From 1b1a35ee97c87290b75be4c46f58dfb00d0036d5 Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Tue, 10 Nov 2020 17:01:33 +0000 Subject: [PATCH] New upstream version 1.48.0~beta.8+dfsg1 --- Cargo.lock | 462 +- Cargo.toml | 4 +- README.md | 59 +- RELEASES.md | 9 +- {src => compiler}/rustc/Cargo.toml | 9 +- .../rustc.rs => compiler/rustc/src/main.rs | 0 .../rustc_apfloat}/Cargo.toml | 4 - .../rustc_apfloat/src}/ieee.rs | 0 .../rustc_apfloat/src}/lib.rs | 2 +- .../rustc_apfloat/src}/ppc.rs | 0 .../rustc_apfloat}/tests/ieee.rs | 0 .../rustc_apfloat}/tests/ppc.rs | 0 .../rustc_arena}/Cargo.toml | 6 +- .../rustc_arena/src}/lib.rs | 86 +- .../rustc_arena/src}/tests.rs | 11 + compiler/rustc_ast/Cargo.toml | 19 + .../rustc_ast}/README.md | 0 .../rustc_ast/src}/ast.rs | 58 +- .../rustc_ast/src}/ast/tests.rs | 0 .../rustc_ast/src}/attr/mod.rs | 29 +- .../rustc_ast/src}/crate_disambiguator.rs | 0 .../rustc_ast/src}/entry.rs | 0 .../rustc_ast/src}/expand/allocator.rs | 0 .../rustc_ast/src}/expand/mod.rs | 0 .../rustc_ast/src}/lib.rs | 10 +- .../rustc_ast/src}/mut_visit.rs | 38 +- .../rustc_ast/src}/node_id.rs | 0 .../rustc_ast/src}/ptr.rs | 0 .../rustc_ast/src}/token.rs | 21 +- .../rustc_ast/src}/tokenstream.rs | 41 +- .../rustc_ast/src}/util/classify.rs | 0 .../rustc_ast/src}/util/comments.rs | 0 .../rustc_ast/src}/util/comments/tests.rs | 0 .../rustc_ast/src}/util/lev_distance.rs | 3 +- .../rustc_ast/src}/util/lev_distance/tests.rs | 0 .../rustc_ast/src}/util/literal.rs | 0 .../rustc_ast/src}/util/parser.rs | 0 .../rustc_ast/src}/visit.rs | 4 +- compiler/rustc_ast_lowering/Cargo.toml | 22 + .../rustc_ast_lowering/src}/expr.rs | 5 +- .../rustc_ast_lowering/src}/item.rs | 17 +- .../rustc_ast_lowering/src}/lib.rs | 2 + .../rustc_ast_lowering/src}/pat.rs | 0 .../rustc_ast_lowering/src}/path.rs | 0 compiler/rustc_ast_passes/Cargo.toml | 18 + .../rustc_ast_passes/src}/ast_validation.rs | 19 +- .../rustc_ast_passes/src}/feature_gate.rs | 37 +- .../rustc_ast_passes/src}/lib.rs | 0 .../rustc_ast_passes/src}/node_count.rs | 0 .../rustc_ast_passes/src}/show_span.rs | 0 compiler/rustc_ast_pretty/Cargo.toml | 14 + .../rustc_ast_pretty/src}/helpers.rs | 0 .../rustc_ast_pretty/src}/lib.rs | 0 .../rustc_ast_pretty/src}/pp.rs | 0 .../rustc_ast_pretty/src}/pprust.rs | 24 +- .../rustc_ast_pretty/src}/pprust/tests.rs | 7 +- compiler/rustc_attr/Cargo.toml | 21 + .../rustc_attr/src}/builtin.rs | 58 +- .../rustc_attr/src}/lib.rs | 0 compiler/rustc_builtin_macros/Cargo.toml | 24 + .../rustc_builtin_macros/src}/asm.rs | 2 +- .../rustc_builtin_macros/src}/assert.rs | 0 .../rustc_builtin_macros/src}/cfg.rs | 0 .../src}/cfg_accessible.rs | 0 .../src}/cmdline_attrs.rs | 2 +- .../src}/compile_error.rs | 0 .../rustc_builtin_macros/src}/concat.rs | 0 .../src}/concat_idents.rs | 15 +- .../src}/deriving/bounds.rs | 0 .../src}/deriving/clone.rs | 0 .../src}/deriving/cmp/eq.rs | 0 .../src}/deriving/cmp/ord.rs | 0 .../src}/deriving/cmp/partial_eq.rs | 0 .../src}/deriving/cmp/partial_ord.rs | 0 .../src}/deriving/debug.rs | 2 +- .../src}/deriving/decodable.rs | 0 .../src}/deriving/default.rs | 0 .../src}/deriving/encodable.rs | 0 .../src}/deriving/generic/mod.rs | 15 +- .../src}/deriving/generic/ty.rs | 0 .../src}/deriving/hash.rs | 0 .../rustc_builtin_macros/src}/deriving/mod.rs | 1 + .../rustc_builtin_macros/src}/env.rs | 0 .../rustc_builtin_macros/src}/format.rs | 58 +- .../src}/format_foreign.rs | 15 +- .../src}/format_foreign/printf/tests.rs | 0 .../src}/format_foreign/shell/tests.rs | 0 .../src}/global_allocator.rs | 0 .../rustc_builtin_macros/src}/global_asm.rs | 7 +- .../rustc_builtin_macros/src}/lib.rs | 2 +- .../rustc_builtin_macros/src}/llvm_asm.rs | 0 .../rustc_builtin_macros/src}/log_syntax.rs | 0 .../src}/proc_macro_harness.rs | 8 +- .../rustc_builtin_macros/src}/source_util.rs | 0 .../src}/standard_library_imports.rs | 0 .../rustc_builtin_macros/src}/test.rs | 9 +- .../rustc_builtin_macros/src}/test_harness.rs | 3 +- .../rustc_builtin_macros/src}/trace_macros.rs | 0 .../rustc_builtin_macros/src}/util.rs | 0 compiler/rustc_codegen_llvm/Cargo.toml | 34 + .../rustc_codegen_llvm}/README.md | 0 .../rustc_codegen_llvm/src}/abi.rs | 0 .../rustc_codegen_llvm/src}/allocator.rs | 0 .../rustc_codegen_llvm/src}/asm.rs | 27 +- .../rustc_codegen_llvm/src}/attributes.rs | 3 + .../rustc_codegen_llvm/src}/back/archive.rs | 0 .../rustc_codegen_llvm/src}/back/lto.rs | 6 +- .../rustc_codegen_llvm/src}/back/profiling.rs | 0 .../rustc_codegen_llvm/src}/back/write.rs | 32 + .../rustc_codegen_llvm/src}/base.rs | 9 +- .../rustc_codegen_llvm/src}/builder.rs | 27 +- .../rustc_codegen_llvm/src}/callee.rs | 0 .../rustc_codegen_llvm/src}/common.rs | 2 - .../rustc_codegen_llvm/src}/consts.rs | 16 +- .../rustc_codegen_llvm/src}/context.rs | 32 + .../src}/coverageinfo/mapgen.rs | 0 .../src}/coverageinfo/mod.rs | 0 .../src}/debuginfo/create_scope_map.rs | 0 .../rustc_codegen_llvm/src}/debuginfo/doc.rs | 0 .../rustc_codegen_llvm/src}/debuginfo/gdb.rs | 0 .../src}/debuginfo/metadata.rs | 39 +- .../rustc_codegen_llvm/src}/debuginfo/mod.rs | 6 +- .../src}/debuginfo/namespace.rs | 13 +- .../src}/debuginfo/source_loc.rs | 0 .../src}/debuginfo/utils.rs | 0 .../rustc_codegen_llvm/src}/declare.rs | 43 +- .../rustc_codegen_llvm/src}/intrinsic.rs | 717 +- .../rustc_codegen_llvm/src}/lib.rs | 10 +- .../src}/llvm/archive_ro.rs | 0 .../src}/llvm/diagnostic.rs | 2 + .../rustc_codegen_llvm/src}/llvm/ffi.rs | 6 +- .../rustc_codegen_llvm/src}/llvm/mod.rs | 6 + .../rustc_codegen_llvm/src}/llvm_util.rs | 1 - .../rustc_codegen_llvm/src}/metadata.rs | 0 .../rustc_codegen_llvm/src}/mono_item.rs | 0 .../rustc_codegen_llvm/src}/type_.rs | 4 - .../rustc_codegen_llvm/src}/type_of.rs | 55 +- .../rustc_codegen_llvm/src}/va_arg.rs | 1 - .../rustc_codegen_llvm/src}/value.rs | 0 compiler/rustc_codegen_ssa/Cargo.toml | 36 + .../rustc_codegen_ssa}/README.md | 0 .../rustc_codegen_ssa/src}/back/archive.rs | 0 .../rustc_codegen_ssa/src}/back/command.rs | 0 .../rustc_codegen_ssa/src}/back/link.rs | 215 +- .../rustc_codegen_ssa/src}/back/linker.rs | 0 .../rustc_codegen_ssa/src}/back/lto.rs | 0 .../rustc_codegen_ssa/src}/back/mod.rs | 0 .../rustc_codegen_ssa/src}/back/rpath.rs | 0 .../src}/back/rpath/tests.rs | 0 .../src}/back/symbol_export.rs | 0 .../rustc_codegen_ssa/src}/back/write.rs | 59 +- .../rustc_codegen_ssa/src}/base.rs | 63 +- .../rustc_codegen_ssa/src}/common.rs | 4 +- .../src}/coverageinfo/ffi.rs | 0 .../src}/coverageinfo/map.rs | 0 .../src}/coverageinfo/mod.rs | 0 .../rustc_codegen_ssa/src}/debuginfo/mod.rs | 0 .../src}/debuginfo/type_names.rs | 9 +- .../rustc_codegen_ssa/src}/glue.rs | 4 +- .../rustc_codegen_ssa/src}/lib.rs | 5 +- .../rustc_codegen_ssa/src}/meth.rs | 0 .../rustc_codegen_ssa/src}/mir/analyze.rs | 2 +- .../rustc_codegen_ssa/src}/mir/block.rs | 58 +- .../rustc_codegen_ssa/src}/mir/constant.rs | 0 .../src}/mir/coverageinfo.rs | 0 .../rustc_codegen_ssa/src}/mir/debuginfo.rs | 0 .../rustc_codegen_ssa/src/mir/intrinsic.rs | 596 + .../rustc_codegen_ssa/src}/mir/mod.rs | 5 +- .../rustc_codegen_ssa/src}/mir/operand.rs | 50 +- .../rustc_codegen_ssa/src}/mir/place.rs | 38 +- .../rustc_codegen_ssa/src}/mir/rvalue.rs | 34 +- .../rustc_codegen_ssa/src}/mir/statement.rs | 0 .../rustc_codegen_ssa/src}/mono_item.rs | 8 +- .../rustc_codegen_ssa/src}/traits/abi.rs | 0 .../rustc_codegen_ssa/src}/traits/asm.rs | 0 .../rustc_codegen_ssa/src}/traits/backend.rs | 7 + .../rustc_codegen_ssa/src}/traits/builder.rs | 17 +- .../rustc_codegen_ssa/src}/traits/consts.rs | 0 .../src}/traits/coverageinfo.rs | 0 .../src}/traits/debuginfo.rs | 0 .../rustc_codegen_ssa/src/traits/declare.rs | 21 + .../src}/traits/intrinsic.rs | 6 +- .../rustc_codegen_ssa/src}/traits/misc.rs | 2 + .../rustc_codegen_ssa/src}/traits/mod.rs | 4 +- .../rustc_codegen_ssa/src}/traits/statics.rs | 0 .../rustc_codegen_ssa/src}/traits/type_.rs | 2 +- .../rustc_codegen_ssa/src}/traits/write.rs | 6 + .../rustc_data_structures}/Cargo.toml | 16 +- .../rustc_data_structures/src}/atomic_ref.rs | 0 .../rustc_data_structures/src}/base_n.rs | 0 .../src}/base_n/tests.rs | 0 .../src}/binary_search_util/mod.rs | 0 .../src}/binary_search_util/tests.rs | 0 .../rustc_data_structures/src}/box_region.rs | 0 .../rustc_data_structures/src}/captures.rs | 0 .../rustc_data_structures/src}/const_cstr.rs | 0 .../rustc_data_structures/src}/fingerprint.rs | 30 +- .../rustc_data_structures/src}/flock.rs | 0 .../rustc_data_structures/src}/frozen.rs | 0 .../rustc_data_structures/src}/fx.rs | 0 .../src}/graph/dominators/mod.rs | 0 .../src}/graph/dominators/tests.rs | 0 .../src}/graph/implementation/mod.rs | 0 .../src}/graph/implementation/tests.rs | 0 .../src}/graph/iterate/mod.rs | 15 +- .../src}/graph/iterate/tests.rs | 0 .../rustc_data_structures/src}/graph/mod.rs | 0 .../src}/graph/reference.rs | 0 .../src}/graph/scc/mod.rs | 0 .../src}/graph/scc/tests.rs | 0 .../rustc_data_structures/src}/graph/tests.rs | 0 .../src}/graph/vec_graph/mod.rs | 0 .../src}/graph/vec_graph/tests.rs | 0 .../rustc_data_structures/src/jobserver.rs | 40 + .../rustc_data_structures/src}/lib.rs | 12 +- .../rustc_data_structures/src}/macros.rs | 12 - .../src}/map_in_place.rs | 0 .../rustc_data_structures/src}/mini_map.rs | 0 .../rustc_data_structures/src/mini_set.rs | 41 + .../src}/obligation_forest/graphviz.rs | 0 .../src}/obligation_forest/mod.rs | 0 .../src}/obligation_forest/tests.rs | 0 .../src}/owning_ref/LICENSE | 0 .../src}/owning_ref/mod.rs | 0 .../src}/owning_ref/tests.rs | 0 .../rustc_data_structures/src}/profiling.rs | 5 +- .../rustc_data_structures/src}/ptr_key.rs | 0 .../rustc_data_structures/src}/sharded.rs | 0 .../rustc_data_structures/src}/sip128.rs | 25 +- .../src}/sip128/tests.rs | 56 +- .../rustc_data_structures/src}/small_c_str.rs | 0 .../src}/small_c_str/tests.rs | 0 .../src}/snapshot_map/mod.rs | 0 .../src}/snapshot_map/tests.rs | 0 .../rustc_data_structures/src}/sorted_map.rs | 4 +- .../src}/sorted_map/index_map.rs | 0 .../src}/sorted_map/tests.rs | 0 .../src}/stable_hasher.rs | 6 +- .../src/stable_hasher/tests.rs | 73 + .../rustc_data_structures/src}/stable_map.rs | 0 .../rustc_data_structures/src}/stable_set.rs | 0 .../rustc_data_structures/src}/stack.rs | 0 .../rustc_data_structures/src}/svh.rs | 0 .../rustc_data_structures/src}/sync.rs | 4 +- .../rustc_data_structures/src}/tagged_ptr.rs | 0 .../src}/tagged_ptr/copy.rs | 2 +- .../src}/tagged_ptr/drop.rs | 0 .../rustc_data_structures/src}/temp_dir.rs | 2 +- .../rustc_data_structures/src}/thin_vec.rs | 0 .../rustc_data_structures/src}/tiny_list.rs | 0 .../src}/tiny_list/tests.rs | 0 .../src}/transitive_relation.rs | 0 .../src}/transitive_relation/tests.rs | 0 compiler/rustc_data_structures/src/unhash.rs | 29 + .../src}/vec_linked_list.rs | 0 .../rustc_data_structures/src}/work_queue.rs | 0 compiler/rustc_driver/Cargo.toml | 41 + .../rustc_driver}/README.md | 0 .../rustc_driver/src}/args.rs | 3 +- .../rustc_driver/src}/lib.rs | 30 +- .../rustc_driver/src}/pretty.rs | 0 .../rustc_error_codes}/Cargo.toml | 4 - .../rustc_error_codes/src}/error_codes.rs | 10 +- .../src}/error_codes/E0001.md | 0 .../src}/error_codes/E0002.md | 0 .../src}/error_codes/E0004.md | 0 .../src}/error_codes/E0005.md | 0 .../src}/error_codes/E0007.md | 0 .../src}/error_codes/E0009.md | 0 .../src}/error_codes/E0010.md | 0 .../src}/error_codes/E0013.md | 0 .../src}/error_codes/E0014.md | 0 .../src}/error_codes/E0015.md | 0 .../src}/error_codes/E0023.md | 0 .../src}/error_codes/E0025.md | 0 .../src}/error_codes/E0026.md | 0 .../src}/error_codes/E0027.md | 0 .../src}/error_codes/E0029.md | 0 .../src}/error_codes/E0030.md | 0 .../src}/error_codes/E0033.md | 0 .../src}/error_codes/E0034.md | 0 .../src}/error_codes/E0038.md | 0 .../src}/error_codes/E0040.md | 0 .../src}/error_codes/E0044.md | 0 .../src}/error_codes/E0045.md | 0 .../src}/error_codes/E0046.md | 0 .../src}/error_codes/E0049.md | 0 .../src}/error_codes/E0050.md | 0 .../src}/error_codes/E0053.md | 0 .../src}/error_codes/E0054.md | 0 .../src}/error_codes/E0055.md | 0 .../src}/error_codes/E0057.md | 0 .../src}/error_codes/E0059.md | 0 .../src}/error_codes/E0060.md | 0 .../src}/error_codes/E0061.md | 0 .../src}/error_codes/E0062.md | 0 .../src}/error_codes/E0063.md | 0 .../src}/error_codes/E0067.md | 0 .../src}/error_codes/E0069.md | 0 .../src}/error_codes/E0070.md | 0 .../src}/error_codes/E0071.md | 0 .../src}/error_codes/E0072.md | 0 .../src}/error_codes/E0073.md | 0 .../src}/error_codes/E0074.md | 0 .../src}/error_codes/E0075.md | 0 .../src}/error_codes/E0076.md | 0 .../src}/error_codes/E0077.md | 0 .../src}/error_codes/E0080.md | 0 .../src}/error_codes/E0081.md | 0 .../src}/error_codes/E0084.md | 0 .../src}/error_codes/E0087.md | 0 .../src}/error_codes/E0088.md | 0 .../src}/error_codes/E0089.md | 0 .../src}/error_codes/E0090.md | 0 .../src}/error_codes/E0091.md | 0 .../src}/error_codes/E0092.md | 4 +- .../src}/error_codes/E0093.md | 4 +- .../src}/error_codes/E0094.md | 0 .../src}/error_codes/E0106.md | 0 .../src}/error_codes/E0107.md | 0 .../src}/error_codes/E0109.md | 0 .../src}/error_codes/E0110.md | 0 .../src}/error_codes/E0116.md | 0 .../src}/error_codes/E0117.md | 0 .../src}/error_codes/E0118.md | 27 +- .../src}/error_codes/E0119.md | 0 .../src}/error_codes/E0120.md | 0 .../src}/error_codes/E0121.md | 0 .../src}/error_codes/E0124.md | 0 .../src}/error_codes/E0128.md | 0 .../src}/error_codes/E0130.md | 0 .../src}/error_codes/E0131.md | 0 .../src}/error_codes/E0132.md | 0 .../src}/error_codes/E0133.md | 0 .../src}/error_codes/E0136.md | 0 .../src}/error_codes/E0137.md | 0 .../src}/error_codes/E0138.md | 0 .../src}/error_codes/E0139.md | 0 .../src}/error_codes/E0152.md | 0 .../src}/error_codes/E0154.md | 0 .../src}/error_codes/E0158.md | 0 .../src}/error_codes/E0161.md | 0 .../src}/error_codes/E0162.md | 0 .../src}/error_codes/E0164.md | 0 .../src}/error_codes/E0165.md | 0 .../src}/error_codes/E0170.md | 0 .../src}/error_codes/E0178.md | 0 .../src}/error_codes/E0184.md | 0 .../src}/error_codes/E0185.md | 0 .../src}/error_codes/E0186.md | 0 .../src}/error_codes/E0191.md | 0 .../src}/error_codes/E0192.md | 0 .../src}/error_codes/E0193.md | 0 .../src}/error_codes/E0195.md | 0 .../src}/error_codes/E0197.md | 0 .../src}/error_codes/E0198.md | 0 .../src}/error_codes/E0199.md | 0 .../src}/error_codes/E0200.md | 0 .../src}/error_codes/E0201.md | 0 .../src}/error_codes/E0202.md | 0 .../src}/error_codes/E0203.md | 0 .../src}/error_codes/E0204.md | 0 .../src}/error_codes/E0205.md | 0 .../src}/error_codes/E0206.md | 0 .../src}/error_codes/E0207.md | 0 .../src}/error_codes/E0210.md | 0 .../src}/error_codes/E0211.md | 0 .../src}/error_codes/E0214.md | 0 .../src}/error_codes/E0220.md | 0 .../src}/error_codes/E0221.md | 0 .../src}/error_codes/E0222.md | 0 .../src}/error_codes/E0223.md | 0 .../src}/error_codes/E0224.md | 4 +- .../src}/error_codes/E0225.md | 0 .../src}/error_codes/E0226.md | 0 .../src}/error_codes/E0228.md | 0 .../src}/error_codes/E0229.md | 0 .../src}/error_codes/E0230.md | 0 .../src}/error_codes/E0231.md | 0 .../src}/error_codes/E0232.md | 0 .../src}/error_codes/E0243.md | 0 .../src}/error_codes/E0244.md | 0 .../src}/error_codes/E0251.md | 0 .../src}/error_codes/E0252.md | 0 .../src}/error_codes/E0253.md | 0 .../src}/error_codes/E0254.md | 0 .../src}/error_codes/E0255.md | 0 .../src}/error_codes/E0256.md | 0 .../src}/error_codes/E0259.md | 0 .../src}/error_codes/E0260.md | 0 .../src}/error_codes/E0261.md | 0 .../src}/error_codes/E0262.md | 0 .../src}/error_codes/E0263.md | 0 .../src}/error_codes/E0264.md | 0 .../src}/error_codes/E0267.md | 0 .../src}/error_codes/E0268.md | 0 .../src}/error_codes/E0271.md | 0 .../src}/error_codes/E0275.md | 0 .../src}/error_codes/E0276.md | 0 .../src}/error_codes/E0277.md | 0 .../src}/error_codes/E0281.md | 0 .../src}/error_codes/E0282.md | 0 .../src}/error_codes/E0283.md | 0 .../src}/error_codes/E0284.md | 0 .../src}/error_codes/E0297.md | 0 .../src}/error_codes/E0301.md | 0 .../src}/error_codes/E0302.md | 0 .../src}/error_codes/E0303.md | 0 .../src}/error_codes/E0307.md | 0 .../src}/error_codes/E0308.md | 0 .../src}/error_codes/E0309.md | 0 .../src}/error_codes/E0310.md | 0 .../src}/error_codes/E0312.md | 0 .../src}/error_codes/E0317.md | 0 .../src}/error_codes/E0321.md | 0 .../src}/error_codes/E0322.md | 0 .../src}/error_codes/E0323.md | 0 .../src}/error_codes/E0324.md | 0 .../src}/error_codes/E0325.md | 0 .../src}/error_codes/E0326.md | 0 .../src}/error_codes/E0328.md | 0 .../src}/error_codes/E0329.md | 0 .../src}/error_codes/E0364.md | 0 .../src}/error_codes/E0365.md | 0 .../src}/error_codes/E0366.md | 0 .../src}/error_codes/E0367.md | 0 .../src}/error_codes/E0368.md | 0 .../src}/error_codes/E0369.md | 0 .../src}/error_codes/E0370.md | 0 .../src}/error_codes/E0371.md | 0 .../src}/error_codes/E0373.md | 0 .../src}/error_codes/E0374.md | 0 .../src}/error_codes/E0375.md | 0 .../src}/error_codes/E0376.md | 0 .../src}/error_codes/E0378.md | 0 .../src}/error_codes/E0379.md | 0 .../src}/error_codes/E0380.md | 0 .../src}/error_codes/E0381.md | 0 .../src}/error_codes/E0382.md | 0 .../src}/error_codes/E0383.md | 0 .../src}/error_codes/E0384.md | 0 .../src}/error_codes/E0386.md | 0 .../src}/error_codes/E0387.md | 0 .../src}/error_codes/E0388.md | 0 .../src}/error_codes/E0389.md | 0 .../src}/error_codes/E0390.md | 0 .../src}/error_codes/E0391.md | 0 .../src}/error_codes/E0392.md | 0 .../src}/error_codes/E0393.md | 0 .../src}/error_codes/E0398.md | 0 .../src}/error_codes/E0399.md | 0 .../src}/error_codes/E0401.md | 0 .../src}/error_codes/E0403.md | 0 .../src}/error_codes/E0404.md | 0 .../src}/error_codes/E0405.md | 0 .../src}/error_codes/E0407.md | 0 .../src}/error_codes/E0408.md | 0 .../src}/error_codes/E0409.md | 0 .../src}/error_codes/E0411.md | 0 .../src}/error_codes/E0412.md | 0 .../src}/error_codes/E0415.md | 0 .../src}/error_codes/E0416.md | 0 .../src}/error_codes/E0422.md | 0 .../src}/error_codes/E0423.md | 0 .../src}/error_codes/E0424.md | 0 .../src}/error_codes/E0425.md | 0 .../src}/error_codes/E0426.md | 0 .../src}/error_codes/E0428.md | 0 .../src}/error_codes/E0429.md | 0 .../src}/error_codes/E0430.md | 0 .../src}/error_codes/E0431.md | 0 .../src}/error_codes/E0432.md | 0 .../src/error_codes/E0433.md | 27 + .../src}/error_codes/E0434.md | 0 .../src}/error_codes/E0435.md | 0 .../src}/error_codes/E0436.md | 0 .../src}/error_codes/E0437.md | 0 .../src}/error_codes/E0438.md | 0 .../src}/error_codes/E0439.md | 0 .../src}/error_codes/E0445.md | 0 .../src}/error_codes/E0446.md | 0 .../src}/error_codes/E0447.md | 0 .../src}/error_codes/E0448.md | 0 .../src}/error_codes/E0449.md | 0 .../src}/error_codes/E0451.md | 0 .../src}/error_codes/E0452.md | 0 .../src}/error_codes/E0453.md | 0 .../src}/error_codes/E0454.md | 0 .../src}/error_codes/E0455.md | 0 .../src}/error_codes/E0458.md | 0 .../src}/error_codes/E0459.md | 0 .../src}/error_codes/E0463.md | 0 .../src}/error_codes/E0466.md | 0 .../src}/error_codes/E0468.md | 0 .../src}/error_codes/E0469.md | 0 .../src}/error_codes/E0477.md | 0 .../src}/error_codes/E0478.md | 0 .../src}/error_codes/E0491.md | 0 .../src}/error_codes/E0492.md | 0 .../src}/error_codes/E0493.md | 0 .../src}/error_codes/E0495.md | 0 .../src}/error_codes/E0496.md | 0 .../src}/error_codes/E0497.md | 0 .../src}/error_codes/E0499.md | 0 .../src}/error_codes/E0500.md | 0 .../src}/error_codes/E0501.md | 0 .../src}/error_codes/E0502.md | 0 .../src}/error_codes/E0503.md | 0 .../src}/error_codes/E0504.md | 0 .../src}/error_codes/E0505.md | 0 .../src}/error_codes/E0506.md | 0 .../src}/error_codes/E0507.md | 0 .../src}/error_codes/E0508.md | 0 .../src}/error_codes/E0509.md | 0 .../src}/error_codes/E0510.md | 0 .../src}/error_codes/E0511.md | 0 .../src}/error_codes/E0512.md | 0 .../src}/error_codes/E0515.md | 0 .../src}/error_codes/E0516.md | 0 .../src}/error_codes/E0517.md | 0 .../src}/error_codes/E0518.md | 0 .../src}/error_codes/E0520.md | 0 .../src}/error_codes/E0522.md | 0 .../src}/error_codes/E0524.md | 0 .../src}/error_codes/E0525.md | 0 .../src}/error_codes/E0527.md | 0 .../src}/error_codes/E0528.md | 0 .../src}/error_codes/E0529.md | 0 .../src}/error_codes/E0530.md | 0 .../src}/error_codes/E0531.md | 0 .../src}/error_codes/E0532.md | 0 .../src}/error_codes/E0533.md | 0 .../src}/error_codes/E0534.md | 0 .../src}/error_codes/E0535.md | 0 .../src}/error_codes/E0536.md | 0 .../src}/error_codes/E0537.md | 0 .../src}/error_codes/E0538.md | 0 .../src}/error_codes/E0539.md | 0 .../src}/error_codes/E0541.md | 0 .../src}/error_codes/E0550.md | 0 .../src}/error_codes/E0551.md | 0 .../src}/error_codes/E0552.md | 0 .../src}/error_codes/E0554.md | 0 .../src}/error_codes/E0556.md | 0 .../src}/error_codes/E0557.md | 0 .../src}/error_codes/E0559.md | 0 .../src}/error_codes/E0560.md | 0 .../src}/error_codes/E0561.md | 0 .../src}/error_codes/E0562.md | 0 .../src}/error_codes/E0565.md | 0 .../src}/error_codes/E0566.md | 0 .../src}/error_codes/E0567.md | 0 .../src}/error_codes/E0568.md | 0 .../src}/error_codes/E0569.md | 0 .../src}/error_codes/E0570.md | 0 .../src}/error_codes/E0571.md | 0 .../src}/error_codes/E0572.md | 0 .../src}/error_codes/E0573.md | 0 .../src}/error_codes/E0574.md | 0 .../src}/error_codes/E0575.md | 0 .../src}/error_codes/E0576.md | 0 .../src}/error_codes/E0577.md | 0 .../src}/error_codes/E0578.md | 0 .../src}/error_codes/E0579.md | 0 .../src}/error_codes/E0580.md | 0 .../src}/error_codes/E0581.md | 0 .../src}/error_codes/E0582.md | 0 .../src}/error_codes/E0583.md | 0 .../src}/error_codes/E0584.md | 0 .../src}/error_codes/E0585.md | 0 .../src}/error_codes/E0586.md | 0 .../src}/error_codes/E0587.md | 0 .../src}/error_codes/E0588.md | 0 .../src}/error_codes/E0589.md | 0 .../src}/error_codes/E0590.md | 0 .../src}/error_codes/E0591.md | 0 .../src}/error_codes/E0592.md | 0 .../src}/error_codes/E0593.md | 0 .../src}/error_codes/E0594.md | 0 .../src}/error_codes/E0595.md | 0 .../src}/error_codes/E0596.md | 0 .../src}/error_codes/E0597.md | 0 .../src}/error_codes/E0599.md | 0 .../src}/error_codes/E0600.md | 0 .../src}/error_codes/E0601.md | 0 .../src}/error_codes/E0602.md | 0 .../src}/error_codes/E0603.md | 0 .../src}/error_codes/E0604.md | 0 .../src}/error_codes/E0605.md | 0 .../src}/error_codes/E0606.md | 0 .../src}/error_codes/E0607.md | 14 +- .../src}/error_codes/E0608.md | 0 .../src}/error_codes/E0609.md | 0 .../src}/error_codes/E0610.md | 0 .../src}/error_codes/E0614.md | 0 .../src}/error_codes/E0615.md | 0 .../src}/error_codes/E0616.md | 0 .../src}/error_codes/E0617.md | 0 .../src}/error_codes/E0618.md | 0 .../src}/error_codes/E0619.md | 0 .../src}/error_codes/E0620.md | 0 .../src}/error_codes/E0621.md | 0 .../src}/error_codes/E0622.md | 0 .../src}/error_codes/E0623.md | 0 .../src}/error_codes/E0624.md | 0 .../src}/error_codes/E0626.md | 0 .../src}/error_codes/E0627.md | 0 .../src}/error_codes/E0628.md | 0 .../src}/error_codes/E0631.md | 0 .../src}/error_codes/E0633.md | 0 .../src}/error_codes/E0634.md | 0 .../src}/error_codes/E0635.md | 0 .../src}/error_codes/E0636.md | 0 .../src}/error_codes/E0637.md | 0 .../src}/error_codes/E0638.md | 0 .../src}/error_codes/E0639.md | 0 .../src}/error_codes/E0641.md | 0 .../src}/error_codes/E0642.md | 0 .../src}/error_codes/E0643.md | 0 .../src}/error_codes/E0644.md | 0 .../src}/error_codes/E0646.md | 0 .../src}/error_codes/E0647.md | 0 .../src}/error_codes/E0648.md | 0 .../src}/error_codes/E0657.md | 0 .../src}/error_codes/E0658.md | 0 .../src}/error_codes/E0659.md | 0 .../src}/error_codes/E0660.md | 0 .../src}/error_codes/E0661.md | 0 .../src}/error_codes/E0662.md | 0 .../src}/error_codes/E0663.md | 0 .../src}/error_codes/E0664.md | 0 .../src}/error_codes/E0665.md | 0 .../src}/error_codes/E0666.md | 0 .../src}/error_codes/E0668.md | 0 .../src}/error_codes/E0669.md | 0 .../src}/error_codes/E0670.md | 0 .../src}/error_codes/E0671.md | 0 .../src}/error_codes/E0687.md | 0 .../src}/error_codes/E0688.md | 0 .../src}/error_codes/E0689.md | 0 .../src}/error_codes/E0690.md | 0 .../src}/error_codes/E0691.md | 0 .../src}/error_codes/E0692.md | 0 .../src}/error_codes/E0693.md | 0 .../src}/error_codes/E0695.md | 0 .../src}/error_codes/E0696.md | 0 .../src}/error_codes/E0697.md | 0 .../src}/error_codes/E0698.md | 0 .../src}/error_codes/E0699.md | 0 .../src}/error_codes/E0700.md | 0 .../src}/error_codes/E0701.md | 0 .../src}/error_codes/E0703.md | 0 .../src}/error_codes/E0704.md | 0 .../src}/error_codes/E0705.md | 0 .../src}/error_codes/E0706.md | 0 .../src}/error_codes/E0708.md | 0 .../src}/error_codes/E0710.md | 0 .../src}/error_codes/E0712.md | 0 .../src}/error_codes/E0713.md | 0 .../src}/error_codes/E0714.md | 0 .../src}/error_codes/E0715.md | 0 .../src}/error_codes/E0716.md | 0 .../src}/error_codes/E0718.md | 0 .../src}/error_codes/E0719.md | 0 .../src}/error_codes/E0720.md | 0 .../src}/error_codes/E0723.md | 0 .../src}/error_codes/E0724.md | 0 .../src}/error_codes/E0725.md | 0 .../src}/error_codes/E0727.md | 0 .../src}/error_codes/E0728.md | 0 .../src}/error_codes/E0729.md | 0 .../src}/error_codes/E0730.md | 0 .../src}/error_codes/E0731.md | 0 .../src}/error_codes/E0732.md | 0 .../src}/error_codes/E0733.md | 0 .../src}/error_codes/E0734.md | 0 .../src}/error_codes/E0735.md | 0 .../src}/error_codes/E0736.md | 0 .../src}/error_codes/E0737.md | 0 .../src}/error_codes/E0739.md | 0 .../src}/error_codes/E0740.md | 0 .../src}/error_codes/E0741.md | 0 .../src}/error_codes/E0742.md | 0 .../src}/error_codes/E0743.md | 0 .../src}/error_codes/E0744.md | 0 .../src}/error_codes/E0745.md | 0 .../src}/error_codes/E0746.md | 0 .../src}/error_codes/E0747.md | 0 .../src}/error_codes/E0748.md | 0 .../src}/error_codes/E0749.md | 0 .../src}/error_codes/E0750.md | 0 .../src}/error_codes/E0751.md | 0 .../src}/error_codes/E0752.md | 0 .../src}/error_codes/E0753.md | 0 .../src}/error_codes/E0754.md | 0 .../src/error_codes/E0755.md | 28 + .../src/error_codes/E0756.md | 29 + .../src}/error_codes/E0758.md | 0 .../src}/error_codes/E0759.md | 0 .../src}/error_codes/E0760.md | 0 .../src}/error_codes/E0761.md | 10 +- .../src}/error_codes/E0762.md | 0 .../src}/error_codes/E0763.md | 0 .../src}/error_codes/E0764.md | 22 +- .../src}/error_codes/E0765.md | 0 .../src}/error_codes/E0766.md | 0 .../src}/error_codes/E0767.md | 0 .../src}/error_codes/E0768.md | 0 .../src}/error_codes/E0769.md | 22 +- .../src}/error_codes/E0770.md | 0 .../src}/error_codes/E0771.md | 0 .../src/error_codes/E0773.md | 38 + .../src/error_codes/E0774.md | 24 + .../src/error_codes/E0775.md | 17 + .../src/error_codes/E0776.md | 13 + .../rustc_error_codes/src}/lib.rs | 0 .../rustc_errors}/Cargo.toml | 10 +- .../src}/annotate_snippet_emitter_writer.rs | 0 .../rustc_errors/src}/diagnostic.rs | 0 .../rustc_errors/src}/diagnostic_builder.rs | 0 .../rustc_errors/src}/emitter.rs | 22 +- .../rustc_errors/src}/json.rs | 0 .../rustc_errors/src}/json/tests.rs | 0 .../rustc_errors/src}/lib.rs | 69 +- .../rustc_errors/src}/lock.rs | 0 .../rustc_errors/src}/registry.rs | 0 .../rustc_errors/src}/snippet.rs | 8 +- .../rustc_errors/src}/styled_buffer.rs | 0 compiler/rustc_expand/Cargo.toml | 26 + .../rustc_expand/src}/base.rs | 36 +- .../rustc_expand/src}/build.rs | 56 +- .../rustc_expand/src}/config.rs | 13 +- .../rustc_expand/src}/expand.rs | 52 +- .../rustc_expand/src}/lib.rs | 6 - .../rustc_expand/src}/mbe.rs | 0 .../rustc_expand/src}/mbe/macro_check.rs | 0 .../rustc_expand/src}/mbe/macro_parser.rs | 0 .../rustc_expand/src}/mbe/macro_rules.rs | 0 .../rustc_expand/src}/mbe/quoted.rs | 0 .../rustc_expand/src}/mbe/transcribe.rs | 4 +- .../rustc_expand/src}/module.rs | 15 +- .../rustc_expand/src}/mut_visit/tests.rs | 0 .../rustc_expand/src}/parse/tests.rs | 0 .../rustc_expand/src}/placeholders.rs | 32 +- .../rustc_expand/src}/proc_macro.rs | 41 +- .../rustc_expand/src}/proc_macro_server.rs | 18 +- .../rustc_expand/src}/tests.rs | 0 .../rustc_expand/src}/tokenstream/tests.rs | 0 compiler/rustc_feature/Cargo.toml | 12 + .../rustc_feature/src}/accepted.rs | 6 +- .../rustc_feature/src}/active.rs | 26 +- .../rustc_feature/src}/builtin_attrs.rs | 18 +- .../rustc_feature/src}/lib.rs | 27 +- .../rustc_feature/src}/removed.rs | 6 +- .../rustc_fs_util}/Cargo.toml | 6 - .../rustc_fs_util/src}/lib.rs | 0 .../rustc_graphviz}/Cargo.toml | 4 - .../rustc_graphviz/src}/lib.rs | 31 +- .../rustc_graphviz/src}/tests.rs | 0 compiler/rustc_hir/Cargo.toml | 19 + .../rustc_hir/src}/arena.rs | 0 .../rustc_hir/src}/def.rs | 38 +- .../rustc_hir/src}/definitions.rs | 97 +- .../rustc_hir/src}/hir.rs | 24 + .../rustc_hir/src}/hir_id.rs | 0 .../rustc_hir/src}/intravisit.rs | 3 - .../rustc_hir/src}/itemlikevisit.rs | 0 .../rustc_hir/src}/lang_items.rs | 16 +- .../rustc_hir/src}/lib.rs | 2 + .../rustc_hir/src}/pat_util.rs | 0 .../rustc_hir/src}/stable_hash_impls.rs | 0 .../rustc_hir/src}/target.rs | 0 .../rustc_hir/src}/weak_lang_items.rs | 15 +- compiler/rustc_hir_pretty/Cargo.toml | 15 + .../rustc_hir_pretty/src}/lib.rs | 0 compiler/rustc_incremental/Cargo.toml | 22 + .../src}/assert_dep_graph.rs | 0 .../src}/assert_module_sources.rs | 0 .../rustc_incremental/src}/lib.rs | 2 +- .../rustc_incremental/src}/persist/README.md | 0 .../rustc_incremental/src}/persist/data.rs | 0 .../src}/persist/dirty_clean.rs | 0 .../src}/persist/file_format.rs | 0 .../rustc_incremental/src}/persist/fs.rs | 0 .../src}/persist/fs/tests.rs | 0 .../rustc_incremental/src}/persist/load.rs | 0 .../rustc_incremental/src}/persist/mod.rs | 0 .../rustc_incremental/src}/persist/save.rs | 0 .../src}/persist/work_product.rs | 0 .../rustc_index}/Cargo.toml | 6 +- .../rustc_index/src}/bit_set.rs | 54 +- .../rustc_index/src}/bit_set/tests.rs | 0 .../rustc_index/src}/lib.rs | 0 .../rustc_index/src}/vec.rs | 0 .../rustc_index/src}/vec/tests.rs | 0 compiler/rustc_infer/Cargo.toml | 24 + .../rustc_infer/src}/infer/at.rs | 0 .../src}/infer/canonical/canonicalizer.rs | 4 +- .../rustc_infer/src}/infer/canonical/mod.rs | 0 .../src}/infer/canonical/query_response.rs | 2 +- .../src}/infer/canonical/substitute.rs | 0 .../rustc_infer/src}/infer/combine.rs | 246 +- .../rustc_infer/src}/infer/equate.rs | 2 +- .../src}/infer/error_reporting/mod.rs | 152 +- .../infer/error_reporting/need_type_info.rs | 286 +- .../nice_region_error/different_lifetimes.rs | 0 .../nice_region_error/find_anon_type.rs | 0 .../error_reporting/nice_region_error/mod.rs | 0 .../nice_region_error/named_anon_conflict.rs | 2 +- .../nice_region_error/placeholder_error.rs | 0 .../nice_region_error/static_impl_trait.rs | 28 +- .../trait_impl_difference.rs | 6 +- .../error_reporting/nice_region_error/util.rs | 2 +- .../src}/infer/error_reporting/note.rs | 0 .../rustc_infer/src}/infer/free_regions.rs | 0 .../rustc_infer/src}/infer/freshen.rs | 2 +- .../rustc_infer/src}/infer/fudge.rs | 2 +- .../rustc_infer/src}/infer/glb.rs | 0 .../src}/infer/higher_ranked/README.md | 0 .../src}/infer/higher_ranked/mod.rs | 0 .../rustc_infer/src}/infer/lattice.rs | 2 +- .../infer/lexical_region_resolve/README.md | 0 .../src}/infer/lexical_region_resolve/mod.rs | 0 .../rustc_infer/src}/infer/lub.rs | 2 +- .../rustc_infer/src}/infer/mod.rs | 18 +- .../rustc_infer/src}/infer/nll_relate/mod.rs | 8 +- .../rustc_infer/src}/infer/outlives/env.rs | 0 .../rustc_infer/src}/infer/outlives/mod.rs | 3 +- .../src}/infer/outlives/obligations.rs | 2 +- .../rustc_infer/src}/infer/outlives/verify.rs | 6 +- .../src}/infer/region_constraints/README.md | 0 .../infer/region_constraints/leak_check.rs | 0 .../src}/infer/region_constraints/mod.rs | 0 .../rustc_infer/src}/infer/resolve.rs | 4 +- .../rustc_infer/src}/infer/sub.rs | 2 +- .../rustc_infer/src}/infer/type_variable.rs | 2 +- .../rustc_infer/src}/infer/undo_log.rs | 0 .../rustc_infer/src}/lib.rs | 4 +- .../rustc_infer/src}/traits/engine.rs | 0 .../src}/traits/error_reporting/mod.rs | 0 .../rustc_infer/src}/traits/mod.rs | 2 +- .../rustc_infer/src}/traits/project.rs | 0 .../src}/traits/structural_impls.rs | 0 .../rustc_infer/src}/traits/util.rs | 3 + compiler/rustc_interface/Cargo.toml | 54 + .../rustc_interface/src}/callbacks.rs | 0 .../rustc_interface/src}/interface.rs | 5 + .../rustc_interface/src}/lib.rs | 1 + .../rustc_interface/src}/passes.rs | 7 +- .../rustc_interface/src}/proc_macro_decls.rs | 0 .../rustc_interface/src}/queries.rs | 0 .../rustc_interface/src}/tests.rs | 5 + .../rustc_interface/src}/util.rs | 30 +- .../rustc_lexer}/Cargo.toml | 3 +- .../rustc_lexer}/src/cursor.rs | 0 .../rustc_lexer}/src/lib.rs | 16 +- compiler/rustc_lexer/src/tests.rs | 287 + .../rustc_lexer}/src/unescape.rs | 0 .../rustc_lexer}/src/unescape/tests.rs | 0 compiler/rustc_lint/Cargo.toml | 22 + .../rustc_lint/src}/array_into_iter.rs | 33 +- .../rustc_lint/src}/builtin.rs | 650 +- .../rustc_lint/src}/context.rs | 35 +- .../rustc_lint/src}/early.rs | 0 .../rustc_lint/src}/internal.rs | 32 +- .../rustc_lint/src}/late.rs | 0 .../rustc_lint/src}/levels.rs | 0 .../rustc_lint/src}/lib.rs | 4 +- .../rustc_lint/src}/non_ascii_idents.rs | 132 +- .../rustc_lint/src}/nonstandard_style.rs | 53 +- .../src}/nonstandard_style/tests.rs | 0 .../rustc_lint/src}/passes.rs | 0 .../rustc_lint/src}/redundant_semicolon.rs | 15 + .../rustc_lint/src}/types.rs | 176 +- .../rustc_lint/src}/unused.rs | 148 +- .../rustc_llvm}/Cargo.toml | 8 +- .../rustc_llvm}/build.rs | 18 +- .../rustc_llvm/llvm-wrapper}/.editorconfig | 0 .../llvm-wrapper}/ArchiveWrapper.cpp | 2 +- .../llvm-wrapper}/CoverageMappingWrapper.cpp | 2 +- .../rustc_llvm/llvm-wrapper/LLVMWrapper.h | 0 .../rustc_llvm/llvm-wrapper}/Linker.cpp | 2 +- .../rustc_llvm/llvm-wrapper}/PassWrapper.cpp | 2 +- .../rustc_llvm/llvm-wrapper}/README | 0 .../rustc_llvm/llvm-wrapper}/RustWrapper.cpp | 5 +- .../rustc_llvm/src}/lib.rs | 3 +- .../rustc_macros}/Cargo.toml | 0 .../rustc_macros}/src/hash_stable.rs | 0 .../rustc_macros}/src/lib.rs | 13 + .../rustc_macros}/src/lift.rs | 0 .../rustc_macros}/src/query.rs | 32 +- .../rustc_macros}/src/serialize.rs | 0 .../rustc_macros/src/session_diagnostic.rs | 666 + .../rustc_macros}/src/symbols.rs | 1 - .../rustc_macros}/src/type_foldable.rs | 0 compiler/rustc_metadata/Cargo.toml | 34 + .../rustc_metadata/src}/creader.rs | 11 +- .../rustc_metadata/src}/dependency_format.rs | 0 .../rustc_metadata/src}/dynamic_lib.rs | 107 +- .../rustc_metadata/src}/dynamic_lib/tests.rs | 0 .../rustc_metadata/src}/foreign_modules.rs | 0 .../rustc_metadata/src}/lib.rs | 3 +- .../rustc_metadata/src}/link_args.rs | 0 .../rustc_metadata/src}/locator.rs | 4 +- .../rustc_metadata/src}/native_libs.rs | 4 +- .../rustc_metadata/src}/rmeta/decoder.rs | 76 +- .../src}/rmeta/decoder/cstore_impl.rs | 16 +- .../rustc_metadata/src}/rmeta/encoder.rs | 180 +- .../rustc_metadata/src}/rmeta/mod.rs | 30 +- .../rustc_metadata/src}/rmeta/table.rs | 0 compiler/rustc_middle/Cargo.toml | 32 + .../rustc_middle}/README.md | 0 .../rustc_middle}/benches/lib.rs | 0 .../rustc_middle/src}/arena.rs | 0 .../rustc_middle/src}/dep_graph/dep_node.rs | 0 .../rustc_middle/src}/dep_graph/mod.rs | 0 .../rustc_middle/src}/hir/exports.rs | 0 .../rustc_middle/src}/hir/map/blocks.rs | 0 .../rustc_middle/src}/hir/map/collector.rs | 8 +- .../rustc_middle/src}/hir/map/mod.rs | 6 +- .../rustc_middle/src}/hir/mod.rs | 0 .../rustc_middle/src}/hir/place.rs | 0 .../rustc_middle/src}/ich/hcx.rs | 0 .../rustc_middle/src}/ich/impls_hir.rs | 0 .../rustc_middle/src}/ich/impls_syntax.rs | 0 .../rustc_middle/src}/ich/impls_ty.rs | 0 .../rustc_middle/src}/ich/mod.rs | 0 .../rustc_middle/src}/infer/canonical.rs | 0 .../rustc_middle/src}/infer/mod.rs | 0 .../rustc_middle/src}/infer/unify_key.rs | 17 +- .../rustc_middle/src}/lib.rs | 9 +- .../rustc_middle/src}/lint.rs | 0 .../rustc_middle/src}/macros.rs | 0 .../src}/middle/codegen_fn_attrs.rs | 3 + .../rustc_middle/src}/middle/cstore.rs | 2 +- .../src}/middle/dependency_format.rs | 0 .../src}/middle/exported_symbols.rs | 0 .../rustc_middle/src}/middle/lang_items.rs | 10 +- .../rustc_middle/src}/middle/limits.rs | 0 .../rustc_middle/src}/middle/mod.rs | 0 .../rustc_middle/src}/middle/privacy.rs | 0 .../rustc_middle/src}/middle/region.rs | 0 .../src}/middle/resolve_lifetime.rs | 0 .../rustc_middle/src}/middle/stability.rs | 31 +- .../rustc_middle/src/mir/abstract_const.rs | 20 + .../rustc_middle/src}/mir/coverage/mod.rs | 0 .../src}/mir/interpret/allocation.rs | 12 +- .../rustc_middle/src}/mir/interpret/error.rs | 12 +- .../rustc_middle/src}/mir/interpret/mod.rs | 61 +- .../src}/mir/interpret/pointer.rs | 0 .../src}/mir/interpret/queries.rs | 16 +- .../rustc_middle/src}/mir/interpret/value.rs | 19 +- .../rustc_middle/src}/mir/mod.rs | 173 +- .../rustc_middle/src}/mir/mono.rs | 39 +- .../rustc_middle/src}/mir/predecessors.rs | 2 +- .../rustc_middle/src}/mir/query.rs | 0 .../rustc_middle/src}/mir/tcx.rs | 4 +- .../rustc_middle/src}/mir/terminator/mod.rs | 2 + .../rustc_middle/src}/mir/traversal.rs | 0 .../rustc_middle/src}/mir/type_foldable.rs | 2 +- .../rustc_middle/src}/mir/visit.rs | 2 - .../rustc_middle/src}/query/mod.rs | 133 +- .../rustc_middle/src}/tests.rs | 0 .../rustc_middle/src}/traits/chalk.rs | 83 +- .../rustc_middle/src}/traits/mod.rs | 98 +- .../rustc_middle/src}/traits/query.rs | 68 - .../rustc_middle/src}/traits/select.rs | 0 .../src}/traits/specialization_graph.rs | 0 .../src}/traits/structural_impls.rs | 22 +- .../rustc_middle/src}/ty/_match.rs | 2 +- .../rustc_middle/src}/ty/adjustment.rs | 4 + .../rustc_middle/src}/ty/binding.rs | 0 .../rustc_middle/src}/ty/cast.rs | 2 +- .../rustc_middle/src}/ty/codec.rs | 24 +- .../rustc_middle/src}/ty/consts.rs | 0 .../rustc_middle/src}/ty/consts/int.rs | 0 .../rustc_middle/src}/ty/consts/kind.rs | 0 .../rustc_middle/src}/ty/context.rs | 83 +- .../rustc_middle/src}/ty/diagnostics.rs | 74 +- .../rustc_middle/src}/ty/erase_regions.rs | 0 .../rustc_middle/src}/ty/error.rs | 66 +- .../rustc_middle/src}/ty/fast_reject.rs | 2 +- .../rustc_middle/src}/ty/flags.rs | 5 +- .../rustc_middle/src}/ty/fold.rs | 25 +- .../src}/ty/inhabitedness/def_id_forest.rs | 0 .../rustc_middle/src}/ty/inhabitedness/mod.rs | 2 +- .../rustc_middle/src}/ty/instance.rs | 60 +- .../rustc_middle/src}/ty/layout.rs | 162 +- .../rustc_middle/src}/ty/list.rs | 0 .../rustc_middle/src}/ty/mod.rs | 121 +- .../src}/ty/normalize_erasing_regions.rs | 0 .../rustc_middle/src}/ty/outlives.rs | 4 +- .../rustc_middle/src}/ty/print/mod.rs | 6 +- .../rustc_middle/src}/ty/print/pretty.rs | 338 +- .../rustc_middle/src}/ty/query/README.md | 0 .../rustc_middle/src}/ty/query/job.rs | 0 .../rustc_middle/src}/ty/query/keys.rs | 16 + .../rustc_middle/src}/ty/query/mod.rs | 2 +- .../src}/ty/query/on_disk_cache.rs | 6 + .../rustc_middle/src}/ty/query/plumbing.rs | 0 .../src}/ty/query/profiling_support.rs | 9 +- .../rustc_middle/src}/ty/query/stats.rs | 0 .../rustc_middle/src}/ty/query/values.rs | 0 .../rustc_middle/src}/ty/relate.rs | 21 +- .../rustc_middle/src}/ty/steal.rs | 0 .../rustc_middle/src}/ty/structural_impls.rs | 50 +- .../rustc_middle/src}/ty/sty.rs | 181 +- .../rustc_middle/src}/ty/subst.rs | 2 +- .../rustc_middle/src}/ty/trait_def.rs | 2 +- .../rustc_middle/src}/ty/util.rs | 50 +- .../rustc_middle/src}/ty/walk.rs | 50 +- .../rustc_middle/src}/util/bug.rs | 0 .../rustc_middle/src}/util/common.rs | 2 - .../rustc_middle/src}/util/common/tests.rs | 0 compiler/rustc_mir/Cargo.toml | 34 + .../rustc_mir/src}/borrow_check/borrow_set.rs | 0 .../borrow_check/constraint_generation.rs | 0 .../src}/borrow_check/constraints/graph.rs | 0 .../src}/borrow_check/constraints/mod.rs | 0 .../rustc_mir/src}/borrow_check/def_use.rs | 3 +- .../diagnostics/conflict_errors.rs | 131 +- .../diagnostics/explain_borrow.rs | 6 +- .../src}/borrow_check/diagnostics/find_use.rs | 0 .../src}/borrow_check/diagnostics/mod.rs | 284 +- .../borrow_check/diagnostics/move_errors.rs | 25 +- .../diagnostics/mutability_errors.rs | 13 +- .../diagnostics/outlives_suggestion.rs | 7 +- .../borrow_check/diagnostics/region_errors.rs | 12 +- .../borrow_check/diagnostics/region_name.rs | 12 +- .../src}/borrow_check/diagnostics/var_name.rs | 0 .../rustc_mir/src}/borrow_check/facts.rs | 0 .../src}/borrow_check/invalidation.rs | 0 .../rustc_mir/src}/borrow_check/location.rs | 0 .../src}/borrow_check/member_constraints.rs | 2 +- .../rustc_mir/src}/borrow_check/mod.rs | 23 +- .../rustc_mir/src}/borrow_check/nll.rs | 0 .../rustc_mir/src}/borrow_check/path_utils.rs | 0 .../rustc_mir/src}/borrow_check/place_ext.rs | 2 +- .../src}/borrow_check/places_conflict.rs | 4 +- .../rustc_mir/src}/borrow_check/prefixes.rs | 3 +- .../borrow_check/region_infer/dump_mir.rs | 0 .../borrow_check/region_infer/graphviz.rs | 0 .../src}/borrow_check/region_infer/mod.rs | 29 +- .../borrow_check/region_infer/opaque_types.rs | 0 .../borrow_check/region_infer/reverse_sccs.rs | 0 .../src}/borrow_check/region_infer/values.rs | 4 +- .../rustc_mir/src}/borrow_check/renumber.rs | 0 .../type_check/constraint_conversion.rs | 3 +- .../type_check/free_region_relations.rs | 0 .../borrow_check/type_check/input_output.rs | 0 .../type_check/liveness/local_use_map.rs | 0 .../borrow_check/type_check/liveness/mod.rs | 0 .../type_check/liveness/polonius.rs | 0 .../borrow_check/type_check/liveness/trace.rs | 0 .../src}/borrow_check/type_check/mod.rs | 40 +- .../borrow_check/type_check/relate_tys.rs | 0 .../src}/borrow_check/universal_regions.rs | 4 +- .../rustc_mir/src}/borrow_check/used_muts.rs | 0 .../rustc_mir/src}/const_eval/error.rs | 0 .../rustc_mir/src}/const_eval/eval_queries.rs | 155 +- .../rustc_mir/src}/const_eval/fn_queries.rs | 8 +- .../rustc_mir/src}/const_eval/machine.rs | 73 +- .../rustc_mir/src}/const_eval/mod.rs | 43 +- .../src}/dataflow/drop_flag_effects.rs | 2 +- .../src}/dataflow/framework/cursor.rs | 41 +- .../src}/dataflow/framework/direction.rs | 170 +- .../src}/dataflow/framework/engine.rs | 137 +- .../rustc_mir/src/dataflow/framework/fmt.rs | 172 + .../src}/dataflow/framework/graphviz.rs | 561 +- .../src/dataflow/framework/lattice.rs | 230 + .../rustc_mir/src}/dataflow/framework/mod.rs | 196 +- .../src}/dataflow/framework/tests.rs | 29 +- .../src}/dataflow/framework/visitor.rs | 13 +- .../src}/dataflow/impls/borrowed_locals.rs | 17 +- .../rustc_mir/src}/dataflow/impls/borrows.rs | 26 +- .../src}/dataflow/impls/init_locals.rs | 19 +- .../rustc_mir/src}/dataflow/impls/liveness.rs | 18 +- .../rustc_mir/src}/dataflow/impls/mod.rs | 238 +- .../src}/dataflow/impls/storage_liveness.rs | 33 +- .../rustc_mir/src}/dataflow/mod.rs | 6 +- .../src}/dataflow/move_paths/abs_domain.rs | 0 .../src}/dataflow/move_paths/builder.rs | 16 +- .../rustc_mir/src}/dataflow/move_paths/mod.rs | 1 - .../rustc_mir/src}/interpret/cast.rs | 18 +- .../rustc_mir/src}/interpret/eval_context.rs | 46 +- .../rustc_mir/src}/interpret/intern.rs | 6 +- .../rustc_mir/src}/interpret/intrinsics.rs | 56 +- .../interpret/intrinsics/caller_location.rs | 0 .../src}/interpret/intrinsics/type_name.rs | 5 +- .../rustc_mir/src}/interpret/machine.rs | 0 .../rustc_mir/src}/interpret/memory.rs | 14 +- .../rustc_mir/src}/interpret/mod.rs | 0 .../rustc_mir/src}/interpret/operand.rs | 18 +- .../rustc_mir/src}/interpret/operator.rs | 4 +- .../rustc_mir/src}/interpret/place.rs | 26 +- .../rustc_mir/src}/interpret/step.rs | 0 .../rustc_mir/src}/interpret/terminator.rs | 17 +- .../rustc_mir/src}/interpret/traits.rs | 0 .../rustc_mir/src}/interpret/util.rs | 4 +- .../rustc_mir/src}/interpret/validity.rs | 76 +- .../rustc_mir/src}/interpret/visitor.rs | 2 +- .../rustc_mir/src}/lib.rs | 15 +- .../rustc_mir/src}/monomorphize/collector.rs | 106 +- .../rustc_mir/src}/monomorphize/mod.rs | 2 +- .../src}/monomorphize/partitioning/default.rs | 38 +- .../src}/monomorphize/partitioning/merging.rs | 19 +- .../src}/monomorphize/partitioning/mod.rs | 48 +- .../src}/monomorphize/polymorphize.rs | 4 +- .../rustc_mir/src}/shim.rs | 68 +- .../src}/transform/add_call_guards.rs | 0 .../transform/add_moves_for_packed_drops.rs | 0 .../rustc_mir/src}/transform/add_retag.rs | 2 +- .../transform/check_const_item_mutation.rs | 147 + .../src/transform/check_consts/mod.rs | 115 + .../src/transform/check_consts/ops.rs | 642 + .../check_consts/post_drop_elaboration.rs | 18 +- .../src}/transform/check_consts/qualifs.rs | 2 +- .../src}/transform/check_consts/resolver.rs | 18 +- .../src}/transform/check_consts/validation.rs | 479 +- .../src}/transform/check_packed_ref.rs | 0 .../src}/transform/check_unsafety.rs | 8 +- .../src}/transform/cleanup_post_borrowck.rs | 0 .../rustc_mir/src}/transform/const_prop.rs | 12 +- .../rustc_mir/src}/transform/copy_prop.rs | 4 +- .../rustc_mir/src}/transform/deaggregator.rs | 0 compiler/rustc_mir/src/transform/dest_prop.rs | 1057 + .../rustc_mir/src}/transform/dump_mir.rs | 0 .../src/transform/early_otherwise_branch.rs | 339 + .../src}/transform/elaborate_drops.rs | 5 +- .../rustc_mir/src}/transform/generator.rs | 13 +- .../rustc_mir/src}/transform/inline.rs | 74 +- .../rustc_mir/src/transform/instcombine.rs | 285 + .../src/transform/instrument_coverage.rs | 491 + .../src}/transform/match_branches.rs | 7 + .../rustc_mir/src}/transform/mod.rs | 24 +- .../transform/multiple_return_terminators.rs | 38 + .../src}/transform/no_landing_pads.rs | 0 .../rustc_mir/src}/transform/nrvo.rs | 15 +- .../src}/transform/promote_consts.rs | 102 +- .../transform/remove_noop_landing_pads.rs | 19 +- .../src/transform/remove_unneeded_drops.rs | 58 + .../src}/transform/required_consts.rs | 0 .../rustc_mir/src}/transform/rustc_peek.rs | 21 +- .../rustc_mir/src}/transform/simplify.rs | 3 +- .../src}/transform/simplify_branches.rs | 0 .../transform/simplify_comparison_integral.rs | 227 + .../rustc_mir/src}/transform/simplify_try.rs | 68 +- .../transform/uninhabited_enum_branching.rs | 0 .../src}/transform/unreachable_prop.rs | 0 .../rustc_mir/src}/transform/validate.rs | 169 +- .../rustc_mir/src}/util/aggregate.rs | 6 +- .../rustc_mir/src}/util/alignment.rs | 2 +- .../rustc_mir/src}/util/borrowck_errors.rs | 2 +- .../rustc_mir/src}/util/collect_writes.rs | 0 .../rustc_mir/src}/util/def_use.rs | 0 .../rustc_mir/src}/util/elaborate_drops.rs | 9 +- compiler/rustc_mir/src/util/find_self_call.rs | 36 + .../rustc_mir/src}/util/graphviz.rs | 29 +- .../rustc_mir/src}/util/mod.rs | 3 + .../rustc_mir/src}/util/patch.rs | 0 .../rustc_mir/src}/util/pretty.rs | 24 +- compiler/rustc_mir/src/util/spanview.rs | 672 + .../rustc_mir/src}/util/storage.rs | 0 compiler/rustc_mir_build/Cargo.toml | 27 + .../rustc_mir_build/src}/build/block.rs | 3 +- .../rustc_mir_build/src}/build/cfg.rs | 0 .../src}/build/expr/as_constant.rs | 2 +- .../src}/build/expr/as_operand.rs | 0 .../src}/build/expr/as_place.rs | 4 +- .../src}/build/expr/as_rvalue.rs | 0 .../src}/build/expr/as_temp.rs | 3 + .../src}/build/expr/category.rs | 0 .../rustc_mir_build/src}/build/expr/into.rs | 2 +- .../rustc_mir_build/src}/build/expr/mod.rs | 0 .../rustc_mir_build/src}/build/expr/stmt.rs | 0 .../rustc_mir_build/src}/build/into.rs | 0 .../rustc_mir_build/src}/build/matches/mod.rs | 8 +- .../src}/build/matches/simplify.rs | 2 +- .../src}/build/matches/test.rs | 8 +- .../src}/build/matches/util.rs | 12 +- .../rustc_mir_build/src}/build/misc.rs | 0 .../rustc_mir_build/src}/build/mod.rs | 12 +- .../rustc_mir_build/src}/build/scope.rs | 0 .../rustc_mir_build/src}/lib.rs | 3 +- .../rustc_mir_build/src}/lints.rs | 8 +- .../rustc_mir_build/src}/thir/constant.rs | 12 +- .../rustc_mir_build/src}/thir/cx/block.rs | 0 .../rustc_mir_build/src}/thir/cx/expr.rs | 58 +- .../rustc_mir_build/src}/thir/cx/mod.rs | 0 .../rustc_mir_build/src}/thir/cx/to_ref.rs | 0 .../rustc_mir_build/src}/thir/mod.rs | 4 + .../src}/thir/pattern/_match.rs | 307 +- .../src}/thir/pattern/check_match.rs | 10 +- .../src/thir/pattern/const_to_pat.rs | 535 + .../rustc_mir_build/src}/thir/pattern/mod.rs | 26 +- .../rustc_mir_build/src}/thir/util.rs | 2 +- compiler/rustc_parse/Cargo.toml | 22 + .../rustc_parse/src}/lexer/mod.rs | 186 +- .../rustc_parse/src}/lexer/tokentrees.rs | 57 +- .../src}/lexer/unescape_error_reporting.rs | 0 .../rustc_parse/src}/lexer/unicode_chars.rs | 4 +- .../rustc_parse/src}/lib.rs | 140 +- .../rustc_parse/src}/parser/attr.rs | 2 +- .../rustc_parse/src}/parser/diagnostics.rs | 57 +- .../rustc_parse/src}/parser/expr.rs | 42 +- .../rustc_parse/src}/parser/generics.rs | 0 .../rustc_parse/src}/parser/item.rs | 84 +- .../rustc_parse/src}/parser/mod.rs | 51 +- .../rustc_parse/src}/parser/nonterminal.rs | 75 +- .../rustc_parse/src}/parser/pat.rs | 3 +- .../rustc_parse/src}/parser/path.rs | 9 +- .../rustc_parse/src}/parser/stmt.rs | 37 +- .../rustc_parse/src}/parser/ty.rs | 32 +- .../rustc_parse/src}/validate_attr.rs | 0 compiler/rustc_parse_format/Cargo.toml | 9 + .../rustc_parse_format/src}/lib.rs | 15 +- .../rustc_parse_format/src}/tests.rs | 0 compiler/rustc_passes/Cargo.toml | 20 + .../rustc_passes/src}/check_attr.rs | 353 +- .../rustc_passes/src}/check_const.rs | 0 .../rustc_passes/src}/dead.rs | 13 +- .../rustc_passes/src}/diagnostic_items.rs | 14 +- .../rustc_passes/src}/entry.rs | 0 .../rustc_passes/src}/hir_id_validator.rs | 8 +- .../rustc_passes/src}/hir_stats.rs | 0 .../rustc_passes/src}/intrinsicck.rs | 12 +- .../rustc_passes/src}/lang_items.rs | 0 .../rustc_passes/src}/layout_test.rs | 0 .../rustc_passes/src}/lib.rs | 4 +- .../rustc_passes/src}/lib_features.rs | 0 .../rustc_passes/src}/liveness.rs | 657 +- .../rustc_passes/src}/loops.rs | 0 .../rustc_passes/src}/reachable.rs | 0 .../rustc_passes/src}/region.rs | 0 .../rustc_passes/src}/stability.rs | 259 +- .../rustc_passes/src}/upvars.rs | 0 .../rustc_passes/src}/weak_lang_items.rs | 3 + compiler/rustc_plugin_impl/Cargo.toml | 19 + .../rustc_plugin_impl/src}/build.rs | 0 .../rustc_plugin_impl/src}/lib.rs | 2 +- .../rustc_plugin_impl/src}/load.rs | 0 compiler/rustc_privacy/Cargo.toml | 16 + .../rustc_privacy/src}/lib.rs | 16 +- compiler/rustc_query_system/Cargo.toml | 21 + .../rustc_query_system/src}/cache.rs | 0 .../src}/dep_graph/README.md | 0 .../src}/dep_graph/debug.rs | 0 .../src}/dep_graph/dep_node.rs | 0 .../src}/dep_graph/graph.rs | 0 .../rustc_query_system/src}/dep_graph/mod.rs | 0 .../rustc_query_system/src}/dep_graph/prev.rs | 0 .../src}/dep_graph/query.rs | 0 .../src}/dep_graph/serialized.rs | 0 .../rustc_query_system/src}/lib.rs | 0 .../rustc_query_system/src}/query/README.md | 0 .../rustc_query_system/src}/query/caches.rs | 0 .../rustc_query_system/src}/query/config.rs | 0 .../rustc_query_system/src}/query/job.rs | 0 .../rustc_query_system/src}/query/mod.rs | 0 .../rustc_query_system/src}/query/plumbing.rs | 0 compiler/rustc_resolve/Cargo.toml | 29 + .../rustc_resolve/src}/build_reduced_graph.rs | 21 +- .../rustc_resolve/src}/check_unused.rs | 2 +- .../rustc_resolve/src}/def_collector.rs | 0 .../rustc_resolve/src}/diagnostics.rs | 20 +- .../rustc_resolve/src}/imports.rs | 15 +- .../rustc_resolve/src}/late.rs | 48 +- .../rustc_resolve/src}/late/diagnostics.rs | 111 +- .../rustc_resolve/src}/late/lifetimes.rs | 4 + .../rustc_resolve/src}/lib.rs | 76 +- .../rustc_resolve/src}/macros.rs | 22 +- compiler/rustc_save_analysis/Cargo.toml | 20 + .../rustc_save_analysis/src}/dump_visitor.rs | 6 +- .../rustc_save_analysis/src}/dumper.rs | 0 .../rustc_save_analysis/src}/lib.rs | 58 +- .../rustc_save_analysis/src}/sig.rs | 2 +- .../rustc_save_analysis/src}/span_utils.rs | 84 +- .../rustc_serialize}/Cargo.toml | 6 +- .../rustc_serialize/src}/collection_impls.rs | 0 .../rustc_serialize/src}/json.rs | 0 .../rustc_serialize/src}/json/tests.rs | 0 .../rustc_serialize/src}/leb128.rs | 0 .../rustc_serialize/src}/lib.rs | 3 +- .../rustc_serialize/src}/opaque.rs | 0 .../rustc_serialize/src}/serialize.rs | 34 +- .../rustc_serialize}/tests/json.rs | 0 .../rustc_serialize}/tests/leb128.rs | 0 .../rustc_serialize}/tests/opaque.rs | 0 compiler/rustc_session/Cargo.toml | 20 + .../rustc_session/src}/cgu_reuse_tracker.rs | 0 .../rustc_session/src}/code_stats.rs | 0 .../rustc_session/src}/config.rs | 96 +- .../rustc_session/src}/filesearch.rs | 2 - .../rustc_session/src}/lib.rs | 1 + .../rustc_session/src}/lint.rs | 58 +- compiler/rustc_session/src/lint/builtin.rs | 2783 +++ .../rustc_session/src}/options.rs | 73 +- .../rustc_session/src}/output.rs | 0 .../rustc_session/src}/parse.rs | 0 .../rustc_session/src}/search_paths.rs | 20 +- .../rustc_session/src}/session.rs | 87 +- .../rustc_session/src}/utils.rs | 0 compiler/rustc_span/Cargo.toml | 21 + .../rustc_span/src}/analyze_source_file.rs | 0 .../src}/analyze_source_file/tests.rs | 0 .../src}/caching_source_map_view.rs | 0 .../rustc_span/src}/def_id.rs | 0 .../rustc_span/src}/edition.rs | 0 .../rustc_span/src}/fatal_error.rs | 0 .../rustc_span/src}/hygiene.rs | 4 +- .../rustc_span/src}/lib.rs | 178 +- .../rustc_span/src}/source_map.rs | 9 + .../rustc_span/src}/source_map/tests.rs | 0 .../rustc_span/src}/span_encoding.rs | 0 .../rustc_span/src}/symbol.rs | 23 +- .../rustc_span/src}/symbol/tests.rs | 0 .../rustc_span/src}/tests.rs | 0 compiler/rustc_symbol_mangling/Cargo.toml | 21 + .../rustc_symbol_mangling/src}/legacy.rs | 9 +- .../rustc_symbol_mangling/src}/lib.rs | 2 +- .../rustc_symbol_mangling/src}/test.rs | 0 .../rustc_symbol_mangling/src}/v0.rs | 14 +- compiler/rustc_target/Cargo.toml | 14 + .../rustc_target}/README.md | 0 .../rustc_target/src}/abi/call/aarch64.rs | 0 .../rustc_target/src}/abi/call/amdgpu.rs | 0 .../rustc_target/src}/abi/call/arm.rs | 0 .../rustc_target/src}/abi/call/avr.rs | 0 .../rustc_target/src}/abi/call/hexagon.rs | 0 .../rustc_target/src}/abi/call/mips.rs | 0 .../rustc_target/src}/abi/call/mips64.rs | 0 .../rustc_target/src}/abi/call/mod.rs | 12 + .../rustc_target/src}/abi/call/msp430.rs | 0 .../rustc_target/src}/abi/call/nvptx.rs | 0 .../rustc_target/src}/abi/call/nvptx64.rs | 0 .../rustc_target/src}/abi/call/powerpc.rs | 0 .../rustc_target/src}/abi/call/powerpc64.rs | 0 .../rustc_target/src}/abi/call/riscv.rs | 0 .../rustc_target/src}/abi/call/s390x.rs | 0 .../rustc_target/src}/abi/call/sparc.rs | 0 .../rustc_target/src}/abi/call/sparc64.rs | 0 .../rustc_target/src}/abi/call/wasm32.rs | 0 .../src}/abi/call/wasm32_bindgen_compat.rs | 0 .../rustc_target/src}/abi/call/x86.rs | 0 .../rustc_target/src}/abi/call/x86_64.rs | 0 .../rustc_target/src}/abi/call/x86_win64.rs | 0 .../rustc_target/src}/abi/mod.rs | 23 +- .../rustc_target/src}/asm/aarch64.rs | 0 .../rustc_target/src}/asm/arm.rs | 0 .../rustc_target/src}/asm/hexagon.rs | 0 compiler/rustc_target/src/asm/mips.rs | 132 + .../rustc_target/src}/asm/mod.rs | 25 + .../rustc_target/src}/asm/nvptx.rs | 0 .../rustc_target/src}/asm/riscv.rs | 0 .../rustc_target/src}/asm/x86.rs | 0 .../rustc_target/src}/lib.rs | 2 +- .../src}/spec/aarch64_apple_darwin.rs | 0 .../src}/spec/aarch64_apple_ios.rs | 4 +- .../src}/spec/aarch64_apple_tvos.rs | 4 +- .../rustc_target/src}/spec/aarch64_fuchsia.rs | 0 .../src}/spec/aarch64_linux_android.rs | 0 .../src}/spec/aarch64_pc_windows_msvc.rs | 0 .../src}/spec/aarch64_unknown_cloudabi.rs | 0 .../src}/spec/aarch64_unknown_freebsd.rs | 0 .../src}/spec/aarch64_unknown_hermit.rs | 6 +- .../src}/spec/aarch64_unknown_linux_gnu.rs | 0 .../src}/spec/aarch64_unknown_linux_musl.rs | 0 .../src}/spec/aarch64_unknown_netbsd.rs | 0 .../src}/spec/aarch64_unknown_none.rs | 0 .../spec/aarch64_unknown_none_softfloat.rs | 0 .../src}/spec/aarch64_unknown_openbsd.rs | 0 .../src}/spec/aarch64_unknown_redox.rs | 0 .../src}/spec/aarch64_uwp_windows_msvc.rs | 0 .../src}/spec/aarch64_wrs_vxworks.rs | 0 .../rustc_target/src}/spec/abi.rs | 0 .../rustc_target/src}/spec/abi/tests.rs | 0 .../rustc_target/src}/spec/android_base.rs | 0 .../rustc_target/src}/spec/apple_base.rs | 0 .../rustc_target/src/spec/apple_sdk_base.rs | 43 + .../rustc_target/src}/spec/arm_base.rs | 0 .../src}/spec/arm_linux_androideabi.rs | 0 .../src}/spec/arm_unknown_linux_gnueabi.rs | 0 .../src}/spec/arm_unknown_linux_gnueabihf.rs | 0 .../src}/spec/arm_unknown_linux_musleabi.rs | 0 .../src}/spec/arm_unknown_linux_musleabihf.rs | 0 .../src}/spec/armebv7r_none_eabi.rs | 0 .../src}/spec/armebv7r_none_eabihf.rs | 0 .../src}/spec/armv4t_unknown_linux_gnueabi.rs | 0 .../spec/armv5te_unknown_linux_gnueabi.rs | 0 .../spec/armv5te_unknown_linux_musleabi.rs | 0 .../src}/spec/armv6_unknown_freebsd.rs | 0 .../src}/spec/armv6_unknown_netbsd_eabihf.rs | 0 .../rustc_target/src}/spec/armv7_apple_ios.rs | 4 +- .../src}/spec/armv7_linux_androideabi.rs | 0 .../spec/armv7_unknown_cloudabi_eabihf.rs | 0 .../src}/spec/armv7_unknown_freebsd.rs | 0 .../src}/spec/armv7_unknown_linux_gnueabi.rs | 0 .../spec/armv7_unknown_linux_gnueabihf.rs | 0 .../src}/spec/armv7_unknown_linux_musleabi.rs | 0 .../spec/armv7_unknown_linux_musleabihf.rs | 0 .../src}/spec/armv7_unknown_netbsd_eabihf.rs | 0 .../src}/spec/armv7_wrs_vxworks_eabihf.rs | 0 .../src}/spec/armv7a_none_eabi.rs | 0 .../src}/spec/armv7a_none_eabihf.rs | 0 .../src}/spec/armv7r_none_eabi.rs | 0 .../src}/spec/armv7r_none_eabihf.rs | 0 .../src}/spec/armv7s_apple_ios.rs | 4 +- .../src}/spec/asmjs_unknown_emscripten.rs | 0 .../rustc_target/src/spec/avr_gnu_base.rs | 53 + .../src/spec/avr_unknown_gnu_atmega328.rs | 5 + .../rustc_target/src}/spec/cloudabi_base.rs | 0 .../rustc_target/src}/spec/crt_objects.rs | 0 .../rustc_target/src}/spec/dragonfly_base.rs | 0 .../rustc_target/src}/spec/freebsd_base.rs | 0 .../rustc_target/src}/spec/fuchsia_base.rs | 0 .../rustc_target/src}/spec/haiku_base.rs | 0 .../rustc_target/src}/spec/hermit_base.rs | 3 +- .../src}/spec/hermit_kernel_base.rs | 3 +- .../src}/spec/hexagon_unknown_linux_musl.rs | 0 .../rustc_target/src}/spec/i386_apple_ios.rs | 4 +- .../src}/spec/i586_pc_windows_msvc.rs | 0 .../src}/spec/i586_unknown_linux_gnu.rs | 0 .../src}/spec/i586_unknown_linux_musl.rs | 0 .../src}/spec/i686_apple_darwin.rs | 0 .../src}/spec/i686_linux_android.rs | 0 .../src}/spec/i686_pc_windows_gnu.rs | 0 .../src}/spec/i686_pc_windows_msvc.rs | 0 .../src}/spec/i686_unknown_cloudabi.rs | 0 .../src}/spec/i686_unknown_freebsd.rs | 0 .../src}/spec/i686_unknown_haiku.rs | 0 .../src}/spec/i686_unknown_linux_gnu.rs | 0 .../src}/spec/i686_unknown_linux_musl.rs | 0 .../src}/spec/i686_unknown_netbsd.rs | 0 .../src}/spec/i686_unknown_openbsd.rs | 0 .../src}/spec/i686_unknown_uefi.rs | 0 .../src}/spec/i686_uwp_windows_gnu.rs | 0 .../src}/spec/i686_uwp_windows_msvc.rs | 0 .../src}/spec/i686_wrs_vxworks.rs | 0 .../rustc_target/src}/spec/illumos_base.rs | 0 .../rustc_target/src}/spec/l4re_base.rs | 0 .../rustc_target/src}/spec/linux_base.rs | 0 .../src}/spec/linux_kernel_base.rs | 0 .../rustc_target/src}/spec/linux_musl_base.rs | 0 .../spec/mips64_unknown_linux_gnuabi64.rs | 0 .../spec/mips64_unknown_linux_muslabi64.rs | 0 .../spec/mips64el_unknown_linux_gnuabi64.rs | 0 .../spec/mips64el_unknown_linux_muslabi64.rs | 0 .../src}/spec/mips_unknown_linux_gnu.rs | 0 .../src}/spec/mips_unknown_linux_musl.rs | 0 .../src}/spec/mips_unknown_linux_uclibc.rs | 0 .../rustc_target/src}/spec/mipsel_sony_psp.rs | 0 .../spec/mipsel_sony_psp_linker_script.ld | 0 .../src}/spec/mipsel_unknown_linux_gnu.rs | 0 .../src}/spec/mipsel_unknown_linux_musl.rs | 0 .../src}/spec/mipsel_unknown_linux_uclibc.rs | 0 .../spec/mipsisa32r6_unknown_linux_gnu.rs | 0 .../spec/mipsisa32r6el_unknown_linux_gnu.rs | 0 .../mipsisa64r6_unknown_linux_gnuabi64.rs | 0 .../mipsisa64r6el_unknown_linux_gnuabi64.rs | 0 .../rustc_target/src}/spec/mod.rs | 5 +- .../rustc_target/src}/spec/msp430_none_elf.rs | 0 .../rustc_target/src}/spec/msvc_base.rs | 0 .../rustc_target/src}/spec/netbsd_base.rs | 0 .../src}/spec/nvptx64_nvidia_cuda.rs | 0 .../rustc_target/src}/spec/openbsd_base.rs | 0 .../src}/spec/powerpc64_unknown_freebsd.rs | 0 .../src}/spec/powerpc64_unknown_linux_gnu.rs | 0 .../src}/spec/powerpc64_unknown_linux_musl.rs | 0 .../src}/spec/powerpc64_wrs_vxworks.rs | 0 .../spec/powerpc64le_unknown_linux_gnu.rs | 0 .../spec/powerpc64le_unknown_linux_musl.rs | 0 .../src}/spec/powerpc_unknown_linux_gnu.rs | 0 .../src}/spec/powerpc_unknown_linux_gnuspe.rs | 0 .../src}/spec/powerpc_unknown_linux_musl.rs | 0 .../src}/spec/powerpc_unknown_netbsd.rs | 0 .../src}/spec/powerpc_wrs_vxworks.rs | 0 .../src}/spec/powerpc_wrs_vxworks_spe.rs | 0 .../rustc_target/src}/spec/redox_base.rs | 0 .../src/spec/riscv32gc_unknown_linux_gnu.rs | 25 + .../src}/spec/riscv32i_unknown_none_elf.rs | 0 .../src}/spec/riscv32imac_unknown_none_elf.rs | 0 .../src}/spec/riscv32imc_unknown_none_elf.rs | 0 .../src}/spec/riscv64gc_unknown_linux_gnu.rs | 0 .../src}/spec/riscv64gc_unknown_none_elf.rs | 0 .../src}/spec/riscv64imac_unknown_none_elf.rs | 0 .../rustc_target/src}/spec/riscv_base.rs | 0 .../src}/spec/s390x_unknown_linux_gnu.rs | 0 .../rustc_target/src}/spec/solaris_base.rs | 0 .../src}/spec/sparc64_unknown_linux_gnu.rs | 0 .../src}/spec/sparc64_unknown_netbsd.rs | 0 .../src}/spec/sparc64_unknown_openbsd.rs | 0 .../src}/spec/sparc_unknown_linux_gnu.rs | 0 .../src}/spec/sparcv9_sun_solaris.rs | 0 .../src}/spec/tests/tests_impl.rs | 0 .../rustc_target/src}/spec/thumb_base.rs | 0 .../src}/spec/thumbv4t_none_eabi.rs | 0 .../src}/spec/thumbv6m_none_eabi.rs | 0 .../src}/spec/thumbv7a_pc_windows_msvc.rs | 0 .../src}/spec/thumbv7a_uwp_windows_msvc.rs | 0 .../src}/spec/thumbv7em_none_eabi.rs | 0 .../src}/spec/thumbv7em_none_eabihf.rs | 0 .../src}/spec/thumbv7m_none_eabi.rs | 0 .../spec/thumbv7neon_linux_androideabi.rs | 0 .../thumbv7neon_unknown_linux_gnueabihf.rs | 0 .../thumbv7neon_unknown_linux_musleabihf.rs | 0 .../src}/spec/thumbv8m_base_none_eabi.rs | 0 .../src}/spec/thumbv8m_main_none_eabi.rs | 0 .../src}/spec/thumbv8m_main_none_eabihf.rs | 0 .../rustc_target/src}/spec/uefi_msvc_base.rs | 0 .../rustc_target/src}/spec/vxworks_base.rs | 0 .../rustc_target/src}/spec/wasm32_base.rs | 1 + .../src}/spec/wasm32_unknown_emscripten.rs | 0 .../src}/spec/wasm32_unknown_unknown.rs | 0 .../rustc_target/src}/spec/wasm32_wasi.rs | 2 +- .../src}/spec/windows_gnu_base.rs | 7 +- .../src}/spec/windows_msvc_base.rs | 0 .../src}/spec/windows_uwp_gnu_base.rs | 2 +- .../src}/spec/windows_uwp_msvc_base.rs | 0 .../src}/spec/x86_64_apple_darwin.rs | 0 .../src}/spec/x86_64_apple_ios.rs | 4 +- .../src}/spec/x86_64_apple_ios_macabi.rs | 4 +- .../src}/spec/x86_64_apple_tvos.rs | 4 +- .../src}/spec/x86_64_fortanix_unknown_sgx.rs | 0 .../rustc_target/src}/spec/x86_64_fuchsia.rs | 0 .../src}/spec/x86_64_linux_android.rs | 0 .../src}/spec/x86_64_linux_kernel.rs | 0 .../src}/spec/x86_64_pc_windows_gnu.rs | 0 .../src}/spec/x86_64_pc_windows_msvc.rs | 0 .../src}/spec/x86_64_rumprun_netbsd.rs | 0 .../src}/spec/x86_64_sun_solaris.rs | 0 .../src}/spec/x86_64_unknown_cloudabi.rs | 0 .../src}/spec/x86_64_unknown_dragonfly.rs | 0 .../src}/spec/x86_64_unknown_freebsd.rs | 0 .../src}/spec/x86_64_unknown_haiku.rs | 0 .../src}/spec/x86_64_unknown_hermit.rs | 0 .../src}/spec/x86_64_unknown_hermit_kernel.rs | 0 .../src}/spec/x86_64_unknown_illumos.rs | 0 .../src}/spec/x86_64_unknown_l4re_uclibc.rs | 0 .../src}/spec/x86_64_unknown_linux_gnu.rs | 0 .../src}/spec/x86_64_unknown_linux_gnux32.rs | 0 .../src}/spec/x86_64_unknown_linux_musl.rs | 0 .../src}/spec/x86_64_unknown_netbsd.rs | 0 .../src}/spec/x86_64_unknown_openbsd.rs | 0 .../src}/spec/x86_64_unknown_redox.rs | 0 .../src}/spec/x86_64_unknown_uefi.rs | 0 .../src}/spec/x86_64_uwp_windows_gnu.rs | 0 .../src}/spec/x86_64_uwp_windows_msvc.rs | 0 .../src}/spec/x86_64_wrs_vxworks.rs | 0 compiler/rustc_trait_selection/Cargo.toml | 25 + .../rustc_trait_selection/src}/autoderef.rs | 7 + .../rustc_trait_selection/src}/infer.rs | 0 .../rustc_trait_selection/src}/lib.rs | 4 +- .../src}/opaque_types.rs | 11 +- .../src}/traits/auto_trait.rs | 16 +- .../src/traits/chalk_fulfill.rs | 143 + .../src}/traits/codegen/mod.rs | 5 +- .../src}/traits/coherence.rs | 8 +- .../src/traits/const_evaluatable.rs | 593 + .../src}/traits/engine.rs | 0 .../src}/traits/error_reporting/mod.rs | 104 +- .../error_reporting/on_unimplemented.rs | 4 +- .../traits/error_reporting/suggestions.rs | 33 +- .../src}/traits/fulfill.rs | 98 +- .../rustc_trait_selection/src}/traits/misc.rs | 2 +- .../rustc_trait_selection/src}/traits/mod.rs | 32 +- .../src}/traits/object_safety.rs | 34 +- .../src}/traits/on_unimplemented.rs | 0 .../src}/traits/project.rs | 50 +- .../src}/traits/query/dropck_outlives.rs | 2 +- .../src}/traits/query/evaluate_obligation.rs | 0 .../src}/traits/query/method_autoderef.rs | 0 .../src}/traits/query/mod.rs | 0 .../src}/traits/query/normalize.rs | 4 +- .../src}/traits/query/outlives_bounds.rs | 0 .../traits/query/type_op/ascribe_user_type.rs | 0 .../src}/traits/query/type_op/custom.rs | 0 .../src}/traits/query/type_op/eq.rs | 0 .../query/type_op/implied_outlives_bounds.rs | 0 .../src}/traits/query/type_op/mod.rs | 0 .../src}/traits/query/type_op/normalize.rs | 0 .../src}/traits/query/type_op/outlives.rs | 0 .../traits/query/type_op/prove_predicate.rs | 0 .../src}/traits/query/type_op/subtype.rs | 0 .../src}/traits/select/candidate_assembly.rs | 176 +- .../src}/traits/select/confirmation.rs | 44 +- .../src}/traits/select/mod.rs | 430 +- .../src}/traits/specialize/mod.rs | 0 .../traits/specialize/specialization_graph.rs | 6 +- .../src}/traits/structural_match.rs | 2 +- .../rustc_trait_selection/src}/traits/util.rs | 0 .../rustc_trait_selection/src}/traits/wf.rs | 33 +- compiler/rustc_traits/Cargo.toml | 20 + .../rustc_traits/src}/chalk/db.rs | 401 +- .../rustc_traits/src}/chalk/lowering.rs | 656 +- compiler/rustc_traits/src/chalk/mod.rs | 159 + .../rustc_traits/src}/dropck_outlives.rs | 4 +- .../rustc_traits/src}/evaluate_obligation.rs | 0 .../src}/implied_outlives_bounds.rs | 3 +- .../rustc_traits/src}/lib.rs | 1 - .../src}/normalize_erasing_regions.rs | 3 +- .../src}/normalize_projection_ty.rs | 0 .../rustc_traits/src}/type_op.rs | 0 compiler/rustc_ty/Cargo.toml | 17 + .../rustc_ty/src}/common_traits.rs | 0 .../rustc_ty/src}/instance.rs | 28 +- .../rustc_ty/src}/lib.rs | 3 +- .../rustc_ty/src}/needs_drop.rs | 4 +- .../rustc_ty/src}/ty.rs | 152 +- compiler/rustc_typeck/Cargo.toml | 28 + .../rustc_typeck}/README.md | 0 .../rustc_typeck/src}/astconv/errors.rs | 0 .../rustc_typeck/src}/astconv/generics.rs | 85 +- .../rustc_typeck/src}/astconv/mod.rs | 100 +- .../rustc_typeck/src}/bounds.rs | 0 .../rustc_typeck/src}/check/_match.rs | 90 +- .../rustc_typeck/src}/check/autoderef.rs | 21 +- .../rustc_typeck/src}/check/callee.rs | 16 +- .../rustc_typeck/src}/check/cast.rs | 18 +- compiler/rustc_typeck/src/check/check.rs | 1345 + .../rustc_typeck/src}/check/closure.rs | 6 +- .../rustc_typeck/src}/check/coercion.rs | 75 +- .../rustc_typeck/src}/check/compare_method.rs | 43 +- .../rustc_typeck/src}/check/demand.rs | 50 +- compiler/rustc_typeck/src/check/diverges.rs | 78 + .../rustc_typeck/src}/check/dropck.rs | 2 +- .../rustc_typeck/src/check/expectation.rs | 117 + .../rustc_typeck/src}/check/expr.rs | 352 +- .../rustc_typeck/src/check/fn_ctxt.rs | 3406 +-- .../rustc_typeck/src/check/gather_locals.rs | 120 + .../src}/check/generator_interior.rs | 0 compiler/rustc_typeck/src/check/inherited.rs | 167 + .../rustc_typeck/src}/check/intrinsic.rs | 51 +- .../rustc_typeck/src}/check/method/confirm.rs | 7 +- .../rustc_typeck/src}/check/method/mod.rs | 4 +- .../rustc_typeck/src}/check/method/probe.rs | 37 +- .../rustc_typeck/src}/check/method/suggest.rs | 83 +- compiler/rustc_typeck/src/check/mod.rs | 1151 + .../rustc_typeck/src}/check/op.rs | 42 +- .../rustc_typeck/src}/check/pat.rs | 257 +- .../rustc_typeck/src}/check/place_op.rs | 39 +- .../rustc_typeck/src}/check/regionck.rs | 8 +- .../rustc_typeck/src}/check/upvar.rs | 43 +- .../rustc_typeck/src}/check/wfcheck.rs | 18 +- .../rustc_typeck/src}/check/writeback.rs | 23 +- .../rustc_typeck/src}/check_unused.rs | 0 .../rustc_typeck/src}/coherence/builtin.rs | 35 +- .../src}/coherence/inherent_impls.rs | 31 +- .../src}/coherence/inherent_impls_overlap.rs | 0 .../rustc_typeck/src}/coherence/mod.rs | 2 +- .../rustc_typeck/src}/coherence/orphan.rs | 14 +- .../rustc_typeck/src}/coherence/unsafety.rs | 0 .../rustc_typeck/src}/collect.rs | 237 +- .../rustc_typeck/src}/collect/type_of.rs | 23 +- .../src}/constrained_generic_params.rs | 2 +- compiler/rustc_typeck/src/errors.rs | 199 + .../rustc_typeck/src}/expr_use_visitor.rs | 4 +- .../rustc_typeck/src}/impl_wf_check.rs | 18 +- .../src}/impl_wf_check/min_specialization.rs | 3 +- .../rustc_typeck/src}/lib.rs | 10 +- .../rustc_typeck/src}/mem_categorization.rs | 8 +- .../rustc_typeck/src}/outlives/explicit.rs | 3 +- .../src}/outlives/implicit_infer.rs | 2 +- .../rustc_typeck/src}/outlives/mod.rs | 0 .../rustc_typeck/src}/outlives/test.rs | 0 .../rustc_typeck/src}/outlives/utils.rs | 0 .../rustc_typeck/src}/structured_errors.rs | 0 .../rustc_typeck/src}/variance/constraints.rs | 4 +- .../rustc_typeck/src}/variance/mod.rs | 0 .../rustc_typeck/src}/variance/solve.rs | 2 +- .../rustc_typeck/src}/variance/terms.rs | 0 .../rustc_typeck/src}/variance/test.rs | 0 .../rustc_typeck/src}/variance/xform.rs | 0 config.toml.example | 90 +- git-commit-hash | 2 +- library/alloc/benches/binary_heap.rs | 91 + library/alloc/benches/lib.rs | 1 + library/alloc/benches/vec.rs | 244 +- library/alloc/src/alloc.rs | 121 +- library/alloc/src/borrow.rs | 6 +- library/alloc/src/boxed.rs | 8 +- library/alloc/src/collections/binary_heap.rs | 77 +- library/alloc/src/collections/btree/borrow.rs | 47 + .../src/collections/btree/borrow/tests.rs | 19 + library/alloc/src/collections/btree/map.rs | 335 +- .../alloc/src/collections/btree/map/tests.rs | 174 +- library/alloc/src/collections/btree/mod.rs | 4 + .../alloc/src/collections/btree/navigate.rs | 322 +- library/alloc/src/collections/btree/node.rs | 687 +- .../alloc/src/collections/btree/node/tests.rs | 9 + library/alloc/src/collections/btree/search.rs | 6 +- library/alloc/src/collections/linked_list.rs | 2 +- library/alloc/src/collections/vec_deque.rs | 108 +- .../alloc/src/collections/vec_deque/drain.rs | 3 +- library/alloc/src/lib.rs | 23 +- library/alloc/src/raw_vec.rs | 50 +- library/alloc/src/raw_vec/tests.rs | 21 +- library/alloc/src/rc.rs | 169 +- library/alloc/src/rc/tests.rs | 66 + library/alloc/src/slice.rs | 6 + library/alloc/src/string.rs | 57 +- library/alloc/src/sync.rs | 10 +- library/alloc/src/task.rs | 2 + library/alloc/src/vec.rs | 595 +- library/alloc/tests/binary_heap.rs | 12 + library/alloc/tests/borrow.rs | 13 + library/alloc/tests/boxed.rs | 8 + library/alloc/tests/fmt.rs | 322 +- library/alloc/tests/heap.rs | 2 +- library/alloc/tests/lib.rs | 6 + library/alloc/tests/slice.rs | 9 + library/alloc/tests/str.rs | 21 + library/alloc/tests/string.rs | 50 +- library/alloc/tests/vec.rs | 286 +- library/alloc/tests/vec_deque.rs | 15 + .../benches/num/flt2dec/strategy/dragon.rs | 49 +- .../benches/num/flt2dec/strategy/grisu.rs | 49 +- library/core/src/alloc/layout.rs | 1 + library/core/src/alloc/mod.rs | 186 +- library/core/src/array/iter.rs | 8 +- library/core/src/array/mod.rs | 30 +- library/core/src/ascii.rs | 4 - library/core/src/cell.rs | 104 +- library/core/src/clone.rs | 13 +- library/core/src/cmp.rs | 12 +- library/core/src/convert/mod.rs | 54 +- library/core/src/fmt/float.rs | 116 +- library/core/src/fmt/mod.rs | 7 +- library/core/src/fmt/num.rs | 11 +- library/core/src/future/future.rs | 12 +- library/core/src/future/mod.rs | 11 +- library/core/src/future/pending.rs | 24 +- library/core/src/future/poll_fn.rs | 4 +- library/core/src/future/ready.rs | 17 +- library/core/src/hash/mod.rs | 31 +- library/core/src/hint.rs | 12 +- library/core/src/intrinsics.rs | 25 +- library/core/src/iter/adapters/chain.rs | 16 +- library/core/src/iter/adapters/flatten.rs | 7 +- library/core/src/iter/adapters/fuse.rs | 33 +- library/core/src/iter/adapters/mod.rs | 370 +- library/core/src/iter/adapters/zip.rs | 60 +- library/core/src/iter/mod.rs | 90 +- library/core/src/iter/sources.rs | 76 +- library/core/src/iter/traits/accum.rs | 46 +- library/core/src/iter/traits/collect.rs | 22 +- library/core/src/iter/traits/double_ended.rs | 100 +- library/core/src/iter/traits/exact_size.rs | 23 +- library/core/src/iter/traits/iterator.rs | 237 +- library/core/src/iter/traits/marker.rs | 26 +- library/core/src/iter/traits/mod.rs | 2 + library/core/src/lazy.rs | 8 +- library/core/src/lib.rs | 56 +- library/core/src/macros/mod.rs | 12 +- library/core/src/macros/panic.md | 16 +- library/core/src/marker.rs | 89 +- library/core/src/mem/manually_drop.rs | 61 +- library/core/src/mem/maybe_uninit.rs | 132 +- library/core/src/mem/mod.rs | 59 +- library/core/src/num/bignum.rs | 34 +- library/core/src/num/dec2flt/algorithm.rs | 20 +- library/core/src/num/dec2flt/mod.rs | 12 +- library/core/src/num/error.rs | 151 + library/core/src/num/flt2dec/mod.rs | 250 +- .../core/src/num/flt2dec/strategy/dragon.rs | 41 +- .../core/src/num/flt2dec/strategy/grisu.rs | 99 +- library/core/src/num/int_macros.rs | 2212 +- library/core/src/num/mod.rs | 4743 +--- library/core/src/num/nonzero.rs | 190 + library/core/src/num/{ => shells}/i128.rs | 0 library/core/src/num/{ => shells}/i16.rs | 0 library/core/src/num/{ => shells}/i32.rs | 0 library/core/src/num/{ => shells}/i64.rs | 0 library/core/src/num/{ => shells}/i8.rs | 0 library/core/src/num/shells/int_macros.rs | 49 + library/core/src/num/{ => shells}/isize.rs | 0 library/core/src/num/{ => shells}/u128.rs | 0 library/core/src/num/{ => shells}/u16.rs | 0 library/core/src/num/{ => shells}/u32.rs | 0 library/core/src/num/{ => shells}/u64.rs | 0 library/core/src/num/{ => shells}/u8.rs | 0 library/core/src/num/{ => shells}/usize.rs | 0 library/core/src/num/uint_macros.rs | 1955 ++ library/core/src/num/wrapping.rs | 81 +- library/core/src/ops/arith.rs | 99 +- library/core/src/ops/bit.rs | 203 +- library/core/src/ops/control_flow.rs | 110 + library/core/src/ops/deref.rs | 2 + library/core/src/ops/mod.rs | 16 +- library/core/src/ops/range.rs | 14 +- library/core/src/ops/try.rs | 6 +- library/core/src/option.rs | 33 +- library/core/src/panic.rs | 11 +- library/core/src/pin.rs | 52 +- library/core/src/ptr/const_ptr.rs | 2 +- library/core/src/ptr/mod.rs | 81 +- library/core/src/ptr/mut_ptr.rs | 2 +- library/core/src/ptr/non_null.rs | 38 +- library/core/src/ptr/unique.rs | 2 - library/core/src/result.rs | 10 +- library/core/src/slice/ascii.rs | 156 + library/core/src/slice/cmp.rs | 288 + library/core/src/slice/index.rs | 528 + library/core/src/slice/iter.rs | 2979 +++ library/core/src/slice/iter/macros.rs | 407 + library/core/src/slice/memchr.rs | 40 +- library/core/src/slice/mod.rs | 4280 +--- library/core/src/slice/raw.rs | 151 + library/core/src/slice/sort.rs | 17 +- library/core/src/str/converts.rs | 192 + library/core/src/str/error.rs | 129 + library/core/src/str/iter.rs | 1255 + library/core/src/str/lossy.rs | 10 +- library/core/src/str/mod.rs | 2507 +- library/core/src/str/pattern.rs | 2 +- library/core/src/str/traits.rs | 597 + library/core/src/str/validations.rs | 275 + library/core/src/sync/atomic.rs | 363 +- library/core/src/task/poll.rs | 12 +- library/core/src/task/ready.rs | 2 - library/core/src/task/wake.rs | 37 +- library/core/src/time.rs | 115 +- library/core/tests/array.rs | 46 +- library/core/tests/ascii.rs | 11 + library/core/tests/cell.rs | 55 + library/core/tests/cmp.rs | 18 +- library/core/tests/intrinsics.rs | 15 + library/core/tests/iter.rs | 159 +- library/core/tests/lib.rs | 15 + library/core/tests/nonzero.rs | 17 + library/core/tests/num/flt2dec/mod.rs | 71 +- library/core/tests/num/flt2dec/random.rs | 31 +- library/core/tests/num/i32.rs | 29 + library/core/tests/num/int_macros.rs | 20 +- library/core/tests/num/mod.rs | 14 +- library/core/tests/num/uint_macros.rs | 20 +- library/core/tests/num/wrapping.rs | 76 + library/core/tests/option.rs | 47 +- library/core/tests/pin.rs | 31 + library/core/tests/result.rs | 17 +- library/core/tests/slice.rs | 174 +- library/core/tests/time.rs | 131 + library/panic_abort/src/lib.rs | 29 +- library/panic_unwind/src/dwarf/eh.rs | 16 +- library/panic_unwind/src/dwarf/mod.rs | 4 +- library/panic_unwind/src/emcc.rs | 46 +- library/panic_unwind/src/gcc.rs | 30 +- library/panic_unwind/src/lib.rs | 7 +- library/panic_unwind/src/seh.rs | 14 +- library/proc_macro/src/bridge/client.rs | 14 +- library/proc_macro/src/bridge/mod.rs | 3 + library/proc_macro/src/bridge/scoped_cell.rs | 1 + library/proc_macro/src/bridge/server.rs | 34 +- library/proc_macro/src/lib.rs | 2 + library/profiler_builtins/build.rs | 3 +- library/std/Cargo.toml | 7 +- library/std/build.rs | 6 +- library/std/src/alloc.rs | 117 +- library/std/src/ascii.rs | 2 - library/std/src/backtrace.rs | 55 +- library/std/src/backtrace/tests.rs | 53 + library/std/src/collections/hash/map.rs | 1168 +- library/std/src/collections/hash/map/tests.rs | 1087 + library/std/src/collections/hash/set.rs | 701 +- library/std/src/collections/hash/set/tests.rs | 486 + library/std/src/env.rs | 175 +- library/std/src/env/tests.rs | 102 + library/std/src/error.rs | 71 +- library/std/src/error/tests.rs | 37 + library/std/src/f32.rs | 766 +- library/std/src/f32/tests.rs | 759 + library/std/src/f64.rs | 762 +- library/std/src/f64/tests.rs | 755 + library/std/src/ffi/c_str.rs | 207 +- library/std/src/ffi/c_str/tests.rs | 195 + library/std/src/ffi/os_str.rs | 178 +- library/std/src/ffi/os_str/tests.rs | 165 + library/std/src/fs.rs | 1381 +- library/std/src/fs/tests.rs | 1339 + library/std/src/future.rs | 2 +- library/std/src/io/buffered.rs | 1121 +- library/std/src/io/buffered/tests.rs | 958 + library/std/src/io/cursor.rs | 531 +- library/std/src/io/cursor/tests.rs | 516 + library/std/src/io/error.rs | 60 +- library/std/src/io/error/tests.rs | 53 + library/std/src/io/impls.rs | 64 +- library/std/src/io/impls/tests.rs | 57 + library/std/src/io/lazy.rs | 63 - library/std/src/io/mod.rs | 502 +- library/std/src/io/stdio.rs | 265 +- library/std/src/io/stdio/tests.rs | 47 + library/std/src/io/tests.rs | 494 + library/std/src/io/util.rs | 87 +- library/std/src/io/util/tests.rs | 45 + library/std/src/keyword_docs.rs | 26 +- library/std/src/lazy.rs | 405 +- library/std/src/lazy/tests.rs | 323 + library/std/src/lib.rs | 18 +- library/std/src/memchr.rs | 90 +- library/std/src/memchr/tests.rs | 86 + library/std/src/net/addr.rs | 244 +- library/std/src/net/addr/tests.rs | 229 + library/std/src/net/ip.rs | 1025 +- library/std/src/net/ip/tests.rs | 939 + library/std/src/net/parser.rs | 146 +- library/std/src/net/parser/tests.rs | 139 + library/std/src/net/tcp.rs | 870 +- library/std/src/net/tcp/tests.rs | 862 + library/std/src/net/udp.rs | 380 +- library/std/src/net/udp/tests.rs | 372 + library/std/src/num.rs | 253 +- library/std/src/num/benches.rs | 9 + library/std/src/num/tests.rs | 230 + library/std/src/os/linux/fs.rs | 8 +- library/std/src/os/linux/mod.rs | 2 +- library/std/src/os/linux/raw.rs | 54 +- library/std/src/os/raw/mod.rs | 30 +- library/std/src/os/raw/tests.rs | 15 + library/std/src/os/redox/fs.rs | 6 +- library/std/src/panic.rs | 22 +- .../std/src/panic/tests.rs | 23 +- library/std/src/panicking.rs | 8 + library/std/src/path.rs | 1442 +- library/std/src/path/tests.rs | 1394 ++ library/std/src/prelude/mod.rs | 2 +- library/std/src/primitive_docs.rs | 234 +- library/std/src/process.rs | 562 +- library/std/src/process/tests.rs | 401 + library/std/src/sync/barrier.rs | 73 +- library/std/src/sync/barrier/tests.rs | 35 + library/std/src/sync/condvar.rs | 256 +- library/std/src/sync/condvar/tests.rs | 211 + library/std/src/sync/mpsc/mod.rs | 1382 +- library/std/src/sync/mpsc/mpsc_queue.rs | 54 +- library/std/src/sync/mpsc/mpsc_queue/tests.rs | 47 + library/std/src/sync/mpsc/spsc_queue.rs | 108 +- library/std/src/sync/mpsc/spsc_queue/tests.rs | 101 + library/std/src/sync/mpsc/sync_tests.rs | 647 + library/std/src/sync/mpsc/tests.rs | 706 + library/std/src/sync/mutex.rs | 287 +- library/std/src/sync/mutex/tests.rs | 238 + library/std/src/sync/once.rs | 187 +- library/std/src/sync/once/tests.rs | 116 + library/std/src/sync/rwlock.rs | 262 +- library/std/src/sync/rwlock/tests.rs | 247 + library/std/src/sys/hermit/args.rs | 4 +- library/std/src/sys/sgx/abi/mem.rs | 11 +- library/std/src/sys/sgx/abi/tls.rs | 116 +- .../std/src/sys/sgx/abi/tls/sync_bitset.rs | 85 + .../src/sys/sgx/abi/tls/sync_bitset/tests.rs | 25 + library/std/src/sys/sgx/ext/arch.rs | 29 +- library/std/src/sys/sgx/fs.rs | 308 - library/std/src/sys/sgx/io.rs | 47 - library/std/src/sys/sgx/mod.rs | 4 + library/std/src/sys/sgx/pipe.rs | 38 - library/std/src/sys/sgx/process.rs | 149 - library/std/src/sys/sgx/rwlock.rs | 50 +- library/std/src/sys/sgx/rwlock/tests.rs | 31 + library/std/src/sys/sgx/waitqueue.rs | 398 +- .../std/src/sys/sgx/waitqueue/spin_mutex.rs | 76 + .../src/sys/sgx/waitqueue/spin_mutex/tests.rs | 23 + library/std/src/sys/sgx/waitqueue/tests.rs | 20 + .../std/src/sys/sgx/waitqueue/unsafe_list.rs | 146 + .../sys/sgx/waitqueue/unsafe_list/tests.rs | 103 + library/std/src/sys/unix/alloc.rs | 86 +- library/std/src/sys/unix/args.rs | 4 +- library/std/src/sys/unix/ext/ffi.rs | 2 +- library/std/src/sys/unix/ext/fs.rs | 18 +- library/std/src/sys/unix/ext/io.rs | 61 +- library/std/src/sys/unix/ext/mod.rs | 12 + library/std/src/sys/unix/ext/net.rs | 567 +- library/std/src/sys/unix/ext/net/tests.rs | 454 + library/std/src/sys/unix/ext/raw.rs | 2 +- library/std/src/sys/unix/ext/ucred.rs | 97 + library/std/src/sys/unix/ext/ucred/tests.rs | 25 + library/std/src/sys/unix/fd.rs | 59 +- library/std/src/sys/unix/fd/tests.rs | 9 + library/std/src/sys/unix/fs.rs | 27 +- library/std/src/sys/unix/futex.rs | 37 + library/std/src/sys/unix/mod.rs | 64 + library/std/src/sys/unix/os.rs | 39 +- library/std/src/sys/unix/os/tests.rs | 23 + library/std/src/sys/unix/process/mod.rs | 3 +- .../src/sys/unix/process/process_common.rs | 112 +- .../sys/unix/process/process_common/tests.rs | 64 + .../src/sys/unix/process/process_fuchsia.rs | 5 +- .../std/src/sys/unix/process/process_unix.rs | 42 +- library/std/src/sys/unix/process/zircon.rs | 1 + library/std/src/sys/unix/thread.rs | 10 +- library/std/src/sys/unsupported/fs.rs | 4 - library/std/src/sys/unsupported/mod.rs | 1 + library/std/src/sys/unsupported/path.rs | 19 - library/std/src/sys/unsupported/process.rs | 43 +- library/std/src/sys/vxworks/args.rs | 4 +- library/std/src/sys/vxworks/ext/fs.rs | 11 +- library/std/src/sys/vxworks/ext/io.rs | 19 + library/std/src/sys/vxworks/fd.rs | 2 +- library/std/src/sys/vxworks/net.rs | 30 +- library/std/src/sys/vxworks/net/tests.rs | 23 + library/std/src/sys/vxworks/os.rs | 9 +- .../src/sys/vxworks/process/process_common.rs | 15 +- .../std/src/sys/vxworks/thread_local_dtor.rs | 2 +- library/std/src/sys/wasi/alloc.rs | 42 - library/std/src/sys/wasi/args.rs | 2 + library/std/src/sys/wasi/ext/fs.rs | 28 +- library/std/src/sys/wasi/ext/io.rs | 20 + library/std/src/sys/wasi/ext/mod.rs | 2 + library/std/src/sys/wasi/fd.rs | 1 + library/std/src/sys/wasi/fs.rs | 2 + library/std/src/sys/wasi/io.rs | 2 + library/std/src/sys/wasi/mod.rs | 4 + library/std/src/sys/wasi/net.rs | 2 + library/std/src/sys/wasi/os.rs | 2 + library/std/src/sys/wasi/path.rs | 19 - library/std/src/sys/wasi/pipe.rs | 38 - library/std/src/sys/wasi/process.rs | 149 - library/std/src/sys/wasi/stdio.rs | 2 + library/std/src/sys/wasi/thread.rs | 2 + library/std/src/sys/wasi/time.rs | 2 + library/std/src/sys/wasm/mod.rs | 2 +- library/std/src/sys/windows/args.rs | 69 +- library/std/src/sys/windows/args/tests.rs | 61 + library/std/src/sys/windows/c.rs | 2 +- library/std/src/sys/windows/compat.rs | 75 +- library/std/src/sys/windows/ext/io.rs | 2 + library/std/src/sys/windows/ext/raw.rs | 2 +- library/std/src/sys/windows/mod.rs | 16 +- library/std/src/sys/windows/mutex.rs | 105 +- library/std/src/sys/windows/os.rs | 20 +- library/std/src/sys/windows/os/tests.rs | 13 + library/std/src/sys/windows/os_str.rs | 4 +- library/std/src/sys/windows/process.rs | 81 +- library/std/src/sys/windows/process/tests.rs | 31 + library/std/src/sys_common/alloc.rs | 4 +- library/std/src/sys_common/at_exit_imp.rs | 7 +- library/std/src/sys_common/bytestring.rs | 26 +- .../std/src/sys_common/bytestring/tests.rs | 19 + library/std/src/sys_common/condvar.rs | 10 +- library/std/src/sys_common/mod.rs | 9 +- library/std/src/sys_common/mutex.rs | 127 +- library/std/src/sys_common/net.rs | 26 +- library/std/src/sys_common/net/tests.rs | 19 + library/std/src/sys_common/os_str_bytes.rs | 16 +- library/std/src/sys_common/poison.rs | 29 +- library/std/src/sys_common/process.rs | 37 + library/std/src/sys_common/remutex.rs | 89 +- library/std/src/sys_common/remutex/tests.rs | 72 + library/std/src/sys_common/tests.rs | 6 + .../std/src/sys_common/thread_local_key.rs | 46 +- .../src/sys_common/thread_local_key/tests.rs | 34 + .../std/src/sys_common/thread_parker/futex.rs | 93 + .../src/sys_common/thread_parker/generic.rs | 119 + .../std/src/sys_common/thread_parker/mod.rs | 9 + library/std/src/sys_common/wtf8.rs | 407 +- library/std/src/sys_common/wtf8/tests.rs | 397 + library/std/src/thread/local.rs | 354 +- library/std/src/thread/local/dynamic_tests.rs | 40 + library/std/src/thread/local/tests.rs | 154 + library/std/src/thread/mod.rs | 434 +- library/std/src/thread/tests.rs | 262 + library/std/src/time.rs | 188 +- library/std/src/time/tests.rs | 165 + library/stdarch/crates/core_arch/avx512f.md | 1418 ++ .../crates/core_arch/src/aarch64/mod.rs | 5 +- .../crates/core_arch/src/aarch64/neon/mod.rs | 501 +- .../crates/core_arch/src/aarch64/prefetch.rs | 89 + .../stdarch/crates/core_arch/src/arm/mod.rs | 14 +- .../crates/core_arch/src/arm/neon/mod.rs | 340 +- library/stdarch/crates/core_arch/src/lib.rs | 2 +- library/stdarch/crates/core_arch/src/simd.rs | 678 +- .../stdarch/crates/core_arch/src/simd_llvm.rs | 4 +- .../crates/core_arch/src/wasm32/simd128.rs | 2 +- .../stdarch/crates/core_arch/src/x86/avx.rs | 2 +- .../stdarch/crates/core_arch/src/x86/avx2.rs | 32 +- .../crates/core_arch/src/x86/avx512f.rs | 20593 ++++++++++++++-- .../crates/core_arch/src/x86/macros.rs | 517 + .../stdarch/crates/core_arch/src/x86/mmx.rs | 786 - .../stdarch/crates/core_arch/src/x86/mod.rs | 114 +- .../stdarch/crates/core_arch/src/x86/sse.rs | 876 - .../stdarch/crates/core_arch/src/x86/sse2.rs | 202 - .../stdarch/crates/core_arch/src/x86/sse42.rs | 14 - .../stdarch/crates/core_arch/src/x86/ssse3.rs | 345 - .../stdarch/crates/core_arch/src/x86/test.rs | 9 - .../crates/core_arch/src/x86_64/avx512f.rs | 4730 +++- .../stdarch/crates/simd-test-macro/src/lib.rs | 12 - .../crates/std_detect/src/detect/cache.rs | 79 +- .../crates/std_detect/src/detect/mod.rs | 2 +- .../stdarch/crates/stdarch-test/src/lib.rs | 1 - .../stdarch/crates/stdarch-verify/src/lib.rs | 3 + .../crates/stdarch-verify/tests/arm.rs | 3 +- .../crates/stdarch-verify/tests/x86-intel.rs | 11 +- library/test/Cargo.toml | 1 + library/test/src/bench.rs | 28 +- library/test/src/formatters/pretty.rs | 2 +- library/test/src/formatters/terse.rs | 4 +- library/test/src/lib.rs | 9 +- library/test/src/stats.rs | 20 +- library/unwind/src/libunwind.rs | 4 +- src/README.md | 2 +- src/bootstrap/CHANGELOG.md | 47 + src/bootstrap/Cargo.toml | 3 +- src/bootstrap/README.md | 54 +- src/bootstrap/bin/main.rs | 50 +- src/bootstrap/bin/rustc.rs | 3 + src/bootstrap/bin/rustdoc.rs | 5 +- src/bootstrap/bootstrap.py | 143 +- src/bootstrap/build.rs | 26 + src/bootstrap/builder.rs | 168 +- src/bootstrap/builder/tests.rs | 156 +- src/bootstrap/cc_detect.rs | 3 +- src/bootstrap/channel.rs | 3 - src/bootstrap/check.rs | 65 +- src/bootstrap/compile.rs | 23 +- src/bootstrap/config.rs | 356 +- src/bootstrap/defaults/README.md | 12 + src/bootstrap/defaults/config.toml.codegen | 13 + src/bootstrap/defaults/config.toml.compiler | 8 + src/bootstrap/defaults/config.toml.library | 10 + src/bootstrap/defaults/config.toml.user | 9 + src/bootstrap/dist.rs | 251 +- src/bootstrap/doc.rs | 75 +- src/bootstrap/flags.rs | 152 +- src/bootstrap/format.rs | 8 +- src/bootstrap/install.rs | 2 +- src/bootstrap/lib.rs | 133 +- src/bootstrap/native.rs | 41 +- src/bootstrap/run.rs | 43 +- src/bootstrap/sanity.rs | 34 +- src/bootstrap/setup.rs | 88 + src/bootstrap/test.rs | 75 +- src/bootstrap/tool.rs | 23 +- src/build_helper/Cargo.toml | 1 - src/ci/azure-pipelines/auto.yml | 42 +- src/ci/azure-pipelines/steps/run.yml | 142 - .../host-aarch64/aarch64-gnu/Dockerfile | 1 + .../docker/host-x86_64/arm-android/Dockerfile | 2 +- .../docker/host-x86_64/armhf-gnu/Dockerfile | 5 +- .../host-x86_64/disabled/asmjs/Dockerfile | 3 +- .../disabled/dist-powerpcspe-linux/Dockerfile | 1 + .../disabled/dist-sparc64-linux/Dockerfile | 1 + .../disabled/dist-x86_64-dragonfly/Dockerfile | 1 + .../disabled/dist-x86_64-haiku/Dockerfile | 1 + .../disabled/dist-x86_64-redox/Dockerfile | 2 +- .../disabled/riscv64gc-linux/Dockerfile | 1 + .../host-x86_64/dist-android/Dockerfile | 2 +- .../host-x86_64/dist-arm-linux/Dockerfile | 13 +- .../dist-arm-linux/arm-linux-gnueabi.config | 17 +- .../dist-i586-gnu-i586-i686-musl/Dockerfile | 5 +- .../host-x86_64/dist-i686-freebsd/Dockerfile | 1 + .../host-x86_64/dist-i686-linux/Dockerfile | 1 + .../host-x86_64/dist-mips-linux/Dockerfile | 1 + .../host-x86_64/dist-mips64-linux/Dockerfile | 1 + .../dist-mips64el-linux/Dockerfile | 1 + .../host-x86_64/dist-mipsel-linux/Dockerfile | 1 + .../host-x86_64/dist-various-1/Dockerfile | 11 +- .../host-x86_64/dist-various-2/Dockerfile | 2 +- .../build-cloudabi-toolchain.sh | 1 + .../dist-x86_64-freebsd/Dockerfile | 1 + .../host-x86_64/dist-x86_64-linux/Dockerfile | 5 +- .../dist-x86_64-linux/build-git.sh | 15 - .../dist-x86_64-linux/build-headers.sh | 16 - .../dist-x86_64-linux/build-perl.sh | 21 - .../host-x86_64/dist-x86_64-musl/Dockerfile | 2 + .../host-x86_64/i686-gnu-nopt/Dockerfile | 1 + src/ci/docker/host-x86_64/i686-gnu/Dockerfile | 1 + .../docker/host-x86_64/mingw-check/Dockerfile | 1 + .../host-x86_64/test-various/Dockerfile | 7 +- src/ci/docker/host-x86_64/wasm32/Dockerfile | 3 +- .../host-x86_64/x86_64-gnu-aux/Dockerfile | 1 + .../host-x86_64/x86_64-gnu-debug/Dockerfile | 1 + .../x86_64-gnu-distcheck/Dockerfile | 1 + .../host-x86_64/x86_64-gnu-llvm-8/Dockerfile | 3 +- .../host-x86_64/x86_64-gnu-nopt/Dockerfile | 1 + .../host-x86_64/x86_64-gnu-tools/Dockerfile | 1 + .../docker/host-x86_64/x86_64-gnu/Dockerfile | 1 + src/ci/docker/scripts/android-base-apt-get.sh | 1 + src/ci/docker/scripts/cross-apt-packages.sh | 1 + src/ci/github-actions/ci.yml | 120 +- src/ci/run.sh | 4 +- src/ci/scripts/symlink-build-dir.sh | 18 - .../output.txt | 17 +- .../listing-10-05/src/main.rs | 2 +- .../no-listing-10-result-in-tests/src/lib.rs | 5 + src/doc/book/src/appendix-06-translation.md | 1 + src/doc/book/src/ch03-02-data-types.md | 2 +- src/doc/book/src/ch11-01-writing-tests.md | 2 +- .../edition-guide/src/rust-next/const-fn.md | 4 +- src/doc/embedded-book/src/intro/install.md | 18 +- src/doc/nomicon/src/vec-final.md | 2 +- .../src/behavior-considered-undefined.md | 5 + src/doc/reference/src/const_eval.md | 19 +- .../reference/src/expressions/match-expr.md | 2 +- src/doc/reference/src/items/functions.md | 57 +- src/doc/reference/src/linkage.md | 8 +- src/doc/reference/src/patterns.md | 96 +- src/doc/reference/src/type-coercions.md | 52 +- src/doc/reference/src/type-layout.md | 221 +- src/doc/rust-by-example/src/SUMMARY.md | 4 +- src/doc/rust-by-example/src/crates/lib.md | 2 +- src/doc/rust-by-example/src/crates/link.md | 29 - .../rust-by-example/src/crates/using_lib.md | 27 + .../src/custom_types/structs.md | 10 +- .../error/multiple_error_types/wrap_error.md | 16 +- src/doc/rust-by-example/src/error/panic.md | 18 +- src/doc/rust-by-example/src/mod/use.md | 2 - .../rust-by-example/src/primitives/array.md | 10 +- .../rust-by-example/src/std_misc/threads.md | 2 +- .../src/testing/integration_testing.md | 8 +- src/doc/rust-by-example/src/trait/clone.md | 4 +- .../src/variable_bindings/scope.md | 33 +- src/doc/rustc/src/codegen-options/index.md | 20 +- src/doc/rustc/src/linker-plugin-lto.md | 49 +- src/doc/rustc/src/lints/groups.md | 9 +- src/doc/rustc/src/lints/index.md | 32 + .../src/lints/listing/allowed-by-default.md | 452 +- .../src/lints/listing/deny-by-default.md | 211 +- .../src/lints/listing/warn-by-default.md | 902 +- src/doc/rustc/src/platform-support.md | 24 +- src/doc/rustdoc/src/SUMMARY.md | 1 + src/doc/rustdoc/src/advanced-features.md | 16 + .../rustdoc/src/linking-to-items-by-name.md | 65 + src/doc/rustdoc/src/lints.md | 143 +- src/doc/rustdoc/src/unstable-features.md | 73 - src/doc/rustdoc/src/what-is-rustdoc.md | 23 + .../src/compiler-flags/tls-model.md | 2 +- .../src/compiler-flags/unsound-mir-opts.md | 8 + .../language-features/cmse-nonsecure-entry.md | 81 + .../src/language-features/doc-alias.md | 23 - .../src/language-features/ffi-const.md | 5 + .../src/language-features/ffi-pure.md | 5 + .../src/language-features/rustc-attrs.md | 4 +- .../unstable-book/src/library-features/asm.md | 38 +- .../src/library-features/llvm-asm.md | 6 +- .../src/library-features/slice-check-range.md | 10 + src/etc/gdb_lookup.py | 4 +- src/etc/gdb_providers.py | 14 +- src/etc/lldb_lookup.py | 2 +- src/etc/lldb_providers.py | 13 +- src/etc/natvis/libstd.natvis | 18 +- src/librustc_ast/Cargo.toml | 21 - src/librustc_ast_lowering/Cargo.toml | 24 - src/librustc_ast_passes/Cargo.toml | 22 - src/librustc_ast_pretty/Cargo.toml | 16 - src/librustc_attr/Cargo.toml | 23 - src/librustc_builtin_macros/Cargo.toml | 26 - src/librustc_codegen_llvm/Cargo.toml | 36 - src/librustc_codegen_ssa/Cargo.toml | 38 - src/librustc_codegen_ssa/traits/declare.rs | 65 - src/librustc_data_structures/jobserver.rs | 42 - src/librustc_driver/Cargo.toml | 43 - src/librustc_error_codes/error_codes/E0019.md | 36 - src/librustc_error_codes/error_codes/E0433.md | 17 - src/librustc_expand/Cargo.toml | 28 - src/librustc_expand/parse/lexer/tests.rs | 252 - src/librustc_feature/Cargo.toml | 15 - src/librustc_hir/Cargo.toml | 22 - src/librustc_hir_pretty/Cargo.toml | 17 - src/librustc_incremental/Cargo.toml | 24 - src/librustc_infer/Cargo.toml | 27 - src/librustc_interface/Cargo.toml | 57 - src/librustc_lexer/src/tests.rs | 167 - src/librustc_lint/Cargo.toml | 26 - src/librustc_metadata/Cargo.toml | 35 - src/librustc_middle/Cargo.toml | 36 - src/librustc_middle/ty/print/obsolete.rs | 251 - src/librustc_mir/Cargo.toml | 35 - .../transform/check_consts/mod.rs | 57 - .../transform/check_consts/ops.rs | 393 - src/librustc_mir/transform/instcombine.rs | 117 - .../transform/instrument_coverage.rs | 247 - .../transform/qualify_min_const_fn.rs | 464 - src/librustc_mir_build/Cargo.toml | 29 - .../thir/pattern/const_to_pat.rs | 306 - src/librustc_parse/Cargo.toml | 24 - src/librustc_parse_format/Cargo.toml | 13 - src/librustc_passes/Cargo.toml | 23 - src/librustc_plugin_impl/Cargo.toml | 21 - src/librustc_privacy/Cargo.toml | 20 - src/librustc_query_system/Cargo.toml | 23 - src/librustc_resolve/Cargo.toml | 31 - src/librustc_save_analysis/Cargo.toml | 24 - src/librustc_session/Cargo.toml | 24 - src/librustc_session/lint/builtin.rs | 635 - src/librustc_span/Cargo.toml | 23 - src/librustc_symbol_mangling/Cargo.toml | 23 - src/librustc_target/Cargo.toml | 18 - src/librustc_target/spec/apple_sdk_base.rs | 151 - .../spec/avr_unknown_unknown.rs | 17 - src/librustc_target/spec/freestanding_base.rs | 31 - src/librustc_trait_selection/Cargo.toml | 27 - .../traits/chalk_fulfill.rs | 267 - src/librustc_traits/Cargo.toml | 23 - src/librustc_traits/chalk/mod.rs | 229 - src/librustc_ty/Cargo.toml | 21 - src/librustc_typeck/Cargo.toml | 29 - src/librustdoc/Cargo.toml | 8 +- src/librustdoc/clean/blanket_impl.rs | 5 +- src/librustdoc/clean/cfg.rs | 151 +- src/librustdoc/clean/cfg/tests.rs | 13 +- src/librustdoc/clean/inline.rs | 59 +- src/librustdoc/clean/mod.rs | 87 +- src/librustdoc/clean/types.rs | 55 +- src/librustdoc/clean/utils.rs | 13 +- src/librustdoc/config.rs | 22 +- src/librustdoc/core.rs | 27 +- src/librustdoc/{test.rs => doctest.rs} | 3 +- src/librustdoc/{test => doctest}/tests.rs | 0 src/librustdoc/doctree.rs | 34 +- src/librustdoc/fold.rs | 14 +- src/librustdoc/formats/cache.rs | 4 +- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/highlight.rs | 556 +- .../html/highlight/fixtures/sample.html | 27 + .../html/highlight/fixtures/sample.rs | 16 + src/librustdoc/html/highlight/tests.rs | 99 +- src/librustdoc/html/layout.rs | 8 +- src/librustdoc/html/markdown.rs | 209 +- src/librustdoc/html/markdown/tests.rs | 48 +- src/librustdoc/html/render/cache.rs | 6 +- src/librustdoc/html/render/mod.rs | 259 +- src/librustdoc/html/sources.rs | 2 +- src/librustdoc/html/static/favicon-16x16.png | Bin 0 -> 2214 bytes src/librustdoc/html/static/favicon-32x32.png | Bin 0 -> 2919 bytes src/librustdoc/html/static/favicon.ico | Bin 23229 -> 0 bytes src/librustdoc/html/static/favicon.svg | 24 + src/librustdoc/html/static/main.js | 56 +- src/librustdoc/html/static/rustdoc.css | 6 +- src/librustdoc/html/static/themes/ayu.css | 10 +- src/librustdoc/html/static/themes/dark.css | 1 + src/librustdoc/html/static_files.rs | 6 +- src/librustdoc/lib.rs | 42 +- src/librustdoc/markdown.rs | 2 +- .../passes/check_code_block_syntax.rs | 75 +- .../passes/collect_intra_doc_links.rs | 1773 +- src/librustdoc/passes/doc_test_lints.rs | 18 +- src/librustdoc/passes/mod.rs | 3 +- src/librustdoc/passes/strip_private.rs | 2 +- src/librustdoc/visit_ast.rs | 34 +- src/stage0.txt | 8 +- src/test/assembly/asm/aarch64-types.rs | 16 +- src/test/assembly/asm/mips-types.rs | 191 + ...4-fortanix-unknown-sgx-lvi-generic-load.rs | 17 + ...64-fortanix-unknown-sgx-lvi-generic-ret.rs | 12 + ...ortanix-unknown-sgx-lvi-inline-assembly.rs | 41 + .../cross-crate-generic-functions.rs | 10 +- .../cross-crate-trait-method.rs | 22 +- .../drop_in_place_intrinsic.rs | 14 +- .../item-collection/function-as-argument.rs | 23 +- .../item-collection/generic-drop-glue.rs | 24 +- .../item-collection/generic-functions.rs | 28 +- .../item-collection/generic-impl.rs | 36 +- .../impl-in-non-instantiated-generic.rs | 4 +- .../instantiation-through-vtable.rs | 14 +- .../items-within-generic-items.rs | 12 +- .../item-collection/non-generic-drop-glue.rs | 10 +- .../item-collection/non-generic-functions.rs | 24 +- .../item-collection/overloaded-operators.rs | 12 +- .../item-collection/static-init.rs | 6 +- .../item-collection/statics-and-consts.rs | 12 +- .../item-collection/trait-implementations.rs | 22 +- .../trait-method-as-argument.rs | 31 +- .../trait-method-default-impl.rs | 18 +- .../item-collection/transitive-drop-glue.rs | 26 +- .../item-collection/tuple-drop-glue.rs | 12 +- .../item-collection/unreferenced-const-fn.rs | 2 +- .../codegen-units/item-collection/unsizing.rs | 18 +- .../unused-traits-and-generics.rs | 2 +- .../partitioning/extern-drop-glue.rs | 10 +- .../partitioning/extern-generic.rs | 14 +- .../partitioning/incremental-merging.rs | 9 +- .../inlining-from-extern-crate.rs | 10 +- .../partitioning/local-drop-glue.rs | 14 +- .../partitioning/local-generic.rs | 17 +- .../local-inlining-but-not-all.rs | 8 +- .../partitioning/local-inlining.rs | 8 +- .../partitioning/local-transitive-inlining.rs | 8 +- .../partitioning/regular-modules.rs | 43 +- .../partitioning/shared-generics.rs | 4 +- .../codegen-units/partitioning/statics.rs | 20 +- .../partitioning/vtable-through-const.rs | 24 +- .../unused_type_parameters.rs | 147 +- src/test/codegen/avr/avr-func-addrspace.rs | 2 +- src/test/codegen/consts.rs | 6 +- .../codegen/enum-bounds-check-derived-idx.rs | 25 + .../codegen/enum-bounds-check-issue-13926.rs | 19 + src/test/codegen/enum-bounds-check.rs | 12 + src/test/codegen/issue-27130.rs | 22 + src/test/codegen/issue-34634.rs | 16 + ...issue-73396-bounds-check-after-position.rs | 78 + src/test/codegen/issue-75659.rs | 63 + src/test/codegen/return-value-in-reg.rs | 32 + src/test/codegen/try_identity.rs | 2 +- src/test/codegen/tuple-layout-opt.rs | 36 + src/test/codegen/x86_mmx.rs | 27 - src/test/codegen/zst-offset.rs | 43 + .../auxiliary/panic-runtime-lang-items.rs | 2 + .../compile-fail/consts/const-fn-error.rs | 6 +- src/test/compile-fail/issue-43733-2.rs | 2 +- src/test/compile-fail/issue-44415.rs | 2 +- .../compile-fail/must_use-in-stdlib-traits.rs | 10 +- .../debuginfo/pretty-std-collections-hash.rs | 4 + src/test/incremental/dirty_clean.rs | 4 +- src/test/incremental/issue-54242.rs | 2 +- ..._regression.encode.SimplifyBranchSame.diff | 28 + src/test/mir-opt/76803_regression.rs | 19 + ...mplifyCfg-elaborate-drops.after.32bit.mir} | 2 +- ...mplifyCfg-elaborate-drops.after.64bit.mir} | 2 +- ...ignment.main.SimplifyCfg-initial.after.mir | 2 +- .../box_expr.main.ElaborateDrops.before.mir | 2 +- ...ne_array_len.norm2.InstCombine.32bit.diff} | 4 +- ...ne_array_len.norm2.InstCombine.64bit.diff} | 4 +- ...allocation.main.ConstProp.after.32bit.mir} | 30 +- ...allocation.main.ConstProp.after.64bit.mir} | 34 +- ...llocation2.main.ConstProp.after.32bit.mir} | 28 +- ...llocation2.main.ConstProp.after.64bit.mir} | 30 +- ...llocation3.main.ConstProp.after.32bit.mir} | 0 ...llocation3.main.ConstProp.after.64bit.mir} | 0 ...motion_extern_static.BAR.PromoteTemps.diff | 4 +- ...motion_extern_static.FOO.PromoteTemps.diff | 4 +- ... => array_index.main.ConstProp.32bit.diff} | 4 +- ... => array_index.main.ConstProp.64bit.diff} | 4 +- .../bad_op_div_by_zero.main.ConstProp.diff | 8 +- .../bad_op_mod_by_zero.main.ConstProp.diff | 8 +- ..._oob_for_slices.main.ConstProp.32bit.diff} | 8 +- ..._oob_for_slices.main.ConstProp.64bit.diff} | 8 +- .../checked_add.main.ConstProp.diff | 4 +- ..._prop_fails_gracefully.main.ConstProp.diff | 6 +- ...l_flow_simplification.hello.ConstProp.diff | 2 +- ...=> discriminant.main.ConstProp.32bit.diff} | 0 ...=> discriminant.main.ConstProp.64bit.diff} | 0 .../const_prop/indirect.main.ConstProp.diff | 4 +- ...rge_array_index.main.ConstProp.32bit.diff} | 4 +- ...rge_array_index.main.ConstProp.64bit.diff} | 4 +- ...s_into_variable.main.ConstProp.32bit.diff} | 8 +- ...s_into_variable.main.ConstProp.64bit.diff} | 8 +- ...iable.main.SimplifyLocals.after.32bit.mir} | 0 ...iable.main.SimplifyLocals.after.64bit.mir} | 0 .../const_prop/ref_deref.main.ConstProp.diff | 4 +- .../ref_deref.main.PromoteTemps.diff | 4 +- .../ref_deref_project.main.ConstProp.diff | 4 +- .../ref_deref_project.main.PromoteTemps.diff | 4 +- ...32bit => repeat.main.ConstProp.32bit.diff} | 4 +- ...64bit => repeat.main.ConstProp.64bit.diff} | 4 +- .../return_place.add.ConstProp.diff | 4 +- ...it => slice_len.main.ConstProp.32bit.diff} | 8 +- ...it => slice_len.main.ConstProp.64bit.diff} | 8 +- src/test/mir-opt/copy_propagation.rs | 1 + ...copy_propagation.test.CopyPropagation.diff | 23 +- ...opagation_arg.arg_src.CopyPropagation.diff | 10 +- ...y_propagation_arg.baz.CopyPropagation.diff | 8 +- ...y_propagation_arg.foo.CopyPropagation.diff | 8 +- .../branch.main.DestinationPropagation.diff | 73 + src/test/mir-opt/dest-prop/branch.rs | 21 + .../cycle.main.DestinationPropagation.diff | 72 + src/test/mir-opt/dest-prop/cycle.rs | 15 + .../simple.nrvo.DestinationPropagation.diff | 39 + src/test/mir-opt/dest-prop/simple.rs | 14 + .../union.main.DestinationPropagation.diff | 42 + src/test/mir-opt/dest-prop/union.rs | 16 + ...wise_branch.opt1.EarlyOtherwiseBranch.diff | 77 + ...wise_branch.opt2.EarlyOtherwiseBranch.diff | 91 + src/test/mir-opt/early_otherwise_branch.rs | 22 + ...ement_tuple.opt1.EarlyOtherwiseBranch.diff | 99 + .../early_otherwise_branch_3_element_tuple.rs | 13 + .../mir-opt/early_otherwise_branch_68867.rs | 33 + ...implifyBranches-after-copy-prop.after.diff | 304 + ...ch_68867.try_sum.EarlyOtherwiseBranch.diff | 216 + ...nch_noopt.noopt1.EarlyOtherwiseBranch.diff | 90 + ...nch_noopt.noopt2.EarlyOtherwiseBranch.diff | 60 + .../mir-opt/early_otherwise_branch_noopt.rs | 28 + .../mir-opt/equal_true.opt.InstCombine.diff | 35 + src/test/mir-opt/equal_true.rs | 9 + ....match_tuple.SimplifyCfg-initial.after.mir | 2 +- ...-Fn-call.AddMovesForPackedDrops.before.mir | 4 +- ...float_to_exponential_common.ConstProp.diff | 6 +- src/test/mir-opt/generator-drop-cleanup.rs | 2 +- .../mir-opt/generator-storage-dead-unwind.rs | 2 +- src/test/mir-opt/generator-tiny.rs | 2 +- ...nup.main-{closure#0}.generator_drop.0.mir} | 4 +- ...ain-{closure#0}.StateTransform.before.mir} | 4 +- ...y.main-{closure#0}.generator_resume.0.mir} | 4 +- src/test/mir-opt/graphviz.main.mir_map.0.dot | 6 +- .../mir-opt/graphviz.main.mir_map.0.dot.mir | 10 + src/test/mir-opt/if-condition-int.rs | 65 + ...t_opt_bool.SimplifyComparisonIntegral.diff | 30 + ...opt_floats.SimplifyComparisonIntegral.diff | 37 + ...comparison.SimplifyComparisonIntegral.diff | 58 + ...t.opt_char.SimplifyComparisonIntegral.diff | 39 + ...int.opt_i8.SimplifyComparisonIntegral.diff | 39 + ...ltiple_ifs.SimplifyComparisonIntegral.diff | 65 + ...t_negative.SimplifyComparisonIntegral.diff | 39 + ...nt.opt_u32.SimplifyComparisonIntegral.diff | 39 + src/test/mir-opt/inline/inline-async.rs | 18 + .../inline/inline-closure-borrows-arg.rs | 2 +- .../mir-opt/inline/inline-compatibility.rs | 39 + .../inline_any_operand.bar.Inline.after.mir | 24 +- .../inline_closure.foo.Inline.after.mir | 8 +- ...e_closure_borrows_arg.foo.Inline.after.mir | 24 +- ...line_closure_captures.foo.Inline.after.mir | 26 +- ...patibility.inlined_no_sanitize.Inline.diff | 25 + ...ibility.inlined_target_feature.Inline.diff | 25 + ...bility.not_inlined_no_sanitize.Inline.diff | 22 + ...ity.not_inlined_target_feature.Inline.diff | 22 + ...ine_into_box_place.main.Inline.32bit.diff} | 6 +- ...ine_into_box_place.main.Inline.64bit.diff} | 6 +- .../inline/inline_retag.bar.Inline.after.mir | 8 +- .../inline_specialization.main.Inline.diff | 2 +- ...line_trait_method_2.test2.Inline.after.mir | 6 +- ...67_inline_as_ref_as_mut.b.Inline.after.mir | 2 +- ...67_inline_as_ref_as_mut.d.Inline.after.mir | 2 +- ...st_combine_deref.deep_opt.InstCombine.diff | 92 + ...e_deref.do_not_miscompile.InstCombine.diff | 85 + ...st_combine_deref.dont_opt.InstCombine.diff | 53 + ..._combine_deref.opt_struct.InstCombine.diff | 44 + src/test/mir-opt/inst_combine_deref.rs | 69 + ..._combine_deref.simple_opt.InstCombine.diff | 34 + ...ument_coverage.bar.InstrumentCoverage.diff | 2 +- ...ment_coverage.main.InstrumentCoverage.diff | 2 +- src/test/mir-opt/issue-41697.rs | 2 +- ...implifyCfg-promote-consts.after.32bit.mir} | 6 +- ...implifyCfg-promote-consts.after.64bit.mir} | 6 +- ...issue_62289.test.ElaborateDrops.before.mir | 12 +- ...it => issue_72181.bar.mir_map.0.32bit.mir} | 0 ...it => issue_72181.bar.mir_map.0.64bit.mir} | 0 ...it => issue_72181.foo.mir_map.0.32bit.mir} | 2 +- ...it => issue_72181.foo.mir_map.0.64bit.mir} | 2 +- ...t => issue_72181.main.mir_map.0.32bit.mir} | 2 +- ...t => issue_72181.main.mir_map.0.64bit.mir} | 2 +- .../mir-opt/issue_72181_1.main.mir_map.0.mir | 2 +- ...=> issue_73223.main.PreCodegen.32bit.diff} | 182 +- ...=> issue_73223.main.PreCodegen.64bit.diff} | 182 +- ...73223.main.SimplifyArmIdentity.32bit.diff} | 42 +- ...73223.main.SimplifyArmIdentity.64bit.diff} | 42 +- src/test/mir-opt/issue_76432.rs | 16 + ...76432.test.SimplifyComparisonIntegral.diff | 116 + src/test/mir-opt/issues/issue-75439.rs | 21 + ...e_75439.foo.MatchBranchSimplification.diff | 87 + ...fg-initial.after-ElaborateDrops.after.diff | 2 +- ...s.full_tested_match.PromoteTemps.after.mir | 6 +- ...full_tested_match2.PromoteTemps.before.mir | 2 +- ...h_false_edges.main.PromoteTemps.before.mir | 2 +- ....bar.MatchBranchSimplification.32bit.diff} | 116 +- ....bar.MatchBranchSimplification.64bit.diff} | 116 +- ....foo.MatchBranchSimplification.32bit.diff} | 24 +- ....foo.MatchBranchSimplification.64bit.diff} | 24 +- src/test/mir-opt/matches_reduce_branches.rs | 1 + ...atch.MatchBranchSimplification.32bit.diff} | 0 ...atch.MatchBranchSimplification.64bit.diff} | 0 ...h_i8.MatchBranchSimplification.32bit.diff} | 0 ...h_i8.MatchBranchSimplification.64bit.diff} | 0 .../mir-opt/multiple_return_terminators.rs | 14 + ...nators.test.MultipleReturnTerminators.diff | 30 + ...gion_subtyping_basic.main.nll.0.32bit.mir} | 2 +- ...gion_subtyping_basic.main.nll.0.64bit.mir} | 2 +- ...wrap.SimplifyCfg-elaborate-drops.after.mir | 4 +- ..._after_call.main.ElaborateDrops.before.mir | 4 +- .../not_equal_false.opt.InstCombine.diff | 68 + src/test/mir-opt/not_equal_false.rs | 9 + src/test/mir-opt/nrvo-simple.rs | 2 + .../nrvo_simple.nrvo.RenameReturnPlace.diff | 55 +- ...mplifyCfg-elaborate-drops.after.32bit.mir} | 0 ...mplifyCfg-elaborate-drops.after.64bit.mir} | 0 ...tch_guard.CleanupNonCodegenStatements.diff | 2 +- ...annot_opt_generic.RemoveUnneededDrops.diff | 32 + ...ed_drops.dont_opt.RemoveUnneededDrops.diff | 32 + ...nneeded_drops.opt.RemoveUnneededDrops.diff | 28 + ....opt_generic_copy.RemoveUnneededDrops.diff | 28 + src/test/mir-opt/remove_unneeded_drops.rs | 29 + ...place.Test.SimplifyCfg-make_shim.after.mir | 6 +- ...#0}.SimplifyCfg-elaborate-drops.after.mir} | 4 +- ...main.SimplifyCfg-elaborate-drops.after.mir | 10 +- src/test/mir-opt/retag.rs | 6 +- ...foo.SimplifyCfg-elaborate-drops.after.mir} | 0 ...shr.SimplifyCfg-elaborate-drops.after.mir} | 0 ...c.try_identity.DestinationPropagation.diff | 72 + ...mple_match.match_bool.mir_map.0.32bit.mir} | 0 ...mple_match.match_bool.mir_map.0.64bit.mir} | 0 src/test/mir-opt/simplify-arm.rs | 2 +- ...ocals-removes-unused-discriminant-reads.rs | 2 + .../simplify_arm.id.SimplifyArmIdentity.diff | 2 +- .../simplify_arm.id.SimplifyBranchSame.diff | 29 +- ...ntity.main.SimplifyArmIdentity.32bit.diff} | 0 ...ntity.main.SimplifyArmIdentity.64bit.diff} | 0 ...inant_reads.map.SimplifyLocals.32bit.diff} | 32 +- ...inant_reads.map.SimplifyLocals.64bit.diff} | 32 +- src/test/mir-opt/simplify_try.rs | 2 + ...y.try_identity.DestinationPropagation.diff | 68 + ..._try.try_identity.SimplifyArmIdentity.diff | 104 +- ....try_identity.SimplifyBranchSame.after.mir | 58 +- ..._try.try_identity.SimplifyLocals.after.mir | 16 +- src/test/mir-opt/simplify_try_if_let.rs | 9 +- ....{impl#0}-append.SimplifyArmIdentity.diff} | 18 +- src/test/mir-opt/slice-drop-shim.rs | 2 +- ...].AddMovesForPackedDrops.before.32bit.mir} | 4 +- ...].AddMovesForPackedDrops.before.64bit.mir} | 4 +- src/test/mir-opt/spanview-block.rs | 5 + src/test/mir-opt/spanview-statement.rs | 5 + src/test/mir-opt/spanview-terminator.rs | 5 + .../spanview_block.main.mir_map.0.html | 67 + .../spanview_block.main.mir_map.0.html.mir | 67 + .../spanview_statement.main.mir_map.0.html | 67 + ...spanview_statement.main.mir_map.0.html.mir | 67 + .../spanview_terminator.main.mir_map.0.html | 66 + ...panview_terminator.main.mir_map.0.html.mir | 66 + .../mir-opt/storage_ranges.main.nll.0.mir | 2 +- src/test/mir-opt/unusual-item-types.rs | 8 +- ...ypes.E-V-{constant#0}.mir_map.0.32bit.mir} | 4 +- ...ypes.E-V-{constant#0}.mir_map.0.64bit.mir} | 4 +- ...est-X-{constructor#0}.mir_map.0.32bit.mir} | 0 ...est-X-{constructor#0}.mir_map.0.64bit.mir} | 0 ..._.AddMovesForPackedDrops.before.32bit.mir} | 6 +- ..._.AddMovesForPackedDrops.before.64bit.mir} | 6 +- ...}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir} | 0 ...}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir} | 0 ...ops.change_loop_body.ConstProp.32bit.diff} | 0 ...ops.change_loop_body.ConstProp.64bit.diff} | 0 ...ange_loop_body.PreCodegen.after.32bit.mir} | 0 ...ange_loop_body.PreCodegen.after.64bit.mir} | 0 src/test/pretty/issue-4264.pp | 56 +- .../foreign-exceptions/foo.cpp | 6 +- .../foreign-exceptions/foo.rs | 21 +- .../Makefile | 81 + ...d_export_coverage.coverage_of_if_else.json | 59 + .../prettify_json.py | 0 ...ical_show_coverage.coverage_of_if_else.txt | 64 + .../Makefile | 15 + ...d_export_coverage.coverage_of_if_else.json | 59 + ...ical_show_coverage.coverage_of_if_else.txt | 64 + .../instrument-coverage-llvm-ir-base/Makefile | 65 + .../filecheck.testprog.txt | 49 + .../testprog.rs | 0 .../Makefile | 11 + .../Makefile | 42 + ...lse.main.-------.InstrumentCoverage.0.html | 808 + .../Makefile | 11 + ...lse.main.-------.InstrumentCoverage.0.html | 808 + .../instrument-coverage/Makefile | 103 - .../compiletest-ignore-dir | 3 + .../coverage_of_if_else.rs | 51 + .../instrument-coverage/coverage_tools.mk | 39 + .../expected_export_coverage.json | 59 - .../filecheck-patterns.txt | 51 - .../typical_show_coverage.txt | 55 - src/test/run-make-fulldeps/issue-19371/foo.rs | 1 + src/test/run-make-fulldeps/issue-69368/a.rs | 5 + .../pgo-branch-weights/Makefile | 4 + .../run-make-fulldeps/pgo-gen-lto/Makefile | 4 + src/test/run-make-fulldeps/pgo-gen/Makefile | 4 + .../pgo-indirect-call-promotion/Makefile | 4 + src/test/run-make-fulldeps/pgo-use/Makefile | 4 + src/test/run-make-fulldeps/tools.mk | 4 +- .../type-mismatch-same-crate-name/Makefile | 4 +- .../run-make/thumb-none-cortex-m/Makefile | 2 +- src/test/run-make/thumb-none-qemu/script.sh | 4 +- .../x86_64-fortanix-unknown-sgx-lvi/Makefile | 23 + .../cc_plus_one_asm.checks | 8 + .../cc_plus_one_c.checks | 6 + .../cc_plus_one_c_asm.checks | 15 + .../cc_plus_one_cxx.checks | 6 + .../cc_plus_one_cxx_asm.checks | 16 + .../cmake_plus_one_asm.checks | 7 + .../cmake_plus_one_c.checks | 6 + .../cmake_plus_one_c_asm.checks | 16 + .../cmake_plus_one_c_global_asm.checks | 2 + .../cmake_plus_one_cxx.checks | 6 + .../cmake_plus_one_cxx_asm.checks | 16 + .../cmake_plus_one_cxx_global_asm.checks | 2 + .../enclave/Cargo.toml | 13 + .../enclave/build.rs | 30 + .../enclave/foo.c | 18 + .../enclave/foo_asm.s | 7 + .../enclave/foo_cxx.cpp | 21 + .../enclave/libcmake_foo/CMakeLists.txt | 33 + .../enclave/libcmake_foo/src/foo.c | 26 + .../enclave/libcmake_foo/src/foo_asm.s | 7 + .../enclave/libcmake_foo/src/foo_cxx.cpp | 29 + .../enclave/src/main.rs | 48 + .../jumpto.checks | 8 + .../print.checks | 7 + .../rust_plus_one_global_asm.checks | 2 + .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 57 + .../unw_getcontext.checks | 6 + .../rustdoc-ui/assoc-item-not-in-scope.stderr | 3 +- src/test/rustdoc-ui/check-doc-alias-attr.rs | 6 + .../rustdoc-ui/check-doc-alias-attr.stderr | 34 +- .../rustdoc-ui/coverage/doc-examples.stdout | 4 +- .../deny-intra-link-resolution-failure.stderr | 2 +- src/test/rustdoc-ui/doc-alias-assoc-const.rs | 22 + .../rustdoc-ui/doc-alias-assoc-const.stderr | 8 + src/test/rustdoc-ui/failed-doctest-output.rs | 2 +- ...finite-recursive-type-impl-trait-return.rs | 2 +- .../rustdoc-ui/intra-doc-alias-ice.stderr | 3 +- .../rustdoc-ui/intra-link-double-anchor.rs | 7 + .../intra-link-double-anchor.stderr | 10 + src/test/rustdoc-ui/intra-link-errors.rs | 105 + src/test/rustdoc-ui/intra-link-errors.stderr | 143 + .../rustdoc-ui/intra-link-prim-conflict.rs | 4 +- .../intra-link-prim-conflict.stderr | 20 +- .../intra-link-span-ice-55723.stderr | 2 +- .../rustdoc-ui/intra-links-ambiguity.stderr | 16 +- .../rustdoc-ui/intra-links-anchors.stderr | 6 +- .../intra-links-disambiguator-mismatch.rs | 22 +- .../intra-links-disambiguator-mismatch.stderr | 22 +- .../intra-links-private.private.stderr | 2 +- .../intra-links-private.public.stderr | 2 +- .../intra-links-warning-crlf.stderr | 8 +- .../rustdoc-ui/intra-links-warning.stderr | 44 +- .../rustdoc-ui/issue-74134.private.stderr | 2 +- src/test/rustdoc-ui/issue-74134.public.stderr | 2 +- src/test/rustdoc-ui/lint-group.stderr | 2 +- src/test/rustdoc-ui/private-doc-test.rs | 12 + src/test/rustdoc-ui/unknown-renamed-lints.rs | 8 + .../rustdoc-ui/unknown-renamed-lints.stderr | 28 + .../auxiliary/intra-link-cross-crate-crate.rs | 5 + .../rustdoc/auxiliary/intra-link-pub-use.rs | 4 + src/test/rustdoc/bad-codeblock-syntax.rs | 12 +- src/test/rustdoc/const-display.rs | 6 +- src/test/rustdoc/const-generics/type-alias.rs | 6 + src/test/rustdoc/duplicate-cfg.rs | 26 +- src/test/rustdoc/index-page.rs | 4 +- src/test/rustdoc/intra-doc-crate/traits.rs | 2 - src/test/rustdoc/intra-doc-link-private.rs | 6 + .../rustdoc/intra-link-associated-items.rs | 2 + .../rustdoc/intra-link-cross-crate-crate.rs | 6 + .../intra-link-disambiguators-removed.rs | 51 + src/test/rustdoc/intra-link-prim-assoc.rs | 5 + src/test/rustdoc/intra-link-pub-use.rs | 27 + src/test/rustdoc/issue-76501.rs | 18 + src/test/rustdoc/plain-text-summaries.rs | 26 + src/test/rustdoc/primitive-link.rs | 7 + src/test/rustdoc/trait-impl.rs | 46 + .../ui-fulldeps/auxiliary/proc-macro-panic.rs | 13 + src/test/ui-fulldeps/compiler-calls.rs | 8 +- .../dropck-tarena-cycle-checked.stderr | 2 +- .../dropck-tarena-unsound-drop.stderr | 2 +- .../internal-lints/pass_ty_by_ref_self.rs | 33 + .../internal-lints/pass_ty_by_ref_self.stderr | 20 + .../issue-76270-panic-in-libproc-macro.rs | 17 + .../issue-76270-panic-in-libproc-macro.stderr | 10 + src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 3 +- src/test/ui-fulldeps/session-derive-errors.rs | 260 + .../ui-fulldeps/session-derive-errors.stderr | 124 + src/test/ui/access-mode-in-closures.stderr | 2 +- src/test/ui/allocator/custom.rs | 5 +- src/test/ui/allocator/not-an-allocator.stderr | 16 +- .../anonymous-higher-ranked-lifetime.stderr | 8 +- src/test/ui/array-slice-vec/arr_cycle.rs | 31 - src/test/ui/array-slice-vec/slice-2.rs | 62 - .../slice-pat-type-mismatches.rs | 2 +- .../slice-pat-type-mismatches.stderr | 4 +- src/test/ui/array-slice-vec/vec-concat.rs | 14 - src/test/ui/array-slice-vec/vec-growth.rs | 16 - src/test/ui/array-slice-vec/vec-push.rs | 3 - src/test/ui/array-slice-vec/vec-slice-drop.rs | 31 - src/test/ui/array-slice-vec/vec-slice.rs | 9 - src/test/ui/array-slice-vec/vec-to_str.rs | 12 - src/test/ui/array-slice-vec/vec.rs | 15 - src/test/ui/array-slice-vec/vec_cycle.rs | 39 - .../ui/array-slice-vec/vec_cycle_wrapped.rs | 50 - src/test/ui/array_const_index-0.rs | 2 +- src/test/ui/array_const_index-0.stderr | 2 +- src/test/ui/array_const_index-1.rs | 2 +- src/test/ui/array_const_index-1.stderr | 2 +- src/test/ui/asm/type-check-1.stderr | 6 +- src/test/ui/asm/type-check-2.rs | 2 +- src/test/ui/asm/type-check-2.stderr | 2 +- src/test/ui/asm/type-check-3.rs | 4 +- src/test/ui/asm/type-check-3.stderr | 4 +- .../defaults-cyclic-fail.stderr | 14 +- .../defaults-not-assumed-fail.stderr | 2 +- ...20-assoc-const-arith-overflow.noopt.stderr | 16 +- ...9020-assoc-const-arith-overflow.opt.stderr | 16 +- ...h-overflow.opt_with_overflow_checks.stderr | 16 +- ...9-assoc-const-static-recursion-impl.stderr | 14 +- ...onst-static-recursion-trait-default.stderr | 14 +- ...-assoc-const-static-recursion-trait.stderr | 14 +- .../assoc-type-eq-with-dyn-atb-fail.rs | 2 +- .../assoc-type-eq-with-dyn-atb-fail.stderr | 4 +- .../bad-bounds-on-assoc-in-trait.rs | 12 +- .../bad-bounds-on-assoc-in-trait.stderr | 52 +- .../ui/associated-type-bounds/duplicate.rs | 159 +- .../associated-type-bounds/duplicate.stderr | 362 +- .../ui/associated-type-bounds/inside-adt.rs | 13 +- .../associated-type-bounds/inside-adt.stderr | 115 +- ...sociated-types-in-ambiguous-context.stderr | 2 +- .../associated-types-issue-20346.stderr | 6 +- ...sociated-types-overridden-binding-2.stderr | 4 +- ...associated-types-overridden-binding.stderr | 8 +- .../associated-types-unsized.fixed | 2 +- .../associated-types-unsized.stderr | 6 +- .../associated-types/defaults-suitability.rs | 14 +- .../defaults-suitability.stderr | 56 +- .../defaults-unsound-62211-1.rs | 8 +- .../defaults-unsound-62211-1.stderr | 40 +- .../defaults-unsound-62211-2.rs | 8 +- .../defaults-unsound-62211-2.stderr | 40 +- .../hr-associated-type-bound-1.rs | 2 +- .../hr-associated-type-bound-1.stderr | 8 +- .../hr-associated-type-bound-2.stderr | 2 +- .../hr-associated-type-bound-object.rs | 2 +- .../hr-associated-type-bound-object.stderr | 8 +- .../hr-associated-type-bound-param-1.rs | 2 +- .../hr-associated-type-bound-param-1.stderr | 8 +- .../hr-associated-type-bound-param-2.rs | 6 +- .../hr-associated-type-bound-param-2.stderr | 24 +- .../hr-associated-type-bound-param-3.rs | 4 +- .../hr-associated-type-bound-param-3.stderr | 10 +- .../hr-associated-type-bound-param-4.rs | 2 +- .../hr-associated-type-bound-param-4.stderr | 8 +- .../hr-associated-type-bound-param-5.rs | 10 +- .../hr-associated-type-bound-param-5.stderr | 40 +- .../hr-associated-type-bound-param-6.rs | 2 +- .../hr-associated-type-bound-param-6.stderr | 8 +- .../hr-associated-type-projection-1.rs | 4 +- .../hr-associated-type-projection-1.stderr | 16 +- .../ui/associated-types/issue-43924.stderr | 12 +- .../ui/associated-types/issue-63593.stderr | 4 +- .../missing-associated-types.stderr | 22 +- ...with-supertraits-needing-sized-self.stderr | 6 +- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- ...ync-block-control-flow-static-semantics.rs | 5 +- ...block-control-flow-static-semantics.stderr | 24 +- .../ui/async-await/async-error-span.stderr | 2 +- .../ui/async-await/async-fn-nonsend.stderr | 12 +- .../incorrect-syntax-suggestions.rs | 4 +- .../incorrect-syntax-suggestions.stderr | 16 +- .../dont-suggest-missing-await.stderr | 2 +- src/test/ui/async-await/issue-61076.rs | 45 +- src/test/ui/async-await/issue-61076.stderr | 72 +- .../ui/async-await/issue-64130-1-sync.stderr | 2 +- .../ui/async-await/issue-64130-2-send.stderr | 2 +- .../ui/async-await/issue-64130-3-other.rs | 2 +- .../ui/async-await/issue-64130-3-other.stderr | 6 +- .../issue-64130-4-async-move.stderr | 4 +- .../issue-64130-non-send-future-diags.stderr | 4 +- .../issue-67252-unnamed-future.stderr | 2 +- src/test/ui/async-await/issue-68112.rs | 2 +- src/test/ui/async-await/issue-68112.stderr | 36 +- src/test/ui/async-await/issue-68523.rs | 2 +- src/test/ui/async-await/issue-68523.stderr | 4 +- src/test/ui/async-await/issue-70594.stderr | 4 +- src/test/ui/async-await/issue-70818.stderr | 6 +- src/test/ui/async-await/issue-71137.stderr | 4 +- src/test/ui/async-await/issue-72442.stderr | 6 +- .../issue-72590-type-error-sized.stderr | 2 +- .../async-await/issues/issue-62009-1.stderr | 4 +- src/test/ui/async-await/issues/issue-65159.rs | 2 +- .../issue-65436-raw-ptr-not-send.stderr | 2 +- .../issue-66958-non-copy-infered-type-arg.rs | 2 +- ...sue-66958-non-copy-infered-type-arg.stderr | 6 +- src/test/ui/async-await/issues/issue-67893.rs | 2 +- .../ui/async-await/issues/issue-67893.stderr | 18 +- src/test/ui/async-await/no-const-async.rs | 1 - src/test/ui/async-await/no-const-async.stderr | 12 +- .../no-move-across-await-struct.stderr | 2 +- .../no-move-across-await-tuple.stderr | 2 +- .../suggest-missing-await-closure.stderr | 2 +- .../async-await/suggest-missing-await.stderr | 4 +- .../suggest-switching-edition-on-await.stderr | 2 +- .../async-await/try-on-option-in-async.stderr | 18 +- src/test/ui/atomic-from-mut-not-available.rs | 7 + .../ui/atomic-from-mut-not-available.stderr | 9 + .../attributes/register-attr-tool-prelude.rs | 2 +- .../register-attr-tool-prelude.stderr | 4 +- src/test/ui/auto-ref-slice-plus-ref.stderr | 6 +- src/test/ui/autoderef-full-lval.rs | 4 +- src/test/ui/autoderef-full-lval.stderr | 12 +- .../using-target-feature-unstable.rs | 4 +- src/test/ui/bad/bad-const-type.rs | 2 +- src/test/ui/bad/bad-const-type.stderr | 2 +- src/test/ui/bad/bad-expr-path.stderr | 2 +- src/test/ui/bad/bad-expr-path2.stderr | 2 +- .../ui/bad/bad-method-typaram-kind.stderr | 4 +- src/test/ui/bad/bad-module.rs | 4 +- src/test/ui/bad/bad-module.stderr | 8 +- src/test/ui/bad/bad-sized.stderr | 10 +- .../binding/issue-53114-borrow-checks.stderr | 24 +- src/test/ui/binop/binop-bitxor-str.rs | 2 +- src/test/ui/binop/binop-bitxor-str.stderr | 6 +- .../ui/blind/blind-item-block-middle.stderr | 2 +- .../consider-removing-last-semi.stderr | 4 +- src/test/ui/block-result/issue-13428.stderr | 4 +- src/test/ui/block-result/issue-13624.rs | 4 +- src/test/ui/block-result/issue-13624.stderr | 4 +- src/test/ui/block-result/issue-20862.stderr | 2 +- src/test/ui/block-result/issue-22645.stderr | 2 +- ...atterns-slice-patterns-box-patterns.stderr | 6 +- ...ck-borrow-mut-base-ptr-in-aliasable-loc.rs | 2 +- .../borrowck-borrow-of-mut-base-ptr-safe.rs | 2 +- ...rrowck-borrow-overloaded-auto-deref.stderr | 28 +- .../borrowck-borrow-overloaded-deref.stderr | 14 +- .../borrowck-closures-slice-patterns.stderr | 4 +- .../borrowck-consume-unsize-vec.stderr | 2 +- .../borrowck-consume-upcast-box.stderr | 2 +- .../borrowck/borrowck-describe-lvalue.stderr | 2 +- .../borrowck/borrowck-drop-from-guard.stderr | 2 +- ...ature-nll-overrides-migrate.edition.stderr | 2 +- ...feature-nll-overrides-migrate.zflag.stderr | 2 +- .../borrowck-field-sensitivity.stderr | 16 +- .../ui/borrowck/borrowck-fn-in-const-a.stderr | 2 +- ...ck-for-loop-correct-cmt-for-pattern.stderr | 4 +- .../ui/borrowck/borrowck-in-static.stderr | 2 +- .../ui/borrowck/borrowck-issue-2657-2.stderr | 2 +- .../borrowck/borrowck-move-by-capture.stderr | 2 +- .../borrowck-move-error-with-note.stderr | 2 +- .../borrowck-move-from-unsafe-ptr.stderr | 2 +- .../borrowck-move-in-irrefut-pat.stderr | 6 +- ...rowck-move-moved-value-into-closure.stderr | 2 +- .../ui/borrowck/borrowck-move-mut-base-ptr.rs | 2 +- .../borrowck-move-out-from-array-match.rs | 12 +- .../borrowck-move-out-from-array-match.stderr | 44 +- ...ck-move-out-from-array-no-overlap-match.rs | 18 +- ...ove-out-from-array-no-overlap-match.stderr | 54 +- ...rowck-move-out-from-array-use-match.stderr | 68 +- ...ove-out-from-array-use-no-overlap-match.rs | 18 +- ...out-from-array-use-no-overlap-match.stderr | 54 +- .../borrowck-move-out-from-array-use.stderr | 68 +- .../borrowck-move-out-from-array.stderr | 44 +- ...k-move-out-of-overloaded-auto-deref.stderr | 2 +- ...rrowck-move-out-of-overloaded-deref.stderr | 2 +- ...rrowck-move-out-of-struct-with-dtor.stderr | 6 +- ...-move-out-of-tuple-struct-with-dtor.stderr | 6 +- .../borrowck-multiple-captures.stderr | 10 +- .../borrowck-mut-borrow-of-mut-base-ptr.rs | 2 +- ...borrowck-overloaded-index-move-from-vec.rs | 2 +- ...owck-overloaded-index-move-from-vec.stderr | 4 +- ...orrowck-overloaded-index-move-index.stderr | 2 +- src/test/ui/borrowck/borrowck-reinit.stderr | 2 +- .../borrowck-struct-update-with-dtor.stderr | 2 +- .../ui/borrowck/borrowck-swap-mut-base-ptr.rs | 2 +- .../borrowck-uninit-field-access.stderr | 6 +- .../borrowck-vec-pattern-nesting.stderr | 22 +- src/test/ui/borrowck/index-mut-help.stderr | 12 +- .../issue-27282-mutation-in-guard.stderr | 2 +- .../borrowck/issue-31287-drop-in-guard.stderr | 2 +- src/test/ui/borrowck/issue-41962.stderr | 2 +- .../issue-47215-ice-from-drop-elab.stderr | 2 +- src/test/ui/borrowck/issue-51415.stderr | 2 +- ...ted-closure-outlives-borrowed-value.stderr | 2 +- ...7-reject-move-out-of-borrow-via-pat.stderr | 2 +- src/test/ui/borrowck/issue-64453.stderr | 2 +- .../move-from-union-field-issue-66500.stderr | 8 +- src/test/ui/borrowck/move-in-pattern-mut.rs | 4 +- .../ui/borrowck/move-in-pattern-mut.stderr | 12 +- src/test/ui/borrowck/move-in-pattern.fixed | 4 +- src/test/ui/borrowck/move-in-pattern.rs | 4 +- src/test/ui/borrowck/move-in-pattern.stderr | 12 +- src/test/ui/borrowck/or-patterns.stderr | 8 +- .../two-phase-nonrecv-autoref.nll.stderr | 4 +- ...ove-upvar-from-non-once-ref-closure.stderr | 2 +- src/test/ui/bound-suggestions.fixed | 16 +- src/test/ui/bound-suggestions.rs | 4 + src/test/ui/bound-suggestions.stderr | 60 +- src/test/ui/box-into-boxed-slice-fail.rs | 5 +- src/test/ui/box-into-boxed-slice-fail.stderr | 24 +- ...builtin-superkinds-double-superkind.stderr | 8 +- .../builtin-superkinds-in-metadata.stderr | 6 +- .../builtin-superkinds-simple.rs | 2 +- .../builtin-superkinds-simple.stderr | 6 +- ...builtin-superkinds-typaram-not-send.stderr | 4 +- src/test/ui/by-move-pattern-binding.stderr | 2 +- src/test/ui/c-variadic/variadic-ffi-4.stderr | 34 +- ...-to-unsized-trait-object-suggestion.stderr | 4 +- src/test/ui/casts-differing-anon.stderr | 2 +- src/test/ui/cell-does-not-clone.rs | 26 - src/test/ui/chalkify/generic_impls.stderr | 4 +- src/test/ui/chalkify/impl_wf.stderr | 2 +- src/test/ui/chalkify/type_inference.rs | 2 +- src/test/ui/chalkify/type_inference.stderr | 10 +- src/test/ui/chalkify/type_wf.rs | 2 +- src/test/ui/chalkify/type_wf.stderr | 8 +- src/test/ui/check-doc-alias-attr.rs | 6 + src/test/ui/check-doc-alias-attr.stderr | 34 +- src/test/ui/check-static-recursion-foreign.rs | 5 +- .../ui/check-static-values-constraints.rs | 7 - .../ui/check-static-values-constraints.stderr | 78 +- src/test/ui/class-cast-to-trait.stderr | 4 +- src/test/ui/closure-expected.rs | 2 +- src/test/ui/closure-expected.stderr | 4 +- ...ds-cant-promote-superkind-in-struct.stderr | 4 +- .../ui/closures/closure-bounds-subtype.stderr | 4 +- src/test/ui/closures/closure-move-sync.rs | 2 +- src/test/ui/closures/closure-move-sync.stderr | 20 +- src/test/ui/closures/closure-no-fn-1.stderr | 2 +- src/test/ui/closures/closure-no-fn-2.stderr | 2 +- src/test/ui/closures/closure-no-fn-3.stderr | 2 +- .../ui/closures/closure-reform-bad.stderr | 2 +- .../closure_cap_coerce_many_fail.stderr | 14 +- src/test/ui/closures/issue-41366.stderr | 2 +- .../closures/print/closure-print-generic-1.rs | 23 + .../print/closure-print-generic-1.stderr | 20 + .../closures/print/closure-print-generic-2.rs | 13 + .../print/closure-print-generic-2.stderr | 20 + ...losure-print-generic-trim-off-verbose-2.rs | 16 + ...re-print-generic-trim-off-verbose-2.stderr | 20 + .../print/closure-print-generic-verbose-1.rs | 24 + .../closure-print-generic-verbose-1.stderr | 20 + .../print/closure-print-generic-verbose-2.rs | 16 + .../closure-print-generic-verbose-2.stderr | 20 + .../closures/print/closure-print-verbose.rs | 12 + .../print/closure-print-verbose.stderr | 14 + src/test/ui/cmse-nonsecure-entry/gate_test.rs | 11 + .../ui/cmse-nonsecure-entry/gate_test.stderr | 19 + .../params-on-registers.rs | 11 + .../cmse-nonsecure-entry/params-on-stack.rs | 10 + .../params-on-stack.stderr | 5 + .../ui/cmse-nonsecure-entry/trustzone-only.rs | 10 + .../trustzone-only.stderr | 9 + src/test/ui/cmse-nonsecure-entry/wrong-abi.rs | 10 + .../ui/cmse-nonsecure-entry/wrong-abi.stderr | 9 + src/test/ui/codemap_tests/bad-format-args.rs | 2 +- .../ui/codemap_tests/bad-format-args.stderr | 2 +- src/test/ui/codemap_tests/empty_span.stderr | 2 +- src/test/ui/codemap_tests/tab_3.stderr | 2 +- .../coerce-expect-unsized-ascribed.stderr | 52 +- ...conflicts-with-specific-cross-crate.stderr | 4 +- .../ui/coherence/coherence-cow.re_a.stderr | 2 +- .../ui/coherence/coherence-cow.re_b.stderr | 2 +- .../ui/coherence/coherence-cow.re_c.stderr | 2 +- .../coherence-cross-crate-conflict.stderr | 2 +- ...coherence-fundamental-trait-objects.stderr | 2 +- ...mpl-trait-for-marker-trait-negative.stderr | 4 +- ...mpl-trait-for-marker-trait-positive.stderr | 4 +- .../ui/coherence/coherence-impls-copy.stderr | 6 +- .../ui/coherence/coherence-impls-send.stderr | 6 +- src/test/ui/coherence/coherence-orphan.stderr | 2 +- .../coherence-overlapping-pairs.stderr | 2 +- .../coherence-pair-covered-uncovered-1.stderr | 2 +- .../coherence-pair-covered-uncovered.stderr | 2 +- .../ui/coherence/coherence-vec-local-2.stderr | 2 +- .../ui/coherence/coherence-vec-local.stderr | 2 +- .../ui/coherence/coherence_inherent.stderr | 4 +- .../ui/coherence/coherence_inherent_cc.stderr | 4 +- .../coherence_local_err_struct.stderr | 2 +- .../conflicting-impl-with-err.stderr | 8 +- .../impl-foreign-for-foreign[foreign].stderr | 6 +- ...pl-foreign-for-fundamental[foreign].stderr | 2 +- ...n[fundemental[foreign]]-for-foreign.stderr | 6 +- .../impl[t]-foreign-for-foreign[t].stderr | 4 +- .../trait-bound-on-type-parameter.stderr | 2 +- .../traits-misc-mismatch-1.stderr | 4 +- .../issue-2392.stderr | 2 +- .../private-field.stderr | 2 +- src/test/ui/conservative_impl_trait.stderr | 2 +- ...rder.stderr => argument_order.full.stderr} | 4 +- .../const-generics/argument_order.min.stderr | 30 + src/test/ui/const-generics/argument_order.rs | 8 +- .../array-wrapper-struct-ctor.rs | 7 +- .../array-wrapper-struct-ctor.stderr | 11 - .../auxiliary/const_generic_lib.rs | 4 +- .../ui/const-generics/auxiliary/impl-const.rs | 4 +- .../cannot-infer-type-for-const-param.rs | 6 +- .../cannot-infer-type-for-const-param.stderr | 11 - ...const-arg-type-arg-misordered.full.stderr} | 2 +- .../const-arg-type-arg-misordered.min.stderr | 12 + .../const-arg-type-arg-misordered.rs | 9 +- ...argument-cross-crate-mismatch.full.stderr} | 4 +- ...t-argument-cross-crate-mismatch.min.stderr | 15 + .../const-argument-cross-crate-mismatch.rs | 1 + .../const-argument-cross-crate.rs | 1 + ...nst-param-before-other-params.full.stderr} | 2 +- ...const-param-before-other-params.min.stderr | 32 + .../const-param-before-other-params.rs | 9 +- ...ram-type-depends-on-type-param.full.stderr | 2 +- ...aram-type-depends-on-type-param.min.stderr | 2 +- .../auxiliary/const_evaluatable_lib.rs | 9 + .../const_evaluatable_checked/closures.rs | 6 + .../const_evaluatable_checked/closures.stderr | 12 + .../const_evaluatable_checked/cross_crate.rs | 15 + .../cross_crate_predicate.rs | 14 + .../cross_crate_predicate.stderr | 50 + ...gate-const_evaluatable_checked.full.stderr | 10 + ...-gate-const_evaluatable_checked.min.stderr | 10 + .../feature-gate-const_evaluatable_checked.rs | 17 + .../const_evaluatable_checked/fn_call.rs | 30 + .../from-sig-fail.rs | 11 + .../from-sig-fail.stderr | 9 + .../const_evaluatable_checked/from-sig.rs | 14 + .../const_evaluatable_checked/impl-bounds.rs | 25 + .../infer-too-generic.rs | 24 + .../const_evaluatable_checked/less_than.rs | 14 + .../const_evaluatable_checked/let-bindings.rs | 15 + .../let-bindings.stderr | 22 + .../simple.min.stderr | 18 + .../const_evaluatable_checked/simple.rs | 17 + .../simple_fail.full.stderr | 9 + .../simple_fail.min.stderr | 10 + .../const_evaluatable_checked/simple_fail.rs | 16 + .../const_evaluatable_checked/unop.rs | 14 + .../defaults/complex-unord-param.min.stderr | 8 + .../defaults/complex-unord-param.rs | 10 +- ...stderr => intermixed-lifetime.full.stderr} | 4 +- .../defaults/intermixed-lifetime.min.stderr | 26 + .../defaults/intermixed-lifetime.rs | 12 +- .../defaults/simple-defaults.min.stderr | 8 + .../defaults/simple-defaults.rs | 9 +- .../cannot-infer-const-args.full.stderr | 4 +- .../cannot-infer-const-args.min.stderr | 4 +- .../{ => infer}/cannot-infer-const-args.rs | 0 .../ui/const-generics/infer/issue-77092.rs | 16 + .../const-generics/infer/issue-77092.stderr | 9 + .../infer/method-chain.full.stderr | 9 + .../infer/method-chain.min.stderr | 9 + .../ui/const-generics/infer/method-chain.rs | 22 + .../{ => infer}/uninferred-consts.full.stderr | 6 +- .../{ => infer}/uninferred-consts.min.stderr | 6 +- .../{ => infer}/uninferred-consts.rs | 0 src/test/ui/const-generics/invalid-enum.rs | 39 + .../ui/const-generics/invalid-enum.stderr | 99 + src/test/ui/const-generics/issue-74906.rs | 25 + .../auxiliary/const_generic_issues_lib.rs | 4 +- .../issues/issue-61336-2.full.stderr | 8 +- .../issues/issue-61336-2.min.stderr | 8 +- .../ui/const-generics/issues/issue-61336-2.rs | 2 +- .../issues/issue-61336.full.stderr | 8 +- .../issues/issue-61336.min.stderr | 8 +- .../ui/const-generics/issues/issue-61336.rs | 2 +- .../const-generics/issues/issue-61336.stderr | 8 +- .../issues/issue-61935.full.stderr | 10 + .../issues/issue-61935.min.stderr | 10 + .../ui/const-generics/issues/issue-61935.rs | 9 +- .../const-generics/issues/issue-61935.stderr | 19 - ...sue-62187-encountered-polymorphic-const.rs | 8 +- ...62187-encountered-polymorphic-const.stderr | 19 - ...e-62220.stderr => issue-62220.full.stderr} | 2 +- .../issues/issue-62220.min.stderr | 10 + .../ui/const-generics/issues/issue-62220.rs | 9 +- .../issues/issue-62456.full.stderr | 10 + .../issues/issue-62456.min.stderr | 10 + .../ui/const-generics/issues/issue-62456.rs | 9 +- .../const-generics/issues/issue-62456.stderr | 19 - ...e-62504.stderr => issue-62504.full.stderr} | 2 +- .../issues/issue-62504.min.stderr | 14 + .../ui/const-generics/issues/issue-62504.rs | 10 +- .../issues/issue-62579-no-match.min.stderr | 11 + .../issues/issue-62579-no-match.rs | 10 +- .../issues/issue-62579-no-match.stderr | 11 - ...e-62878.stderr => issue-62878.full.stderr} | 19 +- .../issues/issue-62878.min.stderr | 18 + .../ui/const-generics/issues/issue-62878.rs | 12 +- .../issues/issue-63322-forbid-dyn.full.stderr | 9 + .../issues/issue-63322-forbid-dyn.min.stderr | 18 + .../issues/issue-63322-forbid-dyn.rs | 7 +- .../issues/issue-63322-forbid-dyn.stderr | 18 - ...e-64494.stderr => issue-64494.full.stderr} | 4 +- .../issues/issue-64494.min.stderr | 28 + .../ui/const-generics/issues/issue-64494.rs | 13 +- .../ui/const-generics/issues/issue-64519.rs | 7 +- .../issues/issue-66205.full.stderr | 10 + .../issues/issue-66205.min.stderr | 10 + .../ui/const-generics/issues/issue-66205.rs | 9 +- .../const-generics/issues/issue-66205.stderr | 19 - .../ui/const-generics/issues/issue-66906.rs | 7 +- .../const-generics/issues/issue-66906.stderr | 11 - .../ui/const-generics/issues/issue-67185-1.rs | 7 +- .../issues/issue-67185-1.stderr | 11 - ...185-2.stderr => issue-67185-2.full.stderr} | 23 +- .../issues/issue-67185-2.min.stderr | 103 + .../ui/const-generics/issues/issue-67185-2.rs | 6 +- ...e-67739.stderr => issue-67739.full.stderr} | 0 .../issues/issue-67739.min.stderr | 10 + .../ui/const-generics/issues/issue-67739.rs | 11 +- .../issues/issue-68366.full.stderr | 21 + .../issues/issue-68366.min.stderr | 29 + .../ui/const-generics/issues/issue-68366.rs | 21 + .../ui/const-generics/issues/issue-68596.rs | 6 +- .../issues/issue-68615-adt.min.stderr | 11 + .../const-generics/issues/issue-68615-adt.rs | 9 +- .../issues/issue-68615-array.min.stderr | 11 + .../issues/issue-68615-array.rs | 9 +- .../issues/issue-68977.full.stderr | 10 + .../issues/issue-68977.min.stderr | 18 + .../ui/const-generics/issues/issue-68977.rs | 10 +- .../const-generics/issues/issue-68977.stderr | 19 - .../issues/issue-69654-run-pass.rs | 18 + .../ui/const-generics/issues/issue-69654.rs | 18 + .../const-generics/issues/issue-69654.stderr | 9 + .../ui/const-generics/issues/issue-70125-1.rs | 6 +- .../issues/issue-70125-1.stderr | 11 - .../ui/const-generics/issues/issue-70125-2.rs | 7 +- .../issues/issue-70125-2.stderr | 11 - .../ui/const-generics/issues/issue-70167.rs | 7 +- .../const-generics/issues/issue-70167.stderr | 11 - .../ui/const-generics/issues/issue-70225.rs | 21 + ...e-71169.stderr => issue-71169.full.stderr} | 4 +- .../issues/issue-71169.min.stderr | 18 + .../ui/const-generics/issues/issue-71169.rs | 9 +- ...e-71381.stderr => issue-71381.full.stderr} | 8 +- .../issues/issue-71381.min.stderr | 27 + .../ui/const-generics/issues/issue-71381.rs | 6 +- ...e-71382.stderr => issue-71382.full.stderr} | 2 +- .../issues/issue-71382.min.stderr | 8 + .../ui/const-generics/issues/issue-71382.rs | 6 +- ...e-71611.stderr => issue-71611.full.stderr} | 4 +- .../issues/issue-71611.min.stderr | 15 + .../ui/const-generics/issues/issue-71611.rs | 6 +- ...e-72352.stderr => issue-72352.full.stderr} | 2 +- .../issues/issue-72352.min.stderr | 8 + .../ui/const-generics/issues/issue-72352.rs | 6 +- ...e-72787.stderr => issue-72787.full.stderr} | 10 +- .../issues/issue-72787.min.stderr | 57 + .../ui/const-generics/issues/issue-72787.rs | 22 +- ...e-72819-generic-in-const-eval.full.stderr} | 2 +- ...sue-72819-generic-in-const-eval.min.stderr | 10 + .../issue-72819-generic-in-const-eval.rs | 9 +- .../ui/const-generics/issues/issue-73120.rs | 1 + .../ui/const-generics/issues/issue-73260.rs | 20 + .../const-generics/issues/issue-73260.stderr | 29 + .../issues/issue-73491.min.stderr | 11 + .../ui/const-generics/issues/issue-73491.rs | 9 +- .../issues/issue-73508.full.stderr | 8 + .../issues/issue-73508.min.stderr | 8 + .../ui/const-generics/issues/issue-73508.rs | 5 +- .../const-generics/issues/issue-73508.stderr | 17 - .../issues/issue-74101.min.stderr | 20 + .../ui/const-generics/issues/issue-74101.rs | 10 +- .../issues/issue-74255.min.stderr | 11 + .../ui/const-generics/issues/issue-74255.rs | 9 +- .../ui/const-generics/issues/issue-74634.rs | 27 + .../const-generics/issues/issue-74634.stderr | 10 + .../issues/issue-75047.min.stderr | 11 + .../ui/const-generics/issues/issue-75047.rs | 9 +- .../ui/const-generics/issues/issue-76595.rs | 17 + .../const-generics/issues/issue-76595.stderr | 9 + .../issue-76701-ty-param-in-const.full.stderr | 18 + .../issue-76701-ty-param-in-const.min.stderr | 18 + .../issues/issue-76701-ty-param-in-const.rs | 18 + .../issues/issue70273-assoc-fn.rs | 7 +- .../issues/issue70273-assoc-fn.stderr | 11 - .../const-generics/min-and-full-same-time.rs | 7 + .../min-and-full-same-time.stderr | 13 + .../forbid-non-static-lifetimes.rs | 27 + .../forbid-non-static-lifetimes.stderr | 21 + .../min_const_generics/self-ty-in-const-1.rs | 27 + .../self-ty-in-const-1.stderr | 22 + .../min_const_generics/self-ty-in-const-2.rs | 21 + .../self-ty-in-const-2.stderr | 14 + .../ui/const-generics/nested-type.full.stderr | 2 +- .../ui/const-generics/nested-type.min.stderr | 2 +- .../const-generics/occurs-check/bind-param.rs | 17 + .../occurs-check/unify-fixpoint.rs | 18 + .../occurs-check/unify-fixpoint.stderr | 27 + .../occurs-check/unify-n-nplusone.rs | 17 + .../occurs-check/unify-n-nplusone.stderr | 10 + .../occurs-check/unused-substs-1.rs | 14 + .../occurs-check/unused-substs-2.rs | 27 + .../occurs-check/unused-substs-3.rs | 18 + .../occurs-check/unused-substs-4.rs | 12 + ...ams-in-ct-in-ty-param-lazy-norm.min.stderr | 2 +- .../std/const-generics-range.min.stderr | 56 + .../std/const-generics-range.rs | 14 +- .../type-after-const-ok.min.stderr | 8 + .../ui/const-generics/type-after-const-ok.rs | 10 +- .../auxiliary/type_dependent_lib.rs | 5 +- .../type-dependent/issue-61936.rs | 18 +- .../type-dependent/issue-63695.rs | 6 +- .../type-dependent/issue-67144-1.rs | 6 +- .../type-dependent/issue-67144-2.rs | 6 +- .../type-dependent/issue-69816.rs | 6 +- .../type-dependent/issue-70217.rs | 7 +- .../type-dependent/issue-70507.rs | 6 +- .../type-dependent/issue-70586.rs | 6 +- .../type-dependent/issue-71348.min.stderr | 20 + .../type-dependent/issue-71348.rs | 10 +- .../type-dependent/issue-71382.full.stderr | 8 + .../type-dependent/issue-71382.min.stderr | 8 + .../type-dependent/issue-71382.rs | 6 +- .../type-dependent/issue-71382.stderr | 17 - .../type-dependent/issue-71805.rs | 6 +- .../type-dependent/issue-73730.rs | 6 +- .../type-dependent/non-local.rs | 6 +- .../ui/const-generics/type-dependent/qpath.rs | 6 +- .../const-generics/type-dependent/simple.rs | 6 +- .../type-dependent/type-mismatch.full.stderr | 14 + .../type-dependent/type-mismatch.min.stderr | 14 + .../type-dependent/type-mismatch.rs | 6 +- .../type-dependent/type-mismatch.stderr | 23 - ... => types-mismatch-const-args.full.stderr} | 15 +- .../types-mismatch-const-args.min.stderr | 25 + .../types-mismatch-const-args.rs | 6 +- .../uninferred-consts-during-codegen-1.rs | 7 +- .../uninferred-consts-during-codegen-1.stderr | 11 - .../uninferred-consts-during-codegen-2.rs | 7 +- .../uninferred-consts-during-codegen-2.stderr | 11 - src/test/ui/const-suggest-feature.rs | 2 - src/test/ui/const-suggest-feature.stderr | 13 +- .../ui/const_evaluatable/associated-const.rs | 11 + .../ui/const_evaluatable/function-call.rs | 19 + .../ui/const_evaluatable/function-call.stderr | 12 + .../ice-assert-fail-div-by-zero.stderr | 2 +- .../ui/consts/array-literal-index-oob.stderr | 2 +- .../ui/consts/assoc_const_generic_impl.stderr | 2 +- src/test/ui/consts/async-block.rs | 8 + src/test/ui/consts/async-block.stderr | 8 + src/test/ui/consts/auxiliary/const_fn_lib.rs | 2 +- .../ui/consts/cast-discriminant-zst-enum.rs | 15 +- src/test/ui/consts/const-array-oob.rs | 2 +- src/test/ui/consts/const-array-oob.stderr | 2 +- .../const-block-non-item-statement-3.rs | 2 +- .../const-block-non-item-statement-rpass.rs | 2 +- src/test/ui/consts/const-err-early.stderr | 10 +- src/test/ui/consts/const-err-multi.stderr | 2 +- src/test/ui/consts/const-err.stderr | 2 +- src/test/ui/consts/const-err2.noopt.stderr | 14 +- src/test/ui/consts/const-err2.opt.stderr | 14 +- ...const-err2.opt_with_overflow_checks.stderr | 14 +- .../assign-to-static-within-other-static-2.rs | 4 +- ...ign-to-static-within-other-static-2.stderr | 8 +- .../conditional_array_execution.stderr | 2 +- .../const-eval/const-eval-overflow-3.stderr | 2 +- .../const-eval/const-eval-overflow-3b.stderr | 2 +- .../const-eval/const-eval-overflow-4.stderr | 2 +- .../const-eval/const-eval-overflow-4b.stderr | 2 +- .../const-eval/const-eval-overflow2.stderr | 16 +- .../const-eval/const-eval-overflow2b.stderr | 16 +- .../const-eval/const-eval-overflow2c.stderr | 16 +- .../const-eval/const-eval-query-stack.stderr | 6 +- ...nst-pointer-values-in-various-types.stderr | 12 +- .../ui/consts/const-eval/const_fn_ptr.stderr | 14 +- .../const-eval/const_fn_ptr_fail2.stderr | 10 + .../const-eval/const_panic_libcore_main.rs | 2 + .../ui/consts/const-eval/double_check2.rs | 21 +- .../ui/consts/const-eval/double_check2.stderr | 22 - .../consts/const-eval/erroneous-const.stderr | 4 +- .../index-out-of-bounds-never-type.stderr | 2 +- .../const-eval/index_out_of_bounds.stderr | 2 +- .../index_out_of_bounds_propagated.stderr | 2 +- .../ui/consts/const-eval/issue-43197.stderr | 4 +- .../ui/consts/const-eval/issue-50814-2.stderr | 2 +- .../ui/consts/const-eval/issue-50814.stderr | 2 +- .../const-eval/issue-70804-fn-subtyping.rs | 2 +- .../const-eval/mod-static-with-const-fn.rs | 7 +- .../mod-static-with-const-fn.stderr | 16 +- .../const-eval/promoted_errors.noopt.stderr | 12 +- .../const-eval/promoted_errors.opt.stderr | 10 +- ...ted_errors.opt_with_overflow_checks.stderr | 12 +- .../ui/consts/const-eval/pub_const_err.stderr | 2 +- .../const-eval/pub_const_err_bin.stderr | 2 +- .../consts/const-eval/shift_overflow.stderr | 2 +- src/test/ui/consts/const-eval/ub-enum.stderr | 8 +- .../ui/consts/const-eval/ub-nonnull.stderr | 2 +- src/test/ui/consts/const-eval/ub-ref.stderr | 2 +- .../const-eval/unused-broken-const.stderr | 2 +- .../const-extern-fn-call-extern-fn.rs | 4 +- .../const-extern-fn-call-extern-fn.stderr | 12 +- .../const-extern-fn-min-const-fn.rs | 7 +- .../const-extern-fn-min-const-fn.stderr | 33 +- .../const-external-macro-const-err.stderr | 2 +- .../ui/consts/const-fn-not-safe-for-const.rs | 2 +- .../const-len-underflow-separate-spans.stderr | 2 +- .../ui/consts/const-len-underflow-subspans.rs | 2 +- .../const-len-underflow-subspans.stderr | 2 +- .../feature-gate-const_mut_refs.rs | 3 +- .../feature-gate-const_mut_refs.stderr | 8 +- src/test/ui/consts/const-nonzero.rs | 16 - src/test/ui/consts/const-option.rs | 14 - src/test/ui/consts/const-prop-ice.stderr | 2 +- src/test/ui/consts/const-prop-ice2.stderr | 2 +- src/test/ui/consts/const-size_of-cycle.stderr | 12 +- src/test/ui/consts/const-slice-oob.rs | 2 +- src/test/ui/consts/const-slice-oob.stderr | 2 +- src/test/ui/consts/const-unsized.stderr | 12 +- src/test/ui/consts/const-unwrap.stderr | 2 +- src/test/ui/consts/const_discriminant.rs | 16 +- ..._fn_floating_point_arithmetic.gated.stderr | 8 + .../const_fn_floating_point_arithmetic.rs | 20 + ..._fn_floating_point_arithmetic.stock.stderr | 48 + .../const_in_pattern/cross-crate-fail.rs | 2 - .../const_in_pattern/cross-crate-fail.stderr | 20 +- .../const_in_pattern/custom-eq-branch-warn.rs | 6 +- .../custom-eq-branch-warn.stderr | 12 +- .../ui/consts/const_in_pattern/issue-65466.rs | 6 +- .../const_in_pattern/issue-65466.stderr | 15 - .../const_in_pattern/no-eq-branch-fail.rs | 1 - .../const_in_pattern/no-eq-branch-fail.stderr | 8 +- .../const_in_pattern/reject_non_structural.rs | 10 - .../reject_non_structural.stderr | 82 +- .../const_in_pattern/warn_corner_cases.stderr | 18 +- src/test/ui/consts/const_let_assign3.rs | 8 +- src/test/ui/consts/const_let_assign3.stderr | 23 +- src/test/ui/consts/const_let_eq_float.rs | 4 +- .../consts/const_unsafe_unreachable_ub.stderr | 2 +- src/test/ui/consts/consts-in-patterns.rs | 2 - src/test/ui/consts/control-flow/drop-pass.rs | 1 + src/test/ui/consts/duration-consts-2.rs | 57 - src/test/ui/consts/inline_asm.rs | 2 +- src/test/ui/consts/inline_asm.stderr | 4 +- src/test/ui/consts/is_ascii.rs | 15 - src/test/ui/consts/issue-37550.rs | 2 +- src/test/ui/consts/issue-56164.rs | 7 +- src/test/ui/consts/issue-56164.stderr | 2 +- .../issue-68542-closure-in-array-len.stderr | 2 +- src/test/ui/consts/match_ice.rs | 5 +- src/test/ui/consts/match_ice.stderr | 21 +- .../consts/min_const_fn/allow_const_fn_ptr.rs | 8 +- .../min_const_fn/allow_const_fn_ptr.stderr | 15 +- .../allow_const_fn_ptr_feature_gate.rs | 11 - .../allow_const_fn_ptr_feature_gate.stderr | 11 - .../allow_const_fn_ptr_run_pass.rs | 4 +- .../min_const_fn/bad_const_fn_body_ice.rs | 4 +- .../min_const_fn/bad_const_fn_body_ice.stderr | 17 +- .../ui/consts/min_const_fn/cast_errors.rs | 12 +- .../ui/consts/min_const_fn/cast_errors.stderr | 66 +- .../ui/consts/min_const_fn/cmp_fn_pointers.rs | 5 +- .../min_const_fn/cmp_fn_pointers.stderr | 25 +- .../ui/consts/min_const_fn/min_const_fn.rs | 55 +- .../consts/min_const_fn/min_const_fn.stderr | 253 +- .../consts/min_const_fn/min_const_fn_dyn.rs | 2 +- .../min_const_fn/min_const_fn_dyn.stderr | 2 +- .../min_const_fn/min_const_fn_fn_ptr.rs | 6 +- .../min_const_fn/min_const_fn_fn_ptr.stderr | 14 +- .../min_const_fn_libstd_stability.rs | 13 +- .../min_const_fn_libstd_stability.stderr | 30 +- .../min_const_fn/min_const_fn_unsafe_bad.rs | 2 +- .../min_const_fn_unsafe_bad.stderr | 9 +- .../min_const_unsafe_fn_libstd_stability.rs | 11 +- ...in_const_unsafe_fn_libstd_stability.stderr | 30 +- .../min_const_unsafe_fn_libstd_stability2.rs | 6 +- ...n_const_unsafe_fn_libstd_stability2.stderr | 16 +- .../ui/consts/min_const_fn/mutable_borrow.rs | 4 +- .../consts/min_const_fn/mutable_borrow.stderr | 22 +- .../consts/miri_unleashed/abi-mismatch.stderr | 10 + src/test/ui/consts/miri_unleashed/box.stderr | 2 +- src/test/ui/consts/miri_unleashed/drop.rs | 2 +- src/test/ui/consts/miri_unleashed/drop.stderr | 20 +- .../miri_unleashed/mutable_references.stderr | 8 +- .../mutable_references_err.stderr | 2 +- src/test/ui/consts/miri_unleashed/tls.stderr | 4 +- src/test/ui/consts/offset_from_ub.stderr | 10 +- src/test/ui/consts/offset_ub.stderr | 22 +- src/test/ui/consts/projection_qualif.rs | 1 - .../ui/consts/projection_qualif.stock.stderr | 14 +- src/test/ui/consts/promote-not.rs | 30 + src/test/ui/consts/promote-not.stderr | 43 + src/test/ui/consts/promotion-mutable-ref.rs | 17 + src/test/ui/consts/promotion.rs | 2 +- src/test/ui/consts/ptr_comparisons.stderr | 2 +- .../recursive-zst-static.default.stderr | 12 +- src/test/ui/consts/recursive-zst-static.rs | 2 +- .../recursive-zst-static.unleash.stderr | 12 +- .../fn-call-in-non-const.rs | 2 +- .../fn-call-in-non-const.stderr | 6 +- .../migrate-fail.rs | 5 +- .../migrate-fail.stderr | 16 +- .../nll-fail.rs | 5 +- .../nll-fail.stderr | 16 +- .../trait-error.rs | 3 +- .../trait-error.stderr | 8 +- .../stable-precise-live-drops-in-libcore.rs | 22 + ...table-precise-live-drops-in-libcore.stderr | 12 + .../consts/static_mut_containing_mut_ref2.rs | 1 - ...tatic_mut_containing_mut_ref2.stock.stderr | 13 +- .../ui/consts/too_generic_eval_ice.stderr | 2 +- src/test/ui/consts/unsizing-cast-non-null.rs | 2 +- .../ui/consts/unsizing-cast-non-null.stderr | 2 +- .../ui/consts/unstable-const-fn-in-libcore.rs | 1 + .../unstable-const-fn-in-libcore.stderr | 6 +- .../unstable-precise-live-drops-in-libcore.rs | 23 + src/test/ui/conversion-methods.stderr | 10 +- src/test/ui/copy-a-resource.stderr | 6 +- src/test/ui/cross/cross-borrow-trait.rs | 2 +- src/test/ui/cross/cross-borrow-trait.stderr | 4 +- .../ui/custom_test_frameworks/mismatch.rs | 2 +- .../ui/custom_test_frameworks/mismatch.stderr | 6 +- .../dep-graph/dep-graph-caller-callee.stderr | 2 +- src/test/ui/deprecation/deprecation-lint.rs | 2 +- .../ui/deprecation/deprecation-lint.stderr | 2 +- src/test/ui/deref-lval.rs | 11 - src/test/ui/deref-suggestion.stderr | 6 +- .../ui/derived-errors/issue-31997-1.stderr | 2 +- .../derives/derive-assoc-type-not-impl.stderr | 14 +- .../derive-on-trait-item-or-impl-item.stderr | 5 +- ...ives-span-Clone-enum-struct-variant.stderr | 6 +- .../ui/derives/derives-span-Clone-enum.stderr | 6 +- .../derives/derives-span-Clone-struct.stderr | 6 +- .../derives-span-Clone-tuple-struct.stderr | 6 +- ...ives-span-Debug-enum-struct-variant.stderr | 10 +- .../ui/derives/derives-span-Debug-enum.stderr | 10 +- .../derives/derives-span-Debug-struct.stderr | 10 +- .../derives-span-Debug-tuple-struct.stderr | 10 +- .../derives-span-Default-struct.stderr | 4 +- .../derives-span-Default-tuple-struct.stderr | 4 +- ...derives-span-Eq-enum-struct-variant.stderr | 6 +- .../ui/derives/derives-span-Eq-enum.stderr | 6 +- .../ui/derives/derives-span-Eq-struct.stderr | 6 +- .../derives-span-Eq-tuple-struct.stderr | 6 +- ...rives-span-Hash-enum-struct-variant.stderr | 4 +- .../ui/derives/derives-span-Hash-enum.stderr | 4 +- .../derives/derives-span-Hash-struct.stderr | 4 +- .../derives-span-Hash-tuple-struct.stderr | 4 +- ...erives-span-Ord-enum-struct-variant.stderr | 4 +- .../ui/derives/derives-span-Ord-enum.stderr | 4 +- .../ui/derives/derives-span-Ord-struct.stderr | 4 +- .../derives-span-Ord-tuple-struct.stderr | 4 +- ...span-PartialOrd-enum-struct-variant.stderr | 10 +- .../derives-span-PartialOrd-enum.stderr | 10 +- .../derives-span-PartialOrd-struct.stderr | 10 +- ...erives-span-PartialOrd-tuple-struct.stderr | 10 +- src/test/ui/derives/deriving-copyclone.stderr | 18 +- .../deriving-no-inner-impl-error-message.rs | 2 +- ...eriving-no-inner-impl-error-message.stderr | 6 +- src/test/ui/derives/deriving-non-type.stderr | 19 +- src/test/ui/dest-prop/skeptic-miscompile.rs | 24 + src/test/ui/destructure-trait-ref.rs | 4 +- src/test/ui/destructure-trait-ref.stderr | 10 +- src/test/ui/did_you_mean/bad-assoc-ty.stderr | 4 +- src/test/ui/did_you_mean/issue-40396.rs | 21 + src/test/ui/did_you_mean/issue-40396.stderr | 83 +- .../issue-42599_available_fields_note.stderr | 10 +- ...de-confusable-in-float-literal-expt.stderr | 2 +- .../ui/did_you_mean/recursion_limit.stderr | 2 +- ...reference-without-parens-suggestion.stderr | 4 +- ...constructing-destructing-struct-let.stderr | 2 +- ...nstructing-destructing-struct-match.stderr | 2 +- src/test/ui/disambiguate-identical-names.rs | 15 + .../ui/disambiguate-identical-names.stderr | 12 + .../dropck-eyepatch-extern-crate.stderr | 4 +- .../dropck_no_diverge_on_nonregular_3.rs | 4 +- .../dropck_no_diverge_on_nonregular_3.stderr | 4 +- src/test/ui/dst/dst-bad-assign-2.stderr | 2 +- src/test/ui/dst/dst-bad-assign-3.stderr | 2 +- src/test/ui/dst/dst-bad-assign.stderr | 2 +- src/test/ui/dst/dst-bad-deep-2.stderr | 2 +- src/test/ui/dst/dst-bad-deep.stderr | 2 +- src/test/ui/dst/dst-index.stderr | 4 +- .../dst/dst-object-from-unsized-type.stderr | 8 +- src/test/ui/dst/dst-sized-trait-param.stderr | 4 +- src/test/ui/dyn-trait-compatibility.rs | 4 +- src/test/ui/dyn-trait-compatibility.stderr | 8 +- .../dst-tuple-no-reorder.rs | 26 + .../dst-tuple-zst-offsets.rs | 22 + .../issue-70453-generics-in-discr-ice.stderr | 2 +- .../issue-70453-polymorphic-ctfe.rs | 3 +- .../issue-70453-polymorphic-ctfe.stderr | 12 + src/test/ui/error-codes/E0004-2.stderr | 2 +- src/test/ui/error-codes/E0005.stderr | 2 +- src/test/ui/error-codes/E0007.stderr | 2 +- src/test/ui/error-codes/E0010-teach.rs | 1 - src/test/ui/error-codes/E0010-teach.stderr | 15 +- src/test/ui/error-codes/E0010.rs | 1 - src/test/ui/error-codes/E0010.stderr | 13 +- src/test/ui/error-codes/E0017.rs | 4 +- src/test/ui/error-codes/E0017.stderr | 51 +- src/test/ui/error-codes/E0027-teach.rs | 15 - src/test/ui/error-codes/E0027-teach.stderr | 11 - src/test/ui/error-codes/E0027.rs | 6 +- src/test/ui/error-codes/E0027.stderr | 26 +- src/test/ui/error-codes/E0029-teach.rs | 2 +- src/test/ui/error-codes/E0029-teach.stderr | 2 +- src/test/ui/error-codes/E0029.rs | 2 +- src/test/ui/error-codes/E0029.stderr | 2 +- src/test/ui/error-codes/E0067.stderr | 4 +- src/test/ui/error-codes/E0070.stderr | 12 +- src/test/ui/error-codes/E0080.rs | 2 +- src/test/ui/error-codes/E0080.stderr | 4 +- src/test/ui/error-codes/E0118-2.rs | 8 + src/test/ui/error-codes/E0118-2.stderr | 12 + src/test/ui/error-codes/E0118.stderr | 4 +- src/test/ui/error-codes/E0221.stderr | 2 +- src/test/ui/error-codes/E0276.stderr | 2 +- src/test/ui/error-codes/E0277-2.stderr | 2 +- src/test/ui/error-codes/E0277.stderr | 4 +- src/test/ui/error-codes/E0297.stderr | 2 +- src/test/ui/error-codes/E0308-2.stderr | 4 +- src/test/ui/error-codes/E0388.rs | 6 +- src/test/ui/error-codes/E0388.stderr | 49 +- src/test/ui/error-codes/E0392.stderr | 2 +- src/test/ui/error-codes/E0433.stderr | 4 +- src/test/ui/error-codes/E0446.stderr | 4 +- src/test/ui/error-codes/E0451.stderr | 4 +- src/test/ui/error-codes/E0507.stderr | 2 +- src/test/ui/error-codes/E0605.stderr | 2 +- src/test/ui/error-codes/E0616.stderr | 2 +- src/test/ui/error-codes/E0719.stderr | 4 +- .../ui/error-codes/e0119/complex-impl.stderr | 4 +- .../e0119/conflict-with-std.stderr | 8 +- .../ui/error-codes/e0119/issue-23563.stderr | 4 +- .../ui/error-codes/e0119/issue-27403.stderr | 4 +- .../ui/error-codes/e0119/issue-28981.stderr | 2 +- .../ui/error-codes/e0119/so-37347311.stderr | 2 +- src/test/ui/error-codes/ex-E0611.rs | 2 +- src/test/ui/error-codes/ex-E0611.stderr | 2 +- src/test/ui/error-festival.stderr | 2 +- src/test/ui/error-should-say-copy-not-pod.rs | 2 +- .../ui/error-should-say-copy-not-pod.stderr | 4 +- src/test/ui/estr-subtyping.stderr | 2 +- src/test/ui/eval-enum.rs | 4 +- src/test/ui/eval-enum.stderr | 4 +- src/test/ui/explore-issue-38412.stderr | 12 +- src/test/ui/export-fully-qualified.rs | 4 +- src/test/ui/export-fully-qualified.stderr | 6 +- src/test/ui/export2.rs | 2 +- src/test/ui/export2.stderr | 4 +- src/test/ui/exterior.rs | 24 - src/test/ui/extern-flag/multiple-opts.stderr | 4 +- src/test/ui/extern-flag/noprelude.stderr | 4 +- .../ui/extern-flag/public-and-private.stderr | 2 +- .../auxiliary/extern-types-inherent-impl.rs | 9 + .../ui/extern/extern-types-inherent-impl.rs | 23 +- .../extern/extern-types-not-sync-send.stderr | 4 +- .../ui/extern/extern-types-unsized.stderr | 8 +- src/test/ui/extern/extern-wrong-value-type.rs | 2 +- .../ui/extern/extern-wrong-value-type.stderr | 4 +- .../issue-36122-accessing-externed-dst.stderr | 2 +- src/test/ui/fat-ptr-cast.stderr | 2 +- ...sue-43106-gating-of-builtin-attrs-error.rs | 91 + ...43106-gating-of-builtin-attrs-error.stderr | 136 + .../issue-43106-gating-of-builtin-attrs.rs | 170 +- ...issue-43106-gating-of-builtin-attrs.stderr | 665 +- .../issue-43106-gating-of-derive.stderr | 11 +- .../issue-43106-gating-of-inline.rs | 31 - .../issue-43106-gating-of-inline.stderr | 52 - .../feature-gate-arbitrary-self-types.rs | 2 +- .../feature-gate-arbitrary-self-types.stderr | 2 +- .../feature-gate-cfg-target-has-atomic.rs | 24 + .../feature-gate-cfg-target-has-atomic.stderr | 110 +- .../feature-gate-const_fn_transmute.rs | 18 +- .../feature-gate-const_fn_transmute.stderr | 65 +- ...-gate-const_in_array_repeat_expressions.rs | 5 +- ...e-const_in_array_repeat_expressions.stderr | 16 +- .../feature-gates/feature-gate-doc_alias.rs | 4 - .../feature-gate-doc_alias.stderr | 12 - .../feature-gate-trivial_bounds.stderr | 12 +- .../feature-gate-unsized_locals.stderr | 4 +- src/test/ui/ffi_const.stderr | 1 + src/test/ui/ffi_pure.stderr | 1 + .../format-args-capture-missing-variables.rs | 6 +- ...rmat-args-capture-missing-variables.stderr | 31 +- src/test/ui/fmt/incorrect-separator.rs | 29 + src/test/ui/fmt/incorrect-separator.stderr | 44 + src/test/ui/fmt/send-sync.stderr | 20 +- src/test/ui/fn/fn-compare-mismatch.stderr | 10 +- src/test/ui/fn/fn-item-type.rs | 6 +- src/test/ui/fn/fn-item-type.stderr | 8 +- src/test/ui/fn/fn-trait-formatting.rs | 8 +- src/test/ui/fn/fn-trait-formatting.stderr | 16 +- src/test/ui/for/for-c-in-str.rs | 4 +- src/test/ui/for/for-c-in-str.stderr | 4 +- src/test/ui/for/for-loop-bogosity.stderr | 4 +- src/test/ui/format-ref-cell.rs | 10 - .../fully-qualified-type-name1.rs | 4 +- .../fully-qualified-type-name1.stderr | 4 +- .../fully-qualified-type-name4.rs | 4 +- .../fully-qualified-type-name4.stderr | 6 +- ...unctional-struct-update-noncopyable.stderr | 2 +- ...nctional-struct-update-respects-privacy.rs | 2 +- ...onal-struct-update-respects-privacy.stderr | 2 +- ...erator-yielding-or-returning-itself.stderr | 4 +- src/test/ui/generator/issue-68112.rs | 2 +- src/test/ui/generator/issue-68112.stderr | 22 +- src/test/ui/generator/not-send-sync.stderr | 18 +- .../print/generator-print-verbose-1.rs | 60 + .../print/generator-print-verbose-1.stderr | 40 + .../print/generator-print-verbose-2.rs | 24 + .../print/generator-print-verbose-2.stderr | 36 + .../print/generator-print-verbose-3.rs | 12 + .../print/generator-print-verbose-3.stderr | 19 + .../ui/generator/resume-arg-late-bound.stderr | 8 +- src/test/ui/generator/sized-yield.stderr | 4 +- src/test/ui/generator/static-generators.rs | 2 +- src/test/ui/generator/static-not-unpin.stderr | 2 +- .../type-mismatch-signature-deduction.stderr | 2 +- .../generic-associated-types-where.stderr | 2 +- .../generic-associated-types/impl_bounds.rs | 2 +- .../impl_bounds.stderr | 12 +- .../issue-47206-where-clause.stderr | 2 +- .../issue-68641-check-gat-bounds.rs | 2 +- .../issue-68641-check-gat-bounds.stderr | 8 +- .../issue-68642-broken-llvm-ir.rs | 2 +- .../issue-68642-broken-llvm-ir.stderr | 6 +- .../issue-68643-broken-mir.rs | 2 +- .../issue-68643-broken-mir.stderr | 6 +- .../issue-68644-codegen-selection.rs | 2 +- .../issue-68644-codegen-selection.stderr | 6 +- .../issue-68645-codegen-fulfillment.rs | 2 +- .../issue-68645-codegen-fulfillment.stderr | 6 +- .../issue-68656-unsized-values.rs | 2 +- .../issue-68656-unsized-values.stderr | 8 +- .../missing-bounds.fixed | 4 +- .../missing-bounds.stderr | 12 +- .../generic/generic-type-params-name-repr.rs | 4 +- .../generic-type-params-name-repr.stderr | 4 +- ...e-param-can-reference-self-in-trait.stderr | 2 +- .../half-open-range-pats-bad-types.rs | 6 +- .../half-open-range-pats-bad-types.stderr | 6 +- ...pe.bound_a_b_ret_a_vs_bound_a_ret_a.stderr | 4 +- .../hr-subtype.bound_a_vs_free_x.stderr | 4 +- ...ubtype.bound_inv_a_b_vs_bound_inv_a.stderr | 4 +- ...hr-subtype.free_inv_x_vs_free_inv_y.stderr | 8 +- .../hr-subtype.free_x_vs_free_y.stderr | 4 +- .../hrtb-exists-forall-trait-invariant.stderr | 4 +- src/test/ui/hrtb/issue-62203-hrtb-ice.stderr | 2 +- src/test/ui/huge-enum.stderr | 2 +- .../extern-prelude-from-opaque-fail.rs | 4 +- .../extern-prelude-from-opaque-fail.stderr | 8 +- src/test/ui/hygiene/fields.rs | 4 +- src/test/ui/hygiene/fields.stderr | 4 +- src/test/ui/hygiene/intercrate.rs | 2 +- src/test/ui/hygiene/intercrate.stderr | 2 +- src/test/ui/hygiene/nested_macro_privacy.rs | 2 +- .../ui/hygiene/nested_macro_privacy.stderr | 2 +- .../ui/hygiene/no_implicit_prelude.stderr | 2 +- src/test/ui/if/ifmt-unimpl.rs | 2 +- src/test/ui/if/ifmt-unimpl.stderr | 6 +- src/test/ui/ifmt.rs | 319 - src/test/ui/impl-trait/auto-trait-leak.stderr | 16 +- src/test/ui/impl-trait/auto-trait-leak2.rs | 4 +- .../ui/impl-trait/auto-trait-leak2.stderr | 24 +- src/test/ui/impl-trait/bindings-opaque.stderr | 12 +- ...n-trait-return-should-be-impl-trait.stderr | 52 +- src/test/ui/impl-trait/equality.stderr | 4 +- .../ui/impl-trait/hidden-lifetimes.stderr | 2 +- .../impl-trait/impl_trait_projections.stderr | 2 +- src/test/ui/impl-trait/issue-55872-1.rs | 10 +- src/test/ui/impl-trait/issue-55872-1.stderr | 37 +- src/test/ui/impl-trait/issue-55872-2.rs | 4 +- src/test/ui/impl-trait/issue-55872-2.stderr | 6 +- src/test/ui/impl-trait/issue-56445.rs | 3 +- src/test/ui/impl-trait/issue-72911.stderr | 16 +- .../infinite-impl-trait-issue-38064.stderr | 8 +- .../method-suggestion-no-duplication.stderr | 2 +- .../no-method-suggested-traits.stderr | 64 +- ...trait-in-return-position-impl-trait.stderr | 15 +- .../recursive-impl-trait-type-indirect.stderr | 14 +- .../impl-trait/region-escape-via-bound.stderr | 2 +- src/test/ui/impl-trait/trait_type.stderr | 8 +- .../universal-mismatched-type.stderr | 6 +- src/test/ui/impl-trait/where-allowed.rs | 2 + src/test/ui/impl-trait/where-allowed.stderr | 82 +- .../extern-prelude-extern-crate-fail.rs | 4 +- .../extern-prelude-extern-crate-fail.stderr | 8 +- src/test/ui/imports/issue-62767.rs | 23 +- src/test/ui/imports/issue-62767.stderr | 21 + src/test/ui/index-help.stderr | 4 +- src/test/ui/indexing-requires-a-uint.stderr | 4 +- ...r-async-enabled-impl-trait-bindings.stderr | 4 +- .../inference_unstable_featured.stderr | 12 +- .../ui/infinite/infinite-instantiation.rs | 3 +- .../ui/infinite/infinite-instantiation.stderr | 7 +- .../infinite/infinite-recursion-const-fn.rs | 11 +- .../infinite-recursion-const-fn.stderr | 16 +- .../infinite-tag-type-recursion.stderr | 2 +- .../ui/inner-static-type-parameter.stderr | 2 +- src/test/ui/integral-indexing.stderr | 32 +- .../interior-mutability.rs | 2 +- .../interior-mutability.stderr | 14 +- .../internal/auxiliary/internal_unstable.rs | 9 + .../ui/internal/internal-unstable-const.rs | 2 +- .../internal/internal-unstable-const.stderr | 9 +- src/test/ui/internal/internal-unstable.rs | 1 + src/test/ui/internal/internal-unstable.stderr | 8 +- .../intrinsics/panic-uninitialized-zeroed.rs | 40 +- ...lid-rustc_args_required_const-arguments.rs | 26 + ...rustc_args_required_const-arguments.stderr | 48 + src/test/ui/issue-74047.stderr | 2 +- src/test/ui/issues-71798.stderr | 2 +- src/test/ui/issues/auxiliary/issue-75907.rs | 5 + src/test/ui/issues/issue-10398.stderr | 2 +- src/test/ui/issues/issue-10412.stderr | 2 +- src/test/ui/issues/issue-10465.stderr | 4 +- src/test/ui/issues/issue-11374.stderr | 4 +- src/test/ui/issues/issue-11515.stderr | 6 +- src/test/ui/issues/issue-11771.stderr | 4 +- src/test/ui/issues/issue-11844.stderr | 6 +- src/test/ui/issues/issue-12041.stderr | 2 +- src/test/ui/issues/issue-12127.stderr | 2 +- src/test/ui/issues/issue-12552.stderr | 8 +- src/test/ui/issues/issue-12997-2.stderr | 2 +- src/test/ui/issues/issue-13407.stderr | 12 +- src/test/ui/issues/issue-13446.stderr | 4 +- src/test/ui/issues/issue-13466.rs | 8 +- src/test/ui/issues/issue-13466.stderr | 12 +- src/test/ui/issues/issue-13853-2.stderr | 2 +- src/test/ui/issues/issue-13853.stderr | 4 +- src/test/ui/issues/issue-14366.stderr | 4 +- src/test/ui/issues/issue-14915.rs | 2 +- src/test/ui/issues/issue-14915.stderr | 4 +- src/test/ui/issues/issue-15756.stderr | 2 +- src/test/ui/issues/issue-15783.rs | 4 +- src/test/ui/issues/issue-15783.stderr | 4 +- src/test/ui/issues/issue-15896.rs | 1 - src/test/ui/issues/issue-15896.stderr | 4 +- src/test/ui/issues/issue-16538.stderr | 2 +- src/test/ui/issues/issue-17252.stderr | 8 +- src/test/ui/issues/issue-17441.rs | 4 +- src/test/ui/issues/issue-17441.stderr | 4 +- src/test/ui/issues/issue-17651.stderr | 6 +- .../ui/issues/issue-17718-static-sync.stderr | 2 +- src/test/ui/issues/issue-17728.nll.stderr | 4 +- src/test/ui/issues/issue-17728.stderr | 4 +- src/test/ui/issues/issue-17904-2.stderr | 2 +- src/test/ui/issues/issue-17959.rs | 2 +- src/test/ui/issues/issue-17959.stderr | 2 +- src/test/ui/issues/issue-18400.stderr | 2 +- src/test/ui/issues/issue-18783.stderr | 4 +- src/test/ui/issues/issue-18919.stderr | 4 +- src/test/ui/issues/issue-1920-1.rs | 2 +- src/test/ui/issues/issue-1920-1.stderr | 4 +- src/test/ui/issues/issue-1920-2.rs | 2 +- src/test/ui/issues/issue-1920-2.stderr | 4 +- src/test/ui/issues/issue-1920-3.rs | 2 +- src/test/ui/issues/issue-1920-3.stderr | 4 +- src/test/ui/issues/issue-19538.stderr | 2 +- src/test/ui/issues/issue-20005.stderr | 4 +- src/test/ui/issues/issue-20162.rs | 2 +- src/test/ui/issues/issue-20162.stderr | 4 +- src/test/ui/issues/issue-20413.stderr | 2 +- src/test/ui/issues/issue-20433.stderr | 4 +- src/test/ui/issues/issue-20605.stderr | 6 +- src/test/ui/issues/issue-20692.stderr | 2 +- src/test/ui/issues/issue-2111.stderr | 2 +- src/test/ui/issues/issue-21160.rs | 2 +- src/test/ui/issues/issue-21160.stderr | 4 +- src/test/ui/issues/issue-21332.rs | 2 +- src/test/ui/issues/issue-21332.stderr | 4 +- src/test/ui/issues/issue-21596.stderr | 2 +- src/test/ui/issues/issue-21763.rs | 2 +- src/test/ui/issues/issue-21763.stderr | 14 +- src/test/ui/issues/issue-22034.rs | 2 +- src/test/ui/issues/issue-22034.stderr | 6 +- src/test/ui/issues/issue-2214.rs | 1 - src/test/ui/issues/issue-22289.stderr | 2 +- src/test/ui/issues/issue-22312.stderr | 2 +- src/test/ui/issues/issue-22638.rs | 1 + src/test/ui/issues/issue-22638.stderr | 5 +- src/test/ui/issues/issue-22872.stderr | 6 +- src/test/ui/issues/issue-22874.stderr | 4 +- src/test/ui/issues/issue-23024.rs | 2 +- src/test/ui/issues/issue-23024.stderr | 2 +- src/test/ui/issues/issue-23122-2.stderr | 4 +- src/test/ui/issues/issue-23281.stderr | 4 +- src/test/ui/issues/issue-23302-1.stderr | 8 +- src/test/ui/issues/issue-23302-2.stderr | 8 +- src/test/ui/issues/issue-23302-3.stderr | 14 +- src/test/ui/issues/issue-23966.stderr | 4 +- src/test/ui/issues/issue-24352.stderr | 2 +- src/test/ui/issues/issue-24446.stderr | 4 +- src/test/ui/issues/issue-24819.rs | 2 +- src/test/ui/issues/issue-24819.stderr | 6 +- src/test/ui/issues/issue-25368.stderr | 4 +- src/test/ui/issues/issue-25386.rs | 4 +- src/test/ui/issues/issue-25386.stderr | 4 +- src/test/ui/issues/issue-2590.stderr | 2 +- src/test/ui/issues/issue-26472.rs | 4 +- src/test/ui/issues/issue-26472.stderr | 4 +- src/test/ui/issues/issue-27060-2.stderr | 2 +- src/test/ui/issues/issue-27078.stderr | 4 +- src/test/ui/issues/issue-2718-a.rs | 2 +- src/test/ui/issues/issue-2718-a.stderr | 4 +- ...issue-27282-move-ref-mut-into-guard.stderr | 2 +- src/test/ui/issues/issue-28098.stderr | 20 +- src/test/ui/issues/issue-2823.stderr | 6 +- src/test/ui/issues/issue-28344.stderr | 12 +- src/test/ui/issues/issue-29723.stderr | 2 +- src/test/ui/issues/issue-30355.stderr | 2 +- src/test/ui/issues/issue-31173.stderr | 18 +- src/test/ui/issues/issue-32709.stderr | 4 +- src/test/ui/issues/issue-32963.rs | 2 +- src/test/ui/issues/issue-32963.stderr | 8 +- src/test/ui/issues/issue-33293.rs | 2 +- src/test/ui/issues/issue-33293.stderr | 4 +- src/test/ui/issues/issue-3344.stderr | 2 +- src/test/ui/issues/issue-33941.stderr | 10 +- src/test/ui/issues/issue-34229.stderr | 10 +- src/test/ui/issues/issue-34334.rs | 2 +- src/test/ui/issues/issue-34334.stderr | 6 +- src/test/ui/issues/issue-34784.rs | 2 + src/test/ui/issues/issue-35677.stderr | 8 +- src/test/ui/issues/issue-35869.stderr | 4 +- src/test/ui/issues/issue-35988.stderr | 4 +- src/test/ui/issues/issue-3601.stderr | 2 +- src/test/ui/issues/issue-36163.stderr | 14 +- src/test/ui/issues/issue-36299.stderr | 4 +- src/test/ui/issues/issue-36617.stderr | 3 +- src/test/ui/issues/issue-36638.stderr | 2 +- src/test/ui/issues/issue-3680.rs | 4 +- src/test/ui/issues/issue-3680.stderr | 6 +- src/test/ui/issues/issue-37026.stderr | 4 +- .../issue-37311.rs | 1 + .../issue-37311.stderr | 5 +- src/test/ui/issues/issue-37534.stderr | 2 +- src/test/ui/issues/issue-37550.rs | 2 +- src/test/ui/issues/issue-37550.stderr | 6 +- src/test/ui/issues/issue-3763.rs | 6 +- src/test/ui/issues/issue-3763.stderr | 6 +- src/test/ui/issues/issue-37884.stderr | 4 +- src/test/ui/issues/issue-38604.stderr | 4 +- src/test/ui/issues/issue-38954.stderr | 2 +- src/test/ui/issues/issue-39175.stderr | 4 +- src/test/ui/issues/issue-40000.stderr | 4 +- .../issue-40402-1.stderr | 4 +- .../issue-40402-2.stderr | 2 +- src/test/ui/issues/issue-40749.rs | 2 +- src/test/ui/issues/issue-40749.stderr | 4 +- src/test/ui/issues/issue-40827.stderr | 16 +- src/test/ui/issues/issue-41229-ref-str.stderr | 2 +- src/test/ui/issues/issue-41726.stderr | 4 +- src/test/ui/issues/issue-41974.stderr | 2 +- src/test/ui/issues/issue-42312.stderr | 12 +- src/test/ui/issues/issue-42796.stderr | 2 +- src/test/ui/issues/issue-42880.stderr | 4 +- src/test/ui/issues/issue-43023.stderr | 7 +- .../issues/issue-43420-no-over-suggest.stderr | 4 +- .../ui/issues/issue-43784-associated-type.rs | 2 +- .../issues/issue-43784-associated-type.stderr | 8 +- src/test/ui/issues/issue-43784-supertrait.rs | 2 +- .../ui/issues/issue-43784-supertrait.stderr | 8 +- src/test/ui/issues/issue-44333.rs | 9 +- src/test/ui/issues/issue-44333.stderr | 25 + src/test/ui/issues/issue-46112.stderr | 4 +- src/test/ui/issues/issue-46553.rs | 2 +- src/test/ui/issues/issue-46771.rs | 2 +- src/test/ui/issues/issue-46771.stderr | 4 +- src/test/ui/issues/issue-47646.stderr | 2 +- src/test/ui/issues/issue-47725.rs | 29 + src/test/ui/issues/issue-47725.stderr | 60 + src/test/ui/issues/issue-4972.stderr | 4 +- src/test/ui/issues/issue-49934-errors.stderr | 5 +- .../option-as_deref.rs | 2 +- .../option-as_deref.stderr | 6 +- .../option-as_deref_mut.rs | 2 +- .../option-as_deref_mut.stderr | 8 +- .../result-as_deref.stderr | 4 +- .../result-as_deref_mut.stderr | 4 +- src/test/ui/issues/issue-50480.stderr | 2 +- src/test/ui/issues/issue-50582.stderr | 2 +- src/test/ui/issues/issue-5100.rs | 2 +- src/test/ui/issues/issue-5100.stderr | 4 +- src/test/ui/issues/issue-51154.rs | 6 + src/test/ui/issues/issue-51154.stderr | 15 + src/test/ui/issues/issue-5216.stderr | 8 +- src/test/ui/issues/issue-52262.stderr | 2 +- src/test/ui/issues/issue-53348.rs | 2 +- src/test/ui/issues/issue-53348.stderr | 2 +- src/test/ui/issues/issue-53692.stderr | 6 +- src/test/ui/issues/issue-54044.rs | 14 + src/test/ui/issues/issue-54044.stderr | 29 + src/test/ui/issues/issue-54062.rs | 5 +- src/test/ui/issues/issue-54062.stderr | 15 +- src/test/ui/issues/issue-54348.stderr | 4 +- src/test/ui/issues/issue-54410.stderr | 2 +- src/test/ui/issues/issue-55796.stderr | 12 +- src/test/ui/issues/issue-56175.stderr | 8 +- src/test/ui/issues/issue-56806.stderr | 2 +- src/test/ui/issues/issue-56943.stderr | 2 +- src/test/ui/issues/issue-57741-1.stderr | 12 +- src/test/ui/issues/issue-57741.stderr | 24 +- src/test/ui/issues/issue-57843.stderr | 4 +- src/test/ui/issues/issue-58344.rs | 4 +- src/test/ui/issues/issue-58344.stderr | 12 +- src/test/ui/issues/issue-5883.stderr | 4 +- src/test/ui/issues/issue-59488.rs | 4 +- src/test/ui/issues/issue-59488.stderr | 16 +- src/test/ui/issues/issue-60218.stderr | 4 +- src/test/ui/issues/issue-61106.stderr | 2 +- src/test/ui/issues/issue-61108.stderr | 2 +- src/test/ui/issues/issue-64559.stderr | 2 +- src/test/ui/issues/issue-6458-4.stderr | 2 +- src/test/ui/issues/issue-65611.stderr | 2 +- .../issue-65634-raw-ident-suggestion.stderr | 4 +- src/test/ui/issues/issue-65673.stderr | 2 +- ...e-66923-show-error-for-correct-call.stderr | 12 +- .../issue-67039-unsound-pin-partialeq.stderr | 8 +- src/test/ui/issues/issue-67552.rs | 1 + src/test/ui/issues/issue-67552.stderr | 5 +- src/test/ui/issues/issue-69725.stderr | 14 +- src/test/ui/issues/issue-7013.rs | 2 +- src/test/ui/issues/issue-7013.stderr | 10 +- src/test/ui/issues/issue-70381.rs | 6 + src/test/ui/issues/issue-70381.stderr | 8 + src/test/ui/issues/issue-7061.rs | 2 +- src/test/ui/issues/issue-7061.stderr | 6 +- ...70724-add_type_neq_err_label-unwrap.stderr | 8 +- src/test/ui/issues/issue-7092.rs | 4 +- src/test/ui/issues/issue-7092.stderr | 4 +- src/test/ui/issues/issue-71036.rs | 4 +- src/test/ui/issues/issue-71036.stderr | 6 +- src/test/ui/issues/issue-71584.stderr | 4 +- src/test/ui/issues/issue-72690.stderr | 50 +- src/test/ui/issues/issue-7364.rs | 3 +- src/test/ui/issues/issue-7364.stderr | 22 +- src/test/ui/issues/issue-73886.rs | 2 +- src/test/ui/issues/issue-73886.stderr | 2 +- src/test/ui/issues/issue-74236/main.stderr | 4 +- src/test/ui/issues/issue-75907.rs | 18 + src/test/ui/issues/issue-75907.stderr | 29 + src/test/ui/issues/issue-75907_b.rs | 11 + src/test/ui/issues/issue-75907_b.stderr | 9 + src/test/ui/issues/issue-76077-1.fixed | 18 + src/test/ui/issues/issue-76077-1.rs | 18 + src/test/ui/issues/issue-76077-1.stderr | 24 + src/test/ui/issues/issue-76077.rs | 10 + src/test/ui/issues/issue-76077.stderr | 8 + src/test/ui/issues/issue-76191.rs | 19 + src/test/ui/issues/issue-76191.stderr | 43 + src/test/ui/issues/issue-77002.rs | 16 + src/test/ui/issues/issue-77218.rs | 7 + src/test/ui/issues/issue-77218.stderr | 14 + src/test/ui/issues/issue-77919.rs | 13 + src/test/ui/issues/issue-77919.stderr | 46 + src/test/ui/issues/issue-78372.rs | 14 + src/test/ui/issues/issue-78372.stderr | 62 + src/test/ui/issues/issue-78622.rs | 7 + src/test/ui/issues/issue-78622.stderr | 9 + .../ui/issues/issue-8460-const.noopt.stderr | 48 +- .../ui/issues/issue-8460-const.opt.stderr | 48 +- ...8460-const.opt_with_overflow_checks.stderr | 48 +- src/test/ui/issues/issue-8727.rs | 3 +- src/test/ui/issues/issue-8727.stderr | 9 +- src/test/ui/iterators/array-of-ranges.stderr | 66 +- src/test/ui/iterators/array.stderr | 12 +- src/test/ui/iterators/bound.stderr | 2 +- src/test/ui/iterators/integral.stderr | 48 +- .../issue-58952-filter-type-length.rs | 3 +- src/test/ui/iterators/iter-zip.rs | 103 - src/test/ui/iterators/ranges.stderr | 18 +- src/test/ui/iterators/string.rs | 2 +- src/test/ui/iterators/string.stderr | 12 +- .../ui/json-bom-plus-crlf-multifile.stderr | 8 +- src/test/ui/json-bom-plus-crlf.stderr | 8 +- src/test/ui/kindck/kindck-copy.rs | 22 +- src/test/ui/kindck/kindck-copy.stderr | 48 +- .../ui/kindck/kindck-impl-type-params-2.rs | 2 +- .../kindck/kindck-impl-type-params-2.stderr | 6 +- .../kindck/kindck-impl-type-params.nll.stderr | 40 +- src/test/ui/kindck/kindck-impl-type-params.rs | 8 +- .../ui/kindck/kindck-impl-type-params.stderr | 40 +- .../kindck-inherited-copy-bound.curr.stderr | 8 +- ...copy-bound.object_safe_for_dispatch.stderr | 8 +- src/test/ui/kindck/kindck-nonsendable-1.rs | 2 +- .../ui/kindck/kindck-nonsendable-1.stderr | 10 +- src/test/ui/kindck/kindck-send-object.stderr | 10 +- .../ui/kindck/kindck-send-object1.nll.stderr | 10 +- src/test/ui/kindck/kindck-send-object1.stderr | 12 +- src/test/ui/kindck/kindck-send-object2.stderr | 10 +- src/test/ui/kindck/kindck-send-owned.stderr | 6 +- src/test/ui/kindck/kindck-send-unsafe.stderr | 2 +- ...ture-gate-lazy_normalization_consts.stderr | 2 +- .../lazy_normalization_consts/issue-73980.rs | 2 + .../issue-73980.stderr | 12 + .../lifetime-bound-will-change-warning.stderr | 8 +- .../ex2b-push-no-existing-names.nll.stderr | 2 +- ...h-anon-regions-both-are-structs.nll.stderr | 2 +- src/test/ui/lint/clashing-extern-fn.rs | 104 +- src/test/ui/lint/clashing-extern-fn.stderr | 32 +- src/test/ui/lint/dead-code/trait-impl.rs | 19 + src/test/ui/lint/lint-const-item-mutation.rs | 53 + .../ui/lint/lint-const-item-mutation.stderr | 127 + src/test/ui/lint/lint-ctypes-enum.rs | 2 +- src/test/ui/lint/lint-ctypes-enum.stderr | 8 +- src/test/ui/lint/lint-ctypes-fn.rs | 8 +- src/test/ui/lint/lint-ctypes-fn.stderr | 8 +- src/test/ui/lint/lint-ctypes.rs | 10 +- src/test/ui/lint/lint-ctypes.stderr | 10 +- .../lint-exceeding-bitshifts.noopt.stderr | 48 +- .../lint/lint-exceeding-bitshifts.opt.stderr | 48 +- ...-bitshifts.opt_with_overflow_checks.stderr | 48 +- src/test/ui/lint/lint-exceeding-bitshifts.rs | 2 +- src/test/ui/lint/lint-missing-doc.rs | 19 +- src/test/ui/lint/lint-missing-doc.stderr | 20 +- .../ui/lint/lint-owned-heap-memory.stderr | 4 +- .../lint/lint-unconditional-recursion.stderr | 2 +- src/test/ui/lint/lint-uppercase-variables.rs | 6 +- .../ui/lint/lint-uppercase-variables.stderr | 12 +- src/test/ui/lint/opaque-ty-ffi-unsafe.rs | 2 +- src/test/ui/lint/opaque-ty-ffi-unsafe.stderr | 2 +- src/test/ui/lint/uninitialized-zeroed.stderr | 14 +- src/test/ui/liveness/liveness-consts.rs | 63 + src/test/ui/liveness/liveness-consts.stderr | 68 + src/test/ui/liveness/liveness-derive.rs | 38 + src/test/ui/liveness/liveness-derive.stderr | 21 + .../ui/liveness/liveness-move-call-arg.stderr | 2 +- .../ui/liveness/liveness-move-in-loop.stderr | 2 +- .../ui/liveness/liveness-move-in-while.stderr | 2 +- .../liveness/liveness-use-after-move.stderr | 2 +- .../liveness/liveness-use-after-send.stderr | 2 +- .../ui/macros/builtin-prelude-no-accidents.rs | 6 +- .../builtin-prelude-no-accidents.stderr | 12 +- src/test/ui/macros/duplicate-builtin.rs | 17 + src/test/ui/macros/duplicate-builtin.stderr | 21 + src/test/ui/macros/issue-68060.rs | 8 +- src/test/ui/macros/issue-68060.stderr | 12 +- .../macros/macro-comma-behavior.core.stderr | 14 +- src/test/ui/macros/macro-comma-behavior.rs | 1 + .../ui/macros/macro-comma-behavior.std.stderr | 20 +- src/test/ui/macros/macro-inner-attributes.rs | 2 +- .../ui/macros/macro-inner-attributes.stderr | 4 +- .../macros/macro_path_as_generic_bound.stderr | 4 +- src/test/ui/macros/missing-comma.rs | 2 +- src/test/ui/macros/missing-comma.stderr | 2 +- src/test/ui/macros/same-sequence-span.stderr | 12 +- src/test/ui/macros/trace_faulty_macros.stderr | 3 +- src/test/ui/macros/unknown-builtin.rs | 4 +- src/test/ui/macros/unknown-builtin.stderr | 9 +- .../issue-69341-malformed-derive-inert.stderr | 3 +- .../malformed/malformed-derive-entry.stderr | 12 +- src/test/ui/map-types.rs | 2 +- src/test/ui/map-types.stderr | 4 +- .../match/const_non_normal_zst_ref_pattern.rs | 9 + src/test/ui/match/issue-70972-dyn-trait.rs | 2 +- .../ui/match/issue-70972-dyn-trait.stderr | 2 +- src/test/ui/match/match-range-fail.rs | 6 +- src/test/ui/match/match-range-fail.stderr | 6 +- src/test/ui/match/pattern-deref-miscompile.rs | 46 + ...od-ambig-one-trait-unknown-int-type.stderr | 4 +- ...method-ambig-two-traits-cross-crate.stderr | 6 +- .../ui/methods/method-call-err-msg.stderr | 8 +- ...e-trait-object-with-separate-params.stderr | 12 +- .../ui/methods/method-missing-call.stderr | 2 +- src/test/ui/minus-string.rs | 2 +- src/test/ui/minus-string.stderr | 2 +- .../ui/mir/issue-71793-inline-args-storage.rs | 16 + src/test/ui/mir/issue-76248.rs | 29 + .../ui/mir/issue-76740-copy-propagation.rs | 30 + .../mir/issue-77359-simplify-arm-identity-.rs | 35 + .../mir/mir_const_prop_tuple_field_reorder.rs | 27 + .../ui/mir/mir_detects_invalid_ops.stderr | 4 +- src/test/ui/mismatched_types/abridged.stderr | 30 +- src/test/ui/mismatched_types/binops.rs | 6 +- src/test/ui/mismatched_types/binops.stderr | 24 +- .../ui/mismatched_types/cast-rfc0401.stderr | 6 +- .../closure-arg-type-mismatch.stderr | 16 +- .../mismatched_types/closure-mismatch.stderr | 4 +- .../ui/mismatched_types/issue-36053-2.stderr | 22 +- .../issue-74918-missing-lifetime.stderr | 8 +- .../issue-75361-mismatched-impl.stderr | 8 +- .../method-help-unsatisfied-bound.stderr | 4 +- .../trait-bounds-cant-coerce.stderr | 6 +- src/test/ui/missing/missing-items/m2.stderr | 8 +- src/test/ui/missing_debug_impls.rs | 4 +- src/test/ui/missing_debug_impls.stderr | 4 +- src/test/ui/mod/mod_file_disambig.rs | 2 +- src/test/ui/mod/mod_file_disambig.stderr | 4 +- .../ui/moves/issue-46099-move-in-macro.stderr | 2 +- .../ui/moves/issue-75904-move-closure-loop.rs | 15 + .../issue-75904-move-closure-loop.stderr | 15 + src/test/ui/moves/move-deref-coercion.rs | 33 + src/test/ui/moves/move-deref-coercion.stderr | 35 + .../ui/moves/move-fn-self-receiver.stderr | 12 +- .../ui/moves/move-guard-same-consts.stderr | 2 +- src/test/ui/moves/move-in-guard-1.stderr | 2 +- src/test/ui/moves/move-in-guard-2.stderr | 2 +- .../ui/moves/move-out-of-tuple-field.stderr | 4 +- ...moves-based-on-type-access-to-field.stderr | 2 +- .../moves-based-on-type-block-bad.stderr | 2 +- ...es-based-on-type-capture-clause-bad.stderr | 2 +- ...s-based-on-type-cyclic-types-issue-4821.rs | 2 +- ...sed-on-type-cyclic-types-issue-4821.stderr | 6 +- ...ased-on-type-distribute-copy-over-paren.rs | 4 +- ...-on-type-distribute-copy-over-paren.stderr | 4 +- .../ui/moves/moves-based-on-type-exprs.stderr | 22 +- .../moves-based-on-type-match-bindings.rs | 4 +- .../moves-based-on-type-match-bindings.stderr | 6 +- ...-move-out-of-closure-env-issue-1965.stderr | 2 +- .../ui/moves/moves-based-on-type-tuple.stderr | 2 +- .../ui/moves/moves-sru-moved-field.stderr | 2 +- src/test/ui/mut/mut-cross-borrowing.stderr | 4 +- src/test/ui/mut/mutable-enum-indirect.stderr | 2 +- src/test/ui/mutexguard-sync.rs | 2 +- src/test/ui/mutexguard-sync.stderr | 8 +- src/test/ui/never_type/issue-13352.stderr | 2 +- src/test/ui/never_type/issue-2149.stderr | 6 +- src/test/ui/never_type/issue-51506.stderr | 2 +- .../ui/nll/cannot-move-block-spans.stderr | 24 +- src/test/ui/nll/closure-access-spans.stderr | 8 +- src/test/ui/nll/closure-move-spans.stderr | 6 +- .../escape-argument-callee.stderr | 2 +- .../escape-argument.stderr | 2 +- .../escape-upvar-nested.stderr | 4 +- .../escape-upvar-ref.stderr | 2 +- ...pagate-approximated-fail-no-postdom.stderr | 6 +- .../propagate-approximated-ref.stderr | 2 +- ...er-to-static-comparing-against-free.stderr | 4 +- ...oximated-shorter-to-static-no-bound.stderr | 2 +- ...mated-shorter-to-static-wrong-bound.stderr | 2 +- .../propagate-approximated-val.stderr | 2 +- .../propagate-despite-same-free-region.stderr | 2 +- ...ail-to-approximate-longer-no-bounds.stderr | 6 +- ...-to-approximate-longer-wrong-bounds.stderr | 6 +- .../propagate-from-trait-match.stderr | 2 +- .../return-wrong-bound-region.stderr | 2 +- src/test/ui/nll/closures-in-loops.stderr | 2 +- src/test/ui/nll/guarantor-issue-46974.stderr | 2 +- .../issue-21232-partial-init-and-use.stderr | 22 +- src/test/ui/nll/issue-50716.stderr | 4 +- ...eport-when-borrow-and-drop-conflict.stderr | 2 +- src/test/ui/nll/issue-52086.stderr | 4 +- ...e-52663-span-decl-captured-variable.stderr | 2 +- src/test/ui/nll/issue-53807.stderr | 2 +- .../ui/nll/issue-54556-stephaneyfx.stderr | 2 +- src/test/ui/nll/match-cfg-fake-edges.stderr | 2 +- .../ui/nll/match-guards-always-borrow.stderr | 2 +- src/test/ui/nll/move-errors.stderr | 12 +- src/test/ui/nll/move-subpaths-moves-root.rs | 2 +- .../ui/nll/move-subpaths-moves-root.stderr | 6 +- .../ui/nll/trait-associated-constant.stderr | 4 +- .../projection-no-regions-closure.rs | 4 +- .../projection-no-regions-closure.stderr | 16 +- .../ty-outlives/projection-no-regions-fn.rs | 4 +- .../projection-no-regions-fn.stderr | 8 +- .../projection-one-region-closure.stderr | 8 +- ...tion-one-region-trait-bound-closure.stderr | 10 +- ...e-region-trait-bound-static-closure.stderr | 10 +- ...tion-two-region-trait-bound-closure.stderr | 16 +- ...ram-closure-approximate-lower-bound.stderr | 4 +- ...m-closure-outlives-from-return-type.stderr | 2 +- ...-closure-outlives-from-where-clause.stderr | 8 +- .../ui/nll/type-alias-free-regions.nll.stderr | 4 +- .../ui/nll/type-alias-free-regions.stderr | 8 +- src/test/ui/no-capture-arc.stderr | 13 +- src/test/ui/no-reuse-move-arc.stderr | 13 +- src/test/ui/no-send-res-ports.rs | 2 +- src/test/ui/no-send-res-ports.stderr | 14 +- src/test/ui/no-stdio.rs | 22 +- src/test/ui/no_owned_box_lang_item.rs | 1 + src/test/ui/no_send-enum.stderr | 2 +- src/test/ui/no_send-rc.rs | 2 +- src/test/ui/no_send-rc.stderr | 6 +- src/test/ui/no_send-struct.stderr | 2 +- src/test/ui/no_share-enum.stderr | 2 +- src/test/ui/no_share-struct.stderr | 2 +- src/test/ui/noexporttypeexe.rs | 4 +- src/test/ui/noexporttypeexe.stderr | 4 +- src/test/ui/non-copyable-void.stderr | 8 +- src/test/ui/non-integer-atomic.rs | 8 +- src/test/ui/non-integer-atomic.stderr | 8 +- src/test/ui/noncopyable-class.stderr | 6 +- src/test/ui/not-clone-closure.rs | 2 +- src/test/ui/not-clone-closure.stderr | 8 +- src/test/ui/not-panic/not-panic-safe-2.rs | 4 +- src/test/ui/not-panic/not-panic-safe-2.stderr | 22 +- src/test/ui/not-panic/not-panic-safe-3.rs | 4 +- src/test/ui/not-panic/not-panic-safe-3.stderr | 22 +- src/test/ui/not-panic/not-panic-safe-4.rs | 4 +- src/test/ui/not-panic/not-panic-safe-4.stderr | 22 +- src/test/ui/not-panic/not-panic-safe-5.stderr | 8 +- src/test/ui/not-panic/not-panic-safe-6.rs | 4 +- src/test/ui/not-panic/not-panic-safe-6.stderr | 22 +- src/test/ui/not-panic/not-panic-safe.stderr | 4 +- src/test/ui/not-sync.rs | 8 +- src/test/ui/not-sync.stderr | 28 +- src/test/ui/numbers-arithmetic/arith-0.rs | 8 - src/test/ui/numbers-arithmetic/arith-1.rs | 24 - src/test/ui/numbers-arithmetic/arith-2.rs | 9 - .../overflowing-lsh-1.stderr | 2 +- .../overflowing-lsh-2.stderr | 2 +- .../overflowing-lsh-3.stderr | 2 +- .../overflowing-lsh-4.stderr | 2 +- .../overflowing-rsh-1.stderr | 2 +- .../overflowing-rsh-2.stderr | 2 +- .../overflowing-rsh-3.stderr | 2 +- .../overflowing-rsh-4.stderr | 2 +- .../overflowing-rsh-5.stderr | 2 +- .../overflowing-rsh-6.stderr | 2 +- src/test/ui/object-does-not-impl-trait.rs | 2 +- src/test/ui/object-does-not-impl-trait.stderr | 4 +- ...lifetime-default-from-box-error.nll.stderr | 2 +- ...ifetime-default-from-rptr-box-error.stderr | 4 +- src/test/ui/object-pointer-types.stderr | 4 +- ...ted-consts.object_safe_for_dispatch.stderr | 2 +- ...y-generics.object_safe_for_dispatch.stderr | 4 +- ...tions-Self.object_safe_for_dispatch.stderr | 4 +- ...-no-static.object_safe_for_dispatch.stderr | 4 +- ...ty-sized-2.object_safe_for_dispatch.stderr | 2 +- ...fety-sized.object_safe_for_dispatch.stderr | 2 +- src/test/ui/on-unimplemented/no-debug.rs | 6 +- src/test/ui/on-unimplemented/no-debug.stderr | 18 +- src/test/ui/on-unimplemented/on-trait.stderr | 12 +- .../ui/on-unimplemented/slice-index.stderr | 10 +- src/test/ui/option-to-result.stderr | 12 +- src/test/ui/option-unwrap.rs | 32 - .../exhaustiveness-non-exhaustive.stderr | 2 +- .../or-patterns-binding-type-mismatch.stderr | 26 +- .../or-patterns-syntactic-fail.stderr | 2 +- .../auxiliary/panic-runtime-lang-items.rs | 2 + src/test/ui/paren-span.rs | 2 +- src/test/ui/paren-span.stderr | 2 +- .../parser/bind-struct-early-modifiers.stderr | 6 +- src/test/ui/parser/float-field.stderr | 10 +- .../ui/parser/fn-header-semantic-fail.stderr | 4 +- src/test/ui/parser/issue-10392.stderr | 4 +- src/test/ui/parser/issue-63135.stderr | 4 +- .../parser/issue-73568-lifetime-after-mut.rs | 21 + .../issue-73568-lifetime-after-mut.stderr | 53 + .../ui/parser/lex-bad-char-literals-6.stderr | 4 +- src/test/ui/parser/mod_file_not_exist.rs | 2 +- src/test/ui/parser/mod_file_not_exist.stderr | 4 +- .../ui/parser/mod_file_not_exist_windows.rs | 2 +- .../parser/mod_file_not_exist_windows.stderr | 4 +- src/test/ui/parser/recover-range-pats.rs | 24 +- src/test/ui/parser/recover-range-pats.stderr | 24 +- src/test/ui/parser/removed-syntax-with-2.rs | 2 +- .../ui/parser/removed-syntax-with-2.stderr | 2 +- .../ui/parser/shebang/shebang-doc-comment.rs | 5 +- .../parser/shebang/shebang-doc-comment.stderr | 8 +- .../ui/parser/struct-literal-in-for.stderr | 4 +- .../parser/unclosed-delimiter-in-dep.stderr | 2 +- src/test/ui/parser/unicode-quote-chars.rs | 2 +- src/test/ui/parser/unicode-quote-chars.stderr | 2 +- src/test/ui/parser/unsafe-foreign-mod.rs | 9 + src/test/ui/parser/unsafe-foreign-mod.stderr | 14 + src/test/ui/parser/unsafe-mod.rs | 9 + src/test/ui/parser/unsafe-mod.stderr | 23 + src/test/ui/partialeq_help.stderr | 2 +- .../borrowck-move-and-move.stderr | 16 +- .../borrowck-pat-at-and-box.stderr | 10 +- ...t-by-move-and-ref-inverse-promotion.stderr | 2 +- ...orrowck-pat-by-move-and-ref-inverse.stderr | 96 +- .../borrowck-pat-ref-mut-and-ref.stderr | 8 +- .../borrowck-pat-ref-mut-twice.stderr | 16 +- ...inding-modes-both-sides-independent.stderr | 2 +- src/test/ui/pattern/const-pat-ice.rs | 8 +- src/test/ui/pattern/const-pat-ice.stderr | 13 - ...opaquely-typed-constant-used-in-pattern.rs | 3 +- ...uely-typed-constant-used-in-pattern.stderr | 4 +- .../feature-gate-move_ref_pattern.stderr | 4 +- ...ef-patterns-closure-captures-inside.stderr | 54 +- ...-ref-patterns-default-binding-modes.stderr | 4 +- .../pattern/pat-type-err-formal-param.stderr | 2 +- .../ui/pattern/pat-type-err-let-stmt.stderr | 12 +- .../ui/pattern/patkind-litrange-no-expr.rs | 2 +- .../pattern/patkind-litrange-no-expr.stderr | 2 +- src/test/ui/pattern/pattern-error-continue.rs | 2 +- .../ui/pattern/pattern-error-continue.stderr | 4 +- .../pattern-ident-path-generics.stderr | 6 +- src/test/ui/pattern/pattern-tyvar-2.rs | 2 +- src/test/ui/pattern/pattern-tyvar-2.stderr | 4 +- src/test/ui/pattern/pattern-tyvar.stderr | 6 +- .../usefulness/exhaustive_integer_patterns.rs | 2 +- .../exhaustive_integer_patterns.stderr | 10 +- .../ui/pattern/usefulness/issue-35609.stderr | 2 +- .../usefulness/match-arm-statics-2.stderr | 2 +- .../usefulness/match-privately-empty.stderr | 2 +- .../usefulness/match-slice-patterns.stderr | 2 +- .../non-exhaustive-match-nested.stderr | 2 +- .../usefulness/non-exhaustive-match.stderr | 4 +- .../refutable-pattern-errors.stderr | 4 +- .../usefulness/slice-pattern-const-2.rs | 6 +- .../usefulness/slice-pattern-const-2.stderr | 26 +- .../usefulness/slice-pattern-const-3.rs | 6 +- .../usefulness/slice-pattern-const-3.stderr | 26 +- .../slice-patterns-exhaustiveness.rs | 62 +- .../slice-patterns-exhaustiveness.stderr | 48 +- src/test/ui/phantom-oibit.stderr | 12 +- ...-to-type-err-cause-on-impl-trait-return.rs | 62 +- ...type-err-cause-on-impl-trait-return.stderr | 237 +- .../privacy/associated-item-privacy-trait.rs | 12 +- .../associated-item-privacy-trait.stderr | 12 +- .../associated-item-privacy-type-binding.rs | 32 +- ...ssociated-item-privacy-type-binding.stderr | 32 +- .../ui/privacy/private-in-public-assoc-ty.rs | 14 +- .../privacy/private-in-public-assoc-ty.stderr | 22 +- .../privacy/private-in-public-ill-formed.rs | 6 +- .../private-in-public-ill-formed.stderr | 10 +- .../private-in-public-non-principal-2.rs | 2 +- .../private-in-public-non-principal-2.stderr | 2 +- src/test/ui/privacy/private-in-public-warn.rs | 6 +- .../ui/privacy/private-in-public-warn.stderr | 6 +- src/test/ui/privacy/private-in-public.rs | 4 +- src/test/ui/privacy/private-in-public.stderr | 8 +- .../ui/privacy/private-inferred-type-1.rs | 4 +- .../ui/privacy/private-inferred-type-1.stderr | 4 +- .../ui/privacy/private-inferred-type-2.rs | 4 +- .../ui/privacy/private-inferred-type-2.stderr | 4 +- .../ui/privacy/private-inferred-type-3.rs | 4 +- .../ui/privacy/private-inferred-type-3.stderr | 4 +- src/test/ui/privacy/private-inferred-type.rs | 66 +- .../ui/privacy/private-inferred-type.stderr | 70 +- .../private-struct-field-cross-crate.rs | 2 +- .../private-struct-field-cross-crate.stderr | 2 +- .../ui/privacy/private-struct-field-ctor.rs | 2 +- .../privacy/private-struct-field-ctor.stderr | 2 +- .../privacy/private-struct-field-pattern.rs | 2 +- .../private-struct-field-pattern.stderr | 2 +- src/test/ui/privacy/private-struct-field.rs | 2 +- .../ui/privacy/private-struct-field.stderr | 2 +- .../ui/privacy/private-type-in-interface.rs | 10 +- .../privacy/private-type-in-interface.stderr | 10 +- src/test/ui/privacy/pub-priv-dep/pub-priv1.rs | 6 +- .../ui/privacy/pub-priv-dep/pub-priv1.stderr | 6 +- .../restricted/private-in-public.stderr | 8 +- .../restricted/struct-literal-field.stderr | 2 +- src/test/ui/privacy/restricted/test.stderr | 6 +- src/test/ui/privacy/union-field-privacy-1.rs | 4 +- .../ui/privacy/union-field-privacy-1.stderr | 4 +- src/test/ui/privacy/union-field-privacy-2.rs | 2 +- .../ui/privacy/union-field-privacy-2.stderr | 2 +- .../attributes-on-modules-fail.stderr | 4 +- .../proc-macro/auxiliary/macro-only-syntax.rs | 89 + .../ui/proc-macro/break-token-spans.stderr | 4 +- .../proc-macro/capture-macro-rules-invoke.rs | 29 +- .../capture-macro-rules-invoke.stdout | 303 +- .../dollar-crate-issue-57089.stdout | 32 +- .../dollar-crate-issue-62325.stdout | 44 +- src/test/ui/proc-macro/dollar-crate.stdout | 96 +- .../group-compat-hack.stdout | 12 +- .../ui/proc-macro/input-interpolated.stdout | 22 +- src/test/ui/proc-macro/issue-37788.stderr | 4 +- .../ui/proc-macro/issue-75930-derive-cfg.rs | 66 + .../proc-macro/issue-75930-derive-cfg.stdout | 1831 ++ .../issue-76182-leading-vert-pat.rs | 16 + .../issue-76182-leading-vert-pat.stdout | 62 + .../ui/proc-macro/load-panic-backtrace.rs | 21 + .../ui/proc-macro/load-panic-backtrace.stderr | 11 + .../proc-macro/macros-in-extern-derive.stderr | 3 +- src/test/ui/proc-macro/meta-macro-hygiene.rs | 3 +- .../ui/proc-macro/meta-macro-hygiene.stdout | 29 +- src/test/ui/proc-macro/meta-macro.stdout | 2 +- .../ui/proc-macro/nested-macro-rules.stdout | 8 +- .../proc-macro/nested-nonterminal-tokens.rs | 26 + .../nested-nonterminal-tokens.stdout | 60 + src/test/ui/proc-macro/nodelim-groups.stdout | 30 +- .../ui/proc-macro/resolved-located-at.stderr | 2 +- .../ui/proc-macro/span-preservation.stderr | 4 +- src/test/ui/proc-macro/trailing-plus.rs | 14 + src/test/ui/proc-macro/trailing-plus.stdout | 57 + src/test/ui/proc-macro/unsafe-foreign-mod.rs | 14 + src/test/ui/proc-macro/unsafe-mod.rs | 13 + ...174-restricted-type-in-public-interface.rs | 4 +- ...restricted-type-in-public-interface.stderr | 4 +- .../ui/qualified/qualified-path-params.rs | 5 +- .../ui/qualified/qualified-path-params.stderr | 2 +- src/test/ui/question-mark-type-infer.stderr | 2 +- .../ui/range/issue-54505-no-literals.stderr | 40 +- src/test/ui/range/issue-54505-no-std.rs | 3 + src/test/ui/range/issue-54505-no-std.stderr | 36 +- src/test/ui/range/issue-54505.stderr | 20 +- src/test/ui/range/range-1.rs | 2 +- src/test/ui/range/range-1.stderr | 10 +- src/test/ui/range/range_traits-1.stderr | 84 +- src/test/ui/realloc-16687.rs | 16 +- ...ssue-38591-non-regular-dropck-recursion.rs | 2 + ...-38591-non-regular-dropck-recursion.stderr | 25 +- src/test/ui/recursion/recursion.rs | 1 + src/test/ui/recursion/recursion.stderr | 5 +- .../recursion/recursive-requirements.stderr | 6 +- .../recursion/recursive-static-definition.rs | 2 +- .../recursive-static-definition.stderr | 12 +- src/test/ui/ref-suggestion.rs | 2 +- src/test/ui/ref-suggestion.stderr | 10 +- .../ui/regions/issue-78262.default.stderr | 18 + src/test/ui/regions/issue-78262.nll.stderr | 10 + src/test/ui/regions/issue-78262.rs | 14 + ...unds-on-objects-and-type-parameters.stderr | 2 +- .../region-object-lifetime-in-coercion.stderr | 4 +- ...s-bounded-by-trait-requiring-static.stderr | 2 +- ...s-close-associated-type-into-object.stderr | 4 +- .../regions-close-object-into-object-2.stderr | 4 +- .../regions-close-object-into-object-4.stderr | 4 +- ...-close-over-type-parameter-multiple.stderr | 4 +- .../regions-close-param-into-object.stderr | 4 +- .../regions-infer-paramd-indirect.nll.stderr | 2 +- .../regions/regions-infer-paramd-indirect.rs | 4 +- .../regions-infer-paramd-indirect.stderr | 4 +- src/test/ui/reify-intrinsic.stderr | 4 +- src/test/ui/repeat-to-run-dtor-twice.rs | 2 +- src/test/ui/repeat-to-run-dtor-twice.stderr | 4 +- src/test/ui/repeat_count.rs | 2 +- src/test/ui/repeat_count.stderr | 2 +- src/test/ui/resolve/issue-5035-2.stderr | 2 +- src/test/ui/resolve/issue-54379.stderr | 6 +- ...0736-async-fn-no-body-def-collector.stderr | 2 +- src/test/ui/resolve/name-clash-nullary.stderr | 4 +- src/test/ui/resolve/privacy-enum-ctor.stderr | 24 +- src/test/ui/resolve/use_suggestion.stderr | 6 +- src/test/ui/retslot-cast.stderr | 6 +- .../rfc-reject-double-move-across-arms.stderr | 2 +- ...rfc-reject-double-move-in-first-arm.stderr | 2 +- .../termination-trait-impl-trait.rs | 2 +- .../termination-trait-impl-trait.stderr | 4 +- .../termination-trait-main-i32.rs | 2 +- .../termination-trait-main-i32.stderr | 2 +- .../termination-trait-main-wrong-type.stderr | 2 +- .../termination-trait-not-satisfied.stderr | 2 +- .../termination-trait-test-wrong-type.stderr | 8 +- src/test/ui/rfc-2008-non-exhaustive/enum.rs | 2 +- .../ui/rfc-2008-non-exhaustive/enum.stderr | 8 +- .../improper_ctypes/extern_crate_improper.rs | 10 +- .../extern_crate_improper.stderr | 10 +- .../uninhabited/coercions.stderr | 8 +- .../uninhabited/indirect_match.stderr | 16 +- ...rect_match_with_exhaustive_patterns.stderr | 16 +- .../uninhabited/match.stderr | 14 +- .../match_with_exhaustive_patterns.stderr | 14 +- ...caller-location-fnptr-rt-ctfe-equiv.stderr | 19 +- .../rfc-2093-infer-outlives/projection.stderr | 2 +- ...ns-outlives-nominal-type-region-rev.stderr | 2 +- ...egions-outlives-nominal-type-region.stderr | 2 +- ...ions-outlives-nominal-type-type-rev.stderr | 2 +- .../regions-outlives-nominal-type-type.stderr | 2 +- .../non-existent-1.stderr | 2 +- .../non-existent-3.stderr | 2 +- .../not-allowed.stderr | 2 +- .../dbg-macro-requires-debug.rs | 2 +- .../dbg-macro-requires-debug.stderr | 8 +- .../disallowed-positions.rs | 12 +- .../disallowed-positions.stderr | 90 +- .../const-and-non-const-impl.stderr | 2 +- .../const-check-fns-in-const-impl.rs | 2 +- .../const-check-fns-in-const-impl.stderr | 7 +- .../feature-gate.gated.stderr | 2 +- .../const-trait-bound-opt-out/feature-gate.rs | 1 + .../feature-gate.stock.stderr | 2 +- .../ui/rfc-2632-const-trait-impl/stability.rs | 2 +- .../stability.stderr | 8 +- ...-hide-behind-direct-unsafe-ptr-embedded.rs | 2 + ...low-hide-behind-direct-unsafe-ptr-param.rs | 2 + ...ide-behind-indirect-unsafe-ptr-embedded.rs | 2 + ...w-hide-behind-indirect-unsafe-ptr-param.rs | 2 + ...cant-hide-behind-direct-struct-embedded.rs | 1 - ...-hide-behind-direct-struct-embedded.stderr | 8 +- .../cant-hide-behind-direct-struct-param.rs | 1 - ...ant-hide-behind-direct-struct-param.stderr | 8 +- ...nt-hide-behind-doubly-indirect-embedded.rs | 2 +- .../cant-hide-behind-doubly-indirect-param.rs | 2 +- ...nt-hide-behind-indirect-struct-embedded.rs | 2 +- .../cant-hide-behind-indirect-struct-param.rs | 2 +- ...2307-match-ref-ref-forbidden-without-eq.rs | 6 +- ...-match-ref-ref-forbidden-without-eq.stderr | 2 +- .../ui/rfc1445/issue-63479-match-fnptr.rs | 4 + .../ui/rfc1445/issue-63479-match-fnptr.stderr | 16 + .../ui/rfc1445/match-forbidden-without-eq.rs | 1 - .../rfc1445/match-forbidden-without-eq.stderr | 12 +- ...tch-nonempty-array-forbidden-without-eq.rs | 1 - ...nonempty-array-forbidden-without-eq.stderr | 8 +- .../match-requires-both-partialeq-and-eq.rs | 1 - ...atch-requires-both-partialeq-and-eq.stderr | 8 +- src/test/ui/rfc1623.nll.stderr | 8 +- src/test/ui/rfc1623.stderr | 4 +- .../rfc-2396-target_feature-11/fn-traits.rs | 12 +- .../fn-traits.stderr | 24 +- src/test/ui/rmeta_meta_main.rs | 2 +- src/test/ui/rmeta_meta_main.stderr | 2 +- ...ary-self-types-not-object-safe.curr.stderr | 4 +- ...bject-safe.object_safe_for_dispatch.stderr | 4 +- ...elf_types_pin_lifetime_mismatch.nll.stderr | 2 +- ...point-at-arbitrary-self-type-method.stderr | 2 +- ...at-arbitrary-self-type-trait-method.stderr | 2 +- src/test/ui/self/self_type_keyword.stderr | 2 +- src/test/ui/shift-various-bad-types.stderr | 6 +- src/test/ui/slice-to-vec-comparison.rs | 6 + src/test/ui/slice-to-vec-comparison.stderr | 12 + ...borrowck-call-is-borrow-issue-12224.stderr | 2 +- .../ui/span/borrowck-fn-in-const-b.stderr | 2 +- src/test/ui/span/coerce-suggestions.stderr | 12 +- .../ui/span/destructor-restrictions.stderr | 2 +- src/test/ui/span/dropck-object-cycle.stderr | 2 +- .../ui/span/impl-wrong-item-for-trait.stderr | 2 +- ...338-locals-die-before-temps-of-body.stderr | 4 +- src/test/ui/span/issue-29106.stderr | 4 +- src/test/ui/span/issue-33884.stderr | 2 +- src/test/ui/span/issue-39018.stderr | 38 +- .../issue-42234-unknown-receiver-type.stderr | 4 +- .../ui/span/issue-43927-non-ADT-derive.stderr | 3 +- src/test/ui/span/multiline-span-simple.stderr | 2 +- src/test/ui/span/mut-arg-hint.stderr | 4 +- ...ions-close-over-borrowed-ref-in-obj.stderr | 2 +- .../span/send-is-not-static-std-sync.stderr | 2 +- src/test/ui/span/type-binding.stderr | 2 +- .../deafult-associated-type-bound-1.rs | 2 +- .../deafult-associated-type-bound-1.stderr | 4 +- .../deafult-associated-type-bound-2.stderr | 2 +- ...afult-generic-associated-type-bound.stderr | 6 +- .../defaultimpl/specialization-wfcheck.rs | 2 +- .../defaultimpl/specialization-wfcheck.stderr | 8 +- src/test/ui/specialization/issue-44861.rs | 2 +- src/test/ui/specialization/issue-44861.stderr | 4 +- src/test/ui/specialization/issue-59435.rs | 2 +- src/test/ui/specialization/issue-59435.stderr | 4 +- .../repeated_projection_type.stderr | 2 +- .../specialization_super_trait.stderr | 2 +- .../specialization_trait.stderr | 2 +- .../specialization-default-types.stderr | 12 +- .../auxiliary/unstable_generic_param.rs | 229 + .../generics-default-stability-where.rs | 12 + .../generics-default-stability-where.stderr | 11 + .../generics-default-stability.rs | 264 + .../generics-default-stability.stderr | 493 + .../missing-const-stability.rs | 12 + .../missing-const-stability.stderr | 8 + .../stability-attribute-trait-impl.rs | 28 + .../stability-attribute-trait-impl.stderr | 11 + src/test/ui/static/static-mut-not-constant.rs | 1 - .../ui/static/static-mut-not-constant.stderr | 13 +- .../ui/static/static-reference-to-fn-1.stderr | 4 +- src/test/ui/statics/static-promotion.rs | 2 +- src/test/ui/stdout-during-shutdown.rs | 19 + src/test/ui/stdout-during-shutdown.run.stdout | 1 + src/test/ui/str-concat.rs | 9 - src/test/ui/str-multiline.rs | 13 - src/test/ui/str/str-array-assignment.stderr | 2 +- src/test/ui/str/str-concat-on-double-ref.rs | 2 +- .../ui/str/str-concat-on-double-ref.stderr | 4 +- src/test/ui/str/str-idx.stderr | 18 +- src/test/ui/str/str-mut-idx.stderr | 20 +- src/test/ui/string-escapes.rs | 7 - src/test/ui/structs/struct-field-cfg.stderr | 9 + src/test/ui/structs/struct-field-privacy.rs | 2 +- .../ui/structs/struct-field-privacy.stderr | 2 +- .../structs/struct-pat-derived-error.stderr | 9 + .../ui/structs/struct-path-alias-bounds.rs | 2 +- .../structs/struct-path-alias-bounds.stderr | 4 +- src/test/ui/substs-ppaux.normal.stderr | 2 +- src/test/ui/substs-ppaux.verbose.stderr | 2 +- ...adt-param-with-implicit-sized-bound.stderr | 18 +- src/test/ui/suggestions/as-ref.stderr | 6 +- ...rg-where-it-should-have-been-called.stderr | 8 +- .../suggestions/borrow-for-loop-head.stderr | 2 +- ...chain-method-call-mutation-in-place.stderr | 4 +- .../ui/suggestions/const-in-struct-pat.stderr | 2 +- src/test/ui/suggestions/const-no-type.rs | 2 +- src/test/ui/suggestions/const-no-type.stderr | 2 +- ...gest-deref-inside-macro-issue-58298.stderr | 2 +- .../dont-suggest-ref/simple.stderr | 22 +- .../expected-boxed-future-isnt-pinned.stderr | 40 +- src/test/ui/suggestions/for-i-in-vec.stderr | 2 +- src/test/ui/suggestions/format-borrow.stderr | 4 +- src/test/ui/suggestions/if-let-typo.rs | 8 + src/test/ui/suggestions/if-let-typo.stderr | 56 + .../suggestions/imm-ref-trait-object.stderr | 2 +- .../impl-trait-with-missing-bounds.rs | 10 +- .../impl-trait-with-missing-bounds.stderr | 50 +- src/test/ui/suggestions/into-str.rs | 2 +- src/test/ui/suggestions/into-str.stderr | 7 +- src/test/ui/suggestions/issue-52820.stderr | 4 +- src/test/ui/suggestions/issue-59819.stderr | 2 +- src/test/ui/suggestions/issue-62843.stderr | 8 +- .../suggestions/issue-71394-no-from-impl.rs | 2 +- .../issue-71394-no-from-impl.stderr | 6 +- src/test/ui/suggestions/issue-72766.stderr | 8 +- .../missing-lifetimes-in-signature.stderr | 8 +- .../ui/suggestions/match-ergonomics.stderr | 8 +- ...sing-assoc-fn-applicable-suggestions.fixed | 2 +- .../ui/suggestions/missing-assoc-fn.stderr | 2 +- ...issing-trait-bounds-for-method-call.stderr | 12 +- .../mut-borrow-needed-by-trait.stderr | 14 +- .../suggestions/mut-ref-reassignment.stderr | 24 +- .../ui/suggestions/opaque-type-error.stderr | 5 +- .../ui/suggestions/option-content-move.stderr | 4 +- .../suggestions/option-content-move2.stderr | 2 +- src/test/ui/suggestions/path-by-value.stderr | 4 +- src/test/ui/suggestions/path-display.stderr | 10 +- ...ecover-from-semicolon-trailing-item.stderr | 2 +- .../suggestions/restrict-type-argument.stderr | 24 +- ...n-call-with-turbofish-through-deref.stderr | 2 +- src/test/ui/suggestions/suggest-box.stderr | 4 +- .../ui/suggestions/suggest-methods.stderr | 2 +- .../ui/suggestions/suggest-private-fields.rs | 4 +- .../suggestions/suggest-private-fields.stderr | 6 +- .../suggestions/suggest-remove-refs-1.fixed | 2 +- .../ui/suggestions/suggest-remove-refs-1.rs | 2 +- .../suggestions/suggest-remove-refs-1.stderr | 8 +- .../suggestions/suggest-remove-refs-2.fixed | 2 +- .../ui/suggestions/suggest-remove-refs-2.rs | 2 +- .../suggestions/suggest-remove-refs-2.stderr | 8 +- .../suggestions/suggest-remove-refs-3.fixed | 2 +- .../ui/suggestions/suggest-remove-refs-3.rs | 2 +- .../suggestions/suggest-remove-refs-3.stderr | 8 +- .../type-ascription-instead-of-path.rs | 2 +- .../type-ascription-instead-of-path.stderr | 4 +- src/test/ui/switched-expectations.stderr | 2 +- src/test/ui/symbol-names/impl1.legacy.stderr | 2 +- src/test/ui/symbol-names/impl1.rs | 4 +- src/test/ui/symbol-names/impl1.v0.stderr | 2 +- src/test/ui/symbol-names/issue-76365.rs | 18 + .../ui/tag-that-dare-not-speak-its-name.rs | 4 +- .../tag-that-dare-not-speak-its-name.stderr | 4 +- src/test/ui/target-feature/gate.rs | 4 +- src/test/ui/target-feature/gate.stderr | 2 +- .../ui/target-feature/invalid-attribute.rs | 19 +- .../target-feature/invalid-attribute.stderr | 69 +- src/test/ui/terr-sorts.rs | 2 +- src/test/ui/terr-sorts.stderr | 4 +- .../ui/trait-impl-bound-suggestions.fixed | 20 + src/test/ui/trait-impl-bound-suggestions.rs | 20 + .../ui/trait-impl-bound-suggestions.stderr | 17 + .../ui/traits/cycle-cache-err-60010.stderr | 2 +- .../negated-auto-traits-error.stderr | 28 +- .../ui/traits/trait-alias-ambiguous.stderr | 12 +- .../trait-alias/trait-alias-cross-crate.rs | 4 +- .../trait-alias-cross-crate.stderr | 12 +- .../trait-alias/trait-alias-object-fail.rs | 2 +- .../trait-alias-object-fail.stderr | 6 +- .../trait-bounds-not-on-bare-trait.stderr | 4 +- ...rait-bounds-on-structs-and-enums-xc.stderr | 12 +- ...ait-bounds-on-structs-and-enums-xc1.stderr | 12 +- .../trait-bounds-same-crate-name.stderr | 26 +- src/test/ui/traits/trait-bounds-sugar.stderr | 6 +- .../ui/traits/trait-object-macro-matcher.rs | 2 +- .../traits/trait-object-macro-matcher.stderr | 4 +- src/test/ui/traits/trait-object-safety.stderr | 2 +- .../traits/trait-safety-trait-impl-cc.stderr | 2 +- ...ait-static-method-generic-inference.stderr | 4 +- ...trait-suggest-deferences-issue-39029.fixed | 2 +- .../trait-suggest-deferences-issue-39029.rs | 2 +- ...rait-suggest-deferences-issue-39029.stderr | 8 +- ...trait-suggest-deferences-issue-62530.fixed | 2 +- .../trait-suggest-deferences-issue-62530.rs | 2 +- ...rait-suggest-deferences-issue-62530.stderr | 4 +- .../ui/traits/trait-suggest-where-clause.rs | 6 +- .../traits/trait-suggest-where-clause.stderr | 26 +- src/test/ui/traits/trait-test-2.stderr | 4 +- ...traits-assoc-type-in-supertrait-bad.stderr | 2 +- .../traits-inductive-overflow-lifetime.stderr | 2 +- ...inductive-overflow-supertrait-oibit.stderr | 4 +- src/test/ui/traits/traits-issue-71136.stderr | 8 +- .../transmute-from-fn-item-types-error.stderr | 10 +- .../transmute-type-parameters.stderr | 2 +- .../trivial-bounds-inconsistent-copy.stderr | 8 +- .../trivial-bounds-inconsistent-sized.stderr | 6 +- ...ial-bounds-inconsistent-well-formed.stderr | 4 +- .../trivial-bounds-inconsistent.stderr | 10 +- .../trivial-bounds-leak-copy.stderr | 2 +- .../trivial-bounds/trivial-bounds-leak.stderr | 2 +- .../trivial-bounds/trivial-bounds-lint.stderr | 4 +- src/test/ui/trivial_casts.rs | 6 +- src/test/ui/trivial_casts.stderr | 8 +- src/test/ui/try-block/try-block-bad-type.rs | 4 +- .../ui/try-block/try-block-bad-type.stderr | 28 +- src/test/ui/try-block/try-block-in-return.rs | 12 + src/test/ui/try-block/try-block-in-while.rs | 2 +- .../ui/try-block/try-block-in-while.stderr | 6 +- .../try-block-maybe-bad-lifetime.stderr | 2 +- .../ui/try-block/try-block-type-error.stderr | 4 +- src/test/ui/try-on-option-diagnostics.stderr | 24 +- src/test/ui/try-on-option.stderr | 10 +- src/test/ui/try-operator-on-main.rs | 2 +- src/test/ui/try-operator-on-main.stderr | 22 +- src/test/ui/tuple/index-invalid.stderr | 8 +- .../self-in-enum-definition.rs | 4 +- .../self-in-enum-definition.stderr | 10 +- .../type-alias-impl-trait/bound_reduction2.rs | 5 +- .../bound_reduction2.stderr | 16 +- .../declared_but_not_defined_in_scope.rs | 1 + .../declared_but_not_defined_in_scope.stderr | 17 +- .../generic_duplicate_param_use2.rs | 2 +- .../generic_duplicate_param_use2.stderr | 16 +- .../generic_duplicate_param_use3.rs | 2 +- .../generic_duplicate_param_use3.stderr | 16 +- .../generic_underconstrained.rs | 3 +- .../generic_underconstrained.stderr | 8 +- .../generic_underconstrained2.rs | 8 +- .../generic_underconstrained2.stderr | 30 +- .../impl-with-unconstrained-param.rs | 3 +- .../impl-with-unconstrained-param.stderr | 18 +- .../incoherent-assoc-imp-trait.stderr | 4 +- .../issue-52843-closure-constrain.stderr | 2 +- .../ui/type-alias-impl-trait/issue-53096.rs | 2 +- .../issue-57611-trait-alias.rs | 2 +- .../issue-57611-trait-alias.stderr | 4 +- .../type-alias-impl-trait/issue-63279.stderr | 4 +- .../ui/type-alias-impl-trait/issue-74761.rs | 16 + .../type-alias-impl-trait/issue-74761.stderr | 15 + .../issue-76202-trait-impl-for-tait.rs | 23 + .../issue-76202-trait-impl-for-tait.stderr | 14 + .../never_reveal_concrete_type.stderr | 4 +- ...o_revealing_outside_defining_module.stderr | 6 +- .../not_a_defining_use.rs | 5 +- .../not_a_defining_use.stderr | 16 +- .../structural-match-no-leak.rs | 4 +- .../structural-match-no-leak.stderr | 2 +- .../type-alias-impl-trait/structural-match.rs | 4 +- .../structural-match.stderr | 2 +- .../type-alias-impl-trait-const.rs | 2 +- ...alias-impl-trait-unconstrained-lifetime.rs | 18 + ...s-impl-trait-unconstrained-lifetime.stderr | 9 + .../ui/type-alias/issue-62263-self-in-atb.rs | 2 +- .../type-alias/issue-62263-self-in-atb.stderr | 4 +- .../type-alias/issue-62305-self-assoc-ty.rs | 2 +- .../issue-62305-self-assoc-ty.stderr | 4 +- .../ui/type/type-annotation-needed.stderr | 2 +- src/test/ui/type/type-check-defaults.rs | 8 +- src/test/ui/type/type-check-defaults.stderr | 26 +- .../assignment-expected-bool.stderr | 114 +- .../type/type-check/assignment-in-if.stderr | 64 +- .../cannot_infer_local_or_vec.stderr | 4 +- ...cannot_infer_local_or_vec_in_tuples.stderr | 4 +- .../ui/type/type-mismatch-same-crate-name.rs | 4 +- .../type/type-mismatch-same-crate-name.stderr | 4 +- src/test/ui/type/type-path-err-node-types.rs | 2 +- .../ui/type/type-path-err-node-types.stderr | 4 +- src/test/ui/type_length_limit.rs | 1 + src/test/ui/type_length_limit.stderr | 7 +- ...e-57673-ice-on-deref-of-boxed-trait.stderr | 4 +- src/test/ui/typeck/issue-67971.stderr | 2 +- ...typeck-default-trait-impl-assoc-type.fixed | 2 +- ...ypeck-default-trait-impl-assoc-type.stderr | 6 +- ...lt-trait-impl-cross-crate-coherence.stderr | 4 +- ...ck-default-trait-impl-negation-send.stderr | 2 +- ...typeck-default-trait-impl-negation-sync.rs | 2 +- ...ck-default-trait-impl-negation-sync.stderr | 10 +- ...ypeck-default-trait-impl-send-param.stderr | 4 +- .../ui/typeck/typeck-unsafe-always-share.rs | 6 +- .../typeck/typeck-unsafe-always-share.stderr | 20 +- .../typeck_type_placeholder_item.stderr | 96 +- .../typeck_type_placeholder_item_help.stderr | 4 +- .../ui/ufcs/ufcs-qpath-self-mismatch.stderr | 2 +- .../ui/unboxed-closures/issue-30906.stderr | 4 +- .../unboxed-closure-illegal-move.stderr | 8 +- ...oxed-closures-failed-recursive-fn-1.stderr | 2 +- ...oxed-closures-failed-recursive-fn-2.stderr | 4 +- .../unboxed-closures-fnmut-as-fn.stderr | 4 +- ...ument-types-two-region-pointers.nll.stderr | 2 +- .../unboxed-closures-unsafe-extern-fn.stderr | 12 +- .../unboxed-closures-wrong-abi.stderr | 12 +- ...d-closures-wrong-arg-type-extern-fn.stderr | 12 +- src/test/ui/union/union-const-pat.rs | 1 - src/test/ui/union/union-const-pat.stderr | 8 +- src/test/ui/union/union-deref.rs | 28 + src/test/ui/union/union-deref.stderr | 56 + src/test/ui/union/union-derive-clone.rs | 2 +- src/test/ui/union/union-derive-clone.stderr | 18 +- src/test/ui/union/union-derive-eq.rs | 2 +- src/test/ui/union/union-derive-eq.stderr | 6 +- src/test/ui/union/union-drop.rs | 7 +- src/test/ui/union/union-generic.rs | 4 +- src/test/ui/union/union-generic.stderr | 8 +- src/test/ui/union/union-move.rs | 53 + src/test/ui/union/union-move.stderr | 35 + src/test/ui/union/union-sized-field.stderr | 6 +- src/test/ui/union/union-unsized.stderr | 4 +- src/test/ui/unique-object-noncopyable.stderr | 22 +- src/test/ui/unique-pinned-nocopy.stderr | 18 +- src/test/ui/unknown-tool-name.rs | 2 +- src/test/ui/unknown-tool-name.stderr | 4 +- src/test/ui/unsafe/ranged_ints2_const.rs | 4 +- src/test/ui/unsafe/ranged_ints2_const.stderr | 22 +- src/test/ui/unsafe/unsafe-subtyping.stderr | 6 +- .../unsized-locals/borrow-after-move.stderr | 6 +- src/test/ui/unsized-locals/double-move.stderr | 8 +- .../issue-30276-feature-flagged.stderr | 2 +- src/test/ui/unsized-locals/issue-30276.stderr | 2 +- .../issue-50940-with-feature.stderr | 4 +- src/test/ui/unsized-locals/issue-50940.stderr | 2 +- .../ui/unsized-locals/unsized-exprs.stderr | 6 +- .../ui/unsized-locals/unsized-exprs3.stderr | 2 +- .../ui/unsized/unsized-bare-typaram.stderr | 2 +- src/test/ui/unsized/unsized-enum.stderr | 2 +- src/test/ui/unsized/unsized-enum2.stderr | 40 +- src/test/ui/unsized/unsized-fn-param.stderr | 16 +- .../unsized-inherent-impl-self-type.stderr | 2 +- src/test/ui/unsized/unsized-struct.stderr | 4 +- .../unsized-trait-impl-self-type.stderr | 2 +- .../unsized-trait-impl-trait-arg.stderr | 2 +- src/test/ui/unsized3.stderr | 12 +- src/test/ui/unsized5.stderr | 12 +- src/test/ui/unsized6.stderr | 26 +- src/test/ui/unsized7.stderr | 2 +- src/test/ui/unused/unused-closure.rs | 2 +- src/test/ui/unused/unused-closure.stderr | 2 +- .../use/use-after-move-based-on-type.stderr | 2 +- ...after-move-implicity-coerced-object.stderr | 2 +- src/test/ui/use/use-self-type.rs | 2 +- src/test/ui/use/use-self-type.stderr | 6 +- .../variance-regions-unused-direct.stderr | 4 +- .../variance-regions-unused-indirect.stderr | 4 +- .../variance-unused-region-param.stderr | 4 +- .../variance-unused-type-param.stderr | 6 +- src/test/ui/vec/vec-res-add.rs | 2 +- src/test/ui/vec/vec-res-add.stderr | 6 +- src/test/ui/vector-no-ann.stderr | 4 +- src/test/ui/wf/wf-array-elem-sized.stderr | 2 +- src/test/ui/wf/wf-const-type.stderr | 6 +- .../wf/wf-convert-unsafe-trait-obj-box.stderr | 12 +- .../ui/wf/wf-convert-unsafe-trait-obj.stderr | 6 +- src/test/ui/wf/wf-enum-bound.stderr | 8 +- .../wf/wf-enum-fields-struct-variant.stderr | 8 +- src/test/ui/wf/wf-enum-fields.stderr | 8 +- src/test/ui/wf/wf-fn-where-clause.stderr | 16 +- src/test/ui/wf/wf-impl-self-type.stderr | 4 +- src/test/ui/wf/wf-in-fn-arg.stderr | 8 +- src/test/ui/wf/wf-in-fn-ret.stderr | 8 +- src/test/ui/wf/wf-in-fn-type-arg.stderr | 8 +- src/test/ui/wf/wf-in-fn-type-ret.stderr | 8 +- src/test/ui/wf/wf-in-fn-where-clause.stderr | 8 +- src/test/ui/wf/wf-in-obj-type-trait.stderr | 8 +- ...f-inherent-impl-method-where-clause.stderr | 8 +- .../wf/wf-inherent-impl-where-clause.stderr | 8 +- src/test/ui/wf/wf-static-type.stderr | 6 +- src/test/ui/wf/wf-struct-bound.stderr | 8 +- src/test/ui/wf/wf-struct-field.stderr | 8 +- .../wf/wf-trait-associated-type-bound.stderr | 8 +- .../wf/wf-trait-associated-type-trait.stderr | 8 +- src/test/ui/wf/wf-trait-bound.stderr | 8 +- src/test/ui/wf/wf-trait-default-fn-arg.stderr | 8 +- src/test/ui/wf/wf-trait-default-fn-ret.stderr | 8 +- .../wf-trait-default-fn-where-clause.stderr | 8 +- src/test/ui/wf/wf-trait-fn-arg.stderr | 8 +- src/test/ui/wf/wf-trait-fn-ret.stderr | 8 +- .../ui/wf/wf-trait-fn-where-clause.stderr | 8 +- src/test/ui/wf/wf-trait-superbound.stderr | 8 +- .../ui/wf/wf-unsafe-trait-obj-match.stderr | 4 +- ...constraints-are-local-for-inherent-impl.rs | 2 +- ...traints-are-local-for-inherent-impl.stderr | 8 +- ...se-constraints-are-local-for-trait-impl.rs | 2 +- ...onstraints-are-local-for-trait-impl.stderr | 8 +- .../where-clauses-method-unsatisfied.rs | 2 +- .../where-clauses-method-unsatisfied.stderr | 4 +- .../where-clauses-unsatisfied.rs | 2 +- .../where-clauses-unsatisfied.stderr | 4 +- src/test/ui/wrapping-int-combinations.rs | 77 - .../ui/write-to-static-mut-in-static.stderr | 12 +- src/tools/build-manifest/Cargo.toml | 7 + src/tools/build-manifest/README.md | 10 +- src/tools/build-manifest/src/main.rs | 471 +- src/tools/build-manifest/src/manifest.rs | 114 + src/tools/build-manifest/src/versions.rs | 191 + src/tools/cargotest/main.rs | 11 +- src/tools/compiletest/src/common.rs | 3 + src/tools/compiletest/src/header.rs | 32 +- src/tools/compiletest/src/main.rs | 29 +- src/tools/compiletest/src/runtest.rs | 21 +- src/tools/error_index_generator/build.rs | 4 +- src/tools/linkchecker/main.rs | 1 + src/tools/lint-docs/Cargo.toml | 13 + src/tools/lint-docs/src/groups.rs | 114 + src/tools/lint-docs/src/lib.rs | 482 + src/tools/lint-docs/src/main.rs | 69 + src/tools/publish_toolstate.py | 23 +- src/tools/rustbook/Cargo.toml | 2 +- src/tools/rustc-workspace-hack/Cargo.toml | 2 +- src/tools/tidy/src/debug_artifacts.rs | 2 +- src/tools/tidy/src/deps.rs | 2 + src/tools/tidy/src/edition.rs | 1 - src/tools/tidy/src/features.rs | 20 +- src/tools/tidy/src/main.rs | 47 +- src/tools/tidy/src/pal.rs | 5 + src/tools/tidy/src/unit_tests.rs | 14 +- src/tools/tier-check/src/main.rs | 2 - src/tools/unstable-book-gen/src/main.rs | 14 +- src/version | 1 + .../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-buffer/.cargo-checksum.json | 2 +- vendor/block-buffer/Cargo.toml | 17 +- vendor/block-buffer/src/lib.rs | 177 +- vendor/cargo_metadata/.cargo-checksum.json | 2 +- vendor/cargo_metadata/Cargo.toml | 4 +- vendor/cargo_metadata/src/lib.rs | 5 + vendor/cargo_metadata/tests/test_samples.rs | 9 +- vendor/cc-1.0.59/.cargo-checksum.json | 1 + vendor/cc-1.0.59/Cargo.lock | 145 + vendor/cc-1.0.59/Cargo.toml | 34 + .../LICENSE-APACHE | 0 .../LICENSE-MIT | 2 +- vendor/cc-1.0.59/README.md | 195 + vendor/cc-1.0.59/src/bin/gcc-shim.rs | 48 + vendor/cc-1.0.59/src/com.rs | 155 + vendor/cc-1.0.59/src/lib.rs | 2960 +++ vendor/cc-1.0.59/src/registry.rs | 204 + vendor/cc-1.0.59/src/setup_config.rs | 283 + vendor/cc-1.0.59/src/winapi.rs | 218 + vendor/cc-1.0.59/src/windows_registry.rs | 794 + vendor/cc-1.0.59/tests/cc_env.rs | 118 + vendor/cc-1.0.59/tests/cflags.rs | 15 + vendor/cc-1.0.59/tests/cxxflags.rs | 15 + vendor/cc-1.0.59/tests/support/mod.rs | 173 + vendor/cc-1.0.59/tests/test.rs | 413 + vendor/cc/.cargo-checksum.json | 2 +- vendor/cc/Cargo.lock | 14 +- vendor/cc/Cargo.toml | 2 +- vendor/cc/README.md | 3 - vendor/cc/src/lib.rs | 41 +- .../chalk-derive-0.14.0/.cargo-checksum.json | 1 - .../chalk-derive-0.25.0/.cargo-checksum.json | 1 + .../Cargo.toml | 2 +- .../README.md | 0 .../src/lib.rs | 0 vendor/chalk-derive/.cargo-checksum.json | 2 +- vendor/chalk-derive/Cargo.toml | 2 +- vendor/chalk-engine/.cargo-checksum.json | 2 +- vendor/chalk-engine/Cargo.toml | 11 +- vendor/chalk-engine/src/forest.rs | 4 +- vendor/chalk-engine/src/lib.rs | 3 + vendor/chalk-engine/src/logic.rs | 128 +- .../src}/normalize_deep.rs | 56 +- vendor/chalk-engine/src/simplify.rs | 27 +- .../src/solve => chalk-engine/src}/slg.rs | 101 +- .../src}/slg/aggregate.rs | 144 +- .../src}/slg/resolvent.rs | 27 +- vendor/chalk-engine/src/solve.rs | 84 + vendor/chalk-engine/src/stack.rs | 40 + vendor/chalk-engine/src/table.rs | 16 +- vendor/chalk-engine/src/tables.rs | 1 + vendor/chalk-ir-0.14.0/.cargo-checksum.json | 1 - vendor/chalk-ir-0.25.0/.cargo-checksum.json | 1 + .../Cargo.toml | 4 +- .../README.md | 0 .../src/cast.rs | 15 +- .../src/could_match.rs | 3 + .../src/debug.rs | 72 +- .../src/fold.rs | 8 +- .../src/fold/binder_impls.rs | 19 +- .../src/fold/boring_impls.rs | 23 + .../src/fold/shift.rs | 2 + .../src/fold/subst.rs | 2 + .../src/interner.rs | 270 +- .../src/lib.rs | 997 +- .../src/visit.rs | 10 +- .../src/visit/binder_impls.rs | 6 +- .../src/visit/boring_impls.rs | 26 +- .../src/visit/visitors.rs | 8 + .../src/zip.rs | 16 +- vendor/chalk-ir/.cargo-checksum.json | 2 +- vendor/chalk-ir/Cargo.toml | 4 +- vendor/chalk-ir/src/debug.rs | 32 +- vendor/chalk-ir/src/fold/binder_impls.rs | 12 +- vendor/chalk-ir/src/fold/boring_impls.rs | 1 + vendor/chalk-ir/src/interner.rs | 21 + vendor/chalk-ir/src/lib.rs | 31 +- vendor/chalk-ir/src/visit/boring_impls.rs | 8 +- vendor/chalk-recursive/.cargo-checksum.json | 2 +- vendor/chalk-recursive/Cargo.toml | 8 +- vendor/chalk-recursive/src/fulfill.rs | 14 +- vendor/chalk-recursive/src/lib.rs | 21 +- .../chalk-solve-0.14.0/.cargo-checksum.json | 1 - vendor/chalk-solve-0.14.0/src/recursive.rs | 279 - .../src/recursive/combine.rs | 77 - .../src/recursive/fulfill.rs | 577 - .../src/recursive/search_graph.rs | 131 - .../chalk-solve-0.14.0/src/recursive/solve.rs | 314 - .../chalk-solve-0.14.0/src/recursive/stack.rs | 101 - vendor/chalk-solve-0.14.0/src/solve.rs | 395 - vendor/chalk-solve-0.14.0/src/test_macros.rs | 115 - .../chalk-solve-0.25.0/.cargo-checksum.json | 1 + .../Cargo.toml | 27 +- .../README.md | 0 .../src/clauses.rs | 244 +- .../src/clauses/builder.rs | 58 +- .../src/clauses/builtin_traits.rs | 33 +- .../src/clauses/builtin_traits/clone.rs | 7 +- .../src/clauses/builtin_traits/copy.rs | 42 +- .../src/clauses/builtin_traits/fn_family.rs | 43 +- .../src/clauses/builtin_traits/sized.rs | 51 +- .../src/clauses/builtin_traits/unsize.rs | 95 +- .../src/clauses/dyn_ty.rs | 2 + .../src/clauses/env_elaborator.rs | 35 +- .../src/clauses/generalize.rs | 5 +- .../src/clauses/program_clauses.rs | 164 +- .../src/coherence.rs | 16 +- .../src/coherence/orphan.rs | 15 +- .../src/coherence/solve.rs | 23 +- .../src/coinductive_goal.rs | 1 + vendor/chalk-solve-0.25.0/src/display.rs | 219 + .../chalk-solve-0.25.0/src/display/bounds.rs | 168 + .../src/display/identifiers.rs | 54 + .../chalk-solve-0.25.0/src/display/items.rs | 490 + .../src/display/render_trait.rs | 30 + .../chalk-solve-0.25.0/src/display/state.rs | 350 + vendor/chalk-solve-0.25.0/src/display/stub.rs | 239 + vendor/chalk-solve-0.25.0/src/display/ty.rs | 333 + .../chalk-solve-0.25.0/src/display/utils.rs | 51 + .../src/ext.rs | 0 .../src/goal_builder.rs | 6 +- .../src/infer.rs | 35 +- .../src/infer/canonicalize.rs | 19 +- .../src/infer/instantiate.rs | 16 +- .../src/infer/invert.rs | 4 +- .../src/infer/test.rs | 44 +- .../src/infer/ucanonicalize.rs | 21 +- .../src/infer/unify.rs | 87 +- .../src/infer/var.rs | 12 +- .../src/lib.rs | 94 +- vendor/chalk-solve-0.25.0/src/logging.rs | 19 + vendor/chalk-solve-0.25.0/src/logging_db.rs | 529 + .../src/logging_db/id_collector.rs | 170 + .../src/recursive/lib.rs | 8 +- .../src/rust_ir.rs | 116 +- vendor/chalk-solve-0.25.0/src/solve.rs | 206 + .../src/solve/test/bench.rs | 0 .../src/solve/truncate.rs | 4 +- .../src/split.rs | 53 +- .../src/wf.rs | 146 +- vendor/chalk-solve/.cargo-checksum.json | 2 +- vendor/chalk-solve/Cargo.toml | 6 +- vendor/chalk-solve/src/clauses.rs | 130 +- .../chalk-solve/src/clauses/builtin_traits.rs | 4 +- .../src/clauses/builtin_traits/copy.rs | 1 + .../src/clauses/builtin_traits/fn_family.rs | 4 +- .../src/clauses/builtin_traits/sized.rs | 1 + vendor/chalk-solve/src/coherence/solve.rs | 5 +- vendor/chalk-solve/src/display/items.rs | 2 + vendor/chalk-solve/src/display/stub.rs | 2 +- vendor/chalk-solve/src/display/ty.rs | 1 + vendor/chalk-solve/src/infer/unify.rs | 77 +- vendor/chalk-solve/src/lib.rs | 9 +- vendor/chalk-solve/src/logging_db.rs | 12 +- vendor/chalk-solve/src/rust_ir.rs | 10 +- vendor/chalk-solve/src/solve.rs | 13 + vendor/chalk-solve/src/wf.rs | 501 +- vendor/compiler_builtins/.cargo-checksum.json | 2 +- vendor/compiler_builtins/Cargo.lock | 6 +- vendor/compiler_builtins/Cargo.toml | 2 +- vendor/compiler_builtins/build.rs | 31 + .../src/int/leading_zeros.rs | 143 + vendor/compiler_builtins/src/int/mod.rs | 69 +- vendor/compiler_builtins/src/lib.rs | 2 +- vendor/cpuid-bool/.cargo-checksum.json | 1 + vendor/cpuid-bool/CHANGELOG.md | 21 + vendor/cpuid-bool/Cargo.toml | 23 + vendor/cpuid-bool/LICENSE-APACHE | 201 + vendor/cpuid-bool/LICENSE-MIT | 25 + vendor/cpuid-bool/src/lib.rs | 121 + vendor/crossbeam-channel/.cargo-checksum.json | 1 + vendor/crossbeam-channel/CHANGELOG.md | 167 + vendor/crossbeam-channel/Cargo.lock | 262 + .../Cargo.toml | 29 +- .../LICENSE-APACHE | 0 .../LICENSE-MIT | 0 vendor/crossbeam-channel/LICENSE-THIRD-PARTY | 625 + vendor/crossbeam-channel/README.md | 93 + vendor/crossbeam-channel/benches/crossbeam.rs | 715 + .../crossbeam-channel/examples/fibonacci.rs | 27 + vendor/crossbeam-channel/examples/matching.rs | 76 + .../crossbeam-channel/examples/stopwatch.rs | 58 + vendor/crossbeam-channel/src/channel.rs | 1389 ++ vendor/crossbeam-channel/src/context.rs | 191 + vendor/crossbeam-channel/src/counter.rs | 144 + vendor/crossbeam-channel/src/err.rs | 451 + vendor/crossbeam-channel/src/flavors/after.rs | 200 + vendor/crossbeam-channel/src/flavors/array.rs | 639 + vendor/crossbeam-channel/src/flavors/list.rs | 671 + vendor/crossbeam-channel/src/flavors/mod.rs | 17 + vendor/crossbeam-channel/src/flavors/never.rs | 110 + vendor/crossbeam-channel/src/flavors/tick.rs | 167 + vendor/crossbeam-channel/src/flavors/zero.rs | 466 + vendor/crossbeam-channel/src/lib.rs | 379 + vendor/crossbeam-channel/src/select.rs | 1166 + vendor/crossbeam-channel/src/select_macro.rs | 1214 + vendor/crossbeam-channel/src/utils.rs | 112 + vendor/crossbeam-channel/src/waker.rs | 285 + vendor/crossbeam-channel/tests/after.rs | 339 + vendor/crossbeam-channel/tests/array.rs | 659 + vendor/crossbeam-channel/tests/golang.rs | 1448 ++ vendor/crossbeam-channel/tests/iter.rs | 113 + vendor/crossbeam-channel/tests/list.rs | 538 + vendor/crossbeam-channel/tests/mpsc.rs | 2095 ++ vendor/crossbeam-channel/tests/never.rs | 99 + vendor/crossbeam-channel/tests/ready.rs | 837 + .../crossbeam-channel/tests/same_channel.rs | 114 + vendor/crossbeam-channel/tests/select.rs | 1304 + .../crossbeam-channel/tests/select_macro.rs | 1440 ++ .../crossbeam-channel/tests/thread_locals.rs | 55 + vendor/crossbeam-channel/tests/tick.rs | 353 + vendor/crossbeam-channel/tests/zero.rs | 559 + vendor/crossbeam-queue/.cargo-checksum.json | 1 - vendor/crossbeam-queue/CHANGELOG.md | 28 - vendor/crossbeam-queue/LICENSE-THIRD-PARTY | 31 - vendor/crossbeam-queue/README.md | 67 - vendor/crossbeam-queue/src/array_queue.rs | 440 - vendor/crossbeam-queue/src/err.rs | 47 - vendor/crossbeam-queue/src/lib.rs | 42 - vendor/crossbeam-queue/src/seg_queue.rs | 490 - vendor/crossbeam-queue/tests/array_queue.rs | 254 - vendor/crossbeam-queue/tests/seg_queue.rs | 167 - 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 + .../LICENSE-MIT | 2 +- 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/digest/.cargo-checksum.json | 2 +- vendor/digest/CHANGELOG.md | 78 + vendor/digest/Cargo.toml | 14 +- vendor/digest/README.md | 161 + vendor/digest/src/dev.rs | 155 +- vendor/digest/src/digest.rs | 54 +- vendor/digest/src/dyn_digest.rs | 33 +- vendor/digest/src/errors.rs | 10 +- vendor/digest/src/fixed.rs | 71 + vendor/digest/src/lib.rs | 153 +- vendor/digest/src/variable.rs | 106 + vendor/digest/src/xof.rs | 102 + vendor/expect-test/.cargo-checksum.json | 2 +- vendor/expect-test/Cargo.toml | 10 +- vendor/expect-test/README.md | 2 +- vendor/expect-test/src/lib.rs | 42 +- vendor/fs-err/.cargo-checksum.json | 1 + vendor/fs-err/CHANGELOG.md | 33 + vendor/fs-err/Cargo.toml | 30 + vendor/fs-err/LICENSE-APACHE | 201 + vendor/fs-err/LICENSE-MIT | 23 + vendor/fs-err/README.md | 88 + vendor/fs-err/README.tpl | 28 + vendor/fs-err/src/dir.rs | 85 + vendor/fs-err/src/errors.rs | 125 + vendor/fs-err/src/file.rs | 217 + vendor/fs-err/src/lib.rs | 170 + vendor/fs-err/tests/version-numbers.rs | 9 + .../generic-array-0.12.3/.cargo-checksum.json | 1 + vendor/generic-array-0.12.3/CHANGELOG.md | 48 + vendor/generic-array-0.12.3/Cargo.toml | 40 + vendor/generic-array-0.12.3/LICENSE | 21 + vendor/generic-array-0.12.3/README.md | 34 + vendor/generic-array-0.12.3/rustfmt.toml | 3 + vendor/generic-array-0.12.3/src/arr.rs | 57 + vendor/generic-array-0.12.3/src/functional.rs | 94 + vendor/generic-array-0.12.3/src/hex.rs | 102 + vendor/generic-array-0.12.3/src/impl_serde.rs | 108 + vendor/generic-array-0.12.3/src/impls.rs | 182 + vendor/generic-array-0.12.3/src/iter.rs | 190 + vendor/generic-array-0.12.3/src/lib.rs | 632 + vendor/generic-array-0.12.3/src/sequence.rs | 320 + vendor/generic-array-0.12.3/tests/arr.rs | 27 + vendor/generic-array-0.12.3/tests/generics.rs | 98 + vendor/generic-array-0.12.3/tests/hex.rs | 61 + .../generic-array-0.12.3/tests/import_name.rs | 10 + vendor/generic-array-0.12.3/tests/iter.rs | 164 + vendor/generic-array-0.12.3/tests/mod.rs | 287 + vendor/generic-array/.cargo-checksum.json | 2 +- vendor/generic-array/CHANGELOG.md | 42 + vendor/generic-array/Cargo.toml | 9 +- vendor/generic-array/DESIGN.md | 585 + vendor/generic-array/README.md | 30 +- vendor/generic-array/build.rs | 5 + vendor/generic-array/src/arr.rs | 182 +- vendor/generic-array/src/functional.rs | 3 +- vendor/generic-array/src/hex.rs | 37 +- vendor/generic-array/src/impl_serde.rs | 8 +- vendor/generic-array/src/impls.rs | 107 +- vendor/generic-array/src/iter.rs | 99 +- vendor/generic-array/src/lib.rs | 143 +- vendor/generic-array/src/sequence.rs | 156 +- vendor/generic-array/tests/iter.rs | 49 +- vendor/generic-array/tests/mod.rs | 136 +- .../.cargo-checksum.json | 0 .../CHANGELOG.md | 0 .../Cargo.toml | 0 .../LICENSE-APACHE | 0 .../LICENSE-MIT | 0 .../{getrandom => getrandom-0.1.14}/README.md | 0 .../benches/mod.rs | 0 .../{getrandom => getrandom-0.1.14}/build.rs | 0 .../src/bsd_arandom.rs | 0 .../src/cloudabi.rs | 0 .../src/dummy.rs | 0 .../src/error.rs | 0 .../src/error_impls.rs | 0 .../src/fuchsia.rs | 0 .../src/ios.rs | 0 .../src/lib.rs | 0 .../src/linux_android.rs | 0 .../src/macos.rs | 0 .../src/openbsd.rs | 0 .../src/rdrand.rs | 0 .../src/solaris_illumos.rs | 0 .../src/use_file.rs | 0 .../src/util.rs | 0 .../src/util_libc.rs | 0 .../src/vxworks.rs | 0 .../src/wasi.rs | 0 .../src/wasm32_bindgen.rs | 0 .../src/wasm32_stdweb.rs | 0 .../src/windows.rs | 0 .../src/windows_uwp.rs | 0 .../tests/common.rs | 0 vendor/hashbrown/.cargo-checksum.json | 2 +- vendor/hashbrown/CHANGELOG.md | 21 +- vendor/hashbrown/Cargo.toml | 7 +- vendor/hashbrown/build.rs | 9 - vendor/hashbrown/src/lib.rs | 14 +- vendor/hashbrown/src/map.rs | 554 +- vendor/hashbrown/src/raw/generic.rs | 16 +- vendor/hashbrown/src/raw/mod.rs | 47 +- vendor/hashbrown/src/raw/sse2.rs | 15 +- vendor/hashbrown/src/set.rs | 197 +- vendor/hex/.cargo-checksum.json | 1 + vendor/hex/Cargo.toml | 62 + vendor/hex/LICENSE-APACHE | 202 + vendor/hex/LICENSE-MIT | 20 + vendor/hex/README.md | 67 + vendor/hex/benches/hex.rs | 70 + vendor/hex/src/error.rs | 55 + vendor/hex/src/lib.rs | 485 + vendor/hex/src/serde.rs | 88 + vendor/hex/tests/serde.rs | 58 + vendor/hex/tests/version-number.rs | 9 + vendor/indexmap/.cargo-checksum.json | 2 +- vendor/indexmap/Cargo.toml | 5 +- vendor/indexmap/README.rst | 14 + vendor/indexmap/build.rs | 7 +- vendor/itertools-0.8.2/.cargo-checksum.json | 1 - vendor/itertools-0.8.2/Cargo.lock | 227 - vendor/itertools-0.8.2/Cargo.toml | 47 - vendor/itertools-0.8.2/README.rst | 620 - vendor/itertools-0.8.2/benches/bench1.rs | 806 - .../benches/combinations_with_replacement.rs | 34 - vendor/itertools-0.8.2/benches/extra/mod.rs | 4 - .../benches/extra/zipslices.rs | 189 - .../benches/fold_specialization.rs | 66 - vendor/itertools-0.8.2/benches/tree_fold1.rs | 126 - .../benches/tuple_combinations.rs | 97 - vendor/itertools-0.8.2/benches/tuples.rs | 190 - vendor/itertools-0.8.2/examples/iris.data | 150 - vendor/itertools-0.8.2/examples/iris.rs | 141 - vendor/itertools-0.8.2/src/adaptors/mod.rs | 1251 - .../src/adaptors/multi_product.rs | 220 - vendor/itertools-0.8.2/src/combinations.rs | 100 - .../src/combinations_with_replacement.rs | 108 - vendor/itertools-0.8.2/src/concat_impl.rs | 22 - .../itertools-0.8.2/src/cons_tuples_impl.rs | 68 - vendor/itertools-0.8.2/src/diff.rs | 61 - vendor/itertools-0.8.2/src/either_or_both.rs | 190 - vendor/itertools-0.8.2/src/exactly_one_err.rs | 58 - vendor/itertools-0.8.2/src/format.rs | 113 - vendor/itertools-0.8.2/src/free.rs | 236 - vendor/itertools-0.8.2/src/group_map.rs | 22 - vendor/itertools-0.8.2/src/groupbylazy.rs | 571 - vendor/itertools-0.8.2/src/impl_macros.rs | 14 - vendor/itertools-0.8.2/src/intersperse.rs | 79 - vendor/itertools-0.8.2/src/kmerge_impl.rs | 231 - vendor/itertools-0.8.2/src/lazy_buffer.rs | 68 - vendor/itertools-0.8.2/src/lib.rs | 2391 -- vendor/itertools-0.8.2/src/merge_join.rs | 87 - vendor/itertools-0.8.2/src/minmax.rs | 114 - vendor/itertools-0.8.2/src/multipeek_impl.rs | 104 - vendor/itertools-0.8.2/src/pad_tail.rs | 83 - .../itertools-0.8.2/src/peeking_take_while.rs | 149 - vendor/itertools-0.8.2/src/permutations.rs | 272 - .../src/process_results_impl.rs | 81 - vendor/itertools-0.8.2/src/put_back_n_impl.rs | 63 - vendor/itertools-0.8.2/src/rciter_impl.rs | 98 - vendor/itertools-0.8.2/src/repeatn.rs | 54 - vendor/itertools-0.8.2/src/size_hint.rs | 104 - vendor/itertools-0.8.2/src/sources.rs | 190 - vendor/itertools-0.8.2/src/tee.rs | 78 - vendor/itertools-0.8.2/src/tuple_impl.rs | 266 - vendor/itertools-0.8.2/src/unique_impl.rs | 134 - vendor/itertools-0.8.2/src/with_position.rs | 90 - vendor/itertools-0.8.2/src/zip_eq_impl.rs | 60 - vendor/itertools-0.8.2/src/zip_longest.rs | 78 - vendor/itertools-0.8.2/src/ziptuple.rs | 111 - .../tests/adaptors_no_collect.rs | 49 - .../tests/fold_specialization.rs | 15 - vendor/itertools-0.8.2/tests/merge_join.rs | 110 - .../tests/peeking_take_while.rs | 53 - vendor/itertools-0.8.2/tests/quick.rs | 1161 - vendor/itertools-0.8.2/tests/test_core.rs | 272 - vendor/itertools-0.8.2/tests/test_std.rs | 781 - vendor/itertools-0.8.2/tests/tuples.rs | 88 - vendor/itertools-0.8.2/tests/zip.rs | 65 - vendor/libc/.cargo-checksum.json | 2 +- vendor/libc/Cargo.toml | 2 +- vendor/libc/src/macros.rs | 30 + vendor/libc/src/unix/bsd/apple/mod.rs | 1 + .../unix/bsd/freebsdlike/dragonfly/errno.rs | 1 + .../src/unix/bsd/freebsdlike/dragonfly/mod.rs | 22 +- .../src/unix/bsd/freebsdlike/freebsd/mod.rs | 22 - vendor/libc/src/unix/bsd/freebsdlike/mod.rs | 27 + vendor/libc/src/unix/bsd/mod.rs | 23 + vendor/libc/src/unix/haiku/mod.rs | 3 + vendor/libc/src/unix/linux_like/linux/mod.rs | 5 - .../linux_like/linux/musl/b64/aarch64/mod.rs | 6 +- vendor/libc/src/unix/linux_like/mod.rs | 40 +- vendor/libc/src/unix/solarish/mod.rs | 9 + vendor/libc/src/wasi.rs | 12 + vendor/libloading/.cargo-checksum.json | 2 +- vendor/libloading/Cargo.toml | 14 +- vendor/libloading/README.mkd | 4 +- vendor/libloading/build.rs | 6 + vendor/libloading/src/changelog.rs | 20 +- vendor/libloading/src/error.rs | 78 +- vendor/libloading/src/lib.rs | 84 +- vendor/libloading/src/os/mod.rs | 34 +- vendor/libloading/src/os/unix/consts.rs | 230 + vendor/libloading/src/os/unix/mod.rs | 120 +- vendor/libloading/src/os/windows/mod.rs | 260 +- vendor/libloading/src/test_helpers.rs | 14 +- vendor/libloading/src/util.rs | 2 +- vendor/libloading/tests/constants.rs | 13 + vendor/libloading/tests/functions.rs | 91 +- vendor/libloading/tests/library_filename.rs | 17 + vendor/libloading/tests/markers.rs | 17 + vendor/lsp-types/.cargo-checksum.json | 2 +- vendor/lsp-types/CHANGELOG.md | 190 +- vendor/lsp-types/Cargo.toml | 2 +- vendor/lsp-types/LICENSE | 44 +- vendor/lsp-types/README.md | 18 +- vendor/lsp-types/release.sh | 30 +- vendor/lsp-types/release.toml | 4 +- vendor/lsp-types/src/lib.rs | 9744 ++++---- vendor/lsp-types/src/notification.rs | 608 +- vendor/lsp-types/src/request.rs | 1478 +- vendor/mdbook/.cargo-checksum.json | 2 +- vendor/mdbook/CHANGELOG.md | 22 + vendor/mdbook/Cargo.lock | 2 +- vendor/mdbook/Cargo.toml | 2 +- vendor/mdbook/README.md | 2 +- vendor/mdbook/src/book/mod.rs | 7 +- vendor/mdbook/src/config.rs | 8 + .../renderer/html_handlebars/hbs_renderer.rs | 6 +- .../renderer/html_handlebars/helpers/toc.rs | 50 +- vendor/merge/.cargo-checksum.json | 1 + vendor/merge/CHANGELOG.md | 9 + vendor/merge/Cargo.lock | 372 + vendor/merge/Cargo.toml | 51 + vendor/merge/LICENSES/Apache-2.0.txt | 202 + vendor/merge/LICENSES/CC0-1.0.txt | 119 + vendor/merge/LICENSES/MIT.txt | 21 + vendor/merge/README.md | 98 + vendor/merge/examples/args.rs | 43 + vendor/merge/examples/user.rs | 31 + vendor/merge/src/lib.rs | 223 + vendor/merge/tests/compile.rs | 9 + vendor/merge/tests/compile/derive-enum.rs | 13 + vendor/merge/tests/compile/derive-enum.stderr | 7 + .../tests/compile/derive-invalid-attribute.rs | 12 + .../compile/derive-invalid-attribute.stderr | 5 + .../tests/compile/derive-invalid-skip.rs | 12 + .../tests/compile/derive-invalid-skip.stderr | 5 + .../tests/compile/derive-invalid-strategy.rs | 16 + .../compile/derive-invalid-strategy.stderr | 13 + .../tests/compile/derive-missing-strategy.rs | 12 + .../compile/derive-missing-strategy.stderr | 5 + .../merge/tests/compile/derive-no-strategy.rs | 12 + .../tests/compile/derive-no-strategy.stderr | 5 + vendor/merge/tests/compile/derive-u8.rs | 12 + vendor/merge/tests/compile/derive-u8.stderr | 7 + vendor/merge/tests/derive.rs | 540 + vendor/merge/tests/impls.rs | 16 + vendor/merge/tests/strategies.rs | 122 + vendor/merge_derive/.cargo-checksum.json | 1 + vendor/merge_derive/CHANGELOG.md | 8 + vendor/merge_derive/Cargo.toml | 37 + vendor/merge_derive/README.md | 11 + vendor/merge_derive/src/lib.rs | 150 + vendor/miniz_oxide/.cargo-checksum.json | 2 +- vendor/miniz_oxide/Cargo.toml | 3 +- vendor/miniz_oxide/src/deflate/mod.rs | 4 +- vendor/miniz_oxide/src/inflate/mod.rs | 81 +- vendor/miniz_oxide/src/inflate/stream.rs | 76 +- vendor/miniz_oxide/src/lib.rs | 5 +- vendor/net2/.cargo-checksum.json | 1 + vendor/net2/Cargo.toml | 35 + .../LICENSE-APACHE | 0 vendor/net2/LICENSE-MIT | 25 + vendor/net2/README.md | 31 + vendor/net2/src/ext.rs | 1561 ++ vendor/net2/src/lib.rs | 127 + vendor/net2/src/socket.rs | 142 + vendor/net2/src/sys/redox/impls.rs | 43 + vendor/net2/src/sys/redox/mod.rs | 81 + vendor/net2/src/sys/unix/impls.rs | 44 + vendor/net2/src/sys/unix/mod.rs | 104 + vendor/net2/src/sys/wasi/impls.rs | 33 + vendor/net2/src/sys/wasi/mod.rs | 185 + vendor/net2/src/sys/windows/impls.rs | 44 + vendor/net2/src/sys/windows/mod.rs | 124 + vendor/net2/src/tcp.rs | 161 + vendor/net2/src/udp.rs | 89 + vendor/net2/src/unix.rs | 57 + vendor/net2/src/utils.rs | 51 + .../opaque-debug-0.2.3/.cargo-checksum.json | 1 + vendor/opaque-debug-0.2.3/Cargo.toml | 22 + vendor/opaque-debug-0.2.3/LICENSE-APACHE | 201 + vendor/opaque-debug-0.2.3/LICENSE-MIT | 25 + vendor/opaque-debug-0.2.3/src/lib.rs | 24 + vendor/opaque-debug/.cargo-checksum.json | 2 +- vendor/opaque-debug/Cargo.toml | 5 +- vendor/opaque-debug/src/lib.rs | 4 +- vendor/opaque-debug/tests/mod.rs | 13 + .../parking_lot-0.10.2/.cargo-checksum.json | 1 - vendor/parking_lot-0.10.2/CHANGELOG.md | 120 - vendor/parking_lot-0.10.2/Cargo.toml | 40 - vendor/parking_lot-0.10.2/README.md | 140 - vendor/parking_lot-0.10.2/appveyor.yml | 59 - vendor/parking_lot-0.10.2/bors.toml | 3 - vendor/parking_lot-0.10.2/src/condvar.rs | 1052 - vendor/parking_lot-0.10.2/src/deadlock.rs | 232 - vendor/parking_lot-0.10.2/src/elision.rs | 116 - vendor/parking_lot-0.10.2/src/fair_mutex.rs | 278 - vendor/parking_lot-0.10.2/src/lib.rs | 48 - vendor/parking_lot-0.10.2/src/mutex.rs | 312 - vendor/parking_lot-0.10.2/src/once.rs | 458 - .../parking_lot-0.10.2/src/raw_fair_mutex.rs | 60 - vendor/parking_lot-0.10.2/src/raw_mutex.rs | 325 - vendor/parking_lot-0.10.2/src/raw_rwlock.rs | 1137 - vendor/parking_lot-0.10.2/src/remutex.rs | 149 - vendor/parking_lot-0.10.2/src/rwlock.rs | 613 - vendor/parking_lot-0.10.2/src/util.rs | 38 - vendor/parking_lot-0.10.2/tests/issue_203.rs | 26 - .../.cargo-checksum.json | 1 - vendor/parking_lot_core-0.7.2/Cargo.toml | 52 - vendor/parking_lot_core-0.7.2/src/lib.rs | 71 - .../parking_lot_core-0.7.2/src/parking_lot.rs | 1708 -- vendor/parking_lot_core-0.7.2/src/spinwait.rs | 74 - .../src/thread_parker/cloudabi.rs | 304 - .../src/thread_parker/generic.rs | 77 - .../src/thread_parker/linux.rs | 155 - .../src/thread_parker/mod.rs | 88 - .../src/thread_parker/redox.rs | 138 - .../src/thread_parker/sgx.rs | 94 - .../src/thread_parker/unix.rs | 252 - .../src/thread_parker/wasm.rs | 53 - .../src/thread_parker/wasm_atomic.rs | 96 - .../src/thread_parker/windows/keyed_event.rs | 220 - .../src/thread_parker/windows/mod.rs | 188 - .../src/thread_parker/windows/waitaddress.rs | 149 - vendor/parking_lot_core-0.7.2/src/util.rs | 31 - .../parking_lot_core-0.7.2/src/word_lock.rs | 316 - .../perf-event-open-sys/.cargo-checksum.json | 2 +- vendor/perf-event-open-sys/Cargo.toml | 2 +- vendor/perf-event-open-sys/src/lib.rs | 139 +- .../.cargo-checksum.json | 1 + vendor/proc-macro-error-attr/Cargo.toml | 33 + vendor/proc-macro-error-attr/LICENSE-APACHE | 201 + vendor/proc-macro-error-attr/LICENSE-MIT | 21 + vendor/proc-macro-error-attr/build.rs | 5 + vendor/proc-macro-error-attr/src/lib.rs | 121 + vendor/proc-macro-error-attr/src/parse.rs | 89 + vendor/proc-macro-error-attr/src/settings.rs | 72 + vendor/proc-macro-error/.cargo-checksum.json | 1 + vendor/proc-macro-error/CHANGELOG.md | 162 + vendor/proc-macro-error/Cargo.toml | 56 + vendor/proc-macro-error/LICENSE-APACHE | 201 + vendor/proc-macro-error/LICENSE-MIT | 21 + vendor/proc-macro-error/README.md | 258 + vendor/proc-macro-error/build.rs | 11 + vendor/proc-macro-error/src/diagnostic.rs | 349 + vendor/proc-macro-error/src/dummy.rs | 150 + vendor/proc-macro-error/src/imp/delegate.rs | 69 + vendor/proc-macro-error/src/imp/fallback.rs | 30 + vendor/proc-macro-error/src/lib.rs | 560 + vendor/proc-macro-error/src/macros.rs | 288 + vendor/proc-macro-error/src/sealed.rs | 3 + vendor/proc-macro-error/tests/macro-errors.rs | 8 + vendor/proc-macro-error/tests/ok.rs | 10 + .../proc-macro-error/tests/runtime-errors.rs | 13 + vendor/proc-macro-error/tests/ui/abort.rs | 11 + vendor/proc-macro-error/tests/ui/abort.stderr | 48 + .../proc-macro-error/tests/ui/append_dummy.rs | 13 + .../tests/ui/append_dummy.stderr | 5 + .../tests/ui/children_messages.rs | 6 + .../tests/ui/children_messages.stderr | 23 + vendor/proc-macro-error/tests/ui/dummy.rs | 13 + vendor/proc-macro-error/tests/ui/dummy.stderr | 5 + vendor/proc-macro-error/tests/ui/emit.rs | 7 + vendor/proc-macro-error/tests/ui/emit.stderr | 48 + .../tests/ui/explicit_span_range.rs | 6 + .../tests/ui/explicit_span_range.stderr | 5 + vendor/proc-macro-error/tests/ui/misuse.rs | 11 + .../proc-macro-error/tests/ui/misuse.stderr | 13 + .../tests/ui/multiple_tokens.rs | 6 + .../tests/ui/multiple_tokens.stderr | 5 + .../tests/ui/not_proc_macro.rs | 4 + .../tests/ui/not_proc_macro.stderr | 10 + .../proc-macro-error/tests/ui/option_ext.rs | 6 + .../tests/ui/option_ext.stderr | 7 + .../tests/ui/proc_macro_hack.rs | 10 + .../tests/ui/proc_macro_hack.stderr | 26 + .../proc-macro-error/tests/ui/result_ext.rs | 7 + .../tests/ui/result_ext.stderr | 11 + .../tests/ui/to_tokens_span.rs | 6 + .../tests/ui/to_tokens_span.stderr | 11 + .../tests/ui/unknown_setting.rs | 4 + .../tests/ui/unknown_setting.stderr | 5 + .../tests/ui/unrelated_panic.rs | 6 + .../tests/ui/unrelated_panic.stderr | 7 + vendor/proc-macro2/.cargo-checksum.json | 2 +- vendor/proc-macro2/Cargo.toml | 2 +- vendor/proc-macro2/build.rs | 4 + vendor/proc-macro2/src/fallback.rs | 45 +- vendor/proc-macro2/src/lib.rs | 61 +- vendor/proc-macro2/src/marker.rs | 18 + vendor/proc-macro2/src/strnom.rs | 0 vendor/proc-macro2/tests/marker.rs | 33 + vendor/proc-macro2/tests/test_fmt.rs | 26 + .../pulldown-cmark-0.7.2/.cargo-checksum.json | 1 + vendor/pulldown-cmark-0.7.2/CONTRIBUTING.md | 21 + vendor/pulldown-cmark-0.7.2/Cargo.lock | 918 + vendor/pulldown-cmark-0.7.2/Cargo.toml | 68 + vendor/pulldown-cmark-0.7.2/LICENSE | 21 + vendor/pulldown-cmark-0.7.2/README.md | 152 + .../benches/html_rendering.rs | 77 + vendor/pulldown-cmark-0.7.2/benches/lib.rs | 49 + vendor/pulldown-cmark-0.7.2/build.rs | 187 + .../examples/event-filter.rs | 29 + .../examples/string-to-string.rs | 26 + vendor/pulldown-cmark-0.7.2/src/entities.rs | 2158 ++ vendor/pulldown-cmark-0.7.2/src/escape.rs | 297 + vendor/pulldown-cmark-0.7.2/src/html.rs | 520 + vendor/pulldown-cmark-0.7.2/src/lib.rs | 76 + vendor/pulldown-cmark-0.7.2/src/linklabel.rs | 135 + vendor/pulldown-cmark-0.7.2/src/main.rs | 109 + vendor/pulldown-cmark-0.7.2/src/parse.rs | 3138 +++ vendor/pulldown-cmark-0.7.2/src/puncttable.rs | 351 + vendor/pulldown-cmark-0.7.2/src/scanners.rs | 1247 + vendor/pulldown-cmark-0.7.2/src/simd.rs | 229 + vendor/pulldown-cmark-0.7.2/src/strings.rs | 243 + vendor/pulldown-cmark-0.7.2/src/tree.rs | 216 + vendor/pulldown-cmark-0.7.2/tests/errors.rs | 44 + vendor/pulldown-cmark-0.7.2/tests/html.rs | 245 + vendor/pulldown-cmark-0.7.2/tests/lib.rs | 422 + .../tests/suite/footnotes.rs | 165 + .../tests/suite/gfm_strikethrough.rs | 27 + .../tests/suite/gfm_table.rs | 205 + .../tests/suite/gfm_tasklist.rs | 39 + .../pulldown-cmark-0.7.2/tests/suite/mod.rs | 12 + .../tests/suite/regression.rs | 904 + .../pulldown-cmark-0.7.2/tests/suite/spec.rs | 8447 +++++++ .../pulldown-cmark-0.7.2/tests/suite/table.rs | 205 + .../.cargo-checksum.json | 1 + vendor/pulldown-cmark-to-cmark/CHANGELOG.md | 28 + vendor/pulldown-cmark-to-cmark/Cargo.toml | 33 + vendor/pulldown-cmark-to-cmark/README.md | 41 + vendor/pulldown-cmark-to-cmark/src/lib.rs | 482 + vendor/pulldown-cmark/.cargo-checksum.json | 2 +- vendor/pulldown-cmark/CONTRIBUTING.md | 42 +- vendor/pulldown-cmark/Cargo.lock | 238 +- vendor/pulldown-cmark/Cargo.toml | 2 +- vendor/pulldown-cmark/LICENSE | 42 +- vendor/pulldown-cmark/README.md | 304 +- .../pulldown-cmark/benches/html_rendering.rs | 178 +- vendor/pulldown-cmark/benches/lib.rs | 98 +- vendor/pulldown-cmark/build.rs | 373 +- .../examples/broken-link-callbacks.rs | 37 + .../pulldown-cmark/examples/event-filter.rs | 58 +- .../examples/string-to-string.rs | 52 +- vendor/pulldown-cmark/src/entities.rs | 4316 ++-- vendor/pulldown-cmark/src/escape.rs | 653 +- vendor/pulldown-cmark/src/html.rs | 981 +- vendor/pulldown-cmark/src/lib.rs | 152 +- vendor/pulldown-cmark/src/linklabel.rs | 270 +- vendor/pulldown-cmark/src/main.rs | 218 +- vendor/pulldown-cmark/src/parse.rs | 6512 ++--- vendor/pulldown-cmark/src/puncttable.rs | 702 +- vendor/pulldown-cmark/src/scanners.rs | 2555 +- vendor/pulldown-cmark/src/simd.rs | 477 +- vendor/pulldown-cmark/src/strings.rs | 486 +- vendor/pulldown-cmark/src/tree.rs | 432 +- vendor/pulldown-cmark/tests/errors.rs | 88 +- vendor/pulldown-cmark/tests/html.rs | 497 +- vendor/pulldown-cmark/tests/lib.rs | 847 +- .../pulldown-cmark/tests/suite/footnotes.rs | 330 +- .../tests/suite/gfm_strikethrough.rs | 54 +- .../pulldown-cmark/tests/suite/gfm_table.rs | 410 +- .../tests/suite/gfm_tasklist.rs | 78 +- vendor/pulldown-cmark/tests/suite/mod.rs | 25 +- .../pulldown-cmark/tests/suite/regression.rs | 1857 +- .../pulldown-cmark/tests/suite/smart_punct.rs | 201 + vendor/pulldown-cmark/tests/suite/spec.rs | 16894 ++++++------- vendor/pulldown-cmark/tests/suite/table.rs | 410 +- vendor/rayon-core/.cargo-checksum.json | 2 +- vendor/rayon-core/Cargo.toml | 8 +- vendor/rayon-core/src/job.rs | 14 +- vendor/rayon-core/src/join/mod.rs | 20 +- vendor/rayon-core/src/latch.rs | 276 +- vendor/rayon-core/src/lib.rs | 3 +- vendor/rayon-core/src/log.rs | 499 +- vendor/rayon-core/src/private.rs | 4 +- vendor/rayon-core/src/registry.rs | 194 +- vendor/rayon-core/src/scope/mod.rs | 30 +- vendor/rayon-core/src/scope/test.rs | 82 +- vendor/rayon-core/src/sleep/README.md | 601 +- vendor/rayon-core/src/sleep/counters.rs | 269 + vendor/rayon-core/src/sleep/mod.rs | 569 +- vendor/rayon-core/src/spawn/mod.rs | 3 +- vendor/rayon-core/src/thread_pool/mod.rs | 4 +- vendor/rayon-core/src/thread_pool/test.rs | 77 +- vendor/rayon/.cargo-checksum.json | 2 +- vendor/rayon/Cargo.lock | 123 +- vendor/rayon/Cargo.toml | 4 +- vendor/rayon/RELEASES.md | 22 + vendor/rayon/src/iter/collect/mod.rs | 2 +- vendor/rayon/src/iter/mod.rs | 13 +- vendor/rayon/src/lib.rs | 3 +- vendor/rayon/src/private.rs | 4 +- vendor/rayon/src/range.rs | 70 + vendor/rayon/src/range_inclusive.rs | 89 +- vendor/rayon/src/slice/mod.rs | 4 +- vendor/rayon/tests/chars.rs | 39 + .../.cargo-checksum.json | 0 .../Cargo.toml | 0 .../src/cursor.rs | 0 .../src/lib.rs | 0 .../src/tests.rs | 0 .../src/unescape.rs | 0 .../src/unescape/tests.rs | 0 vendor/serde/.cargo-checksum.json | 2 +- vendor/serde/Cargo.toml | 4 +- vendor/serde/src/de/impls.rs | 12 +- vendor/serde/src/de/mod.rs | 2 +- vendor/serde/src/lib.rs | 8 +- vendor/serde/src/ser/mod.rs | 2 +- vendor/serde_derive/.cargo-checksum.json | 2 +- vendor/serde_derive/Cargo.toml | 2 +- vendor/serde_derive/src/lib.rs | 2 +- vendor/sha2/.cargo-checksum.json | 1 + vendor/sha2/CHANGELOG.md | 70 + vendor/sha2/Cargo.lock | 135 + vendor/sha2/Cargo.toml | 57 + vendor/sha2/LICENSE-APACHE | 201 + vendor/sha2/LICENSE-MIT | 27 + vendor/sha2/README.md | 56 + vendor/sha2/benches/sha256.rs | 4 + vendor/sha2/benches/sha512.rs | 4 + vendor/sha2/examples/sha256sum.rs | 47 + vendor/sha2/examples/sha512sum.rs | 47 + vendor/sha2/src/consts.rs | 216 + vendor/sha2/src/lib.rs | 72 + vendor/sha2/src/sha256.rs | 169 + vendor/sha2/src/sha256/aarch64.rs | 20 + vendor/sha2/src/sha256/soft.rs | 219 + vendor/sha2/src/sha256/x86.rs | 108 + vendor/sha2/src/sha512.rs | 250 + vendor/sha2/src/sha512/soft.rs | 216 + vendor/sha2/tests/data/sha224.blb | Bin 0 -> 184 bytes vendor/sha2/tests/data/sha256.blb | Bin 0 -> 196 bytes .../sha2/tests/data/sha256_one_million_a.bin | 1 + vendor/sha2/tests/data/sha384.blb | Bin 0 -> 244 bytes vendor/sha2/tests/data/sha512.blb | Bin 0 -> 292 bytes vendor/sha2/tests/data/sha512_224.blb | Bin 0 -> 184 bytes vendor/sha2/tests/data/sha512_256.blb | Bin 0 -> 196 bytes .../sha2/tests/data/sha512_one_million_a.bin | Bin 0 -> 64 bytes vendor/sha2/tests/lib.rs | 31 + vendor/snap/.cargo-checksum.json | 1 + vendor/snap/COPYING | 27 + vendor/snap/Cargo.lock | 14 + vendor/snap/Cargo.toml | 34 + vendor/snap/README.md | 229 + vendor/snap/build.rs | 124 + vendor/snap/data/COPYING | 23 + vendor/snap/data/Mark.Twain-Tom.Sawyer.txt | 396 + .../data/Mark.Twain-Tom.Sawyer.txt.rawsnappy | Bin 0 -> 9871 bytes vendor/snap/data/alice29.txt | 3609 +++ vendor/snap/data/asyoulik.txt | 4122 ++++ vendor/snap/data/baddata1.snappy | Bin 0 -> 27512 bytes vendor/snap/data/baddata2.snappy | Bin 0 -> 27483 bytes vendor/snap/data/baddata3.snappy | Bin 0 -> 28384 bytes vendor/snap/data/fireworks.jpeg | Bin 0 -> 123093 bytes vendor/snap/data/geo.protodata | Bin 0 -> 118588 bytes vendor/snap/data/html | 1 + vendor/snap/data/html_x_4 | 1 + vendor/snap/data/kppkn.gtb | Bin 0 -> 184320 bytes vendor/snap/data/lcet10.txt | 7519 ++++++ vendor/snap/data/paper-100k.pdf | 598 + vendor/snap/data/plrabn12.txt | 10699 ++++++++ vendor/snap/data/urls.10K | 10000 ++++++++ vendor/snap/examples/compress-escaped.rs | 39 + vendor/snap/examples/compress.rs | 13 + vendor/snap/examples/decompress.rs | 13 + vendor/snap/rustfmt.toml | 2 + vendor/snap/src/bytes.rs | 118 + vendor/snap/src/compress.rs | 539 + vendor/snap/src/crc32.rs | 111 + vendor/snap/src/crc32_table.rs | 2 + vendor/snap/src/decompress.rs | 470 + vendor/snap/src/error.rs | 333 + vendor/snap/src/frame.rs | 104 + vendor/snap/src/lib.rs | 109 + vendor/snap/src/raw.rs | 14 + vendor/snap/src/read.rs | 444 + vendor/snap/src/tag.rs | 2 + vendor/snap/src/varint.rs | 31 + vendor/snap/src/write.rs | 215 + vendor/stacker/.cargo-checksum.json | 2 +- vendor/stacker/Cargo.toml | 4 +- vendor/stacker/src/lib.rs | 34 +- vendor/syn/.cargo-checksum.json | 2 +- vendor/syn/Cargo.toml | 2 +- vendor/syn/benches/rust.rs | 3 +- vendor/syn/src/attr.rs | 41 +- vendor/syn/src/buffer.rs | 19 +- vendor/syn/src/error.rs | 9 +- vendor/syn/src/expr.rs | 300 +- vendor/syn/src/ext.rs | 8 +- vendor/syn/src/gen/clone.rs | 2051 ++ vendor/syn/src/gen/debug.rs | 2857 +++ vendor/syn/src/gen/eq.rs | 1930 ++ vendor/syn/src/gen/fold.rs | 268 +- vendor/syn/src/gen/hash.rs | 2691 ++ vendor/syn/src/generics.rs | 89 +- vendor/syn/src/item.rs | 306 +- vendor/syn/src/lib.rs | 23 +- vendor/syn/src/lifetime.rs | 11 +- vendor/syn/src/lit.rs | 156 +- vendor/syn/src/mac.rs | 32 +- vendor/syn/src/macros.rs | 36 +- vendor/syn/src/op.rs | 2 - vendor/syn/src/parse.rs | 20 +- vendor/syn/src/pat.rs | 112 +- vendor/syn/src/punctuated.rs | 92 +- vendor/syn/src/reserved.rs | 42 + vendor/syn/src/token.rs | 33 +- vendor/syn/src/ty.rs | 107 +- vendor/syn/tests/common/eq.rs | 84 +- vendor/syn/tests/repo/mod.rs | 7 +- vendor/syn/tests/test_derive_input.rs | 4 +- vendor/syn/tests/test_generics.rs | 2 +- vendor/syn/tests/test_grouping.rs | 2 +- vendor/syn/tests/test_lit.rs | 1 + vendor/syn/tests/test_precedence.rs | 2 +- vendor/syn/tests/test_round_trip.rs | 2 +- vendor/syn/tests/test_shebang.rs | 2 +- vendor/syn/tests/test_token_trees.rs | 2 +- vendor/time/.cargo-checksum.json | 2 +- vendor/time/Cargo.toml | 4 +- vendor/time/src/lib.rs | 2 + vendor/time/src/sys.rs | 82 +- vendor/toml/.cargo-checksum.json | 2 +- vendor/toml/Cargo.lock | 87 +- vendor/toml/Cargo.toml | 2 +- vendor/toml/src/de.rs | 33 +- vendor/toml/src/lib.rs | 23 +- vendor/toml/src/map.rs | 2 +- vendor/toml/src/ser.rs | 9 +- vendor/toml/src/tokens.rs | 10 +- vendor/toml/src/value.rs | 1 + vendor/tracing-core/.cargo-checksum.json | 2 +- vendor/tracing-core/CHANGELOG.md | 21 + vendor/tracing-core/Cargo.toml | 2 +- vendor/tracing-core/README.md | 51 +- vendor/tracing-core/src/callsite.rs | 22 +- vendor/tracing-core/src/dispatcher.rs | 102 +- vendor/tracing-core/src/lib.rs | 27 +- vendor/tracing-core/src/metadata.rs | 18 +- vendor/tracing-core/src/subscriber.rs | 25 +- vendor/ungrammar/.cargo-checksum.json | 2 +- vendor/ungrammar/Cargo.toml | 2 +- vendor/ungrammar/rust.ungram | 3 +- vendor/version_check/.cargo-checksum.json | 2 +- vendor/version_check/Cargo.toml | 2 +- vendor/version_check/src/version.rs | 154 +- .../.cargo-checksum.json | 1 + .../CODE_OF_CONDUCT.md | 49 + .../CONTRIBUTING.md | 8 + .../Cargo.toml | 43 + .../LICENSE-APACHE | 0 .../LICENSE-Apache-2.0_WITH_LLVM-exception | 220 + .../LICENSE-MIT | 2 - .../ORG_CODE_OF_CONDUCT.md | 143 + .../README.md | 76 + .../SECURITY.md | 29 + .../old-bitflags.patch | 0 .../src/error.rs | 51 + .../src/lib.rs | 36 + .../src/lib_generated.rs | 1853 ++ vendor/wasi/.cargo-checksum.json | 2 +- vendor/wasi/Cargo.toml | 2 +- vendor/wasi/src/lib.rs | 12 + vendor/wasi/src/lib_generated.rs | 137 +- version | 2 +- 5849 files changed, 282521 insertions(+), 127107 deletions(-) rename {src => compiler}/rustc/Cargo.toml (74%) rename src/rustc/rustc.rs => compiler/rustc/src/main.rs (100%) rename {src/librustc_apfloat => compiler/rustc_apfloat}/Cargo.toml (82%) rename {src/librustc_apfloat => compiler/rustc_apfloat/src}/ieee.rs (100%) rename {src/librustc_apfloat => compiler/rustc_apfloat/src}/lib.rs (99%) rename {src/librustc_apfloat => compiler/rustc_apfloat/src}/ppc.rs (100%) rename {src/librustc_apfloat => compiler/rustc_apfloat}/tests/ieee.rs (100%) rename {src/librustc_apfloat => compiler/rustc_apfloat}/tests/ppc.rs (100%) rename {src/librustc_arena => compiler/rustc_arena}/Cargo.toml (63%) rename {src/librustc_arena => compiler/rustc_arena/src}/lib.rs (90%) rename {src/librustc_arena => compiler/rustc_arena/src}/tests.rs (94%) create mode 100644 compiler/rustc_ast/Cargo.toml rename {src/librustc_ast => compiler/rustc_ast}/README.md (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/ast.rs (98%) rename {src/librustc_ast => compiler/rustc_ast/src}/ast/tests.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/attr/mod.rs (96%) rename {src/librustc_ast => compiler/rustc_ast/src}/crate_disambiguator.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/entry.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/expand/allocator.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/expand/mod.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/lib.rs (90%) rename {src/librustc_ast => compiler/rustc_ast/src}/mut_visit.rs (97%) rename {src/librustc_ast => compiler/rustc_ast/src}/node_id.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/ptr.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/token.rs (97%) rename {src/librustc_ast => compiler/rustc_ast/src}/tokenstream.rs (93%) rename {src/librustc_ast => compiler/rustc_ast/src}/util/classify.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/util/comments.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/util/comments/tests.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/util/lev_distance.rs (97%) rename {src/librustc_ast => compiler/rustc_ast/src}/util/lev_distance/tests.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/util/literal.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/util/parser.rs (100%) rename {src/librustc_ast => compiler/rustc_ast/src}/visit.rs (99%) create mode 100644 compiler/rustc_ast_lowering/Cargo.toml rename {src/librustc_ast_lowering => compiler/rustc_ast_lowering/src}/expr.rs (99%) rename {src/librustc_ast_lowering => compiler/rustc_ast_lowering/src}/item.rs (99%) rename {src/librustc_ast_lowering => compiler/rustc_ast_lowering/src}/lib.rs (99%) rename {src/librustc_ast_lowering => compiler/rustc_ast_lowering/src}/pat.rs (100%) rename {src/librustc_ast_lowering => compiler/rustc_ast_lowering/src}/path.rs (100%) create mode 100644 compiler/rustc_ast_passes/Cargo.toml rename {src/librustc_ast_passes => compiler/rustc_ast_passes/src}/ast_validation.rs (98%) rename {src/librustc_ast_passes => compiler/rustc_ast_passes/src}/feature_gate.rs (95%) rename {src/librustc_ast_passes => compiler/rustc_ast_passes/src}/lib.rs (100%) rename {src/librustc_ast_passes => compiler/rustc_ast_passes/src}/node_count.rs (100%) rename {src/librustc_ast_passes => compiler/rustc_ast_passes/src}/show_span.rs (100%) create mode 100644 compiler/rustc_ast_pretty/Cargo.toml rename {src/librustc_ast_pretty => compiler/rustc_ast_pretty/src}/helpers.rs (100%) rename {src/librustc_ast_pretty => compiler/rustc_ast_pretty/src}/lib.rs (100%) rename {src/librustc_ast_pretty => compiler/rustc_ast_pretty/src}/pp.rs (100%) rename {src/librustc_ast_pretty => compiler/rustc_ast_pretty/src}/pprust.rs (99%) rename {src/librustc_ast_pretty => compiler/rustc_ast_pretty/src}/pprust/tests.rs (89%) create mode 100644 compiler/rustc_attr/Cargo.toml rename {src/librustc_attr => compiler/rustc_attr/src}/builtin.rs (95%) rename {src/librustc_attr => compiler/rustc_attr/src}/lib.rs (100%) create mode 100644 compiler/rustc_builtin_macros/Cargo.toml rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/asm.rs (99%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/assert.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/cfg.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/cfg_accessible.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/cmdline_attrs.rs (92%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/compile_error.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/concat.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/concat_idents.rs (84%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/bounds.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/clone.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/cmp/eq.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/cmp/ord.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/cmp/partial_eq.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/cmp/partial_ord.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/debug.rs (99%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/decodable.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/default.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/encodable.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/generic/mod.rs (99%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/generic/ty.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/hash.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/deriving/mod.rs (99%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/env.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/format.rs (95%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/format_foreign.rs (98%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/format_foreign/printf/tests.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/format_foreign/shell/tests.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/global_allocator.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/global_asm.rs (91%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/lib.rs (98%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/llvm_asm.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/log_syntax.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/proc_macro_harness.rs (98%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/source_util.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/standard_library_imports.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/test.rs (98%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/test_harness.rs (99%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/trace_macros.rs (100%) rename {src/librustc_builtin_macros => compiler/rustc_builtin_macros/src}/util.rs (100%) create mode 100644 compiler/rustc_codegen_llvm/Cargo.toml rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm}/README.md (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/abi.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/allocator.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/asm.rs (95%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/attributes.rs (98%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/back/archive.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/back/lto.rs (99%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/back/profiling.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/back/write.rs (96%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/base.rs (96%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/builder.rs (98%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/callee.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/common.rs (99%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/consts.rs (97%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/context.rs (96%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/coverageinfo/mapgen.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/coverageinfo/mod.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/debuginfo/create_scope_map.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/debuginfo/doc.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/debuginfo/gdb.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/debuginfo/metadata.rs (98%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/debuginfo/mod.rs (99%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/debuginfo/namespace.rs (80%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/debuginfo/source_loc.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/debuginfo/utils.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/declare.rs (59%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/intrinsic.rs (71%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/lib.rs (97%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/llvm/archive_ro.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/llvm/diagnostic.rs (98%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/llvm/ffi.rs (99%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/llvm/mod.rs (97%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/llvm_util.rs (99%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/metadata.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/mono_item.rs (100%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/type_.rs (98%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/type_of.rs (89%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/va_arg.rs (99%) rename {src/librustc_codegen_llvm => compiler/rustc_codegen_llvm/src}/value.rs (100%) create mode 100644 compiler/rustc_codegen_ssa/Cargo.toml rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa}/README.md (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/archive.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/command.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/link.rs (94%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/linker.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/lto.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/mod.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/rpath.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/rpath/tests.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/symbol_export.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/back/write.rs (97%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/base.rs (95%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/common.rs (98%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/coverageinfo/ffi.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/coverageinfo/map.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/coverageinfo/mod.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/debuginfo/mod.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/debuginfo/type_names.rs (98%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/glue.rs (98%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/lib.rs (96%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/meth.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/analyze.rs (99%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/block.rs (96%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/constant.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/coverageinfo.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/debuginfo.rs (100%) create mode 100644 compiler/rustc_codegen_ssa/src/mir/intrinsic.rs rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/mod.rs (99%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/operand.rs (92%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/place.rs (92%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/rvalue.rs (97%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mir/statement.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/mono_item.rs (94%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/abi.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/asm.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/backend.rs (92%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/builder.rs (95%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/consts.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/coverageinfo.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/debuginfo.rs (100%) create mode 100644 compiler/rustc_codegen_ssa/src/traits/declare.rs rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/intrinsic.rs (80%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/misc.rs (82%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/mod.rs (96%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/statics.rs (100%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/type_.rs (99%) rename {src/librustc_codegen_ssa => compiler/rustc_codegen_ssa/src}/traits/write.rs (90%) rename {src/librustc_data_structures => compiler/rustc_data_structures}/Cargo.toml (69%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/atomic_ref.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/base_n.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/base_n/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/binary_search_util/mod.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/binary_search_util/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/box_region.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/captures.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/const_cstr.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/fingerprint.rs (82%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/flock.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/frozen.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/fx.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/dominators/mod.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/dominators/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/implementation/mod.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/implementation/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/iterate/mod.rs (97%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/iterate/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/mod.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/reference.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/scc/mod.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/scc/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/vec_graph/mod.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/graph/vec_graph/tests.rs (100%) create mode 100644 compiler/rustc_data_structures/src/jobserver.rs rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/lib.rs (91%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/macros.rs (76%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/map_in_place.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/mini_map.rs (100%) create mode 100644 compiler/rustc_data_structures/src/mini_set.rs rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/obligation_forest/graphviz.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/obligation_forest/mod.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/obligation_forest/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/owning_ref/LICENSE (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/owning_ref/mod.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/owning_ref/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/profiling.rs (99%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/ptr_key.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/sharded.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/sip128.rs (89%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/sip128/tests.rs (90%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/small_c_str.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/small_c_str/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/snapshot_map/mod.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/snapshot_map/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/sorted_map.rs (98%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/sorted_map/index_map.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/sorted_map/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/stable_hasher.rs (98%) create mode 100644 compiler/rustc_data_structures/src/stable_hasher/tests.rs rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/stable_map.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/stable_set.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/stack.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/svh.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/sync.rs (99%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/tagged_ptr.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/tagged_ptr/copy.rs (98%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/tagged_ptr/drop.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/temp_dir.rs (92%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/thin_vec.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/tiny_list.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/tiny_list/tests.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/transitive_relation.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/transitive_relation/tests.rs (100%) create mode 100644 compiler/rustc_data_structures/src/unhash.rs rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/vec_linked_list.rs (100%) rename {src/librustc_data_structures => compiler/rustc_data_structures/src}/work_queue.rs (100%) create mode 100644 compiler/rustc_driver/Cargo.toml rename {src/librustc_driver => compiler/rustc_driver}/README.md (100%) rename {src/librustc_driver => compiler/rustc_driver/src}/args.rs (94%) rename {src/librustc_driver => compiler/rustc_driver/src}/lib.rs (97%) rename {src/librustc_driver => compiler/rustc_driver/src}/pretty.rs (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes}/Cargo.toml (69%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes.rs (98%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0001.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0002.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0004.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0005.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0007.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0009.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0010.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0013.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0014.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0015.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0023.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0025.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0026.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0027.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0029.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0030.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0033.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0034.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0038.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0040.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0044.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0045.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0046.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0049.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0050.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0053.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0054.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0055.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0057.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0059.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0060.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0061.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0062.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0063.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0067.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0069.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0070.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0071.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0072.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0073.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0074.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0075.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0076.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0077.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0080.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0081.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0084.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0087.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0088.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0089.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0090.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0091.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0092.md (74%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0093.md (77%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0094.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0106.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0107.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0109.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0110.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0116.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0117.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0118.md (63%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0119.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0120.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0121.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0124.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0128.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0130.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0131.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0132.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0133.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0136.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0137.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0138.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0139.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0152.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0154.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0158.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0161.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0162.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0164.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0165.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0170.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0178.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0184.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0185.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0186.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0191.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0192.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0193.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0195.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0197.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0198.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0199.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0200.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0201.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0202.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0203.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0204.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0205.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0206.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0207.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0210.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0211.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0214.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0220.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0221.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0222.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0223.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0224.md (59%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0225.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0226.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0228.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0229.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0230.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0231.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0232.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0243.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0244.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0251.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0252.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0253.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0254.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0255.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0256.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0259.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0260.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0261.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0262.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0263.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0264.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0267.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0268.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0271.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0275.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0276.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0277.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0281.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0282.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0283.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0284.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0297.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0301.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0302.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0303.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0307.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0308.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0309.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0310.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0312.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0317.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0321.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0322.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0323.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0324.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0325.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0326.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0328.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0329.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0364.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0365.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0366.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0367.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0368.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0369.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0370.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0371.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0373.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0374.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0375.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0376.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0378.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0379.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0380.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0381.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0382.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0383.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0384.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0386.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0387.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0388.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0389.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0390.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0391.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0392.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0393.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0398.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0399.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0401.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0403.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0404.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0405.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0407.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0408.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0409.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0411.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0412.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0415.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0416.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0422.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0423.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0424.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0425.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0426.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0428.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0429.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0430.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0431.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0432.md (100%) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0433.md rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0434.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0435.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0436.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0437.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0438.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0439.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0445.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0446.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0447.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0448.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0449.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0451.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0452.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0453.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0454.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0455.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0458.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0459.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0463.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0466.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0468.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0469.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0477.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0478.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0491.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0492.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0493.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0495.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0496.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0497.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0499.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0500.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0501.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0502.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0503.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0504.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0505.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0506.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0507.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0508.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0509.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0510.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0511.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0512.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0515.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0516.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0517.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0518.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0520.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0522.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0524.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0525.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0527.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0528.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0529.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0530.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0531.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0532.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0533.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0534.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0535.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0536.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0537.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0538.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0539.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0541.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0550.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0551.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0552.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0554.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0556.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0557.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0559.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0560.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0561.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0562.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0565.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0566.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0567.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0568.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0569.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0570.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0571.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0572.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0573.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0574.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0575.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0576.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0577.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0578.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0579.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0580.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0581.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0582.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0583.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0584.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0585.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0586.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0587.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0588.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0589.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0590.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0591.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0592.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0593.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0594.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0595.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0596.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0597.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0599.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0600.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0601.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0602.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0603.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0604.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0605.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0606.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0607.md (55%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0608.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0609.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0610.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0614.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0615.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0616.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0617.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0618.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0619.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0620.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0621.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0622.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0623.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0624.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0626.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0627.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0628.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0631.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0633.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0634.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0635.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0636.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0637.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0638.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0639.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0641.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0642.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0643.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0644.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0646.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0647.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0648.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0657.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0658.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0659.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0660.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0661.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0662.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0663.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0664.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0665.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0666.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0668.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0669.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0670.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0671.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0687.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0688.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0689.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0690.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0691.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0692.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0693.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0695.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0696.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0697.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0698.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0699.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0700.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0701.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0703.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0704.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0705.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0706.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0708.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0710.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0712.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0713.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0714.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0715.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0716.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0718.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0719.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0720.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0723.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0724.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0725.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0727.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0728.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0729.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0730.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0731.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0732.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0733.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0734.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0735.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0736.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0737.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0739.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0740.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0741.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0742.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0743.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0744.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0745.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0746.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0747.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0748.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0749.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0750.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0751.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0752.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0753.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0754.md (100%) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0755.md create mode 100644 compiler/rustc_error_codes/src/error_codes/E0756.md rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0758.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0759.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0760.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0761.md (93%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0762.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0763.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0764.md (60%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0765.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0766.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0767.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0768.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0769.md (58%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0770.md (100%) rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/error_codes/E0771.md (100%) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0773.md create mode 100644 compiler/rustc_error_codes/src/error_codes/E0774.md create mode 100644 compiler/rustc_error_codes/src/error_codes/E0775.md create mode 100644 compiler/rustc_error_codes/src/error_codes/E0776.md rename {src/librustc_error_codes => compiler/rustc_error_codes/src}/lib.rs (100%) rename {src/librustc_errors => compiler/rustc_errors}/Cargo.toml (60%) rename {src/librustc_errors => compiler/rustc_errors/src}/annotate_snippet_emitter_writer.rs (100%) rename {src/librustc_errors => compiler/rustc_errors/src}/diagnostic.rs (100%) rename {src/librustc_errors => compiler/rustc_errors/src}/diagnostic_builder.rs (100%) rename {src/librustc_errors => compiler/rustc_errors/src}/emitter.rs (99%) rename {src/librustc_errors => compiler/rustc_errors/src}/json.rs (100%) rename {src/librustc_errors => compiler/rustc_errors/src}/json/tests.rs (100%) rename {src/librustc_errors => compiler/rustc_errors/src}/lib.rs (94%) rename {src/librustc_errors => compiler/rustc_errors/src}/lock.rs (100%) rename {src/librustc_errors => compiler/rustc_errors/src}/registry.rs (100%) rename {src/librustc_errors => compiler/rustc_errors/src}/snippet.rs (96%) rename {src/librustc_errors => compiler/rustc_errors/src}/styled_buffer.rs (100%) create mode 100644 compiler/rustc_expand/Cargo.toml rename {src/librustc_expand => compiler/rustc_expand/src}/base.rs (97%) rename {src/librustc_expand => compiler/rustc_expand/src}/build.rs (93%) rename {src/librustc_expand => compiler/rustc_expand/src}/config.rs (98%) rename {src/librustc_expand => compiler/rustc_expand/src}/expand.rs (97%) rename {src/librustc_expand => compiler/rustc_expand/src}/lib.rs (90%) rename {src/librustc_expand => compiler/rustc_expand/src}/mbe.rs (100%) rename {src/librustc_expand => compiler/rustc_expand/src}/mbe/macro_check.rs (100%) rename {src/librustc_expand => compiler/rustc_expand/src}/mbe/macro_parser.rs (100%) rename {src/librustc_expand => compiler/rustc_expand/src}/mbe/macro_rules.rs (100%) rename {src/librustc_expand => compiler/rustc_expand/src}/mbe/quoted.rs (100%) rename {src/librustc_expand => compiler/rustc_expand/src}/mbe/transcribe.rs (99%) rename {src/librustc_expand => compiler/rustc_expand/src}/module.rs (96%) rename {src/librustc_expand => compiler/rustc_expand/src}/mut_visit/tests.rs (100%) rename {src/librustc_expand => compiler/rustc_expand/src}/parse/tests.rs (100%) rename {src/librustc_expand => compiler/rustc_expand/src}/placeholders.rs (92%) rename {src/librustc_expand => compiler/rustc_expand/src}/proc_macro.rs (89%) rename {src/librustc_expand => compiler/rustc_expand/src}/proc_macro_server.rs (97%) rename {src/librustc_expand => compiler/rustc_expand/src}/tests.rs (100%) rename {src/librustc_expand => compiler/rustc_expand/src}/tokenstream/tests.rs (100%) create mode 100644 compiler/rustc_feature/Cargo.toml rename {src/librustc_feature => compiler/rustc_feature/src}/accepted.rs (98%) rename {src/librustc_feature => compiler/rustc_feature/src}/active.rs (96%) rename {src/librustc_feature => compiler/rustc_feature/src}/builtin_attrs.rs (98%) rename {src/librustc_feature => compiler/rustc_feature/src}/lib.rs (88%) rename {src/librustc_feature => compiler/rustc_feature/src}/removed.rs (97%) rename {src/librustc_fs_util => compiler/rustc_fs_util}/Cargo.toml (63%) rename {src/librustc_fs_util => compiler/rustc_fs_util/src}/lib.rs (100%) rename {src/librustc_graphviz => compiler/rustc_graphviz}/Cargo.toml (70%) rename {src/librustc_graphviz => compiler/rustc_graphviz/src}/lib.rs (95%) rename {src/librustc_graphviz => compiler/rustc_graphviz/src}/tests.rs (100%) create mode 100644 compiler/rustc_hir/Cargo.toml rename {src/librustc_hir => compiler/rustc_hir/src}/arena.rs (100%) rename {src/librustc_hir => compiler/rustc_hir/src}/def.rs (91%) rename {src/librustc_hir => compiler/rustc_hir/src}/definitions.rs (87%) rename {src/librustc_hir => compiler/rustc_hir/src}/hir.rs (99%) rename {src/librustc_hir => compiler/rustc_hir/src}/hir_id.rs (100%) rename {src/librustc_hir => compiler/rustc_hir/src}/intravisit.rs (99%) rename {src/librustc_hir => compiler/rustc_hir/src}/itemlikevisit.rs (100%) rename {src/librustc_hir => compiler/rustc_hir/src}/lang_items.rs (97%) rename {src/librustc_hir => compiler/rustc_hir/src}/lib.rs (94%) rename {src/librustc_hir => compiler/rustc_hir/src}/pat_util.rs (100%) rename {src/librustc_hir => compiler/rustc_hir/src}/stable_hash_impls.rs (100%) rename {src/librustc_hir => compiler/rustc_hir/src}/target.rs (100%) rename {src/librustc_hir => compiler/rustc_hir/src}/weak_lang_items.rs (79%) create mode 100644 compiler/rustc_hir_pretty/Cargo.toml rename {src/librustc_hir_pretty => compiler/rustc_hir_pretty/src}/lib.rs (100%) create mode 100644 compiler/rustc_incremental/Cargo.toml rename {src/librustc_incremental => compiler/rustc_incremental/src}/assert_dep_graph.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/assert_module_sources.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/lib.rs (92%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/README.md (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/data.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/dirty_clean.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/file_format.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/fs.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/fs/tests.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/load.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/mod.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/save.rs (100%) rename {src/librustc_incremental => compiler/rustc_incremental/src}/persist/work_product.rs (100%) rename {src/librustc_index => compiler/rustc_index}/Cargo.toml (60%) rename {src/librustc_index => compiler/rustc_index/src}/bit_set.rs (97%) rename {src/librustc_index => compiler/rustc_index/src}/bit_set/tests.rs (100%) rename {src/librustc_index => compiler/rustc_index/src}/lib.rs (100%) rename {src/librustc_index => compiler/rustc_index/src}/vec.rs (100%) rename {src/librustc_index => compiler/rustc_index/src}/vec/tests.rs (100%) create mode 100644 compiler/rustc_infer/Cargo.toml rename {src/librustc_infer => compiler/rustc_infer/src}/infer/at.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/canonical/canonicalizer.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/canonical/mod.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/canonical/query_response.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/canonical/substitute.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/combine.rs (76%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/equate.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/mod.rs (94%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/need_type_info.rs (72%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/nice_region_error/different_lifetimes.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/nice_region_error/find_anon_type.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/nice_region_error/mod.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/nice_region_error/named_anon_conflict.rs (98%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/nice_region_error/placeholder_error.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/nice_region_error/static_impl_trait.rs (96%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/nice_region_error/trait_impl_difference.rs (96%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/nice_region_error/util.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/error_reporting/note.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/free_regions.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/freshen.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/fudge.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/glb.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/higher_ranked/README.md (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/higher_ranked/mod.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/lattice.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/lexical_region_resolve/README.md (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/lexical_region_resolve/mod.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/lub.rs (98%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/mod.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/nll_relate/mod.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/outlives/env.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/outlives/mod.rs (90%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/outlives/obligations.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/outlives/verify.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/region_constraints/README.md (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/region_constraints/leak_check.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/region_constraints/mod.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/resolve.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/sub.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/type_variable.rs (99%) rename {src/librustc_infer => compiler/rustc_infer/src}/infer/undo_log.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/lib.rs (88%) rename {src/librustc_infer => compiler/rustc_infer/src}/traits/engine.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/traits/error_reporting/mod.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/traits/mod.rs (98%) rename {src/librustc_infer => compiler/rustc_infer/src}/traits/project.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/traits/structural_impls.rs (100%) rename {src/librustc_infer => compiler/rustc_infer/src}/traits/util.rs (98%) create mode 100644 compiler/rustc_interface/Cargo.toml rename {src/librustc_interface => compiler/rustc_interface/src}/callbacks.rs (100%) rename {src/librustc_interface => compiler/rustc_interface/src}/interface.rs (96%) rename {src/librustc_interface => compiler/rustc_interface/src}/lib.rs (95%) rename {src/librustc_interface => compiler/rustc_interface/src}/passes.rs (99%) rename {src/librustc_interface => compiler/rustc_interface/src}/proc_macro_decls.rs (100%) rename {src/librustc_interface => compiler/rustc_interface/src}/queries.rs (100%) rename {src/librustc_interface => compiler/rustc_interface/src}/tests.rs (99%) rename {src/librustc_interface => compiler/rustc_interface/src}/util.rs (96%) rename {src/librustc_lexer => compiler/rustc_lexer}/Cargo.toml (93%) rename {src/librustc_lexer => compiler/rustc_lexer}/src/cursor.rs (100%) rename {src/librustc_lexer => compiler/rustc_lexer}/src/lib.rs (98%) create mode 100644 compiler/rustc_lexer/src/tests.rs rename {src/librustc_lexer => compiler/rustc_lexer}/src/unescape.rs (100%) rename {src/librustc_lexer => compiler/rustc_lexer}/src/unescape/tests.rs (100%) create mode 100644 compiler/rustc_lint/Cargo.toml rename {src/librustc_lint => compiler/rustc_lint/src}/array_into_iter.rs (73%) rename {src/librustc_lint => compiler/rustc_lint/src}/builtin.rs (80%) rename {src/librustc_lint => compiler/rustc_lint/src}/context.rs (96%) rename {src/librustc_lint => compiler/rustc_lint/src}/early.rs (100%) rename {src/librustc_lint => compiler/rustc_lint/src}/internal.rs (85%) rename {src/librustc_lint => compiler/rustc_lint/src}/late.rs (100%) rename {src/librustc_lint => compiler/rustc_lint/src}/levels.rs (100%) rename {src/librustc_lint => compiler/rustc_lint/src}/lib.rs (99%) rename {src/librustc_lint => compiler/rustc_lint/src}/non_ascii_idents.rs (64%) rename {src/librustc_lint => compiler/rustc_lint/src}/nonstandard_style.rs (90%) rename {src/librustc_lint => compiler/rustc_lint/src}/nonstandard_style/tests.rs (100%) rename {src/librustc_lint => compiler/rustc_lint/src}/passes.rs (100%) rename {src/librustc_lint => compiler/rustc_lint/src}/redundant_semicolon.rs (80%) rename {src/librustc_lint => compiler/rustc_lint/src}/types.rs (89%) rename {src/librustc_lint => compiler/rustc_lint/src}/unused.rs (90%) rename {src/librustc_llvm => compiler/rustc_llvm}/Cargo.toml (67%) rename {src/librustc_llvm => compiler/rustc_llvm}/build.rs (95%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/.editorconfig (100%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/ArchiveWrapper.cpp (99%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/CoverageMappingWrapper.cpp (98%) rename src/rustllvm/rustllvm.h => compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h (100%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/Linker.cpp (97%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/PassWrapper.cpp (99%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/README (100%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/RustWrapper.cpp (99%) rename {src/librustc_llvm => compiler/rustc_llvm/src}/lib.rs (98%) rename {src/librustc_macros => compiler/rustc_macros}/Cargo.toml (100%) rename {src/librustc_macros => compiler/rustc_macros}/src/hash_stable.rs (100%) rename {src/librustc_macros => compiler/rustc_macros}/src/lib.rs (78%) rename {src/librustc_macros => compiler/rustc_macros}/src/lift.rs (100%) rename {src/librustc_macros => compiler/rustc_macros}/src/query.rs (94%) rename {src/librustc_macros => compiler/rustc_macros}/src/serialize.rs (100%) create mode 100644 compiler/rustc_macros/src/session_diagnostic.rs rename {src/librustc_macros => compiler/rustc_macros}/src/symbols.rs (99%) rename {src/librustc_macros => compiler/rustc_macros}/src/type_foldable.rs (100%) create mode 100644 compiler/rustc_metadata/Cargo.toml rename {src/librustc_metadata => compiler/rustc_metadata/src}/creader.rs (98%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/dependency_format.rs (100%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/dynamic_lib.rs (51%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/dynamic_lib/tests.rs (100%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/foreign_modules.rs (100%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/lib.rs (87%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/link_args.rs (100%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/locator.rs (99%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/native_libs.rs (98%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/rmeta/decoder.rs (97%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/rmeta/decoder/cstore_impl.rs (97%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/rmeta/encoder.rs (93%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/rmeta/mod.rs (91%) rename {src/librustc_metadata => compiler/rustc_metadata/src}/rmeta/table.rs (100%) create mode 100644 compiler/rustc_middle/Cargo.toml rename {src/librustc_middle => compiler/rustc_middle}/README.md (100%) rename {src/librustc_middle => compiler/rustc_middle}/benches/lib.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/arena.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/dep_graph/dep_node.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/dep_graph/mod.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/hir/exports.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/hir/map/blocks.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/hir/map/collector.rs (98%) rename {src/librustc_middle => compiler/rustc_middle/src}/hir/map/mod.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/hir/mod.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/hir/place.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ich/hcx.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ich/impls_hir.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ich/impls_syntax.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ich/impls_ty.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ich/mod.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/infer/canonical.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/infer/mod.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/infer/unify_key.rs (94%) rename {src/librustc_middle => compiler/rustc_middle/src}/lib.rs (91%) rename {src/librustc_middle => compiler/rustc_middle/src}/lint.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/macros.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/codegen_fn_attrs.rs (96%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/cstore.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/dependency_format.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/exported_symbols.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/lang_items.rs (83%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/limits.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/mod.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/privacy.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/region.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/resolve_lifetime.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/middle/stability.rs (92%) create mode 100644 compiler/rustc_middle/src/mir/abstract_const.rs rename {src/librustc_middle => compiler/rustc_middle/src}/mir/coverage/mod.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/interpret/allocation.rs (98%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/interpret/error.rs (98%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/interpret/mod.rs (90%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/interpret/pointer.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/interpret/queries.rs (90%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/interpret/value.rs (97%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/mod.rs (93%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/mono.rs (95%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/predecessors.rs (97%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/query.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/tcx.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/terminator/mod.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/traversal.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/type_foldable.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/mir/visit.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/query/mod.rs (93%) rename {src/librustc_middle => compiler/rustc_middle/src}/tests.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/traits/chalk.rs (81%) rename {src/librustc_middle => compiler/rustc_middle/src}/traits/mod.rs (89%) rename {src/librustc_middle => compiler/rustc_middle/src}/traits/query.rs (77%) rename {src/librustc_middle => compiler/rustc_middle/src}/traits/select.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/traits/specialization_graph.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/traits/structural_impls.rs (77%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/_match.rs (98%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/adjustment.rs (98%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/binding.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/cast.rs (98%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/codec.rs (95%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/consts.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/consts/int.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/consts/kind.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/context.rs (97%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/diagnostics.rs (78%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/erase_regions.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/error.rs (94%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/fast_reject.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/flags.rs (98%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/fold.rs (98%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/inhabitedness/def_id_forest.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/inhabitedness/mod.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/instance.rs (95%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/layout.rs (96%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/list.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/mod.rs (97%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/normalize_erasing_regions.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/outlives.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/print/mod.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/print/pretty.rs (87%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/query/README.md (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/query/job.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/query/keys.rs (95%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/query/mod.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/query/on_disk_cache.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/query/plumbing.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/query/profiling_support.rs (97%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/query/stats.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/query/values.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/relate.rs (97%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/steal.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/structural_impls.rs (96%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/sty.rs (95%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/subst.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/trait_def.rs (99%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/util.rs (97%) rename {src/librustc_middle => compiler/rustc_middle/src}/ty/walk.rs (83%) rename {src/librustc_middle => compiler/rustc_middle/src}/util/bug.rs (100%) rename {src/librustc_middle => compiler/rustc_middle/src}/util/common.rs (97%) rename {src/librustc_middle => compiler/rustc_middle/src}/util/common/tests.rs (100%) create mode 100644 compiler/rustc_mir/Cargo.toml rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/borrow_set.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/constraint_generation.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/constraints/graph.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/constraints/mod.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/def_use.rs (96%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/conflict_errors.rs (95%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/explain_borrow.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/find_use.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/mod.rs (81%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/move_errors.rs (96%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/mutability_errors.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/outlives_suggestion.rs (98%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/region_errors.rs (98%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/region_name.rs (98%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/diagnostics/var_name.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/facts.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/invalidation.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/location.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/member_constraints.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/mod.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/nll.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/path_utils.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/place_ext.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/places_conflict.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/prefixes.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/region_infer/dump_mir.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/region_infer/graphviz.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/region_infer/mod.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/region_infer/opaque_types.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/region_infer/reverse_sccs.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/region_infer/values.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/renumber.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/type_check/constraint_conversion.rs (98%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/type_check/free_region_relations.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/type_check/input_output.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/type_check/liveness/local_use_map.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/type_check/liveness/mod.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/type_check/liveness/polonius.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/type_check/liveness/trace.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/type_check/mod.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/type_check/relate_tys.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/universal_regions.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/borrow_check/used_muts.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/const_eval/error.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/const_eval/eval_queries.rs (78%) rename {src/librustc_mir => compiler/rustc_mir/src}/const_eval/fn_queries.rs (95%) rename {src/librustc_mir => compiler/rustc_mir/src}/const_eval/machine.rs (81%) rename {src/librustc_mir => compiler/rustc_mir/src}/const_eval/mod.rs (60%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/drop_flag_effects.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/framework/cursor.rs (90%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/framework/direction.rs (80%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/framework/engine.rs (73%) create mode 100644 compiler/rustc_mir/src/dataflow/framework/fmt.rs rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/framework/graphviz.rs (53%) create mode 100644 compiler/rustc_mir/src/dataflow/framework/lattice.rs rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/framework/mod.rs (76%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/framework/tests.rs (93%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/framework/visitor.rs (95%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/impls/borrowed_locals.rs (97%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/impls/borrows.rs (96%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/impls/init_locals.rs (91%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/impls/liveness.rs (94%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/impls/mod.rs (74%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/impls/storage_liveness.rs (95%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/mod.rs (82%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/move_paths/abs_domain.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/move_paths/builder.rs (97%) rename {src/librustc_mir => compiler/rustc_mir/src}/dataflow/move_paths/mod.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/cast.rs (97%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/eval_context.rs (95%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/intern.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/intrinsics.rs (90%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/intrinsics/caller_location.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/intrinsics/type_name.rs (97%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/machine.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/memory.rs (98%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/mod.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/operand.rs (97%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/operator.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/place.rs (98%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/step.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/terminator.rs (96%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/traits.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/util.rs (96%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/validity.rs (94%) rename {src/librustc_mir => compiler/rustc_mir/src}/interpret/visitor.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/lib.rs (75%) rename {src/librustc_mir => compiler/rustc_mir/src}/monomorphize/collector.rs (94%) rename {src/librustc_mir => compiler/rustc_mir/src}/monomorphize/mod.rs (91%) rename {src/librustc_mir => compiler/rustc_mir/src}/monomorphize/partitioning/default.rs (95%) rename {src/librustc_mir => compiler/rustc_mir/src}/monomorphize/partitioning/merging.rs (90%) rename {src/librustc_mir => compiler/rustc_mir/src}/monomorphize/partitioning/mod.rs (93%) rename {src/librustc_mir => compiler/rustc_mir/src}/monomorphize/polymorphize.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/shim.rs (94%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/add_call_guards.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/add_moves_for_packed_drops.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/add_retag.rs (99%) create mode 100644 compiler/rustc_mir/src/transform/check_const_item_mutation.rs create mode 100644 compiler/rustc_mir/src/transform/check_consts/mod.rs create mode 100644 compiler/rustc_mir/src/transform/check_consts/ops.rs rename {src/librustc_mir => compiler/rustc_mir/src}/transform/check_consts/post_drop_elaboration.rs (90%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/check_consts/qualifs.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/check_consts/resolver.rs (94%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/check_consts/validation.rs (55%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/check_packed_ref.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/check_unsafety.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/cleanup_post_borrowck.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/const_prop.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/copy_prop.rs (98%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/deaggregator.rs (100%) create mode 100644 compiler/rustc_mir/src/transform/dest_prop.rs rename {src/librustc_mir => compiler/rustc_mir/src}/transform/dump_mir.rs (100%) create mode 100644 compiler/rustc_mir/src/transform/early_otherwise_branch.rs rename {src/librustc_mir => compiler/rustc_mir/src}/transform/elaborate_drops.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/generator.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/inline.rs (92%) create mode 100644 compiler/rustc_mir/src/transform/instcombine.rs create mode 100644 compiler/rustc_mir/src/transform/instrument_coverage.rs rename {src/librustc_mir => compiler/rustc_mir/src}/transform/match_branches.rs (95%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/mod.rs (95%) create mode 100644 compiler/rustc_mir/src/transform/multiple_return_terminators.rs rename {src/librustc_mir => compiler/rustc_mir/src}/transform/no_landing_pads.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/nrvo.rs (93%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/promote_consts.rs (93%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/remove_noop_landing_pads.rs (94%) create mode 100644 compiler/rustc_mir/src/transform/remove_unneeded_drops.rs rename {src/librustc_mir => compiler/rustc_mir/src}/transform/required_consts.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/rustc_peek.rs (95%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/simplify.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/simplify_branches.rs (100%) create mode 100644 compiler/rustc_mir/src/transform/simplify_comparison_integral.rs rename {src/librustc_mir => compiler/rustc_mir/src}/transform/simplify_try.rs (91%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/uninhabited_enum_branching.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/unreachable_prop.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/transform/validate.rs (78%) rename {src/librustc_mir => compiler/rustc_mir/src}/util/aggregate.rs (91%) rename {src/librustc_mir => compiler/rustc_mir/src}/util/alignment.rs (98%) rename {src/librustc_mir => compiler/rustc_mir/src}/util/borrowck_errors.rs (99%) rename {src/librustc_mir => compiler/rustc_mir/src}/util/collect_writes.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/util/def_use.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/util/elaborate_drops.rs (99%) create mode 100644 compiler/rustc_mir/src/util/find_self_call.rs rename {src/librustc_mir => compiler/rustc_mir/src}/util/graphviz.rs (85%) rename {src/librustc_mir => compiler/rustc_mir/src}/util/mod.rs (84%) rename {src/librustc_mir => compiler/rustc_mir/src}/util/patch.rs (100%) rename {src/librustc_mir => compiler/rustc_mir/src}/util/pretty.rs (98%) create mode 100644 compiler/rustc_mir/src/util/spanview.rs rename {src/librustc_mir => compiler/rustc_mir/src}/util/storage.rs (100%) create mode 100644 compiler/rustc_mir_build/Cargo.toml rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/block.rs (98%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/cfg.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/expr/as_constant.rs (95%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/expr/as_operand.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/expr/as_place.rs (99%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/expr/as_rvalue.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/expr/as_temp.rs (96%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/expr/category.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/expr/into.rs (99%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/expr/mod.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/expr/stmt.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/into.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/matches/mod.rs (99%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/matches/simplify.rs (99%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/matches/test.rs (99%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/matches/util.rs (91%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/misc.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/mod.rs (99%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/build/scope.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/lib.rs (92%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/lints.rs (97%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/constant.rs (89%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/cx/block.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/cx/expr.rs (96%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/cx/mod.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/cx/to_ref.rs (100%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/mod.rs (98%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/pattern/_match.rs (90%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/pattern/check_match.rs (99%) create mode 100644 compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/pattern/mod.rs (98%) rename {src/librustc_mir_build => compiler/rustc_mir_build/src}/thir/util.rs (97%) create mode 100644 compiler/rustc_parse/Cargo.toml rename {src/librustc_parse => compiler/rustc_parse/src}/lexer/mod.rs (81%) rename {src/librustc_parse => compiler/rustc_parse/src}/lexer/tokentrees.rs (89%) rename {src/librustc_parse => compiler/rustc_parse/src}/lexer/unescape_error_reporting.rs (100%) rename {src/librustc_parse => compiler/rustc_parse/src}/lexer/unicode_chars.rs (99%) rename {src/librustc_parse => compiler/rustc_parse/src}/lib.rs (82%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/attr.rs (99%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/diagnostics.rs (96%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/expr.rs (98%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/generics.rs (100%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/item.rs (96%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/mod.rs (96%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/nonterminal.rs (72%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/pat.rs (99%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/path.rs (98%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/stmt.rs (92%) rename {src/librustc_parse => compiler/rustc_parse/src}/parser/ty.rs (94%) rename {src/librustc_parse => compiler/rustc_parse/src}/validate_attr.rs (100%) create mode 100644 compiler/rustc_parse_format/Cargo.toml rename {src/librustc_parse_format => compiler/rustc_parse_format/src}/lib.rs (98%) rename {src/librustc_parse_format => compiler/rustc_parse_format/src}/tests.rs (100%) create mode 100644 compiler/rustc_passes/Cargo.toml rename {src/librustc_passes => compiler/rustc_passes/src}/check_attr.rs (56%) rename {src/librustc_passes => compiler/rustc_passes/src}/check_const.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/dead.rs (98%) rename {src/librustc_passes => compiler/rustc_passes/src}/diagnostic_items.rs (87%) rename {src/librustc_passes => compiler/rustc_passes/src}/entry.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/hir_id_validator.rs (98%) rename {src/librustc_passes => compiler/rustc_passes/src}/hir_stats.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/intrinsicck.rs (98%) rename {src/librustc_passes => compiler/rustc_passes/src}/lang_items.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/layout_test.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/lib.rs (90%) rename {src/librustc_passes => compiler/rustc_passes/src}/lib_features.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/liveness.rs (79%) rename {src/librustc_passes => compiler/rustc_passes/src}/loops.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/reachable.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/region.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/stability.rs (74%) rename {src/librustc_passes => compiler/rustc_passes/src}/upvars.rs (100%) rename {src/librustc_passes => compiler/rustc_passes/src}/weak_lang_items.rs (95%) create mode 100644 compiler/rustc_plugin_impl/Cargo.toml rename {src/librustc_plugin_impl => compiler/rustc_plugin_impl/src}/build.rs (100%) rename {src/librustc_plugin_impl => compiler/rustc_plugin_impl/src}/lib.rs (89%) rename {src/librustc_plugin_impl => compiler/rustc_plugin_impl/src}/load.rs (100%) create mode 100644 compiler/rustc_privacy/Cargo.toml rename {src/librustc_privacy => compiler/rustc_privacy/src}/lib.rs (99%) create mode 100644 compiler/rustc_query_system/Cargo.toml rename {src/librustc_query_system => compiler/rustc_query_system/src}/cache.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/dep_graph/README.md (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/dep_graph/debug.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/dep_graph/dep_node.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/dep_graph/graph.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/dep_graph/mod.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/dep_graph/prev.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/dep_graph/query.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/dep_graph/serialized.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/lib.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/query/README.md (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/query/caches.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/query/config.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/query/job.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/query/mod.rs (100%) rename {src/librustc_query_system => compiler/rustc_query_system/src}/query/plumbing.rs (100%) create mode 100644 compiler/rustc_resolve/Cargo.toml rename {src/librustc_resolve => compiler/rustc_resolve/src}/build_reduced_graph.rs (99%) rename {src/librustc_resolve => compiler/rustc_resolve/src}/check_unused.rs (99%) rename {src/librustc_resolve => compiler/rustc_resolve/src}/def_collector.rs (100%) rename {src/librustc_resolve => compiler/rustc_resolve/src}/diagnostics.rs (99%) rename {src/librustc_resolve => compiler/rustc_resolve/src}/imports.rs (99%) rename {src/librustc_resolve => compiler/rustc_resolve/src}/late.rs (98%) rename {src/librustc_resolve => compiler/rustc_resolve/src}/late/diagnostics.rs (93%) rename {src/librustc_resolve => compiler/rustc_resolve/src}/late/lifetimes.rs (99%) rename {src/librustc_resolve => compiler/rustc_resolve/src}/lib.rs (97%) rename {src/librustc_resolve => compiler/rustc_resolve/src}/macros.rs (97%) create mode 100644 compiler/rustc_save_analysis/Cargo.toml rename {src/librustc_save_analysis => compiler/rustc_save_analysis/src}/dump_visitor.rs (99%) rename {src/librustc_save_analysis => compiler/rustc_save_analysis/src}/dumper.rs (100%) rename {src/librustc_save_analysis => compiler/rustc_save_analysis/src}/lib.rs (96%) rename {src/librustc_save_analysis => compiler/rustc_save_analysis/src}/sig.rs (99%) rename {src/librustc_save_analysis => compiler/rustc_save_analysis/src}/span_utils.rs (50%) rename {src/librustc_serialize => compiler/rustc_serialize}/Cargo.toml (70%) rename {src/librustc_serialize => compiler/rustc_serialize/src}/collection_impls.rs (100%) rename {src/librustc_serialize => compiler/rustc_serialize/src}/json.rs (100%) rename {src/librustc_serialize => compiler/rustc_serialize/src}/json/tests.rs (100%) rename {src/librustc_serialize => compiler/rustc_serialize/src}/leb128.rs (100%) rename {src/librustc_serialize => compiler/rustc_serialize/src}/lib.rs (83%) rename {src/librustc_serialize => compiler/rustc_serialize/src}/opaque.rs (100%) rename {src/librustc_serialize => compiler/rustc_serialize/src}/serialize.rs (96%) rename {src/librustc_serialize => compiler/rustc_serialize}/tests/json.rs (100%) rename {src/librustc_serialize => compiler/rustc_serialize}/tests/leb128.rs (100%) rename {src/librustc_serialize => compiler/rustc_serialize}/tests/opaque.rs (100%) create mode 100644 compiler/rustc_session/Cargo.toml rename {src/librustc_session => compiler/rustc_session/src}/cgu_reuse_tracker.rs (100%) rename {src/librustc_session => compiler/rustc_session/src}/code_stats.rs (100%) rename {src/librustc_session => compiler/rustc_session/src}/config.rs (95%) rename {src/librustc_session => compiler/rustc_session/src}/filesearch.rs (99%) rename {src/librustc_session => compiler/rustc_session/src}/lib.rs (94%) rename {src/librustc_session => compiler/rustc_session/src}/lint.rs (84%) create mode 100644 compiler/rustc_session/src/lint/builtin.rs rename {src/librustc_session => compiler/rustc_session/src}/options.rs (93%) rename {src/librustc_session => compiler/rustc_session/src}/output.rs (100%) rename {src/librustc_session => compiler/rustc_session/src}/parse.rs (100%) rename {src/librustc_session => compiler/rustc_session/src}/search_paths.rs (81%) rename {src/librustc_session => compiler/rustc_session/src}/session.rs (94%) rename {src/librustc_session => compiler/rustc_session/src}/utils.rs (100%) create mode 100644 compiler/rustc_span/Cargo.toml rename {src/librustc_span => compiler/rustc_span/src}/analyze_source_file.rs (100%) rename {src/librustc_span => compiler/rustc_span/src}/analyze_source_file/tests.rs (100%) rename {src/librustc_span => compiler/rustc_span/src}/caching_source_map_view.rs (100%) rename {src/librustc_span => compiler/rustc_span/src}/def_id.rs (100%) rename {src/librustc_span => compiler/rustc_span/src}/edition.rs (100%) rename {src/librustc_span => compiler/rustc_span/src}/fatal_error.rs (100%) rename {src/librustc_span => compiler/rustc_span/src}/hygiene.rs (99%) rename {src/librustc_span => compiler/rustc_span/src}/lib.rs (95%) rename {src/librustc_span => compiler/rustc_span/src}/source_map.rs (98%) rename {src/librustc_span => compiler/rustc_span/src}/source_map/tests.rs (100%) rename {src/librustc_span => compiler/rustc_span/src}/span_encoding.rs (100%) rename {src/librustc_span => compiler/rustc_span/src}/symbol.rs (99%) rename {src/librustc_span => compiler/rustc_span/src}/symbol/tests.rs (100%) rename {src/librustc_span => compiler/rustc_span/src}/tests.rs (100%) create mode 100644 compiler/rustc_symbol_mangling/Cargo.toml rename {src/librustc_symbol_mangling => compiler/rustc_symbol_mangling/src}/legacy.rs (98%) rename {src/librustc_symbol_mangling => compiler/rustc_symbol_mangling/src}/lib.rs (99%) rename {src/librustc_symbol_mangling => compiler/rustc_symbol_mangling/src}/test.rs (100%) rename {src/librustc_symbol_mangling => compiler/rustc_symbol_mangling/src}/v0.rs (98%) create mode 100644 compiler/rustc_target/Cargo.toml rename {src/librustc_target => compiler/rustc_target}/README.md (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/aarch64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/amdgpu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/arm.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/avr.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/hexagon.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/mips.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/mips64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/mod.rs (97%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/msp430.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/nvptx.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/nvptx64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/powerpc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/powerpc64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/riscv.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/s390x.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/sparc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/sparc64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/wasm32.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/wasm32_bindgen_compat.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/x86.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/x86_64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/call/x86_win64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/abi/mod.rs (97%) rename {src/librustc_target => compiler/rustc_target/src}/asm/aarch64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/asm/arm.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/asm/hexagon.rs (100%) create mode 100644 compiler/rustc_target/src/asm/mips.rs rename {src/librustc_target => compiler/rustc_target/src}/asm/mod.rs (94%) rename {src/librustc_target => compiler/rustc_target/src}/asm/nvptx.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/asm/riscv.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/asm/x86.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/lib.rs (92%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_apple_darwin.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_apple_ios.rs (93%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_apple_tvos.rs (90%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_fuchsia.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_linux_android.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_pc_windows_msvc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_cloudabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_freebsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_hermit.rs (73%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_netbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_none.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_none_softfloat.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_openbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_unknown_redox.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_uwp_windows_msvc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/aarch64_wrs_vxworks.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/abi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/abi/tests.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/android_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/apple_base.rs (100%) create mode 100644 compiler/rustc_target/src/spec/apple_sdk_base.rs rename {src/librustc_target => compiler/rustc_target/src}/spec/arm_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/arm_linux_androideabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/arm_unknown_linux_gnueabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/arm_unknown_linux_gnueabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/arm_unknown_linux_musleabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/arm_unknown_linux_musleabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armebv7r_none_eabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armebv7r_none_eabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv4t_unknown_linux_gnueabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv5te_unknown_linux_gnueabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv5te_unknown_linux_musleabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv6_unknown_freebsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv6_unknown_netbsd_eabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_apple_ios.rs (89%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_linux_androideabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_unknown_cloudabi_eabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_unknown_freebsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_unknown_linux_gnueabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_unknown_linux_gnueabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_unknown_linux_musleabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_unknown_linux_musleabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_unknown_netbsd_eabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7_wrs_vxworks_eabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7a_none_eabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7a_none_eabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7r_none_eabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7r_none_eabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/armv7s_apple_ios.rs (89%) rename {src/librustc_target => compiler/rustc_target/src}/spec/asmjs_unknown_emscripten.rs (100%) create mode 100644 compiler/rustc_target/src/spec/avr_gnu_base.rs create mode 100644 compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs rename {src/librustc_target => compiler/rustc_target/src}/spec/cloudabi_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/crt_objects.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/dragonfly_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/freebsd_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/fuchsia_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/haiku_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/hermit_base.rs (88%) rename {src/librustc_target => compiler/rustc_target/src}/spec/hermit_kernel_base.rs (88%) rename {src/librustc_target => compiler/rustc_target/src}/spec/hexagon_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i386_apple_ios.rs (88%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i586_pc_windows_msvc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i586_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i586_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_apple_darwin.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_linux_android.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_pc_windows_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_pc_windows_msvc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_unknown_cloudabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_unknown_freebsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_unknown_haiku.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_unknown_netbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_unknown_openbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_unknown_uefi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_uwp_windows_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_uwp_windows_msvc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/i686_wrs_vxworks.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/illumos_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/l4re_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/linux_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/linux_kernel_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/linux_musl_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mips64_unknown_linux_gnuabi64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mips64_unknown_linux_muslabi64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mips64el_unknown_linux_gnuabi64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mips64el_unknown_linux_muslabi64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mips_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mips_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mips_unknown_linux_uclibc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mipsel_sony_psp.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mipsel_sony_psp_linker_script.ld (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mipsel_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mipsel_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mipsel_unknown_linux_uclibc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mipsisa32r6_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mipsisa32r6el_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mipsisa64r6_unknown_linux_gnuabi64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/mod.rs (99%) rename {src/librustc_target => compiler/rustc_target/src}/spec/msp430_none_elf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/msvc_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/netbsd_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/nvptx64_nvidia_cuda.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/openbsd_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc64_unknown_freebsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc64_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc64_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc64_wrs_vxworks.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc64le_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc64le_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc_unknown_linux_gnuspe.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc_unknown_netbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc_wrs_vxworks.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/powerpc_wrs_vxworks_spe.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/redox_base.rs (100%) create mode 100644 compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs rename {src/librustc_target => compiler/rustc_target/src}/spec/riscv32i_unknown_none_elf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/riscv32imac_unknown_none_elf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/riscv32imc_unknown_none_elf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/riscv64gc_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/riscv64gc_unknown_none_elf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/riscv64imac_unknown_none_elf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/riscv_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/s390x_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/solaris_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/sparc64_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/sparc64_unknown_netbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/sparc64_unknown_openbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/sparc_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/sparcv9_sun_solaris.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/tests/tests_impl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumb_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv4t_none_eabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv6m_none_eabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv7a_pc_windows_msvc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv7a_uwp_windows_msvc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv7em_none_eabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv7em_none_eabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv7m_none_eabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv7neon_linux_androideabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv7neon_unknown_linux_gnueabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv7neon_unknown_linux_musleabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv8m_base_none_eabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv8m_main_none_eabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/thumbv8m_main_none_eabihf.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/uefi_msvc_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/vxworks_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/wasm32_base.rs (99%) rename {src/librustc_target => compiler/rustc_target/src}/spec/wasm32_unknown_emscripten.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/wasm32_unknown_unknown.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/wasm32_wasi.rs (98%) rename {src/librustc_target => compiler/rustc_target/src}/spec/windows_gnu_base.rs (94%) rename {src/librustc_target => compiler/rustc_target/src}/spec/windows_msvc_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/windows_uwp_gnu_base.rs (98%) rename {src/librustc_target => compiler/rustc_target/src}/spec/windows_uwp_msvc_base.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_apple_darwin.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_apple_ios.rs (87%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_apple_ios_macabi.rs (87%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_apple_tvos.rs (87%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_fortanix_unknown_sgx.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_fuchsia.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_linux_android.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_linux_kernel.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_pc_windows_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_pc_windows_msvc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_rumprun_netbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_sun_solaris.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_cloudabi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_dragonfly.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_freebsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_haiku.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_hermit.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_hermit_kernel.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_illumos.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_l4re_uclibc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_linux_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_linux_gnux32.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_linux_musl.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_netbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_openbsd.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_redox.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_unknown_uefi.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_uwp_windows_gnu.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_uwp_windows_msvc.rs (100%) rename {src/librustc_target => compiler/rustc_target/src}/spec/x86_64_wrs_vxworks.rs (100%) create mode 100644 compiler/rustc_trait_selection/Cargo.toml rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/autoderef.rs (97%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/infer.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/lib.rs (86%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/opaque_types.rs (99%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/auto_trait.rs (98%) create mode 100644 compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/codegen/mod.rs (96%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/coherence.rs (99%) create mode 100644 compiler/rustc_trait_selection/src/traits/const_evaluatable.rs rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/engine.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/error_reporting/mod.rs (96%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/error_reporting/on_unimplemented.rs (98%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/error_reporting/suggestions.rs (99%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/fulfill.rs (90%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/misc.rs (97%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/mod.rs (95%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/object_safety.rs (97%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/on_unimplemented.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/project.rs (97%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/dropck_outlives.rs (99%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/evaluate_obligation.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/method_autoderef.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/mod.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/normalize.rs (98%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/outlives_bounds.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/type_op/ascribe_user_type.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/type_op/custom.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/type_op/eq.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/type_op/implied_outlives_bounds.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/type_op/mod.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/type_op/normalize.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/type_op/outlives.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/type_op/prove_predicate.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/query/type_op/subtype.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/select/candidate_assembly.rs (77%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/select/confirmation.rs (96%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/select/mod.rs (86%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/specialize/mod.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/specialize/specialization_graph.rs (98%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/structural_match.rs (99%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/util.rs (100%) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/wf.rs (96%) create mode 100644 compiler/rustc_traits/Cargo.toml rename {src/librustc_traits => compiler/rustc_traits/src}/chalk/db.rs (57%) rename {src/librustc_traits => compiler/rustc_traits/src}/chalk/lowering.rs (59%) create mode 100644 compiler/rustc_traits/src/chalk/mod.rs rename {src/librustc_traits => compiler/rustc_traits/src}/dropck_outlives.rs (99%) rename {src/librustc_traits => compiler/rustc_traits/src}/evaluate_obligation.rs (100%) rename {src/librustc_traits => compiler/rustc_traits/src}/implied_outlives_bounds.rs (98%) rename {src/librustc_traits => compiler/rustc_traits/src}/lib.rs (97%) rename {src/librustc_traits => compiler/rustc_traits/src}/normalize_erasing_regions.rs (95%) rename {src/librustc_traits => compiler/rustc_traits/src}/normalize_projection_ty.rs (100%) rename {src/librustc_traits => compiler/rustc_traits/src}/type_op.rs (100%) create mode 100644 compiler/rustc_ty/Cargo.toml rename {src/librustc_ty => compiler/rustc_ty/src}/common_traits.rs (100%) rename {src/librustc_ty => compiler/rustc_ty/src}/instance.rs (93%) rename {src/librustc_ty => compiler/rustc_ty/src}/lib.rs (84%) rename {src/librustc_ty => compiler/rustc_ty/src}/needs_drop.rs (98%) rename {src/librustc_ty => compiler/rustc_ty/src}/ty.rs (79%) create mode 100644 compiler/rustc_typeck/Cargo.toml rename {src/librustc_typeck => compiler/rustc_typeck}/README.md (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/astconv/errors.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/astconv/generics.rs (90%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/astconv/mod.rs (97%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/bounds.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/_match.rs (81%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/autoderef.rs (74%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/callee.rs (98%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/cast.rs (98%) create mode 100644 compiler/rustc_typeck/src/check/check.rs rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/closure.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/coercion.rs (96%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/compare_method.rs (98%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/demand.rs (97%) create mode 100644 compiler/rustc_typeck/src/check/diverges.rs rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/dropck.rs (99%) create mode 100644 compiler/rustc_typeck/src/check/expectation.rs rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/expr.rs (88%) rename src/librustc_typeck/check/mod.rs => compiler/rustc_typeck/src/check/fn_ctxt.rs (52%) create mode 100644 compiler/rustc_typeck/src/check/gather_locals.rs rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/generator_interior.rs (100%) create mode 100644 compiler/rustc_typeck/src/check/inherited.rs rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/intrinsic.rs (93%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/method/confirm.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/method/mod.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/method/probe.rs (98%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/method/suggest.rs (95%) create mode 100644 compiler/rustc_typeck/src/check/mod.rs rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/op.rs (97%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/pat.rs (86%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/place_op.rs (89%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/regionck.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/upvar.rs (92%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/wfcheck.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check/writeback.rs (97%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/check_unused.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/coherence/builtin.rs (95%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/coherence/inherent_impls.rs (93%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/coherence/inherent_impls_overlap.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/coherence/mod.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/coherence/orphan.rs (95%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/coherence/unsafety.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/collect.rs (94%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/collect/type_of.rs (98%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/constrained_generic_params.rs (99%) create mode 100644 compiler/rustc_typeck/src/errors.rs rename {src/librustc_typeck => compiler/rustc_typeck/src}/expr_use_visitor.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/impl_wf_check.rs (95%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/impl_wf_check/min_specialization.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/lib.rs (98%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/mem_categorization.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/outlives/explicit.rs (94%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/outlives/implicit_infer.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/outlives/mod.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/outlives/test.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/outlives/utils.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/structured_errors.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/variance/constraints.rs (99%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/variance/mod.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/variance/solve.rs (98%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/variance/terms.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/variance/test.rs (100%) rename {src/librustc_typeck => compiler/rustc_typeck/src}/variance/xform.rs (100%) create mode 100644 library/alloc/benches/binary_heap.rs create mode 100644 library/alloc/src/collections/btree/borrow.rs create mode 100644 library/alloc/src/collections/btree/borrow/tests.rs create mode 100644 library/core/src/num/error.rs create mode 100644 library/core/src/num/nonzero.rs rename library/core/src/num/{ => shells}/i128.rs (100%) rename library/core/src/num/{ => shells}/i16.rs (100%) rename library/core/src/num/{ => shells}/i32.rs (100%) rename library/core/src/num/{ => shells}/i64.rs (100%) rename library/core/src/num/{ => shells}/i8.rs (100%) create mode 100644 library/core/src/num/shells/int_macros.rs rename library/core/src/num/{ => shells}/isize.rs (100%) rename library/core/src/num/{ => shells}/u128.rs (100%) rename library/core/src/num/{ => shells}/u16.rs (100%) rename library/core/src/num/{ => shells}/u32.rs (100%) rename library/core/src/num/{ => shells}/u64.rs (100%) rename library/core/src/num/{ => shells}/u8.rs (100%) rename library/core/src/num/{ => shells}/usize.rs (100%) create mode 100644 library/core/src/num/uint_macros.rs create mode 100644 library/core/src/ops/control_flow.rs create mode 100644 library/core/src/slice/ascii.rs create mode 100644 library/core/src/slice/cmp.rs create mode 100644 library/core/src/slice/index.rs create mode 100644 library/core/src/slice/iter.rs create mode 100644 library/core/src/slice/iter/macros.rs create mode 100644 library/core/src/slice/raw.rs create mode 100644 library/core/src/str/converts.rs create mode 100644 library/core/src/str/error.rs create mode 100644 library/core/src/str/iter.rs create mode 100644 library/core/src/str/traits.rs create mode 100644 library/core/src/str/validations.rs create mode 100644 library/core/tests/num/wrapping.rs create mode 100644 library/core/tests/pin.rs create mode 100644 library/std/src/backtrace/tests.rs create mode 100644 library/std/src/collections/hash/map/tests.rs create mode 100644 library/std/src/collections/hash/set/tests.rs create mode 100644 library/std/src/env/tests.rs create mode 100644 library/std/src/error/tests.rs create mode 100644 library/std/src/f32/tests.rs create mode 100644 library/std/src/f64/tests.rs create mode 100644 library/std/src/ffi/c_str/tests.rs create mode 100644 library/std/src/ffi/os_str/tests.rs create mode 100644 library/std/src/fs/tests.rs create mode 100644 library/std/src/io/buffered/tests.rs create mode 100644 library/std/src/io/cursor/tests.rs create mode 100644 library/std/src/io/error/tests.rs create mode 100644 library/std/src/io/impls/tests.rs delete mode 100644 library/std/src/io/lazy.rs create mode 100644 library/std/src/io/stdio/tests.rs create mode 100644 library/std/src/io/tests.rs create mode 100644 library/std/src/io/util/tests.rs create mode 100644 library/std/src/lazy/tests.rs create mode 100644 library/std/src/memchr/tests.rs create mode 100644 library/std/src/net/addr/tests.rs create mode 100644 library/std/src/net/ip/tests.rs create mode 100644 library/std/src/net/parser/tests.rs create mode 100644 library/std/src/net/tcp/tests.rs create mode 100644 library/std/src/net/udp/tests.rs create mode 100644 library/std/src/num/benches.rs create mode 100644 library/std/src/num/tests.rs create mode 100644 library/std/src/os/raw/tests.rs rename src/test/ui/panics/panic-safe.rs => library/std/src/panic/tests.rs (77%) create mode 100644 library/std/src/path/tests.rs create mode 100644 library/std/src/process/tests.rs create mode 100644 library/std/src/sync/barrier/tests.rs create mode 100644 library/std/src/sync/condvar/tests.rs create mode 100644 library/std/src/sync/mpsc/mpsc_queue/tests.rs create mode 100644 library/std/src/sync/mpsc/spsc_queue/tests.rs create mode 100644 library/std/src/sync/mpsc/sync_tests.rs create mode 100644 library/std/src/sync/mpsc/tests.rs create mode 100644 library/std/src/sync/mutex/tests.rs create mode 100644 library/std/src/sync/once/tests.rs create mode 100644 library/std/src/sync/rwlock/tests.rs create mode 100644 library/std/src/sys/sgx/abi/tls/sync_bitset.rs create mode 100644 library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs delete mode 100644 library/std/src/sys/sgx/fs.rs delete mode 100644 library/std/src/sys/sgx/io.rs delete mode 100644 library/std/src/sys/sgx/pipe.rs delete mode 100644 library/std/src/sys/sgx/process.rs create mode 100644 library/std/src/sys/sgx/rwlock/tests.rs create mode 100644 library/std/src/sys/sgx/waitqueue/spin_mutex.rs create mode 100644 library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs create mode 100644 library/std/src/sys/sgx/waitqueue/tests.rs create mode 100644 library/std/src/sys/sgx/waitqueue/unsafe_list.rs create mode 100644 library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs create mode 100644 library/std/src/sys/unix/ext/net/tests.rs create mode 100644 library/std/src/sys/unix/ext/ucred.rs create mode 100644 library/std/src/sys/unix/ext/ucred/tests.rs create mode 100644 library/std/src/sys/unix/fd/tests.rs create mode 100644 library/std/src/sys/unix/futex.rs create mode 100644 library/std/src/sys/unix/os/tests.rs create mode 100644 library/std/src/sys/unix/process/process_common/tests.rs delete mode 100644 library/std/src/sys/unsupported/path.rs create mode 100644 library/std/src/sys/vxworks/net/tests.rs delete mode 100644 library/std/src/sys/wasi/alloc.rs delete mode 100644 library/std/src/sys/wasi/path.rs delete mode 100644 library/std/src/sys/wasi/pipe.rs delete mode 100644 library/std/src/sys/wasi/process.rs create mode 100644 library/std/src/sys/windows/args/tests.rs create mode 100644 library/std/src/sys/windows/os/tests.rs create mode 100644 library/std/src/sys/windows/process/tests.rs create mode 100644 library/std/src/sys_common/bytestring/tests.rs create mode 100644 library/std/src/sys_common/net/tests.rs create mode 100644 library/std/src/sys_common/remutex/tests.rs create mode 100644 library/std/src/sys_common/tests.rs create mode 100644 library/std/src/sys_common/thread_local_key/tests.rs create mode 100644 library/std/src/sys_common/thread_parker/futex.rs create mode 100644 library/std/src/sys_common/thread_parker/generic.rs create mode 100644 library/std/src/sys_common/thread_parker/mod.rs create mode 100644 library/std/src/sys_common/wtf8/tests.rs create mode 100644 library/std/src/thread/local/dynamic_tests.rs create mode 100644 library/std/src/thread/local/tests.rs create mode 100644 library/std/src/thread/tests.rs create mode 100644 library/std/src/time/tests.rs create mode 100644 library/stdarch/crates/core_arch/avx512f.md create mode 100644 library/stdarch/crates/core_arch/src/aarch64/prefetch.rs delete mode 100644 library/stdarch/crates/core_arch/src/x86/mmx.rs create mode 100644 src/bootstrap/CHANGELOG.md create mode 100644 src/bootstrap/build.rs create mode 100644 src/bootstrap/defaults/README.md create mode 100644 src/bootstrap/defaults/config.toml.codegen create mode 100644 src/bootstrap/defaults/config.toml.compiler create mode 100644 src/bootstrap/defaults/config.toml.library create mode 100644 src/bootstrap/defaults/config.toml.user create mode 100644 src/bootstrap/setup.rs delete mode 100644 src/ci/azure-pipelines/steps/run.yml delete mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh delete mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh delete mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh delete mode 100644 src/doc/rust-by-example/src/crates/link.md create mode 100644 src/doc/rust-by-example/src/crates/using_lib.md create mode 100644 src/doc/rustdoc/src/linking-to-items-by-name.md create mode 100644 src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md create mode 100644 src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md delete mode 100644 src/doc/unstable-book/src/language-features/doc-alias.md create mode 100644 src/doc/unstable-book/src/library-features/slice-check-range.md delete mode 100644 src/librustc_ast/Cargo.toml delete mode 100644 src/librustc_ast_lowering/Cargo.toml delete mode 100644 src/librustc_ast_passes/Cargo.toml delete mode 100644 src/librustc_ast_pretty/Cargo.toml delete mode 100644 src/librustc_attr/Cargo.toml delete mode 100644 src/librustc_builtin_macros/Cargo.toml delete mode 100644 src/librustc_codegen_llvm/Cargo.toml delete mode 100644 src/librustc_codegen_ssa/Cargo.toml delete mode 100644 src/librustc_codegen_ssa/traits/declare.rs delete mode 100644 src/librustc_data_structures/jobserver.rs delete mode 100644 src/librustc_driver/Cargo.toml delete mode 100644 src/librustc_error_codes/error_codes/E0019.md delete mode 100644 src/librustc_error_codes/error_codes/E0433.md delete mode 100644 src/librustc_expand/Cargo.toml delete mode 100644 src/librustc_expand/parse/lexer/tests.rs delete mode 100644 src/librustc_feature/Cargo.toml delete mode 100644 src/librustc_hir/Cargo.toml delete mode 100644 src/librustc_hir_pretty/Cargo.toml delete mode 100644 src/librustc_incremental/Cargo.toml delete mode 100644 src/librustc_infer/Cargo.toml delete mode 100644 src/librustc_interface/Cargo.toml delete mode 100644 src/librustc_lexer/src/tests.rs delete mode 100644 src/librustc_lint/Cargo.toml delete mode 100644 src/librustc_metadata/Cargo.toml delete mode 100644 src/librustc_middle/Cargo.toml delete mode 100644 src/librustc_middle/ty/print/obsolete.rs delete mode 100644 src/librustc_mir/Cargo.toml delete mode 100644 src/librustc_mir/transform/check_consts/mod.rs delete mode 100644 src/librustc_mir/transform/check_consts/ops.rs delete mode 100644 src/librustc_mir/transform/instcombine.rs delete mode 100644 src/librustc_mir/transform/instrument_coverage.rs delete mode 100644 src/librustc_mir/transform/qualify_min_const_fn.rs delete mode 100644 src/librustc_mir_build/Cargo.toml delete mode 100644 src/librustc_mir_build/thir/pattern/const_to_pat.rs delete mode 100644 src/librustc_parse/Cargo.toml delete mode 100644 src/librustc_parse_format/Cargo.toml delete mode 100644 src/librustc_passes/Cargo.toml delete mode 100644 src/librustc_plugin_impl/Cargo.toml delete mode 100644 src/librustc_privacy/Cargo.toml delete mode 100644 src/librustc_query_system/Cargo.toml delete mode 100644 src/librustc_resolve/Cargo.toml delete mode 100644 src/librustc_save_analysis/Cargo.toml delete mode 100644 src/librustc_session/Cargo.toml delete mode 100644 src/librustc_session/lint/builtin.rs delete mode 100644 src/librustc_span/Cargo.toml delete mode 100644 src/librustc_symbol_mangling/Cargo.toml delete mode 100644 src/librustc_target/Cargo.toml delete mode 100644 src/librustc_target/spec/apple_sdk_base.rs delete mode 100644 src/librustc_target/spec/avr_unknown_unknown.rs delete mode 100644 src/librustc_target/spec/freestanding_base.rs delete mode 100644 src/librustc_trait_selection/Cargo.toml delete mode 100644 src/librustc_trait_selection/traits/chalk_fulfill.rs delete mode 100644 src/librustc_traits/Cargo.toml delete mode 100644 src/librustc_traits/chalk/mod.rs delete mode 100644 src/librustc_ty/Cargo.toml delete mode 100644 src/librustc_typeck/Cargo.toml rename src/librustdoc/{test.rs => doctest.rs} (99%) rename src/librustdoc/{test => doctest}/tests.rs (100%) create mode 100644 src/librustdoc/html/highlight/fixtures/sample.html create mode 100644 src/librustdoc/html/highlight/fixtures/sample.rs create mode 100644 src/librustdoc/html/static/favicon-16x16.png create mode 100644 src/librustdoc/html/static/favicon-32x32.png delete mode 100644 src/librustdoc/html/static/favicon.ico create mode 100644 src/librustdoc/html/static/favicon.svg create mode 100644 src/test/assembly/asm/mips-types.rs create mode 100644 src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs create mode 100644 src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs create mode 100644 src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs create mode 100644 src/test/codegen/enum-bounds-check-derived-idx.rs create mode 100644 src/test/codegen/enum-bounds-check-issue-13926.rs create mode 100644 src/test/codegen/issue-27130.rs create mode 100644 src/test/codegen/issue-34634.rs create mode 100644 src/test/codegen/issue-73396-bounds-check-after-position.rs create mode 100644 src/test/codegen/issue-75659.rs create mode 100644 src/test/codegen/return-value-in-reg.rs create mode 100644 src/test/codegen/tuple-layout-opt.rs delete mode 100644 src/test/codegen/x86_mmx.rs create mode 100644 src/test/codegen/zst-offset.rs create mode 100644 src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff create mode 100644 src/test/mir-opt/76803_regression.rs rename src/test/mir-opt/{array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit => array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir} (96%) rename src/test/mir-opt/{array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit => array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir} (96%) rename src/test/mir-opt/{combine_array_len.norm2.InstCombine.diff.64bit => combine_array_len.norm2.InstCombine.32bit.diff} (94%) rename src/test/mir-opt/{combine_array_len.norm2.InstCombine.diff.32bit => combine_array_len.norm2.InstCombine.64bit.diff} (94%) rename src/test/mir-opt/{const_allocation.main.ConstProp.after.mir.32bit => const_allocation.main.ConstProp.after.32bit.mir} (76%) rename src/test/mir-opt/{const_allocation.main.ConstProp.after.mir.64bit => const_allocation.main.ConstProp.after.64bit.mir} (76%) rename src/test/mir-opt/{const_allocation2.main.ConstProp.after.mir.32bit => const_allocation2.main.ConstProp.after.32bit.mir} (77%) rename src/test/mir-opt/{const_allocation2.main.ConstProp.after.mir.64bit => const_allocation2.main.ConstProp.after.64bit.mir} (75%) rename src/test/mir-opt/{const_allocation3.main.ConstProp.after.mir.32bit => const_allocation3.main.ConstProp.after.32bit.mir} (100%) rename src/test/mir-opt/{const_allocation3.main.ConstProp.after.mir.64bit => const_allocation3.main.ConstProp.after.64bit.mir} (100%) rename src/test/mir-opt/const_prop/{array_index.main.ConstProp.diff.32bit => array_index.main.ConstProp.32bit.diff} (86%) rename src/test/mir-opt/const_prop/{array_index.main.ConstProp.diff.64bit => array_index.main.ConstProp.64bit.diff} (86%) rename src/test/mir-opt/const_prop/{bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit => bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff} (89%) rename src/test/mir-opt/const_prop/{bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit => bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff} (89%) rename src/test/mir-opt/const_prop/{discriminant.main.ConstProp.diff.32bit => discriminant.main.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/const_prop/{discriminant.main.ConstProp.diff.64bit => discriminant.main.ConstProp.64bit.diff} (100%) rename src/test/mir-opt/const_prop/{large_array_index.main.ConstProp.diff.32bit => large_array_index.main.ConstProp.32bit.diff} (86%) rename src/test/mir-opt/const_prop/{large_array_index.main.ConstProp.diff.64bit => large_array_index.main.ConstProp.64bit.diff} (86%) rename src/test/mir-opt/const_prop/{optimizes_into_variable.main.ConstProp.diff.32bit => optimizes_into_variable.main.ConstProp.32bit.diff} (89%) rename src/test/mir-opt/const_prop/{optimizes_into_variable.main.ConstProp.diff.64bit => optimizes_into_variable.main.ConstProp.64bit.diff} (89%) rename src/test/mir-opt/const_prop/{optimizes_into_variable.main.SimplifyLocals.after.mir.32bit => optimizes_into_variable.main.SimplifyLocals.after.32bit.mir} (100%) rename src/test/mir-opt/const_prop/{optimizes_into_variable.main.SimplifyLocals.after.mir.64bit => optimizes_into_variable.main.SimplifyLocals.after.64bit.mir} (100%) rename src/test/mir-opt/const_prop/{repeat.main.ConstProp.diff.32bit => repeat.main.ConstProp.32bit.diff} (88%) rename src/test/mir-opt/const_prop/{repeat.main.ConstProp.diff.64bit => repeat.main.ConstProp.64bit.diff} (88%) rename src/test/mir-opt/const_prop/{slice_len.main.ConstProp.diff.32bit => slice_len.main.ConstProp.32bit.diff} (87%) rename src/test/mir-opt/const_prop/{slice_len.main.ConstProp.diff.64bit => slice_len.main.ConstProp.64bit.diff} (87%) create mode 100644 src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff create mode 100644 src/test/mir-opt/dest-prop/branch.rs create mode 100644 src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff create mode 100644 src/test/mir-opt/dest-prop/cycle.rs create mode 100644 src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff create mode 100644 src/test/mir-opt/dest-prop/simple.rs create mode 100644 src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff create mode 100644 src/test/mir-opt/dest-prop/union.rs create mode 100644 src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch.rs create mode 100644 src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs create mode 100644 src/test/mir-opt/early_otherwise_branch_68867.rs create mode 100644 src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff create mode 100644 src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.rs create mode 100644 src/test/mir-opt/equal_true.opt.InstCombine.diff create mode 100644 src/test/mir-opt/equal_true.rs rename src/test/mir-opt/{generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir => generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir} (95%) rename src/test/mir-opt/{generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir => generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir} (97%) rename src/test/mir-opt/{generator_tiny.main-{{closure}}.generator_resume.0.mir => generator_tiny.main-{closure#0}.generator_resume.0.mir} (95%) create mode 100644 src/test/mir-opt/graphviz.main.mir_map.0.dot.mir create mode 100644 src/test/mir-opt/if-condition-int.rs create mode 100644 src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff create mode 100644 src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff create mode 100644 src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff create mode 100644 src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff create mode 100644 src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff create mode 100644 src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff create mode 100644 src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff create mode 100644 src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff create mode 100644 src/test/mir-opt/inline/inline-async.rs create mode 100644 src/test/mir-opt/inline/inline-compatibility.rs create mode 100644 src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff create mode 100644 src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff create mode 100644 src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff create mode 100644 src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff rename src/test/mir-opt/inline/{inline_into_box_place.main.Inline.diff.32bit => inline_into_box_place.main.Inline.32bit.diff} (89%) rename src/test/mir-opt/inline/{inline_into_box_place.main.Inline.diff.64bit => inline_into_box_place.main.Inline.64bit.diff} (89%) create mode 100644 src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff create mode 100644 src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff create mode 100644 src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff create mode 100644 src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff create mode 100644 src/test/mir-opt/inst_combine_deref.rs create mode 100644 src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff rename src/test/mir-opt/{issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit => issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir} (69%) rename src/test/mir-opt/{issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit => issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir} (69%) rename src/test/mir-opt/{issue_72181.bar.mir_map.0.mir.32bit => issue_72181.bar.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{issue_72181.bar.mir_map.0.mir.64bit => issue_72181.bar.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{issue_72181.foo.mir_map.0.mir.32bit => issue_72181.foo.mir_map.0.32bit.mir} (88%) rename src/test/mir-opt/{issue_72181.foo.mir_map.0.mir.64bit => issue_72181.foo.mir_map.0.64bit.mir} (88%) rename src/test/mir-opt/{issue_72181.main.mir_map.0.mir.32bit => issue_72181.main.mir_map.0.32bit.mir} (95%) rename src/test/mir-opt/{issue_72181.main.mir_map.0.mir.64bit => issue_72181.main.mir_map.0.64bit.mir} (95%) rename src/test/mir-opt/{issue_73223.main.PreCodegen.diff.64bit => issue_73223.main.PreCodegen.32bit.diff} (56%) rename src/test/mir-opt/{issue_73223.main.PreCodegen.diff.32bit => issue_73223.main.PreCodegen.64bit.diff} (56%) rename src/test/mir-opt/{issue_73223.main.SimplifyArmIdentity.diff.64bit => issue_73223.main.SimplifyArmIdentity.32bit.diff} (92%) rename src/test/mir-opt/{issue_73223.main.SimplifyArmIdentity.diff.32bit => issue_73223.main.SimplifyArmIdentity.64bit.diff} (92%) create mode 100644 src/test/mir-opt/issue_76432.rs create mode 100644 src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff create mode 100644 src/test/mir-opt/issues/issue-75439.rs create mode 100644 src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff rename src/test/mir-opt/{matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit => matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff} (70%) rename src/test/mir-opt/{matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit => matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff} (70%) rename src/test/mir-opt/{matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit => matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff} (77%) rename src/test/mir-opt/{matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit => matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff} (77%) rename src/test/mir-opt/{matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit => matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff} (100%) rename src/test/mir-opt/{matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit => matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff} (100%) rename src/test/mir-opt/{matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit => matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff} (100%) rename src/test/mir-opt/{matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit => matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff} (100%) create mode 100644 src/test/mir-opt/multiple_return_terminators.rs create mode 100644 src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff rename src/test/mir-opt/nll/{region_subtyping_basic.main.nll.0.mir.32bit => region_subtyping_basic.main.nll.0.32bit.mir} (97%) rename src/test/mir-opt/nll/{region_subtyping_basic.main.nll.0.mir.64bit => region_subtyping_basic.main.nll.0.64bit.mir} (97%) create mode 100644 src/test/mir-opt/not_equal_false.opt.InstCombine.diff create mode 100644 src/test/mir-opt/not_equal_false.rs rename src/test/mir-opt/{packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit => packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir} (100%) rename src/test/mir-opt/{packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit => packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir} (100%) create mode 100644 src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.rs rename src/test/mir-opt/{retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir => retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir} (88%) rename src/test/mir-opt/{retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir => retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir} (100%) rename src/test/mir-opt/{retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir => retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir} (100%) create mode 100644 src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff rename src/test/mir-opt/{simple_match.match_bool.mir_map.0.mir.32bit => simple_match.match_bool.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{simple_match.match_bool.mir_map.0.mir.64bit => simple_match.match_bool.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit => simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff} (100%) rename src/test/mir-opt/{simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit => simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff} (100%) rename src/test/mir-opt/{simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit => simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff} (56%) rename src/test/mir-opt/{simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit => simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff} (56%) create mode 100644 src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff rename src/test/mir-opt/{simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff => simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff} (88%) rename src/test/mir-opt/{slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.64bit => slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir} (97%) rename src/test/mir-opt/{slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.32bit => slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir} (97%) create mode 100644 src/test/mir-opt/spanview-block.rs create mode 100644 src/test/mir-opt/spanview-statement.rs create mode 100644 src/test/mir-opt/spanview-terminator.rs create mode 100644 src/test/mir-opt/spanview_block.main.mir_map.0.html create mode 100644 src/test/mir-opt/spanview_block.main.mir_map.0.html.mir create mode 100644 src/test/mir-opt/spanview_statement.main.mir_map.0.html create mode 100644 src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir create mode 100644 src/test/mir-opt/spanview_terminator.main.mir_map.0.html create mode 100644 src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir rename src/test/mir-opt/{unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit => unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir} (85%) rename src/test/mir-opt/{unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit => unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir} (85%) rename src/test/mir-opt/{unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.32bit => unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.64bit => unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit => unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir} (84%) rename src/test/mir-opt/{unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit => unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir} (84%) rename src/test/mir-opt/{unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.32bit => unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.64bit => unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{while_let_loops.change_loop_body.ConstProp.diff.32bit => while_let_loops.change_loop_body.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/{while_let_loops.change_loop_body.ConstProp.diff.64bit => while_let_loops.change_loop_body.ConstProp.64bit.diff} (100%) rename src/test/mir-opt/{while_let_loops.change_loop_body.PreCodegen.after.mir.32bit => while_let_loops.change_loop_body.PreCodegen.after.32bit.mir} (100%) rename src/test/mir-opt/{while_let_loops.change_loop_body.PreCodegen.after.mir.64bit => while_let_loops.change_loop_body.PreCodegen.after.64bit.mir} (100%) create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json rename src/test/run-make-fulldeps/{instrument-coverage => instrument-coverage-cov-reports-base}/prettify_json.py (100%) create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile create mode 100644 src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/filecheck.testprog.txt rename src/test/run-make-fulldeps/{instrument-coverage => instrument-coverage-llvm-ir-base}/testprog.rs (100%) create mode 100644 src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/instrument-coverage/Makefile create mode 100644 src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir create mode 100644 src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/coverage_tools.mk delete mode 100644 src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json delete mode 100644 src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt delete mode 100644 src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks create mode 100644 src/test/rustdoc-ui/doc-alias-assoc-const.rs create mode 100644 src/test/rustdoc-ui/doc-alias-assoc-const.stderr create mode 100644 src/test/rustdoc-ui/intra-link-double-anchor.rs create mode 100644 src/test/rustdoc-ui/intra-link-double-anchor.stderr create mode 100644 src/test/rustdoc-ui/intra-link-errors.rs create mode 100644 src/test/rustdoc-ui/intra-link-errors.stderr create mode 100644 src/test/rustdoc-ui/private-doc-test.rs create mode 100644 src/test/rustdoc-ui/unknown-renamed-lints.rs create mode 100644 src/test/rustdoc-ui/unknown-renamed-lints.stderr create mode 100644 src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs create mode 100644 src/test/rustdoc/auxiliary/intra-link-pub-use.rs create mode 100644 src/test/rustdoc/const-generics/type-alias.rs create mode 100644 src/test/rustdoc/intra-doc-link-private.rs create mode 100644 src/test/rustdoc/intra-link-cross-crate-crate.rs create mode 100644 src/test/rustdoc/intra-link-disambiguators-removed.rs create mode 100644 src/test/rustdoc/intra-link-prim-assoc.rs create mode 100644 src/test/rustdoc/intra-link-pub-use.rs create mode 100644 src/test/rustdoc/issue-76501.rs create mode 100644 src/test/rustdoc/plain-text-summaries.rs create mode 100644 src/test/rustdoc/trait-impl.rs create mode 100644 src/test/ui-fulldeps/auxiliary/proc-macro-panic.rs create mode 100644 src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs create mode 100644 src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr create mode 100644 src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.rs create mode 100644 src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr create mode 100644 src/test/ui-fulldeps/session-derive-errors.rs create mode 100644 src/test/ui-fulldeps/session-derive-errors.stderr delete mode 100644 src/test/ui/array-slice-vec/arr_cycle.rs delete mode 100644 src/test/ui/array-slice-vec/slice-2.rs delete mode 100644 src/test/ui/array-slice-vec/vec-concat.rs delete mode 100644 src/test/ui/array-slice-vec/vec-growth.rs delete mode 100644 src/test/ui/array-slice-vec/vec-push.rs delete mode 100644 src/test/ui/array-slice-vec/vec-slice-drop.rs delete mode 100644 src/test/ui/array-slice-vec/vec-slice.rs delete mode 100644 src/test/ui/array-slice-vec/vec-to_str.rs delete mode 100644 src/test/ui/array-slice-vec/vec.rs delete mode 100644 src/test/ui/array-slice-vec/vec_cycle.rs delete mode 100644 src/test/ui/array-slice-vec/vec_cycle_wrapped.rs create mode 100644 src/test/ui/atomic-from-mut-not-available.rs create mode 100644 src/test/ui/atomic-from-mut-not-available.stderr delete mode 100644 src/test/ui/cell-does-not-clone.rs create mode 100644 src/test/ui/closures/print/closure-print-generic-1.rs create mode 100644 src/test/ui/closures/print/closure-print-generic-1.stderr create mode 100644 src/test/ui/closures/print/closure-print-generic-2.rs create mode 100644 src/test/ui/closures/print/closure-print-generic-2.stderr create mode 100644 src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs create mode 100644 src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr create mode 100644 src/test/ui/closures/print/closure-print-generic-verbose-1.rs create mode 100644 src/test/ui/closures/print/closure-print-generic-verbose-1.stderr create mode 100644 src/test/ui/closures/print/closure-print-generic-verbose-2.rs create mode 100644 src/test/ui/closures/print/closure-print-generic-verbose-2.stderr create mode 100644 src/test/ui/closures/print/closure-print-verbose.rs create mode 100644 src/test/ui/closures/print/closure-print-verbose.stderr create mode 100644 src/test/ui/cmse-nonsecure-entry/gate_test.rs create mode 100644 src/test/ui/cmse-nonsecure-entry/gate_test.stderr create mode 100644 src/test/ui/cmse-nonsecure-entry/params-on-registers.rs create mode 100644 src/test/ui/cmse-nonsecure-entry/params-on-stack.rs create mode 100644 src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr create mode 100644 src/test/ui/cmse-nonsecure-entry/trustzone-only.rs create mode 100644 src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr create mode 100644 src/test/ui/cmse-nonsecure-entry/wrong-abi.rs create mode 100644 src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr rename src/test/ui/const-generics/{argument_order.stderr => argument_order.full.stderr} (91%) create mode 100644 src/test/ui/const-generics/argument_order.min.stderr delete mode 100644 src/test/ui/const-generics/array-wrapper-struct-ctor.stderr delete mode 100644 src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr rename src/test/ui/const-generics/{const-arg-type-arg-misordered.stderr => const-arg-type-arg-misordered.full.stderr} (84%) create mode 100644 src/test/ui/const-generics/const-arg-type-arg-misordered.min.stderr rename src/test/ui/const-generics/{const-argument-cross-crate-mismatch.stderr => const-argument-cross-crate-mismatch.full.stderr} (86%) create mode 100644 src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr rename src/test/ui/const-generics/{const-param-before-other-params.stderr => const-param-before-other-params.full.stderr} (84%) create mode 100644 src/test/ui/const-generics/const-param-before-other-params.min.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/closures.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/closures.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/less_than.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/unop.rs create mode 100644 src/test/ui/const-generics/defaults/complex-unord-param.min.stderr rename src/test/ui/const-generics/defaults/{intermixed-lifetime.stderr => intermixed-lifetime.full.stderr} (87%) create mode 100644 src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr create mode 100644 src/test/ui/const-generics/defaults/simple-defaults.min.stderr rename src/test/ui/const-generics/{ => infer}/cannot-infer-const-args.full.stderr (70%) rename src/test/ui/const-generics/{ => infer}/cannot-infer-const-args.min.stderr (70%) rename src/test/ui/const-generics/{ => infer}/cannot-infer-const-args.rs (100%) create mode 100644 src/test/ui/const-generics/infer/issue-77092.rs create mode 100644 src/test/ui/const-generics/infer/issue-77092.stderr create mode 100644 src/test/ui/const-generics/infer/method-chain.full.stderr create mode 100644 src/test/ui/const-generics/infer/method-chain.min.stderr create mode 100644 src/test/ui/const-generics/infer/method-chain.rs rename src/test/ui/const-generics/{ => infer}/uninferred-consts.full.stderr (54%) rename src/test/ui/const-generics/{ => infer}/uninferred-consts.min.stderr (54%) rename src/test/ui/const-generics/{ => infer}/uninferred-consts.rs (100%) create mode 100644 src/test/ui/const-generics/invalid-enum.rs create mode 100644 src/test/ui/const-generics/invalid-enum.stderr create mode 100644 src/test/ui/const-generics/issue-74906.rs create mode 100644 src/test/ui/const-generics/issues/issue-61935.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-61935.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-61935.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr rename src/test/ui/const-generics/issues/{issue-62220.stderr => issue-62220.full.stderr} (90%) create mode 100644 src/test/ui/const-generics/issues/issue-62220.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62456.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62456.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-62456.stderr rename src/test/ui/const-generics/issues/{issue-62504.stderr => issue-62504.full.stderr} (89%) create mode 100644 src/test/ui/const-generics/issues/issue-62504.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-62579-no-match.stderr rename src/test/ui/const-generics/issues/{issue-62878.stderr => issue-62878.full.stderr} (58%) create mode 100644 src/test/ui/const-generics/issues/issue-62878.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr rename src/test/ui/const-generics/issues/{issue-64494.stderr => issue-64494.full.stderr} (94%) create mode 100644 src/test/ui/const-generics/issues/issue-64494.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-66205.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-66205.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-66205.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-66906.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-67185-1.stderr rename src/test/ui/const-generics/issues/{issue-67185-2.stderr => issue-67185-2.full.stderr} (82%) create mode 100644 src/test/ui/const-generics/issues/issue-67185-2.min.stderr rename src/test/ui/const-generics/issues/{issue-67739.stderr => issue-67739.full.stderr} (100%) create mode 100644 src/test/ui/const-generics/issues/issue-67739.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68366.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68366.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68366.rs create mode 100644 src/test/ui/const-generics/issues/issue-68615-adt.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68615-array.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68977.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68977.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-68977.stderr create mode 100644 src/test/ui/const-generics/issues/issue-69654-run-pass.rs create mode 100644 src/test/ui/const-generics/issues/issue-69654.rs create mode 100644 src/test/ui/const-generics/issues/issue-69654.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-70125-1.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-70125-2.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-70167.stderr create mode 100644 src/test/ui/const-generics/issues/issue-70225.rs rename src/test/ui/const-generics/issues/{issue-71169.stderr => issue-71169.full.stderr} (89%) create mode 100644 src/test/ui/const-generics/issues/issue-71169.min.stderr rename src/test/ui/const-generics/issues/{issue-71381.stderr => issue-71381.full.stderr} (89%) create mode 100644 src/test/ui/const-generics/issues/issue-71381.min.stderr rename src/test/ui/const-generics/issues/{issue-71382.stderr => issue-71382.full.stderr} (85%) create mode 100644 src/test/ui/const-generics/issues/issue-71382.min.stderr rename src/test/ui/const-generics/issues/{issue-71611.stderr => issue-71611.full.stderr} (89%) create mode 100644 src/test/ui/const-generics/issues/issue-71611.min.stderr rename src/test/ui/const-generics/issues/{issue-72352.stderr => issue-72352.full.stderr} (89%) create mode 100644 src/test/ui/const-generics/issues/issue-72352.min.stderr rename src/test/ui/const-generics/issues/{issue-72787.stderr => issue-72787.full.stderr} (88%) create mode 100644 src/test/ui/const-generics/issues/issue-72787.min.stderr rename src/test/ui/const-generics/issues/{issue-72819-generic-in-const-eval.stderr => issue-72819-generic-in-const-eval.full.stderr} (84%) create mode 100644 src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-73260.rs create mode 100644 src/test/ui/const-generics/issues/issue-73260.stderr create mode 100644 src/test/ui/const-generics/issues/issue-73491.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-73508.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-73508.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-73508.stderr create mode 100644 src/test/ui/const-generics/issues/issue-74101.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-74255.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-74634.rs create mode 100644 src/test/ui/const-generics/issues/issue-74634.stderr create mode 100644 src/test/ui/const-generics/issues/issue-75047.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-76595.rs create mode 100644 src/test/ui/const-generics/issues/issue-76595.stderr create mode 100644 src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs delete mode 100644 src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr create mode 100644 src/test/ui/const-generics/min-and-full-same-time.rs create mode 100644 src/test/ui/const-generics/min-and-full-same-time.stderr create mode 100644 src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs create mode 100644 src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr create mode 100644 src/test/ui/const-generics/occurs-check/bind-param.rs create mode 100644 src/test/ui/const-generics/occurs-check/unify-fixpoint.rs create mode 100644 src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr create mode 100644 src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs create mode 100644 src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-1.rs create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-2.rs create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-3.rs create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-4.rs create mode 100644 src/test/ui/const-generics/std/const-generics-range.min.stderr create mode 100644 src/test/ui/const-generics/type-after-const-ok.min.stderr create mode 100644 src/test/ui/const-generics/type-dependent/issue-71348.min.stderr create mode 100644 src/test/ui/const-generics/type-dependent/issue-71382.full.stderr create mode 100644 src/test/ui/const-generics/type-dependent/issue-71382.min.stderr delete mode 100644 src/test/ui/const-generics/type-dependent/issue-71382.stderr create mode 100644 src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr create mode 100644 src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr delete mode 100644 src/test/ui/const-generics/type-dependent/type-mismatch.stderr rename src/test/ui/const-generics/{types-mismatch-const-args.stderr => types-mismatch-const-args.full.stderr} (64%) create mode 100644 src/test/ui/const-generics/types-mismatch-const-args.min.stderr delete mode 100644 src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr delete mode 100644 src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr create mode 100644 src/test/ui/const_evaluatable/associated-const.rs create mode 100644 src/test/ui/const_evaluatable/function-call.rs create mode 100644 src/test/ui/const_evaluatable/function-call.stderr create mode 100644 src/test/ui/consts/async-block.rs create mode 100644 src/test/ui/consts/async-block.stderr delete mode 100644 src/test/ui/consts/const-eval/double_check2.stderr delete mode 100644 src/test/ui/consts/const-nonzero.rs delete mode 100644 src/test/ui/consts/const-option.rs create mode 100644 src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr create mode 100644 src/test/ui/consts/const_fn_floating_point_arithmetic.rs create mode 100644 src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr delete mode 100644 src/test/ui/consts/const_in_pattern/issue-65466.stderr delete mode 100644 src/test/ui/consts/duration-consts-2.rs delete mode 100644 src/test/ui/consts/is_ascii.rs delete mode 100644 src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs delete mode 100644 src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr create mode 100644 src/test/ui/consts/promote-not.rs create mode 100644 src/test/ui/consts/promote-not.stderr create mode 100644 src/test/ui/consts/promotion-mutable-ref.rs create mode 100644 src/test/ui/consts/stable-precise-live-drops-in-libcore.rs create mode 100644 src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr create mode 100644 src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs delete mode 100644 src/test/ui/deref-lval.rs create mode 100644 src/test/ui/dest-prop/skeptic-miscompile.rs create mode 100644 src/test/ui/disambiguate-identical-names.rs create mode 100644 src/test/ui/disambiguate-identical-names.stderr create mode 100644 src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs create mode 100644 src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs create mode 100644 src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr delete mode 100644 src/test/ui/error-codes/E0027-teach.rs delete mode 100644 src/test/ui/error-codes/E0027-teach.stderr create mode 100644 src/test/ui/error-codes/E0118-2.rs create mode 100644 src/test/ui/error-codes/E0118-2.stderr delete mode 100644 src/test/ui/exterior.rs create mode 100644 src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs create mode 100644 src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs create mode 100644 src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr delete mode 100644 src/test/ui/feature-gate/issue-43106-gating-of-inline.rs delete mode 100644 src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-doc_alias.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-doc_alias.stderr create mode 100644 src/test/ui/fmt/incorrect-separator.rs create mode 100644 src/test/ui/fmt/incorrect-separator.stderr delete mode 100644 src/test/ui/format-ref-cell.rs create mode 100644 src/test/ui/generator/print/generator-print-verbose-1.rs create mode 100644 src/test/ui/generator/print/generator-print-verbose-1.stderr create mode 100644 src/test/ui/generator/print/generator-print-verbose-2.rs create mode 100644 src/test/ui/generator/print/generator-print-verbose-2.stderr create mode 100644 src/test/ui/generator/print/generator-print-verbose-3.rs create mode 100644 src/test/ui/generator/print/generator-print-verbose-3.stderr delete mode 100644 src/test/ui/ifmt.rs create mode 100644 src/test/ui/imports/issue-62767.stderr create mode 100644 src/test/ui/invalid-rustc_args_required_const-arguments.rs create mode 100644 src/test/ui/invalid-rustc_args_required_const-arguments.stderr create mode 100644 src/test/ui/issues/auxiliary/issue-75907.rs create mode 100644 src/test/ui/issues/issue-44333.stderr create mode 100644 src/test/ui/issues/issue-47725.rs create mode 100644 src/test/ui/issues/issue-47725.stderr create mode 100644 src/test/ui/issues/issue-51154.rs create mode 100644 src/test/ui/issues/issue-51154.stderr create mode 100644 src/test/ui/issues/issue-54044.rs create mode 100644 src/test/ui/issues/issue-54044.stderr create mode 100644 src/test/ui/issues/issue-70381.rs create mode 100644 src/test/ui/issues/issue-70381.stderr create mode 100644 src/test/ui/issues/issue-75907.rs create mode 100644 src/test/ui/issues/issue-75907.stderr create mode 100644 src/test/ui/issues/issue-75907_b.rs create mode 100644 src/test/ui/issues/issue-75907_b.stderr create mode 100644 src/test/ui/issues/issue-76077-1.fixed create mode 100644 src/test/ui/issues/issue-76077-1.rs create mode 100644 src/test/ui/issues/issue-76077-1.stderr create mode 100644 src/test/ui/issues/issue-76077.rs create mode 100644 src/test/ui/issues/issue-76077.stderr create mode 100644 src/test/ui/issues/issue-76191.rs create mode 100644 src/test/ui/issues/issue-76191.stderr create mode 100644 src/test/ui/issues/issue-77002.rs create mode 100644 src/test/ui/issues/issue-77218.rs create mode 100644 src/test/ui/issues/issue-77218.stderr create mode 100644 src/test/ui/issues/issue-77919.rs create mode 100644 src/test/ui/issues/issue-77919.stderr create mode 100644 src/test/ui/issues/issue-78372.rs create mode 100644 src/test/ui/issues/issue-78372.stderr create mode 100644 src/test/ui/issues/issue-78622.rs create mode 100644 src/test/ui/issues/issue-78622.stderr delete mode 100644 src/test/ui/iterators/iter-zip.rs create mode 100644 src/test/ui/lazy_normalization_consts/issue-73980.stderr create mode 100644 src/test/ui/lint/dead-code/trait-impl.rs create mode 100644 src/test/ui/lint/lint-const-item-mutation.rs create mode 100644 src/test/ui/lint/lint-const-item-mutation.stderr create mode 100644 src/test/ui/liveness/liveness-consts.rs create mode 100644 src/test/ui/liveness/liveness-consts.stderr create mode 100644 src/test/ui/liveness/liveness-derive.rs create mode 100644 src/test/ui/liveness/liveness-derive.stderr create mode 100644 src/test/ui/macros/duplicate-builtin.rs create mode 100644 src/test/ui/macros/duplicate-builtin.stderr create mode 100644 src/test/ui/match/const_non_normal_zst_ref_pattern.rs create mode 100644 src/test/ui/match/pattern-deref-miscompile.rs create mode 100644 src/test/ui/mir/issue-71793-inline-args-storage.rs create mode 100644 src/test/ui/mir/issue-76248.rs create mode 100644 src/test/ui/mir/issue-76740-copy-propagation.rs create mode 100644 src/test/ui/mir/issue-77359-simplify-arm-identity-.rs create mode 100644 src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs create mode 100644 src/test/ui/moves/issue-75904-move-closure-loop.rs create mode 100644 src/test/ui/moves/issue-75904-move-closure-loop.stderr create mode 100644 src/test/ui/moves/move-deref-coercion.rs create mode 100644 src/test/ui/moves/move-deref-coercion.stderr delete mode 100644 src/test/ui/numbers-arithmetic/arith-0.rs delete mode 100644 src/test/ui/numbers-arithmetic/arith-1.rs delete mode 100644 src/test/ui/numbers-arithmetic/arith-2.rs delete mode 100644 src/test/ui/option-unwrap.rs create mode 100644 src/test/ui/parser/issue-73568-lifetime-after-mut.rs create mode 100644 src/test/ui/parser/issue-73568-lifetime-after-mut.stderr create mode 100644 src/test/ui/parser/unsafe-foreign-mod.rs create mode 100644 src/test/ui/parser/unsafe-foreign-mod.stderr create mode 100644 src/test/ui/parser/unsafe-mod.rs create mode 100644 src/test/ui/parser/unsafe-mod.stderr delete mode 100644 src/test/ui/pattern/const-pat-ice.stderr create mode 100644 src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs create mode 100644 src/test/ui/proc-macro/issue-75930-derive-cfg.rs create mode 100644 src/test/ui/proc-macro/issue-75930-derive-cfg.stdout create mode 100644 src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs create mode 100644 src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout create mode 100644 src/test/ui/proc-macro/load-panic-backtrace.rs create mode 100644 src/test/ui/proc-macro/load-panic-backtrace.stderr create mode 100644 src/test/ui/proc-macro/nested-nonterminal-tokens.rs create mode 100644 src/test/ui/proc-macro/nested-nonterminal-tokens.stdout create mode 100644 src/test/ui/proc-macro/trailing-plus.rs create mode 100644 src/test/ui/proc-macro/trailing-plus.stdout create mode 100644 src/test/ui/proc-macro/unsafe-foreign-mod.rs create mode 100644 src/test/ui/proc-macro/unsafe-mod.rs create mode 100644 src/test/ui/regions/issue-78262.default.stderr create mode 100644 src/test/ui/regions/issue-78262.nll.stderr create mode 100644 src/test/ui/regions/issue-78262.rs create mode 100644 src/test/ui/rfc1445/issue-63479-match-fnptr.stderr create mode 100644 src/test/ui/slice-to-vec-comparison.rs create mode 100644 src/test/ui/slice-to-vec-comparison.stderr create mode 100644 src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs create mode 100644 src/test/ui/stability-attribute/generics-default-stability-where.rs create mode 100644 src/test/ui/stability-attribute/generics-default-stability-where.stderr create mode 100644 src/test/ui/stability-attribute/generics-default-stability.rs create mode 100644 src/test/ui/stability-attribute/generics-default-stability.stderr create mode 100644 src/test/ui/stability-attribute/missing-const-stability.rs create mode 100644 src/test/ui/stability-attribute/missing-const-stability.stderr create mode 100644 src/test/ui/stability-attribute/stability-attribute-trait-impl.rs create mode 100644 src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr create mode 100644 src/test/ui/stdout-during-shutdown.rs create mode 100644 src/test/ui/stdout-during-shutdown.run.stdout delete mode 100644 src/test/ui/str-concat.rs delete mode 100644 src/test/ui/str-multiline.rs delete mode 100644 src/test/ui/string-escapes.rs create mode 100644 src/test/ui/suggestions/if-let-typo.rs create mode 100644 src/test/ui/suggestions/if-let-typo.stderr create mode 100644 src/test/ui/symbol-names/issue-76365.rs create mode 100644 src/test/ui/trait-impl-bound-suggestions.fixed create mode 100644 src/test/ui/trait-impl-bound-suggestions.rs create mode 100644 src/test/ui/trait-impl-bound-suggestions.stderr create mode 100644 src/test/ui/try-block/try-block-in-return.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-74761.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-74761.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr create mode 100644 src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs create mode 100644 src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr create mode 100644 src/test/ui/union/union-deref.rs create mode 100644 src/test/ui/union/union-deref.stderr create mode 100644 src/test/ui/union/union-move.rs create mode 100644 src/test/ui/union/union-move.stderr delete mode 100644 src/test/ui/wrapping-int-combinations.rs create mode 100644 src/tools/build-manifest/src/manifest.rs create mode 100644 src/tools/build-manifest/src/versions.rs create mode 100644 src/tools/lint-docs/Cargo.toml create mode 100644 src/tools/lint-docs/src/groups.rs create mode 100644 src/tools/lint-docs/src/lib.rs create mode 100644 src/tools/lint-docs/src/main.rs create mode 100644 src/version create mode 100644 vendor/block-buffer-0.7.3/.cargo-checksum.json create mode 100644 vendor/block-buffer-0.7.3/Cargo.toml create mode 100644 vendor/block-buffer-0.7.3/LICENSE-APACHE create mode 100644 vendor/block-buffer-0.7.3/LICENSE-MIT create mode 100644 vendor/block-buffer-0.7.3/src/lib.rs create mode 100644 vendor/cc-1.0.59/.cargo-checksum.json create mode 100644 vendor/cc-1.0.59/Cargo.lock create mode 100644 vendor/cc-1.0.59/Cargo.toml rename vendor/{crossbeam-queue => cc-1.0.59}/LICENSE-APACHE (100%) rename vendor/{parking_lot-0.10.2 => cc-1.0.59}/LICENSE-MIT (95%) create mode 100644 vendor/cc-1.0.59/README.md create mode 100644 vendor/cc-1.0.59/src/bin/gcc-shim.rs create mode 100644 vendor/cc-1.0.59/src/com.rs create mode 100644 vendor/cc-1.0.59/src/lib.rs create mode 100644 vendor/cc-1.0.59/src/registry.rs create mode 100644 vendor/cc-1.0.59/src/setup_config.rs create mode 100644 vendor/cc-1.0.59/src/winapi.rs create mode 100644 vendor/cc-1.0.59/src/windows_registry.rs create mode 100644 vendor/cc-1.0.59/tests/cc_env.rs create mode 100644 vendor/cc-1.0.59/tests/cflags.rs create mode 100644 vendor/cc-1.0.59/tests/cxxflags.rs create mode 100644 vendor/cc-1.0.59/tests/support/mod.rs create mode 100644 vendor/cc-1.0.59/tests/test.rs delete mode 100644 vendor/chalk-derive-0.14.0/.cargo-checksum.json create mode 100644 vendor/chalk-derive-0.25.0/.cargo-checksum.json rename vendor/{chalk-derive-0.14.0 => chalk-derive-0.25.0}/Cargo.toml (98%) rename vendor/{chalk-derive-0.14.0 => chalk-derive-0.25.0}/README.md (100%) rename vendor/{chalk-derive-0.14.0 => chalk-derive-0.25.0}/src/lib.rs (100%) rename vendor/{chalk-solve-0.14.0/src/infer => chalk-engine/src}/normalize_deep.rs (66%) rename vendor/{chalk-solve-0.14.0/src/solve => chalk-engine/src}/slg.rs (88%) rename vendor/{chalk-solve-0.14.0/src/solve => chalk-engine/src}/slg/aggregate.rs (86%) rename vendor/{chalk-solve-0.14.0/src/solve => chalk-engine/src}/slg/resolvent.rs (97%) create mode 100644 vendor/chalk-engine/src/solve.rs delete mode 100644 vendor/chalk-ir-0.14.0/.cargo-checksum.json create mode 100644 vendor/chalk-ir-0.25.0/.cargo-checksum.json rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/Cargo.toml (95%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/README.md (100%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/cast.rs (94%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/could_match.rs (95%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/debug.rs (91%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/fold.rs (98%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/fold/binder_impls.rs (86%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/fold/boring_impls.rs (93%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/fold/shift.rs (99%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/fold/subst.rs (97%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/interner.rs (72%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/lib.rs (74%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/visit.rs (97%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/visit/binder_impls.rs (87%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/visit/boring_impls.rs (90%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/visit/visitors.rs (84%) rename vendor/{chalk-ir-0.14.0 => chalk-ir-0.25.0}/src/zip.rs (94%) delete mode 100644 vendor/chalk-solve-0.14.0/.cargo-checksum.json delete mode 100644 vendor/chalk-solve-0.14.0/src/recursive.rs delete mode 100644 vendor/chalk-solve-0.14.0/src/recursive/combine.rs delete mode 100644 vendor/chalk-solve-0.14.0/src/recursive/fulfill.rs delete mode 100644 vendor/chalk-solve-0.14.0/src/recursive/search_graph.rs delete mode 100644 vendor/chalk-solve-0.14.0/src/recursive/solve.rs delete mode 100644 vendor/chalk-solve-0.14.0/src/recursive/stack.rs delete mode 100644 vendor/chalk-solve-0.14.0/src/solve.rs delete mode 100644 vendor/chalk-solve-0.14.0/src/test_macros.rs create mode 100644 vendor/chalk-solve-0.25.0/.cargo-checksum.json rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/Cargo.toml (79%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/README.md (100%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses.rs (66%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/builder.rs (74%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/builtin_traits.rs (72%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/builtin_traits/clone.rs (71%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/builtin_traits/copy.rs (61%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/builtin_traits/fn_family.rs (83%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/builtin_traits/sized.rs (58%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/builtin_traits/unsize.rs (87%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/dyn_ty.rs (98%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/env_elaborator.rs (77%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/generalize.rs (95%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/clauses/program_clauses.rs (87%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/coherence.rs (93%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/coherence/orphan.rs (76%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/coherence/solve.rs (94%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/coinductive_goal.rs (96%) create mode 100644 vendor/chalk-solve-0.25.0/src/display.rs create mode 100644 vendor/chalk-solve-0.25.0/src/display/bounds.rs create mode 100644 vendor/chalk-solve-0.25.0/src/display/identifiers.rs create mode 100644 vendor/chalk-solve-0.25.0/src/display/items.rs create mode 100644 vendor/chalk-solve-0.25.0/src/display/render_trait.rs create mode 100644 vendor/chalk-solve-0.25.0/src/display/state.rs create mode 100644 vendor/chalk-solve-0.25.0/src/display/stub.rs create mode 100644 vendor/chalk-solve-0.25.0/src/display/ty.rs create mode 100644 vendor/chalk-solve-0.25.0/src/display/utils.rs rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/ext.rs (100%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/goal_builder.rs (97%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/infer.rs (87%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/infer/canonicalize.rs (93%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/infer/instantiate.rs (92%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/infer/invert.rs (98%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/infer/test.rs (87%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/infer/ucanonicalize.rs (95%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/infer/unify.rs (91%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/infer/var.rs (93%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/lib.rs (64%) create mode 100644 vendor/chalk-solve-0.25.0/src/logging.rs create mode 100644 vendor/chalk-solve-0.25.0/src/logging_db.rs create mode 100644 vendor/chalk-solve-0.25.0/src/logging_db/id_collector.rs rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/recursive/lib.rs (96%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/rust_ir.rs (84%) create mode 100644 vendor/chalk-solve-0.25.0/src/solve.rs rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/solve/test/bench.rs (100%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/solve/truncate.rs (97%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/split.rs (79%) rename vendor/{chalk-solve-0.14.0 => chalk-solve-0.25.0}/src/wf.rs (85%) create mode 100644 vendor/compiler_builtins/src/int/leading_zeros.rs create mode 100644 vendor/cpuid-bool/.cargo-checksum.json create mode 100644 vendor/cpuid-bool/CHANGELOG.md create mode 100644 vendor/cpuid-bool/Cargo.toml create mode 100644 vendor/cpuid-bool/LICENSE-APACHE create mode 100644 vendor/cpuid-bool/LICENSE-MIT create mode 100644 vendor/cpuid-bool/src/lib.rs create mode 100644 vendor/crossbeam-channel/.cargo-checksum.json create mode 100644 vendor/crossbeam-channel/CHANGELOG.md create mode 100644 vendor/crossbeam-channel/Cargo.lock rename vendor/{crossbeam-queue => crossbeam-channel}/Cargo.toml (65%) rename vendor/{itertools-0.8.2 => crossbeam-channel}/LICENSE-APACHE (100%) rename vendor/{crossbeam-queue => crossbeam-channel}/LICENSE-MIT (100%) create mode 100644 vendor/crossbeam-channel/LICENSE-THIRD-PARTY create mode 100644 vendor/crossbeam-channel/README.md create mode 100644 vendor/crossbeam-channel/benches/crossbeam.rs create mode 100644 vendor/crossbeam-channel/examples/fibonacci.rs create mode 100644 vendor/crossbeam-channel/examples/matching.rs create mode 100644 vendor/crossbeam-channel/examples/stopwatch.rs create mode 100644 vendor/crossbeam-channel/src/channel.rs create mode 100644 vendor/crossbeam-channel/src/context.rs create mode 100644 vendor/crossbeam-channel/src/counter.rs create mode 100644 vendor/crossbeam-channel/src/err.rs create mode 100644 vendor/crossbeam-channel/src/flavors/after.rs create mode 100644 vendor/crossbeam-channel/src/flavors/array.rs create mode 100644 vendor/crossbeam-channel/src/flavors/list.rs create mode 100644 vendor/crossbeam-channel/src/flavors/mod.rs create mode 100644 vendor/crossbeam-channel/src/flavors/never.rs create mode 100644 vendor/crossbeam-channel/src/flavors/tick.rs create mode 100644 vendor/crossbeam-channel/src/flavors/zero.rs create mode 100644 vendor/crossbeam-channel/src/lib.rs create mode 100644 vendor/crossbeam-channel/src/select.rs create mode 100644 vendor/crossbeam-channel/src/select_macro.rs create mode 100644 vendor/crossbeam-channel/src/utils.rs create mode 100644 vendor/crossbeam-channel/src/waker.rs create mode 100644 vendor/crossbeam-channel/tests/after.rs create mode 100644 vendor/crossbeam-channel/tests/array.rs create mode 100644 vendor/crossbeam-channel/tests/golang.rs create mode 100644 vendor/crossbeam-channel/tests/iter.rs create mode 100644 vendor/crossbeam-channel/tests/list.rs create mode 100644 vendor/crossbeam-channel/tests/mpsc.rs create mode 100644 vendor/crossbeam-channel/tests/never.rs create mode 100644 vendor/crossbeam-channel/tests/ready.rs create mode 100644 vendor/crossbeam-channel/tests/same_channel.rs create mode 100644 vendor/crossbeam-channel/tests/select.rs create mode 100644 vendor/crossbeam-channel/tests/select_macro.rs create mode 100644 vendor/crossbeam-channel/tests/thread_locals.rs create mode 100644 vendor/crossbeam-channel/tests/tick.rs create mode 100644 vendor/crossbeam-channel/tests/zero.rs delete mode 100644 vendor/crossbeam-queue/.cargo-checksum.json delete mode 100644 vendor/crossbeam-queue/CHANGELOG.md delete mode 100644 vendor/crossbeam-queue/LICENSE-THIRD-PARTY delete mode 100644 vendor/crossbeam-queue/README.md delete mode 100644 vendor/crossbeam-queue/src/array_queue.rs delete mode 100644 vendor/crossbeam-queue/src/err.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 create mode 100644 vendor/digest-0.8.1/.cargo-checksum.json create mode 100644 vendor/digest-0.8.1/Cargo.toml create mode 100644 vendor/digest-0.8.1/LICENSE-APACHE rename vendor/{parking_lot_core-0.7.2 => digest-0.8.1}/LICENSE-MIT (95%) create mode 100644 vendor/digest-0.8.1/src/dev.rs create mode 100644 vendor/digest-0.8.1/src/digest.rs create mode 100644 vendor/digest-0.8.1/src/dyn_digest.rs create mode 100644 vendor/digest-0.8.1/src/errors.rs create mode 100644 vendor/digest-0.8.1/src/lib.rs create mode 100644 vendor/digest/CHANGELOG.md create mode 100644 vendor/digest/README.md create mode 100644 vendor/digest/src/fixed.rs create mode 100644 vendor/digest/src/variable.rs create mode 100644 vendor/digest/src/xof.rs create mode 100644 vendor/fs-err/.cargo-checksum.json create mode 100644 vendor/fs-err/CHANGELOG.md create mode 100644 vendor/fs-err/Cargo.toml create mode 100644 vendor/fs-err/LICENSE-APACHE create mode 100644 vendor/fs-err/LICENSE-MIT create mode 100644 vendor/fs-err/README.md create mode 100644 vendor/fs-err/README.tpl create mode 100644 vendor/fs-err/src/dir.rs create mode 100644 vendor/fs-err/src/errors.rs create mode 100644 vendor/fs-err/src/file.rs create mode 100644 vendor/fs-err/src/lib.rs create mode 100644 vendor/fs-err/tests/version-numbers.rs create mode 100644 vendor/generic-array-0.12.3/.cargo-checksum.json create mode 100644 vendor/generic-array-0.12.3/CHANGELOG.md create mode 100644 vendor/generic-array-0.12.3/Cargo.toml create mode 100644 vendor/generic-array-0.12.3/LICENSE create mode 100644 vendor/generic-array-0.12.3/README.md create mode 100644 vendor/generic-array-0.12.3/rustfmt.toml create mode 100644 vendor/generic-array-0.12.3/src/arr.rs create mode 100644 vendor/generic-array-0.12.3/src/functional.rs create mode 100644 vendor/generic-array-0.12.3/src/hex.rs create mode 100644 vendor/generic-array-0.12.3/src/impl_serde.rs create mode 100644 vendor/generic-array-0.12.3/src/impls.rs create mode 100644 vendor/generic-array-0.12.3/src/iter.rs create mode 100644 vendor/generic-array-0.12.3/src/lib.rs create mode 100644 vendor/generic-array-0.12.3/src/sequence.rs create mode 100644 vendor/generic-array-0.12.3/tests/arr.rs create mode 100644 vendor/generic-array-0.12.3/tests/generics.rs create mode 100644 vendor/generic-array-0.12.3/tests/hex.rs create mode 100644 vendor/generic-array-0.12.3/tests/import_name.rs create mode 100644 vendor/generic-array-0.12.3/tests/iter.rs create mode 100644 vendor/generic-array-0.12.3/tests/mod.rs create mode 100644 vendor/generic-array/DESIGN.md create mode 100644 vendor/generic-array/build.rs rename vendor/{getrandom => getrandom-0.1.14}/.cargo-checksum.json (100%) rename vendor/{getrandom => getrandom-0.1.14}/CHANGELOG.md (100%) rename vendor/{getrandom => getrandom-0.1.14}/Cargo.toml (100%) rename vendor/{getrandom => getrandom-0.1.14}/LICENSE-APACHE (100%) rename vendor/{getrandom => getrandom-0.1.14}/LICENSE-MIT (100%) rename vendor/{getrandom => getrandom-0.1.14}/README.md (100%) rename vendor/{getrandom => getrandom-0.1.14}/benches/mod.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/build.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/bsd_arandom.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/cloudabi.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/dummy.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/error.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/error_impls.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/fuchsia.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/ios.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/lib.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/linux_android.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/macos.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/openbsd.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/rdrand.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/solaris_illumos.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/use_file.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/util.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/util_libc.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/vxworks.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/wasi.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/wasm32_bindgen.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/wasm32_stdweb.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/windows.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/src/windows_uwp.rs (100%) rename vendor/{getrandom => getrandom-0.1.14}/tests/common.rs (100%) delete mode 100644 vendor/hashbrown/build.rs create mode 100644 vendor/hex/.cargo-checksum.json create mode 100644 vendor/hex/Cargo.toml create mode 100644 vendor/hex/LICENSE-APACHE create mode 100644 vendor/hex/LICENSE-MIT create mode 100644 vendor/hex/README.md create mode 100644 vendor/hex/benches/hex.rs create mode 100644 vendor/hex/src/error.rs create mode 100644 vendor/hex/src/lib.rs create mode 100644 vendor/hex/src/serde.rs create mode 100644 vendor/hex/tests/serde.rs create mode 100644 vendor/hex/tests/version-number.rs delete mode 100644 vendor/itertools-0.8.2/.cargo-checksum.json delete mode 100644 vendor/itertools-0.8.2/Cargo.lock delete mode 100644 vendor/itertools-0.8.2/Cargo.toml delete mode 100644 vendor/itertools-0.8.2/README.rst delete mode 100644 vendor/itertools-0.8.2/benches/bench1.rs delete mode 100644 vendor/itertools-0.8.2/benches/combinations_with_replacement.rs delete mode 100644 vendor/itertools-0.8.2/benches/extra/mod.rs delete mode 100644 vendor/itertools-0.8.2/benches/extra/zipslices.rs delete mode 100644 vendor/itertools-0.8.2/benches/fold_specialization.rs delete mode 100644 vendor/itertools-0.8.2/benches/tree_fold1.rs delete mode 100644 vendor/itertools-0.8.2/benches/tuple_combinations.rs delete mode 100644 vendor/itertools-0.8.2/benches/tuples.rs delete mode 100644 vendor/itertools-0.8.2/examples/iris.data delete mode 100644 vendor/itertools-0.8.2/examples/iris.rs delete mode 100644 vendor/itertools-0.8.2/src/adaptors/mod.rs delete mode 100644 vendor/itertools-0.8.2/src/adaptors/multi_product.rs delete mode 100644 vendor/itertools-0.8.2/src/combinations.rs delete mode 100644 vendor/itertools-0.8.2/src/combinations_with_replacement.rs delete mode 100644 vendor/itertools-0.8.2/src/concat_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/cons_tuples_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/diff.rs delete mode 100644 vendor/itertools-0.8.2/src/either_or_both.rs delete mode 100644 vendor/itertools-0.8.2/src/exactly_one_err.rs delete mode 100644 vendor/itertools-0.8.2/src/format.rs delete mode 100644 vendor/itertools-0.8.2/src/free.rs delete mode 100644 vendor/itertools-0.8.2/src/group_map.rs delete mode 100644 vendor/itertools-0.8.2/src/groupbylazy.rs delete mode 100644 vendor/itertools-0.8.2/src/impl_macros.rs delete mode 100644 vendor/itertools-0.8.2/src/intersperse.rs delete mode 100644 vendor/itertools-0.8.2/src/kmerge_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/lazy_buffer.rs delete mode 100644 vendor/itertools-0.8.2/src/lib.rs delete mode 100644 vendor/itertools-0.8.2/src/merge_join.rs delete mode 100644 vendor/itertools-0.8.2/src/minmax.rs delete mode 100644 vendor/itertools-0.8.2/src/multipeek_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/pad_tail.rs delete mode 100644 vendor/itertools-0.8.2/src/peeking_take_while.rs delete mode 100644 vendor/itertools-0.8.2/src/permutations.rs delete mode 100644 vendor/itertools-0.8.2/src/process_results_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/put_back_n_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/rciter_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/repeatn.rs delete mode 100644 vendor/itertools-0.8.2/src/size_hint.rs delete mode 100644 vendor/itertools-0.8.2/src/sources.rs delete mode 100644 vendor/itertools-0.8.2/src/tee.rs delete mode 100644 vendor/itertools-0.8.2/src/tuple_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/unique_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/with_position.rs delete mode 100644 vendor/itertools-0.8.2/src/zip_eq_impl.rs delete mode 100644 vendor/itertools-0.8.2/src/zip_longest.rs delete mode 100644 vendor/itertools-0.8.2/src/ziptuple.rs delete mode 100644 vendor/itertools-0.8.2/tests/adaptors_no_collect.rs delete mode 100644 vendor/itertools-0.8.2/tests/fold_specialization.rs delete mode 100644 vendor/itertools-0.8.2/tests/merge_join.rs delete mode 100644 vendor/itertools-0.8.2/tests/peeking_take_while.rs delete mode 100644 vendor/itertools-0.8.2/tests/quick.rs delete mode 100644 vendor/itertools-0.8.2/tests/test_core.rs delete mode 100644 vendor/itertools-0.8.2/tests/test_std.rs delete mode 100644 vendor/itertools-0.8.2/tests/tuples.rs delete mode 100644 vendor/itertools-0.8.2/tests/zip.rs create mode 100644 vendor/libloading/src/os/unix/consts.rs create mode 100644 vendor/libloading/tests/constants.rs create mode 100644 vendor/libloading/tests/library_filename.rs mode change 100755 => 100644 vendor/lsp-types/release.sh create mode 100644 vendor/merge/.cargo-checksum.json create mode 100644 vendor/merge/CHANGELOG.md create mode 100644 vendor/merge/Cargo.lock create mode 100644 vendor/merge/Cargo.toml create mode 100644 vendor/merge/LICENSES/Apache-2.0.txt create mode 100644 vendor/merge/LICENSES/CC0-1.0.txt create mode 100644 vendor/merge/LICENSES/MIT.txt create mode 100644 vendor/merge/README.md create mode 100644 vendor/merge/examples/args.rs create mode 100644 vendor/merge/examples/user.rs create mode 100644 vendor/merge/src/lib.rs create mode 100644 vendor/merge/tests/compile.rs create mode 100644 vendor/merge/tests/compile/derive-enum.rs create mode 100644 vendor/merge/tests/compile/derive-enum.stderr create mode 100644 vendor/merge/tests/compile/derive-invalid-attribute.rs create mode 100644 vendor/merge/tests/compile/derive-invalid-attribute.stderr create mode 100644 vendor/merge/tests/compile/derive-invalid-skip.rs create mode 100644 vendor/merge/tests/compile/derive-invalid-skip.stderr create mode 100644 vendor/merge/tests/compile/derive-invalid-strategy.rs create mode 100644 vendor/merge/tests/compile/derive-invalid-strategy.stderr create mode 100644 vendor/merge/tests/compile/derive-missing-strategy.rs create mode 100644 vendor/merge/tests/compile/derive-missing-strategy.stderr create mode 100644 vendor/merge/tests/compile/derive-no-strategy.rs create mode 100644 vendor/merge/tests/compile/derive-no-strategy.stderr create mode 100644 vendor/merge/tests/compile/derive-u8.rs create mode 100644 vendor/merge/tests/compile/derive-u8.stderr create mode 100644 vendor/merge/tests/derive.rs create mode 100644 vendor/merge/tests/impls.rs create mode 100644 vendor/merge/tests/strategies.rs create mode 100644 vendor/merge_derive/.cargo-checksum.json create mode 100644 vendor/merge_derive/CHANGELOG.md create mode 100644 vendor/merge_derive/Cargo.toml create mode 100644 vendor/merge_derive/README.md create mode 100644 vendor/merge_derive/src/lib.rs create mode 100644 vendor/net2/.cargo-checksum.json create mode 100644 vendor/net2/Cargo.toml rename vendor/{parking_lot-0.10.2 => net2}/LICENSE-APACHE (100%) create mode 100644 vendor/net2/LICENSE-MIT create mode 100644 vendor/net2/README.md create mode 100644 vendor/net2/src/ext.rs create mode 100644 vendor/net2/src/lib.rs create mode 100644 vendor/net2/src/socket.rs create mode 100644 vendor/net2/src/sys/redox/impls.rs create mode 100644 vendor/net2/src/sys/redox/mod.rs create mode 100644 vendor/net2/src/sys/unix/impls.rs create mode 100644 vendor/net2/src/sys/unix/mod.rs create mode 100644 vendor/net2/src/sys/wasi/impls.rs create mode 100644 vendor/net2/src/sys/wasi/mod.rs create mode 100644 vendor/net2/src/sys/windows/impls.rs create mode 100644 vendor/net2/src/sys/windows/mod.rs create mode 100644 vendor/net2/src/tcp.rs create mode 100644 vendor/net2/src/udp.rs create mode 100644 vendor/net2/src/unix.rs create mode 100644 vendor/net2/src/utils.rs create mode 100644 vendor/opaque-debug-0.2.3/.cargo-checksum.json create mode 100644 vendor/opaque-debug-0.2.3/Cargo.toml create mode 100644 vendor/opaque-debug-0.2.3/LICENSE-APACHE create mode 100644 vendor/opaque-debug-0.2.3/LICENSE-MIT create mode 100644 vendor/opaque-debug-0.2.3/src/lib.rs create mode 100644 vendor/opaque-debug/tests/mod.rs delete mode 100644 vendor/parking_lot-0.10.2/.cargo-checksum.json delete mode 100644 vendor/parking_lot-0.10.2/CHANGELOG.md delete mode 100644 vendor/parking_lot-0.10.2/Cargo.toml delete mode 100644 vendor/parking_lot-0.10.2/README.md delete mode 100644 vendor/parking_lot-0.10.2/appveyor.yml delete mode 100644 vendor/parking_lot-0.10.2/bors.toml delete mode 100644 vendor/parking_lot-0.10.2/src/condvar.rs delete mode 100644 vendor/parking_lot-0.10.2/src/deadlock.rs delete mode 100644 vendor/parking_lot-0.10.2/src/elision.rs delete mode 100644 vendor/parking_lot-0.10.2/src/fair_mutex.rs delete mode 100644 vendor/parking_lot-0.10.2/src/lib.rs delete mode 100644 vendor/parking_lot-0.10.2/src/mutex.rs delete mode 100644 vendor/parking_lot-0.10.2/src/once.rs delete mode 100644 vendor/parking_lot-0.10.2/src/raw_fair_mutex.rs delete mode 100644 vendor/parking_lot-0.10.2/src/raw_mutex.rs delete mode 100644 vendor/parking_lot-0.10.2/src/raw_rwlock.rs delete mode 100644 vendor/parking_lot-0.10.2/src/remutex.rs delete mode 100644 vendor/parking_lot-0.10.2/src/rwlock.rs delete mode 100644 vendor/parking_lot-0.10.2/src/util.rs delete mode 100644 vendor/parking_lot-0.10.2/tests/issue_203.rs delete mode 100644 vendor/parking_lot_core-0.7.2/.cargo-checksum.json delete mode 100644 vendor/parking_lot_core-0.7.2/Cargo.toml delete mode 100644 vendor/parking_lot_core-0.7.2/src/lib.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/parking_lot.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/spinwait.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/cloudabi.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/generic.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/linux.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/mod.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/redox.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/sgx.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/unix.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/wasm.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/wasm_atomic.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/windows/keyed_event.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/windows/mod.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/thread_parker/windows/waitaddress.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/util.rs delete mode 100644 vendor/parking_lot_core-0.7.2/src/word_lock.rs create mode 100644 vendor/proc-macro-error-attr/.cargo-checksum.json create mode 100644 vendor/proc-macro-error-attr/Cargo.toml create mode 100644 vendor/proc-macro-error-attr/LICENSE-APACHE create mode 100644 vendor/proc-macro-error-attr/LICENSE-MIT create mode 100644 vendor/proc-macro-error-attr/build.rs create mode 100644 vendor/proc-macro-error-attr/src/lib.rs create mode 100644 vendor/proc-macro-error-attr/src/parse.rs create mode 100644 vendor/proc-macro-error-attr/src/settings.rs create mode 100644 vendor/proc-macro-error/.cargo-checksum.json create mode 100644 vendor/proc-macro-error/CHANGELOG.md create mode 100644 vendor/proc-macro-error/Cargo.toml create mode 100644 vendor/proc-macro-error/LICENSE-APACHE create mode 100644 vendor/proc-macro-error/LICENSE-MIT create mode 100644 vendor/proc-macro-error/README.md create mode 100644 vendor/proc-macro-error/build.rs create mode 100644 vendor/proc-macro-error/src/diagnostic.rs create mode 100644 vendor/proc-macro-error/src/dummy.rs create mode 100644 vendor/proc-macro-error/src/imp/delegate.rs create mode 100644 vendor/proc-macro-error/src/imp/fallback.rs create mode 100644 vendor/proc-macro-error/src/lib.rs create mode 100644 vendor/proc-macro-error/src/macros.rs create mode 100644 vendor/proc-macro-error/src/sealed.rs create mode 100644 vendor/proc-macro-error/tests/macro-errors.rs create mode 100644 vendor/proc-macro-error/tests/ok.rs create mode 100644 vendor/proc-macro-error/tests/runtime-errors.rs create mode 100644 vendor/proc-macro-error/tests/ui/abort.rs create mode 100644 vendor/proc-macro-error/tests/ui/abort.stderr create mode 100644 vendor/proc-macro-error/tests/ui/append_dummy.rs create mode 100644 vendor/proc-macro-error/tests/ui/append_dummy.stderr create mode 100644 vendor/proc-macro-error/tests/ui/children_messages.rs create mode 100644 vendor/proc-macro-error/tests/ui/children_messages.stderr create mode 100644 vendor/proc-macro-error/tests/ui/dummy.rs create mode 100644 vendor/proc-macro-error/tests/ui/dummy.stderr create mode 100644 vendor/proc-macro-error/tests/ui/emit.rs create mode 100644 vendor/proc-macro-error/tests/ui/emit.stderr create mode 100644 vendor/proc-macro-error/tests/ui/explicit_span_range.rs create mode 100644 vendor/proc-macro-error/tests/ui/explicit_span_range.stderr create mode 100644 vendor/proc-macro-error/tests/ui/misuse.rs create mode 100644 vendor/proc-macro-error/tests/ui/misuse.stderr create mode 100644 vendor/proc-macro-error/tests/ui/multiple_tokens.rs create mode 100644 vendor/proc-macro-error/tests/ui/multiple_tokens.stderr create mode 100644 vendor/proc-macro-error/tests/ui/not_proc_macro.rs create mode 100644 vendor/proc-macro-error/tests/ui/not_proc_macro.stderr create mode 100644 vendor/proc-macro-error/tests/ui/option_ext.rs create mode 100644 vendor/proc-macro-error/tests/ui/option_ext.stderr create mode 100644 vendor/proc-macro-error/tests/ui/proc_macro_hack.rs create mode 100644 vendor/proc-macro-error/tests/ui/proc_macro_hack.stderr create mode 100644 vendor/proc-macro-error/tests/ui/result_ext.rs create mode 100644 vendor/proc-macro-error/tests/ui/result_ext.stderr create mode 100644 vendor/proc-macro-error/tests/ui/to_tokens_span.rs create mode 100644 vendor/proc-macro-error/tests/ui/to_tokens_span.stderr create mode 100644 vendor/proc-macro-error/tests/ui/unknown_setting.rs create mode 100644 vendor/proc-macro-error/tests/ui/unknown_setting.stderr create mode 100644 vendor/proc-macro-error/tests/ui/unrelated_panic.rs create mode 100644 vendor/proc-macro-error/tests/ui/unrelated_panic.stderr create mode 100644 vendor/proc-macro2/src/marker.rs delete mode 100644 vendor/proc-macro2/src/strnom.rs create mode 100644 vendor/proc-macro2/tests/test_fmt.rs create mode 100644 vendor/pulldown-cmark-0.7.2/.cargo-checksum.json create mode 100644 vendor/pulldown-cmark-0.7.2/CONTRIBUTING.md create mode 100644 vendor/pulldown-cmark-0.7.2/Cargo.lock create mode 100644 vendor/pulldown-cmark-0.7.2/Cargo.toml create mode 100644 vendor/pulldown-cmark-0.7.2/LICENSE create mode 100644 vendor/pulldown-cmark-0.7.2/README.md create mode 100644 vendor/pulldown-cmark-0.7.2/benches/html_rendering.rs create mode 100644 vendor/pulldown-cmark-0.7.2/benches/lib.rs create mode 100644 vendor/pulldown-cmark-0.7.2/build.rs create mode 100644 vendor/pulldown-cmark-0.7.2/examples/event-filter.rs create mode 100644 vendor/pulldown-cmark-0.7.2/examples/string-to-string.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/entities.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/escape.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/html.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/lib.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/linklabel.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/main.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/parse.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/puncttable.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/scanners.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/simd.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/strings.rs create mode 100644 vendor/pulldown-cmark-0.7.2/src/tree.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/errors.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/html.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/lib.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/suite/footnotes.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/suite/gfm_strikethrough.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/suite/gfm_table.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/suite/gfm_tasklist.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/suite/mod.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/suite/regression.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/suite/spec.rs create mode 100644 vendor/pulldown-cmark-0.7.2/tests/suite/table.rs create mode 100644 vendor/pulldown-cmark-to-cmark/.cargo-checksum.json create mode 100644 vendor/pulldown-cmark-to-cmark/CHANGELOG.md create mode 100644 vendor/pulldown-cmark-to-cmark/Cargo.toml create mode 100644 vendor/pulldown-cmark-to-cmark/README.md create mode 100644 vendor/pulldown-cmark-to-cmark/src/lib.rs create mode 100644 vendor/pulldown-cmark/examples/broken-link-callbacks.rs create mode 100644 vendor/pulldown-cmark/tests/suite/smart_punct.rs create mode 100644 vendor/rayon-core/src/sleep/counters.rs create mode 100644 vendor/rayon/tests/chars.rs rename vendor/{rustc-ap-rustc_lexer => rustc-ap-rustc_lexer-673.0.0}/.cargo-checksum.json (100%) rename vendor/{rustc-ap-rustc_lexer => rustc-ap-rustc_lexer-673.0.0}/Cargo.toml (100%) rename vendor/{rustc-ap-rustc_lexer => rustc-ap-rustc_lexer-673.0.0}/src/cursor.rs (100%) rename vendor/{rustc-ap-rustc_lexer => rustc-ap-rustc_lexer-673.0.0}/src/lib.rs (100%) rename vendor/{rustc-ap-rustc_lexer => rustc-ap-rustc_lexer-673.0.0}/src/tests.rs (100%) rename vendor/{rustc-ap-rustc_lexer => rustc-ap-rustc_lexer-673.0.0}/src/unescape.rs (100%) rename vendor/{rustc-ap-rustc_lexer => rustc-ap-rustc_lexer-673.0.0}/src/unescape/tests.rs (100%) create mode 100644 vendor/sha2/.cargo-checksum.json create mode 100644 vendor/sha2/CHANGELOG.md create mode 100644 vendor/sha2/Cargo.lock create mode 100644 vendor/sha2/Cargo.toml create mode 100644 vendor/sha2/LICENSE-APACHE create mode 100644 vendor/sha2/LICENSE-MIT create mode 100644 vendor/sha2/README.md create mode 100644 vendor/sha2/benches/sha256.rs create mode 100644 vendor/sha2/benches/sha512.rs create mode 100644 vendor/sha2/examples/sha256sum.rs create mode 100644 vendor/sha2/examples/sha512sum.rs create mode 100644 vendor/sha2/src/consts.rs create mode 100644 vendor/sha2/src/lib.rs create mode 100644 vendor/sha2/src/sha256.rs create mode 100644 vendor/sha2/src/sha256/aarch64.rs create mode 100644 vendor/sha2/src/sha256/soft.rs create mode 100644 vendor/sha2/src/sha256/x86.rs create mode 100644 vendor/sha2/src/sha512.rs create mode 100644 vendor/sha2/src/sha512/soft.rs create mode 100644 vendor/sha2/tests/data/sha224.blb create mode 100644 vendor/sha2/tests/data/sha256.blb create mode 100644 vendor/sha2/tests/data/sha256_one_million_a.bin create mode 100644 vendor/sha2/tests/data/sha384.blb create mode 100644 vendor/sha2/tests/data/sha512.blb create mode 100644 vendor/sha2/tests/data/sha512_224.blb create mode 100644 vendor/sha2/tests/data/sha512_256.blb create mode 100644 vendor/sha2/tests/data/sha512_one_million_a.bin create mode 100644 vendor/sha2/tests/lib.rs create mode 100644 vendor/snap/.cargo-checksum.json create mode 100644 vendor/snap/COPYING create mode 100644 vendor/snap/Cargo.lock create mode 100644 vendor/snap/Cargo.toml create mode 100644 vendor/snap/README.md create mode 100644 vendor/snap/build.rs create mode 100644 vendor/snap/data/COPYING create mode 100644 vendor/snap/data/Mark.Twain-Tom.Sawyer.txt create mode 100644 vendor/snap/data/Mark.Twain-Tom.Sawyer.txt.rawsnappy create mode 100644 vendor/snap/data/alice29.txt create mode 100644 vendor/snap/data/asyoulik.txt create mode 100644 vendor/snap/data/baddata1.snappy create mode 100644 vendor/snap/data/baddata2.snappy create mode 100644 vendor/snap/data/baddata3.snappy create mode 100644 vendor/snap/data/fireworks.jpeg create mode 100644 vendor/snap/data/geo.protodata create mode 100644 vendor/snap/data/html create mode 100644 vendor/snap/data/html_x_4 create mode 100644 vendor/snap/data/kppkn.gtb create mode 100644 vendor/snap/data/lcet10.txt create mode 100644 vendor/snap/data/paper-100k.pdf create mode 100644 vendor/snap/data/plrabn12.txt create mode 100644 vendor/snap/data/urls.10K create mode 100644 vendor/snap/examples/compress-escaped.rs create mode 100644 vendor/snap/examples/compress.rs create mode 100644 vendor/snap/examples/decompress.rs create mode 100644 vendor/snap/rustfmt.toml create mode 100644 vendor/snap/src/bytes.rs create mode 100644 vendor/snap/src/compress.rs create mode 100644 vendor/snap/src/crc32.rs create mode 100644 vendor/snap/src/crc32_table.rs create mode 100644 vendor/snap/src/decompress.rs create mode 100644 vendor/snap/src/error.rs create mode 100644 vendor/snap/src/frame.rs create mode 100644 vendor/snap/src/lib.rs create mode 100644 vendor/snap/src/raw.rs create mode 100644 vendor/snap/src/read.rs create mode 100644 vendor/snap/src/tag.rs create mode 100644 vendor/snap/src/varint.rs create mode 100644 vendor/snap/src/write.rs create mode 100644 vendor/syn/src/gen/clone.rs create mode 100644 vendor/syn/src/gen/debug.rs create mode 100644 vendor/syn/src/gen/eq.rs create mode 100644 vendor/syn/src/gen/hash.rs create mode 100644 vendor/syn/src/reserved.rs create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/.cargo-checksum.json create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/CODE_OF_CONDUCT.md create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/CONTRIBUTING.md create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/Cargo.toml rename vendor/{parking_lot_core-0.7.2 => wasi-0.9.0+wasi-snapshot-preview1}/LICENSE-APACHE (100%) create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/LICENSE-Apache-2.0_WITH_LLVM-exception rename vendor/{itertools-0.8.2 => wasi-0.9.0+wasi-snapshot-preview1}/LICENSE-MIT (98%) create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/ORG_CODE_OF_CONDUCT.md create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/README.md create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/SECURITY.md rename vendor/{wasi => wasi-0.9.0+wasi-snapshot-preview1}/old-bitflags.patch (100%) create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/src/error.rs create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/src/lib.rs create mode 100644 vendor/wasi-0.9.0+wasi-snapshot-preview1/src/lib_generated.rs diff --git a/Cargo.lock b/Cargo.lock index d5466d57e7..ecd42d6d4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -183,7 +183,16 @@ dependencies = [ "block-padding", "byte-tools", "byteorder", - "generic-array", + "generic-array 0.12.3", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.4", ] [[package]] @@ -207,6 +216,7 @@ dependencies = [ "ignore", "lazy_static", "libc", + "merge", "num_cpus", "opener", "pretty_assertions", @@ -230,8 +240,15 @@ dependencies = [ name = "build-manifest" version = "0.1.0" dependencies = [ + "anyhow", + "flate2", + "hex 0.4.2", + "num_cpus", + "rayon", "serde", "serde_json", + "sha2", + "tar", "toml", ] @@ -278,7 +295,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da" [[package]] name = "cargo" -version = "0.48.0" +version = "0.49.0" dependencies = [ "anyhow", "atty", @@ -342,7 +359,6 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata 0.9.1", "directories", "rustc-workspace-hack", "rustc_version", @@ -391,18 +407,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "cargo_metadata" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" -dependencies = [ - "semver 0.9.0", - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "cargo_metadata" version = "0.11.1" @@ -420,9 +424,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" +checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" dependencies = [ "jobserver", ] @@ -439,9 +443,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.14.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d463e01905d607e181de72e8608721d3269f29176c9a14ce037011316ae7131d" +checksum = "3a7f257e3bcdc56d8877ae31c012bd69fba0be66929d588e603905f2632c0c59" dependencies = [ "proc-macro2", "quote", @@ -451,21 +455,22 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.14.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaf428f5398d36284f79690cf988762b7c091249f50a6c11db613a46c057000" +checksum = "c43fcc7edf4d51b42f44ed50e2337bd90ddc8e088d0cd78a71db92a6f780f782" dependencies = [ "chalk-derive", "chalk-ir", + "chalk-solve", "rustc-hash", "tracing", ] [[package]] name = "chalk-ir" -version = "0.14.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3fdc1e9f68498ffe80f4a23b0b95f1ca6fb21d5a4c9b0c085fab3ca712bdbe" +checksum = "03a4050029ecb2b5a1ff3bfc64c39279179b294821ec2e8891a4a5c6e3a08db0" dependencies = [ "chalk-derive", "lazy_static", @@ -473,18 +478,19 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.14.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9fd4102807b7ebe8fb034fa0f488c5656e1966d3261b558b81a08d519cdb29" +checksum = "828c1f80d4eaf681027cce02050c54a3c97370f81988d31bf2a56df54048746c" dependencies = [ "chalk-derive", - "chalk-engine", "chalk-ir", "ena", "itertools 0.9.0", "petgraph", "rustc-hash", "tracing", + "tracing-subscriber", + "tracing-tree", ] [[package]] @@ -518,7 +524,7 @@ dependencies = [ name = "clippy" version = "0.0.212" dependencies = [ - "cargo_metadata 0.9.1", + "cargo_metadata 0.11.1", "clippy-mini-macro-test", "clippy_lints", "compiletest_rs", @@ -526,7 +532,7 @@ dependencies = [ "lazy_static", "rustc-workspace-hack", "rustc_tools_util 0.2.0", - "semver 0.9.0", + "semver 0.10.0", "serde", "tempfile", "tester", @@ -540,15 +546,15 @@ version = "0.2.0" name = "clippy_lints" version = "0.0.212" dependencies = [ - "cargo_metadata 0.9.1", + "cargo_metadata 0.11.1", "if_chain", "itertools 0.9.0", "lazy_static", - "pulldown-cmark", + "pulldown-cmark 0.8.0", "quine-mc_cluskey", "quote", "regex-syntax", - "semver 0.9.0", + "semver 0.10.0", "serde", "smallvec 1.4.2", "syn", @@ -586,9 +592,9 @@ dependencies = [ [[package]] name = "colored" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" dependencies = [ "atty", "lazy_static", @@ -615,9 +621,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.32" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c" +checksum = "e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455" dependencies = [ "cc", "rustc-std-workspace-core", @@ -694,6 +700,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6" +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + [[package]] name = "crates-io" version = "0.31.1" @@ -717,12 +729,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" dependencies = [ - "cfg-if", "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] @@ -891,16 +903,24 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array", + "generic-array 0.12.3", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", ] [[package]] name = "directories" -version = "2.0.2" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f" dependencies = [ - "cfg-if", "dirs-sys", ] @@ -1010,9 +1030,9 @@ dependencies = [ [[package]] name = "expect-test" -version = "0.1.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e383741ea1982866572109d1a8c807bd36aad91fca701489fdca56ef92b3b8" +checksum = "ceb96f3eaa0d4e8769c52dacfd4eb60183b817ed2f176171b3c691d5022b0f2e" dependencies = [ "difference", "once_cell", @@ -1174,6 +1194,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getopts" version = "0.2.21" @@ -1196,6 +1226,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.22.0" @@ -1209,9 +1250,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.8" +version = "0.13.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ac22e49b7d886b6802c66662b12609452248b1bc9e87d6d83ecea3db96f557" +checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224" dependencies = [ "bitflags", "libc", @@ -1269,11 +1310,10 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" +checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" dependencies = [ - "autocfg", "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -1411,9 +1451,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ "autocfg", "hashbrown", @@ -1621,18 +1661,18 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" dependencies = [ "rustc-std-workspace-core", ] [[package]] name = "libgit2-sys" -version = "0.12.9+1.0.1" +version = "0.12.14+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b33bf3d9d4c45b48ae1ea7c334be69994624dc0a69f833d5d9f7605f24b552b" +checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" dependencies = [ "cc", "libc", @@ -1654,9 +1694,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafa907407504b0e683786d4aba47acf250f114d37357d56608333fd167dd0fc" +checksum = "ca46220853ba1c512fc82826d0834d87b06bcd3c2a42241b7de72f3d2fe17056" dependencies = [ "cc", "libc", @@ -1668,9 +1708,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.0.27" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ca8894883d250240341478bf987467332fbdd5da5c42426c69a8f93dbc302f2" +checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" dependencies = [ "cc", "libc", @@ -1688,6 +1728,15 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" +[[package]] +name = "lint-docs" +version = "0.1.0" +dependencies = [ + "serde_json", + "tempfile", + "walkdir", +] + [[package]] name = "lock_api" version = "0.3.4" @@ -1833,16 +1882,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8" dependencies = [ - "block-buffer", - "digest", - "opaque-debug", + "block-buffer 0.7.3", + "digest 0.8.1", + "opaque-debug 0.2.3", ] [[package]] name = "mdbook" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75e31ae4eaa0e45e17ee2b6b9e3ed969c3c6ff12bb4c2e352c42493f4ebb706" +checksum = "29be448fcafb00c5a8966c4020c2a5ffbbc333e5b96d0bb5ef54b5bd0524d9ff" dependencies = [ "ammonia", "anyhow", @@ -1855,7 +1904,7 @@ dependencies = [ "log", "memchr", "open", - "pulldown-cmark", + "pulldown-cmark 0.7.2", "regex", "serde", "serde_derive", @@ -1902,6 +1951,28 @@ dependencies = [ "autocfg", ] +[[package]] +name = "merge" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" +dependencies = [ + "merge_derive", + "num-traits", +] + +[[package]] +name = "merge_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "minifier" version = "0.0.33" @@ -1991,11 +2062,10 @@ dependencies = [ name = "miri" version = "0.1.0" dependencies = [ - "byteorder", "colored", "compiletest_rs", "env_logger 0.7.1", - "getrandom", + "getrandom 0.2.0", "hex 0.4.2", "libc", "log", @@ -2067,9 +2137,6 @@ name = "once_cell" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" -dependencies = [ - "parking_lot 0.11.0", -] [[package]] name = "opaque-debug" @@ -2077,6 +2144,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "open" version = "1.4.0" @@ -2517,6 +2590,17 @@ dependencies = [ "unicase", ] +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + [[package]] name = "punycode" version = "0.4.1" @@ -2552,9 +2636,9 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.37" +version = "2.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db975752fc2c2430b4159d262585f7e45eb9aa43d733bf02c5f2fde512b00bfb" +checksum = "b9424b4650b9c1134d0a1b34dab82319691e1c95fa8af1658fc640deb1b6823c" dependencies = [ "bitflags", "clap", @@ -2579,7 +2663,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.14", "libc", "rand_chacha", "rand_core", @@ -2603,7 +2687,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.14", ] [[package]] @@ -2679,7 +2763,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" dependencies = [ - "getrandom", + "getrandom 0.1.14", "redox_syscall", "rust-argon2", ] @@ -2879,9 +2963,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_arena" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3941333c39ffa778611a34692244052fc9ba0f6b02dcf019c8d24925707dd6" +checksum = "e8e941a8fc3878a111d2bbfe78e39522d884136f0b412b12592195f26f653476" dependencies = [ "rustc-ap-rustc_data_structures", "smallvec 1.4.2", @@ -2889,30 +2973,28 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c579f7d89e6fc971b433e92bb2b8c65b716d7c797b21de8685945be9455610" +checksum = "3b58b6b035710df7f339a2bf86f6dafa876efd95439540970e24609e33598ca6" dependencies = [ "bitflags", - "log", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_index", "rustc-ap-rustc_lexer", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", - "scoped-tls", "smallvec 1.4.2", + "tracing", ] [[package]] name = "rustc-ap-rustc_ast_passes" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9914fadee461568d19ca2ebaec8699ff898f8ffec9928154659a57ee018e5fd" +checksum = "3d379a900d6a1f098490d92ab83e87487dcee2e4ec3f04c3ac4512b5117b64e2" dependencies = [ - "itertools 0.8.2", - "log", + "itertools 0.9.0", "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", "rustc-ap-rustc_attr", @@ -2922,31 +3004,33 @@ dependencies = [ "rustc-ap-rustc_parse", "rustc-ap-rustc_session", "rustc-ap-rustc_span", + "tracing", ] [[package]] name = "rustc-ap-rustc_ast_pretty" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a78c5cc50a2f294d3c4e9131a15676724c9f136d3ed54e9ba419850b6025cb3" +checksum = "658d925c0da9e3c5cddc5e54f4fa8c03b41aff1fc6dc5e41837c1118ad010ac0" dependencies = [ - "log", "rustc-ap-rustc_ast", "rustc-ap-rustc_span", "rustc-ap-rustc_target", + "tracing", ] [[package]] name = "rustc-ap-rustc_attr" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78ce08227d146949755175c0cf710280a4b5bf6ee504c0e3f7ccc30d66fbfd9" +checksum = "3f387037534f34c148aed753622677500e42d190a095670e7ac3fffc09811a59" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", + "rustc-ap-rustc_lexer", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_session", @@ -2956,9 +3040,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_data_structures" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5ac3735c38d2d0e95991ebcd7eb1618b60e784194a738e0ce2e8d39c39b809" +checksum = "14ffd17a37e00d77926a0713f191c59ff3aeb2b551a024c7cfffce14bab79be8" dependencies = [ "bitflags", "cfg-if", @@ -2966,14 +3050,12 @@ dependencies = [ "ena", "indexmap", "jobserver", - "lazy_static", "libc", - "log", "measureme", - "once_cell", - "parking_lot 0.10.2", + "parking_lot 0.11.0", "rustc-ap-rustc_graphviz", "rustc-ap-rustc_index", + "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-hash", "rustc-rayon", @@ -2981,34 +3063,36 @@ dependencies = [ "smallvec 1.4.2", "stable_deref_trait", "stacker", + "tempfile", + "tracing", "winapi 0.3.9", ] [[package]] name = "rustc-ap-rustc_errors" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5166a95afa6e3b78ccbece4c2f1e163634854297f1147c6fd90e2712ed3fede5" +checksum = "2b3263ddcfa9eb911e54a4e8088878dd9fd10e00d8b99b01033ba4a2733fe91d" dependencies = [ "annotate-snippets 0.8.0", "atty", - "log", "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", "termcolor", "termize", + "tracing", "unicode-width", "winapi 0.3.9", ] [[package]] name = "rustc-ap-rustc_expand" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a0586e83bdfe70eda8393429a8a38ecb529525dd252d787e479af075d3cab08" +checksum = "e1ab7e68cede8a2273fd8b8623002ce9dc832e061dfc3330e9bcc1fc2a722d73" dependencies = [ - "log", "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_passes", "rustc-ap-rustc_ast_pretty", @@ -3017,60 +3101,62 @@ dependencies = [ "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", "rustc-ap-rustc_lexer", + "rustc-ap-rustc_macros", "rustc-ap-rustc_parse", "rustc-ap-rustc_serialize", "rustc-ap-rustc_session", "rustc-ap-rustc_span", "smallvec 1.4.2", + "tracing", ] [[package]] name = "rustc-ap-rustc_feature" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fc3aa8de0737a8c5a4353e6948548f469150d2b5d3eac391843de32c6c6ca2" +checksum = "eea2dc95421bc19bbd4d939399833a882c46b684283b4267ad1fcf982fc043d9" dependencies = [ - "lazy_static", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_span", ] [[package]] name = "rustc-ap-rustc_fs_util" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fd3380f4029020b693bbfd5a14ec8c893ec33c5c0063ad2e68e46d3fbd6a1f" +checksum = "1e44c1804f09635f83f6cf1e04c2e92f8aeb7b4e850ac6c53d373dab02c13053" [[package]] name = "rustc-ap-rustc_graphviz" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54bd98f70e04291bf611151d1fcd4d7770b35f7ec603d301c4aee0d1979cca4" +checksum = "dc491f2b9be6e928f6df6b287549b8d50c48e8eff8638345155f40fa2cfb785d" [[package]] name = "rustc-ap-rustc_index" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335bfb187a2489a59ee8c67fcf5d1760e9dcdbe0f02025c199a74caa05096b15" +checksum = "fa73f3fed413cdb6290738a10267da17b9ae8e02087334778b9a8c9491c5efc0" dependencies = [ "arrayvec", + "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", ] [[package]] name = "rustc-ap-rustc_lexer" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1221f3bfa2943c942cf8da319ab2346887f8757778c29c7f1822cd27b521f" +checksum = "e993881244a92f3b44cf43c8f22ae2ca5cefe4f55a34e2b65b72ee66fe5ad077" dependencies = [ "unicode-xid", ] [[package]] name = "rustc-ap-rustc_macros" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b774df26c4ef513555b3a303cb209f44cf68a9e6a5481b41ac832301c6487cb" +checksum = "4effe366556e1d75344764adf4d54cba7c2fad33dbd07588e96d0853831ddc7c" dependencies = [ "proc-macro2", "quote", @@ -3080,12 +3166,11 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_parse" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065e632101bdd57a271f38ee7a4d72b5a3d0467ec845104346c284b2c6c69960" +checksum = "0342675835251571471d3dca9ea1576a853a8dfa1f4b0084db283c861223cb60" dependencies = [ "bitflags", - "log", "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", "rustc-ap-rustc_data_structures", @@ -3094,14 +3179,16 @@ dependencies = [ "rustc-ap-rustc_lexer", "rustc-ap-rustc_session", "rustc-ap-rustc_span", + "smallvec 1.4.2", + "tracing", "unicode-normalization", ] [[package]] name = "rustc-ap-rustc_serialize" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e8c0b704e3dedb97cbb1ac566bbc0ab397ec4a4743098326a8f2230463fd9f9" +checksum = "438255ed968d73bf6573aa18d3b8d33c0a85ecdfd14160ef09ff813938e0606c" dependencies = [ "indexmap", "smallvec 1.4.2", @@ -3109,32 +3196,32 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_session" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda99ede4e6e260712754f8548b0a175b615686ad393653a3bd11f6c5e41a04e" +checksum = "7d61ff76dede8eb827f6805754900d1097a7046f938f950231b62b448f55bf78" dependencies = [ "bitflags", "getopts", - "log", "num_cpus", "rustc-ap-rustc_ast", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", "rustc-ap-rustc_fs_util", + "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", "rustc-ap-rustc_target", + "tracing", ] [[package]] name = "rustc-ap-rustc_span" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53453791c2c0b501a921927ce8e305a801eef130920873f8da92d83dad595236" +checksum = "1c267f15c3cfc82a8a441d2bf86bcccf299d1eb625822468e3d8ee6f7c5a1c89" dependencies = [ "cfg-if", - "log", "md-5", "rustc-ap-rustc_arena", "rustc-ap-rustc_data_structures", @@ -3143,22 +3230,23 @@ dependencies = [ "rustc-ap-rustc_serialize", "scoped-tls", "sha-1", + "tracing", "unicode-width", ] [[package]] name = "rustc-ap-rustc_target" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac82006fdb31ef44e24e1623f8b72ac2b404ef15ba20b7ebec0df35e5d20bbef" +checksum = "8b1b4b266c4d44aac0f7f83b6741d8f0545b03d1ce32f3b5254f2014225cb96c" dependencies = [ "bitflags", - "log", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_index", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", + "tracing", ] [[package]] @@ -3300,7 +3388,7 @@ dependencies = [ name = "rustc_ast_passes" version = "0.0.0" dependencies = [ - "itertools 0.8.2", + "itertools 0.9.0", "rustc_ast", "rustc_ast_pretty", "rustc_attr", @@ -3365,7 +3453,6 @@ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ "bitflags", - "flate2", "libc", "measureme", "rustc-demangle", @@ -3386,6 +3473,7 @@ dependencies = [ "rustc_span", "rustc_target", "smallvec 1.4.2", + "snap", "tracing", ] @@ -3431,11 +3519,9 @@ dependencies = [ "ena", "indexmap", "jobserver", - "lazy_static", "libc", "measureme", - "once_cell", - "parking_lot 0.10.2", + "parking_lot 0.11.0", "rustc-hash", "rustc-rayon", "rustc-rayon-core", @@ -3455,7 +3541,6 @@ dependencies = [ name = "rustc_driver" version = "0.0.0" dependencies = [ - "lazy_static", "libc", "rustc_ast", "rustc_ast_pretty", @@ -3529,7 +3614,6 @@ dependencies = [ name = "rustc_feature" version = "0.0.0" dependencies = [ - "lazy_static", "rustc_data_structures", "rustc_span", ] @@ -3546,7 +3630,6 @@ version = "0.0.0" name = "rustc_hir" version = "0.0.0" dependencies = [ - "lazy_static", "rustc_ast", "rustc_data_structures", "rustc_index", @@ -3600,7 +3683,6 @@ dependencies = [ name = "rustc_infer" version = "0.0.0" dependencies = [ - "arrayvec", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -3622,7 +3704,6 @@ name = "rustc_interface" version = "0.0.0" dependencies = [ "libc", - "once_cell", "rustc-rayon", "rustc_ast", "rustc_ast_lowering", @@ -3713,7 +3794,6 @@ dependencies = [ name = "rustc_metadata" version = "0.0.0" dependencies = [ - "flate2", "libc", "memmap", "rustc_ast", @@ -3721,6 +3801,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_expand", + "rustc_feature", "rustc_hir", "rustc_hir_pretty", "rustc_index", @@ -3731,6 +3812,7 @@ dependencies = [ "rustc_span", "rustc_target", "smallvec 1.4.2", + "snap", "stable_deref_trait", "tracing", "winapi 0.3.9", @@ -3740,9 +3822,7 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ - "arrayvec", "bitflags", - "byteorder", "chalk-ir", "measureme", "polonius-engine", @@ -3771,9 +3851,10 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "either", - "itertools 0.8.2", + "itertools 0.9.0", "log_settings", "polonius-engine", + "regex", "rustc_apfloat", "rustc_ast", "rustc_attr", @@ -3855,6 +3936,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", @@ -3895,7 +3977,7 @@ dependencies = [ name = "rustc_query_system" version = "0.0.0" dependencies = [ - "parking_lot 0.10.2", + "parking_lot 0.11.0", "rustc-rayon-core", "rustc_arena", "rustc_data_structures", @@ -3943,8 +4025,8 @@ dependencies = [ "rustc_data_structures", "rustc_hir", "rustc_hir_pretty", + "rustc_lexer", "rustc_middle", - "rustc_parse", "rustc_session", "rustc_span", "serde_json", @@ -4060,6 +4142,7 @@ dependencies = [ name = "rustc_traits" version = "0.0.0" dependencies = [ + "chalk-engine", "chalk-ir", "chalk-solve", "rustc_ast", @@ -4103,6 +4186,7 @@ dependencies = [ "rustc_hir_pretty", "rustc_index", "rustc_infer", + "rustc_macros", "rustc_middle", "rustc_session", "rustc_span", @@ -4125,9 +4209,10 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "itertools 0.8.2", + "expect-test", + "itertools 0.9.0", "minifier", - "pulldown-cmark", + "pulldown-cmark 0.8.0", "rustc-rayon", "serde", "serde_json", @@ -4170,7 +4255,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.20" +version = "1.4.22" dependencies = [ "annotate-snippets 0.6.1", "anyhow", @@ -4328,10 +4413,23 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.7.3", + "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpuid-bool", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] @@ -4402,6 +4500,12 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" +[[package]] +name = "snap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e" + [[package]] name = "socket2" version = "0.3.12" @@ -4422,9 +4526,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stacker" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92bc346006ae78c539d6ab2cf1a1532bc657b8339c464877a990ec82073c66f" +checksum = "21ccb4c06ec57bc82d0f610f1a2963d7648700e43a6f513e564b9c89f7991786" dependencies = [ "cc", "cfg-if", @@ -4973,9 +5077,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" dependencies = [ "serde", ] @@ -4993,9 +5097,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe233f4227389ab7df5b32649239da7ebe0b281824b4e84b342d04d3fd8c25e" +checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada" dependencies = [ "proc-macro2", "quote", @@ -5004,13 +5108,34 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db63662723c316b43ca36d833707cc93dff82a02ba3d7e354f342682cc8b3545" +checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5" dependencies = [ "lazy_static", ] +[[package]] +name = "tracing-log" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0f8c7178e13481ff6765bd169b33e8d554c5d2bbede5e32c356194be02b9b9" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6ccba2f8f16e0ed268fc765d9b7ff22e965e7185d32f8f1ec8294fe17d86e79" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.2.11" @@ -5018,14 +5143,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abd165311cc4d7a555ad11cc77a37756df836182db0d81aac908c8184c584f40" dependencies = [ "ansi_term 0.12.1", + "chrono", "lazy_static", "matchers", "parking_lot 0.11.0", "regex", + "serde", + "serde_json", "sharded-slab", "smallvec 1.4.2", "thread_local", "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "tracing-tree" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a3dc4774db3a6b2d66a4f8d8de670e874ec3ed55615860c994927419b32c5f" +dependencies = [ + "ansi_term 0.12.1", + "atty", + "chrono", + "termcolor", + "tracing", + "tracing-subscriber", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d8d9cc399c..02794d1028 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [workspace] members = [ "src/bootstrap", - "src/rustc", - "src/librustc_codegen_llvm", + "compiler/rustc", "library/std", "library/test", "src/tools/cargotest", @@ -10,6 +9,7 @@ members = [ "src/tools/compiletest", "src/tools/error_index_generator", "src/tools/linkchecker", + "src/tools/lint-docs", "src/tools/rustbook", "src/tools/unstable-book-gen", "src/tools/tidy", diff --git a/README.md b/README.md index 3399f7fe6c..d445bbdf6e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,10 @@ standard library, and documentation. [Rust]: https://www.rust-lang.org -**Note: this README is for _users_ rather than _contributors_.** +**Note: this README is for _users_ rather than _contributors_. +If you wish to _contribute_ to the compiler, you should read the +[Getting Started][gettingstarted] of the rustc-dev-guide instead of this +section.** ## Quick Start @@ -18,10 +21,6 @@ Read ["Installation"] from [The Book]. ## Installing from Source -**Note: If you wish to _contribute_ to the compiler, you should read the -[Getting Started][gettingstarted] of the rustc-dev-guide instead of this -section.** - The Rust build system uses a Python script called `x.py` to build the compiler, which manages the bootstrapping process. More information about it can be found by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. @@ -36,6 +35,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. * `python` 3 or 2.7 * GNU `make` 3.81 or later * `cmake` 3.4.3 or later + * `ninja` * `curl` * `git` * `ssl` which comes in `libssl-dev` or `openssl-devel` @@ -44,8 +44,8 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. 2. Clone the [source] with `git`: ```sh - $ git clone https://github.com/rust-lang/rust.git - $ cd rust + git clone https://github.com/rust-lang/rust.git + cd rust ``` [source]: https://github.com/rust-lang/rust @@ -57,7 +57,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. Copy the default `config.toml.example` to `config.toml` to get started. ```sh - $ cp config.toml.example config.toml + cp config.toml.example config.toml ``` If you plan to use `x.py install` to create an installation, it is recommended @@ -68,7 +68,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. 4. Build and install: ```sh - $ ./x.py build && ./x.py install + ./x.py build && ./x.py install ``` When complete, `./x.py install` will place several programs into @@ -106,27 +106,28 @@ build. ```sh # Update package mirrors (may be needed if you have a fresh install of MSYS2) - $ pacman -Sy pacman-mirrors + pacman -Sy pacman-mirrors # Install build tools needed for Rust. If you're building a 32-bit compiler, # then replace "x86_64" below with "i686". If you've already got git, python, # or CMake installed and in PATH you can remove them from this list. Note - # that it is important that you do **not** use the 'python2' and 'cmake' + # that it is important that you do **not** use the 'python2', 'cmake' and 'ninja' # packages from the 'msys2' subsystem. The build has historically been known # to fail with these packages. - $ pacman -S git \ + pacman -S git \ make \ diffutils \ tar \ mingw-w64-x86_64-python \ mingw-w64-x86_64-cmake \ - mingw-w64-x86_64-gcc + mingw-w64-x86_64-gcc \ + mingw-w64-x86_64-ninja ``` 4. Navigate to Rust's source code (or clone it), then build it: ```sh - $ ./x.py build && ./x.py install + ./x.py build && ./x.py install ``` #### MSVC @@ -144,7 +145,7 @@ With these dependencies installed, you can build the compiler in a `cmd.exe` shell with: ```sh -> python x.py build +python x.py build ``` Currently, building Rust only works with some known versions of Visual Studio. If @@ -153,8 +154,8 @@ 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. ```batch -> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" -> python x.py build +CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" +python x.py build ``` #### Specifying an ABI @@ -180,8 +181,8 @@ While it's not the recommended build system, this project also provides a configure script and makefile (the latter of which just invokes `x.py`). ```sh -$ ./configure -$ make && sudo make install +./configure +make && sudo make install ``` When using the configure script, the generated `config.mk` file may override the @@ -193,7 +194,7 @@ When using the configure script, the generated `config.mk` file may override the If you’d like to build the documentation, it’s almost the same: ```sh -$ ./x.py doc +./x.py doc ``` The generated documentation will appear under `doc` in the `build` directory for @@ -209,11 +210,17 @@ fetch snapshots, and an OS that can execute the available snapshot binaries. Snapshot binaries are currently built and tested on several platforms: -| Platform / Architecture | x86 | x86_64 | -|----------------------------|-----|--------| -| Windows (7, 8, 10, ...) | ✓ | ✓ | -| Linux (2.6.18 or later) | ✓ | ✓ | -| macOS (10.7 Lion or later) | ✓ | ✓ | +| Platform / Architecture | x86 | x86_64 | +|---------------------------------------------|-----|--------| +| Windows (7, 8, 10, ...) | ✓ | ✓ | +| Linux (kernel 2.6.32, glibc 2.11 or later) | ✓ | ✓ | +| macOS (10.7 Lion or later) | (\*) | ✓ | + +(\*): Apple dropped support for running 32-bit binaries starting from macOS 10.15 and iOS 11. +Due to this decision from Apple, the targets are no longer useful to our users. +Please read [our blog post][macx32] for more info. + +[macx32]: https://blog.rust-lang.org/2020/01/03/reducing-support-for-32-bit-apple-targets.html You may find that other platforms work, but these are our officially supported build environments that are most likely to work. @@ -235,6 +242,8 @@ The Rust community congregates in a few places: If you are interested in contributing to the Rust project, please take a look at the [Getting Started][gettingstarted] guide in the [rustc-dev-guide]. +[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org + ## License Rust is primarily distributed under the terms of both the MIT license diff --git a/RELEASES.md b/RELEASES.md index 10c4994f2d..62d30842b2 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -84,16 +84,15 @@ Compatibility Notes `Delimiter::None`. - [Moved support for the CloudABI target to tier 3.][75568] - [`linux-gnu` targets now require minimum kernel 2.6.32 and glibc 2.11.][74163] - -Internal Only --------- -- [Improved default settings for bootstrapping in `x.py`.][73964] You can read details about this change in the ["Changes to `x.py` defaults"](https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html) post on the Inside Rust blog. - [Added the `rustc-docs` component.][75560] This allows you to install and read the documentation for the compiler internal APIs. (Currently only available for `x86_64-unknown-linux-gnu`.) +Internal Only +-------- +- [Improved default settings for bootstrapping in `x.py`.][73964] You can read details about this change in the ["Changes To `x.py` Defaults"](https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html) post on the Inside Rust blog. + [1.47.0-cfg]: https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard -[76980]: https://github.com/rust-lang/rust/issues/76980 [75048]: https://github.com/rust-lang/rust/pull/75048/ [74163]: https://github.com/rust-lang/rust/pull/74163/ [71237]: https://github.com/rust-lang/rust/pull/71237/ diff --git a/src/rustc/Cargo.toml b/compiler/rustc/Cargo.toml similarity index 74% rename from src/rustc/Cargo.toml rename to compiler/rustc/Cargo.toml index 5e0f167bb3..6e6c0c71a1 100644 --- a/src/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -4,16 +4,12 @@ name = "rustc-main" version = "0.0.0" edition = '2018' -[[bin]] -name = "rustc_binary" -path = "rustc.rs" - [dependencies] -rustc_driver = { path = "../librustc_driver" } +rustc_driver = { path = "../rustc_driver" } # Make sure rustc_codegen_ssa ends up in the sysroot, because this # crate is intended to be used by codegen backends, which may not be in-tree. -rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } +rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } [dependencies.jemalloc-sys] version = '0.3.0' @@ -23,3 +19,4 @@ features = ['unprefixed_malloc_on_supported_platforms'] [features] jemalloc = ['jemalloc-sys'] llvm = ['rustc_driver/llvm'] +max_level_info = ['rustc_driver/max_level_info'] diff --git a/src/rustc/rustc.rs b/compiler/rustc/src/main.rs similarity index 100% rename from src/rustc/rustc.rs rename to compiler/rustc/src/main.rs diff --git a/src/librustc_apfloat/Cargo.toml b/compiler/rustc_apfloat/Cargo.toml similarity index 82% rename from src/librustc_apfloat/Cargo.toml rename to compiler/rustc_apfloat/Cargo.toml index 726965e1e7..306513f1a7 100644 --- a/src/librustc_apfloat/Cargo.toml +++ b/compiler/rustc_apfloat/Cargo.toml @@ -4,10 +4,6 @@ name = "rustc_apfloat" version = "0.0.0" edition = "2018" -[lib] -name = "rustc_apfloat" -path = "lib.rs" - [dependencies] bitflags = "1.2.1" smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_apfloat/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs similarity index 100% rename from src/librustc_apfloat/ieee.rs rename to compiler/rustc_apfloat/src/ieee.rs diff --git a/src/librustc_apfloat/lib.rs b/compiler/rustc_apfloat/src/lib.rs similarity index 99% rename from src/librustc_apfloat/lib.rs rename to compiler/rustc_apfloat/src/lib.rs index ba3adc4a13..4a845fcb69 100644 --- a/src/librustc_apfloat/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -30,7 +30,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![no_std] #![forbid(unsafe_code)] #![feature(nll)] diff --git a/src/librustc_apfloat/ppc.rs b/compiler/rustc_apfloat/src/ppc.rs similarity index 100% rename from src/librustc_apfloat/ppc.rs rename to compiler/rustc_apfloat/src/ppc.rs diff --git a/src/librustc_apfloat/tests/ieee.rs b/compiler/rustc_apfloat/tests/ieee.rs similarity index 100% rename from src/librustc_apfloat/tests/ieee.rs rename to compiler/rustc_apfloat/tests/ieee.rs diff --git a/src/librustc_apfloat/tests/ppc.rs b/compiler/rustc_apfloat/tests/ppc.rs similarity index 100% rename from src/librustc_apfloat/tests/ppc.rs rename to compiler/rustc_apfloat/tests/ppc.rs diff --git a/src/librustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml similarity index 63% rename from src/librustc_arena/Cargo.toml rename to compiler/rustc_arena/Cargo.toml index dfae956e2b..41701f3255 100644 --- a/src/librustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -4,10 +4,6 @@ name = "rustc_arena" version = "0.0.0" edition = "2018" -[lib] -name = "rustc_arena" -path = "lib.rs" - [dependencies] -rustc_data_structures = { path = "../librustc_data_structures" } +rustc_data_structures = { path = "../rustc_data_structures" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_arena/lib.rs b/compiler/rustc_arena/src/lib.rs similarity index 90% rename from src/librustc_arena/lib.rs rename to compiler/rustc_arena/src/lib.rs index 5e6a0340d1..166f7f53c4 100644 --- a/src/librustc_arena/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -8,16 +8,13 @@ //! This crate implements several kinds of arena. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(no_crate_inject, attr(deny(warnings))) )] -#![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![feature(raw_vec_internals)] +#![feature(new_uninit)] +#![feature(maybe_uninit_slice)] #![cfg_attr(test, feature(test))] -#![allow(deprecated)] - -extern crate alloc; use rustc_data_structures::cold_path; use smallvec::SmallVec; @@ -25,14 +22,11 @@ use smallvec::SmallVec; use std::alloc::Layout; use std::cell::{Cell, RefCell}; use std::cmp; -use std::intrinsics; use std::marker::{PhantomData, Send}; -use std::mem; +use std::mem::{self, MaybeUninit}; use std::ptr; use std::slice; -use alloc::raw_vec::RawVec; - /// An arena that can hold objects of only one type. pub struct TypedArena { /// A pointer to the next object to be allocated. @@ -52,7 +46,7 @@ pub struct TypedArena { struct TypedArenaChunk { /// The raw storage for the arena chunk. - storage: RawVec, + storage: Box<[MaybeUninit]>, /// The number of valid entries in the chunk. entries: usize, } @@ -60,7 +54,7 @@ struct TypedArenaChunk { impl TypedArenaChunk { #[inline] unsafe fn new(capacity: usize) -> TypedArenaChunk { - TypedArenaChunk { storage: RawVec::with_capacity(capacity), entries: 0 } + TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 } } /// Destroys this arena chunk. @@ -69,30 +63,25 @@ impl TypedArenaChunk { // The branch on needs_drop() is an -O1 performance optimization. // Without the branch, dropping TypedArena takes linear time. if mem::needs_drop::() { - let mut start = self.start(); - // Destroy all allocated objects. - for _ in 0..len { - ptr::drop_in_place(start); - start = start.offset(1); - } + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut self.storage[..len])); } } // Returns a pointer to the first allocated object. #[inline] - fn start(&self) -> *mut T { - self.storage.ptr() + fn start(&mut self) -> *mut T { + MaybeUninit::slice_as_mut_ptr(&mut self.storage) } // Returns a pointer to the end of the allocated space. #[inline] - fn end(&self) -> *mut T { + fn end(&mut self) -> *mut T { unsafe { if mem::size_of::() == 0 { // A pointer as large as possible for zero-sized elements. !0 as *mut T } else { - self.start().add(self.storage.capacity()) + self.start().add(self.storage.len()) } } } @@ -130,7 +119,7 @@ impl TypedArena { unsafe { if mem::size_of::() == 0 { - self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T); + self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T); let ptr = mem::align_of::() as *mut T; // Don't drop the object. This `write` is equivalent to `forget`. ptr::write(ptr, object); @@ -226,10 +215,10 @@ impl TypedArena { let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; last_chunk.entries = used_bytes / mem::size_of::(); - // If the previous chunk's capacity is less than HUGE_PAGE + // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.capacity(); + new_cap = last_chunk.storage.len(); if new_cap < HUGE_PAGE / elem_size { new_cap = new_cap.checked_mul(2).unwrap(); } @@ -239,7 +228,7 @@ impl TypedArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let chunk = TypedArenaChunk::::new(new_cap); + let mut chunk = TypedArenaChunk::::new(new_cap); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); @@ -301,7 +290,7 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena { chunk.destroy(chunk.entries); } } - // RawVec handles deallocation of `last_chunk` and `self.chunks`. + // Box handles deallocation of `last_chunk` and `self.chunks`. } } } @@ -309,11 +298,13 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena { unsafe impl Send for TypedArena {} pub struct DroplessArena { - /// A pointer to the next object to be allocated. - ptr: Cell<*mut u8>, + /// A pointer to the start of the free space. + start: Cell<*mut u8>, - /// A pointer to the end of the allocated area. When this pointer is - /// reached, a new chunk is allocated. + /// A pointer to the end of free space. + /// + /// The allocation proceeds from the end of the chunk towards the start. + /// When this pointer crosses the start pointer, a new chunk is allocated. end: Cell<*mut u8>, /// A vector of arena chunks. @@ -326,7 +317,7 @@ impl Default for DroplessArena { #[inline] fn default() -> DroplessArena { DroplessArena { - ptr: Cell::new(ptr::null_mut()), + start: Cell::new(ptr::null_mut()), end: Cell::new(ptr::null_mut()), chunks: Default::default(), } @@ -344,10 +335,10 @@ impl DroplessArena { // There is no need to update `last_chunk.entries` because that // field isn't used by `DroplessArena`. - // If the previous chunk's capacity is less than HUGE_PAGE + // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.capacity(); + new_cap = last_chunk.storage.len(); if new_cap < HUGE_PAGE { new_cap = new_cap.checked_mul(2).unwrap(); } @@ -357,8 +348,8 @@ impl DroplessArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let chunk = TypedArenaChunk::::new(new_cap); - self.ptr.set(chunk.start()); + let mut chunk = TypedArenaChunk::::new(new_cap); + self.start.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); } @@ -369,24 +360,17 @@ impl DroplessArena { /// request. #[inline] fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> { - let ptr = self.ptr.get() as usize; + let start = self.start.get() as usize; let end = self.end.get() as usize; + let align = layout.align(); let bytes = layout.size(); - // The allocation request fits into the current chunk iff: - // - // let aligned = align_to(ptr, align); - // ptr <= aligned && aligned + bytes <= end - // - // Except that we work with fixed width integers and need to be careful - // about potential overflow in the calcuation. If the overflow does - // happen, then we definitely don't have enough free and need to grow - // the arena. - let aligned = ptr.checked_add(align - 1)? & !(align - 1); - let new_ptr = aligned.checked_add(bytes)?; - if new_ptr <= end { - self.ptr.set(new_ptr as *mut u8); - Some(aligned as *mut u8) + + let new_end = end.checked_sub(bytes)? & !(align - 1); + if start <= new_end { + let new_end = new_end as *mut u8; + self.end.set(new_end); + Some(new_end) } else { None } diff --git a/src/librustc_arena/tests.rs b/compiler/rustc_arena/src/tests.rs similarity index 94% rename from src/librustc_arena/tests.rs rename to compiler/rustc_arena/src/tests.rs index 8e63bdf545..e8a1f2db1a 100644 --- a/src/librustc_arena/tests.rs +++ b/compiler/rustc_arena/src/tests.rs @@ -121,6 +121,17 @@ pub fn bench_typed_arena_clear(b: &mut Bencher) { }) } +#[bench] +pub fn bench_typed_arena_clear_100(b: &mut Bencher) { + let mut arena = TypedArena::default(); + b.iter(|| { + for _ in 0..100 { + arena.alloc(Point { x: 1, y: 2, z: 3 }); + } + arena.clear(); + }) +} + // Drop tests struct DropCounter<'a> { diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml new file mode 100644 index 0000000000..13e17a807c --- /dev/null +++ b/compiler/rustc_ast/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ast" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_serialize = { path = "../rustc_serialize" } +tracing = "0.1" +rustc_span = { path = "../rustc_span" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_macros = { path = "../rustc_macros" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +bitflags = "1.2.1" diff --git a/src/librustc_ast/README.md b/compiler/rustc_ast/README.md similarity index 100% rename from src/librustc_ast/README.md rename to compiler/rustc_ast/README.md diff --git a/src/librustc_ast/ast.rs b/compiler/rustc_ast/src/ast.rs similarity index 98% rename from src/librustc_ast/ast.rs rename to compiler/rustc_ast/src/ast.rs index 127a53cad2..95abf55291 100644 --- a/src/librustc_ast/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -96,6 +96,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, } impl PartialEq for Path { @@ -117,7 +118,7 @@ impl Path { // Convert a span and an identifier to the corresponding // one-segment path. pub fn from_ident(ident: Ident) -> Path { - Path { segments: vec![PathSegment::from_ident(ident)], span: ident.span } + Path { segments: vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None } } pub fn is_global(&self) -> bool { @@ -540,6 +541,7 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }`. pub rules: BlockCheckMode, pub span: Span, + pub tokens: Option, } /// A match pattern. @@ -586,7 +588,7 @@ impl Pat { _ => return None, }; - Some(P(Ty { kind, id: self.id, span: self.span })) + Some(P(Ty { kind, id: self.id, span: self.span, tokens: None })) } /// Walk top-down and call `it` in each place where a pattern occurs @@ -916,15 +918,20 @@ pub struct Stmt { pub id: NodeId, pub kind: StmtKind, pub span: Span, + pub tokens: Option, } impl Stmt { pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), - StmtKind::MacCall(mac) => StmtKind::MacCall( - mac.map(|(mac, _style, attrs)| (mac, MacStmtStyle::Semicolon, attrs)), - ), + StmtKind::MacCall(mac) => { + StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs }| MacCallStmt { + mac, + style: MacStmtStyle::Semicolon, + attrs, + })) + } kind => kind, }; self @@ -958,7 +965,14 @@ pub enum StmtKind { /// Just a trailing semi-colon. Empty, /// Macro. - MacCall(P<(MacCall, MacStmtStyle, AttrVec)>), + MacCall(P), +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct MacCallStmt { + pub mac: MacCall, + pub style: MacStmtStyle, + pub attrs: AttrVec, } #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)] @@ -1057,7 +1071,7 @@ pub struct Expr { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Expr, 104); +rustc_data_structures::static_assert_size!(Expr, 112); impl Expr { /// Returns `true` if this expression would be valid somewhere that expects a value; @@ -1157,7 +1171,7 @@ impl Expr { _ => return None, }; - Some(P(Ty { kind, id: self.id, span: self.span })) + Some(P(Ty { kind, id: self.id, span: self.span, tokens: None })) } pub fn precedence(&self) -> ExprPrecedence { @@ -1855,6 +1869,7 @@ pub struct Ty { pub id: NodeId, pub kind: TyKind, pub span: Span, + pub tokens: Option, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -1916,7 +1931,7 @@ pub enum TyKind { impl TyKind { pub fn is_implicit_self(&self) -> bool { - if let TyKind::ImplicitSelf = *self { true } else { false } + matches!(self, TyKind::ImplicitSelf) } pub fn is_unit(&self) -> bool { @@ -2133,7 +2148,7 @@ impl Param { /// Builds a `Param` object from `ExplicitSelf`. 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 }); + let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span, tokens: None }); let param = |mutbl, ty| Param { attrs, pat: P(Pat { @@ -2156,6 +2171,7 @@ impl Param { id: DUMMY_NODE_ID, kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }), span, + tokens: None, }), ), } @@ -2211,7 +2227,7 @@ pub enum Async { impl Async { pub fn is_async(self) -> bool { - if let Async::Yes { .. } = self { true } else { false } + matches!(self, Async::Yes { .. }) } /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item. @@ -2278,12 +2294,15 @@ impl FnRetTy { /// Module declaration. /// /// E.g., `mod foo;` or `mod foo { .. }`. -#[derive(Clone, Encodable, Decodable, Debug, Default)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct Mod { /// A span from the first token past `{` to the last token until `}`. /// For `mod foo;`, the inner span ranges from the first token /// to the last token in the external file. pub inner: Span, + /// `unsafe` keyword accepted syntactically for macro DSLs, but not + /// semantically by Rust. + pub unsafety: Unsafe, pub items: Vec>, /// `true` for `mod foo { .. }`; `false` for `mod foo;`. pub inline: bool, @@ -2291,9 +2310,12 @@ pub struct Mod { /// Foreign module declaration. /// -/// E.g., `extern { .. }` or `extern C { .. }`. +/// E.g., `extern { .. }` or `extern "C" { .. }`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct ForeignMod { + /// `unsafe` keyword accepted syntactically for macro DSLs, but not + /// semantically by Rust. + pub unsafety: Unsafe, pub abi: Option, pub items: Vec>, } @@ -2399,6 +2421,7 @@ impl rustc_serialize::Decodable for AttrId { pub struct AttrItem { pub path: Path, pub args: MacArgs, + pub tokens: Option, } /// A list of attributes. @@ -2468,7 +2491,12 @@ pub enum CrateSugar { JustCrate, } -pub type Visibility = Spanned; +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct Visibility { + pub kind: VisibilityKind, + pub span: Span, + pub tokens: Option, +} #[derive(Clone, Encodable, Decodable, Debug)] pub enum VisibilityKind { @@ -2480,7 +2508,7 @@ pub enum VisibilityKind { impl VisibilityKind { pub fn is_pub(&self) -> bool { - if let VisibilityKind::Public = *self { true } else { false } + matches!(self, VisibilityKind::Public) } } diff --git a/src/librustc_ast/ast/tests.rs b/compiler/rustc_ast/src/ast/tests.rs similarity index 100% rename from src/librustc_ast/ast/tests.rs rename to compiler/rustc_ast/src/ast/tests.rs diff --git a/src/librustc_ast/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs similarity index 96% rename from src/librustc_ast/attr/mod.rs rename to compiler/rustc_ast/src/attr/mod.rs index edcbce3e2c..2782869fb8 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -8,7 +8,7 @@ use crate::ast::{Path, PathSegment}; use crate::mut_visit::visit_clobber; use crate::ptr::P; use crate::token::{self, CommentKind, Token}; -use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; +use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_index::bit_set::GrowableBitSet; use rustc_span::source_map::{BytePos, Spanned}; @@ -16,7 +16,6 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use std::iter; -use std::ops::DerefMut; pub struct MarkedAttrs(GrowableBitSet); @@ -331,7 +330,7 @@ crate fn mk_attr_id() -> AttrId { } pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { - mk_attr_from_item(style, AttrItem { path, args }, span) + mk_attr_from_item(style, AttrItem { path, args, tokens: None }, span) } pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute { @@ -362,7 +361,7 @@ pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { } impl MetaItem { - fn token_trees_and_joints(&self) -> Vec { + fn token_trees_and_spacings(&self) -> Vec { let mut idents = vec![]; let mut last_pos = BytePos(0 as u32); for (i, segment) in self.path.segments.iter().enumerate() { @@ -375,7 +374,7 @@ impl MetaItem { idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into()); last_pos = segment.ident.span.hi(); } - idents.extend(self.kind.token_trees_and_joints(self.span)); + idents.extend(self.kind.token_trees_and_spacings(self.span)); idents } @@ -416,7 +415,7 @@ impl MetaItem { } } let span = span.with_hi(segments.last().unwrap().ident.span.hi()); - Path { span, segments } + Path { span, segments, tokens: None } } Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), @@ -448,7 +447,7 @@ impl MetaItemKind { if i > 0 { tts.push(TokenTree::token(token::Comma, span).into()); } - tts.extend(item.token_trees_and_joints()) + tts.extend(item.token_trees_and_spacings()) } MacArgs::Delimited( DelimSpan::from_single(span), @@ -459,7 +458,7 @@ impl MetaItemKind { } } - fn token_trees_and_joints(&self, span: Span) -> Vec { + fn token_trees_and_spacings(&self, span: Span) -> Vec { match *self { MetaItemKind::Word => vec![], MetaItemKind::NameValue(ref lit) => { @@ -471,7 +470,7 @@ impl MetaItemKind { if i > 0 { tokens.push(TokenTree::token(token::Comma, span).into()); } - tokens.extend(item.token_trees_and_joints()) + tokens.extend(item.token_trees_and_spacings()) } vec![ TokenTree::Delimited( @@ -554,9 +553,9 @@ impl NestedMetaItem { } } - fn token_trees_and_joints(&self) -> Vec { + fn token_trees_and_spacings(&self) -> Vec { match *self { - NestedMetaItem::MetaItem(ref item) => item.token_trees_and_joints(), + NestedMetaItem::MetaItem(ref item) => item.token_trees_and_spacings(), NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()], } } @@ -634,10 +633,7 @@ impl HasAttrs for StmtKind { StmtKind::Local(ref local) => local.attrs(), StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(), StmtKind::Empty | StmtKind::Item(..) => &[], - StmtKind::MacCall(ref mac) => { - let (_, _, ref attrs) = **mac; - attrs.attrs() - } + StmtKind::MacCall(ref mac) => mac.attrs.attrs(), } } @@ -647,8 +643,7 @@ impl HasAttrs for StmtKind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), StmtKind::Empty | StmtKind::Item(..) => {} StmtKind::MacCall(mac) => { - let (_mac, _style, attrs) = mac.deref_mut(); - attrs.visit_attrs(f); + mac.attrs.visit_attrs(f); } } } diff --git a/src/librustc_ast/crate_disambiguator.rs b/compiler/rustc_ast/src/crate_disambiguator.rs similarity index 100% rename from src/librustc_ast/crate_disambiguator.rs rename to compiler/rustc_ast/src/crate_disambiguator.rs diff --git a/src/librustc_ast/entry.rs b/compiler/rustc_ast/src/entry.rs similarity index 100% rename from src/librustc_ast/entry.rs rename to compiler/rustc_ast/src/entry.rs diff --git a/src/librustc_ast/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs similarity index 100% rename from src/librustc_ast/expand/allocator.rs rename to compiler/rustc_ast/src/expand/allocator.rs diff --git a/src/librustc_ast/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs similarity index 100% rename from src/librustc_ast/expand/mod.rs rename to compiler/rustc_ast/src/expand/mod.rs diff --git a/src/librustc_ast/lib.rs b/compiler/rustc_ast/src/lib.rs similarity index 90% rename from src/librustc_ast/lib.rs rename to compiler/rustc_ast/src/lib.rs index b556c1a446..6e47ff7d74 100644 --- a/src/librustc_ast/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -4,18 +4,18 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![feature(bool_to_option)] +#![doc( + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", + test(attr(deny(warnings))) +)] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` -#![feature(const_panic)] #![feature(const_fn_transmute)] +#![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(nll)] #![feature(or_patterns)] -#![feature(try_trait)] -#![feature(unicode_internals)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/librustc_ast/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs similarity index 97% rename from src/librustc_ast/mut_visit.rs rename to compiler/rustc_ast/src/mut_visit.rs index 965571aaa5..425ef83b57 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -14,7 +14,7 @@ use crate::tokenstream::*; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::sync::Lrc; -use rustc_span::source_map::{respan, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -451,7 +451,7 @@ pub fn noop_visit_ty_constraint( } pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { - let Ty { id, kind, span } = ty.deref_mut(); + let Ty { id, kind, span, tokens: _ } = ty.deref_mut(); vis.visit_id(id); match kind { TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {} @@ -490,7 +490,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { } pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: &mut T) { - let ForeignMod { abi: _, items } = foreign_mod; + let ForeignMod { unsafety: _, abi: _, items } = foreign_mod; items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } @@ -513,7 +513,7 @@ pub fn noop_visit_ident(Ident { name: _, span }: &mut Ident, vis: vis.visit_span(span); } -pub fn noop_visit_path(Path { segments, span }: &mut Path, vis: &mut T) { +pub fn noop_visit_path(Path { segments, span, tokens: _ }: &mut Path, vis: &mut T) { vis.visit_span(span); for PathSegment { ident, id, args } in segments { vis.visit_ident(ident); @@ -579,7 +579,7 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { 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 }) => { + AttrKind::Normal(AttrItem { path, args, tokens: _ }) => { vis.visit_path(path); visit_mac_args(args, vis); } @@ -709,7 +709,7 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { - let AttrItem { path, args } = item.deref_mut(); + let AttrItem { path, args, tokens: _ } = item.deref_mut(); vis.visit_path(path); visit_mac_args(args, vis); } @@ -871,7 +871,7 @@ pub fn noop_visit_mt(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mu } pub fn noop_visit_block(block: &mut P, vis: &mut T) { - let Block { id, stmts, rules: _, span } = block.deref_mut(); + let Block { id, stmts, rules: _, span, tokens: _ } = block.deref_mut(); vis.visit_id(id); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); vis.visit_span(span); @@ -970,18 +970,21 @@ pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { vis.visit_asyncness(asyncness); } -pub fn noop_visit_mod(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) { +pub fn noop_visit_mod(module: &mut Mod, vis: &mut T) { + let Mod { inner, unsafety: _, items, inline: _ } = module; vis.visit_span(inner); items.flat_map_in_place(|item| vis.flat_map_item(item)); } pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| { + let item_vis = + Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None }; let item = P(Item { ident: Ident::invalid(), attrs, id: DUMMY_NODE_ID, - vis: respan(span.shrink_to_lo(), VisibilityKind::Public), + vis: item_vis, span, kind: ItemKind::Mod(module), tokens: None, @@ -990,7 +993,7 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { let len = items.len(); if len == 0 { - let module = Mod { inner: span, items: vec![], inline: true }; + let module = Mod { inner: span, unsafety: Unsafe::No, items: vec![], inline: true }; Crate { module, attrs: vec![], span, proc_macros } } else if len == 1 { let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner(); @@ -1283,12 +1286,15 @@ pub fn noop_filter_map_expr(mut e: P, vis: &mut T) -> Optio } pub fn noop_flat_map_stmt( - Stmt { kind, mut span, mut id }: Stmt, + Stmt { kind, mut span, mut id, tokens }: Stmt, vis: &mut T, ) -> SmallVec<[Stmt; 1]> { vis.visit_id(&mut id); vis.visit_span(&mut span); - noop_flat_map_stmt_kind(kind, vis).into_iter().map(|kind| Stmt { id, kind, span }).collect() + noop_flat_map_stmt_kind(kind, vis) + .into_iter() + .map(|kind| Stmt { id, kind, span, tokens: tokens.clone() }) + .collect() } pub fn noop_flat_map_stmt_kind( @@ -1305,7 +1311,7 @@ pub fn noop_flat_map_stmt_kind( StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(), StmtKind::Empty => smallvec![StmtKind::Empty], StmtKind::MacCall(mut mac) => { - let (mac_, _semi, attrs) = mac.deref_mut(); + let MacCallStmt { mac: mac_, style: _, attrs } = mac.deref_mut(); vis.visit_mac(mac_); visit_thin_attrs(attrs, vis); smallvec![StmtKind::MacCall(mac)] @@ -1313,13 +1319,13 @@ pub fn noop_flat_map_stmt_kind( } } -pub fn noop_visit_vis(Spanned { node, span }: &mut Visibility, vis: &mut T) { - match node { +pub fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { + match &mut visibility.kind { VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {} VisibilityKind::Restricted { path, id } => { vis.visit_path(path); vis.visit_id(id); } } - vis.visit_span(span); + vis.visit_span(&mut visibility.span); } diff --git a/src/librustc_ast/node_id.rs b/compiler/rustc_ast/src/node_id.rs similarity index 100% rename from src/librustc_ast/node_id.rs rename to compiler/rustc_ast/src/node_id.rs diff --git a/src/librustc_ast/ptr.rs b/compiler/rustc_ast/src/ptr.rs similarity index 100% rename from src/librustc_ast/ptr.rs rename to compiler/rustc_ast/src/ptr.rs diff --git a/src/librustc_ast/token.rs b/compiler/rustc_ast/src/token.rs similarity index 97% rename from src/librustc_ast/token.rs rename to compiler/rustc_ast/src/token.rs index 7e58aab5a7..d5b3e87adc 100644 --- a/src/librustc_ast/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -173,6 +173,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { kw::Move, kw::Return, kw::True, + kw::Try, kw::Unsafe, kw::While, kw::Yield, @@ -251,17 +252,6 @@ pub enum TokenKind { /// similarly to symbols in string literal tokens. DocComment(CommentKind, ast::AttrStyle, Symbol), - // Junk. These carry no data because we don't really care about the data - // they *would* carry, and don't really want to allocate a new ident for - // them. Instead, users could extract that from the associated span. - /// Whitespace. - Whitespace, - /// A comment. - Comment, - Shebang(Symbol), - /// A completely invalid token which should be skipped. - Unknown(Symbol), - Eof, } @@ -331,7 +321,7 @@ impl Token { /// Some token that will be thrown away later. pub fn dummy() -> Self { - Token::new(TokenKind::Whitespace, DUMMY_SP) + Token::new(TokenKind::Question, DUMMY_SP) } /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary. @@ -360,7 +350,7 @@ impl Token { pub fn is_op(&self) -> bool { match self.kind { OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | Whitespace | Comment | Shebang(..) | Eof => false, + | Lifetime(..) | Interpolated(..) | Eof => false, _ => true, } } @@ -676,8 +666,7 @@ impl Token { Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | DocComment(..) | Whitespace | Comment - | Shebang(..) | Unknown(..) | Eof => return None, + | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None, }; Some(Token::new(kind, self.span.to(joint.span))) @@ -711,7 +700,7 @@ pub enum Nonterminal { // `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Nonterminal, 40); +rustc_data_structures::static_assert_size!(Nonterminal, 48); #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)] pub enum NonterminalKind { diff --git a/src/librustc_ast/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs similarity index 93% rename from src/librustc_ast/tokenstream.rs rename to compiler/rustc_ast/src/tokenstream.rs index 151acddae8..f201f0b5c6 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -83,7 +83,7 @@ impl TokenTree { } pub fn joint(self) -> TokenStream { - TokenStream::new(vec![(self, Joint)]) + TokenStream::new(vec![(self, Spacing::Joint)]) } pub fn token(kind: TokenKind, span: Span) -> TokenTree { @@ -125,22 +125,20 @@ where /// instead of a representation of the abstract syntax tree. /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat. #[derive(Clone, Debug, Default, Encodable, Decodable)] -pub struct TokenStream(pub Lrc>); +pub struct TokenStream(pub Lrc>); -pub type TreeAndJoint = (TokenTree, IsJoint); +pub type TreeAndSpacing = (TokenTree, Spacing); // `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] rustc_data_structures::static_assert_size!(TokenStream, 8); #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable)] -pub enum IsJoint { +pub enum Spacing { + Alone, Joint, - NonJoint, } -use IsJoint::*; - impl TokenStream { /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream` /// separating the two arguments with a comma for diagnostic suggestions. @@ -153,7 +151,7 @@ impl TokenStream { let sp = match (&ts, &next) { (_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue, ( - (TokenTree::Token(token_left), NonJoint), + (TokenTree::Token(token_left), Spacing::Alone), (TokenTree::Token(token_right), _), ) if ((token_left.is_ident() && !token_left.is_reserved_ident()) || token_left.is_lit()) @@ -162,11 +160,11 @@ impl TokenStream { { token_left.span } - ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(), + ((TokenTree::Delimited(sp, ..), Spacing::Alone), _) => sp.entire(), _ => continue, }; let sp = sp.shrink_to_hi(); - let comma = (TokenTree::token(token::Comma, sp), NonJoint); + let comma = (TokenTree::token(token::Comma, sp), Spacing::Alone); suggestion = Some((pos, comma, sp)); } } @@ -184,19 +182,19 @@ impl TokenStream { impl From for TokenStream { fn from(tree: TokenTree) -> TokenStream { - TokenStream::new(vec![(tree, NonJoint)]) + TokenStream::new(vec![(tree, Spacing::Alone)]) } } -impl From for TreeAndJoint { - fn from(tree: TokenTree) -> TreeAndJoint { - (tree, NonJoint) +impl From for TreeAndSpacing { + fn from(tree: TokenTree) -> TreeAndSpacing { + (tree, Spacing::Alone) } } impl iter::FromIterator for TokenStream { fn from_iter>(iter: I) -> Self { - TokenStream::new(iter.into_iter().map(Into::into).collect::>()) + TokenStream::new(iter.into_iter().map(Into::into).collect::>()) } } @@ -209,7 +207,7 @@ impl PartialEq for TokenStream { } impl TokenStream { - pub fn new(streams: Vec) -> TokenStream { + pub fn new(streams: Vec) -> TokenStream { TokenStream(Lrc::new(streams)) } @@ -320,11 +318,11 @@ impl TokenStreamBuilder { // If `self` is not empty and the last tree within the last stream is a // token tree marked with `Joint`... if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut() { - if let Some((TokenTree::Token(last_token), Joint)) = last_stream_lrc.last() { + if let Some((TokenTree::Token(last_token), Spacing::Joint)) = last_stream_lrc.last() { // ...and `stream` is not empty and the first tree within it is // a token tree... let TokenStream(ref mut stream_lrc) = stream; - if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() { + if let Some((TokenTree::Token(token), spacing)) = stream_lrc.first() { // ...and the two tokens can be glued together... if let Some(glued_tok) = last_token.glue(&token) { // ...then do so, by overwriting the last token @@ -337,8 +335,7 @@ impl TokenStreamBuilder { // Overwrite the last token tree with the merged // token. let last_vec_mut = Lrc::make_mut(last_stream_lrc); - *last_vec_mut.last_mut().unwrap() = - (TokenTree::Token(glued_tok), *is_joint); + *last_vec_mut.last_mut().unwrap() = (TokenTree::Token(glued_tok), *spacing); // Remove the first token tree from `stream`. (This // is almost always the only tree in `stream`.) @@ -375,7 +372,7 @@ impl Iterator for Cursor { type Item = TokenTree; fn next(&mut self) -> Option { - self.next_with_joint().map(|(tree, _)| tree) + self.next_with_spacing().map(|(tree, _)| tree) } } @@ -384,7 +381,7 @@ impl Cursor { Cursor { stream, index: 0 } } - pub fn next_with_joint(&mut self) -> Option { + pub fn next_with_spacing(&mut self) -> Option { if self.index < self.stream.len() { self.index += 1; Some(self.stream.0[self.index - 1].clone()) diff --git a/src/librustc_ast/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs similarity index 100% rename from src/librustc_ast/util/classify.rs rename to compiler/rustc_ast/src/util/classify.rs diff --git a/src/librustc_ast/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs similarity index 100% rename from src/librustc_ast/util/comments.rs rename to compiler/rustc_ast/src/util/comments.rs diff --git a/src/librustc_ast/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs similarity index 100% rename from src/librustc_ast/util/comments/tests.rs rename to compiler/rustc_ast/src/util/comments/tests.rs diff --git a/src/librustc_ast/util/lev_distance.rs b/compiler/rustc_ast/src/util/lev_distance.rs similarity index 97% rename from src/librustc_ast/util/lev_distance.rs rename to compiler/rustc_ast/src/util/lev_distance.rs index d4e0e3ba05..754b1f1338 100644 --- a/src/librustc_ast/util/lev_distance.rs +++ b/compiler/rustc_ast/src/util/lev_distance.rs @@ -103,6 +103,7 @@ fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> fn sort_by_words(name: &str) -> String { let mut split_words: Vec<&str> = name.split('_').collect(); - split_words.sort(); + // We are sorting primitive &strs and can use unstable sort here + split_words.sort_unstable(); split_words.join("_") } diff --git a/src/librustc_ast/util/lev_distance/tests.rs b/compiler/rustc_ast/src/util/lev_distance/tests.rs similarity index 100% rename from src/librustc_ast/util/lev_distance/tests.rs rename to compiler/rustc_ast/src/util/lev_distance/tests.rs diff --git a/src/librustc_ast/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs similarity index 100% rename from src/librustc_ast/util/literal.rs rename to compiler/rustc_ast/src/util/literal.rs diff --git a/src/librustc_ast/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs similarity index 100% rename from src/librustc_ast/util/parser.rs rename to compiler/rustc_ast/src/util/parser.rs diff --git a/src/librustc_ast/visit.rs b/compiler/rustc_ast/src/visit.rs similarity index 99% rename from src/librustc_ast/visit.rs rename to compiler/rustc_ast/src/visit.rs index b65a88cb90..86fd87f6c4 100644 --- a/src/librustc_ast/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -692,7 +692,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr), StmtKind::Empty => {} StmtKind::MacCall(ref mac) => { - let (ref mac, _, ref attrs) = **mac; + let MacCallStmt { ref mac, style: _, ref attrs } = **mac; visitor.visit_mac(mac); for attr in attrs.iter() { visitor.visit_attribute(attr); @@ -879,7 +879,7 @@ 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.node { + if let VisibilityKind::Restricted { ref path, id } = vis.kind { visitor.visit_path(path, id); } } diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml new file mode 100644 index 0000000000..177a9066ed --- /dev/null +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ast_lowering" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +tracing = "0.1" +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_index = { path = "../rustc_index" } +rustc_span = { path = "../rustc_span" } +rustc_errors = { path = "../rustc_errors" } +rustc_session = { path = "../rustc_session" } +rustc_ast = { path = "../rustc_ast" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_ast_lowering/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs similarity index 99% rename from src/librustc_ast_lowering/expr.rs rename to compiler/rustc_ast_lowering/src/expr.rs index df452825bb..c97f80cf09 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1121,7 +1121,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // features. We check that at least one type is available for // the current target. let reg_class = reg.reg_class(); - let mut required_features = vec![]; + let mut required_features: Vec<&str> = vec![]; for &(_, feature) in reg_class.supported_types(asm_arch) { if let Some(feature) = feature { if self.sess.target_features.contains(&Symbol::intern(feature)) { @@ -1135,7 +1135,8 @@ impl<'hir> LoweringContext<'_, 'hir> { break; } } - required_features.sort(); + // We are sorting primitive strs here and can use unstable sort here + required_features.sort_unstable(); required_features.dedup(); match &required_features[..] { [] => {} diff --git a/src/librustc_ast_lowering/item.rs b/compiler/rustc_ast_lowering/src/item.rs similarity index 99% rename from src/librustc_ast_lowering/item.rs rename to compiler/rustc_ast_lowering/src/item.rs index f3309afec7..617cacee0e 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -27,7 +27,7 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { impl ItemLowerer<'_, '_, '_> { fn with_trait_impl_ref(&mut self, impl_ref: &Option, f: impl FnOnce(&mut Self)) { let old = self.lctx.is_in_trait_impl; - self.lctx.is_in_trait_impl = if let &None = impl_ref { false } else { true }; + self.lctx.is_in_trait_impl = impl_ref.is_some(); f(self); self.lctx.is_in_trait_impl = old; } @@ -251,7 +251,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(orig_name), ItemKind::Use(ref use_tree) => { // Start with an empty prefix. - let prefix = Path { segments: vec![], span: use_tree.span }; + let prefix = Path { segments: vec![], span: use_tree.span, tokens: None }; self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs) } @@ -488,7 +488,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *ident = tree.ident(); // First, apply the prefix to the path. - let mut path = Path { segments, span: path.span }; + let mut path = Path { segments, span: path.span, tokens: None }; // Correctly resolve `self` imports. if path.segments.len() > 1 @@ -540,8 +540,11 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::Use(path, hir::UseKind::Single) } UseTreeKind::Glob => { - let path = - self.lower_path(id, &Path { segments, span: path.span }, ParamMode::Explicit); + let path = self.lower_path( + id, + &Path { segments, span: path.span, tokens: None }, + ParamMode::Explicit, + ); hir::ItemKind::Use(path, hir::UseKind::Glob) } UseTreeKind::Nested(ref trees) => { @@ -569,7 +572,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // for that we return the `{}` import (called the // `ListStem`). - let prefix = Path { segments, span: prefix.span.to(path.span) }; + let prefix = Path { segments, span: prefix.span.to(path.span), tokens: None }; // Add all the nested `PathListItem`s to the HIR. for &(ref use_tree, id) in trees { @@ -927,7 +930,7 @@ impl<'hir> LoweringContext<'_, 'hir> { v: &Visibility, explicit_owner: Option, ) -> hir::Visibility<'hir> { - let node = match v.node { + let node = match v.kind { VisibilityKind::Public => hir::VisibilityKind::Public, VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar), VisibilityKind::Restricted { ref path, id } => { diff --git a/src/librustc_ast_lowering/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs similarity index 99% rename from src/librustc_ast_lowering/lib.rs rename to compiler/rustc_ast_lowering/src/lib.rs index 586355fe61..a28d022c66 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -967,6 +967,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AttrKind::Normal(ref item) => AttrKind::Normal(AttrItem { path: item.path.clone(), args: self.lower_mac_args(&item.args), + tokens: None, }), AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data), }; @@ -1106,6 +1107,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: node_id, kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), span: constraint.span, + tokens: None, }, itctx, ); diff --git a/src/librustc_ast_lowering/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs similarity index 100% rename from src/librustc_ast_lowering/pat.rs rename to compiler/rustc_ast_lowering/src/pat.rs diff --git a/src/librustc_ast_lowering/path.rs b/compiler/rustc_ast_lowering/src/path.rs similarity index 100% rename from src/librustc_ast_lowering/path.rs rename to compiler/rustc_ast_lowering/src/path.rs diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml new file mode 100644 index 0000000000..9ed6bdc3d6 --- /dev/null +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ast_passes" +version = "0.0.0" +edition = "2018" + +[dependencies] +itertools = "0.9" +tracing = "0.1" +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_feature = { path = "../rustc_feature" } +rustc_parse = { path = "../rustc_parse" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_ast = { path = "../rustc_ast" } diff --git a/src/librustc_ast_passes/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs similarity index 98% rename from src/librustc_ast_passes/ast_validation.rs rename to compiler/rustc_ast_passes/src/ast_validation.rs index a01dd8c939..232ee35c4f 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -198,13 +198,13 @@ impl<'a> AstValidator<'a> { } fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { - if let VisibilityKind::Inherited = vis.node { + if let VisibilityKind::Inherited = vis.kind { return; } let mut err = struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier"); - if vis.node.is_pub() { + if vis.kind.is_pub() { err.span_label(vis.span, "`pub` not permitted here because it's implied"); } if let Some(note) = note { @@ -868,10 +868,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .emit(); } - if !bounds - .iter() - .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) - { + if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) { self.err_handler().span_err(ty.span, "at least one trait must be specified"); } @@ -990,12 +987,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.error_item_without_body(item.span, "function", msg, " { }"); } } - ItemKind::ForeignMod(_) => { + ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => { let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.invalid_visibility( &item.vis, Some("place qualifiers on individual foreign items instead"), ); + if let Unsafe::Yes(span) = unsafety { + self.err_handler().span_err(span, "extern block cannot be declared unsafe"); + } visit::walk_item(self, item); self.extern_mod = old_item; return; // Avoid visiting again. @@ -1029,7 +1029,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; } - ItemKind::Mod(Mod { inline, .. }) => { + ItemKind::Mod(Mod { inline, unsafety, .. }) => { + if let Unsafe::Yes(span) = unsafety { + self.err_handler().span_err(span, "module cannot be declared unsafe"); + } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). if !inline && !self.session.contains_name(&item.attrs, sym::path) { self.check_mod_file_item_asciionly(item.ident); diff --git a/src/librustc_ast_passes/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs similarity index 95% rename from src/librustc_ast_passes/feature_gate.rs rename to compiler/rustc_ast_passes/src/feature_gate.rs index 0ee8ef55e6..00d3db7376 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -260,7 +260,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { cfg => doc_cfg masked => doc_masked spotlight => doc_spotlight - alias => doc_alias keyword => doc_keyword ); } @@ -594,7 +593,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_vis(&mut self, vis: &'a ast::Visibility) { - if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { + if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.kind { gate_feature_post!( &self, crate_visibility_modifier, @@ -608,6 +607,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { pub fn check_crate(krate: &ast::Crate, sess: &Session) { maybe_stage_features(sess, krate); + check_incompatible_features(sess); let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() }; let spans = sess.parse_sess.gated_spans.spans.borrow(); @@ -677,3 +677,36 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { } } } + +fn check_incompatible_features(sess: &Session) { + let features = sess.features_untracked(); + + let declared_features = features + .declared_lang_features + .iter() + .copied() + .map(|(name, span, _)| (name, span)) + .chain(features.declared_lib_features.iter().copied()); + + for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES + .iter() + .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2)) + { + if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) { + if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) + { + let spans = vec![f1_span, f2_span]; + sess.struct_span_err( + spans.clone(), + &format!( + "features `{}` and `{}` are incompatible, using them at the same time \ + is not allowed", + f1_name, f2_name + ), + ) + .help("remove one of these features") + .emit(); + } + } + } +} diff --git a/src/librustc_ast_passes/lib.rs b/compiler/rustc_ast_passes/src/lib.rs similarity index 100% rename from src/librustc_ast_passes/lib.rs rename to compiler/rustc_ast_passes/src/lib.rs diff --git a/src/librustc_ast_passes/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs similarity index 100% rename from src/librustc_ast_passes/node_count.rs rename to compiler/rustc_ast_passes/src/node_count.rs diff --git a/src/librustc_ast_passes/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs similarity index 100% rename from src/librustc_ast_passes/show_span.rs rename to compiler/rustc_ast_passes/src/show_span.rs diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml new file mode 100644 index 0000000000..f447bc7f4e --- /dev/null +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ast_pretty" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +tracing = "0.1" +rustc_span = { path = "../rustc_span" } +rustc_ast = { path = "../rustc_ast" } +rustc_target = { path = "../rustc_target" } diff --git a/src/librustc_ast_pretty/helpers.rs b/compiler/rustc_ast_pretty/src/helpers.rs similarity index 100% rename from src/librustc_ast_pretty/helpers.rs rename to compiler/rustc_ast_pretty/src/helpers.rs diff --git a/src/librustc_ast_pretty/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs similarity index 100% rename from src/librustc_ast_pretty/lib.rs rename to compiler/rustc_ast_pretty/src/lib.rs diff --git a/src/librustc_ast_pretty/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs similarity index 100% rename from src/librustc_ast_pretty/pp.rs rename to compiler/rustc_ast_pretty/src/pp.rs diff --git a/src/librustc_ast_pretty/pprust.rs b/compiler/rustc_ast_pretty/src/pprust.rs similarity index 99% rename from src/librustc_ast_pretty/pprust.rs rename to compiler/rustc_ast_pretty/src/pprust.rs index cb48deb588..d16b541c69 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/compiler/rustc_ast_pretty/src/pprust.rs @@ -289,10 +289,6 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option) doc_comment_to_string(comment_kind, attr_style, data) } token::Eof => "".to_string(), - token::Whitespace => " ".to_string(), - token::Comment => "/* */".to_string(), - token::Shebang(s) => format!("/* shebang: {}*/", s), - token::Unknown(s) => s.to_string(), token::Interpolated(ref nt) => nonterminal_to_string(nt), } @@ -1143,7 +1139,11 @@ impl<'a> State<'a> { self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs); } ast::ItemKind::Mod(ref _mod) => { - self.head(visibility_qualified(&item.vis, "mod")); + self.head(to_string(|s| { + s.print_visibility(&item.vis); + s.print_unsafety(_mod.unsafety); + s.word("mod"); + })); self.print_ident(item.ident); if _mod.inline || self.is_expanded { @@ -1158,7 +1158,10 @@ impl<'a> State<'a> { } } ast::ItemKind::ForeignMod(ref nmod) => { - self.head("extern"); + self.head(to_string(|s| { + s.print_unsafety(nmod.unsafety); + s.word("extern"); + })); if let Some(abi) = nmod.abi { self.print_literal(&abi.as_lit()); self.nbsp(); @@ -1356,7 +1359,7 @@ impl<'a> State<'a> { } crate fn print_visibility(&mut self, vis: &ast::Visibility) { - match vis.node { + match vis.kind { ast::VisibilityKind::Public => self.word_nbsp("pub"), ast::VisibilityKind::Crate(sugar) => match sugar { ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"), @@ -1507,11 +1510,10 @@ impl<'a> State<'a> { self.s.word(";"); } ast::StmtKind::MacCall(ref mac) => { - let (ref mac, style, ref attrs) = **mac; self.space_if_not_bol(); - self.print_outer_attributes(attrs); - self.print_mac(mac); - if style == ast::MacStmtStyle::Semicolon { + self.print_outer_attributes(&mac.attrs); + self.print_mac(&mac.mac); + if mac.style == ast::MacStmtStyle::Semicolon { self.s.word(";"); } } diff --git a/src/librustc_ast_pretty/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs similarity index 89% rename from src/librustc_ast_pretty/pprust/tests.rs rename to compiler/rustc_ast_pretty/src/pprust/tests.rs index fdbf3feb90..b1a73a0bf0 100644 --- a/src/librustc_ast_pretty/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -1,7 +1,6 @@ use super::*; use rustc_ast as ast; -use rustc_span::source_map::respan; use rustc_span::symbol::Ident; use rustc_span::with_default_session_globals; @@ -45,7 +44,11 @@ fn test_variant_to_string() { let var = ast::Variant { ident, - vis: respan(rustc_span::DUMMY_SP, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: rustc_span::DUMMY_SP, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, attrs: Vec::new(), id: ast::DUMMY_NODE_ID, data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml new file mode 100644 index 0000000000..5f941a0a65 --- /dev/null +++ b/compiler/rustc_attr/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_attr" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_errors = { path = "../rustc_errors" } +rustc_span = { path = "../rustc_span" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_feature = { path = "../rustc_feature" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_macros = { path = "../rustc_macros" } +rustc_session = { path = "../rustc_session" } +rustc_ast = { path = "../rustc_ast" } +version_check = "0.9" diff --git a/src/librustc_attr/builtin.rs b/compiler/rustc_attr/src/builtin.rs similarity index 95% rename from src/librustc_attr/builtin.rs rename to compiler/rustc_attr/src/builtin.rs index b8929fe088..94e2a40e1f 100644 --- a/src/librustc_attr/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -145,8 +145,6 @@ pub struct ConstStability { pub feature: Symbol, /// whether the function has a `#[rustc_promotable]` attribute pub promotable: bool, - /// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute - pub allow_const_fn_ptr: bool, } /// The available stability levels. @@ -160,10 +158,10 @@ pub enum StabilityLevel { impl StabilityLevel { pub fn is_unstable(&self) -> bool { - if let StabilityLevel::Unstable { .. } = *self { true } else { false } + matches!(self, StabilityLevel::Unstable { .. }) } pub fn is_stable(&self) -> bool { - if let StabilityLevel::Stable { .. } = *self { true } else { false } + matches!(self, StabilityLevel::Stable { .. }) } } @@ -190,7 +188,6 @@ where let mut stab: Option = None; let mut const_stab: Option = None; let mut promotable = false; - let mut allow_const_fn_ptr = false; let diagnostic = &sess.parse_sess.span_diagnostic; 'outer: for attr in attrs_iter { @@ -200,7 +197,6 @@ where sym::unstable, sym::stable, sym::rustc_promotable, - sym::rustc_allow_const_fn_ptr, ] .iter() .any(|&s| attr.has_name(s)) @@ -215,9 +211,6 @@ where if attr.has_name(sym::rustc_promotable) { promotable = true; } - if attr.has_name(sym::rustc_allow_const_fn_ptr) { - allow_const_fn_ptr = true; - } // attributes with data else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta { let meta = meta.as_ref().unwrap(); @@ -301,7 +294,7 @@ where .emit(); }; match issue.parse() { - Ok(num) if num == 0 => { + Ok(0) => { emit_diag( "`issue` must not be \"0\", \ use \"none\" instead", @@ -360,12 +353,8 @@ where if sym::unstable == meta_name { stab = Some(Stability { level, feature }); } else { - const_stab = Some(ConstStability { - level, - feature, - promotable: false, - allow_const_fn_ptr: false, - }); + const_stab = + Some(ConstStability { level, feature, promotable: false }); } } (None, _, _) => { @@ -440,12 +429,8 @@ where if sym::stable == meta_name { stab = Some(Stability { level, feature }); } else { - const_stab = Some(ConstStability { - level, - feature, - promotable: false, - allow_const_fn_ptr: false, - }); + const_stab = + Some(ConstStability { level, feature, promotable: false }); } } (None, _) => { @@ -464,18 +449,16 @@ where } // Merge the const-unstable info into the stability info - if promotable || allow_const_fn_ptr { + if promotable { if let Some(ref mut stab) = const_stab { stab.promotable = promotable; - stab.allow_const_fn_ptr = allow_const_fn_ptr; } else { struct_span_err!( diagnostic, item_sp, E0717, - "rustc_promotable and rustc_allow_const_fn_ptr attributes \ - must be paired with either a rustc_const_unstable or a rustc_const_stable \ - attribute" + "`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` \ + or a `rustc_const_stable` attribute" ) .emit(); } @@ -1022,14 +1005,21 @@ pub fn find_transparency( pub fn allow_internal_unstable<'a>( sess: &'a Session, - attrs: &[Attribute], + attrs: &'a [Attribute], ) -> Option + 'a> { - let attr = sess.find_by_name(attrs, sym::allow_internal_unstable)?; - let list = attr.meta_item_list().or_else(|| { - sess.diagnostic() - .span_err(attr.span, "allow_internal_unstable expects list of feature names"); - None - })?; + let attrs = sess.filter_by_name(attrs, sym::allow_internal_unstable); + let list = attrs + .filter_map(move |attr| { + attr.meta_item_list().or_else(|| { + sess.diagnostic().span_err( + attr.span, + "`allow_internal_unstable` expects a list of feature names", + ); + None + }) + }) + .flatten(); + Some(list.into_iter().filter_map(move |it| { let name = it.ident().map(|ident| ident.name); if name.is_none() { diff --git a/src/librustc_attr/lib.rs b/compiler/rustc_attr/src/lib.rs similarity index 100% rename from src/librustc_attr/lib.rs rename to compiler/rustc_attr/src/lib.rs diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml new file mode 100644 index 0000000000..c397a85412 --- /dev/null +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_builtin_macros" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_parse_format = { path = "../rustc_parse_format" } +tracing = "0.1" +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_feature = { path = "../rustc_feature" } +rustc_parse = { path = "../rustc_parse" } +rustc_target = { path = "../rustc_target" } +rustc_session = { path = "../rustc_session" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } +rustc_expand = { path = "../rustc_expand" } +rustc_span = { path = "../rustc_span" } diff --git a/src/librustc_builtin_macros/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs similarity index 99% rename from src/librustc_builtin_macros/asm.rs rename to compiler/rustc_builtin_macros/src/asm.rs index 5dafd6b77a..09985959b6 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -368,7 +368,7 @@ fn parse_reg<'a>( explicit_reg: &mut bool, ) -> Result> { p.expect(&token::OpenDelim(token::DelimToken::Paren))?; - let result = match p.token.kind { + let result = match p.token.uninterpolate().kind { token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name), token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => { *explicit_reg = true; diff --git a/src/librustc_builtin_macros/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs similarity index 100% rename from src/librustc_builtin_macros/assert.rs rename to compiler/rustc_builtin_macros/src/assert.rs diff --git a/src/librustc_builtin_macros/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs similarity index 100% rename from src/librustc_builtin_macros/cfg.rs rename to compiler/rustc_builtin_macros/src/cfg.rs diff --git a/src/librustc_builtin_macros/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs similarity index 100% rename from src/librustc_builtin_macros/cfg_accessible.rs rename to compiler/rustc_builtin_macros/src/cfg_accessible.rs diff --git a/src/librustc_builtin_macros/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs similarity index 92% rename from src/librustc_builtin_macros/cmdline_attrs.rs rename to compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 34e2accc61..5ed8b69d92 100644 --- a/src/librustc_builtin_macros/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -15,7 +15,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - ); let start_span = parser.token.span; - let AttrItem { path, args } = match parser.parse_attr_item() { + let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item() { Ok(ai) => ai, Err(mut err) => { err.emit(); diff --git a/src/librustc_builtin_macros/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs similarity index 100% rename from src/librustc_builtin_macros/compile_error.rs rename to compiler/rustc_builtin_macros/src/compile_error.rs diff --git a/src/librustc_builtin_macros/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs similarity index 100% rename from src/librustc_builtin_macros/concat.rs rename to compiler/rustc_builtin_macros/src/concat.rs diff --git a/src/librustc_builtin_macros/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs similarity index 84% rename from src/librustc_builtin_macros/concat_idents.rs rename to compiler/rustc_builtin_macros/src/concat_idents.rs index 8223cdda07..209158ce39 100644 --- a/src/librustc_builtin_macros/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -27,15 +27,15 @@ pub fn expand_concat_idents<'cx>( } } } else { - match e { - TokenTree::Token(Token { kind: token::Ident(name, _), .. }) => { - res_str.push_str(&name.as_str()) - } - _ => { - cx.span_err(sp, "concat_idents! requires ident args."); - return DummyResult::any(sp); + if let TokenTree::Token(token) = e { + if let Some((ident, _)) = token.ident() { + res_str.push_str(&ident.name.as_str()); + continue; } } + + cx.span_err(sp, "concat_idents! requires ident args."); + return DummyResult::any(sp); } } @@ -61,6 +61,7 @@ pub fn expand_concat_idents<'cx>( id: ast::DUMMY_NODE_ID, kind: ast::TyKind::Path(None, ast::Path::from_ident(self.ident)), span: self.ident.span, + tokens: None, })) } } diff --git a/src/librustc_builtin_macros/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/bounds.rs rename to compiler/rustc_builtin_macros/src/deriving/bounds.rs diff --git a/src/librustc_builtin_macros/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/clone.rs rename to compiler/rustc_builtin_macros/src/deriving/clone.rs diff --git a/src/librustc_builtin_macros/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/cmp/eq.rs rename to compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs diff --git a/src/librustc_builtin_macros/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/cmp/ord.rs rename to compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/cmp/partial_eq.rs rename to compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/cmp/partial_ord.rs rename to compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs diff --git a/src/librustc_builtin_macros/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs similarity index 99% rename from src/librustc_builtin_macros/deriving/debug.rs rename to compiler/rustc_builtin_macros/src/deriving/debug.rs index 120e859f2b..d84b395647 100644 --- a/src/librustc_builtin_macros/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -133,5 +133,5 @@ fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P) -> as span: sp, attrs: ast::AttrVec::new(), }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp, tokens: None } } diff --git a/src/librustc_builtin_macros/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/decodable.rs rename to compiler/rustc_builtin_macros/src/deriving/decodable.rs diff --git a/src/librustc_builtin_macros/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/default.rs rename to compiler/rustc_builtin_macros/src/deriving/default.rs diff --git a/src/librustc_builtin_macros/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/encodable.rs rename to compiler/rustc_builtin_macros/src/deriving/encodable.rs diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs similarity index 99% rename from src/librustc_builtin_macros/deriving/generic/mod.rs rename to compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 849e8b136e..f4924997d1 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -187,7 +187,6 @@ use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_data_structures::map_in_place::MapInPlace; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::source_map::respan; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -532,7 +531,11 @@ impl<'a> TraitDef<'a> { id: ast::DUMMY_NODE_ID, span: self.span, ident, - vis: respan(self.span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: self.span.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, attrs: Vec::new(), kind: ast::AssocItemKind::TyAlias( ast::Defaultness::Final, @@ -933,7 +936,11 @@ impl<'a> MethodDef<'a> { id: ast::DUMMY_NODE_ID, attrs: self.attributes.clone(), span: trait_.span, - vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: trait_lo_sp, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, ident: method_ident, kind: ast::AssocItemKind::Fn(def, sig, fn_generics, Some(body_block)), tokens: None, @@ -1522,7 +1529,7 @@ impl<'a> TraitDef<'a> { } } - let is_tuple = if let ast::VariantData::Tuple(..) = struct_def { true } else { false }; + let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..)); match (just_spans.is_empty(), named_idents.is_empty()) { (false, false) => cx.span_bug( self.span, diff --git a/src/librustc_builtin_macros/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/generic/ty.rs rename to compiler/rustc_builtin_macros/src/deriving/generic/ty.rs diff --git a/src/librustc_builtin_macros/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/hash.rs rename to compiler/rustc_builtin_macros/src/deriving/hash.rs diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs similarity index 99% rename from src/librustc_builtin_macros/deriving/mod.rs rename to compiler/rustc_builtin_macros/src/deriving/mod.rs index 7e3fd131d4..9c8e0fc2f0 100644 --- a/src/librustc_builtin_macros/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -75,6 +75,7 @@ fn call_intrinsic( id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), span, + tokens: None, })) } diff --git a/src/librustc_builtin_macros/env.rs b/compiler/rustc_builtin_macros/src/env.rs similarity index 100% rename from src/librustc_builtin_macros/env.rs rename to compiler/rustc_builtin_macros/src/env.rs diff --git a/src/librustc_builtin_macros/format.rs b/compiler/rustc_builtin_macros/src/format.rs similarity index 95% rename from src/librustc_builtin_macros/format.rs rename to compiler/rustc_builtin_macros/src/format.rs index 373277f525..550524e652 100644 --- a/src/librustc_builtin_macros/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -135,21 +135,52 @@ fn parse_args<'a>( return Err(ecx.struct_span_err(sp, "requires at least a format string argument")); } - let fmtstr = p.parse_expr()?; + let first_token = &p.token; + let fmtstr = match first_token.kind { + token::TokenKind::Literal(token::Lit { + kind: token::LitKind::Str | token::LitKind::StrRaw(_), + .. + }) => { + // If the first token is a string literal, then a format expression + // is constructed from it. + // + // This allows us to properly handle cases when the first comma + // after the format string is mistakenly replaced with any operator, + // which cause the expression parser to eat too much tokens. + p.parse_literal_maybe_minus()? + } + _ => { + // Otherwise, we fall back to the expression parser. + p.parse_expr()? + } + }; + let mut first = true; let mut named = false; while p.token != token::Eof { if !p.eat(&token::Comma) { if first { - // After `format!(""` we always expect *only* a comma... - let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`"); - err.span_label(p.token.span, "expected `,`"); - p.maybe_annotate_with_ascription(&mut err, false); - return Err(err); - } else { - // ...after that delegate to `expect` to also include the other expected tokens. - let _ = p.expect(&token::Comma)?; + p.clear_expected_tokens(); + } + + // `Parser::expect` tries to recover using the + // `Parser::unexpected_try_recover` function. This function is able + // to recover if the expected token is a closing delimiter. + // + // As `,` is not a closing delimiter, it will always return an `Err` + // variant. + let mut err = p.expect(&token::Comma).unwrap_err(); + + match token::TokenKind::Comma.similar_tokens() { + Some(tks) if tks.contains(&p.token.kind) => { + // If a similar token is found, then it may be a typo. We + // consider it as a comma, and continue parsing. + err.emit(); + p.bump(); + } + // Otherwise stop the parsing and return the error. + _ => return Err(err), } } first = false; @@ -512,9 +543,12 @@ impl<'a, 'b> Context<'a, 'b> { let idx = self.args.len(); self.arg_types.push(Vec::new()); self.arg_unique_types.push(Vec::new()); - self.args.push( - self.ecx.expr_ident(self.fmtsp, Ident::new(name, self.fmtsp)), - ); + let span = if self.is_literal { + *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp) + } else { + self.fmtsp + }; + self.args.push(self.ecx.expr_ident(span, Ident::new(name, span))); self.names.insert(name, idx); self.verify_arg_type(Exact(idx), ty) } else { diff --git a/src/librustc_builtin_macros/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs similarity index 98% rename from src/librustc_builtin_macros/format_foreign.rs rename to compiler/rustc_builtin_macros/src/format_foreign.rs index 85cf4c42e9..ff81b5eca1 100644 --- a/src/librustc_builtin_macros/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -166,14 +166,14 @@ pub mod printf { let cap = self.span.len() + if has_options { 2 } else { 0 }; let mut s = String::with_capacity(cap); - s.push_str("{"); + s.push('{'); if let Some(arg) = self.parameter { write!(s, "{}", arg.checked_sub(1)?).ok()?; } if has_options { - s.push_str(":"); + s.push(':'); let align = if let Some(fill) = fill { s.push_str(fill); @@ -191,11 +191,11 @@ pub mod printf { } if alt { - s.push_str("#"); + s.push('#'); } if zero_fill { - s.push_str("0"); + s.push('0'); } if let Some(width) = width { @@ -203,7 +203,7 @@ pub mod printf { } if let Some(precision) = precision { - s.push_str("."); + s.push('.'); precision.translate(&mut s).ok()?; } @@ -212,7 +212,7 @@ pub mod printf { } } - s.push_str("}"); + s.push('}'); Some(s) } } @@ -518,8 +518,7 @@ pub mod printf { .and_then(|end| end.at_next_cp()) .map(|end| (next.slice_between(end).unwrap(), end)); let end = match end { - Some(("32", end)) => end, - Some(("64", end)) => end, + Some(("32" | "64", end)) => end, _ => next, }; state = Type; diff --git a/src/librustc_builtin_macros/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs similarity index 100% rename from src/librustc_builtin_macros/format_foreign/printf/tests.rs rename to compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs diff --git a/src/librustc_builtin_macros/format_foreign/shell/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs similarity index 100% rename from src/librustc_builtin_macros/format_foreign/shell/tests.rs rename to compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs diff --git a/src/librustc_builtin_macros/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs similarity index 100% rename from src/librustc_builtin_macros/global_allocator.rs rename to compiler/rustc_builtin_macros/src/global_allocator.rs diff --git a/src/librustc_builtin_macros/global_asm.rs b/compiler/rustc_builtin_macros/src/global_asm.rs similarity index 91% rename from src/librustc_builtin_macros/global_asm.rs rename to compiler/rustc_builtin_macros/src/global_asm.rs index 2465f33622..3689e33be6 100644 --- a/src/librustc_builtin_macros/global_asm.rs +++ b/compiler/rustc_builtin_macros/src/global_asm.rs @@ -14,7 +14,6 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_errors::DiagnosticBuilder; use rustc_expand::base::{self, *}; -use rustc_span::source_map::respan; use rustc_span::symbol::Ident; use rustc_span::Span; use smallvec::smallvec; @@ -30,7 +29,11 @@ pub fn expand_global_asm<'cx>( attrs: Vec::new(), id: ast::DUMMY_NODE_ID, kind: ast::ItemKind::GlobalAsm(P(global_asm)), - vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: sp.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, span: cx.with_def_site_ctxt(sp), tokens: None, })]), diff --git a/src/librustc_builtin_macros/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs similarity index 98% rename from src/librustc_builtin_macros/lib.rs rename to compiler/rustc_builtin_macros/src/lib.rs index 87be6d1743..97cadb913c 100644 --- a/src/librustc_builtin_macros/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -1,7 +1,7 @@ //! This crate contains implementations of built-in macros and other code generating facilities //! injecting code into the crate before it is lowered to HIR. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] diff --git a/src/librustc_builtin_macros/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs similarity index 100% rename from src/librustc_builtin_macros/llvm_asm.rs rename to compiler/rustc_builtin_macros/src/llvm_asm.rs diff --git a/src/librustc_builtin_macros/log_syntax.rs b/compiler/rustc_builtin_macros/src/log_syntax.rs similarity index 100% rename from src/librustc_builtin_macros/log_syntax.rs rename to compiler/rustc_builtin_macros/src/log_syntax.rs diff --git a/src/librustc_builtin_macros/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs similarity index 98% rename from src/librustc_builtin_macros/proc_macro_harness.rs rename to compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 0c6769906f..c6ab3faf56 100644 --- a/src/librustc_builtin_macros/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -98,7 +98,7 @@ pub fn inject( impl<'a> CollectProcMacros<'a> { fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { - if self.is_proc_macro_crate && self.in_root && vis.node.is_pub() { + if self.is_proc_macro_crate && self.in_root && vis.kind.is_pub() { self.handler.span_err( sp, "`proc-macro` crate types currently cannot export any items other \ @@ -184,7 +184,7 @@ impl<'a> CollectProcMacros<'a> { Vec::new() }; - if self.in_root && item.vis.node.is_pub() { + if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Derive(ProcMacroDerive { id: item.id, span: item.span, @@ -204,7 +204,7 @@ impl<'a> CollectProcMacros<'a> { } fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.node.is_pub() { + if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Def(ProcMacroDef { id: item.id, span: item.span, @@ -223,7 +223,7 @@ impl<'a> CollectProcMacros<'a> { } fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.node.is_pub() { + if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Def(ProcMacroDef { id: item.id, span: item.span, diff --git a/src/librustc_builtin_macros/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs similarity index 100% rename from src/librustc_builtin_macros/source_util.rs rename to compiler/rustc_builtin_macros/src/source_util.rs diff --git a/src/librustc_builtin_macros/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs similarity index 100% rename from src/librustc_builtin_macros/standard_library_imports.rs rename to compiler/rustc_builtin_macros/src/standard_library_imports.rs diff --git a/src/librustc_builtin_macros/test.rs b/compiler/rustc_builtin_macros/src/test.rs similarity index 98% rename from src/librustc_builtin_macros/test.rs rename to compiler/rustc_builtin_macros/src/test.rs index 8e56e80bba..1de0b32f51 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -7,7 +7,6 @@ use rustc_ast::attr; use rustc_ast_pretty::pprust; use rustc_expand::base::*; use rustc_session::Session; -use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; @@ -35,7 +34,11 @@ pub fn expand_test_case( let sp = ecx.with_def_site_ctxt(attr_sp); let mut item = anno_item.expect_item(); item = item.map(|mut item| { - item.vis = respan(item.vis.span, ast::VisibilityKind::Public); + item.vis = ast::Visibility { + span: item.vis.span, + kind: ast::VisibilityKind::Public, + tokens: None, + }; item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); item.attrs.push(ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker))); item @@ -292,7 +295,7 @@ pub fn expand_test_or_bench( ), ); test_const = test_const.map(|mut tc| { - tc.vis.node = ast::VisibilityKind::Public; + tc.vis.kind = ast::VisibilityKind::Public; tc }); diff --git a/src/librustc_builtin_macros/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs similarity index 99% rename from src/librustc_builtin_macros/test_harness.rs rename to compiler/rustc_builtin_macros/src/test_harness.rs index 0ea60665d6..0a60ca8faa 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -10,7 +10,6 @@ use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; use rustc_session::Session; use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; -use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::PanicStrategy; @@ -333,7 +332,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { attrs: vec![main_attr], id: ast::DUMMY_NODE_ID, kind: main, - vis: respan(sp, ast::VisibilityKind::Public), + vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None }, span: sp, tokens: None, }); diff --git a/src/librustc_builtin_macros/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs similarity index 100% rename from src/librustc_builtin_macros/trace_macros.rs rename to compiler/rustc_builtin_macros/src/trace_macros.rs diff --git a/src/librustc_builtin_macros/util.rs b/compiler/rustc_builtin_macros/src/util.rs similarity index 100% rename from src/librustc_builtin_macros/util.rs rename to compiler/rustc_builtin_macros/src/util.rs diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml new file mode 100644 index 0000000000..04792b334d --- /dev/null +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -0,0 +1,34 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_codegen_llvm" +version = "0.0.0" +edition = "2018" + +[lib] +test = false +doctest = false + +[dependencies] +bitflags = "1.0" +libc = "0.2" +measureme = "0.7.1" +snap = "1" +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc-demangle = "0.1" +rustc_attr = { path = "../rustc_attr" } +rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_fs_util = { path = "../rustc_fs_util" } +rustc_hir = { path = "../rustc_hir" } +rustc_incremental = { path = "../rustc_incremental" } +rustc_index = { path = "../rustc_index" } +rustc_llvm = { path = "../rustc_llvm" } +rustc_session = { path = "../rustc_session" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_target = { path = "../rustc_target" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } diff --git a/src/librustc_codegen_llvm/README.md b/compiler/rustc_codegen_llvm/README.md similarity index 100% rename from src/librustc_codegen_llvm/README.md rename to compiler/rustc_codegen_llvm/README.md diff --git a/src/librustc_codegen_llvm/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs similarity index 100% rename from src/librustc_codegen_llvm/abi.rs rename to compiler/rustc_codegen_llvm/src/abi.rs diff --git a/src/librustc_codegen_llvm/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs similarity index 100% rename from src/librustc_codegen_llvm/allocator.rs rename to compiler/rustc_codegen_llvm/src/allocator.rs diff --git a/src/librustc_codegen_llvm/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs similarity index 95% rename from src/librustc_codegen_llvm/asm.rs rename to compiler/rustc_codegen_llvm/src/asm.rs index 4fef94dde5..f801f845ac 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -259,6 +259,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {} InlineAsmArch::Nvptx64 => {} InlineAsmArch::Hexagon => {} + InlineAsmArch::Mips => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -485,7 +486,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) format!("{{{}{}}}", class, idx) } else if reg == InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) { // LLVM doesn't recognize x30 - "lr".to_string() + "{lr}".to_string() } else { format!("{{{}}}", reg.name()) } @@ -505,6 +506,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", @@ -551,6 +554,7 @@ fn modifier_to_llvm( } } InlineAsmRegClass::Hexagon(_) => None, + InlineAsmRegClass::Mips(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, @@ -603,6 +607,8 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll cx.type_vector(cx.type_i64(), 2) } InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), @@ -700,6 +706,12 @@ fn llvm_fixup_input( value } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), + Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()), + _ => value, + }, _ => value, } } @@ -768,6 +780,13 @@ fn llvm_fixup_output( value } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), + Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()), + Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()), + _ => value, + }, _ => value, } } @@ -831,6 +850,12 @@ fn llvm_fixup_output_type( layout.llvm_type(cx) } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), + Primitive::F32 => cx.type_i32(), + _ => layout.llvm_type(cx), + }, _ => layout.llvm_type(cx), } } diff --git a/src/librustc_codegen_llvm/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs similarity index 98% rename from src/librustc_codegen_llvm/attributes.rs rename to compiler/rustc_codegen_llvm/src/attributes.rs index 227a87ff81..73c3481844 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -294,6 +294,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn); } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { + llvm::AddFunctionAttrString(llfn, Function, const_cstr!("cmse_nonsecure_entry")); + } sanitize(cx, codegen_fn_attrs.no_sanitize, llfn); // Always annotate functions with the target-cpu they are compiled for. diff --git a/src/librustc_codegen_llvm/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs similarity index 100% rename from src/librustc_codegen_llvm/back/archive.rs rename to compiler/rustc_codegen_llvm/src/back/archive.rs diff --git a/src/librustc_codegen_llvm/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs similarity index 99% rename from src/librustc_codegen_llvm/back/lto.rs rename to compiler/rustc_codegen_llvm/src/back/lto.rs index 7c710a1cb3..4b2d5907a0 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -346,14 +346,14 @@ fn fat_lto( Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode }) } -struct Linker<'a>(&'a mut llvm::Linker<'a>); +crate struct Linker<'a>(&'a mut llvm::Linker<'a>); impl Linker<'a> { - fn new(llmod: &'a llvm::Module) -> Self { + crate fn new(llmod: &'a llvm::Module) -> Self { unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } } - fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + crate fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { unsafe { if llvm::LLVMRustLinkerAdd( self.0, diff --git a/src/librustc_codegen_llvm/back/profiling.rs b/compiler/rustc_codegen_llvm/src/back/profiling.rs similarity index 100% rename from src/librustc_codegen_llvm/back/profiling.rs rename to compiler/rustc_codegen_llvm/src/back/profiling.rs diff --git a/src/librustc_codegen_llvm/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs similarity index 96% rename from src/librustc_codegen_llvm/back/write.rs rename to compiler/rustc_codegen_llvm/src/back/write.rs index 6f386c1287..f35c1016f8 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -344,6 +344,13 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void .expect("non-UTF8 diagnostic"); diag_handler.warn(&msg); } + llvm::diagnostic::Unsupported(diagnostic_ref) => { + let msg = llvm::build_string(|s| { + llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) + }) + .expect("non-UTF8 diagnostic"); + diag_handler.err(&msg); + } llvm::diagnostic::UnknownDiagnostic(..) => {} } } @@ -617,6 +624,31 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static } } +pub(crate) fn link( + cgcx: &CodegenContext, + diag_handler: &Handler, + mut modules: Vec>, +) -> Result, FatalError> { + use super::lto::{Linker, ModuleBuffer}; + // Sort the modules by name to ensure to ensure deterministic behavior. + modules.sort_by(|a, b| a.name.cmp(&b.name)); + let (first, elements) = + modules.split_first().expect("Bug! modules must contain at least one module."); + + let mut linker = Linker::new(first.module_llvm.llmod()); + for module in elements { + let _timer = + cgcx.prof.generic_activity_with_arg("LLVM_link_module", format!("{:?}", module.name)); + let buffer = ModuleBuffer::new(module.module_llvm.llmod()); + linker.add(&buffer.data()).map_err(|()| { + let msg = format!("failed to serialize module {:?}", module.name); + llvm_err(&diag_handler, &msg) + })?; + } + drop(linker); + Ok(modules.remove(0)) +} + pub(crate) unsafe fn codegen( cgcx: &CodegenContext, diag_handler: &Handler, diff --git a/src/librustc_codegen_llvm/base.rs b/compiler/rustc_codegen_llvm/src/base.rs similarity index 96% rename from src/librustc_codegen_llvm/base.rs rename to compiler/rustc_codegen_llvm/src/base.rs index b19199b9cf..f35708b1d0 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -45,15 +45,12 @@ pub fn write_compressed_metadata<'tcx>( metadata: &EncodedMetadata, llvm_module: &mut ModuleLlvm, ) { - use flate2::write::DeflateEncoder; - use flate2::Compression; + use snap::write::FrameEncoder; use std::io::Write; let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod()); let mut compressed = tcx.metadata_encoding_version(); - DeflateEncoder::new(&mut compressed, Compression::fast()) - .write_all(&metadata.raw_data) - .unwrap(); + FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); let llmeta = common::bytes_in_context(metadata_llcx, &compressed); let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false); @@ -111,7 +108,7 @@ pub fn compile_codegen_unit( // We assume that the cost to run LLVM on a CGU is proportional to // the time we needed for codegenning it. - let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64; + let cost = time_to_codegen.as_nanos() as u64; fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); diff --git a/src/librustc_codegen_llvm/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs similarity index 98% rename from src/librustc_codegen_llvm/builder.rs rename to compiler/rustc_codegen_llvm/src/builder.rs index 4ece08f629..0c172dc33b 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -6,7 +6,6 @@ use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use libc::{c_char, c_uint}; -use rustc_codegen_ssa::base::to_immediate; use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, TypeKind}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; @@ -22,7 +21,6 @@ use rustc_target::abi::{self, Align, Size}; use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ffi::CStr; -use std::iter::TrustedLen; use std::ops::{Deref, Range}; use std::ptr; use tracing::debug; @@ -180,7 +178,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { &mut self, v: &'ll Value, else_llbb: &'ll BasicBlock, - cases: impl ExactSizeIterator + TrustedLen, + cases: impl ExactSizeIterator, ) { let switch = unsafe { llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, cases.len() as c_uint) }; @@ -307,10 +305,10 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { use rustc_ast::UintTy::*; use rustc_middle::ty::{Int, Uint}; - let new_kind = match ty.kind { + let new_kind = match ty.kind() { Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.ptr_width)), Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.ptr_width)), - ref t @ (Uint(_) | Int(_)) => t.clone(), + t @ (Uint(_) | Int(_)) => t.clone(), _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), }; @@ -367,6 +365,20 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { (self.extract_value(res, 0), self.extract_value(res, 1)) } + fn from_immediate(&mut self, val: Self::Value) -> Self::Value { + if self.cx().val_ty(val) == self.cx().type_i1() { + self.zext(val, self.cx().type_i8()) + } else { + val + } + } + fn to_immediate_scalar(&mut self, val: Self::Value, scalar: &abi::Scalar) -> Self::Value { + if scalar.is_bool() { + return self.trunc(val, self.cx().type_i1()); + } + val + } + fn alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value { let mut bx = Builder::with_cx(self.cx); bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); @@ -471,7 +483,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } load }); - OperandValue::Immediate(to_immediate(self, llval, place.layout)) + OperandValue::Immediate(self.to_immediate(llval, place.layout)) } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { let b_offset = a.value.size(self).align_to(b.value.align(self).abi); @@ -479,7 +491,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let llptr = self.struct_gep(place.llval, i as u64); let load = self.load(llptr, align); scalar_load_metadata(self, load, scalar); - if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } + self.to_immediate_scalar(load, scalar) }; OperandValue::Pair( @@ -918,7 +930,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, UNNAMED) } } - #[allow(dead_code)] fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } diff --git a/src/librustc_codegen_llvm/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs similarity index 100% rename from src/librustc_codegen_llvm/callee.rs rename to compiler/rustc_codegen_llvm/src/callee.rs diff --git a/src/librustc_codegen_llvm/common.rs b/compiler/rustc_codegen_llvm/src/common.rs similarity index 99% rename from src/librustc_codegen_llvm/common.rs rename to compiler/rustc_codegen_llvm/src/common.rs index 0b1cf03fa7..0992410a72 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types, non_snake_case)] - //! Code that is useful in various codegen modules. use crate::consts::{self, const_alloc_to_llvm}; diff --git a/src/librustc_codegen_llvm/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs similarity index 97% rename from src/librustc_codegen_llvm/consts.rs rename to compiler/rustc_codegen_llvm/src/consts.rs index 86a5ec5925..6d3582d302 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -7,12 +7,13 @@ use crate::type_of::LayoutLlvmExt; use crate::value::Value; use libc::c_uint; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::const_cstr; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ - read_target_uint, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer, + read_target_uint, Allocation, ErrorHandled, GlobalAlloc, Pointer, }; use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; @@ -22,8 +23,6 @@ use rustc_span::Span; use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size}; use tracing::debug; -use std::ffi::CStr; - pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value { let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); let dl = cx.data_layout(); @@ -85,10 +84,7 @@ pub fn codegen_static_initializer( cx: &CodegenCx<'ll, 'tcx>, def_id: DefId, ) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> { - let alloc = match cx.tcx.const_eval_poly(def_id)? { - ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => alloc, - val => bug!("static const eval returned {:#?}", val), - }; + let alloc = cx.tcx.eval_static_initializer(def_id)?; Ok((const_alloc_to_llvm(cx, alloc), alloc)) } @@ -125,7 +121,7 @@ fn check_and_apply_linkage( // extern "C" fn() from being non-null, so we can't just declare a // static and call it a day. Some linkages (like weak) will make it such // that the static actually has a null value. - let llty2 = if let ty::RawPtr(ref mt) = ty.kind { + let llty2 = if let ty::RawPtr(ref mt) = ty.kind() { cx.layout_of(mt.ty).llvm_type(cx) } else { cx.sess().span_fatal( @@ -457,9 +453,9 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { .all(|&byte| byte == 0); let sect_name = if all_bytes_are_zero { - CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0") + const_cstr!("__DATA,__thread_bss") } else { - CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0") + const_cstr!("__DATA,__thread_data") }; llvm::LLVMSetSection(g, sect_name.as_ptr()); } diff --git a/src/librustc_codegen_llvm/context.rs b/compiler/rustc_codegen_llvm/src/context.rs similarity index 96% rename from src/librustc_codegen_llvm/context.rs rename to compiler/rustc_codegen_llvm/src/context.rs index 26707fdf83..1696f35563 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -82,6 +82,7 @@ pub struct CodegenCx<'ll, 'tcx> { pub dbg_cx: Option>, eh_personality: Cell>, + eh_catch_typeinfo: Cell>, pub rust_try_fn: Cell>, intrinsics: RefCell>, @@ -311,6 +312,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { coverage_cx, dbg_cx, eh_personality: Cell::new(None), + eh_catch_typeinfo: Cell::new(None), rust_try_fn: Cell::new(None), intrinsics: Default::default(), local_gen_sym_counter: Cell::new(0), @@ -431,6 +433,17 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMSetSection(g, section.as_ptr()); } } + + fn declare_c_main(&self, fn_type: Self::Type) -> Option { + if self.get_declared_value("main").is_none() { + Some(self.declare_cfn("main", fn_type)) + } else { + // If the symbol already exists, it is an error: for example, the user wrote + // #[no_mangle] extern "C" fn main(..) {..} + // instead of #[start] + None + } + } } impl CodegenCx<'b, 'tcx> { @@ -819,6 +832,25 @@ impl CodegenCx<'b, 'tcx> { } None } + + crate fn eh_catch_typeinfo(&self) -> &'b Value { + if let Some(eh_catch_typeinfo) = self.eh_catch_typeinfo.get() { + return eh_catch_typeinfo; + } + let tcx = self.tcx; + assert!(self.sess().target.target.options.is_like_emscripten); + let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() { + Some(def_id) => self.get_static(def_id), + _ => { + let ty = self + .type_struct(&[self.type_ptr_to(self.type_isize()), self.type_i8p()], false); + self.declare_global("rust_eh_catch_typeinfo", ty) + } + }; + let eh_catch_typeinfo = self.const_bitcast(eh_catch_typeinfo, self.type_i8p()); + self.eh_catch_typeinfo.set(Some(eh_catch_typeinfo)); + eh_catch_typeinfo + } } impl<'b, 'tcx> CodegenCx<'b, 'tcx> { diff --git a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs similarity index 100% rename from src/librustc_codegen_llvm/coverageinfo/mapgen.rs rename to compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs diff --git a/src/librustc_codegen_llvm/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs similarity index 100% rename from src/librustc_codegen_llvm/coverageinfo/mod.rs rename to compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/create_scope_map.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs diff --git a/src/librustc_codegen_llvm/debuginfo/doc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/doc.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/doc.rs diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/gdb.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs similarity index 98% rename from src/librustc_codegen_llvm/debuginfo/metadata.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9d92d53775..987149cb4c 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -343,7 +343,7 @@ fn fixed_vec_metadata( let (size, align) = cx.size_and_align_of(array_or_slice_type); - let upper_bound = match array_or_slice_type.kind { + let upper_bound = match array_or_slice_type.kind() { ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong, _ => -1, }; @@ -432,7 +432,7 @@ fn subroutine_type_metadata( let signature_metadata: Vec<_> = iter::once( // return type - match signature.output().kind { + match signature.output().kind() { ty::Tuple(ref tys) if tys.is_empty() => None, _ => Some(type_metadata(cx, signature.output(), span)), }, @@ -472,7 +472,7 @@ fn trait_pointer_metadata( // type is assigned the correct name, size, namespace, and source location. // However, it does not describe the trait's methods. - let containing_scope = match trait_type.kind { + let containing_scope = match trait_type.kind() { ty::Dynamic(ref data, ..) => { data.principal_def_id().map(|did| get_namespace_for_item(cx, did)) } @@ -572,7 +572,7 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp debug!("type_metadata: {:?}", t); - let ptr_metadata = |ty: Ty<'tcx>| match ty.kind { + let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() { ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)), ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span)), ty::Dynamic(..) => Ok(MetadataCreationResult::new( @@ -592,7 +592,7 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp } }; - let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.kind { + let MetadataCreationResult { metadata, already_stored_in_typemap } = match *t.kind() { ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } @@ -876,7 +876,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { // .natvis visualizers (and perhaps other existing native debuggers?) let msvc_like_names = cx.tcx.sess.target.target.options.is_like_msvc; - let (name, encoding) = match t.kind { + let (name, encoding) = match t.kind() { ty::Never => ("!", DW_ATE_unsigned), ty::Tuple(ref elements) if elements.is_empty() => ("()", DW_ATE_unsigned), ty::Bool => ("bool", DW_ATE_boolean), @@ -904,7 +904,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { return ty_metadata; } - let typedef_name = match t.kind { + let typedef_name = match t.kind() { ty::Int(int_ty) => int_ty.name_str(), ty::Uint(uint_ty) => uint_ty.name_str(), ty::Float(float_ty) => float_ty.name_str(), @@ -1239,7 +1239,7 @@ fn prepare_struct_metadata( ) -> RecursiveTypeDescription<'ll, 'tcx> { let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false); - let (struct_def_id, variant) = match struct_type.kind { + let (struct_def_id, variant) = match struct_type.kind() { ty::Adt(def, _) => (def.did, def.non_enum_variant()), _ => bug!("prepare_struct_metadata on a non-ADT"), }; @@ -1373,7 +1373,7 @@ fn prepare_union_metadata( ) -> RecursiveTypeDescription<'ll, 'tcx> { let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false); - let (union_def_id, variant) = match union_type.kind { + let (union_def_id, variant) = match union_type.kind() { ty::Adt(def, _) => (def.did, def.non_enum_variant()), _ => bug!("prepare_union_metadata on a non-ADT"), }; @@ -1457,14 +1457,14 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> { impl EnumMemberDescriptionFactory<'ll, 'tcx> { fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec> { - let generator_variant_info_data = match self.enum_type.kind { + let generator_variant_info_data = match *self.enum_type.kind() { ty::Generator(def_id, ..) => { Some(generator_layout_and_saved_local_names(cx.tcx, def_id)) } _ => None, }; - let variant_info_for = |index: VariantIdx| match self.enum_type.kind { + let variant_info_for = |index: VariantIdx| match *self.enum_type.kind() { ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]), ty::Generator(def_id, _, _) => { let (generator_layout, generator_saved_local_names) = @@ -1486,14 +1486,14 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } else { type_metadata(cx, self.enum_type, self.span) }; - let flags = match self.enum_type.kind { + let flags = match self.enum_type.kind() { ty::Generator(..) => DIFlags::FlagArtificial, _ => DIFlags::FlagZero, }; match self.layout.variants { Variants::Single { index } => { - if let ty::Adt(adt, _) = &self.enum_type.kind { + if let ty::Adt(adt, _) = self.enum_type.kind() { if adt.variants.is_empty() { return vec![]; } @@ -1845,7 +1845,6 @@ impl<'tcx> VariantInfo<'_, 'tcx> { None } - #[allow(dead_code)] fn is_artificial(&self) -> bool { match self { VariantInfo::Generator { .. } => true, @@ -1942,7 +1941,7 @@ fn prepare_enum_metadata( let tcx = cx.tcx; let enum_name = compute_debuginfo_type_name(tcx, enum_type, false); // FIXME(tmandry): This doesn't seem to have any effect. - let enum_flags = match enum_type.kind { + let enum_flags = match enum_type.kind() { ty::Generator(..) => DIFlags::FlagArtificial, _ => DIFlags::FlagZero, }; @@ -1957,13 +1956,13 @@ fn prepare_enum_metadata( let file_metadata = unknown_file_metadata(cx); let discriminant_type_metadata = |discr: Primitive| { - let enumerators_metadata: Vec<_> = match enum_type.kind { + let enumerators_metadata: Vec<_> = match enum_type.kind() { ty::Adt(def, _) => def .discriminants(tcx) .zip(&def.variants) .map(|((_, discr), v)| { let name = v.ident.as_str(); - let is_unsigned = match discr.ty.kind { + let is_unsigned = match discr.ty.kind() { ty::Int(_) => false, ty::Uint(_) => true, _ => bug!("non integer discriminant"), @@ -2012,7 +2011,7 @@ fn prepare_enum_metadata( type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP); let item_name; - let discriminant_name = match enum_type.kind { + let discriminant_name = match enum_type.kind() { ty::Adt(..) => { item_name = tcx.item_name(enum_def_id).as_str(); &*item_name @@ -2105,7 +2104,7 @@ fn prepare_enum_metadata( ); } - let discriminator_name = match &enum_type.kind { + let discriminator_name = match enum_type.kind() { ty::Generator(..) => "__state", _ => "", }; @@ -2328,7 +2327,7 @@ fn set_members_of_composite_type( /// Computes the type parameters for a type, if any, for the given metadata. fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> { - if let ty::Adt(def, substs) = ty.kind { + if let ty::Adt(def, substs) = *ty.kind() { if substs.types().next().is_some() { let generics = cx.tcx.generics_of(def.did); let names = get_parameter_names(cx, generics); diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs similarity index 99% rename from src/librustc_codegen_llvm/debuginfo/mod.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index b414426af8..7cdd366175 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -361,9 +361,9 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // already inaccurate due to ABI adjustments (see #42800). signature.extend(fn_abi.args.iter().map(|arg| { let t = arg.layout.ty; - let t = match t.kind { + let t = match t.kind() { ty::Array(ct, _) - if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => + if (*ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => { cx.tcx.mk_imm_ptr(ct) } @@ -467,7 +467,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g., `<*mut T>::null`). - match impl_self_ty.kind { + match impl_self_ty.kind() { ty::Adt(def, ..) if !def.is_box() => { // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == DebugInfo::Full diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs similarity index 80% rename from src/librustc_codegen_llvm/debuginfo/namespace.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index d1a55335c4..9945d4f428 100644 --- a/src/librustc_codegen_llvm/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -27,11 +27,18 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { .parent .map(|parent| item_namespace(cx, DefId { krate: def_id.krate, index: parent })); + let crate_name_as_str; + let name_to_string; let namespace_name = match def_key.disambiguated_data.data { - DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate), - data => data.as_symbol(), + DefPathData::CrateRoot => { + crate_name_as_str = cx.tcx.crate_name(def_id.krate).as_str(); + &*crate_name_as_str + } + data => { + name_to_string = data.to_string(); + &*name_to_string + } }; - let namespace_name = namespace_name.as_str(); let scope = unsafe { llvm::LLVMRustDIBuilderCreateNameSpace( diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/source_loc.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs diff --git a/src/librustc_codegen_llvm/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/utils.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/utils.rs diff --git a/src/librustc_codegen_llvm/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs similarity index 59% rename from src/librustc_codegen_llvm/declare.rs rename to compiler/rustc_codegen_llvm/src/declare.rs index ec42bd4a03..a3d6882940 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -51,17 +51,32 @@ fn declare_raw_fn( llfn } -impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { +impl CodegenCx<'ll, 'tcx> { + /// Declare a global value. + /// + /// If there’s a value with the same name already declared, the function will + /// return its Value instead. + pub fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { debug!("declare_global(name={:?})", name); unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty) } } - fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value { + /// Declare a C ABI function. + /// + /// Only use this for foreign function ABIs and glue. For Rust functions use + /// `declare_fn` instead. + /// + /// If there’s a value with the same name already declared, the function will + /// update the declaration and return existing Value instead. + pub fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value { declare_raw_fn(self, name, llvm::CCallConv, fn_type) } - fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value { + /// Declare a Rust function. + /// + /// If there’s a value with the same name already declared, the function will + /// update the declaration and return existing Value instead. + pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value { debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi); let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self)); @@ -69,7 +84,13 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { llfn } - fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> { + /// Declare a global with an intention to define it. + /// + /// Use this function when you intend to define a global. This function will + /// return `None` if the name already has a definition associated with it. In that + /// case an error should be reported to the user, because it usually happens due + /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes). + pub fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> { if self.get_defined_value(name).is_some() { None } else { @@ -77,16 +98,22 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn define_private_global(&self, ty: &'ll Type) -> &'ll Value { + /// Declare a private global + /// + /// Use this function when you intend to define a global without a name. + pub fn define_private_global(&self, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty) } } - fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { + /// Gets declared value by name. + pub fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { debug!("get_declared_value(name={:?})", name); unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) } } - fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { + /// Gets defined or externally defined (AvailableExternally linkage) value by + /// name. + pub fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { self.get_declared_value(name).and_then(|val| { let declaration = unsafe { llvm::LLVMIsDeclaration(val) != 0 }; if !declaration { Some(val) } else { None } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs similarity index 71% rename from src/librustc_codegen_llvm/intrinsic.rs rename to compiler/rustc_codegen_llvm/src/intrinsic.rs index bb79a52dcf..7f5b09eac4 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -7,15 +7,12 @@ use crate::type_of::LayoutLlvmExt; use crate::va_arg::emit_va_arg; use crate::value::Value; -use rustc_ast as ast; -use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh}; +use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; -use rustc_codegen_ssa::glue; -use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; +use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::MemFlags; use rustc_hir as hir; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Ty}; @@ -71,8 +68,6 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Va sym::nearbyintf64 => "llvm.nearbyint.f64", sym::roundf32 => "llvm.round.f32", sym::roundf64 => "llvm.round.f64", - sym::assume => "llvm.assume", - sym::abort => "llvm.trap", _ => return None, }; Some(cx.get_intrinsic(&llvm_name)) @@ -90,7 +85,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let tcx = self.tcx; let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); - let (def_id, substs) = match callee_ty.kind { + let (def_id, substs) = match *callee_ty.kind() { ty::FnDef(def_id, substs) => (def_id, substs), _ => bug!("expected fn item type, found {}", callee_ty), }; @@ -112,9 +107,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &args.iter().map(|arg| arg.immediate()).collect::>(), None, ), - sym::unreachable => { - return; - } sym::likely => { let expect = self.get_intrinsic(&("llvm.expect.i1")); self.call(expect, &[args[0].immediate(), self.const_bool(true)], None) @@ -137,8 +129,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let llfn = self.get_intrinsic(&("llvm.debugtrap")); self.call(llfn, &[], None) } - sym::va_start => self.va_start(args[0].immediate()), - sym::va_end => self.va_end(args[0].immediate()), sym::va_copy => { let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy")); self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None) @@ -169,123 +159,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { _ => bug!("the va_arg intrinsic does not work with non-scalar types"), } } - sym::size_of_val => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (llsize, _) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); - llsize - } else { - self.const_usize(self.size_of(tp_ty).bytes()) - } - } - sym::min_align_of_val => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (_, llalign) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); - llalign - } else { - self.const_usize(self.align_of(tp_ty).bytes()) - } - } - sym::size_of - | sym::pref_align_of - | sym::min_align_of - | sym::needs_drop - | sym::type_id - | sym::type_name - | sym::variant_count => { - let value = self - .tcx - .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) - .unwrap(); - OperandRef::from_const(self, value, ret_ty).immediate_or_packed_pair(self) - } - // Effectively no-op - sym::forget => { - return; - } - sym::offset => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - self.inbounds_gep(ptr, &[offset]) - } - sym::arith_offset => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - self.gep(ptr, &[offset]) - } - - sym::copy_nonoverlapping => { - copy_intrinsic( - self, - false, - false, - substs.type_at(0), - args[1].immediate(), - args[0].immediate(), - args[2].immediate(), - ); - return; - } - sym::copy => { - copy_intrinsic( - self, - true, - false, - substs.type_at(0), - args[1].immediate(), - args[0].immediate(), - args[2].immediate(), - ); - return; - } - sym::write_bytes => { - memset_intrinsic( - self, - false, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_copy_nonoverlapping_memory => { - copy_intrinsic( - self, - false, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_copy_memory => { - copy_intrinsic( - self, - true, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_set_memory => { - memset_intrinsic( - self, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); @@ -301,7 +175,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMSetAlignment(load, align); } - to_immediate(self, load, self.layout_of(tp_ty)) + self.to_immediate(load, self.layout_of(tp_ty)) } sym::volatile_store => { let dst = args[0].deref(self.cx()); @@ -343,20 +217,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { | sym::ctpop | sym::bswap | sym::bitreverse - | sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow - | sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul - | sym::unchecked_div - | sym::unchecked_rem - | sym::unchecked_shl - | sym::unchecked_shr - | sym::unchecked_add - | sym::unchecked_sub - | sym::unchecked_mul - | sym::exact_div | sym::rotate_left | sym::rotate_right | sym::saturating_add @@ -396,84 +256,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &[args[0].immediate()], None, ), - sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow => { - let intrinsic = format!( - "llvm.{}{}.with.overflow.i{}", - if signed { 's' } else { 'u' }, - &name_str[..3], - width - ); - let llfn = self.get_intrinsic(&intrinsic); - - // Convert `i1` to a `bool`, and write it to the out parameter - let pair = - self.call(llfn, &[args[0].immediate(), args[1].immediate()], None); - let val = self.extract_value(pair, 0); - let overflow = self.extract_value(pair, 1); - let overflow = self.zext(overflow, self.type_bool()); - - let dest = result.project_field(self, 0); - self.store(val, dest.llval, dest.align); - let dest = result.project_field(self, 1); - self.store(overflow, dest.llval, dest.align); - - return; - } - sym::wrapping_add => self.add(args[0].immediate(), args[1].immediate()), - sym::wrapping_sub => self.sub(args[0].immediate(), args[1].immediate()), - sym::wrapping_mul => self.mul(args[0].immediate(), args[1].immediate()), - sym::exact_div => { - if signed { - self.exactsdiv(args[0].immediate(), args[1].immediate()) - } else { - self.exactudiv(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_div => { - if signed { - self.sdiv(args[0].immediate(), args[1].immediate()) - } else { - self.udiv(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_rem => { - if signed { - self.srem(args[0].immediate(), args[1].immediate()) - } else { - self.urem(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_shl => self.shl(args[0].immediate(), args[1].immediate()), - sym::unchecked_shr => { - if signed { - self.ashr(args[0].immediate(), args[1].immediate()) - } else { - self.lshr(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_add => { - if signed { - self.unchecked_sadd(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_uadd(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_sub => { - if signed { - self.unchecked_ssub(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_usub(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_mul => { - if signed { - self.unchecked_smul(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_umul(args[0].immediate(), args[1].immediate()) - } - } sym::rotate_left | sym::rotate_right => { let is_left = name == sym::rotate_left; let val = args[0].immediate(); @@ -513,75 +295,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } } - sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { - match float_type_width(arg_tys[0]) { - Some(_width) => match name { - sym::fadd_fast => self.fadd_fast(args[0].immediate(), args[1].immediate()), - sym::fsub_fast => self.fsub_fast(args[0].immediate(), args[1].immediate()), - sym::fmul_fast => self.fmul_fast(args[0].immediate(), args[1].immediate()), - sym::fdiv_fast => self.fdiv_fast(args[0].immediate(), args[1].immediate()), - sym::frem_fast => self.frem_fast(args[0].immediate(), args[1].immediate()), - _ => bug!(), - }, - None => { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `{}` intrinsic: \ - expected basic float type, found `{}`", - name, arg_tys[0] - ), - ); - return; - } - } - } - - sym::float_to_int_unchecked => { - if float_type_width(arg_tys[0]).is_none() { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `float_to_int_unchecked` \ - intrinsic: expected basic float type, \ - found `{}`", - arg_tys[0] - ), - ); - return; - } - let (width, signed) = match int_type_width_signed(ret_ty, self.cx) { - Some(pair) => pair, - None => { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `float_to_int_unchecked` \ - intrinsic: expected basic integer type, \ - found `{}`", - ret_ty - ), - ); - return; - } - }; - if signed { - self.fptosi(args[0].immediate(), self.cx.type_ix(width)) - } else { - self.fptoui(args[0].immediate(), self.cx.type_ix(width)) - } - } - - sym::discriminant_value => { - if ret_ty.is_integral() { - args[0].deref(self.cx()).codegen_get_discr(self, ret_ty) - } else { - span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) - } - } _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { @@ -589,174 +302,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { Err(()) => return, } } - // This requires that atomic intrinsics follow a specific naming pattern: - // "atomic_[_]", and no ordering means SeqCst - name if name_str.starts_with("atomic_") => { - use rustc_codegen_ssa::common::AtomicOrdering::*; - use rustc_codegen_ssa::common::{AtomicRmwBinOp, SynchronizationScope}; - - let split: Vec<&str> = name_str.split('_').collect(); - - let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; - let (order, failorder) = match split.len() { - 2 => (SequentiallyConsistent, SequentiallyConsistent), - 3 => match split[2] { - "unordered" => (Unordered, Unordered), - "relaxed" => (Monotonic, Monotonic), - "acq" => (Acquire, Acquire), - "rel" => (Release, Monotonic), - "acqrel" => (AcquireRelease, Acquire), - "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), - "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), - _ => self.sess().fatal("unknown ordering in atomic intrinsic"), - }, - 4 => match (split[2], split[3]) { - ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), - ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), - _ => self.sess().fatal("unknown ordering in atomic intrinsic"), - }, - _ => self.sess().fatal("Atomic intrinsic not in correct format"), - }; - - let invalid_monomorphization = |ty| { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `{}` intrinsic: \ - expected basic integer type, found `{}`", - name, ty - ), - ); - }; - - match split[1] { - "cxchg" | "cxchgweak" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let weak = split[1] == "cxchgweak"; - let pair = self.atomic_cmpxchg( - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - order, - failorder, - weak, - ); - let val = self.extract_value(pair, 0); - let success = self.extract_value(pair, 1); - let success = self.zext(success, self.type_bool()); - - let dest = result.project_field(self, 0); - self.store(val, dest.llval, dest.align); - let dest = result.project_field(self, 1); - self.store(success, dest.llval, dest.align); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "load" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let size = self.size_of(ty); - self.atomic_load(args[0].immediate(), order, size) - } else { - return invalid_monomorphization(ty); - } - } - - "store" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let size = self.size_of(ty); - self.atomic_store( - args[1].immediate(), - args[0].immediate(), - order, - size, - ); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "fence" => { - self.atomic_fence(order, SynchronizationScope::CrossThread); - return; - } - - "singlethreadfence" => { - self.atomic_fence(order, SynchronizationScope::SingleThread); - return; - } - - // These are all AtomicRMW ops - op => { - let atom_op = match op { - "xchg" => AtomicRmwBinOp::AtomicXchg, - "xadd" => AtomicRmwBinOp::AtomicAdd, - "xsub" => AtomicRmwBinOp::AtomicSub, - "and" => AtomicRmwBinOp::AtomicAnd, - "nand" => AtomicRmwBinOp::AtomicNand, - "or" => AtomicRmwBinOp::AtomicOr, - "xor" => AtomicRmwBinOp::AtomicXor, - "max" => AtomicRmwBinOp::AtomicMax, - "min" => AtomicRmwBinOp::AtomicMin, - "umax" => AtomicRmwBinOp::AtomicUMax, - "umin" => AtomicRmwBinOp::AtomicUMin, - _ => self.sess().fatal("unknown atomic operation"), - }; - - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - self.atomic_rmw( - atom_op, - args[0].immediate(), - args[1].immediate(), - order, - ) - } else { - return invalid_monomorphization(ty); - } - } - } - } - - sym::nontemporal_store => { - let dst = args[0].deref(self.cx()); - args[1].val.nontemporal_store(self, dst); - return; - } - - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - let a = args[0].immediate(); - let b = args[1].immediate(); - if name == sym::ptr_guaranteed_eq { - self.icmp(IntPredicate::IntEQ, a, b) - } else { - self.icmp(IntPredicate::IntNE, a, b) - } - } - - sym::ptr_offset_from => { - let ty = substs.type_at(0); - let pointee_size = self.size_of(ty); - - // This is the same sequence that Clang emits for pointer subtraction. - // It can be neither `nsw` nor `nuw` because the input is treated as - // unsigned but then the output is treated as signed, so neither works. - let a = args[0].immediate(); - let b = args[1].immediate(); - let a = self.ptrtoint(a, self.type_isize()); - let b = self.ptrtoint(b, self.type_isize()); - let d = self.sub(a, b); - let pointee_size = self.const_usize(pointee_size.bytes()); - // this is where the signed magic happens (notice the `s` in `exactsdiv`) - self.exactsdiv(d, pointee_size) - } _ => bug!("unknown intrinsic '{}'", name), }; @@ -807,39 +352,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } -fn copy_intrinsic( - bx: &mut Builder<'a, 'll, 'tcx>, - allow_overlap: bool, - volatile: bool, - ty: Ty<'tcx>, - dst: &'ll Value, - src: &'ll Value, - count: &'ll Value, -) { - let (size, align) = bx.size_and_align_of(ty); - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - if allow_overlap { - bx.memmove(dst, align, src, align, size, flags); - } else { - bx.memcpy(dst, align, src, align, size, flags); - } -} - -fn memset_intrinsic( - bx: &mut Builder<'a, 'll, 'tcx>, - volatile: bool, - ty: Ty<'tcx>, - dst: &'ll Value, - val: &'ll Value, - count: &'ll Value, -) { - let (size, align) = bx.size_and_align_of(ty); - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - bx.memset(dst, val, size, align, flags); -} - fn try_intrinsic( bx: &mut Builder<'a, 'll, 'tcx>, try_func: &'ll Value, @@ -855,6 +367,8 @@ fn try_intrinsic( bx.store(bx.const_i32(0), dest, ret_align); } else if wants_msvc_seh(bx.sess()) { codegen_msvc_try(bx, try_func, data, catch_func, dest); + } else if bx.sess().target.target.options.is_like_emscripten { + codegen_emcc_try(bx, try_func, data, catch_func, dest); } else { codegen_gnu_try(bx, try_func, data, catch_func, dest); } @@ -880,7 +394,8 @@ fn codegen_msvc_try( let mut normal = bx.build_sibling_block("normal"); let mut catchswitch = bx.build_sibling_block("catchswitch"); - let mut catchpad = bx.build_sibling_block("catchpad"); + let mut catchpad_rust = bx.build_sibling_block("catchpad_rust"); + let mut catchpad_foreign = bx.build_sibling_block("catchpad_foreign"); let mut caught = bx.build_sibling_block("caught"); let try_func = llvm::get_param(bx.llfn(), 0); @@ -890,21 +405,26 @@ fn codegen_msvc_try( // We're generating an IR snippet that looks like: // // declare i32 @rust_try(%try_func, %data, %catch_func) { - // %slot = alloca u8* + // %slot = alloca i8* // invoke %try_func(%data) to label %normal unwind label %catchswitch // // normal: // ret i32 0 // // catchswitch: - // %cs = catchswitch within none [%catchpad] unwind to caller + // %cs = catchswitch within none [%catchpad_rust, %catchpad_foreign] unwind to caller // - // catchpad: - // %tok = catchpad within %cs [%type_descriptor, 0, %slot] + // catchpad_rust: + // %tok = catchpad within %cs [%type_descriptor, 8, %slot] // %ptr = load %slot // call %catch_func(%data, %ptr) // catchret from %tok to label %caught // + // catchpad_foreign: + // %tok = catchpad within %cs [null, 64, null] + // call %catch_func(%data, null) + // catchret from %tok to label %caught + // // caught: // ret i32 1 // } @@ -912,13 +432,11 @@ fn codegen_msvc_try( // This structure follows the basic usage of throw/try/catch in LLVM. // For example, compile this C++ snippet to see what LLVM generates: // - // #include - // // struct rust_panic { // rust_panic(const rust_panic&); // ~rust_panic(); // - // uint64_t x[2]; + // void* x[2]; // }; // // int __rust_try( @@ -932,6 +450,9 @@ fn codegen_msvc_try( // } catch(rust_panic& a) { // catch_func(data, &a); // return 1; + // } catch(...) { + // catch_func(data, NULL); + // return 1; // } // } // @@ -942,8 +463,9 @@ fn codegen_msvc_try( normal.ret(bx.const_i32(0)); - let cs = catchswitch.catch_switch(None, None, 1); - catchswitch.add_handler(cs, catchpad.llbb()); + let cs = catchswitch.catch_switch(None, None, 2); + catchswitch.add_handler(cs, catchpad_rust.llbb()); + catchswitch.add_handler(cs, catchpad_foreign.llbb()); // We can't use the TypeDescriptor defined in libpanic_unwind because it // might be in another DLL and the SEH encoding only supports specifying @@ -977,11 +499,17 @@ fn codegen_msvc_try( // // Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang let flags = bx.const_i32(8); - let funclet = catchpad.catch_pad(cs, &[tydesc, flags, slot]); - let ptr = catchpad.load(slot, ptr_align); - catchpad.call(catch_func, &[data, ptr], Some(&funclet)); - - catchpad.catch_ret(&funclet, caught.llbb()); + let funclet = catchpad_rust.catch_pad(cs, &[tydesc, flags, slot]); + let ptr = catchpad_rust.load(slot, ptr_align); + catchpad_rust.call(catch_func, &[data, ptr], Some(&funclet)); + catchpad_rust.catch_ret(&funclet, caught.llbb()); + + // The flag value of 64 indicates a "catch-all". + let flags = bx.const_i32(64); + let null = bx.const_null(bx.type_i8p()); + let funclet = catchpad_foreign.catch_pad(cs, &[null, flags, null]); + catchpad_foreign.call(catch_func, &[data, null], Some(&funclet)); + catchpad_foreign.catch_ret(&funclet, caught.llbb()); caught.ret(bx.const_i32(1)); }); @@ -1044,13 +572,7 @@ fn codegen_gnu_try( // rust_try ignores the selector. let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false); let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 1); - let tydesc = match bx.tcx().lang_items().eh_catch_typeinfo() { - Some(tydesc) => { - let tydesc = bx.get_static(tydesc); - bx.bitcast(tydesc, bx.type_i8p()) - } - None => bx.const_null(bx.type_i8p()), - }; + let tydesc = bx.const_null(bx.type_i8p()); catch.add_clause(vals, tydesc); let ptr = catch.extract_value(vals, 0); catch.call(catch_func, &[data, ptr], None); @@ -1064,6 +586,88 @@ fn codegen_gnu_try( bx.store(ret, dest, i32_align); } +// Variant of codegen_gnu_try used for emscripten where Rust panics are +// implemented using C++ exceptions. Here we use exceptions of a specific type +// (`struct rust_panic`) to represent Rust panics. +fn codegen_emcc_try( + bx: &mut Builder<'a, 'll, 'tcx>, + try_func: &'ll Value, + data: &'ll Value, + catch_func: &'ll Value, + dest: &'ll Value, +) { + let llfn = get_rust_try_fn(bx, &mut |mut bx| { + // Codegens the shims described above: + // + // bx: + // invoke %try_func(%data) normal %normal unwind %catch + // + // normal: + // ret 0 + // + // catch: + // (%ptr, %selector) = landingpad + // %rust_typeid = @llvm.eh.typeid.for(@_ZTI10rust_panic) + // %is_rust_panic = %selector == %rust_typeid + // %catch_data = alloca { i8*, i8 } + // %catch_data[0] = %ptr + // %catch_data[1] = %is_rust_panic + // call %catch_func(%data, %catch_data) + // ret 1 + + bx.sideeffect(); + + let mut then = bx.build_sibling_block("then"); + let mut catch = bx.build_sibling_block("catch"); + + let try_func = llvm::get_param(bx.llfn(), 0); + let data = llvm::get_param(bx.llfn(), 1); + let catch_func = llvm::get_param(bx.llfn(), 2); + bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None); + then.ret(bx.const_i32(0)); + + // Type indicator for the exception being thrown. + // + // The first value in this tuple is a pointer to the exception object + // being thrown. The second value is a "selector" indicating which of + // the landing pad clauses the exception's type had been matched to. + let tydesc = bx.eh_catch_typeinfo(); + let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false); + let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 2); + catch.add_clause(vals, tydesc); + catch.add_clause(vals, bx.const_null(bx.type_i8p())); + let ptr = catch.extract_value(vals, 0); + let selector = catch.extract_value(vals, 1); + + // Check if the typeid we got is the one for a Rust panic. + let llvm_eh_typeid_for = bx.get_intrinsic("llvm.eh.typeid.for"); + let rust_typeid = catch.call(llvm_eh_typeid_for, &[tydesc], None); + let is_rust_panic = catch.icmp(IntPredicate::IntEQ, selector, rust_typeid); + let is_rust_panic = catch.zext(is_rust_panic, bx.type_bool()); + + // We need to pass two values to catch_func (ptr and is_rust_panic), so + // create an alloca and pass a pointer to that. + let ptr_align = bx.tcx().data_layout.pointer_align.abi; + let i8_align = bx.tcx().data_layout.i8_align.abi; + let catch_data = + catch.alloca(bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false), ptr_align); + let catch_data_0 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(0)]); + catch.store(ptr, catch_data_0, ptr_align); + let catch_data_1 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(1)]); + catch.store(is_rust_panic, catch_data_1, i8_align); + let catch_data = catch.bitcast(catch_data, bx.type_i8p()); + + catch.call(catch_func, &[data, catch_data], None); + catch.ret(bx.const_i32(1)); + }); + + // Note that no invoke is used here because by definition this function + // can't panic (that's what it's catching). + let ret = bx.call(llfn, &[try_func, data, catch_func], None); + let i32_align = bx.tcx().data_layout.i32_align.abi; + bx.store(ret, dest, i32_align); +} + // Helper function to give a Block to a closure to codegen a shim function. // This is currently primarily used for the `try` intrinsic functions above. fn gen_fn<'ll, 'tcx>( @@ -1179,7 +783,7 @@ fn generic_simd_intrinsic( if name == sym::simd_select_bitmask { let in_ty = arg_tys[0]; - let m_len = match in_ty.kind { + let m_len = match in_ty.kind() { // Note that this `.unwrap()` crashes for isize/usize, that's sort // of intentional as there's not currently a use case for that. ty::Int(i) => i.bit_width().unwrap(), @@ -1344,7 +948,7 @@ fn generic_simd_intrinsic( m_len, v_len ); - match m_elem_ty.kind { + match m_elem_ty.kind() { ty::Int(_) => {} _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty), } @@ -1363,13 +967,13 @@ fn generic_simd_intrinsic( // If the vector has less than 8 lanes, an u8 is returned with zeroed // trailing bits. let expected_int_bits = in_len.max(8); - match ret_ty.kind { + match ret_ty.kind() { ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (), _ => return_error!("bitmask `{}`, expected `u{}`", ret_ty, expected_int_bits), } // Integer vector : - let (i_xn, in_elem_bitwidth) = match in_elem.kind { + let (i_xn, in_elem_bitwidth) = match in_elem.kind() { ty::Int(i) => { (args[0].immediate(), i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits())) } @@ -1426,7 +1030,7 @@ fn generic_simd_intrinsic( } } } - let ety = match in_elem.kind { + let ety = match in_elem.kind() { ty::Float(f) if f.bit_width() == 32 => { if in_len < 2 || in_len > 16 { return_error!( @@ -1520,7 +1124,7 @@ fn generic_simd_intrinsic( // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 fn llvm_vector_str(elem_ty: Ty<'_>, vec_len: u64, no_pointers: usize) -> String { let p0s: String = "p0".repeat(no_pointers); - match elem_ty.kind { + match *elem_ty.kind() { ty::Int(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), ty::Uint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), ty::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), @@ -1535,7 +1139,7 @@ fn generic_simd_intrinsic( mut no_pointers: usize, ) -> &'ll Type { // FIXME: use cx.layout_of(ty).llvm_type() ? - let mut elem_ty = match elem_ty.kind { + let mut elem_ty = match *elem_ty.kind() { ty::Int(v) => cx.type_int_from_ty(v), ty::Uint(v) => cx.type_uint_from_ty(v), ty::Float(v) => cx.type_float_from_ty(v), @@ -1588,7 +1192,7 @@ fn generic_simd_intrinsic( // This counts how many pointers fn ptr_count(t: Ty<'_>) -> usize { - match t.kind { + match t.kind() { ty::RawPtr(p) => 1 + ptr_count(p.ty), _ => 0, } @@ -1596,7 +1200,7 @@ fn generic_simd_intrinsic( // Non-ptr type fn non_ptr(t: Ty<'_>) -> Ty<'_> { - match t.kind { + match t.kind() { ty::RawPtr(p) => non_ptr(p.ty), _ => t, } @@ -1604,7 +1208,7 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind { + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { ty::RawPtr(p) if p.ty == in_elem => { (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) } @@ -1629,7 +1233,7 @@ fn generic_simd_intrinsic( assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind { + match arg_tys[2].simd_type(tcx).kind() { ty::Int(_) => (), _ => { require!( @@ -1711,7 +1315,7 @@ fn generic_simd_intrinsic( // This counts how many pointers fn ptr_count(t: Ty<'_>) -> usize { - match t.kind { + match t.kind() { ty::RawPtr(p) => 1 + ptr_count(p.ty), _ => 0, } @@ -1719,7 +1323,7 @@ fn generic_simd_intrinsic( // Non-ptr type fn non_ptr(t: Ty<'_>) -> Ty<'_> { - match t.kind { + match t.kind() { ty::RawPtr(p) => non_ptr(p.ty), _ => t, } @@ -1727,7 +1331,7 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind { + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => { (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) } @@ -1752,7 +1356,7 @@ fn generic_simd_intrinsic( assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind { + match arg_tys[2].simd_type(tcx).kind() { ty::Int(_) => (), _ => { require!( @@ -1808,7 +1412,7 @@ fn generic_simd_intrinsic( in_ty, ret_ty ); - return match in_elem.kind { + return match in_elem.kind() { ty::Int(_) | ty::Uint(_) => { let r = bx.$integer_reduce(args[0].immediate()); if $ordered { @@ -1880,7 +1484,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, in_ty, ret_ty ); - return match in_elem.kind { + return match in_elem.kind() { ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)), ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)), ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())), @@ -1915,7 +1519,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ); args[0].immediate() } else { - match in_elem.kind { + match in_elem.kind() { ty::Int(_) | ty::Uint(_) => {} _ => return_error!( "unsupported {} from `{}` with element `{}` to `{}`", @@ -1931,7 +1535,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, let i1xn = bx.type_vector(i1, in_len as u64); bx.trunc(args[0].immediate(), i1xn) }; - return match in_elem.kind { + return match in_elem.kind() { ty::Int(_) | ty::Uint(_) => { let r = bx.$red(input); Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) }) @@ -1979,7 +1583,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, Unsupported, } - let (in_style, in_width) = match in_elem.kind { + let (in_style, in_width) = match in_elem.kind() { // vectors of pointer-sized integers should've been // disallowed before here, so this unwrap is safe. ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()), @@ -1987,7 +1591,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ty::Float(f) => (Style::Float, f.bit_width()), _ => (Style::Unsupported, 0), }; - let (out_style, out_width) = match out_elem.kind { + let (out_style, out_width) = match out_elem.kind() { ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()), ty::Uint(u) => (Style::Int(false), u.bit_width().unwrap()), ty::Float(f) => (Style::Float, f.bit_width()), @@ -2043,7 +1647,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, macro_rules! arith { ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { $(if name == sym::$name { - match in_elem.kind { + match in_elem.kind() { $($(ty::$p(_))|* => { return Ok(bx.$call(args[0].immediate(), args[1].immediate())) })* @@ -2077,7 +1681,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, let rhs = args[1].immediate(); let is_add = name == sym::simd_saturating_add; let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; - let (signed, elem_width, elem_ty) = match in_elem.kind { + let (signed, elem_width, elem_ty) = match *in_elem.kind() { ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)), ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)), _ => { @@ -2112,38 +1716,13 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, // FIXME: there’s multiple of this functions, investigate using some of the already existing // stuffs. fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> { - match ty.kind { - ty::Int(t) => Some(( - match t { - ast::IntTy::Isize => u64::from(cx.tcx.sess.target.ptr_width), - ast::IntTy::I8 => 8, - ast::IntTy::I16 => 16, - ast::IntTy::I32 => 32, - ast::IntTy::I64 => 64, - ast::IntTy::I128 => 128, - }, - true, - )), - ty::Uint(t) => Some(( - match t { - ast::UintTy::Usize => u64::from(cx.tcx.sess.target.ptr_width), - ast::UintTy::U8 => 8, - ast::UintTy::U16 => 16, - ast::UintTy::U32 => 32, - ast::UintTy::U64 => 64, - ast::UintTy::U128 => 128, - }, - false, - )), - _ => None, - } -} - -// Returns the width of a float Ty -// Returns None if the type is not a float -fn float_type_width(ty: Ty<'_>) -> Option { - match ty.kind { - ty::Float(t) => Some(t.bit_width()), + match ty.kind() { + ty::Int(t) => { + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true)) + } + ty::Uint(t) => { + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false)) + } _ => None, } } diff --git a/src/librustc_codegen_llvm/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs similarity index 97% rename from src/librustc_codegen_llvm/lib.rs rename to compiler/rustc_codegen_llvm/src/lib.rs index 67d4b2642c..f14493e604 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] @@ -12,7 +12,6 @@ #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] -#![feature(trusted_len)] #![recursion_limit = "256"] use back::write::{create_informational_target_machine, create_target_machine}; @@ -130,6 +129,13 @@ impl WriteBackendMethods for LlvmCodegenBackend { llvm::LLVMRustPrintPassTimings(); } } + fn run_link( + cgcx: &CodegenContext, + diag_handler: &Handler, + modules: Vec>, + ) -> Result, FatalError> { + back::write::link(cgcx, diag_handler, modules) + } fn run_fat_lto( cgcx: &CodegenContext, modules: Vec>, diff --git a/src/librustc_codegen_llvm/llvm/archive_ro.rs b/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs similarity index 100% rename from src/librustc_codegen_llvm/llvm/archive_ro.rs rename to compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs diff --git a/src/librustc_codegen_llvm/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs similarity index 98% rename from src/librustc_codegen_llvm/llvm/diagnostic.rs rename to compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index 47f5c94e70..ccd3e42e45 100644 --- a/src/librustc_codegen_llvm/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -118,6 +118,7 @@ pub enum Diagnostic<'ll> { InlineAsm(InlineAsmDiagnostic<'ll>), PGO(&'ll DiagnosticInfo), Linker(&'ll DiagnosticInfo), + Unsupported(&'ll DiagnosticInfo), /// LLVM has other types that we do not wrap here. UnknownDiagnostic(&'ll DiagnosticInfo), @@ -159,6 +160,7 @@ impl Diagnostic<'ll> { Dk::PGOProfile => PGO(di), Dk::Linker => Linker(di), + Dk::Unsupported => Unsupported(di), _ => UnknownDiagnostic(di), } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs similarity index 99% rename from src/librustc_codegen_llvm/llvm/ffi.rs rename to compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 32822eba93..af3f3e7aa0 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -96,7 +96,7 @@ pub enum DLLStorageClass { DllExport = 2, // Function to be accessible from DLL. } -/// Matches LLVMRustAttribute in rustllvm.h +/// Matches LLVMRustAttribute in LLVMWrapper.h /// Semantically a subset of the C++ enum llvm::Attribute::AttrKind, /// though it is not ABI compatible (since it's a C++ enum) #[repr(C)] @@ -483,6 +483,7 @@ pub enum DiagnosticKind { OptimizationFailure, PGOProfile, Linker, + Unsupported, } /// LLVMRustDiagnosticLevel @@ -948,7 +949,6 @@ extern "C" { // Operations on other types pub fn LLVMVoidTypeInContext(C: &Context) -> &Type; - pub fn LLVMX86MMXTypeInContext(C: &Context) -> &Type; pub fn LLVMRustMetadataTypeInContext(C: &Context) -> &Type; // Operations on all values @@ -1705,7 +1705,7 @@ extern "C" { PM: &PassManager<'_>, ); - // Stuff that's in rustllvm/ because it's not upstream yet. + // Stuff that's in llvm-wrapper/ because it's not upstream yet. /// Opens an object file. pub fn LLVMCreateObjectFile( diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs similarity index 97% rename from src/librustc_codegen_llvm/llvm/mod.rs rename to compiler/rustc_codegen_llvm/src/llvm/mod.rs index c09e3659f8..ed9b99188b 100644 --- a/src/librustc_codegen_llvm/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -37,6 +37,12 @@ pub fn AddFunctionAttrStringValue(llfn: &'a Value, idx: AttributePlace, attr: &C } } +pub fn AddFunctionAttrString(llfn: &'a Value, idx: AttributePlace, attr: &CStr) { + unsafe { + LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), std::ptr::null()) + } +} + #[derive(Copy, Clone)] pub enum AttributePlace { ReturnValue, diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs similarity index 99% rename from src/librustc_codegen_llvm/llvm_util.rs rename to compiler/rustc_codegen_llvm/src/llvm_util.rs index f0b5045983..900f2df383 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -203,7 +203,6 @@ const X86_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("fma", None), ("fxsr", None), ("lzcnt", None), - ("mmx", Some(sym::mmx_target_feature)), ("movbe", Some(sym::movbe_target_feature)), ("pclmulqdq", None), ("popcnt", None), diff --git a/src/librustc_codegen_llvm/metadata.rs b/compiler/rustc_codegen_llvm/src/metadata.rs similarity index 100% rename from src/librustc_codegen_llvm/metadata.rs rename to compiler/rustc_codegen_llvm/src/metadata.rs diff --git a/src/librustc_codegen_llvm/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs similarity index 100% rename from src/librustc_codegen_llvm/mono_item.rs rename to compiler/rustc_codegen_llvm/src/mono_item.rs diff --git a/src/librustc_codegen_llvm/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs similarity index 98% rename from src/librustc_codegen_llvm/type_.rs rename to compiler/rustc_codegen_llvm/src/type_.rs index 3b53b4fe77..a43724fd49 100644 --- a/src/librustc_codegen_llvm/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -62,10 +62,6 @@ impl CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) } } - crate fn type_x86_mmx(&self) -> &'ll Type { - unsafe { llvm::LLVMX86MMXTypeInContext(self.llcx) } - } - crate fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } diff --git a/src/librustc_codegen_llvm/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs similarity index 89% rename from src/librustc_codegen_llvm/type_of.rs rename to compiler/rustc_codegen_llvm/src/type_of.rs index 40870c6647..e0754d21df 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -4,7 +4,7 @@ use crate::type_::Type; use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout}; -use rustc_middle::ty::print::obsolete::DefPathBasedNames; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; @@ -21,23 +21,8 @@ fn uncached_llvm_type<'a, 'tcx>( match layout.abi { Abi::Scalar(_) => bug!("handled elsewhere"), Abi::Vector { ref element, count } => { - // LLVM has a separate type for 64-bit SIMD vectors on X86 called - // `x86_mmx` which is needed for some SIMD operations. As a bit of a - // hack (all SIMD definitions are super unstable anyway) we - // recognize any one-element SIMD vector as "this should be an - // x86_mmx" type. In general there shouldn't be a need for other - // one-element SIMD vectors, so it's assumed this won't clash with - // much else. - let use_x86_mmx = count == 1 - && layout.size.bits() == 64 - && (cx.sess().target.target.arch == "x86" - || cx.sess().target.target.arch == "x86_64"); - if use_x86_mmx { - return cx.type_x86_mmx(); - } else { - let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); - return cx.type_vector(element, count); - } + let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); + return cx.type_vector(element, count); } Abi::ScalarPair(..) => { return cx.type_struct( @@ -51,33 +36,35 @@ fn uncached_llvm_type<'a, 'tcx>( Abi::Uninhabited | Abi::Aggregate { .. } => {} } - let name = match layout.ty.kind { - ty::Closure(..) | - ty::Generator(..) | - ty::Adt(..) | + let name = match layout.ty.kind() { // FIXME(eddyb) producing readable type names for trait objects can result // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | - ty::Foreign(..) | - ty::Str => { - let mut name = String::with_capacity(32); - let printer = DefPathBasedNames::new(cx.tcx, true, true); - printer.push_type_name(layout.ty, &mut name, false); - if let (&ty::Adt(def, _), &Variants::Single { index }) - = (&layout.ty.kind, &layout.variants) + ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str + if !cx.sess().fewer_names() => + { + let mut name = with_no_trimmed_paths(|| layout.ty.to_string()); + if let (&ty::Adt(def, _), &Variants::Single { index }) = + (layout.ty.kind(), &layout.variants) { if def.is_enum() && !def.variants.is_empty() { write!(&mut name, "::{}", def.variants[index].ident).unwrap(); } } - if let (&ty::Generator(_, _, _), &Variants::Single { index }) - = (&layout.ty.kind, &layout.variants) + if let (&ty::Generator(_, _, _), &Variants::Single { index }) = + (layout.ty.kind(), &layout.variants) { write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap(); } Some(name) } - _ => None + ty::Adt(..) => { + // If `Some` is returned then a named struct is created in LLVM. Name collisions are + // avoided by LLVM (with increasing suffixes). If rustc doesn't generate names then that + // can improve perf. + Some(String::new()) + } + _ => None, }; match layout.fields { @@ -236,7 +223,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { return llty; } - let llty = match self.ty.kind { + let llty = match *self.ty.kind() { ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { cx.type_ptr_to(cx.layout_of(ty).llvm_type(cx)) } @@ -329,7 +316,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { ) -> &'a Type { // HACK(eddyb) special-case fat pointers until LLVM removes // pointee types, to avoid bitcasting every `OperandRef::deref`. - match self.ty.kind { + match self.ty.kind() { ty::Ref(..) | ty::RawPtr(_) => { return self.field(cx, index).llvm_type(cx); } diff --git a/src/librustc_codegen_llvm/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs similarity index 99% rename from src/librustc_codegen_llvm/va_arg.rs rename to compiler/rustc_codegen_llvm/src/va_arg.rs index 54efa05aee..22ed4dd757 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -11,7 +11,6 @@ use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::Ty; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size}; -#[allow(dead_code)] fn round_pointer_up_to_alignment( bx: &mut Builder<'a, 'll, 'tcx>, addr: &'ll Value, diff --git a/src/librustc_codegen_llvm/value.rs b/compiler/rustc_codegen_llvm/src/value.rs similarity index 100% rename from src/librustc_codegen_llvm/value.rs rename to compiler/rustc_codegen_llvm/src/value.rs diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml new file mode 100644 index 0000000000..e5df0f6094 --- /dev/null +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -0,0 +1,36 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_codegen_ssa" +version = "0.0.0" +edition = "2018" + +[lib] +test = false + +[dependencies] +bitflags = "1.2.1" +cc = "1.0.1" +num_cpus = "1.0" +memmap = "0.7" +tracing = "0.1" +libc = "0.2.50" +jobserver = "0.1.11" +tempfile = "3.1" +pathdiff = "0.2.0" + +rustc_serialize = { path = "../rustc_serialize" } +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"} +rustc_errors = { path = "../rustc_errors" } +rustc_fs_util = { path = "../rustc_fs_util" } +rustc_hir = { path = "../rustc_hir" } +rustc_incremental = { path = "../rustc_incremental" } +rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } +rustc_target = { path = "../rustc_target" } +rustc_session = { path = "../rustc_session" } diff --git a/src/librustc_codegen_ssa/README.md b/compiler/rustc_codegen_ssa/README.md similarity index 100% rename from src/librustc_codegen_ssa/README.md rename to compiler/rustc_codegen_ssa/README.md diff --git a/src/librustc_codegen_ssa/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs similarity index 100% rename from src/librustc_codegen_ssa/back/archive.rs rename to compiler/rustc_codegen_ssa/src/back/archive.rs diff --git a/src/librustc_codegen_ssa/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs similarity index 100% rename from src/librustc_codegen_ssa/back/command.rs rename to compiler/rustc_codegen_ssa/src/back/command.rs diff --git a/src/librustc_codegen_ssa/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs similarity index 94% rename from src/librustc_codegen_ssa/back/link.rs rename to compiler/rustc_codegen_ssa/src/back/link.rs index bfcf979d12..010fd4e9c5 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1014,86 +1014,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { } } -// Because windows-gnu target is meant to be self-contained for pure Rust code it bundles -// own mingw-w64 libraries. These libraries are usually not compatible with mingw-w64 -// installed in the system. This breaks many cases where Rust is mixed with other languages -// (e.g. *-sys crates). -// We prefer system mingw-w64 libraries if they are available to avoid this issue. -fn get_crt_libs_path(sess: &Session) -> Option { - fn find_exe_in_path

(exe_name: P) -> Option - where - P: AsRef, - { - for dir in env::split_paths(&env::var_os("PATH")?) { - let full_path = dir.join(&exe_name); - if full_path.is_file() { - return Some(fix_windows_verbatim_for_gcc(&full_path)); - } - } - None - } - - fn probe(sess: &Session) -> Option { - if let (linker, LinkerFlavor::Gcc) = linker_and_flavor(&sess) { - let linker_path = if cfg!(windows) && linker.extension().is_none() { - linker.with_extension("exe") - } else { - linker - }; - if let Some(linker_path) = find_exe_in_path(linker_path) { - let mingw_arch = match &sess.target.target.arch { - x if x == "x86" => "i686", - x => x, - }; - let mingw_bits = &sess.target.target.target_pointer_width; - let mingw_dir = format!("{}-w64-mingw32", mingw_arch); - // Here we have path/bin/gcc but we need path/ - let mut path = linker_path; - path.pop(); - path.pop(); - // Loosely based on Clang MinGW driver - let probe_paths = vec![ - path.join(&mingw_dir).join("lib"), // Typical path - path.join(&mingw_dir).join("sys-root/mingw/lib"), // Rare path - path.join(format!( - "lib/mingw/tools/install/mingw{}/{}/lib", - &mingw_bits, &mingw_dir - )), // Chocolatey is creative - ]; - for probe_path in probe_paths { - if probe_path.join("crt2.o").exists() { - return Some(probe_path); - }; - } - }; - }; - None - } - - let mut system_library_path = sess.system_library_path.borrow_mut(); - match &*system_library_path { - Some(Some(compiler_libs_path)) => Some(compiler_libs_path.clone()), - Some(None) => None, - None => { - let path = probe(sess); - *system_library_path = Some(path.clone()); - path - } - } -} - fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf { - // prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details - if sess.opts.debugging_opts.link_self_contained.is_none() - && sess.target.target.llvm_target.contains("windows-gnu") - { - if let Some(compiler_libs_path) = get_crt_libs_path(sess) { - let file_path = compiler_libs_path.join(name); - if file_path.exists() { - return file_path; - } - } - } let fs = sess.target_filesearch(PathKind::Native); let file_path = fs.get_lib_path().join(name); if file_path.exists() { @@ -1155,7 +1076,7 @@ fn exec_linker( } .to_string(), ); - args.push_str("\n"); + args.push('\n'); } let file = tmpdir.join("linker-arguments"); let bytes = if sess.target.target.options.is_like_msvc { @@ -1286,10 +1207,32 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { } } +// Returns true if linker is located within sysroot +fn detect_self_contained_mingw(sess: &Session) -> bool { + let (linker, _) = linker_and_flavor(&sess); + // Assume `-C linker=rust-lld` as self-contained mode + if linker == Path::new("rust-lld") { + return true; + } + let linker_with_extension = if cfg!(windows) && linker.extension().is_none() { + linker.with_extension("exe") + } else { + linker + }; + for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { + let full_path = dir.join(&linker_with_extension); + // If linker comes from sysroot assume self-contained mode + if full_path.is_file() && !full_path.starts_with(&sess.sysroot) { + return false; + } + } + true +} + /// Whether we link to our own CRT objects instead of relying on gcc to pull them. /// We only provide such support for a very limited number of targets. fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { - if let Some(self_contained) = sess.opts.debugging_opts.link_self_contained { + if let Some(self_contained) = sess.opts.cg.link_self_contained { return self_contained; } @@ -1298,10 +1241,10 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { // 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)), - // FIXME: Find some heuristic for "native mingw toolchain is available", - // likely based on `get_crt_libs_path` (https://github.com/rust-lang/rust/pull/67429). Some(CrtObjectsFallback::Mingw) => { - sess.host == sess.target.target && sess.target.target.target_vendor != "uwp" + sess.host == sess.target.target + && sess.target.target.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, @@ -1390,9 +1333,6 @@ fn add_late_link_args( crate_type: CrateType, codegen_results: &CodegenResults, ) { - if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { - cmd.args(args); - } let any_dynamic_crate = crate_type == CrateType::Dylib || codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| { *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic) @@ -1406,6 +1346,9 @@ fn add_late_link_args( cmd.args(args); } } + if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { + cmd.args(args); + } } /// Add arbitrary "post-link" args defined by the target spec. @@ -1498,16 +1441,6 @@ fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<' /// Add sysroot and other globally set directories to the directory search list. fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) { - // Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details. - if sess.opts.debugging_opts.link_self_contained.is_none() - && cfg!(windows) - && sess.target.target.llvm_target.contains("windows-gnu") - { - if let Some(compiler_libs_path) = get_crt_libs_path(sess) { - cmd.include_path(&compiler_libs_path); - } - } - // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); @@ -1591,6 +1524,9 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT add_pre_link_args(cmd, sess, flavor); + // NO-OPT-OUT, OBJECT-FILES-NO + add_apple_sdk(cmd, sess, flavor); + // NO-OPT-OUT add_link_script(cmd, sess, tmpdir, crate_type); @@ -1668,7 +1604,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // FIXME: Order dependent, applies to the following objects. Where should it be placed? // Try to strip as much out of the generated object by removing unused // sections if possible. See more comments in linker.rs - if sess.opts.cg.link_dead_code != Some(true) { + if !sess.link_dead_code() { let keep_metadata = crate_type == CrateType::Dylib; cmd.gc_sections(keep_metadata); } @@ -2150,3 +2086,86 @@ fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { config::Lto::No | config::Lto::ThinLocal => false, } } + +fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { + let arch = &sess.target.target.arch; + let os = &sess.target.target.target_os; + let llvm_target = &sess.target.target.llvm_target; + if sess.target.target.target_vendor != "apple" + || !matches!(os.as_str(), "ios" | "tvos") + || flavor != LinkerFlavor::Gcc + { + return; + } + let sdk_name = match (arch.as_str(), os.as_str()) { + ("aarch64", "tvos") => "appletvos", + ("x86_64", "tvos") => "appletvsimulator", + ("arm", "ios") => "iphoneos", + ("aarch64", "ios") => "iphoneos", + ("x86", "ios") => "iphonesimulator", + ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx10.15", + ("x86_64", "ios") => "iphonesimulator", + _ => { + sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os)); + return; + } + }; + let sdk_root = match get_apple_sdk_root(sdk_name) { + Ok(s) => s, + Err(e) => { + sess.err(&e); + return; + } + }; + let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen"); + cmd.args(&["-arch", arch_name, "-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]); +} + +fn get_apple_sdk_root(sdk_name: &str) -> Result { + // Following what clang does + // (https://github.com/llvm/llvm-project/blob/ + // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678) + // to allow the SDK path to be set. (For clang, xcrun sets + // SDKROOT; for rustc, the user or build system can set it, or we + // can fall back to checking for xcrun on PATH.) + if let Ok(sdkroot) = env::var("SDKROOT") { + let p = Path::new(&sdkroot); + match sdk_name { + // Ignore `SDKROOT` if it's clearly set for the wrong platform. + "appletvos" + if sdkroot.contains("TVSimulator.platform") + || sdkroot.contains("MacOSX.platform") => {} + "appletvsimulator" + if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {} + "iphoneos" + if sdkroot.contains("iPhoneSimulator.platform") + || sdkroot.contains("MacOSX.platform") => {} + "iphonesimulator" + if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => { + } + "macosx10.15" + if sdkroot.contains("iPhoneOS.platform") + || sdkroot.contains("iPhoneSimulator.platform") => {} + // Ignore `SDKROOT` if it's not a valid path. + _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {} + _ => return Ok(sdkroot), + } + } + let res = + Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then( + |output| { + if output.status.success() { + Ok(String::from_utf8(output.stdout).unwrap()) + } else { + let error = String::from_utf8(output.stderr); + let error = format!("process exit with error: {}", error.unwrap()); + Err(io::Error::new(io::ErrorKind::Other, &error[..])) + } + }, + ); + + match res { + Ok(output) => Ok(output.trim().to_string()), + Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)), + } +} diff --git a/src/librustc_codegen_ssa/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs similarity index 100% rename from src/librustc_codegen_ssa/back/linker.rs rename to compiler/rustc_codegen_ssa/src/back/linker.rs diff --git a/src/librustc_codegen_ssa/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs similarity index 100% rename from src/librustc_codegen_ssa/back/lto.rs rename to compiler/rustc_codegen_ssa/src/back/lto.rs diff --git a/src/librustc_codegen_ssa/back/mod.rs b/compiler/rustc_codegen_ssa/src/back/mod.rs similarity index 100% rename from src/librustc_codegen_ssa/back/mod.rs rename to compiler/rustc_codegen_ssa/src/back/mod.rs diff --git a/src/librustc_codegen_ssa/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs similarity index 100% rename from src/librustc_codegen_ssa/back/rpath.rs rename to compiler/rustc_codegen_ssa/src/back/rpath.rs diff --git a/src/librustc_codegen_ssa/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs similarity index 100% rename from src/librustc_codegen_ssa/back/rpath/tests.rs rename to compiler/rustc_codegen_ssa/src/back/rpath/tests.rs diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs similarity index 100% rename from src/librustc_codegen_ssa/back/symbol_export.rs rename to compiler/rustc_codegen_ssa/src/back/symbol_export.rs diff --git a/src/librustc_codegen_ssa/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs similarity index 97% rename from src/librustc_codegen_ssa/back/write.rs rename to compiler/rustc_codegen_ssa/src/back/write.rs index 7d69bb983d..0edf0fcd1a 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -702,6 +702,7 @@ impl WorkItem { enum WorkItemResult { Compiled(CompiledModule), + NeedsLink(ModuleCodegen), NeedsFatLTO(FatLTOInput), NeedsThinLTO(String, B::ThinBuffer), } @@ -801,11 +802,8 @@ fn execute_optimize_work_item( None }; - Ok(match lto_type { - ComputedLtoType::No => { - let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? }; - WorkItemResult::Compiled(module) - } + match lto_type { + ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config), ComputedLtoType::Thin => { let (name, thin_buffer) = B::prepare_thin(module); if let Some(path) = bitcode { @@ -813,7 +811,7 @@ fn execute_optimize_work_item( panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); } - WorkItemResult::NeedsThinLTO(name, thin_buffer) + Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer)) } ComputedLtoType::Fat => match bitcode { Some(path) => { @@ -821,11 +819,11 @@ fn execute_optimize_work_item( fs::write(&path, buffer.data()).unwrap_or_else(|e| { panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); - WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }) + Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer })) } - None => WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module)), + None => Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module))), }, - }) + } } fn execute_copy_from_cache_work_item( @@ -870,13 +868,26 @@ fn execute_lto_work_item( cgcx: &CodegenContext, mut module: lto::LtoModuleCodegen, module_config: &ModuleConfig, +) -> Result, FatalError> { + let module = unsafe { module.optimize(cgcx)? }; + finish_intra_module_work(cgcx, module, module_config) +} + +fn finish_intra_module_work( + cgcx: &CodegenContext, + module: ModuleCodegen, + module_config: &ModuleConfig, ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); - unsafe { - let module = module.optimize(cgcx)?; - let module = B::codegen(cgcx, &diag_handler, module, module_config)?; + if !cgcx.opts.debugging_opts.combine_cgu + || module.kind == ModuleKind::Metadata + || module.kind == ModuleKind::Allocator + { + let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? }; Ok(WorkItemResult::Compiled(module)) + } else { + Ok(WorkItemResult::NeedsLink(module)) } } @@ -891,6 +902,10 @@ pub enum Message { thin_buffer: B::ThinBuffer, worker_id: usize, }, + NeedsLink { + module: ModuleCodegen, + worker_id: usize, + }, Done { result: Result>, worker_id: usize, @@ -1178,6 +1193,7 @@ fn start_executing_work( let mut compiled_modules = vec![]; let mut compiled_metadata_module = None; let mut compiled_allocator_module = None; + let mut needs_link = Vec::new(); let mut needs_fat_lto = Vec::new(); let mut needs_thin_lto = Vec::new(); let mut lto_import_only_modules = Vec::new(); @@ -1434,6 +1450,10 @@ fn start_executing_work( } } } + Message::NeedsLink { module, worker_id } => { + free_worker(worker_id); + needs_link.push(module); + } Message::NeedsFatLTO { result, worker_id } => { assert!(!started_lto); free_worker(worker_id); @@ -1462,6 +1482,18 @@ fn start_executing_work( } } + let needs_link = mem::take(&mut needs_link); + if !needs_link.is_empty() { + assert!(compiled_modules.is_empty()); + let diag_handler = cgcx.create_diag_handler(); + let module = B::run_link(&cgcx, &diag_handler, needs_link).map_err(|_| ())?; + let module = unsafe { + B::codegen(&cgcx, &diag_handler, module, cgcx.config(ModuleKind::Regular)) + .map_err(|_| ())? + }; + compiled_modules.push(module); + } + // Drop to print timings drop(llvm_start_time); @@ -1521,6 +1553,9 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem Some(Ok(WorkItemResult::Compiled(m))) => { Message::Done:: { result: Ok(m), worker_id } } + Some(Ok(WorkItemResult::NeedsLink(m))) => { + Message::NeedsLink:: { module: m, worker_id } + } Some(Ok(WorkItemResult::NeedsFatLTO(m))) => { Message::NeedsFatLTO:: { result: m, worker_id } } diff --git a/src/librustc_codegen_ssa/base.rs b/compiler/rustc_codegen_ssa/src/base.rs similarity index 95% rename from src/librustc_codegen_ssa/base.rs rename to compiler/rustc_codegen_ssa/src/base.rs index 77c12c410d..d82fc2c9f6 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -38,7 +38,7 @@ use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::cstore::{self, LinkagePreference}; use rustc_middle::middle::lang_items; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; -use rustc_middle::ty::layout::{self, HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -48,7 +48,7 @@ use rustc_session::utils::NativeLibKind; use rustc_session::Session; use rustc_span::Span; use rustc_symbol_mangling::test as symbol_names_test; -use rustc_target::abi::{Abi, Align, LayoutOf, Scalar, VariantIdx}; +use rustc_target::abi::{Align, LayoutOf, VariantIdx}; use std::cmp; use std::ops::{Deref, DerefMut}; @@ -120,7 +120,7 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ret_ty: Bx::Type, op: hir::BinOpKind, ) -> Bx::Value { - let signed = match t.kind { + let signed = match t.kind() { ty::Float(_) => { let cmp = bin_op_to_fcmp_predicate(op); let cmp = bx.fcmp(cmp, lhs, rhs); @@ -153,7 +153,7 @@ pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>( ) -> Cx::Value { let (source, target) = cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, cx.param_env()); - match (&source.kind, &target.kind) { + match (source.kind(), target.kind()) { (&ty::Array(_, len), &ty::Slice(_)) => { cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all())) } @@ -182,7 +182,7 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( dst_ty: Ty<'tcx>, ) -> (Bx::Value, Bx::Value) { debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); - match (&src_ty.kind, &dst_ty.kind) { + match (src_ty.kind(), dst_ty.kind()) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { assert!(bx.cx().type_is_sized(a)); @@ -231,7 +231,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) { let src_ty = src.layout.ty; let dst_ty = dst.layout.ty; - match (&src_ty.kind, &dst_ty.kind) { + match (src_ty.kind(), dst_ty.kind()) { (&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => { let (base, info) = match bx.load_operand(src).val { OperandValue::Pair(base, info) => { @@ -330,35 +330,6 @@ pub fn wants_msvc_seh(sess: &Session) -> bool { sess.target.target.options.is_like_msvc } -pub fn from_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - val: Bx::Value, -) -> Bx::Value { - if bx.cx().val_ty(val) == bx.cx().type_i1() { bx.zext(val, bx.cx().type_i8()) } else { val } -} - -pub fn to_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - val: Bx::Value, - layout: layout::TyAndLayout<'_>, -) -> Bx::Value { - if let Abi::Scalar(ref scalar) = layout.abi { - return to_immediate_scalar(bx, val, scalar); - } - val -} - -pub fn to_immediate_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - val: Bx::Value, - scalar: &Scalar, -) -> Bx::Value { - if scalar.is_bool() { - return bx.trunc(val, bx.cx().type_i1()); - } - val -} - pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, dst: Bx::Value, @@ -436,16 +407,18 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // listing. let main_ret_ty = cx.tcx().erase_regions(&main_ret_ty.no_bound_vars().unwrap()); - if cx.get_declared_value("main").is_some() { - // FIXME: We should be smart and show a better diagnostic here. - cx.sess() - .struct_span_err(sp, "entry symbol `main` declared multiple times") - .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead") - .emit(); - cx.sess().abort_if_errors(); - bug!(); - } - let llfn = cx.declare_cfn("main", llfty); + let llfn = match cx.declare_c_main(llfty) { + Some(llfn) => llfn, + None => { + // FIXME: We should be smart and show a better diagnostic here. + cx.sess() + .struct_span_err(sp, "entry symbol `main` declared multiple times") + .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead") + .emit(); + cx.sess().abort_if_errors(); + bug!(); + } + }; // `main` should respect same config for frame pointer elimination as rest of code cx.set_frame_pointer_elimination(llfn); diff --git a/src/librustc_codegen_ssa/common.rs b/compiler/rustc_codegen_ssa/src/common.rs similarity index 98% rename from src/librustc_codegen_ssa/common.rs rename to compiler/rustc_codegen_ssa/src/common.rs index e04ed531bb..780b1d2cd9 100644 --- a/src/librustc_codegen_ssa/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -1,4 +1,4 @@ -#![allow(non_camel_case_types, non_snake_case)] +#![allow(non_camel_case_types)] use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -25,7 +25,6 @@ pub enum IntPredicate { IntSLE, } -#[allow(dead_code)] pub enum RealPredicate { RealPredicateFalse, RealOEQ, @@ -60,7 +59,6 @@ pub enum AtomicRmwBinOp { } pub enum AtomicOrdering { - #[allow(dead_code)] NotAtomic, Unordered, Monotonic, diff --git a/src/librustc_codegen_ssa/coverageinfo/ffi.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs similarity index 100% rename from src/librustc_codegen_ssa/coverageinfo/ffi.rs rename to compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs diff --git a/src/librustc_codegen_ssa/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs similarity index 100% rename from src/librustc_codegen_ssa/coverageinfo/map.rs rename to compiler/rustc_codegen_ssa/src/coverageinfo/map.rs diff --git a/src/librustc_codegen_ssa/coverageinfo/mod.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/mod.rs similarity index 100% rename from src/librustc_codegen_ssa/coverageinfo/mod.rs rename to compiler/rustc_codegen_ssa/src/coverageinfo/mod.rs diff --git a/src/librustc_codegen_ssa/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs similarity index 100% rename from src/librustc_codegen_ssa/debuginfo/mod.rs rename to compiler/rustc_codegen_ssa/src/debuginfo/mod.rs diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs similarity index 98% rename from src/librustc_codegen_ssa/debuginfo/type_names.rs rename to compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index fb8f5a6298..45ecb79338 100644 --- a/src/librustc_codegen_ssa/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -5,6 +5,8 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt}; +use std::fmt::Write; + // Compute the name of the type as it should be stored in debuginfo. Does not do // any caching, i.e., calling the function twice with the same type will also do // the work twice. The `qualified` parameter only affects the first level of the @@ -33,11 +35,11 @@ pub fn push_debuginfo_type_name<'tcx>( // .natvis visualizers (and perhaps other existing native debuggers?) let cpp_like_names = tcx.sess.target.target.options.is_like_msvc; - match t.kind { + match *t.kind() { ty::Bool => output.push_str("bool"), ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), - ty::Never => output.push_str("!"), + ty::Never => output.push('!'), ty::Int(int_ty) => output.push_str(int_ty.name_str()), ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()), ty::Float(float_ty) => output.push_str(float_ty.name_str()), @@ -228,8 +230,7 @@ pub fn push_debuginfo_type_name<'tcx>( if qualified { output.push_str(&tcx.crate_name(def_id.krate).as_str()); for path_element in tcx.def_path(def_id).data { - output.push_str("::"); - output.push_str(&path_element.data.as_symbol().as_str()); + write!(output, "::{}", path_element.data).unwrap(); } } else { output.push_str(&tcx.item_name(def_id).as_str()); diff --git a/src/librustc_codegen_ssa/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs similarity index 98% rename from src/librustc_codegen_ssa/glue.rs rename to compiler/rustc_codegen_ssa/src/glue.rs index 5b086bc43f..b88de0b241 100644 --- a/src/librustc_codegen_ssa/glue.rs +++ b/compiler/rustc_codegen_ssa/src/glue.rs @@ -19,7 +19,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let align = bx.const_usize(layout.align.abi.bytes()); return (size, align); } - match t.kind { + match t.kind() { ty::Dynamic(..) => { // load size/align from vtable let vtable = info.unwrap(); @@ -64,7 +64,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let size = bx.add(sized_size, unsized_size); // Packed types ignore the alignment of their fields. - if let ty::Adt(def, _) = t.kind { + if let ty::Adt(def, _) = t.kind() { if def.repr.packed() { unsized_align = sized_align; } diff --git a/src/librustc_codegen_ssa/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs similarity index 96% rename from src/librustc_codegen_ssa/lib.rs rename to compiler/rustc_codegen_ssa/src/lib.rs index 73e3336917..d4f3bf3779 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(option_expect_none)] #![feature(box_patterns)] @@ -6,10 +6,7 @@ #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] -#![feature(trusted_len)] #![feature(associated_type_bounds)] -#![feature(const_fn)] // for rustc_index::newtype_index -#![feature(const_panic)] // for rustc_index::newtype_index #![recursion_limit = "256"] //! This crate contains codegen code that is used by all codegen backends (LLVM and others). diff --git a/src/librustc_codegen_ssa/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs similarity index 100% rename from src/librustc_codegen_ssa/meth.rs rename to compiler/rustc_codegen_ssa/src/meth.rs diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs similarity index 99% rename from src/librustc_codegen_ssa/mir/analyze.rs rename to compiler/rustc_codegen_ssa/src/mir/analyze.rs index 2e386c1e59..bdde07d3fa 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -236,7 +236,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { let check = match terminator.kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => { - match c.literal.ty.kind { + match *c.literal.ty.kind() { ty::FnDef(did, _) => Some((did, args)), _ => None, } diff --git a/src/librustc_codegen_ssa/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs similarity index 96% rename from src/librustc_codegen_ssa/mir/block.rs rename to compiler/rustc_codegen_ssa/src/mir/block.rs index 8048a569f7..703a17b200 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -13,9 +13,10 @@ use rustc_ast as ast; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::mir; -use rustc_middle::mir::interpret::{AllocId, ConstValue, Pointer, Scalar}; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::AssertKind; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; @@ -331,7 +332,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args1 = [place.llval]; &args1[..] }; - let (drop_fn, fn_abi) = match ty.kind { + let (drop_fn, fn_abi) = match ty.kind() { // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? ty::Dynamic(..) => { @@ -479,14 +480,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false).unwrap(), }; if do_panic { - let msg_str = if layout.abi.is_uninhabited() { - // Use this error even for the other intrinsics as it is more precise. - format!("attempted to instantiate uninhabited type `{}`", ty) - } else if intrinsic == ZeroValid { - format!("attempted to zero-initialize type `{}`, which is invalid", ty) - } else { - format!("attempted to leave type `{}` uninitialized, which is invalid", ty) - }; + let msg_str = with_no_trimmed_paths(|| { + if layout.abi.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{}`", ty) + } else if intrinsic == ZeroValid { + format!("attempted to zero-initialize type `{}`, which is invalid", ty) + } else { + format!("attempted to leave type `{}` uninitialized, which is invalid", ty) + } + }); let msg = bx.const_str(Symbol::intern(&msg_str)); let location = self.get_caller_location(bx, span).immediate(); @@ -537,7 +540,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.codegen_operand(&mut bx, func); - let (instance, mut llfn) = match callee.layout.ty.kind { + let (instance, mut llfn) = match *callee.layout.ty.kind() { ty::FnDef(def_id, substs) => ( Some( ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs) @@ -684,7 +687,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); - bx.codegen_intrinsic_call( + Self::codegen_intrinsic_call( + &mut bx, *instance.as_ref().unwrap(), &fn_abi, &args, @@ -864,27 +868,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = constant.literal.ty; let size = bx.layout_of(ty).size; let scalar = match const_value { - // Promoted constants are evaluated into a ByRef instead of a Scalar, - // but we want the scalar value here. - ConstValue::ByRef { alloc, offset } => { - let ptr = Pointer::new(AllocId(0), offset); - alloc - .read_scalar(&bx, ptr, size) - .and_then(|s| s.check_init()) - .unwrap_or_else(|e| { - bx.tcx().sess.span_err( - span, - &format!("Could not evaluate asm const: {}", e), - ); - - // We are erroring out, just emit a dummy constant. - Scalar::from_u64(0) - }) - } - _ => span_bug!(span, "expected ByRef for promoted asm const"), + ConstValue::Scalar(s) => s, + _ => span_bug!( + span, + "expected Scalar for promoted asm const, but got {:#?}", + const_value + ), }; let value = scalar.assert_bits(size); - let string = match ty.kind { + let string = match ty.kind() { ty::Uint(_) => value.to_string(), ty::Int(int_ty) => { match int_ty.normalize(bx.tcx().sess.target.ptr_width) { @@ -911,7 +903,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::InlineAsmOperand::SymFn { ref value } => { let literal = self.monomorphize(&value.literal); - if let ty::FnDef(def_id, substs) = literal.ty.kind { + if let ty::FnDef(def_id, substs) = *literal.ty.kind() { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), ty::ParamEnv::reveal_all(), @@ -1143,7 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } // We store bools as `i8` so we need to truncate to `i1`. - llval = base::to_immediate(bx, llval, arg.layout); + llval = bx.to_immediate(llval, arg.layout); } } diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs similarity index 100% rename from src/librustc_codegen_ssa/mir/constant.rs rename to compiler/rustc_codegen_ssa/src/mir/constant.rs diff --git a/src/librustc_codegen_ssa/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs similarity index 100% rename from src/librustc_codegen_ssa/mir/coverageinfo.rs rename to compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs similarity index 100% rename from src/librustc_codegen_ssa/mir/debuginfo.rs rename to compiler/rustc_codegen_ssa/src/mir/debuginfo.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs new file mode 100644 index 0000000000..14f1ed59a6 --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -0,0 +1,596 @@ +use super::operand::{OperandRef, OperandValue}; +use super::place::PlaceRef; +use super::FunctionCx; +use crate::common::{span_invalid_monomorphization_error, IntPredicate}; +use crate::glue; +use crate::traits::*; +use crate::MemFlags; + +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::{sym, Span}; +use rustc_target::abi::call::{FnAbi, PassMode}; + +fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + allow_overlap: bool, + volatile: bool, + ty: Ty<'tcx>, + dst: Bx::Value, + src: Bx::Value, + count: Bx::Value, +) { + let layout = bx.layout_of(ty); + let size = layout.size; + let align = layout.align.abi; + let size = bx.mul(bx.const_usize(size.bytes()), count); + let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; + if allow_overlap { + bx.memmove(dst, align, src, align, size, flags); + } else { + bx.memcpy(dst, align, src, align, size, flags); + } +} + +fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + volatile: bool, + ty: Ty<'tcx>, + dst: Bx::Value, + val: Bx::Value, + count: Bx::Value, +) { + let layout = bx.layout_of(ty); + let size = layout.size; + let align = layout.align.abi; + let size = bx.mul(bx.const_usize(size.bytes()), count); + let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; + bx.memset(dst, val, size, align, flags); +} + +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + pub fn codegen_intrinsic_call( + bx: &mut Bx, + instance: ty::Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + args: &[OperandRef<'tcx, Bx::Value>], + llresult: Bx::Value, + span: Span, + ) { + let callee_ty = instance.ty(bx.tcx(), ty::ParamEnv::reveal_all()); + + let (def_id, substs) = match *callee_ty.kind() { + ty::FnDef(def_id, substs) => (def_id, substs), + _ => bug!("expected fn item type, found {}", callee_ty), + }; + + let sig = callee_ty.fn_sig(bx.tcx()); + let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let arg_tys = sig.inputs(); + let ret_ty = sig.output(); + let name = bx.tcx().item_name(def_id); + let name_str = &*name.as_str(); + + let llret_ty = bx.backend_type(bx.layout_of(ret_ty)); + let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); + + let llval = match name { + sym::assume => { + bx.assume(args[0].immediate()); + return; + } + sym::abort => { + bx.abort(); + return; + } + + sym::unreachable => { + return; + } + sym::va_start => bx.va_start(args[0].immediate()), + sym::va_end => bx.va_end(args[0].immediate()), + sym::size_of_val => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (llsize, _) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); + llsize + } else { + bx.const_usize(bx.layout_of(tp_ty).size.bytes()) + } + } + sym::min_align_of_val => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (_, llalign) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); + llalign + } else { + bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes()) + } + } + sym::size_of + | sym::pref_align_of + | sym::min_align_of + | sym::needs_drop + | sym::type_id + | sym::type_name + | sym::variant_count => { + let value = bx + .tcx() + .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) + .unwrap(); + OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) + } + // Effectively no-op + sym::forget => { + return; + } + sym::offset => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.inbounds_gep(ptr, &[offset]) + } + sym::arith_offset => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.gep(ptr, &[offset]) + } + + sym::copy_nonoverlapping => { + copy_intrinsic( + bx, + false, + false, + substs.type_at(0), + args[1].immediate(), + args[0].immediate(), + args[2].immediate(), + ); + return; + } + sym::copy => { + copy_intrinsic( + bx, + true, + false, + substs.type_at(0), + args[1].immediate(), + args[0].immediate(), + args[2].immediate(), + ); + return; + } + sym::write_bytes => { + memset_intrinsic( + bx, + false, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + + sym::volatile_copy_nonoverlapping_memory => { + copy_intrinsic( + bx, + false, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_copy_memory => { + copy_intrinsic( + bx, + true, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_set_memory => { + memset_intrinsic( + bx, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.volatile_store(bx, dst); + return; + } + sym::unaligned_volatile_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.unaligned_volatile_store(bx, dst); + return; + } + sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow + | sym::wrapping_add + | sym::wrapping_sub + | sym::wrapping_mul + | sym::unchecked_div + | sym::unchecked_rem + | sym::unchecked_shl + | sym::unchecked_shr + | sym::unchecked_add + | sym::unchecked_sub + | sym::unchecked_mul + | sym::exact_div => { + let ty = arg_tys[0]; + match int_type_width_signed(ty, bx.tcx()) { + Some((_width, signed)) => match name { + sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow => { + let op = match name { + sym::add_with_overflow => OverflowOp::Add, + sym::sub_with_overflow => OverflowOp::Sub, + sym::mul_with_overflow => OverflowOp::Mul, + _ => bug!(), + }; + let (val, overflow) = + bx.checked_binop(op, ty, args[0].immediate(), args[1].immediate()); + // Convert `i1` to a `bool`, and write it to the out parameter + let val = bx.from_immediate(val); + let overflow = bx.from_immediate(overflow); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(overflow, dest.llval, dest.align); + + return; + } + sym::wrapping_add => bx.add(args[0].immediate(), args[1].immediate()), + sym::wrapping_sub => bx.sub(args[0].immediate(), args[1].immediate()), + sym::wrapping_mul => bx.mul(args[0].immediate(), args[1].immediate()), + sym::exact_div => { + if signed { + bx.exactsdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.exactudiv(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_div => { + if signed { + bx.sdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.udiv(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_rem => { + if signed { + bx.srem(args[0].immediate(), args[1].immediate()) + } else { + bx.urem(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()), + sym::unchecked_shr => { + if signed { + bx.ashr(args[0].immediate(), args[1].immediate()) + } else { + bx.lshr(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_add => { + if signed { + bx.unchecked_sadd(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_uadd(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_sub => { + if signed { + bx.unchecked_ssub(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_usub(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_mul => { + if signed { + bx.unchecked_smul(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_umul(args[0].immediate(), args[1].immediate()) + } + } + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + return; + } + } + } + sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { + match float_type_width(arg_tys[0]) { + Some(_width) => match name { + sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()), + sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()), + sym::fmul_fast => bx.fmul_fast(args[0].immediate(), args[1].immediate()), + sym::fdiv_fast => bx.fdiv_fast(args[0].immediate(), args[1].immediate()), + sym::frem_fast => bx.frem_fast(args[0].immediate(), args[1].immediate()), + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic float type, found `{}`", + name, arg_tys[0] + ), + ); + return; + } + } + } + + sym::float_to_int_unchecked => { + if float_type_width(arg_tys[0]).is_none() { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `float_to_int_unchecked` \ + intrinsic: expected basic float type, \ + found `{}`", + arg_tys[0] + ), + ); + return; + } + let (_width, signed) = match int_type_width_signed(ret_ty, bx.tcx()) { + Some(pair) => pair, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `float_to_int_unchecked` \ + intrinsic: expected basic integer type, \ + found `{}`", + ret_ty + ), + ); + return; + } + }; + if signed { + bx.fptosi(args[0].immediate(), llret_ty) + } else { + bx.fptoui(args[0].immediate(), llret_ty) + } + } + + sym::discriminant_value => { + if ret_ty.is_integral() { + args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty) + } else { + span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) + } + } + + // This requires that atomic intrinsics follow a specific naming pattern: + // "atomic_[_]", and no ordering means SeqCst + name if name_str.starts_with("atomic_") => { + use crate::common::AtomicOrdering::*; + use crate::common::{AtomicRmwBinOp, SynchronizationScope}; + + let split: Vec<&str> = name_str.split('_').collect(); + + let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; + let (order, failorder) = match split.len() { + 2 => (SequentiallyConsistent, SequentiallyConsistent), + 3 => match split[2] { + "unordered" => (Unordered, Unordered), + "relaxed" => (Monotonic, Monotonic), + "acq" => (Acquire, Acquire), + "rel" => (Release, Monotonic), + "acqrel" => (AcquireRelease, Acquire), + "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), + "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), + _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), + }, + 4 => match (split[2], split[3]) { + ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), + ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), + _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), + }, + _ => bx.sess().fatal("Atomic intrinsic not in correct format"), + }; + + let invalid_monomorphization = |ty| { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + }; + + match split[1] { + "cxchg" | "cxchgweak" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let weak = split[1] == "cxchgweak"; + let pair = bx.atomic_cmpxchg( + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + order, + failorder, + weak, + ); + let val = bx.extract_value(pair, 0); + let success = bx.extract_value(pair, 1); + let val = bx.from_immediate(val); + let success = bx.from_immediate(success); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(success, dest.llval, dest.align); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "load" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let size = bx.layout_of(ty).size; + bx.atomic_load(args[0].immediate(), order, size) + } else { + return invalid_monomorphization(ty); + } + } + + "store" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let size = bx.layout_of(ty).size; + bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "fence" => { + bx.atomic_fence(order, SynchronizationScope::CrossThread); + return; + } + + "singlethreadfence" => { + bx.atomic_fence(order, SynchronizationScope::SingleThread); + return; + } + + // These are all AtomicRMW ops + op => { + let atom_op = match op { + "xchg" => AtomicRmwBinOp::AtomicXchg, + "xadd" => AtomicRmwBinOp::AtomicAdd, + "xsub" => AtomicRmwBinOp::AtomicSub, + "and" => AtomicRmwBinOp::AtomicAnd, + "nand" => AtomicRmwBinOp::AtomicNand, + "or" => AtomicRmwBinOp::AtomicOr, + "xor" => AtomicRmwBinOp::AtomicXor, + "max" => AtomicRmwBinOp::AtomicMax, + "min" => AtomicRmwBinOp::AtomicMin, + "umax" => AtomicRmwBinOp::AtomicUMax, + "umin" => AtomicRmwBinOp::AtomicUMin, + _ => bx.sess().fatal("unknown atomic operation"), + }; + + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order) + } else { + return invalid_monomorphization(ty); + } + } + } + } + + sym::nontemporal_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.nontemporal_store(bx, dst); + return; + } + + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { + 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) + } + } + + sym::ptr_offset_from => { + let ty = substs.type_at(0); + let pointee_size = bx.layout_of(ty).size; + + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let a = args[0].immediate(); + let b = args[1].immediate(); + let a = bx.ptrtoint(a, bx.type_isize()); + let b = bx.ptrtoint(b, bx.type_isize()); + let d = bx.sub(a, b); + let pointee_size = bx.const_usize(pointee_size.bytes()); + // this is where the signed magic happens (notice the `s` in `exactsdiv`) + bx.exactsdiv(d, pointee_size) + } + + _ => { + // Need to use backend-specific things in the implementation. + bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span); + return; + } + }; + + 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)); + let ptr = bx.pointercast(result.llval, ptr_llty); + bx.store(llval, ptr, result.align); + } else { + OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) + .val + .store(bx, result); + } + } + } +} + +// Returns the width of an int Ty, and if it's signed or not +// Returns None if the type is not an integer +// FIXME: there’s multiple of this functions, investigate using some of the already existing +// stuffs. +fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> { + match ty.kind() { + ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)), + ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)), + _ => None, + } +} + +// Returns the width of a float Ty +// Returns None if the type is not a float +fn float_type_width(ty: Ty<'_>) -> Option { + match ty.kind() { + ty::Float(t) => Some(t.bit_width()), + _ => None, + } +} diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs similarity index 99% rename from src/librustc_codegen_ssa/mir/mod.rs rename to compiler/rustc_codegen_ssa/src/mir/mod.rs index 26e6c35470..64d456fb7a 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -369,8 +369,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // individual LLVM function arguments. let arg_ty = fx.monomorphize(&arg_decl.ty); - let tupled_arg_tys = match arg_ty.kind { - ty::Tuple(ref tys) => tys, + let tupled_arg_tys = match arg_ty.kind() { + ty::Tuple(tys) => tys, _ => bug!("spread argument isn't a tuple?!"), }; @@ -486,6 +486,7 @@ mod block; pub mod constant; pub mod coverageinfo; pub mod debuginfo; +mod intrinsic; pub mod operand; pub mod place; mod rvalue; diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs similarity index 92% rename from src/librustc_codegen_ssa/mir/operand.rs rename to compiler/rustc_codegen_ssa/src/mir/operand.rs index 937c7457c6..bbd004be87 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -147,8 +147,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty); // Reconstruct the immediate aggregate. let mut llpair = bx.cx().const_undef(llty); - let imm_a = base::from_immediate(bx, a); - let imm_b = base::from_immediate(bx, b); + let imm_a = bx.from_immediate(a); + let imm_b = bx.from_immediate(b); llpair = bx.insert_value(llpair, imm_a, 0); llpair = bx.insert_value(llpair, imm_b, 1); llpair @@ -168,9 +168,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // Deconstruct the immediate aggregate. let a_llval = bx.extract_value(llval, 0); - let a_llval = base::to_immediate_scalar(bx, a_llval, a); + let a_llval = bx.to_immediate_scalar(a_llval, a); let b_llval = bx.extract_value(llval, 1); - let b_llval = base::to_immediate_scalar(bx, b_llval, b); + let b_llval = bx.to_immediate_scalar(b_llval, b); OperandValue::Pair(a_llval, b_llval) } else { OperandValue::Immediate(llval) @@ -220,29 +220,23 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { _ => bug!("OperandRef::extract_field({:?}): not applicable", self), }; - // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. - // Bools in union fields needs to be truncated. - let to_immediate_or_cast = |bx: &mut Bx, val, ty| { - if ty == bx.cx().type_i1() { bx.trunc(val, ty) } else { bx.bitcast(val, ty) } - }; - - match val { - OperandValue::Immediate(ref mut llval) => { - *llval = to_immediate_or_cast(bx, *llval, bx.cx().immediate_backend_type(field)); + match (&mut val, &field.abi) { + (OperandValue::Immediate(llval), _) => { + // Bools in union fields needs to be truncated. + *llval = bx.to_immediate(*llval, field); + // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. + *llval = bx.bitcast(*llval, bx.cx().immediate_backend_type(field)); } - OperandValue::Pair(ref mut a, ref mut b) => { - *a = to_immediate_or_cast( - bx, - *a, - bx.cx().scalar_pair_element_backend_type(field, 0, true), - ); - *b = to_immediate_or_cast( - bx, - *b, - bx.cx().scalar_pair_element_backend_type(field, 1, true), - ); + (OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => { + // Bools in union fields needs to be truncated. + *a = bx.to_immediate_scalar(*a, a_abi); + *b = bx.to_immediate_scalar(*b, b_abi); + // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. + *a = bx.bitcast(*a, bx.cx().scalar_pair_element_backend_type(field, 0, true)); + *b = bx.bitcast(*b, bx.cx().scalar_pair_element_backend_type(field, 1, true)); } - OperandValue::Ref(..) => bug!(), + (OperandValue::Pair(..), _) => bug!(), + (OperandValue::Ref(..), _) => bug!(), } OperandRef { val, layout: field } @@ -302,7 +296,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { bug!("cannot directly store unsized values"); } OperandValue::Immediate(s) => { - let val = base::from_immediate(bx, s); + let val = bx.from_immediate(s); bx.store_with_flags(val, dest.llval, dest.align, flags); } OperandValue::Pair(a, b) => { @@ -313,12 +307,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { let b_offset = a_scalar.value.size(bx).align_to(b_scalar.value.align(bx).abi); let llptr = bx.struct_gep(dest.llval, 0); - let val = base::from_immediate(bx, a); + let val = bx.from_immediate(a); let align = dest.align; bx.store_with_flags(val, llptr, align, flags); let llptr = bx.struct_gep(dest.llval, 1); - let val = base::from_immediate(bx, b); + let val = bx.from_immediate(b); let align = dest.align.restrict_for_offset(b_offset); bx.store_with_flags(val, llptr, align, flags); } diff --git a/src/librustc_codegen_ssa/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs similarity index 92% rename from src/librustc_codegen_ssa/mir/place.rs rename to compiler/rustc_codegen_ssa/src/mir/place.rs index 05656774f0..91609b2261 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -93,15 +93,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let effective_field_align = self.align.restrict_for_offset(offset); let mut simple = || { - // Unions and newtypes only use an offset of 0. - let llval = if offset.bytes() == 0 { - self.llval - } else if let Abi::ScalarPair(ref a, ref b) = self.layout.abi { - // Offsets have to match either first or second field. - assert_eq!(offset, a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi)); - bx.struct_gep(self.llval, 1) - } else { - bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)) + let llval = match self.layout.abi { + _ if offset.bytes() == 0 => { + // Unions and newtypes only use an offset of 0. + // Also handles the first field of Scalar, ScalarPair, and Vector layouts. + self.llval + } + Abi::ScalarPair(ref a, ref b) + if offset == a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi) => + { + // Offset matches second field. + bx.struct_gep(self.llval, 1) + } + Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => { + // ZST fields are not included in Scalar, ScalarPair, and Vector layouts, so manually offset the pointer. + let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p()); + bx.gep(byte_ptr, &[bx.const_usize(offset.bytes())]) + } + Abi::Scalar(_) | Abi::ScalarPair(..) => { + // All fields of Scalar and ScalarPair layouts must have been handled by this point. + // Vector layouts have additional fields for each element of the vector, so don't panic in that case. + bug!( + "offset of non-ZST field `{:?}` does not match layout `{:#?}`", + field, + self.layout + ); + } + _ => bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)), }; PlaceRef { // HACK(eddyb): have to bitcast pointers until LLVM removes pointee types. @@ -116,7 +134,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { // * no metadata available - just log the case // * known alignment - sized types, `[T]`, `str` or a foreign type // * packed struct - there is no alignment padding - match field.ty.kind { + match field.ty.kind() { _ if self.llextra.is_none() => { debug!( "unsized field `{}`, of `{:?}` has no metadata for adjustment", diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs similarity index 97% rename from src/librustc_codegen_ssa/mir/rvalue.rs rename to compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 71f924df11..7ce110dcbf 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -98,7 +98,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } // Use llvm.memset.p0i8.* to initialize byte arrays - let v = base::from_immediate(&mut bx, v); + let v = bx.from_immediate(v); if bx.cx().val_ty(v) == bx.cx().type_i8() { bx.memset(start, v, size, dest.align, MemFlags::empty()); return bx; @@ -185,7 +185,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = match *kind { mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { - match operand.layout.ty.kind { + match *operand.layout.ty.kind() { ty::FnDef(def_id, substs) => { if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { bug!("reifying a fn ptr that requires const arguments"); @@ -204,7 +204,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => { - match operand.layout.ty.kind { + match *operand.layout.ty.kind() { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( bx.cx().tcx(), @@ -327,13 +327,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if er.end != er.start && scalar.valid_range.end() > scalar.valid_range.start() { - // We want `table[e as usize]` to not + // We want `table[e as usize ± k]` to not // have bound checks, and this is the most - // convenient place to put the `assume`. - let ll_t_in_const = + // convenient place to put the `assume`s. + if *scalar.valid_range.start() > 0 { + let enum_value_lower_bound = bx + .cx() + .const_uint_big(ll_t_in, *scalar.valid_range.start()); + let cmp_start = bx.icmp( + IntPredicate::IntUGE, + llval, + enum_value_lower_bound, + ); + bx.assume(cmp_start); + } + + let enum_value_upper_bound = bx.cx().const_uint_big(ll_t_in, *scalar.valid_range.end()); - let cmp = bx.icmp(IntPredicate::IntULE, llval, ll_t_in_const); - bx.assume(cmp); + let cmp_end = bx.icmp( + IntPredicate::IntULE, + llval, + enum_value_upper_bound, + ); + bx.assume(cmp_end); } } } @@ -548,7 +564,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // because codegen_place() panics if Local is operand. if let Some(index) = place.as_local() { if let LocalRef::Operand(Some(op)) = self.locals[index] { - if let ty::Array(_, n) = op.layout.ty.kind { + if let ty::Array(_, n) = op.layout.ty.kind() { let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); return bx.cx().const_usize(n); } diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs similarity index 100% rename from src/librustc_codegen_ssa/mir/statement.rs rename to compiler/rustc_codegen_ssa/src/mir/statement.rs diff --git a/src/librustc_codegen_ssa/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs similarity index 94% rename from src/librustc_codegen_ssa/mono_item.rs rename to compiler/rustc_codegen_ssa/src/mono_item.rs index fc65149937..607b545967 100644 --- a/src/librustc_codegen_ssa/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { fn define>(&self, cx: &'a Bx::CodegenCx) { debug!( "BEGIN IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(cx.tcx(), true), + self, self.to_raw_string(), cx.codegen_unit().name() ); @@ -45,7 +45,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { debug!( "END IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(cx.tcx(), true), + self, self.to_raw_string(), cx.codegen_unit().name() ); @@ -59,7 +59,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { ) { debug!( "BEGIN PREDEFINING '{} ({})' in cgu {}", - self.to_string(cx.tcx(), true), + self, self.to_raw_string(), cx.codegen_unit().name() ); @@ -80,7 +80,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { debug!( "END PREDEFINING '{} ({})' in cgu {}", - self.to_string(cx.tcx(), true), + self, self.to_raw_string(), cx.codegen_unit().name() ); diff --git a/src/librustc_codegen_ssa/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/abi.rs rename to compiler/rustc_codegen_ssa/src/traits/abi.rs diff --git a/src/librustc_codegen_ssa/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/asm.rs rename to compiler/rustc_codegen_ssa/src/traits/asm.rs diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs similarity index 92% rename from src/librustc_codegen_ssa/traits/backend.rs rename to compiler/rustc_codegen_ssa/src/traits/backend.rs index 3522ea0115..90520f77e3 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -15,6 +15,7 @@ use rustc_session::{ }; use rustc_span::symbol::Symbol; use rustc_target::abi::LayoutOf; +use rustc_target::spec::Target; pub use rustc_data_structures::sync::MetadataRef; @@ -54,6 +55,12 @@ pub trait CodegenBackend { fn print_passes(&self) {} fn print_version(&self) {} + /// If this plugin provides additional builtin targets, provide the one enabled by the options here. + /// Be careful: this is called *before* init() is called. + fn target_override(&self, _opts: &config::Options) -> Option { + None + } + fn metadata_loader(&self) -> Box; fn provide(&self, _providers: &mut Providers); fn provide_extern(&self, _providers: &mut Providers); diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs similarity index 95% rename from src/librustc_codegen_ssa/traits/builder.rs rename to compiler/rustc_codegen_ssa/src/traits/builder.rs index 5ffc83c5f9..b35b0f2420 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -13,12 +13,11 @@ use crate::mir::operand::OperandRef; use crate::mir::place::PlaceRef; use crate::MemFlags; -use rustc_middle::ty::layout::HasParamEnv; +use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout}; use rustc_middle::ty::Ty; -use rustc_target::abi::{Align, Size}; +use rustc_target::abi::{Abi, Align, Scalar, Size}; use rustc_target::spec::HasTargetSpec; -use std::iter::TrustedLen; use std::ops::Range; #[derive(Copy, Clone)] @@ -60,7 +59,7 @@ pub trait BuilderMethods<'a, 'tcx>: &mut self, v: Self::Value, else_llbb: Self::BasicBlock, - cases: impl ExactSizeIterator + TrustedLen, + cases: impl ExactSizeIterator, ); fn invoke( &mut self, @@ -115,6 +114,16 @@ pub trait BuilderMethods<'a, 'tcx>: rhs: Self::Value, ) -> (Self::Value, Self::Value); + fn from_immediate(&mut self, val: Self::Value) -> Self::Value; + fn to_immediate(&mut self, val: Self::Value, layout: TyAndLayout<'_>) -> Self::Value { + if let Abi::Scalar(ref scalar) = layout.abi { + self.to_immediate_scalar(val, scalar) + } else { + val + } + } + fn to_immediate_scalar(&mut self, val: Self::Value, scalar: &Scalar) -> Self::Value; + fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value; fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value; fn array_alloca(&mut self, ty: Self::Type, len: Self::Value, align: Align) -> Self::Value; diff --git a/src/librustc_codegen_ssa/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/consts.rs rename to compiler/rustc_codegen_ssa/src/traits/consts.rs diff --git a/src/librustc_codegen_ssa/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/coverageinfo.rs rename to compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/debuginfo.rs rename to compiler/rustc_codegen_ssa/src/traits/debuginfo.rs diff --git a/compiler/rustc_codegen_ssa/src/traits/declare.rs b/compiler/rustc_codegen_ssa/src/traits/declare.rs new file mode 100644 index 0000000000..655afcd17f --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/traits/declare.rs @@ -0,0 +1,21 @@ +use super::BackendTypes; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::ty::Instance; + +pub trait PreDefineMethods<'tcx>: BackendTypes { + fn predefine_static( + &self, + def_id: DefId, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str, + ); + fn predefine_fn( + &self, + instance: Instance<'tcx>, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str, + ); +} diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs similarity index 80% rename from src/librustc_codegen_ssa/traits/intrinsic.rs rename to compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index 9d48e233de..ccd294d92b 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -5,9 +5,9 @@ use rustc_span::Span; use rustc_target::abi::call::FnAbi; pub trait IntrinsicCallMethods<'tcx>: BackendTypes { - /// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs, - /// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics, - /// add them to librustc_codegen_llvm/context.rs + /// Remember to add all intrinsics here, in `compiler/rustc_typeck/src/check/mod.rs`, + /// and in `library/core/src/intrinsics.rs`; if you need access to any LLVM intrinsics, + /// add them to `compiler/rustc_codegen_llvm/src/context.rs`. fn codegen_intrinsic_call( &mut self, instance: ty::Instance<'tcx>, diff --git a/src/librustc_codegen_ssa/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs similarity index 82% rename from src/librustc_codegen_ssa/traits/misc.rs rename to compiler/rustc_codegen_ssa/src/traits/misc.rs index fc57a9a80b..6fff64bfcb 100644 --- a/src/librustc_codegen_ssa/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -19,4 +19,6 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn set_frame_pointer_elimination(&self, llfn: Self::Function); fn apply_target_cpu_attr(&self, llfn: Self::Function); fn create_used_variable(&self); + /// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists. + fn declare_c_main(&self, fn_type: Self::Type) -> Option; } diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs similarity index 96% rename from src/librustc_codegen_ssa/traits/mod.rs rename to compiler/rustc_codegen_ssa/src/traits/mod.rs index 0ac519dd0b..698ef6083e 100644 --- a/src/librustc_codegen_ssa/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -35,7 +35,7 @@ pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; pub use self::coverageinfo::{CoverageInfoBuilderMethods, CoverageInfoMethods}; pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods}; -pub use self::declare::{DeclareMethods, PreDefineMethods}; +pub use self::declare::PreDefineMethods; pub use self::intrinsic::IntrinsicCallMethods; pub use self::misc::MiscMethods; pub use self::statics::{StaticBuilderMethods, StaticMethods}; @@ -60,7 +60,6 @@ pub trait CodegenMethods<'tcx>: + StaticMethods + CoverageInfoMethods + DebugInfoMethods<'tcx> - + DeclareMethods<'tcx> + AsmMethods + PreDefineMethods<'tcx> + HasParamEnv<'tcx> @@ -77,7 +76,6 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + StaticMethods + CoverageInfoMethods + DebugInfoMethods<'tcx> - + DeclareMethods<'tcx> + AsmMethods + PreDefineMethods<'tcx> + HasParamEnv<'tcx> diff --git a/src/librustc_codegen_ssa/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/statics.rs rename to compiler/rustc_codegen_ssa/src/traits/statics.rs diff --git a/src/librustc_codegen_ssa/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs similarity index 99% rename from src/librustc_codegen_ssa/traits/type_.rs rename to compiler/rustc_codegen_ssa/src/traits/type_.rs index 726d948cfd..cec07b977e 100644 --- a/src/librustc_codegen_ssa/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -89,7 +89,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } let tail = self.tcx().struct_tail_erasing_lifetimes(ty, param_env); - match tail.kind { + match tail.kind() { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, _ => bug!("unexpected unsized tail: {:?}", tail), diff --git a/src/librustc_codegen_ssa/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs similarity index 90% rename from src/librustc_codegen_ssa/traits/write.rs rename to compiler/rustc_codegen_ssa/src/traits/write.rs index 27d52e9b9c..264e7c2aa9 100644 --- a/src/librustc_codegen_ssa/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -13,6 +13,12 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { type ThinData: Send + Sync; type ThinBuffer: ThinBufferMethods; + /// Merge all modules into main_module and returning it + fn run_link( + cgcx: &CodegenContext, + diag_handler: &Handler, + modules: Vec>, + ) -> Result, FatalError>; /// Performs fat LTO by merging all modules into a single one and returning it /// for further optimization. fn run_fat_lto( diff --git a/src/librustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml similarity index 69% rename from src/librustc_data_structures/Cargo.toml rename to compiler/rustc_data_structures/Cargo.toml index 5905065120..caaf7c0c3c 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -5,8 +5,6 @@ version = "0.0.0" edition = "2018" [lib] -name = "rustc_data_structures" -path = "lib.rs" doctest = false [dependencies] @@ -15,11 +13,9 @@ ena = "0.14" indexmap = "1.5.1" tracing = "0.1" jobserver_crate = { version = "0.1.13", package = "jobserver" } -lazy_static = "1" -once_cell = { version = "1", features = ["parking_lot"] } -rustc_serialize = { path = "../librustc_serialize" } -rustc_macros = { path = "../librustc_macros" } -rustc_graphviz = { path = "../librustc_graphviz" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_macros = { path = "../rustc_macros" } +rustc_graphviz = { path = "../rustc_graphviz" } cfg-if = "0.1.2" crossbeam-utils = { version = "0.7", features = ["nightly"] } stable_deref_trait = "1.0.0" @@ -27,15 +23,15 @@ rayon = { version = "0.3.0", package = "rustc-rayon" } rayon-core = { version = "0.3.0", package = "rustc-rayon-core" } rustc-hash = "1.1.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_index = { path = "../librustc_index", package = "rustc_index" } +rustc_index = { path = "../rustc_index", package = "rustc_index" } bitflags = "1.2.1" measureme = "0.7.1" libc = "0.2" -stacker = "0.1.11" +stacker = "0.1.12" tempfile = "3.0.5" [dependencies.parking_lot] -version = "0.10" +version = "0.11" features = ["nightly"] [target.'cfg(windows)'.dependencies] diff --git a/src/librustc_data_structures/atomic_ref.rs b/compiler/rustc_data_structures/src/atomic_ref.rs similarity index 100% rename from src/librustc_data_structures/atomic_ref.rs rename to compiler/rustc_data_structures/src/atomic_ref.rs diff --git a/src/librustc_data_structures/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs similarity index 100% rename from src/librustc_data_structures/base_n.rs rename to compiler/rustc_data_structures/src/base_n.rs diff --git a/src/librustc_data_structures/base_n/tests.rs b/compiler/rustc_data_structures/src/base_n/tests.rs similarity index 100% rename from src/librustc_data_structures/base_n/tests.rs rename to compiler/rustc_data_structures/src/base_n/tests.rs diff --git a/src/librustc_data_structures/binary_search_util/mod.rs b/compiler/rustc_data_structures/src/binary_search_util/mod.rs similarity index 100% rename from src/librustc_data_structures/binary_search_util/mod.rs rename to compiler/rustc_data_structures/src/binary_search_util/mod.rs diff --git a/src/librustc_data_structures/binary_search_util/tests.rs b/compiler/rustc_data_structures/src/binary_search_util/tests.rs similarity index 100% rename from src/librustc_data_structures/binary_search_util/tests.rs rename to compiler/rustc_data_structures/src/binary_search_util/tests.rs diff --git a/src/librustc_data_structures/box_region.rs b/compiler/rustc_data_structures/src/box_region.rs similarity index 100% rename from src/librustc_data_structures/box_region.rs rename to compiler/rustc_data_structures/src/box_region.rs diff --git a/src/librustc_data_structures/captures.rs b/compiler/rustc_data_structures/src/captures.rs similarity index 100% rename from src/librustc_data_structures/captures.rs rename to compiler/rustc_data_structures/src/captures.rs diff --git a/src/librustc_data_structures/const_cstr.rs b/compiler/rustc_data_structures/src/const_cstr.rs similarity index 100% rename from src/librustc_data_structures/const_cstr.rs rename to compiler/rustc_data_structures/src/const_cstr.rs diff --git a/src/librustc_data_structures/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs similarity index 82% rename from src/librustc_data_structures/fingerprint.rs rename to compiler/rustc_data_structures/src/fingerprint.rs index f8d631ce01..aba0bbbac8 100644 --- a/src/librustc_data_structures/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -3,9 +3,10 @@ use rustc_serialize::{ opaque::{self, EncodeResult}, Decodable, Encodable, }; +use std::hash::{Hash, Hasher}; use std::mem; -#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)] +#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)] pub struct Fingerprint(u64, u64); impl Fingerprint { @@ -76,6 +77,33 @@ impl ::std::fmt::Display for Fingerprint { } } +impl Hash for Fingerprint { + #[inline] + fn hash(&self, state: &mut H) { + state.write_fingerprint(self); + } +} + +trait FingerprintHasher { + fn write_fingerprint(&mut self, fingerprint: &Fingerprint); +} + +impl FingerprintHasher for H { + #[inline] + default fn write_fingerprint(&mut self, fingerprint: &Fingerprint) { + self.write_u64(fingerprint.0); + self.write_u64(fingerprint.1); + } +} + +impl FingerprintHasher for crate::unhash::Unhasher { + #[inline] + fn write_fingerprint(&mut self, fingerprint: &Fingerprint) { + // `Unhasher` only wants a single `u64` + self.write_u64(fingerprint.0); + } +} + impl stable_hasher::StableHasherResult for Fingerprint { #[inline] fn finish(hasher: stable_hasher::StableHasher) -> Self { diff --git a/src/librustc_data_structures/flock.rs b/compiler/rustc_data_structures/src/flock.rs similarity index 100% rename from src/librustc_data_structures/flock.rs rename to compiler/rustc_data_structures/src/flock.rs diff --git a/src/librustc_data_structures/frozen.rs b/compiler/rustc_data_structures/src/frozen.rs similarity index 100% rename from src/librustc_data_structures/frozen.rs rename to compiler/rustc_data_structures/src/frozen.rs diff --git a/src/librustc_data_structures/fx.rs b/compiler/rustc_data_structures/src/fx.rs similarity index 100% rename from src/librustc_data_structures/fx.rs rename to compiler/rustc_data_structures/src/fx.rs diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/dominators/mod.rs rename to compiler/rustc_data_structures/src/graph/dominators/mod.rs diff --git a/src/librustc_data_structures/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/dominators/tests.rs rename to compiler/rustc_data_structures/src/graph/dominators/tests.rs diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/implementation/mod.rs rename to compiler/rustc_data_structures/src/graph/implementation/mod.rs diff --git a/src/librustc_data_structures/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/implementation/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/implementation/tests.rs rename to compiler/rustc_data_structures/src/graph/implementation/tests.rs diff --git a/src/librustc_data_structures/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs similarity index 97% rename from src/librustc_data_structures/graph/iterate/mod.rs rename to compiler/rustc_data_structures/src/graph/iterate/mod.rs index 64ff6130dd..bc3d1ce53b 100644 --- a/src/librustc_data_structures/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -87,11 +87,8 @@ where } /// Allows searches to terminate early with a value. -#[derive(Clone, Copy, Debug)] -pub enum ControlFlow { - Break(T), - Continue, -} +// FIXME (#75744): remove the alias once the generics are in a better order and `C=()`. +pub type ControlFlow = std::ops::ControlFlow<(), T>; /// The status of a node in the depth-first search. /// @@ -260,12 +257,12 @@ where _node: G::Node, _prior_status: Option, ) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Called after all nodes reachable from this one have been examined. fn node_settled(&mut self, _node: G::Node) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Behave as if no edges exist from `source` to `target`. @@ -289,8 +286,8 @@ where prior_status: Option, ) -> ControlFlow { match prior_status { - Some(NodeStatus::Visited) => ControlFlow::Break(()), - _ => ControlFlow::Continue, + Some(NodeStatus::Visited) => ControlFlow::BREAK, + _ => ControlFlow::CONTINUE, } } } diff --git a/src/librustc_data_structures/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/iterate/tests.rs rename to compiler/rustc_data_structures/src/graph/iterate/tests.rs diff --git a/src/librustc_data_structures/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/mod.rs rename to compiler/rustc_data_structures/src/graph/mod.rs diff --git a/src/librustc_data_structures/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs similarity index 100% rename from src/librustc_data_structures/graph/reference.rs rename to compiler/rustc_data_structures/src/graph/reference.rs diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/scc/mod.rs rename to compiler/rustc_data_structures/src/graph/scc/mod.rs diff --git a/src/librustc_data_structures/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/scc/tests.rs rename to compiler/rustc_data_structures/src/graph/scc/tests.rs diff --git a/src/librustc_data_structures/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/tests.rs rename to compiler/rustc_data_structures/src/graph/tests.rs diff --git a/src/librustc_data_structures/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/vec_graph/mod.rs rename to compiler/rustc_data_structures/src/graph/vec_graph/mod.rs diff --git a/src/librustc_data_structures/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/vec_graph/tests.rs rename to compiler/rustc_data_structures/src/graph/vec_graph/tests.rs diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs new file mode 100644 index 0000000000..41605afb44 --- /dev/null +++ b/compiler/rustc_data_structures/src/jobserver.rs @@ -0,0 +1,40 @@ +pub use jobserver_crate::Client; +use std::lazy::SyncLazy; + +// We can only call `from_env` once per process + +// Note that this is unsafe because it may misinterpret file descriptors +// on Unix as jobserver file descriptors. We hopefully execute this near +// the beginning of the process though to ensure we don't get false +// positives, or in other words we try to execute this before we open +// any file descriptors ourselves. +// +// Pick a "reasonable maximum" if we don't otherwise have +// a jobserver in our environment, capping out at 32 so we +// don't take everything down by hogging the process run queue. +// The fixed number is used to have deterministic compilation +// across machines. +// +// Also note that we stick this in a global because there could be +// multiple rustc instances in this process, and the jobserver is +// per-process. +static GLOBAL_CLIENT: SyncLazy = SyncLazy::new(|| unsafe { + Client::from_env().unwrap_or_else(|| { + let client = Client::new(32).expect("failed to create jobserver"); + // Acquire a token for the main thread which we can release later + client.acquire_raw().ok(); + client + }) +}); + +pub fn client() -> Client { + GLOBAL_CLIENT.clone() +} + +pub fn acquire_thread() { + GLOBAL_CLIENT.acquire_raw().ok(); +} + +pub fn release_thread() { + GLOBAL_CLIENT.release_raw().ok(); +} diff --git a/src/librustc_data_structures/lib.rs b/compiler/rustc_data_structures/src/lib.rs similarity index 91% rename from src/librustc_data_structures/lib.rs rename to compiler/rustc_data_structures/src/lib.rs index cd25ba2ac6..90b0f25475 100644 --- a/src/librustc_data_structures/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -6,13 +6,14 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![allow(incomplete_features)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(array_windows)] +#![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] -#![feature(generators)] #![feature(generator_trait)] #![feature(fn_traits)] +#![feature(int_bits_const)] #![feature(min_specialization)] #![feature(optin_builtin_traits)] #![feature(nll)] @@ -25,7 +26,8 @@ #![feature(thread_id_value)] #![feature(extend_one)] #![feature(const_panic)] -#![feature(const_generics)] +#![feature(min_const_generics)] +#![feature(once_cell)] #![allow(rustc::default_hash_types)] #[macro_use] @@ -99,8 +101,10 @@ pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; pub mod mini_map; +pub mod mini_set; pub mod tagged_ptr; pub mod temp_dir; +pub mod unhash; pub use ena::undo_log; pub use ena::unify; diff --git a/src/librustc_data_structures/macros.rs b/compiler/rustc_data_structures/src/macros.rs similarity index 76% rename from src/librustc_data_structures/macros.rs rename to compiler/rustc_data_structures/src/macros.rs index 67fbe3058c..b918ed9458 100644 --- a/src/librustc_data_structures/macros.rs +++ b/compiler/rustc_data_structures/src/macros.rs @@ -1,15 +1,3 @@ -/// A simple static assertion macro. -#[macro_export] -#[allow_internal_unstable(type_ascription)] -macro_rules! static_assert { - ($test:expr) => { - // Use the bool to access an array such that if the bool is false, the access - // is out-of-bounds. - #[allow(dead_code)] - const _: () = [()][!($test: bool) as usize]; - }; -} - /// Type size assertion. The first argument is a type and the second argument is its expected size. #[macro_export] macro_rules! static_assert_size { diff --git a/src/librustc_data_structures/map_in_place.rs b/compiler/rustc_data_structures/src/map_in_place.rs similarity index 100% rename from src/librustc_data_structures/map_in_place.rs rename to compiler/rustc_data_structures/src/map_in_place.rs diff --git a/src/librustc_data_structures/mini_map.rs b/compiler/rustc_data_structures/src/mini_map.rs similarity index 100% rename from src/librustc_data_structures/mini_map.rs rename to compiler/rustc_data_structures/src/mini_map.rs diff --git a/compiler/rustc_data_structures/src/mini_set.rs b/compiler/rustc_data_structures/src/mini_set.rs new file mode 100644 index 0000000000..9d45af723d --- /dev/null +++ b/compiler/rustc_data_structures/src/mini_set.rs @@ -0,0 +1,41 @@ +use crate::fx::FxHashSet; +use arrayvec::ArrayVec; +use std::hash::Hash; +/// Small-storage-optimized implementation of a set. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashSet` when that length is exceeded. +pub enum MiniSet { + Array(ArrayVec<[T; 8]>), + Set(FxHashSet), +} + +impl MiniSet { + /// Creates an empty `MiniSet`. + pub fn new() -> Self { + MiniSet::Array(ArrayVec::new()) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, true is returned. + /// + /// If the set did have this value present, false is returned. + pub fn insert(&mut self, elem: T) -> bool { + match self { + MiniSet::Array(array) => { + if array.iter().any(|e| *e == elem) { + false + } else { + if let Err(error) = array.try_push(elem) { + let mut set: FxHashSet = array.drain(..).collect(); + set.insert(error.element()); + *self = MiniSet::Set(set); + } + true + } + } + MiniSet::Set(set) => set.insert(elem), + } + } +} diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs similarity index 100% rename from src/librustc_data_structures/obligation_forest/graphviz.rs rename to compiler/rustc_data_structures/src/obligation_forest/graphviz.rs diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs similarity index 100% rename from src/librustc_data_structures/obligation_forest/mod.rs rename to compiler/rustc_data_structures/src/obligation_forest/mod.rs diff --git a/src/librustc_data_structures/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs similarity index 100% rename from src/librustc_data_structures/obligation_forest/tests.rs rename to compiler/rustc_data_structures/src/obligation_forest/tests.rs diff --git a/src/librustc_data_structures/owning_ref/LICENSE b/compiler/rustc_data_structures/src/owning_ref/LICENSE similarity index 100% rename from src/librustc_data_structures/owning_ref/LICENSE rename to compiler/rustc_data_structures/src/owning_ref/LICENSE diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/compiler/rustc_data_structures/src/owning_ref/mod.rs similarity index 100% rename from src/librustc_data_structures/owning_ref/mod.rs rename to compiler/rustc_data_structures/src/owning_ref/mod.rs diff --git a/src/librustc_data_structures/owning_ref/tests.rs b/compiler/rustc_data_structures/src/owning_ref/tests.rs similarity index 100% rename from src/librustc_data_structures/owning_ref/tests.rs rename to compiler/rustc_data_structures/src/owning_ref/tests.rs diff --git a/src/librustc_data_structures/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs similarity index 99% rename from src/librustc_data_structures/profiling.rs rename to compiler/rustc_data_structures/src/profiling.rs index 07d16c6483..363879cbb1 100644 --- a/src/librustc_data_structures/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -600,10 +600,7 @@ pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) { // Hack up our own formatting for the duration to make it easier for scripts // to parse (always use the same number of decimal places and the same unit). pub fn duration_to_secs_str(dur: std::time::Duration) -> String { - const NANOS_PER_SEC: f64 = 1_000_000_000.0; - let secs = dur.as_secs() as f64 + dur.subsec_nanos() as f64 / NANOS_PER_SEC; - - format!("{:.3}", secs) + format!("{:.3}", dur.as_secs_f64()) } // Memory reporting diff --git a/src/librustc_data_structures/ptr_key.rs b/compiler/rustc_data_structures/src/ptr_key.rs similarity index 100% rename from src/librustc_data_structures/ptr_key.rs rename to compiler/rustc_data_structures/src/ptr_key.rs diff --git a/src/librustc_data_structures/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs similarity index 100% rename from src/librustc_data_structures/sharded.rs rename to compiler/rustc_data_structures/src/sharded.rs diff --git a/src/librustc_data_structures/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs similarity index 89% rename from src/librustc_data_structures/sip128.rs rename to compiler/rustc_data_structures/src/sip128.rs index beb28dd072..2c4eff618c 100644 --- a/src/librustc_data_structures/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -125,15 +125,28 @@ impl SipHasher128 { // A specialized write function for values with size <= 8. // - // The hashing of multi-byte integers depends on endianness. E.g.: + // The input must be zero-extended to 64-bits by the caller. This extension + // isn't hashed, but the implementation requires it for correctness. + // + // This function, given the same integer size and value, has the same effect + // on both little- and big-endian hardware. It operates on values without + // depending on their sequence in memory, so is independent of endianness. + // + // However, we want SipHasher128 to be platform-dependent, in order to be + // consistent with the platform-dependent SipHasher in libstd. In other + // words, we want: + // // - little-endian: `write_u32(0xDDCCBBAA)` == `write([0xAA, 0xBB, 0xCC, 0xDD])` // - big-endian: `write_u32(0xDDCCBBAA)` == `write([0xDD, 0xCC, 0xBB, 0xAA])` // - // This function does the right thing for little-endian hardware. On - // big-endian hardware `x` must be byte-swapped first to give the right - // behaviour. After any byte-swapping, the input must be zero-extended to - // 64-bits. The caller is responsible for the byte-swapping and - // zero-extension. + // Therefore, in order to produce endian-dependent results, SipHasher128's + // `write_xxx` Hasher trait methods byte-swap `x` prior to zero-extending. + // + // If clients of SipHasher128 itself want platform-independent results, they + // *also* must byte-swap integer inputs before invoking the `write_xxx` + // methods on big-endian hardware (that is, two byte-swaps must occur--one + // in the client, and one in SipHasher128). Additionally, they must extend + // `usize` and `isize` types to 64 bits on 32-bit systems. #[inline] fn short_write(&mut self, _x: T, x: u64) { let size = mem::size_of::(); diff --git a/src/librustc_data_structures/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs similarity index 90% rename from src/librustc_data_structures/sip128/tests.rs rename to compiler/rustc_data_structures/src/sip128/tests.rs index 80b7fc7475..2e2274a7b7 100644 --- a/src/librustc_data_structures/sip128/tests.rs +++ b/compiler/rustc_data_structures/src/sip128/tests.rs @@ -1,7 +1,6 @@ use super::*; use std::hash::{Hash, Hasher}; -use std::{mem, slice}; // Hash just the bytes of the slice, without length prefix struct Bytes<'a>(&'a [u8]); @@ -399,20 +398,55 @@ fn test_hash_no_concat_alias() { } #[test] -fn test_write_short_works() { - let test_usize = 0xd0c0b0a0usize; +fn test_short_write_works() { + let test_u8 = 0xFF_u8; + let test_u16 = 0x1122_u16; + let test_u32 = 0x22334455_u32; + let test_u64 = 0x33445566_778899AA_u64; + let test_u128 = 0x11223344_55667788_99AABBCC_DDEEFF77_u128; + let test_usize = 0xD0C0B0A0_usize; + + let test_i8 = -1_i8; + let test_i16 = -2_i16; + let test_i32 = -3_i32; + let test_i64 = -4_i64; + let test_i128 = -5_i128; + let test_isize = -6_isize; + let mut h1 = SipHasher128::new_with_keys(0, 0); - h1.write_usize(test_usize); h1.write(b"bytes"); h1.write(b"string"); - h1.write_u8(0xFFu8); - h1.write_u8(0x01u8); + h1.write_u8(test_u8); + h1.write_u16(test_u16); + h1.write_u32(test_u32); + h1.write_u64(test_u64); + h1.write_u128(test_u128); + h1.write_usize(test_usize); + h1.write_i8(test_i8); + h1.write_i16(test_i16); + h1.write_i32(test_i32); + h1.write_i64(test_i64); + h1.write_i128(test_i128); + h1.write_isize(test_isize); + let mut h2 = SipHasher128::new_with_keys(0, 0); - h2.write(unsafe { - slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::()) - }); h2.write(b"bytes"); h2.write(b"string"); - h2.write(&[0xFFu8, 0x01u8]); - assert_eq!(h1.finish128(), h2.finish128()); + h2.write(&test_u8.to_ne_bytes()); + h2.write(&test_u16.to_ne_bytes()); + h2.write(&test_u32.to_ne_bytes()); + h2.write(&test_u64.to_ne_bytes()); + h2.write(&test_u128.to_ne_bytes()); + h2.write(&test_usize.to_ne_bytes()); + h2.write(&test_i8.to_ne_bytes()); + h2.write(&test_i16.to_ne_bytes()); + h2.write(&test_i32.to_ne_bytes()); + h2.write(&test_i64.to_ne_bytes()); + h2.write(&test_i128.to_ne_bytes()); + h2.write(&test_isize.to_ne_bytes()); + + let h1_hash = h1.finish128(); + let h2_hash = h2.finish128(); + + assert_eq!(h1_hash, h2_hash); } diff --git a/src/librustc_data_structures/small_c_str.rs b/compiler/rustc_data_structures/src/small_c_str.rs similarity index 100% rename from src/librustc_data_structures/small_c_str.rs rename to compiler/rustc_data_structures/src/small_c_str.rs diff --git a/src/librustc_data_structures/small_c_str/tests.rs b/compiler/rustc_data_structures/src/small_c_str/tests.rs similarity index 100% rename from src/librustc_data_structures/small_c_str/tests.rs rename to compiler/rustc_data_structures/src/small_c_str/tests.rs diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/compiler/rustc_data_structures/src/snapshot_map/mod.rs similarity index 100% rename from src/librustc_data_structures/snapshot_map/mod.rs rename to compiler/rustc_data_structures/src/snapshot_map/mod.rs diff --git a/src/librustc_data_structures/snapshot_map/tests.rs b/compiler/rustc_data_structures/src/snapshot_map/tests.rs similarity index 100% rename from src/librustc_data_structures/snapshot_map/tests.rs rename to compiler/rustc_data_structures/src/snapshot_map/tests.rs diff --git a/src/librustc_data_structures/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs similarity index 98% rename from src/librustc_data_structures/sorted_map.rs rename to compiler/rustc_data_structures/src/sorted_map.rs index 856eb73e62..4807380595 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -34,7 +34,7 @@ impl SortedMap { /// and that there are no duplicates. #[inline] pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap { - debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); SortedMap { data: elements } } @@ -159,7 +159,7 @@ impl SortedMap { return; } - debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); let start_index = self.lookup_index_for(&elements[0].0); diff --git a/src/librustc_data_structures/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs similarity index 100% rename from src/librustc_data_structures/sorted_map/index_map.rs rename to compiler/rustc_data_structures/src/sorted_map/index_map.rs diff --git a/src/librustc_data_structures/sorted_map/tests.rs b/compiler/rustc_data_structures/src/sorted_map/tests.rs similarity index 100% rename from src/librustc_data_structures/sorted_map/tests.rs rename to compiler/rustc_data_structures/src/sorted_map/tests.rs diff --git a/src/librustc_data_structures/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs similarity index 98% rename from src/librustc_data_structures/stable_hasher.rs rename to compiler/rustc_data_structures/src/stable_hasher.rs index c1c79b174f..68875b3fbd 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -5,6 +5,9 @@ use smallvec::SmallVec; use std::hash::{BuildHasher, Hash, Hasher}; use std::mem; +#[cfg(test)] +mod tests; + /// When hashing something that ends up affecting properties like symbol names, /// we want these symbol names to be calculated independently of other factors /// like what architecture you're compiling *from*. @@ -129,7 +132,8 @@ impl Hasher for StableHasher { fn write_isize(&mut self, i: isize) { // Always treat isize as i64 so we get the same results on 32 and 64 bit // platforms. This is important for symbol hashes when cross compiling, - // for example. + // for example. Sign extending here is preferable as it means that the + // same negative number hashes the same on both 32 and 64 bit platforms. self.state.write_i64((i as i64).to_le()); } } diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs new file mode 100644 index 0000000000..cd6ff96a55 --- /dev/null +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -0,0 +1,73 @@ +use super::*; + +// The tests below compare the computed hashes to particular expected values +// in order to test that we produce the same results on different platforms, +// regardless of endianness and `usize` and `isize` size differences (this +// of course assumes we run these tests on platforms that differ in those +// ways). The expected values depend on the hashing algorithm used, so they +// need to be updated whenever StableHasher changes its hashing algorithm. + +#[test] +fn test_hash_integers() { + // Test that integers are handled consistently across platforms. + let test_u8 = 0xAB_u8; + let test_u16 = 0xFFEE_u16; + let test_u32 = 0x445577AA_u32; + let test_u64 = 0x01234567_13243546_u64; + let test_u128 = 0x22114433_66557788_99AACCBB_EEDDFF77_u128; + let test_usize = 0xD0C0B0A0_usize; + + let test_i8 = -100_i8; + let test_i16 = -200_i16; + let test_i32 = -300_i32; + let test_i64 = -400_i64; + let test_i128 = -500_i128; + let test_isize = -600_isize; + + let mut h = StableHasher::new(); + test_u8.hash(&mut h); + test_u16.hash(&mut h); + test_u32.hash(&mut h); + test_u64.hash(&mut h); + test_u128.hash(&mut h); + test_usize.hash(&mut h); + test_i8.hash(&mut h); + test_i16.hash(&mut h); + test_i32.hash(&mut h); + test_i64.hash(&mut h); + test_i128.hash(&mut h); + test_isize.hash(&mut h); + + // This depends on the hashing algorithm. See note at top of file. + let expected = (2736651863462566372, 8121090595289675650); + + assert_eq!(h.finalize(), expected); +} + +#[test] +fn test_hash_usize() { + // Test that usize specifically is handled consistently across platforms. + let test_usize = 0xABCDEF01_usize; + + let mut h = StableHasher::new(); + test_usize.hash(&mut h); + + // This depends on the hashing algorithm. See note at top of file. + let expected = (5798740672699530587, 11186240177685111648); + + assert_eq!(h.finalize(), expected); +} + +#[test] +fn test_hash_isize() { + // Test that isize specifically is handled consistently across platforms. + let test_isize = -7_isize; + + let mut h = StableHasher::new(); + test_isize.hash(&mut h); + + // This depends on the hashing algorithm. See note at top of file. + let expected = (14721296605626097289, 11385941877786388409); + + assert_eq!(h.finalize(), expected); +} diff --git a/src/librustc_data_structures/stable_map.rs b/compiler/rustc_data_structures/src/stable_map.rs similarity index 100% rename from src/librustc_data_structures/stable_map.rs rename to compiler/rustc_data_structures/src/stable_map.rs diff --git a/src/librustc_data_structures/stable_set.rs b/compiler/rustc_data_structures/src/stable_set.rs similarity index 100% rename from src/librustc_data_structures/stable_set.rs rename to compiler/rustc_data_structures/src/stable_set.rs diff --git a/src/librustc_data_structures/stack.rs b/compiler/rustc_data_structures/src/stack.rs similarity index 100% rename from src/librustc_data_structures/stack.rs rename to compiler/rustc_data_structures/src/stack.rs diff --git a/src/librustc_data_structures/svh.rs b/compiler/rustc_data_structures/src/svh.rs similarity index 100% rename from src/librustc_data_structures/svh.rs rename to compiler/rustc_data_structures/src/svh.rs diff --git a/src/librustc_data_structures/sync.rs b/compiler/rustc_data_structures/src/sync.rs similarity index 99% rename from src/librustc_data_structures/sync.rs rename to compiler/rustc_data_structures/src/sync.rs index 53d831749c..d22f3adfb0 100644 --- a/src/librustc_data_structures/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -229,7 +229,7 @@ cfg_if! { pub use std::cell::RefMut as LockGuard; pub use std::cell::RefMut as MappedLockGuard; - pub use once_cell::unsync::OnceCell; + pub use std::lazy::OnceCell; use std::cell::RefCell as InnerRwLock; use std::cell::RefCell as InnerLock; @@ -314,7 +314,7 @@ cfg_if! { pub use parking_lot::MutexGuard as LockGuard; pub use parking_lot::MappedMutexGuard as MappedLockGuard; - pub use once_cell::sync::OnceCell; + pub use std::lazy::SyncOnceCell as OnceCell; pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; diff --git a/src/librustc_data_structures/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs similarity index 100% rename from src/librustc_data_structures/tagged_ptr.rs rename to compiler/rustc_data_structures/src/tagged_ptr.rs diff --git a/src/librustc_data_structures/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs similarity index 98% rename from src/librustc_data_structures/tagged_ptr/copy.rs rename to compiler/rustc_data_structures/src/tagged_ptr/copy.rs index d39d146db3..d63bcdb3c2 100644 --- a/src/librustc_data_structures/tagged_ptr/copy.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs @@ -48,7 +48,7 @@ where P: Pointer, T: Tag, { - const TAG_BIT_SHIFT: usize = (8 * std::mem::size_of::()) - T::BITS; + const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS; const ASSERTION: () = { assert!(T::BITS <= P::BITS); // Used for the transmute_copy's below diff --git a/src/librustc_data_structures/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs similarity index 100% rename from src/librustc_data_structures/tagged_ptr/drop.rs rename to compiler/rustc_data_structures/src/tagged_ptr/drop.rs diff --git a/src/librustc_data_structures/temp_dir.rs b/compiler/rustc_data_structures/src/temp_dir.rs similarity index 92% rename from src/librustc_data_structures/temp_dir.rs rename to compiler/rustc_data_structures/src/temp_dir.rs index 0d9b3e3ca2..a780d2386a 100644 --- a/src/librustc_data_structures/temp_dir.rs +++ b/compiler/rustc_data_structures/src/temp_dir.rs @@ -12,7 +12,7 @@ pub struct MaybeTempDir { impl Drop for MaybeTempDir { fn drop(&mut self) { - // Safety: We are in the destructor, and no further access will + // SAFETY: We are in the destructor, and no further access will // occur. let dir = unsafe { ManuallyDrop::take(&mut self.dir) }; if self.keep { diff --git a/src/librustc_data_structures/thin_vec.rs b/compiler/rustc_data_structures/src/thin_vec.rs similarity index 100% rename from src/librustc_data_structures/thin_vec.rs rename to compiler/rustc_data_structures/src/thin_vec.rs diff --git a/src/librustc_data_structures/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs similarity index 100% rename from src/librustc_data_structures/tiny_list.rs rename to compiler/rustc_data_structures/src/tiny_list.rs diff --git a/src/librustc_data_structures/tiny_list/tests.rs b/compiler/rustc_data_structures/src/tiny_list/tests.rs similarity index 100% rename from src/librustc_data_structures/tiny_list/tests.rs rename to compiler/rustc_data_structures/src/tiny_list/tests.rs diff --git a/src/librustc_data_structures/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs similarity index 100% rename from src/librustc_data_structures/transitive_relation.rs rename to compiler/rustc_data_structures/src/transitive_relation.rs diff --git a/src/librustc_data_structures/transitive_relation/tests.rs b/compiler/rustc_data_structures/src/transitive_relation/tests.rs similarity index 100% rename from src/librustc_data_structures/transitive_relation/tests.rs rename to compiler/rustc_data_structures/src/transitive_relation/tests.rs diff --git a/compiler/rustc_data_structures/src/unhash.rs b/compiler/rustc_data_structures/src/unhash.rs new file mode 100644 index 0000000000..48e21a9dab --- /dev/null +++ b/compiler/rustc_data_structures/src/unhash.rs @@ -0,0 +1,29 @@ +use std::collections::{HashMap, HashSet}; +use std::hash::{BuildHasherDefault, Hasher}; + +pub type UnhashMap = HashMap>; +pub type UnhashSet = HashSet>; + +/// This no-op hasher expects only a single `write_u64` call. It's intended for +/// map keys that already have hash-like quality, like `Fingerprint`. +#[derive(Default)] +pub struct Unhasher { + value: u64, +} + +impl Hasher for Unhasher { + #[inline] + fn finish(&self) -> u64 { + self.value + } + + fn write(&mut self, _bytes: &[u8]) { + unimplemented!("use write_u64"); + } + + #[inline] + fn write_u64(&mut self, value: u64) { + debug_assert_eq!(0, self.value, "Unhasher doesn't mix values!"); + self.value = value; + } +} diff --git a/src/librustc_data_structures/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs similarity index 100% rename from src/librustc_data_structures/vec_linked_list.rs rename to compiler/rustc_data_structures/src/vec_linked_list.rs diff --git a/src/librustc_data_structures/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs similarity index 100% rename from src/librustc_data_structures/work_queue.rs rename to compiler/rustc_data_structures/src/work_queue.rs diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml new file mode 100644 index 0000000000..adfce1008e --- /dev/null +++ b/compiler/rustc_driver/Cargo.toml @@ -0,0 +1,41 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_driver" +version = "0.0.0" +edition = "2018" + +[lib] +crate-type = ["dylib"] + +[dependencies] +libc = "0.2" +tracing = { version = "0.1.18" } +tracing-subscriber = { version = "0.2.10", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } +rustc_middle = { path = "../rustc_middle" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_target = { path = "../rustc_target" } +rustc_lint = { path = "../rustc_lint" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_mir = { path = "../rustc_mir" } +rustc_parse = { path = "../rustc_parse" } +rustc_plugin_impl = { path = "../rustc_plugin_impl" } +rustc_save_analysis = { path = "../rustc_save_analysis" } +rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } +rustc_session = { path = "../rustc_session" } +rustc_error_codes = { path = "../rustc_error_codes" } +rustc_interface = { path = "../rustc_interface" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] } + +[features] +llvm = ['rustc_interface/llvm'] +max_level_info = ['tracing/max_level_info'] diff --git a/src/librustc_driver/README.md b/compiler/rustc_driver/README.md similarity index 100% rename from src/librustc_driver/README.md rename to compiler/rustc_driver/README.md diff --git a/src/librustc_driver/args.rs b/compiler/rustc_driver/src/args.rs similarity index 94% rename from src/librustc_driver/args.rs rename to compiler/rustc_driver/src/args.rs index 5686819c61..4f2febf04b 100644 --- a/src/librustc_driver/args.rs +++ b/compiler/rustc_driver/src/args.rs @@ -4,8 +4,7 @@ use std::fs; use std::io; pub fn arg_expand(arg: String) -> Result, Error> { - if arg.starts_with('@') { - let path = &arg[1..]; + if let Some(path) = arg.strip_prefix('@') { let file = match fs::read_to_string(path) { Ok(file) => file, Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { diff --git a/src/librustc_driver/lib.rs b/compiler/rustc_driver/src/lib.rs similarity index 97% rename from src/librustc_driver/lib.rs rename to compiler/rustc_driver/src/lib.rs index 09f5b22cc6..544efc124e 100644 --- a/src/librustc_driver/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -4,14 +4,13 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] +#![feature(once_cell)] #![recursion_limit = "256"] #[macro_use] extern crate tracing; -#[macro_use] -extern crate lazy_static; pub extern crate rustc_plugin_impl as plugin; @@ -33,7 +32,7 @@ use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; use rustc_serialize::json::{self, ToJson}; use rustc_session::config::nightly_options; -use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest}; +use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}; use rustc_session::getopts; use rustc_session::lint::{Lint, LintId}; use rustc_session::{config, DiagnosticOutput, Session}; @@ -48,6 +47,7 @@ use std::env; use std::ffi::OsString; use std::fs; use std::io::{self, Read, Write}; +use std::lazy::SyncLazy; use std::mem; use std::panic::{self, catch_unwind}; use std::path::PathBuf; @@ -126,6 +126,7 @@ impl Callbacks for TimePassesCallbacks { // time because it will mess up the --prints output. See #64339. self.time_passes = config.opts.prints.is_empty() && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time); + config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath; } } @@ -140,6 +141,9 @@ pub fn run_compiler( callbacks: &mut (dyn Callbacks + Send), file_loader: Option>, emitter: Option>, + make_codegen_backend: Option< + Box Box + Send>, + >, ) -> interface::Result<()> { let mut args = Vec::new(); for arg in at_args { @@ -161,6 +165,11 @@ pub fn run_compiler( let sopts = config::build_session_options(&matches); let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg")); + // We wrap `make_codegen_backend` in another `Option` such that `dummy_config` can take + // ownership of it when necessary, while also allowing the non-dummy config to take ownership + // when `dummy_config` is not used. + let mut make_codegen_backend = Some(make_codegen_backend); + let mut dummy_config = |sopts, cfg, diagnostic_output| { let mut config = interface::Config { opts: sopts, @@ -176,6 +185,7 @@ pub fn run_compiler( lint_caps: Default::default(), register_lints: None, override_queries: None, + make_codegen_backend: make_codegen_backend.take().unwrap(), registry: diagnostics_registry(), }; callbacks.config(&mut config); @@ -252,6 +262,7 @@ pub fn run_compiler( lint_caps: Default::default(), register_lints: None, override_queries: None, + make_codegen_backend: make_codegen_backend.unwrap(), registry: diagnostics_registry(), }; @@ -1141,13 +1152,12 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { } } -lazy_static! { - static ref DEFAULT_HOOK: Box) + Sync + Send + 'static> = { +static DEFAULT_HOOK: SyncLazy) + Sync + Send + 'static>> = + SyncLazy::new(|| { let hook = panic::take_hook(); panic::set_hook(Box::new(|info| report_ice(info, BUG_REPORT_URL))); hook - }; -} + }); /// Prints the ICE message, including backtrace and query stack. /// @@ -1222,7 +1232,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { /// /// A custom rustc driver can skip calling this to set up a custom ICE hook. pub fn install_ice_hook() { - lazy_static::initialize(&DEFAULT_HOOK); + SyncLazy::force(&DEFAULT_HOOK); } /// This allows tools to enable rust logging without having to magically match rustc's @@ -1265,7 +1275,7 @@ pub fn main() -> ! { }) }) .collect::>(); - run_compiler(&args, &mut callbacks, None, None) + run_compiler(&args, &mut callbacks, None, None, None) }); // The extra `\t` is necessary to align this label with the others. print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed()); diff --git a/src/librustc_driver/pretty.rs b/compiler/rustc_driver/src/pretty.rs similarity index 100% rename from src/librustc_driver/pretty.rs rename to compiler/rustc_driver/src/pretty.rs diff --git a/src/librustc_error_codes/Cargo.toml b/compiler/rustc_error_codes/Cargo.toml similarity index 69% rename from src/librustc_error_codes/Cargo.toml rename to compiler/rustc_error_codes/Cargo.toml index 5def867ff1..b4c9cd9456 100644 --- a/src/librustc_error_codes/Cargo.toml +++ b/compiler/rustc_error_codes/Cargo.toml @@ -3,7 +3,3 @@ authors = ["The Rust Project Developers"] name = "rustc_error_codes" version = "0.0.0" edition = "2018" - -[lib] -name = "rustc_error_codes" -path = "lib.rs" diff --git a/src/librustc_error_codes/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs similarity index 98% rename from src/librustc_error_codes/error_codes.rs rename to compiler/rustc_error_codes/src/error_codes.rs index 4e5e77f80c..81f65ac869 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -18,7 +18,6 @@ E0010: include_str!("./error_codes/E0010.md"), E0013: include_str!("./error_codes/E0013.md"), E0014: include_str!("./error_codes/E0014.md"), E0015: include_str!("./error_codes/E0015.md"), -E0019: include_str!("./error_codes/E0019.md"), E0023: include_str!("./error_codes/E0023.md"), E0025: include_str!("./error_codes/E0025.md"), E0026: include_str!("./error_codes/E0026.md"), @@ -440,6 +439,8 @@ E0751: include_str!("./error_codes/E0751.md"), E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), E0754: include_str!("./error_codes/E0754.md"), +E0755: include_str!("./error_codes/E0755.md"), +E0756: include_str!("./error_codes/E0756.md"), E0758: include_str!("./error_codes/E0758.md"), E0759: include_str!("./error_codes/E0759.md"), E0760: include_str!("./error_codes/E0760.md"), @@ -454,9 +455,14 @@ E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), E0770: include_str!("./error_codes/E0770.md"), E0771: include_str!("./error_codes/E0771.md"), +E0773: include_str!("./error_codes/E0773.md"), +E0774: include_str!("./error_codes/E0774.md"), +E0775: include_str!("./error_codes/E0775.md"), +E0776: include_str!("./error_codes/E0776.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard +// E0019, merged into E0015 // E0035, merged into E0087/E0089 // E0036, merged into E0087/E0089 // E0068, @@ -630,8 +636,6 @@ E0771: include_str!("./error_codes/E0771.md"), E0722, // Malformed `#[optimize]` attribute E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. - E0755, // `#[ffi_pure]` is only allowed on foreign functions - E0756, // `#[ffi_const]` is only allowed on foreign functions E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]` E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/src/librustc_error_codes/error_codes/E0001.md b/compiler/rustc_error_codes/src/error_codes/E0001.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0001.md rename to compiler/rustc_error_codes/src/error_codes/E0001.md diff --git a/src/librustc_error_codes/error_codes/E0002.md b/compiler/rustc_error_codes/src/error_codes/E0002.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0002.md rename to compiler/rustc_error_codes/src/error_codes/E0002.md diff --git a/src/librustc_error_codes/error_codes/E0004.md b/compiler/rustc_error_codes/src/error_codes/E0004.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0004.md rename to compiler/rustc_error_codes/src/error_codes/E0004.md diff --git a/src/librustc_error_codes/error_codes/E0005.md b/compiler/rustc_error_codes/src/error_codes/E0005.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0005.md rename to compiler/rustc_error_codes/src/error_codes/E0005.md diff --git a/src/librustc_error_codes/error_codes/E0007.md b/compiler/rustc_error_codes/src/error_codes/E0007.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0007.md rename to compiler/rustc_error_codes/src/error_codes/E0007.md diff --git a/src/librustc_error_codes/error_codes/E0009.md b/compiler/rustc_error_codes/src/error_codes/E0009.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0009.md rename to compiler/rustc_error_codes/src/error_codes/E0009.md diff --git a/src/librustc_error_codes/error_codes/E0010.md b/compiler/rustc_error_codes/src/error_codes/E0010.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0010.md rename to compiler/rustc_error_codes/src/error_codes/E0010.md diff --git a/src/librustc_error_codes/error_codes/E0013.md b/compiler/rustc_error_codes/src/error_codes/E0013.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0013.md rename to compiler/rustc_error_codes/src/error_codes/E0013.md diff --git a/src/librustc_error_codes/error_codes/E0014.md b/compiler/rustc_error_codes/src/error_codes/E0014.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0014.md rename to compiler/rustc_error_codes/src/error_codes/E0014.md diff --git a/src/librustc_error_codes/error_codes/E0015.md b/compiler/rustc_error_codes/src/error_codes/E0015.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0015.md rename to compiler/rustc_error_codes/src/error_codes/E0015.md diff --git a/src/librustc_error_codes/error_codes/E0023.md b/compiler/rustc_error_codes/src/error_codes/E0023.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0023.md rename to compiler/rustc_error_codes/src/error_codes/E0023.md diff --git a/src/librustc_error_codes/error_codes/E0025.md b/compiler/rustc_error_codes/src/error_codes/E0025.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0025.md rename to compiler/rustc_error_codes/src/error_codes/E0025.md diff --git a/src/librustc_error_codes/error_codes/E0026.md b/compiler/rustc_error_codes/src/error_codes/E0026.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0026.md rename to compiler/rustc_error_codes/src/error_codes/E0026.md diff --git a/src/librustc_error_codes/error_codes/E0027.md b/compiler/rustc_error_codes/src/error_codes/E0027.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0027.md rename to compiler/rustc_error_codes/src/error_codes/E0027.md diff --git a/src/librustc_error_codes/error_codes/E0029.md b/compiler/rustc_error_codes/src/error_codes/E0029.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0029.md rename to compiler/rustc_error_codes/src/error_codes/E0029.md diff --git a/src/librustc_error_codes/error_codes/E0030.md b/compiler/rustc_error_codes/src/error_codes/E0030.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0030.md rename to compiler/rustc_error_codes/src/error_codes/E0030.md diff --git a/src/librustc_error_codes/error_codes/E0033.md b/compiler/rustc_error_codes/src/error_codes/E0033.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0033.md rename to compiler/rustc_error_codes/src/error_codes/E0033.md diff --git a/src/librustc_error_codes/error_codes/E0034.md b/compiler/rustc_error_codes/src/error_codes/E0034.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0034.md rename to compiler/rustc_error_codes/src/error_codes/E0034.md diff --git a/src/librustc_error_codes/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0038.md rename to compiler/rustc_error_codes/src/error_codes/E0038.md diff --git a/src/librustc_error_codes/error_codes/E0040.md b/compiler/rustc_error_codes/src/error_codes/E0040.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0040.md rename to compiler/rustc_error_codes/src/error_codes/E0040.md diff --git a/src/librustc_error_codes/error_codes/E0044.md b/compiler/rustc_error_codes/src/error_codes/E0044.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0044.md rename to compiler/rustc_error_codes/src/error_codes/E0044.md diff --git a/src/librustc_error_codes/error_codes/E0045.md b/compiler/rustc_error_codes/src/error_codes/E0045.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0045.md rename to compiler/rustc_error_codes/src/error_codes/E0045.md diff --git a/src/librustc_error_codes/error_codes/E0046.md b/compiler/rustc_error_codes/src/error_codes/E0046.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0046.md rename to compiler/rustc_error_codes/src/error_codes/E0046.md diff --git a/src/librustc_error_codes/error_codes/E0049.md b/compiler/rustc_error_codes/src/error_codes/E0049.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0049.md rename to compiler/rustc_error_codes/src/error_codes/E0049.md diff --git a/src/librustc_error_codes/error_codes/E0050.md b/compiler/rustc_error_codes/src/error_codes/E0050.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0050.md rename to compiler/rustc_error_codes/src/error_codes/E0050.md diff --git a/src/librustc_error_codes/error_codes/E0053.md b/compiler/rustc_error_codes/src/error_codes/E0053.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0053.md rename to compiler/rustc_error_codes/src/error_codes/E0053.md diff --git a/src/librustc_error_codes/error_codes/E0054.md b/compiler/rustc_error_codes/src/error_codes/E0054.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0054.md rename to compiler/rustc_error_codes/src/error_codes/E0054.md diff --git a/src/librustc_error_codes/error_codes/E0055.md b/compiler/rustc_error_codes/src/error_codes/E0055.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0055.md rename to compiler/rustc_error_codes/src/error_codes/E0055.md diff --git a/src/librustc_error_codes/error_codes/E0057.md b/compiler/rustc_error_codes/src/error_codes/E0057.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0057.md rename to compiler/rustc_error_codes/src/error_codes/E0057.md diff --git a/src/librustc_error_codes/error_codes/E0059.md b/compiler/rustc_error_codes/src/error_codes/E0059.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0059.md rename to compiler/rustc_error_codes/src/error_codes/E0059.md diff --git a/src/librustc_error_codes/error_codes/E0060.md b/compiler/rustc_error_codes/src/error_codes/E0060.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0060.md rename to compiler/rustc_error_codes/src/error_codes/E0060.md diff --git a/src/librustc_error_codes/error_codes/E0061.md b/compiler/rustc_error_codes/src/error_codes/E0061.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0061.md rename to compiler/rustc_error_codes/src/error_codes/E0061.md diff --git a/src/librustc_error_codes/error_codes/E0062.md b/compiler/rustc_error_codes/src/error_codes/E0062.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0062.md rename to compiler/rustc_error_codes/src/error_codes/E0062.md diff --git a/src/librustc_error_codes/error_codes/E0063.md b/compiler/rustc_error_codes/src/error_codes/E0063.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0063.md rename to compiler/rustc_error_codes/src/error_codes/E0063.md diff --git a/src/librustc_error_codes/error_codes/E0067.md b/compiler/rustc_error_codes/src/error_codes/E0067.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0067.md rename to compiler/rustc_error_codes/src/error_codes/E0067.md diff --git a/src/librustc_error_codes/error_codes/E0069.md b/compiler/rustc_error_codes/src/error_codes/E0069.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0069.md rename to compiler/rustc_error_codes/src/error_codes/E0069.md diff --git a/src/librustc_error_codes/error_codes/E0070.md b/compiler/rustc_error_codes/src/error_codes/E0070.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0070.md rename to compiler/rustc_error_codes/src/error_codes/E0070.md diff --git a/src/librustc_error_codes/error_codes/E0071.md b/compiler/rustc_error_codes/src/error_codes/E0071.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0071.md rename to compiler/rustc_error_codes/src/error_codes/E0071.md diff --git a/src/librustc_error_codes/error_codes/E0072.md b/compiler/rustc_error_codes/src/error_codes/E0072.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0072.md rename to compiler/rustc_error_codes/src/error_codes/E0072.md diff --git a/src/librustc_error_codes/error_codes/E0073.md b/compiler/rustc_error_codes/src/error_codes/E0073.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0073.md rename to compiler/rustc_error_codes/src/error_codes/E0073.md diff --git a/src/librustc_error_codes/error_codes/E0074.md b/compiler/rustc_error_codes/src/error_codes/E0074.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0074.md rename to compiler/rustc_error_codes/src/error_codes/E0074.md diff --git a/src/librustc_error_codes/error_codes/E0075.md b/compiler/rustc_error_codes/src/error_codes/E0075.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0075.md rename to compiler/rustc_error_codes/src/error_codes/E0075.md diff --git a/src/librustc_error_codes/error_codes/E0076.md b/compiler/rustc_error_codes/src/error_codes/E0076.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0076.md rename to compiler/rustc_error_codes/src/error_codes/E0076.md diff --git a/src/librustc_error_codes/error_codes/E0077.md b/compiler/rustc_error_codes/src/error_codes/E0077.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0077.md rename to compiler/rustc_error_codes/src/error_codes/E0077.md diff --git a/src/librustc_error_codes/error_codes/E0080.md b/compiler/rustc_error_codes/src/error_codes/E0080.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0080.md rename to compiler/rustc_error_codes/src/error_codes/E0080.md diff --git a/src/librustc_error_codes/error_codes/E0081.md b/compiler/rustc_error_codes/src/error_codes/E0081.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0081.md rename to compiler/rustc_error_codes/src/error_codes/E0081.md diff --git a/src/librustc_error_codes/error_codes/E0084.md b/compiler/rustc_error_codes/src/error_codes/E0084.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0084.md rename to compiler/rustc_error_codes/src/error_codes/E0084.md diff --git a/src/librustc_error_codes/error_codes/E0087.md b/compiler/rustc_error_codes/src/error_codes/E0087.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0087.md rename to compiler/rustc_error_codes/src/error_codes/E0087.md diff --git a/src/librustc_error_codes/error_codes/E0088.md b/compiler/rustc_error_codes/src/error_codes/E0088.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0088.md rename to compiler/rustc_error_codes/src/error_codes/E0088.md diff --git a/src/librustc_error_codes/error_codes/E0089.md b/compiler/rustc_error_codes/src/error_codes/E0089.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0089.md rename to compiler/rustc_error_codes/src/error_codes/E0089.md diff --git a/src/librustc_error_codes/error_codes/E0090.md b/compiler/rustc_error_codes/src/error_codes/E0090.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0090.md rename to compiler/rustc_error_codes/src/error_codes/E0090.md diff --git a/src/librustc_error_codes/error_codes/E0091.md b/compiler/rustc_error_codes/src/error_codes/E0091.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0091.md rename to compiler/rustc_error_codes/src/error_codes/E0091.md diff --git a/src/librustc_error_codes/error_codes/E0092.md b/compiler/rustc_error_codes/src/error_codes/E0092.md similarity index 74% rename from src/librustc_error_codes/error_codes/E0092.md rename to compiler/rustc_error_codes/src/error_codes/E0092.md index e289534bf7..496174b28e 100644 --- a/src/librustc_error_codes/error_codes/E0092.md +++ b/compiler/rustc_error_codes/src/error_codes/E0092.md @@ -12,8 +12,8 @@ extern "rust-intrinsic" { ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in `librustc_codegen_llvm/intrinsic.rs` and in -`libcore/intrinsics.rs` in the Rust source code. Example: +functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in +`library/core/src/intrinsics.rs` in the Rust source code. Example: ``` #![feature(intrinsics)] diff --git a/src/librustc_error_codes/error_codes/E0093.md b/compiler/rustc_error_codes/src/error_codes/E0093.md similarity index 77% rename from src/librustc_error_codes/error_codes/E0093.md rename to compiler/rustc_error_codes/src/error_codes/E0093.md index 8e7de1a9d3..6d58e50ec8 100644 --- a/src/librustc_error_codes/error_codes/E0093.md +++ b/compiler/rustc_error_codes/src/error_codes/E0093.md @@ -17,8 +17,8 @@ fn main() { ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in `librustc_codegen_llvm/intrinsic.rs` and in -`libcore/intrinsics.rs` in the Rust source code. Example: +functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in +`library/core/src/intrinsics.rs` in the Rust source code. Example: ``` #![feature(intrinsics)] diff --git a/src/librustc_error_codes/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0094.md rename to compiler/rustc_error_codes/src/error_codes/E0094.md diff --git a/src/librustc_error_codes/error_codes/E0106.md b/compiler/rustc_error_codes/src/error_codes/E0106.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0106.md rename to compiler/rustc_error_codes/src/error_codes/E0106.md diff --git a/src/librustc_error_codes/error_codes/E0107.md b/compiler/rustc_error_codes/src/error_codes/E0107.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0107.md rename to compiler/rustc_error_codes/src/error_codes/E0107.md diff --git a/src/librustc_error_codes/error_codes/E0109.md b/compiler/rustc_error_codes/src/error_codes/E0109.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0109.md rename to compiler/rustc_error_codes/src/error_codes/E0109.md diff --git a/src/librustc_error_codes/error_codes/E0110.md b/compiler/rustc_error_codes/src/error_codes/E0110.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0110.md rename to compiler/rustc_error_codes/src/error_codes/E0110.md diff --git a/src/librustc_error_codes/error_codes/E0116.md b/compiler/rustc_error_codes/src/error_codes/E0116.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0116.md rename to compiler/rustc_error_codes/src/error_codes/E0116.md diff --git a/src/librustc_error_codes/error_codes/E0117.md b/compiler/rustc_error_codes/src/error_codes/E0117.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0117.md rename to compiler/rustc_error_codes/src/error_codes/E0117.md diff --git a/src/librustc_error_codes/error_codes/E0118.md b/compiler/rustc_error_codes/src/error_codes/E0118.md similarity index 63% rename from src/librustc_error_codes/error_codes/E0118.md rename to compiler/rustc_error_codes/src/error_codes/E0118.md index 5cb5f506e0..345ec341c3 100644 --- a/src/librustc_error_codes/error_codes/E0118.md +++ b/compiler/rustc_error_codes/src/error_codes/E0118.md @@ -1,10 +1,10 @@ -An inherent implementation was defined for something which isn't a struct nor -an enum. +An inherent implementation was defined for something which isn't a struct, +enum, union, or trait object. Erroneous code example: ```compile_fail,E0118 -impl (u8, u8) { // error: no base type found for inherent implementation +impl (u8, u8) { // error: no nominal type found for inherent implementation fn get_state(&self) -> String { // ... } @@ -41,3 +41,24 @@ impl TypeWrapper { } } ``` + +Instead of defining an inherent implementation on a reference, you could also +move the reference inside the implementation: + +```compile_fail,E0118 +struct Foo; + +impl &Foo { // error: no nominal type found for inherent implementation + fn bar(self, other: Self) {} +} +``` + +becomes + +``` +struct Foo; + +impl Foo { + fn bar(&self, other: &Self) {} +} +``` diff --git a/src/librustc_error_codes/error_codes/E0119.md b/compiler/rustc_error_codes/src/error_codes/E0119.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0119.md rename to compiler/rustc_error_codes/src/error_codes/E0119.md diff --git a/src/librustc_error_codes/error_codes/E0120.md b/compiler/rustc_error_codes/src/error_codes/E0120.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0120.md rename to compiler/rustc_error_codes/src/error_codes/E0120.md diff --git a/src/librustc_error_codes/error_codes/E0121.md b/compiler/rustc_error_codes/src/error_codes/E0121.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0121.md rename to compiler/rustc_error_codes/src/error_codes/E0121.md diff --git a/src/librustc_error_codes/error_codes/E0124.md b/compiler/rustc_error_codes/src/error_codes/E0124.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0124.md rename to compiler/rustc_error_codes/src/error_codes/E0124.md diff --git a/src/librustc_error_codes/error_codes/E0128.md b/compiler/rustc_error_codes/src/error_codes/E0128.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0128.md rename to compiler/rustc_error_codes/src/error_codes/E0128.md diff --git a/src/librustc_error_codes/error_codes/E0130.md b/compiler/rustc_error_codes/src/error_codes/E0130.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0130.md rename to compiler/rustc_error_codes/src/error_codes/E0130.md diff --git a/src/librustc_error_codes/error_codes/E0131.md b/compiler/rustc_error_codes/src/error_codes/E0131.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0131.md rename to compiler/rustc_error_codes/src/error_codes/E0131.md diff --git a/src/librustc_error_codes/error_codes/E0132.md b/compiler/rustc_error_codes/src/error_codes/E0132.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0132.md rename to compiler/rustc_error_codes/src/error_codes/E0132.md diff --git a/src/librustc_error_codes/error_codes/E0133.md b/compiler/rustc_error_codes/src/error_codes/E0133.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0133.md rename to compiler/rustc_error_codes/src/error_codes/E0133.md diff --git a/src/librustc_error_codes/error_codes/E0136.md b/compiler/rustc_error_codes/src/error_codes/E0136.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0136.md rename to compiler/rustc_error_codes/src/error_codes/E0136.md diff --git a/src/librustc_error_codes/error_codes/E0137.md b/compiler/rustc_error_codes/src/error_codes/E0137.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0137.md rename to compiler/rustc_error_codes/src/error_codes/E0137.md diff --git a/src/librustc_error_codes/error_codes/E0138.md b/compiler/rustc_error_codes/src/error_codes/E0138.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0138.md rename to compiler/rustc_error_codes/src/error_codes/E0138.md diff --git a/src/librustc_error_codes/error_codes/E0139.md b/compiler/rustc_error_codes/src/error_codes/E0139.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0139.md rename to compiler/rustc_error_codes/src/error_codes/E0139.md diff --git a/src/librustc_error_codes/error_codes/E0152.md b/compiler/rustc_error_codes/src/error_codes/E0152.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0152.md rename to compiler/rustc_error_codes/src/error_codes/E0152.md diff --git a/src/librustc_error_codes/error_codes/E0154.md b/compiler/rustc_error_codes/src/error_codes/E0154.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0154.md rename to compiler/rustc_error_codes/src/error_codes/E0154.md diff --git a/src/librustc_error_codes/error_codes/E0158.md b/compiler/rustc_error_codes/src/error_codes/E0158.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0158.md rename to compiler/rustc_error_codes/src/error_codes/E0158.md diff --git a/src/librustc_error_codes/error_codes/E0161.md b/compiler/rustc_error_codes/src/error_codes/E0161.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0161.md rename to compiler/rustc_error_codes/src/error_codes/E0161.md diff --git a/src/librustc_error_codes/error_codes/E0162.md b/compiler/rustc_error_codes/src/error_codes/E0162.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0162.md rename to compiler/rustc_error_codes/src/error_codes/E0162.md diff --git a/src/librustc_error_codes/error_codes/E0164.md b/compiler/rustc_error_codes/src/error_codes/E0164.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0164.md rename to compiler/rustc_error_codes/src/error_codes/E0164.md diff --git a/src/librustc_error_codes/error_codes/E0165.md b/compiler/rustc_error_codes/src/error_codes/E0165.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0165.md rename to compiler/rustc_error_codes/src/error_codes/E0165.md diff --git a/src/librustc_error_codes/error_codes/E0170.md b/compiler/rustc_error_codes/src/error_codes/E0170.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0170.md rename to compiler/rustc_error_codes/src/error_codes/E0170.md diff --git a/src/librustc_error_codes/error_codes/E0178.md b/compiler/rustc_error_codes/src/error_codes/E0178.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0178.md rename to compiler/rustc_error_codes/src/error_codes/E0178.md diff --git a/src/librustc_error_codes/error_codes/E0184.md b/compiler/rustc_error_codes/src/error_codes/E0184.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0184.md rename to compiler/rustc_error_codes/src/error_codes/E0184.md diff --git a/src/librustc_error_codes/error_codes/E0185.md b/compiler/rustc_error_codes/src/error_codes/E0185.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0185.md rename to compiler/rustc_error_codes/src/error_codes/E0185.md diff --git a/src/librustc_error_codes/error_codes/E0186.md b/compiler/rustc_error_codes/src/error_codes/E0186.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0186.md rename to compiler/rustc_error_codes/src/error_codes/E0186.md diff --git a/src/librustc_error_codes/error_codes/E0191.md b/compiler/rustc_error_codes/src/error_codes/E0191.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0191.md rename to compiler/rustc_error_codes/src/error_codes/E0191.md diff --git a/src/librustc_error_codes/error_codes/E0192.md b/compiler/rustc_error_codes/src/error_codes/E0192.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0192.md rename to compiler/rustc_error_codes/src/error_codes/E0192.md diff --git a/src/librustc_error_codes/error_codes/E0193.md b/compiler/rustc_error_codes/src/error_codes/E0193.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0193.md rename to compiler/rustc_error_codes/src/error_codes/E0193.md diff --git a/src/librustc_error_codes/error_codes/E0195.md b/compiler/rustc_error_codes/src/error_codes/E0195.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0195.md rename to compiler/rustc_error_codes/src/error_codes/E0195.md diff --git a/src/librustc_error_codes/error_codes/E0197.md b/compiler/rustc_error_codes/src/error_codes/E0197.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0197.md rename to compiler/rustc_error_codes/src/error_codes/E0197.md diff --git a/src/librustc_error_codes/error_codes/E0198.md b/compiler/rustc_error_codes/src/error_codes/E0198.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0198.md rename to compiler/rustc_error_codes/src/error_codes/E0198.md diff --git a/src/librustc_error_codes/error_codes/E0199.md b/compiler/rustc_error_codes/src/error_codes/E0199.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0199.md rename to compiler/rustc_error_codes/src/error_codes/E0199.md diff --git a/src/librustc_error_codes/error_codes/E0200.md b/compiler/rustc_error_codes/src/error_codes/E0200.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0200.md rename to compiler/rustc_error_codes/src/error_codes/E0200.md diff --git a/src/librustc_error_codes/error_codes/E0201.md b/compiler/rustc_error_codes/src/error_codes/E0201.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0201.md rename to compiler/rustc_error_codes/src/error_codes/E0201.md diff --git a/src/librustc_error_codes/error_codes/E0202.md b/compiler/rustc_error_codes/src/error_codes/E0202.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0202.md rename to compiler/rustc_error_codes/src/error_codes/E0202.md diff --git a/src/librustc_error_codes/error_codes/E0203.md b/compiler/rustc_error_codes/src/error_codes/E0203.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0203.md rename to compiler/rustc_error_codes/src/error_codes/E0203.md diff --git a/src/librustc_error_codes/error_codes/E0204.md b/compiler/rustc_error_codes/src/error_codes/E0204.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0204.md rename to compiler/rustc_error_codes/src/error_codes/E0204.md diff --git a/src/librustc_error_codes/error_codes/E0205.md b/compiler/rustc_error_codes/src/error_codes/E0205.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0205.md rename to compiler/rustc_error_codes/src/error_codes/E0205.md diff --git a/src/librustc_error_codes/error_codes/E0206.md b/compiler/rustc_error_codes/src/error_codes/E0206.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0206.md rename to compiler/rustc_error_codes/src/error_codes/E0206.md diff --git a/src/librustc_error_codes/error_codes/E0207.md b/compiler/rustc_error_codes/src/error_codes/E0207.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0207.md rename to compiler/rustc_error_codes/src/error_codes/E0207.md diff --git a/src/librustc_error_codes/error_codes/E0210.md b/compiler/rustc_error_codes/src/error_codes/E0210.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0210.md rename to compiler/rustc_error_codes/src/error_codes/E0210.md diff --git a/src/librustc_error_codes/error_codes/E0211.md b/compiler/rustc_error_codes/src/error_codes/E0211.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0211.md rename to compiler/rustc_error_codes/src/error_codes/E0211.md diff --git a/src/librustc_error_codes/error_codes/E0214.md b/compiler/rustc_error_codes/src/error_codes/E0214.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0214.md rename to compiler/rustc_error_codes/src/error_codes/E0214.md diff --git a/src/librustc_error_codes/error_codes/E0220.md b/compiler/rustc_error_codes/src/error_codes/E0220.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0220.md rename to compiler/rustc_error_codes/src/error_codes/E0220.md diff --git a/src/librustc_error_codes/error_codes/E0221.md b/compiler/rustc_error_codes/src/error_codes/E0221.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0221.md rename to compiler/rustc_error_codes/src/error_codes/E0221.md diff --git a/src/librustc_error_codes/error_codes/E0222.md b/compiler/rustc_error_codes/src/error_codes/E0222.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0222.md rename to compiler/rustc_error_codes/src/error_codes/E0222.md diff --git a/src/librustc_error_codes/error_codes/E0223.md b/compiler/rustc_error_codes/src/error_codes/E0223.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0223.md rename to compiler/rustc_error_codes/src/error_codes/E0223.md diff --git a/src/librustc_error_codes/error_codes/E0224.md b/compiler/rustc_error_codes/src/error_codes/E0224.md similarity index 59% rename from src/librustc_error_codes/error_codes/E0224.md rename to compiler/rustc_error_codes/src/error_codes/E0224.md index fd89c1d525..628488575b 100644 --- a/src/librustc_error_codes/error_codes/E0224.md +++ b/compiler/rustc_error_codes/src/error_codes/E0224.md @@ -1,4 +1,4 @@ -A trait object was declaired with no traits. +A trait object was declared with no traits. Erroneous code example: @@ -8,7 +8,7 @@ type Foo = dyn 'static +; Rust does not currently support this. -To solve ensure the the trait object has at least one trait: +To solve, ensure that the trait object has at least one trait: ``` type Foo = dyn 'static + Copy; diff --git a/src/librustc_error_codes/error_codes/E0225.md b/compiler/rustc_error_codes/src/error_codes/E0225.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0225.md rename to compiler/rustc_error_codes/src/error_codes/E0225.md diff --git a/src/librustc_error_codes/error_codes/E0226.md b/compiler/rustc_error_codes/src/error_codes/E0226.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0226.md rename to compiler/rustc_error_codes/src/error_codes/E0226.md diff --git a/src/librustc_error_codes/error_codes/E0228.md b/compiler/rustc_error_codes/src/error_codes/E0228.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0228.md rename to compiler/rustc_error_codes/src/error_codes/E0228.md diff --git a/src/librustc_error_codes/error_codes/E0229.md b/compiler/rustc_error_codes/src/error_codes/E0229.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0229.md rename to compiler/rustc_error_codes/src/error_codes/E0229.md diff --git a/src/librustc_error_codes/error_codes/E0230.md b/compiler/rustc_error_codes/src/error_codes/E0230.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0230.md rename to compiler/rustc_error_codes/src/error_codes/E0230.md diff --git a/src/librustc_error_codes/error_codes/E0231.md b/compiler/rustc_error_codes/src/error_codes/E0231.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0231.md rename to compiler/rustc_error_codes/src/error_codes/E0231.md diff --git a/src/librustc_error_codes/error_codes/E0232.md b/compiler/rustc_error_codes/src/error_codes/E0232.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0232.md rename to compiler/rustc_error_codes/src/error_codes/E0232.md diff --git a/src/librustc_error_codes/error_codes/E0243.md b/compiler/rustc_error_codes/src/error_codes/E0243.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0243.md rename to compiler/rustc_error_codes/src/error_codes/E0243.md diff --git a/src/librustc_error_codes/error_codes/E0244.md b/compiler/rustc_error_codes/src/error_codes/E0244.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0244.md rename to compiler/rustc_error_codes/src/error_codes/E0244.md diff --git a/src/librustc_error_codes/error_codes/E0251.md b/compiler/rustc_error_codes/src/error_codes/E0251.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0251.md rename to compiler/rustc_error_codes/src/error_codes/E0251.md diff --git a/src/librustc_error_codes/error_codes/E0252.md b/compiler/rustc_error_codes/src/error_codes/E0252.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0252.md rename to compiler/rustc_error_codes/src/error_codes/E0252.md diff --git a/src/librustc_error_codes/error_codes/E0253.md b/compiler/rustc_error_codes/src/error_codes/E0253.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0253.md rename to compiler/rustc_error_codes/src/error_codes/E0253.md diff --git a/src/librustc_error_codes/error_codes/E0254.md b/compiler/rustc_error_codes/src/error_codes/E0254.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0254.md rename to compiler/rustc_error_codes/src/error_codes/E0254.md diff --git a/src/librustc_error_codes/error_codes/E0255.md b/compiler/rustc_error_codes/src/error_codes/E0255.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0255.md rename to compiler/rustc_error_codes/src/error_codes/E0255.md diff --git a/src/librustc_error_codes/error_codes/E0256.md b/compiler/rustc_error_codes/src/error_codes/E0256.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0256.md rename to compiler/rustc_error_codes/src/error_codes/E0256.md diff --git a/src/librustc_error_codes/error_codes/E0259.md b/compiler/rustc_error_codes/src/error_codes/E0259.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0259.md rename to compiler/rustc_error_codes/src/error_codes/E0259.md diff --git a/src/librustc_error_codes/error_codes/E0260.md b/compiler/rustc_error_codes/src/error_codes/E0260.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0260.md rename to compiler/rustc_error_codes/src/error_codes/E0260.md diff --git a/src/librustc_error_codes/error_codes/E0261.md b/compiler/rustc_error_codes/src/error_codes/E0261.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0261.md rename to compiler/rustc_error_codes/src/error_codes/E0261.md diff --git a/src/librustc_error_codes/error_codes/E0262.md b/compiler/rustc_error_codes/src/error_codes/E0262.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0262.md rename to compiler/rustc_error_codes/src/error_codes/E0262.md diff --git a/src/librustc_error_codes/error_codes/E0263.md b/compiler/rustc_error_codes/src/error_codes/E0263.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0263.md rename to compiler/rustc_error_codes/src/error_codes/E0263.md diff --git a/src/librustc_error_codes/error_codes/E0264.md b/compiler/rustc_error_codes/src/error_codes/E0264.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0264.md rename to compiler/rustc_error_codes/src/error_codes/E0264.md diff --git a/src/librustc_error_codes/error_codes/E0267.md b/compiler/rustc_error_codes/src/error_codes/E0267.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0267.md rename to compiler/rustc_error_codes/src/error_codes/E0267.md diff --git a/src/librustc_error_codes/error_codes/E0268.md b/compiler/rustc_error_codes/src/error_codes/E0268.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0268.md rename to compiler/rustc_error_codes/src/error_codes/E0268.md diff --git a/src/librustc_error_codes/error_codes/E0271.md b/compiler/rustc_error_codes/src/error_codes/E0271.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0271.md rename to compiler/rustc_error_codes/src/error_codes/E0271.md diff --git a/src/librustc_error_codes/error_codes/E0275.md b/compiler/rustc_error_codes/src/error_codes/E0275.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0275.md rename to compiler/rustc_error_codes/src/error_codes/E0275.md diff --git a/src/librustc_error_codes/error_codes/E0276.md b/compiler/rustc_error_codes/src/error_codes/E0276.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0276.md rename to compiler/rustc_error_codes/src/error_codes/E0276.md diff --git a/src/librustc_error_codes/error_codes/E0277.md b/compiler/rustc_error_codes/src/error_codes/E0277.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0277.md rename to compiler/rustc_error_codes/src/error_codes/E0277.md diff --git a/src/librustc_error_codes/error_codes/E0281.md b/compiler/rustc_error_codes/src/error_codes/E0281.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0281.md rename to compiler/rustc_error_codes/src/error_codes/E0281.md diff --git a/src/librustc_error_codes/error_codes/E0282.md b/compiler/rustc_error_codes/src/error_codes/E0282.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0282.md rename to compiler/rustc_error_codes/src/error_codes/E0282.md diff --git a/src/librustc_error_codes/error_codes/E0283.md b/compiler/rustc_error_codes/src/error_codes/E0283.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0283.md rename to compiler/rustc_error_codes/src/error_codes/E0283.md diff --git a/src/librustc_error_codes/error_codes/E0284.md b/compiler/rustc_error_codes/src/error_codes/E0284.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0284.md rename to compiler/rustc_error_codes/src/error_codes/E0284.md diff --git a/src/librustc_error_codes/error_codes/E0297.md b/compiler/rustc_error_codes/src/error_codes/E0297.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0297.md rename to compiler/rustc_error_codes/src/error_codes/E0297.md diff --git a/src/librustc_error_codes/error_codes/E0301.md b/compiler/rustc_error_codes/src/error_codes/E0301.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0301.md rename to compiler/rustc_error_codes/src/error_codes/E0301.md diff --git a/src/librustc_error_codes/error_codes/E0302.md b/compiler/rustc_error_codes/src/error_codes/E0302.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0302.md rename to compiler/rustc_error_codes/src/error_codes/E0302.md diff --git a/src/librustc_error_codes/error_codes/E0303.md b/compiler/rustc_error_codes/src/error_codes/E0303.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0303.md rename to compiler/rustc_error_codes/src/error_codes/E0303.md diff --git a/src/librustc_error_codes/error_codes/E0307.md b/compiler/rustc_error_codes/src/error_codes/E0307.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0307.md rename to compiler/rustc_error_codes/src/error_codes/E0307.md diff --git a/src/librustc_error_codes/error_codes/E0308.md b/compiler/rustc_error_codes/src/error_codes/E0308.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0308.md rename to compiler/rustc_error_codes/src/error_codes/E0308.md diff --git a/src/librustc_error_codes/error_codes/E0309.md b/compiler/rustc_error_codes/src/error_codes/E0309.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0309.md rename to compiler/rustc_error_codes/src/error_codes/E0309.md diff --git a/src/librustc_error_codes/error_codes/E0310.md b/compiler/rustc_error_codes/src/error_codes/E0310.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0310.md rename to compiler/rustc_error_codes/src/error_codes/E0310.md diff --git a/src/librustc_error_codes/error_codes/E0312.md b/compiler/rustc_error_codes/src/error_codes/E0312.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0312.md rename to compiler/rustc_error_codes/src/error_codes/E0312.md diff --git a/src/librustc_error_codes/error_codes/E0317.md b/compiler/rustc_error_codes/src/error_codes/E0317.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0317.md rename to compiler/rustc_error_codes/src/error_codes/E0317.md diff --git a/src/librustc_error_codes/error_codes/E0321.md b/compiler/rustc_error_codes/src/error_codes/E0321.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0321.md rename to compiler/rustc_error_codes/src/error_codes/E0321.md diff --git a/src/librustc_error_codes/error_codes/E0322.md b/compiler/rustc_error_codes/src/error_codes/E0322.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0322.md rename to compiler/rustc_error_codes/src/error_codes/E0322.md diff --git a/src/librustc_error_codes/error_codes/E0323.md b/compiler/rustc_error_codes/src/error_codes/E0323.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0323.md rename to compiler/rustc_error_codes/src/error_codes/E0323.md diff --git a/src/librustc_error_codes/error_codes/E0324.md b/compiler/rustc_error_codes/src/error_codes/E0324.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0324.md rename to compiler/rustc_error_codes/src/error_codes/E0324.md diff --git a/src/librustc_error_codes/error_codes/E0325.md b/compiler/rustc_error_codes/src/error_codes/E0325.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0325.md rename to compiler/rustc_error_codes/src/error_codes/E0325.md diff --git a/src/librustc_error_codes/error_codes/E0326.md b/compiler/rustc_error_codes/src/error_codes/E0326.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0326.md rename to compiler/rustc_error_codes/src/error_codes/E0326.md diff --git a/src/librustc_error_codes/error_codes/E0328.md b/compiler/rustc_error_codes/src/error_codes/E0328.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0328.md rename to compiler/rustc_error_codes/src/error_codes/E0328.md diff --git a/src/librustc_error_codes/error_codes/E0329.md b/compiler/rustc_error_codes/src/error_codes/E0329.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0329.md rename to compiler/rustc_error_codes/src/error_codes/E0329.md diff --git a/src/librustc_error_codes/error_codes/E0364.md b/compiler/rustc_error_codes/src/error_codes/E0364.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0364.md rename to compiler/rustc_error_codes/src/error_codes/E0364.md diff --git a/src/librustc_error_codes/error_codes/E0365.md b/compiler/rustc_error_codes/src/error_codes/E0365.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0365.md rename to compiler/rustc_error_codes/src/error_codes/E0365.md diff --git a/src/librustc_error_codes/error_codes/E0366.md b/compiler/rustc_error_codes/src/error_codes/E0366.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0366.md rename to compiler/rustc_error_codes/src/error_codes/E0366.md diff --git a/src/librustc_error_codes/error_codes/E0367.md b/compiler/rustc_error_codes/src/error_codes/E0367.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0367.md rename to compiler/rustc_error_codes/src/error_codes/E0367.md diff --git a/src/librustc_error_codes/error_codes/E0368.md b/compiler/rustc_error_codes/src/error_codes/E0368.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0368.md rename to compiler/rustc_error_codes/src/error_codes/E0368.md diff --git a/src/librustc_error_codes/error_codes/E0369.md b/compiler/rustc_error_codes/src/error_codes/E0369.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0369.md rename to compiler/rustc_error_codes/src/error_codes/E0369.md diff --git a/src/librustc_error_codes/error_codes/E0370.md b/compiler/rustc_error_codes/src/error_codes/E0370.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0370.md rename to compiler/rustc_error_codes/src/error_codes/E0370.md diff --git a/src/librustc_error_codes/error_codes/E0371.md b/compiler/rustc_error_codes/src/error_codes/E0371.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0371.md rename to compiler/rustc_error_codes/src/error_codes/E0371.md diff --git a/src/librustc_error_codes/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0373.md rename to compiler/rustc_error_codes/src/error_codes/E0373.md diff --git a/src/librustc_error_codes/error_codes/E0374.md b/compiler/rustc_error_codes/src/error_codes/E0374.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0374.md rename to compiler/rustc_error_codes/src/error_codes/E0374.md diff --git a/src/librustc_error_codes/error_codes/E0375.md b/compiler/rustc_error_codes/src/error_codes/E0375.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0375.md rename to compiler/rustc_error_codes/src/error_codes/E0375.md diff --git a/src/librustc_error_codes/error_codes/E0376.md b/compiler/rustc_error_codes/src/error_codes/E0376.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0376.md rename to compiler/rustc_error_codes/src/error_codes/E0376.md diff --git a/src/librustc_error_codes/error_codes/E0378.md b/compiler/rustc_error_codes/src/error_codes/E0378.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0378.md rename to compiler/rustc_error_codes/src/error_codes/E0378.md diff --git a/src/librustc_error_codes/error_codes/E0379.md b/compiler/rustc_error_codes/src/error_codes/E0379.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0379.md rename to compiler/rustc_error_codes/src/error_codes/E0379.md diff --git a/src/librustc_error_codes/error_codes/E0380.md b/compiler/rustc_error_codes/src/error_codes/E0380.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0380.md rename to compiler/rustc_error_codes/src/error_codes/E0380.md diff --git a/src/librustc_error_codes/error_codes/E0381.md b/compiler/rustc_error_codes/src/error_codes/E0381.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0381.md rename to compiler/rustc_error_codes/src/error_codes/E0381.md diff --git a/src/librustc_error_codes/error_codes/E0382.md b/compiler/rustc_error_codes/src/error_codes/E0382.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0382.md rename to compiler/rustc_error_codes/src/error_codes/E0382.md diff --git a/src/librustc_error_codes/error_codes/E0383.md b/compiler/rustc_error_codes/src/error_codes/E0383.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0383.md rename to compiler/rustc_error_codes/src/error_codes/E0383.md diff --git a/src/librustc_error_codes/error_codes/E0384.md b/compiler/rustc_error_codes/src/error_codes/E0384.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0384.md rename to compiler/rustc_error_codes/src/error_codes/E0384.md diff --git a/src/librustc_error_codes/error_codes/E0386.md b/compiler/rustc_error_codes/src/error_codes/E0386.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0386.md rename to compiler/rustc_error_codes/src/error_codes/E0386.md diff --git a/src/librustc_error_codes/error_codes/E0387.md b/compiler/rustc_error_codes/src/error_codes/E0387.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0387.md rename to compiler/rustc_error_codes/src/error_codes/E0387.md diff --git a/src/librustc_error_codes/error_codes/E0388.md b/compiler/rustc_error_codes/src/error_codes/E0388.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0388.md rename to compiler/rustc_error_codes/src/error_codes/E0388.md diff --git a/src/librustc_error_codes/error_codes/E0389.md b/compiler/rustc_error_codes/src/error_codes/E0389.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0389.md rename to compiler/rustc_error_codes/src/error_codes/E0389.md diff --git a/src/librustc_error_codes/error_codes/E0390.md b/compiler/rustc_error_codes/src/error_codes/E0390.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0390.md rename to compiler/rustc_error_codes/src/error_codes/E0390.md diff --git a/src/librustc_error_codes/error_codes/E0391.md b/compiler/rustc_error_codes/src/error_codes/E0391.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0391.md rename to compiler/rustc_error_codes/src/error_codes/E0391.md diff --git a/src/librustc_error_codes/error_codes/E0392.md b/compiler/rustc_error_codes/src/error_codes/E0392.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0392.md rename to compiler/rustc_error_codes/src/error_codes/E0392.md diff --git a/src/librustc_error_codes/error_codes/E0393.md b/compiler/rustc_error_codes/src/error_codes/E0393.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0393.md rename to compiler/rustc_error_codes/src/error_codes/E0393.md diff --git a/src/librustc_error_codes/error_codes/E0398.md b/compiler/rustc_error_codes/src/error_codes/E0398.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0398.md rename to compiler/rustc_error_codes/src/error_codes/E0398.md diff --git a/src/librustc_error_codes/error_codes/E0399.md b/compiler/rustc_error_codes/src/error_codes/E0399.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0399.md rename to compiler/rustc_error_codes/src/error_codes/E0399.md diff --git a/src/librustc_error_codes/error_codes/E0401.md b/compiler/rustc_error_codes/src/error_codes/E0401.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0401.md rename to compiler/rustc_error_codes/src/error_codes/E0401.md diff --git a/src/librustc_error_codes/error_codes/E0403.md b/compiler/rustc_error_codes/src/error_codes/E0403.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0403.md rename to compiler/rustc_error_codes/src/error_codes/E0403.md diff --git a/src/librustc_error_codes/error_codes/E0404.md b/compiler/rustc_error_codes/src/error_codes/E0404.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0404.md rename to compiler/rustc_error_codes/src/error_codes/E0404.md diff --git a/src/librustc_error_codes/error_codes/E0405.md b/compiler/rustc_error_codes/src/error_codes/E0405.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0405.md rename to compiler/rustc_error_codes/src/error_codes/E0405.md diff --git a/src/librustc_error_codes/error_codes/E0407.md b/compiler/rustc_error_codes/src/error_codes/E0407.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0407.md rename to compiler/rustc_error_codes/src/error_codes/E0407.md diff --git a/src/librustc_error_codes/error_codes/E0408.md b/compiler/rustc_error_codes/src/error_codes/E0408.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0408.md rename to compiler/rustc_error_codes/src/error_codes/E0408.md diff --git a/src/librustc_error_codes/error_codes/E0409.md b/compiler/rustc_error_codes/src/error_codes/E0409.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0409.md rename to compiler/rustc_error_codes/src/error_codes/E0409.md diff --git a/src/librustc_error_codes/error_codes/E0411.md b/compiler/rustc_error_codes/src/error_codes/E0411.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0411.md rename to compiler/rustc_error_codes/src/error_codes/E0411.md diff --git a/src/librustc_error_codes/error_codes/E0412.md b/compiler/rustc_error_codes/src/error_codes/E0412.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0412.md rename to compiler/rustc_error_codes/src/error_codes/E0412.md diff --git a/src/librustc_error_codes/error_codes/E0415.md b/compiler/rustc_error_codes/src/error_codes/E0415.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0415.md rename to compiler/rustc_error_codes/src/error_codes/E0415.md diff --git a/src/librustc_error_codes/error_codes/E0416.md b/compiler/rustc_error_codes/src/error_codes/E0416.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0416.md rename to compiler/rustc_error_codes/src/error_codes/E0416.md diff --git a/src/librustc_error_codes/error_codes/E0422.md b/compiler/rustc_error_codes/src/error_codes/E0422.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0422.md rename to compiler/rustc_error_codes/src/error_codes/E0422.md diff --git a/src/librustc_error_codes/error_codes/E0423.md b/compiler/rustc_error_codes/src/error_codes/E0423.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0423.md rename to compiler/rustc_error_codes/src/error_codes/E0423.md diff --git a/src/librustc_error_codes/error_codes/E0424.md b/compiler/rustc_error_codes/src/error_codes/E0424.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0424.md rename to compiler/rustc_error_codes/src/error_codes/E0424.md diff --git a/src/librustc_error_codes/error_codes/E0425.md b/compiler/rustc_error_codes/src/error_codes/E0425.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0425.md rename to compiler/rustc_error_codes/src/error_codes/E0425.md diff --git a/src/librustc_error_codes/error_codes/E0426.md b/compiler/rustc_error_codes/src/error_codes/E0426.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0426.md rename to compiler/rustc_error_codes/src/error_codes/E0426.md diff --git a/src/librustc_error_codes/error_codes/E0428.md b/compiler/rustc_error_codes/src/error_codes/E0428.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0428.md rename to compiler/rustc_error_codes/src/error_codes/E0428.md diff --git a/src/librustc_error_codes/error_codes/E0429.md b/compiler/rustc_error_codes/src/error_codes/E0429.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0429.md rename to compiler/rustc_error_codes/src/error_codes/E0429.md diff --git a/src/librustc_error_codes/error_codes/E0430.md b/compiler/rustc_error_codes/src/error_codes/E0430.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0430.md rename to compiler/rustc_error_codes/src/error_codes/E0430.md diff --git a/src/librustc_error_codes/error_codes/E0431.md b/compiler/rustc_error_codes/src/error_codes/E0431.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0431.md rename to compiler/rustc_error_codes/src/error_codes/E0431.md diff --git a/src/librustc_error_codes/error_codes/E0432.md b/compiler/rustc_error_codes/src/error_codes/E0432.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0432.md rename to compiler/rustc_error_codes/src/error_codes/E0432.md diff --git a/compiler/rustc_error_codes/src/error_codes/E0433.md b/compiler/rustc_error_codes/src/error_codes/E0433.md new file mode 100644 index 0000000000..5a64c13c9a --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0433.md @@ -0,0 +1,27 @@ +An undeclared crate, module, or type was used. + +Erroneous code example: + +```compile_fail,E0433 +let map = HashMap::new(); +// error: failed to resolve: use of undeclared type `HashMap` +``` + +Please verify you didn't misspell the type/module's name or that you didn't +forget to import it: + +``` +use std::collections::HashMap; // HashMap has been imported. +let map: HashMap = HashMap::new(); // So it can be used! +``` + +If you've expected to use a crate name: + +```compile_fail +use ferris_wheel::BigO; +// error: failed to resolve: use of undeclared crate or module `ferris_wheel` +``` + +Make sure the crate has been added as a dependency in `Cargo.toml`. + +To use a module from your current crate, add the `crate::` prefix to the path. diff --git a/src/librustc_error_codes/error_codes/E0434.md b/compiler/rustc_error_codes/src/error_codes/E0434.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0434.md rename to compiler/rustc_error_codes/src/error_codes/E0434.md diff --git a/src/librustc_error_codes/error_codes/E0435.md b/compiler/rustc_error_codes/src/error_codes/E0435.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0435.md rename to compiler/rustc_error_codes/src/error_codes/E0435.md diff --git a/src/librustc_error_codes/error_codes/E0436.md b/compiler/rustc_error_codes/src/error_codes/E0436.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0436.md rename to compiler/rustc_error_codes/src/error_codes/E0436.md diff --git a/src/librustc_error_codes/error_codes/E0437.md b/compiler/rustc_error_codes/src/error_codes/E0437.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0437.md rename to compiler/rustc_error_codes/src/error_codes/E0437.md diff --git a/src/librustc_error_codes/error_codes/E0438.md b/compiler/rustc_error_codes/src/error_codes/E0438.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0438.md rename to compiler/rustc_error_codes/src/error_codes/E0438.md diff --git a/src/librustc_error_codes/error_codes/E0439.md b/compiler/rustc_error_codes/src/error_codes/E0439.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0439.md rename to compiler/rustc_error_codes/src/error_codes/E0439.md diff --git a/src/librustc_error_codes/error_codes/E0445.md b/compiler/rustc_error_codes/src/error_codes/E0445.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0445.md rename to compiler/rustc_error_codes/src/error_codes/E0445.md diff --git a/src/librustc_error_codes/error_codes/E0446.md b/compiler/rustc_error_codes/src/error_codes/E0446.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0446.md rename to compiler/rustc_error_codes/src/error_codes/E0446.md diff --git a/src/librustc_error_codes/error_codes/E0447.md b/compiler/rustc_error_codes/src/error_codes/E0447.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0447.md rename to compiler/rustc_error_codes/src/error_codes/E0447.md diff --git a/src/librustc_error_codes/error_codes/E0448.md b/compiler/rustc_error_codes/src/error_codes/E0448.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0448.md rename to compiler/rustc_error_codes/src/error_codes/E0448.md diff --git a/src/librustc_error_codes/error_codes/E0449.md b/compiler/rustc_error_codes/src/error_codes/E0449.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0449.md rename to compiler/rustc_error_codes/src/error_codes/E0449.md diff --git a/src/librustc_error_codes/error_codes/E0451.md b/compiler/rustc_error_codes/src/error_codes/E0451.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0451.md rename to compiler/rustc_error_codes/src/error_codes/E0451.md diff --git a/src/librustc_error_codes/error_codes/E0452.md b/compiler/rustc_error_codes/src/error_codes/E0452.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0452.md rename to compiler/rustc_error_codes/src/error_codes/E0452.md diff --git a/src/librustc_error_codes/error_codes/E0453.md b/compiler/rustc_error_codes/src/error_codes/E0453.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0453.md rename to compiler/rustc_error_codes/src/error_codes/E0453.md diff --git a/src/librustc_error_codes/error_codes/E0454.md b/compiler/rustc_error_codes/src/error_codes/E0454.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0454.md rename to compiler/rustc_error_codes/src/error_codes/E0454.md diff --git a/src/librustc_error_codes/error_codes/E0455.md b/compiler/rustc_error_codes/src/error_codes/E0455.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0455.md rename to compiler/rustc_error_codes/src/error_codes/E0455.md diff --git a/src/librustc_error_codes/error_codes/E0458.md b/compiler/rustc_error_codes/src/error_codes/E0458.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0458.md rename to compiler/rustc_error_codes/src/error_codes/E0458.md diff --git a/src/librustc_error_codes/error_codes/E0459.md b/compiler/rustc_error_codes/src/error_codes/E0459.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0459.md rename to compiler/rustc_error_codes/src/error_codes/E0459.md diff --git a/src/librustc_error_codes/error_codes/E0463.md b/compiler/rustc_error_codes/src/error_codes/E0463.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0463.md rename to compiler/rustc_error_codes/src/error_codes/E0463.md diff --git a/src/librustc_error_codes/error_codes/E0466.md b/compiler/rustc_error_codes/src/error_codes/E0466.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0466.md rename to compiler/rustc_error_codes/src/error_codes/E0466.md diff --git a/src/librustc_error_codes/error_codes/E0468.md b/compiler/rustc_error_codes/src/error_codes/E0468.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0468.md rename to compiler/rustc_error_codes/src/error_codes/E0468.md diff --git a/src/librustc_error_codes/error_codes/E0469.md b/compiler/rustc_error_codes/src/error_codes/E0469.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0469.md rename to compiler/rustc_error_codes/src/error_codes/E0469.md diff --git a/src/librustc_error_codes/error_codes/E0477.md b/compiler/rustc_error_codes/src/error_codes/E0477.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0477.md rename to compiler/rustc_error_codes/src/error_codes/E0477.md diff --git a/src/librustc_error_codes/error_codes/E0478.md b/compiler/rustc_error_codes/src/error_codes/E0478.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0478.md rename to compiler/rustc_error_codes/src/error_codes/E0478.md diff --git a/src/librustc_error_codes/error_codes/E0491.md b/compiler/rustc_error_codes/src/error_codes/E0491.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0491.md rename to compiler/rustc_error_codes/src/error_codes/E0491.md diff --git a/src/librustc_error_codes/error_codes/E0492.md b/compiler/rustc_error_codes/src/error_codes/E0492.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0492.md rename to compiler/rustc_error_codes/src/error_codes/E0492.md diff --git a/src/librustc_error_codes/error_codes/E0493.md b/compiler/rustc_error_codes/src/error_codes/E0493.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0493.md rename to compiler/rustc_error_codes/src/error_codes/E0493.md diff --git a/src/librustc_error_codes/error_codes/E0495.md b/compiler/rustc_error_codes/src/error_codes/E0495.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0495.md rename to compiler/rustc_error_codes/src/error_codes/E0495.md diff --git a/src/librustc_error_codes/error_codes/E0496.md b/compiler/rustc_error_codes/src/error_codes/E0496.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0496.md rename to compiler/rustc_error_codes/src/error_codes/E0496.md diff --git a/src/librustc_error_codes/error_codes/E0497.md b/compiler/rustc_error_codes/src/error_codes/E0497.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0497.md rename to compiler/rustc_error_codes/src/error_codes/E0497.md diff --git a/src/librustc_error_codes/error_codes/E0499.md b/compiler/rustc_error_codes/src/error_codes/E0499.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0499.md rename to compiler/rustc_error_codes/src/error_codes/E0499.md diff --git a/src/librustc_error_codes/error_codes/E0500.md b/compiler/rustc_error_codes/src/error_codes/E0500.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0500.md rename to compiler/rustc_error_codes/src/error_codes/E0500.md diff --git a/src/librustc_error_codes/error_codes/E0501.md b/compiler/rustc_error_codes/src/error_codes/E0501.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0501.md rename to compiler/rustc_error_codes/src/error_codes/E0501.md diff --git a/src/librustc_error_codes/error_codes/E0502.md b/compiler/rustc_error_codes/src/error_codes/E0502.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0502.md rename to compiler/rustc_error_codes/src/error_codes/E0502.md diff --git a/src/librustc_error_codes/error_codes/E0503.md b/compiler/rustc_error_codes/src/error_codes/E0503.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0503.md rename to compiler/rustc_error_codes/src/error_codes/E0503.md diff --git a/src/librustc_error_codes/error_codes/E0504.md b/compiler/rustc_error_codes/src/error_codes/E0504.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0504.md rename to compiler/rustc_error_codes/src/error_codes/E0504.md diff --git a/src/librustc_error_codes/error_codes/E0505.md b/compiler/rustc_error_codes/src/error_codes/E0505.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0505.md rename to compiler/rustc_error_codes/src/error_codes/E0505.md diff --git a/src/librustc_error_codes/error_codes/E0506.md b/compiler/rustc_error_codes/src/error_codes/E0506.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0506.md rename to compiler/rustc_error_codes/src/error_codes/E0506.md diff --git a/src/librustc_error_codes/error_codes/E0507.md b/compiler/rustc_error_codes/src/error_codes/E0507.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0507.md rename to compiler/rustc_error_codes/src/error_codes/E0507.md diff --git a/src/librustc_error_codes/error_codes/E0508.md b/compiler/rustc_error_codes/src/error_codes/E0508.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0508.md rename to compiler/rustc_error_codes/src/error_codes/E0508.md diff --git a/src/librustc_error_codes/error_codes/E0509.md b/compiler/rustc_error_codes/src/error_codes/E0509.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0509.md rename to compiler/rustc_error_codes/src/error_codes/E0509.md diff --git a/src/librustc_error_codes/error_codes/E0510.md b/compiler/rustc_error_codes/src/error_codes/E0510.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0510.md rename to compiler/rustc_error_codes/src/error_codes/E0510.md diff --git a/src/librustc_error_codes/error_codes/E0511.md b/compiler/rustc_error_codes/src/error_codes/E0511.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0511.md rename to compiler/rustc_error_codes/src/error_codes/E0511.md diff --git a/src/librustc_error_codes/error_codes/E0512.md b/compiler/rustc_error_codes/src/error_codes/E0512.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0512.md rename to compiler/rustc_error_codes/src/error_codes/E0512.md diff --git a/src/librustc_error_codes/error_codes/E0515.md b/compiler/rustc_error_codes/src/error_codes/E0515.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0515.md rename to compiler/rustc_error_codes/src/error_codes/E0515.md diff --git a/src/librustc_error_codes/error_codes/E0516.md b/compiler/rustc_error_codes/src/error_codes/E0516.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0516.md rename to compiler/rustc_error_codes/src/error_codes/E0516.md diff --git a/src/librustc_error_codes/error_codes/E0517.md b/compiler/rustc_error_codes/src/error_codes/E0517.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0517.md rename to compiler/rustc_error_codes/src/error_codes/E0517.md diff --git a/src/librustc_error_codes/error_codes/E0518.md b/compiler/rustc_error_codes/src/error_codes/E0518.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0518.md rename to compiler/rustc_error_codes/src/error_codes/E0518.md diff --git a/src/librustc_error_codes/error_codes/E0520.md b/compiler/rustc_error_codes/src/error_codes/E0520.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0520.md rename to compiler/rustc_error_codes/src/error_codes/E0520.md diff --git a/src/librustc_error_codes/error_codes/E0522.md b/compiler/rustc_error_codes/src/error_codes/E0522.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0522.md rename to compiler/rustc_error_codes/src/error_codes/E0522.md diff --git a/src/librustc_error_codes/error_codes/E0524.md b/compiler/rustc_error_codes/src/error_codes/E0524.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0524.md rename to compiler/rustc_error_codes/src/error_codes/E0524.md diff --git a/src/librustc_error_codes/error_codes/E0525.md b/compiler/rustc_error_codes/src/error_codes/E0525.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0525.md rename to compiler/rustc_error_codes/src/error_codes/E0525.md diff --git a/src/librustc_error_codes/error_codes/E0527.md b/compiler/rustc_error_codes/src/error_codes/E0527.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0527.md rename to compiler/rustc_error_codes/src/error_codes/E0527.md diff --git a/src/librustc_error_codes/error_codes/E0528.md b/compiler/rustc_error_codes/src/error_codes/E0528.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0528.md rename to compiler/rustc_error_codes/src/error_codes/E0528.md diff --git a/src/librustc_error_codes/error_codes/E0529.md b/compiler/rustc_error_codes/src/error_codes/E0529.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0529.md rename to compiler/rustc_error_codes/src/error_codes/E0529.md diff --git a/src/librustc_error_codes/error_codes/E0530.md b/compiler/rustc_error_codes/src/error_codes/E0530.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0530.md rename to compiler/rustc_error_codes/src/error_codes/E0530.md diff --git a/src/librustc_error_codes/error_codes/E0531.md b/compiler/rustc_error_codes/src/error_codes/E0531.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0531.md rename to compiler/rustc_error_codes/src/error_codes/E0531.md diff --git a/src/librustc_error_codes/error_codes/E0532.md b/compiler/rustc_error_codes/src/error_codes/E0532.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0532.md rename to compiler/rustc_error_codes/src/error_codes/E0532.md diff --git a/src/librustc_error_codes/error_codes/E0533.md b/compiler/rustc_error_codes/src/error_codes/E0533.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0533.md rename to compiler/rustc_error_codes/src/error_codes/E0533.md diff --git a/src/librustc_error_codes/error_codes/E0534.md b/compiler/rustc_error_codes/src/error_codes/E0534.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0534.md rename to compiler/rustc_error_codes/src/error_codes/E0534.md diff --git a/src/librustc_error_codes/error_codes/E0535.md b/compiler/rustc_error_codes/src/error_codes/E0535.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0535.md rename to compiler/rustc_error_codes/src/error_codes/E0535.md diff --git a/src/librustc_error_codes/error_codes/E0536.md b/compiler/rustc_error_codes/src/error_codes/E0536.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0536.md rename to compiler/rustc_error_codes/src/error_codes/E0536.md diff --git a/src/librustc_error_codes/error_codes/E0537.md b/compiler/rustc_error_codes/src/error_codes/E0537.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0537.md rename to compiler/rustc_error_codes/src/error_codes/E0537.md diff --git a/src/librustc_error_codes/error_codes/E0538.md b/compiler/rustc_error_codes/src/error_codes/E0538.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0538.md rename to compiler/rustc_error_codes/src/error_codes/E0538.md diff --git a/src/librustc_error_codes/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0539.md rename to compiler/rustc_error_codes/src/error_codes/E0539.md diff --git a/src/librustc_error_codes/error_codes/E0541.md b/compiler/rustc_error_codes/src/error_codes/E0541.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0541.md rename to compiler/rustc_error_codes/src/error_codes/E0541.md diff --git a/src/librustc_error_codes/error_codes/E0550.md b/compiler/rustc_error_codes/src/error_codes/E0550.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0550.md rename to compiler/rustc_error_codes/src/error_codes/E0550.md diff --git a/src/librustc_error_codes/error_codes/E0551.md b/compiler/rustc_error_codes/src/error_codes/E0551.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0551.md rename to compiler/rustc_error_codes/src/error_codes/E0551.md diff --git a/src/librustc_error_codes/error_codes/E0552.md b/compiler/rustc_error_codes/src/error_codes/E0552.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0552.md rename to compiler/rustc_error_codes/src/error_codes/E0552.md diff --git a/src/librustc_error_codes/error_codes/E0554.md b/compiler/rustc_error_codes/src/error_codes/E0554.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0554.md rename to compiler/rustc_error_codes/src/error_codes/E0554.md diff --git a/src/librustc_error_codes/error_codes/E0556.md b/compiler/rustc_error_codes/src/error_codes/E0556.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0556.md rename to compiler/rustc_error_codes/src/error_codes/E0556.md diff --git a/src/librustc_error_codes/error_codes/E0557.md b/compiler/rustc_error_codes/src/error_codes/E0557.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0557.md rename to compiler/rustc_error_codes/src/error_codes/E0557.md diff --git a/src/librustc_error_codes/error_codes/E0559.md b/compiler/rustc_error_codes/src/error_codes/E0559.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0559.md rename to compiler/rustc_error_codes/src/error_codes/E0559.md diff --git a/src/librustc_error_codes/error_codes/E0560.md b/compiler/rustc_error_codes/src/error_codes/E0560.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0560.md rename to compiler/rustc_error_codes/src/error_codes/E0560.md diff --git a/src/librustc_error_codes/error_codes/E0561.md b/compiler/rustc_error_codes/src/error_codes/E0561.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0561.md rename to compiler/rustc_error_codes/src/error_codes/E0561.md diff --git a/src/librustc_error_codes/error_codes/E0562.md b/compiler/rustc_error_codes/src/error_codes/E0562.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0562.md rename to compiler/rustc_error_codes/src/error_codes/E0562.md diff --git a/src/librustc_error_codes/error_codes/E0565.md b/compiler/rustc_error_codes/src/error_codes/E0565.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0565.md rename to compiler/rustc_error_codes/src/error_codes/E0565.md diff --git a/src/librustc_error_codes/error_codes/E0566.md b/compiler/rustc_error_codes/src/error_codes/E0566.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0566.md rename to compiler/rustc_error_codes/src/error_codes/E0566.md diff --git a/src/librustc_error_codes/error_codes/E0567.md b/compiler/rustc_error_codes/src/error_codes/E0567.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0567.md rename to compiler/rustc_error_codes/src/error_codes/E0567.md diff --git a/src/librustc_error_codes/error_codes/E0568.md b/compiler/rustc_error_codes/src/error_codes/E0568.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0568.md rename to compiler/rustc_error_codes/src/error_codes/E0568.md diff --git a/src/librustc_error_codes/error_codes/E0569.md b/compiler/rustc_error_codes/src/error_codes/E0569.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0569.md rename to compiler/rustc_error_codes/src/error_codes/E0569.md diff --git a/src/librustc_error_codes/error_codes/E0570.md b/compiler/rustc_error_codes/src/error_codes/E0570.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0570.md rename to compiler/rustc_error_codes/src/error_codes/E0570.md diff --git a/src/librustc_error_codes/error_codes/E0571.md b/compiler/rustc_error_codes/src/error_codes/E0571.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0571.md rename to compiler/rustc_error_codes/src/error_codes/E0571.md diff --git a/src/librustc_error_codes/error_codes/E0572.md b/compiler/rustc_error_codes/src/error_codes/E0572.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0572.md rename to compiler/rustc_error_codes/src/error_codes/E0572.md diff --git a/src/librustc_error_codes/error_codes/E0573.md b/compiler/rustc_error_codes/src/error_codes/E0573.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0573.md rename to compiler/rustc_error_codes/src/error_codes/E0573.md diff --git a/src/librustc_error_codes/error_codes/E0574.md b/compiler/rustc_error_codes/src/error_codes/E0574.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0574.md rename to compiler/rustc_error_codes/src/error_codes/E0574.md diff --git a/src/librustc_error_codes/error_codes/E0575.md b/compiler/rustc_error_codes/src/error_codes/E0575.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0575.md rename to compiler/rustc_error_codes/src/error_codes/E0575.md diff --git a/src/librustc_error_codes/error_codes/E0576.md b/compiler/rustc_error_codes/src/error_codes/E0576.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0576.md rename to compiler/rustc_error_codes/src/error_codes/E0576.md diff --git a/src/librustc_error_codes/error_codes/E0577.md b/compiler/rustc_error_codes/src/error_codes/E0577.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0577.md rename to compiler/rustc_error_codes/src/error_codes/E0577.md diff --git a/src/librustc_error_codes/error_codes/E0578.md b/compiler/rustc_error_codes/src/error_codes/E0578.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0578.md rename to compiler/rustc_error_codes/src/error_codes/E0578.md diff --git a/src/librustc_error_codes/error_codes/E0579.md b/compiler/rustc_error_codes/src/error_codes/E0579.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0579.md rename to compiler/rustc_error_codes/src/error_codes/E0579.md diff --git a/src/librustc_error_codes/error_codes/E0580.md b/compiler/rustc_error_codes/src/error_codes/E0580.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0580.md rename to compiler/rustc_error_codes/src/error_codes/E0580.md diff --git a/src/librustc_error_codes/error_codes/E0581.md b/compiler/rustc_error_codes/src/error_codes/E0581.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0581.md rename to compiler/rustc_error_codes/src/error_codes/E0581.md diff --git a/src/librustc_error_codes/error_codes/E0582.md b/compiler/rustc_error_codes/src/error_codes/E0582.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0582.md rename to compiler/rustc_error_codes/src/error_codes/E0582.md diff --git a/src/librustc_error_codes/error_codes/E0583.md b/compiler/rustc_error_codes/src/error_codes/E0583.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0583.md rename to compiler/rustc_error_codes/src/error_codes/E0583.md diff --git a/src/librustc_error_codes/error_codes/E0584.md b/compiler/rustc_error_codes/src/error_codes/E0584.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0584.md rename to compiler/rustc_error_codes/src/error_codes/E0584.md diff --git a/src/librustc_error_codes/error_codes/E0585.md b/compiler/rustc_error_codes/src/error_codes/E0585.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0585.md rename to compiler/rustc_error_codes/src/error_codes/E0585.md diff --git a/src/librustc_error_codes/error_codes/E0586.md b/compiler/rustc_error_codes/src/error_codes/E0586.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0586.md rename to compiler/rustc_error_codes/src/error_codes/E0586.md diff --git a/src/librustc_error_codes/error_codes/E0587.md b/compiler/rustc_error_codes/src/error_codes/E0587.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0587.md rename to compiler/rustc_error_codes/src/error_codes/E0587.md diff --git a/src/librustc_error_codes/error_codes/E0588.md b/compiler/rustc_error_codes/src/error_codes/E0588.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0588.md rename to compiler/rustc_error_codes/src/error_codes/E0588.md diff --git a/src/librustc_error_codes/error_codes/E0589.md b/compiler/rustc_error_codes/src/error_codes/E0589.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0589.md rename to compiler/rustc_error_codes/src/error_codes/E0589.md diff --git a/src/librustc_error_codes/error_codes/E0590.md b/compiler/rustc_error_codes/src/error_codes/E0590.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0590.md rename to compiler/rustc_error_codes/src/error_codes/E0590.md diff --git a/src/librustc_error_codes/error_codes/E0591.md b/compiler/rustc_error_codes/src/error_codes/E0591.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0591.md rename to compiler/rustc_error_codes/src/error_codes/E0591.md diff --git a/src/librustc_error_codes/error_codes/E0592.md b/compiler/rustc_error_codes/src/error_codes/E0592.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0592.md rename to compiler/rustc_error_codes/src/error_codes/E0592.md diff --git a/src/librustc_error_codes/error_codes/E0593.md b/compiler/rustc_error_codes/src/error_codes/E0593.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0593.md rename to compiler/rustc_error_codes/src/error_codes/E0593.md diff --git a/src/librustc_error_codes/error_codes/E0594.md b/compiler/rustc_error_codes/src/error_codes/E0594.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0594.md rename to compiler/rustc_error_codes/src/error_codes/E0594.md diff --git a/src/librustc_error_codes/error_codes/E0595.md b/compiler/rustc_error_codes/src/error_codes/E0595.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0595.md rename to compiler/rustc_error_codes/src/error_codes/E0595.md diff --git a/src/librustc_error_codes/error_codes/E0596.md b/compiler/rustc_error_codes/src/error_codes/E0596.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0596.md rename to compiler/rustc_error_codes/src/error_codes/E0596.md diff --git a/src/librustc_error_codes/error_codes/E0597.md b/compiler/rustc_error_codes/src/error_codes/E0597.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0597.md rename to compiler/rustc_error_codes/src/error_codes/E0597.md diff --git a/src/librustc_error_codes/error_codes/E0599.md b/compiler/rustc_error_codes/src/error_codes/E0599.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0599.md rename to compiler/rustc_error_codes/src/error_codes/E0599.md diff --git a/src/librustc_error_codes/error_codes/E0600.md b/compiler/rustc_error_codes/src/error_codes/E0600.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0600.md rename to compiler/rustc_error_codes/src/error_codes/E0600.md diff --git a/src/librustc_error_codes/error_codes/E0601.md b/compiler/rustc_error_codes/src/error_codes/E0601.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0601.md rename to compiler/rustc_error_codes/src/error_codes/E0601.md diff --git a/src/librustc_error_codes/error_codes/E0602.md b/compiler/rustc_error_codes/src/error_codes/E0602.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0602.md rename to compiler/rustc_error_codes/src/error_codes/E0602.md diff --git a/src/librustc_error_codes/error_codes/E0603.md b/compiler/rustc_error_codes/src/error_codes/E0603.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0603.md rename to compiler/rustc_error_codes/src/error_codes/E0603.md diff --git a/src/librustc_error_codes/error_codes/E0604.md b/compiler/rustc_error_codes/src/error_codes/E0604.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0604.md rename to compiler/rustc_error_codes/src/error_codes/E0604.md diff --git a/src/librustc_error_codes/error_codes/E0605.md b/compiler/rustc_error_codes/src/error_codes/E0605.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0605.md rename to compiler/rustc_error_codes/src/error_codes/E0605.md diff --git a/src/librustc_error_codes/error_codes/E0606.md b/compiler/rustc_error_codes/src/error_codes/E0606.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0606.md rename to compiler/rustc_error_codes/src/error_codes/E0606.md diff --git a/src/librustc_error_codes/error_codes/E0607.md b/compiler/rustc_error_codes/src/error_codes/E0607.md similarity index 55% rename from src/librustc_error_codes/error_codes/E0607.md rename to compiler/rustc_error_codes/src/error_codes/E0607.md index ea6e10105b..0545246929 100644 --- a/src/librustc_error_codes/error_codes/E0607.md +++ b/compiler/rustc_error_codes/src/error_codes/E0607.md @@ -12,15 +12,15 @@ First: what are thin and fat pointers? Thin pointers are "simple" pointers: they are purely a reference to a memory address. -Fat pointers are pointers referencing Dynamically Sized Types (also called DST). -DST don't have a statically known size, therefore they can only exist behind -some kind of pointers that contain additional information. Slices and trait -objects are DSTs. In the case of slices, the additional information the fat -pointer holds is their size. +Fat pointers are pointers referencing Dynamically Sized Types (also called +DSTs). DSTs don't have a statically known size, therefore they can only exist +behind some kind of pointer that contains additional information. For example, +slices and trait objects are DSTs. In the case of slices, the additional +information the fat pointer holds is their size. To fix this error, don't try to cast directly between thin and fat pointers. -For more information about casts, take a look at the Type cast section in -[The Reference Book][1]. +For more information about type casts, take a look at the section of the +[The Rust Reference][1] on type cast expressions. [1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions diff --git a/src/librustc_error_codes/error_codes/E0608.md b/compiler/rustc_error_codes/src/error_codes/E0608.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0608.md rename to compiler/rustc_error_codes/src/error_codes/E0608.md diff --git a/src/librustc_error_codes/error_codes/E0609.md b/compiler/rustc_error_codes/src/error_codes/E0609.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0609.md rename to compiler/rustc_error_codes/src/error_codes/E0609.md diff --git a/src/librustc_error_codes/error_codes/E0610.md b/compiler/rustc_error_codes/src/error_codes/E0610.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0610.md rename to compiler/rustc_error_codes/src/error_codes/E0610.md diff --git a/src/librustc_error_codes/error_codes/E0614.md b/compiler/rustc_error_codes/src/error_codes/E0614.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0614.md rename to compiler/rustc_error_codes/src/error_codes/E0614.md diff --git a/src/librustc_error_codes/error_codes/E0615.md b/compiler/rustc_error_codes/src/error_codes/E0615.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0615.md rename to compiler/rustc_error_codes/src/error_codes/E0615.md diff --git a/src/librustc_error_codes/error_codes/E0616.md b/compiler/rustc_error_codes/src/error_codes/E0616.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0616.md rename to compiler/rustc_error_codes/src/error_codes/E0616.md diff --git a/src/librustc_error_codes/error_codes/E0617.md b/compiler/rustc_error_codes/src/error_codes/E0617.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0617.md rename to compiler/rustc_error_codes/src/error_codes/E0617.md diff --git a/src/librustc_error_codes/error_codes/E0618.md b/compiler/rustc_error_codes/src/error_codes/E0618.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0618.md rename to compiler/rustc_error_codes/src/error_codes/E0618.md diff --git a/src/librustc_error_codes/error_codes/E0619.md b/compiler/rustc_error_codes/src/error_codes/E0619.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0619.md rename to compiler/rustc_error_codes/src/error_codes/E0619.md diff --git a/src/librustc_error_codes/error_codes/E0620.md b/compiler/rustc_error_codes/src/error_codes/E0620.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0620.md rename to compiler/rustc_error_codes/src/error_codes/E0620.md diff --git a/src/librustc_error_codes/error_codes/E0621.md b/compiler/rustc_error_codes/src/error_codes/E0621.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0621.md rename to compiler/rustc_error_codes/src/error_codes/E0621.md diff --git a/src/librustc_error_codes/error_codes/E0622.md b/compiler/rustc_error_codes/src/error_codes/E0622.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0622.md rename to compiler/rustc_error_codes/src/error_codes/E0622.md diff --git a/src/librustc_error_codes/error_codes/E0623.md b/compiler/rustc_error_codes/src/error_codes/E0623.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0623.md rename to compiler/rustc_error_codes/src/error_codes/E0623.md diff --git a/src/librustc_error_codes/error_codes/E0624.md b/compiler/rustc_error_codes/src/error_codes/E0624.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0624.md rename to compiler/rustc_error_codes/src/error_codes/E0624.md diff --git a/src/librustc_error_codes/error_codes/E0626.md b/compiler/rustc_error_codes/src/error_codes/E0626.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0626.md rename to compiler/rustc_error_codes/src/error_codes/E0626.md diff --git a/src/librustc_error_codes/error_codes/E0627.md b/compiler/rustc_error_codes/src/error_codes/E0627.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0627.md rename to compiler/rustc_error_codes/src/error_codes/E0627.md diff --git a/src/librustc_error_codes/error_codes/E0628.md b/compiler/rustc_error_codes/src/error_codes/E0628.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0628.md rename to compiler/rustc_error_codes/src/error_codes/E0628.md diff --git a/src/librustc_error_codes/error_codes/E0631.md b/compiler/rustc_error_codes/src/error_codes/E0631.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0631.md rename to compiler/rustc_error_codes/src/error_codes/E0631.md diff --git a/src/librustc_error_codes/error_codes/E0633.md b/compiler/rustc_error_codes/src/error_codes/E0633.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0633.md rename to compiler/rustc_error_codes/src/error_codes/E0633.md diff --git a/src/librustc_error_codes/error_codes/E0634.md b/compiler/rustc_error_codes/src/error_codes/E0634.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0634.md rename to compiler/rustc_error_codes/src/error_codes/E0634.md diff --git a/src/librustc_error_codes/error_codes/E0635.md b/compiler/rustc_error_codes/src/error_codes/E0635.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0635.md rename to compiler/rustc_error_codes/src/error_codes/E0635.md diff --git a/src/librustc_error_codes/error_codes/E0636.md b/compiler/rustc_error_codes/src/error_codes/E0636.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0636.md rename to compiler/rustc_error_codes/src/error_codes/E0636.md diff --git a/src/librustc_error_codes/error_codes/E0637.md b/compiler/rustc_error_codes/src/error_codes/E0637.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0637.md rename to compiler/rustc_error_codes/src/error_codes/E0637.md diff --git a/src/librustc_error_codes/error_codes/E0638.md b/compiler/rustc_error_codes/src/error_codes/E0638.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0638.md rename to compiler/rustc_error_codes/src/error_codes/E0638.md diff --git a/src/librustc_error_codes/error_codes/E0639.md b/compiler/rustc_error_codes/src/error_codes/E0639.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0639.md rename to compiler/rustc_error_codes/src/error_codes/E0639.md diff --git a/src/librustc_error_codes/error_codes/E0641.md b/compiler/rustc_error_codes/src/error_codes/E0641.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0641.md rename to compiler/rustc_error_codes/src/error_codes/E0641.md diff --git a/src/librustc_error_codes/error_codes/E0642.md b/compiler/rustc_error_codes/src/error_codes/E0642.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0642.md rename to compiler/rustc_error_codes/src/error_codes/E0642.md diff --git a/src/librustc_error_codes/error_codes/E0643.md b/compiler/rustc_error_codes/src/error_codes/E0643.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0643.md rename to compiler/rustc_error_codes/src/error_codes/E0643.md diff --git a/src/librustc_error_codes/error_codes/E0644.md b/compiler/rustc_error_codes/src/error_codes/E0644.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0644.md rename to compiler/rustc_error_codes/src/error_codes/E0644.md diff --git a/src/librustc_error_codes/error_codes/E0646.md b/compiler/rustc_error_codes/src/error_codes/E0646.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0646.md rename to compiler/rustc_error_codes/src/error_codes/E0646.md diff --git a/src/librustc_error_codes/error_codes/E0647.md b/compiler/rustc_error_codes/src/error_codes/E0647.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0647.md rename to compiler/rustc_error_codes/src/error_codes/E0647.md diff --git a/src/librustc_error_codes/error_codes/E0648.md b/compiler/rustc_error_codes/src/error_codes/E0648.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0648.md rename to compiler/rustc_error_codes/src/error_codes/E0648.md diff --git a/src/librustc_error_codes/error_codes/E0657.md b/compiler/rustc_error_codes/src/error_codes/E0657.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0657.md rename to compiler/rustc_error_codes/src/error_codes/E0657.md diff --git a/src/librustc_error_codes/error_codes/E0658.md b/compiler/rustc_error_codes/src/error_codes/E0658.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0658.md rename to compiler/rustc_error_codes/src/error_codes/E0658.md diff --git a/src/librustc_error_codes/error_codes/E0659.md b/compiler/rustc_error_codes/src/error_codes/E0659.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0659.md rename to compiler/rustc_error_codes/src/error_codes/E0659.md diff --git a/src/librustc_error_codes/error_codes/E0660.md b/compiler/rustc_error_codes/src/error_codes/E0660.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0660.md rename to compiler/rustc_error_codes/src/error_codes/E0660.md diff --git a/src/librustc_error_codes/error_codes/E0661.md b/compiler/rustc_error_codes/src/error_codes/E0661.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0661.md rename to compiler/rustc_error_codes/src/error_codes/E0661.md diff --git a/src/librustc_error_codes/error_codes/E0662.md b/compiler/rustc_error_codes/src/error_codes/E0662.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0662.md rename to compiler/rustc_error_codes/src/error_codes/E0662.md diff --git a/src/librustc_error_codes/error_codes/E0663.md b/compiler/rustc_error_codes/src/error_codes/E0663.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0663.md rename to compiler/rustc_error_codes/src/error_codes/E0663.md diff --git a/src/librustc_error_codes/error_codes/E0664.md b/compiler/rustc_error_codes/src/error_codes/E0664.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0664.md rename to compiler/rustc_error_codes/src/error_codes/E0664.md diff --git a/src/librustc_error_codes/error_codes/E0665.md b/compiler/rustc_error_codes/src/error_codes/E0665.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0665.md rename to compiler/rustc_error_codes/src/error_codes/E0665.md diff --git a/src/librustc_error_codes/error_codes/E0666.md b/compiler/rustc_error_codes/src/error_codes/E0666.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0666.md rename to compiler/rustc_error_codes/src/error_codes/E0666.md diff --git a/src/librustc_error_codes/error_codes/E0668.md b/compiler/rustc_error_codes/src/error_codes/E0668.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0668.md rename to compiler/rustc_error_codes/src/error_codes/E0668.md diff --git a/src/librustc_error_codes/error_codes/E0669.md b/compiler/rustc_error_codes/src/error_codes/E0669.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0669.md rename to compiler/rustc_error_codes/src/error_codes/E0669.md diff --git a/src/librustc_error_codes/error_codes/E0670.md b/compiler/rustc_error_codes/src/error_codes/E0670.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0670.md rename to compiler/rustc_error_codes/src/error_codes/E0670.md diff --git a/src/librustc_error_codes/error_codes/E0671.md b/compiler/rustc_error_codes/src/error_codes/E0671.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0671.md rename to compiler/rustc_error_codes/src/error_codes/E0671.md diff --git a/src/librustc_error_codes/error_codes/E0687.md b/compiler/rustc_error_codes/src/error_codes/E0687.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0687.md rename to compiler/rustc_error_codes/src/error_codes/E0687.md diff --git a/src/librustc_error_codes/error_codes/E0688.md b/compiler/rustc_error_codes/src/error_codes/E0688.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0688.md rename to compiler/rustc_error_codes/src/error_codes/E0688.md diff --git a/src/librustc_error_codes/error_codes/E0689.md b/compiler/rustc_error_codes/src/error_codes/E0689.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0689.md rename to compiler/rustc_error_codes/src/error_codes/E0689.md diff --git a/src/librustc_error_codes/error_codes/E0690.md b/compiler/rustc_error_codes/src/error_codes/E0690.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0690.md rename to compiler/rustc_error_codes/src/error_codes/E0690.md diff --git a/src/librustc_error_codes/error_codes/E0691.md b/compiler/rustc_error_codes/src/error_codes/E0691.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0691.md rename to compiler/rustc_error_codes/src/error_codes/E0691.md diff --git a/src/librustc_error_codes/error_codes/E0692.md b/compiler/rustc_error_codes/src/error_codes/E0692.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0692.md rename to compiler/rustc_error_codes/src/error_codes/E0692.md diff --git a/src/librustc_error_codes/error_codes/E0693.md b/compiler/rustc_error_codes/src/error_codes/E0693.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0693.md rename to compiler/rustc_error_codes/src/error_codes/E0693.md diff --git a/src/librustc_error_codes/error_codes/E0695.md b/compiler/rustc_error_codes/src/error_codes/E0695.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0695.md rename to compiler/rustc_error_codes/src/error_codes/E0695.md diff --git a/src/librustc_error_codes/error_codes/E0696.md b/compiler/rustc_error_codes/src/error_codes/E0696.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0696.md rename to compiler/rustc_error_codes/src/error_codes/E0696.md diff --git a/src/librustc_error_codes/error_codes/E0697.md b/compiler/rustc_error_codes/src/error_codes/E0697.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0697.md rename to compiler/rustc_error_codes/src/error_codes/E0697.md diff --git a/src/librustc_error_codes/error_codes/E0698.md b/compiler/rustc_error_codes/src/error_codes/E0698.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0698.md rename to compiler/rustc_error_codes/src/error_codes/E0698.md diff --git a/src/librustc_error_codes/error_codes/E0699.md b/compiler/rustc_error_codes/src/error_codes/E0699.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0699.md rename to compiler/rustc_error_codes/src/error_codes/E0699.md diff --git a/src/librustc_error_codes/error_codes/E0700.md b/compiler/rustc_error_codes/src/error_codes/E0700.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0700.md rename to compiler/rustc_error_codes/src/error_codes/E0700.md diff --git a/src/librustc_error_codes/error_codes/E0701.md b/compiler/rustc_error_codes/src/error_codes/E0701.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0701.md rename to compiler/rustc_error_codes/src/error_codes/E0701.md diff --git a/src/librustc_error_codes/error_codes/E0703.md b/compiler/rustc_error_codes/src/error_codes/E0703.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0703.md rename to compiler/rustc_error_codes/src/error_codes/E0703.md diff --git a/src/librustc_error_codes/error_codes/E0704.md b/compiler/rustc_error_codes/src/error_codes/E0704.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0704.md rename to compiler/rustc_error_codes/src/error_codes/E0704.md diff --git a/src/librustc_error_codes/error_codes/E0705.md b/compiler/rustc_error_codes/src/error_codes/E0705.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0705.md rename to compiler/rustc_error_codes/src/error_codes/E0705.md diff --git a/src/librustc_error_codes/error_codes/E0706.md b/compiler/rustc_error_codes/src/error_codes/E0706.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0706.md rename to compiler/rustc_error_codes/src/error_codes/E0706.md diff --git a/src/librustc_error_codes/error_codes/E0708.md b/compiler/rustc_error_codes/src/error_codes/E0708.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0708.md rename to compiler/rustc_error_codes/src/error_codes/E0708.md diff --git a/src/librustc_error_codes/error_codes/E0710.md b/compiler/rustc_error_codes/src/error_codes/E0710.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0710.md rename to compiler/rustc_error_codes/src/error_codes/E0710.md diff --git a/src/librustc_error_codes/error_codes/E0712.md b/compiler/rustc_error_codes/src/error_codes/E0712.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0712.md rename to compiler/rustc_error_codes/src/error_codes/E0712.md diff --git a/src/librustc_error_codes/error_codes/E0713.md b/compiler/rustc_error_codes/src/error_codes/E0713.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0713.md rename to compiler/rustc_error_codes/src/error_codes/E0713.md diff --git a/src/librustc_error_codes/error_codes/E0714.md b/compiler/rustc_error_codes/src/error_codes/E0714.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0714.md rename to compiler/rustc_error_codes/src/error_codes/E0714.md diff --git a/src/librustc_error_codes/error_codes/E0715.md b/compiler/rustc_error_codes/src/error_codes/E0715.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0715.md rename to compiler/rustc_error_codes/src/error_codes/E0715.md diff --git a/src/librustc_error_codes/error_codes/E0716.md b/compiler/rustc_error_codes/src/error_codes/E0716.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0716.md rename to compiler/rustc_error_codes/src/error_codes/E0716.md diff --git a/src/librustc_error_codes/error_codes/E0718.md b/compiler/rustc_error_codes/src/error_codes/E0718.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0718.md rename to compiler/rustc_error_codes/src/error_codes/E0718.md diff --git a/src/librustc_error_codes/error_codes/E0719.md b/compiler/rustc_error_codes/src/error_codes/E0719.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0719.md rename to compiler/rustc_error_codes/src/error_codes/E0719.md diff --git a/src/librustc_error_codes/error_codes/E0720.md b/compiler/rustc_error_codes/src/error_codes/E0720.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0720.md rename to compiler/rustc_error_codes/src/error_codes/E0720.md diff --git a/src/librustc_error_codes/error_codes/E0723.md b/compiler/rustc_error_codes/src/error_codes/E0723.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0723.md rename to compiler/rustc_error_codes/src/error_codes/E0723.md diff --git a/src/librustc_error_codes/error_codes/E0724.md b/compiler/rustc_error_codes/src/error_codes/E0724.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0724.md rename to compiler/rustc_error_codes/src/error_codes/E0724.md diff --git a/src/librustc_error_codes/error_codes/E0725.md b/compiler/rustc_error_codes/src/error_codes/E0725.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0725.md rename to compiler/rustc_error_codes/src/error_codes/E0725.md diff --git a/src/librustc_error_codes/error_codes/E0727.md b/compiler/rustc_error_codes/src/error_codes/E0727.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0727.md rename to compiler/rustc_error_codes/src/error_codes/E0727.md diff --git a/src/librustc_error_codes/error_codes/E0728.md b/compiler/rustc_error_codes/src/error_codes/E0728.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0728.md rename to compiler/rustc_error_codes/src/error_codes/E0728.md diff --git a/src/librustc_error_codes/error_codes/E0729.md b/compiler/rustc_error_codes/src/error_codes/E0729.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0729.md rename to compiler/rustc_error_codes/src/error_codes/E0729.md diff --git a/src/librustc_error_codes/error_codes/E0730.md b/compiler/rustc_error_codes/src/error_codes/E0730.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0730.md rename to compiler/rustc_error_codes/src/error_codes/E0730.md diff --git a/src/librustc_error_codes/error_codes/E0731.md b/compiler/rustc_error_codes/src/error_codes/E0731.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0731.md rename to compiler/rustc_error_codes/src/error_codes/E0731.md diff --git a/src/librustc_error_codes/error_codes/E0732.md b/compiler/rustc_error_codes/src/error_codes/E0732.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0732.md rename to compiler/rustc_error_codes/src/error_codes/E0732.md diff --git a/src/librustc_error_codes/error_codes/E0733.md b/compiler/rustc_error_codes/src/error_codes/E0733.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0733.md rename to compiler/rustc_error_codes/src/error_codes/E0733.md diff --git a/src/librustc_error_codes/error_codes/E0734.md b/compiler/rustc_error_codes/src/error_codes/E0734.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0734.md rename to compiler/rustc_error_codes/src/error_codes/E0734.md diff --git a/src/librustc_error_codes/error_codes/E0735.md b/compiler/rustc_error_codes/src/error_codes/E0735.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0735.md rename to compiler/rustc_error_codes/src/error_codes/E0735.md diff --git a/src/librustc_error_codes/error_codes/E0736.md b/compiler/rustc_error_codes/src/error_codes/E0736.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0736.md rename to compiler/rustc_error_codes/src/error_codes/E0736.md diff --git a/src/librustc_error_codes/error_codes/E0737.md b/compiler/rustc_error_codes/src/error_codes/E0737.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0737.md rename to compiler/rustc_error_codes/src/error_codes/E0737.md diff --git a/src/librustc_error_codes/error_codes/E0739.md b/compiler/rustc_error_codes/src/error_codes/E0739.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0739.md rename to compiler/rustc_error_codes/src/error_codes/E0739.md diff --git a/src/librustc_error_codes/error_codes/E0740.md b/compiler/rustc_error_codes/src/error_codes/E0740.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0740.md rename to compiler/rustc_error_codes/src/error_codes/E0740.md diff --git a/src/librustc_error_codes/error_codes/E0741.md b/compiler/rustc_error_codes/src/error_codes/E0741.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0741.md rename to compiler/rustc_error_codes/src/error_codes/E0741.md diff --git a/src/librustc_error_codes/error_codes/E0742.md b/compiler/rustc_error_codes/src/error_codes/E0742.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0742.md rename to compiler/rustc_error_codes/src/error_codes/E0742.md diff --git a/src/librustc_error_codes/error_codes/E0743.md b/compiler/rustc_error_codes/src/error_codes/E0743.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0743.md rename to compiler/rustc_error_codes/src/error_codes/E0743.md diff --git a/src/librustc_error_codes/error_codes/E0744.md b/compiler/rustc_error_codes/src/error_codes/E0744.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0744.md rename to compiler/rustc_error_codes/src/error_codes/E0744.md diff --git a/src/librustc_error_codes/error_codes/E0745.md b/compiler/rustc_error_codes/src/error_codes/E0745.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0745.md rename to compiler/rustc_error_codes/src/error_codes/E0745.md diff --git a/src/librustc_error_codes/error_codes/E0746.md b/compiler/rustc_error_codes/src/error_codes/E0746.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0746.md rename to compiler/rustc_error_codes/src/error_codes/E0746.md diff --git a/src/librustc_error_codes/error_codes/E0747.md b/compiler/rustc_error_codes/src/error_codes/E0747.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0747.md rename to compiler/rustc_error_codes/src/error_codes/E0747.md diff --git a/src/librustc_error_codes/error_codes/E0748.md b/compiler/rustc_error_codes/src/error_codes/E0748.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0748.md rename to compiler/rustc_error_codes/src/error_codes/E0748.md diff --git a/src/librustc_error_codes/error_codes/E0749.md b/compiler/rustc_error_codes/src/error_codes/E0749.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0749.md rename to compiler/rustc_error_codes/src/error_codes/E0749.md diff --git a/src/librustc_error_codes/error_codes/E0750.md b/compiler/rustc_error_codes/src/error_codes/E0750.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0750.md rename to compiler/rustc_error_codes/src/error_codes/E0750.md diff --git a/src/librustc_error_codes/error_codes/E0751.md b/compiler/rustc_error_codes/src/error_codes/E0751.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0751.md rename to compiler/rustc_error_codes/src/error_codes/E0751.md diff --git a/src/librustc_error_codes/error_codes/E0752.md b/compiler/rustc_error_codes/src/error_codes/E0752.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0752.md rename to compiler/rustc_error_codes/src/error_codes/E0752.md diff --git a/src/librustc_error_codes/error_codes/E0753.md b/compiler/rustc_error_codes/src/error_codes/E0753.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0753.md rename to compiler/rustc_error_codes/src/error_codes/E0753.md diff --git a/src/librustc_error_codes/error_codes/E0754.md b/compiler/rustc_error_codes/src/error_codes/E0754.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0754.md rename to compiler/rustc_error_codes/src/error_codes/E0754.md diff --git a/compiler/rustc_error_codes/src/error_codes/E0755.md b/compiler/rustc_error_codes/src/error_codes/E0755.md new file mode 100644 index 0000000000..88b7f48496 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0755.md @@ -0,0 +1,28 @@ +The `ffi_pure` attribute was used on a non-foreign function. + +Erroneous code example: + +```compile_fail,E0755 +#![feature(ffi_pure)] + +#[ffi_pure] // error! +pub fn foo() {} +# fn main() {} +``` + +The `ffi_pure` attribute can only be used on foreign functions which do not have +side effects or infinite loops: + +``` +#![feature(ffi_pure)] + +extern "C" { + #[ffi_pure] // ok! + pub fn strlen(s: *const i8) -> isize; +} +# fn main() {} +``` + +You can find more information about it in the [unstable Rust Book]. + +[unstable Rust Book]: https://doc.rust-lang.org/unstable-book/language-features/ffi-pure.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md new file mode 100644 index 0000000000..ffdc421aab --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0756.md @@ -0,0 +1,29 @@ +The `ffi_const` attribute was used on something other than a foreign function +declaration. + +Erroneous code example: + +```compile_fail,E0756 +#![feature(ffi_const)] + +#[ffi_const] // error! +pub fn foo() {} +# fn main() {} +``` + +The `ffi_const` attribute can only be used on foreign function declarations +which have no side effects except for their return value: + +``` +#![feature(ffi_const)] + +extern "C" { + #[ffi_const] // ok! + pub fn strlen(s: *const i8) -> i32; +} +# fn main() {} +``` + +You can get more information about it in the [unstable Rust Book]. + +[unstable Rust Book]: https://doc.rust-lang.org/nightly/unstable-book/language-features/ffi-const.html diff --git a/src/librustc_error_codes/error_codes/E0758.md b/compiler/rustc_error_codes/src/error_codes/E0758.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0758.md rename to compiler/rustc_error_codes/src/error_codes/E0758.md diff --git a/src/librustc_error_codes/error_codes/E0759.md b/compiler/rustc_error_codes/src/error_codes/E0759.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0759.md rename to compiler/rustc_error_codes/src/error_codes/E0759.md diff --git a/src/librustc_error_codes/error_codes/E0760.md b/compiler/rustc_error_codes/src/error_codes/E0760.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0760.md rename to compiler/rustc_error_codes/src/error_codes/E0760.md diff --git a/src/librustc_error_codes/error_codes/E0761.md b/compiler/rustc_error_codes/src/error_codes/E0761.md similarity index 93% rename from src/librustc_error_codes/error_codes/E0761.md rename to compiler/rustc_error_codes/src/error_codes/E0761.md index c01574e413..e112674fbc 100644 --- a/src/librustc_error_codes/error_codes/E0761.md +++ b/compiler/rustc_error_codes/src/error_codes/E0761.md @@ -2,24 +2,20 @@ Multiple candidate files were found for an out-of-line module. Erroneous code example: -```rust +```ignore (multiple source files required for compile_fail) // file: ambiguous_module/mod.rs fn foo() {} -``` -```rust // file: ambiguous_module.rs fn foo() {} -``` -```ignore (multiple source files required for compile_fail) +// file: lib.rs + mod ambiguous_module; // error: file for module `ambiguous_module` // found at both ambiguous_module.rs and // ambiguous_module.rs/mod.rs - -fn main() {} ``` Please remove this ambiguity by deleting/renaming one of the candidate files. diff --git a/src/librustc_error_codes/error_codes/E0762.md b/compiler/rustc_error_codes/src/error_codes/E0762.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0762.md rename to compiler/rustc_error_codes/src/error_codes/E0762.md diff --git a/src/librustc_error_codes/error_codes/E0763.md b/compiler/rustc_error_codes/src/error_codes/E0763.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0763.md rename to compiler/rustc_error_codes/src/error_codes/E0763.md diff --git a/src/librustc_error_codes/error_codes/E0764.md b/compiler/rustc_error_codes/src/error_codes/E0764.md similarity index 60% rename from src/librustc_error_codes/error_codes/E0764.md rename to compiler/rustc_error_codes/src/error_codes/E0764.md index e9061f988a..0a2e2290e7 100644 --- a/src/librustc_error_codes/error_codes/E0764.md +++ b/compiler/rustc_error_codes/src/error_codes/E0764.md @@ -1,12 +1,4 @@ -Mutable references (`&mut`) can only be used in constant functions, not statics -or constants. This limitation exists to prevent the creation of constants that -have a mutable reference in their final value. If you had a constant of `&mut -i32` type, you could modify the value through that reference, making the -constant essentially mutable. While there could be a more fine-grained scheme -in the future that allows mutable references if they are not "leaked" to the -final value, a more conservative approach was chosen for now. `const fn` do not -have this problem, as the borrow checker will prevent the `const fn` from -returning new mutable references. +A mutable reference was used in a constant. Erroneous code example: @@ -19,6 +11,18 @@ fn main() { } ``` +Mutable references (`&mut`) can only be used in constant functions, not statics +or constants. This limitation exists to prevent the creation of constants that +have a mutable reference in their final value. If you had a constant of +`&mut i32` type, you could modify the value through that reference, making the +constant essentially mutable. + +While there could be a more fine-grained scheme in the future that allows +mutable references if they are not "leaked" to the final value, a more +conservative approach was chosen for now. `const fn` do not have this problem, +as the borrow checker will prevent the `const fn` from returning new mutable +references. + Remember: you cannot use a function call inside a constant or static. However, you can totally use it in constant functions: diff --git a/src/librustc_error_codes/error_codes/E0765.md b/compiler/rustc_error_codes/src/error_codes/E0765.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0765.md rename to compiler/rustc_error_codes/src/error_codes/E0765.md diff --git a/src/librustc_error_codes/error_codes/E0766.md b/compiler/rustc_error_codes/src/error_codes/E0766.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0766.md rename to compiler/rustc_error_codes/src/error_codes/E0766.md diff --git a/src/librustc_error_codes/error_codes/E0767.md b/compiler/rustc_error_codes/src/error_codes/E0767.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0767.md rename to compiler/rustc_error_codes/src/error_codes/E0767.md diff --git a/src/librustc_error_codes/error_codes/E0768.md b/compiler/rustc_error_codes/src/error_codes/E0768.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0768.md rename to compiler/rustc_error_codes/src/error_codes/E0768.md diff --git a/src/librustc_error_codes/error_codes/E0769.md b/compiler/rustc_error_codes/src/error_codes/E0769.md similarity index 58% rename from src/librustc_error_codes/error_codes/E0769.md rename to compiler/rustc_error_codes/src/error_codes/E0769.md index d1995be989..4a3b674b05 100644 --- a/src/librustc_error_codes/error_codes/E0769.md +++ b/compiler/rustc_error_codes/src/error_codes/E0769.md @@ -1,5 +1,5 @@ -A tuple struct or tuple variant was used in a pattern as if it were a -struct or struct variant. +A tuple struct or tuple variant was used in a pattern as if it were a struct or +struct variant. Erroneous code example: @@ -7,9 +7,13 @@ Erroneous code example: enum E { A(i32), } + let e = E::A(42); + match e { - E::A { number } => println!("{}", x), + E::A { number } => { // error! + println!("{}", number); + } } ``` @@ -21,12 +25,14 @@ To fix this error, you can use the tuple pattern: # } # let e = E::A(42); match e { - E::A(number) => println!("{}", number), + E::A(number) => { // ok! + println!("{}", number); + } } ``` -Alternatively, you can also use the struct pattern by using the correct -field names and binding them to new identifiers: +Alternatively, you can also use the struct pattern by using the correct field +names and binding them to new identifiers: ``` # enum E { @@ -34,6 +40,8 @@ field names and binding them to new identifiers: # } # let e = E::A(42); match e { - E::A { 0: number } => println!("{}", number), + E::A { 0: number } => { // ok! + println!("{}", number); + } } ``` diff --git a/src/librustc_error_codes/error_codes/E0770.md b/compiler/rustc_error_codes/src/error_codes/E0770.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0770.md rename to compiler/rustc_error_codes/src/error_codes/E0770.md diff --git a/src/librustc_error_codes/error_codes/E0771.md b/compiler/rustc_error_codes/src/error_codes/E0771.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0771.md rename to compiler/rustc_error_codes/src/error_codes/E0771.md diff --git a/compiler/rustc_error_codes/src/error_codes/E0773.md b/compiler/rustc_error_codes/src/error_codes/E0773.md new file mode 100644 index 0000000000..b19a58bf33 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0773.md @@ -0,0 +1,38 @@ +A builtin-macro was defined more than once. + +Erroneous code example: + +```compile_fail,E0773 +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + /* compiler built-in */ + } +} +``` + +To fix the issue, remove the duplicate declaration: + +``` +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} +``` + +In very rare edge cases, this may happen when loading `core` or `std` twice, +once with `check` metadata and once with `build` metadata. +For more information, see [#75176]. + +[#75176]: https://github.com/rust-lang/rust/pull/75176#issuecomment-683234468 diff --git a/compiler/rustc_error_codes/src/error_codes/E0774.md b/compiler/rustc_error_codes/src/error_codes/E0774.md new file mode 100644 index 0000000000..79793ba9d7 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0774.md @@ -0,0 +1,24 @@ +`derive` was applied on something which is not a struct, a union or an enum. + +Erroneous code example: + +```compile_fail,E0774 +trait Foo { + #[derive(Clone)] // error! + type Bar; +} +``` + +As said above, the `derive` attribute is only allowed on structs, unions or +enums: + +``` +#[derive(Clone)] // ok! +struct Bar { + field: u32, +} +``` + +You can find more information about `derive` in the [Rust Book]. + +[Rust Book]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md new file mode 100644 index 0000000000..9bafd52f75 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0775.md @@ -0,0 +1,17 @@ +`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M +extension. + +Erroneous code example: + +```compile_fail,E0775 +#![feature(cmse_nonsecure_entry)] + +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function() {} +``` + +To fix this error, compile your code for a Rust target that supports the +TrustZone-M extension. The current possible targets are: +* `thumbv8m.main-none-eabi` +* `thumbv8m.main-none-eabihf` +* `thumbv8m.base-none-eabi` diff --git a/compiler/rustc_error_codes/src/error_codes/E0776.md b/compiler/rustc_error_codes/src/error_codes/E0776.md new file mode 100644 index 0000000000..d65beebe07 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0776.md @@ -0,0 +1,13 @@ +`#[cmse_nonsecure_entry]` functions require a C ABI + +Erroneous code example: + +```compile_fail,E0776 +#![feature(cmse_nonsecure_entry)] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub fn entry_function(input: Vec) {} +``` + +To fix this error, declare your entry function with a C ABI, using `extern "C"`. diff --git a/src/librustc_error_codes/lib.rs b/compiler/rustc_error_codes/src/lib.rs similarity index 100% rename from src/librustc_error_codes/lib.rs rename to compiler/rustc_error_codes/src/lib.rs diff --git a/src/librustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml similarity index 60% rename from src/librustc_errors/Cargo.toml rename to compiler/rustc_errors/Cargo.toml index 7c794bcd98..e4dbb8db38 100644 --- a/src/librustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -5,16 +5,14 @@ version = "0.0.0" edition = "2018" [lib] -name = "rustc_errors" -path = "lib.rs" doctest = false [dependencies] tracing = "0.1" -rustc_serialize = { path = "../librustc_serialize" } -rustc_span = { path = "../librustc_span" } -rustc_macros = { path = "../librustc_macros" } -rustc_data_structures = { path = "../librustc_data_structures" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +rustc_macros = { path = "../rustc_macros" } +rustc_data_structures = { path = "../rustc_data_structures" } unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs similarity index 100% rename from src/librustc_errors/annotate_snippet_emitter_writer.rs rename to compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs diff --git a/src/librustc_errors/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs similarity index 100% rename from src/librustc_errors/diagnostic.rs rename to compiler/rustc_errors/src/diagnostic.rs diff --git a/src/librustc_errors/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs similarity index 100% rename from src/librustc_errors/diagnostic_builder.rs rename to compiler/rustc_errors/src/diagnostic_builder.rs diff --git a/src/librustc_errors/emitter.rs b/compiler/rustc_errors/src/emitter.rs similarity index 99% rename from src/librustc_errors/emitter.rs rename to compiler/rustc_errors/src/emitter.rs index 4555168af0..98cbf98df9 100644 --- a/src/librustc_errors/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1227,18 +1227,14 @@ impl EmitterWriter { } draw_note_separator(&mut buffer, 0, max_line_num_len + 1); if *level != Level::FailureNote { - let level_str = level.to_string(); - if !level_str.is_empty() { - buffer.append(0, &level_str, Style::MainHeaderMsg); - buffer.append(0, ": ", Style::NoStyle); - } + buffer.append(0, level.to_str(), Style::MainHeaderMsg); + buffer.append(0, ": ", Style::NoStyle); } self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None); } else { - let level_str = level.to_string(); // The failure note level itself does not provide any useful diagnostic information - if *level != Level::FailureNote && !level_str.is_empty() { - buffer.append(0, &level_str, Style::Level(*level)); + if *level != Level::FailureNote { + buffer.append(0, level.to_str(), Style::Level(*level)); } // only render error codes, not lint codes if let Some(DiagnosticId::Error(ref code)) = *code { @@ -1246,7 +1242,7 @@ impl EmitterWriter { buffer.append(0, &code, Style::Level(*level)); buffer.append(0, "]", Style::Level(*level)); } - if *level != Level::FailureNote && !level_str.is_empty() { + if *level != Level::FailureNote { buffer.append(0, ": ", header_style); } for &(ref text, _) in msg.iter() { @@ -1548,11 +1544,9 @@ impl EmitterWriter { let mut buffer = StyledBuffer::new(); // Render the suggestion message - let level_str = level.to_string(); - if !level_str.is_empty() { - buffer.append(0, &level_str, Style::Level(*level)); - buffer.append(0, ": ", Style::HeaderMsg); - } + buffer.append(0, level.to_str(), Style::Level(*level)); + buffer.append(0, ": ", Style::HeaderMsg); + self.msg_to_buffer( &mut buffer, &[(suggestion.msg.to_owned(), Style::NoStyle)], diff --git a/src/librustc_errors/json.rs b/compiler/rustc_errors/src/json.rs similarity index 100% rename from src/librustc_errors/json.rs rename to compiler/rustc_errors/src/json.rs diff --git a/src/librustc_errors/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs similarity index 100% rename from src/librustc_errors/json/tests.rs rename to compiler/rustc_errors/src/json/tests.rs diff --git a/src/librustc_errors/lib.rs b/compiler/rustc_errors/src/lib.rs similarity index 94% rename from src/librustc_errors/lib.rs rename to compiler/rustc_errors/src/lib.rs index d4f0a9d83e..2e8a4ef327 100644 --- a/src/librustc_errors/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2,8 +2,9 @@ //! //! This module contains the code for creating and emitting diagnostics. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(crate_visibility_modifier)] +#![feature(backtrace)] #![feature(nll)] #[macro_use] @@ -296,9 +297,11 @@ struct HandlerInner { /// This is not necessarily the count that's reported to the user once /// compilation ends. err_count: usize, + warn_count: usize, deduplicated_err_count: usize, emitter: Box, delayed_span_bugs: Vec, + delayed_good_path_bugs: Vec, /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid /// emitting the same diagnostic with extended help (`--teach`) twice, which @@ -361,13 +364,15 @@ impl Drop for HandlerInner { if !self.has_errors() { let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new()); - let has_bugs = !bugs.is_empty(); - for bug in bugs { - self.emit_diagnostic(&bug); - } - if has_bugs { - panic!("no errors encountered even though `delay_span_bug` issued"); - } + self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued"); + } + + if !self.has_any_message() { + let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new()); + self.flush_delayed( + bugs, + "no warnings or errors encountered even though `delayed_good_path_bugs` issued", + ); } } } @@ -422,10 +427,12 @@ impl Handler { inner: Lock::new(HandlerInner { flags, err_count: 0, + warn_count: 0, deduplicated_err_count: 0, deduplicated_warn_count: 0, emitter, delayed_span_bugs: Vec::new(), + delayed_good_path_bugs: Vec::new(), taught_diagnostics: Default::default(), emitted_diagnostic_codes: Default::default(), emitted_diagnostics: Default::default(), @@ -448,11 +455,13 @@ impl Handler { pub fn reset_err_count(&self) { let mut inner = self.inner.borrow_mut(); inner.err_count = 0; + inner.warn_count = 0; inner.deduplicated_err_count = 0; inner.deduplicated_warn_count = 0; // actually free the underlying memory (which `clear` would not do) inner.delayed_span_bugs = Default::default(); + inner.delayed_good_path_bugs = Default::default(); inner.taught_diagnostics = Default::default(); inner.emitted_diagnostic_codes = Default::default(); inner.emitted_diagnostics = Default::default(); @@ -629,6 +638,10 @@ impl Handler { self.inner.borrow_mut().delay_span_bug(span, msg) } + pub fn delay_good_path_bug(&self, msg: &str) { + self.inner.borrow_mut().delay_good_path_bug(msg) + } + pub fn span_bug_no_panic(&self, span: impl Into, msg: &str) { self.emit_diag_at_span(Diagnostic::new(Bug, msg), span); } @@ -768,6 +781,8 @@ impl HandlerInner { } if diagnostic.is_error() { self.bump_err_count(); + } else { + self.bump_warn_count(); } } @@ -859,6 +874,9 @@ impl HandlerInner { fn has_errors_or_delayed_span_bugs(&self) -> bool { self.has_errors() || !self.delayed_span_bugs.is_empty() } + fn has_any_message(&self) -> bool { + self.err_count() > 0 || self.warn_count > 0 + } fn abort_if_errors(&mut self) { self.emit_stashed_diagnostics(); @@ -892,6 +910,15 @@ impl HandlerInner { self.delay_as_bug(diagnostic) } + fn delay_good_path_bug(&mut self, msg: &str) { + let mut diagnostic = Diagnostic::new(Level::Bug, msg); + if self.flags.report_delayed_bugs { + self.emit_diagnostic(&diagnostic); + } + diagnostic.note(&format!("delayed at {}", std::backtrace::Backtrace::force_capture())); + self.delayed_good_path_bugs.push(diagnostic); + } + fn failure(&mut self, msg: &str) { self.emit_diagnostic(&Diagnostic::new(FailureNote, msg)); } @@ -925,23 +952,35 @@ impl HandlerInner { self.delayed_span_bugs.push(diagnostic); } + fn flush_delayed(&mut self, bugs: Vec, explanation: &str) { + let has_bugs = !bugs.is_empty(); + for bug in bugs { + self.emit_diagnostic(&bug); + } + if has_bugs { + panic!("{}", explanation); + } + } + fn bump_err_count(&mut self) { self.err_count += 1; self.panic_if_treat_err_as_bug(); } + fn bump_warn_count(&mut self) { + self.warn_count += 1; + } + fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { - let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) { - (0, _) => return, - (1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(), - (1, _) => return, - (count, as_bug) => format!( + match (self.err_count(), self.flags.treat_err_as_bug.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, ), - }; - panic!(s); + } } } } diff --git a/src/librustc_errors/lock.rs b/compiler/rustc_errors/src/lock.rs similarity index 100% rename from src/librustc_errors/lock.rs rename to compiler/rustc_errors/src/lock.rs diff --git a/src/librustc_errors/registry.rs b/compiler/rustc_errors/src/registry.rs similarity index 100% rename from src/librustc_errors/registry.rs rename to compiler/rustc_errors/src/registry.rs diff --git a/src/librustc_errors/snippet.rs b/compiler/rustc_errors/src/snippet.rs similarity index 96% rename from src/librustc_errors/snippet.rs rename to compiler/rustc_errors/src/snippet.rs index 160bf57779..fae5b94b3a 100644 --- a/src/librustc_errors/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -118,17 +118,15 @@ pub struct Annotation { impl Annotation { /// Whether this annotation is a vertical line placeholder. pub fn is_line(&self) -> bool { - if let AnnotationType::MultilineLine(_) = self.annotation_type { true } else { false } + matches!(self.annotation_type, AnnotationType::MultilineLine(_)) } pub fn is_multiline(&self) -> bool { - match self.annotation_type { + matches!(self.annotation_type, AnnotationType::Multiline(_) | AnnotationType::MultilineStart(_) | AnnotationType::MultilineLine(_) - | AnnotationType::MultilineEnd(_) => true, - _ => false, - } + | AnnotationType::MultilineEnd(_)) } pub fn len(&self) -> usize { diff --git a/src/librustc_errors/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs similarity index 100% rename from src/librustc_errors/styled_buffer.rs rename to compiler/rustc_errors/src/styled_buffer.rs diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml new file mode 100644 index 0000000000..25c2851f6d --- /dev/null +++ b/compiler/rustc_expand/Cargo.toml @@ -0,0 +1,26 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_expand" +version = "0.0.0" +edition = "2018" +build = false + +[lib] +doctest = false + +[dependencies] +rustc_serialize = { path = "../rustc_serialize" } +tracing = "0.1" +rustc_span = { path = "../rustc_span" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_ast_passes = { path = "../rustc_ast_passes" } +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_lexer = { path = "../rustc_lexer" } +rustc_parse = { path = "../rustc_parse" } +rustc_session = { path = "../rustc_session" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } diff --git a/src/librustc_expand/base.rs b/compiler/rustc_expand/src/base.rs similarity index 97% rename from src/librustc_expand/base.rs rename to compiler/rustc_expand/src/base.rs index 4c01cb8159..f7651ca0ba 100644 --- a/src/librustc_expand/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1,10 +1,9 @@ use crate::expand::{self, AstFragment, Invocation}; use crate::module::DirectoryOwnership; -use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::token; -use rustc_ast::tokenstream::{self, TokenStream}; +use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, Attribute, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; @@ -313,7 +312,7 @@ where ts: TokenStream, ) -> Result { // FIXME setup implicit context in TLS before calling self. - Ok((*self)(ts)) + Ok(self(ts)) } } @@ -339,7 +338,7 @@ where annotated: TokenStream, ) -> Result { // FIXME setup implicit context in TLS before calling self. - Ok((*self)(annotation, annotated)) + Ok(self(annotation, annotated)) } } @@ -364,31 +363,9 @@ where &self, ecx: &'cx mut ExtCtxt<'_>, span: Span, - mut input: TokenStream, + input: TokenStream, ) -> Box { - struct AvoidInterpolatedIdents; - - impl MutVisitor for AvoidInterpolatedIdents { - fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) { - if let tokenstream::TokenTree::Token(token) = tt { - if let token::Interpolated(nt) = &token.kind { - if let token::NtIdent(ident, is_raw) = **nt { - *tt = tokenstream::TokenTree::token( - token::Ident(ident.name, is_raw), - ident.span, - ); - } - } - } - mut_visit::noop_visit_tt(tt, self) - } - - fn visit_mac(&mut self, mac: &mut ast::MacCall) { - mut_visit::noop_visit_mac(mac, self) - } - } - AvoidInterpolatedIdents.visit_tts(&mut input); - (*self)(ecx, span, input) + self(ecx, span, input) } } @@ -400,6 +377,7 @@ macro_rules! make_stmts_default { id: ast::DUMMY_NODE_ID, span: e.span, kind: ast::StmtKind::Expr(e), + tokens: None }] }) }; @@ -607,6 +585,7 @@ impl DummyResult { id: ast::DUMMY_NODE_ID, kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(Vec::new()) }, span: sp, + tokens: None, }) } } @@ -641,6 +620,7 @@ impl MacResult for DummyResult { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), span: self.span, + tokens: None }]) } diff --git a/src/librustc_expand/build.rs b/compiler/rustc_expand/src/build.rs similarity index 93% rename from src/librustc_expand/build.rs rename to compiler/rustc_expand/src/build.rs index 9490b62aa1..a5a7ee6c9a 100644 --- a/src/librustc_expand/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -3,7 +3,7 @@ use crate::base::ExtCtxt; use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, PatKind, UnOp}; -use rustc_span::source_map::{respan, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -46,7 +46,7 @@ impl<'a> ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, args, }); - ast::Path { span, segments } + ast::Path { span, segments, tokens: None } } pub fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy { @@ -54,7 +54,7 @@ impl<'a> ExtCtxt<'a> { } pub fn ty(&self, span: Span, kind: ast::TyKind) -> P { - P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind }) + P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind, tokens: None }) } pub fn ty_path(&self, path: ast::Path) -> P { @@ -158,7 +158,12 @@ impl<'a> ExtCtxt<'a> { } pub fn stmt_expr(&self, expr: P) -> ast::Stmt { - ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) } + ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: expr.span, + kind: ast::StmtKind::Expr(expr), + tokens: None, + } } pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P) -> ast::Stmt { @@ -176,7 +181,12 @@ impl<'a> ExtCtxt<'a> { span: sp, attrs: AttrVec::new(), }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } + ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Local(local), + span: sp, + tokens: None, + } } // Generates `let _: Type;`, which is usually used for type assertions. @@ -189,11 +199,16 @@ impl<'a> ExtCtxt<'a> { span, attrs: AttrVec::new(), }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span, tokens: None } } pub fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(item), span: sp } + ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Item(item), + span: sp, + tokens: None, + } } pub fn block_expr(&self, expr: P) -> P { @@ -203,11 +218,18 @@ impl<'a> ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr), + tokens: None, }], ) } pub fn block(&self, span: Span, stmts: Vec) -> P { - P(ast::Block { stmts, id: ast::DUMMY_NODE_ID, rules: BlockCheckMode::Default, span }) + P(ast::Block { + stmts, + id: ast::DUMMY_NODE_ID, + rules: BlockCheckMode::Default, + span, + tokens: None, + }) } pub fn expr(&self, span: Span, kind: ast::ExprKind) -> P { @@ -578,7 +600,11 @@ impl<'a> ExtCtxt<'a> { attrs, id: ast::DUMMY_NODE_ID, kind, - vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: span.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, span, tokens: None, }) @@ -592,7 +618,11 @@ impl<'a> ExtCtxt<'a> { span: ty.span, ty, ident: None, - vis: respan(vis_span, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: vis_span, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, attrs: Vec::new(), id: ast::DUMMY_NODE_ID, is_placeholder: false, @@ -611,7 +641,11 @@ impl<'a> ExtCtxt<'a> { disr_expr: None, id: ast::DUMMY_NODE_ID, ident, - vis: respan(vis_span, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: vis_span, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, span, is_placeholder: false, } diff --git a/src/librustc_expand/config.rs b/compiler/rustc_expand/src/config.rs similarity index 98% rename from src/librustc_expand/config.rs rename to compiler/rustc_expand/src/config.rs index afd1e60640..dd087ab915 100644 --- a/src/librustc_expand/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -399,14 +399,10 @@ impl<'a> StripUnconfigured<'a> { } pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { - let ast::ForeignMod { abi: _, items } = foreign_mod; + let ast::ForeignMod { unsafety: _, abi: _, items } = foreign_mod; items.flat_map_in_place(|item| self.configure(item)); } - pub fn configure_generic_params(&mut self, params: &mut Vec) { - params.flat_map_in_place(|param| self.configure(param)); - } - fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) { match vdata { ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) => { @@ -496,6 +492,13 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { Some(expr) } + fn flat_map_generic_param( + &mut self, + param: ast::GenericParam, + ) -> SmallVec<[ast::GenericParam; 1]> { + noop_flat_map_generic_param(configure!(self, param), self) + } + fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { noop_flat_map_stmt(configure!(self, stmt), self) } diff --git a/src/librustc_expand/expand.rs b/compiler/rustc_expand/src/expand.rs similarity index 97% rename from src/librustc_expand/expand.rs rename to compiler/rustc_expand/src/expand.rs index 7a21caf255..e5cfb86693 100644 --- a/src/librustc_expand/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,7 +13,7 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path}; -use rustc_ast::{ItemKind, MacArgs, MacStmtStyle, StmtKind}; +use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_data_structures::map_in_place::MapInPlace; @@ -26,7 +26,6 @@ use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Limit; -use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{ExpnId, FileName, Span, DUMMY_SP}; @@ -358,7 +357,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind: ast::ItemKind::Mod(krate.module), ident: Ident::invalid(), id: ast::DUMMY_NODE_ID, - vis: respan(krate.span.shrink_to_lo(), ast::VisibilityKind::Public), + vis: ast::Visibility { + span: krate.span.shrink_to_lo(), + kind: ast::VisibilityKind::Public, + tokens: None, + }, tokens: None, })]); @@ -370,11 +373,21 @@ impl<'a, 'b> MacroExpander<'a, 'b> { None => { // Resolution failed so we return an empty expansion krate.attrs = vec![]; - krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; + krate.module = ast::Mod { + inner: orig_mod_span, + unsafety: Unsafe::No, + items: vec![], + inline: true, + }; } Some(ast::Item { span, kind, .. }) => { krate.attrs = vec![]; - krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; + krate.module = ast::Mod { + inner: orig_mod_span, + unsafety: Unsafe::No, + items: vec![], + inline: true, + }; self.cx.span_err( span, &format!( @@ -529,9 +542,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) { let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive); let span = attr.map_or(item.span(), |attr| attr.span); - let mut err = self - .cx - .struct_span_err(span, "`derive` may only be applied to structs, enums and unions"); + let mut err = rustc_errors::struct_span_err!( + self.cx.sess, + span, + E0774, + "`derive` may only be applied to structs, enums and unions", + ); if let Some(ast::Attribute { style: ast::AttrStyle::Inner, .. }) = attr { let trait_list = derives.iter().map(|t| pprust::path_to_string(t)).collect::>(); let suggestion = format!("#[derive({})]", trait_list.join(", ")); @@ -1363,7 +1379,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } if let StmtKind::MacCall(mac) = stmt.kind { - let (mac, style, attrs) = mac.into_inner(); + let MacCallStmt { mac, style, attrs } = mac.into_inner(); self.check_attributes(&attrs); let mut placeholder = self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts(); @@ -1380,10 +1396,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } // The placeholder expander gives ids to statements, so we avoid folding the id here. - let ast::Stmt { id, kind, span } = stmt; + let ast::Stmt { id, kind, span, tokens } = stmt; noop_flat_map_stmt_kind(kind, self) .into_iter() - .map(|kind| ast::Stmt { id, kind, span }) + .map(|kind| ast::Stmt { id, kind, span, tokens: tokens.clone() }) .collect() } @@ -1438,8 +1454,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { push_directory(&self.cx.sess, ident, &item.attrs, dir) } else { // We have an outline `mod foo;` so we need to parse the file. - let (new_mod, dir) = - parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed); + let (new_mod, dir) = parse_external_mod( + &self.cx.sess, + ident, + span, + old_mod.unsafety, + dir, + &mut attrs, + pushed, + ); let krate = ast::Crate { span: new_mod.inner, @@ -1757,6 +1780,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { kind: ast::AttrKind::Normal(AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span), + tokens: None, }), span: at.span, id: at.id, @@ -1788,6 +1812,7 @@ pub struct ExpansionConfig<'feat> { pub should_test: bool, // If false, strip `#[test]` nodes pub keep_macs: bool, pub span_debug: bool, // If true, use verbose debugging for `proc_macro::Span` + pub proc_macro_backtrace: bool, // If true, show backtraces for proc-macro panics } impl<'feat> ExpansionConfig<'feat> { @@ -1800,6 +1825,7 @@ impl<'feat> ExpansionConfig<'feat> { should_test: false, keep_macs: false, span_debug: false, + proc_macro_backtrace: false, } } diff --git a/src/librustc_expand/lib.rs b/compiler/rustc_expand/src/lib.rs similarity index 90% rename from src/librustc_expand/lib.rs rename to compiler/rustc_expand/src/lib.rs index 7f631cb71a..47247294f5 100644 --- a/src/librustc_expand/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,5 +1,4 @@ #![feature(bool_to_option)] -#![feature(cow_is_borrowed)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(or_patterns)] @@ -39,11 +38,6 @@ mod tests; mod parse { #[cfg(test)] mod tests; - #[cfg(test)] - mod lexer { - #[cfg(test)] - mod tests; - } } #[cfg(test)] mod tokenstream { diff --git a/src/librustc_expand/mbe.rs b/compiler/rustc_expand/src/mbe.rs similarity index 100% rename from src/librustc_expand/mbe.rs rename to compiler/rustc_expand/src/mbe.rs diff --git a/src/librustc_expand/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs similarity index 100% rename from src/librustc_expand/mbe/macro_check.rs rename to compiler/rustc_expand/src/mbe/macro_check.rs diff --git a/src/librustc_expand/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs similarity index 100% rename from src/librustc_expand/mbe/macro_parser.rs rename to compiler/rustc_expand/src/mbe/macro_parser.rs diff --git a/src/librustc_expand/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs similarity index 100% rename from src/librustc_expand/mbe/macro_rules.rs rename to compiler/rustc_expand/src/mbe/macro_rules.rs diff --git a/src/librustc_expand/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs similarity index 100% rename from src/librustc_expand/mbe/quoted.rs rename to compiler/rustc_expand/src/mbe/quoted.rs diff --git a/src/librustc_expand/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs similarity index 99% rename from src/librustc_expand/mbe/transcribe.rs rename to compiler/rustc_expand/src/mbe/transcribe.rs index b908a12c1f..0e5c5fe4d4 100644 --- a/src/librustc_expand/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -4,7 +4,7 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, NtTT, Token}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::MacCall; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -111,7 +111,7 @@ pub(super) fn transcribe<'a>( // // Thus, if we try to pop the `result_stack` and it is empty, we have reached the top-level // again, and we are done transcribing. - let mut result: Vec = Vec::new(); + let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); let mut marker = Marker(cx.current_expansion.id, transparency); diff --git a/src/librustc_expand/module.rs b/compiler/rustc_expand/src/module.rs similarity index 96% rename from src/librustc_expand/module.rs rename to compiler/rustc_expand/src/module.rs index 1e123a2e14..171cb3fa8e 100644 --- a/src/librustc_expand/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -1,4 +1,4 @@ -use rustc_ast::{token, Attribute, Mod}; +use rustc_ast::{token, Attribute, Mod, Unsafe}; use rustc_errors::{struct_span_err, PResult}; use rustc_parse::new_parser_from_file; use rustc_session::parse::ParseSess; @@ -42,6 +42,7 @@ crate fn parse_external_mod( sess: &Session, id: Ident, span: Span, // The span to blame on errors. + unsafety: Unsafe, Directory { mut ownership, path }: Directory, attrs: &mut Vec, pop_mod_stack: &mut bool, @@ -60,13 +61,16 @@ crate fn parse_external_mod( drop(included_mod_stack); // Actually parse the external file as a module. - let mut module = - new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)).parse_mod(&token::Eof)?; + let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)); + let mut module = parser.parse_mod(&token::Eof, unsafety)?; module.0.inline = false; module }; // (1) ...instead, we return a dummy module. - let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default(); + let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| { + let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }; + (module, Vec::new()) + }); attrs.append(&mut new_attrs); // Extract the directory path for submodules of `module`. @@ -219,8 +223,7 @@ fn error_cannot_declare_mod_here<'a, T>( /// Derive a submodule path from the first found `#[path = "path_string"]`. /// The provided `dir_path` is joined with the `path_string`. -// Public for rustfmt usage. -pub fn submod_path_from_attr( +pub(super) fn submod_path_from_attr( sess: &Session, attrs: &[Attribute], dir_path: &Path, diff --git a/src/librustc_expand/mut_visit/tests.rs b/compiler/rustc_expand/src/mut_visit/tests.rs similarity index 100% rename from src/librustc_expand/mut_visit/tests.rs rename to compiler/rustc_expand/src/mut_visit/tests.rs diff --git a/src/librustc_expand/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs similarity index 100% rename from src/librustc_expand/parse/tests.rs rename to compiler/rustc_expand/src/parse/tests.rs diff --git a/src/librustc_expand/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs similarity index 92% rename from src/librustc_expand/placeholders.rs rename to compiler/rustc_expand/src/placeholders.rs index 29fb4c95ec..4c9271a58d 100644 --- a/src/librustc_expand/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -4,7 +4,7 @@ use crate::expand::{AstFragment, AstFragmentKind}; use rustc_ast as ast; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_span::source_map::{dummy_spanned, DUMMY_SP}; +use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::Ident; use smallvec::{smallvec, SmallVec}; @@ -18,7 +18,7 @@ pub fn placeholder( ) -> AstFragment { fn mac_placeholder() -> ast::MacCall { ast::MacCall { - path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, + path: ast::Path { span: DUMMY_SP, segments: Vec::new(), tokens: None }, args: P(ast::MacArgs::Empty), prior_type_ascription: None, } @@ -26,7 +26,11 @@ pub fn placeholder( let ident = Ident::invalid(); let attrs = Vec::new(); - let vis = vis.unwrap_or_else(|| dummy_spanned(ast::VisibilityKind::Inherited)); + let vis = vis.unwrap_or(ast::Visibility { + span: DUMMY_SP, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }); let span = DUMMY_SP; let expr_placeholder = || { P(ast::Expr { @@ -37,7 +41,8 @@ pub fn placeholder( tokens: None, }) }; - let ty = || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span }); + let ty = + || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span, tokens: None }); let pat = || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None }); @@ -88,12 +93,19 @@ pub fn placeholder( kind: ast::PatKind::MacCall(mac_placeholder()), tokens: None, })), - AstFragmentKind::Ty => { - AstFragment::Ty(P(ast::Ty { id, span, kind: ast::TyKind::MacCall(mac_placeholder()) })) - } + AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty { + id, + span, + kind: ast::TyKind::MacCall(mac_placeholder()), + tokens: None, + })), AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{ - let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::AttrVec::new())); - ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) } + let mac = P(ast::MacCallStmt { + mac: mac_placeholder(), + style: ast::MacStmtStyle::Braces, + attrs: ast::AttrVec::new(), + }); + ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac), tokens: None } }]), AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm { attrs: Default::default(), @@ -293,7 +305,7 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { let (style, mut stmts) = match stmt.kind { - ast::StmtKind::MacCall(mac) => (mac.1, self.remove(stmt.id).make_stmts()), + ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()), _ => return noop_flat_map_stmt(stmt, self), }; diff --git a/src/librustc_expand/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs similarity index 89% rename from src/librustc_expand/proc_macro.rs rename to compiler/rustc_expand/src/proc_macro.rs index 4e865c20d6..94b3fcf285 100644 --- a/src/librustc_expand/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -24,7 +24,7 @@ impl base::ProcMacro for BangProcMacro { input: TokenStream, ) -> Result { let server = proc_macro_server::Rustc::new(ecx); - self.client.run(&EXEC_STRATEGY, server, input).map_err(|e| { + self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| { let mut err = ecx.struct_span_err(span, "proc macro panicked"); if let Some(s) = e.as_str() { err.help(&format!("message: {}", s)); @@ -48,14 +48,16 @@ impl base::AttrProcMacro for AttrProcMacro { annotated: TokenStream, ) -> Result { let server = proc_macro_server::Rustc::new(ecx); - self.client.run(&EXEC_STRATEGY, server, annotation, annotated).map_err(|e| { - let mut err = ecx.struct_span_err(span, "custom attribute panicked"); - if let Some(s) = e.as_str() { - err.help(&format!("message: {}", s)); - } - err.emit(); - ErrorReported - }) + self.client + .run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace) + .map_err(|e| { + let mut err = ecx.struct_span_err(span, "custom attribute panicked"); + if let Some(s) = e.as_str() { + err.help(&format!("message: {}", s)); + } + err.emit(); + ErrorReported + }) } } @@ -111,17 +113,18 @@ impl MultiItemModifier for ProcMacroDerive { }; let server = proc_macro_server::Rustc::new(ecx); - let stream = match self.client.run(&EXEC_STRATEGY, server, input) { - Ok(stream) => stream, - Err(e) => { - let mut err = ecx.struct_span_err(span, "proc-macro derive panicked"); - if let Some(s) = e.as_str() { - err.help(&format!("message: {}", s)); + let stream = + match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) { + Ok(stream) => stream, + Err(e) => { + let mut err = ecx.struct_span_err(span, "proc-macro derive panicked"); + if let Some(s) = e.as_str() { + err.help(&format!("message: {}", s)); + } + err.emit(); + return ExpandResult::Ready(vec![]); } - err.emit(); - return ExpandResult::Ready(vec![]); - } - }; + }; let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count(); let mut parser = diff --git a/src/librustc_expand/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs similarity index 97% rename from src/librustc_expand/proc_macro_server.rs rename to compiler/rustc_expand/src/proc_macro_server.rs index 409784812f..4cfb188783 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -2,7 +2,7 @@ use crate::base::ExtCtxt; use rustc_ast as ast; use rustc_ast::token; -use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; +use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::Diagnostic; @@ -47,15 +47,15 @@ impl ToInternal for Delimiter { } } -impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> +impl FromInternal<(TreeAndSpacing, &'_ ParseSess, &'_ mut Vec)> for TokenTree { fn from_internal( - ((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec), + ((tree, spacing), sess, stack): (TreeAndSpacing, &ParseSess, &mut Vec), ) -> Self { use rustc_ast::token::*; - let joint = is_joint == Joint; + let joint = spacing == Joint; let Token { kind, span } = match tree { tokenstream::TokenTree::Delimited(span, delim, tts) => { let delimiter = Delimiter::from_internal(delim); @@ -189,7 +189,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> } OpenDelim(..) | CloseDelim(..) => unreachable!(), - Whitespace | Comment | Shebang(..) | Unknown(..) | Eof => unreachable!(), + Eof => unreachable!(), } } } @@ -261,7 +261,7 @@ impl ToInternal for TokenTree { }; let tree = tokenstream::TokenTree::token(kind, span); - TokenStream::new(vec![(tree, if joint { Joint } else { NonJoint })]) + TokenStream::new(vec![(tree, if joint { Joint } else { Alone })]) } } @@ -444,7 +444,7 @@ impl server::TokenStreamIter for Rustc<'_> { ) -> Option> { loop { let tree = iter.stack.pop().or_else(|| { - let next = iter.cursor.next_with_joint()?; + let next = iter.cursor.next_with_spacing()?; Some(TokenTree::from_internal((next, self.sess, &mut iter.stack))) })?; // A hack used to pass AST fragments to attribute and derive macros @@ -584,12 +584,12 @@ impl server::Literal for Rustc<'_> { let start = match start { Bound::Included(lo) => lo, - Bound::Excluded(lo) => lo + 1, + Bound::Excluded(lo) => lo.checked_add(1)?, Bound::Unbounded => 0, }; let end = match end { - Bound::Included(hi) => hi + 1, + Bound::Included(hi) => hi.checked_add(1)?, Bound::Excluded(hi) => hi, Bound::Unbounded => length, }; diff --git a/src/librustc_expand/tests.rs b/compiler/rustc_expand/src/tests.rs similarity index 100% rename from src/librustc_expand/tests.rs rename to compiler/rustc_expand/src/tests.rs diff --git a/src/librustc_expand/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs similarity index 100% rename from src/librustc_expand/tokenstream/tests.rs rename to compiler/rustc_expand/src/tokenstream/tests.rs diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml new file mode 100644 index 0000000000..7a06bce13c --- /dev/null +++ b/compiler/rustc_feature/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_feature" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_span = { path = "../rustc_span" } diff --git a/src/librustc_feature/accepted.rs b/compiler/rustc_feature/src/accepted.rs similarity index 98% rename from src/librustc_feature/accepted.rs rename to compiler/rustc_feature/src/accepted.rs index d16f023c00..e2492efb9d 100644 --- a/src/librustc_feature/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -1,6 +1,6 @@ //! List of the accepted feature gates. -use super::{Feature, State}; +use super::{to_nonzero, Feature, State}; use rustc_span::symbol::sym; macro_rules! declare_features { @@ -14,7 +14,7 @@ macro_rules! declare_features { state: State::Accepted, name: sym::$feature, since: $ver, - issue: $issue, + issue: to_nonzero($issue), edition: None, description: concat!($($doc,)*), } @@ -268,6 +268,8 @@ declare_features! ( /// Allows `#[track_caller]` to be used which provides /// accurate caller location reporting during panic (RFC 2091). (accepted, track_caller, "1.46.0", Some(47809), None), + /// Allows `#[doc(alias = "...")]`. + (accepted, doc_alias, "1.48.0", Some(50146), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/src/librustc_feature/active.rs b/compiler/rustc_feature/src/active.rs similarity index 96% rename from src/librustc_feature/active.rs rename to compiler/rustc_feature/src/active.rs index e858980738..060efd270d 100644 --- a/src/librustc_feature/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -1,6 +1,6 @@ //! List of the active feature gates. -use super::{Feature, State}; +use super::{to_nonzero, Feature, State}; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; @@ -29,7 +29,7 @@ macro_rules! declare_features { state: State::Active { set: set!($feature) }, name: sym::$feature, since: $ver, - issue: $issue, + issue: to_nonzero($issue), edition: $edition, description: concat!($($doc,)*), } @@ -229,7 +229,6 @@ declare_features! ( (active, powerpc_target_feature, "1.27.0", Some(44839), None), (active, mips_target_feature, "1.27.0", Some(44839), None), (active, avx512_target_feature, "1.27.0", Some(44839), None), - (active, mmx_target_feature, "1.27.0", Some(44839), None), (active, sse4a_target_feature, "1.27.0", Some(44839), None), (active, tbm_target_feature, "1.27.0", Some(44839), None), (active, wasm_target_feature, "1.30.0", Some(44839), None), @@ -404,9 +403,6 @@ declare_features! ( /// Allows dereferencing raw pointers during const eval. (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - /// Allows `#[doc(alias = "...")]`. - (active, doc_alias, "1.27.0", Some(50146), None), - /// Allows inconsistent bounds in where clauses. (active, trivial_bounds, "1.28.0", Some(48214), None), @@ -585,6 +581,18 @@ declare_features! ( /// Allows `if let` guard in match arms. (active, if_let_guard, "1.47.0", Some(51114), None), + /// Allows non trivial generic constants which have to be manually propageted upwards. + (active, const_evaluatable_checked, "1.48.0", Some(76560), None), + + /// Allows basic arithmetic on floating point types in a `const fn`. + (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None), + + /// Allows using and casting function pointers in a `const fn`. + (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None), + + /// Allows to use the `#[cmse_nonsecure_entry]` attribute. + (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -600,8 +608,14 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::const_generics, sym::let_chains, sym::raw_dylib, + sym::const_evaluatable_checked, sym::const_trait_impl, sym::const_trait_bound_opt_out, sym::lazy_normalization_consts, sym::specialization, ]; + +/// Some features are not allowed to be used together at the same time, if +/// the two are present, produce an error. +pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = + &[(sym::const_generics, sym::min_const_generics)]; diff --git a/src/librustc_feature/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs similarity index 98% rename from src/librustc_feature/builtin_attrs.rs rename to compiler/rustc_feature/src/builtin_attrs.rs index 879f06f89a..b7e113e601 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -5,10 +5,11 @@ use AttributeType::*; use crate::{Features, Stability}; -use lazy_static::lazy_static; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{sym, Symbol}; +use std::lazy::SyncLazy; + type GateFn = fn(&Features) -> bool; macro_rules! cfg_fn { @@ -25,6 +26,11 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + ( + sym::target_has_atomic_equal_alignment, + sym::cfg_target_has_atomic, + cfg_fn!(cfg_target_has_atomic), + ), (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), ]; @@ -343,6 +349,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ experimental!(register_tool), ), + gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== @@ -458,7 +466,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), - rustc_attr!(rustc_allow_const_fn_ptr, AssumedUsed, template!(Word), IMPL_DETAIL), rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), // ========================================================================== @@ -589,8 +596,8 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } -lazy_static! { - pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { +pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy> = + SyncLazy::new(|| { let mut map = FxHashMap::default(); for attr in BUILTIN_ATTRIBUTES.iter() { if map.insert(attr.0, attr).is_some() { @@ -598,5 +605,4 @@ lazy_static! { } } map - }; -} + }); diff --git a/src/librustc_feature/lib.rs b/compiler/rustc_feature/src/lib.rs similarity index 88% rename from src/librustc_feature/lib.rs rename to compiler/rustc_feature/src/lib.rs index f8bf0315d0..68ac2841fe 100644 --- a/src/librustc_feature/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -11,6 +11,8 @@ //! even if it is stabilized or removed, *do not remove it*. Instead, move the //! symbol to the `accepted` or `removed` modules respectively. +#![feature(once_cell)] + mod accepted; mod active; mod builtin_attrs; @@ -44,17 +46,11 @@ pub struct Feature { pub state: State, pub name: Symbol, pub since: &'static str, - issue: Option, // FIXME: once #58732 is done make this an Option + issue: Option, pub edition: Option, description: &'static str, } -impl Feature { - fn issue(&self) -> Option { - self.issue.and_then(NonZeroU32::new) - } -} - #[derive(Copy, Clone, Debug)] pub enum Stability { Unstable, @@ -100,8 +96,8 @@ impl UnstableFeatures { fn find_lang_feature_issue(feature: Symbol) -> Option { if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { // FIXME (#28244): enforce that active features have issue numbers - // assert!(info.issue().is_some()) - info.issue() + // assert!(info.issue.is_some()) + info.issue } else { // search in Accepted, Removed, or Stable Removed features let found = ACCEPTED_FEATURES @@ -110,12 +106,21 @@ fn find_lang_feature_issue(feature: Symbol) -> Option { .chain(STABLE_REMOVED_FEATURES) .find(|t| t.name == feature); match found { - Some(found) => found.issue(), + Some(found) => found.issue, None => panic!("feature `{}` is not declared anywhere", feature), } } } +const fn to_nonzero(n: Option) -> Option { + // Can be replaced with `n.and_then(NonZeroU32::new)` if that is ever usable + // in const context. Requires https://github.com/rust-lang/rfcs/pull/2632. + match n { + None => None, + Some(n) => NonZeroU32::new(n), + } +} + pub enum GateIssue { Language, Library(Option), @@ -129,7 +134,7 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option { fn target(&'a self, edge: &Self::Edge) -> Self::Node; } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum RenderOption { NoEdgeLabels, NoNodeLabels, NoEdgeStyles, NoNodeStyles, - Monospace, + Fontname(String), + DarkTheme, } /// Returns vec holding all the default render options. @@ -630,10 +631,26 @@ where writeln!(w, "digraph {} {{", g.graph_id().as_slice())?; // Global graph properties - if options.contains(&RenderOption::Monospace) { - writeln!(w, r#" graph[fontname="monospace"];"#)?; - writeln!(w, r#" node[fontname="monospace"];"#)?; - writeln!(w, r#" edge[fontname="monospace"];"#)?; + let mut graph_attrs = Vec::new(); + let mut content_attrs = Vec::new(); + let font; + if let Some(fontname) = options.iter().find_map(|option| { + if let RenderOption::Fontname(fontname) = option { Some(fontname) } else { None } + }) { + font = format!(r#"fontname="{}""#, fontname); + graph_attrs.push(&font[..]); + content_attrs.push(&font[..]); + } + if options.contains(&RenderOption::DarkTheme) { + graph_attrs.push(r#"bgcolor="black""#); + content_attrs.push(r#"color="white""#); + content_attrs.push(r#"fontcolor="white""#); + } + if !(graph_attrs.is_empty() && content_attrs.is_empty()) { + writeln!(w, r#" graph[{}];"#, graph_attrs.join(" "))?; + let content_attrs_str = content_attrs.join(" "); + writeln!(w, r#" node[{}];"#, content_attrs_str)?; + writeln!(w, r#" edge[{}];"#, content_attrs_str)?; } for n in g.nodes().iter() { diff --git a/src/librustc_graphviz/tests.rs b/compiler/rustc_graphviz/src/tests.rs similarity index 100% rename from src/librustc_graphviz/tests.rs rename to compiler/rustc_graphviz/src/tests.rs diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml new file mode 100644 index 0000000000..b24c208c76 --- /dev/null +++ b/compiler/rustc_hir/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_hir" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_target = { path = "../rustc_target" } +rustc_macros = { path = "../rustc_macros" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index" } +rustc_span = { path = "../rustc_span" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_ast = { path = "../rustc_ast" } +tracing = "0.1" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_hir/arena.rs b/compiler/rustc_hir/src/arena.rs similarity index 100% rename from src/librustc_hir/arena.rs rename to compiler/rustc_hir/src/arena.rs diff --git a/src/librustc_hir/def.rs b/compiler/rustc_hir/src/def.rs similarity index 91% rename from src/librustc_hir/def.rs rename to compiler/rustc_hir/src/def.rs index fb7fced27c..96fde48d96 100644 --- a/src/librustc_hir/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -6,6 +6,7 @@ use rustc_ast::NodeId; use rustc_macros::HashStable_Generic; use rustc_span::hygiene::MacroKind; +use std::array::IntoIter; use std::fmt::Debug; /// Encodes if a `DefKind::Ctor` is the constructor of an enum variant or a struct. @@ -198,7 +199,16 @@ pub enum Res { // Type namespace PrimTy(hir::PrimTy), - SelfTy(Option /* trait */, Option /* impl */), + /// `Self`, with both an optional trait and impl `DefId`. + /// + /// HACK(min_const_generics): impl self types also have an optional requirement to not mention + /// any generic parameters to allow the following with `min_const_generics`: + /// ```rust + /// impl Foo { fn test() -> [u8; std::mem::size_of::()] {} } + /// ``` + /// + /// FIXME(lazy_normalization_consts): Remove this bodge once this feature is stable. + SelfTy(Option /* trait */, Option<(DefId, bool)> /* impl */), ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]` // Value namespace @@ -291,6 +301,14 @@ impl PerNS { pub fn map U>(self, mut f: F) -> PerNS { PerNS { value_ns: f(self.value_ns), type_ns: f(self.type_ns), macro_ns: f(self.macro_ns) } } + + pub fn into_iter(self) -> IntoIter { + IntoIter::new([self.value_ns, self.type_ns, self.macro_ns]) + } + + pub fn iter(&self) -> IntoIter<&T, 3> { + IntoIter::new([&self.value_ns, &self.type_ns, &self.macro_ns]) + } } impl ::std::ops::Index for PerNS { @@ -451,13 +469,19 @@ impl Res { } } - pub fn matches_ns(&self, ns: Namespace) -> bool { + /// Returns `None` if this is `Res::Err` + pub fn ns(&self) -> Option { match self { - Res::Def(kind, ..) => kind.ns() == Some(ns), - Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => ns == Namespace::TypeNS, - Res::SelfCtor(..) | Res::Local(..) => ns == Namespace::ValueNS, - Res::NonMacroAttr(..) => ns == Namespace::MacroNS, - Res::Err => true, + Res::Def(kind, ..) => kind.ns(), + Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => Some(Namespace::TypeNS), + Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS), + Res::NonMacroAttr(..) => Some(Namespace::MacroNS), + Res::Err => None, } } + + /// Always returns `true` if `self` is `Res::Err` + pub fn matches_ns(&self, ns: Namespace) -> bool { + self.ns().map_or(true, |actual_ns| actual_ns == ns) + } } diff --git a/src/librustc_hir/definitions.rs b/compiler/rustc_hir/src/definitions.rs similarity index 87% rename from src/librustc_hir/definitions.rs rename to compiler/rustc_hir/src/definitions.rs index 45735ead25..afefde07f9 100644 --- a/src/librustc_hir/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -13,9 +13,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; use rustc_index::vec::IndexVec; use rustc_span::hygiene::ExpnId; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; -use std::fmt::Write; +use std::fmt::{self, Write}; use std::hash::Hash; use tracing::debug; @@ -155,6 +155,29 @@ pub struct DisambiguatedDefPathData { pub disambiguator: u32, } +impl DisambiguatedDefPathData { + pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result { + match self.data.name() { + DefPathDataName::Named(name) => { + if verbose && self.disambiguator != 0 { + write!(writer, "{}#{}", name, self.disambiguator) + } else { + writer.write_str(&name.as_str()) + } + } + DefPathDataName::Anon { namespace } => { + write!(writer, "{{{}#{}}}", namespace, self.disambiguator) + } + } + } +} + +impl fmt::Display for DisambiguatedDefPathData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.fmt_maybe_verbose(f, true) + } +} + #[derive(Clone, Debug, Encodable, Decodable)] pub struct DefPath { /// The path leading from the crate root to the item. @@ -198,33 +221,11 @@ impl DefPath { /// Returns a string representation of the `DefPath` without /// the crate-prefix. This method is useful if you don't have /// a `TyCtxt` available. - pub fn to_string_no_crate(&self) -> String { + pub fn to_string_no_crate_verbose(&self) -> String { let mut s = String::with_capacity(self.data.len() * 16); for component in &self.data { - write!(s, "::{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap(); - } - - s - } - - /// Returns a filename-friendly string for the `DefPath`, with the - /// crate-prefix. - pub fn to_string_friendly(&self, crate_imported_name: F) -> String - where - F: FnOnce(CrateNum) -> Symbol, - { - let crate_name_str = crate_imported_name(self.krate).as_str(); - let mut s = String::with_capacity(crate_name_str.len() + self.data.len() * 16); - - write!(s, "::{}", crate_name_str).unwrap(); - - for component in &self.data { - if component.disambiguator == 0 { - write!(s, "::{}", component.data.as_symbol()).unwrap(); - } else { - write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap(); - } + write!(s, "::{}", component).unwrap(); } s @@ -240,12 +241,9 @@ impl DefPath { for component in &self.data { s.extend(opt_delimiter); opt_delimiter = Some('-'); - if component.disambiguator == 0 { - write!(s, "{}", component.data.as_symbol()).unwrap(); - } else { - write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap(); - } + write!(s, "{}", component).unwrap(); } + s } } @@ -313,6 +311,7 @@ impl Definitions { } #[inline] + #[track_caller] pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId { self.def_id_to_hir_id[id].unwrap() } @@ -426,6 +425,12 @@ impl Definitions { } } +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum DefPathDataName { + Named(Symbol), + Anon { namespace: Symbol }, +} + impl DefPathData { pub fn get_opt_name(&self) -> Option { use self::DefPathData::*; @@ -436,22 +441,30 @@ impl DefPathData { } } - pub fn as_symbol(&self) -> Symbol { + pub fn name(&self) -> DefPathDataName { use self::DefPathData::*; match *self { - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => name, + TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => { + DefPathDataName::Named(name) + } // Note that this does not show up in user print-outs. - CrateRoot => sym::double_braced_crate, - Impl => sym::double_braced_impl, - Misc => sym::double_braced_misc, - ClosureExpr => sym::double_braced_closure, - Ctor => sym::double_braced_constructor, - AnonConst => sym::double_braced_constant, - ImplTrait => sym::double_braced_opaque, + CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, + Impl => DefPathDataName::Anon { namespace: kw::Impl }, + Misc => DefPathDataName::Anon { namespace: sym::misc }, + ClosureExpr => DefPathDataName::Anon { namespace: sym::closure }, + Ctor => DefPathDataName::Anon { namespace: sym::constructor }, + AnonConst => DefPathDataName::Anon { namespace: sym::constant }, + ImplTrait => DefPathDataName::Anon { namespace: sym::opaque }, } } +} - pub fn to_string(&self) -> String { - self.as_symbol().to_string() +impl fmt::Display for DefPathData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.name() { + DefPathDataName::Named(name) => f.write_str(&name.as_str()), + // FIXME(#70334): this will generate legacy {{closure}}, {{impl}}, etc + DefPathDataName::Anon { namespace } => write!(f, "{{{{{}}}}}", namespace), + } } } diff --git a/src/librustc_hir/hir.rs b/compiler/rustc_hir/src/hir.rs similarity index 99% rename from src/librustc_hir/hir.rs rename to compiler/rustc_hir/src/hir.rs index cd4185226d..636f67a77c 100644 --- a/src/librustc_hir/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2004,6 +2004,30 @@ pub enum PrimTy { Char, } +impl PrimTy { + pub fn name_str(self) -> &'static str { + match self { + PrimTy::Int(i) => i.name_str(), + PrimTy::Uint(u) => u.name_str(), + PrimTy::Float(f) => f.name_str(), + PrimTy::Str => "str", + PrimTy::Bool => "bool", + PrimTy::Char => "char", + } + } + + pub fn name(self) -> Symbol { + match self { + PrimTy::Int(i) => i.name(), + PrimTy::Uint(u) => u.name(), + PrimTy::Float(f) => f.name(), + PrimTy::Str => sym::str, + PrimTy::Bool => sym::bool, + PrimTy::Char => sym::char, + } + } +} + #[derive(Debug, HashStable_Generic)] pub struct BareFnTy<'hir> { pub unsafety: Unsafety, diff --git a/src/librustc_hir/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs similarity index 100% rename from src/librustc_hir/hir_id.rs rename to compiler/rustc_hir/src/hir_id.rs diff --git a/src/librustc_hir/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs similarity index 99% rename from src/librustc_hir/intravisit.rs rename to compiler/rustc_hir/src/intravisit.rs index 76cf6bd477..820d664c07 100644 --- a/src/librustc_hir/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -256,7 +256,6 @@ pub trait Visitor<'v>: Sized { /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only /// reason to override this method is if you want a nested pattern /// but cannot supply a `Map`; see `nested_visit_map` for advice. - #[allow(unused_variables)] fn visit_nested_item(&mut self, id: ItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.item(id.id)); walk_list!(self, visit_item, opt_item); @@ -265,7 +264,6 @@ pub trait Visitor<'v>: Sized { /// Like `visit_nested_item()`, but for trait items. See /// `visit_nested_item()` for advice on when to override this /// method. - #[allow(unused_variables)] fn visit_nested_trait_item(&mut self, id: TraitItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id)); walk_list!(self, visit_trait_item, opt_item); @@ -274,7 +272,6 @@ pub trait Visitor<'v>: Sized { /// Like `visit_nested_item()`, but for impl items. See /// `visit_nested_item()` for advice on when to override this /// method. - #[allow(unused_variables)] fn visit_nested_impl_item(&mut self, id: ImplItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id)); walk_list!(self, visit_impl_item, opt_item); diff --git a/src/librustc_hir/itemlikevisit.rs b/compiler/rustc_hir/src/itemlikevisit.rs similarity index 100% rename from src/librustc_hir/itemlikevisit.rs rename to compiler/rustc_hir/src/itemlikevisit.rs diff --git a/src/librustc_hir/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs similarity index 97% rename from src/librustc_hir/lang_items.rs rename to compiler/rustc_hir/src/lang_items.rs index acf6847c01..5e4c03bec8 100644 --- a/src/librustc_hir/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -17,7 +17,7 @@ use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use lazy_static::lazy_static; +use std::lazy::SyncLazy; pub enum LangItemGroup { Op, @@ -117,14 +117,12 @@ macro_rules! language_item_table { )* } - lazy_static! { - /// A mapping from the name of the lang item to its order and the form it must be of. - pub static ref ITEM_REFS: FxHashMap = { - let mut item_refs = FxHashMap::default(); - $( item_refs.insert($name, (LangItem::$variant as usize, $target)); )* - item_refs - }; - } + /// A mapping from the name of the lang item to its order and the form it must be of. + pub static ITEM_REFS: SyncLazy> = SyncLazy::new(|| { + let mut item_refs = FxHashMap::default(); + $( item_refs.insert($name, (LangItem::$variant as usize, $target)); )* + item_refs + }); // End of the macro } diff --git a/src/librustc_hir/lib.rs b/compiler/rustc_hir/src/lib.rs similarity index 94% rename from src/librustc_hir/lib.rs rename to compiler/rustc_hir/src/lib.rs index 19ea1de568..9d931b3a9e 100644 --- a/src/librustc_hir/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -2,10 +2,12 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html +#![feature(array_value_iter)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] // For the unsizing cast on `&[]` #![feature(const_panic)] #![feature(in_band_lifetimes)] +#![feature(once_cell)] #![feature(or_patterns)] #![recursion_limit = "256"] diff --git a/src/librustc_hir/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs similarity index 100% rename from src/librustc_hir/pat_util.rs rename to compiler/rustc_hir/src/pat_util.rs diff --git a/src/librustc_hir/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs similarity index 100% rename from src/librustc_hir/stable_hash_impls.rs rename to compiler/rustc_hir/src/stable_hash_impls.rs diff --git a/src/librustc_hir/target.rs b/compiler/rustc_hir/src/target.rs similarity index 100% rename from src/librustc_hir/target.rs rename to compiler/rustc_hir/src/target.rs diff --git a/src/librustc_hir/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs similarity index 79% rename from src/librustc_hir/weak_lang_items.rs rename to compiler/rustc_hir/src/weak_lang_items.rs index 74e2a90262..52f28bf8f4 100644 --- a/src/librustc_hir/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -7,18 +7,16 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{sym, Symbol}; -use lazy_static::lazy_static; +use std::lazy::SyncLazy; macro_rules! weak_lang_items { ($($name:ident, $item:ident, $sym:ident;)*) => ( -lazy_static! { - pub static ref WEAK_ITEMS_REFS: FxHashMap = { - let mut map = FxHashMap::default(); - $(map.insert(sym::$name, LangItem::$item);)* - map - }; -} +pub static WEAK_ITEMS_REFS: SyncLazy> = SyncLazy::new(|| { + let mut map = FxHashMap::default(); + $(map.insert(sym::$name, LangItem::$item);)* + map +}); /// The `check_name` argument avoids the need for `librustc_hir` to depend on /// `librustc_session`. @@ -48,5 +46,6 @@ impl LanguageItems { weak_lang_items! { panic_impl, PanicImpl, rust_begin_unwind; eh_personality, EhPersonality, rust_eh_personality; + eh_catch_typeinfo, EhCatchTypeinfo, rust_eh_catch_typeinfo; oom, Oom, rust_oom; } diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml new file mode 100644 index 0000000000..1f7643e9fb --- /dev/null +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -0,0 +1,15 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_hir_pretty" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_hir = { path = "../rustc_hir" } +rustc_target = { path = "../rustc_target" } +rustc_span = { path = "../rustc_span" } +rustc_ast = { path = "../rustc_ast" } diff --git a/src/librustc_hir_pretty/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs similarity index 100% rename from src/librustc_hir_pretty/lib.rs rename to compiler/rustc_hir_pretty/src/lib.rs diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml new file mode 100644 index 0000000000..049e5b8b72 --- /dev/null +++ b/compiler/rustc_incremental/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_incremental" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_graphviz = { path = "../rustc_graphviz" } +tracing = "0.1" +rand = "0.7" +rustc_middle = { path = "../rustc_middle" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_ast = { path = "../rustc_ast" } +rustc_macros = { path = "../rustc_macros" } +rustc_span = { path = "../rustc_span" } +rustc_fs_util = { path = "../rustc_fs_util" } +rustc_session = { path = "../rustc_session" } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs similarity index 100% rename from src/librustc_incremental/assert_dep_graph.rs rename to compiler/rustc_incremental/src/assert_dep_graph.rs diff --git a/src/librustc_incremental/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs similarity index 100% rename from src/librustc_incremental/assert_module_sources.rs rename to compiler/rustc_incremental/src/assert_module_sources.rs diff --git a/src/librustc_incremental/lib.rs b/compiler/rustc_incremental/src/lib.rs similarity index 92% rename from src/librustc_incremental/lib.rs rename to compiler/rustc_incremental/src/lib.rs index ad18913805..a80c4be3e9 100644 --- a/src/librustc_incremental/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -1,6 +1,6 @@ //! Support for serializing the dep-graph and reloading it. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/src/librustc_incremental/persist/README.md b/compiler/rustc_incremental/src/persist/README.md similarity index 100% rename from src/librustc_incremental/persist/README.md rename to compiler/rustc_incremental/src/persist/README.md diff --git a/src/librustc_incremental/persist/data.rs b/compiler/rustc_incremental/src/persist/data.rs similarity index 100% rename from src/librustc_incremental/persist/data.rs rename to compiler/rustc_incremental/src/persist/data.rs diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs similarity index 100% rename from src/librustc_incremental/persist/dirty_clean.rs rename to compiler/rustc_incremental/src/persist/dirty_clean.rs diff --git a/src/librustc_incremental/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs similarity index 100% rename from src/librustc_incremental/persist/file_format.rs rename to compiler/rustc_incremental/src/persist/file_format.rs diff --git a/src/librustc_incremental/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs similarity index 100% rename from src/librustc_incremental/persist/fs.rs rename to compiler/rustc_incremental/src/persist/fs.rs diff --git a/src/librustc_incremental/persist/fs/tests.rs b/compiler/rustc_incremental/src/persist/fs/tests.rs similarity index 100% rename from src/librustc_incremental/persist/fs/tests.rs rename to compiler/rustc_incremental/src/persist/fs/tests.rs diff --git a/src/librustc_incremental/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs similarity index 100% rename from src/librustc_incremental/persist/load.rs rename to compiler/rustc_incremental/src/persist/load.rs diff --git a/src/librustc_incremental/persist/mod.rs b/compiler/rustc_incremental/src/persist/mod.rs similarity index 100% rename from src/librustc_incremental/persist/mod.rs rename to compiler/rustc_incremental/src/persist/mod.rs diff --git a/src/librustc_incremental/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs similarity index 100% rename from src/librustc_incremental/persist/save.rs rename to compiler/rustc_incremental/src/persist/save.rs diff --git a/src/librustc_incremental/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs similarity index 100% rename from src/librustc_incremental/persist/work_product.rs rename to compiler/rustc_incremental/src/persist/work_product.rs diff --git a/src/librustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml similarity index 60% rename from src/librustc_index/Cargo.toml rename to compiler/rustc_index/Cargo.toml index 061f440ef1..6e1471df19 100644 --- a/src/librustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -5,11 +5,9 @@ version = "0.0.0" edition = "2018" [lib] -name = "rustc_index" -path = "lib.rs" doctest = false [dependencies] arrayvec = { version = "0.5.1", default-features = false } -rustc_serialize = { path = "../librustc_serialize" } -rustc_macros = { path = "../librustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_macros = { path = "../rustc_macros" } diff --git a/src/librustc_index/bit_set.rs b/compiler/rustc_index/src/bit_set.rs similarity index 97% rename from src/librustc_index/bit_set.rs rename to compiler/rustc_index/src/bit_set.rs index c43d1a6830..8e00e54650 100644 --- a/src/librustc_index/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -28,13 +28,20 @@ pub const WORD_BITS: usize = WORD_BYTES * 8; /// will panic if the bitsets have differing domain sizes. /// /// [`GrowableBitSet`]: struct.GrowableBitSet.html -#[derive(Clone, Eq, PartialEq, Decodable, Encodable)] -pub struct BitSet { +#[derive(Eq, PartialEq, Decodable, Encodable)] +pub struct BitSet { domain_size: usize, words: Vec, marker: PhantomData, } +impl BitSet { + /// Gets the domain size. + pub fn domain_size(&self) -> usize { + self.domain_size + } +} + impl BitSet { /// Creates a new, empty bitset with a given `domain_size`. #[inline] @@ -52,11 +59,6 @@ impl BitSet { result } - /// Gets the domain size. - pub fn domain_size(&self) -> usize { - self.domain_size - } - /// Clear all elements. #[inline] pub fn clear(&mut self) { @@ -75,12 +77,6 @@ impl BitSet { } } - /// Efficiently overwrite `self` with `other`. - pub fn overwrite(&mut self, other: &BitSet) { - assert!(self.domain_size == other.domain_size); - self.words.clone_from_slice(&other.words); - } - /// Count the number of set bits in the set. pub fn count(&self) -> usize { self.words.iter().map(|e| e.count_ones() as usize).sum() @@ -243,6 +239,21 @@ impl SubtractFromBitSet for BitSet { } } +impl Clone for BitSet { + fn clone(&self) -> Self { + BitSet { domain_size: self.domain_size, words: self.words.clone(), marker: PhantomData } + } + + fn clone_from(&mut self, from: &Self) { + if self.domain_size != from.domain_size { + self.words.resize(from.domain_size, 0); + self.domain_size = from.domain_size; + } + + self.words.copy_from_slice(&from.words); + } +} + impl fmt::Debug for BitSet { fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { w.debug_list().entries(self.iter()).finish() @@ -363,7 +374,7 @@ const SPARSE_MAX: usize = 8; /// /// This type is used by `HybridBitSet`; do not use directly. #[derive(Clone, Debug)] -pub struct SparseBitSet { +pub struct SparseBitSet { domain_size: usize, elems: ArrayVec<[T; SPARSE_MAX]>, } @@ -464,18 +475,27 @@ impl SubtractFromBitSet for SparseBitSet { /// All operations that involve an element will panic if the element is equal /// to or greater than the domain size. All operations that involve two bitsets /// will panic if the bitsets have differing domain sizes. -#[derive(Clone, Debug)] -pub enum HybridBitSet { +#[derive(Clone)] +pub enum HybridBitSet { Sparse(SparseBitSet), Dense(BitSet), } +impl fmt::Debug for HybridBitSet { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Sparse(b) => b.fmt(w), + Self::Dense(b) => b.fmt(w), + } + } +} + impl HybridBitSet { pub fn new_empty(domain_size: usize) -> Self { HybridBitSet::Sparse(SparseBitSet::new_empty(domain_size)) } - fn domain_size(&self) -> usize { + pub fn domain_size(&self) -> usize { match self { HybridBitSet::Sparse(sparse) => sparse.domain_size, HybridBitSet::Dense(dense) => dense.domain_size, diff --git a/src/librustc_index/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs similarity index 100% rename from src/librustc_index/bit_set/tests.rs rename to compiler/rustc_index/src/bit_set/tests.rs diff --git a/src/librustc_index/lib.rs b/compiler/rustc_index/src/lib.rs similarity index 100% rename from src/librustc_index/lib.rs rename to compiler/rustc_index/src/lib.rs diff --git a/src/librustc_index/vec.rs b/compiler/rustc_index/src/vec.rs similarity index 100% rename from src/librustc_index/vec.rs rename to compiler/rustc_index/src/vec.rs diff --git a/src/librustc_index/vec/tests.rs b/compiler/rustc_index/src/vec/tests.rs similarity index 100% rename from src/librustc_index/vec/tests.rs rename to compiler/rustc_index/src/vec/tests.rs diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml new file mode 100644 index 0000000000..5dba4106c9 --- /dev/null +++ b/compiler/rustc_infer/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_infer" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_graphviz = { path = "../rustc_graphviz" } +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +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_session = { path = "../rustc_session" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } diff --git a/src/librustc_infer/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs similarity index 100% rename from src/librustc_infer/infer/at.rs rename to compiler/rustc_infer/src/infer/at.rs diff --git a/src/librustc_infer/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs similarity index 99% rename from src/librustc_infer/infer/canonical/canonicalizer.rs rename to compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index ea32a1ae5a..871fc4fafe 100644 --- a/src/librustc_infer/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -340,7 +340,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match *t.kind() { ty::Infer(ty::TyVar(vid)) => { debug!("canonical: type var found with vid {:?}", vid); match self.infcx.unwrap().probe_ty_var(vid) { @@ -418,7 +418,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { | ty::Foreign(..) | ty::Param(..) | ty::Opaque(..) => { - if t.flags.intersects(self.needs_canonical_flags) { + if t.flags().intersects(self.needs_canonical_flags) { t.super_fold_with(self) } else { t diff --git a/src/librustc_infer/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs similarity index 100% rename from src/librustc_infer/infer/canonical/mod.rs rename to compiler/rustc_infer/src/infer/canonical/mod.rs diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs similarity index 99% rename from src/librustc_infer/infer/canonical/query_response.rs rename to compiler/rustc_infer/src/infer/canonical/query_response.rs index 0dbebac7e3..93e1952189 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -422,7 +422,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { match result_value.unpack() { GenericArgKind::Type(result_value) => { // e.g., here `result_value` might be `?0` in the example above... - if let ty::Bound(debruijn, b) = result_value.kind { + if let ty::Bound(debruijn, b) = *result_value.kind() { // ...in which case we would set `canonical_vars[0]` to `Some(?U)`. // We only allow a `ty::INNERMOST` index in substitutions. diff --git a/src/librustc_infer/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs similarity index 100% rename from src/librustc_infer/infer/canonical/substitute.rs rename to compiler/rustc_infer/src/infer/canonical/substitute.rs diff --git a/src/librustc_infer/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs similarity index 76% rename from src/librustc_infer/infer/combine.rs rename to compiler/rustc_infer/src/infer/combine.rs index c89d8ced50..a540face4f 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -43,7 +43,7 @@ use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -73,7 +73,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { { let a_is_expected = relation.a_is_expected(); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { // Relate integral variables to other types (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => { self.inner @@ -160,11 +160,11 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(a_is_expected, vid, b); + return self.unify_const_variable(relation.param_env(), vid, b, a_is_expected); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(!a_is_expected, vid, a); + return self.unify_const_variable(relation.param_env(), vid, a, !a_is_expected); } (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => { // FIXME(#59490): Need to remove the leak check to accommodate @@ -188,17 +188,66 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ty::relate::super_relate_consts(relation, a, b) } - pub fn unify_const_variable( + /// Unifies the const variable `target_vid` with the given constant. + /// + /// This also tests if the given const `ct` contains an inference variable which was previously + /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct` + /// would result in an infinite type as we continously replace an inference variable + /// in `ct` with `ct` itself. + /// + /// This is especially important as unevaluated consts use their parents generics. + /// They therefore often contain unused substs, making these errors far more likely. + /// + /// A good example of this is the following: + /// + /// ```rust + /// #![feature(const_generics)] + /// + /// fn bind(value: [u8; N]) -> [u8; 3 + 4] { + /// todo!() + /// } + /// + /// fn main() { + /// let mut arr = Default::default(); + /// arr = bind(arr); + /// } + /// ``` + /// + /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics + /// of `fn bind` (meaning that its substs contain `N`). + /// + /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`. + /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`. + /// + /// As `3 + 4` contains `N` in its substs, this must not succeed. + /// + /// See `src/test/ui/const-generics/occurs-check/` for more examples where this is relevant. + fn unify_const_variable( &self, + param_env: ty::ParamEnv<'tcx>, + target_vid: ty::ConstVid<'tcx>, + ct: &'tcx ty::Const<'tcx>, vid_is_expected: bool, - vid: ty::ConstVid<'tcx>, - value: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + let (for_universe, span) = { + let mut inner = self.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + let var_value = variable_table.probe_value(target_vid); + match var_value.val { + ConstVariableValue::Known { value } => { + bug!("instantiating {:?} which has a known value {:?}", target_vid, value) + } + ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span), + } + }; + let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid } + .relate(ct, ct)?; + self.inner .borrow_mut() .const_unification_table() .unify_var_value( - vid, + target_vid, ConstVarValue { origin: ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, @@ -207,8 +256,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { val: ConstVariableValue::Known { value }, }, ) - .map_err(|e| const_unification_error(vid_is_expected, e))?; - Ok(value) + .map(|()| value) + .map_err(|e| const_unification_error(vid_is_expected, e)) } fn unify_integral_variable( @@ -363,7 +412,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) { v @ TypeVariableValue::Known { .. } => { - panic!("instantiating {:?} which has a known value {:?}", for_vid, v,) + bug!("instantiating {:?} which has a known value {:?}", for_vid, v,) } TypeVariableValue::Unknown { universe } => universe, }; @@ -548,7 +597,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // any other type variable related to `vid` via // subtyping. This is basically our "occurs check", preventing // us from creating infinitely sized types. - let result = match t.kind { + let result = match *t.kind() { ty::Infer(ty::TyVar(vid)) => { let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid); @@ -681,7 +730,6 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(c), _ => relate::super_relate_consts(self, c, c), } } @@ -731,3 +779,175 @@ fn float_unification_error<'tcx>( let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, a, b)) } + +struct ConstInferUnifier<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + + span: Span, + + param_env: ty::ParamEnv<'tcx>, + + for_universe: ty::UniverseIndex, + + /// The vid of the const variable that is in the process of being + /// instantiated; if we find this within the const we are folding, + /// that means we would have created a cyclic const. + target_vid: ty::ConstVid<'tcx>, +} + +// We use `TypeRelation` here to propagate `RelateResult` upwards. +// +// Both inputs are expected to be the same. +impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + + fn tag(&self) -> &'static str { + "ConstInferUnifier" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance>( + &mut self, + _variance: ty::Variance, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + // We don't care about variance here. + self.relate(a, b) + } + + fn binders( + &mut self, + a: ty::Binder, + b: ty::Binder, + ) -> RelateResult<'tcx, ty::Binder> + where + T: Relate<'tcx>, + { + Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + } + + 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)) => { + let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); + let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); + match probe { + TypeVariableValue::Known { value: u } => { + debug!("ConstOccursChecker: known value {:?}", u); + self.tys(u, u) + } + TypeVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + return Ok(t); + } + + let origin = + *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); + let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var( + self.for_universe, + false, + origin, + ); + let u = self.tcx().mk_ty_var(new_var_id); + debug!( + "ConstInferUnifier: replacing original vid={:?} with new={:?}", + vid, u + ); + Ok(u) + } + } + } + _ => relate::super_relate_tys(self, t, t), + } + } + + fn regions( + &mut self, + r: ty::Region<'tcx>, + _r: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + debug_assert_eq!(r, _r); + debug!("ConstInferUnifier: r={:?}", r); + + match r { + // Never make variables for regions bound within the type itself, + // nor for erased regions. + ty::ReLateBound(..) | ty::ReErased => { + return Ok(r); + } + + ty::RePlaceholder(..) + | ty::ReVar(..) + | ty::ReEmpty(_) + | ty::ReStatic + | ty::ReEarlyBound(..) + | ty::ReFree(..) => { + // see common code below + } + } + + let r_universe = self.infcx.universe_of_region(r); + if self.for_universe.can_name(r_universe) { + return Ok(r); + } else { + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) + } + } + + fn consts( + &mut self, + c: &'tcx ty::Const<'tcx>, + _c: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + debug_assert_eq!(c, _c); + debug!("ConstInferUnifier: c={:?}", c); + + match c.val { + ty::ConstKind::Infer(InferConst::Var(vid)) => { + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + + // Check if the current unification would end up + // unifying `target_vid` with a const which contains + // an inference variable which is unioned with `target_vid`. + // + // Not doing so can easily result in stack overflows. + if variable_table.unioned(self.target_vid, vid) { + return Err(TypeError::CyclicConst(c)); + } + + let var_value = variable_table.probe_value(vid); + match var_value.val { + ConstVariableValue::Known { value: u } => self.consts(u, u), + ConstVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + Ok(c) + } else { + let new_var_id = variable_table.new_key(ConstVarValue { + origin: var_value.origin, + val: ConstVariableValue::Unknown { universe: self.for_universe }, + }); + Ok(self.tcx().mk_const_var(new_var_id, c.ty)) + } + } + } + } + _ => relate::super_relate_consts(self, c, c), + } + } +} diff --git a/src/librustc_infer/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs similarity index 99% rename from src/librustc_infer/infer/equate.rs rename to compiler/rustc_infer/src/infer/equate.rs index 7de752d1de..7c388b5503 100644 --- a/src/librustc_infer/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -77,7 +77,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { infcx.inner.borrow_mut().type_variables().equate(a_id, b_id); } diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs similarity index 94% rename from src/librustc_infer/infer/error_reporting/mod.rs rename to compiler/rustc_infer/src/infer/error_reporting/mod.rs index 8212958510..795c5a64d2 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -50,6 +50,7 @@ use super::region_constraints::GenericKind; use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; use crate::infer; +use crate::infer::OriginalQueryValues; use crate::traits::error_reporting::report_object_safety_error; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, @@ -60,14 +61,16 @@ use rustc_errors::{pluralize, struct_span_err}; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; use rustc_hir::{Item, ItemKind, Node}; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::ParamEnvAnd; use rustc_middle::ty::{ self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable, }; -use rustc_span::{DesugaringKind, Pos, Span}; +use rustc_span::{BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; use std::{cmp, fmt}; @@ -528,7 +531,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result { let mut path = print_prefix(self)?; - path.push(disambiguated_data.data.as_symbol().to_string()); + path.push(disambiguated_data.to_string()); Ok(path) } fn path_generic_args( @@ -567,7 +570,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // if they are both "path types", there's a chance of ambiguity // due to different versions of the same crate if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) = - (&exp_found.expected.kind, &exp_found.found.kind) + (exp_found.expected.kind(), exp_found.found.kind()) { report_path_match(err, exp_adt.did, found_adt.did); } @@ -614,11 +617,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ref prior_arms, last_ty, scrut_hir_id, + opt_suggest_box_span, + arm_span, .. }) => match source { hir::MatchSource::IfLetDesugar { .. } => { let msg = "`if let` arms have incompatible types"; err.span_label(cause.span, msg); + if let Some(ret_sp) = opt_suggest_box_span { + self.suggest_boxing_for_return_impl_trait( + err, + ret_sp, + prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s), + ); + } } hir::MatchSource::TryDesugar => { if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { @@ -672,9 +684,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } + if let Some(ret_sp) = opt_suggest_box_span { + // Get return type span and point to it. + self.suggest_boxing_for_return_impl_trait( + err, + ret_sp, + prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s), + ); + } } }, - ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => { + ObligationCauseCode::IfExpression(box IfExpressionCause { + then, + else_sp, + outer, + semicolon, + opt_suggest_box_span, + }) => { err.span_label(then, "expected because of this"); if let Some(sp) = outer { err.span_label(sp, "`if` and `else` have incompatible types"); @@ -687,11 +713,48 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } + if let Some(ret_sp) = opt_suggest_box_span { + self.suggest_boxing_for_return_impl_trait( + err, + ret_sp, + vec![then, else_sp].into_iter(), + ); + } } _ => (), } } + fn suggest_boxing_for_return_impl_trait( + &self, + err: &mut DiagnosticBuilder<'tcx>, + return_sp: Span, + arm_spans: impl Iterator, + ) { + err.multipart_suggestion( + "you could change the return type to be a boxed trait object", + vec![ + (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box".to_string()), + ], + Applicability::MaybeIncorrect, + ); + let sugg = arm_spans + .flat_map(|sp| { + vec![ + (sp.shrink_to_lo(), "Box::new(".to_string()), + (sp.shrink_to_hi(), ")".to_string()), + ] + .into_iter() + }) + .collect::>(); + err.multipart_suggestion( + "if you change the return type to expect trait objects, box the returned expressions", + sugg, + Applicability::MaybeIncorrect, + ); + } + /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and /// populate `other_value` with `other_ty`. @@ -793,7 +856,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); return Some(()); } - if let &ty::Adt(def, _) = &ta.kind { + if let &ty::Adt(def, _) = ta.kind() { let path_ = self.tcx.def_path_str(def.did); if path_ == other_path { self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); @@ -974,11 +1037,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Compares two given types, eliding parts that are the same between them and highlighting /// relevant differences, and return two representation of those types for highlighted printing. fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) { - debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind, t2, t2.kind); + debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind(), t2, t2.kind()); // helper functions fn equals<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (a, b) if *a == *b => true, (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_))) | ( @@ -1011,7 +1074,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } // process starts here - match (&t1.kind, &t2.kind) { + match (t1.kind(), t2.kind()) { (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => { let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1); let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2); @@ -1473,7 +1536,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; match (&terr, expected == found) { (TypeError::Sorts(values), extra) => { - let sort_string = |ty: Ty<'tcx>| match (extra, &ty.kind) { + let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) { (true, ty::Opaque(def_id, _)) => format!( " (opaque type at {})", self.tcx @@ -1529,6 +1592,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; if let Some(exp_found) = exp_found { self.suggest_as_ref_where_appropriate(span, &exp_found, diag); + self.suggest_await_on_expect_found(cause, span, &exp_found, diag); } // In some (most?) cases cause.body_id points to actual body, but in some cases @@ -1547,6 +1611,62 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.note_error_origin(diag, cause, exp_found); } + fn suggest_await_on_expect_found( + &self, + cause: &ObligationCause<'tcx>, + exp_span: Span, + exp_found: &ty::error::ExpectedFound>, + diag: &mut DiagnosticBuilder<'tcx>, + ) { + debug!( + "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}", + exp_span, exp_found.expected, exp_found.found + ); + + if let ty::Opaque(def_id, _) = *exp_found.expected.kind() { + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + // Future::Output + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + + let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); + if let Some(projection_ty) = projection_ty { + let projection_query = self.canonicalize_query( + &ParamEnvAnd { param_env: self.tcx.param_env(def_id), value: projection_ty }, + &mut OriginalQueryValues::default(), + ); + if let Ok(resp) = self.tcx.normalize_projection_ty(projection_query) { + let normalized_ty = resp.value.value.normalized_ty; + debug!("suggest_await_on_expect_found: normalized={:?}", normalized_ty); + if ty::TyS::same_type(normalized_ty, exp_found.found) { + let span = if let ObligationCauseCode::Pattern { + span, + origin_expr: _, + root_ty: _, + } = cause.code + { + // scrutinee's span + span.unwrap_or(exp_span) + } else { + exp_span + }; + diag.span_suggestion_verbose( + span.shrink_to_hi(), + "consider awaiting on the future", + ".await".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate, /// suggests it. fn suggest_as_ref_where_appropriate( @@ -1556,9 +1676,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diag: &mut DiagnosticBuilder<'tcx>, ) { if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) = - (&exp_found.expected.kind, &exp_found.found.kind) + (exp_found.expected.kind(), exp_found.found.kind()) { - if let ty::Adt(found_def, found_substs) = found_ty.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 \ @@ -1577,9 +1697,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { let mut show_suggestion = true; for (exp_ty, found_ty) in exp_substs.types().zip(found_substs.types()) { - match exp_ty.kind { + match *exp_ty.kind() { ty::Ref(_, exp_ty, _) => { - match (&exp_ty.kind, &found_ty.kind) { + match (exp_ty.kind(), found_ty.kind()) { (_, ty::Param(_)) | (_, ty::Infer(_)) | (ty::Param(_), _) @@ -1929,7 +2049,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); if let Some(infer::RelateParamBound(_, t)) = origin { let t = self.resolve_vars_if_possible(&t); - match t.kind { + match t.kind() { // We've got: // fn get_later(g: G, dest: &mut T) -> impl FnOnce() + '_ // suggest: @@ -2033,7 +2153,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => String::new(), }; if !s.is_empty() { - s.push_str(" "); + s.push(' '); } s }; @@ -2171,7 +2291,7 @@ impl TyCategory { } pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { - match ty.kind { + match *ty.kind() { ty::Closure(def_id, _) => Some((Self::Closure, def_id)), ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs similarity index 72% rename from src/librustc_infer/infer/error_reporting/need_type_info.rs rename to compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index bf087dfacf..2f3089f1a9 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -6,9 +6,10 @@ use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; use rustc_middle::hir::map::Map; +use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::print::Print; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, DefIdTree, Ty}; +use rustc_middle::ty::{self, DefIdTree, InferConst, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::kw; use rustc_span::Span; @@ -53,7 +54,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { inner == self.target || match (inner.unpack(), self.target.unpack()) { (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => { - match (&inner_ty.kind, &target_ty.kind) { + match (inner_ty.kind(), target_ty.kind()) { ( &ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid)), @@ -175,7 +176,10 @@ fn closure_return_type_suggestion( suggestion, Applicability::HasPlaceholders, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); + err.span_label( + span, + InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr), + ); } /// Given a closure signature, return a `String` containing a list of all its argument types. @@ -216,65 +220,151 @@ impl Into for TypeAnnotationNeeded { } } +/// Information about a constant or a type containing inference variables. +pub struct InferenceDiagnosticsData { + pub name: String, + pub span: Option, + pub description: Cow<'static, str>, + pub parent_name: Option, + pub parent_description: Option<&'static str>, +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn extract_type_name( + /// Extracts data used by diagnostic for either types or constants + /// which were stuck during inference. + pub fn extract_inference_diagnostics_data( &self, - ty: Ty<'tcx>, + arg: GenericArg<'tcx>, highlight: Option, - ) -> (String, Option, Cow<'static, str>, Option, Option<&'static str>) { - if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind { - let mut inner = self.inner.borrow_mut(); - let ty_vars = &inner.type_variables(); - let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind { - let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); - let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id { - let parent_name = self - .tcx - .def_key(parent_def_id) - .disambiguated_data - .data - .get_opt_name() - .map(|parent_symbol| parent_symbol.to_string()); - - (parent_name, Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id))) - } else { - (None, None) - }; + ) -> InferenceDiagnosticsData { + match arg.unpack() { + GenericArgKind::Type(ty) => { + if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { + let mut inner = self.inner.borrow_mut(); + let ty_vars = &inner.type_variables(); + let var_origin = ty_vars.var_origin(ty_vid); + if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = + var_origin.kind + { + let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); + let (parent_name, parent_description) = + if let Some(parent_def_id) = parent_def_id { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); + + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; + + if name != kw::SelfUpper { + return InferenceDiagnosticsData { + name: name.to_string(), + span: Some(var_origin.span), + description: "type parameter".into(), + parent_name, + parent_description, + }; + } + } + } - if name != kw::SelfUpper { - return ( - name.to_string(), - Some(var_origin.span), - "type parameter".into(), - parent_name, - parent_desc, - ); + let mut s = String::new(); + let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); + if let Some(highlight) = highlight { + printer.region_highlight_mode = highlight; + } + let _ = ty.print(printer); + InferenceDiagnosticsData { + name: s, + span: None, + description: ty.prefix_string(), + parent_name: None, + parent_description: None, } } - } + GenericArgKind::Const(ct) => { + if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { + let origin = + self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; + if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) = + origin.kind + { + let parent_def_id = self.tcx.parent(def_id); + let (parent_name, parent_description) = + if let Some(parent_def_id) = parent_def_id { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); + + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; + + return InferenceDiagnosticsData { + name: name.to_string(), + span: Some(origin.span), + description: "const parameter".into(), + parent_name, + parent_description, + }; + } - let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); - if let Some(highlight) = highlight { - printer.region_highlight_mode = highlight; + debug_assert!(!origin.span.is_dummy()); + let mut s = String::new(); + let mut printer = + ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS); + if let Some(highlight) = highlight { + printer.region_highlight_mode = highlight; + } + let _ = ct.print(printer); + InferenceDiagnosticsData { + name: s, + span: Some(origin.span), + description: "the constant".into(), + parent_name: None, + parent_description: None, + } + } else { + bug!("unexpect const: {:?}", ct); + } + } + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), } - let _ = ty.print(printer); - (s, None, ty.prefix_string(), None, None) } - // FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well. - pub fn need_type_info_err( + pub fn emit_inference_failure_err( &self, body_id: Option, span: Span, - ty: Ty<'tcx>, + arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { - let ty = self.resolve_vars_if_possible(&ty); - let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); + let arg = self.resolve_vars_if_possible(&arg); + let arg_data = self.extract_inference_diagnostics_data(arg, None); + let kind_str = match arg.unpack() { + GenericArgKind::Type(_) => "type", + GenericArgKind::Const(_) => "the value", + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + }; - let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span); + let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -288,7 +378,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { None }; printer.name_resolver = Some(Box::new(&getter)); - let _ = if let ty::FnDef(..) = ty.kind { + let _ = if let ty::FnDef(..) = ty.kind() { // We don't want the regular output for `fn`s because it includes its path in // invalid pseudo-syntax, we want the `fn`-pointer output instead. ty.fn_sig(self.tcx).print(printer) @@ -304,7 +394,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let err_span = if let Some(pattern) = local_visitor.found_arg_pattern { pattern.span - } else if let Some(span) = name_sp { + } else if let Some(span) = arg_data.span { // `span` here lets us point at `sum` instead of the entire right hand side expr: // error[E0282]: type annotations needed // --> file2.rs:3:15 @@ -336,7 +426,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) { (_, Some(_)) => String::new(), - (Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => { + (Some(ty), _) if ty.is_closure() => { + let substs = + if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() }; let fn_sig = substs.as_closure().sig(); let args = closure_args(&fn_sig); let ret = fn_sig.output().skip_binder().to_string(); @@ -349,7 +441,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => String::new(), }; - // When `name` corresponds to a type argument, show the path of the full type we're + // When `arg_data.name` corresponds to a type argument, show the path of the full type we're // trying to infer. In the following example, `ty_msg` contains // " in `std::result::Result`": // ``` @@ -370,7 +462,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); let suffix = match local_visitor.found_node_ty { - Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => { + Some(ty) if ty.is_closure() => { + let substs = + if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() }; let fn_sig = substs.as_closure().sig(); let ret = fn_sig.output().skip_binder().to_string(); @@ -386,11 +480,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &mut err, &decl.output, self.tcx.hir().body(body_id), - &descr, - &name, + &arg_data.description, + &arg_data.name, &ret, - parent_name, - parent_descr, + arg_data.parent_name, + arg_data.parent_description, ); // We don't want to give the other suggestions when the problem is the // closure return type. @@ -404,15 +498,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // nudge them in the right direction. format!("a boxed closure type like `Box {}>`", args, ret) } - Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => { + Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => { let ty = ty_to_string(ty); format!("the explicit type `{}`, with the type parameters specified", ty) } - Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => { + Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => { let ty = ty_to_string(ty); format!( "the explicit type `{}`, where the type parameter `{}` is specified", - ty, name, + ty, arg_data.name, ) } _ => "a type".to_string(), @@ -529,7 +623,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // | ^^^ cannot infer type for `S` // | // = note: type must be known at this point - let span = name_sp.unwrap_or(err_span); + let span = arg_data.span.unwrap_or(err_span); if !err .span .span_labels() @@ -540,43 +634,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Avoid multiple labels pointing at `span`. err.span_label( span, - InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr), + InferCtxt::cannot_infer_msg( + kind_str, + &arg_data.name, + &arg_data.description, + arg_data.parent_name, + arg_data.parent_description, + ), ); } err } - // FIXME(const_generics): We should either try and merge this with `need_type_info_err` - // or improve the errors created here. - // - // Unlike for type inference variables, we don't yet store the origin of const inference variables. - // This is needed for to get a more relevant error span. - pub fn need_type_info_err_const( - &self, - body_id: Option, - span: Span, - ct: &'tcx ty::Const<'tcx>, - error_code: TypeAnnotationNeeded, - ) -> DiagnosticBuilder<'tcx> { - let mut local_visitor = FindHirNodeVisitor::new(&self, ct.into(), span); - if let Some(body_id) = body_id { - let expr = self.tcx.hir().expect_expr(body_id.hir_id); - local_visitor.visit_expr(expr); - } - - let error_code = error_code.into(); - let mut err = self.tcx.sess.struct_span_err_with_code( - local_visitor.target_span, - "type annotations needed", - error_code, - ); - - err.note("unable to infer the value of a const parameter"); - - err - } - /// If the `FnSig` for the method call can be found and type arguments are identified as /// needed, suggest annotating the call, otherwise point out the resulting type of the call. fn annotate_method_call( @@ -611,11 +681,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let sig = self.tcx.fn_sig(did); let bound_output = sig.output(); let output = bound_output.skip_binder(); - err.span_label(e.span, &format!("this method call resolves to `{:?}`", output)); - let kind = &output.kind; + err.span_label(e.span, &format!("this method call resolves to `{}`", output)); + let kind = output.kind(); if let ty::Projection(proj) = kind { if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) { - err.span_label(span, &format!("`{:?}` defined here", output)); + err.span_label(span, &format!("`{}` defined here", output)); } } } @@ -630,7 +700,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); + let data = self.extract_inference_diagnostics_data(ty.into(), None); let mut err = struct_span_err!( self.tcx.sess, @@ -639,18 +709,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "type inside {} must be known in this context", kind, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); + err.span_label( + span, + InferCtxt::cannot_infer_msg( + "type", + &data.name, + &data.description, + data.parent_name, + data.parent_description, + ), + ); err } - fn missing_type_msg( + fn cannot_infer_msg( + kind_str: &str, type_name: &str, descr: &str, parent_name: Option, parent_descr: Option<&str>, - ) -> Cow<'static, str> { + ) -> String { if type_name == "_" { - "cannot infer type".into() + format!("cannot infer {}", kind_str) } else { let parent_desc = if let Some(parent_name) = parent_name { let parent_type_descr = if let Some(parent_descr) = parent_descr { @@ -664,7 +744,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "".to_string() }; - format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into() + // FIXME: We really shouldn't be dealing with strings here + // but instead use a sensible enum for cases like this. + let preposition = if "the value" == kind_str { "of" } else { "for" }; + // For example: "cannot infer type for type parameter `T`" + format!( + "cannot infer {} {} {} `{}`{}", + kind_str, preposition, descr, type_name, parent_desc + ) + .into() } } } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs similarity index 100% rename from src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs diff --git a/src/librustc_infer/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 similarity index 100% rename from src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs similarity index 100% rename from src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs similarity index 98% rename from src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 89142edb2d..e3c613b1d6 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -85,7 +85,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { debug!("try_report_named_anon_conflict: ret ty {:?}", ty); if sub == &ty::ReStatic - && v.0.into_iter().find(|t| t.span.desugaring_kind().is_none()).is_some() + && v.0.into_iter().any(|t| t.span.desugaring_kind().is_none()) { // If the failure is due to a `'static` requirement coming from a `dyn` or // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs similarity index 100% rename from src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs diff --git a/src/librustc_infer/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 similarity index 96% rename from src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 7493b8b0a9..e9d5ebad7d 100644 --- a/src/librustc_infer/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 @@ -39,6 +39,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ) if **sub_r == RegionKind::ReStatic => { // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`. if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { + // This may have a closure and it would cause ICE + // through `find_param_with_region` (#78262). + let anon_reg_sup = tcx.is_suitable_region(sup_r)?; + let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); + if fn_returns.is_empty() { + return None; + } + let param = self.find_param_with_region(sup_r, sub_r)?; let lifetime = if sup_r.has_name() { format!("lifetime `{}`", sup_r) @@ -465,7 +473,7 @@ struct TraitObjectVisitor(Vec); impl TypeVisitor<'_> for TraitObjectVisitor { fn visit_ty(&mut self, t: Ty<'_>) -> bool { - match t.kind { + match t.kind() { ty::Dynamic(preds, RegionKind::ReStatic) => { if let Some(def_id) = preds.principal_def_id() { self.0.push(def_id); @@ -488,18 +496,16 @@ impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor { } fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { - match t.kind { - TyKind::TraitObject( - poly_trait_refs, - Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, - ) => { - for ptr in poly_trait_refs { - if Some(self.1) == ptr.trait_ref.trait_def_id() { - self.0.push(ptr.span); - } + if let TyKind::TraitObject( + poly_trait_refs, + Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, + ) = t.kind + { + for ptr in poly_trait_refs { + if Some(self.1) == ptr.trait_ref.trait_def_id() { + self.0.push(ptr.span); } } - _ => {} } walk_ty(self, t); } diff --git a/src/librustc_infer/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 similarity index 96% rename from src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 788eabf296..c061f485c1 100644 --- a/src/librustc_infer/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 @@ -58,8 +58,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .tcx() .sess .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); - err.span_label(sp, &format!("found `{:?}`", found)); - err.span_label(trait_sp, &format!("expected `{:?}`", expected)); + err.span_label(sp, &format!("found `{}`", found)); + err.span_label(trait_sp, &format!("expected `{}`", expected)); // Get the span of all the used type parameters in the method. let assoc_item = self.tcx().associated_item(trait_def_id); @@ -92,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.note_expected_found(&"", expected, &"", found); } else { // This fallback shouldn't be necessary, but let's keep it in just in case. - err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); + err.note(&format!("expected `{}`\n found `{}`", expected, found)); } err.span_help( type_param_span, diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs similarity index 99% rename from src/librustc_infer/infer/error_reporting/nice_region_error/util.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 6e2d49f1ad..c055fed43f 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { decl: &hir::FnDecl<'_>, ) -> Option { let ret_ty = self.tcx().type_of(scope_def_id); - if let ty::FnDef(_, _) = ret_ty.kind { + if let ty::FnDef(_, _) = ret_ty.kind() { let sig = ret_ty.fn_sig(self.tcx()); let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&sig.output()); diff --git a/src/librustc_infer/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs similarity index 100% rename from src/librustc_infer/infer/error_reporting/note.rs rename to compiler/rustc_infer/src/infer/error_reporting/note.rs diff --git a/src/librustc_infer/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs similarity index 100% rename from src/librustc_infer/infer/free_regions.rs rename to compiler/rustc_infer/src/infer/free_regions.rs diff --git a/src/librustc_infer/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs similarity index 99% rename from src/librustc_infer/infer/freshen.rs rename to compiler/rustc_infer/src/infer/freshen.rs index 02bebe10ed..b3d7876c6e 100644 --- a/src/librustc_infer/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { let tcx = self.infcx.tcx; - match t.kind { + match *t.kind() { ty::Infer(ty::TyVar(v)) => { let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known(); self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy) diff --git a/src/librustc_infer/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs similarity index 99% rename from src/librustc_infer/infer/fudge.rs rename to compiler/rustc_infer/src/infer/fudge.rs index c6651108df..d7bc636db8 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match *ty.kind() { ty::Infer(ty::InferTy::TyVar(vid)) => { if self.type_vars.0.contains(&vid) { // This variable was created during the fudging. diff --git a/src/librustc_infer/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs similarity index 100% rename from src/librustc_infer/infer/glb.rs rename to compiler/rustc_infer/src/infer/glb.rs diff --git a/src/librustc_infer/infer/higher_ranked/README.md b/compiler/rustc_infer/src/infer/higher_ranked/README.md similarity index 100% rename from src/librustc_infer/infer/higher_ranked/README.md rename to compiler/rustc_infer/src/infer/higher_ranked/README.md diff --git a/src/librustc_infer/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs similarity index 100% rename from src/librustc_infer/infer/higher_ranked/mod.rs rename to compiler/rustc_infer/src/infer/higher_ranked/mod.rs diff --git a/src/librustc_infer/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs similarity index 99% rename from src/librustc_infer/infer/lattice.rs rename to compiler/rustc_infer/src/infer/lattice.rs index 1bf43e74dc..c47d476963 100644 --- a/src/librustc_infer/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -58,7 +58,7 @@ where let infcx = this.infcx(); let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { // If one side is known to be a variable and one is not, // create a variable (`v`) to represent the LUB. Make sure to // relate `v` to the non-type-variable first (by passing it diff --git a/src/librustc_infer/infer/lexical_region_resolve/README.md b/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md similarity index 100% rename from src/librustc_infer/infer/lexical_region_resolve/README.md rename to compiler/rustc_infer/src/infer/lexical_region_resolve/README.md diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs similarity index 100% rename from src/librustc_infer/infer/lexical_region_resolve/mod.rs rename to compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs diff --git a/src/librustc_infer/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs similarity index 98% rename from src/librustc_infer/infer/lub.rs rename to compiler/rustc_infer/src/infer/lub.rs index 3e2ea3d0f8..9f43fac091 100644 --- a/src/librustc_infer/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -50,7 +50,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), // FIXME(#41044) -- not correct, need test - ty::Bivariant => Ok(a.clone()), + ty::Bivariant => Ok(a), ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } } diff --git a/src/librustc_infer/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs similarity index 99% rename from src/librustc_infer/infer/mod.rs rename to compiler/rustc_infer/src/infer/mod.rs index 3744ad5d03..07a55c7f85 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -21,7 +21,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; -use rustc_middle::mir::interpret::ConstEvalResult; +use rustc_middle::mir::interpret::EvalToConstValueResult; use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; @@ -680,7 +680,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { - match ty.kind { + match *ty.kind() { ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid), _ => false, } @@ -693,7 +693,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric { use rustc_middle::ty::error::UnconstrainedNumeric::Neither; use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; - match ty.kind { + match *ty.kind() { ty::Infer(ty::IntVar(vid)) => { if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() { Neither @@ -1163,7 +1163,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } GenericParamDefKind::Const { .. } => { let origin = ConstVariableOrigin { - kind: ConstVariableOriginKind::ConstParameterDefinition(param.name), + kind: ConstVariableOriginKind::ConstParameterDefinition( + param.name, + param.def_id, + ), span, }; let const_var_id = @@ -1275,7 +1278,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Gives temporary access to the region constraint data. - #[allow(non_camel_case_types)] // bug with impl trait pub fn with_region_constraints( &self, op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, @@ -1542,7 +1544,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { substs: SubstsRef<'tcx>, promoted: Option, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { let mut original_values = OriginalQueryValues::default(); let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values); @@ -1557,7 +1559,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// not a type variable, just return it unmodified. // FIXME(eddyb) inline into `ShallowResolver::visit_ty`. fn shallow_resolve_ty(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match typ.kind { + match *typ.kind() { ty::Infer(ty::TyVar(v)) => { // Not entirely obvious: if `typ` is a type variable, // it can be resolved to an int/float variable, which @@ -1677,7 +1679,7 @@ impl 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 { - match ty.kind { + match *ty.kind() { ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)), ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)), ty::Infer(ty::FloatVar(v)) => Some(TyOrConstInferVar::TyFloat(v)), diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs similarity index 99% rename from src/librustc_infer/infer/nll_relate/mod.rs rename to compiler/rustc_infer/src/infer/nll_relate/mod.rs index 3f5ed36035..839891f322 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -265,7 +265,7 @@ where use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_span::DUMMY_SP; - match value_ty.kind { + match *value_ty.kind() { ty::Projection(other_projection_ty) => { let var = self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, @@ -311,7 +311,7 @@ where // This only presently applies to chalk integration, as NLL // doesn't permit type variables to appear on both sides (and // doesn't use lazy norm). - match value_ty.kind { + match *value_ty.kind() { ty::Infer(ty::TyVar(value_vid)) => { // Two type variables: just equate them. self.infcx.inner.borrow_mut().type_variables().equate(vid, value_vid); @@ -531,7 +531,7 @@ where } } - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (_, &ty::Infer(ty::TyVar(vid))) => { if D::forbid_inference_vars() { // Forbid inference variables in the RHS. @@ -868,7 +868,7 @@ where debug!("TypeGeneralizer::tys(a={:?})", a); - match a.kind { + match *a.kind() { ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) if D::forbid_inference_vars() => { diff --git a/src/librustc_infer/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs similarity index 100% rename from src/librustc_infer/infer/outlives/env.rs rename to compiler/rustc_infer/src/infer/outlives/env.rs diff --git a/src/librustc_infer/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs similarity index 90% rename from src/librustc_infer/infer/outlives/mod.rs rename to compiler/rustc_infer/src/infer/outlives/mod.rs index a1e7f1fa3e..de98cccf25 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -26,7 +26,8 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { Some(OutlivesBound::RegionSubRegion(r_b, r_a)) } diff --git a/src/librustc_infer/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs similarity index 99% rename from src/librustc_infer/infer/outlives/obligations.rs rename to compiler/rustc_infer/src/infer/outlives/obligations.rs index 48f6d937f2..2851da89ab 100644 --- a/src/librustc_infer/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -383,7 +383,7 @@ where // #55756) in cases where you have e.g., `>::Item: // 'a` in the environment but `trait Foo<'b> { type Item: 'b // }` in the trait definition. - approx_env_bounds.retain(|bound| match bound.0.kind { + approx_env_bounds.retain(|bound| match *bound.0.kind() { ty::Projection(projection_ty) => self .verify_bound .projection_declared_bounds_from_trait(projection_ty) diff --git a/src/librustc_infer/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs similarity index 99% rename from src/librustc_infer/infer/outlives/verify.rs rename to compiler/rustc_infer/src/infer/outlives/verify.rs index 5a8368700b..21b0836563 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,9 +1,9 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::captures::Captures; +use rustc_data_structures::mini_set::MiniSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; -use rustc_middle::ty::walk::MiniSet; use rustc_middle::ty::{self, Ty, TyCtxt}; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` @@ -46,7 +46,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { ty: Ty<'tcx>, visited: &mut MiniSet>, ) -> VerifyBound<'tcx> { - match ty.kind { + match *ty.kind() { ty::Param(p) => self.param_bound(p), ty::Projection(data) => self.projection_bound(data, visited), ty::FnDef(_, substs) => { @@ -126,7 +126,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx); let erased_projection_ty = self.tcx.erase_regions(&projection_ty); self.declared_generic_bounds_from_env_with_compare_fn(|ty| { - if let ty::Projection(..) = ty.kind { + if let ty::Projection(..) = ty.kind() { let erased_ty = self.tcx.erase_regions(&ty); erased_ty == erased_projection_ty } else { diff --git a/src/librustc_infer/infer/region_constraints/README.md b/compiler/rustc_infer/src/infer/region_constraints/README.md similarity index 100% rename from src/librustc_infer/infer/region_constraints/README.md rename to compiler/rustc_infer/src/infer/region_constraints/README.md diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs similarity index 100% rename from src/librustc_infer/infer/region_constraints/leak_check.rs rename to compiler/rustc_infer/src/infer/region_constraints/leak_check.rs diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs similarity index 100% rename from src/librustc_infer/infer/region_constraints/mod.rs rename to compiler/rustc_infer/src/infer/region_constraints/mod.rs diff --git a/src/librustc_infer/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs similarity index 99% rename from src/librustc_infer/infer/resolve.rs rename to compiler/rustc_infer/src/infer/resolve.rs index 74f365ced2..337772d70b 100644 --- a/src/librustc_infer/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -124,7 +124,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { - if let ty::Infer(infer_ty) = t.kind { + if let ty::Infer(infer_ty) = *t.kind() { // Since we called `shallow_resolve` above, this must // be an (as yet...) unresolved inference variable. let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { @@ -191,7 +191,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { let t = self.infcx.shallow_resolve(t); - match t.kind { + match *t.kind() { ty::Infer(ty::TyVar(vid)) => { self.err = Some(FixupError::UnresolvedTy(vid)); self.tcx().ty_error() diff --git a/src/librustc_infer/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs similarity index 99% rename from src/librustc_infer/infer/sub.rs rename to compiler/rustc_infer/src/infer/sub.rs index 308f884f9a..a676c5e65a 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -83,7 +83,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { let infcx = self.fields.infcx; let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { // Shouldn't have any LBR here, so we can safely put // this under a binder below without fear of accidental diff --git a/src/librustc_infer/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs similarity index 99% rename from src/librustc_infer/infer/type_variable.rs rename to compiler/rustc_infer/src/infer/type_variable.rs index 53c7dcc637..35b97fff3d 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -306,7 +306,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// instantiated, then return the with which it was /// instantiated. Otherwise, returns `t`. pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match *t.kind() { ty::Infer(ty::TyVar(v)) => match self.probe(v) { TypeVariableValue::Unknown { .. } => t, TypeVariableValue::Known { value } => value, diff --git a/src/librustc_infer/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs similarity index 100% rename from src/librustc_infer/infer/undo_log.rs rename to compiler/rustc_infer/src/infer/undo_log.rs diff --git a/src/librustc_infer/lib.rs b/compiler/rustc_infer/src/lib.rs similarity index 88% rename from src/librustc_infer/lib.rs rename to compiler/rustc_infer/src/lib.rs index e05041d884..ea9a466134 100644 --- a/src/librustc_infer/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -12,8 +12,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(bindings_after_at)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -23,7 +22,6 @@ #![feature(never_type)] #![feature(or_patterns)] #![feature(in_band_lifetimes)] -#![feature(crate_visibility_modifier)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/src/librustc_infer/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs similarity index 100% rename from src/librustc_infer/traits/engine.rs rename to compiler/rustc_infer/src/traits/engine.rs diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs similarity index 100% rename from src/librustc_infer/traits/error_reporting/mod.rs rename to compiler/rustc_infer/src/traits/error_reporting/mod.rs diff --git a/src/librustc_infer/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs similarity index 98% rename from src/librustc_infer/traits/mod.rs rename to compiler/rustc_infer/src/traits/mod.rs index 7e7c8588ff..a3c4920fa8 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -57,7 +57,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PredicateObligation<'_>, 40); +static_assert_size!(PredicateObligation<'_>, 32); pub type Obligations<'tcx, O> = Vec>; pub type PredicateObligations<'tcx> = Vec>; diff --git a/src/librustc_infer/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs similarity index 100% rename from src/librustc_infer/traits/project.rs rename to compiler/rustc_infer/src/traits/project.rs diff --git a/src/librustc_infer/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs similarity index 100% rename from src/librustc_infer/traits/structural_impls.rs rename to compiler/rustc_infer/src/traits/structural_impls.rs diff --git a/src/librustc_infer/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs similarity index 98% rename from src/librustc_infer/traits/util.rs rename to compiler/rustc_infer/src/traits/util.rs index 93fc7f1f3b..9c0d934a03 100644 --- a/src/librustc_infer/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -236,6 +236,9 @@ impl Elaborator<'tcx> { .map(|predicate| predicate_obligation(predicate, None)), ); } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + // Nothing to elaborate + } } } } diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml new file mode 100644 index 0000000000..e214493a56 --- /dev/null +++ b/compiler/rustc_interface/Cargo.toml @@ -0,0 +1,54 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_interface" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +libc = "0.2" +tracing = "0.1" +rayon = { version = "0.3.0", package = "rustc-rayon" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } +rustc_attr = { path = "../rustc_attr" } +rustc_builtin_macros = { path = "../rustc_builtin_macros" } +rustc_expand = { path = "../rustc_expand" } +rustc_parse = { path = "../rustc_parse" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_middle = { path = "../rustc_middle" } +rustc_ast_lowering = { path = "../rustc_ast_lowering" } +rustc_ast_passes = { path = "../rustc_ast_passes" } +rustc_incremental = { path = "../rustc_incremental" } +rustc_traits = { path = "../rustc_traits" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } +rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } +rustc_codegen_llvm = { path = "../rustc_codegen_llvm", optional = true } +rustc_hir = { path = "../rustc_hir" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_mir = { path = "../rustc_mir" } +rustc_mir_build = { path = "../rustc_mir_build" } +rustc_passes = { path = "../rustc_passes" } +rustc_typeck = { path = "../rustc_typeck" } +rustc_lint = { path = "../rustc_lint" } +rustc_errors = { path = "../rustc_errors" } +rustc_plugin_impl = { path = "../rustc_plugin_impl" } +rustc_privacy = { path = "../rustc_privacy" } +rustc_resolve = { path = "../rustc_resolve" } +rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_ty = { path = "../rustc_ty" } +tempfile = "3.0.5" + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["libloaderapi"] } + +[dev-dependencies] +rustc_target = { path = "../rustc_target" } + +[features] +llvm = ['rustc_codegen_llvm'] diff --git a/src/librustc_interface/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs similarity index 100% rename from src/librustc_interface/callbacks.rs rename to compiler/rustc_interface/src/callbacks.rs diff --git a/src/librustc_interface/interface.rs b/compiler/rustc_interface/src/interface.rs similarity index 96% rename from src/librustc_interface/interface.rs rename to compiler/rustc_interface/src/interface.rs index 4d84462c42..73a51ad477 100644 --- a/src/librustc_interface/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -154,6 +154,10 @@ pub struct Config { pub override_queries: Option, + /// This is a callback from the driver that is called to create a codegen backend. + pub make_codegen_backend: + Option Box + Send>>, + /// Registry of diagnostics codes. pub registry: Registry, } @@ -167,6 +171,7 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R config.file_loader, config.input_path.clone(), config.lint_caps, + config.make_codegen_backend, registry.clone(), ); diff --git a/src/librustc_interface/lib.rs b/compiler/rustc_interface/src/lib.rs similarity index 95% rename from src/librustc_interface/lib.rs rename to compiler/rustc_interface/src/lib.rs index fe40c615f7..88d2efe96d 100644 --- a/src/librustc_interface/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -4,6 +4,7 @@ #![feature(nll)] #![feature(generator_trait)] #![feature(generators)] +#![feature(once_cell)] #![recursion_limit = "256"] mod callbacks; diff --git a/src/librustc_interface/passes.rs b/compiler/rustc_interface/src/passes.rs similarity index 99% rename from src/librustc_interface/passes.rs rename to compiler/rustc_interface/src/passes.rs index 007dbfb9fd..77d80bb542 100644 --- a/src/librustc_interface/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -2,7 +2,6 @@ use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; use crate::util; -use once_cell::sync::Lazy; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; @@ -47,6 +46,7 @@ use std::any::Any; use std::cell::RefCell; use std::ffi::OsString; use std::io::{self, BufWriter, Write}; +use std::lazy::SyncLazy; use std::path::PathBuf; use std::rc::Rc; use std::{env, fs, iter, mem}; @@ -292,6 +292,7 @@ fn configure_and_expand_inner<'a>( trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, span_debug: sess.opts.debugging_opts.span_debug, + proc_macro_backtrace: sess.opts.debugging_opts.proc_macro_backtrace, ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; @@ -697,7 +698,7 @@ pub fn prepare_outputs( Ok(outputs) } -pub static DEFAULT_QUERY_PROVIDERS: Lazy = Lazy::new(|| { +pub static DEFAULT_QUERY_PROVIDERS: SyncLazy = SyncLazy::new(|| { let providers = &mut Providers::default(); providers.analysis = analysis; proc_macro_decls::provide(providers); @@ -720,7 +721,7 @@ pub static DEFAULT_QUERY_PROVIDERS: Lazy = Lazy::new(|| { *providers }); -pub static DEFAULT_EXTERN_QUERY_PROVIDERS: Lazy = Lazy::new(|| { +pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy = SyncLazy::new(|| { let mut extern_providers = *DEFAULT_QUERY_PROVIDERS; rustc_metadata::provide_extern(&mut extern_providers); rustc_codegen_ssa::provide_extern(&mut extern_providers); diff --git a/src/librustc_interface/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs similarity index 100% rename from src/librustc_interface/proc_macro_decls.rs rename to compiler/rustc_interface/src/proc_macro_decls.rs diff --git a/src/librustc_interface/queries.rs b/compiler/rustc_interface/src/queries.rs similarity index 100% rename from src/librustc_interface/queries.rs rename to compiler/rustc_interface/src/queries.rs diff --git a/src/librustc_interface/tests.rs b/compiler/rustc_interface/src/tests.rs similarity index 99% rename from src/librustc_interface/tests.rs rename to compiler/rustc_interface/src/tests.rs index e94745519a..07ce9d0cd9 100644 --- a/src/librustc_interface/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -40,6 +40,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { DiagnosticOutput::Default, Default::default(), None, + None, ); (sess, cfg) } @@ -402,6 +403,7 @@ fn test_codegen_options_tracking_hash() { // `link_arg` is omitted because it just forwards to `link_args`. untracked!(link_args, vec![String::from("abc"), String::from("def")]); untracked!(link_dead_code, Some(true)); + untracked!(link_self_contained, Some(true)); untracked!(linker, Some(PathBuf::from("linker"))); untracked!(linker_flavor, Some(LinkerFlavor::Gcc)); untracked!(no_stack_check, true); @@ -502,6 +504,7 @@ fn test_debugging_options_tracking_hash() { untracked!(print_llvm_passes, true); untracked!(print_mono_items, Some(String::from("abc"))); untracked!(print_type_sizes, true); + untracked!(proc_macro_backtrace, true); untracked!(query_dep_graph, true); untracked!(query_stats, true); untracked!(save_analysis, true); @@ -516,6 +519,7 @@ fn test_debugging_options_tracking_hash() { untracked!(time_llvm_passes, true); untracked!(time_passes, true); untracked!(trace_macros, true); + untracked!(trim_diagnostic_paths, false); untracked!(ui_testing, true); untracked!(unpretty, Some("expanded".to_string())); untracked!(unstable_options, true); @@ -564,6 +568,7 @@ fn test_debugging_options_tracking_hash() { tracked!(osx_rpath_install_name, true); tracked!(panic_abort_tests, true); tracked!(plt, Some(true)); + tracked!(precise_enum_drop_elaboration, false); tracked!(print_fuel, Some("abc".to_string())); tracked!(profile, true); tracked!(profile_emit, Some(PathBuf::from("abc"))); diff --git a/src/librustc_interface/util.rs b/compiler/rustc_interface/src/util.rs similarity index 96% rename from src/librustc_interface/util.rs rename to compiler/rustc_interface/src/util.rs index 8816ba198c..7ace707cc8 100644 --- a/src/librustc_interface/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -25,6 +25,7 @@ use rustc_span::symbol::{sym, Symbol}; use smallvec::SmallVec; use std::env; use std::io::{self, Write}; +use std::lazy::SyncOnceCell; use std::mem; use std::ops::DerefMut; use std::path::{Path, PathBuf}; @@ -62,8 +63,20 @@ pub fn create_session( file_loader: Option>, input_path: Option, lint_caps: FxHashMap, + make_codegen_backend: Option< + Box Box + Send>, + >, descriptions: Registry, ) -> (Lrc, Lrc>) { + let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { + make_codegen_backend(&sopts) + } else { + get_codegen_backend(&sopts) + }; + + // target_override is documented to be called before init(), so this is okay + let target_override = codegen_backend.target_override(&sopts); + let mut sess = session::build_session( sopts, input_path, @@ -71,9 +84,10 @@ pub fn create_session( diagnostic_output, lint_caps, file_loader, + target_override, ); - let codegen_backend = get_codegen_backend(&sess); + codegen_backend.init(&sess); let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); add_configuration(&mut cfg, &mut sess, &*codegen_backend); @@ -218,13 +232,13 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box { } } -pub fn get_codegen_backend(sess: &Session) -> Box { +pub fn get_codegen_backend(sopts: &config::Options) -> Box { static INIT: Once = Once::new(); static mut LOAD: fn() -> Box = || unreachable!(); INIT.call_once(|| { - let codegen_name = sess.opts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm"); + let codegen_name = sopts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm"); let backend = match codegen_name { filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()), codegen_name => get_builtin_codegen_backend(codegen_name), @@ -234,17 +248,14 @@ pub fn get_codegen_backend(sess: &Session) -> Box { LOAD = backend; } }); - let backend = unsafe { LOAD() }; - backend.init(sess); - backend + unsafe { LOAD() } } // This is used for rustdoc, but it uses similar machinery to codegen backend // loading, so we leave the code here. It is potentially useful for other tools // that want to invoke the rustc binary while linking to rustc as well. pub fn rustc_path<'a>() -> Option<&'a Path> { - static RUSTC_PATH: once_cell::sync::OnceCell> = - once_cell::sync::OnceCell::new(); + static RUSTC_PATH: SyncOnceCell> = SyncOnceCell::new(); const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR"); @@ -693,6 +704,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { rules, id: resolver.next_node_id(), span: rustc_span::DUMMY_SP, + tokens: None, } } @@ -709,6 +721,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { id: resolver.next_node_id(), kind: ast::StmtKind::Expr(expr), span: rustc_span::DUMMY_SP, + tokens: None, } } @@ -725,6 +738,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { id: self.resolver.next_node_id(), span: rustc_span::DUMMY_SP, kind: ast::StmtKind::Expr(loop_expr), + tokens: None, }; if self.within_static_or_const { diff --git a/src/librustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml similarity index 93% rename from src/librustc_lexer/Cargo.toml rename to compiler/rustc_lexer/Cargo.toml index 28b56f6fef..12101776de 100644 --- a/src/librustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -14,11 +14,10 @@ Rust lexer used by rustc. No stability guarantees are provided. # This will be used when publishing this crate as `rustc-ap-rustc_lexer`. [lib] doctest = false -name = "rustc_lexer" # Note that this crate purposefully does not depend on other rustc crates [dependencies] unicode-xid = "0.2.0" [dev-dependencies] -expect-test = "0.1" +expect-test = "1.0" diff --git a/src/librustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs similarity index 100% rename from src/librustc_lexer/src/cursor.rs rename to compiler/rustc_lexer/src/cursor.rs diff --git a/src/librustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs similarity index 98% rename from src/librustc_lexer/src/lib.rs rename to compiler/rustc_lexer/src/lib.rs index b7d6194cd7..d784a86f14 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -2,7 +2,7 @@ //! //! The idea with `librustc_lexer` is to make a reusable library, //! by separating out pure lexing and rustc-specific concerns, like spans, -//! error reporting an interning. So, rustc_lexer operates directly on `&str`, +//! error reporting, and interning. So, rustc_lexer operates directly on `&str`, //! produces simple tokens which are a pair of type-tag and a bit of original text, //! and does not report errors, instead storing them as flags on the token. //! @@ -191,12 +191,16 @@ pub fn strip_shebang(input: &str) -> Option { // For simplicity we consider any line starting with `#!` a shebang, // regardless of restrictions put on shebangs by specific platforms. if let Some(input_tail) = input.strip_prefix("#!") { - // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe - // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level), + // Ok, this is a shebang but if the next non-whitespace token is `[`, // then it may be valid Rust code, so consider it Rust code. - let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| - !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. }) - ); + let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| { + !matches!( + tok, + TokenKind::Whitespace + | TokenKind::LineComment { doc_style: None } + | TokenKind::BlockComment { doc_style: None, .. } + ) + }); if next_non_whitespace_token != Some(TokenKind::OpenBracket) { // No other choice than to consider this a shebang. return Some(2 + input_tail.lines().next().unwrap_or_default().len()); diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs new file mode 100644 index 0000000000..94017b7b28 --- /dev/null +++ b/compiler/rustc_lexer/src/tests.rs @@ -0,0 +1,287 @@ +use super::*; + +use expect_test::{expect, Expect}; + +fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option) { + let s = &format!("r{}", s); + let mut cursor = Cursor::new(s); + cursor.bump(); + let (n_hashes, err) = cursor.raw_double_quoted_string(0); + assert_eq!(n_hashes, expected_hashes); + assert_eq!(err, expected_err); +} + +#[test] +fn test_naked_raw_str() { + check_raw_str(r#""abc""#, 0, None); +} + +#[test] +fn test_raw_no_start() { + check_raw_str(r##""abc"#"##, 0, None); +} + +#[test] +fn test_too_many_terminators() { + // this error is handled in the parser later + check_raw_str(r###"#"abc"##"###, 1, None); +} + +#[test] +fn test_unterminated() { + check_raw_str( + r#"#"abc"#, + 1, + Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }), + ); + check_raw_str( + r###"##"abc"#"###, + 2, + Some(RawStrError::NoTerminator { + expected: 2, + found: 1, + possible_terminator_offset: Some(7), + }), + ); + // We're looking for "# not just any # + check_raw_str( + r###"##"abc#"###, + 2, + Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }), + ) +} + +#[test] +fn test_invalid_start() { + check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' })); +} + +#[test] +fn test_unterminated_no_pound() { + // https://github.com/rust-lang/rust/issues/70677 + check_raw_str( + r#"""#, + 0, + Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }), + ); +} + +#[test] +fn test_valid_shebang() { + // https://github.com/rust-lang/rust/issues/70528 + let input = "#!/usr/bin/rustrun\nlet x = 5;"; + assert_eq!(strip_shebang(input), Some(18)); +} + +#[test] +fn test_invalid_shebang_valid_rust_syntax() { + // https://github.com/rust-lang/rust/issues/70528 + let input = "#! [bad_attribute]"; + assert_eq!(strip_shebang(input), None); +} + +#[test] +fn test_shebang_second_line() { + // Because shebangs are interpreted by the kernel, they must be on the first line + let input = "\n#!/bin/bash"; + assert_eq!(strip_shebang(input), None); +} + +#[test] +fn test_shebang_space() { + let input = "#! /bin/bash"; + assert_eq!(strip_shebang(input), Some(input.len())); +} + +#[test] +fn test_shebang_empty_shebang() { + let input = "#! \n[attribute(foo)]"; + assert_eq!(strip_shebang(input), None); +} + +#[test] +fn test_invalid_shebang_comment() { + let input = "#!//bin/ami/a/comment\n["; + assert_eq!(strip_shebang(input), None) +} + +#[test] +fn test_invalid_shebang_another_comment() { + let input = "#!/*bin/ami/a/comment*/\n[attribute"; + assert_eq!(strip_shebang(input), None) +} + +#[test] +fn test_shebang_valid_rust_after() { + let input = "#!/*bin/ami/a/comment*/\npub fn main() {}"; + assert_eq!(strip_shebang(input), Some(23)) +} + +#[test] +fn test_shebang_followed_by_attrib() { + let input = "#!/bin/rust-scripts\n#![allow_unused(true)]"; + assert_eq!(strip_shebang(input), Some(19)); +} + +fn check_lexing(src: &str, expect: Expect) { + let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect(); + expect.assert_eq(&actual) +} + +#[test] +fn smoke_test() { + check_lexing( + "/* my source file */ fn main() { println!(\"zebra\"); }\n", + expect![[r#" + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 20 } + Token { kind: Whitespace, len: 1 } + Token { kind: Ident, len: 2 } + Token { kind: Whitespace, len: 1 } + Token { kind: Ident, len: 4 } + Token { kind: OpenParen, len: 1 } + Token { kind: CloseParen, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: OpenBrace, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: Ident, len: 7 } + Token { kind: Bang, len: 1 } + Token { kind: OpenParen, len: 1 } + Token { kind: Literal { kind: Str { terminated: true }, suffix_start: 7 }, len: 7 } + Token { kind: CloseParen, len: 1 } + Token { kind: Semi, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: CloseBrace, len: 1 } + Token { kind: Whitespace, len: 1 } + "#]], + ) +} + +#[test] +fn comment_flavors() { + check_lexing( + r" +// line +//// line as well +/// outer doc line +//! inner doc line +/* block */ +/**/ +/*** also block */ +/** outer doc block */ +/*! inner doc block */ +", + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: None }, len: 7 } + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: None }, len: 17 } + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: Some(Outer) }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: Some(Inner) }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: Some(Outer), terminated: true }, len: 22 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: Some(Inner), terminated: true }, len: 22 } + Token { kind: Whitespace, len: 1 } + "#]], + ) +} + +#[test] +fn nested_block_comments() { + check_lexing( + "/* /* */ */'a'", + expect![[r#" + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } + "#]], + ) +} + +#[test] +fn characters() { + check_lexing( + "'a' ' ' '\\n'", + expect![[r#" + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 4 }, len: 4 } + "#]], + ); +} + +#[test] +fn lifetime() { + check_lexing( + "'abc", + expect![[r#" + Token { kind: Lifetime { starts_with_number: false }, len: 4 } + "#]], + ); +} + +#[test] +fn raw_string() { + check_lexing( + "r###\"\"#a\\b\x00c\"\"###", + expect![[r#" + Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 17 }, len: 17 } + "#]], + ) +} + +#[test] +fn literal_suffixes() { + check_lexing( + r####" +'a' +b'a' +"a" +b"a" +1234 +0b101 +0xABC +1.0 +1.0e10 +2us +r###"raw"###suffix +br###"raw"###suffix +"####, + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Byte { terminated: true }, suffix_start: 4 }, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Str { terminated: true }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: ByteStr { terminated: true }, suffix_start: 4 }, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Int { base: Decimal, empty_int: false }, suffix_start: 4 }, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Int { base: Binary, empty_int: false }, suffix_start: 5 }, len: 5 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Int { base: Hexadecimal, empty_int: false }, suffix_start: 5 }, len: 5 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Float { base: Decimal, empty_exponent: false }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Float { base: Decimal, empty_exponent: false }, suffix_start: 6 }, len: 6 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Int { base: Decimal, empty_int: false }, suffix_start: 1 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 12 }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: RawByteStr { n_hashes: 3, err: None }, suffix_start: 13 }, len: 19 } + Token { kind: Whitespace, len: 1 } + "#]], + ) +} diff --git a/src/librustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs similarity index 100% rename from src/librustc_lexer/src/unescape.rs rename to compiler/rustc_lexer/src/unescape.rs diff --git a/src/librustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs similarity index 100% rename from src/librustc_lexer/src/unescape/tests.rs rename to compiler/rustc_lexer/src/unescape/tests.rs diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml new file mode 100644 index 0000000000..760a8e385d --- /dev/null +++ b/compiler/rustc_lint/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_lint" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.1" +unicode-security = "0.0.5" +rustc_middle = { path = "../rustc_middle" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr = { path = "../rustc_attr" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_target = { path = "../rustc_target" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_feature = { path = "../rustc_feature" } +rustc_index = { path = "../rustc_index" } +rustc_session = { path = "../rustc_session" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_lint/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs similarity index 73% rename from src/librustc_lint/array_into_iter.rs rename to compiler/rustc_lint/src/array_into_iter.rs index 9d74ad3b2f..e6be082da0 100644 --- a/src/librustc_lint/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -7,6 +7,31 @@ use rustc_session::lint::FutureIncompatibleInfo; use rustc_span::symbol::sym; declare_lint! { + /// The `array_into_iter` lint detects calling `into_iter` on arrays. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// [1, 2, 3].into_iter().for_each(|n| { *n; }); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the future, it is planned to add an `IntoIter` implementation for + /// arrays such that it will iterate over *values* of the array instead of + /// references. Due to how method resolution works, this will change + /// existing code that uses `into_iter` on arrays. The solution to avoid + /// this warning is to use `iter()` instead of `into_iter()`. + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #66145] for more details and a more thorough + /// description of the lint. + /// + /// [issue #66145]: https://github.com/rust-lang/rust/issues/66145 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub ARRAY_INTO_ITER, Warn, "detects calling `into_iter` on arrays", @@ -53,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { } // Make sure we found an array after peeling the boxes. - if !matches!(recv_ty.kind, ty::Array(..)) { + if !matches!(recv_ty.kind(), ty::Array(..)) { return; } @@ -66,9 +91,9 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { } // Emit lint diagnostic. - let target = match cx.typeck_results().expr_ty_adjusted(receiver_arg).kind { - ty::Ref(_, ty::TyS { kind: ty::Array(..), .. }, _) => "[T; N]", - ty::Ref(_, ty::TyS { kind: ty::Slice(..), .. }, _) => "[T]", + let target = match *cx.typeck_results().expr_ty_adjusted(receiver_arg).kind() { + ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]", + ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]", // We know the original first argument type is an array type, // we know that the first adjustment was an autoref coercion diff --git a/src/librustc_lint/builtin.rs b/compiler/rustc_lint/src/builtin.rs similarity index 80% rename from src/librustc_lint/builtin.rs rename to compiler/rustc_lint/src/builtin.rs index b337bf0a3f..abd899e8db 100644 --- a/src/librustc_lint/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,7 +21,8 @@ //! `late_lint_methods!` invocation in `lib.rs`. use crate::{ - types::CItemKind, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, + types::{transparent_newtype_field, CItemKind}, + EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, }; use rustc_ast::attr::{self, HasAttrs}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; @@ -38,9 +39,11 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind}; use rustc_hir::{HirId, HirIdSet, Node}; +use rustc_index::vec::Idx; use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt}; use rustc_session::lint::FutureIncompatibleInfo; use rustc_session::Session; use rustc_span::edition::Edition; @@ -59,6 +62,23 @@ use tracing::{debug, trace}; pub use rustc_session::lint::builtin::*; declare_lint! { + /// The `while_true` lint detects `while true { }`. + /// + /// ### Example + /// + /// ```rust,no_run + /// while true { + /// + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `while true` should be replaced with `loop`. A `loop` expression is + /// the preferred way to write an infinite loop because it more directly + /// expresses the intent of the loop. WHILE_TRUE, Warn, "suggest using `loop { }` instead of `while true { }`" @@ -100,6 +120,24 @@ impl EarlyLintPass for WhileTrue { } declare_lint! { + /// The `box_pointers` lints use of the Box type. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(box_pointers)] + /// struct Foo { + /// x: Box, + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is mostly historical, and not particularly useful. `Box` + /// used to be built into the language, and the only way to do heap + /// allocation. Today's Rust can call into other allocators, etc. BOX_POINTERS, Allow, "use of owned (Box type) heap memory" @@ -154,6 +192,36 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers { } declare_lint! { + /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }` + /// instead of `Struct { x }` in a pattern. + /// + /// ### Example + /// + /// ```rust + /// struct Point { + /// x: i32, + /// y: i32, + /// } + /// + /// + /// fn main() { + /// let p = Point { + /// x: 5, + /// y: 5, + /// }; + /// + /// match p { + /// Point { x: x, y: y } => (), + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style is to avoid the repetition of specifying both the + /// field name and the binding name if both identifiers are the same. NON_SHORTHAND_FIELD_PATTERNS, Warn, "using `Struct { x: x }` instead of `Struct { x }` in a pattern" @@ -214,6 +282,25 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { } declare_lint! { + /// The `unsafe_code` lint catches usage of `unsafe` code. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unsafe_code)] + /// fn main() { + /// unsafe { + /// + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is intended to restrict the usage of `unsafe`, which can be + /// difficult to use correctly. UNSAFE_CODE, Allow, "usage of `unsafe` code" @@ -301,6 +388,25 @@ impl EarlyLintPass for UnsafeCode { } declare_lint! { + /// The `missing_docs` lint detects missing documentation for public items. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_docs)] + /// pub fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is intended to ensure that a library is well-documented. + /// Items without documentation can be difficult for users to understand + /// how to use properly. + /// + /// This lint is "allow" by default because it can be noisy, and not all + /// projects may want to enforce everything to be documented. pub MISSING_DOCS, Allow, "detects missing documentation for public members", @@ -507,6 +613,19 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { ); } + fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) { + let def_id = cx.tcx.hir().local_def_id(foreign_item.hir_id); + let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id()); + self.check_missing_docs_attrs( + cx, + Some(foreign_item.hir_id), + &foreign_item.attrs, + foreign_item.span, + article, + desc, + ); + } + fn check_struct_field(&mut self, cx: &LateContext<'_>, sf: &hir::StructField<'_>) { if !sf.is_positional() { self.check_missing_docs_attrs( @@ -526,6 +645,34 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } declare_lint! { + /// The `missing_copy_implementations` lint detects potentially-forgotten + /// implementations of [`Copy`]. + /// + /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_copy_implementations)] + /// pub struct Foo { + /// pub field: i32 + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Historically (before 1.0), types were automatically marked as `Copy` + /// if possible. This was changed so that it required an explicit opt-in + /// by implementing the `Copy` trait. As part of this change, a lint was + /// added to alert if a copyable type was not marked `Copy`. + /// + /// This lint is "allow" by default because this code isn't bad; it is + /// common to write newtypes like this specifically so that a `Copy` type + /// is no longer `Copy`. `Copy` types can result in unintended copies of + /// large data which can impact performance. pub MISSING_COPY_IMPLEMENTATIONS, Allow, "detects potentially-forgotten implementations of `Copy`" @@ -582,6 +729,32 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { } declare_lint! { + /// The `missing_debug_implementations` lint detects missing + /// implementations of [`fmt::Debug`]. + /// + /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_debug_implementations)] + /// pub struct Foo; + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Having a `Debug` implementation on all types can assist with + /// debugging, as it provides a convenient way to format and display a + /// value. Using the `#[derive(Debug)]` attribute will automatically + /// generate a typical implementation, or a custom implementation can be + /// added by manually implementing the `Debug` trait. + /// + /// This lint is "allow" by default because adding `Debug` to all types can + /// have a negative impact on compile time and code size. It also requires + /// boilerplate to be added to every type, which can be an impediment. MISSING_DEBUG_IMPLEMENTATIONS, Allow, "detects missing implementations of Debug" @@ -638,6 +811,45 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { } declare_lint! { + /// The `anonymous_parameters` lint detects anonymous parameters in trait + /// definitions. + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(anonymous_parameters)] + /// // edition 2015 + /// pub trait Foo { + /// fn foo(usize); + /// } + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This syntax is mostly a historical accident, and can be worked around + /// quite easily by adding an `_` pattern or a descriptive identifier: + /// + /// ```rust + /// trait Foo { + /// fn foo(_: usize); + /// } + /// ``` + /// + /// This syntax is now a hard error in the 2018 edition. In the 2015 + /// edition, this lint is "allow" by default, because the old code is + /// still valid, and warning for all old code can be noisy. This lint + /// enables the [`cargo fix`] tool with the `--edition` flag to + /// automatically transition old code from the 2015 edition to 2018. The + /// tool will switch this lint to "warn" and will automatically apply the + /// suggested fix from the compiler (which is to add `_` to each + /// parameter). This provides a completely automated way to update old + /// code for a new edition. See [issue #41686] for more details. + /// + /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686 + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html pub ANONYMOUS_PARAMETERS, Allow, "detects anonymous parameters", @@ -763,7 +975,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & continue; } - let span = sugared_span.take().unwrap_or_else(|| attr.span); + let span = sugared_span.take().unwrap_or(attr.span); if attr.is_doc_comment() || cx.sess().check_name(attr, sym::doc) { cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { @@ -804,12 +1016,54 @@ impl EarlyLintPass for UnusedDocComment { } declare_lint! { + /// The `no_mangle_const_items` lint detects any `const` items with the + /// [`no_mangle` attribute]. + /// + /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[no_mangle] + /// const FOO: i32 = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Constants do not have their symbols exported, and therefore, this + /// probably means you meant to use a [`static`], not a [`const`]. + /// + /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html + /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html NO_MANGLE_CONST_ITEMS, Deny, "const items will not have their symbols exported" } declare_lint! { + /// The `no_mangle_generic_items` lint detects generic items that must be + /// mangled. + /// + /// ### Example + /// + /// ```rust + /// #[no_mangle] + /// fn foo(t: T) { + /// + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// An function with generics must have its symbol mangled to accommodate + /// the generic parameter. The [`no_mangle` attribute] has no effect in + /// this situation, and should be removed. + /// + /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute NO_MANGLE_GENERIC_ITEMS, Warn, "generic items must be mangled" @@ -880,6 +1134,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { } declare_lint! { + /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut + /// T` because it is [undefined behavior]. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// unsafe { + /// let y = std::mem::transmute::<&i32, &mut i32>(&5); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Certain assumptions are made about aliasing of data, and this transmute + /// violates those assumptions. Consider using [`UnsafeCell`] instead. + /// + /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html MUTABLE_TRANSMUTES, Deny, "mutating transmuted &mut T from &T may cause undefined behavior" @@ -891,7 +1166,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { use rustc_target::spec::abi::Abi::RustIntrinsic; if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) = - get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.kind, &ty2.kind)) + get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) { if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not { let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ @@ -929,6 +1204,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { } declare_lint! { + /// The `unstable_features` is deprecated and should no longer be used. UNSTABLE_FEATURES, Allow, "enabling unstable features (deprecated. do not use)" @@ -954,6 +1230,32 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { } declare_lint! { + /// The `unreachable_pub` lint triggers for `pub` items not reachable from + /// the crate root. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unreachable_pub)] + /// mod foo { + /// pub mod bar { + /// + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A bare `pub` visibility may be misleading if the item is not actually + /// publicly exported from the crate. The `pub(crate)` visibility is + /// recommended to be used instead, which more clearly expresses the intent + /// that the item is only visible within its own crate. + /// + /// This lint is "allow" by default because it will trigger for a large + /// amount existing Rust code, and has some false-positives. Eventually it + /// is desired for this to become warn-by-default. pub UNREACHABLE_PUB, Allow, "`pub` items not reachable from crate root" @@ -1033,6 +1335,21 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub { } declare_lint! { + /// The `type_alias_bounds` lint detects bounds in type aliases. + /// + /// ### Example + /// + /// ```rust + /// type SendVec = Vec; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The trait bounds in a type alias are currently ignored, and should not + /// be included to avoid confusion. This was previously allowed + /// unintentionally; this may become a hard error in the future. TYPE_ALIAS_BOUNDS, Warn, "bounds in type aliases are not enforced" @@ -1170,21 +1487,19 @@ declare_lint_pass!( UnusedBrokenConst => [] ); -fn check_const(cx: &LateContext<'_>, body_id: hir::BodyId) { - let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); - // trigger the query once for all constants since that will already report the errors - // FIXME: Use ensure here - let _ = cx.tcx.const_eval_poly(def_id); -} - impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { match it.kind { hir::ItemKind::Const(_, body_id) => { - check_const(cx, body_id); + let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); + // trigger the query once for all constants since that will already report the errors + // FIXME: Use ensure here + let _ = cx.tcx.const_eval_poly(def_id); } hir::ItemKind::Static(_, _, body_id) => { - check_const(cx, body_id); + let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); + // FIXME: Use ensure here + let _ = cx.tcx.eval_static_initializer(def_id); } _ => {} } @@ -1192,6 +1507,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { } declare_lint! { + /// The `trivial_bounds` lint detects trait bounds that don't depend on + /// any type parameters. + /// + /// ### Example + /// + /// ```rust + /// #![feature(trivial_bounds)] + /// pub struct A where i32: Copy; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Usually you would not write a trait bound that you know is always + /// true, or never true. However, when using macros, the macro may not + /// know whether or not the constraint would hold or not at the time when + /// generating the code. Currently, the compiler does not alert you if the + /// constraint is always true, and generates an error if it is never true. + /// The `trivial_bounds` feature changes this to be a warning in both + /// cases, giving macros more freedom and flexibility to generate code, + /// while still providing a signal when writing non-macro code that + /// something is amiss. + /// + /// See [RFC 2056] for more details. This feature is currently only + /// available on the nightly channel, see [tracking issue #48214]. + /// + /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md + /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214 TRIVIAL_BOUNDS, Warn, "these bounds don't depend on an type parameters" @@ -1226,7 +1570,8 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ClosureKind(..) | Subtype(..) | ConstEvaluatable(..) | - ConstEquate(..) => continue, + ConstEquate(..) | + TypeWellFormedFromEnv(..) => continue, }; if predicate.is_global() { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { @@ -1267,6 +1612,29 @@ declare_lint_pass!( ); declare_lint! { + /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range + /// pattern], which is deprecated. + /// + /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns + /// + /// ### Example + /// + /// ```rust + /// let x = 123; + /// match x { + /// 0...100 => {} + /// _ => {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `...` range pattern syntax was changed to `..=` to avoid potential + /// confusion with the [`..` range expression]. Use the new form instead. + /// + /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, Warn, "`...` range patterns are deprecated" @@ -1353,6 +1721,38 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } declare_lint! { + /// The `unnameable_test_items` lint detects [`#[test]`][test] functions + /// that are not able to be run by the test harness because they are in a + /// position where they are not nameable. + /// + /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute + /// + /// ### Example + /// + /// ```rust,test + /// fn main() { + /// #[test] + /// fn foo() { + /// // This test will not fail because it does not run. + /// assert_eq!(1, 2); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In order for the test harness to run a test, the test function must be + /// located in a position where it can be accessed from the crate root. + /// This generally means it must be defined in a module, and not anywhere + /// else such as inside another function. The compiler previously allowed + /// this without an error, so a lint was added as an alert that a test is + /// not being used. Whether or not this should be allowed has not yet been + /// decided, see [RFC 2471] and [issue #36629]. + /// + /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443 + /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629 UNNAMEABLE_TEST_ITEMS, Warn, "detects an item that cannot be named being marked as `#[test_case]`", @@ -1398,6 +1798,41 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { } declare_lint! { + /// The `keyword_idents` lint detects edition keywords being used as an + /// identifier. + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(keyword_idents)] + /// // edition 2015 + /// fn dyn() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust [editions] allow the language to evolve without breaking + /// backwards compatibility. This lint catches code that uses new keywords + /// that are added to the language that are used as identifiers (such as a + /// variable name, function name, etc.). If you switch the compiler to a + /// new edition without updating the code, then it will fail to compile if + /// you are using a new keyword as an identifier. + /// + /// You can manually change the identifiers to a non-keyword, or use a + /// [raw identifier], for example `r#dyn`, to transition to a new edition. + /// + /// This lint solves the problem automatically. It is "allow" by default + /// because the code is perfectly valid in older editions. The [`cargo + /// fix`] tool with the `--edition` flag will switch this lint to "warn" + /// and automatically apply the suggested fix from the compiler (which is + /// to use a raw identifier). This provides a completely automated way to + /// update old code for a new edition. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html pub KEYWORD_IDENTS, Allow, "detects edition keywords being used as an identifier", @@ -1562,9 +1997,9 @@ 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::Static) if infer_static => inferred_outlives - .iter() - .any(|r| if let ty::ReStatic = r { true } else { false }), + Some(Region::Static) if infer_static => { + inferred_outlives.iter().any(|r| matches!(r, ty::ReStatic)) + } Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| { if let ty::ReEarlyBound(ebr) = r { ebr.index == index } else { false } }), @@ -1656,9 +2091,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { let mut lint_spans = Vec::new(); for param in hir_generics.params { - let has_lifetime_bounds = param.bounds.iter().any(|bound| { - if let hir::GenericBound::Outlives(_) = bound { true } else { false } - }); + let has_lifetime_bounds = param + .bounds + .iter() + .any(|bound| matches!(bound, hir::GenericBound::Outlives(_))); if !has_lifetime_bounds { continue; } @@ -1799,6 +2235,26 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } declare_lint! { + /// The `incomplete_features` lint detects unstable features enabled with + /// the [`feature` attribute] that may function improperly in some or all + /// cases. + /// + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// ### Example + /// + /// ```rust + /// #![feature(generic_associated_types)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Although it is encouraged for people to experiment with unstable + /// features, some of them are known to be incomplete or faulty. This lint + /// is a signal that the feature has not yet been finished, and you may + /// experience problems with it. pub INCOMPLETE_FEATURES, Warn, "incomplete features that may function improperly in some or all cases" @@ -1839,6 +2295,36 @@ impl EarlyLintPass for IncompleteFeatures { } declare_lint! { + /// The `invalid_value` lint detects creating a value that is not valid, + /// such as a NULL reference. + /// + /// ### Example + /// + /// ```rust,no_run + /// # #![allow(unused)] + /// unsafe { + /// let x: &'static i32 = std::mem::zeroed(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In some situations the compiler can detect that the code is creating + /// an invalid value, which should be avoided. + /// + /// In particular, this lint will check for improper use of + /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and + /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The + /// lint should provide extra information to indicate what the problem is + /// and a possible solution. + /// + /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html + /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html + /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html + /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html pub INVALID_VALUE, Warn, "an invalid value is being created (such as a NULL reference)" @@ -1877,13 +2363,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { /// Determine if this expression is a "dangerous initialization". fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { - // `transmute` is inside an anonymous module (the `extern` block?); - // `Invalid` represents the empty string and matches that. - // FIXME(#66075): use diagnostic items. Somehow, that does not seem to work - // on intrinsics right now. - const TRANSMUTE_PATH: &[Symbol] = - &[sym::core, sym::intrinsics, kw::Invalid, sym::transmute]; - if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind { // Find calls to `mem::{uninitialized,zeroed}` methods. if let hir::ExprKind::Path(ref qpath) = path_expr.kind { @@ -1893,7 +2372,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { return Some(InitKind::Zeroed); } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) { return Some(InitKind::Uninit); - } else if cx.match_def_path(def_id, TRANSMUTE_PATH) { + } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) { if is_zero(&args[0]) { return Some(InitKind::Zeroed); } @@ -1938,13 +2417,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { init: InitKind, ) -> Option { use rustc_middle::ty::TyKind::*; - match ty.kind { + match ty.kind() { // Primitive types that don't like 0 as a value. Ref(..) => Some(("references must be non-null".to_string(), None)), Adt(..) if ty.is_box() => Some(("`Box` must be non-null".to_string(), None)), FnPtr(..) => Some(("function pointers must be non-null".to_string(), None)), Never => Some(("the `!` type has no valid value".to_string(), None)), - RawPtr(tm) if matches!(tm.ty.kind, Dynamic(..)) => + RawPtr(tm) if matches!(tm.ty.kind(), Dynamic(..)) => // raw ptr to dyn Trait { Some(("the vtable of a wide raw pointer must be non-null".to_string(), None)) @@ -2039,7 +2518,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // using zeroed or uninitialized memory. // We are extremely conservative with what we warn about. let conjured_ty = cx.typeck_results().expr_ty(expr); - if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) { + if let Some((msg, span)) = + with_no_trimmed_paths(|| ty_find_init_error(cx.tcx, conjured_ty, init)) + { cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| { let mut err = lint.build(&format!( "the type `{}` does not permit {}", @@ -2068,6 +2549,40 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { } declare_lint! { + /// The `clashing_extern_declarations` lint detects when an `extern fn` + /// has been declared with the same name but different types. + /// + /// ### Example + /// + /// ```rust + /// mod m { + /// extern "C" { + /// fn foo(); + /// } + /// } + /// + /// extern "C" { + /// fn foo(_: u32); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Because two symbols of the same name cannot be resolved to two + /// different functions at link time, and one function cannot possibly + /// have two types, a clashing extern declaration is almost certainly a + /// mistake. Check to make sure that the `extern` definitions are correct + /// and equivalent, and possibly consider unifying them in one location. + /// + /// This lint does not run between crates because a project may have + /// dependencies which both rely on the same extern function, but declare + /// it in a different (but valid) way. For example, they may both declare + /// an opaque type for one or more of the arguments (which would end up + /// distinct types), or use types that are valid conversions in the + /// language the `extern fn` is defined in. In these cases, the compiler + /// can't say that the clashing declaration is incorrect. pub CLASHING_EXTERN_DECLARATIONS, Warn, "detects when an extern fn has been declared with the same name but different types" @@ -2162,6 +2677,39 @@ impl ClashingExternDeclarations { ckind: CItemKind, ) -> bool { debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b); + let tcx = cx.tcx; + + // Given a transparent newtype, reach through and grab the inner + // type unless the newtype makes the type non-null. + let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> { + let mut ty = ty; + loop { + if let ty::Adt(def, substs) = *ty.kind() { + let is_transparent = def.subst(tcx, substs).repr.transparent(); + let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, &def); + debug!( + "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}", + ty, is_transparent, is_non_null + ); + if is_transparent && !is_non_null { + debug_assert!(def.variants.len() == 1); + let v = &def.variants[VariantIdx::new(0)]; + ty = transparent_newtype_field(tcx, v) + .expect( + "single-variant transparent structure with zero-sized field", + ) + .ty(tcx, substs); + continue; + } + } + debug!("non_transparent_ty -> {:?}", ty); + return ty; + } + }; + + let a = non_transparent_ty(a); + let b = non_transparent_ty(b); + if !seen_types.insert((a, b)) { // We've encountered a cycle. There's no point going any further -- the types are // structurally the same. @@ -2174,14 +2722,20 @@ impl ClashingExternDeclarations { } else { // Do a full, depth-first comparison between the two. use rustc_middle::ty::TyKind::*; - let a_kind = &a.kind; - let b_kind = &b.kind; - - let compare_layouts = |a, b| -> bool { - let a_layout = &cx.layout_of(a).unwrap().layout.abi; - let b_layout = &cx.layout_of(b).unwrap().layout.abi; - debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout); - a_layout == b_layout + let a_kind = a.kind(); + let b_kind = b.kind(); + + let compare_layouts = |a, b| -> Result> { + debug!("compare_layouts({:?}, {:?})", a, b); + let a_layout = &cx.layout_of(a)?.layout.abi; + let b_layout = &cx.layout_of(b)?.layout.abi; + debug!( + "comparing layouts: {:?} == {:?} = {}", + a_layout, + b_layout, + a_layout == b_layout + ); + Ok(a_layout == b_layout) }; #[allow(rustc::usage_of_ty_tykind)] @@ -2196,11 +2750,19 @@ impl ClashingExternDeclarations { let b = b.subst(cx.tcx, b_substs); debug!("Comparing {:?} and {:?}", a, b); + // We can immediately rule out these types as structurally same if + // their layouts differ. + match compare_layouts(a, b) { + Ok(false) => return false, + _ => (), // otherwise, continue onto the full, fields comparison + } + // Grab a flattened representation of all fields. let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter()); let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter()); - compare_layouts(a, b) - && a_fields.eq_by( + + // Perform a structural comparison for each field. + a_fields.eq_by( b_fields, |&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| { @@ -2283,17 +2845,17 @@ impl ClashingExternDeclarations { if is_primitive_or_pointer(other_kind) => { let (primitive, adt) = - if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) }; + if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) }; if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { ty == primitive } else { - compare_layouts(a, b) + compare_layouts(a, b).unwrap_or(false) } } // Otherwise, just compare the layouts. This may fail to lint for some // incompatible types, but at the very least, will stop reads into // uninitialised memory. - _ => compare_layouts(a, b), + _ => compare_layouts(a, b).unwrap_or(false), } }) } diff --git a/src/librustc_lint/context.rs b/compiler/rustc_lint/src/context.rs similarity index 96% rename from src/librustc_lint/context.rs rename to compiler/rustc_lint/src/context.rs index a6784ffffc..7a3035e5b4 100644 --- a/src/librustc_lint/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -31,6 +31,7 @@ use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; use rustc_session::lint::{add_elided_lifetime_in_path_suggestion, BuiltinLintDiagnostics}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; @@ -719,6 +720,10 @@ impl<'tcx> LateContext<'tcx> { /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; /// inherent `impl` blocks are matched with the name of the type. /// + /// Instead of using this method, it is often preferable to instead use + /// `rustc_diagnostic_item` or a `lang_item`. This is less prone to errors + /// as paths get invalidated if the target definition moves. + /// /// # Examples /// /// ```rust,ignore (no context or def id available) @@ -789,16 +794,18 @@ impl<'tcx> LateContext<'tcx> { trait_ref: Option>, ) -> Result { if trait_ref.is_none() { - if let ty::Adt(def, substs) = self_ty.kind { + if let ty::Adt(def, substs) = self_ty.kind() { return self.print_def_path(def.did, substs); } } // This shouldn't ever be needed, but just in case: - Ok(vec![match trait_ref { - Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)), - None => Symbol::intern(&format!("<{}>", self_ty)), - }]) + with_no_trimmed_paths(|| { + Ok(vec![match trait_ref { + Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)), + None => Symbol::intern(&format!("<{}>", self_ty)), + }]) + }) } fn path_append_impl( @@ -812,12 +819,16 @@ impl<'tcx> LateContext<'tcx> { // This shouldn't ever be needed, but just in case: path.push(match trait_ref { - Some(trait_ref) => Symbol::intern(&format!( - "", - trait_ref.print_only_trait_path(), - self_ty - )), - None => Symbol::intern(&format!("", self_ty)), + Some(trait_ref) => with_no_trimmed_paths(|| { + Symbol::intern(&format!( + "", + trait_ref.print_only_trait_path(), + self_ty + )) + }), + None => { + with_no_trimmed_paths(|| Symbol::intern(&format!("", self_ty))) + } }); Ok(path) @@ -835,7 +846,7 @@ impl<'tcx> LateContext<'tcx> { return Ok(path); } - path.push(disambiguated_data.data.as_symbol()); + path.push(Symbol::intern(&disambiguated_data.data.to_string())); Ok(path) } diff --git a/src/librustc_lint/early.rs b/compiler/rustc_lint/src/early.rs similarity index 100% rename from src/librustc_lint/early.rs rename to compiler/rustc_lint/src/early.rs diff --git a/src/librustc_lint/internal.rs b/compiler/rustc_lint/src/internal.rs similarity index 85% rename from src/librustc_lint/internal.rs rename to compiler/rustc_lint/src/internal.rs index 100e555f29..c2d98b8e4a 100644 --- a/src/librustc_lint/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,7 +5,9 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast::{Item, ItemKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -177,11 +179,31 @@ fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool { fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { if let TyKind::Path(qpath) = &ty.kind { if let QPath::Resolved(_, path) = qpath { - let did = path.res.opt_def_id()?; - if cx.tcx.is_diagnostic_item(sym::Ty, did) { - return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { - return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + match path.res { + Res::Def(_, did) => { + if cx.tcx.is_diagnostic_item(sym::Ty, did) { + return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { + return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + } + } + // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. + Res::SelfTy(None, Some((did, _))) => { + if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { + if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) { + // NOTE: This path is currently unreachable as `Ty<'tcx>` is + // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>` + // is not actually allowed. + // + // I(@lcnr) still kept this branch in so we don't miss this + // if we ever change it in the future. + return Some(format!("Ty<{}>", substs[0])); + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) { + return Some(format!("TyCtxt<{}>", substs[0])); + } + } + } + _ => (), } } } diff --git a/src/librustc_lint/late.rs b/compiler/rustc_lint/src/late.rs similarity index 100% rename from src/librustc_lint/late.rs rename to compiler/rustc_lint/src/late.rs diff --git a/src/librustc_lint/levels.rs b/compiler/rustc_lint/src/levels.rs similarity index 100% rename from src/librustc_lint/levels.rs rename to compiler/rustc_lint/src/levels.rs diff --git a/src/librustc_lint/lib.rs b/compiler/rustc_lint/src/lib.rs similarity index 99% rename from src/librustc_lint/lib.rs rename to compiler/rustc_lint/src/lib.rs index 0a14b16e27..33caedfc19 100644 --- a/src/librustc_lint/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -25,8 +25,9 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![cfg_attr(test, feature(test))] +#![feature(array_windows)] #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] @@ -304,6 +305,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { add_lint_group!( "rustdoc", BROKEN_INTRA_DOC_LINKS, + PRIVATE_INTRA_DOC_LINKS, INVALID_CODEBLOCK_ATTRIBUTES, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS diff --git a/src/librustc_lint/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs similarity index 64% rename from src/librustc_lint/non_ascii_idents.rs rename to compiler/rustc_lint/src/non_ascii_idents.rs index 2f0b2a8d68..a1c7e47e74 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -4,6 +4,32 @@ use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::Symbol; declare_lint! { + /// The `non_ascii_idents` lint detects non-ASCII identifiers. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// #![feature(non_ascii_idents)] + /// #![deny(non_ascii_idents)] + /// fn main() { + /// let föö = 1; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Currently on stable Rust, identifiers must contain ASCII characters. + /// The [`non_ascii_idents`] nightly-only feature allows identifiers to + /// contain non-ASCII characters. This lint allows projects that wish to + /// retain the limit of only using ASCII characters to switch this lint to + /// "forbid" (for example to ease collaboration or for security reasons). + /// See [RFC 2457] for more details. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html + /// [RFC 2457]: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md pub NON_ASCII_IDENTS, Allow, "detects non-ASCII identifiers", @@ -11,6 +37,37 @@ declare_lint! { } declare_lint! { + /// The `uncommon_codepoints` lint detects uncommon Unicode codepoints in + /// identifiers. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// #![feature(non_ascii_idents)] + /// const µ: f64 = 0.000001; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With the [`non_ascii_idents`] nightly-only feature enabled, + /// identifiers are allowed to use non-ASCII characters. This lint warns + /// about using characters which are not commonly used, and may cause + /// visual confusion. + /// + /// This lint is triggered by identifiers that contain a codepoint that is + /// not part of the set of "Allowed" codepoints as described by [Unicode® + /// Technical Standard #39 Unicode Security Mechanisms Section 3.1 General + /// Security Profile for Identifiers][TR39Allowed]. + /// + /// Note that the set of uncommon codepoints may change over time. Beware + /// that if you "forbid" this lint that existing code may fail in the + /// future. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html + /// [TR39Allowed]: https://www.unicode.org/reports/tr39/#General_Security_Profile pub UNCOMMON_CODEPOINTS, Warn, "detects uncommon Unicode codepoints in identifiers", @@ -18,6 +75,43 @@ declare_lint! { } declare_lint! { + /// The `confusable_idents` lint detects visually confusable pairs between + /// identifiers. + /// + /// ### Example + /// + /// ```rust + /// #![feature(non_ascii_idents)] + /// + /// // Latin Capital Letter E With Caron + /// pub const Ě: i32 = 1; + /// // Latin Capital Letter E With Breve + /// pub const Ĕ: i32 = 2; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With the [`non_ascii_idents`] nightly-only feature enabled, + /// identifiers are allowed to use non-ASCII characters. This lint warns + /// when different identifiers may appear visually similar, which can + /// cause confusion. + /// + /// The confusable detection algorithm is based on [Unicode® Technical + /// Standard #39 Unicode Security Mechanisms Section 4 Confusable + /// Detection][TR39Confusable]. For every distinct identifier X execute + /// the function `skeleton(X)`. If there exist two distinct identifiers X + /// and Y in the same crate where `skeleton(X) = skeleton(Y)` report it. + /// The compiler uses the same mechanism to check if an identifier is too + /// similar to a keyword. + /// + /// Note that the set of confusable characters may change over time. + /// Beware that if you "forbid" this lint that existing code may fail in + /// the future. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html + /// [TR39Confusable]: https://www.unicode.org/reports/tr39/#Confusable_Detection pub CONFUSABLE_IDENTS, Warn, "detects visually confusable pairs between identifiers", @@ -25,6 +119,41 @@ declare_lint! { } declare_lint! { + /// The `mixed_script_confusables` lint detects visually confusable + /// characters in identifiers between different [scripts]. + /// + /// [scripts]: https://en.wikipedia.org/wiki/Script_(Unicode) + /// + /// ### Example + /// + /// ```rust + /// #![feature(non_ascii_idents)] + /// + /// // The Japanese katakana character エ can be confused with the Han character å·¥. + /// const エ: &'static str = "アイウ"; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With the [`non_ascii_idents`] nightly-only feature enabled, + /// identifiers are allowed to use non-ASCII characters. This lint warns + /// when characters between different scripts may appear visually similar, + /// which can cause confusion. + /// + /// If the crate contains other identifiers in the same script that have + /// non-confusable characters, then this lint will *not* be issued. For + /// example, if the example given above has another identifier with + /// katakana characters (such as `let カタカナ = 123;`), then this indicates + /// that you are intentionally using katakana, and it will not warn about + /// it. + /// + /// Note that the set of confusable characters may change over time. + /// Beware that if you "forbid" this lint that existing code may fail in + /// the future. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html pub MIXED_SCRIPT_CONFUSABLES, Warn, "detects Unicode scripts whose mixed script confusables codepoints are solely used", @@ -212,7 +341,8 @@ impl EarlyLintPass for NonAsciiIdents { } } - ch_list.sort(); + // We sort primitive chars here and can use unstable sort + ch_list.sort_unstable(); ch_list.dedup(); lint_reports.insert((sp, ch_list), augment_script_set); } diff --git a/src/librustc_lint/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs similarity index 90% rename from src/librustc_lint/nonstandard_style.rs rename to compiler/rustc_lint/src/nonstandard_style.rs index f23e8c5e20..b3125f55d4 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -31,6 +31,24 @@ pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext } declare_lint! { + /// The `non_camel_case_types` lint detects types, variants, traits and + /// type parameters that don't have camel case names. + /// + /// ### Example + /// + /// ```rust + /// struct my_struct; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style for these identifiers is to use "camel case", such + /// as `MyStruct`, where the first letter should not be lowercase, and + /// should not use underscores between letters. Underscores are allowed at + /// the beginning and end of the identifier, as well as between + /// non-letters (such as `X86_64`). pub NON_CAMEL_CASE_TYPES, Warn, "types, variants, traits and type parameters should have camel case names" @@ -52,9 +70,9 @@ fn is_camel_case(name: &str) -> bool { // ones (some scripts don't have a concept of upper/lowercase) !name.chars().next().unwrap().is_lowercase() && !name.contains("__") - && !name.chars().collect::>().windows(2).any(|pair| { + && !name.chars().collect::>().array_windows().any(|&[fst, snd]| { // contains a capitalisable character followed by, or preceded by, an underscore - char_has_case(pair[0]) && pair[1] == '_' || char_has_case(pair[1]) && pair[0] == '_' + char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_' }) } @@ -161,6 +179,22 @@ impl EarlyLintPass for NonCamelCaseTypes { } declare_lint! { + /// The `non_snake_case` lint detects variables, methods, functions, + /// lifetime parameters and modules that don't have snake case names. + /// + /// ### Example + /// + /// ```rust + /// let MY_VALUE = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style for these identifiers is to use "snake case", + /// where all the characters are in lowercase, with words separated with a + /// single underscore, such as `my_value`. pub NON_SNAKE_CASE, Warn, "variables, methods, functions, lifetime parameters and modules should have snake case names" @@ -379,6 +413,21 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } declare_lint! { + /// The `non_upper_case_globals` lint detects static items that don't have + /// uppercase identifiers. + /// + /// ### Example + /// + /// ```rust + /// static max_points: i32 = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style is for static item names to use all uppercase + /// letters such as `MAX_POINTS`. pub NON_UPPER_CASE_GLOBALS, Warn, "static constants should have uppercase identifiers" diff --git a/src/librustc_lint/nonstandard_style/tests.rs b/compiler/rustc_lint/src/nonstandard_style/tests.rs similarity index 100% rename from src/librustc_lint/nonstandard_style/tests.rs rename to compiler/rustc_lint/src/nonstandard_style/tests.rs diff --git a/src/librustc_lint/passes.rs b/compiler/rustc_lint/src/passes.rs similarity index 100% rename from src/librustc_lint/passes.rs rename to compiler/rustc_lint/src/passes.rs diff --git a/src/librustc_lint/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs similarity index 80% rename from src/librustc_lint/redundant_semicolon.rs rename to compiler/rustc_lint/src/redundant_semicolon.rs index d4aa4968f2..a31deb87ff 100644 --- a/src/librustc_lint/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -4,6 +4,21 @@ use rustc_errors::Applicability; use rustc_span::Span; declare_lint! { + /// The `redundant_semicolons` lint detects unnecessary trailing + /// semicolons. + /// + /// ### Example + /// + /// ```rust + /// let _ = 123;; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Extra semicolons are not needed, and may be removed to avoid confusion + /// and visual clutter. pub REDUNDANT_SEMICOLONS, Warn, "detects unnecessary trailing semicolons" diff --git a/src/librustc_lint/types.rs b/compiler/rustc_lint/src/types.rs similarity index 89% rename from src/librustc_lint/types.rs rename to compiler/rustc_lint/src/types.rs index 4ca5f23ebf..9925444b86 100644 --- a/src/librustc_lint/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,5 +1,3 @@ -#![allow(non_snake_case)] - use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; @@ -11,7 +9,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::interpret::{sign_extend, truncate}; use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable}; +use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -23,18 +21,82 @@ use std::cmp; use tracing::debug; declare_lint! { + /// The `unused_comparisons` lint detects comparisons made useless by + /// limits of the types involved. + /// + /// ### Example + /// + /// ```rust + /// fn foo(x: u8) { + /// x >= 0; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A useless comparison may indicate a mistake, and should be fixed or + /// removed. UNUSED_COMPARISONS, Warn, "comparisons made useless by limits of the types involved" } declare_lint! { + /// The `overflowing_literals` lint detects literal out of range for its + /// type. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// let x: u8 = 1000; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to use a literal that overflows the type where + /// it is used. Either use a literal that is within range, or change the + /// type to be within the range of the literal. OVERFLOWING_LITERALS, Deny, "literal out of range for its type" } declare_lint! { + /// The `variant_size_differences` lint detects enums with widely varying + /// variant sizes. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(variant_size_differences)] + /// enum En { + /// V0(u8), + /// VBig([u8; 1024]), + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It can be a mistake to add a variant to an enum that is much larger + /// than the other variants, bloating the overall size required for all + /// variants. This can impact performance and memory usage. This is + /// triggered if one variant is more than 3 times larger than the + /// second-largest variant. + /// + /// Consider placing the large variant's contents on the heap (for example + /// via [`Box`]) to keep the overall size of the enum itself down. + /// + /// This lint is "allow" by default because it can be noisy, and may not be + /// an actual problem. Decisions about this should be guided with + /// profiling and benchmarking. + /// + /// [`Box`]: https://doc.rust-lang.org/std/boxed/index.html VARIANT_SIZE_DIFFERENCES, Allow, "detects enums with widely varying variant sizes" @@ -217,7 +279,7 @@ fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static } } } - match t.kind { + match t.kind() { ty::Int(i) => find_fit!(i, val, negative, I8 => [U8] => [I16, I32, I64, I128], I16 => [U16] => [I32, I64, I128], @@ -303,7 +365,7 @@ fn lint_uint_literal<'tcx>( if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) { match par_e.kind { hir::ExprKind::Cast(..) => { - if let ty::Char = cx.typeck_results().expr_ty(par_e).kind { + if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| { lint.build("only `u8` can be cast into `char`") .span_suggestion( @@ -354,7 +416,7 @@ fn lint_literal<'tcx>( e: &'tcx hir::Expr<'tcx>, lit: &hir::Lit, ) { - match cx.typeck_results().node_type(e.hir_id).kind { + match *cx.typeck_results().node_type(e.hir_id).kind() { ty::Int(t) => { match lit.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => { @@ -450,7 +512,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { // Normalize the binop so that the literal is always on the RHS in // the comparison let norm_binop = if swap { rev_binop(binop) } else { binop }; - match cx.typeck_results().node_type(expr.hir_id).kind { + match *cx.typeck_results().node_type(expr.hir_id).kind() { ty::Int(int_ty) => { let (min, max) = int_ty_range(int_ty); let lit_val: i128 = match lit.kind { @@ -495,6 +557,27 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { } declare_lint! { + /// The `improper_ctypes` lint detects incorrect use of types in foreign + /// modules. + /// + /// ### Example + /// + /// ```rust + /// extern "C" { + /// static STATIC: String; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler has several checks to verify that types used in `extern` + /// blocks are safe and follow certain rules to ensure proper + /// compatibility with the foreign interfaces. This lint is issued when it + /// detects a probable mistake in a definition. The lint usually should + /// provide a description of the issue, along with possibly a hint on how + /// to resolve it. IMPROPER_CTYPES, Warn, "proper use of libc types in foreign modules" @@ -503,6 +586,27 @@ declare_lint! { declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]); declare_lint! { + /// The `improper_ctypes_definitions` lint detects incorrect use of + /// [`extern` function] definitions. + /// + /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// pub extern "C" fn str_type(p: &str) { } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// There are many parameter and return types that may be specified in an + /// `extern` function that are not compatible with the given ABI. This + /// lint is an alert that these types should not be used. The lint usually + /// should provide a description of the issue, along with possibly a hint + /// on how to resolve it. IMPROPER_CTYPES_DEFINITIONS, Warn, "proper use of libc types in foreign item definitions" @@ -527,24 +631,48 @@ enum FfiResult<'tcx> { FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option }, } +crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtDef) -> bool { + tcx.get_attrs(def.did) + .iter() + .any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed)) +} + +/// `repr(transparent)` structs can have a single non-ZST field, this function returns that +/// field. +pub fn transparent_newtype_field<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + variant: &'a ty::VariantDef, +) -> Option<&'a ty::FieldDef> { + let param_env = tcx.param_env(variant.def_id); + for field in &variant.fields { + let field_ty = tcx.type_of(field.did); + let is_zst = + tcx.layout_of(param_env.and(field_ty)).map(|layout| layout.is_zst()).unwrap_or(false); + + if !is_zst { + return Some(field); + } + } + + None +} + /// Is type known to be non-null? -fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { +crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { let tcx = cx.tcx; - match ty.kind { + match ty.kind() { ty::FnPtr(_) => true, ty::Ref(..) => true, ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true, ty::Adt(def, substs) if def.repr.transparent() && !def.is_union() => { - let guaranteed_nonnull_optimization = tcx - .get_attrs(def.did) - .iter() - .any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed)); + let marked_non_null = nonnull_optimization_guaranteed(tcx, &def); - if guaranteed_nonnull_optimization { + if marked_non_null { return true; } + for variant in &def.variants { - if let Some(field) = variant.transparent_newtype_field(tcx) { + if let Some(field) = transparent_newtype_field(cx.tcx, variant) { if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) { return true; } @@ -561,11 +689,11 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi /// If the type passed in was not scalar, returns None. fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { let tcx = cx.tcx; - Some(match ty.kind { + Some(match *ty.kind() { ty::Adt(field_def, field_substs) => { let inner_field_ty = { let first_non_zst_ty = - field_def.variants.iter().filter_map(|v| v.transparent_newtype_field(tcx)); + field_def.variants.iter().filter_map(|v| transparent_newtype_field(cx.tcx, v)); debug_assert_eq!( first_non_zst_ty.clone().count(), 1, @@ -603,7 +731,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option( ckind: CItemKind, ) -> Option> { debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty); - if let ty::Adt(ty_def, substs) = ty.kind { + if let ty::Adt(ty_def, substs) = ty.kind() { if ty_def.variants.len() != 2 { return None; } @@ -663,7 +791,7 @@ crate fn repr_nullable_ptr<'tcx>( impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the type is array and emit an unsafe type lint. fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { - if let ty::Array(..) = ty.kind { + if let ty::Array(..) = ty.kind() { self.emit_ffi_unsafe_type_lint( ty, sp, @@ -706,7 +834,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.repr.transparent() { // Can assume that only one field is not a ZST, so only check // that field's type for FFI-safety. - if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) { + if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) { self.check_field_type_for_ffi(cache, field, substs) } else { bug!("malformed transparent type"); @@ -751,7 +879,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiSafe; } - match ty.kind { + match ty.kind() { ty::Adt(def, _) if def.is_box() && matches!(self.mode, CItemKind::Definition) => { FfiSafe } @@ -990,7 +1118,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { diag.help(help); } diag.note(note); - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) { diag.span_note(sp, "the type is defined here"); } @@ -1007,7 +1135,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - match ty.kind { + match ty.kind() { ty::Opaque(..) => { self.ty = Some(ty); true diff --git a/src/librustc_lint/unused.rs b/compiler/rustc_lint/src/unused.rs similarity index 90% rename from src/librustc_lint/unused.rs rename to compiler/rustc_lint/src/unused.rs index c793e81ebe..1e8c30071e 100644 --- a/src/librustc_lint/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -20,6 +20,29 @@ use rustc_span::{BytePos, Span, DUMMY_SP}; use tracing::debug; declare_lint! { + /// The `unused_must_use` lint detects unused result of a type flagged as + /// `#[must_use]`. + /// + /// ### Example + /// + /// ```rust + /// fn returns_result() -> Result<(), ()> { + /// Ok(()) + /// } + /// + /// fn main() { + /// returns_result(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `#[must_use]` attribute is an indicator that it is a mistake to + /// ignore the value. See [the reference] for more details. + /// + /// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute pub UNUSED_MUST_USE, Warn, "unused result of a type flagged as `#[must_use]`", @@ -27,6 +50,39 @@ declare_lint! { } declare_lint! { + /// The `unused_results` lint checks for the unused result of an + /// expression in a statement. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_results)] + /// fn foo() -> T { panic!() } + /// + /// fn main() { + /// foo::(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Ignoring the return value of a function may indicate a mistake. In + /// cases were it is almost certain that the result should be used, it is + /// recommended to annotate the function with the [`must_use` attribute]. + /// Failure to use such a return value will trigger the [`unused_must_use` + /// lint] which is warn-by-default. The `unused_results` lint is + /// essentially the same, but triggers for *all* return values. + /// + /// This lint is "allow" by default because it can be noisy, and may not be + /// an actual problem. For example, calling the `remove` method of a `Vec` + /// or `HashMap` returns the previous value, which you may not care about. + /// Using this lint would require explicitly ignoring or discarding such + /// values. + /// + /// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute + /// [`unused_must_use` lint]: warn-by-default.html#unused-must-use pub UNUSED_RESULTS, Allow, "unused result of an expression in a statement" @@ -135,7 +191,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let plural_suffix = pluralize!(plural_len); - match ty.kind { + match *ty.kind() { ty::Adt(..) if ty.is_box() => { let boxed_ty = ty.boxed_ty(); let descr_pre = &format!("{}boxed ", descr_pre); @@ -265,6 +321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } declare_lint! { + /// The `path_statements` lint detects path statements with no effect. + /// + /// ### Example + /// + /// ```rust + /// let x = 42; + /// + /// x; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to have a statement that has no effect. pub PATH_STATEMENTS, Warn, "path statements with no effect" @@ -635,6 +706,21 @@ trait UnusedDelimLint { } declare_lint! { + /// The `unused_parens` lint detects `if`, `match`, `while` and `return` + /// with parentheses; they do not need them. + /// + /// ### Examples + /// + /// ```rust + /// if(true) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The parenthesis are not needed, and should be removed. This is the + /// preferred style for writing these expressions. pub(super) UNUSED_PARENS, Warn, "`if`, `match`, `while` and `return` do not need parentheses" @@ -808,6 +894,23 @@ impl EarlyLintPass for UnusedParens { } declare_lint! { + /// The `unused_braces` lint detects unnecessary braces around an + /// expression. + /// + /// ### Example + /// + /// ```rust + /// if { true } { + /// // ... + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The braces are not needed, and should be removed. This is the + /// preferred style for writing these expressions. pub(super) UNUSED_BRACES, Warn, "unnecessary braces around an expression" @@ -929,6 +1032,30 @@ impl EarlyLintPass for UnusedBraces { } declare_lint! { + /// The `unused_import_braces` lint catches unnecessary braces around an + /// imported item. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_import_braces)] + /// use test::{A}; + /// + /// pub mod test { + /// pub struct A; + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If there is only a single item, then remove the braces (`use test::A;` + /// for example). + /// + /// This lint is "allow" by default because it is only enforcing a + /// stylistic choice. UNUSED_IMPORT_BRACES, Allow, "unnecessary braces around an imported item" @@ -978,6 +1105,25 @@ impl EarlyLintPass for UnusedImportBraces { } declare_lint! { + /// The `unused_allocation` lint detects unnecessary allocations that can + /// be eliminated. + /// + /// ### Example + /// + /// ```rust + /// #![feature(box_syntax)] + /// fn main() { + /// let a = (box [1,2,3]).len(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When a `box` expression is immediately coerced to a reference, then + /// the allocation is unnecessary, and a reference (using `&` or `&mut`) + /// should be used instead to avoid the allocation. pub(super) UNUSED_ALLOCATION, Warn, "detects unnecessary allocations that can be eliminated" diff --git a/src/librustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml similarity index 67% rename from src/librustc_llvm/Cargo.toml rename to compiler/rustc_llvm/Cargo.toml index 9f2711eec1..e29af05328 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -4,10 +4,6 @@ name = "rustc_llvm" version = "0.0.0" edition = "2018" -[lib] -name = "rustc_llvm" -path = "lib.rs" - [features] static-libstdcpp = [] emscripten = [] @@ -16,5 +12,5 @@ emscripten = [] libc = "0.2.73" [build-dependencies] -build_helper = { path = "../build_helper" } -cc = "1.0.58" +build_helper = { path = "../../src/build_helper" } +cc = "1.0.60" diff --git a/src/librustc_llvm/build.rs b/compiler/rustc_llvm/build.rs similarity index 95% rename from src/librustc_llvm/build.rs rename to compiler/rustc_llvm/build.rs index 25c0b40c49..7f1e5cf336 100644 --- a/src/librustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -175,15 +175,15 @@ fn main() { cfg.debug(false); } - build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm")); - cfg.file("../rustllvm/PassWrapper.cpp") - .file("../rustllvm/RustWrapper.cpp") - .file("../rustllvm/ArchiveWrapper.cpp") - .file("../rustllvm/CoverageMappingWrapper.cpp") - .file("../rustllvm/Linker.cpp") + build_helper::rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper")); + cfg.file("llvm-wrapper/PassWrapper.cpp") + .file("llvm-wrapper/RustWrapper.cpp") + .file("llvm-wrapper/ArchiveWrapper.cpp") + .file("llvm-wrapper/CoverageMappingWrapper.cpp") + .file("llvm-wrapper/Linker.cpp") .cpp(true) .cpp_link_stdlib(None) // we handle this below - .compile("rustllvm"); + .compile("llvm-wrapper"); let (llvm_kind, llvm_link_arg) = detect_llvm_link(); @@ -198,6 +198,8 @@ fn main() { } else if target.contains("windows-gnu") { println!("cargo:rustc-link-lib=shell32"); println!("cargo:rustc-link-lib=uuid"); + } else if target.contains("netbsd") || target.contains("haiku") { + println!("cargo:rustc-link-lib=z"); } cmd.args(&components); @@ -257,7 +259,7 @@ fn main() { } // Some LLVM linker flags (-L and -l) may be needed even when linking - // librustc_llvm, for example when using static libc++, we may need to + // rustc_llvm, for example when using static libc++, we may need to // manually specify the library search path and -ldl -lpthread as link // dependencies. let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS"); diff --git a/src/rustllvm/.editorconfig b/compiler/rustc_llvm/llvm-wrapper/.editorconfig similarity index 100% rename from src/rustllvm/.editorconfig rename to compiler/rustc_llvm/llvm-wrapper/.editorconfig diff --git a/src/rustllvm/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp similarity index 99% rename from src/rustllvm/ArchiveWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index 9ce614fda5..2797fe8df4 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -1,4 +1,4 @@ -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" diff --git a/src/rustllvm/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp similarity index 98% rename from src/rustllvm/CoverageMappingWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 81aba0cbf7..2b1143a4ec 100644 --- a/src/rustllvm/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -1,4 +1,4 @@ -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProf.h" diff --git a/src/rustllvm/rustllvm.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h similarity index 100% rename from src/rustllvm/rustllvm.h rename to compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h diff --git a/src/rustllvm/Linker.cpp b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp similarity index 97% rename from src/rustllvm/Linker.cpp rename to compiler/rustc_llvm/llvm-wrapper/Linker.cpp index 69176f9cb1..8766e96f08 100644 --- a/src/rustllvm/Linker.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp @@ -1,6 +1,6 @@ #include "llvm/Linker/Linker.h" -#include "rustllvm.h" +#include "LLVMWrapper.h" using namespace llvm; diff --git a/src/rustllvm/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp similarity index 99% rename from src/rustllvm/PassWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 76fe5e7f76..7b1c3f9ba2 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -3,7 +3,7 @@ #include #include -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" diff --git a/src/rustllvm/README b/compiler/rustc_llvm/llvm-wrapper/README similarity index 100% rename from src/rustllvm/README rename to compiler/rustc_llvm/llvm-wrapper/README diff --git a/src/rustllvm/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp similarity index 99% rename from src/rustllvm/RustWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 9d90b0dfe0..9f8ea7f43d 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1,4 +1,4 @@ -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" @@ -1171,6 +1171,7 @@ enum class LLVMRustDiagnosticKind { OptimizationFailure, PGOProfile, Linker, + Unsupported, }; static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) { @@ -1197,6 +1198,8 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) { return LLVMRustDiagnosticKind::PGOProfile; case DK_Linker: return LLVMRustDiagnosticKind::Linker; + case DK_Unsupported: + return LLVMRustDiagnosticKind::Unsupported; default: return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark) ? LLVMRustDiagnosticKind::OptimizationRemarkOther diff --git a/src/librustc_llvm/lib.rs b/compiler/rustc_llvm/src/lib.rs similarity index 98% rename from src/librustc_llvm/lib.rs rename to compiler/rustc_llvm/src/lib.rs index 9d23397ade..a381290d46 100644 --- a/src/librustc_llvm/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,6 +1,6 @@ #![feature(nll)] #![feature(static_nobundle)] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. @@ -21,7 +21,6 @@ impl RustString { /// Appending to a Rust string -- used by RawRustStringOstream. #[no_mangle] -#[allow(improper_ctypes_definitions)] pub unsafe extern "C" fn LLVMRustStringWriteImpl( sr: &RustString, ptr: *const c_char, diff --git a/src/librustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml similarity index 100% rename from src/librustc_macros/Cargo.toml rename to compiler/rustc_macros/Cargo.toml diff --git a/src/librustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs similarity index 100% rename from src/librustc_macros/src/hash_stable.rs rename to compiler/rustc_macros/src/hash_stable.rs diff --git a/src/librustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs similarity index 78% rename from src/librustc_macros/src/lib.rs rename to compiler/rustc_macros/src/lib.rs index 7fb3b0e7ea..5c28839c9b 100644 --- a/src/librustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(proc_macro_diagnostic)] #![allow(rustc::default_hash_types)] #![recursion_limit = "128"] @@ -9,6 +10,7 @@ mod hash_stable; mod lift; mod query; mod serialize; +mod session_diagnostic; mod symbols; mod type_foldable; @@ -36,3 +38,14 @@ decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive); decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive); decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_foldable_derive); decl_derive!([Lift, attributes(lift)] => lift::lift_derive); +decl_derive!( + [SessionDiagnostic, attributes( + message, + lint, + error, + label, + suggestion, + suggestion_short, + suggestion_hidden, + suggestion_verbose)] => session_diagnostic::session_diagnostic_derive +); diff --git a/src/librustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs similarity index 100% rename from src/librustc_macros/src/lift.rs rename to compiler/rustc_macros/src/lift.rs diff --git a/src/librustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs similarity index 94% rename from src/librustc_macros/src/query.rs rename to compiler/rustc_macros/src/query.rs index c17d5311e8..e7c054653a 100644 --- a/src/librustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -5,11 +5,10 @@ use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - braced, parenthesized, parse_macro_input, Attribute, Block, Error, Expr, Ident, ReturnType, - Token, Type, + braced, parenthesized, parse_macro_input, AttrStyle, Attribute, Block, Error, Expr, Ident, + ReturnType, Token, Type, }; -#[allow(non_camel_case_types)] mod kw { syn::custom_keyword!(query); } @@ -128,17 +127,25 @@ impl Parse for QueryModifier { } /// Ensures only doc comment attributes are used -fn check_attributes(attrs: Vec) -> Result<()> { - for attr in attrs { +fn check_attributes(attrs: Vec) -> Result> { + let inner = |attr: Attribute| { if !attr.path.is_ident("doc") { - return Err(Error::new(attr.span(), "attributes not supported on queries")); + Err(Error::new(attr.span(), "attributes not supported on queries")) + } else if attr.style != AttrStyle::Outer { + Err(Error::new( + attr.span(), + "attributes must be outer attributes (`///`), not inner attributes", + )) + } else { + Ok(attr) } - } - Ok(()) + }; + attrs.into_iter().map(inner).collect() } /// A compiler query. `query ... { ... }` struct Query { + doc_comments: Vec, modifiers: List, name: Ident, key: IdentOrWild, @@ -148,7 +155,7 @@ struct Query { impl Parse for Query { fn parse(input: ParseStream<'_>) -> Result { - check_attributes(input.call(Attribute::parse_outer)?)?; + let doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?; // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>` input.parse::()?; @@ -165,7 +172,7 @@ impl Parse for Query { braced!(content in input); let modifiers = content.parse()?; - Ok(Query { modifiers, name, key, arg, result }) + Ok(Query { doc_comments, modifiers, name, key, arg, result }) } } @@ -392,7 +399,7 @@ fn add_query_description_impl( #tcx: TyCtxt<'tcx>, #key: #arg, ) -> Cow<'static, str> { - format!(#desc).into() + ::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc).into()) } }; @@ -476,9 +483,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { }; let attribute_stream = quote! {#(#attributes),*}; - + let doc_comments = query.doc_comments.iter(); // Add the query to the group group_stream.extend(quote! { + #(#doc_comments)* [#attribute_stream] fn #name: #name(#arg) #result, }); diff --git a/src/librustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs similarity index 100% rename from src/librustc_macros/src/serialize.rs rename to compiler/rustc_macros/src/serialize.rs diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs new file mode 100644 index 0000000000..610b9155cf --- /dev/null +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -0,0 +1,666 @@ +#![deny(unused_must_use)] +use proc_macro::Diagnostic; +use quote::{format_ident, quote}; +use syn::spanned::Spanned; + +use std::collections::{BTreeSet, HashMap}; + +/// Implements #[derive(SessionDiagnostic)], which allows for errors to be specified as a struct, independent +/// from the actual diagnostics emitting code. +/// ```ignore (pseudo-rust) +/// # extern crate rustc_errors; +/// # use rustc_errors::Applicability; +/// # extern crate rustc_span; +/// # use rustc_span::{symbol::Ident, Span}; +/// # extern crate rust_middle; +/// # use rustc_middle::ty::Ty; +/// #[derive(SessionDiagnostic)] +/// #[code = "E0505"] +/// #[error = "cannot move out of {name} because it is borrowed"] +/// pub struct MoveOutOfBorrowError<'tcx> { +/// pub name: Ident, +/// pub ty: Ty<'tcx>, +/// #[label = "cannot move out of borrow"] +/// pub span: Span, +/// #[label = "`{ty}` first borrowed here"] +/// pub other_span: Span, +/// #[suggestion(message = "consider cloning here", code = "{name}.clone()")] +/// pub opt_sugg: Option<(Span, Applicability)> +/// } +/// ``` +/// Then, later, to emit the error: +/// +/// ```ignore (pseudo-rust) +/// sess.emit_err(MoveOutOfBorrowError { +/// expected, +/// actual, +/// span, +/// other_span, +/// opt_sugg: Some(suggestion, Applicability::MachineApplicable), +/// }); +/// ``` +pub fn session_diagnostic_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + // Names for the diagnostic we build and the session we build it from. + let diag = format_ident!("diag"); + let sess = format_ident!("sess"); + + SessionDiagnosticDerive::new(diag, sess, s).into_tokens() +} + +// Checks whether the type name of `ty` matches `name`. +// +// Given some struct at a::b::c::Foo, this will return true for c::Foo, b::c::Foo, or +// a::b::c::Foo. This reasonably allows qualified names to be used in the macro. +fn type_matches_path(ty: &syn::Type, name: &[&str]) -> bool { + if let syn::Type::Path(ty) = ty { + ty.path + .segments + .iter() + .map(|s| s.ident.to_string()) + .rev() + .zip(name.iter().rev()) + .all(|(x, y)| &x.as_str() == y) + } else { + false + } +} + +/// The central struct for constructing the as_error method from an annotated struct. +struct SessionDiagnosticDerive<'a> { + structure: synstructure::Structure<'a>, + builder: SessionDiagnosticDeriveBuilder<'a>, +} + +impl std::convert::From for SessionDiagnosticDeriveError { + fn from(e: syn::Error) -> Self { + SessionDiagnosticDeriveError::SynError(e) + } +} + +/// Equivalent to rustc:errors::diagnostic::DiagnosticId, except stores the quoted expression to +/// initialise the code with. +enum DiagnosticId { + Error(proc_macro2::TokenStream), + Lint(proc_macro2::TokenStream), +} + +#[derive(Debug)] +enum SessionDiagnosticDeriveError { + SynError(syn::Error), + ErrorHandled, +} + +impl SessionDiagnosticDeriveError { + fn to_compile_error(self) -> proc_macro2::TokenStream { + match self { + SessionDiagnosticDeriveError::SynError(e) => e.to_compile_error(), + SessionDiagnosticDeriveError::ErrorHandled => { + // Return ! to avoid having to create a blank DiagnosticBuilder to return when an + // error has already been emitted to the compiler. + quote! { + unreachable!() + } + } + } + } +} + +fn span_err(span: impl proc_macro::MultiSpan, msg: &str) -> proc_macro::Diagnostic { + Diagnostic::spanned(span, proc_macro::Level::Error, msg) +} + +/// For methods that return a Result<_, SessionDiagnosticDeriveError>: emit a diagnostic on +/// span $span with msg $msg (and, optionally, perform additional decoration using the FnOnce +/// passed in `diag`). Then, return Err(ErrorHandled). +macro_rules! throw_span_err { + ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }}; + ($span:expr, $msg:expr, $f:expr) => {{ + return Err(_throw_span_err($span, $msg, $f)); + }}; +} + +/// When possible, prefer using throw_span_err! over using this function directly. This only exists +/// as a function to constrain `f` to an impl FnOnce. +fn _throw_span_err( + span: impl proc_macro::MultiSpan, + msg: &str, + f: impl FnOnce(proc_macro::Diagnostic) -> proc_macro::Diagnostic, +) -> SessionDiagnosticDeriveError { + let diag = span_err(span, msg); + f(diag).emit(); + SessionDiagnosticDeriveError::ErrorHandled +} + +impl<'a> SessionDiagnosticDerive<'a> { + fn new(diag: syn::Ident, sess: syn::Ident, structure: synstructure::Structure<'a>) -> Self { + // Build the mapping of field names to fields. This allows attributes to peek values from + // other fields. + let mut fields_map = HashMap::new(); + + // Convenience bindings. + let ast = structure.ast(); + + if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data { + for field in fields.iter() { + if let Some(ident) = &field.ident { + fields_map.insert(ident.to_string(), field); + } + } + } + + Self { + builder: SessionDiagnosticDeriveBuilder { diag, sess, fields: fields_map, kind: None }, + structure, + } + } + fn into_tokens(self) -> proc_macro2::TokenStream { + let SessionDiagnosticDerive { structure, mut builder } = self; + + let ast = structure.ast(); + let attrs = &ast.attrs; + + let implementation = { + if let syn::Data::Struct(..) = ast.data { + let preamble = { + let preamble = attrs.iter().map(|attr| { + builder + .generate_structure_code(attr) + .unwrap_or_else(|v| v.to_compile_error()) + }); + quote! { + #(#preamble)*; + } + }; + + let body = structure.each(|field_binding| { + let field = field_binding.ast(); + let result = field.attrs.iter().map(|attr| { + builder + .generate_field_code( + attr, + FieldInfo { + vis: &field.vis, + binding: field_binding, + ty: &field.ty, + span: &field.span(), + }, + ) + .unwrap_or_else(|v| v.to_compile_error()) + }); + return quote! { + #(#result);* + }; + }); + // Finally, putting it altogether. + match builder.kind { + None => { + span_err(ast.span().unwrap(), "`code` not specified") + .help("use the [code = \"...\"] attribute to set this diagnostic's error code ") + .emit(); + SessionDiagnosticDeriveError::ErrorHandled.to_compile_error() + } + Some((kind, _)) => match kind { + DiagnosticId::Lint(_lint) => todo!(), + DiagnosticId::Error(code) => { + let (diag, sess) = (&builder.diag, &builder.sess); + quote! { + let mut #diag = #sess.struct_err_with_code("", rustc_errors::DiagnosticId::Error(#code)); + #preamble + match self { + #body + } + #diag + } + } + }, + } + } else { + span_err( + ast.span().unwrap(), + "`#[derive(SessionDiagnostic)]` can only be used on structs", + ) + .emit(); + SessionDiagnosticDeriveError::ErrorHandled.to_compile_error() + } + }; + + let sess = &builder.sess; + structure.gen_impl(quote! { + gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess> + for @Self + { + fn into_diagnostic( + self, + #sess: &'__session_diagnostic_sess rustc_session::Session + ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess> { + #implementation + } + } + }) + } +} + +/// Field information passed to the builder. Deliberately omits attrs to discourage the generate_* +/// methods from walking the attributes themselves. +struct FieldInfo<'a> { + vis: &'a syn::Visibility, + binding: &'a synstructure::BindingInfo<'a>, + ty: &'a syn::Type, + span: &'a proc_macro2::Span, +} + +/// Tracks persistent information required for building up the individual calls to diagnostic +/// methods for the final generated method. This is a separate struct to SessionDerive only to be +/// able to destructure and split self.builder and the self.structure up to avoid a double mut +/// borrow later on. +struct SessionDiagnosticDeriveBuilder<'a> { + /// Name of the session parameter that's passed in to the as_error method. + sess: syn::Ident, + + /// Store a map of field name to its corresponding field. This is built on construction of the + /// derive builder. + fields: HashMap, + + /// The identifier to use for the generated DiagnosticBuilder instance. + diag: syn::Ident, + + /// Whether this is a lint or an error. This dictates how the diag will be initialised. Span + /// stores at what Span the kind was first set at (for error reporting purposes, if the kind + /// was multiply specified). + kind: Option<(DiagnosticId, proc_macro2::Span)>, +} + +impl<'a> SessionDiagnosticDeriveBuilder<'a> { + fn generate_structure_code( + &mut self, + attr: &syn::Attribute, + ) -> Result { + Ok(match attr.parse_meta()? { + syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { + let formatted_str = self.build_format(&s.value(), attr.span()); + let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = name.as_str(); + match name { + "message" => { + let diag = &self.diag; + quote! { + #diag.set_primary_message(#formatted_str); + } + } + attr @ "error" | attr @ "lint" => { + self.set_kind_once( + if attr == "error" { + DiagnosticId::Error(formatted_str) + } else if attr == "lint" { + DiagnosticId::Lint(formatted_str) + } else { + unreachable!() + }, + s.span(), + )?; + // This attribute is only allowed to be applied once, and the attribute + // will be set in the initialisation code. + quote! {} + } + other => throw_span_err!( + attr.span().unwrap(), + &format!( + "`#[{} = ...]` is not a valid SessionDiagnostic struct attribute", + other + ) + ), + } + } + _ => todo!("unhandled meta kind"), + }) + } + + #[must_use] + fn set_kind_once( + &mut self, + kind: DiagnosticId, + span: proc_macro2::Span, + ) -> Result<(), SessionDiagnosticDeriveError> { + if self.kind.is_none() { + self.kind = Some((kind, span)); + Ok(()) + } else { + let kind_str = |kind: &DiagnosticId| match kind { + DiagnosticId::Lint(..) => "lint", + DiagnosticId::Error(..) => "error", + }; + + let existing_kind = kind_str(&self.kind.as_ref().unwrap().0); + let this_kind = kind_str(&kind); + + let msg = if this_kind == existing_kind { + format!("`{}` specified multiple times", existing_kind) + } else { + format!("`{}` specified when `{}` was already specified", this_kind, existing_kind) + }; + throw_span_err!(span.unwrap(), &msg); + } + } + + fn generate_field_code( + &mut self, + attr: &syn::Attribute, + info: FieldInfo<'_>, + ) -> Result { + let field_binding = &info.binding.binding; + + let option_ty = option_inner_ty(&info.ty); + + let generated_code = self.generate_non_option_field_code( + attr, + FieldInfo { + vis: info.vis, + binding: info.binding, + ty: option_ty.unwrap_or(&info.ty), + span: info.span, + }, + )?; + Ok(if option_ty.is_none() { + quote! { #generated_code } + } else { + quote! { + if let Some(#field_binding) = #field_binding { + #generated_code + } + } + }) + } + + fn generate_non_option_field_code( + &mut self, + attr: &syn::Attribute, + info: FieldInfo<'_>, + ) -> Result { + let diag = &self.diag; + let field_binding = &info.binding.binding; + let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = name.as_str(); + // At this point, we need to dispatch based on the attribute key + the + // type. + let meta = attr.parse_meta()?; + Ok(match meta { + syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { + let formatted_str = self.build_format(&s.value(), attr.span()); + match name { + "message" => { + if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + quote! { + #diag.set_span(*#field_binding); + #diag.set_primary_message(#formatted_str); + } + } else { + throw_span_err!( + attr.span().unwrap(), + "the `#[message = \"...\"]` attribute can only be applied to fields of type Span" + ); + } + } + "label" => { + if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + quote! { + #diag.span_label(*#field_binding, #formatted_str); + } + } else { + throw_span_err!( + attr.span().unwrap(), + "The `#[label = ...]` attribute can only be applied to fields of type Span" + ); + } + } + other => throw_span_err!( + attr.span().unwrap(), + &format!( + "`#[{} = ...]` is not a valid SessionDiagnostic field attribute", + other + ) + ), + } + } + syn::Meta::List(list) => { + match list.path.segments.iter().last().unwrap().ident.to_string().as_str() { + suggestion_kind @ "suggestion" + | suggestion_kind @ "suggestion_short" + | suggestion_kind @ "suggestion_hidden" + | suggestion_kind @ "suggestion_verbose" => { + // For suggest, we need to ensure we are running on a (Span, + // Applicability) pair. + let (span, applicability) = (|| match &info.ty { + ty @ syn::Type::Path(..) + if type_matches_path(ty, &["rustc_span", "Span"]) => + { + let binding = &info.binding.binding; + Ok(( + quote!(*#binding), + quote!(rustc_errors::Applicability::Unspecified), + )) + } + syn::Type::Tuple(tup) => { + let mut span_idx = None; + let mut applicability_idx = None; + for (idx, elem) in tup.elems.iter().enumerate() { + if type_matches_path(elem, &["rustc_span", "Span"]) { + if span_idx.is_none() { + span_idx = Some(syn::Index::from(idx)); + } else { + throw_span_err!( + info.span.clone().unwrap(), + "type of field annotated with `#[suggestion(...)]` contains more than one Span" + ); + } + } else if type_matches_path( + elem, + &["rustc_errors", "Applicability"], + ) { + if applicability_idx.is_none() { + applicability_idx = Some(syn::Index::from(idx)); + } else { + throw_span_err!( + info.span.clone().unwrap(), + "type of field annotated with `#[suggestion(...)]` contains more than one Applicability" + ); + } + } + } + if let Some(span_idx) = span_idx { + let binding = &info.binding.binding; + let span = quote!(#binding.#span_idx); + let applicability = applicability_idx + .map( + |applicability_idx| quote!(#binding.#applicability_idx), + ) + .unwrap_or(quote!( + rustc_errors::Applicability::Unspecified + )); + return Ok((span, applicability)); + } + throw_span_err!( + info.span.clone().unwrap(), + "wrong types for suggestion", + |diag| { + diag.help("#[suggestion(...)] on a tuple field must be applied to fields of type (Span, Applicability)") + } + ); + } + _ => throw_span_err!( + info.span.clone().unwrap(), + "wrong field type for suggestion", + |diag| { + diag.help("#[suggestion(...)] should be applied to fields of type Span or (Span, Applicability)") + } + ), + })()?; + // Now read the key-value pairs. + let mut msg = None; + let mut code = None; + + for arg in list.nested.iter() { + if let syn::NestedMeta::Meta(syn::Meta::NameValue(arg_name_value)) = arg + { + if let syn::MetaNameValue { lit: syn::Lit::Str(s), .. } = + arg_name_value + { + let name = arg_name_value + .path + .segments + .last() + .unwrap() + .ident + .to_string(); + let name = name.as_str(); + let formatted_str = self.build_format(&s.value(), arg.span()); + match name { + "message" => { + msg = Some(formatted_str); + } + "code" => { + code = Some(formatted_str); + } + other => throw_span_err!( + arg.span().unwrap(), + &format!( + "`{}` is not a valid key for `#[suggestion(...)]`", + other + ) + ), + } + } + } + } + let msg = if let Some(msg) = msg { + quote!(#msg.as_str()) + } else { + throw_span_err!( + list.span().unwrap(), + "missing suggestion message", + |diag| { + diag.help("provide a suggestion message using #[suggestion(message = \"...\")]") + } + ); + }; + let code = code.unwrap_or_else(|| quote! { String::new() }); + // Now build it out: + let suggestion_method = format_ident!("span_{}", suggestion_kind); + quote! { + #diag.#suggestion_method(#span, #msg, #code, #applicability); + } + } + other => throw_span_err!( + list.span().unwrap(), + &format!("invalid annotation list `#[{}(...)]`", other) + ), + } + } + _ => panic!("unhandled meta kind"), + }) + } + + /// In the strings in the attributes supplied to this macro, we want callers to be able to + /// reference fields in the format string. Take this, for example: + /// ```ignore (not-usage-example) + /// struct Point { + /// #[error = "Expected a point greater than ({x}, {y})"] + /// x: i32, + /// y: i32, + /// } + /// ``` + /// We want to automatically pick up that {x} refers `self.x` and {y} refers to `self.y`, then + /// generate this call to format!: + /// ```ignore (not-usage-example) + /// format!("Expected a point greater than ({x}, {y})", x = self.x, y = self.y) + /// ``` + /// This function builds the entire call to format!. + fn build_format(&self, input: &String, span: proc_macro2::Span) -> proc_macro2::TokenStream { + // This set is used later to generate the final format string. To keep builds reproducible, + // the iteration order needs to be deterministic, hence why we use a BTreeSet here instead + // of a HashSet. + let mut referenced_fields: BTreeSet = BTreeSet::new(); + + // At this point, we can start parsing the format string. + let mut it = input.chars().peekable(); + // Once the start of a format string has been found, process the format string and spit out + // 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') != '{' { + #[must_use] + 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; + } + Some(result) + }; + + if let Some(referenced_field) = eat_argument() { + referenced_fields.insert(referenced_field); + } + } + } + // At this point, `referenced_fields` contains a set of the unique fields that were + // referenced in the format string. Generate the corresponding "x = self.x" format + // string parameters: + let args = referenced_fields.into_iter().map(|field: String| { + let field_ident = format_ident!("{}", field); + let value = if self.fields.contains_key(&field) { + quote! { + &self.#field_ident + } + } else { + // This field doesn't exist. Emit a diagnostic. + Diagnostic::spanned( + span.unwrap(), + proc_macro::Level::Error, + format!("`{}` doesn't refer to a field on this type", field), + ) + .emit(); + quote! { + "{#field}" + } + }; + quote! { + #field_ident = #value + } + }); + quote! { + format!(#input #(,#args)*) + } + } +} + +/// If `ty` is an Option, returns Some(inner type). Else, returns None. +fn option_inner_ty(ty: &syn::Type) -> Option<&syn::Type> { + if type_matches_path(ty, &["std", "option", "Option"]) { + if let syn::Type::Path(ty_path) = ty { + let path = &ty_path.path; + let ty = path.segments.iter().last().unwrap(); + if let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments { + if bracketed.args.len() == 1 { + if let syn::GenericArgument::Type(ty) = &bracketed.args[0] { + return Some(ty); + } + } + } + } + } + None +} diff --git a/src/librustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs similarity index 99% rename from src/librustc_macros/src/symbols.rs rename to compiler/rustc_macros/src/symbols.rs index 352665f0ab..94d4ad78e8 100644 --- a/src/librustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -4,7 +4,6 @@ use std::collections::HashSet; use syn::parse::{Parse, ParseStream, Result}; use syn::{braced, parse_macro_input, Ident, LitStr, Token}; -#[allow(non_camel_case_types)] mod kw { syn::custom_keyword!(Keywords); syn::custom_keyword!(Symbols); diff --git a/src/librustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs similarity index 100% rename from src/librustc_macros/src/type_foldable.rs rename to compiler/rustc_macros/src/type_foldable.rs diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml new file mode 100644 index 0000000000..f1975e7880 --- /dev/null +++ b/compiler/rustc_metadata/Cargo.toml @@ -0,0 +1,34 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_metadata" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +libc = "0.2" +snap = "1" +tracing = "0.1" +memmap = "0.7" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_middle = { path = "../rustc_middle" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_target = { path = "../rustc_target" } +rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +stable_deref_trait = "1.0.0" +rustc_ast = { path = "../rustc_ast" } +rustc_expand = { path = "../rustc_expand" } +rustc_span = { path = "../rustc_span" } +rustc_session = { path = "../rustc_session" } + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] } diff --git a/src/librustc_metadata/creader.rs b/compiler/rustc_metadata/src/creader.rs similarity index 98% rename from src/librustc_metadata/creader.rs rename to compiler/rustc_metadata/src/creader.rs index f8446d83d2..7562da6d78 100644 --- a/src/librustc_metadata/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -222,6 +222,7 @@ impl<'a> CrateLoader<'a> { let mut ret = None; self.cstore.iter_crate_data(|cnum, data| { if data.name() != name { + tracing::trace!("{} did not match {}", data.name(), name); return; } @@ -230,7 +231,10 @@ impl<'a> CrateLoader<'a> { ret = Some(cnum); return; } - Some(..) => return, + Some(hash) => { + debug!("actual hash {} did not match expected {}", hash, data.hash()); + return; + } None => {} } @@ -273,6 +277,11 @@ impl<'a> CrateLoader<'a> { .1; if kind.matches(prev_kind) { ret = Some(cnum); + } else { + debug!( + "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}", + name, kind, prev_kind + ); } }); ret diff --git a/src/librustc_metadata/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs similarity index 100% rename from src/librustc_metadata/dependency_format.rs rename to compiler/rustc_metadata/src/dependency_format.rs diff --git a/src/librustc_metadata/dynamic_lib.rs b/compiler/rustc_metadata/src/dynamic_lib.rs similarity index 51% rename from src/librustc_metadata/dynamic_lib.rs rename to compiler/rustc_metadata/src/dynamic_lib.rs index ce19240a00..bdb53e3f75 100644 --- a/src/librustc_metadata/dynamic_lib.rs +++ b/compiler/rustc_metadata/src/dynamic_lib.rs @@ -51,51 +51,90 @@ mod tests; #[cfg(unix)] mod dl { - use std::ffi::{CStr, CString, OsStr}; + use std::ffi::{CString, OsStr}; use std::os::unix::prelude::*; - use std::ptr; - use std::str; - pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> { - check_for_errors_in(|| unsafe { - let s = CString::new(filename.as_bytes()).unwrap(); - libc::dlopen(s.as_ptr(), libc::RTLD_LAZY) as *mut u8 - }) - } + // As of the 2017 revision of the POSIX standard (IEEE 1003.1-2017), it is + // implementation-defined whether `dlerror` is thread-safe (in which case it returns the most + // recent error in the calling thread) or not thread-safe (in which case it returns the most + // recent error in *any* thread). + // + // There's no easy way to tell what strategy is used by a given POSIX implementation, so we + // lock around all calls that can modify `dlerror` in this module lest we accidentally read an + // error from a different thread. This is bulletproof when we are the *only* code using the + // dynamic library APIs at a given point in time. However, it's still possible for us to race + // with other code (see #74469) on platforms where `dlerror` is not thread-safe. + mod error { + use std::ffi::CStr; + use std::lazy::SyncLazy; + use std::sync::{Mutex, MutexGuard}; + + pub fn lock() -> MutexGuard<'static, Guard> { + static LOCK: SyncLazy> = SyncLazy::new(|| Mutex::new(Guard { _priv: () })); + LOCK.lock().unwrap() + } - fn check_for_errors_in(f: F) -> Result - where - F: FnOnce() -> T, - { - use std::sync::{Mutex, Once}; - static INIT: Once = Once::new(); - static mut LOCK: *mut Mutex<()> = ptr::null_mut(); - unsafe { - INIT.call_once(|| { - LOCK = Box::into_raw(Box::new(Mutex::new(()))); - }); - // dlerror isn't thread safe, so we need to lock around this entire - // sequence - let _guard = (*LOCK).lock(); - let _old_error = libc::dlerror(); - - let result = f(); - - let last_error = libc::dlerror() as *const _; - if ptr::null() == last_error { - Ok(result) - } else { - let s = CStr::from_ptr(last_error).to_bytes(); - Err(str::from_utf8(s).unwrap().to_owned()) + pub struct Guard { + _priv: (), + } + + impl Guard { + pub fn get(&mut self) -> Result<(), String> { + let msg = unsafe { libc::dlerror() }; + if msg.is_null() { + Ok(()) + } else { + let msg = unsafe { CStr::from_ptr(msg as *const _) }; + Err(msg.to_string_lossy().into_owned()) + } + } + + pub fn clear(&mut self) { + let _ = unsafe { libc::dlerror() }; } } } + pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> { + let s = CString::new(filename.as_bytes()).unwrap(); + + let mut dlerror = error::lock(); + let ret = unsafe { libc::dlopen(s.as_ptr(), libc::RTLD_LAZY | libc::RTLD_LOCAL) }; + + if !ret.is_null() { + return Ok(ret.cast()); + } + + // A NULL return from `dlopen` indicates that an error has definitely occurred, so if + // nothing is in `dlerror`, we are racing with another thread that has stolen our error + // message. See the explanation on the `dl::error` module for more information. + dlerror.get().and_then(|()| Err("Unknown error".to_string())) + } + pub(super) unsafe fn symbol( handle: *mut u8, symbol: *const libc::c_char, ) -> Result<*mut u8, String> { - check_for_errors_in(|| libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8) + let mut dlerror = error::lock(); + + // Unlike `dlopen`, it's possible for `dlsym` to return NULL without overwriting `dlerror`. + // Because of this, we clear `dlerror` before calling `dlsym` to avoid picking up a stale + // error message by accident. + dlerror.clear(); + + let ret = libc::dlsym(handle as *mut libc::c_void, symbol); + + if !ret.is_null() { + return Ok(ret.cast()); + } + + // If `dlsym` returns NULL but there is nothing in `dlerror` it means one of two things: + // - We tried to load a symbol mapped to address 0. This is not technically an error but is + // unlikely to occur in practice and equally unlikely to be handled correctly by calling + // code. Therefore we treat it as an error anyway. + // - An error has occurred, but we are racing with another thread that has stolen our error + // message. See the explanation on the `dl::error` module for more information. + dlerror.get().and_then(|()| Err("Tried to load symbol mapped to address 0".to_string())) } pub(super) unsafe fn close(handle: *mut u8) { diff --git a/src/librustc_metadata/dynamic_lib/tests.rs b/compiler/rustc_metadata/src/dynamic_lib/tests.rs similarity index 100% rename from src/librustc_metadata/dynamic_lib/tests.rs rename to compiler/rustc_metadata/src/dynamic_lib/tests.rs diff --git a/src/librustc_metadata/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs similarity index 100% rename from src/librustc_metadata/foreign_modules.rs rename to compiler/rustc_metadata/src/foreign_modules.rs diff --git a/src/librustc_metadata/lib.rs b/compiler/rustc_metadata/src/lib.rs similarity index 87% rename from src/librustc_metadata/lib.rs rename to compiler/rustc_metadata/src/lib.rs index e50fa34554..77766be739 100644 --- a/src/librustc_metadata/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,10 +1,11 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] #![feature(nll)] +#![feature(once_cell)] #![feature(or_patterns)] #![feature(proc_macro_internals)] #![feature(min_specialization)] diff --git a/src/librustc_metadata/link_args.rs b/compiler/rustc_metadata/src/link_args.rs similarity index 100% rename from src/librustc_metadata/link_args.rs rename to compiler/rustc_metadata/src/link_args.rs diff --git a/src/librustc_metadata/locator.rs b/compiler/rustc_metadata/src/locator.rs similarity index 99% rename from src/librustc_metadata/locator.rs rename to compiler/rustc_metadata/src/locator.rs index 8fa14a44f5..0869ec2836 100644 --- a/src/librustc_metadata/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -229,7 +229,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use rustc_target::spec::{Target, TargetTriple}; -use flate2::read::DeflateDecoder; +use snap::read::FrameDecoder; use std::io::{Read, Result as IoResult, Write}; use std::ops::Deref; use std::path::{Path, PathBuf}; @@ -766,7 +766,7 @@ fn get_metadata_section( let compressed_bytes = &buf[header_len..]; debug!("inflating {} bytes of compressed metadata", compressed_bytes.len()); let mut inflated = Vec::new(); - match DeflateDecoder::new(compressed_bytes).read_to_end(&mut inflated) { + match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) { Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()), Err(_) => { return Err(format!("failed to decompress metadata: {}", filename.display())); diff --git a/src/librustc_metadata/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs similarity index 98% rename from src/librustc_metadata/native_libs.rs rename to compiler/rustc_metadata/src/native_libs.rs index 3976475cb0..e76c2cb356 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -170,7 +170,7 @@ impl Collector<'tcx> { feature_err( &self.tcx.sess.parse_sess, sym::static_nobundle, - span.unwrap_or_else(|| rustc_span::DUMMY_SP), + span.unwrap_or(rustc_span::DUMMY_SP), "kind=\"static-nobundle\" is unstable", ) .emit(); @@ -179,7 +179,7 @@ impl Collector<'tcx> { feature_err( &self.tcx.sess.parse_sess, sym::raw_dylib, - span.unwrap_or_else(|| rustc_span::DUMMY_SP), + span.unwrap_or(rustc_span::DUMMY_SP), "kind=\"raw-dylib\" is unstable", ) .emit(); diff --git a/src/librustc_metadata/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs similarity index 97% rename from src/librustc_metadata/rmeta/decoder.rs rename to compiler/rustc_metadata/src/rmeta/decoder.rs index 43d76e9fdb..c31e941b3f 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -11,6 +11,7 @@ use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, OnceCell}; +use rustc_errors::ErrorReported; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive}; use rustc_hir as hir; @@ -562,6 +563,12 @@ impl<'a, 'tcx> Decodable> for Span { } } +impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { + ty::codec::RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { ty::codec::RefDecodable::decode(d) @@ -700,7 +707,11 @@ impl CrateRoot<'_> { impl<'a, 'tcx> CrateMetadataRef<'a> { fn is_proc_macro(&self, id: DefIndex) -> bool { - self.root.proc_macro_data.and_then(|data| data.decode(self).find(|x| *x == id)).is_some() + self.root + .proc_macro_data + .as_ref() + .and_then(|data| data.macros.decode(self).find(|x| *x == id)) + .is_some() } fn maybe_kind(&self, item_id: DefIndex) -> Option { @@ -722,7 +733,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. - let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap(); + let pos = self + .root + .proc_macro_data + .as_ref() + .unwrap() + .macros + .decode(self) + .position(|i| i == id) + .unwrap(); &self.raw_proc_macros.unwrap()[pos] } @@ -759,7 +778,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_span(&self, index: DefIndex, sess: &Session) -> Span { - self.root.tables.span.get(self, index).unwrap().decode((self, sess)) + self.root + .tables + .span + .get(self, index) + .unwrap_or_else(|| panic!("Missing span for {:?}", index)) + .decode((self, sess)) } fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension { @@ -935,7 +959,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_stability(&self, id: DefIndex) -> Option { match self.is_proc_macro(id) { - true => self.root.proc_macro_stability, + true => self.root.proc_macro_data.as_ref().unwrap().stability, false => self.root.tables.stability.get(self, id).map(|stab| stab.decode(self)), } } @@ -1028,24 +1052,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { where F: FnMut(Export), { - if let Some(proc_macros_ids) = self.root.proc_macro_data.map(|d| d.decode(self)) { + if let Some(data) = &self.root.proc_macro_data { /* If we are loading as a proc macro, we want to return the view of this crate * as a proc macro crate. */ if id == CRATE_DEF_INDEX { - for def_index in proc_macros_ids { + let macros = data.macros.decode(self); + for def_index in macros { let raw_macro = self.raw_proc_macro(def_index); let res = Res::Def( DefKind::Macro(macro_kind(raw_macro)), self.local_def_id(def_index), ); let ident = self.item_ident(def_index, sess); - callback(Export { - ident, - res, - vis: ty::Visibility::Public, - span: self.get_span(def_index, sess), - }); + callback(Export { ident, res, vis: ty::Visibility::Public, span: ident.span }); } } return; @@ -1191,6 +1211,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } + fn get_mir_abstract_const( + &self, + tcx: TyCtxt<'tcx>, + id: DefIndex, + ) -> Result]>, ErrorReported> { + self.root + .tables + .mir_abstract_consts + .get(self, id) + .filter(|_| !self.is_proc_macro(id)) + .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) + } + fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { self.root .tables @@ -1539,12 +1572,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> { let mut def_path_hashes = self.def_path_hash_cache.lock(); - (0..self.num_def_ids()) - .map(|index| { - let index = DefIndex::from_usize(index); - (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) - }) - .collect() + let mut def_index_to_data = |index| { + (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) + }; + if let Some(data) = &self.root.proc_macro_data { + std::iter::once(CRATE_DEF_INDEX) + .chain(data.macros.decode(self)) + .map(def_index_to_data) + .collect() + } else { + (0..self.num_def_ids()) + .map(|index| def_index_to_data(DefIndex::from_usize(index))) + .collect() + } } /// Get the `DepNodeIndex` corresponding this crate. The result of this diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs similarity index 97% rename from src/librustc_metadata/rmeta/decoder/cstore_impl.rs rename to compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 36ff65fc5e..4102cf84a6 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::utils::NativeLibKind; use rustc_session::{CrateDisambiguator, Session}; -use rustc_span::source_map::{self, Span, Spanned}; +use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Symbol; use rustc_data_structures::sync::Lrc; @@ -112,6 +112,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, } optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) } promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } + mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) } unused_generic_params => { cdata.get_unused_generic_params(def_id.index) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } fn_sig => { cdata.fn_sig(def_id.index, tcx) } @@ -178,8 +179,11 @@ provide! { <'tcx> tcx, def_id, other, cdata, }) } proc_macro_decls_static => { - cdata.root.proc_macro_decls_static.map(|index| { - DefId { krate: def_id.krate, index } + cdata.root.proc_macro_data.as_ref().map(|data| { + DefId { + krate: def_id.krate, + index: data.proc_macro_decls_static, + } }) } crate_disambiguator => { cdata.root.disambiguator } @@ -421,7 +425,11 @@ impl CStore { span, attrs: attrs.to_vec(), kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)), - vis: source_map::respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: span.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, tokens: None, }, data.root.edition, diff --git a/src/librustc_metadata/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs similarity index 93% rename from src/librustc_metadata/rmeta/encoder.rs rename to compiler/rustc_metadata/src/rmeta/encoder.rs index 509ef1caf1..f58a792ef5 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -40,6 +40,7 @@ use tracing::{debug, trace}; pub(super) struct EncodeContext<'a, 'tcx> { opaque: opaque::Encoder, tcx: TyCtxt<'tcx>, + feat: &'tcx rustc_feature::Features, tables: TableBuilders<'tcx>, @@ -67,6 +68,17 @@ pub(super) struct EncodeContext<'a, 'tcx> { hygiene_ctxt: &'a HygieneEncodeContext, } +/// If the current crate is a proc-macro, returns early with `Lazy:empty()`. +/// This is useful for skipping the encoding of things that aren't needed +/// for proc-macro crates. +macro_rules! empty_proc_macro { + ($self:ident) => { + if $self.is_proc_macro { + return Lazy::empty(); + } + }; +} + macro_rules! encoder_methods { ($($name:ident($ty:ty);)*) => { $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { @@ -137,6 +149,15 @@ where } } +impl<'a, 'tcx> Encodable> for CrateNum { + fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { + if *self != LOCAL_CRATE && s.is_proc_macro { + panic!("Attempted to encode non-local CrateNum {:?} for proc-macro crate", self); + } + s.emit_u32(self.as_u32()) + } +} + impl<'a, 'tcx> Encodable> for DefIndex { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { s.emit_u32(self.as_u32()) @@ -162,7 +183,7 @@ impl<'a, 'tcx> Encodable> for ExpnId { impl<'a, 'tcx> Encodable> for Span { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - if self.is_dummy() { + if *self == rustc_span::DUMMY_SP { return TAG_INVALID_SPAN.encode(s); } @@ -320,6 +341,12 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { } } +impl<'a, 'tcx> Encodable> for &'tcx [mir::abstract_const::Node<'tcx>] { + fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { + (**self).encode(s) + } +} + impl<'a, 'tcx> Encodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { (**self).encode(s) @@ -411,6 +438,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let krate = self.tcx.hir().krate(); let vis = Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public }; self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs, &vis); + + // Proc-macro crates only export proc-macro items, which are looked + // up using `proc_macro_data` + if self.is_proc_macro { + return; + } + krate.visit_all_item_likes(&mut self.as_deep_visitor()); for macro_def in krate.exported_macros { self.visit_macro_def(macro_def); @@ -419,11 +453,22 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_def_path_table(&mut self) { let table = self.tcx.hir().definitions().def_path_table(); - for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() { - let def_key = self.lazy(def_key); - let def_path_hash = self.lazy(def_path_hash); - self.tables.def_keys.set(def_index, def_key); - self.tables.def_path_hashes.set(def_index, def_path_hash); + if self.is_proc_macro { + for def_index in std::iter::once(CRATE_DEF_INDEX) + .chain(self.tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index)) + { + let def_key = self.lazy(table.def_key(def_index)); + let def_path_hash = self.lazy(table.def_path_hash(def_index)); + self.tables.def_keys.set(def_index, def_key); + self.tables.def_path_hashes.set(def_index, def_path_hash); + } + } else { + for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() { + let def_key = self.lazy(def_key); + let def_path_hash = self.lazy(def_path_hash); + self.tables.def_keys.set(def_index, def_key); + self.tables.def_path_hashes.set(def_index, def_path_hash); + } } } @@ -490,13 +535,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(adapted.iter().map(|rc| &**rc)) } - fn is_proc_macro(&self) -> bool { - self.tcx.sess.crate_types().contains(&CrateType::ProcMacro) - } - fn encode_crate_root(&mut self) -> Lazy> { - let is_proc_macro = self.is_proc_macro(); - let mut i = self.position(); // Encode the crate deps @@ -568,15 +607,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(interpret_alloc_index) }; - i = self.position(); - let tables = self.tables.encode(&mut self.opaque); - let tables_bytes = self.position() - i; - - // Encode the proc macro data + // Encode the proc macro data. This affects 'tables', + // so we need to do this before we encode the tables i = self.position(); let proc_macro_data = self.encode_proc_macros(); let proc_macro_data_bytes = self.position() - i; + i = self.position(); + let tables = self.tables.encode(&mut self.opaque); + let tables_bytes = self.position() - i; + // Encode exported symbols info. This is prefetched in `encode_metadata` so we encode // this as late as possible to give the prefetching as much time as possible to complete. i = self.position(); @@ -617,18 +657,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), has_default_lib_allocator, plugin_registrar_fn: tcx.plugin_registrar_fn(LOCAL_CRATE).map(|id| id.index), - proc_macro_decls_static: if is_proc_macro { - let id = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap(); - Some(id.index) - } else { - None - }, proc_macro_data, - proc_macro_stability: if is_proc_macro { - tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied() - } else { - None - }, compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins), needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator), needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime), @@ -793,8 +822,13 @@ impl EncodeContext<'a, 'tcx> { let def_id = local_def_id.to_def_id(); debug!("EncodeContext::encode_info_for_mod({:?})", def_id); - let data = ModData { - reexports: match tcx.module_exports(local_def_id) { + // If we are encoding a proc-macro crates, `encode_info_for_mod` will + // only ever get called for the crate root. We still want to encode + // the crate root for consistency with other crates (some of the resolver + // 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_exports(local_def_id) { Some(exports) => { let hir = self.tcx.hir(); self.lazy( @@ -804,7 +838,13 @@ impl EncodeContext<'a, 'tcx> { ) } _ => Lazy::empty(), - }, + } + } else { + Lazy::empty() + }; + + let data = ModData { + reexports, expansion: tcx.hir().definitions().expansion_that_defined(local_def_id), }; @@ -812,9 +852,13 @@ impl EncodeContext<'a, 'tcx> { record!(self.tables.visibility[def_id] <- ty::Visibility::from_hir(vis, id, self.tcx)); record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); record!(self.tables.attributes[def_id] <- attrs); - record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| { - tcx.hir().local_def_id(item_id.id).local_def_index - })); + if self.is_proc_macro { + record!(self.tables.children[def_id] <- &[]); + } else { + record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| { + tcx.hir().local_def_id(item_id.id).local_def_index + })); + } self.encode_stability(def_id); self.encode_deprecation(def_id); } @@ -1108,6 +1152,11 @@ impl EncodeContext<'a, 'tcx> { if !unused.is_empty() { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } + + let abstract_const = self.tcx.mir_abstract_const(def_id); + if let Ok(Some(abstract_const)) = abstract_const { + record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const); + } } } @@ -1132,15 +1181,25 @@ impl EncodeContext<'a, 'tcx> { fn encode_stability(&mut self, def_id: DefId) { debug!("EncodeContext::encode_stability({:?})", def_id); - if let Some(stab) = self.tcx.lookup_stability(def_id) { - record!(self.tables.stability[def_id] <- stab) + + // 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.debugging_opts.force_unstable_if_unmarked { + if let Some(stab) = self.tcx.lookup_stability(def_id) { + record!(self.tables.stability[def_id] <- stab) + } } } fn encode_const_stability(&mut self, def_id: DefId) { debug!("EncodeContext::encode_const_stability({:?})", def_id); - if let Some(stab) = self.tcx.lookup_const_stability(def_id) { - record!(self.tables.const_stability[def_id] <- stab) + + // 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.debugging_opts.force_unstable_if_unmarked { + if let Some(stab) = self.tcx.lookup_const_stability(def_id) { + record!(self.tables.const_stability[def_id] <- stab) + } } } @@ -1278,7 +1337,7 @@ impl EncodeContext<'a, 'tcx> { }); record!(self.tables.visibility[def_id] <- ty::Visibility::from_hir(&item.vis, item.hir_id, tcx)); - record!(self.tables.span[def_id] <- item.span); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); record!(self.tables.attributes[def_id] <- item.attrs); // FIXME(eddyb) there should be a nicer way to do this. match item.kind { @@ -1418,7 +1477,7 @@ impl EncodeContext<'a, 'tcx> { let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let ty = self.tcx.typeck(def_id).node_type(hir_id); - record!(self.tables.kind[def_id.to_def_id()] <- match ty.kind { + record!(self.tables.kind[def_id.to_def_id()] <- match ty.kind() { ty::Generator(..) => { let data = self.tcx.generator_kind(def_id).unwrap(); EntryKind::Generator(data) @@ -1432,7 +1491,7 @@ impl EncodeContext<'a, 'tcx> { record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id)); record!(self.tables.attributes[def_id.to_def_id()] <- &self.tcx.get_attrs(def_id.to_def_id())[..]); self.encode_item_type(def_id.to_def_id()); - if let ty::Closure(def_id, substs) = ty.kind { + if let ty::Closure(def_id, substs) = *ty.kind() { record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig()); } self.encode_generics(def_id.to_def_id()); @@ -1459,11 +1518,13 @@ impl EncodeContext<'a, 'tcx> { } fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> { + empty_proc_macro!(self); let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); self.lazy(used_libraries.iter().cloned()) } fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> { + empty_proc_macro!(self); let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE); self.lazy(foreign_modules.iter().cloned()) } @@ -1487,17 +1548,37 @@ impl EncodeContext<'a, 'tcx> { (syntax_contexts.encode(&mut self.opaque), expn_data_table.encode(&mut self.opaque)) } - fn encode_proc_macros(&mut self) -> Option> { + fn encode_proc_macros(&mut self) -> Option { let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro); if is_proc_macro { let tcx = self.tcx; - Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index))) + let hir = tcx.hir(); + + let proc_macro_decls_static = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap().index; + let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied(); + let macros = self.lazy(hir.krate().proc_macros.iter().map(|p| p.owner.local_def_index)); + + // Normally, this information is encoded when we walk the items + // defined in this crate. However, we skip doing that for proc-macro crates, + // so we manually encode just the information that we need + for proc_macro in &hir.krate().proc_macros { + let id = proc_macro.owner.local_def_index; + let span = self.lazy(hir.span(*proc_macro)); + // Proc-macros may have attributes like `#[allow_internal_unstable]`, + // so downstream crates need access to them. + let attrs = self.lazy(hir.attrs(*proc_macro)); + self.tables.span.set(id, span); + self.tables.attributes.set(id, attrs); + } + + Some(ProcMacroData { proc_macro_decls_static, stability, macros }) } else { None } } fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> { + empty_proc_macro!(self); let crates = self.tcx.crates(); let mut deps = crates @@ -1533,18 +1614,21 @@ impl EncodeContext<'a, 'tcx> { } fn encode_lib_features(&mut self) -> Lazy<[(Symbol, Option)]> { + empty_proc_macro!(self); let tcx = self.tcx; let lib_features = tcx.lib_features(); self.lazy(lib_features.to_vec()) } fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> { + empty_proc_macro!(self); let tcx = self.tcx; let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE); self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) } fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> { + empty_proc_macro!(self); let tcx = self.tcx; let lang_items = tcx.lang_items(); let lang_items = lang_items.items().iter(); @@ -1559,12 +1643,14 @@ impl EncodeContext<'a, 'tcx> { } fn encode_lang_items_missing(&mut self) -> Lazy<[lang_items::LangItem]> { + empty_proc_macro!(self); let tcx = self.tcx; self.lazy(&tcx.lang_items().missing) } /// Encodes an index, mapping each trait to its (local) implementations. fn encode_impls(&mut self) -> Lazy<[TraitImpls]> { + empty_proc_macro!(self); debug!("EncodeContext::encode_impls()"); let tcx = self.tcx; let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() }; @@ -1603,6 +1689,7 @@ impl EncodeContext<'a, 'tcx> { &mut self, exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportLevel)], ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]> { + empty_proc_macro!(self); // The metadata symbol name is special. It should not show up in // downstream crates. let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx)); @@ -1619,6 +1706,7 @@ impl EncodeContext<'a, 'tcx> { } fn encode_dylib_dependency_formats(&mut self) -> Lazy<[Option]> { + empty_proc_macro!(self); let formats = self.tcx.dependency_formats(LOCAL_CRATE); for (ty, arr) in formats.iter() { if *ty != CrateType::Dylib { @@ -1665,6 +1753,7 @@ impl EncodeContext<'a, 'tcx> { self.encode_const_stability(def_id); self.encode_deprecation(def_id); self.encode_item_type(def_id); + self.encode_inherent_implementations(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); @@ -1734,6 +1823,9 @@ impl EncodeContext<'a, 'tcx> { EntryKind::TypeParam, default.is_some(), ); + if default.is_some() { + self.encode_stability(def_id.to_def_id()); + } } GenericParamKind::Const { .. } => { self.encode_info_for_generic_param( @@ -1741,6 +1833,7 @@ impl EncodeContext<'a, 'tcx> { EntryKind::ConstParam, true, ); + // FIXME(const_generics:defaults) } } } @@ -1979,6 +2072,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { let mut ecx = EncodeContext { opaque: encoder, tcx, + feat: tcx.features(), tables: Default::default(), lazy_state: LazyState::NoNode, type_shorthands: Default::default(), diff --git a/src/librustc_metadata/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs similarity index 91% rename from src/librustc_metadata/rmeta/mod.rs rename to compiler/rustc_metadata/src/rmeta/mod.rs index 1ba5962d11..1a127035d4 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -172,6 +172,29 @@ macro_rules! Lazy { type SyntaxContextTable = Lazy>>; type ExpnDataTable = Lazy>>; +#[derive(MetadataEncodable, MetadataDecodable)] +crate struct ProcMacroData { + proc_macro_decls_static: DefIndex, + stability: Option, + macros: Lazy<[DefIndex]>, +} + +/// Serialized metadata for a crate. +/// When compiling a proc-macro crate, we encode many of +/// the `Lazy<[T]>` fields as `Lazy::empty()`. This serves two purposes: +/// +/// 1. We avoid performing unnecessary work. Proc-macro crates can only +/// export proc-macros functions, which are compiled into a shared library. +/// As a result, a large amount of the information we normally store +/// (e.g. optimized MIR) is unneeded by downstream crates. +/// 2. We avoid serializing invalid `CrateNum`s. When we deserialize +/// a proc-macro crate, we don't load any of its dependencies (since we +/// just need to invoke a native function from the shared library). +/// This means that any foreign `CrateNum`s that we serialize cannot be +/// deserialized, since we will not know how to map them into the current +/// compilation session. If we were to serialize a proc-macro crate like +/// a normal crate, much of what we serialized would be unusable in addition +/// to being unused. #[derive(MetadataEncodable, MetadataDecodable)] crate struct CrateRoot<'tcx> { name: Symbol, @@ -185,8 +208,6 @@ crate struct CrateRoot<'tcx> { has_panic_handler: bool, has_default_lib_allocator: bool, plugin_registrar_fn: Option, - proc_macro_decls_static: Option, - proc_macro_stability: Option, crate_deps: Lazy<[CrateDep]>, dylib_dependency_formats: Lazy<[Option]>, @@ -198,12 +219,10 @@ crate struct CrateRoot<'tcx> { foreign_modules: Lazy<[ForeignModule]>, impls: Lazy<[TraitImpls]>, interpret_alloc_index: Lazy<[u32]>, + proc_macro_data: Option, tables: LazyTables<'tcx>, - /// The DefIndex's of any proc macros declared by this crate. - proc_macro_data: Option>, - exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]), syntax_contexts: SyntaxContextTable, @@ -284,6 +303,7 @@ define_tables! { super_predicates: Table)>, mir: Table)>, promoted_mir: Table>)>, + mir_abstract_consts: Table])>, unused_generic_params: Table>>, // `def_keys` and `def_path_hashes` represent a lazy version of a // `DefPathTable`. This allows us to avoid deserializing an entire diff --git a/src/librustc_metadata/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs similarity index 100% rename from src/librustc_metadata/rmeta/table.rs rename to compiler/rustc_metadata/src/rmeta/table.rs diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml new file mode 100644 index 0000000000..e8ace361b2 --- /dev/null +++ b/compiler/rustc_middle/Cargo.toml @@ -0,0 +1,32 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_middle" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +bitflags = "1.2.1" +tracing = "0.1" +rustc-rayon-core = "0.3.0" +polonius-engine = "0.12.0" +rustc_apfloat = { path = "../rustc_apfloat" } +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_index = { path = "../rustc_index" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +chalk-ir = "0.29.0" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +measureme = "0.7.1" +rustc_session = { path = "../rustc_session" } diff --git a/src/librustc_middle/README.md b/compiler/rustc_middle/README.md similarity index 100% rename from src/librustc_middle/README.md rename to compiler/rustc_middle/README.md diff --git a/src/librustc_middle/benches/lib.rs b/compiler/rustc_middle/benches/lib.rs similarity index 100% rename from src/librustc_middle/benches/lib.rs rename to compiler/rustc_middle/benches/lib.rs diff --git a/src/librustc_middle/arena.rs b/compiler/rustc_middle/src/arena.rs similarity index 100% rename from src/librustc_middle/arena.rs rename to compiler/rustc_middle/src/arena.rs diff --git a/src/librustc_middle/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs similarity index 100% rename from src/librustc_middle/dep_graph/dep_node.rs rename to compiler/rustc_middle/src/dep_graph/dep_node.rs diff --git a/src/librustc_middle/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs similarity index 100% rename from src/librustc_middle/dep_graph/mod.rs rename to compiler/rustc_middle/src/dep_graph/mod.rs diff --git a/src/librustc_middle/hir/exports.rs b/compiler/rustc_middle/src/hir/exports.rs similarity index 100% rename from src/librustc_middle/hir/exports.rs rename to compiler/rustc_middle/src/hir/exports.rs diff --git a/src/librustc_middle/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs similarity index 100% rename from src/librustc_middle/hir/map/blocks.rs rename to compiler/rustc_middle/src/hir/map/blocks.rs diff --git a/src/librustc_middle/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs similarity index 98% rename from src/librustc_middle/hir/map/collector.rs rename to compiler/rustc_middle/src/hir/map/collector.rs index dce06a5f7e..d6869ab887 100644 --- a/src/librustc_middle/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -244,7 +244,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { if cfg!(debug_assertions) { if hir_id.owner != self.current_dep_node_owner { let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) { - Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate(), + Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(), None => format!("{:?}", node), }; @@ -254,9 +254,11 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", self.source_map.span_to_string(span), node_str, - self.definitions.def_path(self.current_dep_node_owner).to_string_no_crate(), + self.definitions + .def_path(self.current_dep_node_owner) + .to_string_no_crate_verbose(), self.current_dep_node_owner, - self.definitions.def_path(hir_id.owner).to_string_no_crate(), + self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(), hir_id.owner, ) } diff --git a/src/librustc_middle/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs similarity index 99% rename from src/librustc_middle/hir/map/mod.rs rename to compiler/rustc_middle/src/hir/map/mod.rs index 1e57411f9c..ceb873adf5 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1002,11 +1002,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { let def_id = map.local_def_id(id); tcx.def_path_str(def_id.to_def_id()) } else if let Some(path) = map.def_path_from_hir_id(id) { - path.data - .into_iter() - .map(|elem| elem.data.to_string()) - .collect::>() - .join("::") + path.data.into_iter().map(|elem| elem.to_string()).collect::>().join("::") } else { String::from("") } diff --git a/src/librustc_middle/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs similarity index 100% rename from src/librustc_middle/hir/mod.rs rename to compiler/rustc_middle/src/hir/mod.rs diff --git a/src/librustc_middle/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs similarity index 100% rename from src/librustc_middle/hir/place.rs rename to compiler/rustc_middle/src/hir/place.rs diff --git a/src/librustc_middle/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs similarity index 100% rename from src/librustc_middle/ich/hcx.rs rename to compiler/rustc_middle/src/ich/hcx.rs diff --git a/src/librustc_middle/ich/impls_hir.rs b/compiler/rustc_middle/src/ich/impls_hir.rs similarity index 100% rename from src/librustc_middle/ich/impls_hir.rs rename to compiler/rustc_middle/src/ich/impls_hir.rs diff --git a/src/librustc_middle/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs similarity index 100% rename from src/librustc_middle/ich/impls_syntax.rs rename to compiler/rustc_middle/src/ich/impls_syntax.rs diff --git a/src/librustc_middle/ich/impls_ty.rs b/compiler/rustc_middle/src/ich/impls_ty.rs similarity index 100% rename from src/librustc_middle/ich/impls_ty.rs rename to compiler/rustc_middle/src/ich/impls_ty.rs diff --git a/src/librustc_middle/ich/mod.rs b/compiler/rustc_middle/src/ich/mod.rs similarity index 100% rename from src/librustc_middle/ich/mod.rs rename to compiler/rustc_middle/src/ich/mod.rs diff --git a/src/librustc_middle/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs similarity index 100% rename from src/librustc_middle/infer/canonical.rs rename to compiler/rustc_middle/src/infer/canonical.rs diff --git a/src/librustc_middle/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs similarity index 100% rename from src/librustc_middle/infer/mod.rs rename to compiler/rustc_middle/src/infer/mod.rs diff --git a/src/librustc_middle/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs similarity index 94% rename from src/librustc_middle/infer/unify_key.rs rename to compiler/rustc_middle/src/infer/unify_key.rs index 2580ac6beb..4d884dde39 100644 --- a/src/librustc_middle/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -4,8 +4,9 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify::{ self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue, }; +use rustc_span::def_id::DefId; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::cmp; use std::marker::PhantomData; @@ -124,7 +125,7 @@ pub struct ConstVariableOrigin { pub enum ConstVariableOriginKind { MiscVariable, ConstInference, - ConstParameterDefinition(Symbol), + ConstParameterDefinition(Symbol, DefId), SubstitutionPlaceholder, } @@ -175,17 +176,17 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>); fn unify_values(value1: &Self, value2: &Self) -> Result { - let val = match (value1.val, value2.val) { + let (val, span) = match (value1.val, value2.val) { (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => { bug!("equating two const variables, both of which have known values") } // If one side is known, prefer that one. (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => { - Ok(value1.val) + (value1.val, value1.origin.span) } (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => { - Ok(value2.val) + (value2.val, value2.origin.span) } // If both sides are *unknown*, it hardly matters, does it? @@ -199,14 +200,14 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { // universe is the minimum of the two universes, because that is // the one which contains the fewest names in scope. let universe = cmp::min(universe1, universe2); - Ok(ConstVariableValue::Unknown { universe }) + (ConstVariableValue::Unknown { universe }, value1.origin.span) } - }?; + }; Ok(ConstVarValue { origin: ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, - span: DUMMY_SP, + span: span, }, val, }) diff --git a/src/librustc_middle/lib.rs b/compiler/rustc_middle/src/lib.rs similarity index 91% rename from src/librustc_middle/lib.rs rename to compiler/rustc_middle/src/lib.rs index 1b2dea8a37..fa885ce2e7 100644 --- a/src/librustc_middle/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -22,7 +22,8 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(array_windows)] #![feature(backtrace)] #![feature(bool_to_option)] #![feature(box_patterns)] @@ -30,25 +31,21 @@ #![feature(cmp_min_max_by)] #![feature(const_fn)] #![feature(const_panic)] -#![feature(const_fn_transmute)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] -#![feature(drain_filter)] #![feature(never_type)] -#![feature(exhaustive_patterns)] #![feature(extern_types)] #![feature(nll)] +#![feature(once_cell)] #![feature(option_expect_none)] #![feature(or_patterns)] #![feature(min_specialization)] #![feature(trusted_len)] -#![feature(stmt_expr_attributes)] #![feature(test)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] -#![feature(hash_raw_entry)] #![feature(int_error_matching)] #![recursion_limit = "512"] diff --git a/src/librustc_middle/lint.rs b/compiler/rustc_middle/src/lint.rs similarity index 100% rename from src/librustc_middle/lint.rs rename to compiler/rustc_middle/src/lint.rs diff --git a/src/librustc_middle/macros.rs b/compiler/rustc_middle/src/macros.rs similarity index 100% rename from src/librustc_middle/macros.rs rename to compiler/rustc_middle/src/macros.rs diff --git a/src/librustc_middle/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs similarity index 96% rename from src/librustc_middle/middle/codegen_fn_attrs.rs rename to compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 62a6198b9b..d71cdc4e67 100644 --- a/src/librustc_middle/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -79,6 +79,9 @@ bitflags! { /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. const FFI_CONST = 1 << 13; + /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a + /// function as an entry function from Non-Secure code. + const CMSE_NONSECURE_ENTRY = 1 << 14; } } diff --git a/src/librustc_middle/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs similarity index 99% rename from src/librustc_middle/middle/cstore.rs rename to compiler/rustc_middle/src/middle/cstore.rs index 1af1d58181..f3d7c8506a 100644 --- a/src/librustc_middle/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -69,7 +69,7 @@ pub enum LibSource { impl LibSource { pub fn is_some(&self) -> bool { - if let LibSource::Some(_) = *self { true } else { false } + matches!(self, LibSource::Some(_)) } pub fn option(&self) -> Option { diff --git a/src/librustc_middle/middle/dependency_format.rs b/compiler/rustc_middle/src/middle/dependency_format.rs similarity index 100% rename from src/librustc_middle/middle/dependency_format.rs rename to compiler/rustc_middle/src/middle/dependency_format.rs diff --git a/src/librustc_middle/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs similarity index 100% rename from src/librustc_middle/middle/exported_symbols.rs rename to compiler/rustc_middle/src/middle/exported_symbols.rs diff --git a/src/librustc_middle/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs similarity index 83% rename from src/librustc_middle/middle/lang_items.rs rename to compiler/rustc_middle/src/middle/lang_items.rs index 3e1caa3b54..cc9706f2d8 100644 --- a/src/librustc_middle/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -17,7 +17,7 @@ use rustc_target::spec::PanicStrategy; 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 { + pub fn require_lang_item(self, lang_item: LangItem, span: Option) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { if let Some(span) = span { self.sess.span_fatal(span, &msg) @@ -27,7 +27,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn fn_trait_kind_from_lang_item(&self, id: DefId) -> Option { + pub fn fn_trait_kind_from_lang_item(self, id: DefId) -> Option { let items = self.lang_items(); match Some(id) { x if x == items.fn_trait() => Some(ty::ClosureKind::Fn), @@ -37,7 +37,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { + pub fn is_weak_lang_item(self, item_def_id: DefId) -> bool { self.lang_items().is_weak_lang_item(item_def_id) } } @@ -53,7 +53,9 @@ pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool { // symbols. Other panic runtimes ensure that the relevant symbols are // available to link things together, but they're never exercised. match tcx.sess.panic_strategy() { - PanicStrategy::Abort => lang_item != LangItem::EhPersonality, + PanicStrategy::Abort => { + lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo + } PanicStrategy::Unwind => true, } } diff --git a/src/librustc_middle/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs similarity index 100% rename from src/librustc_middle/middle/limits.rs rename to compiler/rustc_middle/src/middle/limits.rs diff --git a/src/librustc_middle/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs similarity index 100% rename from src/librustc_middle/middle/mod.rs rename to compiler/rustc_middle/src/middle/mod.rs diff --git a/src/librustc_middle/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs similarity index 100% rename from src/librustc_middle/middle/privacy.rs rename to compiler/rustc_middle/src/middle/privacy.rs diff --git a/src/librustc_middle/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs similarity index 100% rename from src/librustc_middle/middle/region.rs rename to compiler/rustc_middle/src/middle/region.rs diff --git a/src/librustc_middle/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs similarity index 100% rename from src/librustc_middle/middle/resolve_lifetime.rs rename to compiler/rustc_middle/src/middle/resolve_lifetime.rs diff --git a/src/librustc_middle/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs similarity index 92% rename from src/librustc_middle/middle/stability.rs rename to compiler/rustc_middle/src/middle/stability.rs index b32eebbb11..7e2415fd54 100644 --- a/src/librustc_middle/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -13,6 +13,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; use rustc_hir::{self, HirId}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; use rustc_session::lint::{BuiltinLintDiagnostics, Lint, LintBuffer}; use rustc_session::parse::feature_err_issue; @@ -308,7 +309,7 @@ impl<'tcx> TyCtxt<'tcx> { // #[rustc_deprecated] however wants to emit down the whole // hierarchy. if !skip || depr_entry.attr.is_since_rustc_version { - let path = &self.def_path_str(def_id); + let path = &with_no_trimmed_paths(|| self.def_path_str(def_id)); let kind = self.def_kind(def_id).descr(def_id); let (message, lint) = deprecation_message(&depr_entry.attr, kind, path); late_report_deprecation( @@ -391,9 +392,27 @@ impl<'tcx> TyCtxt<'tcx> { /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not /// exist, emits an error. /// - /// Additionally, this function will also check if the item is deprecated. If so, and `id` is - /// not `None`, a deprecated lint attached to `id` will be emitted. + /// This function will also check if the item is deprecated. + /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. pub fn check_stability(self, def_id: DefId, id: Option, span: Span) { + self.check_optional_stability(def_id, id, span, |span, def_id| { + // The API could be uncallable for other reasons, for example when a private module + // was referenced. + self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); + }) + } + + /// Like `check_stability`, except that we permit items to have custom behaviour for + /// missing stability attributes (not necessarily just emit a `bug!`). This is necessary + /// for default generic parameters, which only have stability attributes if they were + /// added after the type on which they're defined. + pub fn check_optional_stability( + self, + def_id: DefId, + id: Option, + span: Span, + unmarked: impl FnOnce(Span, DefId) -> (), + ) { let soft_handler = |lint, span, msg: &_| { self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { lint.build(msg).emit() @@ -404,11 +423,7 @@ impl<'tcx> TyCtxt<'tcx> { EvalResult::Deny { feature, reason, issue, is_soft } => { report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler) } - EvalResult::Unmarked => { - // The API could be uncallable for other reasons, for example when a private module - // was referenced. - self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); - } + EvalResult::Unmarked => unmarked(span, def_id), } } diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs new file mode 100644 index 0000000000..b85f1e6e5d --- /dev/null +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -0,0 +1,20 @@ +//! A subset of a mir body used for const evaluatability checking. +use crate::mir; +use crate::ty; + +rustc_index::newtype_index! { + /// An index into an `AbstractConst`. + pub struct NodeId { + derive [HashStable] + DEBUG_FORMAT = "n{}", + } +} + +/// A node of an `AbstractConst`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum Node<'tcx> { + Leaf(&'tcx ty::Const<'tcx>), + Binop(mir::BinOp, NodeId, NodeId), + UnaryOp(mir::UnOp, NodeId), + FunctionCall(NodeId, &'tcx [NodeId]), +} diff --git a/src/librustc_middle/mir/coverage/mod.rs b/compiler/rustc_middle/src/mir/coverage/mod.rs similarity index 100% rename from src/librustc_middle/mir/coverage/mod.rs rename to compiler/rustc_middle/src/mir/coverage/mod.rs diff --git a/src/librustc_middle/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs similarity index 98% rename from src/librustc_middle/mir/interpret/allocation.rs rename to compiler/rustc_middle/src/mir/interpret/allocation.rs index 505939d56e..ee1ea816e0 100644 --- a/src/librustc_middle/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -345,10 +345,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { /// Reads a *non-ZST* scalar. /// - /// ZSTs can't be read for two reasons: - /// * byte-order cannot work with zero-element buffers; - /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer - /// pointers being valid for ZSTs. + /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check + /// for ZSTness anyway due to integer pointers being valid for ZSTs. /// /// It is the caller's responsibility to check bounds and alignment beforehand. /// Most likely, you want to call `InterpCx::read_scalar` instead of this method. @@ -397,10 +395,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { /// Writes a *non-ZST* scalar. /// - /// ZSTs can't be read for two reasons: - /// * byte-order cannot work with zero-element buffers; - /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer - /// pointers being valid for ZSTs. + /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check + /// for ZSTness anyway due to integer pointers being valid for ZSTs. /// /// It is the caller's responsibility to check bounds and alignment beforehand. /// Most likely, you want to call `InterpCx::write_scalar` instead of this method. diff --git a/src/librustc_middle/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs similarity index 98% rename from src/librustc_middle/mir/interpret/error.rs rename to compiler/rustc_middle/src/mir/interpret/error.rs index 059925088c..d41e568060 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,4 +1,4 @@ -use super::{AllocId, Pointer, RawConst, Scalar}; +use super::{AllocId, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty}; @@ -23,12 +23,18 @@ pub enum ErrorHandled { TooGeneric, } +impl From for ErrorHandled { + fn from(err: ErrorReported) -> ErrorHandled { + ErrorHandled::Reported(err) + } +} + CloneTypeFoldableAndLiftImpls! { ErrorHandled, } -pub type ConstEvalRawResult<'tcx> = Result, ErrorHandled>; -pub type ConstEvalResult<'tcx> = Result, ErrorHandled>; +pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; +pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> { struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) diff --git a/src/librustc_middle/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs similarity index 90% rename from src/librustc_middle/mir/interpret/mod.rs rename to compiler/rustc_middle/src/mir/interpret/mod.rs index 0dc3d6e344..20363625e4 100644 --- a/src/librustc_middle/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -98,16 +98,17 @@ mod value; use std::convert::TryFrom; use std::fmt; use std::io; +use std::io::{Read, Write}; use std::num::NonZeroU32; use std::sync::atomic::{AtomicU32, Ordering}; -use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{HashMapExt, Lock}; use rustc_data_structures::tiny_list::TinyList; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; use rustc_target::abi::{Endian, Size}; @@ -117,12 +118,12 @@ use crate::ty::subst::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - struct_error, CheckInAllocMsg, ConstEvalRawResult, ConstEvalResult, ErrorHandled, InterpError, - InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, ResourceExhaustionInfo, - UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, + struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, + InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, + ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, }; -pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit}; +pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; pub use self::allocation::{Allocation, AllocationExtra, InitMask, Relocations}; @@ -145,7 +146,7 @@ pub struct GlobalId<'tcx> { impl GlobalId<'tcx> { pub fn display(self, tcx: TyCtxt<'tcx>) -> String { - let instance_name = tcx.def_path_str(self.instance.def.def_id()); + let instance_name = with_no_trimmed_paths(|| tcx.def_path_str(self.instance.def.def_id())); if let Some(promoted) = self.promoted { format!("{}::{:?}", instance_name, promoted) } else { @@ -446,14 +447,14 @@ impl<'tcx> TyCtxt<'tcx> { /// /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such /// an `AllocId` from a query. - pub fn reserve_alloc_id(&self) -> AllocId { + pub fn reserve_alloc_id(self) -> AllocId { self.alloc_map.lock().reserve() } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. /// Should only be used for function pointers and statics, we don't want /// to dedup IDs for "real" memory! - fn reserve_and_set_dedup(&self, alloc: GlobalAlloc<'tcx>) -> AllocId { + fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {} @@ -471,13 +472,13 @@ impl<'tcx> TyCtxt<'tcx> { /// Generates an `AllocId` for a static or return a cached one in case this function has been /// called on the same static before. - pub fn create_static_alloc(&self, static_id: DefId) -> AllocId { + pub fn create_static_alloc(self, static_id: DefId) -> AllocId { self.reserve_and_set_dedup(GlobalAlloc::Static(static_id)) } /// Generates an `AllocId` for a function. Depending on the function type, /// this might get deduplicated or assigned a new ID each time. - pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> AllocId { + pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId { // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be // duplicated across crates. @@ -506,7 +507,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Statics with identical content will still point to the same `Allocation`, i.e., /// their data will be deduplicated through `Allocation` interning -- but they /// are different places in memory and as such need different IDs. - pub fn create_memory_alloc(&self, mem: &'tcx Allocation) -> AllocId { + pub fn create_memory_alloc(self, mem: &'tcx Allocation) -> AllocId { let id = self.reserve_alloc_id(); self.set_alloc_id_memory(id, mem); id @@ -518,7 +519,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This function exists to allow const eval to detect the difference between evaluation- /// local dangling pointers and allocations in constants/statics. #[inline] - pub fn get_global_alloc(&self, id: AllocId) -> Option> { + pub fn get_global_alloc(self, id: AllocId) -> Option> { self.alloc_map.lock().alloc_map.get(&id).cloned() } @@ -528,7 +529,7 @@ impl<'tcx> TyCtxt<'tcx> { /// constants (as all constants must pass interning and validation that check for dangling /// ids), this function is frequently used throughout rustc, but should not be used within /// the miri engine. - pub fn global_alloc(&self, id: AllocId) -> GlobalAlloc<'tcx> { + pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { match self.get_global_alloc(id) { Some(alloc) => alloc, None => bug!("could not find allocation for {}", id), @@ -537,7 +538,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to /// call this function twice, even with the same `Allocation` will ICE the compiler. - pub fn set_alloc_id_memory(&self, id: AllocId, mem: &'tcx Allocation) { + pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) { if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) { bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old); } @@ -545,7 +546,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called /// twice for the same `(AllocId, Allocation)` pair. - fn set_alloc_id_same_memory(&self, id: AllocId, mem: &'tcx Allocation) { + fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) { self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem)); } } @@ -560,19 +561,33 @@ pub fn write_target_uint( mut target: &mut [u8], data: u128, ) -> Result<(), io::Error> { - let len = target.len(); + // This u128 holds an "any-size uint" (since smaller uints can fits in it) + // So we do not write all bytes of the u128, just the "payload". match endianness { - Endian::Little => target.write_uint128::(data, len), - Endian::Big => target.write_uint128::(data, len), - } + Endian::Little => target.write(&data.to_le_bytes())?, + Endian::Big => target.write(&data.to_be_bytes()[16 - target.len()..])?, + }; + debug_assert!(target.len() == 0); // We should have filled the target buffer. + Ok(()) } #[inline] pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result { - match endianness { - Endian::Little => source.read_uint128::(source.len()), - Endian::Big => source.read_uint128::(source.len()), - } + // This u128 holds an "any-size uint" (since smaller uints can fits in it) + let mut buf = [0u8; std::mem::size_of::()]; + // So we do not read exactly 16 bytes into the u128, just the "payload". + let uint = match endianness { + Endian::Little => { + source.read(&mut buf)?; + Ok(u128::from_le_bytes(buf)) + } + Endian::Big => { + source.read(&mut buf[16 - source.len()..])?; + Ok(u128::from_be_bytes(buf)) + } + }; + debug_assert!(source.len() == 0); // We should have consumed the source buffer. + uint } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_middle/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs similarity index 100% rename from src/librustc_middle/mir/interpret/pointer.rs rename to compiler/rustc_middle/src/mir/interpret/pointer.rs diff --git a/src/librustc_middle/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs similarity index 90% rename from src/librustc_middle/mir/interpret/queries.rs rename to compiler/rustc_middle/src/mir/interpret/queries.rs index dcc1f8b1a4..f366681bc7 100644 --- a/src/librustc_middle/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,4 +1,4 @@ -use super::{ConstEvalResult, ErrorHandled, GlobalId}; +use super::{ErrorHandled, EvalToConstValueResult, GlobalId}; use crate::mir; use crate::ty::subst::{InternalSubsts, SubstsRef}; @@ -10,7 +10,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts /// that can't take any generic arguments like statics, const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. - pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> { + pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { // In some situations def_id will have substitutions within scope, but they aren't allowed // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are @@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> { substs: SubstsRef<'tcx>, promoted: Option, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { match ty::Instance::resolve_opt_const_arg(self, param_env, def, substs) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted }; @@ -54,7 +54,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span) } @@ -64,14 +64,14 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, cid: GlobalId<'tcx>, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. let inputs = self.erase_regions(¶m_env.and(cid)); if let Some(span) = span { - self.at(span).const_eval_validated(inputs) + self.at(span).eval_to_const_value_raw(inputs) } else { - self.const_eval_validated(inputs) + self.eval_to_const_value_raw(inputs) } } @@ -94,7 +94,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> Result<&'tcx mir::Allocation, ErrorHandled> { trace!("eval_to_allocation: Need to compute {:?}", gid); - let raw_const = self.const_eval_raw(param_env.and(gid))?; + let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) } } diff --git a/src/librustc_middle/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs similarity index 97% rename from src/librustc_middle/mir/interpret/value.rs rename to compiler/rustc_middle/src/mir/interpret/value.rs index 4c47f25105..206f01c249 100644 --- a/src/librustc_middle/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -12,9 +12,9 @@ use crate::ty::{ParamEnv, Ty, TyCtxt}; use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; -/// Represents the result of a raw const operation, pre-validation. -#[derive(Clone, HashStable)] -pub struct RawConst<'tcx> { +/// Represents the result of const evaluation via the `eval_to_allocation` query. +#[derive(Clone, HashStable, TyEncodable, TyDecodable)] +pub struct ConstAlloc<'tcx> { // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` // (so you can use `AllocMap::unwrap_memory`). pub alloc_id: AllocId, @@ -503,6 +503,11 @@ impl<'tcx, Tag> Scalar { self.to_unsigned_with_bit_width(64).map(|v| u64::try_from(v).unwrap()) } + /// Converts the scalar to produce an `u128`. Fails if the scalar is a pointer. + pub fn to_u128(self) -> InterpResult<'static, u128> { + self.to_unsigned_with_bit_width(128) + } + pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'static, u64> { let b = self.to_bits(cx.data_layout().pointer_size)?; Ok(u64::try_from(b).unwrap()) @@ -535,6 +540,11 @@ impl<'tcx, Tag> Scalar { self.to_signed_with_bit_width(64).map(|v| i64::try_from(v).unwrap()) } + /// Converts the scalar to produce an `i128`. Fails if the scalar is a pointer. + pub fn to_i128(self) -> InterpResult<'static, i128> { + self.to_signed_with_bit_width(128) + } + pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> { let sz = cx.data_layout().pointer_size; let b = self.to_bits(sz)?; @@ -568,6 +578,9 @@ pub enum ScalarMaybeUninit { Uninit, } +#[cfg(target_arch = "x86_64")] +static_assert_size!(ScalarMaybeUninit, 24); + impl From> for ScalarMaybeUninit { #[inline(always)] fn from(s: Scalar) -> Self { diff --git a/src/librustc_middle/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs similarity index 93% rename from src/librustc_middle/mir/mod.rs rename to compiler/rustc_middle/src/mir/mod.rs index ad40cf221b..fee24f0bae 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -40,6 +40,7 @@ use std::{iter, mem, option}; use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; +pub mod abstract_const; pub mod coverage; pub mod interpret; pub mod mono; @@ -186,6 +187,23 @@ pub struct Body<'tcx> { /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components. pub ignore_interior_mut_in_const_validation: bool, + /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check. + /// + /// Note that this does not actually mean that this body is not computable right now. + /// The repeat count in the following example is polymorphic, but can still be evaluated + /// without knowing anything about the type parameter `T`. + /// + /// ```rust + /// fn test() { + /// let _ = [0; std::mem::size_of::<*mut T>()]; + /// } + /// ``` + /// + /// **WARNING**: Do not change this flags after the MIR was originally created, even if an optimization + /// removed the last mention of all generic params. We do not want to rely on optimizations and + /// potentially allow things like `[u8; std::mem::size_of::() * 0]` due to this. + pub is_polymorphic: bool, + predecessor_cache: PredecessorCache, } @@ -208,7 +226,7 @@ impl<'tcx> Body<'tcx> { local_decls.len() ); - Body { + let mut body = Body { phase: MirPhase::Build, basic_blocks, source_scopes, @@ -224,8 +242,11 @@ impl<'tcx> Body<'tcx> { span, required_consts: Vec::new(), ignore_interior_mut_in_const_validation: false, + is_polymorphic: false, predecessor_cache: PredecessorCache::new(), - } + }; + body.is_polymorphic = body.has_param_types_or_consts(); + body } /// Returns a partially initialized MIR body containing only a list of basic blocks. @@ -234,7 +255,7 @@ impl<'tcx> Body<'tcx> { /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different /// crate. pub fn new_cfg_only(basic_blocks: IndexVec>) -> Self { - Body { + let mut body = Body { phase: MirPhase::Build, basic_blocks, source_scopes: IndexVec::new(), @@ -250,8 +271,11 @@ impl<'tcx> Body<'tcx> { generator_kind: None, var_debug_info: Vec::new(), ignore_interior_mut_in_const_validation: false, + is_polymorphic: false, predecessor_cache: PredecessorCache::new(), - } + }; + body.is_polymorphic = body.has_param_types_or_consts(); + body } #[inline] @@ -646,7 +670,7 @@ impl Atom for Local { } /// Classifies locals into categories. See `Body::local_kind`. -#[derive(PartialEq, Eq, Debug, HashStable)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] pub enum LocalKind { /// User-declared variable binding. Var, @@ -899,6 +923,8 @@ pub enum LocalInfo<'tcx> { User(ClearCrossCrate>), /// A temporary created that references the static with the given `DefId`. StaticRef { def_id: DefId, is_thread_local: bool }, + /// A temporary created that references the const with the given `DefId` + ConstRef { def_id: DefId }, } impl<'tcx> LocalDecl<'tcx> { @@ -1051,6 +1077,25 @@ pub struct VarDebugInfo<'tcx> { // BasicBlock rustc_index::newtype_index! { + /// A node in the MIR [control-flow graph][CFG]. + /// + /// There are no branches (e.g., `if`s, function calls, etc.) within a basic block, which makes + /// it easier to do [data-flow analyses] and optimizations. Instead, branches are represented + /// as an edge in a graph between basic blocks. + /// + /// Basic blocks consist of a series of [statements][Statement], ending with a + /// [terminator][Terminator]. Basic blocks can have multiple predecessors and successors, + /// however there is a MIR pass ([`CriticalCallEdges`]) that removes *critical edges*, which + /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is + /// needed because some analyses require that there are no critical edges in the CFG. + /// + /// Read more about basic blocks in the [rustc-dev-guide][guide-mir]. + /// + /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg + /// [data-flow analyses]: + /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis + /// [`CriticalCallEdges`]: ../../rustc_mir/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges + /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/ pub struct BasicBlock { derive [HashStable] DEBUG_FORMAT = "bb{}", @@ -1067,6 +1112,7 @@ impl BasicBlock { /////////////////////////////////////////////////////////////////////////// // BasicBlockData and Terminator +/// See [`BasicBlock`] for documentation on what basic blocks are at a high level. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] pub struct BasicBlockData<'tcx> { /// List of statements in this block. @@ -1254,49 +1300,49 @@ impl AssertKind { match self { BoundsCheck { ref len, ref index } => write!( f, - "\"index out of bounds: the len is {{}} but the index is {{}}\", {:?}, {:?}", + "\"index out of bounds: the length is {{}} but the index is {{}}\", {:?}, {:?}", len, index ), OverflowNeg(op) => { - write!(f, "\"attempt to negate {{}} which would overflow\", {:?}", op) + write!(f, "\"attempt to negate `{{}}`, which would overflow\", {:?}", op) } - DivisionByZero(op) => write!(f, "\"attempt to divide {{}} by zero\", {:?}", op), + DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {:?}", op), RemainderByZero(op) => write!( f, - "\"attempt to calculate the remainder of {{}} with a divisor of zero\", {:?}", + "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {:?}", op ), Overflow(BinOp::Add, l, r) => write!( f, - "\"attempt to compute `{{}} + {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute `{{}} + {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Sub, l, r) => write!( f, - "\"attempt to compute `{{}} - {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute `{{}} - {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Mul, l, r) => write!( f, - "\"attempt to compute `{{}} * {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute `{{}} * {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Div, l, r) => write!( f, - "\"attempt to compute `{{}} / {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute `{{}} / {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Rem, l, r) => write!( f, - "\"attempt to compute the remainder of `{{}} % {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Shr, _, r) => { - write!(f, "\"attempt to shift right by {{}} which would overflow\", {:?}", r) + write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {:?}", r) } Overflow(BinOp::Shl, _, r) => { - write!(f, "\"attempt to shift left by {{}} which would overflow\", {:?}", r) + write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {:?}", r) } _ => write!(f, "\"{}\"", self.description()), } @@ -1307,36 +1353,40 @@ impl fmt::Debug for AssertKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use AssertKind::*; match self { - BoundsCheck { ref len, ref index } => { - write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index) - } - OverflowNeg(op) => write!(f, "attempt to negate {:#?} which would overflow", op), - DivisionByZero(op) => write!(f, "attempt to divide {:#?} by zero", op), - RemainderByZero(op) => { - write!(f, "attempt to calculate the remainder of {:#?} with a divisor of zero", op) - } + BoundsCheck { ref len, ref index } => write!( + f, + "index out of bounds: the length is {:?} but the index is {:?}", + len, index + ), + OverflowNeg(op) => write!(f, "attempt to negate `{:#?}`, which would overflow", op), + DivisionByZero(op) => write!(f, "attempt to divide `{:#?}` by zero", op), + RemainderByZero(op) => write!( + f, + "attempt to calculate the remainder of `{:#?}` with a divisor of zero", + op + ), Overflow(BinOp::Add, l, r) => { - write!(f, "attempt to compute `{:#?} + {:#?}` which would overflow", l, r) + write!(f, "attempt to compute `{:#?} + {:#?}`, which would overflow", l, r) } Overflow(BinOp::Sub, l, r) => { - write!(f, "attempt to compute `{:#?} - {:#?}` which would overflow", l, r) + write!(f, "attempt to compute `{:#?} - {:#?}`, which would overflow", l, r) } Overflow(BinOp::Mul, l, r) => { - write!(f, "attempt to compute `{:#?} * {:#?}` which would overflow", l, r) + write!(f, "attempt to compute `{:#?} * {:#?}`, which would overflow", l, r) } Overflow(BinOp::Div, l, r) => { - write!(f, "attempt to compute `{:#?} / {:#?}` which would overflow", l, r) + write!(f, "attempt to compute `{:#?} / {:#?}`, which would overflow", l, r) } Overflow(BinOp::Rem, l, r) => write!( f, - "attempt to compute the remainder of `{:#?} % {:#?}` which would overflow", + "attempt to compute the remainder of `{:#?} % {:#?}`, which would overflow", l, r ), Overflow(BinOp::Shr, _, r) => { - write!(f, "attempt to shift right by {:#?} which would overflow", r) + write!(f, "attempt to shift right by `{:#?}`, which would overflow", r) } Overflow(BinOp::Shl, _, r) => { - write!(f, "attempt to shift left by {:#?} which would overflow", r) + write!(f, "attempt to shift left by `{:#?}`, which would overflow", r) } _ => write!(f, "{}", self.description()), } @@ -1430,6 +1480,15 @@ pub enum StatementKind<'tcx> { Nop, } +impl<'tcx> StatementKind<'tcx> { + pub fn as_assign_mut(&mut self) -> Option<&mut Box<(Place<'tcx>, Rvalue<'tcx>)>> { + match self { + StatementKind::Assign(x) => Some(x), + _ => None, + } + } +} + /// Describes what kind of retag is to be performed. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, HashStable)] pub enum RetagKind { @@ -1521,7 +1580,24 @@ impl Debug for Statement<'_> { AscribeUserType(box (ref place, ref c_ty), ref variance) => { write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) } - Coverage(box ref coverage) => write!(fmt, "{:?}", coverage), + Coverage(box ref coverage) => { + let rgn = &coverage.code_region; + match coverage.kind { + CoverageKind::Counter { id, .. } => { + write!(fmt, "Coverage::Counter({:?}) for {:?}", id.index(), rgn) + } + CoverageKind::Expression { id, lhs, op, rhs } => write!( + fmt, + "Coverage::Expression({:?}) = {} {} {} for {:?}", + id.index(), + lhs.index(), + if op == coverage::Op::Add { "+" } else { "-" }, + rhs.index(), + rgn + ), + CoverageKind::Unreachable => write!(fmt, "Coverage::Unreachable for {:?}", rgn), + } + } Nop => write!(fmt, "nop"), } } @@ -1564,10 +1640,10 @@ pub enum ProjectionElem { /// ``` ConstantIndex { /// index or -index (in Python terms), depending on from_end - offset: u32, + offset: u64, /// The thing being indexed must be at least this long. For arrays this /// is always the exact length. - min_length: u32, + min_length: u64, /// Counting backwards from end? This is always false when indexing an /// array. from_end: bool, @@ -1578,8 +1654,8 @@ pub enum ProjectionElem { /// If `from_end` is true `slice[from..slice.len() - to]`. /// Otherwise `array[from..to]`. Subslice { - from: u32, - to: u32, + from: u64, + to: u64, /// Whether `to` counts from the start or end of the array/slice. /// For `PlaceElem`s this is `true` if and only if the base is a slice. /// For `ProjectionKind`, this can also be `true` for arrays. @@ -1616,7 +1692,7 @@ pub type PlaceElem<'tcx> = ProjectionElem>; // At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. #[cfg(target_arch = "x86_64")] -static_assert_size!(PlaceElem<'_>, 16); +static_assert_size!(PlaceElem<'_>, 24); /// Alias for projections as they appear in `UserTypeProjection`, where we /// need neither the `V` parameter for `Index` nor the `T` for `Field`. @@ -1843,6 +1919,10 @@ impl<'tcx> Operand<'tcx> { }) } + pub fn is_move(&self) -> bool { + matches!(self, Operand::Move(..)) + } + /// Convenience helper to make a literal-like constant from a given scalar value. /// Since this is used to synthesize MIR, assumes `user_ty` is None. pub fn const_from_scalar( @@ -1924,6 +2004,15 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(_) => None, } } + + /// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a + /// place. + pub fn constant(&self) -> Option<&Constant<'tcx>> { + match self { + Operand::Constant(x) => Some(&**x), + Operand::Copy(_) | Operand::Move(_) => None, + } + } } /////////////////////////////////////////////////////////////////////////// @@ -2221,8 +2310,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// Constants /// /// Two constants are equal if they are the same constant. Note that -/// this does not necessarily mean that they are "==" in Rust -- in -/// particular one must be wary of `NaN`! +/// this does not necessarily mean that they are `==` in Rust. In +/// particular, one must be wary of `NaN`! #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)] pub struct Constant<'tcx> { @@ -2330,7 +2419,7 @@ impl<'tcx> UserTypeProjections { self.map_projections(|pat_ty_proj| pat_ty_proj.index()) } - pub fn subslice(self, from: u32, to: u32) -> Self { + pub fn subslice(self, from: u64, to: u64) -> Self { self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) } @@ -2376,7 +2465,7 @@ impl UserTypeProjection { self } - pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self { + pub(crate) fn subslice(mut self, from: u64, to: u64) -> Self { self.projs.push(ProjectionElem::Subslice { from, to, from_end: true }); self } @@ -2452,7 +2541,7 @@ impl<'tcx> Debug for Constant<'tcx> { impl<'tcx> Display for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - match self.literal.ty.kind { + match self.literal.ty.kind() { ty::FnDef(..) => {} _ => write!(fmt, "const ")?, } diff --git a/src/librustc_middle/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs similarity index 95% rename from src/librustc_middle/mir/mono.rs rename to compiler/rustc_middle/src/mir/mono.rs index 0d5f6619df..79e2c5aac2 100644 --- a/src/librustc_middle/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,6 +1,5 @@ use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId}; use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use crate::ty::print::obsolete::DefPathBasedNames; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; use rustc_attr::InlineAttr; use rustc_data_structures::base_n; @@ -86,7 +85,7 @@ impl<'tcx> MonoItem<'tcx> { .debugging_opts .inline_in_all_cgus .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) - && tcx.sess.opts.cg.link_dead_code != Some(true); + && !tcx.sess.link_dead_code(); match *self { MonoItem::Fn(ref instance) => { @@ -171,30 +170,6 @@ impl<'tcx> MonoItem<'tcx> { !tcx.subst_and_check_impossible_predicates((def_id, &substs)) } - pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String { - return match *self { - MonoItem::Fn(instance) => to_string_internal(tcx, "fn ", instance, debug), - MonoItem::Static(def_id) => { - let instance = Instance::new(def_id, tcx.intern_substs(&[])); - to_string_internal(tcx, "static ", instance, debug) - } - MonoItem::GlobalAsm(..) => "global_asm".to_string(), - }; - - fn to_string_internal<'tcx>( - tcx: TyCtxt<'tcx>, - prefix: &str, - instance: Instance<'tcx>, - debug: bool, - ) -> String { - let mut result = String::with_capacity(32); - result.push_str(prefix); - let printer = DefPathBasedNames::new(tcx, false, false); - printer.push_instance_as_string(instance, &mut result, debug); - result - } - } - pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option { match *self { MonoItem::Fn(Instance { def, .. }) => { @@ -229,6 +204,18 @@ impl<'a, 'tcx> HashStable> for MonoItem<'tcx> { } } +impl<'tcx> fmt::Display for MonoItem<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + MonoItem::Fn(instance) => write!(f, "fn {}", instance), + MonoItem::Static(def_id) => { + write!(f, "static {}", Instance::new(def_id, InternalSubsts::empty())) + } + MonoItem::GlobalAsm(..) => write!(f, "global_asm"), + } + } +} + pub struct CodegenUnit<'tcx> { /// A name for this CGU. Incremental compilation requires that /// name be unique amongst **all** crates. Therefore, it should diff --git a/src/librustc_middle/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs similarity index 97% rename from src/librustc_middle/mir/predecessors.rs rename to compiler/rustc_middle/src/mir/predecessors.rs index b16a1d53ff..a8b7488335 100644 --- a/src/librustc_middle/mir/predecessors.rs +++ b/compiler/rustc_middle/src/mir/predecessors.rs @@ -33,7 +33,7 @@ impl PredecessorCache { self.cache = OnceCell::new(); } - /// Returns the the predecessor graph for this MIR. + /// Returns the predecessor graph for this MIR. #[inline] pub(super) fn compute( &self, diff --git a/src/librustc_middle/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs similarity index 100% rename from src/librustc_middle/mir/query.rs rename to compiler/rustc_middle/src/mir/query.rs diff --git a/src/librustc_middle/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs similarity index 99% rename from src/librustc_middle/mir/tcx.rs rename to compiler/rustc_middle/src/mir/tcx.rs index efcd41e5c1..b9e4f6fb12 100644 --- a/src/librustc_middle/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -33,7 +33,7 @@ impl<'tcx> PlaceTy<'tcx> { /// /// Note that the resulting type has not been normalized. pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> { - let answer = match self.ty.kind { + let answer = match self.ty.kind() { ty::Adt(adt_def, substs) => { let variant_def = match self.variant_index { None => adt_def.non_enum_variant(), @@ -90,7 +90,7 @@ impl<'tcx> PlaceTy<'tcx> { PlaceTy::from_ty(self.ty.builtin_index().unwrap()) } ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match self.ty.kind { + PlaceTy::from_ty(match self.ty.kind() { ty::Slice(..) => self.ty, ty::Array(inner, _) if !from_end => tcx.mk_array(inner, (to - from) as u64), ty::Array(inner, size) if from_end => { diff --git a/src/librustc_middle/mir/terminator/mod.rs b/compiler/rustc_middle/src/mir/terminator/mod.rs similarity index 99% rename from src/librustc_middle/mir/terminator/mod.rs rename to compiler/rustc_middle/src/mir/terminator/mod.rs index fcfd648c2b..8909f02270 100644 --- a/src/librustc_middle/mir/terminator/mod.rs +++ b/compiler/rustc_middle/src/mir/terminator/mod.rs @@ -96,6 +96,8 @@ pub enum TerminatorKind<'tcx> { /// P <- V /// } /// ``` + /// + /// Note that DropAndReplace is eliminated as part of the `ElaborateDrops` pass. DropAndReplace { place: Place<'tcx>, value: Operand<'tcx>, diff --git a/src/librustc_middle/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs similarity index 100% rename from src/librustc_middle/mir/traversal.rs rename to compiler/rustc_middle/src/mir/traversal.rs diff --git a/src/librustc_middle/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs similarity index 99% rename from src/librustc_middle/mir/type_foldable.rs rename to compiler/rustc_middle/src/mir/type_foldable.rs index 6bb6abe028..ad2eae0298 100644 --- a/src/librustc_middle/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -175,7 +175,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { use crate::mir::Rvalue::*; match *self { Use(ref op) => Use(op.fold_with(folder)), - Repeat(ref op, len) => Repeat(op.fold_with(folder), len), + Repeat(ref op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)), ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)), Ref(region, bk, ref place) => { Ref(region.fold_with(folder), bk, place.fold_with(folder)) diff --git a/src/librustc_middle/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs similarity index 99% rename from src/librustc_middle/mir/visit.rs rename to compiler/rustc_middle/src/mir/visit.rs index 6515ae31b4..a008bd5f75 100644 --- a/src/librustc_middle/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1150,8 +1150,6 @@ pub enum NonUseContext { StorageDead, /// User type annotation assertions for NLL. AscribeUserTy, - /// Coverage code region and counter metadata. - Coverage, /// The data of an user variable, for debug info. VarDebugInfo, } diff --git a/src/librustc_middle/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs similarity index 93% rename from src/librustc_middle/query/mod.rs rename to compiler/rustc_middle/src/query/mod.rs index d6836d2ee3..d5b99ea4d2 100644 --- a/src/librustc_middle/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -42,48 +42,48 @@ rustc_queries! { } Other { - // Represents crate as a whole (as distinct from the top-level crate module). - // If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), - // we will have to assume that any change means that you need to be recompiled. - // This is because the `hir_crate` query gives you access to all other items. - // To avoid this fate, do not call `tcx.hir().krate()`; instead, - // prefer wrappers like `tcx.visit_all_items_in_krate()`. + /// Represents crate as a whole (as distinct from the top-level crate module). + /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), + /// we will have to assume that any change means that you need to be recompiled. + /// This is because the `hir_crate` query gives you access to all other items. + /// To avoid this fate, do not call `tcx.hir().krate()`; instead, + /// prefer wrappers like `tcx.visit_all_items_in_krate()`. query hir_crate(key: CrateNum) -> &'tcx Crate<'tcx> { eval_always no_hash desc { "get the crate HIR" } } - // The indexed HIR. This can be conveniently accessed by `tcx.hir()`. - // Avoid calling this query directly. + /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. + /// Avoid calling this query directly. query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> { eval_always no_hash desc { "index HIR" } } - // The items in a module. - // - // This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. - // Avoid calling this query directly. + /// The items in a module. + /// + /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. + /// Avoid calling this query directly. query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems { eval_always desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) } } - // Gives access to the HIR node for the HIR owner `key`. - // - // This can be conveniently accessed by methods on `tcx.hir()`. - // Avoid calling this query directly. + /// Gives access to the HIR node for the HIR owner `key`. + /// + /// This can be conveniently accessed by methods on `tcx.hir()`. + /// Avoid calling this query directly. query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> { eval_always desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } - // Gives access to the HIR nodes and bodies inside the HIR owner `key`. - // - // This can be conveniently accessed by methods on `tcx.hir()`. - // Avoid calling this query directly. + /// Gives access to the HIR nodes and bodies inside the HIR owner `key`. + /// + /// This can be conveniently accessed by methods on `tcx.hir()`. + /// Avoid calling this query directly. query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { eval_always desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } @@ -173,6 +173,10 @@ rustc_queries! { desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) } } + query projection_ty_from_predicates(key: (DefId, DefId)) -> Option> { + desc { |tcx| "finding projection type inside predicates of `{}`", tcx.def_path_str(key.0) } + } + query native_libraries(_: CrateNum) -> Lrc> { desc { "looking up the native libraries of a linked crate" } } @@ -240,6 +244,35 @@ rustc_queries! { no_hash } + /// Try to build an abstract representation of the given constant. + query mir_abstract_const( + key: DefId + ) -> Result]>, ErrorReported> { + desc { + |tcx| "building an abstract representation for {}", tcx.def_path_str(key), + } + } + /// Try to build an abstract representation of the given constant. + query mir_abstract_const_of_const_arg( + key: (LocalDefId, DefId) + ) -> Result]>, ErrorReported> { + desc { + |tcx| + "building an abstract representation for the const argument {}", + tcx.def_path_str(key.0.to_def_id()), + } + } + + query try_unify_abstract_consts(key: ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>) + )) -> bool { + desc { + |tcx| "trying to unify the generic constants {} and {}", + tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did) + } + } + query mir_drops_elaborated_and_const_checked( key: ty::WithOptConstParam ) -> &'tcx Steal> { @@ -301,9 +334,9 @@ rustc_queries! { } TypeChecking { - // Erases regions from `ty` to yield a new type. - // Normally you would just use `tcx.erase_regions(&value)`, - // however, which uses this query as a kind of cache. + /// Erases regions from `ty` to yield a new type. + /// Normally you would just use `tcx.erase_regions(&value)`, + /// however, which uses this query as a kind of cache. query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { // This query is not expected to have input -- as a result, it // is not a good candidates for "replay" because it is essentially a @@ -424,10 +457,6 @@ rustc_queries! { desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) } } - query const_fn_is_allowed_fn_ptr(key: DefId) -> bool { - desc { |tcx| "checking if const fn allows `fn()` types: `{}`", tcx.def_path_str(key) } - } - /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). query is_foreign_item(key: DefId) -> bool { desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) } @@ -674,38 +703,31 @@ rustc_queries! { } Other { - /// Evaluates a constant without running sanity checks. + /// Evaluates a constant and returns the computed allocation. /// - /// **Do not use this** outside const eval. Const eval uses this to break query cycles - /// during validation. Please add a comment to every use site explaining why using - /// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable - /// form to be used outside of const eval. - query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalRawResult<'tcx> { + /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper. + query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> EvalToAllocationRawResult<'tcx> { desc { |tcx| - "const-evaluating `{}`", + "const-evaluating + checking `{}`", key.value.display(tcx) } + cache_on_disk_if { true } } - /// Results of evaluating const items or constants embedded in - /// other items (such as enum variant explicit discriminants). - /// - /// In contrast to `const_eval_raw` this performs some validation on the constant, and - /// returns a proper constant that is usable by the rest of the compiler. + /// Evaluates const items or anonymous constants + /// (such as enum variant explicit discriminants or array lengths) + /// into a representation suitable for the type system and const generics. /// /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. - query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalResult<'tcx> { + query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> EvalToConstValueResult<'tcx> { desc { |tcx| - "const-evaluating + checking `{}`", + "simplifying constant for the type system `{}`", key.value.display(tcx) } - cache_on_disk_if(_, opt_result) { - // Only store results without errors - opt_result.map_or(true, |r| r.is_ok()) - } + cache_on_disk_if { true } } /// Destructure a constant ADT or array into its variant index and its @@ -716,6 +738,14 @@ rustc_queries! { desc { "destructure constant" } } + /// Dereference a constant reference or raw pointer and turn the result into a constant + /// again. + query deref_const( + key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> + ) -> &'tcx ty::Const<'tcx> { + desc { "deref constant" } + } + query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { desc { "get a &core::panic::Location referring to a span" } } @@ -1251,6 +1281,11 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) desc { "calculating the visible parent map" } } + query trimmed_def_paths(_: CrateNum) + -> FxHashMap { + storage(ArenaCacheSelector<'tcx>) + desc { "calculating trimmed def paths" } + } query missing_extern_crate_item(_: CrateNum) -> bool { eval_always desc { "seeing if we're missing an `extern crate` item for this crate" } @@ -1390,7 +1425,7 @@ rustc_queries! { } query evaluate_goal( - goal: traits::ChalkCanonicalGoal<'tcx> + goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution @@ -1505,7 +1540,7 @@ rustc_queries! { desc { "looking up supported target features" } } - // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. + /// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) -> usize { desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } diff --git a/src/librustc_middle/tests.rs b/compiler/rustc_middle/src/tests.rs similarity index 100% rename from src/librustc_middle/tests.rs rename to compiler/rustc_middle/src/tests.rs diff --git a/src/librustc_middle/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs similarity index 81% rename from src/librustc_middle/traits/chalk.rs rename to compiler/rustc_middle/src/traits/chalk.rs index 405af8cb24..d8507d08c1 100644 --- a/src/librustc_middle/traits/chalk.rs +++ b/compiler/rustc_middle/src/traits/chalk.rs @@ -6,14 +6,11 @@ //! interned Chalk types. use rustc_middle::mir::interpret::ConstValue; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, TyCtxt}; use rustc_hir::def_id::DefId; use rustc_target::spec::abi::Abi; -use smallvec::SmallVec; - use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; @@ -75,6 +72,7 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { type InternedQuantifiedWhereClauses = Vec>; type InternedVariableKinds = Vec>; type InternedCanonicalVarKinds = Vec>; + type InternedConstraints = Vec>>; type DefId = DefId; type InternedAdtId = &'tcx AdtDef; type Identifier = (); @@ -108,8 +106,42 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { application_ty: &chalk_ir::ApplicationTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { - let chalk_ir::ApplicationTy { name, substitution } = application_ty; - Some(write!(fmt, "{:?}{:?}", name, chalk_ir::debug::Angle(substitution.interned()))) + match application_ty.name { + chalk_ir::TypeName::Ref(mutbl) => { + let data = application_ty.substitution.interned(); + match (&**data[0].interned(), &**data[1].interned()) { + ( + chalk_ir::GenericArgData::Lifetime(lifetime), + chalk_ir::GenericArgData::Ty(ty), + ) => Some(match mutbl { + chalk_ir::Mutability::Not => write!(fmt, "(&{:?} {:?})", lifetime, ty), + chalk_ir::Mutability::Mut => write!(fmt, "(&{:?} mut {:?})", lifetime, ty), + }), + _ => unreachable!(), + } + } + chalk_ir::TypeName::Array => { + let data = application_ty.substitution.interned(); + match (&**data[0].interned(), &**data[1].interned()) { + (chalk_ir::GenericArgData::Ty(ty), chalk_ir::GenericArgData::Const(len)) => { + Some(write!(fmt, "[{:?}; {:?}]", ty, len)) + } + _ => unreachable!(), + } + } + chalk_ir::TypeName::Slice => { + let data = application_ty.substitution.interned(); + let ty = match &**data[0].interned() { + chalk_ir::GenericArgData::Ty(t) => t, + _ => unreachable!(), + }; + Some(write!(fmt, "[{:?}]", ty)) + } + _ => { + let chalk_ir::ApplicationTy { name, substitution } = application_ty; + Some(write!(fmt, "{:?}{:?}", name, chalk_ir::debug::Angle(substitution.interned()))) + } + } } fn debug_substitution( @@ -321,37 +353,30 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { ) -> &'a [chalk_ir::CanonicalVarKind] { canonical_var_kinds } + + fn intern_constraints( + &self, + data: impl IntoIterator>, E>>, + ) -> Result { + data.into_iter().collect::, _>>() + } + + fn constraints_data<'a>( + &self, + constraints: &'a Self::InternedConstraints, + ) -> &'a [chalk_ir::InEnvironment>] { + constraints + } } impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> { type Interner = Self; } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub enum ChalkEnvironmentClause<'tcx> { - /// A normal rust `ty::Predicate` in the environment. - Predicate(ty::Predicate<'tcx>), - /// A special clause in the environment that gets lowered to - /// `chalk_ir::FromEnv::Ty`. - TypeFromEnv(Ty<'tcx>), -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_chalk_environment_clause_list(&v) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} -/// We have to elaborate the environment of a chalk goal *before* -/// canonicalization. This type wraps the predicate and the elaborated -/// environment. +/// A chalk environment and goal. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] pub struct ChalkEnvironmentAndGoal<'tcx> { - pub environment: &'tcx ty::List>, + pub environment: &'tcx ty::List>, pub goal: ty::Predicate<'tcx>, } diff --git a/src/librustc_middle/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs similarity index 89% rename from src/librustc_middle/traits/mod.rs rename to compiler/rustc_middle/src/traits/mod.rs index f86403fa50..1dd6d590d9 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -26,14 +26,11 @@ use std::rc::Rc; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; -pub type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; +pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; -pub use self::ImplSource::*; pub use self::ObligationCauseCode::*; -pub use self::chalk::{ - ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustInterner as ChalkRustInterner, -}; +pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -350,13 +347,16 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arms: Vec, pub last_ty: Ty<'tcx>, pub scrut_hir_id: hir::HirId, + pub opt_suggest_box_span: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct IfExpressionCause { pub then: Span, + pub else_sp: Span, pub outer: Option, pub semicolon: Option, + pub opt_suggest_box_span: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] @@ -417,10 +417,10 @@ pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; /// /// // Case B: ImplSource must be provided by caller. This applies when /// // type is a type parameter. -/// param.clone(); // ImplSourceParam +/// param.clone(); // ImplSource::Param /// /// // Case C: A mix of cases A and B. -/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam]) +/// mixed.clone(); // ImplSource(Impl_1, [ImplSource::Param]) /// } /// ``` /// @@ -430,72 +430,72 @@ pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] pub enum ImplSource<'tcx, N> { /// ImplSource identifying a particular impl. - ImplSourceUserDefined(ImplSourceUserDefinedData<'tcx, N>), + UserDefined(ImplSourceUserDefinedData<'tcx, N>), /// ImplSource for auto trait implementations. /// This carries the information and nested obligations with regards /// to an auto implementation for a trait `Trait`. The nested obligations /// ensure the trait implementation holds for all the constituent types. - ImplSourceAutoImpl(ImplSourceAutoImplData), + AutoImpl(ImplSourceAutoImplData), /// Successful resolution to an obligation provided by the caller /// for some type parameter. The `Vec` represents the /// obligations incurred from normalizing the where-clause (if /// any). - ImplSourceParam(Vec), + Param(Vec), /// Virtual calls through an object. - ImplSourceObject(ImplSourceObjectData<'tcx, N>), + Object(ImplSourceObjectData<'tcx, N>), /// Successful resolution for a builtin trait. - ImplSourceBuiltin(ImplSourceBuiltinData), + Builtin(ImplSourceBuiltinData), /// ImplSource automatically generated for a closure. The `DefId` is the ID - /// of the closure expression. This is a `ImplSourceUserDefined` in spirit, but the + /// of the closure expression. This is a `ImplSource::UserDefined` in spirit, but the /// impl is generated by the compiler and does not appear in the source. - ImplSourceClosure(ImplSourceClosureData<'tcx, N>), + Closure(ImplSourceClosureData<'tcx, N>), /// Same as above, but for a function pointer type with the given signature. - ImplSourceFnPointer(ImplSourceFnPointerData<'tcx, N>), + FnPointer(ImplSourceFnPointerData<'tcx, N>), /// ImplSource for a builtin `DeterminantKind` trait implementation. - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData), + DiscriminantKind(ImplSourceDiscriminantKindData), /// ImplSource automatically generated for a generator. - ImplSourceGenerator(ImplSourceGeneratorData<'tcx, N>), + Generator(ImplSourceGeneratorData<'tcx, N>), /// ImplSource for a trait alias. - ImplSourceTraitAlias(ImplSourceTraitAliasData<'tcx, N>), + TraitAlias(ImplSourceTraitAliasData<'tcx, N>), } impl<'tcx, N> ImplSource<'tcx, N> { pub fn nested_obligations(self) -> Vec { match self { - ImplSourceUserDefined(i) => i.nested, - ImplSourceParam(n) => n, - ImplSourceBuiltin(i) => i.nested, - ImplSourceAutoImpl(d) => d.nested, - ImplSourceClosure(c) => c.nested, - ImplSourceGenerator(c) => c.nested, - ImplSourceObject(d) => d.nested, - ImplSourceFnPointer(d) => d.nested, - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(), - ImplSourceTraitAlias(d) => d.nested, + ImplSource::UserDefined(i) => i.nested, + ImplSource::Param(n) => n, + ImplSource::Builtin(i) => i.nested, + ImplSource::AutoImpl(d) => d.nested, + ImplSource::Closure(c) => c.nested, + ImplSource::Generator(c) => c.nested, + ImplSource::Object(d) => d.nested, + ImplSource::FnPointer(d) => d.nested, + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(), + ImplSource::TraitAlias(d) => d.nested, } } pub fn borrow_nested_obligations(&self) -> &[N] { match &self { - ImplSourceUserDefined(i) => &i.nested[..], - ImplSourceParam(n) => &n[..], - ImplSourceBuiltin(i) => &i.nested[..], - ImplSourceAutoImpl(d) => &d.nested[..], - ImplSourceClosure(c) => &c.nested[..], - ImplSourceGenerator(c) => &c.nested[..], - ImplSourceObject(d) => &d.nested[..], - ImplSourceFnPointer(d) => &d.nested[..], - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => &[], - ImplSourceTraitAlias(d) => &d.nested[..], + ImplSource::UserDefined(i) => &i.nested[..], + ImplSource::Param(n) => &n[..], + ImplSource::Builtin(i) => &i.nested[..], + ImplSource::AutoImpl(d) => &d.nested[..], + ImplSource::Closure(c) => &c.nested[..], + ImplSource::Generator(c) => &c.nested[..], + ImplSource::Object(d) => &d.nested[..], + ImplSource::FnPointer(d) => &d.nested[..], + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[], + ImplSource::TraitAlias(d) => &d.nested[..], } } @@ -504,42 +504,42 @@ impl<'tcx, N> ImplSource<'tcx, N> { F: FnMut(N) -> M, { match self { - ImplSourceUserDefined(i) => ImplSourceUserDefined(ImplSourceUserDefinedData { + ImplSource::UserDefined(i) => ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id: i.impl_def_id, substs: i.substs, nested: i.nested.into_iter().map(f).collect(), }), - ImplSourceParam(n) => ImplSourceParam(n.into_iter().map(f).collect()), - ImplSourceBuiltin(i) => ImplSourceBuiltin(ImplSourceBuiltinData { + ImplSource::Param(n) => ImplSource::Param(n.into_iter().map(f).collect()), + ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData { nested: i.nested.into_iter().map(f).collect(), }), - ImplSourceObject(o) => ImplSourceObject(ImplSourceObjectData { + ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData { upcast_trait_ref: o.upcast_trait_ref, vtable_base: o.vtable_base, nested: o.nested.into_iter().map(f).collect(), }), - ImplSourceAutoImpl(d) => ImplSourceAutoImpl(ImplSourceAutoImplData { + ImplSource::AutoImpl(d) => ImplSource::AutoImpl(ImplSourceAutoImplData { trait_def_id: d.trait_def_id, nested: d.nested.into_iter().map(f).collect(), }), - ImplSourceClosure(c) => ImplSourceClosure(ImplSourceClosureData { + ImplSource::Closure(c) => ImplSource::Closure(ImplSourceClosureData { closure_def_id: c.closure_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), - ImplSourceGenerator(c) => ImplSourceGenerator(ImplSourceGeneratorData { + ImplSource::Generator(c) => ImplSource::Generator(ImplSourceGeneratorData { generator_def_id: c.generator_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), - ImplSourceFnPointer(p) => ImplSourceFnPointer(ImplSourceFnPointerData { + ImplSource::FnPointer(p) => ImplSource::FnPointer(ImplSourceFnPointerData { fn_ty: p.fn_ty, nested: p.nested.into_iter().map(f).collect(), }), - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => { - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => { + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) } - ImplSourceTraitAlias(d) => ImplSourceTraitAlias(ImplSourceTraitAliasData { + ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData { alias_def_id: d.alias_def_id, substs: d.substs, nested: d.nested.into_iter().map(f).collect(), diff --git a/src/librustc_middle/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs similarity index 77% rename from src/librustc_middle/traits/query.rs rename to compiler/rustc_middle/src/traits/query.rs index 4b7663e9ad..f9cadb3bb2 100644 --- a/src/librustc_middle/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -190,74 +190,6 @@ impl<'tcx> FromIterator> for DtorckConstraint<'tcx> { } } -/// This returns true if the type `ty` is "trivial" for -/// dropck-outlives -- that is, if it doesn't require any types to -/// outlive. This is similar but not *quite* the same as the -/// `needs_drop` test in the compiler already -- that is, for every -/// type T for which this function return true, needs-drop would -/// return `false`. But the reverse does not hold: in particular, -/// `needs_drop` returns false for `PhantomData`, but it is not -/// trivial for dropck-outlives. -/// -/// Note also that `needs_drop` requires a "global" type (i.e., one -/// with erased regions), but this function does not. -pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind { - // None of these types have a destructor and hence they do not - // require anything in particular to outlive the dtor's - // execution. - ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Bool - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Never - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Char - | ty::GeneratorWitness(..) - | ty::RawPtr(_) - | ty::Ref(..) - | ty::Str - | ty::Foreign(..) - | ty::Error(_) => true, - - // [T; N] and [T] have same properties as T. - ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), - - // (T1..Tn) and closures have same properties as T1..Tn -- - // check if *any* of those are trivial. - ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), - ty::Closure(_, ref substs) => { - substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t)) - } - - ty::Adt(def, _) => { - if Some(def.did) == tcx.lang_items().manually_drop() { - // `ManuallyDrop` never has a dtor. - true - } else { - // Other types might. Moreover, PhantomData doesn't - // have a dtor, but it is considered to own its - // content, so it is non-trivial. Unions can have `impl Drop`, - // and hence are non-trivial as well. - false - } - } - - // The following *might* require a destructor: needs deeper inspection. - ty::Dynamic(..) - | ty::Projection(..) - | ty::Param(_) - | ty::Opaque(..) - | ty::Placeholder(..) - | ty::Infer(_) - | ty::Bound(..) - | ty::Generator(..) => false, - } -} - #[derive(Debug, HashStable)] pub struct CandidateStep<'tcx> { pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, diff --git a/src/librustc_middle/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs similarity index 100% rename from src/librustc_middle/traits/select.rs rename to compiler/rustc_middle/src/traits/select.rs diff --git a/src/librustc_middle/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs similarity index 100% rename from src/librustc_middle/traits/specialization_graph.rs rename to compiler/rustc_middle/src/traits/specialization_graph.rs diff --git a/src/librustc_middle/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs similarity index 77% rename from src/librustc_middle/traits/structural_impls.rs rename to compiler/rustc_middle/src/traits/structural_impls.rs index d73fc628ce..b8f6675b8e 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -7,25 +7,25 @@ use std::fmt; impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - super::ImplSourceUserDefined(ref v) => write!(f, "{:?}", v), + super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v), - super::ImplSourceAutoImpl(ref t) => write!(f, "{:?}", t), + super::ImplSource::AutoImpl(ref t) => write!(f, "{:?}", t), - super::ImplSourceClosure(ref d) => write!(f, "{:?}", d), + super::ImplSource::Closure(ref d) => write!(f, "{:?}", d), - super::ImplSourceGenerator(ref d) => write!(f, "{:?}", d), + super::ImplSource::Generator(ref d) => write!(f, "{:?}", d), - super::ImplSourceFnPointer(ref d) => write!(f, "ImplSourceFnPointer({:?})", d), + super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d), - super::ImplSourceDiscriminantKind(ref d) => write!(f, "{:?}", d), + super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d), - super::ImplSourceObject(ref d) => write!(f, "{:?}", d), + super::ImplSource::Object(ref d) => write!(f, "{:?}", d), - super::ImplSourceParam(ref n) => write!(f, "ImplSourceParam({:?})", n), + super::ImplSource::Param(ref n) => write!(f, "ImplSourceParamData({:?})", n), - super::ImplSourceBuiltin(ref d) => write!(f, "{:?}", d), + super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d), - super::ImplSourceTraitAlias(ref d) => write!(f, "{:?}", d), + super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d), } } } @@ -96,7 +96,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "ImplSourceTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", + "ImplSourceTraitAliasData(alias_def_id={:?}, substs={:?}, nested={:?})", self.alias_def_id, self.substs, self.nested ) } diff --git a/src/librustc_middle/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs similarity index 98% rename from src/librustc_middle/ty/_match.rs rename to compiler/rustc_middle/src/ty/_match.rs index 4693a2f66f..27bccc0bca 100644 --- a/src/librustc_middle/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -67,7 +67,7 @@ impl TypeRelation<'tcx> for Match<'tcx> { return Ok(a); } - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { ( _, &ty::Infer(ty::FreshTy(_)) diff --git a/src/librustc_middle/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs similarity index 98% rename from src/librustc_middle/ty/adjustment.rs rename to compiler/rustc_middle/src/ty/adjustment.rs index 6a9bb8d6c2..46ef5ff7dd 100644 --- a/src/librustc_middle/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; +use rustc_span::Span; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub enum PointerCast { @@ -113,6 +114,9 @@ pub enum Adjust<'tcx> { pub struct OverloadedDeref<'tcx> { pub region: ty::Region<'tcx>, pub mutbl: hir::Mutability, + /// The `Span` associated with the field access or method call + /// that triggered this overloaded deref. + pub span: Span, } impl<'tcx> OverloadedDeref<'tcx> { diff --git a/src/librustc_middle/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs similarity index 100% rename from src/librustc_middle/ty/binding.rs rename to compiler/rustc_middle/src/ty/binding.rs diff --git a/src/librustc_middle/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs similarity index 98% rename from src/librustc_middle/ty/cast.rs rename to compiler/rustc_middle/src/ty/cast.rs index 79a3008c36..b47d9c50e1 100644 --- a/src/librustc_middle/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -50,7 +50,7 @@ impl<'tcx> CastTy<'tcx> { /// Returns `Some` for integral/pointer casts. /// casts like unsizing casts will return `None` pub fn from_ty(t: Ty<'tcx>) -> Option> { - match t.kind { + match *t.kind() { ty::Bool => Some(CastTy::Int(IntTy::Bool)), ty::Char => Some(CastTy::Int(IntTy::Char)), ty::Int(_) => Some(CastTy::Int(IntTy::I)), diff --git a/src/librustc_middle/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs similarity index 95% rename from src/librustc_middle/ty/codec.rs rename to compiler/rustc_middle/src/ty/codec.rs index 291648869f..8ea34f9161 100644 --- a/src/librustc_middle/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -36,8 +36,10 @@ pub trait EncodableWithShorthand<'tcx, E: TyEncoder<'tcx>>: Copy + Eq + Hash { #[allow(rustc::usage_of_ty_tykind)] impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for Ty<'tcx> { type Variant = ty::TyKind<'tcx>; + + #[inline] fn variant(&self) -> &Self::Variant { - &self.kind + self.kind() } } @@ -355,6 +357,26 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, } } +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] { + fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + Ok(decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()?) + .map(|_| Decodable::decode(decoder)) + .collect::, _>>()?, + )) + } +} + +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] { + fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + Ok(decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()?) + .map(|_| Decodable::decode(decoder)) + .collect::, _>>()?, + )) + } +} + impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List>, diff --git a/src/librustc_middle/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs similarity index 100% rename from src/librustc_middle/ty/consts.rs rename to compiler/rustc_middle/src/ty/consts.rs diff --git a/src/librustc_middle/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs similarity index 100% rename from src/librustc_middle/ty/consts/int.rs rename to compiler/rustc_middle/src/ty/consts/int.rs diff --git a/src/librustc_middle/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs similarity index 100% rename from src/librustc_middle/ty/consts/kind.rs rename to compiler/rustc_middle/src/ty/consts/kind.rs diff --git a/src/librustc_middle/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs similarity index 97% rename from src/librustc_middle/ty/context.rs rename to compiler/rustc_middle/src/ty/context.rs index 18ae744cb1..22c3fd37be 100644 --- a/src/librustc_middle/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -34,6 +34,7 @@ use rustc_data_structures::stable_hasher::{ hash_stable_hashmap, HashStable, StableHasher, StableVec, }; use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; +use rustc_data_structures::unhash::UnhashMap; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -65,8 +66,8 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -/// A type that is not publicly constructable. This prevents people from making `TyKind::Error` -/// except through `tcx.err*()`, which are in this module. +/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s +/// except through the error-reporting functions on a [`tcx`][TyCtxt]. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] #[derive(TyEncodable, TyDecodable, HashStable)] pub struct DelaySpanBugEmitted(()); @@ -90,8 +91,6 @@ pub struct CtxtInterners<'tcx> { projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, - - chalk_environment_clause_list: InternedSet<'tcx, List>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -109,7 +108,6 @@ impl<'tcx> CtxtInterners<'tcx> { projs: Default::default(), place_elems: Default::default(), const_: Default::default(), - chalk_environment_clause_list: Default::default(), } } @@ -758,10 +756,10 @@ impl CanonicalUserType<'tcx> { user_substs.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { match kind.unpack() { - GenericArgKind::Type(ty) => match ty.kind { + GenericArgKind::Type(ty) => match ty.kind() { ty::Bound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debruijn, ty::INNERMOST); + assert_eq!(*debruijn, ty::INNERMOST); cvar == b.var } _ => false, @@ -935,7 +933,7 @@ pub struct GlobalCtxt<'tcx> { /// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate /// as well as all upstream crates. Only populated in incremental mode. - pub def_path_hash_to_def_id: Option>, + pub def_path_hash_to_def_id: Option>, pub queries: query::Queries<'tcx>, @@ -943,7 +941,7 @@ pub struct GlobalCtxt<'tcx> { maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, /// A map of glob use to a set of names it actually imports. Currently only /// used in save-analysis. - glob_map: FxHashMap>, + pub(crate) glob_map: FxHashMap>, /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. pub extern_prelude: FxHashMap, @@ -1104,7 +1102,7 @@ impl<'tcx> TyCtxt<'tcx> { let def_path_hash_to_def_id = if s.opts.build_dep_graph() { let capacity = definitions.def_path_table().num_def_ids() + crates.iter().map(|cnum| cstore.num_def_ids(*cnum)).sum::(); - let mut map = FxHashMap::with_capacity_and_hasher(capacity, Default::default()); + let mut map = UnhashMap::with_capacity_and_hasher(capacity, Default::default()); map.extend(definitions.def_path_table().all_def_path_hashes_and_def_ids(LOCAL_CRATE)); for cnum in &crates { @@ -1181,7 +1179,7 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty }) } - pub fn consider_optimizing String>(&self, msg: T) -> bool { + pub fn consider_optimizing String>(self, msg: T) -> bool { let cname = self.crate_name(LOCAL_CRATE).as_str(); self.sess.consider_optimizing(&cname, msg) } @@ -1274,7 +1272,7 @@ impl<'tcx> TyCtxt<'tcx> { // Don't print the whole crate disambiguator. That's just // annoying in debug output. &(crate_disambiguator.to_fingerprint().to_hex())[..4], - self.def_path(def_id).to_string_no_crate() + self.def_path(def_id).to_string_no_crate_verbose() ) } @@ -1405,7 +1403,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Returns the `DefId` and the `BoundRegion` corresponding to the given region. - pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option { + pub fn is_suitable_region(self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { (free_region.scope.expect_local(), free_region.bound_region) @@ -1435,7 +1433,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type. pub fn return_type_impl_or_dyn_traits( - &self, + self, scope_def_id: LocalDefId, ) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); @@ -1481,7 +1479,7 @@ impl<'tcx> TyCtxt<'tcx> { v.0 } - pub fn return_type_impl_trait(&self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { + pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`. let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); match self.hir().get(hir_id) { @@ -1497,9 +1495,9 @@ impl<'tcx> TyCtxt<'tcx> { } let ret_ty = self.type_of(scope_def_id); - match ret_ty.kind { + match ret_ty.kind() { ty::FnDef(_, _) => { - let sig = ret_ty.fn_sig(*self); + let sig = ret_ty.fn_sig(self); let output = self.erase_late_bound_regions(&sig.output()); if output.is_impl_trait() { let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); @@ -1513,7 +1511,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Checks if the bound region is in Impl Item. - pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: LocalDefId) -> bool { + pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool { let container_id = self.associated_item(suitable_region_binding_scope.to_def_id()).container.id(); if self.impl_trait_ref(container_id).is_some() { @@ -1530,21 +1528,21 @@ impl<'tcx> TyCtxt<'tcx> { /// Determines whether identifiers in the assembly have strict naming rules. /// Currently, only NVPTX* targets need it. - pub fn has_strict_asm_symbol_naming(&self) -> bool { + pub fn has_strict_asm_symbol_naming(self) -> bool { self.sess.target.target.arch.contains("nvptx") } /// Returns `&'static core::panic::Location<'static>`. - pub fn caller_location_ty(&self) -> Ty<'tcx> { + pub fn caller_location_ty(self) -> Ty<'tcx> { self.mk_imm_ref( self.lifetimes.re_static, self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) - .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())), + .subst(self, self.mk_substs([self.lifetimes.re_static.into()].iter())), ) } /// Returns a displayable description and article for the given `def_id` (e.g. `("a", "struct")`). - pub fn article_and_description(&self, def_id: DefId) -> (&'static str, &'static str) { + pub fn article_and_description(self, def_id: DefId) -> (&'static str, &'static str) { match self.def_kind(def_id) { DefKind::Generator => match self.generator_kind(def_id).unwrap() { rustc_hir::GeneratorKind::Async(..) => ("an", "async closure"), @@ -1821,15 +1819,15 @@ macro_rules! sty_debug_print { let shards = tcx.interners.type_.lock_shards(); let types = shards.iter().flat_map(|shard| shard.keys()); for &Interned(t) in types { - let variant = match t.kind { + let variant = match t.kind() { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, ty::Error(_) => /* unimportant */ continue, $(ty::$variant(..) => &mut $variant,)* }; - let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER); - let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER); - let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER); + let lt = t.flags().intersects(ty::TypeFlags::HAS_RE_INFER); + let ty = t.flags().intersects(ty::TypeFlags::HAS_TY_INFER); + let ct = t.flags().intersects(ty::TypeFlags::HAS_CT_INFER); variant.total += 1; total.total += 1; @@ -1930,7 +1928,7 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> { // N.B., an `Interned` compares and hashes as a `TyKind`. impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> { fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool { - self.0.kind == other.0.kind + self.0.kind() == other.0.kind() } } @@ -1938,14 +1936,14 @@ impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {} impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> { fn hash(&self, s: &mut H) { - self.0.kind.hash(s) + self.0.kind().hash(s) } } #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Borrow> for Interned<'tcx, TyS<'tcx>> { fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { - &self.0.kind + &self.0.kind() } } // N.B., an `Interned` compares and hashes as a `PredicateKind`. @@ -2040,7 +2038,7 @@ direct_interners! { } macro_rules! slice_interners { - ($($field:ident: $method:ident($ty:ty)),+) => ( + ($($field:ident: $method:ident($ty:ty)),+ $(,)?) => ( $(impl<'tcx> TyCtxt<'tcx> { pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { self.interners.$field.intern_ref(v, || { @@ -2059,8 +2057,6 @@ slice_interners!( predicates: _intern_predicates(Predicate<'tcx>), projs: _intern_projs(ProjectionKind), place_elems: _intern_place_elems(PlaceElem<'tcx>), - chalk_environment_clause_list: - _intern_chalk_environment_clause_list(traits::ChalkEnvironmentClause<'tcx>) ); impl<'tcx> TyCtxt<'tcx> { @@ -2085,7 +2081,7 @@ impl<'tcx> TyCtxt<'tcx> { unsafety: hir::Unsafety, ) -> PolyFnSig<'tcx> { sig.map_bound(|s| { - let params_iter = match s.inputs()[0].kind { + let params_iter = match s.inputs()[0].kind() { ty::Tuple(params) => params.into_iter().map(|k| k.expect_ty()), _ => bug!(), }; @@ -2423,7 +2419,7 @@ impl<'tcx> TyCtxt<'tcx> { eps: &[ExistentialPredicate<'tcx>], ) -> &'tcx List> { assert!(!eps.is_empty()); - assert!(eps.windows(2).all(|w| w[0].stable_cmp(self, &w[1]) != Ordering::Greater)); + assert!(eps.array_windows().all(|[a, b]| a.stable_cmp(self, b) != Ordering::Greater)); self._intern_existential_predicates(eps) } @@ -2459,13 +2455,6 @@ impl<'tcx> TyCtxt<'tcx> { if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) } } - pub fn intern_chalk_environment_clause_list( - self, - ts: &[traits::ChalkEnvironmentClause<'tcx>], - ) -> &'tcx List> { - if ts.is_empty() { List::empty() } else { self._intern_chalk_environment_clause_list(ts) } - } - pub fn mk_fn_sig( self, inputs: I, @@ -2523,18 +2512,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned())) } - pub fn mk_chalk_environment_clause_list< - I: InternAs< - [traits::ChalkEnvironmentClause<'tcx>], - &'tcx List>, - >, - >( - self, - iter: I, - ) -> I::Output { - iter.intern_with(|xs| self.intern_chalk_environment_clause_list(xs)) - } - /// Walks upwards from `id` to find a node which might change lint levels with attributes. /// It stops at `bound` and just returns it if reached. pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { diff --git a/src/librustc_middle/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs similarity index 78% rename from src/librustc_middle/ty/diagnostics.rs rename to compiler/rustc_middle/src/ty/diagnostics.rs index b22727bdd7..715319747e 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -11,7 +11,7 @@ use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; impl<'tcx> TyS<'tcx> { /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive. pub fn is_primitive_ty(&self) -> bool { - match self.kind { + match self.kind() { Bool | Char | Str @@ -31,7 +31,7 @@ impl<'tcx> TyS<'tcx> { /// Whether the type is succinctly representable as a type instead of just referred to with a /// description in error messages. This is used in the main error message. pub fn is_simple_ty(&self) -> bool { - match self.kind { + match self.kind() { Bool | Char | Str @@ -55,7 +55,7 @@ impl<'tcx> TyS<'tcx> { /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to /// ADTs with no type arguments. pub fn is_simple_text(&self) -> bool { - match self.kind { + match self.kind() { Adt(_, substs) => substs.types().next().is_none(), Ref(_, ty, _) => ty.is_simple_text(), _ => self.is_simple_ty(), @@ -64,7 +64,7 @@ impl<'tcx> TyS<'tcx> { /// Whether the type can be safely suggested during error recovery. pub fn is_suggestable(&self) -> bool { - match self.kind { + match self.kind() { Opaque(..) | FnDef(..) | FnPtr(..) | Dynamic(..) | Closure(..) | Infer(..) | Projection(..) => false, _ => true, @@ -202,33 +202,59 @@ pub fn suggest_constraining_type_param( // Suggestion: // fn foo(t: T) where T: Foo, T: Bar {... } // - insert: `, T: Zar` + // + // Additionally, there may be no `where` clause whatsoever in the case that this was + // reached because the generic parameter has a default: + // + // Message: + // trait Foo {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // trait Foo where T: Zar {... } + // - insert: `where T: Zar` - let mut param_spans = Vec::new(); + if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) + && generics.where_clause.predicates.len() == 0 + { + // Suggest a bound, but there is no existing `where` clause *and* the type param has a + // default (``), so we suggest adding `where T: Bar`. + err.span_suggestion_verbose( + generics.where_clause.tail_span_for_suggestion(), + &msg_restrict_type_further, + format!(" where {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } else { + let mut param_spans = Vec::new(); - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, bounded_ty, .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - param_spans.push(span); + for predicate in generics.where_clause.predicates { + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + span, + bounded_ty, + .. + }) = predicate + { + if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { + if let Some(segment) = path.segments.first() { + if segment.ident.to_string() == param_name { + param_spans.push(span); + } } } } } - } - match ¶m_spans[..] { - &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), - _ => { - err.span_suggestion_verbose( - generics.where_clause.tail_span_for_suggestion(), - &msg_restrict_type_further, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); + match ¶m_spans[..] { + &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), + _ => { + err.span_suggestion_verbose( + generics.where_clause.tail_span_for_suggestion(), + &msg_restrict_type_further, + format!(", {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } } } diff --git a/src/librustc_middle/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs similarity index 100% rename from src/librustc_middle/ty/erase_regions.rs rename to compiler/rustc_middle/src/ty/erase_regions.rs diff --git a/src/librustc_middle/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs similarity index 94% rename from src/librustc_middle/ty/error.rs rename to compiler/rustc_middle/src/ty/error.rs index 1963881626..82d698b37a 100644 --- a/src/librustc_middle/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -56,6 +56,7 @@ pub enum TypeError<'tcx> { /// created a cycle (because it appears somewhere within that /// type). CyclicTy(Ty<'tcx>), + CyclicConst(&'tcx ty::Const<'tcx>), ProjectionMismatched(ExpectedFound), ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), ObjectUnsafeCoercion(DefId), @@ -100,6 +101,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { match *self { CyclicTy(_) => write!(f, "cyclic type of infinite size"), + CyclicConst(_) => write!(f, "encountered a self-referencing constant"), Mismatch => write!(f, "types differ"), UnsafetyMismatch(values) => { write!(f, "expected {} fn, found {} fn", values.expected, values.found) @@ -195,9 +197,9 @@ impl<'tcx> TypeError<'tcx> { pub fn must_include_note(&self) -> bool { use self::TypeError::*; match self { - CyclicTy(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) - | TargetFeatureCast(_) => false, + CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) + | FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) + | VariadicMismatch(_) | TargetFeatureCast(_) => false, Mutability | TupleSize(_) @@ -218,7 +220,7 @@ impl<'tcx> TypeError<'tcx> { impl<'tcx> ty::TyS<'tcx> { pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { - match self.kind { + match *self.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { format!("`{}`", self).into() } @@ -230,7 +232,7 @@ impl<'tcx> ty::TyS<'tcx> { let n = tcx.lift(&n).unwrap(); match n.try_eval_usize(tcx, ty::ParamEnv::empty()) { _ if t.is_simple_ty() => format!("array `{}`", self).into(), - Some(n) => format!("array of {} element{} ", n, pluralize!(n)).into(), + Some(n) => format!("array of {} element{}", n, pluralize!(n)).into(), None => "array".into(), } } @@ -282,7 +284,7 @@ impl<'tcx> ty::TyS<'tcx> { } pub fn prefix_string(&self) -> Cow<'static, str> { - match self.kind { + match *self.kind() { ty::Infer(_) | ty::Error(_) | ty::Bool @@ -351,7 +353,7 @@ impl<'tcx> TyCtxt<'tcx> { ); } } - match (&values.expected.kind, &values.found.kind) { + match (values.expected.kind(), values.found.kind()) { (ty::Float(_), ty::Infer(ty::IntVar(_))) => { if let Ok( // Issue #53280 @@ -473,6 +475,18 @@ impl Trait for X { #traits-as-parameters", ); } + (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => { + let generics = self.generics_of(body_owner_def_id); + let p_span = self.def_span(generics.type_param(p, self).def_id); + if !sp.contains(p_span) { + db.span_label(p_span, "this type parameter"); + } + db.help(&format!( + "every closure has a distinct type and so could not always match the \ + caller-chosen type of parameter `{}`", + p + )); + } (ty::Param(p), _) | (_, ty::Param(p)) => { let generics = self.generics_of(body_owner_def_id); let p_span = self.def_span(generics.type_param(p, self).def_id); @@ -512,7 +526,10 @@ impl Trait for X { } debug!( "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})", - values.expected, values.expected.kind, values.found, values.found.kind, + values.expected, + values.expected.kind(), + values.found, + values.found.kind(), ); } CyclicTy(ty) => { @@ -543,7 +560,7 @@ impl Trait for X { } fn suggest_constraint( - &self, + self, db: &mut DiagnosticBuilder<'_>, msg: &str, body_owner_def_id: DefId, @@ -551,14 +568,14 @@ impl Trait for X { ty: Ty<'tcx>, ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); - let trait_ref = proj_ty.trait_ref(*self); + let trait_ref = proj_ty.trait_ref(self); if let Some(item) = self.hir().get_if_local(body_owner_def_id) { if let Some(hir_generics) = item.generics() { // Get the `DefId` for the type parameter corresponding to `A` in `::Foo`. // This will also work for `impl Trait`. - let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind { + let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { let generics = self.generics_of(body_owner_def_id); - generics.type_param(¶m_ty, *self).def_id + generics.type_param(param_ty, self).def_id } else { return false; }; @@ -626,7 +643,7 @@ impl Trait for X { /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc /// fn that returns the type. fn expected_projection( - &self, + self, db: &mut DiagnosticBuilder<'_>, proj_ty: &ty::ProjectionTy<'tcx>, values: &ExpectedFound>, @@ -680,7 +697,7 @@ impl Trait for X { } } - if let ty::Opaque(def_id, _) = proj_ty.self_ty().kind { + if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() { // When the expected `impl Trait` is not defined in the current item, it will come from // a return type. This can occur when dealing with `TryStream` (#71035). if self.constrain_associated_type_structured_suggestion( @@ -731,7 +748,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_methods_that_satisfy_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, assoc_container_id: DefId, current_method_ident: Option, @@ -750,7 +767,7 @@ fn foo(&self) -> Self::T { String::new() } }) .filter_map(|(_, item)| { let method = self.fn_sig(item.def_id); - match method.output().skip_binder().kind { + match *method.output().skip_binder().kind() { ty::Projection(ty::ProjectionTy { item_def_id, .. }) if item_def_id == proj_ty_item_def_id => { @@ -786,7 +803,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, body_owner_def_id: DefId, found: Ty<'tcx>, @@ -829,14 +846,11 @@ fn foo(&self) -> Self::T { String::new() } kind: hir::ItemKind::Impl { items, .. }, .. })) => { for item in &items[..] { - match item.kind { - hir::AssocItemKind::Type => { - if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { - db.span_label(item.span, "expected this associated type"); - return true; - } + if let hir::AssocItemKind::Type = item.kind { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { + db.span_label(item.span, "expected this associated type"); + return true; } - _ => {} } } } @@ -848,7 +862,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`. fn constrain_generic_bound_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, @@ -872,7 +886,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a span corresponding to a bound, provide a structured suggestion to set an /// associated type to a given type `ty`. fn constrain_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, span: Span, assoc: &ty::AssocItem, diff --git a/src/librustc_middle/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs similarity index 99% rename from src/librustc_middle/ty/fast_reject.rs rename to compiler/rustc_middle/src/ty/fast_reject.rs index 1bee2d60f7..860f91db2b 100644 --- a/src/librustc_middle/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -60,7 +60,7 @@ pub fn simplify_type( ty: Ty<'_>, can_simplify_params: bool, ) -> Option { - match ty.kind { + match *ty.kind() { ty::Bool => Some(BoolSimplifiedType), ty::Char => Some(CharSimplifiedType), ty::Int(int_type) => Some(IntSimplifiedType(int_type)), diff --git a/src/librustc_middle/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs similarity index 98% rename from src/librustc_middle/ty/flags.rs rename to compiler/rustc_middle/src/ty/flags.rs index 27f50c240d..c9a4022330 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -249,11 +249,14 @@ impl FlagComputation { self.add_const(expected); self.add_const(found); } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + self.add_ty(ty); + } } } fn add_ty(&mut self, ty: Ty<'_>) { - self.add_flags(ty.flags); + self.add_flags(ty.flags()); self.add_exclusive_binder(ty.outer_exclusive_binder); } diff --git a/src/librustc_middle/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs similarity index 98% rename from src/librustc_middle/ty/fold.rs rename to compiler/rustc_middle/src/ty/fold.rs index 492f8ce9ef..84134bedef 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -352,7 +352,7 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { // We're only interested in types involving regions - if ty.flags.intersects(TypeFlags::HAS_FREE_REGIONS) { + if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) } else { false // keep visiting @@ -471,7 +471,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match *t.kind() { ty::Bound(debruijn, bound_ty) => { if debruijn == self.current_index { let fld_t = &mut self.fld_t; @@ -623,7 +623,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Replaces any late-bound regions bound in `value` with /// free variants attached to `all_outlive_scope`. pub fn liberate_late_bound_regions( - &self, + self, all_outlive_scope: DefId, value: &ty::Binder, ) -> T @@ -644,7 +644,7 @@ impl<'tcx> TyCtxt<'tcx> { /// variables and equate `value` with something else, those /// variables will also be equated. pub fn collect_constrained_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -655,7 +655,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns a set of all late-bound regions that appear in `value` anywhere. pub fn collect_referenced_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -665,7 +665,7 @@ impl<'tcx> TyCtxt<'tcx> { } fn collect_late_bound_regions( - &self, + self, value: &Binder, just_constraint: bool, ) -> FxHashSet @@ -771,7 +771,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match *ty.kind() { ty::Bound(debruijn, bound_ty) => { if self.amount == 0 || debruijn < self.current_index { ty @@ -922,8 +922,13 @@ struct HasTypeFlagsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { fn visit_ty(&mut self, t: Ty<'_>) -> bool { - debug!("HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, t.flags, self.flags); - t.flags.intersects(self.flags) + debug!( + "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", + t, + t.flags(), + self.flags + ); + t.flags().intersects(self.flags) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { @@ -987,7 +992,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(..) | ty::Opaque(..) = t.kind { + if let ty::Projection(..) | ty::Opaque(..) = t.kind() { return false; } } diff --git a/src/librustc_middle/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs similarity index 100% rename from src/librustc_middle/ty/inhabitedness/def_id_forest.rs rename to compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs diff --git a/src/librustc_middle/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs similarity index 99% rename from src/librustc_middle/ty/inhabitedness/mod.rs rename to compiler/rustc_middle/src/ty/inhabitedness/mod.rs index d1b5eed921..2c1179c21f 100644 --- a/src/librustc_middle/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -196,7 +196,7 @@ impl<'tcx> FieldDef { impl<'tcx> TyS<'tcx> { /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest { - match self.kind { + match *self.kind() { Adt(def, substs) => { ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env)) } diff --git a/src/librustc_middle/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs similarity index 95% rename from src/librustc_middle/ty/instance.rs rename to compiler/rustc_middle/src/ty/instance.rs index 8e08fe4b87..a6b62097d5 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -62,10 +62,6 @@ pub enum InstanceDef<'tcx> { /// `::call_*` (generated `FnTrait` implementation for `fn()` pointers). /// /// `DefId` is `FnTrait::call_*`. - /// - /// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution - /// problems with the MIR shim bodies. `Instance::resolve` enforces this. - // FIXME(#69925) support polymorphic MIR shim bodies properly instead. FnPtrShim(DefId, Ty<'tcx>), /// Dynamic dispatch to `::fn`. @@ -87,10 +83,6 @@ pub enum InstanceDef<'tcx> { /// The `DefId` is for `core::ptr::drop_in_place`. /// The `Option>` is either `Some(T)`, or `None` for empty drop /// glue. - /// - /// NB: the type must currently be monomorphic to avoid double substitution - /// problems with the MIR shim bodies. `Instance::resolve` enforces this. - // FIXME(#69925) support polymorphic MIR shim bodies properly instead. DropGlue(DefId, Option>), /// Compiler-generated `::clone` implementation. @@ -99,10 +91,6 @@ pub enum InstanceDef<'tcx> { /// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`. /// /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl. - /// - /// NB: the type must currently be monomorphic to avoid double substitution - /// problems with the MIR shim bodies. `Instance::resolve` enforces this. - // FIXME(#69925) support polymorphic MIR shim bodies properly instead. CloneShim(DefId, Ty<'tcx>), } @@ -243,6 +231,27 @@ impl<'tcx> InstanceDef<'tcx> { _ => false, } } + + /// Returns `true` when the MIR body associated with this instance should be monomorphized + /// by its users (e.g. codegen or miri) by substituting the `substs` from `Instance` (see + /// `Instance::substs_for_mir_body`). + /// + /// Otherwise, returns `false` only for some kinds of shims where the construction of the MIR + /// body should perform necessary substitutions. + pub fn has_polymorphic_mir_body(&self) -> bool { + match *self { + InstanceDef::CloneShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::DropGlue(_, Some(_)) => false, + InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::Item(_) + | InstanceDef::Intrinsic(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::VtableShim(..) => true, + } + } } impl<'tcx> fmt::Display for Instance<'tcx> { @@ -260,10 +269,11 @@ impl<'tcx> fmt::Display for Instance<'tcx> { InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num), - InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({:?})", ty), + InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty), InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), - InstanceDef::DropGlue(_, ty) => write!(f, " - shim({:?})", ty), - InstanceDef::CloneShim(_, ty) => write!(f, " - shim({:?})", ty), + InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), + InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", ty), + InstanceDef::CloneShim(_, ty) => write!(f, " - shim({})", ty), } } } @@ -439,30 +449,18 @@ impl<'tcx> Instance<'tcx> { Instance { def, substs } } - /// FIXME(#69925) Depending on the kind of `InstanceDef`, the MIR body associated with an + /// Depending on the kind of `InstanceDef`, the MIR body associated with an /// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other /// cases the MIR body is expressed in terms of the types found in the substitution array. /// In the former case, we want to substitute those generic types and replace them with the /// values from the substs when monomorphizing the function body. But in the latter case, we /// don't want to do that substitution, since it has already been done effectively. /// - /// This function returns `Some(substs)` in the former case and None otherwise -- i.e., if + /// This function returns `Some(substs)` in the former case and `None` otherwise -- i.e., if /// this function returns `None`, then the MIR body does not require substitution during - /// monomorphization. + /// codegen. pub fn substs_for_mir_body(&self) -> Option> { - match self.def { - InstanceDef::CloneShim(..) - | InstanceDef::DropGlue(_, Some(_)) => None, - InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - // FIXME(#69925): `FnPtrShim` should be in the other branch. - | InstanceDef::FnPtrShim(..) - | InstanceDef::Item(_) - | InstanceDef::Intrinsic(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::VtableShim(..) => Some(self.substs), - } + if self.def.has_polymorphic_mir_body() { Some(self.substs) } else { None } } /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by diff --git a/src/librustc_middle/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs similarity index 96% rename from src/librustc_middle/ty/layout.rs rename to compiler/rustc_middle/src/ty/layout.rs index 08bd131565..ee669ed228 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -174,9 +174,9 @@ pub enum LayoutError<'tcx> { impl<'tcx> fmt::Display for LayoutError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - LayoutError::Unknown(ty) => write!(f, "the type `{:?}` has an unknown layout", ty), + LayoutError::Unknown(ty) => write!(f, "the type `{}` has an unknown layout", ty), LayoutError::SizeOverflow(ty) => { - write!(f, "the type `{:?}` is too big for the current architecture", ty) + write!(f, "the type `{}` is too big for the current architecture", ty) } } } @@ -390,78 +390,60 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Unpack newtype ABIs and find scalar pairs. if sized && size.bytes() > 0 { - // All other fields must be ZSTs, and we need them to all start at 0. - let mut zst_offsets = offsets.iter().enumerate().filter(|&(i, _)| fields[i].is_zst()); - if zst_offsets.all(|(_, o)| o.bytes() == 0) { - let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.is_zst()); - - match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { - // We have exactly one non-ZST field. - (Some((i, field)), None, None) => { - // Field fills the struct and it has a scalar or scalar pair ABI. - if offsets[i].bytes() == 0 - && align.abi == field.align.abi - && size == field.size - { - match field.abi { - // For plain scalars, or vectors of them, we can't unpack - // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize => { - abi = field.abi.clone(); - } - // But scalar pairs are Rust-specific and get - // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi.clone(); - } - _ => {} + // All other fields must be ZSTs. + let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.is_zst()); + + match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { + // We have exactly one non-ZST field. + (Some((i, field)), None, None) => { + // Field fills the struct and it has a scalar or scalar pair ABI. + if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size + { + match field.abi { + // For plain scalars, or vectors of them, we can't unpack + // newtypes for `#[repr(C)]`, as that affects C ABIs. + Abi::Scalar(_) | Abi::Vector { .. } if optimize => { + abi = field.abi.clone(); } + // But scalar pairs are Rust-specific and get + // treated as aggregates by C ABIs anyway. + Abi::ScalarPair(..) => { + abi = field.abi.clone(); + } + _ => {} } } + } - // Two non-ZST fields, and they're both scalars. - ( - Some(( - i, - &TyAndLayout { - layout: &Layout { abi: Abi::Scalar(ref a), .. }, .. - }, - )), - Some(( - j, - &TyAndLayout { - layout: &Layout { abi: Abi::Scalar(ref b), .. }, .. - }, - )), - None, - ) => { - // Order by the memory placement, not source order. - let ((i, a), (j, b)) = if offsets[i] < offsets[j] { - ((i, a), (j, b)) - } else { - ((j, b), (i, a)) - }; - let pair = self.scalar_pair(a.clone(), b.clone()); - let pair_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index, &[0, 1]); - offsets - } - _ => bug!(), - }; - if offsets[i] == pair_offsets[0] - && offsets[j] == pair_offsets[1] - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + // Two non-ZST fields, and they're both scalars. + ( + Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(ref a), .. }, .. })), + Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(ref b), .. }, .. })), + None, + ) => { + // Order by the memory placement, not source order. + let ((i, a), (j, b)) = + if offsets[i] < offsets[j] { ((i, a), (j, b)) } else { ((j, b), (i, a)) }; + let pair = self.scalar_pair(a.clone(), b.clone()); + let pair_offsets = match pair.fields { + FieldsShape::Arbitrary { ref offsets, ref memory_index } => { + assert_eq!(memory_index, &[0, 1]); + offsets } + _ => bug!(), + }; + if offsets[i] == pair_offsets[0] + && offsets[j] == pair_offsets[1] + && align == pair.align + && size == pair.size + { + // We can use `ScalarPair` only when it matches our + // already computed layout (including `#[repr(C)]`). + abi = pair.abi; } - - _ => {} } + + _ => {} } } @@ -495,7 +477,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; debug_assert!(!ty.has_infer_types_or_consts()); - Ok(match ty.kind { + Ok(match *ty.kind() { // Basic scalars. ty::Bool => tcx.intern_layout(Layout::scalar( self, @@ -540,7 +522,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - let metadata = match unsized_part.kind { + let metadata = match unsized_part.kind() { ty::Foreign(..) => { return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr))); } @@ -1259,11 +1241,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.layout_raw(param_env.and(normalized))? } - ty::Bound(..) | ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { + ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { bug!("Layout::compute: unexpected type `{}`", ty) } - ty::Param(_) | ty::Error(_) => { + ty::Bound(..) | ty::Param(_) | ty::Error(_) => { return Err(LayoutError::Unknown(ty)); } }) @@ -1624,7 +1606,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { ); }; - let adt_def = match layout.ty.kind { + let adt_def = match *layout.ty.kind() { ty::Adt(ref adt_def, _) => { debug!("print-type-size t: `{:?}` process adt", layout.ty); adt_def @@ -1767,11 +1749,11 @@ impl<'tcx> SizeSkeleton<'tcx> { Err(err) => err, }; - match ty.kind { + match *ty.kind() { ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { let non_zero = !ty.is_unsafe_ptr(); let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - match tail.kind { + match tail.kind() { ty::Param(_) | ty::Projection(_) => { debug_assert!(tail.has_param_types_or_consts()); Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(&tail) }) @@ -2018,7 +2000,7 @@ where assert_eq!(original_layout.variants, Variants::Single { index }); } - let fields = match this.ty.kind { + let fields = match this.ty.kind() { ty::Adt(def, _) if def.variants.is_empty() => bug!("for_variant called on zero-variant enum"), ty::Adt(def, _) => def.variants[variant_index].fields.len(), @@ -2056,7 +2038,7 @@ where })) }; - cx.layout_of(match this.ty.kind { + cx.layout_of(match *this.ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -2092,7 +2074,7 @@ where )); } - match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind { + match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { ty::Slice(_) | ty::Str => tcx.types.usize, ty::Dynamic(_, _) => { tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3)) @@ -2170,7 +2152,7 @@ where if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA } }; - let pointee_info = match this.ty.kind { + let pointee_info = match *this.ty.kind() { ty::RawPtr(mt) if offset.bytes() == 0 => { cx.layout_of(mt.ty).to_result().ok().map(|layout| PointeeInfo { size: layout.size, @@ -2286,7 +2268,7 @@ where // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = this.ty.kind { + if let ty::Adt(def, _) = this.ty.kind() { if def.is_box() && offset.bytes() == 0 { pointee.safe = Some(PointerKind::UniqueOwned); } @@ -2299,7 +2281,9 @@ where debug!( "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}", - offset, this.ty.kind, pointee_info + offset, + this.ty.kind(), + pointee_info ); pointee_info @@ -2326,14 +2310,14 @@ impl<'tcx> ty::Instance<'tcx> { fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function. let ty = self.ty(tcx, ty::ParamEnv::reveal_all()); - match ty.kind { + match *ty.kind() { ty::FnDef(..) => { // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering // parameters unused if they show up in the signature, but not in the `mir::Body` // (i.e. due to being inside a projection that got normalized, see // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping // track of a polymorphization `ParamEnv` to allow normalizing later. - let mut sig = match ty.kind { + let mut sig = match *ty.kind() { ty::FnDef(def_id, substs) => tcx .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id)) .subst(tcx, substs), @@ -2596,7 +2580,7 @@ where assert!(!sig.c_variadic && extra_args.is_empty()); if let Some(input) = sig.inputs().last() { - if let ty::Tuple(tupled_arguments) = input.kind { + if let ty::Tuple(tupled_arguments) = input.kind() { inputs = &sig.inputs()[0..sig.inputs().len() - 1]; tupled_arguments.iter().map(|k| k.expect_ty()).collect() } else { @@ -2751,6 +2735,7 @@ where can_unwind: fn_can_unwind(cx.tcx().sess.panic_strategy(), codegen_fn_attr_flags, conv), }; fn_abi.adjust_for_abi(cx, sig.abi); + debug!("FnAbi::new_internal = {:?}", fn_abi); fn_abi } @@ -2764,7 +2749,7 @@ where || abi == SpecAbi::RustIntrinsic || abi == SpecAbi::PlatformIntrinsic { - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| { + let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, is_ret: bool| { if arg.is_ignore() { return; } @@ -2802,8 +2787,11 @@ where _ => return, } + let max_by_val_size = + if is_ret { call::max_ret_by_val(cx) } else { Pointer.size(cx) }; let size = arg.layout.size; - if arg.layout.is_unsized() || size > Pointer.size(cx) { + + if arg.layout.is_unsized() || size > max_by_val_size { arg.make_indirect(); } else { // We want to pass small aggregates as immediates, but using @@ -2812,9 +2800,9 @@ where arg.cast_to(Reg { kind: RegKind::Integer, size }); } }; - fixup(&mut self.ret); + fixup(&mut self.ret, true); for arg in &mut self.args { - fixup(arg); + fixup(arg, false); } if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { attrs.set(ArgAttribute::StructRet); diff --git a/src/librustc_middle/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs similarity index 100% rename from src/librustc_middle/ty/list.rs rename to compiler/rustc_middle/src/ty/list.rs diff --git a/src/librustc_middle/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs similarity index 97% rename from src/librustc_middle/ty/mod.rs rename to compiler/rustc_middle/src/ty/mod.rs index a961d02f7a..b7530c077c 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -580,8 +580,12 @@ bitflags! { #[allow(rustc::usage_of_ty_tykind)] pub struct TyS<'tcx> { - pub kind: TyKind<'tcx>, - pub flags: TypeFlags, + /// This field shouldn't be used directly and may be removed in the future. + /// Use `TyS::kind()` instead. + kind: TyKind<'tcx>, + /// This field shouldn't be used directly and may be removed in the future. + /// Use `TyS::flags()` instead. + flags: TypeFlags, /// This is a kind of confusing thing: it stores the smallest /// binder such that @@ -609,13 +613,13 @@ static_assert_size!(TyS<'_>, 32); impl<'tcx> Ord for TyS<'tcx> { fn cmp(&self, other: &TyS<'tcx>) -> Ordering { - self.kind.cmp(&other.kind) + self.kind().cmp(other.kind()) } } impl<'tcx> PartialOrd for TyS<'tcx> { fn partial_cmp(&self, other: &TyS<'tcx>) -> Option { - Some(self.kind.cmp(&other.kind)) + Some(self.kind().cmp(other.kind())) } } @@ -678,25 +682,31 @@ pub enum BorrowKind { /// implicit closure bindings. It is needed when the closure /// is borrowing or mutating a mutable referent, e.g.: /// - /// let x: &mut isize = ...; - /// let y = || *x += 5; + /// ``` + /// let x: &mut isize = ...; + /// let y = || *x += 5; + /// ``` /// /// If we were to try to translate this closure into a more explicit /// form, we'd encounter an error with the code as written: /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` /// /// This is then illegal because you cannot mutate a `&mut` found /// in an aliasable location. To solve, you'd have to translate with /// an `&mut` borrow: /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` /// /// Now the assignment to `**env.x` is legal, but creating a /// mutable pointer to `x` is not because `x` is not mutable. We @@ -721,7 +731,13 @@ pub enum UpvarCapture<'tcx> { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases /// depending on inference. - ByValue, + /// + /// If the upvar was inferred to be captured by value (e.g. `move` + /// was not used), then the `Span` points to a usage that + /// required it. There may be more than one such usage + /// (e.g. `|| { a; a; }`), in which case we pick an + /// arbitrary one. + ByValue(Option), /// Upvar is captured by reference. ByRef(UpvarBorrow<'tcx>), @@ -1145,6 +1161,11 @@ pub enum PredicateAtom<'tcx> { /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), + + /// Represents a type found in the environment that we can use for implied bounds. + /// + /// Only used for Chalk. + TypeWellFormedFromEnv(Ty<'tcx>), } impl<'tcx> PredicateAtom<'tcx> { @@ -1440,7 +1461,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateAtom::ClosureKind(..) | PredicateAtom::TypeOutlives(..) | PredicateAtom::ConstEvaluatable(..) - | PredicateAtom::ConstEquate(..) => None, + | PredicateAtom::ConstEquate(..) + | PredicateAtom::TypeWellFormedFromEnv(..) => None, } } @@ -1455,7 +1477,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateAtom::ObjectSafe(..) | PredicateAtom::ClosureKind(..) | PredicateAtom::ConstEvaluatable(..) - | PredicateAtom::ConstEquate(..) => None, + | PredicateAtom::ConstEquate(..) + | PredicateAtom::TypeWellFormedFromEnv(..) => None, } } } @@ -1728,11 +1751,6 @@ pub struct ParamEnv<'tcx> { /// /// Note: This is packed, use the reveal() method to access it. packed: CopyTaggedPtr<&'tcx List>, traits::Reveal, true>, - - /// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`, - /// register that `def_id` (useful for transitioning to the chalk trait - /// solver). - pub def_id: Option, } unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal { @@ -1757,7 +1775,6 @@ impl<'tcx> fmt::Debug for ParamEnv<'tcx> { f.debug_struct("ParamEnv") .field("caller_bounds", &self.caller_bounds()) .field("reveal", &self.reveal()) - .field("def_id", &self.def_id) .finish() } } @@ -1766,23 +1783,16 @@ impl<'a, 'tcx> HashStable> for ParamEnv<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.caller_bounds().hash_stable(hcx, hasher); self.reveal().hash_stable(hcx, hasher); - self.def_id.hash_stable(hcx, hasher); } } impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - ParamEnv::new( - self.caller_bounds().fold_with(folder), - self.reveal().fold_with(folder), - self.def_id.fold_with(folder), - ) + ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.caller_bounds().visit_with(visitor) - || self.reveal().visit_with(visitor) - || self.def_id.visit_with(visitor) + self.caller_bounds().visit_with(visitor) || self.reveal().visit_with(visitor) } } @@ -1793,7 +1803,7 @@ impl<'tcx> ParamEnv<'tcx> { /// type-checking. #[inline] pub fn empty() -> Self { - Self::new(List::empty(), Reveal::UserFacing, None) + Self::new(List::empty(), Reveal::UserFacing) } #[inline] @@ -1815,17 +1825,13 @@ impl<'tcx> ParamEnv<'tcx> { /// or invoke `param_env.with_reveal_all()`. #[inline] pub fn reveal_all() -> Self { - Self::new(List::empty(), Reveal::All, None) + Self::new(List::empty(), Reveal::All) } /// Construct a trait environment with the given set of predicates. #[inline] - pub fn new( - caller_bounds: &'tcx List>, - reveal: Reveal, - def_id: Option, - ) -> Self { - ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal), def_id } + pub fn new(caller_bounds: &'tcx List>, reveal: Reveal) -> Self { + ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) } } pub fn with_user_facing(mut self) -> Self { @@ -1847,12 +1853,12 @@ impl<'tcx> ParamEnv<'tcx> { return self; } - ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All, self.def_id) + ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All) } /// Returns this same environment but with no caller bounds. pub fn without_caller_bounds(self) -> Self { - Self::new(List::empty(), self.reveal(), self.def_id) + Self::new(List::empty(), self.reveal()) } /// Creates a suitable environment in which to perform trait @@ -1971,6 +1977,9 @@ bitflags! { const NO_VARIANT_FLAGS = 0; /// Indicates whether the field list of this variant is `#[non_exhaustive]`. const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0; + /// Indicates whether this variant was obtained as part of recovering from + /// a syntactic error. May be incomplete or bogus. + const IS_RECOVERED = 1 << 1; } } @@ -1994,12 +2003,9 @@ pub struct VariantDef { pub ctor_kind: CtorKind, /// Flags of the variant (e.g. is field list non-exhaustive)? flags: VariantFlags, - /// Variant is obtained as part of recovering from a syntactic error. - /// May be incomplete or bogus. - pub recovered: bool, } -impl<'tcx> VariantDef { +impl VariantDef { /// Creates a new `VariantDef`. /// /// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef` @@ -2039,6 +2045,10 @@ impl<'tcx> VariantDef { flags |= VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; } + if recovered { + flags |= VariantFlags::IS_RECOVERED; + } + VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor_def_id, @@ -2047,7 +2057,6 @@ impl<'tcx> VariantDef { fields, ctor_kind, flags, - recovered, } } @@ -2057,17 +2066,10 @@ impl<'tcx> VariantDef { self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) } - /// `repr(transparent)` structs can have a single non-ZST field, this function returns that - /// field. - pub fn transparent_newtype_field(&self, tcx: TyCtxt<'tcx>) -> Option<&FieldDef> { - for field in &self.fields { - let field_ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.def_id)); - if !field_ty.is_zst(tcx, self.def_id) { - return Some(field); - } - } - - None + /// Was this variant obtained as part of recovering from a syntactic error? + #[inline] + pub fn is_recovered(&self) -> bool { + self.flags.intersects(VariantFlags::IS_RECOVERED) } } @@ -2676,7 +2678,7 @@ impl<'tcx> ClosureKind { } } - /// Returns `true` if this a type that impls this closure kind + /// Returns `true` if a type that impls this closure kind /// must also implement `other`. pub fn extends(self, other: ty::ClosureKind) -> bool { match (self, other) { @@ -3086,6 +3088,7 @@ pub fn provide(providers: &mut ty::query::Providers) { erase_regions::provide(providers); layout::provide(providers); util::provide(providers); + print::provide(providers); super::util::bug::provide(providers); *providers = ty::query::Providers { trait_impls_of: trait_def::trait_impls_of_provider, diff --git a/src/librustc_middle/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs similarity index 100% rename from src/librustc_middle/ty/normalize_erasing_regions.rs rename to compiler/rustc_middle/src/ty/normalize_erasing_regions.rs diff --git a/src/librustc_middle/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs similarity index 99% rename from src/librustc_middle/ty/outlives.rs rename to compiler/rustc_middle/src/ty/outlives.rs index 07a0bcc0c4..ca992d36e9 100644 --- a/src/librustc_middle/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -3,8 +3,8 @@ // RFC for reference. use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::walk::MiniSet; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_data_structures::mini_set::MiniSet; use smallvec::SmallVec; #[derive(Debug)] @@ -68,7 +68,7 @@ fn compute_components( // with `collect()` because of the need to sometimes skip subtrees // in the `subtys` iterator (e.g., when encountering a // projection). - match ty.kind { + match *ty.kind() { ty::FnDef(_, substs) => { // HACK(eddyb) ignore lifetimes found shallowly in `substs`. // This is inconsistent with `ty::Adt` (including all substs) diff --git a/src/librustc_middle/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs similarity index 99% rename from src/librustc_middle/ty/print/mod.rs rename to compiler/rustc_middle/src/ty/print/mod.rs index 981e013683..225ea2399f 100644 --- a/src/librustc_middle/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -2,16 +2,14 @@ use crate::ty::subst::{GenericArg, Subst}; use crate::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::mini_set::MiniSet; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::ty::walk::MiniSet; // `pretty` is a separate module only for organization. mod pretty; pub use self::pretty::*; -pub mod obsolete; - // FIXME(eddyb) false positive, the lifetime parameters are used with `P: Printer<...>`. #[allow(unused_lifetimes)] pub trait Print<'tcx, P> { @@ -273,7 +271,7 @@ fn characteristic_def_id_of_type_cached<'a>( ty: Ty<'a>, visited: &mut MiniSet>, ) -> Option { - match ty.kind { + match *ty.kind() { ty::Adt(adt_def, _) => Some(adt_def.did), ty::Dynamic(data, ..) => data.principal_def_id(), diff --git a/src/librustc_middle/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs similarity index 87% rename from src/librustc_middle/ty/print/pretty.rs rename to compiler/rustc_middle/src/ty/print/pretty.rs index a29e0b0000..7b5cf681f3 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -7,10 +7,13 @@ use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_ast as ast; use rustc_attr::{SignedInt, UnsignedInt}; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, DefKind, Namespace}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; +use rustc_hir::ItemKind; +use rustc_session::config::TrimmedDefPaths; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_target::abi::{Integer, Size}; use rustc_target::spec::abi::Abi; @@ -52,6 +55,7 @@ macro_rules! define_scoped_cx { thread_local! { static FORCE_IMPL_FILENAME_LINE: Cell = Cell::new(false); static SHOULD_PREFIX_WITH_CRATE: Cell = Cell::new(false); + static NO_TRIMMED_PATH: Cell = Cell::new(false); static NO_QUERIES: Cell = Cell::new(false); } @@ -94,6 +98,18 @@ pub fn with_crate_prefix R, R>(f: F) -> R { }) } +/// Prevent path trimming if it is turned on. Path trimming affects `Display` impl +/// of various rustc types, for example `std::vec::Vec` would be trimmed to `Vec`, +/// if no other `Vec` is found. +pub fn with_no_trimmed_paths R, R>(f: F) -> R { + NO_TRIMMED_PATH.with(|flag| { + let old = flag.replace(true); + let result = f(); + flag.set(old); + result + }) +} + /// The "region highlights" are used to control region printing during /// specific error messages. When a "region highlight" is enabled, it /// gives an alternate way to print specific regions. For now, we @@ -243,6 +259,28 @@ pub trait PrettyPrinter<'tcx>: self.try_print_visible_def_path_recur(def_id, &mut callers) } + /// Try to see if this path can be trimmed to a unique symbol name. + fn try_print_trimmed_def_path( + mut self, + def_id: DefId, + ) -> Result<(Self::Path, bool), Self::Error> { + if !self.tcx().sess.opts.debugging_opts.trim_diagnostic_paths + || matches!(self.tcx().sess.opts.trimmed_def_paths, TrimmedDefPaths::Never) + || NO_TRIMMED_PATH.with(|flag| flag.get()) + || SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) + { + return Ok((self, false)); + } + + match self.tcx().trimmed_def_paths(LOCAL_CRATE).get(&def_id) { + None => Ok((self, false)), + Some(symbol) => { + self.write_str(&symbol.as_str())?; + Ok((self, true)) + } + } + } + /// Does the work of `try_print_visible_def_path`, building the /// full definition path recursively before attempting to /// post-process it into the valid and visible version that @@ -419,7 +457,7 @@ pub trait PrettyPrinter<'tcx>: // Inherent impls. Try to print `Foo::bar` for an inherent // impl on `Foo`, but fallback to `::bar` if self-type is // anything other than a simple path. - match self_ty.kind { + match self_ty.kind() { ty::Adt(..) | ty::Foreign(_) | ty::Bool @@ -470,7 +508,7 @@ pub trait PrettyPrinter<'tcx>: fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result { define_scoped_cx!(self); - match ty.kind { + match *ty.kind() { ty::Bool => p!(write("bool")), ty::Char => p!(write("char")), ty::Int(t) => p!(write("{}", t.name_str())), @@ -603,42 +641,35 @@ pub trait PrettyPrinter<'tcx>: } ty::Str => p!(write("str")), ty::Generator(did, substs, movability) => { + p!(write("[")); match movability { - hir::Movability::Movable => p!(write("[generator")), - hir::Movability::Static => p!(write("[static generator")), + hir::Movability::Movable => {} + hir::Movability::Static => p!(write("static ")), } - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - let hir_id = self.tcx().hir().local_def_id_to_hir_id(did); - let span = self.tcx().hir().span(hir_id); - p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); - - if substs.as_generator().is_valid() { - let upvar_tys = substs.as_generator().upvar_tys(); - let mut sep = " "; - for (&var_id, upvar_ty) in self - .tcx() - .upvars_mentioned(did) - .as_ref() - .iter() - .flat_map(|v| v.keys()) - .zip(upvar_tys) - { - p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty)); - sep = ", "; - } + if !self.tcx().sess.verbose() { + p!(write("generator")); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { + let hir_id = self.tcx().hir().local_def_id_to_hir_id(did); + let span = self.tcx().hir().span(hir_id); + p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); + } else { + p!(write("@{}", self.tcx().def_path_str(did))); } } else { - p!(write("@{}", self.tcx().def_path_str(did))); - + p!(print_def_path(did, substs)); if substs.as_generator().is_valid() { - let upvar_tys = substs.as_generator().upvar_tys(); - let mut sep = " "; - for (index, upvar_ty) in upvar_tys.enumerate() { - p!(write("{}{}:", sep, index), print(upvar_ty)); - sep = ", "; + // Search for the first inference variable + p!(write(" upvar_tys=(")); + let mut uninferred_ty = + substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer()); + if uninferred_ty.next().is_some() { + p!(write("unavailable")); + } else { + self = self.comma_sep(substs.as_generator().upvar_tys())?; } + p!(write(")")); } } @@ -646,61 +677,50 @@ pub trait PrettyPrinter<'tcx>: p!(write(" "), print(substs.as_generator().witness())); } - p!(write("]")) + p!(write("]")); } ty::GeneratorWitness(types) => { p!(in_binder(&types)); } ty::Closure(did, substs) => { - p!(write("[closure")); - - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - let hir_id = self.tcx().hir().local_def_id_to_hir_id(did); - if self.tcx().sess.opts.debugging_opts.span_free_formats { - p!(write("@"), print_def_path(did.to_def_id(), substs)); - } else { - let span = self.tcx().hir().span(hir_id); - p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); - } - - if substs.as_closure().is_valid() { - let upvar_tys = substs.as_closure().upvar_tys(); - let mut sep = " "; - for (&var_id, upvar_ty) in self - .tcx() - .upvars_mentioned(did) - .as_ref() - .iter() - .flat_map(|v| v.keys()) - .zip(upvar_tys) - { - p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty)); - sep = ", "; + p!(write("[")); + if !self.tcx().sess.verbose() { + p!(write("closure")); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { + let hir_id = self.tcx().hir().local_def_id_to_hir_id(did); + if self.tcx().sess.opts.debugging_opts.span_free_formats { + p!(write("@"), print_def_path(did.to_def_id(), substs)); + } else { + let span = self.tcx().hir().span(hir_id); + p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); } + } else { + p!(write("@{}", self.tcx().def_path_str(did))); } } else { - p!(write("@{}", self.tcx().def_path_str(did))); - + p!(print_def_path(did, substs)); if substs.as_closure().is_valid() { - let upvar_tys = substs.as_closure().upvar_tys(); - let mut sep = " "; - for (index, upvar_ty) in upvar_tys.enumerate() { - p!(write("{}{}:", sep, index), print(upvar_ty)); - sep = ", "; + // Search for the first inference variable + let mut uninferred_ty = + substs.as_closure().upvar_tys().filter(|ty| ty.is_ty_infer()); + if uninferred_ty.next().is_some() { + // If the upvar substs contain an inference variable we haven't + // finished capture analysis. + p!(write(" closure_substs=(unavailable)")); + } else { + p!(write(" closure_kind_ty="), print(substs.as_closure().kind_ty())); + p!( + write(" closure_sig_as_fn_ptr_ty="), + print(substs.as_closure().sig_as_fn_ptr_ty()) + ); + p!(write(" upvar_tys=(")); + self = self.comma_sep(substs.as_closure().upvar_tys())?; + p!(write(")")); } } } - - if self.tcx().sess.verbose() && substs.as_closure().is_valid() { - p!(write(" closure_kind_ty="), print(substs.as_closure().kind_ty())); - p!( - write(" closure_sig_as_fn_ptr_ty="), - print(substs.as_closure().sig_as_fn_ptr_ty()) - ); - } - - p!(write("]")) + p!(write("]")); } ty::Array(ty, sz) => { p!(write("["), print(ty), write("; ")); @@ -759,7 +779,7 @@ pub trait PrettyPrinter<'tcx>: // Special-case `Fn(...) -> ...` and resugar it. let fn_trait_kind = self.tcx().fn_trait_kind_from_lang_item(principal.def_id); if !self.tcx().sess.verbose() && fn_trait_kind.is_some() { - if let ty::Tuple(ref args) = principal.substs.type_at(0).kind { + if let ty::Tuple(ref args) = principal.substs.type_at(0).kind() { let mut projections = predicates.projection_bounds(); if let (Some(proj), None) = (projections.next(), projections.next()) { let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); @@ -938,7 +958,7 @@ pub trait PrettyPrinter<'tcx>: ) -> Result { define_scoped_cx!(self); - match (scalar, &ty.kind) { + match (scalar, &ty.kind()) { // Byte strings (&[u8; N]) ( Scalar::Ptr(ptr), @@ -1098,7 +1118,7 @@ pub trait PrettyPrinter<'tcx>: let u8_type = self.tcx().types.u8; - match (ct, &ty.kind) { + match (ct, ty.kind()) { // Byte/string slices, printed as (byte) string literals. ( ConstValue::Slice { data, start, end }, @@ -1151,7 +1171,7 @@ pub trait PrettyPrinter<'tcx>: ); let fields = contents.fields.iter().copied(); - match ty.kind { + match *ty.kind() { ty::Array(..) => { p!(write("["), comma_sep(fields), write("]")); } @@ -1326,6 +1346,11 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { define_scoped_cx!(self); if substs.is_empty() { + match self.try_print_trimmed_def_path(def_id)? { + (cx, true) => return Ok(cx), + (cx, false) => self = cx, + } + match self.try_print_visible_def_path(def_id)? { (cx, true) => return Ok(cx), (cx, false) => self = cx, @@ -1455,25 +1480,21 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { // FIXME(eddyb) `name` should never be empty, but it // currently is for `extern { ... }` "foreign modules". - let name = disambiguated_data.data.as_symbol(); - if name != kw::Invalid { + let name = disambiguated_data.data.name(); + if name != DefPathDataName::Named(kw::Invalid) { if !self.empty_path { write!(self, "::")?; } - if Ident::with_dummy_span(name).is_raw_guess() { - write!(self, "r#")?; - } - write!(self, "{}", name)?; - // FIXME(eddyb) this will print e.g. `{{closure}}#3`, but it - // might be nicer to use something else, e.g. `{closure#3}`. - let dis = disambiguated_data.disambiguator; - let print_dis = disambiguated_data.data.get_opt_name().is_none() - || dis != 0 && self.tcx.sess.verbose(); - if print_dis { - write!(self, "#{}", dis)?; + if let DefPathDataName::Named(name) = name { + if Ident::with_dummy_span(name).is_raw_guess() { + write!(self, "r#")?; + } } + let verbose = self.tcx.sess.verbose(); + disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?; + self.empty_path = false; } @@ -2061,6 +2082,11 @@ define_print_and_forward_display! { print(c2), write("`")) } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + p!(write("the type `"), + print(ty), + write("` is found in the environment")) + } } } @@ -2072,3 +2098,127 @@ define_print_and_forward_display! { } } } + +fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) { + // Iterate all local crate items no matter where they are defined. + let hir = tcx.hir(); + for item in hir.krate().items.values() { + if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) { + continue; + } + + if let Some(local_def_id) = hir.definitions().opt_hir_id_to_local_def_id(item.hir_id) { + let def_id = local_def_id.to_def_id(); + let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS); + collect_fn(&item.ident, ns, def_id); + } + } + + // Now take care of extern crate items. + let queue = &mut Vec::new(); + let mut seen_defs: DefIdSet = Default::default(); + + for &cnum in tcx.crates().iter() { + let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; + + // Ignore crates that are not direct dependencies. + match tcx.extern_crate(def_id) { + None => continue, + Some(extern_crate) => { + if !extern_crate.is_direct() { + continue; + } + } + } + + queue.push(def_id); + } + + // Iterate external crate defs but be mindful about visibility + while let Some(def) = queue.pop() { + for child in tcx.item_children(def).iter() { + if child.vis != ty::Visibility::Public { + continue; + } + + match child.res { + def::Res::Def(DefKind::AssocTy, _) => {} + def::Res::Def(defkind, def_id) => { + if let Some(ns) = defkind.ns() { + collect_fn(&child.ident, ns, def_id); + } + + if seen_defs.insert(def_id) { + queue.push(def_id); + } + } + _ => {} + } + } + } +} + +/// The purpose of this function is to collect public symbols names that are unique across all +/// crates in the build. Later, when printing about types we can use those names instead of the +/// full exported path to them. +/// +/// So essentially, if a symbol name can only be imported from one place for a type, and as +/// long as it was not glob-imported anywhere in the current crate, we can trim its printed +/// path and print only the name. +/// +/// This has wide implications on error messages with types, for example, shortening +/// `std::vec::Vec` to just `Vec`, as long as there is no other `Vec` importable anywhere. +/// +/// The implementation uses similar import discovery logic to that of 'use' suggestions. +fn trimmed_def_paths(tcx: TyCtxt<'_>, crate_num: CrateNum) -> FxHashMap { + assert_eq!(crate_num, LOCAL_CRATE); + + let mut map = FxHashMap::default(); + + if let TrimmedDefPaths::GoodPath = tcx.sess.opts.trimmed_def_paths { + // For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths` + // wrapper can be used to suppress this query, in exchange for full paths being formatted. + tcx.sess.delay_good_path_bug("trimmed_def_paths constructed"); + } + + let unique_symbols_rev: &mut FxHashMap<(Namespace, Symbol), Option> = + &mut FxHashMap::default(); + + for symbol_set in tcx.glob_map.values() { + for symbol in symbol_set { + unique_symbols_rev.insert((Namespace::TypeNS, *symbol), None); + unique_symbols_rev.insert((Namespace::ValueNS, *symbol), None); + unique_symbols_rev.insert((Namespace::MacroNS, *symbol), None); + } + } + + for_each_def(tcx, |ident, ns, def_id| { + use std::collections::hash_map::Entry::{Occupied, Vacant}; + + match unique_symbols_rev.entry((ns, ident.name)) { + Occupied(mut v) => match v.get() { + None => {} + Some(existing) => { + if *existing != def_id { + v.insert(None); + } + } + }, + Vacant(v) => { + v.insert(Some(def_id)); + } + } + }); + + for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() { + if let Some(def_id) = opt_def_id { + map.insert(def_id, symbol); + } + } + + map +} + +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { trimmed_def_paths, ..*providers }; +} diff --git a/src/librustc_middle/ty/query/README.md b/compiler/rustc_middle/src/ty/query/README.md similarity index 100% rename from src/librustc_middle/ty/query/README.md rename to compiler/rustc_middle/src/ty/query/README.md diff --git a/src/librustc_middle/ty/query/job.rs b/compiler/rustc_middle/src/ty/query/job.rs similarity index 100% rename from src/librustc_middle/ty/query/job.rs rename to compiler/rustc_middle/src/ty/query/job.rs diff --git a/src/librustc_middle/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs similarity index 95% rename from src/librustc_middle/ty/query/keys.rs rename to compiler/rustc_middle/src/ty/query/keys.rs index 3f7a20bba2..a005990264 100644 --- a/src/librustc_middle/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -193,6 +193,22 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { } } +impl<'tcx> Key + for ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>), + ) +{ + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + (self.0).0.did.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + (self.0).0.did.default_span(tcx) + } +} + impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector; diff --git a/src/librustc_middle/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs similarity index 99% rename from src/librustc_middle/ty/query/mod.rs rename to compiler/rustc_middle/src/ty/query/mod.rs index ee9b203b15..d3a7412ef1 100644 --- a/src/librustc_middle/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -14,7 +14,7 @@ use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLife use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult, ConstValue}; +use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult}; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::traits::query::{ diff --git a/src/librustc_middle/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs similarity index 99% rename from src/librustc_middle/ty/query/on_disk_cache.rs rename to compiler/rustc_middle/src/ty/query/on_disk_cache.rs index dcfb8d3143..b0c48a860e 100644 --- a/src/librustc_middle/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -760,6 +760,12 @@ impl<'a, 'tcx> Decodable> } } +impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { + RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { RefDecodable::decode(d) diff --git a/src/librustc_middle/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs similarity index 100% rename from src/librustc_middle/ty/query/plumbing.rs rename to compiler/rustc_middle/src/ty/query/plumbing.rs diff --git a/src/librustc_middle/ty/query/profiling_support.rs b/compiler/rustc_middle/src/ty/query/profiling_support.rs similarity index 97% rename from src/librustc_middle/ty/query/profiling_support.rs rename to compiler/rustc_middle/src/ty/query/profiling_support.rs index 9b1837356e..4e8db3194b 100644 --- a/src/librustc_middle/ty/query/profiling_support.rs +++ b/compiler/rustc_middle/src/ty/query/profiling_support.rs @@ -55,18 +55,22 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { }; let dis_buffer = &mut [0u8; 16]; + let crate_name; + let other_name; let name; let dis; let end_index; match def_key.disambiguated_data.data { DefPathData::CrateRoot => { - name = self.tcx.original_crate_name(def_id.krate); + crate_name = self.tcx.original_crate_name(def_id.krate).as_str(); + name = &*crate_name; dis = ""; end_index = 3; } other => { - name = other.as_symbol(); + other_name = other.to_string(); + name = other_name.as_str(); if def_key.disambiguated_data.disambiguator == 0 { dis = ""; end_index = 3; @@ -80,7 +84,6 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { } } - let name = &*name.as_str(); let components = [ StringComponent::Ref(parent_string_id), StringComponent::Value("::"), diff --git a/src/librustc_middle/ty/query/stats.rs b/compiler/rustc_middle/src/ty/query/stats.rs similarity index 100% rename from src/librustc_middle/ty/query/stats.rs rename to compiler/rustc_middle/src/ty/query/stats.rs diff --git a/src/librustc_middle/ty/query/values.rs b/compiler/rustc_middle/src/ty/query/values.rs similarity index 100% rename from src/librustc_middle/ty/query/values.rs rename to compiler/rustc_middle/src/ty/query/values.rs diff --git a/src/librustc_middle/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs similarity index 97% rename from src/librustc_middle/ty/relate.rs rename to compiler/rustc_middle/src/ty/relate.rs index ae2820b460..c4df0bba72 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -325,7 +325,7 @@ pub fn super_relate_tys>( ) -> RelateResult<'tcx, Ty<'tcx>> { let tcx = relation.tcx(); debug!("super_relate_tys: a={:?} b={:?}", a, b); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { // The caller should handle these cases! bug!("var types encountered in super_relate_tys") @@ -516,7 +516,7 @@ pub fn super_relate_consts>( (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => { if a_val == b_val { Ok(ConstValue::Scalar(a_val)) - } else if let ty::FnPtr(_) = a.ty.kind { + } else if let ty::FnPtr(_) = a.ty.kind() { let a_instance = tcx.global_alloc(a_val.assert_ptr().alloc_id).unwrap_fn(); let b_instance = tcx.global_alloc(b_val.assert_ptr().alloc_id).unwrap_fn(); if a_instance == b_instance { @@ -540,7 +540,7 @@ pub fn super_relate_consts>( } (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { - match a.ty.kind { + match a.ty.kind() { ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { let a_destructured = tcx.destructure_const(relation.param_env().and(a)); let b_destructured = tcx.destructure_const(relation.param_env().and(b)); @@ -576,7 +576,20 @@ pub fn super_relate_consts>( new_val.map(ty::ConstKind::Value) } - // FIXME(const_generics): this is wrong, as it is a projection + ( + ty::ConstKind::Unevaluated(a_def, a_substs, None), + ty::ConstKind::Unevaluated(b_def, b_substs, None), + ) if tcx.features().const_evaluatable_checked => { + if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { + Ok(a.val) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, a, b))) + } + } + + // While this is slightly incorrect, it shouldn't matter for `min_const_generics` + // and is the better alternative to waiting until `const_evaluatable_checked` can + // be stabilized. ( ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted), ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted), diff --git a/src/librustc_middle/ty/steal.rs b/compiler/rustc_middle/src/ty/steal.rs similarity index 100% rename from src/librustc_middle/ty/steal.rs rename to compiler/rustc_middle/src/ty/steal.rs diff --git a/src/librustc_middle/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs similarity index 96% rename from src/librustc_middle/ty/structural_impls.rs rename to compiler/rustc_middle/src/ty/structural_impls.rs index 605e3545de..597ceac938 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -5,7 +5,7 @@ use crate::mir::interpret; use crate::mir::ProjectionKind; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::print::{FmtPrinter, Printer}; +use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::{self, InferConst, Lift, Ty, TyCtxt}; use rustc_hir as hir; use rustc_hir::def::Namespace; @@ -20,7 +20,9 @@ use std::sync::Arc; impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { - FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.def_id, &[])?; + with_no_trimmed_paths(|| { + FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.def_id, &[]) + })?; Ok(()) }) } @@ -29,7 +31,9 @@ impl fmt::Debug for ty::TraitDef { impl fmt::Debug for ty::AdtDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { - FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.did, &[])?; + with_no_trimmed_paths(|| { + FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.did, &[]) + })?; Ok(()) }) } @@ -50,7 +54,7 @@ impl fmt::Debug for ty::UpvarBorrow<'tcx> { impl fmt::Debug for ty::ExistentialTraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) + with_no_trimmed_paths(|| fmt::Display::fmt(self, f)) } } @@ -183,13 +187,13 @@ impl fmt::Debug for ty::FloatVarValue { impl fmt::Debug for ty::TraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) + with_no_trimmed_paths(|| fmt::Display::fmt(self, f)) } } impl fmt::Debug for Ty<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) + with_no_trimmed_paths(|| fmt::Display::fmt(self, f)) } } @@ -256,6 +260,9 @@ impl fmt::Debug for ty::PredicateAtom<'tcx> { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::PredicateAtom::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + write!(f, "TypeWellFormedFromEnv({:?})", ty) + } } } } @@ -532,6 +539,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> { ty::PredicateAtom::ConstEquate(c1, c2) => { tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateAtom::ConstEquate(c1, c2)) } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + tcx.lift(&ty).map(ty::PredicateAtom::TypeWellFormedFromEnv) + } } } } @@ -547,7 +557,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { type Lifted = ty::ParamEnv<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { tcx.lift(&self.caller_bounds()) - .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.def_id)) + .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal())) } } @@ -602,8 +612,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { 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 }) + tcx.lift(&self.region).map(|region| ty::adjustment::OverloadedDeref { + region, + mutbl: self.mutbl, + span: self.span, + }) } } @@ -676,6 +689,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { 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), Sorts(ref x) => return tcx.lift(x).map(Sorts), ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), @@ -919,25 +933,25 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - let kind = match self.kind { + let kind = match self.kind() { ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)), ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), ty::Slice(typ) => ty::Slice(typ.fold_with(folder)), - ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)), + ty::Adt(tid, substs) => ty::Adt(*tid, substs.fold_with(folder)), ty::Dynamic(ref trait_ty, ref region) => { ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder)) } ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)), - ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)), + ty::FnDef(def_id, substs) => ty::FnDef(*def_id, substs.fold_with(folder)), ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)), - ty::Ref(ref r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl), + ty::Ref(ref r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), *mutbl), ty::Generator(did, substs, movability) => { - ty::Generator(did, substs.fold_with(folder), movability) + ty::Generator(*did, substs.fold_with(folder), *movability) } ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)), - ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)), + ty::Closure(did, substs) => ty::Closure(*did, substs.fold_with(folder)), ty::Projection(ref data) => ty::Projection(data.fold_with(folder)), - ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)), + ty::Opaque(did, substs) => ty::Opaque(*did, substs.fold_with(folder)), ty::Bool | ty::Char @@ -954,7 +968,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { | ty::Foreign(..) => return self, }; - if self.kind == kind { self } else { folder.tcx().mk_ty(kind) } + if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) } } fn fold_with>(&self, folder: &mut F) -> Self { @@ -962,7 +976,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - match self.kind { + match self.kind() { ty::RawPtr(ref tm) => tm.visit_with(visitor), ty::Array(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor), ty::Slice(typ) => typ.visit_with(visitor), diff --git a/src/librustc_middle/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs similarity index 95% rename from src/librustc_middle/ty/sty.rs rename to compiler/rustc_middle/src/ty/sty.rs index c1f354c7a1..724ec101b2 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -367,7 +367,8 @@ impl<'tcx> ClosureSubsts<'tcx> { /// Used primarily by `ty::print::pretty` to be able to handle closure /// types that haven't had their synthetic types substituted in. pub fn is_valid(self) -> bool { - self.substs.len() >= 3 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_)) + self.substs.len() >= 3 + && matches!(self.split().tupled_upvars_ty.expect_ty().kind(), Tuple(_)) } /// Returns the substitutions of the closure's parent. @@ -414,9 +415,9 @@ impl<'tcx> ClosureSubsts<'tcx> { /// Extracts the signature from the closure. pub fn sig(self) -> ty::PolyFnSig<'tcx> { let ty = self.sig_as_fn_ptr_ty(); - match ty.kind { - ty::FnPtr(sig) => sig, - _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind), + match ty.kind() { + ty::FnPtr(sig) => *sig, + _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()), } } } @@ -484,7 +485,8 @@ impl<'tcx> GeneratorSubsts<'tcx> { /// Used primarily by `ty::print::pretty` to be able to handle generator /// types that haven't had their synthetic types substituted in. pub fn is_valid(self) -> bool { - self.substs.len() >= 5 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_)) + self.substs.len() >= 5 + && matches!(self.split().tupled_upvars_ty.expect_ty().kind(), Tuple(_)) } /// Returns the substitutions of the generator's parent. @@ -1231,13 +1233,13 @@ rustc_index::newtype_index! { /// particular, imagine a type like this: /// /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) - /// ^ ^ | | | - /// | | | | | - /// | +------------+ 0 | | - /// | | | - /// +--------------------------------+ 1 | - /// | | - /// +------------------------------------------+ 0 + /// ^ ^ | | | + /// | | | | | + /// | +------------+ 0 | | + /// | | | + /// +----------------------------------+ 1 | + /// | | + /// +----------------------------------------------+ 0 /// /// In this type, there are two binders (the outer fn and the inner /// fn). We need to be able to determine, for any given region, which @@ -1741,9 +1743,19 @@ impl RegionKind { /// Type utilities impl<'tcx> TyS<'tcx> { + #[inline(always)] + pub fn kind(&self) -> &TyKind<'tcx> { + &self.kind + } + + #[inline(always)] + pub fn flags(&self) -> TypeFlags { + self.flags + } + #[inline] pub fn is_unit(&self) -> bool { - match self.kind { + match self.kind() { Tuple(ref tys) => tys.is_empty(), _ => false, } @@ -1751,7 +1763,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_never(&self) -> bool { - match self.kind { + match self.kind() { Never => true, _ => false, } @@ -1766,7 +1778,7 @@ impl<'tcx> TyS<'tcx> { pub fn conservative_is_privately_uninhabited(&self, tcx: TyCtxt<'tcx>) -> bool { // FIXME(varkor): we can make this less conversative by substituting concrete // type arguments. - match self.kind { + match self.kind() { ty::Never => true, ty::Adt(def, _) if def.is_union() => { // For now, `union`s are never considered uninhabited. @@ -1806,12 +1818,28 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_primitive(&self) -> bool { - self.kind.is_primitive() + self.kind().is_primitive() + } + + #[inline] + pub fn is_adt(&self) -> bool { + match self.kind() { + Adt(..) => true, + _ => false, + } + } + + #[inline] + pub fn is_ref(&self) -> bool { + match self.kind() { + Ref(..) => true, + _ => false, + } } #[inline] pub fn is_ty_var(&self) -> bool { - match self.kind { + match self.kind() { Infer(TyVar(_)) => true, _ => false, } @@ -1819,7 +1847,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_ty_infer(&self) -> bool { - match self.kind { + match self.kind() { Infer(_) => true, _ => false, } @@ -1827,23 +1855,23 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_phantom_data(&self) -> bool { - if let Adt(def, _) = self.kind { def.is_phantom_data() } else { false } + if let Adt(def, _) = self.kind() { def.is_phantom_data() } else { false } } #[inline] pub fn is_bool(&self) -> bool { - self.kind == Bool + *self.kind() == Bool } /// Returns `true` if this type is a `str`. #[inline] pub fn is_str(&self) -> bool { - self.kind == Str + *self.kind() == Str } #[inline] pub fn is_param(&self, index: u32) -> bool { - match self.kind { + match self.kind() { ty::Param(ref data) => data.index == index, _ => false, } @@ -1851,8 +1879,8 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_slice(&self) -> bool { - match self.kind { - RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.kind { + match self.kind() { + RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.kind() { Slice(_) | Str => true, _ => false, }, @@ -1860,16 +1888,24 @@ impl<'tcx> TyS<'tcx> { } } + #[inline] + pub fn is_array(&self) -> bool { + match self.kind() { + Array(..) => true, + _ => false, + } + } + #[inline] pub fn is_simd(&self) -> bool { - match self.kind { + match self.kind() { Adt(def, _) => def.repr.simd(), _ => false, } } pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind { + match self.kind() { Array(ty, _) | Slice(ty) => ty, Str => tcx.mk_mach_uint(ast::UintTy::U8), _ => bug!("`sequence_element_type` called on non-sequence value: {}", self), @@ -1877,7 +1913,7 @@ impl<'tcx> TyS<'tcx> { } pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind { + match self.kind() { Adt(def, substs) => def.non_enum_variant().fields[0].ty(tcx, substs), _ => bug!("`simd_type` called on invalid type"), } @@ -1886,14 +1922,14 @@ impl<'tcx> TyS<'tcx> { pub fn simd_size(&self, _tcx: TyCtxt<'tcx>) -> u64 { // Parameter currently unused, but probably needed in the future to // allow `#[repr(simd)] struct Simd([T; N]);`. - match self.kind { + match self.kind() { Adt(def, _) => def.non_enum_variant().fields.len() as u64, _ => bug!("`simd_size` called on invalid type"), } } pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { - match self.kind { + match self.kind() { Adt(def, substs) => { let variant = def.non_enum_variant(); (variant.fields.len() as u64, variant.fields[0].ty(tcx, substs)) @@ -1904,7 +1940,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_region_ptr(&self) -> bool { - match self.kind { + match self.kind() { Ref(..) => true, _ => false, } @@ -1912,7 +1948,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_mutable_ptr(&self) -> bool { - match self.kind { + match self.kind() { RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. }) | Ref(_, _, hir::Mutability::Mut) => true, _ => false, @@ -1921,7 +1957,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_unsafe_ptr(&self) -> bool { - match self.kind { + match self.kind() { RawPtr(_) => true, _ => false, } @@ -1935,7 +1971,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_box(&self) -> bool { - match self.kind { + match self.kind() { Adt(def, _) => def.is_box(), _ => false, } @@ -1943,7 +1979,7 @@ impl<'tcx> TyS<'tcx> { /// Panics if called on any type other than `Box`. pub fn boxed_ty(&self) -> Ty<'tcx> { - match self.kind { + match self.kind() { Adt(def, substs) if def.is_box() => substs.type_at(0), _ => bug!("`boxed_ty` is called on non-box type {:?}", self), } @@ -1954,7 +1990,7 @@ impl<'tcx> TyS<'tcx> { /// contents are abstract to rustc.) #[inline] pub fn is_scalar(&self) -> bool { - match self.kind { + match self.kind() { Bool | Char | Int(_) @@ -1971,7 +2007,7 @@ impl<'tcx> TyS<'tcx> { /// Returns `true` if this type is a floating point type. #[inline] pub fn is_floating_point(&self) -> bool { - match self.kind { + match self.kind() { Float(_) | Infer(FloatVar(_)) => true, _ => false, } @@ -1979,7 +2015,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_trait(&self) -> bool { - match self.kind { + match self.kind() { Dynamic(..) => true, _ => false, } @@ -1987,7 +2023,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_enum(&self) -> bool { - match self.kind { + match self.kind() { Adt(adt_def, _) => adt_def.is_enum(), _ => false, } @@ -1995,7 +2031,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_closure(&self) -> bool { - match self.kind { + match self.kind() { Closure(..) => true, _ => false, } @@ -2003,7 +2039,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_generator(&self) -> bool { - match self.kind { + match self.kind() { Generator(..) => true, _ => false, } @@ -2011,7 +2047,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_integral(&self) -> bool { - match self.kind { + match self.kind() { Infer(IntVar(_)) | Int(_) | Uint(_) => true, _ => false, } @@ -2019,7 +2055,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fresh_ty(&self) -> bool { - match self.kind { + match self.kind() { Infer(FreshTy(_)) => true, _ => false, } @@ -2027,7 +2063,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fresh(&self) -> bool { - match self.kind { + match self.kind() { Infer(FreshTy(_)) => true, Infer(FreshIntTy(_)) => true, Infer(FreshFloatTy(_)) => true, @@ -2037,7 +2073,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_char(&self) -> bool { - match self.kind { + match self.kind() { Char => true, _ => false, } @@ -2050,7 +2086,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_signed(&self) -> bool { - match self.kind { + match self.kind() { Int(_) => true, _ => false, } @@ -2058,7 +2094,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_ptr_sized_integral(&self) -> bool { - match self.kind { + match self.kind() { Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true, _ => false, } @@ -2066,7 +2102,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_machine(&self) -> bool { - match self.kind { + match self.kind() { Int(..) | Uint(..) | Float(..) => true, _ => false, } @@ -2074,7 +2110,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn has_concrete_skeleton(&self) -> bool { - match self.kind { + match self.kind() { Param(_) | Infer(_) | Error(_) => false, _ => true, } @@ -2085,28 +2121,28 @@ impl<'tcx> TyS<'tcx> { /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. pub fn builtin_deref(&self, explicit: bool) -> Option> { - match self.kind { + match self.kind() { Adt(def, _) if def.is_box() => { Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not }) } - Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl }), - RawPtr(mt) if explicit => Some(mt), + Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl: *mutbl }), + RawPtr(mt) if explicit => Some(*mt), _ => None, } } /// Returns the type of `ty[i]`. pub fn builtin_index(&self) -> Option> { - match self.kind { + match self.kind() { Array(ty, _) | Slice(ty) => Some(ty), _ => None, } } pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { - match self.kind { - FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs), - FnPtr(f) => f, + match self.kind() { + FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs), + FnPtr(f) => *f, Error(_) => { // ignore errors (#54954) ty::Binder::dummy(FnSig::fake()) @@ -2120,7 +2156,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fn(&self) -> bool { - match self.kind { + match self.kind() { FnDef(..) | FnPtr(_) => true, _ => false, } @@ -2128,7 +2164,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fn_ptr(&self) -> bool { - match self.kind { + match self.kind() { FnPtr(_) => true, _ => false, } @@ -2136,7 +2172,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_impl_trait(&self) -> bool { - match self.kind { + match self.kind() { Opaque(..) => true, _ => false, } @@ -2144,7 +2180,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> { - match self.kind { + match self.kind() { Adt(adt, _) => Some(adt), _ => None, } @@ -2153,7 +2189,7 @@ impl<'tcx> TyS<'tcx> { /// Iterates over tuple fields. /// Panics when called on anything but a tuple. pub fn tuple_fields(&self) -> impl DoubleEndedIterator> { - match self.kind { + match self.kind() { Tuple(substs) => substs.iter().map(|field| field.expect_ty()), _ => bug!("tuple_fields called on non-tuple"), } @@ -2164,10 +2200,10 @@ impl<'tcx> TyS<'tcx> { // FIXME: This requires the optimized MIR in the case of generators. #[inline] pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option> { - match self.kind { + match self.kind() { TyKind::Adt(adt, _) => Some(adt.variant_range()), TyKind::Generator(def_id, substs, _) => { - Some(substs.as_generator().variant_range(def_id, tcx)) + Some(substs.as_generator().variant_range(*def_id, tcx)) } _ => None, } @@ -2183,7 +2219,7 @@ impl<'tcx> TyS<'tcx> { tcx: TyCtxt<'tcx>, variant_index: VariantIdx, ) -> Option> { - match self.kind { + match self.kind() { TyKind::Adt(adt, _) if adt.variants.is_empty() => { bug!("discriminant_for_variant called on zero variant enum"); } @@ -2191,7 +2227,7 @@ impl<'tcx> TyS<'tcx> { Some(adt.discriminant_for_variant(tcx, variant_index)) } TyKind::Generator(def_id, substs, _) => { - Some(substs.as_generator().discriminant_for_variant(def_id, tcx, variant_index)) + Some(substs.as_generator().discriminant_for_variant(*def_id, tcx, variant_index)) } _ => None, } @@ -2199,7 +2235,7 @@ impl<'tcx> TyS<'tcx> { /// Returns the type of the discriminant of this type. pub fn discriminant_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind { + match self.kind() { ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx), ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), _ => { @@ -2222,7 +2258,7 @@ impl<'tcx> TyS<'tcx> { /// inferred. Once upvar inference (in `src/librustc_typeck/check/upvar.rs`) /// is complete, that type variable will be unified. pub fn to_opt_closure_kind(&self) -> Option { - match self.kind { + match self.kind() { Int(int_ty) => match int_ty { ast::IntTy::I8 => Some(ty::ClosureKind::Fn), ast::IntTy::I16 => Some(ty::ClosureKind::FnMut), @@ -2244,8 +2280,14 @@ impl<'tcx> TyS<'tcx> { /// /// Returning true means the type is known to be sized. Returning /// `false` means nothing -- could be sized, might not be. + /// + /// Note that we could never rely on the fact that a type such as `[_]` is + /// trivially `!Sized` because we could be in a type environment with a + /// bound such as `[_]: Copy`. A function with such a bound obviously never + /// can be called, but that doesn't mean it shouldn't typecheck. This is why + /// this method doesn't return `Option`. pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool { - match self.kind { + match self.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) | ty::Int(_) @@ -2280,9 +2322,4 @@ impl<'tcx> TyS<'tcx> { } } } - - /// Is this a zero-sized type? - pub fn is_zst(&'tcx self, tcx: TyCtxt<'tcx>, did: DefId) -> bool { - tcx.layout_of(tcx.param_env(did).and(self)).map(|layout| layout.is_zst()).unwrap_or(false) - } } diff --git a/src/librustc_middle/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs similarity index 99% rename from src/librustc_middle/ty/subst.rs rename to compiler/rustc_middle/src/ty/subst.rs index acd58ab7f9..1bd3bcb6a4 100644 --- a/src/librustc_middle/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -486,7 +486,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { return t; } - match t.kind { + match *t.kind() { ty::Param(p) => self.ty_for_param(p, t), _ => t.super_fold_with(self), } diff --git a/src/librustc_middle/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs similarity index 99% rename from src/librustc_middle/ty/trait_def.rs rename to compiler/rustc_middle/src/ty/trait_def.rs index 86fe3ac375..9d5b558234 100644 --- a/src/librustc_middle/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -167,7 +167,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Returns a vector containing all impls + /// Returns an iterator containing all impls pub fn all_impls(self, def_id: DefId) -> impl Iterator + 'tcx { let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id); diff --git a/src/librustc_middle/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs similarity index 97% rename from src/librustc_middle/ty/util.rs rename to compiler/rustc_middle/src/ty/util.rs index 63d4dcca08..4127b6535b 100644 --- a/src/librustc_middle/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -33,7 +33,7 @@ pub struct Discr<'tcx> { impl<'tcx> fmt::Display for Discr<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.ty.kind { + match *self.ty.kind() { ty::Int(ity) => { let size = ty::tls::with(|tcx| Integer::from_attr(&tcx, SignedInt(ity)).size()); let x = self.val; @@ -59,7 +59,7 @@ fn unsigned_max(size: Size) -> u128 { } fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) { - let (int, signed) = match ty.kind { + let (int, signed) = match *ty.kind() { Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true), Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false), _ => bug!("non integer discriminant"), @@ -170,14 +170,12 @@ impl<'tcx> TyCtxt<'tcx> { }); hasher.finish() } -} -impl<'tcx> TyCtxt<'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { - if let ty::Adt(def, substs) = ty.kind { + if let ty::Adt(def, substs) = *ty.kind() { for field in def.all_fields() { let field_ty = field.ty(self, substs); - if let Error(_) = field_ty.kind { + if let Error(_) = field_ty.kind() { return true; } } @@ -225,7 +223,7 @@ impl<'tcx> TyCtxt<'tcx> { normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>, ) -> Ty<'tcx> { loop { - match ty.kind { + match *ty.kind() { ty::Adt(def, substs) => { if !def.is_struct() { break; @@ -298,7 +296,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); loop { - match (&a.kind, &b.kind) { + match (&a.kind(), &b.kind()) { (&Adt(a_def, a_substs), &Adt(b_def, b_substs)) if a_def == b_def && a_def.is_struct() => { @@ -401,12 +399,12 @@ impl<'tcx> TyCtxt<'tcx> { // , and then look up which of the impl substs refer to // parameters marked as pure. - let impl_substs = match self.type_of(impl_def_id).kind { + let impl_substs = match *self.type_of(impl_def_id).kind() { ty::Adt(def_, substs) if def_ == def => substs, _ => bug!(), }; - let item_substs = match self.type_of(def.did).kind { + let item_substs = match *self.type_of(def.did).kind() { ty::Adt(def_, substs) if def_ == def => substs, _ => bug!(), }; @@ -526,22 +524,22 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns `true` if the node pointed to by `def_id` is a `static` item. - pub fn is_static(&self, def_id: DefId) -> bool { + pub fn is_static(self, def_id: DefId) -> bool { self.static_mutability(def_id).is_some() } /// Returns `true` if this is a `static` item with the `#[thread_local]` attribute. - pub fn is_thread_local_static(&self, def_id: DefId) -> bool { + pub fn is_thread_local_static(self, def_id: DefId) -> bool { self.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) } /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item. - pub fn is_mutable_static(&self, def_id: DefId) -> bool { + pub fn is_mutable_static(self, def_id: DefId) -> bool { self.static_mutability(def_id) == Some(hir::Mutability::Mut) } /// Get the type of the pointer to the static that we use in MIR. - pub fn static_ptr_ty(&self, def_id: DefId) -> Ty<'tcx> { + pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { // Make sure that any constants in the static's type are evaluated. let static_ty = self.normalize_erasing_regions(ty::ParamEnv::empty(), self.type_of(def_id)); @@ -640,7 +638,7 @@ impl<'tcx> ty::TyS<'tcx> { /// Returns the maximum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { - let val = match self.kind { + let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) }; @@ -659,7 +657,7 @@ impl<'tcx> ty::TyS<'tcx> { /// Returns the minimum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { - let val = match self.kind { + let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); let val = if signed { truncate(signed_min(size) as u128, size) } else { 0 }; @@ -717,7 +715,7 @@ impl<'tcx> ty::TyS<'tcx> { /// Returning true means the type is known to be `Freeze`. Returning /// `false` means nothing -- could be `Freeze`, might not be. fn is_trivially_freeze(&self) -> bool { - match self.kind { + match self.kind() { ty::Int(_) | ty::Uint(_) | ty::Float(_) @@ -793,7 +791,7 @@ impl<'tcx> ty::TyS<'tcx> { /// down, you will need to use a type visitor. #[inline] pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool { - match self.kind { + match self.kind() { // Look for an impl of both `PartialStructuralEq` and `StructuralEq`. Adt(..) => tcx.has_structural_eq_impls(self), @@ -828,7 +826,7 @@ impl<'tcx> ty::TyS<'tcx> { } pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.kind, &b.kind) { + match (&a.kind(), &b.kind()) { (&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => { if did_a != did_b { return false; @@ -860,7 +858,7 @@ impl<'tcx> ty::TyS<'tcx> { representable_cache: &mut FxHashMap, Representability>, ty: Ty<'tcx>, ) -> Representability { - match ty.kind { + match ty.kind() { Tuple(..) => { // Find non representable fold_repr(ty.tuple_fields().map(|ty| { @@ -909,7 +907,7 @@ impl<'tcx> ty::TyS<'tcx> { } fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool { - match ty.kind { + match *ty.kind() { Adt(ty_def, _) => ty_def == def, _ => false, } @@ -947,7 +945,7 @@ impl<'tcx> ty::TyS<'tcx> { representable_cache: &mut FxHashMap, Representability>, ty: Ty<'tcx>, ) -> Representability { - match ty.kind { + match ty.kind() { Adt(def, _) => { { // Iterate through stack of previously seen types. @@ -962,7 +960,7 @@ impl<'tcx> ty::TyS<'tcx> { // struct Bar { x: Bar } if let Some(&seen_type) = iter.next() { - if same_struct_or_enum(seen_type, def) { + if same_struct_or_enum(seen_type, *def) { debug!("SelfRecursive: {:?} contains {:?}", seen_type, ty); return Representability::SelfRecursive(vec![sp]); } @@ -1024,7 +1022,7 @@ impl<'tcx> ty::TyS<'tcx> { /// - `&'a *const &'b u8 -> *const &'b u8` pub fn peel_refs(&'tcx self) -> Ty<'tcx> { let mut ty = self; - while let Ref(_, inner_ty, _) = ty.kind { + while let Ref(_, inner_ty, _) = ty.kind() { ty = inner_ty; } ty @@ -1070,7 +1068,7 @@ impl<'tcx> ExplicitSelf<'tcx> { { use self::ExplicitSelf::*; - match self_arg_ty.kind { + match *self_arg_ty.kind() { _ if is_self_ty(self_arg_ty) => ByValue, ty::Ref(region, ty, mutbl) if is_self_ty(ty) => ByReference(region, mutbl), ty::RawPtr(ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => ByRawPointer(mutbl), @@ -1087,7 +1085,7 @@ pub fn needs_drop_components( ty: Ty<'tcx>, target_layout: &TargetDataLayout, ) -> Result; 2]>, AlwaysRequiresDrop> { - match ty.kind { + match ty.kind() { ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) | ty::Bool diff --git a/src/librustc_middle/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs similarity index 83% rename from src/librustc_middle/ty/walk.rs rename to compiler/rustc_middle/src/ty/walk.rs index 024f655eb6..80ade7dda4 100644 --- a/src/librustc_middle/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -3,50 +3,8 @@ use crate::ty; use crate::ty::subst::{GenericArg, GenericArgKind}; -use arrayvec::ArrayVec; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::mini_set::MiniSet; use smallvec::{self, SmallVec}; -use std::hash::Hash; - -/// Small-storage-optimized implementation of a set -/// made specifically for walking type tree. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashSet` when that length is exceeded. -pub enum MiniSet { - Array(ArrayVec<[T; 8]>), - Set(FxHashSet), -} - -impl MiniSet { - /// Creates an empty `MiniSet`. - pub fn new() -> Self { - MiniSet::Array(ArrayVec::new()) - } - - /// Adds a value to the set. - /// - /// If the set did not have this value present, true is returned. - /// - /// If the set did have this value present, false is returned. - pub fn insert(&mut self, elem: T) -> bool { - match self { - MiniSet::Array(array) => { - if array.iter().any(|e| *e == elem) { - false - } else { - if array.try_push(elem).is_err() { - let mut set: FxHashSet = array.iter().copied().collect(); - set.insert(elem); - *self = MiniSet::Set(set); - } - true - } - } - MiniSet::Set(set) => set.insert(elem), - } - } -} // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. @@ -111,7 +69,7 @@ impl GenericArg<'tcx> { /// that appear in `self`, it does not descend into the fields of /// structs or variants. For example: /// - /// ```notrust + /// ```text /// isize => { isize } /// Foo> => { Foo>, Bar, isize } /// [isize] => { [isize], isize } @@ -144,7 +102,7 @@ impl<'tcx> super::TyS<'tcx> { /// that appear in `self`, it does not descend into the fields of /// structs or variants. For example: /// - /// ```notrust + /// ```text /// isize => { isize } /// Foo> => { Foo>, Bar, isize } /// [isize] => { [isize], isize } @@ -162,7 +120,7 @@ impl<'tcx> super::TyS<'tcx> { // types as they are written). fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) { match parent.unpack() { - GenericArgKind::Type(parent_ty) => match parent_ty.kind { + GenericArgKind::Type(parent_ty) => match *parent_ty.kind() { ty::Bool | ty::Char | ty::Int(_) diff --git a/src/librustc_middle/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs similarity index 100% rename from src/librustc_middle/util/bug.rs rename to compiler/rustc_middle/src/util/bug.rs diff --git a/src/librustc_middle/util/common.rs b/compiler/rustc_middle/src/util/common.rs similarity index 97% rename from src/librustc_middle/util/common.rs rename to compiler/rustc_middle/src/util/common.rs index 1e09702bf2..da857b0a40 100644 --- a/src/librustc_middle/util/common.rs +++ b/compiler/rustc_middle/src/util/common.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types)] - use rustc_data_structures::sync::Lock; use std::fmt::Debug; diff --git a/src/librustc_middle/util/common/tests.rs b/compiler/rustc_middle/src/util/common/tests.rs similarity index 100% rename from src/librustc_middle/util/common/tests.rs rename to compiler/rustc_middle/src/util/common/tests.rs diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml new file mode 100644 index 0000000000..a6d22243d6 --- /dev/null +++ b/compiler/rustc_mir/Cargo.toml @@ -0,0 +1,34 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_mir" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +either = "1.5.0" +rustc_graphviz = { path = "../rustc_graphviz" } +itertools = "0.9" +tracing = "0.1" +log_settings = "0.1.1" +polonius-engine = "0.12.0" +regex = "1" +rustc_middle = { path = "../rustc_middle" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_apfloat = { path = "../rustc_apfloat" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/compiler/rustc_mir/src/borrow_check/borrow_set.rs similarity index 100% rename from src/librustc_mir/borrow_check/borrow_set.rs rename to compiler/rustc_mir/src/borrow_check/borrow_set.rs diff --git a/src/librustc_mir/borrow_check/constraint_generation.rs b/compiler/rustc_mir/src/borrow_check/constraint_generation.rs similarity index 100% rename from src/librustc_mir/borrow_check/constraint_generation.rs rename to compiler/rustc_mir/src/borrow_check/constraint_generation.rs diff --git a/src/librustc_mir/borrow_check/constraints/graph.rs b/compiler/rustc_mir/src/borrow_check/constraints/graph.rs similarity index 100% rename from src/librustc_mir/borrow_check/constraints/graph.rs rename to compiler/rustc_mir/src/borrow_check/constraints/graph.rs diff --git a/src/librustc_mir/borrow_check/constraints/mod.rs b/compiler/rustc_mir/src/borrow_check/constraints/mod.rs similarity index 100% rename from src/librustc_mir/borrow_check/constraints/mod.rs rename to compiler/rustc_mir/src/borrow_check/constraints/mod.rs diff --git a/src/librustc_mir/borrow_check/def_use.rs b/compiler/rustc_mir/src/borrow_check/def_use.rs similarity index 96% rename from src/librustc_mir/borrow_check/def_use.rs rename to compiler/rustc_mir/src/borrow_check/def_use.rs index 6574e58440..689ec249a2 100644 --- a/src/librustc_mir/borrow_check/def_use.rs +++ b/compiler/rustc_mir/src/borrow_check/def_use.rs @@ -72,8 +72,7 @@ pub fn categorize(context: PlaceContext) -> Option { PlaceContext::MutatingUse(MutatingUseContext::Drop) => Some(DefUse::Drop), - // Coverage and debug info are neither def nor use. - PlaceContext::NonUse(NonUseContext::Coverage) | + // Debug info is neither def nor use. PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, } } diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs similarity index 95% rename from src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 7a50bdfeef..11122b195c 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -66,7 +66,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let span = use_spans.args_or_use(); let move_site_vec = self.get_moved_indexes(location, mpi); - debug!("report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec); + debug!( + "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}", + move_site_vec, use_spans + ); let move_out_indices: Vec<_> = move_site_vec.iter().map(|move_site| move_site.moi).collect(); @@ -113,23 +116,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - let msg = ""; //FIXME: add "partially " or "collaterally " + let is_partial_move = move_site_vec.iter().any(|move_site| { + let move_out = self.move_data.moves[(*move_site).moi]; + let moved_place = &self.move_data.move_paths[move_out.path].place; + // `*(_1)` where `_1` is a `Box` is actually a move out. + let is_box_move = moved_place.as_ref().projection == &[ProjectionElem::Deref] + && self.body.local_decls[moved_place.local].ty.is_box(); + + !is_box_move + && used_place != moved_place.as_ref() + && used_place.is_prefix_of(moved_place.as_ref()) + }); + + let partial_str = if is_partial_move { "partial " } else { "" }; + let partially_str = if is_partial_move { "partially " } else { "" }; let mut err = self.cannot_act_on_moved_value( span, desired_action.as_noun(), - msg, + partially_str, self.describe_place_with_options(moved_place, IncludingDowncast(true)), ); self.add_moved_or_invoked_closure_note(location, used_place, &mut err); let mut is_loop_move = false; - let is_partial_move = move_site_vec.iter().any(|move_site| { - let move_out = self.move_data.moves[(*move_site).moi]; - let moved_place = &self.move_data.move_paths[move_out.path].place; - used_place != moved_place.as_ref() && used_place.is_prefix_of(moved_place.as_ref()) - }); + for move_site in &move_site_vec { let move_out = self.move_data.moves[(*move_site).moi]; let moved_place = &self.move_data.move_paths[move_out.path].place; @@ -142,13 +154,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if location == move_out.source { err.span_label( span, - format!("value moved{} here, in previous iteration of loop", move_msg), + format!( + "value {}moved{} here, in previous iteration of loop", + partially_str, move_msg + ), ); is_loop_move = true; } else if move_site.traversed_back_edge { err.span_label( move_span, - format!("value moved{} here, in previous iteration of loop", move_msg), + format!( + "value {}moved{} here, in previous iteration of loop", + partially_str, move_msg + ), ); } else { if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = @@ -162,7 +180,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { FnSelfUseKind::FnOnceCall => { err.span_label( fn_call_span, - &format!("{} moved due to this call", place_name), + &format!( + "{} {}moved due to this call", + place_name, partially_str + ), ); err.span_note( var_span, @@ -172,7 +193,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { FnSelfUseKind::Operator { self_arg } => { err.span_label( fn_call_span, - &format!("{} moved due to usage in operator", place_name), + &format!( + "{} {}moved due to usage in operator", + place_name, partially_str + ), ); if self.fn_self_span_reported.insert(fn_span) { err.span_note( @@ -186,14 +210,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( fn_call_span, &format!( - "{} moved due to this implicit call to `.into_iter()`", - place_name + "{} {}moved due to this implicit call to `.into_iter()`", + place_name, partially_str ), ); } else { err.span_label( fn_call_span, - &format!("{} moved due to this method call", place_name), + &format!( + "{} {}moved due to this method call", + place_name, partially_str + ), ); } // Avoid pointing to the same function in multiple different @@ -205,12 +232,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } + // Deref::deref takes &self, which cannot cause a move + FnSelfUseKind::DerefCoercion { .. } => unreachable!(), } } else { - err.span_label(move_span, format!("value moved{} here", move_msg)); + err.span_label( + move_span, + format!("value {}moved{} here", partially_str, move_msg), + ); move_spans.var_span_label( &mut err, - format!("variable moved due to use{}", move_spans.describe()), + format!( + "variable {}moved due to use{}", + partially_str, + move_spans.describe() + ), ); } } @@ -250,9 +286,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( span, format!( - "value {} here {}", + "value {} here after {}move", desired_action.as_verb_in_past_tense(), - if is_partial_move { "after partial move" } else { "after move" }, + partial_str ), ); } @@ -260,7 +296,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = Place::ty_from(used_place.local, used_place.projection, self.body, self.infcx.tcx) .ty; - let needs_note = match ty.kind { + let needs_note = match ty.kind() { ty::Closure(id, _) => { let tables = self.infcx.tcx.typeck(id.expect_local()); let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local()); @@ -275,7 +311,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = place.ty(self.body, self.infcx.tcx).ty; if is_loop_move { - if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind { + if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { // We have a `&mut` ref, we need to reborrow on each iteration (#62112). err.span_suggestion_verbose( span.shrink_to_lo(), @@ -298,7 +334,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(ref name) => format!("`{}`", name), None => "value".to_owned(), }; - if let ty::Param(param_ty) = ty.kind { + if let ty::Param(param_ty) = ty.kind() { let tcx = self.infcx.tcx; let generics = tcx.generics_of(self.mir_def_id); let param = generics.type_param(¶m_ty, tcx); @@ -321,7 +357,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { None }; - self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span); + self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str); + } + + if let UseSpans::FnSelfUse { + kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty }, + .. + } = use_spans + { + err.note(&format!( + "{} occurs due to deref coercion to `{}`", + desired_action.as_noun(), + deref_target_ty + )); + + err.span_note(deref_target, "deref defined here"); } if let Some((_, mut old_err)) = @@ -914,7 +964,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { name: &str, borrow: &BorrowData<'tcx>, drop_span: Span, - borrow_spans: UseSpans, + borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation, ) -> DiagnosticBuilder<'cx> { debug!( @@ -966,7 +1016,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .opt_name(fn_hir_id) .map(|name| format!("function `{}`", name)) .unwrap_or_else(|| { - match &self.infcx.tcx.typeck(self.mir_def_id).node_type(fn_hir_id).kind + match &self + .infcx + .tcx + .typeck(self.mir_def_id) + .node_type(fn_hir_id) + .kind() { ty::Closure(..) => "enclosing closure", ty::Generator(..) => "enclosing generator", @@ -1110,7 +1165,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, borrow: &BorrowData<'tcx>, drop_span: Span, - borrow_spans: UseSpans, + borrow_spans: UseSpans<'tcx>, proper_span: Span, explanation: BorrowExplanation, ) -> DiagnosticBuilder<'cx> { @@ -1238,7 +1293,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn report_escaping_closure_capture( &mut self, - use_span: UseSpans, + use_span: UseSpans<'tcx>, var_span: Span, fr_name: &RegionName, category: ConstraintCategory, @@ -1398,8 +1453,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for moi in &self.move_data.loc_map[location] { debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); - if mpis.contains(&self.move_data.moves[*moi].path) { - debug!("report_use_of_moved_or_uninitialized: found"); + let path = self.move_data.moves[*moi].path; + if mpis.contains(&path) { + debug!( + "report_use_of_moved_or_uninitialized: found {:?}", + move_paths[path].place + ); result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge }); // Strictly speaking, we could continue our DFS here. There may be @@ -1590,7 +1649,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }, ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { let base_ty = Place::ty_from(place.local, proj_base, self.body, tcx).ty; - match base_ty.kind { + match base_ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor match base_access { @@ -1654,7 +1713,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None } else { let ty = self.infcx.tcx.type_of(self.mir_def_id); - match ty.kind { + match ty.kind() { ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( self.mir_def_id.to_def_id(), self.infcx.tcx.fn_sig(self.mir_def_id), @@ -1889,13 +1948,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // 3. The return type is not a reference. In this case, we don't highlight // anything. let return_ty = sig.output(); - match return_ty.skip_binder().kind { + match return_ty.skip_binder().kind() { ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { // This is case 1 from above, return type is a named reference so we need to // search for relevant arguments. let mut arguments = Vec::new(); for (index, argument) in sig.inputs().skip_binder().iter().enumerate() { - if let ty::Ref(argument_region, _, _) = argument.kind { + if let ty::Ref(argument_region, _, _) = argument.kind() { if argument_region == return_region { // Need to use the `rustc_middle::ty` types to compare against the // `return_region`. Then use the `rustc_hir` type to get only @@ -1941,9 +2000,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Closure arguments are wrapped in a tuple, so we need to get the first // from that. - if let ty::Tuple(elems) = argument_ty.kind { + if let ty::Tuple(elems) = argument_ty.kind() { let argument_ty = elems.first()?.expect_ty(); - if let ty::Ref(_, _, _) = argument_ty.kind { + if let ty::Ref(_, _, _) = argument_ty.kind() { return Some(AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span, @@ -1963,7 +2022,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let return_ty = sig.output().skip_binder(); // We expect the first argument to be a reference. - match argument_ty.kind { + match argument_ty.kind() { ty::Ref(_, _, _) => {} _ => return None, } diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs similarity index 99% rename from src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index b591b938b5..eccb616822 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -102,7 +102,7 @@ impl BorrowExplanation { should_note_order, } => { let local_decl = &body.local_decls[dropped_local]; - let (dtor_desc, type_desc) = match local_decl.ty.kind { + let (dtor_desc, type_desc) = match local_decl.ty.kind() { // If type is an ADT that implements Drop, then // simplify output by reporting just the ADT name. ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => { @@ -501,7 +501,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn later_use_kind( &self, borrow: &BorrowData<'tcx>, - use_spans: UseSpans, + use_spans: UseSpans<'tcx>, location: Location, ) -> (LaterUseKind, Span) { match use_spans { @@ -626,7 +626,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if from == target { debug!("was_captured_by_trait_object: ty={:?}", ty); // Check the type for a trait object. - return match ty.kind { + return match ty.kind() { // `&dyn Trait` ty::Ref(_, ty, _) if ty.is_trait() => true, // `Box` diff --git a/src/librustc_mir/borrow_check/diagnostics/find_use.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs similarity index 100% rename from src/librustc_mir/borrow_check/diagnostics/find_use.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs similarity index 81% rename from src/librustc_mir/borrow_check/diagnostics/mod.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index daffdec2a8..4256f6e39d 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::{ PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::print::Print; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; use rustc_span::{ hygiene::{DesugaringKind, ForLoopLoc}, symbol::sym, @@ -81,43 +81,41 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let terminator = self.body[location.block].terminator(); debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); if let TerminatorKind::Call { - func: - Operand::Constant(box Constant { - literal: ty::Const { ty: &ty::TyS { kind: ty::FnDef(id, _), .. }, .. }, - .. - }), + func: Operand::Constant(box Constant { literal: ty::Const { ty: const_ty, .. }, .. }), args, .. } = &terminator.kind { - debug!("add_moved_or_invoked_closure_note: id={:?}", id); - if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() { - let closure = match args.first() { - Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place)) - if target == place.local_or_deref_local() => - { - place.local_or_deref_local().unwrap() - } - _ => return, - }; + if let ty::FnDef(id, _) = *const_ty.kind() { + debug!("add_moved_or_invoked_closure_note: id={:?}", id); + if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() { + let closure = match args.first() { + Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place)) + if target == place.local_or_deref_local() => + { + place.local_or_deref_local().unwrap() + } + _ => return, + }; - debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); - if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind { - let did = did.expect_local(); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); + debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); + if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { + let did = did.expect_local(); + let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); - if let Some((span, name)) = - self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) - { - diag.span_note( - *span, - &format!( - "closure cannot be invoked more than once because it moves the \ - variable `{}` out of its environment", - name, - ), - ); - return; + if let Some((span, name)) = + self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) + { + diag.span_note( + *span, + &format!( + "closure cannot be invoked more than once because it moves the \ + variable `{}` out of its environment", + name, + ), + ); + return; + } } } } @@ -125,7 +123,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Check if we are just moving a closure after it has been invoked. if let Some(target) = target { - if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind { + if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { let did = did.expect_local(); let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); @@ -152,8 +150,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(mut descr) => { // Surround descr with `backticks`. descr.reserve(2); - descr.insert_str(0, "`"); - descr.push_str("`"); + descr.insert(0, '`'); + descr.push('`'); descr } None => "value".to_string(), @@ -224,7 +222,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.upvars[var_index].by_ref { buf.push_str(&name); } else { - buf.push_str(&format!("*{}", &name)); + buf.push('*'); + buf.push_str(&name); } } else { if autoderef { @@ -236,7 +235,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &including_downcast, )?; } else { - buf.push_str(&"*"); + buf.push('*'); self.append_place_to_string( PlaceRef { local, projection: proj_base }, buf, @@ -274,7 +273,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef, &including_downcast, )?; - buf.push_str(&format!(".{}", field_name)); + buf.push('.'); + buf.push_str(&field_name); } } ProjectionElem::Index(index) => { @@ -286,11 +286,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef, &including_downcast, )?; - buf.push_str("["); + buf.push('['); if self.append_local_to_string(*index, buf).is_err() { - buf.push_str("_"); + buf.push('_'); } - buf.push_str("]"); + buf.push(']'); } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { autoderef = true; @@ -303,7 +303,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef, &including_downcast, )?; - buf.push_str(&"[..]"); + buf.push_str("[..]"); } }; } @@ -365,7 +365,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // If the type is a box, the field is described from the boxed type self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index) } else { - match ty.kind { + match *ty.kind() { ty::Adt(def, _) => { let variant = if let Some(idx) = variant_index { assert!(def.is_enum()); @@ -412,10 +412,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place_desc: &str, ty: Ty<'tcx>, span: Option, + move_prefix: &str, ) { let message = format!( - "move occurs because {} has type `{}`, which does not implement the `Copy` trait", - place_desc, ty, + "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait", + move_prefix, place_desc, ty, ); if let Some(span) = span { err.span_label(span, message); @@ -495,7 +496,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // We need to add synthesized lifetimes where appropriate. We do // this by hooking into the pretty printer and telling it to label the // lifetimes without names with the value `'0`. - match ty.kind { + match ty.kind() { ty::Ref( ty::RegionKind::ReLateBound(_, br) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), @@ -515,7 +516,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); - let region = match ty.kind { + let region = match ty.kind() { ty::Ref(region, _, _) => { match region { ty::RegionKind::ReLateBound(_, br) @@ -537,7 +538,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// The span(s) associated to a use of a place. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum UseSpans { +pub(super) enum UseSpans<'tcx> { /// The access is caused by capturing a variable for a closure. ClosureUse { /// This is true if the captured variable was from a generator. @@ -557,7 +558,7 @@ pub(super) enum UseSpans { fn_call_span: Span, /// The definition span of the method being called fn_span: Span, - kind: FnSelfUseKind, + kind: FnSelfUseKind<'tcx>, }, /// This access is caused by a `match` or `if let` pattern. PatUse(Span), @@ -566,22 +567,32 @@ pub(super) enum UseSpans { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum FnSelfUseKind { +pub(super) enum FnSelfUseKind<'tcx> { /// A normal method call of the form `receiver.foo(a, b, c)` Normal { self_arg: Ident, implicit_into_iter: bool }, /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)` FnOnceCall, /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) Operator { self_arg: Ident }, + DerefCoercion { + /// The `Span` of the `Target` associated type + /// in the `Deref` impl we are using. + deref_target: Span, + /// The type `T::Deref` we are dereferencing to + deref_target_ty: Ty<'tcx>, + }, } -impl UseSpans { +impl UseSpans<'_> { pub(super) fn args_or_use(self) -> Span { match self { UseSpans::ClosureUse { args_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -589,8 +600,11 @@ impl UseSpans { match self { UseSpans::ClosureUse { var_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -649,7 +663,7 @@ impl UseSpans { " in closure".to_string() } } - _ => "".to_string(), + _ => String::new(), } } @@ -679,7 +693,7 @@ impl BorrowedContentSource<'tcx> { BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(), BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(), BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(), - BorrowedContentSource::OverloadedDeref(ty) => match ty.kind { + BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { "an `Rc`".to_string() } @@ -711,7 +725,7 @@ impl BorrowedContentSource<'tcx> { BorrowedContentSource::DerefMutableRef => { bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") } - BorrowedContentSource::OverloadedDeref(ty) => match ty.kind { + BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { "an `Rc`".to_string() } @@ -725,7 +739,7 @@ impl BorrowedContentSource<'tcx> { } fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option { - match func.kind { + match *func.kind() { ty::FnDef(def_id, substs) => { let trait_id = tcx.trait_of_item(def_id)?; @@ -753,7 +767,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, moved_place: PlaceRef<'tcx>, // Could also be an upvar. location: Location, - ) -> UseSpans { + ) -> UseSpans<'tcx> { use self::UseSpans::*; let stmt = match self.body[location.block].statements.get(location.statement_index) { @@ -805,68 +819,79 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: target_temp = {:?}", target_temp); if let Some(Terminator { - kind: TerminatorKind::Call { func, args, fn_span, from_hir_call, .. }, - .. + kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. }) = &self.body[location.block].terminator { - let mut method_did = None; - if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { - if let ty::FnDef(def_id, _) = ty.kind { - debug!("move_spans: fn = {:?}", def_id); - if let Some(ty::AssocItem { fn_has_self_parameter, .. }) = - self.infcx.tcx.opt_associated_item(def_id) - { - if *fn_has_self_parameter { - method_did = Some(def_id); - } - } - } - } + let (method_did, method_substs) = if let Some(info) = + crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block) + { + info + } else { + return normal_ret; + }; let tcx = self.infcx.tcx; - let method_did = if let Some(did) = method_did { did } else { return normal_ret }; - - if let [Operand::Move(self_place), ..] = **args { - if self_place.as_local() == Some(target_temp) { - let parent = tcx.parent(method_did); - let is_fn_once = parent == tcx.lang_items().fn_once_trait(); - let is_operator = !from_hir_call - && parent.map_or(false, |p| { - tcx.lang_items().group(LangItemGroup::Op).contains(&p) - }); - let fn_call_span = *fn_span; - - let self_arg = tcx.fn_arg_names(method_did)[0]; - - let kind = if is_fn_once { - FnSelfUseKind::FnOnceCall - } else if is_operator { - FnSelfUseKind::Operator { self_arg } - } else { - debug!( - "move_spans: method_did={:?}, fn_call_span={:?}", - method_did, fn_call_span - ); - let implicit_into_iter = matches!( - fn_call_span.desugaring_kind(), - Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) - ); - FnSelfUseKind::Normal { self_arg, implicit_into_iter } - }; - - return FnSelfUse { - var_span: stmt.source_info.span, - fn_call_span, - fn_span: self - .infcx - .tcx - .sess - .source_map() - .guess_head_span(self.infcx.tcx.def_span(method_did)), - kind, - }; + let parent = tcx.parent(method_did); + let is_fn_once = parent == tcx.lang_items().fn_once_trait(); + let is_operator = !from_hir_call + && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p)); + let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); + let fn_call_span = *fn_span; + + let self_arg = tcx.fn_arg_names(method_did)[0]; + + debug!( + "terminator = {:?} from_hir_call={:?}", + self.body[location.block].terminator, from_hir_call + ); + + // Check for a 'special' use of 'self' - + // an FnOnce call, an operator (e.g. `<<`), or a + // deref coercion. + let kind = if is_fn_once { + Some(FnSelfUseKind::FnOnceCall) + } else if is_operator { + Some(FnSelfUseKind::Operator { self_arg }) + } else if is_deref { + let deref_target = + tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { + Instance::resolve(tcx, self.param_env, deref_target, method_substs) + .transpose() + }); + if let Some(Ok(instance)) = deref_target { + let deref_target_ty = instance.ty(tcx, self.param_env); + Some(FnSelfUseKind::DerefCoercion { + deref_target: tcx.def_span(instance.def_id()), + deref_target_ty, + }) + } else { + None } - } + } else { + None + }; + + let kind = kind.unwrap_or_else(|| { + // This isn't a 'special' use of `self` + debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); + let implicit_into_iter = matches!( + fn_call_span.desugaring_kind(), + Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) + ); + FnSelfUseKind::Normal { self_arg, implicit_into_iter } + }); + + return FnSelfUse { + var_span: stmt.source_info.span, + fn_call_span, + fn_span: self + .infcx + .tcx + .sess + .source_map() + .guess_head_span(self.infcx.tcx.def_span(method_did)), + kind, + }; } normal_ret } @@ -875,7 +900,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// and its usage of the local assigned at `location`. /// This is done by searching in statements succeeding `location` /// and originating from `maybe_closure_span`. - pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans { + pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> { use self::UseSpans::*; debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); @@ -937,11 +962,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "closure_span: def_id={:?} target_place={:?} places={:?}", def_id, target_place, places ); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(def_id.as_local()?); + let local_did = def_id.as_local()?; + let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did); let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr { - for (upvar, place) in self.infcx.tcx.upvars_mentioned(def_id)?.values().zip(places) { + for ((upvar_hir_id, upvar), place) in + self.infcx.tcx.upvars_mentioned(def_id)?.iter().zip(places) + { match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => @@ -949,7 +977,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("closure_span: found captured local {:?}", place); let body = self.infcx.tcx.hir().body(*body_id); let generator_kind = body.generator_kind(); - return Some((*args_span, generator_kind, upvar.span)); + let upvar_id = ty::UpvarId { + var_path: ty::UpvarPath { hir_id: *upvar_hir_id }, + closure_expr_id: local_did, + }; + + // If we have a more specific span available, point to that. + // We do this even though this span might be part of a borrow error + // message rather than a move error message. Our goal is to point + // to a span that shows why the upvar is used in the closure, + // so a move-related span is as good as any (and potentially better, + // if the overall error is due to a move of the upvar). + let usage_span = + match self.infcx.tcx.typeck(local_did).upvar_capture(upvar_id) { + ty::UpvarCapture::ByValue(Some(span)) => span, + _ => upvar.span, + }; + return Some((*args_span, generator_kind, usage_span)); } _ => {} } @@ -960,7 +1004,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Helper to retrieve span(s) of given borrow from the current MIR /// representation - pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans { + pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> { let span = self.body.source_info(borrow.reserve_location).span; self.borrow_spans(span, borrow.reserve_location) } diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs similarity index 96% rename from src/librustc_mir/borrow_check/diagnostics/move_errors.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index bd3e20458b..629e9be9dd 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -47,7 +47,7 @@ enum GroupedMoveError<'tcx> { // Everything that isn't from pattern matching. OtherIllegalMove { original_path: Place<'tcx>, - use_spans: UseSpans, + use_spans: UseSpans<'tcx>, kind: IllegalMoveOriginKind<'tcx>, }, } @@ -222,7 +222,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let (mut err, err_span) = { let (span, use_spans, original_path, kind): ( Span, - Option, + Option>, Place<'tcx>, &IllegalMoveOriginKind<'_>, ) = match error { @@ -291,7 +291,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { move_place: Place<'tcx>, deref_target_place: Place<'tcx>, span: Span, - use_spans: Option, + use_spans: Option>, ) -> DiagnosticBuilder<'a> { // Inspect the type of the content behind the // borrow to provide feedback about why this @@ -326,7 +326,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } debug!("report: ty={:?}", ty); - let mut err = match ty.kind { + let mut err = match ty.kind() { ty::Array(..) | ty::Slice(..) => { self.cannot_move_out_of_interior_noncopy(span, ty, None) } @@ -385,7 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } }; if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { - let def_id = match move_place.ty(self.body, self.infcx.tcx).ty.kind { + let def_id = match *move_place.ty(self.body, self.infcx.tcx).ty.kind() { ty::Adt(self_def, _) => self_def.did, ty::Foreign(def_id) | ty::FnDef(def_id, _) @@ -445,7 +445,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { None => "value".to_string(), }; - self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span)); + self.note_type_does_not_implement_copy( + err, + &place_desc, + place_ty, + Some(span), + "", + ); } else { binds_to.sort(); binds_to.dedup(); @@ -467,7 +473,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Some(desc) => format!("`{}`", desc), None => "value".to_string(), }; - self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span)); + self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc)); use_spans @@ -486,8 +492,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) { - if pat_snippet.starts_with('&') { - let pat_snippet = pat_snippet[1..].trim_start(); + if let Some(stripped) = pat_snippet.strip_prefix('&') { + let pat_snippet = stripped.trim_start(); let (suggestion, to_remove) = if pat_snippet.starts_with("mut") && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace) { @@ -529,6 +535,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &format!("`{}`", self.local_names[*local].unwrap()), bind_to.ty, Some(binding_span), + "", ); } } diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs similarity index 99% rename from src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index d26436ff1d..d4cdf02104 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -230,7 +230,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Otherwise, check if the name is the self kewyord - in which case // we have an explicit self. Do the same thing in this case and check // for a `self: &mut Self` to suggest removing the `&mut`. - if let ty::Ref(_, _, hir::Mutability::Mut) = local_decl.ty.kind { + if let ty::Ref(_, _, hir::Mutability::Mut) = local_decl.ty.kind() { true } else { false @@ -509,7 +509,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let def_id = hir.local_def_id(item_id); let tables = self.infcx.tcx.typeck(def_id); if let Some(ty::FnDef(def_id, _)) = - tables.node_type_opt(func.hir_id).as_ref().map(|ty| &ty.kind) + tables.node_type_opt(func.hir_id).as_ref().map(|ty| ty.kind()) { let arg = match hir.get_if_local(*def_id) { Some( @@ -631,9 +631,8 @@ fn suggest_ampmut<'tcx>( let lt_name = &src[1..ws_pos]; let ty = &src[ws_pos..]; return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty)); - } else if src.starts_with('&') { - let borrowed_expr = &src[1..]; - return (assignment_rhs_span, format!("&mut {}", borrowed_expr)); + } else if let Some(stripped) = src.strip_prefix('&') { + return (assignment_rhs_span, format!("&mut {}", stripped)); } } } @@ -687,8 +686,8 @@ fn annotate_struct_field( field: &mir::Field, ) -> Option<(Span, String)> { // Expect our local to be a reference to a struct of some kind. - if let ty::Ref(_, ty, _) = ty.kind { - if let ty::Adt(def, _) = ty.kind { + if let ty::Ref(_, ty, _) = ty.kind() { + if let ty::Adt(def, _) = ty.kind() { let field = def.all_fields().nth(field.index())?; // Use the HIR types to construct the diagnostic message. let hir_id = tcx.hir().local_def_id_to_hir_id(field.did.as_local()?); diff --git a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs similarity index 98% rename from src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs index a775fa59c1..7505e6e2dd 100644 --- a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs @@ -115,9 +115,10 @@ impl OutlivesSuggestionBuilder { // should just replace 'a with 'static. // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a - if outlived.iter().any(|(_, outlived_name)| { - if let RegionNameSource::Static = outlived_name.source { true } else { false } - }) { + if outlived + .iter() + .any(|(_, outlived_name)| matches!(outlived_name.source, RegionNameSource::Static)) + { suggested.push(SuggestedConstraint::Static(fr_name)); } else { // We want to isolate out all lifetimes that should be unified and print out diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs similarity index 98% rename from src/librustc_mir/borrow_check/diagnostics/region_errors.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs index a0d99ac33c..eb1f70099f 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -364,13 +364,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .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 { + if let ty::Opaque(def_id, _) = *output_ty.kind() { output_ty = self.infcx.tcx.type_of(def_id) }; debug!("report_fnmut_error: output_ty={:?}", output_ty); - let message = match output_ty.kind { + 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" @@ -387,7 +387,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let ReturnConstraint::ClosureUpvar(upvar) = kind { let def_id = match self.regioncx.universal_regions().defining_ty { DefiningTy::Closure(def_id, _) => def_id, - ty @ _ => bug!("unexpected DefiningTy {:?}", ty), + ty => bug!("unexpected DefiningTy {:?}", ty), }; let upvar_def_span = self.infcx.tcx.hir().span(upvar); @@ -571,13 +571,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let (Some(f), Some(ty::RegionKind::ReStatic)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - if let Some((&ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self + if let Some(&ty::Opaque(did, substs)) = self .infcx .tcx .is_suitable_region(f) .map(|r| r.def_id) - .map(|id| self.infcx.tcx.return_type_impl_trait(id)) - .unwrap_or(None) + .and_then(|id| self.infcx.tcx.return_type_impl_trait(id)) + .map(|(ty, _)| ty.kind()) { // Check whether or not the impl trait return type is intended to capture // data with the static lifetime. diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs similarity index 98% rename from src/librustc_mir/borrow_check/diagnostics/region_name.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index 2603b1e048..5f64eb3dba 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -396,7 +396,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ) -> Option { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(needle_fr, counter); - let type_name = self.infcx.extract_type_name(&ty, Some(highlight)).0; + let type_name = + self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; debug!( "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -404,7 +405,6 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ); if type_name.find(&format!("'{}", counter)).is_some() { // Only add a label if we can confirm that a region was labelled. - Some(RegionNameHighlight::CannotMatchHirTy(span, type_name)) } else { None @@ -441,7 +441,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)]; while let Some((ty, hir_ty)) = search_stack.pop() { - match (&ty.kind, &hir_ty.kind) { + match (&ty.kind(), &hir_ty.kind) { // Check if the `ty` is `&'X ..` where `'X` // is the region we are looking for -- if so, and we have a `&T` // on the RHS, then we want to highlight the `&` like so: @@ -646,7 +646,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0; + let type_name = + self.infcx.extract_inference_diagnostics_data(return_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); @@ -698,7 +699,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0; + let type_name = + self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); diff --git a/src/librustc_mir/borrow_check/diagnostics/var_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs similarity index 100% rename from src/librustc_mir/borrow_check/diagnostics/var_name.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs diff --git a/src/librustc_mir/borrow_check/facts.rs b/compiler/rustc_mir/src/borrow_check/facts.rs similarity index 100% rename from src/librustc_mir/borrow_check/facts.rs rename to compiler/rustc_mir/src/borrow_check/facts.rs diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs similarity index 100% rename from src/librustc_mir/borrow_check/invalidation.rs rename to compiler/rustc_mir/src/borrow_check/invalidation.rs diff --git a/src/librustc_mir/borrow_check/location.rs b/compiler/rustc_mir/src/borrow_check/location.rs similarity index 100% rename from src/librustc_mir/borrow_check/location.rs rename to compiler/rustc_mir/src/borrow_check/location.rs diff --git a/src/librustc_mir/borrow_check/member_constraints.rs b/compiler/rustc_mir/src/borrow_check/member_constraints.rs similarity index 99% rename from src/librustc_mir/borrow_check/member_constraints.rs rename to compiler/rustc_mir/src/borrow_check/member_constraints.rs index d4baa5d809..baaf6f27ee 100644 --- a/src/librustc_mir/borrow_check/member_constraints.rs +++ b/compiler/rustc_mir/src/borrow_check/member_constraints.rs @@ -71,7 +71,7 @@ impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> { /// Pushes a member constraint into the set. /// /// The input member constraint `m_c` is in the form produced by - /// the the `rustc_middle::infer` code. + /// the `rustc_middle::infer` code. /// /// The `to_region_vid` callback fn is used to convert the regions /// within into `RegionVid` format -- it typically consults the diff --git a/src/librustc_mir/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs similarity index 99% rename from src/librustc_mir/borrow_check/mod.rs rename to compiler/rustc_mir/src/borrow_check/mod.rs index a61af5c3f0..e4237482f4 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -17,7 +17,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, InstanceDef, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT}; use rustc_span::{Span, Symbol, DUMMY_SP}; @@ -163,7 +163,7 @@ fn do_mir_borrowck<'a, 'tcx>( let var_hir_id = upvar_id.var_path.hir_id; let capture = tables.upvar_capture(*upvar_id); let by_ref = match capture { - ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByValue(_) => false, ty::UpvarCapture::ByRef(..) => true, }; let mut upvar = Upvar { @@ -205,6 +205,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint() .into_results_cursor(&body); @@ -264,12 +265,15 @@ fn do_mir_borrowck<'a, 'tcx>( let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint(); let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint(); let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint(); let movable_generator = match tcx.hir().get(id) { @@ -287,6 +291,7 @@ fn do_mir_borrowck<'a, 'tcx>( if let Err((move_data, move_errors)) = move_data_results { let mut promoted_mbcx = MirBorrowckCtxt { infcx, + param_env, body: promoted_body, mir_def_id: def.did, move_data: &move_data, @@ -320,6 +325,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut mbcx = MirBorrowckCtxt { infcx, + param_env, body, mir_def_id: def.did, move_data: &mdpe.move_data, @@ -473,6 +479,7 @@ fn do_mir_borrowck<'a, 'tcx>( crate struct MirBorrowckCtxt<'cx, 'tcx> { crate infcx: &'cx InferCtxt<'cx, 'tcx>, + param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, mir_def_id: LocalDefId, move_data: &'cx MoveData<'tcx>, @@ -1694,8 +1701,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), maybe_uninits: &BitSet, - from: u32, - to: u32, + from: u64, + to: u64, ) { if let Some(mpi) = self.move_path_for_place(place_span.0) { let move_paths = &self.move_data.move_paths; @@ -1758,7 +1765,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { { let place_ty = Place::ty_from(place_span.0.local, base_proj, self.body(), self.infcx.tcx); - if let ty::Array(..) = place_ty.ty.kind { + if let ty::Array(..) = place_ty.ty.kind() { let array_place = PlaceRef { local: place_span.0.local, projection: base_proj }; self.check_if_subslice_element_is_moved( location, @@ -1876,7 +1883,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // be already initialized let tcx = self.infcx.tcx; let base_ty = Place::ty_from(place.local, proj_base, self.body(), tcx).ty; - match base_ty.kind { + match base_ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Assignment, @@ -1979,7 +1986,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // of the union - we should error in that case. let tcx = this.infcx.tcx; if let ty::Adt(def, _) = - Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind + Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind() { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { @@ -2206,7 +2213,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Place::ty_from(place.local, proj_base, self.body(), self.infcx.tcx).ty; // Check the kind of deref to decide - match base_ty.kind { + match base_ty.kind() { ty::Ref(_, _, mutbl) => { match mutbl { // Shared borrowed data is never mutable diff --git a/src/librustc_mir/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll.rs rename to compiler/rustc_mir/src/borrow_check/nll.rs diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/compiler/rustc_mir/src/borrow_check/path_utils.rs similarity index 100% rename from src/librustc_mir/borrow_check/path_utils.rs rename to compiler/rustc_mir/src/borrow_check/path_utils.rs diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/compiler/rustc_mir/src/borrow_check/place_ext.rs similarity index 99% rename from src/librustc_mir/borrow_check/place_ext.rs rename to compiler/rustc_mir/src/borrow_check/place_ext.rs index cadf1ebf1b..52fac3e53e 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/compiler/rustc_mir/src/borrow_check/place_ext.rs @@ -49,7 +49,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { if elem == ProjectionElem::Deref { let ty = Place::ty_from(self.local, proj_base, body, tcx).ty; - match ty.kind { + match ty.kind() { ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { // For references to thread-local statics, we do need // to track the borrow. diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/compiler/rustc_mir/src/borrow_check/places_conflict.rs similarity index 99% rename from src/librustc_mir/borrow_check/places_conflict.rs rename to compiler/rustc_mir/src/borrow_check/places_conflict.rs index 246e4826e0..02c7b7dc20 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/compiler/rustc_mir/src/borrow_check/places_conflict.rs @@ -210,7 +210,7 @@ fn place_components_conflict<'tcx>( let proj_base = &borrow_place.projection[..access_place.projection.len() + i]; let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty; - match (elem, &base_ty.kind, access) { + match (elem, &base_ty.kind(), access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { // The array length is like additional fields on the @@ -330,7 +330,7 @@ fn place_projection_conflict<'tcx>( Overlap::EqualOrDisjoint } else { let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; - match ty.kind { + match ty.kind() { ty::Adt(def, _) if def.is_union() => { // Different fields of a union, we are basically stuck. debug!("place_element_conflict: STUCK-UNION"); diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/compiler/rustc_mir/src/borrow_check/prefixes.rs similarity index 99% rename from src/librustc_mir/borrow_check/prefixes.rs rename to compiler/rustc_mir/src/borrow_check/prefixes.rs index a2475e0ff2..6c5d42296f 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/compiler/rustc_mir/src/borrow_check/prefixes.rs @@ -33,7 +33,6 @@ pub(super) struct Prefixes<'cx, 'tcx> { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[allow(dead_code)] pub(super) enum PrefixSet { /// Doesn't stop until it returns the base case (a Local or /// Static prefix). @@ -121,7 +120,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { // reference. let ty = Place::ty_from(cursor.local, proj_base, self.body, self.tcx).ty; - match ty.kind { + match ty.kind() { ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => { // don't continue traversing over derefs of raw pointers or shared // borrows. diff --git a/src/librustc_mir/borrow_check/region_infer/dump_mir.rs b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs similarity index 100% rename from src/librustc_mir/borrow_check/region_infer/dump_mir.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs diff --git a/src/librustc_mir/borrow_check/region_infer/graphviz.rs b/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs similarity index 100% rename from src/librustc_mir/borrow_check/region_infer/graphviz.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs similarity index 99% rename from src/librustc_mir/borrow_check/region_infer/mod.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/mod.rs index 081125cb62..3dc082a441 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs @@ -551,7 +551,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id: DefId, polonius_output: Option>, ) -> (Option>, RegionErrors<'tcx>) { - self.propagate_constraints(body); + self.propagate_constraints(body, infcx.tcx); let mut errors_buffer = RegionErrors::new(); @@ -599,7 +599,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// for each region variable until all the constraints are /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. - fn propagate_constraints(&mut self, _body: &Body<'tcx>) { + fn propagate_constraints(&mut self, _body: &Body<'tcx>, tcx: TyCtxt<'tcx>) { debug!("propagate_constraints()"); debug!("propagate_constraints: constraints={:#?}", { @@ -617,7 +617,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // own. let constraint_sccs = self.constraint_sccs.clone(); for scc in constraint_sccs.all_sccs() { - self.compute_value_for_scc(scc); + self.compute_value_for_scc(scc, tcx); } // Sort the applied member constraints so we can binary search @@ -629,7 +629,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// computed, by unioning the values of its successors. /// Assumes that all successors have been computed already /// (which is assured by iterating over SCCs in dependency order). - fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) { + fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex, tcx: TyCtxt<'tcx>) { let constraint_sccs = self.constraint_sccs.clone(); // Walk each SCC `B` such that `A: B`... @@ -652,7 +652,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Now take member constraints into account. let member_constraints = self.member_constraints.clone(); for m_c_i in member_constraints.indices(scc_a) { - self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i)); + self.apply_member_constraint( + tcx, + scc_a, + m_c_i, + member_constraints.choice_regions(m_c_i), + ); } debug!( @@ -675,6 +680,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// If we make any changes, returns true, else false. fn apply_member_constraint( &mut self, + tcx: TyCtxt<'tcx>, scc: ConstraintSccIndex, member_constraint_index: NllMemberConstraintIndex, choice_regions: &[ty::RegionVid], @@ -688,12 +694,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { // `impl_trait_in_bindings`, I believe, and we are just // opting not to handle it for now. See #61773 for // details. - bug!( - "member constraint for `{:?}` has an option region `{:?}` \ - that is not a universal region", - self.member_constraints[member_constraint_index].opaque_type_def_id, - uh_oh, + tcx.sess.delay_span_bug( + self.member_constraints[member_constraint_index].definition_span, + &format!( + "member constraint for `{:?}` has an option region `{:?}` \ + that is not a universal region", + self.member_constraints[member_constraint_index].opaque_type_def_id, uh_oh, + ), ); + return false; } // Create a mutable vector of the options. We'll try to winnow diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs similarity index 100% rename from src/librustc_mir/borrow_check/region_infer/opaque_types.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs diff --git a/src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs b/compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs similarity index 100% rename from src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs diff --git a/src/librustc_mir/borrow_check/region_infer/values.rs b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs similarity index 99% rename from src/librustc_mir/borrow_check/region_infer/values.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/values.rs index 8a5a600cfd..f247d07e1f 100644 --- a/src/librustc_mir/borrow_check/region_infer/values.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs @@ -417,7 +417,7 @@ crate fn location_set_str( fn region_value_str(elements: impl IntoIterator) -> String { let mut result = String::new(); - result.push_str("{"); + result.push('{'); // Set to Some(l1, l2) when we have observed all the locations // from l1..=l2 (inclusive) but not yet printed them. This @@ -478,7 +478,7 @@ fn region_value_str(elements: impl IntoIterator) -> String push_location_range(&mut result, location1, location2); } - result.push_str("}"); + result.push('}'); return result; diff --git a/src/librustc_mir/borrow_check/renumber.rs b/compiler/rustc_mir/src/borrow_check/renumber.rs similarity index 100% rename from src/librustc_mir/borrow_check/renumber.rs rename to compiler/rustc_mir/src/borrow_check/renumber.rs diff --git a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs similarity index 98% rename from src/librustc_mir/borrow_check/type_check/constraint_conversion.rs rename to compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs index 711271a63f..8513e5e531 100644 --- a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs @@ -62,8 +62,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // `self.constraints`, but we also want to be mutating // `self.member_constraints`. For now, just swap out the value // we want and replace at the end. - let mut tmp = - std::mem::replace(&mut self.constraints.member_constraints, Default::default()); + let mut tmp = std::mem::take(&mut self.constraints.member_constraints); for member_constraint in member_constraints { tmp.push_constraint(member_constraint, |r| self.to_region_vid(r)); } diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/free_region_relations.rs rename to compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/input_output.rs rename to compiler/rustc_mir/src/borrow_check/type_check/input_output.rs diff --git a/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs rename to compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs diff --git a/src/librustc_mir/borrow_check/type_check/liveness/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/liveness/mod.rs rename to compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs diff --git a/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/liveness/polonius.rs rename to compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs diff --git a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/liveness/trace.rs rename to compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs similarity index 99% rename from src/librustc_mir/borrow_check/type_check/mod.rs rename to compiler/rustc_mir/src/borrow_check/type_check/mod.rs index b95d963759..3ace14610e 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -386,7 +386,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } } - if let ty::FnDef(def_id, substs) = constant.literal.ty.kind { + if let ty::FnDef(def_id, substs) = *constant.literal.ty.kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); self.cx.normalize_and_prove_instantiated_predicates( instantiated_predicates, @@ -412,7 +412,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { // If we have a binding of the form `let ref x: T = ..` // then remove the outermost reference so we can check the // type annotation for the remaining type. - if let ty::Ref(_, rty, _) = local_decl.ty.kind { + if let ty::Ref(_, rty, _) = local_decl.ty.kind() { rty } else { bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); @@ -646,10 +646,10 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { })) } ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match base_ty.kind { + PlaceTy::from_ty(match base_ty.kind() { ty::Array(inner, _) => { assert!(!from_end, "array subslices should not use from_end"); - tcx.mk_array(inner, (to - from) as u64) + tcx.mk_array(inner, to - from) } ty::Slice(..) => { assert!(from_end, "slice subslices should use from_end"); @@ -658,7 +658,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), }) } - ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind { + ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind() { ty::Adt(adt_def, _substs) if adt_def.is_enum() => { if index.as_usize() >= adt_def.variants.len() { PlaceTy::from_ty(span_mirbug_and_err!( @@ -738,7 +738,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let tcx = self.tcx(); let (variant, substs) = match base_ty { - PlaceTy { ty, variant_index: Some(variant_index) } => match ty.kind { + PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() { ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs), ty::Generator(def_id, substs, _) => { let mut variants = substs.as_generator().state_tys(def_id, tcx); @@ -757,7 +757,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } _ => bug!("can't have downcast of non-adt non-generator type"), }, - PlaceTy { ty, variant_index: None } => match ty.kind { + PlaceTy { ty, variant_index: None } => match *ty.kind() { ty::Adt(adt_def, substs) if !adt_def.is_enum() => { (&adt_def.variants[VariantIdx::new(0)], substs) } @@ -1140,7 +1140,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory, ) -> Fallible<()> { if let Err(terr) = self.sub_types(sub, sup, locations, category) { - if let ty::Opaque(..) = sup.kind { + if let ty::Opaque(..) = sup.kind() { // When you have `let x: impl Foo = ...` in a closure, // the resulting inferend values are stored with the // def-id of the base function. @@ -1283,8 +1283,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { for (&opaque_def_id, opaque_decl) in &opaque_type_map { let resolved_ty = infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty); - let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind { - def_id == opaque_def_id + let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { + *def_id == opaque_def_id } else { false }; @@ -1486,7 +1486,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } StatementKind::SetDiscriminant { ref place, variant_index } => { let place_type = place.ty(body, tcx).ty; - let adt = match place_type.kind { + let adt = match place_type.kind() { ty::Adt(adt, _) if adt.is_enum() => adt, _ => { span_bug!( @@ -1602,7 +1602,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => { let func_ty = func.ty(body, tcx); debug!("check_terminator: call, func_ty={:?}", func_ty); - let sig = match func_ty.kind { + let sig = match func_ty.kind() { ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx), _ => { span_mirbug!(self, term, "call to non-function {:?}", func_ty); @@ -2093,7 +2093,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { - let sig = match op.ty(body, tcx).kind { + let sig = match op.ty(body, tcx).kind() { ty::Closure(_, substs) => substs.as_closure().sig(), _ => bug!(), }; @@ -2161,7 +2161,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::Pointer(PointerCast::MutToConstPointer) => { - let ty_from = match op.ty(body, tcx).kind { + let ty_from = match op.ty(body, tcx).kind() { ty::RawPtr(ty::TypeAndMut { ty: ty_from, mutbl: hir::Mutability::Mut, @@ -2176,7 +2176,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return; } }; - let ty_to = match ty.kind { + let ty_to = match ty.kind() { ty::RawPtr(ty::TypeAndMut { ty: ty_to, mutbl: hir::Mutability::Not, @@ -2211,11 +2211,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { CastKind::Pointer(PointerCast::ArrayToPointer) => { let ty_from = op.ty(body, tcx); - let opt_ty_elem = match ty_from.kind { + let opt_ty_elem = match ty_from.kind() { ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: array_ty, - }) => match array_ty.kind { + }) => match array_ty.kind() { ty::Array(ty_elem, _) => Some(ty_elem), _ => None, }, @@ -2235,7 +2235,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; - let ty_to = match ty.kind { + let ty_to = match ty.kind() { ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: ty_to, @@ -2301,7 +2301,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { right, ) => { let ty_left = left.ty(body, tcx); - match ty_left.kind { + match ty_left.kind() { // Types with regions are comparable if they have a common super-type. ty::RawPtr(_) | ty::FnPtr(_) => { let ty_right = right.ty(body, tcx); @@ -2512,7 +2512,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty; debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); - match base_ty.kind { + match base_ty.kind() { ty::Ref(ref_region, _, mutbl) => { constraints.outlives_constraints.push(OutlivesConstraint { sup: ref_region.to_region_vid(), diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/relate_tys.rs rename to compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs similarity index 99% rename from src/librustc_mir/borrow_check/universal_regions.rs rename to compiler/rustc_mir/src/borrow_check/universal_regions.rs index 9dfc67bcf6..4742113b1a 100644 --- a/src/librustc_mir/borrow_check/universal_regions.rs +++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs @@ -524,7 +524,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let defining_ty = self.infcx.replace_free_regions_with_nll_infer_vars(FR, &defining_ty); - match defining_ty.kind { + match *defining_ty.kind() { ty::Closure(def_id, substs) => DefiningTy::Closure(def_id, substs), ty::Generator(def_id, substs, movability) => { DefiningTy::Generator(def_id, substs, movability) @@ -603,7 +603,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // flattens this tuple. let (&output, tuplized_inputs) = inputs_and_output.split_last().unwrap(); assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); - let inputs = match tuplized_inputs[0].kind { + let inputs = match tuplized_inputs[0].kind() { ty::Tuple(inputs) => inputs, _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]), }; diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/compiler/rustc_mir/src/borrow_check/used_muts.rs similarity index 100% rename from src/librustc_mir/borrow_check/used_muts.rs rename to compiler/rustc_mir/src/borrow_check/used_muts.rs diff --git a/src/librustc_mir/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs similarity index 100% rename from src/librustc_mir/const_eval/error.rs rename to compiler/rustc_mir/src/const_eval/error.rs diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs similarity index 78% rename from src/librustc_mir/const_eval/eval_queries.rs rename to compiler/rustc_mir/src/const_eval/eval_queries.rs index 291b42c12d..57aa216850 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -1,8 +1,8 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra}; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ - intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, Immediate, InternKind, - InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar, + intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, GlobalId, Immediate, + InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, ScalarMaybeUninit, StackPopCleanup, }; @@ -10,10 +10,11 @@ use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::traits::Reveal; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, subst::Subst, TyCtxt}; use rustc_span::source_map::Span; use rustc_target::abi::{Abi, LayoutOf}; -use std::convert::TryInto; +use std::convert::{TryFrom, TryInto}; pub fn note_on_undefined_behavior_error() -> &'static str { "The rules on what exactly is undefined behavior aren't clear, \ @@ -33,7 +34,8 @@ fn eval_body_using_ecx<'mir, 'tcx>( assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack); - let name = ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id())); + let name = + with_no_trimmed_paths(|| ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id()))); let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); @@ -102,6 +104,8 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( ) } +/// This function converts an interpreter value into a constant that is meant for use in the +/// type system. pub(super) fn op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, 'tcx>, op: OpTy<'tcx>, @@ -115,8 +119,8 @@ pub(super) fn op_to_const<'tcx>( // `Undef` situation. let try_as_immediate = match op.layout.abi { Abi::Scalar(..) => true, - Abi::ScalarPair(..) => match op.layout.ty.kind { - ty::Ref(_, inner, _) => match inner.kind { + Abi::ScalarPair(..) => match op.layout.ty.kind() { + ty::Ref(_, inner, _) => match *inner.kind() { ty::Slice(elem) => elem == ecx.tcx.types.u8, ty::Str => true, _ => false, @@ -144,10 +148,10 @@ pub(super) fn op_to_const<'tcx>( Scalar::Raw { data, .. } => { assert!(mplace.layout.is_zst()); assert_eq!( - data, - mplace.layout.align.abi.bytes().into(), - "this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what - value this integer address must have", + u64::try_from(data).unwrap() % mplace.layout.align.abi.bytes(), + 0, + "this MPlaceTy must come from a validated constant, thus we can assume the \ + alignment is correct", ); ConstValue::Scalar(Scalar::zst()) } @@ -180,63 +184,37 @@ pub(super) fn op_to_const<'tcx>( } } -fn validate_and_turn_into_const<'tcx>( +fn turn_into_const_value<'tcx>( tcx: TyCtxt<'tcx>, - constant: RawConst<'tcx>, + constant: ConstAlloc<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> { +) -> ConstValue<'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); - let val = (|| { - let mplace = ecx.raw_const_to_mplace(constant)?; - // FIXME do not validate promoteds until a decision on - // https://github.com/rust-lang/rust/issues/67465 is made - if cid.promoted.is_none() { - let mut ref_tracking = RefTracking::new(mplace); - while let Some((mplace, path)) = ref_tracking.todo.pop() { - ecx.const_validate_operand( - mplace.into(), - path, - &mut ref_tracking, - /*may_ref_to_static*/ ecx.memory.extra.can_access_statics, - )?; - } - } - // Now that we validated, turn this into a proper constant. - // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides - // whether they become immediates. - if is_static || cid.promoted.is_some() { - let ptr = mplace.ptr.assert_ptr(); - Ok(ConstValue::ByRef { - alloc: ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), - offset: ptr.offset, - }) - } else { - Ok(op_to_const(&ecx, mplace.into())) - } - })(); - - val.map_err(|error| { - let err = ConstEvalErr::new(&ecx, error, None); - err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| { - diag.note(note_on_undefined_behavior_error()); - diag.emit(); - }) - }) + let mplace = ecx.raw_const_to_mplace(constant).expect( + "can only fail if layout computation failed, \ + which should have given a good error before ever invoking this function", + ); + assert!( + !is_static || cid.promoted.is_some(), + "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead" + ); + // Turn this into a proper constant. + op_to_const(&ecx, mplace.into()) } -pub fn const_eval_validated_provider<'tcx>( +pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> { +) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { // see comment in const_eval_raw_provider for what we're doing here if key.param_env.reveal() == Reveal::All { let mut key = key; key.param_env = key.param_env.with_user_facing(); - match tcx.const_eval_validated(key) { + match tcx.eval_to_const_value_raw(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // deduplicate calls @@ -248,7 +226,7 @@ pub fn const_eval_validated_provider<'tcx>( // Catch such calls and evaluate them instead of trying to load a constant's MIR. if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { let ty = key.value.instance.ty(tcx, key.param_env); - let substs = match ty.kind { + let substs = match ty.kind() { ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), }; @@ -259,13 +237,13 @@ pub fn const_eval_validated_provider<'tcx>( }); } - tcx.const_eval_raw(key).and_then(|val| validate_and_turn_into_const(tcx, val, key)) + tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) } -pub fn const_eval_raw_provider<'tcx>( +pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::ConstEvalRawResult<'tcx> { +) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { // Because the constant is computed twice (once per value of `Reveal`), we are at risk of // reporting the same error twice here. To resolve this, we check whether we can evaluate the // constant in the more restrictive `Reveal::UserFacing`, which most likely already was @@ -277,7 +255,7 @@ pub fn const_eval_raw_provider<'tcx>( if key.param_env.reveal() == Reveal::All { let mut key = key; key.param_env = key.param_env.with_user_facing(); - match tcx.const_eval_raw(key) { + match tcx.eval_to_allocation_raw(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // deduplicate calls @@ -290,7 +268,7 @@ pub fn const_eval_raw_provider<'tcx>( // The next two lines concatenated contain some discussion: // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ // subject/anon_const_instance_printing/near/135980032 - let instance = key.value.instance.to_string(); + let instance = with_no_trimmed_paths(|| key.value.instance.to_string()); trace!("const eval: {:?} ({})", key, instance); } @@ -316,9 +294,8 @@ pub fn const_eval_raw_provider<'tcx>( ); let res = ecx.load_mir(cid.instance.def, cid.promoted); - res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) - .map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty }) - .map_err(|error| { + match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) { + Err(error) => { let err = ConstEvalErr::new(&ecx, error, None); // errors in statics are always emitted as fatal errors if is_static { @@ -340,7 +317,7 @@ pub fn const_eval_raw_provider<'tcx>( ); } - v + Err(v) } else if let Some(def) = def.as_local() { // constant defined in this crate, we can figure out a lint level! match tcx.def_kind(def.did.to_def_id()) { @@ -354,12 +331,12 @@ pub fn const_eval_raw_provider<'tcx>( // compatibility hazard DefKind::Const | DefKind::AssocConst => { let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - err.report_as_lint( + Err(err.report_as_lint( tcx.at(tcx.def_span(def.did)), "any use of this value will cause an error", hir_id, Some(err.span), - ) + )) } // promoting runtime code is only allowed to error if it references broken // constants any other kind of error will be reported to the user as a @@ -368,31 +345,65 @@ pub fn const_eval_raw_provider<'tcx>( if let Some(p) = cid.promoted { let span = tcx.promoted_mir_of_opt_const_arg(def.to_global())[p].span; if let err_inval!(ReferencedConstant) = err.error { - err.report_as_error( + Err(err.report_as_error( tcx.at(span), "evaluation of constant expression failed", - ) + )) } else { - err.report_as_lint( + Err(err.report_as_lint( tcx.at(span), "reaching this expression at runtime will panic or abort", tcx.hir().local_def_id_to_hir_id(def.did), Some(err.span), - ) + )) } // anything else (array lengths, enum initializers, constant patterns) are // reported as hard errors } else { - err.report_as_error( + Err(err.report_as_error( ecx.tcx.at(ecx.cur_span()), "evaluation of constant value failed", - ) + )) } } } } else { // use of broken constant from other crate - err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant") + Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant")) } - }) + } + Ok(mplace) => { + // Since evaluation had no errors, valiate the resulting constant: + let validation = try { + // FIXME do not validate promoteds until a decision on + // https://github.com/rust-lang/rust/issues/67465 is made + if cid.promoted.is_none() { + let mut ref_tracking = RefTracking::new(mplace); + while let Some((mplace, path)) = ref_tracking.todo.pop() { + ecx.const_validate_operand( + mplace.into(), + path, + &mut ref_tracking, + /*may_ref_to_static*/ ecx.memory.extra.can_access_statics, + )?; + } + } + }; + if let Err(error) = validation { + // Validation failed, report an error + let err = ConstEvalErr::new(&ecx, error, None); + Err(err.struct_error( + ecx.tcx, + "it is undefined behavior to use this value", + |mut diag| { + diag.note(note_on_undefined_behavior_error()); + diag.emit(); + }, + )) + } else { + // Convert to raw constant + Ok(ConstAlloc { alloc_id: mplace.ptr.assert_ptr().alloc_id, ty: mplace.layout.ty }) + } + } + } } diff --git a/src/librustc_mir/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs similarity index 95% rename from src/librustc_mir/const_eval/fn_queries.rs rename to compiler/rustc_mir/src/const_eval/fn_queries.rs index 9ef63b3322..aca822a05b 100644 --- a/src/librustc_mir/const_eval/fn_queries.rs +++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs @@ -50,7 +50,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { None => { if let Some(stab) = tcx.lookup_stability(def_id) { if stab.level.is_stable() { - tcx.sess.span_err( + tcx.sess.delay_span_bug( tcx.def_span(def_id), "stable const functions must have either `rustc_const_stable` or \ `rustc_const_unstable` attribute", @@ -151,17 +151,11 @@ fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - is_const_fn(tcx, def_id) - && tcx.lookup_const_stability(def_id).map(|stab| stab.allow_const_fn_ptr).unwrap_or(false) -} - pub fn provide(providers: &mut Providers) { *providers = Providers { is_const_fn_raw, is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, def_id.expect_local()), is_promotable_const_fn, - const_fn_is_allowed_fn_ptr, ..*providers }; } diff --git a/src/librustc_mir/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs similarity index 81% rename from src/librustc_mir/const_eval/machine.rs rename to compiler/rustc_mir/src/const_eval/machine.rs index b0357c508a..73ca7e0d47 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -11,7 +11,7 @@ use rustc_ast::Mutability; use rustc_hir::def_id::DefId; use rustc_middle::mir::AssertMessage; use rustc_session::Limit; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use crate::interpret::{ self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx, @@ -51,7 +51,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { let gid = GlobalId { instance, promoted: None }; - let place = self.const_eval_raw(gid)?; + let place = self.eval_to_allocation(gid)?; self.copy_op(place.into(), dest)?; @@ -176,6 +176,38 @@ impl interpret::MayLeak for ! { } } +impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { + fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { + match (a, b) { + // Comparisons between integers are always known. + (Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b, + // Equality with integers can never be known for sure. + (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => 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) -> bool { + match (a, b) { + // Comparisons between integers are always known. + (Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b, + // 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. + (Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr)) + | (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr), + // Inequality with integers other than null can never be known for sure. + (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, + // FIXME: return `true` 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, + } + } +} + impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); @@ -234,12 +266,45 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { + // Shared intrinsics. if ecx.emulate_intrinsic(instance, args, ret)? { return Ok(()); } - // An intrinsic that we do not support let intrinsic_name = ecx.tcx.item_name(instance.def_id()); - Err(ConstEvalErrKind::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into()) + + // CTFE-specific intrinsics. + let (dest, ret) = match ret { + None => { + return Err(ConstEvalErrKind::NeedsRfc(format!( + "calling intrinsic `{}`", + intrinsic_name + )) + .into()); + } + Some(p) => p, + }; + 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)?; + } + _ => { + return Err(ConstEvalErrKind::NeedsRfc(format!( + "calling intrinsic `{}`", + intrinsic_name + )) + .into()); + } + } + + ecx.go_to_block(ret); + Ok(()) } fn assert_panic( diff --git a/src/librustc_mir/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs similarity index 60% rename from src/librustc_mir/const_eval/mod.rs rename to compiler/rustc_mir/src/const_eval/mod.rs index e7eeb4b4de..978d2fe000 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -2,11 +2,14 @@ use std::convert::TryFrom; +use rustc_hir::Mutability; use rustc_middle::mir; 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}; +use crate::interpret::{ + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MemPlaceMeta, Scalar, +}; mod error; mod eval_queries; @@ -44,7 +47,7 @@ pub(crate) fn destructure_const<'tcx>( let op = ecx.const_to_op(val, None).unwrap(); // We go to `usize` as we cannot allocate anything bigger anyway. - let (field_count, variant, down) = match val.ty.kind { + let (field_count, variant, down) = match val.ty.kind() { ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), ty::Adt(def, _) if def.variants.is_empty() => { return mir::DestructuredConst { variant: None, fields: tcx.arena.alloc_slice(&[]) }; @@ -67,3 +70,39 @@ pub(crate) fn destructure_const<'tcx>( mir::DestructuredConst { variant, fields } } + +pub(crate) fn deref_const<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: &'tcx ty::Const<'tcx>, +) -> &'tcx ty::Const<'tcx> { + trace!("deref_const: {:?}", val); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let op = ecx.const_to_op(val, None).unwrap(); + let mplace = ecx.deref_operand(op).unwrap(); + if let Scalar::Ptr(ptr) = mplace.ptr { + assert_eq!( + ecx.memory.get_raw(ptr.alloc_id).unwrap().mutability, + Mutability::Not, + "deref_const cannot be used with mutable allocations as \ + that could allow pattern matching to observe mutable statics", + ); + } + + let ty = match mplace.meta { + MemPlaceMeta::None => mplace.layout.ty, + MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), + // In case of unsized types, figure out the real type behind. + MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { + ty::Str => bug!("there's no sized equivalent of a `str`"), + ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()), + _ => bug!( + "type {} should not have metadata, but had {:?}", + mplace.layout.ty, + mplace.meta + ), + }, + }; + + tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, mplace.into())), ty }) +} diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs similarity index 99% rename from src/librustc_mir/dataflow/drop_flag_effects.rs rename to compiler/rustc_mir/src/dataflow/drop_flag_effects.rs index 707e136678..d1d507e54e 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs @@ -53,7 +53,7 @@ fn place_contents_drop_state_cannot_differ<'tcx>( place: mir::Place<'tcx>, ) -> bool { let ty = place.ty(body, tcx).ty; - match ty.kind { + match ty.kind() { ty::Array(..) => { debug!( "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", diff --git a/src/librustc_mir/dataflow/framework/cursor.rs b/compiler/rustc_mir/src/dataflow/framework/cursor.rs similarity index 90% rename from src/librustc_mir/dataflow/framework/cursor.rs rename to compiler/rustc_mir/src/dataflow/framework/cursor.rs index 4f5930dc3f..4942bed656 100644 --- a/src/librustc_mir/dataflow/framework/cursor.rs +++ b/compiler/rustc_mir/src/dataflow/framework/cursor.rs @@ -4,6 +4,7 @@ use std::borrow::Borrow; use std::cmp::Ordering; use rustc_index::bit_set::BitSet; +use rustc_index::vec::Idx; use rustc_middle::mir::{self, BasicBlock, Location}; use super::{Analysis, Direction, Effect, EffectIndex, Results}; @@ -26,7 +27,7 @@ where { body: &'mir mir::Body<'tcx>, results: R, - state: BitSet, + state: A::Domain, pos: CursorPosition, @@ -46,17 +47,16 @@ where { /// Returns a new cursor that can inspect `results`. pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self { - let bits_per_block = results.borrow().entry_set_for_block(mir::START_BLOCK).domain_size(); - + let bottom_value = results.borrow().analysis.bottom_value(body); ResultsCursor { body, results, - // Initialize to an empty `BitSet` and set `state_needs_reset` to tell the cursor that + // Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that // it needs to reset to block entry before the first seek. The cursor position is // immaterial. state_needs_reset: true, - state: BitSet::new_empty(bits_per_block), + state: bottom_value, pos: CursorPosition::block_entry(mir::START_BLOCK), #[cfg(debug_assertions)] @@ -68,23 +68,21 @@ where self.body } - /// Returns the `Analysis` used to generate the underlying results. + /// Returns the underlying `Results`. + pub fn results(&self) -> &Results<'tcx, A> { + &self.results.borrow() + } + + /// Returns the `Analysis` used to generate the underlying `Results`. pub fn analysis(&self) -> &A { &self.results.borrow().analysis } /// Returns the dataflow state at the current location. - pub fn get(&self) -> &BitSet { + pub fn get(&self) -> &A::Domain { &self.state } - /// Returns `true` if the dataflow state at the current location contains the given element. - /// - /// Shorthand for `self.get().contains(elem)` - pub fn contains(&self, elem: A::Idx) -> bool { - self.state.contains(elem) - } - /// Resets the cursor to hold the entry set for the given basic block. /// /// For forward dataflow analyses, this is the dataflow state prior to the first statement. @@ -94,7 +92,7 @@ where #[cfg(debug_assertions)] assert!(self.reachable_blocks.contains(block)); - self.state.overwrite(&self.results.borrow().entry_set_for_block(block)); + self.state.clone_from(&self.results.borrow().entry_set_for_block(block)); self.pos = CursorPosition::block_entry(block); self.state_needs_reset = false; } @@ -202,12 +200,23 @@ where /// /// This can be used, e.g., to apply the call return effect directly to the cursor without /// creating an extra copy of the dataflow state. - pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut BitSet)) { + pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) { f(&self.results.borrow().analysis, &mut self.state); self.state_needs_reset = true; } } +impl<'mir, 'tcx, A, R, T> ResultsCursor<'mir, 'tcx, A, R> +where + A: Analysis<'tcx, Domain = BitSet>, + T: Idx, + R: Borrow>, +{ + pub fn contains(&self, elem: T) -> bool { + self.get().contains(elem) + } +} + #[derive(Clone, Copy, Debug)] struct CursorPosition { block: BasicBlock, diff --git a/src/librustc_mir/dataflow/framework/direction.rs b/compiler/rustc_mir/src/dataflow/framework/direction.rs similarity index 80% rename from src/librustc_mir/dataflow/framework/direction.rs rename to compiler/rustc_mir/src/dataflow/framework/direction.rs index 4512ae96c0..ca2bb6e0bf 100644 --- a/src/librustc_mir/dataflow/framework/direction.rs +++ b/compiler/rustc_mir/src/dataflow/framework/direction.rs @@ -1,10 +1,10 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::TyCtxt; use std::ops::RangeInclusive; use super::visitor::{ResultsVisitable, ResultsVisitor}; -use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet}; +use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget}; pub trait Direction { fn is_forward() -> bool; @@ -18,7 +18,7 @@ pub trait Direction { /// `effects.start()` must precede or equal `effects.end()` in this direction. fn apply_effects_in_range( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, effects: RangeInclusive, @@ -27,7 +27,7 @@ pub trait Direction { fn apply_effects_in_block( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, ) where @@ -55,9 +55,9 @@ pub trait Direction { tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, dead_unwinds: Option<&BitSet>, - exit_state: &mut BitSet, + exit_state: &mut A::Domain, block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>), - propagate: impl FnMut(BasicBlock, &BitSet), + propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>; } @@ -72,7 +72,7 @@ impl Direction for Backward { fn apply_effects_in_block( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, ) where @@ -112,7 +112,7 @@ impl Direction for Backward { fn apply_effects_in_range( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, effects: RangeInclusive, @@ -224,9 +224,9 @@ impl Direction for Backward { _tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, dead_unwinds: Option<&BitSet>, - exit_state: &mut BitSet, + exit_state: &mut A::Domain, (bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), - mut propagate: impl FnMut(BasicBlock, &BitSet), + mut propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>, { @@ -281,7 +281,7 @@ impl Direction for Forward { fn apply_effects_in_block( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, ) where @@ -321,7 +321,7 @@ impl Direction for Forward { fn apply_effects_in_range( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, effects: RangeInclusive, @@ -425,12 +425,12 @@ impl Direction for Forward { fn join_state_into_successors_of( analysis: &A, - tcx: TyCtxt<'tcx>, - body: &mir::Body<'tcx>, + _tcx: TyCtxt<'tcx>, + _body: &mir::Body<'tcx>, dead_unwinds: Option<&BitSet>, - exit_state: &mut BitSet, + exit_state: &mut A::Domain, (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), - mut propagate: impl FnMut(BasicBlock, &BitSet), + mut propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>, { @@ -489,50 +489,23 @@ impl Direction for Forward { } SwitchInt { ref targets, ref values, ref discr, switch_ty: _ } => { - let enum_ = discr - .place() - .and_then(|discr| switch_on_enum_discriminant(tcx, &body, bb_data, discr)); - match enum_ { - // If this is a switch on an enum discriminant, a custom effect may be applied - // along each outgoing edge. - Some((enum_place, enum_def)) => { - // MIR building adds discriminants to the `values` array in the same order as they - // are yielded by `AdtDef::discriminants`. We rely on this to match each - // discriminant in `values` to its corresponding variant in linear time. - let mut tmp = BitSet::new_empty(exit_state.domain_size()); - let mut discriminants = enum_def.discriminants(tcx); - for (value, target) in values.iter().zip(targets.iter().copied()) { - let (variant_idx, _) = - discriminants.find(|&(_, discr)| discr.val == *value).expect( - "Order of `AdtDef::discriminants` differed \ - from that of `SwitchInt::values`", - ); - - tmp.overwrite(exit_state); - analysis.apply_discriminant_switch_effect( - &mut tmp, - bb, - enum_place, - enum_def, - variant_idx, - ); - propagate(target, &tmp); - } - - // Move out of `tmp` so we don't accidentally use it below. - std::mem::drop(tmp); - - // Propagate dataflow state along the "otherwise" edge. - let otherwise = targets.last().copied().unwrap(); - propagate(otherwise, exit_state) - } - - // Otherwise, it's just a normal `SwitchInt`, and every successor sees the same - // exit state. - None => { - for target in targets.iter().copied() { - propagate(target, exit_state); - } + let mut applier = SwitchIntEdgeEffectApplier { + exit_state, + targets: targets.as_ref(), + values: values.as_ref(), + propagate, + effects_applied: false, + }; + + analysis.apply_switch_int_edge_effects(bb, discr, &mut applier); + + let SwitchIntEdgeEffectApplier { + exit_state, mut propagate, effects_applied, .. + } = applier; + + if !effects_applied { + for &target in targets.iter() { + propagate(target, exit_state); } } } @@ -540,37 +513,54 @@ impl Direction for Forward { } } -/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is -/// an enum discriminant. -/// -/// We expect such blocks to have a call to `discriminant` as their last statement like so: -/// _42 = discriminant(_1) -/// SwitchInt(_42, ..) -/// -/// If the basic block matches this pattern, this function returns the place corresponding to the -/// enum (`_1` in the example above) as well as the `AdtDef` of that enum. -fn switch_on_enum_discriminant( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - block: &'mir mir::BasicBlockData<'tcx>, - switch_on: mir::Place<'tcx>, -) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> { - match block.statements.last().map(|stmt| &stmt.kind) { - Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))) - if *lhs == switch_on => - { - match &discriminated.ty(body, tcx).ty.kind { - ty::Adt(def, _) => Some((*discriminated, def)), - - // `Rvalue::Discriminant` is also used to get the active yield point for a - // generator, but we do not need edge-specific effects in that case. This may - // change in the future. - ty::Generator(..) => None, - - t => bug!("`discriminant` called on unexpected type {:?}", t), - } +struct SwitchIntEdgeEffectApplier<'a, D, F> { + exit_state: &'a mut D, + values: &'a [u128], + targets: &'a [BasicBlock], + propagate: F, + + effects_applied: bool, +} + +impl super::SwitchIntEdgeEffects for SwitchIntEdgeEffectApplier<'_, D, F> +where + D: Clone, + F: FnMut(BasicBlock, &D), +{ + fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { + assert!(!self.effects_applied); + + let mut tmp = None; + for (&value, &target) in self.values.iter().zip(self.targets.iter()) { + let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); + apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target }); + (self.propagate)(target, tmp); } - _ => None, + // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`, + // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state. + let otherwise = self.targets.last().copied().unwrap(); + apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise }); + (self.propagate)(otherwise, self.exit_state); + + self.effects_applied = true; + } +} + +/// An analogue of `Option::get_or_insert_with` that stores a clone of `val` into `opt`, but uses +/// the more efficient `clone_from` if `opt` was `Some`. +/// +/// Returns a mutable reference to the new clone that resides in `opt`. +// +// FIXME: Figure out how to express this using `Option::clone_from`, or maybe lift it into the +// standard library? +fn opt_clone_from_or_clone(opt: &'a mut Option, val: &T) -> &'a mut T { + if opt.is_some() { + let ret = opt.as_mut().unwrap(); + ret.clone_from(val); + ret + } else { + *opt = Some(val.clone()); + opt.as_mut().unwrap() } } diff --git a/src/librustc_mir/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs similarity index 73% rename from src/librustc_mir/dataflow/framework/engine.rs rename to compiler/rustc_mir/src/dataflow/framework/engine.rs index b703852b1d..f39c78f503 100644 --- a/src/librustc_mir/dataflow/framework/engine.rs +++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs @@ -1,5 +1,6 @@ //! A solver for dataflow problems. +use std::borrow::BorrowMut; use std::ffi::OsString; use std::fs; use std::path::PathBuf; @@ -9,14 +10,16 @@ use rustc_data_structures::work_queue::WorkQueue; use rustc_graphviz as dot; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; -use rustc_index::vec::IndexVec; +use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::{self, traversal, BasicBlock}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; +use super::fmt::DebugWithContext; use super::graphviz; use super::{ - visit_results, Analysis, Direction, GenKillAnalysis, GenKillSet, ResultsCursor, ResultsVisitor, + visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice, + ResultsCursor, ResultsVisitor, }; use crate::util::pretty::dump_enabled; @@ -26,7 +29,7 @@ where A: Analysis<'tcx>, { pub analysis: A, - pub(super) entry_sets: IndexVec>, + pub(super) entry_sets: IndexVec, } impl Results<'tcx, A> @@ -39,7 +42,7 @@ where } /// Gets the dataflow state for the given block. - pub fn entry_set_for_block(&self, block: BasicBlock) -> &BitSet { + pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { &self.entry_sets[block] } @@ -47,7 +50,7 @@ where &self, body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, ) { visit_results(body, blocks, self, vis) } @@ -55,7 +58,7 @@ where pub fn visit_reachable_with( &self, body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, ) { let blocks = mir::traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) @@ -64,7 +67,7 @@ where pub fn visit_in_rpo_with( &self, body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, ) { let blocks = mir::traversal::reverse_postorder(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) @@ -76,21 +79,28 @@ pub struct Engine<'a, 'tcx, A> where A: Analysis<'tcx>, { - bits_per_block: usize, tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, def_id: DefId, dead_unwinds: Option<&'a BitSet>, - entry_sets: IndexVec>, + entry_sets: IndexVec, + pass_name: Option<&'static str>, analysis: A, /// Cached, cumulative transfer functions for each block. - trans_for_block: Option>>, + // + // FIXME(ecstaticmorse): This boxed `Fn` trait object is invoked inside a tight loop for + // gen/kill problems on cyclic CFGs. This is not ideal, but it doesn't seem to degrade + // performance in practice. I've tried a few ways to avoid this, but they have downsides. See + // the message for the commit that added this FIXME for more information. + apply_trans_for_block: Option>, } -impl Engine<'a, 'tcx, A> +impl Engine<'a, 'tcx, A> where - A: GenKillAnalysis<'tcx>, + A: GenKillAnalysis<'tcx, Idx = T, Domain = D>, + D: Clone + JoinSemiLattice + GenKill + BorrowMut>, + T: Idx, { /// Creates a new `Engine` to solve a gen-kill dataflow problem. pub fn new_gen_kill( @@ -109,22 +119,26 @@ where // Otherwise, compute and store the cumulative transfer function for each block. - let bits_per_block = analysis.bits_per_block(body); - let mut trans_for_block = - IndexVec::from_elem(GenKillSet::identity(bits_per_block), body.basic_blocks()); + let identity = GenKillSet::identity(analysis.bottom_value(body).borrow().domain_size()); + let mut trans_for_block = IndexVec::from_elem(identity, body.basic_blocks()); 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); } - Self::new(tcx, body, def_id, analysis, Some(trans_for_block)) + let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| { + trans_for_block[bb].apply(state.borrow_mut()); + }); + + Self::new(tcx, body, def_id, analysis, Some(apply_trans as Box<_>)) } } -impl Engine<'a, 'tcx, A> +impl Engine<'a, 'tcx, A> where - A: Analysis<'tcx>, + A: Analysis<'tcx, Domain = D>, + D: Clone + JoinSemiLattice, { /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer /// function. @@ -145,32 +159,25 @@ where body: &'a mir::Body<'tcx>, def_id: DefId, analysis: A, - trans_for_block: Option>>, + apply_trans_for_block: Option>, ) -> Self { - let bits_per_block = analysis.bits_per_block(body); - - let bottom_value_set = if A::BOTTOM_VALUE { - BitSet::new_filled(bits_per_block) - } else { - BitSet::new_empty(bits_per_block) - }; - - let mut entry_sets = IndexVec::from_elem(bottom_value_set.clone(), body.basic_blocks()); + let bottom_value = analysis.bottom_value(body); + 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_set { + if A::Direction::is_backward() && entry_sets[mir::START_BLOCK] != bottom_value { bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } Engine { analysis, - bits_per_block, tcx, body, def_id, dead_unwinds: None, + pass_name: None, entry_sets, - trans_for_block, + apply_trans_for_block, } } @@ -184,17 +191,29 @@ where self } + /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis. + /// + /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name` + /// to differentiate them. Otherwise, only the results for the latest run will be saved. + pub fn pass_name(mut self, name: &'static str) -> Self { + self.pass_name = Some(name); + self + } + /// Computes the fixpoint for this dataflow problem and returns it. - pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> { + pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> + where + A::Domain: DebugWithContext, + { let Engine { analysis, - bits_per_block, body, dead_unwinds, def_id, mut entry_sets, tcx, - trans_for_block, + apply_trans_for_block, + pass_name, .. } = self; @@ -213,14 +232,14 @@ where } } - let mut state = BitSet::new_empty(bits_per_block); + let mut state = analysis.bottom_value(body); while let Some(bb) = dirty_queue.pop() { let bb_data = &body[bb]; // Apply the block transfer function, using the cached one if it exists. - state.overwrite(&entry_sets[bb]); - match &trans_for_block { - Some(trans_for_block) => trans_for_block[bb].apply(&mut state), + state.clone_from(&entry_sets[bb]); + match &apply_trans_for_block { + Some(apply) => apply(bb, &mut state), None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data), } @@ -231,8 +250,8 @@ where dead_unwinds, &mut state, (bb, bb_data), - |target: BasicBlock, state: &BitSet| { - let set_changed = analysis.join(&mut entry_sets[target], state); + |target: BasicBlock, state: &A::Domain| { + let set_changed = entry_sets[target].join(state); if set_changed { dirty_queue.insert(target); } @@ -242,7 +261,7 @@ where let results = Results { analysis, entry_sets }; - let res = write_graphviz_results(tcx, def_id, &body, &results, trans_for_block); + let res = write_graphviz_results(tcx, def_id, &body, &results, pass_name); if let Err(e) = res { warn!("Failed to write graphviz dataflow results: {}", e); } @@ -260,10 +279,11 @@ fn write_graphviz_results( def_id: DefId, body: &mir::Body<'tcx>, results: &Results<'tcx, A>, - block_transfer_functions: Option>>, + pass_name: Option<&'static str>, ) -> std::io::Result<()> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { let attrs = match RustcMirAttrs::parse(tcx, def_id) { Ok(attrs) => attrs, @@ -278,39 +298,38 @@ where None if tcx.sess.opts.debugging_opts.dump_mir_dataflow && dump_enabled(tcx, A::NAME, def_id) => { + // FIXME: Use some variant of `pretty::dump_path` for this let mut path = PathBuf::from(&tcx.sess.opts.debugging_opts.dump_mir_dir); + let crate_name = tcx.crate_name(def_id.krate); let item_name = ty::print::with_forced_impl_filename_line(|| { tcx.def_path(def_id).to_filename_friendly_no_crate() }); - path.push(format!("rustc.{}.{}.dot", item_name, A::NAME)); + + let pass_name = pass_name.map(|s| format!(".{}", s)).unwrap_or_default(); + + path.push(format!("{}.{}.{}{}.dot", crate_name, item_name, A::NAME, pass_name)); path } None => return Ok(()), }; - let bits_per_block = results.analysis.bits_per_block(body); - - let mut formatter: Box> = match attrs.formatter { - Some(sym::two_phase) => Box::new(graphviz::TwoPhaseDiff::new(bits_per_block)), - Some(sym::gen_kill) => { - if let Some(trans_for_block) = block_transfer_functions { - Box::new(graphviz::BlockTransferFunc::new(body, trans_for_block)) - } else { - Box::new(graphviz::SimpleDiff::new(body, &results)) - } - } - - // Default to the `SimpleDiff` output style. - _ => Box::new(graphviz::SimpleDiff::new(body, &results)), + let style = match attrs.formatter { + Some(sym::two_phase) => graphviz::OutputStyle::BeforeAndAfter, + _ => graphviz::OutputStyle::AfterOnly, }; debug!("printing dataflow results for {:?} to {}", def_id, path.display()); let mut buf = Vec::new(); - let graphviz = graphviz::Formatter::new(body, def_id, results, &mut *formatter); - dot::render_opts(&graphviz, &mut buf, &[dot::RenderOption::Monospace])?; + let graphviz = graphviz::Formatter::new(body, def_id, results, style); + let mut render_opts = + vec![dot::RenderOption::Fontname(tcx.sess.opts.debugging_opts.graphviz_font.clone())]; + if tcx.sess.opts.debugging_opts.graphviz_dark_mode { + render_opts.push(dot::RenderOption::DarkTheme); + } + dot::render_opts(&graphviz, &mut buf, &render_opts)?; if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; diff --git a/compiler/rustc_mir/src/dataflow/framework/fmt.rs b/compiler/rustc_mir/src/dataflow/framework/fmt.rs new file mode 100644 index 0000000000..0140a75054 --- /dev/null +++ b/compiler/rustc_mir/src/dataflow/framework/fmt.rs @@ -0,0 +1,172 @@ +//! Custom formatting traits used when outputting Graphviz diagrams with the results of a dataflow +//! analysis. + +use rustc_index::bit_set::{BitSet, HybridBitSet}; +use rustc_index::vec::Idx; +use std::fmt; + +/// An extension to `fmt::Debug` for data that can be better printed with some auxiliary data `C`. +pub trait DebugWithContext: Eq + fmt::Debug { + fn fmt_with(&self, _ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } + + /// Print the difference between `self` and `old`. + /// + /// This should print nothing if `self == old`. + /// + /// `+` and `-` are typically used to indicate differences. However, these characters are + /// fairly common and may be needed to print a types representation. If using them to indicate + /// a diff, prefix them with the "Unit Separator" control character (␟ U+001F). + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self == old { + return Ok(()); + } + + write!(f, "\u{001f}+")?; + self.fmt_with(ctxt, f)?; + + if f.alternate() { + write!(f, "\n")?; + } else { + write!(f, "\t")?; + } + + write!(f, "\u{001f}-")?; + self.fmt_with(ctxt, f) + } +} + +/// Implements `fmt::Debug` by deferring to `>::fmt_with`. +pub struct DebugWithAdapter<'a, T, C> { + pub this: T, + pub ctxt: &'a C, +} + +impl fmt::Debug for DebugWithAdapter<'_, T, C> +where + T: DebugWithContext, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.this.fmt_with(self.ctxt, f) + } +} + +/// Implements `fmt::Debug` by deferring to `>::fmt_diff_with`. +pub struct DebugDiffWithAdapter<'a, T, C> { + pub new: T, + pub old: T, + pub ctxt: &'a C, +} + +impl fmt::Debug for DebugDiffWithAdapter<'_, T, C> +where + T: DebugWithContext, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.new.fmt_diff_with(&self.old, self.ctxt, f) + } +} + +// Impls + +impl DebugWithContext for BitSet +where + T: Idx + DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter().map(|i| DebugWithAdapter { this: i, ctxt })).finish() + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let size = self.domain_size(); + assert_eq!(size, old.domain_size()); + + let mut set_in_self = HybridBitSet::new_empty(size); + let mut cleared_in_self = HybridBitSet::new_empty(size); + + for i in (0..size).map(T::new) { + match (self.contains(i), old.contains(i)) { + (true, false) => set_in_self.insert(i), + (false, true) => cleared_in_self.insert(i), + _ => continue, + }; + } + + let mut first = true; + for idx in set_in_self.iter() { + let delim = if first { + "\u{001f}+" + } else if f.alternate() { + "\n\u{001f}+" + } else { + ", " + }; + + write!(f, "{}", delim)?; + idx.fmt_with(ctxt, f)?; + first = false; + } + + if !f.alternate() { + first = true; + if !set_in_self.is_empty() && !cleared_in_self.is_empty() { + write!(f, "\t")?; + } + } + + for idx in cleared_in_self.iter() { + let delim = if first { + "\u{001f}-" + } else if f.alternate() { + "\n\u{001f}-" + } else { + ", " + }; + + write!(f, "{}", delim)?; + idx.fmt_with(ctxt, f)?; + first = false; + } + + Ok(()) + } +} + +impl DebugWithContext for &'_ T +where + T: DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (*self).fmt_with(ctxt, f) + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (*self).fmt_diff_with(*old, ctxt, f) + } +} + +impl DebugWithContext for rustc_middle::mir::Local {} +impl DebugWithContext for crate::dataflow::move_paths::InitIndex {} + +impl<'tcx, C> DebugWithContext for crate::dataflow::move_paths::MovePathIndex +where + C: crate::dataflow::move_paths::HasMoveData<'tcx>, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", ctxt.move_data().move_paths[*self]) + } +} + +impl DebugWithContext for crate::dataflow::lattice::Dual +where + T: DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self.0).fmt_with(ctxt, f) + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self.0).fmt_diff_with(&old.0, ctxt, f) + } +} diff --git a/src/librustc_mir/dataflow/framework/graphviz.rs b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs similarity index 53% rename from src/librustc_mir/dataflow/framework/graphviz.rs rename to compiler/rustc_mir/src/dataflow/framework/graphviz.rs index 896616a217..5d4c425196 100644 --- a/src/librustc_mir/dataflow/framework/graphviz.rs +++ b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs @@ -1,26 +1,41 @@ //! A helpful diagram for debugging dataflow problems. -use std::cell::RefCell; +use std::borrow::Cow; +use std::lazy::SyncOnceCell; use std::{io, ops, str}; +use regex::Regex; use rustc_graphviz as dot; use rustc_hir::def_id::DefId; -use rustc_index::bit_set::{BitSet, HybridBitSet}; -use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::{self, BasicBlock, Body, Location}; -use super::{Analysis, Direction, GenKillSet, Results, ResultsRefCursor}; +use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext}; +use super::{Analysis, Direction, Results, ResultsRefCursor, ResultsVisitor}; use crate::util::graphviz_safe_def_name; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum OutputStyle { + AfterOnly, + BeforeAndAfter, +} + +impl OutputStyle { + fn num_state_columns(&self) -> usize { + match self { + Self::AfterOnly => 1, + Self::BeforeAndAfter => 2, + } + } +} + pub struct Formatter<'a, 'tcx, A> where A: Analysis<'tcx>, { body: &'a Body<'tcx>, def_id: DefId, - - // This must be behind a `RefCell` because `dot::Labeller` takes `&self`. - block_formatter: RefCell>, + results: &'a Results<'tcx, A>, + style: OutputStyle, } impl Formatter<'a, 'tcx, A> @@ -31,15 +46,9 @@ where body: &'a Body<'tcx>, def_id: DefId, results: &'a Results<'tcx, A>, - state_formatter: &'a mut dyn StateFormatter<'tcx, A>, + style: OutputStyle, ) -> Self { - let block_formatter = BlockFormatter { - bg: Background::Light, - results: ResultsRefCursor::new(body, results), - state_formatter, - }; - - Formatter { body, def_id, block_formatter: RefCell::new(block_formatter) } + Formatter { body, def_id, results, style } } } @@ -62,6 +71,7 @@ fn dataflow_successors(body: &Body<'tcx>, bb: BasicBlock) -> Vec { impl dot::Labeller<'_> for Formatter<'a, 'tcx, A> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { type Node = BasicBlock; type Edge = CfgEdge; @@ -77,7 +87,13 @@ where fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { let mut label = Vec::new(); - self.block_formatter.borrow_mut().write_node_label(&mut label, self.body, *block).unwrap(); + let mut fmt = BlockFormatter { + results: ResultsRefCursor::new(self.body, self.results), + style: self.style, + bg: Background::Light, + }; + + fmt.write_node_label(&mut label, self.body, *block).unwrap(); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -126,19 +142,16 @@ where { results: ResultsRefCursor<'a, 'a, 'tcx, A>, bg: Background, - state_formatter: &'a mut dyn StateFormatter<'tcx, A>, + style: OutputStyle, } impl BlockFormatter<'a, 'tcx, A> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { const HEADER_COLOR: &'static str = "#a0a0a0"; - fn num_state_columns(&self) -> usize { - std::cmp::max(1, self.state_formatter.column_names().len()) - } - fn toggle_background(&mut self) -> Background { let bg = self.bg; self.bg = !bg; @@ -187,40 +200,30 @@ where write!(w, r#""#, fmt = table_fmt)?; // A + B: Block header - if self.state_formatter.column_names().is_empty() { - self.write_block_header_simple(w, block)?; - } else { - self.write_block_header_with_state_columns(w, block)?; + match self.style { + OutputStyle::AfterOnly => self.write_block_header_simple(w, block)?, + OutputStyle::BeforeAndAfter => { + self.write_block_header_with_state_columns(w, block, &["BEFORE", "AFTER"])? + } } // C: State at start of block self.bg = Background::Light; self.results.seek_to_block_start(block); - let block_entry_state = self.results.get().clone(); - + let block_start_state = self.results.get().clone(); self.write_row_with_full_state(w, "", "(on start)")?; - // D: Statement transfer functions - for (i, statement) in body[block].statements.iter().enumerate() { - let location = Location { block, statement_index: i }; - let statement_str = format!("{:?}", statement); - self.write_row_for_location(w, &i.to_string(), &statement_str, location)?; - } - - // E: Terminator transfer function - let terminator = body[block].terminator(); - let terminator_loc = body.terminator_loc(block); - let mut terminator_str = String::new(); - terminator.kind.fmt_head(&mut terminator_str).unwrap(); - - self.write_row_for_location(w, "T", &terminator_str, terminator_loc)?; + // D + E: Statement and terminator transfer functions + self.write_statements_and_terminator(w, body, block)?; // F: State at end of block + let terminator = body[block].terminator(); + // Write the full dataflow state immediately after the terminator if it differs from the // state at block entry. self.results.seek_to_block_end(block); - if self.results.get() != &block_entry_state || A::Direction::is_backward() { + if self.results.get() != &block_start_state || A::Direction::is_backward() { let after_terminator_name = match terminator.kind { mir::TerminatorKind::Call { destination: Some(_), .. } => "(on unwind)", _ => "(on end)", @@ -229,8 +232,11 @@ where self.write_row_with_full_state(w, "", after_terminator_name)?; } - // Write any changes caused by terminator-specific effects - let num_state_columns = self.num_state_columns(); + // Write any changes caused by terminator-specific effects. + // + // FIXME: These should really be printed as part of each outgoing edge rather than the node + // for the basic block itself. That way, we could display terminator-specific effects for + // backward dataflow analyses as well as effects for `SwitchInt` terminators. match terminator.kind { mir::TerminatorKind::Call { destination: Some((return_place, _)), @@ -239,44 +245,43 @@ where .. } => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - write!( - w, - r#""#, - colspan = num_state_columns, - fmt = fmt, - )?; - let state_on_unwind = this.results.get().clone(); this.results.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect(state, block, func, args, return_place); }); - write_diff(w, this.results.analysis(), &state_on_unwind, this.results.get())?; - write!(w, "") + write!( + w, + r#"{diff}"#, + colspan = this.style.num_state_columns(), + fmt = fmt, + diff = diff_pretty( + this.results.get(), + &state_on_unwind, + this.results.analysis() + ), + ) })?; } mir::TerminatorKind::Yield { resume, resume_arg, .. } => { self.write_row(w, "", "(on yield resume)", |this, w, fmt| { - write!( - w, - r#""#, - colspan = num_state_columns, - fmt = fmt, - )?; - let state_on_generator_drop = this.results.get().clone(); this.results.apply_custom_effect(|analysis, state| { analysis.apply_yield_resume_effect(state, resume, resume_arg); }); - write_diff( + write!( w, - this.results.analysis(), - &state_on_generator_drop, - this.results.get(), - )?; - write!(w, "") + r#"{diff}"#, + colspan = this.style.num_state_columns(), + fmt = fmt, + diff = diff_pretty( + this.results.get(), + &state_on_generator_drop, + this.results.analysis() + ), + ) })?; } @@ -322,6 +327,7 @@ where &mut self, w: &mut impl io::Write, block: BasicBlock, + state_column_names: &[&str], ) -> io::Result<()> { // +------------------------------------+-------------+ // A | bb4 | STATE | @@ -330,8 +336,6 @@ where // +-+----------------------------------+------+------+ // | | ... | | | - let state_column_names = self.state_formatter.column_names(); - // A write!( w, @@ -357,6 +361,56 @@ where write!(w, "") } + fn write_statements_and_terminator( + &mut self, + w: &mut impl io::Write, + body: &'a Body<'tcx>, + block: BasicBlock, + ) -> io::Result<()> { + let diffs = StateDiffCollector::run(body, block, self.results.results(), self.style); + + let mut befores = diffs.before.map(|v| v.into_iter()); + let mut afters = diffs.after.into_iter(); + + let next_in_dataflow_order = |it: &mut std::vec::IntoIter<_>| { + if A::Direction::is_forward() { it.next().unwrap() } else { it.next_back().unwrap() } + }; + + for (i, statement) in body[block].statements.iter().enumerate() { + let statement_str = format!("{:?}", statement); + let index_str = format!("{}", i); + + let after = next_in_dataflow_order(&mut afters); + let before = befores.as_mut().map(next_in_dataflow_order); + + self.write_row(w, &index_str, &statement_str, |_this, w, fmt| { + if let Some(before) = before { + write!(w, r#"{diff}"#, fmt = fmt, diff = before)?; + } + + write!(w, r#"{diff}"#, fmt = fmt, diff = after) + })?; + } + + let after = next_in_dataflow_order(&mut afters); + let before = befores.as_mut().map(next_in_dataflow_order); + + assert!(afters.is_empty()); + assert!(befores.as_ref().map_or(true, ExactSizeIterator::is_empty)); + + let terminator = body[block].terminator(); + let mut terminator_str = String::new(); + terminator.kind.fmt_head(&mut terminator_str).unwrap(); + + self.write_row(w, "T", &terminator_str, |_this, w, fmt| { + if let Some(before) = before { + write!(w, r#"{diff}"#, fmt = fmt, diff = before)?; + } + + write!(w, r#"{diff}"#, fmt = fmt, diff = after) + }) + } + /// Write a row with the given index and MIR, using the function argument to fill in the /// "STATE" column(s). fn write_row( @@ -397,319 +451,176 @@ where let state = this.results.get(); let analysis = this.results.analysis(); + // FIXME: The full state vector can be quite long. It would be nice to split on commas + // and use some text wrapping algorithm. write!( w, - r#"{{"#, - colspan = this.num_state_columns(), + r#"{state}"#, + colspan = this.style.num_state_columns(), fmt = fmt, - )?; - pretty_print_state_elems(w, analysis, state.iter(), ", ", LIMIT_30_ALIGN_1)?; - write!(w, "}}") - }) - } - - fn write_row_for_location( - &mut self, - w: &mut impl io::Write, - i: &str, - mir: &str, - location: Location, - ) -> io::Result<()> { - self.write_row(w, i, mir, |this, w, fmt| { - this.state_formatter.write_state_for_location(w, fmt, &mut this.results, location) + state = format!("{:?}", DebugWithAdapter { this: state, ctxt: analysis }), + ) }) } } -/// Controls what gets printed under the `STATE` header. -pub trait StateFormatter<'tcx, A> +struct StateDiffCollector<'a, 'tcx, A> where A: Analysis<'tcx>, { - /// The columns that will get printed under `STATE`. - fn column_names(&self) -> &[&str]; - - fn write_state_for_location( - &mut self, - w: &mut dyn io::Write, - fmt: &str, - results: &mut ResultsRefCursor<'_, '_, 'tcx, A>, - location: Location, - ) -> io::Result<()>; + analysis: &'a A, + prev_state: A::Domain, + before: Option>, + after: Vec, } -/// Prints a single column containing the state vector immediately *after* each statement. -pub struct SimpleDiff<'a, 'tcx, A> +impl StateDiffCollector<'a, 'tcx, A> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { - prev_state: ResultsRefCursor<'a, 'a, 'tcx, A>, -} + fn run( + body: &'a mir::Body<'tcx>, + block: BasicBlock, + results: &'a Results<'tcx, A>, + style: OutputStyle, + ) -> Self { + let mut collector = StateDiffCollector { + analysis: &results.analysis, + prev_state: results.analysis.bottom_value(body), + after: vec![], + before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]), + }; -impl SimpleDiff<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>) -> Self { - SimpleDiff { prev_state: ResultsRefCursor::new(body, results) } + results.visit_with(body, std::iter::once(block), &mut collector); + collector } } -impl StateFormatter<'tcx, A> for SimpleDiff<'_, 'tcx, A> +impl ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { - fn column_names(&self) -> &[&str] { - &[] - } + type FlowState = A::Domain; - fn write_state_for_location( + fn visit_block_start( &mut self, - mut w: &mut dyn io::Write, - fmt: &str, - results: &mut ResultsRefCursor<'_, '_, 'tcx, A>, - location: Location, - ) -> io::Result<()> { + state: &Self::FlowState, + _block_data: &'mir mir::BasicBlockData<'tcx>, + _block: BasicBlock, + ) { if A::Direction::is_forward() { - if location.statement_index == 0 { - self.prev_state.seek_to_block_start(location.block); - } else { - self.prev_state.seek_after_primary_effect(Location { - statement_index: location.statement_index - 1, - ..location - }); - } - } else { - if location == results.body().terminator_loc(location.block) { - self.prev_state.seek_to_block_end(location.block); - } else { - self.prev_state.seek_after_primary_effect(location.successor_within_block()); - } + self.prev_state.clone_from(state); } - - write!(w, r#""#, fmt = fmt)?; - results.seek_after_primary_effect(location); - let curr_state = results.get(); - write_diff(&mut w, results.analysis(), self.prev_state.get(), curr_state)?; - write!(w, "") } -} -/// Prints two state columns, one containing only the "before" effect of each statement and one -/// containing the full effect. -pub struct TwoPhaseDiff { - prev_state: BitSet, - prev_loc: Location, -} + fn visit_block_end( + &mut self, + state: &Self::FlowState, + _block_data: &'mir mir::BasicBlockData<'tcx>, + _block: BasicBlock, + ) { + if A::Direction::is_backward() { + self.prev_state.clone_from(state); + } + } -impl TwoPhaseDiff { - pub fn new(bits_per_block: usize) -> Self { - TwoPhaseDiff { prev_state: BitSet::new_empty(bits_per_block), prev_loc: Location::START } + fn visit_statement_before_primary_effect( + &mut self, + state: &Self::FlowState, + _statement: &'mir mir::Statement<'tcx>, + _location: Location, + ) { + if let Some(before) = self.before.as_mut() { + before.push(diff_pretty(state, &self.prev_state, self.analysis)); + self.prev_state.clone_from(state) + } } -} -impl StateFormatter<'tcx, A> for TwoPhaseDiff -where - A: Analysis<'tcx>, -{ - fn column_names(&self) -> &[&str] { - &["BEFORE", " AFTER"] + fn visit_statement_after_primary_effect( + &mut self, + state: &Self::FlowState, + _statement: &'mir mir::Statement<'tcx>, + _location: Location, + ) { + self.after.push(diff_pretty(state, &self.prev_state, self.analysis)); + self.prev_state.clone_from(state) } - fn write_state_for_location( + fn visit_terminator_before_primary_effect( &mut self, - mut w: &mut dyn io::Write, - fmt: &str, - results: &mut ResultsRefCursor<'_, '_, 'tcx, A>, - location: Location, - ) -> io::Result<()> { - if location.statement_index == 0 { - results.seek_to_block_entry(location.block); - self.prev_state.overwrite(results.get()); - } else { - // Ensure that we are visiting statements in order, so `prev_state` is correct. - assert_eq!(self.prev_loc.successor_within_block(), location); + state: &Self::FlowState, + _terminator: &'mir mir::Terminator<'tcx>, + _location: Location, + ) { + if let Some(before) = self.before.as_mut() { + before.push(diff_pretty(state, &self.prev_state, self.analysis)); + self.prev_state.clone_from(state) } - - self.prev_loc = location; - - // Before - - write!(w, r#""#, fmt = fmt)?; - results.seek_before_primary_effect(location); - let curr_state = results.get(); - write_diff(&mut w, results.analysis(), &self.prev_state, curr_state)?; - self.prev_state.overwrite(curr_state); - write!(w, "")?; - - // After - - write!(w, r#""#, fmt = fmt)?; - results.seek_after_primary_effect(location); - let curr_state = results.get(); - write_diff(&mut w, results.analysis(), &self.prev_state, curr_state)?; - self.prev_state.overwrite(curr_state); - write!(w, "") } -} -/// Prints the gen/kill set for the entire block. -pub struct BlockTransferFunc<'a, 'tcx, T: Idx> { - body: &'a mir::Body<'tcx>, - trans_for_block: IndexVec>, + fn visit_terminator_after_primary_effect( + &mut self, + state: &Self::FlowState, + _terminator: &'mir mir::Terminator<'tcx>, + _location: Location, + ) { + self.after.push(diff_pretty(state, &self.prev_state, self.analysis)); + self.prev_state.clone_from(state) + } } -impl BlockTransferFunc<'mir, 'tcx, T> { - pub fn new( - body: &'mir mir::Body<'tcx>, - trans_for_block: IndexVec>, - ) -> Self { - BlockTransferFunc { body, trans_for_block } - } +macro_rules! regex { + ($re:literal $(,)?) => {{ + static RE: SyncOnceCell = SyncOnceCell::new(); + RE.get_or_init(|| Regex::new($re).unwrap()) + }}; } -impl StateFormatter<'tcx, A> for BlockTransferFunc<'mir, 'tcx, A::Idx> +fn diff_pretty(new: T, old: T, ctxt: &C) -> String where - A: Analysis<'tcx>, + T: DebugWithContext, { - fn column_names(&self) -> &[&str] { - &["GEN", "KILL"] + if new == old { + return String::new(); } - fn write_state_for_location( - &mut self, - mut w: &mut dyn io::Write, - fmt: &str, - results: &mut ResultsRefCursor<'_, '_, 'tcx, A>, - location: Location, - ) -> io::Result<()> { - // Only print a single row. - if location.statement_index != 0 { - return Ok(()); - } + let re = regex!("\t?\u{001f}([+-])"); - let block_trans = &self.trans_for_block[location.block]; - let rowspan = self.body.basic_blocks()[location.block].statements.len(); + let raw_diff = format!("{:#?}", DebugDiffWithAdapter { new, old, ctxt }); - for set in &[&block_trans.gen, &block_trans.kill] { - write!( - w, - r#""#, - fmt = fmt, - rowspan = rowspan - )?; + // Replace newlines in the `Debug` output with `
` + let raw_diff = raw_diff.replace('\n', r#"
"#); - pretty_print_state_elems(&mut w, results.analysis(), set.iter(), BR_LEFT, None)?; - write!(w, "")?; + let mut inside_font_tag = false; + let html_diff = re.replace_all(&raw_diff, |captures: ®ex::Captures<'_>| { + let mut ret = String::new(); + if inside_font_tag { + ret.push_str(r#""#); } - Ok(()) - } -} - -/// Writes two lines, one containing the added bits and one the removed bits. -fn write_diff>( - w: &mut impl io::Write, - analysis: &A, - from: &BitSet, - to: &BitSet, -) -> io::Result<()> { - assert_eq!(from.domain_size(), to.domain_size()); - let len = from.domain_size(); - - let mut set = HybridBitSet::new_empty(len); - let mut clear = HybridBitSet::new_empty(len); - - // FIXME: Implement a lazy iterator over the symmetric difference of two bitsets. - for i in (0..len).map(A::Idx::new) { - match (from.contains(i), to.contains(i)) { - (false, true) => set.insert(i), - (true, false) => clear.insert(i), - _ => continue, + let tag = match &captures[1] { + "+" => r#"+"#, + "-" => r#"-"#, + _ => unreachable!(), }; - } - - if !set.is_empty() { - write!(w, r#"+"#)?; - pretty_print_state_elems(w, analysis, set.iter(), ", ", LIMIT_30_ALIGN_1)?; - write!(w, r#""#)?; - } - - if !set.is_empty() && !clear.is_empty() { - write!(w, "{}", BR_LEFT)?; - } - - if !clear.is_empty() { - write!(w, r#"-"#)?; - pretty_print_state_elems(w, analysis, clear.iter(), ", ", LIMIT_30_ALIGN_1)?; - write!(w, r#""#)?; - } - - Ok(()) -} -const BR_LEFT: &str = r#"
"#; -const BR_LEFT_SPACE: &str = r#"
"#; + inside_font_tag = true; + ret.push_str(tag); + ret + }); -/// Line break policy that breaks at 40 characters and starts the next line with a single space. -const LIMIT_30_ALIGN_1: Option = Some(LineBreak { sequence: BR_LEFT_SPACE, limit: 30 }); - -struct LineBreak { - sequence: &'static str, - limit: usize, -} - -/// Formats each `elem` using the pretty printer provided by `analysis` into a list with the given -/// separator (`sep`). -/// -/// Optionally, it will break lines using the given character sequence (usually `
`) and -/// character limit. -fn pretty_print_state_elems
( - w: &mut impl io::Write, - analysis: &A, - elems: impl Iterator, - sep: &str, - line_break: Option, -) -> io::Result -where - A: Analysis<'tcx>, -{ - let sep_width = sep.chars().count(); - - let mut buf = Vec::new(); - - let mut first = true; - let mut curr_line_width = 0; - let mut line_break_inserted = false; - - for idx in elems { - buf.clear(); - analysis.pretty_print_idx(&mut buf, idx)?; - let idx_str = - str::from_utf8(&buf).expect("Output of `pretty_print_idx` must be valid UTF-8"); - let escaped = dot::escape_html(idx_str); - let escaped_width = escaped.chars().count(); - - if first { - first = false; - } else { - write!(w, "{}", sep)?; - curr_line_width += sep_width; - - if let Some(line_break) = &line_break { - if curr_line_width + sep_width + escaped_width > line_break.limit { - write!(w, "{}", line_break.sequence)?; - line_break_inserted = true; - curr_line_width = 0; - } - } - } + let mut html_diff = match html_diff { + Cow::Borrowed(_) => return raw_diff, + Cow::Owned(s) => s, + }; - write!(w, "{}", escaped)?; - curr_line_width += escaped_width; + if inside_font_tag { + html_diff.push_str(""); } - Ok(line_break_inserted) + html_diff } /// The background color used for zebra-striping the table. diff --git a/compiler/rustc_mir/src/dataflow/framework/lattice.rs b/compiler/rustc_mir/src/dataflow/framework/lattice.rs new file mode 100644 index 0000000000..e7ef9267db --- /dev/null +++ b/compiler/rustc_mir/src/dataflow/framework/lattice.rs @@ -0,0 +1,230 @@ +//! Traits used to represent [lattices] for use as the domain of a dataflow analysis. +//! +//! # Overview +//! +//! The most common lattice is a powerset of some set `S`, ordered by [set inclusion]. The [Hasse +//! diagram] for the powerset of a set with two elements (`X` and `Y`) is shown below. Note that +//! distinct elements at the same height in a Hasse diagram (e.g. `{X}` and `{Y}`) are +//! *incomparable*, not equal. +//! +//! ```text +//! {X, Y} <- top +//! / \ +//! {X} {Y} +//! \ / +//! {} <- bottom +//! +//! ``` +//! +//! The defining characteristic of a lattice—the one that differentiates it from a [partially +//! ordered set][poset]—is the existence of a *unique* least upper and greatest lower bound for +//! every pair of elements. The lattice join operator (`∨`) returns the least upper bound, and the +//! lattice meet operator (`∧`) returns the greatest lower bound. Types that implement one operator +//! but not the other are known as semilattices. Dataflow analysis only uses the join operator and +//! will work with any join-semilattice, but both should be specified when possible. +//! +//! ## `PartialOrd` +//! +//! Given that they represent partially ordered sets, you may be surprised that [`JoinSemiLattice`] +//! and [`MeetSemiLattice`] do not have [`PartialOrd`][std::cmp::PartialOrd] as a supertrait. This +//! is because most standard library types use lexicographic ordering instead of set inclusion for +//! their `PartialOrd` impl. Since we do not actually need to compare lattice elements to run a +//! dataflow analysis, there's no need for a newtype wrapper with a custom `PartialOrd` impl. The +//! only benefit would be the ability to check that the least upper (or greatest lower) bound +//! returned by the lattice join (or meet) operator was in fact greater (or lower) than the inputs. +//! +//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) +//! [set inclusion]: https://en.wikipedia.org/wiki/Subset +//! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram +//! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set + +use rustc_index::bit_set::BitSet; +use rustc_index::vec::{Idx, IndexVec}; + +/// A [partially ordered set][poset] that has a [least upper bound][lub] for any pair of elements +/// in the set. +/// +/// [lub]: https://en.wikipedia.org/wiki/Infimum_and_supremum +/// [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set +pub trait JoinSemiLattice: Eq { + /// Computes the least upper bound of two elements, storing the result in `self` and returning + /// `true` if `self` has changed. + /// + /// The lattice join operator is abbreviated as `∨`. + fn join(&mut self, other: &Self) -> bool; +} + +/// A [partially ordered set][poset] that has a [greatest lower bound][glb] for any pair of +/// elements in the set. +/// +/// Dataflow analyses only require that their domains implement [`JoinSemiLattice`], not +/// `MeetSemiLattice`. However, types that will be used as dataflow domains should implement both +/// so that they can be used with [`Dual`]. +/// +/// [glb]: https://en.wikipedia.org/wiki/Infimum_and_supremum +/// [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set +pub trait MeetSemiLattice: Eq { + /// Computes the greatest lower bound of two elements, storing the result in `self` and + /// returning `true` if `self` has changed. + /// + /// The lattice meet operator is abbreviated as `∧`. + fn meet(&mut self, other: &Self) -> bool; +} + +/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom: +/// +/// ```text +/// true +/// | +/// false +/// ``` +impl JoinSemiLattice for bool { + fn join(&mut self, other: &Self) -> bool { + if let (false, true) = (*self, *other) { + *self = true; + return true; + } + + false + } +} + +impl MeetSemiLattice for bool { + fn meet(&mut self, other: &Self) -> bool { + if let (true, false) = (*self, *other) { + *self = false; + return true; + } + + false + } +} + +/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation +/// of the least upper bounds of each element of the tuple (or list). +/// +/// In other words: +/// (A₀, A₁, ..., Aₙ) ∨ (B₀, B₁, ..., Bₙ) = (A₀∨B₀, A₁∨B₁, ..., Aₙ∨Bₙ) +impl JoinSemiLattice for IndexVec { + fn join(&mut self, other: &Self) -> bool { + assert_eq!(self.len(), other.len()); + + let mut changed = false; + for (a, b) in self.iter_mut().zip(other.iter()) { + changed |= a.join(b); + } + changed + } +} + +impl MeetSemiLattice for IndexVec { + fn meet(&mut self, other: &Self) -> bool { + assert_eq!(self.len(), other.len()); + + let mut changed = false; + for (a, b) in self.iter_mut().zip(other.iter()) { + changed |= a.meet(b); + } + changed + } +} + +/// A `BitSet` represents the lattice formed by the powerset of all possible values of +/// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices, +/// one for each possible value of `T`. +impl JoinSemiLattice for BitSet { + fn join(&mut self, other: &Self) -> bool { + self.union(other) + } +} + +impl MeetSemiLattice for BitSet { + fn meet(&mut self, other: &Self) -> bool { + self.intersect(other) + } +} + +/// The counterpart of a given semilattice `T` using the [inverse order]. +/// +/// The dual of a join-semilattice is a meet-semilattice and vice versa. For example, the dual of a +/// powerset has the empty set as its top element and the full set as its bottom element and uses +/// set *intersection* as its join operator. +/// +/// [inverse order]: https://en.wikipedia.org/wiki/Duality_(order_theory) +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Dual(pub T); + +impl std::borrow::Borrow for Dual { + fn borrow(&self) -> &T { + &self.0 + } +} + +impl std::borrow::BorrowMut for Dual { + fn borrow_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl JoinSemiLattice for Dual { + fn join(&mut self, other: &Self) -> bool { + self.0.meet(&other.0) + } +} + +impl MeetSemiLattice for Dual { + fn meet(&mut self, other: &Self) -> bool { + self.0.join(&other.0) + } +} + +/// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no +/// value of `T` is comparable with any other. A flat set has the following [Hasse diagram]: +/// +/// ```text +/// top +/// / / \ \ +/// all possible values of `T` +/// \ \ / / +/// bottom +/// ``` +/// +/// [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FlatSet { + Bottom, + Elem(T), + Top, +} + +impl JoinSemiLattice for FlatSet { + fn join(&mut self, other: &Self) -> bool { + let result = match (&*self, other) { + (Self::Top, _) | (_, Self::Bottom) => return false, + (Self::Elem(a), Self::Elem(b)) if a == b => return false, + + (Self::Bottom, Self::Elem(x)) => Self::Elem(x.clone()), + + _ => Self::Top, + }; + + *self = result; + true + } +} + +impl MeetSemiLattice for FlatSet { + fn meet(&mut self, other: &Self) -> bool { + let result = match (&*self, other) { + (Self::Bottom, _) | (_, Self::Top) => return false, + (Self::Elem(ref a), Self::Elem(ref b)) if a == b => return false, + + (Self::Top, Self::Elem(ref x)) => Self::Elem(x.clone()), + + _ => Self::Bottom, + }; + + *self = result; + true + } +} diff --git a/src/librustc_mir/dataflow/framework/mod.rs b/compiler/rustc_mir/src/dataflow/framework/mod.rs similarity index 76% rename from src/librustc_mir/dataflow/framework/mod.rs rename to compiler/rustc_mir/src/dataflow/framework/mod.rs index a21bbacb46..65c159e6a7 100644 --- a/src/librustc_mir/dataflow/framework/mod.rs +++ b/compiler/rustc_mir/src/dataflow/framework/mod.rs @@ -30,82 +30,39 @@ //! //! [gen-kill]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems +use std::borrow::BorrowMut; use std::cmp::Ordering; -use std::io; use rustc_hir::def_id::DefId; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_index::vec::Idx; use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_target::abi::VariantIdx; +use rustc_middle::ty::TyCtxt; mod cursor; mod direction; mod engine; +pub mod fmt; mod graphviz; +pub mod lattice; mod visitor; pub use self::cursor::{ResultsCursor, ResultsRefCursor}; pub use self::direction::{Backward, Direction, Forward}; pub use self::engine::{Engine, Results}; +pub use self::lattice::{JoinSemiLattice, MeetSemiLattice}; pub use self::visitor::{visit_results, ResultsVisitor}; pub use self::visitor::{BorrowckFlowState, BorrowckResults}; -/// Parameterization for the precise form of data flow that is used. -/// -/// `BottomValue` determines whether the initial entry set for each basic block is empty or full. -/// This also determines the semantics of the lattice `join` operator used to merge dataflow -/// results, since dataflow works by starting at the bottom and moving monotonically to a fixed -/// point. -/// -/// This means, for propagation across the graph, that you either want to start at all-zeroes and -/// then use Union as your merge when propagating, or you start at all-ones and then use Intersect -/// as your merge when propagating. -pub trait BottomValue { - /// Specifies the initial value for each bit in the entry set for each basic block. - const BOTTOM_VALUE: bool; - - /// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed. - /// - /// It is almost certainly wrong to override this, since it automatically applies - /// * `inout_set & in_set` if `BOTTOM_VALUE == true` - /// * `inout_set | in_set` if `BOTTOM_VALUE == false` - /// - /// This means that if a bit is not `BOTTOM_VALUE`, it is propagated into all target blocks. - /// For clarity, the above statement again from a different perspective: - /// A bit in the block's entry set is `!BOTTOM_VALUE` if *any* predecessor block's bit value is - /// `!BOTTOM_VALUE`. - /// - /// There are situations where you want the opposite behaviour: propagate only if *all* - /// predecessor blocks's value is `!BOTTOM_VALUE`. - /// E.g. if you want to know whether a bit is *definitely* set at a specific location. This - /// means that all code paths leading to the location must have set the bit, instead of any - /// code path leading there. - /// - /// If you want this kind of "definitely set" analysis, you need to - /// 1. Invert `BOTTOM_VALUE` - /// 2. Reset the `entry_set` in `start_block_effect` to `!BOTTOM_VALUE` - /// 3. Override `join` to do the opposite from what it's doing now. - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) } - } -} - /// Define the domain of a dataflow problem. /// -/// This trait specifies the lattice on which this analysis operates. For now, this must be a -/// powerset of values of type `Idx`. The elements of this lattice are represented with a `BitSet` -/// and referred to as the state vector. -/// -/// This trait also defines the initial value for the dataflow state upon entry to the -/// `START_BLOCK`, as well as some names used to refer to this analysis when debugging. -pub trait AnalysisDomain<'tcx>: BottomValue { - /// The type of the elements in the state vector. - type Idx: Idx; +/// This trait specifies the lattice on which this analysis operates (the domain) as well as its +/// initial value at the entry point of each basic block. +pub trait AnalysisDomain<'tcx> { + /// The type that holds the dataflow state at any given point in the program. + type Domain: Clone + JoinSemiLattice; - /// The direction of this analyis. Either `Forward` or `Backward`. + /// The direction of this analysis. Either `Forward` or `Backward`. type Direction: Direction = Forward; /// A descriptive name for this analysis. Used only for debugging. @@ -114,11 +71,10 @@ pub trait AnalysisDomain<'tcx>: BottomValue { /// suitable as part of a filename. const NAME: &'static str; - /// The size of the state vector. - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize; + /// The initial value of the dataflow state upon entry to each basic block. + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain; - /// Mutates the entry set of the `START_BLOCK` to contain the initial state for dataflow - /// analysis. + /// Mutates the initial value of the dataflow state upon entry to the `START_BLOCK`. /// /// For backward analyses, initial state besides the bottom value is not yet supported. Trying /// to mutate the initial state will result in a panic. @@ -126,20 +82,30 @@ pub trait AnalysisDomain<'tcx>: BottomValue { // FIXME: For backward dataflow analyses, the initial state should be applied to every basic // block where control flow could exit the MIR body (e.g., those terminated with `return` or // `resume`). It's not obvious how to handle `yield` points in generators, however. - fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet); - - /// Prints an element in the state vector for debugging. - fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> { - write!(w, "{:?}", idx) - } + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain); } /// A dataflow problem with an arbitrarily complex transfer function. +/// +/// # Convergence +/// +/// When implementing this trait directly (not via [`GenKillAnalysis`]), it's possible to choose a +/// transfer function such that the analysis does not reach fixpoint. To guarantee convergence, +/// your transfer functions must maintain the following invariant: +/// +/// > If the dataflow state **before** some point in the program changes to be greater +/// than the prior state **before** that point, the dataflow state **after** that point must +/// also change to be greater than the prior state **after** that point. +/// +/// This invariant guarantees that the dataflow state at a given point in the program increases +/// monotonically until fixpoint is reached. Note that this monotonicity requirement only applies +/// to the same point in the program at different points in time. The dataflow state at a given +/// point in the program may or may not be greater than the state at any preceding point. pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// Updates the current dataflow state with the effect of evaluating a statement. fn apply_statement_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ); @@ -152,7 +118,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// analyses should not implement this without implementing `apply_statement_effect`. fn apply_before_statement_effect( &self, - _state: &mut BitSet, + _state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -166,7 +132,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// initialized here. fn apply_terminator_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ); @@ -179,12 +145,14 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// analyses should not implement this without implementing `apply_terminator_effect`. fn apply_before_terminator_effect( &self, - _state: &mut BitSet, + _state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { } + /* Edge-specific effects */ + /// Updates the current dataflow state with the effect of a successful return from a `Call` /// terminator. /// @@ -192,7 +160,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// edges. fn apply_call_return_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, block: BasicBlock, func: &mir::Operand<'tcx>, args: &[mir::Operand<'tcx>], @@ -207,7 +175,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// By default, no effects happen. fn apply_yield_resume_effect( &self, - _state: &mut BitSet, + _state: &mut Self::Domain, _resume_block: BasicBlock, _resume_place: mir::Place<'tcx>, ) { @@ -216,20 +184,28 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// Updates the current dataflow state with the effect of taking a particular branch in a /// `SwitchInt` terminator. /// - /// Much like `apply_call_return_effect`, this effect is only propagated along a single - /// outgoing edge from this basic block. + /// Unlike the other edge-specific effects, which are allowed to mutate `Self::Domain` + /// directly, overriders of this method must pass a callback to + /// `SwitchIntEdgeEffects::apply`. The callback will be run once for each outgoing edge and + /// will have access to the dataflow state that will be propagated along that edge. + /// + /// This interface is somewhat more complex than the other visitor-like "effect" methods. + /// However, it is both more ergonomic—callers don't need to recompute or cache information + /// about a given `SwitchInt` terminator for each one of its edges—and more efficient—the + /// engine doesn't need to clone the exit state for a block unless + /// `SwitchIntEdgeEffects::apply` is actually called. /// /// FIXME: This class of effects is not supported for backward dataflow analyses. - fn apply_discriminant_switch_effect( + fn apply_switch_int_edge_effects( &self, - _state: &mut BitSet, _block: BasicBlock, - _enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - _variant: VariantIdx, + _discr: &mir::Operand<'tcx>, + _apply_edge_effects: &mut impl SwitchIntEdgeEffects, ) { } + /* Extension methods */ + /// Creates an `Engine` to find the fixpoint for this dataflow problem. /// /// You shouldn't need to override this outside this module, since the combination of the @@ -264,6 +240,8 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// /// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis`. pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { + type Idx: Idx; + /// See `Analysis::apply_statement_effect`. fn statement_effect( &self, @@ -298,6 +276,8 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { ) { } + /* Edge-specific effects */ + /// See `Analysis::apply_call_return_effect`. fn call_return_effect( &self, @@ -317,14 +297,12 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { ) { } - /// See `Analysis::apply_discriminant_switch_effect`. - fn discriminant_switch_effect( + /// See `Analysis::apply_switch_int_edge_effects`. + fn switch_int_edge_effects>( &self, - _state: &mut impl GenKill, _block: BasicBlock, - _enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - _variant: VariantIdx, + _discr: &mir::Operand<'tcx>, + _edge_effects: &mut impl SwitchIntEdgeEffects, ) { } } @@ -332,10 +310,11 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { impl Analysis<'tcx> for A where A: GenKillAnalysis<'tcx>, + A::Domain: GenKill + BorrowMut>, { fn apply_statement_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { @@ -344,7 +323,7 @@ where fn apply_before_statement_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { @@ -353,7 +332,7 @@ where fn apply_terminator_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ) { @@ -362,16 +341,18 @@ where fn apply_before_terminator_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ) { self.before_terminator_effect(state, terminator, location); } + /* Edge-specific effects */ + fn apply_call_return_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, func: &mir::Operand<'tcx>, args: &[mir::Operand<'tcx>], @@ -382,24 +363,24 @@ where fn apply_yield_resume_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, resume_block: BasicBlock, resume_place: mir::Place<'tcx>, ) { self.yield_resume_effect(state, resume_block, resume_place); } - fn apply_discriminant_switch_effect( + fn apply_switch_int_edge_effects( &self, - state: &mut BitSet, block: BasicBlock, - enum_place: mir::Place<'tcx>, - adt: &ty::AdtDef, - variant: VariantIdx, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { - self.discriminant_switch_effect(state, block, enum_place, adt, variant); + self.switch_int_edge_effects(block, discr, edge_effects); } + /* Extension methods */ + fn into_engine( self, tcx: TyCtxt<'tcx>, @@ -450,7 +431,7 @@ pub trait GenKill { /// applied multiple times efficiently. When there are multiple calls to `gen` and/or `kill` for /// the same element, the most recent one takes precedence. #[derive(Clone)] -pub struct GenKillSet { +pub struct GenKillSet { gen: HybridBitSet, kill: HybridBitSet, } @@ -464,7 +445,6 @@ impl GenKillSet { } } - /// Applies this transfer function to the given state vector. pub fn apply(&self, state: &mut BitSet) { state.union(&self.gen); state.subtract(&self.kill); @@ -493,6 +473,16 @@ impl GenKill for BitSet { } } +impl GenKill for lattice::Dual> { + fn gen(&mut self, elem: T) { + self.0.insert(elem); + } + + fn kill(&mut self, elem: T) { + self.0.remove(elem); + } +} + // NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Effect { @@ -552,5 +542,17 @@ impl EffectIndex { } } +pub struct SwitchIntTarget { + pub value: Option, + pub target: BasicBlock, +} + +/// A type that records the edge-specific effects for a `SwitchInt` terminator. +pub trait SwitchIntEdgeEffects { + /// Calls `apply_edge_effect` for each outgoing edge from a `SwitchInt` terminator and + /// records the results. + fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)); +} + #[cfg(test)] mod tests; diff --git a/src/librustc_mir/dataflow/framework/tests.rs b/compiler/rustc_mir/src/dataflow/framework/tests.rs similarity index 93% rename from src/librustc_mir/dataflow/framework/tests.rs rename to compiler/rustc_mir/src/dataflow/framework/tests.rs index 9349f5133a..a598912167 100644 --- a/src/librustc_mir/dataflow/framework/tests.rs +++ b/compiler/rustc_mir/src/dataflow/framework/tests.rs @@ -9,7 +9,6 @@ use rustc_middle::ty; use rustc_span::DUMMY_SP; use super::*; -use crate::dataflow::BottomValue; /// Creates a `mir::Body` with a few disconnected basic blocks. /// @@ -92,13 +91,13 @@ impl MockAnalysis<'tcx, D> { /// The entry set for each `BasicBlock` is the ID of that block offset by a fixed amount to /// avoid colliding with the statement/terminator effects. fn mock_entry_set(&self, bb: BasicBlock) -> BitSet { - let mut ret = BitSet::new_empty(self.bits_per_block(self.body)); + let mut ret = self.bottom_value(self.body); ret.insert(Self::BASIC_BLOCK_OFFSET + bb.index()); ret } fn mock_entry_sets(&self) -> IndexVec> { - let empty = BitSet::new_empty(self.bits_per_block(self.body)); + let empty = self.bottom_value(self.body); let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks()); for (bb, _) in self.body.basic_blocks().iter_enumerated() { @@ -130,7 +129,7 @@ impl MockAnalysis<'tcx, D> { /// would be `[102, 0, 1, 2, 3, 4]`. fn expected_state_at_target(&self, target: SeekTarget) -> BitSet { let block = target.block(); - let mut ret = BitSet::new_empty(self.bits_per_block(self.body)); + let mut ret = self.bottom_value(self.body); ret.insert(Self::BASIC_BLOCK_OFFSET + block.index()); let target = match target { @@ -161,21 +160,17 @@ impl MockAnalysis<'tcx, D> { } } -impl BottomValue for MockAnalysis<'tcx, D> { - const BOTTOM_VALUE: bool = false; -} - impl AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> { - type Idx = usize; + type Domain = BitSet; type Direction = D; const NAME: &'static str = "mock"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - Self::BASIC_BLOCK_OFFSET + body.basic_blocks().len() + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + BitSet::new_empty(Self::BASIC_BLOCK_OFFSET + body.basic_blocks().len()) } - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint"); } } @@ -183,7 +178,7 @@ impl AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> { impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_statement_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { @@ -193,7 +188,7 @@ impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_before_statement_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { @@ -203,7 +198,7 @@ impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_terminator_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, location: Location, ) { @@ -213,7 +208,7 @@ impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_before_terminator_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, location: Location, ) { @@ -223,7 +218,7 @@ impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_call_return_effect( &self, - _state: &mut BitSet, + _state: &mut Self::Domain, _block: BasicBlock, _func: &mir::Operand<'tcx>, _args: &[mir::Operand<'tcx>], diff --git a/src/librustc_mir/dataflow/framework/visitor.rs b/compiler/rustc_mir/src/dataflow/framework/visitor.rs similarity index 95% rename from src/librustc_mir/dataflow/framework/visitor.rs rename to compiler/rustc_mir/src/dataflow/framework/visitor.rs index 257f3cb9a6..82eb734ed0 100644 --- a/src/librustc_mir/dataflow/framework/visitor.rs +++ b/compiler/rustc_mir/src/dataflow/framework/visitor.rs @@ -1,4 +1,3 @@ -use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, BasicBlock, Location}; use super::{Analysis, Direction, Results}; @@ -139,16 +138,16 @@ impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A> where A: Analysis<'tcx>, { - type FlowState = BitSet; + type FlowState = A::Domain; type Direction = A::Direction; fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { - BitSet::new_empty(self.analysis.bits_per_block(body)) + self.analysis.bottom_value(body) } fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { - state.overwrite(&self.entry_set_for_block(block)); + state.clone_from(&self.entry_set_for_block(block)); } fn reconstruct_before_statement_effect( @@ -217,11 +216,11 @@ macro_rules! impl_visitable { $( $A: Analysis<'tcx, Direction = D>, )* { type Direction = D; - type FlowState = $T<$( BitSet<$A::Idx> ),*>; + type FlowState = $T<$( $A::Domain ),*>; fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { $T { - $( $field: BitSet::new_empty(self.$field.analysis.bits_per_block(body)) ),* + $( $field: self.$field.analysis.bottom_value(body) ),* } } @@ -230,7 +229,7 @@ macro_rules! impl_visitable { state: &mut Self::FlowState, block: BasicBlock, ) { - $( state.$field.overwrite(&self.$field.entry_set_for_block(block)); )* + $( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )* } fn reconstruct_before_statement_effect( diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs similarity index 97% rename from src/librustc_mir/dataflow/impls/borrowed_locals.rs rename to compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs index a3fc51cad6..65e04ed683 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs @@ -82,15 +82,15 @@ impl AnalysisDomain<'tcx> for MaybeBorrowedLocals where K: BorrowAnalysisKind<'tcx>, { - type Idx = Local; - + type Domain = BitSet; const NAME: &'static str = K::ANALYSIS_NAME; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls().len() + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = unborrowed + BitSet::new_empty(body.local_decls().len()) } - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { // No locals are aliased on function entry } } @@ -99,6 +99,8 @@ impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals where K: BorrowAnalysisKind<'tcx>, { + type Idx = Local; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -128,11 +130,6 @@ where } } -impl BottomValue for MaybeBorrowedLocals { - // bottom = unborrowed - const BOTTOM_VALUE: bool = false; -} - /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`. struct TransferFunction<'a, T, K> { trans: &'a mut T, diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/compiler/rustc_mir/src/dataflow/impls/borrows.rs similarity index 96% rename from src/librustc_mir/dataflow/impls/borrows.rs rename to compiler/rustc_mir/src/dataflow/impls/borrows.rs index aeb7ffe3e3..0be13b6ba8 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/compiler/rustc_mir/src/dataflow/impls/borrows.rs @@ -8,9 +8,9 @@ use rustc_index::bit_set::BitSet; use crate::borrow_check::{ places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid, }; -use crate::dataflow::BottomValue; -use crate::dataflow::{self, GenKill}; +use crate::dataflow::{self, fmt::DebugWithContext, GenKill}; +use std::fmt; use std::rc::Rc; rustc_index::newtype_index! { @@ -227,25 +227,24 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { } impl<'tcx> dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { - type Idx = BorrowIndex; + type Domain = BitSet; const NAME: &'static str = "borrows"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.borrow_set.len() * 2 + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = nothing is reserved or activated yet; + BitSet::new_empty(self.borrow_set.len() * 2) } - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { // no borrows of code region_scopes have been taken prior to // function execution, so this method has no effect. } - - fn pretty_print_idx(&self, w: &mut impl std::io::Write, idx: Self::Idx) -> std::io::Result<()> { - write!(w, "{:?}", self.location(idx)) - } } impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { + type Idx = BorrowIndex; + fn before_statement_effect( &self, trans: &mut impl GenKill, @@ -344,7 +343,8 @@ impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } } -impl<'a, 'tcx> BottomValue for Borrows<'a, 'tcx> { - /// bottom = nothing is reserved or activated yet; - const BOTTOM_VALUE: bool = false; +impl DebugWithContext> for BorrowIndex { + fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", ctxt.location(*self)) + } } diff --git a/src/librustc_mir/dataflow/impls/init_locals.rs b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs similarity index 91% rename from src/librustc_mir/dataflow/impls/init_locals.rs rename to compiler/rustc_mir/src/dataflow/impls/init_locals.rs index 0e7cd1bb0e..bb7292cd03 100644 --- a/src/librustc_mir/dataflow/impls/init_locals.rs +++ b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs @@ -2,7 +2,7 @@ //! //! A local will be maybe initialized if *any* projections of that local might be initialized. -use crate::dataflow::{self, BottomValue, GenKill}; +use crate::dataflow::{self, GenKill}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{PlaceContext, Visitor}; @@ -10,21 +10,17 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location}; pub struct MaybeInitializedLocals; -impl BottomValue for MaybeInitializedLocals { - /// bottom = uninit - const BOTTOM_VALUE: bool = false; -} - impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals { - type Idx = Local; + type Domain = BitSet; const NAME: &'static str = "maybe_init_locals"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = uninit + BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut BitSet) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut Self::Domain) { // Function arguments are initialized to begin with. for arg in body.args_iter() { entry_set.insert(arg); @@ -33,6 +29,8 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals { } impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals { + type Idx = Local; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -99,7 +97,6 @@ where PlaceContext::NonUse( NonUseContext::StorageLive | NonUseContext::AscribeUserTy - | NonUseContext::Coverage | NonUseContext::VarDebugInfo, ) | PlaceContext::NonMutatingUse( diff --git a/src/librustc_mir/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs similarity index 94% rename from src/librustc_mir/dataflow/impls/liveness.rs rename to compiler/rustc_mir/src/dataflow/impls/liveness.rs index 784b0bd929..b0da28156d 100644 --- a/src/librustc_mir/dataflow/impls/liveness.rs +++ b/compiler/rustc_mir/src/dataflow/impls/liveness.rs @@ -2,7 +2,7 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, Local, Location}; -use crate::dataflow::{AnalysisDomain, Backward, BottomValue, GenKill, GenKillAnalysis}; +use crate::dataflow::{AnalysisDomain, Backward, GenKill, GenKillAnalysis}; /// A [live-variable dataflow analysis][liveness]. /// @@ -22,27 +22,25 @@ impl MaybeLiveLocals { } } -impl BottomValue for MaybeLiveLocals { - // bottom = not live - const BOTTOM_VALUE: bool = false; -} - impl AnalysisDomain<'tcx> for MaybeLiveLocals { - type Idx = Local; + type Domain = BitSet; type Direction = Backward; const NAME: &'static str = "liveness"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = not live + BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { // No variables are live until we observe a use } } impl GenKillAnalysis<'tcx> for MaybeLiveLocals { + type Idx = Local; + fn statement_effect( &self, trans: &mut impl GenKill, diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/compiler/rustc_mir/src/dataflow/impls/mod.rs similarity index 74% rename from src/librustc_mir/dataflow/impls/mod.rs rename to compiler/rustc_mir/src/dataflow/impls/mod.rs index 8975faec48..185f0edfeb 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/compiler/rustc_mir/src/dataflow/impls/mod.rs @@ -6,19 +6,19 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_middle::mir::{self, Body, Location}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_target::abi::VariantIdx; use super::MoveDataParamEnv; use crate::util::elaborate_drops::DropFlagState; use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex}; -use super::{AnalysisDomain, BottomValue, GenKill, GenKillAnalysis}; +use super::{lattice, AnalysisDomain, GenKill, GenKillAnalysis}; use super::drop_flag_effects_for_function_entry; use super::drop_flag_effects_for_location; use super::on_lookup_result_bits; use crate::dataflow::drop_flag_effects; +use crate::dataflow::framework::SwitchIntEdgeEffects; mod borrowed_locals; pub(super) mod borrows; @@ -204,7 +204,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { /// `EverInitializedPlaces` tracks all places that might have ever been /// initialized upon reaching a particular point in the control flow -/// for a function, without an intervening `Storage Dead`. +/// for a function, without an intervening `StorageDead`. /// /// This dataflow is used to determine if an immutable local variable may /// be assigned to. @@ -290,27 +290,25 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - + type Domain = BitSet; const NAME: &'static str = "maybe_init"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.move_data().move_paths.len() + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = uninitialized + BitSet::new_empty(self.move_data().move_paths.len()) } - fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); state.insert(path); }); } - - fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { - write!(w, "{}", self.move_data().move_paths[mpi]) - } } impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -354,40 +352,66 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { ); } - fn discriminant_switch_effect( + fn switch_int_edge_effects>( &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - variant: VariantIdx, + block: mir::BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { - // Kill all move paths that correspond to variants we know to be inactive along this - // particular outgoing edge of a `SwitchInt`. - drop_flag_effects::on_all_inactive_variants( - self.tcx, - self.body, - self.move_data(), - enum_place, - variant, - |mpi| trans.kill(mpi), - ); + if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { + return; + } + + let enum_ = discr.place().and_then(|discr| { + switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) + }); + + let (enum_place, enum_def) = match enum_ { + Some(x) => x, + None => return, + }; + + let mut discriminants = enum_def.discriminants(self.tcx); + edge_effects.apply(|trans, edge| { + let value = match edge.value { + Some(x) => x, + None => return, + }; + + // MIR building adds discriminants to the `values` array in the same order as they + // are yielded by `AdtDef::discriminants`. We rely on this to match each + // discriminant in `values` to its corresponding variant in linear time. + let (variant, _) = discriminants + .find(|&(_, discr)| discr.val == value) + .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); + + // Kill all move paths that correspond to variants we know to be inactive along this + // particular outgoing edge of a `SwitchInt`. + drop_flag_effects::on_all_inactive_variants( + self.tcx, + self.body, + self.move_data(), + enum_place, + variant, + |mpi| trans.kill(mpi), + ); + }); } } impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; + type Domain = BitSet; const NAME: &'static str = "maybe_uninit"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.move_data().move_paths.len() + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = initialized (start_block_effect counters this at outset) + BitSet::new_empty(self.move_data().move_paths.len()) } // sets on_entry bits for Arg places - fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { // set all bits to 1 (uninit) before gathering counterevidence - assert!(self.bits_per_block(body) == state.domain_size()); state.insert_all(); drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { @@ -395,13 +419,11 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { state.remove(path); }); } - - fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { - write!(w, "{}", self.move_data().move_paths[mpi]) - } } impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -445,56 +467,82 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { ); } - fn discriminant_switch_effect( + fn switch_int_edge_effects>( &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - variant: VariantIdx, + block: mir::BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { + if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { + return; + } + if !self.mark_inactive_variants_as_uninit { return; } - // Mark all move paths that correspond to variants other than this one as maybe - // uninitialized (in reality, they are *definitely* uninitialized). - drop_flag_effects::on_all_inactive_variants( - self.tcx, - self.body, - self.move_data(), - enum_place, - variant, - |mpi| trans.gen(mpi), - ); + let enum_ = discr.place().and_then(|discr| { + switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) + }); + + let (enum_place, enum_def) = match enum_ { + Some(x) => x, + None => return, + }; + + let mut discriminants = enum_def.discriminants(self.tcx); + edge_effects.apply(|trans, edge| { + let value = match edge.value { + Some(x) => x, + None => return, + }; + + // MIR building adds discriminants to the `values` array in the same order as they + // are yielded by `AdtDef::discriminants`. We rely on this to match each + // discriminant in `values` to its corresponding variant in linear time. + let (variant, _) = discriminants + .find(|&(_, discr)| discr.val == value) + .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); + + // Mark all move paths that correspond to variants other than this one as maybe + // uninitialized (in reality, they are *definitely* uninitialized). + drop_flag_effects::on_all_inactive_variants( + self.tcx, + self.body, + self.move_data(), + enum_place, + variant, + |mpi| trans.gen(mpi), + ); + }); } } impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { - type Idx = MovePathIndex; + /// Use set intersection as the join operator. + type Domain = lattice::Dual>; const NAME: &'static str = "definite_init"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.move_data().move_paths.len() + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = initialized (start_block_effect counters this at outset) + lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len())) } // sets on_entry bits for Arg places - fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet) { - state.clear(); + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { + state.0.clear(); drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - state.insert(path); + state.0.insert(path); }); } - - fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { - write!(w, "{}", self.move_data().move_paths[mpi]) - } } impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -540,15 +588,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { } impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { - type Idx = InitIndex; + type Domain = BitSet; const NAME: &'static str = "ever_init"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.move_data().inits.len() + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = no initialized variables by default + BitSet::new_empty(self.move_data().inits.len()) } - fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { for arg_init in 0..body.arg_count { state.insert(InitIndex::new(arg_init)); } @@ -556,6 +605,8 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { } impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { + type Idx = InitIndex; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -626,22 +677,41 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } } -impl<'a, 'tcx> BottomValue for MaybeInitializedPlaces<'a, 'tcx> { - /// bottom = uninitialized - const BOTTOM_VALUE: bool = false; -} - -impl<'a, 'tcx> BottomValue for MaybeUninitializedPlaces<'a, 'tcx> { - /// bottom = initialized (start_block_effect counters this at outset) - const BOTTOM_VALUE: bool = false; -} - -impl<'a, 'tcx> BottomValue for DefinitelyInitializedPlaces<'a, 'tcx> { - /// bottom = initialized (start_block_effect counters this at outset) - const BOTTOM_VALUE: bool = true; -} +/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is +/// an enum discriminant. +/// +/// We expect such blocks to have a call to `discriminant` as their last statement like so: +/// +/// ```text +/// ... +/// _42 = discriminant(_1) +/// SwitchInt(_42, ..) +/// ``` +/// +/// If the basic block matches this pattern, this function returns the place corresponding to the +/// enum (`_1` in the example above) as well as the `AdtDef` of that enum. +fn switch_on_enum_discriminant( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + block: &'mir mir::BasicBlockData<'tcx>, + switch_on: mir::Place<'tcx>, +) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> { + match block.statements.last().map(|stmt| &stmt.kind) { + Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))) + if *lhs == switch_on => + { + match &discriminated.ty(body, tcx).ty.kind() { + ty::Adt(def, _) => Some((*discriminated, def)), + + // `Rvalue::Discriminant` is also used to get the active yield point for a + // generator, but we do not need edge-specific effects in that case. This may + // change in the future. + ty::Generator(..) => None, + + t => bug!("`discriminant` called on unexpected type {:?}", t), + } + } -impl<'a, 'tcx> BottomValue for EverInitializedPlaces<'a, 'tcx> { - /// bottom = no initialized variables by default - const BOTTOM_VALUE: bool = false; + _ => None, + } } diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs similarity index 95% rename from src/librustc_mir/dataflow/impls/storage_liveness.rs rename to compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs index 21623e3cad..9250cd4084 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs @@ -1,6 +1,5 @@ pub use super::*; -use crate::dataflow::BottomValue; use crate::dataflow::{self, GenKill, Results, ResultsRefCursor}; use crate::util::storage::AlwaysLiveLocals; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; @@ -19,15 +18,16 @@ impl MaybeStorageLive { } impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive { - type Idx = Local; + type Domain = BitSet; const NAME: &'static str = "maybe_storage_live"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = dead + BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) { assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size()); for local in self.always_live_locals.iter() { on_entry.insert(local); @@ -40,6 +40,8 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive { } impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive { + type Idx = Local; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -74,11 +76,6 @@ impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive { } } -impl BottomValue for MaybeStorageLive { - /// bottom = dead - const BOTTOM_VALUE: bool = false; -} - type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; /// Dataflow analysis that determines whether each local requires storage at a @@ -101,15 +98,16 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { } impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { - type Idx = Local; + type Domain = BitSet; const NAME: &'static str = "requires_storage"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = dead + BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) { // The resume argument is live on function entry (we don't care about // the `self` argument) for arg in body.args_iter().skip(1) { @@ -119,6 +117,8 @@ impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, ' } impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { + type Idx = Local; + fn before_statement_effect( &self, trans: &mut impl GenKill, @@ -285,11 +285,6 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { } } -impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> { - /// bottom = dead - const BOTTOM_VALUE: bool = false; -} - struct MoveVisitor<'a, 'mir, 'tcx, T> { borrowed_locals: &'a RefCell>, trans: &'a mut T, diff --git a/src/librustc_mir/dataflow/mod.rs b/compiler/rustc_mir/src/dataflow/mod.rs similarity index 82% rename from src/librustc_mir/dataflow/mod.rs rename to compiler/rustc_mir/src/dataflow/mod.rs index a0c2463605..5575a97982 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/compiler/rustc_mir/src/dataflow/mod.rs @@ -5,9 +5,9 @@ use rustc_span::symbol::{sym, Symbol}; pub(crate) use self::drop_flag_effects::*; pub use self::framework::{ - visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState, BorrowckResults, - BottomValue, Engine, Forward, GenKill, GenKillAnalysis, Results, ResultsCursor, - ResultsRefCursor, ResultsVisitor, + fmt, lattice, visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState, + BorrowckResults, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, + ResultsCursor, ResultsRefCursor, ResultsVisitor, }; use self::move_paths::MoveData; diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs similarity index 100% rename from src/librustc_mir/dataflow/move_paths/abs_domain.rs rename to compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs similarity index 97% rename from src/librustc_mir/dataflow/move_paths/builder.rs rename to compiler/rustc_mir/src/dataflow/move_paths/builder.rs index e567063e0d..5c3e353840 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs @@ -4,7 +4,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; use smallvec::{smallvec, SmallVec}; -use std::convert::TryInto; use std::mem; use super::abs_domain::Lift; @@ -110,7 +109,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { let body = self.builder.body; let tcx = self.builder.tcx; let place_ty = Place::ty_from(place.local, proj_base, body, tcx).ty; - match place_ty.kind { + match place_ty.kind() { ty::Ref(..) | ty::RawPtr(..) => { let proj = &place.projection[..i + 1]; return Err(MoveError::cannot_move_out_of( @@ -480,13 +479,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } }; let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; - let len: u32 = match base_ty.kind { - ty::Array(_, size) => { - let length = size.eval_usize(self.builder.tcx, self.builder.param_env); - length - .try_into() - .expect("slice pattern of array with more than u32::MAX elements") - } + let len: u64 = match base_ty.kind() { + ty::Array(_, size) => size.eval_usize(self.builder.tcx, self.builder.param_env), _ => bug!("from_end: false slice pattern of non-array type"), }; for offset in from..to { @@ -525,7 +519,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // of the union so it is marked as initialized again. if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection { if let ty::Adt(def, _) = - Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx).ty.kind + Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx) + .ty + .kind() { if def.is_union() { place = PlaceRef { local: place.local, projection: proj_base } diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/compiler/rustc_mir/src/dataflow/move_paths/mod.rs similarity index 99% rename from src/librustc_mir/dataflow/move_paths/mod.rs rename to compiler/rustc_mir/src/dataflow/move_paths/mod.rs index d66d2625d7..7c63025918 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/mod.rs @@ -144,7 +144,6 @@ impl<'tcx> fmt::Display for MovePath<'tcx> { } } -#[allow(unused)] struct MovePathLinearIter<'a, 'tcx, F> { next: Option<(MovePathIndex, &'a MovePath<'tcx>)>, fetch_next: F, diff --git a/src/librustc_mir/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs similarity index 97% rename from src/librustc_mir/interpret/cast.rs rename to compiler/rustc_mir/src/interpret/cast.rs index 501a5bcddb..0e16b0caef 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -47,7 +47,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::ReifyFnPointer) => { // The src operand does not matter, just its type - match src.layout.ty.kind { + match *src.layout.ty.kind() { ty::FnDef(def_id, substs) => { // All reifications must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; @@ -76,7 +76,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::UnsafeFnPointer) => { let src = self.read_immediate(src)?; - match cast_ty.kind { + match cast_ty.kind() { ty::FnPtr(_) => { // No change to value self.write_immediate(*src, dest)?; @@ -87,7 +87,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::ClosureFnPointer(_)) => { // The src operand does not matter, just its type - match src.layout.ty.kind { + match *src.layout.ty.kind() { ty::Closure(def_id, substs) => { // All reifications must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; @@ -116,7 +116,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { use rustc_middle::ty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); - match src.layout.ty.kind { + match src.layout.ty.kind() { // Floating point Float(FloatTy::F32) => { return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into()); @@ -196,9 +196,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let v = if signed { self.sign_extend(v, src_layout) } else { v }; trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty); use rustc_middle::ty::TyKind::*; - match cast_ty.kind { + match *cast_ty.kind() { Int(_) | Uint(_) | RawPtr(_) => { - let size = match cast_ty.kind { + let size = match *cast_ty.kind() { Int(t) => Integer::from_attr(self, attr::IntType::SignedInt(t)).size(), Uint(t) => Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size(), RawPtr(_) => self.pointer_size(), @@ -228,7 +228,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { F: Float + Into> + FloatConvert + FloatConvert, { use rustc_middle::ty::TyKind::*; - match dest_ty.kind { + match *dest_ty.kind() { // float -> uint Uint(t) => { let size = Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size(); @@ -267,7 +267,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env); - match (&src_pointee_ty.kind, &dest_pointee_ty.kind) { + match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) { (&ty::Array(_, length), &ty::Slice(_)) => { let ptr = self.read_immediate(src)?.to_scalar()?; // u64 cast is from usize to u64, which is always good @@ -303,7 +303,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty); - match (&src.layout.ty.kind, &cast_ty.ty.kind) { + match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. })) | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => { self.unsize_into_ptr(src, dest, s, c) diff --git a/src/librustc_mir/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs similarity index 95% rename from src/librustc_mir/interpret/eval_context.rs rename to compiler/rustc_mir/src/interpret/eval_context.rs index 525da87463..f97096984f 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -20,7 +20,7 @@ use rustc_span::{Pos, Span}; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout}; use super::{ - Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy, + Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, Operand, Place, PlaceTy, ScalarMaybeUninit, StackPopJump, }; use crate::transform::validate::equal_up_to_regions; @@ -482,13 +482,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// The `substs` are assumed to already be in our interpreter "universe" (param_env). pub(super) fn resolve( &self, - def_id: DefId, + def: ty::WithOptConstParam, substs: SubstsRef<'tcx>, ) -> InterpResult<'tcx, ty::Instance<'tcx>> { - trace!("resolve: {:?}, {:#?}", def_id, substs); + trace!("resolve: {:?}, {:#?}", def, substs); trace!("param_env: {:#?}", self.param_env); trace!("substs: {:#?}", substs); - match ty::Instance::resolve(*self.tcx, self.param_env, def_id, substs) { + match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) { Ok(Some(instance)) => Ok(instance), Ok(None) => throw_inval!(TooGeneric), @@ -534,7 +534,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if !layout.is_unsized() { return Ok(Some((layout.size, layout.align.abi))); } - match layout.ty.kind { + match layout.ty.kind() { ty::Adt(..) | ty::Tuple(..) => { // First get the size of all statically known fields. // Don't use type_of::sizing_type_of because that expects t to be sized, @@ -875,32 +875,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - pub(super) fn const_eval( - &self, - gid: GlobalId<'tcx>, - ty: Ty<'tcx>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics - // and thus don't care about the parameter environment. While we could just use - // `self.param_env`, that would mean we invoke the query to evaluate the static - // with different parameter environments, thus causing the static to be evaluated - // multiple times. - let param_env = if self.tcx.is_static(gid.instance.def_id()) { - ty::ParamEnv::reveal_all() - } else { - self.param_env - }; - let val = self.tcx.const_eval_global_id(param_env, gid, Some(self.tcx.span))?; - - // Even though `ecx.const_eval` is called from `const_to_op` we can never have a - // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not - // return `ConstValue::Unevaluated`, which is the only way that `const_to_op` will call - // `ecx.const_eval`. - let const_ = ty::Const { val: ty::ConstKind::Value(val), ty }; - self.const_to_op(&const_, None) - } - - pub fn const_eval_raw( + pub fn eval_to_allocation( &self, gid: GlobalId<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { @@ -914,14 +889,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; - // We use `const_eval_raw` here, and get an unvalidated result. That is okay: - // Our result will later be validated anyway, and there seems no good reason - // to have to fail early here. This is also more consistent with - // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles. - // FIXME: We can hit delay_span_bug if this is an invalid const, interning finds - // that problem, but we never run validation to show an error. Can we ensure - // this does not happen? - let val = self.tcx.const_eval_raw(param_env.and(gid))?; + let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?; self.raw_const_to_mplace(val) } diff --git a/src/librustc_mir/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs similarity index 99% rename from src/librustc_mir/interpret/intern.rs rename to compiler/rustc_mir/src/interpret/intern.rs index 606be7cad2..dd5e9c9977 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -195,13 +195,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir // Raw pointers (and boxes) are handled by the `leftover_relocations` logic. let tcx = self.ecx.tcx; let ty = mplace.layout.ty; - if let ty::Ref(_, referenced_ty, ref_mutability) = ty.kind { + if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() { let value = self.ecx.read_immediate(mplace.into())?; let mplace = self.ecx.ref_to_mplace(value)?; assert_eq!(mplace.layout.ty, referenced_ty); // Handle trait object vtables. if let ty::Dynamic(..) = - tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind + tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() { // Validation will error (with a better message) on an invalid vtable pointer // so we can safely not do anything if this is not a real pointer. @@ -253,7 +253,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir // This helps to prevent users from accidentally exploiting UB that they // caused (by somehow getting a mutable reference in a `const`). if ref_mutability == Mutability::Mut { - match referenced_ty.kind { + match referenced_ty.kind() { ty::Array(_, n) if n.eval_usize(*tcx, self.ecx.param_env) == 0 => {} ty::Slice(_) if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? diff --git a/src/librustc_mir/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs similarity index 90% rename from src/librustc_mir/interpret/intrinsics.rs rename to compiler/rustc_mir/src/interpret/intrinsics.rs index b37dcd42f4..d3b6d70633 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -76,7 +76,7 @@ crate fn eval_nullary_intrinsic<'tcx>( ConstValue::from_u64(tcx.type_id_hash(tp_ty)) } sym::variant_count => { - if let ty::Adt(ref adt, _) = tp_ty.kind { + if let ty::Adt(ref adt, _) = tp_ty.kind() { ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx) } else { ConstValue::from_machine_usize(0u64, &tcx) @@ -88,6 +88,8 @@ crate fn eval_nullary_intrinsic<'tcx>( impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Returns `true` if emulation happened. + /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own + /// intrinsic handling. pub fn emulate_intrinsic( &mut self, instance: ty::Instance<'tcx>, @@ -150,7 +152,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::type_name => self.tcx.mk_static_str(), _ => bug!("already checked for nullary intrinsics"), }; - let val = self.const_eval(gid, ty)?; + let val = + self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?; + let const_ = ty::Const { val: ty::ConstKind::Value(val), ty }; + let val = self.const_to_op(&const_, None)?; self.copy_op(val, dest)?; } @@ -328,16 +333,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self); self.write_scalar(offset_ptr, dest)?; } - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - let a = self.read_immediate(args[0])?.to_scalar()?; - let b = self.read_immediate(args[1])?.to_scalar()?; - let cmp = if intrinsic_name == sym::ptr_guaranteed_eq { - self.guaranteed_eq(a, b) - } else { - self.guaranteed_ne(a, b) - }; - self.write_scalar(Scalar::from_bool(cmp), dest)?; - } sym::ptr_offset_from => { let a = self.read_immediate(args[0])?.to_scalar()?; let b = self.read_immediate(args[1])?.to_scalar()?; @@ -440,6 +435,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // These just return their argument self.copy_op(args[0], dest)?; } + sym::assume => { + let cond = self.read_scalar(args[0])?.check_init()?.to_bool()?; + if !cond { + throw_ub_format!("`assume` intrinsic called with `false`"); + } + } _ => return Ok(false), } @@ -448,37 +449,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(true) } - fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { - match (a, b) { - // Comparisons between integers are always known. - (Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b, - // Equality with integers can never be known for sure. - (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => 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. - (Scalar::Ptr(_), Scalar::Ptr(_)) => false, - } - } - - fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool { - match (a, b) { - // Comparisons between integers are always known. - (Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b, - // 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. - (Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr)) - | (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr), - // Inequality with integers other than null can never be known for sure. - (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, - // FIXME: return `true` 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 static items, for these we can - // give reliable results. - (Scalar::Ptr(_), Scalar::Ptr(_)) => false, - } - } - pub fn exact_div( &mut self, a: ImmTy<'tcx, M::PointerTag>, diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs similarity index 100% rename from src/librustc_mir/interpret/intrinsics/caller_location.rs rename to compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs similarity index 97% rename from src/librustc_mir/interpret/intrinsics/type_name.rs rename to compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index 379117f3b8..554ada1ab2 100644 --- a/src/librustc_mir/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -32,7 +32,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } fn print_type(mut self, ty: Ty<'tcx>) -> Result { - match ty.kind { + match *ty.kind() { // Types without identity. ty::Bool | ty::Char @@ -132,9 +132,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { return Ok(self); } - self.path.push_str("::"); + write!(self.path, "::{}", disambiguated_data.data).unwrap(); - self.path.push_str(&disambiguated_data.data.as_symbol().as_str()); Ok(self) } diff --git a/src/librustc_mir/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs similarity index 100% rename from src/librustc_mir/interpret/machine.rs rename to compiler/rustc_mir/src/interpret/machine.rs diff --git a/src/librustc_mir/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs similarity index 98% rename from src/librustc_mir/interpret/memory.rs rename to compiler/rustc_mir/src/interpret/memory.rs index d4be2ce056..f3e373813c 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -285,9 +285,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { None => { // Deallocating global memory -- always an error return Err(match self.tcx.get_global_alloc(ptr.alloc_id) { - Some(GlobalAlloc::Function(..)) => err_ub_format!("deallocating a function"), + Some(GlobalAlloc::Function(..)) => { + err_ub_format!("deallocating {}, which is a function", ptr.alloc_id) + } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { - err_ub_format!("deallocating static memory") + err_ub_format!("deallocating {}, which is static memory", ptr.alloc_id) } None => err_ub!(PointerUseAfterFree(ptr.alloc_id)), } @@ -297,7 +299,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if alloc_kind != kind { throw_ub_format!( - "deallocating {} memory using {} deallocation operation", + "deallocating {}, which is {} memory, using {} deallocation operation", + ptr.alloc_id, alloc_kind, kind ); @@ -305,7 +308,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if let Some((size, align)) = old_size_and_align { if size != alloc.size || align != alloc.align { throw_ub_format!( - "incorrect layout on deallocation: allocation has size {} and alignment {}, but gave size {} and alignment {}", + "incorrect layout on deallocation: {} has size {} and alignment {}, but gave size {} and alignment {}", + ptr.alloc_id, alloc.size.bytes(), alloc.align.bytes(), size.bytes(), @@ -469,7 +473,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // Notice that every static has two `AllocId` that will resolve to the same // thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID, // and the other one is maps to `GlobalAlloc::Memory`, this is returned by - // `const_eval_raw` and it is the "resolved" ID. + // `eval_static_initializer` and it is the "resolved" ID. // The resolved ID is never used by the interpreted program, it is hidden. // This is relied upon for soundness of const-patterns; a pointer to the resolved // ID would "sidestep" the checks that make sure consts do not point to statics! diff --git a/src/librustc_mir/interpret/mod.rs b/compiler/rustc_mir/src/interpret/mod.rs similarity index 100% rename from src/librustc_mir/interpret/mod.rs rename to compiler/rustc_mir/src/interpret/mod.rs diff --git a/src/librustc_mir/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs similarity index 97% rename from src/librustc_mir/interpret/operand.rs rename to compiler/rustc_mir/src/interpret/operand.rs index 0b58caef54..735f890a33 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -549,21 +549,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Early-return cases. let val_val = match val.val { - ty::ConstKind::Param(_) => throw_inval!(TooGeneric), + ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), ty::ConstKind::Unevaluated(def, substs, promoted) => { - let instance = self.resolve(def.did, substs)?; - // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation. - // The reason we use `const_eval_raw` everywhere else is to prevent cycles during - // validation, because validation automatically reads through any references, thus - // potentially requiring the current static to be evaluated again. This is not a - // problem here, because we are building an operand which means an actual read is - // happening. - return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?); + let instance = self.resolve(def, substs)?; + return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()); } - ty::ConstKind::Infer(..) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(..) => { + ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) } ty::ConstKind::Value(val_val) => val_val, @@ -662,7 +654,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty); let discr_bits = discr_val.assert_bits(discr_layout.size); // Convert discriminant to variant index, and catch invalid discriminants. - let index = match op.layout.ty.kind { + let index = match *op.layout.ty.kind() { ty::Adt(adt, _) => { adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits) } diff --git a/src/librustc_mir/interpret/operator.rs b/compiler/rustc_mir/src/interpret/operator.rs similarity index 99% rename from src/librustc_mir/interpret/operator.rs rename to compiler/rustc_mir/src/interpret/operator.rs index 30c40b8fde..fc266fa74b 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/compiler/rustc_mir/src/interpret/operator.rs @@ -282,7 +282,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right.layout.ty ); - match left.layout.ty.kind { + match left.layout.ty.kind() { ty::Char => { assert_eq!(left.layout.ty, right.layout.ty); let left = left.to_scalar()?; @@ -368,7 +368,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = val.to_scalar()?; trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty); - match layout.ty.kind { + match layout.ty.kind() { ty::Bool => { let val = val.to_bool()?; let res = match un_op { diff --git a/src/librustc_mir/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs similarity index 98% rename from src/librustc_mir/interpret/place.rs rename to compiler/rustc_mir/src/interpret/place.rs index 20fd8e4336..72551b2337 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -13,9 +13,9 @@ use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants}; use super::{ - mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ImmTy, - Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, - PointerArithmetic, RawConst, Scalar, ScalarMaybeUninit, + mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc, + ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, + Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit, }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] @@ -202,7 +202,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { if self.layout.is_unsized() { // We need to consult `meta` metadata - match self.layout.ty.kind { + match self.layout.ty.kind() { ty::Slice(..) | ty::Str => self.mplace.meta.unwrap_meta().to_machine_usize(cx), _ => bug!("len not supported on unsized type {:?}", self.layout.ty), } @@ -218,7 +218,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { #[inline] pub(super) fn vtable(self) -> Scalar { - match self.layout.ty.kind { + match self.layout.ty.kind() { ty::Dynamic(..) => self.mplace.meta.unwrap_meta(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), } @@ -498,7 +498,7 @@ where // Compute meta and new layout let inner_len = actual_to.checked_sub(from).unwrap(); - let (meta, ty) = match base.layout.ty.kind { + let (meta, ty) = match base.layout.ty.kind() { // It is not nice to match on the type, but that seems to be the only way to // implement this. ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)), @@ -549,25 +549,23 @@ where ConstantIndex { offset, min_length, from_end } => { let n = base.len(self)?; - if n < u64::from(min_length) { + if n < min_length { // This can only be reached in ConstProp and non-rustc-MIR. - throw_ub!(BoundsCheckFailed { len: min_length.into(), index: n }); + throw_ub!(BoundsCheckFailed { len: min_length, index: n }); } let index = if from_end { assert!(0 < offset && offset <= min_length); - n.checked_sub(u64::from(offset)).unwrap() + n.checked_sub(offset).unwrap() } else { assert!(offset < min_length); - u64::from(offset) + offset }; self.mplace_index(base, index)? } - Subslice { from, to, from_end } => { - self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)? - } + Subslice { from, to, from_end } => self.mplace_subslice(base, from, to, from_end)?, }) } @@ -1122,7 +1120,7 @@ where pub fn raw_const_to_mplace( &self, - raw: RawConst<'tcx>, + raw: ConstAlloc<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // This must be an allocation in `tcx` let _ = self.tcx.global_alloc(raw.alloc_id); diff --git a/src/librustc_mir/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs similarity index 100% rename from src/librustc_mir/interpret/step.rs rename to compiler/rustc_mir/src/interpret/step.rs diff --git a/src/librustc_mir/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs similarity index 96% rename from src/librustc_mir/interpret/terminator.rs rename to compiler/rustc_mir/src/interpret/terminator.rs index 9a036a0f29..9f200ca62b 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -55,7 +55,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; - let (fn_val, abi) = match func.layout.ty.kind { + let (fn_val, abi) = match *func.layout.ty.kind() { ty::FnPtr(sig) => { let caller_abi = sig.abi(); let fn_ptr = self.read_scalar(func)?.check_init()?; @@ -64,7 +64,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } ty::FnDef(def_id, substs) => { let sig = func.layout.ty.fn_sig(*self.tcx); - (FnVal::Instance(self.resolve(def_id, substs)?), sig.abi()) + ( + FnVal::Instance( + self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?, + ), + sig.abi(), + ) } _ => span_bug!( terminator.source_info.span, @@ -222,7 +227,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { { let callee_abi = { let instance_ty = instance.ty(*self.tcx, self.param_env); - match instance_ty.kind { + match instance_ty.kind() { ty::FnDef(..) => instance_ty.fn_sig(*self.tcx).abi(), ty::Closure(..) => Abi::RustCall, ty::Generator(..) => Abi::Rust, @@ -385,9 +390,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::InstanceDef::Virtual(_, idx) => { let mut args = args.to_vec(); // We have to implement all "object safe receivers". Currently we - // support built-in pointers (&, &mut, Box) as well as unsized-self. We do + // support built-in pointers `(&, &mut, Box)` as well as unsized-self. We do // not yet support custom self types. - // Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs. + // Also see `compiler/rustc_codegen_llvm/src/abi.rs` and `compiler/rustc_codegen_ssa/src/mir/block.rs`. let receiver_place = match args[0].layout.ty.builtin_deref(true) { Some(_) => { // Built-in pointer. @@ -431,7 +436,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // implementation fail -- a problem shared by rustc. let place = self.force_allocation(place)?; - let (instance, place) = match place.layout.ty.kind { + let (instance, place) = match place.layout.ty.kind() { ty::Dynamic(..) => { // Dropping a trait object. self.unpack_dyn_trait(place)? diff --git a/src/librustc_mir/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs similarity index 100% rename from src/librustc_mir/interpret/traits.rs rename to compiler/rustc_mir/src/interpret/traits.rs diff --git a/src/librustc_mir/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs similarity index 96% rename from src/librustc_mir/interpret/util.rs rename to compiler/rustc_mir/src/interpret/util.rs index 57c5fc59cc..fc5a25ffbf 100644 --- a/src/librustc_mir/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -33,7 +33,7 @@ where return false; } - match ty.kind { + match *ty.kind() { ty::Param(_) => true, ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) @@ -59,7 +59,7 @@ where // `ty::Param`/`ty::ConstKind::Param`. (false, true) if cfg!(debug_assertions) => match subst.unpack() { ty::subst::GenericArgKind::Type(ty) => { - assert!(matches!(ty.kind, ty::Param(_))) + assert!(matches!(ty.kind(), ty::Param(_))) } ty::subst::GenericArgKind::Const(ct) => { assert!(matches!(ct.val, ty::ConstKind::Param(_))) diff --git a/src/librustc_mir/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs similarity index 94% rename from src/librustc_mir/interpret/validity.rs rename to compiler/rustc_mir/src/interpret/validity.rs index 9cd2034013..2b83e1c813 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -26,18 +26,22 @@ use super::{ macro_rules! throw_validation_failure { ($where:expr, { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )?) => {{ - let mut msg = String::new(); - msg.push_str("encountered "); - write!(&mut msg, $($what_fmt),+).unwrap(); - let where_ = &$where; - if !where_.is_empty() { - msg.push_str(" at "); - write_path(&mut msg, where_); - } - $( - msg.push_str(", but expected "); - write!(&mut msg, $($expected_fmt),+).unwrap(); - )? + let msg = rustc_middle::ty::print::with_no_trimmed_paths(|| { + let mut msg = String::new(); + msg.push_str("encountered "); + write!(&mut msg, $($what_fmt),+).unwrap(); + let where_ = &$where; + if !where_.is_empty() { + msg.push_str(" at "); + write_path(&mut msg, where_); + } + $( + msg.push_str(", but expected "); + write!(&mut msg, $($expected_fmt),+).unwrap(); + )? + + msg + }); throw_ub!(ValidationFailure(msg)) }}; } @@ -210,7 +214,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' match layout.variants { Variants::Multiple { tag_field, .. } => { if tag_field == field { - return match layout.ty.kind { + return match layout.ty.kind() { ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, ty::Generator(..) => PathElem::GeneratorTag, _ => bug!("non-variant type {:?}", layout.ty), @@ -221,7 +225,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' } // Now we know we are projecting to a field, so figure out which one. - match layout.ty.kind { + match layout.ty.kind() { // generators and closures. ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { let mut name = None; @@ -299,7 +303,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' pointee: TyAndLayout<'tcx>, ) -> InterpResult<'tcx> { let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); - match tail.kind { + match tail.kind() { ty::Dynamic(..) => { let vtable = meta.unwrap_meta(); // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. @@ -421,26 +425,28 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let alloc_kind = self.ecx.tcx.get_global_alloc(ptr.alloc_id); if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); - // 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`). - // We also need to do it here instead of going on to avoid running - // into the `before_access_global` check during validation. - if !self.may_ref_to_static && self.ecx.tcx.is_static(did) { + assert!(self.ecx.tcx.is_static(did)); + if self.may_ref_to_static { + // 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(()); + } else { + // 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 } ); } - // `extern static` cannot be validated as they have no body. - // FIXME: Statics from other crates are also skipped. - // They might be checked at a different type, but for now we - // want to avoid recursing too deeply. We might miss const-invalid data, - // but things are still sound otherwise (in particular re: consts - // referring to statics). - if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { - return Ok(()); - } } } // Proceed recursively even for ZST, no reason to skip them! @@ -473,7 +479,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ) -> InterpResult<'tcx, bool> { // Go over all the primitive types let ty = value.layout.ty; - match ty.kind { + match ty.kind() { ty::Bool => { let value = self.ecx.read_scalar(value)?; try_validation!( @@ -688,7 +694,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> variant_id: VariantIdx, new_op: OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { - let name = match old_op.layout.ty.kind { + let name = match old_op.layout.ty.kind() { ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name), // Generators also have variants ty::Generator(..) => PathElem::GeneratorState(variant_id), @@ -758,7 +764,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> op: OpTy<'tcx, M::PointerTag>, fields: impl Iterator>, ) -> InterpResult<'tcx> { - match op.layout.ty.kind { + match op.layout.ty.kind() { ty::Str => { let mplace = op.assert_mem_place(self.ecx); // strings are never immediate let len = mplace.len(self.ecx)?; @@ -775,7 +781,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // FIXME(wesleywiser) This logic could be extended further to arbitrary structs // or tuples made up of integer/floating point types or inhabited ZSTs with no // padding. - match tys.kind { + match tys.kind() { ty::Int(..) | ty::Uint(..) | ty::Float(..) => true, _ => false, } diff --git a/src/librustc_mir/interpret/visitor.rs b/compiler/rustc_mir/src/interpret/visitor.rs similarity index 99% rename from src/librustc_mir/interpret/visitor.rs rename to compiler/rustc_mir/src/interpret/visitor.rs index 6c53df40a7..097b9ae6ca 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/compiler/rustc_mir/src/interpret/visitor.rs @@ -203,7 +203,7 @@ macro_rules! make_value_visitor { trace!("walk_value: type: {}", v.layout().ty); // Special treatment for special types, where the (static) layout is not sufficient. - match v.layout().ty.kind { + match *v.layout().ty.kind() { // If it is a trait object, switch to the real type that was used to create it. ty::Dynamic(..) => { // immediate trait objects are not a thing diff --git a/src/librustc_mir/lib.rs b/compiler/rustc_mir/src/lib.rs similarity index 75% rename from src/librustc_mir/lib.rs rename to compiler/rustc_mir/src/lib.rs index 2e3b508463..c00c686090 100644 --- a/src/librustc_mir/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -6,6 +6,8 @@ Rust MIR: a lowered representation of Rust. #![feature(nll)] #![feature(in_band_lifetimes)] +#![feature(array_windows)] +#![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -13,19 +15,18 @@ Rust MIR: a lowered representation of Rust. #![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] -#![feature(drain_filter)] +#![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] -#![feature(iter_order_by)] #![feature(never_type)] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(try_blocks)] -#![feature(associated_type_bounds)] #![feature(associated_type_defaults)] #![feature(stmt_expr_attributes)] #![feature(trait_alias)] #![feature(option_expect_none)] #![feature(or_patterns)] +#![feature(once_cell)] #![recursion_limit = "256"] #[macro_use] @@ -51,11 +52,15 @@ pub fn provide(providers: &mut Providers) { transform::provide(providers); monomorphize::partitioning::provide(providers); monomorphize::polymorphize::provide(providers); - providers.const_eval_validated = const_eval::const_eval_validated_provider; - providers.const_eval_raw = const_eval::const_eval_raw_provider; + providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; + providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.const_caller_location = const_eval::const_caller_location; providers.destructure_const = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); const_eval::destructure_const(tcx, param_env, value) }; + providers.deref_const = |tcx, param_env_and_value| { + let (param_env, value) = param_env_and_value.into_parts(); + const_eval::deref_const(tcx, param_env, value) + }; } diff --git a/src/librustc_mir/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs similarity index 94% rename from src/librustc_mir/monomorphize/collector.rs rename to compiler/rustc_mir/src/monomorphize/collector.rs index 1afa720f69..7e12cc9176 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -191,13 +191,13 @@ use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Local, Location}; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; -use rustc_middle::ty::print::obsolete::DefPathBasedNames; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_session::config::EntryFnType; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; use smallvec::SmallVec; use std::iter; +use std::path::PathBuf; #[derive(PartialEq)] pub enum MonoItemCollectionMode { @@ -348,7 +348,7 @@ fn collect_items_rec<'tcx>( // We've been here already, no need to search again. return; } - debug!("BEGIN collect_items_rec({})", starting_point.node.to_string(tcx, true)); + debug!("BEGIN collect_items_rec({})", starting_point.node); let mut neighbors = Vec::new(); let recursion_depth_reset; @@ -365,8 +365,10 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; - if let Ok(val) = tcx.const_eval_poly(def_id) { - collect_const_value(tcx, val, &mut neighbors); + if let Ok(alloc) = tcx.eval_static_initializer(def_id) { + for &((), id) in alloc.relocations().values() { + collect_miri(tcx, id, &mut neighbors); + } } } MonoItem::Fn(instance) => { @@ -397,7 +399,7 @@ fn collect_items_rec<'tcx>( recursion_depths.insert(def_id, depth); } - debug!("END collect_items_rec({})", starting_point.node.to_string(tcx, true)); + debug!("END collect_items_rec({})", starting_point.node); } fn record_accesses<'a, 'tcx: 'a>( @@ -419,27 +421,38 @@ fn record_accesses<'a, 'tcx: 'a>( inlining_map.lock_mut().record_accesses(caller, &accesses); } -// Shrinks string by keeping prefix and suffix of given sizes. -fn shrink(s: String, before: usize, after: usize) -> String { - // An iterator of all byte positions including the end of the string. - let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); - - let shrunk = format!( - "{before}...{after}", - before = &s[..positions().nth(before).unwrap_or(s.len())], - after = &s[positions().rev().nth(after).unwrap_or(0)..], - ); +/// Format instance name that is already known to be too long for rustc. +/// Show only the first and last 32 characters to avoid blasting +/// the user's terminal with thousands of lines of type-name. +/// +/// If the type name is longer than before+after, it will be written to a file. +fn shrunk_instance_name( + tcx: TyCtxt<'tcx>, + instance: &Instance<'tcx>, + before: usize, + after: usize, +) -> (String, Option) { + let s = instance.to_string(); // Only use the shrunk version if it's really shorter. // This also avoids the case where before and after slices overlap. - if shrunk.len() < s.len() { shrunk } else { s } -} + if s.chars().nth(before + after + 1).is_some() { + // An iterator of all byte positions including the end of the string. + let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); + + let shrunk = format!( + "{before}...{after}", + before = &s[..positions().nth(before).unwrap_or(s.len())], + after = &s[positions().rev().nth(after).unwrap_or(0)..], + ); -// Format instance name that is already known to be too long for rustc. -// Show only the first and last 32 characters to avoid blasting -// the user's terminal with thousands of lines of type-name. -fn shrunk_instance_name(instance: &Instance<'tcx>) -> String { - shrink(instance.to_string(), 32, 32) + let path = tcx.output_filenames(LOCAL_CRATE).temp_path_ext("long-type.txt", None); + let written_to_path = std::fs::write(&path, s).ok().map(|_| path); + + (shrunk, written_to_path) + } else { + (s, None) + } } fn check_recursion_limit<'tcx>( @@ -464,15 +477,16 @@ fn check_recursion_limit<'tcx>( // more than the recursion limit is assumed to be causing an // infinite expansion. if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) { - let error = format!( - "reached the recursion limit while instantiating `{}`", - shrunk_instance_name(&instance), - ); + 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(); FatalError.raise(); } @@ -501,12 +515,13 @@ 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.sess.type_length_limit().value_within_limit(type_length) { - let msg = format!( - "reached the type-length limit while instantiating `{}`", - shrunk_instance_name(&instance), - ); + 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); - diag.note(&format!( + 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 )); @@ -585,7 +600,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ) => { let source_ty = operand.ty(self.body, self.tcx); let source_ty = self.monomorphize(source_ty); - match source_ty.kind { + match *source_ty.kind() { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( self.tcx, @@ -726,7 +741,7 @@ fn visit_fn_use<'tcx>( source: Span, output: &mut Vec>>, ) { - if let ty::FnDef(def_id, substs) = ty.kind { + if let ty::FnDef(def_id, substs) = *ty.kind() { let instance = if is_direct_call { ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap() } else { @@ -863,7 +878,7 @@ fn find_vtable_types_for_unsizing<'tcx>( return false; } let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); - match tail.kind { + match tail.kind() { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, _ => bug!("unexpected unsized tail: {:?}", tail), @@ -876,7 +891,7 @@ fn find_vtable_types_for_unsizing<'tcx>( } }; - match (&source_ty.kind, &target_ty.kind) { + match (&source_ty.kind(), &target_ty.kind()) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { ptr_vtable(a, b) @@ -932,7 +947,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( ) { assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars()); - if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind { + if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind() { if let Some(principal) = trait_ty.principal() { let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); assert!(!poly_trait_ref.has_escaping_bound_vars()); @@ -1001,7 +1016,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { let def_id = self.tcx.hir().local_def_id(item.hir_id); debug!( "RootCollector: ADT drop-glue for {}", - def_id_to_string(self.tcx, def_id) + self.tcx.def_path_str(def_id.to_def_id()) ); let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty()) @@ -1013,14 +1028,14 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { hir::ItemKind::GlobalAsm(..) => { debug!( "RootCollector: ItemKind::GlobalAsm({})", - def_id_to_string(self.tcx, self.tcx.hir().local_def_id(item.hir_id)) + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id()) ); self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.hir_id))); } hir::ItemKind::Static(..) => { - let def_id = self.tcx.hir().local_def_id(item.hir_id); - debug!("RootCollector: ItemKind::Static({})", def_id_to_string(self.tcx, def_id)); - self.output.push(dummy_spanned(MonoItem::Static(def_id.to_def_id()))); + let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id(); + debug!("RootCollector: ItemKind::Static({})", self.tcx.def_path_str(def_id)); + self.output.push(dummy_spanned(MonoItem::Static(def_id))); } hir::ItemKind::Const(..) => { // const items only generate mono items if they are @@ -1143,7 +1158,7 @@ fn create_mono_items_for_default_impls<'tcx>( debug!( "create_mono_items_for_default_impls(item={})", - def_id_to_string(tcx, impl_def_id) + tcx.def_path_str(impl_def_id.to_def_id()) ); if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { @@ -1227,13 +1242,6 @@ fn collect_neighbours<'tcx>( MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body); } -fn def_id_to_string(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { - let mut output = String::new(); - let printer = DefPathBasedNames::new(tcx, false, false); - printer.push_def_path(def_id.to_def_id(), &mut output); - output -} - fn collect_const_value<'tcx>( tcx: TyCtxt<'tcx>, value: ConstValue<'tcx>, diff --git a/src/librustc_mir/monomorphize/mod.rs b/compiler/rustc_mir/src/monomorphize/mod.rs similarity index 91% rename from src/librustc_mir/monomorphize/mod.rs rename to compiler/rustc_mir/src/monomorphize/mod.rs index edafa00a03..d2586f0f84 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/mod.rs @@ -21,7 +21,7 @@ pub fn custom_coerce_unsize_info<'tcx>( }); match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) { - Ok(traits::ImplSourceUserDefined(traits::ImplSourceUserDefinedData { + Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData { impl_def_id, .. })) => tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap(), diff --git a/src/librustc_mir/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs similarity index 95% rename from src/librustc_mir/monomorphize/partitioning/default.rs rename to compiler/rustc_mir/src/monomorphize/partitioning/default.rs index b48bae8378..3c89111a65 100644 --- a/src/librustc_mir/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -3,6 +3,7 @@ use std::collections::hash_map::Entry; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::definitions::DefPathDataName; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::SymbolExportLevel; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; @@ -11,6 +12,7 @@ use rustc_middle::ty::print::characteristic_def_id_of_type; use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt}; use rustc_span::symbol::Symbol; +use super::PartitioningCx; use crate::monomorphize::collector::InliningMap; use crate::monomorphize::partitioning::merging; use crate::monomorphize::partitioning::{ @@ -22,35 +24,36 @@ pub struct DefaultPartitioning; impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn place_root_mono_items( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, mono_items: &mut dyn Iterator>, ) -> PreInliningPartitioning<'tcx> { let mut roots = FxHashSet::default(); let mut codegen_units = FxHashMap::default(); - let is_incremental_build = tcx.sess.opts.incremental.is_some(); + let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); let mut internalization_candidates = FxHashSet::default(); // Determine if monomorphizations instantiated in this crate will be made // available to downstream crates. This depends on whether we are in // share-generics mode and whether the current crate can even have // downstream crates. - let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics(); + let export_generics = + cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); let cgu_name_cache = &mut FxHashMap::default(); for mono_item in mono_items { - match mono_item.instantiation_mode(tcx) { + match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} InstantiationMode::LocalCopy => continue, } - let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item); + let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); let is_volatile = is_incremental_build && mono_item.is_generic_fn(); let codegen_unit_name = match characteristic_def_id { Some(def_id) => compute_codegen_unit_name( - tcx, + cx.tcx, cgu_name_builder, def_id, is_volatile, @@ -65,7 +68,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { let mut can_be_internalized = true; let (linkage, visibility) = mono_item_linkage_and_visibility( - tcx, + cx.tcx, &mono_item, &mut can_be_internalized, export_generics, @@ -97,17 +100,16 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn merge_codegen_units( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ) { - merging::merge_codegen_units(tcx, initial_partitioning, target_cgu_count); + merging::merge_codegen_units(cx, initial_partitioning); } fn place_inlined_mono_items( &mut self, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: PreInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) -> PostInliningPartitioning<'tcx> { let mut new_partitioning = Vec::new(); let mut mono_item_placements = FxHashMap::default(); @@ -124,7 +126,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { // Collect all items that need to be available in this codegen unit. let mut reachable = FxHashSet::default(); for root in old_codegen_unit.items().keys() { - follow_inlining(*root, inlining_map, &mut reachable); + follow_inlining(*root, cx.inlining_map, &mut reachable); } let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); @@ -198,9 +200,8 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn internalize_symbols( &mut self, - _tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) { if partitioning.codegen_units.len() == 1 { // Fast path for when there is only one codegen unit. In this case we @@ -218,7 +219,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { // Build a map from every monomorphization to all the monomorphizations that // reference it. let mut accessor_map: FxHashMap, Vec>> = Default::default(); - inlining_map.iter_accesses(|accessor, accessees| { + cx.inlining_map.iter_accesses(|accessor, accessees| { for accessee in accessees { accessor_map.entry(*accessee).or_default().push(accessor); } @@ -354,7 +355,10 @@ fn compute_codegen_unit_name( *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { let def_path = tcx.def_path(cgu_def_id); - let components = def_path.data.iter().map(|part| part.data.as_symbol()); + let components = def_path.data.iter().map(|part| match part.data.name() { + DefPathDataName::Named(name) => name, + DefPathDataName::Anon { .. } => unreachable!(), + }); let volatile_suffix = volatile.then_some("volatile"); diff --git a/src/librustc_mir/monomorphize/partitioning/merging.rs b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs similarity index 90% rename from src/librustc_mir/monomorphize/partitioning/merging.rs rename to compiler/rustc_mir/src/monomorphize/partitioning/merging.rs index 1787e6df1b..5107e69726 100644 --- a/src/librustc_mir/monomorphize/partitioning/merging.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs @@ -3,17 +3,16 @@ use std::cmp; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder}; -use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{Symbol, SymbolStr}; +use super::PartitioningCx; use crate::monomorphize::partitioning::PreInliningPartitioning; pub fn merge_codegen_units<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ) { - assert!(target_cgu_count >= 1); + assert!(cx.target_cgu_count >= 1); let codegen_units = &mut initial_partitioning.codegen_units; // Note that at this point in time the `codegen_units` here may not be in a @@ -32,7 +31,7 @@ pub fn merge_codegen_units<'tcx>( codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect(); // Merge the two smallest codegen units until the target size is reached. - while codegen_units.len() > target_cgu_count { + while codegen_units.len() > cx.target_cgu_count { // Sort small cgus to the back codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); let mut smallest = codegen_units.pop().unwrap(); @@ -56,9 +55,9 @@ pub fn merge_codegen_units<'tcx>( ); } - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - if tcx.sess.opts.incremental.is_some() { + if cx.tcx.sess.opts.incremental.is_some() { // If we are doing incremental compilation, we want CGU names to // reflect the path of the source level module they correspond to. // For CGUs that contain the code of multiple modules because of the @@ -74,7 +73,9 @@ pub fn merge_codegen_units<'tcx>( // Sort the names, so things are deterministic and easy to // predict. - cgu_contents.sort(); + + // We are sorting primitive &strs here so we can use unstable sort + cgu_contents.sort_unstable(); (current_cgu_name, cgu_contents.join("--")) }) @@ -82,7 +83,7 @@ pub fn merge_codegen_units<'tcx>( for cgu in codegen_units.iter_mut() { if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if tcx.sess.opts.debugging_opts.human_readable_cgu_names { + if cx.tcx.sess.opts.debugging_opts.human_readable_cgu_names { cgu.set_name(Symbol::intern(&new_cgu_name)); } else { // If we don't require CGU names to be human-readable, we diff --git a/src/librustc_mir/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs similarity index 93% rename from src/librustc_mir/monomorphize/partitioning/mod.rs rename to compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index 9dfbd65e1b..db6d3b2d91 100644 --- a/src/librustc_mir/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -100,6 +100,7 @@ use rustc_data_structures::sync; use rustc_hir::def_id::{CrateNum, DefIdSet, LOCAL_CRATE}; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{CodegenUnit, Linkage}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; @@ -107,31 +108,35 @@ use rustc_span::symbol::Symbol; use crate::monomorphize::collector::InliningMap; use crate::monomorphize::collector::{self, MonoItemCollectionMode}; +pub struct PartitioningCx<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + target_cgu_count: usize, + inlining_map: &'a InliningMap<'tcx>, +} + trait Partitioner<'tcx> { fn place_root_mono_items( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, mono_items: &mut dyn Iterator>, ) -> PreInliningPartitioning<'tcx>; fn merge_codegen_units( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ); fn place_inlined_mono_items( &mut self, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: PreInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) -> PostInliningPartitioning<'tcx>; fn internalize_symbols( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ); } @@ -156,12 +161,13 @@ pub fn partition<'tcx>( let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); let mut partitioner = get_partitioner(tcx); + let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; // In the first step, we place all regular monomorphizations into their // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. let mut initial_partitioning = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - partitioner.place_root_mono_items(tcx, mono_items) + partitioner.place_root_mono_items(cx, mono_items) }; initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -171,7 +177,7 @@ pub fn partition<'tcx>( // Merge until we have at most `max_cgu_count` codegen units. { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - partitioner.merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count); + partitioner.merge_codegen_units(cx, &mut initial_partitioning); debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); } @@ -181,7 +187,7 @@ pub fn partition<'tcx>( // local functions the definition of which is marked with `#[inline]`. let mut post_inlining = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - partitioner.place_inlined_mono_items(initial_partitioning, inlining_map) + partitioner.place_inlined_mono_items(cx, initial_partitioning) }; post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -190,9 +196,9 @@ pub fn partition<'tcx>( // Next we try to make as many symbols "internal" as possible, so LLVM has // more freedom to optimize. - if tcx.sess.opts.cg.link_dead_code != Some(true) { + if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - partitioner.internalize_symbols(tcx, &mut post_inlining, inlining_map); + partitioner.internalize_symbols(cx, &mut post_inlining); } // Finally, sort by codegen unit name, so that we get deterministic results. @@ -246,7 +252,7 @@ where debug!( " - {} [{:?}] [{}] estimated size {}", - mono_item.to_string(tcx, true), + mono_item, linkage, symbol_hash, mono_item.size_estimate(tcx) @@ -271,14 +277,8 @@ where symbols.sort_by_key(|sym| sym.1); - for pair in symbols.windows(2) { - let sym1 = &pair[0].1; - let sym2 = &pair[1].1; - + for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() { if sym1 == sym2 { - let mono_item1 = pair[0].0; - let mono_item2 = pair[1].0; - let span1 = mono_item1.local_span(tcx); let span2 = mono_item2.local_span(tcx); @@ -327,7 +327,7 @@ fn collect_and_partition_mono_items<'tcx>( } } None => { - if tcx.sess.opts.cg.link_dead_code == Some(true) { + if tcx.sess.link_dead_code() { MonoItemCollectionMode::Eager } else { MonoItemCollectionMode::Lazy @@ -374,14 +374,14 @@ fn collect_and_partition_mono_items<'tcx>( let mut item_keys: Vec<_> = items .iter() .map(|i| { - let mut output = i.to_string(tcx, false); + let mut output = with_no_trimmed_paths(|| i.to_string()); output.push_str(" @@"); let mut empty = Vec::new(); let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); cgus.sort_by_key(|(name, _)| *name); cgus.dedup(); for &(ref cgu_name, (linkage, _)) in cgus.iter() { - output.push_str(" "); + output.push(' '); output.push_str(&cgu_name.as_str()); let linkage_abbrev = match linkage { @@ -398,9 +398,9 @@ fn collect_and_partition_mono_items<'tcx>( Linkage::Common => "Common", }; - output.push_str("["); + output.push('['); output.push_str(linkage_abbrev); - output.push_str("]"); + output.push(']'); } output }) diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs similarity index 99% rename from src/librustc_mir/monomorphize/polymorphize.rs rename to compiler/rustc_mir/src/monomorphize/polymorphize.rs index 69f3288ee3..3f6f117acd 100644 --- a/src/librustc_mir/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -288,7 +288,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { return false; } - match ty.kind { + match *ty.kind() { ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => { debug!("visit_ty: def_id={:?}", def_id); // Avoid cycle errors with generators. @@ -337,7 +337,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { return false; } - match ty.kind { + match ty.kind() { ty::Param(param) => !self.unused_parameters.contains(param.index).unwrap_or(false), _ => ty.super_visit_with(self), } diff --git a/src/librustc_mir/shim.rs b/compiler/rustc_mir/src/shim.rs similarity index 94% rename from src/librustc_mir/shim.rs rename to compiler/rustc_mir/src/shim.rs index 08ed0d3770..7e4d189f0b 100644 --- a/src/librustc_mir/shim.rs +++ b/compiler/rustc_mir/src/shim.rs @@ -33,7 +33,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let mut result = match instance { ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), ty::InstanceDef::VtableShim(def_id) => { - build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None) + build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id)) } ty::InstanceDef::FnPtrShim(def_id, ty) => { let trait_ = tcx.trait_of_item(def_id).unwrap(); @@ -42,16 +42,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref, None => bug!("fn pointer {:?} is not an fn", ty), }; - // HACK: we need the "real" argument types for the MIR, - // but because our substs are (Self, Args), where Args - // is a tuple, we must include the *concrete* argument - // types in the MIR. They will be substituted again with - // the param-substs, but because they are concrete, this - // will not do any harm. - let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); - let arg_tys = sig.inputs(); - - build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty), Some(arg_tys)) + + build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty)) } // We are generating a call back to our def-id, which the // codegen backend knows to turn to an actual call, be it @@ -59,7 +51,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // indirect calls must be codegen'd differently than direct ones // (such as `#[track_caller]`). ty::InstanceDef::ReifyShim(def_id) => { - build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None) + build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } ty::InstanceDef::ClosureOnceShim { call_once: _ } => { let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); @@ -70,13 +62,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' .unwrap() .def_id; - build_call_shim( - tcx, - instance, - Some(Adjustment::RefMut), - CallKind::Direct(call_mut), - None, - ) + build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) } ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty), ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), @@ -149,7 +135,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); // Check if this is a generator, if so, return the drop glue for it - if let Some(&ty::TyS { kind: ty::Generator(gen_def_id, substs, _), .. }) = ty { + if let Some(&ty::Generator(gen_def_id, substs, _)) = ty.map(|ty| ty.kind()) { let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap(); return body.subst(tcx, substs); } @@ -295,7 +281,7 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option { Some(()) } - fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option { + fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option { None } } @@ -312,7 +298,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - let dest = Place::return_place(); let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0))); - match self_ty.kind { + match self_ty.kind() { _ if is_copy => builder.copy_shim(), ty::Array(ty, len) => { let len = len.eval_usize(tcx, param_env); @@ -641,29 +627,45 @@ impl CloneShimBuilder<'tcx> { } } -/// Builds a "call" shim for `instance`. The shim calls the -/// function specified by `call_kind`, first adjusting its first -/// argument according to `rcvr_adjustment`. -/// -/// If `untuple_args` is a vec of types, the second argument of the -/// function will be untupled as these types. +/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`, +/// first adjusting its first argument according to `rcvr_adjustment`. fn build_call_shim<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>, rcvr_adjustment: Option, call_kind: CallKind<'tcx>, - untuple_args: Option<&[Ty<'tcx>]>, ) -> Body<'tcx> { debug!( - "build_call_shim(instance={:?}, rcvr_adjustment={:?}, \ - call_kind={:?}, untuple_args={:?})", - instance, rcvr_adjustment, call_kind, untuple_args + "build_call_shim(instance={:?}, rcvr_adjustment={:?}, call_kind={:?})", + instance, rcvr_adjustment, call_kind ); + // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used + // to substitute into the signature of the shim. It is not necessary for users of this + // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`). + let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance { + let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); + + let untuple_args = sig.inputs(); + + // Create substitutions for the `Self` and `Args` generic parameters of the shim body. + let arg_tup = tcx.mk_tup(untuple_args.iter()); + let sig_substs = tcx.mk_substs_trait(ty, &[ty::subst::GenericArg::from(arg_tup)]); + + (Some(sig_substs), Some(untuple_args)) + } else { + (None, None) + }; + let def_id = instance.def_id(); let sig = tcx.fn_sig(def_id); let mut sig = tcx.erase_late_bound_regions(&sig); + assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); + if let Some(sig_substs) = sig_substs { + sig = sig.subst(tcx, sig_substs); + } + if let CallKind::Indirect(fnty) = call_kind { // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from @@ -853,7 +855,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { let sig = tcx.fn_sig(ctor_id).no_bound_vars().expect("LBR in ADT constructor signature"); let sig = tcx.normalize_erasing_regions(param_env, sig); - let (adt_def, substs) = match sig.output().kind { + let (adt_def, substs) = match sig.output().kind() { ty::Adt(adt_def, substs) => (adt_def, substs), _ => bug!("unexpected type for ADT ctor {:?}", sig.output()), }; diff --git a/src/librustc_mir/transform/add_call_guards.rs b/compiler/rustc_mir/src/transform/add_call_guards.rs similarity index 100% rename from src/librustc_mir/transform/add_call_guards.rs rename to compiler/rustc_mir/src/transform/add_call_guards.rs diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs similarity index 100% rename from src/librustc_mir/transform/add_moves_for_packed_drops.rs rename to compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs diff --git a/src/librustc_mir/transform/add_retag.rs b/compiler/rustc_mir/src/transform/add_retag.rs similarity index 99% rename from src/librustc_mir/transform/add_retag.rs rename to compiler/rustc_mir/src/transform/add_retag.rs index 324289166b..0c596ba715 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/compiler/rustc_mir/src/transform/add_retag.rs @@ -35,7 +35,7 @@ fn is_stable(place: PlaceRef<'_>) -> bool { /// Determine whether this type may be a reference (or box), and thus needs retagging. fn may_be_reference(ty: Ty<'tcx>) -> bool { - match ty.kind { + match ty.kind() { // Primitive types that are not references ty::Bool | ty::Char diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs new file mode 100644 index 0000000000..b6d57b899d --- /dev/null +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -0,0 +1,147 @@ +use rustc_errors::DiagnosticBuilder; +use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::lint::builtin::CONST_ITEM_MUTATION; +use rustc_span::def_id::DefId; + +use crate::transform::{MirPass, MirSource}; + +pub struct CheckConstItemMutation; + +impl<'tcx> MirPass<'tcx> for CheckConstItemMutation { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + let mut checker = ConstMutationChecker { body, tcx, target_local: None }; + checker.visit_body(&body); + } +} + +struct ConstMutationChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + target_local: Option, +} + +impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { + fn is_const_item(&self, local: Local) -> Option { + if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info { + Some(def_id) + } else { + None + } + } + + fn is_const_item_without_destructor(&self, local: Local) -> Option { + let def_id = self.is_const_item(local)?; + let mut any_dtor = |_tcx, _def_id| Ok(()); + + // We avoid linting mutation of a const item if the const's type has a + // Drop impl. The Drop logic observes the mutation which was performed. + // + // pub struct Log { msg: &'static str } + // pub const LOG: Log = Log { msg: "" }; + // impl Drop for Log { + // fn drop(&mut self) { println!("{}", self.msg); } + // } + // + // LOG.msg = "wow"; // prints "wow" + // + // FIXME(https://github.com/rust-lang/rust/issues/77425): + // Drop this exception once there is a stable attribute to suppress the + // const item mutation lint for a single specific const only. Something + // equivalent to: + // + // #[const_mutation_allowed] + // pub const LOG: Log = Log { msg: "" }; + match self.tcx.calculate_dtor(def_id, &mut any_dtor) { + Some(_) => None, + None => Some(def_id), + } + } + + fn lint_const_item_usage( + &self, + const_item: DefId, + location: Location, + decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>, + ) { + let source_info = self.body.source_info(location); + let lint_root = self.body.source_scopes[source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + + self.tcx.struct_span_lint_hir(CONST_ITEM_MUTATION, lint_root, source_info.span, |lint| { + decorate(lint) + .span_note(self.tcx.def_span(const_item), "`const` item defined here") + .emit() + }); + } +} + +impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { + fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) { + if let StatementKind::Assign(box (lhs, _)) = &stmt.kind { + // Check for assignment to fields of a constant + // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error, + // so emitting a lint would be redundant. + if !lhs.projection.is_empty() { + if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) { + // Don't lint on writes through a pointer + // (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`) + if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) { + self.lint_const_item_usage(def_id, loc, |lint| { + let mut lint = lint.build("attempting to modify a `const` item"); + lint.note("each usage of a `const` item creates a new temporary - the original `const` item will not be modified"); + lint + }) + } + } + } + // We are looking for MIR of the form: + // + // ``` + // _1 = const FOO; + // _2 = &mut _1; + // method_call(_2, ..) + // ``` + // + // Record our current LHS, so that we can detect this + // pattern in `visit_rvalue` + self.target_local = lhs.as_local(); + } + self.super_statement(stmt, loc); + self.target_local = None; + } + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) { + if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue { + let local = place.local; + if let Some(def_id) = self.is_const_item(local) { + // If this Rvalue is being used as the right-hand side of a + // `StatementKind::Assign`, see if it ends up getting used as + // the `self` parameter of a method call (as the terminator of our current + // BasicBlock). If so, we emit a more specific lint. + let method_did = self.target_local.and_then(|target_local| { + crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block) + }); + let lint_loc = + if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc }; + self.lint_const_item_usage(def_id, lint_loc, |lint| { + let mut lint = lint.build("taking a mutable reference to a `const` item"); + lint + .note("each usage of a `const` item creates a new temporary") + .note("the mutable reference will refer to this temporary, not the original `const` item"); + + if let Some((method_did, _substs)) = method_did { + lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method"); + } + + lint + }); + } + } + self.super_rvalue(rvalue, loc); + } +} diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs new file mode 100644 index 0000000000..8df134860a --- /dev/null +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -0,0 +1,115 @@ +//! Check the bodies of `const`s, `static`s and `const fn`s for illegal operations. +//! +//! This module will eventually replace the parts of `qualify_consts.rs` that check whether a local +//! has interior mutability or needs to be dropped, as well as the visitor that emits errors when +//! it finds operations that are invalid in a certain context. + +use rustc_attr as attr; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::mir; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::Symbol; + +pub use self::qualifs::Qualif; + +mod ops; +pub mod post_drop_elaboration; +pub mod qualifs; +mod resolver; +pub mod validation; + +/// Information about the item currently being const-checked, as well as a reference to the global +/// context. +pub struct ConstCx<'mir, 'tcx> { + pub body: &'mir mir::Body<'tcx>, + pub tcx: TyCtxt<'tcx>, + pub def_id: LocalDefId, + pub param_env: ty::ParamEnv<'tcx>, + pub const_kind: Option, +} + +impl ConstCx<'mir, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'mir mir::Body<'tcx>) -> Self { + let param_env = tcx.param_env(def_id); + Self::new_with_param_env(tcx, def_id, body, param_env) + } + + pub fn new_with_param_env( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + body: &'mir mir::Body<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Self { + let const_kind = tcx.hir().body_const_context(def_id); + ConstCx { body, tcx, def_id: def_id, param_env, const_kind } + } + + /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.). + /// + /// Panics if this `Item` is not const. + pub fn const_kind(&self) -> hir::ConstContext { + self.const_kind.expect("`const_kind` must not be called on a non-const fn") + } + + pub fn is_const_stable_const_fn(&self) -> bool { + self.const_kind == Some(hir::ConstContext::ConstFn) + && self.tcx.features().staged_api + && is_const_stable_const_fn(self.tcx, self.def_id.to_def_id()) + } + + /// Returns the function signature of the item being const-checked if it is a `fn` or `const fn`. + pub fn fn_sig(&self) -> Option<&'tcx hir::FnSig<'tcx>> { + // Get this from the HIR map instead of a query to avoid cycle errors. + // + // FIXME: Is this still an issue? + let hir_map = self.tcx.hir(); + let hir_id = hir_map.local_def_id_to_hir_id(self.def_id); + hir_map.fn_sig_by_hir_id(hir_id) + } +} + +/// Returns `true` if this `DefId` points to one of the official `panic` lang items. +pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn() +} + +pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { + let attrs = tcx.get_attrs(def_id); + attr::allow_internal_unstable(&tcx.sess, attrs) + .map_or(false, |mut features| features.any(|name| name == feature_gate)) +} + +// Returns `true` if the given `const fn` is "const-stable". +// +// Panics if the given `DefId` does not refer to a `const fn`. +// +// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" +// functions can be called in a const-context by users of the stable compiler. "const-stable" +// functions are subject to more stringent restrictions than "const-unstable" functions: They +// cannot use unstable features and can only call other "const-stable" functions. +pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + use attr::{ConstStability, Stability, StabilityLevel}; + + // Const-stability is only relevant for `const fn`. + assert!(tcx.is_const_fn_raw(def_id)); + + // Functions with `#[rustc_const_unstable]` are const-unstable. + match tcx.lookup_const_stability(def_id) { + Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false, + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true, + None => {} + } + + // Functions with `#[unstable]` are const-unstable. + // + // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability + // attributes. `#[unstable]` should be irrelevant. + if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) = + tcx.lookup_stability(def_id) + { + return false; + } + + true +} diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs new file mode 100644 index 0000000000..32e233e337 --- /dev/null +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -0,0 +1,642 @@ +//! Concrete error types for all operations which may be invalid in a certain const context. + +use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::mir; +use rustc_session::config::nightly_options; +use rustc_session::parse::feature_err; +use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; + +use super::ConstCx; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Status { + Allowed, + Unstable(Symbol), + Forbidden, +} + +#[derive(Clone, Copy)] +pub enum DiagnosticImportance { + /// An operation that must be removed for const-checking to pass. + Primary, + + /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere. + Secondary, +} + +/// An operation that is not *always* allowed in a const context. +pub trait NonConstOp: std::fmt::Debug { + /// Returns an enum indicating whether this operation is allowed within the given item. + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Forbidden + } + + fn importance(&self) -> DiagnosticImportance { + DiagnosticImportance::Primary + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; +} + +#[derive(Debug)] +pub struct Abort; +impl NonConstOp for Abort { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + mcf_build_error(ccx, span, "abort is not stable in const fn") + } +} + +#[derive(Debug)] +pub struct FloatingPointOp; +impl NonConstOp for FloatingPointOp { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_fn_floating_point_arithmetic) + } else { + Status::Allowed + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_floating_point_arithmetic, + span, + &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()), + ) + } +} + +/// A function call where the callee is a pointer. +#[derive(Debug)] +pub struct FnCallIndirect; +impl NonConstOp for FnCallIndirect { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn") + } +} + +/// A function call where the callee is not marked as `const`. +#[derive(Debug)] +pub struct FnCallNonConst(pub DefId); +impl NonConstOp for FnCallNonConst { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + ccx.tcx.sess, + span, + E0015, + "calls in {}s are limited to constant functions, \ + tuple structs and tuple variants", + ccx.const_kind(), + ) + } +} + +/// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function. +/// +/// Contains the name of the feature that would allow the use of this function. +#[derive(Debug)] +pub struct FnCallUnstable(pub DefId, pub Option); + +impl NonConstOp for FnCallUnstable { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + 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)), + ); + + if ccx.is_const_stable_const_fn() { + err.help("Const-stable functions can only call other const-stable functions"); + } else if nightly_options::is_nightly_build() { + if let Some(feature) = feature { + err.help(&format!( + "add `#![feature({})]` to the crate attributes to enable", + feature + )); + } + } + + err + } +} + +#[derive(Debug)] +pub struct FnPtrCast; +impl NonConstOp for FnPtrCast { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_fn_ptr_basics) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_fn_ptr_basics, + span, + &format!("function pointer casts are not allowed in {}s", ccx.const_kind()), + ) + } +} + +#[derive(Debug)] +pub struct Generator(pub hir::GeneratorKind); +impl NonConstOp for Generator { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Forbidden + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); + ccx.tcx.sess.struct_span_err(span, &msg) + } +} + +#[derive(Debug)] +pub struct HeapAllocation; +impl NonConstOp for HeapAllocation { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!( + ccx.tcx.sess, + 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 + } +} + +#[derive(Debug)] +pub struct InlineAsm; +impl NonConstOp for InlineAsm { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + ccx.tcx.sess, + span, + E0015, + "inline assembly is not allowed in {}s", + ccx.const_kind() + ) + } +} + +#[derive(Debug)] +pub struct LiveDrop { + pub dropped_at: Option, +} +impl NonConstOp for LiveDrop { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0493, + "destructors cannot be evaluated at compile-time" + ); + err.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())); + if let Some(span) = self.dropped_at { + err.span_label(span, "value is dropped here"); + } + err + } +} + +#[derive(Debug)] +pub struct CellBorrow; +impl NonConstOp for CellBorrow { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + ccx.tcx.sess, + span, + E0492, + "cannot borrow a constant which may contain \ + interior mutability, create a static instead" + ) + } +} + +#[derive(Debug)] +pub struct MutBorrow; +impl NonConstOp for MutBorrow { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("mutable references are not allowed in {}s", ccx.const_kind()), + ) + } else { + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0764, + "mutable references are not allowed in {}s", + ccx.const_kind(), + ); + err.span_label(span, format!("`&mut` is only allowed in `const fn`")); + err + }; + 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.", + ); + } + err + } +} + +// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues. +#[derive(Debug)] +pub struct MutAddressOf; +impl NonConstOp for MutAddressOf { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("`&raw mut` is not allowed in {}s", ccx.const_kind()), + ) + } +} + +#[derive(Debug)] +pub struct MutDeref; +impl NonConstOp for MutDeref { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) + } + + fn importance(&self) -> DiagnosticImportance { + // Usually a side-effect of a `MutBorrow` somewhere. + DiagnosticImportance::Secondary + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("mutation through a reference is not allowed in {}s", ccx.const_kind()), + ) + } +} + +#[derive(Debug)] +pub struct Panic; +impl NonConstOp for Panic { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_panic) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_panic, + span, + &format!("panicking in {}s is unstable", ccx.const_kind()), + ) + } +} + +#[derive(Debug)] +pub struct RawPtrComparison; +impl NonConstOp for RawPtrComparison { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = ccx + .tcx + .sess + .struct_span_err(span, "pointers cannot be reliably compared during const eval."); + err.note( + "see issue #53020 \ + for more information", + ); + err + } +} + +#[derive(Debug)] +pub struct RawPtrDeref; +impl NonConstOp for RawPtrDeref { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_deref) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_raw_ptr_deref, + span, + &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),), + ) + } +} + +#[derive(Debug)] +pub struct RawPtrToIntCast; +impl NonConstOp for RawPtrToIntCast { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_to_usize_cast) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_raw_ptr_to_usize_cast, + span, + &format!("casting pointers to integers in {}s is unstable", ccx.const_kind(),), + ) + } +} + +/// An access to a (non-thread-local) `static`. +#[derive(Debug)] +pub struct StaticAccess; +impl NonConstOp for StaticAccess { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if let hir::ConstContext::Static(_) = ccx.const_kind() { + Status::Allowed + } else { + Status::Forbidden + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0013, + "{}s cannot refer to statics", + ccx.const_kind() + ); + err.help( + "consider extracting the value of the `static` to a `const`, and referring to that", + ); + if ccx.tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "`static` and `const` variables can refer to other `const` variables. \ + A `const` variable, however, cannot refer to a `static` variable.", + ); + err.help("To fix this, the value can be extracted to a `const` and then used."); + } + err + } +} + +/// An access to a thread-local `static`. +#[derive(Debug)] +pub struct ThreadLocalAccess; +impl NonConstOp for ThreadLocalAccess { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + ccx.tcx.sess, + span, + E0625, + "thread-local statics cannot be \ + accessed at compile-time" + ) + } +} + +#[derive(Debug)] +pub struct Transmute; +impl NonConstOp for Transmute { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_transmute) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_transmute, + span, + &format!("`transmute` is not allowed in {}s", ccx.const_kind()), + ); + err.note("`transmute` is only allowed in constants and statics for now"); + err + } +} + +#[derive(Debug)] +pub struct UnionAccess; +impl NonConstOp for UnionAccess { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Union accesses are stable in all contexts except `const fn`. + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_union) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_union, + span, + "unions in const fn are unstable", + ) + } +} + +/// See [#64992]. +/// +/// [#64992]: https://github.com/rust-lang/rust/issues/64992 +#[derive(Debug)] +pub struct UnsizingCast; +impl NonConstOp for UnsizingCast { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + mcf_build_error( + ccx, + span, + "unsizing casts to types besides slices are not allowed in const fn", + ) + } +} + +// Types that cannot appear in the signature or locals of a `const fn`. +pub mod ty { + use super::*; + + #[derive(Debug)] + pub struct MutRef(pub mir::LocalKind); + impl NonConstOp for MutRef { + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) + } + + fn importance(&self) -> DiagnosticImportance { + match self.0 { + mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, + mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { + DiagnosticImportance::Primary + } + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("mutable references are not allowed in {}s", ccx.const_kind()), + ) + } + } + + #[derive(Debug)] + pub struct FnPtr(pub mir::LocalKind); + impl NonConstOp for FnPtr { + fn importance(&self) -> DiagnosticImportance { + match self.0 { + mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, + mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { + DiagnosticImportance::Primary + } + } + } + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_fn_ptr_basics) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_fn_ptr_basics, + span, + &format!("function pointers cannot appear in {}s", ccx.const_kind()), + ) + } + } + + #[derive(Debug)] + pub struct ImplTrait; + impl NonConstOp for ImplTrait { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + mcf_build_error(ccx, span, "`impl Trait` in const fn is unstable") + } + } + + #[derive(Debug)] + pub struct TraitBound(pub mir::LocalKind); + impl NonConstOp for TraitBound { + fn importance(&self) -> DiagnosticImportance { + match self.0 { + mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, + mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { + DiagnosticImportance::Primary + } + } + } + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + mcf_build_error( + ccx, + span, + "trait bounds other than `Sized` on const fn parameters are unstable", + ) + } + } + + /// A trait bound with the `?const Trait` opt-out + #[derive(Debug)] + pub struct TraitBoundNotConst; + impl NonConstOp for TraitBoundNotConst { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_trait_bound_opt_out) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_trait_bound_opt_out, + span, + "`?const Trait` syntax is unstable", + ) + } + } +} + +fn mcf_status_in_item(ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn) + } +} + +fn mcf_build_error(ccx: &ConstCx<'_, 'tcx>, span: Span, msg: &str) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!(ccx.tcx.sess, span, E0723, "{}", msg); + err.note( + "see issue #57563 \ + for more information", + ); + err.help("add `#![feature(const_fn)]` to the crate attributes to enable"); + err +} diff --git a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs similarity index 90% rename from src/librustc_mir/transform/check_consts/post_drop_elaboration.rs rename to compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index 55075b3ab5..9b2568d5ab 100644 --- a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -4,15 +4,20 @@ use rustc_middle::mir::{self, BasicBlock, Location}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; -use super::ops; +use super::ops::{self, NonConstOp}; use super::qualifs::{NeedsDrop, Qualif}; use super::validation::Qualifs; use super::ConstCx; /// Returns `true` if we should use the more precise live drop checker that runs after drop /// elaboration. -pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool { - tcx.features().const_precise_live_drops +pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { + // Const-stable functions must always use the stable live drop checker. + if ccx.is_const_stable_const_fn() { + return false; + } + + ccx.tcx.features().const_precise_live_drops } /// Look for live drops in a const context. @@ -25,12 +30,11 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body< return; } - if !checking_enabled(tcx) { + let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) }; + if !checking_enabled(&ccx) { return; } - let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) }; - let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() }; visitor.visit_body(body); @@ -52,7 +56,7 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { impl CheckLiveDrops<'mir, 'tcx> { fn check_live_drop(&self, span: Span) { - ops::non_const(self.ccx, ops::LiveDrop(None), span); + ops::LiveDrop { dropped_at: None }.build_error(self.ccx, span).emit(); } } diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs similarity index 99% rename from src/librustc_mir/transform/check_consts/qualifs.rs rename to compiler/rustc_mir/src/transform/check_consts/qualifs.rs index 445a0230af..3f4b3ca2ee 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs @@ -170,7 +170,7 @@ where // Special-case reborrows to be more like a copy of the reference. if let &[ref proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() { let base_ty = Place::ty_from(place.local, proj_base, cx.body, cx.tcx).ty; - if let ty::Ref(..) = base_ty.kind { + if let ty::Ref(..) = base_ty.kind() { return in_place::( cx, in_local, diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/compiler/rustc_mir/src/transform/check_consts/resolver.rs similarity index 94% rename from src/librustc_mir/transform/check_consts/resolver.rs rename to compiler/rustc_mir/src/transform/check_consts/resolver.rs index b8104292aa..a00301952b 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/compiler/rustc_mir/src/transform/check_consts/resolver.rs @@ -165,23 +165,19 @@ where } } -impl dataflow::BottomValue for FlowSensitiveAnalysis<'_, '_, '_, Q> { - const BOTTOM_VALUE: bool = false; -} - impl dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> where Q: Qualif, { - type Idx = Local; + type Domain = BitSet; const NAME: &'static str = Q::ANALYSIS_NAME; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut BitSet) { + fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) { self.transfer_function(state).initialize_state(); } } @@ -192,7 +188,7 @@ where { fn apply_statement_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { @@ -201,7 +197,7 @@ where fn apply_terminator_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ) { @@ -210,7 +206,7 @@ where fn apply_call_return_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, block: BasicBlock, func: &mir::Operand<'tcx>, args: &[mir::Operand<'tcx>], diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs similarity index 55% rename from src/librustc_mir/transform/check_consts/validation.rs rename to compiler/rustc_mir/src/transform/check_consts/validation.rs index e21f314ca1..4e714bfeed 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -1,25 +1,28 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. -use rustc_errors::struct_span_err; -use rustc_hir::{self as hir, LangItem}; -use rustc_hir::{def_id::DefId, HirId}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, HirId, LangItem}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::{self, Instance, InstanceDef, TyCtxt}; -use rustc_span::Span; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{ + self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut, +}; +use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, TraitEngine}; -use std::borrow::Cow; +use std::mem; use std::ops::Deref; -use super::ops::{self, NonConstOp}; +use super::ops::{self, NonConstOp, Status}; use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{is_lang_panic_fn, ConstCx, Qualif}; -use crate::const_eval::{is_const_fn, is_unstable_const_fn}; +use crate::const_eval::is_unstable_const_fn; use crate::dataflow::impls::MaybeMutBorrowedLocals; use crate::dataflow::{self, Analysis}; @@ -57,6 +60,7 @@ impl Qualifs<'mir, 'tcx> { MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env) .unsound_ignore_borrow_on_drop() .into_engine(tcx, &body, def_id.to_def_id()) + .pass_name("const_qualification") .iterate_to_fixpoint() .into_results_cursor(&body) }); @@ -176,6 +180,9 @@ pub struct Validator<'mir, 'tcx> { /// The span of the current statement. span: Span, + + error_emitted: bool, + secondary_errors: Vec, } impl Deref for Validator<'mir, 'tcx> { @@ -188,36 +195,83 @@ impl Deref for Validator<'mir, 'tcx> { impl Validator<'mir, 'tcx> { pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { - Validator { span: ccx.body.span, ccx, qualifs: Default::default() } + Validator { + span: ccx.body.span, + ccx, + qualifs: Default::default(), + error_emitted: false, + secondary_errors: Vec::new(), + } } pub fn check_body(&mut self) { - let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx; + let ConstCx { tcx, body, def_id, .. } = *self.ccx; + + // `async` functions cannot be `const fn`. This is checked during AST lowering, so there's + // no need to emit duplicate errors here. + if is_async_fn(self.ccx) || body.generator_kind.is_some() { + tcx.sess.delay_span_bug(body.span, "`async` functions cannot be `const fn`"); + return; + } - let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn) - && crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id())) - && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you; + // The local type and predicate checks are not free and only relevant for `const fn`s. + if self.const_kind() == hir::ConstContext::ConstFn { + // Prevent const trait methods from being annotated as `stable`. + // FIXME: Do this as part of stability checking. + if self.is_const_stable_const_fn() { + let hir_id = tcx.hir().local_def_id_to_hir_id(self.def_id); + if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { + struct_span_err!( + self.ccx.tcx.sess, + self.span, + E0723, + "trait methods cannot be stable const fn" + ) + .emit(); + } + } - if use_min_const_fn_checks { - // Enforce `min_const_fn` for stable `const fn`s. - use crate::transform::qualify_min_const_fn::is_min_const_fn; - if let Err((span, err)) = is_min_const_fn(tcx, def_id.to_def_id(), &body) { - error_min_const_fn_violation(tcx, span, err); - return; + self.check_item_predicates(); + + for (idx, local) in body.local_decls.iter_enumerated() { + // Handle the return place below. + if idx == RETURN_PLACE || local.internal { + continue; + } + + self.span = local.source_info.span; + self.check_local_or_return_ty(local.ty, idx); } + + // impl trait is gone in MIR, so check the return type of a const fn by its signature + // instead of the type of the return place. + self.span = body.local_decls[RETURN_PLACE].source_info.span; + let return_ty = tcx.fn_sig(def_id).output(); + self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); } self.visit_body(&body); // Ensure that the end result is `Sync` in a non-thread local `static`. - let should_check_for_sync = const_kind - == Some(hir::ConstContext::Static(hir::Mutability::Not)) + let should_check_for_sync = self.const_kind() + == hir::ConstContext::Static(hir::Mutability::Not) && !tcx.is_thread_local_static(def_id.to_def_id()); if should_check_for_sync { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); check_return_ty_is_sync(tcx, &body, hir_id); } + + // If we got through const-checking without emitting any "primary" errors, emit any + // "secondary" errors if they occurred. + let secondary_errors = mem::take(&mut self.secondary_errors); + if !self.error_emitted { + for error in secondary_errors { + self.tcx.sess.diagnostic().emit_diagnostic(&error); + } + } else { + assert!(self.tcx.sess.has_errors()); + } } pub fn qualifs_in_return_place(&mut self) -> ConstQualifs { @@ -226,13 +280,45 @@ impl Validator<'mir, 'tcx> { /// Emits an error if an expression cannot be evaluated in the current context. pub fn check_op(&mut self, op: impl NonConstOp) { - ops::non_const(self.ccx, op, self.span); + self.check_op_spanned(op, self.span); } /// Emits an error at the given `span` if an expression cannot be evaluated in the current /// context. - pub fn check_op_spanned(&mut self, op: impl NonConstOp, span: Span) { - ops::non_const(self.ccx, op, span); + pub fn check_op_spanned(&mut self, op: O, span: Span) { + let gate = match op.status_in_item(self.ccx) { + Status::Allowed => return, + + Status::Unstable(gate) if self.tcx.features().enabled(gate) => { + let unstable_in_stable = self.ccx.is_const_stable_const_fn() + && !super::allow_internal_unstable(self.tcx, self.def_id.to_def_id(), gate); + if unstable_in_stable { + emit_unstable_in_stable_error(self.ccx, span, gate); + } + + return; + } + + Status::Unstable(gate) => Some(gate), + Status::Forbidden => None, + }; + + if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { + self.tcx.sess.miri_unleashed_feature(span, gate); + return; + } + + let mut err = op.build_error(self.ccx, span); + assert!(err.is_error()); + + match op.importance() { + ops::DiagnosticImportance::Primary => { + self.error_emitted = true; + err.emit(); + } + + ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors), + } } fn check_static(&mut self, def_id: DefId, span: Span) { @@ -242,6 +328,106 @@ impl Validator<'mir, 'tcx> { ); self.check_op_spanned(ops::StaticAccess, span) } + + fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { + let kind = self.body.local_kind(local); + + for ty in ty.walk() { + let ty = match ty.unpack() { + GenericArgKind::Type(ty) => ty, + + // No constraints on lifetimes or constants, except potentially + // constants' types, but `walk` will get to them as well. + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + }; + + match *ty.kind() { + ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)), + ty::Opaque(..) => self.check_op(ops::ty::ImplTrait), + ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)), + + ty::Dynamic(preds, _) => { + for pred in preds.iter() { + match pred.skip_binder() { + ty::ExistentialPredicate::AutoTrait(_) + | ty::ExistentialPredicate::Projection(_) => { + self.check_op(ops::ty::TraitBound(kind)) + } + ty::ExistentialPredicate::Trait(trait_ref) => { + if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() { + self.check_op(ops::ty::TraitBound(kind)) + } + } + } + } + } + _ => {} + } + } + } + + fn check_item_predicates(&mut self) { + let ConstCx { tcx, def_id, .. } = *self.ccx; + + let mut current = def_id.to_def_id(); + loop { + let predicates = tcx.predicates_of(current); + for (predicate, _) in predicates.predicates { + match predicate.skip_binders() { + ty::PredicateAtom::RegionOutlives(_) + | ty::PredicateAtom::TypeOutlives(_) + | ty::PredicateAtom::WellFormed(_) + | ty::PredicateAtom::Projection(_) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue, + ty::PredicateAtom::ObjectSafe(_) => { + bug!("object safe predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::ClosureKind(..) => { + bug!("closure kind predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Subtype(_) => { + bug!("subtype predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Trait(pred, constness) => { + if Some(pred.def_id()) == tcx.lang_items().sized_trait() { + continue; + } + match pred.self_ty().kind() { + ty::Param(p) => { + let generics = tcx.generics_of(current); + let def = generics.type_param(p, tcx); + let span = tcx.def_span(def.def_id); + + // These are part of the function signature, so treat them like + // arguments when determining importance. + let kind = LocalKind::Arg; + + if constness == hir::Constness::Const { + self.check_op_spanned(ops::ty::TraitBound(kind), span); + } else if !tcx.features().const_fn + || self.ccx.is_const_stable_const_fn() + { + // HACK: We shouldn't need the conditional above, but trait + // bounds on containing impl blocks are wrongly being marked as + // "not-const". + self.check_op_spanned(ops::ty::TraitBound(kind), span); + } + } + // other kinds of bounds are either tautologies + // or cause errors in other passes + _ => continue, + } + } + } + } + match predicates.parent { + Some(parent) => current = parent, + None => break, + } + } + } } impl Visitor<'tcx> for Validator<'mir, 'tcx> { @@ -309,11 +495,6 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { Rvalue::Use(_) | Rvalue::Repeat(..) - | Rvalue::UnaryOp(UnOp::Neg, _) - | Rvalue::UnaryOp(UnOp::Not, _) - | Rvalue::NullaryOp(NullOp::SizeOf, _) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::Cast(CastKind::Pointer(_), ..) | Rvalue::Discriminant(..) | Rvalue::Len(_) | Rvalue::Aggregate(..) => {} @@ -321,7 +502,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place) | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => { let ty = place.ty(self.body, self.tcx).ty; - let is_allowed = match ty.kind { + let is_allowed = match ty.kind() { // Inside a `static mut`, `&mut [...]` is allowed. ty::Array(..) | ty::Slice(_) if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) => @@ -363,6 +544,35 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } + Rvalue::Cast( + CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), + _, + _, + ) => {} + + Rvalue::Cast( + CastKind::Pointer( + PointerCast::UnsafeFnPointer + | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyFnPointer, + ), + _, + _, + ) => self.check_op(ops::FnPtrCast), + + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, cast_ty) => { + if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) { + let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env); + + // Casting/coercing things to slices is fine. + if let ty::Slice(_) | ty::Str = unsized_ty.kind() { + return; + } + } + + self.check_op(ops::UnsizingCast); + } + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); @@ -373,8 +583,29 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } - Rvalue::BinaryOp(op, ref lhs, _) => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { + Rvalue::NullaryOp(NullOp::SizeOf, _) => {} + Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), + + Rvalue::UnaryOp(_, ref operand) => { + let ty = operand.ty(self.body, self.tcx); + if is_int_bool_or_char(ty) { + // Int, bool, and char operations are fine. + } else if ty.is_floating_point() { + self.check_op(ops::FloatingPointOp); + } else { + span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty); + } + } + + Rvalue::BinaryOp(op, ref lhs, ref rhs) + | Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { + let lhs_ty = lhs.ty(self.body, self.tcx); + let rhs_ty = rhs.ty(self.body, self.tcx); + + if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) { + // Int, bool, and char operations are fine. + } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { + assert_eq!(lhs_ty, rhs_ty); assert!( op == BinOp::Eq || op == BinOp::Ne @@ -386,12 +617,17 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { ); self.check_op(ops::RawPtrComparison); + } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() { + self.check_op(ops::FloatingPointOp); + } else { + span_bug!( + self.span, + "non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}", + lhs_ty, + rhs_ty + ); } } - - Rvalue::NullaryOp(NullOp::Box, _) => { - self.check_op(ops::HeapAllocation); - } } } @@ -426,7 +662,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { match elem { ProjectionElem::Deref => { let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty; - if let ty::RawPtr(_) = base_ty.kind { + if let ty::RawPtr(_) = base_ty.kind() { if proj_base.is_empty() { if let (local, []) = (place_local, proj_base) { let decl = &self.body.local_decls[local]; @@ -491,14 +727,19 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + use rustc_target::spec::abi::Abi::RustIntrinsic; + trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); self.super_terminator(terminator, location); match &terminator.kind { TerminatorKind::Call { func, .. } => { - let fn_ty = func.ty(self.body, self.tcx); + let ConstCx { tcx, body, def_id: caller, param_env, .. } = *self.ccx; + let caller = caller.to_def_id(); + + let fn_ty = func.ty(body, tcx); - let (def_id, substs) = match fn_ty.kind { + let (mut callee, substs) = match *fn_ty.kind() { ty::FnDef(def_id, substs) => (def_id, substs), ty::FnPtr(_) => { @@ -510,38 +751,88 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } }; - // At this point, we are calling a function whose `DefId` is known... - if is_const_fn(self.tcx, def_id) { - return; - } - - // See if this is a trait method for a concrete type whose impl of that trait is - // `const`. + // Resolve a trait method call to its concrete implementation, which may be in a + // `const` trait impl. if self.tcx.features().const_trait_impl { - let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs); - debug!("Resolving ({:?}) -> {:?}", def_id, instance); + let instance = Instance::resolve(tcx, param_env, callee, substs); + debug!("Resolving ({:?}) -> {:?}", callee, instance); if let Ok(Some(func)) = instance { if let InstanceDef::Item(def) = func.def { - if is_const_fn(self.tcx, def.did) { - return; - } + callee = def.did; } } } - if is_lang_panic_fn(self.tcx, def_id) { + // At this point, we are calling a function, `callee`, whose `DefId` is known... + + if is_lang_panic_fn(tcx, callee) { self.check_op(ops::Panic); - } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) { - // Exempt unstable const fns inside of macros or functions with - // `#[allow_internal_unstable]`. - use crate::transform::qualify_min_const_fn::lib_feature_allowed; - if !self.span.allows_unstable(feature) - && !lib_feature_allowed(self.tcx, self.def_id.to_def_id(), feature) - { - self.check_op(ops::FnCallUnstable(def_id, feature)); + return; + } + + // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`. + let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn(); + if is_async_block { + let kind = hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block); + self.check_op(ops::Generator(kind)); + return; + } + + // HACK: This is to "unstabilize" the `transmute` intrinsic + // within const fns. `transmute` is allowed in all other const contexts. + // This won't really scale to more intrinsics or functions. Let's allow const + // transmutes in const fn before we add more hacks to this. + if tcx.fn_sig(callee).abi() == RustIntrinsic + && tcx.item_name(callee) == sym::transmute + { + self.check_op(ops::Transmute); + return; + } + + if !tcx.is_const_fn_raw(callee) { + self.check_op(ops::FnCallNonConst(callee)); + return; + } + + // If the `const fn` we are trying to call is not const-stable, ensure that we have + // the proper feature gate enabled. + if let Some(gate) = is_unstable_const_fn(tcx, callee) { + if self.span.allows_unstable(gate) { + return; + } + + // Calling an unstable function *always* requires that the corresponding gate + // be enabled, even if the function has `#[allow_internal_unstable(the_gate)]`. + if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) { + self.check_op(ops::FnCallUnstable(callee, Some(gate))); + return; + } + + // If this crate is not using stability attributes, or the caller is not claiming to be a + // stable `const fn`, that is all that is required. + if !self.ccx.is_const_stable_const_fn() { + return; + } + + // Otherwise, we are something const-stable calling a const-unstable fn. + + if super::allow_internal_unstable(tcx, caller, gate) { + return; + } + + self.check_op(ops::FnCallUnstable(callee, Some(gate))); + return; + } + + // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that + // have no `rustc_const_stable` attributes to be const-unstable as well. This + // should be fixed later. + let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() + && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable()); + if callee_is_unstable_unmarked { + if self.ccx.is_const_stable_const_fn() { + self.check_op(ops::FnCallUnstable(callee, None)); } - } else { - self.check_op(ops::FnCallNonConst(def_id)); } } @@ -551,7 +842,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { // If we are checking live drops after drop-elaboration, don't emit duplicate // errors here. - if super::post_drop_elaboration::checking_enabled(self.tcx) { + if super::post_drop_elaboration::checking_enabled(self.ccx) { return; } @@ -576,43 +867,31 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if needs_drop { self.check_op_spanned( - ops::LiveDrop(Some(terminator.source_info.span)), + ops::LiveDrop { dropped_at: Some(terminator.source_info.span) }, err_span, ); } } - TerminatorKind::InlineAsm { .. } => { - self.check_op(ops::InlineAsm); + TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), + TerminatorKind::Abort => self.check_op(ops::Abort), + + TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { + self.check_op(ops::Generator(hir::GeneratorKind::Gen)) } - // FIXME: Some of these are only caught by `min_const_fn`, but should error here - // instead. - TerminatorKind::Abort - | TerminatorKind::Assert { .. } + TerminatorKind::Assert { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop | TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } => {} + | TerminatorKind::Unreachable => {} } } } -fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>) { - struct_span_err!(tcx.sess, span, E0723, "{}", msg) - .note( - "see issue #57563 \ - for more information", - ) - .help("add `#![feature(const_fn)]` to the crate attributes to enable") - .emit(); -} - fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) { let ty = body.return_ty(); tcx.infer_ctxt().enter(|infcx| { @@ -647,9 +926,41 @@ fn place_as_reborrow( // This is sufficient to prevent an access to a `static mut` from being marked as a // reborrow, even if the check above were to disappear. let inner_ty = Place::ty_from(place.local, inner, body, tcx).ty; - match inner_ty.kind { + match inner_ty.kind() { ty::Ref(..) => Some(inner), _ => None, } }) } + +fn is_int_bool_or_char(ty: Ty<'_>) -> bool { + ty.is_bool() || ty.is_integral() || ty.is_char() +} + +fn is_async_fn(ccx: &ConstCx<'_, '_>) -> bool { + ccx.fn_sig().map_or(false, |sig| sig.header.asyncness == hir::IsAsync::Async) +} + +fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) { + let attr_span = ccx.fn_sig().map_or(ccx.body.span, |sig| sig.span.shrink_to_lo()); + + ccx.tcx + .sess + .struct_span_err( + span, + &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()), + ) + .span_suggestion( + attr_span, + "if it is not part of the public API, make this function unstably const", + concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(), + Applicability::HasPlaceholders, + ) + .span_suggestion( + attr_span, + "otherwise `#[allow_internal_unstable]` can be used to bypass stability checks", + format!("#[allow_internal_unstable({})]\n", gate), + Applicability::MaybeIncorrect, + ) + .emit(); +} diff --git a/src/librustc_mir/transform/check_packed_ref.rs b/compiler/rustc_mir/src/transform/check_packed_ref.rs similarity index 100% rename from src/librustc_mir/transform/check_packed_ref.rs rename to compiler/rustc_mir/src/transform/check_packed_ref.rs diff --git a/src/librustc_mir/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs similarity index 99% rename from src/librustc_mir/transform/check_unsafety.rs rename to compiler/rustc_mir/src/transform/check_unsafety.rs index c3e04e698d..7309a4129e 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -91,8 +91,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { ) } - if let ty::FnDef(func_id, _) = func_ty.kind { - self.check_target_features(func_id); + if let ty::FnDef(func_id, _) = func_ty.kind() { + self.check_target_features(*func_id); } } @@ -227,7 +227,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; - match base_ty.kind { + match base_ty.kind() { ty::RawPtr(..) => self.require_unsafe( UnsafetyViolationKind::GeneralAndConstFn, UnsafetyViolationDetails::DerefOfRawPointer, @@ -394,7 +394,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { ProjectionElem::Field(..) => { let ty = Place::ty_from(place.local, proj_base, &self.body.local_decls, self.tcx).ty; - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { if self.tcx.layout_scalar_valid_range(def.did) != (Bound::Unbounded, Bound::Unbounded) { diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs similarity index 100% rename from src/librustc_mir/transform/cleanup_post_borrowck.rs rename to compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs similarity index 99% rename from src/librustc_mir/transform/const_prop.rs rename to compiler/rustc_mir/src/transform/const_prop.rs index 56479b047f..0f04ead94d 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -832,7 +832,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // FIXME: enable the general case stated above ^. let ty = &value.layout.ty; // Only do it for tuples - if let ty::Tuple(substs) = ty.kind { + if let ty::Tuple(substs) = ty.kind() { // Only do it if tuple is also a pair with two scalars if substs.len() == 2 { let alloc = self.use_ecx(|this| { @@ -1046,9 +1046,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { self.super_operand(operand, location); - // Only const prop copies and moves on `mir_opt_level=3` as doing so - // currently increases compile time. - if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 3 { + // Only const prop copies and moves on `mir_opt_level=2` as doing so + // currently slightly increases compile time in some cases. + if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { self.propagate_operand(operand) } } @@ -1246,8 +1246,8 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { | TerminatorKind::InlineAsm { .. } => {} // Every argument in our function calls have already been propagated in `visit_operand`. // - // NOTE: because LLVM codegen gives performance regressions with it, so this is gated - // on `mir_opt_level=3`. + // NOTE: because LLVM codegen gives slight performance regressions with it, so this is + // gated on `mir_opt_level=2`. TerminatorKind::Call { .. } => {} } diff --git a/src/librustc_mir/transform/copy_prop.rs b/compiler/rustc_mir/src/transform/copy_prop.rs similarity index 98% rename from src/librustc_mir/transform/copy_prop.rs rename to compiler/rustc_mir/src/transform/copy_prop.rs index ba406c72df..74194467b3 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/compiler/rustc_mir/src/transform/copy_prop.rs @@ -31,9 +31,11 @@ pub struct CopyPropagation; impl<'tcx> MirPass<'tcx> for CopyPropagation { fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { + let opts = &tcx.sess.opts.debugging_opts; // We only run when the MIR optimization level is > 1. // This avoids a slow pass, and messing up debug info. - if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { + // FIXME(76740): This optimization is buggy and can cause unsoundness. + if opts.mir_opt_level <= 1 || !opts.unsound_mir_opts { return; } diff --git a/src/librustc_mir/transform/deaggregator.rs b/compiler/rustc_mir/src/transform/deaggregator.rs similarity index 100% rename from src/librustc_mir/transform/deaggregator.rs rename to compiler/rustc_mir/src/transform/deaggregator.rs diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs new file mode 100644 index 0000000000..97d2617607 --- /dev/null +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -0,0 +1,1057 @@ +//! Propagates assignment destinations backwards in the CFG to eliminate redundant assignments. +//! +//! # Motivation +//! +//! MIR building can insert a lot of redundant copies, and Rust code in general often tends to move +//! values around a lot. The result is a lot of assignments of the form `dest = {move} src;` in MIR. +//! MIR building for constants in particular tends to create additional locals that are only used +//! inside a single block to shuffle a value around unnecessarily. +//! +//! LLVM by itself is not good enough at eliminating these redundant copies (eg. see +//! https://github.com/rust-lang/rust/issues/32966), so this leaves some performance on the table +//! that we can regain by implementing an optimization for removing these assign statements in rustc +//! itself. When this optimization runs fast enough, it can also speed up the constant evaluation +//! and code generation phases of rustc due to the reduced number of statements and locals. +//! +//! # The Optimization +//! +//! Conceptually, this optimization is "destination propagation". It is similar to the Named Return +//! Value Optimization, or NRVO, known from the C++ world, except that it isn't limited to return +//! values or the return place `_0`. On a very high level, independent of the actual implementation +//! details, it does the following: +//! +//! 1) Identify `dest = src;` statements that can be soundly eliminated. +//! 2) Replace all mentions of `src` with `dest` ("unifying" them and propagating the destination +//! backwards). +//! 3) Delete the `dest = src;` statement (by making it a `nop`). +//! +//! Step 1) is by far the hardest, so it is explained in more detail below. +//! +//! ## Soundness +//! +//! Given an `Assign` statement `dest = src;`, where `dest` is a `Place` and `src` is an `Rvalue`, +//! there are a few requirements that must hold for the optimization to be sound: +//! +//! * `dest` must not contain any *indirection* through a pointer. It must access part of the base +//! local. Otherwise it might point to arbitrary memory that is hard to track. +//! +//! It must also not contain any indexing projections, since those take an arbitrary `Local` as +//! the index, and that local might only be initialized shortly before `dest` is used. +//! +//! Subtle case: If `dest` is a, or projects through a union, then we have to make sure that there +//! remains an assignment to it, since that sets the "active field" of the union. But if `src` is +//! a ZST, it might not be initialized, so there might not be any use of it before the assignment, +//! and performing the optimization would simply delete the assignment, leaving `dest` +//! uninitialized. +//! +//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Is this a +//! fundamental restriction or just current impl state?). It can be copied or moved by the +//! assignment. +//! +//! * The `dest` and `src` locals must never be [*live*][liveness] at the same time. If they are, it +//! means that they both hold a (potentially different) value that is needed by a future use of +//! the locals. Unifying them would overwrite one of the values. +//! +//! Note that computing liveness of locals that have had their address taken is more difficult: +//! Short of doing full escape analysis on the address/pointer/reference, the pass would need to +//! assume that any operation that can potentially involve opaque user code (such as function +//! calls, destructors, and inline assembly) may access any local that had its address taken +//! before that point. +//! +//! Here, the first two conditions are simple structural requirements on the `Assign` statements +//! that can be trivially checked. The liveness requirement however is more difficult and costly to +//! check. +//! +//! ## Previous Work +//! +//! A [previous attempt] at implementing an optimization like this turned out to be a significant +//! regression in compiler performance. Fixing the regressions introduced a lot of undesirable +//! complexity to the implementation. +//! +//! A [subsequent approach] tried to avoid the costly computation by limiting itself to acyclic +//! CFGs, but still turned out to be far too costly to run due to suboptimal performance within +//! individual basic blocks, requiring a walk across the entire block for every assignment found +//! within the block. For the `tuple-stress` benchmark, which has 458745 statements in a single +//! block, this proved to be far too costly. +//! +//! Since the first attempt at this, the compiler has improved dramatically, and new analysis +//! frameworks have been added that should make this approach viable without requiring a limited +//! approach that only works for some classes of CFGs: +//! - rustc now has a powerful dataflow analysis framework that can handle forwards and backwards +//! analyses efficiently. +//! - Layout optimizations for generators have been added to improve code generation for +//! async/await, which are very similar in spirit to what this optimization does. Both walk the +//! MIR and record conflicting uses of locals in a `BitMatrix`. +//! +//! Also, rustc now has a simple NRVO pass (see `nrvo.rs`), which handles a subset of the cases that +//! this destination propagation pass handles, proving that similar optimizations can be performed +//! on MIR. +//! +//! ## Pre/Post Optimization +//! +//! It is recommended to run `SimplifyCfg` and then `SimplifyLocals` some time after this pass, as +//! it replaces the eliminated assign statements with `nop`s and leaves unused locals behind. +//! +//! [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis +//! [previous attempt]: https://github.com/rust-lang/rust/pull/47954 +//! [subsequent approach]: https://github.com/rust-lang/rust/pull/71003 + +use crate::dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals}; +use crate::dataflow::Analysis; +use crate::{ + transform::{MirPass, MirSource}, + util::{dump_mir, PassWhere}, +}; +use itertools::Itertools; +use rustc_data_structures::unify::{InPlaceUnificationTable, UnifyKey}; +use rustc_index::{ + bit_set::{BitMatrix, BitSet}, + vec::IndexVec, +}; +use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::{ + traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem, + Rvalue, Statement, StatementKind, Terminator, TerminatorKind, +}; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +// Empirical measurements have resulted in some observations: +// - Running on a body with a single block and 500 locals takes barely any time +// - Running on a body with ~400 blocks and ~300 relevant locals takes "too long" +// ...so we just limit both to somewhat reasonable-ish looking values. +const MAX_LOCALS: usize = 500; +const MAX_BLOCKS: usize = 250; + +pub struct DestinationPropagation; + +impl<'tcx> MirPass<'tcx> for DestinationPropagation { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + // Only run at mir-opt-level=2 or higher for now (we don't fix up debuginfo and remove + // storage statements at the moment). + if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { + return; + } + + let candidates = find_candidates(tcx, body); + if candidates.is_empty() { + debug!("{:?}: no dest prop candidates, done", source.def_id()); + return; + } + + // Collect all locals we care about. We only compute conflicts for these to save time. + let mut relevant_locals = BitSet::new_empty(body.local_decls.len()); + for CandidateAssignment { dest, src, loc: _ } in &candidates { + relevant_locals.insert(dest.local); + relevant_locals.insert(*src); + } + + // This pass unfortunately has `O(l² * s)` performance, where `l` is the number of locals + // and `s` is the number of statements and terminators in the function. + // To prevent blowing up compile times too much, we bail out when there are too many locals. + let relevant = relevant_locals.count(); + debug!( + "{:?}: {} locals ({} relevant), {} blocks", + source.def_id(), + body.local_decls.len(), + relevant, + body.basic_blocks().len() + ); + if relevant > MAX_LOCALS { + warn!( + "too many candidate locals in {:?} ({}, max is {}), not optimizing", + source.def_id(), + relevant, + MAX_LOCALS + ); + return; + } + if body.basic_blocks().len() > MAX_BLOCKS { + warn!( + "too many blocks in {:?} ({}, max is {}), not optimizing", + source.def_id(), + body.basic_blocks().len(), + MAX_BLOCKS + ); + return; + } + + let mut conflicts = Conflicts::build(tcx, body, source, &relevant_locals); + + let mut replacements = Replacements::new(body.local_decls.len()); + for candidate @ CandidateAssignment { dest, src, loc } in candidates { + // Merge locals that don't conflict. + if !conflicts.can_unify(dest.local, src) { + debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src); + continue; + } + + if replacements.for_src(candidate.src).is_some() { + debug!("src {:?} already has replacement", candidate.src); + continue; + } + + if !tcx.consider_optimizing(|| { + format!("DestinationPropagation {:?} {:?}", source.def_id(), candidate) + }) { + break; + } + + replacements.push(candidate); + conflicts.unify(candidate.src, candidate.dest.local); + } + + replacements.flatten(tcx); + + debug!("replacements {:?}", replacements.map); + + Replacer { tcx, replacements, place_elem_cache: Vec::new() }.visit_body(body); + + // FIXME fix debug info + } +} + +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +struct UnifyLocal(Local); + +impl From for UnifyLocal { + fn from(l: Local) -> Self { + Self(l) + } +} + +impl UnifyKey for UnifyLocal { + type Value = (); + fn index(&self) -> u32 { + self.0.as_u32() + } + fn from_index(u: u32) -> Self { + Self(Local::from_u32(u)) + } + fn tag() -> &'static str { + "UnifyLocal" + } +} + +struct Replacements<'tcx> { + /// Maps locals to their replacement. + map: IndexVec>>, + + /// Whose locals' live ranges to kill. + kill: BitSet, +} + +impl Replacements<'tcx> { + fn new(locals: usize) -> Self { + Self { map: IndexVec::from_elem_n(None, locals), kill: BitSet::new_empty(locals) } + } + + fn push(&mut self, candidate: CandidateAssignment<'tcx>) { + trace!("Replacements::push({:?})", candidate); + let entry = &mut self.map[candidate.src]; + assert!(entry.is_none()); + + *entry = Some(candidate.dest); + self.kill.insert(candidate.src); + self.kill.insert(candidate.dest.local); + } + + /// Applies the stored replacements to all replacements, until no replacements would result in + /// locals that need further replacements when applied. + fn flatten(&mut self, tcx: TyCtxt<'tcx>) { + // Note: This assumes that there are no cycles in the replacements, which is enforced via + // `self.unified_locals`. Otherwise this can cause an infinite loop. + + for local in self.map.indices() { + if let Some(replacement) = self.map[local] { + // Substitute the base local of `replacement` until fixpoint. + let mut base = replacement.local; + let mut reversed_projection_slices = Vec::with_capacity(1); + while let Some(replacement_for_replacement) = self.map[base] { + base = replacement_for_replacement.local; + reversed_projection_slices.push(replacement_for_replacement.projection); + } + + let projection: Vec<_> = reversed_projection_slices + .iter() + .rev() + .flat_map(|projs| projs.iter()) + .chain(replacement.projection.iter()) + .collect(); + let projection = tcx.intern_place_elems(&projection); + + // Replace with the final `Place`. + self.map[local] = Some(Place { local: base, projection }); + } + } + } + + fn for_src(&self, src: Local) -> Option> { + self.map[src] + } +} + +struct Replacer<'tcx> { + tcx: TyCtxt<'tcx>, + replacements: Replacements<'tcx>, + place_elem_cache: Vec>, +} + +impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, context: PlaceContext, location: Location) { + if context.is_use() && self.replacements.for_src(*local).is_some() { + bug!( + "use of local {:?} should have been replaced by visit_place; context={:?}, loc={:?}", + local, + context, + location, + ); + } + } + + fn process_projection_elem( + &mut self, + elem: PlaceElem<'tcx>, + _: Location, + ) -> Option> { + match elem { + PlaceElem::Index(local) => { + if let Some(replacement) = self.replacements.for_src(local) { + bug!( + "cannot replace {:?} with {:?} in index projection {:?}", + local, + replacement, + elem, + ); + } else { + None + } + } + _ => None, + } + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { + if let Some(replacement) = self.replacements.for_src(place.local) { + // Rebase `place`s projections onto `replacement`'s. + self.place_elem_cache.clear(); + self.place_elem_cache.extend(replacement.projection.iter().chain(place.projection)); + let projection = self.tcx.intern_place_elems(&self.place_elem_cache); + let new_place = Place { local: replacement.local, projection }; + + debug!("Replacer: {:?} -> {:?}", place, new_place); + *place = new_place; + } + + self.super_place(place, context, location); + } + + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + self.super_statement(statement, location); + + match &statement.kind { + // FIXME: Don't delete storage statements, merge the live ranges instead + StatementKind::StorageDead(local) | StatementKind::StorageLive(local) + if self.replacements.kill.contains(*local) => + { + statement.make_nop() + } + + StatementKind::Assign(box (dest, rvalue)) => { + match rvalue { + Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { + // These might've been turned into self-assignments by the replacement + // (this includes the original statement we wanted to eliminate). + if dest == place { + debug!("{:?} turned into self-assignment, deleting", location); + statement.make_nop(); + } + } + _ => {} + } + } + + _ => {} + } + } +} + +struct Conflicts<'a> { + relevant_locals: &'a BitSet, + + /// The conflict matrix. It is always symmetric and the adjacency matrix of the corresponding + /// conflict graph. + matrix: BitMatrix, + + /// Preallocated `BitSet` used by `unify`. + unify_cache: BitSet, + + /// Tracks locals that have been merged together to prevent cycles and propagate conflicts. + unified_locals: InPlaceUnificationTable, +} + +impl Conflicts<'a> { + fn build<'tcx>( + tcx: TyCtxt<'tcx>, + body: &'_ Body<'tcx>, + source: MirSource<'tcx>, + relevant_locals: &'a BitSet, + ) -> Self { + // We don't have to look out for locals that have their address taken, since + // `find_candidates` already takes care of that. + + let conflicts = BitMatrix::from_row_n( + &BitSet::new_empty(body.local_decls.len()), + body.local_decls.len(), + ); + + let def_id = source.def_id(); + let mut init = MaybeInitializedLocals + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); + let mut live = MaybeLiveLocals + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); + + let mut reachable = None; + dump_mir( + tcx, + None, + "DestinationPropagation-dataflow", + &"", + source, + body, + |pass_where, w| { + let reachable = + reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body)); + + match pass_where { + PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => { + init.seek_before_primary_effect(loc); + live.seek_after_primary_effect(loc); + + writeln!(w, " // init: {:?}", init.get())?; + writeln!(w, " // live: {:?}", live.get())?; + } + PassWhere::AfterTerminator(bb) if reachable.contains(bb) => { + let loc = body.terminator_loc(bb); + init.seek_after_primary_effect(loc); + live.seek_before_primary_effect(loc); + + writeln!(w, " // init: {:?}", init.get())?; + writeln!(w, " // live: {:?}", live.get())?; + } + + PassWhere::BeforeBlock(bb) if reachable.contains(bb) => { + init.seek_to_block_start(bb); + live.seek_to_block_start(bb); + + writeln!(w, " // init: {:?}", init.get())?; + writeln!(w, " // live: {:?}", live.get())?; + } + + PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {} + + PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => { + writeln!(w, " // init: ")?; + writeln!(w, " // live: ")?; + } + + PassWhere::BeforeBlock(_) => { + writeln!(w, " // init: ")?; + writeln!(w, " // live: ")?; + } + } + + Ok(()) + }, + ); + + let mut this = Self { + relevant_locals, + matrix: conflicts, + unify_cache: BitSet::new_empty(body.local_decls.len()), + unified_locals: { + let mut table = InPlaceUnificationTable::new(); + // Pre-fill table with all locals (this creates N nodes / "connected" components, + // "graph"-ically speaking). + for local in 0..body.local_decls.len() { + assert_eq!(table.new_key(()), UnifyLocal(Local::from_usize(local))); + } + table + }, + }; + + let mut live_and_init_locals = Vec::new(); + + // Visit only reachable basic blocks. The exact order is not important. + for (block, data) in traversal::preorder(body) { + // We need to observe the dataflow state *before* all possible locations (statement or + // terminator) in each basic block, and then observe the state *after* the terminator + // effect is applied. As long as neither `init` nor `borrowed` has a "before" effect, + // we will observe all possible dataflow states. + + // Since liveness is a backwards analysis, we need to walk the results backwards. To do + // that, we first collect in the `MaybeInitializedLocals` results in a forwards + // traversal. + + live_and_init_locals.resize_with(data.statements.len() + 1, || { + BitSet::new_empty(body.local_decls.len()) + }); + + // First, go forwards for `MaybeInitializedLocals` and apply intra-statement/terminator + // conflicts. + for (i, statement) in data.statements.iter().enumerate() { + this.record_statement_conflicts(statement); + + let loc = Location { block, statement_index: i }; + init.seek_before_primary_effect(loc); + + live_and_init_locals[i].clone_from(init.get()); + } + + this.record_terminator_conflicts(data.terminator()); + let term_loc = Location { block, statement_index: data.statements.len() }; + init.seek_before_primary_effect(term_loc); + live_and_init_locals[term_loc.statement_index].clone_from(init.get()); + + // Now, go backwards and union with the liveness results. + for statement_index in (0..=data.statements.len()).rev() { + let loc = Location { block, statement_index }; + live.seek_after_primary_effect(loc); + + live_and_init_locals[statement_index].intersect(live.get()); + + trace!("record conflicts at {:?}", loc); + + this.record_dataflow_conflicts(&mut live_and_init_locals[statement_index]); + } + + init.seek_to_block_end(block); + live.seek_to_block_end(block); + let mut conflicts = init.get().clone(); + conflicts.intersect(live.get()); + trace!("record conflicts at end of {:?}", block); + + this.record_dataflow_conflicts(&mut conflicts); + } + + this + } + + fn record_dataflow_conflicts(&mut self, new_conflicts: &mut BitSet) { + // Remove all locals that are not candidates. + new_conflicts.intersect(self.relevant_locals); + + for local in new_conflicts.iter() { + self.matrix.union_row_with(&new_conflicts, local); + } + } + + fn record_local_conflict(&mut self, a: Local, b: Local, why: &str) { + trace!("conflict {:?} <-> {:?} due to {}", a, b, why); + self.matrix.insert(a, b); + self.matrix.insert(b, a); + } + + /// Records locals that must not overlap during the evaluation of `stmt`. These locals conflict + /// and must not be merged. + fn record_statement_conflicts(&mut self, stmt: &Statement<'_>) { + match &stmt.kind { + // While the left and right sides of an assignment must not overlap, we do not mark + // conflicts here as that would make this optimization useless. When we optimize, we + // eliminate the resulting self-assignments automatically. + StatementKind::Assign(_) => {} + + StatementKind::LlvmInlineAsm(asm) => { + // Inputs and outputs must not overlap. + for (_, input) in &*asm.inputs { + if let Some(in_place) = input.place() { + if !in_place.is_indirect() { + for out_place in &*asm.outputs { + if !out_place.is_indirect() && !in_place.is_indirect() { + self.record_local_conflict( + in_place.local, + out_place.local, + "aliasing llvm_asm! operands", + ); + } + } + } + } + } + } + + StatementKind::SetDiscriminant { .. } + | StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::Retag(..) + | StatementKind::FakeRead(..) + | StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) + | StatementKind::Nop => {} + } + } + + fn record_terminator_conflicts(&mut self, term: &Terminator<'_>) { + match &term.kind { + TerminatorKind::DropAndReplace { + place: dropped_place, + value, + target: _, + unwind: _, + } => { + if let Some(place) = value.place() { + if !place.is_indirect() && !dropped_place.is_indirect() { + self.record_local_conflict( + place.local, + dropped_place.local, + "DropAndReplace operand overlap", + ); + } + } + } + TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { + if let Some(place) = value.place() { + if !place.is_indirect() && !resume_arg.is_indirect() { + self.record_local_conflict( + place.local, + resume_arg.local, + "Yield operand overlap", + ); + } + } + } + TerminatorKind::Call { + func, + args, + destination: Some((dest_place, _)), + cleanup: _, + from_hir_call: _, + fn_span: _, + } => { + // No arguments may overlap with the destination. + for arg in args.iter().chain(Some(func)) { + if let Some(place) = arg.place() { + if !place.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + dest_place.local, + place.local, + "call dest/arg overlap", + ); + } + } + } + } + TerminatorKind::InlineAsm { + template: _, + operands, + options: _, + line_spans: _, + destination: _, + } => { + // The intended semantics here aren't documented, we just assume that nothing that + // could be written to by the assembly may overlap with any other operands. + for op in operands { + match op { + InlineAsmOperand::Out { reg: _, late: _, place: Some(dest_place) } + | InlineAsmOperand::InOut { + reg: _, + late: _, + in_value: _, + out_place: Some(dest_place), + } => { + // For output place `place`, add all places accessed by the inline asm. + for op in operands { + match op { + InlineAsmOperand::In { reg: _, value } => { + if let Some(p) = value.place() { + if !p.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + p.local, + dest_place.local, + "asm! operand overlap", + ); + } + } + } + InlineAsmOperand::Out { + reg: _, + late: _, + place: Some(place), + } => { + if !place.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + place.local, + dest_place.local, + "asm! operand overlap", + ); + } + } + InlineAsmOperand::InOut { + reg: _, + late: _, + in_value, + out_place, + } => { + if let Some(place) = in_value.place() { + if !place.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + place.local, + dest_place.local, + "asm! operand overlap", + ); + } + } + + if let Some(place) = out_place { + if !place.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + place.local, + dest_place.local, + "asm! operand overlap", + ); + } + } + } + InlineAsmOperand::Out { reg: _, late: _, place: None } + | InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::SymFn { value: _ } + | InlineAsmOperand::SymStatic { def_id: _ } => {} + } + } + } + InlineAsmOperand::Const { value } => { + assert!(value.place().is_none()); + } + InlineAsmOperand::InOut { + reg: _, + late: _, + in_value: _, + out_place: None, + } + | InlineAsmOperand::In { reg: _, value: _ } + | InlineAsmOperand::Out { reg: _, late: _, place: None } + | InlineAsmOperand::SymFn { value: _ } + | InlineAsmOperand::SymStatic { def_id: _ } => {} + } + } + } + + TerminatorKind::Goto { .. } + | TerminatorKind::Call { destination: None, .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => {} + } + } + + /// Checks whether `a` and `b` may be merged. Returns `false` if there's a conflict. + fn can_unify(&mut self, a: Local, b: Local) -> bool { + // After some locals have been unified, their conflicts are only tracked in the root key, + // so look that up. + let a = self.unified_locals.find(a).0; + let b = self.unified_locals.find(b).0; + + if a == b { + // Already merged (part of the same connected component). + return false; + } + + if self.matrix.contains(a, b) { + // Conflict (derived via dataflow, intra-statement conflicts, or inherited from another + // local during unification). + return false; + } + + true + } + + /// Merges the conflicts of `a` and `b`, so that each one inherits all conflicts of the other. + /// + /// `can_unify` must have returned `true` for the same locals, or this may panic or lead to + /// miscompiles. + /// + /// This is called when the pass makes the decision to unify `a` and `b` (or parts of `a` and + /// `b`) and is needed to ensure that future unification decisions take potentially newly + /// introduced conflicts into account. + /// + /// For an example, assume we have locals `_0`, `_1`, `_2`, and `_3`. There are these conflicts: + /// + /// * `_0` <-> `_1` + /// * `_1` <-> `_2` + /// * `_3` <-> `_0` + /// + /// We then decide to merge `_2` with `_3` since they don't conflict. Then we decide to merge + /// `_2` with `_0`, which also doesn't have a conflict in the above list. However `_2` is now + /// `_3`, which does conflict with `_0`. + fn unify(&mut self, a: Local, b: Local) { + trace!("unify({:?}, {:?})", a, b); + + // Get the root local of the connected components. The root local stores the conflicts of + // all locals in the connected component (and *is stored* as the conflicting local of other + // locals). + let a = self.unified_locals.find(a).0; + let b = self.unified_locals.find(b).0; + assert_ne!(a, b); + + trace!("roots: a={:?}, b={:?}", a, b); + trace!("{:?} conflicts: {:?}", a, self.matrix.iter(a).format(", ")); + trace!("{:?} conflicts: {:?}", b, self.matrix.iter(b).format(", ")); + + self.unified_locals.union(a, b); + + let root = self.unified_locals.find(a).0; + assert!(root == a || root == b); + + // Make all locals that conflict with `a` also conflict with `b`, and vice versa. + self.unify_cache.clear(); + for conflicts_with_a in self.matrix.iter(a) { + self.unify_cache.insert(conflicts_with_a); + } + for conflicts_with_b in self.matrix.iter(b) { + self.unify_cache.insert(conflicts_with_b); + } + for conflicts_with_a_or_b in self.unify_cache.iter() { + // Set both `a` and `b` for this local's row. + self.matrix.insert(conflicts_with_a_or_b, a); + self.matrix.insert(conflicts_with_a_or_b, b); + } + + // Write the locals `a` conflicts with to `b`'s row. + self.matrix.union_rows(a, b); + // Write the locals `b` conflicts with to `a`'s row. + self.matrix.union_rows(b, a); + } +} + +/// A `dest = {move} src;` statement at `loc`. +/// +/// We want to consider merging `dest` and `src` due to this assignment. +#[derive(Debug, Copy, Clone)] +struct CandidateAssignment<'tcx> { + /// Does not contain indirection or indexing (so the only local it contains is the place base). + dest: Place<'tcx>, + src: Local, + loc: Location, +} + +/// Scans the MIR for assignments between locals that we might want to consider merging. +/// +/// This will filter out assignments that do not match the right form (as described in the top-level +/// comment) and also throw out assignments that involve a local that has its address taken or is +/// otherwise ineligible (eg. locals used as array indices are ignored because we cannot propagate +/// arbitrary places into array indices). +fn find_candidates<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, +) -> Vec> { + let mut visitor = FindAssignments { + tcx, + body, + candidates: Vec::new(), + ever_borrowed_locals: ever_borrowed_locals(body), + locals_used_as_array_index: locals_used_as_array_index(body), + }; + visitor.visit_body(body); + visitor.candidates +} + +struct FindAssignments<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + candidates: Vec>, + ever_borrowed_locals: BitSet, + locals_used_as_array_index: BitSet, +} + +impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + if let StatementKind::Assign(box ( + dest, + Rvalue::Use(Operand::Copy(src) | Operand::Move(src)), + )) = &statement.kind + { + // `dest` must not have pointer indirection. + if dest.is_indirect() { + return; + } + + // `src` must be a plain local. + if !src.projection.is_empty() { + return; + } + + // Since we want to replace `src` with `dest`, `src` must not be required. + if is_local_required(src.local, self.body) { + return; + } + + // Can't optimize if both locals ever have their address taken (can introduce + // aliasing). + // FIXME: This can be smarter and take `StorageDead` into account (which + // invalidates borrows). + if self.ever_borrowed_locals.contains(dest.local) + || self.ever_borrowed_locals.contains(src.local) + { + return; + } + + assert_ne!(dest.local, src.local, "self-assignments are UB"); + + // We can't replace locals occurring in `PlaceElem::Index` for now. + if self.locals_used_as_array_index.contains(src.local) { + return; + } + + // Handle the "subtle case" described above by rejecting any `dest` that is or + // projects through a union. + let is_union = |ty: Ty<'_>| { + if let ty::Adt(def, _) = ty.kind() { + if def.is_union() { + return true; + } + } + + false + }; + let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty); + if is_union(place_ty.ty) { + return; + } + for elem in dest.projection { + if let PlaceElem::Index(_) = elem { + // `dest` contains an indexing projection. + return; + } + + place_ty = place_ty.projection_ty(self.tcx, elem); + if is_union(place_ty.ty) { + return; + } + } + + self.candidates.push(CandidateAssignment { + dest: *dest, + src: src.local, + loc: location, + }); + } + } +} + +/// Some locals are part of the function's interface and can not be removed. +/// +/// Note that these locals *can* still be merged with non-required locals by removing that other +/// local. +fn is_local_required(local: Local, body: &Body<'_>) -> bool { + match body.local_kind(local) { + LocalKind::Arg | LocalKind::ReturnPointer => true, + LocalKind::Var | LocalKind::Temp => false, + } +} + +/// Walks MIR to find all locals that have their address taken anywhere. +fn ever_borrowed_locals(body: &Body<'_>) -> BitSet { + let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) }; + visitor.visit_body(body); + visitor.locals +} + +struct BorrowCollector { + locals: BitSet, +} + +impl<'tcx> Visitor<'tcx> for BorrowCollector { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + + match rvalue { + Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { + if !borrowed_place.is_indirect() { + self.locals.insert(borrowed_place.local); + } + } + + Rvalue::Cast(..) + | Rvalue::Use(..) + | Rvalue::Repeat(..) + | Rvalue::Len(..) + | Rvalue::BinaryOp(..) + | Rvalue::CheckedBinaryOp(..) + | Rvalue::NullaryOp(..) + | Rvalue::UnaryOp(..) + | Rvalue::Discriminant(..) + | Rvalue::Aggregate(..) + | Rvalue::ThreadLocalRef(..) => {} + } + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); + + match terminator.kind { + TerminatorKind::Drop { place: dropped_place, .. } + | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { + self.locals.insert(dropped_place.local); + } + + TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable + | TerminatorKind::Yield { .. } + | TerminatorKind::InlineAsm { .. } => {} + } + } +} + +/// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`. +/// +/// Collect locals used as indices so we don't generate candidates that are impossible to apply +/// later. +fn locals_used_as_array_index(body: &Body<'_>) -> BitSet { + let mut visitor = IndexCollector { locals: BitSet::new_empty(body.local_decls.len()) }; + visitor.visit_body(body); + visitor.locals +} + +struct IndexCollector { + locals: BitSet, +} + +impl<'tcx> Visitor<'tcx> for IndexCollector { + fn visit_projection_elem( + &mut self, + local: Local, + proj_base: &[PlaceElem<'tcx>], + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + if let PlaceElem::Index(i) = elem { + self.locals.insert(i); + } + self.super_projection_elem(local, proj_base, elem, context, location); + } +} diff --git a/src/librustc_mir/transform/dump_mir.rs b/compiler/rustc_mir/src/transform/dump_mir.rs similarity index 100% rename from src/librustc_mir/transform/dump_mir.rs rename to compiler/rustc_mir/src/transform/dump_mir.rs diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs new file mode 100644 index 0000000000..ba64e6c1e5 --- /dev/null +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -0,0 +1,339 @@ +use crate::{ + transform::{MirPass, MirSource}, + util::patch::MirPatch, +}; +use rustc_middle::mir::*; +use rustc_middle::ty::{Ty, TyCtxt}; +use std::{borrow::Cow, fmt::Debug}; + +use super::simplify::simplify_cfg; + +/// This pass optimizes something like +/// ```text +/// let x: Option<()>; +/// let y: Option<()>; +/// match (x,y) { +/// (Some(_), Some(_)) => {0}, +/// _ => {1} +/// } +/// ``` +/// into something like +/// ```text +/// let x: Option<()>; +/// let y: Option<()>; +/// let discriminant_x = // get discriminant of x +/// let discriminant_y = // get discriminant of y +/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0} +/// ``` +pub struct EarlyOtherwiseBranch; + +impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { + return; + } + trace!("running EarlyOtherwiseBranch on {:?}", source); + // we are only interested in this bb if the terminator is a switchInt + let bbs_with_switch = + body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator())); + + let opts_to_apply: Vec> = bbs_with_switch + .flat_map(|(bb_idx, bb)| { + let switch = bb.terminator(); + let helper = Helper { body, tcx }; + let infos = helper.go(bb, switch)?; + Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx }) + }) + .collect(); + + let should_cleanup = !opts_to_apply.is_empty(); + + for opt_to_apply in opts_to_apply { + trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply); + + let statements_before = + body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len(); + let end_of_block_location = Location { + block: opt_to_apply.basic_block_first_switch, + statement_index: statements_before, + }; + + let mut patch = MirPatch::new(body); + + // create temp to store second discriminant in + let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty; + let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span; + let second_discriminant_temp = patch.new_temp(discr_type, discr_span); + + patch.add_statement( + end_of_block_location, + StatementKind::StorageLive(second_discriminant_temp), + ); + + // create assignment of discriminant + let place_of_adt_to_get_discriminant_of = + opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read; + patch.add_assign( + end_of_block_location, + Place::from(second_discriminant_temp), + Rvalue::Discriminant(place_of_adt_to_get_discriminant_of), + ); + + // create temp to store NotEqual comparison between the two discriminants + let not_equal = BinOp::Ne; + let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type); + let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span); + patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp)); + + // create NotEqual comparison between the two discriminants + let first_descriminant_place = + opt_to_apply.infos[0].first_switch_info.discr_used_in_switch; + let not_equal_rvalue = Rvalue::BinaryOp( + not_equal, + Operand::Copy(Place::from(second_discriminant_temp)), + Operand::Copy(first_descriminant_place), + ); + patch.add_statement( + end_of_block_location, + StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)), + ); + + let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply + .infos + .iter() + .flat_map(|x| x.second_switch_info.targets_with_values.iter()) + .cloned() + .unzip(); + + // add otherwise case in the end + targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb); + // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal + let new_switch_data = BasicBlockData::new(Some(Terminator { + source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info, + kind: TerminatorKind::SwitchInt { + // the first and second discriminants are equal, so just pick one + discr: Operand::Copy(first_descriminant_place), + switch_ty: discr_type, + values: Cow::from(values_to_jump_to), + targets: targets_to_jump_to, + }, + })); + + let new_switch_bb = patch.new_block(new_switch_data); + + // switch on the NotEqual. If true, then jump to the `otherwise` case. + // If false, then jump to a basic block that then jumps to the correct disciminant case + let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb; + let false_case = new_switch_bb; + patch.patch_terminator( + opt_to_apply.basic_block_first_switch, + TerminatorKind::if_( + tcx, + Operand::Move(Place::from(not_equal_temp)), + true_case, + false_case, + ), + ); + + // generate StorageDead for the second_discriminant_temp not in use anymore + patch.add_statement( + end_of_block_location, + StatementKind::StorageDead(second_discriminant_temp), + ); + + // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch + for bb in [false_case, true_case].iter() { + patch.add_statement( + Location { block: *bb, statement_index: 0 }, + StatementKind::StorageDead(not_equal_temp), + ); + } + + patch.apply(body); + } + + // Since this optimization adds new basic blocks and invalidates others, + // clean up the cfg to make it nicer for other passes + if should_cleanup { + simplify_cfg(body); + } + } +} + +fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool { + match terminator.kind { + TerminatorKind::SwitchInt { .. } => true, + _ => false, + } +} + +struct Helper<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, +} + +#[derive(Debug, Clone)] +struct SwitchDiscriminantInfo<'tcx> { + /// Type of the discriminant being switched on + discr_ty: Ty<'tcx>, + /// The basic block that the otherwise branch points to + otherwise_bb: BasicBlock, + /// Target along with the value being branched from. Otherwise is not included + targets_with_values: Vec<(BasicBlock, u128)>, + discr_source_info: SourceInfo, + /// The place of the discriminant used in the switch + discr_used_in_switch: Place<'tcx>, + /// The place of the adt that has its discriminant read + place_of_adt_discr_read: Place<'tcx>, + /// The type of the adt that has its discriminant read + type_adt_matched_on: Ty<'tcx>, +} + +#[derive(Debug)] +struct OptimizationToApply<'tcx> { + infos: Vec>, + /// Basic block of the original first switch + basic_block_first_switch: BasicBlock, +} + +#[derive(Debug)] +struct OptimizationInfo<'tcx> { + /// Info about the first switch and discriminant + first_switch_info: SwitchDiscriminantInfo<'tcx>, + /// Info about the second switch and discriminant + second_switch_info: SwitchDiscriminantInfo<'tcx>, +} + +impl<'a, 'tcx> Helper<'a, 'tcx> { + pub fn go( + &self, + bb: &BasicBlockData<'tcx>, + switch: &Terminator<'tcx>, + ) -> Option>> { + // try to find the statement that defines the discriminant that is used for the switch + let discr = self.find_switch_discriminant_info(bb, switch)?; + + // go through each target, finding a discriminant read, and a switch + let results = discr.targets_with_values.iter().map(|(target, value)| { + self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone()) + }); + + // if the optimization did not apply for one of the targets, then abort + if results.clone().any(|x| x.is_none()) || results.len() == 0 { + trace!("NO: not all of the targets matched the pattern for optimization"); + return None; + } + + Some(results.flatten().collect()) + } + + fn find_discriminant_switch_pairing( + &self, + discr_info: &SwitchDiscriminantInfo<'tcx>, + target: BasicBlock, + value: u128, + ) -> Option> { + let bb = &self.body.basic_blocks()[target]; + // find switch + let terminator = bb.terminator(); + if is_switch(terminator) { + let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?; + + // the types of the two adts matched on have to be equalfor this optimization to apply + if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on { + trace!( + "NO: types do not match. LHS: {:?}, RHS: {:?}", + discr_info.type_adt_matched_on, + this_bb_discr_info.type_adt_matched_on + ); + return None; + } + + // the otherwise branch of the two switches have to point to the same bb + if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb { + trace!("NO: otherwise target is not the same"); + return None; + } + + // check that the value being matched on is the same. The + if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() { + trace!("NO: values being matched on are not the same"); + return None; + } + + // only allow optimization if the left and right of the tuple being matched are the same variants. + // so the following should not optimize + // ```rust + // let x: Option<()>; + // let y: Option<()>; + // match (x,y) { + // (Some(_), None) => {}, + // _ => {} + // } + // ``` + // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch + if !(this_bb_discr_info.targets_with_values.len() == 1 + && this_bb_discr_info.targets_with_values[0].1 == value) + { + trace!( + "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here" + ); + return None; + } + + // if we reach this point, the optimization applies, and we should be able to optimize this case + // store the info that is needed to apply the optimization + + Some(OptimizationInfo { + first_switch_info: discr_info.clone(), + second_switch_info: this_bb_discr_info, + }) + } else { + None + } + } + + fn find_switch_discriminant_info( + &self, + bb: &BasicBlockData<'tcx>, + switch: &Terminator<'tcx>, + ) -> Option> { + match &switch.kind { + TerminatorKind::SwitchInt { discr, targets, values, .. } => { + let discr_local = discr.place()?.as_local()?; + // the declaration of the discriminant read. Place of this read is being used in the switch + let discr_decl = &self.body.local_decls()[discr_local]; + let discr_ty = discr_decl.ty; + // the otherwise target lies as the last element + let otherwise_bb = targets.get(values.len())?.clone(); + let targets_with_values = targets + .iter() + .zip(values.iter()) + .map(|(t, v)| (t.clone(), v.clone())) + .collect(); + + // find the place of the adt where the discriminant is being read from + // assume this is the last statement of the block + let place_of_adt_discr_read = match bb.statements.last()?.kind { + StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => { + Some(adt_place) + } + _ => None, + }?; + + let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty; + + Some(SwitchDiscriminantInfo { + discr_used_in_switch: discr.place()?, + discr_ty, + otherwise_bb, + targets_with_values, + discr_source_info: discr_decl.source_info, + place_of_adt_discr_read, + type_adt_matched_on, + }) + } + _ => unreachable!("must only be passed terminator that is a switch"), + } + } +} diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/compiler/rustc_mir/src/transform/elaborate_drops.rs similarity index 99% rename from src/librustc_mir/transform/elaborate_drops.rs rename to compiler/rustc_mir/src/transform/elaborate_drops.rs index ad49090bfc..a8b2ee5705 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/compiler/rustc_mir/src/transform/elaborate_drops.rs @@ -44,6 +44,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { let inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body, def_id) .dead_unwinds(&dead_unwinds) + .pass_name("elaborate_drops") .iterate_to_fixpoint() .into_results_cursor(body); @@ -51,6 +52,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { .mark_inactive_variants_as_uninit() .into_engine(tcx, body, def_id) .dead_unwinds(&dead_unwinds) + .pass_name("elaborate_drops") .iterate_to_fixpoint() .into_results_cursor(body); @@ -83,6 +85,7 @@ fn find_dead_unwinds<'tcx>( let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body, def_id) + .pass_name("find_dead_unwinds") .iterate_to_fixpoint() .into_results_cursor(body); for (bb, bb_data) in body.basic_blocks().iter_enumerated() { @@ -219,7 +222,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { }) } - fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { + fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { ProjectionElem::ConstantIndex { offset, min_length, from_end } => { debug_assert!(size == min_length, "min_length should be exact for arrays"); diff --git a/src/librustc_mir/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs similarity index 99% rename from src/librustc_mir/transform/generator.rs rename to compiler/rustc_mir/src/transform/generator.rs index a22075e760..1fffcf8151 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -467,8 +467,10 @@ fn locals_live_across_suspend_points( // Calculate the MIR locals which have been previously // borrowed (even if they are still active). - let borrowed_locals_results = - MaybeBorrowedLocals::all_borrows().into_engine(tcx, body_ref, def_id).iterate_to_fixpoint(); + let borrowed_locals_results = MaybeBorrowedLocals::all_borrows() + .into_engine(tcx, body_ref, def_id) + .pass_name("generator") + .iterate_to_fixpoint(); let mut borrowed_locals_cursor = dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results); @@ -484,6 +486,7 @@ fn locals_live_across_suspend_points( // Calculate the liveness of MIR locals ignoring borrows. let mut liveness = MaybeLiveLocals .into_engine(tcx, body_ref, def_id) + .pass_name("generator") .iterate_to_fixpoint() .into_results_cursor(body_ref); @@ -726,12 +729,12 @@ fn sanitize_witness<'tcx>( saved_locals: &GeneratorSavedLocals, ) { let allowed_upvars = tcx.erase_regions(upvars); - let allowed = match witness.kind { + let allowed = match witness.kind() { ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s), _ => { tcx.sess.delay_span_bug( body.span, - &format!("unexpected generator witness type {:?}", witness.kind), + &format!("unexpected generator witness type {:?}", witness.kind()), ); return; } @@ -1252,7 +1255,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { let gen_ty = body.local_decls.raw[1].ty; // Get the interior types and substs which typeck computed - let (upvars, interior, discr_ty, movable) = match gen_ty.kind { + let (upvars, interior, discr_ty, movable) = match *gen_ty.kind() { ty::Generator(_, substs, movability) => { let substs = substs.as_generator(); ( diff --git a/src/librustc_mir/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs similarity index 92% rename from src/librustc_mir/transform/inline.rs rename to compiler/rustc_mir/src/transform/inline.rs index 315d4fa9d4..4e7cacc2f4 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -4,7 +4,7 @@ use rustc_attr as attr; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::subst::{Subst, SubstsRef}; @@ -45,7 +45,8 @@ impl<'tcx> MirPass<'tcx> for Inline { // based function. debug!("function inlining is disabled when compiling with `instrument_coverage`"); } else { - Inliner { tcx, source }.run_pass(body); + Inliner { tcx, source, codegen_fn_attrs: tcx.codegen_fn_attrs(source.def_id()) } + .run_pass(body); } } } @@ -54,6 +55,7 @@ impl<'tcx> MirPass<'tcx> for Inline { struct Inliner<'tcx> { tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, + codegen_fn_attrs: &'tcx CodegenFnAttrs, } impl Inliner<'tcx> { @@ -107,8 +109,14 @@ impl Inliner<'tcx> { // Avoid a cycle here by only using `optimized_mir` only if we have // a lower `HirId` than the callee. This ensures that the callee will // not inline us. This trick only works without incremental compilation. - // So don't do it if that is enabled. - if !self.tcx.dep_graph.is_fully_enabled() && self_hir_id < callee_hir_id { + // So don't do it if that is enabled. Also avoid inlining into generators, + // since their `optimized_mir` is used for layout computation, which can + // create a cycle, even when no attempt is made to inline the function + // in the other direction. + if !self.tcx.dep_graph.is_fully_enabled() + && self_hir_id < callee_hir_id + && caller_body.generator_kind.is_none() + { self.tcx.optimized_mir(callsite.callee) } else { continue; @@ -191,7 +199,7 @@ impl Inliner<'tcx> { // Only consider direct calls to functions let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: ref op, .. } = terminator.kind { - if let ty::FnDef(callee_def_id, substs) = op.ty(caller_body, self.tcx).kind { + if let ty::FnDef(callee_def_id, substs) = *op.ty(caller_body, self.tcx).kind() { let instance = Instance::resolve(self.tcx, param_env, callee_def_id, substs).ok().flatten()?; @@ -236,9 +244,19 @@ impl Inliner<'tcx> { return false; } - // Avoid inlining functions marked as no_sanitize if sanitizer is enabled, - // since instrumentation might be enabled and performed on the caller. - if self.tcx.sess.opts.debugging_opts.sanitizer.intersects(codegen_fn_attrs.no_sanitize) { + let self_features = &self.codegen_fn_attrs.target_features; + let callee_features = &codegen_fn_attrs.target_features; + if callee_features.iter().any(|feature| !self_features.contains(feature)) { + debug!("`callee has extra target features - not inlining"); + return false; + } + + let self_no_sanitize = + self.codegen_fn_attrs.no_sanitize & self.tcx.sess.opts.debugging_opts.sanitizer; + let callee_no_sanitize = + codegen_fn_attrs.no_sanitize & self.tcx.sess.opts.debugging_opts.sanitizer; + if self_no_sanitize != callee_no_sanitize { + debug!("`callee has incompatible no_sanitize attribute - not inlining"); return false; } @@ -336,7 +354,7 @@ impl Inliner<'tcx> { } TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { - if let ty::FnDef(def_id, _) = f.literal.ty.kind { + if let ty::FnDef(def_id, _) = *f.literal.ty.kind() { // Don't give intrinsics the extra penalty for calls let f = tcx.fn_sig(def_id); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { @@ -488,7 +506,7 @@ impl Inliner<'tcx> { let return_block = destination.1; // Copy the arguments if needed. - let args: Vec<_> = self.make_call_args(args, &callsite, caller_body); + let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, return_block); let bb_len = caller_body.basic_blocks().len(); let mut integrator = Integrator { @@ -535,6 +553,7 @@ impl Inliner<'tcx> { args: Vec>, callsite: &CallSite<'tcx>, caller_body: &mut Body<'tcx>, + return_block: BasicBlock, ) -> Vec { let tcx = self.tcx; @@ -563,12 +582,22 @@ impl Inliner<'tcx> { // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. if tcx.is_closure(callsite.callee) { let mut args = args.into_iter(); - let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); - let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); + let self_ = self.create_temp_if_necessary( + args.next().unwrap(), + callsite, + caller_body, + return_block, + ); + let tuple = self.create_temp_if_necessary( + args.next().unwrap(), + callsite, + caller_body, + return_block, + ); assert!(args.next().is_none()); let tuple = Place::from(tuple); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind { + let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind() { s } else { bug!("Closure arguments are not passed as a tuple"); @@ -584,13 +613,13 @@ impl Inliner<'tcx> { Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty())); // Spill to a local to make e.g., `tmp0`. - self.create_temp_if_necessary(tuple_field, callsite, caller_body) + self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block) }); closure_ref_arg.chain(tuple_tmp_args).collect() } else { args.into_iter() - .map(|a| self.create_temp_if_necessary(a, callsite, caller_body)) + .map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block)) .collect() } } @@ -602,6 +631,7 @@ impl Inliner<'tcx> { arg: Operand<'tcx>, callsite: &CallSite<'tcx>, caller_body: &mut Body<'tcx>, + return_block: BasicBlock, ) -> Local { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. @@ -624,11 +654,19 @@ impl Inliner<'tcx> { let arg_tmp = LocalDecl::new(ty, callsite.location.span); let arg_tmp = caller_body.local_decls.push(arg_tmp); - let stmt = Statement { + caller_body[callsite.bb].statements.push(Statement { + source_info: callsite.location, + kind: StatementKind::StorageLive(arg_tmp), + }); + caller_body[callsite.bb].statements.push(Statement { source_info: callsite.location, kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)), - }; - caller_body[callsite.bb].statements.push(stmt); + }); + caller_body[return_block].statements.insert( + 0, + Statement { source_info: callsite.location, kind: StatementKind::StorageDead(arg_tmp) }, + ); + arg_tmp } } diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs new file mode 100644 index 0000000000..ada24899e1 --- /dev/null +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -0,0 +1,285 @@ +//! Performs various peephole optimizations. + +use crate::transform::{MirPass, MirSource}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::Mutability; +use rustc_index::vec::Idx; +use rustc_middle::mir::{ + visit::PlaceContext, + visit::{MutVisitor, Visitor}, + Statement, +}; +use rustc_middle::mir::{ + BinOp, Body, BorrowKind, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, + Rvalue, +}; +use rustc_middle::ty::{self, TyCtxt}; +use std::mem; + +pub struct InstCombine; + +impl<'tcx> MirPass<'tcx> for InstCombine { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + // First, find optimization opportunities. This is done in a pre-pass to keep the MIR + // read-only so that we can do global analyses on the MIR in the process (e.g. + // `Place::ty()`). + let optimizations = { + let mut optimization_finder = OptimizationFinder::new(body, tcx); + optimization_finder.visit_body(body); + optimization_finder.optimizations + }; + + // Then carry out those optimizations. + MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body); + } +} + +pub struct InstCombineVisitor<'tcx> { + optimizations: OptimizationList<'tcx>, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + if self.optimizations.and_stars.remove(&location) { + debug!("replacing `&*`: {:?}", rvalue); + let new_place = match rvalue { + Rvalue::Ref(_, _, place) => { + if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() { + place.projection = self.tcx().intern_place_elems(&[proj_r]); + + Place { + // Replace with dummy + local: mem::replace(&mut place.local, Local::new(0)), + projection: self.tcx().intern_place_elems(proj_l), + } + } else { + unreachable!(); + } + } + _ => bug!("Detected `&*` but didn't find `&*`!"), + }; + *rvalue = Rvalue::Use(Operand::Copy(new_place)) + } + + if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { + debug!("replacing `Len([_; N])`: {:?}", rvalue); + *rvalue = Rvalue::Use(Operand::Constant(box constant)); + } + + if let Some(operand) = self.optimizations.unneeded_equality_comparison.remove(&location) { + debug!("replacing {:?} with {:?}", rvalue, operand); + *rvalue = Rvalue::Use(operand); + } + + if let Some(place) = self.optimizations.unneeded_deref.remove(&location) { + debug!("unneeded_deref: replacing {:?} with {:?}", rvalue, place); + *rvalue = Rvalue::Use(Operand::Copy(place)); + } + + self.super_rvalue(rvalue, location) + } +} + +struct MutatingUseVisitor { + has_mutating_use: bool, + local_to_look_for: Local, +} + +impl MutatingUseVisitor { + fn has_mutating_use_in_stmt(local: Local, stmt: &Statement<'tcx>, location: Location) -> bool { + let mut _self = Self { has_mutating_use: false, local_to_look_for: local }; + _self.visit_statement(stmt, location); + _self.has_mutating_use + } +} + +impl<'tcx> Visitor<'tcx> for MutatingUseVisitor { + fn visit_local(&mut self, local: &Local, context: PlaceContext, _: Location) { + if *local == self.local_to_look_for { + self.has_mutating_use |= context.is_mutating_use(); + } + } +} + +/// Finds optimization opportunities on the MIR. +struct OptimizationFinder<'b, 'tcx> { + body: &'b Body<'tcx>, + tcx: TyCtxt<'tcx>, + optimizations: OptimizationList<'tcx>, +} + +impl OptimizationFinder<'b, 'tcx> { + fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx> { + OptimizationFinder { body, tcx, optimizations: OptimizationList::default() } + } + + fn find_deref_of_address(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> { + // FIXME(#78192): This optimization can result in unsoundness. + if !self.tcx.sess.opts.debugging_opts.unsound_mir_opts { + return None; + } + + // Look for the sequence + // + // _2 = &_1; + // ... + // _5 = (*_2); + // + // which we can replace the last statement with `_5 = _1;` to avoid the load of `_2`. + if let Rvalue::Use(op) = rvalue { + let local_being_derefed = match op.place()?.as_ref() { + PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), + _ => None, + }?; + + let stmt_index = location.statement_index; + // Look behind for statement that assigns the local from a address of operator. + // 6 is chosen as a heuristic determined by seeing the number of times + // the optimization kicked in compiling rust std. + let lower_index = stmt_index.saturating_sub(6); + let statements_to_look_in = self.body.basic_blocks()[location.block].statements + [lower_index..stmt_index] + .iter() + .rev(); + for stmt in statements_to_look_in { + match &stmt.kind { + // Exhaustive match on statements to detect conditions that warrant we bail out of the optimization. + rustc_middle::mir::StatementKind::Assign(box (l, r)) + if l.local == local_being_derefed => + { + match r { + // Looking for immutable reference e.g _local_being_deref = &_1; + Rvalue::Ref( + _, + // Only apply the optimization if it is an immutable borrow. + BorrowKind::Shared, + place_taken_address_of, + ) => { + self.optimizations + .unneeded_deref + .insert(location, *place_taken_address_of); + return Some(()); + } + + // We found an assignment of `local_being_deref` that is not an immutable ref, e.g the following sequence + // _2 = &_1; + // _3 = &5 + // _2 = _3; <-- this means it is no longer valid to replace the last statement with `_5 = _1;` + // _5 = (*_2); + _ => return None, + } + } + + // Inline asm can do anything, so bail out of the optimization. + rustc_middle::mir::StatementKind::LlvmInlineAsm(_) => return None, + + // Check that `local_being_deref` is not being used in a mutating way which can cause misoptimization. + rustc_middle::mir::StatementKind::Assign(box (_, _)) + | rustc_middle::mir::StatementKind::Coverage(_) + | rustc_middle::mir::StatementKind::Nop + | rustc_middle::mir::StatementKind::FakeRead(_, _) + | rustc_middle::mir::StatementKind::StorageLive(_) + | rustc_middle::mir::StatementKind::StorageDead(_) + | rustc_middle::mir::StatementKind::Retag(_, _) + | rustc_middle::mir::StatementKind::AscribeUserType(_, _) + | rustc_middle::mir::StatementKind::SetDiscriminant { .. } => { + if MutatingUseVisitor::has_mutating_use_in_stmt( + local_being_derefed, + stmt, + location, + ) { + return None; + } + } + } + } + } + Some(()) + } + + fn find_unneeded_equality_comparison(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + // find Ne(_place, false) or Ne(false, _place) + // or Eq(_place, true) or Eq(true, _place) + if let Rvalue::BinaryOp(op, l, r) = rvalue { + let const_to_find = if *op == BinOp::Ne { + false + } else if *op == BinOp::Eq { + true + } else { + return; + }; + // (const, _place) + if let Some(o) = self.find_operand_in_equality_comparison_pattern(l, r, const_to_find) { + self.optimizations.unneeded_equality_comparison.insert(location, o.clone()); + } + // (_place, const) + else if let Some(o) = + self.find_operand_in_equality_comparison_pattern(r, l, const_to_find) + { + self.optimizations.unneeded_equality_comparison.insert(location, o.clone()); + } + } + } + + fn find_operand_in_equality_comparison_pattern( + &self, + l: &Operand<'tcx>, + r: &'a Operand<'tcx>, + const_to_find: bool, + ) -> Option<&'a Operand<'tcx>> { + let const_ = l.constant()?; + if const_.literal.ty == self.tcx.types.bool + && const_.literal.val.try_to_bool() == Some(const_to_find) + { + if r.place().is_some() { + return Some(r); + } + } + + None + } +} + +impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::Ref(_, _, place) = rvalue { + if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } = + place.as_ref() + { + // The dereferenced place must have type `&_`. + let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty; + if let ty::Ref(_, _, Mutability::Not) = ty.kind() { + self.optimizations.and_stars.insert(location); + } + } + } + + if let Rvalue::Len(ref place) = *rvalue { + let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; + if let ty::Array(_, len) = place_ty.kind() { + let span = self.body.source_info(location).span; + let constant = Constant { span, literal: len, user_ty: None }; + self.optimizations.arrays_lengths.insert(location, constant); + } + } + + let _ = self.find_deref_of_address(rvalue, location); + + self.find_unneeded_equality_comparison(rvalue, location); + + self.super_rvalue(rvalue, location) + } +} + +#[derive(Default)] +struct OptimizationList<'tcx> { + and_stars: FxHashSet, + arrays_lengths: FxHashMap>, + unneeded_equality_comparison: FxHashMap>, + unneeded_deref: FxHashMap>, +} diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs new file mode 100644 index 0000000000..a5b30a25a9 --- /dev/null +++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs @@ -0,0 +1,491 @@ +use crate::transform::{MirPass, MirSource}; +use crate::util::pretty; +use crate::util::spanview::{ + source_range_no_file, statement_kind_name, terminator_kind_name, write_spanview_document, + SpanViewable, TOOLTIP_INDENT, +}; + +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_index::bit_set::BitSet; +use rustc_middle::hir; +use rustc_middle::ich::StableHashingContext; +use rustc_middle::mir; +use rustc_middle::mir::coverage::*; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{ + BasicBlock, BasicBlockData, Coverage, CoverageInfo, Location, Statement, StatementKind, + TerminatorKind, +}; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::TyCtxt; +use rustc_span::def_id::DefId; +use rustc_span::{FileName, Pos, RealFileName, Span, Symbol}; + +/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected +/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen +/// to construct the coverage map. +pub struct InstrumentCoverage; + +/// The `query` provider for `CoverageInfo`, requested by `codegen_coverage()` (to inject each +/// counter) and `FunctionCoverage::new()` (to extract the coverage map metadata from the MIR). +pub(crate) fn provide(providers: &mut Providers) { + providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id); +} + +struct CoverageVisitor { + info: CoverageInfo, +} + +impl Visitor<'_> for CoverageVisitor { + fn visit_coverage(&mut self, coverage: &Coverage, _location: Location) { + match coverage.kind { + CoverageKind::Counter { id, .. } => { + let counter_id = u32::from(id); + self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1); + } + CoverageKind::Expression { id, .. } => { + let expression_index = u32::MAX - u32::from(id); + self.info.num_expressions = + std::cmp::max(self.info.num_expressions, expression_index + 1); + } + _ => {} + } + } +} + +fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo { + let mir_body = tcx.optimized_mir(def_id); + + // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected + // counters, with each counter having a counter ID from `0..num_counters-1`. MIR optimization + // may split and duplicate some BasicBlock sequences. Simply counting the calls may not + // work; but computing the num_counters by adding `1` to the highest counter_id (for a given + // instrumented function) is valid. + // + // `num_expressions` is the number of counter expressions added to the MIR body. Both + // `num_counters` and `num_expressions` are used to initialize new vectors, during backend + // code generate, to lookup counters and expressions by simple u32 indexes. + let mut coverage_visitor = + CoverageVisitor { info: CoverageInfo { num_counters: 0, num_expressions: 0 } }; + + coverage_visitor.visit_body(mir_body); + coverage_visitor.info +} + +impl<'tcx> MirPass<'tcx> for InstrumentCoverage { + fn run_pass( + &self, + tcx: TyCtxt<'tcx>, + mir_source: MirSource<'tcx>, + mir_body: &mut mir::Body<'tcx>, + ) { + // If the InstrumentCoverage pass is called on promoted MIRs, skip them. + // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601 + if mir_source.promoted.is_none() { + Instrumentor::new(&self.name(), tcx, mir_source, mir_body).inject_counters(); + } + } +} + +#[derive(Clone)] +struct CoverageRegion { + pub span: Span, + pub blocks: Vec, +} + +struct Instrumentor<'a, 'tcx> { + pass_name: &'a str, + tcx: TyCtxt<'tcx>, + mir_source: MirSource<'tcx>, + mir_body: &'a mut mir::Body<'tcx>, + hir_body: &'tcx rustc_hir::Body<'tcx>, + function_source_hash: Option, + num_counters: u32, + num_expressions: u32, +} + +impl<'a, 'tcx> Instrumentor<'a, 'tcx> { + fn new( + pass_name: &'a str, + tcx: TyCtxt<'tcx>, + mir_source: MirSource<'tcx>, + mir_body: &'a mut mir::Body<'tcx>, + ) -> Self { + let hir_body = hir_body(tcx, mir_source.def_id()); + Self { + pass_name, + tcx, + mir_source, + mir_body, + hir_body, + function_source_hash: None, + num_counters: 0, + num_expressions: 0, + } + } + + /// Counter IDs start from zero and go up. + fn next_counter(&mut self) -> CounterValueReference { + assert!(self.num_counters < u32::MAX - self.num_expressions); + let next = self.num_counters; + self.num_counters += 1; + CounterValueReference::from(next) + } + + /// Expression IDs start from u32::MAX and go down because a CounterExpression can reference + /// (add or subtract counts) of both Counter regions and CounterExpression regions. The counter + /// expression operand IDs must be unique across both types. + fn next_expression(&mut self) -> InjectedExpressionIndex { + assert!(self.num_counters < u32::MAX - self.num_expressions); + let next = u32::MAX - self.num_expressions; + self.num_expressions += 1; + InjectedExpressionIndex::from(next) + } + + fn function_source_hash(&mut self) -> u64 { + match self.function_source_hash { + Some(hash) => hash, + None => { + let hash = hash_mir_source(self.tcx, self.hir_body); + self.function_source_hash.replace(hash); + hash + } + } + } + + fn inject_counters(&mut self) { + let tcx = self.tcx; + let def_id = self.mir_source.def_id(); + let mir_body = &self.mir_body; + let body_span = self.hir_body.value.span; + debug!( + "instrumenting {:?}, span: {}", + def_id, + tcx.sess.source_map().span_to_string(body_span) + ); + + if !tcx.sess.opts.debugging_opts.experimental_coverage { + // Coverage at the function level should be accurate. This is the default implementation + // if `-Z experimental-coverage` is *NOT* enabled. + let block = rustc_middle::mir::START_BLOCK; + let counter = self.make_counter(); + self.inject_statement(counter, body_span, block); + return; + } + // FIXME(richkadel): else if `-Z experimental-coverage` *IS* enabled: Efforts are still in + // progress to identify the correct code region spans and associated counters to generate + // accurate Rust coverage reports. + + let block_span = |data: &BasicBlockData<'tcx>| { + // The default span will be the `Terminator` span; but until we have a smarter solution, + // the coverage region also incorporates at least the statements in this BasicBlock as + // well. Extend the span to encompass all, if possible. + // FIXME(richkadel): Assuming the terminator's span is already known to be contained in `body_span`. + let mut span = data.terminator().source_info.span; + // FIXME(richkadel): It's looking unlikely that we should compute a span from MIR + // spans, but if we do keep something like this logic, we will need a smarter way + // to combine `Statement`s and/or `Terminator`s with `Span`s from different + // files. + for statement_span in data.statements.iter().map(|statement| statement.source_info.span) + { + // Only combine Spans from the function's body_span. + if body_span.contains(statement_span) { + span = span.to(statement_span); + } + } + span + }; + + // Traverse the CFG but ignore anything following an `unwind` + let cfg_without_unwind = ShortCircuitPreorder::new(mir_body, |term_kind| { + let mut successors = term_kind.successors(); + match &term_kind { + // SwitchInt successors are never unwind, and all of them should be traversed + TerminatorKind::SwitchInt { .. } => successors, + // For all other kinds, return only the first successor, if any, and ignore unwinds + _ => successors.next().into_iter().chain(&[]), + } + }); + + let mut coverage_regions = Vec::with_capacity(cfg_without_unwind.size_hint().0); + for (bb, data) in cfg_without_unwind { + if !body_span.contains(data.terminator().source_info.span) { + continue; + } + + // FIXME(richkadel): Regions will soon contain multiple blocks. + let mut blocks = Vec::new(); + blocks.push(bb); + let span = block_span(data); + coverage_regions.push(CoverageRegion { span, blocks }); + } + + let span_viewables = if pretty::dump_enabled(tcx, self.pass_name, def_id) { + Some(self.span_viewables(&coverage_regions)) + } else { + None + }; + + // Inject counters for the selected spans + for CoverageRegion { span, blocks } in coverage_regions { + debug!( + "Injecting counter at: {:?}:\n{}\n==========", + span, + tcx.sess.source_map().span_to_snippet(span).expect("Error getting source for span"), + ); + let counter = self.make_counter(); + self.inject_statement(counter, span, blocks[0]); + } + + if let Some(span_viewables) = span_viewables { + let mut file = + pretty::create_dump_file(tcx, "html", None, self.pass_name, &0, self.mir_source) + .expect("Unexpected error creating MIR spanview HTML file"); + write_spanview_document(tcx, def_id, span_viewables, &mut file) + .expect("Unexpected IO error dumping coverage spans as HTML"); + } + + // FIXME(richkadel): Some regions will be counted by "counter expression". Counter + // expressions are supported, but are not yet generated. When they are, remove this `fake_use` + // block. + let fake_use = false; + if fake_use { + let add = false; + let fake_counter = CoverageKind::Counter { + function_source_hash: self.function_source_hash(), + id: CounterValueReference::from_u32(1), + }; + let fake_expression = CoverageKind::Expression { + id: InjectedExpressionIndex::from(u32::MAX - 1), + lhs: ExpressionOperandId::from_u32(1), + op: Op::Add, + rhs: ExpressionOperandId::from_u32(2), + }; + + let lhs = fake_counter.as_operand_id(); + let op = if add { Op::Add } else { Op::Subtract }; + let rhs = fake_expression.as_operand_id(); + + let block = rustc_middle::mir::START_BLOCK; + + let expression = self.make_expression(lhs, op, rhs); + self.inject_statement(expression, body_span, block); + } + } + + fn make_counter(&mut self) -> CoverageKind { + CoverageKind::Counter { + function_source_hash: self.function_source_hash(), + id: self.next_counter(), + } + } + + fn make_expression( + &mut self, + lhs: ExpressionOperandId, + op: Op, + rhs: ExpressionOperandId, + ) -> CoverageKind { + CoverageKind::Expression { id: self.next_expression(), lhs, op, rhs } + } + + fn inject_statement(&mut self, coverage_kind: CoverageKind, span: Span, block: BasicBlock) { + let code_region = make_code_region(self.tcx, &span); + debug!(" injecting statement {:?} covering {:?}", coverage_kind, code_region); + + let data = &mut self.mir_body[block]; + let source_info = data.terminator().source_info; + let statement = Statement { + source_info, + kind: StatementKind::Coverage(box Coverage { kind: coverage_kind, code_region }), + }; + data.statements.push(statement); + } + + /// Converts the computed `CoverageRegion`s into `SpanViewable`s. + fn span_viewables(&self, coverage_regions: &Vec) -> Vec { + let mut span_viewables = Vec::new(); + for coverage_region in coverage_regions { + span_viewables.push(SpanViewable { + span: coverage_region.span, + id: format!("{}", coverage_region.blocks[0].index()), + tooltip: self.make_tooltip_text(coverage_region), + }); + } + span_viewables + } + + /// A custom tooltip renderer used in a spanview HTML+CSS document used for coverage analysis. + fn make_tooltip_text(&self, coverage_region: &CoverageRegion) -> String { + const INCLUDE_COVERAGE_STATEMENTS: bool = false; + let tcx = self.tcx; + let source_map = tcx.sess.source_map(); + let mut text = Vec::new(); + for (i, &bb) in coverage_region.blocks.iter().enumerate() { + if i > 0 { + text.push("\n".to_owned()); + } + text.push(format!("{:?}: {}:", bb, &source_map.span_to_string(coverage_region.span))); + let data = &self.mir_body.basic_blocks()[bb]; + for statement in &data.statements { + let statement_string = match statement.kind { + StatementKind::Coverage(box ref coverage) => match coverage.kind { + CoverageKind::Counter { id, .. } => { + if !INCLUDE_COVERAGE_STATEMENTS { + continue; + } + format!("increment counter #{}", id.index()) + } + CoverageKind::Expression { id, lhs, op, rhs } => { + if !INCLUDE_COVERAGE_STATEMENTS { + continue; + } + format!( + "expression #{} = {} {} {}", + id.index(), + lhs.index(), + if op == Op::Add { "+" } else { "-" }, + rhs.index() + ) + } + CoverageKind::Unreachable => { + if !INCLUDE_COVERAGE_STATEMENTS { + continue; + } + String::from("unreachable") + } + }, + _ => format!("{:?}", statement), + }; + let source_range = source_range_no_file(tcx, &statement.source_info.span); + text.push(format!( + "\n{}{}: {}: {}", + TOOLTIP_INDENT, + source_range, + statement_kind_name(statement), + statement_string + )); + } + let term = data.terminator(); + let source_range = source_range_no_file(tcx, &term.source_info.span); + text.push(format!( + "\n{}{}: {}: {:?}", + TOOLTIP_INDENT, + source_range, + terminator_kind_name(term), + term.kind + )); + } + text.join("") + } +} + +/// Convert the Span into its file name, start line and column, and end line and column +fn make_code_region<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> CodeRegion { + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(span.lo()); + let end = if span.hi() == span.lo() { + start.clone() + } else { + let end = source_map.lookup_char_pos(span.hi()); + debug_assert_eq!( + start.file.name, + end.file.name, + "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!", + span.lo(), + start, + span.hi(), + end + ); + end + }; + match &start.file.name { + FileName::Real(RealFileName::Named(path)) => CodeRegion { + file_name: Symbol::intern(&path.to_string_lossy()), + start_line: start.line as u32, + start_col: start.col.to_u32() + 1, + end_line: end.line as u32, + end_col: end.col.to_u32() + 1, + }, + _ => bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name), + } +} + +fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { + 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"); + tcx.hir().body(fn_body_id) +} + +fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { + let mut hcx = tcx.create_no_span_stable_hashing_context(); + hash(&mut hcx, &hir_body.value).to_smaller_hash() +} + +fn hash( + hcx: &mut StableHashingContext<'tcx>, + node: &impl HashStable>, +) -> Fingerprint { + let mut stable_hasher = StableHasher::new(); + node.hash_stable(hcx, &mut stable_hasher); + stable_hasher.finish() +} + +pub struct ShortCircuitPreorder< + 'a, + 'tcx, + F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>, +> { + body: &'a mir::Body<'tcx>, + visited: BitSet, + worklist: Vec, + filtered_successors: F, +} + +impl<'a, 'tcx, F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>> + ShortCircuitPreorder<'a, 'tcx, F> +{ + pub fn new( + body: &'a mir::Body<'tcx>, + filtered_successors: F, + ) -> ShortCircuitPreorder<'a, 'tcx, F> { + let worklist = vec![mir::START_BLOCK]; + + ShortCircuitPreorder { + body, + visited: BitSet::new_empty(body.basic_blocks().len()), + worklist, + filtered_successors, + } + } +} + +impl<'a: 'tcx, 'tcx, F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>> Iterator + for ShortCircuitPreorder<'a, 'tcx, F> +{ + type Item = (BasicBlock, &'a BasicBlockData<'tcx>); + + fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { + while let Some(idx) = self.worklist.pop() { + if !self.visited.insert(idx) { + continue; + } + + let data = &self.body[idx]; + + if let Some(ref term) = data.terminator { + self.worklist.extend((self.filtered_successors)(&term.kind)); + } + + return Some((idx, data)); + } + + None + } + + fn size_hint(&self) -> (usize, Option) { + let size = self.body.basic_blocks().len() - self.visited.count(); + (size, Some(size)) + } +} diff --git a/src/librustc_mir/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs similarity index 95% rename from src/librustc_mir/transform/match_branches.rs rename to compiler/rustc_mir/src/transform/match_branches.rs index c1d574d6ef..70ae5474a4 100644 --- a/src/librustc_mir/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -38,6 +38,13 @@ pub struct MatchBranchSimplification; impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + // FIXME: This optimization can result in unsoundness, because it introduces + // additional uses of a place holding the discriminant value without ensuring that + // it is valid to do so. + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + return; + } + let param_env = tcx.param_env(src.def_id()); let bbs = body.basic_blocks_mut(); 'outer: for bb_idx in bbs.indices() { diff --git a/src/librustc_mir/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs similarity index 95% rename from src/librustc_mir/transform/mod.rs rename to compiler/rustc_mir/src/transform/mod.rs index 0db5bd662c..67193814a4 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -16,6 +16,7 @@ use std::borrow::Cow; pub mod add_call_guards; pub mod add_moves_for_packed_drops; pub mod add_retag; +pub mod check_const_item_mutation; pub mod check_consts; pub mod check_packed_ref; pub mod check_unsafety; @@ -23,22 +24,26 @@ pub mod cleanup_post_borrowck; pub mod const_prop; pub mod copy_prop; pub mod deaggregator; +pub mod dest_prop; pub mod dump_mir; +pub mod early_otherwise_branch; pub mod elaborate_drops; pub mod generator; pub mod inline; pub mod instcombine; pub mod instrument_coverage; pub mod match_branches; +pub mod multiple_return_terminators; pub mod no_landing_pads; pub mod nrvo; pub mod promote_consts; -pub mod qualify_min_const_fn; pub mod remove_noop_landing_pads; +pub mod remove_unneeded_drops; pub mod required_consts; pub mod rustc_peek; pub mod simplify; pub mod simplify_branches; +pub mod simplify_comparison_integral; pub mod simplify_try; pub mod uninhabited_enum_branching; pub mod unreachable_prop; @@ -306,6 +311,7 @@ fn mir_const<'tcx>( &[&[ // MIR-level lints. &check_packed_ref::CheckPackedRef, + &check_const_item_mutation::CheckConstItemMutation, // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, @@ -326,7 +332,11 @@ fn mir_promoted( // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. let _ = tcx.mir_const_qualif_opt_const_arg(def); - + let _ = if let Some(param_did) = def.const_param_did { + tcx.mir_abstract_const_of_const_arg((def.did, param_did)) + } else { + tcx.mir_abstract_const(def.did.to_def_id()) + }; let mut body = tcx.mir_const(def).steal(); let mut required_consts = Vec::new(); @@ -452,19 +462,25 @@ fn run_optimization_passes<'tcx>( // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ - &instcombine::InstCombine, + &remove_unneeded_drops::RemoveUnneededDrops, &match_branches::MatchBranchSimplification, + // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) + &multiple_return_terminators::MultipleReturnTerminators, + &instcombine::InstCombine, &const_prop::ConstProp, &simplify_branches::SimplifyBranches::new("after-const-prop"), + &early_otherwise_branch::EarlyOtherwiseBranch, + &simplify_comparison_integral::SimplifyComparisonIntegral, &simplify_try::SimplifyArmIdentity, &simplify_try::SimplifyBranchSame, + &dest_prop::DestinationPropagation, ©_prop::CopyPropagation, &simplify_branches::SimplifyBranches::new("after-copy-prop"), &remove_noop_landing_pads::RemoveNoopLandingPads, - &simplify::SimplifyCfg::new("after-remove-noop-landing-pads"), &simplify::SimplifyCfg::new("final"), &nrvo::RenameReturnPlace, &simplify::SimplifyLocals, + &multiple_return_terminators::MultipleReturnTerminators, ]; // Optimizations to run even if mir optimizations have been disabled. diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs new file mode 100644 index 0000000000..3c9c8454f7 --- /dev/null +++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs @@ -0,0 +1,38 @@ +//! This pass removes jumps to basic blocks containing only a return, and replaces them with a +//! return instead. + +use crate::transform::{simplify, MirPass, MirSource}; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct MultipleReturnTerminators; + +impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.opts.debugging_opts.mir_opt_level < 3 { + return; + } + + // find basic blocks with no statement and a return terminator + let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len()); + let bbs = body.basic_blocks_mut(); + for idx in bbs.indices() { + if bbs[idx].statements.is_empty() + && bbs[idx].terminator().kind == TerminatorKind::Return + { + bbs_simple_returns.insert(idx); + } + } + + for bb in bbs { + if let TerminatorKind::Goto { target } = bb.terminator().kind { + if bbs_simple_returns.contains(target) { + bb.terminator_mut().kind = TerminatorKind::Return; + } + } + } + + simplify::remove_dead_blocks(body) + } +} diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/compiler/rustc_mir/src/transform/no_landing_pads.rs similarity index 100% rename from src/librustc_mir/transform/no_landing_pads.rs rename to compiler/rustc_mir/src/transform/no_landing_pads.rs diff --git a/src/librustc_mir/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs similarity index 93% rename from src/librustc_mir/transform/nrvo.rs rename to compiler/rustc_mir/src/transform/nrvo.rs index 1f3d7bb7cc..1ffb5a87c4 100644 --- a/src/librustc_mir/transform/nrvo.rs +++ b/compiler/rustc_mir/src/transform/nrvo.rs @@ -1,6 +1,6 @@ use rustc_hir::Mutability; use rustc_index::bit_set::HybridBitSet; -use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, BasicBlock, Local, Location}; use rustc_middle::ty::TyCtxt; @@ -36,6 +36,12 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { return; } + if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { + // The `DestinationPropagation` pass runs at level 2, so this pass is redundant (and + // fails some asserts). + return; + } + let returned_local = match local_eligible_for_nrvo(body) { Some(l) => l, None => { @@ -196,9 +202,10 @@ impl MutVisitor<'tcx> for RenameToReturnPlace<'tcx> { self.super_terminator(terminator, loc); } - fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { - assert_ne!(*l, mir::RETURN_PLACE); - if *l == self.to_rename { + fn visit_local(&mut self, l: &mut Local, ctxt: PlaceContext, _: Location) { + if *l == mir::RETURN_PLACE { + assert_eq!(ctxt, PlaceContext::NonUse(NonUseContext::VarDebugInfo)); + } else if *l == self.to_rename { *l = mir::RETURN_PLACE; } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs similarity index 93% rename from src/librustc_mir/transform/promote_consts.rs rename to compiler/rustc_mir/src/transform/promote_consts.rs index b2dda1caa5..89f7531b3a 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -92,7 +92,7 @@ pub enum TempState { impl TempState { pub fn is_promotable(&self) -> bool { debug!("is_promotable: self={:?}", self); - if let TempState::Defined { .. } = *self { true } else { false } + matches!(self, TempState::Defined { .. } ) } } @@ -137,7 +137,7 @@ fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { LitKind::Int(a, _) => { ret.push(a as usize); } - _ => return None, + _ => bug!("invalid arg index"), } } Some(ret) @@ -220,7 +220,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { match terminator.kind { TerminatorKind::Call { ref func, .. } => { - if let ty::FnDef(def_id, _) = func.ty(self.ccx.body, self.ccx.tcx).kind { + if let ty::FnDef(def_id, _) = *func.ty(self.ccx.body, self.ccx.tcx).kind() { let fn_sig = self.ccx.tcx.fn_sig(def_id); if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() { let name = self.ccx.tcx.item_name(def_id); @@ -242,11 +242,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } TerminatorKind::InlineAsm { ref operands, .. } => { for (index, op) in operands.iter().enumerate() { - match op { - InlineAsmOperand::Const { .. } => { - self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) - } - _ => {} + if let InlineAsmOperand::Const { .. } = op { + self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) } } } @@ -297,6 +294,17 @@ impl std::ops::Deref for Validator<'a, 'tcx> { struct Unpromotable; impl<'tcx> Validator<'_, 'tcx> { + /// Determines if this code could be executed at runtime and thus is subject to codegen. + /// That means even unused constants need to be evaluated. + /// + /// `const_kind` should not be used in this file other than through this method! + fn maybe_runtime(&self) -> bool { + match self.const_kind { + None | Some(hir::ConstContext::ConstFn) => true, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => false, + } + } + fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> { match candidate { Candidate::Ref(loc) => { @@ -363,20 +371,10 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] - // is allowed right now, and only in functions. - if self.const_kind - == Some(hir::ConstContext::Static(hir::Mutability::Mut)) - { - // Inside a `static mut`, &mut [...] is also allowed. - match ty.kind { - ty::Array(..) | ty::Slice(_) => {} - _ => return Err(Unpromotable), - } - } else if let ty::Array(_, len) = ty.kind { - // FIXME(eddyb) the `self.is_non_const_fn` condition - // seems unnecessary, given that this is merely a ZST. + // is allowed right now. + if let ty::Array(_, len) = ty.kind() { match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) if self.const_kind.is_none() => {} + Some(0) => {} _ => return Err(Unpromotable), } } else { @@ -503,9 +501,10 @@ impl<'tcx> Validator<'_, 'tcx> { match place { PlaceRef { local, projection: [] } => self.validate_local(local), PlaceRef { local, projection: [proj_base @ .., elem] } => { + // Validate topmost projection, then recurse. match *elem { ProjectionElem::Deref => { - let mut not_promotable = true; + let mut promotable = false; // This is a special treatment for cases like *&STATIC where STATIC is a // global static variable. // This pattern is generated only when global static variables are directly @@ -520,6 +519,9 @@ impl<'tcx> Validator<'_, 'tcx> { }) = def_stmt { if let Some(did) = c.check_static_ptr(self.tcx) { + // Evaluating a promoted may not read statics except if it got + // promoted from a static (this is a CTFE check). So we + // can only promote static accesses inside statics. if let Some(hir::ConstContext::Static(..)) = self.const_kind { // The `is_empty` predicate is introduced to exclude the case // where the projection operations are [ .field, * ]. @@ -532,13 +534,13 @@ impl<'tcx> Validator<'_, 'tcx> { if proj_base.is_empty() && !self.tcx.is_thread_local_static(did) { - not_promotable = false; + promotable = true; } } } } } - if not_promotable { + if !promotable { return Err(Unpromotable); } } @@ -553,7 +555,7 @@ impl<'tcx> Validator<'_, 'tcx> { } ProjectionElem::Field(..) => { - if self.const_kind.is_none() { + if self.maybe_runtime() { let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { @@ -581,6 +583,10 @@ impl<'tcx> Validator<'_, 'tcx> { if let Some(def_id) = c.check_static_ptr(self.tcx) { // Only allow statics (not consts) to refer to other statics. // FIXME(eddyb) does this matter at all for promotion? + // FIXME(RalfJung) it makes little sense to not promote this in `fn`/`const fn`, + // and in `const` this cannot occur anyway. The only concern is that we might + // promote even `let x = &STATIC` which would be useless, but this applies to + // promotion inside statics as well. let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_))); if !is_static { return Err(Unpromotable); @@ -599,21 +605,18 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match *rvalue { - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.const_kind.is_none() => { + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - match (cast_in, cast_out) { - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - // in normal functions, mark such casts as not promotable - return Err(Unpromotable); - } - _ => {} + if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { + // ptr-to-int casts are not possible in consts and thus not promotable + return Err(Unpromotable); } } - Rvalue::BinaryOp(op, ref lhs, _) if self.const_kind.is_none() => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { + Rvalue::BinaryOp(op, ref lhs, _) => { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { assert!( op == BinOp::Eq || op == BinOp::Ne @@ -624,13 +627,14 @@ impl<'tcx> Validator<'_, 'tcx> { || op == BinOp::Offset ); - // raw pointer operations are not allowed inside promoteds + // raw pointer operations are not allowed inside consts and thus not promotable return Err(Unpromotable); } } Rvalue::NullaryOp(NullOp::Box, _) => return Err(Unpromotable), + // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous. _ => {} } @@ -652,11 +656,11 @@ impl<'tcx> Validator<'_, 'tcx> { } Rvalue::AddressOf(_, place) => { - // Raw reborrows can come from reference to pointer coercions, - // so are allowed. + // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is + // no problem, only using it is. if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() { let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; - if let ty::Ref(..) = base_ty.kind { + if let ty::Ref(..) = base_ty.kind() { return self.validate_place(PlaceRef { local: place.local, projection: proj_base, @@ -672,18 +676,10 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] - // is allowed right now, and only in functions. - if self.const_kind == Some(hir::ConstContext::Static(hir::Mutability::Mut)) { - // Inside a `static mut`, &mut [...] is also allowed. - match ty.kind { - ty::Array(..) | ty::Slice(_) => {} - _ => return Err(Unpromotable), - } - } else if let ty::Array(_, len) = ty.kind { - // FIXME(eddyb): We only return `Unpromotable` for `&mut []` inside a - // const context which seems unnecessary given that this is merely a ZST. + // is allowed right now. + if let ty::Array(_, len) = ty.kind() { match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) if self.const_kind.is_none() => {} + Some(0) => {} _ => return Err(Unpromotable), } } else { @@ -695,7 +691,7 @@ impl<'tcx> Validator<'_, 'tcx> { let mut place = place.as_ref(); if let [proj_base @ .., ProjectionElem::Deref] = &place.projection { let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; - if let ty::Ref(..) = base_ty.kind { + if let ty::Ref(..) = base_ty.kind() { place = PlaceRef { local: place.local, projection: proj_base }; } } @@ -748,8 +744,8 @@ impl<'tcx> Validator<'_, 'tcx> { ) -> Result<(), Unpromotable> { let fn_ty = callee.ty(self.body, self.tcx); - if !self.explicit && self.const_kind.is_none() { - if let ty::FnDef(def_id, _) = fn_ty.kind { + if !self.explicit && self.maybe_runtime() { + if let ty::FnDef(def_id, _) = *fn_ty.kind() { // Never promote runtime `const fn` calls of // functions without `#[rustc_promotable]`. if !self.tcx.is_promotable_const_fn(def_id) { @@ -758,7 +754,7 @@ impl<'tcx> Validator<'_, 'tcx> { } } - let is_const_fn = match fn_ty.kind { + let is_const_fn = match *fn_ty.kind() { ty::FnDef(def_id, _) => { is_const_fn(self.tcx, def_id) || is_unstable_const_fn(self.tcx, def_id).is_some() diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs similarity index 94% rename from src/librustc_mir/transform/remove_noop_landing_pads.rs rename to compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs index 0bad1e5037..4079f0110e 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs @@ -102,6 +102,16 @@ impl RemoveNoopLandingPads { let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect(); for bb in postorder { debug!(" processing {:?}", bb); + if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { + if let Some(unwind_bb) = *unwind { + if nop_landing_pads.contains(unwind_bb) { + debug!(" removing noop landing pad"); + landing_pads_removed += 1; + *unwind = None; + } + } + } + for target in body[bb].terminator_mut().successors_mut() { if *target != resume_block && nop_landing_pads.contains(*target) { debug!(" folding noop jump to {:?} to resume block", target); @@ -110,15 +120,6 @@ impl RemoveNoopLandingPads { } } - if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { - if *unwind == Some(resume_block) { - debug!(" removing noop landing pad"); - jumps_folded -= 1; - landing_pads_removed += 1; - *unwind = None; - } - } - let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads); if is_nop_landing_pad { nop_landing_pads.insert(bb); diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs new file mode 100644 index 0000000000..b9f29786c6 --- /dev/null +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -0,0 +1,58 @@ +//! This pass replaces a drop of a type that does not need dropping, with a goto + +use crate::transform::{MirPass, MirSource}; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +use super::simplify::simplify_cfg; + +pub struct RemoveUnneededDrops; + +impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + trace!("Running RemoveUnneededDrops on {:?}", source); + let mut opt_finder = RemoveUnneededDropsOptimizationFinder { + tcx, + body, + optimizations: vec![], + def_id: source.def_id().expect_local(), + }; + opt_finder.visit_body(body); + let should_simplify = !opt_finder.optimizations.is_empty(); + for (loc, target) in opt_finder.optimizations { + let terminator = body.basic_blocks_mut()[loc.block].terminator_mut(); + debug!("SUCCESS: replacing `drop` with goto({:?})", target); + terminator.kind = TerminatorKind::Goto { target }; + } + + // if we applied optimizations, we potentially have some cfg to cleanup to + // make it easier for further passes + if should_simplify { + simplify_cfg(body); + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + match terminator.kind { + TerminatorKind::Drop { place, target, .. } => { + let ty = place.ty(self.body, self.tcx); + let needs_drop = ty.ty.needs_drop(self.tcx, self.tcx.param_env(self.def_id)); + if !needs_drop { + self.optimizations.push((location, target)); + } + } + _ => {} + } + self.super_terminator(terminator, location); + } +} +pub struct RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + optimizations: Vec<(Location, BasicBlock)>, + def_id: LocalDefId, +} diff --git a/src/librustc_mir/transform/required_consts.rs b/compiler/rustc_mir/src/transform/required_consts.rs similarity index 100% rename from src/librustc_mir/transform/required_consts.rs rename to compiler/rustc_mir/src/transform/required_consts.rs diff --git a/src/librustc_mir/transform/rustc_peek.rs b/compiler/rustc_mir/src/transform/rustc_peek.rs similarity index 95% rename from src/librustc_mir/transform/rustc_peek.rs rename to compiler/rustc_mir/src/transform/rustc_peek.rs index 00d269a4af..015af44b80 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/compiler/rustc_mir/src/transform/rustc_peek.rs @@ -1,4 +1,6 @@ -use rustc_ast as ast; +use std::borrow::Borrow; + +use rustc_ast::ast; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -16,7 +18,7 @@ use crate::dataflow::impls::{ use crate::dataflow::move_paths::{HasMoveData, MoveData}; use crate::dataflow::move_paths::{LookupResult, MovePathIndex}; use crate::dataflow::MoveDataParamEnv; -use crate::dataflow::{Analysis, Results, ResultsCursor}; +use crate::dataflow::{Analysis, JoinSemiLattice, Results, ResultsCursor}; pub struct SanityCheck; @@ -180,7 +182,7 @@ enum PeekCallKind { impl PeekCallKind { fn from_arg_ty(arg: Ty<'_>) -> Self { - match arg.kind { + match arg.kind() { ty::Ref(_, _, _) => PeekCallKind::ByRef, _ => PeekCallKind::ByVal, } @@ -205,7 +207,7 @@ impl PeekCall { if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = &terminator.kind { - if let ty::FnDef(def_id, substs) = func.literal.ty.kind { + if let ty::FnDef(def_id, substs) = *func.literal.ty.kind() { let sig = tcx.fn_sig(def_id); let name = tcx.item_name(def_id); if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek { @@ -248,25 +250,26 @@ pub trait RustcPeekAt<'tcx>: Analysis<'tcx> { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &BitSet, + flow_state: &Self::Domain, call: PeekCall, ); } -impl<'tcx, A> RustcPeekAt<'tcx> for A +impl<'tcx, A, D> RustcPeekAt<'tcx> for A where - A: Analysis<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>, + A: Analysis<'tcx, Domain = D> + HasMoveData<'tcx>, + D: JoinSemiLattice + Clone + Borrow>, { fn peek_at( &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &BitSet, + flow_state: &Self::Domain, call: PeekCall, ) { match self.move_data().rev_lookup.find(place.as_ref()) { LookupResult::Exact(peek_mpi) => { - let bit_state = flow_state.contains(peek_mpi); + let bit_state = flow_state.borrow().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"); diff --git a/src/librustc_mir/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs similarity index 99% rename from src/librustc_mir/transform/simplify.rs rename to compiler/rustc_mir/src/transform/simplify.rs index d8995e92ab..3fc8e6d4b0 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -281,8 +281,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { - blk.statements - .retain(|stmt| if let StatementKind::Nop = stmt.kind { false } else { true }) + blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop)) } } } diff --git a/src/librustc_mir/transform/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs similarity index 100% rename from src/librustc_mir/transform/simplify_branches.rs rename to compiler/rustc_mir/src/transform/simplify_branches.rs diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs new file mode 100644 index 0000000000..9b460c9ecb --- /dev/null +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -0,0 +1,227 @@ +use super::{MirPass, MirSource}; +use rustc_middle::{ + mir::{ + interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement, + StatementKind, TerminatorKind, + }, + ty::{Ty, TyCtxt}, +}; + +/// Pass to convert `if` conditions on integrals into switches on the integral. +/// For an example, it turns something like +/// +/// ``` +/// _3 = Eq(move _4, const 43i32); +/// StorageDead(_4); +/// switchInt(_3) -> [false: bb2, otherwise: bb3]; +/// ``` +/// +/// into: +/// +/// ``` +/// switchInt(_4) -> [43i32: bb3, otherwise: bb2]; +/// ``` +pub struct SimplifyComparisonIntegral; + +impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { + fn run_pass(&self, _: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + trace!("Running SimplifyComparisonIntegral on {:?}", source); + + let helper = OptimizationFinder { body }; + let opts = helper.find_optimizations(); + let mut storage_deads_to_insert = vec![]; + let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![]; + for opt in opts { + trace!("SUCCESS: Applying {:?}", opt); + // replace terminator with a switchInt that switches on the integer directly + let bbs = &mut body.basic_blocks_mut(); + let bb = &mut bbs[opt.bb_idx]; + // We only use the bits for the untyped, not length checked `values` field. Thus we are + // not using any of the convenience wrappers here and directly access the bits. + let new_value = match opt.branch_value_scalar { + Scalar::Raw { data, .. } => data, + Scalar::Ptr(_) => continue, + }; + const FALSE: u128 = 0; + let mut new_targets = opt.targets.clone(); + let first_is_false_target = opt.values[0] == FALSE; + match opt.op { + BinOp::Eq => { + // if the assignment was Eq we want the true case to be first + if first_is_false_target { + new_targets.swap(0, 1); + } + } + BinOp::Ne => { + // if the assignment was Ne we want the false case to be first + if !first_is_false_target { + new_targets.swap(0, 1); + } + } + _ => unreachable!(), + } + + // delete comparison statement if it the value being switched on was moved, which means it can not be user later on + if opt.can_remove_bin_op_stmt { + bb.statements[opt.bin_op_stmt_idx].make_nop(); + } else { + // if the integer being compared to a const integral is being moved into the comparison, + // e.g `_2 = Eq(move _3, const 'x');` + // we want to avoid making a double move later on in the switchInt on _3. + // So to avoid `switchInt(move _3) -> ['x': bb2, otherwise: bb1];`, + // we convert the move in the comparison statement to a copy. + + // unwrap is safe as we know this statement is an assign + let box (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap(); + + use Operand::*; + match rhs { + Rvalue::BinaryOp(_, ref mut left @ Move(_), Constant(_)) => { + *left = Copy(opt.to_switch_on); + } + Rvalue::BinaryOp(_, Constant(_), ref mut right @ Move(_)) => { + *right = Copy(opt.to_switch_on); + } + _ => (), + } + } + + let terminator = bb.terminator(); + + // remove StorageDead (if it exists) being used in the assign of the comparison + for (stmt_idx, stmt) in bb.statements.iter().enumerate() { + if !matches!(stmt.kind, StatementKind::StorageDead(local) if local == opt.to_switch_on.local) + { + continue; + } + storage_deads_to_remove.push((stmt_idx, opt.bb_idx)); + // if we have StorageDeads to remove then make sure to insert them at the top of each target + for bb_idx in new_targets.iter() { + storage_deads_to_insert.push(( + *bb_idx, + Statement { + source_info: terminator.source_info, + kind: StatementKind::StorageDead(opt.to_switch_on.local), + }, + )); + } + } + + let terminator = bb.terminator_mut(); + + terminator.kind = TerminatorKind::SwitchInt { + discr: Operand::Move(opt.to_switch_on), + switch_ty: opt.branch_value_ty, + values: vec![new_value].into(), + targets: new_targets, + }; + } + + for (idx, bb_idx) in storage_deads_to_remove { + body.basic_blocks_mut()[bb_idx].statements[idx].make_nop(); + } + + for (idx, stmt) in storage_deads_to_insert { + body.basic_blocks_mut()[idx].statements.insert(0, stmt); + } + } +} + +struct OptimizationFinder<'a, 'tcx> { + body: &'a Body<'tcx>, +} + +impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> { + fn find_optimizations(&self) -> Vec> { + self.body + .basic_blocks() + .iter_enumerated() + .filter_map(|(bb_idx, bb)| { + // find switch + let (place_switched_on, values, targets, place_switched_on_moved) = match &bb + .terminator() + .kind + { + rustc_middle::mir::TerminatorKind::SwitchInt { + discr, values, targets, .. + } => Some((discr.place()?, values, targets, discr.is_move())), + _ => None, + }?; + + // find the statement that assigns the place being switched on + bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| { + match &stmt.kind { + rustc_middle::mir::StatementKind::Assign(box (lhs, rhs)) + if *lhs == place_switched_on => + { + match rhs { + Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), left, right) => { + let (branch_value_scalar, branch_value_ty, to_switch_on) = + find_branch_value_info(left, right)?; + + Some(OptimizationInfo { + bin_op_stmt_idx: stmt_idx, + bb_idx, + can_remove_bin_op_stmt: place_switched_on_moved, + to_switch_on, + branch_value_scalar, + branch_value_ty, + op: *op, + values: values.clone().into_owned(), + targets: targets.clone(), + }) + } + _ => None, + } + } + _ => None, + } + }) + }) + .collect() + } +} + +fn find_branch_value_info<'tcx>( + left: &Operand<'tcx>, + right: &Operand<'tcx>, +) -> Option<(Scalar, Ty<'tcx>, Place<'tcx>)> { + // check that either left or right is a constant. + // if any are, we can use the other to switch on, and the constant as a value in a switch + use Operand::*; + match (left, right) { + (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on)) + | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => { + let branch_value_ty = branch_value.literal.ty; + // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats + if !branch_value_ty.is_integral() && !branch_value_ty.is_char() { + return None; + }; + let branch_value_scalar = branch_value.literal.val.try_to_scalar()?; + Some((branch_value_scalar, branch_value_ty, *to_switch_on)) + } + _ => None, + } +} + +#[derive(Debug)] +struct OptimizationInfo<'tcx> { + /// Basic block to apply the optimization + bb_idx: BasicBlock, + /// Statement index of Eq/Ne assignment that can be removed. None if the assignment can not be removed - i.e the statement is used later on + bin_op_stmt_idx: usize, + /// Can remove Eq/Ne assignment + can_remove_bin_op_stmt: bool, + /// Place that needs to be switched on. This place is of type integral + to_switch_on: Place<'tcx>, + /// Constant to use in switch target value + branch_value_scalar: Scalar, + /// Type of the constant value + branch_value_ty: Ty<'tcx>, + /// Either Eq or Ne + op: BinOp, + /// Current values used in the switch target. This needs to be replaced with the branch_value + values: Vec, + /// Current targets used in the switch + targets: Vec, +} diff --git a/src/librustc_mir/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs similarity index 91% rename from src/librustc_mir/transform/simplify_try.rs rename to compiler/rustc_mir/src/transform/simplify_try.rs index 9a80f0818c..45fa3b700c 100644 --- a/src/librustc_mir/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, List, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; -use std::iter::{Enumerate, Peekable}; +use std::iter::{once, Enumerate, Peekable}; use std::slice::Iter; /// Simplifies arms of form `Variant(x) => Variant(x)` to just a move. @@ -230,8 +230,8 @@ fn get_arm_identity_info<'a, 'tcx>( } } } - - nop_stmts.sort(); + // We sort primitive usize here so we can use unstable sort + nop_stmts.sort_unstable(); // Use one of the statements we're going to discard between the point // where the storage location for the variant field becomes live and @@ -368,7 +368,8 @@ fn optimization_applies<'tcx>( impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { + // FIXME(77359): This optimization can result in unsoundness. + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { return; } @@ -555,6 +556,12 @@ struct SimplifyBranchSameOptimization { bb_to_opt_terminator: BasicBlock, } +struct SwitchTargetAndValue { + target: BasicBlock, + // None in case of the `otherwise` case + value: Option, +} + struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> { body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, @@ -566,8 +573,16 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { .basic_blocks() .iter_enumerated() .filter_map(|(bb_idx, bb)| { - let (discr_switched_on, targets) = match &bb.terminator().kind { - TerminatorKind::SwitchInt { targets, discr, .. } => (discr, targets), + let (discr_switched_on, targets_and_values) = match &bb.terminator().kind { + TerminatorKind::SwitchInt { targets, discr, values, .. } => { + // if values.len() == targets.len() - 1, we need to include None where no value is present + // such that the zip does not throw away targets. If no `otherwise` case is in targets, the zip will simply throw away the added None + let values_extended = values.iter().map(|x|Some(*x)).chain(once(None)); + let targets_and_values:Vec<_> = targets.iter().zip(values_extended) + .map(|(target, value)| SwitchTargetAndValue{target:*target, value}) + .collect(); + assert_eq!(targets.len(), targets_and_values.len()); + (discr, targets_and_values)}, _ => return None, }; @@ -591,9 +606,9 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { }, }; - let mut iter_bbs_reachable = targets + let mut iter_bbs_reachable = targets_and_values .iter() - .map(|idx| (*idx, &self.body.basic_blocks()[*idx])) + .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 @@ -607,17 +622,17 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { }) .peekable(); - let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(targets[0]); + let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(&targets_and_values[0]); let mut all_successors_equivalent = StatementEquality::TrivialEqual; // All successor basic blocks must be equal or contain statements that are pairwise considered equal. - for ((bb_l_idx,bb_l), (bb_r_idx,bb_r)) in iter_bbs_reachable.tuple_windows() { + for ((target_and_value_l,bb_l), (target_and_value_r,bb_r)) in iter_bbs_reachable.tuple_windows() { let trivial_checks = bb_l.is_cleanup == bb_r.is_cleanup && bb_l.terminator().kind == bb_r.terminator().kind && bb_l.statements.len() == bb_r.statements.len(); let statement_check = || { bb_l.statements.iter().zip(&bb_r.statements).try_fold(StatementEquality::TrivialEqual, |acc,(l,r)| { - let stmt_equality = self.statement_equality(*adt_matched_on, &l, bb_l_idx, &r, bb_r_idx, self.tcx.sess.opts.debugging_opts.mir_opt_level); + let stmt_equality = self.statement_equality(*adt_matched_on, &l, target_and_value_l, &r, target_and_value_r); if matches!(stmt_equality, StatementEquality::NotEqual) { // short circuit None @@ -639,7 +654,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { // statements are trivially equal, so just take first trace!("Statements are trivially equal"); Some(SimplifyBranchSameOptimization { - bb_to_goto: bb_first, + bb_to_goto: bb_first.target, bb_to_opt_terminator: bb_idx, }) } @@ -674,17 +689,16 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { &self, adt_matched_on: Place<'tcx>, x: &Statement<'tcx>, - x_bb_idx: BasicBlock, + x_target_and_value: &SwitchTargetAndValue, y: &Statement<'tcx>, - y_bb_idx: BasicBlock, - mir_opt_level: usize, + y_target_and_value: &SwitchTargetAndValue, ) -> StatementEquality { let helper = |rhs: &Rvalue<'tcx>, - place: &Box>, + place: &Place<'tcx>, variant_index: &VariantIdx, side_to_choose| { let place_type = place.ty(self.body, self.tcx).ty; - let adt = match place_type.kind { + let adt = match *place_type.kind() { ty::Adt(adt, _) if adt.is_enum() => adt, _ => return StatementEquality::NotEqual, }; @@ -696,13 +710,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { match rhs { Rvalue::Use(operand) if operand.place() == Some(adt_matched_on) => { - // FIXME(76803): This logic is currently broken because it does not take into - // account the current discriminant value. - if mir_opt_level > 2 { - StatementEquality::ConsideredEqual(side_to_choose) - } else { - StatementEquality::NotEqual - } + StatementEquality::ConsideredEqual(side_to_choose) } _ => { trace!( @@ -722,16 +730,20 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { ( StatementKind::Assign(box (_, rhs)), StatementKind::SetDiscriminant { place, variant_index }, - ) => { + ) + // we need to make sure that the switch value that targets the bb with SetDiscriminant (y), is the same as the variant index + if Some(variant_index.index() as u128) == y_target_and_value.value => { // choose basic block of x, as that has the assign - helper(rhs, place, variant_index, x_bb_idx) + helper(rhs, place, variant_index, x_target_and_value.target) } ( StatementKind::SetDiscriminant { place, variant_index }, StatementKind::Assign(box (_, rhs)), - ) => { + ) + // we need to make sure that the switch value that targets the bb with SetDiscriminant (x), is the same as the variant index + if Some(variant_index.index() as u128) == x_target_and_value.value => { // choose basic block of y, as that has the assign - helper(rhs, place, variant_index, y_bb_idx) + helper(rhs, place, variant_index, y_target_and_value.target) } _ => { trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y); diff --git a/src/librustc_mir/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs similarity index 100% rename from src/librustc_mir/transform/uninhabited_enum_branching.rs rename to compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs diff --git a/src/librustc_mir/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs similarity index 100% rename from src/librustc_mir/transform/unreachable_prop.rs rename to compiler/rustc_mir/src/transform/unreachable_prop.rs diff --git a/src/librustc_mir/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs similarity index 78% rename from src/librustc_mir/transform/validate.rs rename to compiler/rustc_mir/src/transform/validate.rs index d7c9ecd065..94018a39b1 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -1,18 +1,18 @@ //! Validates the MIR to ensure that invariants are upheld. +use crate::dataflow::impls::MaybeStorageLive; +use crate::dataflow::{Analysis, ResultsCursor}; +use crate::util::storage::AlwaysLiveLocals; + use super::{MirPass, MirSource}; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::{ - mir::{ - AggregateKind, BasicBlock, Body, Location, MirPhase, Operand, Rvalue, Statement, - StatementKind, Terminator, TerminatorKind, - }, - ty::{ - self, - relate::{Relate, RelateResult, TypeRelation}, - ParamEnv, Ty, TyCtxt, - }, +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{ + AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue, + Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, }; +use rustc_middle::ty::fold::BottomUpFolder; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable}; #[derive(Copy, Clone, Debug)] enum EdgeKind { @@ -33,9 +33,18 @@ pub struct Validator { impl<'tcx> MirPass<'tcx> for Validator { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { - let param_env = tcx.param_env(source.def_id()); + let def_id = source.def_id(); + let param_env = tcx.param_env(def_id); let mir_phase = self.mir_phase; - TypeChecker { when: &self.when, source, body, tcx, param_env, mir_phase }.visit_body(body); + + let always_live_locals = AlwaysLiveLocals::new(body); + let storage_liveness = MaybeStorageLive::new(always_live_locals) + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); + + TypeChecker { when: &self.when, source, body, tcx, param_env, mir_phase, storage_liveness } + .visit_body(body); } } @@ -56,79 +65,24 @@ pub fn equal_up_to_regions( return true; } - struct LifetimeIgnoreRelation<'tcx> { - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - } - - impl TypeRelation<'tcx> for LifetimeIgnoreRelation<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn tag(&self) -> &'static str { - "librustc_mir::transform::validate" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance>( - &mut self, - _: ty::Variance, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - // Ignore variance, require types to be exactly the same. - self.relate(a, b) - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - if a == b { - // Short-circuit. - return Ok(a); - } - ty::relate::super_relate_tys(self, a, b) - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - _b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - // Ignore regions. - Ok(a) - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - ty::relate::super_relate_consts(self, a, b) - } - - fn binders( - &mut self, - a: ty::Binder, - b: ty::Binder, - ) -> RelateResult<'tcx, ty::Binder> - where - T: Relate<'tcx>, - { - self.relate(a.skip_binder(), b.skip_binder())?; - Ok(a) - } - } - - // Instantiate and run relation. - let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env }; - relator.relate(src, dest).is_ok() + // Normalize lifetimes away on both sides, then compare. + let param_env = param_env.with_reveal_all_normalized(tcx); + let normalize = |ty: Ty<'tcx>| { + tcx.normalize_erasing_regions( + param_env, + ty.fold_with(&mut BottomUpFolder { + tcx, + // We just erase all late-bound lifetimes, but this is not fully correct (FIXME): + // lifetimes in invariant positions could matter (e.g. through associated types). + // We rely on the fact that layout was confirmed to be equal above. + lt_op: |_| tcx.lifetimes.re_erased, + // 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()) } struct TypeChecker<'a, 'tcx> { @@ -138,6 +92,7 @@ struct TypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, mir_phase: MirPhase, + storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>, } impl<'a, 'tcx> TypeChecker<'a, 'tcx> { @@ -210,6 +165,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { + fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { + if context.is_use() { + // Uses of locals must occur while the local's storage is allocated. + self.storage_liveness.seek_after_primary_effect(location); + let locals_with_storage = self.storage_liveness.get(); + if !locals_with_storage.contains(*local) { + self.fail(location, format!("use of local {:?}, which has no storage here", local)); + } + } + } + + fn visit_var_debug_info(&mut self, _var_debug_info: &VarDebugInfo<'tcx>) { + // Debuginfo can contain field projections, which count as a use of the base local. Skip + // debuginfo so that we avoid the storage liveness assertion in that case. + } + fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { // `Operand::Copy` is only supposed to be used with `Copy` types. if let Operand::Copy(place) = operand { @@ -274,9 +245,33 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ) } } + Rvalue::Ref(_, BorrowKind::Shallow, _) => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase", + ); + } + } _ => {} } } + StatementKind::AscribeUserType(..) => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`AscribeUserType` should have been removed after drop lowering phase", + ); + } + } + StatementKind::FakeRead(..) => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`FakeRead` should have been removed after drop lowering phase", + ); + } + } _ => {} } } @@ -331,7 +326,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } TerminatorKind::Call { func, destination, cleanup, .. } => { let func_ty = func.ty(&self.body.local_decls, self.tcx); - match func_ty.kind { + match func_ty.kind() { ty::FnPtr(..) | ty::FnDef(..) => {} _ => self.fail( location, diff --git a/src/librustc_mir/util/aggregate.rs b/compiler/rustc_mir/src/util/aggregate.rs similarity index 91% rename from src/librustc_mir/util/aggregate.rs rename to compiler/rustc_mir/src/util/aggregate.rs index 1a22eee3a0..130409b9df 100644 --- a/src/librustc_mir/util/aggregate.rs +++ b/compiler/rustc_mir/src/util/aggregate.rs @@ -3,6 +3,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_target::abi::VariantIdx; +use std::convert::TryFrom; use std::iter::TrustedLen; /// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields. @@ -52,14 +53,11 @@ pub fn expand_aggregate<'tcx>( .enumerate() .map(move |(i, (op, ty))| { let lhs_field = if let AggregateKind::Array(_) = kind { - // FIXME(eddyb) `offset` should be u64. - let offset = i as u32; - assert_eq!(offset as usize, i); + let offset = u64::try_from(i).unwrap(); tcx.mk_place_elem( lhs, ProjectionElem::ConstantIndex { offset, - // FIXME(eddyb) `min_length` doesn't appear to be used. min_length: offset + 1, from_end: false, }, diff --git a/src/librustc_mir/util/alignment.rs b/compiler/rustc_mir/src/util/alignment.rs similarity index 98% rename from src/librustc_mir/util/alignment.rs rename to compiler/rustc_mir/src/util/alignment.rs index 202e5e27f1..a0728a6a63 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/compiler/rustc_mir/src/util/alignment.rs @@ -47,7 +47,7 @@ where ProjectionElem::Deref => break, ProjectionElem::Field(..) => { let ty = Place::ty_from(place.local, proj_base, local_decls, tcx).ty; - match ty.kind { + match ty.kind() { ty::Adt(def, _) if def.repr.packed() => return true, _ => {} } diff --git a/src/librustc_mir/util/borrowck_errors.rs b/compiler/rustc_mir/src/util/borrowck_errors.rs similarity index 99% rename from src/librustc_mir/util/borrowck_errors.rs rename to compiler/rustc_mir/src/util/borrowck_errors.rs index f8bb7e7a85..83bf7584f2 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/compiler/rustc_mir/src/util/borrowck_errors.rs @@ -287,7 +287,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { ty: Ty<'_>, is_index: Option, ) -> DiagnosticBuilder<'cx> { - let type_name = match (&ty.kind, is_index) { + let type_name = match (&ty.kind(), is_index) { (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", (&ty::Slice(_), _) => "slice", _ => span_bug!(move_from_span, "this path should not cause illegal move"), diff --git a/src/librustc_mir/util/collect_writes.rs b/compiler/rustc_mir/src/util/collect_writes.rs similarity index 100% rename from src/librustc_mir/util/collect_writes.rs rename to compiler/rustc_mir/src/util/collect_writes.rs diff --git a/src/librustc_mir/util/def_use.rs b/compiler/rustc_mir/src/util/def_use.rs similarity index 100% rename from src/librustc_mir/util/def_use.rs rename to compiler/rustc_mir/src/util/def_use.rs diff --git a/src/librustc_mir/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs similarity index 99% rename from src/librustc_mir/util/elaborate_drops.rs rename to compiler/rustc_mir/src/util/elaborate_drops.rs index 5d84a008d4..bf0a6be9a7 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/compiler/rustc_mir/src/util/elaborate_drops.rs @@ -10,8 +10,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use std::fmt; -use std::convert::TryInto; - /// The value of an inserted drop flag. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum DropFlagState { @@ -150,7 +148,7 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug { /// If this returns `None`, elements of `path` will not get a dedicated drop flag. /// /// This is only relevant for array patterns, which can move out of individual array elements. - fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option; + fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option; } #[derive(Debug)] @@ -744,9 +742,6 @@ where let tcx = self.tcx(); if let Some(size) = opt_size { - let size: u32 = size.try_into().unwrap_or_else(|_| { - bug!("move out check isn't implemented for array sizes bigger than u32::MAX"); - }); let fields: Vec<(Place<'tcx>, Option)> = (0..size) .map(|i| { ( @@ -863,7 +858,7 @@ where /// ADT, both in the success case or if one of the destructors fail. fn open_drop(&mut self) -> BasicBlock { let ty = self.place_ty(self.place); - match ty.kind { + match ty.kind() { ty::Closure(_, substs) => { let tys: Vec<_> = substs.as_closure().upvar_tys().collect(); self.open_drop_for_tuple(&tys) diff --git a/compiler/rustc_mir/src/util/find_self_call.rs b/compiler/rustc_mir/src/util/find_self_call.rs new file mode 100644 index 0000000000..5b146eeb87 --- /dev/null +++ b/compiler/rustc_mir/src/util/find_self_call.rs @@ -0,0 +1,36 @@ +use rustc_middle::mir::*; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::DefId; + +/// Checks if the specified `local` is used as the `self` prameter of a method call +/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is +/// returned. +pub fn find_self_call<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + local: Local, + block: BasicBlock, +) -> Option<(DefId, SubstsRef<'tcx>)> { + debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator); + if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = + &body[block].terminator + { + debug!("find_self_call: func={:?}", func); + if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { + if let ty::FnDef(def_id, substs) = *ty.kind() { + if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = + tcx.opt_associated_item(def_id) + { + debug!("find_self_call: args={:?}", args); + if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args { + if self_place.as_local() == Some(local) { + return Some((def_id, substs)); + } + } + } + } + } + } + None +} diff --git a/src/librustc_mir/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs similarity index 85% rename from src/librustc_mir/util/graphviz.rs rename to compiler/rustc_mir/src/util/graphviz.rs index 50193c4a0d..4511962d68 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -55,16 +55,28 @@ where writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?; // Global graph properties - writeln!(w, r#" graph [fontname="monospace"];"#)?; - writeln!(w, r#" node [fontname="monospace"];"#)?; - writeln!(w, r#" edge [fontname="monospace"];"#)?; + let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); + let mut graph_attrs = vec![&font[..]]; + let mut content_attrs = vec![&font[..]]; + + let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + if dark_mode { + graph_attrs.push(r#"bgcolor="black""#); + content_attrs.push(r#"color="white""#); + content_attrs.push(r#"fontcolor="white""#); + } + + writeln!(w, r#" graph [{}];"#, graph_attrs.join(" "))?; + let content_attrs_str = content_attrs.join(" "); + writeln!(w, r#" node [{}];"#, content_attrs_str)?; + writeln!(w, r#" edge [{}];"#, content_attrs_str)?; // Graph label write_graph_label(tcx, def_id, body, w)?; // Nodes for (block, _) in body.basic_blocks().iter_enumerated() { - write_node(def_id, block, body, w)?; + write_node(def_id, block, body, dark_mode, w)?; } // Edges @@ -84,6 +96,7 @@ where pub fn write_node_label( block: BasicBlock, body: &Body<'_>, + dark_mode: bool, w: &mut W, num_cols: u32, init: INIT, @@ -100,8 +113,9 @@ where // Basic block number at the top. write!( w, - r#"{blk}"#, - attrs = r#"bgcolor="gray" align="center""#, + r#"{blk}"#, + bgcolor = if dark_mode { "dimgray" } else { "gray" }, + attrs = r#"align="center""#, colspan = num_cols, blk = block.index() )?; @@ -134,11 +148,12 @@ fn write_node( def_id: DefId, block: BasicBlock, body: &Body<'_>, + dark_mode: bool, w: &mut W, ) -> io::Result<()> { // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables. write!(w, r#" {} [shape="none", label=<"#, node(def_id, block))?; - write_node_label(block, body, w, 1, |_| Ok(()), |_| Ok(()))?; + write_node_label(block, body, dark_mode, w, 1, |_| Ok(()), |_| Ok(()))?; // Close the node label and the node itself. writeln!(w, ">];") } diff --git a/src/librustc_mir/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs similarity index 84% rename from src/librustc_mir/util/mod.rs rename to compiler/rustc_mir/src/util/mod.rs index 8bbe207c07..699f3bcf01 100644 --- a/src/librustc_mir/util/mod.rs +++ b/compiler/rustc_mir/src/util/mod.rs @@ -7,11 +7,14 @@ pub mod storage; mod alignment; pub mod collect_writes; +mod find_self_call; mod graphviz; pub(crate) mod pretty; +pub(crate) mod spanview; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; +pub use self::find_self_call::find_self_call; pub use self::graphviz::write_node_label as write_graphviz_node_label; pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz}; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; diff --git a/src/librustc_mir/util/patch.rs b/compiler/rustc_mir/src/util/patch.rs similarity index 100% rename from src/librustc_mir/util/patch.rs rename to compiler/rustc_mir/src/util/patch.rs diff --git a/src/librustc_mir/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs similarity index 98% rename from src/librustc_mir/util/pretty.rs rename to compiler/rustc_mir/src/util/pretty.rs index 2a9cbc7fc0..49c644a20b 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -6,6 +6,7 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use super::graphviz::write_mir_fn_graphviz; +use super::spanview::write_mir_fn_spanview; use crate::transform::MirSource; use either::Either; use rustc_data_structures::fx::FxHashMap; @@ -147,6 +148,16 @@ fn dump_matched_mir_node<'tcx, F>( write_mir_fn_graphviz(tcx, source.def_id(), body, false, &mut file)?; }; } + + if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview { + let _: io::Result<()> = try { + let mut file = + create_dump_file(tcx, "html", pass_num, pass_name, disambiguator, source)?; + if source.def_id().is_local() { + write_mir_fn_spanview(tcx, source.def_id(), body, spanview, &mut file)?; + } + }; + } } /// Returns the path to the filename where we should dump a given MIR. @@ -387,7 +398,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); let Constant { span, user_ty, literal } = constant; - match literal.ty.kind { + match literal.ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char => {} // Unit type ty::Tuple(tys) if tys.is_empty() => {} @@ -405,7 +416,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); let ty::Const { ty, val, .. } = constant; - match ty.kind { + match ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => {} // Unit type ty::Tuple(tys) if tys.is_empty() => {} @@ -503,7 +514,7 @@ fn write_scope_tree( write!(indented_decl, " as {:?}", user_ty).unwrap(); } } - indented_decl.push_str(";"); + indented_decl.push(';'); let local_name = if local == RETURN_PLACE { " return place".to_string() } else { String::new() }; @@ -620,14 +631,11 @@ pub fn write_allocations<'tcx>( None => write!(w, " (deallocated)")?, Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { - match tcx.const_eval_poly(did) { - Ok(ConstValue::ByRef { alloc, .. }) => { + match tcx.eval_static_initializer(did) { + Ok(alloc) => { write!(w, " (static: {}, ", tcx.def_path_str(did))?; write_allocation_track_relocs(w, alloc)?; } - Ok(_) => { - span_bug!(tcx.def_span(did), " static item without `ByRef` initializer") - } Err(_) => write!( w, " (static: {}, error during initializer evaluation)", diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs new file mode 100644 index 0000000000..fe33fffe0e --- /dev/null +++ b/compiler/rustc_mir/src/util/spanview.rs @@ -0,0 +1,672 @@ +use rustc_hir::def_id::DefId; +use rustc_middle::hir; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::MirSpanview; +use rustc_span::{BytePos, Pos, Span, SyntaxContext}; + +use std::cmp; +use std::io::{self, Write}; + +pub const TOOLTIP_INDENT: &str = " "; + +const CARET: char = '\u{2038}'; // Unicode `CARET` +const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET +const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` +const NEW_LINE_SPAN: &str = "\n"; +const HEADER: &str = r#" + + + coverage_of_if_else - Code Regions + + +"#; + +const FOOTER: &str = r#" + +"#; + +/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. +pub struct SpanViewable { + pub span: Span, + pub id: String, + pub tooltip: String, +} + +/// Write a spanview HTML+CSS file to analyze MIR element spans. +pub fn write_mir_fn_spanview<'tcx, W>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + body: &Body<'tcx>, + spanview: MirSpanview, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let body_span = hir_body(tcx, def_id).value.span; + let mut span_viewables = Vec::new(); + for (bb, data) in body.basic_blocks().iter_enumerated() { + match spanview { + MirSpanview::Statement => { + for (i, statement) in data.statements.iter().enumerate() { + if let Some(span_viewable) = + statement_span_viewable(tcx, body_span, bb, i, statement) + { + span_viewables.push(span_viewable); + } + } + if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + MirSpanview::Terminator => { + if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + MirSpanview::Block => { + if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + } + } + write_spanview_document(tcx, def_id, span_viewables, w)?; + Ok(()) +} + +/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated +/// list `SpanViewable`s. +pub fn write_spanview_document<'tcx, W>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + mut span_viewables: Vec, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let fn_span = fn_span(tcx, def_id); + let mut from_pos = fn_span.lo(); + let end_pos = fn_span.hi(); + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(from_pos); + let indent_to_initial_start_col = " ".repeat(start.col.to_usize()); + debug!( + "fn_span source is:\n{}{}", + indent_to_initial_start_col, + source_map.span_to_snippet(fn_span).expect("function should have printable source") + ); + writeln!(w, "{}", HEADER)?; + write!( + w, + r#"

{}"#, + start.line - 1, + indent_to_initial_start_col, + )?; + span_viewables.sort_unstable_by(|a, b| { + let a = a.span; + let b = b.span; + if a.lo() == b.lo() { + // Sort hi() in reverse order so shorter spans are attempted after longer spans. + // This should give shorter spans a higher "layer", so they are not covered by + // the longer spans. + b.hi().partial_cmp(&a.hi()) + } else { + a.lo().partial_cmp(&b.lo()) + } + .unwrap() + }); + let mut ordered_viewables = &span_viewables[..]; + const LOWEST_VIEWABLE_LAYER: usize = 1; + let mut alt = false; + while ordered_viewables.len() > 0 { + debug!( + "calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}", + from_pos.to_usize(), + end_pos.to_usize(), + ordered_viewables.len() + ); + let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps( + tcx, + from_pos, + end_pos, + ordered_viewables, + alt, + LOWEST_VIEWABLE_LAYER, + w, + )?; + debug!( + "DONE calling write_next_viewable, with new from_pos={}, \ + and remaining viewables len={}", + next_from_pos.to_usize(), + next_ordered_viewables.len() + ); + assert!( + from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(), + "write_next_viewable_with_overlaps() must make a state change" + ); + from_pos = next_from_pos; + if next_ordered_viewables.len() != ordered_viewables.len() { + ordered_viewables = next_ordered_viewables; + alt = !alt; + } + } + if from_pos < end_pos { + write_coverage_gap(tcx, from_pos, end_pos, w)?; + } + write!(w, r#"
"#)?; + writeln!(w, "{}", FOOTER)?; + Ok(()) +} + +/// Format a string showing the start line and column, and end line and column within a file. +pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String { + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(span.lo()); + let end = source_map.lookup_char_pos(span.hi()); + format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1) +} + +pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { + use StatementKind::*; + match statement.kind { + Assign(..) => "Assign", + FakeRead(..) => "FakeRead", + SetDiscriminant { .. } => "SetDiscriminant", + StorageLive(..) => "StorageLive", + StorageDead(..) => "StorageDead", + LlvmInlineAsm(..) => "LlvmInlineAsm", + Retag(..) => "Retag", + AscribeUserType(..) => "AscribeUserType", + Coverage(..) => "Coverage", + Nop => "Nop", + } +} + +pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str { + use TerminatorKind::*; + match term.kind { + Goto { .. } => "Goto", + SwitchInt { .. } => "SwitchInt", + Resume => "Resume", + Abort => "Abort", + Return => "Return", + Unreachable => "Unreachable", + Drop { .. } => "Drop", + DropAndReplace { .. } => "DropAndReplace", + Call { .. } => "Call", + Assert { .. } => "Assert", + Yield { .. } => "Yield", + GeneratorDrop => "GeneratorDrop", + FalseEdge { .. } => "FalseEdge", + FalseUnwind { .. } => "FalseUnwind", + InlineAsm { .. } => "InlineAsm", + } +} + +fn statement_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + i: usize, + statement: &Statement<'tcx>, +) -> Option { + let span = statement.source_info.span; + if !body_span.contains(span) { + return None; + } + let id = format!("{}[{}]", bb.index(), i); + let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None); + Some(SpanViewable { span, id, tooltip }) +} + +fn terminator_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + data: &BasicBlockData<'tcx>, +) -> Option { + let term = data.terminator(); + let span = term.source_info.span; + if !body_span.contains(span) { + return None; + } + let id = format!("{}:{}", bb.index(), terminator_kind_name(term)); + let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator); + Some(SpanViewable { span, id, tooltip }) +} + +fn block_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + data: &BasicBlockData<'tcx>, +) -> Option { + let span = compute_block_span(data, body_span); + if !body_span.contains(span) { + return None; + } + let id = format!("{}", bb.index()); + let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator); + Some(SpanViewable { span, id, tooltip }) +} + +fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span { + let mut span = data.terminator().source_info.span; + for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { + // Only combine Spans from the root context, and within the function's body_span. + if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) { + span = span.to(statement_span); + } + } + span +} + +/// Recursively process each ordered span. Spans that overlap will have progressively varying +/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will +/// have alternating style choices, to help distinguish between them if, visually adjacent. +/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true +/// and false, for each adjacent non-overlapping span. Source code between the spans (code +/// that is not in any coverage region) has neutral styling. +fn write_next_viewable_with_overlaps<'tcx, 'b, W>( + tcx: TyCtxt<'tcx>, + mut from_pos: BytePos, + mut to_pos: BytePos, + ordered_viewables: &'b [SpanViewable], + alt: bool, + layer: usize, + w: &mut W, +) -> io::Result<(BytePos, &'b [SpanViewable])> +where + W: Write, +{ + let debug_indent = " ".repeat(layer); + let (viewable, mut remaining_viewables) = + ordered_viewables.split_first().expect("ordered_viewables should have some"); + + if from_pos < viewable.span.lo() { + debug!( + "{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \ + of {:?}), with to_pos={}", + debug_indent, + from_pos.to_usize(), + viewable.span.lo().to_usize(), + viewable.span, + to_pos.to_usize() + ); + let hi = cmp::min(viewable.span.lo(), to_pos); + write_coverage_gap(tcx, from_pos, hi, w)?; + from_pos = hi; + if from_pos < viewable.span.lo() { + debug!( + "{}EARLY RETURN: stopped before getting to next SpanViewable, at {}", + debug_indent, + from_pos.to_usize() + ); + return Ok((from_pos, ordered_viewables)); + } + } + + if from_pos < viewable.span.hi() { + // Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing + // with room to print the tail. + to_pos = cmp::min(viewable.span.hi(), to_pos); + debug!( + "{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}", + debug_indent, + viewable.span.hi().to_usize(), + to_pos.to_usize() + ); + } + + let mut subalt = false; + while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) { + let overlapping_viewable = &remaining_viewables[0]; + debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span); + + let span = + trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos)); + let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() { + // `viewable` is not yet fully rendered, so start writing the span, up to either the + // `to_pos` or the next `overlapping_viewable`, whichever comes first. + debug!( + "{}make html_snippet (may not write it if early exit) for partial span {:?} \ + of viewable.span {:?}", + debug_indent, span, viewable.span + ); + from_pos = span.hi(); + make_html_snippet(tcx, span, Some(&viewable)) + } else { + None + }; + + // Defer writing the HTML snippet (until after early return checks) ONLY for empty spans. + // An empty Span with Some(html_snippet) is probably a tail marker. If there is an early + // exit, there should be another opportunity to write the tail marker. + if !span.is_empty() { + if let Some(ref html_snippet) = some_html_snippet { + debug!( + "{}write html_snippet for that partial span of viewable.span {:?}", + debug_indent, viewable.span + ); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + some_html_snippet = None; + } + + if from_pos < overlapping_viewable.span.lo() { + debug!( + "{}EARLY RETURN: from_pos={} has not yet reached the \ + overlapping_viewable.span {:?}", + debug_indent, + from_pos.to_usize(), + overlapping_viewable.span + ); + // must have reached `to_pos` before reaching the start of the + // `overlapping_viewable.span` + return Ok((from_pos, ordered_viewables)); + } + + if from_pos == to_pos + && !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty()) + { + debug!( + "{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \ + empty, or not from_pos", + debug_indent, + to_pos.to_usize(), + overlapping_viewable.span + ); + // `to_pos` must have occurred before the overlapping viewable. Return + // `ordered_viewables` so we can continue rendering the `viewable`, from after the + // `to_pos`. + return Ok((from_pos, ordered_viewables)); + } + + if let Some(ref html_snippet) = some_html_snippet { + debug!( + "{}write html_snippet for that partial span of viewable.span {:?}", + debug_indent, viewable.span + ); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + + debug!( + "{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \ + and viewables len={}", + debug_indent, + from_pos.to_usize(), + to_pos.to_usize(), + remaining_viewables.len() + ); + // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`. + let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps( + tcx, + from_pos, + to_pos, + &remaining_viewables, + subalt, + layer + 1, + w, + )?; + debug!( + "{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \ + viewables len={}", + debug_indent, + next_from_pos.to_usize(), + next_remaining_viewables.len() + ); + assert!( + from_pos != next_from_pos + || remaining_viewables.len() != next_remaining_viewables.len(), + "write_next_viewable_with_overlaps() must make a state change" + ); + from_pos = next_from_pos; + if next_remaining_viewables.len() != remaining_viewables.len() { + remaining_viewables = next_remaining_viewables; + subalt = !subalt; + } + } + if from_pos <= viewable.span.hi() { + let span = trim_span(viewable.span, from_pos, to_pos); + debug!( + "{}After overlaps, writing (end span?) {:?} of viewable.span {:?}", + debug_indent, span, viewable.span + ); + if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(&viewable)) { + from_pos = span.hi(); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + } + debug!("{}RETURN: No more overlap", debug_indent); + Ok(( + from_pos, + if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables }, + )) +} + +#[inline(always)] +fn write_coverage_gap<'tcx, W>( + tcx: TyCtxt<'tcx>, + lo: BytePos, + hi: BytePos, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let span = Span::with_root_ctxt(lo, hi); + if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) { + write_span(html_snippet, "", false, 0, w) + } else { + Ok(()) + } +} + +fn write_span( + html_snippet: &str, + tooltip: &str, + alt: bool, + layer: usize, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let maybe_alt_class = if layer > 0 { + if alt { " odd" } else { " even" } + } else { + "" + }; + let maybe_title_attr = if !tooltip.is_empty() { + format!(" title=\"{}\"", escape_attr(tooltip)) + } else { + "".to_owned() + }; + if layer == 1 { + write!(w, "")?; + } + for (i, line) in html_snippet.lines().enumerate() { + if i > 0 { + write!(w, "{}", NEW_LINE_SPAN)?; + } + write!( + w, + r#"{}"#, + maybe_alt_class, layer, maybe_title_attr, line + )?; + } + // Check for and translate trailing newlines, because `str::lines()` ignores them + if html_snippet.ends_with('\n') { + write!(w, "{}", NEW_LINE_SPAN)?; + } + if layer == 1 { + write!(w, "")?; + } + Ok(()) +} + +fn make_html_snippet<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + some_viewable: Option<&SpanViewable>, +) -> Option { + let source_map = tcx.sess.source_map(); + let snippet = source_map + .span_to_snippet(span) + .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); + let html_snippet = if let Some(viewable) = some_viewable { + let is_head = span.lo() == viewable.span.lo(); + let is_tail = span.hi() == viewable.span.hi(); + let mut labeled_snippet = if is_head { + format!(r#"{}{}"#, viewable.id, ANNOTATION_LEFT_BRACKET) + } else { + "".to_owned() + }; + if span.is_empty() { + if is_head && is_tail { + labeled_snippet.push(CARET); + } + } else { + labeled_snippet.push_str(&escape_html(&snippet)); + }; + if is_tail { + labeled_snippet.push_str(&format!( + r#"{}{}"#, + ANNOTATION_RIGHT_BRACKET, viewable.id + )); + } + labeled_snippet + } else { + escape_html(&snippet) + }; + if html_snippet.is_empty() { None } else { Some(html_snippet) } +} + +fn tooltip<'tcx>( + tcx: TyCtxt<'tcx>, + spanview_id: &str, + span: Span, + statements: Vec>, + terminator: &Option>, +) -> String { + let source_map = tcx.sess.source_map(); + let mut text = Vec::new(); + text.push(format!("{}: {}:", spanview_id, &source_map.span_to_string(span))); + for statement in statements { + let source_range = source_range_no_file(tcx, &statement.source_info.span); + text.push(format!( + "\n{}{}: {}: {}", + TOOLTIP_INDENT, + source_range, + statement_kind_name(&statement), + format!("{:?}", statement) + )); + } + if let Some(term) = terminator { + let source_range = source_range_no_file(tcx, &term.source_info.span); + text.push(format!( + "\n{}{}: {}: {:?}", + TOOLTIP_INDENT, + source_range, + terminator_kind_name(term), + term.kind + )); + } + text.join("") +} + +fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span { + trim_span_hi(trim_span_lo(span, from_pos), to_pos) +} + +fn trim_span_lo(span: Span, from_pos: BytePos) -> Span { + if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) } +} + +fn trim_span_hi(span: Span, to_pos: BytePos) -> Span { + if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) } +} + +fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span { + let hir_id = + tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local")); + let fn_decl_span = tcx.hir().span(hir_id); + let body_span = hir_body(tcx, def_id).value.span; + debug_assert_eq!(fn_decl_span.ctxt(), body_span.ctxt()); + fn_decl_span.to(body_span) +} + +fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { + 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"); + tcx.hir().body(fn_body_id) +} + +fn escape_html(s: &str) -> String { + s.replace("&", "&").replace("<", "<").replace(">", ">") +} + +fn escape_attr(s: &str) -> String { + s.replace("&", "&") + .replace("\"", """) + .replace("'", "'") + .replace("<", "<") + .replace(">", ">") +} diff --git a/src/librustc_mir/util/storage.rs b/compiler/rustc_mir/src/util/storage.rs similarity index 100% rename from src/librustc_mir/util/storage.rs rename to compiler/rustc_mir/src/util/storage.rs diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml new file mode 100644 index 0000000000..2dd894a67a --- /dev/null +++ b/compiler/rustc_mir_build/Cargo.toml @@ -0,0 +1,27 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_mir_build" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_apfloat = { path = "../rustc_apfloat" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_infer = { path = "../rustc_infer" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_ast = { path = "../rustc_ast" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir_build/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs similarity index 98% rename from src/librustc_mir_build/build/block.rs rename to compiler/rustc_mir_build/src/build/block.rs index d1cbf209b0..beaf12b1db 100644 --- a/src/librustc_mir_build/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -96,8 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => { - let ignores_expr_result = - if let PatKind::Wild = *pattern.kind { true } else { false }; + 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. diff --git a/src/librustc_mir_build/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs similarity index 100% rename from src/librustc_mir_build/build/cfg.rs rename to compiler/rustc_mir_build/src/build/cfg.rs diff --git a/src/librustc_mir_build/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs similarity index 95% rename from src/librustc_mir_build/build/expr/as_constant.rs rename to compiler/rustc_mir_build/src/build/expr/as_constant.rs index 982aefcf60..244a70f83b 100644 --- a/src/librustc_mir_build/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let Expr { ty, temp_lifetime: _, span, kind } = expr; match kind { ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), - ExprKind::Literal { literal, user_ty } => { + ExprKind::Literal { literal, user_ty, const_id: _ } => { let user_ty = user_ty.map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, diff --git a/src/librustc_mir_build/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs similarity index 100% rename from src/librustc_mir_build/build/expr/as_operand.rs rename to compiler/rustc_mir_build/src/build/expr/as_operand.rs diff --git a/src/librustc_mir_build/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs similarity index 99% rename from src/librustc_mir_build/build/expr/as_place.rs rename to compiler/rustc_mir_build/src/build/expr/as_place.rs index 1e3e104c2b..39dbb6dd3f 100644 --- a/src/librustc_mir_build/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -367,7 +367,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.hir.tcx(); let place_ty = Place::ty_from(base_place.local, &base_place.projection, &self.local_decls, tcx); - if let ty::Slice(_) = place_ty.ty.kind { + if let ty::Slice(_) = place_ty.ty.kind() { // We need to create fake borrows to ensure that the bounds // check that we just did stays valid. Since we can't assign to // unsized values, we only need to ensure that none of the @@ -406,7 +406,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &self.local_decls, tcx, ); - match index_ty.ty.kind { + match index_ty.ty.kind() { // The previous index expression has already // done any index expressions needed here. ty::Slice(_) => break, diff --git a/src/librustc_mir_build/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs similarity index 100% rename from src/librustc_mir_build/build/expr/as_rvalue.rs rename to compiler/rustc_mir_build/src/build/expr/as_rvalue.rs diff --git a/src/librustc_mir_build/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs similarity index 96% rename from src/librustc_mir_build/build/expr/as_temp.rs rename to compiler/rustc_mir_build/src/build/expr/as_temp.rs index a9cc0cc2f2..9984b527ff 100644 --- a/src/librustc_mir_build/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -76,6 +76,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { local_decl.local_info = Some(box LocalInfo::StaticRef { def_id, is_thread_local: true }); } + ExprKind::Literal { const_id: Some(def_id), .. } => { + local_decl.local_info = Some(box LocalInfo::ConstRef { def_id }); + } _ => {} } this.local_decls.push(local_decl) diff --git a/src/librustc_mir_build/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs similarity index 100% rename from src/librustc_mir_build/build/expr/category.rs rename to compiler/rustc_mir_build/src/build/expr/category.rs diff --git a/src/librustc_mir_build/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs similarity index 99% rename from src/librustc_mir_build/build/expr/into.rs rename to compiler/rustc_mir_build/src/build/expr/into.rs index 3d623abfa6..319fae5009 100644 --- a/src/librustc_mir_build/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -168,7 +168,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { exit_block.unit() } ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => { - let intrinsic = match ty.kind { + let intrinsic = match *ty.kind() { ty::FnDef(def_id, _) => { let f = ty.fn_sig(this.hir.tcx()); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { diff --git a/src/librustc_mir_build/build/expr/mod.rs b/compiler/rustc_mir_build/src/build/expr/mod.rs similarity index 100% rename from src/librustc_mir_build/build/expr/mod.rs rename to compiler/rustc_mir_build/src/build/expr/mod.rs diff --git a/src/librustc_mir_build/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs similarity index 100% rename from src/librustc_mir_build/build/expr/stmt.rs rename to compiler/rustc_mir_build/src/build/expr/stmt.rs diff --git a/src/librustc_mir_build/build/into.rs b/compiler/rustc_mir_build/src/build/into.rs similarity index 100% rename from src/librustc_mir_build/build/into.rs rename to compiler/rustc_mir_build/src/build/into.rs diff --git a/src/librustc_mir_build/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs similarity index 99% rename from src/librustc_mir_build/build/matches/mod.rs rename to compiler/rustc_mir_build/src/build/matches/mod.rs index 5f87cb364b..a9b8a6181d 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -321,7 +321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_block = self.cfg.start_new_block(); let mut schedule_drops = true; // We keep a stack of all of the bindings and type asciptions - // from the the parent candidates that we visit, that also need to + // from the parent candidates that we visit, that also need to // be bound for each candidate. traverse_candidate( candidate, @@ -609,8 +609,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Array { ref prefix, ref slice, ref suffix } | PatKind::Slice { ref prefix, ref slice, ref suffix } => { - let from = u32::try_from(prefix.len()).unwrap(); - let to = u32::try_from(suffix.len()).unwrap(); + let from = u64::try_from(prefix.len()).unwrap(); + let to = u64::try_from(suffix.len()).unwrap(); for subpattern in prefix { self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); } @@ -1793,7 +1793,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .flat_map(|(bindings, _)| bindings) .chain(&candidate.bindings) .filter(|binding| { - if let BindingMode::ByValue = binding.binding_mode { true } else { false } + matches!(binding.binding_mode, BindingMode::ByValue ) }); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. diff --git a/src/librustc_mir_build/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs similarity index 99% rename from src/librustc_mir_build/build/matches/simplify.rs rename to compiler/rustc_mir_build/src/build/matches/simplify.rs index e584aeb922..a28a181e93 100644 --- a/src/librustc_mir_build/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -154,7 +154,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::Range(PatRange { lo, hi, end }) => { - let (range, bias) = match lo.ty.kind { + let (range, bias) = match *lo.ty.kind() { ty::Char => { (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0) } diff --git a/src/librustc_mir_build/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs similarity index 99% rename from src/librustc_mir_build/build/matches/test.rs rename to compiler/rustc_mir_build/src/build/matches/test.rs index c4a87a554a..d81c3b68f4 100644 --- a/src/librustc_mir_build/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -215,7 +215,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::SwitchInt { switch_ty, ref options } => { let target_blocks = make_target_blocks(self); - let terminator = if switch_ty.kind == ty::Bool { + let terminator = if *switch_ty.kind() == ty::Bool { assert!(!options.is_empty() && options.len() <= 2); if let [first_bb, second_bb] = *target_blocks { let (true_bb, false_bb) = match options[0] { @@ -368,8 +368,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // We want to do this even when the scrutinee is a reference to an // array, so we can call `<[u8]>::eq` rather than having to find an // `<[u8; N]>::eq`. - let unsize = |ty: Ty<'tcx>| match ty.kind { - ty::Ref(region, rty, _) => match rty.kind { + let unsize = |ty: Ty<'tcx>| match ty.kind() { + ty::Ref(region, rty, _) => match rty.kind() { ty::Array(inner_ty, n) => Some((region, inner_ty, n)), _ => None, }, @@ -407,7 +407,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let deref_ty = match ty.kind { + let deref_ty = match *ty.kind() { ty::Ref(_, deref_ty, _) => deref_ty, _ => bug!("non_scalar_compare called on non-reference type: {}", ty), }; diff --git a/src/librustc_mir_build/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs similarity index 91% rename from src/librustc_mir_build/build/matches/util.rs rename to compiler/rustc_mir_build/src/build/matches/util.rs index 605396c5eb..4ef88c25ca 100644 --- a/src/librustc_mir_build/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -31,26 +31,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { suffix: &'pat [Pat<'tcx>], ) { let tcx = self.hir.tcx(); - let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind { + let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind() { ty::Array(_, length) => { - (length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(), true) + (length.eval_usize(tcx, self.hir.param_env), true) } _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), }; match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { let elem = - ProjectionElem::ConstantIndex { offset: idx as u32, min_length, from_end: false }; + ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; let place = tcx.mk_place_elem(*place, elem); MatchPair::new(place, subpattern) })); if let Some(subslice_pat) = opt_slice { - let suffix_len = suffix.len() as u32; + let suffix_len = suffix.len() as u64; let subslice = tcx.mk_place_elem( *place, ProjectionElem::Subslice { - from: prefix.len() as u32, + from: prefix.len() as u64, to: if exact_size { min_length - suffix_len } else { suffix_len }, from_end: !exact_size, }, @@ -59,7 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { - let end_offset = (idx + 1) as u32; + let end_offset = (idx + 1) as u64; let elem = ProjectionElem::ConstantIndex { offset: if exact_size { min_length - end_offset } else { end_offset }, min_length, diff --git a/src/librustc_mir_build/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs similarity index 100% rename from src/librustc_mir_build/build/misc.rs rename to compiler/rustc_mir_build/src/build/misc.rs diff --git a/src/librustc_mir_build/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs similarity index 99% rename from src/librustc_mir_build/build/mod.rs rename to compiler/rustc_mir_build/src/build/mod.rs index 71026f5096..aa96ae8759 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -96,7 +96,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ let body = tcx.hir().body(body_id); let ty = tcx.type_of(fn_def_id); let mut abi = fn_sig.abi; - let implicit_argument = match ty.kind { + let implicit_argument = match ty.kind() { ty::Closure(..) => { // HACK(eddyb) Avoid having RustCall on closures, // as it adds unnecessary (and wrong) auto-tupling. @@ -159,7 +159,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ 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 { + 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), }; @@ -228,7 +228,7 @@ fn liberated_closure_env_ty( ) -> Ty<'_> { let closure_ty = tcx.typeck_body(body_id).node_type(closure_expr_id); - let (closure_def_id, closure_substs) = match closure_ty.kind { + let (closure_def_id, closure_substs) = match *closure_ty.kind() { ty::Closure(closure_def_id, closure_substs) => (closure_def_id, closure_substs), _ => bug!("closure expr does not have closure type: {:?}", closure_ty), }; @@ -840,11 +840,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let closure_env_arg = Local::new(1); let mut closure_env_projs = vec![]; let mut closure_ty = self.local_decls[closure_env_arg].ty; - if let ty::Ref(_, ty, _) = closure_ty.kind { + if let ty::Ref(_, ty, _) = closure_ty.kind() { closure_env_projs.push(ProjectionElem::Deref); closure_ty = ty; } - let upvar_substs = match closure_ty.kind { + let upvar_substs = match closure_ty.kind() { ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty), @@ -876,7 +876,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut projs = closure_env_projs.clone(); projs.push(ProjectionElem::Field(Field::new(i), ty)); match capture { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue(_) => {} ty::UpvarCapture::ByRef(..) => { projs.push(ProjectionElem::Deref); } diff --git a/src/librustc_mir_build/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs similarity index 100% rename from src/librustc_mir_build/build/scope.rs rename to compiler/rustc_mir_build/src/build/scope.rs diff --git a/src/librustc_mir_build/lib.rs b/compiler/rustc_mir_build/src/lib.rs similarity index 92% rename from src/librustc_mir_build/lib.rs rename to compiler/rustc_mir_build/src/lib.rs index 313bb979a5..714041ad4e 100644 --- a/src/librustc_mir_build/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,11 +1,12 @@ //! Construction of MIR from HIR. //! //! This crate also contains the match exhaustiveness and usefulness checking. - +#![feature(array_windows)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(const_fn)] #![feature(const_panic)] +#![feature(control_flow_enum)] #![feature(crate_visibility_modifier)] #![feature(bool_to_option)] #![feature(or_patterns)] diff --git a/src/librustc_mir_build/lints.rs b/compiler/rustc_mir_build/src/lints.rs similarity index 97% rename from src/librustc_mir_build/lints.rs rename to compiler/rustc_mir_build/src/lints.rs index fd2d5a4abd..a8d7c612a8 100644 --- a/src/librustc_mir_build/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -70,7 +70,7 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> { let param_env = tcx.param_env(def_id); let func_ty = func.ty(body, tcx); - if let ty::FnDef(fn_def_id, substs) = func_ty.kind { + if let ty::FnDef(fn_def_id, substs) = *func_ty.kind() { let (call_fn_id, call_substs) = if let Ok(Some(instance)) = Instance::resolve(tcx, param_env, fn_def_id, substs) { (instance.def_id(), instance.substs) @@ -117,7 +117,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { // A diverging InlineAsm is treated as non-recursing TerminatorKind::InlineAsm { destination, .. } => { if destination.is_some() { - ControlFlow::Continue + ControlFlow::CONTINUE } else { ControlFlow::Break(NonRecursive) } @@ -131,7 +131,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue, + | TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE, } } @@ -144,7 +144,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { } } - ControlFlow::Continue + ControlFlow::CONTINUE } fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { diff --git a/src/librustc_mir_build/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs similarity index 89% rename from src/librustc_mir_build/thir/constant.rs rename to compiler/rustc_mir_build/src/thir/constant.rs index dd5515d39b..a7bb2864da 100644 --- a/src/librustc_mir_build/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_middle::mir::interpret::{ truncate, Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, }; -use rustc_middle::ty::{self, ParamEnv, TyCtxt, TyS}; +use rustc_middle::ty::{self, ParamEnv, TyCtxt}; use rustc_span::symbol::Symbol; use rustc_target::abi::Size; @@ -21,19 +21,21 @@ crate fn lit_to_const<'tcx>( Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) }; - let lit = match (lit, &ty.kind) { - (ast::LitKind::Str(s, _), ty::Ref(_, TyS { kind: ty::Str, .. }, _)) => { + let lit = match (lit, &ty.kind()) { + (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes()); let allocation = tcx.intern_const_alloc(allocation); ConstValue::Slice { data: allocation, start: 0, end: s.len() } } - (ast::LitKind::ByteStr(data), ty::Ref(_, TyS { kind: ty::Slice(_), .. }, _)) => { + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) + if matches!(inner_ty.kind(), ty::Slice(_)) => + { let allocation = Allocation::from_byte_aligned_bytes(data as &Vec); let allocation = tcx.intern_const_alloc(allocation); ConstValue::Slice { data: allocation, start: 0, end: data.len() } } - (ast::LitKind::ByteStr(data), ty::Ref(_, TyS { kind: ty::Array(_, _), .. }, _)) => { + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { let id = tcx.allocate_bytes(data); ConstValue::Scalar(Scalar::Ptr(id.into())) } diff --git a/src/librustc_mir_build/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs similarity index 100% rename from src/librustc_mir_build/thir/cx/block.rs rename to compiler/rustc_mir_build/src/thir/cx/block.rs diff --git a/src/librustc_mir_build/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs similarity index 96% rename from src/librustc_mir_build/thir/cx/expr.rs rename to compiler/rustc_mir_build/src/thir/cx/expr.rs index c51c3bcf56..13e69474cf 100644 --- a/src/librustc_mir_build/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -117,7 +117,14 @@ fn apply_adjustment<'a, 'tcx>( }, }; - overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()]) + overloaded_place( + cx, + hir_expr, + adjustment.target, + Some(call), + vec![expr.to_ref()], + deref.span, + ) } Adjust::Borrow(AutoBorrow::Ref(_, m)) => { ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() } @@ -247,6 +254,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Lit(ref lit) => ExprKind::Literal { literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), user_ty: None, + const_id: None, }, hir::ExprKind::Binary(op, ref lhs, ref rhs) => { @@ -276,7 +284,14 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Index(ref lhs, ref index) => { if cx.typeck_results().is_method_call(expr) { - overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()]) + overloaded_place( + cx, + expr, + expr_ty, + None, + vec![lhs.to_ref(), index.to_ref()], + expr.span, + ) } else { ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() } } @@ -284,7 +299,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => { if cx.typeck_results().is_method_call(expr) { - overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()]) + overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span) } else { ExprKind::Deref { arg: arg.to_ref() } } @@ -306,6 +321,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( ExprKind::Literal { literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), user_ty: None, + const_id: None, } } else { ExprKind::Unary { op: UnOp::Neg, arg: arg.to_ref() } @@ -313,7 +329,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( } } - hir::ExprKind::Struct(ref qpath, ref fields, ref base) => match expr_ty.kind { + hir::ExprKind::Struct(ref qpath, ref fields, ref base) => match expr_ty.kind() { ty::Adt(adt, substs) => match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { let user_provided_types = cx.typeck_results().user_provided_types(); @@ -363,7 +379,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Closure(..) => { let closure_ty = cx.typeck_results().expr_ty(expr); - let (def_id, substs, movability) = match closure_ty.kind { + let (def_id, substs, movability) = match *closure_ty.kind() { ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs), None), ty::Generator(def_id, substs, movability) => { (def_id, UpvarSubsts::Generator(substs), Some(movability)) @@ -447,6 +463,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx, ty), user_ty, + const_id: None, }, } .to_ref(), @@ -473,6 +490,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx, ty), user_ty: None, + const_id: None, }, } .to_ref(), @@ -585,7 +603,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( temp_lifetime, ty: var_ty, span: expr.span, - kind: ExprKind::Literal { literal, user_ty: None }, + kind: ExprKind::Literal { literal, user_ty: None, const_id: None }, } .to_ref() }; @@ -714,7 +732,11 @@ fn method_callee<'a, 'tcx>( temp_lifetime, ty, span, - kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx(), ty), user_ty }, + kind: ExprKind::Literal { + literal: ty::Const::zero_sized(cx.tcx(), ty), + user_ty, + const_id: None, + }, } } @@ -777,6 +799,7 @@ fn convert_path_expr<'a, 'tcx>( ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx, cx.typeck_results().node_type(expr.hir_id)), user_ty, + const_id: None, } } @@ -794,6 +817,7 @@ fn convert_path_expr<'a, 'tcx>( .tcx .mk_const(ty::Const { val, ty: cx.typeck_results().node_type(expr.hir_id) }), user_ty: None, + const_id: Some(def_id), } } @@ -810,6 +834,7 @@ fn convert_path_expr<'a, 'tcx>( ty: cx.typeck_results().node_type(expr.hir_id), }), user_ty, + const_id: Some(def_id), } } @@ -818,7 +843,7 @@ fn convert_path_expr<'a, 'tcx>( let user_provided_type = user_provided_types.get(expr.hir_id).copied(); debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); let ty = cx.typeck_results().node_type(expr.hir_id); - match ty.kind { + 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 { @@ -899,7 +924,7 @@ fn convert_var<'tcx>( }); let region = cx.tcx.mk_region(region); - let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind { + let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind() { match cx.infcx.closure_kind(closure_substs).unwrap() { ty::ClosureKind::Fn => { let ref_closure_ty = cx.tcx.mk_ref( @@ -959,7 +984,7 @@ fn convert_var<'tcx>( // ...but the upvar might be an `&T` or `&mut T` capture, at which // point we need an implicit deref match cx.typeck_results().upvar_capture(upvar_id) { - ty::UpvarCapture::ByValue => field_kind, + ty::UpvarCapture::ByValue(_) => field_kind, ty::UpvarCapture::ByRef(borrow) => ExprKind::Deref { arg: Expr { temp_lifetime, @@ -1014,6 +1039,7 @@ fn overloaded_place<'a, 'tcx>( place_ty: Ty<'tcx>, overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, args: Vec>, + span: Span, ) -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // call returns an &T and we must add the deref so that the types @@ -1027,26 +1053,26 @@ fn overloaded_place<'a, 'tcx>( // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. - let (region, mutbl) = match recv_ty.kind { + let (region, mutbl) = match *recv_ty.kind() { ty::Ref(region, _, mutbl) => (region, mutbl), - _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"), + _ => span_bug!(span, "overloaded_place: receiver is not a reference"), }; let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl }); // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let fun = method_callee(cx, expr, expr.span, overloaded_callee); + let fun = method_callee(cx, expr, span, overloaded_callee); let ref_expr = Expr { temp_lifetime, ty: ref_ty, - span: expr.span, + span, kind: ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false, - fn_span: expr.span, + fn_span: span, }, }; @@ -1074,7 +1100,7 @@ fn capture_upvar<'tcx>( kind: convert_var(cx, closure_expr, var_hir_id), }; match upvar_capture { - ty::UpvarCapture::ByValue => captured_var.to_ref(), + ty::UpvarCapture::ByValue(_) => captured_var.to_ref(), ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow.kind { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, diff --git a/src/librustc_mir_build/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs similarity index 100% rename from src/librustc_mir_build/thir/cx/mod.rs rename to compiler/rustc_mir_build/src/thir/cx/mod.rs diff --git a/src/librustc_mir_build/thir/cx/to_ref.rs b/compiler/rustc_mir_build/src/thir/cx/to_ref.rs similarity index 100% rename from src/librustc_mir_build/thir/cx/to_ref.rs rename to compiler/rustc_mir_build/src/thir/cx/to_ref.rs diff --git a/src/librustc_mir_build/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs similarity index 98% rename from src/librustc_mir_build/thir/mod.rs rename to compiler/rustc_mir_build/src/thir/mod.rs index 2837bfa040..4d57fd5c64 100644 --- a/src/librustc_mir_build/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -273,6 +273,10 @@ crate enum ExprKind<'tcx> { Literal { literal: &'tcx Const<'tcx>, user_ty: Option>>, + /// The `DefId` of the `const` item this literal + /// was produced from, if this is not a user-written + /// literal value. + const_id: Option, }, /// A literal containing the address of a `static`. /// diff --git a/src/librustc_mir_build/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs similarity index 90% rename from src/librustc_mir_build/thir/pattern/_match.rs rename to compiler/rustc_mir_build/src/thir/pattern/_match.rs index 3202f7d1b1..04de9a7a58 100644 --- a/src/librustc_mir_build/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -139,10 +139,10 @@ //! //! It is computed as follows. We look at the pattern `p_1` on top of the stack, //! and we have three cases: -//! 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. -//! 1.2. `p_1 = _`. We return the rest of the stack: +//! 2.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. +//! 2.2. `p_1 = _`. We return the rest of the stack: //! p_2, .., p_n -//! 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting +//! 2.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting //! stack. //! D((r_1, p_2, .., p_n)) //! D((r_2, p_2, .., p_n)) @@ -276,7 +276,7 @@ use self::Usefulness::*; use self::WitnessPreference::*; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::Idx; use super::{compare_const_vals, PatternFoldable, PatternFolder}; @@ -327,7 +327,7 @@ impl<'tcx> LiteralExpander<'tcx> { crty: Ty<'tcx>, ) -> ConstValue<'tcx> { debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty); - match (val, &crty.kind, &rty.kind) { + match (val, &crty.kind(), &rty.kind()) { // the easy case, deref a reference (ConstValue::Scalar(p), x, y) if x == y => { match p { @@ -368,41 +368,35 @@ impl<'tcx> LiteralExpander<'tcx> { impl<'tcx> PatternFolder<'tcx> for LiteralExpander<'tcx> { fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> { - debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind, pat.kind); - match (&pat.ty.kind, &*pat.kind) { - ( - &ty::Ref(_, rty, _), - &PatKind::Constant { - value: - Const { - val: ty::ConstKind::Value(val), - ty: ty::TyS { kind: ty::Ref(_, crty, _), .. }, - }, - }, - ) => Pat { - ty: pat.ty, - span: pat.span, - kind: box PatKind::Deref { - subpattern: Pat { - ty: rty, + debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind); + match (pat.ty.kind(), &*pat.kind) { + (&ty::Ref(_, rty, _), &PatKind::Constant { value: Const { val, ty: const_ty } }) + if const_ty.is_ref() => + { + let crty = + if let ty::Ref(_, crty, _) = const_ty.kind() { crty } else { unreachable!() }; + if let ty::ConstKind::Value(val) = val { + Pat { + ty: pat.ty, span: pat.span, - kind: box PatKind::Constant { - value: Const::from_value( - self.tcx, - self.fold_const_value_deref(*val, rty, crty), - rty, - ), + kind: box PatKind::Deref { + subpattern: Pat { + ty: rty, + span: pat.span, + kind: box PatKind::Constant { + value: Const::from_value( + self.tcx, + self.fold_const_value_deref(*val, rty, crty), + rty, + ), + }, + }, }, - }, - }, - }, - - ( - &ty::Ref(_, rty, _), - &PatKind::Constant { - value: Const { val, ty: ty::TyS { kind: ty::Ref(_, crty, _), .. } }, - }, - ) => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), + } + } else { + bug!("cannot deref {:#?}, {} -> {}", val, crty, rty) + } + } (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self), (_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self), @@ -422,7 +416,7 @@ impl<'tcx> Pat<'tcx> { /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` /// works well. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] crate struct PatStack<'p, 'tcx>(SmallVec<[&'p Pat<'tcx>; 2]>); impl<'p, 'tcx> PatStack<'p, 'tcx> { @@ -510,13 +504,36 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { } } +/// Depending on the match patterns, the specialization process might be able to use a fast path. +/// Tracks whether we can use the fast path and the lookup table needed in those cases. +#[derive(Clone, Debug, PartialEq)] +enum SpecializationCache { + /// Patterns consist of only enum variants. + /// Variant patterns does not intersect with each other (in contrast to range patterns), + /// so it is possible to precompute the result of `Matrix::specialize_constructor` at a + /// lower computational complexity. + /// `lookup` is responsible for holding the precomputed result of + /// `Matrix::specialize_constructor`, while `wilds` is used for two purposes: the first one is + /// the precomputed result of `Matrix::specialize_wildcard`, and the second is to be used as a + /// fallback for `Matrix::specialize_constructor` when it tries to apply a constructor that + /// has not been seen in the `Matrix`. See `update_cache` for further explanations. + Variants { lookup: FxHashMap>, wilds: SmallVec<[usize; 1]> }, + /// Does not belong to the cases above, use the slow path. + Incompatible, +} + /// A 2D matrix. -#[derive(Clone)] -crate struct Matrix<'p, 'tcx>(Vec>); +#[derive(Clone, PartialEq)] +crate struct Matrix<'p, 'tcx> { + patterns: Vec>, + cache: SpecializationCache, +} impl<'p, 'tcx> Matrix<'p, 'tcx> { crate fn empty() -> Self { - Matrix(vec![]) + // Use `SpecializationCache::Incompatible` as a placeholder; we will initialize it on the + // first call to `push`. See the first half of `update_cache`. + Matrix { patterns: vec![], cache: SpecializationCache::Incompatible } } /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it. @@ -528,18 +545,101 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { self.push(row) } } else { - self.0.push(row); + self.patterns.push(row); + self.update_cache(self.patterns.len() - 1); + } + } + + fn update_cache(&mut self, idx: usize) { + let row = &self.patterns[idx]; + // We don't know which kind of cache could be used until we see the first row; therefore an + // empty `Matrix` is initialized with `SpecializationCache::Empty`, then the cache is + // assigned the appropriate variant below on the first call to `push`. + if self.patterns.is_empty() { + self.cache = if row.is_empty() { + SpecializationCache::Incompatible + } else { + match *row.head().kind { + PatKind::Variant { .. } => SpecializationCache::Variants { + lookup: FxHashMap::default(), + wilds: SmallVec::new(), + }, + // Note: If the first pattern is a wildcard, then all patterns after that is not + // useful. The check is simple enough so we treat it as the same as unsupported + // patterns. + _ => SpecializationCache::Incompatible, + } + }; + } + // Update the cache. + match &mut self.cache { + SpecializationCache::Variants { ref mut lookup, ref mut wilds } => { + let head = row.head(); + match *head.kind { + _ if head.is_wildcard() => { + // Per rule 1.3 in the top-level comments, a wildcard pattern is included in + // the result of `specialize_constructor` for *any* `Constructor`. + // We push the wildcard pattern to the precomputed result for constructors + // that we have seen before; results for constructors we have not yet seen + // defaults to `wilds`, which is updated right below. + for (_, v) in lookup.iter_mut() { + v.push(idx); + } + // Per rule 2.1 and 2.2 in the top-level comments, only wildcard patterns + // are included in the result of `specialize_wildcard`. + // What we do here is to track the wildcards we have seen; so in addition to + // acting as the precomputed result of `specialize_wildcard`, `wilds` also + // serves as the default value of `specialize_constructor` for constructors + // that are not in `lookup`. + wilds.push(idx); + } + PatKind::Variant { adt_def, variant_index, .. } => { + // Handle the cases of rule 1.1 and 1.2 in the top-level comments. + // A variant pattern can only be included in the results of + // `specialize_constructor` for a particular constructor, therefore we are + // using a HashMap to track that. + lookup + .entry(adt_def.variants[variant_index].def_id) + // Default to `wilds` for absent keys. See above for an explanation. + .or_insert_with(|| wilds.clone()) + .push(idx); + } + _ => { + self.cache = SpecializationCache::Incompatible; + } + } + } + SpecializationCache::Incompatible => {} } } /// Iterate over the first component of each row fn heads<'a>(&'a self) -> impl Iterator> + Captures<'p> { - self.0.iter().map(|r| r.head()) + self.patterns.iter().map(|r| r.head()) } /// This computes `D(self)`. See top of the file for explanations. fn specialize_wildcard(&self) -> Self { - self.0.iter().filter_map(|r| r.specialize_wildcard()).collect() + match &self.cache { + SpecializationCache::Variants { wilds, .. } => { + let result = + wilds.iter().filter_map(|&i| self.patterns[i].specialize_wildcard()).collect(); + // When debug assertions are enabled, check the results against the "slow path" + // result. + debug_assert_eq!( + result, + Self { + patterns: self.patterns.clone(), + cache: SpecializationCache::Incompatible + } + .specialize_wildcard() + ); + result + } + SpecializationCache::Incompatible => { + self.patterns.iter().filter_map(|r| r.specialize_wildcard()).collect() + } + } } /// This computes `S(constructor, self)`. See top of the file for explanations. @@ -549,10 +649,47 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { constructor: &Constructor<'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>, ) -> Matrix<'p, 'tcx> { - self.0 - .iter() - .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns)) - .collect() + match &self.cache { + SpecializationCache::Variants { lookup, wilds } => { + let result: Self = if let Constructor::Variant(id) = constructor { + lookup + .get(id) + // Default to `wilds` for absent keys. See `update_cache` for an explanation. + .unwrap_or(&wilds) + .iter() + .filter_map(|&i| { + self.patterns[i].specialize_constructor( + cx, + constructor, + ctor_wild_subpatterns, + ) + }) + .collect() + } else { + unreachable!() + }; + // When debug assertions are enabled, check the results against the "slow path" + // result. + debug_assert_eq!( + result, + Matrix { + patterns: self.patterns.clone(), + cache: SpecializationCache::Incompatible + } + .specialize_constructor( + cx, + constructor, + ctor_wild_subpatterns + ) + ); + result + } + SpecializationCache::Incompatible => self + .patterns + .iter() + .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns)) + .collect(), + } } } @@ -574,7 +711,7 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\n")?; - let &Matrix(ref m) = self; + let Matrix { patterns: m, .. } = self; let pretty_printed_matrix: Vec> = m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); @@ -639,7 +776,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. crate fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { - match ty.kind { + match ty.kind() { ty::Adt(def, ..) => { def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local() } @@ -920,14 +1057,14 @@ impl<'tcx> Constructor<'tcx> { let mut subpatterns = fields.all_patterns(); let pat = match self { - Single | Variant(_) => match ty.kind { + Single | Variant(_) => match ty.kind() { ty::Adt(..) | ty::Tuple(..) => { let subpatterns = subpatterns .enumerate() .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) .collect(); - if let ty::Adt(adt, substs) = ty.kind { + if let ty::Adt(adt, substs) = ty.kind() { if adt.is_enum() { PatKind::Variant { adt_def: adt, @@ -1074,7 +1211,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); let ret = match constructor { - Single | Variant(_) => match ty.kind { + Single | Variant(_) => match ty.kind() { ty::Tuple(ref fs) => { Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty())) } @@ -1125,7 +1262,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { } _ => Fields::empty(), }, - Slice(slice) => match ty.kind { + Slice(slice) => match *ty.kind() { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty)) @@ -1443,7 +1580,7 @@ fn all_constructors<'a, 'tcx>( .unwrap(), ) }; - match pcx.ty.kind { + match *pcx.ty.kind() { ty::Bool => { [true, false].iter().map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b))).collect() } @@ -1558,7 +1695,7 @@ struct IntRange<'tcx> { impl<'tcx> IntRange<'tcx> { #[inline] fn is_integral(ty: Ty<'_>) -> bool { - match ty.kind { + match ty.kind() { ty::Char | ty::Int(_) | ty::Uint(_) => true, _ => false, } @@ -1580,7 +1717,7 @@ impl<'tcx> IntRange<'tcx> { #[inline] fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> { - match ty.kind { + match *ty.kind() { ty::Char => Some((Size::from_bytes(4), 0)), ty::Int(ity) => { let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); @@ -1650,15 +1787,38 @@ impl<'tcx> IntRange<'tcx> { param_env: ty::ParamEnv<'tcx>, pat: &Pat<'tcx>, ) -> Option> { - match pat_constructor(tcx, param_env, pat)? { - IntRange(range) => Some(range), - _ => None, + // This MUST be kept in sync with `pat_constructor`. + match *pat.kind { + PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` + PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."), + + PatKind::Binding { .. } + | PatKind::Wild + | PatKind::Leaf { .. } + | PatKind::Deref { .. } + | PatKind::Variant { .. } + | PatKind::Array { .. } + | PatKind::Slice { .. } => None, + + PatKind::Constant { value } => Self::from_const(tcx, param_env, value, pat.span), + + PatKind::Range(PatRange { lo, hi, end }) => { + let ty = lo.ty; + Self::from_range( + tcx, + lo.eval_bits(tcx, param_env, lo.ty), + hi.eval_bits(tcx, param_env, hi.ty), + ty, + &end, + pat.span, + ) + } } } // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it. fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 { - match ty.kind { + match *ty.kind() { ty::Int(ity) => { let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128; 1u128 << (bits - 1) @@ -1830,7 +1990,7 @@ crate fn is_useful<'p, 'tcx>( is_under_guard: bool, is_top_level: bool, ) -> Usefulness<'tcx> { - let &Matrix(ref rows) = matrix; + let Matrix { patterns: rows, .. } = matrix; debug!("is_useful({:#?}, {:#?})", matrix, v); // The base case. We are pattern-matching on () and the return value is @@ -2059,6 +2219,7 @@ fn pat_constructor<'tcx>( param_env: ty::ParamEnv<'tcx>, pat: &Pat<'tcx>, ) -> Option> { + // This MUST be kept in sync with `IntRange::from_pat`. match *pat.kind { PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` PatKind::Binding { .. } | PatKind::Wild => None, @@ -2070,7 +2231,7 @@ fn pat_constructor<'tcx>( if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) { Some(IntRange(int_range)) } else { - match (value.val, &value.ty.kind) { + match (value.val, &value.ty.kind()) { (_, ty::Array(_, n)) => { let len = n.eval_usize(tcx, param_env); Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) })) @@ -2102,7 +2263,7 @@ fn pat_constructor<'tcx>( } PatKind::Array { ref prefix, ref slice, ref suffix } | PatKind::Slice { ref prefix, ref slice, ref suffix } => { - let array_len = match pat.ty.kind { + let array_len = match pat.ty.kind() { ty::Array(_, length) => Some(length.eval_usize(tcx, param_env)), ty::Slice(_) => None, _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), @@ -2141,7 +2302,7 @@ fn slice_pat_covered_by_const<'tcx>( ) }; - let data: &[u8] = match (const_val_val, &const_val.ty.kind) { + let data: &[u8] = match (const_val_val, &const_val.ty.kind()) { (ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => { assert_eq!(*t, tcx.types.u8); let n = n.eval_usize(tcx, param_env); @@ -2272,7 +2433,7 @@ fn split_grouped_constructors<'p, 'tcx>( // `borders` is the set of borders between equivalence classes: each equivalence // class lies between 2 borders. let row_borders = matrix - .0 + .patterns .iter() .flat_map(|row| { IntRange::from_pat(tcx, param_env, row.head()).map(|r| (r, row.len())) @@ -2305,19 +2466,19 @@ fn split_grouped_constructors<'p, 'tcx>( // interval into a constructor. split_ctors.extend( borders - .windows(2) - .filter_map(|window| match (window[0], window[1]) { - (Border::JustBefore(n), Border::JustBefore(m)) => { + .array_windows() + .filter_map(|&pair| match pair { + [Border::JustBefore(n), Border::JustBefore(m)] => { if n < m { Some(IntRange { range: n..=(m - 1), ty, span }) } else { None } } - (Border::JustBefore(n), Border::AfterMax) => { + [Border::JustBefore(n), Border::AfterMax] => { Some(IntRange { range: n..=u128::MAX, ty, span }) } - (Border::AfterMax, _) => None, + [Border::AfterMax, _] => None, }) .map(IntRange), ); @@ -2561,7 +2722,7 @@ fn specialize_one_pattern<'p, 'tcx>( // elements don't necessarily point to memory, they are usually // just integers. The only time they should be pointing to memory // is when they are subslices of nonzero slices. - let (alloc, offset, n, ty) = match value.ty.kind { + let (alloc, offset, n, ty) = match value.ty.kind() { ty::Array(t, n) => { let n = n.eval_usize(cx.tcx, cx.param_env); // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce, diff --git a/src/librustc_mir_build/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs similarity index 99% rename from src/librustc_mir_build/thir/pattern/check_match.rs rename to compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 4e7108667e..047bf7db4c 100644 --- a/src/librustc_mir_build/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -289,7 +289,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa cx.typeck_results.extract_binding_mode(cx.tcx.sess, p.hir_id, p.span) { let pat_ty = cx.typeck_results.pat_ty(p).peel_refs(); - if let ty::Adt(edef, _) = pat_ty.kind { + if let ty::Adt(edef, _) = pat_ty.kind() { if edef.is_enum() && edef.variants.iter().any(|variant| { variant.ident == ident && variant.ctor_kind == CtorKind::Const @@ -442,7 +442,7 @@ fn check_exhaustive<'p, 'tcx>( // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by // `is_useful` to exhaustively match uninhabited types, so we manually check here. if is_empty_match && !cx.tcx.features().exhaustive_patterns { - let scrutinee_is_visibly_uninhabited = match scrut_ty.kind { + let scrutinee_is_visibly_uninhabited = match scrut_ty.kind() { ty::Never => true, ty::Adt(def, _) => { def.is_enum() @@ -462,7 +462,7 @@ fn check_exhaustive<'p, 'tcx>( Err(err) => err, }; - let non_empty_enum = match scrut_ty.kind { + let non_empty_enum = match scrut_ty.kind() { ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(), _ => false, }; @@ -541,7 +541,7 @@ fn adt_defined_here( witnesses: &[super::Pat<'_>], ) { let ty = ty.peel_refs(); - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { if let Some(sp) = cx.tcx.hir().span_if_local(def.did) { err.span_label(sp, format!("`{}` defined here", ty)); } @@ -556,7 +556,7 @@ fn adt_defined_here( fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec { let mut covered = vec![]; - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { // Don't point at variants that have already been covered due to other patterns to avoid // visual clutter. for pattern in patterns { 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 new file mode 100644 index 0000000000..a203b3a142 --- /dev/null +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -0,0 +1,535 @@ +use rustc_hir as hir; +use rustc_index::vec::Idx; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_middle::mir::Field; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_session::lint; +use rustc_span::Span; +use rustc_trait_selection::traits::predicate_for_trait_def; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; + +use std::cell::Cell; + +use super::{FieldPat, Pat, PatCtxt, PatKind}; + +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). + pub(super) fn const_to_pat( + &self, + cv: &'tcx ty::Const<'tcx>, + id: hir::HirId, + span: Span, + mir_structural_match_violation: bool, + ) -> Pat<'tcx> { + debug!("const_to_pat: cv={:#?} id={:?}", cv, id); + debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span); + + let pat = self.tcx.infer_ctxt().enter(|infcx| { + let mut convert = ConstToPat::new(self, id, span, infcx); + convert.to_pat(cv, mir_structural_match_violation) + }); + + debug!("const_to_pat: pat={:?}", pat); + pat + } +} + +struct ConstToPat<'a, 'tcx> { + id: hir::HirId, + span: Span, + param_env: ty::ParamEnv<'tcx>, + + // This tracks if we emitted some hard error for a given const value, so that + // we will not subsequently issue an irrelevant lint for the same const + // value. + saw_const_match_error: Cell, + + // This tracks if we emitted some diagnostic for a given const value, so that + // we will not subsequently issue an irrelevant lint for the same const + // value. + saw_const_match_lint: Cell, + + // For backcompat we need to keep allowing non-structurally-eq types behind references. + // See also all the `cant-hide-behind` tests. + behind_reference: Cell, + + // inference context used for checking `T: Structural` bounds. + infcx: InferCtxt<'a, 'tcx>, + + include_lint_checks: bool, +} + +mod fallback_to_const_ref { + #[derive(Debug)] + /// This error type signals that we encountered a non-struct-eq situation behind a reference. + /// We bubble this up in order to get back to the reference destructuring and make that emit + /// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq` + /// on such patterns (since that function takes a reference) and not have to jump through any + /// hoops to get a reference to the value. + pub(super) struct FallbackToConstRef(()); + + pub(super) fn fallback_to_const_ref<'a, 'tcx>( + c2p: &super::ConstToPat<'a, 'tcx>, + ) -> FallbackToConstRef { + assert!(c2p.behind_reference.get()); + FallbackToConstRef(()) + } +} +use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef}; + +impl<'a, 'tcx> ConstToPat<'a, 'tcx> { + fn new( + pat_ctxt: &PatCtxt<'_, 'tcx>, + id: hir::HirId, + span: Span, + infcx: InferCtxt<'a, 'tcx>, + ) -> Self { + ConstToPat { + id, + span, + infcx, + param_env: pat_ctxt.param_env, + include_lint_checks: pat_ctxt.include_lint_checks, + saw_const_match_error: Cell::new(false), + saw_const_match_lint: Cell::new(false), + behind_reference: Cell::new(false), + } + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn adt_derive_msg(&self, adt_def: &AdtDef) -> String { + let path = self.tcx().def_path_str(adt_def.did); + format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ) + } + + fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { + traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty).map( + |non_sm_ty| { + with_no_trimmed_paths(|| match non_sm_ty { + traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt), + traits::NonStructuralMatchTy::Dynamic => { + "trait objects cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Opaque => { + "opaque types cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Generator => { + "generators cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Closure => { + "closures cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Param => { + bug!("use of a constant whose type is a parameter inside a pattern") + } + traits::NonStructuralMatchTy::Projection => { + bug!("use of a constant whose type is a projection inside a pattern") + } + traits::NonStructuralMatchTy::Foreign => { + bug!("use of a value of a foreign type inside a pattern") + } + }) + }, + ) + } + + fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { + ty.is_structural_eq_shallow(self.infcx.tcx) + } + + fn to_pat( + &mut self, + cv: &'tcx ty::Const<'tcx>, + mir_structural_match_violation: bool, + ) -> Pat<'tcx> { + // 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 + // invoked except by this method. + // + // 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(); + + if self.include_lint_checks && !self.saw_const_match_error.get() { + // If we were able to successfully convert the const to some pat, + // double-check that all types in the const implement `Structural`. + + let structural = self.search_for_structural_match_violation(cv.ty); + debug!( + "search_for_structural_match_violation cv.ty: {:?} returned: {:?}", + cv.ty, structural + ); + + // This can occur because const qualification treats all associated constants as + // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them + // before it runs. + // + // FIXME(#73448): Find a way to bring const qualification into parity with + // `search_for_structural_match_violation`. + if structural.is_none() && mir_structural_match_violation { + warn!("MIR const-checker found novel structural match violation. See #73448."); + return inlined_const_as_pat; + } + + if let Some(msg) = structural { + if !self.type_may_have_partial_eq_impl(cv.ty) { + // span_fatal avoids ICE from resolution of non-existent method (rare case). + self.tcx().sess.span_fatal(self.span, &msg); + } else if mir_structural_match_violation && !self.saw_const_match_lint.get() { + self.tcx().struct_span_lint_hir( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + self.id, + self.span, + |lint| lint.build(&msg).emit(), + ); + } else { + debug!( + "`search_for_structural_match_violation` found one, but `CustomEq` was \ + not in the qualifs for that `const`" + ); + } + } + } + + inlined_const_as_pat + } + + fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { + // double-check there even *is* a semantic `PartialEq` to dispatch to. + // + // (If there isn't, then we can safely issue a hard + // error, because that's never worked, due to compiler + // using `PartialEq::eq` in this scenario in the past.) + let partial_eq_trait_id = + self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); + let obligation: PredicateObligation<'_> = predicate_for_trait_def( + self.tcx(), + self.param_env, + ObligationCause::misc(self.span, self.id), + partial_eq_trait_id, + 0, + ty, + &[], + ); + // FIXME: should this call a `predicate_must_hold` variant instead? + + let has_impl = self.infcx.predicate_may_hold(&obligation); + + // Note: To fix rust-lang/rust#65466, we could just remove this type + // walk hack for function pointers, and unconditionally error + // if `PartialEq` is not implemented. However, that breaks stable + // code at the moment, because types like `for <'a> fn(&'a ())` do + // not *yet* implement `PartialEq`. So for now we leave this here. + has_impl + || ty.walk().any(|t| match t.unpack() { + ty::subst::GenericArgKind::Lifetime(_) => false, + ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(), + ty::subst::GenericArgKind::Const(_) => false, + }) + } + + // Recursive helper for `to_pat`; invoke that (instead of calling this directly). + fn recur( + &self, + cv: &'tcx ty::Const<'tcx>, + mir_structural_match_violation: bool, + ) -> Result, FallbackToConstRef> { + let id = self.id; + let span = self.span; + let tcx = self.tcx(); + let param_env = self.param_env; + + let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| -> Result<_, _> { + vals.iter() + .enumerate() + .map(|(idx, val)| { + let field = Field::new(idx); + Ok(FieldPat { field, pattern: self.recur(val, false)? }) + }) + .collect() + }; + + let kind = match cv.ty.kind() { + ty::Float(_) => { + tcx.struct_span_lint_hir( + lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + id, + span, + |lint| lint.build("floating-point types cannot be used in patterns").emit(), + ); + PatKind::Constant { value: cv } + } + ty::Adt(adt_def, _) if adt_def.is_union() => { + // Matching on union fields is unsafe, we can't hide it in constants + self.saw_const_match_error.set(true); + let msg = "cannot use unions in constant patterns"; + if self.include_lint_checks { + tcx.sess.span_err(span, msg); + } else { + tcx.sess.delay_span_bug(span, msg) + } + PatKind::Wild + } + ty::Adt(..) + if !self.type_may_have_partial_eq_impl(cv.ty) + // FIXME(#73448): Find a way to bring const qualification into parity with + // `search_for_structural_match_violation` and then remove this condition. + && self.search_for_structural_match_violation(cv.ty).is_some() => + { + // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we + // could get `Option`, even though `Option` is annotated with derive. + let msg = self.search_for_structural_match_violation(cv.ty).unwrap(); + self.saw_const_match_error.set(true); + if self.include_lint_checks { + tcx.sess.span_err(self.span, &msg); + } else { + tcx.sess.delay_span_bug(self.span, &msg) + } + PatKind::Wild + } + // If the type is not structurally comparable, just emit the constant directly, + // causing the pattern match code to treat it opaquely. + // FIXME: This code doesn't emit errors itself, the caller emits the errors. + // So instead of specific errors, you just get blanket errors about the whole + // const type. See + // https://github.com/rust-lang/rust/pull/70743#discussion_r404701963 for + // details. + // Backwards compatibility hack because we can't cause hard errors on these + // types, so we compare them via `PartialEq::eq` at runtime. + ty::Adt(..) if !self.type_marked_structural(cv.ty) && self.behind_reference.get() => { + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + cv.ty, cv.ty, + ); + tcx.struct_span_lint_hir( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + // Since we are behind a reference, we can just bubble the error up so we get a + // constant at reference type, making it easy to let the fallback call + // `PartialEq::eq` on it. + return Err(fallback_to_const_ref(self)); + } + ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { + debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty); + let path = tcx.def_path_str(adt_def.did); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ); + self.saw_const_match_error.set(true); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } + PatKind::Wild + } + ty::Adt(adt_def, substs) if adt_def.is_enum() => { + let destructured = tcx.destructure_const(param_env.and(cv)); + PatKind::Variant { + adt_def, + substs, + variant_index: destructured + .variant + .expect("destructed const of adt without variant id"), + subpatterns: field_pats(destructured.fields)?, + } + } + ty::Tuple(_) | ty::Adt(_, _) => { + let destructured = tcx.destructure_const(param_env.and(cv)); + PatKind::Leaf { subpatterns: field_pats(destructured.fields)? } + } + ty::Array(..) => PatKind::Array { + prefix: tcx + .destructure_const(param_env.and(cv)) + .fields + .iter() + .map(|val| self.recur(val, false)) + .collect::>()?, + slice: None, + suffix: Vec::new(), + }, + ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { + // These are not allowed and will error elsewhere anyway. + ty::Dynamic(..) => { + self.saw_const_match_error.set(true); + let msg = format!("`{}` cannot be used in patterns", cv.ty); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } + PatKind::Wild + } + // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this + // optimization for now. + ty::Str => PatKind::Constant { value: cv }, + ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, + // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when + // matching against references, you can only use byte string literals. + // FIXME: clean this up, likely by permitting array patterns when matching on slices + ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, + // Cannot merge this with the catch all branch below, because the `const_deref` + // changes the type from slice to array, and slice patterns behave differently from + // array patterns. + ty::Slice(..) => { + let old = self.behind_reference.replace(true); + let array = tcx.deref_const(self.param_env.and(cv)); + let val = PatKind::Deref { + subpattern: Pat { + kind: Box::new(PatKind::Slice { + prefix: tcx + .destructure_const(param_env.and(array)) + .fields + .iter() + .map(|val| self.recur(val, false)) + .collect::>()?, + slice: None, + suffix: vec![], + }), + span, + ty: pointee_ty, + }, + }; + self.behind_reference.set(old); + val + } + // Backwards compatibility hack: support references to non-structural types. + // We'll lower + // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a + // reference. This makes the rest of the matching logic simpler as it doesn't have + // to figure out how to get a reference again. + ty::Adt(adt_def, _) if !self.type_marked_structural(pointee_ty) => { + if self.behind_reference.get() { + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); + let msg = self.adt_derive_msg(adt_def); + self.tcx().struct_span_lint_hir( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + self.id, + self.span, + |lint| lint.build(&msg).emit(), + ); + } + PatKind::Constant { value: cv } + } else { + if !self.saw_const_match_error.get() { + self.saw_const_match_error.set(true); + let msg = self.adt_derive_msg(adt_def); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } + } + PatKind::Wild + } + } + // All other references are converted into deref patterns and then recursively + // convert the dereferenced constant to a pattern that is the sub-pattern of the + // deref pattern. + _ => { + let old = self.behind_reference.replace(true); + // In case there are structural-match violations somewhere in this subpattern, + // we fall back to a const pattern. If we do not do this, we may end up with + // a !structural-match constant that is not of reference type, which makes it + // very hard to invoke `PartialEq::eq` on it as a fallback. + let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) { + Ok(subpattern) => PatKind::Deref { subpattern }, + Err(_) => PatKind::Constant { value: cv }, + }; + self.behind_reference.set(old); + val + } + }, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => { + PatKind::Constant { value: cv } + } + ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => { + PatKind::Constant { value: cv } + } + // FIXME: these can have very suprising behaviour where optimization levels or other + // compilation choices change the runtime behaviour of the match. + // See https://github.com/rust-lang/rust/issues/70861 for examples. + ty::FnPtr(..) | ty::RawPtr(..) => { + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); + let msg = "function pointers and unsized pointers in patterns behave \ + unpredictably and should not be relied upon. \ + See https://github.com/rust-lang/rust/issues/70861 for details."; + tcx.struct_span_lint_hir( + lint::builtin::POINTER_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + PatKind::Constant { value: cv } + } + _ => { + self.saw_const_match_error.set(true); + let msg = format!("`{}` cannot be used in patterns", cv.ty); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } + PatKind::Wild + } + }; + + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + && mir_structural_match_violation + // FIXME(#73448): Find a way to bring const qualification into parity with + // `search_for_structural_match_violation` and then remove this condition. + && self.search_for_structural_match_violation(cv.ty).is_some() + { + self.saw_const_match_lint.set(true); + // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we + // could get `Option`, even though `Option` is annotated with derive. + let msg = self.search_for_structural_match_violation(cv.ty).unwrap().replace( + "in a pattern,", + "in a pattern, the constant's initializer must be trivial or", + ); + tcx.struct_span_lint_hir( + lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + + Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) }) + } +} diff --git a/src/librustc_mir_build/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs similarity index 98% rename from src/librustc_mir_build/thir/pattern/mod.rs rename to compiler/rustc_mir_build/src/thir/pattern/mod.rs index c163cb0e60..718ed78889 100644 --- a/src/librustc_mir_build/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -39,19 +39,19 @@ crate enum PatternError { NonConstPath(Span), } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq)] crate enum BindingMode { ByValue, ByRef(BorrowKind), } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] crate struct FieldPat<'tcx> { crate field: Field, crate pattern: Pat<'tcx>, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] crate struct Pat<'tcx> { crate ty: Ty<'tcx>, crate span: Span, @@ -116,7 +116,7 @@ crate struct Ascription<'tcx> { crate user_ty_span: Span, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] crate enum PatKind<'tcx> { Wild, @@ -237,7 +237,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { Some(&adt_def.variants[variant_index]) } _ => { - if let ty::Adt(adt, _) = self.ty.kind { + if let ty::Adt(adt, _) = self.ty.kind() { if !adt.is_enum() { Some(&adt.variants[VariantIdx::new(0)]) } else { @@ -302,7 +302,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { Ok(()) } PatKind::Deref { ref subpattern } => { - match self.ty.kind { + match self.ty.kind() { ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, ty::Ref(_, _, mutbl) => { write!(f, "&{}", mutbl.prefix_str())?; @@ -559,7 +559,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } hir::PatKind::Tuple(ref pats, ddpos) => { - let tys = match ty.kind { + let tys = match ty.kind() { ty::Tuple(ref tys) => tys, _ => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty), }; @@ -588,7 +588,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // x's type, which is &T, where we want T (the type being matched). let var_ty = ty; if let ty::BindByReference(_) = bm { - if let ty::Ref(_, rty, _) = ty.kind { + if let ty::Ref(_, rty, _) = ty.kind() { ty = rty; } else { bug!("`ref {}` has wrong type {}", ident, ty); @@ -608,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::TupleStruct(ref qpath, ref pats, ddpos) => { let res = self.typeck_results.qpath_res(qpath, pat.hir_id); - let adt_def = match ty.kind { + let adt_def = match ty.kind() { ty::Adt(adt_def, _) => adt_def, _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty), }; @@ -670,7 +670,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let prefix = self.lower_patterns(prefix); let slice = self.lower_opt_pattern(slice); let suffix = self.lower_patterns(suffix); - match ty.kind { + match ty.kind() { // Matching a slice, `[T]`. ty::Slice(..) => PatKind::Slice { prefix, slice, suffix }, // Fixed-length array, `[T; len]`. @@ -704,7 +704,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let enum_id = self.tcx.parent(variant_id).unwrap(); let adt_def = self.tcx.adt_def(enum_id); if adt_def.is_enum() { - let substs = match ty.kind { + let substs = match ty.kind() { ty::Adt(_, substs) | ty::FnDef(_, substs) => substs, ty::Error(_) => { // Avoid ICE (#50585) @@ -1058,7 +1058,7 @@ crate fn compare_const_vals<'tcx>( if let (Some(a), Some(b)) = (a_bits, b_bits) { use rustc_apfloat::Float; - return match ty.kind { + return match *ty.kind() { ty::Float(ast::FloatTy::F32) => { let l = ::rustc_apfloat::ieee::Single::from_bits(a); let r = ::rustc_apfloat::ieee::Single::from_bits(b); @@ -1081,7 +1081,7 @@ crate fn compare_const_vals<'tcx>( }; } - if let ty::Str = ty.kind { + if let ty::Str = ty.kind() { if let ( ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }), ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }), diff --git a/src/librustc_mir_build/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs similarity index 97% rename from src/librustc_mir_build/thir/util.rs rename to compiler/rustc_mir_build/src/thir/util.rs index 7de60ddda4..aea8667314 100644 --- a/src/librustc_mir_build/thir/util.rs +++ b/compiler/rustc_mir_build/src/thir/util.rs @@ -17,7 +17,7 @@ crate trait UserAnnotatedTyHelpers<'tcx> { let mut user_ty = *user_provided_types.get(hir_id)?; debug!("user_subts_applied_to_ty_of_hir_id: user_ty={:?}", user_ty); let ty = self.typeck_results().node_type(hir_id); - match ty.kind { + match ty.kind() { ty::Adt(adt_def, ..) => { if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value { *did = adt_def.did; diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml new file mode 100644 index 0000000000..52835e5c8a --- /dev/null +++ b/compiler/rustc_parse/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_parse" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +bitflags = "1.0" +tracing = "0.1" +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_feature = { path = "../rustc_feature" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_errors = { path = "../rustc_errors" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_ast = { path = "../rustc_ast" } +unicode-normalization = "0.1.11" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_parse/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs similarity index 81% rename from src/librustc_parse/lexer/mod.rs rename to compiler/rustc_parse/src/lexer/mod.rs index 7503f15ac5..32b124970c 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,21 +1,19 @@ use rustc_ast::ast::AttrStyle; use rustc_ast::token::{self, CommentKind, Token, TokenKind}; -use rustc_data_structures::sync::Lrc; -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError}; -use rustc_lexer::Base; -use rustc_lexer::{unescape, RawStrError}; +use rustc_ast::tokenstream::{Spacing, TokenStream}; +use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult}; +use rustc_lexer::unescape::{self, Mode}; +use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Pos, Span}; -use std::char; use tracing::debug; mod tokentrees; mod unescape_error_reporting; mod unicode_chars; -use rustc_lexer::{unescape::Mode, DocStyle}; use unescape_error_reporting::{emit_unescape_error, push_escaped_char}; #[derive(Clone, Debug)] @@ -27,7 +25,17 @@ pub struct UnmatchedBrace { pub candidate_span: Option, } -pub struct StringReader<'a> { +crate fn parse_token_trees<'a>( + sess: &'a ParseSess, + src: &'a str, + start_pos: BytePos, + override_span: Option, +) -> (PResult<'a, TokenStream>, Vec) { + StringReader { sess, start_pos, pos: start_pos, end_src_index: src.len(), src, override_span } + .into_token_trees() +} + +struct StringReader<'a> { sess: &'a ParseSess, /// Initial position, read-only. start_pos: BytePos, @@ -36,97 +44,55 @@ pub struct StringReader<'a> { /// Stop reading src at this index. end_src_index: usize, /// Source text to tokenize. - src: Lrc, + src: &'a str, override_span: Option, } impl<'a> StringReader<'a> { - pub fn new( - sess: &'a ParseSess, - source_file: Lrc, - override_span: Option, - ) -> Self { - // Make sure external source is loaded first, before accessing it. - // While this can't show up during normal parsing, `retokenize` may - // be called with a source file from an external crate. - sess.source_map().ensure_source_file_source_present(Lrc::clone(&source_file)); - - let src = if let Some(src) = &source_file.src { - Lrc::clone(&src) - } else if let Some(src) = source_file.external_src.borrow().get_source() { - Lrc::clone(&src) - } else { - sess.span_diagnostic - .bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); - }; - - StringReader { - sess, - start_pos: source_file.start_pos, - pos: source_file.start_pos, - end_src_index: src.len(), - src, - override_span, - } - } - - pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self { - let begin = sess.source_map().lookup_byte_offset(span.lo()); - let end = sess.source_map().lookup_byte_offset(span.hi()); - - // Make the range zero-length if the span is invalid. - if begin.sf.start_pos != end.sf.start_pos { - span = span.shrink_to_lo(); - } - - let mut sr = StringReader::new(sess, begin.sf, None); - - // Seek the lexer to the right byte range. - sr.end_src_index = sr.src_index(span.hi()); - - sr - } - fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span { self.override_span.unwrap_or_else(|| Span::with_root_ctxt(lo, hi)) } - /// Returns the next token, including trivia like whitespace or comments. - pub fn next_token(&mut self) -> Token { + /// Returns the next token, and info about preceding whitespace, if any. + fn next_token(&mut self) -> (Spacing, Token) { + let mut spacing = Spacing::Joint; + + // Skip `#!` at the start of the file let start_src_index = self.src_index(self.pos); let text: &str = &self.src[start_src_index..self.end_src_index]; - - if text.is_empty() { - let span = self.mk_sp(self.pos, self.pos); - return Token::new(token::Eof, span); + let is_beginning_of_file = self.pos == self.start_pos; + if is_beginning_of_file { + if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { + self.pos = self.pos + BytePos::from_usize(shebang_len); + spacing = Spacing::Alone; + } } - { - let is_beginning_of_file = self.pos == self.start_pos; - if is_beginning_of_file { - if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { - let start = self.pos; - self.pos = self.pos + BytePos::from_usize(shebang_len); + // Skip trivial (whitespace & comments) tokens + loop { + let start_src_index = self.src_index(self.pos); + let text: &str = &self.src[start_src_index..self.end_src_index]; - let sym = self.symbol_from(start + BytePos::from_usize("#!".len())); - let kind = token::Shebang(sym); - - let span = self.mk_sp(start, self.pos); - return Token::new(kind, span); - } + if text.is_empty() { + let span = self.mk_sp(self.pos, self.pos); + return (spacing, Token::new(token::Eof, span)); } - } - let token = rustc_lexer::first_token(text); + let token = rustc_lexer::first_token(text); - let start = self.pos; - self.pos = self.pos + BytePos::from_usize(token.len); + let start = self.pos; + self.pos = self.pos + BytePos::from_usize(token.len); - debug!("try_next_token: {:?}({:?})", token.kind, self.str_from(start)); + debug!("next_token: {:?}({:?})", token.kind, self.str_from(start)); - let kind = self.cook_lexer_token(token.kind, start); - let span = self.mk_sp(start, self.pos); - Token::new(kind, span) + match self.cook_lexer_token(token.kind, start) { + Some(kind) => { + let span = self.mk_sp(start, self.pos); + return (spacing, Token::new(kind, span)); + } + None => spacing = Spacing::Alone, + } + } } /// Report a fatal lexical error with a given span. @@ -166,19 +132,16 @@ impl<'a> StringReader<'a> { /// Turns simple `rustc_lexer::TokenKind` enum into a rich /// `librustc_ast::TokenKind`. This turns strings into interned /// symbols and runs additional validation. - fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> TokenKind { - match token { + fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Option { + Some(match token { rustc_lexer::TokenKind::LineComment { doc_style } => { - match doc_style { - Some(doc_style) => { - // Opening delimiter of the length 3 is not included into the symbol. - let content_start = start + BytePos(3); - let content = self.str_from(content_start); + // Skip non-doc comments + let doc_style = doc_style?; - self.cook_doc_comment(content_start, content, CommentKind::Line, doc_style) - } - None => token::Comment, - } + // Opening delimiter of the length 3 is not included into the symbol. + let content_start = start + BytePos(3); + let content = self.str_from(content_start); + self.cook_doc_comment(content_start, content, CommentKind::Line, doc_style) } rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => { if !terminated { @@ -197,20 +160,18 @@ impl<'a> StringReader<'a> { .emit(); FatalError.raise(); } - match doc_style { - Some(doc_style) => { - // Opening delimiter of the length 3 and closing delimiter of the length 2 - // are not included into the symbol. - let content_start = start + BytePos(3); - let content_end = self.pos - BytePos(if terminated { 2 } else { 0 }); - let content = self.str_from_to(content_start, content_end); - - self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style) - } - None => token::Comment, - } + + // Skip non-doc comments + let doc_style = doc_style?; + + // Opening delimiter of the length 3 and closing delimiter of the length 2 + // are not included into the symbol. + let content_start = start + BytePos(3); + let content_end = self.pos - BytePos(if terminated { 2 } else { 0 }); + let content = self.str_from_to(content_start, content_end); + self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style) } - rustc_lexer::TokenKind::Whitespace => token::Whitespace, + rustc_lexer::TokenKind::Whitespace => return None, rustc_lexer::TokenKind::Ident | rustc_lexer::TokenKind::RawIdent => { let is_raw_ident = token == rustc_lexer::TokenKind::RawIdent; let mut ident_start = start; @@ -308,12 +269,11 @@ impl<'a> StringReader<'a> { // this should be inside `rustc_lexer`. However, we should first remove compound // tokens like `<<` from `rustc_lexer`, and then add fancier error recovery to it, // as there will be less overall work to do this way. - let token = unicode_chars::check_for_substitution(self, start, c, &mut err) - .unwrap_or_else(|| token::Unknown(self.symbol_from(start))); + let token = unicode_chars::check_for_substitution(self, start, c, &mut err); err.emit(); - token + token? } - } + }) } fn cook_doc_comment( @@ -465,10 +425,6 @@ impl<'a> StringReader<'a> { (lit_kind, id) } - pub fn pos(&self) -> BytePos { - self.pos - } - #[inline] fn src_index(&self, pos: BytePos) -> usize { (pos - self.start_pos).to_usize() @@ -480,12 +436,6 @@ impl<'a> StringReader<'a> { self.str_from_to(start, self.pos) } - /// Creates a Symbol from a given offset to the current offset. - fn symbol_from(&self, start: BytePos) -> Symbol { - debug!("taking an ident from {:?} to {:?}", start, self.pos); - Symbol::intern(self.str_from(start)) - } - /// As symbol_from, with an explicit endpoint. fn symbol_from_to(&self, start: BytePos, end: BytePos) -> Symbol { debug!("taking an ident from {:?} to {:?}", start, end); diff --git a/src/librustc_parse/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs similarity index 89% rename from src/librustc_parse/lexer/tokentrees.rs rename to compiler/rustc_parse/src/lexer/tokentrees.rs index c08659ec9f..6233549dc8 100644 --- a/src/librustc_parse/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -3,8 +3,8 @@ use super::{StringReader, UnmatchedBrace}; use rustc_ast::token::{self, DelimToken, Token}; use rustc_ast::tokenstream::{ DelimSpan, - IsJoint::{self, *}, - TokenStream, TokenTree, TreeAndJoint, + Spacing::{self, *}, + TokenStream, TokenTree, TreeAndSpacing, }; use rustc_ast_pretty::pprust::token_to_string; use rustc_data_structures::fx::FxHashMap; @@ -12,11 +12,10 @@ use rustc_errors::PResult; use rustc_span::Span; impl<'a> StringReader<'a> { - crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { + pub(super) fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { let mut tt_reader = TokenTreesReader { string_reader: self, token: Token::dummy(), - joint_to_prev: Joint, open_braces: Vec::new(), unmatched_braces: Vec::new(), matching_delim_spans: Vec::new(), @@ -32,7 +31,6 @@ impl<'a> StringReader<'a> { struct TokenTreesReader<'a> { string_reader: StringReader<'a>, token: Token, - joint_to_prev: IsJoint, /// Stack of open delimiters and their spans. Used for error message. open_braces: Vec<(token::DelimToken, Span)>, unmatched_braces: Vec, @@ -53,7 +51,7 @@ impl<'a> TokenTreesReader<'a> { fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { let mut buf = TokenStreamBuilder::default(); - self.real_token(); + self.bump(); while self.token != token::Eof { buf.push(self.parse_token_tree()?); } @@ -79,7 +77,7 @@ impl<'a> TokenTreesReader<'a> { } } - fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> { + fn parse_token_tree(&mut self) -> PResult<'a, TreeAndSpacing> { let sm = self.string_reader.sess.source_map(); match self.token.kind { @@ -126,7 +124,7 @@ impl<'a> TokenTreesReader<'a> { // Parse the open delimiter. self.open_braces.push((delim, self.token.span)); - self.real_token(); + self.bump(); // Parse the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user @@ -151,12 +149,9 @@ impl<'a> TokenTreesReader<'a> { } } - match (open_brace, delim) { - //only add braces - (DelimToken::Brace, DelimToken::Brace) => { - self.matching_block_spans.push((open_brace_span, close_brace_span)); - } - _ => {} + //only add braces + if let (DelimToken::Brace, DelimToken::Brace) = (open_brace, delim) { + self.matching_block_spans.push((open_brace_span, close_brace_span)); } if self.open_braces.is_empty() { @@ -171,7 +166,7 @@ impl<'a> TokenTreesReader<'a> { )); } // Parse the closing delimiter. - self.real_token(); + self.bump(); } // Incorrect delimiter. token::CloseDelim(other) => { @@ -217,7 +212,7 @@ impl<'a> TokenTreesReader<'a> { // bar(baz( // } // Incorrect delimiter but matches the earlier `{` if !self.open_braces.iter().any(|&(b, _)| b == other) { - self.real_token(); + self.bump(); } } token::Eof => { @@ -264,37 +259,29 @@ impl<'a> TokenTreesReader<'a> { } _ => { let tt = TokenTree::Token(self.token.take()); - self.real_token(); - let is_joint = self.joint_to_prev == Joint && self.token.is_op(); - Ok((tt, if is_joint { Joint } else { NonJoint })) + let mut spacing = self.bump(); + if !self.token.is_op() { + spacing = Alone; + } + Ok((tt, spacing)) } } } - fn real_token(&mut self) { - self.joint_to_prev = Joint; - loop { - let token = self.string_reader.next_token(); - match token.kind { - token::Whitespace | token::Comment | token::Shebang(_) | token::Unknown(_) => { - self.joint_to_prev = NonJoint; - } - _ => { - self.token = token; - return; - } - } - } + fn bump(&mut self) -> Spacing { + let (spacing, token) = self.string_reader.next_token(); + self.token = token; + spacing } } #[derive(Default)] struct TokenStreamBuilder { - buf: Vec, + buf: Vec, } impl TokenStreamBuilder { - fn push(&mut self, (tree, joint): TreeAndJoint) { + fn push(&mut self, (tree, joint): TreeAndSpacing) { if let Some((TokenTree::Token(prev_token), Joint)) = self.buf.last() { if let TokenTree::Token(token) = &tree { if let Some(glued) = prev_token.glue(token) { diff --git a/src/librustc_parse/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs similarity index 100% rename from src/librustc_parse/lexer/unescape_error_reporting.rs rename to compiler/rustc_parse/src/lexer/unescape_error_reporting.rs diff --git a/src/librustc_parse/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs similarity index 99% rename from src/librustc_parse/lexer/unicode_chars.rs rename to compiler/rustc_parse/src/lexer/unicode_chars.rs index ac395f6cbc..40e2e34aa0 100644 --- a/src/librustc_parse/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -303,7 +303,7 @@ const UNICODE_ARRAY: &[(char, &str, char)] = &[ // However, we should first remove compound tokens like `<<` from `rustc_lexer`, and then add // fancier error recovery to it, as there will be less overall work to do this way. const ASCII_ARRAY: &[(char, &str, Option)] = &[ - (' ', "Space", Some(token::Whitespace)), + (' ', "Space", None), ('_', "Underscore", Some(token::Ident(kw::Underscore, false))), ('-', "Minus/Hyphen", Some(token::BinOp(token::Minus))), (',', "Comma", Some(token::Comma)), @@ -332,7 +332,7 @@ const ASCII_ARRAY: &[(char, &str, Option)] = &[ ('"', "Quotation Mark", None), ]; -crate fn check_for_substitution<'a>( +pub(super) fn check_for_substitution<'a>( reader: &StringReader<'a>, pos: BytePos, ch: char, diff --git a/src/librustc_parse/lib.rs b/compiler/rustc_parse/src/lib.rs similarity index 82% rename from src/librustc_parse/lib.rs rename to compiler/rustc_parse/src/lib.rs index bc857c9774..b68d36c9a8 100644 --- a/src/librustc_parse/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,12 +3,12 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] -#![feature(try_blocks)] +#![feature(iter_order_by)] #![feature(or_patterns)] use rustc_ast as ast; -use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{self, IsJoint, TokenStream, TokenTree}; +use rustc_ast::token::{self, Nonterminal, Token, TokenKind}; +use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; @@ -109,7 +109,7 @@ pub fn maybe_new_parser_from_source_str( } /// Creates a new parser, handling errors as appropriate if the file doesn't exist. -/// If a span is given, that is used on an error as the as the source of the problem. +/// If a span is given, that is used on an error as the source of the problem. pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option) -> Parser<'a> { source_file_to_parser(sess, file_to_source_file(sess, path, sp)) } @@ -200,8 +200,13 @@ pub fn maybe_file_to_stream( source_file: Lrc, override_span: Option, ) -> Result<(TokenStream, Vec), Vec> { - let srdr = lexer::StringReader::new(sess, source_file, override_span); - let (token_trees, unmatched_braces) = srdr.into_token_trees(); + let src = source_file.src.as_ref().unwrap_or_else(|| { + sess.span_diagnostic + .bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); + }); + + let (token_trees, unmatched_braces) = + lexer::parse_token_trees(sess, src.as_str(), source_file.start_pos, override_span); match token_trees { Ok(stream) => Ok((stream, unmatched_braces)), @@ -263,27 +268,38 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Nonterminal::NtItem(ref item) => { prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) } + Nonterminal::NtBlock(ref block) => block.tokens.clone(), + Nonterminal::NtStmt(ref stmt) => { + // FIXME: We currently only collect tokens for `:stmt` + // matchers in `macro_rules!` macros. When we start collecting + // tokens for attributes on statements, we will need to prepend + // attributes here + stmt.tokens.clone() + } Nonterminal::NtPat(ref pat) => pat.tokens.clone(), + Nonterminal::NtTy(ref ty) => ty.tokens.clone(), Nonterminal::NtIdent(ident, is_raw) => { Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) } Nonterminal::NtLifetime(ident) => { Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) } + Nonterminal::NtMeta(ref attr) => attr.tokens.clone(), + Nonterminal::NtPath(ref path) => path.tokens.clone(), + Nonterminal::NtVis(ref vis) => vis.tokens.clone(), Nonterminal::NtTT(ref tt) => Some(tt.clone().into()), - Nonterminal::NtExpr(ref expr) => { + Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => { if expr.tokens.is_none() { debug!("missing tokens for expr {:?}", expr); } prepend_attrs(sess, &expr.attrs, expr.tokens.as_ref(), span) } - _ => None, }; // FIXME(#43081): Avoid this pretty-print + reparse hack let source = pprust::nonterminal_to_string(nt); let filename = FileName::macro_expansion_source_code(&source); - let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span)); + let reparsed_tokens = parse_stream_from_source_str(filename, source, sess, Some(span)); // During early phases of the compiler the AST could get modified // directly (e.g., attributes added or removed) and the internal cache @@ -309,7 +325,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real, sess) { + if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess) { return tokens; } info!( @@ -317,9 +333,9 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke going with stringified version" ); info!("cached tokens: {:?}", tokens); - info!("reparsed tokens: {:?}", tokens_for_real); + info!("reparsed tokens: {:?}", reparsed_tokens); } - tokens_for_real + reparsed_tokens } // See comments in `Nonterminal::to_tokenstream` for why we care about @@ -328,8 +344,8 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. pub fn tokenstream_probably_equal_for_proc_macro( - first: &TokenStream, - other: &TokenStream, + tokens: &TokenStream, + reparsed_tokens: &TokenStream, sess: &ParseSess, ) -> bool { // When checking for `probably_eq`, we ignore certain tokens that aren't @@ -343,14 +359,14 @@ pub fn tokenstream_probably_equal_for_proc_macro( // The pretty printer tends to add trailing commas to // everything, and in particular, after struct fields. | token::Comma - // The pretty printer emits `NoDelim` as whitespace. - | token::OpenDelim(DelimToken::NoDelim) - | token::CloseDelim(DelimToken::NoDelim) // The pretty printer collapses many semicolons into one. | token::Semi - // The pretty printer collapses whitespace arbitrarily and can - // introduce whitespace from `NoDelim`. - | token::Whitespace + // We don't preserve leading `|` tokens in patterns, so + // we ignore them entirely + | token::BinOp(token::BinOpToken::Or) + // We don't preserve trailing '+' tokens in trait bounds, + // so we ignore them entirely + | token::BinOp(token::BinOpToken::Plus) // The pretty printer can turn `$crate` into `::crate_name` | token::ModSep = token.kind { return false; @@ -419,36 +435,44 @@ pub fn tokenstream_probably_equal_for_proc_macro( token_trees.into_iter() } - let expand_nt = |tree: TokenTree| { - if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree { - // When checking tokenstreams for 'probable equality', we are comparing - // a captured (from parsing) `TokenStream` to a reparsed tokenstream. - // The reparsed Tokenstream will never have `None`-delimited groups, - // since they are only ever inserted as a result of macro expansion. - // Therefore, inserting a `None`-delimtied group here (when we - // convert a nested `Nonterminal` to a tokenstream) would cause - // a mismatch with the reparsed tokenstream. - // - // Note that we currently do not handle the case where the - // reparsed stream has a `Parenthesis`-delimited group - // inserted. This will cause a spurious mismatch: - // issue #75734 tracks resolving this. - nt_to_tokenstream(nt, sess, *span).into_trees() - } else { - TokenStream::new(vec![(tree, IsJoint::NonJoint)]).into_trees() - } - }; + fn expand_token(tree: TokenTree, sess: &ParseSess) -> impl Iterator { + // When checking tokenstreams for 'probable equality', we are comparing + // a captured (from parsing) `TokenStream` to a reparsed tokenstream. + // The reparsed Tokenstream will never have `None`-delimited groups, + // since they are only ever inserted as a result of macro expansion. + // Therefore, inserting a `None`-delimtied group here (when we + // convert a nested `Nonterminal` to a tokenstream) would cause + // a mismatch with the reparsed tokenstream. + // + // Note that we currently do not handle the case where the + // reparsed stream has a `Parenthesis`-delimited group + // inserted. This will cause a spurious mismatch: + // issue #75734 tracks resolving this. + + let expanded: SmallVec<[_; 1]> = + if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree { + nt_to_tokenstream(nt, sess, *span) + .into_trees() + .flat_map(|t| expand_token(t, sess)) + .collect() + } else { + // Filter before and after breaking tokens, + // since we may want to ignore both glued and unglued tokens. + std::iter::once(tree) + .filter(semantic_tree) + .flat_map(break_tokens) + .filter(semantic_tree) + .collect() + }; + expanded.into_iter() + } // Break tokens after we expand any nonterminals, so that we break tokens // that are produced as a result of nonterminal expansion. - let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) { - return false; - } - } - t1.next().is_none() && t2.next().is_none() + let tokens = tokens.trees().flat_map(|t| expand_token(t, sess)); + let reparsed_tokens = reparsed_tokens.trees().flat_map(|t| expand_token(t, sess)); + + tokens.eq_by(reparsed_tokens, |t, rt| tokentree_probably_equal_for_proc_macro(&t, &rt, sess)) } // See comments in `Nonterminal::to_tokenstream` for why we care about @@ -457,16 +481,20 @@ pub fn tokenstream_probably_equal_for_proc_macro( // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. pub fn tokentree_probably_equal_for_proc_macro( - first: &TokenTree, - other: &TokenTree, + token: &TokenTree, + reparsed_token: &TokenTree, sess: &ParseSess, ) -> bool { - match (first, other) { - (TokenTree::Token(token), TokenTree::Token(token2)) => { - token_probably_equal_for_proc_macro(token, token2) + match (token, reparsed_token) { + (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => { + token_probably_equal_for_proc_macro(token, reparsed_token) } - (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { - delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2, sess) + ( + TokenTree::Delimited(_, delim, tokens), + TokenTree::Delimited(_, reparsed_delim, reparsed_tokens), + ) => { + delim == reparsed_delim + && tokenstream_probably_equal_for_proc_macro(tokens, reparsed_tokens, sess) } _ => false, } @@ -506,8 +534,6 @@ fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool { | (&Pound, &Pound) | (&Dollar, &Dollar) | (&Question, &Question) - | (&Whitespace, &Whitespace) - | (&Comment, &Comment) | (&Eof, &Eof) => true, (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b, @@ -516,8 +542,6 @@ fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool { (&DocComment(a1, a2, a3), &DocComment(b1, b2, b3)) => a1 == b1 && a2 == b2 && a3 == b3, - (&Shebang(a), &Shebang(b)) => a == b, - (&Literal(a), &Literal(b)) => a == b, (&Lifetime(a), &Lifetime(b)) => a == b, diff --git a/src/librustc_parse/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs similarity index 99% rename from src/librustc_parse/parser/attr.rs rename to compiler/rustc_parse/src/parser/attr.rs index 4e4429e461..98f94098bf 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -162,7 +162,7 @@ impl<'a> Parser<'a> { } else { let path = self.parse_path(PathStyle::Mod)?; let args = self.parse_attr_args()?; - ast::AttrItem { path, args } + ast::AttrItem { path, args, tokens: None } }) } diff --git a/src/librustc_parse/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs similarity index 96% rename from src/librustc_parse/parser/diagnostics.rs rename to compiler/rustc_parse/src/parser/diagnostics.rs index 12efe391fb..9ab13db4b5 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -28,7 +28,7 @@ pub(super) fn dummy_arg(ident: Ident) -> Param { span: ident.span, tokens: None, }); - let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID }; + let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None }; Param { attrs: AttrVec::default(), id: ast::DUMMY_NODE_ID, @@ -75,7 +75,12 @@ impl RecoverQPath for Ty { Some(P(self.clone())) } fn recovered(qself: Option, path: ast::Path) -> Self { - Self { span: path.span, kind: TyKind::Path(qself, path), id: ast::DUMMY_NODE_ID } + Self { + span: path.span, + kind: TyKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + tokens: None, + } } } @@ -548,6 +553,52 @@ impl<'a> Parser<'a> { } } + /// When writing a turbofish with multiple type parameters missing the leading `::`, we will + /// encounter a parse error when encountering the first `,`. + pub(super) fn check_mistyped_turbofish_with_multiple_type_params( + &mut self, + mut e: DiagnosticBuilder<'a>, + expr: &mut P, + ) -> PResult<'a, ()> { + if let ExprKind::Binary(binop, _, _) = &expr.kind { + if let ast::BinOpKind::Lt = binop.node { + if self.eat(&token::Comma) { + let x = self.parse_seq_to_before_end( + &token::Gt, + SeqSep::trailing_allowed(token::Comma), + |p| p.parse_ty(), + ); + match x { + Ok((_, _, false)) => { + self.bump(); // `>` + match self.parse_expr() { + Ok(_) => { + e.span_suggestion_verbose( + binop.span.shrink_to_lo(), + "use `::<...>` instead of `<...>` to specify type arguments", + "::".to_string(), + Applicability::MaybeIncorrect, + ); + e.emit(); + *expr = self.mk_expr_err(expr.span.to(self.prev_token.span)); + return Ok(()); + } + Err(mut err) => { + err.cancel(); + } + } + } + Err(mut err) => { + err.cancel(); + } + _ => {} + } + } + } + } + Err(e) + } + /// Check to see if a pair of chained operators looks like an attempt at chained comparison, /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or /// parenthesising the leftmost comparison. @@ -896,7 +947,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { self.expect(&token::ModSep)?; - let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP }; + let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP, tokens: None }; self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; path.span = ty_span.to(self.prev_token.span); diff --git a/src/librustc_parse/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs similarity index 98% rename from src/librustc_parse/parser/expr.rs rename to compiler/rustc_parse/src/parser/expr.rs index f022c628fe..a11ad6e89c 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{BytePos, Pos}; use std::mem; use tracing::debug; @@ -839,9 +840,10 @@ impl<'a> Parser<'a> { } use FloatComponent::*; + let float_str = float.as_str(); let mut components = Vec::new(); let mut ident_like = String::new(); - for c in float.as_str().chars() { + for c in float_str.chars() { if c == '_' || c.is_ascii_alphanumeric() { ident_like.push(c); } else if matches!(c, '.' | '+' | '-') { @@ -857,8 +859,13 @@ impl<'a> Parser<'a> { components.push(IdentLike(ident_like)); } - // FIXME: Make the span more precise. + // With proc macros the span can refer to anything, the source may be too short, + // or too long, or non-ASCII. It only makes sense to break our span into components + // if its underlying text is identical to our float literal. let span = self.token.span; + let can_take_span_apart = + || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref(); + match &*components { // 1e2 [IdentLike(i)] => { @@ -866,21 +873,40 @@ impl<'a> Parser<'a> { } // 1. [IdentLike(i), Punct('.')] => { + let (ident_span, dot_span) = if can_take_span_apart() { + let (span, ident_len) = (span.data(), BytePos::from_usize(i.len())); + let ident_span = span.with_hi(span.lo + ident_len); + let dot_span = span.with_lo(span.lo + ident_len); + (ident_span, dot_span) + } else { + (span, span) + }; assert!(suffix.is_none()); let symbol = Symbol::intern(&i); - self.token = Token::new(token::Ident(symbol, false), span); - let next_token = Token::new(token::Dot, span); + self.token = Token::new(token::Ident(symbol, false), ident_span); + let next_token = Token::new(token::Dot, dot_span); self.parse_tuple_field_access_expr(lo, base, symbol, None, Some(next_token)) } // 1.2 | 1.2e3 [IdentLike(i1), Punct('.'), IdentLike(i2)] => { + let (ident1_span, dot_span, ident2_span) = if can_take_span_apart() { + let (span, ident1_len) = (span.data(), BytePos::from_usize(i1.len())); + let ident1_span = span.with_hi(span.lo + ident1_len); + let dot_span = span + .with_lo(span.lo + ident1_len) + .with_hi(span.lo + ident1_len + BytePos(1)); + let ident2_span = self.token.span.with_lo(span.lo + ident1_len + BytePos(1)); + (ident1_span, dot_span, ident2_span) + } else { + (span, span, span) + }; let symbol1 = Symbol::intern(&i1); - self.token = Token::new(token::Ident(symbol1, false), span); - let next_token1 = Token::new(token::Dot, span); + self.token = Token::new(token::Ident(symbol1, false), ident1_span); + let next_token1 = Token::new(token::Dot, dot_span); let base1 = self.parse_tuple_field_access_expr(lo, base, symbol1, None, Some(next_token1)); let symbol2 = Symbol::intern(&i2); - let next_token2 = Token::new(token::Ident(symbol2, false), span); + let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span); self.bump_with(next_token2); // `.` self.parse_tuple_field_access_expr(lo, base1, symbol2, suffix, None) } @@ -1480,7 +1506,7 @@ impl<'a> Parser<'a> { /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. - pub(super) fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { + pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { maybe_whole_expr!(self); let lo = self.token.span; diff --git a/src/librustc_parse/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs similarity index 100% rename from src/librustc_parse/parser/generics.rs rename to compiler/rustc_parse/src/parser/generics.rs diff --git a/src/librustc_parse/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs similarity index 96% rename from src/librustc_parse/parser/item.rs rename to compiler/rustc_parse/src/parser/item.rs index 9143af651d..26ca998012 100644 --- a/src/librustc_parse/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -28,7 +28,7 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> { let lo = self.token.span; - let (module, attrs) = self.parse_mod(&token::Eof)?; + let (module, attrs) = self.parse_mod(&token::Eof, Unsafe::No)?; let span = lo.to(self.token.span); let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. Ok(ast::Crate { attrs, module, span, proc_macros }) @@ -36,27 +36,38 @@ impl<'a> Parser<'a> { /// Parses a `mod { ... }` or `mod ;` item. fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + let unsafety = self.parse_unsafety(); + self.expect_keyword(kw::Mod)?; let id = self.parse_ident()?; let (module, mut inner_attrs) = if self.eat(&token::Semi) { - Default::default() + (Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }, Vec::new()) } else { self.expect(&token::OpenDelim(token::Brace))?; - self.parse_mod(&token::CloseDelim(token::Brace))? + self.parse_mod(&token::CloseDelim(token::Brace), unsafety)? }; attrs.append(&mut inner_attrs); Ok((id, ItemKind::Mod(module))) } /// Parses the contents of a module (inner attributes followed by module items). - pub fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec)> { + pub fn parse_mod( + &mut self, + term: &TokenKind, + unsafety: Unsafe, + ) -> PResult<'a, (Mod, Vec)> { let lo = self.token.span; let attrs = self.parse_inner_attributes()?; - let module = self.parse_mod_items(term, lo)?; + let module = self.parse_mod_items(term, lo, unsafety)?; Ok((module, attrs)) } /// Given a termination token, parses all of the items in a module. - fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> { + fn parse_mod_items( + &mut self, + term: &TokenKind, + inner_lo: Span, + unsafety: Unsafe, + ) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = self.parse_item()? { items.push(item); @@ -75,7 +86,7 @@ impl<'a> Parser<'a> { let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span }; - Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) + Ok(Mod { inner: inner_lo.to(hi), unsafety, items, inline: true }) } } @@ -176,7 +187,7 @@ impl<'a> Parser<'a> { /// Error in-case a non-inherited visibility was parsed but no item followed. fn error_on_unmatched_vis(&self, vis: &Visibility) { - if let VisibilityKind::Inherited = vis.node { + if let VisibilityKind::Inherited = vis.kind { return; } let vs = pprust::vis_to_string(&vis); @@ -235,8 +246,13 @@ impl<'a> Parser<'a> { self.parse_item_extern_crate()? } else { // EXTERN BLOCK - self.parse_item_foreign_mod(attrs)? + self.parse_item_foreign_mod(attrs, Unsafe::No)? } + } else if self.is_unsafe_foreign_mod() { + // EXTERN BLOCK + let unsafety = self.parse_unsafety(); + self.expect_keyword(kw::Extern)?; + self.parse_item_foreign_mod(attrs, unsafety)? } else if self.is_static_global() { // STATIC ITEM self.bump(); // `static` @@ -256,7 +272,9 @@ impl<'a> Parser<'a> { { // IMPL ITEM self.parse_item_impl(attrs, def())? - } else if self.eat_keyword(kw::Mod) { + } else if self.check_keyword(kw::Mod) + || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod]) + { // MODULE ITEM self.parse_item_mod(attrs)? } else if self.eat_keyword(kw::Type) { @@ -278,7 +296,7 @@ impl<'a> Parser<'a> { } else if self.is_macro_rules_item() { // MACRO_RULES ITEM self.parse_item_macro_rules(vis)? - } else if vis.node.is_pub() && self.isnt_macro_invocation() { + } else if vis.kind.is_pub() && self.isnt_macro_invocation() { self.recover_missing_kw_before_item()?; return Ok(None); } else if macros_allowed && self.check_path() { @@ -492,7 +510,12 @@ impl<'a> Parser<'a> { { let span = self.prev_token.span.between(self.token.span); self.struct_span_err(span, "missing trait in a trait impl").emit(); - P(Ty { kind: TyKind::Path(None, err_path(span)), span, id: DUMMY_NODE_ID }) + P(Ty { + kind: TyKind::Path(None, err_path(span)), + span, + id: DUMMY_NODE_ID, + tokens: None, + }) } else { self.parse_ty()? }; @@ -764,7 +787,7 @@ impl<'a> Parser<'a> { fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { let lo = self.token.span; - let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo() }; + let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo(), tokens: None }; let kind = if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() @@ -893,10 +916,14 @@ impl<'a> Parser<'a> { /// extern "C" {} /// extern {} /// ``` - fn parse_item_foreign_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + fn parse_item_foreign_mod( + &mut self, + attrs: &mut Vec, + unsafety: Unsafe, + ) -> PResult<'a, ItemInfo> { let abi = self.parse_abi(); // ABI? let items = self.parse_item_list(attrs, |p| p.parse_foreign_item())?; - let module = ast::ForeignMod { abi, items }; + let module = ast::ForeignMod { unsafety, abi, items }; Ok((Ident::invalid(), ItemKind::ForeignMod(module))) } @@ -938,6 +965,15 @@ impl<'a> Parser<'a> { .emit(); } + fn is_unsafe_foreign_mod(&self) -> bool { + self.token.is_keyword(kw::Unsafe) + && self.is_keyword_ahead(1, &[kw::Extern]) + && self.look_ahead( + 2 + self.look_ahead(2, |t| t.can_begin_literal_maybe_minus() as usize), + |t| t.kind == token::OpenDelim(token::Brace), + ) + } + fn is_static_global(&mut self) -> bool { if self.check_keyword(kw::Static) { // Check if this could be a closure. @@ -1015,7 +1051,7 @@ impl<'a> Parser<'a> { // The user intended that the type be inferred, // so treat this as if the user wrote e.g. `const A: _ = expr;`. - P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID }) + P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID, tokens: None }) } /// Parses an enum declaration. @@ -1382,7 +1418,7 @@ impl<'a> Parser<'a> { /// Item macro invocations or `macro_rules!` definitions need inherited visibility. /// If that's not the case, emit an error. fn complain_if_pub_macro(&self, vis: &Visibility, macro_rules: bool) { - if let VisibilityKind::Inherited = vis.node { + if let VisibilityKind::Inherited = vis.kind { return; } @@ -1552,10 +1588,14 @@ impl<'a> Parser<'a> { // `$qual fn` or `$qual $qual`: || QUALS.iter().any(|&kw| self.check_keyword(kw)) && self.look_ahead(1, |t| { - // ...qualified and then `fn`, e.g. `const fn`. + // `$qual fn`, e.g. `const fn` or `async fn`. t.is_keyword(kw::Fn) - // Two qualifiers. This is enough. Due `async` we need to check that it's reserved. - || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) && i.is_reserved()) + // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`. + || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) + // Rule out 2015 `const async: T = val`. + && i.is_reserved() + // Rule out unsafe extern block. + && !self.is_unsafe_foreign_mod()) }) // `extern ABI fn` || self.check_keyword(kw::Extern) @@ -1567,9 +1607,9 @@ impl<'a> Parser<'a> { /// up to and including the `fn` keyword. The formal grammar is: /// /// ``` - /// Extern = "extern" StringLit ; + /// Extern = "extern" StringLit? ; /// FnQual = "const"? "async"? "unsafe"? Extern? ; - /// FnFrontMatter = FnQual? "fn" ; + /// FnFrontMatter = FnQual "fn" ; /// ``` pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { let constness = self.parse_constness(); diff --git a/src/librustc_parse/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs similarity index 96% rename from src/librustc_parse/parser/mod.rs rename to compiler/rustc_parse/src/parser/mod.rs index 8803e3add4..7340c57448 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -15,14 +15,14 @@ pub use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; -use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint}; +use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; use rustc_ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_session::parse::ParseSess; -use rustc_span::source_map::{respan, Span, DUMMY_SP}; +use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use tracing::debug; @@ -118,7 +118,7 @@ impl<'a> Drop for Parser<'a> { struct TokenCursor { frame: TokenCursorFrame, stack: Vec, - cur_token: Option, + cur_token: Option, collecting: Option, } @@ -136,7 +136,7 @@ struct TokenCursorFrame { struct Collecting { /// Holds the current tokens captured during the most /// recent call to `collect_tokens` - buf: Vec, + buf: Vec, /// The depth of the `TokenCursor` stack at the time /// collection was started. When we encounter a `TokenTree::Delimited`, /// we want to record the `TokenTree::Delimited` itself, @@ -167,7 +167,7 @@ impl TokenCursor { let tree = if !self.frame.open_delim { self.frame.open_delim = true; TokenTree::open_tt(self.frame.span, self.frame.delim).into() - } else if let Some(tree) = self.frame.tree_cursor.next_with_joint() { + } else if let Some(tree) = self.frame.tree_cursor.next_with_spacing() { tree } else if !self.frame.close_delim { self.frame.close_delim = true; @@ -1018,21 +1018,30 @@ impl<'a> Parser<'a> { /// If the following element can't be a tuple (i.e., it's a function definition), then /// it's not a tuple struct field), and the contents within the parentheses isn't valid, /// so emit a proper diagnostic. - pub(crate) fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> { + // Public for rustfmt usage. + pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> { maybe_whole!(self, NtVis, |x| x); self.expected_tokens.push(TokenType::Keyword(kw::Crate)); if self.is_crate_vis() { self.bump(); // `crate` self.sess.gated_spans.gate(sym::crate_visibility_modifier, self.prev_token.span); - return Ok(respan(self.prev_token.span, VisibilityKind::Crate(CrateSugar::JustCrate))); + return Ok(Visibility { + span: self.prev_token.span, + kind: VisibilityKind::Crate(CrateSugar::JustCrate), + tokens: None, + }); } if !self.eat_keyword(kw::Pub) { // We need a span for our `Spanned`, but there's inherently no // keyword to grab a span from for inherited visibility; an empty span at the // beginning of the current token would seem to be the "Schelling span". - return Ok(respan(self.token.span.shrink_to_lo(), VisibilityKind::Inherited)); + return Ok(Visibility { + span: self.token.span.shrink_to_lo(), + kind: VisibilityKind::Inherited, + tokens: None, + }); } let lo = self.prev_token.span; @@ -1049,7 +1058,11 @@ impl<'a> Parser<'a> { self.bump(); // `crate` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = VisibilityKind::Crate(CrateSugar::PubCrate); - return Ok(respan(lo.to(self.prev_token.span), vis)); + return Ok(Visibility { + span: lo.to(self.prev_token.span), + kind: vis, + tokens: None, + }); } else if self.is_keyword_ahead(1, &[kw::In]) { // Parse `pub(in path)`. self.bump(); // `(` @@ -1057,7 +1070,11 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; - return Ok(respan(lo.to(self.prev_token.span), vis)); + return Ok(Visibility { + span: lo.to(self.prev_token.span), + kind: vis, + tokens: None, + }); } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) { @@ -1066,7 +1083,11 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; - return Ok(respan(lo.to(self.prev_token.span), vis)); + return Ok(Visibility { + span: lo.to(self.prev_token.span), + kind: vis, + tokens: None, + }); } else if let FollowedByType::No = fbt { // Provide this diagnostic if a type cannot follow; // in particular, if this is not a tuple struct. @@ -1075,7 +1096,7 @@ impl<'a> Parser<'a> { } } - Ok(respan(lo, VisibilityKind::Public)) + Ok(Visibility { span: lo, kind: VisibilityKind::Public, tokens: None }) } /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` @@ -1157,7 +1178,7 @@ impl<'a> Parser<'a> { f: impl FnOnce(&mut Self) -> PResult<'a, R>, ) -> PResult<'a, (R, TokenStream)> { // Record all tokens we parse when parsing this item. - let tokens: Vec = self.token_cursor.cur_token.clone().into_iter().collect(); + let tokens: Vec = self.token_cursor.cur_token.clone().into_iter().collect(); debug!("collect_tokens: starting with {:?}", tokens); // We need special handling for the case where `collect_tokens` is called @@ -1237,6 +1258,10 @@ impl<'a> Parser<'a> { *t == token::OpenDelim(token::Brace) || *t == token::BinOp(token::Star) }) } + + pub fn clear_expected_tokens(&mut self) { + self.expected_tokens.clear(); + } } crate fn make_unclosed_delims_error( diff --git a/src/librustc_parse/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs similarity index 72% rename from src/librustc_parse/parser/nonterminal.rs rename to compiler/rustc_parse/src/parser/nonterminal.rs index f40cd1131d..15660fd574 100644 --- a/src/librustc_parse/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -111,11 +111,28 @@ impl<'a> Parser<'a> { return Err(self.struct_span_err(self.token.span, "expected an item keyword")); } }, - NonterminalKind::Block => token::NtBlock(self.parse_block()?), - NonterminalKind::Stmt => match self.parse_stmt()? { - Some(s) => token::NtStmt(s), - None => return Err(self.struct_span_err(self.token.span, "expected a statement")), - }, + NonterminalKind::Block => { + let (mut block, tokens) = self.collect_tokens(|this| this.parse_block())?; + // We have have eaten an NtBlock, which could already have tokens + if block.tokens.is_none() { + block.tokens = Some(tokens); + } + token::NtBlock(block) + } + NonterminalKind::Stmt => { + let (stmt, tokens) = self.collect_tokens(|this| this.parse_stmt())?; + match stmt { + Some(mut s) => { + if s.tokens.is_none() { + s.tokens = Some(tokens); + } + token::NtStmt(s) + } + None => { + return Err(self.struct_span_err(self.token.span, "expected a statement")); + } + } + } NonterminalKind::Pat => { let (mut pat, tokens) = self.collect_tokens(|this| this.parse_pat(None))?; // We have have eaten an NtPat, which could already have tokens @@ -133,8 +150,23 @@ impl<'a> Parser<'a> { } token::NtExpr(expr) } - NonterminalKind::Literal => token::NtLiteral(self.parse_literal_maybe_minus()?), - NonterminalKind::Ty => token::NtTy(self.parse_ty()?), + NonterminalKind::Literal => { + let (mut lit, tokens) = + self.collect_tokens(|this| this.parse_literal_maybe_minus())?; + // We have have eaten a nonterminal, which could already have tokens + if lit.tokens.is_none() { + lit.tokens = Some(tokens); + } + token::NtLiteral(lit) + } + NonterminalKind::Ty => { + let (mut ty, tokens) = self.collect_tokens(|this| this.parse_ty())?; + // We have an eaten an NtTy, which could already have tokens + if ty.tokens.is_none() { + ty.tokens = Some(tokens); + } + token::NtTy(ty) + } // this could be handled like a token, since it is one NonterminalKind::Ident => { if let Some((ident, is_raw)) = get_macro_ident(&self.token) { @@ -146,10 +178,33 @@ impl<'a> Parser<'a> { return Err(self.struct_span_err(self.token.span, msg)); } } - NonterminalKind::Path => token::NtPath(self.parse_path(PathStyle::Type)?), - NonterminalKind::Meta => token::NtMeta(P(self.parse_attr_item()?)), + NonterminalKind::Path => { + let (mut path, tokens) = + self.collect_tokens(|this| this.parse_path(PathStyle::Type))?; + // We have have eaten an NtPath, which could already have tokens + if path.tokens.is_none() { + path.tokens = Some(tokens); + } + token::NtPath(path) + } + NonterminalKind::Meta => { + let (mut attr, tokens) = self.collect_tokens(|this| this.parse_attr_item())?; + // We may have eaten a nonterminal, which could already have tokens + if attr.tokens.is_none() { + attr.tokens = Some(tokens); + } + token::NtMeta(P(attr)) + } NonterminalKind::TT => token::NtTT(self.parse_token_tree()), - NonterminalKind::Vis => token::NtVis(self.parse_visibility(FollowedByType::Yes)?), + NonterminalKind::Vis => { + let (mut vis, tokens) = + self.collect_tokens(|this| this.parse_visibility(FollowedByType::Yes))?; + // We may have etan an `NtVis`, which could already have tokens + if vis.tokens.is_none() { + vis.tokens = Some(tokens); + } + token::NtVis(vis) + } NonterminalKind::Lifetime => { if self.check_lifetime() { token::NtLifetime(self.expect_lifetime().ident) diff --git a/src/librustc_parse/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs similarity index 99% rename from src/librustc_parse/parser/pat.rs rename to compiler/rustc_parse/src/parser/pat.rs index 2c0133a24d..5aced9dc37 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -795,6 +795,7 @@ impl<'a> Parser<'a> { } self.bump(); let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| { + e.span_label(path.span, "while parsing the fields for this pattern"); e.emit(); self.recover_stmt(); (vec![], true) @@ -844,7 +845,7 @@ impl<'a> Parser<'a> { // check that a comma comes after every field if !ate_comma { - let err = self.struct_span_err(self.prev_token.span, "expected `,`"); + let err = self.struct_span_err(self.token.span, "expected `,`"); if let Some(mut delayed) = delayed_err { delayed.emit(); } diff --git a/src/librustc_parse/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs similarity index 98% rename from src/librustc_parse/parser/path.rs rename to compiler/rustc_parse/src/parser/path.rs index 54b4df8613..66ce015d02 100644 --- a/src/librustc_parse/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -64,7 +64,7 @@ impl<'a> Parser<'a> { path_span = path_lo.to(self.prev_token.span); } else { path_span = self.token.span.to(self.token.span); - path = ast::Path { segments: Vec::new(), span: path_span }; + path = ast::Path { segments: Vec::new(), span: path_span, tokens: None }; } // See doc comment for `unmatched_angle_bracket_count`. @@ -81,7 +81,10 @@ impl<'a> Parser<'a> { let qself = QSelf { ty, path_span, position: path.segments.len() }; self.parse_path_segments(&mut path.segments, style)?; - Ok((qself, Path { segments: path.segments, span: lo.to(self.prev_token.span) })) + Ok(( + qself, + Path { segments: path.segments, span: lo.to(self.prev_token.span), tokens: None }, + )) } /// Recover from an invalid single colon, when the user likely meant a qualified path. @@ -144,7 +147,7 @@ impl<'a> Parser<'a> { } self.parse_path_segments(&mut segments, style)?; - Ok(Path { segments, span: lo.to(self.prev_token.span) }) + Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None }) } pub(super) fn parse_path_segments( diff --git a/src/librustc_parse/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs similarity index 92% rename from src/librustc_parse/parser/stmt.rs rename to compiler/rustc_parse/src/parser/stmt.rs index ac067cb0ea..fd1c6b25ae 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -10,7 +10,7 @@ use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; use rustc_ast::util::classify; -use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacStmtStyle}; +use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle}; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID}; use rustc_errors::{Applicability, PResult}; use rustc_span::source_map::{BytePos, Span}; @@ -21,7 +21,8 @@ use std::mem; impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. - pub(super) fn parse_stmt(&mut self) -> PResult<'a, Option> { + // Public for rustfmt usage. + pub fn parse_stmt(&mut self) -> PResult<'a, Option> { Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); @@ -106,7 +107,7 @@ impl<'a> Parser<'a> { let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { - StmtKind::MacCall(P((mac, style, attrs))) + StmtKind::MacCall(P(MacCallStmt { mac, style, attrs })) } else { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); @@ -363,7 +364,7 @@ impl<'a> Parser<'a> { let mut eat_semi = true; match stmt.kind { // Expression without semicolon. - StmtKind::Expr(ref expr) + StmtKind::Expr(ref mut expr) if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { // Just check for errors and recover; do not eat semicolon yet. @@ -387,15 +388,29 @@ impl<'a> Parser<'a> { ); } } - e.emit(); - self.recover_stmt(); + if let Err(mut e) = + self.check_mistyped_turbofish_with_multiple_type_params(e, expr) + { + e.emit(); + self.recover_stmt(); + } // Don't complain about type errors in body tail after parse error (#57383). let sp = expr.span.to(self.prev_token.span); - stmt.kind = StmtKind::Expr(self.mk_expr_err(sp)); + *expr = self.mk_expr_err(sp); } } - StmtKind::Local(..) => { - self.expect_semi()?; + StmtKind::Local(ref mut local) => { + if let Err(e) = self.expect_semi() { + // We might be at the `,` in `let x = foo;`. Try to recover. + match &mut local.init { + Some(ref mut expr) => { + self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?; + // We found `foo`, have we fully recovered? + self.expect_semi()?; + } + None => return Err(e), + } + } eat_semi = false; } StmtKind::Empty => eat_semi = false, @@ -410,11 +425,11 @@ impl<'a> Parser<'a> { } pub(super) fn mk_block(&self, stmts: Vec, rules: BlockCheckMode, span: Span) -> P { - P(Block { stmts, id: DUMMY_NODE_ID, rules, span }) + P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None }) } pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { - Stmt { id: DUMMY_NODE_ID, kind, span } + Stmt { id: DUMMY_NODE_ID, kind, span, tokens: None } } fn mk_stmt_err(&self, span: Span) -> Stmt { diff --git a/src/librustc_parse/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs similarity index 94% rename from src/librustc_parse/parser/ty.rs rename to compiler/rustc_parse/src/parser/ty.rs index 4356850818..d42a786a18 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -67,7 +67,7 @@ impl<'a> Parser<'a> { /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` - /// (`CVarArgs`) at the top level of the the type. + /// (`CVarArgs`) at the top level of the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes) } @@ -276,8 +276,34 @@ impl<'a> Parser<'a> { } fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; + let and_span = self.prev_token.span; + let mut opt_lifetime = + if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; let mutbl = self.parse_mutability(); + if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() { + // A lifetime is invalid here: it would be part of a bare trait bound, which requires + // it to be followed by a plus, but we disallow plus in the pointee type. + // So we can handle this case as an error here, and suggest `'a mut`. + // If there *is* a plus next though, handling the error later provides better suggestions + // (like adding parentheses) + if !self.look_ahead(1, |t| t.is_like_plus()) { + let lifetime_span = self.token.span; + let span = and_span.to(lifetime_span); + + let mut err = self.struct_span_err(span, "lifetime must precede `mut`"); + if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) { + err.span_suggestion( + span, + "place the lifetime before `mut`", + format!("&{} mut", lifetime_src), + Applicability::MaybeIncorrect, + ); + } + err.emit(); + + opt_lifetime = Some(self.expect_lifetime()); + } + } let ty = self.parse_ty_no_plus()?; Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })) } @@ -626,6 +652,6 @@ impl<'a> Parser<'a> { } pub(super) fn mk_ty(&self, span: Span, kind: TyKind) -> P { - P(Ty { kind, span, id: ast::DUMMY_NODE_ID }) + P(Ty { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) } } diff --git a/src/librustc_parse/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs similarity index 100% rename from src/librustc_parse/validate_attr.rs rename to compiler/rustc_parse/src/validate_attr.rs diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml new file mode 100644 index 0000000000..c2317d91a6 --- /dev/null +++ b/compiler/rustc_parse_format/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_parse_format" +version = "0.0.0" +edition = "2018" + +[dependencies] +rustc_span = { path = "../rustc_span" } +rustc_lexer = { path = "../rustc_lexer" } diff --git a/src/librustc_parse_format/lib.rs b/compiler/rustc_parse_format/src/lib.rs similarity index 98% rename from src/librustc_parse_format/lib.rs rename to compiler/rustc_parse_format/src/lib.rs index ebb3aa3866..25e3e67e28 100644 --- a/src/librustc_parse_format/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -5,14 +5,12 @@ //! generated instead. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] #![feature(nll)] #![feature(or_patterns)] -#![feature(rustc_private)] -#![feature(unicode_internals)] #![feature(bool_to_option)] pub use Alignment::*; @@ -527,12 +525,9 @@ impl<'a> Parser<'a> { // fill character if let Some(&(_, c)) = self.cur.peek() { - match self.cur.clone().nth(1) { - Some((_, '>' | '<' | '^')) => { - spec.fill = Some(c); - self.cur.next(); - } - _ => {} + if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) { + spec.fill = Some(c); + self.cur.next(); } } // Alignment @@ -760,7 +755,7 @@ fn find_skips_from_snippet( (' ' | '\n' | '\t', _) if eat_ws => { skips.push(pos); } - ('\\', Some((next_pos, 'n' | 't' | '0' | '\\' | '\'' | '\"'))) => { + ('\\', Some((next_pos, 'n' | 't' | 'r' | '0' | '\\' | '\'' | '\"'))) => { skips.push(*next_pos); let _ = s.next(); } diff --git a/src/librustc_parse_format/tests.rs b/compiler/rustc_parse_format/src/tests.rs similarity index 100% rename from src/librustc_parse_format/tests.rs rename to compiler/rustc_parse_format/src/tests.rs diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml new file mode 100644 index 0000000000..df6667a29d --- /dev/null +++ b/compiler/rustc_passes/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_passes" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_session = { path = "../rustc_session" } +rustc_target = { path = "../rustc_target" } +rustc_ast = { path = "../rustc_ast" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_passes/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs similarity index 56% rename from src/librustc_passes/check_attr.rs rename to compiler/rustc_passes/src/check_attr.rs index 832cde86d0..b52216c45c 100644 --- a/src/librustc_passes/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,12 +8,12 @@ use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_ast::{Attribute, NestedMetaItem}; -use rustc_errors::struct_span_err; +use rustc_ast::{Attribute, LitKind, NestedMetaItem}; +use rustc_errors::{pluralize, struct_span_err}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{self, HirId, Item, ItemKind, TraitItem}; +use rustc_hir::{self, FnSig, ForeignItem, ForeignItemKind, HirId, Item, ItemKind, TraitItem}; use rustc_hir::{MethodKind, Target}; use rustc_session::lint::builtin::{CONFLICTING_REPR_HINTS, UNUSED_ATTRIBUTES}; use rustc_session::parse::feature_err; @@ -43,6 +43,12 @@ pub(crate) fn target_from_impl_item<'tcx>( } } +#[derive(Clone, Copy)] +enum ItemLike<'tcx> { + Item(&'tcx Item<'tcx>), + ForeignItem(&'tcx ForeignItem<'tcx>), +} + struct CheckAttrVisitor<'tcx> { tcx: TyCtxt<'tcx>, } @@ -55,7 +61,7 @@ impl CheckAttrVisitor<'tcx> { attrs: &'hir [Attribute], span: &Span, target: Target, - item: Option<&Item<'_>>, + item: Option>, ) { let mut is_valid = true; for attr in attrs { @@ -66,12 +72,28 @@ impl CheckAttrVisitor<'tcx> { } else if self.tcx.sess.check_name(attr, sym::marker) { self.check_marker(attr, span, target) } else if self.tcx.sess.check_name(attr, sym::target_feature) { - self.check_target_feature(attr, span, target) + self.check_target_feature(hir_id, attr, span, target) } else if self.tcx.sess.check_name(attr, sym::track_caller) { self.check_track_caller(&attr.span, attrs, span, target) } else if self.tcx.sess.check_name(attr, sym::doc) { self.check_doc_alias(attr, hir_id, target) + } else if self.tcx.sess.check_name(attr, sym::no_link) { + self.check_no_link(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::export_name) { + self.check_export_name(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) { + self.check_rustc_args_required_const(&attr, span, target, item) } else { + // lint-only checks + if self.tcx.sess.check_name(attr, sym::cold) { + self.check_cold(hir_id, attr, span, target); + } else if self.tcx.sess.check_name(attr, sym::link_name) { + self.check_link_name(hir_id, attr, span, target); + } else if self.tcx.sess.check_name(attr, sym::link_section) { + self.check_link_section(hir_id, attr, span, target); + } else if self.tcx.sess.check_name(attr, sym::no_mangle) { + self.check_no_mangle(hir_id, attr, span, target); + } true }; } @@ -109,12 +131,12 @@ impl CheckAttrVisitor<'tcx> { lint.build("`#[inline]` is ignored on constants") .warn( "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", + being phased out; it will become a hard error in \ + a future release!", ) .note( "see issue #65833 \ - for more information", + for more information", ) .emit(); }); @@ -153,7 +175,7 @@ impl CheckAttrVisitor<'tcx> { .emit(); false } - Target::Fn | Target::Method(..) | Target::ForeignFn => true, + Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true, _ => { struct_span_err!( self.tcx.sess, @@ -202,10 +224,31 @@ impl CheckAttrVisitor<'tcx> { } /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid. - fn check_target_feature(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_target_feature( + &self, + hir_id: HirId, + attr: &Attribute, + span: &Span, + target: Target, + ) -> bool { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + // FIXME: #[target_feature] was previously erroneously allowed on statements and some + // crates used this, so only emit a warning. + Target::Statement => { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function") + .emit(); + }); + true + } _ => { self.tcx .sess @@ -217,23 +260,42 @@ impl CheckAttrVisitor<'tcx> { } } + fn doc_alias_str_error(&self, meta: &NestedMetaItem) { + self.tcx + .sess + .struct_span_err( + meta.span(), + "doc alias attribute expects a string: #[doc(alias = \"0\")]", + ) + .emit(); + } + fn check_doc_alias(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool { if let Some(mi) = attr.meta() { if let Some(list) = mi.meta_item_list() { for meta in list { if meta.has_name(sym::alias) { - if !meta.is_value_str() - || meta - .value_str() - .map(|s| s.to_string()) - .unwrap_or_else(String::new) - .is_empty() + if !meta.is_value_str() { + self.doc_alias_str_error(meta); + return false; + } + let doc_alias = + meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); + if doc_alias.is_empty() { + self.doc_alias_str_error(meta); + return false; + } + if let Some(c) = + doc_alias.chars().find(|&c| c == '"' || c == '\'' || c.is_whitespace()) { self.tcx .sess .struct_span_err( meta.span(), - "doc alias attribute expects a string: #[doc(alias = \"0\")]", + &format!( + "{:?} character isn't allowed in `#[doc(alias = \"...\")]`", + c, + ), ) .emit(); return false; @@ -250,15 +312,26 @@ impl CheckAttrVisitor<'tcx> { None } } + Target::AssocConst => { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + // We can't link to trait impl's consts. + let err = "associated constant in trait implementation block"; + match containing_item.kind { + ItemKind::Impl { of_trait: Some(_), .. } => Some(err), + _ => None, + } + } _ => None, } { self.tcx .sess .struct_span_err( meta.span(), - &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err,), + &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err), ) .emit(); + return false; } } } @@ -267,13 +340,208 @@ impl CheckAttrVisitor<'tcx> { true } + /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid. + fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {} + _ => { + // FIXME: #[cold] was previously allowed on non-functions and some crates used + // this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function") + .emit(); + }); + } + } + } + + /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. + fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::ForeignFn | Target::ForeignStatic => {} + _ => { + // FIXME: #[cold] was previously allowed on non-functions/statics and some crates + // used this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + let mut diag = + lint.build("attribute should be applied to a foreign function or static"); + diag.warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ); + + // See issue #47725 + if let Target::ForeignMod = target { + if let Some(value) = attr.value_str() { + diag.span_help( + attr.span, + &format!(r#"try `#[link(name = "{}")]` instead"#, value), + ); + } else { + diag.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#); + } + } + + diag.span_label(*span, "not a foreign function or static"); + diag.emit(); + }); + } + } + } + + /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid. + fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + if target == Target::ExternCrate { + true + } else { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to an `extern crate` item") + .span_label(*span, "not an `extern crate` item") + .emit(); + false + } + } + + /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid. + fn check_export_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Static | Target::Fn | Target::Method(..) => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to a function or static", + ) + .span_label(*span, "not a function or static") + .emit(); + false + } + } + } + + /// Checks if `#[rustc_args_required_const]` is applied to a function and has a valid argument. + fn check_rustc_args_required_const( + &self, + attr: &Attribute, + span: &Span, + target: Target, + item: Option>, + ) -> bool { + if let Target::Fn | Target::Method(..) | Target::ForeignFn = target { + let mut invalid_args = vec![]; + for meta in attr.meta_item_list().expect("no meta item list") { + if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { + if let Some(ItemLike::Item(Item { + kind: ItemKind::Fn(FnSig { decl, .. }, ..), + .. + })) + | Some(ItemLike::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(decl, ..), + .. + })) = item + { + let arg_count = decl.inputs.len() as u128; + if *val >= arg_count { + let span = meta.span(); + self.tcx + .sess + .struct_span_err(span, "index exceeds number of arguments") + .span_label( + span, + format!( + "there {} only {} argument{}", + if arg_count != 1 { "are" } else { "is" }, + arg_count, + pluralize!(arg_count) + ), + ) + .emit(); + return false; + } + } else { + bug!("should be a function item"); + } + } else { + invalid_args.push(meta.span()); + } + } + if !invalid_args.is_empty() { + self.tcx + .sess + .struct_span_err(invalid_args, "arguments should be non-negative integers") + .emit(); + false + } else { + true + } + } else { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(*span, "not a function") + .emit(); + false + } + } + + /// Checks if `#[link_section]` is applied to a function or static. + fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::Static | Target::Fn | Target::Method(..) => {} + _ => { + // FIXME: #[link_section] was previously allowed on non-functions/statics and some + // crates used this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function or static") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function or static") + .emit(); + }); + } + } + } + + /// Checks if `#[no_mangle]` is applied to a function or static. + fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::Static | Target::Fn | Target::Method(..) => {} + _ => { + // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some + // crates used this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function or static") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function or static") + .emit(); + }); + } + } + } + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, attrs: &'hir [Attribute], span: &Span, target: Target, - item: Option<&Item<'_>>, + item: Option>, hir_id: HirId, ) { // Extract the names of all repr hints, e.g., [foo, bar, align] for: @@ -311,7 +579,11 @@ impl CheckAttrVisitor<'tcx> { } sym::simd => { is_simd = true; - if target != Target::Struct { ("a", "struct") } else { continue } + if target != Target::Struct { + ("a", "struct") + } else { + continue; + } } sym::transparent => { is_transparent = true; @@ -348,7 +620,11 @@ impl CheckAttrVisitor<'tcx> { | sym::isize | sym::usize => { int_reprs += 1; - if target != Target::Enum { ("an", "enum") } else { continue } + if target != Target::Enum { + ("an", "enum") + } else { + continue; + } } _ => continue, }; @@ -381,7 +657,14 @@ impl CheckAttrVisitor<'tcx> { // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8) if (int_reprs > 1) || (is_simd && is_c) - || (int_reprs == 1 && is_c && item.map_or(false, |item| is_c_like_enum(item))) + || (int_reprs == 1 + && is_c + && item.map_or(false, |item| { + if let ItemLike::Item(item) = item { + return is_c_like_enum(item); + } + return false; + })) { self.tcx.struct_span_lint_hir( CONFLICTING_REPR_HINTS, @@ -411,10 +694,8 @@ impl CheckAttrVisitor<'tcx> { fn check_stmt_attributes(&self, stmt: &hir::Stmt<'_>) { // When checking statements ignore expressions, they will be checked later if let hir::StmtKind::Local(ref l) = stmt.kind { + self.check_attributes(l.hir_id, &l.attrs, &stmt.span, Target::Statement, None); for attr in l.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::inline) { - self.check_inline(l.hir_id, attr, &stmt.span, Target::Statement); - } if self.tcx.sess.check_name(attr, sym::repr) { self.emit_repr_error( attr.span, @@ -432,10 +713,8 @@ impl CheckAttrVisitor<'tcx> { hir::ExprKind::Closure(..) => Target::Closure, _ => Target::Expression, }; + self.check_attributes(expr.hir_id, &expr.attrs, &expr.span, target, None); for attr in expr.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::inline) { - self.check_inline(expr.hir_id, attr, &expr.span, target); - } if self.tcx.sess.check_name(attr, sym::repr) { self.emit_repr_error( attr.span, @@ -470,7 +749,13 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { fn visit_item(&mut self, item: &'tcx Item<'tcx>) { let target = Target::from_item(item); - self.check_attributes(item.hir_id, item.attrs, &item.span, target, Some(item)); + self.check_attributes( + item.hir_id, + item.attrs, + &item.span, + target, + Some(ItemLike::Item(item)), + ); intravisit::walk_item(self, item) } @@ -480,9 +765,15 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_trait_item(self, trait_item) } - fn visit_foreign_item(&mut self, f_item: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) { let target = Target::from_foreign_item(f_item); - self.check_attributes(f_item.hir_id, &f_item.attrs, &f_item.span, target, None); + self.check_attributes( + f_item.hir_id, + &f_item.attrs, + &f_item.span, + target, + Some(ItemLike::ForeignItem(f_item)), + ); intravisit::walk_foreign_item(self, f_item) } diff --git a/src/librustc_passes/check_const.rs b/compiler/rustc_passes/src/check_const.rs similarity index 100% rename from src/librustc_passes/check_const.rs rename to compiler/rustc_passes/src/check_const.rs diff --git a/src/librustc_passes/dead.rs b/compiler/rustc_passes/src/dead.rs similarity index 98% rename from src/librustc_passes/dead.rs rename to compiler/rustc_passes/src/dead.rs index 01da33ddd2..98ded4189c 100644 --- a/src/librustc_passes/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -104,7 +104,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let Some(t) = t { self.check_def_id(t); } - if let Some(i) = i { + if let Some((i, _)) = i { self.check_def_id(i); } } @@ -124,7 +124,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn handle_field_access(&mut self, lhs: &hir::Expr<'_>, hir_id: hir::HirId) { - match self.typeck_results().expr_ty_adjusted(lhs).kind { + match self.typeck_results().expr_ty_adjusted(lhs).kind() { ty::Adt(def, _) => { let index = self.tcx.field_index(hir_id, self.typeck_results()); self.insert_def_id(def.non_enum_variant().fields[index].did); @@ -140,7 +140,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { res: Res, pats: &[hir::FieldPat<'_>], ) { - let variant = match self.typeck_results().node_type(lhs.hir_id).kind { + let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { ty::Adt(adt, _) => adt.variant_of_res(res), _ => span_bug!(lhs.span, "non-ADT in struct pattern"), }; @@ -269,7 +269,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { hir::ExprKind::Struct(ref qpath, ref fields, _) => { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); self.handle_res(res); - if let ty::Adt(ref adt, _) = self.typeck_results().expr_ty(expr).kind { + if let ty::Adt(ref adt, _) = self.typeck_results().expr_ty(expr).kind() { self.mark_as_used_if_union(adt, fields); } } @@ -369,7 +369,7 @@ fn has_allow_dead_code_or_lang_attr( // - This is because lang items are always callable from elsewhere. // or // 2) We are not sure to be live or not -// * Implementation of a trait method +// * Implementations of traits and trait methods struct LifeSeeder<'k, 'tcx> { worklist: Vec, krate: &'k hir::Crate<'k>, @@ -415,6 +415,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } hir::ItemKind::Impl { ref of_trait, items, .. } => { + if of_trait.is_some() { + self.worklist.push(item.hir_id); + } for impl_item_ref in items { let impl_item = self.krate.impl_item(impl_item_ref.id); if of_trait.is_some() diff --git a/src/librustc_passes/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs similarity index 87% rename from src/librustc_passes/diagnostic_items.rs rename to compiler/rustc_passes/src/diagnostic_items.rs index df0f9f157a..94592935c7 100644 --- a/src/librustc_passes/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -12,11 +12,11 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; struct DiagnosticItemCollector<'tcx> { @@ -100,6 +100,18 @@ fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> FxHashMap { // Collect diagnostic items in this crate. tcx.hir().krate().visit_all_item_likes(&mut collector); + // FIXME(visit_all_item_likes): Foreign items are not visited + // here, so we have to manually look at them for now. + for foreign_module in tcx.foreign_modules(LOCAL_CRATE) { + for &foreign_item in foreign_module.foreign_items.iter() { + match tcx.hir().get(tcx.hir().local_def_id_to_hir_id(foreign_item.expect_local())) { + hir::Node::ForeignItem(item) => { + collector.observe_item(item.attrs, item.hir_id); + } + item => bug!("unexpected foreign item {:?}", item), + } + } + } collector.items } diff --git a/src/librustc_passes/entry.rs b/compiler/rustc_passes/src/entry.rs similarity index 100% rename from src/librustc_passes/entry.rs rename to compiler/rustc_passes/src/entry.rs diff --git a/src/librustc_passes/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs similarity index 98% rename from src/librustc_passes/hir_id_validator.rs rename to compiler/rustc_passes/src/hir_id_validator.rs index 2edbc29b7e..24695f5cdf 100644 --- a/src/librustc_passes/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -112,14 +112,14 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { missing_items.push(format!( "[local_id: {}, owner: {}]", local_id, - self.hir_map.def_path(owner).to_string_no_crate() + self.hir_map.def_path(owner).to_string_no_crate_verbose() )); } self.error(|| { format!( "ItemLocalIds not assigned densely in {}. \ Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}", - self.hir_map.def_path(owner).to_string_no_crate(), + self.hir_map.def_path(owner).to_string_no_crate_verbose(), max, missing_items, self.hir_ids_seen @@ -148,8 +148,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { format!( "HirIdValidator: The recorded owner of {} is {} instead of {}", self.hir_map.node_to_string(hir_id), - self.hir_map.def_path(hir_id.owner).to_string_no_crate(), - self.hir_map.def_path(owner).to_string_no_crate() + self.hir_map.def_path(hir_id.owner).to_string_no_crate_verbose(), + self.hir_map.def_path(owner).to_string_no_crate_verbose() ) }); } diff --git a/src/librustc_passes/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs similarity index 100% rename from src/librustc_passes/hir_stats.rs rename to compiler/rustc_passes/src/hir_stats.rs diff --git a/src/librustc_passes/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs similarity index 98% rename from src/librustc_passes/intrinsicck.rs rename to compiler/rustc_passes/src/intrinsicck.rs index ebe231009d..79f1c2b9da 100644 --- a/src/librustc_passes/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -35,7 +35,7 @@ struct ExprVisitor<'tcx> { /// If the type is `Option`, it will return `T`, otherwise /// the type itself. Works on most `Option`-like types. fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let (def, substs) = match ty.kind { + let (def, substs) = match *ty.kind() { ty::Adt(def, substs) => (def, substs), _ => return ty, }; @@ -81,7 +81,7 @@ impl ExprVisitor<'tcx> { // Special-case transmutting from `typeof(function)` and // `Option` to present a clearer error. let from = unpack_option_like(self.tcx, from); - if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (&from.kind, sk_to) { + if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) { if size_to == Pointer.size(&self.tcx) { struct_span_err!(self.tcx.sess, span, E0591, "can't transmute zero-sized type") .note(&format!("source type: {}", from)) @@ -127,7 +127,7 @@ impl ExprVisitor<'tcx> { if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) { return true; } - if let ty::Foreign(..) = ty.kind { + if let ty::Foreign(..) = ty.kind() { return true; } false @@ -149,7 +149,7 @@ impl ExprVisitor<'tcx> { 64 => InlineAsmType::I64, _ => unreachable!(), }; - let asm_ty = match ty.kind { + let asm_ty = match *ty.kind() { ty::Never | ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8), ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16), @@ -166,7 +166,7 @@ impl ExprVisitor<'tcx> { ty::Adt(adt, substs) if adt.repr.simd() => { let fields = &adt.non_enum_variant().fields; let elem_ty = fields[0].ty(self.tcx, substs); - match elem_ty.kind { + match elem_ty.kind() { ty::Never | ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => { Some(InlineAsmType::VecI8(fields.len() as u64)) @@ -374,7 +374,7 @@ impl ExprVisitor<'tcx> { } hir::InlineAsmOperand::Const { ref expr } => { let ty = self.typeck_results.expr_ty_adjusted(expr); - match ty.kind { + match ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Float(_) => {} _ => { let msg = diff --git a/src/librustc_passes/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs similarity index 100% rename from src/librustc_passes/lang_items.rs rename to compiler/rustc_passes/src/lang_items.rs diff --git a/src/librustc_passes/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs similarity index 100% rename from src/librustc_passes/layout_test.rs rename to compiler/rustc_passes/src/layout_test.rs diff --git a/src/librustc_passes/lib.rs b/compiler/rustc_passes/src/lib.rs similarity index 90% rename from src/librustc_passes/lib.rs rename to compiler/rustc_passes/src/lib.rs index be4c542ec3..c32c9c8eaa 100644 --- a/src/librustc_passes/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -4,7 +4,9 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(const_fn)] +#![feature(const_panic)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] diff --git a/src/librustc_passes/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs similarity index 100% rename from src/librustc_passes/lib_features.rs rename to compiler/rustc_passes/src/lib_features.rs diff --git a/src/librustc_passes/liveness.rs b/compiler/rustc_passes/src/liveness.rs similarity index 79% rename from src/librustc_passes/liveness.rs rename to compiler/rustc_passes/src/liveness.rs index de21f0b5e0..e8b97d7dc7 100644 --- a/src/librustc_passes/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -62,13 +62,13 @@ //! - `reader`: the `LiveNode` ID of some node which will read the value //! that `V` holds on entry to `N`. Formally: a node `M` such //! that there exists a path `P` from `N` to `M` where `P` does not -//! write `V`. If the `reader` is `invalid_node()`, then the current +//! write `V`. If the `reader` is `None`, then the current //! value will never be read (the variable is dead, essentially). //! //! - `writer`: the `LiveNode` ID of some node which will write the //! variable `V` and which is reachable from `N`. Formally: a node `M` //! such that there exists a path `P` from `N` to `M` and `M` writes -//! `V`. If the `writer` is `invalid_node()`, then there is no writer +//! `V`. If the `writer` is `None`, then there is no writer //! of `V` that follows `N`. //! //! - `used`: a boolean value indicating whether `V` is *used*. We @@ -79,7 +79,7 @@ //! ## Special nodes and variables //! //! We generate various special nodes for various, well, special purposes. -//! These are described in the `Specials` struct. +//! These are described in the `Liveness` struct. use self::LiveNodeKind::*; use self::VarKind::*; @@ -90,36 +90,30 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node}; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; +use rustc_index::vec::IndexVec; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::collections::VecDeque; -use std::fmt; use std::io; use std::io::prelude::*; use std::rc::Rc; -#[derive(Copy, Clone, PartialEq)] -struct Variable(u32); - -#[derive(Copy, Clone, PartialEq)] -struct LiveNode(u32); - -impl Variable { - fn get(&self) -> usize { - self.0 as usize +rustc_index::newtype_index! { + pub struct Variable { + DEBUG_FORMAT = "v({})", } } -impl LiveNode { - fn get(&self) -> usize { - self.0 as usize +rustc_index::newtype_index! { + pub struct LiveNode { + DEBUG_FORMAT = "ln({})", } } @@ -143,58 +137,14 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { } } -impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { - type Map = Map<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::OnlyBodies(self.tcx.hir()) - } - - fn visit_fn( - &mut self, - fk: FnKind<'tcx>, - fd: &'tcx hir::FnDecl<'tcx>, - b: hir::BodyId, - s: Span, - id: HirId, - ) { - visit_fn(self, fk, fd, b, s, id); - } - - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { - visit_local(self, l); - } - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - visit_expr(self, ex); - } - fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { - visit_arm(self, a); - } -} - fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module( - module_def_id, - &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(), - ); + tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor()); } pub fn provide(providers: &mut Providers) { *providers = Providers { check_mod_liveness, ..*providers }; } -impl fmt::Debug for LiveNode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ln({})", self.get()) - } -} - -impl fmt::Debug for Variable { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "v({})", self.get()) - } -} - // ______________________________________________________________________ // Creating ir_maps // @@ -217,16 +167,6 @@ impl fmt::Debug for Variable { // variable must not be assigned if there is some successor // assignment. And so forth. -impl LiveNode { - fn is_valid(&self) -> bool { - self.0 != u32::MAX - } -} - -fn invalid_node() -> LiveNode { - LiveNode(u32::MAX) -} - struct CaptureInfo { ln: LiveNode, var_hid: HirId, @@ -248,35 +188,27 @@ enum VarKind { struct IrMaps<'tcx> { tcx: TyCtxt<'tcx>, - body_owner: LocalDefId, - num_live_nodes: usize, - num_vars: usize, live_node_map: HirIdMap, variable_map: HirIdMap, capture_info_map: HirIdMap>>, - var_kinds: Vec, - lnks: Vec, + var_kinds: IndexVec, + lnks: IndexVec, } impl IrMaps<'tcx> { - fn new(tcx: TyCtxt<'tcx>, body_owner: LocalDefId) -> IrMaps<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> IrMaps<'tcx> { IrMaps { tcx, - body_owner, - num_live_nodes: 0, - num_vars: 0, live_node_map: HirIdMap::default(), variable_map: HirIdMap::default(), capture_info_map: Default::default(), - var_kinds: Vec::new(), - lnks: Vec::new(), + var_kinds: IndexVec::new(), + lnks: IndexVec::new(), } } fn add_live_node(&mut self, lnk: LiveNodeKind) -> LiveNode { - let ln = LiveNode(self.num_live_nodes as u32); - self.lnks.push(lnk); - self.num_live_nodes += 1; + let ln = self.lnks.push(lnk); debug!("{:?} is of kind {}", ln, live_node_kind_to_string(lnk, self.tcx)); @@ -291,9 +223,7 @@ impl IrMaps<'tcx> { } fn add_variable(&mut self, vk: VarKind) -> Variable { - let v = Variable(self.num_vars as u32); - self.var_kinds.push(vk); - self.num_vars += 1; + let v = self.var_kinds.push(vk); match vk { Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) | Upvar(node_id, _) => { @@ -315,14 +245,14 @@ impl IrMaps<'tcx> { } } - fn variable_name(&self, var: Variable) -> String { - match self.var_kinds[var.get()] { - Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name.to_string(), + fn variable_name(&self, var: Variable) -> Symbol { + match self.var_kinds[var] { + Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name, } } fn variable_is_shorthand(&self, var: Variable) -> bool { - match self.var_kinds[var.get()] { + match self.var_kinds[var] { Local(LocalInfo { is_shorthand, .. }) => is_shorthand, Param(..) | Upvar(..) => false, } @@ -332,203 +262,192 @@ impl IrMaps<'tcx> { self.capture_info_map.insert(hir_id, Rc::new(cs)); } - fn lnk(&self, ln: LiveNode) -> LiveNodeKind { - self.lnks[ln.get()] + fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) { + // For struct patterns, take note of which fields used shorthand + // (`x` rather than `x: x`). + let mut shorthand_field_ids = HirIdSet::default(); + let mut pats = VecDeque::new(); + pats.push_back(pat); + while let Some(pat) = pats.pop_front() { + use rustc_hir::PatKind::*; + match &pat.kind { + Binding(.., inner_pat) => { + pats.extend(inner_pat.iter()); + } + Struct(_, fields, _) => { + let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id); + shorthand_field_ids.extend(ids); + } + Ref(inner_pat, _) | Box(inner_pat) => { + pats.push_back(inner_pat); + } + TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => { + pats.extend(inner_pats.iter()); + } + Slice(pre_pats, inner_pat, post_pats) => { + pats.extend(pre_pats.iter()); + pats.extend(inner_pat.iter()); + pats.extend(post_pats.iter()); + } + _ => {} + } + } + + pat.each_binding(|_, hir_id, _, ident| { + self.add_live_node_for_node(hir_id, VarDefNode(ident.span)); + self.add_variable(Local(LocalInfo { + id: hir_id, + name: ident.name, + is_shorthand: shorthand_field_ids.contains(&hir_id), + })); + }); } } -fn visit_fn<'tcx>( - ir: &mut IrMaps<'tcx>, - fk: FnKind<'tcx>, - decl: &'tcx hir::FnDecl<'tcx>, - body_id: hir::BodyId, - sp: Span, - id: hir::HirId, -) { - debug!("visit_fn {:?}", id); - - // swap in a new set of IR maps for this function body: - let def_id = ir.tcx.hir().local_def_id(id); - let mut fn_maps = IrMaps::new(ir.tcx, def_id); - - // Don't run unused pass for #[derive()] - if let FnKind::Method(..) = fk { - let parent = ir.tcx.hir().get_parent_item(id); - if let Some(Node::Item(i)) = ir.tcx.hir().find(parent) { - if i.attrs.iter().any(|a| ir.tcx.sess.check_name(a, sym::automatically_derived)) { - return; - } - } +impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.tcx.hir()) } - debug!("creating fn_maps: {:p}", &fn_maps); + fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { + debug!("visit_body {:?}", body.id()); - let body = ir.tcx.hir().body(body_id); + // swap in a new set of IR maps for this body + let mut maps = IrMaps::new(self.tcx); + let hir_id = maps.tcx.hir().body_owner(body.id()); + let def_id = maps.tcx.hir().local_def_id(hir_id); - if let Some(upvars) = ir.tcx.upvars_mentioned(def_id) { - for (&var_hir_id, _upvar) in upvars { - debug!("adding upvar {:?}", var_hir_id); - let var_name = ir.tcx.hir().name(var_hir_id); - fn_maps.add_variable(Upvar(var_hir_id, var_name)); + // Don't run unused pass for #[derive()] + if let Some(parent) = self.tcx.parent(def_id.to_def_id()) { + if let DefKind::Impl = self.tcx.def_kind(parent.expect_local()) { + if self.tcx.has_attr(parent, sym::automatically_derived) { + return; + } + } } + + if let Some(upvars) = maps.tcx.upvars_mentioned(def_id) { + for (&var_hir_id, _upvar) in upvars { + let var_name = maps.tcx.hir().name(var_hir_id); + maps.add_variable(Upvar(var_hir_id, var_name)); + } + } + + // gather up the various local variables, significant expressions, + // and so forth: + intravisit::walk_body(&mut maps, body); + + // compute liveness + let mut lsets = Liveness::new(&mut maps, def_id); + let entry_ln = lsets.compute(&body, hir_id); + lsets.log_liveness(entry_ln, body.id().hir_id); + + // check for various error conditions + lsets.visit_body(body); + lsets.warn_about_unused_upvars(entry_ln); + lsets.warn_about_unused_args(body, entry_ln); + } + + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + self.add_from_pat(&local.pat); + intravisit::walk_local(self, local); + } + + fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { + self.add_from_pat(&arm.pat); + intravisit::walk_arm(self, arm); } - for param in body.params { + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { let is_shorthand = match param.pat.kind { rustc_hir::PatKind::Struct(..) => true, _ => false, }; param.pat.each_binding(|_bm, hir_id, _x, ident| { - debug!("adding parameters {:?}", hir_id); let var = if is_shorthand { Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true }) } else { Param(hir_id, ident.name) }; - fn_maps.add_variable(var); - }) + self.add_variable(var); + }); + intravisit::walk_param(self, param); } - // gather up the various local variables, significant expressions, - // and so forth: - intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id); - - // compute liveness - let mut lsets = Liveness::new(&mut fn_maps, def_id); - let entry_ln = lsets.compute(fk, &body, sp, id); - lsets.log_liveness(entry_ln, id); - - // check for various error conditions - lsets.visit_body(body); - lsets.warn_about_unused_upvars(entry_ln); - lsets.warn_about_unused_args(body, entry_ln); -} - -fn add_from_pat(ir: &mut IrMaps<'_>, pat: &hir::Pat<'_>) { - // For struct patterns, take note of which fields used shorthand - // (`x` rather than `x: x`). - let mut shorthand_field_ids = HirIdSet::default(); - let mut pats = VecDeque::new(); - pats.push_back(pat); - while let Some(pat) = pats.pop_front() { - use rustc_hir::PatKind::*; - match &pat.kind { - Binding(.., inner_pat) => { - pats.extend(inner_pat.iter()); - } - Struct(_, fields, _) => { - let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id); - shorthand_field_ids.extend(ids); - } - Ref(inner_pat, _) | Box(inner_pat) => { - pats.push_back(inner_pat); - } - TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => { - pats.extend(inner_pats.iter()); + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + match expr.kind { + // live nodes required for uses or definitions of variables: + hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { + debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res); + if let Res::Local(_var_hir_id) = path.res { + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + } + intravisit::walk_expr(self, expr); } - Slice(pre_pats, inner_pat, post_pats) => { - pats.extend(pre_pats.iter()); - pats.extend(inner_pat.iter()); - pats.extend(post_pats.iter()); + hir::ExprKind::Closure(..) => { + // Interesting control flow (for loops can contain labeled + // breaks or continues) + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + + // Make a live_node for each captured variable, with the span + // being the location that the variable is used. This results + // in better error messages than just pointing at the closure + // construction site. + let mut call_caps = Vec::new(); + let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id); + if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { + call_caps.extend(upvars.iter().map(|(&var_id, upvar)| { + let upvar_ln = self.add_live_node(UpvarNode(upvar.span)); + CaptureInfo { ln: upvar_ln, var_hid: var_id } + })); + } + self.set_captures(expr.hir_id, call_caps); + intravisit::walk_expr(self, expr); } - _ => {} - } - } - - pat.each_binding(|_, hir_id, _, ident| { - ir.add_live_node_for_node(hir_id, VarDefNode(ident.span)); - ir.add_variable(Local(LocalInfo { - id: hir_id, - name: ident.name, - is_shorthand: shorthand_field_ids.contains(&hir_id), - })); - }); -} -fn visit_local<'tcx>(ir: &mut IrMaps<'tcx>, local: &'tcx hir::Local<'tcx>) { - add_from_pat(ir, &local.pat); - intravisit::walk_local(ir, local); -} - -fn visit_arm<'tcx>(ir: &mut IrMaps<'tcx>, arm: &'tcx hir::Arm<'tcx>) { - add_from_pat(ir, &arm.pat); - intravisit::walk_arm(ir, arm); -} - -fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { - match expr.kind { - // live nodes required for uses or definitions of variables: - hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { - debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res); - if let Res::Local(_var_hir_id) = path.res { - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + // live nodes required for interesting control flow: + hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => { + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + intravisit::walk_expr(self, expr); } - intravisit::walk_expr(ir, expr); - } - hir::ExprKind::Closure(..) => { - // Interesting control flow (for loops can contain labeled - // breaks or continues) - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); - - // Make a live_node for each captured variable, with the span - // being the location that the variable is used. This results - // in better error messages than just pointing at the closure - // construction site. - let mut call_caps = Vec::new(); - let closure_def_id = ir.tcx.hir().local_def_id(expr.hir_id); - if let Some(upvars) = ir.tcx.upvars_mentioned(closure_def_id) { - call_caps.extend(upvars.iter().map(|(&var_id, upvar)| { - let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); - CaptureInfo { ln: upvar_ln, var_hid: var_id } - })); + hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => { + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + intravisit::walk_expr(self, expr); } - ir.set_captures(expr.hir_id, call_caps); - let old_body_owner = ir.body_owner; - ir.body_owner = closure_def_id; - intravisit::walk_expr(ir, expr); - ir.body_owner = old_body_owner; - } - // live nodes required for interesting control flow: - hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => { - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); - intravisit::walk_expr(ir, expr); - } - hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => { - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); - intravisit::walk_expr(ir, expr); - } - - // otherwise, live nodes are not required: - hir::ExprKind::Index(..) - | hir::ExprKind::Field(..) - | hir::ExprKind::Array(..) - | hir::ExprKind::Call(..) - | hir::ExprKind::MethodCall(..) - | hir::ExprKind::Tup(..) - | hir::ExprKind::Binary(..) - | hir::ExprKind::AddrOf(..) - | hir::ExprKind::Cast(..) - | hir::ExprKind::DropTemps(..) - | hir::ExprKind::Unary(..) - | hir::ExprKind::Break(..) - | hir::ExprKind::Continue(_) - | hir::ExprKind::Lit(_) - | hir::ExprKind::Ret(..) - | hir::ExprKind::Block(..) - | hir::ExprKind::Assign(..) - | hir::ExprKind::AssignOp(..) - | hir::ExprKind::Struct(..) - | hir::ExprKind::Repeat(..) - | hir::ExprKind::InlineAsm(..) - | hir::ExprKind::LlvmInlineAsm(..) - | hir::ExprKind::Box(..) - | hir::ExprKind::Yield(..) - | hir::ExprKind::Type(..) - | hir::ExprKind::Err - | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) - | hir::ExprKind::Path(hir::QPath::LangItem(..)) => { - intravisit::walk_expr(ir, expr); + // otherwise, live nodes are not required: + hir::ExprKind::Index(..) + | hir::ExprKind::Field(..) + | hir::ExprKind::Array(..) + | hir::ExprKind::Call(..) + | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Tup(..) + | hir::ExprKind::Binary(..) + | hir::ExprKind::AddrOf(..) + | hir::ExprKind::Cast(..) + | hir::ExprKind::DropTemps(..) + | hir::ExprKind::Unary(..) + | hir::ExprKind::Break(..) + | hir::ExprKind::Continue(_) + | hir::ExprKind::Lit(_) + | hir::ExprKind::Ret(..) + | hir::ExprKind::Block(..) + | hir::ExprKind::Assign(..) + | hir::ExprKind::AssignOp(..) + | hir::ExprKind::Struct(..) + | hir::ExprKind::Repeat(..) + | hir::ExprKind::InlineAsm(..) + | hir::ExprKind::LlvmInlineAsm(..) + | hir::ExprKind::Box(..) + | hir::ExprKind::Yield(..) + | hir::ExprKind::Type(..) + | hir::ExprKind::Err + | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) + | hir::ExprKind::Path(hir::QPath::LangItem(..)) => { + intravisit::walk_expr(self, expr); + } } } } @@ -541,8 +460,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { #[derive(Clone, Copy)] struct RWU { - reader: LiveNode, - writer: LiveNode, + reader: Option, + writer: Option, used: bool, } @@ -564,10 +483,10 @@ struct RWUTable { unpacked_rwus: Vec, } -// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: false }`. +// A constant representing `RWU { reader: None; writer: None; used: false }`. const INV_INV_FALSE: u32 = u32::MAX; -// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: true }`. +// A constant representing `RWU { reader: None; writer: None; used: true }`. const INV_INV_TRUE: u32 = u32::MAX - 1; impl RWUTable { @@ -578,24 +497,24 @@ impl RWUTable { fn get(&self, idx: usize) -> RWU { let packed_rwu = self.packed_rwus[idx]; match packed_rwu { - INV_INV_FALSE => RWU { reader: invalid_node(), writer: invalid_node(), used: false }, - INV_INV_TRUE => RWU { reader: invalid_node(), writer: invalid_node(), used: true }, + INV_INV_FALSE => RWU { reader: None, writer: None, used: false }, + INV_INV_TRUE => RWU { reader: None, writer: None, used: true }, _ => self.unpacked_rwus[packed_rwu as usize], } } - fn get_reader(&self, idx: usize) -> LiveNode { + fn get_reader(&self, idx: usize) -> Option { let packed_rwu = self.packed_rwus[idx]; match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => invalid_node(), + INV_INV_FALSE | INV_INV_TRUE => None, _ => self.unpacked_rwus[packed_rwu as usize].reader, } } - fn get_writer(&self, idx: usize) -> LiveNode { + fn get_writer(&self, idx: usize) -> Option { let packed_rwu = self.packed_rwus[idx]; match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => invalid_node(), + INV_INV_FALSE | INV_INV_TRUE => None, _ => self.unpacked_rwus[packed_rwu as usize].writer, } } @@ -615,7 +534,7 @@ impl RWUTable { } fn assign_unpacked(&mut self, idx: usize, rwu: RWU) { - if rwu.reader == invalid_node() && rwu.writer == invalid_node() { + if rwu.reader == None && rwu.writer == None { // When we overwrite an indexing entry in `self.packed_rwus` with // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry // from `self.unpacked_rwus`; it's not worth the effort, and we @@ -634,29 +553,27 @@ impl RWUTable { } } -#[derive(Copy, Clone)] -struct Specials { - /// A live node representing a point of execution before closure entry & - /// after closure exit. Used to calculate liveness of captured variables - /// through calls to the same closure. Used for Fn & FnMut closures only. - closure_ln: LiveNode, - /// A live node representing every 'exit' from the function, whether it be - /// by explicit return, panic, or other means. - exit_ln: LiveNode, -} - const ACC_READ: u32 = 1; const ACC_WRITE: u32 = 2; const ACC_USE: u32 = 4; struct Liveness<'a, 'tcx> { ir: &'a mut IrMaps<'tcx>, + body_owner: LocalDefId, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, - s: Specials, - successors: Vec, + upvars: Option<&'tcx FxIndexMap>, + successors: IndexVec>, rwu_table: RWUTable, + /// A live node representing a point of execution before closure entry & + /// after closure exit. Used to calculate liveness of captured variables + /// through calls to the same closure. Used for Fn & FnMut closures only. + closure_ln: LiveNode, + /// A live node representing every 'exit' from the function, whether it be + /// by explicit return, panic, or other means. + exit_ln: LiveNode, + // mappings from loop node ID to LiveNode // ("break" label should map to loop node ID, // it probably doesn't now) @@ -665,25 +582,27 @@ struct Liveness<'a, 'tcx> { } impl<'a, 'tcx> Liveness<'a, 'tcx> { - fn new(ir: &'a mut IrMaps<'tcx>, def_id: LocalDefId) -> Liveness<'a, 'tcx> { - let specials = Specials { - closure_ln: ir.add_live_node(ClosureNode), - exit_ln: ir.add_live_node(ExitNode), - }; + fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> { + let typeck_results = ir.tcx.typeck(body_owner); + let param_env = ir.tcx.param_env(body_owner); + let upvars = ir.tcx.upvars_mentioned(body_owner); - let typeck_results = ir.tcx.typeck(def_id); - let param_env = ir.tcx.param_env(def_id); + let closure_ln = ir.add_live_node(ClosureNode); + let exit_ln = ir.add_live_node(ExitNode); - let num_live_nodes = ir.num_live_nodes; - let num_vars = ir.num_vars; + let num_live_nodes = ir.lnks.len(); + let num_vars = ir.var_kinds.len(); Liveness { ir, + body_owner, typeck_results, param_env, - s: specials, - successors: vec![invalid_node(); num_live_nodes], + upvars, + successors: IndexVec::from_elem_n(None, num_live_nodes), rwu_table: RWUTable::new(num_live_nodes * num_vars), + closure_ln, + exit_ln, break_ln: Default::default(), cont_ln: Default::default(), } @@ -721,34 +640,37 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn idx(&self, ln: LiveNode, var: Variable) -> usize { - ln.get() * self.ir.num_vars + var.get() + ln.index() * self.ir.var_kinds.len() + var.index() } fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option { - assert!(ln.is_valid()); - let reader = self.rwu_table.get_reader(self.idx(ln, var)); - if reader.is_valid() { Some(self.ir.lnk(reader)) } else { None } + if let Some(reader) = self.rwu_table.get_reader(self.idx(ln, var)) { + Some(self.ir.lnks[reader]) + } else { + None + } } // Is this variable live on entry to any of its successor nodes? fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option { - let successor = self.successors[ln.get()]; + let successor = self.successors[ln].unwrap(); self.live_on_entry(successor, var) } fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool { - assert!(ln.is_valid()); self.rwu_table.get_used(self.idx(ln, var)) } fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option { - assert!(ln.is_valid()); - let writer = self.rwu_table.get_writer(self.idx(ln, var)); - if writer.is_valid() { Some(self.ir.lnk(writer)) } else { None } + if let Some(writer) = self.rwu_table.get_writer(self.idx(ln, var)) { + Some(self.ir.lnks[writer]) + } else { + None + } } fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option { - let successor = self.successors[ln.get()]; + let successor = self.successors[ln].unwrap(); self.assigned_on_entry(successor, var) } @@ -756,9 +678,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { where F: FnMut(&mut Liveness<'a, 'tcx>, usize, usize), { - let node_base_idx = self.idx(ln, Variable(0)); - let succ_base_idx = self.idx(succ_ln, Variable(0)); - for var_idx in 0..self.ir.num_vars { + let node_base_idx = self.idx(ln, Variable::from(0u32)); + let succ_base_idx = self.idx(succ_ln, Variable::from(0u32)); + for var_idx in 0..self.ir.var_kinds.len() { op(self, node_base_idx + var_idx, succ_base_idx + var_idx); } } @@ -767,11 +689,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { where F: FnMut(usize) -> bool, { - let node_base_idx = self.idx(ln, Variable(0)); - for var_idx in 0..self.ir.num_vars { + let node_base_idx = self.idx(ln, Variable::from(0u32)); + for var_idx in 0..self.ir.var_kinds.len() { let idx = node_base_idx + var_idx; if test(idx) { - write!(wr, " {:?}", Variable(var_idx as u32))?; + write!(wr, " {:?}", Variable::from(var_idx))?; } } Ok(()) @@ -782,14 +704,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut wr = Vec::new(); { let wr = &mut wr as &mut dyn Write; - write!(wr, "[ln({:?}) of kind {:?} reads", ln.get(), self.ir.lnk(ln)); - self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_valid()); + write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]); + self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_some()); write!(wr, " writes"); - self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_valid()); + self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_some()); write!(wr, " uses"); self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx)); - write!(wr, " precedes {:?}]", self.successors[ln.get()]); + write!(wr, " precedes {:?}]", self.successors[ln]); } String::from_utf8(wr).unwrap() } @@ -799,8 +721,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!( "^^ liveness computation results for body {} (entry={:?})", { - for ln_idx in 0..self.ir.num_live_nodes { - debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32))); + for ln_idx in 0..self.ir.lnks.len() { + debug!("{:?}", self.ln_str(LiveNode::from(ln_idx))); } hir_id }, @@ -809,7 +731,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) { - self.successors[ln.get()] = succ_ln; + self.successors[ln] = Some(succ_ln); // It is not necessary to initialize the RWUs here because they are all // set to INV_INV_FALSE when they are created, and the sets only grow @@ -818,7 +740,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) { // more efficient version of init_empty() / merge_from_succ() - self.successors[ln.get()] = succ_ln; + self.successors[ln] = Some(succ_ln); self.indices2(ln, succ_ln, |this, idx, succ_idx| { this.rwu_table.copy_packed(idx, succ_idx); @@ -842,12 +764,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut changed = false; let mut rwu = this.rwu_table.get(idx); let succ_rwu = this.rwu_table.get(succ_idx); - if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() { + if succ_rwu.reader.is_some() && rwu.reader.is_none() { rwu.reader = succ_rwu.reader; changed = true } - if succ_rwu.writer.is_valid() && !rwu.writer.is_valid() { + if succ_rwu.writer.is_some() && rwu.writer.is_none() { rwu.writer = succ_rwu.writer; changed = true } @@ -891,14 +813,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut rwu = self.rwu_table.get(idx); if (acc & ACC_WRITE) != 0 { - rwu.reader = invalid_node(); - rwu.writer = ln; + rwu.reader = None; + rwu.writer = Some(ln); } // Important: if we both read/write, must do read second // or else the write will override. if (acc & ACC_READ) != 0 { - rwu.reader = ln; + rwu.reader = Some(ln); } if (acc & ACC_USE) != 0 { @@ -908,14 +830,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.rwu_table.assign_unpacked(idx, rwu); } - fn compute( - &mut self, - fk: FnKind<'_>, - body: &hir::Body<'_>, - span: Span, - id: hir::HirId, - ) -> LiveNode { - debug!("compute: using id for body, {:?}", body.value); + fn compute(&mut self, body: &hir::Body<'_>, hir_id: HirId) -> LiveNode { + debug!("compute: for body {:?}", body.id().hir_id); // # Liveness of captured variables // @@ -933,32 +849,34 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // if they are live on the entry to the closure, since only the closure // itself can access them on subsequent calls. - if let Some(upvars) = self.ir.tcx.upvars_mentioned(self.ir.body_owner) { + if let Some(upvars) = self.upvars { // Mark upvars captured by reference as used after closure exits. for (&var_hir_id, upvar) in upvars.iter().rev() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: self.ir.body_owner, + closure_expr_id: self.body_owner, }; match self.typeck_results.upvar_capture(upvar_id) { ty::UpvarCapture::ByRef(_) => { let var = self.variable(var_hir_id, upvar.span); - self.acc(self.s.exit_ln, var, ACC_READ | ACC_USE); + self.acc(self.exit_ln, var, ACC_READ | ACC_USE); } - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue(_) => {} } } } - let succ = self.propagate_through_expr(&body.value, self.s.exit_ln); + let succ = self.propagate_through_expr(&body.value, self.exit_ln); - match fk { - FnKind::Method(..) | FnKind::ItemFn(..) => return succ, - FnKind::Closure(..) => {} + if self.upvars.is_none() { + // Either not a closure, or closure without any captured variables. + // No need to determine liveness of captured variables, since there + // are none. + return succ; } - let ty = self.typeck_results.node_type(id); - match ty.kind { + let ty = self.typeck_results.node_type(hir_id); + match ty.kind() { ty::Closure(_def_id, substs) => match substs.as_closure().kind() { ty::ClosureKind::Fn => {} ty::ClosureKind::FnMut => {} @@ -966,26 +884,31 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }, ty::Generator(..) => return succ, _ => { - span_bug!(span, "type of closure expr {:?} is not a closure {:?}", id, ty,); + span_bug!( + body.value.span, + "{} has upvars so it should have a closure type: {:?}", + hir_id, + ty + ); } }; // Propagate through calls to the closure. let mut first_merge = true; loop { - self.init_from_succ(self.s.closure_ln, succ); + self.init_from_succ(self.closure_ln, succ); for param in body.params { param.pat.each_binding(|_bm, hir_id, _x, ident| { let var = self.variable(hir_id, ident.span); - self.define(self.s.closure_ln, var); + self.define(self.closure_ln, var); }) } - if !self.merge_from_succ(self.s.exit_ln, self.s.closure_ln, first_merge) { + if !self.merge_from_succ(self.exit_ln, self.closure_ln, first_merge) { break; } first_merge = false; - assert_eq!(succ, self.propagate_through_expr(&body.value, self.s.exit_ln)); + assert_eq!(succ, self.propagate_through_expr(&body.value, self.exit_ln)); } succ @@ -1106,9 +1029,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Ret(ref o_e) => { - // ignore succ and subst exit_ln: - let exit_ln = self.s.exit_ln; - self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln) + // Ignore succ and subst exit_ln. + self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), self.exit_ln) } hir::ExprKind::Break(label, ref opt_expr) => { @@ -1182,7 +1104,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.typeck_results.expr_ty(expr), self.param_env, ) { - self.s.exit_ln + self.exit_ln } else { succ }; @@ -1197,7 +1119,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.typeck_results.expr_ty(expr), self.param_env, ) { - self.s.exit_ln + self.exit_ln } else { succ }; @@ -1234,7 +1156,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::InlineAsm(ref asm) => { // Handle non-returning asm let mut succ = if asm.options.contains(InlineAsmOptions::NORETURN) { - self.s.exit_ln + self.exit_ln } else { succ }; @@ -1595,11 +1517,18 @@ impl<'tcx> Liveness<'_, 'tcx> { fn should_warn(&self, var: Variable) -> Option { let name = self.ir.variable_name(var); - if name.is_empty() || name.as_bytes()[0] == b'_' { None } else { Some(name) } + if name == kw::Invalid { + return None; + } + let name: &str = &name.as_str(); + if name.as_bytes()[0] == b'_' { + return None; + } + Some(name.to_owned()) } fn warn_about_unused_upvars(&self, entry_ln: LiveNode) { - let upvars = match self.ir.tcx.upvars_mentioned(self.ir.body_owner) { + let upvars = match self.upvars { None => return, Some(upvars) => upvars, }; @@ -1607,10 +1536,10 @@ impl<'tcx> Liveness<'_, 'tcx> { let var = self.variable(var_hir_id, upvar.span); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: self.ir.body_owner, + closure_expr_id: self.body_owner, }; match self.typeck_results.upvar_capture(upvar_id) { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue(_) => {} ty::UpvarCapture::ByRef(..) => continue, }; if self.used_on_entry(entry_ln, var) { @@ -1667,7 +1596,7 @@ impl<'tcx> Liveness<'_, 'tcx> { // bindings, and we also consider the first pattern to be the "authoritative" set of ids. // However, we should take the ids and spans of variables with the same name from the later // patterns so the suggestions to prefix with underscores will apply to those too. - let mut vars: FxIndexMap)> = <_>::default(); + let mut vars: FxIndexMap)> = <_>::default(); pat.each_binding(|_, hir_id, pat_sp, ident| { let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp)); @@ -1697,7 +1626,7 @@ impl<'tcx> Liveness<'_, 'tcx> { // {ret}`, there is only one node, so asking about // assigned_on_exit() is not meaningful. let is_assigned = - if ln == self.s.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() }; + if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() }; if is_assigned { self.ir.tcx.struct_span_lint_hir( diff --git a/src/librustc_passes/loops.rs b/compiler/rustc_passes/src/loops.rs similarity index 100% rename from src/librustc_passes/loops.rs rename to compiler/rustc_passes/src/loops.rs diff --git a/src/librustc_passes/reachable.rs b/compiler/rustc_passes/src/reachable.rs similarity index 100% rename from src/librustc_passes/reachable.rs rename to compiler/rustc_passes/src/reachable.rs diff --git a/src/librustc_passes/region.rs b/compiler/rustc_passes/src/region.rs similarity index 100% rename from src/librustc_passes/region.rs rename to compiler/rustc_passes/src/region.rs diff --git a/src/librustc_passes/stability.rs b/compiler/rustc_passes/src/stability.rs similarity index 74% rename from src/librustc_passes/stability.rs rename to compiler/rustc_passes/src/stability.rs index 91edc7d9db..1378b0d570 100644 --- a/src/librustc_passes/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -9,13 +9,14 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Generics, HirId, Item, StructField, Variant}; +use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{DeprecationEntry, Index}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint; +use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; @@ -36,6 +37,24 @@ enum AnnotationKind { Container, } +/// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit +/// deprecation, because nested items rarely have individual deprecation attributes, and so +/// should be treated as deprecated if their parent is. However, default generic parameters +/// have separate deprecation attributes from their parents, so we do not wish to inherit +/// deprecation in this case. For example, inheriting deprecation for `T` in `Foo` +/// would cause a duplicate warning arising from both `Foo` and `T` being deprecated. +#[derive(Clone)] +enum InheritDeprecation { + Yes, + No, +} + +impl InheritDeprecation { + fn yes(&self) -> bool { + matches!(self, InheritDeprecation::Yes) + } +} + // A private tree-walker for producing an Index. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -55,6 +74,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { attrs: &[Attribute], item_sp: Span, kind: AnnotationKind, + inherit_deprecation: InheritDeprecation, visit_children: F, ) where F: FnOnce(&mut Self), @@ -62,7 +82,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs); let mut did_error = false; if !self.tcx.features().staged_api { - did_error = self.forbid_staged_api_attrs(hir_id, attrs); + did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation.clone()); } let depr = @@ -79,9 +99,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let depr_entry = DeprecationEntry::local(depr.clone(), hir_id); self.index.depr_map.insert(hir_id, depr_entry); } else if let Some(parent_depr) = self.parent_depr.clone() { - is_deprecated = true; - info!("tagging child {:?} as deprecated from parent", hir_id); - self.index.depr_map.insert(hir_id, parent_depr); + if inherit_deprecation.yes() { + is_deprecated = true; + info!("tagging child {:?} as deprecated from parent", hir_id); + self.index.depr_map.insert(hir_id, parent_depr); + } } if self.tcx.features().staged_api { @@ -185,7 +207,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if stab.is_none() { debug!("annotate: stab not found, parent = {:?}", self.parent_stab); if let Some(stab) = self.parent_stab { - if stab.level.is_unstable() { + if inherit_deprecation.yes() && stab.level.is_unstable() { self.index.stab_map.insert(hir_id, stab); } } @@ -236,7 +258,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // returns true if an error occurred, used to suppress some spurious errors - fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool { + fn forbid_staged_api_attrs( + &mut self, + hir_id: HirId, + attrs: &[Attribute], + inherit_deprecation: InheritDeprecation, + ) -> bool { // Emit errors for non-staged-api crates. let unstable_attrs = [ sym::unstable, @@ -264,7 +291,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. if let Some(stab) = self.parent_stab { - if stab.level.is_unstable() { + if inherit_deprecation.yes() && stab.level.is_unstable() { self.index.stab_map.insert(hir_id, stab); } } @@ -300,54 +327,119 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } hir::ItemKind::Struct(ref sd, _) => { if let Some(ctor_hir_id) = sd.ctor_hir_id() { - self.annotate(ctor_hir_id, &i.attrs, i.span, AnnotationKind::Required, |_| {}) + self.annotate( + ctor_hir_id, + &i.attrs, + i.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |_| {}, + ) } } _ => {} } - self.annotate(i.hir_id, &i.attrs, i.span, kind, |v| intravisit::walk_item(v, i)); + self.annotate(i.hir_id, &i.attrs, i.span, kind, InheritDeprecation::Yes, |v| { + intravisit::walk_item(v, i) + }); self.in_trait_impl = orig_in_trait_impl; } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, |v| { - intravisit::walk_trait_item(v, ti); - }); + self.annotate( + ti.hir_id, + &ti.attrs, + ti.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + intravisit::walk_trait_item(v, ti); + }, + ); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { let kind = if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required }; - self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, |v| { + self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, InheritDeprecation::Yes, |v| { intravisit::walk_impl_item(v, ii); }); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) { - self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, |v| { - if let Some(ctor_hir_id) = var.data.ctor_hir_id() { - v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required, |_| {}); - } + self.annotate( + var.id, + &var.attrs, + var.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + if let Some(ctor_hir_id) = var.data.ctor_hir_id() { + v.annotate( + ctor_hir_id, + &var.attrs, + var.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |_| {}, + ); + } - intravisit::walk_variant(v, var, g, item_id) - }) + intravisit::walk_variant(v, var, g, item_id) + }, + ) } fn visit_struct_field(&mut self, s: &'tcx StructField<'tcx>) { - self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, |v| { - intravisit::walk_struct_field(v, s); - }); + self.annotate( + s.hir_id, + &s.attrs, + s.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + intravisit::walk_struct_field(v, s); + }, + ); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, |v| { - intravisit::walk_foreign_item(v, i); - }); + self.annotate( + i.hir_id, + &i.attrs, + i.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + intravisit::walk_foreign_item(v, i); + }, + ); } fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { - self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, |_| {}); + self.annotate( + md.hir_id, + &md.attrs, + md.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |_| {}, + ); + } + + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + let kind = match &p.kind { + // FIXME(const_generics:defaults) + hir::GenericParamKind::Type { default, .. } if default.is_some() => { + AnnotationKind::Container + } + _ => AnnotationKind::Prohibited, + }; + + self.annotate(p.hir_id, &p.attrs, p.span, kind, InheritDeprecation::No, |v| { + intravisit::walk_generic_param(v, p); + }); } } @@ -367,6 +459,21 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr)); } } + + fn check_missing_const_stability(&self, hir_id: HirId, span: Span) { + let stab_map = self.tcx.stability(); + let stab = stab_map.local_stability(hir_id); + if stab.map_or(false, |stab| stab.level.is_stable()) { + let const_stab = stab_map.local_const_stability(hir_id); + if const_stab.is_none() { + self.tcx.sess.span_err( + span, + "`#[stable]` const functions must also be either \ + `#[rustc_const_stable]` or `#[rustc_const_unstable]`", + ); + } + } + } } impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { @@ -377,14 +484,23 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - match i.kind { - // Inherent impls and foreign modules serve only as containers for other items, - // they don't have their own stability. They still can be annotated as unstable - // and propagate this unstability to children, but this annotation is completely - // optional. They inherit stability from their parents when unannotated. - hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..) => {} + // Inherent impls and foreign modules serve only as containers for other items, + // they don't have their own stability. They still can be annotated as unstable + // and propagate this unstability to children, but this annotation is completely + // optional. They inherit stability from their parents when unannotated. + if !matches!( + i.kind, + hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..) + ) { + self.check_missing_stability(i.hir_id, i.span); + } - _ => self.check_missing_stability(i.hir_id, i.span), + // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or + // `rustc_const_stable`. + if self.tcx.features().staged_api + && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const()) + { + self.check_missing_const_stability(i.hir_id, i.span); } intravisit::walk_item(self, i) @@ -421,6 +537,10 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { self.check_missing_stability(md.hir_id, md.span); } + + // Note that we don't need to `check_missing_stability` for default generic parameters, + // as we assume that any default generic parameters without attributes are automatically + // stable (assuming they have not inherited instability from their parent). } fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { @@ -483,6 +603,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { &krate.item.attrs, krate.item.span, AnnotationKind::Required, + InheritDeprecation::Yes, |v| intravisit::walk_crate(v, krate), ); } @@ -538,7 +659,37 @@ impl Visitor<'tcx> for Checker<'tcx> { // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemKind::Impl { of_trait: Some(ref t), items, .. } => { + hir::ItemKind::Impl { of_trait: Some(ref t), self_ty, items, .. } => { + if self.tcx.features().staged_api { + // If this impl block has an #[unstable] attribute, give an + // error if all involved types and traits are stable, because + // it will have no effect. + // See: https://github.com/rust-lang/rust/issues/55436 + if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) = + attr::find_stability(&self.tcx.sess, &item.attrs, item.span) + { + let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true }; + c.visit_ty(self_ty); + c.visit_trait_ref(t); + if c.fully_stable { + let span = item + .attrs + .iter() + .find(|a| a.has_name(sym::unstable)) + .map_or(item.span, |a| a.span); + self.tcx.struct_span_lint_hir( + INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + item.hir_id, + span, + |lint| lint + .build("an `#[unstable]` annotation here has no effect") + .note("see issue #55436 for more information") + .emit() + ); + } + } + } + if let Res::Def(DefKind::Trait, trait_did) = t.path.res { for impl_item_ref in items { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); @@ -598,6 +749,44 @@ impl Visitor<'tcx> for Checker<'tcx> { } } +struct CheckTraitImplStable<'tcx> { + tcx: TyCtxt<'tcx>, + fully_stable: bool, +} + +impl Visitor<'tcx> for CheckTraitImplStable<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) { + if let Some(def_id) = path.res.opt_def_id() { + if let Some(stab) = self.tcx.lookup_stability(def_id) { + self.fully_stable &= stab.level.is_stable(); + } + } + intravisit::walk_path(self, path) + } + + fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) { + if let Res::Def(DefKind::Trait, trait_did) = t.path.res { + if let Some(stab) = self.tcx.lookup_stability(trait_did) { + self.fully_stable &= stab.level.is_stable(); + } + } + intravisit::walk_trait_ref(self, t) + } + + fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { + if let TyKind::Never = t.kind { + self.fully_stable = false; + } + intravisit::walk_ty(self, t) + } +} + /// Given the list of enabled features that were not language features (i.e., that /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. diff --git a/src/librustc_passes/upvars.rs b/compiler/rustc_passes/src/upvars.rs similarity index 100% rename from src/librustc_passes/upvars.rs rename to compiler/rustc_passes/src/upvars.rs diff --git a/src/librustc_passes/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs similarity index 95% rename from src/librustc_passes/weak_lang_items.rs rename to compiler/rustc_passes/src/weak_lang_items.rs index f559d66587..6bc2110bfb 100644 --- a/src/librustc_passes/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -26,6 +26,9 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem if items.eh_personality().is_none() { items.missing.push(LangItem::EhPersonality); } + if tcx.sess.target.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() { + items.missing.push(LangItem::EhCatchTypeinfo); + } { let mut cx = Context { tcx, items }; diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml new file mode 100644 index 0000000000..500d13a8c1 --- /dev/null +++ b/compiler/rustc_plugin_impl/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_plugin_impl" +version = "0.0.0" +build = false +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_middle = { path = "../rustc_middle" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_lint = { path = "../rustc_lint" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_ast = { path = "../rustc_ast" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } diff --git a/src/librustc_plugin_impl/build.rs b/compiler/rustc_plugin_impl/src/build.rs similarity index 100% rename from src/librustc_plugin_impl/build.rs rename to compiler/rustc_plugin_impl/src/build.rs diff --git a/src/librustc_plugin_impl/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs similarity index 89% rename from src/librustc_plugin_impl/lib.rs rename to compiler/rustc_plugin_impl/src/lib.rs index 1eb65dd96b..5bf4d300e9 100644 --- a/src/librustc_plugin_impl/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -6,7 +6,7 @@ //! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) //! of the Unstable Book for some examples. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/src/librustc_plugin_impl/load.rs b/compiler/rustc_plugin_impl/src/load.rs similarity index 100% rename from src/librustc_plugin_impl/load.rs rename to compiler/rustc_plugin_impl/src/load.rs diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml new file mode 100644 index 0000000000..ce83dc1de7 --- /dev/null +++ b/compiler/rustc_privacy/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_privacy" +version = "0.0.0" +edition = "2018" + +[dependencies] +rustc_middle = { path = "../rustc_middle" } +rustc_attr = { path = "../rustc_attr" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_typeck = { path = "../rustc_typeck" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_data_structures = { path = "../rustc_data_structures" } +tracing = "0.1" diff --git a/src/librustc_privacy/lib.rs b/compiler/rustc_privacy/src/lib.rs similarity index 99% rename from src/librustc_privacy/lib.rs rename to compiler/rustc_privacy/src/lib.rs index deb4277cb3..8d1b826ea3 100644 --- a/src/librustc_privacy/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,7 +1,6 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(or_patterns)] #![recursion_limit = "256"] use rustc_attr as attr; @@ -97,6 +96,15 @@ where ty.visit_with(self) } ty::PredicateAtom::RegionOutlives(..) => false, + ty::PredicateAtom::ConstEvaluatable(..) + if self.def_id_visitor.tcx().features().const_evaluatable_checked => + { + // FIXME(const_evaluatable_checked): If the constant used here depends on a + // private function we may have to do something here... + // + // For now, let's just pretend that everything is fine. + false + } _ => bug!("unexpected predicate: {:?}", predicate), } } @@ -119,7 +127,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { let tcx = self.def_id_visitor.tcx(); // InternalSubsts are not visited here because they are visited below in `super_visit_with`. - match ty.kind { + match *ty.kind() { ty::Adt(&ty::AdtDef { did: def_id, .. }, ..) | ty::Foreign(def_id) | ty::FnDef(def_id, ..) @@ -134,7 +142,7 @@ where // Default type visitor doesn't visit signatures of fn types. // Something like `fn() -> Priv {my_func}` is considered a private type even if // `my_func` is public, so we need to visit signatures. - if let ty::FnDef(..) = ty.kind { + if let ty::FnDef(..) = ty.kind() { if tcx.fn_sig(def_id).visit_with(self) { return true; } diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml new file mode 100644 index 0000000000..f38d62dec0 --- /dev/null +++ b/compiler/rustc_query_system/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_query_system" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +tracing = "0.1" +rustc-rayon-core = "0.3.0" +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_macros = { path = "../rustc_macros" } +rustc_index = { path = "../rustc_index" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +parking_lot = "0.11" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_query_system/cache.rs b/compiler/rustc_query_system/src/cache.rs similarity index 100% rename from src/librustc_query_system/cache.rs rename to compiler/rustc_query_system/src/cache.rs diff --git a/src/librustc_query_system/dep_graph/README.md b/compiler/rustc_query_system/src/dep_graph/README.md similarity index 100% rename from src/librustc_query_system/dep_graph/README.md rename to compiler/rustc_query_system/src/dep_graph/README.md diff --git a/src/librustc_query_system/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs similarity index 100% rename from src/librustc_query_system/dep_graph/debug.rs rename to compiler/rustc_query_system/src/dep_graph/debug.rs diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs similarity index 100% rename from src/librustc_query_system/dep_graph/dep_node.rs rename to compiler/rustc_query_system/src/dep_graph/dep_node.rs diff --git a/src/librustc_query_system/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs similarity index 100% rename from src/librustc_query_system/dep_graph/graph.rs rename to compiler/rustc_query_system/src/dep_graph/graph.rs diff --git a/src/librustc_query_system/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs similarity index 100% rename from src/librustc_query_system/dep_graph/mod.rs rename to compiler/rustc_query_system/src/dep_graph/mod.rs diff --git a/src/librustc_query_system/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs similarity index 100% rename from src/librustc_query_system/dep_graph/prev.rs rename to compiler/rustc_query_system/src/dep_graph/prev.rs diff --git a/src/librustc_query_system/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs similarity index 100% rename from src/librustc_query_system/dep_graph/query.rs rename to compiler/rustc_query_system/src/dep_graph/query.rs diff --git a/src/librustc_query_system/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs similarity index 100% rename from src/librustc_query_system/dep_graph/serialized.rs rename to compiler/rustc_query_system/src/dep_graph/serialized.rs diff --git a/src/librustc_query_system/lib.rs b/compiler/rustc_query_system/src/lib.rs similarity index 100% rename from src/librustc_query_system/lib.rs rename to compiler/rustc_query_system/src/lib.rs diff --git a/src/librustc_query_system/query/README.md b/compiler/rustc_query_system/src/query/README.md similarity index 100% rename from src/librustc_query_system/query/README.md rename to compiler/rustc_query_system/src/query/README.md diff --git a/src/librustc_query_system/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs similarity index 100% rename from src/librustc_query_system/query/caches.rs rename to compiler/rustc_query_system/src/query/caches.rs diff --git a/src/librustc_query_system/query/config.rs b/compiler/rustc_query_system/src/query/config.rs similarity index 100% rename from src/librustc_query_system/query/config.rs rename to compiler/rustc_query_system/src/query/config.rs diff --git a/src/librustc_query_system/query/job.rs b/compiler/rustc_query_system/src/query/job.rs similarity index 100% rename from src/librustc_query_system/query/job.rs rename to compiler/rustc_query_system/src/query/job.rs diff --git a/src/librustc_query_system/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs similarity index 100% rename from src/librustc_query_system/query/mod.rs rename to compiler/rustc_query_system/src/query/mod.rs diff --git a/src/librustc_query_system/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs similarity index 100% rename from src/librustc_query_system/query/plumbing.rs rename to compiler/rustc_query_system/src/query/plumbing.rs diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml new file mode 100644 index 0000000000..821f9ea473 --- /dev/null +++ b/compiler/rustc_resolve/Cargo.toml @@ -0,0 +1,29 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_resolve" +version = "0.0.0" +edition = "2018" + +[lib] +test = false +doctest = false + +[dependencies] +bitflags = "1.2.1" +tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } +rustc_arena = { path = "../rustc_arena" } +rustc_middle = { path = "../rustc_middle" } +rustc_ast_lowering = { path = "../rustc_ast_lowering" } +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_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs similarity index 99% rename from src/librustc_resolve/build_reduced_graph.rs rename to compiler/rustc_resolve/src/build_reduced_graph.rs index 761724be57..a48d002b2a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -218,7 +218,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { speculative: bool, ) -> Result> { let parent_scope = &self.parent_scope; - match vis.node { + match vis.kind { ast::VisibilityKind::Public => Ok(ty::Visibility::Public), ast::VisibilityKind::Crate(..) => { Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))) @@ -395,7 +395,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // so prefixes are prepended with crate root segment if necessary. // The root is prepended lazily, when the first non-empty prefix or terminating glob // appears, so imports in braced groups can have roots prepended independently. - let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false }; + let is_glob = matches!(use_tree.kind, ast::UseTreeKind::Glob); let crate_root = match prefix_iter.peek() { Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => { Some(seg.ident.span.ctxt()) @@ -796,23 +796,26 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { vis }; + let mut ret_fields = Vec::with_capacity(vdata.fields().len()); + for field in vdata.fields() { // NOTE: The field may be an expansion placeholder, but expansion sets // correct visibilities for unnamed field placeholders specifically, so the // constructor visibility should still be determined correctly. - if let Ok(field_vis) = self.resolve_visibility_speculative(&field.vis, true) - { - if ctor_vis.is_at_least(field_vis, &*self.r) { - ctor_vis = field_vis; - } + let field_vis = self + .resolve_visibility_speculative(&field.vis, true) + .unwrap_or(ty::Visibility::Public); + if ctor_vis.is_at_least(field_vis, &*self.r) { + ctor_vis = field_vis; } + ret_fields.push(field_vis); } let ctor_res = Res::Def( DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)), self.r.local_def_id(ctor_node_id).to_def_id(), ); self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); - self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis)); + self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis, ret_fields)); } } @@ -964,7 +967,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => { let parent = cstore.def_key(def_id).parent; if let Some(struct_def_id) = parent.map(|index| DefId { index, ..def_id }) { - self.r.struct_constructors.insert(struct_def_id, (res, vis)); + self.r.struct_constructors.insert(struct_def_id, (res, vis, vec![])); } } _ => {} diff --git a/src/librustc_resolve/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs similarity index 99% rename from src/librustc_resolve/check_unused.rs rename to compiler/rustc_resolve/src/check_unused.rs index 5624a6b6ac..89ce89b2e9 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -105,7 +105,7 @@ impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> { // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. if let ast::ItemKind::Use(..) = item.kind { - if item.vis.node.is_pub() || item.span.is_dummy() { + if item.vis.kind.is_pub() || item.span.is_dummy() { return; } } diff --git a/src/librustc_resolve/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs similarity index 100% rename from src/librustc_resolve/def_collector.rs rename to compiler/rustc_resolve/src/def_collector.rs diff --git a/src/librustc_resolve/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs similarity index 99% rename from src/librustc_resolve/diagnostics.rs rename to compiler/rustc_resolve/src/diagnostics.rs index 48e1068b8d..612bc3e749 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -112,7 +112,7 @@ impl<'a> Resolver<'a> { match outer_res { Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => { if let Some(impl_span) = - maybe_impl_defid.and_then(|def_id| self.opt_span(def_id)) + maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id)) { err.span_label( reduce_impl_span_to_impl_keyword(sm, impl_span), @@ -466,7 +466,7 @@ impl<'a> Resolver<'a> { ); err } - ResolutionError::ParamInNonTrivialAnonConst(name) => { + ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => { let mut err = self.session.struct_span_err( span, "generic parameters must not be used inside of non trivial constant values", @@ -478,9 +478,17 @@ impl<'a> Resolver<'a> { name ), ); - err.help( - &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name) - ); + + if is_type { + err.note("type parameters are currently not permitted in anonymous constants"); + } else { + err.help( + &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", + name + ) + ); + } + err } ResolutionError::SelfInTyParamDefault => { @@ -794,7 +802,7 @@ impl<'a> Resolver<'a> { } segms.push(ast::PathSegment::from_ident(ident)); - let path = Path { span: name_binding.span, segments: segms }; + let path = Path { span: name_binding.span, segments: segms, tokens: None }; let did = match res { Res::Def(DefKind::Ctor(..), did) => this.parent(did), _ => res.opt_def_id(), diff --git a/src/librustc_resolve/imports.rs b/compiler/rustc_resolve/src/imports.rs similarity index 99% rename from src/librustc_resolve/imports.rs rename to compiler/rustc_resolve/src/imports.rs index b02fc427d6..adff4542b0 100644 --- a/src/librustc_resolve/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -875,12 +875,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: &'b Import<'b>) -> Option { let orig_vis = import.vis.replace(ty::Visibility::Invisible); - let orig_unusable_binding = match &import.kind { - ImportKind::Single { target_bindings, .. } => { - Some(mem::replace(&mut self.r.unusable_binding, target_bindings[TypeNS].get())) - } - _ => None, - }; let prev_ambiguity_errors_len = self.r.ambiguity_errors.len(); let path_res = self.r.resolve_path( &import.module_path, @@ -891,9 +885,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { import.crate_lint(), ); let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len; - if let Some(orig_unusable_binding) = orig_unusable_binding { - self.r.unusable_binding = orig_unusable_binding; - } import.vis.set(orig_vis); if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res { // Consider erroneous imports used to avoid duplicate diagnostics. @@ -904,7 +895,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Consistency checks, analogous to `finalize_macro_resolutions`. if let Some(initial_module) = import.imported_module.get() { if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity { - span_bug!(import.span, "inconsistent resolution for an import"); + let msg = "inconsistent resolution for an import"; + self.r.session.span_err(import.span, msg); } } else { if self.r.privacy_errors.is_empty() { @@ -926,7 +918,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => { if no_ambiguity { - assert!(import.imported_module.get().is_none()); let err = match self.make_path_suggestion( span, import.module_path.clone(), @@ -1157,7 +1148,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } _ => { if !ident.is_path_segment_keyword() { - format!("no `{}` external crate", ident) + format!("no external crate `{}`", ident) } else { // HACK(eddyb) this shows up for `self` & `super`, which // should work instead - for now keep the same error message. diff --git a/src/librustc_resolve/late.rs b/compiler/rustc_resolve/src/late.rs similarity index 98% rename from src/librustc_resolve/late.rs rename to compiler/rustc_resolve/src/late.rs index d113eb22ab..2c01934b49 100644 --- a/src/librustc_resolve/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -110,6 +110,9 @@ crate enum RibKind<'a> { ItemRibKind(HasGenericParams), /// We're in a constant item. Can't refer to dynamic stuff. + /// + /// The `bool` indicates if this constant may reference generic parameters + /// and is used to only allow generic parameters to be used in trivial constant expressions. ConstantItemRibKind(bool), /// We passed through a module. @@ -188,7 +191,7 @@ crate enum PathSource<'a> { // Paths in struct expressions and patterns `Path { .. }`. Struct, // Paths in tuple struct patterns `Path(..)`. - TupleStruct(Span), + TupleStruct(Span, &'a [Span]), // `m::A::B` in `::B::C`. TraitItem(Namespace), } @@ -197,7 +200,7 @@ impl<'a> PathSource<'a> { fn namespace(self) -> Namespace { match self { PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS, - PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(_) => ValueNS, + PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) => ValueNS, PathSource::TraitItem(ns) => ns, } } @@ -208,7 +211,7 @@ impl<'a> PathSource<'a> { | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct - | PathSource::TupleStruct(_) => true, + | PathSource::TupleStruct(..) => true, PathSource::Trait(_) | PathSource::TraitItem(..) => false, } } @@ -219,7 +222,7 @@ impl<'a> PathSource<'a> { PathSource::Trait(_) => "trait", PathSource::Pat => "unit struct, unit variant or constant", PathSource::Struct => "struct, variant or union type", - PathSource::TupleStruct(_) => "tuple struct or tuple variant", + PathSource::TupleStruct(..) => "tuple struct or tuple variant", PathSource::TraitItem(ns) => match ns { TypeNS => "associated type", ValueNS => "method or associated constant", @@ -305,7 +308,7 @@ impl<'a> PathSource<'a> { | Res::SelfCtor(..) => true, _ => false, }, - PathSource::TupleStruct(_) => match res { + PathSource::TupleStruct(..) => match res { Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, _ => false, }, @@ -340,8 +343,8 @@ impl<'a> PathSource<'a> { (PathSource::Struct, false) => error_code!(E0422), (PathSource::Expr(..), true) => error_code!(E0423), (PathSource::Expr(..), false) => error_code!(E0425), - (PathSource::Pat | PathSource::TupleStruct(_), true) => error_code!(E0532), - (PathSource::Pat | PathSource::TupleStruct(_), false) => error_code!(E0531), + (PathSource::Pat | PathSource::TupleStruct(..), true) => error_code!(E0532), + (PathSource::Pat | PathSource::TupleStruct(..), false) => error_code!(E0531), (PathSource::TraitItem(..), true) => error_code!(E0575), (PathSource::TraitItem(..), false) => error_code!(E0576), } @@ -378,6 +381,9 @@ struct DiagnosticMetadata<'ast> { /// Only used for better errors on `let : ;`. current_let_binding: Option<(Span, Option, Option)>, + + /// Used to detect possible `if let` written without `let` and to provide structured suggestion. + in_if_condition: Option<&'ast Expr>, } struct LateResolutionVisitor<'a, 'b, 'ast> { @@ -403,12 +409,12 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// /// In particular, rustdoc uses this to avoid giving errors for `cfg()` items. /// In most cases this will be `None`, in which case errors will always be reported. - /// If it is `Some(_)`, then it will be updated when entering a nested function or trait body. + /// If it is `true`, then it will be updated when entering a nested function or trait body. in_func_body: bool, } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. -impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { +impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_item(&mut self, item: &'ast Item) { let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item)); // Always report errors in items we just entered. @@ -656,7 +662,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } -impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { +impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. @@ -845,7 +851,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_current_self_item(item, |this| { this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { let item_def_id = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| { visit::walk_item(this, item); }); }); @@ -1028,7 +1034,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let mut add_bindings_for_ns = |ns| { let parent_rib = self.ribs[ns] .iter() - .rfind(|r| if let ItemRibKind(_) = r.kind { true } else { false }) + .rfind(|r| matches!(r.kind, ItemRibKind(_))) .expect("associated item outside of an item"); seen_bindings .extend(parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span))); @@ -1212,7 +1218,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Resolve the trait reference, if necessary. this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { let item_def_id = this.r.local_def_id(item_id).to_def_id(); - this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| { if let Some(trait_ref) = opt_trait_reference.as_ref() { // Resolve type arguments in the trait path. visit::walk_trait_ref(this, trait_ref); @@ -1536,8 +1542,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings)); self.r.record_partial_res(pat.id, PartialRes::new(res)); } - PatKind::TupleStruct(ref path, ..) => { - self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct(pat.span)); + PatKind::TupleStruct(ref path, ref sub_patterns) => { + self.smart_resolve_path( + pat.id, + None, + path, + PathSource::TupleStruct( + pat.span, + self.r.arenas.alloc_pattern_spans(sub_patterns.iter().map(|p| p.span)), + ), + ); } PatKind::Path(ref qself, ref path) => { self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat); @@ -1964,7 +1978,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if qself.is_none() { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); - let path = Path { segments: path.iter().map(path_seg).collect(), span }; + let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; if let Ok((_, res)) = self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false) { @@ -2199,7 +2213,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::If(ref cond, ref then, ref opt_else) => { self.with_rib(ValueNS, NormalRibKind, |this| { + let old = this.diagnostic_metadata.in_if_condition.replace(cond); this.visit_expr(cond); + this.diagnostic_metadata.in_if_condition = old; this.visit_block(then); }); if let Some(expr) = opt_else { diff --git a/src/librustc_resolve/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs similarity index 93% rename from src/librustc_resolve/late/diagnostics.rs rename to compiler/rustc_resolve/src/late/diagnostics.rs index d392967af3..521ea7ad18 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -16,6 +16,7 @@ use rustc_hir::def::{self, CtorKind, DefKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::PrimTy; use rustc_session::config::nightly_options; +use rustc_session::parse::feature_err; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, DUMMY_SP}; @@ -83,13 +84,14 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str let enum_path = ast::Path { span: suggestion.path.span, segments: suggestion.path.segments[0..path_len - 1].to_vec(), + tokens: None, }; let enum_path_string = path_names_to_string(&enum_path); (variant_path_string, enum_path_string) } -impl<'a> LateResolutionVisitor<'a, '_, '_> { +impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn def_span(&self, def_id: DefId) -> Option { match def_id.krate { LOCAL_CRATE => self.r.opt_span(def_id), @@ -176,6 +178,19 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { let code = source.error_code(res.is_some()); let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code); + match (source, self.diagnostic_metadata.in_if_condition) { + (PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "you might have meant to use pattern matching", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + self.r.session.if_let_suggestions.borrow_mut().insert(*span); + } + _ => {} + } + let is_assoc_fn = self.self_type_is_available(span); // Emit help message for fake-self from other languages (e.g., `this` in Javascript). if ["this", "my"].contains(&&*item_str.as_str()) && is_assoc_fn { @@ -609,12 +624,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { ); } } - PathSource::Expr(_) | PathSource::TupleStruct(_) | PathSource::Pat => { + PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => { let span = match &source { PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. })) - | PathSource::TupleStruct(span) => { + | PathSource::TupleStruct(span, _) => { // We want the main underline to cover the suggested code as well for // cleaner output. err.set_span(*span); @@ -626,7 +641,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { err.span_label(span, &format!("`{}` defined here", path_str)); } let (tail, descr, applicability) = match source { - PathSource::Pat | PathSource::TupleStruct(_) => { + PathSource::Pat | PathSource::TupleStruct(..) => { ("", "pattern", Applicability::MachineApplicable) } _ => (": val", "literal", Applicability::HasPlaceholders), @@ -691,7 +706,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { } ( Res::Def(DefKind::Enum, def_id), - PathSource::TupleStruct(_) | PathSource::Expr(..), + PathSource::TupleStruct(..) | PathSource::Expr(..), ) => { if self .diagnostic_metadata @@ -731,15 +746,50 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { } } (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { - if let Some((ctor_def, ctor_vis)) = self.r.struct_constructors.get(&def_id).cloned() + if let Some((ctor_def, ctor_vis, fields)) = + self.r.struct_constructors.get(&def_id).cloned() { let accessible_ctor = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); if is_expected(ctor_def) && !accessible_ctor { - err.span_label( - span, - "constructor is not visible here due to private fields".to_string(), - ); + let mut better_diag = false; + if let PathSource::TupleStruct(_, pattern_spans) = source { + if pattern_spans.len() > 0 && fields.len() == pattern_spans.len() { + let non_visible_spans: Vec = fields + .iter() + .zip(pattern_spans.iter()) + .filter_map(|(vis, span)| { + match self + .r + .is_accessible_from(*vis, self.parent_scope.module) + { + true => None, + false => Some(*span), + } + }) + .collect(); + // Extra check to be sure + if non_visible_spans.len() > 0 { + let mut m: rustc_span::MultiSpan = + non_visible_spans.clone().into(); + non_visible_spans.into_iter().for_each(|s| { + m.push_span_label(s, "private field".to_string()) + }); + err.span_note( + m, + "constructor is not visible here due to private fields", + ); + better_diag = true; + } + } + } + + if !better_diag { + err.span_label( + span, + "constructor is not visible here due to private fields".to_string(), + ); + } } } else { bad_struct_syntax_suggestion(def_id); @@ -1052,7 +1102,8 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { path_segments.push(ast::PathSegment::from_ident(ident)); let module_def_id = module.def_id().unwrap(); if module_def_id == def_id { - let path = Path { span: name_binding.span, segments: path_segments }; + let path = + Path { span: name_binding.span, segments: path_segments, tokens: None }; result = Some(( module, ImportSuggestion { @@ -1082,7 +1133,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { if let Res::Def(DefKind::Variant, _) = name_binding.res() { let mut segms = enum_import_suggestion.path.segments.clone(); segms.push(ast::PathSegment::from_ident(ident)); - variants.push(Path { span: name_binding.span, segments: segms }); + variants.push(Path { span: name_binding.span, segments: segms, tokens: None }); } }); variants @@ -1368,13 +1419,13 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { if snippet.starts_with('&') && !snippet.starts_with("&'") { introduce_suggestion .push((param.span, format!("&{} {}", lt_name, &snippet[1..]))); - } else if snippet.starts_with("&'_ ") { + } else if let Some(stripped) = snippet.strip_prefix("&'_ ") { introduce_suggestion - .push((param.span, format!("&{} {}", lt_name, &snippet[4..]))); + .push((param.span, format!("&{} {}", lt_name, stripped))); } } } - introduce_suggestion.push((*for_span, for_sugg.to_string())); + introduce_suggestion.push((*for_span, for_sugg)); introduce_suggestion.push((span, formatter(<_name))); err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect); } @@ -1484,7 +1535,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } }; - let lifetime_names: Vec<_> = lifetime_names.into_iter().collect(); + let lifetime_names: Vec<_> = lifetime_names.iter().collect(); match (&lifetime_names[..], snippet.as_deref()) { ([name], Some("&")) => { suggest_existing(err, &name.as_str()[..], &|name| format!("&{} ", name)); @@ -1549,4 +1600,32 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { _ => {} } } + + /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics` so + /// this function will emit an error if `min_const_generics` is enabled, the body identified by + /// `body_id` is an anonymous constant and `lifetime_ref` is non-static. + crate fn maybe_emit_forbidden_non_static_lifetime_error( + &self, + body_id: hir::BodyId, + lifetime_ref: &'tcx hir::Lifetime, + ) { + let is_anon_const = matches!( + self.tcx.def_kind(self.tcx.hir().body_owner_def_id(body_id)), + hir::def::DefKind::AnonConst + ); + let is_allowed_lifetime = matches!( + lifetime_ref.name, + hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore + ); + + if self.tcx.features().min_const_generics && is_anon_const && !is_allowed_lifetime { + feature_err( + &self.tcx.sess.parse_sess, + sym::const_generics, + lifetime_ref.span, + "a non-static lifetime is not allowed in a `const`", + ) + .emit(); + } + } } diff --git a/src/librustc_resolve/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs similarity index 99% rename from src/librustc_resolve/late/lifetimes.rs rename to compiler/rustc_resolve/src/late/lifetimes.rs index 31360d4747..072fb509b1 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1777,6 +1777,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let result = loop { match *scope { Scope::Body { id, s } => { + // Non-static lifetimes are prohibited in anonymous constants under + // `min_const_generics`. + self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref); + outermost_body = Some(id); scope = s; } diff --git a/src/librustc_resolve/lib.rs b/compiler/rustc_resolve/src/lib.rs similarity index 97% rename from src/librustc_resolve/lib.rs rename to compiler/rustc_resolve/src/lib.rs index f2319bfe64..283db1404d 100644 --- a/src/librustc_resolve/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -8,7 +8,7 @@ //! //! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(nll)] @@ -221,7 +221,7 @@ enum ResolutionError<'a> { /// generic parameters must not be used inside of non trivial constant values. /// /// This error is only emitted when using `min_const_generics`. - ParamInNonTrivialAnonConst(Symbol), + ParamInNonTrivialAnonConst { name: Symbol, is_type: bool }, /// Error E0735: type parameters with a default cannot use `Self` SelfInTyParamDefault, /// Error E0767: use of unreachable label @@ -534,11 +534,8 @@ impl<'a> ModuleData<'a> { if ns != TypeNS { return; } - match binding.res() { - Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { - collected_traits.push((name, binding)) - } - _ => (), + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() { + collected_traits.push((name, binding)) } }); *traits = Some(collected_traits.into_boxed_slice()); @@ -867,6 +864,12 @@ pub struct ExternPreludeEntry<'a> { pub introduced_by_item: bool, } +/// Used for better errors for E0773 +enum BuiltinMacroState { + NotYetSeen(SyntaxExtension), + AlreadySeen(Span), +} + /// The main resolver class. /// /// This is the visitor that walks the whole crate. @@ -960,7 +963,7 @@ pub struct Resolver<'a> { crate_loader: CrateLoader<'a>, macro_names: FxHashSet, - builtin_macros: FxHashMap, + builtin_macros: FxHashMap, registered_attrs: FxHashSet, registered_tools: FxHashSet, macro_use_prelude: FxHashMap>, @@ -999,7 +1002,8 @@ pub struct Resolver<'a> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. - struct_constructors: DefIdMap<(Res, ty::Visibility)>, + /// Also includes of list of each fields visibility + struct_constructors: DefIdMap<(Res, ty::Visibility, Vec)>, /// Features enabled for this crate. active_features: FxHashSet, @@ -1036,6 +1040,7 @@ pub struct ResolverArenas<'a> { name_resolutions: TypedArena>>, macro_rules_bindings: TypedArena>, ast_paths: TypedArena, + pattern_spans: TypedArena, } impl<'a> ResolverArenas<'a> { @@ -1067,6 +1072,9 @@ impl<'a> ResolverArenas<'a> { fn alloc_ast_paths(&'a self, paths: &[ast::Path]) -> &'a [ast::Path] { self.ast_paths.alloc_from_iter(paths.iter().cloned()) } + fn alloc_pattern_spans(&'a self, spans: impl Iterator) -> &'a [Span] { + self.pattern_spans.alloc_from_iter(spans) + } } impl<'a> AsMut> for Resolver<'a> { @@ -2385,8 +2393,12 @@ impl<'a> Resolver<'a> { Res::Def(DefKind::Mod, _) => true, _ => false, }; - let mut candidates = - self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod); + // Don't look up import candidates if this is a speculative resolve + let mut candidates = if record_used { + self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod) + } else { + Vec::new() + }; candidates.sort_by_cached_key(|c| { (c.path.segments.len(), pprust::path_to_string(&c.path)) }); @@ -2403,7 +2415,14 @@ impl<'a> Resolver<'a> { (format!("maybe a missing crate `{}`?", ident), None) } } else if i == 0 { - (format!("use of undeclared type or module `{}`", ident), None) + if ident + .name + .with(|n| n.chars().next().map_or(false, |c| c.is_ascii_uppercase())) + { + (format!("use of undeclared type `{}`", ident), None) + } else { + (format!("use of undeclared crate or module `{}`", ident), None) + } } else { let mut msg = format!("could not find `{}` in `{}`", ident, path[i - 1].ident); @@ -2517,7 +2536,7 @@ impl<'a> Resolver<'a> { &mut self, rib_index: usize, rib_ident: Ident, - res: Res, + mut res: Res, record_used: bool, span: Span, all_ribs: &[Rib<'a>], @@ -2607,13 +2626,23 @@ impl<'a> Resolver<'a> { ConstantItemRibKind(trivial) => { // HACK(min_const_generics): We currently only allow `N` or `{ N }`. if !trivial && self.session.features_untracked().min_const_generics { - if record_used { - self.report_error( - span, - ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name), - ); + // HACK(min_const_generics): If we encounter `Self` in an anonymous constant + // we can't easily tell if it's generic at this stage, so we instead remember + // this and then enforce the self type to be concrete later on. + if let Res::SelfTy(trait_def, Some((impl_def, _))) = res { + res = Res::SelfTy(trait_def, Some((impl_def, true))); + } else { + if record_used { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: true, + }, + ); + } + return Res::Err; } - return Res::Err; } if in_ty_param_default { @@ -2687,7 +2716,10 @@ impl<'a> Resolver<'a> { if record_used { self.report_error( span, - ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name), + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: false, + }, ); } return Res::Err; @@ -3172,6 +3204,7 @@ impl<'a> Resolver<'a> { .chain(path_str.split("::").skip(1).map(Ident::from_str)) .map(|i| self.new_ast_path_segment(i)) .collect(), + tokens: None, } } else { ast::Path { @@ -3181,6 +3214,7 @@ impl<'a> Resolver<'a> { .map(Ident::from_str) .map(|i| self.new_ast_path_segment(i)) .collect(), + tokens: None, } }; let module = self.get_module(module_id); @@ -3200,7 +3234,7 @@ impl<'a> Resolver<'a> { &Segment::from_path(path), Some(ns), parent_scope, - true, + false, path.span, CrateLint::No, ) { diff --git a/src/librustc_resolve/macros.rs b/compiler/rustc_resolve/src/macros.rs similarity index 97% rename from src/librustc_resolve/macros.rs rename to compiler/rustc_resolve/src/macros.rs index 51518d63ae..bea7138964 100644 --- a/src/librustc_resolve/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -3,7 +3,7 @@ use crate::imports::ImportResolver; use crate::Namespace::*; -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy}; +use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy}; use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; use rustc_ast::{self as ast, NodeId}; @@ -11,6 +11,7 @@ use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::struct_span_err; use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension}; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; @@ -166,7 +167,7 @@ impl<'a> ResolverExpand for Resolver<'a> { } fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) { - if self.builtin_macros.insert(ident.name, ext).is_some() { + if self.builtin_macros.insert(ident.name, BuiltinMacroState::NotYetSeen(ext)).is_some() { self.session .span_err(ident.span, &format!("built-in macro `{}` was already defined", ident)); } @@ -1076,10 +1077,23 @@ impl<'a> Resolver<'a> { if result.is_builtin { // The macro was marked with `#[rustc_builtin_macro]`. - if let Some(ext) = self.builtin_macros.remove(&item.ident.name) { + if let Some(builtin_macro) = self.builtin_macros.get_mut(&item.ident.name) { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. - result.kind = ext.kind; + // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'. + match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) { + BuiltinMacroState::NotYetSeen(ext) => result.kind = ext.kind, + BuiltinMacroState::AlreadySeen(span) => { + struct_span_err!( + self.session, + item.span, + E0773, + "attempted to define built-in macro more than once" + ) + .span_note(span, "previously defined here") + .emit(); + } + } } else { let msg = format!("cannot find a built-in macro with name `{}`", item.ident); self.session.span_err(item.span, &msg); diff --git a/compiler/rustc_save_analysis/Cargo.toml b/compiler/rustc_save_analysis/Cargo.toml new file mode 100644 index 0000000000..da1bed37a9 --- /dev/null +++ b/compiler/rustc_save_analysis/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_save_analysis" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_lexer = { path = "../rustc_lexer" } +serde_json = "1" +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rls-data = "0.19" +rls-span = "0.5" diff --git a/src/librustc_save_analysis/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs similarity index 99% rename from src/librustc_save_analysis/dump_visitor.rs rename to compiler/rustc_save_analysis/src/dump_visitor.rs index 77aecefe5a..ce484858cb 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -14,7 +14,7 @@ //! recording the output. use rustc_ast as ast; -use rustc_ast::{token, walk_list}; +use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res}; @@ -1207,9 +1207,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { // Otherwise it's a span with wrong macro expansion info, which // we don't want to track anyway, since it's probably macro-internal `use` - if let Some(sub_span) = - self.span.sub_span_of_token(item.span, token::BinOp(token::Star)) - { + if let Some(sub_span) = self.span.sub_span_of_star(item.span) { if !self.span.filter_generated(item.span) { let access = access_from!(self.save_ctxt, item, item.hir_id); let span = self.span_from_span(sub_span); diff --git a/src/librustc_save_analysis/dumper.rs b/compiler/rustc_save_analysis/src/dumper.rs similarity index 100% rename from src/librustc_save_analysis/dumper.rs rename to compiler/rustc_save_analysis/src/dumper.rs diff --git a/src/librustc_save_analysis/lib.rs b/compiler/rustc_save_analysis/src/lib.rs similarity index 96% rename from src/librustc_save_analysis/lib.rs rename to compiler/rustc_save_analysis/src/lib.rs index 629051c182..f6434689fe 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![feature(or_patterns)] #![recursion_limit = "256"] @@ -21,7 +21,7 @@ use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string}; use rustc_middle::hir::map::Map; use rustc_middle::middle::cstore::ExternCrate; use rustc_middle::middle::privacy::AccessLevels; -use rustc_middle::ty::{self, DefIdTree, TyCtxt}; +use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, Input, OutputType}; use rustc_session::output::{filename_for_metadata, out_filename}; @@ -438,7 +438,7 @@ impl<'tcx> SaveContext<'tcx> { .next() .map(|item| item.def_id); } - qualname.push_str(">"); + qualname.push('>'); (qualname, trait_id, decl_id, docs, attrs) } @@ -524,12 +524,12 @@ impl<'tcx> SaveContext<'tcx> { pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option { let ty = self.typeck_results().expr_ty_adjusted_opt(expr)?; - if matches!(ty.kind, ty::Error(_)) { + if matches!(ty.kind(), ty::Error(_)) { return None; } match expr.kind { hir::ExprKind::Field(ref sub_ex, ident) => { - match self.typeck_results().expr_ty_adjusted(&sub_ex).kind { + match self.typeck_results().expr_ty_adjusted(&sub_ex).kind() { ty::Adt(def, _) if !def.is_enum() => { let variant = &def.non_enum_variant(); filter!(self.span_utils, ident.span); @@ -551,7 +551,7 @@ impl<'tcx> SaveContext<'tcx> { } } } - hir::ExprKind::Struct(qpath, ..) => match ty.kind { + hir::ExprKind::Struct(qpath, ..) => match ty.kind() { ty::Adt(def, _) => { let sub_span = qpath.last_segment_span(); filter!(self.span_utils, sub_span); @@ -989,32 +989,34 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( config: Option, mut handler: H, ) { - tcx.dep_graph.with_ignore(|| { - info!("Dumping crate {}", cratename); - - // Privacy checking requires and is done after type checking; use a - // fallback in case the access levels couldn't have been correctly computed. - let access_levels = match tcx.sess.compile_status() { - Ok(..) => tcx.privacy_access_levels(LOCAL_CRATE), - Err(..) => tcx.arena.alloc(AccessLevels::default()), - }; + with_no_trimmed_paths(|| { + tcx.dep_graph.with_ignore(|| { + info!("Dumping crate {}", cratename); + + // Privacy checking requires and is done after type checking; use a + // fallback in case the access levels couldn't have been correctly computed. + let access_levels = match tcx.sess.compile_status() { + Ok(..) => tcx.privacy_access_levels(LOCAL_CRATE), + Err(..) => tcx.arena.alloc(AccessLevels::default()), + }; - let save_ctxt = SaveContext { - tcx, - maybe_typeck_results: None, - access_levels: &access_levels, - span_utils: SpanUtils::new(&tcx.sess), - config: find_config(config), - impl_counter: Cell::new(0), - }; + let save_ctxt = SaveContext { + tcx, + maybe_typeck_results: None, + access_levels: &access_levels, + span_utils: SpanUtils::new(&tcx.sess), + config: find_config(config), + impl_counter: Cell::new(0), + }; - let mut visitor = DumpVisitor::new(save_ctxt); + let mut visitor = DumpVisitor::new(save_ctxt); - visitor.dump_crate_info(cratename, tcx.hir().krate()); - visitor.dump_compilation_options(input, cratename); - visitor.process_crate(tcx.hir().krate()); + visitor.dump_crate_info(cratename, tcx.hir().krate()); + visitor.dump_compilation_options(input, cratename); + visitor.process_crate(tcx.hir().krate()); - handler.save(&visitor.save_ctxt, &visitor.analysis()) + handler.save(&visitor.save_ctxt, &visitor.analysis()) + }) }) } diff --git a/src/librustc_save_analysis/sig.rs b/compiler/rustc_save_analysis/src/sig.rs similarity index 99% rename from src/librustc_save_analysis/sig.rs rename to compiler/rustc_save_analysis/src/sig.rs index 6dd7f89d59..747e198cd9 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -497,7 +497,7 @@ impl<'hir> Sig for hir::Item<'hir> { sig.text.push_str(&bounds_to_string(bounds)); } // FIXME where clause - sig.text.push_str(";"); + sig.text.push(';'); Ok(sig) } diff --git a/src/librustc_save_analysis/span_utils.rs b/compiler/rustc_save_analysis/src/span_utils.rs similarity index 50% rename from src/librustc_save_analysis/span_utils.rs rename to compiler/rustc_save_analysis/src/span_utils.rs index d5f992b0de..edcd492577 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/compiler/rustc_save_analysis/src/span_utils.rs @@ -1,6 +1,6 @@ use crate::generated_code; -use rustc_ast::token::{self, TokenKind}; -use rustc_parse::lexer::{self, StringReader}; +use rustc_data_structures::sync::Lrc; +use rustc_lexer::{tokenize, TokenKind}; use rustc_session::Session; use rustc_span::*; @@ -43,61 +43,37 @@ impl<'a> SpanUtils<'a> { } } - pub fn retokenise_span(&self, span: Span) -> StringReader<'a> { - lexer::StringReader::retokenize(&self.sess.parse_sess, span) - } - - pub fn sub_span_of_token(&self, span: Span, tok: TokenKind) -> Option { - let mut toks = self.retokenise_span(span); - loop { - let next = toks.next_token(); - if next == token::Eof { - return None; - } - if next == tok { - return Some(next.span); - } + /// Finds the span of `*` token withing the larger `span`. + pub fn sub_span_of_star(&self, mut span: Span) -> Option { + let begin = self.sess.source_map().lookup_byte_offset(span.lo()); + let end = self.sess.source_map().lookup_byte_offset(span.hi()); + // Make the range zero-length if the span is invalid. + if begin.sf.start_pos != end.sf.start_pos { + span = span.shrink_to_lo(); } - } - // // Return the name for a macro definition (identifier after first `!`) - // pub fn span_for_macro_def_name(&self, span: Span) -> Option { - // let mut toks = self.retokenise_span(span); - // loop { - // let ts = toks.real_token(); - // if ts == token::Eof { - // return None; - // } - // if ts == token::Not { - // let ts = toks.real_token(); - // if ts.kind.is_ident() { - // return Some(ts.sp); - // } else { - // return None; - // } - // } - // } - // } + let sf = Lrc::clone(&begin.sf); - // // Return the name for a macro use (identifier before first `!`). - // pub fn span_for_macro_use_name(&self, span:Span) -> Option { - // let mut toks = self.retokenise_span(span); - // let mut prev = toks.real_token(); - // loop { - // if prev == token::Eof { - // return None; - // } - // let ts = toks.real_token(); - // if ts == token::Not { - // if prev.kind.is_ident() { - // return Some(prev.sp); - // } else { - // return None; - // } - // } - // prev = ts; - // } - // } + self.sess.source_map().ensure_source_file_source_present(Lrc::clone(&sf)); + let src = + sf.src.clone().or_else(|| sf.external_src.borrow().get_source().map(Lrc::clone))?; + let to_index = |pos: BytePos| -> usize { (pos - sf.start_pos).0 as usize }; + let text = &src[to_index(span.lo())..to_index(span.hi())]; + let start_pos = { + let mut pos = 0; + tokenize(text) + .map(|token| { + let start = pos; + pos += token.len; + (start, token) + }) + .find(|(_pos, token)| token.kind == TokenKind::Star)? + .0 + }; + let lo = span.lo() + BytePos(start_pos as u32); + let hi = lo + BytePos(1); + Some(span.with_lo(lo).with_hi(hi)) + } /// Return true if the span is generated code, and /// it is not a subspan of the root callsite. diff --git a/src/librustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml similarity index 70% rename from src/librustc_serialize/Cargo.toml rename to compiler/rustc_serialize/Cargo.toml index 939e6a59ba..16c5dff734 100644 --- a/src/librustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -4,13 +4,9 @@ name = "rustc_serialize" version = "0.0.0" edition = "2018" -[lib] -name = "rustc_serialize" -path = "lib.rs" - [dependencies] indexmap = "1" smallvec = { version = "1.0", features = ["union", "may_dangle"] } [dev-dependencies] -rustc_macros = { path = "../librustc_macros" } +rustc_macros = { path = "../rustc_macros" } diff --git a/src/librustc_serialize/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs similarity index 100% rename from src/librustc_serialize/collection_impls.rs rename to compiler/rustc_serialize/src/collection_impls.rs diff --git a/src/librustc_serialize/json.rs b/compiler/rustc_serialize/src/json.rs similarity index 100% rename from src/librustc_serialize/json.rs rename to compiler/rustc_serialize/src/json.rs diff --git a/src/librustc_serialize/json/tests.rs b/compiler/rustc_serialize/src/json/tests.rs similarity index 100% rename from src/librustc_serialize/json/tests.rs rename to compiler/rustc_serialize/src/json/tests.rs diff --git a/src/librustc_serialize/leb128.rs b/compiler/rustc_serialize/src/leb128.rs similarity index 100% rename from src/librustc_serialize/leb128.rs rename to compiler/rustc_serialize/src/leb128.rs diff --git a/src/librustc_serialize/lib.rs b/compiler/rustc_serialize/src/lib.rs similarity index 83% rename from src/librustc_serialize/lib.rs rename to compiler/rustc_serialize/src/lib.rs index 265b3b95e9..fab29f29e8 100644 --- a/src/librustc_serialize/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -5,7 +5,7 @@ Core encoding and decoding interfaces. */ #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))) )] @@ -13,6 +13,7 @@ Core encoding and decoding interfaces. #![feature(never_type)] #![feature(nll)] #![feature(associated_type_bounds)] +#![feature(min_const_generics)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] diff --git a/src/librustc_serialize/opaque.rs b/compiler/rustc_serialize/src/opaque.rs similarity index 100% rename from src/librustc_serialize/opaque.rs rename to compiler/rustc_serialize/src/opaque.rs diff --git a/src/librustc_serialize/serialize.rs b/compiler/rustc_serialize/src/serialize.rs similarity index 96% rename from src/librustc_serialize/serialize.rs rename to compiler/rustc_serialize/src/serialize.rs index c0e23b89a6..aa305f3c7f 100644 --- a/src/librustc_serialize/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -539,12 +539,8 @@ impl> Encodable for [T] { impl> Encodable for Vec { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))? - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } @@ -560,22 +556,18 @@ impl> Decodable for Vec { } } -impl Encodable for [u8; 20] { +impl, const N: usize> Encodable for [T; N] { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))? - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } -impl Decodable for [u8; 20] { - fn decode(d: &mut D) -> Result<[u8; 20], D::Error> { +impl Decodable for [u8; N] { + fn decode(d: &mut D) -> Result<[u8; N], D::Error> { d.read_seq(|d, len| { - assert!(len == 20); - let mut v = [0u8; 20]; + assert!(len == N); + let mut v = [0u8; N]; for i in 0..len { v[i] = d.read_seq_elt(i, |d| Decodable::decode(d))?; } @@ -589,12 +581,8 @@ where [T]: ToOwned>, { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))? - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } diff --git a/src/librustc_serialize/tests/json.rs b/compiler/rustc_serialize/tests/json.rs similarity index 100% rename from src/librustc_serialize/tests/json.rs rename to compiler/rustc_serialize/tests/json.rs diff --git a/src/librustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs similarity index 100% rename from src/librustc_serialize/tests/leb128.rs rename to compiler/rustc_serialize/tests/leb128.rs diff --git a/src/librustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs similarity index 100% rename from src/librustc_serialize/tests/opaque.rs rename to compiler/rustc_serialize/tests/opaque.rs diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml new file mode 100644 index 0000000000..cdff1662fd --- /dev/null +++ b/compiler/rustc_session/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_session" +version = "0.0.0" +edition = "2018" + +[dependencies] +bitflags = "1.2.1" +getopts = "0.2" +rustc_macros = { path = "../rustc_macros" } +tracing = "0.1" +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_target = { path = "../rustc_target" } +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" } diff --git a/src/librustc_session/cgu_reuse_tracker.rs b/compiler/rustc_session/src/cgu_reuse_tracker.rs similarity index 100% rename from src/librustc_session/cgu_reuse_tracker.rs rename to compiler/rustc_session/src/cgu_reuse_tracker.rs diff --git a/src/librustc_session/code_stats.rs b/compiler/rustc_session/src/code_stats.rs similarity index 100% rename from src/librustc_session/code_stats.rs rename to compiler/rustc_session/src/code_stats.rs diff --git a/src/librustc_session/config.rs b/compiler/rustc_session/src/config.rs similarity index 95% rename from src/librustc_session/config.rs rename to compiler/rustc_session/src/config.rs index 1808a0ca59..ab96b0333f 100644 --- a/src/librustc_session/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,6 +12,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::impl_stable_hash_via_hash; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_target::abi::{Align, TargetDataLayout}; use rustc_target::spec::{Target, TargetTriple}; use crate::parse::CrateConfig; @@ -163,6 +164,21 @@ pub enum LtoCli { Unspecified, } +/// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a +/// document highlighting each span of every statement (including terminators). `Terminator` and +/// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a +/// computed span for the block, representing the entire range, covering the block's terminator and +/// all of its statements. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum MirSpanview { + /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement` + Statement, + /// `-Z dump_mir_spanview=terminator` + Terminator, + /// `-Z dump_mir_spanview=block` + Block, +} + #[derive(Clone, PartialEq, Hash)] pub enum LinkerPluginLto { LinkerPlugin(PathBuf), @@ -313,6 +329,23 @@ impl Default for ErrorOutputType { } } +/// Parameter to control path trimming. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum TrimmedDefPaths { + /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query + Never, + /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug` + Always, + /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug` + GoodPath, +} + +impl Default for TrimmedDefPaths { + fn default() -> Self { + Self::Never + } +} + /// Use tree-based collections to cheaply get a deterministic `Hash` implementation. /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break /// dependency tracking for command-line arguments. @@ -549,9 +582,9 @@ impl OutputFilenames { if !ext.is_empty() { if !extension.is_empty() { - extension.push_str("."); + extension.push('.'); extension.push_str(RUST_CGU_EXT); - extension.push_str("."); + extension.push('.'); } extension.push_str(ext); @@ -606,6 +639,7 @@ impl Default for Options { unstable_features: UnstableFeatures::Disallow, debug_assertions: true, actually_rustdoc: false, + trimmed_def_paths: TrimmedDefPaths::default(), cli_forced_codegen_units: None, cli_forced_thinlto_off: false, remap_path_prefix: Vec::new(), @@ -715,6 +749,9 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { let min_atomic_width = sess.target.target.min_atomic_width(); let max_atomic_width = sess.target.target.max_atomic_width(); let atomic_cas = sess.target.target.options.atomic_cas; + let layout = TargetDataLayout::parse(&sess.target.target).unwrap_or_else(|err| { + sess.fatal(&err); + }); let mut ret = FxHashSet::default(); ret.reserve(6); // the minimum number of insertions @@ -736,18 +773,27 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { if sess.target.target.options.has_elf_tls { ret.insert((sym::target_thread_local, None)); } - for &i in &[8, 16, 32, 64, 128] { + for &(i, align) in &[ + (8, layout.i8_align.abi), + (16, layout.i16_align.abi), + (32, layout.i32_align.abi), + (64, layout.i64_align.abi), + (128, layout.i128_align.abi), + ] { if i >= min_atomic_width && i <= max_atomic_width { - let mut insert_atomic = |s| { + let mut insert_atomic = |s, align: Align| { ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s)))); if atomic_cas { ret.insert((sym::target_has_atomic, Some(Symbol::intern(s)))); } + if align.bits() == i { + ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s)))); + } }; let s = i.to_string(); - insert_atomic(&s); + insert_atomic(&s, align); if &s == wordsz { - insert_atomic("ptr"); + insert_atomic("ptr", layout.pointer_align.abi); } } } @@ -785,10 +831,11 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo user_cfg } -pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config { - let target = Target::search(&opts.target_triple).unwrap_or_else(|e| { +pub fn build_target_config(opts: &Options, target_override: Option) -> Config { + let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok); + let target = target_result.unwrap_or_else(|e| { early_error( - error_format, + opts.error_format, &format!( "Error loading target specification: {}. \ Use `--print target-list` for a list of built-in targets", @@ -802,7 +849,7 @@ pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Con "32" => 32, "64" => 64, w => early_error( - error_format, + opts.error_format, &format!( "target specification was invalid: \ unrecognized target-pointer-width {}", @@ -1709,6 +1756,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } + if debugging_opts.experimental_coverage { + debugging_opts.instrument_coverage = true; + } + if debugging_opts.instrument_coverage { if cg.profile_generate.enabled() || cg.profile_use.is_some() { early_error( @@ -1718,20 +1769,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } - // `-Z instrument-coverage` implies: - // * `-Z symbol-mangling-version=v0` - to ensure consistent and reversible name mangling. - // Note, LLVM coverage tools can analyze coverage over multiple runs, including some - // changes to source code; so mangled names must be consistent across compilations. - // * `-C link-dead-code` - so unexecuted code is still counted as zero, rather than be - // optimized out. Note that instrumenting dead code can be explicitly disabled with: - // `-Z instrument-coverage -C link-dead-code=no`. + // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent + // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over + // multiple runs, including some changes to source code; so mangled names must be consistent + // across compilations. debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0; - if cg.link_dead_code == None { - // FIXME(richkadel): Investigate if the `instrument-coverage` implementation can - // inject ["zero counters"](https://llvm.org/docs/CoverageMappingFormat.html#counter) - // in the coverage map when "dead code" is removed, rather than forcing `link-dead-code`. - cg.link_dead_code = Some(true); - } + } + + if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { + debugging_opts.graphviz_font = graphviz_font; } if !cg.embed_bitcode { @@ -1805,6 +1851,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { unstable_features: UnstableFeatures::from_environment(), debug_assertions, actually_rustdoc: false, + trimmed_def_paths: TrimmedDefPaths::default(), cli_forced_codegen_units: codegen_units, cli_forced_thinlto_off: disable_thinlto, remap_path_prefix, @@ -2051,7 +2098,7 @@ crate mod dep_tracking { use super::{ CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath, - SymbolManglingVersion, + SymbolManglingVersion, TrimmedDefPaths, }; use crate::lint; use crate::utils::NativeLibKind; @@ -2132,6 +2179,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(SwitchWithOptPath); impl_dep_tracking_hash_via_hash!(SymbolManglingVersion); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(TrimmedDefPaths); impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); diff --git a/src/librustc_session/filesearch.rs b/compiler/rustc_session/src/filesearch.rs similarity index 99% rename from src/librustc_session/filesearch.rs rename to compiler/rustc_session/src/filesearch.rs index 284fca652e..12a268d5b1 100644 --- a/src/librustc_session/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types)] - pub use self::FileMatch::*; use std::borrow::Cow; diff --git a/src/librustc_session/lib.rs b/compiler/rustc_session/src/lib.rs similarity index 94% rename from src/librustc_session/lib.rs rename to compiler/rustc_session/src/lib.rs index c2ea141a06..a808261798 100644 --- a/src/librustc_session/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,4 +1,5 @@ #![feature(crate_visibility_modifier)] +#![feature(once_cell)] #![feature(or_patterns)] #[macro_use] diff --git a/src/librustc_session/lint.rs b/compiler/rustc_session/src/lint.rs similarity index 84% rename from src/librustc_session/lint.rs rename to compiler/rustc_session/src/lint.rs index 0dcbee08ab..62e021d5e4 100644 --- a/src/librustc_session/lint.rs +++ b/compiler/rustc_session/src/lint.rs @@ -65,9 +65,15 @@ pub struct Lint { /// /// The name is written with underscores, e.g., "unused_imports". /// On the command line, underscores become dashes. + /// + /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming + /// for naming guidelines. pub name: &'static str, /// Default level for the lint. + /// + /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels + /// for guidelines on choosing a default level. pub default_level: Level, /// Description of the lint or the issue it detects. @@ -275,17 +281,60 @@ impl LintBuffer { } /// Declares a static item of type `&'static Lint`. +/// +/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation +/// and guidelines on writing lints. +/// +/// The macro call should start with a doc comment explaining the lint +/// which will be embedded in the rustc user documentation book. It should +/// be written in markdown and have a format that looks like this: +/// +/// ```rust,ignore (doc-example) +/// /// The `my_lint_name` lint detects [short explanation here]. +/// /// +/// /// ### Example +/// /// +/// /// ```rust +/// /// [insert a concise example that triggers the lint] +/// /// ``` +/// /// +/// /// {{produces}} +/// /// +/// /// ### Explanation +/// /// +/// /// This should be a detailed explanation of *why* the lint exists, +/// /// and also include suggestions on how the user should fix the problem. +/// /// Try to keep the text simple enough that a beginner can understand, +/// /// and include links to other documentation for terminology that a +/// /// beginner may not be familiar with. If this is "allow" by default, +/// /// it should explain why (are there false positives or other issues?). If +/// /// this is a future-incompatible lint, it should say so, with text that +/// /// looks roughly like this: +/// /// +/// /// This is a [future-incompatible] lint to transition this to a hard +/// /// error in the future. See [issue #xxxxx] for more details. +/// /// +/// /// [issue #xxxxx]: https://github.com/rust-lang/rust/issues/xxxxx +/// ``` +/// +/// The `{{produces}}` tag will be automatically replaced with the output from +/// the example by the build system. You can build and view the rustc book +/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too +/// complex to run as a simple example (for example, it needs an extern +/// crate), mark it with `ignore` and manually paste the expected output below +/// the example. #[macro_export] macro_rules! declare_lint { - ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( $crate::declare_lint!( - $vis $NAME, $Level, $desc, + $(#[$attr])* $vis $NAME, $Level, $desc, ); ); - ($vis: vis $NAME: ident, $Level: ident, $desc: expr, + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $(@future_incompatible = $fi:expr;)? $(@feature_gate = $gate:expr;)? $($v:ident),*) => ( + $(#[$attr])* $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, @@ -298,9 +347,10 @@ macro_rules! declare_lint { ..$crate::lint::Lint::default_fields_for_macro() }; ); - ($vis: vis $NAME: ident, $Level: ident, $desc: expr, + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $lint_edition: expr => $edition_level: ident ) => ( + $(#[$attr])* $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs new file mode 100644 index 0000000000..6133f4d94a --- /dev/null +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -0,0 +1,2783 @@ +//! Some lints that are built in to the compiler. +//! +//! These are the built-in lints that are emitted direct in the main +//! compiler code, rather than using their own custom pass. Those +//! lints are all available in `rustc_lint::builtin`. + +use crate::lint::FutureIncompatibleInfo; +use crate::{declare_lint, declare_lint_pass, declare_tool_lint}; +use rustc_span::edition::Edition; +use rustc_span::symbol::sym; + +declare_lint! { + /// The `ill_formed_attribute_input` lint detects ill-formed attribute + /// inputs that were previously accepted and used in practice. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[inline = "this is not valid"] + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previously, inputs for many built-in attributes weren't validated and + /// nonsensical attribute inputs were accepted. After validation was + /// added, it was determined that some existing projects made use of these + /// invalid forms. This is a [future-incompatible] lint to transition this + /// to a hard error in the future. See [issue #57571] for more details. + /// + /// Check the [attribute reference] for details on the valid inputs for + /// attributes. + /// + /// [issue #57571]: https://github.com/rust-lang/rust/issues/57571 + /// [attribute reference]: https://doc.rust-lang.org/nightly/reference/attributes.html + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub ILL_FORMED_ATTRIBUTE_INPUT, + Deny, + "ill-formed attribute inputs that were previously accepted and used in practice", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #57571 ", + edition: None, + }; + crate_level_only +} + +declare_lint! { + /// The `conflicting_repr_hints` lint detects [`repr` attributes] with + /// conflicting hints. + /// + /// [`repr` attributes]: https://doc.rust-lang.org/reference/type-layout.html#representations + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[repr(u32, u64)] + /// enum Foo { + /// Variant1, + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler incorrectly accepted these conflicting representations in + /// the past. This is a [future-incompatible] lint to transition this to a + /// hard error in the future. See [issue #68585] for more details. + /// + /// To correct the issue, remove one of the conflicting hints. + /// + /// [issue #68585]: https://github.com/rust-lang/rust/issues/68585 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub CONFLICTING_REPR_HINTS, + Deny, + "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #68585 ", + edition: None, + }; +} + +declare_lint! { + /// The `meta_variable_misuse` lint detects possible meta-variable misuse + /// in macro definitions. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(meta_variable_misuse)] + /// + /// macro_rules! foo { + /// () => {}; + /// ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* }; + /// } + /// + /// fn main() { + /// foo!(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// There are quite a few different ways a [`macro_rules`] macro can be + /// improperly defined. Many of these errors were previously only detected + /// when the macro was expanded or not at all. This lint is an attempt to + /// catch some of these problems when the macro is *defined*. + /// + /// This lint is "allow" by default because it may have false positives + /// and other issues. See [issue #61053] for more details. + /// + /// [`macro_rules`]: https://doc.rust-lang.org/reference/macros-by-example.html + /// [issue #61053]: https://github.com/rust-lang/rust/issues/61053 + pub META_VARIABLE_MISUSE, + Allow, + "possible meta-variable misuse at macro definition" +} + +declare_lint! { + /// The `incomplete_include` lint detects the use of the [`include!`] + /// macro with a file that contains more than one expression. + /// + /// [`include!`]: https://doc.rust-lang.org/std/macro.include.html + /// + /// ### Example + /// + /// ```rust,ignore (needs separate file) + /// fn main() { + /// include!("foo.txt"); + /// } + /// ``` + /// + /// where the file `foo.txt` contains: + /// + /// ```text + /// println!("hi!"); + /// ``` + /// + /// produces: + /// + /// ```text + /// error: include macro expected single expression in source + /// --> foo.txt:1:14 + /// | + /// 1 | println!("1"); + /// | ^ + /// | + /// = note: `#[deny(incomplete_include)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// The [`include!`] macro is currently only intended to be used to + /// include a single [expression] or multiple [items]. Historically it + /// would ignore any contents after the first expression, but that can be + /// confusing. In the example above, the `println!` expression ends just + /// before the semicolon, making the semicolon "extra" information that is + /// ignored. Perhaps even more surprising, if the included file had + /// multiple print statements, the subsequent ones would be ignored! + /// + /// One workaround is to place the contents in braces to create a [block + /// expression]. Also consider alternatives, like using functions to + /// encapsulate the expressions, or use [proc-macros]. + /// + /// This is a lint instead of a hard error because existing projects were + /// found to hit this error. To be cautious, it is a lint for now. The + /// future semantics of the `include!` macro are also uncertain, see + /// [issue #35560]. + /// + /// [items]: https://doc.rust-lang.org/reference/items.html + /// [expression]: https://doc.rust-lang.org/reference/expressions.html + /// [block expression]: https://doc.rust-lang.org/reference/expressions/block-expr.html + /// [proc-macros]: https://doc.rust-lang.org/reference/procedural-macros.html + /// [issue #35560]: https://github.com/rust-lang/rust/issues/35560 + pub INCOMPLETE_INCLUDE, + Deny, + "trailing content in included file" +} + +declare_lint! { + /// The `arithmetic_overflow` lint detects that an arithmetic operation + /// will [overflow]. + /// + /// [overflow]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow + /// + /// ### Example + /// + /// ```rust,compile_fail + /// 1_i32 << 32; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is very likely a mistake to perform an arithmetic operation that + /// overflows its value. If the compiler is able to detect these kinds of + /// overflows at compile-time, it will trigger this lint. Consider + /// adjusting the expression to avoid overflow, or use a data type that + /// will not overflow. + pub ARITHMETIC_OVERFLOW, + Deny, + "arithmetic operation overflows" +} + +declare_lint! { + /// The `unconditional_panic` lint detects an operation that will cause a + /// panic at runtime. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// let x = 1 / 0; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint detects code that is very likely incorrect. When possible, + /// the compiler will attempt to detect situations where code can be + /// evaluated at compile-time to generate more efficient code. While + /// evaluating such code, if it detects that the code will unconditionally + /// panic, this usually indicates that it is doing something incorrectly. + /// If this lint is allowed, then the code will not be evaluated at + /// compile-time, and instead continue to generate code to evaluate at + /// runtime, which may panic during runtime. + pub UNCONDITIONAL_PANIC, + Deny, + "operation will cause a panic at runtime" +} + +declare_lint! { + /// The `const_err` lint detects an erroneous expression while doing + /// constant evaluation. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![allow(unconditional_panic)] + /// let x: &'static i32 = &(1 / 0); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint detects code that is very likely incorrect. If this lint is + /// allowed, then the code will not be evaluated at compile-time, and + /// instead continue to generate code to evaluate at runtime, which may + /// panic during runtime. + /// + /// Note that this lint may trigger in either inside or outside of a + /// [const context]. Outside of a [const context], the compiler can + /// sometimes evaluate an expression at compile-time in order to generate + /// more efficient code. As the compiler becomes better at doing this, it + /// needs to decide what to do when it encounters code that it knows for + /// certain will panic or is otherwise incorrect. Making this a hard error + /// would prevent existing code that exhibited this behavior from + /// compiling, breaking backwards-compatibility. However, this is almost + /// certainly incorrect code, so this is a deny-by-default lint. For more + /// details, see [RFC 1229] and [issue #28238]. + /// + /// Note that there are several other more specific lints associated with + /// compile-time evaluation, such as [`arithmetic_overflow`], + /// [`unconditional_panic`]. + /// + /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context + /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md + /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238 + /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow + /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic + pub CONST_ERR, + Deny, + "constant evaluation detected erroneous expression", + report_in_external_macro +} + +declare_lint! { + /// The `unused_imports` lint detects imports that are never used. + /// + /// ### Example + /// + /// ```rust + /// use std::collections::HashMap; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused imports may signal a mistake or unfinished code, and clutter + /// the code, and should be removed. If you intended to re-export the item + /// to make it available outside of the module, add a visibility modifier + /// like `pub`. + pub UNUSED_IMPORTS, + Warn, + "imports that are never used" +} + +declare_lint! { + /// The `unused_extern_crates` lint guards against `extern crate` items + /// that are never used. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_extern_crates)] + /// extern crate proc_macro; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `extern crate` items that are unused have no effect and should be + /// removed. Note that there are some cases where specifying an `extern + /// crate` is desired for the side effect of ensuring the given crate is + /// linked, even though it is not otherwise directly referenced. The lint + /// can be silenced by aliasing the crate to an underscore, such as + /// `extern crate foo as _`. Also note that it is no longer idiomatic to + /// use `extern crate` in the [2018 edition], as extern crates are now + /// automatically added in scope. + /// + /// This lint is "allow" by default because it can be noisy, and produce + /// false-positives. If a dependency is being removed from a project, it + /// is recommended to remove it from the build configuration (such as + /// `Cargo.toml`) to ensure stale build entries aren't left behind. + /// + /// [2018 edition]: https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html#no-more-extern-crate + pub UNUSED_EXTERN_CRATES, + Allow, + "extern crates that are never used" +} + +declare_lint! { + /// The `unused_crate_dependencies` lint detects crate dependencies that + /// are never used. + /// + /// ### Example + /// + /// ```rust,ignore (needs extern crate) + /// #![deny(unused_crate_dependencies)] + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: external crate `regex` unused in `lint_example`: remove the dependency or add `use regex as _;` + /// | + /// note: the lint level is defined here + /// --> src/lib.rs:1:9 + /// | + /// 1 | #![deny(unused_crate_dependencies)] + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^ + /// ``` + /// + /// ### Explanation + /// + /// After removing the code that uses a dependency, this usually also + /// requires removing the dependency from the build configuration. + /// However, sometimes that step can be missed, which leads to time wasted + /// building dependencies that are no longer used. This lint can be + /// enabled to detect dependencies that are never used (more specifically, + /// any dependency passed with the `--extern` command-line flag that is + /// never referenced via [`use`], [`extern crate`], or in any [path]). + /// + /// This lint is "allow" by default because it can provide false positives + /// depending on how the build system is configured. For example, when + /// using Cargo, a "package" consists of multiple crates (such as a + /// library and a binary), but the dependencies are defined for the + /// package as a whole. If there is a dependency that is only used in the + /// binary, but not the library, then the lint will be incorrectly issued + /// in the library. + /// + /// [path]: https://doc.rust-lang.org/reference/paths.html + /// [`use`]: https://doc.rust-lang.org/reference/items/use-declarations.html + /// [`extern crate`]: https://doc.rust-lang.org/reference/items/extern-crates.html + pub UNUSED_CRATE_DEPENDENCIES, + Allow, + "crate dependencies that are never used", + crate_level_only +} + +declare_lint! { + /// The `unused_qualifications` lint detects unnecessarily qualified + /// names. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_qualifications)] + /// mod foo { + /// pub fn bar() {} + /// } + /// + /// fn main() { + /// use foo::bar; + /// foo::bar(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If an item from another module is already brought into scope, then + /// there is no need to qualify it in this case. You can call `bar()` + /// directly, without the `foo::`. + /// + /// This lint is "allow" by default because it is somewhat pedantic, and + /// doesn't indicate an actual problem, but rather a stylistic choice, and + /// can be noisy when refactoring or moving around code. + pub UNUSED_QUALIFICATIONS, + Allow, + "detects unnecessarily qualified names" +} + +declare_lint! { + /// The `unknown_lints` lint detects unrecognized lint attribute. + /// + /// ### Example + /// + /// ```rust + /// #![allow(not_a_real_lint)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to specify a lint that does not exist. Check + /// the spelling, and check the lint listing for the correct name. Also + /// consider if you are using an old version of the compiler, and the lint + /// is only available in a newer version. + pub UNKNOWN_LINTS, + Warn, + "unrecognized lint attribute" +} + +declare_lint! { + /// The `unused_variables` lint detects variables which are not used in + /// any way. + /// + /// ### Example + /// + /// ```rust + /// let x = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused variables may signal a mistake or unfinished code. To silence + /// the warning for the individual variable, prefix it with an underscore + /// such as `_x`. + pub UNUSED_VARIABLES, + Warn, + "detect variables which are not used in any way" +} + +declare_lint! { + /// The `unused_assignments` lint detects assignments that will never be read. + /// + /// ### Example + /// + /// ```rust + /// let mut x = 5; + /// x = 6; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused assignments may signal a mistake or unfinished code. If the + /// variable is never used after being assigned, then the assignment can + /// be removed. Variables with an underscore prefix such as `_x` will not + /// trigger this lint. + pub UNUSED_ASSIGNMENTS, + Warn, + "detect assignments that will never be read" +} + +declare_lint! { + /// The `dead_code` lint detects unused, unexported items. + /// + /// ### Example + /// + /// ```rust + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Dead code may signal a mistake or unfinished code. To silence the + /// warning for individual items, prefix the name with an underscore such + /// as `_foo`. If it was intended to expose the item outside of the crate, + /// consider adding a visibility modifier like `pub`. Otherwise consider + /// removing the unused code. + pub DEAD_CODE, + Warn, + "detect unused, unexported items" +} + +declare_lint! { + /// The `unused_attributes` lint detects attributes that were not used by + /// the compiler. + /// + /// ### Example + /// + /// ```rust + /// #![macro_export] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused [attributes] may indicate the attribute is placed in the wrong + /// position. Consider removing it, or placing it in the correct position. + /// Also consider if you intended to use an _inner attribute_ (with a `!` + /// such as `#![allow(unused)]`) which applies to the item the attribute + /// is within, or an _outer attribute_ (without a `!` such as + /// `#[allow(unsued)]`) which applies to the item *following* the + /// attribute. + /// + /// [attributes]: https://doc.rust-lang.org/reference/attributes.html + pub UNUSED_ATTRIBUTES, + Warn, + "detects attributes that were not used by the compiler" +} + +declare_lint! { + /// The `unreachable_code` lint detects unreachable code paths. + /// + /// ### Example + /// + /// ```rust,no_run + /// panic!("we never go past here!"); + /// + /// let x = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unreachable code may signal a mistake or unfinished code. If the code + /// is no longer in use, consider removing it. + pub UNREACHABLE_CODE, + Warn, + "detects unreachable code paths", + report_in_external_macro +} + +declare_lint! { + /// The `unreachable_patterns` lint detects unreachable patterns. + /// + /// ### Example + /// + /// ```rust + /// let x = 5; + /// match x { + /// y => (), + /// 5 => (), + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This usually indicates a mistake in how the patterns are specified or + /// ordered. In this example, the `y` pattern will always match, so the + /// five is impossible to reach. Remember, match arms match in order, you + /// probably wanted to put the `5` case above the `y` case. + pub UNREACHABLE_PATTERNS, + Warn, + "detects unreachable patterns" +} + +declare_lint! { + /// The `overlapping_patterns` lint detects `match` arms that have + /// [range patterns] that overlap. + /// + /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns + /// + /// ### Example + /// + /// ```rust + /// let x = 123u8; + /// match x { + /// 0..=100 => { println!("small"); } + /// 100..=255 => { println!("large"); } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is likely a mistake to have range patterns in a match expression + /// that overlap. Check that the beginning and end values are what you + /// expect, and keep in mind that with `..=` the left and right bounds are + /// inclusive. + pub OVERLAPPING_PATTERNS, + Warn, + "detects overlapping patterns" +} + +declare_lint! { + /// The `bindings_with_variant_name` lint detects pattern bindings with + /// the same name as one of the matched variants. + /// + /// ### Example + /// + /// ```rust + /// pub enum Enum { + /// Foo, + /// Bar, + /// } + /// + /// pub fn foo(x: Enum) { + /// match x { + /// Foo => {} + /// Bar => {} + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to specify an enum variant name as an + /// [identifier pattern]. In the example above, the `match` arms are + /// specifying a variable name to bind the value of `x` to. The second arm + /// is ignored because the first one matches *all* values. The likely + /// intent is that the arm was intended to match on the enum variant. + /// + /// Two possible solutions are: + /// + /// * Specify the enum variant using a [path pattern], such as + /// `Enum::Foo`. + /// * Bring the enum variants into local scope, such as adding `use + /// Enum::*;` to the beginning of the `foo` function in the example + /// above. + /// + /// [identifier pattern]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns + /// [path pattern]: https://doc.rust-lang.org/reference/patterns.html#path-patterns + pub BINDINGS_WITH_VARIANT_NAME, + Warn, + "detects pattern bindings with the same name as one of the matched variants" +} + +declare_lint! { + /// The `unused_macros` lint detects macros that were not used. + /// + /// ### Example + /// + /// ```rust + /// macro_rules! unused { + /// () => {}; + /// } + /// + /// fn main() { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused macros may signal a mistake or unfinished code. To silence the + /// warning for the individual macro, prefix the name with an underscore + /// such as `_my_macro`. If you intended to export the macro to make it + /// available outside of the crate, use the [`macro_export` attribute]. + /// + /// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope + pub UNUSED_MACROS, + Warn, + "detects macros that were not used" +} + +declare_lint! { + /// The `warnings` lint allows you to change the level of other + /// lints which produce warnings. + /// + /// ### Example + /// + /// ```rust + /// #![deny(warnings)] + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `warnings` lint is a bit special; by changing its level, you + /// change every other warning that would produce a warning to whatever + /// value you'd like. As such, you won't ever trigger this lint in your + /// code directly. + pub WARNINGS, + Warn, + "mass-change the level for lints which produce warnings" +} + +declare_lint! { + /// The `unused_features` lint detects unused or unknown features found in + /// crate-level [`feature` attributes]. + /// + /// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// Note: This lint is currently not functional, see [issue #44232] for + /// more details. + /// + /// [issue #44232]: https://github.com/rust-lang/rust/issues/44232 + pub UNUSED_FEATURES, + Warn, + "unused features found in crate-level `#[feature]` directives" +} + +declare_lint! { + /// The `stable_features` lint detects a [`feature` attribute] that + /// has since been made stable. + /// + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// ### Example + /// + /// ```rust + /// #![feature(test_accepted_feature)] + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When a feature is stabilized, it is no longer necessary to include a + /// `#![feature]` attribute for it. To fix, simply remove the + /// `#![feature]` attribute. + pub STABLE_FEATURES, + Warn, + "stable features found in `#[feature]` directive" +} + +declare_lint! { + /// The `unknown_crate_types` lint detects an unknown crate type found in + /// a [`crate_type` attribute]. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![crate_type="lol"] + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// An unknown value give to the `crate_type` attribute is almost + /// certainly a mistake. + /// + /// [`crate_type` attribute]: https://doc.rust-lang.org/reference/linkage.html + pub UNKNOWN_CRATE_TYPES, + Deny, + "unknown crate type found in `#[crate_type]` directive", + crate_level_only +} + +declare_lint! { + /// The `trivial_casts` lint detects trivial casts which could be replaced + /// with coercion, which may require [type ascription] or a temporary + /// variable. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(trivial_casts)] + /// let x: &u32 = &42; + /// let y = x as *const u32; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A trivial cast is a cast `e as T` where `e` has type `U` and `U` is a + /// subtype of `T`. This type of cast is usually unnecessary, as it can be + /// usually be inferred. + /// + /// This lint is "allow" by default because there are situations, such as + /// with FFI interfaces or complex type aliases, where it triggers + /// incorrectly, or in situations where it will be more difficult to + /// clearly express the intent. It may be possible that this will become a + /// warning in the future, possibly with [type ascription] providing a + /// convenient way to work around the current issues. See [RFC 401] for + /// historical context. + /// + /// [type ascription]: https://github.com/rust-lang/rust/issues/23416 + /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md + pub TRIVIAL_CASTS, + Allow, + "detects trivial casts which could be removed" +} + +declare_lint! { + /// The `trivial_numeric_casts` lint detects trivial numeric casts of types + /// which could be removed. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(trivial_numeric_casts)] + /// let x = 42_i32 as i32; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A trivial numeric cast is a cast of a numeric type to the same numeric + /// type. This type of cast is usually unnecessary. + /// + /// This lint is "allow" by default because there are situations, such as + /// with FFI interfaces or complex type aliases, where it triggers + /// incorrectly, or in situations where it will be more difficult to + /// clearly express the intent. It may be possible that this will become a + /// warning in the future, possibly with [type ascription] providing a + /// convenient way to work around the current issues. See [RFC 401] for + /// historical context. + /// + /// [type ascription]: https://github.com/rust-lang/rust/issues/23416 + /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md + pub TRIVIAL_NUMERIC_CASTS, + Allow, + "detects trivial casts of numeric types which could be removed" +} + +declare_lint! { + /// The `private_in_public` lint detects private items in public + /// interfaces not caught by the old implementation. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// struct SemiPriv; + /// + /// mod m1 { + /// struct Priv; + /// impl super::SemiPriv { + /// pub fn f(_: Priv) {} + /// } + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The visibility rules are intended to prevent exposing private items in + /// public interfaces. This is a [future-incompatible] lint to transition + /// this to a hard error in the future. See [issue #34537] for more + /// details. + /// + /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PRIVATE_IN_PUBLIC, + Warn, + "detect private items in public interfaces not caught by the old implementation", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #34537 ", + edition: None, + }; +} + +declare_lint! { + /// The `exported_private_dependencies` lint detects private dependencies + /// that are exposed in a public interface. + /// + /// ### Example + /// + /// ```rust,ignore (needs-dependency) + /// pub fn foo() -> Option { + /// None + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: type `bar::Thing` from private dependency 'bar' in public interface + /// --> src/lib.rs:3:1 + /// | + /// 3 | pub fn foo() -> Option { + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// | + /// = note: `#[warn(exported_private_dependencies)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// Dependencies can be marked as "private" to indicate that they are not + /// exposed in the public interface of a crate. This can be used by Cargo + /// to independently resolve those dependencies because it can assume it + /// does not need to unify them with other packages using that same + /// dependency. This lint is an indication of a violation of that + /// contract. + /// + /// To fix this, avoid exposing the dependency in your public interface. + /// Or, switch the dependency to a public dependency. + /// + /// Note that support for this is only available on the nightly channel. + /// See [RFC 1977] for more details, as well as the [Cargo documentation]. + /// + /// [RFC 1977]: https://github.com/rust-lang/rfcs/blob/master/text/1977-public-private-dependencies.md + /// [Cargo documentation]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#public-dependency + pub EXPORTED_PRIVATE_DEPENDENCIES, + Warn, + "public interface leaks type from a private dependency" +} + +declare_lint! { + /// The `pub_use_of_private_extern_crate` lint detects a specific + /// situation of re-exporting a private `extern crate`. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// extern crate core; + /// pub use core as reexported_core; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A public `use` declaration should not be used to publicly re-export a + /// private `extern crate`. `pub extern crate` should be used instead. + /// + /// This was historically allowed, but is not the intended behavior + /// according to the visibility rules. This is a [future-incompatible] + /// lint to transition this to a hard error in the future. See [issue + /// #34537] for more details. + /// + /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PUB_USE_OF_PRIVATE_EXTERN_CRATE, + Deny, + "detect public re-exports of private extern crates", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #34537 ", + edition: None, + }; +} + +declare_lint! { + /// The `invalid_type_param_default` lint detects type parameter defaults + /// erroneously allowed in an invalid location. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// fn foo(t: T) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Default type parameters were only intended to be allowed in certain + /// situations, but historically the compiler allowed them everywhere. + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #36887] for more details. + /// + /// [issue #36887]: https://github.com/rust-lang/rust/issues/36887 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub INVALID_TYPE_PARAM_DEFAULT, + Deny, + "type parameter default erroneously allowed in invalid location", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #36887 ", + edition: None, + }; +} + +declare_lint! { + /// The `renamed_and_removed_lints` lint detects lints that have been + /// renamed or removed. + /// + /// ### Example + /// + /// ```rust + /// #![deny(raw_pointer_derive)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To fix this, either remove the lint or use the new name. This can help + /// avoid confusion about lints that are no longer valid, and help + /// maintain consistency for renamed lints. + pub RENAMED_AND_REMOVED_LINTS, + Warn, + "lints that have been renamed or removed" +} + +declare_lint! { + /// The `unaligned_references` lint detects unaligned references to fields + /// of [packed] structs. + /// + /// [packed]: https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unaligned_references)] + /// + /// #[repr(packed)] + /// pub struct Foo { + /// field1: u64, + /// field2: u8, + /// } + /// + /// fn main() { + /// unsafe { + /// let foo = Foo { field1: 0, field2: 0 }; + /// let _ = &foo.field1; + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Creating a reference to an insufficiently aligned packed field is + /// [undefined behavior] and should be disallowed. + /// + /// This lint is "allow" by default because there is no stable + /// alternative, and it is not yet certain how widespread existing code + /// will trigger this lint. + /// + /// See [issue #27060] for more discussion. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [issue #27060]: https://github.com/rust-lang/rust/issues/27060 + pub UNALIGNED_REFERENCES, + Allow, + "detects unaligned references to fields of packed structs", +} + +declare_lint! { + /// The `const_item_mutation` lint detects attempts to mutate a `const` + /// item. + /// + /// ### Example + /// + /// ```rust + /// const FOO: [i32; 1] = [0]; + /// + /// fn main() { + /// FOO[0] = 1; + /// // This will print "[0]". + /// println!("{:?}", FOO); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Trying to directly mutate a `const` item is almost always a mistake. + /// What is happening in the example above is that a temporary copy of the + /// `const` is mutated, but the original `const` is not. Each time you + /// refer to the `const` by name (such as `FOO` in the example above), a + /// separate copy of the value is inlined at that location. + /// + /// This lint checks for writing directly to a field (`FOO.field = + /// some_value`) or array entry (`FOO[0] = val`), or taking a mutable + /// reference to the const item (`&mut FOO`), including through an + /// autoderef (`FOO.some_mut_self_method()`). + /// + /// There are various alternatives depending on what you are trying to + /// accomplish: + /// + /// * First, always reconsider using mutable globals, as they can be + /// difficult to use correctly, and can make the code more difficult to + /// use or understand. + /// * If you are trying to perform a one-time initialization of a global: + /// * If the value can be computed at compile-time, consider using + /// const-compatible values (see [Constant Evaluation]). + /// * For more complex single-initialization cases, consider using a + /// third-party crate, such as [`lazy_static`] or [`once_cell`]. + /// * If you are using the [nightly channel], consider the new + /// [`lazy`] module in the standard library. + /// * If you truly need a mutable global, consider using a [`static`], + /// which has a variety of options: + /// * Simple data types can be directly defined and mutated with an + /// [`atomic`] type. + /// * More complex types can be placed in a synchronization primitive + /// like a [`Mutex`], which can be initialized with one of the options + /// listed above. + /// * A [mutable `static`] is a low-level primitive, requiring unsafe. + /// Typically This should be avoided in preference of something + /// higher-level like one of the above. + /// + /// [Constant Evaluation]: https://doc.rust-lang.org/reference/const_eval.html + /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html + /// [mutable `static`]: https://doc.rust-lang.org/reference/items/static-items.html#mutable-statics + /// [`lazy`]: https://doc.rust-lang.org/nightly/std/lazy/index.html + /// [`lazy_static`]: https://crates.io/crates/lazy_static + /// [`once_cell`]: https://crates.io/crates/once_cell + /// [`atomic`]: https://doc.rust-lang.org/std/sync/atomic/index.html + /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html + pub CONST_ITEM_MUTATION, + Warn, + "detects attempts to mutate a `const` item", +} + +declare_lint! { + /// The `safe_packed_borrows` lint detects borrowing a field in the + /// interior of a packed structure with alignment other than 1. + /// + /// ### Example + /// + /// ```rust + /// #[repr(packed)] + /// pub struct Unaligned(pub T); + /// + /// pub struct Foo { + /// start: u8, + /// data: Unaligned, + /// } + /// + /// fn main() { + /// let x = Foo { start: 0, data: Unaligned(1) }; + /// let y = &x.data.0; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This type of borrow is unsafe and can cause errors on some platforms + /// and violates some assumptions made by the compiler. This was + /// previously allowed unintentionally. This is a [future-incompatible] + /// lint to transition this to a hard error in the future. See [issue + /// #46043] for more details, including guidance on how to solve the + /// problem. + /// + /// [issue #46043]: https://github.com/rust-lang/rust/issues/46043 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub SAFE_PACKED_BORROWS, + Warn, + "safe borrows of fields of packed structs were erroneously allowed", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #46043 ", + edition: None, + }; +} + +declare_lint! { + /// The `patterns_in_fns_without_body` lint detects `mut` identifier + /// patterns as a parameter in functions without a body. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// trait Trait { + /// fn foo(mut arg: u8); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To fix this, remove `mut` from the parameter in the trait definition; + /// it can be used in the implementation. That is, the following is OK: + /// + /// ```rust + /// trait Trait { + /// fn foo(arg: u8); // Removed `mut` here + /// } + /// + /// impl Trait for i32 { + /// fn foo(mut arg: u8) { // `mut` here is OK + /// + /// } + /// } + /// ``` + /// + /// Trait definitions can define functions without a body to specify a + /// function that implementors must define. The parameter names in the + /// body-less functions are only allowed to be `_` or an [identifier] for + /// documentation purposes (only the type is relevant). Previous versions + /// of the compiler erroneously allowed [identifier patterns] with the + /// `mut` keyword, but this was not intended to be allowed. This is a + /// [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #35203] for more details. + /// + /// [identifier]: https://doc.rust-lang.org/reference/identifiers.html + /// [identifier patterns]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns + /// [issue #35203]: https://github.com/rust-lang/rust/issues/35203 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PATTERNS_IN_FNS_WITHOUT_BODY, + Deny, + "patterns in functions without body were erroneously allowed", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #35203 ", + edition: None, + }; +} + +declare_lint! { + /// The `missing_fragment_specifier` lint is issued when an unused pattern + /// in a `macro_rules!` macro definition has a meta-variable (e.g. `$e`) + /// that is not followed by a fragment specifier (e.g. `:expr`). + /// + /// This warning can always be fixed by removing the unused pattern in the + /// `macro_rules!` macro definition. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// macro_rules! foo { + /// ($e) => {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// + /// ### Explanation + /// + /// The meta-variable (`$e` above) lacks a fragment specifier, which is a + /// malformed input. It can be fixed by adding a fragment specifier. + pub MISSING_FRAGMENT_SPECIFIER, + Deny, + "detects missing fragment specifiers in unused `macro_rules!` patterns", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #40107 ", + edition: None, + }; +} + +declare_lint! { + /// The `late_bound_lifetime_arguments` lint detects generic lifetime + /// arguments in path segments with late bound lifetime parameters. + /// + /// ### Example + /// + /// ```rust + /// struct S; + /// + /// impl S { + /// fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + /// } + /// + /// fn main() { + /// S.late::<'static>(&0, &0); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is not clear how to provide arguments for early-bound lifetime + /// parameters if they are intermixed with late-bound parameters in the + /// same list. For now, providing any explicit arguments will trigger this + /// lint if late-bound parameters are present, so in the future a solution + /// can be adopted without hitting backward compatibility issues. This is + /// a [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #42868] for more details, along with a description + /// of the difference between early and late-bound parameters. + /// + /// [issue #42868]: https://github.com/rust-lang/rust/issues/42868 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub LATE_BOUND_LIFETIME_ARGUMENTS, + Warn, + "detects generic lifetime arguments in path segments with late bound lifetime parameters", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #42868 ", + edition: None, + }; +} + +declare_lint! { + /// The `order_dependent_trait_objects` lint detects a trait coherency + /// violation that would allow creating two trait impls for the same + /// dynamic trait object involving marker traits. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// pub trait Trait {} + /// + /// impl Trait for dyn Send + Sync { } + /// impl Trait for dyn Sync + Send { } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A previous bug caused the compiler to interpret traits with different + /// orders (such as `Send + Sync` and `Sync + Send`) as distinct types + /// when they were intended to be treated the same. This allowed code to + /// define separate trait implementations when there should be a coherence + /// error. This is a [future-incompatible] lint to transition this to a + /// hard error in the future. See [issue #56484] for more details. + /// + /// [issue #56484]: https://github.com/rust-lang/rust/issues/56484 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub ORDER_DEPENDENT_TRAIT_OBJECTS, + Deny, + "trait-object types were treated as different depending on marker-trait order", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #56484 ", + edition: None, + }; +} + +declare_lint! { + /// The `coherence_leak_check` lint detects conflicting implementations of + /// a trait that are only distinguished by the old leak-check code. + /// + /// ### Example + /// + /// ```rust + /// trait SomeTrait { } + /// impl SomeTrait for for<'a> fn(&'a u8) { } + /// impl<'a> SomeTrait for fn(&'a u8) { } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the past, the compiler would accept trait implementations for + /// identical functions that differed only in where the lifetime binder + /// appeared. Due to a change in the borrow checker implementation to fix + /// several bugs, this is no longer allowed. However, since this affects + /// existing code, this is a [future-incompatible] lint to transition this + /// to a hard error in the future. + /// + /// Code relying on this pattern should introduce "[newtypes]", + /// like `struct Foo(for<'a> fn(&'a u8))`. + /// + /// See [issue #56105] for more details. + /// + /// [issue #56105]: https://github.com/rust-lang/rust/issues/56105 + /// [newtypes]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub COHERENCE_LEAK_CHECK, + Warn, + "distinct impls distinguished only by the leak-check code", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #56105 ", + edition: None, + }; +} + +declare_lint! { + /// The `deprecated` lint detects use of deprecated items. + /// + /// ### Example + /// + /// ```rust + /// #[deprecated] + /// fn foo() {} + /// + /// fn bar() { + /// foo(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Items may be marked "deprecated" with the [`deprecated` attribute] to + /// indicate that they should no longer be used. Usually the attribute + /// should include a note on what to use instead, or check the + /// documentation. + /// + /// [`deprecated` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute + pub DEPRECATED, + Warn, + "detects use of deprecated items", + report_in_external_macro +} + +declare_lint! { + /// The `unused_unsafe` lint detects unnecessary use of an `unsafe` block. + /// + /// ### Example + /// + /// ```rust + /// unsafe {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If nothing within the block requires `unsafe`, then remove the + /// `unsafe` marker because it is not required and may cause confusion. + pub UNUSED_UNSAFE, + Warn, + "unnecessary use of an `unsafe` block" +} + +declare_lint! { + /// The `unused_mut` lint detects mut variables which don't need to be + /// mutable. + /// + /// ### Example + /// + /// ```rust + /// let mut x = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style is to only mark variables as `mut` if it is + /// required. + pub UNUSED_MUT, + Warn, + "detect mut variables which don't need to be mutable" +} + +declare_lint! { + /// The `unconditional_recursion` lint detects functions that cannot + /// return without calling themselves. + /// + /// ### Example + /// + /// ```rust + /// fn foo() { + /// foo(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to have a recursive call that does not have + /// some condition to cause it to terminate. If you really intend to have + /// an infinite loop, using a `loop` expression is recommended. + pub UNCONDITIONAL_RECURSION, + Warn, + "functions that cannot return without calling themselves" +} + +declare_lint! { + /// The `single_use_lifetimes` lint detects lifetimes that are only used + /// once. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(single_use_lifetimes)] + /// + /// fn foo<'a>(x: &'a u32) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Specifying an explicit lifetime like `'a` in a function or `impl` + /// should only be used to link together two things. Otherwise, you should + /// just use `'_` to indicate that the lifetime is not linked to anything, + /// or elide the lifetime altogether if possible. + /// + /// This lint is "allow" by default because it was introduced at a time + /// when `'_` and elided lifetimes were first being introduced, and this + /// lint would be too noisy. Also, there are some known false positives + /// that it produces. See [RFC 2115] for historical context, and [issue + /// #44752] for more details. + /// + /// [RFC 2115]: https://github.com/rust-lang/rfcs/blob/master/text/2115-argument-lifetimes.md + /// [issue #44752]: https://github.com/rust-lang/rust/issues/44752 + pub SINGLE_USE_LIFETIMES, + Allow, + "detects lifetime parameters that are only used once" +} + +declare_lint! { + /// The `unused_lifetimes` lint detects lifetime parameters that are never + /// used. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[deny(unused_lifetimes)] + /// + /// pub fn foo<'a>() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused lifetime parameters may signal a mistake or unfinished code. + /// Consider removing the parameter. + pub UNUSED_LIFETIMES, + Allow, + "detects lifetime parameters that are never used" +} + +declare_lint! { + /// The `tyvar_behind_raw_pointer` lint detects raw pointer to an + /// inference variable. + /// + /// ### Example + /// + /// ```rust,edition2015 + /// // edition 2015 + /// let data = std::ptr::null(); + /// let _ = &data as *const *const (); + /// + /// if data.is_null() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This kind of inference was previously allowed, but with the future + /// arrival of [arbitrary self types], this can introduce ambiguity. To + /// resolve this, use an explicit type instead of relying on type + /// inference. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the 2018 edition. See [issue #46906] for more details. This + /// is currently a hard-error on the 2018 edition, and is "warn" by + /// default in the 2015 edition. + /// + /// [arbitrary self types]: https://github.com/rust-lang/rust/issues/44874 + /// [issue #46906]: https://github.com/rust-lang/rust/issues/46906 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub TYVAR_BEHIND_RAW_POINTER, + Warn, + "raw pointer to an inference variable", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #46906 ", + edition: Some(Edition::Edition2018), + }; +} + +declare_lint! { + /// The `elided_lifetimes_in_paths` lint detects the use of hidden + /// lifetime parameters. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(elided_lifetimes_in_paths)] + /// struct Foo<'a> { + /// x: &'a u32 + /// } + /// + /// fn foo(x: &Foo) { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Elided lifetime parameters can make it difficult to see at a glance + /// that borrowing is occurring. This lint ensures that lifetime + /// parameters are always explicitly stated, even if it is the `'_` + /// [placeholder lifetime]. + /// + /// This lint is "allow" by default because it has some known issues, and + /// may require a significant transition for old code. + /// + /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions + pub ELIDED_LIFETIMES_IN_PATHS, + Allow, + "hidden lifetime parameters in types are deprecated", + crate_level_only +} + +declare_lint! { + /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait + /// objects. + /// + /// ### Example + /// + /// ```rust + /// trait Trait { } + /// + /// fn takes_trait_object(_: Box) { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Without the `dyn` indicator, it can be ambiguous or confusing when + /// reading code as to whether or not you are looking at a trait object. + /// The `dyn` keyword makes it explicit, and adds a symmetry to contrast + /// with [`impl Trait`]. + /// + /// [`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + pub BARE_TRAIT_OBJECTS, + Warn, + "suggest using `dyn Trait` for trait objects" +} + +declare_lint! { + /// The `absolute_paths_not_starting_with_crate` lint detects fully + /// qualified paths that start with a module name instead of `crate`, + /// `self`, or an extern crate name + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(absolute_paths_not_starting_with_crate)] + /// + /// mod foo { + /// pub fn bar() {} + /// } + /// + /// fn main() { + /// ::foo::bar(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust [editions] allow the language to evolve without breaking + /// backwards compatibility. This lint catches code that uses absolute + /// paths in the style of the 2015 edition. In the 2015 edition, absolute + /// paths (those starting with `::`) refer to either the crate root or an + /// external crate. In the 2018 edition it was changed so that they only + /// refer to external crates. The path prefix `crate::` should be used + /// instead to reference items from the crate root. + /// + /// If you switch the compiler from the 2015 to 2018 edition without + /// updating the code, then it will fail to compile if the old style paths + /// are used. You can manually change the paths to use the `crate::` + /// prefix to transition to the 2018 edition. + /// + /// This lint solves the problem automatically. It is "allow" by default + /// because the code is perfectly valid in the 2015 edition. The [`cargo + /// fix`] tool with the `--edition` flag will switch this lint to "warn" + /// and automatically apply the suggested fix from the compiler. This + /// provides a completely automated way to update old code to the 2018 + /// edition. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html + pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + Allow, + "fully qualified paths that start with a module name \ + instead of `crate`, `self`, or an extern crate name", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #53130 ", + edition: Some(Edition::Edition2018), + }; +} + +declare_lint! { + /// The `illegal_floating_point_literal_pattern` lint detects + /// floating-point literals used in patterns. + /// + /// ### Example + /// + /// ```rust + /// let x = 42.0; + /// + /// match x { + /// 5.0 => {} + /// _ => {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of the compiler accepted floating-point literals in + /// patterns, but it was later determined this was a mistake. The + /// semantics of comparing floating-point values may not be clear in a + /// pattern when contrasted with "structural equality". Typically you can + /// work around this by using a [match guard], such as: + /// + /// ```rust + /// # let x = 42.0; + /// + /// match x { + /// y if y == 5.0 => {} + /// _ => {} + /// } + /// ``` + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #41620] for more details. + /// + /// [issue #41620]: https://github.com/rust-lang/rust/issues/41620 + /// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + Warn, + "floating-point literals cannot be used in patterns", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #41620 ", + edition: None, + }; +} + +declare_lint! { + /// The `unstable_name_collisions` lint detects that you have used a name + /// that the standard library plans to add in the future. + /// + /// ### Example + /// + /// ```rust + /// trait MyIterator : Iterator { + /// // is_sorted is an unstable method that already exists on the Iterator trait + /// fn is_sorted(self) -> bool where Self: Sized {true} + /// } + /// + /// impl MyIterator for T where T: Iterator { } + /// + /// let x = vec![1,2,3]; + /// let _ = x.iter().is_sorted(); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When new methods are added to traits in the standard library, they are + /// usually added in an "unstable" form which is only available on the + /// [nightly channel] with a [`feature` attribute]. If there is any + /// pre-existing code which extends a trait to have a method with the same + /// name, then the names will collide. In the future, when the method is + /// stabilized, this will cause an error due to the ambiguity. This lint + /// is an early-warning to let you know that there may be a collision in + /// the future. This can be avoided by adding type annotations to + /// disambiguate which trait method you intend to call, such as + /// `MyIterator::is_sorted(my_iter)` or renaming or removing the method. + /// + /// [nightly channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ + pub UNSTABLE_NAME_COLLISIONS, + Warn, + "detects name collision with an existing but unstable method", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #48919 ", + edition: None, + // Note: this item represents future incompatibility of all unstable functions in the + // standard library, and thus should never be removed or changed to an error. + }; +} + +declare_lint! { + /// The `irrefutable_let_patterns` lint detects detects [irrefutable + /// patterns] in [if-let] and [while-let] statements. + /// + /// + /// + /// ### Example + /// + /// ```rust + /// if let _ = 123 { + /// println!("always runs!"); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// There usually isn't a reason to have an irrefutable pattern in an + /// if-let or while-let statement, because the pattern will always match + /// successfully. A [`let`] or [`loop`] statement will suffice. However, + /// when generating code with a macro, forbidding irrefutable patterns + /// would require awkward workarounds in situations where the macro + /// doesn't know if the pattern is refutable or not. This lint allows + /// macros to accept this form, while alerting for a possibly incorrect + /// use in normal code. + /// + /// See [RFC 2086] for more details. + /// + /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability + /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions + /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops + /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements + /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops + /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md + pub IRREFUTABLE_LET_PATTERNS, + Warn, + "detects irrefutable patterns in if-let and while-let statements" +} + +declare_lint! { + /// The `unused_labels` lint detects [labels] that are never used. + /// + /// [labels]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#loop-labels + /// + /// ### Example + /// + /// ```rust,no_run + /// 'unused_label: loop {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused labels may signal a mistake or unfinished code. To silence the + /// warning for the individual label, prefix it with an underscore such as + /// `'_my_label:`. + pub UNUSED_LABELS, + Warn, + "detects labels that are never used" +} + +declare_lint! { + /// The `broken_intra_doc_links` lint detects failures in resolving + /// intra-doc link targets. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links + pub BROKEN_INTRA_DOC_LINKS, + Warn, + "failures in resolving intra-doc link targets" +} + +declare_lint! { + /// This is a subset of `broken_intra_doc_links` that warns when linking from + /// a public item to a private one. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links + pub PRIVATE_INTRA_DOC_LINKS, + Warn, + "linking from a public item to a private one" +} + +declare_lint! { + /// The `invalid_codeblock_attributes` lint detects code block attributes + /// in documentation examples that have potentially mis-typed values. This + /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes + pub INVALID_CODEBLOCK_ATTRIBUTES, + Warn, + "codeblock attribute looks a lot like a known one" +} + +declare_lint! { + /// The `missing_crate_level_docs` lint detects if documentation is + /// missing at the crate root. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs + pub MISSING_CRATE_LEVEL_DOCS, + Allow, + "detects crates with no crate-level documentation" +} + +declare_lint! { + /// The `missing_doc_code_examples` lint detects publicly-exported items + /// without code samples in their documentation. This is a `rustdoc` only + /// lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples + pub MISSING_DOC_CODE_EXAMPLES, + Allow, + "detects publicly-exported items without code samples in their documentation" +} + +declare_lint! { + /// The `private_doc_tests` lint detects code samples in docs of private + /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see + /// the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests + pub PRIVATE_DOC_TESTS, + Allow, + "detects code samples in docs of private items not documented by rustdoc" +} + +declare_lint! { + /// The `where_clauses_object_safety` lint detects for [object safety] of + /// [where clauses]. + /// + /// [object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety + /// [where clauses]: https://doc.rust-lang.org/reference/items/generics.html#where-clauses + /// + /// ### Example + /// + /// ```rust,no_run + /// trait Trait {} + /// + /// trait X { fn foo(&self) where Self: Trait; } + /// + /// impl X for () { fn foo(&self) {} } + /// + /// impl Trait for dyn X {} + /// + /// // Segfault at opt-level 0, SIGILL otherwise. + /// pub fn main() { ::foo(&()); } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler previously allowed these object-unsafe bounds, which was + /// incorrect. This is a [future-incompatible] lint to transition this to + /// a hard error in the future. See [issue #51443] for more details. + /// + /// [issue #51443]: https://github.com/rust-lang/rust/issues/51443 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub WHERE_CLAUSES_OBJECT_SAFETY, + Warn, + "checks the object safety of where clauses", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #51443 ", + edition: None, + }; +} + +declare_lint! { + /// The `proc_macro_derive_resolution_fallback` lint detects proc macro + /// derives using inaccessible names from parent modules. + /// + /// ### Example + /// + /// ```rust,ignore (proc-macro) + /// // foo.rs + /// #![crate_type = "proc-macro"] + /// + /// extern crate proc_macro; + /// + /// use proc_macro::*; + /// + /// #[proc_macro_derive(Foo)] + /// pub fn foo1(a: TokenStream) -> TokenStream { + /// drop(a); + /// "mod __bar { static mut BAR: Option = None; }".parse().unwrap() + /// } + /// ``` + /// + /// ```rust,ignore (needs-dependency) + /// // bar.rs + /// #[macro_use] + /// extern crate foo; + /// + /// struct Something; + /// + /// #[derive(Foo)] + /// struct Another; + /// + /// fn main() {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: cannot find type `Something` in this scope + /// --> src/main.rs:8:10 + /// | + /// 8 | #[derive(Foo)] + /// | ^^^ names from parent modules are not accessible without an explicit import + /// | + /// = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #50504 + /// ``` + /// + /// ### Explanation + /// + /// If a proc-macro generates a module, the compiler unintentionally + /// allowed items in that module to refer to items in the crate root + /// without importing them. This is a [future-incompatible] lint to + /// transition this to a hard error in the future. See [issue #50504] for + /// more details. + /// + /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + Warn, + "detects proc macro derives using inaccessible names from parent modules", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #50504 ", + edition: None, + }; +} + +declare_lint! { + /// The `macro_use_extern_crate` lint detects the use of the + /// [`macro_use` attribute]. + /// + /// ### Example + /// + /// ```rust,ignore (needs extern crate) + /// #![deny(macro_use_extern_crate)] + /// + /// #[macro_use] + /// extern crate serde_json; + /// + /// fn main() { + /// let _ = json!{{}}; + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead + /// --> src/main.rs:3:1 + /// | + /// 3 | #[macro_use] + /// | ^^^^^^^^^^^^ + /// | + /// note: the lint level is defined here + /// --> src/main.rs:1:9 + /// | + /// 1 | #![deny(macro_use_extern_crate)] + /// | ^^^^^^^^^^^^^^^^^^^^^^ + /// ``` + /// + /// ### Explanation + /// + /// The [`macro_use` attribute] on an [`extern crate`] item causes + /// macros in that external crate to be brought into the prelude of the + /// crate, making the macros in scope everywhere. As part of the efforts + /// to simplify handling of dependencies in the [2018 edition], the use of + /// `extern crate` is being phased out. To bring macros from extern crates + /// into scope, it is recommended to use a [`use` import]. + /// + /// This lint is "allow" by default because this is a stylistic choice + /// that has not been settled, see [issue #52043] for more information. + /// + /// [`macro_use` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute + /// [`use` import]: https://doc.rust-lang.org/reference/items/use-declarations.html + /// [issue #52043]: https://github.com/rust-lang/rust/issues/52043 + pub MACRO_USE_EXTERN_CRATE, + Allow, + "the `#[macro_use]` attribute is now deprecated in favor of using macros \ + via the module system" +} + +declare_lint! { + /// The `macro_expanded_macro_exports_accessed_by_absolute_paths` lint + /// detects macro-expanded [`macro_export`] macros from the current crate + /// that cannot be referred to by absolute paths. + /// + /// [`macro_export`]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope + /// + /// ### Example + /// + /// ```rust,compile_fail + /// macro_rules! define_exported { + /// () => { + /// #[macro_export] + /// macro_rules! exported { + /// () => {}; + /// } + /// }; + /// } + /// + /// define_exported!(); + /// + /// fn main() { + /// crate::exported!(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The intent is that all macros marked with the `#[macro_export]` + /// attribute are made available in the root of the crate. However, when a + /// `macro_rules!` definition is generated by another macro, the macro + /// expansion is unable to uphold this rule. This is a + /// [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #53495] for more details. + /// + /// [issue #53495]: https://github.com/rust-lang/rust/issues/53495 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + Deny, + "macro-expanded `macro_export` macros from the current crate \ + cannot be referred to by absolute paths", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #52234 ", + edition: None, + }; + crate_level_only +} + +declare_lint! { + /// The `explicit_outlives_requirements` lint detects unnecessary + /// lifetime bounds that can be inferred. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// #![deny(explicit_outlives_requirements)] + /// + /// struct SharedRef<'a, T> + /// where + /// T: 'a, + /// { + /// data: &'a T, + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If a `struct` contains a reference, such as `&'a T`, the compiler + /// requires that `T` outlives the lifetime `'a`. This historically + /// required writing an explicit lifetime bound to indicate this + /// requirement. However, this can be overly explicit, causing clutter and + /// unnecessary complexity. The language was changed to automatically + /// infer the bound if it is not specified. Specifically, if the struct + /// contains a reference, directly or indirectly, to `T` with lifetime + /// `'x`, then it will infer that `T: 'x` is a requirement. + /// + /// This lint is "allow" by default because it can be noisy for existing + /// code that already had these requirements. This is a stylistic choice, + /// as it is still valid to explicitly state the bound. It also has some + /// false positives that can cause confusion. + /// + /// See [RFC 2093] for more details. + /// + /// [RFC 2093]: https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md + pub EXPLICIT_OUTLIVES_REQUIREMENTS, + Allow, + "outlives requirements can be inferred" +} + +declare_lint! { + /// The `indirect_structural_match` lint detects a `const` in a pattern + /// that manually implements [`PartialEq`] and [`Eq`]. + /// + /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(indirect_structural_match)] + /// + /// struct NoDerive(i32); + /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + /// impl Eq for NoDerive { } + /// #[derive(PartialEq, Eq)] + /// struct WrapParam(T); + /// const WRAP_INDIRECT_PARAM: & &WrapParam = & &WrapParam(NoDerive(0)); + /// fn main() { + /// match WRAP_INDIRECT_PARAM { + /// WRAP_INDIRECT_PARAM => { } + /// _ => { } + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler unintentionally accepted this form in the past. This is a + /// [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #62411] for a complete description of the problem, + /// and some possible solutions. + /// + /// [issue #62411]: https://github.com/rust-lang/rust/issues/62411 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub INDIRECT_STRUCTURAL_MATCH, + Warn, + "constant used in pattern contains value of non-structural-match type in a field or a variant", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #62411 ", + edition: None, + }; +} + +declare_lint! { + /// The `deprecated_in_future` lint is internal to rustc and should not be + /// used by user code. + /// + /// This lint is only enabled in the standard library. It works with the + /// use of `#[rustc_deprecated]` with a `since` field of a version in the + /// future. This allows something to be marked as deprecated in a future + /// version, and then this lint will ensure that the item is no longer + /// used in the standard library. See the [stability documentation] for + /// more details. + /// + /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#rustc_deprecated + pub DEPRECATED_IN_FUTURE, + Allow, + "detects use of items that will be deprecated in a future version", + report_in_external_macro +} + +declare_lint! { + /// The `pointer_structural_match` lint detects pointers used in patterns whose behaviour + /// cannot be relied upon across compiler versions and optimization levels. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(pointer_structural_match)] + /// fn foo(a: usize, b: usize) -> usize { a + b } + /// const FOO: fn(usize, usize) -> usize = foo; + /// fn main() { + /// match FOO { + /// FOO => {}, + /// _ => {}, + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust allowed function pointers and wide raw pointers in patterns. + /// While these work in many cases as expected by users, it is possible that due to + /// optimizations pointers are "not equal to themselves" or pointers to different functions + /// compare as equal during runtime. This is because LLVM optimizations can deduplicate + /// functions if their bodies are the same, thus also making pointers to these functions point + /// to the same location. Additionally functions may get duplicated if they are instantiated + /// in different crates and not deduplicated again via LTO. + pub POINTER_STRUCTURAL_MATCH, + Allow, + "pointers are not structural-match", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #62411 ", + edition: None, + }; +} + +declare_lint! { + /// The `nontrivial_structural_match` lint detects constants that are used in patterns, + /// whose type is not structural-match and whose initializer body actually uses values + /// that are not structural-match. So `Option` is ok if the constant + /// is just `None`. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(nontrivial_structural_match)] + /// + /// #[derive(Copy, Clone, Debug)] + /// struct NoDerive(u32); + /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + /// impl Eq for NoDerive { } + /// fn main() { + /// const INDEX: Option = [None, Some(NoDerive(10))][0]; + /// match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust accepted constants in patterns, even if those constants's types + /// did not have `PartialEq` derived. Thus the compiler falls back to runtime execution of + /// `PartialEq`, which can report that two constants are not equal even if they are + /// bit-equivalent. + pub NONTRIVIAL_STRUCTURAL_MATCH, + Warn, + "constant used in pattern of non-structural-match type and the constant's initializer \ + expression contains values of non-structural-match types", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #73448 ", + edition: None, + }; +} + +declare_lint! { + /// The `ambiguous_associated_items` lint detects ambiguity between + /// [associated items] and [enum variants]. + /// + /// [associated items]: https://doc.rust-lang.org/reference/items/associated-items.html + /// [enum variants]: https://doc.rust-lang.org/reference/items/enumerations.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// enum E { + /// V + /// } + /// + /// trait Tr { + /// type V; + /// fn foo() -> Self::V; + /// } + /// + /// impl Tr for E { + /// type V = u8; + /// // `Self::V` is ambiguous because it may refer to the associated type or + /// // the enum variant. + /// fn foo() -> Self::V { 0 } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust did not allow accessing enum variants + /// through [type aliases]. When this ability was added (see [RFC 2338]), this + /// introduced some situations where it can be ambiguous what a type + /// was referring to. + /// + /// To fix this ambiguity, you should use a [qualified path] to explicitly + /// state which type to use. For example, in the above example the + /// function can be written as `fn f() -> ::V { 0 }` to + /// specifically refer to the associated type. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #57644] for more details. + /// + /// [issue #57644]: https://github.com/rust-lang/rust/issues/57644 + /// [type aliases]: https://doc.rust-lang.org/reference/items/type-aliases.html#type-aliases + /// [RFC 2338]: https://github.com/rust-lang/rfcs/blob/master/text/2338-type-alias-enum-variants.md + /// [qualified path]: https://doc.rust-lang.org/reference/paths.html#qualified-paths + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub AMBIGUOUS_ASSOCIATED_ITEMS, + Deny, + "ambiguous associated items", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #57644 ", + edition: None, + }; +} + +declare_lint! { + /// The `mutable_borrow_reservation_conflict` lint detects the reservation + /// of a two-phased borrow that conflicts with other shared borrows. + /// + /// ### Example + /// + /// ```rust + /// let mut v = vec![0, 1, 2]; + /// let shared = &v; + /// v.push(shared.len()); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #59159] for a complete description of the + /// problem, and some possible solutions. + /// + /// [issue #59159]: https://github.com/rust-lang/rust/issues/59159 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub MUTABLE_BORROW_RESERVATION_CONFLICT, + Warn, + "reservation of a two-phased borrow conflicts with other shared borrows", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #59159 ", + edition: None, + }; +} + +declare_lint! { + /// The `soft_unstable` lint detects unstable features that were + /// unintentionally allowed on stable. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[cfg(test)] + /// extern crate test; + /// + /// #[bench] + /// fn name(b: &mut test::Bencher) { + /// b.iter(|| 123) + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The [`bench` attribute] was accidentally allowed to be specified on + /// the [stable release channel]. Turning this to a hard error would have + /// broken some projects. This lint allows those projects to continue to + /// build correctly when [`--cap-lints`] is used, but otherwise signal an + /// error that `#[bench]` should not be used on the stable channel. This + /// is a [future-incompatible] lint to transition this to a hard error in + /// the future. See [issue #64266] for more details. + /// + /// [issue #64266]: https://github.com/rust-lang/rust/issues/64266 + /// [`bench` attribute]: https://doc.rust-lang.org/nightly/unstable-book/library-features/test.html + /// [stable release channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// [`--cap-lints`]: https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub SOFT_UNSTABLE, + Deny, + "a feature gate that doesn't break dependent crates", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #64266 ", + edition: None, + }; +} + +declare_lint! { + /// The `inline_no_sanitize` lint detects incompatible use of + /// [`#[inline(always)]`][inline] and [`#[no_sanitize(...)]`][no_sanitize]. + /// + /// [inline]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute + /// [no_sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html + /// + /// ### Example + /// + /// ```rust + /// #![feature(no_sanitize)] + /// + /// #[inline(always)] + /// #[no_sanitize(address)] + /// fn x() {} + /// + /// fn main() { + /// x() + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The use of the [`#[inline(always)]`][inline] attribute prevents the + /// the [`#[no_sanitize(...)]`][no_sanitize] attribute from working. + /// Consider temporarily removing `inline` attribute. + pub INLINE_NO_SANITIZE, + Warn, + "detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`", +} + +declare_lint! { + /// The `asm_sub_register` lint detects using only a subset of a register + /// for inline asm inputs. + /// + /// ### Example + /// + /// ```rust,ignore (fails on system llvm) + /// #![feature(asm)] + /// + /// fn main() { + /// #[cfg(target_arch="x86_64")] + /// unsafe { + /// asm!("mov {0}, {0}", in(reg) 0i16); + /// } + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: formatting may not be suitable for sub-register argument + /// --> src/main.rs:6:19 + /// | + /// 6 | asm!("mov {0}, {0}", in(reg) 0i16); + /// | ^^^ ^^^ ---- for this argument + /// | + /// = note: `#[warn(asm_sub_register)]` on by default + /// = help: use the `x` modifier to have the register formatted as `ax` + /// = help: or use the `r` modifier to keep the default formatting of `rax` + /// ``` + /// + /// ### Explanation + /// + /// Registers on some architectures can use different names to refer to a + /// subset of the register. By default, the compiler will use the name for + /// the full register size. To explicitly use a subset of the register, + /// you can override the default by using a modifier on the template + /// string operand to specify when subregister to use. This lint is issued + /// if you pass in a value with a smaller data type than the default + /// register size, to alert you of possibly using the incorrect width. To + /// fix this, add the suggested modifier to the template, or cast the + /// value to the correct size. + /// + /// See [register template modifiers] for more details. + /// + /// [register template modifiers]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#register-template-modifiers + pub ASM_SUB_REGISTER, + Warn, + "using only a subset of a register for inline asm inputs", +} + +declare_lint! { + /// The `unsafe_op_in_unsafe_fn` lint detects unsafe operations in unsafe + /// functions without an explicit unsafe block. This lint only works on + /// the [**nightly channel**] with the + /// `#![feature(unsafe_block_in_unsafe_fn)]` feature. + /// + /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![feature(unsafe_block_in_unsafe_fn)] + /// #![deny(unsafe_op_in_unsafe_fn)] + /// + /// unsafe fn foo() {} + /// + /// unsafe fn bar() { + /// foo(); + /// } + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Currently, an [`unsafe fn`] allows any [unsafe] operation within its + /// body. However, this can increase the surface area of code that needs + /// to be scrutinized for proper behavior. The [`unsafe` block] provides a + /// convenient way to make it clear exactly which parts of the code are + /// performing unsafe operations. In the future, it is desired to change + /// it so that unsafe operations cannot be performed in an `unsafe fn` + /// without an `unsafe` block. + /// + /// The fix to this is to wrap the unsafe code in an `unsafe` block. + /// + /// This lint is "allow" by default because it has not yet been + /// stabilized, and is not yet complete. See [RFC #2585] and [issue + /// #71668] for more details + /// + /// [`unsafe fn`]: https://doc.rust-lang.org/reference/unsafe-functions.html + /// [`unsafe` block]: https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks + /// [unsafe]: https://doc.rust-lang.org/reference/unsafety.html + /// [RFC #2585]: https://github.com/rust-lang/rfcs/blob/master/text/2585-unsafe-block-in-unsafe-fn.md + /// [issue #71668]: https://github.com/rust-lang/rust/issues/71668 + pub UNSAFE_OP_IN_UNSAFE_FN, + Allow, + "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", + @feature_gate = sym::unsafe_block_in_unsafe_fn; +} + +declare_lint! { + /// The `cenum_impl_drop_cast` lint detects an `as` cast of a field-less + /// `enum` that implements [`Drop`]. + /// + /// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// enum E { + /// A, + /// } + /// + /// impl Drop for E { + /// fn drop(&mut self) { + /// println!("Drop"); + /// } + /// } + /// + /// fn main() { + /// let e = E::A; + /// let i = e as u32; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Casting a field-less `enum` that does not implement [`Copy`] to an + /// integer moves the value without calling `drop`. This can result in + /// surprising behavior if it was expected that `drop` should be called. + /// Calling `drop` automatically would be inconsistent with other move + /// operations. Since neither behavior is clear or consistent, it was + /// decided that a cast of this nature will no longer be allowed. + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #73333] for more details. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + /// [issue #73333]: https://github.com/rust-lang/rust/issues/73333 + /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html + pub CENUM_IMPL_DROP_CAST, + Warn, + "a C-like enum implementing Drop is cast", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #73333 ", + edition: None, + }; +} + +declare_lint! { + /// The `const_evaluatable_unchecked` lint detects a generic constant used + /// in a type. + /// + /// ### Example + /// + /// ```rust + /// const fn foo() -> usize { + /// if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T + /// 4 + /// } else { + /// 8 + /// } + /// } + /// + /// fn test() { + /// let _ = [0; foo::()]; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the 1.43 release, some uses of generic parameters in array repeat + /// expressions were accidentally allowed. This is a [future-incompatible] + /// lint to transition this to a hard error in the future. See [issue + /// #76200] for a more detailed description and possible fixes. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + /// [issue #76200]: https://github.com/rust-lang/rust/issues/76200 + pub CONST_EVALUATABLE_UNCHECKED, + Warn, + "detects a generic constant is used in a type without a emitting a warning", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #76200 ", + edition: None, + }; +} + +declare_tool_lint! { + pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + Deny, + "detects `#[unstable]` on stable trait implementations for stable types" +} + +declare_lint_pass! { + /// Does nothing as a lint pass, but registers some `Lint`s + /// that are used by other parts of the compiler. + HardwiredLints => [ + ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + ARITHMETIC_OVERFLOW, + UNCONDITIONAL_PANIC, + UNUSED_IMPORTS, + UNUSED_EXTERN_CRATES, + UNUSED_CRATE_DEPENDENCIES, + UNUSED_QUALIFICATIONS, + UNKNOWN_LINTS, + UNUSED_VARIABLES, + UNUSED_ASSIGNMENTS, + DEAD_CODE, + UNREACHABLE_CODE, + UNREACHABLE_PATTERNS, + OVERLAPPING_PATTERNS, + BINDINGS_WITH_VARIANT_NAME, + UNUSED_MACROS, + WARNINGS, + UNUSED_FEATURES, + STABLE_FEATURES, + UNKNOWN_CRATE_TYPES, + TRIVIAL_CASTS, + TRIVIAL_NUMERIC_CASTS, + PRIVATE_IN_PUBLIC, + EXPORTED_PRIVATE_DEPENDENCIES, + PUB_USE_OF_PRIVATE_EXTERN_CRATE, + INVALID_TYPE_PARAM_DEFAULT, + CONST_ERR, + RENAMED_AND_REMOVED_LINTS, + UNALIGNED_REFERENCES, + CONST_ITEM_MUTATION, + SAFE_PACKED_BORROWS, + PATTERNS_IN_FNS_WITHOUT_BODY, + LATE_BOUND_LIFETIME_ARGUMENTS, + ORDER_DEPENDENT_TRAIT_OBJECTS, + COHERENCE_LEAK_CHECK, + DEPRECATED, + UNUSED_UNSAFE, + UNUSED_MUT, + UNCONDITIONAL_RECURSION, + SINGLE_USE_LIFETIMES, + UNUSED_LIFETIMES, + UNUSED_LABELS, + TYVAR_BEHIND_RAW_POINTER, + ELIDED_LIFETIMES_IN_PATHS, + BARE_TRAIT_OBJECTS, + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + UNSTABLE_NAME_COLLISIONS, + IRREFUTABLE_LET_PATTERNS, + BROKEN_INTRA_DOC_LINKS, + INVALID_CODEBLOCK_ATTRIBUTES, + MISSING_CRATE_LEVEL_DOCS, + MISSING_DOC_CODE_EXAMPLES, + PRIVATE_DOC_TESTS, + WHERE_CLAUSES_OBJECT_SAFETY, + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + MACRO_USE_EXTERN_CRATE, + MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + ILL_FORMED_ATTRIBUTE_INPUT, + CONFLICTING_REPR_HINTS, + META_VARIABLE_MISUSE, + DEPRECATED_IN_FUTURE, + AMBIGUOUS_ASSOCIATED_ITEMS, + MUTABLE_BORROW_RESERVATION_CONFLICT, + INDIRECT_STRUCTURAL_MATCH, + POINTER_STRUCTURAL_MATCH, + NONTRIVIAL_STRUCTURAL_MATCH, + SOFT_UNSTABLE, + INLINE_NO_SANITIZE, + ASM_SUB_REGISTER, + UNSAFE_OP_IN_UNSAFE_FN, + INCOMPLETE_INCLUDE, + CENUM_IMPL_DROP_CAST, + CONST_EVALUATABLE_UNCHECKED, + INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + MISSING_FRAGMENT_SPECIFIER, + ] +} + +declare_lint! { + /// The `unused_doc_comments` lint detects doc comments that aren't used + /// by `rustdoc`. + /// + /// ### Example + /// + /// ```rust + /// /// docs for x + /// let x = 12; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `rustdoc` does not use doc comments in all positions, and so the doc + /// comment will be ignored. Try changing it to a normal comment with `//` + /// to avoid the warning. + pub UNUSED_DOC_COMMENTS, + Warn, + "detects doc comments that aren't used by rustdoc" +} + +declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); diff --git a/src/librustc_session/options.rs b/compiler/rustc_session/src/options.rs similarity index 93% rename from src/librustc_session/options.rs rename to compiler/rustc_session/src/options.rs index d05f1a3f34..b705ab6d93 100644 --- a/src/librustc_session/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -125,6 +125,9 @@ top_level_options!( // try to not rely on this too much. actually_rustdoc: bool [TRACKED], + // Control path trimming. + trimmed_def_paths: TrimmedDefPaths [TRACKED], + // Specifications of codegen units / ThinLTO which are forced as a // result of parsing command line options. These are not necessarily // what rustc was invoked with, but massaged a bit to agree with @@ -255,6 +258,7 @@ macro_rules! options { 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_optimization_fuel: &str = "crate=integer"; + pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0"; pub const parse_lto: &str = @@ -551,6 +555,36 @@ macro_rules! options { } } + fn parse_mir_spanview(slot: &mut Option, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + Some(MirSpanview::Statement) + } else { + None + }; + return true + } + } + + let v = match v { + None => { + *slot = Some(MirSpanview::Statement); + return true; + } + Some(v) => v, + }; + + *slot = Some(match v.trim_end_matches("s") { + "statement" | "stmt" => MirSpanview::Statement, + "terminator" | "term" => MirSpanview::Terminator, + "block" | "basicblock" => MirSpanview::Block, + _ => return false, + }); + true + } + fn parse_treat_err_as_bug(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 } @@ -719,6 +753,9 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "extra arguments to append to the linker invocation (space separated)"), link_dead_code: Option = (None, parse_opt_bool, [UNTRACKED], "keep dead code at link time (useful for code coverage) (default: no)"), + link_self_contained: Option = (None, parse_opt_bool, [UNTRACKED], + "control whether to link Rust provided C objects/libraries or rely + 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], @@ -813,6 +850,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable the experimental Chalk-based trait solving engine"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), + combine_cgu: bool = (false, parse_bool, [TRACKED], + "combine CGUs into a single one"), crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], "inject the given attribute in the crate"), debug_macros: bool = (false, parse_bool, [TRACKED], @@ -849,8 +888,18 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "exclude the pass number when dumping MIR (used in tests) (default: no)"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], "in addition to `.mir` files, create graphviz `.dot` files (default: no)"), + dump_mir_spanview: Option = (None, parse_mir_spanview, [UNTRACKED], + "in addition to `.mir` files, create `.html` files to view spans for \ + all `statement`s (including terminators), only `terminator` spans, or \ + computed `block` spans (one span encompassing a block's terminator and \ + all statements)."), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), + experimental_coverage: bool = (false, parse_bool, [TRACKED], + "enable and extend the `-Z instrument-coverage` function-level coverage \ + feature, adding additional experimental (likely inaccurate) counters and \ + code regions (used by `rustc` compiler developers to test new coverage \ + counter placements) (default: no)"), fewer_names: bool = (false, parse_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), @@ -860,6 +909,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "force all crates to be `rustc_private` unstable (default: no)"), fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], "set the optimization fuel quota for a crate"), + graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED], + "use dark-themed colors in graphviz output (default: no)"), + graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED], + "use the given `fontname` in graphviz output; can be overridden by setting \ + environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), hir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about AST and HIR (default: no)"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], @@ -885,18 +939,15 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`, \ and is mutually exclusive with `-C profile-generate`/`-C profile-use`); \ - implies `-C link-dead-code` (unless explicitly disabled)` and \ - `-Z symbol-mangling-version=v0`; and disables/overrides some optimization \ - options (default: no)"), + implies `-C link-dead-code` (unless targeting MSVC, or explicitly disabled) \ + and `-Z symbol-mangling-version=v0`; disables/overrides some Rust \ + optimizations (default: no)"), 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], "keep hygiene data after analysis (default: no)"), link_native_libraries: bool = (true, parse_bool, [UNTRACKED], "link native libraries in the linker invocation (default: yes)"), - link_self_contained: Option = (None, parse_opt_bool, [TRACKED], - "control whether to link Rust provided C objects/libraries or rely - on C toolchain installed in the system"), link_only: bool = (false, parse_bool, [TRACKED], "link the `.rlink` file generated by `-Z no-link` (default: no)"), llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], @@ -957,6 +1008,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "a single extra argument to prepend the linker invocation (can be used several times)"), pre_link_args: Vec = (Vec::new(), parse_list, [UNTRACKED], "extra arguments to prepend to the linker invocation (space separated)"), + precise_enum_drop_elaboration: bool = (true, parse_bool, [TRACKED], + "use a more precise version of drop elaboration for matches on enums (default: yes). \ + This results in better codegen, but has caused miscompilations on some tier 2 platforms. \ + See #77382 and #74551."), print_fuel: Option = (None, parse_opt_string, [TRACKED], "make rustc print the total optimization fuel used by a crate"), print_link_args: bool = (false, parse_bool, [UNTRACKED], @@ -967,6 +1022,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print the result of the monomorphization collection pass"), print_type_sizes: bool = (false, parse_bool, [UNTRACKED], "print layout information for each type encountered (default: no)"), + proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED], + "show backtraces for panics during proc-macro execution (default: no)"), profile: bool = (false, parse_bool, [TRACKED], "insert profiling code (default: no)"), profile_emit: Option = (None, parse_opt_pathbuf, [TRACKED], @@ -1046,6 +1103,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "for every macro invocation, print its name and arguments (default: no)"), treat_err_as_bug: Option = (None, parse_treat_err_as_bug, [TRACKED], "treat error number `val` that occurs as bug"), + trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], + "in diagnostics, use heuristics to shorten paths referring to items"), ui_testing: bool = (false, parse_bool, [UNTRACKED], "emit compiler diagnostics in a form suitable for UI testing (default: no)"), unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED], @@ -1060,6 +1119,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, `hir,typed` (HIR with types for each node), `hir-tree` (dump the raw HIR), `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"), + unsound_mir_opts: bool = (false, parse_bool, [TRACKED], + "enable unsound and buggy MIR optimizations (default: no)"), 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], diff --git a/src/librustc_session/output.rs b/compiler/rustc_session/src/output.rs similarity index 100% rename from src/librustc_session/output.rs rename to compiler/rustc_session/src/output.rs diff --git a/src/librustc_session/parse.rs b/compiler/rustc_session/src/parse.rs similarity index 100% rename from src/librustc_session/parse.rs rename to compiler/rustc_session/src/parse.rs diff --git a/src/librustc_session/search_paths.rs b/compiler/rustc_session/src/search_paths.rs similarity index 81% rename from src/librustc_session/search_paths.rs rename to compiler/rustc_session/src/search_paths.rs index e12364b7da..83b737a73b 100644 --- a/src/librustc_session/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -56,16 +56,16 @@ impl PathKind { impl SearchPath { pub fn from_cli_opt(path: &str, output: config::ErrorOutputType) -> Self { - let (kind, path) = if path.starts_with("native=") { - (PathKind::Native, &path["native=".len()..]) - } else if path.starts_with("crate=") { - (PathKind::Crate, &path["crate=".len()..]) - } else if path.starts_with("dependency=") { - (PathKind::Dependency, &path["dependency=".len()..]) - } else if path.starts_with("framework=") { - (PathKind::Framework, &path["framework=".len()..]) - } else if path.starts_with("all=") { - (PathKind::All, &path["all=".len()..]) + let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") { + (PathKind::Native, stripped) + } else if let Some(stripped) = path.strip_prefix("crate=") { + (PathKind::Crate, stripped) + } else if let Some(stripped) = path.strip_prefix("dependency=") { + (PathKind::Dependency, stripped) + } else if let Some(stripped) = path.strip_prefix("framework=") { + (PathKind::Framework, stripped) + } else if let Some(stripped) = path.strip_prefix("all=") { + (PathKind::All, stripped) } else { (PathKind::All, path) }; diff --git a/src/librustc_session/session.rs b/compiler/rustc_session/src/session.rs similarity index 94% rename from src/librustc_session/session.rs rename to compiler/rustc_session/src/session.rs index c006e593e4..ff5e6156d8 100644 --- a/src/librustc_session/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -213,6 +213,9 @@ pub struct Session { known_attrs: Lock, used_attrs: Lock, + + /// `Span`s for `if` conditions that we have suggested turning into `if let`. + pub if_let_suggestions: Lock>, } pub struct PerfStats { @@ -234,6 +237,14 @@ enum DiagnosticBuilderMethod { // Add more variants as needed to support one-time diagnostics. } +/// Trait implemented by error types. This should not be implemented manually. Instead, use +/// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic]. +pub trait SessionDiagnostic<'a> { + /// Write out as a diagnostic out of `sess`. + #[must_use] + fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a>; +} + /// Diagnostic message ID, used by `Session.one_time_diagnostics` to avoid /// emitting the same message more than once. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -389,6 +400,9 @@ impl Session { pub fn err(&self, msg: &str) { self.diagnostic().err(msg) } + pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) { + err.into_diagnostic(self).emit() + } pub fn err_count(&self) -> usize { self.diagnostic().err_count() } @@ -439,6 +453,24 @@ impl Session { pub fn delay_span_bug>(&self, sp: S, msg: &str) { self.diagnostic().delay_span_bug(sp, msg) } + + /// Used for code paths of expensive computations that should only take place when + /// warnings or errors are emitted. If no messages are emitted ("good path"), then + /// it's likely a bug. + pub fn delay_good_path_bug(&self, msg: &str) { + if self.opts.debugging_opts.print_type_sizes + || self.opts.debugging_opts.query_dep_graph + || self.opts.debugging_opts.dump_mir.is_some() + || self.opts.debugging_opts.unpretty.is_some() + || self.opts.output_types.contains_key(&OutputType::Mir) + || std::env::var_os("RUSTC_LOG").is_some() + { + return; + } + + self.diagnostic().delay_good_path_bug(msg) + } + pub fn note_without_error(&self, msg: &str) { self.diagnostic().note_without_error(msg) } @@ -1021,6 +1053,40 @@ impl Session { || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY) } + pub fn link_dead_code(&self) -> bool { + match self.opts.cg.link_dead_code { + Some(explicitly_set) => explicitly_set, + None => { + self.opts.debugging_opts.instrument_coverage + && !self.target.target.options.is_like_msvc + // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid + // binaries when LLVM InstrProf counters are enabled). As described by this issue, + // the "link dead code" option produces incorrect binaries when compiled and linked + // under MSVC. The resulting Rust programs typically crash with a segmentation + // fault, or produce an empty "*.profraw" file (profiling counter results normally + // generated during program exit). + // + // If not targeting MSVC, `-Z instrument-coverage` implies `-C link-dead-code`, so + // unexecuted code is still counted as zero, rather than be optimized out. Note that + // instrumenting dead code can be explicitly disabled with: + // + // `-Z instrument-coverage -C link-dead-code=no`. + // + // FIXME(richkadel): Investigate if `instrument-coverage` implementation can inject + // [zero counters](https://llvm.org/docs/CoverageMappingFormat.html#counter) in the + // coverage map when "dead code" is removed, rather than forcing `link-dead-code`. + // This may not be possible, however, if (as it seems to appear) the "dead code" + // that would otherwise not be linked is only identified as "dead" by the native + // linker. If that's the case, I believe it is too late for the Rust compiler to + // leverage any information it might be able to get from the linker regarding what + // code is dead, to be able to add those counters. + // + // On the other hand, if any Rust compiler passes are optimizing out dead code blocks + // we should inject "zero" counters for those code regions. + } + } + } + pub fn mark_attr_known(&self, attr: &Attribute) { self.known_attrs.lock().mark(attr) } @@ -1037,9 +1103,6 @@ impl Session { self.used_attrs.lock().is_marked(attr) } - /// Returns `true` if the attribute's path matches the argument. If it matches, then the - /// attribute is marked as used. - /// Returns `true` if the attribute's path matches the argument. If it /// matches, then the attribute is marked as used. /// @@ -1168,6 +1231,7 @@ pub fn build_session( diagnostics_output: DiagnosticOutput, driver_lint_caps: FxHashMap, file_loader: Option>, + target_override: Option, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed @@ -1187,7 +1251,7 @@ pub fn build_session( DiagnosticOutput::Raw(write) => Some(write), }; - let target_cfg = config::build_target_config(&sopts, sopts.error_format); + let target_cfg = config::build_target_config(&sopts, target_override); let host_triple = TargetTriple::from_triple(config::host_triple()); let host = Target::search(&host_triple).unwrap_or_else(|e| { early_error(sopts.error_format, &format!("Error loading host specification: {}", e)) @@ -1354,6 +1418,7 @@ pub fn build_session( target_features: FxHashSet::default(), known_attrs: Lock::new(MarkedAttrs::new()), used_attrs: Lock::new(MarkedAttrs::new()), + if_let_suggestions: Default::default(), }; validate_commandline_args_with_session_available(&sess); @@ -1428,20 +1493,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) { ); } - // FIXME(richkadel): See `src/test/run-make-fulldeps/instrument-coverage/Makefile`. After - // compiling with `-Zinstrument-coverage`, the resulting binary generates a segfault during - // the program's exit process (likely while attempting to generate the coverage stats in - // the "*.profraw" file). An investigation to resolve the problem on Windows is ongoing, - // but until this is resolved, the option is disabled on Windows, and the test is skipped - // when targeting `MSVC`. - if sess.opts.debugging_opts.instrument_coverage && sess.target.target.options.is_like_msvc { - sess.warn( - "Rust source-based code coverage instrumentation (with `-Z instrument-coverage`) \ - is not yet supported on Windows when targeting MSVC. The resulting binaries will \ - still be instrumented for experimentation purposes, but may not execute correctly.", - ); - } - const ASAN_SUPPORTED_TARGETS: &[&str] = &[ "aarch64-fuchsia", "aarch64-unknown-linux-gnu", diff --git a/src/librustc_session/utils.rs b/compiler/rustc_session/src/utils.rs similarity index 100% rename from src/librustc_session/utils.rs rename to compiler/rustc_session/src/utils.rs diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml new file mode 100644 index 0000000000..1abfd50f00 --- /dev/null +++ b/compiler/rustc_span/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_span" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_serialize = { path = "../rustc_serialize" } +rustc_macros = { path = "../rustc_macros" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index" } +rustc_arena = { path = "../rustc_arena" } +scoped-tls = "1.0" +unicode-width = "0.1.4" +cfg-if = "0.1.2" +tracing = "0.1" +sha-1 = "0.8" +md-5 = "0.8" diff --git a/src/librustc_span/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs similarity index 100% rename from src/librustc_span/analyze_source_file.rs rename to compiler/rustc_span/src/analyze_source_file.rs diff --git a/src/librustc_span/analyze_source_file/tests.rs b/compiler/rustc_span/src/analyze_source_file/tests.rs similarity index 100% rename from src/librustc_span/analyze_source_file/tests.rs rename to compiler/rustc_span/src/analyze_source_file/tests.rs diff --git a/src/librustc_span/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs similarity index 100% rename from src/librustc_span/caching_source_map_view.rs rename to compiler/rustc_span/src/caching_source_map_view.rs diff --git a/src/librustc_span/def_id.rs b/compiler/rustc_span/src/def_id.rs similarity index 100% rename from src/librustc_span/def_id.rs rename to compiler/rustc_span/src/def_id.rs diff --git a/src/librustc_span/edition.rs b/compiler/rustc_span/src/edition.rs similarity index 100% rename from src/librustc_span/edition.rs rename to compiler/rustc_span/src/edition.rs diff --git a/src/librustc_span/fatal_error.rs b/compiler/rustc_span/src/fatal_error.rs similarity index 100% rename from src/librustc_span/fatal_error.rs rename to compiler/rustc_span/src/fatal_error.rs diff --git a/src/librustc_span/hygiene.rs b/compiler/rustc_span/src/hygiene.rs similarity index 99% rename from src/librustc_span/hygiene.rs rename to compiler/rustc_span/src/hygiene.rs index 942c664834..fb80dcb756 100644 --- a/src/librustc_span/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -702,7 +702,7 @@ pub struct ExpnData { /// The `DefId` of the macro being invoked, /// if this `ExpnData` corresponds to a macro invocation pub macro_def_id: Option, - /// The crate that originally created this `ExpnData. During + /// The crate that originally created this `ExpnData`. During /// metadata serialization, we only encode `ExpnData`s that were /// created locally - when our serialized metadata is decoded, /// foreign `ExpnId`s will have their `ExpnData` looked up @@ -759,7 +759,7 @@ impl ExpnData { #[inline] pub fn is_root(&self) -> bool { - if let ExpnKind::Root = self.kind { true } else { false } + matches!(self.kind, ExpnKind::Root) } } diff --git a/src/librustc_span/lib.rs b/compiler/rustc_span/src/lib.rs similarity index 95% rename from src/librustc_span/lib.rs rename to compiler/rustc_span/src/lib.rs index c654dade2a..96a6956a40 100644 --- a/src/librustc_span/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -4,16 +4,15 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] #![feature(const_panic)] #![feature(negative_impls)] #![feature(nll)] -#![feature(optin_builtin_traits)] #![feature(min_specialization)] #![feature(option_expect_none)] -#![feature(refcell_take)] #[macro_use] extern crate rustc_macros; @@ -400,6 +399,13 @@ impl Span { span.with_lo(span.hi) } + #[inline] + /// Returns true if hi == lo + pub fn is_empty(&self) -> bool { + let span = self.data(); + span.hi == span.lo + } + /// Returns `self` if `self` is not the dummy span, and `other` otherwise. pub fn substitute_dummy(self, other: Span) -> Span { if self.is_dummy() { other } else { self } @@ -537,6 +543,12 @@ impl Span { } /// Returns a `Span` that would enclose both `self` and `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^^^^^^^^ + /// ``` pub fn to(self, end: Span) -> Span { let span_data = self.data(); let end_data = end.data(); @@ -560,6 +572,12 @@ impl Span { } /// Returns a `Span` between the end of `self` to the beginning of `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^ + /// ``` pub fn between(self, end: Span) -> Span { let span = self.data(); let end = end.data(); @@ -570,7 +588,13 @@ impl Span { ) } - /// Returns a `Span` between the beginning of `self` to the beginning of `end`. + /// Returns a `Span` from the beginning of `self` until the beginning of `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^^^^^ + /// ``` pub fn until(self, end: Span) -> Span { let span = self.data(); let end = end.data(); @@ -1133,7 +1157,12 @@ impl Encodable for SourceFile { let max_line_length = if lines.len() == 1 { 0 } else { - lines.windows(2).map(|w| w[1] - w[0]).map(|bp| bp.to_usize()).max().unwrap() + lines + .array_windows() + .map(|&[fst, snd]| snd - fst) + .map(|bp| bp.to_usize()) + .max() + .unwrap() }; let bytes_per_diff: u8 = match max_line_length { @@ -1148,7 +1177,7 @@ impl Encodable for SourceFile { // Encode the first element. lines[0].encode(s)?; - let diff_iter = (&lines[..]).windows(2).map(|w| (w[1] - w[0])); + let diff_iter = lines[..].array_windows().map(|&[fst, snd]| snd - fst); match bytes_per_diff { 1 => { @@ -1529,58 +1558,71 @@ pub trait Pos { fn to_u32(&self) -> u32; } -/// A byte offset. Keep this small (currently 32-bits), as AST contains -/// a lot of them. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -pub struct BytePos(pub u32); - -/// A character offset. Because of multibyte UTF-8 characters, a byte offset -/// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` -/// values to `CharPos` values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct CharPos(pub usize); +macro_rules! impl_pos { + ( + $( + $(#[$attr:meta])* + $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty); + )* + ) => { + $( + $(#[$attr])* + $vis struct $ident($inner_vis $inner_ty); + + impl Pos for $ident { + #[inline(always)] + fn from_usize(n: usize) -> $ident { + $ident(n as $inner_ty) + } -// FIXME: lots of boilerplate in these impls, but so far my attempts to fix -// have been unsuccessful. + #[inline(always)] + fn to_usize(&self) -> usize { + self.0 as usize + } -impl Pos for BytePos { - #[inline(always)] - fn from_usize(n: usize) -> BytePos { - BytePos(n as u32) - } + #[inline(always)] + fn from_u32(n: u32) -> $ident { + $ident(n as $inner_ty) + } - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 as usize - } + #[inline(always)] + fn to_u32(&self) -> u32 { + self.0 as u32 + } + } - #[inline(always)] - fn from_u32(n: u32) -> BytePos { - BytePos(n) - } + impl Add for $ident { + type Output = $ident; - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 - } -} + #[inline(always)] + fn add(self, rhs: $ident) -> $ident { + $ident(self.0 + rhs.0) + } + } -impl Add for BytePos { - type Output = BytePos; + impl Sub for $ident { + type Output = $ident; - #[inline(always)] - fn add(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() + rhs.to_usize()) as u32) - } + #[inline(always)] + fn sub(self, rhs: $ident) -> $ident { + $ident(self.0 - rhs.0) + } + } + )* + }; } -impl Sub for BytePos { - type Output = BytePos; +impl_pos! { + /// A byte offset. Keep this small (currently 32-bits), as AST contains + /// a lot of them. + #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] + pub struct BytePos(pub u32); - #[inline(always)] - fn sub(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() - rhs.to_usize()) as u32) - } + /// A character offset. Because of multibyte UTF-8 characters, a byte offset + /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` + /// values to `CharPos` values as necessary. + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] + pub struct CharPos(pub usize); } impl Encodable for BytePos { @@ -1595,46 +1637,6 @@ impl Decodable for BytePos { } } -impl Pos for CharPos { - #[inline(always)] - fn from_usize(n: usize) -> CharPos { - CharPos(n) - } - - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 - } - - #[inline(always)] - fn from_u32(n: u32) -> CharPos { - CharPos(n as usize) - } - - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 as u32 - } -} - -impl Add for CharPos { - type Output = CharPos; - - #[inline(always)] - fn add(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() + rhs.to_usize()) - } -} - -impl Sub for CharPos { - type Output = CharPos; - - #[inline(always)] - fn sub(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() - rhs.to_usize()) - } -} - // _____________________________________________________________________________ // Loc, SourceFileAndLine, SourceFileAndBytePos // diff --git a/src/librustc_span/source_map.rs b/compiler/rustc_span/src/source_map.rs similarity index 98% rename from src/librustc_span/source_map.rs rename to compiler/rustc_span/src/source_map.rs index 7c656db22e..37596b8ef6 100644 --- a/src/librustc_span/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -487,6 +487,15 @@ impl SourceMap { } } + /// Returns a new `Span` covering the start and end `BytePos`s of the file containing the given + /// `pos`. This can be used to quickly determine if another `BytePos` or `Span` is from the same + /// file. + pub fn lookup_file_span(&self, pos: BytePos) -> Span { + let idx = self.lookup_source_file_idx(pos); + let SourceFile { start_pos, end_pos, .. } = *(*self.files.borrow().source_files)[idx]; + Span::with_root_ctxt(start_pos, end_pos) + } + /// Returns `Some(span)`, a union of the LHS and RHS span. The LHS must precede the RHS. If /// there are gaps between LHS and RHS, the resulting union will cross these gaps. /// For this to work, diff --git a/src/librustc_span/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs similarity index 100% rename from src/librustc_span/source_map/tests.rs rename to compiler/rustc_span/src/source_map/tests.rs diff --git a/src/librustc_span/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs similarity index 100% rename from src/librustc_span/span_encoding.rs rename to compiler/rustc_span/src/span_encoding.rs diff --git a/src/librustc_span/symbol.rs b/compiler/rustc_span/src/symbol.rs similarity index 99% rename from src/librustc_span/symbol.rs rename to compiler/rustc_span/src/symbol.rs index 46612145bf..e3ad31469b 100644 --- a/src/librustc_span/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -110,7 +110,7 @@ symbols! { // called `sym::proc_macro` because then it's easy to mistakenly think it // represents "proc_macro". // - // As well as the symbols listed, there are symbols for the the strings + // As well as the symbols listed, there are symbols for the strings // "0", "1", ..., "9", which are accessible via `sym::integer`. // // The proc macro will abort if symbols are not in alphabetical order (as @@ -333,9 +333,11 @@ symbols! { clone, clone_closures, clone_from, + closure, closure_to_fn_coercion, cmp, cmpxchg16b_target_feature, + cmse_nonsecure_entry, coerce_unsized, cold, column, @@ -348,8 +350,11 @@ symbols! { const_compare_raw_pointers, const_constructor, const_eval_limit, + const_evaluatable_checked, const_extern_fn, const_fn, + const_fn_floating_point_arithmetic, + const_fn_fn_ptr_basics, const_fn_transmute, const_fn_union, const_generics, @@ -368,6 +373,8 @@ symbols! { const_trait_bound_opt_out, const_trait_impl, const_transmute, + constant, + constructor, contents, context, convert, @@ -415,7 +422,9 @@ symbols! { deny, deprecated, deref, + deref_method, deref_mut, + deref_target, derive, diagnostic, direct, @@ -435,13 +444,6 @@ symbols! { document_private_items, dotdot_in_tuple_patterns, dotdoteq_in_patterns, - double_braced_closure: "{{closure}}", - double_braced_constant: "{{constant}}", - double_braced_constructor: "{{constructor}}", - double_braced_crate: "{{crate}}", - double_braced_impl: "{{impl}}", - double_braced_misc: "{{misc}}", - double_braced_opaque: "{{opaque}}", drop, drop_in_place, drop_types_in_const, @@ -676,7 +678,7 @@ symbols! { minnumf32, minnumf64, mips_target_feature, - mmx_target_feature, + misc, module, module_path, more_struct_aliases, @@ -876,6 +878,7 @@ symbols! { rust_2015_preview, rust_2018_preview, rust_begin_unwind, + rust_eh_catch_typeinfo, rust_eh_personality, rust_eh_register_frames, rust_eh_unregister_frames, @@ -883,7 +886,6 @@ symbols! { rustc, rustc_allocator, rustc_allocator_nounwind, - rustc_allow_const_fn_ptr, rustc_args_required_const, rustc_attrs, rustc_builtin_macro, @@ -1068,6 +1070,7 @@ symbols! { target_feature, target_feature_11, target_has_atomic, + target_has_atomic_equal_alignment, target_has_atomic_load_store, target_os, target_pointer_width, diff --git a/src/librustc_span/symbol/tests.rs b/compiler/rustc_span/src/symbol/tests.rs similarity index 100% rename from src/librustc_span/symbol/tests.rs rename to compiler/rustc_span/src/symbol/tests.rs diff --git a/src/librustc_span/tests.rs b/compiler/rustc_span/src/tests.rs similarity index 100% rename from src/librustc_span/tests.rs rename to compiler/rustc_span/src/tests.rs diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml new file mode 100644 index 0000000000..c0dacd24c3 --- /dev/null +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_symbol_mangling" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +tracing = "0.1" +punycode = "0.4.0" +rustc-demangle = "0.1.16" + +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_middle = { path = "../rustc_middle" } +rustc_hir = { path = "../rustc_hir" } +rustc_target = { path = "../rustc_target" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_session = { path = "../rustc_session" } diff --git a/src/librustc_symbol_mangling/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs similarity index 98% rename from src/librustc_symbol_mangling/legacy.rs rename to compiler/rustc_symbol_mangling/src/legacy.rs index 24356844ba..b96e318bd3 100644 --- a/src/librustc_symbol_mangling/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -110,7 +110,7 @@ fn get_symbol_hash<'tcx>( // If this is a function, we hash the signature as well. // This is not *strictly* needed, but it may help in some // situations, see the `run-make/a-b-a-linker-guard` test. - if let ty::FnDef(..) = item_type.kind { + if let ty::FnDef(..) = item_type.kind() { item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher); } @@ -210,7 +210,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { } fn print_type(self, ty: Ty<'tcx>) -> Result { - match ty.kind { + match *ty.kind() { // Print all nominal types as paths (unlike `pretty_print_type`). ty::FnDef(def_id, substs) | ty::Opaque(def_id, substs) @@ -258,7 +258,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { ) -> Result { // Similar to `pretty_path_qualified`, but for the other // types that are printed as paths (see `print_type` above). - match self_ty.kind { + match self_ty.kind() { ty::FnDef(..) | ty::Opaque(..) | ty::Projection(_) @@ -316,7 +316,8 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { self.path.finalize_pending_component(); } - self.write_str(&disambiguated_data.data.as_symbol().as_str())?; + write!(self, "{}", disambiguated_data.data)?; + Ok(self) } fn path_generic_args( diff --git a/src/librustc_symbol_mangling/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs similarity index 99% rename from src/librustc_symbol_mangling/lib.rs rename to compiler/rustc_symbol_mangling/src/lib.rs index 296b40c4e3..75150a56c4 100644 --- a/src/librustc_symbol_mangling/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -87,7 +87,7 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(never_type)] #![feature(nll)] #![feature(or_patterns)] diff --git a/src/librustc_symbol_mangling/test.rs b/compiler/rustc_symbol_mangling/src/test.rs similarity index 100% rename from src/librustc_symbol_mangling/test.rs rename to compiler/rustc_symbol_mangling/src/test.rs diff --git a/src/librustc_symbol_mangling/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs similarity index 98% rename from src/librustc_symbol_mangling/v0.rs rename to compiler/rustc_symbol_mangling/src/v0.rs index f01c3da8b5..da9c93143b 100644 --- a/src/librustc_symbol_mangling/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -152,11 +152,8 @@ impl SymbolMangler<'tcx> { let _ = write!(self.out, "{}", ident.len()); // Write a separating `_` if necessary (leading digit or `_`). - match ident.chars().next() { - Some('_' | '0'..='9') => { - self.push("_"); - } - _ => {} + if let Some('_' | '0'..='9') = ident.chars().next() { + self.push("_"); } self.push(ident); @@ -323,7 +320,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn print_type(mut self, ty: Ty<'tcx>) -> Result { // Basic types, never cached (single-character). - let basic_type = match ty.kind { + let basic_type = match ty.kind() { ty::Bool => "b", ty::Char => "c", ty::Str => "e", @@ -359,7 +356,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } let start = self.out.len(); - match ty.kind { + match *ty.kind() { // Basic types, handled above. ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never => { unreachable!() @@ -505,8 +502,9 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } let start = self.out.len(); - match ct.ty.kind { + match ct.ty.kind() { ty::Uint(_) => {} + ty::Bool => {} _ => { bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct); } diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml new file mode 100644 index 0000000000..2d7d9f1d82 --- /dev/null +++ b/compiler/rustc_target/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_target" +version = "0.0.0" +edition = "2018" + +[dependencies] +bitflags = "1.2.1" +tracing = "0.1" +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +rustc_index = { path = "../rustc_index" } diff --git a/src/librustc_target/README.md b/compiler/rustc_target/README.md similarity index 100% rename from src/librustc_target/README.md rename to compiler/rustc_target/README.md diff --git a/src/librustc_target/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs similarity index 100% rename from src/librustc_target/abi/call/aarch64.rs rename to compiler/rustc_target/src/abi/call/aarch64.rs diff --git a/src/librustc_target/abi/call/amdgpu.rs b/compiler/rustc_target/src/abi/call/amdgpu.rs similarity index 100% rename from src/librustc_target/abi/call/amdgpu.rs rename to compiler/rustc_target/src/abi/call/amdgpu.rs diff --git a/src/librustc_target/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs similarity index 100% rename from src/librustc_target/abi/call/arm.rs rename to compiler/rustc_target/src/abi/call/arm.rs diff --git a/src/librustc_target/abi/call/avr.rs b/compiler/rustc_target/src/abi/call/avr.rs similarity index 100% rename from src/librustc_target/abi/call/avr.rs rename to compiler/rustc_target/src/abi/call/avr.rs diff --git a/src/librustc_target/abi/call/hexagon.rs b/compiler/rustc_target/src/abi/call/hexagon.rs similarity index 100% rename from src/librustc_target/abi/call/hexagon.rs rename to compiler/rustc_target/src/abi/call/hexagon.rs diff --git a/src/librustc_target/abi/call/mips.rs b/compiler/rustc_target/src/abi/call/mips.rs similarity index 100% rename from src/librustc_target/abi/call/mips.rs rename to compiler/rustc_target/src/abi/call/mips.rs diff --git a/src/librustc_target/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs similarity index 100% rename from src/librustc_target/abi/call/mips64.rs rename to compiler/rustc_target/src/abi/call/mips64.rs diff --git a/src/librustc_target/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs similarity index 97% rename from src/librustc_target/abi/call/mod.rs rename to compiler/rustc_target/src/abi/call/mod.rs index 8f7e2bba5a..602c424a04 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -610,3 +610,15 @@ impl<'a, Ty> FnAbi<'a, Ty> { Ok(()) } } + +/// Returns the maximum size of return values to be passed by value in the Rust ABI. +/// +/// Return values beyond this size will use an implicit out-pointer instead. +pub fn max_ret_by_val(spec: &C) -> Size { + match spec.target_spec().arch.as_str() { + // System-V will pass return values up to 128 bits in RAX/RDX. + "x86_64" => Size::from_bits(128), + + _ => spec.data_layout().pointer_size, + } +} diff --git a/src/librustc_target/abi/call/msp430.rs b/compiler/rustc_target/src/abi/call/msp430.rs similarity index 100% rename from src/librustc_target/abi/call/msp430.rs rename to compiler/rustc_target/src/abi/call/msp430.rs diff --git a/src/librustc_target/abi/call/nvptx.rs b/compiler/rustc_target/src/abi/call/nvptx.rs similarity index 100% rename from src/librustc_target/abi/call/nvptx.rs rename to compiler/rustc_target/src/abi/call/nvptx.rs diff --git a/src/librustc_target/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs similarity index 100% rename from src/librustc_target/abi/call/nvptx64.rs rename to compiler/rustc_target/src/abi/call/nvptx64.rs diff --git a/src/librustc_target/abi/call/powerpc.rs b/compiler/rustc_target/src/abi/call/powerpc.rs similarity index 100% rename from src/librustc_target/abi/call/powerpc.rs rename to compiler/rustc_target/src/abi/call/powerpc.rs diff --git a/src/librustc_target/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs similarity index 100% rename from src/librustc_target/abi/call/powerpc64.rs rename to compiler/rustc_target/src/abi/call/powerpc64.rs diff --git a/src/librustc_target/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs similarity index 100% rename from src/librustc_target/abi/call/riscv.rs rename to compiler/rustc_target/src/abi/call/riscv.rs diff --git a/src/librustc_target/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs similarity index 100% rename from src/librustc_target/abi/call/s390x.rs rename to compiler/rustc_target/src/abi/call/s390x.rs diff --git a/src/librustc_target/abi/call/sparc.rs b/compiler/rustc_target/src/abi/call/sparc.rs similarity index 100% rename from src/librustc_target/abi/call/sparc.rs rename to compiler/rustc_target/src/abi/call/sparc.rs diff --git a/src/librustc_target/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs similarity index 100% rename from src/librustc_target/abi/call/sparc64.rs rename to compiler/rustc_target/src/abi/call/sparc64.rs diff --git a/src/librustc_target/abi/call/wasm32.rs b/compiler/rustc_target/src/abi/call/wasm32.rs similarity index 100% rename from src/librustc_target/abi/call/wasm32.rs rename to compiler/rustc_target/src/abi/call/wasm32.rs diff --git a/src/librustc_target/abi/call/wasm32_bindgen_compat.rs b/compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs similarity index 100% rename from src/librustc_target/abi/call/wasm32_bindgen_compat.rs rename to compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs diff --git a/src/librustc_target/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs similarity index 100% rename from src/librustc_target/abi/call/x86.rs rename to compiler/rustc_target/src/abi/call/x86.rs diff --git a/src/librustc_target/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs similarity index 100% rename from src/librustc_target/abi/call/x86_64.rs rename to compiler/rustc_target/src/abi/call/x86_64.rs diff --git a/src/librustc_target/abi/call/x86_win64.rs b/compiler/rustc_target/src/abi/call/x86_win64.rs similarity index 100% rename from src/librustc_target/abi/call/x86_win64.rs rename to compiler/rustc_target/src/abi/call/x86_win64.rs diff --git a/src/librustc_target/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs similarity index 97% rename from src/librustc_target/abi/mod.rs rename to compiler/rustc_target/src/abi/mod.rs index 4b565dd246..3c1a2ea39d 100644 --- a/src/librustc_target/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1135,16 +1135,31 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Abi::Scalar(s) => scalar_allows_raw_init(s), Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s), - Abi::Aggregate { .. } => true, // Cannot be excluded *right now*. + Abi::Aggregate { .. } => true, // Fields are checked below. }; if !valid { // This is definitely not okay. - trace!("might_permit_raw_init({:?}, zero={}): not valid", self.layout, zero); return Ok(false); } - // If we have not found an error yet, we need to recursively descend. - // FIXME(#66151): For now, we are conservative and do not do this. + // If we have not found an error yet, we need to recursively descend into fields. + match &self.fields { + FieldsShape::Primitive | FieldsShape::Union { .. } => {} + FieldsShape::Array { .. } => { + // FIXME(#66151): For now, we are conservative and do not check arrays. + } + FieldsShape::Arbitrary { offsets, .. } => { + for idx in 0..offsets.len() { + let field = self.field(cx, idx).to_result()?; + if !field.might_permit_raw_init(cx, zero)? { + // We found a field that is unhappy with this kind of initialization. + return Ok(false); + } + } + } + } + + // FIXME(#66151): For now, we are conservative and do not check `self.variants`. Ok(true) } } diff --git a/src/librustc_target/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs similarity index 100% rename from src/librustc_target/asm/aarch64.rs rename to compiler/rustc_target/src/asm/aarch64.rs diff --git a/src/librustc_target/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs similarity index 100% rename from src/librustc_target/asm/arm.rs rename to compiler/rustc_target/src/asm/arm.rs diff --git a/src/librustc_target/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs similarity index 100% rename from src/librustc_target/asm/hexagon.rs rename to compiler/rustc_target/src/asm/hexagon.rs diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs new file mode 100644 index 0000000000..638c52d97f --- /dev/null +++ b/compiler/rustc_target/src/asm/mips.rs @@ -0,0 +1,132 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use std::fmt; + +def_reg_class! { + Mips MipsInlineAsmRegClass { + reg, + freg, + } +} + +impl MipsInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::reg => types! { _: I8, I16, I32, F32; }, + Self::freg => types! { _: F32; }, + } + } +} + +// The reserved registers are somewhat taken from . +def_regs! { + Mips MipsInlineAsmReg MipsInlineAsmRegClass { + v0: reg = ["$2", "$v0"], + v1: reg = ["$3", "$v1"], + a0: reg = ["$4", "$a0"], + a1: reg = ["$5", "$a1"], + a2: reg = ["$6", "$a2"], + a3: reg = ["$7", "$a3"], + // FIXME: Reserve $t0, $t1 if in mips16 mode. + t0: reg = ["$8", "$t0"], + t1: reg = ["$9", "$t1"], + t2: reg = ["$10", "$t2"], + t3: reg = ["$11", "$t3"], + t4: reg = ["$12", "$t4"], + t5: reg = ["$13", "$t5"], + t6: reg = ["$14", "$t6"], + t7: reg = ["$15", "$t7"], + s0: reg = ["$16", "$s0"], + s1: reg = ["$17", "$s1"], + s2: reg = ["$18", "$s2"], + s3: reg = ["$19", "$s3"], + s4: reg = ["$20", "$s4"], + s5: reg = ["$21", "$s5"], + s6: reg = ["$22", "$s6"], + s7: reg = ["$23", "$s7"], + t8: reg = ["$24", "$t8"], + t9: reg = ["$25", "$t9"], + f0: freg = ["$f0"], + f1: freg = ["$f1"], + f2: freg = ["$f2"], + f3: freg = ["$f3"], + f4: freg = ["$f4"], + f5: freg = ["$f5"], + f6: freg = ["$f6"], + f7: freg = ["$f7"], + f8: freg = ["$f8"], + f9: freg = ["$f9"], + f10: freg = ["$f10"], + f11: freg = ["$f11"], + f12: freg = ["$f12"], + f13: freg = ["$f13"], + f14: freg = ["$f14"], + f15: freg = ["$f15"], + f16: freg = ["$f16"], + f17: freg = ["$f17"], + f18: freg = ["$f18"], + f19: freg = ["$f19"], + f20: freg = ["$f20"], + f21: freg = ["$f21"], + f22: freg = ["$f22"], + f23: freg = ["$f23"], + f24: freg = ["$f24"], + f25: freg = ["$f25"], + f26: freg = ["$f26"], + f27: freg = ["$f27"], + f28: freg = ["$f28"], + f29: freg = ["$f29"], + f30: freg = ["$f30"], + f31: freg = ["$f31"], + #error = ["$0", "$zero"] => + "constant zero cannot be used as an operand for inline asm", + #error = ["$1", "$at"] => + "reserved for assembler (Assembler Temp)", + #error = ["$26", "$k0"] => + "OS-reserved register cannot be used as an operand for inline asm", + #error = ["$27", "$k1"] => + "OS-reserved register cannot be used as an operand for inline asm", + #error = ["$28", "$gp"] => + "the global pointer cannot be used as an operand for inline asm", + #error = ["$29", "$sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["$30", "$s8", "$fp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["$31", "$ra"] => + "the return address register cannot be used as an operand for inline asm", + } +} + +impl MipsInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option, + ) -> fmt::Result { + out.write_str(self.name()) + } +} diff --git a/src/librustc_target/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs similarity index 94% rename from src/librustc_target/asm/mod.rs rename to compiler/rustc_target/src/asm/mod.rs index c22644bf81..e2f8e91fa9 100644 --- a/src/librustc_target/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -152,6 +152,7 @@ macro_rules! types { mod aarch64; mod arm; mod hexagon; +mod mips; mod nvptx; mod riscv; mod x86; @@ -159,6 +160,7 @@ mod x86; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; +pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; @@ -173,6 +175,7 @@ pub enum InlineAsmArch { RiscV64, Nvptx64, Hexagon, + Mips, } impl FromStr for InlineAsmArch { @@ -188,6 +191,7 @@ impl FromStr for InlineAsmArch { "riscv64" => Ok(Self::RiscV64), "nvptx64" => Ok(Self::Nvptx64), "hexagon" => Ok(Self::Hexagon), + "mips" => Ok(Self::Mips), _ => Err(()), } } @@ -201,6 +205,7 @@ pub enum InlineAsmReg { RiscV(RiscVInlineAsmReg), Nvptx(NvptxInlineAsmReg), Hexagon(HexagonInlineAsmReg), + Mips(MipsInlineAsmReg), } impl InlineAsmReg { @@ -211,6 +216,7 @@ impl InlineAsmReg { Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::Mips(r) => r.name(), } } @@ -221,6 +227,7 @@ impl InlineAsmReg { Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), + Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), } } @@ -252,6 +259,9 @@ impl InlineAsmReg { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?) } + InlineAsmArch::Mips => { + Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?) + } }) } @@ -269,6 +279,7 @@ impl InlineAsmReg { Self::AArch64(r) => r.emit(out, arch, modifier), Self::RiscV(r) => r.emit(out, arch, modifier), Self::Hexagon(r) => r.emit(out, arch, modifier), + Self::Mips(r) => r.emit(out, arch, modifier), } } @@ -279,6 +290,7 @@ impl InlineAsmReg { Self::AArch64(_) => cb(self), Self::RiscV(_) => cb(self), Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), + Self::Mips(_) => cb(self), } } } @@ -291,6 +303,7 @@ pub enum InlineAsmRegClass { RiscV(RiscVInlineAsmRegClass), Nvptx(NvptxInlineAsmRegClass), Hexagon(HexagonInlineAsmRegClass), + Mips(MipsInlineAsmRegClass), } impl InlineAsmRegClass { @@ -302,6 +315,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.name(), Self::Nvptx(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::Mips(r) => r.name(), } } @@ -316,6 +330,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), + Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), } } @@ -337,6 +352,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.suggest_modifier(arch, ty), Self::Nvptx(r) => r.suggest_modifier(arch, ty), Self::Hexagon(r) => r.suggest_modifier(arch, ty), + Self::Mips(r) => r.suggest_modifier(arch, ty), } } @@ -354,6 +370,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.default_modifier(arch), Self::Nvptx(r) => r.default_modifier(arch), Self::Hexagon(r) => r.default_modifier(arch), + Self::Mips(r) => r.default_modifier(arch), } } @@ -370,6 +387,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.supported_types(arch), Self::Nvptx(r) => r.supported_types(arch), Self::Hexagon(r) => r.supported_types(arch), + Self::Mips(r) => r.supported_types(arch), } } @@ -391,6 +409,7 @@ impl InlineAsmRegClass { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?) } + InlineAsmArch::Mips => Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?), }) }) } @@ -405,6 +424,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.valid_modifiers(arch), Self::Nvptx(r) => r.valid_modifiers(arch), Self::Hexagon(r) => r.valid_modifiers(arch), + Self::Mips(r) => r.valid_modifiers(arch), } } } @@ -545,5 +565,10 @@ pub fn allocatable_registers( hexagon::fill_reg_map(arch, has_feature, target, &mut map); map } + InlineAsmArch::Mips => { + let mut map = mips::regclass_map(); + mips::fill_reg_map(arch, has_feature, target, &mut map); + map + } } } diff --git a/src/librustc_target/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs similarity index 100% rename from src/librustc_target/asm/nvptx.rs rename to compiler/rustc_target/src/asm/nvptx.rs diff --git a/src/librustc_target/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs similarity index 100% rename from src/librustc_target/asm/riscv.rs rename to compiler/rustc_target/src/asm/riscv.rs diff --git a/src/librustc_target/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs similarity index 100% rename from src/librustc_target/asm/x86.rs rename to compiler/rustc_target/src/asm/x86.rs diff --git a/src/librustc_target/lib.rs b/compiler/rustc_target/src/lib.rs similarity index 92% rename from src/librustc_target/lib.rs rename to compiler/rustc_target/src/lib.rs index 5788e1e838..fb747dfcbd 100644 --- a/src/librustc_target/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -7,7 +7,7 @@ //! more 'stuff' here in the future. It does not have a dependency on //! LLVM. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_fn)] #![feature(const_panic)] diff --git a/src/librustc_target/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs similarity index 100% rename from src/librustc_target/spec/aarch64_apple_darwin.rs rename to compiler/rustc_target/src/spec/aarch64_apple_darwin.rs diff --git a/src/librustc_target/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs similarity index 93% rename from src/librustc_target/spec/aarch64_apple_ios.rs rename to compiler/rustc_target/src/spec/aarch64_apple_ios.rs index 21dcec8d5e..168cd01878 100644 --- a/src/librustc_target/spec/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::Arm64, AppleOS::iOS)?; + let base = opts(Arch::Arm64); Ok(Target { llvm_target: "arm64-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs similarity index 90% rename from src/librustc_target/spec/aarch64_apple_tvos.rs rename to compiler/rustc_target/src/spec/aarch64_apple_tvos.rs index 2b0cd6cabf..5e2cab0df1 100644 --- a/src/librustc_target/spec/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::Arm64, AppleOS::tvOS)?; + let base = opts(Arch::Arm64); Ok(Target { llvm_target: "arm64-apple-tvos".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs similarity index 100% rename from src/librustc_target/spec/aarch64_fuchsia.rs rename to compiler/rustc_target/src/spec/aarch64_fuchsia.rs diff --git a/src/librustc_target/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs similarity index 100% rename from src/librustc_target/spec/aarch64_linux_android.rs rename to compiler/rustc_target/src/spec/aarch64_linux_android.rs diff --git a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/aarch64_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/aarch64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_cloudabi.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs diff --git a/src/librustc_target/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs diff --git a/src/librustc_target/spec/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs similarity index 73% rename from src/librustc_target/spec/aarch64_unknown_hermit.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs index 5f978c0324..e07b8f7a75 100644 --- a/src/librustc_target/spec/aarch64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs @@ -1,10 +1,8 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::hermit_base::opts(); base.max_atomic_width = Some(128); - base.unsupported_abis = super::arm_base::unsupported_abis(); - base.linker = Some("aarch64-hermit-gcc".to_string()); Ok(Target { llvm_target: "aarch64-unknown-hermit".to_string(), @@ -16,7 +14,7 @@ pub fn target() -> TargetResult { target_os: "hermit".to_string(), target_env: String::new(), target_vendor: "unknown".to_string(), - linker_flavor: LinkerFlavor::Gcc, + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), options: base, }) } diff --git a/src/librustc_target/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs diff --git a/src/librustc_target/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_none.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_none.rs diff --git a/src/librustc_target/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_none_softfloat.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs diff --git a/src/librustc_target/spec/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_openbsd.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs diff --git a/src/librustc_target/spec/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_redox.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_redox.rs diff --git a/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/aarch64_uwp_windows_msvc.rs rename to compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs diff --git a/src/librustc_target/spec/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/aarch64_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs diff --git a/src/librustc_target/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs similarity index 100% rename from src/librustc_target/spec/abi.rs rename to compiler/rustc_target/src/spec/abi.rs diff --git a/src/librustc_target/spec/abi/tests.rs b/compiler/rustc_target/src/spec/abi/tests.rs similarity index 100% rename from src/librustc_target/spec/abi/tests.rs rename to compiler/rustc_target/src/spec/abi/tests.rs diff --git a/src/librustc_target/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs similarity index 100% rename from src/librustc_target/spec/android_base.rs rename to compiler/rustc_target/src/spec/android_base.rs diff --git a/src/librustc_target/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs similarity index 100% rename from src/librustc_target/spec/apple_base.rs rename to compiler/rustc_target/src/spec/apple_base.rs diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs new file mode 100644 index 0000000000..e34277d5af --- /dev/null +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -0,0 +1,43 @@ +use crate::spec::TargetOptions; + +use Arch::*; +#[allow(non_camel_case_types)] +#[derive(Copy, Clone)] +pub enum Arch { + Armv7, + Armv7s, + Arm64, + I386, + X86_64, + X86_64_macabi, +} + +fn target_cpu(arch: Arch) -> String { + match arch { + Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher + Armv7s => "cortex-a9", + Arm64 => "apple-a7", + I386 => "yonah", + X86_64 => "core2", + X86_64_macabi => "core2", + } + .to_string() +} + +fn link_env_remove(arch: Arch) -> Vec { + match arch { + Armv7 | Armv7s | Arm64 | I386 | X86_64 => vec!["MACOSX_DEPLOYMENT_TARGET".to_string()], + X86_64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()], + } +} + +pub fn opts(arch: Arch) -> TargetOptions { + TargetOptions { + cpu: target_cpu(arch), + executables: true, + link_env_remove: link_env_remove(arch), + has_elf_tls: false, + eliminate_frame_pointer: false, + ..super::apple_base::opts() + } +} diff --git a/src/librustc_target/spec/arm_base.rs b/compiler/rustc_target/src/spec/arm_base.rs similarity index 100% rename from src/librustc_target/spec/arm_base.rs rename to compiler/rustc_target/src/spec/arm_base.rs diff --git a/src/librustc_target/spec/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs similarity index 100% rename from src/librustc_target/spec/arm_linux_androideabi.rs rename to compiler/rustc_target/src/spec/arm_linux_androideabi.rs diff --git a/src/librustc_target/spec/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs similarity index 100% rename from src/librustc_target/spec/arm_unknown_linux_gnueabi.rs rename to compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs diff --git a/src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs similarity index 100% rename from src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs rename to compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs diff --git a/src/librustc_target/spec/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs similarity index 100% rename from src/librustc_target/spec/arm_unknown_linux_musleabi.rs rename to compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs diff --git a/src/librustc_target/spec/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs similarity index 100% rename from src/librustc_target/spec/arm_unknown_linux_musleabihf.rs rename to compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs diff --git a/src/librustc_target/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/armebv7r_none_eabi.rs rename to compiler/rustc_target/src/spec/armebv7r_none_eabi.rs diff --git a/src/librustc_target/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armebv7r_none_eabihf.rs rename to compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs diff --git a/src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs similarity index 100% rename from src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs rename to compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs diff --git a/src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs similarity index 100% rename from src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs rename to compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs diff --git a/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs similarity index 100% rename from src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs rename to compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs diff --git a/src/librustc_target/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/armv6_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs diff --git a/src/librustc_target/spec/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv6_unknown_netbsd_eabihf.rs rename to compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs diff --git a/src/librustc_target/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs similarity index 89% rename from src/librustc_target/spec/armv7_apple_ios.rs rename to compiler/rustc_target/src/spec/armv7_apple_ios.rs index 393843526a..6dafcc2c34 100644 --- a/src/librustc_target/spec/armv7_apple_ios.rs +++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::Armv7, AppleOS::iOS)?; + let base = opts(Arch::Armv7); Ok(Target { llvm_target: "armv7-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs similarity index 100% rename from src/librustc_target/spec/armv7_linux_androideabi.rs rename to compiler/rustc_target/src/spec/armv7_linux_androideabi.rs diff --git a/src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs rename to compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs diff --git a/src/librustc_target/spec/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs diff --git a/src/librustc_target/spec/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_linux_gnueabi.rs rename to compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs diff --git a/src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs rename to compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs diff --git a/src/librustc_target/spec/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_linux_musleabi.rs rename to compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs diff --git a/src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs rename to compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs diff --git a/src/librustc_target/spec/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_netbsd_eabihf.rs rename to compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs diff --git a/src/librustc_target/spec/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_wrs_vxworks_eabihf.rs rename to compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs diff --git a/src/librustc_target/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/armv7a_none_eabi.rs rename to compiler/rustc_target/src/spec/armv7a_none_eabi.rs diff --git a/src/librustc_target/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7a_none_eabihf.rs rename to compiler/rustc_target/src/spec/armv7a_none_eabihf.rs diff --git a/src/librustc_target/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/armv7r_none_eabi.rs rename to compiler/rustc_target/src/spec/armv7r_none_eabi.rs diff --git a/src/librustc_target/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7r_none_eabihf.rs rename to compiler/rustc_target/src/spec/armv7r_none_eabihf.rs diff --git a/src/librustc_target/spec/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs similarity index 89% rename from src/librustc_target/spec/armv7s_apple_ios.rs rename to compiler/rustc_target/src/spec/armv7s_apple_ios.rs index 998a7b2e16..d6c99c4ade 100644 --- a/src/librustc_target/spec/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::Armv7s, AppleOS::iOS)?; + let base = opts(Arch::Armv7s); Ok(Target { llvm_target: "armv7s-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs similarity index 100% rename from src/librustc_target/spec/asmjs_unknown_emscripten.rs rename to compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs new file mode 100644 index 0000000000..527a322d56 --- /dev/null +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -0,0 +1,53 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +/// A base target for AVR devices using the GNU toolchain. +/// +/// Requires GNU avr-gcc and avr-binutils on the host system. +pub fn target(target_cpu: String) -> TargetResult { + Ok(Target { + arch: "avr".to_string(), + data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(), + llvm_target: "avr-unknown-unknown".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "16".to_string(), + linker_flavor: LinkerFlavor::Gcc, + target_os: "unknown".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + target_c_int_width: 16.to_string(), + options: TargetOptions { + cpu: target_cpu.clone(), + exe_suffix: ".elf".to_string(), + + linker: Some("avr-gcc".to_owned()), + dynamic_linking: false, + executables: true, + linker_is_gnu: true, + has_rpath: false, + position_independent_executables: false, + eh_frame_header: false, + pre_link_args: vec![( + LinkerFlavor::Gcc, + vec![ + format!("-mmcu={}", target_cpu), + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), + ], + )] + .into_iter() + .collect(), + late_link_args: vec![(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])] + .into_iter() + .collect(), + max_atomic_width: Some(0), + atomic_cas: false, + ..TargetOptions::default() + }, + }) +} diff --git a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs new file mode 100644 index 0000000000..5d22598b57 --- /dev/null +++ b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs @@ -0,0 +1,5 @@ +use crate::spec::TargetResult; + +pub fn target() -> TargetResult { + super::avr_gnu_base::target("atmega328".to_owned()) +} diff --git a/src/librustc_target/spec/cloudabi_base.rs b/compiler/rustc_target/src/spec/cloudabi_base.rs similarity index 100% rename from src/librustc_target/spec/cloudabi_base.rs rename to compiler/rustc_target/src/spec/cloudabi_base.rs diff --git a/src/librustc_target/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs similarity index 100% rename from src/librustc_target/spec/crt_objects.rs rename to compiler/rustc_target/src/spec/crt_objects.rs diff --git a/src/librustc_target/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs similarity index 100% rename from src/librustc_target/spec/dragonfly_base.rs rename to compiler/rustc_target/src/spec/dragonfly_base.rs diff --git a/src/librustc_target/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs similarity index 100% rename from src/librustc_target/spec/freebsd_base.rs rename to compiler/rustc_target/src/spec/freebsd_base.rs diff --git a/src/librustc_target/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs similarity index 100% rename from src/librustc_target/spec/fuchsia_base.rs rename to compiler/rustc_target/src/spec/fuchsia_base.rs diff --git a/src/librustc_target/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs similarity index 100% rename from src/librustc_target/spec/haiku_base.rs rename to compiler/rustc_target/src/spec/haiku_base.rs diff --git a/src/librustc_target/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs similarity index 88% rename from src/librustc_target/spec/hermit_base.rs rename to compiler/rustc_target/src/spec/hermit_base.rs index 18fb2aa3d5..e063c94cf2 100644 --- a/src/librustc_target/spec/hermit_base.rs +++ b/compiler/rustc_target/src/spec/hermit_base.rs @@ -16,7 +16,8 @@ pub fn opts() -> TargetOptions { pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, - relocation_model: RelocModel::Static, + static_position_independent_executables: true, + relocation_model: RelocModel::Pic, target_family: None, tls_model: TlsModel::InitialExec, ..Default::default() diff --git a/src/librustc_target/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs similarity index 88% rename from src/librustc_target/spec/hermit_kernel_base.rs rename to compiler/rustc_target/src/spec/hermit_kernel_base.rs index 7f2dada714..01b9f75637 100644 --- a/src/librustc_target/spec/hermit_kernel_base.rs +++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs @@ -17,7 +17,8 @@ pub fn opts() -> TargetOptions { pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, - relocation_model: RelocModel::Static, + static_position_independent_executables: true, + relocation_model: RelocModel::Pic, target_family: None, tls_model: TlsModel::InitialExec, ..Default::default() diff --git a/src/librustc_target/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/hexagon_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs similarity index 88% rename from src/librustc_target/spec/i386_apple_ios.rs rename to compiler/rustc_target/src/spec/i386_apple_ios.rs index a121d49769..6cb209ab1c 100644 --- a/src/librustc_target/spec/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::I386, AppleOS::iOS)?; + let base = opts(Arch::I386); Ok(Target { llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/i586_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/i586_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/i586_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/i586_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/i586_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs similarity index 100% rename from src/librustc_target/spec/i686_apple_darwin.rs rename to compiler/rustc_target/src/spec/i686_apple_darwin.rs diff --git a/src/librustc_target/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs similarity index 100% rename from src/librustc_target/spec/i686_linux_android.rs rename to compiler/rustc_target/src/spec/i686_linux_android.rs diff --git a/src/librustc_target/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs similarity index 100% rename from src/librustc_target/spec/i686_pc_windows_gnu.rs rename to compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs diff --git a/src/librustc_target/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/i686_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/i686_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_cloudabi.rs rename to compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs diff --git a/src/librustc_target/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/i686_unknown_freebsd.rs diff --git a/src/librustc_target/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_haiku.rs rename to compiler/rustc_target/src/spec/i686_unknown_haiku.rs diff --git a/src/librustc_target/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/i686_unknown_netbsd.rs diff --git a/src/librustc_target/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_openbsd.rs rename to compiler/rustc_target/src/spec/i686_unknown_openbsd.rs diff --git a/src/librustc_target/spec/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_uefi.rs rename to compiler/rustc_target/src/spec/i686_unknown_uefi.rs diff --git a/src/librustc_target/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs similarity index 100% rename from src/librustc_target/spec/i686_uwp_windows_gnu.rs rename to compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs diff --git a/src/librustc_target/spec/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/i686_uwp_windows_msvc.rs rename to compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs diff --git a/src/librustc_target/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/i686_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/i686_wrs_vxworks.rs diff --git a/src/librustc_target/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs similarity index 100% rename from src/librustc_target/spec/illumos_base.rs rename to compiler/rustc_target/src/spec/illumos_base.rs diff --git a/src/librustc_target/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs similarity index 100% rename from src/librustc_target/spec/l4re_base.rs rename to compiler/rustc_target/src/spec/l4re_base.rs diff --git a/src/librustc_target/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs similarity index 100% rename from src/librustc_target/spec/linux_base.rs rename to compiler/rustc_target/src/spec/linux_base.rs diff --git a/src/librustc_target/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs similarity index 100% rename from src/librustc_target/spec/linux_kernel_base.rs rename to compiler/rustc_target/src/spec/linux_kernel_base.rs diff --git a/src/librustc_target/spec/linux_musl_base.rs b/compiler/rustc_target/src/spec/linux_musl_base.rs similarity index 100% rename from src/librustc_target/spec/linux_musl_base.rs rename to compiler/rustc_target/src/spec/linux_musl_base.rs diff --git a/src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs similarity index 100% rename from src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs rename to compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs diff --git a/src/librustc_target/spec/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs similarity index 100% rename from src/librustc_target/spec/mips64_unknown_linux_muslabi64.rs rename to compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs diff --git a/src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs similarity index 100% rename from src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs rename to compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs diff --git a/src/librustc_target/spec/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs similarity index 100% rename from src/librustc_target/spec/mips64el_unknown_linux_muslabi64.rs rename to compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs diff --git a/src/librustc_target/spec/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/mips_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/mips_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs similarity index 100% rename from src/librustc_target/spec/mips_unknown_linux_uclibc.rs rename to compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs diff --git a/src/librustc_target/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs similarity index 100% rename from src/librustc_target/spec/mipsel_sony_psp.rs rename to compiler/rustc_target/src/spec/mipsel_sony_psp.rs diff --git a/src/librustc_target/spec/mipsel_sony_psp_linker_script.ld b/compiler/rustc_target/src/spec/mipsel_sony_psp_linker_script.ld similarity index 100% rename from src/librustc_target/spec/mipsel_sony_psp_linker_script.ld rename to compiler/rustc_target/src/spec/mipsel_sony_psp_linker_script.ld diff --git a/src/librustc_target/spec/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/mipsel_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/mipsel_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs similarity index 100% rename from src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs rename to compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs diff --git a/src/librustc_target/spec/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/mipsisa32r6_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/mipsisa32r6el_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs similarity index 100% rename from src/librustc_target/spec/mipsisa64r6_unknown_linux_gnuabi64.rs rename to compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs diff --git a/src/librustc_target/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs similarity index 100% rename from src/librustc_target/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs rename to compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs diff --git a/src/librustc_target/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs similarity index 99% rename from src/librustc_target/spec/mod.rs rename to compiler/rustc_target/src/spec/mod.rs index fa29ff3f8d..f1e8330425 100644 --- a/src/librustc_target/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -51,10 +51,10 @@ mod android_base; mod apple_base; mod apple_sdk_base; mod arm_base; +mod avr_gnu_base; mod cloudabi_base; mod dragonfly_base; mod freebsd_base; -mod freestanding_base; mod fuchsia_base; mod haiku_base; mod hermit_base; @@ -581,7 +581,7 @@ supported_targets! { ("aarch64-fuchsia", aarch64_fuchsia), ("x86_64-fuchsia", x86_64_fuchsia), - ("avr-unknown-unknown", avr_unknown_unknown), + ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328), ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), @@ -654,6 +654,7 @@ supported_targets! { ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), + ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu), ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf), ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf), ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu), diff --git a/src/librustc_target/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs similarity index 100% rename from src/librustc_target/spec/msp430_none_elf.rs rename to compiler/rustc_target/src/spec/msp430_none_elf.rs diff --git a/src/librustc_target/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs similarity index 100% rename from src/librustc_target/spec/msvc_base.rs rename to compiler/rustc_target/src/spec/msvc_base.rs diff --git a/src/librustc_target/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs similarity index 100% rename from src/librustc_target/spec/netbsd_base.rs rename to compiler/rustc_target/src/spec/netbsd_base.rs diff --git a/src/librustc_target/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs similarity index 100% rename from src/librustc_target/spec/nvptx64_nvidia_cuda.rs rename to compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs diff --git a/src/librustc_target/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs similarity index 100% rename from src/librustc_target/spec/openbsd_base.rs rename to compiler/rustc_target/src/spec/openbsd_base.rs diff --git a/src/librustc_target/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/powerpc64_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs diff --git a/src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/powerpc64_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/powerpc64_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs diff --git a/src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/powerpc64le_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/powerpc_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs similarity index 100% rename from src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs rename to compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs diff --git a/src/librustc_target/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/powerpc_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/powerpc_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs diff --git a/src/librustc_target/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/powerpc_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs diff --git a/src/librustc_target/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs similarity index 100% rename from src/librustc_target/spec/powerpc_wrs_vxworks_spe.rs rename to compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs diff --git a/src/librustc_target/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs similarity index 100% rename from src/librustc_target/spec/redox_base.rs rename to compiler/rustc_target/src/spec/redox_base.rs diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs new file mode 100644 index 0000000000..28710c6017 --- /dev/null +++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs @@ -0,0 +1,25 @@ +use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "riscv32-unknown-linux-gnu".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + target_env: "gnu".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), + arch: "riscv32".to_string(), + target_os: "linux".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: TargetOptions { + unsupported_abis: super::riscv_base::unsupported_abis(), + code_model: Some(CodeModel::Medium), + cpu: "generic-rv32".to_string(), + features: "+m,+a,+f,+d,+c".to_string(), + llvm_abiname: "ilp32d".to_string(), + max_atomic_width: Some(32), + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_target/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv32i_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv32imac_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv32imc_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/riscv64gc_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv64gc_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv64imac_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv_base.rs b/compiler/rustc_target/src/spec/riscv_base.rs similarity index 100% rename from src/librustc_target/spec/riscv_base.rs rename to compiler/rustc_target/src/spec/riscv_base.rs diff --git a/src/librustc_target/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/s390x_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs similarity index 100% rename from src/librustc_target/spec/solaris_base.rs rename to compiler/rustc_target/src/spec/solaris_base.rs diff --git a/src/librustc_target/spec/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/sparc64_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/sparc64_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs diff --git a/src/librustc_target/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs similarity index 100% rename from src/librustc_target/spec/sparc64_unknown_openbsd.rs rename to compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs diff --git a/src/librustc_target/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/sparc_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs similarity index 100% rename from src/librustc_target/spec/sparcv9_sun_solaris.rs rename to compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs diff --git a/src/librustc_target/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs similarity index 100% rename from src/librustc_target/spec/tests/tests_impl.rs rename to compiler/rustc_target/src/spec/tests/tests_impl.rs diff --git a/src/librustc_target/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs similarity index 100% rename from src/librustc_target/spec/thumb_base.rs rename to compiler/rustc_target/src/spec/thumb_base.rs diff --git a/src/librustc_target/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv4t_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv6m_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs rename to compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs diff --git a/src/librustc_target/spec/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv7em_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/thumbv7em_none_eabihf.rs rename to compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs diff --git a/src/librustc_target/spec/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv7m_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv7neon_linux_androideabi.rs rename to compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs diff --git a/src/librustc_target/spec/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs similarity index 100% rename from src/librustc_target/spec/thumbv7neon_unknown_linux_gnueabihf.rs rename to compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs diff --git a/src/librustc_target/spec/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs similarity index 100% rename from src/librustc_target/spec/thumbv7neon_unknown_linux_musleabihf.rs rename to compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs diff --git a/src/librustc_target/spec/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv8m_base_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv8m_main_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/thumbv8m_main_none_eabihf.rs rename to compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs diff --git a/src/librustc_target/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs similarity index 100% rename from src/librustc_target/spec/uefi_msvc_base.rs rename to compiler/rustc_target/src/spec/uefi_msvc_base.rs diff --git a/src/librustc_target/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs similarity index 100% rename from src/librustc_target/spec/vxworks_base.rs rename to compiler/rustc_target/src/spec/vxworks_base.rs diff --git a/src/librustc_target/spec/wasm32_base.rs b/compiler/rustc_target/src/spec/wasm32_base.rs similarity index 99% rename from src/librustc_target/spec/wasm32_base.rs rename to compiler/rustc_target/src/spec/wasm32_base.rs index 62fc8f0618..a7957d84cb 100644 --- a/src/librustc_target/spec/wasm32_base.rs +++ b/compiler/rustc_target/src/spec/wasm32_base.rs @@ -83,6 +83,7 @@ pub fn options() -> TargetOptions { dll_prefix: String::new(), dll_suffix: ".wasm".to_string(), linker_is_gnu: false, + eh_frame_header: false, max_atomic_width: Some(64), diff --git a/src/librustc_target/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs similarity index 100% rename from src/librustc_target/spec/wasm32_unknown_emscripten.rs rename to compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs diff --git a/src/librustc_target/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs similarity index 100% rename from src/librustc_target/spec/wasm32_unknown_unknown.rs rename to compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs diff --git a/src/librustc_target/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs similarity index 98% rename from src/librustc_target/spec/wasm32_wasi.rs rename to compiler/rustc_target/src/spec/wasm32_wasi.rs index 0bba7bdd47..351167105e 100644 --- a/src/librustc_target/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -30,7 +30,7 @@ //! ## No interop with C required //! //! By default the `crt-static` target feature is enabled, and when enabled -//! this means that the the bundled version of `libc.a` found in `liblibc.rlib` +//! this means that the bundled version of `libc.a` found in `liblibc.rlib` //! is used. This isn't intended really for interoperation with a C because it //! may be the case that Rust's bundled C library is incompatible with a //! foreign-compiled C library. In this use case, though, we use `rust-lld` and diff --git a/src/librustc_target/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs similarity index 94% rename from src/librustc_target/spec/windows_gnu_base.rs rename to compiler/rustc_target/src/spec/windows_gnu_base.rs index a864918655..0234ff55f0 100644 --- a/src/librustc_target/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions { "-lmsvcrt".to_string(), "-lmingwex".to_string(), "-lmingw32".to_string(), + "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc // mingw's msvcrt is a weird hybrid import library and static library. // And it seems that the linker fails to use import symbols from msvcrt // that are required from functions in msvcrt in certain cases. For example @@ -41,8 +42,6 @@ pub fn opts() -> TargetOptions { // the shared libgcc_s-dw2-1.dll. This is required to support // unwinding across DLL boundaries. "-lgcc_s".to_string(), - "-lgcc".to_string(), - "-lkernel32".to_string(), ]; late_link_args_dynamic.insert(LinkerFlavor::Gcc, dynamic_unwind_libs.clone()); late_link_args_dynamic.insert(LinkerFlavor::Lld(LldFlavor::Ld), dynamic_unwind_libs); @@ -54,10 +53,6 @@ pub fn opts() -> TargetOptions { // boundaries when unwinding across FFI boundaries. "-lgcc_eh".to_string(), "-l:libpthread.a".to_string(), - "-lgcc".to_string(), - // libpthread depends on libmsvcrt, so we need to link it *again*. - "-lmsvcrt".to_string(), - "-lkernel32".to_string(), ]; late_link_args_static.insert(LinkerFlavor::Gcc, static_unwind_libs.clone()); late_link_args_static.insert(LinkerFlavor::Lld(LldFlavor::Ld), static_unwind_libs); diff --git a/src/librustc_target/spec/windows_msvc_base.rs b/compiler/rustc_target/src/spec/windows_msvc_base.rs similarity index 100% rename from src/librustc_target/spec/windows_msvc_base.rs rename to compiler/rustc_target/src/spec/windows_msvc_base.rs diff --git a/src/librustc_target/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs similarity index 98% rename from src/librustc_target/spec/windows_uwp_gnu_base.rs rename to compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs index fd55a0fc6a..fcb2af0005 100644 --- a/src/librustc_target/spec/windows_uwp_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs @@ -22,7 +22,7 @@ pub fn opts() -> TargetOptions { "-lmingw32".to_string(), ]; late_link_args.insert(LinkerFlavor::Gcc, mingw_libs.clone()); - late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs.clone()); + late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs); TargetOptions { executables: false, diff --git a/src/librustc_target/spec/windows_uwp_msvc_base.rs b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs similarity index 100% rename from src/librustc_target/spec/windows_uwp_msvc_base.rs rename to compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs diff --git a/src/librustc_target/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs similarity index 100% rename from src/librustc_target/spec/x86_64_apple_darwin.rs rename to compiler/rustc_target/src/spec/x86_64_apple_darwin.rs diff --git a/src/librustc_target/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs similarity index 87% rename from src/librustc_target/spec/x86_64_apple_ios.rs rename to compiler/rustc_target/src/spec/x86_64_apple_ios.rs index cfcf856836..fd3e4e2f57 100644 --- a/src/librustc_target/spec/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::X86_64, AppleOS::iOS)?; + let base = opts(Arch::X86_64); Ok(Target { llvm_target: "x86_64-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs similarity index 87% rename from src/librustc_target/spec/x86_64_apple_ios_macabi.rs rename to compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs index c42d091172..4cfbd9eba0 100644 --- a/src/librustc_target/spec/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::X86_64_macabi, AppleOS::iOS)?; + let base = opts(Arch::X86_64_macabi); Ok(Target { llvm_target: "x86_64-apple-ios13.0-macabi".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs similarity index 87% rename from src/librustc_target/spec/x86_64_apple_tvos.rs rename to compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index a56062c0b2..664a3ed881 100644 --- a/src/librustc_target/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::X86_64, AppleOS::iOS)?; + let base = opts(Arch::X86_64); Ok(Target { llvm_target: "x86_64-apple-tvos".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs similarity index 100% rename from src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs rename to compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs diff --git a/src/librustc_target/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs similarity index 100% rename from src/librustc_target/spec/x86_64_fuchsia.rs rename to compiler/rustc_target/src/spec/x86_64_fuchsia.rs diff --git a/src/librustc_target/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs similarity index 100% rename from src/librustc_target/spec/x86_64_linux_android.rs rename to compiler/rustc_target/src/spec/x86_64_linux_android.rs diff --git a/src/librustc_target/spec/x86_64_linux_kernel.rs b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs similarity index 100% rename from src/librustc_target/spec/x86_64_linux_kernel.rs rename to compiler/rustc_target/src/spec/x86_64_linux_kernel.rs diff --git a/src/librustc_target/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs similarity index 100% rename from src/librustc_target/spec/x86_64_pc_windows_gnu.rs rename to compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs diff --git a/src/librustc_target/spec/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/x86_64_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/x86_64_rumprun_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs similarity index 100% rename from src/librustc_target/spec/x86_64_rumprun_netbsd.rs rename to compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs diff --git a/src/librustc_target/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs similarity index 100% rename from src/librustc_target/spec/x86_64_sun_solaris.rs rename to compiler/rustc_target/src/spec/x86_64_sun_solaris.rs diff --git a/src/librustc_target/spec/x86_64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_cloudabi.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs diff --git a/src/librustc_target/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_dragonfly.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs diff --git a/src/librustc_target/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs diff --git a/src/librustc_target/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_haiku.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs diff --git a/src/librustc_target/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_hermit.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs diff --git a/src/librustc_target/spec/x86_64_unknown_hermit_kernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_hermit_kernel.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs diff --git a/src/librustc_target/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_illumos.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs diff --git a/src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs diff --git a/src/librustc_target/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs diff --git a/src/librustc_target/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs diff --git a/src/librustc_target/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_openbsd.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs diff --git a/src/librustc_target/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_redox.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_redox.rs diff --git a/src/librustc_target/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_uefi.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs diff --git a/src/librustc_target/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs similarity index 100% rename from src/librustc_target/spec/x86_64_uwp_windows_gnu.rs rename to compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs diff --git a/src/librustc_target/spec/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/x86_64_uwp_windows_msvc.rs rename to compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs diff --git a/src/librustc_target/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/x86_64_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml new file mode 100644 index 0000000000..a72c172918 --- /dev/null +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -0,0 +1,25 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_trait_selection" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_parse_format = { path = "../rustc_parse_format" } +tracing = "0.1" +rustc_attr = { path = "../rustc_attr" } +rustc_middle = { path = "../rustc_middle" } +rustc_ast = { path = "../rustc_ast" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_macros = { path = "../rustc_macros" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_trait_selection/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs similarity index 97% rename from src/librustc_trait_selection/autoderef.rs rename to compiler/rustc_trait_selection/src/autoderef.rs index 02eefe5622..b9c5123e49 100644 --- a/src/librustc_trait_selection/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -27,6 +27,7 @@ pub struct Autoderef<'a, 'tcx> { // Meta infos: infcx: &'a InferCtxt<'a, 'tcx>, span: Span, + overloaded_span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, @@ -98,10 +99,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { body_id: hir::HirId, span: Span, base_ty: Ty<'tcx>, + overloaded_span: Span, ) -> Autoderef<'a, 'tcx> { Autoderef { infcx, span, + overloaded_span, body_id, param_env, state: AutoderefSnapshot { @@ -190,6 +193,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { self.span } + pub fn overloaded_span(&self) -> Span { + self.overloaded_span + } + pub fn reached_recursion_limit(&self) -> bool { self.state.reached_recursion_limit } diff --git a/src/librustc_trait_selection/infer.rs b/compiler/rustc_trait_selection/src/infer.rs similarity index 100% rename from src/librustc_trait_selection/infer.rs rename to compiler/rustc_trait_selection/src/infer.rs diff --git a/src/librustc_trait_selection/lib.rs b/compiler/rustc_trait_selection/src/lib.rs similarity index 86% rename from src/librustc_trait_selection/lib.rs rename to compiler/rustc_trait_selection/src/lib.rs index b5882df472..ddeab340f3 100644 --- a/src/librustc_trait_selection/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -10,10 +10,12 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] +#![feature(box_patterns)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] +#![feature(never_type)] #![feature(crate_visibility_modifier)] #![feature(or_patterns)] #![recursion_limit = "512"] // For rustdoc diff --git a/src/librustc_trait_selection/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs similarity index 99% rename from src/librustc_trait_selection/opaque_types.rs rename to compiler/rustc_trait_selection/src/opaque_types.rs index 379c976df6..28697ec4e3 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -708,11 +708,11 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { // We're only interested in types involving regions - if !ty.flags.intersects(ty::TypeFlags::HAS_FREE_REGIONS) { + if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { return false; // keep visiting } - match ty.kind { + match ty.kind() { ty::Closure(_, ref substs) => { // Skip lifetime parameters of the enclosing item(s) @@ -866,7 +866,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match *ty.kind() { ty::Closure(def_id, substs) => { // I am a horrible monster and I pray for death. When // we encounter a closure here, it is always a closure @@ -1003,7 +1003,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { ty_op: |ty| { if ty.references_error() { return tcx.ty_error(); - } else if let ty::Opaque(def_id, substs) = ty.kind { + } else if let ty::Opaque(def_id, substs) = ty.kind() { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose // value we are inferring. At present, this is @@ -1261,7 +1261,8 @@ crate fn required_region_bounds( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::RegionOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs similarity index 98% rename from src/librustc_trait_selection/traits/auto_trait.rs rename to compiler/rustc_trait_selection/src/traits/auto_trait.rs index fa3d024199..e40067202e 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -32,6 +32,7 @@ pub enum AutoTraitResult { NegativeImpl, } +#[allow(dead_code)] impl AutoTraitResult { fn is_auto(&self) -> bool { match *self { @@ -96,7 +97,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { )); match result { - Ok(Some(ImplSource::ImplSourceUserDefined(_))) => { + Ok(Some(ImplSource::UserDefined(_))) => { debug!( "find_auto_trait_generics({:?}): \ manual impl found, bailing out", @@ -315,9 +316,8 @@ impl AutoTraitFinder<'tcx> { // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`), // we immediately bail out, since it's impossible for us to continue. - if let ImplSource::ImplSourceUserDefined(ImplSourceUserDefinedData { - impl_def_id, - .. + if let ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id, .. }) = impl_source { // Blame 'tidy' for the weird bracket placement. @@ -373,14 +373,12 @@ impl AutoTraitFinder<'tcx> { computed_preds.clone().chain(user_computed_preds.iter().cloned()), ) .map(|o| o.predicate); - new_env = - ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal(), None); + new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal()); } let final_user_env = ty::ParamEnv::new( tcx.mk_predicates(user_computed_preds.into_iter()), user_env.reveal(), - None, ); debug!( "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ @@ -598,7 +596,7 @@ impl AutoTraitFinder<'tcx> { } pub fn is_of_param(&self, ty: Ty<'_>) -> bool { - match ty.kind { + match ty.kind() { ty::Param(_) => true, ty::Projection(p) => self.is_of_param(p.self_ty()), _ => false, @@ -606,7 +604,7 @@ impl AutoTraitFinder<'tcx> { } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - match p.ty().skip_binder().kind { + match *p.ty().skip_binder().kind() { ty::Projection(proj) if proj == p.skip_binder().projection_ty => true, _ => false, } diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs new file mode 100644 index 0000000000..adc8ae5908 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -0,0 +1,143 @@ +//! Defines a Chalk-based `TraitEngine` + +use crate::infer::canonical::OriginalQueryValues; +use crate::infer::InferCtxt; +use crate::traits::query::NoSolution; +use crate::traits::{ + ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, + PredicateObligation, SelectionError, TraitEngine, +}; +use rustc_data_structures::fx::FxIndexSet; +use rustc_middle::ty::{self, Ty}; + +pub struct FulfillmentContext<'tcx> { + obligations: FxIndexSet>, +} + +impl FulfillmentContext<'tcx> { + crate fn new() -> Self { + FulfillmentContext { obligations: FxIndexSet::default() } + } +} + +impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { + fn normalize_projection_type( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + _param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + _cause: ObligationCause<'tcx>, + ) -> Ty<'tcx> { + infcx.tcx.mk_ty(ty::Projection(projection_ty)) + } + + fn register_predicate_obligation( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + obligation: PredicateObligation<'tcx>, + ) { + assert!(!infcx.is_in_snapshot()); + let obligation = infcx.resolve_vars_if_possible(&obligation); + + self.obligations.insert(obligation); + } + + fn select_all_or_error( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec>> { + self.select_where_possible(infcx)?; + + if self.obligations.is_empty() { + Ok(()) + } else { + let errors = self + .obligations + .iter() + .map(|obligation| FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeAmbiguity, + points_at_arg_span: false, + }) + .collect(); + Err(errors) + } + } + + fn select_where_possible( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec>> { + assert!(!infcx.is_in_snapshot()); + + let mut errors = Vec::new(); + let mut next_round = FxIndexSet::default(); + let mut making_progress; + + loop { + making_progress = false; + + // We iterate over all obligations, and record if we are able + // to unambiguously prove at least one obligation. + for obligation in self.obligations.drain(..) { + let obligation = infcx.resolve_vars_if_possible(&obligation); + let environment = obligation.param_env.caller_bounds(); + let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }; + let mut orig_values = OriginalQueryValues::default(); + let canonical_goal = infcx.canonicalize_query(&goal, &mut orig_values); + + match infcx.tcx.evaluate_goal(canonical_goal) { + Ok(response) => { + if response.is_proven() { + making_progress = true; + + match infcx.instantiate_query_response_and_region_obligations( + &obligation.cause, + obligation.param_env, + &orig_values, + &response, + ) { + Ok(infer_ok) => next_round.extend( + infer_ok.obligations.into_iter().map(|obligation| { + assert!(!infcx.is_in_snapshot()); + infcx.resolve_vars_if_possible(&obligation) + }), + ), + + Err(_err) => errors.push(FulfillmentError { + obligation, + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + points_at_arg_span: false, + }), + } + } else { + // Ambiguous: retry at next round. + next_round.insert(obligation); + } + } + + Err(NoSolution) => errors.push(FulfillmentError { + obligation, + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + points_at_arg_span: false, + }), + } + } + next_round = std::mem::replace(&mut self.obligations, next_round); + + if !making_progress { + break; + } + } + + if errors.is_empty() { Ok(()) } else { Err(errors) } + } + + fn pending_obligations(&self) -> Vec> { + self.obligations.iter().cloned().collect() + } +} diff --git a/src/librustc_trait_selection/traits/codegen/mod.rs b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs similarity index 96% rename from src/librustc_trait_selection/traits/codegen/mod.rs rename to compiler/rustc_trait_selection/src/traits/codegen/mod.rs index dd7ea55cc1..6b1ed5f493 100644 --- a/src/librustc_trait_selection/traits/codegen/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs @@ -118,7 +118,10 @@ where // contains unbound type parameters. It could be a slight // optimization to stop iterating early. if let Err(errors) = fulfill_cx.select_all_or_error(infcx) { - bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors); + infcx.tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors), + ); } let result = infcx.resolve_vars_if_possible(result); diff --git a/src/librustc_trait_selection/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs similarity index 99% rename from src/librustc_trait_selection/traits/coherence.rs rename to compiler/rustc_trait_selection/src/traits/coherence.rs index b06cf4411d..c53c65c00b 100644 --- a/src/librustc_trait_selection/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -182,7 +182,7 @@ fn overlap_within_probe( } if !skip_leak_check.is_yes() { - if let Err(_) = infcx.leak_check(true, snapshot) { + if infcx.leak_check(true, snapshot).is_err() { debug!("overlap: leak check failed"); return None; } @@ -412,7 +412,7 @@ fn orphan_check_trait_ref<'tcx>( if non_local_tys.is_empty() { debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); return Ok(()); - } else if let ty::Param(_) = input_ty.kind { + } else if let ty::Param(_) = input_ty.kind() { debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); let local_type = trait_ref .substs @@ -467,7 +467,7 @@ fn fundamental_ty_inner_tys( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, ) -> Option>> { - let (first_ty, rest_tys) = match ty.kind { + let (first_ty, rest_tys) = match *ty.kind() { ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()), ty::Adt(def, substs) if def.is_fundamental() => { let mut types = substs.types(); @@ -504,7 +504,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { debug!("ty_is_local_constructor({:?})", ty); - match ty.kind { + match *ty.kind() { ty::Bool | ty::Char | ty::Int(..) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs new file mode 100644 index 0000000000..3828cf4d30 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -0,0 +1,593 @@ +//! Checking that constant values used in types can be successfully evaluated. +//! +//! For concrete constants, this is fairly simple as we can just try and evaluate it. +//! +//! When dealing with polymorphic constants, for example `std::mem::size_of::() - 1`, +//! this is not as easy. +//! +//! In this case we try to build an abstract representation of this constant using +//! `mir_abstract_const` which can then be checked for structural equality with other +//! generic constants mentioned in the `caller_bounds` of the current environment. +use rustc_errors::ErrorReported; +use rustc_hir::def::DefKind; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_infer::infer::InferCtxt; +use rustc_middle::mir::abstract_const::{Node, NodeId}; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; +use rustc_session::lint; +use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::Span; + +use std::cmp; + +/// Check if a given constant can be evaluated. +pub fn is_const_evaluatable<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + def: ty::WithOptConstParam, + substs: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, +) -> Result<(), ErrorHandled> { + debug!("is_const_evaluatable({:?}, {:?})", def, substs); + if infcx.tcx.features().const_evaluatable_checked { + let tcx = infcx.tcx; + match AbstractConst::new(tcx, def, substs)? { + // We are looking at a generic abstract constant. + Some(ct) => { + for pred in param_env.caller_bounds() { + match pred.skip_binders() { + ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { + debug!( + "is_const_evaluatable: caller_bound={:?}, {:?}", + b_def, b_substs + ); + if b_def == def && b_substs == substs { + debug!("is_const_evaluatable: caller_bound ~~> ok"); + return Ok(()); + } else if AbstractConst::new(tcx, b_def, b_substs)? + .map_or(false, |b_ct| try_unify(tcx, ct, b_ct)) + { + debug!("is_const_evaluatable: abstract_const ~~> ok"); + return Ok(()); + } + } + _ => {} // don't care + } + } + + // We were unable to unify the abstract constant with + // a constant found in the caller bounds, there are + // now three possible cases here. + // + // - The substs are concrete enough that we can simply + // try and evaluate the given constant. + // - The abstract const still references an inference + // variable, in this case we return `TooGeneric`. + // - The abstract const references a generic parameter, + // this means that we emit an error here. + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum FailureKind { + MentionsInfer, + MentionsParam, + Concrete, + } + let mut failure_kind = FailureKind::Concrete; + walk_abstract_const(tcx, ct, |node| match node { + Node::Leaf(leaf) => { + let leaf = leaf.subst(tcx, ct.substs); + if leaf.has_infer_types_or_consts() { + failure_kind = FailureKind::MentionsInfer; + } else if leaf.has_param_types_or_consts() { + failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); + } + } + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => (), + }); + + match failure_kind { + FailureKind::MentionsInfer => { + return Err(ErrorHandled::TooGeneric); + } + FailureKind::MentionsParam => { + // FIXME(const_evaluatable_checked): Better error message. + infcx + .tcx + .sess + .struct_span_err(span, "unconstrained generic constant") + .span_help( + tcx.def_span(def.did), + "consider adding a `where` bound for this expression", + ) + .emit(); + return Err(ErrorHandled::Reported(ErrorReported)); + } + FailureKind::Concrete => { + // Dealt with below by the same code which handles this + // without the feature gate. + } + } + } + None => { + // If we are dealing with a concrete constant, we can + // reuse the old code path and try to evaluate + // the constant. + } + } + } + + let future_compat_lint = || { + if let Some(local_def_id) = def.did.as_local() { + infcx.tcx.struct_span_lint_hir( + lint::builtin::CONST_EVALUATABLE_UNCHECKED, + infcx.tcx.hir().local_def_id_to_hir_id(local_def_id), + span, + |err| { + err.build("cannot use constants which depend on generic parameters in types") + .emit(); + }, + ); + } + }; + + // FIXME: We should only try to evaluate a given constant here if it is fully concrete + // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`. + // + // We previously did not check this, so we only emit a future compat warning if + // const evaluation succeeds and the given constant is still polymorphic for now + // and hopefully soon change this to an error. + // + // See #74595 for more details about this. + let concrete = infcx.const_eval_resolve(param_env, def, substs, None, Some(span)); + + if concrete.is_ok() && substs.has_param_types_or_consts() { + match infcx.tcx.def_kind(def.did) { + DefKind::AnonConst => { + let mir_body = if let Some(def) = def.as_const_arg() { + infcx.tcx.optimized_mir_of_const_arg(def) + } else { + infcx.tcx.optimized_mir(def.did) + }; + + if mir_body.is_polymorphic { + future_compat_lint(); + } + } + _ => future_compat_lint(), + } + } + + debug!(?concrete, "is_const_evaluatable"); + match concrete { + Err(ErrorHandled::TooGeneric) if !substs.has_infer_types_or_consts() => { + // FIXME(const_evaluatable_checked): We really should move + // emitting this error message to fulfill instead. For + // now this is easier. + // + // This is not a problem without `const_evaluatable_checked` as + // all `ConstEvaluatable` predicates have to be fulfilled for compilation + // to succeed. + // + // @lcnr: We already emit an error for things like + // `fn test() -> [0 - N]` eagerly here, + // so until we fix this I don't really care. + + let mut err = infcx + .tcx + .sess + .struct_span_err(span, "constant expression depends on a generic parameter"); + // FIXME(const_generics): we should suggest to the user how they can resolve this + // issue. However, this is currently not actually possible + // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). + // + // Note that with `feature(const_evaluatable_checked)` this case should not + // be reachable. + err.note("this may fail depending on what value the parameter takes"); + err.emit(); + Err(ErrorHandled::Reported(ErrorReported)) + } + c => c.map(drop), + } +} + +/// A tree representing an anonymous constant. +/// +/// This is only able to represent a subset of `MIR`, +/// and should not leak any information about desugarings. +#[derive(Clone, Copy)] +pub struct AbstractConst<'tcx> { + // FIXME: Consider adding something like `IndexSlice` + // and use this here. + inner: &'tcx [Node<'tcx>], + substs: SubstsRef<'tcx>, +} + +impl AbstractConst<'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, + substs: SubstsRef<'tcx>, + ) -> Result>, ErrorReported> { + let inner = match (def.did.as_local(), def.const_param_did) { + (Some(did), Some(param_did)) => { + tcx.mir_abstract_const_of_const_arg((did, param_did))? + } + _ => tcx.mir_abstract_const(def.did)?, + }; + + Ok(inner.map(|inner| AbstractConst { inner, substs })) + } + + #[inline] + pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> { + AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs } + } + + #[inline] + pub fn root(self) -> Node<'tcx> { + self.inner.last().copied().unwrap() + } +} + +struct AbstractConstBuilder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + /// The current WIP node tree. + nodes: IndexVec>, + locals: IndexVec, + /// We only allow field accesses if they access + /// the result of a checked operation. + checked_op_locals: BitSet, +} + +impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { + fn error(&mut self, span: Option, msg: &str) -> Result { + self.tcx + .sess + .struct_span_err(self.body.span, "overly complex generic constant") + .span_label(span.unwrap_or(self.body.span), msg) + .help("consider moving this anonymous constant into a `const` function") + .emit(); + + Err(ErrorReported) + } + + fn new( + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + ) -> Result>, ErrorReported> { + let mut builder = AbstractConstBuilder { + tcx, + body, + nodes: IndexVec::new(), + locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls), + checked_op_locals: BitSet::new_empty(body.local_decls.len()), + }; + + // We don't have to look at concrete constants, as we + // can just evaluate them. + if !body.is_polymorphic { + return Ok(None); + } + + // We only allow consts without control flow, so + // we check for cycles here which simplifies the + // rest of this implementation. + if body.is_cfg_cyclic() { + builder.error(None, "cyclic anonymous constants are forbidden")?; + } + + Ok(Some(builder)) + } + + fn place_to_local( + &mut self, + span: Span, + p: &mir::Place<'tcx>, + ) -> Result { + const ZERO_FIELD: mir::Field = mir::Field::from_usize(0); + // Do not allow any projections. + // + // One exception are field accesses on the result of checked operations, + // which are required to support things like `1 + 2`. + if let Some(p) = p.as_local() { + debug_assert!(!self.checked_op_locals.contains(p)); + Ok(p) + } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() { + // Only allow field accesses if the given local + // contains the result of a checked operation. + if self.checked_op_locals.contains(p.local) { + Ok(p.local) + } else { + self.error(Some(span), "unsupported projection")?; + } + } else { + self.error(Some(span), "unsupported projection")?; + } + } + + fn operand_to_node( + &mut self, + span: Span, + op: &mir::Operand<'tcx>, + ) -> Result { + debug!("operand_to_node: op={:?}", op); + match op { + mir::Operand::Copy(p) | mir::Operand::Move(p) => { + let local = self.place_to_local(span, p)?; + Ok(self.locals[local]) + } + mir::Operand::Constant(ct) => Ok(self.nodes.push(Node::Leaf(ct.literal))), + } + } + + /// We do not allow all binary operations in abstract consts, so filter disallowed ones. + fn check_binop(op: mir::BinOp) -> bool { + use mir::BinOp::*; + match op { + Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le + | Ne | Ge | Gt => true, + Offset => false, + } + } + + /// While we currently allow all unary operations, we still want to explicitly guard against + /// future changes here. + fn check_unop(op: mir::UnOp) -> bool { + use mir::UnOp::*; + match op { + Not | Neg => true, + } + } + + fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> { + debug!("AbstractConstBuilder: stmt={:?}", stmt); + match stmt.kind { + StatementKind::Assign(box (ref place, ref rvalue)) => { + let local = self.place_to_local(stmt.source_info.span, place)?; + match *rvalue { + Rvalue::Use(ref operand) => { + self.locals[local] = + self.operand_to_node(stmt.source_info.span, operand)?; + Ok(()) + } + Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { + let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; + let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; + self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); + if op.is_checkable() { + bug!("unexpected unchecked checkable binary operation"); + } else { + Ok(()) + } + } + Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { + let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; + let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; + self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); + self.checked_op_locals.insert(local); + Ok(()) + } + Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { + let operand = self.operand_to_node(stmt.source_info.span, operand)?; + self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand)); + Ok(()) + } + _ => self.error(Some(stmt.source_info.span), "unsupported rvalue")?, + } + } + // These are not actually relevant for us here, so we can ignore them. + StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Ok(()), + _ => self.error(Some(stmt.source_info.span), "unsupported statement")?, + } + } + + /// Possible return values: + /// + /// - `None`: unsupported terminator, stop building + /// - `Some(None)`: supported terminator, finish building + /// - `Some(Some(block))`: support terminator, build `block` next + fn build_terminator( + &mut self, + terminator: &mir::Terminator<'tcx>, + ) -> Result, ErrorReported> { + debug!("AbstractConstBuilder: terminator={:?}", terminator); + match terminator.kind { + TerminatorKind::Goto { target } => Ok(Some(target)), + TerminatorKind::Return => Ok(None), + TerminatorKind::Call { + ref func, + ref args, + destination: Some((ref place, target)), + // We do not care about `cleanup` here. Any branch which + // uses `cleanup` will fail const-eval and they therefore + // do not matter when checking for const evaluatability. + // + // Do note that even if `panic::catch_unwind` is made const, + // we still do not have to care about this, as we do not look + // into functions. + cleanup: _, + // Do not allow overloaded operators for now, + // we probably do want to allow this in the future. + // + // This is currently fairly irrelevant as it requires `const Trait`s. + from_hir_call: true, + fn_span, + } => { + let local = self.place_to_local(fn_span, place)?; + let func = self.operand_to_node(fn_span, func)?; + let args = self.tcx.arena.alloc_from_iter( + args.iter() + .map(|arg| self.operand_to_node(terminator.source_info.span, arg)) + .collect::, _>>()?, + ); + self.locals[local] = self.nodes.push(Node::FunctionCall(func, args)); + Ok(Some(target)) + } + // We only allow asserts for checked operations. + // + // These asserts seem to all have the form `!_local.0` so + // we only allow exactly that. + TerminatorKind::Assert { ref cond, expected: false, target, .. } => { + let p = match cond { + mir::Operand::Copy(p) | mir::Operand::Move(p) => p, + mir::Operand::Constant(_) => bug!("unexpected assert"), + }; + + const ONE_FIELD: mir::Field = mir::Field::from_usize(1); + debug!("proj: {:?}", p.projection); + if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { + // Only allow asserts checking the result of a checked operation. + if self.checked_op_locals.contains(p.local) { + return Ok(Some(target)); + } + } + + self.error(Some(terminator.source_info.span), "unsupported assertion")?; + } + _ => self.error(Some(terminator.source_info.span), "unsupported terminator")?, + } + } + + /// Builds the abstract const by walking the mir from start to finish + /// and bailing out when encountering an unsupported operation. + fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> { + let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; + // We checked for a cyclic cfg above, so this should terminate. + loop { + debug!("AbstractConstBuilder: block={:?}", block); + for stmt in block.statements.iter() { + self.build_statement(stmt)?; + } + + if let Some(next) = self.build_terminator(block.terminator())? { + block = &self.body.basic_blocks()[next]; + } else { + return Ok(self.tcx.arena.alloc_from_iter(self.nodes)); + } + } + } +} + +/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. +pub(super) fn mir_abstract_const<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> Result]>, ErrorReported> { + if tcx.features().const_evaluatable_checked { + match tcx.def_kind(def.did) { + // FIXME(const_evaluatable_checked): We currently only do this for anonymous constants, + // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether + // we want to look into them or treat them as opaque projections. + // + // Right now we do neither of that and simply always fail to unify them. + DefKind::AnonConst => (), + _ => return Ok(None), + } + let body = tcx.mir_const(def).borrow(); + AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose() + } else { + Ok(None) + } +} + +pub(super) fn try_unify_abstract_consts<'tcx>( + tcx: TyCtxt<'tcx>, + ((a, a_substs), (b, b_substs)): ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>), + ), +) -> bool { + (|| { + if let Some(a) = AbstractConst::new(tcx, a, a_substs)? { + if let Some(b) = AbstractConst::new(tcx, b, b_substs)? { + return Ok(try_unify(tcx, a, b)); + } + } + + Ok(false) + })() + .unwrap_or_else(|ErrorReported| true) + // FIXME(const_evaluatable_checked): We should instead have this + // method return the resulting `ty::Const` and return `ConstKind::Error` + // on `ErrorReported`. +} + +fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F) +where + F: FnMut(Node<'tcx>), +{ + recurse(tcx, ct, &mut f); + fn recurse<'tcx>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, f: &mut dyn FnMut(Node<'tcx>)) { + let root = ct.root(); + f(root); + match root { + Node::Leaf(_) => (), + Node::Binop(_, l, r) => { + recurse(tcx, ct.subtree(l), f); + recurse(tcx, ct.subtree(r), f); + } + Node::UnaryOp(_, v) => { + recurse(tcx, ct.subtree(v), f); + } + Node::FunctionCall(func, args) => { + recurse(tcx, ct.subtree(func), f); + for &arg in args { + recurse(tcx, ct.subtree(arg), f); + } + } + } + } +} + +/// Tries to unify two abstract constants using structural equality. +pub(super) fn try_unify<'tcx>( + tcx: TyCtxt<'tcx>, + a: AbstractConst<'tcx>, + b: AbstractConst<'tcx>, +) -> bool { + match (a.root(), b.root()) { + (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { + let a_ct = a_ct.subst(tcx, a.substs); + let b_ct = b_ct.subst(tcx, b.substs); + match (a_ct.val, b_ct.val) { + // We can just unify errors with everything to reduce the amount of + // emitted errors here. + (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true, + (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => { + a_param == b_param + } + (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, + // If we have `fn a() -> [u8; N + 1]` and `fn b() -> [u8; 1 + M]` + // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This + // means that we only allow inference variables if they are equal. + (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val, + // FIXME(const_evaluatable_checked): We may want to either actually try + // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like + // this, for now we just return false here. + _ => false, + } + } + (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => { + try_unify(tcx, a.subtree(al), b.subtree(bl)) + && try_unify(tcx, a.subtree(ar), b.subtree(br)) + } + (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => { + try_unify(tcx, a.subtree(av), b.subtree(bv)) + } + (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args)) + if a_args.len() == b_args.len() => + { + try_unify(tcx, a.subtree(a_f), b.subtree(b_f)) + && a_args + .iter() + .zip(b_args) + .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) + } + _ => false, + } +} diff --git a/src/librustc_trait_selection/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs similarity index 100% rename from src/librustc_trait_selection/traits/engine.rs rename to compiler/rustc_trait_selection/src/traits/engine.rs diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs similarity index 96% rename from src/librustc_trait_selection/traits/error_reporting/mod.rs rename to compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 28542d4b12..cb3de57cfe 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -20,7 +20,6 @@ use rustc_hir::Node; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{ self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -382,7 +381,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! err.span_label(span, s.as_str()); - if !matches!(trait_ref.skip_binder().self_ty().kind, ty::Param(_)) { + if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point // at the type param with a label to suggest constraining it. @@ -446,12 +445,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.tcx.lang_items().fn_once_trait(), ] .contains(&Some(trait_ref.def_id())); - let is_target_feature_fn = - if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind { - !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() - } else { - false - }; + let is_target_feature_fn = if let ty::FnDef(def_id, _) = + *trait_ref.skip_binder().self_ty().kind() + { + !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() + } else { + false + }; if is_fn_trait && is_target_feature_fn { err.note( "`#[target_feature]` functions do not implement the `Fn` traits", @@ -662,6 +662,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation ) } + + ty::PredicateAtom::TypeWellFormedFromEnv(..) => span_bug!( + span, + "TypeWellFormedFromEnv predicate should only exist in the environment" + ), } } @@ -678,7 +683,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { None => return, }; - let found_did = match found_trait_ty.kind { + let found_did = match *found_trait_ty.kind() { ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), ty::Adt(def, _) => Some(def.did), _ => None, @@ -696,13 +701,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); - let found = match found_trait_ref.skip_binder().substs.type_at(1).kind { + 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()], }; let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); - let expected = match expected_ty.kind { + let expected = match expected_ty.kind() { ty::Tuple(ref tys) => tys .iter() .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))) @@ -740,25 +745,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let violations = self.tcx.object_safety_violations(did); report_object_safety_error(self.tcx, span, did, violations) } - ConstEvalFailure(ErrorHandled::TooGeneric) => { - // In this instance, we have a const expression containing an unevaluated - // generic parameter. We have no idea whether this expression is valid or - // not (e.g. it might result in an error), but we don't want to just assume - // that it's okay, because that might result in post-monomorphisation time - // errors. The onus is really on the caller to provide values that it can - // prove are well-formed. - let mut err = self - .tcx - .sess - .struct_span_err(span, "constant expression depends on a generic parameter"); - // FIXME(const_generics): we should suggest to the user how they can resolve this - // issue. However, this is currently not actually possible - // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). - err.note("this may fail depending on what value the parameter takes"); - err + bug!("too generic should have been handled in `is_const_evaluatable`"); } - // Already reported in the query. ConstEvalFailure(ErrorHandled::Reported(ErrorReported)) => { // FIXME(eddyb) remove this once `ErrorReported` becomes a proof token. @@ -1252,7 +1241,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { /// returns the fuzzy category of a given type, or None /// if the type can be equated to any type. fn type_category(t: Ty<'_>) -> Option { - match t.kind { + match t.kind() { ty::Bool => Some(0), ty::Char => Some(1), ty::Str => Some(2), @@ -1281,7 +1270,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } match (type_category(a), type_category(b)) { - (Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) { + (Some(cat_a), Some(cat_b)) => match (a.kind(), b.kind()) { (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b, _ => cat_a == cat_b, }, @@ -1342,8 +1331,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { .normalize(candidate) .ok(); match normalized { - Some(normalized) => format!("\n {:?}", normalized.value), - None => format!("\n {:?}", candidate), + Some(normalized) => format!("\n {}", normalized.value), + None => format!("\n {}", candidate), } }) }; @@ -1476,7 +1465,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ty::PredicateAtom::Trait(data, _) => { let trait_ref = ty::Binder::bind(data.trait_ref); let self_ty = trait_ref.skip_binder().self_ty(); - debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); + debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind(), trait_ref); if predicate.references_error() { return; @@ -1506,16 +1495,22 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. - if self - .tcx - .lang_items() - .sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { - self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); + if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + self.emit_inference_failure_err( + body_id, + span, + self_ty.into(), + ErrorCode::E0282, + ) + .emit(); return; } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); + let mut err = self.emit_inference_failure_err( + body_id, + span, + self_ty.into(), + ErrorCode::E0283, + ); err.note(&format!("cannot satisfy `{}`", predicate)); if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); @@ -1579,17 +1574,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - match arg.unpack() { - GenericArgKind::Lifetime(lt) => { - span_bug!(span, "unexpected well formed predicate: {:?}", lt) - } - GenericArgKind::Type(ty) => { - self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) - } - GenericArgKind::Const(ct) => { - self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) - } - } + self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282) } ty::PredicateAtom::Subtype(data) => { @@ -1600,7 +1585,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let SubtypePredicate { a_is_expected: _, a, b } = data; // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info_err(body_id, span, a, ErrorCode::E0282) + self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282) } ty::PredicateAtom::Projection(data) => { let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx); @@ -1611,7 +1596,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } if self_ty.needs_infer() && ty.needs_infer() { // We do this for the `foo.collect()?` case to produce a suggestion. - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); + let mut err = self.emit_inference_failure_err( + body_id, + span, + self_ty.into(), + ErrorCode::E0284, + ); err.note(&format!("cannot satisfy `{}`", predicate)); err } else { @@ -1664,7 +1654,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Param(ty::ParamTy { name, .. }) = ty.kind { + if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() { let infcx = self.infcx; self.var_map.entry(ty).or_insert_with(|| { infcx.next_ty_var(TypeVariableOrigin { @@ -1938,8 +1928,8 @@ impl ArgKind { /// Creates an `ArgKind` from the expected type of an /// argument. It has no name (`_`) and an optional source span. pub fn from_expected_ty(t: Ty<'_>, span: Option) -> ArgKind { - match t.kind { - ty::Tuple(ref tys) => ArgKind::Tuple( + match t.kind() { + ty::Tuple(tys) => ArgKind::Tuple( span, tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::>(), ), diff --git a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs similarity index 98% rename from src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs rename to compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index d2b9f84af3..0f5aad5af1 100644 --- a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -194,7 +194,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { flags.push((sym::_Self, Some("{integral}".to_owned()))); } - if let ty::Array(aty, len) = self_ty.kind { + if let ty::Array(aty, len) = self_ty.kind() { flags.push((sym::_Self, Some("[]".to_owned()))); flags.push((sym::_Self, Some(format!("[{}]", aty)))); if let Some(def) = aty.ty_adt_def() { @@ -218,7 +218,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.skip_binder() { if let ty::ExistentialPredicate::Trait(trait_ref) = t { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs similarity index 99% rename from src/librustc_trait_selection/traits/error_reporting/suggestions.rs rename to compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 138293c953..90a8d9634a 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -207,7 +207,7 @@ fn suggest_restriction( } // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... if let Some((bound_str, fn_sig)) = - fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind { + fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind() { // Shenanigans to get the `Trait` from the `impl Trait`. ty::Param(param) => { // `fn foo(t: impl Trait)` @@ -323,7 +323,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { body_id: hir::HirId, ) { let self_ty = trait_ref.skip_binder().self_ty(); - let (param_ty, projection) = match &self_ty.kind { + let (param_ty, projection) = match self_ty.kind() { ty::Param(_) => (true, None), ty::Projection(projection) => (false, Some(projection)), _ => return, @@ -482,8 +482,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { None => return, }; - if let ty::Ref(region, base_ty, mutbl) = real_ty.kind { - let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty); + 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 Some(steps) = autoderef.find_map(|(ty, steps)| { // Re-add the `&` let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); @@ -563,7 +563,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { Some(ty) => ty, }; - let (def_id, output_ty, callable) = match self_ty.kind { + let (def_id, output_ty, callable) = match *self_ty.kind() { ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"), ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"), _ => return, @@ -751,7 +751,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; for refs_remaining in 0..refs_number { - if let ty::Ref(_, inner_ty, _) = suggested_ty.kind { + if let ty::Ref(_, inner_ty, _) = suggested_ty.kind() { suggested_ty = inner_ty; let new_obligation = self.mk_trait_obligation_with_new_self_ty( @@ -814,7 +814,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind { + if let ty::Ref(region, t_type, mutability) = *trait_ref.skip_binder().self_ty().kind() { if region.is_late_bound() || t_type.has_escaping_bound_vars() { // Avoid debug assertion in `mk_obligation_for_def_id`. // @@ -871,7 +871,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: &ty::Binder>, ) { let is_empty_tuple = - |ty: ty::Binder>| ty.skip_binder().kind == ty::Tuple(ty::List::empty()); + |ty: ty::Binder>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty()); let hir = self.tcx.hir(); let parent_node = hir.get_parent_node(obligation.cause.body_id); @@ -941,7 +941,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let body = hir.body(*body_id); let trait_ref = self.resolve_vars_if_possible(trait_ref); let ty = trait_ref.skip_binder().self_ty(); - let is_object_safe = match ty.kind { + let is_object_safe = match ty.kind() { ty::Dynamic(predicates, _) => { // If the `dyn Trait` is not object safe, do not suggest `Box`. predicates @@ -982,11 +982,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty| { let ty = self.resolve_vars_if_possible(&ty); same &= - !matches!(ty.kind, ty::Error(_)) + !matches!(ty.kind(), ty::Error(_)) && last_ty.map_or(true, |last_ty| { // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes // *after* in the dependency graph. - match (&ty.kind, &last_ty.kind) { + match (ty.kind(), last_ty.kind()) { (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_))) | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_))) | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_))) @@ -997,12 +997,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => ty == last_ty, } }); - (Some(ty), same, only_never_return && matches!(ty.kind, ty::Never)) + (Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never)) }, ); let all_returns_conform_to_trait = if let Some(ty_ret_ty) = typeck_results.node_type_opt(ret_ty.hir_id) { - match ty_ret_ty.kind { + match ty_ret_ty.kind() { ty::Dynamic(predicates, _) => { let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id); let param_env = ty::ParamEnv::empty(); @@ -1151,7 +1151,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: ty::TraitRef<'tcx>, ) -> String { let inputs = trait_ref.substs.type_at(1); - let sig = if let ty::Tuple(inputs) = inputs.kind { + let sig = if let ty::Tuple(inputs) = inputs.kind() { tcx.mk_fn_sig( inputs.iter().map(|k| k.expect_ty()), tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), @@ -1317,10 +1317,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { debug!( "maybe_note_obligation_cause_for_async_await: \ parent_trait_ref={:?} self_ty.kind={:?}", - derived_obligation.parent_trait_ref, ty.kind + derived_obligation.parent_trait_ref, + ty.kind() ); - match ty.kind { + match *ty.kind() { ty::Generator(did, ..) => { generator = generator.or(Some(did)); outer_generator = Some(did); diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs similarity index 90% rename from src/librustc_trait_selection/traits/fulfill.rs rename to compiler/rustc_trait_selection/src/traits/fulfill.rs index a5c6dc042a..8586a55023 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; use std::marker::PhantomData; +use super::const_evaluatable; use super::project; use super::select::SelectionContext; use super::wf; @@ -86,7 +87,7 @@ pub struct PendingPredicateObligation<'tcx> { // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PendingPredicateObligation<'_>, 64); +static_assert_size!(PendingPredicateObligation<'_>, 56); impl<'a, 'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. @@ -304,8 +305,34 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { return ProcessResult::Unchanged; } - // This part of the code is much colder. + self.progress_changed_obligations(pending_obligation) + } + + fn process_backedge<'c, I>( + &mut self, + cycle: I, + _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, + ) where + I: Clone + Iterator>, + { + if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { + debug!("process_child_obligations: coinductive match"); + } else { + let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); + self.selcx.infcx().report_overflow_error_cycle(&cycle); + } + } +} +impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { + // The code calling this method is extremely hot and only rarely + // actually uses this, so move this part of the code + // out of that loop. + #[inline(never)] + fn progress_changed_obligations( + &mut self, + pending_obligation: &mut PendingPredicateObligation<'tcx>, + ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { pending_obligation.stalled_on.truncate(0); let obligation = &mut pending_obligation.obligation; @@ -354,6 +381,9 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { obligation.with(pred.to_predicate(self.selcx.tcx())), ])) } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } }, &ty::PredicateKind::Atom(atom) => match atom { ty::PredicateAtom::Trait(ref data, _) => { @@ -458,20 +488,46 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { - match self.selcx.infcx().const_eval_resolve( - obligation.param_env, + match const_evaluatable::is_const_evaluatable( + self.selcx.infcx(), def_id, substs, - None, - Some(obligation.cause.span), + obligation.param_env, + obligation.cause.span, ) { - Ok(_) => ProcessResult::Changed(vec![]), - Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))), + Ok(()) => ProcessResult::Changed(vec![]), + Err(ErrorHandled::TooGeneric) => { + pending_obligation.stalled_on = substs + .iter() + .filter_map(|ty| TyOrConstInferVar::maybe_from_generic_arg(ty)) + .collect(); + ProcessResult::Unchanged + } + Err(e) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))), } } ty::PredicateAtom::ConstEquate(c1, c2) => { debug!("equating consts: c1={:?} c2={:?}", c1, c2); + if self.selcx.tcx().features().const_evaluatable_checked { + // FIXME: we probably should only try to unify abstract constants + // if the constants depend on generic parameters. + // + // Let's just see where this breaks :shrug: + if let ( + ty::ConstKind::Unevaluated(a_def, a_substs, None), + ty::ConstKind::Unevaluated(b_def, b_substs, None), + ) = (c1.val, c2.val) + { + if self + .selcx + .tcx() + .try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) + { + return ProcessResult::Changed(vec![]); + } + } + } let stalled_on = &mut pending_obligation.stalled_on; @@ -488,8 +544,10 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { Err(ErrorHandled::TooGeneric) => { stalled_on.append( &mut substs - .types() - .filter_map(|ty| TyOrConstInferVar::maybe_from_ty(ty)) + .iter() + .filter_map(|arg| { + TyOrConstInferVar::maybe_from_generic_arg(arg) + }) .collect(), ); Err(ErrorHandled::TooGeneric) @@ -535,27 +593,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } }, } } - fn process_backedge<'c, I>( - &mut self, - cycle: I, - _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, - ) where - I: Clone + Iterator>, - { - if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { - debug!("process_child_obligations: coinductive match"); - } else { - let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); - self.selcx.infcx().report_overflow_error_cycle(&cycle); - } - } -} - -impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { fn process_trait_obligation( &mut self, obligation: &PredicateObligation<'tcx>, diff --git a/src/librustc_trait_selection/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs similarity index 97% rename from src/librustc_trait_selection/traits/misc.rs rename to compiler/rustc_trait_selection/src/traits/misc.rs index 61567aeb57..e23f5a583b 100644 --- a/src/librustc_trait_selection/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -23,7 +23,7 @@ pub fn can_type_implement_copy( ) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { - let (adt, substs) = match self_type.kind { + let (adt, substs) = match self_type.kind() { // These types used to have a builtin impl. // Now libcore provides that impl. ty::Uint(_) diff --git a/src/librustc_trait_selection/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs similarity index 95% rename from src/librustc_trait_selection/traits/mod.rs rename to compiler/rustc_trait_selection/src/traits/mod.rs index fe406e88c5..c93087a18c 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -2,11 +2,11 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html -#[allow(dead_code)] pub mod auto_trait; mod chalk_fulfill; pub mod codegen; mod coherence; +mod const_evaluatable; mod engine; pub mod error_reporting; mod fulfill; @@ -301,11 +301,8 @@ pub fn normalize_param_env_or_error<'tcx>( debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - let elaborated_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal(), - unnormalized_env.def_id, - ); + let elaborated_env = + ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal()); // HACK: we are trying to normalize the param-env inside *itself*. The problem is that // normalization expects its param-env to be already normalized, which means we have @@ -359,7 +356,7 @@ pub fn normalize_param_env_or_error<'tcx>( let outlives_env: Vec<_> = non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); let outlives_env = - ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal(), None); + ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal()); let outlives_predicates = match do_normalize_predicates( tcx, region_context, @@ -379,11 +376,7 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates = non_outlives_predicates; predicates.extend(outlives_predicates); debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal(), - unnormalized_env.def_id, - ) + ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal()) } pub fn fully_normalize<'a, 'tcx, T>( @@ -558,6 +551,21 @@ pub fn provide(providers: &mut ty::query::Providers) { vtable_methods, type_implements_trait, subst_and_check_impossible_predicates, + mir_abstract_const: |tcx, def_id| { + let def_id = def_id.expect_local(); + if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { + tcx.mir_abstract_const_of_const_arg(def) + } else { + const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) + } + }, + mir_abstract_const_of_const_arg: |tcx, (did, param_did)| { + const_evaluatable::mir_abstract_const( + tcx, + ty::WithOptConstParam { did, const_param_did: Some(param_did) }, + ) + }, + try_unify_abstract_consts: const_evaluatable::try_unify_abstract_consts, ..*providers }; } diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs similarity index 97% rename from src/librustc_trait_selection/traits/object_safety.rs rename to compiler/rustc_trait_selection/src/traits/object_safety.rs index c003e4f806..86fc3cbfea 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -276,7 +276,8 @@ fn predicates_reference_self( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } }) .collect() @@ -310,7 +311,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => false, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => false, } }) } @@ -422,10 +424,17 @@ fn virtual_call_violation_for_method<'tcx>( let param_env = tcx.param_env(method.def_id); - let abi_of_ty = |ty: Ty<'tcx>| -> &Abi { + let abi_of_ty = |ty: Ty<'tcx>| -> Option<&Abi> { match tcx.layout_of(param_env.and(ty)) { - Ok(layout) => &layout.abi, - Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty), + Ok(layout) => Some(&layout.abi), + Err(err) => { + // #78372 + tcx.sess.delay_span_bug( + tcx.def_span(method.def_id), + &format!("error: {}\n while computing layout for type {:?}", err, ty), + ); + None + } } }; @@ -434,7 +443,7 @@ fn virtual_call_violation_for_method<'tcx>( receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id); match abi_of_ty(unit_receiver_ty) { - &Abi::Scalar(..) => (), + Some(Abi::Scalar(..)) => (), abi => { tcx.sess.delay_span_bug( tcx.def_span(method.def_id), @@ -454,13 +463,12 @@ fn virtual_call_violation_for_method<'tcx>( receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id); match abi_of_ty(trait_object_receiver) { - &Abi::ScalarPair(..) => (), + Some(Abi::ScalarPair(..)) => (), abi => { tcx.sess.delay_span_bug( tcx.def_span(method.def_id), &format!( - "receiver when `Self = {}` should have a ScalarPair ABI; \ - found {:?}", + "receiver when `Self = {}` should have a ScalarPair ABI; found {:?}", trait_object_ty, abi ), ); @@ -654,11 +662,7 @@ fn receiver_is_dispatchable<'tcx>( .chain(iter::once(trait_predicate)) .collect(); - ty::ParamEnv::new( - tcx.intern_predicates(&caller_bounds), - param_env.reveal(), - param_env.def_id, - ) + ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal()) }; // Receiver: DispatchFromDyn U]> @@ -732,7 +736,7 @@ fn contains_illegal_self_type_reference<'tcx>( impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { + match t.kind() { ty::Param(_) => t == self.self_ty, ty::Projection(ref data) => { // This is a projected type `::X`. diff --git a/src/librustc_trait_selection/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs similarity index 100% rename from src/librustc_trait_selection/traits/on_unimplemented.rs rename to compiler/rustc_trait_selection/src/traits/on_unimplemented.rs diff --git a/src/librustc_trait_selection/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs similarity index 97% rename from src/librustc_trait_selection/traits/project.rs rename to compiler/rustc_trait_selection/src/traits/project.rs index c788e4f5c9..6ac620b01b 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -345,8 +345,8 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // should occur eventually). let ty = ty.super_fold_with(self); - match ty.kind { - ty::Opaque(def_id, substs) => { + match *ty.kind() { + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty, @@ -908,7 +908,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let tcx = selcx.tcx(); // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. - let bounds = match obligation_trait_ref.self_ty().kind { + let bounds = match *obligation_trait_ref.self_ty().kind() { ty::Projection(ref data) => { tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) } @@ -1000,15 +1000,15 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( }; let eligible = match &impl_source { - super::ImplSourceClosure(_) - | super::ImplSourceGenerator(_) - | super::ImplSourceFnPointer(_) - | super::ImplSourceObject(_) - | super::ImplSourceTraitAlias(_) => { + super::ImplSource::Closure(_) + | super::ImplSource::Generator(_) + | super::ImplSource::FnPointer(_) + | super::ImplSource::Object(_) + | super::ImplSource::TraitAlias(_) => { debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source); true } - super::ImplSourceUserDefined(impl_data) => { + super::ImplSource::UserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in // codegen (i.e., projection mode is not "any"), and the @@ -1060,14 +1060,14 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( } } } - super::ImplSourceDiscriminantKind(..) => { + super::ImplSource::DiscriminantKind(..) => { // While `DiscriminantKind` is automatically implemented for every type, // the concrete discriminant may not be known yet. // // Any type with multiple potential discriminant types is therefore not eligible. let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); - match self_ty.kind { + match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -1100,7 +1100,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Error(_) => false, } } - super::ImplSourceParam(..) => { + super::ImplSource::Param(..) => { // This case tell us nothing about the value of an // associated type. Consider: // @@ -1128,7 +1128,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // in `assemble_candidates_from_param_env`. false } - super::ImplSourceAutoImpl(..) | super::ImplSourceBuiltin(..) => { + super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => { // These traits have no associated types. selcx.tcx().sess.delay_span_bug( obligation.cause.span, @@ -1186,20 +1186,20 @@ fn confirm_select_candidate<'cx, 'tcx>( impl_source: Selection<'tcx>, ) -> Progress<'tcx> { match impl_source { - super::ImplSourceUserDefined(data) => confirm_impl_candidate(selcx, obligation, data), - super::ImplSourceGenerator(data) => confirm_generator_candidate(selcx, obligation, data), - super::ImplSourceClosure(data) => confirm_closure_candidate(selcx, obligation, data), - super::ImplSourceFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), - super::ImplSourceDiscriminantKind(data) => { + super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), + super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data), + super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data), + super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), + super::ImplSource::DiscriminantKind(data) => { confirm_discriminant_kind_candidate(selcx, obligation, data) } - super::ImplSourceObject(_) => { + super::ImplSource::Object(_) => { confirm_object_candidate(selcx, obligation, obligation_trait_ref) } - super::ImplSourceAutoImpl(..) - | super::ImplSourceParam(..) - | super::ImplSourceBuiltin(..) - | super::ImplSourceTraitAlias(..) => + super::ImplSource::AutoImpl(..) + | super::ImplSource::Param(..) + | super::ImplSource::Builtin(..) + | super::ImplSource::TraitAlias(..) => // we don't create Select candidates with this kind of resolution { span_bug!( @@ -1219,8 +1219,8 @@ fn confirm_object_candidate<'cx, 'tcx>( let self_ty = obligation_trait_ref.self_ty(); let object_ty = selcx.infcx().shallow_resolve(self_ty); debug!("confirm_object_candidate(object_ty={:?})", object_ty); - let data = match object_ty.kind { - ty::Dynamic(ref data, ..) => data, + let data = match object_ty.kind() { + ty::Dynamic(data, ..) => data, _ => span_bug!( obligation.cause.span, "confirm_object_candidate called with non-object: {:?}", diff --git a/src/librustc_trait_selection/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs similarity index 99% rename from src/librustc_trait_selection/traits/query/dropck_outlives.rs rename to compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index d07c95270e..424b3bd67f 100644 --- a/src/librustc_trait_selection/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -82,7 +82,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { /// Note also that `needs_drop` requires a "global" type (i.e., one /// with erased regions), but this function does not. pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind { + match ty.kind() { // None of these types have a destructor and hence they do not // require anything in particular to outlive the dtor's // execution. diff --git a/src/librustc_trait_selection/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/evaluate_obligation.rs rename to compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs diff --git a/src/librustc_trait_selection/traits/query/method_autoderef.rs b/compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/method_autoderef.rs rename to compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs diff --git a/src/librustc_trait_selection/traits/query/mod.rs b/compiler/rustc_trait_selection/src/traits/query/mod.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/mod.rs rename to compiler/rustc_trait_selection/src/traits/query/mod.rs diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs similarity index 98% rename from src/librustc_trait_selection/traits/query/normalize.rs rename to compiler/rustc_trait_selection/src/traits/query/normalize.rs index 17963a6c82..c0ae7bf697 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -107,8 +107,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } let ty = ty.super_fold_with(self); - let res = (|| match ty.kind { - ty::Opaque(def_id, substs) => { + let res = (|| match *ty.kind() { + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty, diff --git a/src/librustc_trait_selection/traits/query/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/outlives_bounds.rs rename to compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/ascribe_user_type.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/custom.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/eq.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/implied_outlives_bounds.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/mod.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/normalize.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/outlives.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/subtype.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs similarity index 77% rename from src/librustc_trait_selection/traits/select/candidate_assembly.rs rename to compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 1d5441b8ef..9cb5c23264 100644 --- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -7,14 +7,19 @@ //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly use rustc_hir as hir; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TypeFoldable}; use rustc_target::spec::abi::Abi; +use crate::traits::coherence::Conflict; use crate::traits::{util, SelectionResult}; +use crate::traits::{Overflow, Unimplemented}; use super::BuiltinImplConditions; +use super::IntercrateAmbiguityCause; +use super::OverflowError; use super::SelectionCandidate::{self, *}; -use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack}; +use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack}; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub(super) fn candidate_from_obligation<'o>( @@ -62,6 +67,161 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate } + fn candidate_from_obligation_no_cache<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + if let Some(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"); + // Heuristics: show the diagnostics when there are no candidates in crate. + if let Ok(candidate_set) = self.assemble_candidates(stack) { + let mut no_candidates_apply = true; + + for c in candidate_set.vec.iter() { + if self.evaluate_candidate(stack, &c)?.may_apply() { + no_candidates_apply = false; + break; + } + } + + if !candidate_set.ambiguous && no_candidates_apply { + let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let self_ty = trait_ref.self_ty(); + let (trait_desc, self_desc) = with_no_trimmed_paths(|| { + let trait_desc = trait_ref.print_only_trait_path().to_string(); + let self_desc = if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }; + (trait_desc, self_desc) + }); + let cause = if let Conflict::Upstream = conflict { + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } + } else { + IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + }; + debug!("evaluate_stack: pushing cause = {:?}", cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + } + } + } + return Ok(None); + } + + let candidate_set = self.assemble_candidates(stack)?; + + if candidate_set.ambiguous { + debug!("candidate set contains ambig"); + return Ok(None); + } + + let mut candidates = candidate_set.vec; + + debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + + // At this point, we know that each of the entries in the + // candidate set is *individually* applicable. Now we have to + // figure out if they contain mutual incompatibilities. This + // frequently arises if we have an unconstrained input type -- + // for example, we are looking for `$0: Eq` where `$0` is some + // unconstrained type variable. In that case, we'll get a + // candidate which assumes $0 == int, one that assumes `$0 == + // usize`, etc. This spells an ambiguity. + + // If there is more than one candidate, first winnow them down + // by considering extra conditions (nested obligations and so + // forth). We don't winnow if there is exactly one + // candidate. This is a relatively minor distinction but it + // can lead to better inference and error-reporting. An + // example would be if there was an impl: + // + // impl Vec { fn push_clone(...) { ... } } + // + // and we were to see some code `foo.push_clone()` where `boo` + // is a `Vec` and `Bar` does not implement `Clone`. If + // we were to winnow, we'd wind up with zero candidates. + // Instead, we select the right impl now but report "`Bar` does + // not implement `Clone`". + if candidates.len() == 1 { + return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); + } + + // Winnow, but record the exact outcome of evaluation, which + // is needed for specialization. Propagate overflow if it occurs. + let mut candidates = candidates + .into_iter() + .map(|c| match self.evaluate_candidate(stack, &c) { + Ok(eval) if eval.may_apply() => { + Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) + } + Ok(_) => Ok(None), + Err(OverflowError) => Err(Overflow), + }) + .flat_map(Result::transpose) + .collect::, _>>()?; + + debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + + let needs_infer = stack.obligation.predicate.needs_infer(); + + // If there are STILL multiple candidates, we can further + // reduce the list by dropping duplicates -- including + // resolving specializations. + if candidates.len() > 1 { + let mut i = 0; + while i < candidates.len() { + let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { + self.candidate_should_be_dropped_in_favor_of( + &candidates[i], + &candidates[j], + needs_infer, + ) + }); + if is_dup { + debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + candidates.swap_remove(i); + } else { + debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + i += 1; + + // If there are *STILL* multiple candidates, give up + // and report ambiguity. + if i > 1 { + debug!("multiple matches, ambig"); + return Ok(None); + } + } + } + } + + // If there are *NO* candidates, then there are no impls -- + // that we know of, anyway. Note that in the case where there + // are unbound type variables within the obligation, it might + // be the case that you could still satisfy the obligation + // from another crate by instantiating the type variables with + // a type from another crate that does have an impl. This case + // is checked for in `evaluate_stack` (and hence users + // who might care about this case, like coherence, should use + // that function). + if candidates.is_empty() { + // If there's an error type, 'downgrade' our result from + // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid + // emitting additional spurious errors, since we're guaranteed + // to have emitted at least one. + if stack.obligation.references_error() { + debug!("no results for error type, treating as ambiguous"); + return Ok(None); + } + return Err(Unimplemented); + } + + // Just one candidate left. + self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) + } + pub(super) fn assemble_candidates<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -152,7 +312,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. - match obligation.predicate.skip_binder().trait_ref.self_ty().kind { + match obligation.predicate.skip_binder().trait_ref.self_ty().kind() { ty::Projection(_) | ty::Opaque(..) => {} ty::Infer(ty::TyVar(_)) => { span_bug!( @@ -221,7 +381,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = obligation.self_ty().skip_binder(); - match self_ty.kind { + match self_ty.kind() { ty::Generator(..) => { debug!( "assemble_generator_candidates: self_ty={:?} obligation={:?}", @@ -261,7 +421,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because the substs on closure types never // touch bound regions, they just capture the in-scope // type/region parameters - match obligation.self_ty().skip_binder().kind { + match *obligation.self_ty().skip_binder().kind() { ty::Closure(_, closure_substs) => { debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); match self.infcx.closure_kind(closure_substs) { @@ -300,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because what we are inspecting doesn't involve bound regions. let self_ty = obligation.self_ty().skip_binder(); - match self_ty.kind { + match *self_ty.kind() { ty::Infer(ty::TyVar(_)) => { debug!("assemble_fn_pointer_candidates: ambiguous self-type"); candidates.ambiguous = true; // Could wind up being a fn() type. @@ -382,7 +542,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let def_id = obligation.predicate.def_id(); if self.tcx().trait_is_auto(def_id) { - match self_ty.kind { + match self_ty.kind() { ty::Dynamic(..) => { // For object types, we don't know what the closed // over types are. This means we conservatively @@ -453,7 +613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // self-ty here doesn't escape this probe, so just erase // any LBR. let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); - let poly_trait_ref = match self_ty.kind { + let poly_trait_ref = match self_ty.kind() { ty::Dynamic(ref data, ..) => { if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { debug!( @@ -539,7 +699,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); - let may_apply = match (&source.kind, &target.kind) { + let may_apply = match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { // Upcasts permit two things: diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs similarity index 96% rename from src/librustc_trait_selection/traits/select/confirmation.rs rename to compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3d6eb84513..88b656ce68 100644 --- a/src/librustc_trait_selection/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -19,16 +19,12 @@ use crate::traits::project::{self, normalize_with_depth}; use crate::traits::select::TraitObligationExt; use crate::traits::util; use crate::traits::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use crate::traits::ImplSource; use crate::traits::Normalized; use crate::traits::OutputTypeParameterMismatch; use crate::traits::Selection; use crate::traits::TraitNotObjectSafe; use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation}; -use crate::traits::{ - ImplSourceAutoImpl, ImplSourceBuiltin, ImplSourceClosure, ImplSourceDiscriminantKind, - ImplSourceFnPointer, ImplSourceGenerator, ImplSourceObject, ImplSourceParam, - ImplSourceTraitAlias, ImplSourceUserDefined, -}; use crate::traits::{ ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData, @@ -55,67 +51,67 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); - Ok(ImplSourceBuiltin(data)) + Ok(ImplSource::Builtin(data)) } ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param); - Ok(ImplSourceParam(obligations)) + Ok(ImplSource::Param(obligations)) } ImplCandidate(impl_def_id) => { - Ok(ImplSourceUserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) + Ok(ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) } AutoImplCandidate(trait_def_id) => { let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); - Ok(ImplSourceAutoImpl(data)) + Ok(ImplSource::AutoImpl(data)) } ProjectionCandidate => { self.confirm_projection_candidate(obligation); - Ok(ImplSourceParam(Vec::new())) + Ok(ImplSource::Param(Vec::new())) } ClosureCandidate => { let vtable_closure = self.confirm_closure_candidate(obligation)?; - Ok(ImplSourceClosure(vtable_closure)) + Ok(ImplSource::Closure(vtable_closure)) } GeneratorCandidate => { let vtable_generator = self.confirm_generator_candidate(obligation)?; - Ok(ImplSourceGenerator(vtable_generator)) + Ok(ImplSource::Generator(vtable_generator)) } FnPointerCandidate => { let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(ImplSourceFnPointer(data)) + Ok(ImplSource::FnPointer(data)) } DiscriminantKindCandidate => { - Ok(ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData)) + Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)) } TraitAliasCandidate(alias_def_id) => { let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); - Ok(ImplSourceTraitAlias(data)) + Ok(ImplSource::TraitAlias(data)) } ObjectCandidate => { let data = self.confirm_object_candidate(obligation); - Ok(ImplSourceObject(data)) + Ok(ImplSource::Object(data)) } BuiltinObjectCandidate => { // This indicates something like `Trait + Send: Send`. In this case, we know that // this holds because that's what the object type is telling us, and there's really // no additional obligations to prove and no types in particular to unify, etc. - Ok(ImplSourceParam(Vec::new())) + Ok(ImplSource::Param(Vec::new())) } BuiltinUnsizeCandidate => { let data = self.confirm_builtin_unsize_candidate(obligation)?; - Ok(ImplSourceBuiltin(data)) + Ok(ImplSource::Builtin(data)) } } } @@ -327,8 +323,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // from the object. Have to try to make a broken test case that // results. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let poly_trait_ref = match self_ty.kind { - ty::Dynamic(ref data, ..) => data + let poly_trait_ref = match self_ty.kind() { + ty::Dynamic(data, ..) => data .principal() .unwrap_or_else(|| { span_bug!(obligation.cause.span, "object candidate with no principal") @@ -449,7 +445,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let (generator_def_id, substs) = match self_ty.kind { + let (generator_def_id, substs) = match *self_ty.kind() { ty::Generator(id, substs, _) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), }; @@ -498,7 +494,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let (closure_def_id, substs) = match self_ty.kind { + let (closure_def_id, substs) = match *self_ty.kind() { ty::Closure(id, substs) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), }; @@ -594,7 +590,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); let mut nested = vec![]; - match (&source.kind, &target.kind) { + match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { // See `assemble_candidates_for_unsizing` for more info. @@ -693,7 +689,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Struct` -> `Struct` (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind { + GenericArgKind::Type(ty) => match ty.kind() { ty::Param(p) => Some(p.index), _ => None, }, diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs similarity index 86% rename from src/librustc_trait_selection/traits/select/mod.rs rename to compiler/rustc_trait_selection/src/traits/select/mod.rs index 82f476b463..114dc79c44 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -6,6 +6,7 @@ use self::EvaluationResult::*; use self::SelectionCandidate::*; use super::coherence::{self, Conflict}; +use super::const_evaluatable; use super::project; use super::project::normalize_with_depth_to; use super::util; @@ -32,6 +33,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fast_reject; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{ @@ -448,150 +450,167 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - match obligation.predicate.skip_binders() { - ty::PredicateAtom::Trait(t, _) => { - let t = ty::Binder::bind(t); - debug_assert!(!t.has_escaping_bound_vars()); - let obligation = obligation.with(t); - self.evaluate_trait_predicate_recursively(previous_stack, obligation) - } + ensure_sufficient_stack(|| { + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Trait(t, _) => { + let t = ty::Binder::bind(t); + debug_assert!(!t.has_escaping_bound_vars()); + let obligation = obligation.with(t); + self.evaluate_trait_predicate_recursively(previous_stack, obligation) + } + + ty::PredicateAtom::Subtype(p) => { + let p = ty::Binder::bind(p); + // Does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { + Some(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), + } + } - ty::PredicateAtom::Subtype(p) => { - let p = ty::Binder::bind(p); - // Does this code ever run? - match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Some(Ok(InferOk { mut obligations, .. })) => { + ty::PredicateAtom::WellFormed(arg) => match wf::obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + arg, + obligation.cause.span, + ) { + Some(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), - } - } + }, - ty::PredicateAtom::WellFormed(arg) => match wf::obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_id, - arg, - obligation.cause.span, - ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) + ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => { + // We do not consider region relationships when evaluating trait matches. + Ok(EvaluatedToOkModuloRegions) } - None => Ok(EvaluatedToAmbig), - }, - - ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => { - // We do not consider region relationships when evaluating trait matches. - Ok(EvaluatedToOkModuloRegions) - } - ty::PredicateAtom::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) + ty::PredicateAtom::ObjectSafe(trait_def_id) => { + if self.tcx().is_object_safe(trait_def_id) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } } - } - ty::PredicateAtom::Projection(data) => { - let data = ty::Binder::bind(data); - let project_obligation = obligation.with(data); - match project::poly_project_and_unify_type(self, &project_obligation) { - Ok(Ok(Some(mut subobligations))) => { - self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); - let result = self.evaluate_predicates_recursively( - previous_stack, - subobligations.into_iter(), - ); - if let Some(key) = - ProjectionCacheKey::from_poly_projection_predicate(self, data) - { - self.infcx.inner.borrow_mut().projection_cache().complete(key); + ty::PredicateAtom::Projection(data) => { + let data = ty::Binder::bind(data); + let project_obligation = obligation.with(data); + match project::poly_project_and_unify_type(self, &project_obligation) { + Ok(Ok(Some(mut subobligations))) => { + self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); + let result = self.evaluate_predicates_recursively( + previous_stack, + subobligations.into_iter(), + ); + if let Some(key) = + ProjectionCacheKey::from_poly_projection_predicate(self, data) + { + self.infcx.inner.borrow_mut().projection_cache().complete(key); + } + result } - result + Ok(Ok(None)) => Ok(EvaluatedToAmbig), + // EvaluatedToRecur might also be acceptable here, but use + // Unknown for now because it means that we won't dismiss a + // selection candidate solely because it has a projection + // cycle. This is closest to the previous behavior of + // immediately erroring. + Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown), + Err(_) => Ok(EvaluatedToErr), } - Ok(Ok(None)) => Ok(EvaluatedToAmbig), - // EvaluatedToRecur might also be acceptable here, but use - // Unknown for now because it means that we won't dismiss a - // selection candidate solely because it has a projection - // cycle. This is closest to the previous behavior of - // immediately erroring. - Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown), - Err(_) => Ok(EvaluatedToErr), } - } - ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => { - match self.infcx.closure_kind(closure_substs) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) + ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => { + match self.infcx.closure_kind(closure_substs) { + Some(closure_kind) => { + if closure_kind.extends(kind) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } } + None => Ok(EvaluatedToAmbig), } - None => Ok(EvaluatedToAmbig), } - } - ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { - match self.tcx().const_eval_resolve( - obligation.param_env, - def_id, - substs, - None, - None, - ) { - Ok(_) => Ok(EvaluatedToOk), - Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), - Err(_) => Ok(EvaluatedToErr), + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { + match const_evaluatable::is_const_evaluatable( + self.infcx, + def_id, + substs, + obligation.param_env, + obligation.cause.span, + ) { + Ok(()) => Ok(EvaluatedToOk), + Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), + Err(_) => Ok(EvaluatedToErr), + } } - } - ty::PredicateAtom::ConstEquate(c1, c2) => { - debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2); - - let evaluate = |c: &'tcx ty::Const<'tcx>| { - if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { - self.infcx - .const_eval_resolve( - obligation.param_env, - def, - substs, - promoted, - Some(obligation.cause.span), - ) - .map(|val| ty::Const::from_value(self.tcx(), val, c.ty)) - } else { - Ok(c) - } - }; + ty::PredicateAtom::ConstEquate(c1, c2) => { + debug!( + "evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", + c1, c2 + ); - match (evaluate(c1), evaluate(c2)) { - (Ok(c1), Ok(c2)) => { - match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) { - Ok(_) => Ok(EvaluatedToOk), - Err(_) => Ok(EvaluatedToErr), + let evaluate = |c: &'tcx ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { + self.infcx + .const_eval_resolve( + obligation.param_env, + def, + substs, + promoted, + Some(obligation.cause.span), + ) + .map(|val| ty::Const::from_value(self.tcx(), val, c.ty)) + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self + .infcx() + .at(&obligation.cause, obligation.param_env) + .eq(c1, c2) + { + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr), + } + } + (Err(ErrorHandled::Reported(ErrorReported)), _) + | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), + (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { + span_bug!( + obligation.cause.span(self.tcx()), + "ConstEquate: const_eval_resolve returned an unexpected error" + ) + } + (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + Ok(EvaluatedToAmbig) } - } - (Err(ErrorHandled::Reported(ErrorReported)), _) - | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), - (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!( - obligation.cause.span(self.tcx()), - "ConstEquate: const_eval_resolve returned an unexpected error" - ), - (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { - Ok(EvaluatedToAmbig) } } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for chalk") + } } - } + }) } fn evaluate_trait_predicate_recursively<'o>( @@ -778,14 +797,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if !candidate_set.ambiguous && candidate_set.vec.is_empty() { let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; let self_ty = trait_ref.self_ty(); - let cause = IntercrateAmbiguityCause::DownstreamCrate { - trait_desc: trait_ref.print_only_trait_path().to_string(), - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - }; + let cause = + with_no_trimmed_paths(|| IntercrateAmbiguityCause::DownstreamCrate { + trait_desc: trait_ref.print_only_trait_path().to_string(), + self_desc: if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }, + }); + debug!("evaluate_stack: pushing cause = {:?}", cause); self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); } @@ -1008,158 +1029,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(candidate)) } - fn candidate_from_obligation_no_cache<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if let Some(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"); - // Heuristics: show the diagnostics when there are no candidates in crate. - if let Ok(candidate_set) = self.assemble_candidates(stack) { - let mut no_candidates_apply = true; - - for c in candidate_set.vec.iter() { - if self.evaluate_candidate(stack, &c)?.may_apply() { - no_candidates_apply = false; - break; - } - } - - if !candidate_set.ambiguous && no_candidates_apply { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }; - let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } - } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } - }; - debug!("evaluate_stack: pushing cause = {:?}", cause); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); - } - } - } - return Ok(None); - } - - let candidate_set = self.assemble_candidates(stack)?; - - if candidate_set.ambiguous { - debug!("candidate set contains ambig"); - return Ok(None); - } - - let mut candidates = candidate_set.vec; - - debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - // At this point, we know that each of the entries in the - // candidate set is *individually* applicable. Now we have to - // figure out if they contain mutual incompatibilities. This - // frequently arises if we have an unconstrained input type -- - // for example, we are looking for `$0: Eq` where `$0` is some - // unconstrained type variable. In that case, we'll get a - // candidate which assumes $0 == int, one that assumes `$0 == - // usize`, etc. This spells an ambiguity. - - // If there is more than one candidate, first winnow them down - // by considering extra conditions (nested obligations and so - // forth). We don't winnow if there is exactly one - // candidate. This is a relatively minor distinction but it - // can lead to better inference and error-reporting. An - // example would be if there was an impl: - // - // impl Vec { fn push_clone(...) { ... } } - // - // and we were to see some code `foo.push_clone()` where `boo` - // is a `Vec` and `Bar` does not implement `Clone`. If - // we were to winnow, we'd wind up with zero candidates. - // Instead, we select the right impl now but report "`Bar` does - // not implement `Clone`". - if candidates.len() == 1 { - return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); - } - - // Winnow, but record the exact outcome of evaluation, which - // is needed for specialization. Propagate overflow if it occurs. - let mut candidates = candidates - .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { - Ok(eval) if eval.may_apply() => { - Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) - } - Ok(_) => Ok(None), - Err(OverflowError) => Err(Overflow), - }) - .flat_map(Result::transpose) - .collect::, _>>()?; - - debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - let needs_infer = stack.obligation.predicate.needs_infer(); - - // If there are STILL multiple candidates, we can further - // reduce the list by dropping duplicates -- including - // resolving specializations. - if candidates.len() > 1 { - let mut i = 0; - while i < candidates.len() { - let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { - self.candidate_should_be_dropped_in_favor_of( - &candidates[i], - &candidates[j], - needs_infer, - ) - }); - if is_dup { - debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - candidates.swap_remove(i); - } else { - debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - i += 1; - - // If there are *STILL* multiple candidates, give up - // and report ambiguity. - if i > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - } - } - } - - // If there are *NO* candidates, then there are no impls -- - // that we know of, anyway. Note that in the case where there - // are unbound type variables within the obligation, it might - // be the case that you could still satisfy the obligation - // from another crate by instantiating the type variables with - // a type from another crate that does have an impl. This case - // is checked for in `evaluate_stack` (and hence users - // who might care about this case, like coherence, should use - // that function). - if candidates.is_empty() { - // If there's an error type, 'downgrade' our result from - // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid - // emitting additional spurious errors, since we're guaranteed - // to have emitted at least one. - if stack.obligation.references_error() { - debug!("no results for error type, treating as ambiguous"); - return Ok(None); - } - return Err(Unimplemented); - } - - // Just one candidate left. - self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) - } - fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option { debug!("is_knowable(intercrate={:?})", self.intercrate); @@ -1301,7 +1170,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); let tcx = self.infcx.tcx; - let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind { + let predicates = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { ty::Projection(ref data) => { tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) } @@ -1560,7 +1429,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // NOTE: binder moved to (*) let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - match self_ty.kind { + match self_ty.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) | ty::Int(_) @@ -1615,7 +1484,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { use self::BuiltinImplConditions::{Ambiguous, None, Where}; - match self_ty.kind { + match self_ty.kind() { ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) | ty::FnDef(..) @@ -1689,7 +1558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { - match t.kind { + match *t.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -2124,7 +1993,6 @@ trait TraitObligationExt<'tcx> { } impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { - #[allow(unused_comparisons)] fn derived_cause( &self, variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, diff --git a/src/librustc_trait_selection/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs similarity index 100% rename from src/librustc_trait_selection/traits/specialize/mod.rs rename to compiler/rustc_trait_selection/src/traits/specialize/mod.rs diff --git a/src/librustc_trait_selection/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs similarity index 98% rename from src/librustc_trait_selection/traits/specialize/specialization_graph.rs rename to compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 56b8354d68..c8bcab6efd 100644 --- a/src/librustc_trait_selection/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -3,6 +3,7 @@ use super::OverlapError; use crate::traits; use rustc_hir::def_id::DefId; use rustc_middle::ty::fast_reject::{self, SimplifiedType}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; pub use rustc_middle::traits::specialization_graph::*; @@ -102,7 +103,8 @@ impl ChildrenExt for Children { let trait_ref = overlap.impl_header.trait_ref.unwrap(); let self_ty = trait_ref.self_ty(); - OverlapError { + // FIXME: should postpone string formatting until we decide to actually emit. + with_no_trimmed_paths(|| OverlapError { with_impl: possible_sibling, trait_desc: trait_ref.print_only_trait_path().to_string(), // Only report the `Self` type if it has at least @@ -115,7 +117,7 @@ impl ChildrenExt for Children { }, intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, involves_placeholder: overlap.involves_placeholder, - } + }) }; let report_overlap_error = |overlap: traits::coherence::OverlapResult<'_>, diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs similarity index 99% rename from src/librustc_trait_selection/traits/structural_match.rs rename to compiler/rustc_trait_selection/src/traits/structural_match.rs index 78186a5e8a..4f7fa2c398 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -137,7 +137,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { debug!("Search visiting ty: {:?}", ty); - let (adt_def, substs) = match ty.kind { + let (adt_def, substs) = match *ty.kind() { ty::Adt(adt_def, substs) => (adt_def, substs), ty::Param(_) => { self.found = Some(NonStructuralMatchTy::Param); diff --git a/src/librustc_trait_selection/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs similarity index 100% rename from src/librustc_trait_selection/traits/util.rs rename to compiler/rustc_trait_selection/src/traits/util.rs diff --git a/src/librustc_trait_selection/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs similarity index 96% rename from src/librustc_trait_selection/traits/wf.rs rename to compiler/rustc_trait_selection/src/traits/wf.rs index 0ac3c6ffe6..909cd2aa15 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -7,8 +7,9 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::Span; -use std::rc::Rc; +use std::iter; +use std::rc::Rc; /// Returns the set of obligations needed to make `arg` well-formed. /// If `arg` contains unresolved inference variables, this may include /// further WF obligations. However, if `arg` IS an unresolved @@ -25,7 +26,7 @@ pub fn obligations<'a, 'tcx>( // Handle the "livelock" case (see comment above) by bailing out if necessary. let arg = match arg.unpack() { GenericArgKind::Type(ty) => { - match ty.kind { + match ty.kind() { ty::Infer(ty::TyVar(_)) => { let resolved_ty = infcx.shallow_resolve(ty); if resolved_ty == ty { @@ -127,6 +128,9 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(c1.into()); wf.compute(c2.into()); } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } } wf.normalize() @@ -200,7 +204,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // projection coming from another associated type. See // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and // `traits-assoc-type-in-supertrait-bad.rs`. - if let ty::Projection(projection_ty) = proj.ty.kind { + if let ty::Projection(projection_ty) = proj.ty.kind() { let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id); if let Some(impl_item_span) = items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) @@ -213,7 +217,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // An associated item obligation born out of the `trait` failed to be met. An example // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); - if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = pred.self_ty().kind { + if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind() { if let Some(impl_item_span) = trait_assoc_items .find(|i| i.def_id == item_def_id) .and_then(|trait_assoc_item| { @@ -412,7 +416,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } }; - match ty.kind { + match *ty.kind() { ty::Bool | ty::Char | ty::Int(..) @@ -590,7 +594,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // prevention, which happens before this can be reached. ty::Infer(_) => { let ty = self.infcx.shallow_resolve(ty); - if let ty::Infer(ty::TyVar(_)) = ty.kind { + if let ty::Infer(ty::TyVar(_)) = ty.kind() { // Not yet resolved, but we've made progress. let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::new( @@ -613,13 +617,24 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { def_id: DefId, substs: SubstsRef<'tcx>, ) -> Vec> { - let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs); + let predicates = self.infcx.tcx.predicates_of(def_id); + let mut origins = vec![def_id; predicates.predicates.len()]; + let mut head = predicates; + while let Some(parent) = head.parent { + head = self.infcx.tcx.predicates_of(parent); + origins.extend(iter::repeat(parent).take(head.predicates.len())); + } + + let predicates = predicates.instantiate(self.infcx.tcx, substs); + debug_assert_eq!(predicates.predicates.len(), origins.len()); + predicates .predicates .into_iter() .zip(predicates.spans.into_iter()) - .map(|(pred, span)| { - let cause = self.cause(traits::BindingObligation(def_id, span)); + .zip(origins.into_iter().rev()) + .map(|((pred, span), origin_def_id)| { + let cause = self.cause(traits::BindingObligation(origin_def_id, span)); traits::Obligation::new(cause, self.param_env, pred) }) .filter(|pred| !pred.has_escaping_bound_vars()) diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml new file mode 100644 index 0000000000..6d49571827 --- /dev/null +++ b/compiler/rustc_traits/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_traits" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +chalk-ir = "0.29.0" +chalk-solve = "0.29.0" +chalk-engine = "0.29.0" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_infer = { path = "../rustc_infer" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_traits/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs similarity index 57% rename from src/librustc_traits/chalk/db.rs rename to compiler/rustc_traits/src/chalk/db.rs index 4c8be8eb61..828ee6dea6 100644 --- a/src/librustc_traits/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -8,7 +8,7 @@ use rustc_middle::traits::ChalkRustInterner as RustInterner; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt}; +use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt, TypeFoldable}; use rustc_hir::def_id::DefId; @@ -17,11 +17,13 @@ use rustc_span::symbol::sym; use std::fmt; use std::sync::Arc; -use crate::chalk::lowering::LowerInto; +use crate::chalk::lowering::{self, LowerInto}; +use rustc_ast::ast; pub struct RustIrDatabase<'tcx> { - pub tcx: TyCtxt<'tcx>, - pub interner: RustInterner<'tcx>, + pub(crate) interner: RustInterner<'tcx>, + pub(crate) restatic_placeholder: ty::Region<'tcx>, + pub(crate) reempty_placeholder: ty::Region<'tcx>, } impl fmt::Debug for RustIrDatabase<'_> { @@ -30,6 +32,26 @@ impl fmt::Debug for RustIrDatabase<'_> { } } +impl<'tcx> RustIrDatabase<'tcx> { + fn where_clauses_for( + &self, + def_id: DefId, + bound_vars: SubstsRef<'tcx>, + ) -> Vec>> { + let predicates = self.interner.tcx.predicates_of(def_id).predicates; + let mut regions_substitutor = lowering::RegionsSubstitutor::new( + self.interner.tcx, + self.restatic_placeholder, + self.reempty_placeholder, + ); + predicates + .iter() + .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars)) + .map(|wc| wc.fold_with(&mut regions_substitutor)) + .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect() + } +} + impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'tcx> { fn interner(&self) -> &RustInterner<'tcx> { &self.interner @@ -40,7 +62,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t assoc_type_id: chalk_ir::AssocTypeId>, ) -> Arc>> { let def_id = assoc_type_id.0; - let assoc_item = self.tcx.associated_item(def_id); + let assoc_item = self.interner.tcx.associated_item(def_id); let trait_def_id = match assoc_item.container { AssocItemContainer::TraitContainer(def_id) => def_id, _ => unimplemented!("Not possible??"), @@ -49,16 +71,12 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t AssocKind::Type => {} _ => unimplemented!("Not possible??"), } - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); // FIXME(chalk): this really isn't right I don't think. The functions // for GATs are a bit hard to figure out. Are these supposed to be where // clauses or bounds? - let predicates = self.tcx.predicates_defined_on(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(def_id, bound_vars); Arc::new(chalk_solve::rust_ir::AssociatedTyDatum { trait_id: chalk_ir::TraitId(trait_def_id), @@ -76,16 +94,15 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t trait_id: chalk_ir::TraitId>, ) -> Arc>> { let def_id = trait_id.0; - let trait_def = self.tcx.trait_def(def_id); + let trait_def = self.interner.tcx.trait_def(def_id); - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_defined_on(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + + let where_clauses = self.where_clauses_for(def_id, bound_vars); + let associated_ty_ids: Vec<_> = self + .interner .tcx .associated_items(def_id) .in_definition_order() @@ -93,24 +110,37 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t .map(|i| chalk_ir::AssocTypeId(i.def_id)) .collect(); - let well_known = - if self.tcx.lang_items().sized_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Sized) - } else if self.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Copy) - } else if self.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Clone) - } else if self.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Drop) - } else if self.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Fn) - } else if self.tcx.lang_items().fn_once_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce) - } else if self.tcx.lang_items().fn_mut_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::FnMut) - } else { - None - }; + let well_known = if self.interner.tcx.lang_items().sized_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Sized) + } else if self.interner.tcx.lang_items().copy_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Copy) + } else if self.interner.tcx.lang_items().clone_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Clone) + } else if self.interner.tcx.lang_items().drop_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Drop) + } else if self.interner.tcx.lang_items().fn_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Fn) + } else if self + .interner + .tcx + .lang_items() + .fn_once_trait() + .map(|t| def_id == t) + .unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce) + } else if self + .interner + .tcx + .lang_items() + .fn_mut_trait() + .map(|t| def_id == t) + .unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::FnMut) + } else { + None + }; Arc::new(chalk_solve::rust_ir::TraitDatum { id: trait_id, binders: chalk_ir::Binders::new( @@ -121,7 +151,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t auto: trait_def.has_auto_impl, marker: trait_def.is_marker, upstream: !def_id.is_local(), - fundamental: self.tcx.has_attr(def_id, sym::fundamental), + fundamental: self.interner.tcx.has_attr(def_id, sym::fundamental), non_enumerable: true, coinductive: false, }, @@ -136,45 +166,50 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t ) -> Arc>> { let adt_def = adt_id.0; - let bound_vars = bound_vars_for_item(self.tcx, adt_def.did); + let bound_vars = bound_vars_for_item(self.interner.tcx, adt_def.did); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_of(adt_def.did).predicates; - let where_clauses: Vec<_> = predicates + let where_clauses = self.where_clauses_for(adt_def.did, bound_vars); + + let variants: Vec<_> = adt_def + .variants .iter() - .map(|(wc, _)| wc.subst(self.tcx, bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)) - .collect(); - let fields = match adt_def.adt_kind() { - ty::AdtKind::Struct | ty::AdtKind::Union => { - let variant = adt_def.non_enum_variant(); - variant + .map(|variant| chalk_solve::rust_ir::AdtVariantDatum { + fields: variant .fields .iter() - .map(|field| { - self.tcx - .type_of(field.did) - .subst(self.tcx, bound_vars) - .lower_into(&self.interner) - }) - .collect() - } - // FIXME(chalk): handle enums; force_impl_for requires this - ty::AdtKind::Enum => vec![], - }; - let struct_datum = Arc::new(chalk_solve::rust_ir::AdtDatum { + .map(|field| field.ty(self.interner.tcx, bound_vars).lower_into(&self.interner)) + .collect(), + }) + .collect(); + Arc::new(chalk_solve::rust_ir::AdtDatum { id: adt_id, binders: chalk_ir::Binders::new( binders, - chalk_solve::rust_ir::AdtDatumBound { fields, where_clauses }, + chalk_solve::rust_ir::AdtDatumBound { variants, where_clauses }, ), flags: chalk_solve::rust_ir::AdtFlags { upstream: !adt_def.did.is_local(), fundamental: adt_def.is_fundamental(), phantom_data: adt_def.is_phantom_data(), }, - }); - struct_datum + kind: match adt_def.adt_kind() { + ty::AdtKind::Struct => chalk_solve::rust_ir::AdtKind::Struct, + ty::AdtKind::Union => chalk_solve::rust_ir::AdtKind::Union, + ty::AdtKind::Enum => chalk_solve::rust_ir::AdtKind::Enum, + }, + }) + } + + fn adt_repr( + &self, + adt_id: chalk_ir::AdtId>, + ) -> chalk_solve::rust_ir::AdtRepr { + let adt_def = adt_id.0; + chalk_solve::rust_ir::AdtRepr { + repr_c: adt_def.repr.c(), + repr_packed: adt_def.repr.packed(), + } } fn fn_def_datum( @@ -182,30 +217,25 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t fn_def_id: chalk_ir::FnDefId>, ) -> Arc>> { let def_id = fn_def_id.0; - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_defined_on(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(def_id, bound_vars); - let sig = self.tcx.fn_sig(def_id); - let inputs_and_output = sig.inputs_and_output(); + let sig = self.interner.tcx.fn_sig(def_id); let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars( &self.interner, - self.tcx, - &inputs_and_output, + self.interner.tcx, + &sig.inputs_and_output().subst(self.interner.tcx, bound_vars), ); let argument_types = inputs_and_output[..inputs_and_output.len() - 1] .iter() - .map(|t| t.subst(self.tcx, &bound_vars).lower_into(&self.interner)) + .map(|t| t.subst(self.interner.tcx, &bound_vars).lower_into(&self.interner)) .collect(); let return_type = inputs_and_output[inputs_and_output.len() - 1] - .subst(self.tcx, &bound_vars) + .subst(self.interner.tcx, &bound_vars) .lower_into(&self.interner); let bound = chalk_solve::rust_ir::FnDefDatumBound { @@ -217,7 +247,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t }; Arc::new(chalk_solve::rust_ir::FnDefDatum { id: fn_def_id, - abi: sig.abi(), + sig: sig.lower_into(&self.interner), binders: chalk_ir::Binders::new(binders, bound), }) } @@ -227,17 +257,19 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t impl_id: chalk_ir::ImplId>, ) -> Arc>> { let def_id = impl_id.0; - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let trait_ref = self.tcx.impl_trait_ref(def_id).expect("not an impl"); - let trait_ref = trait_ref.subst(self.tcx, bound_vars); + let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl"); + let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars); + let mut regions_substitutor = lowering::RegionsSubstitutor::new( + self.interner.tcx, + self.restatic_placeholder, + self.reempty_placeholder, + ); + let trait_ref = trait_ref.fold_with(&mut regions_substitutor); - let predicates = self.tcx.predicates_of(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(def_id, bound_vars); let value = chalk_solve::rust_ir::ImplDatumBound { trait_ref: trait_ref.lower_into(&self.interner), @@ -256,6 +288,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t &self, trait_id: chalk_ir::TraitId>, parameters: &[chalk_ir::GenericArg>], + _binders: &chalk_ir::CanonicalVarKinds>, ) -> Vec>> { let def_id = trait_id.0; @@ -263,14 +296,20 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t // require us to be able to interconvert `Ty<'tcx>`, and we're // not there yet. - let all_impls = self.tcx.all_impls(def_id); + let all_impls = self.interner.tcx.all_impls(def_id); let matched_impls = all_impls.filter(|impl_def_id| { use chalk_ir::could_match::CouldMatch; - let trait_ref = self.tcx.impl_trait_ref(*impl_def_id).unwrap(); - let bound_vars = bound_vars_for_item(self.tcx, *impl_def_id); + let trait_ref = self.interner.tcx.impl_trait_ref(*impl_def_id).unwrap(); + let bound_vars = bound_vars_for_item(self.interner.tcx, *impl_def_id); let self_ty = trait_ref.self_ty(); - let self_ty = self_ty.subst(self.tcx, bound_vars); + let self_ty = self_ty.subst(self.interner.tcx, bound_vars); + let mut regions_substitutor = lowering::RegionsSubstitutor::new( + self.interner.tcx, + self.restatic_placeholder, + self.reempty_placeholder, + ); + let self_ty = self_ty.fold_with(&mut regions_substitutor); let lowered_ty = self_ty.lower_into(&self.interner); parameters[0].assert_ty_ref(&self.interner).could_match(&self.interner, &lowered_ty) @@ -283,21 +322,75 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t fn impl_provided_for( &self, auto_trait_id: chalk_ir::TraitId>, - adt_id: chalk_ir::AdtId>, + app_ty: &chalk_ir::ApplicationTy>, ) -> bool { + use chalk_ir::Scalar::*; + use chalk_ir::TypeName::*; + let trait_def_id = auto_trait_id.0; - let adt_def = adt_id.0; - let all_impls = self.tcx.all_impls(trait_def_id); + let all_impls = self.interner.tcx.all_impls(trait_def_id); for impl_def_id in all_impls { - let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); + let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap(); let self_ty = trait_ref.self_ty(); - match self_ty.kind { - ty::Adt(impl_adt_def, _) => { - if impl_adt_def == adt_def { - return true; + let provides = match (self_ty.kind(), app_ty.name) { + (&ty::Adt(impl_adt_def, ..), Adt(id)) => impl_adt_def.did == id.0.did, + (_, AssociatedType(_ty_id)) => { + // FIXME(chalk): See https://github.com/rust-lang/rust/pull/77152#discussion_r494484774 + false + } + (ty::Bool, Scalar(Bool)) => true, + (ty::Char, Scalar(Char)) => true, + (ty::Int(ty1), Scalar(Int(ty2))) => match (ty1, ty2) { + (ast::IntTy::Isize, chalk_ir::IntTy::Isize) + | (ast::IntTy::I8, chalk_ir::IntTy::I8) + | (ast::IntTy::I16, chalk_ir::IntTy::I16) + | (ast::IntTy::I32, chalk_ir::IntTy::I32) + | (ast::IntTy::I64, chalk_ir::IntTy::I64) + | (ast::IntTy::I128, chalk_ir::IntTy::I128) => true, + _ => false, + }, + (ty::Uint(ty1), Scalar(Uint(ty2))) => match (ty1, ty2) { + (ast::UintTy::Usize, chalk_ir::UintTy::Usize) + | (ast::UintTy::U8, chalk_ir::UintTy::U8) + | (ast::UintTy::U16, chalk_ir::UintTy::U16) + | (ast::UintTy::U32, chalk_ir::UintTy::U32) + | (ast::UintTy::U64, chalk_ir::UintTy::U64) + | (ast::UintTy::U128, chalk_ir::UintTy::U128) => true, + _ => false, + }, + (ty::Float(ty1), Scalar(Float(ty2))) => match (ty1, ty2) { + (ast::FloatTy::F32, chalk_ir::FloatTy::F32) + | (ast::FloatTy::F64, chalk_ir::FloatTy::F64) => true, + _ => false, + }, + (&ty::Tuple(..), Tuple(..)) => true, + (&ty::Array(..), Array) => true, + (&ty::Slice(..), Slice) => true, + (&ty::RawPtr(type_and_mut), Raw(mutability)) => { + match (type_and_mut.mutbl, mutability) { + (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true, + (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Not) => true, } } - _ => {} + (&ty::Ref(.., mutability1), Ref(mutability2)) => match (mutability1, mutability2) { + (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true, + (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Not) => true, + }, + (&ty::Opaque(def_id, ..), OpaqueType(opaque_ty_id)) => def_id == opaque_ty_id.0, + (&ty::FnDef(def_id, ..), FnDef(fn_def_id)) => def_id == fn_def_id.0, + (&ty::Str, Str) => true, + (&ty::Never, Never) => true, + (&ty::Closure(def_id, ..), Closure(closure_id)) => def_id == closure_id.0, + (&ty::Foreign(def_id), Foreign(foreign_def_id)) => def_id == foreign_def_id.0, + (&ty::Error(..), Error) => false, + _ => false, + }; + if provides { + return true; } } false @@ -308,7 +401,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t associated_ty_id: chalk_solve::rust_ir::AssociatedTyValueId>, ) -> Arc>> { let def_id = associated_ty_id.0; - let assoc_item = self.tcx.associated_item(def_id); + let assoc_item = self.interner.tcx.associated_item(def_id); let impl_id = match assoc_item.container { AssocItemContainer::TraitContainer(def_id) => def_id, _ => unimplemented!("Not possible??"), @@ -317,9 +410,9 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t AssocKind::Type => {} _ => unimplemented!("Not possible??"), } - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let ty = self.tcx.type_of(def_id); + let ty = self.interner.tcx.type_of(def_id); Arc::new(chalk_solve::rust_ir::AssociatedTyValue { impl_id: chalk_ir::ImplId(impl_id), @@ -346,78 +439,20 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t &self, opaque_ty_id: chalk_ir::OpaqueTyId>, ) -> Arc>> { - let bound_vars = bound_vars_for_item(self.tcx, opaque_ty_id.0); + let bound_vars = bound_vars_for_item(self.interner.tcx, opaque_ty_id.0); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_defined_on(opaque_ty_id.0).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars); let value = chalk_solve::rust_ir::OpaqueTyDatumBound { - bounds: chalk_ir::Binders::new(binders, where_clauses), + bounds: chalk_ir::Binders::new(binders.clone(), vec![]), + where_clauses: chalk_ir::Binders::new(binders, where_clauses), }; Arc::new(chalk_solve::rust_ir::OpaqueTyDatum { opaque_ty_id, - bound: chalk_ir::Binders::new(chalk_ir::VariableKinds::new(&self.interner), value), + bound: chalk_ir::Binders::empty(&self.interner, value), }) } - /// Since Chalk can't handle all Rust types currently, we have to handle - /// some specially for now. Over time, these `Some` returns will change to - /// `None` and eventually this function will be removed. - fn force_impl_for( - &self, - well_known: chalk_solve::rust_ir::WellKnownTrait, - ty: &chalk_ir::TyData>, - ) -> Option { - use chalk_ir::TyData::*; - match well_known { - chalk_solve::rust_ir::WellKnownTrait::Sized => match ty { - Apply(apply) => match apply.name { - chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() { - ty::AdtKind::Struct | ty::AdtKind::Union => None, - ty::AdtKind::Enum => { - let constraint = self.tcx.adt_sized_constraint(adt_def.did); - if !constraint.0.is_empty() { unimplemented!() } else { Some(true) } - } - }, - _ => None, - }, - Dyn(_) - | Alias(_) - | Placeholder(_) - | Function(_) - | InferenceVar(_, _) - | BoundVar(_) => None, - }, - chalk_solve::rust_ir::WellKnownTrait::Copy - | chalk_solve::rust_ir::WellKnownTrait::Clone => match ty { - Apply(apply) => match apply.name { - chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() { - ty::AdtKind::Struct | ty::AdtKind::Union => None, - ty::AdtKind::Enum => { - let constraint = self.tcx.adt_sized_constraint(adt_def.did); - if !constraint.0.is_empty() { unimplemented!() } else { Some(true) } - } - }, - _ => None, - }, - Dyn(_) - | Alias(_) - | Placeholder(_) - | Function(_) - | InferenceVar(_, _) - | BoundVar(_) => None, - }, - chalk_solve::rust_ir::WellKnownTrait::Drop => None, - chalk_solve::rust_ir::WellKnownTrait::Fn => None, - chalk_solve::rust_ir::WellKnownTrait::FnMut => None, - chalk_solve::rust_ir::WellKnownTrait::FnOnce => None, - chalk_solve::rust_ir::WellKnownTrait::Unsize => None, - } - } - fn program_clauses_for_env( &self, environment: &chalk_ir::Environment>, @@ -430,21 +465,24 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t well_known_trait: chalk_solve::rust_ir::WellKnownTrait, ) -> Option>> { use chalk_solve::rust_ir::WellKnownTrait::*; + let lang_items = self.interner.tcx.lang_items(); let def_id = match well_known_trait { - Sized => self.tcx.lang_items().sized_trait(), - Copy => self.tcx.lang_items().copy_trait(), - Clone => self.tcx.lang_items().clone_trait(), - Drop => self.tcx.lang_items().drop_trait(), - Fn => self.tcx.lang_items().fn_trait(), - FnMut => self.tcx.lang_items().fn_mut_trait(), - FnOnce => self.tcx.lang_items().fn_once_trait(), - Unsize => self.tcx.lang_items().unsize_trait(), + Sized => lang_items.sized_trait(), + Copy => lang_items.copy_trait(), + Clone => lang_items.clone_trait(), + Drop => lang_items.drop_trait(), + Fn => lang_items.fn_trait(), + FnMut => lang_items.fn_mut_trait(), + FnOnce => lang_items.fn_once_trait(), + Unsize => lang_items.unsize_trait(), + Unpin => lang_items.unpin_trait(), + CoerceUnsized => lang_items.coerce_unsized_trait(), }; def_id.map(chalk_ir::TraitId) } fn is_object_safe(&self, trait_id: chalk_ir::TraitId>) -> bool { - self.tcx.is_object_safe(trait_id.0) + self.interner.tcx.is_object_safe(trait_id.0) } fn hidden_opaque_type( @@ -452,7 +490,10 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t _id: chalk_ir::OpaqueTyId>, ) -> chalk_ir::Ty> { // FIXME(chalk): actually get hidden ty - self.tcx.mk_ty(ty::Tuple(self.tcx.intern_substs(&[]))).lower_into(&self.interner) + self.interner + .tcx + .mk_ty(ty::Tuple(self.interner.tcx.intern_substs(&[]))) + .lower_into(&self.interner) } fn closure_kind( @@ -460,7 +501,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t _closure_id: chalk_ir::ClosureId>, substs: &chalk_ir::Substitution>, ) -> chalk_solve::rust_ir::ClosureKind { - let kind = &substs.parameters(&self.interner)[substs.len(&self.interner) - 3]; + let kind = &substs.as_slice(&self.interner)[substs.len(&self.interner) - 3]; match kind.assert_ty_ref(&self.interner).data(&self.interner) { chalk_ir::TyData::Apply(apply) => match apply.name { chalk_ir::TypeName::Scalar(scalar) => match scalar { @@ -484,10 +525,10 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t substs: &chalk_ir::Substitution>, ) -> chalk_ir::Binders>> { - let sig = &substs.parameters(&self.interner)[substs.len(&self.interner) - 2]; + let sig = &substs.as_slice(&self.interner)[substs.len(&self.interner) - 2]; match sig.assert_ty_ref(&self.interner).data(&self.interner) { chalk_ir::TyData::Function(f) => { - let substitution = f.substitution.parameters(&self.interner); + let substitution = f.substitution.as_slice(&self.interner); let return_type = substitution.last().unwrap().assert_ty_ref(&self.interner).clone(); // Closure arguments are tupled @@ -506,7 +547,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t }; chalk_ir::Binders::new( - chalk_ir::VariableKinds::from( + chalk_ir::VariableKinds::from_iter( &self.interner, (0..f.num_binders).map(|_| chalk_ir::VariableKind::Lifetime), ), @@ -523,7 +564,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t substs: &chalk_ir::Substitution>, ) -> chalk_ir::Binders>> { let inputs_and_output = self.closure_inputs_and_output(_closure_id, substs); - let tuple = substs.parameters(&self.interner).last().unwrap().assert_ty_ref(&self.interner); + let tuple = substs.as_slice(&self.interner).last().unwrap().assert_ty_ref(&self.interner); inputs_and_output.map_ref(|_| tuple.clone()) } @@ -532,8 +573,8 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t _closure_id: chalk_ir::ClosureId>, substs: &chalk_ir::Substitution>, ) -> chalk_ir::Substitution> { - let substitution = &substs.parameters(&self.interner)[0..substs.len(&self.interner) - 3]; - chalk_ir::Substitution::from(&self.interner, substitution) + let substitution = &substs.as_slice(&self.interner)[0..substs.len(&self.interner) - 3]; + chalk_ir::Substitution::from_iter(&self.interner, substitution) } } @@ -573,7 +614,7 @@ fn binders_for<'tcx>( interner: &RustInterner<'tcx>, bound_vars: SubstsRef<'tcx>, ) -> chalk_ir::VariableKinds> { - chalk_ir::VariableKinds::from( + chalk_ir::VariableKinds::from_iter( interner, bound_vars.iter().map(|arg| match arg.unpack() { ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::VariableKind::Lifetime, diff --git a/src/librustc_traits/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs similarity index 59% rename from src/librustc_traits/chalk/lowering.rs rename to compiler/rustc_traits/src/chalk/lowering.rs index a043fa3f4c..1e1841a57f 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -31,9 +31,7 @@ //! not. To lower anything wrapped in a `Binder`, we first deeply find any bound //! variables from the current `Binder`. -use rustc_middle::traits::{ - ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustInterner as RustInterner, -}; +use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner}; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ @@ -41,10 +39,10 @@ use rustc_middle::ty::{ }; use rustc_span::def_id::DefId; +use chalk_ir::{FnSig, ForeignDefId}; +use rustc_hir::Unsafety; use std::collections::btree_map::{BTreeMap, Entry}; -use chalk_ir::fold::shift::Shift; - /// Essentially an `Into` with a `&RustInterner` parameter crate trait LowerInto<'tcx, T> { /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`. @@ -56,7 +54,13 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution>> for Subst self, interner: &RustInterner<'tcx>, ) -> chalk_ir::Substitution> { - chalk_ir::Substitution::from(interner, self.iter().map(|s| s.lower_into(interner))) + chalk_ir::Substitution::from_iter(interner, self.iter().map(|s| s.lower_into(interner))) + } +} + +impl<'tcx> LowerInto<'tcx, SubstsRef<'tcx>> for &chalk_ir::Substitution> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> SubstsRef<'tcx> { + interner.tcx.mk_substs(self.iter(interner).map(|subst| subst.lower_into(interner))) } } @@ -76,107 +80,51 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment, ) -> chalk_ir::InEnvironment>> { - let clauses = self.environment.into_iter().filter_map(|clause| match clause { - ChalkEnvironmentClause::Predicate(predicate) => { - // FIXME(chalk): forall - match predicate.bound_atom(interner.tcx).skip_binder() { - ty::PredicateAtom::Trait(predicate, _) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - binders, - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::FromEnv( - chalk_ir::FromEnv::Trait( - predicate.trait_ref.lower_into(interner), - ), - ), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ) - } - ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - binders, - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::LifetimeOutlives( - chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }, - ), - ), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ) - } - // FIXME(chalk): need to add TypeOutlives - ty::PredicateAtom::TypeOutlives(_) => None, - ty::PredicateAtom::Projection(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - binders, - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq( - predicate.lower_into(interner), - ), - ), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ) - } - ty::PredicateAtom::WellFormed(..) - | ty::PredicateAtom::ObjectSafe(..) - | ty::PredicateAtom::ClosureKind(..) - | ty::PredicateAtom::Subtype(..) - | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => { - bug!("unexpected predicate {}", predicate) - } + let clauses = self.environment.into_iter().map(|predicate| { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx)); + let consequence = match predicate { + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))) } - } - ChalkEnvironmentClause::TypeFromEnv(ty) => Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - chalk_ir::VariableKinds::new(interner), - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty( - ty.lower_into(interner).shifted_in(interner), - )), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ), + ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv( + chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)), + ), + ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + }), + ), + ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + }), + ), + ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), + ), + ty::PredicateAtom::WellFormed(..) + | ty::PredicateAtom::ObjectSafe(..) + | ty::PredicateAtom::ClosureKind(..) + | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", predicate), + }; + let value = chalk_ir::ProgramClauseImplication { + consequence, + conditions: chalk_ir::Goals::empty(interner), + priority: chalk_ir::ClausePriority::High, + constraints: chalk_ir::Constraints::empty(interner), + }; + chalk_ir::ProgramClauseData(chalk_ir::Binders::new(binders, value)).intern(interner) }); let goal: chalk_ir::GoalData> = self.goal.lower_into(&interner); chalk_ir::InEnvironment { environment: chalk_ir::Environment { - clauses: chalk_ir::ProgramClauses::from(&interner, clauses), + clauses: chalk_ir::ProgramClauses::from_iter(&interner, clauses), }, goal: goal.intern(&interner), } @@ -185,63 +133,52 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predicate<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - // FIXME(chalk): forall - match self.bound_atom(interner.tcx).skip_binder() { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx)); + + let value = match predicate { ty::PredicateAtom::Trait(predicate, _) => { - ty::Binder::bind(predicate).lower_into(interner) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), + )) } ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }), - )) - .intern(interner), - ), - ) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + }), + )) } - // FIXME(chalk): TypeOutlives - ty::PredicateAtom::TypeOutlives(_predicate) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + ty::PredicateAtom::TypeOutlives(predicate) => { + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + }), + )) } ty::PredicateAtom::Projection(predicate) => { - ty::Binder::bind(predicate).lower_into(interner) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), + )) } ty::PredicateAtom::WellFormed(arg) => match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind { + GenericArgKind::Type(ty) => match ty.kind() { // FIXME(chalk): In Chalk, a placeholder is WellFormed if it // `FromEnv`. However, when we "lower" Params, we don't update // the environment. - ty::Placeholder(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)), - - _ => { - let (ty, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &ty::Binder::bind(ty)); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( - chalk_ir::WellFormed::Ty(ty.lower_into(interner)), - )) - .intern(interner), - ), - ) + ty::Placeholder(..) => { + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } + + _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( + chalk_ir::WellFormed::Ty(ty.lower_into(interner)), + )), }, // FIXME(chalk): handle well formed consts GenericArgKind::Const(..) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt), }, @@ -258,9 +195,17 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } - } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal( + chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))), + ), + }; + + chalk_ir::GoalData::Quantified( + chalk_ir::QuantifierKind::ForAll, + chalk_ir::Binders::new(binders, value.intern(interner)), + ) } } @@ -275,25 +220,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::TraitRef>> } } -impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> - for ty::PolyTraitPredicate<'tcx> -{ - fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - let (ty, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::Implemented(ty.trait_ref.lower_into(interner)), - )) - .intern(interner), - ), - ) - } -} - impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq>> for rustc_middle::ty::ProjectionPredicate<'tcx> { @@ -305,25 +231,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq>> } } -impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> - for ty::PolyProjectionPredicate<'tcx> -{ - fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - let (ty, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(ty.lower_into(interner)), - )) - .intern(interner), - ), - ) - } -} - impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty> { use chalk_ir::TyData; @@ -340,7 +247,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { let uint = |i| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Uint(i)), empty()); let float = |f| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Float(f)), empty()); - match self.kind { + match *self.kind() { Bool => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Bool), empty()), Char => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Char), empty()), Int(ty) => match ty { @@ -364,7 +271,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64), }, Adt(def, substs) => apply(struct_ty(def.did), substs.lower_into(interner)), - Foreign(_def_id) => unimplemented!(), + Foreign(def_id) => apply(chalk_ir::TypeName::Foreign(ForeignDefId(def_id)), empty()), Str => apply(chalk_ir::TypeName::Str, empty()), Array(ty, len) => { let value = match len.val { @@ -381,7 +288,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { }; apply( chalk_ir::TypeName::Array, - chalk_ir::Substitution::from( + chalk_ir::Substitution::from_iter( interner, &[ chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner), @@ -415,7 +322,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { }; apply( name, - chalk_ir::Substitution::from( + chalk_ir::Substitution::from_iter( interner, &[ chalk_ir::GenericArgData::Lifetime(region.lower_into(interner)) @@ -432,9 +339,10 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { FnPtr(sig) => { let (inputs_and_outputs, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output()); - TyData::Function(chalk_ir::Fn { + TyData::Function(chalk_ir::FnPointer { num_binders: binders.len(interner), - substitution: chalk_ir::Substitution::from( + sig: sig.lower_into(interner), + substitution: chalk_ir::Substitution::from_iter( interner, inputs_and_outputs.iter().map(|ty| { chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner) @@ -485,6 +393,112 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { } } +impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> Ty<'tcx> { + use chalk_ir::TyData; + use rustc_ast::ast; + + let kind = match self.data(interner) { + TyData::Apply(application_ty) => match application_ty.name { + chalk_ir::TypeName::Adt(struct_id) => { + ty::Adt(struct_id.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Scalar(scalar) => match scalar { + chalk_ir::Scalar::Bool => ty::Bool, + chalk_ir::Scalar::Char => ty::Char, + chalk_ir::Scalar::Int(int_ty) => match int_ty { + chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize), + chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8), + chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16), + chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32), + chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64), + chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128), + }, + chalk_ir::Scalar::Uint(int_ty) => match int_ty { + chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize), + chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8), + chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16), + chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32), + chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64), + chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128), + }, + chalk_ir::Scalar::Float(float_ty) => match float_ty { + chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32), + chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64), + }, + }, + chalk_ir::TypeName::Array => unimplemented!(), + chalk_ir::TypeName::FnDef(id) => { + ty::FnDef(id.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Closure(closure) => { + ty::Closure(closure.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Never => ty::Never, + chalk_ir::TypeName::Tuple(_size) => { + ty::Tuple(application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Slice => ty::Slice( + application_ty.substitution.as_slice(interner)[0] + .ty(interner) + .unwrap() + .lower_into(interner), + ), + chalk_ir::TypeName::Raw(mutbl) => ty::RawPtr(ty::TypeAndMut { + ty: application_ty.substitution.as_slice(interner)[0] + .ty(interner) + .unwrap() + .lower_into(interner), + mutbl: match mutbl { + chalk_ir::Mutability::Mut => ast::Mutability::Mut, + chalk_ir::Mutability::Not => ast::Mutability::Not, + }, + }), + chalk_ir::TypeName::Ref(mutbl) => ty::Ref( + application_ty.substitution.as_slice(interner)[0] + .lifetime(interner) + .unwrap() + .lower_into(interner), + application_ty.substitution.as_slice(interner)[1] + .ty(interner) + .unwrap() + .lower_into(interner), + match mutbl { + chalk_ir::Mutability::Mut => ast::Mutability::Mut, + chalk_ir::Mutability::Not => ast::Mutability::Not, + }, + ), + chalk_ir::TypeName::Str => ty::Str, + chalk_ir::TypeName::OpaqueType(opaque_ty) => { + ty::Opaque(opaque_ty.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::AssociatedType(assoc_ty) => ty::Projection(ty::ProjectionTy { + substs: application_ty.substitution.lower_into(interner), + item_def_id: assoc_ty.0, + }), + chalk_ir::TypeName::Foreign(def_id) => ty::Foreign(def_id.0), + chalk_ir::TypeName::Error => unimplemented!(), + }, + TyData::Placeholder(placeholder) => ty::Placeholder(ty::Placeholder { + universe: ty::UniverseIndex::from_usize(placeholder.ui.counter), + name: ty::BoundVar::from_usize(placeholder.idx), + }), + TyData::Alias(_alias_ty) => unimplemented!(), + TyData::Function(_quantified_ty) => unimplemented!(), + TyData::BoundVar(_bound) => ty::Bound( + ty::DebruijnIndex::from_usize(_bound.debruijn.depth() as usize), + ty::BoundTy { + var: ty::BoundVar::from_usize(_bound.index), + kind: ty::BoundTyKind::Anon, + }, + ), + TyData::InferenceVar(_, _) => unimplemented!(), + TyData::Dyn(_) => unimplemented!(), + }; + interner.tcx.mk_ty(kind) + } +} + impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Lifetime> { use rustc_middle::ty::RegionKind::*; @@ -522,6 +536,59 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'t } } +impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> Region<'tcx> { + let kind = match self.data(interner) { + chalk_ir::LifetimeData::BoundVar(var) => ty::RegionKind::ReLateBound( + ty::DebruijnIndex::from_u32(var.debruijn.depth()), + ty::BoundRegion::BrAnon(var.index as u32), + ), + chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), + chalk_ir::LifetimeData::Placeholder(p) => { + ty::RegionKind::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::from_usize(p.ui.counter), + name: ty::BoundRegion::BrAnon(p.idx as u32), + }) + } + chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(), + }; + interner.tcx.mk_region(kind) + } +} + +impl<'tcx> LowerInto<'tcx, chalk_ir::Const>> for ty::Const<'tcx> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Const> { + let ty = self.ty.lower_into(interner); + let value = match self.val { + ty::ConstKind::Value(val) => { + chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val }) + } + ty::ConstKind::Bound(db, bound) => chalk_ir::ConstValue::BoundVar( + chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::new(db.as_u32()), bound.index()), + ), + _ => unimplemented!("Const not implemented. {:?}", self), + }; + chalk_ir::ConstData { ty, value }.intern(interner) + } +} + +impl<'tcx> LowerInto<'tcx, ty::Const<'tcx>> for &chalk_ir::Const> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> ty::Const<'tcx> { + let data = self.data(interner); + let ty = data.ty.lower_into(interner); + let val = match data.value { + chalk_ir::ConstValue::BoundVar(var) => ty::ConstKind::Bound( + ty::DebruijnIndex::from_u32(var.debruijn.depth()), + ty::BoundVar::from_u32(var.index as u32), + ), + chalk_ir::ConstValue::InferenceVar(_var) => unimplemented!(), + chalk_ir::ConstValue::Placeholder(_p) => unimplemented!(), + chalk_ir::ConstValue::Concrete(c) => ty::ConstKind::Value(c.interned), + }; + ty::Const { ty, val } + } +} + impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg>> for GenericArg<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GenericArg> { match self.unpack() { @@ -531,18 +598,35 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg>> for Generic ty::subst::GenericArgKind::Lifetime(lifetime) => { chalk_ir::GenericArgData::Lifetime(lifetime.lower_into(interner)) } - ty::subst::GenericArgKind::Const(_) => chalk_ir::GenericArgData::Ty( - chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { - name: chalk_ir::TypeName::Tuple(0), - substitution: chalk_ir::Substitution::empty(interner), - }) - .intern(interner), - ), + ty::subst::GenericArgKind::Const(c) => { + chalk_ir::GenericArgData::Const(c.lower_into(interner)) + } } .intern(interner) } } +impl<'tcx> LowerInto<'tcx, ty::subst::GenericArg<'tcx>> + for &chalk_ir::GenericArg> +{ + fn lower_into(self, interner: &RustInterner<'tcx>) -> ty::subst::GenericArg<'tcx> { + match self.data(interner) { + chalk_ir::GenericArgData::Ty(ty) => { + let t: Ty<'tcx> = ty.lower_into(interner); + t.into() + } + chalk_ir::GenericArgData::Lifetime(lifetime) => { + let r: Region<'tcx> = lifetime.lower_into(interner); + r.into() + } + chalk_ir::GenericArgData::Const(c) => { + let c: ty::Const<'tcx> = c.lower_into(interner); + interner.tcx.mk_const(c).into() + } + } + } +} + // We lower into an Option here since there are some predicates which Chalk // doesn't have a representation for yet (as a `WhereClause`), but are so common // that we just are accepting the unsoundness for now. The `Option` will @@ -554,41 +638,39 @@ impl<'tcx> LowerInto<'tcx, Option, ) -> Option>> { - // FIXME(chalk): forall - match self.bound_atom(interner.tcx).skip_binder() { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx)); + let value = match predicate { ty::PredicateAtom::Trait(predicate, _) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some(chalk_ir::Binders::new( - binders, - chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), - )) + Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner))) } ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some(chalk_ir::Binders::new( - binders, - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }), - )) + Some(chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + })) + } + ty::PredicateAtom::TypeOutlives(predicate) => { + Some(chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + })) + } + ty::PredicateAtom::Projection(predicate) => { + Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner))) } - ty::PredicateAtom::TypeOutlives(_predicate) => None, - ty::PredicateAtom::Projection(_predicate) => None, ty::PredicateAtom::WellFormed(_ty) => None, ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", &self), - } + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("unexpected predicate {}", &self) + } + }; + value.map(|value| chalk_ir::Binders::new(binders, value)) } } @@ -601,30 +683,51 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders chalk_ir::Binders>> { let (predicates, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self); + let self_ty = interner.tcx.mk_ty(ty::Bound( + // This is going to be wrapped in a binder + ty::DebruijnIndex::from_usize(1), + ty::BoundTy { var: ty::BoundVar::from_usize(0), kind: ty::BoundTyKind::Anon }, + )); let where_clauses = predicates.into_iter().map(|predicate| match predicate { ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { chalk_ir::Binders::new( - chalk_ir::VariableKinds::new(interner), + chalk_ir::VariableKinds::empty(interner), chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { trait_id: chalk_ir::TraitId(def_id), - substitution: substs.lower_into(interner), + substitution: interner + .tcx + .mk_substs_trait(self_ty, substs) + .lower_into(interner), }), ) } ty::ExistentialPredicate::Projection(_predicate) => unimplemented!(), ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( - chalk_ir::VariableKinds::new(interner), + chalk_ir::VariableKinds::empty(interner), chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { trait_id: chalk_ir::TraitId(def_id), - substitution: chalk_ir::Substitution::empty(interner), + substitution: interner.tcx.mk_substs_trait(self_ty, &[]).lower_into(interner), }), ), }); - let value = chalk_ir::QuantifiedWhereClauses::from(interner, where_clauses); + let value = chalk_ir::QuantifiedWhereClauses::from_iter(interner, where_clauses); chalk_ir::Binders::new(binders, value) } } +impl<'tcx> LowerInto<'tcx, chalk_ir::FnSig>> for ty::Binder> { + fn lower_into(self, _interner: &RustInterner<'_>) -> FnSig> { + chalk_ir::FnSig { + abi: self.abi(), + safety: match self.unsafety() { + Unsafety::Normal => chalk_ir::Safety::Safe, + Unsafety::Unsafe => chalk_ir::Safety::Unsafe, + }, + variadic: self.c_variadic(), + } + } +} + /// To collect bound vars, we have to do two passes. In the first pass, we /// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then /// replace `BrNamed` into `BrAnon`. The two separate passes are important, @@ -662,7 +765,8 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( .or_else(|| bug!("Skipped bound var index: ty={:?}, parameters={:?}", ty, parameters)); }); - let binders = chalk_ir::VariableKinds::from(interner, parameters.into_iter().map(|(_, v)| v)); + let binders = + chalk_ir::VariableKinds::from_iter(interner, parameters.into_iter().map(|(_, v)| v)); (new_ty, binders, named_parameters) } @@ -692,7 +796,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { } fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { + match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { match self.parameters.entry(bound_ty.var.as_u32()) { Entry::Vacant(entry) => { @@ -773,10 +877,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { result } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - t.super_fold_with(self) - } - fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { match r { ty::ReLateBound(index, br) if *index == self.binder_index => match br { @@ -807,16 +907,18 @@ crate struct ParamsSubstitutor<'tcx> { tcx: TyCtxt<'tcx>, binder_index: ty::DebruijnIndex, list: Vec, + next_ty_placeholder: usize, crate params: rustc_data_structures::fx::FxHashMap, crate named_regions: BTreeMap, } impl<'tcx> ParamsSubstitutor<'tcx> { - crate fn new(tcx: TyCtxt<'tcx>) -> Self { + crate fn new(tcx: TyCtxt<'tcx>, next_ty_placeholder: usize) -> Self { ParamsSubstitutor { tcx, binder_index: ty::INNERMOST, list: vec![], + next_ty_placeholder, params: rustc_data_structures::fx::FxHashMap::default(), named_regions: BTreeMap::default(), } @@ -836,19 +938,19 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match *t.kind() { // FIXME(chalk): currently we convert params to placeholders starting at // index `0`. To support placeholders, we'll actually need to do a // first pass to collect placeholders. Then we can insert params after. ty::Placeholder(_) => unimplemented!(), ty::Param(param) => match self.list.iter().position(|r| r == ¶m) { - Some(_idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { + Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::from_usize(0), - name: ty::BoundVar::from_usize(_idx), + name: ty::BoundVar::from_usize(idx), })), None => { self.list.push(param); - let idx = self.list.len() - 1; + let idx = self.list.len() - 1 + self.next_ty_placeholder; self.params.insert(idx, param); self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::from_usize(0), @@ -884,3 +986,83 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { } } } + +/// Used to collect `Placeholder`s. +crate struct PlaceholdersCollector { + universe_index: ty::UniverseIndex, + crate next_ty_placeholder: usize, + crate next_anon_region_placeholder: u32, +} + +impl PlaceholdersCollector { + crate fn new() -> Self { + PlaceholdersCollector { + universe_index: ty::UniverseIndex::ROOT, + next_ty_placeholder: 0, + next_anon_region_placeholder: 0, + } + } +} + +impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.kind() { + ty::Placeholder(p) if p.universe == self.universe_index => { + self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1); + } + + _ => (), + }; + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: Region<'tcx>) -> bool { + match r { + ty::RePlaceholder(p) if p.universe == self.universe_index => { + if let ty::BoundRegion::BrAnon(anon) = p.name { + self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon); + } + } + + _ => (), + }; + + r.super_visit_with(self) + } +} + +/// Used to substitute specific `Regions`s with placeholders. +crate struct RegionsSubstitutor<'tcx> { + tcx: TyCtxt<'tcx>, + restatic_placeholder: ty::Region<'tcx>, + reempty_placeholder: ty::Region<'tcx>, +} + +impl<'tcx> RegionsSubstitutor<'tcx> { + crate fn new( + tcx: TyCtxt<'tcx>, + restatic_placeholder: ty::Region<'tcx>, + reempty_placeholder: ty::Region<'tcx>, + ) -> Self { + RegionsSubstitutor { tcx, restatic_placeholder, reempty_placeholder } + } +} + +impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { + match r { + ty::ReStatic => self.restatic_placeholder, + ty::ReEmpty(ui) => { + assert_eq!(ui.as_usize(), 0); + self.reempty_placeholder + } + + _ => r.super_fold_with(self), + } + } +} diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs new file mode 100644 index 0000000000..63c5b88435 --- /dev/null +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -0,0 +1,159 @@ +//! Calls `chalk-solve` to solve a `ty::Predicate` +//! +//! In order to call `chalk-solve`, this file must convert a `CanonicalChalkEnvironmentAndGoal` into +//! a Chalk uncanonical goal. It then calls Chalk, and converts the answer back into rustc solution. + +crate mod db; +crate mod lowering; + +use rustc_data_structures::fx::FxHashMap; + +use rustc_index::vec::IndexVec; + +use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; +use rustc_middle::traits::ChalkRustInterner; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::subst::GenericArg; +use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable}; + +use rustc_infer::infer::canonical::{ + Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, +}; +use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal}; + +use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase; +use crate::chalk::lowering::{ + LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor, +}; + +use chalk_solve::Solution; + +crate fn provide(p: &mut Providers) { + *p = Providers { evaluate_goal, ..*p }; +} + +crate fn evaluate_goal<'tcx>( + tcx: TyCtxt<'tcx>, + obligation: CanonicalChalkEnvironmentAndGoal<'tcx>, +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> { + let interner = ChalkRustInterner { tcx }; + + // Chalk doesn't have a notion of `Params`, so instead we use placeholders. + let mut placeholders_collector = PlaceholdersCollector::new(); + obligation.visit_with(&mut placeholders_collector); + + let restatic_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder), + })); + let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder + 1), + })); + + let mut params_substitutor = + ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder); + let obligation = obligation.fold_with(&mut params_substitutor); + // FIXME(chalk): we really should be substituting these back in the solution + let _params: FxHashMap = params_substitutor.params; + + let mut regions_substitutor = + RegionsSubstitutor::new(tcx, restatic_placeholder, reempty_placeholder); + let obligation = obligation.fold_with(&mut regions_substitutor); + + let max_universe = obligation.max_universe.index(); + + let lowered_goal: chalk_ir::UCanonical< + chalk_ir::InEnvironment>>, + > = chalk_ir::UCanonical { + canonical: chalk_ir::Canonical { + binders: chalk_ir::CanonicalVarKinds::from_iter( + &interner, + obligation.variables.iter().map(|v| match v.kind { + CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(), + CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(), + CanonicalVarKind::Ty(ty) => match ty { + CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new( + chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General), + chalk_ir::UniverseIndex { counter: ui.index() }, + ), + CanonicalTyVarKind::Int => chalk_ir::WithKind::new( + chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Integer), + chalk_ir::UniverseIndex::root(), + ), + CanonicalTyVarKind::Float => chalk_ir::WithKind::new( + chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Float), + chalk_ir::UniverseIndex::root(), + ), + }, + CanonicalVarKind::Region(ui) => chalk_ir::WithKind::new( + chalk_ir::VariableKind::Lifetime, + chalk_ir::UniverseIndex { counter: ui.index() }, + ), + CanonicalVarKind::Const(_ui) => unimplemented!(), + CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(), + }), + ), + value: obligation.value.lower_into(&interner), + }, + universes: max_universe + 1, + }; + + use chalk_solve::Solver; + let mut solver = chalk_engine::solve::SLGSolver::new(32, None); + let db = ChalkRustIrDatabase { interner, restatic_placeholder, reempty_placeholder }; + let solution = chalk_solve::logging::with_tracing_logs(|| solver.solve(&db, &lowered_goal)); + + // Ideally, the code to convert *back* to rustc types would live close to + // the code to convert *from* rustc types. Right now though, we don't + // really need this and so it's really minimal. + // Right now, we also treat a `Unique` solution the same as + // `Ambig(Definite)`. This really isn't right. + let make_solution = |subst: chalk_ir::Substitution<_>| { + let mut var_values: IndexVec> = IndexVec::new(); + subst.as_slice(&interner).iter().for_each(|p| { + var_values.push(p.lower_into(&interner)); + }); + let sol = Canonical { + max_universe: ty::UniverseIndex::from_usize(0), + variables: obligation.variables.clone(), + value: QueryResponse { + var_values: CanonicalVarValues { var_values }, + region_constraints: QueryRegionConstraints::default(), + certainty: Certainty::Proven, + value: (), + }, + }; + tcx.arena.alloc(sol) + }; + solution + .map(|s| match s { + Solution::Unique(subst) => { + // FIXME(chalk): handle constraints + make_solution(subst.value.subst) + } + Solution::Ambig(guidance) => { + match guidance { + chalk_solve::Guidance::Definite(subst) => make_solution(subst.value), + chalk_solve::Guidance::Suggested(_) => unimplemented!(), + chalk_solve::Guidance::Unknown => { + // chalk_fulfill doesn't use the var_values here, so + // let's just ignore that + let sol = Canonical { + max_universe: ty::UniverseIndex::from_usize(0), + variables: obligation.variables.clone(), + value: QueryResponse { + var_values: CanonicalVarValues { var_values: IndexVec::new() } + .make_identity(tcx), + region_constraints: QueryRegionConstraints::default(), + certainty: Certainty::Ambiguous, + value: (), + }, + }; + &*tcx.arena.alloc(sol) + } + } + } + }) + .ok_or(traits::query::NoSolution) +} diff --git a/src/librustc_traits/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs similarity index 99% rename from src/librustc_traits/dropck_outlives.rs rename to compiler/rustc_traits/src/dropck_outlives.rs index ce00060b9b..3ee391d6dc 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -112,7 +112,7 @@ fn dropck_outlives<'tcx>( debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); - match ty.kind { + match ty.kind() { // All parameters live for the duration of the // function. ty::Param(..) => {} @@ -172,7 +172,7 @@ fn dtorck_constraint_for_ty<'tcx>( return Ok(()); } - match ty.kind { + match ty.kind() { ty::Bool | ty::Char | ty::Int(_) diff --git a/src/librustc_traits/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs similarity index 100% rename from src/librustc_traits/evaluate_obligation.rs rename to compiler/rustc_traits/src/evaluate_obligation.rs diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs similarity index 98% rename from src/librustc_traits/implied_outlives_bounds.rs rename to compiler/rustc_traits/src/implied_outlives_bounds.rs index de3096eac9..79308b032e 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -103,7 +103,8 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => vec![], + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => vec![], ty::PredicateAtom::WellFormed(arg) => { wf_args.push(arg); vec![] diff --git a/src/librustc_traits/lib.rs b/compiler/rustc_traits/src/lib.rs similarity index 97% rename from src/librustc_traits/lib.rs rename to compiler/rustc_traits/src/lib.rs index 6fea4732dd..d0b05beb4e 100644 --- a/src/librustc_traits/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -4,7 +4,6 @@ #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(or_patterns)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs similarity index 95% rename from src/librustc_traits/normalize_erasing_regions.rs rename to compiler/rustc_traits/src/normalize_erasing_regions.rs index 83aee31a39..3e7c9ac62e 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -49,6 +49,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => true, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => true, } } diff --git a/src/librustc_traits/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs similarity index 100% rename from src/librustc_traits/normalize_projection_ty.rs rename to compiler/rustc_traits/src/normalize_projection_ty.rs diff --git a/src/librustc_traits/type_op.rs b/compiler/rustc_traits/src/type_op.rs similarity index 100% rename from src/librustc_traits/type_op.rs rename to compiler/rustc_traits/src/type_op.rs diff --git a/compiler/rustc_ty/Cargo.toml b/compiler/rustc_ty/Cargo.toml new file mode 100644 index 0000000000..acb011b2dc --- /dev/null +++ b/compiler/rustc_ty/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ty" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_infer = { path = "../rustc_infer" } +rustc_span = { path = "../rustc_span" } +rustc_session = { path = "../rustc_session" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_ty/common_traits.rs b/compiler/rustc_ty/src/common_traits.rs similarity index 100% rename from src/librustc_ty/common_traits.rs rename to compiler/rustc_ty/src/common_traits.rs diff --git a/src/librustc_ty/instance.rs b/compiler/rustc_ty/src/instance.rs similarity index 93% rename from src/librustc_ty/instance.rs rename to compiler/rustc_ty/src/instance.rs index d0bd88af1f..220f4cec74 100644 --- a/src/librustc_ty/instance.rs +++ b/compiler/rustc_ty/src/instance.rs @@ -53,7 +53,7 @@ fn inner_resolve_instance<'tcx>( let ty = tcx.type_of(def.def_id_for_type_of()); let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); - let def = match item_type.kind { + let def = match *item_type.kind() { ty::FnDef(..) if { let f = item_type.fn_sig(tcx); @@ -68,7 +68,7 @@ fn inner_resolve_instance<'tcx>( if ty.needs_drop(tcx, param_env) { debug!(" => nontrivial drop glue"); - match ty.kind { + match *ty.kind() { ty::Closure(..) | ty::Generator(..) | ty::Tuple(..) @@ -119,9 +119,9 @@ fn resolve_associated_item<'tcx>( // Now that we know which impl is being used, we can dispatch to // the actual function: Ok(match vtbl { - traits::ImplSourceUserDefined(impl_data) => { + traits::ImplSource::UserDefined(impl_data) => { debug!( - "resolving ImplSourceUserDefined: {:?}, {:?}, {:?}, {:?}", + "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}", param_env, trait_item, rcvr_substs, impl_data ); assert!(!rcvr_substs.needs_infer()); @@ -216,13 +216,13 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new(leaf_def.item.def_id, substs)) } - traits::ImplSourceGenerator(generator_data) => Some(Instance { + traits::ImplSource::Generator(generator_data) => Some(Instance { def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( generator_data.generator_def_id, )), substs: generator_data.substs, }), - traits::ImplSourceClosure(closure_data) => { + traits::ImplSource::Closure(closure_data) => { let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); Some(Instance::resolve_closure( tcx, @@ -231,18 +231,18 @@ fn resolve_associated_item<'tcx>( trait_closure_kind, )) } - traits::ImplSourceFnPointer(ref data) => match data.fn_ty.kind { + traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() { ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), substs: rcvr_substs, }), _ => None, }, - traits::ImplSourceObject(ref data) => { + traits::ImplSource::Object(ref data) => { let index = traits::get_vtable_index_of_object_method(tcx, data, def_id); Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) } - traits::ImplSourceBuiltin(..) => { + traits::ImplSource::Builtin(..) => { if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() { // FIXME(eddyb) use lang items for methods instead of names. let name = tcx.item_name(def_id); @@ -250,7 +250,7 @@ fn resolve_associated_item<'tcx>( let self_ty = trait_ref.self_ty(); let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env); - match self_ty.kind { + match self_ty.kind() { _ if is_copy => (), ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {} _ => return Ok(None), @@ -271,10 +271,10 @@ fn resolve_associated_item<'tcx>( None } } - traits::ImplSourceAutoImpl(..) - | traits::ImplSourceParam(..) - | traits::ImplSourceTraitAlias(..) - | traits::ImplSourceDiscriminantKind(..) => None, + traits::ImplSource::AutoImpl(..) + | traits::ImplSource::Param(..) + | traits::ImplSource::TraitAlias(..) + | traits::ImplSource::DiscriminantKind(..) => None, }) } diff --git a/src/librustc_ty/lib.rs b/compiler/rustc_ty/src/lib.rs similarity index 84% rename from src/librustc_ty/lib.rs rename to compiler/rustc_ty/src/lib.rs index 6e9042d1ba..904c0062a9 100644 --- a/src/librustc_ty/lib.rs +++ b/compiler/rustc_ty/src/lib.rs @@ -4,8 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(bool_to_option)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/src/librustc_ty/needs_drop.rs b/compiler/rustc_ty/src/needs_drop.rs similarity index 98% rename from src/librustc_ty/needs_drop.rs rename to compiler/rustc_ty/src/needs_drop.rs index c4af95205f..0356bcec54 100644 --- a/src/librustc_ty/needs_drop.rs +++ b/compiler/rustc_ty/src/needs_drop.rs @@ -90,7 +90,7 @@ where }; for component in components { - match component.kind { + match *component.kind() { _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (), ty::Closure(_, substs) => { @@ -106,7 +106,7 @@ where } let witness = substs.witness(); - let interior_tys = match &witness.kind { + let interior_tys = match witness.kind() { ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), _ => { tcx.sess.delay_span_bug( diff --git a/src/librustc_ty/ty.rs b/compiler/rustc_ty/src/ty.rs similarity index 79% rename from src/librustc_ty/ty.rs rename to compiler/rustc_ty/src/ty.rs index 0f1dee7e2e..c4b6b64339 100644 --- a/src/librustc_ty/ty.rs +++ b/compiler/rustc_ty/src/ty.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -5,7 +6,9 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_infer::traits::util; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{ + self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness, +}; use rustc_session::CrateDisambiguator; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -18,7 +21,7 @@ fn sized_constraint_for_ty<'tcx>( ) -> Vec> { use ty::TyKind::*; - let result = match ty.kind { + let result = match ty.kind() { Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![], @@ -245,7 +248,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { } // Compute the bounds on Self and the type parameters. - let ty::InstantiatedPredicates { predicates, .. } = + let ty::InstantiatedPredicates { mut predicates, .. } = tcx.predicates_of(def_id).instantiate_identity(tcx); // Finally, we have to normalize the bounds in the environment, in @@ -260,11 +263,13 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // are any errors at that point, so after type checking you can be // sure that this will succeed without errors anyway. - let unnormalized_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - traits::Reveal::UserFacing, - tcx.sess.opts.debugging_opts.chalk.then_some(def_id), - ); + if tcx.sess.opts.debugging_opts.chalk { + let environment = well_formed_types_in_env(tcx, def_id); + predicates.extend(environment); + } + + let unnormalized_env = + ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing); let body_id = def_id .as_local() @@ -276,6 +281,122 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) } +/// Elaborate the environment. +/// +/// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s +/// that are assumed to be well-formed (because they come from the environment). +/// +/// Used only in chalk mode. +fn well_formed_types_in_env<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> &'tcx ty::List> { + use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind}; + use rustc_middle::ty::subst::GenericArgKind; + + debug!("environment(def_id = {:?})", def_id); + + // The environment of an impl Trait type is its defining function's environment. + if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { + return well_formed_types_in_env(tcx, parent); + } + + // Compute the bounds on `Self` and the type parameters. + let ty::InstantiatedPredicates { predicates, .. } = + tcx.predicates_of(def_id).instantiate_identity(tcx); + + let clauses = predicates.into_iter(); + + if !def_id.is_local() { + return ty::List::empty(); + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let node = tcx.hir().get(hir_id); + + enum NodeKind { + TraitImpl, + InherentImpl, + Fn, + Other, + }; + + let node_kind = match node { + Node::TraitItem(item) => match item.kind { + TraitItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + Node::ImplItem(item) => match item.kind { + ImplItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + Node::Item(item) => match item.kind { + ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl, + ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl, + ItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + Node::ForeignItem(item) => match item.kind { + ForeignItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + // FIXME: closures? + _ => NodeKind::Other, + }; + + // FIXME(eddyb) isn't the unordered nature of this a hazard? + let mut inputs = FxIndexSet::default(); + + match node_kind { + // In a trait impl, we assume that the header trait ref and all its + // constituents are well-formed. + NodeKind::TraitImpl => { + let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl"); + + // FIXME(chalk): this has problems because of late-bound regions + //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk())); + inputs.extend(trait_ref.substs.iter()); + } + + // In an inherent impl, we assume that the receiver type and all its + // constituents are well-formed. + NodeKind::InherentImpl => { + let self_ty = tcx.type_of(def_id); + inputs.extend(self_ty.walk()); + } + + // In an fn, we assume that the arguments and all their constituents are + // well-formed. + NodeKind::Fn => { + let fn_sig = tcx.fn_sig(def_id); + let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); + + inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); + } + + NodeKind::Other => (), + } + let input_clauses = inputs.into_iter().filter_map(|arg| { + match arg.unpack() { + GenericArgKind::Type(ty) => { + let binder = Binder::dummy(PredicateAtom::TypeWellFormedFromEnv(ty)); + Some(tcx.mk_predicate(PredicateKind::ForAll(binder))) + } + + // FIXME(eddyb) no WF conditions from lifetimes? + GenericArgKind::Lifetime(_) => None, + + // FIXME(eddyb) support const generics in Chalk + GenericArgKind::Const(_) => None, + } + }); + + tcx.mk_predicates(clauses.chain(input_clauses)) +} + fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { tcx.param_env(def_id).with_reveal_all_normalized(tcx) } @@ -344,7 +465,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 { + let self_ty_matches = match self_ty.kind() { ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(), _ => false, }; @@ -398,21 +519,21 @@ fn associated_type_projection_predicates( let pred = obligation.predicate; match pred.skip_binders() { ty::PredicateAtom::Trait(tr, _) => { - if let ty::Projection(p) = tr.self_ty().kind { + if let ty::Projection(p) = *tr.self_ty().kind() { if p == assoc_item_ty { return Some(pred); } } } ty::PredicateAtom::Projection(proj) => { - if let ty::Projection(p) = proj.projection_ty.self_ty().kind { + if let ty::Projection(p) = *proj.projection_ty.self_ty().kind() { if p == assoc_item_ty { return Some(pred); } } } ty::PredicateAtom::TypeOutlives(outlives) => { - if let ty::Projection(p) = outlives.0.kind { + if let ty::Projection(p) = *outlives.0.kind() { if p == assoc_item_ty { return Some(pred); } @@ -449,14 +570,15 @@ fn opaque_type_projection_predicates( let pred = obligation.predicate; match pred.skip_binders() { ty::PredicateAtom::Trait(tr, _) => { - if let ty::Opaque(opaque_def_id, opaque_substs) = tr.self_ty().kind { + if let ty::Opaque(opaque_def_id, opaque_substs) = *tr.self_ty().kind() { if opaque_def_id == def_id && opaque_substs == substs { return Some(pred); } } } ty::PredicateAtom::Projection(proj) => { - if let ty::Opaque(opaque_def_id, opaque_substs) = proj.projection_ty.self_ty().kind + if let ty::Opaque(opaque_def_id, opaque_substs) = + *proj.projection_ty.self_ty().kind() { if opaque_def_id == def_id && opaque_substs == substs { return Some(pred); @@ -464,7 +586,7 @@ fn opaque_type_projection_predicates( } } ty::PredicateAtom::TypeOutlives(outlives) => { - if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.0.kind { + if let ty::Opaque(opaque_def_id, opaque_substs) = *outlives.0.kind() { if opaque_def_id == def_id && opaque_substs == substs { return Some(pred); } diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml new file mode 100644 index 0000000000..e3ba0bea7e --- /dev/null +++ b/compiler/rustc_typeck/Cargo.toml @@ -0,0 +1,28 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_typeck" +version = "0.0.0" +edition = "2018" + +[lib] +test = false +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +tracing = "0.1" +rustc_macros = { path = "../rustc_macros" } +rustc_middle = { path = "../rustc_middle" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_target = { path = "../rustc_target" } +rustc_session = { path = "../rustc_session" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_typeck/README.md b/compiler/rustc_typeck/README.md similarity index 100% rename from src/librustc_typeck/README.md rename to compiler/rustc_typeck/README.md diff --git a/src/librustc_typeck/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs similarity index 100% rename from src/librustc_typeck/astconv/errors.rs rename to compiler/rustc_typeck/src/astconv/errors.rs diff --git a/src/librustc_typeck/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs similarity index 90% rename from src/librustc_typeck/astconv/generics.rs rename to compiler/rustc_typeck/src/astconv/generics.rs index 84dab6de95..b54de1d091 100644 --- a/src/librustc_typeck/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -1,8 +1,9 @@ use crate::astconv::{ AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, }; +use crate::errors::AssocTypeBindingNotAllowed; use rustc_ast::ast::ParamKindOrd; -use rustc_errors::{pluralize, struct_span_err, DiagnosticId, ErrorReported}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{GenericArg, GenericArgs}; @@ -367,7 +368,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if position != GenericArgPosition::Type && !args.bindings.is_empty() { - Self::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); + AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); } let explicit_late_bound = @@ -392,7 +393,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if silent { - return Err(true); + return Err((0i32, None)); } // Unfortunately lifetime and type parameter mismatches are typically styled @@ -441,16 +442,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { for span in spans { err.span_label(span, label.as_str()); } - err.emit(); - Err(true) + assert_ne!(bound, provided); + Err((bound as i32 - provided as i32, Some(err))) }; - let mut arg_count_correct = Ok(()); let mut unexpected_spans = vec![]; + let mut lifetime_count_correct = Ok(()); if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { - arg_count_correct = check_kind_count( + lifetime_count_correct = check_kind_count( "lifetime", param_counts.lifetimes, param_counts.lifetimes, @@ -458,12 +459,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { 0, &mut unexpected_spans, explicit_late_bound == ExplicitLateBound::Yes, - ) - .and(arg_count_correct); + ); } + // FIXME(const_generics:defaults) + let mut const_count_correct = Ok(()); if !infer_args || arg_counts.consts > param_counts.consts { - arg_count_correct = check_kind_count( + const_count_correct = check_kind_count( "const", param_counts.consts, param_counts.consts, @@ -471,13 +473,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.lifetimes + arg_counts.types, &mut unexpected_spans, false, - ) - .and(arg_count_correct); + ); } + // Note that type errors are currently be emitted *after* const errors. + let mut type_count_correct = Ok(()); if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize { - arg_count_correct = check_kind_count( + type_count_correct = check_kind_count( "type", param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, @@ -485,14 +488,54 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.lifetimes, &mut unexpected_spans, false, - ) - .and(arg_count_correct); + ); + } + + // Emit a help message if it's possible that a type could be surrounded in braces + if let Err((c_mismatch, Some(ref mut _const_err))) = const_count_correct { + if let Err((_, Some(ref mut type_err))) = type_count_correct { + let possible_matches = args.args[arg_counts.lifetimes..] + .iter() + .filter(|arg| { + matches!( + arg, + GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }) + ) + }) + .take(c_mismatch.max(0) as usize); + for arg in possible_matches { + let suggestions = vec![ + (arg.span().shrink_to_lo(), String::from("{ ")), + (arg.span().shrink_to_hi(), String::from(" }")), + ]; + type_err.multipart_suggestion( + "If this generic argument was intended as a const parameter, \ + try surrounding it with braces:", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } } + let emit_correct = + |correct: Result<(), (_, Option>)>| match correct { + Ok(()) => Ok(()), + Err((_, None)) => Err(()), + Err((_, Some(mut err))) => { + err.emit(); + Err(()) + } + }; + + let arg_count_correct = emit_correct(lifetime_count_correct) + .and(emit_correct(const_count_correct)) + .and(emit_correct(type_count_correct)); + GenericArgCountResult { explicit_late_bound, - correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { - reported: if reported_err { Some(ErrorReported) } else { None }, + correct: arg_count_correct.map_err(|()| GenericArgCountMismatch { + reported: Some(ErrorReported), invalid_args: unexpected_spans, }), } @@ -544,13 +587,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Emits an error regarding forbidden type binding associations pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) { - let mut err = struct_span_err!( - tcx.sess, - span, - E0229, - "associated type bindings are not allowed here" - ); - err.span_label(span, "associated type not allowed here").emit(); + tcx.sess.emit_err(AssocTypeBindingNotAllowed { span }); } /// Prohibits explicit lifetime arguments if late-bound lifetime parameters diff --git a/src/librustc_typeck/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs similarity index 97% rename from src/librustc_typeck/astconv/mod.rs rename to compiler/rustc_typeck/src/astconv/mod.rs index 80dd26e915..46b8b2e14c 100644 --- a/src/librustc_typeck/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -7,6 +7,10 @@ mod generics; use crate::bounds::Bounds; use crate::collect::PlaceholderHirTyCollector; +use crate::errors::{ + AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, + TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified, +}; use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; use rustc_ast::util::lev_distance::find_best_match_for_name; @@ -356,7 +360,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { self.ast_region_to_region(<, Some(param)).into() } - (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + (GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { + if *has_default { + tcx.check_optional_stability( + param.def_id, + Some(arg.id()), + arg.span(), + |_, _| { + // Default generic parameters may not be marked + // with stability attributes, i.e. when the + // default parameter was defined at the same time + // as the rest of the type. As such, we ignore missing + // stability attributes. + }, + ) + } if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { inferred_params.push(ty.span); tcx.ty_error().into() @@ -684,14 +702,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if unbound.is_none() { unbound = Some(&ptr.trait_ref); } else { - struct_span_err!( - tcx.sess, - span, - E0203, - "type parameter has more than one relaxed default \ - bound, only one is supported" - ) - .emit(); + tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span }); } } } @@ -927,18 +938,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { dup_bindings .entry(assoc_ty.def_id) .and_modify(|prev_span| { - struct_span_err!( - self.tcx().sess, - binding.span, - E0719, - "the value of the associated type `{}` (from trait `{}`) \ - is already specified", - binding.item_name, - tcx.def_path_str(assoc_ty.container.id()) - ) - .span_label(binding.span, "re-bound here") - .span_label(*prev_span, format!("`{}` bound here first", binding.item_name)) - .emit(); + self.tcx().sess.emit_err(ValueOfAssociatedStructAlreadySpecified { + span: binding.span, + prev_span: *prev_span, + item_name: binding.item_name, + def_path: tcx.def_path_str(assoc_ty.container.id()), + }); }) .or_insert(binding.span); } @@ -1051,13 +1056,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if regular_traits.is_empty() && auto_traits.is_empty() { - struct_span_err!( - tcx.sess, - span, - E0224, - "at least one trait is required for an object type" - ) - .emit(); + tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span }); return tcx.ty_error(); } @@ -1454,7 +1453,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Check if we have an enum variant. let mut variant_resolution = None; - if let ty::Adt(adt_def, _) = qself_ty.kind { + if let ty::Adt(adt_def, _) = qself_ty.kind() { if adt_def.is_enum() { let variant_def = adt_def .variants @@ -1474,8 +1473,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Find the type of the associated item, and the trait where the associated // item is declared. - let bound = match (&qself_ty.kind, qself_res) { - (_, Res::SelfTy(Some(_), Some(impl_def_id))) => { + let bound = match (&qself_ty.kind(), qself_res) { + (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => { // `Self` in an impl of a trait -- we have a concrete self type and a // trait reference. let trait_ref = match tcx.impl_trait_ref(impl_def_id) { @@ -1932,12 +1931,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.prohibit_generics(path.segments); tcx.types.self_param } - Res::SelfTy(_, Some(def_id)) => { + Res::SelfTy(_, Some((def_id, forbid_generic))) => { // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); self.prohibit_generics(path.segments); // Try to evaluate any array length constants. - self.normalize_ty(span, tcx.at(span).type_of(def_id)) + let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); + if forbid_generic && normalized_ty.needs_subst() { + let mut err = tcx.sess.struct_span_err( + path.span, + "generic `Self` types are currently not permitted in anonymous constants", + ); + if let Some(hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Impl { self_ty, .. }, + .. + })) = tcx.hir().get_if_local(def_id) + { + err.span_note(self_ty.span, "not a concrete type"); + } + err.emit(); + tcx.ty_error() + } else { + normalized_ty + } } Res::Def(DefKind::AssocTy, def_id) => { debug_assert!(path.segments.len() >= 2); @@ -2059,15 +2075,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(ast_ty.span, array_ty) } hir::TyKind::Typeof(ref _e) => { - struct_span_err!( - tcx.sess, - ast_ty.span, - E0516, - "`typeof` is a reserved keyword but unimplemented" - ) - .span_label(ast_ty.span, "reserved keyword") - .emit(); - + tcx.sess.emit_err(TypeofReservedKeywordUsed { span: ast_ty.span }); tcx.ty_error() } hir::TyKind::Infer => { @@ -2283,13 +2291,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // error. let r = derived_region_bounds[0]; if derived_region_bounds[1..].iter().any(|r1| r != *r1) { - struct_span_err!( - tcx.sess, - span, - E0227, - "ambiguous lifetime bound, explicit lifetime bound required" - ) - .emit(); + tcx.sess.emit_err(AmbiguousLifetimeBound { span }); } Some(r) } diff --git a/src/librustc_typeck/bounds.rs b/compiler/rustc_typeck/src/bounds.rs similarity index 100% rename from src/librustc_typeck/bounds.rs rename to compiler/rustc_typeck/src/bounds.rs diff --git a/src/librustc_typeck/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs similarity index 81% rename from src/librustc_typeck/check/_match.rs rename to compiler/rustc_typeck/src/check/_match.rs index 40088bc069..7cb23dc053 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -1,12 +1,15 @@ use crate::check::coercion::CoerceMany; use crate::check::{Diverges, Expectation, FnCtxt, Needs}; -use rustc_hir as hir; -use rustc_hir::ExprKind; +use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_middle::ty::Ty; +use rustc_infer::traits::Obligation; +use rustc_middle::ty::{self, ToPredicate, Ty}; use rustc_span::Span; -use rustc_trait_selection::traits::ObligationCauseCode; -use rustc_trait_selection::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause}; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{ + IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, +}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_match( @@ -14,7 +17,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, scrut: &'tcx hir::Expr<'tcx>, arms: &'tcx [hir::Arm<'tcx>], - expected: Expectation<'tcx>, + orig_expected: Expectation<'tcx>, match_src: hir::MatchSource, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -22,13 +25,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { use hir::MatchSource::*; let (source_if, if_no_else, force_scrutinee_bool) = match match_src { IfDesugar { contains_else_clause } => (true, !contains_else_clause, true), - IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false), + IfLetDesugar { contains_else_clause, .. } => (true, !contains_else_clause, false), WhileDesugar => (false, false, true), _ => (false, false, false), }; // Type check the descriminant and get its type. - let scrut_ty = if force_scrutinee_bool { + let scrutinee_ty = if force_scrutinee_bool { // Here we want to ensure: // // 1. That default match bindings are *not* accepted in the condition of an @@ -55,7 +58,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // #55810: Type check patterns first so we get types for all bindings. for arm in arms { - self.check_pat_top(&arm.pat, scrut_ty, Some(scrut.span), true); + self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut.span), true); } // Now typecheck the blocks. @@ -69,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type in that case) let mut all_arms_diverge = Diverges::WarnedAlways; - let expected = expected.adjust_for_branches(self); + let expected = orig_expected.adjust_for_branches(self); let mut coercion = { let coerce_first = match expected { @@ -112,6 +115,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_with_expectation(&arm.body, expected) }; all_arms_diverge &= self.diverges.get(); + + // 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. + let opt_suggest_box_span = match ( + orig_expected, + self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty)), + ) { + (Expectation::ExpectHasType(expected), Some((id, ty))) + if self.in_tail_expr && self.can_coerce(arm_ty, expected) => + { + let impl_trait_ret_ty = self.infcx.instantiate_opaque_types( + id, + self.body_id, + self.param_env, + &ty, + arm.body.span, + ); + let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty(); + for o in impl_trait_ret_ty.obligations { + match o.predicate.skip_binders_unchecked() { + ty::PredicateAtom::Trait(t, constness) => { + let pred = ty::PredicateAtom::Trait( + ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: t.def_id(), + substs: self.infcx.tcx.mk_substs_trait(arm_ty, &[]), + }, + }, + constness, + ); + let obl = Obligation::new( + o.cause.clone(), + self.param_env, + pred.to_predicate(self.infcx.tcx), + ); + suggest_box &= self.infcx.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; + } + } + _ => {} + } + } + // 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 } + } + _ => None, + }; + if source_if { let then_expr = &arms[0].body; match (i, if_no_else) { @@ -119,7 +176,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (_, true) => {} // Handled above to avoid duplicated type errors (#60254). (_, _) => { let then_ty = prior_arm_ty.unwrap(); - let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty); + let cause = self.if_cause( + expr.span, + then_expr, + &arm.body, + then_ty, + arm_ty, + opt_suggest_box_span, + ); coercion.coerce(self, &cause, &arm.body, arm_ty); } } @@ -142,6 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arms: other_arms.clone(), last_ty: prior_arm_ty.unwrap(), scrut_hir_id: scrut.hir_id, + opt_suggest_box_span, }), ), }; @@ -266,6 +331,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else_expr: &'tcx hir::Expr<'tcx>, then_ty: Ty<'tcx>, else_ty: Ty<'tcx>, + opt_suggest_box_span: Option, ) -> ObligationCause<'tcx> { let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) { // The `if`/`else` isn't in one line in the output, include some context to make it @@ -353,8 +419,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error_sp, ObligationCauseCode::IfExpression(box IfExpressionCause { then: then_sp, + else_sp: error_sp, outer: outer_sp, semicolon: remove_semicolon, + opt_suggest_box_span, }), ) } diff --git a/src/librustc_typeck/check/autoderef.rs b/compiler/rustc_typeck/src/check/autoderef.rs similarity index 74% rename from src/librustc_typeck/check/autoderef.rs rename to compiler/rustc_typeck/src/check/autoderef.rs index 97d2b3e5a8..59c366ad7d 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/compiler/rustc_typeck/src/check/autoderef.rs @@ -12,7 +12,18 @@ use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { - Autoderef::new(self, self.param_env, self.body_id, span, base_ty) + Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span) + } + + /// Like `autoderef`, but provides a custom `Span` to use for calls to + /// an overloaded `Deref` operator + pub fn autoderef_overloaded_span( + &'a self, + span: Span, + base_ty: Ty<'tcx>, + overloaded_span: Span, + ) -> Autoderef<'a, 'tcx> { + Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span) } pub fn try_overloaded_deref( @@ -43,8 +54,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_overloaded_deref(autoderef.span(), source).and_then( |InferOk { value: method, obligations: o }| { obligations.extend(o); - if let ty::Ref(region, _, mutbl) = method.sig.output().kind { - Some(OverloadedDeref { region, mutbl }) + if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { + Some(OverloadedDeref { + region, + mutbl, + span: autoderef.overloaded_span(), + }) } else { None } diff --git a/src/librustc_typeck/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs similarity index 98% rename from src/librustc_typeck/check/callee.rs rename to compiler/rustc_typeck/src/check/callee.rs index 4ba64035ca..740783aeb9 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // If the callee is a bare function or a closure, then we're all set. - match adjusted_ty.kind { + match *adjusted_ty.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let adjustments = self.adjust_steps(autoderef); self.apply_adjustments(callee_expr, adjustments); @@ -223,12 +223,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if borrow { // Check for &self vs &mut self in the method signature. Since this is either // the Fn or FnMut trait, it should be one of those. - let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind - { - (r, mutbl) - } else { - span_bug!(call_expr.span, "input to call/call_mut is not a ref?"); - }; + let (region, mutbl) = + if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind() { + (r, mutbl) + } else { + span_bug!(call_expr.span, "input to call/call_mut is not a ref?"); + }; let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, @@ -285,7 +285,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let (fn_sig, def_span) = match callee_ty.kind { + let (fn_sig, def_span) = match *callee_ty.kind() { ty::FnDef(def_id, _) => { (callee_ty.fn_sig(self.tcx), self.tcx.hir().span_if_local(def_id)) } diff --git a/src/librustc_typeck/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs similarity index 98% rename from src/librustc_typeck/check/cast.rs rename to compiler/rustc_typeck/src/check/cast.rs index e41314e8ab..5c2bdb86f7 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -97,7 +97,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ok(Some(PointerKind::Thin)); } - Ok(match t.kind { + Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), ty::Dynamic(ref tty, ..) => Some(PointerKind::Vtable(tty.principal_def_id())), ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { @@ -203,7 +203,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once // inference is more completely known. - match cast_ty.kind { + match cast_ty.kind() { ty::Dynamic(..) | ty::Slice(..) => { check.report_cast_to_unsized_type(fcx); Err(ErrorReported) @@ -348,7 +348,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx.ty_to_string(self.cast_ty) ); let mut sugg = None; - if let ty::Ref(reg, _, mutbl) = self.cast_ty.kind { + if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() { if fcx .try_coerce( self.expr, @@ -370,7 +370,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { Applicability::MachineApplicable, ); } else if !matches!( - self.cast_ty.kind, + self.cast_ty.kind(), ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) ) { let mut label = true; @@ -474,7 +474,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx.resolve_vars_if_possible(&self.expr_ty), tstr ); - match self.expr_ty.kind { + match self.expr_ty.kind() { ty::Ref(_, _, mt) => { let mtstr = mt.prefix_str(); if self.cast_ty.is_trait() { @@ -602,7 +602,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Some(t_from), Some(t_cast)) => (t_from, t_cast), // Function item types may need to be reified before casts. (None, Some(t_cast)) => { - match self.expr_ty.kind { + match *self.expr_ty.kind() { ty::FnDef(..) => { // Attempt a coercion to a fn pointer type. let f = fcx.normalize_associated_types_in( @@ -629,7 +629,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // a cast. ty::Ref(_, inner_ty, mutbl) => { return match t_cast { - Int(_) | Float => match inner_ty.kind { + Int(_) | Float => match *inner_ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Float(_) @@ -768,7 +768,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // array-ptr-cast. if m_expr.mutbl == hir::Mutability::Not && m_cast.mutbl == hir::Mutability::Not { - if let ty::Array(ety, _) = m_expr.ty.kind { + if let ty::Array(ety, _) = m_expr.ty.kind() { // Due to the limitations of LLVM global constants, // region pointers end up pointing at copies of // vector elements instead of the original values. @@ -817,7 +817,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { - if let ty::Adt(d, _) = self.expr_ty.kind { + if let ty::Adt(d, _) = self.expr_ty.kind() { if d.has_dtor(fcx.tcx) { fcx.tcx.struct_span_lint_hir( lint::builtin::CENUM_IMPL_DROP_CAST, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs new file mode 100644 index 0000000000..0647be2dfd --- /dev/null +++ b/compiler/rustc_typeck/src/check/check.rs @@ -0,0 +1,1345 @@ +use super::coercion::CoerceMany; +use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; +use super::*; + +use rustc_attr as attr; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{ItemKind, Node}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::RegionVariableOrigin; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; +use rustc_middle::ty::{self, RegionKind, ToPredicate, Ty, TyCtxt}; +use rustc_session::config::EntryFnType; +use rustc_span::symbol::sym; +use rustc_span::{self, MultiSpan, Span}; +use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; + +pub fn check_wf_new(tcx: TyCtxt<'_>) { + let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); + tcx.hir().krate().par_visit_all_item_likes(&visit); +} + +pub(super) fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { + if !tcx.sess.target.target.is_abi_supported(abi) { + struct_span_err!( + tcx.sess, + span, + E0570, + "The ABI `{}` is not supported for the current target", + abi + ) + .emit() + } +} + +/// Helper used for fns and closures. Does the grungy work of checking a function +/// body and returns the function context used for that purpose, since in the case of a fn item +/// there is still a bit more to do. +/// +/// * ... +/// * inherited: other fields inherited from the enclosing fn (if any) +pub(super) fn check_fn<'a, 'tcx>( + inherited: &'a Inherited<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + fn_sig: ty::FnSig<'tcx>, + decl: &'tcx hir::FnDecl<'tcx>, + fn_id: hir::HirId, + body: &'tcx hir::Body<'tcx>, + can_be_generator: Option, +) -> (FnCtxt<'a, 'tcx>, Option>) { + let mut fn_sig = fn_sig; + + debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); + + // Create the function context. This is either derived from scratch or, + // in the case of closures, based on the outer context. + let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); + *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); + + let tcx = fcx.tcx; + let sess = tcx.sess; + let hir = tcx.hir(); + + let declared_ret_ty = fn_sig.output(); + + let revealed_ret_ty = + fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); + debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); + fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); + fcx.ret_type_span = Some(decl.output.span()); + if let ty::Opaque(..) = declared_ret_ty.kind() { + fcx.ret_coercion_impl_trait = Some(declared_ret_ty); + } + fn_sig = tcx.mk_fn_sig( + fn_sig.inputs().iter().cloned(), + revealed_ret_ty, + fn_sig.c_variadic, + fn_sig.unsafety, + fn_sig.abi, + ); + + let span = body.value.span; + + fn_maybe_err(tcx, span, fn_sig.abi); + + if body.generator_kind.is_some() && can_be_generator.is_some() { + let yield_ty = fcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); + fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + + // Resume type defaults to `()` if the generator has no argument. + let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); + + fcx.resume_yield_tys = Some((resume_ty, yield_ty)); + } + + let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local(); + let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id); + GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body); + + // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` + // (as it's created inside the body itself, not passed in from outside). + let maybe_va_list = if fn_sig.c_variadic { + let span = body.params.last().unwrap().span; + let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); + + Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) + } else { + None + }; + + // Add formal parameters. + let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); + let inputs_fn = fn_sig.inputs().iter().copied(); + for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { + // Check the pattern. + let ty_span = try { inputs_hir?.get(idx)?.span }; + fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); + + // Check that argument is Sized. + // The check for a non-trivial pattern is a hack to avoid duplicate warnings + // for simple cases like `fn foo(x: Trait)`, + // where we would error once on the parameter as a whole, and once on the binding `x`. + if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { + fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); + } + + fcx.write_ty(param.hir_id, param_ty); + } + + inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); + + fcx.in_tail_expr = true; + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // FIXME: We need to verify that the return type is `Sized` after the return expression has + // been evaluated so that we have types available for all the nodes being returned, but that + // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this + // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, + // while keeping the current ordering we will ignore the tail expression's type because we + // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` + // because we will trigger "unreachable expression" lints unconditionally. + // Because of all of this, we perform a crude check to know whether the simplest `!Sized` + // case that a newcomer might make, returning a bare trait, and in that case we populate + // the tail expression's type so that the suggestion will be correct, but ignore all other + // possible cases. + fcx.check_expr(&body.value); + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type"); + } else { + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + fcx.check_return_expr(&body.value); + } + fcx.in_tail_expr = false; + + // We insert the deferred_generator_interiors entry after visiting the body. + // This ensures that all nested generators appear before the entry of this generator. + // resolve_generator_interiors relies on this property. + let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { + let interior = fcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); + fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); + + let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); + Some(GeneratorTypes { + resume_ty, + yield_ty, + interior, + movability: can_be_generator.unwrap(), + }) + } else { + None + }; + + // Finalize the return check by taking the LUB of the return types + // we saw and assigning it to the expected return type. This isn't + // really expected to fail, since the coercions would have failed + // earlier when trying to find a LUB. + // + // However, the behavior around `!` is sort of complex. In the + // event that the `actual_return_ty` comes back as `!`, that + // indicates that the fn either does not return or "returns" only + // values of type `!`. In this case, if there is an expected + // return type that is *not* `!`, that should be ok. But if the + // return type is being inferred, we want to "fallback" to `!`: + // + // let x = move || panic!(); + // + // To allow for that, I am creating a type variable with diverging + // fallback. This was deemed ever so slightly better than unifying + // the return value with `!` because it allows for the caller to + // make more assumptions about the return type (e.g., they could do + // + // let y: Option = Some(x()); + // + // which would then cause this return type to become `u32`, not + // `!`). + let coercion = fcx.ret_coercion.take().unwrap().into_inner(); + let mut actual_return_ty = coercion.complete(&fcx); + if actual_return_ty.is_never() { + actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::DivergingFn, + span, + }); + } + fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); + + // Check that the main return type implements the termination trait. + if let Some(term_id) = tcx.lang_items().termination() { + if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) { + let main_id = hir.local_def_id_to_hir_id(def_id); + if main_id == fn_id { + let substs = tcx.mk_substs_trait(declared_ret_ty, &[]); + let trait_ref = ty::TraitRef::new(term_id, substs); + let return_ty_span = decl.output.span(); + let cause = traits::ObligationCause::new( + return_ty_span, + fn_id, + ObligationCauseCode::MainFunctionType, + ); + + inherited.register_predicate(traits::Obligation::new( + cause, + param_env, + trait_ref.without_const().to_predicate(tcx), + )); + } + } + } + + // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` + if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { + if panic_impl_did == hir.local_def_id(fn_id).to_def_id() { + if let Some(panic_info_did) = tcx.lang_items().panic_info() { + if *declared_ret_ty.kind() != ty::Never { + sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let inputs = fn_sig.inputs(); + let span = hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_panic_info = match *inputs[0].kind() { + ty::Ref(region, ty, mutbl) => match *ty.kind() { + ty::Adt(ref adt, _) => { + adt.did == panic_info_did + && mutbl == hir::Mutability::Not + && *region != RegionKind::ReStatic + } + _ => false, + }, + _ => false, + }; + + if !arg_is_panic_info { + sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); + } + + if let Node::Item(item) = hir.get(fn_id) { + if let ItemKind::Fn(_, ref generics, _) = item.kind { + if !generics.params.is_empty() { + sess.span_err(span, "should have no type parameters"); + } + } + } + } else { + let span = sess.source_map().guess_head_span(span); + sess.span_err(span, "function should have one argument"); + } + } else { + sess.err("language item required, but not found: `panic_info`"); + } + } + } + + // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` + if let Some(alloc_error_handler_did) = tcx.lang_items().oom() { + if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() { + if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() { + if *declared_ret_ty.kind() != ty::Never { + sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let inputs = fn_sig.inputs(); + let span = hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_alloc_layout = match inputs[0].kind() { + ty::Adt(ref adt, _) => adt.did == alloc_layout_did, + _ => false, + }; + + if !arg_is_alloc_layout { + sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); + } + + if let Node::Item(item) = hir.get(fn_id) { + if let ItemKind::Fn(_, ref generics, _) = item.kind { + if !generics.params.is_empty() { + sess.span_err( + span, + "`#[alloc_error_handler]` function should have no type \ + parameters", + ); + } + } + } + } else { + let span = sess.source_map().guess_head_span(span); + sess.span_err(span, "function should have one argument"); + } + } else { + sess.err("language item required, but not found: `alloc_layout`"); + } + } + } + + (fcx, gen_ty) +} + +pub(super) fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { + let def_id = tcx.hir().local_def_id(id); + let def = tcx.adt_def(def_id); + def.destructor(tcx); // force the destructor to be evaluated + check_representable(tcx, span, def_id); + + if def.repr.simd() { + check_simd(tcx, span, def_id); + } + + check_transparent(tcx, span, def); + check_packed(tcx, span, def); +} + +pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { + let def_id = tcx.hir().local_def_id(id); + let def = tcx.adt_def(def_id); + def.destructor(tcx); // force the destructor to be evaluated + check_representable(tcx, span, def_id); + check_transparent(tcx, span, def); + check_union_fields(tcx, span, def_id); + check_packed(tcx, span, def); +} + +/// When the `#![feature(untagged_unions)]` gate is active, +/// check that the fields of the `union` does not contain fields that need dropping. +pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { + let item_type = tcx.type_of(item_def_id); + if let ty::Adt(def, substs) = item_type.kind() { + assert!(def.is_union()); + let fields = &def.non_enum_variant().fields; + let param_env = tcx.param_env(item_def_id); + for field in fields { + let field_ty = field.ty(tcx, substs); + // We are currently checking the type this field came from, so it must be local. + let field_span = tcx.hir().span_if_local(field.did).unwrap(); + if field_ty.needs_drop(tcx, param_env) { + struct_span_err!( + tcx.sess, + field_span, + E0740, + "unions may not contain fields that need dropping" + ) + .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type") + .emit(); + return false; + } + } + } else { + span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind()); + } + true +} + +/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` +/// projections that would result in "inheriting lifetimes". +pub(super) fn check_opaque<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + substs: SubstsRef<'tcx>, + span: Span, + origin: &hir::OpaqueTyOrigin, +) { + check_opaque_for_inheriting_lifetimes(tcx, def_id, span); + tcx.ensure().type_of(def_id); + check_opaque_for_cycles(tcx, def_id, substs, span, origin); +} + +/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result +/// in "inheriting lifetimes". +pub(super) fn check_opaque_for_inheriting_lifetimes( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + span: Span, +) { + let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id)); + debug!( + "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}", + def_id, span, item + ); + + #[derive(Debug)] + struct ProhibitOpaqueVisitor<'tcx> { + opaque_identity_ty: Ty<'tcx>, + generics: &'tcx ty::Generics, + ty: Option>, + }; + + impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); + if t != self.opaque_identity_ty && t.super_visit_with(self) { + self.ty = Some(t); + return true; + } + false + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); + if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { + return *index < self.generics.parent_count as u32; + } + + r.super_visit_with(self) + } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(..) = c.val { + // FIXME(#72219) We currenctly don't detect lifetimes within substs + // which would violate this check. Even though the particular substitution is not used + // within the const, this should still be fixed. + return false; + } + c.super_visit_with(self) + } + } + + if let ItemKind::OpaqueTy(hir::OpaqueTy { + origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, + .. + }) = item.kind + { + let mut visitor = ProhibitOpaqueVisitor { + opaque_identity_ty: tcx.mk_opaque( + def_id.to_def_id(), + InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), + ), + generics: tcx.generics_of(def_id), + ty: None, + }; + let prohibit_opaque = tcx + .predicates_of(def_id) + .predicates + .iter() + .any(|(predicate, _)| predicate.visit_with(&mut visitor)); + debug!( + "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", + prohibit_opaque, visitor + ); + + if prohibit_opaque { + let is_async = match item.kind { + ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { + hir::OpaqueTyOrigin::AsyncFn => true, + _ => false, + }, + _ => unreachable!(), + }; + + let mut err = struct_span_err!( + tcx.sess, + span, + E0760, + "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ + a parent scope", + if is_async { "async fn" } else { "impl Trait" }, + ); + + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { + if snippet == "Self" { + if let Some(ty) = visitor.ty { + err.span_suggestion( + span, + "consider spelling out the type instead", + format!("{:?}", ty), + Applicability::MaybeIncorrect, + ); + } + } + } + err.emit(); + } + } +} + +/// Checks that an opaque type does not contain cycles. +pub(super) fn check_opaque_for_cycles<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + substs: SubstsRef<'tcx>, + span: Span, + origin: &hir::OpaqueTyOrigin, +) { + if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs) + { + match origin { + hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span), + hir::OpaqueTyOrigin::Binding => { + binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type) + } + _ => opaque_type_cycle_error(tcx, def_id, span), + } + } +} + +pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { + debug!( + "check_item_type(it.hir_id={}, it.name={})", + it.hir_id, + tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id()) + ); + let _indenter = indenter(); + match it.kind { + // Consts can play a role in type-checking, so they are included here. + hir::ItemKind::Static(..) => { + let def_id = tcx.hir().local_def_id(it.hir_id); + tcx.ensure().typeck(def_id); + maybe_check_static_with_link_section(tcx, def_id, it.span); + } + hir::ItemKind::Const(..) => { + tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id)); + } + hir::ItemKind::Enum(ref enum_definition, _) => { + check_enum(tcx, it.span, &enum_definition.variants, it.hir_id); + } + hir::ItemKind::Fn(..) => {} // entirely within check_item_body + hir::ItemKind::Impl { ref items, .. } => { + debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id); + let impl_def_id = tcx.hir().local_def_id(it.hir_id); + if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { + check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items); + let trait_def_id = impl_trait_ref.def_id; + check_on_unimplemented(tcx, trait_def_id, it); + } + } + hir::ItemKind::Trait(_, _, _, _, ref items) => { + let def_id = tcx.hir().local_def_id(it.hir_id); + check_on_unimplemented(tcx, def_id.to_def_id(), it); + + for item in items.iter() { + let item = tcx.hir().trait_item(item.id); + if let hir::TraitItemKind::Fn(sig, _) = &item.kind { + let abi = sig.header.abi; + fn_maybe_err(tcx, item.ident.span, abi); + } + } + } + hir::ItemKind::Struct(..) => { + check_struct(tcx, it.hir_id, it.span); + } + hir::ItemKind::Union(..) => { + check_union(tcx, it.hir_id, it.span); + } + hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { + // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting + // `async-std` (and `pub async fn` in general). + // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! + // See https://github.com/rust-lang/rust/issues/75100 + if !tcx.sess.opts.actually_rustdoc { + let def_id = tcx.hir().local_def_id(it.hir_id); + + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + check_opaque(tcx, def_id, substs, it.span, &origin); + } + } + hir::ItemKind::TyAlias(..) => { + let def_id = tcx.hir().local_def_id(it.hir_id); + let pty_ty = tcx.type_of(def_id); + let generics = tcx.generics_of(def_id); + check_type_params_are_used(tcx, &generics, pty_ty); + } + hir::ItemKind::ForeignMod(ref m) => { + check_abi(tcx, it.span, m.abi); + + if m.abi == Abi::RustIntrinsic { + for item in m.items { + intrinsic::check_intrinsic_type(tcx, item); + } + } else if m.abi == Abi::PlatformIntrinsic { + for item in m.items { + intrinsic::check_platform_intrinsic_type(tcx, item); + } + } else { + for item in m.items { + let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id)); + let own_counts = generics.own_counts(); + if generics.params.len() - own_counts.lifetimes != 0 { + let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) { + (_, 0) => ("type", "types", Some("u32")), + // We don't specify an example value, because we can't generate + // a valid value for any type. + (0, _) => ("const", "consts", None), + _ => ("type or const", "types or consts", None), + }; + struct_span_err!( + tcx.sess, + item.span, + E0044, + "foreign items may not have {} parameters", + kinds, + ) + .span_label(item.span, &format!("can't have {} parameters", kinds)) + .help( + // FIXME: once we start storing spans for type arguments, turn this + // into a suggestion. + &format!( + "replace the {} parameters with concrete {}{}", + kinds, + kinds_pl, + egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(), + ), + ) + .emit(); + } + + if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind { + require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span); + } + } + } + } + _ => { /* nothing to do */ } + } +} + +pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) { + let item_def_id = tcx.hir().local_def_id(item.hir_id); + // an error would be reported if this fails. + let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id()); +} + +pub(super) fn check_specialization_validity<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def: &ty::TraitDef, + trait_item: &ty::AssocItem, + impl_id: DefId, + impl_item: &hir::ImplItem<'_>, +) { + let kind = match impl_item.kind { + hir::ImplItemKind::Const(..) => ty::AssocKind::Const, + hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, + hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type, + }; + + let ancestors = match trait_def.ancestors(tcx, impl_id) { + Ok(ancestors) => ancestors, + Err(_) => return, + }; + let mut ancestor_impls = ancestors + .skip(1) + .filter_map(|parent| { + if parent.is_from_trait() { + None + } else { + Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id))) + } + }) + .peekable(); + + if ancestor_impls.peek().is_none() { + // No parent, nothing to specialize. + return; + } + + let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| { + match parent_item { + // Parent impl exists, and contains the parent item we're trying to specialize, but + // doesn't mark it `default`. + Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => { + Some(Err(parent_impl.def_id())) + } + + // Parent impl contains item and makes it specializable. + Some(_) => Some(Ok(())), + + // Parent impl doesn't mention the item. This means it's inherited from the + // grandparent. In that case, if parent is a `default impl`, inherited items use the + // "defaultness" from the grandparent, else they are final. + None => { + if tcx.impl_defaultness(parent_impl.def_id()).is_default() { + None + } else { + Some(Err(parent_impl.def_id())) + } + } + } + }); + + // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the + // item. This is allowed, the item isn't actually getting specialized here. + let result = opt_result.unwrap_or(Ok(())); + + if let Err(parent_impl) = result { + report_forbidden_specialization(tcx, impl_item, parent_impl); + } +} + +pub(super) fn check_impl_items_against_trait<'tcx>( + tcx: TyCtxt<'tcx>, + full_impl_span: Span, + impl_id: LocalDefId, + impl_trait_ref: ty::TraitRef<'tcx>, + impl_item_refs: &[hir::ImplItemRef<'_>], +) { + let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); + + // If the trait reference itself is erroneous (so the compilation is going + // to fail), skip checking the items here -- the `impl_item` table in `tcx` + // isn't populated for such impls. + if impl_trait_ref.references_error() { + return; + } + + // Negative impls are not expected to have any items + match tcx.impl_polarity(impl_id) { + ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {} + ty::ImplPolarity::Negative => { + if let [first_item_ref, ..] = impl_item_refs { + let first_item_span = tcx.hir().impl_item(first_item_ref.id).span; + struct_span_err!( + tcx.sess, + first_item_span, + E0749, + "negative impls cannot have any items" + ) + .emit(); + } + return; + } + } + + // Locate trait definition and items + let trait_def = tcx.trait_def(impl_trait_ref.def_id); + + let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); + + // Check existing impl methods to see if they are both present in trait + // and compatible with trait signature + for impl_item in impl_items() { + let namespace = impl_item.kind.namespace(); + let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id)); + let ty_trait_item = tcx + .associated_items(impl_trait_ref.def_id) + .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id) + .or_else(|| { + // Not compatible, but needed for the error message + tcx.associated_items(impl_trait_ref.def_id) + .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id) + .next() + }); + + // Check that impl definition matches trait definition + if let Some(ty_trait_item) = ty_trait_item { + match impl_item.kind { + hir::ImplItemKind::Const(..) => { + // Find associated const definition. + if ty_trait_item.kind == ty::AssocKind::Const { + compare_const_impl( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0323, + "item `{}` is an associated const, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + // We can only get the spans from local trait definition + // Same for E0324 and E0325 + if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } + } + hir::ImplItemKind::Fn(..) => { + let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); + if ty_trait_item.kind == ty::AssocKind::Fn { + compare_impl_method( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0324, + "item `{}` is an associated method, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + if let Some(trait_span) = opt_trait_span { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } + } + hir::ImplItemKind::TyAlias(_) => { + let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); + if ty_trait_item.kind == ty::AssocKind::Type { + compare_ty_impl( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0325, + "item `{}` is an associated type, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + if let Some(trait_span) = opt_trait_span { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } + } + } + + check_specialization_validity( + tcx, + trait_def, + &ty_trait_item, + impl_id.to_def_id(), + impl_item, + ); + } + } + + // Check for missing items from trait + let mut missing_items = Vec::new(); + if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) { + for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { + let is_implemented = ancestors + .leaf_def(tcx, trait_item.ident, trait_item.kind) + .map(|node_item| !node_item.defining_node.is_from_trait()) + .unwrap_or(false); + + if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { + if !trait_item.defaultness.has_value() { + missing_items.push(*trait_item); + } + } + } + } + + if !missing_items.is_empty() { + missing_items_err(tcx, impl_span, &missing_items, full_impl_span); + } +} + +/// Checks whether a type can be represented in memory. In particular, it +/// identifies types that contain themselves without indirection through a +/// pointer, which would mean their size is unbounded. +pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool { + let rty = tcx.type_of(item_def_id); + + // Check that it is possible to represent this type. This call identifies + // (1) types that contain themselves and (2) types that contain a different + // recursive type. It is only necessary to throw an error on those that + // contain themselves. For case 2, there must be an inner type that will be + // caught by case 1. + match rty.is_representable(tcx, sp) { + Representability::SelfRecursive(spans) => { + recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans); + return false; + } + Representability::Representable | Representability::ContainsRecursive => (), + } + true +} + +pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { + let t = tcx.type_of(def_id); + if let ty::Adt(def, substs) = t.kind() { + if def.is_struct() { + let fields = &def.non_enum_variant().fields; + if fields.is_empty() { + struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); + return; + } + let e = fields[0].ty(tcx, substs); + if !fields.iter().all(|f| f.ty(tcx, substs) == e) { + struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous") + .span_label(sp, "SIMD elements must have the same type") + .emit(); + return; + } + match e.kind() { + ty::Param(_) => { /* struct(T, T, T, T) is ok */ } + _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } + _ => { + struct_span_err!( + tcx.sess, + sp, + E0077, + "SIMD vector element type should be machine type" + ) + .emit(); + return; + } + } + } + } +} + +pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { + let repr = def.repr; + if repr.packed() { + for attr in tcx.get_attrs(def.did).iter() { + for r in attr::find_repr_attrs(&tcx.sess, attr) { + if let attr::ReprPacked(pack) = r { + if let Some(repr_pack) = repr.pack { + if pack as u64 != repr_pack.bytes() { + struct_span_err!( + tcx.sess, + sp, + E0634, + "type has conflicting packed representation hints" + ) + .emit(); + } + } + } + } + } + if repr.align.is_some() { + struct_span_err!( + tcx.sess, + sp, + E0587, + "type has conflicting packed and align representation hints" + ) + .emit(); + } else { + if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) { + let mut err = struct_span_err!( + tcx.sess, + sp, + E0588, + "packed type cannot transitively contain a `#[repr(align)]` type" + ); + + err.span_note( + tcx.def_span(def_spans[0].0), + &format!( + "`{}` has a `#[repr(align)]` attribute", + tcx.item_name(def_spans[0].0) + ), + ); + + if def_spans.len() > 2 { + let mut first = true; + for (adt_def, span) in def_spans.iter().skip(1).rev() { + let ident = tcx.item_name(*adt_def); + err.span_note( + *span, + &if first { + format!( + "`{}` contains a field of type `{}`", + tcx.type_of(def.did), + ident + ) + } else { + format!("...which contains a field of type `{}`", ident) + }, + ); + first = false; + } + } + + err.emit(); + } + } + } +} + +pub(super) fn check_packed_inner( + tcx: TyCtxt<'_>, + def_id: DefId, + stack: &mut Vec, +) -> Option> { + if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() { + if def.is_struct() || def.is_union() { + if def.repr.align.is_some() { + return Some(vec![(def.did, DUMMY_SP)]); + } + + stack.push(def_id); + for field in &def.non_enum_variant().fields { + if let ty::Adt(def, _) = field.ty(tcx, substs).kind() { + if !stack.contains(&def.did) { + if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) { + defs.push((def.did, field.ident.span)); + return Some(defs); + } + } + } + } + stack.pop(); + } + } + + None +} + +pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) { + if !adt.repr.transparent() { + return; + } + let sp = tcx.sess.source_map().guess_head_span(sp); + + if adt.is_union() && !tcx.features().transparent_unions { + feature_err( + &tcx.sess.parse_sess, + sym::transparent_unions, + sp, + "transparent unions are unstable", + ) + .emit(); + } + + if adt.variants.len() != 1 { + bad_variant_count(tcx, adt, sp, adt.did); + if adt.variants.is_empty() { + // Don't bother checking the fields. No variants (and thus no fields) exist. + return; + } + } + + // For each field, figure out if it's known to be a ZST and align(1) + let field_infos = adt.all_fields().map(|field| { + let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); + let param_env = tcx.param_env(field.did); + let layout = tcx.layout_of(param_env.and(ty)); + // We are currently checking the type this field came from, so it must be local + let span = tcx.hir().span_if_local(field.did).unwrap(); + let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false); + let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false); + (span, zst, align1) + }); + + let non_zst_fields = + field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None }); + let non_zst_count = non_zst_fields.clone().count(); + if non_zst_count != 1 { + bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); + } + for (span, zst, align1) in field_infos { + if zst && !align1 { + struct_span_err!( + tcx.sess, + span, + E0691, + "zero-sized field in transparent {} has alignment larger than 1", + adt.descr(), + ) + .span_label(span, "has alignment larger than 1") + .emit(); + } + } +} + +#[allow(trivial_numeric_casts)] +pub fn check_enum<'tcx>( + tcx: TyCtxt<'tcx>, + sp: Span, + vs: &'tcx [hir::Variant<'tcx>], + id: hir::HirId, +) { + let def_id = tcx.hir().local_def_id(id); + let def = tcx.adt_def(def_id); + def.destructor(tcx); // force the destructor to be evaluated + + if vs.is_empty() { + let attributes = tcx.get_attrs(def_id.to_def_id()); + if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) { + struct_span_err!( + tcx.sess, + attr.span, + E0084, + "unsupported representation for zero-variant enum" + ) + .span_label(sp, "zero-variant enum") + .emit(); + } + } + + let repr_type_ty = def.repr.discr_type().to_ty(tcx); + if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { + if !tcx.features().repr128 { + feature_err( + &tcx.sess.parse_sess, + sym::repr128, + sp, + "repr with 128-bit type is unstable", + ) + .emit(); + } + } + + for v in vs { + if let Some(ref e) = v.disr_expr { + tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id)); + } + } + + if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant { + let is_unit = |var: &hir::Variant<'_>| match var.data { + hir::VariantData::Unit(..) => true, + _ => false, + }; + + let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); + let has_non_units = vs.iter().any(|var| !is_unit(var)); + let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); + let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); + + if disr_non_unit || (disr_units && has_non_units) { + let mut err = + struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified"); + err.emit(); + } + } + + let mut disr_vals: Vec> = Vec::with_capacity(vs.len()); + for ((_, discr), v) in def.discriminants(tcx).zip(vs) { + // Check for duplicate discriminant values + if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { + let variant_did = def.variants[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.hir().span(variant_i_hir_id), + }; + let span = match v.disr_expr { + Some(ref expr) => tcx.hir().span(expr.hir_id), + None => v.span, + }; + struct_span_err!( + tcx.sess, + span, + E0081, + "discriminant value `{}` already exists", + disr_vals[i] + ) + .span_label(i_span, format!("first use of `{}`", disr_vals[i])) + .span_label(span, format!("enum already has `{}`", disr_vals[i])) + .emit(); + } + disr_vals.push(discr); + } + + check_representable(tcx, sp, def_id); + check_transparent(tcx, sp, def); +} + +pub(super) fn check_type_params_are_used<'tcx>( + tcx: TyCtxt<'tcx>, + generics: &ty::Generics, + ty: Ty<'tcx>, +) { + debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); + + assert_eq!(generics.parent, None); + + if generics.own_counts().types == 0 { + return; + } + + let mut params_used = BitSet::new_empty(generics.params.len()); + + if ty.references_error() { + // If there is already another error, do not emit + // an error for not using a type parameter. + assert!(tcx.sess.has_errors()); + return; + } + + for leaf in ty.walk() { + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { + if let ty::Param(param) = leaf_ty.kind() { + debug!("found use of ty param {:?}", param); + params_used.insert(param.index); + } + } + } + + for param in &generics.params { + if !params_used.contains(param.index) { + if let ty::GenericParamDefKind::Type { .. } = param.kind { + let span = tcx.def_span(param.def_id); + struct_span_err!( + tcx.sess, + span, + E0091, + "type parameter `{}` is unused", + param.name, + ) + .span_label(span, "unused type parameter") + .emit(); + } + } + } +} + +pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { + tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); +} + +pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_item_well_formed(tcx, def_id); +} + +pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_trait_item(tcx, def_id); +} + +pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_impl_item(tcx, def_id); +} + +fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) { + struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") + .span_label(span, "recursive `async fn`") + .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") + .emit(); +} + +/// Emit an error for recursive opaque types. +/// +/// If this is a return `impl Trait`, find the item's return expressions and point at them. For +/// direct recursion this is enough, but for indirect recursion also point at the last intermediary +/// `impl Trait`. +/// +/// If all the return expressions evaluate to `!`, then we explain that the error will go away +/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. +fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { + let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); + + let mut label = false; + if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) { + let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id)); + if visitor + .returns + .iter() + .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) + .all(|ty| matches!(ty.kind(), ty::Never)) + { + let spans = visitor + .returns + .iter() + .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some()) + .map(|expr| expr.span) + .collect::>(); + let span_len = spans.len(); + if span_len == 1 { + err.span_label(spans[0], "this returned value is of `!` type"); + } else { + let mut multispan: MultiSpan = spans.clone().into(); + for span in spans { + multispan + .push_span_label(span, "this returned value is of `!` type".to_string()); + } + err.span_note(multispan, "these returned values have a concrete \"never\" type"); + } + err.help("this error will resolve once the item's body returns a concrete type"); + } else { + let mut seen = FxHashSet::default(); + seen.insert(span); + err.span_label(span, "recursive opaque type"); + label = true; + for (sp, ty) in visitor + .returns + .iter() + .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) + .filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) + { + struct VisitTypes(Vec); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match *t.kind() { + ty::Opaque(def, _) => { + self.0.push(def); + false + } + _ => t.super_visit_with(self), + } + } + } + let mut visitor = VisitTypes(vec![]); + ty.visit_with(&mut visitor); + for def_id in visitor.0 { + let ty_span = tcx.def_span(def_id); + if !seen.contains(&ty_span) { + err.span_label(ty_span, &format!("returning this opaque type `{}`", ty)); + seen.insert(ty_span); + } + err.span_label(sp, &format!("returning here with type `{}`", ty)); + } + } + } + } + if !label { + err.span_label(span, "cannot resolve opaque type"); + } + err.emit(); +} diff --git a/src/librustc_typeck/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs similarity index 99% rename from src/librustc_typeck/check/closure.rs rename to compiler/rustc_typeck/src/check/closure.rs index 97f7e4537c..8898a54522 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> (Option>, Option) { debug!("deduce_expectations_from_expected_type(expected_ty={:?})", expected_ty); - match expected_ty.kind { + match *expected_ty.kind() { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); @@ -268,7 +268,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let arg_param_ty = self.resolve_vars_if_possible(&arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty); - match arg_param_ty.kind { + match arg_param_ty.kind() { ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::>(), _ => return None, } @@ -611,7 +611,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be inferring. let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); - let ret_vid = match ret_ty.kind { + let ret_vid = match *ret_ty.kind() { ty::Infer(ty::TyVar(ret_vid)) => ret_vid, _ => span_bug!( self.tcx.def_span(expr_def_id), diff --git a/src/librustc_typeck/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs similarity index 96% rename from src/librustc_typeck/check/coercion.rs rename to compiler/rustc_typeck/src/check/coercion.rs index f0802c45ae..4addee1a4c 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -37,7 +37,7 @@ use crate::astconv::AstConv; use crate::check::FnCtxt; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; @@ -51,7 +51,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TypeAndMut}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{self, Span}; +use rustc_span::{self, BytePos, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; @@ -197,7 +197,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // // Note: does not attempt to resolve type variables we encounter. // See above for details. - match b.kind { + match *b.kind() { ty::RawPtr(mt_b) => { return self.coerce_unsafe_ptr(a, b, mt_b.mutbl); } @@ -207,7 +207,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { _ => {} } - match a.kind { + match *a.kind() { ty::FnDef(..) => { // Function items are coercible to any closure // type; function pointers are not (that would @@ -252,7 +252,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // to type check, we will construct the type that `&M*expr` would // yield. - let (r_a, mt_a) = match a.kind { + let (r_a, mt_a) = match *a.kind() { ty::Ref(r_a, ty, mutbl) => { let mt_a = ty::TypeAndMut { ty, mutbl }; coerce_mutbls(mt_a.mutbl, mutbl_b)?; @@ -415,7 +415,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Now apply the autoref. We have to extract the region out of // the final ref type we got. - let r_borrow = match ty.kind { + let r_borrow = match ty.kind() { ty::Ref(r_borrow, _, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), }; @@ -490,7 +490,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // that, at which point we will need extra checks on the target here. // Handle reborrows before selecting `Source: CoerceUnsized`. - let reborrow = match (&source.kind, &target.kind) { + let reborrow = match (source.kind(), target.kind()) { (&ty::Ref(_, ty_a, mutbl_a), &ty::Ref(_, _, mutbl_b)) => { coerce_mutbls(mutbl_a, mutbl_b)?; @@ -588,7 +588,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { { if unsize_did == trait_pred.def_id() { let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty(); - if let ty::Tuple(..) = unsize_ty.kind { + if let ty::Tuple(..) = unsize_ty.kind() { debug!("coerce_unsized: found unsized tuple coercion"); has_unsized_tuple_coercion = true; } @@ -608,7 +608,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let self_ty = trait_pred.skip_binder().self_ty(); let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); - match (&self_ty.kind, &unsize_ty.kind) { + match (&self_ty.kind(), &unsize_ty.kind()) { (ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) if self.type_var_is_sized(*v) => { @@ -672,7 +672,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { F: FnOnce(Ty<'tcx>) -> Vec>, G: FnOnce(Ty<'tcx>) -> Vec>, { - if let ty::FnPtr(fn_ty_b) = b.kind { + if let ty::FnPtr(fn_ty_b) = b.kind() { if let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) = (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { @@ -712,7 +712,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let b = self.shallow_resolve(b); debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); - match b.kind { + match b.kind() { ty::FnPtr(b_sig) => { let a_sig = a.fn_sig(self.tcx); // Intrinsics are not coercible to function pointers @@ -721,7 +721,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396). - if let ty::FnDef(def_id, _) = a.kind { + if let ty::FnDef(def_id, _) = *a.kind() { if b_sig.unsafety() == hir::Unsafety::Normal && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() { @@ -771,7 +771,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let b = self.shallow_resolve(b); - match b.kind { + match b.kind() { ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => { // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` @@ -802,7 +802,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ) -> CoerceResult<'tcx> { debug!("coerce_unsafe_ptr(a={:?}, b={:?})", a, b); - let (is_ref, mt_a) = match a.kind { + let (is_ref, mt_a) = match *a.kind() { ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), ty::RawPtr(mt) => (false, mt), _ => return self.unify_and(a, b, identity), @@ -912,10 +912,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } }; - if is_capturing_closure(&prev_ty.kind) || is_capturing_closure(&new_ty.kind) { + if is_capturing_closure(&prev_ty.kind()) || is_capturing_closure(&new_ty.kind()) { (None, None) } else { - match (&prev_ty.kind, &new_ty.kind) { + match (&prev_ty.kind(), &new_ty.kind()) { (&ty::FnDef(..), &ty::FnDef(..)) => { // Don't reify if the function types have a LUB, i.e., they // are the same function and their parameters have a LUB. @@ -969,12 +969,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Reify both sides and return the reified fn pointer type. let fn_ptr = self.tcx.mk_fn_ptr(sig); - let prev_adjustment = match prev_ty.kind { + let prev_adjustment = match prev_ty.kind() { ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())), ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), _ => unreachable!(), }; - let next_adjustment = match new_ty.kind { + let next_adjustment = match new_ty.kind() { ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())), ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), _ => unreachable!(), @@ -1024,7 +1024,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let noop = match self.typeck_results.borrow().expr_adjustments(expr) { &[Adjustment { kind: Adjust::Deref(_), .. }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }] => { - match self.node_ty(expr.hir_id).kind { + match *self.node_ty(expr.hir_id).kind() { ty::Ref(_, _, mt_orig) => { let mutbl_adj: hir::Mutability = mutbl_adj.into(); // Reborrow that we can safely ignore, because @@ -1459,7 +1459,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) { - self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, fn_output); + self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output); } err } @@ -1467,6 +1467,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn add_impl_trait_explanation<'a>( &self, err: &mut DiagnosticBuilder<'a>, + cause: &ObligationCause<'tcx>, fcx: &FnCtxt<'a, 'tcx>, expected: Ty<'tcx>, sp: Span, @@ -1501,7 +1502,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if let hir::TyKind::OpaqueDef(..) = ty.kind { let ty = AstConv::ast_ty_to_ty(fcx, ty); // Get the `impl Trait`'s `DefId`. - if let ty::Opaque(def_id, _) = ty.kind { + if let ty::Opaque(def_id, _) = ty.kind() { let hir_id = fcx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); // Get the `impl Trait`'s `Item` so that we can get its trait bounds and // get the `Trait`'s `DefId`. @@ -1523,10 +1524,30 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { }; if has_impl { if is_object_safe { - err.help(&format!( - "you can instead return a boxed trait object using `Box`", - &snippet[5..] - )); + err.multipart_suggestion( + "you could change the return type to be a boxed trait object", + vec![ + (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box".to_string()), + ], + Applicability::MachineApplicable, + ); + let sugg = vec![sp, cause.span] + .into_iter() + .flat_map(|sp| { + vec![ + (sp.shrink_to_lo(), "Box::new(".to_string()), + (sp.shrink_to_hi(), ")".to_string()), + ] + .into_iter() + }) + .collect::>(); + err.multipart_suggestion( + "if you change the return type to expect trait objects, box the returned \ + expressions", + sugg, + Applicability::MaybeIncorrect, + ); } else { err.help(&format!( "if the trait `{}` were object safe, you could return a boxed trait object", @@ -1535,14 +1556,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } err.note(trait_obj_msg); } - err.help("alternatively, create a new `enum` with a variant for each returned type"); + err.help("you could instead create a new `enum` with a variant for each returned type"); } fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) { if let hir::FnRetTy::Return(ty) = fn_decl.output { let ty = AstConv::ast_ty_to_ty(fcx, ty); - if let ty::Dynamic(..) = ty.kind { + if let ty::Dynamic(..) = ty.kind() { return true; } } diff --git a/src/librustc_typeck/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs similarity index 98% rename from src/librustc_typeck/check/compare_method.rs rename to compiler/rustc_typeck/src/check/compare_method.rs index 7adcd7b472..7aa54e0ebc 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1,3 +1,4 @@ +use crate::errors::LifetimesOrBoundsMismatchOnTrait; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -201,11 +202,8 @@ fn compare_predicate_entailment<'tcx>( // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id); - let param_env = ty::ParamEnv::new( - tcx.intern_predicates(&hybrid_preds.predicates), - Reveal::UserFacing, - None, - ); + let param_env = + ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( tcx, impl_m.def_id, @@ -366,24 +364,18 @@ fn check_region_bounds_on_impl_item<'tcx>( let item_kind = assoc_item_kind_str(impl_m); let def_span = tcx.sess.source_map().guess_head_span(span); let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span); - let mut err = struct_span_err!( - tcx.sess, + let generics_span = if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) { + let def_sp = tcx.sess.source_map().guess_head_span(sp); + Some(tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp)) + } else { + None + }; + tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait { span, - E0195, - "lifetime parameters or bounds on {} `{}` do not match the trait declaration", item_kind, - impl_m.ident, - ); - err.span_label(span, &format!("lifetimes do not match {} in trait", item_kind)); - if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) { - let def_sp = tcx.sess.source_map().guess_head_span(sp); - let sp = tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp); - err.span_label( - sp, - &format!("lifetimes in impl do not match this {} in trait", item_kind), - ); - } - err.emit(); + ident: impl_m.ident, + generics_span, + }); return Err(ErrorReported); } @@ -1125,11 +1117,8 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); - let param_env = ty::ParamEnv::new( - tcx.intern_predicates(&hybrid_preds.predicates), - Reveal::UserFacing, - None, - ); + let param_env = + ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( tcx, impl_ty.def_id, @@ -1232,7 +1221,7 @@ fn compare_projection_bounds<'tcx>( }) .to_predicate(tcx), ); - ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None) + ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing) }; tcx.infer_ctxt().enter(move |infcx| { diff --git a/src/librustc_typeck/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs similarity index 97% rename from src/librustc_typeck/check/demand.rs rename to compiler/rustc_typeck/src/check/demand.rs index 5dc5480c33..3e66885448 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -117,11 +117,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - // Checks that the type of `expr` can be coerced to `expected`. - // - // 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". + /// Checks that the type of `expr` can be coerced to `expected`. + /// + /// 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". pub fn demand_coerce_diag( &self, expr: &hir::Expr<'_>, @@ -186,7 +185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, expr_ty: Ty<'tcx>, ) { - if let ty::Adt(expected_adt, substs) = expected.kind { + if let ty::Adt(expected_adt, substs) = expected.kind() { if !expected_adt.is_enum() { return; } @@ -362,15 +361,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn replace_prefix(&self, s: A, old: B, new: C) -> Option - where - A: AsRef, - B: AsRef, - C: AsRef, - { - let s = s.as_ref(); - let old = old.as_ref(); - if s.starts_with(old) { Some(new.as_ref().to_owned() + &s[old.len()..]) } else { None } + fn replace_prefix(&self, s: &str, old: &str, new: &str) -> Option { + if let Some(stripped) = s.strip_prefix(old) { + Some(new.to_string() + stripped) + } else { + None + } } /// This function is used to determine potential "simple" improvements or users' errors and @@ -413,12 +409,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `ExprKind::DropTemps` is semantically irrelevant for these suggestions. let expr = expr.peel_drop_temps(); - match (&expr.kind, &expected.kind, &checked_ty.kind) { - (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) { + match (&expr.kind, expected.kind(), checked_ty.kind()) { + (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) { (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(src, "b\"", "\"") { + if let Some(src) = self.replace_prefix(&src, "b\"", "\"") { return Some(( sp, "consider removing the leading `b`", @@ -432,7 +428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(src, "\"", "b\"") { + if let Some(src) = self.replace_prefix(&src, "\"", "b\"") { return Some(( sp, "consider adding a leading `b`", @@ -557,7 +553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(src, "&", "") { + if let Some(src) = self.replace_prefix(&src, "&", "") { return Some(( sp, "consider removing the borrow", @@ -594,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match mutbl_a { hir::Mutability::Mut => { if let Some(s) = - self.replace_prefix(src, "&mut ", new_prefix) + self.replace_prefix(&src, "&mut ", &new_prefix) { Some((s, Applicability::MachineApplicable)) } else { @@ -603,7 +599,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } hir::Mutability::Not => { if let Some(s) = - self.replace_prefix(src, "&", new_prefix) + self.replace_prefix(&src, "&", &new_prefix) { Some((s, Applicability::Unspecified)) } else { @@ -617,7 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match mutbl_a { hir::Mutability::Mut => { if let Some(s) = - self.replace_prefix(src, "&mut ", new_prefix) + self.replace_prefix(&src, "&mut ", &new_prefix) { Some((s, Applicability::MachineApplicable)) } else { @@ -626,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } hir::Mutability::Not => { if let Some(s) = - self.replace_prefix(src, "&", new_prefix) + self.replace_prefix(&src, "&", &new_prefix) { Some((s, Applicability::MachineApplicable)) } else { @@ -774,7 +770,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suffix_suggestion = with_opt_paren(&format_args!( "{}{}", if matches!( - (&expected_ty.kind, &checked_ty.kind), + (&expected_ty.kind(), &checked_ty.kind()), (ty::Int(_) | ty::Uint(_), ty::Float(_)) ) { // Remove fractional part from literal, for example `42.0f32` into `42` @@ -790,7 +786,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let is_negative_int = |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnNeg, ..)); - let is_uint = |ty: Ty<'_>| matches!(ty.kind, ty::Uint(..)); + let is_uint = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(..)); let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id); @@ -857,7 +853,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion(expr.span, msg, suggestion, Applicability::MachineApplicable); }; - match (&expected_ty.kind, &checked_ty.kind) { + match (&expected_ty.kind(), &checked_ty.kind()) { (&ty::Int(ref exp), &ty::Int(ref found)) => { let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) { diff --git a/compiler/rustc_typeck/src/check/diverges.rs b/compiler/rustc_typeck/src/check/diverges.rs new file mode 100644 index 0000000000..963a93a95c --- /dev/null +++ b/compiler/rustc_typeck/src/check/diverges.rs @@ -0,0 +1,78 @@ +use rustc_span::source_map::DUMMY_SP; +use rustc_span::{self, Span}; +use std::{cmp, ops}; + +/// Tracks whether executing a node may exit normally (versus +/// return/break/panic, which "diverge", leaving dead code in their +/// wake). Tracked semi-automatically (through type variables marked +/// as diverging), with some manual adjustments for control-flow +/// primitives (approximating a CFG). +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Diverges { + /// Potentially unknown, some cases converge, + /// others require a CFG to determine them. + Maybe, + + /// Definitely known to diverge and therefore + /// not reach the next sibling or its parent. + Always { + /// The `Span` points to the expression + /// that caused us to diverge + /// (e.g. `return`, `break`, etc). + span: Span, + /// In some cases (e.g. a `match` expression + /// where all arms diverge), we may be + /// able to provide a more informative + /// message to the user. + /// If this is `None`, a default message + /// will be generated, which is suitable + /// for most cases. + custom_note: Option<&'static str>, + }, + + /// Same as `Always` but with a reachability + /// warning already emitted. + WarnedAlways, +} + +// Convenience impls for combining `Diverges`. + +impl ops::BitAnd for Diverges { + type Output = Self; + fn bitand(self, other: Self) -> Self { + cmp::min(self, other) + } +} + +impl ops::BitOr for Diverges { + type Output = Self; + fn bitor(self, other: Self) -> Self { + cmp::max(self, other) + } +} + +impl ops::BitAndAssign for Diverges { + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } +} + +impl ops::BitOrAssign for Diverges { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl Diverges { + /// Creates a `Diverges::Always` with the provided `span` and the default note message. + pub(super) fn always(span: Span) -> Diverges { + Diverges::Always { span, custom_note: None } + } + + pub(super) fn is_always(self) -> bool { + // Enum comparison ignores the + // contents of fields, so we just + // fill them in with garbage here. + self >= Diverges::Always { span: DUMMY_SP, custom_note: None } + } +} diff --git a/src/librustc_typeck/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs similarity index 99% rename from src/librustc_typeck/check/dropck.rs rename to compiler/rustc_typeck/src/check/dropck.rs index 434886538f..ae94a6df5f 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -34,7 +34,7 @@ use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorReported> { let dtor_self_type = tcx.type_of(drop_impl_did); let dtor_predicates = tcx.predicates_of(drop_impl_did); - match dtor_self_type.kind { + match dtor_self_type.kind() { ty::Adt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond( tcx, diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_typeck/src/check/expectation.rs new file mode 100644 index 0000000000..fd6fe1406c --- /dev/null +++ b/compiler/rustc_typeck/src/check/expectation.rs @@ -0,0 +1,117 @@ +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::ty::{self, Ty}; +use rustc_span::{self, Span}; + +use super::Expectation::*; +use super::FnCtxt; + +/// When type-checking an expression, we propagate downward +/// whatever type hint we are able in the form of an `Expectation`. +#[derive(Copy, Clone, Debug)] +pub enum Expectation<'tcx> { + /// We know nothing about what type this expression should have. + NoExpectation, + + /// This expression should have the type given (or some subtype). + ExpectHasType(Ty<'tcx>), + + /// This expression will be cast to the `Ty`. + ExpectCastableToType(Ty<'tcx>), + + /// This rvalue expression will be wrapped in `&` or `Box` and coerced + /// to `&Ty` or `Box`, respectively. `Ty` is `[A]` or `Trait`. + ExpectRvalueLikeUnsized(Ty<'tcx>), +} + +impl<'a, 'tcx> Expectation<'tcx> { + // Disregard "castable to" expectations because they + // can lead us astray. Consider for example `if cond + // {22} else {c} as u8` -- if we propagate the + // "castable to u8" constraint to 22, it will pick the + // type 22u8, which is overly constrained (c might not + // be a u8). In effect, the problem is that the + // "castable to" expectation is not the tightest thing + // we can say, so we want to drop it in this case. + // The tightest thing we can say is "must unify with + // else branch". Note that in the case of a "has type" + // constraint, this limitation does not hold. + + // If the expected type is just a type variable, then don't use + // an expected type. Otherwise, we might write parts of the type + // when checking the 'then' block which are incompatible with the + // 'else' branch. + pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + match *self { + ExpectHasType(ety) => { + let ety = fcx.shallow_resolve(ety); + if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } + } + ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), + _ => NoExpectation, + } + } + + /// Provides an expectation for an rvalue expression given an *optional* + /// hint, which is not required for type safety (the resulting type might + /// be checked higher up, as is the case with `&expr` and `box expr`), but + /// is useful in determining the concrete type. + /// + /// The primary use case is where the expected type is a fat pointer, + /// like `&[isize]`. For example, consider the following statement: + /// + /// let x: &[isize] = &[1, 2, 3]; + /// + /// In this case, the expected type for the `&[1, 2, 3]` expression is + /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the + /// expectation `ExpectHasType([isize])`, that would be too strong -- + /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. + /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced + /// to the type `&[isize]`. Therefore, we propagate this more limited hint, + /// which still is useful, because it informs integer literals and the like. + /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 + /// for examples of where this comes up,. + pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { + match fcx.tcx.struct_tail_without_normalization(ty).kind() { + ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty), + _ => ExpectHasType(ty), + } + } + + // Resolves `expected` by a single level if it is a variable. If + // there is no expected type or resolution is not possible (e.g., + // no constraints yet present), just returns `None`. + fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + match self { + NoExpectation => NoExpectation, + ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)), + ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)), + ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)), + } + } + + pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { + match self.resolve(fcx) { + NoExpectation => None, + ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), + } + } + + /// It sometimes happens that we want to turn an expectation into + /// a **hard constraint** (i.e., something that must be satisfied + /// for the program to type-check). `only_has_type` will return + /// such a constraint, if it exists. + pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { + match self.resolve(fcx) { + ExpectHasType(ty) => Some(ty), + NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, + } + } + + /// Like `only_has_type`, but instead of returning `None` if no + /// hard constraint exists, creates a fresh type variable. + pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { + self.only_has_type(fcx).unwrap_or_else(|| { + fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }) + }) + } +} diff --git a/src/librustc_typeck/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs similarity index 88% rename from src/librustc_typeck/check/expr.rs rename to compiler/rustc_typeck/src/check/expr.rs index 0e9f64c359..275f2ed7c8 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -14,8 +14,13 @@ use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExp use crate::check::FnCtxt; use crate::check::Needs; use crate::check::TupleArgumentsFlag::DontTupleArguments; +use crate::errors::{ + FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, + YieldExprOutsideOfGenerator, +}; use crate::type_error_struct; +use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; use rustc_ast as ast; use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; @@ -37,7 +42,7 @@ use rustc_middle::ty::{AdtKind, Visibility}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_trait_selection::traits::{self, ObligationCauseCode}; +use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::fmt::Display; @@ -296,7 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn check_expr_box(&self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>) -> Ty<'tcx> { - let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind { + let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind() { ty::Adt(def, _) if def.is_box() => Expectation::rvalue_hint(self, ty.boxed_ty()), _ => NoExpectation, }); @@ -346,7 +351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::UnOp::UnNot => { let result = self.check_user_unop(expr, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. - if !(oprnd_t.is_integral() || oprnd_t.kind == ty::Bool) { + if !(oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool) { oprnd_t = result; } } @@ -371,7 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { - match ty.kind { + match ty.kind() { ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { if oprnd.is_syntactic_place_expr() { // Places may legitimately have unsized types. @@ -434,19 +439,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is maybe too permissive, since it allows // `let u = &raw const Box::new((1,)).0`, which creates an // immediately dangling raw pointer. - self.typeck_results.borrow().adjustments().get(base.hir_id).map_or(false, |x| { - x.iter().any(|adj| if let Adjust::Deref(_) = adj.kind { true } else { false }) - }) + self.typeck_results + .borrow() + .adjustments() + .get(base.hir_id) + .map_or(false, |x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_)))) }); if !is_named { - struct_span_err!( - self.tcx.sess, - oprnd.span, - E0745, - "cannot take address of a temporary" - ) - .span_label(oprnd.span, "temporary value") - .emit(); + self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span }) } } @@ -473,7 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; - if let ty::FnDef(..) = ty.kind { + if let ty::FnDef(..) = ty.kind() { let fn_sig = ty.fn_sig(tcx); if !tcx.features().unsized_locals { // We want to remove some Sized bounds from std functions, @@ -665,13 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { if self.ret_coercion.is_none() { - struct_span_err!( - self.tcx.sess, - expr.span, - E0572, - "return statement outside of function body", - ) - .emit(); + self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span }); } else if let Some(ref e) = expr_opt { if self.ret_coercion_span.borrow().is_none() { *self.ret_coercion_span.borrow_mut() = Some(e.span); @@ -740,6 +734,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_span: &Span, ) { if !lhs.is_syntactic_place_expr() { + // FIXME: Make this use SessionDiagnostic once error codes can be dynamically set. let mut err = self.tcx.sess.struct_span_err_with_code( *expr_span, "invalid left-hand side of assignment", @@ -764,9 +759,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs: &'tcx hir::Expr<'tcx>, span: &Span, ) -> Ty<'tcx> { - let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); - let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs)); - let expected_ty = expected.coercion_target_type(self, expr.span); if expected_ty == self.tcx.types.bool { // The expected type is `bool` but this will result in `()` so we can reasonably @@ -774,20 +766,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The likely cause of this is `if foo = bar { .. }`. let actual_ty = self.tcx.mk_unit(); let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); - let msg = "try comparing for equality"; - let left = self.tcx.sess.source_map().span_to_snippet(lhs.span); - let right = self.tcx.sess.source_map().span_to_snippet(rhs.span); - if let (Ok(left), Ok(right)) = (left, right) { - let help = format!("{} == {}", left, right); - err.span_suggestion(expr.span, msg, help, Applicability::MaybeIncorrect); + let lhs_ty = self.check_expr(&lhs); + let rhs_ty = self.check_expr(&rhs); + let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) { + (Applicability::MachineApplicable, true) + } else { + (Applicability::MaybeIncorrect, false) + }; + if !lhs.is_syntactic_place_expr() { + // Do not suggest `if let x = y` as `==` is way more likely to be the intention. + if let hir::Node::Expr(hir::Expr { + kind: + ExprKind::Match( + _, + _, + hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar, + ), + .. + }) = self.tcx.hir().get( + self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(expr.hir_id)), + ) { + // Likely `if let` intended. + err.span_suggestion_verbose( + expr.span.shrink_to_lo(), + "you might have meant to use pattern matching", + "let ".to_string(), + applicability, + ); + } + } + if eq { + err.span_suggestion_verbose( + *span, + "you might have meant to compare for equality", + "==".to_string(), + applicability, + ); + } + + if self.sess().if_let_suggestions.borrow().get(&expr.span).is_some() { + // We already emitted an `if let` suggestion due to an identifier not found. + err.delay_as_bug(); } else { - err.help(msg); + err.emit(); } - err.emit(); - } else { - self.check_lhs_assignable(lhs, "E0070", span); + return self.tcx.ty_error(); } + self.check_lhs_assignable(lhs, "E0070", span); + + let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); + let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs)); + self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); if lhs_ty.references_error() || rhs_ty.references_error() { @@ -922,7 +952,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error, Some(args), ) { - if let ty::Adt(..) = rcvr_t.kind { + if let ty::Adt(..) = rcvr_t.kind() { // Try alternative arbitrary self types that could fulfill this call. // FIXME: probe for all types that *could* be arbitrary self-types, not // just this list. @@ -973,7 +1003,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_ty = if !args.is_empty() { let coerce_to = expected .to_option(self) - .and_then(|uty| match uty.kind { + .and_then(|uty| match *uty.kind() { ty::Array(ty, _) | ty::Slice(ty) => Some(ty), _ => None, }) @@ -1011,7 +1041,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let count = self.to_const(count); let uty = match expected { - ExpectHasType(uty) => match uty.kind { + ExpectHasType(uty) => match *uty.kind() { ty::Array(ty, _) | ty::Slice(ty) => Some(ty), _ => None, }, @@ -1048,7 +1078,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let flds = expected.only_has_type(self).and_then(|ty| { let ty = self.resolve_vars_with_obligations(ty); - match ty.kind { + match ty.kind() { ty::Tuple(ref flds) => Some(&flds[..]), _ => None, } @@ -1091,14 +1121,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Prohibit struct expressions when non-exhaustive flag is set. let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); if !adt.did.is_local() && variant.is_field_list_non_exhaustive() { - struct_span_err!( - self.tcx.sess, - expr.span, - E0639, - "cannot create non-exhaustive {} using struct expression", - adt.variant_descr() - ) - .emit(); + self.tcx + .sess + .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() }); } let error_happened = self.check_expr_struct_fields( @@ -1116,7 +1141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // when certain fields are assumed to exist that in fact do not. if !error_happened { self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {}); - match adt_ty.kind { + match adt_ty.kind() { ty::Adt(adt, substs) if adt.is_struct() => { let fru_field_types = adt .non_enum_variant() @@ -1136,13 +1161,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .insert(expr.hir_id, fru_field_types); } _ => { - struct_span_err!( - self.tcx.sess, - base_expr.span, - E0436, - "functional record update syntax requires a struct" - ) - .emit(); + self.tcx + .sess + .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); } } } @@ -1171,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // re-link the regions that EIfEO can erase. self.demand_eqtype(span, adt_ty_hint, adt_ty); - let (substs, adt_kind, kind_name) = match &adt_ty.kind { + let (substs, adt_kind, kind_name) = match &adt_ty.kind() { &ty::Adt(adt, substs) => (substs, adt.adt_kind(), adt.variant_descr()), _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields"), }; @@ -1205,18 +1226,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { error_happened = true; if let Some(prev_span) = seen_fields.get(&ident) { - let mut err = struct_span_err!( - self.tcx.sess, - field.ident.span, - E0062, - "field `{}` specified more than once", - ident - ); - - err.span_label(field.ident.span, "used more than once"); - err.span_label(*prev_span, format!("first use of `{}`", ident)); - - err.emit(); + tcx.sess.emit_err(FieldMultiplySpecifiedInInitializer { + span: field.ident.span, + prev_span: *prev_span, + ident, + }); } else { self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span); } @@ -1235,42 +1249,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.span_err(span, "union expressions should have exactly one field"); } } else if check_completeness && !error_happened && !remaining_fields.is_empty() { - let len = remaining_fields.len(); - - let mut displayable_field_names = - remaining_fields.keys().map(|ident| ident.as_str()).collect::>(); - - displayable_field_names.sort(); + let no_accessible_remaining_fields = remaining_fields + .iter() + .find(|(_, (_, field))| { + field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) + }) + .is_none(); - let truncated_fields_error = if len <= 3 { - String::new() + if no_accessible_remaining_fields { + self.report_no_accessible_fields(adt_ty, span); } else { - format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" }) - }; - - let remaining_fields_names = displayable_field_names - .iter() - .take(3) - .map(|n| format!("`{}`", n)) - .collect::>() - .join(", "); - - struct_span_err!( - tcx.sess, - span, - E0063, - "missing field{} {}{} in initializer of `{}`", - pluralize!(remaining_fields.len()), - remaining_fields_names, - truncated_fields_error, - adt_ty - ) - .span_label( - span, - format!("missing {}{}", remaining_fields_names, truncated_fields_error), - ) - .emit(); + self.report_missing_field(adt_ty, span, remaining_fields); + } } + error_happened } @@ -1287,6 +1279,79 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Report an error for a struct field expression when there are fields which aren't provided. + /// + /// ```ignore (diagnostic) + /// error: missing field `you_can_use_this_field` in initializer of `foo::Foo` + /// --> src/main.rs:8:5 + /// | + /// 8 | foo::Foo {}; + /// | ^^^^^^^^ missing `you_can_use_this_field` + /// + /// error: aborting due to previous error + /// ``` + fn report_missing_field( + &self, + adt_ty: Ty<'tcx>, + span: Span, + remaining_fields: FxHashMap, + ) { + let tcx = self.tcx; + let len = remaining_fields.len(); + + let mut displayable_field_names = + remaining_fields.keys().map(|ident| ident.as_str()).collect::>(); + + displayable_field_names.sort(); + + let truncated_fields_error = if len <= 3 { + String::new() + } else { + format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" }) + }; + + let remaining_fields_names = displayable_field_names + .iter() + .take(3) + .map(|n| format!("`{}`", n)) + .collect::>() + .join(", "); + + struct_span_err!( + tcx.sess, + span, + E0063, + "missing field{} {}{} in initializer of `{}`", + pluralize!(remaining_fields.len()), + remaining_fields_names, + truncated_fields_error, + adt_ty + ) + .span_label(span, format!("missing {}{}", remaining_fields_names, truncated_fields_error)) + .emit(); + } + + /// Report an error for a struct field expression when there are no visible fields. + /// + /// ```ignore (diagnostic) + /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields + /// --> src/main.rs:8:5 + /// | + /// 8 | foo::Foo {}; + /// | ^^^^^^^^ + /// + /// error: aborting due to previous error + /// ``` + fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) { + self.tcx.sess.span_err( + span, + &format!( + "cannot construct `{}` with struct literal syntax due to inaccessible fields", + adt_ty, + ), + ); + } + fn report_unknown_field( &self, ty: Ty<'tcx>, @@ -1296,13 +1361,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind_name: &str, ty_span: Span, ) { - if variant.recovered { + if variant.is_recovered() { self.set_tainted_by_errors(); return; } let mut err = self.type_error_struct_with_diag( field.ident.span, - |actual| match ty.kind { + |actual| match ty.kind() { ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!( self.tcx.sess, field.ident.span, @@ -1352,7 +1417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } else { - match ty.kind { + match ty.kind() { ty::Adt(adt, ..) => { if adt.is_enum() { err.span_label( @@ -1439,7 +1504,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, _)) = autoderef.next() { - match base_t.kind { + match base_t.kind() { ty::Adt(base_def, substs) if !base_def.is_enum() => { debug!("struct named {:?}", base_t); let (ident, def_scope) = @@ -1509,6 +1574,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx().ty_error() } + fn suggest_await_on_field_access( + &self, + err: &mut DiagnosticBuilder<'_>, + field_ident: Ident, + base: &'tcx hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + def_id: DefId, + ) { + let param_env = self.tcx().param_env(def_id); + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + // Future::Output + let item_def_id = + self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id; + + let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); + debug!("suggest_await_on_field_access: projection_ty={:?}", projection_ty); + + let cause = self.misc(expr.span); + let mut selcx = SelectionContext::new(&self.infcx); + + let mut obligations = vec![]; + if let Some(projection_ty) = projection_ty { + let normalized_ty = rustc_trait_selection::traits::normalize_projection_type( + &mut selcx, + param_env, + projection_ty, + cause, + 0, + &mut obligations, + ); + debug!( + "suggest_await_on_field_access: normalized_ty={:?}, ty_kind={:?}", + self.resolve_vars_if_possible(&normalized_ty), + normalized_ty.kind(), + ); + if let ty::Adt(def, _) = normalized_ty.kind() { + // no field access on enum type + if !def.is_enum() { + if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) + { + err.span_suggestion_verbose( + base.span.shrink_to_hi(), + "consider awaiting before field access", + ".await".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + fn ban_nonexisting_field( &self, field: Ident, @@ -1516,9 +1633,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, expr_t: Ty<'tcx>, ) { + debug!( + "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}", + field, base, expr, expr_t + ); let mut err = self.no_such_field_err(field.span, field, expr_t); - match expr_t.peel_refs().kind { + match *expr_t.peel_refs().kind() { ty::Array(_, len) => { self.maybe_suggest_array_indexing(&mut err, expr, base, field, len); } @@ -1531,6 +1652,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Param(param_ty) => { self.point_at_param_definition(&mut err, param_ty); } + ty::Opaque(def_id, _) => { + self.suggest_await_on_field_access(&mut err, field, base, expr, def_id); + } _ => {} } @@ -1735,7 +1859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_t ); // Try to give some advice about indexing tuples. - if let ty::Tuple(..) = base_t.kind { + if let ty::Tuple(..) = base_t.kind() { let mut needs_note = true; // If the index is an integer, we can show the actual // fixed expression: @@ -1788,13 +1912,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.mk_unit() } _ => { - struct_span_err!( - self.tcx.sess, - expr.span, - E0627, - "yield expression outside of generator literal" - ) - .emit(); + self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span }); self.tcx.mk_unit() } } @@ -1820,7 +1938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // function. if is_input { let ty = self.structurally_resolved_type(expr.span, &ty); - match ty.kind { + match *ty.kind() { ty::FnDef(..) => { let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx)); self.demand_coerce(expr, ty, fnptr_ty, None, AllowTwoPhase::No); @@ -1868,7 +1986,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { - Some(match ty.kind { + Some(match ty.kind() { ty::Bool => "true", ty::Char => "'a'", ty::Int(_) | ty::Uint(_) => "42", diff --git a/src/librustc_typeck/check/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs similarity index 52% rename from src/librustc_typeck/check/mod.rs rename to compiler/rustc_typeck/src/check/fn_ctxt.rs index 031d48f8a6..79d6c7dbfd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt.rs @@ -1,3076 +1,154 @@ // ignore-tidy-filelength - -/*! - -# typeck: check phase - -Within the check phase of type check, we check each item one at a time -(bodies of function expressions are checked as part of the containing -function). Inference is used to supply types wherever they are unknown. - -By far the most complex case is checking the body of a function. This -can be broken down into several distinct phases: - -- gather: creates type variables to represent the type of each local - variable and pattern binding. - -- main: the main pass does the lion's share of the work: it - determines the types of all expressions, resolves - methods, checks for most invalid conditions, and so forth. In - some cases, where a type is unknown, it may create a type or region - variable and use that as the type of an expression. - - In the process of checking, various constraints will be placed on - these type variables through the subtyping relationships requested - through the `demand` module. The `infer` module is in charge - of resolving those constraints. - -- regionck: after main is complete, the regionck pass goes over all - types looking for regions and making sure that they did not escape - into places they are not in scope. This may also influence the - final assignments of the various region variables if there is some - flexibility. - -- writeback: writes the final types within a function body, replacing - type variables with their final inferred types. These final types - are written into the `tcx.node_types` table, which should *never* contain - any reference to a type variable. - -## Intermediate types - -While type checking a function, the intermediate types for the -expressions, blocks, and so forth contained within the function are -stored in `fcx.node_types` and `fcx.node_substs`. These types -may contain unresolved type variables. After type checking is -complete, the functions in the writeback module are used to take the -types from this table, resolve them, and then write them into their -permanent home in the type context `tcx`. - -This means that during inferencing you should use `fcx.write_ty()` -and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of -nodes within the function. - -The types of top-level items, which never contain unbound type -variables, are stored directly into the `tcx` typeck_results. - -N.B., a type variable is not the same thing as a type parameter. A -type variable is rather an "instance" of a type parameter: that is, -given a generic function `fn foo(t: T)`: while checking the -function `foo`, the type `ty_param(0)` refers to the type `T`, which -is treated in abstract. When `foo()` is called, however, `T` will be -substituted for a fresh type variable `N`. This variable will -eventually be resolved to some concrete type (which might itself be -type parameter). - -*/ - -pub mod _match; -mod autoderef; -mod callee; -pub mod cast; -mod closure; -pub mod coercion; -mod compare_method; -pub mod demand; -pub mod dropck; -mod expr; -mod generator_interior; -pub mod intrinsic; -pub mod method; -mod op; -mod pat; -mod place_op; -mod regionck; -mod upvar; -mod wfcheck; -pub mod writeback; - +// FIXME: This file seems to have too much functionality wrapped into it, +// leading to it being too long. +// Splitting this file may involve abstracting functionality into other files. + +use super::callee::{self, DeferredCallResolution}; +use super::coercion::{CoerceMany, DynamicCoerceMany}; +use super::method::{self, MethodCallee, SelfSource}; +use super::Expectation::*; +use super::TupleArgumentsFlag::*; +use super::{ + potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, EnclosingBreakables, + Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, UnsafetyState, +}; use crate::astconv::{ AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, }; + use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; -use rustc_attr as attr; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::ErrorReported; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath}; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::Idx; -use rustc_infer::infer; +use rustc_hir::{ExprKind, GenericArg, ItemKind, Node, QPath}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::infer::{self, InferOk, InferResult}; use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts}; -use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; -use rustc_middle::ty::WithConstness; -use rustc_middle::ty::{self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind}; -use rustc_middle::ty::{RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType}; -use rustc_session::config::{self, EntryFnType}; -use rustc_session::lint; -use rustc_session::parse::feature_err; -use rustc_session::Session; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::{ + self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, +}; +use rustc_middle::ty::{ + self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, ToPolyTraitRef, + ToPredicate, Ty, TyCtxt, UserType, +}; +use rustc_session::{lint, Session}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{self, BytePos, MultiSpan, Span}; -use rustc_target::abi::VariantIdx; -use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl}; -use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; -use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, }; -use std::cell::{Cell, Ref, RefCell, RefMut}; -use std::cmp; +use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::iter; use std::mem::replace; -use std::ops::{self, Deref}; +use std::ops::Deref; use std::slice; -use crate::require_c_abi_if_c_variadic; -use crate::util::common::indenter; - -use self::callee::DeferredCallResolution; -use self::coercion::{CoerceMany, DynamicCoerceMany}; -use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; -use self::method::{MethodCallee, SelfSource}; -pub use self::Expectation::*; -use self::TupleArgumentsFlag::*; - -#[macro_export] -macro_rules! type_error_struct { - ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ - if $typ.references_error() { - $session.diagnostic().struct_dummy() - } else { - rustc_errors::struct_span_err!($session, $span, $code, $($message)*) - } - }) -} - -/// The type of a local binding, including the revealed type for anon types. -#[derive(Copy, Clone, Debug)] -pub struct LocalTy<'tcx> { - decl_ty: Ty<'tcx>, - revealed_ty: Ty<'tcx>, -} - -/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. -#[derive(Copy, Clone)] -struct MaybeInProgressTables<'a, 'tcx> { - maybe_typeck_results: Option<&'a RefCell>>, -} - -impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { - fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" - ), - } - } - - fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow_mut(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" - ), - } - } -} - -/// Closures defined within the function. For example: -/// -/// fn foo() { -/// bar(move|| { ... }) -/// } -/// -/// Here, the function `foo()` and the closure passed to -/// `bar()` will each have their own `FnCtxt`, but they will -/// share the inherited fields. -pub struct Inherited<'a, 'tcx> { - infcx: InferCtxt<'a, 'tcx>, - - typeck_results: MaybeInProgressTables<'a, 'tcx>, - - locals: RefCell>>, - - fulfillment_cx: RefCell>>, - - // Some additional `Sized` obligations badly affect type inference. - // These obligations are added in a later stage of typeck. - deferred_sized_obligations: RefCell, Span, traits::ObligationCauseCode<'tcx>)>>, - - // When we process a call like `c()` where `c` is a closure type, - // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or - // `FnOnce` closure. In that case, we defer full resolution of the - // call until upvar inference can kick in and make the - // decision. We keep these deferred resolutions grouped by the - // def-id of the closure, so that once we decide, we can easily go - // back and process them. - deferred_call_resolutions: RefCell>>>, - - deferred_cast_checks: RefCell>>, - - deferred_generator_interiors: RefCell, hir::GeneratorKind)>>, - - // Opaque types found in explicit return types and their - // associated fresh inference variable. Writeback resolves these - // variables to get the concrete type, which can be used to - // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. - opaque_types: RefCell>>, - - /// A map from inference variables created from opaque - /// type instantiations (`ty::Infer`) to the actual opaque - /// type (`ty::Opaque`). Used during fallback to map unconstrained - /// opaque type inference variables to their corresponding - /// opaque type. - opaque_types_vars: RefCell, Ty<'tcx>>>, - - body_id: Option, -} - -impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { - type Target = InferCtxt<'a, 'tcx>; - fn deref(&self) -> &Self::Target { - &self.infcx - } -} - -/// When type-checking an expression, we propagate downward -/// whatever type hint we are able in the form of an `Expectation`. -#[derive(Copy, Clone, Debug)] -pub enum Expectation<'tcx> { - /// We know nothing about what type this expression should have. - NoExpectation, - - /// This expression should have the type given (or some subtype). - ExpectHasType(Ty<'tcx>), - - /// This expression will be cast to the `Ty`. - ExpectCastableToType(Ty<'tcx>), - - /// This rvalue expression will be wrapped in `&` or `Box` and coerced - /// to `&Ty` or `Box`, respectively. `Ty` is `[A]` or `Trait`. - ExpectRvalueLikeUnsized(Ty<'tcx>), -} - -impl<'a, 'tcx> Expectation<'tcx> { - // Disregard "castable to" expectations because they - // can lead us astray. Consider for example `if cond - // {22} else {c} as u8` -- if we propagate the - // "castable to u8" constraint to 22, it will pick the - // type 22u8, which is overly constrained (c might not - // be a u8). In effect, the problem is that the - // "castable to" expectation is not the tightest thing - // we can say, so we want to drop it in this case. - // The tightest thing we can say is "must unify with - // else branch". Note that in the case of a "has type" - // constraint, this limitation does not hold. - - // If the expected type is just a type variable, then don't use - // an expected type. Otherwise, we might write parts of the type - // when checking the 'then' block which are incompatible with the - // 'else' branch. - fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { - match *self { - ExpectHasType(ety) => { - let ety = fcx.shallow_resolve(ety); - if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } - } - ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), - _ => NoExpectation, - } - } - - /// Provides an expectation for an rvalue expression given an *optional* - /// hint, which is not required for type safety (the resulting type might - /// be checked higher up, as is the case with `&expr` and `box expr`), but - /// is useful in determining the concrete type. - /// - /// The primary use case is where the expected type is a fat pointer, - /// like `&[isize]`. For example, consider the following statement: - /// - /// let x: &[isize] = &[1, 2, 3]; - /// - /// In this case, the expected type for the `&[1, 2, 3]` expression is - /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the - /// expectation `ExpectHasType([isize])`, that would be too strong -- - /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. - /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced - /// to the type `&[isize]`. Therefore, we propagate this more limited hint, - /// which still is useful, because it informs integer literals and the like. - /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 - /// for examples of where this comes up,. - fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { - match fcx.tcx.struct_tail_without_normalization(ty).kind { - ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty), - _ => ExpectHasType(ty), - } - } - - // Resolves `expected` by a single level if it is a variable. If - // there is no expected type or resolution is not possible (e.g., - // no constraints yet present), just returns `None`. - fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { - match self { - NoExpectation => NoExpectation, - ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)), - ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)), - ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)), - } - } - - fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { - match self.resolve(fcx) { - NoExpectation => None, - ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), - } - } - - /// It sometimes happens that we want to turn an expectation into - /// a **hard constraint** (i.e., something that must be satisfied - /// for the program to type-check). `only_has_type` will return - /// such a constraint, if it exists. - fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { - match self.resolve(fcx) { - ExpectHasType(ty) => Some(ty), - NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, - } - } - - /// Like `only_has_type`, but instead of returning `None` if no - /// hard constraint exists, creates a fresh type variable. - fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { - self.only_has_type(fcx).unwrap_or_else(|| { - fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }) - }) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Needs { - MutPlace, - None, -} - -impl Needs { - fn maybe_mut_place(m: hir::Mutability) -> Self { - match m { - hir::Mutability::Mut => Needs::MutPlace, - hir::Mutability::Not => Needs::None, - } - } -} - -#[derive(Copy, Clone)] -pub struct UnsafetyState { - pub def: hir::HirId, - pub unsafety: hir::Unsafety, - pub unsafe_push_count: u32, - from_fn: bool, -} - -impl UnsafetyState { - pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState { - UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true } - } - - pub fn recurse(&mut self, blk: &hir::Block<'_>) -> UnsafetyState { - use hir::BlockCheckMode; - match self.unsafety { - // If this unsafe, then if the outer function was already marked as - // unsafe we shouldn't attribute the unsafe'ness to the block. This - // way the block can be warned about instead of ignoring this - // extraneous block (functions are never warned about). - hir::Unsafety::Unsafe if self.from_fn => *self, - - unsafety => { - let (unsafety, def, count) = match blk.rules { - BlockCheckMode::PushUnsafeBlock(..) => { - (unsafety, blk.hir_id, self.unsafe_push_count.checked_add(1).unwrap()) - } - BlockCheckMode::PopUnsafeBlock(..) => { - (unsafety, blk.hir_id, self.unsafe_push_count.checked_sub(1).unwrap()) - } - BlockCheckMode::UnsafeBlock(..) => { - (hir::Unsafety::Unsafe, blk.hir_id, self.unsafe_push_count) - } - BlockCheckMode::DefaultBlock => (unsafety, self.def, self.unsafe_push_count), - }; - UnsafetyState { def, unsafety, unsafe_push_count: count, from_fn: false } - } - } - } -} - -#[derive(Debug, Copy, Clone)] -pub enum PlaceOp { - Deref, - Index, -} - -/// Tracks whether executing a node may exit normally (versus -/// return/break/panic, which "diverge", leaving dead code in their -/// wake). Tracked semi-automatically (through type variables marked -/// as diverging), with some manual adjustments for control-flow -/// primitives (approximating a CFG). -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum Diverges { - /// Potentially unknown, some cases converge, - /// others require a CFG to determine them. - Maybe, - - /// Definitely known to diverge and therefore - /// not reach the next sibling or its parent. - Always { - /// The `Span` points to the expression - /// that caused us to diverge - /// (e.g. `return`, `break`, etc). - span: Span, - /// In some cases (e.g. a `match` expression - /// where all arms diverge), we may be - /// able to provide a more informative - /// message to the user. - /// If this is `None`, a default message - /// will be generated, which is suitable - /// for most cases. - custom_note: Option<&'static str>, - }, - - /// Same as `Always` but with a reachability - /// warning already emitted. - WarnedAlways, -} - -// Convenience impls for combining `Diverges`. - -impl ops::BitAnd for Diverges { - type Output = Self; - fn bitand(self, other: Self) -> Self { - cmp::min(self, other) - } -} - -impl ops::BitOr for Diverges { - type Output = Self; - fn bitor(self, other: Self) -> Self { - cmp::max(self, other) - } -} - -impl ops::BitAndAssign for Diverges { - fn bitand_assign(&mut self, other: Self) { - *self = *self & other; - } -} - -impl ops::BitOrAssign for Diverges { - fn bitor_assign(&mut self, other: Self) { - *self = *self | other; - } -} - -impl Diverges { - /// Creates a `Diverges::Always` with the provided `span` and the default note message. - fn always(span: Span) -> Diverges { - Diverges::Always { span, custom_note: None } - } - - fn is_always(self) -> bool { - // Enum comparison ignores the - // contents of fields, so we just - // fill them in with garbage here. - self >= Diverges::Always { span: DUMMY_SP, custom_note: None } - } -} - -pub struct BreakableCtxt<'tcx> { - may_break: bool, - - // this is `null` for loops where break with a value is illegal, - // such as `while`, `for`, and `while let` - coerce: Option>, -} - -pub struct EnclosingBreakables<'tcx> { - stack: Vec>, - by_id: HirIdMap, -} - -impl<'tcx> EnclosingBreakables<'tcx> { - fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { - self.opt_find_breakable(target_id).unwrap_or_else(|| { - bug!("could not find enclosing breakable with id {}", target_id); - }) - } - - fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> { - match self.by_id.get(&target_id) { - Some(ix) => Some(&mut self.stack[*ix]), - None => None, - } - } -} - pub struct FnCtxt<'a, 'tcx> { - body_id: hir::HirId, + pub(super) body_id: hir::HirId, /// The parameter environment used for proving trait obligations /// in this function. This can change when we descend into /// closures (as they bring new things into scope), hence it is /// not part of `Inherited` (as of the time of this writing, /// closures do not yet change the environment, but they will - /// eventually). - param_env: ty::ParamEnv<'tcx>, - - /// Number of errors that had been reported when we started - /// checking this function. On exit, if we find that *more* errors - /// have been reported, we will skip regionck and other work that - /// expects the types within the function to be consistent. - // FIXME(matthewjasper) This should not exist, and it's not correct - // if type checking is run in parallel. - err_count_on_creation: usize, - - /// If `Some`, this stores coercion information for returned - /// expressions. If `None`, this is in a context where return is - /// inappropriate, such as a const expression. - /// - /// This is a `RefCell`, which means that we - /// can track all the return expressions and then use them to - /// compute a useful coercion from the set, similar to a match - /// expression or other branching context. You can use methods - /// like `expected_ty` to access the declared return type (if - /// any). - ret_coercion: Option>>, - - /// First span of a return site that we find. Used in error messages. - ret_coercion_span: RefCell>, - - resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, - - ps: RefCell, - - /// Whether the last checked node generates a divergence (e.g., - /// `return` will set this to `Always`). In general, when entering - /// an expression or other node in the tree, the initial value - /// indicates whether prior parts of the containing expression may - /// have diverged. It is then typically set to `Maybe` (and the - /// old value remembered) for processing the subparts of the - /// current expression. As each subpart is processed, they may set - /// the flag to `Always`, etc. Finally, at the end, we take the - /// result and "union" it with the original value, so that when we - /// return the flag indicates if any subpart of the parent - /// expression (up to and including this part) has diverged. So, - /// if you read it after evaluating a subexpression `X`, the value - /// you get indicates whether any subexpression that was - /// evaluating up to and including `X` diverged. - /// - /// We currently use this flag only for diagnostic purposes: - /// - /// - To warn about unreachable code: if, after processing a - /// sub-expression but before we have applied the effects of the - /// current node, we see that the flag is set to `Always`, we - /// can issue a warning. This corresponds to something like - /// `foo(return)`; we warn on the `foo()` expression. (We then - /// update the flag to `WarnedAlways` to suppress duplicate - /// reports.) Similarly, if we traverse to a fresh statement (or - /// tail expression) from a `Always` setting, we will issue a - /// warning. This corresponds to something like `{return; - /// foo();}` or `{return; 22}`, where we would warn on the - /// `foo()` or `22`. - /// - /// An expression represents dead code if, after checking it, - /// the diverges flag is set to something other than `Maybe`. - diverges: Cell, - - /// Whether any child nodes have any type errors. - has_errors: Cell, - - enclosing_breakables: RefCell>, - - inh: &'a Inherited<'a, 'tcx>, -} - -impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { - type Target = Inherited<'a, 'tcx>; - fn deref(&self) -> &Self::Target { - &self.inh - } -} - -/// Helper type of a temporary returned by `Inherited::build(...)`. -/// Necessary because we can't write the following bound: -/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`. -pub struct InheritedBuilder<'tcx> { - infcx: infer::InferCtxtBuilder<'tcx>, - def_id: LocalDefId, -} - -impl Inherited<'_, 'tcx> { - pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> { - let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; - - InheritedBuilder { - infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner), - def_id, - } - } -} - -impl<'tcx> InheritedBuilder<'tcx> { - pub fn enter(&mut self, f: F) -> R - where - F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R, - { - let def_id = self.def_id; - self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) - } -} - -impl Inherited<'a, 'tcx> { - fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { - let tcx = infcx.tcx; - let item_id = tcx.hir().local_def_id_to_hir_id(def_id); - let body_id = tcx.hir().maybe_body_owned_by(item_id); - - Inherited { - typeck_results: MaybeInProgressTables { - maybe_typeck_results: infcx.in_progress_typeck_results, - }, - infcx, - fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), - locals: RefCell::new(Default::default()), - deferred_sized_obligations: RefCell::new(Vec::new()), - deferred_call_resolutions: RefCell::new(Default::default()), - deferred_cast_checks: RefCell::new(Vec::new()), - deferred_generator_interiors: RefCell::new(Vec::new()), - opaque_types: RefCell::new(Default::default()), - opaque_types_vars: RefCell::new(Default::default()), - body_id, - } - } - - fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { - debug!("register_predicate({:?})", obligation); - if obligation.has_escaping_bound_vars() { - span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); - } - self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation); - } - - fn register_predicates(&self, obligations: I) - where - I: IntoIterator>, - { - for obligation in obligations { - self.register_predicate(obligation); - } - } - - fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { - self.register_predicates(infer_ok.obligations); - infer_ok.value - } - - fn normalize_associated_types_in( - &self, - span: Span, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value); - self.register_infer_ok_obligations(ok) - } -} - -struct CheckItemTypesVisitor<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { - fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - check_item_type(self.tcx, i); - } - fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} - fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} -} - -pub fn check_wf_new(tcx: TyCtxt<'_>) { - let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().krate().par_visit_all_item_likes(&visit); -} - -fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); -} - -fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { - debug_assert!(crate_num == LOCAL_CRATE); - tcx.par_body_owners(|body_owner_def_id| { - tcx.ensure().typeck(body_owner_def_id); - }); -} - -fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_item_well_formed(tcx, def_id); -} - -fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_trait_item(tcx, def_id); -} - -fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_impl_item(tcx, def_id); -} - -pub fn provide(providers: &mut Providers) { - method::provide(providers); - *providers = Providers { - typeck_item_bodies, - typeck_const_arg, - typeck, - diagnostic_only_typeck, - has_typeck_results, - adt_destructor, - used_trait_imports, - check_item_well_formed, - check_trait_item_well_formed, - check_impl_item_well_formed, - check_mod_item_types, - ..*providers - }; -} - -fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) -} - -/// If this `DefId` is a "primary tables entry", returns -/// `Some((body_id, header, decl))` with information about -/// it's body-id, fn-header and fn-decl (if any). Otherwise, -/// returns `None`. -/// -/// If this function returns `Some`, then `typeck_results(def_id)` will -/// succeed; if it returns `None`, then `typeck_results(def_id)` may or -/// may not succeed. In some cases where this function returns `None` -/// (notably closures), `typeck_results(def_id)` would wind up -/// redirecting to the owning function. -fn primary_body_of( - tcx: TyCtxt<'_>, - id: hir::HirId, -) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnHeader>, Option<&hir::FnDecl<'_>>)> { - match tcx.hir().get(id) { - Node::Item(item) => match item.kind { - hir::ItemKind::Const(ref ty, body) | hir::ItemKind::Static(ref ty, _, body) => { - Some((body, Some(ty), None, None)) - } - hir::ItemKind::Fn(ref sig, .., body) => { - Some((body, None, Some(&sig.header), Some(&sig.decl))) - } - _ => None, - }, - Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None, None)), - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - Some((body, None, Some(&sig.header), Some(&sig.decl))) - } - _ => None, - }, - Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None, None)), - hir::ImplItemKind::Fn(ref sig, body) => { - Some((body, None, Some(&sig.header), Some(&sig.decl))) - } - _ => None, - }, - Node::AnonConst(constant) => Some((constant.body, None, None, None)), - _ => None, - } -} - -fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // Closures' typeck results come from their outermost function, - // as they are part of the same "inference environment". - let outer_def_id = tcx.closure_base_def_id(def_id); - if outer_def_id != def_id { - return tcx.has_typeck_results(outer_def_id); - } - - if let Some(def_id) = def_id.as_local() { - let id = tcx.hir().local_def_id_to_hir_id(def_id); - primary_body_of(tcx, id).is_some() - } else { - false - } -} - -fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet { - &*tcx.typeck(def_id).used_trait_imports -} - -/// Inspects the substs of opaque types, replacing any inference variables -/// with proper generic parameter from the identity substs. -/// -/// This is run after we normalize the function signature, to fix any inference -/// variables introduced by the projection of associated types. This ensures that -/// any opaque types used in the signature continue to refer to generic parameters, -/// allowing them to be considered for defining uses in the function body -/// -/// For example, consider this code. -/// -/// ```rust -/// trait MyTrait { -/// type MyItem; -/// fn use_it(self) -> Self::MyItem -/// } -/// impl MyTrait for T where T: Iterator { -/// type MyItem = impl Iterator; -/// fn use_it(self) -> Self::MyItem { -/// self -/// } -/// } -/// ``` -/// -/// When we normalize the signature of `use_it` from the impl block, -/// we will normalize `Self::MyItem` to the opaque type `impl Iterator` -/// However, this projection result may contain inference variables, due -/// to the way that projection works. We didn't have any inference variables -/// in the signature to begin with - leaving them in will cause us to incorrectly -/// conclude that we don't have a defining use of `MyItem`. By mapping inference -/// variables back to the actual generic parameters, we will correctly see that -/// we have a defining use of `MyItem` -fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: &T) -> T -where - T: TypeFoldable<'tcx>, -{ - struct FixupFolder<'tcx> { - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> TypeFolder<'tcx> for FixupFolder<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { - ty::Opaque(def_id, substs) => { - debug!("fixup_opaque_types: found type {:?}", ty); - // Here, we replace any inference variables that occur within - // the substs of an opaque type. By definition, any type occurring - // in the substs has a corresponding generic parameter, which is what - // we replace it with. - // This replacement is only run on the function signature, so any - // inference variables that we come across must be the rust of projection - // (there's no other way for a user to get inference variables into - // a function signature). - if ty.needs_infer() { - let new_substs = InternalSubsts::for_item(self.tcx, def_id, |param, _| { - let old_param = substs[param.index as usize]; - match old_param.unpack() { - GenericArgKind::Type(old_ty) => { - if let ty::Infer(_) = old_ty.kind { - // Replace inference type with a generic parameter - self.tcx.mk_param_from_def(param) - } else { - old_param.fold_with(self) - } - } - GenericArgKind::Const(old_const) => { - if let ty::ConstKind::Infer(_) = old_const.val { - // This should never happen - we currently do not support - // 'const projections', e.g.: - // `impl MyTrait for T where ::MyConst == 25` - // which should be the only way for us to end up with a const inference - // variable after projection. If Rust ever gains support for this kind - // of projection, this should *probably* be changed to - // `self.tcx.mk_param_from_def(param)` - bug!( - "Found infer const: `{:?}` in opaque type: {:?}", - old_const, - ty - ); - } else { - old_param.fold_with(self) - } - } - GenericArgKind::Lifetime(old_region) => { - if let RegionKind::ReVar(_) = old_region { - self.tcx.mk_param_from_def(param) - } else { - old_param.fold_with(self) - } - } - } - }); - let new_ty = self.tcx.mk_opaque(def_id, new_substs); - debug!("fixup_opaque_types: new type: {:?}", new_ty); - new_ty - } else { - ty - } - } - _ => ty.super_fold_with(self), - } - } - } - - debug!("fixup_opaque_types({:?})", val); - val.fold_with(&mut FixupFolder { tcx }) -} - -fn typeck_const_arg<'tcx>( - tcx: TyCtxt<'tcx>, - (did, param_did): (LocalDefId, DefId), -) -> &ty::TypeckResults<'tcx> { - let fallback = move || tcx.type_of(param_did); - typeck_with_fallback(tcx, did, fallback) -} - -fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { - if let Some(param_did) = tcx.opt_const_param_of(def_id) { - tcx.typeck_const_arg((def_id, param_did)) - } else { - let fallback = move || tcx.type_of(def_id.to_def_id()); - typeck_with_fallback(tcx, def_id, fallback) - } -} - -/// Used only to get `TypeckResults` for type inference during error recovery. -/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. -fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { - let fallback = move || { - let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); - tcx.ty_error_with_message(span, "diagnostic only typeck table used") - }; - typeck_with_fallback(tcx, def_id, fallback) -} - -fn typeck_with_fallback<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - fallback: impl Fn() -> Ty<'tcx> + 'tcx, -) -> &'tcx ty::TypeckResults<'tcx> { - // Closures' typeck results come from their outermost function, - // as they are part of the same "inference environment". - let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); - if outer_def_id != def_id { - return tcx.typeck(outer_def_id); - } - - let id = tcx.hir().local_def_id_to_hir_id(def_id); - let span = tcx.hir().span(id); - - // Figure out what primary body this item has. - let (body_id, body_ty, fn_header, fn_decl) = primary_body_of(tcx, id).unwrap_or_else(|| { - span_bug!(span, "can't type-check body of {:?}", def_id); - }); - let body = tcx.hir().body(body_id); - - let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { - let param_env = tcx.param_env(def_id); - let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) { - let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { - let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); - AstConv::ty_of_fn( - &fcx, - header.unsafety, - header.abi, - decl, - &hir::Generics::empty(), - None, - ) - } else { - tcx.fn_sig(def_id) - }; - - check_abi(tcx, span, fn_sig.abi()); - - // Compute the fty from point of view of inside the fn. - let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), &fn_sig); - let fn_sig = inh.normalize_associated_types_in( - body.value.span, - body_id.hir_id, - param_env, - &fn_sig, - ); - - let fn_sig = fixup_opaque_types(tcx, &fn_sig); - - let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0; - fcx - } else { - let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); - let expected_type = body_ty - .and_then(|ty| match ty.kind { - hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)), - _ => None, - }) - .unwrap_or_else(fallback); - let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); - fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); - - let revealed_ty = if tcx.features().impl_trait_in_bindings { - fcx.instantiate_opaque_types_from_value(id, &expected_type, body.value.span) - } else { - expected_type - }; - - // Gather locals in statics (because of block expressions). - GatherLocalsVisitor { fcx: &fcx, parent_id: id }.visit_body(body); - - fcx.check_expr_coercable_to_type(&body.value, revealed_ty, None); - - fcx.write_ty(id, revealed_ty); - - fcx - }; - - // All type checking constraints were added, try to fallback unsolved variables. - fcx.select_obligations_where_possible(false, |_| {}); - let mut fallback_has_occurred = false; - - // We do fallback in two passes, to try to generate - // better error messages. - // The first time, we do *not* replace opaque types. - for ty in &fcx.unsolved_variables() { - fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque); - } - // We now see if we can make progress. This might - // cause us to unify inference variables for opaque types, - // since we may have unified some other type variables - // during the first phase of fallback. - // This means that we only replace inference variables with their underlying - // opaque types as a last resort. - // - // In code like this: - // - // ```rust - // type MyType = impl Copy; - // fn produce() -> MyType { true } - // fn bad_produce() -> MyType { panic!() } - // ``` - // - // we want to unify the opaque inference variable in `bad_produce` - // with the diverging fallback for `panic!` (e.g. `()` or `!`). - // This will produce a nice error message about conflicting concrete - // types for `MyType`. - // - // If we had tried to fallback the opaque inference variable to `MyType`, - // we will generate a confusing type-check error that does not explicitly - // refer to opaque types. - fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); - - // We now run fallback again, but this time we allow it to replace - // unconstrained opaque type variables, in addition to performing - // other kinds of fallback. - for ty in &fcx.unsolved_variables() { - fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All); - } - - // See if we can make any more progress. - fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); - - // Even though coercion casts provide type hints, we check casts after fallback for - // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. - fcx.check_casts(); - - // Closure and generator analysis may run after fallback - // because they don't constrain other type variables. - fcx.closure_analyze(body); - assert!(fcx.deferred_call_resolutions.borrow().is_empty()); - fcx.resolve_generator_interiors(def_id.to_def_id()); - - for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { - let ty = fcx.normalize_ty(span, ty); - fcx.require_type_is_sized(ty, span, code); - } - - fcx.select_all_obligations_or_error(); - - if fn_decl.is_some() { - fcx.regionck_fn(id, body); - } else { - fcx.regionck_expr(body); - } - - fcx.resolve_type_vars_in_body(body) - }); - - // Consistency check our TypeckResults instance can hold all ItemLocalIds - // it will need to hold. - assert_eq!(typeck_results.hir_owner, id.owner); - - typeck_results -} - -fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { - if !tcx.sess.target.target.is_abi_supported(abi) { - struct_span_err!( - tcx.sess, - span, - E0570, - "The ABI `{}` is not supported for the current target", - abi - ) - .emit() - } -} - -struct GatherLocalsVisitor<'a, 'tcx> { - fcx: &'a FnCtxt<'a, 'tcx>, - parent_id: hir::HirId, -} - -impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { - fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { - match ty_opt { - None => { - // Infer the variable's type. - let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }); - self.fcx - .locals - .borrow_mut() - .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty }); - var_ty - } - Some(typ) => { - // Take type that the user specified. - self.fcx.locals.borrow_mut().insert(nid, typ); - typ.revealed_ty - } - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } - - // Add explicitly-declared locals. - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { - let local_ty = match local.ty { - Some(ref ty) => { - let o_ty = self.fcx.to_ty(&ty); - - let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { - self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span) - } else { - o_ty - }; - - let c_ty = self - .fcx - .inh - .infcx - .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty)); - debug!( - "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", - ty.hir_id, o_ty, revealed_ty, c_ty - ); - self.fcx - .typeck_results - .borrow_mut() - .user_provided_types_mut() - .insert(ty.hir_id, c_ty); - - Some(LocalTy { decl_ty: o_ty, revealed_ty }) - } - None => None, - }; - self.assign(local.span, local.hir_id, local_ty); - - debug!( - "local variable {:?} is assigned type {}", - local.pat, - self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty) - ); - intravisit::walk_local(self, local); - } - - // Add pattern bindings. - fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { - if let PatKind::Binding(_, _, ident, _) = p.kind { - let var_ty = self.assign(p.span, p.hir_id, None); - - if !self.fcx.tcx.features().unsized_locals { - self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); - } - - debug!( - "pattern binding {} is assigned to {} with type {:?}", - ident, - self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), - var_ty - ); - } - intravisit::walk_pat(self, p); - } - - // Don't descend into the bodies of nested closures. - fn visit_fn( - &mut self, - _: intravisit::FnKind<'tcx>, - _: &'tcx hir::FnDecl<'tcx>, - _: hir::BodyId, - _: Span, - _: hir::HirId, - ) { - } -} - -/// When `check_fn` is invoked on a generator (i.e., a body that -/// includes yield), it returns back some information about the yield -/// points. -struct GeneratorTypes<'tcx> { - /// Type of generator argument / values returned by `yield`. - resume_ty: Ty<'tcx>, - - /// Type of value that is yielded. - yield_ty: Ty<'tcx>, - - /// Types that are captured (see `GeneratorInterior` for more). - interior: Ty<'tcx>, - - /// Indicates if the generator is movable or static (immovable). - movability: hir::Movability, -} - -/// Helper used for fns and closures. Does the grungy work of checking a function -/// body and returns the function context used for that purpose, since in the case of a fn item -/// there is still a bit more to do. -/// -/// * ... -/// * inherited: other fields inherited from the enclosing fn (if any) -fn check_fn<'a, 'tcx>( - inherited: &'a Inherited<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - fn_sig: ty::FnSig<'tcx>, - decl: &'tcx hir::FnDecl<'tcx>, - fn_id: hir::HirId, - body: &'tcx hir::Body<'tcx>, - can_be_generator: Option, -) -> (FnCtxt<'a, 'tcx>, Option>) { - let mut fn_sig = fn_sig; - - debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); - - // Create the function context. This is either derived from scratch or, - // in the case of closures, based on the outer context. - let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); - *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); - - let tcx = fcx.tcx; - let sess = tcx.sess; - let hir = tcx.hir(); - - let declared_ret_ty = fn_sig.output(); - let revealed_ret_ty = - fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); - debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); - fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); - fn_sig = tcx.mk_fn_sig( - fn_sig.inputs().iter().cloned(), - revealed_ret_ty, - fn_sig.c_variadic, - fn_sig.unsafety, - fn_sig.abi, - ); - - let span = body.value.span; - - fn_maybe_err(tcx, span, fn_sig.abi); - - if body.generator_kind.is_some() && can_be_generator.is_some() { - let yield_ty = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); - fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); - - // Resume type defaults to `()` if the generator has no argument. - let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); - - fcx.resume_yield_tys = Some((resume_ty, yield_ty)); - } - - let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local(); - let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id); - GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id }.visit_body(body); - - // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` - // (as it's created inside the body itself, not passed in from outside). - let maybe_va_list = if fn_sig.c_variadic { - let span = body.params.last().unwrap().span; - let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); - let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); - - Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) - } else { - None - }; - - // Add formal parameters. - let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); - let inputs_fn = fn_sig.inputs().iter().copied(); - for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { - // Check the pattern. - let ty_span = try { inputs_hir?.get(idx)?.span }; - fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); - - // Check that argument is Sized. - // The check for a non-trivial pattern is a hack to avoid duplicate warnings - // for simple cases like `fn foo(x: Trait)`, - // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { - fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); - } - - fcx.write_ty(param.hir_id, param_ty); - } - - inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); - - if let ty::Dynamic(..) = declared_ret_ty.kind { - // FIXME: We need to verify that the return type is `Sized` after the return expression has - // been evaluated so that we have types available for all the nodes being returned, but that - // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this - // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, - // while keeping the current ordering we will ignore the tail expression's type because we - // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` - // because we will trigger "unreachable expression" lints unconditionally. - // Because of all of this, we perform a crude check to know whether the simplest `!Sized` - // case that a newcomer might make, returning a bare trait, and in that case we populate - // the tail expression's type so that the suggestion will be correct, but ignore all other - // possible cases. - fcx.check_expr(&body.value); - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type"); - } else { - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - fcx.check_return_expr(&body.value); - } - - // We insert the deferred_generator_interiors entry after visiting the body. - // This ensures that all nested generators appear before the entry of this generator. - // resolve_generator_interiors relies on this property. - let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { - let interior = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); - fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); - - let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); - Some(GeneratorTypes { - resume_ty, - yield_ty, - interior, - movability: can_be_generator.unwrap(), - }) - } else { - None - }; - - // Finalize the return check by taking the LUB of the return types - // we saw and assigning it to the expected return type. This isn't - // really expected to fail, since the coercions would have failed - // earlier when trying to find a LUB. - // - // However, the behavior around `!` is sort of complex. In the - // event that the `actual_return_ty` comes back as `!`, that - // indicates that the fn either does not return or "returns" only - // values of type `!`. In this case, if there is an expected - // return type that is *not* `!`, that should be ok. But if the - // return type is being inferred, we want to "fallback" to `!`: - // - // let x = move || panic!(); - // - // To allow for that, I am creating a type variable with diverging - // fallback. This was deemed ever so slightly better than unifying - // the return value with `!` because it allows for the caller to - // make more assumptions about the return type (e.g., they could do - // - // let y: Option = Some(x()); - // - // which would then cause this return type to become `u32`, not - // `!`). - let coercion = fcx.ret_coercion.take().unwrap().into_inner(); - let mut actual_return_ty = coercion.complete(&fcx); - if actual_return_ty.is_never() { - actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::DivergingFn, - span, - }); - } - fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); - - // Check that the main return type implements the termination trait. - if let Some(term_id) = tcx.lang_items().termination() { - if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) { - let main_id = hir.local_def_id_to_hir_id(def_id); - if main_id == fn_id { - let substs = tcx.mk_substs_trait(declared_ret_ty, &[]); - let trait_ref = ty::TraitRef::new(term_id, substs); - let return_ty_span = decl.output.span(); - let cause = traits::ObligationCause::new( - return_ty_span, - fn_id, - ObligationCauseCode::MainFunctionType, - ); - - inherited.register_predicate(traits::Obligation::new( - cause, - param_env, - trait_ref.without_const().to_predicate(tcx), - )); - } - } - } - - // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` - if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { - if panic_impl_did == hir.local_def_id(fn_id).to_def_id() { - if let Some(panic_info_did) = tcx.lang_items().panic_info() { - if declared_ret_ty.kind != ty::Never { - sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - let span = hir.span(fn_id); - if inputs.len() == 1 { - let arg_is_panic_info = match inputs[0].kind { - ty::Ref(region, ty, mutbl) => match ty.kind { - ty::Adt(ref adt, _) => { - adt.did == panic_info_did - && mutbl == hir::Mutability::Not - && *region != RegionKind::ReStatic - } - _ => false, - }, - _ => false, - }; - - if !arg_is_panic_info { - sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); - } - - if let Node::Item(item) = hir.get(fn_id) { - if let ItemKind::Fn(_, ref generics, _) = item.kind { - if !generics.params.is_empty() { - sess.span_err(span, "should have no type parameters"); - } - } - } - } else { - let span = sess.source_map().guess_head_span(span); - sess.span_err(span, "function should have one argument"); - } - } else { - sess.err("language item required, but not found: `panic_info`"); - } - } - } - - // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` - if let Some(alloc_error_handler_did) = tcx.lang_items().oom() { - if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() { - if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() { - if declared_ret_ty.kind != ty::Never { - sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - let span = hir.span(fn_id); - if inputs.len() == 1 { - let arg_is_alloc_layout = match inputs[0].kind { - ty::Adt(ref adt, _) => adt.did == alloc_layout_did, - _ => false, - }; - - if !arg_is_alloc_layout { - sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); - } - - if let Node::Item(item) = hir.get(fn_id) { - if let ItemKind::Fn(_, ref generics, _) = item.kind { - if !generics.params.is_empty() { - sess.span_err( - span, - "`#[alloc_error_handler]` function should have no type \ - parameters", - ); - } - } - } - } else { - let span = sess.source_map().guess_head_span(span); - sess.span_err(span, "function should have one argument"); - } - } else { - sess.err("language item required, but not found: `alloc_layout`"); - } - } - } - - (fcx, gen_ty) -} - -fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { - let def_id = tcx.hir().local_def_id(id); - let def = tcx.adt_def(def_id); - def.destructor(tcx); // force the destructor to be evaluated - check_representable(tcx, span, def_id); - - if def.repr.simd() { - check_simd(tcx, span, def_id); - } - - check_transparent(tcx, span, def); - check_packed(tcx, span, def); -} - -fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { - let def_id = tcx.hir().local_def_id(id); - let def = tcx.adt_def(def_id); - def.destructor(tcx); // force the destructor to be evaluated - check_representable(tcx, span, def_id); - check_transparent(tcx, span, def); - check_union_fields(tcx, span, def_id); - check_packed(tcx, span, def); -} - -/// When the `#![feature(untagged_unions)]` gate is active, -/// check that the fields of the `union` does not contain fields that need dropping. -fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { - let item_type = tcx.type_of(item_def_id); - if let ty::Adt(def, substs) = item_type.kind { - assert!(def.is_union()); - let fields = &def.non_enum_variant().fields; - let param_env = tcx.param_env(item_def_id); - for field in fields { - let field_ty = field.ty(tcx, substs); - // We are currently checking the type this field came from, so it must be local. - let field_span = tcx.hir().span_if_local(field.did).unwrap(); - if field_ty.needs_drop(tcx, param_env) { - struct_span_err!( - tcx.sess, - field_span, - E0740, - "unions may not contain fields that need dropping" - ) - .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type") - .emit(); - return false; - } - } - } else { - span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind); - } - true -} - -/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` -/// projections that would result in "inheriting lifetimes". -fn check_opaque<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - substs: SubstsRef<'tcx>, - span: Span, - origin: &hir::OpaqueTyOrigin, -) { - check_opaque_for_inheriting_lifetimes(tcx, def_id, span); - check_opaque_for_cycles(tcx, def_id, substs, span, origin); -} - -/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result -/// in "inheriting lifetimes". -fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { - let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id)); - debug!( - "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}", - def_id, span, item - ); - - #[derive(Debug)] - struct ProhibitOpaqueVisitor<'tcx> { - opaque_identity_ty: Ty<'tcx>, - generics: &'tcx ty::Generics, - ty: Option>, - }; - - impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); - if t != self.opaque_identity_ty && t.super_visit_with(self) { - self.ty = Some(t); - return true; - } - false - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); - if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - return *index < self.generics.parent_count as u32; - } - - r.super_visit_with(self) - } - - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { - if let ty::ConstKind::Unevaluated(..) = c.val { - // FIXME(#72219) We currenctly don't detect lifetimes within substs - // which would violate this check. Even though the particular substitution is not used - // within the const, this should still be fixed. - return false; - } - c.super_visit_with(self) - } - } - - if let ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, - .. - }) = item.kind - { - let mut visitor = ProhibitOpaqueVisitor { - opaque_identity_ty: tcx.mk_opaque( - def_id.to_def_id(), - InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), - ), - generics: tcx.generics_of(def_id), - ty: None, - }; - let prohibit_opaque = tcx - .predicates_of(def_id) - .predicates - .iter() - .any(|(predicate, _)| predicate.visit_with(&mut visitor)); - debug!( - "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", - prohibit_opaque, visitor - ); - - if prohibit_opaque { - let is_async = match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { - hir::OpaqueTyOrigin::AsyncFn => true, - _ => false, - }, - _ => unreachable!(), - }; - - let mut err = struct_span_err!( - tcx.sess, - span, - E0760, - "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ - a parent scope", - if is_async { "async fn" } else { "impl Trait" }, - ); - - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { - if snippet == "Self" { - if let Some(ty) = visitor.ty { - err.span_suggestion( - span, - "consider spelling out the type instead", - format!("{:?}", ty), - Applicability::MaybeIncorrect, - ); - } - } - } - err.emit(); - } - } -} - -/// Given a `DefId` for an opaque type in return position, find its parent item's return -/// expressions. -fn get_owner_return_paths( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, -) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let id = tcx.hir().get_parent_item(hir_id); - tcx.hir() - .find(id) - .map(|n| (id, n)) - .and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b))) - .map(|(hir_id, body_id)| { - let body = tcx.hir().body(body_id); - let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(body); - (hir_id, visitor) - }) -} - -/// Emit an error for recursive opaque types. -/// -/// If this is a return `impl Trait`, find the item's return expressions and point at them. For -/// direct recursion this is enough, but for indirect recursion also point at the last intermediary -/// `impl Trait`. -/// -/// If all the return expressions evaluate to `!`, then we explain that the error will go away -/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. -fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { - let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); - - let mut label = false; - if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) { - let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id)); - if visitor - .returns - .iter() - .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) - .all(|ty| matches!(ty.kind, ty::Never)) - { - let spans = visitor - .returns - .iter() - .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some()) - .map(|expr| expr.span) - .collect::>(); - let span_len = spans.len(); - if span_len == 1 { - err.span_label(spans[0], "this returned value is of `!` type"); - } else { - let mut multispan: MultiSpan = spans.clone().into(); - for span in spans { - multispan - .push_span_label(span, "this returned value is of `!` type".to_string()); - } - err.span_note(multispan, "these returned values have a concrete \"never\" type"); - } - err.help("this error will resolve once the item's body returns a concrete type"); - } else { - let mut seen = FxHashSet::default(); - seen.insert(span); - err.span_label(span, "recursive opaque type"); - label = true; - for (sp, ty) in visitor - .returns - .iter() - .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) - .filter(|(_, ty)| !matches!(ty.kind, ty::Never)) - { - struct VisitTypes(Vec); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { - ty::Opaque(def, _) => { - self.0.push(def); - false - } - _ => t.super_visit_with(self), - } - } - } - let mut visitor = VisitTypes(vec![]); - ty.visit_with(&mut visitor); - for def_id in visitor.0 { - let ty_span = tcx.def_span(def_id); - if !seen.contains(&ty_span) { - err.span_label(ty_span, &format!("returning this opaque type `{}`", ty)); - seen.insert(ty_span); - } - err.span_label(sp, &format!("returning here with type `{}`", ty)); - } - } - } - } - if !label { - err.span_label(span, "cannot resolve opaque type"); - } - err.emit(); -} - -/// Emit an error for recursive opaque types in a `let` binding. -fn binding_opaque_type_cycle_error( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - span: Span, - partially_expanded_type: Ty<'tcx>, -) { - let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); - err.span_label(span, "cannot resolve opaque type"); - // Find the the owner that declared this `impl Trait` type. - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let mut prev_hir_id = hir_id; - let mut hir_id = tcx.hir().get_parent_node(hir_id); - while let Some(node) = tcx.hir().find(hir_id) { - match node { - hir::Node::Local(hir::Local { - pat, - init: None, - ty: Some(ty), - source: hir::LocalSource::Normal, - .. - }) => { - err.span_label(pat.span, "this binding might not have a concrete type"); - err.span_suggestion_verbose( - ty.span.shrink_to_hi(), - "set the binding to a value for a concrete type to be resolved", - " = /* value */".to_string(), - Applicability::HasPlaceholders, - ); - } - hir::Node::Local(hir::Local { - init: Some(expr), - source: hir::LocalSource::Normal, - .. - }) => { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let typeck_results = - tcx.typeck(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id))); - if let Some(ty) = typeck_results.node_type_opt(expr.hir_id) { - err.span_label( - expr.span, - &format!( - "this is of type `{}`, which doesn't constrain \ - `{}` enough to arrive to a concrete type", - ty, partially_expanded_type - ), - ); - } - } - _ => {} - } - if prev_hir_id == hir_id { - break; - } - prev_hir_id = hir_id; - hir_id = tcx.hir().get_parent_node(hir_id); - } - err.emit(); -} - -fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) { - struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") - .span_label(span, "recursive `async fn`") - .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") - .emit(); -} - -/// Checks that an opaque type does not contain cycles. -fn check_opaque_for_cycles<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - substs: SubstsRef<'tcx>, - span: Span, - origin: &hir::OpaqueTyOrigin, -) { - if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs) - { - match origin { - hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span), - hir::OpaqueTyOrigin::Binding => { - binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type) - } - _ => opaque_type_cycle_error(tcx, def_id, span), - } - } -} - -// Forbid defining intrinsics in Rust code, -// as they must always be defined by the compiler. -fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { - if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi { - tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block"); - } -} - -pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { - debug!( - "check_item_type(it.hir_id={}, it.name={})", - it.hir_id, - tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id()) - ); - let _indenter = indenter(); - match it.kind { - // Consts can play a role in type-checking, so they are included here. - hir::ItemKind::Static(..) => { - let def_id = tcx.hir().local_def_id(it.hir_id); - tcx.ensure().typeck(def_id); - maybe_check_static_with_link_section(tcx, def_id, it.span); - } - hir::ItemKind::Const(..) => { - tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id)); - } - hir::ItemKind::Enum(ref enum_definition, _) => { - check_enum(tcx, it.span, &enum_definition.variants, it.hir_id); - } - hir::ItemKind::Fn(..) => {} // entirely within check_item_body - hir::ItemKind::Impl { ref items, .. } => { - debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id); - let impl_def_id = tcx.hir().local_def_id(it.hir_id); - if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { - check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items); - let trait_def_id = impl_trait_ref.def_id; - check_on_unimplemented(tcx, trait_def_id, it); - } - } - hir::ItemKind::Trait(_, _, _, _, ref items) => { - let def_id = tcx.hir().local_def_id(it.hir_id); - check_on_unimplemented(tcx, def_id.to_def_id(), it); - - for item in items.iter() { - let item = tcx.hir().trait_item(item.id); - if let hir::TraitItemKind::Fn(sig, _) = &item.kind { - let abi = sig.header.abi; - fn_maybe_err(tcx, item.ident.span, abi); - } - } - } - hir::ItemKind::Struct(..) => { - check_struct(tcx, it.hir_id, it.span); - } - hir::ItemKind::Union(..) => { - check_union(tcx, it.hir_id, it.span); - } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { - // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting - // `async-std` (and `pub async fn` in general). - // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! - // See https://github.com/rust-lang/rust/issues/75100 - if !tcx.sess.opts.actually_rustdoc { - let def_id = tcx.hir().local_def_id(it.hir_id); - - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - check_opaque(tcx, def_id, substs, it.span, &origin); - } - } - hir::ItemKind::TyAlias(..) => { - let def_id = tcx.hir().local_def_id(it.hir_id); - let pty_ty = tcx.type_of(def_id); - let generics = tcx.generics_of(def_id); - check_type_params_are_used(tcx, &generics, pty_ty); - } - hir::ItemKind::ForeignMod(ref m) => { - check_abi(tcx, it.span, m.abi); - - if m.abi == Abi::RustIntrinsic { - for item in m.items { - intrinsic::check_intrinsic_type(tcx, item); - } - } else if m.abi == Abi::PlatformIntrinsic { - for item in m.items { - intrinsic::check_platform_intrinsic_type(tcx, item); - } - } else { - for item in m.items { - let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id)); - let own_counts = generics.own_counts(); - if generics.params.len() - own_counts.lifetimes != 0 { - let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) { - (_, 0) => ("type", "types", Some("u32")), - // We don't specify an example value, because we can't generate - // a valid value for any type. - (0, _) => ("const", "consts", None), - _ => ("type or const", "types or consts", None), - }; - struct_span_err!( - tcx.sess, - item.span, - E0044, - "foreign items may not have {} parameters", - kinds, - ) - .span_label(item.span, &format!("can't have {} parameters", kinds)) - .help( - // FIXME: once we start storing spans for type arguments, turn this - // into a suggestion. - &format!( - "replace the {} parameters with concrete {}{}", - kinds, - kinds_pl, - egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(), - ), - ) - .emit(); - } - - if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind { - require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span); - } - } - } - } - _ => { /* nothing to do */ } - } -} - -fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) { - // Only restricted on wasm32 target for now - if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") { - return; - } - - // If `#[link_section]` is missing, then nothing to verify - let attrs = tcx.codegen_fn_attrs(id); - if attrs.link_section.is_none() { - return; - } - - // 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. - // `#[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. - match tcx.const_eval_poly(id.to_def_id()) { - Ok(ConstValue::ByRef { alloc, .. }) => { - if alloc.relocations().len() != 0 { - let msg = "statics with a custom `#[link_section]` must be a \ - simple list of bytes on the wasm target with no \ - extra levels of indirection such as references"; - tcx.sess.span_err(span, msg); - } - } - Ok(_) => bug!("Matching on non-ByRef static"), - Err(_) => {} - } -} - -fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) { - let item_def_id = tcx.hir().local_def_id(item.hir_id); - // an error would be reported if this fails. - let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id()); -} - -fn report_forbidden_specialization( - tcx: TyCtxt<'_>, - impl_item: &hir::ImplItem<'_>, - parent_impl: DefId, -) { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0520, - "`{}` specializes an item from a parent `impl`, but \ - that item is not marked `default`", - impl_item.ident - ); - err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident)); - - match tcx.span_of_impl(parent_impl) { - Ok(span) => { - err.span_label(span, "parent `impl` is here"); - err.note(&format!( - "to specialize, `{}` in the parent `impl` must be marked `default`", - impl_item.ident - )); - } - Err(cname) => { - err.note(&format!("parent implementation is in crate `{}`", cname)); - } - } - - err.emit(); -} - -fn check_specialization_validity<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def: &ty::TraitDef, - trait_item: &ty::AssocItem, - impl_id: DefId, - impl_item: &hir::ImplItem<'_>, -) { - let kind = match impl_item.kind { - hir::ImplItemKind::Const(..) => ty::AssocKind::Const, - hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, - hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type, - }; - - let ancestors = match trait_def.ancestors(tcx, impl_id) { - Ok(ancestors) => ancestors, - Err(_) => return, - }; - let mut ancestor_impls = ancestors - .skip(1) - .filter_map(|parent| { - if parent.is_from_trait() { - None - } else { - Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id))) - } - }) - .peekable(); - - if ancestor_impls.peek().is_none() { - // No parent, nothing to specialize. - return; - } - - let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| { - match parent_item { - // Parent impl exists, and contains the parent item we're trying to specialize, but - // doesn't mark it `default`. - Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => { - Some(Err(parent_impl.def_id())) - } - - // Parent impl contains item and makes it specializable. - Some(_) => Some(Ok(())), - - // Parent impl doesn't mention the item. This means it's inherited from the - // grandparent. In that case, if parent is a `default impl`, inherited items use the - // "defaultness" from the grandparent, else they are final. - None => { - if tcx.impl_defaultness(parent_impl.def_id()).is_default() { - None - } else { - Some(Err(parent_impl.def_id())) - } - } - } - }); - - // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the - // item. This is allowed, the item isn't actually getting specialized here. - let result = opt_result.unwrap_or(Ok(())); - - if let Err(parent_impl) = result { - report_forbidden_specialization(tcx, impl_item, parent_impl); - } -} - -fn check_impl_items_against_trait<'tcx>( - tcx: TyCtxt<'tcx>, - full_impl_span: Span, - impl_id: LocalDefId, - impl_trait_ref: ty::TraitRef<'tcx>, - impl_item_refs: &[hir::ImplItemRef<'_>], -) { - let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); - - // If the trait reference itself is erroneous (so the compilation is going - // to fail), skip checking the items here -- the `impl_item` table in `tcx` - // isn't populated for such impls. - if impl_trait_ref.references_error() { - return; - } - - // Negative impls are not expected to have any items - match tcx.impl_polarity(impl_id) { - ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {} - ty::ImplPolarity::Negative => { - if let [first_item_ref, ..] = impl_item_refs { - let first_item_span = tcx.hir().impl_item(first_item_ref.id).span; - struct_span_err!( - tcx.sess, - first_item_span, - E0749, - "negative impls cannot have any items" - ) - .emit(); - } - return; - } - } - - // Locate trait definition and items - let trait_def = tcx.trait_def(impl_trait_ref.def_id); - - let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); - - // Check existing impl methods to see if they are both present in trait - // and compatible with trait signature - for impl_item in impl_items() { - let namespace = impl_item.kind.namespace(); - let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id)); - let ty_trait_item = tcx - .associated_items(impl_trait_ref.def_id) - .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id) - .or_else(|| { - // Not compatible, but needed for the error message - tcx.associated_items(impl_trait_ref.def_id) - .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id) - .next() - }); - - // Check that impl definition matches trait definition - if let Some(ty_trait_item) = ty_trait_item { - match impl_item.kind { - hir::ImplItemKind::Const(..) => { - // Find associated const definition. - if ty_trait_item.kind == ty::AssocKind::Const { - compare_const_impl( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - ); - } else { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0323, - "item `{}` is an associated const, \ - which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ); - err.span_label(impl_item.span, "does not match trait"); - // We can only get the spans from local trait definition - // Same for E0324 and E0325 - if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) { - err.span_label(trait_span, "item in trait"); - } - err.emit() - } - } - hir::ImplItemKind::Fn(..) => { - let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - if ty_trait_item.kind == ty::AssocKind::Fn { - compare_impl_method( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); - } else { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0324, - "item `{}` is an associated method, \ - which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ); - err.span_label(impl_item.span, "does not match trait"); - if let Some(trait_span) = opt_trait_span { - err.span_label(trait_span, "item in trait"); - } - err.emit() - } - } - hir::ImplItemKind::TyAlias(_) => { - let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - if ty_trait_item.kind == ty::AssocKind::Type { - compare_ty_impl( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); - } else { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0325, - "item `{}` is an associated type, \ - which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ); - err.span_label(impl_item.span, "does not match trait"); - if let Some(trait_span) = opt_trait_span { - err.span_label(trait_span, "item in trait"); - } - err.emit() - } - } - } - - check_specialization_validity( - tcx, - trait_def, - &ty_trait_item, - impl_id.to_def_id(), - impl_item, - ); - } - } - - // Check for missing items from trait - let mut missing_items = Vec::new(); - if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) { - for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { - let is_implemented = ancestors - .leaf_def(tcx, trait_item.ident, trait_item.kind) - .map(|node_item| !node_item.defining_node.is_from_trait()) - .unwrap_or(false); - - if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { - if !trait_item.defaultness.has_value() { - missing_items.push(*trait_item); - } - } - } - } - - if !missing_items.is_empty() { - missing_items_err(tcx, impl_span, &missing_items, full_impl_span); - } -} - -fn missing_items_err( - tcx: TyCtxt<'_>, - impl_span: Span, - missing_items: &[ty::AssocItem], - full_impl_span: Span, -) { - let missing_items_msg = missing_items - .iter() - .map(|trait_item| trait_item.ident.to_string()) - .collect::>() - .join("`, `"); - - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0046, - "not all trait items implemented, missing: `{}`", - missing_items_msg - ); - err.span_label(impl_span, format!("missing `{}` in implementation", missing_items_msg)); - - // `Span` before impl block closing brace. - let hi = full_impl_span.hi() - BytePos(1); - // Point at the place right before the closing brace of the relevant `impl` to suggest - // adding the associated item at the end of its body. - let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi); - // Obtain the level of indentation ending in `sugg_sp`. - let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0); - // Make the whitespace that will make the suggestion have the right indentation. - let padding: String = (0..indentation).map(|_| " ").collect(); - - for trait_item in missing_items { - let snippet = suggestion_signature(&trait_item, tcx); - let code = format!("{}{}\n{}", padding, snippet, padding); - let msg = format!("implement the missing item: `{}`", snippet); - let appl = Applicability::HasPlaceholders; - if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { - err.span_label(span, format!("`{}` from trait", trait_item.ident)); - err.tool_only_span_suggestion(sugg_sp, &msg, code, appl); - } else { - err.span_suggestion_hidden(sugg_sp, &msg, code, appl); - } - } - err.emit(); -} - -/// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. -fn bounds_from_generic_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: ty::GenericPredicates<'tcx>, -) -> (String, String) { - let mut types: FxHashMap, Vec> = FxHashMap::default(); - let mut projections = vec![]; - for (predicate, _) in predicates.predicates { - debug!("predicate {:?}", predicate); - match predicate.skip_binders() { - ty::PredicateAtom::Trait(trait_predicate, _) => { - let entry = types.entry(trait_predicate.self_ty()).or_default(); - let def_id = trait_predicate.def_id(); - if Some(def_id) != tcx.lang_items().sized_trait() { - // Type params are `Sized` by default, do not add that restriction to the list - // if it is a positive requirement. - entry.push(trait_predicate.def_id()); - } - } - ty::PredicateAtom::Projection(projection_pred) => { - projections.push(ty::Binder::bind(projection_pred)); - } - _ => {} - } - } - let generics = if types.is_empty() { - "".to_string() - } else { - format!( - "<{}>", - types - .keys() - .filter_map(|t| match t.kind { - ty::Param(_) => Some(t.to_string()), - // Avoid suggesting the following: - // fn foo::Bar>(_: T) where T: Trait, ::Bar: Other {} - _ => None, - }) - .collect::>() - .join(", ") - ) - }; - let mut where_clauses = vec![]; - for (ty, bounds) in types { - for bound in &bounds { - where_clauses.push(format!("{}: {}", ty, tcx.def_path_str(*bound))); - } - } - for projection in &projections { - let p = projection.skip_binder(); - // FIXME: this is not currently supported syntax, we should be looking at the `types` and - // insert the associated types where they correspond, but for now let's be "lazy" and - // propose this instead of the following valid resugaring: - // `T: Trait, Trait::Assoc = K` → `T: Trait` - where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty)); - } - let where_clauses = if where_clauses.is_empty() { - String::new() - } else { - format!(" where {}", where_clauses.join(", ")) - }; - (generics, where_clauses) -} - -/// Return placeholder code for the given function. -fn fn_sig_suggestion<'tcx>( - tcx: TyCtxt<'tcx>, - sig: ty::FnSig<'tcx>, - ident: Ident, - predicates: ty::GenericPredicates<'tcx>, - assoc: &ty::AssocItem, -) -> String { - let args = sig - .inputs() - .iter() - .enumerate() - .map(|(i, ty)| { - Some(match ty.kind { - ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(), - ty::Ref(reg, ref_ty, mutability) if i == 0 => { - let reg = match &format!("{}", reg)[..] { - "'_" | "" => String::new(), - reg => format!("{} ", reg), - }; - if assoc.fn_has_self_parameter { - match ref_ty.kind { - ty::Param(param) if param.name == kw::SelfUpper => { - format!("&{}{}self", reg, mutability.prefix_str()) - } - - _ => format!("self: {}", ty), - } - } else { - format!("_: {:?}", ty) - } - } - _ => { - if assoc.fn_has_self_parameter && i == 0 { - format!("self: {:?}", ty) - } else { - format!("_: {:?}", ty) - } - } - }) - }) - .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None })) - .filter_map(|arg| arg) - .collect::>() - .join(", "); - let output = sig.output(); - let output = if !output.is_unit() { format!(" -> {:?}", output) } else { String::new() }; - - let unsafety = sig.unsafety.prefix_str(); - let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); - - // FIXME: this is not entirely correct, as the lifetimes from borrowed params will - // not be present in the `fn` definition, not will we account for renamed - // lifetimes between the `impl` and the `trait`, but this should be good enough to - // fill in a significant portion of the missing code, and other subsequent - // suggestions can help the user fix the code. - format!( - "{}fn {}{}({}){}{} {{ todo!() }}", - unsafety, ident, generics, args, output, where_clauses - ) -} - -/// Return placeholder code for the given associated item. -/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a -/// structured suggestion. -fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { - match assoc.kind { - ty::AssocKind::Fn => { - // We skip the binder here because the binder would deanonymize all - // late-bound regions, and we don't want method signatures to show up - // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound - // regions just fine, showing `fn(&MyType)`. - fn_sig_suggestion( - tcx, - tcx.fn_sig(assoc.def_id).skip_binder(), - assoc.ident, - tcx.predicates_of(assoc.def_id), - assoc, - ) - } - ty::AssocKind::Type => format!("type {} = Type;", assoc.ident), - ty::AssocKind::Const => { - let ty = tcx.type_of(assoc.def_id); - let val = expr::ty_kind_suggestion(ty).unwrap_or("value"); - format!("const {}: {:?} = {};", assoc.ident, ty, val) - } - } -} - -/// Checks whether a type can be represented in memory. In particular, it -/// identifies types that contain themselves without indirection through a -/// pointer, which would mean their size is unbounded. -fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool { - let rty = tcx.type_of(item_def_id); - - // Check that it is possible to represent this type. This call identifies - // (1) types that contain themselves and (2) types that contain a different - // recursive type. It is only necessary to throw an error on those that - // contain themselves. For case 2, there must be an inner type that will be - // caught by case 1. - match rty.is_representable(tcx, sp) { - Representability::SelfRecursive(spans) => { - recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans); - return false; - } - Representability::Representable | Representability::ContainsRecursive => (), - } - true -} - -pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { - let t = tcx.type_of(def_id); - if let ty::Adt(def, substs) = t.kind { - if def.is_struct() { - let fields = &def.non_enum_variant().fields; - if fields.is_empty() { - struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); - return; - } - let e = fields[0].ty(tcx, substs); - if !fields.iter().all(|f| f.ty(tcx, substs) == e) { - struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous") - .span_label(sp, "SIMD elements must have the same type") - .emit(); - return; - } - match e.kind { - ty::Param(_) => { /* struct(T, T, T, T) is ok */ } - _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } - _ => { - struct_span_err!( - tcx.sess, - sp, - E0077, - "SIMD vector element type should be machine type" - ) - .emit(); - return; - } - } - } - } -} - -fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { - let repr = def.repr; - if repr.packed() { - for attr in tcx.get_attrs(def.did).iter() { - for r in attr::find_repr_attrs(&tcx.sess, attr) { - if let attr::ReprPacked(pack) = r { - if let Some(repr_pack) = repr.pack { - if pack as u64 != repr_pack.bytes() { - struct_span_err!( - tcx.sess, - sp, - E0634, - "type has conflicting packed representation hints" - ) - .emit(); - } - } - } - } - } - if repr.align.is_some() { - struct_span_err!( - tcx.sess, - sp, - E0587, - "type has conflicting packed and align representation hints" - ) - .emit(); - } else { - if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) { - let mut err = struct_span_err!( - tcx.sess, - sp, - E0588, - "packed type cannot transitively contain a `#[repr(align)]` type" - ); - - err.span_note( - tcx.def_span(def_spans[0].0), - &format!( - "`{}` has a `#[repr(align)]` attribute", - tcx.item_name(def_spans[0].0) - ), - ); - - if def_spans.len() > 2 { - let mut first = true; - for (adt_def, span) in def_spans.iter().skip(1).rev() { - let ident = tcx.item_name(*adt_def); - err.span_note( - *span, - &if first { - format!( - "`{}` contains a field of type `{}`", - tcx.type_of(def.did), - ident - ) - } else { - format!("...which contains a field of type `{}`", ident) - }, - ); - first = false; - } - } - - err.emit(); - } - } - } -} - -fn check_packed_inner( - tcx: TyCtxt<'_>, - def_id: DefId, - stack: &mut Vec, -) -> Option> { - if let ty::Adt(def, substs) = tcx.type_of(def_id).kind { - if def.is_struct() || def.is_union() { - if def.repr.align.is_some() { - return Some(vec![(def.did, DUMMY_SP)]); - } - - stack.push(def_id); - for field in &def.non_enum_variant().fields { - if let ty::Adt(def, _) = field.ty(tcx, substs).kind { - if !stack.contains(&def.did) { - if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) { - defs.push((def.did, field.ident.span)); - return Some(defs); - } - } - } - } - stack.pop(); - } - } - - None -} - -/// Emit an error when encountering more or less than one variant in a transparent enum. -fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) { - let variant_spans: Vec<_> = adt - .variants - .iter() - .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap()) - .collect(); - let msg = format!("needs exactly one variant, but has {}", adt.variants.len(),); - let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg); - err.span_label(sp, &msg); - if let [start @ .., end] = &*variant_spans { - for variant_span in start { - err.span_label(*variant_span, ""); - } - err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did))); - } - err.emit(); -} - -/// Emit an error when encountering more or less than one non-zero-sized field in a transparent -/// enum. -fn bad_non_zero_sized_fields<'tcx>( - tcx: TyCtxt<'tcx>, - adt: &'tcx ty::AdtDef, - field_count: usize, - field_spans: impl Iterator, - sp: Span, -) { - let msg = format!("needs exactly one non-zero-sized field, but has {}", field_count); - let mut err = struct_span_err!( - tcx.sess, - sp, - E0690, - "{}transparent {} {}", - if adt.is_enum() { "the variant of a " } else { "" }, - adt.descr(), - msg, - ); - err.span_label(sp, &msg); - for sp in field_spans { - err.span_label(sp, "this field is non-zero-sized"); - } - err.emit(); -} - -fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) { - if !adt.repr.transparent() { - return; - } - let sp = tcx.sess.source_map().guess_head_span(sp); - - if adt.is_union() && !tcx.features().transparent_unions { - feature_err( - &tcx.sess.parse_sess, - sym::transparent_unions, - sp, - "transparent unions are unstable", - ) - .emit(); - } - - if adt.variants.len() != 1 { - bad_variant_count(tcx, adt, sp, adt.did); - if adt.variants.is_empty() { - // Don't bother checking the fields. No variants (and thus no fields) exist. - return; - } - } - - // For each field, figure out if it's known to be a ZST and align(1) - let field_infos = adt.all_fields().map(|field| { - let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); - let param_env = tcx.param_env(field.did); - let layout = tcx.layout_of(param_env.and(ty)); - // We are currently checking the type this field came from, so it must be local - let span = tcx.hir().span_if_local(field.did).unwrap(); - let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false); - let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false); - (span, zst, align1) - }); - - let non_zst_fields = - field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None }); - let non_zst_count = non_zst_fields.clone().count(); - if non_zst_count != 1 { - bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); - } - for (span, zst, align1) in field_infos { - if zst && !align1 { - struct_span_err!( - tcx.sess, - span, - E0691, - "zero-sized field in transparent {} has alignment larger than 1", - adt.descr(), - ) - .span_label(span, "has alignment larger than 1") - .emit(); - } - } -} - -#[allow(trivial_numeric_casts)] -pub fn check_enum<'tcx>( - tcx: TyCtxt<'tcx>, - sp: Span, - vs: &'tcx [hir::Variant<'tcx>], - id: hir::HirId, -) { - let def_id = tcx.hir().local_def_id(id); - let def = tcx.adt_def(def_id); - def.destructor(tcx); // force the destructor to be evaluated - - if vs.is_empty() { - let attributes = tcx.get_attrs(def_id.to_def_id()); - if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) { - struct_span_err!( - tcx.sess, - attr.span, - E0084, - "unsupported representation for zero-variant enum" - ) - .span_label(sp, "zero-variant enum") - .emit(); - } - } - - let repr_type_ty = def.repr.discr_type().to_ty(tcx); - if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.features().repr128 { - feature_err( - &tcx.sess.parse_sess, - sym::repr128, - sp, - "repr with 128-bit type is unstable", - ) - .emit(); - } - } - - for v in vs { - if let Some(ref e) = v.disr_expr { - tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id)); - } - } - - if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant { - let is_unit = |var: &hir::Variant<'_>| match var.data { - hir::VariantData::Unit(..) => true, - _ => false, - }; - - let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); - let has_non_units = vs.iter().any(|var| !is_unit(var)); - let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); - let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); - - if disr_non_unit || (disr_units && has_non_units) { - let mut err = - struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified"); - err.emit(); - } - } - - let mut disr_vals: Vec> = Vec::with_capacity(vs.len()); - for ((_, discr), v) in def.discriminants(tcx).zip(vs) { - // Check for duplicate discriminant values - if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { - let variant_did = def.variants[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.hir().span(variant_i_hir_id), - }; - let span = match v.disr_expr { - Some(ref expr) => tcx.hir().span(expr.hir_id), - None => v.span, - }; - struct_span_err!( - tcx.sess, - span, - E0081, - "discriminant value `{}` already exists", - disr_vals[i] - ) - .span_label(i_span, format!("first use of `{}`", disr_vals[i])) - .span_label(span, format!("enum already has `{}`", disr_vals[i])) - .emit(); - } - disr_vals.push(discr); - } - - check_representable(tcx, sp, def_id); - check_transparent(tcx, sp, def); -} - -fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) { - struct_span_err!( - tcx.sess, - span, - E0533, - "expected unit struct, unit variant or constant, found {}{}", - res.descr(), - tcx.sess.source_map().span_to_snippet(span).map_or(String::new(), |s| format!(" `{}`", s)), - ) - .emit(); -} - -impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn item_def_id(&self) -> Option { - None - } - - fn default_constness_for_trait_bounds(&self) -> hir::Constness { - // FIXME: refactor this into a method - let node = self.tcx.hir().get(self.body_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { - fn_like.constness() - } else { - hir::Constness::NotConst - } - } - - fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { - let tcx = self.tcx; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_id = tcx.hir().ty_param_owner(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - ty::GenericPredicates { - parent: None, - predicates: tcx.arena.alloc_from_iter( - self.param_env.caller_bounds().iter().filter_map(|predicate| { - match predicate.skip_binders() { - ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { - // HACK(eddyb) should get the original `Span`. - let span = tcx.def_span(def_id); - Some((predicate, span)) - } - _ => None, - } - }), - ), - } - } + /// eventually). + pub(super) param_env: ty::ParamEnv<'tcx>, - fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option> { - let v = match def { - Some(def) => infer::EarlyBoundRegion(span, def.name), - None => infer::MiscVariable(span), - }; - Some(self.next_region_var(v)) - } + /// Number of errors that had been reported when we started + /// checking this function. On exit, if we find that *more* errors + /// have been reported, we will skip regionck and other work that + /// expects the types within the function to be consistent. + // FIXME(matthewjasper) This should not exist, and it's not correct + // if type checking is run in parallel. + err_count_on_creation: usize, - fn allow_ty_infer(&self) -> bool { - true - } + /// If `Some`, this stores coercion information for returned + /// expressions. If `None`, this is in a context where return is + /// inappropriate, such as a const expression. + /// + /// This is a `RefCell`, which means that we + /// can track all the return expressions and then use them to + /// compute a useful coercion from the set, similar to a match + /// expression or other branching context. You can use methods + /// like `expected_ty` to access the declared return type (if + /// any). + pub(super) ret_coercion: Option>>, - fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { - return ty; - } - unreachable!() - } else { - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }) - } - } + pub(super) ret_coercion_impl_trait: Option>, - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> &'tcx Const<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { - return ct; - } - unreachable!() - } else { - self.next_const_var( - ty, - ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, - ) - } - } + pub(super) ret_type_span: Option, - fn projected_ty_from_poly_trait_ref( - &self, - span: Span, - item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Ty<'tcx> { - let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( - span, - infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), - &poly_trait_ref, - ); + /// Used exclusively to reduce cost of advanced evaluation used for + /// more helpful diagnostics. + pub(super) in_tail_expr: bool, - let item_substs = >::create_substs_for_associated_item( - self, - self.tcx, - span, - item_def_id, - item_segment, - trait_ref.substs, - ); + /// First span of a return site that we find. Used in error messages. + pub(super) ret_coercion_span: RefCell>, - self.tcx().mk_projection(item_def_id, item_substs) - } + pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, - fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_escaping_bound_vars() { - ty // FIXME: normalization and escaping regions - } else { - self.normalize_associated_types_in(span, &ty) - } - } + pub(super) ps: RefCell, - fn set_tainted_by_errors(&self) { - self.infcx.set_tainted_by_errors() - } + /// Whether the last checked node generates a divergence (e.g., + /// `return` will set this to `Always`). In general, when entering + /// an expression or other node in the tree, the initial value + /// indicates whether prior parts of the containing expression may + /// have diverged. It is then typically set to `Maybe` (and the + /// old value remembered) for processing the subparts of the + /// current expression. As each subpart is processed, they may set + /// the flag to `Always`, etc. Finally, at the end, we take the + /// result and "union" it with the original value, so that when we + /// return the flag indicates if any subpart of the parent + /// expression (up to and including this part) has diverged. So, + /// if you read it after evaluating a subexpression `X`, the value + /// you get indicates whether any subexpression that was + /// evaluating up to and including `X` diverged. + /// + /// We currently use this flag only for diagnostic purposes: + /// + /// - To warn about unreachable code: if, after processing a + /// sub-expression but before we have applied the effects of the + /// current node, we see that the flag is set to `Always`, we + /// can issue a warning. This corresponds to something like + /// `foo(return)`; we warn on the `foo()` expression. (We then + /// update the flag to `WarnedAlways` to suppress duplicate + /// reports.) Similarly, if we traverse to a fresh statement (or + /// tail expression) from a `Always` setting, we will issue a + /// warning. This corresponds to something like `{return; + /// foo();}` or `{return; 22}`, where we would warn on the + /// `foo()` or `22`. + /// + /// An expression represents dead code if, after checking it, + /// the diverges flag is set to something other than `Maybe`. + pub(super) diverges: Cell, - fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { - self.write_ty(hir_id, ty) - } -} + /// Whether any child nodes have any type errors. + pub(super) has_errors: Cell, -/// Controls whether the arguments are tupled. This is used for the call -/// operator. -/// -/// Tupling means that all call-side arguments are packed into a tuple and -/// passed as a single parameter. For example, if tupling is enabled, this -/// function: -/// -/// fn f(x: (isize, isize)) -/// -/// Can be called as: -/// -/// f(1, 2); -/// -/// Instead of: -/// -/// f((1, 2)); -#[derive(Clone, Eq, PartialEq)] -enum TupleArgumentsFlag { - DontTupleArguments, - TupleArguments, -} + pub(super) enclosing_breakables: RefCell>, -/// Controls how we perform fallback for unconstrained -/// type variables. -enum FallbackMode { - /// Do not fallback type variables to opaque types. - NoOpaque, - /// Perform all possible kinds of fallback, including - /// turning type variables to opaque types. - All, + pub(super) inh: &'a Inherited<'a, 'tcx>, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -3084,6 +162,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_env, err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, + ret_coercion_impl_trait: None, + ret_type_span: None, + in_tail_expr: false, ret_coercion_span: RefCell::new(None), resume_yield_tys: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), @@ -3107,7 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. - fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { + pub(super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { // FIXME: Combine these two 'if' expressions into one once // let chains are implemented if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { @@ -3149,7 +230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// version (resolve_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. - fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + pub(super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { debug!("resolve_vars_with_obligations(ty={:?})", ty); // No Infer()? Nothing needs doing. @@ -3176,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - fn record_deferred_call_resolution( + pub(super) fn record_deferred_call_resolution( &self, closure_def_id: DefId, r: DeferredCallResolution<'tcx>, @@ -3185,7 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_call_resolutions.entry(closure_def_id).or_default().push(r); } - fn remove_deferred_call_resolutions( + pub(super) fn remove_deferred_call_resolutions( &self, closure_def_id: DefId, ) -> Vec> { @@ -3425,7 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Replaces the opaque types from the given value with type variables, /// and records the `OpaqueTypeMap` for later use during writeback. See /// `InferCtxt::instantiate_opaque_types` for more details. - fn instantiate_opaque_types_from_value>( + pub(super) fn instantiate_opaque_types_from_value>( &self, parent_id: hir::HirId, value: &T, @@ -3456,14 +537,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { value } - fn normalize_associated_types_in(&self, span: Span, value: &T) -> T + pub(super) fn normalize_associated_types_in(&self, span: Span, value: &T) -> T where T: TypeFoldable<'tcx>, { self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) } - fn normalize_associated_types_in_as_infer_ok( + pub(super) fn normalize_associated_types_in_as_infer_ok( &self, span: Span, value: &T, @@ -3670,18 +751,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) } - fn check_casts(&self) { + pub(super) fn check_casts(&self) { let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); for cast in deferred_cast_checks.drain(..) { cast.check(self); } } - fn resolve_generator_interiors(&self, def_id: DefId) { + pub(super) fn resolve_generator_interiors(&self, def_id: DefId) { let mut generators = self.deferred_generator_interiors.borrow_mut(); for (body_id, interior, kind) in generators.drain(..) { self.select_obligations_where_possible(false, |_| {}); - generator_interior::resolve_interior(self, def_id, body_id, interior, kind); + super::generator_interior::resolve_interior(self, def_id, body_id, interior, kind); } } @@ -3697,7 +778,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Fallback becomes very dubious if we have encountered type-checking errors. // In that case, fallback to Error. // The return value indicates whether fallback has occurred. - fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { + pub(super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { use rustc_middle::ty::error::UnconstrainedNumeric::Neither; use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; @@ -3762,7 +843,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } - fn select_all_obligations_or_error(&self) { + pub(super) fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { self.report_fulfillment_errors(&errors, self.inh.body_id, false); @@ -3770,7 +851,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Select as many obligations as we can at present. - fn select_obligations_where_possible( + pub(super) fn select_obligations_where_possible( &self, fallback_has_occurred: bool, mutate_fullfillment_errors: impl Fn(&mut Vec>), @@ -3786,7 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// returns a type of `&T`, but the actual type we assign to the /// *expression* is `T`. So this function just peels off the return /// type by one layer to yield `T`. - fn make_overloaded_place_return_type( + pub(super) fn make_overloaded_place_return_type( &self, method: MethodCallee<'tcx>, ) -> ty::TypeAndMut<'tcx> { @@ -3797,7 +878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ret_ty.builtin_deref(true).unwrap() } - fn check_method_argument_types( + pub(super) fn check_method_argument_types( &self, sp: Span, expr: &'tcx hir::Expr<'tcx>, @@ -3862,7 +943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", trait_ref, self_ty, expected_vid ); - match self_ty.kind { + match *self_ty.kind() { ty::Infer(ty::TyVar(found_vid)) => { // FIXME: consider using `sub_root_var` here so we // can see through subtyping. @@ -3874,7 +955,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn obligations_for_self_ty<'b>( + pub(super) fn obligations_for_self_ty<'b>( &'b self, self_ty: ty::TyVid, ) -> impl Iterator, traits::PredicateObligation<'tcx>)> @@ -3918,19 +999,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // code is looking for a self type of a unresolved // inference variable. ty::PredicateAtom::ClosureKind(..) => None, + ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } }) .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) } - fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { + pub(super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { self.obligations_for_self_ty(self_ty) .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait()) } /// Generic function that factors out common logic from function calls, /// method calls and overloaded operators. - fn check_argument_types( + pub(super) fn check_argument_types( &self, sp: Span, expr: &'tcx hir::Expr<'tcx>, @@ -4042,7 +1124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let formal_tys = if tuple_arguments == TupleArguments { let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); - match tuple_type.kind { + match tuple_type.kind() { ty::Tuple(arg_types) if arg_types.len() != args.len() => { param_count_error(arg_types.len(), args.len(), "E0057", false, false); expected_arg_tys = vec![]; @@ -4050,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::Tuple(arg_types) => { expected_arg_tys = match expected_arg_tys.get(0) { - Some(&ty) => match ty.kind { + Some(&ty) => match ty.kind() { ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), _ => vec![], }, @@ -4195,7 +1277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // There are a few types which get autopromoted when passed via varargs // in C but we just error out instead and require explicit casts. let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); - match arg_ty.kind { + match arg_ty.kind() { ty::Float(ast::FloatTy::F32) => { variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); } @@ -4216,7 +1298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn err_args(&self, len: usize) -> Vec> { + pub(super) fn err_args(&self, len: usize) -> Vec> { vec![self.tcx.ty_error(); len] } @@ -4266,11 +1348,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } }) - .collect::>(); + .collect::>(); // Both checked and coerced types could have matched, thus we need to remove // duplicates. - referenced_in.sort(); + + // We sort primitive type usize here and can use unstable sort + referenced_in.sort_unstable(); referenced_in.dedup(); if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { @@ -4332,7 +1416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // AST fragment checking - fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { + pub(super) fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { let tcx = self.tcx; match lit.node { @@ -4345,7 +1429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Int(_) | ty::Uint(_) => Some(ty), ty::Char => Some(tcx.types.u8), ty::RawPtr(..) => Some(tcx.types.usize), @@ -4356,7 +1440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t), ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Float(_) => Some(ty), _ => None, }); @@ -4369,7 +1453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Unifies the output type with the expected type early, for more coercions /// and forward type information on the input expressions. - fn expected_inputs_for_expected_output( + pub(super) fn expected_inputs_for_expected_output( &self, call_span: Span, expected_ret: Expectation<'tcx>, @@ -4434,12 +1518,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(); return None; } - Res::Def(DefKind::Variant, _) => match ty.kind { + Res::Def(DefKind::Variant, _) => match ty.kind() { ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)), _ => bug!("unexpected type: {:?}", ty), }, Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) - | Res::SelfTy(..) => match ty.kind { + | Res::SelfTy(..) => match ty.kind() { ty::Adt(adt, substs) if !adt.is_enum() => { Some((adt.non_enum_variant(), adt.did, substs)) } @@ -4511,7 +1595,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn resolve_lang_item_path( + pub(super) fn resolve_lang_item_path( &self, lang_item: hir::LangItem, span: Span, @@ -4661,7 +1745,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) { + pub(super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) { err.span_suggestion_short( span.shrink_to_hi(), "consider using a semicolon here", @@ -4754,7 +1838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.span } - fn check_block_with_expected( + pub(super) fn check_block_with_expected( &self, blk: &'tcx hir::Block<'tcx>, expected: Expectation<'tcx>, @@ -4905,7 +1989,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. - fn get_node_fn_decl(&self, node: Node<'tcx>) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { + pub(super) fn get_node_fn_decl( + &self, + node: Node<'tcx>, + ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { match node { Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { // This is less than ideal, it will not suggest a return type span on any @@ -4976,7 +2063,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found: Ty<'tcx>, ) -> bool { let hir = self.tcx.hir(); - let (def_id, sig) = match found.kind { + let (def_id, sig) = match *found.kind() { ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()), _ => return false, @@ -5109,7 +2196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { 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)) + (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) { if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { let sp = self.sess().source_map().guess_head_span(sp); @@ -5162,7 +2249,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// When encountering the expected boxed value allocated in the stack, suggest allocating it /// in the heap by calling `Box::new()`. - fn suggest_boxing_when_appropriate( + pub(super) fn suggest_boxing_when_appropriate( &self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, @@ -5196,7 +2283,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn note_internal_mutation_in_method( + pub(super) fn note_internal_mutation_in_method( &self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, @@ -5242,7 +2329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. - fn suggest_calling_boxed_future_when_appropriate( + pub(super) fn suggest_calling_boxed_future_when_appropriate( &self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, @@ -5256,7 +2343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } let pin_did = self.tcx.lang_items().pin_type(); - match expected.kind { + match expected.kind() { ty::Adt(def, _) if Some(def.did) != pin_did => return false, // This guards the `unwrap` and `mk_box` below. _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, @@ -5268,7 +2355,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.can_coerce(new_found, expected), self.sess().source_map().span_to_snippet(expr.span), ) { - match found.kind { + match found.kind() { ty::Adt(def, _) if def.is_box() => { err.help("use `Box::pin`"); } @@ -5337,7 +2424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This routine checks if the return type is left as default, the method is not part of an /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return /// type. - fn suggest_missing_return_type( + pub(super) fn suggest_missing_return_type( &self, err: &mut DiagnosticBuilder<'_>, fn_decl: &hir::FnDecl<'_>, @@ -5376,7 +2463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = AstConv::ast_ty_to_ty(self, ty); debug!("suggest_missing_return_type: return type {:?}", ty); debug!("suggest_missing_return_type: expected type {:?}", ty); - if ty.kind == expected.kind { + if ty.kind() == expected.kind() { err.span_label(sp, format!("expected `{}` because of return type", expected)); return true; } @@ -5403,7 +2490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This routine checks if the found type `T` implements `Future` where `U` is the /// expected type. If this is the case, and we are inside of an async body, it suggests adding /// `.await` to the tail of the expression. - fn suggest_missing_await( + pub(super) fn suggest_missing_await( &self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, @@ -5466,7 +2553,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_missing_parentheses(&self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>) { + pub(super) fn suggest_missing_parentheses( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + ) { let sp = self.tcx.sess.source_map().start_point(expr.span); if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` @@ -5474,13 +2565,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn note_need_for_fn_pointer( + pub(super) fn note_need_for_fn_pointer( &self, err: &mut DiagnosticBuilder<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, ) { - let (sig, did, substs) = match (&expected.kind, &found.kind) { + let (sig, did, substs) = match (&expected.kind(), &found.kind()) { (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); @@ -5538,7 +2629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn could_remove_semicolon( + pub(super) fn could_remove_semicolon( &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, @@ -5551,7 +2642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return None, }; let last_expr_ty = self.node_ty(last_expr.hir_id); - if matches!(last_expr_ty.kind, ty::Error(_)) + if matches!(last_expr_ty.kind(), ty::Error(_)) || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() { return None; @@ -5680,7 +2771,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); - match ty.kind { + match *ty.kind() { ty::Adt(adt_def, substs) if adt_def.has_ctor() => { let variant = adt_def.non_enum_variant(); let ctor_def_id = variant.ctor_def_id.unwrap(); @@ -5900,7 +2991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } else { if !self.is_tainted_by_errors() { - self.need_type_info_err((**self).body_id, sp, ty, E0282) + self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282) .note("type must be known at this point") .emit(); } @@ -5910,7 +3001,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn with_breakable_ctxt R, R>( + pub(super) fn with_breakable_ctxt R, R>( &self, id: hir::HirId, ctxt: BreakableCtxt<'tcx>, @@ -5935,7 +3026,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Instantiate a QueryResponse in a probe context, without a /// good ObligationCause. - fn probe_instantiate_query_response( + pub(super) fn probe_instantiate_query_response( &self, span: Span, original_values: &OriginalQueryValues<'tcx>, @@ -5950,7 +3041,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Returns `true` if an expression is contained inside the LHS of an assignment expression. - fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { + pub(super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { let mut contained_in_place = false; while let hir::Node::Expr(parent_expr) = @@ -5971,70 +3062,139 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { contained_in_place } } +impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { + type Target = Inherited<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.inh + } +} + +impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } -fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { - debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); + fn item_def_id(&self) -> Option { + None + } - assert_eq!(generics.parent, None); + fn default_constness_for_trait_bounds(&self) -> hir::Constness { + // FIXME: refactor this into a method + let node = self.tcx.hir().get(self.body_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + fn_like.constness() + } else { + hir::Constness::NotConst + } + } - if generics.own_counts().types == 0 { - return; + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + let tcx = self.tcx; + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let item_id = tcx.hir().ty_param_owner(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + ty::GenericPredicates { + parent: None, + predicates: tcx.arena.alloc_from_iter( + self.param_env.caller_bounds().iter().filter_map(|predicate| { + match predicate.skip_binders() { + ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { + // HACK(eddyb) should get the original `Span`. + let span = tcx.def_span(def_id); + Some((predicate, span)) + } + _ => None, + } + }), + ), + } } - let mut params_used = BitSet::new_empty(generics.params.len()); + fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option> { + let v = match def { + Some(def) => infer::EarlyBoundRegion(span, def.name), + None => infer::MiscVariable(span), + }; + Some(self.next_region_var(v)) + } - if ty.references_error() { - // If there is already another error, do not emit - // an error for not using a type parameter. - assert!(tcx.sess.has_errors()); - return; + fn allow_ty_infer(&self) -> bool { + true } - for leaf in ty.walk() { - if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { - if let ty::Param(param) = leaf_ty.kind { - debug!("found use of ty param {:?}", param); - params_used.insert(param.index); + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { + return ty; } + unreachable!() + } else { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }) } } - for param in &generics.params { - if !params_used.contains(param.index) { - if let ty::GenericParamDefKind::Type { .. } = param.kind { - let span = tcx.def_span(param.def_id); - struct_span_err!( - tcx.sess, - span, - E0091, - "type parameter `{}` is unused", - param.name, - ) - .span_label(span, "unused type parameter") - .emit(); + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { + return ct; } + unreachable!() + } else { + self.next_const_var( + ty, + ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, + ) } } -} -fn fatally_break_rust(sess: &Session) { - let handler = sess.diagnostic(); - handler.span_bug_no_panic( - MultiSpan::new(), - "It looks like you're trying to break rust; would you like some ICE?", - ); - handler.note_without_error("the compiler expectedly panicked. this is a feature."); - handler.note_without_error( - "we would appreciate a joke overview: \ - https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", - ); - handler.note_without_error(&format!( - "rustc {} running on {}", - option_env!("CFG_VERSION").unwrap_or("unknown_version"), - config::host_triple(), - )); -} + fn projected_ty_from_poly_trait_ref( + &self, + span: Span, + item_def_id: DefId, + item_segment: &hir::PathSegment<'_>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Ty<'tcx> { + let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( + span, + infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), + &poly_trait_ref, + ); + + let item_substs = >::create_substs_for_associated_item( + self, + self.tcx, + span, + item_def_id, + item_segment, + trait_ref.substs, + ); + + self.tcx().mk_projection(item_def_id, item_substs) + } + + fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.has_escaping_bound_vars() { + ty // FIXME: normalization and escaping regions + } else { + self.normalize_associated_types_in(span, &ty) + } + } + + fn set_tainted_by_errors(&self) { + self.infcx.set_tainted_by_errors() + } -fn potentially_plural_count(count: usize, word: &str) -> String { - format!("{} {}{}", count, word, pluralize!(count)) + fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { + self.write_ty(hir_id, ty) + } } diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs new file mode 100644 index 0000000000..1d505cfa69 --- /dev/null +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -0,0 +1,120 @@ +use crate::check::{FnCtxt, LocalTy, UserType}; +use rustc_hir as hir; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::PatKind; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::ty::Ty; +use rustc_span::Span; +use rustc_trait_selection::traits; + +pub(super) struct GatherLocalsVisitor<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, + parent_id: hir::HirId, +} + +impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { + pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self { + Self { fcx, parent_id } + } + + fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { + match ty_opt { + None => { + // Infer the variable's type. + let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }); + self.fcx + .locals + .borrow_mut() + .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty }); + var_ty + } + Some(typ) => { + // Take type that the user specified. + self.fcx.locals.borrow_mut().insert(nid, typ); + typ.revealed_ty + } + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { + type Map = intravisit::ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + // Add explicitly-declared locals. + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + let local_ty = match local.ty { + Some(ref ty) => { + let o_ty = self.fcx.to_ty(&ty); + + let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { + self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span) + } else { + o_ty + }; + + let c_ty = self + .fcx + .inh + .infcx + .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty)); + debug!( + "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", + ty.hir_id, o_ty, revealed_ty, c_ty + ); + self.fcx + .typeck_results + .borrow_mut() + .user_provided_types_mut() + .insert(ty.hir_id, c_ty); + + Some(LocalTy { decl_ty: o_ty, revealed_ty }) + } + None => None, + }; + self.assign(local.span, local.hir_id, local_ty); + + debug!( + "local variable {:?} is assigned type {}", + local.pat, + self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty) + ); + intravisit::walk_local(self, local); + } + + // Add pattern bindings. + fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { + if let PatKind::Binding(_, _, ident, _) = p.kind { + let var_ty = self.assign(p.span, p.hir_id, None); + + if !self.fcx.tcx.features().unsized_locals { + self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); + } + + debug!( + "pattern binding {} is assigned to {} with type {:?}", + ident, + self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), + var_ty + ); + } + intravisit::walk_pat(self, p); + } + + // Don't descend into the bodies of nested closures. + fn visit_fn( + &mut self, + _: intravisit::FnKind<'tcx>, + _: &'tcx hir::FnDecl<'tcx>, + _: hir::BodyId, + _: Span, + _: hir::HirId, + ) { + } +} diff --git a/src/librustc_typeck/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs similarity index 100% rename from src/librustc_typeck/check/generator_interior.rs rename to compiler/rustc_typeck/src/check/generator_interior.rs diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs new file mode 100644 index 0000000000..7e580485c3 --- /dev/null +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -0,0 +1,167 @@ +use super::callee::DeferredCallResolution; +use super::MaybeInProgressTables; + +use rustc_data_structures::fx::FxHashMap; +use rustc_hir as hir; +use rustc_hir::def_id::{DefIdMap, LocalDefId}; +use rustc_hir::HirIdMap; +use rustc_infer::infer; +use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::{self, Span}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::OpaqueTypeDecl; +use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt}; + +use std::cell::RefCell; +use std::ops::Deref; + +/// Closures defined within the function. For example: +/// +/// fn foo() { +/// bar(move|| { ... }) +/// } +/// +/// Here, the function `foo()` and the closure passed to +/// `bar()` will each have their own `FnCtxt`, but they will +/// share the inherited fields. +pub struct Inherited<'a, 'tcx> { + pub(super) infcx: InferCtxt<'a, 'tcx>, + + pub(super) typeck_results: super::MaybeInProgressTables<'a, 'tcx>, + + pub(super) locals: RefCell>>, + + pub(super) fulfillment_cx: RefCell>>, + + // Some additional `Sized` obligations badly affect type inference. + // These obligations are added in a later stage of typeck. + pub(super) deferred_sized_obligations: + RefCell, Span, traits::ObligationCauseCode<'tcx>)>>, + + // When we process a call like `c()` where `c` is a closure type, + // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or + // `FnOnce` closure. In that case, we defer full resolution of the + // call until upvar inference can kick in and make the + // decision. We keep these deferred resolutions grouped by the + // def-id of the closure, so that once we decide, we can easily go + // back and process them. + pub(super) deferred_call_resolutions: RefCell>>>, + + pub(super) deferred_cast_checks: RefCell>>, + + pub(super) deferred_generator_interiors: + RefCell, hir::GeneratorKind)>>, + + // Opaque types found in explicit return types and their + // associated fresh inference variable. Writeback resolves these + // variables to get the concrete type, which can be used to + // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. + pub(super) opaque_types: RefCell>>, + + /// A map from inference variables created from opaque + /// type instantiations (`ty::Infer`) to the actual opaque + /// type (`ty::Opaque`). Used during fallback to map unconstrained + /// opaque type inference variables to their corresponding + /// opaque type. + pub(super) opaque_types_vars: RefCell, Ty<'tcx>>>, + + pub(super) body_id: Option, +} + +impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { + type Target = InferCtxt<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.infcx + } +} + +/// Helper type of a temporary returned by `Inherited::build(...)`. +/// Necessary because we can't write the following bound: +/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`. +pub struct InheritedBuilder<'tcx> { + infcx: infer::InferCtxtBuilder<'tcx>, + def_id: LocalDefId, +} + +impl Inherited<'_, 'tcx> { + pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> { + let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; + + InheritedBuilder { + infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner), + def_id, + } + } +} + +impl<'tcx> InheritedBuilder<'tcx> { + pub fn enter(&mut self, f: F) -> R + where + F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R, + { + let def_id = self.def_id; + self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) + } +} + +impl Inherited<'a, 'tcx> { + pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { + let tcx = infcx.tcx; + let item_id = tcx.hir().local_def_id_to_hir_id(def_id); + let body_id = tcx.hir().maybe_body_owned_by(item_id); + + Inherited { + typeck_results: MaybeInProgressTables { + maybe_typeck_results: infcx.in_progress_typeck_results, + }, + infcx, + fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), + locals: RefCell::new(Default::default()), + deferred_sized_obligations: RefCell::new(Vec::new()), + deferred_call_resolutions: RefCell::new(Default::default()), + deferred_cast_checks: RefCell::new(Vec::new()), + deferred_generator_interiors: RefCell::new(Vec::new()), + opaque_types: RefCell::new(Default::default()), + opaque_types_vars: RefCell::new(Default::default()), + body_id, + } + } + + pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { + debug!("register_predicate({:?})", obligation); + if obligation.has_escaping_bound_vars() { + span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); + } + self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation); + } + + pub(super) fn register_predicates(&self, obligations: I) + where + I: IntoIterator>, + { + for obligation in obligations { + self.register_predicate(obligation); + } + } + + pub(super) fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + self.register_predicates(infer_ok.obligations); + infer_ok.value + } + + pub(super) fn normalize_associated_types_in( + &self, + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> T + where + T: TypeFoldable<'tcx>, + { + let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value); + self.register_infer_ok_obligations(ok) + } +} diff --git a/src/librustc_typeck/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs similarity index 93% rename from src/librustc_typeck/check/intrinsic.rs rename to compiler/rustc_typeck/src/check/intrinsic.rs index 47cea8649e..2ee867c2dd 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -1,6 +1,10 @@ //! Type-checking for the rust-intrinsic and platform-intrinsic //! intrinsics that the compiler exposes. +use crate::errors::{ + SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction, + WrongNumberOfTypeArgumentsToInstrinsic, +}; use crate::require_same_types; use rustc_errors::struct_span_err; @@ -41,17 +45,11 @@ fn equate_intrinsic_type<'tcx>( _ => bug!(), }; - struct_span_err!( - tcx.sess, + tcx.sess.emit_err(WrongNumberOfTypeArgumentsToInstrinsic { span, - E0094, - "intrinsic has wrong number of type \ - parameters: found {}, expected {}", - i_n_tps, - n_tps - ) - .span_label(span, format!("expected {} type parameter", n_tps)) - .emit(); + found: i_n_tps, + expected: n_tps, + }); return; } @@ -108,8 +106,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { } } -/// Remember to add all intrinsics here, in librustc_codegen_llvm/intrinsic.rs, -/// and in libcore/intrinsics.rs +/// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`, +/// and in `library/core/src/intrinsics.rs`. pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n))); let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id(); @@ -146,15 +144,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { | "umin" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], param(0)), "fence" | "singlethreadfence" => (0, Vec::new(), tcx.mk_unit()), op => { - struct_span_err!( - tcx.sess, - it.span, - E0092, - "unrecognized atomic operation function: `{}`", - op - ) - .span_label(it.span, "unrecognized atomic operation") - .emit(); + tcx.sess.emit_err(UnrecognizedAtomicOperation { span: it.span, op }); return; } }; @@ -380,15 +370,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), other => { - struct_span_err!( - tcx.sess, - it.span, - E0093, - "unrecognized intrinsic function: `{}`", - other, - ) - .span_label(it.span, "unrecognized intrinsic") - .emit(); + tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); return; } }; @@ -468,14 +450,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) (2, params, param(1)) } Err(_) => { - struct_span_err!( - tcx.sess, - it.span, - E0439, - "invalid `simd_shuffle`, needs length: `{}`", - name - ) - .emit(); + tcx.sess.emit_err(SimdShuffleMissingLength { span: it.span, name }); return; } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs similarity index 99% rename from src/librustc_typeck/check/method/confirm.rs rename to compiler/rustc_typeck/src/check/method/confirm.rs index 41e37ee975..fd2700b85e 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -137,7 +137,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ) -> Ty<'tcx> { // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various typeck results. - let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); + let mut autoderef = + self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span); let (_, n) = match autoderef.nth(pick.autoderefs) { Some(n) => n, None => { @@ -269,7 +270,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.fcx .autoderef(self.span, self_ty) .include_raw_pointers() - .find_map(|(ty, _)| match ty.kind { + .find_map(|(ty, _)| match ty.kind() { ty::Dynamic(ref data, ..) => Some(closure( self, ty, @@ -464,7 +465,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { } _ => None, }) - .find_map(|(trait_pred, span)| match trait_pred.self_ty().kind { + .find_map(|(trait_pred, span)| match trait_pred.self_ty().kind() { ty::Dynamic(..) => Some(span), _ => None, }) diff --git a/src/librustc_typeck/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs similarity index 99% rename from src/librustc_typeck/check/method/mod.rs rename to compiler/rustc_typeck/src/check/method/mod.rs index c9a4df0317..84bc3979e1 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(span) = result.illegal_sized_bound { let mut needs_mut = false; - if let ty::Ref(region, t_type, mutability) = self_ty.kind { + if let ty::Ref(region, t_type, mutability) = self_ty.kind() { let trait_type = self .tcx .mk_ref(region, ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() }); @@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; // Check if we have an enum variant. - if let ty::Adt(adt_def, _) = self_ty.kind { + if let ty::Adt(adt_def, _) = self_ty.kind() { if adt_def.is_enum() { let variant_def = adt_def .variants diff --git a/src/librustc_typeck/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs similarity index 98% rename from src/librustc_typeck/check/method/probe.rs rename to compiler/rustc_typeck/src/check/method/probe.rs index 7ac6681be1..c1ba29284d 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -4,6 +4,7 @@ use super::NoMatchData; use super::{CandidateSource, ImplSource, TraitSource}; use crate::check::FnCtxt; +use crate::errors::MethodCallOnUnknownType; use crate::hir::def::DefKind; use crate::hir::def_id::DefId; @@ -11,7 +12,6 @@ use rustc_ast as ast; use rustc_ast::util::lev_distance::{find_best_match_for_name, lev_distance}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_infer::infer::canonical::OriginalQueryValues; @@ -376,14 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) if self.tcx.sess.rust_2018() { - struct_span_err!( - self.tcx.sess, - span, - E0699, - "the type of this value must be known to call a method on a raw pointer on \ - it" - ) - .emit(); + self.tcx.sess.emit_err(MethodCallOnUnknownType { span }); } else { self.tcx.struct_span_lint_hir( lint::builtin::TYVAR_BEHIND_RAW_POINTER, @@ -401,7 +394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .probe_instantiate_query_response(span, &orig_values, ty) .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); let ty = self.structurally_resolved_type(span, ty.value); - assert!(matches!(ty.kind, ty::Error(_))); + assert!(matches!(ty.kind(), ty::Error(_))); return Err(MethodError::NoMatch(NoMatchData::new( Vec::new(), Vec::new(), @@ -453,9 +446,10 @@ fn method_autoderef_steps<'tcx>( tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| { let ParamEnvAnd { param_env, value: self_ty } = goal; - let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty) - .include_raw_pointers() - .silence_errors(); + let mut autoderef = + Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP) + .include_raw_pointers() + .silence_errors(); let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef .by_ref() @@ -469,7 +463,7 @@ fn method_autoderef_steps<'tcx>( from_unsafe_deref: reached_raw_pointer, unsize: false, }; - if let ty::RawPtr(_) = ty.kind { + if let ty::RawPtr(_) = ty.kind() { // all the subsequent steps will be from_unsafe_deref reached_raw_pointer = true; } @@ -478,7 +472,7 @@ fn method_autoderef_steps<'tcx>( .collect(); let final_ty = autoderef.final_ty(true); - let opt_bad_ty = match final_ty.kind { + let opt_bad_ty = match final_ty.kind() { ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, ty: infcx @@ -587,7 +581,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { debug!("assemble_probe: self_ty={:?}", self_ty); let lang_items = self.tcx.lang_items(); - match self_ty.value.value.kind { + match *self_ty.value.value.kind() { ty::Dynamic(ref data, ..) => { if let Some(p) = data.principal() { // Subtle: we can't use `instantiate_query_response` here: using it will @@ -759,7 +753,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) { debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty); - let principal = match self_ty.kind { + let principal = match self_ty.kind() { ty::Dynamic(ref data, ..) => Some(data), _ => None, } @@ -806,7 +800,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.param_env.caller_bounds().iter().map(ty::Predicate::skip_binders).filter_map( |predicate| match predicate { ty::PredicateAtom::Trait(trait_predicate, _) => { - match trait_predicate.trait_ref.self_ty().kind { + match trait_predicate.trait_ref.self_ty().kind() { ty::Param(ref p) if *p == param_ty => { Some(ty::Binder::bind(trait_predicate.trait_ref)) } @@ -821,7 +815,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, }, ); @@ -1125,7 +1120,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { pick.autoderefs = step.autoderefs; // Insert a `&*` or `&mut *` if this is a reference type: - if let ty::Ref(_, _, mutbl) = step.self_ty.value.value.kind { + if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() { pick.autoderefs += 1; pick.autoref = Some(mutbl); } @@ -1311,7 +1306,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .at(&ObligationCause::dummy(), self.param_env) .sup(candidate.xform_self_ty, self_ty); match self.select_trait_candidate(trait_ref) { - Ok(Some(traits::ImplSource::ImplSourceUserDefined(ref impl_data))) => { + Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { // If only a single impl matches, make the error message point // to that impl. ImplSource(impl_data.impl_def_id) diff --git a/src/librustc_typeck/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs similarity index 95% rename from src/librustc_typeck/check/method/suggest.rs rename to compiler/rustc_typeck/src/check/method/suggest.rs index 896bfc0795..e33a4e98c5 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -21,6 +21,7 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{source_map, FileName, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::Obligation; +use rustc_trait_selection::traits::SelectionContext; use std::cmp::Ordering; @@ -30,7 +31,7 @@ use super::{CandidateSource, MethodError, NoMatchData}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { let tcx = self.tcx; - match ty.kind { + match ty.kind() { // Not all of these (e.g., unsafe fns) implement `FnOnce`, // so we look for these beforehand. ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true, @@ -392,6 +393,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { actual.prefix_string(), ty_str, ); + if let Mode::MethodCall = mode { + if let SelfSource::MethodCall(call) = source { + self.suggest_await_before_method( + &mut err, item_name, actual, call, span, + ); + } + } if let Some(span) = tcx.sess.confused_type_with_std_module.borrow().get(&span) { @@ -405,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } - if let ty::RawPtr(_) = &actual.kind { + if let ty::RawPtr(_) = &actual.kind() { err.note( "try using `<*const T>::as_ref()` to get a reference to the \ type behind the pointer: https://doc.rust-lang.org/std/\ @@ -442,7 +450,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // give a helping note that it has to be called as `(x.f)(...)`. if let SelfSource::MethodCall(expr) = source { let field_receiver = - self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind { + self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() { ty::Adt(def, substs) if !def.is_enum() => { let variant = &def.non_enum_variant(); self.tcx.find_field_index(item_name, variant).map(|index| { @@ -537,7 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // original type that has the associated function for accurate suggestions. // (#61411) let ty = tcx.at(span).type_of(*impl_did); - match (&ty.peel_refs().kind, &actual.peel_refs().kind) { + match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) { (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => { // Use `actual` as it will have more `substs` filled in. self.ty_to_value_string(actual.peel_refs()) @@ -575,9 +583,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| { // We don't care about regions here, so it's fine to skip the binder here. if let (ty::Param(_), ty::PredicateAtom::Trait(p, _)) = - (&self_ty.kind, parent_pred.skip_binders()) + (self_ty.kind(), parent_pred.skip_binders()) { - if let ty::Adt(def, _) = p.trait_ref.self_ty().kind { + if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() { let node = def.did.as_local().map(|def_id| { self.tcx .hir() @@ -607,7 +615,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "doesn't satisfy `{}`", if obligation.len() > 50 { quiet } else { obligation } ); - match &self_ty.kind { + match &self_ty.kind() { // Point at the type that couldn't satisfy the bound. ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)), // Point at the trait object that couldn't satisfy the bound. @@ -829,7 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); self.suggest_use_candidates(&mut err, help, candidates); } - if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind { + if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() { if needs_mut { let trait_type = self.tcx.mk_ref( region, @@ -848,12 +856,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Print out the type for use in value namespace. fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String { - match ty.kind { + match ty.kind() { ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)), _ => self.ty_to_string(ty), } } + fn suggest_await_before_method( + &self, + err: &mut DiagnosticBuilder<'_>, + item_name: Ident, + ty: Ty<'tcx>, + call: &hir::Expr<'_>, + span: Span, + ) { + if let ty::Opaque(def_id, _) = *ty.kind() { + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + // Future::Output + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + + let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); + let cause = self.misc(span); + let mut selcx = SelectionContext::new(&self.infcx); + let mut obligations = vec![]; + if let Some(projection_ty) = projection_ty { + let normalized_ty = rustc_trait_selection::traits::normalize_projection_type( + &mut selcx, + self.param_env, + projection_ty, + cause, + 0, + &mut obligations, + ); + debug!( + "suggest_await_before_method: normalized_ty={:?}, ty_kind={:?}", + self.resolve_vars_if_possible(&normalized_ty), + normalized_ty.kind(), + ); + let method_exists = self.method_exists(item_name, normalized_ty, call.hir_id, true); + debug!("suggest_await_before_method: is_method_exist={}", method_exists); + if method_exists { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider awaiting before this method call", + "await.".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + } + fn suggest_use_candidates( &self, err: &mut DiagnosticBuilder<'_>, @@ -1030,9 +1089,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidates.sort_by(|a, b| a.cmp(b).reverse()); candidates.dedup(); - let param_type = match rcvr_ty.kind { + let param_type = match rcvr_ty.kind() { ty::Param(param) => Some(param), - ty::Ref(_, ty, _) => match ty.kind { + ty::Ref(_, ty, _) => match ty.kind() { ty::Param(param) => Some(param), _ => None, }, @@ -1184,7 +1243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// autoderefs of `rcvr_ty`. fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool { fn is_local(ty: Ty<'_>) -> bool { - match ty.kind { + match ty.kind() { ty::Adt(def, _) => def.did.is_local(), ty::Foreign(did) => did.is_local(), diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs new file mode 100644 index 0000000000..97172d391b --- /dev/null +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -0,0 +1,1151 @@ +/*! + +# typeck: check phase + +Within the check phase of type check, we check each item one at a time +(bodies of function expressions are checked as part of the containing +function). Inference is used to supply types wherever they are unknown. + +By far the most complex case is checking the body of a function. This +can be broken down into several distinct phases: + +- gather: creates type variables to represent the type of each local + variable and pattern binding. + +- main: the main pass does the lion's share of the work: it + determines the types of all expressions, resolves + methods, checks for most invalid conditions, and so forth. In + some cases, where a type is unknown, it may create a type or region + variable and use that as the type of an expression. + + In the process of checking, various constraints will be placed on + these type variables through the subtyping relationships requested + through the `demand` module. The `infer` module is in charge + of resolving those constraints. + +- regionck: after main is complete, the regionck pass goes over all + types looking for regions and making sure that they did not escape + into places they are not in scope. This may also influence the + final assignments of the various region variables if there is some + flexibility. + +- writeback: writes the final types within a function body, replacing + type variables with their final inferred types. These final types + are written into the `tcx.node_types` table, which should *never* contain + any reference to a type variable. + +## Intermediate types + +While type checking a function, the intermediate types for the +expressions, blocks, and so forth contained within the function are +stored in `fcx.node_types` and `fcx.node_substs`. These types +may contain unresolved type variables. After type checking is +complete, the functions in the writeback module are used to take the +types from this table, resolve them, and then write them into their +permanent home in the type context `tcx`. + +This means that during inferencing you should use `fcx.write_ty()` +and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of +nodes within the function. + +The types of top-level items, which never contain unbound type +variables, are stored directly into the `tcx` typeck_results. + +N.B., a type variable is not the same thing as a type parameter. A +type variable is rather an "instance" of a type parameter: that is, +given a generic function `fn foo(t: T)`: while checking the +function `foo`, the type `ty_param(0)` refers to the type `T`, which +is treated in abstract. When `foo()` is called, however, `T` will be +substituted for a fresh type variable `N`. This variable will +eventually be resolved to some concrete type (which might itself be +type parameter). + +*/ + +pub mod _match; +mod autoderef; +mod callee; +pub mod cast; +mod check; +mod closure; +pub mod coercion; +mod compare_method; +pub mod demand; +mod diverges; +pub mod dropck; +mod expectation; +mod expr; +mod fn_ctxt; +mod gather_locals; +mod generator_interior; +mod inherited; +pub mod intrinsic; +pub mod method; +mod op; +mod pat; +mod place_op; +mod regionck; +mod upvar; +mod wfcheck; +pub mod writeback; + +use check::{ + check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types, + check_trait_item_well_formed, +}; +pub use check::{check_item_type, check_wf_new}; +pub use diverges::Diverges; +pub use expectation::Expectation; +pub use fn_ctxt::FnCtxt; +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}; +use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::intravisit::Visitor; +use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_hir::{HirIdMap, Node}; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::Idx; +use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::WithConstness; +use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType}; +use rustc_session::config; +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, MultiSpan, Span}; +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::{Ref, RefCell, RefMut}; + +use crate::require_c_abi_if_c_variadic; +use crate::util::common::indenter; + +use self::coercion::DynamicCoerceMany; +pub use self::Expectation::*; + +#[macro_export] +macro_rules! type_error_struct { + ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ + if $typ.references_error() { + $session.diagnostic().struct_dummy() + } else { + rustc_errors::struct_span_err!($session, $span, $code, $($message)*) + } + }) +} + +/// The type of a local binding, including the revealed type for anon types. +#[derive(Copy, Clone, Debug)] +pub struct LocalTy<'tcx> { + decl_ty: Ty<'tcx>, + revealed_ty: Ty<'tcx>, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Needs { + MutPlace, + None, +} + +impl Needs { + fn maybe_mut_place(m: hir::Mutability) -> Self { + match m { + hir::Mutability::Mut => Needs::MutPlace, + hir::Mutability::Not => Needs::None, + } + } +} + +#[derive(Copy, Clone)] +pub struct UnsafetyState { + pub def: hir::HirId, + pub unsafety: hir::Unsafety, + pub unsafe_push_count: u32, + from_fn: bool, +} + +impl UnsafetyState { + pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState { + UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true } + } + + pub fn recurse(&mut self, blk: &hir::Block<'_>) -> UnsafetyState { + use hir::BlockCheckMode; + match self.unsafety { + // If this unsafe, then if the outer function was already marked as + // unsafe we shouldn't attribute the unsafe'ness to the block. This + // way the block can be warned about instead of ignoring this + // extraneous block (functions are never warned about). + hir::Unsafety::Unsafe if self.from_fn => *self, + + unsafety => { + let (unsafety, def, count) = match blk.rules { + BlockCheckMode::PushUnsafeBlock(..) => { + (unsafety, blk.hir_id, self.unsafe_push_count.checked_add(1).unwrap()) + } + BlockCheckMode::PopUnsafeBlock(..) => { + (unsafety, blk.hir_id, self.unsafe_push_count.checked_sub(1).unwrap()) + } + BlockCheckMode::UnsafeBlock(..) => { + (hir::Unsafety::Unsafe, blk.hir_id, self.unsafe_push_count) + } + BlockCheckMode::DefaultBlock => (unsafety, self.def, self.unsafe_push_count), + }; + UnsafetyState { def, unsafety, unsafe_push_count: count, from_fn: false } + } + } + } +} + +#[derive(Debug, Copy, Clone)] +pub enum PlaceOp { + Deref, + Index, +} + +pub struct BreakableCtxt<'tcx> { + may_break: bool, + + // this is `null` for loops where break with a value is illegal, + // such as `while`, `for`, and `while let` + coerce: Option>, +} + +pub struct EnclosingBreakables<'tcx> { + stack: Vec>, + by_id: HirIdMap, +} + +impl<'tcx> EnclosingBreakables<'tcx> { + fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { + self.opt_find_breakable(target_id).unwrap_or_else(|| { + bug!("could not find enclosing breakable with id {}", target_id); + }) + } + + fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> { + match self.by_id.get(&target_id) { + Some(ix) => Some(&mut self.stack[*ix]), + None => None, + } + } +} + +pub fn provide(providers: &mut Providers) { + method::provide(providers); + *providers = Providers { + typeck_item_bodies, + typeck_const_arg, + typeck, + diagnostic_only_typeck, + has_typeck_results, + adt_destructor, + used_trait_imports, + check_item_well_formed, + check_trait_item_well_formed, + check_impl_item_well_formed, + check_mod_item_types, + ..*providers + }; +} + +fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) +} + +/// If this `DefId` is a "primary tables entry", returns +/// `Some((body_id, header, decl))` with information about +/// it's body-id, fn-header and fn-decl (if any). Otherwise, +/// returns `None`. +/// +/// If this function returns `Some`, then `typeck_results(def_id)` will +/// succeed; if it returns `None`, then `typeck_results(def_id)` may or +/// may not succeed. In some cases where this function returns `None` +/// (notably closures), `typeck_results(def_id)` would wind up +/// redirecting to the owning function. +fn primary_body_of( + tcx: TyCtxt<'_>, + id: hir::HirId, +) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnHeader>, Option<&hir::FnDecl<'_>>)> { + match tcx.hir().get(id) { + Node::Item(item) => match item.kind { + hir::ItemKind::Const(ref ty, body) | hir::ItemKind::Static(ref ty, _, body) => { + Some((body, Some(ty), None, None)) + } + hir::ItemKind::Fn(ref sig, .., body) => { + Some((body, None, Some(&sig.header), Some(&sig.decl))) + } + _ => None, + }, + Node::TraitItem(item) => match item.kind { + hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None, None)), + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { + Some((body, None, Some(&sig.header), Some(&sig.decl))) + } + _ => None, + }, + Node::ImplItem(item) => match item.kind { + hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None, None)), + hir::ImplItemKind::Fn(ref sig, body) => { + Some((body, None, Some(&sig.header), Some(&sig.decl))) + } + _ => None, + }, + Node::AnonConst(constant) => Some((constant.body, None, None, None)), + _ => None, + } +} + +fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + // Closures' typeck results come from their outermost function, + // as they are part of the same "inference environment". + let outer_def_id = tcx.closure_base_def_id(def_id); + if outer_def_id != def_id { + return tcx.has_typeck_results(outer_def_id); + } + + if let Some(def_id) = def_id.as_local() { + let id = tcx.hir().local_def_id_to_hir_id(def_id); + primary_body_of(tcx, id).is_some() + } else { + false + } +} + +fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet { + &*tcx.typeck(def_id).used_trait_imports +} + +/// Inspects the substs of opaque types, replacing any inference variables +/// with proper generic parameter from the identity substs. +/// +/// This is run after we normalize the function signature, to fix any inference +/// variables introduced by the projection of associated types. This ensures that +/// any opaque types used in the signature continue to refer to generic parameters, +/// allowing them to be considered for defining uses in the function body +/// +/// For example, consider this code. +/// +/// ```rust +/// trait MyTrait { +/// type MyItem; +/// fn use_it(self) -> Self::MyItem +/// } +/// impl MyTrait for T where T: Iterator { +/// type MyItem = impl Iterator; +/// fn use_it(self) -> Self::MyItem { +/// self +/// } +/// } +/// ``` +/// +/// When we normalize the signature of `use_it` from the impl block, +/// we will normalize `Self::MyItem` to the opaque type `impl Iterator` +/// However, this projection result may contain inference variables, due +/// to the way that projection works. We didn't have any inference variables +/// in the signature to begin with - leaving them in will cause us to incorrectly +/// conclude that we don't have a defining use of `MyItem`. By mapping inference +/// variables back to the actual generic parameters, we will correctly see that +/// we have a defining use of `MyItem` +fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: &T) -> T +where + T: TypeFoldable<'tcx>, +{ + struct FixupFolder<'tcx> { + tcx: TyCtxt<'tcx>, + } + + impl<'tcx> TypeFolder<'tcx> for FixupFolder<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match *ty.kind() { + ty::Opaque(def_id, substs) => { + debug!("fixup_opaque_types: found type {:?}", ty); + // Here, we replace any inference variables that occur within + // the substs of an opaque type. By definition, any type occurring + // in the substs has a corresponding generic parameter, which is what + // we replace it with. + // This replacement is only run on the function signature, so any + // inference variables that we come across must be the rust of projection + // (there's no other way for a user to get inference variables into + // a function signature). + if ty.needs_infer() { + let new_substs = InternalSubsts::for_item(self.tcx, def_id, |param, _| { + let old_param = substs[param.index as usize]; + match old_param.unpack() { + GenericArgKind::Type(old_ty) => { + if let ty::Infer(_) = old_ty.kind() { + // Replace inference type with a generic parameter + self.tcx.mk_param_from_def(param) + } else { + old_param.fold_with(self) + } + } + GenericArgKind::Const(old_const) => { + if let ty::ConstKind::Infer(_) = old_const.val { + // This should never happen - we currently do not support + // 'const projections', e.g.: + // `impl MyTrait for T where ::MyConst == 25` + // which should be the only way for us to end up with a const inference + // variable after projection. If Rust ever gains support for this kind + // of projection, this should *probably* be changed to + // `self.tcx.mk_param_from_def(param)` + bug!( + "Found infer const: `{:?}` in opaque type: {:?}", + old_const, + ty + ); + } else { + old_param.fold_with(self) + } + } + GenericArgKind::Lifetime(old_region) => { + if let RegionKind::ReVar(_) = old_region { + self.tcx.mk_param_from_def(param) + } else { + old_param.fold_with(self) + } + } + } + }); + let new_ty = self.tcx.mk_opaque(def_id, new_substs); + debug!("fixup_opaque_types: new type: {:?}", new_ty); + new_ty + } else { + ty + } + } + _ => ty.super_fold_with(self), + } + } + } + + debug!("fixup_opaque_types({:?})", val); + val.fold_with(&mut FixupFolder { tcx }) +} + +fn typeck_const_arg<'tcx>( + tcx: TyCtxt<'tcx>, + (did, param_did): (LocalDefId, DefId), +) -> &ty::TypeckResults<'tcx> { + let fallback = move || tcx.type_of(param_did); + typeck_with_fallback(tcx, did, fallback) +} + +fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { + if let Some(param_did) = tcx.opt_const_param_of(def_id) { + tcx.typeck_const_arg((def_id, param_did)) + } else { + let fallback = move || tcx.type_of(def_id.to_def_id()); + typeck_with_fallback(tcx, def_id, fallback) + } +} + +/// Used only to get `TypeckResults` for type inference during error recovery. +/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. +fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { + let fallback = move || { + let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); + tcx.ty_error_with_message(span, "diagnostic only typeck table used") + }; + typeck_with_fallback(tcx, def_id, fallback) +} + +fn typeck_with_fallback<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + fallback: impl Fn() -> Ty<'tcx> + 'tcx, +) -> &'tcx ty::TypeckResults<'tcx> { + // Closures' typeck results come from their outermost function, + // as they are part of the same "inference environment". + let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); + if outer_def_id != def_id { + return tcx.typeck(outer_def_id); + } + + let id = tcx.hir().local_def_id_to_hir_id(def_id); + let span = tcx.hir().span(id); + + // Figure out what primary body this item has. + let (body_id, body_ty, fn_header, fn_decl) = primary_body_of(tcx, id).unwrap_or_else(|| { + span_bug!(span, "can't type-check body of {:?}", def_id); + }); + let body = tcx.hir().body(body_id); + + let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { + let param_env = tcx.param_env(def_id); + let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) { + let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { + let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); + AstConv::ty_of_fn( + &fcx, + header.unsafety, + header.abi, + decl, + &hir::Generics::empty(), + None, + ) + } else { + tcx.fn_sig(def_id) + }; + + check_abi(tcx, span, fn_sig.abi()); + + // Compute the fty from point of view of inside the fn. + let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), &fn_sig); + let fn_sig = inh.normalize_associated_types_in( + body.value.span, + body_id.hir_id, + param_env, + &fn_sig, + ); + + let fn_sig = fixup_opaque_types(tcx, &fn_sig); + + let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0; + fcx + } else { + let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); + let expected_type = body_ty + .and_then(|ty| match ty.kind { + hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)), + _ => None, + }) + .unwrap_or_else(fallback); + let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); + fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); + + let revealed_ty = if tcx.features().impl_trait_in_bindings { + fcx.instantiate_opaque_types_from_value(id, &expected_type, body.value.span) + } else { + expected_type + }; + + // Gather locals in statics (because of block expressions). + GatherLocalsVisitor::new(&fcx, id).visit_body(body); + + fcx.check_expr_coercable_to_type(&body.value, revealed_ty, None); + + fcx.write_ty(id, revealed_ty); + + fcx + }; + + // All type checking constraints were added, try to fallback unsolved variables. + fcx.select_obligations_where_possible(false, |_| {}); + let mut fallback_has_occurred = false; + + // We do fallback in two passes, to try to generate + // better error messages. + // The first time, we do *not* replace opaque types. + for ty in &fcx.unsolved_variables() { + fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque); + } + // We now see if we can make progress. This might + // cause us to unify inference variables for opaque types, + // since we may have unified some other type variables + // during the first phase of fallback. + // This means that we only replace inference variables with their underlying + // opaque types as a last resort. + // + // In code like this: + // + // ```rust + // type MyType = impl Copy; + // fn produce() -> MyType { true } + // fn bad_produce() -> MyType { panic!() } + // ``` + // + // we want to unify the opaque inference variable in `bad_produce` + // with the diverging fallback for `panic!` (e.g. `()` or `!`). + // This will produce a nice error message about conflicting concrete + // types for `MyType`. + // + // If we had tried to fallback the opaque inference variable to `MyType`, + // we will generate a confusing type-check error that does not explicitly + // refer to opaque types. + fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); + + // We now run fallback again, but this time we allow it to replace + // unconstrained opaque type variables, in addition to performing + // other kinds of fallback. + for ty in &fcx.unsolved_variables() { + fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All); + } + + // See if we can make any more progress. + fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); + + // Even though coercion casts provide type hints, we check casts after fallback for + // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. + fcx.check_casts(); + + // Closure and generator analysis may run after fallback + // because they don't constrain other type variables. + fcx.closure_analyze(body); + assert!(fcx.deferred_call_resolutions.borrow().is_empty()); + fcx.resolve_generator_interiors(def_id.to_def_id()); + + for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { + let ty = fcx.normalize_ty(span, ty); + fcx.require_type_is_sized(ty, span, code); + } + + fcx.select_all_obligations_or_error(); + + if fn_decl.is_some() { + fcx.regionck_fn(id, body); + } else { + fcx.regionck_expr(body); + } + + fcx.resolve_type_vars_in_body(body) + }); + + // Consistency check our TypeckResults instance can hold all ItemLocalIds + // it will need to hold. + assert_eq!(typeck_results.hir_owner, id.owner); + + typeck_results +} + +/// When `check_fn` is invoked on a generator (i.e., a body that +/// includes yield), it returns back some information about the yield +/// points. +struct GeneratorTypes<'tcx> { + /// Type of generator argument / values returned by `yield`. + resume_ty: Ty<'tcx>, + + /// Type of value that is yielded. + yield_ty: Ty<'tcx>, + + /// Types that are captured (see `GeneratorInterior` for more). + interior: Ty<'tcx>, + + /// Indicates if the generator is movable or static (immovable). + movability: hir::Movability, +} + +/// Given a `DefId` for an opaque type in return position, find its parent item's return +/// expressions. +fn get_owner_return_paths( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let id = tcx.hir().get_parent_item(hir_id); + tcx.hir() + .find(id) + .map(|n| (id, n)) + .and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b))) + .map(|(hir_id, body_id)| { + let body = tcx.hir().body(body_id); + let mut visitor = ReturnsVisitor::default(); + visitor.visit_body(body); + (hir_id, visitor) + }) +} + +/// Emit an error for recursive opaque types in a `let` binding. +fn binding_opaque_type_cycle_error( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + span: Span, + partially_expanded_type: Ty<'tcx>, +) { + let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); + err.span_label(span, "cannot resolve opaque type"); + // Find the owner that declared this `impl Trait` type. + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let mut prev_hir_id = hir_id; + let mut hir_id = tcx.hir().get_parent_node(hir_id); + while let Some(node) = tcx.hir().find(hir_id) { + match node { + hir::Node::Local(hir::Local { + pat, + init: None, + ty: Some(ty), + source: hir::LocalSource::Normal, + .. + }) => { + err.span_label(pat.span, "this binding might not have a concrete type"); + err.span_suggestion_verbose( + ty.span.shrink_to_hi(), + "set the binding to a value for a concrete type to be resolved", + " = /* value */".to_string(), + Applicability::HasPlaceholders, + ); + } + hir::Node::Local(hir::Local { + init: Some(expr), + source: hir::LocalSource::Normal, + .. + }) => { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let typeck_results = + tcx.typeck(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id))); + if let Some(ty) = typeck_results.node_type_opt(expr.hir_id) { + err.span_label( + expr.span, + &format!( + "this is of type `{}`, which doesn't constrain \ + `{}` enough to arrive to a concrete type", + ty, partially_expanded_type + ), + ); + } + } + _ => {} + } + if prev_hir_id == hir_id { + break; + } + prev_hir_id = hir_id; + hir_id = tcx.hir().get_parent_node(hir_id); + } + err.emit(); +} + +// Forbid defining intrinsics in Rust code, +// as they must always be defined by the compiler. +fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { + if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi { + tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block"); + } +} + +fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) { + // Only restricted on wasm32 target for now + if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") { + return; + } + + // If `#[link_section]` is missing, then nothing to verify + let attrs = tcx.codegen_fn_attrs(id); + if attrs.link_section.is_none() { + return; + } + + // 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. + // `#[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. + match tcx.eval_static_initializer(id.to_def_id()) { + Ok(alloc) => { + if alloc.relocations().len() != 0 { + let msg = "statics with a custom `#[link_section]` must be a \ + simple list of bytes on the wasm target with no \ + extra levels of indirection such as references"; + tcx.sess.span_err(span, msg); + } + } + Err(_) => {} + } +} + +fn report_forbidden_specialization( + tcx: TyCtxt<'_>, + impl_item: &hir::ImplItem<'_>, + parent_impl: DefId, +) { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0520, + "`{}` specializes an item from a parent `impl`, but \ + that item is not marked `default`", + impl_item.ident + ); + err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident)); + + match tcx.span_of_impl(parent_impl) { + Ok(span) => { + err.span_label(span, "parent `impl` is here"); + err.note(&format!( + "to specialize, `{}` in the parent `impl` must be marked `default`", + impl_item.ident + )); + } + Err(cname) => { + err.note(&format!("parent implementation is in crate `{}`", cname)); + } + } + + err.emit(); +} + +fn missing_items_err( + tcx: TyCtxt<'_>, + impl_span: Span, + missing_items: &[ty::AssocItem], + full_impl_span: Span, +) { + let missing_items_msg = missing_items + .iter() + .map(|trait_item| trait_item.ident.to_string()) + .collect::>() + .join("`, `"); + + let mut err = struct_span_err!( + tcx.sess, + impl_span, + E0046, + "not all trait items implemented, missing: `{}`", + missing_items_msg + ); + err.span_label(impl_span, format!("missing `{}` in implementation", missing_items_msg)); + + // `Span` before impl block closing brace. + let hi = full_impl_span.hi() - BytePos(1); + // Point at the place right before the closing brace of the relevant `impl` to suggest + // adding the associated item at the end of its body. + let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi); + // Obtain the level of indentation ending in `sugg_sp`. + let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0); + // Make the whitespace that will make the suggestion have the right indentation. + let padding: String = (0..indentation).map(|_| " ").collect(); + + for trait_item in missing_items { + let snippet = suggestion_signature(&trait_item, tcx); + let code = format!("{}{}\n{}", padding, snippet, padding); + let msg = format!("implement the missing item: `{}`", snippet); + let appl = Applicability::HasPlaceholders; + if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { + err.span_label(span, format!("`{}` from trait", trait_item.ident)); + err.tool_only_span_suggestion(sugg_sp, &msg, code, appl); + } else { + err.span_suggestion_hidden(sugg_sp, &msg, code, appl); + } + } + err.emit(); +} + +/// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. +fn bounds_from_generic_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: ty::GenericPredicates<'tcx>, +) -> (String, String) { + let mut types: FxHashMap, Vec> = FxHashMap::default(); + let mut projections = vec![]; + for (predicate, _) in predicates.predicates { + debug!("predicate {:?}", predicate); + match predicate.skip_binders() { + ty::PredicateAtom::Trait(trait_predicate, _) => { + let entry = types.entry(trait_predicate.self_ty()).or_default(); + let def_id = trait_predicate.def_id(); + if Some(def_id) != tcx.lang_items().sized_trait() { + // Type params are `Sized` by default, do not add that restriction to the list + // if it is a positive requirement. + entry.push(trait_predicate.def_id()); + } + } + ty::PredicateAtom::Projection(projection_pred) => { + projections.push(ty::Binder::bind(projection_pred)); + } + _ => {} + } + } + let generics = if types.is_empty() { + "".to_string() + } else { + format!( + "<{}>", + types + .keys() + .filter_map(|t| match t.kind() { + ty::Param(_) => Some(t.to_string()), + // Avoid suggesting the following: + // fn foo::Bar>(_: T) where T: Trait, ::Bar: Other {} + _ => None, + }) + .collect::>() + .join(", ") + ) + }; + let mut where_clauses = vec![]; + for (ty, bounds) in types { + for bound in &bounds { + where_clauses.push(format!("{}: {}", ty, tcx.def_path_str(*bound))); + } + } + for projection in &projections { + let p = projection.skip_binder(); + // FIXME: this is not currently supported syntax, we should be looking at the `types` and + // insert the associated types where they correspond, but for now let's be "lazy" and + // propose this instead of the following valid resugaring: + // `T: Trait, Trait::Assoc = K` → `T: Trait` + where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty)); + } + let where_clauses = if where_clauses.is_empty() { + String::new() + } else { + format!(" where {}", where_clauses.join(", ")) + }; + (generics, where_clauses) +} + +/// Return placeholder code for the given function. +fn fn_sig_suggestion<'tcx>( + tcx: TyCtxt<'tcx>, + sig: ty::FnSig<'tcx>, + ident: Ident, + predicates: ty::GenericPredicates<'tcx>, + assoc: &ty::AssocItem, +) -> String { + let args = sig + .inputs() + .iter() + .enumerate() + .map(|(i, ty)| { + Some(match ty.kind() { + ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(), + ty::Ref(reg, ref_ty, mutability) if i == 0 => { + let reg = match &format!("{}", reg)[..] { + "'_" | "" => String::new(), + reg => format!("{} ", reg), + }; + if assoc.fn_has_self_parameter { + match ref_ty.kind() { + ty::Param(param) if param.name == kw::SelfUpper => { + format!("&{}{}self", reg, mutability.prefix_str()) + } + + _ => format!("self: {}", ty), + } + } else { + format!("_: {}", ty) + } + } + _ => { + if assoc.fn_has_self_parameter && i == 0 { + format!("self: {}", ty) + } else { + format!("_: {}", ty) + } + } + }) + }) + .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None })) + .filter_map(|arg| arg) + .collect::>() + .join(", "); + let output = sig.output(); + let output = if !output.is_unit() { format!(" -> {}", output) } else { String::new() }; + + let unsafety = sig.unsafety.prefix_str(); + let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); + + // FIXME: this is not entirely correct, as the lifetimes from borrowed params will + // not be present in the `fn` definition, not will we account for renamed + // lifetimes between the `impl` and the `trait`, but this should be good enough to + // fill in a significant portion of the missing code, and other subsequent + // suggestions can help the user fix the code. + format!( + "{}fn {}{}({}){}{} {{ todo!() }}", + unsafety, ident, generics, args, output, where_clauses + ) +} + +/// Return placeholder code for the given associated item. +/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a +/// structured suggestion. +fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { + match assoc.kind { + ty::AssocKind::Fn => { + // We skip the binder here because the binder would deanonymize all + // late-bound regions, and we don't want method signatures to show up + // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound + // regions just fine, showing `fn(&MyType)`. + fn_sig_suggestion( + tcx, + tcx.fn_sig(assoc.def_id).skip_binder(), + assoc.ident, + tcx.predicates_of(assoc.def_id), + assoc, + ) + } + ty::AssocKind::Type => format!("type {} = Type;", assoc.ident), + ty::AssocKind::Const => { + let ty = tcx.type_of(assoc.def_id); + let val = expr::ty_kind_suggestion(ty).unwrap_or("value"); + format!("const {}: {} = {};", assoc.ident, ty, val) + } + } +} + +/// Emit an error when encountering more or less than one variant in a transparent enum. +fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) { + let variant_spans: Vec<_> = adt + .variants + .iter() + .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap()) + .collect(); + let msg = format!("needs exactly one variant, but has {}", adt.variants.len(),); + let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg); + err.span_label(sp, &msg); + if let [start @ .., end] = &*variant_spans { + for variant_span in start { + err.span_label(*variant_span, ""); + } + err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did))); + } + err.emit(); +} + +/// Emit an error when encountering more or less than one non-zero-sized field in a transparent +/// enum. +fn bad_non_zero_sized_fields<'tcx>( + tcx: TyCtxt<'tcx>, + adt: &'tcx ty::AdtDef, + field_count: usize, + field_spans: impl Iterator, + sp: Span, +) { + let msg = format!("needs exactly one non-zero-sized field, but has {}", field_count); + let mut err = struct_span_err!( + tcx.sess, + sp, + E0690, + "{}transparent {} {}", + if adt.is_enum() { "the variant of a " } else { "" }, + adt.descr(), + msg, + ); + err.span_label(sp, &msg); + for sp in field_spans { + err.span_label(sp, "this field is non-zero-sized"); + } + err.emit(); +} + +fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) { + struct_span_err!( + tcx.sess, + span, + E0533, + "expected unit struct, unit variant or constant, found {}{}", + res.descr(), + tcx.sess.source_map().span_to_snippet(span).map_or(String::new(), |s| format!(" `{}`", s)), + ) + .emit(); +} + +/// Controls whether the arguments are tupled. This is used for the call +/// operator. +/// +/// Tupling means that all call-side arguments are packed into a tuple and +/// passed as a single parameter. For example, if tupling is enabled, this +/// function: +/// +/// fn f(x: (isize, isize)) +/// +/// Can be called as: +/// +/// f(1, 2); +/// +/// Instead of: +/// +/// f((1, 2)); +#[derive(Clone, Eq, PartialEq)] +enum TupleArgumentsFlag { + DontTupleArguments, + TupleArguments, +} + +/// Controls how we perform fallback for unconstrained +/// type variables. +enum FallbackMode { + /// Do not fallback type variables to opaque types. + NoOpaque, + /// Perform all possible kinds of fallback, including + /// turning type variables to opaque types. + All, +} + +/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. +#[derive(Copy, Clone)] +struct MaybeInProgressTables<'a, 'tcx> { + maybe_typeck_results: Option<&'a RefCell>>, +} + +impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { + fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" + ), + } + } + + fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow_mut(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" + ), + } + } +} + +struct CheckItemTypesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { + fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { + check_item_type(self.tcx, i); + } + fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} + fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} +} + +fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { + debug_assert!(crate_num == LOCAL_CRATE); + tcx.par_body_owners(|body_owner_def_id| { + tcx.ensure().typeck(body_owner_def_id); + }); +} + +fn fatally_break_rust(sess: &Session) { + let handler = sess.diagnostic(); + handler.span_bug_no_panic( + MultiSpan::new(), + "It looks like you're trying to break rust; would you like some ICE?", + ); + handler.note_without_error("the compiler expectedly panicked. this is a feature."); + handler.note_without_error( + "we would appreciate a joke overview: \ + https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", + ); + handler.note_without_error(&format!( + "rustc {} running on {}", + option_env!("CFG_VERSION").unwrap_or("unknown_version"), + config::host_triple(), + )); +} + +fn potentially_plural_count(count: usize, word: &str) -> String { + format!("{} {}{}", count, word, pluralize!(count)) +} diff --git a/src/librustc_typeck/check/op.rs b/compiler/rustc_typeck/src/check/op.rs similarity index 97% rename from src/librustc_typeck/check/op.rs rename to compiler/rustc_typeck/src/check/op.rs index 66fb01a54f..66975f32a1 100644 --- a/src/librustc_typeck/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -206,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(method) => { let by_ref_binop = !op.node.is_by_value(); if is_assign == IsAssign::Yes || by_ref_binop { - if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind { + if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() { let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, hir::Mutability::Mut => AutoBorrowMutability::Mut { @@ -223,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if by_ref_binop { - if let ty::Ref(region, _, mutbl) = method.sig.inputs()[1].kind { + if let ty::Ref(region, _, mutbl) = method.sig.inputs()[1].kind() { let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, hir::Mutability::Mut => AutoBorrowMutability::Mut { @@ -395,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; let mut suggested_deref = false; - if let Ref(_, rty, _) = lhs_ty.kind { + if let Ref(_, rty, _) = lhs_ty.kind() { if { self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span) && self @@ -436,7 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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[..] { - if let ty::Param(p) = ty.kind { + if let ty::Param(p) = *ty.kind() { // Check if the method would be found if the type param wasn't // involved. If so, it means that adding a trait bound to the param is // enough. Otherwise we do not give the suggestion. @@ -468,7 +468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } } else { - bug!("type param visitor stored a non type param: {:?}", ty.kind); + bug!("type param visitor stored a non type param: {:?}", ty.kind()); } } else if !suggested_deref && !involves_fn { suggest_impl_missing(&mut err, lhs_ty, &missing_trait); @@ -494,7 +494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_assign: IsAssign, ) -> bool /* did we suggest to call a function because of missing parenthesis? */ { err.span_label(span, ty.to_string()); - if let FnDef(def_id, _) = ty.kind { + if let FnDef(def_id, _) = *ty.kind() { let source_map = self.tcx.sess.source_map(); if !self.tcx.has_typeck_results(def_id) { return false; @@ -502,7 +502,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We're emitting a suggestion, so we can just ignore regions let fn_sig = self.tcx.fn_sig(def_id).skip_binder(); - let other_ty = if let FnDef(def_id, _) = other_ty.kind { + let other_ty = if let FnDef(def_id, _) = *other_ty.kind() { if !self.tcx.has_typeck_results(def_id) { return false; } @@ -568,10 +568,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => false, }; - match (&lhs_ty.kind, &rhs_ty.kind) { + match (lhs_ty.kind(), rhs_ty.kind()) { (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str - if (l_ty.kind == Str || is_std_string(l_ty)) && ( - r_ty.kind == Str || is_std_string(r_ty) || + if (*l_ty.kind() == Str || is_std_string(l_ty)) && ( + *r_ty.kind() == Str || is_std_string(r_ty) || &format!("{:?}", rhs_ty) == "&&str" ) => { @@ -589,10 +589,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { msg }, - if lstring.starts_with('&') { + if let Some(stripped) = lstring.strip_prefix('&') { // let a = String::new(); // let _ = &a + "bar"; - lstring[1..].to_string() + stripped.to_string() } else { format!("{}.to_owned()", lstring) }, @@ -605,7 +605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } (&Ref(_, l_ty, _), &Adt(..)) // Handle `&str` & `&String` + `String` - if (l_ty.kind == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => + if (*l_ty.kind() == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => { err.span_label( op.span, @@ -617,10 +617,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_assign, ) { (Ok(l), Ok(r), IsAssign::No) => { - let to_string = if l.starts_with('&') { + let to_string = if let Some(stripped) = l.strip_prefix('&') { // let a = String::new(); let b = String::new(); // let _ = &a + b; - l[1..].to_string() + stripped.to_string() } else { format!("{}.to_owned()", l) }; @@ -670,12 +670,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ex.span, format!("cannot apply unary operator `{}`", op.as_str()), ); - match actual.kind { + match actual.kind() { Uint(_) if op == hir::UnOp::UnNeg => { err.note("unsigned values cannot be negated"); } Str | Never | Char | Tuple(_) | Array(_, _) => {} - Ref(_, ref lty, _) if lty.kind == Str => {} + Ref(_, ref lty, _) if *lty.kind() == Str => {} _ => { let missing_trait = match op { hir::UnOp::UnNeg => "std::ops::Neg", @@ -844,7 +844,7 @@ enum Op { /// Dereferences a single level of immutable referencing. fn deref_ty_if_possible(ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match ty.kind() { ty::Ref(_, ty, hir::Mutability::Not) => ty, _ => ty, } @@ -903,7 +903,7 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool /// If applicable, note that an implementation of `trait` for `ty` may fix the error. fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_trait: &str) { - if let Adt(def, _) = ty.peel_refs().kind { + if let Adt(def, _) = ty.peel_refs().kind() { if def.did.is_local() { err.note(&format!( "an implementation of `{}` might be missing for `{}`", @@ -957,7 +957,7 @@ struct TypeParamVisitor<'tcx>(Vec>); impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - if let ty::Param(_) = ty.kind { + if let ty::Param(_) = ty.kind() { self.0.push(ty); } ty.super_visit_with(self) @@ -972,7 +972,7 @@ impl TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match ty.kind() { ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: self.1, diff --git a/src/librustc_typeck/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs similarity index 86% rename from src/librustc_typeck/check/pat.rs rename to compiler/rustc_typeck/src/check/pat.rs index dc1ce2d89b..3e431a9c00 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1,5 +1,6 @@ use crate::check::FnCtxt; use rustc_ast as ast; + use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; @@ -10,7 +11,7 @@ use rustc_hir::{HirId, Pat, PatKind}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, BindingMode, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Ident; @@ -281,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. - PatKind::Lit(lt) => match self.check_expr(lt).kind { + PatKind::Lit(lt) => match self.check_expr(lt).kind() { ty::Ref(..) => AdjustMode::Pass, _ => AdjustMode::Peel, }, @@ -341,7 +342,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // See the examples in `ui/match-defbm*.rs`. let mut pat_adjustments = vec![]; - while let ty::Ref(_, inner_ty, inner_mutability) = expected.kind { + while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() { debug!("inspecting {:?}", expected); debug!("current discriminant is Ref, inserting implicit deref"); @@ -389,9 +390,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut pat_ty = ty; if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(_), .. }) = lt.kind { let expected = self.structurally_resolved_type(span, expected); - if let ty::Ref(_, ty::TyS { kind: ty::Slice(_), .. }, _) = expected.kind { - let tcx = self.tcx; - pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); + if let ty::Ref(_, inner_ty, _) = expected.kind() { + if matches!(inner_ty.kind(), ty::Slice(_)) { + let tcx = self.tcx; + pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); + } } } @@ -492,7 +495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.sess, span, E0029, - "only char and numeric types are allowed in range patterns" + "only `char` and numeric types are allowed in range patterns" ); let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty); let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| { @@ -639,7 +642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_dereferenceable(&self, span: Span, expected: Ty<'tcx>, inner: &Pat<'_>) -> bool { if let PatKind::Binding(..) = inner.kind { if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { - if let ty::Dynamic(..) = mt.ty.kind { + if let ty::Dynamic(..) = mt.ty.kind() { // This is "x = SomeTrait" being reduced from // "let &x = &SomeTrait" or "let box x = Box", an error. let type_str = self.ty_to_string(expected); @@ -733,17 +736,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(err) = self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) { - self.emit_bad_pat_path(err, pat.span, res, pat_res, segments, ti.parent_pat); + self.emit_bad_pat_path(err, pat.span, res, pat_res, pat_ty, segments, ti.parent_pat); } pat_ty } + fn maybe_suggest_range_literal( + &self, + e: &mut DiagnosticBuilder<'_>, + opt_def_id: Option, + ident: Ident, + ) -> bool { + match opt_def_id { + Some(def_id) => match self.tcx.hir().get_if_local(def_id) { + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(_, body_id), .. + })) => match self.tcx.hir().get(body_id.hir_id) { + hir::Node::Expr(expr) => { + if hir::is_range_literal(expr) { + let span = self.tcx.hir().span(body_id.hir_id); + if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) { + e.span_suggestion_verbose( + ident.span, + "you may want to move the range into the match block", + snip, + Applicability::MachineApplicable, + ); + return true; + } + } + } + _ => (), + }, + _ => (), + }, + _ => (), + } + false + } + fn emit_bad_pat_path( &self, mut e: DiagnosticBuilder<'_>, pat_span: Span, res: Res, pat_res: Res, + pat_ty: Ty<'tcx>, segments: &'b [hir::PathSegment<'b>], parent_pat: Option<&Pat<'_>>, ) { @@ -769,9 +807,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } _ => { - let msg = "introduce a new binding instead"; - let sugg = format!("other_{}", ident.as_str().to_lowercase()); - e.span_suggestion(ident.span, msg, sugg, Applicability::HasPlaceholders); + let (type_def_id, item_def_id) = match pat_ty.kind() { + Adt(def, _) => match res { + Res::Def(DefKind::Const, def_id) => (Some(def.did), Some(def_id)), + _ => (None, None), + }, + _ => (None, None), + }; + + let ranges = &[ + self.tcx.lang_items().range_struct(), + self.tcx.lang_items().range_from_struct(), + self.tcx.lang_items().range_to_struct(), + self.tcx.lang_items().range_full_struct(), + self.tcx.lang_items().range_inclusive_struct(), + self.tcx.lang_items().range_to_inclusive_struct(), + ]; + if type_def_id != None && ranges.contains(&type_def_id) { + if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { + let msg = "constants only support matching by type, \ + if you meant to match against a range of values, \ + consider using a range pattern like `min ..= max` in the match block"; + e.note(msg); + } + } else { + let msg = "introduce a new binding instead"; + let sugg = format!("other_{}", ident.as_str().to_lowercase()); + e.span_suggestion( + ident.span, + msg, + sugg, + Applicability::HasPlaceholders, + ); + } } }; } @@ -871,7 +939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { - let substs = match pat_ty.kind { + let substs = match pat_ty.kind() { ty::Adt(_, substs) => substs, _ => bug!("unexpected pattern type {:?}", pat_ty), }; @@ -924,13 +992,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // More generally, the expected type wants a tuple variant with one field of an // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. - let missing_parenthesis = match (&expected.kind, fields, had_err) { + let missing_parenthesis = match (&expected.kind(), fields, had_err) { // #67037: only do this if we could successfully type-check the expected type against // the tuple struct pattern. Otherwise the substs could get out of range on e.g., // `let P() = U;` where `P != U` with `struct P(T);`. (ty::Adt(_, substs), [field], false) => { let field_ty = self.field_ty(pat_span, field, substs); - match field_ty.kind { + match field_ty.kind() { ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(), _ => false, } @@ -981,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut expected_len = elements.len(); if ddpos.is_some() { // Require known type only when `..` is present. - if let ty::Tuple(ref tys) = self.structurally_resolved_type(span, expected).kind { + if let ty::Tuple(ref tys) = self.structurally_resolved_type(span, expected).kind() { expected_len = tys.len(); } } @@ -1025,7 +1093,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool { let tcx = self.tcx; - let (substs, adt) = match adt_ty.kind { + let (substs, adt) = match adt_ty.kind() { ty::Adt(adt, substs) => (substs, adt), _ => span_bug!(pat.span, "struct pattern is not an ADT"), }; @@ -1076,11 +1144,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut unmentioned_fields = variant .fields .iter() - .map(|field| field.ident.normalize_to_macros_2_0()) - .filter(|ident| !used_fields.contains_key(&ident)) + .map(|field| (field, field.ident.normalize_to_macros_2_0())) + .filter(|(_, ident)| !used_fields.contains_key(&ident)) .collect::>(); - let inexistent_fields_err = if !inexistent_fields.is_empty() && !variant.recovered { + let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) { Some(self.error_inexistent_fields( adt.variant_descr(), &inexistent_fields, @@ -1108,7 +1176,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !etc && !unmentioned_fields.is_empty() { - unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields)); + let no_accessible_unmentioned_fields = unmentioned_fields + .iter() + .find(|(field, _)| { + field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) + }) + .is_none(); + + if no_accessible_unmentioned_fields { + unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields)); + } else { + unmentioned_err = + Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields)); + } } match (inexistent_fields_err, unmentioned_err) { (Some(mut i), Some(mut u)) => { @@ -1171,7 +1251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, kind_name: &str, inexistent_fields: &[Ident], - unmentioned_fields: &mut Vec, + unmentioned_fields: &mut Vec<(&ty::FieldDef, Ident)>, variant: &ty::VariantDef, ) -> DiagnosticBuilder<'tcx> { let tcx = self.tcx; @@ -1213,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); if plural == "" { - let input = unmentioned_fields.iter().map(|field| &field.name); + let input = unmentioned_fields.iter().map(|(_, field)| &field.name); let suggested_name = find_best_match_for_name(input, ident.name, None); if let Some(suggested_name) = suggested_name { err.span_suggestion( @@ -1230,7 +1310,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `smart_resolve_context_dependent_help`. if suggested_name.to_ident_string().parse::().is_err() { // We don't want to throw `E0027` in case we have thrown `E0026` for them. - unmentioned_fields.retain(|&x| x.name != suggested_name); + unmentioned_fields.retain(|&(_, x)| x.name != suggested_name); } } } @@ -1298,17 +1378,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } + /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to + /// inaccessible fields. + /// + /// ```ignore (diagnostic) + /// error: pattern requires `..` due to inaccessible fields + /// --> src/main.rs:10:9 + /// | + /// LL | let foo::Foo {} = foo::Foo::default(); + /// | ^^^^^^^^^^^ + /// | + /// help: add a `..` + /// | + /// LL | let foo::Foo { .. } = foo::Foo::default(); + /// | ^^^^^^ + /// ``` + fn error_no_accessible_fields( + &self, + pat: &Pat<'_>, + fields: &'tcx [hir::FieldPat<'tcx>], + ) -> DiagnosticBuilder<'tcx> { + let mut err = self + .tcx + .sess + .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields"); + + if let Some(field) = fields.last() { + err.span_suggestion_verbose( + field.span.shrink_to_hi(), + "ignore the inaccessible and unused fields", + ", ..".to_string(), + Applicability::MachineApplicable, + ); + } else { + let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind { + qpath.span() + } else { + bug!("`error_no_accessible_fields` called on non-struct pattern"); + }; + + // Shrink the span to exclude the `foo:Foo` in `foo::Foo { }`. + let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi()); + err.span_suggestion_verbose( + span, + "ignore the inaccessible and unused fields", + " { .. }".to_string(), + Applicability::MachineApplicable, + ); + } + err + } + + /// Returns a diagnostic reporting a struct pattern which does not mention some fields. + /// + /// ```ignore (diagnostic) + /// error[E0027]: pattern does not mention field `you_cant_use_this_field` + /// --> src/main.rs:15:9 + /// | + /// LL | let foo::Foo {} = foo::Foo::new(); + /// | ^^^^^^^^^^^ missing field `you_cant_use_this_field` + /// ``` fn error_unmentioned_fields( &self, pat: &Pat<'_>, - unmentioned_fields: &[Ident], + unmentioned_fields: &[(&ty::FieldDef, Ident)], + fields: &'tcx [hir::FieldPat<'tcx>], ) -> DiagnosticBuilder<'tcx> { let field_names = if unmentioned_fields.len() == 1 { - format!("field `{}`", unmentioned_fields[0]) + format!("field `{}`", unmentioned_fields[0].1) } else { let fields = unmentioned_fields .iter() - .map(|name| format!("`{}`", name)) + .map(|(_, name)| format!("`{}`", name)) .collect::>() .join(", "); format!("fields {}", fields) @@ -1321,14 +1462,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_names ); err.span_label(pat.span, format!("missing {}", field_names)); - if self.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "This error indicates that a pattern for a struct fails to specify a \ - sub-pattern for every one of the struct's fields. Ensure that each field \ - from the struct's definition is mentioned in the pattern, or use `..` to \ - ignore unwanted fields.", - ); - } + let len = unmentioned_fields.len(); + let (prefix, postfix, sp) = match fields { + [] => match &pat.kind { + PatKind::Struct(path, [], false) => { + (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi())) + } + _ => return err, + }, + [.., field] => ( + match pat.kind { + PatKind::Struct(_, [_, ..], _) => ", ", + _ => "", + }, + "", + field.span.shrink_to_hi(), + ), + }; + err.span_suggestion( + sp, + &format!( + "include the missing field{} in the pattern", + if len == 1 { "" } else { "s" }, + ), + format!( + "{}{}{}", + prefix, + unmentioned_fields + .iter() + .map(|(_, name)| name.to_string()) + .collect::>() + .join(", "), + postfix, + ), + Applicability::MachineApplicable, + ); + err.span_suggestion( + sp, + &format!( + "if you don't care about {} missing field{}, you can explicitely ignore {}", + if len == 1 { "this" } else { "these" }, + if len == 1 { "" } else { "s" }, + if len == 1 { "it" } else { "them" }, + ), + format!("{}..{}", prefix, postfix), + Applicability::MachineApplicable, + ); err } @@ -1378,7 +1557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to avoid creating needless variables. This also helps with // the bad interactions of the given hack detailed in (note_1). debug!("check_pat_ref: expected={:?}", expected); - match expected.kind { + match *expected.kind() { ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty), _ => { let inner_ty = self.next_ty_var(TypeVariableOrigin { @@ -1434,7 +1613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let expected = self.structurally_resolved_type(span, expected); - let (element_ty, opt_slice_ty, inferred) = match expected.kind { + let (element_ty, opt_slice_ty, inferred) = match *expected.kind() { // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`. ty::Array(element_ty, len) => { let min = before.len() as u64 + after.len() as u64; @@ -1570,8 +1749,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "expected an array or slice, found `{}`", expected_ty ); - if let ty::Ref(_, ty, _) = expected_ty.kind { - if let ty::Array(..) | ty::Slice(..) = ty.kind { + if let ty::Ref(_, ty, _) = expected_ty.kind() { + if let ty::Array(..) | ty::Slice(..) = ty.kind() { err.help("the semantics of slice patterns changed recently; see issue #62254"); } } diff --git a/src/librustc_typeck/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs similarity index 89% rename from src/librustc_typeck/check/place_op.rs rename to compiler/rustc_typeck/src/check/place_op.rs index 4bef9aecd2..502cb56238 100644 --- a/src/librustc_typeck/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?; let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind { + if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { self.apply_adjustments( oprnd_expr, vec![Adjustment { @@ -86,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut self_ty = adjusted_ty; if unsize { // We only unsize arrays here. - if let ty::Array(element_ty, _) = adjusted_ty.kind { + if let ty::Array(element_ty, _) = adjusted_ty.kind() { self_ty = self.tcx.mk_slice(element_ty); } else { continue; @@ -108,7 +108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let method = self.register_infer_ok_obligations(ok); let mut adjustments = self.adjust_steps(autoderef); - if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind { + if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { adjustments.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)), target: self.tcx.mk_ref( @@ -193,7 +193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index` /// into `DerefMut` and `IndexMut` respectively. /// - /// This is a second pass of typechecking derefs/indices. We need this we do not + /// This is a second pass of typechecking derefs/indices. We need this because we do not /// always know whether a place needs to be mutable or not in the first pass. /// This happens whether there is an implicit mutable reborrow, e.g. when the type /// is used as the receiver of a method call. @@ -211,13 +211,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs); // Fix up autoderefs and derefs. + let mut inside_union = false; for (i, &expr) in exprs.iter().rev().enumerate() { debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr); + let mut source = self.node_ty(expr.hir_id); + if matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnDeref, _)) { + // Clear previous flag; after a pointer indirection it does not apply any more. + inside_union = false; + } + if source.ty_adt_def().map_or(false, |adt| adt.is_union()) { + inside_union = true; + } // Fix up the autoderefs. Autorefs can only occur immediately preceding // overloaded place ops, and will be fixed by them in order to get // the correct region. - let mut source = self.node_ty(expr.hir_id); // Do not mutate adjustments in place, but rather take them, // and replace them after mutating them, to avoid having the // typeck results borrowed during (`deref_mut`) method resolution. @@ -233,8 +241,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceOp::Deref, ) { let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, mutbl) = method.sig.output().kind { - *deref = OverloadedDeref { region, mutbl }; + if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { + *deref = OverloadedDeref { region, mutbl, span: deref.span }; + } + // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). + // This helps avoid accidental drops. + if inside_union + && source.ty_adt_def().map_or(false, |adt| adt.is_manually_drop()) + { + let mut err = self.tcx.sess.struct_span_err( + expr.span, + "not automatically applying `DerefMut` on `ManuallyDrop` union field", + ); + err.help( + "writing to this reference calls the destructor for the old value", + ); + err.help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor"); + err.emit(); } } } @@ -305,7 +328,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("convert_place_op_to_mutable: method={:?}", method); self.write_method_call(expr.hir_id, method); - let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind { + let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() { r } else { span_bug!(expr.span, "input to mutable place op is not a mut ref?"); diff --git a/src/librustc_typeck/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs similarity index 99% rename from src/librustc_typeck/check/regionck.rs rename to compiler/rustc_typeck/src/check/regionck.rs index 221e5f72dc..ba0f22513a 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -624,7 +624,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { ); let rptr_ty = self.resolve_node_type(id); - if let ty::Ref(r, _, _) = rptr_ty.kind { + if let ty::Ref(r, _, _) = rptr_ty.kind() { debug!("rptr_ty={}", rptr_ty); self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } @@ -649,7 +649,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { "link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})", borrow_region, borrow_kind, borrow_place ); - match pointer_ty.kind { + match *pointer_ty.kind() { ty::RawPtr(_) => return, ty::Ref(ref_region, _, ref_mutability) => { if self.link_reborrowed_region(span, borrow_region, ref_region, ref_mutability) @@ -786,7 +786,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { return; } } - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue(_) => {} } let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id); let ty = self.resolve_node_type(fn_hir_id); @@ -794,7 +794,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { // A closure capture can't be borrowed for longer than the // reference to the closure. - if let ty::Closure(_, substs) = ty.kind { + if let ty::Closure(_, substs) = ty.kind() { match self.infcx.closure_kind(substs) { Some(ty::ClosureKind::Fn | ty::ClosureKind::FnMut) => { // Region of environment pointer diff --git a/src/librustc_typeck/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs similarity index 92% rename from src/librustc_typeck/check/upvar.rs rename to compiler/rustc_typeck/src/check/upvar.rs index 030c0ab668..2c3be0da5d 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -42,6 +42,7 @@ use rustc_infer::infer::UpvarRegion; use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId}; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts}; use rustc_span::{Span, Symbol}; +use std::collections::hash_map::Entry; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) { @@ -87,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); - let (closure_def_id, substs) = match ty.kind { + let (closure_def_id, substs) = match *ty.kind() { ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), ty::Error(_) => { @@ -124,7 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_captures.insert(var_hir_id, upvar_id); let capture_kind = match capture_clause { - hir::CaptureBy::Value => ty::UpvarCapture::ByValue, + hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None), hir::CaptureBy::Ref => { let origin = UpvarRegion(upvar_id, span); let upvar_region = self.next_region_var(origin); @@ -237,7 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("var_id={:?} upvar_ty={:?} capture={:?}", var_hir_id, upvar_ty, capture); match capture { - ty::UpvarCapture::ByValue => upvar_ty, + ty::UpvarCapture::ByValue(_) => upvar_ty, ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( borrow.region, ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() }, @@ -300,15 +301,43 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id); + let usage_span = tcx.hir().span(place_with_id.hir_id); + // To move out of an upvar, this must be a FnOnce closure self.adjust_closure_kind( upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, - tcx.hir().span(place_with_id.hir_id), + usage_span, var_name(tcx, upvar_id.var_path.hir_id), ); - self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); + // In a case like `let pat = upvar`, don't use the span + // of the pattern, as this just looks confusing. + let by_value_span = match tcx.hir().get(place_with_id.hir_id) { + hir::Node::Pat(_) => None, + _ => Some(usage_span), + }; + + let new_capture = ty::UpvarCapture::ByValue(by_value_span); + match self.adjust_upvar_captures.entry(upvar_id) { + Entry::Occupied(mut e) => { + match e.get() { + // We always overwrite `ByRef`, since we require + // that the upvar be available by value. + // + // If we had a previous by-value usage without a specific + // span, use ours instead. Otherwise, keep the first span + // we encountered, since there isn't an obviously better one. + ty::UpvarCapture::ByRef(_) | ty::UpvarCapture::ByValue(None) => { + e.insert(new_capture); + } + _ => {} + } + } + Entry::Vacant(e) => { + e.insert(new_capture); + } + } } /// Indicates that `place_with_id` is being directly mutated (e.g., assigned @@ -320,7 +349,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { let mut borrow_kind = ty::MutBorrow; for pointer_ty in place_with_id.place.deref_tys() { - match pointer_ty.kind { + match pointer_ty.kind() { // Raw pointers don't inherit mutability. ty::RawPtr(_) => return, // assignment to deref of an `&mut` @@ -404,7 +433,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { ); match upvar_capture { - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue(_) => { // Upvar is already by-value, the strongest criteria. } ty::UpvarCapture::ByRef(mut upvar_borrow) => { diff --git a/src/librustc_typeck/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs similarity index 99% rename from src/librustc_typeck/check/wfcheck.rs rename to compiler/rustc_typeck/src/check/wfcheck.rs index 9c692edaa7..5203f3fa8f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -291,7 +291,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { let err_ty_str; let mut is_ptr = true; let err = if tcx.features().min_const_generics { - match ty.kind { + match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None, ty::FnPtr(_) => Some("function pointers"), ty::RawPtr(_) => Some("raw pointers"), @@ -302,7 +302,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { } } } else { - match ty.peel_refs().kind { + match ty.peel_refs().kind() { ty::FnPtr(_) => Some("function pointers"), ty::RawPtr(_) => Some("raw pointers"), _ => None, @@ -338,7 +338,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { // We use the same error code in both branches, because this is really the same // issue: we just special-case the message for type parameters to make it // clearer. - if let ty::Param(_) = ty.peel_refs().kind { + if let ty::Param(_) = ty.peel_refs().kind() { // Const parameters may not have type parameters as their types, // because we cannot be sure that the type parameter derives `PartialEq` // and `Eq` (just implementing them is not enough for `structural_match`). @@ -638,7 +638,7 @@ fn check_associated_type_defaults(fcx: &FnCtxt<'_, '_>, trait_def_id: DefId) { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match t.kind() { ty::Projection(proj_ty) => { if let Some(default) = self.map.get(&proj_ty) { default @@ -709,7 +709,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo let mut forbid_unsized = true; if allow_foreign_ty { let tail = fcx.tcx.struct_tail_erasing_lifetimes(item_ty, fcx.param_env); - if let ty::Foreign(_) = tail.kind { + if let ty::Foreign(_) = tail.kind() { forbid_unsized = false; } } @@ -867,7 +867,7 @@ fn check_where_clauses<'tcx, 'fcx>( } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - if let ty::Param(param) = t.kind { + if let ty::Param(param) = t.kind() { self.params.insert(param.index); } t.super_visit_with(self) @@ -1001,7 +1001,7 @@ fn check_opaque_types<'fcx, 'tcx>( ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: fcx.tcx, ty_op: |ty| { - if let ty::Opaque(def_id, substs) = ty.kind { + if let ty::Opaque(def_id, substs) = *ty.kind() { trace!("check_opaque_types: opaque_ty, {:?}, {:?}", def_id, substs); let generics = tcx.generics_of(def_id); @@ -1044,7 +1044,7 @@ fn check_opaque_types<'fcx, 'tcx>( let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); for (i, arg) in substs.iter().enumerate() { let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)), + GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Lifetime(region) => { if let ty::ReStatic = region { @@ -1177,7 +1177,7 @@ fn e0307(fcx: &FnCtxt<'fcx, 'tcx>, span: Span, receiver_ty: Ty<'_>) { fcx.tcx.sess.diagnostic(), span, E0307, - "invalid `self` parameter type: {:?}", + "invalid `self` parameter type: {}", receiver_ty, ) .note("type of `self` must be `Self` or a type that dereferences to it") diff --git a/src/librustc_typeck/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs similarity index 97% rename from src/librustc_typeck/check/writeback.rs rename to compiler/rustc_typeck/src/check/writeback.rs index 50e2d6a94b..5363702a5b 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -70,10 +70,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.typeck_results.used_trait_imports = used_trait_imports; - wbcx.typeck_results.closure_captures = mem::replace( - &mut self.typeck_results.borrow_mut().closure_captures, - Default::default(), - ); + wbcx.typeck_results.closure_captures = + mem::take(&mut self.typeck_results.borrow_mut().closure_captures); if self.is_tainted_by_errors() { // FIXME(eddyb) keep track of `ErrorReported` from where the error was emitted. @@ -193,7 +191,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let mut typeck_results = self.fcx.typeck_results.borrow_mut(); // All valid indexing looks like this; might encounter non-valid indexes at this point. - let base_ty = typeck_results.expr_ty_adjusted_opt(&base).map(|t| &t.kind); + let base_ty = typeck_results.expr_ty_adjusted_opt(&base).map(|t| t.kind()); if base_ty.is_none() { // When encountering `return [0][0]` outside of a `fn` body we can encounter a base // that isn't in the type table. We assume more relevant errors have already been @@ -331,7 +329,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_upvar_capture_map(&mut self) { for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() { let new_upvar_capture = match *upvar_capture { - ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, + ty::UpvarCapture::ByValue(span) => ty::UpvarCapture::ByValue(span), ty::UpvarCapture::ByRef(ref upvar_borrow) => { ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: upvar_borrow.kind, @@ -459,7 +457,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let mut skip_add = false; - if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.kind { + if let ty::Opaque(defin_ty_def_id, _substs) = *definition_ty.kind() { if let hir::OpaqueTyOrigin::Misc = opaque_defn.origin { if def_id == defin_ty_def_id { debug!( @@ -653,7 +651,12 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn report_type_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, E0282) + .emit_inference_failure_err( + Some(self.body.id()), + self.span.to_span(self.tcx), + t.into(), + E0282, + ) .emit(); } } @@ -661,10 +664,10 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info_err_const( + .emit_inference_failure_err( Some(self.body.id()), self.span.to_span(self.tcx), - c, + c.into(), E0282, ) .emit(); diff --git a/src/librustc_typeck/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs similarity index 100% rename from src/librustc_typeck/check_unused.rs rename to compiler/rustc_typeck/src/check_unused.rs diff --git a/src/librustc_typeck/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs similarity index 95% rename from src/librustc_typeck/coherence/builtin.rs rename to compiler/rustc_typeck/src/coherence/builtin.rs index 0d3cac7f7f..89270fb6c7 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -1,6 +1,7 @@ //! Check properties that are required by built-in traits and set //! up data structures required by type-checking/codegen. +use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -48,7 +49,7 @@ 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 { + if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind() { return; } @@ -58,14 +59,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { _ => bug!("expected Drop impl item"), }; - struct_span_err!( - tcx.sess, - sp, - E0120, - "the `Drop` trait may only be implemented for structs, enums, and unions", - ) - .span_label(sp, "must be a struct, enum, or union") - .emit(); + tcx.sess.emit_err(DropImplOnWrongItem { span: sp }); } fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { @@ -108,25 +102,10 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { let span = if let ItemKind::Impl { self_ty, .. } = item.kind { self_ty.span } else { span }; - struct_span_err!( - tcx.sess, - span, - E0206, - "the trait `Copy` may not be implemented for this type" - ) - .span_label(span, "type is not a structure or enumeration") - .emit(); + tcx.sess.emit_err(CopyImplOnNonAdt { span }); } Err(CopyImplementationError::HasDestructor) => { - struct_span_err!( - tcx.sess, - span, - E0184, - "the trait `Copy` may not be implemented for this type; the \ - type has a destructor" - ) - .span_label(span, "Copy not allowed on types with destructors") - .emit(); + tcx.sess.emit_err(CopyImplOnTypeWithDtor { span }); } } } @@ -168,7 +147,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef let cause = ObligationCause::misc(span, impl_hir_id); use ty::TyKind::*; - match (&source.kind, &target.kind) { + match (source.kind(), target.kind()) { (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) if infcx.at(&cause, param_env).eq(r_a, r_b).is_ok() && mutbl_a == *mutbl_b => {} (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (), @@ -352,7 +331,7 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI } (mt_a.ty, mt_b.ty, unsize_trait, None) }; - let (source, target, trait_def_id, kind) = match (&source.kind, &target.kind) { + let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) { (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs similarity index 93% rename from src/librustc_typeck/coherence/inherent_impls.rs rename to compiler/rustc_typeck/src/coherence/inherent_impls.rs index 859d510dcb..373acb95c9 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -52,7 +52,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { let def_id = self.tcx.hir().local_def_id(item.hir_id); let self_ty = self.tcx.type_of(def_id); let lang_items = self.tcx.lang_items(); - match self_ty.kind { + match *self_ty.kind() { ty::Adt(def, _) => { self.check_def_id(item, def.did); } @@ -123,7 +123,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { ); } ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not }) - if matches!(inner.kind, ty::Slice(_)) => + if matches!(inner.kind(), ty::Slice(_)) => { self.check_primitive_impl( def_id, @@ -135,7 +135,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { ); } ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut }) - if matches!(inner.kind, ty::Slice(_)) => + if matches!(inner.kind(), ty::Slice(_)) => { self.check_primitive_impl( def_id, @@ -308,18 +308,25 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { } ty::Error(_) => {} _ => { - struct_span_err!( + let mut err = struct_span_err!( self.tcx.sess, ty.span, E0118, - "no base type found for inherent implementation" - ) - .span_label(ty.span, "impl requires a base type") - .note( - "either implement a trait on it or create a newtype \ - to wrap it instead", - ) - .emit(); + "no nominal type found for inherent implementation" + ); + + err.span_label(ty.span, "impl requires a nominal type") + .note("either implement a trait on it or create a newtype to wrap it instead"); + + if let ty::Ref(_, subty, _) = self_ty.kind() { + err.note(&format!( + "you could also try moving the reference to \ + uses of `{}` (such as `self`) within the implementation", + subty + )); + } + + err.emit(); } } } diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs similarity index 100% rename from src/librustc_typeck/coherence/inherent_impls_overlap.rs rename to compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs diff --git a/src/librustc_typeck/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs similarity index 99% rename from src/librustc_typeck/coherence/mod.rs rename to compiler/rustc_typeck/src/coherence/mod.rs index 1483244717..4294450333 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/compiler/rustc_typeck/src/coherence/mod.rs @@ -209,7 +209,7 @@ fn check_object_overlap<'tcx>( } // check for overlap with the automatic `impl Trait for dyn Trait` - if let ty::Dynamic(ref data, ..) = trait_ref.self_ty().kind { + if let ty::Dynamic(ref data, ..) = trait_ref.self_ty().kind() { // This is something like impl Trait1 for Trait2. Illegal // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. diff --git a/src/librustc_typeck/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs similarity index 95% rename from src/librustc_typeck/coherence/orphan.rs rename to compiler/rustc_typeck/src/coherence/orphan.rs index 71469770f2..917fc5631c 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -52,7 +52,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { // Remove the lifetimes unnecessary for this error. ty = infcx.freshen(ty); }); - ty = match ty.kind { + ty = match ty.kind() { // Remove the type arguments from the output, as they are not relevant. // You can think of this as the reverse of `resolve_vars_if_possible`. // That way if we had `Vec`, we will properly attribute the @@ -62,7 +62,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { _ => ty, }; let this = "this".to_string(); - let (ty, postfix) = match &ty.kind { + let (ty, postfix) = match &ty.kind() { ty::Slice(_) => (this, " because slices are always foreign"), ty::Array(..) => (this, " because arrays are always foreign"), ty::Tuple(..) => (this, " because tuples are always foreign"), @@ -185,7 +185,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { ); if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() { let self_ty = trait_ref.self_ty(); - let opt_self_def_id = match self_ty.kind { + let opt_self_def_id = match *self_ty.kind() { ty::Adt(self_def, _) => Some(self_def.did), ty::Foreign(did) => Some(did), _ => None, @@ -230,6 +230,14 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { return; } } + + if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() { + self.tcx + .sess + .struct_span_err(sp, "cannot implement trait on type alias impl trait") + .span_note(self.tcx.def_span(def_id), "type alias impl trait defined here") + .emit(); + } } } diff --git a/src/librustc_typeck/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs similarity index 100% rename from src/librustc_typeck/coherence/unsafety.rs rename to compiler/rustc_typeck/src/coherence/unsafety.rs diff --git a/src/librustc_typeck/collect.rs b/compiler/rustc_typeck/src/collect.rs similarity index 94% rename from src/librustc_typeck/collect.rs rename to compiler/rustc_typeck/src/collect.rs index 1b472810cc..9aca112a91 100644 --- a/src/librustc_typeck/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -18,6 +18,7 @@ use crate::astconv::{AstConv, SizedByDefault}; use crate::bounds::Bounds; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::constrained_generic_params as cgp; +use crate::errors; use crate::middle::resolve_lifetime as rl; use rustc_ast as ast; use rustc_ast::MetaItemKind; @@ -70,6 +71,7 @@ pub fn provide(providers: &mut Providers) { generics_of, predicates_of, predicates_defined_on, + projection_ty_from_predicates, explicit_predicates_of, super_predicates_of, type_param_predicates, @@ -691,8 +693,14 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) { // Desugared from `impl Trait`, so visited by the function's return type. hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => {} - hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::TyAlias(..) + // Don't call `type_of` on opaque types, since that depends on type + // checking function bodies. `check_item_type` ensures that it's called + // instead. + hir::ItemKind::OpaqueTy(..) => { + tcx.ensure().generics_of(def_id); + tcx.ensure().predicates_of(def_id); + } + hir::ItemKind::TyAlias(..) | hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) => { @@ -833,16 +841,11 @@ fn convert_variant( let fid = tcx.hir().local_def_id(f.hir_id); let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned(); if let Some(prev_span) = dup_span { - struct_span_err!( - tcx.sess, - f.span, - E0124, - "field `{}` is already declared", - f.ident - ) - .span_label(f.span, "field already declared") - .span_label(prev_span, format!("`{}` first declared here", f.ident)) - .emit(); + tcx.sess.emit_err(errors::FieldAlreadyDeclared { + field_name: f.ident, + span: f.span, + prev_span, + }); } else { seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span); } @@ -1675,6 +1678,7 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate .alloc_from_iter(result.predicates.iter().chain(inferred_outlives).copied()); } } + debug!("predicates_defined_on({:?}) = {:?}", def_id, result); result } @@ -1716,29 +1720,6 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat debug!("explicit_predicates_of(def_id={:?})", def_id); - /// A data structure with unique elements, which preserves order of insertion. - /// Preserving the order of insertion is important here so as not to break - /// compile-fail UI tests. - struct UniquePredicates<'tcx> { - predicates: FxIndexSet<(ty::Predicate<'tcx>, Span)>, - } - - impl<'tcx> UniquePredicates<'tcx> { - fn new() -> Self { - UniquePredicates { predicates: FxIndexSet::default() } - } - - fn push(&mut self, value: (ty::Predicate<'tcx>, Span)) { - self.predicates.insert(value); - } - - fn extend, Span)>>(&mut self, iter: I) { - for value in iter { - self.push(value); - } - } - } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let node = tcx.hir().get(hir_id); @@ -1751,7 +1732,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty(); - let mut predicates = UniquePredicates::new(); + // We use an `IndexSet` to preserves order of insertion. + // Preserving the order of insertion is important here so as not to break + // compile-fail UI tests. + let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default(); let ast_generics = match node { Node::TraitItem(item) => { @@ -1853,7 +1837,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { - predicates.push(( + predicates.insert(( trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx), tcx.def_span(def_id), )); @@ -1877,7 +1861,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat hir::GenericBound::Outlives(lt) => { let bound = AstConv::ast_region_to_region(&icx, <, None); let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound)); - predicates.push((outlives.to_predicate(tcx), lt.span)); + predicates.insert((outlives.to_predicate(tcx), lt.span)); } _ => bug!(), }); @@ -1921,7 +1905,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` // is still checked for WF. if bound_pred.bounds.is_empty() { - if let ty::Param(_) = ty.kind { + if let ty::Param(_) = ty.kind() { // This is a `where T:`, which can be in the HIR from the // transformation that moves `?Sized` to `T`'s declaration. // We can skip the predicate because type parameters are @@ -1932,7 +1916,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let span = bound_pred.bounded_ty.span; let re_root_empty = tcx.lifetimes.re_root_empty; let predicate = ty::OutlivesPredicate(ty, re_root_empty); - predicates.push(( + predicates.insert(( ty::PredicateAtom::TypeOutlives(predicate) .potentially_quantified(tcx, ty::PredicateKind::ForAll), span, @@ -1976,11 +1960,11 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); - predicates.push(( + predicates.insert(( ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, region)) .potentially_quantified(tcx, ty::PredicateKind::ForAll), lifetime.span, - )) + )); } } } @@ -2025,7 +2009,11 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat })) } - let mut predicates: Vec<_> = predicates.predicates.into_iter().collect(); + if tcx.features().const_evaluatable_checked { + predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local())); + } + + let mut predicates: Vec<_> = predicates.into_iter().collect(); // Subtle: before we store the predicates into the tcx, we // sort them so that predicates like `T: Foo` come @@ -2051,6 +2039,119 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat result } +fn const_evaluatable_predicates_of<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> { + struct ConstCollector<'tcx> { + tcx: TyCtxt<'tcx>, + preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>, + } + + impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + let def_id = self.tcx.hir().local_def_id(c.hir_id); + let ct = ty::Const::from_anon_const(self.tcx, def_id); + if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { + let span = self.tcx.hir().span(c.hir_id); + self.preds.insert(( + ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), + span, + )); + } + } + + // Look into `TyAlias`. + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + use ty::fold::{TypeFoldable, TypeVisitor}; + struct TyAliasVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + preds: &'a mut FxIndexSet<(ty::Predicate<'tcx>, Span)>, + span: Span, + } + + impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> { + fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { + self.preds.insert(( + ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), + self.span, + )); + } + false + } + } + + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind { + if let Res::Def(DefKind::TyAlias, def_id) = path.res { + let mut visitor = + TyAliasVisitor { tcx: self.tcx, preds: &mut self.preds, span: path.span }; + self.tcx.type_of(def_id).visit_with(&mut visitor); + } + } + + intravisit::walk_ty(self, ty) + } + } + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let node = tcx.hir().get(hir_id); + + let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; + if let hir::Node::Item(item) = node { + if let hir::ItemKind::Impl { ref of_trait, ref self_ty, .. } = item.kind { + if let Some(of_trait) = of_trait { + warn!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); + collector.visit_trait_ref(of_trait); + } + + warn!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id); + collector.visit_ty(self_ty); + } + } + + if let Some(generics) = node.generics() { + warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id); + collector.visit_generics(generics); + } + + if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) { + warn!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id); + collector.visit_fn_decl(fn_sig.decl); + } + warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds); + + collector.preds +} + +fn projection_ty_from_predicates( + tcx: TyCtxt<'tcx>, + key: ( + // ty_def_id + DefId, + // def_id of `N` in `::N` + DefId, + ), +) -> Option> { + let (ty_def_id, item_def_id) = key; + let mut projection_ty = None; + for (predicate, _) in tcx.predicates_of(ty_def_id).predicates { + if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() { + if item_def_id == projection_predicate.projection_ty.item_def_id { + projection_ty = Some(projection_predicate.projection_ty); + break; + } + } + } + projection_ty +} + fn trait_associated_item_predicates( tcx: TyCtxt<'tcx>, def_id: DefId, @@ -2283,8 +2384,8 @@ fn from_target_feature( item.span(), format!("`{}` is not valid for this target", feature), ); - if feature.starts_with('+') { - let valid = supported_target_features.contains_key(&feature[1..]); + if let Some(stripped) = feature.strip_prefix('+') { + let valid = supported_target_features.contains_key(stripped); if valid { err.help("consider removing the leading `+` in the feature name"); } @@ -2303,7 +2404,6 @@ fn from_target_feature( Some(sym::mips_target_feature) => rust_features.mips_target_feature, Some(sym::riscv_target_feature) => rust_features.riscv_target_feature, Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, - Some(sym::mmx_target_feature) => rust_features.mmx_target_feature, Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, @@ -2443,6 +2543,21 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } else if tcx.sess.check_name(attr, sym::used) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; + } else if tcx.sess.check_name(attr, sym::cmse_nonsecure_entry) { + if tcx.fn_sig(id).abi() != abi::Abi::C { + struct_span_err!( + tcx.sess, + attr.span, + E0776, + "`#[cmse_nonsecure_entry]` requires C ABI" + ) + .emit(); + } + if !tcx.sess.target.target.llvm_target.contains("thumbv8m") { + struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY; } else if tcx.sess.check_name(attr, sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; } else if tcx.sess.check_name(attr, sym::track_caller) { @@ -2467,10 +2582,17 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(s); } } else if tcx.sess.check_name(attr, sym::target_feature) { - if !tcx.features().target_feature_11 { - check_target_feature_safe_fn(tcx, id, attr.span); - } else if let Some(local_id) = id.as_local() { - if tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { + if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { + if !tcx.features().target_feature_11 { + let mut err = feature_err( + &tcx.sess.parse_sess, + sym::target_feature_11, + attr.span, + "`#[target_feature(..)]` can only be applied to `unsafe` functions", + ); + err.span_label(tcx.def_span(id), "not an `unsafe` function"); + err.emit(); + } else if let Some(local_id) = id.as_local() { check_target_feature_trait_unsafe(tcx, local_id, attr.span); } } @@ -2727,21 +2849,6 @@ fn check_link_name_xor_ordinal( } } -/// Checks the function annotated with `#[target_feature]` is unsafe, -/// reporting an error if it isn't. -fn check_target_feature_safe_fn(tcx: TyCtxt<'_>, id: DefId, attr_span: Span) { - if tcx.is_closure(id) || tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { - let mut err = feature_err( - &tcx.sess.parse_sess, - sym::target_feature_11, - attr_span, - "`#[target_feature(..)]` can only be applied to `unsafe` functions", - ); - err.span_label(tcx.def_span(id), "not an `unsafe` function"); - err.emit(); - } -} - /// Checks the function annotated with `#[target_feature]` is not a safe /// trait method implementation, reporting an error if it is. fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) { diff --git a/src/librustc_typeck/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs similarity index 98% rename from src/librustc_typeck/collect/type_of.rs rename to compiler/rustc_typeck/src/collect/type_of.rs index 70ed92c561..f6dca4a99c 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -1,5 +1,6 @@ +use crate::errors::AssocTypeOnInherentImpl; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, Applicability, ErrorReported, StashKey}; +use rustc_errors::{Applicability, ErrorReported, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -78,7 +79,13 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let _tables = tcx.typeck(body_owner); &*path } - _ => span_bug!(DUMMY_SP, "unexpected const parent path {:?}", parent_node), + _ => { + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + &format!("unexpected const parent path {:?}", parent_node), + ); + return None; + } }; // We've encountered an `AnonConst` in some path, so we need to @@ -382,7 +389,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { let mut used_params: FxHashSet<_> = FxHashSet::default(); for (i, arg) in substs.iter().enumerate() { let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)), + GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Lifetime(lt) => { matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) } @@ -607,7 +614,7 @@ fn infer_placeholder_type( } None => { let mut diag = bad_placeholder_type(tcx, vec![span]); - if !matches!(ty.kind, ty::Error(_)) { + if !matches!(ty.kind(), ty::Error(_)) { diag.span_suggestion( span, "replace `_` with the correct type", @@ -627,11 +634,5 @@ fn infer_placeholder_type( } fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) { - struct_span_err!( - tcx.sess, - span, - E0202, - "associated types are not yet supported in inherent impls (see #8995)" - ) - .emit(); + tcx.sess.emit_err(AssocTypeOnInherentImpl { span }); } diff --git a/src/librustc_typeck/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs similarity index 99% rename from src/librustc_typeck/constrained_generic_params.rs rename to compiler/rustc_typeck/src/constrained_generic_params.rs index 7c80315ee1..09b5a9b0a6 100644 --- a/src/librustc_typeck/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -57,7 +57,7 @@ struct ParameterCollector { impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { + match *t.kind() { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { // projections are not injective return false; diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs new file mode 100644 index 0000000000..a769e48d2c --- /dev/null +++ b/compiler/rustc_typeck/src/errors.rs @@ -0,0 +1,199 @@ +//! Errors emitted by typeck. +use rustc_macros::SessionDiagnostic; +use rustc_span::{symbol::Ident, Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[error = "E0062"] +pub struct FieldMultiplySpecifiedInInitializer { + #[message = "field `{ident}` specified more than once"] + #[label = "used more than once"] + pub span: Span, + #[label = "first use of `{ident}`"] + pub prev_span: Span, + pub ident: Ident, +} + +#[derive(SessionDiagnostic)] +#[error = "E0092"] +pub struct UnrecognizedAtomicOperation<'a> { + #[message = "unrecognized atomic operation function: `{op}`"] + #[label = "unrecognized atomic operation"] + pub span: Span, + pub op: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error = "E0094"] +pub struct WrongNumberOfTypeArgumentsToInstrinsic { + #[message = "intrinsic has wrong number of type \ + parameters: found {found}, expected {expected}"] + #[label = "expected {expected} type parameter"] + pub span: Span, + pub found: usize, + pub expected: usize, +} + +#[derive(SessionDiagnostic)] +#[error = "E0093"] +pub struct UnrecognizedIntrinsicFunction { + #[message = "unrecognized intrinsic function: `{name}`"] + #[label = "unrecognized intrinsic"] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[error = "E0195"] +pub struct LifetimesOrBoundsMismatchOnTrait { + #[message = "lifetime parameters or bounds on {item_kind} `{ident}` do not match the trait declaration"] + #[label = "lifetimes do not match {item_kind} in trait"] + pub span: Span, + #[label = "lifetimes in impl do not match this {item_kind} in trait"] + pub generics_span: Option, + pub item_kind: &'static str, + pub ident: Ident, +} + +#[derive(SessionDiagnostic)] +#[error = "E0120"] +pub struct DropImplOnWrongItem { + #[message = "the `Drop` trait may only be implemented for structs, enums, and unions"] + #[label = "must be a struct, enum, or union"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0124"] +pub struct FieldAlreadyDeclared { + pub field_name: Ident, + #[message = "field `{field_name}` is already declared"] + #[label = "field already declared"] + pub span: Span, + #[label = "`{field_name}` first declared here"] + pub prev_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0184"] +pub struct CopyImplOnTypeWithDtor { + #[message = "the trait `Copy` may not be implemented for this type; the \ + type has a destructor"] + #[label = "Copy not allowed on types with destructors"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0202"] +pub struct AssocTypeOnInherentImpl { + #[message = "associated types are not yet supported in inherent impls (see #8995)"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0203"] +pub struct MultipleRelaxedDefaultBounds { + #[message = "type parameter has more than one relaxed default bound, only one is supported"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0206"] +pub struct CopyImplOnNonAdt { + #[message = "the trait `Copy` may not be implemented for this type"] + #[label = "type is not a structure or enumeration"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0224"] +pub struct TraitObjectDeclaredWithNoTraits { + #[message = "at least one trait is required for an object type"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0227"] +pub struct AmbiguousLifetimeBound { + #[message = "ambiguous lifetime bound, explicit lifetime bound required"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0229"] +pub struct AssocTypeBindingNotAllowed { + #[message = "associated type bindings are not allowed here"] + #[label = "associated type not allowed here"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0439"] +pub struct SimdShuffleMissingLength { + #[message = "invalid `simd_shuffle`, needs length: `{name}`"] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[error = "E0436"] +pub struct FunctionalRecordUpdateOnNonStruct { + #[message = "functional record update syntax requires a struct"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0516"] +pub struct TypeofReservedKeywordUsed { + #[message = "`typeof` is a reserved keyword but unimplemented"] + #[label = "reserved keyword"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0572"] +pub struct ReturnStmtOutsideOfFnBody { + #[message = "return statement outside of function body"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0627"] +pub struct YieldExprOutsideOfGenerator { + #[message = "yield expression outside of generator literal"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0639"] +pub struct StructExprNonExhaustive { + #[message = "cannot create non-exhaustive {what} using struct expression"] + pub span: Span, + pub what: &'static str, +} + +#[derive(SessionDiagnostic)] +#[error = "E0699"] +pub struct MethodCallOnUnknownType { + #[message = "the type of this value must be known to call a method on a raw pointer on it"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0719"] +pub struct ValueOfAssociatedStructAlreadySpecified { + #[message = "the value of the associated type `{item_name}` (from trait `{def_path}`) is already specified"] + #[label = "re-bound here"] + pub span: Span, + #[label = "`{item_name}` bound here first"] + pub prev_span: Span, + pub item_name: Ident, + pub def_path: String, +} + +#[derive(SessionDiagnostic)] +#[error = "E0745"] +pub struct AddressOfTemporaryTaken { + #[message = "cannot take address of a temporary"] + #[label = "temporary value"] + pub span: Span, +} diff --git a/src/librustc_typeck/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs similarity index 99% rename from src/librustc_typeck/expr_use_visitor.rs rename to compiler/rustc_typeck/src/expr_use_visitor.rs index d1b386c9d4..e16f26c330 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -387,7 +387,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - match with_place.place.ty().kind { + match with_place.place.ty().kind() { ty::Adt(adt, substs) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() { @@ -559,7 +559,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { var_id, )); match upvar_capture { - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue(_) => { let mode = copy_or_move(&self.mc, &captured_place); self.delegate.consume(&captured_place, mode); } diff --git a/src/librustc_typeck/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs similarity index 95% rename from src/librustc_typeck/impl_wf_check.rs rename to compiler/rustc_typeck/src/impl_wf_check.rs index 891e482b43..4901d6041d 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -187,7 +187,7 @@ fn enforce_impl_params_are_constrained( } // (*) This is a horrible concession to reality. I think it'd be - // better to just ban unconstrianed lifetimes outright, but in + // better to just ban unconstrained lifetimes outright, but in // practice people do non-hygenic macros like: // // ``` @@ -207,7 +207,7 @@ fn enforce_impl_params_are_constrained( } fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) { - struct_span_err!( + let mut err = struct_span_err!( tcx.sess, span, E0207, @@ -215,9 +215,17 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) impl trait, self type, or predicates", kind, name - ) - .span_label(span, format!("unconstrained {} parameter", kind)) - .emit(); + ); + err.span_label(span, format!("unconstrained {} parameter", kind)); + if kind == "const" { + err.note( + "expressions using a const parameter must map each value to a distinct output value", + ); + err.note( + "proving the result of expressions other than the parameter are unique is not supported", + ); + } + err.emit(); } /// Enforce that we do not have two items in an impl with the same name. diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs similarity index 99% rename from src/librustc_typeck/impl_wf_check/min_specialization.rs rename to compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 3746e5778a..60b9467fca 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -405,6 +405,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateAtom::ObjectSafe(_) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } } diff --git a/src/librustc_typeck/lib.rs b/compiler/rustc_typeck/src/lib.rs similarity index 98% rename from src/librustc_typeck/lib.rs rename to compiler/rustc_typeck/src/lib.rs index 62f92fe7ff..21fb92ec88 100644 --- a/src/librustc_typeck/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -55,8 +55,7 @@ This API is completely unstable and subject to change. */ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![allow(non_camel_case_types)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] @@ -84,6 +83,7 @@ mod check_unused; mod coherence; mod collect; mod constrained_generic_params; +mod errors; mod impl_wf_check; mod mem_categorization; mod outlives; @@ -158,7 +158,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) { let main_id = tcx.hir().local_def_id_to_hir_id(main_def_id); let main_span = tcx.def_span(main_def_id); let main_t = tcx.type_of(main_def_id); - match main_t.kind { + match main_t.kind() { ty::FnDef(..) => { if let Some(Node::Item(it)) = tcx.hir().find(main_id) { if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind { @@ -254,7 +254,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) { let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id); let start_span = tcx.def_span(start_def_id); let start_t = tcx.type_of(start_def_id); - match start_t.kind { + match start_t.kind() { ty::FnDef(..) => { if let Some(Node::Item(it)) = tcx.hir().find(start_id) { if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind { @@ -359,7 +359,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { // this ensures that later parts of type checking can assume that items // have valid types and not error - // FIXME(matthewjasper) We shouldn't need to do this. + // FIXME(matthewjasper) We shouldn't need to use `track_errors`. tcx.sess.track_errors(|| { tcx.sess.time("type_collecting", || { for &module in tcx.hir().krate().modules.keys() { diff --git a/src/librustc_typeck/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs similarity index 99% rename from src/librustc_typeck/mem_categorization.rs rename to compiler/rustc_typeck/src/mem_categorization.rs index 8a6fe620af..04ead74936 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -482,7 +482,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let place_ty = self.expr_ty(expr)?; let base_ty = self.expr_ty_adjusted(base)?; - let (region, mutbl) = match base_ty.kind { + let (region, mutbl) = match *base_ty.kind() { ty::Ref(region, _, mutbl) => (region, mutbl), _ => span_bug!(expr.span, "cat_overloaded_place: base is not a reference"), }; @@ -542,7 +542,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) -> McResult { let res = self.typeck_results.qpath_res(qpath, pat_hir_id); let ty = self.typeck_results.node_type(pat_hir_id); - let adt_def = match ty.kind { + let adt_def = match ty.kind() { ty::Adt(adt_def, _) => adt_def, _ => { self.tcx() @@ -577,7 +577,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { span: Span, ) -> McResult { let ty = self.typeck_results.node_type(pat_hir_id); - match ty.kind { + match ty.kind() { ty::Adt(adt_def, _) => Ok(adt_def.variants[variant_index].fields.len()), _ => { self.tcx() @@ -592,7 +592,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { /// Here `pat_hir_id` is the HirId of the pattern itself. fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult { let ty = self.typeck_results.node_type(pat_hir_id); - match ty.kind { + match ty.kind() { ty::Tuple(substs) => Ok(substs.len()), _ => { self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple"); diff --git a/src/librustc_typeck/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs similarity index 94% rename from src/librustc_typeck/outlives/explicit.rs rename to compiler/rustc_typeck/src/outlives/explicit.rs index 135960a4c1..ae336ccca4 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/compiler/rustc_typeck/src/outlives/explicit.rs @@ -57,7 +57,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => (), + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => (), } } diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs similarity index 99% rename from src/librustc_typeck/outlives/implicit_infer.rs rename to compiler/rustc_typeck/src/outlives/implicit_infer.rs index 762d4216f7..e7a9e078a7 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -128,7 +128,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, }; - match ty.kind { + match *ty.kind() { // The field is of type &'a T which means that we will have // a predicate requirement of T: 'a (T outlives 'a). // diff --git a/src/librustc_typeck/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs similarity index 100% rename from src/librustc_typeck/outlives/mod.rs rename to compiler/rustc_typeck/src/outlives/mod.rs diff --git a/src/librustc_typeck/outlives/test.rs b/compiler/rustc_typeck/src/outlives/test.rs similarity index 100% rename from src/librustc_typeck/outlives/test.rs rename to compiler/rustc_typeck/src/outlives/test.rs diff --git a/src/librustc_typeck/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs similarity index 100% rename from src/librustc_typeck/outlives/utils.rs rename to compiler/rustc_typeck/src/outlives/utils.rs diff --git a/src/librustc_typeck/structured_errors.rs b/compiler/rustc_typeck/src/structured_errors.rs similarity index 100% rename from src/librustc_typeck/structured_errors.rs rename to compiler/rustc_typeck/src/structured_errors.rs diff --git a/src/librustc_typeck/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs similarity index 99% rename from src/librustc_typeck/variance/constraints.rs rename to compiler/rustc_typeck/src/variance/constraints.rs index 535530a2ed..b2b062e409 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -140,7 +140,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let id = tcx.hir().local_def_id_to_hir_id(def_id); let inferred_start = self.terms_cx.inferred_starts[&id]; let current_item = &CurrentItem { inferred_start }; - match tcx.type_of(def_id).kind { + match tcx.type_of(def_id).kind() { ty::Adt(def, _) => { // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion @@ -257,7 +257,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ) { debug!("add_constraints_from_ty(ty={:?}, variance={:?})", ty, variance); - match ty.kind { + match *ty.kind() { ty::Bool | ty::Char | ty::Int(_) diff --git a/src/librustc_typeck/variance/mod.rs b/compiler/rustc_typeck/src/variance/mod.rs similarity index 100% rename from src/librustc_typeck/variance/mod.rs rename to compiler/rustc_typeck/src/variance/mod.rs diff --git a/src/librustc_typeck/variance/solve.rs b/compiler/rustc_typeck/src/variance/solve.rs similarity index 98% rename from src/librustc_typeck/variance/solve.rs rename to compiler/rustc_typeck/src/variance/solve.rs index 7402117a7e..2d3369cba7 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/compiler/rustc_typeck/src/variance/solve.rs @@ -107,7 +107,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { self.enforce_const_invariance(generics, variances); // Functions are permitted to have unused generic parameters: make those invariant. - if let ty::FnDef(..) = tcx.type_of(def_id).kind { + if let ty::FnDef(..) = tcx.type_of(def_id).kind() { for variance in variances.iter_mut() { if *variance == ty::Bivariant { *variance = ty::Invariant; diff --git a/src/librustc_typeck/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs similarity index 100% rename from src/librustc_typeck/variance/terms.rs rename to compiler/rustc_typeck/src/variance/terms.rs diff --git a/src/librustc_typeck/variance/test.rs b/compiler/rustc_typeck/src/variance/test.rs similarity index 100% rename from src/librustc_typeck/variance/test.rs rename to compiler/rustc_typeck/src/variance/test.rs diff --git a/src/librustc_typeck/variance/xform.rs b/compiler/rustc_typeck/src/variance/xform.rs similarity index 100% rename from src/librustc_typeck/variance/xform.rs rename to compiler/rustc_typeck/src/variance/xform.rs diff --git a/config.toml.example b/config.toml.example index 36587cc078..c5efb8ed5e 100644 --- a/config.toml.example +++ b/config.toml.example @@ -9,11 +9,42 @@ # a custom configuration file can also be specified with `--config` to the build # system. +# Keeps track of the last version of `x.py` used. +# If it does not match the version that is currently running, +# `x.py` will prompt you to update it and read the changelog. +# See `src/bootstrap/CHANGELOG.md` for more information. +changelog-seen = 1 + +# ============================================================================= +# Global Settings +# ============================================================================= + +# Use different pre-set defaults than the global defaults. +# +# See `src/bootstrap/defaults` for more information. +# Note that this has no default value (x.py uses the defaults in `config.toml.example`). +#profile = + # ============================================================================= # Tweaking how LLVM is compiled # ============================================================================= [llvm] +# Whether to use Rust CI built LLVM instead of locally building it. +# +# Unless you're developing for a target where Rust CI doesn't build a compiler +# toolchain or changing LLVM locally, you probably want to set this to true. +# +# It's currently false by default due to being newly added; please file bugs if +# enabling this did not work for you on x86_64-unknown-linux-gnu. +# Other target triples are currently not supported; see #77084. +# +# We also currently only support this when building LLVM for the build triple. +# +# Note that many of the LLVM options are not currently supported for +# downloading. Currently only the "assertions" option can be toggled. +#download-ci-llvm = false + # Indicates whether LLVM rebuild should be skipped when running bootstrap. If # this is `false` then the compiler's LLVM will be rebuilt whenever the built # version doesn't have the correct hash. If it is `true` then LLVM will never @@ -45,14 +76,12 @@ # this flag will indicate that this version check should not be done. #version-check = true -# Link libstdc++ statically into the librustc_llvm instead of relying on a +# Link libstdc++ statically into the rustc_llvm instead of relying on a # dynamic version to be available. #static-libstdcpp = false -# Tell the LLVM build system to use Ninja instead of the platform default for -# the generated build system. This can sometimes be faster than make, for -# example. -#ninja = false +# Whether to use Ninja to build LLVM. This runs much faster than make. +#ninja = true # LLVM targets to build support for. # Note: this is NOT related to Rust compilation targets. However, as Rust is @@ -113,6 +142,23 @@ # General build configuration options # ============================================================================= [build] +# The default stage to use for the `doc` subcommand +#doc-stage = 0 + +# The default stage to use for the `build` subcommand +#build-stage = 1 + +# The default stage to use for the `test` subcommand +#test-stage = 1 + +# The default stage to use for the `dist` subcommand +#dist-stage = 2 + +# The default stage to use for the `install` subcommand +#install-stage = 2 + +# The default stage to use for the `bench` subcommand +#bench-stage = 2 # Build triple for the original snapshot compiler. This must be a compiler that # nightlies are already produced for. The current platform must be able to run @@ -122,19 +168,18 @@ # Defaults to host platform #build = "x86_64-unknown-linux-gnu" -# In addition to the build triple, other triples to produce full compiler -# toolchains for. Each of these triples will be bootstrapped from the build -# triple and then will continue to bootstrap themselves. This platform must -# currently be able to run all of the triples provided here. +# Which triples to produce a compiler toolchain for. Each of these triples will +# be bootstrapped from the build triple themselves. # # Defaults to just the build triple #host = ["x86_64-unknown-linux-gnu"] -# In addition to all host triples, other triples to produce the standard library -# for. Each host triple will be used to produce a copy of the standard library -# for each target triple. +# Which triples to build libraries (core/alloc/std/test/proc_macro) for. Each of +# these triples will be bootstrapped from the build triple themselves. # -# Defaults to just the build triple +# Defaults to `host`. If you set this explicitly, you likely want to add all +# host triples to this list as well in order for those host toolchains to be +# able to compile programs for their native target. #target = ["x86_64-unknown-linux-gnu"] # Use this directory to store build artifacts. @@ -311,7 +356,9 @@ # Number of codegen units to use for each compiler invocation. A value of 0 # means "the number of cores on this machine", and 1+ is passed through to the # compiler. -#codegen-units = 1 +# +# Uses the rustc defaults: https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units +#codegen-units = if incremental { 256 } else { 16 } # Sets the number of codegen units to build the standard library with, # regardless of what the codegen-unit setting for the rest of the compiler is. @@ -323,13 +370,19 @@ # binary, otherwise they are omitted. # # Defaults to rust.debug value -#debug-assertions = false +#debug-assertions = debug # Whether or not debug assertions are enabled for the standard library. # Overrides the `debug-assertions` option, if defined. # # Defaults to rust.debug-assertions value -#debug-assertions-std = false +#debug-assertions-std = debug-assertions + +# Whether or not to leave debug! and trace! calls in the rust binary. +# Overrides the `debug-assertions` option, if defined. +# +# Defaults to rust.debug-assertions value +#debug-logging = debug-assertions # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # `0` - no debug info @@ -373,6 +426,7 @@ #incremental = false # Build a multi-threaded rustc +# FIXME(#75760): Some UI tests fail when this option is enabled. #parallel-compiler = false # The default linker that will be hard-coded into the generated compiler for @@ -394,7 +448,7 @@ # desired in distributions, for example. #rpath = true -# Emits extra output from tests so test failures are debuggable just from logfiles. +# Prints each test name as it is executed, to help debug issues in the test harness itself. #verbose-tests = false # Flag indicating whether tests are compiled with optimizations (the -O flag). @@ -431,7 +485,7 @@ # supported platforms. The LLD from the bootstrap distribution will be used # and not the LLD compiled during the bootstrap. # -# LLD will not be used if we're cross linking or running tests. +# LLD will not be used if we're cross linking. # # Explicitly setting the linker for a target will override this option when targeting MSVC. #use-lld = false diff --git a/git-commit-hash b/git-commit-hash index d00fffae96..c767182e4b 100644 --- a/git-commit-hash +++ b/git-commit-hash @@ -1 +1 @@ -18bf6b4f01a6feaf7259ba7cdae58031af1b7b39 \ No newline at end of file +1219014599fd873fcb640b675d8a662150c74e40 \ No newline at end of file diff --git a/library/alloc/benches/binary_heap.rs b/library/alloc/benches/binary_heap.rs new file mode 100644 index 0000000000..5b6538ea6c --- /dev/null +++ b/library/alloc/benches/binary_heap.rs @@ -0,0 +1,91 @@ +use std::collections::BinaryHeap; + +use rand::{seq::SliceRandom, thread_rng}; +use test::{black_box, Bencher}; + +#[bench] +fn bench_find_smallest_1000(b: &mut Bencher) { + let mut rng = thread_rng(); + let mut vec: Vec = (0..100_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| { + let mut iter = vec.iter().copied(); + let mut heap: BinaryHeap<_> = iter.by_ref().take(1000).collect(); + + for x in iter { + let mut max = heap.peek_mut().unwrap(); + // This comparison should be true only 1% of the time. + // Unnecessary `sift_down`s will degrade performance + if x < *max { + *max = x; + } + } + + heap + }) +} + +#[bench] +fn bench_peek_mut_deref_mut(b: &mut Bencher) { + let mut bheap = BinaryHeap::from(vec![42]); + let vec: Vec = (0..1_000_000).collect(); + + b.iter(|| { + let vec = black_box(&vec); + let mut peek_mut = bheap.peek_mut().unwrap(); + // The compiler shouldn't be able to optimize away the `sift_down` + // assignment in `PeekMut`'s `DerefMut` implementation since + // the loop may not run. + for &i in vec.iter() { + *peek_mut = i; + } + // Remove the already minimal overhead of the sift_down + std::mem::forget(peek_mut); + }) +} + +#[bench] +fn bench_from_vec(b: &mut Bencher) { + let mut rng = thread_rng(); + let mut vec: Vec = (0..100_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| BinaryHeap::from(vec.clone())) +} + +#[bench] +fn bench_into_sorted_vec(b: &mut Bencher) { + let bheap: BinaryHeap = (0..10_000).collect(); + + b.iter(|| bheap.clone().into_sorted_vec()) +} + +#[bench] +fn bench_push(b: &mut Bencher) { + let mut bheap = BinaryHeap::with_capacity(50_000); + let mut rng = thread_rng(); + let mut vec: Vec = (0..50_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| { + for &i in vec.iter() { + bheap.push(i); + } + black_box(&mut bheap); + bheap.clear(); + }) +} + +#[bench] +fn bench_pop(b: &mut Bencher) { + let mut bheap = BinaryHeap::with_capacity(10_000); + + b.iter(|| { + bheap.extend((0..10_000).rev()); + black_box(&mut bheap); + while let Some(elem) = bheap.pop() { + black_box(elem); + } + }) +} diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs index 608eafc88d..32edb86d10 100644 --- a/library/alloc/benches/lib.rs +++ b/library/alloc/benches/lib.rs @@ -8,6 +8,7 @@ extern crate test; +mod binary_heap; mod btree; mod linked_list; mod slice; diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index 4e71eec03e..789ae3a20e 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -1,5 +1,6 @@ +use rand::RngCore; use std::iter::{repeat, FromIterator}; -use test::Bencher; +use test::{black_box, Bencher}; #[bench] fn bench_new(b: &mut Bencher) { @@ -7,6 +8,7 @@ fn bench_new(b: &mut Bencher) { let v: Vec = Vec::new(); assert_eq!(v.len(), 0); assert_eq!(v.capacity(), 0); + v }) } @@ -17,6 +19,7 @@ fn do_bench_with_capacity(b: &mut Bencher, src_len: usize) { let v: Vec = Vec::with_capacity(src_len); assert_eq!(v.len(), 0); assert_eq!(v.capacity(), src_len); + v }) } @@ -47,6 +50,7 @@ fn do_bench_from_fn(b: &mut Bencher, src_len: usize) { let dst = (0..src_len).collect::>(); assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }) } @@ -77,6 +81,7 @@ fn do_bench_from_elem(b: &mut Bencher, src_len: usize) { let dst: Vec = repeat(5).take(src_len).collect(); assert_eq!(dst.len(), src_len); assert!(dst.iter().all(|x| *x == 5)); + dst }) } @@ -109,6 +114,7 @@ fn do_bench_from_slice(b: &mut Bencher, src_len: usize) { let dst = src.clone()[..].to_vec(); assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } @@ -141,6 +147,7 @@ fn do_bench_from_iter(b: &mut Bencher, src_len: usize) { let dst: Vec<_> = FromIterator::from_iter(src.clone()); assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } @@ -175,6 +182,7 @@ fn do_bench_extend(b: &mut Bencher, dst_len: usize, src_len: usize) { dst.extend(src.clone()); assert_eq!(dst.len(), dst_len + src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } @@ -224,9 +232,24 @@ fn do_bench_extend_from_slice(b: &mut Bencher, dst_len: usize, src_len: usize) { dst.extend_from_slice(&src); assert_eq!(dst.len(), dst_len + src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } +#[bench] +fn bench_extend_recycle(b: &mut Bencher) { + let mut data = vec![0; 1000]; + + b.iter(|| { + let tmp = std::mem::take(&mut data); + let mut to_extend = black_box(Vec::new()); + to_extend.extend(tmp.into_iter()); + data = black_box(to_extend); + }); + + black_box(data); +} + #[bench] fn bench_extend_from_slice_0000_0000(b: &mut Bencher) { do_bench_extend_from_slice(b, 0, 0) @@ -271,6 +294,7 @@ fn do_bench_clone(b: &mut Bencher, src_len: usize) { let dst = src.clone(); assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } @@ -305,10 +329,10 @@ fn do_bench_clone_from(b: &mut Bencher, times: usize, dst_len: usize, src_len: u for _ in 0..times { dst.clone_from(&src); - assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| dst_len + i == *x)); } + dst }); } @@ -431,3 +455,219 @@ fn bench_clone_from_10_0100_0010(b: &mut Bencher) { fn bench_clone_from_10_1000_0100(b: &mut Bencher) { do_bench_clone_from(b, 10, 1000, 100) } + +macro_rules! bench_in_place { + ($($fname:ident, $type:ty, $count:expr, $init:expr);*) => { + $( + #[bench] + fn $fname(b: &mut Bencher) { + b.iter(|| { + let src: Vec<$type> = black_box(vec![$init; $count]); + let mut sink = src.into_iter() + .enumerate() + .map(|(idx, e)| idx as $type ^ e) + .collect::>(); + black_box(sink.as_mut_ptr()) + }); + } + )+ + }; +} + +bench_in_place![ + bench_in_place_xxu8_0010_i0, u8, 10, 0; + bench_in_place_xxu8_0100_i0, u8, 100, 0; + bench_in_place_xxu8_1000_i0, u8, 1000, 0; + bench_in_place_xxu8_0010_i1, u8, 10, 1; + bench_in_place_xxu8_0100_i1, u8, 100, 1; + bench_in_place_xxu8_1000_i1, u8, 1000, 1; + bench_in_place_xu32_0010_i0, u32, 10, 0; + bench_in_place_xu32_0100_i0, u32, 100, 0; + bench_in_place_xu32_1000_i0, u32, 1000, 0; + bench_in_place_xu32_0010_i1, u32, 10, 1; + bench_in_place_xu32_0100_i1, u32, 100, 1; + bench_in_place_xu32_1000_i1, u32, 1000, 1; + bench_in_place_u128_0010_i0, u128, 10, 0; + bench_in_place_u128_0100_i0, u128, 100, 0; + bench_in_place_u128_1000_i0, u128, 1000, 0; + bench_in_place_u128_0010_i1, u128, 10, 1; + bench_in_place_u128_0100_i1, u128, 100, 1; + bench_in_place_u128_1000_i1, u128, 1000, 1 +]; + +#[bench] +fn bench_in_place_recycle(b: &mut Bencher) { + let mut data = vec![0; 1000]; + + b.iter(|| { + let tmp = std::mem::take(&mut data); + data = black_box( + tmp.into_iter() + .enumerate() + .map(|(idx, e)| idx.wrapping_add(e)) + .fuse() + .peekable() + .collect::>(), + ); + }); +} + +#[bench] +fn bench_in_place_zip_recycle(b: &mut Bencher) { + let mut data = vec![0u8; 1000]; + let mut rng = rand::thread_rng(); + let mut subst = vec![0u8; 1000]; + rng.fill_bytes(&mut subst[..]); + + b.iter(|| { + let tmp = std::mem::take(&mut data); + let mangled = tmp + .into_iter() + .zip(subst.iter().copied()) + .enumerate() + .map(|(i, (d, s))| d.wrapping_add(i as u8) ^ s) + .collect::>(); + assert_eq!(mangled.len(), 1000); + data = black_box(mangled); + }); +} + +#[bench] +fn bench_in_place_zip_iter_mut(b: &mut Bencher) { + let mut data = vec![0u8; 256]; + let mut rng = rand::thread_rng(); + let mut subst = vec![0u8; 1000]; + rng.fill_bytes(&mut subst[..]); + + b.iter(|| { + data.iter_mut().enumerate().for_each(|(i, d)| { + *d = d.wrapping_add(i as u8) ^ subst[i]; + }); + }); + + black_box(data); +} + +#[derive(Clone)] +struct Droppable(usize); + +impl Drop for Droppable { + fn drop(&mut self) { + black_box(self); + } +} + +#[bench] +fn bench_in_place_collect_droppable(b: &mut Bencher) { + let v: Vec = std::iter::repeat_with(|| Droppable(0)).take(1000).collect(); + b.iter(|| { + v.clone() + .into_iter() + .skip(100) + .enumerate() + .map(|(i, e)| Droppable(i ^ e.0)) + .collect::>() + }) +} + +#[bench] +fn bench_chain_collect(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| data.iter().cloned().chain([1].iter().cloned()).collect::>()); +} + +#[bench] +fn bench_chain_chain_collect(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + data.iter() + .cloned() + .chain([1].iter().cloned()) + .chain([2].iter().cloned()) + .collect::>() + }); +} + +#[bench] +fn bench_nest_chain_chain_collect(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + data.iter().cloned().chain([1].iter().chain([2].iter()).cloned()).collect::>() + }); +} + +pub fn example_plain_slow(l: &[u32]) -> Vec { + let mut result = Vec::with_capacity(l.len()); + result.extend(l.iter().rev()); + result +} + +pub fn map_fast(l: &[(u32, u32)]) -> Vec { + let mut result = Vec::with_capacity(l.len()); + for i in 0..l.len() { + unsafe { + *result.get_unchecked_mut(i) = l[i].0; + result.set_len(i); + } + } + result +} + +const LEN: usize = 16384; + +#[bench] +fn bench_range_map_collect(b: &mut Bencher) { + b.iter(|| (0..LEN).map(|_| u32::default()).collect::>()); +} + +#[bench] +fn bench_chain_extend_ref(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::with_capacity(data.len() + 1); + v.extend(data.iter().chain([1].iter())); + v + }); +} + +#[bench] +fn bench_chain_extend_value(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::with_capacity(data.len() + 1); + v.extend(data.iter().cloned().chain(Some(1))); + v + }); +} + +#[bench] +fn bench_rev_1(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::new(); + v.extend(data.iter().rev()); + v + }); +} + +#[bench] +fn bench_rev_2(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| example_plain_slow(&data)); +} + +#[bench] +fn bench_map_regular(b: &mut Bencher) { + let data = black_box([(0, 0); LEN]); + b.iter(|| { + let mut v = Vec::::new(); + v.extend(data.iter().map(|t| t.1)); + v + }); +} + +#[bench] +fn bench_map_fast(b: &mut Bencher) { + let data = black_box([(0, 0); LEN]); + b.iter(|| map_fast(&data)); +} diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 87b86e590a..75158eefca 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -3,7 +3,7 @@ #![stable(feature = "alloc_module", since = "1.28.0")] use core::intrinsics::{self, min_align_of_val, size_of_val}; -use core::ptr::{NonNull, Unique}; +use core::ptr::{self, NonNull, Unique}; #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] @@ -145,53 +145,62 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { impl Global { #[inline] - fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result, AllocErr> { + fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), // SAFETY: `layout` is non-zero in size, size => unsafe { let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) }; - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::slice_from_raw_parts(ptr, size)) }, } } - // Safety: Same as `AllocRef::grow` + // SAFETY: Same as `AllocRef::grow` #[inline] unsafe fn grow_impl( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, zeroed: bool, - ) -> Result, AllocErr> { + ) -> Result, AllocError> { debug_assert!( - new_size >= layout.size(), - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - match layout.size() { - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - 0 => unsafe { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc_impl(new_layout, zeroed) - }, + match old_layout.size() { + 0 => self.alloc_impl(new_layout, zeroed), // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // as required by safety conditions. Other conditions must be upheld by the caller - old_size => unsafe { - // `realloc` probably checks for `new_size >= size` or something similar. - intrinsics::assume(new_size >= layout.size()); + old_size if old_layout.align() == new_layout.align() => unsafe { + let new_size = new_layout.size(); + + // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. + intrinsics::assume(new_size >= old_layout.size()); - let raw_ptr = realloc(ptr.as_ptr(), layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; if zeroed { raw_ptr.add(old_size).write_bytes(0, new_size - old_size); } Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, + // both the old and new memory allocation are valid for reads and writes for `old_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + old_size => unsafe { + let new_ptr = self.alloc_impl(new_layout, zeroed)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); + self.dealloc(ptr, old_layout); + Ok(new_ptr) + }, } } } @@ -199,17 +208,17 @@ impl Global { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl AllocRef for Global { #[inline] - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -219,54 +228,66 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn grow( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, false) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } } #[inline] unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, true) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } } #[inline] unsafe fn shrink( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size <= layout.size(), - "`new_size` must be smaller than or equal to `layout.size()`" + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - match new_size { + match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, layout); - Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)) + self.dealloc(ptr, old_layout); + Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller - new_size => unsafe { - // `realloc` probably checks for `new_size <= size` or something similar. - intrinsics::assume(new_size <= layout.size()); + new_size if old_layout.align() == new_layout.align() => unsafe { + // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. + intrinsics::assume(new_size <= old_layout.size()); - let raw_ptr = realloc(ptr.as_ptr(), layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, + // both the old and new memory allocation are valid for reads and writes for `new_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + new_size => unsafe { + let new_ptr = self.alloc(new_layout)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); + self.dealloc(ptr, old_layout); + Ok(new_ptr) + }, } } } @@ -279,7 +300,7 @@ unsafe impl AllocRef for Global { unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; match Global.alloc(layout) { - Ok(ptr) => ptr.as_non_null_ptr().as_ptr(), + Ok(ptr) => ptr.as_mut_ptr(), Err(_) => handle_alloc_error(layout), } } diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 51c233a21f..f801c1ac75 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -217,7 +217,8 @@ impl Cow<'_, B> { /// assert!(!bull.is_borrowed()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] - pub fn is_borrowed(&self) -> bool { + #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] + pub const fn is_borrowed(&self) -> bool { match *self { Borrowed(_) => true, Owned(_) => false, @@ -239,7 +240,8 @@ impl Cow<'_, B> { /// assert!(!bull.is_owned()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] - pub fn is_owned(&self) -> bool { + #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] + pub const fn is_owned(&self) -> bool { !self.is_borrowed() } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 05211e2037..5c8c2c5a5a 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -217,7 +217,7 @@ impl Box { /// assert_eq!(*zero, 0) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Box> { let layout = alloc::Layout::new::>(); @@ -289,7 +289,7 @@ impl Box<[T]> { /// assert_eq!(*values, [0, 0, 0]) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit]> { unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } @@ -307,7 +307,7 @@ impl Box> { /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// @@ -343,7 +343,7 @@ impl Box<[mem::MaybeUninit]> { /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 477a598ff5..f2852b1cc2 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -15,7 +15,6 @@ //! [dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm //! [sssp]: https://en.wikipedia.org/wiki/Shortest_path_problem //! [dir_graph]: https://en.wikipedia.org/wiki/Directed_graph -//! [`BinaryHeap`]: struct.BinaryHeap.html //! //! ``` //! use std::cmp::Ordering; @@ -31,7 +30,7 @@ //! // Explicitly implement the trait so the queue becomes a min-heap //! // instead of a max-heap. //! impl Ord for State { -//! fn cmp(&self, other: &State) -> Ordering { +//! fn cmp(&self, other: &Self) -> Ordering { //! // Notice that the we flip the ordering on costs. //! // In case of a tie we compare positions - this step is necessary //! // to make implementations of `PartialEq` and `Ord` consistent. @@ -42,7 +41,7 @@ //! //! // `PartialOrd` needs to be implemented as well. //! impl PartialOrd for State { -//! fn partial_cmp(&self, other: &State) -> Option { +//! fn partial_cmp(&self, other: &Self) -> Option { //! Some(self.cmp(other)) //! } //! } @@ -145,13 +144,13 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::fmt; -use core::iter::{FromIterator, FusedIterator, TrustedLen}; -use core::mem::{self, size_of, swap, ManuallyDrop}; +use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen}; +use core::mem::{self, swap, ManuallyDrop}; use core::ops::{Deref, DerefMut}; use core::ptr; use crate::slice; -use crate::vec::{self, Vec}; +use crate::vec::{self, AsIntoIter, Vec}; use super::SpecExtend; @@ -240,10 +239,10 @@ use super::SpecExtend; /// The value for `push` is an expected cost; the method documentation gives a /// more detailed analysis. /// -/// [push]: #method.push -/// [pop]: #method.pop -/// [peek]: #method.peek -/// [peek\_mut]: #method.peek_mut +/// [push]: BinaryHeap::push +/// [pop]: BinaryHeap::pop +/// [peek]: BinaryHeap::peek +/// [peek\_mut]: BinaryHeap::peek_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct BinaryHeap { data: Vec, @@ -255,8 +254,7 @@ pub struct BinaryHeap { /// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See /// its documentation for more. /// -/// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`peek_mut`]: BinaryHeap::peek_mut #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub struct PeekMut<'a, T: 'a + Ord> { heap: &'a mut BinaryHeap, @@ -293,6 +291,7 @@ impl Deref for PeekMut<'_, T> { impl DerefMut for PeekMut<'_, T> { fn deref_mut(&mut self) -> &mut T { debug_assert!(!self.heap.is_empty()); + self.sift = true; // SAFE: PeekMut is only instantiated for non-empty heaps unsafe { self.heap.data.get_unchecked_mut(0) } } @@ -398,10 +397,11 @@ impl BinaryHeap { /// /// # Time complexity /// - /// Cost is *O*(1) in the worst case. + /// If the item is modified then the worst case time complexity is *O*(log(*n*)), + /// otherwise it's *O*(1). #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option> { - if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: true }) } + if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: false }) } } /// Removes the greatest item from the binary heap and returns it, or `None` if it @@ -617,7 +617,7 @@ impl BinaryHeap { #[inline(always)] fn log2_fast(x: usize) -> usize { - 8 * size_of::() - (x.leading_zeros() as usize) - 1 + (usize::BITS - x.leading_zeros() - 1) as usize } // `rebuild` takes O(len1 + len2) operations @@ -802,7 +802,7 @@ impl BinaryHeap { /// heap.push(4); /// ``` /// - /// [`reserve`]: #method.reserve + /// [`reserve`]: BinaryHeap::reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.data.reserve_exact(additional); @@ -1057,11 +1057,10 @@ impl Drop for Hole<'_, T> { /// An iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`iter`] method on [`BinaryHeap`]. See its +/// This `struct` is created by [`BinaryHeap::iter()`]. See its /// documentation for more. /// -/// [`iter`]: struct.BinaryHeap.html#method.iter -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`iter`]: BinaryHeap::iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { iter: slice::Iter<'a, T>, @@ -1122,11 +1121,10 @@ impl FusedIterator for Iter<'_, T> {} /// An owning iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`] +/// This `struct` is created by [`BinaryHeap::into_iter()`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// -/// [`into_iter`]: struct.BinaryHeap.html#method.into_iter -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`into_iter`]: BinaryHeap::into_iter #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct IntoIter { @@ -1173,6 +1171,27 @@ impl ExactSizeIterator for IntoIter { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for IntoIter { + type Source = IntoIter; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut Self::Source { + self + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for IntoIter {} + +impl AsIntoIter for IntoIter { + type Item = I; + + fn as_into_iter(&mut self) -> &mut vec::IntoIter { + &mut self.iter + } +} + #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] #[derive(Clone, Debug)] pub struct IntoIterSorted { @@ -1206,11 +1225,10 @@ unsafe impl TrustedLen for IntoIterSorted {} /// A draining iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its +/// This `struct` is created by [`BinaryHeap::drain()`]. See its /// documentation for more. /// -/// [`drain`]: struct.BinaryHeap.html#method.drain -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`drain`]: BinaryHeap::drain #[stable(feature = "drain", since = "1.6.0")] #[derive(Debug)] pub struct Drain<'a, T: 'a> { @@ -1252,11 +1270,10 @@ impl FusedIterator for Drain<'_, T> {} /// A draining iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`drain_sorted`] method on [`BinaryHeap`]. See its +/// This `struct` is created by [`BinaryHeap::drain_sorted()`]. See its /// documentation for more. /// -/// [`drain_sorted`]: struct.BinaryHeap.html#method.drain_sorted -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`drain_sorted`]: BinaryHeap::drain_sorted #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] #[derive(Debug)] pub struct DrainSorted<'a, T: Ord> { @@ -1322,6 +1339,10 @@ impl From> for BinaryHeap { #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for Vec { + /// Converts a `BinaryHeap` into a `Vec`. + /// + /// This conversion requires no data movement or allocation, and has + /// constant time complexity. fn from(heap: BinaryHeap) -> Vec { heap.data } diff --git a/library/alloc/src/collections/btree/borrow.rs b/library/alloc/src/collections/btree/borrow.rs new file mode 100644 index 0000000000..016f139a50 --- /dev/null +++ b/library/alloc/src/collections/btree/borrow.rs @@ -0,0 +1,47 @@ +use core::marker::PhantomData; +use core::ptr::NonNull; + +/// Models a reborrow of some unique reference, when you know that the reborrow +/// and all its descendants (i.e., all pointers and references derived from it) +/// will not be used any more at some point, after which you want to use the +/// original unique reference again. +/// +/// The borrow checker usually handles this stacking of borrows for you, but +/// some control flows that accomplish this stacking are too complicated for +/// the compiler to follow. A `DormantMutRef` allows you to check borrowing +/// yourself, while still expressing its stacked nature, and encapsulating +/// the raw pointer code needed to do this without undefined behavior. +pub struct DormantMutRef<'a, T> { + ptr: NonNull, + _marker: PhantomData<&'a mut T>, +} + +unsafe impl<'a, T> Sync for DormantMutRef<'a, T> where &'a mut T: Sync {} +unsafe impl<'a, T> Send for DormantMutRef<'a, T> where &'a mut T: Send {} + +impl<'a, T> DormantMutRef<'a, T> { + /// Capture a unique borrow, and immediately reborrow it. For the compiler, + /// the lifetime of the new reference is the same as the lifetime of the + /// original reference, but you promise to use it for a shorter period. + pub fn new(t: &'a mut T) -> (&'a mut T, Self) { + let ptr = NonNull::from(t); + // SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose + // only this reference, so it is unique. + let new_ref = unsafe { &mut *ptr.as_ptr() }; + (new_ref, Self { ptr, _marker: PhantomData }) + } + + /// Revert to the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn awaken(self) -> &'a mut T { + // SAFETY: our own safety conditions imply this reference is again unique. + unsafe { &mut *self.ptr.as_ptr() } + } +} + +#[cfg(test)] +mod tests; diff --git a/library/alloc/src/collections/btree/borrow/tests.rs b/library/alloc/src/collections/btree/borrow/tests.rs new file mode 100644 index 0000000000..56a8434fc7 --- /dev/null +++ b/library/alloc/src/collections/btree/borrow/tests.rs @@ -0,0 +1,19 @@ +use super::DormantMutRef; + +#[test] +fn test_borrow() { + let mut data = 1; + let mut stack = vec![]; + let mut rr = &mut data; + for factor in [2, 3, 7].iter() { + let (r, dormant_r) = DormantMutRef::new(rr); + rr = r; + assert_eq!(*rr, 1); + stack.push((factor, dormant_r)); + } + while let Some((factor, dormant_r)) = stack.pop() { + let r = unsafe { dormant_r.awaken() }; + *r *= factor; + } + assert_eq!(data, 42); +} diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index f8729c33c6..2b244a04d2 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -5,10 +5,10 @@ use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, FusedIterator, Peekable}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; -use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, RangeBounds}; use core::ptr; +use super::borrow::DormantMutRef; use super::node::{self, marker, ForceResult::*, Handle, InsertResult::*, NodeRef}; use super::search::{self, SearchResult::*}; use super::unwrap_unchecked; @@ -47,7 +47,6 @@ use UnderflowResult::*; /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. /// -/// [`Ord`]: core::cmp::Ord /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell /// @@ -93,9 +92,10 @@ use UnderflowResult::*; /// } /// ``` /// -/// `BTreeMap` also implements an [`Entry API`](#method.entry), which allows -/// for more complex methods of getting, setting, updating and removing keys and -/// their values: +/// `BTreeMap` also implements an [`Entry API`], which allows for more complex +/// methods of getting, setting, updating and removing keys and their values: +/// +/// [`Entry API`]: BTreeMap::entry /// /// ``` /// use std::collections::BTreeMap; @@ -229,24 +229,23 @@ where } fn take(&mut self, key: &Q) -> Option { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); match search::search_tree(root_node, key) { - Found(handle) => Some( - OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData } - .remove_kv() - .0, - ), + Found(handle) => { + Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_kv().0) + } GoDown(_) => None, } } fn replace(&mut self, key: K) -> Option { - let root = Self::ensure_is_owned(&mut self.root); - match search::search_tree::, K, (), K>(root.node_as_mut(), &key) { + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut(); + match search::search_tree::, K, (), K>(root_node, &key) { Found(handle) => Some(mem::replace(handle.into_key_mut(), key)), GoDown(handle) => { - VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData } - .insert(()); + VacantEntry { key, handle, dormant_map, _marker: PhantomData }.insert(()); None } } @@ -298,14 +297,23 @@ pub struct IntoIter { length: usize, } -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl IntoIter { + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { let range = Range { front: self.front.as_ref().map(|f| f.reborrow()), back: self.back.as_ref().map(|b| b.reborrow()), }; - f.debug_list().entries(range).finish() + + Iter { range: range, length: self.length } + } +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() } } @@ -352,11 +360,17 @@ impl fmt::Debug for Values<'_, K, V> { /// /// [`values_mut`]: BTreeMap::values_mut #[stable(feature = "map_values_mut", since = "1.10.0")] -#[derive(Debug)] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } +#[stable(feature = "map_values_mut", since = "1.10.0")] +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() + } +} + /// An owning iterator over the keys of a `BTreeMap`. /// /// This `struct` is created by the [`into_keys`] method on [`BTreeMap`]. @@ -364,11 +378,17 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// /// [`into_keys`]: BTreeMap::into_keys #[unstable(feature = "map_into_keys_values", issue = "75294")] -#[derive(Debug)] pub struct IntoKeys { inner: IntoIter, } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish() + } +} + /// An owning iterator over the values of a `BTreeMap`. /// /// This `struct` is created by the [`into_values`] method on [`BTreeMap`]. @@ -376,11 +396,17 @@ pub struct IntoKeys { /// /// [`into_values`]: BTreeMap::into_values #[unstable(feature = "map_into_keys_values", issue = "75294")] -#[derive(Debug)] pub struct IntoValues { inner: IntoIter, } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() + } +} + /// An iterator over a sub-range of entries in a `BTreeMap`. /// /// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its @@ -408,8 +434,8 @@ impl fmt::Debug for Range<'_, K, V> { /// [`range_mut`]: BTreeMap::range_mut #[stable(feature = "btree_range", since = "1.17.0")] pub struct RangeMut<'a, K: 'a, V: 'a> { - front: Option, K, V, marker::Leaf>, marker::Edge>>, - back: Option, K, V, marker::Leaf>, marker::Edge>>, + front: Option, K, V, marker::Leaf>, marker::Edge>>, + back: Option, K, V, marker::Leaf>, marker::Edge>>, // Be invariant in `K` and `V` _marker: PhantomData<&'a mut (K, V)>, @@ -454,13 +480,11 @@ impl Debug for Entry<'_, K, V> { /// A view into a vacant entry in a `BTreeMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { key: K, handle: Handle, K, V, marker::Leaf>, marker::Edge>, - length: &'a mut usize, + dormant_map: DormantMutRef<'a, BTreeMap>, // Be invariant in `K` and `V` _marker: PhantomData<&'a mut (K, V)>, @@ -475,13 +499,10 @@ impl Debug for VacantEntry<'_, K, V> { /// A view into an occupied entry in a `BTreeMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, - - length: &'a mut usize, + dormant_map: DormantMutRef<'a, BTreeMap>, // Be invariant in `K` and `V` _marker: PhantomData<&'a mut (K, V)>, @@ -645,13 +666,10 @@ impl BTreeMap { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn first_entry(&mut self) -> Option> { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); let kv = root_node.first_leaf_edge().right_kv().ok()?; - Some(OccupiedEntry { - handle: kv.forget_node_type(), - length: &mut self.length, - _marker: PhantomData, - }) + Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData }) } /// Removes and returns the first element in the map. @@ -722,13 +740,10 @@ impl BTreeMap { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn last_entry(&mut self) -> Option> { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); let kv = root_node.last_leaf_edge().left_kv().ok()?; - Some(OccupiedEntry { - handle: kv.forget_node_type(), - length: &mut self.length, - _marker: PhantomData, - }) + Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData }) } /// Removes and returns the last element in the map. @@ -902,12 +917,12 @@ impl BTreeMap { K: Borrow, Q: Ord, { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); match search::search_tree(root_node, key) { - Found(handle) => Some( - OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData } - .remove_entry(), - ), + Found(handle) => { + Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_entry()) + } GoDown(_) => None, } } @@ -999,7 +1014,7 @@ impl BTreeMap { R: RangeBounds, { if let Some(root) = &self.root { - let (f, b) = range_search(root.node_as_ref(), range); + let (f, b) = root.node_as_ref().range_search(range); Range { front: Some(f), back: Some(b) } } else { @@ -1045,7 +1060,7 @@ impl BTreeMap { R: RangeBounds, { if let Some(root) = &mut self.root { - let (f, b) = range_search(root.node_as_mut(), range); + let (f, b) = root.node_as_valmut().range_search(range); RangeMut { front: Some(f), back: Some(b), _marker: PhantomData } } else { @@ -1074,13 +1089,12 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { // FIXME(@porglezomp) Avoid allocating if we don't insert - let root = Self::ensure_is_owned(&mut self.root); - match search::search_tree(root.node_as_mut(), &key) { - Found(handle) => { - Occupied(OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData }) - } + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut(); + match search::search_tree(root_node, &key) { + Found(handle) => Occupied(OccupiedEntry { handle, dormant_map, _marker: PhantomData }), GoDown(handle) => { - Vacant(VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData }) + Vacant(VacantEntry { key, handle, dormant_map, _marker: PhantomData }) } } } @@ -1285,9 +1299,17 @@ impl BTreeMap { } pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V> { - let root_node = self.root.as_mut().map(|r| r.node_as_mut()); - let front = root_node.map(|rn| rn.first_leaf_edge()); - DrainFilterInner { length: &mut self.length, cur_leaf_edge: front } + if let Some(root) = self.root.as_mut() { + let (root, dormant_root) = DormantMutRef::new(root); + let front = root.node_as_mut().first_leaf_edge(); + DrainFilterInner { + length: &mut self.length, + dormant_root: Some(dormant_root), + cur_leaf_edge: Some(front), + } + } else { + DrainFilterInner { length: &mut self.length, dormant_root: None, cur_leaf_edge: None } + } } /// Creates a consuming iterator visiting all the keys, in sorted order. @@ -1470,6 +1492,14 @@ impl ExactSizeIterator for IterMut<'_, K, V> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IterMut<'_, K, V> {} +impl<'a, K, V> IterMut<'a, K, V> { + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { range: self.range.iter(), length: self.length } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeMap { type Item = (K, V); @@ -1478,7 +1508,7 @@ impl IntoIterator for BTreeMap { fn into_iter(self) -> IntoIter { let mut me = ManuallyDrop::new(self); if let Some(root) = me.root.take() { - let (f, b) = full_range_search(root.into_ref()); + let (f, b) = root.into_ref().full_range(); IntoIter { front: Some(f), back: Some(b), length: me.length } } else { @@ -1672,6 +1702,9 @@ where /// of the predicate, thus also serving for BTreeSet::DrainFilter. pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> { length: &'a mut usize, + // dormant_root is wrapped in an Option to be able to `take` it. + dormant_root: Option>>, + // cur_leaf_edge is wrapped in an Option because maps without root lack a leaf edge. cur_leaf_edge: Option, K, V, marker::Leaf>, marker::Edge>>, } @@ -1717,7 +1750,7 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { /// Allow Debug implementations to predict the next element. pub(super) fn peek(&self) -> Option<(&K, &V)> { let edge = self.cur_leaf_edge.as_ref()?; - edge.reborrow().next_kv().ok().map(|kv| kv.into_kv()) + edge.reborrow().next_kv().ok().map(Handle::into_kv) } /// Implementation of a typical `DrainFilter::next` method, given the predicate. @@ -1729,7 +1762,13 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { let (k, v) = kv.kv_mut(); if pred(k, v) { *self.length -= 1; - let (kv, pos) = kv.remove_kv_tracking(); + let (kv, pos) = kv.remove_kv_tracking(|| { + // SAFETY: we will touch the root in a way that will not + // invalidate the position returned. + let root = unsafe { self.dormant_root.take().unwrap().awaken() }; + root.pop_internal_level(); + self.dormant_root = Some(DormantMutRef::new(root).1); + }); self.cur_leaf_edge = Some(pos); return Some(kv); } @@ -1942,9 +1981,18 @@ impl<'a, K, V> RangeMut<'a, K, V> { self.front == self.back } - unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() } } + + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Range<'_, K, V> { + Range { + front: self.front.as_ref().map(|f| f.reborrow()), + back: self.back.as_ref().map(|b| b.reborrow()), + } + } } #[stable(feature = "btree_range", since = "1.17.0")] @@ -1963,7 +2011,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { impl FusedIterator for RangeMut<'_, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { - unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() } } } @@ -2073,119 +2121,6 @@ where } } -/// Finds the leaf edges delimiting a specified range in or underneath a node. -fn range_search>( - root: NodeRef, - range: R, -) -> ( - Handle, marker::Edge>, - Handle, marker::Edge>, -) -where - Q: Ord, - K: Borrow, -{ - match (range.start_bound(), range.end_bound()) { - (Excluded(s), Excluded(e)) if s == e => { - panic!("range start and end are equal and excluded in BTreeMap") - } - (Included(s) | Excluded(s), Included(e) | Excluded(e)) if s > e => { - panic!("range start is greater than range end in BTreeMap") - } - _ => {} - }; - - // We duplicate the root NodeRef here -- we will never access it in a way - // that overlaps references obtained from the root. - let mut min_node = unsafe { ptr::read(&root) }; - let mut max_node = root; - let mut min_found = false; - let mut max_found = false; - - loop { - let front = match (min_found, range.start_bound()) { - (false, Included(key)) => match search::search_node(min_node, key) { - Found(kv) => { - min_found = true; - kv.left_edge() - } - GoDown(edge) => edge, - }, - (false, Excluded(key)) => match search::search_node(min_node, key) { - Found(kv) => { - min_found = true; - kv.right_edge() - } - GoDown(edge) => edge, - }, - (true, Included(_)) => min_node.last_edge(), - (true, Excluded(_)) => min_node.first_edge(), - (_, Unbounded) => min_node.first_edge(), - }; - - let back = match (max_found, range.end_bound()) { - (false, Included(key)) => match search::search_node(max_node, key) { - Found(kv) => { - max_found = true; - kv.right_edge() - } - GoDown(edge) => edge, - }, - (false, Excluded(key)) => match search::search_node(max_node, key) { - Found(kv) => { - max_found = true; - kv.left_edge() - } - GoDown(edge) => edge, - }, - (true, Included(_)) => max_node.first_edge(), - (true, Excluded(_)) => max_node.last_edge(), - (_, Unbounded) => max_node.last_edge(), - }; - - if front.partial_cmp(&back) == Some(Ordering::Greater) { - panic!("Ord is ill-defined in BTreeMap range"); - } - match (front.force(), back.force()) { - (Leaf(f), Leaf(b)) => { - return (f, b); - } - (Internal(min_int), Internal(max_int)) => { - min_node = min_int.descend(); - max_node = max_int.descend(); - } - _ => unreachable!("BTreeMap has different depths"), - }; - } -} - -/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound. -fn full_range_search( - root: NodeRef, -) -> ( - Handle, marker::Edge>, - Handle, marker::Edge>, -) { - // We duplicate the root NodeRef here -- we will never access it in a way - // that overlaps references obtained from the root. - let mut min_node = unsafe { ptr::read(&root) }; - let mut max_node = root; - loop { - let front = min_node.first_edge(); - let back = max_node.last_edge(); - match (front.force(), back.force()) { - (Leaf(f), Leaf(b)) => { - return (f, b); - } - (Internal(min_int), Internal(max_int)) => { - min_node = min_int.descend(); - max_node = max_int.descend(); - } - _ => unreachable!("BTreeMap has different depths"), - }; - } -} - impl BTreeMap { /// Gets an iterator over the entries of the map, sorted by key. /// @@ -2211,7 +2146,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, K, V> { if let Some(root) = &self.root { - let (f, b) = full_range_search(root.node_as_ref()); + let (f, b) = root.node_as_ref().full_range(); Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length } } else { @@ -2243,7 +2178,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { if let Some(root) = &mut self.root { - let (f, b) = full_range_search(root.node_as_mut()); + let (f, b) = root.node_as_valmut().full_range(); IterMut { range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }, @@ -2570,13 +2505,20 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { - *self.length += 1; - let out_ptr = match self.handle.insert_recursing(self.key, value) { - (Fit(_), val_ptr) => val_ptr, + (Fit(_), val_ptr) => { + // Safety: We have consumed self.handle and the handle returned. + let map = unsafe { self.dormant_map.awaken() }; + map.length += 1; + val_ptr + } (Split(ins), val_ptr) => { - let root = ins.left.into_root_mut(); + drop(ins.left); + // Safety: We have consumed self.handle and the reference returned. + let map = unsafe { self.dormant_map.awaken() }; + let root = map.root.as_mut().unwrap(); root.push_internal_level().push(ins.k, ins.v, ins.right); + map.length += 1; val_ptr } }; @@ -2652,7 +2594,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// If you need a reference to the `OccupiedEntry` that may outlive the /// destruction of the `Entry` value, see [`into_mut`]. /// - /// [`into_mut`]: #method.into_mut + /// [`into_mut`]: OccupiedEntry::into_mut /// /// # Examples /// @@ -2682,7 +2624,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. /// - /// [`get_mut`]: #method.get_mut + /// [`get_mut`]: OccupiedEntry::get_mut /// /// # Examples /// @@ -2750,9 +2692,15 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { // Body of `remove_entry`, separate to keep the above implementations short. fn remove_kv(self) -> (K, V) { - *self.length -= 1; - - let (old_kv, _) = self.handle.remove_kv_tracking(); + let mut emptied_internal_root = false; + let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true); + // SAFETY: we consumed the intermediate root borrow, `self.handle`. + let map = unsafe { self.dormant_map.awaken() }; + map.length -= 1; + if emptied_internal_root { + let root = map.root.as_mut().unwrap(); + root.pop_internal_level(); + } old_kv } } @@ -2760,8 +2708,9 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInternal>, marker::KV> { /// Removes a key/value-pair from the map, and returns that pair, as well as /// the leaf edge corresponding to that former pair. - fn remove_kv_tracking( + fn remove_kv_tracking( self, + handle_emptied_internal_root: F, ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { let (old_kv, mut pos, was_internal) = match self.force() { Leaf(leaf) => { @@ -2814,7 +2763,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter // The parent that was just emptied must be the root, // because nodes on a lower level would not have been // left with a single child. - parent.into_root_mut().pop_internal_level(); + handle_emptied_internal_root(); break; } else { cur_node = parent.forget_type(); @@ -2826,7 +2775,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter if stole_from_left && at_leaf { // SAFETY: This is safe since we just added an element to our node. unsafe { - pos.next_unchecked(); + pos.move_next_unchecked(); } } break; @@ -2910,8 +2859,8 @@ enum UnderflowResult<'a, K, V> { Stole(bool), } -fn handle_underfull_node( - node: NodeRef, K, V, marker::LeafOrInternal>, +fn handle_underfull_node<'a, K: 'a, V: 'a>( + node: NodeRef, K, V, marker::LeafOrInternal>, ) -> UnderflowResult<'_, K, V> { let parent = match node.ascend() { Ok(parent) => parent, diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index eb8d86b969..8018514fa1 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -77,7 +77,8 @@ impl<'a, K: 'a, V: 'a> BTreeMap { let min_len = if is_root { 0 } else { node::MIN_LEN }; assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); - for &key in node.keys() { + for idx in 0..node.len() { + let key = *unsafe { node.key_at(idx) }; checker.is_ascending(key); } leaf_length += node.len(); @@ -87,6 +88,11 @@ impl<'a, K: 'a, V: 'a> BTreeMap { let min_len = if is_root { 1 } else { node::MIN_LEN }; assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); + for idx in 0..=node.len() { + let edge = unsafe { node::Handle::new_edge(node, idx) }; + assert!(edge.descend().ascend().ok().unwrap() == edge); + } + internal_length += node.len(); } Position::InternalKV(kv) => { @@ -120,7 +126,13 @@ impl<'a, K: 'a, V: 'a> BTreeMap { Position::Leaf(leaf) => { let depth = root_node.height(); let indent = " ".repeat(depth); - result += &format!("\n{}{:?}", indent, leaf.keys()) + result += &format!("\n{}", indent); + for idx in 0..leaf.len() { + if idx > 0 { + result += ", "; + } + result += &format!("{:?}", unsafe { leaf.key_at(idx) }); + } } Position::Internal(_) => {} Position::InternalKV(kv) => { @@ -432,7 +444,6 @@ fn test_iter_mut_mutation() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_values_mut() { let mut a: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)).collect(); test_all_refs(&mut 13, a.values_mut()); @@ -455,7 +466,6 @@ fn test_values_mut_mutation() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_iter_entering_root_twice() { let mut map: BTreeMap<_, _> = (0..2).map(|i| (i, i)).collect(); let mut it = map.iter_mut(); @@ -471,7 +481,6 @@ fn test_iter_entering_root_twice() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_iter_descending_to_same_node_twice() { let mut map: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)).collect(); let mut it = map.iter_mut(); @@ -515,7 +524,6 @@ fn test_iter_mixed() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_iter_min_max() { let mut a = BTreeMap::new(); assert_eq!(a.iter().min(), None); @@ -1415,6 +1423,146 @@ fn test_variance() { } } +#[test] +#[allow(dead_code)] +fn test_sync() { + fn map(v: &BTreeMap) -> impl Sync + '_ { + v + } + + fn into_iter(v: BTreeMap) -> impl Sync { + v.into_iter() + } + + fn into_keys(v: BTreeMap) -> impl Sync { + v.into_keys() + } + + fn into_values(v: BTreeMap) -> impl Sync { + v.into_values() + } + + fn drain_filter(v: &mut BTreeMap) -> impl Sync + '_ { + v.drain_filter(|_, _| false) + } + + fn iter(v: &BTreeMap) -> impl Sync + '_ { + v.iter() + } + + fn iter_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.iter_mut() + } + + fn keys(v: &BTreeMap) -> impl Sync + '_ { + v.keys() + } + + fn values(v: &BTreeMap) -> impl Sync + '_ { + v.values() + } + + fn values_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.values_mut() + } + + fn range(v: &BTreeMap) -> impl Sync + '_ { + v.range(..) + } + + fn range_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.range_mut(..) + } + + fn entry(v: &mut BTreeMap) -> impl Sync + '_ { + v.entry(Default::default()) + } + + fn occupied_entry(v: &mut BTreeMap) -> impl Sync + '_ { + match v.entry(Default::default()) { + Occupied(entry) => entry, + _ => unreachable!(), + } + } + + fn vacant_entry(v: &mut BTreeMap) -> impl Sync + '_ { + match v.entry(Default::default()) { + Vacant(entry) => entry, + _ => unreachable!(), + } + } +} + +#[test] +#[allow(dead_code)] +fn test_send() { + fn map(v: BTreeMap) -> impl Send { + v + } + + fn into_iter(v: BTreeMap) -> impl Send { + v.into_iter() + } + + fn into_keys(v: BTreeMap) -> impl Send { + v.into_keys() + } + + fn into_values(v: BTreeMap) -> impl Send { + v.into_values() + } + + fn drain_filter(v: &mut BTreeMap) -> impl Send + '_ { + v.drain_filter(|_, _| false) + } + + fn iter(v: &BTreeMap) -> impl Send + '_ { + v.iter() + } + + fn iter_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.iter_mut() + } + + fn keys(v: &BTreeMap) -> impl Send + '_ { + v.keys() + } + + fn values(v: &BTreeMap) -> impl Send + '_ { + v.values() + } + + fn values_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.values_mut() + } + + fn range(v: &BTreeMap) -> impl Send + '_ { + v.range(..) + } + + fn range_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.range_mut(..) + } + + fn entry(v: &mut BTreeMap) -> impl Send + '_ { + v.entry(Default::default()) + } + + fn occupied_entry(v: &mut BTreeMap) -> impl Send + '_ { + match v.entry(Default::default()) { + Occupied(entry) => entry, + _ => unreachable!(), + } + } + + fn vacant_entry(v: &mut BTreeMap) -> impl Send + '_ { + match v.entry(Default::default()) { + Vacant(entry) => entry, + _ => unreachable!(), + } + } +} + #[test] fn test_occupied_entry_key() { let mut a = BTreeMap::new(); @@ -1703,3 +1851,17 @@ fn test_into_values() { assert!(values.contains(&'b')); assert!(values.contains(&'c')); } + +#[test] +fn test_insert_remove_intertwined() { + let loops = if cfg!(miri) { 100 } else { 1_000_000 }; + let mut map = BTreeMap::new(); + let mut i = 1; + for _ in 0..loops { + i = (i + 421) & 0xFF; + map.insert(i, i); + map.remove(&(0xFF - i)); + } + + map.check(); +} diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index 6c8a588eb5..ecbdacda4b 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -1,3 +1,4 @@ +mod borrow; pub mod map; mod navigate; mod node; @@ -13,6 +14,9 @@ trait Recover { fn replace(&mut self, key: Self::Key) -> Option; } +/// Same purpose as `Option::unwrap` but doesn't always guarantee a panic +/// if the option contains no value. +/// SAFETY: the caller must ensure that the option contains a value. #[inline(always)] pub unsafe fn unwrap_unchecked(val: Option) -> T { val.unwrap_or_else(|| { diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index b7b66ac7ce..55ce7d2754 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -1,10 +1,210 @@ +use core::borrow::Borrow; +use core::cmp::Ordering; use core::intrinsics; use core::mem; +use core::ops::Bound::{Excluded, Included, Unbounded}; +use core::ops::RangeBounds; use core::ptr; use super::node::{marker, ForceResult::*, Handle, NodeRef}; +use super::search::{self, SearchResult}; use super::unwrap_unchecked; +/// Finds the leaf edges delimiting a specified range in or underneath a node. +fn range_search( + root1: NodeRef, + root2: NodeRef, + range: R, +) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, +) +where + Q: ?Sized + Ord, + K: Borrow, + R: RangeBounds, +{ + match (range.start_bound(), range.end_bound()) { + (Excluded(s), Excluded(e)) if s == e => { + panic!("range start and end are equal and excluded in BTreeMap") + } + (Included(s) | Excluded(s), Included(e) | Excluded(e)) if s > e => { + panic!("range start is greater than range end in BTreeMap") + } + _ => {} + }; + + let mut min_node = root1; + let mut max_node = root2; + let mut min_found = false; + let mut max_found = false; + + loop { + let front = match (min_found, range.start_bound()) { + (false, Included(key)) => match search::search_node(min_node, key) { + SearchResult::Found(kv) => { + min_found = true; + kv.left_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (false, Excluded(key)) => match search::search_node(min_node, key) { + SearchResult::Found(kv) => { + min_found = true; + kv.right_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (true, Included(_)) => min_node.last_edge(), + (true, Excluded(_)) => min_node.first_edge(), + (_, Unbounded) => min_node.first_edge(), + }; + + let back = match (max_found, range.end_bound()) { + (false, Included(key)) => match search::search_node(max_node, key) { + SearchResult::Found(kv) => { + max_found = true; + kv.right_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (false, Excluded(key)) => match search::search_node(max_node, key) { + SearchResult::Found(kv) => { + max_found = true; + kv.left_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (true, Included(_)) => max_node.first_edge(), + (true, Excluded(_)) => max_node.last_edge(), + (_, Unbounded) => max_node.last_edge(), + }; + + if front.partial_cmp(&back) == Some(Ordering::Greater) { + panic!("Ord is ill-defined in BTreeMap range"); + } + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + } + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + } + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + +/// Equivalent to `range_search(k, v, ..)` but without the `Ord` bound. +fn full_range( + root1: NodeRef, + root2: NodeRef, +) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, +) { + let mut min_node = root1; + let mut max_node = root2; + loop { + let front = min_node.first_edge(); + let back = max_node.last_edge(); + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + } + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + } + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { + /// Creates a pair of leaf edges delimiting a specified range in or underneath a node. + pub fn range_search( + self, + range: R, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) + where + Q: ?Sized + Ord, + K: Borrow, + R: RangeBounds, + { + range_search(self, self, range) + } + + /// Returns (self.first_leaf_edge(), self.last_leaf_edge()), but more efficiently. + pub fn full_range( + self, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) { + full_range(self, self) + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { + /// Splits a unique reference into a pair of leaf edges delimiting a specified range. + /// The result are non-unique references allowing (some) mutation, which must be used + /// carefully. + pub fn range_search( + self, + range: R, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) + where + Q: ?Sized + Ord, + K: Borrow, + R: RangeBounds, + { + // We duplicate the root NodeRef here -- we will never visit the same KV + // twice, and never end up with overlapping value references. + let self2 = unsafe { ptr::read(&self) }; + range_search(self, self2, range) + } + + /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. + /// The results are non-unique references allowing mutation (of values only), so must be used + /// with care. + pub fn full_range( + self, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) { + // We duplicate the root NodeRef here -- we will never visit the same KV + // twice, and never end up with overlapping value references. + let self2 = unsafe { ptr::read(&self) }; + full_range(self, self2) + } +} + +impl NodeRef { + /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. + /// The results are non-unique references allowing massively destructive mutation, so must be + /// used with the utmost care. + pub fn full_range( + self, + ) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, + ) { + // We duplicate the root NodeRef here -- we will never access it in a way + // that overlaps references obtained from the root. + let self2 = unsafe { ptr::read(&self) }; + full_range(self, self2) + } +} + impl Handle, marker::Edge> { /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the right side, which is either in the same leaf node or in an ancestor node. @@ -18,7 +218,7 @@ impl Handle, marker::E let mut edge = self.forget_node_type(); loop { edge = match edge.right_kv() { - Ok(internal_kv) => return Ok(internal_kv), + Ok(kv) => return Ok(kv), Err(last_edge) => match last_edge.into_node().ascend() { Ok(parent_edge) => parent_edge.forget_node_type(), Err(root) => return Err(root), @@ -39,7 +239,7 @@ impl Handle, marker::E let mut edge = self.forget_node_type(); loop { edge = match edge.left_kv() { - Ok(internal_kv) => return Ok(internal_kv), + Ok(kv) => return Ok(kv), Err(last_edge) => match last_edge.into_node().ascend() { Ok(parent_edge) => parent_edge.forget_node_type(), Err(root) => return Err(root), @@ -75,12 +275,13 @@ impl Handle, marke macro_rules! def_next_kv_uncheched_dealloc { { unsafe fn $name:ident : $adjacent_kv:ident } => { /// Given a leaf edge handle into an owned tree, returns a handle to the next KV, - /// while deallocating any node left behind. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the last one in the tree. - /// - The node pointed at by the given handle, and its ancestors, may be deallocated, - /// while the reference to those nodes in the surviving ancestors is left dangling; - /// thus using the returned handle to navigate further is dangerous. + /// while deallocating any node left behind yet leaving the corresponding edge + /// in its parent node dangling. + /// + /// # Safety + /// - The leaf edge must not be the last one in the direction travelled. + /// - The node carrying the next KV returned must not have been deallocated by a + /// previous call on any handle obtained for this tree. unsafe fn $name ( leaf_edge: Handle, marker::Edge>, ) -> Handle, marker::KV> { @@ -103,6 +304,15 @@ macro_rules! def_next_kv_uncheched_dealloc { def_next_kv_uncheched_dealloc! {unsafe fn next_kv_unchecked_dealloc: right_kv} def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv} +/// This replaces the value behind the `v` unique reference by calling the +/// relevant function. +/// +/// If a panic occurs in the `change` closure, the entire process will be aborted. +#[inline] +fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { + replace(v, |value| (change(value), ())) +} + /// This replaces the value behind the `v` unique reference by calling the /// relevant function, and returns a result obtained along the way. /// @@ -128,7 +338,9 @@ fn replace(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns references to the /// key and value in between. - /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree. + /// + /// # Safety + /// There must be another KV in the direction travelled. pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { replace(self, |leaf_edge| { let kv = leaf_edge.next_kv(); @@ -139,7 +351,9 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Ed /// Moves the leaf edge handle to the previous leaf edge and returns references to the /// key and value in between. - /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree. + /// + /// # Safety + /// There must be another KV in the direction travelled. pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { replace(self, |leaf_edge| { let kv = leaf_edge.next_back_kv(); @@ -149,53 +363,65 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Ed } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns references to the /// key and value in between. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the last one in the tree. - /// - Using the updated handle may well invalidate the returned references. - pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + /// + /// # Safety + /// There must be another KV in the direction travelled. + pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { let kv = replace(self, |leaf_edge| { let kv = leaf_edge.next_kv(); let kv = unsafe { unwrap_unchecked(kv.ok()) }; (unsafe { ptr::read(&kv) }.next_leaf_edge(), kv) }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + // Doing this last is faster, according to benchmarks. + kv.into_kv_valmut() } /// Moves the leaf edge handle to the previous leaf and returns references to the /// key and value in between. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the first one in the tree. - /// - Using the updated handle may well invalidate the returned references. - pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + /// + /// # Safety + /// There must be another KV in the direction travelled. + pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { let kv = replace(self, |leaf_edge| { let kv = leaf_edge.next_back_kv(); let kv = unsafe { unwrap_unchecked(kv.ok()) }; (unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv) }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + // Doing this last is faster, according to benchmarks. + kv.into_kv_valmut() + } +} + +impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { + /// Moves the leaf edge handle to the next leaf edge. + /// + /// # Safety + /// There must be another KV in the direction travelled. + pub unsafe fn move_next_unchecked(&mut self) { + take_mut(self, |leaf_edge| { + let kv = leaf_edge.next_kv(); + let kv = unsafe { unwrap_unchecked(kv.ok()) }; + kv.next_leaf_edge() + }) } } impl Handle, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns the key and value - /// in between, while deallocating any node left behind. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the last one in the tree - /// and is not a handle previously resulting from counterpart `next_back_unchecked`. - /// - Further use of the updated leaf edge handle is very dangerous. In particular, - /// if the leaf edge is the last edge of a node, that node and possibly ancestors - /// will be deallocated, while the reference to those nodes in the surviving ancestor - /// is left dangling. - /// The only safe way to proceed with the updated handle is to compare it, drop it, - /// call this method again subject to both preconditions listed in the first point, - /// or call counterpart `next_back_unchecked` subject to its preconditions. + /// in between, deallocating any node left behind while leaving the corresponding + /// edge in its parent node dangling. + /// + /// # Safety + /// - There must be another KV in the direction travelled. + /// - That KV was not previously returned by counterpart `next_back_unchecked` + /// on any copy of the handles being used to traverse the tree. + /// + /// The only safe way to proceed with the updated handle is to compare it, drop it, + /// call this method again subject to its safety conditions, or call counterpart + /// `next_back_unchecked` subject to its safety conditions. pub unsafe fn next_unchecked(&mut self) -> (K, V) { replace(self, |leaf_edge| { let kv = unsafe { next_kv_unchecked_dealloc(leaf_edge) }; @@ -205,18 +431,18 @@ impl Handle, marker::Edge> { }) } - /// Moves the leaf edge handle to the previous leaf edge and returns the key - /// and value in between, while deallocating any node left behind. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the first one in the tree - /// and is not a handle previously resulting from counterpart `next_unchecked`. - /// - Further use of the updated leaf edge handle is very dangerous. In particular, - /// if the leaf edge is the first edge of a node, that node and possibly ancestors - /// will be deallocated, while the reference to those nodes in the surviving ancestor - /// is left dangling. - /// The only safe way to proceed with the updated handle is to compare it, drop it, - /// call this method again subject to both preconditions listed in the first point, - /// or call counterpart `next_unchecked` subject to its preconditions. + /// Moves the leaf edge handle to the previous leaf edge and returns the key and value + /// in between, deallocating any node left behind while leaving the corresponding + /// edge in its parent node dangling. + /// + /// # Safety + /// - There must be another KV in the direction travelled. + /// - That leaf edge was not previously returned by counterpart `next_unchecked` + /// on any copy of the handles being used to traverse the tree. + /// + /// The only safe way to proceed with the updated handle is to compare it, drop it, + /// call this method again subject to its safety conditions, or call counterpart + /// `next_unchecked` subject to its safety conditions. pub unsafe fn next_back_unchecked(&mut self) -> (K, V) { replace(self, |leaf_edge| { let kv = unsafe { next_back_kv_unchecked_dealloc(leaf_edge) }; diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index acc2ae7357..ba08f65f90 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -12,7 +12,7 @@ // edges: if height > 0 { // [Box>; 2 * B] // } else { () }, -// parent: *const Node, +// parent: Option>>, // parent_idx: u16, // len: u16, // } @@ -47,12 +47,10 @@ const KV_IDX_CENTER: usize = B - 1; const EDGE_IDX_LEFT_OF_CENTER: usize = B - 1; const EDGE_IDX_RIGHT_OF_CENTER: usize = B; -/// The underlying representation of leaf nodes. -#[repr(C)] +/// The underlying representation of leaf nodes and part of the representation of internal nodes. struct LeafNode { - /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. - /// This either points to an actual node or is null. - parent: *const InternalNode, + /// We want to be covariant in `K` and `V`. + parent: Option>>, /// This node's index into the parent node's `edges` array. /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`. @@ -60,9 +58,6 @@ struct LeafNode { parent_idx: MaybeUninit, /// The number of keys and values this node stores. - /// - /// This next to `parent_idx` to encourage the compiler to join `len` and - /// `parent_idx` into the same 32-bit word, reducing space overhead. len: u16, /// The arrays storing the actual data of the node. Only the first `len` elements of each @@ -78,9 +73,9 @@ impl LeafNode { LeafNode { // As a general policy, we leave fields uninitialized if they can be, as this should // be both slightly faster and easier to track in Valgrind. - keys: [MaybeUninit::UNINIT; CAPACITY], - vals: [MaybeUninit::UNINIT; CAPACITY], - parent: ptr::null(), + keys: MaybeUninit::uninit_array(), + vals: MaybeUninit::uninit_array(), + parent: None, parent_idx: MaybeUninit::uninit(), len: 0, } @@ -93,7 +88,9 @@ impl LeafNode { /// node, allowing code to act on leaf and internal nodes generically without having to even check /// which of the two a pointer is pointing at. This property is enabled by the use of `repr(C)`. #[repr(C)] +// gdb_providers.py uses this type name for introspection. struct InternalNode { + // gdb_providers.py uses this field name for introspection. data: LeafNode, /// The pointers to the children of this node. `len + 1` of these are considered @@ -111,7 +108,7 @@ impl InternalNode { /// `len` of 0), there must be one initialized and valid edge. This function does not set up /// such an edge. unsafe fn new() -> Self { - InternalNode { data: unsafe { LeafNode::new() }, edges: [MaybeUninit::UNINIT; 2 * B] } + InternalNode { data: unsafe { LeafNode::new() }, edges: MaybeUninit::uninit_array() } } } @@ -131,7 +128,7 @@ impl BoxedNode { } fn from_internal(node: Box>) -> Self { - BoxedNode { ptr: Box::into_unique(node).cast() } + BoxedNode { ptr: Unique::from(&mut Box::leak(node).data) } } unsafe fn from_ptr(ptr: NonNull>) -> Self { @@ -168,36 +165,25 @@ impl Root { /// Borrows and returns an immutable reference to the node owned by the root. pub fn node_as_ref(&self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: ptr::null(), - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } /// Borrows and returns a mutable reference to the node owned by the root. pub fn node_as_mut(&mut self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: self as *mut _, - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } + } + + pub fn node_as_valmut(&mut self) -> NodeRef, K, V, marker::LeafOrInternal> { + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } pub fn into_ref(self) -> NodeRef { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: ptr::null(), - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } - /// Adds a new internal node with a single edge, pointing to the previous root, and make that - /// new node the root. This increases the height by 1 and is the opposite of - /// `pop_internal_level`. + /// Adds a new internal node with a single edge pointing to the previous root node, + /// make that new node the root node, and return it. This increases the height by 1 + /// and is the opposite of `pop_internal_level`. pub fn push_internal_level(&mut self) -> NodeRef, K, V, marker::Internal> { let mut new_node = Box::new(unsafe { InternalNode::new() }); new_node.edges[0].write(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }); @@ -205,12 +191,8 @@ impl Root { self.node = BoxedNode::from_internal(new_node); self.height += 1; - let mut ret = NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: self as *mut _, - _marker: PhantomData, - }; + let mut ret = + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }; unsafe { ret.reborrow_mut().first_edge().correct_parent_link(); @@ -219,11 +201,15 @@ impl Root { ret } - /// Removes the internal root node, using its first child as the new root. - /// As it is intended only to be called when the root has only one child, - /// no cleanup is done on any of the other children of the root. + /// Removes the internal root node, using its first child as the new root node. + /// As it is intended only to be called when the root node has only one child, + /// no cleanup is done on any of the other children. /// This decreases the height by 1 and is the opposite of `push_internal_level`. - /// Panics if there is no internal level, i.e. if the root is a leaf. + /// + /// Requires exclusive access to the `Root` object but not to the root node; + /// it will not invalidate existing handles or references to the root node. + /// + /// Panics if there is no internal level, i.e., if the root node is a leaf. pub fn pop_internal_level(&mut self) { assert!(self.height > 0); @@ -235,9 +221,7 @@ impl Root { ) }; self.height -= 1; - unsafe { - (*self.node_as_mut().as_leaf_mut()).parent = ptr::null(); - } + self.node_as_mut().as_leaf_mut().parent = None; unsafe { Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); @@ -253,9 +237,12 @@ impl Root { /// A reference to a node. /// /// This type has a number of parameters that controls how it acts: -/// - `BorrowType`: This can be `Immut<'a>` or `Mut<'a>` for some `'a` or `Owned`. +/// - `BorrowType`: This can be `Immut<'a>`, `Mut<'a>` or `ValMut<'a>' for some `'a` +/// or `Owned`. /// When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`, /// when this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`, +/// when this is `ValMut<'a>`, the `NodeRef` acts as immutable with respect +/// to keys and tree structure, but allows mutable references to values, /// and when this is `Owned`, the `NodeRef` acts roughly like `Box`. /// - `K` and `V`: These control what types of things are stored in the nodes. /// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is @@ -266,8 +253,6 @@ pub struct NodeRef { /// The number of levels below the node. height: usize, node: NonNull>, - // `root` is null unless the borrow type is `Mut` - root: *const Root, _marker: PhantomData<(BorrowType, Type)>, } @@ -282,15 +267,31 @@ unsafe impl Sync for NodeRef Send for NodeRef, K, V, Type> {} unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef, K, V, Type> {} +unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef, K, V, Type> {} unsafe impl Send for NodeRef {} impl NodeRef { - fn as_internal(&self) -> &InternalNode { - unsafe { &*(self.node.as_ptr() as *mut InternalNode) } + /// Exposes the data of an internal node for reading. + /// + /// Returns a raw ptr to avoid invalidating other references to this node, + /// which is possible when BorrowType is marker::ValMut. + fn as_internal_ptr(&self) -> *const InternalNode { + self.node.as_ptr() as *const InternalNode } } impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// Exposes the data of an internal node for reading, + /// when we know we have exclusive access. + fn as_internal(&mut self) -> &InternalNode { + unsafe { &*self.as_internal_ptr() } + } +} + +impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// Exposes the data of an internal node for writing. + /// + /// We don't need to return a raw ptr because we have unique access to the entire node. fn as_internal_mut(&mut self) -> &mut InternalNode { unsafe { &mut *(self.node.as_ptr() as *mut InternalNode) } } @@ -303,7 +304,9 @@ impl NodeRef { /// Note that, despite being safe, calling this function can have the side effect /// of invalidating mutable references that unsafe code has created. pub fn len(&self) -> usize { - self.as_leaf().len as usize + // Crucially, we only access the `len` field here. If BorrowType is marker::ValMut, + // there might be outstanding mutable references to values that we must not invalidate. + unsafe { usize::from((*self.as_leaf_ptr()).len) } } /// Returns the height of this node in the whole tree. Zero height denotes the @@ -314,30 +317,54 @@ impl NodeRef { /// Temporarily takes out another, immutable reference to the same node. fn reborrow(&self) -> NodeRef, K, V, Type> { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } - /// Exposes the leaf "portion" of any leaf or internal node. + /// Exposes the leaf portion of any leaf or internal node. /// If the node is a leaf, this function simply opens up its data. /// If the node is an internal node, so not a leaf, it does have all the data a leaf has /// (header, keys and values), and this function exposes that. - fn as_leaf(&self) -> &LeafNode { + /// + /// Returns a raw ptr to avoid invalidating other references to this node, + /// which is possible when BorrowType is marker::ValMut. + fn as_leaf_ptr(&self) -> *const LeafNode { // The node must be valid for at least the LeafNode portion. // This is not a reference in the NodeRef type because we don't know if // it should be unique or shared. - unsafe { self.node.as_ref() } + self.node.as_ptr() } - /// Borrows a view into the keys stored in the node. - pub fn keys(&self) -> &[K] { - self.reborrow().into_key_slice() + /// Borrows a reference to one of the keys stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn key_at(&self, idx: usize) -> &K { + unsafe { self.reborrow().into_key_at(idx) } } - /// Borrows a view into the values stored in the node. - fn vals(&self) -> &[V] { - self.reborrow().into_val_slice() + /// Borrows a reference to one of the values stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn val_at(&self, idx: usize) -> &V { + unsafe { self.reborrow().into_val_at(idx) } } +} +impl NodeRef { + /// Borrows a reference to the contents of one of the edges that delimit + /// the elements of the node, without invalidating other references. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn edge_at(&self, idx: usize) -> &BoxedNode { + debug_assert!(idx <= self.len()); + let node = self.as_internal_ptr(); + unsafe { (*node).edges.get_unchecked(idx).assume_init_ref() } + } +} + +impl NodeRef { /// Finds the parent of the current node. Returns `Ok(handle)` if the current /// node actually has a parent, where `handle` points to the edge of the parent /// that points to the current node. Returns `Err(self)` if the current node has @@ -348,21 +375,21 @@ impl NodeRef { pub fn ascend( self, ) -> Result, marker::Edge>, Self> { - let parent_as_leaf = self.as_leaf().parent as *const LeafNode; - if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { - Ok(Handle { + // 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 = self.as_leaf_ptr(); + unsafe { (*leaf_ptr).parent } + .as_ref() + .map(|parent| Handle { node: NodeRef { height: self.height + 1, - node: non_zero, - root: self.root, + node: parent.cast(), _marker: PhantomData, }, - idx: unsafe { usize::from(*self.as_leaf().parent_idx.as_ptr()) }, + idx: unsafe { usize::from((*leaf_ptr).parent_idx.assume_init()) }, _marker: PhantomData, }) - } else { - Err(self) - } + .ok_or(self) } pub fn first_edge(self) -> Handle { @@ -389,6 +416,15 @@ impl NodeRef { } } +impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + /// Exposes the data of a leaf node for reading in an immutable tree. + fn into_leaf(self) -> &'a LeafNode { + // SAFETY: we can access the entire node freely and do no need raw pointers, + // because there can be no mutable references to this Immut tree. + unsafe { &(*self.as_leaf_ptr()) } + } +} + impl NodeRef { /// Similar to `ascend`, gets a reference to a node's parent node, but also /// deallocate the current node in the process. This is unsafe because the @@ -417,168 +453,208 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { /// Unsafely asserts to the compiler some static information about whether this /// node is a `Leaf` or an `Internal`. unsafe fn cast_unchecked(self) -> NodeRef, K, V, NewType> { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Temporarily takes out another, mutable reference to the same node. Beware, as /// this method is very dangerous, doubly so since it may not immediately appear /// dangerous. /// - /// Because mutable pointers can roam anywhere around the tree and can even (through - /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` - /// can easily be used to make the original mutable pointer dangling, or, in the case - /// of a reborrowed handle, out of bounds. - // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts - // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. + /// Because mutable pointers can roam anywhere around the tree, the returned + /// pointer can easily be used to make the original pointer dangling, out of + /// bounds, or invalid under stacked borrow rules. + // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` + // that restricts the use of navigation methods on reborrowed pointers, + // preventing this unsafety. unsafe fn reborrow_mut(&mut self) -> NodeRef, K, V, Type> { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } - /// Exposes the leaf "portion" of any leaf or internal node for writing. + /// Exposes the leaf portion of any leaf or internal node for writing. /// If the node is a leaf, this function simply opens up its data. /// If the node is an internal node, so not a leaf, it does have all the data a leaf has /// (header, keys and values), and this function exposes that. /// - /// Returns a raw ptr to avoid asserting exclusive access to the entire node. - fn as_leaf_mut(&mut self) -> *mut LeafNode { - self.node.as_ptr() + /// We don't need to return a raw ptr because we have unique access to the entire node. + fn as_leaf_mut(&mut self) -> &'a mut LeafNode { + unsafe { &mut (*self.node.as_ptr()) } + } + + /// Borrows a mutable reference to one of the keys stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn key_mut_at(&mut self, idx: usize) -> &mut K { + unsafe { self.reborrow_mut().into_key_mut_at(idx) } } - fn keys_mut(&mut self) -> &mut [K] { + /// Borrows a mutable reference to one of the values stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn val_mut_at(&mut self, idx: usize) -> &mut V { + unsafe { self.reborrow_mut().into_val_mut_at(idx) } + } + + fn keys_mut(&mut self) -> &mut [K] + where + K: 'a, + V: 'a, + { // SAFETY: the caller will not be able to call further methods on self // until the key slice reference is dropped, as we have unique access // for the lifetime of the borrow. - unsafe { self.reborrow_mut().into_key_slice_mut() } + // SAFETY: The keys of a node must always be initialized up to length. + unsafe { + slice::from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().keys), + self.len(), + ) + } } - fn vals_mut(&mut self) -> &mut [V] { + fn vals_mut(&mut self) -> &mut [V] + where + K: 'a, + V: 'a, + { // SAFETY: the caller will not be able to call further methods on self // until the value slice reference is dropped, as we have unique access // for the lifetime of the borrow. - unsafe { self.reborrow_mut().into_val_slice_mut() } + // SAFETY: The values of a node must always be initialized up to length. + unsafe { + slice::from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().vals), + self.len(), + ) + } + } +} + +impl<'a, K, V> NodeRef, K, V, marker::Internal> { + fn edges_mut(&mut self) -> &mut [BoxedNode] { + unsafe { + slice::from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(&mut self.as_internal_mut().edges), + self.len() + 1, + ) + } } } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - fn into_key_slice(self) -> &'a [K] { - unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().keys), self.len()) } + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_key_at(self, idx: usize) -> &'a K { + unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() } } - fn into_val_slice(self) -> &'a [V] { - unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().vals), self.len()) } + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_val_at(self, idx: usize) -> &'a V { + unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() } } } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - /// Gets a mutable reference to the root itself. This is useful primarily when the - /// height of the tree needs to be adjusted. Never call this on a reborrowed pointer. - pub fn into_root_mut(self) -> &'a mut Root { - unsafe { &mut *(self.root as *mut Root) } - } + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_key_mut_at(mut self, idx: usize) -> &'a mut K { + debug_assert!(idx < self.len()); - fn into_key_slice_mut(mut self) -> &'a mut [K] { - // SAFETY: The keys of a node must always be initialized up to length. - unsafe { - slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut (*self.as_leaf_mut()).keys), - self.len(), - ) - } + let leaf = self.as_leaf_mut(); + unsafe { leaf.keys.get_unchecked_mut(idx).assume_init_mut() } } - fn into_val_slice_mut(mut self) -> &'a mut [V] { - // SAFETY: The values of a node must always be initialized up to length. - unsafe { - slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut (*self.as_leaf_mut()).vals), - self.len(), - ) - } - } + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_val_mut_at(mut self, idx: usize) -> &'a mut V { + debug_assert!(idx < self.len()); - fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) { - // We cannot use the getters here, because calling the second one - // invalidates the reference returned by the first. - // More precisely, it is the call to `len` that is the culprit, - // because that creates a shared reference to the header, which *can* - // overlap with the keys (and even the values, for ZST keys). - let len = self.len(); let leaf = self.as_leaf_mut(); + unsafe { leaf.vals.get_unchecked_mut(idx).assume_init_mut() } + } +} + +impl<'a, K, V, Type> NodeRef, K, V, Type> { + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_key_val_mut_at(self, idx: usize) -> (&'a K, &'a mut V) { + // We only create a reference to the one element we are interested in, + // to avoid aliasing with outstanding references to other elements, + // in particular, those returned to the caller in earlier iterations. + let leaf = self.node.as_ptr(); + // We must coerce to unsized array pointers because of Rust issue #74679. + let keys: *const [_] = unsafe { &raw const (*leaf).keys }; + let vals: *mut [_] = unsafe { &raw mut (*leaf).vals }; // SAFETY: The keys and values of a node must always be initialized up to length. - let keys = unsafe { - slice::from_raw_parts_mut(MaybeUninit::first_ptr_mut(&mut (*leaf).keys), len) - }; - let vals = unsafe { - slice::from_raw_parts_mut(MaybeUninit::first_ptr_mut(&mut (*leaf).vals), len) - }; - (keys, vals) + let key = unsafe { (&*keys.get_unchecked(idx)).assume_init_ref() }; + let val = unsafe { (&mut *vals.get_unchecked_mut(idx)).assume_init_mut() }; + (key, val) } } -impl<'a, K, V> NodeRef, K, V, marker::Leaf> { +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key/value pair to the end of the node. pub fn push(&mut self, key: K, val: V) { - assert!(self.len() < CAPACITY); - - let idx = self.len(); - + let len = &mut self.as_leaf_mut().len; + let idx = usize::from(*len); + assert!(idx < CAPACITY); + *len += 1; unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - - (*self.as_leaf_mut()).len += 1; + ptr::write(self.key_mut_at(idx), key); + ptr::write(self.val_mut_at(idx), val); } } /// Adds a key/value pair to the beginning of the node. - pub fn push_front(&mut self, key: K, val: V) { - assert!(self.len() < CAPACITY); + fn push_front(&mut self, key: K, val: V) { + debug_assert!(self.len() < CAPACITY); unsafe { slice_insert(self.keys_mut(), 0, key); slice_insert(self.vals_mut(), 0, val); - - (*self.as_leaf_mut()).len += 1; } + self.as_leaf_mut().len += 1; } } impl<'a, K, V> NodeRef, K, V, marker::Internal> { - /// Adds a key/value pair and an edge to go to the right of that pair to - /// the end of the node. + /// # Safety + /// Every item returned by `range` is a valid edge index for the node. + unsafe fn correct_childrens_parent_links>(&mut self, range: R) { + for i in range { + debug_assert!(i <= self.len()); + unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); + } + } + + fn correct_all_childrens_parent_links(&mut self) { + let len = self.len(); + unsafe { self.correct_childrens_parent_links(0..=len) }; + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { + /// Adds a key/value pair, and an edge to go to the right of that pair, + /// to the end of the node. pub fn push(&mut self, key: K, val: V, edge: Root) { assert!(edge.height == self.height - 1); - assert!(self.len() < CAPACITY); - - let idx = self.len(); + let len = &mut self.as_leaf_mut().len; + let idx = usize::from(*len); + assert!(idx < CAPACITY); + *len += 1; unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); + ptr::write(self.key_mut_at(idx), key); + ptr::write(self.val_mut_at(idx), val); self.as_internal_mut().edges.get_unchecked_mut(idx + 1).write(edge.node); - - (*self.as_leaf_mut()).len += 1; - Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } } - // Unsafe because 'first' and 'after_last' must be in range - unsafe fn correct_childrens_parent_links(&mut self, first: usize, after_last: usize) { - debug_assert!(first <= self.len()); - debug_assert!(after_last <= self.len() + 1); - for i in first..after_last { - unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); - } - } - - fn correct_all_childrens_parent_links(&mut self) { - let len = self.len(); - unsafe { self.correct_childrens_parent_links(0, len + 1) }; - } - - /// Adds a key/value pair and an edge to go to the left of that pair to - /// the beginning of the node. + /// Adds a key/value pair, and an edge to go to the left of that pair, + /// to the beginning of the node. pub fn push_front(&mut self, key: K, val: V, edge: Root) { assert!(edge.height == self.height - 1); assert!(self.len() < CAPACITY); @@ -588,53 +664,52 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { slice_insert(self.vals_mut(), 0, val); slice_insert( slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut self.as_internal_mut().edges), + MaybeUninit::slice_as_mut_ptr(&mut self.as_internal_mut().edges), self.len() + 1, ), 0, edge.node, ); + } - (*self.as_leaf_mut()).len += 1; + self.as_leaf_mut().len += 1; - self.correct_all_childrens_parent_links(); - } + self.correct_all_childrens_parent_links(); } } -impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// Removes a key/value pair from the end of this node and returns the pair. /// If this is an internal node, also removes the edge that was to the right - /// of that pair and returns the orphaned node that this edge owned with its - /// parent erased. - pub fn pop(&mut self) -> (K, V, Option>) { - assert!(self.len() > 0); + /// of that pair and returns the orphaned node that this edge owned. + fn pop(&mut self) -> (K, V, Option>) { + debug_assert!(self.len() > 0); let idx = self.len() - 1; unsafe { - let key = ptr::read(self.keys().get_unchecked(idx)); - let val = ptr::read(self.vals().get_unchecked(idx)); + let key = ptr::read(self.key_at(idx)); + let val = ptr::read(self.val_at(idx)); let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(internal) => { - let edge = - ptr::read(internal.as_internal().edges.get_unchecked(idx + 1).as_ptr()); + let edge = ptr::read(internal.edge_at(idx + 1)); let mut new_root = Root { node: edge, height: internal.height - 1 }; - (*new_root.node_as_mut().as_leaf_mut()).parent = ptr::null(); + new_root.node_as_mut().as_leaf_mut().parent = None; Some(new_root) } }; - (*self.as_leaf_mut()).len -= 1; + self.as_leaf_mut().len -= 1; (key, val, edge) } } - /// Removes a key/value pair from the beginning of this node. If this is an internal node, - /// also removes the edge that was to the left of that pair. - pub fn pop_front(&mut self) -> (K, V, Option>) { - assert!(self.len() > 0); + /// Removes a key/value pair from the beginning of this node and returns the pair. + /// If this is an internal node, also removes the edge that was to the left + /// of that pair and returns the orphaned node that this edge owned. + fn pop_front(&mut self) -> (K, V, Option>) { + debug_assert!(self.len() > 0); let old_len = self.len(); @@ -644,26 +719,17 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(mut internal) => { - let edge = slice_remove( - slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut internal.as_internal_mut().edges), - old_len + 1, - ), - 0, - ); - + let edge = slice_remove(internal.edges_mut(), 0); let mut new_root = Root { node: edge, height: internal.height - 1 }; - (*new_root.node_as_mut().as_leaf_mut()).parent = ptr::null(); + new_root.node_as_mut().as_leaf_mut().parent = None; - for i in 0..old_len { - Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link(); - } + internal.correct_childrens_parent_links(0..old_len); Some(new_root) } }; - (*self.as_leaf_mut()).len -= 1; + self.as_leaf_mut().len -= 1; (key, val, edge) } @@ -686,14 +752,12 @@ impl NodeRef { ForceResult::Leaf(NodeRef { height: self.height, node: self.node, - root: self.root, _marker: PhantomData, }) } else { ForceResult::Internal(NodeRef { height: self.height, node: self.node, - root: self.root, _marker: PhantomData, }) } @@ -784,12 +848,7 @@ impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeT /// this method is very dangerous, doubly so since it may not immediately appear /// dangerous. /// - /// Because mutable pointers can roam anywhere around the tree and can even (through - /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` - /// can easily be used to make the original mutable pointer dangling, or, in the case - /// of a reborrowed handle, out of bounds. - // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts - // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. + /// For details, see `NodeRef::reborrow_mut`. pub unsafe fn reborrow_mut( &mut self, ) -> Handle, K, V, NodeType>, HandleType> { @@ -845,26 +904,25 @@ fn splitpoint(edge_idx: usize) -> (usize, InsertionPlace) { } } -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::Edge> { +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::Edge> { /// Helps implementations of `insert_fit` for a particular `NodeType`, /// by taking care of leaf data. /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method assumes that there is enough space in the node for the new /// pair to fit. fn leafy_insert_fit(&mut self, key: K, val: V) { - // Necessary for correctness, but in a private module debug_assert!(self.node.len() < CAPACITY); unsafe { slice_insert(self.node.keys_mut(), self.idx, key); slice_insert(self.node.vals_mut(), self.idx, val); - (*self.node.as_leaf_mut()).len += 1; + self.node.as_leaf_mut().len += 1; } } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method assumes that there is enough space in the node for the new /// pair to fit. @@ -872,37 +930,37 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge /// The returned pointer points to the inserted value. fn insert_fit(&mut self, key: K, val: V) -> *mut V { self.leafy_insert_fit(key, val); - unsafe { self.node.vals_mut().get_unchecked_mut(self.idx) } + unsafe { self.node.val_mut_at(self.idx) } } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room. /// /// The returned pointer points to the inserted value. fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) { if self.node.len() < CAPACITY { - let ptr = self.insert_fit(key, val); + let val_ptr = self.insert_fit(key, val); let kv = unsafe { Handle::new_kv(self.node, self.idx) }; - (InsertResult::Fit(kv), ptr) + (InsertResult::Fit(kv), val_ptr) } else { let (middle_kv_idx, insertion) = splitpoint(self.idx); let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) }; let (mut left, k, v, mut right) = middle.split(); - let ptr = match insertion { + let mut insertion_edge = match insertion { InsertionPlace::Left(insert_idx) => unsafe { - Handle::new_edge(left.reborrow_mut(), insert_idx).insert_fit(key, val) + Handle::new_edge(left.reborrow_mut(), insert_idx) }, InsertionPlace::Right(insert_idx) => unsafe { Handle::new_edge( right.node_as_mut().cast_unchecked::(), insert_idx, ) - .insert_fit(key, val) }, }; - (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), ptr) + let val_ptr = insertion_edge.insert_fit(key, val); + (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), val_ptr) } } } @@ -912,37 +970,25 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: /// when the ordering of edges has been changed, such as in the various `insert` methods. fn correct_parent_link(mut self) { let idx = self.idx as u16; - let ptr = self.node.as_internal_mut() as *mut _; + let ptr = NonNull::new(self.node.as_internal_mut()); let mut child = self.descend(); - unsafe { - (*child.as_leaf_mut()).parent = ptr; - (*child.as_leaf_mut()).parent_idx.write(idx); - } + child.as_leaf_mut().parent = ptr; + child.as_leaf_mut().parent_idx.write(idx); } +} +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::Edge> { /// Inserts a new key/value pair and an edge that will go to the right of that new pair /// between this edge and the key/value pair to the right of this edge. This method assumes /// that there is enough space in the node for the new pair to fit. fn insert_fit(&mut self, key: K, val: V, edge: Root) { - // Necessary for correctness, but in an internal module - debug_assert!(self.node.len() < CAPACITY); debug_assert!(edge.height == self.node.height - 1); unsafe { + slice_insert(self.node.edges_mut(), self.idx + 1, edge.node); self.leafy_insert_fit(key, val); - slice_insert( - slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut self.node.as_internal_mut().edges), - self.node.len(), - ), - self.idx + 1, - edge.node, - ); - - for i in (self.idx + 1)..(self.node.len() + 1) { - Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); - } + self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len()); } } @@ -982,7 +1028,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } } -impl<'a, K: 'a, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room, and tries to /// insert the split off portion into the parent node recursively, until the root is reached. @@ -1024,12 +1070,17 @@ impl Handle, marke /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. pub fn descend(self) -> NodeRef { + // 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 + // height field because that value is copied. Beware that, once the + // node pointer is dereferenced, we access the edges array with a + // reference (Rust issue #73987) and invalidate any other references + // to or inside the array, should any be around. + let internal_node = self.node.as_internal_ptr(); NodeRef { height: self.node.height - 1, - node: unsafe { - (&*self.node.as_internal().edges.get_unchecked(self.idx).as_ptr()).as_ptr() - }, - root: self.node.root, + node: unsafe { (&*(*internal_node).edges.get_unchecked(self.idx).as_ptr()).as_ptr() }, _marker: PhantomData, } } @@ -1037,74 +1088,71 @@ impl Handle, marke impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn into_kv(self) -> (&'a K, &'a V) { - let keys = self.node.into_key_slice(); - let vals = self.node.into_val_slice(); - unsafe { (keys.get_unchecked(self.idx), vals.get_unchecked(self.idx)) } + (unsafe { self.node.into_key_at(self.idx) }, unsafe { self.node.into_val_at(self.idx) }) } } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn into_key_mut(self) -> &'a mut K { - let keys = self.node.into_key_slice_mut(); - unsafe { keys.get_unchecked_mut(self.idx) } + unsafe { self.node.into_key_mut_at(self.idx) } } pub fn into_val_mut(self) -> &'a mut V { - let vals = self.node.into_val_slice_mut(); - unsafe { vals.get_unchecked_mut(self.idx) } + unsafe { self.node.into_val_mut_at(self.idx) } } +} - pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { - unsafe { - let (keys, vals) = self.node.into_slices_mut(); - (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) - } +impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { + pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) { + unsafe { self.node.into_key_val_mut_at(self.idx) } } } -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn kv_mut(&mut self) -> (&mut K, &mut V) { - unsafe { - let (keys, vals) = self.node.reborrow_mut().into_slices_mut(); - (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) - } + // We cannot call into_key_mut_at and into_val_mut_at, because calling the second one + // invalidates the reference returned by the first. + let leaf = self.node.as_leaf_mut(); + let key = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() }; + let val = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }; + (key, val) } } -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { /// Helps implementations of `split` for a particular `NodeType`, /// by taking care of leaf data. fn leafy_split(&mut self, new_node: &mut LeafNode) -> (K, V, usize) { unsafe { - let k = ptr::read(self.node.keys().get_unchecked(self.idx)); - let v = ptr::read(self.node.vals().get_unchecked(self.idx)); + let k = ptr::read(self.node.key_at(self.idx)); + let v = ptr::read(self.node.val_at(self.idx)); let new_len = self.node.len() - self.idx - 1; ptr::copy_nonoverlapping( - self.node.keys().as_ptr().add(self.idx + 1), - new_node.keys.as_mut_ptr() as *mut K, + self.node.key_at(self.idx + 1), + MaybeUninit::slice_as_mut_ptr(&mut new_node.keys), new_len, ); ptr::copy_nonoverlapping( - self.node.vals().as_ptr().add(self.idx + 1), - new_node.vals.as_mut_ptr() as *mut V, + self.node.val_at(self.idx + 1), + MaybeUninit::slice_as_mut_ptr(&mut new_node.vals), new_len, ); - (*self.node.as_leaf_mut()).len = self.idx as u16; + self.node.as_leaf_mut().len = self.idx as u16; new_node.len = new_len as u16; (k, v, new_len) } } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::KV> { /// Splits the underlying node into three parts: /// /// - The node is truncated to only contain the key/value pairs to the right of /// this handle. - /// - The key and value pointed to by this handle and extracted. + /// - The key and value pointed to by this handle are extracted. /// - All the key/value pairs to the right of this handle are put into a newly /// allocated node. pub fn split(mut self) -> (NodeRef, K, V, marker::Leaf>, K, V, Root) { @@ -1125,18 +1173,30 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> unsafe { let k = slice_remove(self.node.keys_mut(), self.idx); let v = slice_remove(self.node.vals_mut(), self.idx); - (*self.node.as_leaf_mut()).len -= 1; + self.node.as_leaf_mut().len -= 1; ((k, v), self.left_edge()) } } } impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { + /// Returns `true` if it is valid to call `.merge()`, i.e., whether there is enough room in + /// a node to hold the combination of the nodes to the left and right of this handle along + /// with the key/value pair at this handle. + pub fn can_merge(&self) -> bool { + (self.reborrow().left_edge().descend().len() + + self.reborrow().right_edge().descend().len() + + 1) + <= CAPACITY + } +} + +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::KV> { /// Splits the underlying node into three parts: /// /// - The node is truncated to only contain the edges and key/value pairs to the /// right of this handle. - /// - The key and value pointed to by this handle and extracted. + /// - The key and value pointed to by this handle are extracted. /// - All the edges and key/value pairs to the right of this handle are put into /// a newly allocated node. pub fn split(mut self) -> (NodeRef, K, V, marker::Internal>, K, V, Root) { @@ -1145,33 +1205,22 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: let (k, v, new_len) = self.leafy_split(&mut new_node.data); let height = self.node.height; + let old_node = &*self.node.as_internal_ptr(); ptr::copy_nonoverlapping( - self.node.as_internal().edges.as_ptr().add(self.idx + 1), + old_node.edges.as_ptr().add(self.idx + 1), new_node.edges.as_mut_ptr(), new_len + 1, ); let mut new_root = Root { node: BoxedNode::from_internal(new_node), height }; - for i in 0..(new_len + 1) { - Handle::new_edge(new_root.node_as_mut().cast_unchecked(), i).correct_parent_link(); - } + new_root.node_as_mut().cast_unchecked().correct_childrens_parent_links(0..=new_len); (self.node, k, v, new_root) } } - /// Returns `true` if it is valid to call `.merge()`, i.e., whether there is enough room in - /// a node to hold the combination of the nodes to the left and right of this handle along - /// with the key/value pair at this handle. - pub fn can_merge(&self) -> bool { - (self.reborrow().left_edge().descend().len() - + self.reborrow().right_edge().descend().len() - + 1) - <= CAPACITY - } - /// Combines the node immediately to the left of this handle, the key/value pair pointed /// to by this handle, and the node immediately to the right of this handle into one new /// child of the underlying node, returning an edge referencing that new child. @@ -1195,7 +1244,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: slice_remove(self.node.keys_mut(), self.idx), ); ptr::copy_nonoverlapping( - right_node.keys().as_ptr(), + right_node.key_at(0), left_node.keys_mut().as_mut_ptr().add(left_len + 1), right_len, ); @@ -1204,33 +1253,30 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: slice_remove(self.node.vals_mut(), self.idx), ); ptr::copy_nonoverlapping( - right_node.vals().as_ptr(), + right_node.val_at(0), left_node.vals_mut().as_mut_ptr().add(left_len + 1), right_len, ); - slice_remove(&mut self.node.as_internal_mut().edges, self.idx + 1); - for i in self.idx + 1..self.node.len() { - Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); - } - (*self.node.as_leaf_mut()).len -= 1; + slice_remove(&mut self.node.edges_mut(), self.idx + 1); + let self_len = self.node.len(); + self.node.correct_childrens_parent_links(self.idx + 1..self_len); + self.node.as_leaf_mut().len -= 1; - (*left_node.as_leaf_mut()).len += right_len as u16 + 1; + left_node.as_leaf_mut().len += right_len as u16 + 1; if self.node.height > 1 { // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. - let mut left_node = left_node.cast_unchecked(); - let right_node = right_node.cast_unchecked(); + let mut left_node = left_node.cast_unchecked::(); + let right_node = right_node.cast_unchecked::(); ptr::copy_nonoverlapping( - right_node.reborrow().as_internal().edges.as_ptr(), - left_node.reborrow_mut().as_internal_mut().edges.as_mut_ptr().add(left_len + 1), + right_node.edge_at(0), + left_node.edges_mut().as_mut_ptr().add(left_len + 1), right_len + 1, ); - for i in left_len + 1..left_len + right_len + 2 { - Handle::new_edge(left_node.reborrow_mut(), i).correct_parent_link(); - } + left_node.correct_childrens_parent_links(left_len + 1..=left_len + 1 + right_len); Global.dealloc(right_node.node.cast(), Layout::new::>()); } else { @@ -1312,22 +1358,20 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: move_kv(left_kv, new_left_len, parent_kv, 0, 1); } - (*left_node.reborrow_mut().as_leaf_mut()).len -= count as u16; - (*right_node.reborrow_mut().as_leaf_mut()).len += count as u16; + left_node.as_leaf_mut().len -= count as u16; + right_node.as_leaf_mut().len += count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { // Make room for stolen edges. let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); ptr::copy(right_edges, right_edges.add(count), right_len + 1); - right.correct_childrens_parent_links(count, count + right_len + 1); + right.correct_childrens_parent_links(count..count + right_len + 1); move_edges(left, new_left_len + 1, right, 0, count); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} - _ => { - unreachable!(); - } + _ => unreachable!(), } } } @@ -1369,8 +1413,8 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: ptr::copy(right_kv.1.add(count), right_kv.1, new_right_len); } - (*left_node.reborrow_mut().as_leaf_mut()).len += count as u16; - (*right_node.reborrow_mut().as_leaf_mut()).len -= count as u16; + left_node.as_leaf_mut().len += count as u16; + right_node.as_leaf_mut().len -= count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { @@ -1379,12 +1423,10 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: // Fix right indexing. let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); ptr::copy(right_edges.add(count), right_edges, new_right_len + 1); - right.correct_childrens_parent_links(0, new_right_len + 1); + right.correct_childrens_parent_links(0..=new_right_len); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} - _ => { - unreachable!(); - } + _ => unreachable!(), } } } @@ -1411,25 +1453,25 @@ unsafe fn move_edges( dest_offset: usize, count: usize, ) { - let source_ptr = source.as_internal_mut().edges.as_mut_ptr(); + let source_ptr = source.as_internal().edges.as_ptr(); let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr(); unsafe { ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); - dest.correct_childrens_parent_links(dest_offset, dest_offset + count); + dest.correct_childrens_parent_links(dest_offset..dest_offset + count); } } impl NodeRef { /// Removes any static information asserting that this node is a `Leaf` node. pub fn forget_type(self) -> NodeRef { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } impl NodeRef { /// Removes any static information asserting that this node is an `Internal` node. pub fn forget_type(self) -> NodeRef { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } @@ -1509,17 +1551,15 @@ impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, ma move_kv(left_kv, left_new_len, right_kv, 0, right_new_len); - (*left_node.reborrow_mut().as_leaf_mut()).len = left_new_len as u16; - (*right_node.reborrow_mut().as_leaf_mut()).len = right_new_len as u16; + left_node.as_leaf_mut().len = left_new_len as u16; + right_node.as_leaf_mut().len = right_new_len as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(right)) => { move_edges(left, left_new_len + 1, right, 1, right_new_len); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} - _ => { - unreachable!(); - } + _ => unreachable!(), } } } @@ -1558,6 +1598,7 @@ pub mod marker { pub enum Owned {} pub struct Immut<'a>(PhantomData<&'a ()>); pub struct Mut<'a>(PhantomData<&'a mut ()>); + pub struct ValMut<'a>(PhantomData<&'a mut ()>); pub enum KV {} pub enum Edge {} diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index e2416974dd..54c3709821 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -23,3 +23,12 @@ fn test_splitpoint() { assert!(left_len + right_len == CAPACITY); } } + +#[test] +#[cfg(target_arch = "x86_64")] +fn test_sizes() { + assert_eq!(core::mem::size_of::>(), 16); + assert_eq!(core::mem::size_of::>(), 16 + CAPACITY * 8 * 2); + assert_eq!(core::mem::size_of::>(), 112); + assert_eq!(core::mem::size_of::>(), 112 + CAPACITY * 8 * 2); +} diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index 4e80f7f21e..1526c0673c 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -68,11 +68,11 @@ where K: Borrow, { // This function is defined over all borrow types (immutable, mutable, owned). - // Using `keys()` is fine here even if BorrowType is mutable, as all we return + // Using `keys_at()` is fine here even if BorrowType is mutable, as all we return // is an index -- not a reference. let len = node.len(); - let keys = node.keys(); - for (i, k) in keys.iter().enumerate() { + for i in 0..len { + let k = unsafe { node.key_at(i) }; match key.cmp(k.borrow()) { Ordering::Greater => {} Ordering::Equal => return (i, true), diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 5390b57a1d..412c65681e 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -102,7 +102,7 @@ impl fmt::Debug for IterMut<'_, T> { /// This `struct` is created by the [`into_iter`] method on [`LinkedList`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// -/// [`into_iter`]: struct.LinkedList.html#method.into_iter +/// [`into_iter`]: LinkedList::into_iter #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index d3c6d493d6..8e9acc42d9 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -14,8 +14,7 @@ use core::fmt; use core::hash::{Hash, Hasher}; use core::iter::{once, repeat_with, FromIterator, FusedIterator}; use core::mem::{self, replace, ManuallyDrop}; -use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, RangeBounds, Try}; +use core::ops::{Index, IndexMut, Range, RangeBounds, Try}; use core::ptr::{self, NonNull}; use core::slice; @@ -33,12 +32,8 @@ mod tests; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 -#[cfg(target_pointer_width = "16")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (16 - 1); // Largest possible power of two -#[cfg(target_pointer_width = "32")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (32 - 1); // Largest possible power of two -#[cfg(target_pointer_width = "64")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of two + +const MAXIMUM_ZST_CAPACITY: usize = 1 << (core::mem::size_of::() * 8 - 1); // Largest possible power of two /// A double-ended queue implemented with a growable ring buffer. /// @@ -47,10 +42,17 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of /// push onto the back in this manner, and iterating over `VecDeque` goes front /// to back. /// -/// [`push_back`]: #method.push_back -/// [`pop_front`]: #method.pop_front -/// [`extend`]: #method.extend -/// [`append`]: #method.append +/// Since `VecDeque` is a ring buffer, its elements are not necessarily contiguous +/// in memory. If you want to access the elements as a single slice, such as for +/// efficient sorting, you can use [`make_contiguous`]. It rotates the `VecDeque` +/// so that its elements do not wrap, and returns a mutable slice to the +/// now-contiguous element sequence. +/// +/// [`push_back`]: VecDeque::push_back +/// [`pop_front`]: VecDeque::pop_front +/// [`extend`]: VecDeque::extend +/// [`append`]: VecDeque::append +/// [`make_contiguous`]: VecDeque::make_contiguous #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")] #[stable(feature = "rust1", since = "1.0.0")] pub struct VecDeque { @@ -638,7 +640,7 @@ impl VecDeque { /// assert!(buf.capacity() >= 11); /// ``` /// - /// [`reserve`]: #method.reserve + /// [`reserve`]: VecDeque::reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.reserve(additional); @@ -678,7 +680,7 @@ impl VecDeque { } /// Tries to reserve the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `VecDeque`. After calling `reserve_exact`, + /// be inserted in the given `VecDeque`. After calling `try_reserve_exact`, /// capacity will be greater than or equal to `self.len() + additional`. /// Does nothing if the capacity is already sufficient. /// @@ -720,7 +722,7 @@ impl VecDeque { /// Tries to reserve capacity for at least `additional` more elements to be inserted /// in the given `VecDeque`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `reserve`, capacity will be + /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional`. Does nothing if /// capacity is already sufficient. /// @@ -985,8 +987,10 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. /// - /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements - /// of the `VecDeque` will be in the first slice and the second slice will be empty. + /// If [`make_contiguous`] was previously called, all elements of the + /// `VecDeque` will be in the first slice and the second slice will be empty. + /// + /// [`make_contiguous`]: VecDeque::make_contiguous /// /// # Examples /// @@ -1018,8 +1022,10 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. /// - /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements - /// of the `VecDeque` will be in the first slice and the second slice will be empty. + /// If [`make_contiguous`] was previously called, all elements of the + /// `VecDeque` will be in the first slice and the second slice will be empty. + /// + /// [`make_contiguous`]: VecDeque::make_contiguous /// /// # Examples /// @@ -1083,24 +1089,14 @@ impl VecDeque { self.tail == self.head } - fn range_start_end(&self, range: R) -> (usize, usize) + fn range_tail_head(&self, range: R) -> (usize, usize) where R: RangeBounds, { - let len = self.len(); - let start = match range.start_bound() { - Included(&n) => n, - Excluded(&n) => n + 1, - Unbounded => 0, - }; - let end = match range.end_bound() { - Included(&n) => n + 1, - Excluded(&n) => n, - Unbounded => len, - }; - assert!(start <= end, "lower bound was too large"); - assert!(end <= len, "upper bound was too large"); - (start, end) + let Range { start, end } = slice::check_range(self.len(), range); + let tail = self.wrap_add(self.tail, start); + let head = self.wrap_add(self.tail, end); + (tail, head) } /// Creates an iterator that covers the specified range in the `VecDeque`. @@ -1131,9 +1127,7 @@ impl VecDeque { where R: RangeBounds, { - let (start, end) = self.range_start_end(range); - let tail = self.wrap_add(self.tail, start); - let head = self.wrap_add(self.tail, end); + let (tail, head) = self.range_tail_head(range); Iter { tail, head, @@ -1174,9 +1168,7 @@ impl VecDeque { where R: RangeBounds, { - let (start, end) = self.range_start_end(range); - let tail = self.wrap_add(self.tail, start); - let head = self.wrap_add(self.tail, end); + let (tail, head) = self.range_tail_head(range); IterMut { tail, head, @@ -1230,7 +1222,7 @@ impl VecDeque { // When finished, the remaining data will be copied back to cover the hole, // and the head/tail values will be restored correctly. // - let (start, end) = self.range_start_end(range); + let (drain_tail, drain_head) = self.range_tail_head(range); // The deque's elements are parted into three segments: // * self.tail -> drain_tail @@ -1248,8 +1240,6 @@ impl VecDeque { // T t h H // [. . . o o x x o o . . .] // - let drain_tail = self.wrap_add(self.tail, start); - let drain_head = self.wrap_add(self.tail, end); let head = self.head; // "forget" about the values after the start of the drain until after @@ -2174,22 +2164,25 @@ impl VecDeque { } } - /// Rearranges the internal storage of this deque so it is one contiguous slice, which is then returned. + /// Rearranges the internal storage of this deque so it is one contiguous + /// slice, which is then returned. /// - /// This method does not allocate and does not change the order of the inserted elements. - /// As it returns a mutable slice, this can be used to sort or binary search a deque. + /// This method does not allocate and does not change the order of the + /// inserted elements. As it returns a mutable slice, this can be used to + /// sort or binary search a deque. /// - /// Once the internal storage is contiguous, the [`as_slices`](#method.as_slices) and - /// [`as_mut_slices`](#method.as_mut_slices) methods will return the entire contents of the + /// Once the internal storage is contiguous, the [`as_slices`] and + /// [`as_mut_slices`] methods will return the entire contents of the /// `VecDeque` in a single slice. /// + /// [`as_slices`]: VecDeque::as_slices + /// [`as_mut_slices`]: VecDeque::as_mut_slices + /// /// # Examples /// /// Sorting the content of a deque. /// /// ``` - /// #![feature(deque_make_contiguous)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::with_capacity(15); @@ -2210,8 +2203,6 @@ impl VecDeque { /// Getting immutable access to the contiguous slice. /// /// ```rust - /// #![feature(deque_make_contiguous)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -2228,7 +2219,7 @@ impl VecDeque { /// assert_eq!(slice, &[3, 2, 1] as &[_]); /// } /// ``` - #[unstable(feature = "deque_make_contiguous", issue = "70929")] + #[stable(feature = "deque_make_contiguous", since = "1.48.0")] pub fn make_contiguous(&mut self) -> &mut [T] { if self.is_contiguous() { let tail = self.tail; @@ -2402,7 +2393,7 @@ impl VecDeque { } } - // Safety: the following two methods require that the rotation amount + // SAFETY: the following two methods require that the rotation amount // be less than half the length of the deque. // // `wrap_copy` requires that `min(x, cap() - x) + copy_len <= cap()`, @@ -2513,8 +2504,7 @@ fn count(tail: usize, head: usize, size: usize) -> usize { /// This `struct` is created by the [`iter`] method on [`VecDeque`]. See its /// documentation for more. /// -/// [`iter`]: struct.VecDeque.html#method.iter -/// [`VecDeque`]: struct.VecDeque.html +/// [`iter`]: VecDeque::iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { ring: &'a [T], @@ -2668,8 +2658,7 @@ impl FusedIterator for Iter<'_, T> {} /// This `struct` is created by the [`iter_mut`] method on [`VecDeque`]. See its /// documentation for more. /// -/// [`iter_mut`]: struct.VecDeque.html#method.iter_mut -/// [`VecDeque`]: struct.VecDeque.html +/// [`iter_mut`]: VecDeque::iter_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { ring: &'a mut [T], @@ -2774,8 +2763,7 @@ impl FusedIterator for IterMut<'_, T> {} /// This `struct` is created by the [`into_iter`] method on [`VecDeque`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// -/// [`into_iter`]: struct.VecDeque.html#method.into_iter -/// [`VecDeque`]: struct.VecDeque.html +/// [`into_iter`]: VecDeque::into_iter #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index 1ae94de75a..4ffb435d1e 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -9,8 +9,7 @@ use super::{count, Iter, VecDeque}; /// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its /// documentation for more. /// -/// [`drain`]: struct.VecDeque.html#method.drain -/// [`VecDeque`]: struct.VecDeque.html +/// [`drain`]: VecDeque::drain #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { pub(crate) after_tail: usize, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 755a21934f..b33cb3ad8e 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -74,24 +74,25 @@ #![deny(unsafe_op_in_unsafe_fn)] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] +#![cfg_attr(test, feature(new_uninit))] #![feature(allocator_api)] #![feature(array_chunks)] +#![feature(array_windows)] #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(btree_drain_filter)] #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] #![feature(const_btree_new)] +#![feature(const_fn)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] #![feature(cow_is_borrowed)] -#![feature(deque_range)] +#![feature(const_cow_is_borrowed)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] -#![feature(container_error_extra)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(exclusive_range_pattern)] @@ -99,14 +100,13 @@ #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(fundamental)] -#![feature(internal_uninit_const)] +#![feature(inplace_iteration)] +#![feature(int_bits_const)] #![feature(lang_items)] #![feature(layout_for_ptr)] -#![feature(libc)] -#![feature(map_first_last)] -#![feature(map_into_keys_values)] +#![feature(maybe_uninit_ref)] #![feature(negative_impls)] -#![feature(new_uninit)] +#![feature(never_type)] #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(optin_builtin_traits)] @@ -117,13 +117,12 @@ #![feature(rustc_attrs)] #![feature(receiver_trait)] #![feature(min_specialization)] +#![feature(slice_check_range)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(staged_api)] -#![feature(std_internals)] #![feature(str_internals)] #![feature(trusted_len)] -#![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode_internals)] #![feature(unsafe_block_in_unsafe_fn)] @@ -131,9 +130,11 @@ #![feature(unsized_locals)] #![feature(allocator_internals)] #![feature(slice_partition_dedup)] -#![feature(maybe_uninit_extra, maybe_uninit_slice)] +#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)] #![feature(alloc_layout_extra)] +#![feature(trusted_random_access)] #![feature(try_trait)] +#![feature(type_alias_impl_trait)] #![feature(associated_type_bounds)] // Allow testing this library diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 247b636c80..1844d3ae00 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -3,6 +3,7 @@ use core::alloc::LayoutErr; use core::cmp; +use core::intrinsics; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::Drop; use core::ptr::{NonNull, Unique}; @@ -149,6 +150,7 @@ impl RawVec { impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. + #[allow_internal_unstable(const_fn)] pub const fn new_in(alloc: A) -> Self { // `cap: 0` means "unallocated". zero-sized types are ignored. Self { ptr: Unique::dangling(), cap: 0, alloc } @@ -168,7 +170,7 @@ impl RawVec { Self::allocate_in(capacity, AllocInit::Zeroed, alloc) } - fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self { + fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { if mem::size_of::() == 0 { Self::new_in(alloc) } else { @@ -305,11 +307,7 @@ impl RawVec { /// # } /// ``` pub fn reserve(&mut self, len: usize, additional: usize) { - match self.try_reserve(len, additional) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.try_reserve(len, additional)); } /// The same as `reserve`, but returns on errors instead of panicking or aborting. @@ -339,11 +337,7 @@ impl RawVec { /// /// Aborts on OOM. pub fn reserve_exact(&mut self, len: usize, additional: usize) { - match self.try_reserve_exact(len, additional) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.try_reserve_exact(len, additional)); } /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. @@ -366,11 +360,7 @@ impl RawVec { /// /// Aborts on OOM. pub fn shrink_to_fit(&mut self, amount: usize) { - match self.shrink(amount) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.shrink(amount)); } } @@ -465,8 +455,9 @@ impl RawVec { let new_size = amount * mem::size_of::(); let ptr = unsafe { - self.alloc.shrink(ptr, layout, new_size).map_err(|_| TryReserveError::AllocError { - layout: Layout::from_size_align_unchecked(new_size, layout.align()), + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + self.alloc.shrink(ptr, layout, new_layout).map_err(|_| TryReserveError::AllocError { + layout: new_layout, non_exhaustive: (), })? }; @@ -494,13 +485,16 @@ where let memory = if let Some((ptr, old_layout)) = current_memory { debug_assert_eq!(old_layout.align(), new_layout.align()); - unsafe { alloc.grow(ptr, old_layout, new_layout.size()) } + unsafe { + // The allocator checks for alignment equality + intrinsics::assume(old_layout.align() == new_layout.align()); + alloc.grow(ptr, old_layout, new_layout) + } } else { alloc.alloc(new_layout) - } - .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?; + }; - Ok(memory) + memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }) } unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { @@ -512,6 +506,16 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { } } +// Central function for reserve error handling. +#[inline] +fn handle_reserve(result: Result<(), TryReserveError>) { + match result { + Err(CapacityOverflow) => capacity_overflow(), + Err(AllocError { layout, .. }) => handle_alloc_error(layout), + Ok(()) => { /* yay */ } + } +} + // We need to guarantee the following: // * We don't ever allocate `> isize::MAX` byte-size objects. // * We don't overflow `usize::MAX` and actually allocate too little. @@ -523,7 +527,7 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { #[inline] fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { - if mem::size_of::() < 8 && alloc_size > isize::MAX as usize { + if usize::BITS < 64 && alloc_size > isize::MAX as usize { Err(CapacityOverflow) } else { Ok(()) diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index cadd913aa6..cb4fe1b46c 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -1,8 +1,9 @@ use super::*; +use std::cell::Cell; #[test] fn allocator_param() { - use crate::alloc::AllocErr; + use crate::alloc::AllocError; // Writing a test of integration between third-party // allocators and `RawVec` is a little tricky because the `RawVec` @@ -17,32 +18,32 @@ fn allocator_param() { // A dumb allocator that consumes a fixed amount of fuel // before allocation attempts start failing. struct BoundedAlloc { - fuel: usize, + fuel: Cell, } unsafe impl AllocRef for BoundedAlloc { - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocError> { let size = layout.size(); - if size > self.fuel { - return Err(AllocErr); + if size > self.fuel.get() { + return Err(AllocError); } match Global.alloc(layout) { ok @ Ok(_) => { - self.fuel -= size; + self.fuel.set(self.fuel.get() - size); ok } err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { unsafe { Global.dealloc(ptr, layout) } } } - let a = BoundedAlloc { fuel: 500 }; + let a = BoundedAlloc { fuel: Cell::new(500) }; let mut v: RawVec = RawVec::with_capacity_in(50, a); - assert_eq!(v.alloc.fuel, 450); + assert_eq!(v.alloc.fuel.get(), 450); v.reserve(50, 150); // (causes a realloc, thus using 50 + 150 = 200 units of fuel) - assert_eq!(v.alloc.fuel, 250); + assert_eq!(v.alloc.fuel.get(), 250); } #[test] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 1046397f4b..5dbc42cc97 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -247,7 +247,7 @@ use core::pin::Pin; use core::ptr::{self, NonNull}; use core::slice::from_raw_parts_mut; -use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::string::String; use crate::vec::Vec; @@ -295,6 +295,13 @@ impl, U: ?Sized> CoerceUnsized> for Rc {} impl, U: ?Sized> DispatchFromDyn> for Rc {} impl Rc { + #[inline(always)] + fn inner(&self) -> &RcBox { + // This unsafety is ok because while this Rc is alive we're guaranteed + // that the inner pointer is valid. + unsafe { self.ptr.as_ref() } + } + fn from_inner(ptr: NonNull>) -> Self { Self { ptr, phantom: PhantomData } } @@ -325,6 +332,50 @@ impl Rc { ) } + /// Constructs a new `Rc` using a weak reference to itself. Attempting + /// to upgrade the weak reference before this function returns will result + /// in a `None` value. However, the weak reference may be cloned freely and + /// stored for use at a later time. + #[unstable(feature = "arc_new_cyclic", issue = "75861")] + pub fn new_cyclic(data_fn: impl FnOnce(&Weak) -> T) -> Rc { + // Construct the inner in the "uninitialized" state with a single + // weak reference. + let uninit_ptr: NonNull<_> = Box::leak(box RcBox { + strong: Cell::new(0), + weak: Cell::new(1), + value: mem::MaybeUninit::::uninit(), + }) + .into(); + + let init_ptr: NonNull> = uninit_ptr.cast(); + + let weak = Weak { ptr: init_ptr }; + + // It's important we don't give up ownership of the weak pointer, or + // else the memory might be freed by the time `data_fn` returns. If + // we really wanted to pass ownership, we could create an additional + // weak pointer for ourselves, but this would result in additional + // updates to the weak reference count which might not be necessary + // otherwise. + let data = data_fn(&weak); + + unsafe { + let inner = init_ptr.as_ptr(); + ptr::write(&raw mut (*inner).value, data); + + let prev_value = (*inner).strong.get(); + debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); + (*inner).strong.set(1); + } + + let strong = Rc::from_inner(init_ptr); + + // Strong references should collectively own a shared weak reference, + // so don't run the destructor for our old weak reference. + mem::forget(weak); + strong + } + /// Constructs a new `Rc` with uninitialized contents. /// /// # Examples @@ -376,7 +427,7 @@ impl Rc { /// assert_eq!(*zero, 0) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Rc> { unsafe { @@ -425,7 +476,7 @@ impl Rc { // the strong count, and then remove the implicit "strong weak" // pointer while also handling drop logic by just crafting a // fake Weak. - this.dec_strong(); + this.inner().dec_strong(); let _weak = Weak { ptr: this.ptr }; forget(this); Ok(val) @@ -484,7 +535,7 @@ impl Rc<[T]> { /// assert_eq!(*values, [0, 0, 0]) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { unsafe { @@ -511,7 +562,7 @@ impl Rc> { /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// @@ -550,7 +601,7 @@ impl Rc<[mem::MaybeUninit]> { /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// @@ -691,7 +742,7 @@ impl Rc { /// ``` #[stable(feature = "rc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak { - this.inc_weak(); + this.inner().inc_weak(); // Make sure we do not create a dangling Weak debug_assert!(!is_dangling(this.ptr)); Weak { ptr: this.ptr } @@ -712,7 +763,7 @@ impl Rc { #[inline] #[stable(feature = "rc_counts", since = "1.15.0")] pub fn weak_count(this: &Self) -> usize { - this.weak() - 1 + this.inner().weak() - 1 } /// Gets the number of strong (`Rc`) pointers to this allocation. @@ -730,7 +781,7 @@ impl Rc { #[inline] #[stable(feature = "rc_counts", since = "1.15.0")] pub fn strong_count(this: &Self) -> usize { - this.strong() + this.inner().strong() } /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to @@ -800,7 +851,9 @@ impl Rc { #[inline] #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - unsafe { &mut this.ptr.as_mut().value } + // We are careful to *not* create a reference covering the "count" fields, as + // this would conflict with accesses to the reference counts (e.g. by `Weak`). + unsafe { &mut (*this.ptr.as_ptr()).value } } #[inline] @@ -887,10 +940,10 @@ impl Rc { unsafe { let mut swap = Rc::new(ptr::read(&this.ptr.as_ref().value)); mem::swap(this, &mut swap); - swap.dec_strong(); + swap.inner().dec_strong(); // Remove implicit strong-weak ref (no need to craft a fake // Weak here -- we know other Weaks can clean up for us) - swap.dec_weak(); + swap.inner().dec_weak(); forget(swap); } } @@ -943,7 +996,7 @@ impl Rc { /// and must return back a (potentially fat)-pointer for the `RcBox`. unsafe fn allocate_for_layout( value_layout: Layout, - allocate: impl FnOnce(Layout) -> Result, AllocErr>, + allocate: impl FnOnce(Layout) -> Result, AllocError>, mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox, ) -> *mut RcBox { // Calculate layout using the given value layout. @@ -1148,16 +1201,16 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// ``` fn drop(&mut self) { unsafe { - self.dec_strong(); - if self.strong() == 0 { + self.inner().dec_strong(); + if self.inner().strong() == 0 { // destroy the contained object - ptr::drop_in_place(self.ptr.as_mut()); + ptr::drop_in_place(Self::get_mut_unchecked(self)); // remove the implicit "strong weak" pointer now that we've // destroyed the contents. - self.dec_weak(); + self.inner().dec_weak(); - if self.weak() == 0 { + if self.inner().weak() == 0 { Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } @@ -1183,7 +1236,7 @@ impl Clone for Rc { /// ``` #[inline] fn clone(&self) -> Rc { - self.inc_strong(); + self.inner().inc_strong(); Self::from_inner(self.ptr) } } @@ -1807,6 +1860,13 @@ pub(crate) fn is_dangling(ptr: NonNull) -> bool { address == usize::MAX } +/// Helper type to allow accessing the reference counts without +/// making any assertions about the data field. +struct WeakInner<'a> { + weak: &'a Cell, + strong: &'a Cell, +} + impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying /// dropping of the inner value if successful. @@ -1866,11 +1926,21 @@ impl Weak { .unwrap_or(0) } - /// Returns `None` when the pointer is dangling and there is no allocated `RcBox` + /// Returns `None` when the pointer is dangling and there is no allocated `RcBox`, /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] - fn inner(&self) -> Option<&RcBox> { - if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) } + fn inner(&self) -> Option> { + if is_dangling(self.ptr) { + None + } else { + // We are careful to *not* create a reference covering the "data" field, as + // the field may be mutated concurrently (for example, if the last `Rc` + // is dropped, the data field will be dropped in-place). + Some(unsafe { + let ptr = self.ptr.as_ptr(); + WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } + }) + } } /// Returns `true` if the two `Weak`s point to the same allocation (similar to @@ -1948,14 +2018,14 @@ impl Drop for Weak { /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { - if let Some(inner) = self.inner() { - inner.dec_weak(); - // the weak count starts at 1, and will only go to zero if all - // the strong pointers have disappeared. - if inner.weak() == 0 { - unsafe { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); - } + let inner = if let Some(inner) = self.inner() { inner } else { return }; + + inner.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if inner.weak() == 0 { + unsafe { + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -2021,12 +2091,13 @@ impl Default for Weak { // clone these much in Rust thanks to ownership and move-semantics. #[doc(hidden)] -trait RcBoxPtr { - fn inner(&self) -> &RcBox; +trait RcInnerPtr { + fn weak_ref(&self) -> &Cell; + fn strong_ref(&self) -> &Cell; #[inline] fn strong(&self) -> usize { - self.inner().strong.get() + self.strong_ref().get() } #[inline] @@ -2040,17 +2111,17 @@ trait RcBoxPtr { if strong == 0 || strong == usize::MAX { abort(); } - self.inner().strong.set(strong + 1); + self.strong_ref().set(strong + 1); } #[inline] fn dec_strong(&self) { - self.inner().strong.set(self.strong() - 1); + self.strong_ref().set(self.strong() - 1); } #[inline] fn weak(&self) -> usize { - self.inner().weak.get() + self.weak_ref().get() } #[inline] @@ -2064,26 +2135,36 @@ trait RcBoxPtr { if weak == 0 || weak == usize::MAX { abort(); } - self.inner().weak.set(weak + 1); + self.weak_ref().set(weak + 1); } #[inline] fn dec_weak(&self) { - self.inner().weak.set(self.weak() - 1); + self.weak_ref().set(self.weak() - 1); } } -impl RcBoxPtr for Rc { +impl RcInnerPtr for RcBox { #[inline(always)] - fn inner(&self) -> &RcBox { - unsafe { self.ptr.as_ref() } + fn weak_ref(&self) -> &Cell { + &self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + &self.strong } } -impl RcBoxPtr for RcBox { +impl<'a> RcInnerPtr for WeakInner<'a> { #[inline(always)] - fn inner(&self) -> &RcBox { - self + fn weak_ref(&self) -> &Cell { + self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + self.strong } } diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index e88385faf4..fed48a59f8 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -434,3 +434,69 @@ fn test_array_from_slice() { let a: Result, _> = r.clone().try_into(); assert!(a.is_err()); } + +#[test] +fn test_rc_cyclic_with_zero_refs() { + struct ZeroRefs { + inner: Weak, + } + + let zero_refs = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + ZeroRefs { inner: Weak::new() } + }); + + assert_eq!(Rc::strong_count(&zero_refs), 1); + assert_eq!(Rc::weak_count(&zero_refs), 0); + assert_eq!(zero_refs.inner.strong_count(), 0); + assert_eq!(zero_refs.inner.weak_count(), 0); +} + +#[test] +fn test_rc_cyclic_with_one_ref() { + struct OneRef { + inner: Weak, + } + + let one_ref = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + OneRef { inner: inner.clone() } + }); + + assert_eq!(Rc::strong_count(&one_ref), 1); + assert_eq!(Rc::weak_count(&one_ref), 1); + + let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap(); + assert!(Rc::ptr_eq(&one_ref, &one_ref2)); + + assert_eq!(one_ref.inner.strong_count(), 2); + assert_eq!(one_ref.inner.weak_count(), 1); +} + +#[test] +fn test_rc_cyclic_with_two_ref() { + struct TwoRefs { + inner: Weak, + inner1: Weak, + } + + let two_refs = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + TwoRefs { inner: inner.clone(), inner1: inner.clone() } + }); + + assert_eq!(Rc::strong_count(&two_refs), 1); + assert_eq!(Rc::weak_count(&two_refs), 2); + + let two_ref3 = Weak::upgrade(&two_refs.inner).unwrap(); + assert!(Rc::ptr_eq(&two_refs, &two_ref3)); + + let two_ref2 = Weak::upgrade(&two_refs.inner1).unwrap(); + assert!(Rc::ptr_eq(&two_refs, &two_ref2)); + + assert_eq!(Rc::strong_count(&two_refs), 3); + assert_eq!(Rc::weak_count(&two_refs), 2); +} diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 8ea2c6dc85..79403cf868 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -91,8 +91,14 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; +#[unstable(feature = "slice_check_range", issue = "76393")] +pub use core::slice::check_range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; +#[unstable(feature = "array_chunks", issue = "74985")] +pub use core::slice::ArrayChunksMut; +#[unstable(feature = "array_windows", issue = "75027")] +pub use core::slice::ArrayWindows; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[stable(feature = "from_ref", since = "1.28.0")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 05690e19d2..d3598ccfce 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -47,8 +47,9 @@ use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; +use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; +use core::slice; use core::str::{lossy, pattern::Pattern}; use crate::borrow::{Cow, ToOwned}; @@ -1506,23 +1507,15 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let len = self.len(); - let start = match range.start_bound() { - Included(&n) => n, - Excluded(&n) => n + 1, - Unbounded => 0, - }; - let end = match range.end_bound() { - Included(&n) => n + 1, - Excluded(&n) => n, - Unbounded => len, - }; + let Range { start, end } = slice::check_range(self.len(), range); + assert!(self.is_char_boundary(start)); + assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // slicing does the appropriate bounds checks - let chars_iter = self[start..end].chars(); + // SAFETY: `check_range` and `is_char_boundary` do the appropriate bounds checks. + let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } } @@ -2447,7 +2440,7 @@ pub struct Drain<'a> { #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for Drain<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Drain { .. }") + f.debug_tuple("Drain").field(&self.as_str()).finish() } } @@ -2470,6 +2463,40 @@ impl Drop for Drain<'_> { } } +impl<'a> Drain<'a> { + /// Returns the remaining (sub)string of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(string_drain_as_str)] + /// let mut s = String::from("abc"); + /// let mut drain = s.drain(..); + /// assert_eq!(drain.as_str(), "abc"); + /// let _ = drain.next().unwrap(); + /// assert_eq!(drain.as_str(), "bc"); + /// ``` + #[unstable(feature = "string_drain_as_str", issue = "76905")] // Note: uncomment AsRef impls below when stabilizing. + pub fn as_str(&self) -> &str { + self.iter.as_str() + } +} + +// Uncomment when stabilizing `string_drain_as_str`. +// #[unstable(feature = "string_drain_as_str", issue = "76905")] +// impl<'a> AsRef for Drain<'a> { +// fn as_ref(&self) -> &str { +// self.as_str() +// } +// } +// +// #[unstable(feature = "string_drain_as_str", issue = "76905")] +// impl<'a> AsRef<[u8]> for Drain<'a> { +// fn as_ref(&self) -> &[u8] { +// self.as_str().as_bytes() +// } +// } + #[stable(feature = "drain", since = "1.6.0")] impl Iterator for Drain<'_> { type Item = char; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 73d2fe7482..3d7411c79d 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -21,7 +21,7 @@ use core::slice::from_raw_parts_mut; use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -111,7 +111,7 @@ macro_rules! acquire { /// /// # Cloning references /// -/// Creating a new reference from an existing reference counted pointer is done using the +/// Creating a new reference from an existing reference-counted pointer is done using the /// `Clone` trait implemented for [`Arc`][Arc] and [`Weak`][Weak]. /// /// ``` @@ -152,7 +152,7 @@ macro_rules! acquire { /// [upgrade]: Weak::upgrade /// [`RefCell`]: core::cell::RefCell /// [`std::sync`]: ../../std/sync/index.html -/// [`Arc::clone(&from)`]: #method.clone +/// [`Arc::clone(&from)`]: Arc::clone /// /// # Examples /// @@ -201,7 +201,7 @@ macro_rules! acquire { /// See the [`rc` documentation][rc_examples] for more examples of reference /// counting in general. /// -/// [rc_examples]: ../../std/rc/index.html#examples +/// [rc_examples]: crate::rc#examples #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] pub struct Arc { @@ -969,7 +969,7 @@ impl Arc { /// and must return back a (potentially fat)-pointer for the `ArcInner`. unsafe fn allocate_for_layout( value_layout: Layout, - allocate: impl FnOnce(Layout) -> Result, AllocErr>, + allocate: impl FnOnce(Layout) -> Result, AllocError>, mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner, ) -> *mut ArcInner { // Calculate layout using the given value layout. diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 5edc579605..fcab3fd0ba 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -33,6 +33,7 @@ pub trait Wake { } } +#[allow(rustc::ineffective_unstable_trait_impl)] #[unstable(feature = "wake_trait", issue = "69912")] impl From> for Waker { fn from(waker: Arc) -> Waker { @@ -42,6 +43,7 @@ impl From> for Waker { } } +#[allow(rustc::ineffective_unstable_trait_impl)] #[unstable(feature = "wake_trait", issue = "69912")] impl From> for RawWaker { fn from(waker: Arc) -> RawWaker { diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 058a06e132..63ea61820d 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -9,7 +9,7 @@ //! //! # Examples //! -//! You can explicitly create a [`Vec`] with [`new`]: +//! You can explicitly create a [`Vec`] with [`Vec::new`]: //! //! ``` //! let v: Vec = Vec::new(); @@ -50,21 +50,21 @@ //! v[1] = v[1] + 5; //! ``` //! -//! [`Vec`]: Vec -//! [`new`]: Vec::new //! [`push`]: Vec::push #![stable(feature = "rust1", since = "1.0.0")] use core::cmp::{self, Ordering}; +use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::{arith_offset, assume}; -use core::iter::{FromIterator, FusedIterator, TrustedLen}; +use core::iter::{ + FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess, +}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit}; -use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{self, Index, IndexMut, RangeBounds}; +use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; @@ -116,10 +116,14 @@ use crate::raw_vec::RawVec; /// assert_eq!(vec, [0, 0, 0, 0, 0]); /// /// // The following is equivalent, but potentially slower: -/// let mut vec1 = Vec::with_capacity(5); -/// vec1.resize(5, 0); +/// let mut vec = Vec::with_capacity(5); +/// vec.resize(5, 0); +/// assert_eq!(vec, [0, 0, 0, 0, 0]); /// ``` /// +/// For more information, see +/// [Capacity and Reallocation](#capacity-and-reallocation). +/// /// Use a `Vec` as an efficient stack: /// /// ``` @@ -159,7 +163,7 @@ use crate::raw_vec::RawVec; /// # Slicing /// /// A `Vec` can be mutable. Slices, on the other hand, are read-only objects. -/// To get a slice, use `&`. Example: +/// To get a [slice], use [`&`]. Example: /// /// ``` /// fn read_slice(slice: &[usize]) { @@ -171,7 +175,9 @@ use crate::raw_vec::RawVec; /// /// // ... and that's all! /// // you can also do it like this: -/// let x : &[usize] = &v; +/// let u: &[usize] = &v; +/// // or like this: +/// let u: &[_] = &v; /// ``` /// /// In Rust, it's more common to pass slices as arguments rather than vectors @@ -287,6 +293,8 @@ use crate::raw_vec::RawVec; /// [`insert`]: Vec::insert /// [`reserve`]: Vec::reserve /// [owned slice]: Box +/// [slice]: ../../std/primitive.slice.html +/// [`&`]: ../../std/primitive.reference.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] pub struct Vec { @@ -404,7 +412,7 @@ impl Vec { /// (at least, it's highly likely to be incorrect if it wasn't). /// * `T` needs to have the same size and alignment as what `ptr` was allocated with. /// (`T` having a less strict alignment is not sufficient, the alignment really - /// needs to be equal to satsify the [`dealloc`] requirement that memory must be + /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// allocated and deallocated with the same layout.) /// * `length` needs to be less than or equal to `capacity`. /// * `capacity` needs to be the capacity that the pointer was allocated with. @@ -524,7 +532,7 @@ impl Vec { /// Tries to reserve capacity for at least `additional` more elements to be inserted /// in the given `Vec`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `reserve`, capacity will be + /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional`. Does nothing if /// capacity is already sufficient. /// @@ -559,9 +567,10 @@ impl Vec { self.buf.try_reserve(self.len, additional) } - /// Tries to reserves the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `Vec`. After calling `reserve_exact`, - /// capacity will be greater than or equal to `self.len() + additional`. + /// Tries to reserve the minimum capacity for exactly `additional` + /// elements to be inserted in the given `Vec`. After calling + /// `try_reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional` if it returns `Ok(())`. /// Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it @@ -583,7 +592,7 @@ impl Vec { /// let mut output = Vec::new(); /// /// // Pre-reserve the memory, exiting if we can't - /// output.try_reserve(data.len())?; + /// output.try_reserve_exact(data.len())?; /// /// // Now we know this can't OOM in the middle of our complex work /// output.extend(data.iter().map(|&val| { @@ -1305,35 +1314,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let start = match range.start_bound() { - Included(&n) => n, - Excluded(&n) => n + 1, - Unbounded => 0, - }; - let end = match range.end_bound() { - Included(&n) => n + 1, - Excluded(&n) => n, - Unbounded => len, - }; - - #[cold] - #[inline(never)] - fn start_assert_failed(start: usize, end: usize) -> ! { - panic!("start drain index (is {}) should be <= end drain index (is {})", start, end); - } - - #[cold] - #[inline(never)] - fn end_assert_failed(end: usize, len: usize) -> ! { - panic!("end drain index (is {}) should be <= len (is {})", end, len); - } - - if start > end { - start_assert_failed(start, end); - } - if end > len { - end_assert_failed(end, len); - } + let Range { start, end } = slice::check_range(len, range); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked @@ -1433,6 +1414,11 @@ impl Vec { assert_failed(at, self.len()); } + if at == 0 { + // the new vector can take over the original buffer and avoid the copy + return mem::replace(self, Vec::with_capacity(self.capacity())); + } + let other_len = self.len - at; let mut other = Vec::with_capacity(other_len); @@ -1456,9 +1442,9 @@ impl Vec { /// If `new_len` is less than `len`, the `Vec` is simply truncated. /// /// This method uses a closure to create new values on every push. If - /// you'd rather [`Clone`] a given value, use [`resize`]. If you want - /// to use the [`Default`] trait to generate values, you can pass - /// [`Default::default()`] as the second argument. + /// you'd rather [`Clone`] a given value, use [`Vec::resize`]. If you + /// want to use the [`Default`] trait to generate values, you can + /// pass [`Default::default`] as the second argument. /// /// # Examples /// @@ -1472,8 +1458,6 @@ impl Vec { /// vec.resize_with(4, || { p *= 2; p }); /// assert_eq!(vec, [2, 4, 8, 16]); /// ``` - /// - /// [`resize`]: Vec::resize #[stable(feature = "vec_resize_with", since = "1.33.0")] pub fn resize_with(&mut self, new_len: usize, f: F) where @@ -1569,7 +1553,7 @@ impl Vec { /// This method requires `T` to implement [`Clone`], /// in order to be able to clone the passed value. /// If you need more flexibility (or want to rely on [`Default`] instead of - /// [`Clone`]), use [`resize_with`]. + /// [`Clone`]), use [`Vec::resize_with`]. /// /// # Examples /// @@ -1582,8 +1566,6 @@ impl Vec { /// vec.resize(2, 0); /// assert_eq!(vec, [1, 2]); /// ``` - /// - /// [`resize_with`]: Vec::resize_with #[stable(feature = "vec_resize", since = "1.5.0")] pub fn resize(&mut self, new_len: usize, value: T) { let len = self.len(); @@ -1613,7 +1595,7 @@ impl Vec { /// assert_eq!(vec, [1, 2, 3, 4]); /// ``` /// - /// [`extend`]: #method.extend + /// [`extend`]: Vec::extend #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] pub fn extend_from_slice(&mut self, other: &[T]) { self.spec_extend(other.iter()) @@ -2017,7 +1999,7 @@ impl> IndexMut for Vec { impl FromIterator for Vec { #[inline] fn from_iter>(iter: I) -> Vec { - >::from_iter(iter.into_iter()) + >::from_iter(iter.into_iter()) } } @@ -2099,13 +2081,38 @@ impl Extend for Vec { } } -// Specialization trait used for Vec::from_iter and Vec::extend -trait SpecExtend { +/// Specialization trait used for Vec::from_iter +/// +/// ## The delegation graph: +/// +/// ```text +/// +-------------+ +/// |FromIterator | +/// +-+-----------+ +/// | +/// v +/// +-+-------------------------------+ +---------------------+ +/// |SpecFromIter +---->+SpecFromIterNested | +/// |where I: | | |where I: | +/// | Iterator (default)----------+ | | Iterator (default) | +/// | vec::IntoIter | | | TrustedLen | +/// | SourceIterMarker---fallback-+ | | | +/// | slice::Iter | | | +/// | Iterator | +---------------------+ +/// +---------------------------------+ +/// ``` +trait SpecFromIter { fn from_iter(iter: I) -> Self; - fn spec_extend(&mut self, iter: I); } -impl SpecExtend for Vec +/// Another specialization trait for Vec::from_iter +/// necessary to manually prioritize overlapping specializations +/// see [`SpecFromIter`] for details. +trait SpecFromIterNested { + fn from_iter(iter: I) -> Self; +} + +impl SpecFromIterNested for Vec where I: Iterator, { @@ -2127,25 +2134,231 @@ where vector } }; + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs as SpecExtend>::spec_extend(&mut vector, iterator); vector } - - default fn spec_extend(&mut self, iter: I) { - self.extend_desugared(iter) - } } -impl SpecExtend for Vec +impl SpecFromIterNested for Vec where I: TrustedLen, { - default fn from_iter(iterator: I) -> Self { + fn from_iter(iterator: I) -> Self { let mut vector = Vec::new(); + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs vector.spec_extend(iterator); vector } +} + +impl SpecFromIter for Vec +where + I: Iterator, +{ + default fn from_iter(iterator: I) -> Self { + SpecFromIterNested::from_iter(iterator) + } +} + +// A helper struct for in-place iteration that drops the destination slice of iteration, +// i.e. the head. The source slice (the tail) is dropped by IntoIter. +struct InPlaceDrop { + inner: *mut T, + dst: *mut T, +} + +impl InPlaceDrop { + fn len(&self) -> usize { + unsafe { self.dst.offset_from(self.inner) as usize } + } +} + +impl Drop for InPlaceDrop { + #[inline] + fn drop(&mut self) { + unsafe { + ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len())); + } + } +} + +impl SpecFromIter> for Vec { + fn from_iter(iterator: IntoIter) -> Self { + // A common case is passing a vector into a function which immediately + // re-collects into a vector. We can short circuit this if the IntoIter + // has not been advanced at all. + // When it has been advanced We can also reuse the memory and move the data to the front. + // But we only do so when the resulting Vec wouldn't have more unused capacity + // than creating it through the generic FromIterator implementation would. That limitation + // is not strictly necessary as Vec's allocation behavior is intentionally unspecified. + // But it is a conservative choice. + let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr; + if !has_advanced || iterator.len() >= iterator.cap / 2 { + unsafe { + let it = ManuallyDrop::new(iterator); + if has_advanced { + ptr::copy(it.ptr, it.buf.as_ptr(), it.len()); + } + return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap); + } + } + + let mut vec = Vec::new(); + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs + vec.spec_extend(iterator); + vec + } +} + +fn write_in_place_with_drop( + src_end: *const T, +) -> impl FnMut(InPlaceDrop, T) -> Result, !> { + move |mut sink, item| { + unsafe { + // the InPlaceIterable contract cannot be verified precisely here since + // try_fold has an exclusive reference to the source pointer + // all we can do is check if it's still in range + debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation"); + ptr::write(sink.dst, item); + sink.dst = sink.dst.add(1); + } + Ok(sink) + } +} + +/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the +/// source allocation, i.e. executing the pipeline in place. +/// +/// The SourceIter parent trait is necessary for the specializing function to access the allocation +/// which is to be reused. But it is not sufficient for the specialization to be valid. See +/// additional bounds on the impl. +#[rustc_unsafe_specialization_marker] +trait SourceIterMarker: SourceIter {} + +// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of +// Adapter>> (all owned by core/std). Additional bounds +// on the adapter implementations (beyond `impl Trait for Adapter`) only depend on other +// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator). +// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which +// several other specializations already depend on. +impl SourceIterMarker for T where T: SourceIter + InPlaceIterable {} + +impl SpecFromIter for Vec +where + I: Iterator + SourceIterMarker, +{ + default fn from_iter(mut iterator: I) -> Self { + // Additional requirements which cannot expressed via trait bounds. We rely on const eval + // instead: + // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic + // b) size match as required by Alloc contract + // c) alignments match as required by Alloc contract + if mem::size_of::() == 0 + || mem::size_of::() + != mem::size_of::<<::Source as AsIntoIter>::Item>() + || mem::align_of::() + != mem::align_of::<<::Source as AsIntoIter>::Item>() + { + // fallback to more generic implementations + return SpecFromIterNested::from_iter(iterator); + } + + let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe { + let inner = iterator.as_inner().as_into_iter(); + ( + inner.buf.as_ptr(), + inner.ptr, + inner.buf.as_ptr() as *mut T, + inner.end as *const T, + inner.cap, + ) + }; + // use try-fold since + // - it vectorizes better for some iterator adapters + // - unlike most internal iteration methods, it only takes a &mut self + // - it lets us thread the write pointer through its innards and get it back in the end + let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf }; + let sink = iterator + .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end)) + .unwrap(); + // iteration succeeded, don't drop head + let dst = ManuallyDrop::new(sink).dst; + + let src = unsafe { iterator.as_inner().as_into_iter() }; + // check if SourceIter contract was upheld + // caveat: if they weren't we may not even make it to this point + debug_assert_eq!(src_buf, src.buf.as_ptr()); + // check InPlaceIterable contract. This is only possible if the iterator advanced the + // source pointer at all. If it uses unchecked access via TrustedRandomAccess + // then the source pointer will stay in its initial position and we can't use it as reference + if src.ptr != src_ptr { + debug_assert!( + dst as *const _ <= src.ptr, + "InPlaceIterable contract violation, write pointer advanced beyond read pointer" + ); + } + + // drop any remaining values at the tail of the source + src.drop_remaining(); + // but prevent drop of the allocation itself once IntoIter goes out of scope + src.forget_allocation(); + + let vec = unsafe { + let len = dst.offset_from(dst_buf) as usize; + Vec::from_raw_parts(dst_buf, len, cap) + }; + + vec + } +} + +impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec +where + I: Iterator, + T: Clone, +{ + default fn from_iter(iterator: I) -> Self { + SpecFromIter::from_iter(iterator.cloned()) + } +} + +impl<'a, T: 'a> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec +where + T: Copy, +{ + // reuses the extend specialization for T: Copy + fn from_iter(iterator: slice::Iter<'a, T>) -> Self { + let mut vec = Vec::new(); + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs + vec.spec_extend(iterator); + vec + } +} + +// Specialization trait used for Vec::extend +trait SpecExtend { + fn spec_extend(&mut self, iter: I); +} + +impl SpecExtend for Vec +where + I: Iterator, +{ + default fn spec_extend(&mut self, iter: I) { + self.extend_desugared(iter) + } +} + +impl SpecExtend for Vec +where + I: TrustedLen, +{ default fn spec_extend(&mut self, iterator: I) { // This is the case for a TrustedLen iterator. let (low, high) = iterator.size_hint(); @@ -2176,22 +2389,6 @@ where } impl SpecExtend> for Vec { - fn from_iter(iterator: IntoIter) -> Self { - // A common case is passing a vector into a function which immediately - // re-collects into a vector. We can short circuit this if the IntoIter - // has not been advanced at all. - if iterator.buf.as_ptr() as *const _ == iterator.ptr { - unsafe { - let it = ManuallyDrop::new(iterator); - Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap) - } - } else { - let mut vector = Vec::new(); - vector.spec_extend(iterator); - vector - } - } - fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); @@ -2205,10 +2402,6 @@ where I: Iterator, T: Clone, { - default fn from_iter(iterator: I) -> Self { - SpecExtend::from_iter(iterator.cloned()) - } - default fn spec_extend(&mut self, iterator: I) { self.spec_extend(iterator.cloned()) } @@ -2220,17 +2413,13 @@ where { fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { let slice = iterator.as_slice(); - self.reserve(slice.len()); - unsafe { - let len = self.len(); - let dst_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(len), slice.len()); - dst_slice.copy_from_slice(slice); - self.set_len(len + slice.len()); - } + unsafe { self.append_elements(slice) }; } } impl Vec { + // leaf method to which various SpecFrom/SpecExtend implementations delegate when + // they have no further optimizations to apply fn extend_desugared>(&mut self, mut iterator: I) { // This is the case for a general iterator. // @@ -2564,6 +2753,57 @@ impl From<&str> for Vec { } } +#[stable(feature = "array_try_from_vec", since = "1.48.0")] +impl TryFrom> for [T; N] { + type Error = Vec; + + /// Gets the entire contents of the `Vec` as an array, + /// if its size exactly matches that of the requested array. + /// + /// # Examples + /// + /// ``` + /// use std::convert::TryInto; + /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3])); + /// assert_eq!(>::new().try_into(), Ok([])); + /// ``` + /// + /// If the length doesn't match, the input comes back in `Err`: + /// ``` + /// use std::convert::TryInto; + /// let r: Result<[i32; 4], _> = (0..10).collect::>().try_into(); + /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); + /// ``` + /// + /// If you're fine with just getting a prefix of the `Vec`, + /// you can call [`.truncate(N)`](Vec::truncate) first. + /// ``` + /// use std::convert::TryInto; + /// let mut v = String::from("hello world").into_bytes(); + /// v.sort(); + /// v.truncate(2); + /// let [a, b]: [_; 2] = v.try_into().unwrap(); + /// assert_eq!(a, b' '); + /// assert_eq!(b, b'd'); + /// ``` + fn try_from(mut vec: Vec) -> Result<[T; N], Vec> { + if vec.len() != N { + return Err(vec); + } + + // SAFETY: `.set_len(0)` is always sound. + unsafe { vec.set_len(0) }; + + // SAFETY: A `Vec`'s pointer is always aligned properly, and + // the alignment the array needs is the same as the items. + // We checked earlier that we have sufficient items. + // The items will not double-drop as the `set_len` + // tells the `Vec` not to also drop them. + let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) }; + Ok(array) + } +} + //////////////////////////////////////////////////////////////////////////////// // Clone-on-write //////////////////////////////////////////////////////////////////////////////// @@ -2607,6 +2847,13 @@ where /// /// This `struct` is created by the `into_iter` method on [`Vec`] (provided /// by the [`IntoIterator`] trait). +/// +/// # Example +/// +/// ``` +/// let v = vec![0, 1, 2]; +/// let iter: std::vec::IntoIter<_> = v.into_iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { buf: NonNull, @@ -2661,6 +2908,22 @@ impl IntoIter { fn as_raw_mut_slice(&mut self) -> *mut [T] { ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) } + + fn drop_remaining(&mut self) { + unsafe { + ptr::drop_in_place(self.as_mut_slice()); + } + self.ptr = self.end; + } + + /// Relinquishes the backing allocation, equivalent to + /// `ptr::write(&mut self, Vec::new().into_iter())` + fn forget_allocation(&mut self) { + self.cap = 0; + self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) }; + self.ptr = self.buf.as_ptr(); + self.end = self.buf.as_ptr(); + } } #[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] @@ -2681,25 +2944,21 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - unsafe { - if self.ptr as *const _ == 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 = arith_offset(self.ptr as *const i8, 1) as *mut T; - - // Make up a value of this ZST. - Some(mem::zeroed()) - } else { - let old = self.ptr; - self.ptr = self.ptr.offset(1); - - Some(ptr::read(old)) - } - } + if self.ptr as *const _ == 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 }; + + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + let old = self.ptr; + self.ptr = unsafe { self.ptr.offset(1) }; + + Some(unsafe { ptr::read(old) }) } } @@ -2717,28 +2976,41 @@ impl Iterator for IntoIter { fn count(self) -> usize { self.len() } + + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must guarantee that `i` is in bounds of the + // `Vec`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)` + // is guaranteed to pointer to an element of the `Vec` and + // thus guaranteed to be valid to dereference. + // + // Also note the implementation of `Self: TrustedRandomAccess` requires + // that `T: Copy` so reading elements from the buffer doesn't invalidate + // them for `Drop`. + unsafe { + if mem::size_of::() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } + } + } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { - unsafe { - if self.end == self.ptr { - None - } else { - if mem::size_of::() == 0 { - // See above for why 'ptr.offset' isn't used - self.end = arith_offset(self.end as *const i8, -1) as *mut T; + if self.end == self.ptr { + 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 }; - // Make up a value of this ZST. - Some(mem::zeroed()) - } else { - self.end = self.end.offset(-1); + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + self.end = unsafe { self.end.offset(-1) }; - Some(ptr::read(self.end)) - } - } + Some(unsafe { ptr::read(self.end) }) } } } @@ -2756,6 +3028,19 @@ impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for IntoIter {} +#[doc(hidden)] +#[unstable(issue = "none", feature = "std_internals")] +// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr +// and thus we can't implement drop-handling +unsafe impl TrustedRandomAccess for IntoIter +where + T: Copy, +{ + fn may_have_side_effect() -> bool { + false + } +} + #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl Clone for IntoIter { fn clone(&self) -> IntoIter { @@ -2784,9 +3069,45 @@ unsafe impl<#[may_dangle] T> Drop for IntoIter { } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for IntoIter {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for IntoIter { + type Source = IntoIter; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut Self::Source { + self + } +} + +// internal helper trait for in-place iteration specialization. +#[rustc_specialization_trait] +pub(crate) trait AsIntoIter { + type Item; + fn as_into_iter(&mut self) -> &mut IntoIter; +} + +impl AsIntoIter for IntoIter { + type Item = T; + + fn as_into_iter(&mut self) -> &mut IntoIter { + self + } +} + /// A draining iterator for `Vec`. /// /// This `struct` is created by [`Vec::drain`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::Drain<_> = v.drain(..); +/// ``` #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { /// Index of tail to preserve @@ -2916,6 +3237,14 @@ impl FusedIterator for Drain<'_, T> {} /// /// This struct is created by [`Vec::splice()`]. /// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let new = [7, 8]; +/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned()); +/// ``` #[derive(Debug)] #[stable(feature = "vec_splice", since = "1.21.0")] pub struct Splice<'a, I: Iterator + 'a> { @@ -3028,7 +3357,19 @@ impl Drain<'_, T> { } } -/// An iterator produced by calling `drain_filter` on Vec. +/// An iterator which uses a closure to determine if an element should be removed. +/// +/// This struct is created by [`Vec::drain_filter`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// #![feature(drain_filter)] +/// +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0); +/// ``` #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[derive(Debug)] pub struct DrainFilter<'a, T, F> @@ -3044,7 +3385,7 @@ where old_len: usize, /// The filter test predicate. pred: F, - /// A flag that indicates a panic has occurred in the filter test prodicate. + /// A flag that indicates a panic has occurred in the filter test predicate. /// This is used as a hint in the drop implementation to prevent consumption /// of the remainder of the `DrainFilter`. Any unprocessed items will be /// backshifted in the `vec`, but no further items will be dropped or diff --git a/library/alloc/tests/binary_heap.rs b/library/alloc/tests/binary_heap.rs index 62084ccf53..ce794a9a4a 100644 --- a/library/alloc/tests/binary_heap.rs +++ b/library/alloc/tests/binary_heap.rs @@ -230,6 +230,18 @@ fn test_to_vec() { check_to_vec(vec![5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]); } +#[test] +fn test_in_place_iterator_specialization() { + let src: Vec = vec![1, 2, 3]; + let src_ptr = src.as_ptr(); + let heap: BinaryHeap<_> = src.into_iter().map(std::convert::identity).collect(); + let heap_ptr = heap.iter().next().unwrap() as *const usize; + assert_eq!(src_ptr, heap_ptr); + let sink: Vec<_> = heap.into_iter().map(std::convert::identity).collect(); + let sink_ptr = sink.as_ptr(); + assert_eq!(heap_ptr, sink_ptr); +} + #[test] fn test_empty_pop() { let mut heap = BinaryHeap::::new(); diff --git a/library/alloc/tests/borrow.rs b/library/alloc/tests/borrow.rs index 8bfcf323f6..57976aa6cd 100644 --- a/library/alloc/tests/borrow.rs +++ b/library/alloc/tests/borrow.rs @@ -45,3 +45,16 @@ fn test_from_cow_path() { let path = Path::new("hello"); test_from_cow!(path: &Path); } + +#[test] +fn cow_const() { + // test that the methods of `Cow` are usable in a const context + + const COW: Cow<'_, str> = Cow::Borrowed("moo"); + + const IS_BORROWED: bool = COW.is_borrowed(); + assert!(IS_BORROWED); + + const IS_OWNED: bool = COW.is_owned(); + assert!(!IS_OWNED); +} diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index 851ca17a36..6a83f5da87 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -1,3 +1,4 @@ +use std::cell::Cell; use std::mem::MaybeUninit; use std::ptr::NonNull; @@ -49,3 +50,10 @@ fn box_clone_from_ptr_stability() { assert_eq!(copy.as_ptr() as usize, copy_raw); } } + +#[test] +fn box_deref_lval() { + let x = Box::new(Cell::new(5)); + x.set(1000); + assert_eq!(x.get(), 1000); +} diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs index 0ad092b499..757fddd241 100644 --- a/library/alloc/tests/fmt.rs +++ b/library/alloc/tests/fmt.rs @@ -1,7 +1,327 @@ -use std::fmt; +#![deny(warnings)] + +use std::cell::RefCell; +use std::fmt::{self, Write}; #[test] fn test_format() { let s = fmt::format(format_args!("Hello, {}!", "world")); assert_eq!(s, "Hello, world!"); } + +struct A; +struct B; +struct C; +struct D; + +impl fmt::LowerHex for A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("aloha") + } +} +impl fmt::UpperHex for B { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("adios") + } +} +impl fmt::Display for C { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad_integral(true, "☃", "123") + } +} +impl fmt::Binary for D { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("aa")?; + f.write_char('☃')?; + f.write_str("bb") + } +} + +macro_rules! t { + ($a:expr, $b:expr) => { + assert_eq!($a, $b) + }; +} + +#[test] +fn test_format_macro_interface() { + // Various edge cases without formats + t!(format!(""), ""); + t!(format!("hello"), "hello"); + t!(format!("hello {{"), "hello {"); + + // default formatters should work + t!(format!("{}", 1.0f32), "1"); + t!(format!("{}", 1.0f64), "1"); + t!(format!("{}", "a"), "a"); + t!(format!("{}", "a".to_string()), "a"); + t!(format!("{}", false), "false"); + t!(format!("{}", 'a'), "a"); + + // At least exercise all the formats + t!(format!("{}", true), "true"); + t!(format!("{}", '☃'), "☃"); + t!(format!("{}", 10), "10"); + t!(format!("{}", 10_usize), "10"); + t!(format!("{:?}", '☃'), "'☃'"); + t!(format!("{:?}", 10), "10"); + t!(format!("{:?}", 10_usize), "10"); + t!(format!("{:?}", "true"), "\"true\""); + t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); + t!( + format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), + r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""# + ); + t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), r#""foo\u{0}bar\u{1}baz\u{7f}qux""#); + t!(format!("{:o}", 10_usize), "12"); + t!(format!("{:x}", 10_usize), "a"); + t!(format!("{:X}", 10_usize), "A"); + t!(format!("{}", "foo"), "foo"); + t!(format!("{}", "foo".to_string()), "foo"); + if cfg!(target_pointer_width = "32") { + t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234"); + t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234"); + } else { + t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234"); + t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234"); + } + t!(format!("{:p}", 0x1234 as *const isize), "0x1234"); + t!(format!("{:p}", 0x1234 as *mut isize), "0x1234"); + t!(format!("{:x}", A), "aloha"); + t!(format!("{:X}", B), "adios"); + t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); + t!(format!("{1} {0}", 0, 1), "1 0"); + t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1"); + t!(format!("{foo} {1} {bar} {0}", 0, 1, foo = 2, bar = 3), "2 1 3 0"); + t!(format!("{} {0}", "a"), "a a"); + t!(format!("{_foo}", _foo = 6usize), "6"); + t!(format!("{foo_bar}", foo_bar = 1), "1"); + t!(format!("{}", 5 + 5), "10"); + t!(format!("{:#4}", C), "☃123"); + t!(format!("{:b}", D), "aa☃bb"); + + let a: &dyn fmt::Debug = &1; + t!(format!("{:?}", a), "1"); + + // Formatting strings and their arguments + t!(format!("{}", "a"), "a"); + t!(format!("{:4}", "a"), "a "); + t!(format!("{:4}", "☃"), "☃ "); + t!(format!("{:>4}", "a"), " a"); + t!(format!("{:<4}", "a"), "a "); + t!(format!("{:^5}", "a"), " a "); + t!(format!("{:^5}", "aa"), " aa "); + t!(format!("{:^4}", "a"), " a "); + t!(format!("{:^4}", "aa"), " aa "); + t!(format!("{:.4}", "a"), "a"); + t!(format!("{:4.4}", "a"), "a "); + t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), " aaaa"); + t!(format!("{:2.4}", "aaaaa"), "aaaa"); + t!(format!("{:2.4}", "aaaa"), "aaaa"); + t!(format!("{:2.4}", "aaa"), "aaa"); + t!(format!("{:2.4}", "aa"), "aa"); + t!(format!("{:2.4}", "a"), "a "); + t!(format!("{:0>2}", "a"), "0a"); + t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); + t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4), "aaaa"); + t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4), "aaaa"); + t!(format!("{:1$}", "a", 4), "a "); + t!(format!("{1:0$}", 4, "a"), "a "); + t!(format!("{:a$}", "a", a = 4), "a "); + t!(format!("{:-#}", "a"), "a"); + t!(format!("{:+#}", "a"), "a"); + t!(format!("{:/^10.8}", "1234567890"), "/12345678/"); + + // Some float stuff + t!(format!("{:}", 1.0f32), "1"); + t!(format!("{:}", 1.0f64), "1"); + t!(format!("{:.3}", 1.0f64), "1.000"); + t!(format!("{:10.3}", 1.0f64), " 1.000"); + t!(format!("{:+10.3}", 1.0f64), " +1.000"); + t!(format!("{:+10.3}", -1.0f64), " -1.000"); + + t!(format!("{:e}", 1.2345e6f32), "1.2345e6"); + t!(format!("{:e}", 1.2345e6f64), "1.2345e6"); + t!(format!("{:E}", 1.2345e6f64), "1.2345E6"); + t!(format!("{:.3e}", 1.2345e6f64), "1.234e6"); + t!(format!("{:10.3e}", 1.2345e6f64), " 1.234e6"); + t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6"); + t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); + + // Float edge cases + t!(format!("{}", -0.0), "0"); + t!(format!("{:?}", -0.0), "-0.0"); + t!(format!("{:?}", 0.0), "0.0"); + + // sign aware zero padding + t!(format!("{:<3}", 1), "1 "); + t!(format!("{:>3}", 1), " 1"); + t!(format!("{:^3}", 1), " 1 "); + t!(format!("{:03}", 1), "001"); + t!(format!("{:<03}", 1), "001"); + t!(format!("{:>03}", 1), "001"); + t!(format!("{:^03}", 1), "001"); + t!(format!("{:+03}", 1), "+01"); + t!(format!("{:<+03}", 1), "+01"); + t!(format!("{:>+03}", 1), "+01"); + t!(format!("{:^+03}", 1), "+01"); + t!(format!("{:#05x}", 1), "0x001"); + t!(format!("{:<#05x}", 1), "0x001"); + t!(format!("{:>#05x}", 1), "0x001"); + t!(format!("{:^#05x}", 1), "0x001"); + t!(format!("{:05}", 1.2), "001.2"); + t!(format!("{:<05}", 1.2), "001.2"); + t!(format!("{:>05}", 1.2), "001.2"); + t!(format!("{:^05}", 1.2), "001.2"); + t!(format!("{:05}", -1.2), "-01.2"); + t!(format!("{:<05}", -1.2), "-01.2"); + t!(format!("{:>05}", -1.2), "-01.2"); + t!(format!("{:^05}", -1.2), "-01.2"); + t!(format!("{:+05}", 1.2), "+01.2"); + t!(format!("{:<+05}", 1.2), "+01.2"); + t!(format!("{:>+05}", 1.2), "+01.2"); + t!(format!("{:^+05}", 1.2), "+01.2"); + + // Ergonomic format_args! + t!(format!("{0:x} {0:X}", 15), "f F"); + t!(format!("{0:x} {0:X} {}", 15), "f F 15"); + t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a = 15), "dDfEeF"); + t!(format!("{a:x} {a:X}", a = 15), "f F"); + + // And its edge cases + t!( + format!( + "{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}", + 4, + a = "abcdefg", + b = "hijklmn", + c = 3 + ), + "abcd hijk 4\nabc hij 3" + ); + t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a = "abcdef"), "abcd 4 efg"); + t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a = 2), "aa 2 0x2"); + + // Test that pointers don't get truncated. + { + let val = usize::MAX; + let exp = format!("{:#x}", val); + t!(format!("{:p}", val as *const isize), exp); + } + + // Escaping + t!(format!("{{"), "{"); + t!(format!("}}"), "}"); + + // make sure that format! doesn't move out of local variables + let a = Box::new(3); + format!("{}", a); + format!("{}", a); + + // make sure that format! doesn't cause spurious unused-unsafe warnings when + // it's inside of an outer unsafe block + unsafe { + let a: isize = ::std::mem::transmute(3_usize); + format!("{}", a); + } + + // test that trailing commas are acceptable + format!("{}", "test",); + format!("{foo}", foo = "test",); +} + +// Basic test to make sure that we can invoke the `write!` macro with an +// fmt::Write instance. +#[test] +fn test_write() { + let mut buf = String::new(); + let _ = write!(&mut buf, "{}", 3); + { + let w = &mut buf; + let _ = write!(w, "{foo}", foo = 4); + let _ = write!(w, "{}", "hello"); + let _ = writeln!(w, "{}", "line"); + let _ = writeln!(w, "{foo}", foo = "bar"); + let _ = w.write_char('☃'); + let _ = w.write_str("str"); + } + + t!(buf, "34helloline\nbar\n☃str"); +} + +// Just make sure that the macros are defined, there's not really a lot that we +// can do with them just yet (to test the output) +#[test] +fn test_print() { + print!("hi"); + print!("{:?}", vec![0u8]); + println!("hello"); + println!("this is a {}", "test"); + println!("{foo}", foo = "bar"); +} + +// Just make sure that the macros are defined, there's not really a lot that we +// can do with them just yet (to test the output) +#[test] +fn test_format_args() { + let mut buf = String::new(); + { + let w = &mut buf; + let _ = write!(w, "{}", format_args!("{}", 1)); + let _ = write!(w, "{}", format_args!("test")); + let _ = write!(w, "{}", format_args!("{test}", test = 3)); + } + let s = buf; + t!(s, "1test3"); + + let s = fmt::format(format_args!("hello {}", "world")); + t!(s, "hello world"); + let s = format!("{}: {}", "args were", format_args!("hello {}", "world")); + t!(s, "args were: hello world"); +} + +#[test] +fn test_order() { + // Make sure format!() arguments are always evaluated in a left-to-right + // ordering + fn foo() -> isize { + static mut FOO: isize = 0; + unsafe { + FOO += 1; + FOO + } + } + assert_eq!( + format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()), + "1 2 4 5 3 6".to_string() + ); +} + +#[test] +fn test_once() { + // Make sure each argument are evaluated only once even though it may be + // formatted multiple times + fn foo() -> isize { + static mut FOO: isize = 0; + unsafe { + FOO += 1; + FOO + } + } + assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string()); +} + +#[test] +fn test_refcell() { + let refcell = RefCell::new(5); + assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }"); + let borrow = refcell.borrow_mut(); + assert_eq!(format!("{:?}", refcell), "RefCell { value: }"); + drop(borrow); + assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }"); +} diff --git a/library/alloc/tests/heap.rs b/library/alloc/tests/heap.rs index cbde2a7e28..a7239a4b14 100644 --- a/library/alloc/tests/heap.rs +++ b/library/alloc/tests/heap.rs @@ -11,7 +11,7 @@ fn std_heap_overaligned_request() { check_overalign_requests(Global) } -fn check_overalign_requests(mut allocator: T) { +fn check_overalign_requests(allocator: T) { for &align in &[4, 8, 16, 32] { // less than and bigger than `MIN_ALIGN` for &size in &[align / 2, align - 1] { diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index f2ba1ab648..cff8ff9ac7 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,5 +1,7 @@ #![feature(allocator_api)] #![feature(box_syntax)] +#![feature(cow_is_borrowed)] +#![feature(const_cow_is_borrowed)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(new_uninit)] @@ -14,6 +16,10 @@ #![feature(slice_ptr_get)] #![feature(split_inclusive)] #![feature(binary_heap_retain)] +#![feature(deque_range)] +#![feature(inplace_iteration)] +#![feature(iter_map_while)] +#![feature(int_bits_const)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 3c7d57f8b3..1f561bebd9 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1459,6 +1459,15 @@ fn test_to_vec() { assert_eq!(ys, [1, 2, 3]); } +#[test] +fn test_in_place_iterator_specialization() { + let src: Box<[usize]> = box [1, 2, 3]; + let src_ptr = src.as_ptr(); + let sink: Box<_> = src.into_vec().into_iter().map(std::convert::identity).collect(); + let sink_ptr = sink.as_ptr(); + assert_eq!(src_ptr, sink_ptr); +} + #[test] fn test_box_slice_clone() { let data = vec![vec![0, 1], vec![0], vec![1]]; diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index b20cf076ac..ed8ee2d882 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1921,3 +1921,24 @@ fn different_str_pattern_forwarding_lifetimes() { foo::<&str>("x"); } + +#[test] +fn test_str_multiline() { + let a: String = "this \ +is a test" + .to_string(); + let b: String = "this \ + is \ + another \ + test" + .to_string(); + assert_eq!(a, "this is a test".to_string()); + assert_eq!(b, "this is another test".to_string()); +} + +#[test] +fn test_str_escapes() { + let x = "\\\\\ + "; + assert_eq!(x, r"\\"); // extraneous whitespace stripped +} diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index d38655af78..a6e41b21b6 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::collections::TryReserveError::*; -use std::mem::size_of; +use std::ops::Bound::*; pub trait IntoCow<'a, B: ?Sized> where @@ -271,24 +271,28 @@ fn test_split_off_past_end() { #[test] #[should_panic] fn test_split_off_mid_char() { - let mut orig = String::from("山"); - let _ = orig.split_off(1); + let mut shan = String::from("山"); + let _broken_mountain = shan.split_off(1); } #[test] fn test_split_off_ascii() { let mut ab = String::from("ABCD"); + let orig_capacity = ab.capacity(); let cd = ab.split_off(2); assert_eq!(ab, "AB"); assert_eq!(cd, "CD"); + assert_eq!(ab.capacity(), orig_capacity); } #[test] fn test_split_off_unicode() { let mut nihon = String::from("日本語"); + let orig_capacity = nihon.capacity(); let go = nihon.split_off("日本".len()); assert_eq!(nihon, "日本"); assert_eq!(go, "語"); + assert_eq!(nihon.capacity(), orig_capacity); } #[test] @@ -463,6 +467,20 @@ fn test_drain() { assert_eq!(t, ""); } +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut s = String::from("abc"); + s.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut s = String::from("abc"); + s.drain((Included(0), Included(usize::MAX))); +} + #[test] fn test_replace_range() { let mut s = "Hello, world!".to_owned(); @@ -500,6 +518,20 @@ fn test_replace_range_inclusive_out_of_bounds() { s.replace_range(5..=5, "789"); } +#[test] +#[should_panic] +fn test_replace_range_start_overflow() { + let mut s = String::from("123"); + s.replace_range((Excluded(usize::MAX), Included(0)), ""); +} + +#[test] +#[should_panic] +fn test_replace_range_end_overflow() { + let mut s = String::from("456"); + s.replace_range((Included(0), Included(usize::MAX)), ""); +} + #[test] fn test_replace_range_empty() { let mut s = String::from("12345"); @@ -572,7 +604,7 @@ fn test_try_reserve() { // 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; + let guards_against_isize = usize::BITS < 64; { // Note: basic stuff is checked by test_reserve @@ -653,7 +685,7 @@ 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 guards_against_isize = usize::BITS < 64; { let mut empty_string: String = String::new(); @@ -721,3 +753,11 @@ fn test_from_char() { let s: String = 'x'.into(); assert_eq!(s, 'x'.to_string()); } + +#[test] +fn test_str_concat() { + let a: String = "hello".to_string(); + let b: String = "world".to_string(); + let s: String = format!("{}{}", a, b); + assert_eq!(s.as_bytes()[9], 'd' as u8); +} diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index ffff543b07..b7c7138db4 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1,8 +1,12 @@ use std::borrow::Cow; +use std::cell::Cell; use std::collections::TryReserveError::*; use std::fmt::Debug; +use std::iter::InPlaceIterable; use std::mem::size_of; +use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::rc::Rc; use std::vec::{Drain, IntoIter}; struct DropCounter<'a> { @@ -72,6 +76,42 @@ fn test_zst_capacity() { assert_eq!(Vec::<()>::new().capacity(), usize::MAX); } +#[test] +fn test_indexing() { + let v: Vec = vec![10, 20]; + assert_eq!(v[0], 10); + assert_eq!(v[1], 20); + let mut x: usize = 0; + assert_eq!(v[x], 10); + assert_eq!(v[x + 1], 20); + x = x + 1; + assert_eq!(v[x], 20); + assert_eq!(v[x - 1], 10); +} + +#[test] +fn test_debug_fmt() { + let vec1: Vec = vec![]; + assert_eq!("[]", format!("{:?}", vec1)); + + let vec2 = vec![0, 1]; + assert_eq!("[0, 1]", format!("{:?}", vec2)); + + let slice: &[isize] = &[4, 5]; + assert_eq!("[4, 5]", format!("{:?}", slice)); +} + +#[test] +fn test_push() { + let mut v = vec![]; + v.push(1); + assert_eq!(v, [1]); + v.push(2); + assert_eq!(v, [1, 2]); + v.push(3); + assert_eq!(v, [1, 2, 3]); +} + #[test] fn test_extend() { let mut v = Vec::new(); @@ -117,6 +157,18 @@ fn test_extend() { assert_eq!(count_x, 1); } +#[test] +fn test_extend_from_slice() { + let a: Vec = vec![1, 2, 3, 4, 5]; + let b: Vec = vec![6, 7, 8, 9, 0]; + + let mut v: Vec = a; + + v.extend_from_slice(&b); + + assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); +} + #[test] fn test_extend_ref() { let mut v = vec![1, 2]; @@ -132,6 +184,14 @@ fn test_extend_ref() { assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]); } +#[test] +fn test_slice_from_ref() { + let values = vec![1, 2, 3, 4, 5]; + let slice = &values[1..3]; + + assert_eq!(slice, [2, 3]); +} + #[test] fn test_slice_from_mut() { let mut values = vec![1, 2, 3, 4, 5]; @@ -343,6 +403,29 @@ fn test_zip_unzip() { assert_eq!((3, 6), (left[2], right[2])); } +#[test] +fn test_cmp() { + let x: &[isize] = &[1, 2, 3, 4, 5]; + let cmp: &[isize] = &[1, 2, 3, 4, 5]; + assert_eq!(&x[..], cmp); + let cmp: &[isize] = &[3, 4, 5]; + assert_eq!(&x[2..], cmp); + let cmp: &[isize] = &[1, 2, 3]; + assert_eq!(&x[..3], cmp); + let cmp: &[isize] = &[2, 3, 4]; + assert_eq!(&x[1..4], cmp); + + let x: Vec = vec![1, 2, 3, 4, 5]; + let cmp: &[isize] = &[1, 2, 3, 4, 5]; + assert_eq!(&x[..], cmp); + let cmp: &[isize] = &[3, 4, 5]; + assert_eq!(&x[2..], cmp); + let cmp: &[isize] = &[1, 2, 3]; + assert_eq!(&x[..3], cmp); + let cmp: &[isize] = &[2, 3, 4]; + assert_eq!(&x[1..4], cmp); +} + #[test] fn test_vec_truncate_drop() { static mut DROPS: u32 = 0; @@ -564,6 +647,16 @@ fn test_drain_max_vec_size() { assert_eq!(v.len(), usize::MAX - 1); } +#[test] +#[should_panic] +fn test_drain_index_overflow() { + let mut v = Vec::<()>::with_capacity(usize::MAX); + unsafe { + v.set_len(usize::MAX); + } + v.drain(0..=usize::MAX); +} + #[test] #[should_panic] fn test_drain_inclusive_out_of_bounds() { @@ -571,6 +664,20 @@ fn test_drain_inclusive_out_of_bounds() { v.drain(5..=5); } +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Included(0), Included(usize::MAX))); +} + #[test] fn test_drain_leak() { static mut DROPS: i32 = 0; @@ -691,9 +798,23 @@ fn test_append() { #[test] fn test_split_off() { let mut vec = vec![1, 2, 3, 4, 5, 6]; + let orig_capacity = vec.capacity(); let vec2 = vec.split_off(4); assert_eq!(vec, [1, 2, 3, 4]); assert_eq!(vec2, [5, 6]); + assert_eq!(vec.capacity(), orig_capacity); +} + +#[test] +fn test_split_off_take_all() { + let mut vec = vec![1, 2, 3, 4, 5, 6]; + let orig_ptr = vec.as_ptr(); + let orig_capacity = vec.capacity(); + let vec2 = vec.split_off(0); + assert_eq!(vec, []); + assert_eq!(vec2, [1, 2, 3, 4, 5, 6]); + assert_eq!(vec.capacity(), orig_capacity); + assert_eq!(vec2.as_ptr(), orig_ptr); } #[test] @@ -775,6 +896,87 @@ fn test_into_iter_leak() { assert_eq!(unsafe { DROPS }, 3); } +#[test] +fn test_from_iter_specialization() { + let src: Vec = vec![0usize; 1]; + let srcptr = src.as_ptr(); + let sink = src.into_iter().collect::>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr); +} + +#[test] +fn test_from_iter_partially_drained_in_place_specialization() { + let src: Vec = vec![0usize; 10]; + let srcptr = src.as_ptr(); + let mut iter = src.into_iter(); + iter.next(); + iter.next(); + let sink = iter.collect::>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr); +} + +#[test] +fn test_from_iter_specialization_with_iterator_adapters() { + fn assert_in_place_trait(_: &T) {}; + let src: Vec = vec![0usize; 256]; + let srcptr = src.as_ptr(); + let iter = src + .into_iter() + .enumerate() + .map(|i| i.0 + i.1) + .zip(std::iter::repeat(1usize)) + .map(|(a, b)| a + b) + .map_while(Option::Some) + .peekable() + .skip(1) + .map(|e| std::num::NonZeroUsize::new(e)); + assert_in_place_trait(&iter); + let sink = iter.collect::>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr as *const usize); +} + +#[test] +fn test_from_iter_specialization_head_tail_drop() { + let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); + let src: Vec<_> = drop_count.iter().cloned().collect(); + let srcptr = src.as_ptr(); + let iter = src.into_iter(); + let sink: Vec<_> = iter.skip(1).take(1).collect(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr, "specialization was applied"); + assert_eq!(Rc::strong_count(&drop_count[0]), 1, "front was dropped"); + assert_eq!(Rc::strong_count(&drop_count[1]), 2, "one element was collected"); + assert_eq!(Rc::strong_count(&drop_count[2]), 1, "tail was dropped"); + assert_eq!(sink.len(), 1); +} + +#[test] +fn test_from_iter_specialization_panic_drop() { + let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); + let src: Vec<_> = drop_count.iter().cloned().collect(); + let iter = src.into_iter(); + + let _ = std::panic::catch_unwind(AssertUnwindSafe(|| { + let _ = iter + .enumerate() + .filter_map(|(i, e)| { + if i == 1 { + std::panic!("aborting iteration"); + } + Some(e) + }) + .collect::>(); + })); + + assert!( + drop_count.iter().map(Rc::strong_count).all(|count| count == 1), + "all items were dropped once" + ); +} + #[test] fn test_cow_from() { let borrowed: &[_] = &["borrowed", "(slice)"]; @@ -1140,7 +1342,7 @@ fn test_try_reserve() { // 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; + let guards_against_isize = usize::BITS < 64; { // Note: basic stuff is checked by test_reserve @@ -1349,6 +1551,9 @@ fn test_stable_pointers() { // Test that, if we reserved enough space, adding and removing elements does not // invalidate references into the vector (such as `v0`). This test also // runs in Miri, which would detect such problems. + // Note that this test does *not* constitute a stable guarantee that all these functions do not + // reallocate! Only what is explicitly documented at + // is stably guaranteed. let mut v = Vec::with_capacity(128); v.push(13); @@ -1627,3 +1832,82 @@ fn partialeq_vec_full() { assert_partial_eq_valid!(vec2,vec3; array2,array3); assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3); } + +#[test] +fn test_vec_cycle() { + #[derive(Debug)] + struct C<'a> { + v: Vec>>>, + } + + impl<'a> C<'a> { + fn new() -> C<'a> { + C { v: Vec::new() } + } + } + + let mut c1 = C::new(); + let mut c2 = C::new(); + let mut c3 = C::new(); + + // Push + c1.v.push(Cell::new(None)); + c1.v.push(Cell::new(None)); + + c2.v.push(Cell::new(None)); + c2.v.push(Cell::new(None)); + + c3.v.push(Cell::new(None)); + c3.v.push(Cell::new(None)); + + // Set + c1.v[0].set(Some(&c2)); + c1.v[1].set(Some(&c3)); + + c2.v[0].set(Some(&c2)); + c2.v[1].set(Some(&c3)); + + c3.v[0].set(Some(&c1)); + c3.v[1].set(Some(&c2)); +} + +#[test] +fn test_vec_cycle_wrapped() { + struct Refs<'a> { + v: Vec>>>, + } + + struct C<'a> { + refs: Refs<'a>, + } + + impl<'a> Refs<'a> { + fn new() -> Refs<'a> { + Refs { v: Vec::new() } + } + } + + impl<'a> C<'a> { + fn new() -> C<'a> { + C { refs: Refs::new() } + } + } + + let mut c1 = C::new(); + let mut c2 = C::new(); + let mut c3 = C::new(); + + c1.refs.v.push(Cell::new(None)); + c1.refs.v.push(Cell::new(None)); + c2.refs.v.push(Cell::new(None)); + c2.refs.v.push(Cell::new(None)); + c3.refs.v.push(Cell::new(None)); + c3.refs.v.push(Cell::new(None)); + + c1.refs.v[0].set(Some(&c2)); + c1.refs.v[1].set(Some(&c3)); + c2.refs.v[0].set(Some(&c2)); + c2.refs.v[1].set(Some(&c3)); + c3.refs.v[0].set(Some(&c1)); + c3.refs.v[1].set(Some(&c2)); +} diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 762dc4be44..46d8a3c4cb 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -2,6 +2,7 @@ use std::collections::TryReserveError::*; 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}; use crate::hash; @@ -115,6 +116,20 @@ fn test_index_out_of_bounds() { deq[3]; } +#[test] +#[should_panic] +fn test_range_start_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Included(0), Included(usize::MAX))); +} + +#[test] +#[should_panic] +fn test_range_end_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Excluded(usize::MAX), Included(0))); +} + #[derive(Clone, PartialEq, Debug)] enum Taggy { One(i32), diff --git a/library/core/benches/num/flt2dec/strategy/dragon.rs b/library/core/benches/num/flt2dec/strategy/dragon.rs index 4e1fd8bf75..319b9773e4 100644 --- a/library/core/benches/num/flt2dec/strategy/dragon.rs +++ b/library/core/benches/num/flt2dec/strategy/dragon.rs @@ -1,59 +1,76 @@ use super::super::*; use core::num::flt2dec::strategy::dragon::*; +use std::mem::MaybeUninit; use test::Bencher; #[bench] fn bench_small_shortest(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; MAX_SIG_DIGITS]; - b.iter(|| format_shortest(&decoded, &mut buf)); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(&decoded, &mut buf); + }); } #[bench] fn bench_big_shortest(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; MAX_SIG_DIGITS]; - b.iter(|| format_shortest(&decoded, &mut buf)); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(&decoded, &mut buf); + }); } #[bench] fn bench_small_exact_3(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 3]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_3(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 3]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_small_exact_12(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 12]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_12(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 12]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_small_exact_inf(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 1024]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_inf(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 1024]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } diff --git a/library/core/benches/num/flt2dec/strategy/grisu.rs b/library/core/benches/num/flt2dec/strategy/grisu.rs index 77ca901a90..76425731e1 100644 --- a/library/core/benches/num/flt2dec/strategy/grisu.rs +++ b/library/core/benches/num/flt2dec/strategy/grisu.rs @@ -1,5 +1,6 @@ use super::super::*; use core::num::flt2dec::strategy::grisu::*; +use std::mem::MaybeUninit; use test::Bencher; pub fn decode_finite(v: T) -> Decoded { @@ -12,55 +13,71 @@ pub fn decode_finite(v: T) -> Decoded { #[bench] fn bench_small_shortest(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; MAX_SIG_DIGITS]; - b.iter(|| format_shortest(&decoded, &mut buf)); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(&decoded, &mut buf); + }); } #[bench] fn bench_big_shortest(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; MAX_SIG_DIGITS]; - b.iter(|| format_shortest(&decoded, &mut buf)); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(&decoded, &mut buf); + }); } #[bench] fn bench_small_exact_3(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 3]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_3(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 3]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_small_exact_12(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 12]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_12(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 12]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_small_exact_inf(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 1024]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_inf(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 1024]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index a5ddf7619b..a3fbed2ec1 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -177,6 +177,7 @@ impl Layout { /// sentinel value. Types that lazily allocate must track initialization by /// some other means. #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[rustc_const_unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] pub const fn dangling(&self) -> NonNull { // SAFETY: align is guaranteed to be non-zero diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index ad4f8bf139..6d09b4f026 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -13,17 +13,17 @@ pub use self::layout::{Layout, LayoutErr}; use crate::fmt; use crate::ptr::{self, NonNull}; -/// The `AllocErr` error indicates an allocation failure +/// The `AllocError` error indicates an allocation failure /// that may be due to resource exhaustion or to /// something wrong when combining the given input arguments with this /// allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct AllocErr; +pub struct AllocError; // (we need this for downstream impl of trait Error) #[unstable(feature = "allocator_api", issue = "32838")] -impl fmt::Display for AllocErr { +impl fmt::Display for AllocError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("memory allocation failed") } @@ -109,7 +109,7 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + fn alloc(&self, layout: Layout) -> Result, AllocError>; /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized. /// @@ -126,7 +126,7 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { let ptr = self.alloc(layout)?; // SAFETY: `alloc` returns a valid memory block unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) } @@ -142,14 +142,13 @@ pub unsafe trait AllocRef { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout); /// Attempts to extend the memory block. /// /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated - /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s - /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the - /// allocation referenced by `ptr` to fit the new layout. + /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish + /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// transferred to this allocator. The memory may or may not have been freed, and should be @@ -163,11 +162,9 @@ pub unsafe trait AllocRef { /// /// # Safety /// - /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, - /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), - /// * `new_size` must be greater than or equal to `layout.size()`, and - /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow - /// (i.e., the rounded value must be less than or equal to `usize::MAX`). + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -186,30 +183,26 @@ pub unsafe trait AllocRef { /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn grow( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - let size = layout.size(); + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size >= size, - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_ptr = self.alloc(new_layout)?; - // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `size` bytes. Also, because the old - // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. + // SAFETY: because `new_layout.size()` must be greater than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), size); - self.dealloc(ptr, layout); + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); + self.dealloc(ptr, old_layout); } Ok(new_ptr) @@ -220,21 +213,19 @@ pub unsafe trait AllocRef { /// /// The memory block will contain the following contents after a successful call to /// `grow_zeroed`: - /// * Bytes `0..layout.size()` are preserved from the original allocation. - /// * Bytes `layout.size()..old_size` will either be preserved or zeroed, depending on the - /// allocator implementation. `old_size` refers to the size of the memory block prior to - /// the `grow_zeroed` call, which may be larger than the size that was originally requested - /// when it was allocated. + /// * Bytes `0..old_layout.size()` are preserved from the original allocation. + /// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on + /// the allocator implementation. `old_size` refers to the size of the memory block prior + /// to the `grow_zeroed` call, which may be larger than the size that was originally + /// requested when it was allocated. /// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory - /// block returned by the `grow` call. + /// block returned by the `grow_zeroed` call. /// /// # Safety /// - /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, - /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), - /// * `new_size` must be greater than or equal to `layout.size()`, and - /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow - /// (i.e., the rounded value must be less than or equal to `usize::MAX`). + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -253,30 +244,26 @@ pub unsafe trait AllocRef { /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - let size = layout.size(); + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size >= size, - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_ptr = self.alloc_zeroed(new_layout)?; - // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `size` bytes. Also, because the old - // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. + // SAFETY: because `new_layout.size()` must be greater than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), size); - self.dealloc(ptr, layout); + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); + self.dealloc(ptr, old_layout); } Ok(new_ptr) @@ -285,9 +272,8 @@ pub unsafe trait AllocRef { /// Attempts to shrink the memory block. /// /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated - /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s - /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the - /// allocation referenced by `ptr` to fit the new layout. + /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish + /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// transferred to this allocator. The memory may or may not have been freed, and should be @@ -301,9 +287,9 @@ pub unsafe trait AllocRef { /// /// # Safety /// - /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, - /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), and - /// * `new_size` must be smaller than or equal to `layout.size()`. + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`. /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -322,30 +308,26 @@ pub unsafe trait AllocRef { /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn shrink( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - let size = layout.size(); + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size <= size, - "`new_size` must be smaller than or equal to `layout.size()`" + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_ptr = self.alloc(new_layout)?; - // SAFETY: because `new_size` must be lower than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `new_size` bytes. Also, because the - // old allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. + // SAFETY: because `new_layout.size()` must be lower than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), size); - self.dealloc(ptr, layout); + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size()); + self.dealloc(ptr, old_layout); } Ok(new_ptr) @@ -355,62 +337,62 @@ pub unsafe trait AllocRef { /// /// The returned adaptor also implements `AllocRef` and will simply borrow this. #[inline(always)] - fn by_ref(&mut self) -> &mut Self { + fn by_ref(&self) -> &Self { self } } #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl AllocRef for &mut A +unsafe impl AllocRef for &A where A: AllocRef + ?Sized, { #[inline] - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocError> { (**self).alloc(layout) } #[inline] - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { (**self).alloc_zeroed(layout) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { // SAFETY: the safety contract must be upheld by the caller unsafe { (**self).dealloc(ptr, layout) } } #[inline] unsafe fn grow( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).grow(ptr, layout, new_size) } + unsafe { (**self).grow(ptr, old_layout, new_layout) } } #[inline] unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).grow_zeroed(ptr, layout, new_size) } + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } } #[inline] unsafe fn shrink( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).shrink(ptr, layout, new_size) } + unsafe { (**self).shrink(ptr, old_layout, new_layout) } } } diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 919070aadf..cafb002c01 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -73,7 +73,7 @@ impl IntoIter { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked(self.alive.clone()); - MaybeUninit::slice_get_ref(slice) + MaybeUninit::slice_assume_init_ref(slice) } } @@ -82,7 +82,7 @@ impl IntoIter { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked_mut(self.alive.clone()); - MaybeUninit::slice_get_mut(slice) + MaybeUninit::slice_assume_init_mut(slice) } } } @@ -103,7 +103,7 @@ impl Iterator for IntoIter { // dead now (i.e. do not touch). As `idx` was the start of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. - unsafe { self.data.get_unchecked(idx).read() } + unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } @@ -136,7 +136,7 @@ impl DoubleEndedIterator for IntoIter { // dead now (i.e. do not touch). As `idx` was the end of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. - unsafe { self.data.get_unchecked(idx).read() } + unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 88795d8429..966272ca11 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -19,6 +19,20 @@ mod iter; #[unstable(feature = "array_value_iter", issue = "65798")] pub use iter::IntoIter; +/// Converts a reference to `T` into a reference to an array of length 1 (without copying). +#[unstable(feature = "array_from_ref", issue = "77101")] +pub fn from_ref(s: &T) -> &[T; 1] { + // SAFETY: Converting `&T` to `&[T; 1]` is sound. + unsafe { &*(s as *const T).cast::<[T; 1]>() } +} + +/// Converts a mutable reference to `T` into a mutable reference to an array of length 1 (without copying). +#[unstable(feature = "array_from_ref", issue = "77101")] +pub fn from_mut(s: &mut T) -> &mut [T; 1] { + // SAFETY: Converting `&mut T` to `&mut [T; 1]` is sound. + unsafe { &mut *(s as *mut T).cast::<[T; 1]>() } +} + /// Utility trait implemented only on arrays of fixed size /// /// This trait can be used to implement other traits on fixed-size arrays @@ -362,7 +376,6 @@ macro_rules! array_impl_default { array_impl_default! {32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T} -#[cfg(not(bootstrap))] #[lang = "array"] impl [T; N] { /// Returns an array of the same size as `self`, with function `f` applied to each element @@ -411,7 +424,7 @@ impl [T; N] { } let mut dst = MaybeUninit::uninit_array::(); let mut guard: Guard = - Guard { dst: MaybeUninit::first_ptr_mut(&mut dst), initialized: 0 }; + Guard { dst: MaybeUninit::slice_as_mut_ptr(&mut dst), initialized: 0 }; for (src, dst) in IntoIter::new(self).zip(&mut dst) { dst.write(f(src)); guard.initialized += 1; @@ -423,4 +436,17 @@ impl [T; N] { // and we just need to cast it to the correct type. unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) } } + + /// Returns a slice containing the entire array. Equivalent to `&s[..]`. + #[unstable(feature = "array_methods", issue = "76118")] + pub fn as_slice(&self) -> &[T] { + self + } + + /// Returns a mutable slice containing the entire array. Equivalent to + /// `&mut s[..]`. + #[unstable(feature = "array_methods", issue = "76118")] + pub fn as_mut_slice(&mut self) -> &mut [T] { + self + } } diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index e78dfd1ed4..a8a25f9271 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -6,8 +6,6 @@ //! //! The [`escape_default`] function provides an iterator over the bytes of an //! escaped version of the character given. -//! -//! [`escape_default`]: fn.escape_default.html #![stable(feature = "core_ascii", since = "1.26.0")] @@ -20,8 +18,6 @@ use crate::str::from_utf8_unchecked; /// /// This `struct` is created by the [`escape_default`] function. See its /// documentation for more. -/// -/// [`escape_default`]: fn.escape_default.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct EscapeDefault { diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index cbbfcb4611..15ec13ca65 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -496,10 +496,7 @@ impl Cell { #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] pub fn get_mut(&mut self) -> &mut T { - // SAFETY: This can cause data races if called from a separate thread, - // but `Cell` is `!Sync` so this won't happen, and `&mut` guarantees - // unique access. - unsafe { &mut *self.value.get() } + self.value.get_mut() } /// Returns a `&Cell` from a `&mut T` @@ -700,6 +697,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "refcell_replace", since = "1.24.0")] + #[track_caller] pub fn replace(&self, t: T) -> T { mem::replace(&mut *self.borrow_mut(), t) } @@ -722,6 +720,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "refcell_replace_swap", since = "1.35.0")] + #[track_caller] pub fn replace_with T>(&self, f: F) -> T { let mut_borrow = &mut *self.borrow_mut(); let replacement = f(mut_borrow); @@ -945,8 +944,7 @@ impl RefCell { #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] pub fn get_mut(&mut self) -> &mut T { - // SAFETY: `&mut` guarantees unique access. - unsafe { &mut *self.value.get() } + self.value.get_mut() } /// Undo the effect of leaked guards on the borrow state of the `RefCell`. @@ -1056,6 +1054,7 @@ impl Clone for RefCell { /// /// Panics if the value is currently mutably borrowed. #[inline] + #[track_caller] fn clone(&self) -> RefCell { RefCell::new(self.borrow().clone()) } @@ -1543,8 +1542,11 @@ impl fmt::Display for RefMut<'_, T> { /// allow internal mutability, such as `Cell` and `RefCell`, use `UnsafeCell` to wrap their /// internal data. There is *no* legal way to obtain aliasing `&mut`, not even with `UnsafeCell`. /// -/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to -/// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly. +/// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer +/// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer +/// correctly. +/// +/// [`.get()`]: `UnsafeCell::get` /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// @@ -1571,21 +1573,70 @@ impl fmt::Display for RefMut<'_, T> { /// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T` /// co-exist with it. A `&mut T` must always be unique. /// -/// Note that while mutating or mutably aliasing the contents of an `&UnsafeCell` is -/// ok (provided you enforce the invariants some other way), it is still undefined behavior -/// to have multiple `&mut UnsafeCell` aliases. +/// Note that whilst mutating the contents of an `&UnsafeCell` (even while other +/// `&UnsafeCell` references alias the cell) is +/// ok (provided you enforce the above invariants some other way), it is still undefined behavior +/// to have multiple `&mut UnsafeCell` aliases. That is, `UnsafeCell` is a wrapper +/// designed to have a special interaction with _shared_ accesses (_i.e._, through an +/// `&UnsafeCell<_>` reference); there is no magic whatsoever when dealing with _exclusive_ +/// accesses (_e.g._, through an `&mut UnsafeCell<_>`): neither the cell nor the wrapped value +/// may be aliased for the duration of that `&mut` borrow. +/// This is showcased by the [`.get_mut()`] accessor, which is a non-`unsafe` getter that yields +/// a `&mut T`. +/// +/// [`.get_mut()`]: `UnsafeCell::get_mut` /// /// # Examples /// +/// Here is an example showcasing how to soundly mutate the contents of an `UnsafeCell<_>` despite +/// there being multiple references aliasing the cell: +/// /// ``` /// use std::cell::UnsafeCell; /// -/// # #[allow(dead_code)] -/// struct NotThreadSafe { -/// value: UnsafeCell, +/// let x: UnsafeCell = 42.into(); +/// // Get multiple / concurrent / shared references to the same `x`. +/// let (p1, p2): (&UnsafeCell, &UnsafeCell) = (&x, &x); +/// +/// unsafe { +/// // SAFETY: within this scope there are no other references to `x`'s contents, +/// // so ours is effectively unique. +/// let p1_exclusive: &mut i32 = &mut *p1.get(); // -- borrow --+ +/// *p1_exclusive += 27; // | +/// } // <---------- cannot go beyond this point -------------------+ +/// +/// unsafe { +/// // SAFETY: within this scope nobody expects to have exclusive access to `x`'s contents, +/// // so we can have multiple shared accesses concurrently. +/// let p2_shared: &i32 = &*p2.get(); +/// assert_eq!(*p2_shared, 42 + 27); +/// let p1_shared: &i32 = &*p1.get(); +/// assert_eq!(*p1_shared, *p2_shared); /// } +/// ``` +/// +/// The following example showcases the fact that exclusive access to an `UnsafeCell` +/// implies exclusive access to its `T`: +/// +/// ```rust +/// #![feature(unsafe_cell_get_mut)] +/// #![forbid(unsafe_code)] // with exclusive accesses, +/// // `UnsafeCell` is a transparent no-op wrapper, +/// // so no need for `unsafe` here. +/// use std::cell::UnsafeCell; +/// +/// let mut x: UnsafeCell = 42.into(); +/// +/// // Get a compile-time-checked unique reference to `x`. +/// let p_unique: &mut UnsafeCell = &mut x; +/// // With an exclusive reference, we can mutate the contents for free. +/// *p_unique.get_mut() = 0; +/// // Or, equivalently: +/// x = UnsafeCell::new(0); /// -/// unsafe impl Sync for NotThreadSafe {} +/// // When we own the value, we can extract the contents for free. +/// let contents: i32 = x.into_inner(); +/// assert_eq!(contents, 0); /// ``` #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1663,6 +1714,29 @@ impl UnsafeCell { self as *const UnsafeCell as *const T as *mut T } + /// Returns a mutable reference to the underlying data. + /// + /// This call borrows the `UnsafeCell` mutably (at compile-time) which + /// guarantees that we possess the only reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(unsafe_cell_get_mut)] + /// use std::cell::UnsafeCell; + /// + /// let mut c = UnsafeCell::new(5); + /// *c.get_mut() += 1; + /// + /// assert_eq!(*c.get_mut(), 6); + /// ``` + #[inline] + #[unstable(feature = "unsafe_cell_get_mut", issue = "76943")] + pub fn get_mut(&mut self) -> &mut T { + // SAFETY: (outer) `&mut` guarantees unique access. + unsafe { &mut *self.get() } + } + /// Gets a mutable pointer to the wrapped value. /// The difference to [`get`] is that this function accepts a raw pointer, /// which is useful to avoid the creation of temporary references. diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 7784ec687e..a953a3a418 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -7,11 +7,9 @@ //! contain owned boxes or implement [`Drop`]), so the compiler considers //! them cheap and safe to copy. For other types copies must be made //! explicitly, by convention implementing the [`Clone`] trait and calling -//! the [`clone`][clone] method. +//! the [`clone`] method. //! -//! [`Clone`]: trait.Clone.html -//! [clone]: trait.Clone.html#tymethod.clone -//! [`Drop`]: ../../std/ops/trait.Drop.html +//! [`clone`]: Clone::clone //! //! Basic usage example: //! @@ -51,7 +49,9 @@ /// ## Derivable /// /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d -/// implementation of [`clone`] calls [`clone`] on each field. +/// implementation of [`Clone`] calls [`clone`] on each field. +/// +/// [`clone`]: Clone::clone /// /// For a generic struct, `#[derive]` implements `Clone` conditionally by adding bound `Clone` on /// generic parameters. @@ -74,9 +74,6 @@ /// An example is a generic struct holding a function pointer. In this case, the /// implementation of `Clone` cannot be `derive`d, but can be implemented as: /// -/// [`Copy`]: ../../std/marker/trait.Copy.html -/// [`clone`]: trait.Clone.html#tymethod.clone -/// /// ``` /// struct Generate(fn() -> T); /// diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3953c73319..ee79a94cc6 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -356,8 +356,9 @@ impl Ordering { /// ``` #[inline] #[must_use] + #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn reverse(self) -> Ordering { + pub const fn reverse(self) -> Ordering { match self { Less => Greater, Equal => Equal, @@ -394,8 +395,9 @@ impl Ordering { /// ``` #[inline] #[must_use] + #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")] #[stable(feature = "ordering_chaining", since = "1.17.0")] - pub fn then(self, other: Ordering) -> Ordering { + pub const fn then(self, other: Ordering) -> Ordering { match self { Equal => other, _ => self, @@ -724,19 +726,19 @@ impl PartialOrd for Ordering { /// } /// /// impl PartialOrd for Person { -/// fn partial_cmp(&self, other: &Person) -> Option { +/// fn partial_cmp(&self, other: &Self) -> Option { /// Some(self.cmp(other)) /// } /// } /// /// impl Ord for Person { -/// fn cmp(&self, other: &Person) -> Ordering { +/// fn cmp(&self, other: &Self) -> Ordering { /// self.height.cmp(&other.height) /// } /// } /// /// impl PartialEq for Person { -/// fn eq(&self, other: &Person) -> bool { +/// fn eq(&self, other: &Self) -> bool { /// self.height == other.height /// } /// } diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index fcd07befae..2bfeb49b5f 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -31,13 +31,6 @@ //! `into` themselves and `from` themselves //! //! See each trait for usage examples. -//! -//! [`Into`]: trait.Into.html -//! [`From`]: trait.From.html -//! [`TryFrom`]: trait.TryFrom.html -//! [`TryInto`]: trait.TryInto.html -//! [`AsRef`]: trait.AsRef.html -//! [`AsMut`]: trait.AsMut.html #![stable(feature = "rust1", since = "1.0.0")] @@ -141,13 +134,11 @@ pub const fn identity(x: T) -> T { /// want to accept all references that can be converted to [`&str`] as an argument. /// Since both [`String`] and [`&str`] implement `AsRef` we can accept both as input argument. /// -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html -/// [`Borrow`]: ../../std/borrow/trait.Borrow.html -/// [`Hash`]: ../../std/hash/trait.Hash.html -/// [`Eq`]: ../../std/cmp/trait.Eq.html -/// [`Ord`]: ../../std/cmp/trait.Ord.html -/// [`&str`]: ../../std/primitive.str.html +/// [`Option`]: Option +/// [`Result`]: Result +/// [`Borrow`]: crate::borrow::Borrow +/// [`Eq`]: crate::cmp::Eq +/// [`Ord`]: crate::cmp::Ord /// [`String`]: ../../std/string/struct.String.html /// /// ``` @@ -177,8 +168,8 @@ pub trait AsRef { /// **Note: This trait must not fail**. If the conversion can fail, use a /// dedicated method which returns an [`Option`] or a [`Result`]. /// -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html +/// [`Option`]: Option +/// [`Result`]: Result /// /// # Generic Implementations /// @@ -278,12 +269,9 @@ pub trait AsMut { /// is_hello(s); /// ``` /// -/// [`TryInto`]: trait.TryInto.html -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html +/// [`Option`]: Option +/// [`Result`]: Result /// [`String`]: ../../std/string/struct.String.html -/// [`From`]: trait.From.html -/// [`Into`]: trait.Into.html /// [`Vec`]: ../../std/vec/struct.Vec.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { @@ -370,12 +358,10 @@ pub trait Into: Sized { /// } /// ``` /// -/// [`TryFrom`]: trait.TryFrom.html -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html +/// [`Option`]: Option +/// [`Result`]: Result /// [`String`]: ../../std/string/struct.String.html -/// [`Into`]: trait.Into.html -/// [`from`]: trait.From.html#tymethod.from +/// [`from`]: From::from /// [book]: ../../book/ch09-00-error-handling.html #[rustc_diagnostic_item = "from_trait"] #[stable(feature = "rust1", since = "1.0.0")] @@ -385,7 +371,7 @@ pub trait Into: Sized { ))] pub trait From: Sized { /// Performs the conversion. - #[cfg_attr(not(bootstrap), lang = "from")] + #[lang = "from"] #[stable(feature = "rust1", since = "1.0.0")] fn from(_: T) -> Self; } @@ -404,9 +390,6 @@ pub trait From: Sized { /// /// This suffers the same restrictions and reasoning as implementing /// [`Into`], see there for details. -/// -/// [`TryFrom`]: trait.TryFrom.html -/// [`Into`]: trait.Into.html #[stable(feature = "try_from", since = "1.34.0")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. @@ -485,11 +468,9 @@ pub trait TryInto: Sized { /// assert!(try_successful_smaller_number.is_ok()); /// ``` /// -/// [`try_from`]: trait.TryFrom.html#tymethod.try_from -/// [`TryInto`]: trait.TryInto.html -/// [`i32::MAX`]: ../../std/i32/constant.MAX.html +/// [`i32::MAX`]: crate::i32::MAX +/// [`try_from`]: TryFrom::try_from /// [`!`]: ../../std/primitive.never.html -/// [`Infallible`]: enum.Infallible.html #[stable(feature = "try_from", since = "1.34.0")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. @@ -676,7 +657,6 @@ impl AsRef for str { /// /// … and eventually deprecate `Infallible`. /// -/// /// However there is one case where `!` syntax can be used /// before `!` is stabilized as a full-fledged type: in the position of a function’s return type. /// Specifically, it is possible implementations for two different function pointer types: @@ -692,10 +672,6 @@ impl AsRef for str { /// the two `impl`s will start to overlap /// and therefore will be disallowed by the language’s trait coherence rules. /// -/// [`Ok`]: ../result/enum.Result.html#variant.Ok -/// [`Result`]: ../result/enum.Result.html -/// [`TryFrom`]: trait.TryFrom.html -/// [`Into`]: trait.Into.html /// [never]: ../../std/primitive.never.html #[stable(feature = "convert_infallible", since = "1.34.0")] #[derive(Copy)] diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 52d8349bc9..5908da477e 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -14,25 +14,17 @@ fn float_to_decimal_common_exact( where T: flt2dec::DecodableFloat, { - // SAFETY: Possible undefined behavior, see FIXME(#53491) - unsafe { - let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64 - let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit(); - // FIXME(#53491): This is calling `get_mut` on an uninitialized - // `MaybeUninit` (here and elsewhere in this file). Revisit this once - // we decided whether that is valid or not. - // We can do this only because we are libstd and coupled to the compiler. - // (FWIW, using `freeze` would not be enough; `flt2dec::Part` is an enum!) - let formatted = flt2dec::to_exact_fixed_str( - flt2dec::strategy::grisu::format_exact, - *num, - sign, - precision, - buf.get_mut(), - parts.get_mut(), - ); - fmt.pad_formatted_parts(&formatted) - } + let mut buf: [MaybeUninit; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64 + let mut parts: [MaybeUninit>; 4] = MaybeUninit::uninit_array(); + let formatted = flt2dec::to_exact_fixed_str( + flt2dec::strategy::grisu::format_exact, + *num, + sign, + precision, + &mut buf, + &mut parts, + ); + fmt.pad_formatted_parts(&formatted) } // Don't inline this so callers that call both this and the above won't wind @@ -47,22 +39,18 @@ fn float_to_decimal_common_shortest( where T: flt2dec::DecodableFloat, { - // SAFETY: Possible undefined behavior, see FIXME(#53491) - unsafe { - // enough for f32 and f64 - let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit(); - let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit(); - // FIXME(#53491) - let formatted = flt2dec::to_shortest_str( - flt2dec::strategy::grisu::format_shortest, - *num, - sign, - precision, - buf.get_mut(), - parts.get_mut(), - ); - fmt.pad_formatted_parts(&formatted) - } + // enough for f32 and f64 + let mut buf: [MaybeUninit; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array(); + let mut parts: [MaybeUninit>; 4] = MaybeUninit::uninit_array(); + let formatted = flt2dec::to_shortest_str( + flt2dec::strategy::grisu::format_shortest, + *num, + sign, + precision, + &mut buf, + &mut parts, + ); + fmt.pad_formatted_parts(&formatted) } // Common code of floating point Debug and Display. @@ -103,22 +91,18 @@ fn float_to_exponential_common_exact( where T: flt2dec::DecodableFloat, { - // SAFETY: Possible undefined behavior, see FIXME(#53491) - unsafe { - let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64 - let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit(); - // FIXME(#53491) - let formatted = flt2dec::to_exact_exp_str( - flt2dec::strategy::grisu::format_exact, - *num, - sign, - precision, - upper, - buf.get_mut(), - parts.get_mut(), - ); - fmt.pad_formatted_parts(&formatted) - } + let mut buf: [MaybeUninit; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64 + let mut parts: [MaybeUninit>; 6] = MaybeUninit::uninit_array(); + let formatted = flt2dec::to_exact_exp_str( + flt2dec::strategy::grisu::format_exact, + *num, + sign, + precision, + upper, + &mut buf, + &mut parts, + ); + fmt.pad_formatted_parts(&formatted) } // Don't inline this so callers that call both this and the above won't wind @@ -133,23 +117,19 @@ fn float_to_exponential_common_shortest( where T: flt2dec::DecodableFloat, { - // SAFETY: Possible undefined behavior, see FIXME(#53491) - unsafe { - // enough for f32 and f64 - let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit(); - let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit(); - // FIXME(#53491) - let formatted = flt2dec::to_shortest_exp_str( - flt2dec::strategy::grisu::format_shortest, - *num, - sign, - (0, 0), - upper, - buf.get_mut(), - parts.get_mut(), - ); - fmt.pad_formatted_parts(&formatted) - } + // enough for f32 and f64 + let mut buf: [MaybeUninit; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array(); + let mut parts: [MaybeUninit>; 6] = MaybeUninit::uninit_array(); + let formatted = flt2dec::to_shortest_exp_str( + flt2dec::strategy::grisu::format_shortest, + *num, + sign, + (0, 0), + upper, + &mut buf, + &mut parts, + ); + fmt.pad_formatted_parts(&formatted) } // Common code of floating point LowerExp and UpperExp. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 52f73c03e0..c1038ce426 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -168,8 +168,6 @@ pub trait Write { /// This method should generally not be invoked manually, but rather through /// the [`write!`] macro itself. /// - /// [`write!`]: ../../std/macro.write.html - /// /// # Examples /// /// ``` @@ -2088,7 +2086,7 @@ impl Pointer for *const T { f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32); if f.width.is_none() { - f.width = Some(((mem::size_of::() * 8) / 4) + 2); + f.width = Some((usize::BITS / 4) as usize + 2); } } f.flags |= 1 << (FlagV1::Alternate as u32); @@ -2240,5 +2238,6 @@ impl Debug for UnsafeCell { } } -// If you expected tests to be here, look instead at the ui/ifmt.rs test, +// If you expected tests to be here, look instead at the core/tests/fmt.rs file, // it's a lot easier than creating all of the rt::Piece structures here. +// There are also tests in the alloc crate, for those that need allocations. diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 7d77e33d74..ae3d0ddd46 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -85,7 +85,10 @@ trait GenericRadix { // SAFETY: The only chars in `buf` are created by `Self::digit` which are assumed to be // valid UTF-8 let buf = unsafe { - str::from_utf8_unchecked(slice::from_raw_parts(MaybeUninit::first_ptr(buf), buf.len())) + str::from_utf8_unchecked(slice::from_raw_parts( + MaybeUninit::slice_as_ptr(buf), + buf.len(), + )) }; f.pad_integral(is_nonnegative, Self::PREFIX, buf) } @@ -192,7 +195,7 @@ macro_rules! impl_Display { // 2^128 is about 3*10^38, so 39 gives an extra byte of space let mut buf = [MaybeUninit::::uninit(); 39]; let mut curr = buf.len() as isize; - let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf); + let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we @@ -322,7 +325,7 @@ macro_rules! impl_Exp { // that `curr >= 0`. let mut buf = [MaybeUninit::::uninit(); 40]; let mut curr = buf.len() as isize; //index for buf - let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf); + let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); // decode 2 chars at a time @@ -370,7 +373,7 @@ macro_rules! impl_Exp { // stores 'e' (or 'E') and the up to 2-digit exponent let mut exp_buf = [MaybeUninit::::uninit(); 3]; - let exp_ptr = MaybeUninit::first_ptr_mut(&mut exp_buf); + let exp_ptr = MaybeUninit::slice_as_mut_ptr(&mut exp_buf); // SAFETY: In either case, `exp_buf` is written within bounds and `exp_ptr[..len]` // is contained within `exp_buf` since `len <= 3`. let exp_slice = unsafe { diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 8169c14613..e9a99ddb6b 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -23,7 +23,7 @@ use crate::task::{Context, Poll}; /// When using a future, you generally won't call `poll` directly, but instead /// `.await` the value. /// -/// [`Waker`]: ../task/struct.Waker.html +/// [`Waker`]: crate::task::Waker #[doc(spotlight)] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] @@ -91,12 +91,10 @@ pub trait Future { /// (memory corruption, incorrect use of `unsafe` functions, or the like), /// regardless of the future's state. /// - /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending - /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready - /// [`Context`]: ../task/struct.Context.html - /// [`Waker`]: ../task/struct.Waker.html - /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake - #[cfg_attr(not(bootstrap), lang = "poll")] + /// [`Poll::Ready(val)`]: Poll::Ready + /// [`Waker`]: crate::task::Waker + /// [`Waker::wake`]: crate::task::Waker::wake + #[lang = "poll"] #[stable(feature = "futures_api", since = "1.36.0")] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index d44ef857c1..fa5655ca35 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -21,9 +21,9 @@ pub use self::future::Future; #[unstable(feature = "into_future", issue = "67644")] pub use into_future::IntoFuture; -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use pending::{pending, Pending}; -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use ready::{ready, Ready}; #[unstable(feature = "future_poll_fn", issue = "72302")] @@ -53,9 +53,10 @@ unsafe impl Sync for ResumeTy {} /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). // This is `const` to avoid extra errors after we recover from `const async fn` -#[cfg_attr(not(bootstrap), lang = "from_generator")] +#[lang = "from_generator"] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] +#[rustc_const_unstable(feature = "gen_future", issue = "50547")] #[inline] pub const fn from_generator(gen: T) -> impl Future where @@ -71,7 +72,7 @@ where impl> Future for GenFuture { type Output = T::Return; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // Safety: Safe because we're !Unpin + !Drop, and this is just a field projection. + // SAFETY: Safe because we're !Unpin + !Drop, and this is just a field projection. let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The @@ -86,7 +87,7 @@ where GenFuture(gen) } -#[cfg_attr(not(bootstrap), lang = "get_context")] +#[lang = "get_context"] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[inline] diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index 74887b68aa..ab162638a1 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -1,3 +1,4 @@ +use crate::fmt::{self, Debug}; use crate::future::Future; use crate::marker; use crate::pin::Pin; @@ -6,12 +7,9 @@ use crate::task::{Context, Poll}; /// Creates a future which never resolves, representing a computation that never /// finishes. /// -/// This `struct` is created by the [`pending`] function. See its +/// This `struct` is created by [`pending()`]. See its /// documentation for more. -/// -/// [`pending`]: fn.pending.html -#[unstable(feature = "future_readiness_fns", issue = "70921")] -#[derive(Debug)] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Pending { _data: marker::PhantomData, @@ -23,7 +21,6 @@ pub struct Pending { /// # Examples /// /// ```no_run -/// #![feature(future_readiness_fns)] /// use core::future; /// /// # async fn run() { @@ -32,12 +29,12 @@ pub struct Pending { /// unreachable!(); /// # } /// ``` -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub fn pending() -> Pending { Pending { _data: marker::PhantomData } } -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Future for Pending { type Output = T; @@ -46,10 +43,17 @@ impl Future for Pending { } } -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Unpin for Pending {} -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] +impl Debug for Pending { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Pending").finish() + } +} + +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Clone for Pending { fn clone(&self) -> Self { pending() diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index 9ab3bfcea1..f302cda09e 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -33,10 +33,8 @@ where /// A Future that wraps a function returning `Poll`. /// -/// This `struct` is created by the [`poll_fn`] function. See its +/// This `struct` is created by [`poll_fn()`]. See its /// documentation for more. -/// -/// [`poll_fn`]: fn.poll_fn.html #[must_use = "futures do nothing unless you `.await` or poll them"] #[unstable(feature = "future_poll_fn", issue = "72302")] pub struct PollFn { diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index 31b39d7fb6..e98f5c570b 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -4,19 +4,17 @@ use crate::task::{Context, Poll}; /// Creates a future that is immediately ready with a value. /// -/// This `struct` is created by the [`ready`] function. See its +/// This `struct` is created by [`ready()`]. See its /// documentation for more. -/// -/// [`ready`]: fn.ready.html -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] #[derive(Debug, Clone)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Ready(Option); -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Unpin for Ready {} -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Future for Ready { type Output = T; @@ -28,10 +26,13 @@ impl Future for Ready { /// Creates a future that is immediately ready with a value. /// +/// Futures created through this function are functionally similar to those +/// created through `async {}`. The main difference is that futures created +/// through this function are named and implement `Unpin`. +/// /// # Examples /// /// ``` -/// #![feature(future_readiness_fns)] /// use core::future; /// /// # async fn run() { @@ -39,7 +40,7 @@ impl Future for Ready { /// assert_eq!(a.await, 1); /// # } /// ``` -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub fn ready(t: T) -> Ready { Ready(Some(t)) } diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 6abe19dc15..f53ba98143 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -39,8 +39,6 @@ //! If you need more control over how a value is hashed, you need to implement //! the [`Hash`] trait: //! -//! [`Hash`]: trait.Hash.html -//! //! ```rust //! use std::collections::hash_map::DefaultHasher; //! use std::hash::{Hash, Hasher}; @@ -149,11 +147,9 @@ mod sip; /// Thankfully, you won't need to worry about upholding this property when /// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`. /// -/// [`Eq`]: ../../std/cmp/trait.Eq.html -/// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html -/// [`hash`]: #tymethod.hash +/// [`hash`]: Hash::hash #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { /// Feeds this value into the given [`Hasher`]. @@ -168,8 +164,6 @@ pub trait Hash { /// 7920.hash(&mut hasher); /// println!("Hash is {:x}!", hasher.finish()); /// ``` - /// - /// [`Hasher`]: trait.Hasher.html #[stable(feature = "rust1", since = "1.0.0")] fn hash(&self, state: &mut H); @@ -186,8 +180,6 @@ pub trait Hash { /// Hash::hash_slice(&numbers, &mut hasher); /// println!("Hash is {:x}!", hasher.finish()); /// ``` - /// - /// [`Hasher`]: trait.Hasher.html #[stable(feature = "hash_slice", since = "1.3.0")] fn hash_slice(data: &[Self], state: &mut H) where @@ -239,10 +231,9 @@ pub use macros::Hash; /// println!("Hash is {:x}!", hasher.finish()); /// ``` /// -/// [`Hash`]: trait.Hash.html -/// [`finish`]: #tymethod.finish -/// [`write`]: #tymethod.write -/// [`write_u8`]: #method.write_u8 +/// [`finish`]: Hasher::finish +/// [`write`]: Hasher::write +/// [`write_u8`]: Hasher::write_u8 #[stable(feature = "rust1", since = "1.0.0")] pub trait Hasher { /// Returns the hash value for the values written so far. @@ -264,7 +255,7 @@ pub trait Hasher { /// println!("Hash is {:x}!", hasher.finish()); /// ``` /// - /// [`write`]: #tymethod.write + /// [`write`]: Hasher::write #[stable(feature = "rust1", since = "1.0.0")] fn finish(&self) -> u64; @@ -433,8 +424,7 @@ impl Hasher for &mut H { /// assert_eq!(hasher_1.finish(), hasher_2.finish()); /// ``` /// -/// [`build_hasher`]: #tymethod.build_hasher -/// [`Hasher`]: trait.Hasher.html +/// [`build_hasher`]: BuildHasher::build_hasher /// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] pub trait BuildHasher { @@ -456,8 +446,6 @@ pub trait BuildHasher { /// let s = RandomState::new(); /// let new_s = s.build_hasher(); /// ``` - /// - /// [`Hasher`]: trait.Hasher.html #[stable(since = "1.7.0", feature = "build_hasher")] fn build_hasher(&self) -> Self::Hasher; } @@ -470,7 +458,7 @@ pub trait BuildHasher { /// defined. /// /// Any `BuildHasherDefault` is [zero-sized]. It can be created with -/// [`default`][method.Default]. When using `BuildHasherDefault` with [`HashMap`] or +/// [`default`][method.default]. When using `BuildHasherDefault` with [`HashMap`] or /// [`HashSet`], this doesn't need to be done, since they implement appropriate /// [`Default`] instances themselves. /// @@ -503,10 +491,7 @@ pub trait BuildHasher { /// let hash_map = HashMap::::default(); /// ``` /// -/// [`BuildHasher`]: trait.BuildHasher.html -/// [`Default`]: ../default/trait.Default.html -/// [method.default]: #method.default -/// [`Hasher`]: trait.Hasher.html +/// [method.default]: BuildHasherDefault::default /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html /// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 461b4c79a1..4eb47dd137 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -101,17 +101,18 @@ pub fn spin_loop() { /// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html /// /// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can -/// use `x` in any possible valid way that Rust code is allowed to without introducing undefined +/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined /// behavior in the calling code. This property makes `black_box` useful for writing code in which /// certain optimizations are not desired, such as benchmarks. /// /// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The /// extent to which it can block optimisations may vary depending upon the platform and code-gen /// backend used. Programs cannot rely on `black_box` for *correctness* in any way. -#[inline] +#[cfg_attr(not(miri), inline)] +#[cfg_attr(miri, inline(never))] #[unstable(feature = "test", issue = "50297")] -#[allow(unreachable_code)] // this makes #[cfg] a bit easier below. -pub fn black_box(dummy: T) -> T { +#[cfg_attr(miri, allow(unused_mut))] +pub fn black_box(mut dummy: T) -> T { // We need to "use" the argument in some way LLVM can't introspect, and on // targets that support it we can typically leverage inline assembly to do // this. LLVM's interpretation of inline assembly is that it's, well, a black @@ -121,7 +122,8 @@ pub fn black_box(dummy: T) -> T { #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri. // SAFETY: the inline assembly is a no-op. unsafe { - llvm_asm!("" : : "r"(&dummy)); + // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures. + llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile"); } dummy diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d0b12d6982..426cdb12ec 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1,7 +1,7 @@ //! Compiler intrinsics. //! -//! The corresponding definitions are in `librustc_codegen_llvm/intrinsic.rs`. -//! The corresponding const implementations are in `librustc_mir/interpret/intrinsics.rs` +//! The corresponding definitions are in `compiler/rustc_codegen_llvm/src/intrinsic.rs`. +//! The corresponding const implementations are in `compiler/rustc_mir/src/interpret/intrinsics.rs` //! //! # Const intrinsics //! @@ -10,7 +10,7 @@ //! //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation //! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to -//! `librustc_mir/interpret/intrinsics.rs` and add a +//! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a //! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, @@ -733,6 +733,7 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assume", issue = "76972")] pub fn assume(b: bool); /// Hints to the compiler that branch condition is likely to be true. @@ -831,7 +832,7 @@ extern "rust-intrinsic" { /// Gets a reference to a static `Location` indicating where it was called. /// /// Consider using [`crate::panic::Location::caller`] instead. - #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] + #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] pub fn caller_location() -> &'static crate::panic::Location<'static>; /// Moves a value out of scope without running drop glue. @@ -904,7 +905,7 @@ extern "rust-intrinsic" { /// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; /// /// let num = unsafe { - /// std::mem::transmute::<[u8; 4], u32>(raw_bytes); + /// std::mem::transmute::<[u8; 4], u32>(raw_bytes) /// }; /// /// // use `u32::from_ne_bytes` instead @@ -1071,6 +1072,7 @@ extern "rust-intrinsic" { // NOTE: While this makes the intrinsic const stable, we have some custom code in const fn // checks that prevent its use within `const fn`. #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")] + #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "transmute")] pub fn transmute(e: T) -> U; /// Returns `true` if the actual type given as `T` requires drop @@ -1899,11 +1901,22 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { /// ``` /// use std::ptr; /// +/// /// # Safety +/// /// +/// /// * `ptr` must be correctly aligned for its type and non-zero. +/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. +/// /// * Those elements must not be used after calling this function unless `T: Copy`. /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst = Vec::with_capacity(elts); -/// dst.set_len(elts); +/// +/// // SAFETY: Our precondition ensures the source is aligned and valid, +/// // and `Vec::with_capacity` ensures that we have usable space to write them. /// ptr::copy(ptr, dst.as_mut_ptr(), elts); +/// +/// // SAFETY: We created it with this much capacity earlier, +/// // and the previous `copy` has initialized these elements. +/// dst.set_len(elts); /// dst /// } /// ``` diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 6700ef017b..ac27ec19b3 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -4,11 +4,19 @@ use crate::usize; /// An iterator that links two iterators together, in a chain. /// -/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its -/// documentation for more. +/// This `struct` is created by [`Iterator::chain`]. See its documentation +/// for more. /// -/// [`chain`]: trait.Iterator.html#method.chain -/// [`Iterator`]: trait.Iterator.html +/// # Examples +/// +/// ``` +/// use std::iter::Chain; +/// use std::slice::Iter; +/// +/// let a1 = [1, 2, 3]; +/// let a2 = [4, 5, 6]; +/// let iter: Chain, Iter<_>> = a1.iter().chain(a2.iter()); +/// ``` #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 4202e52448..ddb1aaebc1 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -7,11 +7,8 @@ use super::Map; /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// -/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`flat_map`]: trait.Iterator.html#method.flat_map -/// [`Iterator`]: trait.Iterator.html +/// This `struct` is created by [`Iterator::flat_map`]. See its documentation +/// for more. #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct FlatMap { diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index ee5fbe9a84..a78da369c2 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,5 +1,7 @@ +use super::InPlaceIterable; use crate::intrinsics; use crate::iter::adapters::zip::try_get_unchecked; +use crate::iter::adapters::SourceIter; use crate::iter::TrustedRandomAccess; use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; use crate::ops::Try; @@ -7,11 +9,8 @@ use crate::ops::Try; /// An iterator that yields `None` forever after the underlying iterator /// yields `None` once. /// -/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`fuse`]: trait.Iterator.html#method.fuse -/// [`Iterator`]: trait.Iterator.html +/// This `struct` is created by [`Iterator::fuse`]. See its documentation +/// for more. #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -121,7 +120,8 @@ where Self: TrustedRandomAccess, { match self.iter { - // SAFETY: the caller must uphold the contract for `Iterator::get_unchecked`. + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. Some(ref mut iter) => unsafe { try_get_unchecked(iter, idx) }, // SAFETY: the caller asserts there is an item at `i`, so we're not exhausted. None => unsafe { intrinsics::unreachable() }, @@ -517,3 +517,24 @@ where unchecked!(self).is_empty() } } + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Fuse +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + match self.iter { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + Some(ref mut iter) => unsafe { SourceIter::as_inner(iter) }, + // SAFETY: the specialized iterator never sets `None` + None => unsafe { intrinsics::unreachable() }, + } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Fuse {} diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index ce90607e76..1e520b62f7 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,10 +1,12 @@ use crate::cmp; use crate::fmt; use crate::intrinsics; -use crate::ops::{Add, AddAssign, Try}; +use crate::ops::{Add, AddAssign, ControlFlow, Try}; -use super::{from_fn, LoopState}; -use super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedLen}; +use super::from_fn; +use super::{ + DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, TrustedLen, +}; mod chain; mod flatten; @@ -16,9 +18,77 @@ pub use self::chain::Chain; pub use self::flatten::{FlatMap, Flatten}; pub use self::fuse::Fuse; use self::zip::try_get_unchecked; -pub(crate) use self::zip::TrustedRandomAccess; +#[unstable(feature = "trusted_random_access", issue = "none")] +pub use self::zip::TrustedRandomAccess; pub use self::zip::Zip; +/// This trait provides transitive access to source-stage in an interator-adapter pipeline +/// under the conditions that +/// * the iterator source `S` itself implements `SourceIter` +/// * there is a delegating implementation of this trait for each adapter in the pipeline between +/// the source and the pipeline consumer. +/// +/// When the source is an owning iterator struct (commonly called `IntoIter`) then +/// this can be useful for specializing [`FromIterator`] implementations or recovering the +/// remaining elements after an iterator has been partially exhausted. +/// +/// Note that implementations do not necessarily have to provide access to the inner-most +/// source of a pipeline. A stateful intermediate adapter might eagerly evaluate a part +/// of the pipeline and expose its internal storage as source. +/// +/// The trait is unsafe because implementers must uphold additional safety properties. +/// See [`as_inner`] for details. +/// +/// # Examples +/// +/// Retrieving a partially consumed source: +/// +/// ``` +/// # #![feature(inplace_iteration)] +/// # use std::iter::SourceIter; +/// +/// let mut iter = vec![9, 9, 9].into_iter().map(|i| i * i); +/// let _ = iter.next(); +/// let mut remainder = std::mem::replace(unsafe { iter.as_inner() }, Vec::new().into_iter()); +/// println!("n = {} elements remaining", remainder.len()); +/// ``` +/// +/// [`FromIterator`]: crate::iter::FromIterator +/// [`as_inner`]: SourceIter::as_inner +#[unstable(issue = "none", feature = "inplace_iteration")] +pub unsafe trait SourceIter { + /// A source stage in an iterator pipeline. + type Source: Iterator; + + /// Retrieve the source of an iterator pipeline. + /// + /// # Safety + /// + /// Implementations of must return the same mutable reference for their lifetime, unless + /// replaced by a caller. + /// Callers may only replace the reference when they stopped iteration and drop the + /// iterator pipeline after extracting the source. + /// + /// This means iterator adapters can rely on the source not changing during + /// iteration but they cannot rely on it in their Drop implementations. + /// + /// Implementing this method means adapters relinquish private-only access to their + /// source and can only rely on guarantees made based on method receiver types. + /// The lack of restricted access also requires that adapters must uphold the source's + /// public API even when they have access to its internals. + /// + /// Callers in turn must expect the source to be in any state that is consistent with + /// its public API since adapters sitting between it and the source have the same + /// access. In particular an adapter may have consumed more elements than strictly necessary. + /// + /// The overall goal of these requirements is to let the consumer of a pipeline use + /// * whatever remains in the source after iteration has stopped + /// * the memory that has become unused by advancing a consuming iterator + /// + /// [`next()`]: trait.Iterator.html#method.next + unsafe fn as_inner(&mut self) -> &mut Self::Source; +} + /// A double-ended iterator with the direction inverted. /// /// This `struct` is created by the [`rev`] method on [`Iterator`]. See its @@ -54,6 +124,11 @@ where self.iter.size_hint() } + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.iter.advance_back_by(n) + } + #[inline] fn nth(&mut self, n: usize) -> Option<::Item> { self.iter.nth_back(n) @@ -94,6 +169,11 @@ where self.iter.next() } + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.iter.advance_by(n) + } + #[inline] fn nth_back(&mut self, n: usize) -> Option<::Item> { self.iter.nth(n) @@ -220,7 +300,7 @@ where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. *unsafe { try_get_unchecked(&mut self.it, idx) } } } @@ -355,7 +435,7 @@ where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { try_get_unchecked(&mut self.it, idx).clone() } } } @@ -870,7 +950,7 @@ where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) } } } @@ -939,6 +1019,24 @@ where } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Map +where + F: FnMut(I::Item) -> B, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Map where F: FnMut(I::Item) -> B {} + /// An iterator that filters the elements of `iter` with `predicate`. /// /// This `struct` is created by the [`filter`] method on [`Iterator`]. See its @@ -1070,6 +1168,24 @@ where #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Filter +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Filter where P: FnMut(&I::Item) -> bool {} + /// An iterator that uses `f` to both filter and map elements from `iter`. /// /// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its @@ -1164,10 +1280,10 @@ where #[inline] fn find( f: &mut impl FnMut(T) -> Option, - ) -> impl FnMut((), T) -> LoopState<(), B> + '_ { + ) -> impl FnMut((), T) -> ControlFlow<(), B> + '_ { move |(), x| match f(x) { - Some(x) => LoopState::Break(x), - None => LoopState::Continue(()), + Some(x) => ControlFlow::Break(x), + None => ControlFlow::CONTINUE, } } @@ -1196,6 +1312,27 @@ where #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for FilterMap +where + F: FnMut(I::Item) -> Option, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for FilterMap where + F: FnMut(I::Item) -> Option +{ +} + /// An iterator that yields the current count and the element during iteration. /// /// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its @@ -1309,7 +1446,7 @@ where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. let value = unsafe { try_get_unchecked(&mut self.iter, idx) }; (Add::add(self.count, idx), value) } @@ -1414,6 +1551,23 @@ impl FusedIterator for Enumerate where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Enumerate where I: TrustedLen {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Enumerate +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Enumerate {} + /// An iterator with a `peek()` that returns an optional reference to the next /// element. /// @@ -1628,7 +1782,7 @@ impl Peekable { self.peeked.get_or_insert_with(|| iter.next()).as_ref() } - /// Consume the next value of this iterator if a condition is true. + /// Consume and return the next value of this iterator if a condition is true. /// /// If `func` returns `true` for the next value of this iterator, consume and return it. /// Otherwise, return `None`. @@ -1668,7 +1822,7 @@ impl Peekable { } } - /// Consume the next item if it is equal to `expected`. + /// Consume and return the next item if it is equal to `expected`. /// /// # Example /// Consume a number if it's equal to 0. @@ -1683,15 +1837,35 @@ impl Peekable { /// assert_eq!(iter.next(), Some(1)); /// ``` #[unstable(feature = "peekable_next_if", issue = "72480")] - pub fn next_if_eq(&mut self, expected: &R) -> Option + pub fn next_if_eq(&mut self, expected: &T) -> Option where - R: ?Sized, - I::Item: PartialEq, + T: ?Sized, + I::Item: PartialEq, { self.next_if(|next| next == expected) } } +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Peekable where I: TrustedLen {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Peekable +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Peekable {} + /// An iterator that rejects elements while `predicate` returns `true`. /// /// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its @@ -1793,6 +1967,27 @@ where { } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for SkipWhile +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for SkipWhile where + F: FnMut(&I::Item) -> bool +{ +} + /// An iterator that only accepts elements while `predicate` returns `true`. /// /// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its @@ -1864,13 +2059,13 @@ where flag: &'a mut bool, p: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> LoopState + 'a { + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| { if p(&x) { - LoopState::from_try(fold(acc, x)) + ControlFlow::from_try(fold(acc, x)) } else { *flag = true; - LoopState::Break(Try::from_ok(acc)) + ControlFlow::Break(Try::from_ok(acc)) } } } @@ -1907,6 +2102,27 @@ where { } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for TakeWhile +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for TakeWhile where + F: FnMut(&I::Item) -> bool +{ +} + /// An iterator that only accepts elements while `predicate` returns `Some(_)`. /// /// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its @@ -1963,8 +2179,8 @@ where { let Self { iter, predicate } = self; iter.try_fold(init, |acc, x| match predicate(x) { - Some(item) => LoopState::from_try(fold(acc, item)), - None => LoopState::Break(Try::from_ok(acc)), + Some(item) => ControlFlow::from_try(fold(acc, item)), + None => ControlFlow::Break(Try::from_ok(acc)), }) .into_try() } @@ -1984,6 +2200,27 @@ where } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for MapWhile +where + P: FnMut(I::Item) -> Option, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for MapWhile where + P: FnMut(I::Item) -> Option +{ +} + /// An iterator that skips over `n` elements of `iter`. /// /// This `struct` is created by the [`skip`] method on [`Iterator`]. See its @@ -2135,11 +2372,11 @@ where fn check>( mut n: usize, mut fold: impl FnMut(Acc, T) -> R, - ) -> impl FnMut(Acc, T) -> LoopState { + ) -> impl FnMut(Acc, T) -> ControlFlow { move |acc, x| { n -= 1; let r = fold(acc, x); - if n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) } + if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } } } @@ -2167,6 +2404,23 @@ where #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Skip where I: FusedIterator {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Skip +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Skip {} + /// An iterator that only iterates over the first `n` iterations of `iter`. /// /// This `struct` is created by the [`take`] method on [`Iterator`]. See its @@ -2246,11 +2500,11 @@ where fn check<'a, T, Acc, R: Try>( n: &'a mut usize, mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> LoopState + 'a { + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| { *n -= 1; let r = fold(acc, x); - if *n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) } + if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } } } @@ -2277,6 +2531,23 @@ where } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Take +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Take {} + #[stable(feature = "double_ended_take_iterator", since = "1.38.0")] impl DoubleEndedIterator for Take where @@ -2414,10 +2685,10 @@ where state: &'a mut St, f: &'a mut impl FnMut(&mut St, T) -> Option, mut fold: impl FnMut(Acc, B) -> R + 'a, - ) -> impl FnMut(Acc, T) -> LoopState + 'a { + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| match f(state, x) { - None => LoopState::Break(Try::from_ok(acc)), - Some(x) => LoopState::from_try(fold(acc, x)), + None => ControlFlow::Break(Try::from_ok(acc)), + Some(x) => ControlFlow::from_try(fold(acc, x)), } } @@ -2441,6 +2712,27 @@ where } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Scan +where + I: SourceIter, + F: FnMut(&mut St, I::Item) -> Option, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Scan where + F: FnMut(&mut St, I::Item) -> Option +{ +} + /// An iterator that calls a function with a reference to each element before /// yielding it. /// @@ -2587,6 +2879,24 @@ where #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Inspect where F: FnMut(&I::Item) {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Inspect +where + F: FnMut(&I::Item), + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Inspect where F: FnMut(&I::Item) {} + /// An iterator adapter that produces output as long as the underlying /// iterator produces `Result::Ok` values. /// @@ -2638,10 +2948,10 @@ where let error = &mut *self.error; self.iter .try_fold(init, |acc, x| match x { - Ok(x) => LoopState::from_try(f(acc, x)), + Ok(x) => ControlFlow::from_try(f(acc, x)), Err(e) => { *error = Err(e); - LoopState::Break(Try::from_ok(acc)) + ControlFlow::Break(Try::from_ok(acc)) } }) .into_try() diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 581ac6e0d8..78712988ea 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -1,15 +1,15 @@ use crate::cmp; use crate::fmt::{self, Debug}; -use super::super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedLen}; +use super::super::{ + DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, SourceIter, + TrustedLen, +}; /// An iterator that iterates two other iterators simultaneously. /// -/// This `struct` is created by the [`zip`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`zip`]: trait.Iterator.html#method.zip -/// [`Iterator`]: trait.Iterator.html +/// This `struct` is created by [`Iterator::zip`]. See its documentation +/// for more. #[derive(Clone)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -63,8 +63,8 @@ where where Self: TrustedRandomAccess, { - // SAFETY: `ZipImpl::get_unchecked` has same safety requirements as - // `Iterator::get_unchecked`. + // SAFETY: `ZipImpl::__iterator_get_unchecked` has same safety + // requirements as `Iterator::__iterator_get_unchecked`. unsafe { ZipImpl::get_unchecked(self, idx) } } } @@ -93,7 +93,7 @@ trait ZipImpl { where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator; - // This has the same safety requirements as `Iterator::get_unchecked` + // This has the same safety requirements as `Iterator::__iterator_get_unchecked` unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item where Self: Iterator + TrustedRandomAccess; @@ -290,7 +290,7 @@ where #[inline] unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) } } } @@ -331,6 +331,32 @@ where { } +// Arbitrarily selects the left side of the zip iteration as extractable "source" +// it would require negative trait bounds to be able to try both +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Zip +where + A: SourceIter, + B: Iterator, + S: Iterator, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.a) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +// Limited to Item: Copy since interaction between Zip's use of TrustedRandomAccess +// and Drop implementation of the source is unclear. +// +// An additional method returning the number of times the source has been logically advanced +// (without calling next()) would be needed to properly drop the remainder of the source. +unsafe impl InPlaceIterable for Zip where A::Item: Copy {} + #[stable(feature = "rust1", since = "1.0.0")] impl Debug for Zip { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -364,8 +390,8 @@ impl ZipFmt::get_unchecked` must be safe to call provided the -/// following conditions are met. +/// `::__iterator_get_unchecked` must be safe to call +/// provided the following conditions are met. /// /// 1. `0 <= idx` and `idx < self.size()`. /// 2. If `self: !Clone`, then `get_unchecked` is never called with the same @@ -377,7 +403,7 @@ impl ZipFmt bool; } -/// Like `Iterator::get_unchecked`, but doesn't require the compiler to +/// Like `Iterator::__iterator_get_unchecked`, but doesn't require the compiler to /// know that `U: TrustedRandomAccess`. /// /// ## Safety @@ -414,13 +440,13 @@ where I: Iterator, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { it.try_get_unchecked(idx) } } unsafe trait SpecTrustedRandomAccess: Iterator { /// If `Self: TrustedRandomAccess`, it must be safe to call a - /// `Iterator::get_unchecked(self, index)`. + /// `Iterator::__iterator_get_unchecked(self, index)`. unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item; } @@ -433,7 +459,7 @@ unsafe impl SpecTrustedRandomAccess for I { unsafe impl SpecTrustedRandomAccess for I { unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { self.__iterator_get_unchecked(index) } } } diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 9b528cdbe3..59f333e888 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -54,8 +54,7 @@ //! below for more details. //! //! [`Some(Item)`]: Some -//! [`Iterator`]: trait.Iterator.html -//! [`next`]: trait.Iterator.html#tymethod.next +//! [`next`]: Iterator::next //! [`TryIter`]: ../../std/sync/mpsc/struct.TryIter.html //! //! # The three forms of iteration @@ -136,7 +135,7 @@ //! methods like `nth` and `fold` if an iterator can compute them more efficiently without calling //! `next`. //! -//! # for Loops and IntoIterator +//! # `for` loops and `IntoIterator` //! //! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic //! example of `for`: @@ -159,8 +158,7 @@ //! Let's take a look at that `for` loop again, and what the compiler converts //! it into: //! -//! [`IntoIterator`]: trait.IntoIterator.html -//! [`into_iter`]: trait.IntoIterator.html#tymethod.into_iter +//! [`into_iter`]: IntoIterator::into_iter //! //! ``` //! let values = vec![1, 2, 3, 4, 5]; @@ -222,9 +220,9 @@ //! across versions of Rust, so you should avoid relying on the exact values //! returned by an iterator which panicked. //! -//! [`map`]: trait.Iterator.html#method.map -//! [`take`]: trait.Iterator.html#method.take -//! [`filter`]: trait.Iterator.html#method.filter +//! [`map`]: Iterator::map +//! [`take`]: Iterator::take +//! [`filter`]: Iterator::filter //! //! # Laziness //! @@ -261,13 +259,13 @@ //! } //! ``` //! -//! [`map`]: trait.Iterator.html#method.map -//! [`for_each`]: trait.Iterator.html#method.for_each +//! [`map`]: Iterator::map +//! [`for_each`]: Iterator::for_each //! //! Another common way to evaluate an iterator is to use the [`collect`] //! method to produce a new collection. //! -//! [`collect`]: trait.Iterator.html#method.collect +//! [`collect`]: Iterator::collect //! //! # Infinity //! @@ -305,13 +303,11 @@ //! println!("The smallest number one is {}.", least); //! ``` //! -//! [`take`]: trait.Iterator.html#method.take -//! [`min`]: trait.Iterator.html#method.min +//! [`take`]: Iterator::take +//! [`min`]: Iterator::min #![stable(feature = "rust1", since = "1.0.0")] -use crate::ops::Try; - #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::Iterator; @@ -346,16 +342,24 @@ pub use self::traits::{DoubleEndedIterator, Extend, FromIterator, IntoIterator}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ExactSizeIterator, Product, Sum}; +#[unstable(issue = "none", feature = "inplace_iteration")] +pub use self::traits::InPlaceIterable; + #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::adapters::Cloned; #[stable(feature = "iter_copied", since = "1.36.0")] pub use self::adapters::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; + #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::adapters::MapWhile; +#[unstable(issue = "none", feature = "inplace_iteration")] +pub use self::adapters::SourceIter; #[stable(feature = "iterator_step_by", since = "1.28.0")] pub use self::adapters::StepBy; +#[unstable(feature = "trusted_random_access", issue = "none")] +pub use self::adapters::TrustedRandomAccess; #[stable(feature = "rust1", since = "1.0.0")] pub use self::adapters::{Chain, Cycle, Enumerate, Filter, FilterMap, Map, Rev, Zip}; #[stable(feature = "rust1", since = "1.0.0")] @@ -363,63 +367,9 @@ pub use self::adapters::{FlatMap, Peekable, Scan, Skip, SkipWhile, Take, TakeWhi #[stable(feature = "rust1", since = "1.0.0")] pub use self::adapters::{Fuse, Inspect}; -pub(crate) use self::adapters::{process_results, TrustedRandomAccess}; +pub(crate) use self::adapters::process_results; mod adapters; mod range; mod sources; mod traits; - -/// Used to make try_fold closures more like normal loops -#[derive(PartialEq)] -enum LoopState { - Continue(C), - Break(B), -} - -impl Try for LoopState { - type Ok = C; - type Error = B; - #[inline] - fn into_result(self) -> Result { - match self { - LoopState::Continue(y) => Ok(y), - LoopState::Break(x) => Err(x), - } - } - #[inline] - fn from_error(v: Self::Error) -> Self { - LoopState::Break(v) - } - #[inline] - fn from_ok(v: Self::Ok) -> Self { - LoopState::Continue(v) - } -} - -impl LoopState { - #[inline] - fn break_value(self) -> Option { - match self { - LoopState::Continue(..) => None, - LoopState::Break(x) => Some(x), - } - } -} - -impl LoopState { - #[inline] - fn from_try(r: R) -> Self { - match Try::into_result(r) { - Ok(v) => LoopState::Continue(v), - Err(v) => LoopState::Break(Try::from_error(v)), - } - } - #[inline] - fn into_try(self) -> R { - match self { - LoopState::Continue(v) => Try::from_ok(v), - LoopState::Break(v) => v, - } - } -} diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index d76fa89bd0..97562cf73b 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -5,9 +5,7 @@ use super::{FusedIterator, TrustedLen}; /// An iterator that repeats an element endlessly. /// -/// This `struct` is created by the [`repeat`] function. See its documentation for more. -/// -/// [`repeat`]: fn.repeat.html +/// This `struct` is created by the [`repeat()`] function. See its documentation for more. #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Repeat { @@ -47,15 +45,11 @@ unsafe impl TrustedLen for Repeat {} /// The `repeat()` function repeats a single value over and over again. /// /// Infinite iterators like `repeat()` are often used with adapters like -/// [`take`], in order to make them finite. -/// -/// [`take`]: trait.Iterator.html#method.take +/// [`Iterator::take()`], in order to make them finite. /// /// If the element type of the iterator you need does not implement `Clone`, /// or if you do not want to keep the repeated element in memory, you can -/// instead use the [`repeat_with`] function. -/// -/// [`repeat_with`]: fn.repeat_with.html +/// instead use the [`repeat_with()`] function. /// /// # Examples /// @@ -77,7 +71,7 @@ unsafe impl TrustedLen for Repeat {} /// assert_eq!(Some(4), fours.next()); /// ``` /// -/// Going finite with [`take`]: +/// Going finite with [`Iterator::take()`]: /// /// ``` /// use std::iter; @@ -102,10 +96,8 @@ pub fn repeat(elt: T) -> Repeat { /// An iterator that repeats elements of type `A` endlessly by /// applying the provided closure `F: FnMut() -> A`. /// -/// This `struct` is created by the [`repeat_with`] function. +/// This `struct` is created by the [`repeat_with()`] function. /// See its documentation for more. -/// -/// [`repeat_with`]: fn.repeat_with.html #[derive(Copy, Clone, Debug)] #[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub struct RepeatWith { @@ -139,20 +131,18 @@ unsafe impl A> TrustedLen for RepeatWith {} /// The `repeat_with()` function calls the repeater over and over again. /// /// Infinite iterators like `repeat_with()` are often used with adapters like -/// [`take`], in order to make them finite. -/// -/// [`take`]: trait.Iterator.html#method.take +/// [`Iterator::take()`], in order to make them finite. /// -/// If the element type of the iterator you need implements `Clone`, and +/// If the element type of the iterator you need implements [`Clone`], and /// it is OK to keep the source element in memory, you should instead use -/// the [`repeat`] function. -/// -/// [`repeat`]: fn.repeat.html +/// the [`repeat()`] function. /// -/// An iterator produced by `repeat_with()` is not a `DoubleEndedIterator`. -/// If you need `repeat_with()` to return a `DoubleEndedIterator`, +/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`]. +/// If you need `repeat_with()` to return a [`DoubleEndedIterator`], /// please open a GitHub issue explaining your use case. /// +/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator +/// /// # Examples /// /// Basic usage: @@ -201,9 +191,7 @@ pub fn repeat_with A>(repeater: F) -> RepeatWith { /// An iterator that yields nothing. /// -/// This `struct` is created by the [`empty`] function. See its documentation for more. -/// -/// [`empty`]: fn.empty.html +/// This `struct` is created by the [`empty()`] function. See its documentation for more. #[stable(feature = "iter_empty", since = "1.2.0")] pub struct Empty(marker::PhantomData); @@ -292,9 +280,7 @@ pub const fn empty() -> Empty { /// An iterator that yields an element exactly once. /// -/// This `struct` is created by the [`once`] function. See its documentation for more. -/// -/// [`once`]: fn.once.html +/// This `struct` is created by the [`once()`] function. See its documentation for more. #[derive(Clone, Debug)] #[stable(feature = "iter_once", since = "1.2.0")] pub struct Once { @@ -336,12 +322,12 @@ impl FusedIterator for Once {} /// Creates an iterator that yields an element exactly once. /// -/// This is commonly used to adapt a single value into a [`chain`] of other +/// This is commonly used to adapt a single value into a [`chain()`] of other /// kinds of iteration. Maybe you have an iterator that covers almost /// everything, but you need an extra special case. Maybe you have a function /// which works on iterators, but you only need to process one value. /// -/// [`chain`]: trait.Iterator.html#method.chain +/// [`chain()`]: Iterator::chain /// /// # Examples /// @@ -393,10 +379,8 @@ pub fn once(value: T) -> Once { /// An iterator that yields a single element of type `A` by /// applying the provided closure `F: FnOnce() -> A`. /// -/// This `struct` is created by the [`once_with`] function. +/// This `struct` is created by the [`once_with()`] function. /// See its documentation for more. -/// -/// [`once_with`]: fn.once_with.html #[derive(Clone, Debug)] #[stable(feature = "iter_once_with", since = "1.43.0")] pub struct OnceWith { @@ -442,15 +426,14 @@ unsafe impl A> TrustedLen for OnceWith {} /// Creates an iterator that lazily generates a value exactly once by invoking /// the provided closure. /// -/// This is commonly used to adapt a single value generator into a [`chain`] of +/// This is commonly used to adapt a single value generator into a [`chain()`] of /// other kinds of iteration. Maybe you have an iterator that covers almost /// everything, but you need an extra special case. Maybe you have a function /// which works on iterators, but you only need to process one value. /// -/// Unlike [`once`], this function will lazily generate the value on request. +/// Unlike [`once()`], this function will lazily generate the value on request. /// -/// [`once`]: fn.once.html -/// [`chain`]: trait.Iterator.html#method.chain +/// [`chain()`]: Iterator::chain /// /// # Examples /// @@ -505,17 +488,16 @@ pub fn once_with A>(gen: F) -> OnceWith { /// /// This allows creating a custom iterator with any behavior /// without using the more verbose syntax of creating a dedicated type -/// and implementing the `Iterator` trait for it. +/// and implementing the [`Iterator`] trait for it. /// /// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure, /// and therefore conservatively does not implement [`FusedIterator`], -/// or override [`Iterator::size_hint`] from its default `(0, None)`. -/// -/// [`FusedIterator`]: trait.FusedIterator.html -/// [`Iterator::size_hint`]: trait.Iterator.html#method.size_hint +/// or override [`Iterator::size_hint()`] from its default `(0, None)`. /// /// The closure can use captures and its environment to track state across iterations. Depending on -/// how the iterator is used, this may require specifying the `move` keyword on the closure. +/// how the iterator is used, this may require specifying the [`move`] keyword on the closure. +/// +/// [`move`]: ../../std/keyword.move.html /// /// # Examples /// @@ -549,10 +531,10 @@ where /// An iterator where each iteration calls the provided closure `F: FnMut() -> Option`. /// -/// This `struct` is created by the [`iter::from_fn`] function. +/// This `struct` is created by the [`iter::from_fn()`] function. /// See its documentation for more. /// -/// [`iter::from_fn`]: fn.from_fn.html +/// [`iter::from_fn()`]: from_fn #[derive(Clone)] #[stable(feature = "iter_from_fn", since = "1.34.0")] pub struct FromFn(F); @@ -601,10 +583,10 @@ where /// An new iterator where each successive item is computed based on the preceding one. /// -/// This `struct` is created by the [`successors`] function. +/// This `struct` is created by the [`iter::successors()`] function. /// See its documentation for more. /// -/// [`successors`]: fn.successors.html +/// [`iter::successors()`]: successors #[derive(Clone)] #[stable(feature = "iter_successors", since = "1.34.0")] pub struct Successors { diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 494c75174f..dc0d8087ff 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -4,14 +4,13 @@ use crate::ops::{Add, Mul}; /// Trait to represent types that can be created by summing up an iterator. /// -/// This trait is used to implement the [`sum`] method on iterators. Types which -/// implement the trait can be generated by the [`sum`] method. Like +/// This trait is used to implement the [`sum()`] method on iterators. Types which +/// implement the trait can be generated by the [`sum()`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::sum`]. +/// interacted with through [`Iterator::sum()`]. /// -/// [`sum`]: #tymethod.sum -/// [`FromIterator`]: crate::iter::FromIterator -/// [`Iterator::sum`]: crate::iter::Iterator::sum +/// [`sum()`]: Sum::sum +/// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Sum: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -23,14 +22,13 @@ pub trait Sum: Sized { /// Trait to represent types that can be created by multiplying elements of an /// iterator. /// -/// This trait is used to implement the [`product`] method on iterators. Types -/// which implement the trait can be generated by the [`product`] method. Like +/// This trait is used to implement the [`product()`] method on iterators. Types +/// which implement the trait can be generated by the [`product()`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::product`]. +/// interacted with through [`Iterator::product()`]. /// -/// [`product`]: #tymethod.product -/// [`FromIterator`]: crate::iter::FromIterator -/// [`Iterator::product`]: crate::iter::Iterator::product +/// [`product()`]: Product::product +/// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Product: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -120,9 +118,9 @@ impl Sum> for Result where T: Sum, { - /// Takes each element in the `Iterator`: if it is an `Err`, no further - /// elements are taken, and the `Err` is returned. Should no `Err` occur, - /// the sum of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further + /// elements are taken, and the [`Err`] is returned. Should no [`Err`] + /// occur, the sum of all elements is returned. /// /// # Examples /// @@ -150,9 +148,9 @@ impl Product> for Result where T: Product, { - /// Takes each element in the `Iterator`: if it is an `Err`, no further - /// elements are taken, and the `Err` is returned. Should no `Err` occur, - /// the product of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further + /// elements are taken, and the [`Err`] is returned. Should no [`Err`] + /// occur, the product of all elements is returned. fn product(iter: I) -> Result where I: Iterator>, @@ -166,9 +164,9 @@ impl Sum> for Option where T: Sum, { - /// Takes each element in the `Iterator`: if it is a `None`, no further - /// elements are taken, and the `None` is returned. Should no `None` occur, - /// the sum of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is a [`None`], no further + /// elements are taken, and the [`None`] is returned. Should no [`None`] + /// occur, the sum of all elements is returned. /// /// # Examples /// @@ -193,9 +191,9 @@ impl Product> for Option where T: Product, { - /// Takes each element in the `Iterator`: if it is a `None`, no further - /// elements are taken, and the `None` is returned. Should no `None` occur, - /// the product of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is a [`None`], no further + /// elements are taken, and the [`None`] is returned. Should no [`None`] + /// occur, the product of all elements is returned. fn product(iter: I) -> Option where I: Iterator>, diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 84c7787a18..41a503c4ab 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -1,21 +1,15 @@ -/// Conversion from an `Iterator`. +/// Conversion from an [`Iterator`]. /// /// By implementing `FromIterator` for a type, you define how it will be /// created from an iterator. This is common for types which describe a /// collection of some kind. /// -/// `FromIterator`'s [`from_iter`] is rarely called explicitly, and is instead -/// used through [`Iterator`]'s [`collect`] method. See [`collect`]'s +/// [`FromIterator::from_iter()`] is rarely called explicitly, and is instead +/// used through [`Iterator::collect()`] method. See [`Iterator::collect()`]'s /// documentation for more examples. /// -/// [`from_iter`]: #tymethod.from_iter -/// [`Iterator`]: trait.Iterator.html -/// [`collect`]: trait.Iterator.html#method.collect -/// /// See also: [`IntoIterator`]. /// -/// [`IntoIterator`]: trait.IntoIterator.html -/// /// # Examples /// /// Basic usage: @@ -30,7 +24,7 @@ /// assert_eq!(v, vec![5, 5, 5, 5, 5]); /// ``` /// -/// Using [`collect`] to implicitly use `FromIterator`: +/// Using [`Iterator::collect()`] to implicitly use `FromIterator`: /// /// ``` /// let five_fives = std::iter::repeat(5).take(5); @@ -119,7 +113,7 @@ pub trait FromIterator: Sized { fn from_iter>(iter: T) -> Self; } -/// Conversion into an `Iterator`. +/// Conversion into an [`Iterator`]. /// /// By implementing `IntoIterator` for a type, you define how it will be /// converted to an iterator. This is common for types which describe a @@ -130,8 +124,6 @@ pub trait FromIterator: Sized { /// /// See also: [`FromIterator`]. /// -/// [`FromIterator`]: trait.FromIterator.html -/// /// # Examples /// /// Basic usage: @@ -235,7 +227,7 @@ pub trait IntoIterator { /// assert_eq!(Some(3), iter.next()); /// assert_eq!(None, iter.next()); /// ``` - #[cfg_attr(not(bootstrap), lang = "into_iter")] + #[lang = "into_iter"] #[stable(feature = "rust1", since = "1.0.0")] fn into_iter(self) -> Self::IntoIter; } @@ -326,7 +318,7 @@ pub trait Extend { /// As this is the only required method for this trait, the [trait-level] docs /// contain more details. /// - /// [trait-level]: trait.Extend.html + /// [trait-level]: Extend /// /// # Examples /// diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 851a1e49a4..16bee0e2ee 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,5 +1,4 @@ -use crate::iter::LoopState; -use crate::ops::Try; +use crate::ops::{ControlFlow, Try}; /// An iterator able to yield elements from both ends. /// @@ -11,11 +10,12 @@ use crate::ops::Try; /// and do not cross: iteration is over when they meet in the middle. /// /// In a similar fashion to the [`Iterator`] protocol, once a -/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again -/// may or may not ever return `Some` again. `next()` and `next_back()` are -/// interchangeable for this purpose. +/// `DoubleEndedIterator` returns [`None`] from a [`next_back()`], calling it +/// again may or may not ever return [`Some`] again. [`next()`] and +/// [`next_back()`] are interchangeable for this purpose. /// -/// [`Iterator`]: trait.Iterator.html +/// [`next_back()`]: DoubleEndedIterator::next_back +/// [`next()`]: Iterator::next /// /// # Examples /// @@ -43,7 +43,7 @@ pub trait DoubleEndedIterator: Iterator { /// /// The [trait-level] docs contain more details. /// - /// [trait-level]: trait.DoubleEndedIterator.html + /// [trait-level]: DoubleEndedIterator /// /// # Examples /// @@ -67,7 +67,7 @@ pub trait DoubleEndedIterator: Iterator { /// # Remarks /// /// The elements yielded by `DoubleEndedIterator`'s methods may differ from - /// the ones yielded by `Iterator`'s methods: + /// the ones yielded by [`Iterator`]'s methods: /// /// ``` /// let vec = vec![(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b')]; @@ -88,25 +88,63 @@ pub trait DoubleEndedIterator: Iterator { /// vec![(2, 'b'), (1, 'c')] /// ); /// ``` - /// #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; + /// Advances the iterator from the back by `n` elements. + /// + /// `advance_back_by` is the reverse version of [`advance_by`]. This method will + /// eagerly skip `n` elements starting from the back by calling [`next_back`] up + /// to `n` times until [`None`] is encountered. + /// + /// `advance_back_by(n)` will return [`Ok(())`] if the iterator successfully advances by + /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number of + /// elements the iterator is advanced by before running out of elements (i.e. the length + /// of the iterator). Note that `k` is always less than `n`. + /// + /// Calling `advance_back_by(0)` does not consume any elements and always returns [`Ok(())`]. + /// + /// [`advance_by`]: Iterator::advance_by + /// [`next_back`]: DoubleEndedIterator::next_back + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_advance_by)] + /// + /// let a = [3, 4, 5, 6]; + /// let mut iter = a.iter(); + /// + /// assert_eq!(iter.advance_back_by(2), Ok(())); + /// assert_eq!(iter.next_back(), Some(&4)); + /// assert_eq!(iter.advance_back_by(0), Ok(())); + /// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped + /// ``` + #[inline] + #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + for i in 0..n { + self.next_back().ok_or(i)?; + } + Ok(()) + } + /// Returns the `n`th element from the end of the iterator. /// - /// This is essentially the reversed version of [`nth`]. Although like most indexing - /// operations, the count starts from zero, so `nth_back(0)` returns the first value from - /// the end, `nth_back(1)` the second, and so on. + /// This is essentially the reversed version of [`Iterator::nth()`]. + /// Although like most indexing operations, the count starts from zero, so + /// `nth_back(0)` returns the first value from the end, `nth_back(1)` the + /// second, and so on. /// /// Note that all elements between the end and the returned element will be /// consumed, including the returned element. This also means that calling /// `nth_back(0)` multiple times on the same iterator will return different /// elements. /// - /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the - /// iterator. - /// - /// [`nth`]: crate::iter::Iterator::nth + /// `nth_back()` will return [`None`] if `n` is greater than or equal to the + /// length of the iterator. /// /// # Examples /// @@ -136,20 +174,13 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_nth_back", since = "1.37.0")] - fn nth_back(&mut self, mut n: usize) -> Option { - for x in self.rev() { - if n == 0 { - return Some(x); - } - n -= 1; - } - None + fn nth_back(&mut self, n: usize) -> Option { + self.advance_back_by(n).ok()?; + self.next_back() } - /// This is the reverse version of [`try_fold()`]: it takes elements - /// starting from the back of the iterator. - /// - /// [`try_fold()`]: trait.Iterator.html#method.try_fold + /// This is the reverse version of [`Iterator::try_fold()`]: it takes + /// elements starting from the back of the iterator. /// /// # Examples /// @@ -196,8 +227,8 @@ pub trait DoubleEndedIterator: Iterator { /// An iterator method that reduces the iterator's elements to a single, /// final value, starting from the back. /// - /// This is the reverse version of [`fold()`]: it takes elements starting from - /// the back of the iterator. + /// This is the reverse version of [`Iterator::fold()`]: it takes elements + /// starting from the back of the iterator. /// /// `rfold()` takes two arguments: an initial value, and a closure with two /// arguments: an 'accumulator', and an element. The closure returns the value that @@ -214,8 +245,6 @@ pub trait DoubleEndedIterator: Iterator { /// Folding is useful whenever you have a collection of something, and want /// to produce a single value from it. /// - /// [`fold()`]: trait.Iterator.html#method.fold - /// /// # Examples /// /// Basic usage: @@ -309,9 +338,9 @@ pub trait DoubleEndedIterator: Iterator { #[inline] fn check( mut predicate: impl FnMut(&T) -> bool, - ) -> impl FnMut((), T) -> LoopState<(), T> { + ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } } @@ -324,6 +353,9 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { fn next_back(&mut self) -> Option { (**self).next_back() } + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + (**self).advance_back_by(n) + } fn nth_back(&mut self, n: usize) -> Option { (**self).nth_back(n) } diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs index ad87d09588..33ace60a27 100644 --- a/library/core/src/iter/traits/exact_size.rs +++ b/library/core/src/iter/traits/exact_size.rs @@ -6,17 +6,14 @@ /// backwards, a good start is to know where the end is. /// /// When implementing an `ExactSizeIterator`, you must also implement -/// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must* -/// return the exact size of the iterator. -/// -/// [`Iterator`]: trait.Iterator.html -/// [`size_hint`]: trait.Iterator.html#method.size_hint +/// [`Iterator`]. When doing so, the implementation of [`Iterator::size_hint`] +/// *must* return the exact size of the iterator. /// /// The [`len`] method has a default implementation, so you usually shouldn't /// implement it. However, you may be able to provide a more performant /// implementation than the default, so overriding it in this case makes sense. /// -/// [`len`]: #method.len +/// [`len`]: ExactSizeIterator::len /// /// # Examples /// @@ -72,17 +69,17 @@ pub trait ExactSizeIterator: Iterator { /// Returns the exact length of the iterator. /// /// The implementation ensures that the iterator will return exactly `len()` - /// more times a `Some(T)` value, before returning `None`. + /// more times a [`Some(T)`] value, before returning [`None`]. /// This method has a default implementation, so you usually should not /// implement it directly. However, if you can provide a more efficient /// implementation, you can do so. See the [trait-level] docs for an /// example. /// - /// This function has the same safety guarantees as the [`size_hint`] - /// function. + /// This function has the same safety guarantees as the + /// [`Iterator::size_hint`] function. /// - /// [trait-level]: trait.ExactSizeIterator.html - /// [`size_hint`]: trait.Iterator.html#method.size_hint + /// [trait-level]: ExactSizeIterator + /// [`Some(T)`]: Some /// /// # Examples /// @@ -108,8 +105,8 @@ pub trait ExactSizeIterator: Iterator { /// Returns `true` if the iterator is empty. /// - /// This method has a default implementation using `self.len()`, so you - /// don't need to implement it yourself. + /// This method has a default implementation using + /// [`ExactSizeIterator::len()`], so you don't need to implement it yourself. /// /// # Examples /// diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 10498f94c2..813afcc0ec 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3,9 +3,8 @@ // can't split that into multiple files. use crate::cmp::{self, Ordering}; -use crate::ops::{Add, Try}; +use crate::ops::{Add, ControlFlow, Try}; -use super::super::LoopState; use super::super::TrustedRandomAccess; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; @@ -22,8 +21,8 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} /// generally, please see the [module-level documentation]. In particular, you /// may want to know how to [implement `Iterator`][impl]. /// -/// [module-level documentation]: index.html -/// [impl]: index.html#implementing-iterator +/// [module-level documentation]: crate::iter +/// [impl]: crate::iter#implementing-iterator #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( @@ -130,7 +129,7 @@ pub trait Iterator { /// assert_eq!(None, iter.next()); /// assert_eq!(None, iter.next()); /// ``` - #[cfg_attr(not(bootstrap), lang = "next")] + #[lang = "next"] #[stable(feature = "rust1", since = "1.0.0")] fn next(&mut self) -> Option; @@ -212,7 +211,7 @@ pub trait Iterator { /// returning the number of times it saw [`Some`]. Note that [`next`] has to be /// called at least once even if the iterator does not have any elements. /// - /// [`next`]: #tymethod.next + /// [`next`]: Iterator::next /// /// # Overflow Behavior /// @@ -285,6 +284,44 @@ pub trait Iterator { self.fold(None, some) } + /// Advances the iterator by `n` elements. + /// + /// This method will eagerly skip `n` elements by calling [`next`] up to `n` + /// times until [`None`] is encountered. + /// + /// `advance_by(n)` will return [`Ok(())`] if the iterator successfully advances by + /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number + /// of elements the iterator is advanced by before running out of elements (i.e. the + /// length of the iterator). Note that `k` is always less than `n`. + /// + /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`]. + /// + /// [`next`]: Iterator::next + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_advance_by)] + /// + /// let a = [1, 2, 3, 4]; + /// let mut iter = a.iter(); + /// + /// assert_eq!(iter.advance_by(2), Ok(())); + /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.advance_by(0), Ok(())); + /// assert_eq!(iter.advance_by(100), Err(1)); // only `&4` was skipped + /// ``` + #[inline] + #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + for i in 0..n { + self.next().ok_or(i)?; + } + Ok(()) + } + /// Returns the `n`th element of the iterator. /// /// Like most indexing operations, the count starts from zero, so `nth(0)` @@ -326,14 +363,9 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn nth(&mut self, mut n: usize) -> Option { - while let Some(x) = self.next() { - if n == 0 { - return Some(x); - } - n -= 1; - } - None + fn nth(&mut self, n: usize) -> Option { + self.advance_by(n).ok()?; + self.next() } /// Creates an iterator starting at the same point, but stepping by @@ -449,9 +481,7 @@ pub trait Iterator { /// } /// ``` /// - /// [`once`]: fn.once.html - /// [`Iterator`]: trait.Iterator.html - /// [`IntoIterator`]: trait.IntoIterator.html + /// [`once`]: crate::iter::once /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -496,9 +526,6 @@ pub trait Iterator { /// [`Iterator`] itself. For example, slices (`&[T]`) implement /// [`IntoIterator`], and so can be passed to `zip()` directly: /// - /// [`IntoIterator`]: trait.IntoIterator.html - /// [`Iterator`]: trait.Iterator.html - /// /// ``` /// let s1 = &[1, 2, 3]; /// let s2 = &[4, 5, 6]; @@ -530,8 +557,8 @@ pub trait Iterator { /// assert_eq!((2, 'o'), zipper[2]); /// ``` /// - /// [`enumerate`]: #method.enumerate - /// [`next`]: #tymethod.next + /// [`enumerate`]: Iterator::enumerate + /// [`next`]: Iterator::next #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn zip(self, other: U) -> Zip @@ -654,11 +681,9 @@ pub trait Iterator { /// Creates an iterator which uses a closure to determine if an element /// should be yielded. /// - /// The closure must return `true` or `false`. `filter()` creates an - /// iterator which calls this closure on each element. If the closure - /// returns `true`, then the element is returned. If the closure returns - /// `false`, it will try again, and call the closure on the next element, - /// seeing if it passes the test. + /// Given an element the closure must return `true` or `false`. The returned + /// iterator will yield only the elements for which the closure returns + /// true. /// /// # Examples /// @@ -725,23 +750,15 @@ pub trait Iterator { /// Creates an iterator that both filters and maps. /// - /// The closure must return an [`Option`]. `filter_map` creates an - /// iterator which calls this closure on each element. If the closure - /// returns [`Some(element)`][`Some`], then that element is returned. If the - /// closure returns [`None`], it will try again, and call the closure on the - /// next element, seeing if it will return [`Some`]. + /// The returned iterator yields only the `value`s for which the supplied + /// closure returns `Some(value)`. /// - /// Why `filter_map` and not just [`filter`] and [`map`]? The key is in this - /// part: + /// `filter_map` can be used to make chains of [`filter`] and [`map`] more + /// concise. The example below shows how a `map().filter().map()` can be + /// shortened to a single call to `filter_map`. /// - /// [`filter`]: #method.filter - /// [`map`]: #method.map - /// - /// > If the closure returns [`Some(element)`][`Some`], then that element is returned. - /// - /// In other words, it removes the [`Option`] layer automatically. If your - /// mapping is already returning an [`Option`] and you want to skip over - /// [`None`]s, then `filter_map` is much, much nicer to use. + /// [`filter`]: Iterator::filter + /// [`map`]: Iterator::map /// /// # Examples /// @@ -802,7 +819,7 @@ pub trait Iterator { /// /// [`usize`]: type@usize /// [`usize::MAX`]: crate::usize::MAX - /// [`zip`]: #method.zip + /// [`zip`]: Iterator::zip /// /// # Examples /// @@ -825,7 +842,7 @@ pub trait Iterator { Enumerate::new(self) } - /// Creates an iterator which can use `peek` to look at the next element of + /// Creates an iterator which can use [`peek`] to look at the next element of /// the iterator without consuming it. /// /// Adds a [`peek`] method to an iterator. See its documentation for @@ -837,8 +854,8 @@ pub trait Iterator { /// anything other than fetching the next value) of the [`next`] method /// will occur. /// - /// [`peek`]: crate::iter::Peekable::peek - /// [`next`]: #tymethod.next + /// [`peek`]: Peekable::peek + /// [`next`]: Iterator::next /// /// # Examples /// @@ -876,7 +893,7 @@ pub trait Iterator { /// Creates an iterator that [`skip`]s elements based on a predicate. /// - /// [`skip`]: #method.skip + /// [`skip`]: Iterator::skip /// /// `skip_while()` takes a closure as an argument. It will call this /// closure on each element of the iterator, and ignore elements @@ -1043,8 +1060,8 @@ pub trait Iterator { /// /// Here's the same example, but with [`take_while`] and [`map`]: /// - /// [`take_while`]: #method.take_while - /// [`map`]: #method.map + /// [`take_while`]: Iterator::take_while + /// [`map`]: Iterator::map /// /// ``` /// let a = [-1i32, 4, 0, 1]; @@ -1104,7 +1121,7 @@ pub trait Iterator { /// It is also not specified what this iterator returns after the first` None` is returned. /// If you need fused iterator, use [`fuse`]. /// - /// [`fuse`]: #method.fuse + /// [`fuse`]: Iterator::fuse #[inline] #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] fn map_while(self, predicate: P) -> MapWhile @@ -1190,7 +1207,7 @@ pub trait Iterator { /// An iterator adaptor similar to [`fold`] that holds internal state and /// produces a new iterator. /// - /// [`fold`]: #method.fold + /// [`fold`]: Iterator::fold /// /// `scan()` takes two arguments: an initial value which seeds the internal /// state, and a closure with two arguments, the first being a mutable @@ -1246,8 +1263,8 @@ pub trait Iterator { /// one item for each element, and `flat_map()`'s closure returns an /// iterator for each element. /// - /// [`map`]: #method.map - /// [`flatten`]: #method.flatten + /// [`map`]: Iterator::map + /// [`flatten`]: Iterator::flatten /// /// # Examples /// @@ -1333,7 +1350,7 @@ pub trait Iterator { /// two-dimensional and not one-dimensional. To get a one-dimensional /// structure, you have to `flatten()` again. /// - /// [`flat_map()`]: #method.flat_map + /// [`flat_map()`]: Iterator::flat_map #[inline] #[stable(feature = "iterator_flatten", since = "1.29.0")] fn flatten(self) -> Flatten @@ -1640,7 +1657,7 @@ pub trait Iterator { /// assert_eq!(Ok(vec![1, 3]), result); /// ``` /// - /// [`iter`]: #tymethod.next + /// [`iter`]: Iterator::next /// [`String`]: ../../std/string/struct.String.html /// [`char`]: type@char #[inline] @@ -1661,8 +1678,8 @@ pub trait Iterator { /// /// See also [`is_partitioned()`] and [`partition_in_place()`]. /// - /// [`is_partitioned()`]: #method.is_partitioned - /// [`partition_in_place()`]: #method.partition_in_place + /// [`is_partitioned()`]: Iterator::is_partitioned + /// [`partition_in_place()`]: Iterator::partition_in_place /// /// # Examples /// @@ -1716,8 +1733,8 @@ pub trait Iterator { /// /// See also [`is_partitioned()`] and [`partition()`]. /// - /// [`is_partitioned()`]: #method.is_partitioned - /// [`partition()`]: #method.partition + /// [`is_partitioned()`]: Iterator::is_partitioned + /// [`partition()`]: Iterator::partition /// /// # Examples /// @@ -1779,8 +1796,8 @@ pub trait Iterator { /// /// See also [`partition()`] and [`partition_in_place()`]. /// - /// [`partition()`]: #method.partition - /// [`partition_in_place()`]: #method.partition_in_place + /// [`partition()`]: Iterator::partition + /// [`partition_in_place()`]: Iterator::partition_in_place /// /// # Examples /// @@ -1879,8 +1896,8 @@ pub trait Iterator { /// This can also be thought of as the fallible form of [`for_each()`] /// or as the stateless version of [`try_fold()`]. /// - /// [`for_each()`]: #method.for_each - /// [`try_fold()`]: #method.try_fold + /// [`for_each()`]: Iterator::for_each + /// [`try_fold()`]: Iterator::try_fold /// /// # Examples /// @@ -1992,6 +2009,8 @@ pub trait Iterator { /// // they're the same /// assert_eq!(result, result2); /// ``` + #[doc(alias = "reduce")] + #[doc(alias = "inject")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn fold(mut self, init: B, mut f: F) -> B @@ -2006,11 +2025,13 @@ pub trait Iterator { accum } - /// The same as [`fold()`](#method.fold), but uses the first element in the + /// The same as [`fold()`], but uses the first element in the /// iterator as the initial value, folding every subsequent element into it. - /// If the iterator is empty, return `None`; otherwise, return the result + /// If the iterator is empty, return [`None`]; otherwise, return the result /// of the fold. /// + /// [`fold()`]: Iterator::fold + /// /// # Example /// /// Find the maximum value: @@ -2088,12 +2109,12 @@ pub trait Iterator { F: FnMut(Self::Item) -> bool, { #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> { + fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { LoopState::Continue(()) } else { LoopState::Break(()) } + if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } } } - self.try_fold((), check(f)) == LoopState::Continue(()) + self.try_fold((), check(f)) == ControlFlow::CONTINUE } /// Tests if any element of the iterator matches a predicate. @@ -2141,13 +2162,13 @@ pub trait Iterator { F: FnMut(Self::Item) -> bool, { #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> { + fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { LoopState::Break(()) } else { LoopState::Continue(()) } + if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } } - self.try_fold((), check(f)) == LoopState::Break(()) + self.try_fold((), check(f)) == ControlFlow::BREAK } /// Searches for an element of an iterator that satisfies a predicate. @@ -2203,9 +2224,9 @@ pub trait Iterator { #[inline] fn check( mut predicate: impl FnMut(&T) -> bool, - ) -> impl FnMut((), T) -> LoopState<(), T> { + ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } } @@ -2217,7 +2238,6 @@ pub trait Iterator { /// /// `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`. /// - /// /// # Examples /// /// ``` @@ -2235,10 +2255,12 @@ pub trait Iterator { F: FnMut(Self::Item) -> Option, { #[inline] - fn check(mut f: impl FnMut(T) -> Option) -> impl FnMut((), T) -> LoopState<(), B> { + fn check( + mut f: impl FnMut(T) -> Option, + ) -> impl FnMut((), T) -> ControlFlow<(), B> { move |(), x| match f(x) { - Some(x) => LoopState::Break(x), - None => LoopState::Continue(()), + Some(x) => ControlFlow::Break(x), + None => ControlFlow::CONTINUE, } } @@ -2274,15 +2296,15 @@ pub trait Iterator { R: Try, { #[inline] - fn check(mut f: F) -> impl FnMut((), T) -> LoopState<(), Result> + fn check(mut f: F) -> impl FnMut((), T) -> ControlFlow<(), Result> where F: FnMut(&T) -> R, R: Try, { move |(), x| match f(&x).into_result() { - Ok(false) => LoopState::Continue(()), - Ok(true) => LoopState::Break(Ok(x)), - Err(x) => LoopState::Break(Err(x)), + Ok(false) => ControlFlow::CONTINUE, + Ok(true) => ControlFlow::Break(Ok(x)), + Err(x) => ControlFlow::Break(Err(x)), } } @@ -2352,10 +2374,14 @@ pub trait Iterator { #[inline] fn check( mut predicate: impl FnMut(T) -> bool, - ) -> impl FnMut(usize, T) -> LoopState { + ) -> impl FnMut(usize, T) -> ControlFlow { // The addition might panic on overflow move |i, x| { - if predicate(x) { LoopState::Break(i) } else { LoopState::Continue(Add::add(i, 1)) } + if predicate(x) { + ControlFlow::Break(i) + } else { + ControlFlow::Continue(Add::add(i, 1)) + } } } @@ -2411,10 +2437,10 @@ pub trait Iterator { #[inline] fn check( mut predicate: impl FnMut(T) -> bool, - ) -> impl FnMut(usize, T) -> LoopState { + ) -> impl FnMut(usize, T) -> ControlFlow { move |i, x| { let i = i - 1; - if predicate(x) { LoopState::Break(i) } else { LoopState::Continue(i) } + if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i) } } } @@ -2602,8 +2628,6 @@ pub trait Iterator { /// This is only possible if the iterator has an end, so `rev()` only /// works on [`DoubleEndedIterator`]s. /// - /// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html - /// /// # Examples /// /// ``` @@ -2634,7 +2658,7 @@ pub trait Iterator { /// /// This function is, in some sense, the opposite of [`zip`]. /// - /// [`zip`]: #method.zip + /// [`zip`]: Iterator::zip /// /// # Examples /// @@ -2713,7 +2737,7 @@ pub trait Iterator { /// This is useful when you have an iterator over `&T`, but you need an /// iterator over `T`. /// - /// [`clone`]: crate::clone::Clone::clone + /// [`clone`]: Clone::clone /// /// # Examples /// @@ -2831,7 +2855,7 @@ pub trait Iterator { Product::product(self) } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another. /// /// # Examples @@ -2853,7 +2877,7 @@ pub trait Iterator { self.cmp_by(other, |x, y| x.cmp(&y)) } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another with respect to the specified comparison function. /// /// # Examples @@ -2905,7 +2929,7 @@ pub trait Iterator { } } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another. /// /// # Examples @@ -2929,7 +2953,7 @@ pub trait Iterator { self.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another with respect to the specified comparison function. /// /// # Examples @@ -2990,7 +3014,7 @@ pub trait Iterator { } } - /// Determines if the elements of this `Iterator` are equal to those of + /// Determines if the elements of this [`Iterator`] are equal to those of /// another. /// /// # Examples @@ -3009,7 +3033,7 @@ pub trait Iterator { self.eq_by(other, |x, y| x == y) } - /// Determines if the elements of this `Iterator` are equal to those of + /// Determines if the elements of this [`Iterator`] are equal to those of /// another with respect to the specified equality function. /// /// # Examples @@ -3050,7 +3074,7 @@ pub trait Iterator { } } - /// Determines if the elements of this `Iterator` are unequal to those of + /// Determines if the elements of this [`Iterator`] are unequal to those of /// another. /// /// # Examples @@ -3069,7 +3093,7 @@ pub trait Iterator { !self.eq(other) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// less than those of another. /// /// # Examples @@ -3078,6 +3102,7 @@ pub trait Iterator { /// assert_eq!([1].iter().lt([1].iter()), false); /// assert_eq!([1].iter().lt([1, 2].iter()), true); /// assert_eq!([1, 2].iter().lt([1].iter()), false); + /// assert_eq!([1, 2].iter().lt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn lt(self, other: I) -> bool @@ -3089,7 +3114,7 @@ pub trait Iterator { self.partial_cmp(other) == Some(Ordering::Less) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// less or equal to those of another. /// /// # Examples @@ -3098,6 +3123,7 @@ pub trait Iterator { /// assert_eq!([1].iter().le([1].iter()), true); /// assert_eq!([1].iter().le([1, 2].iter()), true); /// assert_eq!([1, 2].iter().le([1].iter()), false); + /// assert_eq!([1, 2].iter().le([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn le(self, other: I) -> bool @@ -3109,7 +3135,7 @@ pub trait Iterator { matches!(self.partial_cmp(other), Some(Ordering::Less | Ordering::Equal)) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// greater than those of another. /// /// # Examples @@ -3118,6 +3144,7 @@ pub trait Iterator { /// assert_eq!([1].iter().gt([1].iter()), false); /// assert_eq!([1].iter().gt([1, 2].iter()), false); /// assert_eq!([1, 2].iter().gt([1].iter()), true); + /// assert_eq!([1, 2].iter().gt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn gt(self, other: I) -> bool @@ -3129,7 +3156,7 @@ pub trait Iterator { self.partial_cmp(other) == Some(Ordering::Greater) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// greater than or equal to those of another. /// /// # Examples @@ -3138,6 +3165,7 @@ pub trait Iterator { /// assert_eq!([1].iter().ge([1].iter()), true); /// assert_eq!([1].iter().ge([1, 2].iter()), false); /// assert_eq!([1, 2].iter().ge([1].iter()), true); + /// assert_eq!([1, 2].iter().ge([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn ge(self, other: I) -> bool @@ -3197,7 +3225,7 @@ pub trait Iterator { /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b))); /// ``` /// - /// [`is_sorted`]: #method.is_sorted + /// [`is_sorted`]: Iterator::is_sorted #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] fn is_sorted_by(mut self, mut compare: F) -> bool where @@ -3226,7 +3254,7 @@ pub trait Iterator { /// the elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see /// its documentation for more information. /// - /// [`is_sorted`]: #method.is_sorted + /// [`is_sorted`]: Iterator::is_sorted /// /// # Examples /// @@ -3248,6 +3276,8 @@ pub trait Iterator { } /// See [TrustedRandomAccess] + // The unusual name is to avoid name collisions in method resolution + // see #76479. #[inline] #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] @@ -3268,6 +3298,9 @@ impl Iterator for &mut I { fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + (**self).advance_by(n) + } fn nth(&mut self, n: usize) -> Option { (**self).nth(n) } diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index 3c893c0399..0900676146 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -2,14 +2,13 @@ /// /// Calling next on a fused iterator that has returned `None` once is guaranteed /// to return [`None`] again. This trait should be implemented by all iterators -/// that behave this way because it allows optimizing [`Iterator::fuse`]. +/// that behave this way because it allows optimizing [`Iterator::fuse()`]. /// /// Note: In general, you should not use `FusedIterator` in generic bounds if -/// you need a fused iterator. Instead, you should just call [`Iterator::fuse`] +/// you need a fused iterator. Instead, you should just call [`Iterator::fuse()`] /// on the iterator. If the iterator is already fused, the additional [`Fuse`] /// wrapper will be a no-op with no performance penalty. /// -/// [`Iterator::fuse`]: crate::iter::Iterator::fuse /// [`Fuse`]: crate::iter::Fuse #[stable(feature = "fused", since = "1.26.0")] #[rustc_unsafe_specialization_marker] @@ -24,21 +23,34 @@ impl FusedIterator for &mut I {} /// (lower bound is equal to upper bound), or the upper bound is [`None`]. /// The upper bound must only be [`None`] if the actual iterator length is /// larger than [`usize::MAX`]. In that case, the lower bound must be -/// [`usize::MAX`], resulting in a [`.size_hint`] of `(usize::MAX, None)`. +/// [`usize::MAX`], resulting in a [`Iterator::size_hint()`] of +/// `(usize::MAX, None)`. /// /// The iterator must produce exactly the number of elements it reported /// or diverge before reaching the end. /// /// # Safety /// -/// This trait must only be implemented when the contract is upheld. -/// Consumers of this trait must inspect [`.size_hint`]’s upper bound. +/// This trait must only be implemented when the contract is upheld. Consumers +/// of this trait must inspect [`Iterator::size_hint()`]’s upper bound. /// /// [`usize::MAX`]: crate::usize::MAX -/// [`.size_hint`]: crate::iter::Iterator::size_hint #[unstable(feature = "trusted_len", issue = "37572")] #[rustc_unsafe_specialization_marker] pub unsafe trait TrustedLen: Iterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for &mut I {} + +/// An iterator that when yielding an item will have taken at least one element +/// from its underlying [`SourceIter`]. +/// +/// Calling [`next()`] guarantees that at least one value of the iterator's underlying source +/// has been moved out and the result of the iterator chain could be inserted in its place, +/// assuming structural constraints of the source allow such an insertion. +/// In other words this trait indicates that an iterator pipeline can be collected in place. +/// +/// [`SourceIter`]: crate::iter::SourceIter +/// [`next()`]: Iterator::next +#[unstable(issue = "none", feature = "inplace_iteration")] +pub unsafe trait InPlaceIterable: Iterator {} diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs index efd1580a54..880f8d831f 100644 --- a/library/core/src/iter/traits/mod.rs +++ b/library/core/src/iter/traits/mod.rs @@ -11,5 +11,7 @@ pub use self::double_ended::DoubleEndedIterator; pub use self::exact_size::ExactSizeIterator; #[stable(feature = "rust1", since = "1.0.0")] pub use self::iterator::Iterator; +#[unstable(issue = "none", feature = "inplace_iteration")] +pub use self::marker::InPlaceIterable; #[stable(feature = "rust1", since = "1.0.0")] pub use self::marker::{FusedIterator, TrustedLen}; diff --git a/library/core/src/lazy.rs b/library/core/src/lazy.rs index 5cf7217ef1..2c517371c2 100644 --- a/library/core/src/lazy.rs +++ b/library/core/src/lazy.rs @@ -92,7 +92,7 @@ impl OnceCell { /// Returns `None` if the cell is empty. #[unstable(feature = "once_cell", issue = "74465")] pub fn get(&self) -> Option<&T> { - // Safety: Safe due to `inner`'s invariant + // SAFETY: Safe due to `inner`'s invariant unsafe { &*self.inner.get() }.as_ref() } @@ -101,7 +101,7 @@ impl OnceCell { /// Returns `None` if the cell is empty. #[unstable(feature = "once_cell", issue = "74465")] pub fn get_mut(&mut self) -> Option<&mut T> { - // Safety: Safe because we have unique access + // SAFETY: Safe because we have unique access unsafe { &mut *self.inner.get() }.as_mut() } @@ -129,13 +129,13 @@ impl OnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn set(&self, value: T) -> Result<(), T> { - // Safety: Safe because we cannot have overlapping mutable borrows + // SAFETY: Safe because we cannot have overlapping mutable borrows let slot = unsafe { &*self.inner.get() }; if slot.is_some() { return Err(value); } - // Safety: This is the only place where we set the slot, no races + // SAFETY: This is the only place where we set the slot, no races // due to reentrancy/concurrency are possible, and we've // checked that slot is currently `None`, so this write // maintains the `inner`'s invariant. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 8270b73203..22bf2b15d6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -66,9 +66,7 @@ #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(asm)] -#![feature(bound_cloned)] #![feature(cfg_target_has_atomic)] -#![feature(concat_idents)] #![feature(const_alloc_layout)] #![feature(const_discriminant)] #![feature(const_checked_int_methods)] @@ -77,17 +75,21 @@ #![feature(const_float_bits_conv)] #![feature(const_overflowing_int_methods)] #![feature(const_int_unchecked_arith)] +#![feature(const_mut_refs)] #![feature(const_int_pow)] #![feature(constctlz)] #![feature(const_panic)] +#![feature(const_pin)] #![feature(const_fn_union)] +#![feature(const_fn)] +#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))] +#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))] #![feature(const_generics)] #![feature(const_option)] #![feature(const_precise_live_drops)] #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_raw_ptr_comparison)] -#![feature(const_result)] #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] #![feature(const_size_of_val)] @@ -99,13 +101,12 @@ #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] -#![cfg_attr(not(bootstrap), feature(doc_spotlight))] +#![feature(doc_spotlight)] #![feature(duration_consts_2)] +#![feature(duration_saturating_ops)] #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] -#![feature(try_find)] -#![feature(is_sorted)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] @@ -117,7 +118,6 @@ #![feature(optin_builtin_traits)] #![feature(or_patterns)] #![feature(prelude_import)] -#![feature(ptr_as_uninit)] #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] #![feature(simd_ffi)] @@ -131,8 +131,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(variant_count)] -#![feature(doc_alias)] -#![feature(mmx_target_feature)] +#![cfg_attr(bootstrap, feature(doc_alias))] #![feature(tbm_target_feature)] #![feature(sse4a_target_feature)] #![feature(arm_target_feature)] @@ -148,8 +147,6 @@ #![feature(const_fn_transmute)] #![feature(abi_unadjusted)] #![feature(adx_target_feature)] -#![feature(maybe_uninit_slice)] -#![feature(maybe_uninit_extra)] #![feature(external_doc)] #![feature(associated_type_bounds)] #![feature(const_caller_location)] @@ -169,34 +166,34 @@ mod macros; #[macro_use] mod internal_macros; -#[path = "num/int_macros.rs"] +#[path = "num/shells/int_macros.rs"] #[macro_use] mod int_macros; -#[path = "num/i128.rs"] +#[path = "num/shells/i128.rs"] pub mod i128; -#[path = "num/i16.rs"] +#[path = "num/shells/i16.rs"] pub mod i16; -#[path = "num/i32.rs"] +#[path = "num/shells/i32.rs"] pub mod i32; -#[path = "num/i64.rs"] +#[path = "num/shells/i64.rs"] pub mod i64; -#[path = "num/i8.rs"] +#[path = "num/shells/i8.rs"] pub mod i8; -#[path = "num/isize.rs"] +#[path = "num/shells/isize.rs"] pub mod isize; -#[path = "num/u128.rs"] +#[path = "num/shells/u128.rs"] pub mod u128; -#[path = "num/u16.rs"] +#[path = "num/shells/u16.rs"] pub mod u16; -#[path = "num/u32.rs"] +#[path = "num/shells/u32.rs"] pub mod u32; -#[path = "num/u64.rs"] +#[path = "num/shells/u64.rs"] pub mod u64; -#[path = "num/u8.rs"] +#[path = "num/shells/u8.rs"] pub mod u8; -#[path = "num/usize.rs"] +#[path = "num/shells/usize.rs"] pub mod usize; #[path = "num/f32.rs"] @@ -221,52 +218,41 @@ pub mod ptr; /* Core language traits */ pub mod borrow; -#[cfg(not(test))] // See #65860 pub mod clone; -#[cfg(not(test))] // See #65860 pub mod cmp; pub mod convert; -#[cfg(not(test))] // See #65860 pub mod default; -#[cfg(not(test))] // See #65860 pub mod marker; pub mod ops; /* Core types and methods on primitives */ pub mod any; -#[cfg(not(test))] // See #65860 pub mod array; pub mod ascii; pub mod cell; pub mod char; pub mod ffi; -#[cfg(not(test))] // See #65860 pub mod iter; #[unstable(feature = "once_cell", issue = "74465")] pub mod lazy; pub mod option; pub mod panic; pub mod panicking; -#[cfg(not(test))] // See #65860 pub mod pin; pub mod raw; pub mod result; pub mod sync; -#[cfg(not(test))] // See #65860 pub mod fmt; -#[cfg(not(test))] // See #65860 pub mod hash; pub mod slice; -#[cfg(not(test))] // See #65860 pub mod str; pub mod time; pub mod unicode; /* Async */ -#[cfg(not(test))] // See #65860 pub mod future; pub mod task; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index d26f2124f1..a1b0821004 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -242,7 +242,7 @@ macro_rules! debug_assert_ne { #[macro_export] #[stable(feature = "matches_macro", since = "1.42.0")] macro_rules! matches { - ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )?) => { + ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => { match $expression { $( $pattern )|+ $( if $guard )? => true, _ => false @@ -333,16 +333,16 @@ macro_rules! r#try { /// This macro accepts a format string, a list of arguments, and a 'writer'. Arguments will be /// formatted according to the specified format string and the result will be passed to the writer. /// The writer may be any value with a `write_fmt` method; generally this comes from an -/// implementation of either the [`std::fmt::Write`] or the [`std::io::Write`] trait. The macro -/// returns whatever the `write_fmt` method returns; commonly a [`std::fmt::Result`], or an +/// implementation of either the [`fmt::Write`] or the [`io::Write`] trait. The macro +/// returns whatever the `write_fmt` method returns; commonly a [`fmt::Result`], or an /// [`io::Result`]. /// /// See [`std::fmt`] for more information on the format string syntax. /// /// [`std::fmt`]: crate::fmt -/// [`std::fmt::Write`]: crate::fmt::Write -/// [`std::io::Write`]: ../std/io/trait.Write.html -/// [`std::fmt::Result`]: crate::fmt::Result +/// [`fmt::Write`]: crate::fmt::Write +/// [`io::Write`]: ../std/io/trait.Write.html +/// [`fmt::Result`]: crate::fmt::Result /// [`io::Result`]: ../std/io/type.Result.html /// /// # Examples diff --git a/library/core/src/macros/panic.md b/library/core/src/macros/panic.md index 3ecfc43be0..a02e74d5e5 100644 --- a/library/core/src/macros/panic.md +++ b/library/core/src/macros/panic.md @@ -5,12 +5,12 @@ to the caller of the program. `panic!` should be used when a program reaches an unrecoverable state. This macro is the perfect way to assert conditions in example code and in -tests. `panic!` is closely tied with the `unwrap` method of both [`Option`] -and [`Result`][runwrap] enums. Both implementations call `panic!` when they are set -to None or Err variants. +tests. `panic!` is closely tied with the `unwrap` method of both +[`Option`][ounwrap] and [`Result`][runwrap] enums. Both implementations call +`panic!` when they are set to [`None`] or [`Err`] variants. This macro is used to inject panic into a Rust thread, causing the thread to -panic entirely. Each thread's panic can be reaped as the `Box` type, +panic entirely. Each thread's panic can be reaped as the [`Box`]`<`[`Any`]`>` type, and the single-argument form of the `panic!` macro will be the value which is transmitted. @@ -24,11 +24,11 @@ The multi-argument form of this macro panics with a string and has the See also the macro [`compile_error!`], for raising errors during compilation. -[runwrap]: ../std/result/enum.Result.html#method.unwrap -[`Option`]: ../std/option/enum.Option.html#method.unwrap -[`Result`]: ../std/result/enum.Result.html +[ounwrap]: Option::unwrap +[runwrap]: Result::unwrap +[`Box`]: ../std/boxed/struct.Box.html +[`Any`]: crate::any::Any [`format!`]: ../std/macro.format.html -[`compile_error!`]: ../std/macro.compile_error.html [book]: ../book/ch09-00-error-handling.html # Current implementation diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 9326aaf568..cdf742057b 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -111,13 +111,13 @@ pub trait Sized { /// - `T` is not part of the type of any other fields /// - `Bar: Unsize>`, if the last field of `Foo` has type `Bar` /// -/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow -/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized +/// `Unsize` is used along with [`ops::CoerceUnsized`] to allow +/// "user-defined" containers such as [`Rc`] to contain dynamically-sized /// types. See the [DST coercion RFC][RFC982] and [the nomicon entry on coercion][nomicon-coerce] /// for more details. /// -/// [coerceunsized]: ../ops/trait.CoerceUnsized.html -/// [rc]: ../../std/rc/struct.Rc.html +/// [`ops::CoerceUnsized`]: crate::ops::CoerceUnsized +/// [`Rc`]: ../../std/rc/struct.Rc.html /// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "unsize", issue = "27732")] @@ -368,11 +368,7 @@ pub trait StructuralEq { /// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html -/// [`Drop`]: ../../std/ops/trait.Drop.html -/// [`size_of::`]: ../../std/mem/fn.size_of.html -/// [`Clone`]: ../clone/trait.Clone.html -/// [`String`]: ../../std/string/struct.String.html -/// [`i32`]: ../../std/primitive.i32.html +/// [`size_of::`]: crate::mem::size_of /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] @@ -400,18 +396,18 @@ pub macro Copy($item:item) { /// This trait is automatically implemented when the compiler determines /// it's appropriate. /// -/// The precise definition is: a type `T` is `Sync` if and only if `&T` is -/// [`Send`][send]. In other words, if there is no possibility of +/// The precise definition is: a type `T` is [`Sync`] if and only if `&T` is +/// [`Send`]. In other words, if there is no possibility of /// [undefined behavior][ub] (including data races) when passing /// `&T` references between threads. /// -/// As one would expect, primitive types like [`u8`][u8] and [`f64`][f64] -/// are all `Sync`, and so are simple aggregate types containing them, -/// like tuples, structs and enums. More examples of basic `Sync` +/// As one would expect, primitive types like [`u8`] and [`f64`] +/// are all [`Sync`], and so are simple aggregate types containing them, +/// like tuples, structs and enums. More examples of basic [`Sync`] /// types include "immutable" types like `&T`, and those with simple /// inherited mutability, such as [`Box`][box], [`Vec`][vec] and -/// most other collection types. (Generic parameters need to be `Sync` -/// for their container to be `Sync`.) +/// most other collection types. (Generic parameters need to be [`Sync`] +/// for their container to be [`Sync`].) /// /// A somewhat surprising consequence of the definition is that `&mut T` /// is `Sync` (if `T` is `Sync`) even though it seems like that might @@ -421,15 +417,15 @@ pub macro Copy($item:item) { /// of a data race. /// /// Types that are not `Sync` are those that have "interior -/// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell] -/// and [`cell::RefCell`][refcell]. These types allow for mutation of +/// mutability" in a non-thread-safe form, such as [`Cell`][cell] +/// and [`RefCell`][refcell]. These types allow for mutation of /// their contents even through an immutable, shared reference. For /// example the `set` method on [`Cell`][cell] takes `&self`, so it requires /// only a shared reference [`&Cell`][cell]. The method performs no /// synchronization, thus [`Cell`][cell] cannot be `Sync`. /// /// Another example of a non-`Sync` type is the reference-counting -/// pointer [`rc::Rc`][rc]. Given any reference [`&Rc`][rc], you can clone +/// pointer [`Rc`][rc]. Given any reference [`&Rc`][rc], you can clone /// a new [`Rc`][rc], modifying the reference counts in a non-atomic way. /// /// For cases when one does need thread-safe interior mutability, @@ -445,24 +441,21 @@ pub macro Copy($item:item) { /// [undefined behavior][ub]. For example, [`transmute`][transmute]-ing /// from `&T` to `&mut T` is invalid. /// -/// See [the Nomicon](../../nomicon/send-and-sync.html) for more -/// details about `Sync`. +/// See [the Nomicon][nomicon-send-and-sync] for more details about `Sync`. /// -/// [send]: trait.Send.html -/// [u8]: ../../std/primitive.u8.html -/// [f64]: ../../std/primitive.f64.html /// [box]: ../../std/boxed/struct.Box.html /// [vec]: ../../std/vec/struct.Vec.html -/// [cell]: ../cell/struct.Cell.html -/// [refcell]: ../cell/struct.RefCell.html +/// [cell]: crate::cell::Cell +/// [refcell]: crate::cell::RefCell /// [rc]: ../../std/rc/struct.Rc.html /// [arc]: ../../std/sync/struct.Arc.html -/// [atomic data types]: ../sync/atomic/index.html +/// [atomic data types]: crate::sync::atomic /// [mutex]: ../../std/sync/struct.Mutex.html /// [rwlock]: ../../std/sync/struct.RwLock.html -/// [unsafecell]: ../cell/struct.UnsafeCell.html +/// [unsafecell]: crate::cell::UnsafeCell /// [ub]: ../../reference/behavior-considered-undefined.html -/// [transmute]: ../../std/mem/fn.transmute.html +/// [transmute]: crate::mem::transmute +/// [nomicon-send-and-sync]: ../../nomicon/send-and-sync.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "sync_trait")] #[lang = "sync"] @@ -650,9 +643,9 @@ macro_rules! impls { /// } /// /// impl ExternalResource { -/// fn new() -> ExternalResource { +/// fn new() -> Self { /// let size_of_res = mem::size_of::(); -/// ExternalResource { +/// Self { /// resource_handle: foreign_lib::new(size_of_res), /// resource_type: PhantomData, /// } @@ -698,7 +691,7 @@ mod impls { /// guarantees to [`mem::Discriminant`]. It is **undefined behavior** to transmute /// between `DiscriminantKind::Discriminant` and `mem::Discriminant`. /// -/// [`mem::Discriminant`]: https://doc.rust-lang.org/stable/core/mem/struct.Discriminant.html +/// [`mem::Discriminant`]: crate::mem::Discriminant #[unstable( feature = "discriminant_kind", issue = "none", @@ -708,7 +701,7 @@ mod impls { pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. - #[cfg_attr(not(bootstrap), lang = "discriminant_type")] + #[lang = "discriminant_type"] type Discriminant: Clone + Copy + Debug + Eq + PartialEq + Hash + Send + Sync + Unpin; } @@ -728,23 +721,23 @@ unsafe impl Freeze for &mut T {} /// Types that can be safely moved after being pinned. /// -/// Since Rust itself has no notion of immovable types, and considers moves -/// (e.g., through assignment or [`mem::replace`]) to always be safe, -/// this trait cannot prevent types from moving by itself. +/// Rust itself has no notion of immovable types, and considers moves (e.g., +/// through assignment or [`mem::replace`]) to always be safe. /// -/// Instead it is used to prevent moves through the type system, -/// by controlling the behavior of pointers `P` wrapped in the [`Pin

`] wrapper, -/// which "pin" the type in place by not allowing it to be moved out of them. -/// See the [`pin module`] documentation for more information on pinning. +/// The [`Pin`][Pin] type is used instead to prevent moves through the type +/// system. Pointers `P` wrapped in the [`Pin>`][Pin] wrapper can't be +/// moved out of. See the [`pin` module] documentation for more information on +/// pinning. /// -/// Implementing this trait lifts the restrictions of pinning off a type, -/// which then allows it to move out with functions such as [`mem::replace`]. +/// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off +/// the type, which then allows moving `T` out of [`Pin>`][Pin] with +/// functions such as [`mem::replace`]. /// /// `Unpin` has no consequence at all for non-pinned data. In particular, /// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not -/// just when `T: Unpin`). However, you cannot use -/// [`mem::replace`] on data wrapped inside a [`Pin

`] because you cannot get the -/// `&mut T` you need for that, and *that* is what makes this system work. +/// just when `T: Unpin`). However, you cannot use [`mem::replace`] on data +/// wrapped inside a [`Pin>`][Pin] because you cannot get the `&mut T` you +/// need for that, and *that* is what makes this system work. /// /// So this, for example, can only be done on types implementing `Unpin`: /// @@ -764,9 +757,9 @@ unsafe impl Freeze for &mut T {} /// /// This trait is automatically implemented for almost every type. /// -/// [`mem::replace`]: ../../std/mem/fn.replace.html -/// [`Pin

{ /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn new(pointer: P) -> Pin

{ - // Safety: the value pointed to is `Unpin`, and so has no requirements + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn new(pointer: P) -> Pin

{ + // SAFETY: the value pointed to is `Unpin`, and so has no requirements // around pinning. unsafe { Pin::new_unchecked(pointer) } } @@ -483,9 +484,10 @@ impl> Pin

{ /// /// This requires that the data inside this `Pin` is [`Unpin`] so that we /// can ignore the pinning invariants when unwrapping it. - #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] - pub fn into_inner(pin: Pin

) -> P { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] + pub const fn into_inner(pin: Pin

) -> P { pin.pointer } } @@ -541,7 +543,7 @@ impl Pin

{ /// use std::pin::Pin; /// /// fn move_pinned_rc(mut x: Rc) { - /// let pinned = unsafe { Pin::new_unchecked(x.clone()) }; + /// let pinned = unsafe { Pin::new_unchecked(Rc::clone(&x)) }; /// { /// let p: Pin<&T> = pinned.as_ref(); /// // This should mean the pointee can never move again. @@ -555,10 +557,11 @@ impl Pin

{ /// ``` /// /// [`mem::swap`]: crate::mem::swap - #[cfg_attr(not(bootstrap), lang = "new_unchecked")] - #[stable(feature = "pin", since = "1.33.0")] + #[lang = "new_unchecked"] #[inline(always)] - pub unsafe fn new_unchecked(pointer: P) -> Pin

{ + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const unsafe fn new_unchecked(pointer: P) -> Pin

{ Pin { pointer } } @@ -589,9 +592,10 @@ impl Pin

{ /// /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used /// instead. - #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] - pub unsafe fn into_inner_unchecked(pin: Pin

) -> P { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] + pub const unsafe fn into_inner_unchecked(pin: Pin

) -> P { pin.pointer } } @@ -661,7 +665,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. /// - /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning + /// [`pin` module]: self#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] pub unsafe fn map_unchecked(self, func: F) -> Pin<&'a U> where @@ -692,19 +696,21 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. /// - /// ["pinning projections"]: ../../std/pin/index.html#projections-and-structural-pinning - #[stable(feature = "pin", since = "1.33.0")] + /// ["pinning projections"]: self#projections-and-structural-pinning #[inline(always)] - pub fn get_ref(self) -> &'a T { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn get_ref(self) -> &'a T { self.pointer } } impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn into_ref(self) -> Pin<&'a T> { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn into_ref(self) -> Pin<&'a T> { Pin { pointer: self.pointer } } @@ -717,9 +723,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// that lives for as long as the borrow of the `Pin`, not the lifetime of /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_mut(self) -> &'a mut T + #[stable(feature = "pin", since = "1.33.0")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const fn get_mut(self) -> &'a mut T where T: Unpin, { @@ -736,9 +743,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// /// If the underlying data is `Unpin`, `Pin::get_mut` should be used /// instead. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self) -> &'a mut T { + #[stable(feature = "pin", since = "1.33.0")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { self.pointer } @@ -756,7 +764,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. /// - /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning + /// [`pin` module]: self#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] pub unsafe fn map_unchecked_mut(self, func: F) -> Pin<&'a mut U> where diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index fc70dec16f..d09cdb44e0 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -836,7 +836,7 @@ impl *const T { /// # use std::mem::align_of; /// # unsafe { /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; + /// let ptr = x.as_ptr().add(n) as *const u8; /// let offset = ptr.align_offset(align_of::()); /// if offset < x.len() - n - 1 { /// let u16_ptr = ptr.add(offset) as *const u16; diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 68b5d1df71..92c4f2ccfe 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -54,16 +54,9 @@ //! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer //! [ub]: ../../reference/behavior-considered-undefined.html -//! [null]: ./fn.null.html //! [zst]: ../../nomicon/exotic-sizes.html#zero-sized-types-zsts -//! [atomic operations]: ../../std/sync/atomic/index.html -//! [`copy`]: ../../std/ptr/fn.copy.html +//! [atomic operations]: crate::sync::atomic //! [`offset`]: ../../std/primitive.pointer.html#method.offset -//! [`read_unaligned`]: ./fn.read_unaligned.html -//! [`write_unaligned`]: ./fn.write_unaligned.html -//! [`read_volatile`]: ./fn.read_volatile.html -//! [`write_volatile`]: ./fn.write_volatile.html -//! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling #![stable(feature = "rust1", since = "1.0.0")] @@ -118,9 +111,9 @@ mod mut_ptr; /// done automatically by the compiler. This means the fields of packed structs /// are not dropped in-place. /// -/// [`ptr::read`]: ../ptr/fn.read.html -/// [`ptr::read_unaligned`]: ../ptr/fn.read_unaligned.html -/// [pinned]: ../pin/index.html +/// [`ptr::read`]: self::read +/// [`ptr::read_unaligned`]: self::read_unaligned +/// [pinned]: crate::pin /// /// # Safety /// @@ -136,14 +129,12 @@ mod mut_ptr; /// Additionally, if `T` is not [`Copy`], using the pointed-to value after /// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = /// foo` counts as a use because it will cause the value to be dropped -/// again. [`write`] can be used to overwrite data without causing it to be +/// again. [`write()`] can be used to overwrite data without causing it to be /// dropped. /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`write`]: ../ptr/fn.write.html +/// [valid]: self#safety /// /// # Examples /// @@ -243,9 +234,9 @@ pub(crate) struct FatPtr { /// The `len` argument is the number of **elements**, not the number of bytes. /// /// This function is safe, but actually using the return value is unsafe. -/// See the documentation of [`from_raw_parts`] for slice safety requirements. +/// See the documentation of [`slice::from_raw_parts`] for slice safety requirements. /// -/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html +/// [`slice::from_raw_parts`]: crate::slice::from_raw_parts /// /// # Examples /// @@ -274,10 +265,9 @@ pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { /// See the documentation of [`slice_from_raw_parts`] for more details. /// /// This function is safe, but actually using the return value is unsafe. -/// See the documentation of [`from_raw_parts_mut`] for slice safety requirements. +/// See the documentation of [`slice::from_raw_parts_mut`] for slice safety requirements. /// -/// [`slice_from_raw_parts`]: fn.slice_from_raw_parts.html -/// [`from_raw_parts_mut`]: ../../std/slice/fn.from_raw_parts_mut.html +/// [`slice::from_raw_parts_mut`]: crate::slice::from_raw_parts_mut /// /// # Examples /// @@ -316,8 +306,6 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// overlapping region of memory from `x` will be used. This is demonstrated /// in the second example below. /// -/// [`mem::swap`]: ../mem/fn.swap.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -328,7 +316,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// /// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// # Examples /// @@ -406,7 +394,7 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// Note that even if the effectively copied size (`count * size_of::()`) is `0`, /// the pointers must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// # Examples /// @@ -533,8 +521,6 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// operates on raw pointers instead of references. When references are /// available, [`mem::replace`] should be preferred. /// -/// [`mem::replace`]: ../mem/fn.replace.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -547,7 +533,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// # Examples /// @@ -653,7 +639,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// `*src` can violate memory safety. Note that assigning to `*src` counts as a /// use because it will attempt to drop the value at `*src`. /// -/// [`write`] can be used to overwrite data without causing it to be dropped. +/// [`write()`] can be used to overwrite data without causing it to be dropped. /// /// ``` /// use std::ptr; @@ -682,11 +668,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// assert_eq!(s, "bar"); /// ``` /// -/// [`mem::swap`]: ../mem/fn.swap.html -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// [`write`]: ./fn.write.html +/// [valid]: self#safety #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { @@ -723,11 +705,8 @@ pub unsafe fn read(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL. /// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ./fn.read.html -/// [`write_unaligned`]: ./fn.write_unaligned.html -/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value -/// [valid]: ../ptr/index.html#safety +/// [read-ownership]: read#ownership-of-the-returned-value +/// [valid]: self#safety /// /// ## On `packed` structs /// @@ -819,8 +798,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been [`read`] from. /// -/// [`read`]: ./fn.read.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -832,8 +809,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety -/// [`write_unaligned`]: ./fn.write_unaligned.html +/// [valid]: self#safety /// /// # Examples /// @@ -888,8 +864,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// assert_eq!(foo, "bar"); /// assert_eq!(bar, "foo"); /// ``` -/// -/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { @@ -904,7 +878,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// Unlike [`write`], the pointer may be unaligned. +/// Unlike [`write()`], the pointer may be unaligned. /// /// `write_unaligned` does not drop the contents of `dst`. This is safe, but it /// could leak allocations or resources, so care should be taken not to overwrite @@ -916,9 +890,6 @@ pub unsafe fn write(dst: *mut T, src: T) { /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been read with [`read_unaligned`]. /// -/// [`write`]: ./fn.write.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -927,7 +898,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// ## On `packed` structs /// @@ -1007,8 +978,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// to not be elided or reordered by the compiler across other volatile /// operations. /// -/// [`write_volatile`]: ./fn.write_volatile.html -/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -1041,10 +1010,8 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ./fn.read.html -/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value +/// [valid]: self#safety +/// [read-ownership]: read#ownership-of-the-returned-value /// /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile @@ -1089,8 +1056,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// -/// [`read_volatile`]: ./fn.read_volatile.html -/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -1115,7 +1080,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 2d25f21e55..537aa20bf1 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1094,7 +1094,7 @@ impl *mut T { /// # use std::mem::align_of; /// # unsafe { /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; + /// let ptr = x.as_ptr().add(n) as *const u8; /// let offset = ptr.align_offset(align_of::()); /// if offset < x.len() - n - 1 { /// let u16_ptr = ptr.add(offset) as *const u16; diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 294a3173d0..5dc7171a7d 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -34,8 +34,8 @@ use crate::slice::{self, SliceIndex}; /// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr` /// is never used for mutation. /// -/// [`PhantomData`]: ../marker/struct.PhantomData.html -/// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html +/// [`PhantomData`]: crate::marker::PhantomData +/// [`UnsafeCell`]: crate::cell::UnsafeCell #[stable(feature = "nonnull", since = "1.25.0")] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] @@ -82,8 +82,8 @@ impl NonNull { /// /// For the mutable counterpart see [`as_uninit_mut`]. /// - /// [`as_ref`]: #method.as_ref - /// [`as_uninit_mut`]: #method.as_uninit_mut + /// [`as_ref`]: NonNull::as_ref + /// [`as_uninit_mut`]: NonNull::as_uninit_mut /// /// # Safety /// @@ -114,8 +114,8 @@ impl NonNull { /// /// For the shared counterpart see [`as_uninit_ref`]. /// - /// [`as_mut`]: #method.as_mut - /// [`as_uninit_ref`]: #method.as_uninit_ref + /// [`as_mut`]: NonNull::as_mut + /// [`as_uninit_ref`]: NonNull::as_uninit_ref /// /// # Safety /// @@ -181,8 +181,8 @@ impl NonNull { /// /// For the mutable counterpart see [`as_mut`]. /// - /// [`as_uninit_ref`]: #method.as_uninit_ref - /// [`as_mut`]: #method.as_mut + /// [`as_uninit_ref`]: NonNull::as_uninit_ref + /// [`as_mut`]: NonNull::as_mut /// /// # Safety /// @@ -217,8 +217,8 @@ impl NonNull { /// /// For the shared counterpart see [`as_ref`]. /// - /// [`as_uninit_mut`]: #method.as_uninit_mut - /// [`as_ref`]: #method.as_ref + /// [`as_uninit_mut`]: NonNull::as_uninit_mut + /// [`as_ref`]: NonNull::as_ref /// /// # Safety /// @@ -266,8 +266,6 @@ impl NonNull<[T]> { /// This function is safe, but dereferencing the return value is unsafe. /// See the documentation of [`slice::from_raw_parts`] for slice safety requirements. /// - /// [`slice::from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html - /// /// # Examples /// /// ```rust @@ -357,8 +355,8 @@ impl NonNull<[T]> { /// /// For the mutable counterpart see [`as_uninit_slice_mut`]. /// - /// [`as_ref`]: #method.as_ref - /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut + /// [`as_ref`]: NonNull::as_ref + /// [`as_uninit_slice_mut`]: NonNull::as_uninit_slice_mut /// /// # Safety /// @@ -386,10 +384,9 @@ impl NonNull<[T]> { /// /// This applies even if the result of this method is unused! /// - /// See also [`slice::from_raw_parts`][]. + /// See also [`slice::from_raw_parts`]. /// /// [valid]: crate::ptr#safety - /// [`NonNull::dangling()`]: NonNull::dangling /// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] @@ -403,8 +400,8 @@ impl NonNull<[T]> { /// /// For the shared counterpart see [`as_uninit_slice`]. /// - /// [`as_mut`]: #method.as_mut - /// [`as_uninit_slice`]: #method.as_uninit_slice + /// [`as_mut`]: NonNull::as_mut + /// [`as_uninit_slice`]: NonNull::as_uninit_slice /// /// # Safety /// @@ -432,10 +429,9 @@ impl NonNull<[T]> { /// /// This applies even if the result of this method is unused! /// - /// See also [`slice::from_raw_parts_mut`][]. + /// See also [`slice::from_raw_parts_mut`]. /// /// [valid]: crate::ptr#safety - /// [`NonNull::dangling()`]: NonNull::dangling /// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset /// /// # Examples @@ -452,7 +448,7 @@ impl NonNull<[T]> { /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized. /// # #[allow(unused_variables)] /// let slice: &mut [MaybeUninit] = unsafe { memory.as_uninit_slice_mut() }; - /// # Ok::<_, std::alloc::AllocErr>(()) + /// # Ok::<_, std::alloc::AllocError>(()) /// ``` #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index 78647eee33..cd6afdccc2 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -4,8 +4,6 @@ use crate::marker::{PhantomData, Unsize}; use crate::mem; use crate::ops::{CoerceUnsized, DispatchFromDyn}; -// ignore-tidy-undocumented-unsafe - /// A wrapper around a raw non-null `*mut T` that indicates that the possessor /// of this wrapper owns the referent. Useful for building abstractions like /// `Box`, `Vec`, `String`, and `HashMap`. diff --git a/library/core/src/result.rs b/library/core/src/result.rs index ade5472717..5cec183c23 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -240,12 +240,12 @@ use crate::{convert, fmt}; #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { /// Contains the success value - #[cfg_attr(not(bootstrap), lang = "Ok")] + #[lang = "Ok"] #[stable(feature = "rust1", since = "1.0.0")] Ok(#[stable(feature = "rust1", since = "1.0.0")] T), /// Contains the error value - #[cfg_attr(not(bootstrap), lang = "Err")] + #[lang = "Err"] #[stable(feature = "rust1", since = "1.0.0")] Err(#[stable(feature = "rust1", since = "1.0.0")] E), } @@ -273,7 +273,7 @@ impl Result { /// assert_eq!(x.is_ok(), false); /// ``` #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"] - #[rustc_const_unstable(feature = "const_result", issue = "67520")] + #[rustc_const_stable(feature = "const_result", since = "1.48.0")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_ok(&self) -> bool { @@ -294,7 +294,7 @@ impl Result { /// assert_eq!(x.is_err(), true); /// ``` #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"] - #[rustc_const_unstable(feature = "const_result", issue = "67520")] + #[rustc_const_stable(feature = "const_result", since = "1.48.0")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_err(&self) -> bool { @@ -438,7 +438,7 @@ impl Result { /// assert_eq!(x.as_ref(), Err(&"Error")); /// ``` #[inline] - #[rustc_const_unstable(feature = "const_result", issue = "67520")] + #[rustc_const_stable(feature = "const_result", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn as_ref(&self) -> Result<&T, &E> { match *self { diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs new file mode 100644 index 0000000000..42032bc903 --- /dev/null +++ b/library/core/src/slice/ascii.rs @@ -0,0 +1,156 @@ +//! Operations on ASCII `[u8]`. + +use crate::mem; + +#[lang = "slice_u8"] +#[cfg(not(test))] +impl [u8] { + /// Checks if all bytes in this slice are within the ASCII range. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + is_ascii(self) + } + + /// Checks that two slices are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { + self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b)) + } + + /// Converts this slice to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + for byte in self { + byte.make_ascii_uppercase(); + } + } + + /// Converts this slice to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + for byte in self { + byte.make_ascii_lowercase(); + } + } +} + +/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed +/// from `../str/mod.rs`, which does something similar for utf8 validation. +#[inline] +fn contains_nonascii(v: usize) -> bool { + const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; + (NONASCII_MASK & v) != 0 +} + +/// Optimized ASCII test that will use usize-at-a-time operations instead of +/// byte-at-a-time operations (when possible). +/// +/// The algorithm we use here is pretty simple. If `s` is too short, we just +/// check each byte and be done with it. Otherwise: +/// +/// - Read the first word with an unaligned load. +/// - Align the pointer, read subsequent words until end with aligned loads. +/// - Read the last `usize` from `s` with an unaligned load. +/// +/// If any of these loads produces something for which `contains_nonascii` +/// (above) returns true, then we know the answer is false. +#[inline] +fn is_ascii(s: &[u8]) -> bool { + const USIZE_SIZE: usize = mem::size_of::(); + + let len = s.len(); + let align_offset = s.as_ptr().align_offset(USIZE_SIZE); + + // If we wouldn't gain anything from the word-at-a-time implementation, fall + // back to a scalar loop. + // + // We also do this for architectures where `size_of::()` isn't + // sufficient alignment for `usize`, because it's a weird edge case. + if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { + return s.iter().all(|b| b.is_ascii()); + } + + // We always read the first word unaligned, which means `align_offset` is + // 0, we'd read the same value again for the aligned read. + let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; + + let start = s.as_ptr(); + // SAFETY: We verify `len < USIZE_SIZE` above. + let first_word = unsafe { (start as *const usize).read_unaligned() }; + + if contains_nonascii(first_word) { + return false; + } + // We checked this above, somewhat implicitly. Note that `offset_to_aligned` + // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked + // above. + debug_assert!(offset_to_aligned <= len); + + // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the + // middle chunk of the slice. + let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; + + // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. + let mut byte_pos = offset_to_aligned; + + // Paranoia check about alignment, since we're about to do a bunch of + // unaligned loads. In practice this should be impossible barring a bug in + // `align_offset` though. + debug_assert_eq!((word_ptr as usize) % mem::align_of::(), 0); + + // Read subsequent words until the last aligned word, excluding the last + // aligned word by itself to be done in tail check later, to ensure that + // tail is always one `usize` at most to extra branch `byte_pos == len`. + while byte_pos < len - USIZE_SIZE { + debug_assert!( + // Sanity check that the read is in bounds + (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) && + // And that our assumptions about `byte_pos` hold. + (word_ptr as usize) - (start as usize) == byte_pos + ); + + // SAFETY: We know `word_ptr` is properly aligned (because of + // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end + let word = unsafe { word_ptr.read() }; + if contains_nonascii(word) { + return false; + } + + byte_pos += USIZE_SIZE; + // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that + // after this `add`, `word_ptr` will be at most one-past-the-end. + word_ptr = unsafe { word_ptr.add(1) }; + } + + // Sanity check to ensure there really is only one `usize` left. This should + // be guaranteed by our loop condition. + debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); + + // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. + let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; + + !contains_nonascii(last_word) +} diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs new file mode 100644 index 0000000000..ed26c59c17 --- /dev/null +++ b/library/core/src/slice/cmp.rs @@ -0,0 +1,288 @@ +//! Comparison traits for `[T]`. + +use crate::cmp; +use crate::cmp::Ordering::{self, Greater, Less}; +use crate::mem; + +use super::from_raw_parts; +use super::memchr; + +extern "C" { + /// Calls implementation provided memcmp. + /// + /// Interprets the data as u8. + /// + /// Returns 0 for equal, < 0 for less than and > 0 for greater + /// than. + // FIXME(#32610): Return type should be c_int + fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq<[B]> for [A] +where + A: PartialEq, +{ + fn eq(&self, other: &[B]) -> bool { + SlicePartialEq::equal(self, other) + } + + fn ne(&self, other: &[B]) -> bool { + SlicePartialEq::not_equal(self, other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for [T] {} + +/// Implements comparison of vectors lexicographically. +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for [T] { + fn cmp(&self, other: &[T]) -> Ordering { + SliceOrd::compare(self, other) + } +} + +/// Implements comparison of vectors lexicographically. +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for [T] { + fn partial_cmp(&self, other: &[T]) -> Option { + SlicePartialOrd::partial_compare(self, other) + } +} + +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialEq +trait SlicePartialEq { + fn equal(&self, other: &[B]) -> bool; + + fn not_equal(&self, other: &[B]) -> bool { + !self.equal(other) + } +} + +// Generic slice equality +impl SlicePartialEq for [A] +where + A: PartialEq, +{ + default fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().zip(other.iter()).all(|(x, y)| x == y) + } +} + +// Use an equal-pointer optimization when types are `Eq` +// We can't make `A` and `B` the same type because `min_specialization` won't +// allow it. +impl SlicePartialEq for [A] +where + A: MarkerEq, +{ + default fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { + return true; + } + + self.iter().zip(other.iter()).all(|(x, y)| x == y) + } +} + +// Use memcmp for bytewise equality when the types allow +impl SlicePartialEq for [A] +where + A: BytewiseEquality, +{ + fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { + return true; + } + // SAFETY: `self` and `other` are references and are thus guaranteed to be valid. + // The two slices have been checked to have the same size above. + unsafe { + let size = mem::size_of_val(self); + memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 + } + } +} + +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialOrd +trait SlicePartialOrd: Sized { + fn partial_compare(left: &[Self], right: &[Self]) -> Option; +} + +impl SlicePartialOrd for A { + default fn partial_compare(left: &[A], right: &[A]) -> Option { + let l = cmp::min(left.len(), right.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &left[..l]; + let rhs = &right[..l]; + + for i in 0..l { + match lhs[i].partial_cmp(&rhs[i]) { + Some(Ordering::Equal) => (), + non_eq => return non_eq, + } + } + + left.len().partial_cmp(&right.len()) + } +} + +// This is the impl that we would like to have. Unfortunately it's not sound. +// See `partial_ord_slice.rs`. +/* +impl SlicePartialOrd for A +where + A: Ord, +{ + default fn partial_compare(left: &[A], right: &[A]) -> Option { + Some(SliceOrd::compare(left, right)) + } +} +*/ + +impl SlicePartialOrd for A { + fn partial_compare(left: &[A], right: &[A]) -> Option { + Some(SliceOrd::compare(left, right)) + } +} + +#[rustc_specialization_trait] +trait AlwaysApplicableOrd: SliceOrd + Ord {} + +macro_rules! always_applicable_ord { + ($([$($p:tt)*] $t:ty,)*) => { + $(impl<$($p)*> AlwaysApplicableOrd for $t {})* + } +} + +always_applicable_ord! { + [] u8, [] u16, [] u32, [] u64, [] u128, [] usize, + [] i8, [] i16, [] i32, [] i64, [] i128, [] isize, + [] bool, [] char, + [T: ?Sized] *const T, [T: ?Sized] *mut T, + [T: AlwaysApplicableOrd] &T, + [T: AlwaysApplicableOrd] &mut T, + [T: AlwaysApplicableOrd] Option, +} + +#[doc(hidden)] +// intermediate trait for specialization of slice's Ord +trait SliceOrd: Sized { + fn compare(left: &[Self], right: &[Self]) -> Ordering; +} + +impl SliceOrd for A { + default fn compare(left: &[Self], right: &[Self]) -> Ordering { + let l = cmp::min(left.len(), right.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &left[..l]; + let rhs = &right[..l]; + + for i in 0..l { + match lhs[i].cmp(&rhs[i]) { + Ordering::Equal => (), + non_eq => return non_eq, + } + } + + left.len().cmp(&right.len()) + } +} + +// memcmp compares a sequence of unsigned bytes lexicographically. +// this matches the order we want for [u8], but no others (not even [i8]). +impl SliceOrd for u8 { + #[inline] + fn compare(left: &[Self], right: &[Self]) -> Ordering { + let order = + // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. + // We use the minimum of both lengths which guarantees that both regions are + // valid for reads in that interval. + unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) }; + if order == 0 { + left.len().cmp(&right.len()) + } else if order < 0 { + Less + } else { + Greater + } + } +} + +// Hack to allow specializing on `Eq` even though `Eq` has a method. +#[rustc_unsafe_specialization_marker] +trait MarkerEq: PartialEq {} + +impl MarkerEq for T {} + +#[doc(hidden)] +/// Trait implemented for types that can be compared for equality using +/// their bytewise representation +#[rustc_specialization_trait] +trait BytewiseEquality: MarkerEq + Copy {} + +macro_rules! impl_marker_for { + ($traitname:ident, $($ty:ty)*) => { + $( + impl $traitname<$ty> for $ty { } + )* + } +} + +impl_marker_for!(BytewiseEquality, + u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); + +pub(super) trait SliceContains: Sized { + fn slice_contains(&self, x: &[Self]) -> bool; +} + +impl SliceContains for T +where + T: PartialEq, +{ + default fn slice_contains(&self, x: &[Self]) -> bool { + x.iter().any(|y| *y == *self) + } +} + +impl SliceContains for u8 { + #[inline] + fn slice_contains(&self, x: &[Self]) -> bool { + memchr::memchr(*self, x).is_some() + } +} + +impl SliceContains for i8 { + #[inline] + fn slice_contains(&self, x: &[Self]) -> bool { + let byte = *self as u8; + // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()` + // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed + // to be valid for reads for the length of the slice `x.len()`, which cannot be larger + // than `isize::MAX`. The returned slice is never mutated. + let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) }; + memchr::memchr(byte, bytes).is_some() + } +} diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs new file mode 100644 index 0000000000..16fcb6231d --- /dev/null +++ b/library/core/src/slice/index.rs @@ -0,0 +1,528 @@ +//! Indexing implementations for `[T]`. + +use crate::ops::{self, Bound, Range, RangeBounds}; +use crate::ptr; + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::IndexMut for [T] +where + I: SliceIndex<[T]>, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut I::Output { + index.index_mut(self) + } +} + +#[inline(never)] +#[cold] +#[track_caller] +fn slice_start_index_len_fail(index: usize, len: usize) -> ! { + panic!("range start index {} out of range for slice of length {}", index, len); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { + panic!("range end index {} out of range for slice of length {}", index, len); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_index_order_fail(index: usize, end: usize) -> ! { + panic!("slice index starts at {} but ends at {}", index, end); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_start_index_overflow_fail() -> ! { + panic!("attempted to index slice from after maximum usize"); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_end_index_overflow_fail() -> ! { + panic!("attempted to index slice up to maximum usize"); +} + +/// Performs bounds-checking of the given range. +/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`] +/// for slices of the given length. +/// +/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked +/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut +/// +/// # Panics +/// +/// Panics if the range is out of bounds. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_check_range)] +/// use std::slice; +/// +/// let v = [10, 40, 30]; +/// assert_eq!(1..2, slice::check_range(v.len(), 1..2)); +/// assert_eq!(0..2, slice::check_range(v.len(), ..2)); +/// assert_eq!(1..3, slice::check_range(v.len(), 1..)); +/// ``` +/// +/// Panics when [`Index::index`] would panic: +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 2..1); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 1..4); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 1..=usize::MAX); +/// ``` +/// +/// [`Index::index`]: ops::Index::index +#[track_caller] +#[unstable(feature = "slice_check_range", issue = "76393")] +pub fn check_range>(len: usize, range: R) -> Range { + let start = match range.start_bound() { + Bound::Included(&start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end = match range.end_bound() { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(&end) => end, + Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + Range { start, end } +} + +mod private_slice_index { + use super::ops; + #[stable(feature = "slice_get_slice", since = "1.28.0")] + pub trait Sealed {} + + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for usize {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::Range {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeTo {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFrom {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFull {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeInclusive {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeToInclusive {} +} + +/// A helper trait used for indexing operations. +/// +/// Implementations of this trait have to promise that if the argument +/// to `get_(mut_)unchecked` is a safe reference, then so is the result. +#[stable(feature = "slice_get_slice", since = "1.28.0")] +#[rustc_on_unimplemented( + on(T = "str", label = "string indices are ranges of `usize`",), + on( + all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"), + note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ + for more information, see chapter 8 in The Book: \ + " + ), + message = "the type `{T}` cannot be indexed by `{Self}`", + label = "slice indices are of type `usize` or ranges of `usize`" +)] +pub unsafe trait SliceIndex: private_slice_index::Sealed { + /// The output type returned by methods. + #[stable(feature = "slice_get_slice", since = "1.28.0")] + type Output: ?Sized; + + /// Returns a shared reference to the output at this location, if in + /// bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + fn get(self, slice: &T) -> Option<&Self::Output>; + + /// Returns a mutable reference to the output at this location, if in + /// bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; + + /// Returns a shared reference to the output at this location, without + /// performing any bounds checking. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_index_methods", issue = "none")] + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + /// Returns a mutable reference to the output at this location, without + /// performing any bounds checking. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_index_methods", issue = "none")] + unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; + + /// Returns a shared reference to the output at this location, panicking + /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + #[track_caller] + fn index(self, slice: &T) -> &Self::Output; + + /// Returns a mutable reference to the output at this location, panicking + /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + #[track_caller] + fn index_mut(self, slice: &mut T) -> &mut Self::Output; +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for usize { + type Output = T; + + #[inline] + fn get(self, slice: &[T]) -> Option<&T> { + // SAFETY: `self` is checked to be in bounds. + if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { + // SAFETY: `self` is checked to be in bounds. + if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + // 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 { slice.as_ptr().add(self) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { + // SAFETY: see comments for `get_unchecked` above. + unsafe { slice.as_mut_ptr().add(self) } + } + + #[inline] + fn index(self, slice: &[T]) -> &T { + // N.B., use intrinsic indexing + &(*slice)[self] + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut T { + // N.B., use intrinsic indexing + &mut (*slice)[self] + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::Range { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + if self.start > self.end || self.end > slice.len() { + None + } else { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { Some(&*self.get_unchecked(slice)) } + } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + if self.start > self.end || self.end > slice.len() { + None + } else { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { Some(&mut *self.get_unchecked_mut(slice)) } + } + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // 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 { 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] { + // SAFETY: see comments for `get_unchecked` above. + unsafe { + ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) + } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if self.start > self.end { + slice_index_order_fail(self.start, self.end); + } else if self.end > slice.len() { + slice_end_index_len_fail(self.end, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &*self.get_unchecked(slice) } + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if self.start > self.end { + slice_index_order_fail(self.start, self.end); + } else if self.end > slice.len() { + slice_end_index_len_fail(self.end, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &mut *self.get_unchecked_mut(slice) } + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::RangeTo { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (0..self.end).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0..self.end).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (0..self.end).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..self.end).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..self.end).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0..self.end).index_mut(slice) + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::RangeFrom { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (self.start..slice.len()).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (self.start..slice.len()).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (self.start..slice.len()).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if self.start > slice.len() { + slice_start_index_len_fail(self.start, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &*self.get_unchecked(slice) } + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if self.start > slice.len() { + slice_start_index_len_fail(self.start, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &mut *self.get_unchecked_mut(slice) } + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::RangeFull { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + Some(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + Some(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + slice + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + slice + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + slice + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + slice + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex<[T]> for ops::RangeInclusive { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + if *self.end() == usize::MAX { + None + } else { + (*self.start()..self.end() + 1).get_mut(slice) + } + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if *self.end() == usize::MAX { + slice_end_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if *self.end() == usize::MAX { + slice_end_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index_mut(slice) + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (0..=self.end).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0..=self.end).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (0..=self.end).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..=self.end).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..=self.end).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0..=self.end).index_mut(slice) + } +} diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs new file mode 100644 index 0000000000..793cbf9949 --- /dev/null +++ b/library/core/src/slice/iter.rs @@ -0,0 +1,2979 @@ +//! Definitions of a bunch of iterators for `[T]`. + +#[macro_use] // import iterator! and forward_iterator! +mod macros; + +use crate::cmp; +use crate::cmp::Ordering; +use crate::fmt; +use crate::intrinsics::{assume, exact_div, unchecked_sub}; +use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; +use crate::marker::{PhantomData, Send, Sized, Sync}; +use crate::mem; +use crate::ptr::NonNull; + +use super::{from_raw_parts, from_raw_parts_mut}; + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a [T] { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a mut [T] { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +// Macro helper functions +#[inline(always)] +fn size_from_ptr(_: *const T) -> usize { + mem::size_of::() +} + +/// Immutable slice iterator +/// +/// This struct is created by the [`iter`] method on [slices]. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]): +/// let slice = &[1, 2, 3]; +/// +/// // Then, we iterate over it: +/// for element in slice.iter() { +/// println!("{}", element); +/// } +/// ``` +/// +/// [`iter`]: ../../std/primitive.slice.html#method.iter +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + ptr: NonNull, + end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that + // ptr == end is a quick test for the Iterator being empty, that works + // for both ZST and non-ZST. + _marker: PhantomData<&'a T>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Iter").field(&self.as_slice()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for Iter<'_, T> {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for Iter<'_, T> {} + +impl<'a, T> Iter<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T]) -> Self { + let ptr = slice.as_ptr(); + // SAFETY: Similar to `IterMut::new`. + unsafe { + assume(!ptr.is_null()); + + let end = if mem::size_of::() == 0 { + (ptr as *const u8).wrapping_add(slice.len()) as *const T + } else { + ptr.add(slice.len()) + }; + + Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData } + } + } + + /// Views the underlying data as a subslice of the original data. + /// + /// This has the same lifetime as the original slice, and so the + /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // First, we declare a type which has the `iter` method to get the `Iter` + /// // struct (&[usize here]): + /// let slice = &[1, 2, 3]; + /// + /// // Then, we get the iterator: + /// let mut iter = slice.iter(); + /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]": + /// println!("{:?}", iter.as_slice()); + /// + /// // Next, we move to the second element of the slice: + /// iter.next(); + /// // Now `as_slice` returns "[2, 3]": + /// println!("{:?}", iter.as_slice()); + /// ``` + #[stable(feature = "iter_to_slice", since = "1.4.0")] + pub fn as_slice(&self) -> &'a [T] { + self.make_slice() + } +} + +iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, { + fn is_sorted_by(self, mut compare: F) -> bool + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Option, + { + self.as_slice().windows(2).all(|w| { + compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false) + }) + } +}} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { + Iter { ptr: self.ptr, end: self.end, _marker: self._marker } + } +} + +#[stable(feature = "slice_iter_as_ref", since = "1.13.0")] +impl AsRef<[T]> for Iter<'_, T> { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +/// Mutable slice iterator. +/// +/// This struct is created by the [`iter_mut`] method on [slices]. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // First, we declare a type which has `iter_mut` method to get the `IterMut` +/// // struct (&[usize here]): +/// let mut slice = &mut [1, 2, 3]; +/// +/// // Then, we iterate over it and increment each element value: +/// for element in slice.iter_mut() { +/// *element += 1; +/// } +/// +/// // We now have "[2, 3, 4]": +/// println!("{:?}", slice); +/// ``` +/// +/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IterMut<'a, T: 'a> { + ptr: NonNull, + end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that + // ptr == end is a quick test for the Iterator being empty, that works + // for both ZST and non-ZST. + _marker: PhantomData<&'a mut T>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for IterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IterMut").field(&self.make_slice()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for IterMut<'_, T> {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for IterMut<'_, T> {} + +impl<'a, T> IterMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T]) -> Self { + let ptr = slice.as_mut_ptr(); + // SAFETY: There are several things here: + // + // `ptr` has been obtained by `slice.as_ptr()` where `slice` is a valid + // reference thus it is non-NUL and safe to use and pass to + // `NonNull::new_unchecked` . + // + // Adding `slice.len()` to the starting pointer gives a pointer + // at the end of `slice`. `end` will never be dereferenced, only checked + // for direct pointer equality with `ptr` to check if the iterator is + // done. + // + // In the case of a ZST, the end pointer is just the start pointer plus + // the length, to also allows for the fast `ptr == end` check. + // + // See the `next_unchecked!` and `is_empty!` macros as well as the + // `post_inc_start` method for more informations. + unsafe { + assume(!ptr.is_null()); + + let end = if mem::size_of::() == 0 { + (ptr as *mut u8).wrapping_add(slice.len()) as *mut T + } else { + ptr.add(slice.len()) + }; + + Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData } + } + } + + /// Views the underlying data as a subslice of the original data. + /// + /// To avoid creating `&mut` references that alias, this is forced + /// to consume the iterator. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // First, we declare a type which has `iter_mut` method to get the `IterMut` + /// // struct (&[usize here]): + /// let mut slice = &mut [1, 2, 3]; + /// + /// { + /// // Then, we get the iterator: + /// let mut iter = slice.iter_mut(); + /// // We move to next element: + /// iter.next(); + /// // So if we print what `into_slice` method returns here, we have "[2, 3]": + /// println!("{:?}", iter.into_slice()); + /// } + /// + /// // Now let's modify a value of the slice: + /// { + /// // First we get back the iterator: + /// let mut iter = slice.iter_mut(); + /// // We change the value of the first element of the slice returned by the `next` method: + /// *iter.next().unwrap() += 1; + /// } + /// // Now slice is "[2, 2, 3]": + /// println!("{:?}", slice); + /// ``` + #[stable(feature = "iter_to_slice", since = "1.4.0")] + pub fn into_slice(self) -> &'a mut [T] { + // SAFETY: the iterator was created from a mutable slice with pointer + // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites + // for `from_raw_parts_mut` are fulfilled. + unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) } + } + + /// Views the underlying data as a subslice of the original data. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slice + /// borrows its lifetime from the iterator the method is applied on. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(slice_iter_mut_as_slice)] + /// let mut slice: &mut [usize] = &mut [1, 2, 3]; + /// + /// // First, we get the iterator: + /// let mut iter = slice.iter_mut(); + /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]": + /// assert_eq!(iter.as_slice(), &[1, 2, 3]); + /// + /// // Next, we move to the second element of the slice: + /// iter.next(); + /// // Now `as_slice` returns "[2, 3]": + /// assert_eq!(iter.as_slice(), &[2, 3]); + /// ``` + #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")] + pub fn as_slice(&self) -> &[T] { + self.make_slice() + } +} + +iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} + +/// An internal abstraction over the splitting iterators, so that +/// splitn, splitn_mut etc can be implemented once. +#[doc(hidden)] +pub(super) trait SplitIter: DoubleEndedIterator { + /// Marks the underlying iterator as complete, extracting the remaining + /// portion of the slice. + fn finish(&mut self) -> Option; +} + +/// An iterator over subslices separated by elements that match a predicate +/// function. +/// +/// This struct is created by the [`split`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 33, 20]; +/// let mut iter = slice.split(|num| num % 3 == 0); +/// ``` +/// +/// [`split`]: ../../std/primitive.slice.html#method.split +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Split<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Split<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Split<'_, T, P> +where + P: Clone + FnMut(&T) -> bool, +{ + fn clone(&self) -> Self { + Split { v: self.v, pred: self.pred.clone(), finished: self.finished } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> Iterator for Split<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + match self.v.iter().position(|x| (self.pred)(x)) { + None => self.finish(), + Some(idx) => { + let ret = Some(&self.v[..idx]); + self.v = &self.v[idx + 1..]; + ret + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + match self.v.iter().rposition(|x| (self.pred)(x)) { + None => self.finish(), + Some(idx) => { + let ret = Some(&self.v[idx + 1..]); + self.v = &self.v[..idx]; + ret + } + } + } +} + +impl<'a, T, P> SplitIter for Split<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + if self.finished { + None + } else { + self.finished = true; + Some(self.v) + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over subslices separated by elements that match a predicate +/// function. Unlike `Split`, it contains the matched part as a terminator +/// of the subslice. +/// +/// This struct is created by the [`split_inclusive`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(split_inclusive)] +/// +/// let slice = [10, 40, 33, 20]; +/// let mut iter = slice.split_inclusive(|num| num % 3 == 0); +/// ``` +/// +/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "split_inclusive", issue = "72360")] +pub struct SplitInclusive<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl fmt::Debug for SplitInclusive<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInclusive") + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "split_inclusive", issue = "72360")] +impl Clone for SplitInclusive<'_, T, P> +where + P: Clone + FnMut(&T) -> bool, +{ + fn clone(&self) -> Self { + SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + let idx = + self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len()); + if idx == self.v.len() { + self.finished = true; + } + let ret = Some(&self.v[..idx]); + self.v = &self.v[idx..]; + ret + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + // The last index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the left. + let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] }; + let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0); + if idx == 0 { + self.finished = true; + } + let ret = Some(&self.v[idx..]); + self.v = &self.v[..idx]; + ret + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the mutable subslices of the vector which are separated +/// by elements that match `pred`. +/// +/// This struct is created by the [`split_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut v = [10, 40, 30, 20, 60, 50]; +/// let iter = v.split_mut(|num| *num % 3 == 0); +/// ``` +/// +/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SplitMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a mut [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitMut<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SplitMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish() + } +} + +impl<'a, T, P> SplitIter for SplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + if self.finished { + None + } else { + self.finished = true; + Some(mem::replace(&mut self.v, &mut [])) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> Iterator for SplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v.iter().position(|x| (*pred)(x)) + }; + match idx_opt { + None => self.finish(), + Some(idx) => { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = &mut tail[1..]; + Some(head) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // if the predicate doesn't match anything, we yield one slice + // if it matches every element, we yield len+1 empty slices. + (1, Some(self.v.len() + 1)) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v.iter().rposition(|x| (*pred)(x)) + }; + match idx_opt { + None => self.finish(), + Some(idx) => { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = head; + Some(&mut tail[1..]) + } + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the mutable subslices of the vector which are separated +/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched +/// parts in the ends of the subslices. +/// +/// This struct is created by the [`split_inclusive_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(split_inclusive)] +/// +/// let mut v = [10, 40, 30, 20, 60, 50]; +/// let iter = v.split_inclusive_mut(|num| *num % 3 == 0); +/// ``` +/// +/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "split_inclusive", issue = "72360")] +pub struct SplitInclusiveMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a mut [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl fmt::Debug for SplitInclusiveMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInclusiveMut") + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v.iter().position(|x| (*pred)(x)) + }; + let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len()); + if idx == self.v.len() { + self.finished = true; + } + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = tail; + Some(head) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // if the predicate doesn't match anything, we yield one slice + // if it matches every element, we yield len+1 empty slices. + (1, Some(self.v.len() + 1)) + } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = if self.v.is_empty() { + None + } else { + // work around borrowck limitations + let pred = &mut self.pred; + + // The last index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the left. + let remainder = &self.v[..(self.v.len() - 1)]; + remainder.iter().rposition(|x| (*pred)(x)) + }; + let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0); + if idx == 0 { + self.finished = true; + } + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = head; + Some(tail) + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over subslices separated by elements that match a predicate +/// function, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = [11, 22, 33, 0, 44, 55]; +/// let iter = slice.rsplit(|num| *num == 0); +/// ``` +/// +/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "slice_rsplit", since = "1.27.0")] +#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? +pub struct RSplit<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: Split<'a, T, P>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplit<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { inner: Split::new(slice, pred) } + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl fmt::Debug for RSplit<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplit") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> Iterator for RSplit<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + self.inner.next() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> SplitIter for RSplit<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + self.inner.finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the subslices of the vector which are separated +/// by elements that match `pred`, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = [11, 22, 33, 0, 44, 55]; +/// let iter = slice.rsplit_mut(|num| *num == 0); +/// ``` +/// +/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub struct RSplitMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: SplitMut<'a, T, P>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitMut<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { inner: SplitMut::new(slice, pred) } + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl fmt::Debug for RSplitMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplitMut") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + self.inner.finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> Iterator for RSplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + self.inner.next() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An private iterator over subslices separated by elements that +/// match a predicate function, splitting at most a fixed number of +/// times. +#[derive(Debug)] +struct GenericSplitN { + iter: I, + count: usize, +} + +impl> Iterator for GenericSplitN { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + match self.count { + 0 => None, + 1 => { + self.count -= 1; + self.iter.finish() + } + _ => { + self.count -= 1; + self.iter.next() + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper_opt) = self.iter.size_hint(); + (lower, upper_opt.map(|upper| cmp::min(self.count, upper))) + } +} + +/// An iterator over subslices separated by elements that match a predicate +/// function, limited to a given number of splits. +/// +/// This struct is created by the [`splitn`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.splitn(2, |num| *num % 3 == 0); +/// ``` +/// +/// [`splitn`]: ../../std/primitive.slice.html#method.splitn +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SplitN<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitN<'a, T, P> { + #[inline] + pub(super) fn new(s: Split<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SplitN<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitN").field("inner", &self.inner).finish() + } +} + +/// An iterator over subslices separated by elements that match a +/// predicate function, limited to a given number of splits, starting +/// from the end of the slice. +/// +/// This struct is created by the [`rsplitn`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.rsplitn(2, |num| *num % 3 == 0); +/// ``` +/// +/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct RSplitN<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitN<'a, T, P> { + #[inline] + pub(super) fn new(s: RSplit<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for RSplitN<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplitN").field("inner", &self.inner).finish() + } +} + +/// An iterator over subslices separated by elements that match a predicate +/// function, limited to a given number of splits. +/// +/// This struct is created by the [`splitn_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.splitn_mut(2, |num| *num % 3 == 0); +/// ``` +/// +/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SplitNMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitNMut<'a, T, P> { + #[inline] + pub(super) fn new(s: SplitMut<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SplitNMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitNMut").field("inner", &self.inner).finish() + } +} + +/// An iterator over subslices separated by elements that match a +/// predicate function, limited to a given number of splits, starting +/// from the end of the slice. +/// +/// This struct is created by the [`rsplitn_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.rsplitn_mut(2, |num| *num % 3 == 0); +/// ``` +/// +/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct RSplitNMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitNMut<'a, T, P> { + #[inline] + pub(super) fn new(s: RSplitMut<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for RSplitNMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplitNMut").field("inner", &self.inner).finish() + } +} + +forward_iterator! { SplitN: T, &'a [T] } +forward_iterator! { RSplitN: T, &'a [T] } +forward_iterator! { SplitNMut: T, &'a mut [T] } +forward_iterator! { RSplitNMut: T, &'a mut [T] } + +/// An iterator over overlapping subslices of length `size`. +/// +/// This struct is created by the [`windows`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['r', 'u', 's', 't']; +/// let iter = slice.windows(2); +/// ``` +/// +/// [`windows`]: ../../std/primitive.slice.html#method.windows +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Windows<'a, T: 'a> { + v: &'a [T], + size: usize, +} + +impl<'a, T: 'a> Windows<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, size } + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Windows<'_, T> { + fn clone(&self) -> Self { + Windows { v: self.v, size: self.size } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Windows<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.size > self.v.len() { + None + } else { + let ret = Some(&self.v[..self.size]); + self.v = &self.v[1..]; + ret + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.size > self.v.len() { + (0, Some(0)) + } else { + let size = self.v.len() - self.size + 1; + (size, Some(size)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = self.size.overflowing_add(n); + if end > self.v.len() || overflow { + self.v = &[]; + None + } else { + let nth = &self.v[n..end]; + self.v = &self.v[n + 1..]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.size > self.v.len() { + None + } else { + let start = self.v.len() - self.size; + Some(&self.v[start..]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + // SAFETY: since the caller guarantees that `i` is in bounds, + // which means that `i` cannot overflow an `isize`, and the + // slice created by `from_raw_parts` is a subslice of `self.v` + // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Windows<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.size > self.v.len() { + None + } else { + let ret = Some(&self.v[self.v.len() - self.size..]); + self.v = &self.v[..self.v.len() - 1]; + ret + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let (end, overflow) = self.v.len().overflowing_sub(n); + if end < self.size || overflow { + self.v = &[]; + None + } else { + let ret = &self.v[end - self.size..end]; + self.v = &self.v[..end - 1]; + Some(ret) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Windows<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Windows<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Windows<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`chunks`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks(2); +/// ``` +/// +/// [`chunks`]: ../../std/primitive.slice.html#method.chunks +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Chunks<'a, T: 'a> { + v: &'a [T], + chunk_size: usize, +} + +impl<'a, T: 'a> Chunks<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Chunks<'_, T> { + fn clone(&self) -> Self { + Chunks { v: self.v, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Chunks<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let chunksz = cmp::min(self.v.len(), self.chunk_size); + let (fst, snd) = self.v.split_at(chunksz); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let end = match start.checked_add(self.chunk_size) { + Some(sum) => cmp::min(self.v.len(), sum), + None => self.v.len(), + }; + let nth = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; + Some(&self.v[start..]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + None => self.v.len(), + Some(end) => cmp::min(end, self.v.len()), + }; + // SAFETY: the caller guarantees that `i` is in bounds, + // which means that `start` must be in bounds of the + // underlying `self.v` slice, and we made sure that `end` + // is also in bounds of `self.v`. Thus, `start` cannot overflow + // an `isize`, and the slice constructed by `from_raw_parts` + // is a subslice of `self.v` which is guaranteed to be valid + // for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; + let (fst, snd) = self.v.split_at(self.v.len() - chunksz); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + Some(res) => cmp::min(res, self.v.len()), + None => self.v.len(), + }; + let nth_back = &self.v[start..end]; + self.v = &self.v[..start]; + Some(nth_back) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Chunks<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Chunks<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Chunks<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`chunks_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_mut(2); +/// ``` +/// +/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ChunksMut<'a, T: 'a> { + v: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T: 'a> ChunksMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for ChunksMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let sz = cmp::min(self.v.len(), self.chunk_size); + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(sz); + self.v = tail; + Some(head) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let end = match start.checked_add(self.chunk_size) { + Some(sum) => cmp::min(self.v.len(), sum), + None => self.v.len(), + }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(end); + let (_, nth) = head.split_at_mut(start); + self.v = tail; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; + Some(&mut self.v[start..]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + None => self.v.len(), + Some(end) => cmp::min(end, self.v.len()), + }; + // SAFETY: see comments for `Chunks::__iterator_get_unchecked`. + // + // Also note that the caller also guarantees that we're never called + // with the same index again, and that no other methods that will + // access this subslice are called, so it is valid for the returned + // slice to be mutable. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let sz = if remainder != 0 { remainder } else { self.chunk_size }; + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - sz); + self.v = head; + Some(tail) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + Some(res) => cmp::min(res, self.v.len()), + None => self.v.len(), + }; + let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (head, nth_back) = temp.split_at_mut(start); + self.v = head; + Some(nth_back) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for ChunksMut<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ChunksMut<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ChunksMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `chunk_size-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. +/// +/// This struct is created by the [`chunks_exact`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_exact(2); +/// ``` +/// +/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact +/// [`remainder`]: ChunksExact::remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub struct ChunksExact<'a, T: 'a> { + v: &'a [T], + rem: &'a [T], + chunk_size: usize, +} + +impl<'a, T> ChunksExact<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + let fst_len = slice.len() - rem; + // SAFETY: 0 <= fst_len <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_unchecked(fst_len) }; + Self { v: fst, rem: snd, chunk_size } + } + + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + #[stable(feature = "chunks_exact", since = "1.31.0")] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl Clone for ChunksExact<'_, T> { + fn clone(&self) -> Self { + ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> Iterator for ChunksExact<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.chunk_size); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let (_, snd) = self.v.split_at(start); + self.v = snd; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = start + self.chunk_size; + let nth_back = &self.v[start..end]; + self.v = &self.v[..start]; + Some(nth_back) + } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl ExactSizeIterator for ChunksExact<'_, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ChunksExact<'_, T> {} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl FusedIterator for ChunksExact<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last up to +/// `chunk_size-1` elements will be omitted but can be retrieved from the +/// [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`chunks_exact_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_exact_mut(2); +/// ``` +/// +/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut +/// [`into_remainder`]: ChunksExactMut::into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub struct ChunksExactMut<'a, T: 'a> { + v: &'a mut [T], + rem: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T> ChunksExactMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + let fst_len = slice.len() - rem; + // SAFETY: 0 <= fst_len <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) }; + Self { v: fst, rem: snd, chunk_size } + } + + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + #[stable(feature = "chunks_exact", since = "1.31.0")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> Iterator for ChunksExactMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(self.chunk_size); + self.v = tail; + Some(head) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (_, snd) = tmp.split_at_mut(start); + self.v = snd; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); + self.v = head; + Some(tail) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = start + self.chunk_size; + let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (head, nth_back) = temp.split_at_mut(start); + self.v = head; + Some(nth_back) + } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl ExactSizeIterator for ChunksExactMut<'_, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ChunksExactMut<'_, T> {} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl FusedIterator for ChunksExactMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// A windowed iterator over a slice in overlapping chunks (`N` elements at a +/// time), starting at the beginning of the slice +/// +/// This struct is created by the [`array_windows`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(array_windows)] +/// +/// let slice = [0, 1, 2, 3]; +/// let iter = slice.array_windows::<2>(); +/// ``` +/// +/// [`array_windows`]: ../../std/primitive.slice.html#method.array_windows +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug, Clone, Copy)] +#[unstable(feature = "array_windows", issue = "75027")] +pub struct ArrayWindows<'a, T: 'a, const N: usize> { + slice_head: *const T, + num: usize, + marker: PhantomData<&'a [T; N]>, +} + +impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> { + #[inline] + pub(super) fn new(slice: &'a [T]) -> Self { + let num_windows = slice.len().saturating_sub(N - 1); + Self { slice_head: slice.as_ptr(), num: num_windows, marker: PhantomData } + } +} + +#[unstable(feature = "array_windows", issue = "75027")] +impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> { + type Item = &'a [T; N]; + + #[inline] + fn next(&mut self) -> Option { + if self.num == 0 { + return None; + } + // SAFETY: + // This is safe because it's indexing into a slice guaranteed to be length > N. + let ret = unsafe { &*self.slice_head.cast::<[T; N]>() }; + // SAFETY: Guaranteed that there are at least 1 item remaining otherwise + // earlier branch would've been hit + self.slice_head = unsafe { self.slice_head.add(1) }; + + self.num -= 1; + Some(ret) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.num, Some(self.num)) + } + + #[inline] + fn count(self) -> usize { + self.num + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + if self.num <= n { + self.num = 0; + return None; + } + // SAFETY: + // This is safe because it's indexing into a slice guaranteed to be length > N. + let ret = unsafe { &*self.slice_head.add(n).cast::<[T; N]>() }; + // SAFETY: Guaranteed that there are at least n items remaining + self.slice_head = unsafe { self.slice_head.add(n + 1) }; + + self.num -= n + 1; + Some(ret) + } + + #[inline] + fn last(mut self) -> Option { + self.nth(self.num.checked_sub(1)?) + } +} + +#[unstable(feature = "array_windows", issue = "75027")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T; N]> { + if self.num == 0 { + return None; + } + // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing. + let ret = unsafe { &*self.slice_head.add(self.num - 1).cast::<[T; N]>() }; + self.num -= 1; + Some(ret) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<&'a [T; N]> { + if self.num <= n { + self.num = 0; + return None; + } + // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing. + let ret = unsafe { &*self.slice_head.add(self.num - (n + 1)).cast::<[T; N]>() }; + self.num -= n + 1; + Some(ret) + } +} + +#[unstable(feature = "array_windows", issue = "75027")] +impl ExactSizeIterator for ArrayWindows<'_, T, N> { + fn is_empty(&self) -> bool { + self.num == 0 + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `N-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. +/// +/// This struct is created by the [`array_chunks`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(array_chunks)] +/// +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.array_chunks::<2>(); +/// ``` +/// +/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks +/// [`remainder`]: ArrayChunks::remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "array_chunks", issue = "74985")] +pub struct ArrayChunks<'a, T: 'a, const N: usize> { + iter: Iter<'a, [T; N]>, + rem: &'a [T], +} + +impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { + #[inline] + pub(super) fn new(slice: &'a [T]) -> Self { + let len = slice.len() / N; + let (fst, snd) = slice.split_at(len * N); + // SAFETY: We cast a slice of `len * N` elements into + // a slice of `len` many `N` elements chunks. + let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) }; + + Self { iter: array_slice.iter(), rem: snd } + } + + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `N-1` + /// elements. + #[unstable(feature = "array_chunks", issue = "74985")] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "array_chunks", issue = "74985")] +impl Clone for ArrayChunks<'_, T, N> { + fn clone(&self) -> Self { + ArrayChunks { iter: self.iter.clone(), rem: self.rem } + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { + type Item = &'a [T; N]; + + #[inline] + fn next(&mut self) -> Option<&'a [T; N]> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } + + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] { + // SAFETY: The safety guarantees of `__iterator_get_unchecked` are + // transferred to the caller. + unsafe { self.iter.__iterator_get_unchecked(i) } + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T; N]> { + self.iter.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n) + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl ExactSizeIterator for ArrayChunks<'_, T, N> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ArrayChunks<'_, T, N> {} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl FusedIterator for ArrayChunks<'_, T, N> {} + +#[doc(hidden)] +#[unstable(feature = "array_chunks", issue = "74985")] +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements +/// at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `N-1` elements will be omitted but can be retrieved from +/// the [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`array_chunks_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(array_chunks)] +/// +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.array_chunks_mut::<2>(); +/// ``` +/// +/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut +/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "array_chunks", issue = "74985")] +pub struct ArrayChunksMut<'a, T: 'a, const N: usize> { + iter: IterMut<'a, [T; N]>, + rem: &'a mut [T], +} + +impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { + #[inline] + pub(super) fn new(slice: &'a mut [T]) -> Self { + let len = slice.len() / N; + let (fst, snd) = slice.split_at_mut(len * N); + // SAFETY: We cast a slice of `len * N` elements into + // a slice of `len` many `N` elements chunks. + unsafe { + let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len); + Self { iter: array_slice.iter_mut(), rem: snd } + } + } + + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `N-1` + /// elements. + #[unstable(feature = "array_chunks", issue = "74985")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { + type Item = &'a mut [T; N]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } + + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { + // SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to + // the caller. + unsafe { self.iter.__iterator_get_unchecked(i) } + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n) + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl ExactSizeIterator for ArrayChunksMut<'_, T, N> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ArrayChunksMut<'_, T, N> {} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl FusedIterator for ArrayChunksMut<'_, T, N> {} + +#[doc(hidden)] +#[unstable(feature = "array_chunks", issue = "74985")] +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`rchunks`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks(2); +/// ``` +/// +/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunks<'a, T: 'a> { + v: &'a [T], + chunk_size: usize, +} + +impl<'a, T: 'a> RChunks<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rchunks", since = "1.31.0")] +impl Clone for RChunks<'_, T> { + fn clone(&self) -> Self { + RChunks { v: self.v, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunks<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let chunksz = cmp::min(self.v.len(), self.chunk_size); + let (fst, snd) = self.v.split_at(self.v.len() - chunksz); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &[]; + None + } else { + // Can't underflow because of the check above + let end = self.v.len() - end; + let start = match end.checked_sub(self.chunk_size) { + Some(sum) => sum, + None => 0, + }; + let nth = &self.v[start..end]; + self.v = &self.v[0..start]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let rem = self.v.len() % self.chunk_size; + let end = if rem == 0 { self.chunk_size } else { rem }; + Some(&self.v[0..end]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; + let (fst, snd) = self.v.split_at(chunksz); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + // can't underflow because `n < len` + let offset_from_end = (len - 1 - n) * self.chunk_size; + let end = self.v.len() - offset_from_end; + let start = end.saturating_sub(self.chunk_size); + let nth_back = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl ExactSizeIterator for RChunks<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunks<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunks<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`rchunks_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_mut(2); +/// ``` +/// +/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunksMut<'a, T: 'a> { + v: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T: 'a> RChunksMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunksMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let sz = cmp::min(self.v.len(), self.chunk_size); + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - sz); + self.v = head; + Some(tail) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + // Can't underflow because of the check above + let end = self.v.len() - end; + let start = match end.checked_sub(self.chunk_size) { + Some(sum) => sum, + None => 0, + }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(start); + let (nth, _) = tail.split_at_mut(end - start); + self.v = head; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let rem = self.v.len() % self.chunk_size; + let end = if rem == 0 { self.chunk_size } else { rem }; + Some(&mut self.v[0..end]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + // SAFETY: see comments for `RChunks::__iterator_get_unchecked` and + // `ChunksMut::__iterator_get_unchecked` + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let sz = if remainder != 0 { remainder } else { self.chunk_size }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(sz); + self.v = tail; + Some(head) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + // can't underflow because `n < len` + let offset_from_end = (len - 1 - n) * self.chunk_size; + let end = self.v.len() - offset_from_end; + let start = end.saturating_sub(self.chunk_size); + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); + self.v = tail; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl ExactSizeIterator for RChunksMut<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunksMut<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunksMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `chunk_size-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. +/// +/// This struct is created by the [`rchunks_exact`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_exact(2); +/// ``` +/// +/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact +/// [`remainder`]: ChunksExact::remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunksExact<'a, T: 'a> { + v: &'a [T], + rem: &'a [T], + chunk_size: usize, +} + +impl<'a, T> RChunksExact<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + // SAFETY: 0 <= rem <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_unchecked(rem) }; + Self { v: snd, rem: fst, chunk_size } + } + + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + #[stable(feature = "rchunks", since = "1.31.0")] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Clone for RChunksExact<'a, T> { + fn clone(&self) -> RChunksExact<'a, T> { + RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunksExact<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let (fst, _) = self.v.split_at(self.v.len() - end); + self.v = fst; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = end - self.chunk_size; + // SAFETY: + // SAFETY: mostmy identical to `Chunks::__iterator_get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.chunk_size); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + // now that we know that `n` corresponds to a chunk, + // none of these operations can underflow/overflow + let offset = (len - n) * self.chunk_size; + let start = self.v.len() - offset; + let end = start + self.chunk_size; + let nth_back = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunksExact<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunksExact<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last up to +/// `chunk_size-1` elements will be omitted but can be retrieved from the +/// [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`rchunks_exact_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_exact_mut(2); +/// ``` +/// +/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut +/// [`into_remainder`]: ChunksExactMut::into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunksExactMut<'a, T: 'a> { + v: &'a mut [T], + rem: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T> RChunksExactMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + // SAFETY: 0 <= rem <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_mut_unchecked(rem) }; + Self { v: snd, rem: fst, chunk_size } + } + + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + #[stable(feature = "rchunks", since = "1.31.0")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunksExactMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); + self.v = head; + Some(tail) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (fst, _) = tmp.split_at_mut(tmp_len - end); + self.v = fst; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = end - self.chunk_size; + // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(self.chunk_size); + self.v = tail; + Some(head) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + // now that we know that `n` corresponds to a chunk, + // none of these operations can underflow/overflow + let offset = (len - n) * self.chunk_size; + let start = self.v.len() - offset; + let end = start + self.chunk_size; + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); + self.v = tail; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl ExactSizeIterator for RChunksExactMut<'_, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunksExactMut<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunksExactMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs new file mode 100644 index 0000000000..457b2a3605 --- /dev/null +++ b/library/core/src/slice/iter/macros.rs @@ -0,0 +1,407 @@ +//! Macros used by iterators of slice. + +// Inlining is_empty and len makes a huge performance difference +macro_rules! is_empty { + // The way we encode the length of a ZST iterator, this works both for ZST + // and non-ZST. + ($self: ident) => { + $self.ptr.as_ptr() as *const T == $self.end + }; +} + +// To get rid of some bounds checks (see `position`), we compute the length in a somewhat +// unexpected way. (Tested by `codegen/slice-position-bounds-check`.) +macro_rules! len { + ($self: ident) => {{ + #![allow(unused_unsafe)] // we're sometimes used within an unsafe block + + let start = $self.ptr; + let size = size_from_ptr(start.as_ptr()); + if size == 0 { + // This _cannot_ use `unchecked_sub` because we depend on wrapping + // to represent the length of long ZST slice iterators. + ($self.end as usize).wrapping_sub(start.as_ptr() as usize) + } else { + // We know that `start <= end`, so can do better than `offset_from`, + // which needs to deal in signed. By setting appropriate flags here + // we can tell LLVM this, which helps it remove bounds checks. + // SAFETY: By the type invariant, `start <= end` + let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) }; + // By also telling LLVM that the pointers are apart by an exact + // multiple of the type size, it can optimize `len() == 0` down to + // `start == end` instead of `(end - start) < size`. + // SAFETY: By the type invariant, the pointers are aligned so the + // distance between them must be a multiple of pointee size + unsafe { exact_div(diff, size) } + } + }}; +} + +// The shared definition of the `Iter` and `IterMut` iterators +macro_rules! iterator { + ( + struct $name:ident -> $ptr:ty, + $elem:ty, + $raw_mut:tt, + {$( $mut_:tt )?}, + {$($extra:tt)*} + ) => { + // Returns the first element and moves the start of the iterator forwards by 1. + // Greatly improves performance compared to an inlined function. The iterator + // must not be empty. + macro_rules! next_unchecked { + ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)} + } + + // Returns the last element and moves the end of the iterator backwards by 1. + // Greatly improves performance compared to an inlined function. The iterator + // must not be empty. + macro_rules! next_back_unchecked { + ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)} + } + + // Shrinks the iterator when T is a ZST, by moving the end of the 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; + } + } + + impl<'a, T> $name<'a, T> { + // Helper function for creating a slice from the iterator. + #[inline(always)] + fn make_slice(&self) -> &'a [T] { + // SAFETY: the iterator was created from a slice with pointer + // `self.ptr` and length `len!(self)`. This guarantees that all + // the prerequisites for `from_raw_parts` are fulfilled. + unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) } + } + + // Helper function for moving the start of the iterator forwards by `offset` elements, + // 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 { + if mem::size_of::() == 0 { + zst_shrink!(self, offset); + self.ptr.as_ptr() + } else { + 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)) }; + old + } + } + + // Helper function for moving the end of the iterator backwards by `offset` elements, + // 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 { + if mem::size_of::() == 0 { + zst_shrink!(self, offset); + self.ptr.as_ptr() + } else { + // 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 + } + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl ExactSizeIterator for $name<'_, T> { + #[inline(always)] + fn len(&self) -> usize { + len!(self) + } + + #[inline(always)] + fn is_empty(&self) -> bool { + is_empty!(self) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T> Iterator for $name<'a, T> { + type Item = $elem; + + #[inline] + fn next(&mut self) -> Option<$elem> { + // could be implemented with slices, but this avoids bounds checks + + // SAFETY: `assume` calls are safe since a slice's start pointer + // must be non-null, and slices over non-ZSTs must also have a + // non-null end pointer. The call to `next_unchecked!` is safe + // since we check if the iterator is empty first. + unsafe { + assume(!self.ptr.as_ptr().is_null()); + if mem::size_of::() != 0 { + assume(!self.end.is_null()); + } + if is_empty!(self) { + None + } else { + Some(next_unchecked!(self)) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let exact = len!(self); + (exact, Some(exact)) + } + + #[inline] + fn count(self) -> usize { + len!(self) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<$elem> { + if n >= len!(self) { + // This iterator is now empty. + if mem::size_of::() == 0 { + // We have to do it this way as `ptr` may never be 0, but `end` + // could be (due to wrapping). + self.end = self.ptr.as_ptr(); + } else { + // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr + unsafe { + self.ptr = NonNull::new_unchecked(self.end as *mut T); + } + } + return None; + } + // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. + unsafe { + self.post_inc_start(n as isize); + Some(next_unchecked!(self)) + } + } + + #[inline] + fn last(mut self) -> Option<$elem> { + self.next_back() + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn for_each(mut self, mut f: F) + where + Self: Sized, + F: FnMut(Self::Item), + { + while let Some(x) = self.next() { + f(x); + } + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn all(&mut self, mut f: F) -> bool + where + Self: Sized, + F: FnMut(Self::Item) -> bool, + { + while let Some(x) = self.next() { + if !f(x) { + return false; + } + } + true + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn any(&mut self, mut f: F) -> bool + where + Self: Sized, + F: FnMut(Self::Item) -> bool, + { + while let Some(x) = self.next() { + if f(x) { + return true; + } + } + false + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn find

(&mut self, mut predicate: P) -> Option + where + Self: Sized, + P: FnMut(&Self::Item) -> bool, + { + while let Some(x) = self.next() { + if predicate(&x) { + return Some(x); + } + } + None + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn find_map(&mut self, mut f: F) -> Option + where + Self: Sized, + F: FnMut(Self::Item) -> Option, + { + while let Some(x) = self.next() { + if let Some(y) = f(x) { + return Some(y); + } + } + None + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. Also, the `assume` avoids a bounds check. + #[inline] + #[rustc_inherit_overflow_checks] + fn position

(&mut self, mut predicate: P) -> Option where + Self: Sized, + P: FnMut(Self::Item) -> bool, + { + let n = len!(self); + let mut i = 0; + while let Some(x) = self.next() { + if predicate(x) { + // SAFETY: we are guaranteed to be in bounds by the loop invariant: + // when `i >= n`, `self.next()` returns `None` and the loop breaks. + unsafe { assume(i < n) }; + return Some(i); + } + i += 1; + } + None + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. Also, the `assume` avoids a bounds check. + #[inline] + fn rposition

(&mut self, mut predicate: P) -> Option where + P: FnMut(Self::Item) -> bool, + Self: Sized + ExactSizeIterator + DoubleEndedIterator + { + let n = len!(self); + let mut i = n; + while let Some(x) = self.next_back() { + i -= 1; + if predicate(x) { + // SAFETY: `i` must be lower than `n` since it starts at `n` + // and is only decreasing. + unsafe { assume(i < n) }; + return Some(i); + } + } + None + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + // SAFETY: the caller must guarantee that `i` is in bounds of + // the underlying slice, so `i` cannot overflow an `isize`, and + // the returned references is guaranteed to refer to an element + // of the slice and thus guaranteed to be valid. + // + // Also note that the caller also guarantees that we're never + // called with the same index again, and that no other methods + // that will access this subslice are called, so it is valid + // for the returned reference to be mutable in the case of + // `IterMut` + unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) } + } + + $($extra)* + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T> DoubleEndedIterator for $name<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<$elem> { + // could be implemented with slices, but this avoids bounds checks + + // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null, + // and slices over non-ZSTs must also have a non-null end pointer. + // The call to `next_back_unchecked!` is safe since we check if the iterator is + // empty first. + unsafe { + assume(!self.ptr.as_ptr().is_null()); + if mem::size_of::() != 0 { + assume(!self.end.is_null()); + } + if is_empty!(self) { + None + } else { + Some(next_back_unchecked!(self)) + } + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<$elem> { + if n >= len!(self) { + // This iterator is now empty. + self.end = self.ptr.as_ptr(); + return None; + } + // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. + unsafe { + self.pre_dec_end(n as isize); + Some(next_back_unchecked!(self)) + } + } + } + + #[stable(feature = "fused", since = "1.26.0")] + impl FusedIterator for $name<'_, T> {} + + #[unstable(feature = "trusted_len", issue = "37572")] + unsafe impl TrustedLen for $name<'_, T> {} + } +} + +macro_rules! forward_iterator { + ($name:ident: $elem:ident, $iter_of:ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, $elem, P> Iterator for $name<'a, $elem, P> + where + P: FnMut(&T) -> bool, + { + type Item = $iter_of; + + #[inline] + fn next(&mut self) -> Option<$iter_of> { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + } + + #[stable(feature = "fused", since = "1.26.0")] + impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} + }; +} diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index 3b13ed5fed..0c0f175026 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -12,6 +12,7 @@ const HI_U64: u64 = 0x8080808080808080; // Use truncation. const LO_USIZE: usize = LO_U64 as usize; const HI_USIZE: usize = HI_U64 as usize; +const USIZE_BYTES: usize = mem::size_of::(); /// Returns `true` if `x` contains any zero byte. /// @@ -38,19 +39,29 @@ fn repeat_byte(b: u8) -> usize { } /// Returns the first index matching the byte `x` in `text`. +#[inline] pub 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); + } + + memchr_general_case(x, text) +} + +fn memchr_general_case(x: u8, text: &[u8]) -> Option { // Scan for a single byte value by reading two `usize` words at a time. // // Split `text` in three parts // - unaligned initial part, before the first word aligned address in text // - body, scan by 2 words at a time // - the last remaining part, < 2 word size + + // search up to an aligned boundary let len = text.len(); let ptr = text.as_ptr(); - let usize_bytes = mem::size_of::(); + let mut offset = ptr.align_offset(USIZE_BYTES); - // search up to an aligned boundary - let mut offset = ptr.align_offset(usize_bytes); if offset > 0 { offset = cmp::min(offset, len); if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { @@ -60,22 +71,19 @@ pub fn memchr(x: u8, text: &[u8]) -> Option { // search the body of the text let repeated_x = repeat_byte(x); + while offset <= len - 2 * USIZE_BYTES { + unsafe { + let u = *(ptr.add(offset) as *const usize); + let v = *(ptr.add(offset + USIZE_BYTES) as *const usize); - if len >= 2 * usize_bytes { - while offset <= len - 2 * usize_bytes { - unsafe { - let u = *(ptr.add(offset) as *const usize); - let v = *(ptr.add(offset + usize_bytes) as *const usize); - - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; - } + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; } - offset += usize_bytes * 2; } + offset += USIZE_BYTES * 2; } // Find the byte after the point the body loop stopped. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e7eed43824..b1ca093add 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -8,31 +8,13 @@ #![stable(feature = "rust1", since = "1.0.0")] -// How this module is organized. -// -// The library infrastructure for slices is fairly messy. There's -// a lot of stuff defined here. Let's keep it clean. -// -// The layout of this file is thus: -// -// * Inherent methods. This is where most of the slice API resides. -// * Implementations of a few common traits with important slice ops. -// * Definitions of a bunch of iterators. -// * Free functions. -// * The `raw` and `bytes` submodules. -// * Boilerplate trait implementations. - -use crate::cmp; use crate::cmp::Ordering::{self, Equal, Greater, Less}; -use crate::fmt; -use crate::intrinsics::{assume, exact_div, is_aligned_and_not_null, unchecked_sub}; -use crate::iter::*; -use crate::marker::{self, Copy, Send, Sized, Sync}; +use crate::marker::Copy; use crate::mem; -use crate::ops::{self, FnMut, Range}; +use crate::ops::{FnMut, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; -use crate::ptr::{self, NonNull}; +use crate::ptr; use crate::result::Result; use crate::result::Result::{Err, Ok}; @@ -44,12 +26,54 @@ use crate::result::Result::{Err, Ok}; /// Pure rust memchr implementation, taken from rust-memchr pub mod memchr; +mod ascii; +mod cmp; +mod index; +mod iter; +mod raw; mod rotate; mod sort; -// -// Extension traits -// +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Chunks, ChunksMut, Windows}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Iter, IterMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut}; + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub use iter::{RSplit, RSplitMut}; + +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub use iter::{ChunksExact, ChunksExactMut}; + +#[stable(feature = "rchunks", since = "1.31.0")] +pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; + +#[unstable(feature = "array_chunks", issue = "74985")] +pub use iter::{ArrayChunks, ArrayChunksMut}; + +#[unstable(feature = "array_windows", issue = "75027")] +pub use iter::ArrayWindows; + +#[unstable(feature = "split_inclusive", issue = "72360")] +pub use iter::{SplitInclusive, SplitInclusiveMut}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::{from_raw_parts, from_raw_parts_mut}; + +#[stable(feature = "from_ref", since = "1.28.0")] +pub use raw::{from_mut, from_ref}; + +// This function is public only because there is no other way to unit test heapsort. +#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] +pub use sort::heapsort; + +#[stable(feature = "slice_get_slice", since = "1.28.0")] +pub use index::SliceIndex; + +#[unstable(feature = "slice_check_range", issue = "76393")] +pub use index::check_range; #[lang = "slice"] #[cfg(not(test))] @@ -66,7 +90,6 @@ impl [T] { #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")] #[inline] // SAFETY: const sound because we transmute out the length field as a usize (which it must be) - #[allow(unused_attributes)] #[allow_internal_unstable(const_fn_union)] pub const fn len(&self) -> usize { // SAFETY: this is safe because `&[T]` and `FatPtr` have the same layout. @@ -288,10 +311,12 @@ impl [T] { /// Returns a reference to an element or subslice, without doing bounds /// checking. /// - /// This is generally not recommended, use with caution! + /// For a safe alternative see [`get`]. + /// + /// # Safety + /// /// Calling this method with an out-of-bounds index is *[undefined behavior]* /// even if the resulting reference is not used. - /// For a safe alternative see [`get`]. /// /// [`get`]: #method.get /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html @@ -320,10 +345,12 @@ impl [T] { /// Returns a mutable reference to an element or subslice, without doing /// bounds checking. /// - /// This is generally not recommended, use with caution! + /// For a safe alternative see [`get_mut`]. + /// + /// # Safety + /// /// Calling this method with an out-of-bounds index is *[undefined behavior]* /// even if the resulting reference is not used. - /// For a safe alternative see [`get_mut`]. /// /// [`get_mut`]: #method.get_mut /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html @@ -406,8 +433,9 @@ impl [T] { /// assert_eq!(x, &[3, 4, 6]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn as_mut_ptr(&mut self) -> *mut T { + pub const fn as_mut_ptr(&mut self) -> *mut T { self as *mut [T] as *mut T } @@ -430,8 +458,6 @@ impl [T] { /// element of this slice: /// /// ``` - /// #![feature(slice_ptr_range)] - /// /// let a = [1, 2, 3]; /// let x = &a[1] as *const _; /// let y = &5 as *const _; @@ -441,9 +467,10 @@ impl [T] { /// ``` /// /// [`as_ptr`]: #method.as_ptr - #[unstable(feature = "slice_ptr_range", issue = "65807")] + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn as_ptr_range(&self) -> Range<*const T> { + pub const fn as_ptr_range(&self) -> Range<*const T> { let start = self.as_ptr(); // SAFETY: The `add` here is safe, because: // @@ -482,9 +509,10 @@ impl [T] { /// common in C++. /// /// [`as_mut_ptr`]: #method.as_mut_ptr - #[unstable(feature = "slice_ptr_range", issue = "65807")] + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> { let start = self.as_mut_ptr(); // SAFETY: See as_ptr_range() above for why `add` here is safe. let end = unsafe { start.add(self.len()) }; @@ -651,34 +679,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter(&self) -> Iter<'_, T> { - let ptr = self.as_ptr(); - // SAFETY: There are several things here: - // - // `ptr` has been obtained by `self.as_ptr()` where `self` is a valid - // reference thus it is non-NUL and safe to use and pass to - // `NonNull::new_unchecked` . - // - // Adding `self.len()` to the starting pointer gives a pointer - // at the end of `self`. `end` will never be dereferenced, only checked - // for direct pointer equality with `ptr` to check if the iterator is - // done. - // - // In the case of a ZST, the end pointer is just the start pointer plus - // the length, to also allows for the fast `ptr == end` check. - // - // See the `next_unchecked!` and `is_empty!` macros as well as the - // `post_inc_start` method for more informations. - unsafe { - assume(!ptr.is_null()); - - let end = if mem::size_of::() == 0 { - (ptr as *const u8).wrapping_add(self.len()) as *const T - } else { - ptr.add(self.len()) - }; - - Iter { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: marker::PhantomData } - } + Iter::new(self) } /// Returns an iterator that allows modifying each value. @@ -695,34 +696,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter_mut(&mut self) -> IterMut<'_, T> { - let ptr = self.as_mut_ptr(); - // SAFETY: There are several things here: - // - // `ptr` has been obtained by `self.as_ptr()` where `self` is a valid - // reference thus it is non-NUL and safe to use and pass to - // `NonNull::new_unchecked` . - // - // Adding `self.len()` to the starting pointer gives a pointer - // at the end of `self`. `end` will never be dereferenced, only checked - // for direct pointer equality with `ptr` to check if the iterator is - // done. - // - // In the case of a ZST, the end pointer is just the start pointer plus - // the length, to also allows for the fast `ptr == end` check. - // - // See the `next_unchecked!` and `is_empty!` macros as well as the - // `post_inc_start` method for more informations. - unsafe { - assume(!ptr.is_null()); - - let end = if mem::size_of::() == 0 { - (ptr as *mut u8).wrapping_add(self.len()) as *mut T - } else { - ptr.add(self.len()) - }; - - IterMut { ptr: NonNull::new_unchecked(ptr), end, _marker: marker::PhantomData } - } + IterMut::new(self) } /// Returns an iterator over all contiguous windows of length @@ -755,7 +729,7 @@ impl [T] { #[inline] pub fn windows(&self, size: usize) -> Windows<'_, T> { assert_ne!(size, 0); - Windows { v: self, size } + Windows::new(self, size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -789,7 +763,7 @@ impl [T] { #[inline] pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { assert_ne!(chunk_size, 0); - Chunks { v: self, chunk_size } + Chunks::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -827,7 +801,7 @@ impl [T] { #[inline] pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { assert_ne!(chunk_size, 0); - ChunksMut { v: self, chunk_size } + ChunksMut::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -864,10 +838,7 @@ impl [T] { #[inline] pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { assert_ne!(chunk_size, 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - let (fst, snd) = self.split_at(len); - ChunksExact { v: fst, rem: snd, chunk_size } + ChunksExact::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -909,18 +880,15 @@ impl [T] { #[inline] pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { assert_ne!(chunk_size, 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - let (fst, snd) = self.split_at_mut(len); - ChunksExactMut { v: fst, rem: snd, chunk_size } + ChunksExactMut::new(self, chunk_size) } /// Returns an iterator over `N` elements of the slice at a time, starting at the /// beginning of the slice. /// - /// The chunks are slices and do not overlap. If `N` does not divide the length of the - /// slice, then the last up to `N-1` elements will be omitted and can be retrieved - /// from the `remainder` function of the iterator. + /// The chunks are array references and do not overlap. If `N` does not divide the + /// length of the slice, then the last up to `N-1` elements will be omitted and can be + /// retrieved from the `remainder` function of the iterator. /// /// This method is the const generic equivalent of [`chunks_exact`]. /// @@ -946,12 +914,75 @@ impl [T] { #[inline] pub fn array_chunks(&self) -> ArrayChunks<'_, T, N> { assert_ne!(N, 0); - let len = self.len() / N; - let (fst, snd) = self.split_at(len * N); - // SAFETY: We cast a slice of `len * N` elements into - // a slice of `len` many `N` elements chunks. - let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) }; - ArrayChunks { iter: array_slice.iter(), rem: snd } + ArrayChunks::new(self) + } + + /// Returns an iterator over `N` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable array references and do not overlap. If `N` does not divide + /// the length of the slice, then the last up to `N-1` elements will be omitted and + /// can be retrieved from the `into_remainder` function of the iterator. + /// + /// This method is the const generic equivalent of [`chunks_exact_mut`]. + /// + /// # Panics + /// + /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// error before this method gets stabilized. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_chunks)] + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.array_chunks_mut() { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_exact_mut`]: #method.chunks_exact_mut + #[unstable(feature = "array_chunks", issue = "74985")] + #[inline] + pub fn array_chunks_mut(&mut self) -> ArrayChunksMut<'_, T, N> { + assert_ne!(N, 0); + ArrayChunksMut::new(self) + } + + /// Returns an iterator over overlapping windows of `N` elements of a slice, + /// starting at the beginning of the slice. + /// + /// This is the const generic equivalent of [`windows`]. + /// + /// If `N` is greater than the size of the slice, it will return no windows. + /// + /// # Panics + /// + /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// error before this method gets stabilized. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_windows)] + /// let slice = [0, 1, 2, 3]; + /// let mut iter = slice.array_windows(); + /// assert_eq!(iter.next().unwrap(), &[0, 1]); + /// assert_eq!(iter.next().unwrap(), &[1, 2]); + /// assert_eq!(iter.next().unwrap(), &[2, 3]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`windows`]: #method.windows + #[unstable(feature = "array_windows", issue = "75027")] + #[inline] + pub fn array_windows(&self) -> ArrayWindows<'_, T, N> { + assert_ne!(N, 0); + ArrayWindows::new(self) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -985,7 +1016,7 @@ impl [T] { #[inline] pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { assert!(chunk_size != 0); - RChunks { v: self, chunk_size } + RChunks::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -1023,7 +1054,7 @@ impl [T] { #[inline] pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { assert!(chunk_size != 0); - RChunksMut { v: self, chunk_size } + RChunksMut::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -1062,9 +1093,7 @@ impl [T] { #[inline] pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let (fst, snd) = self.split_at(rem); - RChunksExact { v: snd, rem: fst, chunk_size } + RChunksExact::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -1107,9 +1136,7 @@ impl [T] { #[inline] pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let (fst, snd) = self.split_at_mut(rem); - RChunksExactMut { v: snd, rem: fst, chunk_size } + RChunksExactMut::new(self, chunk_size) } /// Divides one slice into two at an index. @@ -1129,26 +1156,29 @@ impl [T] { /// /// { /// let (left, right) = v.split_at(0); - /// assert!(left == []); - /// assert!(right == [1, 2, 3, 4, 5, 6]); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); /// } /// /// { /// let (left, right) = v.split_at(2); - /// assert!(left == [1, 2]); - /// assert!(right == [3, 4, 5, 6]); + /// assert_eq!(left, [1, 2]); + /// assert_eq!(right, [3, 4, 5, 6]); /// } /// /// { /// let (left, right) = v.split_at(6); - /// assert!(left == [1, 2, 3, 4, 5, 6]); - /// assert!(right == []); + /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, []); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { - (&self[..mid], &self[mid..]) + assert!(mid <= self.len()); + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `from_raw_parts_mut`. + unsafe { self.split_at_unchecked(mid) } } /// Divides one mutable slice into two at an index. @@ -1168,26 +1198,115 @@ impl [T] { /// // scoped to restrict the lifetime of the borrows /// { /// let (left, right) = v.split_at_mut(2); - /// assert!(left == [1, 0]); - /// assert!(right == [3, 0, 5, 6]); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); /// left[1] = 2; /// right[1] = 4; /// } - /// assert!(v == [1, 2, 3, 4, 5, 6]); + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - let len = self.len(); - let ptr = self.as_mut_ptr(); - + assert!(mid <= self.len()); // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which // fulfills the requirements of `from_raw_parts_mut`. - unsafe { - assert!(mid <= len); + unsafe { self.split_at_mut_unchecked(mid) } + } - (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) - } + /// Divides one slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at`]: #method.split_at + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ```compile_fail + /// #![feature(slice_split_at_unchecked)] + /// + /// let v = [1, 2, 3, 4, 5, 6]; + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(0); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(2); + /// assert_eq!(left, [1, 2]); + /// assert_eq!(right, [3, 4, 5, 6]); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(6); + /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, []); + /// } + /// ``` + #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] + #[inline] + unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + // SAFETY: Caller has to check that `0 <= mid <= self.len()` + unsafe { (self.get_unchecked(..mid), self.get_unchecked(mid..)) } + } + + /// Divides one mutable slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at_mut`]: #method.split_at_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ```compile_fail + /// #![feature(slice_split_at_unchecked)] + /// + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// unsafe { + /// let (left, right) = v.split_at_mut_unchecked(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] + #[inline] + unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + + // SAFETY: Caller has to check that `0 <= mid <= self.len()`. + // + // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference + // is fine. + unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } } /// Returns an iterator over subslices separated by elements that match @@ -1236,7 +1355,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - Split { v: self, pred, finished: false } + Split::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that @@ -1258,7 +1377,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitMut { v: self, pred, finished: false } + SplitMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -1296,7 +1415,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitInclusive { v: self, pred, finished: false } + SplitInclusive::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that @@ -1321,7 +1440,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitInclusiveMut { v: self, pred, finished: false } + SplitInclusiveMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -1357,7 +1476,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplit { inner: self.split(pred) } + RSplit::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that @@ -1383,7 +1502,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitMut { inner: self.split_mut(pred) } + RSplitMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -1411,7 +1530,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitN { inner: GenericSplitN { iter: self.split(pred), count: n } } + SplitN::new(self.split(pred), n) } /// Returns an iterator over subslices separated by elements that match @@ -1437,7 +1556,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitNMut { inner: GenericSplitN { iter: self.split_mut(pred), count: n } } + SplitNMut::new(self.split_mut(pred), n) } /// Returns an iterator over subslices separated by elements that match @@ -1466,7 +1585,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitN { inner: GenericSplitN { iter: self.rsplit(pred), count: n } } + RSplitN::new(self.rsplit(pred), n) } /// Returns an iterator over subslices separated by elements that match @@ -1493,7 +1612,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitNMut { inner: GenericSplitN { iter: self.rsplit_mut(pred), count: n } } + RSplitNMut::new(self.rsplit_mut(pred), n) } /// Returns `true` if the slice contains an element with the given value. @@ -1515,11 +1634,12 @@ impl [T] { /// assert!(!v.iter().any(|e| e == "hi")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn contains(&self, x: &T) -> bool where T: PartialEq, { - x.slice_contains(self) + cmp::SliceContains::slice_contains(x, self) } /// Returns `true` if `needle` is a prefix of the slice. @@ -2551,26 +2671,11 @@ impl [T] { /// ``` #[stable(feature = "copy_within", since = "1.37.0")] #[track_caller] - pub fn copy_within>(&mut self, src: R, dest: usize) + pub fn copy_within>(&mut self, src: R, dest: usize) where T: Copy, { - let src_start = match src.start_bound() { - ops::Bound::Included(&n) => n, - ops::Bound::Excluded(&n) => { - n.checked_add(1).unwrap_or_else(|| slice_index_overflow_fail()) - } - ops::Bound::Unbounded => 0, - }; - let src_end = match src.end_bound() { - ops::Bound::Included(&n) => { - n.checked_add(1).unwrap_or_else(|| slice_index_overflow_fail()) - } - ops::Bound::Excluded(&n) => n, - ops::Bound::Unbounded => self.len(), - }; - assert!(src_start <= src_end, "src end is before src start"); - assert!(src_end <= self.len(), "src is out of bounds"); + let Range { start: src_start, end: src_end } = check_range(self.len(), src); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, @@ -2958,611 +3063,11 @@ impl [T] { } } -#[lang = "slice_u8"] -#[cfg(not(test))] -impl [u8] { - /// Checks if all bytes in this slice are within the ASCII range. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn is_ascii(&self) -> bool { - is_ascii(self) - } - - /// Checks that two slices are an ASCII case-insensitive match. - /// - /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporaries. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { - self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b)) - } - - /// Converts this slice to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_uppercase(&mut self) { - for byte in self { - byte.make_ascii_uppercase(); - } - } - - /// Converts this slice to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_lowercase(&mut self) { - for byte in self { - byte.make_ascii_lowercase(); - } - } -} - -/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed -/// from `../str/mod.rs`, which does something similar for utf8 validation. -#[inline] -fn contains_nonascii(v: usize) -> bool { - const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; - (NONASCII_MASK & v) != 0 -} - -/// Optimized ASCII test that will use usize-at-a-time operations instead of -/// byte-at-a-time operations (when possible). -/// -/// The algorithm we use here is pretty simple. If `s` is too short, we just -/// check each byte and be done with it. Otherwise: -/// -/// - Read the first word with an unaligned load. -/// - Align the pointer, read subsequent words until end with aligned loads. -/// - Read the last `usize` from `s` with an unaligned load. -/// -/// If any of these loads produces something for which `contains_nonascii` -/// (above) returns true, then we know the answer is false. -#[inline] -fn is_ascii(s: &[u8]) -> bool { - const USIZE_SIZE: usize = mem::size_of::(); - - let len = s.len(); - let align_offset = s.as_ptr().align_offset(USIZE_SIZE); - - // If we wouldn't gain anything from the word-at-a-time implementation, fall - // back to a scalar loop. - // - // We also do this for architectures where `size_of::()` isn't - // sufficient alignment for `usize`, because it's a weird edge case. - if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { - return s.iter().all(|b| b.is_ascii()); - } - - // We always read the first word unaligned, which means `align_offset` is - // 0, we'd read the same value again for the aligned read. - let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; - - let start = s.as_ptr(); - // SAFETY: We verify `len < USIZE_SIZE` above. - let first_word = unsafe { (start as *const usize).read_unaligned() }; - - if contains_nonascii(first_word) { - return false; - } - // We checked this above, somewhat implicitly. Note that `offset_to_aligned` - // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked - // above. - debug_assert!(offset_to_aligned <= len); - - // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the - // middle chunk of the slice. - let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; - - // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. - let mut byte_pos = offset_to_aligned; - - // Paranoia check about alignment, since we're about to do a bunch of - // unaligned loads. In practice this should be impossible barring a bug in - // `align_offset` though. - debug_assert_eq!((word_ptr as usize) % mem::align_of::(), 0); - - // Read subsequent words until the last aligned word, excluding the last - // aligned word by itself to be done in tail check later, to ensure that - // tail is always one `usize` at most to extra branch `byte_pos == len`. - while byte_pos < len - USIZE_SIZE { - debug_assert!( - // Sanity check that the read is in bounds - (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) && - // And that our assumptions about `byte_pos` hold. - (word_ptr as usize) - (start as usize) == byte_pos - ); - - // Safety: We know `word_ptr` is properly aligned (because of - // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end - let word = unsafe { word_ptr.read() }; - if contains_nonascii(word) { - return false; - } - - byte_pos += USIZE_SIZE; - // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that - // after this `add`, `word_ptr` will be at most one-past-the-end. - word_ptr = unsafe { word_ptr.add(1) }; - } - - // Sanity check to ensure there really is only one `usize` left. This should - // be guaranteed by our loop condition. - debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); - - // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. - let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; - - !contains_nonascii(last_word) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for [T] -where - I: SliceIndex<[T]>, -{ - type Output = I::Output; - - #[inline] - fn index(&self, index: I) -> &I::Output { - index.index(self) - } -} - #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for [T] -where - I: SliceIndex<[T]>, -{ - #[inline] - fn index_mut(&mut self, index: I) -> &mut I::Output { - index.index_mut(self) - } -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_start_index_len_fail(index: usize, len: usize) -> ! { - panic!("range start index {} out of range for slice of length {}", index, len); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_end_index_len_fail(index: usize, len: usize) -> ! { - panic!("range end index {} out of range for slice of length {}", index, len); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_index_order_fail(index: usize, end: usize) -> ! { - panic!("slice index starts at {} but ends at {}", index, end); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_index_overflow_fail() -> ! { - panic!("attempted to index slice up to maximum usize"); -} - -mod private_slice_index { - use super::ops; - #[stable(feature = "slice_get_slice", since = "1.28.0")] - pub trait Sealed {} - - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for usize {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::Range {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeTo {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeFrom {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeFull {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeInclusive {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeToInclusive {} -} - -/// A helper trait used for indexing operations. -/// -/// Implementations of this trait have to promise that if the argument -/// to `get_(mut_)unchecked` is a safe reference, then so is the result. -#[stable(feature = "slice_get_slice", since = "1.28.0")] -#[rustc_on_unimplemented( - on(T = "str", label = "string indices are ranges of `usize`",), - on( - all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"), - note = "you can use `.chars().nth()` or `.bytes().nth()` -see chapter in The Book " - ), - message = "the type `{T}` cannot be indexed by `{Self}`", - label = "slice indices are of type `usize` or ranges of `usize`" -)] -pub unsafe trait SliceIndex: private_slice_index::Sealed { - /// The output type returned by methods. - #[stable(feature = "slice_get_slice", since = "1.28.0")] - type Output: ?Sized; - - /// Returns a shared reference to the output at this location, if in - /// bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - fn get(self, slice: &T) -> Option<&Self::Output>; - - /// Returns a mutable reference to the output at this location, if in - /// bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; - - /// Returns a shared reference to the output at this location, without - /// performing any bounds checking. - /// Calling this method with an out-of-bounds index or a dangling `slice` pointer - /// is *[undefined behavior]* even if the resulting reference is not used. - /// - /// [undefined behavior]: ../../reference/behavior-considered-undefined.html - #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; - - /// Returns a mutable reference to the output at this location, without - /// performing any bounds checking. - /// Calling this method with an out-of-bounds index or a dangling `slice` pointer - /// is *[undefined behavior]* even if the resulting reference is not used. - /// - /// [undefined behavior]: ../../reference/behavior-considered-undefined.html - #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; - - /// Returns a shared reference to the output at this location, panicking - /// if out of bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - #[track_caller] - fn index(self, slice: &T) -> &Self::Output; - - /// Returns a mutable reference to the output at this location, panicking - /// if out of bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - #[track_caller] - fn index_mut(self, slice: &mut T) -> &mut Self::Output; -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for usize { - type Output = T; - - #[inline] - fn get(self, slice: &[T]) -> Option<&T> { - // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { - // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { - // 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 { slice.as_ptr().add(self) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { - // SAFETY: see comments for `get_unchecked` above. - unsafe { slice.as_mut_ptr().add(self) } - } - - #[inline] - fn index(self, slice: &[T]) -> &T { - // N.B., use intrinsic indexing - &(*slice)[self] - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut T { - // N.B., use intrinsic indexing - &mut (*slice)[self] - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::Range { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&*self.get_unchecked(slice)) } - } - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&mut *self.get_unchecked_mut(slice)) } - } - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // 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 { 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] { - // SAFETY: see comments for `get_unchecked` above. - unsafe { - ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) - } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { - slice_end_index_len_fail(self.end, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { - slice_end_index_len_fail(self.end, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeTo { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - (0..self.end).get(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - (0..self.end).get_mut(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (0..self.end).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (0..self.end).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - (0..self.end).index(slice) - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - (0..self.end).index_mut(slice) - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFrom { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - (self.start..slice.len()).get(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - (self.start..slice.len()).get_mut(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (self.start..slice.len()).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - if self.start > slice.len() { - slice_start_index_len_fail(self.start, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.start > slice.len() { - slice_start_index_len_fail(self.start, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFull { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - Some(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - Some(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - slice - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - slice - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - slice - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - slice - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeInclusive { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if *self.end() == usize::MAX { - None - } else { - (*self.start()..self.end() + 1).get_mut(slice) - } - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - if *self.end() == usize::MAX { - slice_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index(slice) - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if *self.end() == usize::MAX { - slice_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index_mut(slice) - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - (0..=self.end).get(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - (0..=self.end).get_mut(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (0..=self.end).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (0..=self.end).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - (0..=self.end).index(slice) - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - (0..=self.end).index_mut(slice) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Common traits -//////////////////////////////////////////////////////////////////////////////// - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for &[T] { - /// Creates an empty slice. - fn default() -> Self { - &[] +impl Default for &[T] { + /// Creates an empty slice. + fn default() -> Self { + &[] } } @@ -3573,3240 +3078,3 @@ impl Default for &mut [T] { &mut [] } } - -// -// Iterators -// - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a [T] { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut [T] { - type Item = &'a mut T; - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } -} - -// Macro helper functions -#[inline(always)] -fn size_from_ptr(_: *const T) -> usize { - mem::size_of::() -} - -// Inlining is_empty and len makes a huge performance difference -macro_rules! is_empty { - // The way we encode the length of a ZST iterator, this works both for ZST - // and non-ZST. - ($self: ident) => { - $self.ptr.as_ptr() as *const T == $self.end - }; -} - -// To get rid of some bounds checks (see `position`), we compute the length in a somewhat -// unexpected way. (Tested by `codegen/slice-position-bounds-check`.) -macro_rules! len { - ($self: ident) => {{ - #![allow(unused_unsafe)] // we're sometimes used within an unsafe block - - let start = $self.ptr; - let size = size_from_ptr(start.as_ptr()); - if size == 0 { - // This _cannot_ use `unchecked_sub` because we depend on wrapping - // to represent the length of long ZST slice iterators. - ($self.end as usize).wrapping_sub(start.as_ptr() as usize) - } else { - // We know that `start <= end`, so can do better than `offset_from`, - // which needs to deal in signed. By setting appropriate flags here - // we can tell LLVM this, which helps it remove bounds checks. - // SAFETY: By the type invariant, `start <= end` - let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) }; - // By also telling LLVM that the pointers are apart by an exact - // multiple of the type size, it can optimize `len() == 0` down to - // `start == end` instead of `(end - start) < size`. - // SAFETY: By the type invariant, the pointers are aligned so the - // distance between them must be a multiple of pointee size - unsafe { exact_div(diff, size) } - } - }}; -} - -// The shared definition of the `Iter` and `IterMut` iterators -macro_rules! iterator { - ( - struct $name:ident -> $ptr:ty, - $elem:ty, - $raw_mut:tt, - {$( $mut_:tt )?}, - {$($extra:tt)*} - ) => { - // Returns the first element and moves the start of the iterator forwards by 1. - // Greatly improves performance compared to an inlined function. The iterator - // must not be empty. - macro_rules! next_unchecked { - ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)} - } - - // Returns the last element and moves the end of the iterator backwards by 1. - // Greatly improves performance compared to an inlined function. The iterator - // must not be empty. - macro_rules! next_back_unchecked { - ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)} - } - - // Shrinks the iterator when T is a ZST, by moving the end of the 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; - } - } - - impl<'a, T> $name<'a, T> { - // Helper function for creating a slice from the iterator. - #[inline(always)] - fn make_slice(&self) -> &'a [T] { - // SAFETY: the iterator was created from a slice with pointer - // `self.ptr` and length `len!(self)`. This guarantees that all - // the prerequisites for `from_raw_parts` are fulfilled. - unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) } - } - - // Helper function for moving the start of the iterator forwards by `offset` elements, - // 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 { - if mem::size_of::() == 0 { - zst_shrink!(self, offset); - self.ptr.as_ptr() - } else { - 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)) }; - old - } - } - - // Helper function for moving the end of the iterator backwards by `offset` elements, - // 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 { - if mem::size_of::() == 0 { - zst_shrink!(self, offset); - self.ptr.as_ptr() - } else { - // 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 - } - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl ExactSizeIterator for $name<'_, T> { - #[inline(always)] - fn len(&self) -> usize { - len!(self) - } - - #[inline(always)] - fn is_empty(&self) -> bool { - is_empty!(self) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> Iterator for $name<'a, T> { - type Item = $elem; - - #[inline] - fn next(&mut self) -> Option<$elem> { - // could be implemented with slices, but this avoids bounds checks - - // SAFETY: `assume` calls are safe since a slice's start pointer - // must be non-null, and slices over non-ZSTs must also have a - // non-null end pointer. The call to `next_unchecked!` is safe - // since we check if the iterator is empty first. - unsafe { - assume(!self.ptr.as_ptr().is_null()); - if mem::size_of::() != 0 { - assume(!self.end.is_null()); - } - if is_empty!(self) { - None - } else { - Some(next_unchecked!(self)) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let exact = len!(self); - (exact, Some(exact)) - } - - #[inline] - fn count(self) -> usize { - len!(self) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<$elem> { - if n >= len!(self) { - // This iterator is now empty. - if mem::size_of::() == 0 { - // We have to do it this way as `ptr` may never be 0, but `end` - // could be (due to wrapping). - self.end = self.ptr.as_ptr(); - } else { - // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr - unsafe { - self.ptr = NonNull::new_unchecked(self.end as *mut T); - } - } - return None; - } - // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. - unsafe { - self.post_inc_start(n as isize); - Some(next_unchecked!(self)) - } - } - - #[inline] - fn last(mut self) -> Option<$elem> { - self.next_back() - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn for_each(mut self, mut f: F) - where - Self: Sized, - F: FnMut(Self::Item), - { - while let Some(x) = self.next() { - f(x); - } - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn all(&mut self, mut f: F) -> bool - where - Self: Sized, - F: FnMut(Self::Item) -> bool, - { - while let Some(x) = self.next() { - if !f(x) { - return false; - } - } - true - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn any(&mut self, mut f: F) -> bool - where - Self: Sized, - F: FnMut(Self::Item) -> bool, - { - while let Some(x) = self.next() { - if f(x) { - return true; - } - } - false - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn find

(&mut self, mut predicate: P) -> Option - where - Self: Sized, - P: FnMut(&Self::Item) -> bool, - { - while let Some(x) = self.next() { - if predicate(&x) { - return Some(x); - } - } - None - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn find_map(&mut self, mut f: F) -> Option - where - Self: Sized, - F: FnMut(Self::Item) -> Option, - { - while let Some(x) = self.next() { - if let Some(y) = f(x) { - return Some(y); - } - } - None - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. Also, the `assume` avoids a bounds check. - #[inline] - #[rustc_inherit_overflow_checks] - fn position

(&mut self, mut predicate: P) -> Option where - Self: Sized, - P: FnMut(Self::Item) -> bool, - { - let n = len!(self); - let mut i = 0; - while let Some(x) = self.next() { - if predicate(x) { - // SAFETY: we are guaranteed to be in bounds by the loop invariant: - // when `i >= n`, `self.next()` returns `None` and the loop breaks. - unsafe { assume(i < n) }; - return Some(i); - } - i += 1; - } - None - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. Also, the `assume` avoids a bounds check. - #[inline] - fn rposition

(&mut self, mut predicate: P) -> Option where - P: FnMut(Self::Item) -> bool, - Self: Sized + ExactSizeIterator + DoubleEndedIterator - { - let n = len!(self); - let mut i = n; - while let Some(x) = self.next_back() { - i -= 1; - if predicate(x) { - // SAFETY: `i` must be lower than `n` since it starts at `n` - // and is only decreasing. - unsafe { assume(i < n) }; - return Some(i); - } - } - None - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - // SAFETY: the caller must guarantee that `i` is in bounds of - // the underlying slice, so `i` cannot overflow an `isize`, and - // the returned references is guaranteed to refer to an element - // of the slice and thus guaranteed to be valid. - // - // Also note that the caller also guarantees that we're never - // called with the same index again, and that no other methods - // that will access this subslice are called, so it is valid - // for the returned reference to be mutable in the case of - // `IterMut` - unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) } - } - - $($extra)* - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> DoubleEndedIterator for $name<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<$elem> { - // could be implemented with slices, but this avoids bounds checks - - // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null, - // and slices over non-ZSTs must also have a non-null end pointer. - // The call to `next_back_unchecked!` is safe since we check if the iterator is - // empty first. - unsafe { - assume(!self.ptr.as_ptr().is_null()); - if mem::size_of::() != 0 { - assume(!self.end.is_null()); - } - if is_empty!(self) { - None - } else { - Some(next_back_unchecked!(self)) - } - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option<$elem> { - if n >= len!(self) { - // This iterator is now empty. - self.end = self.ptr.as_ptr(); - return None; - } - // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. - unsafe { - self.pre_dec_end(n as isize); - Some(next_back_unchecked!(self)) - } - } - } - - #[stable(feature = "fused", since = "1.26.0")] - impl FusedIterator for $name<'_, T> {} - - #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl TrustedLen for $name<'_, T> {} - } -} - -/// Immutable slice iterator -/// -/// This struct is created by the [`iter`] method on [slices]. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]): -/// let slice = &[1, 2, 3]; -/// -/// // Then, we iterate over it: -/// for element in slice.iter() { -/// println!("{}", element); -/// } -/// ``` -/// -/// [`iter`]: ../../std/primitive.slice.html#method.iter -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T: 'a> { - ptr: NonNull, - end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that - // ptr == end is a quick test for the Iterator being empty, that works - // for both ZST and non-ZST. - _marker: marker::PhantomData<&'a T>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Iter<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Iter").field(&self.as_slice()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for Iter<'_, T> {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Iter<'_, T> {} - -impl<'a, T> Iter<'a, T> { - /// Views the underlying data as a subslice of the original data. - /// - /// This has the same lifetime as the original slice, and so the - /// iterator can continue to be used while this exists. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // First, we declare a type which has the `iter` method to get the `Iter` - /// // struct (&[usize here]): - /// let slice = &[1, 2, 3]; - /// - /// // Then, we get the iterator: - /// let mut iter = slice.iter(); - /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]": - /// println!("{:?}", iter.as_slice()); - /// - /// // Next, we move to the second element of the slice: - /// iter.next(); - /// // Now `as_slice` returns "[2, 3]": - /// println!("{:?}", iter.as_slice()); - /// ``` - #[stable(feature = "iter_to_slice", since = "1.4.0")] - pub fn as_slice(&self) -> &'a [T] { - self.make_slice() - } -} - -iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, { - fn is_sorted_by(self, mut compare: F) -> bool - where - Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Option, - { - self.as_slice().windows(2).all(|w| { - compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false) - }) - } -}} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Iter<'_, T> { - fn clone(&self) -> Self { - Iter { ptr: self.ptr, end: self.end, _marker: self._marker } - } -} - -#[stable(feature = "slice_iter_as_ref", since = "1.13.0")] -impl AsRef<[T]> for Iter<'_, T> { - fn as_ref(&self) -> &[T] { - self.as_slice() - } -} - -/// Mutable slice iterator. -/// -/// This struct is created by the [`iter_mut`] method on [slices]. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// // First, we declare a type which has `iter_mut` method to get the `IterMut` -/// // struct (&[usize here]): -/// let mut slice = &mut [1, 2, 3]; -/// -/// // Then, we iterate over it and increment each element value: -/// for element in slice.iter_mut() { -/// *element += 1; -/// } -/// -/// // We now have "[2, 3, 4]": -/// println!("{:?}", slice); -/// ``` -/// -/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IterMut<'a, T: 'a> { - ptr: NonNull, - end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that - // ptr == end is a quick test for the Iterator being empty, that works - // for both ZST and non-ZST. - _marker: marker::PhantomData<&'a mut T>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for IterMut<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("IterMut").field(&self.make_slice()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for IterMut<'_, T> {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for IterMut<'_, T> {} - -impl<'a, T> IterMut<'a, T> { - /// Views the underlying data as a subslice of the original data. - /// - /// To avoid creating `&mut` references that alias, this is forced - /// to consume the iterator. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // First, we declare a type which has `iter_mut` method to get the `IterMut` - /// // struct (&[usize here]): - /// let mut slice = &mut [1, 2, 3]; - /// - /// { - /// // Then, we get the iterator: - /// let mut iter = slice.iter_mut(); - /// // We move to next element: - /// iter.next(); - /// // So if we print what `into_slice` method returns here, we have "[2, 3]": - /// println!("{:?}", iter.into_slice()); - /// } - /// - /// // Now let's modify a value of the slice: - /// { - /// // First we get back the iterator: - /// let mut iter = slice.iter_mut(); - /// // We change the value of the first element of the slice returned by the `next` method: - /// *iter.next().unwrap() += 1; - /// } - /// // Now slice is "[2, 2, 3]": - /// println!("{:?}", slice); - /// ``` - #[stable(feature = "iter_to_slice", since = "1.4.0")] - pub fn into_slice(self) -> &'a mut [T] { - // SAFETY: the iterator was created from a mutable slice with pointer - // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites - // for `from_raw_parts_mut` are fulfilled. - unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) } - } - - /// Views the underlying data as a subslice of the original data. - /// - /// To avoid creating `&mut [T]` references that alias, the returned slice - /// borrows its lifetime from the iterator the method is applied on. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// # #![feature(slice_iter_mut_as_slice)] - /// let mut slice: &mut [usize] = &mut [1, 2, 3]; - /// - /// // First, we get the iterator: - /// let mut iter = slice.iter_mut(); - /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]": - /// assert_eq!(iter.as_slice(), &[1, 2, 3]); - /// - /// // Next, we move to the second element of the slice: - /// iter.next(); - /// // Now `as_slice` returns "[2, 3]": - /// assert_eq!(iter.as_slice(), &[2, 3]); - /// ``` - #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")] - pub fn as_slice(&self) -> &[T] { - self.make_slice() - } -} - -iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} - -/// An internal abstraction over the splitting iterators, so that -/// splitn, splitn_mut etc can be implemented once. -#[doc(hidden)] -trait SplitIter: DoubleEndedIterator { - /// Marks the underlying iterator as complete, extracting the remaining - /// portion of the slice. - fn finish(&mut self) -> Option; -} - -/// An iterator over subslices separated by elements that match a predicate -/// function. -/// -/// This struct is created by the [`split`] method on [slices]. -/// -/// [`split`]: ../../std/primitive.slice.html#method.split -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Split<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a [T], - pred: P, - finished: bool, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Split<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Split<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - Split { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().position(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx + 1..]; - ret - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().rposition(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[idx + 1..]); - self.v = &self.v[..idx]; - ret - } - } - } -} - -impl<'a, T, P> SplitIter for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(self.v) - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function. Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [slices]. -/// -/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive -/// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "split_inclusive", issue = "72360")] -pub struct SplitInclusive<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a [T], - pred: P, - finished: bool, -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl fmt::Debug for SplitInclusive<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusive") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_inclusive", issue = "72360")] -impl Clone for SplitInclusive<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - let idx = - self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx..]; - ret - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] }; - let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let ret = Some(&self.v[idx..]); - self.v = &self.v[..idx]; - ret - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. -/// -/// This struct is created by the [`split_mut`] method on [slices]. -/// -/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -impl<'a, T, P> SplitIter for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(mem::replace(&mut self.v, &mut [])) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = &mut tail[1..]; - Some(head) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // if the predicate doesn't match anything, we yield one slice - // if it matches every element, we yield len+1 empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().rposition(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(&mut tail[1..]) - } - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched -/// parts in the ends of the subslices. -/// -/// This struct is created by the [`split_inclusive_mut`] method on [slices]. -/// -/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut -/// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "split_inclusive", issue = "72360")] -pub struct SplitInclusiveMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl fmt::Debug for SplitInclusiveMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusiveMut") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = tail; - Some(head) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // if the predicate doesn't match anything, we yield one slice - // if it matches every element, we yield len+1 empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = if self.v.is_empty() { - None - } else { - // work around borrowck limitations - let pred = &mut self.pred; - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = &self.v[..(self.v.len() - 1)]; - remainder.iter().rposition(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(tail) - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit`] method on [slices]. -/// -/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "slice_rsplit", since = "1.27.0")] -#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? -pub struct RSplit<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: Split<'a, T, P>, -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplit<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplit") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - self.inner.next_back() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - self.inner.next() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - self.inner.finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the subslices of the vector which are separated -/// by elements that match `pred`, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit_mut`] method on [slices]. -/// -/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "slice_rsplit", since = "1.27.0")] -pub struct RSplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: SplitMut<'a, T, P>, -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitMut") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - self.inner.finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - self.inner.next_back() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - self.inner.next() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An private iterator over subslices separated by elements that -/// match a predicate function, splitting at most a fixed number of -/// times. -#[derive(Debug)] -struct GenericSplitN { - iter: I, - count: usize, -} - -impl> Iterator for GenericSplitN { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - match self.count { - 0 => None, - 1 => { - self.count -= 1; - self.iter.finish() - } - _ => { - self.count -= 1; - self.iter.next() - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper_opt) = self.iter.size_hint(); - (lower, upper_opt.map(|upper| cmp::min(self.count, upper))) - } -} - -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn`] method on [slices]. -/// -/// [`splitn`]: ../../std/primitive.slice.html#method.splitn -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitN").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn`] method on [slices]. -/// -/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RSplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitN").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn_mut`] method on [slices]. -/// -/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitNMut").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn_mut`] method on [slices]. -/// -/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RSplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitNMut").field("inner", &self.inner).finish() - } -} - -macro_rules! forward_iterator { - ($name:ident: $elem:ident, $iter_of:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, $elem, P> Iterator for $name<'a, $elem, P> - where - P: FnMut(&T) -> bool, - { - type Item = $iter_of; - - #[inline] - fn next(&mut self) -> Option<$iter_of> { - self.inner.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - } - - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} - }; -} - -forward_iterator! { SplitN: T, &'a [T] } -forward_iterator! { RSplitN: T, &'a [T] } -forward_iterator! { SplitNMut: T, &'a mut [T] } -forward_iterator! { RSplitNMut: T, &'a mut [T] } - -/// An iterator over overlapping subslices of length `size`. -/// -/// This struct is created by the [`windows`] method on [slices]. -/// -/// [`windows`]: ../../std/primitive.slice.html#method.windows -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Windows<'a, T: 'a> { - v: &'a [T], - size: usize, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Windows<'_, T> { - fn clone(&self) -> Self { - Windows { v: self.v, size: self.size } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Windows<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.size > self.v.len() { - None - } else { - let ret = Some(&self.v[..self.size]); - self.v = &self.v[1..]; - ret - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.size > self.v.len() { - (0, Some(0)) - } else { - let size = self.v.len() - self.size + 1; - (size, Some(size)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = self.size.overflowing_add(n); - if end > self.v.len() || overflow { - self.v = &[]; - None - } else { - let nth = &self.v[n..end]; - self.v = &self.v[n + 1..]; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.size > self.v.len() { - None - } else { - let start = self.v.len() - self.size; - Some(&self.v[start..]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - // SAFETY: since the caller guarantees that `i` is in bounds, - // which means that `i` cannot overflow an `isize`, and the - // slice created by `from_raw_parts` is a subslice of `self.v` - // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Windows<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.size > self.v.len() { - None - } else { - let ret = Some(&self.v[self.v.len() - self.size..]); - self.v = &self.v[..self.v.len() - 1]; - ret - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let (end, overflow) = self.v.len().overflowing_sub(n); - if end < self.size || overflow { - self.v = &[]; - None - } else { - let ret = &self.v[end - self.size..end]; - self.v = &self.v[..end - 1]; - Some(ret) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Windows<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Windows<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Windows<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`chunks`] method on [slices]. -/// -/// [`chunks`]: ../../std/primitive.slice.html#method.chunks -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Chunks<'a, T: 'a> { - v: &'a [T], - chunk_size: usize, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Chunks<'_, T> { - fn clone(&self) -> Self { - Chunks { v: self.v, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Chunks<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let chunksz = cmp::min(self.v.len(), self.chunk_size); - let (fst, snd) = self.v.split_at(chunksz); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let end = match start.checked_add(self.chunk_size) { - Some(sum) => cmp::min(self.v.len(), sum), - None => self.v.len(), - }; - let nth = &self.v[start..end]; - self.v = &self.v[end..]; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; - Some(&self.v[start..]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; - // SAFETY: the caller guarantees that `i` is in bounds, - // which means that `start` must be in bounds of the - // underlying `self.v` slice, and we made sure that `end` - // is also in bounds of `self.v`. Thus, `start` cannot overflow - // an `isize`, and the slice constructed by `from_raw_parts` - // is a subslice of `self.v` which is guaranteed to be valid - // for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; - let (fst, snd) = self.v.split_at(self.v.len() - chunksz); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), - None => self.v.len(), - }; - let nth_back = &self.v[start..end]; - self.v = &self.v[..start]; - Some(nth_back) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Chunks<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Chunks<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Chunks<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`chunks_mut`] method on [slices]. -/// -/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct ChunksMut<'a, T: 'a> { - v: &'a mut [T], - chunk_size: usize, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for ChunksMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let sz = cmp::min(self.v.len(), self.chunk_size); - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(sz); - self.v = tail; - Some(head) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let end = match start.checked_add(self.chunk_size) { - Some(sum) => cmp::min(self.v.len(), sum), - None => self.v.len(), - }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(end); - let (_, nth) = head.split_at_mut(start); - self.v = tail; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; - Some(&mut self.v[start..]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; - // SAFETY: see comments for `Chunks::get_unchecked`. - // - // Also note that the caller also guarantees that we're never called - // with the same index again, and that no other methods that will - // access this subslice are called, so it is valid for the returned - // slice to be mutable. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let sz = if remainder != 0 { remainder } else { self.chunk_size }; - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - sz); - self.v = head; - Some(tail) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), - None => self.v.len(), - }; - let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (head, nth_back) = temp.split_at_mut(start); - self.v = head; - Some(nth_back) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for ChunksMut<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ChunksMut<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for ChunksMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted but can be retrieved from -/// the [`remainder`] function from the iterator. -/// -/// This struct is created by the [`chunks_exact`] method on [slices]. -/// -/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact -/// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "chunks_exact", since = "1.31.0")] -pub struct ChunksExact<'a, T: 'a> { - v: &'a [T], - rem: &'a [T], - chunk_size: usize, -} - -impl<'a, T> ChunksExact<'a, T> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` - /// elements. - #[stable(feature = "chunks_exact", since = "1.31.0")] - pub fn remainder(&self) -> &'a [T] { - self.rem - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl Clone for ChunksExact<'_, T> { - fn clone(&self) -> Self { - ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> Iterator for ChunksExact<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.chunk_size); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let (_, snd) = self.v.split_at(start); - self.v = snd; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - // SAFETY: mostly identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = start + self.chunk_size; - let nth_back = &self.v[start..end]; - self.v = &self.v[..start]; - Some(nth_back) - } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl ExactSizeIterator for ChunksExact<'_, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ChunksExact<'_, T> {} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl FusedIterator for ChunksExact<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last up to -/// `chunk_size-1` elements will be omitted but can be retrieved from the -/// [`into_remainder`] function from the iterator. -/// -/// This struct is created by the [`chunks_exact_mut`] method on [slices]. -/// -/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut -/// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "chunks_exact", since = "1.31.0")] -pub struct ChunksExactMut<'a, T: 'a> { - v: &'a mut [T], - rem: &'a mut [T], - chunk_size: usize, -} - -impl<'a, T> ChunksExactMut<'a, T> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` - /// elements. - #[stable(feature = "chunks_exact", since = "1.31.0")] - pub fn into_remainder(self) -> &'a mut [T] { - self.rem - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> Iterator for ChunksExactMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(self.chunk_size); - self.v = tail; - Some(head) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (_, snd) = tmp.split_at_mut(start); - self.v = snd; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - // SAFETY: see comments for `ChunksMut::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); - self.v = head; - Some(tail) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = start + self.chunk_size; - let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (head, nth_back) = temp.split_at_mut(start); - self.v = head; - Some(nth_back) - } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl ExactSizeIterator for ChunksExactMut<'_, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ChunksExactMut<'_, T> {} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl FusedIterator for ChunksExactMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a -/// time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted but can be retrieved from -/// the [`remainder`] function from the iterator. -/// -/// This struct is created by the [`array_chunks`] method on [slices]. -/// -/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks -/// [`remainder`]: ../../std/slice/struct.ArrayChunks.html#method.remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[unstable(feature = "array_chunks", issue = "74985")] -pub struct ArrayChunks<'a, T: 'a, const N: usize> { - iter: Iter<'a, [T; N]>, - rem: &'a [T], -} - -impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` - /// elements. - #[unstable(feature = "array_chunks", issue = "74985")] - pub fn remainder(&self) -> &'a [T] { - self.rem - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "array_chunks", issue = "74985")] -impl Clone for ArrayChunks<'_, T, N> { - fn clone(&self) -> Self { - ArrayChunks { iter: self.iter.clone(), rem: self.rem } - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { - type Item = &'a [T; N]; - - #[inline] - fn next(&mut self) -> Option<&'a [T; N]> { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - self.iter.nth(n) - } - - #[inline] - fn last(self) -> Option { - self.iter.last() - } - - unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] { - // SAFETY: The safety guarantees of `get_unchecked` are transferred to - // the caller. - unsafe { self.iter.__iterator_get_unchecked(i) } - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T; N]> { - self.iter.next_back() - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - self.iter.nth_back(n) - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl ExactSizeIterator for ArrayChunks<'_, T, N> { - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ArrayChunks<'_, T, N> {} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl FusedIterator for ArrayChunks<'_, T, N> {} - -#[doc(hidden)] -#[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`rchunks`] method on [slices]. -/// -/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunks<'a, T: 'a> { - v: &'a [T], - chunk_size: usize, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rchunks", since = "1.31.0")] -impl Clone for RChunks<'_, T> { - fn clone(&self) -> Self { - RChunks { v: self.v, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunks<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let chunksz = cmp::min(self.v.len(), self.chunk_size); - let (fst, snd) = self.v.split_at(self.v.len() - chunksz); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &[]; - None - } else { - // Can't underflow because of the check above - let end = self.v.len() - end; - let start = match end.checked_sub(self.chunk_size) { - Some(sum) => sum, - None => 0, - }; - let nth = &self.v[start..end]; - self.v = &self.v[0..start]; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let rem = self.v.len() % self.chunk_size; - let end = if rem == 0 { self.chunk_size } else { rem }; - Some(&self.v[0..end]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; - // SAFETY: mostly identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; - let (fst, snd) = self.v.split_at(chunksz); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - // can't underflow because `n < len` - let offset_from_end = (len - 1 - n) * self.chunk_size; - let end = self.v.len() - offset_from_end; - let start = end.saturating_sub(self.chunk_size); - let nth_back = &self.v[start..end]; - self.v = &self.v[end..]; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl ExactSizeIterator for RChunks<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunks<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunks<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`rchunks_mut`] method on [slices]. -/// -/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunksMut<'a, T: 'a> { - v: &'a mut [T], - chunk_size: usize, -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunksMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let sz = cmp::min(self.v.len(), self.chunk_size); - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - sz); - self.v = head; - Some(tail) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - // Can't underflow because of the check above - let end = self.v.len() - end; - let start = match end.checked_sub(self.chunk_size) { - Some(sum) => sum, - None => 0, - }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(start); - let (nth, _) = tail.split_at_mut(end - start); - self.v = head; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let rem = self.v.len() % self.chunk_size; - let end = if rem == 0 { self.chunk_size } else { rem }; - Some(&mut self.v[0..end]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; - // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked` - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let sz = if remainder != 0 { remainder } else { self.chunk_size }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(sz); - self.v = tail; - Some(head) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - // can't underflow because `n < len` - let offset_from_end = (len - 1 - n) * self.chunk_size; - let end = self.v.len() - offset_from_end; - let start = end.saturating_sub(self.chunk_size); - let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (_, nth_back) = tmp.split_at_mut(start); - self.v = tail; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl ExactSizeIterator for RChunksMut<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunksMut<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunksMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted but can be retrieved from -/// the [`remainder`] function from the iterator. -/// -/// This struct is created by the [`rchunks_exact`] method on [slices]. -/// -/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact -/// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunksExact<'a, T: 'a> { - v: &'a [T], - rem: &'a [T], - chunk_size: usize, -} - -impl<'a, T> RChunksExact<'a, T> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` - /// elements. - #[stable(feature = "rchunks", since = "1.31.0")] - pub fn remainder(&self) -> &'a [T] { - self.rem - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Clone for RChunksExact<'a, T> { - fn clone(&self) -> RChunksExact<'a, T> { - RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunksExact<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let (fst, _) = self.v.split_at(self.v.len() - end); - self.v = fst; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = end - self.chunk_size; - // SAFETY: - // SAFETY: mostmy identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.chunk_size); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - // now that we know that `n` corresponds to a chunk, - // none of these operations can underflow/overflow - let offset = (len - n) * self.chunk_size; - let start = self.v.len() - offset; - let end = start + self.chunk_size; - let nth_back = &self.v[start..end]; - self.v = &self.v[end..]; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunksExact<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunksExact<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last up to -/// `chunk_size-1` elements will be omitted but can be retrieved from the -/// [`into_remainder`] function from the iterator. -/// -/// This struct is created by the [`rchunks_exact_mut`] method on [slices]. -/// -/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut -/// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunksExactMut<'a, T: 'a> { - v: &'a mut [T], - rem: &'a mut [T], - chunk_size: usize, -} - -impl<'a, T> RChunksExactMut<'a, T> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` - /// elements. - #[stable(feature = "rchunks", since = "1.31.0")] - pub fn into_remainder(self) -> &'a mut [T] { - self.rem - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunksExactMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); - self.v = head; - Some(tail) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (fst, _) = tmp.split_at_mut(tmp_len - end); - self.v = fst; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = end - self.chunk_size; - // SAFETY: see comments for `RChunksMut::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(self.chunk_size); - self.v = tail; - Some(head) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - // now that we know that `n` corresponds to a chunk, - // none of these operations can underflow/overflow - let offset = (len - n) * self.chunk_size; - let start = self.v.len() - offset; - let end = start + self.chunk_size; - let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (_, nth_back) = tmp.split_at_mut(start); - self.v = tail; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl ExactSizeIterator for RChunksExactMut<'_, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunksExactMut<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunksExactMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -// -// Free functions -// - -/// Forms a slice from a pointer and a length. -/// -/// The `len` argument is the number of **elements**, not the number of bytes. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `data` must be [valid] for reads for `len * mem::size_of::()` many bytes, -/// and it must be properly aligned. This means in particular: -/// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) -/// for an example incorrectly not taking this into account. -/// * `data` must be non-null and aligned even for zero-length slices. One -/// reason for this is that enum layout optimizations may rely on references -/// (including slices of any length) being aligned and non-null to distinguish -/// them from other data. You can obtain a pointer that is usable as `data` -/// for zero-length slices using [`NonNull::dangling()`]. -/// -/// * The memory referenced by the returned slice must not be mutated for the duration -/// of lifetime `'a`, except inside an `UnsafeCell`. -/// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. -/// See the safety documentation of [`pointer::offset`]. -/// -/// # Caveat -/// -/// The lifetime for the returned slice is inferred from its usage. To -/// prevent accidental misuse, it's suggested to tie the lifetime to whichever -/// source lifetime is safe in the context, such as by providing a helper -/// function taking the lifetime of a host value for the slice, or by explicit -/// annotation. -/// -/// # Examples -/// -/// ``` -/// use std::slice; -/// -/// // manifest a slice for a single element -/// let x = 42; -/// let ptr = &x as *const _; -/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; -/// assert_eq!(slice[0], 42); -/// ``` -/// -/// ### Incorrect usage -/// -/// The following `join_slices` function is **unsound** ⚠️ -/// -/// ```rust,no_run -/// use std::slice; -/// -/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { -/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); -/// let snd_start = snd.as_ptr(); -/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); -/// unsafe { -/// // The assertion above ensures `fst` and `snd` are contiguous, but they might -/// // still be contained within _different allocated objects_, in which case -/// // creating this slice is undefined behavior. -/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) -/// } -/// } -/// -/// fn main() { -/// // `a` and `b` are different allocated objects... -/// let a = 42; -/// let b = 27; -/// // ... which may nevertheless be laid out contiguously in memory: | a | b | -/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB -/// } -/// ``` -/// -/// [valid]: ../../std/ptr/index.html#safety -/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling -/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { - debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); - debug_assert!( - mem::size_of::().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering at least half the address space" - ); - // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. - unsafe { &*ptr::slice_from_raw_parts(data, len) } -} - -/// Performs the same functionality as [`from_raw_parts`], except that a -/// mutable slice is returned. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::()` many bytes, -/// and it must be properly aligned. This means in particular: -/// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. -/// * `data` must be non-null and aligned even for zero-length slices. One -/// reason for this is that enum layout optimizations may rely on references -/// (including slices of any length) being aligned and non-null to distinguish -/// them from other data. You can obtain a pointer that is usable as `data` -/// for zero-length slices using [`NonNull::dangling()`]. -/// -/// * The memory referenced by the returned slice must not be accessed through any other pointer -/// (not derived from the return value) for the duration of lifetime `'a`. -/// Both read and write accesses are forbidden. -/// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. -/// See the safety documentation of [`pointer::offset`]. -/// -/// [valid]: ../../std/ptr/index.html#safety -/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling -/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset -/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { - debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); - debug_assert!( - mem::size_of::().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering at least half the address space" - ); - // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. - unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) } -} - -/// Converts a reference to T into a slice of length 1 (without copying). -#[stable(feature = "from_ref", since = "1.28.0")] -pub fn from_ref(s: &T) -> &[T] { - // SAFETY: a reference is guaranteed to be valid for reads. The returned - // reference cannot be mutated as it is an immutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts` is safe. - unsafe { from_raw_parts(s, 1) } -} - -/// Converts a reference to T into a slice of length 1 (without copying). -#[stable(feature = "from_ref", since = "1.28.0")] -pub fn from_mut(s: &mut T) -> &mut [T] { - // SAFETY: a mutable reference is guaranteed to be valid for writes. - // The reference cannot be accessed by another pointer as it is an mutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts_mut` is safe. - unsafe { from_raw_parts_mut(s, 1) } -} - -// This function is public only because there is no other way to unit test heapsort. -#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] -#[doc(hidden)] -pub fn heapsort(v: &mut [T], mut is_less: F) -where - F: FnMut(&T, &T) -> bool, -{ - sort::heapsort(v, &mut is_less); -} - -// -// Comparison traits -// - -extern "C" { - /// Calls implementation provided memcmp. - /// - /// Interprets the data as u8. - /// - /// Returns 0 for equal, < 0 for less than and > 0 for greater - /// than. - // FIXME(#32610): Return type should be c_int - fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[B]> for [A] -where - A: PartialEq, -{ - fn eq(&self, other: &[B]) -> bool { - SlicePartialEq::equal(self, other) - } - - fn ne(&self, other: &[B]) -> bool { - SlicePartialEq::not_equal(self, other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for [T] {} - -/// Implements comparison of vectors lexicographically. -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for [T] { - fn cmp(&self, other: &[T]) -> Ordering { - SliceOrd::compare(self, other) - } -} - -/// Implements comparison of vectors lexicographically. -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for [T] { - fn partial_cmp(&self, other: &[T]) -> Option { - SlicePartialOrd::partial_compare(self, other) - } -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's PartialEq -trait SlicePartialEq { - fn equal(&self, other: &[B]) -> bool; - - fn not_equal(&self, other: &[B]) -> bool { - !self.equal(other) - } -} - -// Generic slice equality -impl SlicePartialEq for [A] -where - A: PartialEq, -{ - default fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - self.iter().zip(other.iter()).all(|(x, y)| x == y) - } -} - -// Use an equal-pointer optimization when types are `Eq` -// We can't make `A` and `B` the same type because `min_specialization` won't -// allow it. -impl SlicePartialEq for [A] -where - A: MarkerEq, -{ - default fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - // While performance would suffer if `guaranteed_eq` just returned `false` - // for all arguments, correctness and return value of this function are not affected. - if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { - return true; - } - - self.iter().zip(other.iter()).all(|(x, y)| x == y) - } -} - -// Use memcmp for bytewise equality when the types allow -impl SlicePartialEq for [A] -where - A: BytewiseEquality, -{ - fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - // While performance would suffer if `guaranteed_eq` just returned `false` - // for all arguments, correctness and return value of this function are not affected. - if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { - return true; - } - // SAFETY: `self` and `other` are references and are thus guaranteed to be valid. - // The two slices have been checked to have the same size above. - unsafe { - let size = mem::size_of_val(self); - memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 - } - } -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's PartialOrd -trait SlicePartialOrd: Sized { - fn partial_compare(left: &[Self], right: &[Self]) -> Option; -} - -impl SlicePartialOrd for A { - default fn partial_compare(left: &[A], right: &[A]) -> Option { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].partial_cmp(&rhs[i]) { - Some(Ordering::Equal) => (), - non_eq => return non_eq, - } - } - - left.len().partial_cmp(&right.len()) - } -} - -// This is the impl that we would like to have. Unfortunately it's not sound. -// See `partial_ord_slice.rs`. -/* -impl SlicePartialOrd for A -where - A: Ord, -{ - default fn partial_compare(left: &[A], right: &[A]) -> Option { - Some(SliceOrd::compare(left, right)) - } -} -*/ - -impl SlicePartialOrd for A { - fn partial_compare(left: &[A], right: &[A]) -> Option { - Some(SliceOrd::compare(left, right)) - } -} - -#[rustc_specialization_trait] -trait AlwaysApplicableOrd: SliceOrd + Ord {} - -macro_rules! always_applicable_ord { - ($([$($p:tt)*] $t:ty,)*) => { - $(impl<$($p)*> AlwaysApplicableOrd for $t {})* - } -} - -always_applicable_ord! { - [] u8, [] u16, [] u32, [] u64, [] u128, [] usize, - [] i8, [] i16, [] i32, [] i64, [] i128, [] isize, - [] bool, [] char, - [T: ?Sized] *const T, [T: ?Sized] *mut T, - [T: AlwaysApplicableOrd] &T, - [T: AlwaysApplicableOrd] &mut T, - [T: AlwaysApplicableOrd] Option, -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's Ord -trait SliceOrd: Sized { - fn compare(left: &[Self], right: &[Self]) -> Ordering; -} - -impl SliceOrd for A { - default fn compare(left: &[Self], right: &[Self]) -> Ordering { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].cmp(&rhs[i]) { - Ordering::Equal => (), - non_eq => return non_eq, - } - } - - left.len().cmp(&right.len()) - } -} - -// memcmp compares a sequence of unsigned bytes lexicographically. -// this matches the order we want for [u8], but no others (not even [i8]). -impl SliceOrd for u8 { - #[inline] - fn compare(left: &[Self], right: &[Self]) -> Ordering { - let order = - // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. - // We use the minimum of both lengths which guarantees that both regions are - // valid for reads in that interval. - unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) }; - if order == 0 { - left.len().cmp(&right.len()) - } else if order < 0 { - Less - } else { - Greater - } - } -} - -// Hack to allow specializing on `Eq` even though `Eq` has a method. -#[rustc_unsafe_specialization_marker] -trait MarkerEq: PartialEq {} - -impl MarkerEq for T {} - -#[doc(hidden)] -/// Trait implemented for types that can be compared for equality using -/// their bytewise representation -#[rustc_specialization_trait] -trait BytewiseEquality: MarkerEq + Copy {} - -macro_rules! impl_marker_for { - ($traitname:ident, $($ty:ty)*) => { - $( - impl $traitname<$ty> for $ty { } - )* - } -} - -impl_marker_for!(BytewiseEquality, - u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -trait SliceContains: Sized { - fn slice_contains(&self, x: &[Self]) -> bool; -} - -impl SliceContains for T -where - T: PartialEq, -{ - default fn slice_contains(&self, x: &[Self]) -> bool { - x.iter().any(|y| *y == *self) - } -} - -impl SliceContains for u8 { - fn slice_contains(&self, x: &[Self]) -> bool { - memchr::memchr(*self, x).is_some() - } -} - -impl SliceContains for i8 { - fn slice_contains(&self, x: &[Self]) -> bool { - let byte = *self as u8; - // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()` - // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed - // to be valid for reads for the length of the slice `x.len()`, which cannot be larger - // than `isize::MAX`. The returned slice is never mutated. - let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) }; - memchr::memchr(byte, bytes).is_some() - } -} diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs new file mode 100644 index 0000000000..09209306c9 --- /dev/null +++ b/library/core/src/slice/raw.rs @@ -0,0 +1,151 @@ +//! Free functions to create `&[T]` and `&mut [T]`. + +use crate::array; +use crate::intrinsics::is_aligned_and_not_null; +use crate::mem; +use crate::ptr; + +/// Forms a slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be [valid] for reads for `len * mem::size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// use std::slice; +/// +/// // manifest a slice for a single element +/// let x = 42; +/// let ptr = &x as *const _; +/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; +/// assert_eq!(slice[0], 42); +/// ``` +/// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocated objects_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocated objects... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); + debug_assert!( + mem::size_of::().saturating_mul(len) <= isize::MAX as usize, + "attempt to create slice covering at least half the address space" + ); + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { &*ptr::slice_from_raw_parts(data, len) } +} + +/// Performs the same functionality as [`from_raw_parts`], except that a +/// mutable slice is returned. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); + debug_assert!( + mem::size_of::().saturating_mul(len) <= isize::MAX as usize, + "attempt to create slice covering at least half the address space" + ); + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) } +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_ref(s: &T) -> &[T] { + array::from_ref(s) +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_mut(s: &mut T) -> &mut [T] { + array::from_mut(s) +} diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 972a33d648..71d2c2c9b2 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -180,7 +180,8 @@ where /// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case. #[cold] -pub fn heapsort(v: &mut [T], is_less: &mut F) +#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] +pub fn heapsort(v: &mut [T], mut is_less: F) where F: FnMut(&T, &T) -> bool, { @@ -299,8 +300,8 @@ where if start_l == end_l { // Trace `block_l` elements from the left side. - start_l = MaybeUninit::first_ptr_mut(&mut offsets_l); - end_l = MaybeUninit::first_ptr_mut(&mut offsets_l); + start_l = MaybeUninit::slice_as_mut_ptr(&mut offsets_l); + end_l = MaybeUninit::slice_as_mut_ptr(&mut offsets_l); let mut elem = l; for i in 0..block_l { @@ -325,8 +326,8 @@ where if start_r == end_r { // Trace `block_r` elements from the right side. - start_r = MaybeUninit::first_ptr_mut(&mut offsets_r); - end_r = MaybeUninit::first_ptr_mut(&mut offsets_r); + start_r = MaybeUninit::slice_as_mut_ptr(&mut offsets_r); + end_r = MaybeUninit::slice_as_mut_ptr(&mut offsets_r); let mut elem = r; for i in 0..block_r { @@ -564,7 +565,7 @@ fn break_patterns(v: &mut [T]) { random }; let mut gen_usize = || { - if mem::size_of::() <= 4 { + if usize::BITS <= 32 { gen_u32() as usize } else { (((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize @@ -666,7 +667,7 @@ where /// /// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero, /// this function will immediately switch to heapsort. -fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: usize) +fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: u32) where F: FnMut(&T, &T) -> bool, { @@ -762,7 +763,7 @@ where } // Limit the number of imbalanced partitions to `floor(log2(len)) + 1`. - let limit = mem::size_of::() * 8 - v.len().leading_zeros() as usize; + let limit = usize::BITS - v.len().leading_zeros(); recurse(v, &mut is_less, None, limit); } diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs new file mode 100644 index 0000000000..de2a93f735 --- /dev/null +++ b/library/core/src/str/converts.rs @@ -0,0 +1,192 @@ +//! Ways to create a `str` from bytes slice. + +use crate::mem; + +use super::validations::run_utf8_validation; +use super::Utf8Error; + +/// Converts a slice of bytes to a string slice. +/// +/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice +/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between +/// the two. Not all byte slices are valid string slices, however: [`&str`] requires +/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid +/// UTF-8, and then does the conversion. +/// +/// [`&str`]: str +/// [byteslice]: ../../std/primitive.slice.html +/// +/// If you are sure that the byte slice is valid UTF-8, and you don't want to +/// incur the overhead of the validity check, there is an unsafe version of +/// this function, [`from_utf8_unchecked`], which has the same +/// behavior but skips the check. +/// +/// If you need a `String` instead of a `&str`, consider +/// [`String::from_utf8`][string]. +/// +/// [string]: ../../std/string/struct.String.html#method.from_utf8 +/// +/// Because you can stack-allocate a `[u8; N]`, and you can take a +/// [`&[u8]`][byteslice] of it, this function is one way to have a +/// stack-allocated string. There is an example of this in the +/// examples section below. +/// +/// [byteslice]: ../../std/primitive.slice.html +/// +/// # Errors +/// +/// Returns `Err` if the slice is not UTF-8 with a description as to why the +/// provided slice is not UTF-8. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// // some bytes, in a vector +/// let sparkle_heart = vec![240, 159, 146, 150]; +/// +/// // We know these bytes are valid, so just use `unwrap()`. +/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` +/// +/// Incorrect bytes: +/// +/// ``` +/// use std::str; +/// +/// // some invalid bytes, in a vector +/// let sparkle_heart = vec![0, 159, 146, 150]; +/// +/// assert!(str::from_utf8(&sparkle_heart).is_err()); +/// ``` +/// +/// See the docs for [`Utf8Error`] for more details on the kinds of +/// errors that can be returned. +/// +/// A "stack allocated string": +/// +/// ``` +/// use std::str; +/// +/// // some bytes, in a stack-allocated array +/// let sparkle_heart = [240, 159, 146, 150]; +/// +/// // We know these bytes are valid, so just use `unwrap()`. +/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { + run_utf8_validation(v)?; + // SAFETY: Just ran validation. + Ok(unsafe { from_utf8_unchecked(v) }) +} + +/// Converts a mutable slice of bytes to a mutable string slice. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// // "Hello, Rust!" as a mutable vector +/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33]; +/// +/// // As we know these bytes are valid, we can use `unwrap()` +/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap(); +/// +/// assert_eq!("Hello, Rust!", outstr); +/// ``` +/// +/// Incorrect bytes: +/// +/// ``` +/// use std::str; +/// +/// // Some invalid bytes in a mutable vector +/// let mut invalid = vec![128, 223]; +/// +/// assert!(str::from_utf8_mut(&mut invalid).is_err()); +/// ``` +/// See the docs for [`Utf8Error`] for more details on the kinds of +/// errors that can be returned. +#[stable(feature = "str_mut_extras", since = "1.20.0")] +pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { + run_utf8_validation(v)?; + // SAFETY: Just ran validation. + Ok(unsafe { from_utf8_unchecked_mut(v) }) +} + +/// Converts a slice of bytes to a string slice without checking +/// that the string contains valid UTF-8. +/// +/// See the safe version, [`from_utf8`], for more information. +/// +/// # Safety +/// +/// This function is unsafe because it does not check that the bytes passed to +/// it are valid UTF-8. If this constraint is violated, undefined behavior +/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8. +/// +/// [`&str`]: str +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// // some bytes, in a vector +/// let sparkle_heart = vec![240, 159, 146, 150]; +/// +/// let sparkle_heart = unsafe { +/// str::from_utf8_unchecked(&sparkle_heart) +/// }; +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")] +#[allow_internal_unstable(const_fn_transmute)] +pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { + // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. + // Also relies on `&str` and `&[u8]` having the same layout. + unsafe { mem::transmute(v) } +} + +/// Converts a slice of bytes to a string slice without checking +/// that the string contains valid UTF-8; mutable version. +/// +/// See the immutable version, [`from_utf8_unchecked()`] for more information. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// let mut heart = vec![240, 159, 146, 150]; +/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) }; +/// +/// assert_eq!("💖", heart); +/// ``` +#[inline] +#[stable(feature = "str_mut_extras", since = "1.20.0")] +pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { + // SAFETY: the caller must guarantee that the bytes `v` + // are valid UTF-8, thus the cast to `*mut str` is safe. + // Also, the pointer dereference is safe because that pointer + // comes from a reference which is guaranteed to be valid for writes. + unsafe { &mut *(v as *mut [u8] as *mut str) } +} diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs new file mode 100644 index 0000000000..427f720d68 --- /dev/null +++ b/library/core/src/str/error.rs @@ -0,0 +1,129 @@ +//! Defines utf8 error type. + +use crate::fmt; + +/// Errors which can occur when attempting to interpret a sequence of [`u8`] +/// as a string. +/// +/// As such, the `from_utf8` family of functions and methods for both [`String`]s +/// and [`&str`]s make use of this error, for example. +/// +/// [`String`]: ../../std/string/struct.String.html#method.from_utf8 +/// [`&str`]: super::from_utf8 +/// +/// # Examples +/// +/// This error type’s methods can be used to create functionality +/// similar to `String::from_utf8_lossy` without allocating heap memory: +/// +/// ``` +/// fn from_utf8_lossy(mut input: &[u8], mut push: F) where F: FnMut(&str) { +/// loop { +/// match std::str::from_utf8(input) { +/// Ok(valid) => { +/// push(valid); +/// break +/// } +/// Err(error) => { +/// let (valid, after_valid) = input.split_at(error.valid_up_to()); +/// unsafe { +/// push(std::str::from_utf8_unchecked(valid)) +/// } +/// push("\u{FFFD}"); +/// +/// if let Some(invalid_sequence_length) = error.error_len() { +/// input = &after_valid[invalid_sequence_length..] +/// } else { +/// break +/// } +/// } +/// } +/// } +/// } +/// ``` +#[derive(Copy, Eq, PartialEq, Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Utf8Error { + pub(super) valid_up_to: usize, + pub(super) error_len: Option, +} + +impl Utf8Error { + /// Returns the index in the given string up to which valid UTF-8 was + /// verified. + /// + /// It is the maximum index such that `from_utf8(&input[..index])` + /// would return `Ok(_)`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// // some invalid bytes, in a vector + /// let sparkle_heart = vec![0, 159, 146, 150]; + /// + /// // std::str::from_utf8 returns a Utf8Error + /// let error = str::from_utf8(&sparkle_heart).unwrap_err(); + /// + /// // the second byte is invalid here + /// assert_eq!(1, error.valid_up_to()); + /// ``` + #[stable(feature = "utf8_error", since = "1.5.0")] + pub fn valid_up_to(&self) -> usize { + self.valid_up_to + } + + /// Provides more information about the failure: + /// + /// * `None`: the end of the input was reached unexpectedly. + /// `self.valid_up_to()` is 1 to 3 bytes from the end of the input. + /// If a byte stream (such as a file or a network socket) is being decoded incrementally, + /// this could be a valid `char` whose UTF-8 byte sequence is spanning multiple chunks. + /// + /// * `Some(len)`: an unexpected byte was encountered. + /// The length provided is that of the invalid byte sequence + /// that starts at the index given by `valid_up_to()`. + /// Decoding should resume after that sequence + /// (after inserting a [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]) in case of + /// lossy decoding. + /// + /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html + #[stable(feature = "utf8_error_error_len", since = "1.20.0")] + pub fn error_len(&self) -> Option { + self.error_len.map(|len| len as usize) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Utf8Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(error_len) = self.error_len { + write!( + f, + "invalid utf-8 sequence of {} bytes from index {}", + error_len, self.valid_up_to + ) + } else { + write!(f, "incomplete utf-8 byte sequence from index {}", self.valid_up_to) + } + } +} + +/// An error returned when parsing a `bool` using [`from_str`] fails +/// +/// [`from_str`]: super::FromStr::from_str +#[derive(Debug, Clone, PartialEq, Eq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseBoolError { + pub(super) _priv: (), +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseBoolError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "provided string was not `true` or `false`".fmt(f) + } +} diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs new file mode 100644 index 0000000000..27a67e2b22 --- /dev/null +++ b/library/core/src/str/iter.rs @@ -0,0 +1,1255 @@ +//! Iterators for `str` methods. + +use crate::char; +use crate::fmt::{self, Write}; +use crate::iter::TrustedRandomAccess; +use crate::iter::{Chain, FlatMap, Flatten}; +use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen}; +use crate::ops::Try; +use crate::option; +use crate::slice::{self, Split as SliceSplit}; + +use super::from_utf8_unchecked; +use super::pattern::Pattern; +use super::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; +use super::validations::{next_code_point, next_code_point_reverse, utf8_is_cont_byte}; +use super::LinesAnyMap; +use super::{BytesIsNotEmpty, UnsafeBytesToStr}; +use super::{CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode}; +use super::{IsAsciiWhitespace, IsNotEmpty, IsWhitespace}; + +/// An iterator over the [`char`]s of a string slice. +/// +/// +/// This struct is created by the [`chars`] method on [`str`]. +/// See its documentation for more. +/// +/// [`char`]: prim@char +/// [`chars`]: str::chars +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Chars<'a> { + pub(super) iter: slice::Iter<'a, u8>, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Iterator for Chars<'a> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + next_code_point(&mut self.iter).map(|ch| { + // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value. + unsafe { char::from_u32_unchecked(ch) } + }) + } + + #[inline] + fn count(self) -> usize { + // length in `char` is equal to the number of non-continuation bytes + let bytes_len = self.iter.len(); + let mut cont_bytes = 0; + for &byte in self.iter { + cont_bytes += utf8_is_cont_byte(byte) as usize; + } + bytes_len - cont_bytes + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.iter.len(); + // `(len + 3)` can't overflow, because we know that the `slice::Iter` + // belongs to a slice in memory which has a maximum length of + // `isize::MAX` (that's well below `usize::MAX`). + ((len + 3) / 4, Some(len)) + } + + #[inline] + fn last(mut self) -> Option { + // No need to go through the entire string. + self.next_back() + } +} + +#[stable(feature = "chars_debug_impl", since = "1.38.0")] +impl fmt::Debug for Chars<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Chars(")?; + f.debug_list().entries(self.clone()).finish()?; + write!(f, ")")?; + Ok(()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> DoubleEndedIterator for Chars<'a> { + #[inline] + fn next_back(&mut self) -> Option { + next_code_point_reverse(&mut self.iter).map(|ch| { + // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value. + unsafe { char::from_u32_unchecked(ch) } + }) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Chars<'_> {} + +impl<'a> Chars<'a> { + /// Views the underlying data as a subslice of the original data. + /// + /// This has the same lifetime as the original slice, and so the + /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// let mut chars = "abc".chars(); + /// + /// assert_eq!(chars.as_str(), "abc"); + /// chars.next(); + /// assert_eq!(chars.as_str(), "bc"); + /// chars.next(); + /// chars.next(); + /// assert_eq!(chars.as_str(), ""); + /// ``` + #[stable(feature = "iter_to_slice", since = "1.4.0")] + #[inline] + pub fn as_str(&self) -> &'a str { + // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8. + unsafe { from_utf8_unchecked(self.iter.as_slice()) } + } +} + +/// An iterator over the [`char`]s of a string slice, and their positions. +/// +/// This struct is created by the [`char_indices`] method on [`str`]. +/// See its documentation for more. +/// +/// [`char`]: prim@char +/// [`char_indices`]: str::char_indices +#[derive(Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct CharIndices<'a> { + pub(super) front_offset: usize, + pub(super) iter: Chars<'a>, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Iterator for CharIndices<'a> { + type Item = (usize, char); + + #[inline] + fn next(&mut self) -> Option<(usize, char)> { + let pre_len = self.iter.iter.len(); + match self.iter.next() { + None => None, + Some(ch) => { + let index = self.front_offset; + let len = self.iter.iter.len(); + self.front_offset += pre_len - len; + Some((index, ch)) + } + } + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn last(mut self) -> Option<(usize, char)> { + // No need to go through the entire string. + self.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> DoubleEndedIterator for CharIndices<'a> { + #[inline] + fn next_back(&mut self) -> Option<(usize, char)> { + self.iter.next_back().map(|ch| { + let index = self.front_offset + self.iter.iter.len(); + (index, ch) + }) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for CharIndices<'_> {} + +impl<'a> CharIndices<'a> { + /// Views the underlying data as a subslice of the original data. + /// + /// This has the same lifetime as the original slice, and so the + /// iterator can continue to be used while this exists. + #[stable(feature = "iter_to_slice", since = "1.4.0")] + #[inline] + pub fn as_str(&self) -> &'a str { + self.iter.as_str() + } +} + +/// An iterator over the bytes of a string slice. +/// +/// This struct is created by the [`bytes`] method on [`str`]. +/// See its documentation for more. +/// +/// [`bytes`]: str::bytes +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone, Debug)] +pub struct Bytes<'a>(pub(super) Copied>); + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Bytes<'_> { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.0.count() + } + + #[inline] + fn last(self) -> Option { + self.0.last() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.0.nth(n) + } + + #[inline] + fn all(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + self.0.all(f) + } + + #[inline] + fn any(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + self.0.any(f) + } + + #[inline] + fn find

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.0.find(predicate) + } + + #[inline] + fn position

(&mut self, predicate: P) -> Option + where + P: FnMut(Self::Item) -> bool, + { + self.0.position(predicate) + } + + #[inline] + fn rposition

(&mut self, predicate: P) -> Option + where + P: FnMut(Self::Item) -> bool, + { + self.0.rposition(predicate) + } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 { + // SAFETY: the caller must uphold the safety contract + // for `Iterator::__iterator_get_unchecked`. + unsafe { self.0.__iterator_get_unchecked(idx) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Bytes<'_> { + #[inline] + fn next_back(&mut self) -> Option { + self.0.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.0.nth_back(n) + } + + #[inline] + fn rfind

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.0.rfind(predicate) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Bytes<'_> { + #[inline] + fn len(&self) -> usize { + self.0.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Bytes<'_> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Bytes<'_> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Bytes<'_> { + fn may_have_side_effect() -> bool { + false + } +} + +/// This macro generates a Clone impl for string pattern API +/// wrapper types of the form X<'a, P> +macro_rules! derive_pattern_clone { + (clone $t:ident with |$s:ident| $e:expr) => { + impl<'a, P> Clone for $t<'a, P> + where + P: Pattern<'a, Searcher: Clone>, + { + fn clone(&self) -> Self { + let $s = self; + $e + } + } + }; +} + +/// This macro generates two public iterator structs +/// wrapping a private internal one that makes use of the `Pattern` API. +/// +/// For all patterns `P: Pattern<'a>` the following items will be +/// generated (generics omitted): +/// +/// struct $forward_iterator($internal_iterator); +/// struct $reverse_iterator($internal_iterator); +/// +/// impl Iterator for $forward_iterator +/// { /* internal ends up calling Searcher::next_match() */ } +/// +/// impl DoubleEndedIterator for $forward_iterator +/// where P::Searcher: DoubleEndedSearcher +/// { /* internal ends up calling Searcher::next_match_back() */ } +/// +/// impl Iterator for $reverse_iterator +/// where P::Searcher: ReverseSearcher +/// { /* internal ends up calling Searcher::next_match_back() */ } +/// +/// impl DoubleEndedIterator for $reverse_iterator +/// where P::Searcher: DoubleEndedSearcher +/// { /* internal ends up calling Searcher::next_match() */ } +/// +/// The internal one is defined outside the macro, and has almost the same +/// semantic as a DoubleEndedIterator by delegating to `pattern::Searcher` and +/// `pattern::ReverseSearcher` for both forward and reverse iteration. +/// +/// "Almost", because a `Searcher` and a `ReverseSearcher` for a given +/// `Pattern` might not return the same elements, so actually implementing +/// `DoubleEndedIterator` for it would be incorrect. +/// (See the docs in `str::pattern` for more details) +/// +/// However, the internal struct still represents a single ended iterator from +/// either end, and depending on pattern is also a valid double ended iterator, +/// so the two wrapper structs implement `Iterator` +/// and `DoubleEndedIterator` depending on the concrete pattern type, leading +/// to the complex impls seen above. +macro_rules! generate_pattern_iterators { + { + // Forward iterator + forward: + $(#[$forward_iterator_attribute:meta])* + struct $forward_iterator:ident; + + // Reverse iterator + reverse: + $(#[$reverse_iterator_attribute:meta])* + struct $reverse_iterator:ident; + + // Stability of all generated items + stability: + $(#[$common_stability_attribute:meta])* + + // Internal almost-iterator that is being delegated to + internal: + $internal_iterator:ident yielding ($iterty:ty); + + // Kind of delegation - either single ended or double ended + delegate $($t:tt)* + } => { + $(#[$forward_iterator_attribute])* + $(#[$common_stability_attribute])* + pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + + $(#[$common_stability_attribute])* + impl<'a, P> fmt::Debug for $forward_iterator<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple(stringify!($forward_iterator)) + .field(&self.0) + .finish() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> { + type Item = $iterty; + + #[inline] + fn next(&mut self) -> Option<$iterty> { + self.0.next() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P> Clone for $forward_iterator<'a, P> + where + P: Pattern<'a, Searcher: Clone>, + { + fn clone(&self) -> Self { + $forward_iterator(self.0.clone()) + } + } + + $(#[$reverse_iterator_attribute])* + $(#[$common_stability_attribute])* + pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + + $(#[$common_stability_attribute])* + impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple(stringify!($reverse_iterator)) + .field(&self.0) + .finish() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P> Iterator for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + type Item = $iterty; + + #[inline] + fn next(&mut self) -> Option<$iterty> { + self.0.next_back() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P> Clone for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: Clone>, + { + fn clone(&self) -> Self { + $reverse_iterator(self.0.clone()) + } + } + + #[stable(feature = "fused", since = "1.26.0")] + impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} + + #[stable(feature = "fused", since = "1.26.0")] + impl<'a, P> FusedIterator for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + {} + + generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, + $forward_iterator, + $reverse_iterator, $iterty); + }; + { + double ended; with $(#[$common_stability_attribute:meta])*, + $forward_iterator:ident, + $reverse_iterator:ident, $iterty:ty + } => { + $(#[$common_stability_attribute])* + impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P> + where + P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + { + #[inline] + fn next_back(&mut self) -> Option<$iterty> { + self.0.next_back() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + { + #[inline] + fn next_back(&mut self) -> Option<$iterty> { + self.0.next() + } + } + }; + { + single ended; with $(#[$common_stability_attribute:meta])*, + $forward_iterator:ident, + $reverse_iterator:ident, $iterty:ty + } => {} +} + +derive_pattern_clone! { + clone SplitInternal + with |s| SplitInternal { matcher: s.matcher.clone(), ..*s } +} + +pub(super) struct SplitInternal<'a, P: Pattern<'a>> { + pub(super) start: usize, + pub(super) end: usize, + pub(super) matcher: P::Searcher, + pub(super) allow_trailing_empty: bool, + pub(super) finished: bool, +} + +impl<'a, P> fmt::Debug for SplitInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInternal") + .field("start", &self.start) + .field("end", &self.end) + .field("matcher", &self.matcher) + .field("allow_trailing_empty", &self.allow_trailing_empty) + .field("finished", &self.finished) + .finish() + } +} + +impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { + #[inline] + fn get_end(&mut self) -> Option<&'a str> { + if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) { + self.finished = true; + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + unsafe { + let string = self.matcher.haystack().get_unchecked(self.start..self.end); + Some(string) + } + } else { + None + } + } + + #[inline] + fn next(&mut self) -> Option<&'a str> { + if self.finished { + return None; + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match() { + // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. + Some((a, b)) => unsafe { + let elt = haystack.get_unchecked(self.start..a); + self.start = b; + Some(elt) + }, + None => self.get_end(), + } + } + + #[inline] + fn next_inclusive(&mut self) -> Option<&'a str> { + if self.finished { + return None; + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match() { + // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, + // and self.start is either the start of the original string, + // or `b` was assigned to it, so it also lies on unicode boundary. + Some((_, b)) => unsafe { + let elt = haystack.get_unchecked(self.start..b); + self.start = b; + Some(elt) + }, + None => self.get_end(), + } + } + + #[inline] + fn next_back(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + if self.finished { + return None; + } + + if !self.allow_trailing_empty { + self.allow_trailing_empty = true; + match self.next_back() { + Some(elt) if !elt.is_empty() => return Some(elt), + _ => { + if self.finished { + return None; + } + } + } + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match_back() { + // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. + Some((a, b)) => unsafe { + let elt = haystack.get_unchecked(b..self.end); + self.end = a; + Some(elt) + }, + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + None => unsafe { + self.finished = true; + Some(haystack.get_unchecked(self.start..self.end)) + }, + } + } + + #[inline] + fn next_back_inclusive(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + if self.finished { + return None; + } + + if !self.allow_trailing_empty { + self.allow_trailing_empty = true; + match self.next_back_inclusive() { + Some(elt) if !elt.is_empty() => return Some(elt), + _ => { + if self.finished { + return None; + } + } + } + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match_back() { + // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, + // and self.end is either the end of the original string, + // or `b` was assigned to it, so it also lies on unicode boundary. + Some((_, b)) => unsafe { + let elt = haystack.get_unchecked(b..self.end); + self.end = b; + Some(elt) + }, + // SAFETY: self.start is either the start of the original string, + // or start of a substring that represents the part of the string that hasn't + // iterated yet. Either way, it is guaranteed to lie on unicode boundary. + // self.end is either the end of the original string, + // or `b` was assigned to it, so it also lies on unicode boundary. + None => unsafe { + self.finished = true; + Some(haystack.get_unchecked(self.start..self.end)) + }, + } + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`split`]. + /// + /// [`split`]: str::split + struct Split; + reverse: + /// Created with the method [`rsplit`]. + /// + /// [`rsplit`]: str::rsplit + struct RSplit; + stability: + #[stable(feature = "rust1", since = "1.0.0")] + internal: + SplitInternal yielding (&'a str); + delegate double ended; +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`split_terminator`]. + /// + /// [`split_terminator`]: str::split_terminator + struct SplitTerminator; + reverse: + /// Created with the method [`rsplit_terminator`]. + /// + /// [`rsplit_terminator`]: str::rsplit_terminator + struct RSplitTerminator; + stability: + #[stable(feature = "rust1", since = "1.0.0")] + internal: + SplitInternal yielding (&'a str); + delegate double ended; +} + +derive_pattern_clone! { + clone SplitNInternal + with |s| SplitNInternal { iter: s.iter.clone(), ..*s } +} + +pub(super) struct SplitNInternal<'a, P: Pattern<'a>> { + pub(super) iter: SplitInternal<'a, P>, + /// The number of splits remaining + pub(super) count: usize, +} + +impl<'a, P> fmt::Debug for SplitNInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitNInternal") + .field("iter", &self.iter) + .field("count", &self.count) + .finish() + } +} + +impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { + #[inline] + fn next(&mut self) -> Option<&'a str> { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.get_end() + } + _ => { + self.count -= 1; + self.iter.next() + } + } + } + + #[inline] + fn next_back(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.get_end() + } + _ => { + self.count -= 1; + self.iter.next_back() + } + } + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`splitn`]. + /// + /// [`splitn`]: str::splitn + struct SplitN; + reverse: + /// Created with the method [`rsplitn`]. + /// + /// [`rsplitn`]: str::rsplitn + struct RSplitN; + stability: + #[stable(feature = "rust1", since = "1.0.0")] + internal: + SplitNInternal yielding (&'a str); + delegate single ended; +} + +derive_pattern_clone! { + clone MatchIndicesInternal + with |s| MatchIndicesInternal(s.0.clone()) +} + +pub(super) struct MatchIndicesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher); + +impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("MatchIndicesInternal").field(&self.0).finish() + } +} + +impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { + #[inline] + fn next(&mut self) -> Option<(usize, &'a str)> { + self.0 + .next_match() + // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. + .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) }) + } + + #[inline] + fn next_back(&mut self) -> Option<(usize, &'a str)> + where + P::Searcher: ReverseSearcher<'a>, + { + self.0 + .next_match_back() + // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. + .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) }) + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`match_indices`]. + /// + /// [`match_indices`]: str::match_indices + struct MatchIndices; + reverse: + /// Created with the method [`rmatch_indices`]. + /// + /// [`rmatch_indices`]: str::rmatch_indices + struct RMatchIndices; + stability: + #[stable(feature = "str_match_indices", since = "1.5.0")] + internal: + MatchIndicesInternal yielding ((usize, &'a str)); + delegate double ended; +} + +derive_pattern_clone! { + clone MatchesInternal + with |s| MatchesInternal(s.0.clone()) +} + +pub(super) struct MatchesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher); + +impl<'a, P> fmt::Debug for MatchesInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("MatchesInternal").field(&self.0).finish() + } +} + +impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { + #[inline] + fn next(&mut self) -> Option<&'a str> { + // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. + self.0.next_match().map(|(a, b)| unsafe { + // Indices are known to be on utf8 boundaries + self.0.haystack().get_unchecked(a..b) + }) + } + + #[inline] + fn next_back(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. + self.0.next_match_back().map(|(a, b)| unsafe { + // Indices are known to be on utf8 boundaries + self.0.haystack().get_unchecked(a..b) + }) + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`matches`]. + /// + /// [`matches`]: str::matches + struct Matches; + reverse: + /// Created with the method [`rmatches`]. + /// + /// [`rmatches`]: str::rmatches + struct RMatches; + stability: + #[stable(feature = "str_matches", since = "1.2.0")] + internal: + MatchesInternal yielding (&'a str); + delegate double ended; +} + +/// An iterator over the lines of a string, as string slices. +/// +/// This struct is created with the [`lines`] method on [`str`]. +/// See its documentation for more. +/// +/// [`lines`]: str::lines +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone, Debug)] +pub struct Lines<'a>(pub(super) Map, LinesAnyMap>); + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Iterator for Lines<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn last(mut self) -> Option<&'a str> { + self.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> DoubleEndedIterator for Lines<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.0.next_back() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Lines<'_> {} + +/// Created with the method [`lines_any`]. +/// +/// [`lines_any`]: str::lines_any +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")] +#[derive(Clone, Debug)] +#[allow(deprecated)] +pub struct LinesAny<'a>(pub(super) Lines<'a>); + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +impl<'a> Iterator for LinesAny<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +impl<'a> DoubleEndedIterator for LinesAny<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.0.next_back() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +#[allow(deprecated)] +impl FusedIterator for LinesAny<'_> {} + +/// An iterator over the non-whitespace substrings of a string, +/// separated by any amount of whitespace. +/// +/// This struct is created by the [`split_whitespace`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_whitespace`]: str::split_whitespace +#[stable(feature = "split_whitespace", since = "1.1.0")] +#[derive(Clone, Debug)] +pub struct SplitWhitespace<'a> { + pub(super) inner: Filter, IsNotEmpty>, +} + +/// An iterator over the non-ASCII-whitespace substrings of a string, +/// separated by any amount of ASCII whitespace. +/// +/// This struct is created by the [`split_ascii_whitespace`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_ascii_whitespace`]: str::split_ascii_whitespace +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct SplitAsciiWhitespace<'a> { + pub(super) inner: + Map, BytesIsNotEmpty>, UnsafeBytesToStr>, +} + +/// An iterator over the substrings of a string, +/// terminated by a substring matching to a predicate function +/// Unlike `Split`, it contains the matched part as a terminator +/// of the subslice. +/// +/// This struct is created by the [`split_inclusive`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_inclusive`]: str::split_inclusive +#[unstable(feature = "split_inclusive", issue = "72360")] +pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> Iterator for SplitWhitespace<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + #[inline] + fn last(mut self) -> Option<&'a str> { + self.next_back() + } +} + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.inner.next_back() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for SplitWhitespace<'_> {} + +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +impl<'a> Iterator for SplitAsciiWhitespace<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + #[inline] + fn last(mut self) -> Option<&'a str> { + self.next_back() + } +} + +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.inner.next_back() + } +} + +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +impl FusedIterator for SplitAsciiWhitespace<'_> {} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.0.next_inclusive() + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInclusive").field("0", &self.0).finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> { + fn clone(&self) -> Self { + SplitInclusive(self.0.clone()) + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator + for SplitInclusive<'a, P> +{ + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.0.next_back_inclusive() + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} + +/// An iterator of [`u16`] over the string encoded as UTF-16. +/// +/// This struct is created by the [`encode_utf16`] method on [`str`]. +/// See its documentation for more. +/// +/// [`encode_utf16`]: str::encode_utf16 +#[derive(Clone)] +#[stable(feature = "encode_utf16", since = "1.8.0")] +pub struct EncodeUtf16<'a> { + pub(super) chars: Chars<'a>, + pub(super) extra: u16, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for EncodeUtf16<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("EncodeUtf16 { .. }") + } +} + +#[stable(feature = "encode_utf16", since = "1.8.0")] +impl<'a> Iterator for EncodeUtf16<'a> { + type Item = u16; + + #[inline] + fn next(&mut self) -> Option { + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; 2]; + self.chars.next().map(|ch| { + let n = ch.encode_utf16(&mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.chars.size_hint(); + // every char gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low, high.and_then(|n| n.checked_mul(2))) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for EncodeUtf16<'_> {} + +/// The return type of [`str::escape_debug`]. +#[stable(feature = "str_escape", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct EscapeDebug<'a> { + pub(super) inner: Chain< + Flatten>, + FlatMap, char::EscapeDebug, CharEscapeDebugContinue>, + >, +} + +/// The return type of [`str::escape_default`]. +#[stable(feature = "str_escape", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct EscapeDefault<'a> { + pub(super) inner: FlatMap, char::EscapeDefault, CharEscapeDefault>, +} + +/// The return type of [`str::escape_unicode`]. +#[stable(feature = "str_escape", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct EscapeUnicode<'a> { + pub(super) inner: FlatMap, char::EscapeUnicode, CharEscapeUnicode>, +} + +macro_rules! escape_types_impls { + ($( $Name: ident ),+) => {$( + #[stable(feature = "str_escape", since = "1.34.0")] + impl<'a> fmt::Display for $Name<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.clone().try_for_each(|c| f.write_char(c)) + } + } + + #[stable(feature = "str_escape", since = "1.34.0")] + impl<'a> Iterator for $Name<'a> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_fold(init, fold) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.fold(init, fold) + } + } + + #[stable(feature = "str_escape", since = "1.34.0")] + impl<'a> FusedIterator for $Name<'a> {} + )+} +} + +escape_types_impls!(EscapeDebug, EscapeDefault, EscapeUnicode); diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index 88b2bc551b..720a35bbc8 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -1,7 +1,9 @@ use crate::char; use crate::fmt::{self, Write}; use crate::mem; -use crate::str as core_str; + +use super::from_utf8_unchecked; +use super::validations::utf8_char_width; /// Lossy UTF-8 string. #[unstable(feature = "str_internals", issue = "none")] @@ -66,14 +68,14 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { if byte < 128 { } else { - let w = core_str::utf8_char_width(byte); + let w = utf8_char_width(byte); macro_rules! error { () => {{ // SAFETY: We have checked up to `i` that source is valid UTF-8. unsafe { let r = Utf8LossyChunk { - valid: core_str::from_utf8_unchecked(&self.source[0..i_]), + valid: from_utf8_unchecked(&self.source[0..i_]), broken: &self.source[i_..i], }; self.source = &self.source[i..]; @@ -133,7 +135,7 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { let r = Utf8LossyChunk { // SAFETY: We have checked that the entire source is valid UTF-8. - valid: unsafe { core_str::from_utf8_unchecked(self.source) }, + valid: unsafe { from_utf8_unchecked(self.source) }, broken: &[], }; self.source = &[]; diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index d7af5dd860..3e18a4e706 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1,25 +1,23 @@ -// ignore-tidy-filelength - //! String manipulation. //! //! For more details, see the [`std::str`] module. //! -//! [`std::str`]: self +//! [`std::str`]: ../../std/str/index.html #![stable(feature = "rust1", since = "1.0.0")] +mod converts; +mod error; +mod iter; +mod traits; +mod validations; + use self::pattern::Pattern; use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; use crate::char; -use crate::fmt::{self, Write}; -use crate::iter::TrustedRandomAccess; -use crate::iter::{Chain, FlatMap, Flatten}; -use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen}; use crate::mem; -use crate::ops::Try; -use crate::option; -use crate::slice::{self, SliceIndex, Split as SliceSplit}; +use crate::slice::{self, SliceIndex}; pub mod pattern; @@ -27,2202 +25,57 @@ pub mod pattern; #[allow(missing_docs)] pub mod lossy; -/// Parse a value from a string -/// -/// `FromStr`'s [`from_str`] method is often used implicitly, through -/// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples. -/// -/// [`from_str`]: FromStr::from_str -/// [`parse`]: str::parse -/// -/// `FromStr` does not have a lifetime parameter, and so you can only parse types -/// that do not contain a lifetime parameter themselves. In other words, you can -/// parse an `i32` with `FromStr`, but not a `&i32`. You can parse a struct that -/// contains an `i32`, but not one that contains an `&i32`. -/// -/// # Examples -/// -/// Basic implementation of `FromStr` on an example `Point` type: -/// -/// ``` -/// use std::str::FromStr; -/// use std::num::ParseIntError; -/// -/// #[derive(Debug, PartialEq)] -/// struct Point { -/// x: i32, -/// y: i32 -/// } -/// -/// impl FromStr for Point { -/// type Err = ParseIntError; -/// -/// fn from_str(s: &str) -> Result { -/// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) -/// .split(',') -/// .collect(); -/// -/// let x_fromstr = coords[0].parse::()?; -/// let y_fromstr = coords[1].parse::()?; -/// -/// Ok(Point { x: x_fromstr, y: y_fromstr }) -/// } -/// } -/// -/// let p = Point::from_str("(1,2)"); -/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub trait FromStr: Sized { - /// The associated error which can be returned from parsing. - #[stable(feature = "rust1", since = "1.0.0")] - type Err; - - /// Parses a string `s` to return a value of this type. - /// - /// If parsing succeeds, return the value inside [`Ok`], otherwise - /// when the string is ill-formatted return an error specific to the - /// inside [`Err`]. The error type is specific to implementation of the trait. - /// - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`: - /// - /// [ithirtytwo]: ../../std/primitive.i32.html - /// - /// ``` - /// use std::str::FromStr; - /// - /// let s = "5"; - /// let x = i32::from_str(s).unwrap(); - /// - /// assert_eq!(5, x); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn from_str(s: &str) -> Result; -} - #[stable(feature = "rust1", since = "1.0.0")] -impl FromStr for bool { - type Err = ParseBoolError; +pub use converts::{from_utf8, from_utf8_unchecked}; - /// Parse a `bool` from a string. - /// - /// Yields a `Result`, because `s` may or may not - /// actually be parseable. - /// - /// # Examples - /// - /// ``` - /// use std::str::FromStr; - /// - /// assert_eq!(FromStr::from_str("true"), Ok(true)); - /// assert_eq!(FromStr::from_str("false"), Ok(false)); - /// assert!(::from_str("not even a boolean").is_err()); - /// ``` - /// - /// Note, in many cases, the `.parse()` method on `str` is more proper. - /// - /// ``` - /// assert_eq!("true".parse(), Ok(true)); - /// assert_eq!("false".parse(), Ok(false)); - /// assert!("not even a boolean".parse::().is_err()); - /// ``` - #[inline] - fn from_str(s: &str) -> Result { - match s { - "true" => Ok(true), - "false" => Ok(false), - _ => Err(ParseBoolError { _priv: () }), - } - } -} - -/// An error returned when parsing a `bool` using [`from_str`] fails -/// -/// [`from_str`]: FromStr::from_str -#[derive(Debug, Clone, PartialEq, Eq)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct ParseBoolError { - _priv: (), -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseBoolError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "provided string was not `true` or `false`".fmt(f) - } -} - -/* -Section: Creating a string -*/ - -/// Errors which can occur when attempting to interpret a sequence of [`u8`] -/// as a string. -/// -/// As such, the `from_utf8` family of functions and methods for both [`String`]s -/// and [`&str`]s make use of this error, for example. -/// -/// [`String`]: ../../std/string/struct.String.html#method.from_utf8 -/// [`&str`]: from_utf8 -/// -/// # Examples -/// -/// This error type’s methods can be used to create functionality -/// similar to `String::from_utf8_lossy` without allocating heap memory: -/// -/// ``` -/// fn from_utf8_lossy(mut input: &[u8], mut push: F) where F: FnMut(&str) { -/// loop { -/// match std::str::from_utf8(input) { -/// Ok(valid) => { -/// push(valid); -/// break -/// } -/// Err(error) => { -/// let (valid, after_valid) = input.split_at(error.valid_up_to()); -/// unsafe { -/// push(std::str::from_utf8_unchecked(valid)) -/// } -/// push("\u{FFFD}"); -/// -/// if let Some(invalid_sequence_length) = error.error_len() { -/// input = &after_valid[invalid_sequence_length..] -/// } else { -/// break -/// } -/// } -/// } -/// } -/// } -/// ``` -#[derive(Copy, Eq, PartialEq, Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Utf8Error { - valid_up_to: usize, - error_len: Option, -} - -impl Utf8Error { - /// Returns the index in the given string up to which valid UTF-8 was - /// verified. - /// - /// It is the maximum index such that `from_utf8(&input[..index])` - /// would return `Ok(_)`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::str; - /// - /// // some invalid bytes, in a vector - /// let sparkle_heart = vec![0, 159, 146, 150]; - /// - /// // std::str::from_utf8 returns a Utf8Error - /// let error = str::from_utf8(&sparkle_heart).unwrap_err(); - /// - /// // the second byte is invalid here - /// assert_eq!(1, error.valid_up_to()); - /// ``` - #[stable(feature = "utf8_error", since = "1.5.0")] - pub fn valid_up_to(&self) -> usize { - self.valid_up_to - } - - /// Provides more information about the failure: - /// - /// * `None`: the end of the input was reached unexpectedly. - /// `self.valid_up_to()` is 1 to 3 bytes from the end of the input. - /// If a byte stream (such as a file or a network socket) is being decoded incrementally, - /// this could be a valid `char` whose UTF-8 byte sequence is spanning multiple chunks. - /// - /// * `Some(len)`: an unexpected byte was encountered. - /// The length provided is that of the invalid byte sequence - /// that starts at the index given by `valid_up_to()`. - /// Decoding should resume after that sequence - /// (after inserting a [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]) in case of - /// lossy decoding. - /// - /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html - #[stable(feature = "utf8_error_error_len", since = "1.20.0")] - pub fn error_len(&self) -> Option { - self.error_len.map(|len| len as usize) - } -} - -/// Converts a slice of bytes to a string slice. -/// -/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice -/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between -/// the two. Not all byte slices are valid string slices, however: [`&str`] requires -/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid -/// UTF-8, and then does the conversion. -/// -/// [`&str`]: str -/// [byteslice]: ../../std/primitive.slice.html -/// -/// If you are sure that the byte slice is valid UTF-8, and you don't want to -/// incur the overhead of the validity check, there is an unsafe version of -/// this function, [`from_utf8_unchecked`][fromutf8u], which has the same -/// behavior but skips the check. -/// -/// [fromutf8u]: fn.from_utf8_unchecked.html -/// -/// If you need a `String` instead of a `&str`, consider -/// [`String::from_utf8`][string]. -/// -/// [string]: ../../std/string/struct.String.html#method.from_utf8 -/// -/// Because you can stack-allocate a `[u8; N]`, and you can take a -/// [`&[u8]`][byteslice] of it, this function is one way to have a -/// stack-allocated string. There is an example of this in the -/// examples section below. -/// -/// [byteslice]: ../../std/primitive.slice.html -/// -/// # Errors -/// -/// Returns `Err` if the slice is not UTF-8 with a description as to why the -/// provided slice is not UTF-8. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::str; -/// -/// // some bytes, in a vector -/// let sparkle_heart = vec![240, 159, 146, 150]; -/// -/// // We know these bytes are valid, so just use `unwrap()`. -/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); -/// -/// assert_eq!("💖", sparkle_heart); -/// ``` -/// -/// Incorrect bytes: -/// -/// ``` -/// use std::str; -/// -/// // some invalid bytes, in a vector -/// let sparkle_heart = vec![0, 159, 146, 150]; -/// -/// assert!(str::from_utf8(&sparkle_heart).is_err()); -/// ``` -/// -/// See the docs for [`Utf8Error`][error] for more details on the kinds of -/// errors that can be returned. -/// -/// [error]: struct.Utf8Error.html -/// -/// A "stack allocated string": -/// -/// ``` -/// use std::str; -/// -/// // some bytes, in a stack-allocated array -/// let sparkle_heart = [240, 159, 146, 150]; -/// -/// // We know these bytes are valid, so just use `unwrap()`. -/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); -/// -/// assert_eq!("💖", sparkle_heart); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { - run_utf8_validation(v)?; - // SAFETY: Just ran validation. - Ok(unsafe { from_utf8_unchecked(v) }) -} - -/// Converts a mutable slice of bytes to a mutable string slice. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::str; -/// -/// // "Hello, Rust!" as a mutable vector -/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33]; -/// -/// // As we know these bytes are valid, we can use `unwrap()` -/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap(); -/// -/// assert_eq!("Hello, Rust!", outstr); -/// ``` -/// -/// Incorrect bytes: -/// -/// ``` -/// use std::str; -/// -/// // Some invalid bytes in a mutable vector -/// let mut invalid = vec![128, 223]; -/// -/// assert!(str::from_utf8_mut(&mut invalid).is_err()); -/// ``` -/// See the docs for [`Utf8Error`][error] for more details on the kinds of -/// errors that can be returned. -/// -/// [error]: struct.Utf8Error.html -#[stable(feature = "str_mut_extras", since = "1.20.0")] -pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { - run_utf8_validation(v)?; - // SAFETY: Just ran validation. - Ok(unsafe { from_utf8_unchecked_mut(v) }) -} - -/// Converts a slice of bytes to a string slice without checking -/// that the string contains valid UTF-8. -/// -/// See the safe version, [`from_utf8`][fromutf8], for more information. -/// -/// [fromutf8]: fn.from_utf8.html -/// -/// # Safety -/// -/// This function is unsafe because it does not check that the bytes passed to -/// it are valid UTF-8. If this constraint is violated, undefined behavior -/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8. -/// -/// [`&str`]: str -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::str; -/// -/// // some bytes, in a vector -/// let sparkle_heart = vec![240, 159, 146, 150]; -/// -/// let sparkle_heart = unsafe { -/// str::from_utf8_unchecked(&sparkle_heart) -/// }; -/// -/// assert_eq!("💖", sparkle_heart); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")] -#[allow(unused_attributes)] -#[allow_internal_unstable(const_fn_transmute)] -pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { - // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. - // Also relies on `&str` and `&[u8]` having the same layout. - unsafe { mem::transmute(v) } -} - -/// Converts a slice of bytes to a string slice without checking -/// that the string contains valid UTF-8; mutable version. -/// -/// See the immutable version, [`from_utf8_unchecked()`] for more information. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::str; -/// -/// let mut heart = vec![240, 159, 146, 150]; -/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) }; -/// -/// assert_eq!("💖", heart); -/// ``` -#[inline] #[stable(feature = "str_mut_extras", since = "1.20.0")] -pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { - // SAFETY: the caller must guarantee that the bytes `v` - // are valid UTF-8, thus the cast to `*mut str` is safe. - // Also, the pointer dereference is safe because that pointer - // comes from a reference which is guaranteed to be valid for writes. - unsafe { &mut *(v as *mut [u8] as *mut str) } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Utf8Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(error_len) = self.error_len { - write!( - f, - "invalid utf-8 sequence of {} bytes from index {}", - error_len, self.valid_up_to - ) - } else { - write!(f, "incomplete utf-8 byte sequence from index {}", self.valid_up_to) - } - } -} - -/* -Section: Iterators -*/ - -/// An iterator over the [`char`]s of a string slice. -/// -/// -/// This struct is created by the [`chars`] method on [`str`]. -/// See its documentation for more. -/// -/// [`char`]: prim@char -/// [`chars`]: str::chars -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Chars<'a> { - iter: slice::Iter<'a, u8>, -} - -/// Returns the initial codepoint accumulator for the first byte. -/// The first byte is special, only want bottom 5 bits for width 2, 4 bits -/// for width 3, and 3 bits for width 4. -#[inline] -fn utf8_first_byte(byte: u8, width: u32) -> u32 { - (byte & (0x7F >> width)) as u32 -} - -/// Returns the value of `ch` updated with continuation byte `byte`. -#[inline] -fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { - (ch << 6) | (byte & CONT_MASK) as u32 -} - -/// Checks whether the byte is a UTF-8 continuation byte (i.e., starts with the -/// bits `10`). -#[inline] -fn utf8_is_cont_byte(byte: u8) -> bool { - (byte & !CONT_MASK) == TAG_CONT_U8 -} - -#[inline] -fn unwrap_or_0(opt: Option<&u8>) -> u8 { - match opt { - Some(&byte) => byte, - None => 0, - } -} - -/// Reads the next code point out of a byte iterator (assuming a -/// UTF-8-like encoding). -#[unstable(feature = "str_internals", issue = "none")] -#[inline] -pub fn next_code_point<'a, I: Iterator>(bytes: &mut I) -> Option { - // Decode UTF-8 - let x = *bytes.next()?; - if x < 128 { - return Some(x as u32); - } - - // Multibyte case follows - // Decode from a byte combination out of: [[[x y] z] w] - // NOTE: Performance is sensitive to the exact formulation here - let init = utf8_first_byte(x, 2); - let y = unwrap_or_0(bytes.next()); - let mut ch = utf8_acc_cont_byte(init, y); - if x >= 0xE0 { - // [[x y z] w] case - // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid - let z = unwrap_or_0(bytes.next()); - let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z); - ch = init << 12 | y_z; - if x >= 0xF0 { - // [x y z w] case - // use only the lower 3 bits of `init` - let w = unwrap_or_0(bytes.next()); - ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w); - } - } - - Some(ch) -} - -/// Reads the last code point out of a byte iterator (assuming a -/// UTF-8-like encoding). -#[inline] -fn next_code_point_reverse<'a, I>(bytes: &mut I) -> Option -where - I: DoubleEndedIterator, -{ - // Decode UTF-8 - let w = match *bytes.next_back()? { - next_byte if next_byte < 128 => return Some(next_byte as u32), - back_byte => back_byte, - }; - - // Multibyte case follows - // Decode from a byte combination out of: [x [y [z w]]] - let mut ch; - let z = unwrap_or_0(bytes.next_back()); - ch = utf8_first_byte(z, 2); - if utf8_is_cont_byte(z) { - let y = unwrap_or_0(bytes.next_back()); - ch = utf8_first_byte(y, 3); - if utf8_is_cont_byte(y) { - let x = unwrap_or_0(bytes.next_back()); - ch = utf8_first_byte(x, 4); - ch = utf8_acc_cont_byte(ch, y); - } - ch = utf8_acc_cont_byte(ch, z); - } - ch = utf8_acc_cont_byte(ch, w); - - Some(ch) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Chars<'a> { - type Item = char; - - #[inline] - fn next(&mut self) -> Option { - next_code_point(&mut self.iter).map(|ch| { - // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value. - unsafe { char::from_u32_unchecked(ch) } - }) - } - - #[inline] - fn count(self) -> usize { - // length in `char` is equal to the number of non-continuation bytes - let bytes_len = self.iter.len(); - let mut cont_bytes = 0; - for &byte in self.iter { - cont_bytes += utf8_is_cont_byte(byte) as usize; - } - bytes_len - cont_bytes - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.iter.len(); - // `(len + 3)` can't overflow, because we know that the `slice::Iter` - // belongs to a slice in memory which has a maximum length of - // `isize::MAX` (that's well below `usize::MAX`). - ((len + 3) / 4, Some(len)) - } - - #[inline] - fn last(mut self) -> Option { - // No need to go through the entire string. - self.next_back() - } -} - -#[stable(feature = "chars_debug_impl", since = "1.38.0")] -impl fmt::Debug for Chars<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Chars(")?; - f.debug_list().entries(self.clone()).finish()?; - write!(f, ")")?; - Ok(()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for Chars<'a> { - #[inline] - fn next_back(&mut self) -> Option { - next_code_point_reverse(&mut self.iter).map(|ch| { - // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value. - unsafe { char::from_u32_unchecked(ch) } - }) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Chars<'_> {} - -impl<'a> Chars<'a> { - /// Views the underlying data as a subslice of the original data. - /// - /// This has the same lifetime as the original slice, and so the - /// iterator can continue to be used while this exists. - /// - /// # Examples - /// - /// ``` - /// let mut chars = "abc".chars(); - /// - /// assert_eq!(chars.as_str(), "abc"); - /// chars.next(); - /// assert_eq!(chars.as_str(), "bc"); - /// chars.next(); - /// chars.next(); - /// assert_eq!(chars.as_str(), ""); - /// ``` - #[stable(feature = "iter_to_slice", since = "1.4.0")] - #[inline] - pub fn as_str(&self) -> &'a str { - // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8. - unsafe { from_utf8_unchecked(self.iter.as_slice()) } - } -} - -/// An iterator over the [`char`]s of a string slice, and their positions. -/// -/// This struct is created by the [`char_indices`] method on [`str`]. -/// See its documentation for more. -/// -/// [`char`]: prim@char -/// [`char_indices`]: str::char_indices -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct CharIndices<'a> { - front_offset: usize, - iter: Chars<'a>, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for CharIndices<'a> { - type Item = (usize, char); - - #[inline] - fn next(&mut self) -> Option<(usize, char)> { - let pre_len = self.iter.iter.len(); - match self.iter.next() { - None => None, - Some(ch) => { - let index = self.front_offset; - let len = self.iter.iter.len(); - self.front_offset += pre_len - len; - Some((index, ch)) - } - } - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn last(mut self) -> Option<(usize, char)> { - // No need to go through the entire string. - self.next_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for CharIndices<'a> { - #[inline] - fn next_back(&mut self) -> Option<(usize, char)> { - self.iter.next_back().map(|ch| { - let index = self.front_offset + self.iter.iter.len(); - (index, ch) - }) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for CharIndices<'_> {} - -impl<'a> CharIndices<'a> { - /// Views the underlying data as a subslice of the original data. - /// - /// This has the same lifetime as the original slice, and so the - /// iterator can continue to be used while this exists. - #[stable(feature = "iter_to_slice", since = "1.4.0")] - #[inline] - pub fn as_str(&self) -> &'a str { - self.iter.as_str() - } -} - -/// An iterator over the bytes of a string slice. -/// -/// This struct is created by the [`bytes`] method on [`str`]. -/// See its documentation for more. -/// -/// [`bytes`]: str::bytes -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone, Debug)] -pub struct Bytes<'a>(Copied>); - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Bytes<'_> { - type Item = u8; - - #[inline] - fn next(&mut self) -> Option { - self.0.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - - #[inline] - fn count(self) -> usize { - self.0.count() - } - - #[inline] - fn last(self) -> Option { - self.0.last() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - self.0.nth(n) - } - - #[inline] - fn all(&mut self, f: F) -> bool - where - F: FnMut(Self::Item) -> bool, - { - self.0.all(f) - } - - #[inline] - fn any(&mut self, f: F) -> bool - where - F: FnMut(Self::Item) -> bool, - { - self.0.any(f) - } - - #[inline] - fn find

(&mut self, predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.0.find(predicate) - } - - #[inline] - fn position

(&mut self, predicate: P) -> Option - where - P: FnMut(Self::Item) -> bool, - { - self.0.position(predicate) - } - - #[inline] - fn rposition

(&mut self, predicate: P) -> Option - where - P: FnMut(Self::Item) -> bool, - { - self.0.rposition(predicate) - } - - #[inline] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 { - // SAFETY: the caller must uphold the safety contract - // for `Iterator::get_unchecked`. - unsafe { self.0.__iterator_get_unchecked(idx) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Bytes<'_> { - #[inline] - fn next_back(&mut self) -> Option { - self.0.next_back() - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - self.0.nth_back(n) - } - - #[inline] - fn rfind

(&mut self, predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.0.rfind(predicate) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Bytes<'_> { - #[inline] - fn len(&self) -> usize { - self.0.len() - } - - #[inline] - fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Bytes<'_> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Bytes<'_> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Bytes<'_> { - fn may_have_side_effect() -> bool { - false - } -} +pub use converts::{from_utf8_mut, from_utf8_unchecked_mut}; -/// This macro generates a Clone impl for string pattern API -/// wrapper types of the form X<'a, P> -macro_rules! derive_pattern_clone { - (clone $t:ident with |$s:ident| $e:expr) => { - impl<'a, P> Clone for $t<'a, P> - where - P: Pattern<'a, Searcher: Clone>, - { - fn clone(&self) -> Self { - let $s = self; - $e - } - } - }; -} - -/// This macro generates two public iterator structs -/// wrapping a private internal one that makes use of the `Pattern` API. -/// -/// For all patterns `P: Pattern<'a>` the following items will be -/// generated (generics omitted): -/// -/// struct $forward_iterator($internal_iterator); -/// struct $reverse_iterator($internal_iterator); -/// -/// impl Iterator for $forward_iterator -/// { /* internal ends up calling Searcher::next_match() */ } -/// -/// impl DoubleEndedIterator for $forward_iterator -/// where P::Searcher: DoubleEndedSearcher -/// { /* internal ends up calling Searcher::next_match_back() */ } -/// -/// impl Iterator for $reverse_iterator -/// where P::Searcher: ReverseSearcher -/// { /* internal ends up calling Searcher::next_match_back() */ } -/// -/// impl DoubleEndedIterator for $reverse_iterator -/// where P::Searcher: DoubleEndedSearcher -/// { /* internal ends up calling Searcher::next_match() */ } -/// -/// The internal one is defined outside the macro, and has almost the same -/// semantic as a DoubleEndedIterator by delegating to `pattern::Searcher` and -/// `pattern::ReverseSearcher` for both forward and reverse iteration. -/// -/// "Almost", because a `Searcher` and a `ReverseSearcher` for a given -/// `Pattern` might not return the same elements, so actually implementing -/// `DoubleEndedIterator` for it would be incorrect. -/// (See the docs in `str::pattern` for more details) -/// -/// However, the internal struct still represents a single ended iterator from -/// either end, and depending on pattern is also a valid double ended iterator, -/// so the two wrapper structs implement `Iterator` -/// and `DoubleEndedIterator` depending on the concrete pattern type, leading -/// to the complex impls seen above. -macro_rules! generate_pattern_iterators { - { - // Forward iterator - forward: - $(#[$forward_iterator_attribute:meta])* - struct $forward_iterator:ident; - - // Reverse iterator - reverse: - $(#[$reverse_iterator_attribute:meta])* - struct $reverse_iterator:ident; - - // Stability of all generated items - stability: - $(#[$common_stability_attribute:meta])* - - // Internal almost-iterator that is being delegated to - internal: - $internal_iterator:ident yielding ($iterty:ty); - - // Kind of delegation - either single ended or double ended - delegate $($t:tt)* - } => { - $(#[$forward_iterator_attribute])* - $(#[$common_stability_attribute])* - pub struct $forward_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>); - - $(#[$common_stability_attribute])* - impl<'a, P> fmt::Debug for $forward_iterator<'a, P> - where - P: Pattern<'a, Searcher: fmt::Debug>, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple(stringify!($forward_iterator)) - .field(&self.0) - .finish() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> { - type Item = $iterty; - - #[inline] - fn next(&mut self) -> Option<$iterty> { - self.0.next() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P> Clone for $forward_iterator<'a, P> - where - P: Pattern<'a, Searcher: Clone>, - { - fn clone(&self) -> Self { - $forward_iterator(self.0.clone()) - } - } - - $(#[$reverse_iterator_attribute])* - $(#[$common_stability_attribute])* - pub struct $reverse_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>); - - $(#[$common_stability_attribute])* - impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: fmt::Debug>, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple(stringify!($reverse_iterator)) - .field(&self.0) - .finish() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P> Iterator for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, - { - type Item = $iterty; - - #[inline] - fn next(&mut self) -> Option<$iterty> { - self.0.next_back() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P> Clone for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: Clone>, - { - fn clone(&self) -> Self { - $reverse_iterator(self.0.clone()) - } - } - - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} - - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, P> FusedIterator for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, - {} - - generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, - $forward_iterator, - $reverse_iterator, $iterty); - }; - { - double ended; with $(#[$common_stability_attribute:meta])*, - $forward_iterator:ident, - $reverse_iterator:ident, $iterty:ty - } => { - $(#[$common_stability_attribute])* - impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P> - where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, - { - #[inline] - fn next_back(&mut self) -> Option<$iterty> { - self.0.next_back() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, - { - #[inline] - fn next_back(&mut self) -> Option<$iterty> { - self.0.next() - } - } - }; - { - single ended; with $(#[$common_stability_attribute:meta])*, - $forward_iterator:ident, - $reverse_iterator:ident, $iterty:ty - } => {} -} - -derive_pattern_clone! { - clone SplitInternal - with |s| SplitInternal { matcher: s.matcher.clone(), ..*s } -} - -struct SplitInternal<'a, P: Pattern<'a>> { - start: usize, - end: usize, - matcher: P::Searcher, - allow_trailing_empty: bool, - finished: bool, -} - -impl<'a, P> fmt::Debug for SplitInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInternal") - .field("start", &self.start) - .field("end", &self.end) - .field("matcher", &self.matcher) - .field("allow_trailing_empty", &self.allow_trailing_empty) - .field("finished", &self.finished) - .finish() - } -} - -impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { - #[inline] - fn get_end(&mut self) -> Option<&'a str> { - if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) { - self.finished = true; - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - unsafe { - let string = self.matcher.haystack().get_unchecked(self.start..self.end); - Some(string) - } - } else { - None - } - } - - #[inline] - fn next(&mut self) -> Option<&'a str> { - if self.finished { - return None; - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match() { - // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. - Some((a, b)) => unsafe { - let elt = haystack.get_unchecked(self.start..a); - self.start = b; - Some(elt) - }, - None => self.get_end(), - } - } - - #[inline] - fn next_inclusive(&mut self) -> Option<&'a str> { - if self.finished { - return None; - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.start is either the start of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((_, b)) => unsafe { - let elt = haystack.get_unchecked(self.start..b); - self.start = b; - Some(elt) - }, - None => self.get_end(), - } - } - - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - if self.finished { - return None; - } - - if !self.allow_trailing_empty { - self.allow_trailing_empty = true; - match self.next_back() { - Some(elt) if !elt.is_empty() => return Some(elt), - _ => { - if self.finished { - return None; - } - } - } - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. - Some((a, b)) => unsafe { - let elt = haystack.get_unchecked(b..self.end); - self.end = a; - Some(elt) - }, - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - None => unsafe { - self.finished = true; - Some(haystack.get_unchecked(self.start..self.end)) - }, - } - } - - #[inline] - fn next_back_inclusive(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - if self.finished { - return None; - } - - if !self.allow_trailing_empty { - self.allow_trailing_empty = true; - match self.next_back_inclusive() { - Some(elt) if !elt.is_empty() => return Some(elt), - _ => { - if self.finished { - return None; - } - } - } - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((_, b)) => unsafe { - let elt = haystack.get_unchecked(b..self.end); - self.end = b; - Some(elt) - }, - // SAFETY: self.start is either the start of the original string, - // or start of a substring that represents the part of the string that hasn't - // iterated yet. Either way, it is guaranteed to lie on unicode boundary. - // self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - None => unsafe { - self.finished = true; - Some(haystack.get_unchecked(self.start..self.end)) - }, - } - } -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`split`]. - /// - /// [`split`]: str::split - struct Split; - reverse: - /// Created with the method [`rsplit`]. - /// - /// [`rsplit`]: str::rsplit - struct RSplit; - stability: - #[stable(feature = "rust1", since = "1.0.0")] - internal: - SplitInternal yielding (&'a str); - delegate double ended; -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`split_terminator`]. - /// - /// [`split_terminator`]: str::split_terminator - struct SplitTerminator; - reverse: - /// Created with the method [`rsplit_terminator`]. - /// - /// [`rsplit_terminator`]: str::rsplit_terminator - struct RSplitTerminator; - stability: - #[stable(feature = "rust1", since = "1.0.0")] - internal: - SplitInternal yielding (&'a str); - delegate double ended; -} - -derive_pattern_clone! { - clone SplitNInternal - with |s| SplitNInternal { iter: s.iter.clone(), ..*s } -} - -struct SplitNInternal<'a, P: Pattern<'a>> { - iter: SplitInternal<'a, P>, - /// The number of splits remaining - count: usize, -} - -impl<'a, P> fmt::Debug for SplitNInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitNInternal") - .field("iter", &self.iter) - .field("count", &self.count) - .finish() - } -} - -impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { - #[inline] - fn next(&mut self) -> Option<&'a str> { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.get_end() - } - _ => { - self.count -= 1; - self.iter.next() - } - } - } - - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.get_end() - } - _ => { - self.count -= 1; - self.iter.next_back() - } - } - } -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`splitn`]. - /// - /// [`splitn`]: str::splitn - struct SplitN; - reverse: - /// Created with the method [`rsplitn`]. - /// - /// [`rsplitn`]: str::rsplitn - struct RSplitN; - stability: - #[stable(feature = "rust1", since = "1.0.0")] - internal: - SplitNInternal yielding (&'a str); - delegate single ended; -} - -derive_pattern_clone! { - clone MatchIndicesInternal - with |s| MatchIndicesInternal(s.0.clone()) -} - -struct MatchIndicesInternal<'a, P: Pattern<'a>>(P::Searcher); - -impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("MatchIndicesInternal").field(&self.0).finish() - } -} - -impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { - #[inline] - fn next(&mut self) -> Option<(usize, &'a str)> { - self.0 - .next_match() - // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. - .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) }) - } - - #[inline] - fn next_back(&mut self) -> Option<(usize, &'a str)> - where - P::Searcher: ReverseSearcher<'a>, - { - self.0 - .next_match_back() - // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. - .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) }) - } -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`match_indices`]. - /// - /// [`match_indices`]: str::match_indices - struct MatchIndices; - reverse: - /// Created with the method [`rmatch_indices`]. - /// - /// [`rmatch_indices`]: str::rmatch_indices - struct RMatchIndices; - stability: - #[stable(feature = "str_match_indices", since = "1.5.0")] - internal: - MatchIndicesInternal yielding ((usize, &'a str)); - delegate double ended; -} - -derive_pattern_clone! { - clone MatchesInternal - with |s| MatchesInternal(s.0.clone()) -} - -struct MatchesInternal<'a, P: Pattern<'a>>(P::Searcher); - -impl<'a, P> fmt::Debug for MatchesInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("MatchesInternal").field(&self.0).finish() - } -} - -impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { - #[inline] - fn next(&mut self) -> Option<&'a str> { - // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. - self.0.next_match().map(|(a, b)| unsafe { - // Indices are known to be on utf8 boundaries - self.0.haystack().get_unchecked(a..b) - }) - } - - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. - self.0.next_match_back().map(|(a, b)| unsafe { - // Indices are known to be on utf8 boundaries - self.0.haystack().get_unchecked(a..b) - }) - } -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`matches`]. - /// - /// [`matches`]: str::matches - struct Matches; - reverse: - /// Created with the method [`rmatches`]. - /// - /// [`rmatches`]: str::rmatches - struct RMatches; - stability: - #[stable(feature = "str_matches", since = "1.2.0")] - internal: - MatchesInternal yielding (&'a str); - delegate double ended; -} - -/// An iterator over the lines of a string, as string slices. -/// -/// This struct is created with the [`lines`] method on [`str`]. -/// See its documentation for more. -/// -/// [`lines`]: str::lines #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone, Debug)] -pub struct Lines<'a>(Map, LinesAnyMap>); +pub use error::{ParseBoolError, Utf8Error}; #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Lines<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.0.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - - #[inline] - fn last(mut self) -> Option<&'a str> { - self.next_back() - } -} +pub use traits::FromStr; #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for Lines<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.0.next_back() - } -} +pub use iter::{Bytes, CharIndices, Chars, Lines, SplitWhitespace}; -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Lines<'_> {} - -/// Created with the method [`lines_any`]. -/// -/// [`lines_any`]: str::lines_any #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")] -#[derive(Clone, Debug)] #[allow(deprecated)] -pub struct LinesAny<'a>(Lines<'a>); - -impl_fn_for_zst! { - /// A nameable, cloneable fn type - #[derive(Clone)] - struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str { - let l = line.len(); - if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] } - else { line } - }; -} +pub use iter::LinesAny; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl<'a> Iterator for LinesAny<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.0.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} +pub use iter::{RSplit, RSplitTerminator, Split, SplitTerminator}; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl<'a> DoubleEndedIterator for LinesAny<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.0.next_back() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -#[allow(deprecated)] -impl FusedIterator for LinesAny<'_> {} - -/* -Section: UTF-8 validation -*/ - -// use truncation to fit u64 into usize -const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; - -/// Returns `true` if any byte in the word `x` is nonascii (>= 128). -#[inline] -fn contains_nonascii(x: usize) -> bool { - (x & NONASCII_MASK) != 0 -} - -/// Walks through `v` checking that it's a valid UTF-8 sequence, -/// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`. -#[inline(always)] -fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { - let mut index = 0; - let len = v.len(); - - let usize_bytes = mem::size_of::(); - let ascii_block_size = 2 * usize_bytes; - let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 }; - let align = v.as_ptr().align_offset(usize_bytes); - - while index < len { - let old_offset = index; - macro_rules! err { - ($error_len: expr) => { - return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len }); - }; - } - - macro_rules! next { - () => {{ - index += 1; - // we needed data, but there was none: error! - if index >= len { - err!(None) - } - v[index] - }}; - } - - let first = v[index]; - if first >= 128 { - let w = UTF8_CHAR_WIDTH[first as usize]; - // 2-byte encoding is for codepoints \u{0080} to \u{07ff} - // first C2 80 last DF BF - // 3-byte encoding is for codepoints \u{0800} to \u{ffff} - // first E0 A0 80 last EF BF BF - // excluding surrogates codepoints \u{d800} to \u{dfff} - // ED A0 80 to ED BF BF - // 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff - // first F0 90 80 80 last F4 8F BF BF - // - // Use the UTF-8 syntax from the RFC - // - // https://tools.ietf.org/html/rfc3629 - // UTF8-1 = %x00-7F - // UTF8-2 = %xC2-DF UTF8-tail - // UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / - // %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) - // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / - // %xF4 %x80-8F 2( UTF8-tail ) - match w { - 2 => { - if next!() & !CONT_MASK != TAG_CONT_U8 { - err!(Some(1)) - } - } - 3 => { - match (first, next!()) { - (0xE0, 0xA0..=0xBF) - | (0xE1..=0xEC, 0x80..=0xBF) - | (0xED, 0x80..=0x9F) - | (0xEE..=0xEF, 0x80..=0xBF) => {} - _ => err!(Some(1)), - } - if next!() & !CONT_MASK != TAG_CONT_U8 { - err!(Some(2)) - } - } - 4 => { - match (first, next!()) { - (0xF0, 0x90..=0xBF) | (0xF1..=0xF3, 0x80..=0xBF) | (0xF4, 0x80..=0x8F) => {} - _ => err!(Some(1)), - } - if next!() & !CONT_MASK != TAG_CONT_U8 { - err!(Some(2)) - } - if next!() & !CONT_MASK != TAG_CONT_U8 { - err!(Some(3)) - } - } - _ => err!(Some(1)), - } - index += 1; - } else { - // Ascii case, try to skip forward quickly. - // When the pointer is aligned, read 2 words of data per iteration - // until we find a word containing a non-ascii byte. - if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 { - let ptr = v.as_ptr(); - while index < blocks_end { - // 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)`. - 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)); - if zu | zv { - break; - } - } - index += ascii_block_size; - } - // step from the point where the wordwise loop stopped - while index < len && v[index] < 128 { - index += 1; - } - } else { - index += 1; - } - } - } - - Ok(()) -} - -// https://tools.ietf.org/html/rfc3629 -static UTF8_CHAR_WIDTH: [u8; 256] = [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x1F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x3F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x5F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x7F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0x9F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0xBF - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, // 0xDF - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF -]; - -/// Given a first byte, determines how many bytes are in this UTF-8 character. -#[unstable(feature = "str_internals", issue = "none")] -#[inline] -pub fn utf8_char_width(b: u8) -> usize { - UTF8_CHAR_WIDTH[b as usize] as usize -} - -/// Mask of the value bits of a continuation byte. -const CONT_MASK: u8 = 0b0011_1111; -/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte. -const TAG_CONT_U8: u8 = 0b1000_0000; +pub use iter::{RSplitN, SplitN}; -/* -Section: Trait implementations -*/ - -mod traits { - use crate::cmp::Ordering; - use crate::ops; - use crate::ptr; - use crate::slice::SliceIndex; - - /// Implements ordering of strings. - /// - /// Strings are ordered lexicographically by their byte values. This orders Unicode code - /// points based on their positions in the code charts. This is not necessarily the same as - /// "alphabetical" order, which varies by language and locale. Sorting strings according to - /// culturally-accepted standards requires locale-specific data that is outside the scope of - /// the `str` type. - #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for str { - #[inline] - fn cmp(&self, other: &str) -> Ordering { - self.as_bytes().cmp(other.as_bytes()) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq for str { - #[inline] - fn eq(&self, other: &str) -> bool { - self.as_bytes() == other.as_bytes() - } - #[inline] - fn ne(&self, other: &str) -> bool { - !(*self).eq(other) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl Eq for str {} - - /// Implements comparison operations on strings. - /// - /// Strings are compared lexicographically by their byte values. This compares Unicode code - /// points based on their positions in the code charts. This is not necessarily the same as - /// "alphabetical" order, which varies by language and locale. Comparing strings according to - /// culturally-accepted standards requires locale-specific data that is outside the scope of - /// the `str` type. - #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for str { - #[inline] - fn partial_cmp(&self, other: &str) -> Option { - Some(self.cmp(other)) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl ops::Index for str - where - I: SliceIndex, - { - type Output = I::Output; - - #[inline] - fn index(&self, index: I) -> &I::Output { - index.index(self) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl ops::IndexMut for str - where - I: SliceIndex, - { - #[inline] - fn index_mut(&mut self, index: I) -> &mut I::Output { - index.index_mut(self) - } - } +#[stable(feature = "str_matches", since = "1.2.0")] +pub use iter::{Matches, RMatches}; - #[inline(never)] - #[cold] - #[track_caller] - fn str_index_overflow_fail() -> ! { - panic!("attempted to index str up to maximum usize"); - } +#[stable(feature = "str_match_indices", since = "1.5.0")] +pub use iter::{MatchIndices, RMatchIndices}; - /// Implements substring slicing with syntax `&self[..]` or `&mut self[..]`. - /// - /// Returns a slice of the whole string, i.e., returns `&self` or `&mut - /// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike - /// other indexing operations, this can never panic. - /// - /// This operation is `O(1)`. - /// - /// Prior to 1.20.0, these indexing operations were still supported by - /// direct implementation of `Index` and `IndexMut`. - /// - /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe impl SliceIndex for ops::RangeFull { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - Some(slice) - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - Some(slice) - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - slice - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - slice - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - slice - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - slice - } - } +#[stable(feature = "encode_utf16", since = "1.8.0")] +pub use iter::EncodeUtf16; - /// Implements substring slicing with syntax `&self[begin .. end]` or `&mut - /// self[begin .. end]`. - /// - /// Returns a slice of the given string from the byte range - /// [`begin`, `end`). - /// - /// This operation is `O(1)`. - /// - /// Prior to 1.20.0, these indexing operations were still supported by - /// direct implementation of `Index` and `IndexMut`. - /// - /// # Panics - /// - /// Panics if `begin` or `end` does not point to the starting byte offset of - /// a character (as defined by `is_char_boundary`), if `begin > end`, or if - /// `end > len`. - /// - /// # Examples - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// assert_eq!(&s[0 .. 1], "L"); - /// - /// assert_eq!(&s[1 .. 9], "öwe 老"); - /// - /// // these will panic: - /// // byte 2 lies within `ö`: - /// // &s[2 ..3]; - /// - /// // byte 8 lies within `老` - /// // &s[1 .. 8]; - /// - /// // byte 100 is outside the string - /// // &s[3 .. 100]; - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe impl SliceIndex for ops::Range { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if self.start <= self.end - && slice.is_char_boundary(self.start) - && slice.is_char_boundary(self.end) - { - // SAFETY: just checked that `start` and `end` are on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - // We also checked char boundaries, so this is valid UTF-8. - Some(unsafe { &*self.get_unchecked(slice) }) - } else { - None - } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.start <= self.end - && slice.is_char_boundary(self.start) - && slice.is_char_boundary(self.end) - { - // SAFETY: just checked that `start` and `end` are on a char boundary. - // We know the pointer is unique because we got it from `slice`. - Some(unsafe { &mut *self.get_unchecked_mut(slice) }) - } else { - None - } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - let slice = slice as *const [u8]; - // SAFETY: the caller guarantees that `self` is in bounds of `slice` - // which satisfies all the conditions for `add`. - let ptr = unsafe { slice.as_ptr().add(self.start) }; - let len = self.end - self.start; - ptr::slice_from_raw_parts(ptr, len) as *const str - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - let slice = slice as *mut [u8]; - // SAFETY: see comments for `get_unchecked`. - let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; - let len = self.end - self.start; - ptr::slice_from_raw_parts_mut(ptr, len) as *mut str - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - let (start, end) = (self.start, self.end); - match self.get(slice) { - Some(s) => s, - None => super::slice_error_fail(slice, start, end), - } - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - // is_char_boundary checks that the index is in [0, .len()] - // cannot reuse `get` as above, because of NLL trouble - if self.start <= self.end - && slice.is_char_boundary(self.start) - && slice.is_char_boundary(self.end) - { - // SAFETY: just checked that `start` and `end` are on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - unsafe { &mut *self.get_unchecked_mut(slice) } - } else { - super::slice_error_fail(slice, self.start, self.end) - } - } - } +#[stable(feature = "str_escape", since = "1.34.0")] +pub use iter::{EscapeDebug, EscapeDefault, EscapeUnicode}; - /// Implements substring slicing with syntax `&self[.. end]` or `&mut - /// self[.. end]`. - /// - /// Returns a slice of the given string from the byte range [`0`, `end`). - /// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`. - /// - /// This operation is `O(1)`. - /// - /// Prior to 1.20.0, these indexing operations were still supported by - /// direct implementation of `Index` and `IndexMut`. - /// - /// # Panics - /// - /// Panics if `end` does not point to the starting byte offset of a - /// character (as defined by `is_char_boundary`), or if `end > len`. - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe impl SliceIndex for ops::RangeTo { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - Some(unsafe { &*self.get_unchecked(slice) }) - } else { - None - } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - Some(unsafe { &mut *self.get_unchecked_mut(slice) }) - } else { - None - } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - let slice = slice as *const [u8]; - let ptr = slice.as_ptr(); - ptr::slice_from_raw_parts(ptr, self.end) as *const str - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - let slice = slice as *mut [u8]; - let ptr = slice.as_mut_ptr(); - ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - let end = self.end; - match self.get(slice) { - Some(s) => s, - None => super::slice_error_fail(slice, 0, end), - } - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - unsafe { &mut *self.get_unchecked_mut(slice) } - } else { - super::slice_error_fail(slice, 0, self.end) - } - } - } +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +pub use iter::SplitAsciiWhitespace; - /// Implements substring slicing with syntax `&self[begin ..]` or `&mut - /// self[begin ..]`. - /// - /// Returns a slice of the given string from the byte range [`begin`, - /// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin .. - /// len]`. - /// - /// This operation is `O(1)`. - /// - /// Prior to 1.20.0, these indexing operations were still supported by - /// direct implementation of `Index` and `IndexMut`. - /// - /// # Panics - /// - /// Panics if `begin` does not point to the starting byte offset of - /// a character (as defined by `is_char_boundary`), or if `begin > len`. - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe impl SliceIndex for ops::RangeFrom { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - Some(unsafe { &*self.get_unchecked(slice) }) - } else { - None - } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - Some(unsafe { &mut *self.get_unchecked_mut(slice) }) - } else { - None - } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - let slice = slice as *const [u8]; - // SAFETY: the caller guarantees that `self` is in bounds of `slice` - // which satisfies all the conditions for `add`. - let ptr = unsafe { slice.as_ptr().add(self.start) }; - let len = slice.len() - self.start; - ptr::slice_from_raw_parts(ptr, len) as *const str - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - let slice = slice as *mut [u8]; - // SAFETY: identical to `get_unchecked`. - let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; - let len = slice.len() - self.start; - ptr::slice_from_raw_parts_mut(ptr, len) as *mut str - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - let (start, end) = (self.start, slice.len()); - match self.get(slice) { - Some(s) => s, - None => super::slice_error_fail(slice, start, end), - } - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - unsafe { &mut *self.get_unchecked_mut(slice) } - } else { - super::slice_error_fail(slice, self.start, slice.len()) - } - } - } +#[unstable(feature = "split_inclusive", issue = "72360")] +use iter::SplitInclusive; - /// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut - /// self[begin ..= end]`. - /// - /// Returns a slice of the given string from the byte range - /// [`begin`, `end`]. Equivalent to `&self [begin .. end + 1]` or `&mut - /// self[begin .. end + 1]`, except if `end` has the maximum value for - /// `usize`. - /// - /// This operation is `O(1)`. - /// - /// # Panics - /// - /// Panics if `begin` does not point to the starting byte offset of - /// a character (as defined by `is_char_boundary`), if `end` does not point - /// to the ending byte offset of a character (`end + 1` is either a starting - /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. - #[stable(feature = "inclusive_range", since = "1.26.0")] - unsafe impl SliceIndex for ops::RangeInclusive { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if *self.end() == usize::MAX { - None - } else { - (*self.start()..self.end() + 1).get(slice) - } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if *self.end() == usize::MAX { - None - } else { - (*self.start()..self.end() + 1).get_mut(slice) - } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked`. - unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. - unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - if *self.end() == usize::MAX { - str_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index(slice) - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if *self.end() == usize::MAX { - str_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index_mut(slice) - } - } +#[unstable(feature = "str_internals", issue = "none")] +pub use validations::next_code_point; - /// Implements substring slicing with syntax `&self[..= end]` or `&mut - /// self[..= end]`. - /// - /// Returns a slice of the given string from the byte range [0, `end`]. - /// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum - /// value for `usize`. - /// - /// This operation is `O(1)`. - /// - /// # Panics - /// - /// Panics if `end` does not point to the ending byte offset of a character - /// (`end + 1` is either a starting byte offset as defined by - /// `is_char_boundary`, or equal to `len`), or if `end >= len`. - #[stable(feature = "inclusive_range", since = "1.26.0")] - unsafe impl SliceIndex for ops::RangeToInclusive { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if self.end == usize::MAX { None } else { (..self.end + 1).get(slice) } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked`. - unsafe { (..self.end + 1).get_unchecked(slice) } - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. - unsafe { (..self.end + 1).get_unchecked_mut(slice) } - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - if self.end == usize::MAX { - str_index_overflow_fail(); - } - (..self.end + 1).index(slice) - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if self.end == usize::MAX { - str_index_overflow_fail(); - } - (..self.end + 1).index_mut(slice) - } - } -} +use iter::MatchIndicesInternal; +use iter::SplitInternal; +use iter::{MatchesInternal, SplitNInternal}; -// truncate `&str` to length at most equal to `max` -// return `true` if it were truncated, and the new str. -fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) { - if max >= s.len() { - (false, s) - } else { - while !s.is_char_boundary(max) { - max -= 1; - } - (true, &s[..max]) - } -} +use validations::truncate_to_char_boundary; #[inline(never)] #[cold] @@ -4560,22 +2413,6 @@ impl str { } } -impl_fn_for_zst! { - #[derive(Clone)] - struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug { - c.escape_debug_ext(false) - }; - - #[derive(Clone)] - struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode { - c.escape_unicode() - }; - #[derive(Clone)] - struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault { - c.escape_default() - }; -} - #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[u8]> for str { #[inline] @@ -4601,45 +2438,29 @@ impl Default for &mut str { } } -/// An iterator over the non-whitespace substrings of a string, -/// separated by any amount of whitespace. -/// -/// This struct is created by the [`split_whitespace`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_whitespace`]: str::split_whitespace -#[stable(feature = "split_whitespace", since = "1.1.0")] -#[derive(Clone, Debug)] -pub struct SplitWhitespace<'a> { - inner: Filter, IsNotEmpty>, -} +impl_fn_for_zst! { + /// A nameable, cloneable fn type + #[derive(Clone)] + struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str { + let l = line.len(); + if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] } + else { line } + }; -/// An iterator over the non-ASCII-whitespace substrings of a string, -/// separated by any amount of ASCII whitespace. -/// -/// This struct is created by the [`split_ascii_whitespace`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_ascii_whitespace`]: str::split_ascii_whitespace -#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] -#[derive(Clone, Debug)] -pub struct SplitAsciiWhitespace<'a> { - inner: Map, BytesIsNotEmpty>, UnsafeBytesToStr>, -} + #[derive(Clone)] + struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug { + c.escape_debug_ext(false) + }; -/// An iterator over the substrings of a string, -/// terminated by a substring matching to a predicate function -/// Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_inclusive`]: str::split_inclusive -#[unstable(feature = "split_inclusive", issue = "72360")] -pub struct SplitInclusive<'a, P: Pattern<'a>>(SplitInternal<'a, P>); + #[derive(Clone)] + struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode { + c.escape_unicode() + }; + #[derive(Clone)] + struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault { + c.escape_default() + }; -impl_fn_for_zst! { #[derive(Clone)] struct IsWhitespace impl Fn = |c: char| -> bool { c.is_whitespace() @@ -4666,223 +2487,3 @@ impl_fn_for_zst! { unsafe { from_utf8_unchecked(bytes) } }; } - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> Iterator for SplitWhitespace<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.inner.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - - #[inline] - fn last(mut self) -> Option<&'a str> { - self.next_back() - } -} - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.inner.next_back() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SplitWhitespace<'_> {} - -#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] -impl<'a> Iterator for SplitAsciiWhitespace<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.inner.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - - #[inline] - fn last(mut self) -> Option<&'a str> { - self.next_back() - } -} - -#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] -impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.inner.next_back() - } -} - -#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] -impl FusedIterator for SplitAsciiWhitespace<'_> {} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.0.next_inclusive() - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusive").field("0", &self.0).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> { - fn clone(&self) -> Self { - SplitInclusive(self.0.clone()) - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator - for SplitInclusive<'a, P> -{ - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.0.next_back_inclusive() - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} - -/// An iterator of [`u16`] over the string encoded as UTF-16. -/// -/// This struct is created by the [`encode_utf16`] method on [`str`]. -/// See its documentation for more. -/// -/// [`encode_utf16`]: str::encode_utf16 -#[derive(Clone)] -#[stable(feature = "encode_utf16", since = "1.8.0")] -pub struct EncodeUtf16<'a> { - chars: Chars<'a>, - extra: u16, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for EncodeUtf16<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("EncodeUtf16 { .. }") - } -} - -#[stable(feature = "encode_utf16", since = "1.8.0")] -impl<'a> Iterator for EncodeUtf16<'a> { - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; 2]; - self.chars.next().map(|ch| { - let n = ch.encode_utf16(&mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.chars.size_hint(); - // every char gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for EncodeUtf16<'_> {} - -/// The return type of [`str::escape_debug`]. -#[stable(feature = "str_escape", since = "1.34.0")] -#[derive(Clone, Debug)] -pub struct EscapeDebug<'a> { - inner: Chain< - Flatten>, - FlatMap, char::EscapeDebug, CharEscapeDebugContinue>, - >, -} - -/// The return type of [`str::escape_default`]. -#[stable(feature = "str_escape", since = "1.34.0")] -#[derive(Clone, Debug)] -pub struct EscapeDefault<'a> { - inner: FlatMap, char::EscapeDefault, CharEscapeDefault>, -} - -/// The return type of [`str::escape_unicode`]. -#[stable(feature = "str_escape", since = "1.34.0")] -#[derive(Clone, Debug)] -pub struct EscapeUnicode<'a> { - inner: FlatMap, char::EscapeUnicode, CharEscapeUnicode>, -} - -macro_rules! escape_types_impls { - ($( $Name: ident ),+) => {$( - #[stable(feature = "str_escape", since = "1.34.0")] - impl<'a> fmt::Display for $Name<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.clone().try_for_each(|c| f.write_char(c)) - } - } - - #[stable(feature = "str_escape", since = "1.34.0")] - impl<'a> Iterator for $Name<'a> { - type Item = char; - - #[inline] - fn next(&mut self) -> Option { self.inner.next() } - - #[inline] - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - self.inner.try_fold(init, fold) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.inner.fold(init, fold) - } - } - - #[stable(feature = "str_escape", since = "1.34.0")] - impl<'a> FusedIterator for $Name<'a> {} - )+} -} - -escape_types_impls!(EscapeDebug, EscapeDefault, EscapeUnicode); diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 1cc2de5b87..508c522e71 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -28,7 +28,7 @@ //! assert_eq!(s.find(|c: char| c.is_ascii_punctuation()), Some(35)); //! ``` //! -//! [pattern-impls]: trait.Pattern.html#implementors +//! [pattern-impls]: Pattern#implementors #![unstable( feature = "pattern", diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs new file mode 100644 index 0000000000..4f8aa246e5 --- /dev/null +++ b/library/core/src/str/traits.rs @@ -0,0 +1,597 @@ +//! Trait implementations for `str`. + +use crate::cmp::Ordering; +use crate::ops; +use crate::ptr; +use crate::slice::SliceIndex; + +use super::ParseBoolError; + +/// Implements ordering of strings. +/// +/// Strings are ordered lexicographically by their byte values. This orders Unicode code +/// points based on their positions in the code charts. This is not necessarily the same as +/// "alphabetical" order, which varies by language and locale. Sorting strings according to +/// culturally-accepted standards requires locale-specific data that is outside the scope of +/// the `str` type. +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for str { + #[inline] + fn cmp(&self, other: &str) -> Ordering { + self.as_bytes().cmp(other.as_bytes()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for str { + #[inline] + fn eq(&self, other: &str) -> bool { + self.as_bytes() == other.as_bytes() + } + #[inline] + fn ne(&self, other: &str) -> bool { + !(*self).eq(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for str {} + +/// Implements comparison operations on strings. +/// +/// Strings are compared lexicographically by their byte values. This compares Unicode code +/// points based on their positions in the code charts. This is not necessarily the same as +/// "alphabetical" order, which varies by language and locale. Comparing strings according to +/// culturally-accepted standards requires locale-specific data that is outside the scope of +/// the `str` type. +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for str { + #[inline] + fn partial_cmp(&self, other: &str) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Index for str +where + I: SliceIndex, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::IndexMut for str +where + I: SliceIndex, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut I::Output { + index.index_mut(self) + } +} + +#[inline(never)] +#[cold] +#[track_caller] +fn str_index_overflow_fail() -> ! { + panic!("attempted to index str up to maximum usize"); +} + +/// Implements substring slicing with syntax `&self[..]` or `&mut self[..]`. +/// +/// Returns a slice of the whole string, i.e., returns `&self` or `&mut +/// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike +/// other indexing operations, this can never panic. +/// +/// This operation is `O(1)`. +/// +/// Prior to 1.20.0, these indexing operations were still supported by +/// direct implementation of `Index` and `IndexMut`. +/// +/// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. +#[stable(feature = "str_checked_slicing", since = "1.20.0")] +unsafe impl SliceIndex for ops::RangeFull { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + Some(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + Some(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + slice + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + slice + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } +} + +/// Implements substring slicing with syntax `&self[begin .. end]` or `&mut +/// self[begin .. end]`. +/// +/// Returns a slice of the given string from the byte range +/// [`begin`, `end`). +/// +/// This operation is `O(1)`. +/// +/// Prior to 1.20.0, these indexing operations were still supported by +/// direct implementation of `Index` and `IndexMut`. +/// +/// # Panics +/// +/// Panics if `begin` or `end` does not point to the starting byte offset of +/// a character (as defined by `is_char_boundary`), if `begin > end`, or if +/// `end > len`. +/// +/// # Examples +/// +/// ``` +/// let s = "Löwe 老虎 Léopard"; +/// assert_eq!(&s[0 .. 1], "L"); +/// +/// assert_eq!(&s[1 .. 9], "öwe 老"); +/// +/// // these will panic: +/// // byte 2 lies within `ö`: +/// // &s[2 ..3]; +/// +/// // byte 8 lies within `老` +/// // &s[1 .. 8]; +/// +/// // byte 100 is outside the string +/// // &s[3 .. 100]; +/// ``` +#[stable(feature = "str_checked_slicing", since = "1.20.0")] +unsafe impl SliceIndex for ops::Range { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.start <= self.end + && slice.is_char_boundary(self.start) + && slice.is_char_boundary(self.end) + { + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + // We also checked char boundaries, so this is valid UTF-8. + Some(unsafe { &*self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.start <= self.end + && slice.is_char_boundary(self.start) + && slice.is_char_boundary(self.end) + { + // SAFETY: just checked that `start` and `end` are on a char boundary. + // We know the pointer is unique because we got it from `slice`. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; + // SAFETY: the caller guarantees that `self` is in bounds of `slice` + // which satisfies all the conditions for `add`. + let ptr = unsafe { slice.as_ptr().add(self.start) }; + let len = self.end - self.start; + ptr::slice_from_raw_parts(ptr, len) as *const str + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; + // SAFETY: see comments for `get_unchecked`. + let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; + let len = self.end - self.start; + ptr::slice_from_raw_parts_mut(ptr, len) as *mut str + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, self.end); + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, start, end), + } + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + // is_char_boundary checks that the index is in [0, .len()] + // cannot reuse `get` as above, because of NLL trouble + if self.start <= self.end + && slice.is_char_boundary(self.start) + && slice.is_char_boundary(self.end) + { + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, self.end) + } + } +} + +/// Implements substring slicing with syntax `&self[.. end]` or `&mut +/// self[.. end]`. +/// +/// Returns a slice of the given string from the byte range [`0`, `end`). +/// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`. +/// +/// This operation is `O(1)`. +/// +/// Prior to 1.20.0, these indexing operations were still supported by +/// direct implementation of `Index` and `IndexMut`. +/// +/// # Panics +/// +/// Panics if `end` does not point to the starting byte offset of a +/// character (as defined by `is_char_boundary`), or if `end > len`. +#[stable(feature = "str_checked_slicing", since = "1.20.0")] +unsafe impl SliceIndex for ops::RangeTo { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end) { + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &*self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end) { + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; + let ptr = slice.as_ptr(); + ptr::slice_from_raw_parts(ptr, self.end) as *const str + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; + let ptr = slice.as_mut_ptr(); + ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end; + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, 0, end), + } + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end) + } + } +} + +/// Implements substring slicing with syntax `&self[begin ..]` or `&mut +/// self[begin ..]`. +/// +/// Returns a slice of the given string from the byte range [`begin`, +/// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin .. +/// len]`. +/// +/// This operation is `O(1)`. +/// +/// Prior to 1.20.0, these indexing operations were still supported by +/// direct implementation of `Index` and `IndexMut`. +/// +/// # Panics +/// +/// Panics if `begin` does not point to the starting byte offset of +/// a character (as defined by `is_char_boundary`), or if `begin > len`. +#[stable(feature = "str_checked_slicing", since = "1.20.0")] +unsafe impl SliceIndex for ops::RangeFrom { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.start) { + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &*self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.start) { + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; + // SAFETY: the caller guarantees that `self` is in bounds of `slice` + // which satisfies all the conditions for `add`. + let ptr = unsafe { slice.as_ptr().add(self.start) }; + let len = slice.len() - self.start; + ptr::slice_from_raw_parts(ptr, len) as *const str + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; + // SAFETY: identical to `get_unchecked`. + let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; + let len = slice.len() - self.start; + ptr::slice_from_raw_parts_mut(ptr, len) as *mut str + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, slice.len()); + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, start, end), + } + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.start) { + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, slice.len()) + } + } +} + +/// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut +/// self[begin ..= end]`. +/// +/// Returns a slice of the given string from the byte range +/// [`begin`, `end`]. Equivalent to `&self [begin .. end + 1]` or `&mut +/// self[begin .. end + 1]`, except if `end` has the maximum value for +/// `usize`. +/// +/// This operation is `O(1)`. +/// +/// # Panics +/// +/// Panics if `begin` does not point to the starting byte offset of +/// a character (as defined by `is_char_boundary`), if `end` does not point +/// to the ending byte offset of a character (`end + 1` is either a starting +/// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex for ops::RangeInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if *self.end() == usize::MAX { + None + } else { + (*self.start()..self.end() + 1).get_mut(slice) + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + if *self.end() == usize::MAX { + str_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if *self.end() == usize::MAX { + str_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index_mut(slice) + } +} + +/// Implements substring slicing with syntax `&self[..= end]` or `&mut +/// self[..= end]`. +/// +/// Returns a slice of the given string from the byte range [0, `end`]. +/// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum +/// value for `usize`. +/// +/// This operation is `O(1)`. +/// +/// # Panics +/// +/// Panics if `end` does not point to the ending byte offset of a character +/// (`end + 1` is either a starting byte offset as defined by +/// `is_char_boundary`, or equal to `len`), or if `end >= len`. +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex for ops::RangeToInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.end == usize::MAX { None } else { (..self.end + 1).get(slice) } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { (..self.end + 1).get_unchecked(slice) } + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { (..self.end + 1).get_unchecked_mut(slice) } + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + if self.end == usize::MAX { + str_index_overflow_fail(); + } + (..self.end + 1).index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if self.end == usize::MAX { + str_index_overflow_fail(); + } + (..self.end + 1).index_mut(slice) + } +} + +/// Parse a value from a string +/// +/// `FromStr`'s [`from_str`] method is often used implicitly, through +/// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples. +/// +/// [`from_str`]: FromStr::from_str +/// [`parse`]: str::parse +/// +/// `FromStr` does not have a lifetime parameter, and so you can only parse types +/// that do not contain a lifetime parameter themselves. In other words, you can +/// parse an `i32` with `FromStr`, but not a `&i32`. You can parse a struct that +/// contains an `i32`, but not one that contains an `&i32`. +/// +/// # Examples +/// +/// Basic implementation of `FromStr` on an example `Point` type: +/// +/// ``` +/// use std::str::FromStr; +/// use std::num::ParseIntError; +/// +/// #[derive(Debug, PartialEq)] +/// struct Point { +/// x: i32, +/// y: i32 +/// } +/// +/// impl FromStr for Point { +/// type Err = ParseIntError; +/// +/// fn from_str(s: &str) -> Result { +/// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) +/// .split(',') +/// .collect(); +/// +/// let x_fromstr = coords[0].parse::()?; +/// let y_fromstr = coords[1].parse::()?; +/// +/// Ok(Point { x: x_fromstr, y: y_fromstr }) +/// } +/// } +/// +/// let p = Point::from_str("(1,2)"); +/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait FromStr: Sized { + /// The associated error which can be returned from parsing. + #[stable(feature = "rust1", since = "1.0.0")] + type Err; + + /// Parses a string `s` to return a value of this type. + /// + /// If parsing succeeds, return the value inside [`Ok`], otherwise + /// when the string is ill-formatted return an error specific to the + /// inside [`Err`]. The error type is specific to implementation of the trait. + /// + /// # Examples + /// + /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`: + /// + /// [ithirtytwo]: ../../std/primitive.i32.html + /// + /// ``` + /// use std::str::FromStr; + /// + /// let s = "5"; + /// let x = i32::from_str(s).unwrap(); + /// + /// assert_eq!(5, x); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn from_str(s: &str) -> Result; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromStr for bool { + type Err = ParseBoolError; + + /// Parse a `bool` from a string. + /// + /// Yields a `Result`, because `s` may or may not + /// actually be parseable. + /// + /// # Examples + /// + /// ``` + /// use std::str::FromStr; + /// + /// assert_eq!(FromStr::from_str("true"), Ok(true)); + /// assert_eq!(FromStr::from_str("false"), Ok(false)); + /// assert!(::from_str("not even a boolean").is_err()); + /// ``` + /// + /// Note, in many cases, the `.parse()` method on `str` is more proper. + /// + /// ``` + /// assert_eq!("true".parse(), Ok(true)); + /// assert_eq!("false".parse(), Ok(false)); + /// assert!("not even a boolean".parse::().is_err()); + /// ``` + #[inline] + fn from_str(s: &str) -> Result { + match s { + "true" => Ok(true), + "false" => Ok(false), + _ => Err(ParseBoolError { _priv: () }), + } + } +} diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs new file mode 100644 index 0000000000..10cf1e172e --- /dev/null +++ b/library/core/src/str/validations.rs @@ -0,0 +1,275 @@ +//! Operations related to UTF-8 validation. + +use crate::mem; + +use super::Utf8Error; + +/// Returns the initial codepoint accumulator for the first byte. +/// The first byte is special, only want bottom 5 bits for width 2, 4 bits +/// for width 3, and 3 bits for width 4. +#[inline] +fn utf8_first_byte(byte: u8, width: u32) -> u32 { + (byte & (0x7F >> width)) as u32 +} + +/// Returns the value of `ch` updated with continuation byte `byte`. +#[inline] +fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { + (ch << 6) | (byte & CONT_MASK) as u32 +} + +/// Checks whether the byte is a UTF-8 continuation byte (i.e., starts with the +/// bits `10`). +#[inline] +pub(super) fn utf8_is_cont_byte(byte: u8) -> bool { + (byte & !CONT_MASK) == TAG_CONT_U8 +} + +#[inline] +fn unwrap_or_0(opt: Option<&u8>) -> u8 { + match opt { + Some(&byte) => byte, + None => 0, + } +} + +/// Reads the next code point out of a byte iterator (assuming a +/// UTF-8-like encoding). +#[unstable(feature = "str_internals", issue = "none")] +#[inline] +pub fn next_code_point<'a, I: Iterator>(bytes: &mut I) -> Option { + // Decode UTF-8 + let x = *bytes.next()?; + if x < 128 { + return Some(x as u32); + } + + // Multibyte case follows + // Decode from a byte combination out of: [[[x y] z] w] + // NOTE: Performance is sensitive to the exact formulation here + let init = utf8_first_byte(x, 2); + let y = unwrap_or_0(bytes.next()); + let mut ch = utf8_acc_cont_byte(init, y); + if x >= 0xE0 { + // [[x y z] w] case + // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid + let z = unwrap_or_0(bytes.next()); + let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z); + ch = init << 12 | y_z; + if x >= 0xF0 { + // [x y z w] case + // use only the lower 3 bits of `init` + let w = unwrap_or_0(bytes.next()); + ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w); + } + } + + Some(ch) +} + +/// Reads the last code point out of a byte iterator (assuming a +/// UTF-8-like encoding). +#[inline] +pub(super) fn next_code_point_reverse<'a, I>(bytes: &mut I) -> Option +where + I: DoubleEndedIterator, +{ + // Decode UTF-8 + let w = match *bytes.next_back()? { + next_byte if next_byte < 128 => return Some(next_byte as u32), + back_byte => back_byte, + }; + + // Multibyte case follows + // Decode from a byte combination out of: [x [y [z w]]] + let mut ch; + let z = unwrap_or_0(bytes.next_back()); + ch = utf8_first_byte(z, 2); + if utf8_is_cont_byte(z) { + let y = unwrap_or_0(bytes.next_back()); + ch = utf8_first_byte(y, 3); + if utf8_is_cont_byte(y) { + let x = unwrap_or_0(bytes.next_back()); + ch = utf8_first_byte(x, 4); + ch = utf8_acc_cont_byte(ch, y); + } + ch = utf8_acc_cont_byte(ch, z); + } + ch = utf8_acc_cont_byte(ch, w); + + Some(ch) +} + +// use truncation to fit u64 into usize +const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; + +/// Returns `true` if any byte in the word `x` is nonascii (>= 128). +#[inline] +fn contains_nonascii(x: usize) -> bool { + (x & NONASCII_MASK) != 0 +} + +/// Walks through `v` checking that it's a valid UTF-8 sequence, +/// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`. +#[inline(always)] +pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { + let mut index = 0; + let len = v.len(); + + let usize_bytes = mem::size_of::(); + let ascii_block_size = 2 * usize_bytes; + let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 }; + let align = v.as_ptr().align_offset(usize_bytes); + + while index < len { + let old_offset = index; + macro_rules! err { + ($error_len: expr) => { + return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len }); + }; + } + + macro_rules! next { + () => {{ + index += 1; + // we needed data, but there was none: error! + if index >= len { + err!(None) + } + v[index] + }}; + } + + let first = v[index]; + if first >= 128 { + let w = UTF8_CHAR_WIDTH[first as usize]; + // 2-byte encoding is for codepoints \u{0080} to \u{07ff} + // first C2 80 last DF BF + // 3-byte encoding is for codepoints \u{0800} to \u{ffff} + // first E0 A0 80 last EF BF BF + // excluding surrogates codepoints \u{d800} to \u{dfff} + // ED A0 80 to ED BF BF + // 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff + // first F0 90 80 80 last F4 8F BF BF + // + // Use the UTF-8 syntax from the RFC + // + // https://tools.ietf.org/html/rfc3629 + // UTF8-1 = %x00-7F + // UTF8-2 = %xC2-DF UTF8-tail + // UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / + // %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) + // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / + // %xF4 %x80-8F 2( UTF8-tail ) + match w { + 2 => { + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(1)) + } + } + 3 => { + match (first, next!()) { + (0xE0, 0xA0..=0xBF) + | (0xE1..=0xEC, 0x80..=0xBF) + | (0xED, 0x80..=0x9F) + | (0xEE..=0xEF, 0x80..=0xBF) => {} + _ => err!(Some(1)), + } + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(2)) + } + } + 4 => { + match (first, next!()) { + (0xF0, 0x90..=0xBF) | (0xF1..=0xF3, 0x80..=0xBF) | (0xF4, 0x80..=0x8F) => {} + _ => err!(Some(1)), + } + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(2)) + } + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(3)) + } + } + _ => err!(Some(1)), + } + index += 1; + } else { + // Ascii case, try to skip forward quickly. + // When the pointer is aligned, read 2 words of data per iteration + // until we find a word containing a non-ascii byte. + if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 { + let ptr = v.as_ptr(); + while index < blocks_end { + // 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)`. + 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)); + if zu | zv { + break; + } + } + index += ascii_block_size; + } + // step from the point where the wordwise loop stopped + while index < len && v[index] < 128 { + index += 1; + } + } else { + index += 1; + } + } + } + + Ok(()) +} + +// https://tools.ietf.org/html/rfc3629 +static UTF8_CHAR_WIDTH: [u8; 256] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x1F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x3F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x5F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x7F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0x9F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0xBF + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, // 0xDF + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF +]; + +/// Given a first byte, determines how many bytes are in this UTF-8 character. +#[unstable(feature = "str_internals", issue = "none")] +#[inline] +pub fn utf8_char_width(b: u8) -> usize { + UTF8_CHAR_WIDTH[b as usize] as usize +} + +/// Mask of the value bits of a continuation byte. +const CONT_MASK: u8 = 0b0011_1111; +/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte. +const TAG_CONT_U8: u8 = 0b1000_0000; + +// truncate `&str` to length at most equal to `max` +// return `true` if it were truncated, and the new str. +pub(super) fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) { + if max >= s.len() { + (false, s) + } else { + while !s.is_char_boundary(max) { + max -= 1; + } + (true, &s[..max]) + } +} diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index f31a4a0b75..5c9cfe2710 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -10,18 +10,10 @@ //! Atomic types present operations that, when used correctly, synchronize //! updates between threads. //! -//! [`AtomicBool`]: struct.AtomicBool.html -//! [`AtomicIsize`]: struct.AtomicIsize.html -//! [`AtomicUsize`]: struct.AtomicUsize.html -//! [`AtomicI8`]: struct.AtomicI8.html -//! [`AtomicU16`]: struct.AtomicU16.html -//! //! Each method takes an [`Ordering`] which represents the strength of //! the memory barrier for that operation. These orderings are the //! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2]. //! -//! [`Ordering`]: enum.Ordering.html -//! //! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order //! [2]: ../../../nomicon/atomics.html //! @@ -31,15 +23,12 @@ //! The most common way to share an atomic variable is to put it into an [`Arc`][arc] (an //! atomically-reference-counted shared pointer). //! -//! [`Sync`]: ../../marker/trait.Sync.html //! [arc]: ../../../std/sync/struct.Arc.html //! //! Atomic types may be stored in static variables, initialized using //! the constant initializers like [`AtomicBool::new`]. Atomic statics //! are often used for lazy global initialization. //! -//! [`AtomicBool::new`]: struct.AtomicBool.html#method.new -//! //! # Portability //! //! All atomic types in this module are guaranteed to be [lock-free] if they're @@ -87,7 +76,7 @@ //! fn main() { //! let spinlock = Arc::new(AtomicUsize::new(1)); //! -//! let spinlock_clone = spinlock.clone(); +//! let spinlock_clone = Arc::clone(&spinlock); //! let thread = thread::spawn(move|| { //! spinlock_clone.store(0, Ordering::SeqCst); //! }); @@ -155,8 +144,6 @@ pub fn spin_loop_hint() { /// /// **Note**: This type is only available on platforms that support atomic /// loads and stores of `u8`. -/// -/// [`bool`]: ../../../std/primitive.bool.html #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "rust1", since = "1.0.0")] #[repr(C, align(1))] @@ -212,8 +199,8 @@ unsafe impl Sync for AtomicPtr {} /// Atomic memory orderings /// /// Memory orderings specify the way atomic operations synchronize memory. -/// In its weakest [`Relaxed`][Ordering::Relaxed], only the memory directly touched by the -/// operation is synchronized. On the other hand, a store-load pair of [`SeqCst`][Ordering::SeqCst] +/// In its weakest [`Ordering::Relaxed`], only the memory directly touched by the +/// operation is synchronized. On the other hand, a store-load pair of [`Ordering::SeqCst`] /// operations synchronize other memory while additionally preserving a total order of such /// operations across all threads. /// @@ -223,8 +210,6 @@ unsafe impl Sync for AtomicPtr {} /// For more information see the [nomicon]. /// /// [nomicon]: ../../../nomicon/atomics.html -/// [Ordering::Relaxed]: #variant.Relaxed -/// [Ordering::SeqCst]: #variant.SeqCst #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[non_exhaustive] @@ -248,9 +233,6 @@ pub enum Ordering { /// /// Corresponds to [`memory_order_release`] in C++20. /// - /// [`Release`]: #variant.Release - /// [`Acquire`]: #variant.Acquire - /// [`Relaxed`]: #variant.Relaxed /// [`memory_order_release`]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering #[stable(feature = "rust1", since = "1.0.0")] Release, @@ -266,9 +248,6 @@ pub enum Ordering { /// /// Corresponds to [`memory_order_acquire`] in C++20. /// - /// [`Acquire`]: #variant.Acquire - /// [`Release`]: #variant.Release - /// [`Relaxed`]: #variant.Relaxed /// [`memory_order_acquire`]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering #[stable(feature = "rust1", since = "1.0.0")] Acquire, @@ -284,9 +263,6 @@ pub enum Ordering { /// Corresponds to [`memory_order_acq_rel`] in C++20. /// /// [`memory_order_acq_rel`]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering - /// [`Acquire`]: #variant.Acquire - /// [`Release`]: #variant.Release - /// [`Relaxed`]: #variant.Relaxed #[stable(feature = "rust1", since = "1.0.0")] AcqRel, /// Like [`Acquire`]/[`Release`]/[`AcqRel`] (for load, store, and load-with-store @@ -296,16 +272,11 @@ pub enum Ordering { /// Corresponds to [`memory_order_seq_cst`] in C++20. /// /// [`memory_order_seq_cst`]: https://en.cppreference.com/w/cpp/atomic/memory_order#Sequentially-consistent_ordering - /// [`Acquire`]: #variant.Acquire - /// [`Release`]: #variant.Release - /// [`AcqRel`]: #variant.AcqRel #[stable(feature = "rust1", since = "1.0.0")] SeqCst, } /// An [`AtomicBool`] initialized to `false`. -/// -/// [`AtomicBool`]: struct.AtomicBool.html #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated( @@ -339,8 +310,6 @@ impl AtomicBool { /// This is safe because the mutable reference guarantees that no other threads are /// concurrently accessing the atomic data. /// - /// [`bool`]: ../../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -358,6 +327,28 @@ impl AtomicBool { unsafe { &mut *(self.v.get() as *mut bool) } } + /// Get atomic access to a `&mut bool`. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let mut some_bool = true; + /// let a = AtomicBool::from_mut(&mut some_bool); + /// a.store(false, Ordering::Relaxed); + /// assert_eq!(some_bool, false); + /// ``` + #[inline] + #[cfg(target_has_atomic_equal_alignment = "8")] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut bool) -> &Self { + // SAFETY: the mutable reference guarantees unique ownership, and + // alignment of both `bool` and `Self` is 1. + unsafe { &*(v as *mut bool as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -386,13 +377,6 @@ impl AtomicBool { /// /// Panics if `order` is [`Release`] or [`AcqRel`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -419,13 +403,6 @@ impl AtomicBool { /// /// Panics if `order` is [`Acquire`] or [`AcqRel`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -456,11 +433,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -493,13 +465,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`bool`]: ../../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -539,13 +504,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`bool`]: ../../../std/primitive.bool.html - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -587,7 +545,7 @@ impl AtomicBool { /// Stores a value into the [`bool`] if the current value is the same as the `current` value. /// - /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the + /// Unlike [`AtomicBool::compare_exchange`], this function is allowed to spuriously fail even when the /// comparison succeeds, which can result in more efficient code on some platforms. The /// return value is a result indicating whether the new value was written and containing the /// previous value. @@ -603,14 +561,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`bool`]: ../../../std/primitive.bool.html - /// [`compare_exchange`]: #method.compare_exchange - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -658,11 +608,6 @@ impl AtomicBool { /// [`Acquire`] makes the store part of this operation [`Relaxed`], and /// using [`Release`] makes the load part [`Relaxed`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// @@ -706,11 +651,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -763,11 +703,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -808,11 +743,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -850,8 +780,6 @@ impl AtomicBool { /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same /// restriction: operations on it must be atomic. /// - /// [`bool`]: ../../../std/primitive.bool.html - /// /// # Examples /// /// ```ignore (extern-declaration) @@ -910,8 +838,33 @@ impl AtomicPtr { #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] pub fn get_mut(&mut self) -> &mut *mut T { - // SAFETY: the mutable reference guarantees unique ownership. - unsafe { &mut *self.p.get() } + self.p.get_mut() + } + + /// Get atomic access to a pointer. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let mut some_ptr = &mut 123 as *mut i32; + /// let a = AtomicPtr::from_mut(&mut some_ptr); + /// a.store(&mut 456, Ordering::Relaxed); + /// assert_eq!(unsafe { *some_ptr }, 456); + /// ``` + #[inline] + #[cfg(target_has_atomic_equal_alignment = "ptr")] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut *mut T) -> &Self { + use crate::mem::align_of; + let [] = [(); align_of::>() - align_of::<*mut ()>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `*mut T` and `Self` is the same on all platforms + // supported by rust, as verified above. + unsafe { &*(v as *mut *mut T as *mut Self) } } /// Consumes the atomic and returns the contained value. @@ -942,13 +895,6 @@ impl AtomicPtr { /// /// Panics if `order` is [`Release`] or [`AcqRel`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -975,13 +921,6 @@ impl AtomicPtr { /// /// Panics if `order` is [`Acquire`] or [`AcqRel`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -1013,11 +952,6 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -1052,12 +986,6 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// /// # Examples /// /// ``` @@ -1096,12 +1024,6 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -1143,7 +1065,7 @@ impl AtomicPtr { /// Stores a value into the pointer if the current value is the same as the `current` value. /// - /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the + /// Unlike [`AtomicPtr::compare_exchange`], this function is allowed to spuriously fail even when the /// comparison succeeds, which can result in more efficient code on some platforms. The /// return value is a result indicating whether the new value was written and containing the /// previous value. @@ -1159,13 +1081,6 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// - /// [`compare_exchange`]: #method.compare_exchange - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -1236,9 +1151,17 @@ impl From<*mut T> for AtomicPtr { } } +#[allow(unused_macros)] // This macro ends up being unused on some architectures. +macro_rules! if_not_8_bit { + (u8, $($tt:tt)*) => { "" }; + (i8, $($tt:tt)*) => { "" }; + ($_:ident, $($tt:tt)*) => { $($tt)* }; +} + #[cfg(target_has_atomic_load_store = "8")] macro_rules! atomic_int { ($cfg_cas:meta, + $cfg_align:meta, $stable:meta, $stable_cxchg:meta, $stable_debug:meta, @@ -1247,7 +1170,7 @@ macro_rules! atomic_int { $stable_nand:meta, $const_stable:meta, $stable_init_const:meta, - $s_int_type:expr, $int_ref:expr, + $s_int_type:literal, $int_ref:expr, $extra_feature:expr, $min_fn:ident, $max_fn:ident, $align:expr, @@ -1271,7 +1194,7 @@ macro_rules! atomic_int { #[doc = $int_ref] /// ). /// - /// [module-level documentation]: index.html + /// [module-level documentation]: crate::sync::atomic #[$stable] #[repr(C, align($align))] pub struct $atomic_type { @@ -1353,8 +1276,46 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5); #[inline] #[$stable_access] pub fn get_mut(&mut self) -> &mut $int_type { - // SAFETY: the mutable reference guarantees unique ownership. - unsafe { &mut *self.v.get() } + self.v.get_mut() + } + } + + doc_comment! { + concat!("Get atomic access to a `&mut ", stringify!($int_type), "`. + +", +if_not_8_bit! { + $int_type, + concat!( + "**Note:** This function is only available on targets where `", + stringify!($int_type), "` has an alignment of ", $align, " bytes." + ) +}, +" + +# Examples + +``` +#![feature(atomic_from_mut)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let mut some_int = 123; +let a = ", stringify!($atomic_type), "::from_mut(&mut some_int); +a.store(100, Ordering::Relaxed); +assert_eq!(some_int, 100); +``` + "), + #[inline] + #[$cfg_align] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut $int_type) -> &Self { + use crate::mem::align_of; + let [] = [(); align_of::() - align_of::<$int_type>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `$int_type` and `Self` is the + // same, as promised by $cfg_align and verified above. + unsafe { &*(v as *mut $int_type as *mut Self) } } } @@ -1389,13 +1350,6 @@ Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`]. Panics if `order` is [`Release`] or [`AcqRel`]. -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`AcqRel`]: enum.Ordering.html#variant.AcqRel -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - # Examples ``` @@ -1423,13 +1377,6 @@ assert_eq!(some_var.load(Ordering::Relaxed), 5); Panics if `order` is [`Acquire`] or [`AcqRel`]. -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`AcqRel`]: enum.Ordering.html#variant.AcqRel -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - # Examples ``` @@ -1459,11 +1406,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1498,12 +1440,6 @@ happens, and using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`AcqRel`]: enum.Ordering.html#variant.AcqRel - # Examples ``` @@ -1553,12 +1489,6 @@ and must be equivalent to or weaker than the success ordering. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - # Examples ``` @@ -1595,7 +1525,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); concat!("Stores a value into the atomic integer if the current value is the same as the `current` value. -Unlike [`compare_exchange`], this function is allowed to spuriously fail even +Unlike [`", stringify!($atomic_type), "::compare_exchange`], this function is allowed to spuriously fail even when the comparison succeeds, which can result in more efficient code on some platforms. The return value is a result indicating whether the new value was written and containing the previous value. @@ -1608,13 +1538,6 @@ of this operation [`Relaxed`], and using [`Release`] makes the successful load [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the success ordering. -[`compare_exchange`]: #method.compare_exchange -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). @@ -1662,11 +1585,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1698,11 +1616,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1737,11 +1650,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1776,11 +1684,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1816,11 +1719,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1855,11 +1753,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1890,7 +1783,7 @@ only once to the stored value. `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation. The first describes the required ordering for when the operation finally succeeds while the second describes the required ordering for loads. These correspond to the success and failure orderings of -[`compare_exchange`] respectively. +[`", stringify!($atomic_type), "::compare_exchange`] respectively. Using [`Acquire`] as success ordering makes the store part of this operation [`Relaxed`], and using [`Release`] makes the final successful load @@ -1900,14 +1793,6 @@ and must be equivalent to or weaker than the success ordering. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`bool`]: ../../../std/primitive.bool.html -[`compare_exchange`]: #method.compare_exchange -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - # Examples ```rust @@ -1954,11 +1839,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -2004,11 +1884,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -2086,6 +1961,7 @@ let mut atomic = ", stringify!($atomic_type), "::new(1); #[cfg(target_has_atomic_load_store = "8")] atomic_int! { cfg(target_has_atomic = "8"), + cfg(target_has_atomic_equal_alignment = "8"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2104,6 +1980,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "8")] atomic_int! { cfg(target_has_atomic = "8"), + cfg(target_has_atomic_equal_alignment = "8"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2122,6 +1999,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "16")] atomic_int! { cfg(target_has_atomic = "16"), + cfg(target_has_atomic_equal_alignment = "16"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2140,6 +2018,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "16")] atomic_int! { cfg(target_has_atomic = "16"), + cfg(target_has_atomic_equal_alignment = "16"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2158,6 +2037,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "32")] atomic_int! { cfg(target_has_atomic = "32"), + cfg(target_has_atomic_equal_alignment = "32"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2176,6 +2056,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "32")] atomic_int! { cfg(target_has_atomic = "32"), + cfg(target_has_atomic_equal_alignment = "32"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2194,6 +2075,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "64")] atomic_int! { cfg(target_has_atomic = "64"), + cfg(target_has_atomic_equal_alignment = "64"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2212,6 +2094,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "64")] atomic_int! { cfg(target_has_atomic = "64"), + cfg(target_has_atomic_equal_alignment = "64"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2230,6 +2113,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "128")] atomic_int! { cfg(target_has_atomic = "128"), + cfg(target_has_atomic_equal_alignment = "128"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), @@ -2248,6 +2132,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "128")] atomic_int! { cfg(target_has_atomic = "128"), + cfg(target_has_atomic_equal_alignment = "128"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), @@ -2287,6 +2172,7 @@ macro_rules! ptr_width { #[cfg(target_has_atomic_load_store = "ptr")] atomic_int! { cfg(target_has_atomic = "ptr"), + cfg(target_has_atomic_equal_alignment = "ptr"), stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), @@ -2305,6 +2191,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "ptr")] atomic_int! { cfg(target_has_atomic = "ptr"), + cfg(target_has_atomic_equal_alignment = "ptr"), stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), @@ -2660,13 +2547,6 @@ unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { /// } /// } /// ``` -/// -/// [`Ordering`]: enum.Ordering.html -/// [`Acquire`]: enum.Ordering.html#variant.Acquire -/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst -/// [`Release`]: enum.Ordering.html#variant.Release -/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel -/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn fence(order: Ordering) { @@ -2747,13 +2627,6 @@ pub fn fence(order: Ordering) { /// } /// ``` /// -/// [`fence`]: fn.fence.html -/// [`Ordering`]: enum.Ordering.html -/// [`Acquire`]: enum.Ordering.html#variant.Acquire -/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst -/// [`Release`]: enum.Ordering.html#variant.Release -/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel -/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed /// [memory barriers]: https://www.kernel.org/doc/Documentation/memory-barriers.txt #[inline] #[stable(feature = "compiler_fences", since = "1.21.0")] diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index fea396d20f..4e987a53b2 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -10,7 +10,7 @@ use crate::result::Result; #[stable(feature = "futures_api", since = "1.36.0")] pub enum Poll { /// Represents that a value is immediately ready. - #[cfg_attr(not(bootstrap), lang = "Ready")] + #[lang = "Ready"] #[stable(feature = "futures_api", since = "1.36.0")] Ready(#[stable(feature = "futures_api", since = "1.36.0")] T), @@ -19,7 +19,7 @@ pub enum Poll { /// When a function returns `Pending`, the function *must* also /// ensure that the current task is scheduled to be awoken when /// progress can be made. - #[cfg_attr(not(bootstrap), lang = "Pending")] + #[lang = "Pending"] #[stable(feature = "futures_api", since = "1.36.0")] Pending, } @@ -112,6 +112,14 @@ impl Poll>> { #[stable(feature = "futures_api", since = "1.36.0")] impl From for Poll { + /// Convert to a `Ready` variant. + /// + /// # Example + /// + /// ``` + /// # use core::task::Poll; + /// assert_eq!(Poll::from(true), Poll::Ready(true)); + /// ``` fn from(t: T) -> Poll { Poll::Ready(t) } diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index d4e733eb2b..e221aaf3fd 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -5,7 +5,6 @@ /// # Examples /// /// ``` -/// #![feature(future_readiness_fns)] /// #![feature(ready_macro)] /// /// use core::task::{ready, Context, Poll}; @@ -27,7 +26,6 @@ /// The `ready!` call expands to: /// /// ``` -/// # #![feature(future_readiness_fns)] /// # #![feature(ready_macro)] /// # /// # use core::task::{Context, Poll}; diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 92057209d8..ba3fb35caa 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -8,10 +8,8 @@ use crate::marker::{PhantomData, Unpin}; /// /// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table /// -/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that -/// customizes the behavior of the `RawWaker`. -/// -/// [`Waker`]: struct.Waker.html +/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] +/// that customizes the behavior of the `RawWaker`. #[derive(PartialEq, Debug)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct RawWaker { @@ -52,12 +50,10 @@ impl RawWaker { /// The pointer passed to all functions inside the vtable is the `data` pointer /// from the enclosing [`RawWaker`] object. /// -/// The functions inside this struct are only intended be called on the `data` +/// The functions inside this struct are only intended to be called on the `data` /// 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. -/// -/// [`RawWaker`]: struct.RawWaker.html #[stable(feature = "futures_api", since = "1.36.0")] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { @@ -68,9 +64,6 @@ pub struct RawWakerVTable { /// required for this additional instance of a [`RawWaker`] and associated /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup /// of the same task that would have been awoken by the original [`RawWaker`]. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html clone: unsafe fn(*const ()) -> RawWaker, /// This function will be called when `wake` is called on the [`Waker`]. @@ -79,9 +72,6 @@ pub struct RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html wake: unsafe fn(*const ()), /// This function will be called when `wake_by_ref` is called on the [`Waker`]. @@ -89,9 +79,6 @@ pub struct RawWakerVTable { /// /// This function is similar to `wake`, but must not consume the provided data /// pointer. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html wake_by_ref: unsafe fn(*const ()), /// This function gets called when a [`RawWaker`] gets dropped. @@ -99,8 +86,6 @@ pub struct RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - /// - /// [`RawWaker`]: struct.RawWaker.html drop: unsafe fn(*const ()), } @@ -142,18 +127,11 @@ impl RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] - // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else - // without first consulting with T-Lang. - // - // FIXME: remove whenever we have a stable way to accept fn pointers from const fn - // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062) - #[rustc_allow_const_fn_ptr] #[rustc_const_stable(feature = "futures_api", since = "1.36.0")] + #[cfg_attr(not(bootstrap), allow_internal_unstable(const_fn_fn_ptr_basics))] + #[cfg_attr(bootstrap, rustc_allow_const_fn_ptr)] pub const fn new( clone: unsafe fn(*const ()) -> RawWaker, wake: unsafe fn(*const ()), @@ -208,8 +186,6 @@ impl fmt::Debug for Context<'_> { /// executor-specific wakeup behavior. /// /// Implements [`Clone`], [`Send`], and [`Sync`]. -/// -/// [`RawWaker`]: struct.RawWaker.html #[repr(transparent)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { @@ -275,9 +251,6 @@ impl Waker { /// The behavior of the returned `Waker` is undefined if the contract defined /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. /// Therefore this method is unsafe. - /// - /// [`RawWaker`]: struct.RawWaker.html - /// [`RawWakerVTable`]: struct.RawWakerVTable.html #[inline] #[stable(feature = "futures_api", since = "1.36.0")] pub unsafe fn from_raw(waker: RawWaker) -> Waker { diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 5741f8a53b..6dc542dee5 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -108,6 +108,34 @@ impl Duration { #[unstable(feature = "duration_constants", issue = "57391")] pub const NANOSECOND: Duration = Duration::from_nanos(1); + /// The minimum duration. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MIN, Duration::new(0, 0)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MIN: Duration = Duration::from_nanos(0); + + /// The maximum duration. + /// + /// It is roughly equal to a duration of 584,942,417,355 years. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MAX, Duration::new(u64::MAX, 1_000_000_000 - 1)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MAX: Duration = Duration::new(u64::MAX, NANOS_PER_SEC - 1); + /// Creates a new `Duration` from the specified number of whole seconds and /// additional nanoseconds. /// @@ -450,6 +478,29 @@ impl Duration { } } + /// Saturating `Duration` addition. Computes `self + other`, returning [`Duration::MAX`] + /// if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); + /// assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_add(self, rhs: Duration) -> Duration { + match self.checked_add(rhs) { + Some(res) => res, + None => Duration::MAX, + } + } + /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] /// if the result would be negative or if overflow occurred. /// @@ -485,6 +536,29 @@ impl Duration { } } + /// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::MIN`] + /// if the result would be negative or if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 1).saturating_sub(Duration::new(0, 0)), Duration::new(0, 1)); + /// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::MIN); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_sub(self, rhs: Duration) -> Duration { + match self.checked_sub(rhs) { + Some(res) => res, + None => Duration::MIN, + } + } + /// Checked `Duration` multiplication. Computes `self * other`, returning /// [`None`] if overflow occurred. /// @@ -515,6 +589,29 @@ impl Duration { None } + /// Saturating `Duration` multiplication. Computes `self * other`, returning + /// [`Duration::MAX`] if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 500_000_001).saturating_mul(2), Duration::new(1, 2)); + /// assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_mul(self, rhs: u32) -> Duration { + match self.checked_mul(rhs) { + Some(res) => res, + None => Duration::MAX, + } + } + /// Checked `Duration` division. Computes `self / other`, returning [`None`] /// if `other == 0`. /// @@ -596,7 +693,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn from_secs_f64(secs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn from_secs_f64(secs: f64) -> Duration { const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64; let nanos = secs * (NANOS_PER_SEC as f64); if !nanos.is_finite() { @@ -630,7 +728,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn from_secs_f32(secs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn from_secs_f32(secs: f32) -> Duration { const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32; let nanos = secs * (NANOS_PER_SEC as f32); if !nanos.is_finite() { @@ -664,7 +763,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn mul_f64(self, rhs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn mul_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(rhs * self.as_secs_f64()) } @@ -685,7 +785,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn mul_f32(self, rhs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn mul_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(rhs * self.as_secs_f32()) } @@ -705,7 +806,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn div_f64(self, rhs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn div_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(self.as_secs_f64() / rhs) } @@ -727,7 +829,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn div_f32(self, rhs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn div_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(self.as_secs_f32() / rhs) } diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 5aba1a5d95..89c2a969c2 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -1,4 +1,4 @@ -use core::array::{FixedSizeArray, IntoIter}; +use core::array::{self, FixedSizeArray, IntoIter}; use core::convert::TryFrom; #[test] @@ -19,6 +19,21 @@ fn fixed_size_array() { assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0); } +#[test] +fn array_from_ref() { + let value: String = "Hello World!".into(); + let arr: &[String; 1] = array::from_ref(&value); + assert_eq!(&[value.clone()], arr); +} + +#[test] +fn array_from_mut() { + let mut value: String = "Hello World".into(); + let arr: &mut [String; 1] = array::from_mut(&mut value); + arr[0].push_str("!"); + assert_eq!(&value, "Hello World!"); +} + #[test] fn array_try_from() { macro_rules! test { @@ -330,3 +345,32 @@ fn array_map_drop_safety() { assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create); panic!("test succeeded") } + +#[test] +fn cell_allows_array_cycle() { + use core::cell::Cell; + + #[derive(Debug)] + struct B<'a> { + a: [Cell>>; 2], + } + + impl<'a> B<'a> { + fn new() -> B<'a> { + B { a: [Cell::new(None), Cell::new(None)] } + } + } + + let b1 = B::new(); + let b2 = B::new(); + let b3 = B::new(); + + b1.a[0].set(Some(&b2)); + b1.a[1].set(Some(&b3)); + + b2.a[0].set(Some(&b2)); + b2.a[1].set(Some(&b3)); + + b3.a[0].set(Some(&b1)); + b3.a[1].set(Some(&b2)); +} diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 0b97508394..3244bbc2d6 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -397,3 +397,14 @@ fn test_is_ascii_align_size_thoroughly() { } } } + +#[test] +fn ascii_const() { + // test that the `is_ascii` methods of `char` and `u8` are usable in a const context + + const CHAR_IS_ASCII: bool = 'a'.is_ascii(); + assert!(CHAR_IS_ASCII); + + const BYTE_IS_ASCII: bool = 97u8.is_ascii(); + assert!(BYTE_IS_ASCII); +} diff --git a/library/core/tests/cell.rs b/library/core/tests/cell.rs index 801b60be0f..40be01f443 100644 --- a/library/core/tests/cell.rs +++ b/library/core/tests/cell.rs @@ -303,6 +303,53 @@ fn cell_into_inner() { assert_eq!("Hello world".to_owned(), cell.into_inner()); } +#[test] +fn cell_exterior() { + #[derive(Copy, Clone)] + #[allow(dead_code)] + struct Point { + x: isize, + y: isize, + z: isize, + } + + fn f(p: &Cell) { + assert_eq!(p.get().z, 12); + p.set(Point { x: 10, y: 11, z: 13 }); + assert_eq!(p.get().z, 13); + } + + let a = Point { x: 10, y: 11, z: 12 }; + let b = &Cell::new(a); + assert_eq!(b.get().z, 12); + f(b); + assert_eq!(a.z, 12); + assert_eq!(b.get().z, 13); +} + +#[test] +fn cell_does_not_clone() { + #[derive(Copy)] + #[allow(dead_code)] + struct Foo { + x: isize, + } + + impl Clone for Foo { + fn clone(&self) -> Foo { + // Using Cell in any way should never cause clone() to be + // invoked -- after all, that would permit evil user code to + // abuse `Cell` and trigger crashes. + + panic!(); + } + } + + let x = Cell::new(Foo { x: 22 }); + let _y = x.get(); + let _z = x.clone(); +} + #[test] fn refcell_default() { let cell: RefCell = Default::default(); @@ -367,3 +414,11 @@ fn refcell_replace_borrows() { let _b = x.borrow(); x.replace(1); } + +#[test] +fn refcell_format() { + let name = RefCell::new("rust"); + let what = RefCell::new("rocks"); + let msg = format!("{name} {}", &*what.borrow(), name = &*name.borrow()); + assert_eq!(msg, "rust rocks".to_string()); +} diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 4086917780..835289daf7 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -1,4 +1,7 @@ -use core::cmp::{self, Ordering::*}; +use core::cmp::{ + self, + Ordering::{self, *}, +}; #[test] fn test_int_totalord() { @@ -116,3 +119,16 @@ fn test_user_defined_eq() { assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 }); assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 }); } + +#[test] +fn ordering_const() { + // test that the methods of `Ordering` are usable in a const context + + const ORDERING: Ordering = Greater; + + const REVERSE: Ordering = ORDERING.reverse(); + assert_eq!(REVERSE, Less); + + const THEN: Ordering = Equal.then(ORDERING); + assert_eq!(THEN, Greater); +} diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs index fed7c4a5bf..de163a60c9 100644 --- a/library/core/tests/intrinsics.rs +++ b/library/core/tests/intrinsics.rs @@ -1,4 +1,5 @@ use core::any::TypeId; +use core::intrinsics::assume; #[test] fn test_typeid_sized_types() { @@ -20,3 +21,17 @@ fn test_typeid_unsized_types() { assert_eq!(TypeId::of::(), TypeId::of::()); assert!(TypeId::of::() != TypeId::of::()); } + +// Check that `const_assume` feature allow `assume` intrinsic +// to be used in const contexts. +#[test] +fn test_assume_can_be_in_const_contexts() { + const unsafe fn foo(x: usize, y: usize) -> usize { + // SAFETY: the entire function is not safe, + // but it is just an example not used elsewhere. + unsafe { assume(y != 0) }; + x / y + } + let rs = unsafe { foo(42, 97) }; + assert_eq!(rs, 0); +} diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 00e3972c42..b15d6d1b1f 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -376,6 +376,103 @@ fn test_zip_next_back_side_effects_exhausted() { assert_eq!(b, vec![200, 300, 400]); } +#[derive(Debug)] +struct CountClone(Cell); + +fn count_clone() -> CountClone { + CountClone(Cell::new(0)) +} + +impl PartialEq for CountClone { + fn eq(&self, rhs: &i32) -> bool { + self.0.get() == *rhs + } +} + +impl Clone for CountClone { + fn clone(&self) -> Self { + let ret = CountClone(self.0.clone()); + let n = self.0.get(); + self.0.set(n + 1); + ret + } +} + +#[test] +fn test_zip_cloned_sideffectful() { + let xs = [count_clone(), count_clone(), count_clone(), count_clone()]; + let ys = [count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} + + assert_eq!(&xs, &[1, 1, 1, 0][..]); + assert_eq!(&ys, &[1, 1][..]); + + let xs = [count_clone(), count_clone()]; + let ys = [count_clone(), count_clone(), count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} + + assert_eq!(&xs, &[1, 1][..]); + assert_eq!(&ys, &[1, 1, 0, 0][..]); +} + +#[test] +fn test_zip_map_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} + + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + assert_eq!(&ys, &[1, 1, 1, 1]); + + let mut xs = [0; 4]; + let mut ys = [0; 6]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} + + assert_eq!(&xs, &[1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); +} + +#[test] +fn test_zip_map_rev_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + it.next_back(); + } + assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); + assert_eq!(&ys, &[0, 0, 0, 1]); + + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + (&mut it).take(5).count(); + it.next_back(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1]); +} + +#[test] +fn test_zip_nested_sideffectful() { + let mut xs = [0; 6]; + let ys = [0; 4]; + + { + // test that it has the side effect nested inside enumerate + let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); + it.count(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); +} + #[test] fn test_zip_nth_back_side_effects_exhausted() { let mut a = Vec::new(); @@ -474,7 +571,7 @@ fn test_iterator_step_by_nth_overflow() { } let mut it = Test(0); - let root = usize::MAX >> (::std::mem::size_of::() * 8 / 2); + let root = usize::MAX >> (usize::BITS / 2); let n = root + 20; (&mut it).step_by(n).nth(n); assert_eq!(it.0, n as Bigger * n as Bigger); @@ -1473,6 +1570,66 @@ fn test_iterator_rev_nth() { assert_eq!(v.iter().rev().nth(v.len()), None); } +#[test] +fn test_iterator_advance_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.next().unwrap(), &v[i]); + assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_advance_back_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]); + assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_back_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_rev_advance_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter().rev(); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]); + assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().rev().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_rev_advance_back_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter().rev(); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.next_back().unwrap(), &v[i]); + assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len())); +} + #[test] fn test_iterator_last() { let v: &[_] = &[0, 1, 2, 3, 4]; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 81e621318e..0c4ce867f5 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,14 +1,24 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] +#![feature(array_from_ref)] +#![feature(array_methods)] #![feature(array_map)] +#![feature(array_windows)] #![feature(bool_to_option)] #![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] +#![feature(const_assume)] +#![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(debug_non_exhaustive)] #![feature(dec2flt)] +#![feature(div_duration)] +#![feature(duration_consts_2)] +#![feature(duration_constants)] +#![feature(duration_saturating_ops)] +#![feature(duration_zero)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] #![feature(flt2dec)] @@ -31,11 +41,14 @@ #![feature(slice_partition_dedup)] #![feature(int_error_matching)] #![feature(array_value_iter)] +#![feature(iter_advance_by)] #![feature(iter_partition_in_place)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] #![feature(cmp_min_max_by)] #![feature(iter_map_while)] +#![feature(const_mut_refs)] +#![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] #![feature(never_type)] @@ -45,6 +58,7 @@ #![feature(partition_point)] #![feature(once_cell)] #![feature(unsafe_block_in_unsafe_fn)] +#![feature(int_bits_const)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; @@ -71,6 +85,7 @@ mod num; mod ops; mod option; mod pattern; +mod pin; mod ptr; mod result; mod slice; diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs index 48aec6d718..825e5e63b5 100644 --- a/library/core/tests/nonzero.rs +++ b/library/core/tests/nonzero.rs @@ -195,3 +195,20 @@ fn test_nonzero_from_int_on_err() { assert!(NonZeroI8::try_from(0).is_err()); assert!(NonZeroI32::try_from(0).is_err()); } + +#[test] +fn nonzero_const() { + // test that the methods of `NonZeroX>` are usable in a const context + // Note: only tests NonZero8 + + const NONZERO: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; + + const GET: u8 = NONZERO.get(); + assert_eq!(GET, 5); + + const ZERO: Option = NonZeroU8::new(0); + assert!(ZERO.is_none()); + + const ONE: Option = NonZeroU8::new(1); + assert!(ONE.is_some()); +} diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs index ae892e3b0b..8e95249a79 100644 --- a/library/core/tests/num/flt2dec/mod.rs +++ b/library/core/tests/num/flt2dec/mod.rs @@ -1,3 +1,4 @@ +use std::mem::MaybeUninit; use std::{fmt, str}; use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded}; @@ -36,20 +37,20 @@ macro_rules! check_shortest { ); ($f:ident($v:expr) => $buf:expr, $exp:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ - let mut buf = [b'_'; MAX_SIG_DIGITS]; - let (len, k) = $f(&decode_finite($v), &mut buf); - assert!((&buf[..len], k) == ($buf, $exp), - $fmt, actual = (str::from_utf8(&buf[..len]).unwrap(), k), + let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; + let (buf, k) = $f(&decode_finite($v), &mut buf); + assert!((buf, k) == ($buf, $exp), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), expected = (str::from_utf8($buf).unwrap(), $exp), $($key = $val),*); }); ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ - let mut buf = [b'_'; MAX_SIG_DIGITS]; - let (len, k) = $f(&Decoded { $($k: $v),+ }, &mut buf); - assert!((&buf[..len], k) == ($buf, $exp), - $fmt, actual = (str::from_utf8(&buf[..len]).unwrap(), k), + let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; + let (buf, k) = $f(&Decoded { $($k: $v),+ }, &mut buf); + assert!((buf, k) == ($buf, $exp), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), expected = (str::from_utf8($buf).unwrap(), $exp), $($key = $val),*); }) @@ -58,9 +59,9 @@ macro_rules! check_shortest { macro_rules! try_exact { ($f:ident($decoded:expr) => $buf:expr, $expected:expr, $expectedk:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ - let (len, k) = $f($decoded, &mut $buf[..$expected.len()], i16::MIN); - assert!((&$buf[..len], k) == ($expected, $expectedk), - $fmt, actual = (str::from_utf8(&$buf[..len]).unwrap(), k), + let (buf, k) = $f($decoded, &mut $buf[..$expected.len()], i16::MIN); + assert!((buf, k) == ($expected, $expectedk), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), expected = (str::from_utf8($expected).unwrap(), $expectedk), $($key = $val),*); }) @@ -69,9 +70,9 @@ macro_rules! try_exact { macro_rules! try_fixed { ($f:ident($decoded:expr) => $buf:expr, $request:expr, $expected:expr, $expectedk:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ - let (len, k) = $f($decoded, &mut $buf[..], $request); - assert!((&$buf[..len], k) == ($expected, $expectedk), - $fmt, actual = (str::from_utf8(&$buf[..len]).unwrap(), k), + let (buf, k) = $f($decoded, &mut $buf[..], $request); + assert!((buf, k) == ($expected, $expectedk), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), expected = (str::from_utf8($expected).unwrap(), $expectedk), $($key = $val),*); }) @@ -93,10 +94,10 @@ fn ldexp_f64(a: f64, b: i32) -> f64 { fn check_exact(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16) where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { // use a large enough buffer - let mut buf = [b'_'; 1024]; + let mut buf = [MaybeUninit::new(b'_'); 1024]; let mut expected_ = [b'_'; 1024]; let decoded = decode_finite(v); @@ -118,7 +119,7 @@ where // we should always return `100..00` (`i` digits) instead, since that's // what we can came up with `i` digits anyway. `round_up` assumes that // the adjustment to the length is done by caller, which we simply ignore. - if let Some(_) = round_up(&mut expected_, i) { + if let Some(_) = round_up(&mut expected_[..i]) { expectedk_ += 1; } } @@ -193,10 +194,10 @@ impl TestableFloat for f64 { fn check_exact_one(mut f: F, x: i64, e: isize, tstr: &str, expected: &[u8], expectedk: i16) where T: TestableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { // use a large enough buffer - let mut buf = [b'_'; 1024]; + let mut buf = [MaybeUninit::new(b'_'); 1024]; let v: T = TestableFloat::ldexpi(x, e); let decoded = decode_finite(v); @@ -230,7 +231,7 @@ macro_rules! check_exact_one { pub fn f32_shortest_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { // 0.0999999940395355224609375 // 0.100000001490116119384765625 @@ -277,7 +278,7 @@ where pub fn f32_exact_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { let minf32 = ldexp_f32(1.0, -149); @@ -321,7 +322,7 @@ where pub fn f64_shortest_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { // 0.0999999999999999777955395074968691915273... // 0.1000000000000000055511151231257827021181... @@ -387,7 +388,7 @@ where pub fn f64_exact_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { let minf64 = ldexp_f64(1.0, -1074); @@ -474,7 +475,7 @@ where pub fn more_shortest_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, exp: 0, inclusive: true} => b"1", 18); @@ -484,10 +485,10 @@ where fn to_string_with_parts(mut f: F) -> String where - F: for<'a> FnMut(&'a mut [u8], &'a mut [Part<'a>]) -> Formatted<'a>, + F: for<'a> FnMut(&'a mut [MaybeUninit], &'a mut [MaybeUninit>]) -> Formatted<'a>, { - let mut buf = [0; 1024]; - let mut parts = [Part::Zero(0); 16]; + let mut buf = [MaybeUninit::new(0); 1024]; + let mut parts = [MaybeUninit::new(Part::Zero(0)); 16]; let formatted = f(&mut buf, &mut parts); let mut ret = vec![0; formatted.len()]; assert_eq!(formatted.write(&mut ret), Some(ret.len())); @@ -496,14 +497,14 @@ where pub fn to_shortest_str_test(mut f_: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { to_string_with_parts(|buf, parts| { to_shortest_str(|d, b| f(d, b), v, sign, frac_digits, buf, parts) @@ -597,14 +598,14 @@ where pub fn to_shortest_exp_str_test(mut f_: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: bool) -> String where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { to_string_with_parts(|buf, parts| { to_shortest_exp_str(|d, b| f(d, b), v, sign, exp_bounds, upper, buf, parts) @@ -716,14 +717,14 @@ where pub fn to_exact_exp_str_test(mut f_: F) where - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) -> String where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { to_string_with_parts(|buf, parts| { to_exact_exp_str(|d, b, l| f(d, b, l), v, sign, ndigits, upper, buf, parts) @@ -989,14 +990,14 @@ where pub fn to_exact_fixed_str_test(mut f_: F) where - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { to_string_with_parts(|buf, parts| { to_exact_fixed_str(|d, b, l| f(d, b, l), v, sign, frac_digits, buf, parts) diff --git a/library/core/tests/num/flt2dec/random.rs b/library/core/tests/num/flt2dec/random.rs index e5656eb204..57b3dcf8e1 100644 --- a/library/core/tests/num/flt2dec/random.rs +++ b/library/core/tests/num/flt2dec/random.rs @@ -1,5 +1,6 @@ #![cfg(not(target_arch = "wasm32"))] +use std::mem::MaybeUninit; use std::str; use core::num::flt2dec::strategy::grisu::format_exact_opt; @@ -20,8 +21,8 @@ pub fn decode_finite(v: T) -> Decoded { fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) where - F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), V: FnMut(usize) -> Decoded, { assert!(k <= 1024); @@ -42,11 +43,11 @@ where } let decoded = v(i); - let mut buf1 = [0; 1024]; - if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) { - let mut buf2 = [0; 1024]; - let (len2, e2) = g(&decoded, &mut buf2[..k]); - if e1 == e2 && &buf1[..len1] == &buf2[..len2] { + let mut buf1 = [MaybeUninit::new(0); 1024]; + if let Some((buf1, e1)) = f(&decoded, &mut buf1[..k]) { + let mut buf2 = [MaybeUninit::new(0); 1024]; + let (buf2, e2) = g(&decoded, &mut buf2[..k]); + if e1 == e2 && buf1 == buf2 { npassed += 1; } else { println!( @@ -54,9 +55,9 @@ where i, n, decoded, - str::from_utf8(&buf1[..len1]).unwrap(), + str::from_utf8(buf1).unwrap(), e1, - str::from_utf8(&buf2[..len2]).unwrap(), + str::from_utf8(buf2).unwrap(), e2 ); } @@ -85,8 +86,8 @@ where pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) where - F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { if cfg!(target_os = "emscripten") { return; // using rng pulls in i128 support, which doesn't work @@ -101,8 +102,8 @@ where pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) where - F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { if cfg!(target_os = "emscripten") { return; // using rng pulls in i128 support, which doesn't work @@ -117,8 +118,8 @@ where pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) where - F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, // so why not simply testing all of them? diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs index 39250ee84b..4acc760ffa 100644 --- a/library/core/tests/num/i32.rs +++ b/library/core/tests/num/i32.rs @@ -1 +1,30 @@ int_module!(i32, i32); + +#[test] +fn test_arith_operation() { + let a: isize = 10; + assert_eq!(a * (a - 1), 90); + let i32_a: isize = 10; + assert_eq!(i32_a, 10); + assert_eq!(i32_a - 10, 0); + assert_eq!(i32_a / 10, 1); + assert_eq!(i32_a - 20, -10); + assert_eq!(i32_a << 10, 10240); + assert_eq!(i32_a << 16, 655360); + assert_eq!(i32_a * 16, 160); + assert_eq!(i32_a * i32_a * i32_a, 1000); + assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); + assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); + assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); + let i32_b: isize = 0x10101010; + assert_eq!(i32_b + 1 - 1, i32_b); + assert_eq!(i32_b << 1, i32_b << 1); + assert_eq!(i32_b >> 1, i32_b >> 1); + assert_eq!(i32_b & i32_b << 1, 0); + assert_eq!(i32_b | i32_b << 1, 0x30303030); + let i32_c: isize = 0x10101010; + assert_eq!( + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3) + ); +} diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 58a5856691..27e6760e7c 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -2,7 +2,6 @@ macro_rules! int_module { ($T:ident, $T_i:ident) => { #[cfg(test)] mod tests { - use core::mem; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T_i::*; @@ -82,30 +81,27 @@ macro_rules! int_module { #[test] fn test_count_zeros() { - let bits = mem::size_of::<$T>() * 8; - assert_eq!(A.count_zeros(), bits as u32 - 3); - assert_eq!(B.count_zeros(), bits as u32 - 2); - assert_eq!(C.count_zeros(), bits as u32 - 5); + assert_eq!(A.count_zeros(), $T::BITS - 3); + assert_eq!(B.count_zeros(), $T::BITS - 2); + assert_eq!(C.count_zeros(), $T::BITS - 5); } #[test] fn test_leading_trailing_ones() { - let bits = (mem::size_of::<$T>() * 8) as u32; - let a: $T = 0b0101_1111; assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), bits - 7); + assert_eq!((!a).leading_ones(), $T::BITS - 7); assert_eq!(a.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), bits); - assert_eq!(_1.trailing_ones(), bits); + assert_eq!(_1.leading_ones(), $T::BITS); + assert_eq!(_1.trailing_ones(), $T::BITS); assert_eq!((_1 << 1).trailing_ones(), 0); assert_eq!(MAX.leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), bits - 1); - assert_eq!(MAX.trailing_ones(), bits - 1); + assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq!(MAX.trailing_ones(), $T::BITS - 1); assert_eq!(_0.leading_ones(), 0); assert_eq!(_0.trailing_ones(), 0); diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 939f1325c8..378c8af344 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -634,14 +634,18 @@ assume_usize_width! { macro_rules! test_float { ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname { - // FIXME(nagisa): these tests should test for sign of -0.0 #[test] fn min() { assert_eq!((0.0 as $fty).min(0.0), 0.0); + assert!((0.0 as $fty).min(0.0).is_sign_positive()); assert_eq!((-0.0 as $fty).min(-0.0), -0.0); + assert!((-0.0 as $fty).min(-0.0).is_sign_negative()); assert_eq!((9.0 as $fty).min(9.0), 9.0); assert_eq!((-9.0 as $fty).min(0.0), -9.0); assert_eq!((0.0 as $fty).min(9.0), 0.0); + assert!((0.0 as $fty).min(9.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).min(9.0), -0.0); + assert!((-0.0 as $fty).min(9.0).is_sign_negative()); assert_eq!((-0.0 as $fty).min(-9.0), -9.0); assert_eq!(($inf as $fty).min(9.0), 9.0); assert_eq!((9.0 as $fty).min($inf), 9.0); @@ -660,11 +664,19 @@ macro_rules! test_float { #[test] fn max() { assert_eq!((0.0 as $fty).max(0.0), 0.0); + assert!((0.0 as $fty).max(0.0).is_sign_positive()); assert_eq!((-0.0 as $fty).max(-0.0), -0.0); + assert!((-0.0 as $fty).max(-0.0).is_sign_negative()); assert_eq!((9.0 as $fty).max(9.0), 9.0); assert_eq!((-9.0 as $fty).max(0.0), 0.0); + assert!((-9.0 as $fty).max(0.0).is_sign_positive()); + assert_eq!((-9.0 as $fty).max(-0.0), -0.0); + assert!((-9.0 as $fty).max(-0.0).is_sign_negative()); assert_eq!((0.0 as $fty).max(9.0), 9.0); + assert_eq!((0.0 as $fty).max(-9.0), 0.0); + assert!((0.0 as $fty).max(-9.0).is_sign_positive()); assert_eq!((-0.0 as $fty).max(-9.0), -0.0); + assert!((-0.0 as $fty).max(-9.0).is_sign_negative()); assert_eq!(($inf as $fty).max(9.0), $inf); assert_eq!((9.0 as $fty).max($inf), $inf); assert_eq!(($inf as $fty).max(-9.0), $inf); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index b84a8a7d9f..952ec188dc 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -4,7 +4,6 @@ macro_rules! uint_module { mod tests { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T_i::*; - use std::mem; use std::str::FromStr; use crate::num; @@ -47,30 +46,27 @@ macro_rules! uint_module { #[test] fn test_count_zeros() { - let bits = mem::size_of::<$T>() * 8; - assert!(A.count_zeros() == bits as u32 - 3); - assert!(B.count_zeros() == bits as u32 - 2); - assert!(C.count_zeros() == bits as u32 - 5); + assert!(A.count_zeros() == $T::BITS - 3); + assert!(B.count_zeros() == $T::BITS - 2); + assert!(C.count_zeros() == $T::BITS - 5); } #[test] fn test_leading_trailing_ones() { - let bits = (mem::size_of::<$T>() * 8) as u32; - let a: $T = 0b0101_1111; assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), bits - 7); + assert_eq!((!a).leading_ones(), $T::BITS - 7); assert_eq!(a.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), bits); - assert_eq!(_1.trailing_ones(), bits); + assert_eq!(_1.leading_ones(), $T::BITS); + assert_eq!(_1.trailing_ones(), $T::BITS); assert_eq!((_1 << 1).trailing_ones(), 0); assert_eq!((_1 >> 1).leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), bits - 1); - assert_eq!((_1 >> 1).trailing_ones(), bits - 1); + assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq!((_1 >> 1).trailing_ones(), $T::BITS - 1); assert_eq!(_0.leading_ones(), 0); assert_eq!(_0.trailing_ones(), 0); diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs new file mode 100644 index 0000000000..5d4ecb2669 --- /dev/null +++ b/library/core/tests/num/wrapping.rs @@ -0,0 +1,76 @@ +use core::num::Wrapping; + +macro_rules! wrapping_operation { + ($result:expr, $lhs:ident $op:tt $rhs:expr) => { + assert_eq!($result, $lhs $op $rhs); + assert_eq!($result, &$lhs $op $rhs); + assert_eq!($result, $lhs $op &$rhs); + assert_eq!($result, &$lhs $op &$rhs); + }; + ($result:expr, $op:tt $expr:expr) => { + assert_eq!($result, $op $expr); + assert_eq!($result, $op &$expr); + }; +} + +macro_rules! wrapping_assignment { + ($result:expr, $lhs:ident $op:tt $rhs:expr) => { + let mut lhs1 = $lhs; + lhs1 $op $rhs; + assert_eq!($result, lhs1); + + let mut lhs2 = $lhs; + lhs2 $op &$rhs; + assert_eq!($result, lhs2); + }; +} + +macro_rules! wrapping_test { + ($type:ty, $min:expr, $max:expr) => { + #[test] + fn wrapping_$type() { + let zero: Wrapping<$type> = Wrapping(0); + let one: Wrapping<$type> = Wrapping(1); + let min: Wrapping<$type> = Wrapping($min); + let max: Wrapping<$type> = Wrapping($max); + + wrapping_operation!(min, max + one); + wrapping_assignment!(min, max += one); + wrapping_operation!(max, min - one); + wrapping_assignment!(max, min -= one); + wrapping_operation!(max, max * one); + wrapping_assignment!(max, max *= one); + wrapping_operation!(max, max / one); + wrapping_assignment!(max, max /= one); + wrapping_operation!(zero, max % one); + wrapping_assignment!(zero, max %= one); + wrapping_operation!(zero, zero & max); + wrapping_assignment!(zero, zero &= max); + wrapping_operation!(max, zero | max); + wrapping_assignment!(max, zero |= max); + wrapping_operation!(zero, max ^ max); + wrapping_assignment!(zero, max ^= max); + wrapping_operation!(zero, zero << 1usize); + wrapping_assignment!(zero, zero <<= 1usize); + wrapping_operation!(zero, zero >> 1usize); + wrapping_assignment!(zero, zero >>= 1usize); + wrapping_operation!(zero, -zero); + wrapping_operation!(max, !min); + } + }; +} + +wrapping_test!(i8, i8::MIN, i8::MAX); +wrapping_test!(i16, i16::MIN, i16::MAX); +wrapping_test!(i32, i32::MIN, i32::MAX); +wrapping_test!(i64, i64::MIN, i64::MAX); +#[cfg(not(target_os = "emscripten"))] +wrapping_test!(i128, i128::MIN, i128::MAX); +wrapping_test!(isize, isize::MIN, isize::MAX); +wrapping_test!(u8, u8::MIN, u8::MAX); +wrapping_test!(u16, u16::MIN, u16::MAX); +wrapping_test!(u32, u32::MIN, u32::MAX); +wrapping_test!(u64, u64::MIN, u64::MAX); +#[cfg(not(target_os = "emscripten"))] +wrapping_test!(u128, u128::MIN, u128::MAX); +wrapping_test!(usize, usize::MIN, usize::MAX); diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index fa308160fc..ae814efec2 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -1,4 +1,4 @@ -use core::array::FixedSizeArray; +use core::cell::Cell; use core::clone::Clone; use core::mem; use core::ops::DerefMut; @@ -357,3 +357,48 @@ fn test_replace() { assert_eq!(x, Some(3)); assert_eq!(old, None); } + +#[test] +fn option_const() { + // test that the methods of `Option` are usable in a const context + + const OPTION: Option = Some(32); + + const REF: Option<&usize> = OPTION.as_ref(); + assert_eq!(REF, Some(&32)); + + const IS_SOME: bool = OPTION.is_some(); + assert!(IS_SOME); + + const IS_NONE: bool = OPTION.is_none(); + assert!(!IS_NONE); +} + +#[test] +fn test_unwrap_drop() { + struct Dtor<'a> { + x: &'a Cell, + } + + impl<'a> std::ops::Drop for Dtor<'a> { + fn drop(&mut self) { + self.x.set(self.x.get() - 1); + } + } + + fn unwrap(o: Option) -> T { + match o { + Some(v) => v, + None => panic!(), + } + } + + let x = &Cell::new(1); + + { + let b = Some(Dtor { x }); + let _c = unwrap(b); + } + + assert_eq!(x.get(), 0); +} diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs new file mode 100644 index 0000000000..6f617c8d0c --- /dev/null +++ b/library/core/tests/pin.rs @@ -0,0 +1,31 @@ +use core::pin::Pin; + +#[test] +fn pin_const() { + // test that the methods of `Pin` are usable in a const context + + const POINTER: &'static usize = &2; + + const PINNED: Pin<&'static usize> = Pin::new(POINTER); + const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) }; + assert_eq!(PINNED_UNCHECKED, PINNED); + + const INNER: &'static usize = Pin::into_inner(PINNED); + assert_eq!(INNER, POINTER); + + const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) }; + assert_eq!(INNER_UNCHECKED, POINTER); + + const REF: &'static usize = PINNED.get_ref(); + assert_eq!(REF, POINTER); + + // Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context. + // A const fn is used because `&mut` is not (yet) usable in constants. + const fn pin_mut_const() { + let _ = Pin::new(&mut 2).into_ref(); + let _ = Pin::new(&mut 2).get_mut(); + let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() }; + } + + pin_mut_const(); +} diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index caa2d916cd..39ea4831b9 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -1,4 +1,3 @@ -use core::array::FixedSizeArray; use core::ops::DerefMut; use core::option::*; @@ -305,3 +304,19 @@ fn test_result_as_deref_mut() { let expected_result = Result::Err::<&mut u32, &mut Vec>(&mut expected_vec); assert_eq!(mut_err.as_deref_mut(), expected_result); } + +#[test] +fn result_const() { + // test that the methods of `Result` are usable in a const context + + const RESULT: Result = Ok(32); + + const REF: Result<&usize, &bool> = RESULT.as_ref(); + assert_eq!(REF, Ok(&32)); + + const IS_OK: bool = RESULT.is_ok(); + assert!(IS_OK); + + const IS_ERR: bool = RESULT.is_err(); + assert!(!IS_ERR) +} diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 5650c98f9c..5ef30b1a88 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1,3 +1,4 @@ +use core::cell::Cell; use core::result::Result::{Err, Ok}; #[test] @@ -564,6 +565,148 @@ fn test_array_chunks_zip() { assert_eq!(res, vec![14, 22]); } +#[test] +fn test_array_chunks_mut_infer() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + for a in v.array_chunks_mut() { + let sum = a.iter().sum::(); + *a = [sum; 3]; + } + assert_eq!(v, &[3, 3, 3, 12, 12, 12, 6]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + v2.array_chunks_mut().for_each(|[a, b]| core::mem::swap(a, b)); + assert_eq!(v2, &[1, 0, 3, 2, 5, 4, 6]); +} + +#[test] +fn test_array_chunks_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.array_chunks_mut::<3>(); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.array_chunks_mut::<2>(); + assert_eq!(c2.count(), 2); + + let v3: &mut [i32] = &mut []; + let c3 = v3.array_chunks_mut::<2>(); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_array_chunks_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks_mut::<2>(); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.array_chunks_mut::<3>(); + assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_array_chunks_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks_mut::<2>(); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.array_chunks_mut::<3>(); + assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c3 = v3.array_chunks_mut::<10>(); + assert_eq!(c3.nth_back(0), None); +} + +#[test] +fn test_array_chunks_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.array_chunks_mut::<2>(); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.array_chunks_mut::<2>(); + assert_eq!(c2.last().unwrap(), &[2, 3]); +} + +#[test] +fn test_array_chunks_mut_remainder() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c = v.array_chunks_mut::<2>(); + assert_eq!(c.into_remainder(), &[4]); +} + +#[test] +fn test_array_chunks_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.array_chunks_mut::<2>().zip(v2.array_chunks::<2>()) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [13, 14, 19, 20, 4]); +} + +#[test] +fn test_array_windows_infer() { + let v: &[i32] = &[0, 1, 0, 1]; + assert_eq!(v.array_windows::<2>().count(), 3); + let c = v.array_windows(); + for &[a, b] in c { + assert_eq!(a + b, 1); + } + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let total = v2.array_windows().map(|&[a, b, c]| a + b + c).sum::(); + assert_eq!(total, 3 + 6 + 9 + 12 + 15); +} + +#[test] +fn test_array_windows_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.array_windows::<3>(); + assert_eq!(c.count(), 4); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.array_windows::<6>(); + assert_eq!(c2.count(), 0); + + let v3: &[i32] = &[]; + let c3 = v3.array_windows::<2>(); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_array_windows_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let snd = v.array_windows::<4>().nth(1); + assert_eq!(snd, Some(&[1, 2, 3, 4])); + let mut arr_windows = v.array_windows::<2>(); + assert_ne!(arr_windows.nth(0), arr_windows.nth(0)); + let last = v.array_windows::<3>().last(); + assert_eq!(last, Some(&[3, 4, 5])); +} + +#[test] +fn test_array_windows_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let snd = v.array_windows::<4>().nth_back(1); + assert_eq!(snd, Some(&[1, 2, 3, 4])); + let mut arr_windows = v.array_windows::<2>(); + assert_ne!(arr_windows.nth_back(0), arr_windows.nth_back(0)); +} + #[test] fn test_rchunks_count() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; @@ -1795,7 +1938,7 @@ fn test_copy_within() { } #[test] -#[should_panic(expected = "src is out of bounds")] +#[should_panic(expected = "range end index 14 out of range for slice of length 13")] fn test_copy_within_panics_src_too_long() { let mut bytes = *b"Hello, World!"; // The length is only 13, so 14 is out of bounds. @@ -1810,7 +1953,7 @@ fn test_copy_within_panics_dest_too_long() { bytes.copy_within(0..4, 10); } #[test] -#[should_panic(expected = "src end is before src start")] +#[should_panic(expected = "slice index starts at 2 but ends at 1")] fn test_copy_within_panics_src_inverted() { let mut bytes = *b"Hello, World!"; // 2 is greater than 1, so this range is invalid. @@ -1838,3 +1981,30 @@ fn test_is_sorted() { assert!(!["c", "bb", "aaa"].is_sorted()); assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); } + +#[test] +fn test_slice_run_destructors() { + // Make sure that destructors get run on slice literals + struct Foo<'a> { + x: &'a Cell, + } + + impl<'a> Drop for Foo<'a> { + fn drop(&mut self) { + self.x.set(self.x.get() + 1); + } + } + + fn foo(x: &Cell) -> Foo<'_> { + Foo { x } + } + + let x = &Cell::new(0); + + { + let l = &[foo(x)]; + assert_eq!(l[0].x.get(), 0); + } + + assert_eq!(x.get(), 1); +} diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs index 7a6675dc82..7c43885040 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -89,6 +89,16 @@ fn checked_add() { assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None); } +#[test] +fn saturating_add() { + assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); + assert_eq!( + Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)), + Duration::new(1, 1) + ); + assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); +} + #[test] fn sub() { assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1)); @@ -107,6 +117,17 @@ fn checked_sub() { assert_eq!(zero.checked_sub(one_sec), None); } +#[test] +fn saturating_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.saturating_sub(zero), Duration::new(0, 1)); + assert_eq!(one_sec.saturating_sub(one_nano), Duration::new(0, 999_999_999)); + assert_eq!(zero.saturating_sub(one_nano), Duration::MIN); + assert_eq!(zero.saturating_sub(one_sec), Duration::MIN); +} + #[test] #[should_panic] fn sub_bad1() { @@ -136,6 +157,15 @@ fn checked_mul() { assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None); } +#[test] +fn saturating_mul() { + assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000)); + assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); +} + #[test] fn div() { assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); @@ -291,3 +321,104 @@ fn debug_formatting_precision_high() { assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s"); assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s"); } + +#[test] +fn duration_const() { + // test that the methods of `Duration` are usable in a const context + + const DURATION: Duration = Duration::new(0, 123_456_789); + + const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis(); + assert_eq!(SUB_SEC_MILLIS, 123); + + const SUB_SEC_MICROS: u32 = DURATION.subsec_micros(); + assert_eq!(SUB_SEC_MICROS, 123_456); + + const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos(); + assert_eq!(SUB_SEC_NANOS, 123_456_789); + + const ZERO: Duration = Duration::zero(); + assert_eq!(ZERO, Duration::new(0, 0)); + + const IS_ZERO: bool = ZERO.is_zero(); + assert!(IS_ZERO); + + const ONE: Duration = Duration::new(1, 0); + + const SECONDS: u64 = ONE.as_secs(); + assert_eq!(SECONDS, 1); + + const FROM_SECONDS: Duration = Duration::from_secs(1); + assert_eq!(FROM_SECONDS, ONE); + + const SECONDS_F32: f32 = ONE.as_secs_f32(); + assert_eq!(SECONDS_F32, 1.0); + + const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0); + assert_eq!(FROM_SECONDS_F32, ONE); + + const SECONDS_F64: f64 = ONE.as_secs_f64(); + assert_eq!(SECONDS_F64, 1.0); + + const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0); + assert_eq!(FROM_SECONDS_F64, ONE); + + const MILLIS: u128 = ONE.as_millis(); + assert_eq!(MILLIS, 1_000); + + const FROM_MILLIS: Duration = Duration::from_millis(1_000); + assert_eq!(FROM_MILLIS, ONE); + + const MICROS: u128 = ONE.as_micros(); + assert_eq!(MICROS, 1_000_000); + + const FROM_MICROS: Duration = Duration::from_micros(1_000_000); + assert_eq!(FROM_MICROS, ONE); + + const NANOS: u128 = ONE.as_nanos(); + assert_eq!(NANOS, 1_000_000_000); + + const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000); + assert_eq!(FROM_NANOS, ONE); + + const MAX: Duration = Duration::new(u64::MAX, 999_999_999); + + const CHECKED_ADD: Option = MAX.checked_add(ONE); + assert_eq!(CHECKED_ADD, None); + + const CHECKED_SUB: Option = ZERO.checked_sub(ONE); + assert_eq!(CHECKED_SUB, None); + + const CHECKED_MUL: Option = ONE.checked_mul(1); + assert_eq!(CHECKED_MUL, Some(ONE)); + + const MUL_F32: Duration = ONE.mul_f32(1.0); + assert_eq!(MUL_F32, ONE); + + const MUL_F64: Duration = ONE.mul_f64(1.0); + assert_eq!(MUL_F64, ONE); + + const CHECKED_DIV: Option = ONE.checked_div(1); + assert_eq!(CHECKED_DIV, Some(ONE)); + + const DIV_F32: Duration = ONE.div_f32(1.0); + assert_eq!(DIV_F32, ONE); + + const DIV_F64: Duration = ONE.div_f64(1.0); + assert_eq!(DIV_F64, ONE); + + const DIV_DURATION_F32: f32 = ONE.div_duration_f32(ONE); + assert_eq!(DIV_DURATION_F32, 1.0); + + const DIV_DURATION_F64: f64 = ONE.div_duration_f64(ONE); + assert_eq!(DIV_DURATION_F64, 1.0); + + const SATURATING_ADD: Duration = MAX.saturating_add(ONE); + assert_eq!(SATURATING_ADD, MAX); + + const SATURATING_SUB: Duration = ZERO.saturating_sub(ONE); + assert_eq!(SATURATING_SUB, ZERO); + + const SATURATING_MUL: Duration = MAX.saturating_mul(2); + assert_eq!(SATURATING_MUL, MAX); +} diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index ccc067a3c9..9690996e60 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -12,12 +12,11 @@ #![panic_runtime] #![allow(unused_features)] #![feature(core_intrinsics)] -#![feature(libc)] #![feature(nll)] #![feature(panic_runtime)] #![feature(staged_api)] #![feature(rustc_attrs)] -#![feature(llvm_asm)] +#![feature(asm)] use core::any::Any; @@ -47,7 +46,7 @@ pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 { } __rust_abort(); } - } else if #[cfg(all(windows, any(target_arch = "x86", target_arch = "x86_64")))] { + } else if #[cfg(all(windows, not(miri)))] { // On Windows, use the processor-specific __fastfail mechanism. In Windows 8 // and later, this will terminate the process immediately without running any // in-process exception handlers. In earlier versions of Windows, this @@ -59,7 +58,18 @@ pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 { // // Note: this is the same implementation as in libstd's `abort_internal` unsafe fn abort() -> ! { - llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT + const FAST_FAIL_FATAL_APP_EXIT: usize = 7; + cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT); + } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { + asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT); + } else if #[cfg(target_arch = "aarch64")] { + asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT); + } else { + core::intrinsics::abort(); + } + } core::intrinsics::unreachable(); } } else { @@ -117,6 +127,17 @@ pub mod personalities { 1 // `ExceptionContinueSearch` } + // Similar to above, 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 + // currently UB with -C panic=abort (although this may be subject to + // change), any catch_unwind calls will never use this typeinfo. + #[rustc_std_internal_symbol] + #[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] diff --git a/library/panic_unwind/src/dwarf/eh.rs b/library/panic_unwind/src/dwarf/eh.rs index 302478cfac..8ce4dcd2ac 100644 --- a/library/panic_unwind/src/dwarf/eh.rs +++ b/library/panic_unwind/src/dwarf/eh.rs @@ -51,11 +51,7 @@ pub enum EHAction { 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<'_>, - foreign_exception: bool, -) -> Result { +pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result { if lsda.is_null() { return Ok(EHAction::None); } @@ -98,7 +94,7 @@ pub unsafe fn find_eh_action( return Ok(EHAction::None); } else { let lpad = lpad_base + cs_lpad; - return Ok(interpret_cs_action(cs_action, lpad, foreign_exception)); + return Ok(interpret_cs_action(cs_action, lpad)); } } } @@ -123,21 +119,17 @@ pub unsafe fn find_eh_action( // 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, foreign_exception)); + return Ok(interpret_cs_action(cs_action, lpad)); } } } } -fn interpret_cs_action(cs_action: u64, lpad: usize, foreign_exception: bool) -> EHAction { +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 if foreign_exception { - // catch_unwind should not catch foreign exceptions, only Rust panics. - // Instead just continue unwinding. - EHAction::None } else { // Stop unwinding Rust panics at catch_unwind. EHAction::Catch(lpad) diff --git a/library/panic_unwind/src/dwarf/mod.rs b/library/panic_unwind/src/dwarf/mod.rs index 649bbce52a..652fbe95a1 100644 --- a/library/panic_unwind/src/dwarf/mod.rs +++ b/library/panic_unwind/src/dwarf/mod.rs @@ -53,7 +53,7 @@ impl DwarfReader { } pub unsafe fn read_sleb128(&mut self) -> i64 { - let mut shift: usize = 0; + let mut shift: u32 = 0; let mut result: u64 = 0; let mut byte: u8; loop { @@ -65,7 +65,7 @@ impl DwarfReader { } } // sign-extend - if shift < 8 * mem::size_of::() && (byte & 0x40) != 0 { + if shift < u64::BITS && (byte & 0x40) != 0 { result |= (!0 as u64) << shift; } result as i64 diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs index a0bdb1481c..e428f2fdaa 100644 --- a/library/panic_unwind/src/emcc.rs +++ b/library/panic_unwind/src/emcc.rs @@ -8,8 +8,10 @@ use alloc::boxed::Box; use core::any::Any; +use core::intrinsics; use core::mem; use core::ptr; +use core::sync::atomic::{AtomicBool, Ordering}; use libc::{self, c_int}; use unwind as uw; @@ -47,6 +49,11 @@ static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo { }; struct Exception { + // This is necessary because C++ code can capture our execption with + // std::exception_ptr and rethrow it multiple times, possibly even in + // another thread. + caught: AtomicBool, + // This needs to be an Option because the object's lifetime follows C++ // semantics: when catch_unwind moves the Box out of the exception it must // still leave the exception object in a valid state because its destructor @@ -55,11 +62,27 @@ struct Exception { } pub unsafe fn cleanup(ptr: *mut u8) -> Box { - assert!(!ptr.is_null()); - let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void) as *mut Exception; - let ex = (*adjusted_ptr).data.take(); + // intrinsics::try actually gives us a pointer to this structure. + #[repr(C)] + struct CatchData { + ptr: *mut u8, + is_rust_panic: bool, + } + let catch_data = &*(ptr as *mut CatchData); + + let adjusted_ptr = __cxa_begin_catch(catch_data.ptr as *mut libc::c_void) as *mut Exception; + let out = if catch_data.is_rust_panic { + let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::SeqCst); + if was_caught { + // Since cleanup() isn't allowed to panic, we just abort instead. + intrinsics::abort(); + } + (*adjusted_ptr).data.take().unwrap() + } else { + super::__rust_foreign_exception(); + }; __cxa_end_catch(); - ex.unwrap() + out } pub unsafe fn panic(data: Box) -> u32 { @@ -68,25 +91,16 @@ pub unsafe fn panic(data: Box) -> u32 { if exception.is_null() { return uw::_URC_FATAL_PHASE1_ERROR as u32; } - ptr::write(exception, Exception { data: Some(data) }); + ptr::write(exception, Exception { caught: AtomicBool::new(false), data: Some(data) }); __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup); } -// On WASM and ARM, the destructor returns the pointer to the object. -cfg_if::cfg_if! { - if #[cfg(any(target_arch = "arm", target_arch = "wasm32"))] { - type DestructorRet = *mut libc::c_void; - } else { - type DestructorRet = (); - } -} -extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> DestructorRet { +extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> *mut libc::c_void { unsafe { if let Some(b) = (ptr as *mut Exception).read().data { drop(b); super::__rust_drop_panic(); } - #[cfg(any(target_arch = "arm", target_arch = "wasm32"))] ptr } } @@ -109,7 +123,7 @@ extern "C" { fn __cxa_throw( thrown_exception: *mut libc::c_void, tinfo: *const TypeInfo, - dest: extern "C" fn(*mut libc::c_void) -> DestructorRet, + dest: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void, ) -> !; fn __gxx_personality_v0( version: c_int, diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index f5d83c21da..6b88bab827 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -73,8 +73,14 @@ pub unsafe fn panic(data: Box) -> u32 { } pub unsafe fn cleanup(ptr: *mut u8) -> Box { - let exception = Box::from_raw(ptr as *mut Exception); - exception.cause + let exception = ptr as *mut uw::_Unwind_Exception; + if (*exception).exception_class != rust_exception_class() { + uw::_Unwind_DeleteException(exception); + super::__rust_foreign_exception(); + } else { + let exception = Box::from_raw(exception as *mut Exception); + exception.cause + } } // Rust's exception class identifier. This is used by personality routines to @@ -108,13 +114,13 @@ 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(target_arch = "sparc64")] +#[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(target_arch = "riscv64")] +#[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: @@ -164,9 +170,7 @@ cfg_if::cfg_if! { // _Unwind_Context in our libunwind bindings and fetch the required data from there // directly, bypassing DWARF compatibility functions. - let exception_class = (*exception_object).exception_class; - let foreign_exception = exception_class != rust_exception_class(); - let eh_action = match find_eh_action(context, foreign_exception) { + let eh_action = match find_eh_action(context) { Ok(action) => action, Err(_) => return uw::_URC_FAILURE, }; @@ -221,15 +225,14 @@ cfg_if::cfg_if! { // 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_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 foreign_exception = exception_class != rust_exception_class(); - let eh_action = match find_eh_action(context, foreign_exception) { + let eh_action = match find_eh_action(context) { Ok(action) => action, Err(_) => return uw::_URC_FATAL_PHASE1_ERROR, }; @@ -293,10 +296,7 @@ cfg_if::cfg_if! { } } -unsafe fn find_eh_action( - context: *mut uw::_Unwind_Context, - foreign_exception: bool, -) -> Result { +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); @@ -308,7 +308,7 @@ unsafe fn find_eh_action( get_text_start: &|| uw::_Unwind_GetTextRelBase(context), get_data_start: &|| uw::_Unwind_GetDataRelBase(context), }; - eh::find_eh_action(lsda, &eh_context, foreign_exception) + eh::find_eh_action(lsda, &eh_context) } // Frame unwind info registration diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 7d14893c4c..682289384c 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -18,8 +18,8 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/" )] #![feature(core_intrinsics)] +#![feature(int_bits_const)] #![feature(lang_items)] -#![feature(libc)] #![feature(nll)] #![feature(panic_unwind)] #![feature(staged_api)] @@ -65,7 +65,7 @@ cfg_if::cfg_if! { // - os=none ("bare metal" targets) // - os=uefi // - nvptx64-nvidia-cuda - // - avr-unknown-unknown + // - arch=avr #[path = "dummy.rs"] mod real_imp; } @@ -88,6 +88,9 @@ extern "C" { /// Handler in libstd called when a panic object is dropped outside of /// `catch_unwind`. fn __rust_drop_panic() -> !; + + /// Handler in libstd called when a foreign exception is caught. + fn __rust_foreign_exception() -> !; } mod dwarf; diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 1f812f8df6..5597bbb93d 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -175,7 +175,7 @@ pub struct _TypeDescriptor { // to be able to catch Rust panics by simply declaring a `struct rust_panic`. // // When modifying, make sure that the type name string exactly matches -// the one used in src/librustc_codegen_llvm/intrinsic.rs. +// the one used in `compiler/rustc_codegen_llvm/src/intrinsic.rs`. const TYPE_NAME: [u8; 11] = *b"rust_panic\0"; static mut THROW_INFO: _ThrowInfo = _ThrowInfo { @@ -309,15 +309,21 @@ pub unsafe fn panic(data: Box) -> u32 { extern "system" { #[unwind(allowed)] - pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; + fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; } _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _); } pub unsafe fn cleanup(payload: *mut u8) -> Box { - let exception = &mut *(payload as *mut Exception); - exception.data.take().unwrap() + // A NULL payload here means that we got here from the catch (...) of + // __rust_try. This happens when a non-Rust foreign exception is caught. + if payload.is_null() { + super::__rust_foreign_exception(); + } else { + let exception = &mut *(payload as *mut Exception); + exception.data.take().unwrap() + } } // This is required by the compiler to exist (e.g., it's a lang item), but diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index c00e07388b..ba3d4c075e 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -305,17 +305,18 @@ impl Bridge<'_> { } fn enter(self, f: impl FnOnce() -> R) -> R { + let force_show_panics = self.force_show_panics; // 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 hide = BridgeState::with(|state| match state { - BridgeState::NotConnected => false, - BridgeState::Connected(_) | BridgeState::InUse => true, + let show = BridgeState::with(|state| match state { + BridgeState::NotConnected => true, + BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, }); - if !hide { + if show { prev(info) } })); @@ -400,6 +401,7 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( } impl Client crate::TokenStream> { + #[allow_internal_unstable(const_fn)] pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, @@ -412,6 +414,7 @@ impl Client crate::TokenStream> { } impl Client crate::TokenStream> { + #[allow_internal_unstable(const_fn)] pub const fn expand2( f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, ) -> Self { @@ -456,6 +459,7 @@ impl ProcMacro { } } + #[allow_internal_unstable(const_fn)] pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], @@ -464,6 +468,7 @@ impl ProcMacro { ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } } + #[allow_internal_unstable(const_fn)] pub const fn attr( name: &'static str, expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, @@ -471,6 +476,7 @@ impl ProcMacro { ProcMacro::Attr { name, client: Client::expand2(expand) } } + #[allow_internal_unstable(const_fn)] pub const fn bang( name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream, diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 324be9f470..c898d483a8 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -220,6 +220,9 @@ pub struct Bridge<'a> { /// 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, } impl<'a> !Sync for Bridge<'a> {} diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs index 2cde1f65ad..daa577f74b 100644 --- a/library/proc_macro/src/bridge/scoped_cell.rs +++ b/library/proc_macro/src/bridge/scoped_cell.rs @@ -35,6 +35,7 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { pub struct ScopedCell(Cell<>::Out>); impl ScopedCell { + #[allow_internal_unstable(const_fn)] pub const fn new(value: >::Out) -> Self { ScopedCell(Cell::new(value)) } diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index eb39025e4c..1b3ccf4c18 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -135,6 +135,7 @@ pub trait ExecutionStrategy { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer; } @@ -147,10 +148,14 @@ impl ExecutionStrategy for SameThread { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer { let mut dispatch = |b| dispatcher.dispatch(b); - run_client(Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, client_data) + run_client( + Bridge { cached_buffer: input, dispatch: (&mut dispatch).into(), force_show_panics }, + client_data, + ) } } @@ -166,6 +171,7 @@ impl ExecutionStrategy for CrossThread1 { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer { use std::sync::mpsc::channel; @@ -179,7 +185,11 @@ impl ExecutionStrategy for CrossThread1 { }; run_client( - Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, + Bridge { + cached_buffer: input, + dispatch: (&mut dispatch).into(), + force_show_panics, + }, client_data, ) }); @@ -201,6 +211,7 @@ impl ExecutionStrategy for CrossThread2 { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer { use std::sync::{Arc, Mutex}; @@ -226,7 +237,11 @@ impl ExecutionStrategy for CrossThread2 { }; let r = run_client( - Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, + Bridge { + cached_buffer: input, + dispatch: (&mut dispatch).into(), + force_show_panics, + }, client_data, ); @@ -265,6 +280,7 @@ fn run_server< input: I, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Result { let mut dispatcher = Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; @@ -272,7 +288,13 @@ fn run_server< let mut b = Buffer::new(); input.encode(&mut b, &mut dispatcher.handle_store); - b = strategy.run_bridge_and_client(&mut dispatcher, b, run_client, client_data); + b = strategy.run_bridge_and_client( + &mut dispatcher, + b, + run_client, + client_data, + force_show_panics, + ); Result::decode(&mut &b[..], &mut dispatcher.handle_store) } @@ -283,6 +305,7 @@ impl client::Client crate::TokenStream> { strategy: &impl ExecutionStrategy, server: S, input: S::TokenStream, + force_show_panics: bool, ) -> Result { let client::Client { get_handle_counters, run, f } = *self; run_server( @@ -292,6 +315,7 @@ impl client::Client crate::TokenStream> { as Types>::TokenStream::mark(input), run, f, + force_show_panics, ) .map( as Types>::TokenStream::unmark) } @@ -304,6 +328,7 @@ impl client::Client crate::TokenSt server: S, input: S::TokenStream, input2: S::TokenStream, + force_show_panics: bool, ) -> Result { let client::Client { get_handle_counters, run, f } = *self; run_server( @@ -316,6 +341,7 @@ impl client::Client crate::TokenSt ), run, f, + force_show_panics, ) .map( as Types>::TokenStream::unmark) } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index c5a871e09a..93fa1f4e58 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -20,6 +20,8 @@ )] #![feature(nll)] #![feature(staged_api)] +#![feature(const_fn)] +#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))] #![feature(allow_internal_unstable)] #![feature(decl_macro)] #![feature(extern_types)] diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs index b674f73ebf..7d5c601df5 100644 --- a/library/profiler_builtins/build.rs +++ b/library/profiler_builtins/build.rs @@ -20,6 +20,7 @@ fn main() { "InstrProfilingMergeFile.c", "InstrProfilingNameVar.c", "InstrProfilingPlatformDarwin.c", + "InstrProfilingPlatformFuchsia.c", "InstrProfilingPlatformLinux.c", "InstrProfilingPlatformOther.c", "InstrProfilingPlatformWindows.c", @@ -47,10 +48,10 @@ fn main() { // Turn off various features of gcc and such, mostly copying // compiler-rt's build system already cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); cfg.flag("-fomit-frame-pointer"); cfg.define("VISIBILITY_HIDDEN", None); if !target.contains("windows") { + cfg.flag("-fvisibility=hidden"); cfg.define("COMPILER_RT_HAS_UNAME", Some("1")); } else { profile_sources.push("WindowsMMap.c"); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index ef0ef415b4..b27b056086 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -16,11 +16,11 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.74", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.32" } +libc = { version = "0.2.77", default-features = false, features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.35" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.8.1", default-features = false, features = ['rustc-dep-of-std'] } +hashbrown = { version = "0.9.0", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate addr2line = { version = "0.13.0", optional = true, default-features = false } @@ -59,6 +59,7 @@ gimli-symbolize = [] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] compiler-builtins-c = ["alloc/compiler-builtins-c"] +compiler-builtins-mem = ["alloc/compiler-builtins-mem"] llvm-libunwind = ["unwind/llvm-libunwind"] # Make panics and failed asserts immediately abort without formatting any message diff --git a/library/std/build.rs b/library/std/build.rs index 04bfed1215..f2ed7552af 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -8,10 +8,6 @@ fn main() { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=log"); println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("musl") { - println!("cargo:rustc-link-lib=dl"); - println!("cargo:rustc-link-lib=rt"); - println!("cargo:rustc-link-lib=pthread"); } } else if target.contains("freebsd") { println!("cargo:rustc-link-lib=execinfo"); @@ -83,7 +79,7 @@ fn main() { // - os=none ("bare metal" targets) // - mipsel-sony-psp // - nvptx64-nvidia-cuda - // - avr-unknown-unknown + // - arch=avr // - tvos (aarch64-apple-tvos, x86_64-apple-tvos) // - uefi (x86_64-unknown-uefi, i686-unknown-uefi) // - JSON targets diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index b4009c8641..dd76006238 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -133,7 +133,7 @@ pub struct System; impl System { #[inline] - fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result, AllocErr> { + fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), // SAFETY: `layout` is non-zero in size, @@ -143,47 +143,56 @@ impl System { } else { GlobalAlloc::alloc(self, layout) }; - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::slice_from_raw_parts(ptr, size)) }, } } - // Safety: Same as `AllocRef::grow` + // SAFETY: Same as `AllocRef::grow` #[inline] unsafe fn grow_impl( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, zeroed: bool, - ) -> Result, AllocErr> { + ) -> Result, AllocError> { debug_assert!( - new_size >= layout.size(), - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - match layout.size() { - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - 0 => unsafe { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc_impl(new_layout, zeroed) - }, + match old_layout.size() { + 0 => self.alloc_impl(new_layout, zeroed), // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // as required by safety conditions. Other conditions must be upheld by the caller - old_size => unsafe { - // `realloc` probably checks for `new_size >= size` or something similar. - intrinsics::assume(new_size >= layout.size()); + old_size if old_layout.align() == new_layout.align() => unsafe { + let new_size = new_layout.size(); + + // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. + intrinsics::assume(new_size >= old_layout.size()); - let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; if zeroed { raw_ptr.add(old_size).write_bytes(0, new_size - old_size); } Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, + // both the old and new memory allocation are valid for reads and writes for `old_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + old_size => unsafe { + let new_ptr = self.alloc_impl(new_layout, zeroed)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); + AllocRef::dealloc(&self, ptr, old_layout); + Ok(new_ptr) + }, } } } @@ -193,17 +202,17 @@ impl System { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl AllocRef for System { #[inline] - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -213,54 +222,66 @@ unsafe impl AllocRef for System { #[inline] unsafe fn grow( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, false) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } } #[inline] unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, true) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } } #[inline] unsafe fn shrink( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size <= layout.size(), - "`new_size` must be smaller than or equal to `layout.size()`" + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - match new_size { + match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, layout); - Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)) + AllocRef::dealloc(&self, ptr, old_layout); + Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller - new_size => unsafe { - // `realloc` probably checks for `new_size <= size` or something similar. - intrinsics::assume(new_size <= layout.size()); + new_size if old_layout.align() == new_layout.align() => unsafe { + // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. + intrinsics::assume(new_size <= old_layout.size()); - let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, + // both the old and new memory allocation are valid for reads and writes for `new_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + new_size => unsafe { + let new_ptr = AllocRef::alloc(&self, new_layout)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); + AllocRef::dealloc(&self, ptr, old_layout); + Ok(new_ptr) + }, } } } diff --git a/library/std/src/ascii.rs b/library/std/src/ascii.rs index c9106136d3..035cd9f243 100644 --- a/library/std/src/ascii.rs +++ b/library/std/src/ascii.rs @@ -70,7 +70,6 @@ pub trait AsciiExt { /// inherent methods on `u8`, `char`, `[u8]` and `str`. /// /// [`make_ascii_uppercase`]: AsciiExt::make_ascii_uppercase - /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] fn to_ascii_uppercase(&self) -> Self::Owned; @@ -91,7 +90,6 @@ pub trait AsciiExt { /// inherent methods on `u8`, `char`, `[u8]` and `str`. /// /// [`make_ascii_lowercase`]: AsciiExt::make_ascii_lowercase - /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] fn to_ascii_lowercase(&self) -> Self::Owned; diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 09f83ea5fc..cc29e1c0b0 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -66,6 +66,9 @@ #![unstable(feature = "backtrace", issue = "53487")] +#[cfg(test)] +mod tests; + // NB: A note on resolution of a backtrace: // // Backtraces primarily happen in two steps, one is where we actually capture @@ -438,55 +441,3 @@ impl RawFrame { } } } - -#[test] -fn test_debug() { - let backtrace = Backtrace { - inner: Inner::Captured(Mutex::new(Capture { - actual_start: 1, - resolved: true, - frames: vec![ - BacktraceFrame { - frame: RawFrame::Fake, - symbols: vec![BacktraceSymbol { - name: Some(b"std::backtrace::Backtrace::create".to_vec()), - filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())), - lineno: Some(100), - }], - }, - BacktraceFrame { - frame: RawFrame::Fake, - symbols: vec![BacktraceSymbol { - name: Some(b"__rust_maybe_catch_panic".to_vec()), - filename: None, - lineno: None, - }], - }, - BacktraceFrame { - frame: RawFrame::Fake, - symbols: vec![ - BacktraceSymbol { - name: Some(b"std::rt::lang_start_internal".to_vec()), - filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), - lineno: Some(300), - }, - BacktraceSymbol { - name: Some(b"std::rt::lang_start".to_vec()), - filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), - lineno: Some(400), - }, - ], - }, - ], - })), - }; - - #[rustfmt::skip] - let expected = "Backtrace [\ - \n { fn: \"__rust_maybe_catch_panic\" },\ - \n { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 },\ - \n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\ - \n]"; - - assert_eq!(format!("{:#?}", backtrace), expected); -} diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs new file mode 100644 index 0000000000..287359cd54 --- /dev/null +++ b/library/std/src/backtrace/tests.rs @@ -0,0 +1,53 @@ +use super::*; + +#[test] +fn test_debug() { + let backtrace = Backtrace { + inner: Inner::Captured(Mutex::new(Capture { + actual_start: 1, + resolved: true, + frames: vec![ + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![BacktraceSymbol { + name: Some(b"std::backtrace::Backtrace::create".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())), + lineno: Some(100), + }], + }, + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![BacktraceSymbol { + name: Some(b"__rust_maybe_catch_panic".to_vec()), + filename: None, + lineno: None, + }], + }, + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![ + BacktraceSymbol { + name: Some(b"std::rt::lang_start_internal".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), + lineno: Some(300), + }, + BacktraceSymbol { + name: Some(b"std::rt::lang_start".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), + lineno: Some(400), + }, + ], + }, + ], + })), + }; + + #[rustfmt::skip] + let expected = "Backtrace [\ + \n { fn: \"__rust_maybe_catch_panic\" },\ + \n { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 },\ + \n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\ + \n]"; + + assert_eq!(format!("{:#?}", backtrace), expected); +} diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 70f7214e2f..f12cefffbf 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1,4 +1,5 @@ -// ignore-tidy-filelength +#[cfg(test)] +mod tests; use self::Entry::*; @@ -496,6 +497,50 @@ impl HashMap { Drain { base: self.base.drain() } } + /// Creates an iterator which uses a closure to determine if an element should be removed. + /// + /// If the closure returns true, the element is removed from the map and yielded. + /// If the closure returns false, or panics, the element remains in the map and will not be + /// yielded. + /// + /// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// If the iterator is only partially consumed or not consumed at all, each of the remaining + /// elements will still be subjected to the closure and removed and dropped if it returns true. + /// + /// It is unspecified how many more elements will be subjected to the closure + /// if a panic occurs in the closure, or a panic occurs while dropping an element, + /// or if the `DrainFilter` value is leaked. + /// + /// # Examples + /// + /// Splitting a map into even and odd keys, reusing the original map: + /// + /// ``` + /// #![feature(hash_drain_filter)] + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// let drained: HashMap = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().copied().collect::>(); + /// let mut odds = map.keys().copied().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[inline] + #[unstable(feature = "hash_drain_filter", issue = "59618")] + pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, K, V, F> + where + F: FnMut(&K, &mut V) -> bool, + { + DrainFilter { base: self.base.drain_filter(pred) } + } + /// Clears the map, removing all key-value pairs. Keeps the allocated memory /// for reuse. /// @@ -1057,6 +1102,16 @@ where /// documentation for more. /// /// [`iter`]: HashMap::iter +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { base: base::Iter<'a, K, V>, @@ -1084,6 +1139,16 @@ impl fmt::Debug for Iter<'_, K, V> { /// documentation for more. /// /// [`iter_mut`]: HashMap::iter_mut +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.iter_mut(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { base: base::IterMut<'a, K, V>, @@ -1103,6 +1168,16 @@ impl<'a, K, V> IterMut<'a, K, V> { /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.into_iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { base: base::IntoIter, @@ -1122,6 +1197,16 @@ impl IntoIter { /// documentation for more. /// /// [`keys`]: HashMap::keys +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_keys = map.keys(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1149,6 +1234,16 @@ impl fmt::Debug for Keys<'_, K, V> { /// documentation for more. /// /// [`values`]: HashMap::values +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_values = map.values(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1176,6 +1271,16 @@ impl fmt::Debug for Values<'_, K, V> { /// documentation for more. /// /// [`drain`]: HashMap::drain +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.drain(); +/// ``` #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, K: 'a, V: 'a> { base: base::Drain<'a, K, V>, @@ -1189,12 +1294,47 @@ impl<'a, K, V> Drain<'a, K, V> { } } +/// A draining, filtering iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`drain_filter`] method on [`HashMap`]. +/// +/// [`drain_filter`]: HashMap::drain_filter +/// +/// # Example +/// +/// ``` +/// #![feature(hash_drain_filter)] +/// +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.drain_filter(|_k, v| *v % 2 == 0); +/// ``` +#[unstable(feature = "hash_drain_filter", issue = "59618")] +pub struct DrainFilter<'a, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + base: base::DrainFilter<'a, K, V, F>, +} + /// A mutable iterator over the values of a `HashMap`. /// /// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its /// documentation for more. /// /// [`values_mut`]: HashMap::values_mut +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_values = map.values_mut(); +/// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, @@ -1206,6 +1346,18 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// See its documentation for more. /// /// [`into_keys`]: HashMap::into_keys +/// +/// # Example +/// +/// ``` +/// #![feature(map_into_keys_values)] +/// +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_keys = map.into_keys(); +/// ``` #[unstable(feature = "map_into_keys_values", issue = "75294")] pub struct IntoKeys { inner: IntoIter, @@ -1217,6 +1369,18 @@ pub struct IntoKeys { /// See its documentation for more. /// /// [`into_values`]: HashMap::into_values +/// +/// # Example +/// +/// ``` +/// #![feature(map_into_keys_values)] +/// +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_keys = map.into_values(); +/// ``` #[unstable(feature = "map_into_keys_values", issue = "75294")] pub struct IntoValues { inner: IntoIter, @@ -1227,7 +1391,6 @@ pub struct IntoValues { /// See the [`HashMap::raw_entry_mut`] docs for usage examples. /// /// [`HashMap::raw_entry_mut`]: HashMap::raw_entry_mut - #[unstable(feature = "hash_raw_entry", issue = "56167")] pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { map: &'a mut HashMap, @@ -1240,13 +1403,11 @@ pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { /// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], /// then calling one of the methods of that [`RawEntryBuilderMut`]. /// -/// [`Entry`]: enum.Entry.html /// [`raw_entry_mut`]: HashMap::raw_entry_mut -/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html #[unstable(feature = "hash_raw_entry", issue = "56167")] pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// An occupied entry. - Occupied(RawOccupiedEntryMut<'a, K, V>), + Occupied(RawOccupiedEntryMut<'a, K, V, S>), /// A vacant entry. Vacant(RawVacantEntryMut<'a, K, V, S>), } @@ -1254,8 +1415,8 @@ pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// A view into an occupied entry in a `HashMap`. /// It is part of the [`RawEntryMut`] enum. #[unstable(feature = "hash_raw_entry", issue = "56167")] -pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> { - base: base::RawOccupiedEntryMut<'a, K, V>, +pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a, S: 'a> { + base: base::RawOccupiedEntryMut<'a, K, V, S>, } /// A view into a vacant entry in a `HashMap`. @@ -1456,7 +1617,7 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { } } -impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> { +impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// Gets a reference to the key in the entry. #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] @@ -1596,7 +1757,7 @@ impl Debug for RawEntryMut<'_, K, V, S> { } #[unstable(feature = "hash_raw_entry", issue = "56167")] -impl Debug for RawOccupiedEntryMut<'_, K, V> { +impl Debug for RawOccupiedEntryMut<'_, K, V, S> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawOccupiedEntryMut") .field("key", self.key()) @@ -1647,8 +1808,6 @@ impl Debug for Entry<'_, K, V> { /// A view into an occupied entry in a `HashMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { base: base::RustcOccupiedEntry<'a, K, V>, @@ -1663,8 +1822,6 @@ impl Debug for OccupiedEntry<'_, K, V> { /// A view into a vacant entry in a `HashMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { base: base::RustcVacantEntry<'a, K, V>, @@ -1885,13 +2042,9 @@ impl ExactSizeIterator for ValuesMut<'_, K, V> { impl FusedIterator for ValuesMut<'_, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ValuesMut<'_, K, V> -where - K: fmt::Debug, - V: fmt::Debug, -{ +impl fmt::Debug for ValuesMut<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.inner.iter()).finish() + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() } } @@ -1919,7 +2072,7 @@ impl ExactSizeIterator for IntoKeys { impl FusedIterator for IntoKeys {} #[unstable(feature = "map_into_keys_values", issue = "75294")] -impl fmt::Debug for IntoKeys { +impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish() } @@ -1949,7 +2102,7 @@ impl ExactSizeIterator for IntoValues { impl FusedIterator for IntoValues {} #[unstable(feature = "map_into_keys_values", issue = "75294")] -impl fmt::Debug for IntoValues { +impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish() } @@ -1989,6 +2142,36 @@ where } } +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl Iterator for DrainFilter<'_, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + type Item = (K, V); + + #[inline] + fn next(&mut self) -> Option<(K, V)> { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } +} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl<'a, K, V, F> fmt::Debug for DrainFilter<'a, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("DrainFilter { .. }") + } +} + impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns @@ -2381,7 +2564,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// use std::rc::Rc; /// /// let mut map: HashMap, u32> = HashMap::new(); - /// let mut known_strings: Vec> = Vec::new(); + /// let known_strings: Vec> = Vec::new(); /// /// // Initialise known strings, run program, etc. /// @@ -2389,7 +2572,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { /// for s in known_strings { - /// if let Entry::Occupied(entry) = map.entry(s.clone()) { + /// if let Entry::Occupied(entry) = map.entry(Rc::clone(s)) { /// // Replaces the entry's key with our version of it in `known_strings`. /// entry.replace_key(); /// } @@ -2649,11 +2832,10 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] impl Default for DefaultHasher { - // FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link - // resolution failure when re-exporting libstd items. When #56922 fixed, - // link `new` to [DefaultHasher::new] again. - /// Creates a new `DefaultHasher` using `new`. + /// Creates a new `DefaultHasher` using [`new`]. /// See its documentation for more. + /// + /// [`new`]: DefaultHasher::new fn default() -> DefaultHasher { DefaultHasher::new() } @@ -2697,7 +2879,7 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, } #[inline] -fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { +pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { match err { hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow, hashbrown::TryReserveError::AllocError { layout } => { @@ -2754,933 +2936,3 @@ fn assert_covariance() { d } } - -#[cfg(test)] -mod test_map { - use super::Entry::{Occupied, Vacant}; - use super::HashMap; - use super::RandomState; - use crate::cell::RefCell; - use rand::{thread_rng, Rng}; - use realstd::collections::TryReserveError::*; - - // https://github.com/rust-lang/rust/issues/62301 - fn _assert_hashmap_is_unwind_safe() { - fn assert_unwind_safe() {} - assert_unwind_safe::>>(); - } - - #[test] - fn test_zero_capacities() { - type HM = HashMap; - - let m = HM::new(); - assert_eq!(m.capacity(), 0); - - let m = HM::default(); - assert_eq!(m.capacity(), 0); - - let m = HM::with_hasher(RandomState::new()); - assert_eq!(m.capacity(), 0); - - let m = HM::with_capacity(0); - assert_eq!(m.capacity(), 0); - - let m = HM::with_capacity_and_hasher(0, RandomState::new()); - assert_eq!(m.capacity(), 0); - - let mut m = HM::new(); - m.insert(1, 1); - m.insert(2, 2); - m.remove(&1); - m.remove(&2); - m.shrink_to_fit(); - assert_eq!(m.capacity(), 0); - - let mut m = HM::new(); - m.reserve(0); - assert_eq!(m.capacity(), 0); - } - - #[test] - fn test_create_capacity_zero() { - let mut m = HashMap::with_capacity(0); - - assert!(m.insert(1, 1).is_none()); - - assert!(m.contains_key(&1)); - assert!(!m.contains_key(&0)); - } - - #[test] - fn test_insert() { - let mut m = HashMap::new(); - assert_eq!(m.len(), 0); - assert!(m.insert(1, 2).is_none()); - assert_eq!(m.len(), 1); - assert!(m.insert(2, 4).is_none()); - assert_eq!(m.len(), 2); - assert_eq!(*m.get(&1).unwrap(), 2); - assert_eq!(*m.get(&2).unwrap(), 4); - } - - #[test] - fn test_clone() { - let mut m = HashMap::new(); - assert_eq!(m.len(), 0); - assert!(m.insert(1, 2).is_none()); - assert_eq!(m.len(), 1); - assert!(m.insert(2, 4).is_none()); - assert_eq!(m.len(), 2); - let m2 = m.clone(); - assert_eq!(*m2.get(&1).unwrap(), 2); - assert_eq!(*m2.get(&2).unwrap(), 4); - assert_eq!(m2.len(), 2); - } - - thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } - - #[derive(Hash, PartialEq, Eq)] - struct Droppable { - k: usize, - } - - impl Droppable { - fn new(k: usize) -> Droppable { - DROP_VECTOR.with(|slot| { - slot.borrow_mut()[k] += 1; - }); - - Droppable { k } - } - } - - impl Drop for Droppable { - fn drop(&mut self) { - DROP_VECTOR.with(|slot| { - slot.borrow_mut()[self.k] -= 1; - }); - } - } - - impl Clone for Droppable { - fn clone(&self) -> Droppable { - Droppable::new(self.k) - } - } - - #[test] - fn test_drops() { - DROP_VECTOR.with(|slot| { - *slot.borrow_mut() = vec![0; 200]; - }); - - { - let mut m = HashMap::new(); - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - - for i in 0..100 { - let d1 = Droppable::new(i); - let d2 = Droppable::new(i + 100); - m.insert(d1, d2); - } - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 1); - } - }); - - for i in 0..50 { - let k = Droppable::new(i); - let v = m.remove(&k); - - assert!(v.is_some()); - - DROP_VECTOR.with(|v| { - assert_eq!(v.borrow()[i], 1); - assert_eq!(v.borrow()[i + 100], 1); - }); - } - - DROP_VECTOR.with(|v| { - for i in 0..50 { - assert_eq!(v.borrow()[i], 0); - assert_eq!(v.borrow()[i + 100], 0); - } - - for i in 50..100 { - assert_eq!(v.borrow()[i], 1); - assert_eq!(v.borrow()[i + 100], 1); - } - }); - } - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - } - - #[test] - fn test_into_iter_drops() { - DROP_VECTOR.with(|v| { - *v.borrow_mut() = vec![0; 200]; - }); - - let hm = { - let mut hm = HashMap::new(); - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - - for i in 0..100 { - let d1 = Droppable::new(i); - let d2 = Droppable::new(i + 100); - hm.insert(d1, d2); - } - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 1); - } - }); - - hm - }; - - // By the way, ensure that cloning doesn't screw up the dropping. - drop(hm.clone()); - - { - let mut half = hm.into_iter().take(50); - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 1); - } - }); - - for _ in half.by_ref() {} - - DROP_VECTOR.with(|v| { - let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); - - let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); - - assert_eq!(nk, 50); - assert_eq!(nv, 50); - }); - }; - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - } - - #[test] - fn test_empty_remove() { - let mut m: HashMap = HashMap::new(); - assert_eq!(m.remove(&0), None); - } - - #[test] - fn test_empty_entry() { - let mut m: HashMap = HashMap::new(); - match m.entry(0) { - Occupied(_) => panic!(), - Vacant(_) => {} - } - assert!(*m.entry(0).or_insert(true)); - assert_eq!(m.len(), 1); - } - - #[test] - fn test_empty_iter() { - let mut m: HashMap = HashMap::new(); - assert_eq!(m.drain().next(), None); - assert_eq!(m.keys().next(), None); - assert_eq!(m.values().next(), None); - assert_eq!(m.values_mut().next(), None); - assert_eq!(m.iter().next(), None); - assert_eq!(m.iter_mut().next(), None); - assert_eq!(m.len(), 0); - assert!(m.is_empty()); - assert_eq!(m.into_iter().next(), None); - } - - #[test] - fn test_lots_of_insertions() { - let mut m = HashMap::new(); - - // Try this a few times to make sure we never screw up the hashmap's - // internal state. - for _ in 0..10 { - assert!(m.is_empty()); - - for i in 1..1001 { - assert!(m.insert(i, i).is_none()); - - for j in 1..=i { - let r = m.get(&j); - assert_eq!(r, Some(&j)); - } - - for j in i + 1..1001 { - let r = m.get(&j); - assert_eq!(r, None); - } - } - - for i in 1001..2001 { - assert!(!m.contains_key(&i)); - } - - // remove forwards - for i in 1..1001 { - assert!(m.remove(&i).is_some()); - - for j in 1..=i { - assert!(!m.contains_key(&j)); - } - - for j in i + 1..1001 { - assert!(m.contains_key(&j)); - } - } - - for i in 1..1001 { - assert!(!m.contains_key(&i)); - } - - for i in 1..1001 { - assert!(m.insert(i, i).is_none()); - } - - // remove backwards - for i in (1..1001).rev() { - assert!(m.remove(&i).is_some()); - - for j in i..1001 { - assert!(!m.contains_key(&j)); - } - - for j in 1..i { - assert!(m.contains_key(&j)); - } - } - } - } - - #[test] - fn test_find_mut() { - let mut m = HashMap::new(); - assert!(m.insert(1, 12).is_none()); - assert!(m.insert(2, 8).is_none()); - assert!(m.insert(5, 14).is_none()); - let new = 100; - match m.get_mut(&5) { - None => panic!(), - Some(x) => *x = new, - } - assert_eq!(m.get(&5), Some(&new)); - } - - #[test] - fn test_insert_overwrite() { - let mut m = HashMap::new(); - assert!(m.insert(1, 2).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert!(!m.insert(1, 3).is_none()); - assert_eq!(*m.get(&1).unwrap(), 3); - } - - #[test] - fn test_insert_conflicts() { - let mut m = HashMap::with_capacity(4); - assert!(m.insert(1, 2).is_none()); - assert!(m.insert(5, 3).is_none()); - assert!(m.insert(9, 4).is_none()); - assert_eq!(*m.get(&9).unwrap(), 4); - assert_eq!(*m.get(&5).unwrap(), 3); - assert_eq!(*m.get(&1).unwrap(), 2); - } - - #[test] - fn test_conflict_remove() { - let mut m = HashMap::with_capacity(4); - assert!(m.insert(1, 2).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert!(m.insert(5, 3).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert_eq!(*m.get(&5).unwrap(), 3); - assert!(m.insert(9, 4).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert_eq!(*m.get(&5).unwrap(), 3); - assert_eq!(*m.get(&9).unwrap(), 4); - assert!(m.remove(&1).is_some()); - assert_eq!(*m.get(&9).unwrap(), 4); - assert_eq!(*m.get(&5).unwrap(), 3); - } - - #[test] - fn test_is_empty() { - let mut m = HashMap::with_capacity(4); - assert!(m.insert(1, 2).is_none()); - assert!(!m.is_empty()); - assert!(m.remove(&1).is_some()); - assert!(m.is_empty()); - } - - #[test] - fn test_remove() { - let mut m = HashMap::new(); - m.insert(1, 2); - assert_eq!(m.remove(&1), Some(2)); - assert_eq!(m.remove(&1), None); - } - - #[test] - fn test_remove_entry() { - let mut m = HashMap::new(); - m.insert(1, 2); - assert_eq!(m.remove_entry(&1), Some((1, 2))); - assert_eq!(m.remove(&1), None); - } - - #[test] - fn test_iterate() { - let mut m = HashMap::with_capacity(4); - for i in 0..32 { - assert!(m.insert(i, i * 2).is_none()); - } - assert_eq!(m.len(), 32); - - let mut observed: u32 = 0; - - for (k, v) in &m { - assert_eq!(*v, *k * 2); - observed |= 1 << *k; - } - assert_eq!(observed, 0xFFFF_FFFF); - } - - #[test] - fn test_keys() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let keys: Vec<_> = map.keys().cloned().collect(); - assert_eq!(keys.len(), 3); - assert!(keys.contains(&1)); - assert!(keys.contains(&2)); - assert!(keys.contains(&3)); - } - - #[test] - fn test_values() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let values: Vec<_> = map.values().cloned().collect(); - assert_eq!(values.len(), 3); - assert!(values.contains(&'a')); - assert!(values.contains(&'b')); - assert!(values.contains(&'c')); - } - - #[test] - fn test_values_mut() { - let vec = vec![(1, 1), (2, 2), (3, 3)]; - let mut map: HashMap<_, _> = vec.into_iter().collect(); - for value in map.values_mut() { - *value = (*value) * 2 - } - let values: Vec<_> = map.values().cloned().collect(); - assert_eq!(values.len(), 3); - assert!(values.contains(&2)); - assert!(values.contains(&4)); - assert!(values.contains(&6)); - } - - #[test] - fn test_into_keys() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let keys: Vec<_> = map.into_keys().collect(); - - assert_eq!(keys.len(), 3); - assert!(keys.contains(&1)); - assert!(keys.contains(&2)); - assert!(keys.contains(&3)); - } - - #[test] - fn test_into_values() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let values: Vec<_> = map.into_values().collect(); - - assert_eq!(values.len(), 3); - assert!(values.contains(&'a')); - assert!(values.contains(&'b')); - assert!(values.contains(&'c')); - } - - #[test] - fn test_find() { - let mut m = HashMap::new(); - assert!(m.get(&1).is_none()); - m.insert(1, 2); - match m.get(&1) { - None => panic!(), - Some(v) => assert_eq!(*v, 2), - } - } - - #[test] - fn test_eq() { - let mut m1 = HashMap::new(); - m1.insert(1, 2); - m1.insert(2, 3); - m1.insert(3, 4); - - let mut m2 = HashMap::new(); - m2.insert(1, 2); - m2.insert(2, 3); - - assert!(m1 != m2); - - m2.insert(3, 4); - - assert_eq!(m1, m2); - } - - #[test] - fn test_show() { - let mut map = HashMap::new(); - let empty: HashMap = HashMap::new(); - - map.insert(1, 2); - map.insert(3, 4); - - let map_str = format!("{:?}", map); - - assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); - assert_eq!(format!("{:?}", empty), "{}"); - } - - #[test] - fn test_reserve_shrink_to_fit() { - let mut m = HashMap::new(); - m.insert(0, 0); - m.remove(&0); - assert!(m.capacity() >= m.len()); - for i in 0..128 { - m.insert(i, i); - } - m.reserve(256); - - let usable_cap = m.capacity(); - for i in 128..(128 + 256) { - m.insert(i, i); - assert_eq!(m.capacity(), usable_cap); - } - - for i in 100..(128 + 256) { - assert_eq!(m.remove(&i), Some(i)); - } - m.shrink_to_fit(); - - assert_eq!(m.len(), 100); - assert!(!m.is_empty()); - assert!(m.capacity() >= m.len()); - - for i in 0..100 { - assert_eq!(m.remove(&i), Some(i)); - } - m.shrink_to_fit(); - m.insert(0, 0); - - assert_eq!(m.len(), 1); - assert!(m.capacity() >= m.len()); - assert_eq!(m.remove(&0), Some(0)); - } - - #[test] - fn test_from_iter() { - let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let map: HashMap<_, _> = xs.iter().cloned().collect(); - - for &(k, v) in &xs { - assert_eq!(map.get(&k), Some(&v)); - } - - assert_eq!(map.iter().len(), xs.len() - 1); - } - - #[test] - fn test_size_hint() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.size_hint(), (3, Some(3))); - } - - #[test] - fn test_iter_len() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.len(), 3); - } - - #[test] - fn test_mut_size_hint() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter_mut(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.size_hint(), (3, Some(3))); - } - - #[test] - fn test_iter_mut_len() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter_mut(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.len(), 3); - } - - #[test] - fn test_index() { - let mut map = HashMap::new(); - - map.insert(1, 2); - map.insert(2, 1); - map.insert(3, 4); - - assert_eq!(map[&2], 1); - } - - #[test] - #[should_panic] - fn test_index_nonexistent() { - let mut map = HashMap::new(); - - map.insert(1, 2); - map.insert(2, 1); - map.insert(3, 4); - - map[&4]; - } - - #[test] - fn test_entry() { - let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - // Existing key (insert) - match map.entry(1) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - assert_eq!(view.get(), &10); - assert_eq!(view.insert(100), 10); - } - } - assert_eq!(map.get(&1).unwrap(), &100); - assert_eq!(map.len(), 6); - - // Existing key (update) - match map.entry(2) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - let v = view.get_mut(); - let new_v = (*v) * 10; - *v = new_v; - } - } - assert_eq!(map.get(&2).unwrap(), &200); - assert_eq!(map.len(), 6); - - // Existing key (take) - match map.entry(3) { - Vacant(_) => unreachable!(), - Occupied(view) => { - assert_eq!(view.remove(), 30); - } - } - assert_eq!(map.get(&3), None); - assert_eq!(map.len(), 5); - - // Inexistent key (insert) - match map.entry(10) { - Occupied(_) => unreachable!(), - Vacant(view) => { - assert_eq!(*view.insert(1000), 1000); - } - } - assert_eq!(map.get(&10).unwrap(), &1000); - assert_eq!(map.len(), 6); - } - - #[test] - fn test_entry_take_doesnt_corrupt() { - #![allow(deprecated)] //rand - // Test for #19292 - fn check(m: &HashMap) { - for k in m.keys() { - assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); - } - } - - let mut m = HashMap::new(); - let mut rng = thread_rng(); - - // Populate the map with some items. - for _ in 0..50 { - let x = rng.gen_range(-10, 10); - m.insert(x, ()); - } - - for _ in 0..1000 { - let x = rng.gen_range(-10, 10); - match m.entry(x) { - Vacant(_) => {} - Occupied(e) => { - e.remove(); - } - } - - check(&m); - } - } - - #[test] - fn test_extend_ref() { - let mut a = HashMap::new(); - a.insert(1, "one"); - let mut b = HashMap::new(); - b.insert(2, "two"); - b.insert(3, "three"); - - a.extend(&b); - - assert_eq!(a.len(), 3); - assert_eq!(a[&1], "one"); - assert_eq!(a[&2], "two"); - assert_eq!(a[&3], "three"); - } - - #[test] - fn test_capacity_not_less_than_len() { - let mut a = HashMap::new(); - let mut item = 0; - - for _ in 0..116 { - a.insert(item, 0); - item += 1; - } - - assert!(a.capacity() > a.len()); - - let free = a.capacity() - a.len(); - for _ in 0..free { - a.insert(item, 0); - item += 1; - } - - assert_eq!(a.len(), a.capacity()); - - // Insert at capacity should cause allocation. - a.insert(item, 0); - assert!(a.capacity() > a.len()); - } - - #[test] - fn test_occupied_entry_key() { - let mut a = HashMap::new(); - let key = "hello there"; - let value = "value goes here"; - assert!(a.is_empty()); - a.insert(key.clone(), value.clone()); - assert_eq!(a.len(), 1); - assert_eq!(a[key], value); - - match a.entry(key.clone()) { - Vacant(_) => panic!(), - Occupied(e) => assert_eq!(key, *e.key()), - } - assert_eq!(a.len(), 1); - assert_eq!(a[key], value); - } - - #[test] - fn test_vacant_entry_key() { - let mut a = HashMap::new(); - let key = "hello there"; - let value = "value goes here"; - - assert!(a.is_empty()); - match a.entry(key.clone()) { - Occupied(_) => panic!(), - Vacant(e) => { - assert_eq!(key, *e.key()); - e.insert(value.clone()); - } - } - assert_eq!(a.len(), 1); - assert_eq!(a[key], value); - } - - #[test] - fn test_retain() { - let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); - - map.retain(|&k, _| k % 2 == 0); - assert_eq!(map.len(), 50); - assert_eq!(map[&2], 20); - assert_eq!(map[&4], 40); - assert_eq!(map[&6], 60); - } - - #[test] - fn test_try_reserve() { - let mut empty_bytes: HashMap = HashMap::new(); - - const MAX_USIZE: usize = usize::MAX; - - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!"); - } - - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) { - } else { - panic!("usize::MAX / 8 should trigger an OOM!") - } - } - - #[test] - fn test_raw_entry() { - use super::RawEntryMut::{Occupied, Vacant}; - - let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - let compute_hash = |map: &HashMap, k: i32| -> u64 { - use core::hash::{BuildHasher, Hash, Hasher}; - - let mut hasher = map.hasher().build_hasher(); - k.hash(&mut hasher); - hasher.finish() - }; - - // Existing key (insert) - match map.raw_entry_mut().from_key(&1) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - assert_eq!(view.get(), &10); - assert_eq!(view.insert(100), 10); - } - } - let hash1 = compute_hash(&map, 1); - assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); - assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100)); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100)); - assert_eq!(map.len(), 6); - - // Existing key (update) - match map.raw_entry_mut().from_key(&2) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - let v = view.get_mut(); - let new_v = (*v) * 10; - *v = new_v; - } - } - let hash2 = compute_hash(&map, 2); - assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); - assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200)); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200)); - assert_eq!(map.len(), 6); - - // Existing key (take) - let hash3 = compute_hash(&map, 3); - match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { - Vacant(_) => unreachable!(), - Occupied(view) => { - assert_eq!(view.remove_entry(), (3, 30)); - } - } - assert_eq!(map.raw_entry().from_key(&3), None); - assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); - assert_eq!(map.len(), 5); - - // Nonexistent key (insert) - match map.raw_entry_mut().from_key(&10) { - Occupied(_) => unreachable!(), - Vacant(view) => { - assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); - } - } - assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); - assert_eq!(map.len(), 6); - - // Ensure all lookup methods produce equivalent results. - for k in 0..12 { - let hash = compute_hash(&map, k); - let v = map.get(&k).cloned(); - let kv = v.as_ref().map(|v| (&k, v)); - - assert_eq!(map.raw_entry().from_key(&k), kv); - assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); - - match map.raw_entry_mut().from_key(&k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } - match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } - match map.raw_entry_mut().from_hash(hash, |q| *q == k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } - } - } -} diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs new file mode 100644 index 0000000000..467968354e --- /dev/null +++ b/library/std/src/collections/hash/map/tests.rs @@ -0,0 +1,1087 @@ +use super::Entry::{Occupied, Vacant}; +use super::HashMap; +use super::RandomState; +use crate::cell::RefCell; +use rand::{thread_rng, Rng}; +use realstd::collections::TryReserveError::*; + +// https://github.com/rust-lang/rust/issues/62301 +fn _assert_hashmap_is_unwind_safe() { + fn assert_unwind_safe() {} + assert_unwind_safe::>>(); +} + +#[test] +fn test_zero_capacities() { + type HM = HashMap; + + let m = HM::new(); + assert_eq!(m.capacity(), 0); + + let m = HM::default(); + assert_eq!(m.capacity(), 0); + + let m = HM::with_hasher(RandomState::new()); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity(0); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity_and_hasher(0, RandomState::new()); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.insert(1, 1); + m.insert(2, 2); + m.remove(&1); + m.remove(&2); + m.shrink_to_fit(); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.reserve(0); + assert_eq!(m.capacity(), 0); +} + +#[test] +fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + + assert!(m.insert(1, 1).is_none()); + + assert!(m.contains_key(&1)); + assert!(!m.contains_key(&0)); +} + +#[test] +fn test_insert() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&2).unwrap(), 4); +} + +#[test] +fn test_clone() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + let m2 = m.clone(); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); +} + +thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } + +#[derive(Hash, PartialEq, Eq)] +struct Droppable { + k: usize, +} + +impl Droppable { + fn new(k: usize) -> Droppable { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[k] += 1; + }); + + Droppable { k } + } +} + +impl Drop for Droppable { + fn drop(&mut self) { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[self.k] -= 1; + }); + } +} + +impl Clone for Droppable { + fn clone(&self) -> Droppable { + Droppable::new(self.k) + } +} + +#[test] +fn test_drops() { + DROP_VECTOR.with(|slot| { + *slot.borrow_mut() = vec![0; 200]; + }); + + { + let mut m = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + m.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for i in 0..50 { + let k = Droppable::new(i); + let v = m.remove(&k); + + assert!(v.is_some()); + + DROP_VECTOR.with(|v| { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..50 { + assert_eq!(v.borrow()[i], 0); + assert_eq!(v.borrow()[i + 100], 0); + } + + for i in 50..100 { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + } + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); +} + +#[test] +fn test_into_iter_drops() { + DROP_VECTOR.with(|v| { + *v.borrow_mut() = vec![0; 200]; + }); + + let hm = { + let mut hm = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + hm.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + { + let mut half = hm.into_iter().take(50); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for _ in half.by_ref() {} + + DROP_VECTOR.with(|v| { + let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); + + let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); + + assert_eq!(nk, 50); + assert_eq!(nv, 50); + }); + }; + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); +} + +#[test] +fn test_empty_remove() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.remove(&0), None); +} + +#[test] +fn test_empty_entry() { + let mut m: HashMap = HashMap::new(); + match m.entry(0) { + Occupied(_) => panic!(), + Vacant(_) => {} + } + assert!(*m.entry(0).or_insert(true)); + assert_eq!(m.len(), 1); +} + +#[test] +fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.drain().next(), None); + assert_eq!(m.keys().next(), None); + assert_eq!(m.values().next(), None); + assert_eq!(m.values_mut().next(), None); + assert_eq!(m.iter().next(), None); + assert_eq!(m.iter_mut().next(), None); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_iter().next(), None); +} + +#[test] +fn test_lots_of_insertions() { + let mut m = HashMap::new(); + + // Try this a few times to make sure we never screw up the hashmap's + // internal state. + for _ in 0..10 { + assert!(m.is_empty()); + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + + for j in 1..=i { + let r = m.get(&j); + assert_eq!(r, Some(&j)); + } + + for j in i + 1..1001 { + let r = m.get(&j); + assert_eq!(r, None); + } + } + + for i in 1001..2001 { + assert!(!m.contains_key(&i)); + } + + // remove forwards + for i in 1..1001 { + assert!(m.remove(&i).is_some()); + + for j in 1..=i { + assert!(!m.contains_key(&j)); + } + + for j in i + 1..1001 { + assert!(m.contains_key(&j)); + } + } + + for i in 1..1001 { + assert!(!m.contains_key(&i)); + } + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + } + + // remove backwards + for i in (1..1001).rev() { + assert!(m.remove(&i).is_some()); + + for j in i..1001 { + assert!(!m.contains_key(&j)); + } + + for j in 1..i { + assert!(m.contains_key(&j)); + } + } + } +} + +#[test] +fn test_find_mut() { + let mut m = HashMap::new(); + assert!(m.insert(1, 12).is_none()); + assert!(m.insert(2, 8).is_none()); + assert!(m.insert(5, 14).is_none()); + let new = 100; + match m.get_mut(&5) { + None => panic!(), + Some(x) => *x = new, + } + assert_eq!(m.get(&5), Some(&new)); +} + +#[test] +fn test_insert_overwrite() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(!m.insert(1, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 3); +} + +#[test] +fn test_insert_conflicts() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(5, 3).is_none()); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&1).unwrap(), 2); +} + +#[test] +fn test_conflict_remove() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(5, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&9).unwrap(), 4); + assert!(m.remove(&1).is_some()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); +} + +#[test] +fn test_is_empty() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(!m.is_empty()); + assert!(m.remove(&1).is_some()); + assert!(m.is_empty()); +} + +#[test] +fn test_remove() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove(&1), Some(2)); + assert_eq!(m.remove(&1), None); +} + +#[test] +fn test_remove_entry() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove_entry(&1), Some((1, 2))); + assert_eq!(m.remove(&1), None); +} + +#[test] +fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let mut observed: u32 = 0; + + for (k, v) in &m { + assert_eq!(*v, *k * 2); + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); +} + +#[test] +fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().cloned().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); +} + +#[test] +fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); +} + +#[test] +fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value = (*value) * 2 + } + let values: Vec<_> = map.values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); +} + +#[test] +fn test_into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.into_keys().collect(); + + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); +} + +#[test] +fn test_into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.into_values().collect(); + + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); +} + +#[test] +fn test_find() { + let mut m = HashMap::new(); + assert!(m.get(&1).is_none()); + m.insert(1, 2); + match m.get(&1) { + None => panic!(), + Some(v) => assert_eq!(*v, 2), + } +} + +#[test] +fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(m1 != m2); + + m2.insert(3, 4); + + assert_eq!(m1, m2); +} + +#[test] +fn test_show() { + let mut map = HashMap::new(); + let empty: HashMap = HashMap::new(); + + map.insert(1, 2); + map.insert(3, 4); + + let map_str = format!("{:?}", map); + + assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); + assert_eq!(format!("{:?}", empty), "{}"); +} + +#[test] +fn test_reserve_shrink_to_fit() { + let mut m = HashMap::new(); + m.insert(0, 0); + m.remove(&0); + assert!(m.capacity() >= m.len()); + for i in 0..128 { + m.insert(i, i); + } + m.reserve(256); + + let usable_cap = m.capacity(); + for i in 128..(128 + 256) { + m.insert(i, i); + assert_eq!(m.capacity(), usable_cap); + } + + for i in 100..(128 + 256) { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), 100); + assert!(!m.is_empty()); + assert!(m.capacity() >= m.len()); + + for i in 0..100 { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + m.insert(0, 0); + + assert_eq!(m.len(), 1); + assert!(m.capacity() >= m.len()); + assert_eq!(m.remove(&0), Some(0)); +} + +#[test] +fn test_from_iter() { + let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + + assert_eq!(map.iter().len(), xs.len() - 1); +} + +#[test] +fn test_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); +} + +#[test] +fn test_iter_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); +} + +#[test] +fn test_mut_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); +} + +#[test] +fn test_iter_mut_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); +} + +#[test] +fn test_index() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + assert_eq!(map[&2], 1); +} + +#[test] +#[should_panic] +fn test_index_nonexistent() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + map[&4]; +} + +#[test] +fn test_entry() { + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + // Existing key (insert) + match map.entry(1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get(&1).unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry(2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get(&2).unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry(3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get(&3), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry(10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get(&10).unwrap(), &1000); + assert_eq!(map.len(), 6); +} + +#[test] +fn test_entry_take_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + } + } + + let mut m = HashMap::new(); + let mut rng = thread_rng(); + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10, 10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10, 10); + match m.entry(x) { + Vacant(_) => {} + Occupied(e) => { + e.remove(); + } + } + + check(&m); + } +} + +#[test] +fn test_extend_ref() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); +} + +#[test] +fn test_capacity_not_less_than_len() { + let mut a = HashMap::new(); + let mut item = 0; + + for _ in 0..116 { + a.insert(item, 0); + item += 1; + } + + assert!(a.capacity() > a.len()); + + let free = a.capacity() - a.len(); + for _ in 0..free { + a.insert(item, 0); + item += 1; + } + + assert_eq!(a.len(), a.capacity()); + + // Insert at capacity should cause allocation. + a.insert(item, 0); + assert!(a.capacity() > a.len()); +} + +#[test] +fn test_occupied_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key.clone(), value.clone()); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry(key.clone()) { + Vacant(_) => panic!(), + Occupied(e) => assert_eq!(key, *e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); +} + +#[test] +fn test_vacant_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry(key.clone()) { + Occupied(_) => panic!(), + Vacant(e) => { + assert_eq!(key, *e.key()); + e.insert(value.clone()); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); +} + +#[test] +fn test_retain() { + let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); + + map.retain(|&k, _| k % 2 == 0); + assert_eq!(map.len(), 50); + assert_eq!(map[&2], 20); + assert_eq!(map[&4], 40); + assert_eq!(map[&6], 60); +} + +#[test] +fn test_try_reserve() { + let mut empty_bytes: HashMap = HashMap::new(); + + const MAX_USIZE: usize = usize::MAX; + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + } else { + panic!("usize::MAX should trigger an overflow!"); + } + + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) { + } else { + panic!("usize::MAX / 8 should trigger an OOM!") + } +} + +#[test] +fn test_raw_entry() { + use super::RawEntryMut::{Occupied, Vacant}; + + let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let compute_hash = |map: &HashMap, k: i32| -> u64 { + use core::hash::{BuildHasher, Hash, Hasher}; + + let mut hasher = map.hasher().build_hasher(); + k.hash(&mut hasher); + hasher.finish() + }; + + // Existing key (insert) + match map.raw_entry_mut().from_key(&1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + let hash1 = compute_hash(&map, 1); + assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); + assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100)); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100)); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.raw_entry_mut().from_key(&2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + let hash2 = compute_hash(&map, 2); + assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); + assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200)); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200)); + assert_eq!(map.len(), 6); + + // Existing key (take) + let hash3 = compute_hash(&map, 3); + match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove_entry(), (3, 30)); + } + } + assert_eq!(map.raw_entry().from_key(&3), None); + assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); + assert_eq!(map.len(), 5); + + // Nonexistent key (insert) + match map.raw_entry_mut().from_key(&10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); + } + } + assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); + assert_eq!(map.len(), 6); + + // Ensure all lookup methods produce equivalent results. + for k in 0..12 { + let hash = compute_hash(&map, k); + let v = map.get(&k).cloned(); + let kv = v.as_ref().map(|v| (&k, v)); + + assert_eq!(map.raw_entry().from_key(&k), kv); + assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + + match map.raw_entry_mut().from_key(&k) { + Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { + Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_hash(hash, |q| *q == k) { + Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + } +} + +mod test_drain_filter { + use super::*; + + use crate::panic::{catch_unwind, AssertUnwindSafe}; + use crate::sync::atomic::{AtomicUsize, Ordering}; + + trait EqSorted: Iterator { + fn eq_sorted>(self, other: I) -> bool; + } + + impl EqSorted for T + where + T::Item: Eq + Ord, + { + fn eq_sorted>(self, other: I) -> bool { + let mut v: Vec<_> = self.collect(); + v.sort_unstable(); + v.into_iter().eq(other) + } + } + + #[test] + fn empty() { + let mut map: HashMap = HashMap::new(); + map.drain_filter(|_, _| unreachable!("there's nothing to decide on")); + assert!(map.is_empty()); + } + + #[test] + fn consuming_nothing() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.collect(); + assert!(map.drain_filter(|_, _| false).eq_sorted(crate::iter::empty())); + assert_eq!(map.len(), 3); + } + + #[test] + fn consuming_all() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.clone().collect(); + assert!(map.drain_filter(|_, _| true).eq_sorted(pairs)); + assert!(map.is_empty()); + } + + #[test] + fn mutating_and_keeping() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.collect(); + assert!( + map.drain_filter(|_, v| { + *v += 6; + false + }) + .eq_sorted(crate::iter::empty()) + ); + assert!(map.keys().copied().eq_sorted(0..3)); + assert!(map.values().copied().eq_sorted(6..9)); + } + + #[test] + fn mutating_and_removing() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.collect(); + assert!( + map.drain_filter(|_, v| { + *v += 6; + true + }) + .eq_sorted((0..3).map(|i| (i, i + 6))) + ); + assert!(map.is_empty()); + } + + #[test] + fn drop_panic_leak() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + panic!("panic in `drop`"); + } + } + } + + let mut map = (0..3).map(|i| (i, D)).collect::>(); + + catch_unwind(move || { + drop(map.drain_filter(|_, _| { + PREDS.fetch_add(1, Ordering::SeqCst); + true + })) + }) + .unwrap_err(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(DROPS.load(Ordering::SeqCst), 3); + } + + #[test] + fn pred_panic_leak() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut map = (0..3).map(|i| (i, D)).collect::>(); + + catch_unwind(AssertUnwindSafe(|| { + drop(map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { + 0 => true, + _ => panic!(), + })) + })) + .unwrap_err(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 2); + assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(map.len(), 2); + } + + // Same as above, but attempt to use the iterator again after the panic in the predicate + #[test] + fn pred_panic_reuse() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut map = (0..3).map(|i| (i, D)).collect::>(); + + { + let mut it = map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { + 0 => true, + _ => panic!(), + }); + catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); + // Iterator behaviour after a panic is explicitly unspecified, + // so this is just the current implementation: + let result = catch_unwind(AssertUnwindSafe(|| it.next())); + assert!(result.is_err()); + } + + assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(map.len(), 2); + } +} diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 10bf917dae..a0c39852ad 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1,3 +1,8 @@ +#[cfg(test)] +mod tests; + +use hashbrown::hash_set as base; + use crate::borrow::Borrow; use crate::collections::TryReserveError; use crate::fmt; @@ -5,7 +10,7 @@ use crate::hash::{BuildHasher, Hash}; use crate::iter::{Chain, FromIterator, FusedIterator}; use crate::ops::{BitAnd, BitOr, BitXor, Sub}; -use super::map::{self, HashMap, Keys, RandomState}; +use super::map::{map_try_reserve_error, RandomState}; // Future Optimization (FIXME!) // ============================ @@ -98,13 +103,14 @@ use super::map::{self, HashMap, Keys, RandomState}; /// // use the values stored in the set /// ``` /// +/// [`HashMap`]: crate::collections::HashMap /// [`RefCell`]: crate::cell::RefCell /// [`Cell`]: crate::cell::Cell #[derive(Clone)] #[cfg_attr(not(test), rustc_diagnostic_item = "hashset_type")] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashSet { - map: HashMap, + base: base::HashSet, } impl HashSet { @@ -122,7 +128,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> HashSet { - HashSet { map: HashMap::new() } + Default::default() } /// Creates an empty `HashSet` with the specified capacity. @@ -140,7 +146,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> HashSet { - HashSet { map: HashMap::with_capacity(capacity) } + HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, Default::default()) } } } @@ -157,7 +163,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn capacity(&self) -> usize { - self.map.capacity() + self.base.capacity() } /// An iterator visiting all elements in arbitrary order. @@ -179,7 +185,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, T> { - Iter { iter: self.map.keys() } + Iter { base: self.base.iter() } } /// Returns the number of elements in the set. @@ -197,7 +203,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { - self.map.len() + self.base.len() } /// Returns `true` if the set contains no elements. @@ -215,7 +221,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { - self.map.is_empty() + self.base.is_empty() } /// Clears the set, returning all elements in an iterator. @@ -238,7 +244,48 @@ impl HashSet { #[inline] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain<'_, T> { - Drain { iter: self.map.drain() } + Drain { base: self.base.drain() } + } + + /// Creates an iterator which uses a closure to determine if a value should be removed. + /// + /// If the closure returns true, then the value is removed and yielded. + /// If the closure returns false, the value will remain in the list and will not be yielded + /// by the iterator. + /// + /// If the iterator is only partially consumed or not consumed at all, each of the remaining + /// values will still be subjected to the closure and removed and dropped if it returns true. + /// + /// It is unspecified how many more values will be subjected to the closure + /// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the + /// `DrainFilter` itself is leaked. + /// + /// # Examples + /// + /// Splitting a set into even and odd values, reusing the original set: + /// + /// ``` + /// #![feature(hash_drain_filter)] + /// use std::collections::HashSet; + /// + /// let mut set: HashSet = (0..8).collect(); + /// let drained: HashSet = set.drain_filter(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[inline] + #[unstable(feature = "hash_drain_filter", issue = "59618")] + pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, T, F> + where + F: FnMut(&T) -> bool, + { + DrainFilter { base: self.base.drain_filter(pred) } } /// Clears the set, removing all values. @@ -256,7 +303,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn clear(&mut self) { - self.map.clear() + self.base.clear() } /// Creates a new empty hash set which will use the given hasher to hash @@ -285,7 +332,7 @@ impl HashSet { #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hasher: S) -> HashSet { - HashSet { map: HashMap::with_hasher(hasher) } + HashSet { base: base::HashSet::with_hasher(hasher) } } /// Creates an empty `HashSet` with the specified capacity, using @@ -315,7 +362,7 @@ impl HashSet { #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { - HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } + HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } } /// Returns a reference to the set's [`BuildHasher`]. @@ -333,7 +380,7 @@ impl HashSet { #[inline] #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { - self.map.hasher() + self.base.hasher() } } @@ -361,7 +408,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { - self.map.reserve(additional) + self.base.reserve(additional) } /// Tries to reserve capacity for at least `additional` more elements to be inserted @@ -384,7 +431,7 @@ where #[inline] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.map.try_reserve(additional) + self.base.try_reserve(additional).map_err(map_try_reserve_error) } /// Shrinks the capacity of the set as much as possible. It will drop @@ -406,7 +453,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { - self.map.shrink_to_fit() + self.base.shrink_to_fit() } /// Shrinks the capacity of the set with a lower limit. It will drop @@ -434,7 +481,7 @@ where #[inline] #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] pub fn shrink_to(&mut self, min_capacity: usize) { - self.map.shrink_to(min_capacity) + self.base.shrink_to(min_capacity) } /// Visits the values representing the difference, @@ -574,7 +621,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.contains_key(value) + self.base.contains(value) } /// Returns a reference to the value in the set, if any, that is equal to the given value. @@ -599,7 +646,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.get_key_value(value).map(|(k, _)| k) + self.base.get(value) } /// Inserts the given `value` into the set if it is not present, then @@ -623,7 +670,7 @@ where pub fn get_or_insert(&mut self, value: T) -> &T { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.map.raw_entry_mut().from_key(&value).or_insert(value, ()).0 + self.base.get_or_insert(value) } /// Inserts an owned copy of the given `value` into the set if it is not @@ -655,7 +702,7 @@ where { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.map.raw_entry_mut().from_key(value).or_insert_with(|| (value.to_owned(), ())).0 + self.base.get_or_insert_owned(value) } /// Inserts a value computed from `f` into the set if the given `value` is @@ -688,7 +735,7 @@ where { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.map.raw_entry_mut().from_key(value).or_insert_with(|| (f(value), ())).0 + self.base.get_or_insert_with(value, f) } /// Returns `true` if `self` has no elements in common with `other`. @@ -785,7 +832,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: T) -> bool { - self.map.insert(value, ()).is_none() + self.base.insert(value) } /// Adds a value to the set, replacing the existing value, if any, that is equal to the given @@ -806,13 +853,7 @@ where #[inline] #[stable(feature = "set_recovery", since = "1.9.0")] pub fn replace(&mut self, value: T) -> Option { - match self.map.entry(value) { - map::Entry::Occupied(occupied) => Some(occupied.replace_key()), - map::Entry::Vacant(vacant) => { - vacant.insert(()); - None - } - } + self.base.replace(value) } /// Removes a value from the set. Returns whether the value was @@ -840,7 +881,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.remove(value).is_some() + self.base.remove(value) } /// Removes and returns the value in the set, if any, that is equal to the given one. @@ -865,7 +906,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.remove_entry(value).map(|(k, _)| k) + self.base.take(value) } /// Retains only the elements specified by the predicate. @@ -883,11 +924,11 @@ where /// assert_eq!(set.len(), 3); /// ``` #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain(&mut self, mut f: F) + pub fn retain(&mut self, f: F) where F: FnMut(&T) -> bool, { - self.map.retain(|k, _| f(k)); + self.base.retain(f) } } @@ -946,17 +987,17 @@ where { #[inline] fn extend>(&mut self, iter: I) { - self.map.extend(iter.into_iter().map(|k| (k, ()))); + self.base.extend(iter); } #[inline] fn extend_one(&mut self, item: T) { - self.map.insert(item, ()); + self.base.insert(item); } #[inline] fn extend_reserve(&mut self, additional: usize) { - self.map.extend_reserve(additional); + self.base.extend_reserve(additional); } } @@ -973,7 +1014,7 @@ where #[inline] fn extend_one(&mut self, &item: &'a T) { - self.map.insert(item, ()); + self.base.insert(item); } #[inline] @@ -990,7 +1031,7 @@ where /// Creates an empty `HashSet` with the `Default` value for the hasher. #[inline] fn default() -> HashSet { - HashSet { map: HashMap::default() } + HashSet { base: Default::default() } } } @@ -1132,9 +1173,19 @@ where /// See its documentation for more. /// /// [`iter`]: HashSet::iter +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut iter = a.iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a> { - iter: Keys<'a, K, ()>, + base: base::Iter<'a, K>, } /// An owning iterator over the items of a `HashSet`. @@ -1143,9 +1194,19 @@ pub struct Iter<'a, K: 'a> { /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut iter = a.into_iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - iter: map::IntoIter, + base: base::IntoIter, } /// A draining iterator over the items of a `HashSet`. @@ -1154,9 +1215,44 @@ pub struct IntoIter { /// See its documentation for more. /// /// [`drain`]: HashSet::drain +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let mut a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut drain = a.drain(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Drain<'a, K: 'a> { - iter: map::Drain<'a, K, ()>, + base: base::Drain<'a, K>, +} + +/// A draining, filtering iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain_filter`] method on [`HashSet`]. +/// +/// [`drain_filter`]: HashSet::drain_filter +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_drain_filter)] +/// +/// use std::collections::HashSet; +/// +/// let mut a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0); +/// ``` +#[unstable(feature = "hash_drain_filter", issue = "59618")] +pub struct DrainFilter<'a, K, F> +where + F: FnMut(&K) -> bool, +{ + base: base::DrainFilter<'a, K, F>, } /// A lazy iterator producing elements in the intersection of `HashSet`s. @@ -1165,6 +1261,17 @@ pub struct Drain<'a, K: 'a> { /// See its documentation for more. /// /// [`intersection`]: HashSet::intersection +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut intersection = a.intersection(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Intersection<'a, T: 'a, S: 'a> { // iterator of the first set @@ -1179,6 +1286,17 @@ pub struct Intersection<'a, T: 'a, S: 'a> { /// See its documentation for more. /// /// [`difference`]: HashSet::difference +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut difference = a.difference(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Difference<'a, T: 'a, S: 'a> { // iterator of the first set @@ -1193,6 +1311,17 @@ pub struct Difference<'a, T: 'a, S: 'a> { /// [`HashSet`]. See its documentation for more. /// /// [`symmetric_difference`]: HashSet::symmetric_difference +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut intersection = a.symmetric_difference(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct SymmetricDifference<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>>, @@ -1204,6 +1333,17 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> { /// See its documentation for more. /// /// [`union`]: HashSet::union +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut union_iter = a.union(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Union<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>>, @@ -1247,7 +1387,7 @@ impl IntoIterator for HashSet { /// ``` #[inline] fn into_iter(self) -> IntoIter { - IntoIter { iter: self.map.into_iter() } + IntoIter { base: self.base.into_iter() } } } @@ -1255,7 +1395,7 @@ impl IntoIterator for HashSet { impl Clone for Iter<'_, K> { #[inline] fn clone(&self) -> Self { - Iter { iter: self.iter.clone() } + Iter { base: self.base.clone() } } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1264,18 +1404,18 @@ impl<'a, K> Iterator for Iter<'a, K> { #[inline] fn next(&mut self) -> Option<&'a K> { - self.iter.next() + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Iter<'_, K> { #[inline] fn len(&self) -> usize { - self.iter.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -1294,18 +1434,18 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { - self.iter.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -1314,8 +1454,7 @@ impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let entries_iter = self.iter.iter().map(|(k, _)| k); - f.debug_list().entries(entries_iter).finish() + fmt::Debug::fmt(&self.base, f) } } @@ -1325,18 +1464,18 @@ impl<'a, K> Iterator for Drain<'a, K> { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Drain<'_, K> { #[inline] fn len(&self) -> usize { - self.iter.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -1345,8 +1484,37 @@ impl FusedIterator for Drain<'_, K> {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Drain<'_, K> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let entries_iter = self.iter.iter().map(|(k, _)| k); - f.debug_list().entries(entries_iter).finish() + fmt::Debug::fmt(&self.base, f) + } +} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl Iterator for DrainFilter<'_, K, F> +where + F: FnMut(&K) -> bool, +{ + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } +} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl<'a, K, F> fmt::Debug for DrainFilter<'a, K, F> +where + F: FnMut(&K) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("DrainFilter { .. }") } } @@ -1579,422 +1747,3 @@ fn assert_covariance() { d } } - -#[cfg(test)] -mod test_set { - use super::super::map::RandomState; - use super::HashSet; - - #[test] - fn test_zero_capacities() { - type HS = HashSet; - - let s = HS::new(); - assert_eq!(s.capacity(), 0); - - let s = HS::default(); - assert_eq!(s.capacity(), 0); - - let s = HS::with_hasher(RandomState::new()); - assert_eq!(s.capacity(), 0); - - let s = HS::with_capacity(0); - assert_eq!(s.capacity(), 0); - - let s = HS::with_capacity_and_hasher(0, RandomState::new()); - assert_eq!(s.capacity(), 0); - - let mut s = HS::new(); - s.insert(1); - s.insert(2); - s.remove(&1); - s.remove(&2); - s.shrink_to_fit(); - assert_eq!(s.capacity(), 0); - - let mut s = HS::new(); - s.reserve(0); - assert_eq!(s.capacity(), 0); - } - - #[test] - fn test_disjoint() { - let mut xs = HashSet::new(); - let mut ys = HashSet::new(); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(5)); - assert!(ys.insert(11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(7)); - assert!(xs.insert(19)); - assert!(xs.insert(4)); - assert!(ys.insert(2)); - assert!(ys.insert(-11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(ys.insert(7)); - assert!(!xs.is_disjoint(&ys)); - assert!(!ys.is_disjoint(&xs)); - } - - #[test] - fn test_subset_and_superset() { - let mut a = HashSet::new(); - assert!(a.insert(0)); - assert!(a.insert(5)); - assert!(a.insert(11)); - assert!(a.insert(7)); - - let mut b = HashSet::new(); - assert!(b.insert(0)); - assert!(b.insert(7)); - assert!(b.insert(19)); - assert!(b.insert(250)); - assert!(b.insert(11)); - assert!(b.insert(200)); - - assert!(!a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(!b.is_superset(&a)); - - assert!(b.insert(5)); - - assert!(a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(b.is_superset(&a)); - } - - #[test] - fn test_iterate() { - let mut a = HashSet::new(); - for i in 0..32 { - assert!(a.insert(i)); - } - let mut observed: u32 = 0; - for k in &a { - observed |= 1 << *k; - } - assert_eq!(observed, 0xFFFF_FFFF); - } - - #[test] - fn test_intersection() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - assert!(a.intersection(&b).next().is_none()); - - assert!(a.insert(11)); - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(77)); - assert!(a.insert(103)); - assert!(a.insert(5)); - assert!(a.insert(-5)); - - assert!(b.insert(2)); - assert!(b.insert(11)); - assert!(b.insert(77)); - assert!(b.insert(-9)); - assert!(b.insert(-42)); - assert!(b.insert(5)); - assert!(b.insert(3)); - - let mut i = 0; - let expected = [3, 5, 11, 77]; - for x in a.intersection(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - - assert!(a.insert(9)); // make a bigger than b - - i = 0; - for x in a.intersection(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - - i = 0; - for x in b.intersection(&a) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_difference() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(3)); - assert!(b.insert(9)); - - let mut i = 0; - let expected = [1, 5, 11]; - for x in a.difference(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_symmetric_difference() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(-2)); - assert!(b.insert(3)); - assert!(b.insert(9)); - assert!(b.insert(14)); - assert!(b.insert(22)); - - let mut i = 0; - let expected = [-2, 1, 5, 11, 14, 22]; - for x in a.symmetric_difference(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_union() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - assert!(a.union(&b).next().is_none()); - assert!(b.union(&a).next().is_none()); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(11)); - assert!(a.insert(16)); - assert!(a.insert(19)); - assert!(a.insert(24)); - - assert!(b.insert(-2)); - assert!(b.insert(1)); - assert!(b.insert(5)); - assert!(b.insert(9)); - assert!(b.insert(13)); - assert!(b.insert(19)); - - let mut i = 0; - let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; - for x in a.union(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - - assert!(a.insert(9)); // make a bigger than b - assert!(a.insert(5)); - - i = 0; - for x in a.union(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - - i = 0; - for x in b.union(&a) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_from_iter() { - let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]; - - let set: HashSet<_> = xs.iter().cloned().collect(); - - for x in &xs { - assert!(set.contains(x)); - } - - assert_eq!(set.iter().len(), xs.len() - 1); - } - - #[test] - fn test_move_iter() { - let hs = { - let mut hs = HashSet::new(); - - hs.insert('a'); - hs.insert('b'); - - hs - }; - - let v = hs.into_iter().collect::>(); - assert!(v == ['a', 'b'] || v == ['b', 'a']); - } - - #[test] - fn test_eq() { - // These constants once happened to expose a bug in insert(). - // I'm keeping them around to prevent a regression. - let mut s1 = HashSet::new(); - - s1.insert(1); - s1.insert(2); - s1.insert(3); - - let mut s2 = HashSet::new(); - - s2.insert(1); - s2.insert(2); - - assert!(s1 != s2); - - s2.insert(3); - - assert_eq!(s1, s2); - } - - #[test] - fn test_show() { - let mut set = HashSet::new(); - let empty = HashSet::::new(); - - set.insert(1); - set.insert(2); - - let set_str = format!("{:?}", set); - - assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); - assert_eq!(format!("{:?}", empty), "{}"); - } - - #[test] - fn test_trivial_drain() { - let mut s = HashSet::::new(); - for _ in s.drain() {} - assert!(s.is_empty()); - drop(s); - - let mut s = HashSet::::new(); - drop(s.drain()); - assert!(s.is_empty()); - } - - #[test] - fn test_drain() { - let mut s: HashSet<_> = (1..100).collect(); - - // try this a bunch of times to make sure we don't screw up internal state. - for _ in 0..20 { - assert_eq!(s.len(), 99); - - { - let mut last_i = 0; - let mut d = s.drain(); - for (i, x) in d.by_ref().take(50).enumerate() { - last_i = i; - assert!(x != 0); - } - assert_eq!(last_i, 49); - } - - for _ in &s { - panic!("s should be empty!"); - } - - // reset to try again. - s.extend(1..100); - } - } - - #[test] - fn test_replace() { - use crate::hash; - - #[derive(Debug)] - struct Foo(&'static str, i32); - - impl PartialEq for Foo { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl Eq for Foo {} - - impl hash::Hash for Foo { - fn hash(&self, h: &mut H) { - self.0.hash(h); - } - } - - let mut s = HashSet::new(); - assert_eq!(s.replace(Foo("a", 1)), None); - assert_eq!(s.len(), 1); - assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); - assert_eq!(s.len(), 1); - - let mut it = s.iter(); - assert_eq!(it.next(), Some(&Foo("a", 2))); - assert_eq!(it.next(), None); - } - - #[test] - fn test_extend_ref() { - let mut a = HashSet::new(); - a.insert(1); - - a.extend(&[2, 3, 4]); - - assert_eq!(a.len(), 4); - assert!(a.contains(&1)); - assert!(a.contains(&2)); - assert!(a.contains(&3)); - assert!(a.contains(&4)); - - let mut b = HashSet::new(); - b.insert(5); - b.insert(6); - - a.extend(&b); - - assert_eq!(a.len(), 6); - assert!(a.contains(&1)); - assert!(a.contains(&2)); - assert!(a.contains(&3)); - assert!(a.contains(&4)); - assert!(a.contains(&5)); - assert!(a.contains(&6)); - } - - #[test] - fn test_retain() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut set: HashSet = xs.iter().cloned().collect(); - set.retain(|&k| k % 2 == 0); - assert_eq!(set.len(), 3); - assert!(set.contains(&2)); - assert!(set.contains(&4)); - assert!(set.contains(&6)); - } -} diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs new file mode 100644 index 0000000000..40f8467fd9 --- /dev/null +++ b/library/std/src/collections/hash/set/tests.rs @@ -0,0 +1,486 @@ +use super::super::map::RandomState; +use super::HashSet; + +use crate::panic::{catch_unwind, AssertUnwindSafe}; +use crate::sync::atomic::{AtomicU32, Ordering}; + +#[test] +fn test_zero_capacities() { + type HS = HashSet; + + let s = HS::new(); + assert_eq!(s.capacity(), 0); + + let s = HS::default(); + assert_eq!(s.capacity(), 0); + + let s = HS::with_hasher(RandomState::new()); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity(0); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity_and_hasher(0, RandomState::new()); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.insert(1); + s.insert(2); + s.remove(&1); + s.remove(&2); + s.shrink_to_fit(); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.reserve(0); + assert_eq!(s.capacity(), 0); +} + +#[test] +fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.is_disjoint(&ys)); + assert!(!ys.is_disjoint(&xs)); +} + +#[test] +fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(!b.is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(b.is_superset(&a)); +} + +#[test] +fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let mut observed: u32 = 0; + for k in &a { + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); +} + +#[test] +fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + assert!(a.intersection(&b).next().is_none()); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + + assert!(a.insert(9)); // make a bigger than b + + i = 0; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + + i = 0; + for x in b.intersection(&a) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let mut i = 0; + let expected = [1, 5, 11]; + for x in a.difference(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for x in a.symmetric_difference(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + assert!(a.union(&b).next().is_none()); + assert!(b.union(&a).next().is_none()); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + + assert!(a.insert(9)); // make a bigger than b + assert!(a.insert(5)); + + i = 0; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + + i = 0; + for x in b.union(&a) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_from_iter() { + let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.iter().cloned().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + + assert_eq!(set.iter().len(), xs.len() - 1); +} + +#[test] +fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); +} + +#[test] +fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(s1 != s2); + + s2.insert(3); + + assert_eq!(s1, s2); +} + +#[test] +fn test_show() { + let mut set = HashSet::new(); + let empty = HashSet::::new(); + + set.insert(1); + set.insert(2); + + let set_str = format!("{:?}", set); + + assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); + assert_eq!(format!("{:?}", empty), "{}"); +} + +#[test] +fn test_trivial_drain() { + let mut s = HashSet::::new(); + for _ in s.drain() {} + assert!(s.is_empty()); + drop(s); + + let mut s = HashSet::::new(); + drop(s.drain()); + assert!(s.is_empty()); +} + +#[test] +fn test_drain() { + let mut s: HashSet<_> = (1..100).collect(); + + // try this a bunch of times to make sure we don't screw up internal state. + for _ in 0..20 { + assert_eq!(s.len(), 99); + + { + let mut last_i = 0; + let mut d = s.drain(); + for (i, x) in d.by_ref().take(50).enumerate() { + last_i = i; + assert!(x != 0); + } + assert_eq!(last_i, 49); + } + + for _ in &s { + panic!("s should be empty!"); + } + + // reset to try again. + s.extend(1..100); + } +} + +#[test] +fn test_replace() { + use crate::hash; + + #[derive(Debug)] + struct Foo(&'static str, i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl Eq for Foo {} + + impl hash::Hash for Foo { + fn hash(&self, h: &mut H) { + self.0.hash(h); + } + } + + let mut s = HashSet::new(); + assert_eq!(s.replace(Foo("a", 1)), None); + assert_eq!(s.len(), 1); + assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); + assert_eq!(s.len(), 1); + + let mut it = s.iter(); + assert_eq!(it.next(), Some(&Foo("a", 2))); + assert_eq!(it.next(), None); +} + +#[test] +fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.extend(&[2, 3, 4]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); +} + +#[test] +fn test_retain() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut set: HashSet = xs.iter().cloned().collect(); + set.retain(|&k| k % 2 == 0); + assert_eq!(set.len(), 3); + assert!(set.contains(&2)); + assert!(set.contains(&4)); + assert!(set.contains(&6)); +} + +#[test] +fn test_drain_filter() { + let mut x: HashSet<_> = [1].iter().copied().collect(); + let mut y: HashSet<_> = [1].iter().copied().collect(); + + x.drain_filter(|_| true); + y.drain_filter(|_| false); + assert_eq!(x.len(), 0); + assert_eq!(y.len(), 1); +} + +#[test] +fn test_drain_filter_drop_panic_leak() { + static PREDS: AtomicU32 = AtomicU32::new(0); + static DROPS: AtomicU32 = AtomicU32::new(0); + + #[derive(PartialEq, Eq, PartialOrd, Hash)] + struct D(i32); + impl Drop for D { + fn drop(&mut self) { + if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + panic!("panic in `drop`"); + } + } + } + + let mut set = (0..3).map(|i| D(i)).collect::>(); + + catch_unwind(move || { + drop(set.drain_filter(|_| { + PREDS.fetch_add(1, Ordering::SeqCst); + true + })) + }) + .ok(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(DROPS.load(Ordering::SeqCst), 3); +} + +#[test] +fn test_drain_filter_pred_panic_leak() { + static PREDS: AtomicU32 = AtomicU32::new(0); + static DROPS: AtomicU32 = AtomicU32::new(0); + + #[derive(PartialEq, Eq, PartialOrd, Hash)] + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut set: HashSet<_> = (0..3).map(|_| D).collect(); + + catch_unwind(AssertUnwindSafe(|| { + drop(set.drain_filter(|_| match PREDS.fetch_add(1, Ordering::SeqCst) { + 0 => true, + _ => panic!(), + })) + })) + .ok(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 1); + assert_eq!(DROPS.load(Ordering::SeqCst), 3); + assert_eq!(set.len(), 0); +} diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 387c588f4a..b0fceb9b2f 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -10,6 +10,9 @@ #![stable(feature = "env", since = "1.0.0")] +#[cfg(test)] +mod tests; + use crate::error::Error; use crate::ffi::{OsStr, OsString}; use crate::fmt; @@ -65,10 +68,9 @@ pub fn set_current_dir>(path: P) -> io::Result<()> { /// An iterator over a snapshot of the environment variables of this process. /// -/// This structure is created by the [`std::env::vars`] function. See its -/// documentation for more. +/// This structure is created by [`env::vars()`]. See its documentation for more. /// -/// [`std::env::vars`]: vars +/// [`env::vars()`]: vars #[stable(feature = "env", since = "1.0.0")] pub struct Vars { inner: VarsOs, @@ -76,10 +78,9 @@ pub struct Vars { /// An iterator over a snapshot of the environment variables of this process. /// -/// This structure is created by the [`std::env::vars_os`] function. See -/// its documentation for more. +/// This structure is created by [`env::vars_os()`]. See its documentation for more. /// -/// [`std::env::vars_os`]: vars_os +/// [`env::vars_os()`]: vars_os #[stable(feature = "env", since = "1.0.0")] pub struct VarsOs { inner: os_imp::Env, @@ -95,10 +96,8 @@ pub struct VarsOs { /// # Panics /// /// While iterating, the returned iterator will panic if any key or value in the -/// environment is not valid unicode. If this is not desired, consider using the -/// [`env::vars_os`] function. -/// -/// [`env::vars_os`]: vars_os +/// environment is not valid unicode. If this is not desired, consider using +/// [`env::vars_os()`]. /// /// # Examples /// @@ -111,6 +110,8 @@ pub struct VarsOs { /// println!("{}: {}", key, value); /// } /// ``` +/// +/// [`env::vars_os()`]: vars_os #[stable(feature = "env", since = "1.0.0")] pub fn vars() -> Vars { Vars { inner: vars_os() } @@ -242,9 +243,9 @@ fn _var_os(key: &OsStr) -> Option { } /// The error type for operations interacting with environment variables. -/// Possibly returned from the [`env::var`] function. +/// Possibly returned from [`env::var()`]. /// -/// [`env::var`]: var +/// [`env::var()`]: var #[derive(Debug, PartialEq, Eq, Clone)] #[stable(feature = "env", since = "1.0.0")] pub enum VarError { @@ -369,10 +370,10 @@ fn _remove_var(k: &OsStr) { /// /// The iterator element type is [`PathBuf`]. /// -/// This structure is created by the [`std::env::split_paths`] function. See its +/// This structure is created by [`env::split_paths()`]. See its /// documentation for more. /// -/// [`std::env::split_paths`]: split_paths +/// [`env::split_paths()`]: split_paths #[stable(feature = "env", since = "1.0.0")] pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a>, @@ -423,9 +424,9 @@ impl fmt::Debug for SplitPaths<'_> { } /// The error type for operations on the `PATH` variable. Possibly returned from -/// the [`env::join_paths`] function. +/// [`env::join_paths()`]. /// -/// [`env::join_paths`]: join_paths +/// [`env::join_paths()`]: join_paths #[derive(Debug)] #[stable(feature = "env", since = "1.0.0")] pub struct JoinPathsError { @@ -460,7 +461,8 @@ pub struct JoinPathsError { /// } /// ``` /// -/// Joining a path containing a colon on a Unix-like platform results in an error: +/// Joining a path containing a colon on a Unix-like platform results in an +/// error: /// /// ``` /// # if cfg!(unix) { @@ -472,8 +474,8 @@ pub struct JoinPathsError { /// # } /// ``` /// -/// Using `env::join_paths` with [`env::split_paths`] to append an item to the `PATH` environment -/// variable: +/// Using `env::join_paths()` with [`env::split_paths()`] to append an item to +/// the `PATH` environment variable: /// /// ``` /// use std::env; @@ -491,7 +493,7 @@ pub struct JoinPathsError { /// } /// ``` /// -/// [`env::split_paths`]: split_paths +/// [`env::split_paths()`]: split_paths #[stable(feature = "env", since = "1.0.0")] pub fn join_paths(paths: I) -> Result where @@ -664,14 +666,14 @@ pub fn current_exe() -> io::Result { /// An iterator over the arguments of a process, yielding a [`String`] value for /// each argument. /// -/// This struct is created by the [`std::env::args`] function. See its -/// documentation for more. +/// This struct is created by [`env::args()`]. See its documentation +/// for more. /// /// The first element is traditionally the path of the executable, but it can be /// set to arbitrary text, and may not even exist. This means this property /// should not be relied upon for security purposes. /// -/// [`std::env::args`]: args +/// [`env::args()`]: args #[stable(feature = "env", since = "1.0.0")] pub struct Args { inner: ArgsOs, @@ -680,34 +682,34 @@ pub struct Args { /// An iterator over the arguments of a process, yielding an [`OsString`] value /// for each argument. /// -/// This struct is created by the [`std::env::args_os`] function. See its -/// documentation for more. +/// This struct is created by [`env::args_os()`]. See its documentation +/// for more. /// /// The first element is traditionally the path of the executable, but it can be /// set to arbitrary text, and may not even exist. This means this property /// should not be relied upon for security purposes. /// -/// [`std::env::args_os`]: args_os +/// [`env::args_os()`]: args_os #[stable(feature = "env", since = "1.0.0")] pub struct ArgsOs { inner: sys::args::Args, } -/// Returns the arguments which this program was started with (normally passed +/// Returns the arguments that this program was started with (normally passed /// via the command line). /// /// The first element is traditionally the path of the executable, but it can be /// set to arbitrary text, and may not even exist. This means this property should /// not be relied upon for security purposes. /// -/// On Unix systems shell usually expands unquoted arguments with glob patterns +/// On Unix systems the shell usually expands unquoted arguments with glob patterns /// (such as `*` and `?`). On Windows this is not done, and such arguments are /// passed as-is. /// -/// On glibc Linux systems, arguments are retrieved by placing a function in ".init_array". -/// Glibc passes argc, argv, and envp to functions in ".init_array", as a non-standard extension. -/// This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it does on macOS -/// and Windows. +/// On glibc Linux systems, arguments are retrieved by placing a function in `.init_array`. +/// Glibc passes `argc`, `argv`, and `envp` to functions in `.init_array`, as a non-standard +/// extension. This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it +/// does on macOS and Windows. /// /// # Panics /// @@ -944,112 +946,3 @@ pub mod consts { #[stable(feature = "env", since = "1.0.0")] pub const EXE_EXTENSION: &str = os::EXE_EXTENSION; } - -#[cfg(test)] -mod tests { - use super::*; - - use crate::path::Path; - - #[test] - #[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] - fn test_self_exe_path() { - let path = current_exe(); - assert!(path.is_ok()); - let path = path.unwrap(); - - // Hard to test this function - assert!(path.is_absolute()); - } - - #[test] - fn test() { - assert!((!Path::new("test-path").is_absolute())); - - #[cfg(not(target_env = "sgx"))] - current_dir().unwrap(); - } - - #[test] - #[cfg(windows)] - fn split_paths_windows() { - use crate::path::PathBuf; - - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed).collect::>() - == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse(r#""""#, &mut [""])); - assert!(check_parse(";;", &mut ["", "", ""])); - assert!(check_parse(r"c:\", &mut [r"c:\"])); - assert!(check_parse(r"c:\;", &mut [r"c:\", ""])); - assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"])); - assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"])); - assert!(check_parse( - r#"c:\;c:\"foo;bar"\;c:\baz"#, - &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"] - )); - } - - #[test] - #[cfg(unix)] - fn split_paths_unix() { - use crate::path::PathBuf; - - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed).collect::>() - == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse("::", &mut ["", "", ""])); - assert!(check_parse("/", &mut ["/"])); - assert!(check_parse("/:", &mut ["/", ""])); - assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"])); - } - - #[test] - #[cfg(unix)] - fn join_paths_unix() { - use crate::ffi::OsStr; - - fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin")); - assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:")); - assert!(join_paths(["/te:st"].iter().cloned()).is_err()); - } - - #[test] - #[cfg(windows)] - fn join_paths_windows() { - use crate::ffi::OsStr; - - fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\")); - assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;")); - assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#)); - assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err()); - } - - #[test] - fn args_debug() { - assert_eq!( - format!("Args {{ inner: {:?} }}", args().collect::>()), - format!("{:?}", args()) - ); - assert_eq!( - format!("ArgsOs {{ inner: {:?} }}", args_os().collect::>()), - format!("{:?}", args_os()) - ); - } -} diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs new file mode 100644 index 0000000000..94cace03af --- /dev/null +++ b/library/std/src/env/tests.rs @@ -0,0 +1,102 @@ +use super::*; + +use crate::path::Path; + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] +fn test_self_exe_path() { + let path = current_exe(); + assert!(path.is_ok()); + let path = path.unwrap(); + + // Hard to test this function + assert!(path.is_absolute()); +} + +#[test] +fn test() { + assert!((!Path::new("test-path").is_absolute())); + + #[cfg(not(target_env = "sgx"))] + current_dir().unwrap(); +} + +#[test] +#[cfg(windows)] +fn split_paths_windows() { + use crate::path::PathBuf; + + fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { + split_paths(unparsed).collect::>() + == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() + } + + assert!(check_parse("", &mut [""])); + assert!(check_parse(r#""""#, &mut [""])); + assert!(check_parse(";;", &mut ["", "", ""])); + assert!(check_parse(r"c:\", &mut [r"c:\"])); + assert!(check_parse(r"c:\;", &mut [r"c:\", ""])); + assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"])); + assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"])); + assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"])); +} + +#[test] +#[cfg(unix)] +fn split_paths_unix() { + use crate::path::PathBuf; + + fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { + split_paths(unparsed).collect::>() + == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() + } + + assert!(check_parse("", &mut [""])); + assert!(check_parse("::", &mut ["", "", ""])); + assert!(check_parse("/", &mut ["/"])); + assert!(check_parse("/:", &mut ["/", ""])); + assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"])); +} + +#[test] +#[cfg(unix)] +fn join_paths_unix() { + use crate::ffi::OsStr; + + fn test_eq(input: &[&str], output: &str) -> bool { + &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) + } + + assert!(test_eq(&[], "")); + assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin")); + assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:")); + assert!(join_paths(["/te:st"].iter().cloned()).is_err()); +} + +#[test] +#[cfg(windows)] +fn join_paths_windows() { + use crate::ffi::OsStr; + + fn test_eq(input: &[&str], output: &str) -> bool { + &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) + } + + assert!(test_eq(&[], "")); + assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\")); + assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;")); + assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#)); + assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err()); +} + +#[test] +fn args_debug() { + assert_eq!( + format!("Args {{ inner: {:?} }}", args().collect::>()), + format!("{:?}", args()) + ); + assert_eq!( + format!("ArgsOs {{ inner: {:?} }}", args_os().collect::>()), + format!("{:?}", args_os()) + ); +} diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 84e686c2fe..5771ca758a 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -13,10 +13,13 @@ // coherence challenge (e.g., specialization, neg impls, etc) we can // reconsider what crate these items belong in. +#[cfg(test)] +mod tests; + use core::array; use core::convert::Infallible; -use crate::alloc::{AllocErr, LayoutErr}; +use crate::alloc::{AllocError, LayoutErr}; use crate::any::TypeId; use crate::backtrace::Backtrace; use crate::borrow::Cow; @@ -33,15 +36,14 @@ use crate::string; /// themselves through the [`Display`] and [`Debug`] traits, and may provide /// cause chain information: /// -/// The [`source`] method 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 access to that error via the -/// [`source`] method. 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. +/// [`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. /// /// [`Result`]: Result -/// [`source`]: Error::source #[stable(feature = "rust1", since = "1.0.0")] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. @@ -385,13 +387,9 @@ impl Error for ! {} reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838" )] -impl Error for AllocErr {} +impl Error for AllocError {} -#[unstable( - feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked.", - issue = "32838" -)] +#[stable(feature = "alloc_layout", since = "1.28.0")] impl Error for LayoutErr {} #[stable(feature = "rust1", since = "1.0.0")] @@ -636,7 +634,7 @@ impl dyn Error { } /// Returns an iterator starting with the current error and continuing with - /// recursively calling [`source`]. + /// recursively calling [`Error::source`]. /// /// If you want to omit the current error and only use its sources, /// use `skip(1)`. @@ -686,8 +684,6 @@ impl dyn Error { /// assert!(iter.next().is_none()); /// assert!(iter.next().is_none()); /// ``` - /// - /// [`source`]: Error::source #[unstable(feature = "error_iter", issue = "58520")] #[inline] pub fn chain(&self) -> Chain<'_> { @@ -741,44 +737,3 @@ impl dyn Error + Send + Sync { }) } } - -#[cfg(test)] -mod tests { - use super::Error; - use crate::fmt; - - #[derive(Debug, PartialEq)] - struct A; - #[derive(Debug, PartialEq)] - struct B; - - 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 {} - - #[test] - fn downcasting() { - let mut a = A; - let a = &mut a as &mut (dyn Error + 'static); - assert_eq!(a.downcast_ref::(), Some(&A)); - assert_eq!(a.downcast_ref::(), None); - assert_eq!(a.downcast_mut::(), Some(&mut A)); - assert_eq!(a.downcast_mut::(), None); - - let a: Box = Box::new(A); - match a.downcast::() { - Ok(..) => panic!("expected error"), - Err(e) => assert_eq!(*e.downcast::().unwrap(), A), - } - } -} diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs new file mode 100644 index 0000000000..66d6924f34 --- /dev/null +++ b/library/std/src/error/tests.rs @@ -0,0 +1,37 @@ +use super::Error; +use crate::fmt; + +#[derive(Debug, PartialEq)] +struct A; +#[derive(Debug, PartialEq)] +struct B; + +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 {} + +#[test] +fn downcasting() { + let mut a = A; + let a = &mut a as &mut (dyn Error + 'static); + assert_eq!(a.downcast_ref::(), Some(&A)); + assert_eq!(a.downcast_ref::(), None); + assert_eq!(a.downcast_mut::(), Some(&mut A)); + assert_eq!(a.downcast_mut::(), None); + + let a: Box = Box::new(A); + match a.downcast::() { + Ok(..) => panic!("expected error"), + Err(e) => assert_eq!(*e.downcast::().unwrap(), A), + } +} diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index c905bcf5e3..59c2da5273 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -11,6 +11,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] +#[cfg(test)] +mod tests; + #[cfg(not(test))] use crate::intrinsics; #[cfg(not(test))] @@ -909,766 +912,3 @@ impl f32 { x } } - -#[cfg(test)] -mod tests { - use crate::f32::consts; - use crate::num::FpCategory as Fp; - use crate::num::*; - - #[test] - fn test_num_f32() { - test_num(10f32, 2f32); - } - - #[test] - fn test_min_nan() { - assert_eq!(f32::NAN.min(2.0), 2.0); - assert_eq!(2.0f32.min(f32::NAN), 2.0); - } - - #[test] - fn test_max_nan() { - assert_eq!(f32::NAN.max(2.0), 2.0); - assert_eq!(2.0f32.max(f32::NAN), 2.0); - } - - #[test] - fn test_nan() { - let nan: f32 = f32::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - } - - #[test] - fn test_infinity() { - let inf: f32 = f32::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); - } - - #[test] - fn test_neg_infinity() { - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); - } - - #[test] - fn test_zero() { - let zero: f32 = 0.0f32; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); - } - - #[test] - fn test_neg_zero() { - let neg_zero: f32 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); - } - - #[test] - fn test_one() { - let one: f32 = 1.0f32; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); - } - - #[test] - fn test_is_nan() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f32.is_nan()); - assert!(!5.3f32.is_nan()); - assert!(!(-10.732f32).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); - } - - #[test] - fn test_is_infinite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f32.is_infinite()); - assert!(!42.8f32.is_infinite()); - assert!(!(-109.2f32).is_infinite()); - } - - #[test] - fn test_is_finite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f32.is_finite()); - assert!(42.8f32.is_finite()); - assert!((-109.2f32).is_finite()); - } - - #[test] - fn test_is_normal() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); - } - - #[test] - fn test_classify() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f32.classify(), Fp::Normal); - assert_eq!(1e-37f32.classify(), Fp::Normal); - assert_eq!(1e-38f32.classify(), Fp::Subnormal); - } - - #[test] - fn test_floor() { - assert_approx_eq!(1.0f32.floor(), 1.0f32); - assert_approx_eq!(1.3f32.floor(), 1.0f32); - assert_approx_eq!(1.5f32.floor(), 1.0f32); - assert_approx_eq!(1.7f32.floor(), 1.0f32); - assert_approx_eq!(0.0f32.floor(), 0.0f32); - assert_approx_eq!((-0.0f32).floor(), -0.0f32); - assert_approx_eq!((-1.0f32).floor(), -1.0f32); - assert_approx_eq!((-1.3f32).floor(), -2.0f32); - assert_approx_eq!((-1.5f32).floor(), -2.0f32); - assert_approx_eq!((-1.7f32).floor(), -2.0f32); - } - - #[test] - fn test_ceil() { - assert_approx_eq!(1.0f32.ceil(), 1.0f32); - assert_approx_eq!(1.3f32.ceil(), 2.0f32); - assert_approx_eq!(1.5f32.ceil(), 2.0f32); - assert_approx_eq!(1.7f32.ceil(), 2.0f32); - assert_approx_eq!(0.0f32.ceil(), 0.0f32); - assert_approx_eq!((-0.0f32).ceil(), -0.0f32); - assert_approx_eq!((-1.0f32).ceil(), -1.0f32); - assert_approx_eq!((-1.3f32).ceil(), -1.0f32); - assert_approx_eq!((-1.5f32).ceil(), -1.0f32); - assert_approx_eq!((-1.7f32).ceil(), -1.0f32); - } - - #[test] - fn test_round() { - assert_approx_eq!(1.0f32.round(), 1.0f32); - assert_approx_eq!(1.3f32.round(), 1.0f32); - assert_approx_eq!(1.5f32.round(), 2.0f32); - assert_approx_eq!(1.7f32.round(), 2.0f32); - assert_approx_eq!(0.0f32.round(), 0.0f32); - assert_approx_eq!((-0.0f32).round(), -0.0f32); - assert_approx_eq!((-1.0f32).round(), -1.0f32); - assert_approx_eq!((-1.3f32).round(), -1.0f32); - assert_approx_eq!((-1.5f32).round(), -2.0f32); - assert_approx_eq!((-1.7f32).round(), -2.0f32); - } - - #[test] - fn test_trunc() { - assert_approx_eq!(1.0f32.trunc(), 1.0f32); - assert_approx_eq!(1.3f32.trunc(), 1.0f32); - assert_approx_eq!(1.5f32.trunc(), 1.0f32); - assert_approx_eq!(1.7f32.trunc(), 1.0f32); - assert_approx_eq!(0.0f32.trunc(), 0.0f32); - assert_approx_eq!((-0.0f32).trunc(), -0.0f32); - assert_approx_eq!((-1.0f32).trunc(), -1.0f32); - assert_approx_eq!((-1.3f32).trunc(), -1.0f32); - assert_approx_eq!((-1.5f32).trunc(), -1.0f32); - assert_approx_eq!((-1.7f32).trunc(), -1.0f32); - } - - #[test] - fn test_fract() { - assert_approx_eq!(1.0f32.fract(), 0.0f32); - assert_approx_eq!(1.3f32.fract(), 0.3f32); - assert_approx_eq!(1.5f32.fract(), 0.5f32); - assert_approx_eq!(1.7f32.fract(), 0.7f32); - assert_approx_eq!(0.0f32.fract(), 0.0f32); - assert_approx_eq!((-0.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.3f32).fract(), -0.3f32); - assert_approx_eq!((-1.5f32).fract(), -0.5f32); - assert_approx_eq!((-1.7f32).fract(), -0.7f32); - } - - #[test] - fn test_abs() { - assert_eq!(f32::INFINITY.abs(), f32::INFINITY); - assert_eq!(1f32.abs(), 1f32); - assert_eq!(0f32.abs(), 0f32); - assert_eq!((-0f32).abs(), 0f32); - assert_eq!((-1f32).abs(), 1f32); - assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY); - assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32); - assert!(f32::NAN.abs().is_nan()); - } - - #[test] - fn test_signum() { - assert_eq!(f32::INFINITY.signum(), 1f32); - assert_eq!(1f32.signum(), 1f32); - assert_eq!(0f32.signum(), 1f32); - assert_eq!((-0f32).signum(), -1f32); - assert_eq!((-1f32).signum(), -1f32); - assert_eq!(f32::NEG_INFINITY.signum(), -1f32); - assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32); - assert!(f32::NAN.signum().is_nan()); - } - - #[test] - fn test_is_sign_positive() { - assert!(f32::INFINITY.is_sign_positive()); - assert!(1f32.is_sign_positive()); - assert!(0f32.is_sign_positive()); - assert!(!(-0f32).is_sign_positive()); - assert!(!(-1f32).is_sign_positive()); - assert!(!f32::NEG_INFINITY.is_sign_positive()); - assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive()); - assert!(f32::NAN.is_sign_positive()); - assert!(!(-f32::NAN).is_sign_positive()); - } - - #[test] - fn test_is_sign_negative() { - assert!(!f32::INFINITY.is_sign_negative()); - assert!(!1f32.is_sign_negative()); - assert!(!0f32.is_sign_negative()); - assert!((-0f32).is_sign_negative()); - assert!((-1f32).is_sign_negative()); - assert!(f32::NEG_INFINITY.is_sign_negative()); - assert!((1f32 / f32::NEG_INFINITY).is_sign_negative()); - assert!(!f32::NAN.is_sign_negative()); - assert!((-f32::NAN).is_sign_negative()); - } - - #[test] - fn test_mul_add() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05); - assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65); - assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2); - assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f32.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf); - } - - #[test] - fn test_recip() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.recip(), 1.0); - assert_eq!(2.0f32.recip(), 0.5); - assert_eq!((-0.4f32).recip(), -2.5); - assert_eq!(0.0f32.recip(), inf); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); - } - - #[test] - fn test_powi() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.powi(1), 1.0); - assert_approx_eq!((-3.1f32).powi(2), 9.61); - assert_approx_eq!(5.9f32.powi(-2), 0.028727); - assert_eq!(8.3f32.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); - } - - #[test] - fn test_powf() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.powf(1.0), 1.0); - assert_approx_eq!(3.4f32.powf(4.5), 246.408218); - assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); - assert_approx_eq!((-3.1f32).powf(2.0), 9.61); - assert_approx_eq!(5.9f32.powf(-2.0), 0.028727); - assert_eq!(8.3f32.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); - } - - #[test] - fn test_sqrt_domain() { - assert!(f32::NAN.sqrt().is_nan()); - assert!(f32::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f32).sqrt().is_nan()); - assert_eq!((-0.0f32).sqrt(), -0.0); - assert_eq!(0.0f32.sqrt(), 0.0); - assert_eq!(1.0f32.sqrt(), 1.0); - assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); - } - - #[test] - fn test_exp() { - assert_eq!(1.0, 0.0f32.exp()); - assert_approx_eq!(2.718282, 1.0f32.exp()); - assert_approx_eq!(148.413162, 5.0f32.exp()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); - } - - #[test] - fn test_exp2() { - assert_eq!(32.0, 5.0f32.exp2()); - assert_eq!(1.0, 0.0f32.exp2()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); - } - - #[test] - fn test_ln() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(1.0f32.exp().ln(), 1.0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f32).ln().is_nan()); - assert_eq!((-0.0f32).ln(), neg_inf); - assert_eq!(0.0f32.ln(), neg_inf); - assert_approx_eq!(4.0f32.ln(), 1.386294); - } - - #[test] - fn test_log() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log(10.0), 1.0); - assert_approx_eq!(2.3f32.log(3.5), 0.664858); - assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); - assert!(1.0f32.log(1.0).is_nan()); - assert!(1.0f32.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f32).log(0.1).is_nan()); - assert_eq!((-0.0f32).log(2.0), neg_inf); - assert_eq!(0.0f32.log(7.0), neg_inf); - } - - #[test] - fn test_log2() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(10.0f32.log2(), 3.321928); - assert_approx_eq!(2.3f32.log2(), 1.201634); - assert_approx_eq!(1.0f32.exp().log2(), 1.442695); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f32).log2().is_nan()); - assert_eq!((-0.0f32).log2(), neg_inf); - assert_eq!(0.0f32.log2(), neg_inf); - } - - #[test] - fn test_log10() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log10(), 1.0); - assert_approx_eq!(2.3f32.log10(), 0.361728); - assert_approx_eq!(1.0f32.exp().log10(), 0.434294); - assert_eq!(1.0f32.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f32).log10().is_nan()); - assert_eq!((-0.0f32).log10(), neg_inf); - assert_eq!(0.0f32.log10(), neg_inf); - } - - #[test] - fn test_to_degrees() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(0.0f32.to_degrees(), 0.0); - assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); - assert_eq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); - } - - #[test] - fn test_to_radians() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(0.0f32.to_radians(), 0.0); - assert_approx_eq!(154.6f32.to_radians(), 2.698279); - assert_approx_eq!((-332.31f32).to_radians(), -5.799903); - assert_eq!(180.0f32.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); - } - - #[test] - fn test_asinh() { - assert_eq!(0.0f32.asinh(), 0.0f32); - assert_eq!((-0.0f32).asinh(), -0.0f32); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271 - assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); - assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32); - } - - #[test] - fn test_acosh() { - assert_eq!(1.0f32.acosh(), 0.0f32); - assert!(0.999f32.acosh().is_nan()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); - assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); - } - - #[test] - fn test_atanh() { - assert_eq!(0.0f32.atanh(), 0.0f32); - assert_eq!((-0.0f32).atanh(), -0.0f32); - - let inf32: f32 = f32::INFINITY; - let neg_inf32: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.atanh(), inf32); - assert_eq!((-1.0f32).atanh(), neg_inf32); - - assert!(2f64.atanh().atanh().is_nan()); - assert!((-2f64).atanh().atanh().is_nan()); - - let inf64: f32 = f32::INFINITY; - let neg_inf64: f32 = f32::NEG_INFINITY; - let nan32: f32 = f32::NAN; - assert!(inf64.atanh().is_nan()); - assert!(neg_inf64.atanh().is_nan()); - assert!(nan32.atanh().is_nan()); - - assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); - assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); - } - - #[test] - fn test_real_consts() { - use super::consts; - - let pi: f32 = consts::PI; - let frac_pi_2: f32 = consts::FRAC_PI_2; - let frac_pi_3: f32 = consts::FRAC_PI_3; - let frac_pi_4: f32 = consts::FRAC_PI_4; - let frac_pi_6: f32 = consts::FRAC_PI_6; - let frac_pi_8: f32 = consts::FRAC_PI_8; - let frac_1_pi: f32 = consts::FRAC_1_PI; - let frac_2_pi: f32 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI; - let sqrt2: f32 = consts::SQRT_2; - let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2; - let e: f32 = consts::E; - let log2_e: f32 = consts::LOG2_E; - let log10_e: f32 = consts::LOG10_E; - let ln_2: f32 = consts::LN_2; - let ln_10: f32 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f32); - assert_approx_eq!(frac_pi_3, pi / 3f32); - assert_approx_eq!(frac_pi_4, pi / 4f32); - assert_approx_eq!(frac_pi_6, pi / 6f32); - assert_approx_eq!(frac_pi_8, pi / 8f32); - assert_approx_eq!(frac_1_pi, 1f32 / pi); - assert_approx_eq!(frac_2_pi, 2f32 / pi); - assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt()); - assert_approx_eq!(sqrt2, 2f32.sqrt()); - assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt()); - assert_approx_eq!(log2_e, e.log2()); - assert_approx_eq!(log10_e, e.log10()); - assert_approx_eq!(ln_2, 2f32.ln()); - assert_approx_eq!(ln_10, 10f32.ln()); - } - - #[test] - fn test_float_bits_conv() { - assert_eq!((1f32).to_bits(), 0x3f800000); - assert_eq!((12.5f32).to_bits(), 0x41480000); - assert_eq!((1337f32).to_bits(), 0x44a72000); - assert_eq!((-14.25f32).to_bits(), 0xc1640000); - assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); - assert_approx_eq!(f32::from_bits(0x41480000), 12.5); - assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); - assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA; - let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555; - assert!(f32::from_bits(masked_nan1).is_nan()); - assert!(f32::from_bits(masked_nan2).is_nan()); - - assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2); - } - - #[test] - #[should_panic] - fn test_clamp_min_greater_than_max() { - let _ = 1.0f32.clamp(3.0, 1.0); - } - - #[test] - #[should_panic] - fn test_clamp_min_is_nan() { - let _ = 1.0f32.clamp(f32::NAN, 1.0); - } - - #[test] - #[should_panic] - fn test_clamp_max_is_nan() { - let _ = 1.0f32.clamp(3.0, f32::NAN); - } - - #[test] - fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u32 { - 1 << (f32::MANTISSA_DIGITS - 2) - } - - fn min_subnorm() -> f32 { - f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0) - } - - fn max_subnorm() -> f32 { - f32::MIN_POSITIVE - min_subnorm() - } - - fn q_nan() -> f32 { - f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f32 { - f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42) - } - - assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0)); - assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX)); - assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); - assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0)); - assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX)); - assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan())); - assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5)); - assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0)); - assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); - assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); - } -} diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs new file mode 100644 index 0000000000..0d4b865f33 --- /dev/null +++ b/library/std/src/f32/tests.rs @@ -0,0 +1,759 @@ +use crate::f32::consts; +use crate::num::FpCategory as Fp; +use crate::num::*; + +#[test] +fn test_num_f32() { + test_num(10f32, 2f32); +} + +#[test] +fn test_min_nan() { + assert_eq!(f32::NAN.min(2.0), 2.0); + assert_eq!(2.0f32.min(f32::NAN), 2.0); +} + +#[test] +fn test_max_nan() { + assert_eq!(f32::NAN.max(2.0), 2.0); + assert_eq!(2.0f32.max(f32::NAN), 2.0); +} + +#[test] +fn test_nan() { + let nan: f32 = f32::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(!nan.is_normal()); + assert!(nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert_eq!(Fp::Nan, nan.classify()); +} + +#[test] +fn test_infinity() { + let inf: f32 = f32::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); +} + +#[test] +fn test_neg_infinity() { + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); +} + +#[test] +fn test_zero() { + let zero: f32 = 0.0f32; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); +} + +#[test] +fn test_neg_zero() { + let neg_zero: f32 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); +} + +#[test] +fn test_one() { + let one: f32 = 1.0f32; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); +} + +#[test] +fn test_is_nan() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f32.is_nan()); + assert!(!5.3f32.is_nan()); + assert!(!(-10.732f32).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); +} + +#[test] +fn test_is_infinite() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f32.is_infinite()); + assert!(!42.8f32.is_infinite()); + assert!(!(-109.2f32).is_infinite()); +} + +#[test] +fn test_is_finite() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f32.is_finite()); + assert!(42.8f32.is_finite()); + assert!((-109.2f32).is_finite()); +} + +#[test] +fn test_is_normal() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f32.is_normal()); + assert!(1e-37f32.is_normal()); + assert!(!1e-38f32.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f32.classify(), Fp::Normal); + assert_eq!(1e-37f32.classify(), Fp::Normal); + assert_eq!(1e-38f32.classify(), Fp::Subnormal); +} + +#[test] +fn test_floor() { + assert_approx_eq!(1.0f32.floor(), 1.0f32); + assert_approx_eq!(1.3f32.floor(), 1.0f32); + assert_approx_eq!(1.5f32.floor(), 1.0f32); + assert_approx_eq!(1.7f32.floor(), 1.0f32); + assert_approx_eq!(0.0f32.floor(), 0.0f32); + assert_approx_eq!((-0.0f32).floor(), -0.0f32); + assert_approx_eq!((-1.0f32).floor(), -1.0f32); + assert_approx_eq!((-1.3f32).floor(), -2.0f32); + assert_approx_eq!((-1.5f32).floor(), -2.0f32); + assert_approx_eq!((-1.7f32).floor(), -2.0f32); +} + +#[test] +fn test_ceil() { + assert_approx_eq!(1.0f32.ceil(), 1.0f32); + assert_approx_eq!(1.3f32.ceil(), 2.0f32); + assert_approx_eq!(1.5f32.ceil(), 2.0f32); + assert_approx_eq!(1.7f32.ceil(), 2.0f32); + assert_approx_eq!(0.0f32.ceil(), 0.0f32); + assert_approx_eq!((-0.0f32).ceil(), -0.0f32); + assert_approx_eq!((-1.0f32).ceil(), -1.0f32); + assert_approx_eq!((-1.3f32).ceil(), -1.0f32); + assert_approx_eq!((-1.5f32).ceil(), -1.0f32); + assert_approx_eq!((-1.7f32).ceil(), -1.0f32); +} + +#[test] +fn test_round() { + assert_approx_eq!(1.0f32.round(), 1.0f32); + assert_approx_eq!(1.3f32.round(), 1.0f32); + assert_approx_eq!(1.5f32.round(), 2.0f32); + assert_approx_eq!(1.7f32.round(), 2.0f32); + assert_approx_eq!(0.0f32.round(), 0.0f32); + assert_approx_eq!((-0.0f32).round(), -0.0f32); + assert_approx_eq!((-1.0f32).round(), -1.0f32); + assert_approx_eq!((-1.3f32).round(), -1.0f32); + assert_approx_eq!((-1.5f32).round(), -2.0f32); + assert_approx_eq!((-1.7f32).round(), -2.0f32); +} + +#[test] +fn test_trunc() { + assert_approx_eq!(1.0f32.trunc(), 1.0f32); + assert_approx_eq!(1.3f32.trunc(), 1.0f32); + assert_approx_eq!(1.5f32.trunc(), 1.0f32); + assert_approx_eq!(1.7f32.trunc(), 1.0f32); + assert_approx_eq!(0.0f32.trunc(), 0.0f32); + assert_approx_eq!((-0.0f32).trunc(), -0.0f32); + assert_approx_eq!((-1.0f32).trunc(), -1.0f32); + assert_approx_eq!((-1.3f32).trunc(), -1.0f32); + assert_approx_eq!((-1.5f32).trunc(), -1.0f32); + assert_approx_eq!((-1.7f32).trunc(), -1.0f32); +} + +#[test] +fn test_fract() { + assert_approx_eq!(1.0f32.fract(), 0.0f32); + assert_approx_eq!(1.3f32.fract(), 0.3f32); + assert_approx_eq!(1.5f32.fract(), 0.5f32); + assert_approx_eq!(1.7f32.fract(), 0.7f32); + assert_approx_eq!(0.0f32.fract(), 0.0f32); + assert_approx_eq!((-0.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.3f32).fract(), -0.3f32); + assert_approx_eq!((-1.5f32).fract(), -0.5f32); + assert_approx_eq!((-1.7f32).fract(), -0.7f32); +} + +#[test] +fn test_abs() { + assert_eq!(f32::INFINITY.abs(), f32::INFINITY); + assert_eq!(1f32.abs(), 1f32); + assert_eq!(0f32.abs(), 0f32); + assert_eq!((-0f32).abs(), 0f32); + assert_eq!((-1f32).abs(), 1f32); + assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY); + assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32); + assert!(f32::NAN.abs().is_nan()); +} + +#[test] +fn test_signum() { + assert_eq!(f32::INFINITY.signum(), 1f32); + assert_eq!(1f32.signum(), 1f32); + assert_eq!(0f32.signum(), 1f32); + assert_eq!((-0f32).signum(), -1f32); + assert_eq!((-1f32).signum(), -1f32); + assert_eq!(f32::NEG_INFINITY.signum(), -1f32); + assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32); + assert!(f32::NAN.signum().is_nan()); +} + +#[test] +fn test_is_sign_positive() { + assert!(f32::INFINITY.is_sign_positive()); + assert!(1f32.is_sign_positive()); + assert!(0f32.is_sign_positive()); + assert!(!(-0f32).is_sign_positive()); + assert!(!(-1f32).is_sign_positive()); + assert!(!f32::NEG_INFINITY.is_sign_positive()); + assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive()); + assert!(f32::NAN.is_sign_positive()); + assert!(!(-f32::NAN).is_sign_positive()); +} + +#[test] +fn test_is_sign_negative() { + assert!(!f32::INFINITY.is_sign_negative()); + assert!(!1f32.is_sign_negative()); + assert!(!0f32.is_sign_negative()); + assert!((-0f32).is_sign_negative()); + assert!((-1f32).is_sign_negative()); + assert!(f32::NEG_INFINITY.is_sign_negative()); + assert!((1f32 / f32::NEG_INFINITY).is_sign_negative()); + assert!(!f32::NAN.is_sign_negative()); + assert!((-f32::NAN).is_sign_negative()); +} + +#[test] +fn test_mul_add() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05); + assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65); + assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2); + assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f32.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf); +} + +#[test] +fn test_recip() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.recip(), 1.0); + assert_eq!(2.0f32.recip(), 0.5); + assert_eq!((-0.4f32).recip(), -2.5); + assert_eq!(0.0f32.recip(), inf); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); +} + +#[test] +fn test_powi() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.powi(1), 1.0); + assert_approx_eq!((-3.1f32).powi(2), 9.61); + assert_approx_eq!(5.9f32.powi(-2), 0.028727); + assert_eq!(8.3f32.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +fn test_powf() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.powf(1.0), 1.0); + assert_approx_eq!(3.4f32.powf(4.5), 246.408218); + assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); + assert_approx_eq!((-3.1f32).powf(2.0), 9.61); + assert_approx_eq!(5.9f32.powf(-2.0), 0.028727); + assert_eq!(8.3f32.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +fn test_sqrt_domain() { + assert!(f32::NAN.sqrt().is_nan()); + assert!(f32::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f32).sqrt().is_nan()); + assert_eq!((-0.0f32).sqrt(), -0.0); + assert_eq!(0.0f32.sqrt(), 0.0); + assert_eq!(1.0f32.sqrt(), 1.0); + assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); +} + +#[test] +fn test_exp() { + assert_eq!(1.0, 0.0f32.exp()); + assert_approx_eq!(2.718282, 1.0f32.exp()); + assert_approx_eq!(148.413162, 5.0f32.exp()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +fn test_exp2() { + assert_eq!(32.0, 5.0f32.exp2()); + assert_eq!(1.0, 0.0f32.exp2()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +fn test_ln() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(1.0f32.exp().ln(), 1.0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f32).ln().is_nan()); + assert_eq!((-0.0f32).ln(), neg_inf); + assert_eq!(0.0f32.ln(), neg_inf); + assert_approx_eq!(4.0f32.ln(), 1.386294); +} + +#[test] +fn test_log() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(10.0f32.log(10.0), 1.0); + assert_approx_eq!(2.3f32.log(3.5), 0.664858); + assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); + assert!(1.0f32.log(1.0).is_nan()); + assert!(1.0f32.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f32).log(0.1).is_nan()); + assert_eq!((-0.0f32).log(2.0), neg_inf); + assert_eq!(0.0f32.log(7.0), neg_inf); +} + +#[test] +fn test_log2() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(10.0f32.log2(), 3.321928); + assert_approx_eq!(2.3f32.log2(), 1.201634); + assert_approx_eq!(1.0f32.exp().log2(), 1.442695); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f32).log2().is_nan()); + assert_eq!((-0.0f32).log2(), neg_inf); + assert_eq!(0.0f32.log2(), neg_inf); +} + +#[test] +fn test_log10() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(10.0f32.log10(), 1.0); + assert_approx_eq!(2.3f32.log10(), 0.361728); + assert_approx_eq!(1.0f32.exp().log10(), 0.434294); + assert_eq!(1.0f32.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f32).log10().is_nan()); + assert_eq!((-0.0f32).log10(), neg_inf); + assert_eq!(0.0f32.log10(), neg_inf); +} + +#[test] +fn test_to_degrees() { + let pi: f32 = consts::PI; + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(0.0f32.to_degrees(), 0.0); + assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); + assert_eq!(pi.to_degrees(), 180.0); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); + assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); +} + +#[test] +fn test_to_radians() { + let pi: f32 = consts::PI; + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(0.0f32.to_radians(), 0.0); + assert_approx_eq!(154.6f32.to_radians(), 2.698279); + assert_approx_eq!((-332.31f32).to_radians(), -5.799903); + assert_eq!(180.0f32.to_radians(), pi); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); +} + +#[test] +fn test_asinh() { + assert_eq!(0.0f32.asinh(), 0.0f32); + assert_eq!((-0.0f32).asinh(), -0.0f32); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271 + assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); + assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32); +} + +#[test] +fn test_acosh() { + assert_eq!(1.0f32.acosh(), 0.0f32); + assert!(0.999f32.acosh().is_nan()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); + assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); +} + +#[test] +fn test_atanh() { + assert_eq!(0.0f32.atanh(), 0.0f32); + assert_eq!((-0.0f32).atanh(), -0.0f32); + + let inf32: f32 = f32::INFINITY; + let neg_inf32: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.atanh(), inf32); + assert_eq!((-1.0f32).atanh(), neg_inf32); + + assert!(2f64.atanh().atanh().is_nan()); + assert!((-2f64).atanh().atanh().is_nan()); + + let inf64: f32 = f32::INFINITY; + let neg_inf64: f32 = f32::NEG_INFINITY; + let nan32: f32 = f32::NAN; + assert!(inf64.atanh().is_nan()); + assert!(neg_inf64.atanh().is_nan()); + assert!(nan32.atanh().is_nan()); + + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); + assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); +} + +#[test] +fn test_real_consts() { + use super::consts; + + let pi: f32 = consts::PI; + let frac_pi_2: f32 = consts::FRAC_PI_2; + let frac_pi_3: f32 = consts::FRAC_PI_3; + let frac_pi_4: f32 = consts::FRAC_PI_4; + let frac_pi_6: f32 = consts::FRAC_PI_6; + let frac_pi_8: f32 = consts::FRAC_PI_8; + let frac_1_pi: f32 = consts::FRAC_1_PI; + let frac_2_pi: f32 = consts::FRAC_2_PI; + let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI; + let sqrt2: f32 = consts::SQRT_2; + let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2; + let e: f32 = consts::E; + let log2_e: f32 = consts::LOG2_E; + let log10_e: f32 = consts::LOG10_E; + let ln_2: f32 = consts::LN_2; + let ln_10: f32 = consts::LN_10; + + assert_approx_eq!(frac_pi_2, pi / 2f32); + assert_approx_eq!(frac_pi_3, pi / 3f32); + assert_approx_eq!(frac_pi_4, pi / 4f32); + assert_approx_eq!(frac_pi_6, pi / 6f32); + assert_approx_eq!(frac_pi_8, pi / 8f32); + assert_approx_eq!(frac_1_pi, 1f32 / pi); + assert_approx_eq!(frac_2_pi, 2f32 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f32.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f32.ln()); + assert_approx_eq!(ln_10, 10f32.ln()); +} + +#[test] +fn test_float_bits_conv() { + assert_eq!((1f32).to_bits(), 0x3f800000); + assert_eq!((12.5f32).to_bits(), 0x41480000); + assert_eq!((1337f32).to_bits(), 0x44a72000); + assert_eq!((-14.25f32).to_bits(), 0xc1640000); + assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); + assert_approx_eq!(f32::from_bits(0x41480000), 12.5); + assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); + assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signaling-ness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA; + let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555; + assert!(f32::from_bits(masked_nan1).is_nan()); + assert!(f32::from_bits(masked_nan2).is_nan()); + + assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1); + assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2); +} + +#[test] +#[should_panic] +fn test_clamp_min_greater_than_max() { + let _ = 1.0f32.clamp(3.0, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_min_is_nan() { + let _ = 1.0f32.clamp(f32::NAN, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_max_is_nan() { + let _ = 1.0f32.clamp(3.0, f32::NAN); +} + +#[test] +fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u32 { + 1 << (f32::MANTISSA_DIGITS - 2) + } + + fn min_subnorm() -> f32 { + f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0) + } + + fn max_subnorm() -> f32 { + f32::MIN_POSITIVE - min_subnorm() + } + + fn q_nan() -> f32 { + f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f32 { + f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0)); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0)); + assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5)); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0)); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); +} diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index f09fc8d790..bd094bdb55 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -11,6 +11,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] +#[cfg(test)] +mod tests; + #[cfg(not(test))] use crate::intrinsics; #[cfg(not(test))] @@ -936,762 +939,3 @@ impl f64 { } } } - -#[cfg(test)] -mod tests { - use crate::f64::consts; - use crate::num::FpCategory as Fp; - use crate::num::*; - - #[test] - fn test_num_f64() { - test_num(10f64, 2f64); - } - - #[test] - fn test_min_nan() { - assert_eq!(f64::NAN.min(2.0), 2.0); - assert_eq!(2.0f64.min(f64::NAN), 2.0); - } - - #[test] - fn test_max_nan() { - assert_eq!(f64::NAN.max(2.0), 2.0); - assert_eq!(2.0f64.max(f64::NAN), 2.0); - } - - #[test] - fn test_nan() { - let nan: f64 = f64::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - } - - #[test] - fn test_infinity() { - let inf: f64 = f64::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); - } - - #[test] - fn test_neg_infinity() { - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); - } - - #[test] - fn test_zero() { - let zero: f64 = 0.0f64; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); - } - - #[test] - fn test_neg_zero() { - let neg_zero: f64 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); - } - - #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 - #[test] - fn test_one() { - let one: f64 = 1.0f64; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); - } - - #[test] - fn test_is_nan() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f64.is_nan()); - assert!(!5.3f64.is_nan()); - assert!(!(-10.732f64).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); - } - - #[test] - fn test_is_infinite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f64.is_infinite()); - assert!(!42.8f64.is_infinite()); - assert!(!(-109.2f64).is_infinite()); - } - - #[test] - fn test_is_finite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f64.is_finite()); - assert!(42.8f64.is_finite()); - assert!((-109.2f64).is_finite()); - } - - #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 - #[test] - fn test_is_normal() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); - } - - #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 - #[test] - fn test_classify() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1e-307f64.classify(), Fp::Normal); - assert_eq!(1e-308f64.classify(), Fp::Subnormal); - } - - #[test] - fn test_floor() { - assert_approx_eq!(1.0f64.floor(), 1.0f64); - assert_approx_eq!(1.3f64.floor(), 1.0f64); - assert_approx_eq!(1.5f64.floor(), 1.0f64); - assert_approx_eq!(1.7f64.floor(), 1.0f64); - assert_approx_eq!(0.0f64.floor(), 0.0f64); - assert_approx_eq!((-0.0f64).floor(), -0.0f64); - assert_approx_eq!((-1.0f64).floor(), -1.0f64); - assert_approx_eq!((-1.3f64).floor(), -2.0f64); - assert_approx_eq!((-1.5f64).floor(), -2.0f64); - assert_approx_eq!((-1.7f64).floor(), -2.0f64); - } - - #[test] - fn test_ceil() { - assert_approx_eq!(1.0f64.ceil(), 1.0f64); - assert_approx_eq!(1.3f64.ceil(), 2.0f64); - assert_approx_eq!(1.5f64.ceil(), 2.0f64); - assert_approx_eq!(1.7f64.ceil(), 2.0f64); - assert_approx_eq!(0.0f64.ceil(), 0.0f64); - assert_approx_eq!((-0.0f64).ceil(), -0.0f64); - assert_approx_eq!((-1.0f64).ceil(), -1.0f64); - assert_approx_eq!((-1.3f64).ceil(), -1.0f64); - assert_approx_eq!((-1.5f64).ceil(), -1.0f64); - assert_approx_eq!((-1.7f64).ceil(), -1.0f64); - } - - #[test] - fn test_round() { - assert_approx_eq!(1.0f64.round(), 1.0f64); - assert_approx_eq!(1.3f64.round(), 1.0f64); - assert_approx_eq!(1.5f64.round(), 2.0f64); - assert_approx_eq!(1.7f64.round(), 2.0f64); - assert_approx_eq!(0.0f64.round(), 0.0f64); - assert_approx_eq!((-0.0f64).round(), -0.0f64); - assert_approx_eq!((-1.0f64).round(), -1.0f64); - assert_approx_eq!((-1.3f64).round(), -1.0f64); - assert_approx_eq!((-1.5f64).round(), -2.0f64); - assert_approx_eq!((-1.7f64).round(), -2.0f64); - } - - #[test] - fn test_trunc() { - assert_approx_eq!(1.0f64.trunc(), 1.0f64); - assert_approx_eq!(1.3f64.trunc(), 1.0f64); - assert_approx_eq!(1.5f64.trunc(), 1.0f64); - assert_approx_eq!(1.7f64.trunc(), 1.0f64); - assert_approx_eq!(0.0f64.trunc(), 0.0f64); - assert_approx_eq!((-0.0f64).trunc(), -0.0f64); - assert_approx_eq!((-1.0f64).trunc(), -1.0f64); - assert_approx_eq!((-1.3f64).trunc(), -1.0f64); - assert_approx_eq!((-1.5f64).trunc(), -1.0f64); - assert_approx_eq!((-1.7f64).trunc(), -1.0f64); - } - - #[test] - fn test_fract() { - assert_approx_eq!(1.0f64.fract(), 0.0f64); - assert_approx_eq!(1.3f64.fract(), 0.3f64); - assert_approx_eq!(1.5f64.fract(), 0.5f64); - assert_approx_eq!(1.7f64.fract(), 0.7f64); - assert_approx_eq!(0.0f64.fract(), 0.0f64); - assert_approx_eq!((-0.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.3f64).fract(), -0.3f64); - assert_approx_eq!((-1.5f64).fract(), -0.5f64); - assert_approx_eq!((-1.7f64).fract(), -0.7f64); - } - - #[test] - fn test_abs() { - assert_eq!(f64::INFINITY.abs(), f64::INFINITY); - assert_eq!(1f64.abs(), 1f64); - assert_eq!(0f64.abs(), 0f64); - assert_eq!((-0f64).abs(), 0f64); - assert_eq!((-1f64).abs(), 1f64); - assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY); - assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64); - assert!(f64::NAN.abs().is_nan()); - } - - #[test] - fn test_signum() { - assert_eq!(f64::INFINITY.signum(), 1f64); - assert_eq!(1f64.signum(), 1f64); - assert_eq!(0f64.signum(), 1f64); - assert_eq!((-0f64).signum(), -1f64); - assert_eq!((-1f64).signum(), -1f64); - assert_eq!(f64::NEG_INFINITY.signum(), -1f64); - assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64); - assert!(f64::NAN.signum().is_nan()); - } - - #[test] - fn test_is_sign_positive() { - assert!(f64::INFINITY.is_sign_positive()); - assert!(1f64.is_sign_positive()); - assert!(0f64.is_sign_positive()); - assert!(!(-0f64).is_sign_positive()); - assert!(!(-1f64).is_sign_positive()); - assert!(!f64::NEG_INFINITY.is_sign_positive()); - assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive()); - assert!(f64::NAN.is_sign_positive()); - assert!(!(-f64::NAN).is_sign_positive()); - } - - #[test] - fn test_is_sign_negative() { - assert!(!f64::INFINITY.is_sign_negative()); - assert!(!1f64.is_sign_negative()); - assert!(!0f64.is_sign_negative()); - assert!((-0f64).is_sign_negative()); - assert!((-1f64).is_sign_negative()); - assert!(f64::NEG_INFINITY.is_sign_negative()); - assert!((1f64 / f64::NEG_INFINITY).is_sign_negative()); - assert!(!f64::NAN.is_sign_negative()); - assert!((-f64::NAN).is_sign_negative()); - } - - #[test] - fn test_mul_add() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); - assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); - assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); - assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f64.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); - } - - #[test] - fn test_recip() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(1.0f64.recip(), 1.0); - assert_eq!(2.0f64.recip(), 0.5); - assert_eq!((-0.4f64).recip(), -2.5); - assert_eq!(0.0f64.recip(), inf); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); - } - - #[test] - fn test_powi() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(1.0f64.powi(1), 1.0); - assert_approx_eq!((-3.1f64).powi(2), 9.61); - assert_approx_eq!(5.9f64.powi(-2), 0.028727); - assert_eq!(8.3f64.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); - } - - #[test] - fn test_powf() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(1.0f64.powf(1.0), 1.0); - assert_approx_eq!(3.4f64.powf(4.5), 246.408183); - assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); - assert_approx_eq!((-3.1f64).powf(2.0), 9.61); - assert_approx_eq!(5.9f64.powf(-2.0), 0.028727); - assert_eq!(8.3f64.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); - } - - #[test] - fn test_sqrt_domain() { - assert!(f64::NAN.sqrt().is_nan()); - assert!(f64::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f64).sqrt().is_nan()); - assert_eq!((-0.0f64).sqrt(), -0.0); - assert_eq!(0.0f64.sqrt(), 0.0); - assert_eq!(1.0f64.sqrt(), 1.0); - assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); - } - - #[test] - fn test_exp() { - assert_eq!(1.0, 0.0f64.exp()); - assert_approx_eq!(2.718282, 1.0f64.exp()); - assert_approx_eq!(148.413159, 5.0f64.exp()); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); - } - - #[test] - fn test_exp2() { - assert_eq!(32.0, 5.0f64.exp2()); - assert_eq!(1.0, 0.0f64.exp2()); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); - } - - #[test] - fn test_ln() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(1.0f64.exp().ln(), 1.0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f64).ln().is_nan()); - assert_eq!((-0.0f64).ln(), neg_inf); - assert_eq!(0.0f64.ln(), neg_inf); - assert_approx_eq!(4.0f64.ln(), 1.386294); - } - - #[test] - fn test_log() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(10.0f64.log(10.0), 1.0); - assert_approx_eq!(2.3f64.log(3.5), 0.664858); - assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); - assert!(1.0f64.log(1.0).is_nan()); - assert!(1.0f64.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f64).log(0.1).is_nan()); - assert_eq!((-0.0f64).log(2.0), neg_inf); - assert_eq!(0.0f64.log(7.0), neg_inf); - } - - #[test] - fn test_log2() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(10.0f64.log2(), 3.321928); - assert_approx_eq!(2.3f64.log2(), 1.201634); - assert_approx_eq!(1.0f64.exp().log2(), 1.442695); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f64).log2().is_nan()); - assert_eq!((-0.0f64).log2(), neg_inf); - assert_eq!(0.0f64.log2(), neg_inf); - } - - #[test] - fn test_log10() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(10.0f64.log10(), 1.0); - assert_approx_eq!(2.3f64.log10(), 0.361728); - assert_approx_eq!(1.0f64.exp().log10(), 0.434294); - assert_eq!(1.0f64.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f64).log10().is_nan()); - assert_eq!((-0.0f64).log10(), neg_inf); - assert_eq!(0.0f64.log10(), neg_inf); - } - - #[test] - fn test_to_degrees() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(0.0f64.to_degrees(), 0.0); - assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); - assert_eq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - } - - #[test] - fn test_to_radians() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(0.0f64.to_radians(), 0.0); - assert_approx_eq!(154.6f64.to_radians(), 2.698279); - assert_approx_eq!((-332.31f64).to_radians(), -5.799903); - assert_eq!(180.0f64.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); - } - - #[test] - fn test_asinh() { - assert_eq!(0.0f64.asinh(), 0.0f64); - assert_eq!((-0.0f64).asinh(), -0.0f64); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f64).asinh().is_sign_negative()); - // issue 63271 - assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); - assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083); - } - - #[test] - fn test_acosh() { - assert_eq!(1.0f64.acosh(), 0.0f64); - assert!(0.999f64.acosh().is_nan()); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); - assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); - } - - #[test] - fn test_atanh() { - assert_eq!(0.0f64.atanh(), 0.0f64); - assert_eq!((-0.0f64).atanh(), -0.0f64); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(1.0f64.atanh(), inf); - assert_eq!((-1.0f64).atanh(), neg_inf); - assert!(2f64.atanh().atanh().is_nan()); - assert!((-2f64).atanh().atanh().is_nan()); - assert!(inf.atanh().is_nan()); - assert!(neg_inf.atanh().is_nan()); - assert!(nan.atanh().is_nan()); - assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); - assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); - } - - #[test] - fn test_real_consts() { - use super::consts; - let pi: f64 = consts::PI; - let frac_pi_2: f64 = consts::FRAC_PI_2; - let frac_pi_3: f64 = consts::FRAC_PI_3; - let frac_pi_4: f64 = consts::FRAC_PI_4; - let frac_pi_6: f64 = consts::FRAC_PI_6; - let frac_pi_8: f64 = consts::FRAC_PI_8; - let frac_1_pi: f64 = consts::FRAC_1_PI; - let frac_2_pi: f64 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI; - let sqrt2: f64 = consts::SQRT_2; - let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2; - let e: f64 = consts::E; - let log2_e: f64 = consts::LOG2_E; - let log10_e: f64 = consts::LOG10_E; - let ln_2: f64 = consts::LN_2; - let ln_10: f64 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f64); - assert_approx_eq!(frac_pi_3, pi / 3f64); - assert_approx_eq!(frac_pi_4, pi / 4f64); - assert_approx_eq!(frac_pi_6, pi / 6f64); - assert_approx_eq!(frac_pi_8, pi / 8f64); - assert_approx_eq!(frac_1_pi, 1f64 / pi); - assert_approx_eq!(frac_2_pi, 2f64 / pi); - assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt()); - assert_approx_eq!(sqrt2, 2f64.sqrt()); - assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt()); - assert_approx_eq!(log2_e, e.log2()); - assert_approx_eq!(log10_e, e.log10()); - assert_approx_eq!(ln_2, 2f64.ln()); - assert_approx_eq!(ln_10, 10f64.ln()); - } - - #[test] - fn test_float_bits_conv() { - assert_eq!((1f64).to_bits(), 0x3ff0000000000000); - assert_eq!((12.5f64).to_bits(), 0x4029000000000000); - assert_eq!((1337f64).to_bits(), 0x4094e40000000000); - assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); - assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); - assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); - assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); - assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; - let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; - assert!(f64::from_bits(masked_nan1).is_nan()); - assert!(f64::from_bits(masked_nan2).is_nan()); - - assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2); - } - - #[test] - #[should_panic] - fn test_clamp_min_greater_than_max() { - let _ = 1.0f64.clamp(3.0, 1.0); - } - - #[test] - #[should_panic] - fn test_clamp_min_is_nan() { - let _ = 1.0f64.clamp(f64::NAN, 1.0); - } - - #[test] - #[should_panic] - fn test_clamp_max_is_nan() { - let _ = 1.0f64.clamp(3.0, f64::NAN); - } - - #[test] - fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u64 { - 1 << (f64::MANTISSA_DIGITS - 2) - } - - fn min_subnorm() -> f64 { - f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0) - } - - fn max_subnorm() -> f64 { - f64::MIN_POSITIVE - min_subnorm() - } - - fn q_nan() -> f64 { - f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f64 { - f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42) - } - - assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0)); - assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX)); - assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); - assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0)); - assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX)); - assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan())); - assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5)); - assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0)); - assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); - assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); - } -} diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs new file mode 100644 index 0000000000..5c163cfe90 --- /dev/null +++ b/library/std/src/f64/tests.rs @@ -0,0 +1,755 @@ +use crate::f64::consts; +use crate::num::FpCategory as Fp; +use crate::num::*; + +#[test] +fn test_num_f64() { + test_num(10f64, 2f64); +} + +#[test] +fn test_min_nan() { + assert_eq!(f64::NAN.min(2.0), 2.0); + assert_eq!(2.0f64.min(f64::NAN), 2.0); +} + +#[test] +fn test_max_nan() { + assert_eq!(f64::NAN.max(2.0), 2.0); + assert_eq!(2.0f64.max(f64::NAN), 2.0); +} + +#[test] +fn test_nan() { + let nan: f64 = f64::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(!nan.is_normal()); + assert!(nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert_eq!(Fp::Nan, nan.classify()); +} + +#[test] +fn test_infinity() { + let inf: f64 = f64::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); +} + +#[test] +fn test_neg_infinity() { + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); +} + +#[test] +fn test_zero() { + let zero: f64 = 0.0f64; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); +} + +#[test] +fn test_neg_zero() { + let neg_zero: f64 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); +} + +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 +#[test] +fn test_one() { + let one: f64 = 1.0f64; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); +} + +#[test] +fn test_is_nan() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f64.is_nan()); + assert!(!5.3f64.is_nan()); + assert!(!(-10.732f64).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); +} + +#[test] +fn test_is_infinite() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f64.is_infinite()); + assert!(!42.8f64.is_infinite()); + assert!(!(-109.2f64).is_infinite()); +} + +#[test] +fn test_is_finite() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f64.is_finite()); + assert!(42.8f64.is_finite()); + assert!((-109.2f64).is_finite()); +} + +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 +#[test] +fn test_is_normal() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f64.is_normal()); + assert!(1e-307f64.is_normal()); + assert!(!1e-308f64.is_normal()); +} + +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 +#[test] +fn test_classify() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1e-307f64.classify(), Fp::Normal); + assert_eq!(1e-308f64.classify(), Fp::Subnormal); +} + +#[test] +fn test_floor() { + assert_approx_eq!(1.0f64.floor(), 1.0f64); + assert_approx_eq!(1.3f64.floor(), 1.0f64); + assert_approx_eq!(1.5f64.floor(), 1.0f64); + assert_approx_eq!(1.7f64.floor(), 1.0f64); + assert_approx_eq!(0.0f64.floor(), 0.0f64); + assert_approx_eq!((-0.0f64).floor(), -0.0f64); + assert_approx_eq!((-1.0f64).floor(), -1.0f64); + assert_approx_eq!((-1.3f64).floor(), -2.0f64); + assert_approx_eq!((-1.5f64).floor(), -2.0f64); + assert_approx_eq!((-1.7f64).floor(), -2.0f64); +} + +#[test] +fn test_ceil() { + assert_approx_eq!(1.0f64.ceil(), 1.0f64); + assert_approx_eq!(1.3f64.ceil(), 2.0f64); + assert_approx_eq!(1.5f64.ceil(), 2.0f64); + assert_approx_eq!(1.7f64.ceil(), 2.0f64); + assert_approx_eq!(0.0f64.ceil(), 0.0f64); + assert_approx_eq!((-0.0f64).ceil(), -0.0f64); + assert_approx_eq!((-1.0f64).ceil(), -1.0f64); + assert_approx_eq!((-1.3f64).ceil(), -1.0f64); + assert_approx_eq!((-1.5f64).ceil(), -1.0f64); + assert_approx_eq!((-1.7f64).ceil(), -1.0f64); +} + +#[test] +fn test_round() { + assert_approx_eq!(1.0f64.round(), 1.0f64); + assert_approx_eq!(1.3f64.round(), 1.0f64); + assert_approx_eq!(1.5f64.round(), 2.0f64); + assert_approx_eq!(1.7f64.round(), 2.0f64); + assert_approx_eq!(0.0f64.round(), 0.0f64); + assert_approx_eq!((-0.0f64).round(), -0.0f64); + assert_approx_eq!((-1.0f64).round(), -1.0f64); + assert_approx_eq!((-1.3f64).round(), -1.0f64); + assert_approx_eq!((-1.5f64).round(), -2.0f64); + assert_approx_eq!((-1.7f64).round(), -2.0f64); +} + +#[test] +fn test_trunc() { + assert_approx_eq!(1.0f64.trunc(), 1.0f64); + assert_approx_eq!(1.3f64.trunc(), 1.0f64); + assert_approx_eq!(1.5f64.trunc(), 1.0f64); + assert_approx_eq!(1.7f64.trunc(), 1.0f64); + assert_approx_eq!(0.0f64.trunc(), 0.0f64); + assert_approx_eq!((-0.0f64).trunc(), -0.0f64); + assert_approx_eq!((-1.0f64).trunc(), -1.0f64); + assert_approx_eq!((-1.3f64).trunc(), -1.0f64); + assert_approx_eq!((-1.5f64).trunc(), -1.0f64); + assert_approx_eq!((-1.7f64).trunc(), -1.0f64); +} + +#[test] +fn test_fract() { + assert_approx_eq!(1.0f64.fract(), 0.0f64); + assert_approx_eq!(1.3f64.fract(), 0.3f64); + assert_approx_eq!(1.5f64.fract(), 0.5f64); + assert_approx_eq!(1.7f64.fract(), 0.7f64); + assert_approx_eq!(0.0f64.fract(), 0.0f64); + assert_approx_eq!((-0.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.3f64).fract(), -0.3f64); + assert_approx_eq!((-1.5f64).fract(), -0.5f64); + assert_approx_eq!((-1.7f64).fract(), -0.7f64); +} + +#[test] +fn test_abs() { + assert_eq!(f64::INFINITY.abs(), f64::INFINITY); + assert_eq!(1f64.abs(), 1f64); + assert_eq!(0f64.abs(), 0f64); + assert_eq!((-0f64).abs(), 0f64); + assert_eq!((-1f64).abs(), 1f64); + assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY); + assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64); + assert!(f64::NAN.abs().is_nan()); +} + +#[test] +fn test_signum() { + assert_eq!(f64::INFINITY.signum(), 1f64); + assert_eq!(1f64.signum(), 1f64); + assert_eq!(0f64.signum(), 1f64); + assert_eq!((-0f64).signum(), -1f64); + assert_eq!((-1f64).signum(), -1f64); + assert_eq!(f64::NEG_INFINITY.signum(), -1f64); + assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64); + assert!(f64::NAN.signum().is_nan()); +} + +#[test] +fn test_is_sign_positive() { + assert!(f64::INFINITY.is_sign_positive()); + assert!(1f64.is_sign_positive()); + assert!(0f64.is_sign_positive()); + assert!(!(-0f64).is_sign_positive()); + assert!(!(-1f64).is_sign_positive()); + assert!(!f64::NEG_INFINITY.is_sign_positive()); + assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive()); + assert!(f64::NAN.is_sign_positive()); + assert!(!(-f64::NAN).is_sign_positive()); +} + +#[test] +fn test_is_sign_negative() { + assert!(!f64::INFINITY.is_sign_negative()); + assert!(!1f64.is_sign_negative()); + assert!(!0f64.is_sign_negative()); + assert!((-0f64).is_sign_negative()); + assert!((-1f64).is_sign_negative()); + assert!(f64::NEG_INFINITY.is_sign_negative()); + assert!((1f64 / f64::NEG_INFINITY).is_sign_negative()); + assert!(!f64::NAN.is_sign_negative()); + assert!((-f64::NAN).is_sign_negative()); +} + +#[test] +fn test_mul_add() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); + assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); + assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); + assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f64.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); +} + +#[test] +fn test_recip() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(1.0f64.recip(), 1.0); + assert_eq!(2.0f64.recip(), 0.5); + assert_eq!((-0.4f64).recip(), -2.5); + assert_eq!(0.0f64.recip(), inf); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); +} + +#[test] +fn test_powi() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(1.0f64.powi(1), 1.0); + assert_approx_eq!((-3.1f64).powi(2), 9.61); + assert_approx_eq!(5.9f64.powi(-2), 0.028727); + assert_eq!(8.3f64.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +fn test_powf() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(1.0f64.powf(1.0), 1.0); + assert_approx_eq!(3.4f64.powf(4.5), 246.408183); + assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); + assert_approx_eq!((-3.1f64).powf(2.0), 9.61); + assert_approx_eq!(5.9f64.powf(-2.0), 0.028727); + assert_eq!(8.3f64.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +fn test_sqrt_domain() { + assert!(f64::NAN.sqrt().is_nan()); + assert!(f64::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f64).sqrt().is_nan()); + assert_eq!((-0.0f64).sqrt(), -0.0); + assert_eq!(0.0f64.sqrt(), 0.0); + assert_eq!(1.0f64.sqrt(), 1.0); + assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); +} + +#[test] +fn test_exp() { + assert_eq!(1.0, 0.0f64.exp()); + assert_approx_eq!(2.718282, 1.0f64.exp()); + assert_approx_eq!(148.413159, 5.0f64.exp()); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +fn test_exp2() { + assert_eq!(32.0, 5.0f64.exp2()); + assert_eq!(1.0, 0.0f64.exp2()); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +fn test_ln() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(1.0f64.exp().ln(), 1.0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f64).ln().is_nan()); + assert_eq!((-0.0f64).ln(), neg_inf); + assert_eq!(0.0f64.ln(), neg_inf); + assert_approx_eq!(4.0f64.ln(), 1.386294); +} + +#[test] +fn test_log() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(10.0f64.log(10.0), 1.0); + assert_approx_eq!(2.3f64.log(3.5), 0.664858); + assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); + assert!(1.0f64.log(1.0).is_nan()); + assert!(1.0f64.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f64).log(0.1).is_nan()); + assert_eq!((-0.0f64).log(2.0), neg_inf); + assert_eq!(0.0f64.log(7.0), neg_inf); +} + +#[test] +fn test_log2() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(10.0f64.log2(), 3.321928); + assert_approx_eq!(2.3f64.log2(), 1.201634); + assert_approx_eq!(1.0f64.exp().log2(), 1.442695); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f64).log2().is_nan()); + assert_eq!((-0.0f64).log2(), neg_inf); + assert_eq!(0.0f64.log2(), neg_inf); +} + +#[test] +fn test_log10() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(10.0f64.log10(), 1.0); + assert_approx_eq!(2.3f64.log10(), 0.361728); + assert_approx_eq!(1.0f64.exp().log10(), 0.434294); + assert_eq!(1.0f64.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f64).log10().is_nan()); + assert_eq!((-0.0f64).log10(), neg_inf); + assert_eq!(0.0f64.log10(), neg_inf); +} + +#[test] +fn test_to_degrees() { + let pi: f64 = consts::PI; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(0.0f64.to_degrees(), 0.0); + assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); + assert_eq!(pi.to_degrees(), 180.0); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); +} + +#[test] +fn test_to_radians() { + let pi: f64 = consts::PI; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(0.0f64.to_radians(), 0.0); + assert_approx_eq!(154.6f64.to_radians(), 2.698279); + assert_approx_eq!((-332.31f64).to_radians(), -5.799903); + assert_eq!(180.0f64.to_radians(), pi); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); +} + +#[test] +fn test_asinh() { + assert_eq!(0.0f64.asinh(), 0.0f64); + assert_eq!((-0.0f64).asinh(), -0.0f64); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f64).asinh().is_sign_negative()); + // issue 63271 + assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); + assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083); +} + +#[test] +fn test_acosh() { + assert_eq!(1.0f64.acosh(), 0.0f64); + assert!(0.999f64.acosh().is_nan()); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); + assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); +} + +#[test] +fn test_atanh() { + assert_eq!(0.0f64.atanh(), 0.0f64); + assert_eq!((-0.0f64).atanh(), -0.0f64); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(1.0f64.atanh(), inf); + assert_eq!((-1.0f64).atanh(), neg_inf); + assert!(2f64.atanh().atanh().is_nan()); + assert!((-2f64).atanh().atanh().is_nan()); + assert!(inf.atanh().is_nan()); + assert!(neg_inf.atanh().is_nan()); + assert!(nan.atanh().is_nan()); + assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); + assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); +} + +#[test] +fn test_real_consts() { + use super::consts; + let pi: f64 = consts::PI; + let frac_pi_2: f64 = consts::FRAC_PI_2; + let frac_pi_3: f64 = consts::FRAC_PI_3; + let frac_pi_4: f64 = consts::FRAC_PI_4; + let frac_pi_6: f64 = consts::FRAC_PI_6; + let frac_pi_8: f64 = consts::FRAC_PI_8; + let frac_1_pi: f64 = consts::FRAC_1_PI; + let frac_2_pi: f64 = consts::FRAC_2_PI; + let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI; + let sqrt2: f64 = consts::SQRT_2; + let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2; + let e: f64 = consts::E; + let log2_e: f64 = consts::LOG2_E; + let log10_e: f64 = consts::LOG10_E; + let ln_2: f64 = consts::LN_2; + let ln_10: f64 = consts::LN_10; + + assert_approx_eq!(frac_pi_2, pi / 2f64); + assert_approx_eq!(frac_pi_3, pi / 3f64); + assert_approx_eq!(frac_pi_4, pi / 4f64); + assert_approx_eq!(frac_pi_6, pi / 6f64); + assert_approx_eq!(frac_pi_8, pi / 8f64); + assert_approx_eq!(frac_1_pi, 1f64 / pi); + assert_approx_eq!(frac_2_pi, 2f64 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f64.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f64.ln()); + assert_approx_eq!(ln_10, 10f64.ln()); +} + +#[test] +fn test_float_bits_conv() { + assert_eq!((1f64).to_bits(), 0x3ff0000000000000); + assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + assert_eq!((1337f64).to_bits(), 0x4094e40000000000); + assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); + assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); + assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); + assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); + assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signaling-ness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; + let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; + assert!(f64::from_bits(masked_nan1).is_nan()); + assert!(f64::from_bits(masked_nan2).is_nan()); + + assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1); + assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2); +} + +#[test] +#[should_panic] +fn test_clamp_min_greater_than_max() { + let _ = 1.0f64.clamp(3.0, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_min_is_nan() { + let _ = 1.0f64.clamp(f64::NAN, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_max_is_nan() { + let _ = 1.0f64.clamp(3.0, f64::NAN); +} + +#[test] +fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u64 { + 1 << (f64::MANTISSA_DIGITS - 2) + } + + fn min_subnorm() -> f64 { + f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0) + } + + fn max_subnorm() -> f64 { + f64::MIN_POSITIVE - min_subnorm() + } + + fn q_nan() -> f64 { + f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f64 { + f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0)); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0)); + assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5)); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0)); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); +} diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 717967fb76..13021738af 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -1,4 +1,8 @@ #![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(test)] +mod tests; + use crate::ascii; use crate::borrow::{Borrow, Cow}; use crate::cmp::Ordering; @@ -877,13 +881,13 @@ impl From> for CString { unsafe { // Transmute `Vec` to `Vec`. let v: Vec = { - // Safety: + // SAFETY: // - transmuting between `NonZeroU8` and `u8` is sound; // - `alloc::Layout == alloc::Layout`. let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v); Vec::from_raw_parts(ptr.cast::(), len, cap) }; - // Safety: `v` cannot contain null bytes, given the type-level + // SAFETY: `v` cannot contain null bytes, given the type-level // invariant of `NonZeroU8`. CString::from_vec_unchecked(v) } @@ -1522,202 +1526,3 @@ impl AsRef for CString { self } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::borrow::Cow::{Borrowed, Owned}; - use crate::collections::hash_map::DefaultHasher; - use crate::hash::{Hash, Hasher}; - use crate::os::raw::c_char; - use crate::rc::Rc; - use crate::sync::Arc; - - #[test] - fn c_to_rust() { - let data = b"123\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); - assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); - } - } - - #[test] - fn simple() { - let s = CString::new("1234").unwrap(); - assert_eq!(s.as_bytes(), b"1234"); - assert_eq!(s.as_bytes_with_nul(), b"1234\0"); - } - - #[test] - fn build_with_zero1() { - assert!(CString::new(&b"\0"[..]).is_err()); - } - #[test] - fn build_with_zero2() { - assert!(CString::new(vec![0]).is_err()); - } - - #[test] - fn build_with_zero3() { - unsafe { - let s = CString::from_vec_unchecked(vec![0]); - assert_eq!(s.as_bytes(), b"\0"); - } - } - - #[test] - fn formatted() { - let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); - assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); - } - - #[test] - fn borrowed() { - unsafe { - let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); - assert_eq!(s.to_bytes(), b"12"); - assert_eq!(s.to_bytes_with_nul(), b"12\0"); - } - } - - #[test] - fn to_str() { - let data = b"123\xE2\x80\xA6\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); - assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); - } - let data = b"123\xE2\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert!(CStr::from_ptr(ptr).to_str().is_err()); - assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}"))); - } - } - - #[test] - fn to_owned() { - let data = b"123\0"; - let ptr = data.as_ptr() as *const c_char; - - let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; - assert_eq!(owned.as_bytes_with_nul(), data); - } - - #[test] - fn equal_hash() { - let data = b"123\xE2\xFA\xA6\0"; - let ptr = data.as_ptr() as *const c_char; - let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; - - let mut s = DefaultHasher::new(); - cstr.hash(&mut s); - let cstr_hash = s.finish(); - let mut s = DefaultHasher::new(); - CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); - let cstring_hash = s.finish(); - - assert_eq!(cstr_hash, cstring_hash); - } - - #[test] - fn from_bytes_with_nul() { - let data = b"123\0"; - let cstr = CStr::from_bytes_with_nul(data); - assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); - let cstr = CStr::from_bytes_with_nul(data); - assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); - - unsafe { - let cstr = CStr::from_bytes_with_nul(data); - let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); - assert_eq!(cstr, Ok(cstr_unchecked)); - } - } - - #[test] - fn from_bytes_with_nul_unterminated() { - let data = b"123"; - let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_err()); - } - - #[test] - fn from_bytes_with_nul_interior() { - let data = b"1\023\0"; - let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_err()); - } - - #[test] - fn into_boxed() { - let orig: &[u8] = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let boxed: Box = Box::from(cstr); - let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); - assert_eq!(cstr, &*boxed); - assert_eq!(&*boxed, &*cstring); - assert_eq!(&*cstring, cstr); - } - - #[test] - fn boxed_default() { - let boxed = >::default(); - assert_eq!(boxed.to_bytes_with_nul(), &[0]); - } - - #[test] - fn test_c_str_clone_into() { - let mut c_string = CString::new("lorem").unwrap(); - let c_ptr = c_string.as_ptr(); - let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap(); - c_str.clone_into(&mut c_string); - assert_eq!(c_str, c_string.as_c_str()); - // The exact same size shouldn't have needed to move its allocation - assert_eq!(c_ptr, c_string.as_ptr()); - } - - #[test] - fn into_rc() { - let orig: &[u8] = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let rc: Rc = Rc::from(cstr); - let arc: Arc = Arc::from(cstr); - - assert_eq!(&*rc, cstr); - assert_eq!(&*arc, cstr); - - let rc2: Rc = Rc::from(cstr.to_owned()); - let arc2: Arc = Arc::from(cstr.to_owned()); - - assert_eq!(&*rc2, cstr); - assert_eq!(&*arc2, cstr); - } - - #[test] - fn cstr_const_constructor() { - const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") }; - - assert_eq!(CSTR.to_str().unwrap(), "Hello, world!"); - } - - #[test] - fn cstr_index_from() { - let original = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(original).unwrap(); - let result = CStr::from_bytes_with_nul(&original[7..]).unwrap(); - - assert_eq!(&cstr[7..], result); - } - - #[test] - #[should_panic] - fn cstr_index_from_empty() { - let original = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(original).unwrap(); - let _ = &cstr[original.len()..]; - } -} diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs new file mode 100644 index 0000000000..4dff3df63a --- /dev/null +++ b/library/std/src/ffi/c_str/tests.rs @@ -0,0 +1,195 @@ +use super::*; +use crate::borrow::Cow::{Borrowed, Owned}; +use crate::collections::hash_map::DefaultHasher; +use crate::hash::{Hash, Hasher}; +use crate::os::raw::c_char; +use crate::rc::Rc; +use crate::sync::Arc; + +#[test] +fn c_to_rust() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); + assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); + } +} + +#[test] +fn simple() { + let s = CString::new("1234").unwrap(); + assert_eq!(s.as_bytes(), b"1234"); + assert_eq!(s.as_bytes_with_nul(), b"1234\0"); +} + +#[test] +fn build_with_zero1() { + assert!(CString::new(&b"\0"[..]).is_err()); +} +#[test] +fn build_with_zero2() { + assert!(CString::new(vec![0]).is_err()); +} + +#[test] +fn build_with_zero3() { + unsafe { + let s = CString::from_vec_unchecked(vec![0]); + assert_eq!(s.as_bytes(), b"\0"); + } +} + +#[test] +fn formatted() { + let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); + assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); +} + +#[test] +fn borrowed() { + unsafe { + let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); + assert_eq!(s.to_bytes(), b"12"); + assert_eq!(s.to_bytes_with_nul(), b"12\0"); + } +} + +#[test] +fn to_str() { + let data = b"123\xE2\x80\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); + assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); + } + let data = b"123\xE2\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert!(CStr::from_ptr(ptr).to_str().is_err()); + assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}"))); + } +} + +#[test] +fn to_owned() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + + let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; + assert_eq!(owned.as_bytes_with_nul(), data); +} + +#[test] +fn equal_hash() { + let data = b"123\xE2\xFA\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; + + let mut s = DefaultHasher::new(); + cstr.hash(&mut s); + let cstr_hash = s.finish(); + let mut s = DefaultHasher::new(); + CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); + let cstring_hash = s.finish(); + + assert_eq!(cstr_hash, cstring_hash); +} + +#[test] +fn from_bytes_with_nul() { + let data = b"123\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); + + unsafe { + let cstr = CStr::from_bytes_with_nul(data); + let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); + assert_eq!(cstr, Ok(cstr_unchecked)); + } +} + +#[test] +fn from_bytes_with_nul_unterminated() { + let data = b"123"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); +} + +#[test] +fn from_bytes_with_nul_interior() { + let data = b"1\023\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); +} + +#[test] +fn into_boxed() { + let orig: &[u8] = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(orig).unwrap(); + let boxed: Box = Box::from(cstr); + let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); + assert_eq!(cstr, &*boxed); + assert_eq!(&*boxed, &*cstring); + assert_eq!(&*cstring, cstr); +} + +#[test] +fn boxed_default() { + let boxed = >::default(); + assert_eq!(boxed.to_bytes_with_nul(), &[0]); +} + +#[test] +fn test_c_str_clone_into() { + let mut c_string = CString::new("lorem").unwrap(); + let c_ptr = c_string.as_ptr(); + let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap(); + c_str.clone_into(&mut c_string); + assert_eq!(c_str, c_string.as_c_str()); + // The exact same size shouldn't have needed to move its allocation + assert_eq!(c_ptr, c_string.as_ptr()); +} + +#[test] +fn into_rc() { + let orig: &[u8] = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(orig).unwrap(); + let rc: Rc = Rc::from(cstr); + let arc: Arc = Arc::from(cstr); + + assert_eq!(&*rc, cstr); + assert_eq!(&*arc, cstr); + + let rc2: Rc = Rc::from(cstr.to_owned()); + let arc2: Arc = Arc::from(cstr.to_owned()); + + assert_eq!(&*rc2, cstr); + assert_eq!(&*arc2, cstr); +} + +#[test] +fn cstr_const_constructor() { + const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") }; + + assert_eq!(CSTR.to_str().unwrap(), "Hello, world!"); +} + +#[test] +fn cstr_index_from() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let result = CStr::from_bytes_with_nul(&original[7..]).unwrap(); + + assert_eq!(&cstr[7..], result); +} + +#[test] +#[should_panic] +fn cstr_index_from_empty() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let _ = &cstr[original.len()..]; +} diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 262d39d98e..2663f682a1 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::borrow::{Borrow, Cow}; use crate::cmp; use crate::fmt; @@ -91,7 +94,7 @@ pub struct OsString { // `OsStr::from_inner` current implementation relies // on `OsStr` being layout-compatible with `Slice`. // When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`. -// Anyway, `OsStr` representation and layout are considered implementation detail, are +// Anyway, `OsStr` representation and layout are considered implementation details, are // not documented and must not be relied upon. pub struct OsStr { inner: Slice, @@ -507,14 +510,14 @@ impl OsStr { #[inline] fn from_inner(inner: &Slice) -> &OsStr { - // Safety: OsStr is just a wrapper of Slice, + // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &Slice to &OsStr is safe. unsafe { &*(inner as *const Slice as *const OsStr) } } #[inline] fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { - // Safety: OsStr is just a wrapper of Slice, + // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &mut Slice to &mut OsStr is safe. // Any method that mutates OsStr must be careful not to // break platform-specific encoding, in particular Wtf8 on Windows. @@ -1145,172 +1148,3 @@ impl FromStr for OsString { Ok(OsString::from(s)) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::sys_common::{AsInner, IntoInner}; - - use crate::rc::Rc; - use crate::sync::Arc; - - #[test] - fn test_os_string_with_capacity() { - let os_string = OsString::with_capacity(0); - assert_eq!(0, os_string.inner.into_inner().capacity()); - - let os_string = OsString::with_capacity(10); - assert_eq!(10, os_string.inner.into_inner().capacity()); - - let mut os_string = OsString::with_capacity(0); - os_string.push("abc"); - assert!(os_string.inner.into_inner().capacity() >= 3); - } - - #[test] - fn test_os_string_clear() { - let mut os_string = OsString::from("abc"); - assert_eq!(3, os_string.inner.as_inner().len()); - - os_string.clear(); - assert_eq!(&os_string, ""); - assert_eq!(0, os_string.inner.as_inner().len()); - } - - #[test] - fn test_os_string_capacity() { - let os_string = OsString::with_capacity(0); - assert_eq!(0, os_string.capacity()); - - let os_string = OsString::with_capacity(10); - assert_eq!(10, os_string.capacity()); - - let mut os_string = OsString::with_capacity(0); - os_string.push("abc"); - assert!(os_string.capacity() >= 3); - } - - #[test] - fn test_os_string_reserve() { - let mut os_string = OsString::new(); - assert_eq!(os_string.capacity(), 0); - - os_string.reserve(2); - assert!(os_string.capacity() >= 2); - - for _ in 0..16 { - os_string.push("a"); - } - - assert!(os_string.capacity() >= 16); - os_string.reserve(16); - assert!(os_string.capacity() >= 32); - - os_string.push("a"); - - os_string.reserve(16); - assert!(os_string.capacity() >= 33) - } - - #[test] - fn test_os_string_reserve_exact() { - let mut os_string = OsString::new(); - assert_eq!(os_string.capacity(), 0); - - os_string.reserve_exact(2); - assert!(os_string.capacity() >= 2); - - for _ in 0..16 { - os_string.push("a"); - } - - assert!(os_string.capacity() >= 16); - os_string.reserve_exact(16); - assert!(os_string.capacity() >= 32); - - os_string.push("a"); - - os_string.reserve_exact(16); - assert!(os_string.capacity() >= 33) - } - - #[test] - fn test_os_string_default() { - let os_string: OsString = Default::default(); - assert_eq!("", &os_string); - } - - #[test] - fn test_os_str_is_empty() { - let mut os_string = OsString::new(); - assert!(os_string.is_empty()); - - os_string.push("abc"); - assert!(!os_string.is_empty()); - - os_string.clear(); - assert!(os_string.is_empty()); - } - - #[test] - fn test_os_str_len() { - let mut os_string = OsString::new(); - assert_eq!(0, os_string.len()); - - os_string.push("abc"); - assert_eq!(3, os_string.len()); - - os_string.clear(); - assert_eq!(0, os_string.len()); - } - - #[test] - fn test_os_str_default() { - let os_str: &OsStr = Default::default(); - assert_eq!("", os_str); - } - - #[test] - fn into_boxed() { - let orig = "Hello, world!"; - let os_str = OsStr::new(orig); - let boxed: Box = Box::from(os_str); - let os_string = os_str.to_owned().into_boxed_os_str().into_os_string(); - assert_eq!(os_str, &*boxed); - assert_eq!(&*boxed, &*os_string); - assert_eq!(&*os_string, os_str); - } - - #[test] - fn boxed_default() { - let boxed = >::default(); - assert!(boxed.is_empty()); - } - - #[test] - fn test_os_str_clone_into() { - let mut os_string = OsString::with_capacity(123); - os_string.push("hello"); - let os_str = OsStr::new("bonjour"); - os_str.clone_into(&mut os_string); - assert_eq!(os_str, os_string); - assert!(os_string.capacity() >= 123); - } - - #[test] - fn into_rc() { - let orig = "Hello, world!"; - let os_str = OsStr::new(orig); - let rc: Rc = Rc::from(os_str); - let arc: Arc = Arc::from(os_str); - - assert_eq!(&*rc, os_str); - assert_eq!(&*arc, os_str); - - let rc2: Rc = Rc::from(os_str.to_owned()); - let arc2: Arc = Arc::from(os_str.to_owned()); - - assert_eq!(&*rc2, os_str); - assert_eq!(&*arc2, os_str); - } -} diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs new file mode 100644 index 0000000000..283f2b577e --- /dev/null +++ b/library/std/src/ffi/os_str/tests.rs @@ -0,0 +1,165 @@ +use super::*; +use crate::sys_common::{AsInner, IntoInner}; + +use crate::rc::Rc; +use crate::sync::Arc; + +#[test] +fn test_os_string_with_capacity() { + let os_string = OsString::with_capacity(0); + assert_eq!(0, os_string.inner.into_inner().capacity()); + + let os_string = OsString::with_capacity(10); + assert_eq!(10, os_string.inner.into_inner().capacity()); + + let mut os_string = OsString::with_capacity(0); + os_string.push("abc"); + assert!(os_string.inner.into_inner().capacity() >= 3); +} + +#[test] +fn test_os_string_clear() { + let mut os_string = OsString::from("abc"); + assert_eq!(3, os_string.inner.as_inner().len()); + + os_string.clear(); + assert_eq!(&os_string, ""); + assert_eq!(0, os_string.inner.as_inner().len()); +} + +#[test] +fn test_os_string_capacity() { + let os_string = OsString::with_capacity(0); + assert_eq!(0, os_string.capacity()); + + let os_string = OsString::with_capacity(10); + assert_eq!(10, os_string.capacity()); + + let mut os_string = OsString::with_capacity(0); + os_string.push("abc"); + assert!(os_string.capacity() >= 3); +} + +#[test] +fn test_os_string_reserve() { + let mut os_string = OsString::new(); + assert_eq!(os_string.capacity(), 0); + + os_string.reserve(2); + assert!(os_string.capacity() >= 2); + + for _ in 0..16 { + os_string.push("a"); + } + + assert!(os_string.capacity() >= 16); + os_string.reserve(16); + assert!(os_string.capacity() >= 32); + + os_string.push("a"); + + os_string.reserve(16); + assert!(os_string.capacity() >= 33) +} + +#[test] +fn test_os_string_reserve_exact() { + let mut os_string = OsString::new(); + assert_eq!(os_string.capacity(), 0); + + os_string.reserve_exact(2); + assert!(os_string.capacity() >= 2); + + for _ in 0..16 { + os_string.push("a"); + } + + assert!(os_string.capacity() >= 16); + os_string.reserve_exact(16); + assert!(os_string.capacity() >= 32); + + os_string.push("a"); + + os_string.reserve_exact(16); + assert!(os_string.capacity() >= 33) +} + +#[test] +fn test_os_string_default() { + let os_string: OsString = Default::default(); + assert_eq!("", &os_string); +} + +#[test] +fn test_os_str_is_empty() { + let mut os_string = OsString::new(); + assert!(os_string.is_empty()); + + os_string.push("abc"); + assert!(!os_string.is_empty()); + + os_string.clear(); + assert!(os_string.is_empty()); +} + +#[test] +fn test_os_str_len() { + let mut os_string = OsString::new(); + assert_eq!(0, os_string.len()); + + os_string.push("abc"); + assert_eq!(3, os_string.len()); + + os_string.clear(); + assert_eq!(0, os_string.len()); +} + +#[test] +fn test_os_str_default() { + let os_str: &OsStr = Default::default(); + assert_eq!("", os_str); +} + +#[test] +fn into_boxed() { + let orig = "Hello, world!"; + let os_str = OsStr::new(orig); + let boxed: Box = Box::from(os_str); + let os_string = os_str.to_owned().into_boxed_os_str().into_os_string(); + assert_eq!(os_str, &*boxed); + assert_eq!(&*boxed, &*os_string); + assert_eq!(&*os_string, os_str); +} + +#[test] +fn boxed_default() { + let boxed = >::default(); + assert!(boxed.is_empty()); +} + +#[test] +fn test_os_str_clone_into() { + let mut os_string = OsString::with_capacity(123); + os_string.push("hello"); + let os_str = OsStr::new("bonjour"); + os_str.clone_into(&mut os_string); + assert_eq!(os_str, os_string); + assert!(os_string.capacity() >= 123); +} + +#[test] +fn into_rc() { + let orig = "Hello, world!"; + let os_str = OsStr::new(orig); + let rc: Rc = Rc::from(os_str); + let arc: Arc = Arc::from(os_str); + + assert_eq!(&*rc, os_str); + assert_eq!(&*arc, os_str); + + let rc2: Rc = Rc::from(os_str.to_owned()); + let arc2: Arc = Arc::from(os_str.to_owned()); + + assert_eq!(&*rc2, os_str); + assert_eq!(&*arc2, os_str); +} diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index b1630f8f54..161bfe3795 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! Filesystem manipulation operations. //! //! This module contains basic methods to manipulate the contents of the local @@ -10,6 +8,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] +mod tests; + use crate::ffi::OsString; use crate::fmt; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; @@ -552,7 +553,7 @@ impl File { /// the `SetFileInformationByHandle` function on Windows. Note that, this /// [may change in the future][changes]. /// - /// [changes]: ../io/index.html#platform-specific-behavior + /// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1502,7 +1503,7 @@ impl AsInner for DirEntry { /// and the `DeleteFile` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1540,7 +1541,7 @@ pub fn remove_file>(path: P) -> io::Result<()> { /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1574,7 +1575,7 @@ pub fn metadata>(path: P) -> io::Result { /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1617,7 +1618,7 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1668,7 +1669,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// `fcopyfile`. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1706,7 +1707,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// and the `CreateHardLink` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1771,7 +1772,7 @@ pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1811,7 +1812,7 @@ pub fn read_link>(path: P) -> io::Result { /// with other applications (if passed to the application on the command-line, /// or written to a file another application may read). /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// [path]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file /// /// # Errors @@ -1845,7 +1846,7 @@ pub fn canonicalize>(path: P) -> io::Result { /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// **NOTE**: If a parent of the given path doesn't exist, this function will /// return an error. To create a directory and all its missing parents at the @@ -1886,7 +1887,7 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1929,7 +1930,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// and the `RemoveDirectory` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1969,7 +1970,7 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -2005,7 +2006,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// currently corresponds to `readdir` on Unix and `FindNextFile` on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// The order in which this iterator returns entries is platform and filesystem /// dependent. @@ -2074,7 +2075,7 @@ pub fn read_dir>(path: P) -> io::Result { /// and the `SetFileAttributes` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -2194,1349 +2195,3 @@ impl AsInnerMut for DirBuilder { &mut self.inner } } - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] -mod tests { - use crate::io::prelude::*; - - use crate::fs::{self, File, OpenOptions}; - use crate::io::{ErrorKind, SeekFrom}; - use crate::path::Path; - use crate::str; - use crate::sys_common::io::test::{tmpdir, TempDir}; - use crate::thread; - - use rand::{rngs::StdRng, RngCore, SeedableRng}; - - #[cfg(unix)] - use crate::os::unix::fs::symlink as symlink_dir; - #[cfg(unix)] - use crate::os::unix::fs::symlink as symlink_file; - #[cfg(unix)] - use crate::os::unix::fs::symlink as symlink_junction; - #[cfg(windows)] - use crate::os::windows::fs::{symlink_dir, symlink_file}; - #[cfg(windows)] - use crate::sys::fs::symlink_junction; - - macro_rules! check { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("{} failed with: {}", stringify!($e), e), - } - }; - } - - #[cfg(windows)] - macro_rules! error { - ($e:expr, $s:expr) => { - match $e { - Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), - Err(ref err) => assert!( - err.raw_os_error() == Some($s), - format!("`{}` did not have a code of `{}`", err, $s) - ), - } - }; - } - - #[cfg(unix)] - macro_rules! error { - ($e:expr, $s:expr) => { - error_contains!($e, $s) - }; - } - - macro_rules! error_contains { - ($e:expr, $s:expr) => { - match $e { - Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), - Err(ref err) => assert!( - err.to_string().contains($s), - format!("`{}` did not contain `{}`", err, $s) - ), - } - }; - } - - // Several test fail on windows if the user does not have permission to - // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of - // disabling these test on Windows, use this function to test whether we - // have permission, and return otherwise. This way, we still don't run these - // tests most of the time, but at least we do if the user has the right - // permissions. - pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { - if cfg!(unix) { - return true; - } - let link = tmpdir.join("some_hopefully_unique_link_name"); - - match symlink_file(r"nonexisting_target", link) { - Ok(_) => true, - // ERROR_PRIVILEGE_NOT_HELD = 1314 - Err(ref err) if err.raw_os_error() == Some(1314) => false, - Err(_) => true, - } - } - - #[test] - fn file_test_io_smoke_test() { - let message = "it's alright. have a good time"; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test.txt"); - { - let mut write_stream = check!(File::create(filename)); - check!(write_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - let mut read_buf = [0; 1028]; - let read_str = match check!(read_stream.read(&mut read_buf)) { - 0 => panic!("shouldn't happen"), - n => str::from_utf8(&read_buf[..n]).unwrap().to_string(), - }; - assert_eq!(read_str, message); - } - check!(fs::remove_file(filename)); - } - - #[test] - fn invalid_path_raises() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_that_does_not_exist.txt"); - let result = File::open(filename); - - #[cfg(all(unix, not(target_os = "vxworks")))] - error!(result, "No such file or directory"); - #[cfg(target_os = "vxworks")] - error!(result, "no such file or directory"); - #[cfg(windows)] - error!(result, 2); // ERROR_FILE_NOT_FOUND - } - - #[test] - fn file_test_iounlinking_invalid_path_should_raise_condition() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); - - let result = fs::remove_file(filename); - - #[cfg(all(unix, not(target_os = "vxworks")))] - error!(result, "No such file or directory"); - #[cfg(target_os = "vxworks")] - error!(result, "no such file or directory"); - #[cfg(windows)] - error!(result, 2); // ERROR_FILE_NOT_FOUND - } - - #[test] - fn file_test_io_non_positional_read() { - let message: &str = "ten-four"; - let mut read_mem = [0; 8]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - { - let read_buf = &mut read_mem[0..4]; - check!(read_stream.read(read_buf)); - } - { - let read_buf = &mut read_mem[4..8]; - check!(read_stream.read(read_buf)); - } - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, message); - } - - #[test] - fn file_test_io_seek_and_tell_smoke_test() { - let message = "ten-four"; - let mut read_mem = [0; 4]; - let set_cursor = 4 as u64; - let tell_pos_pre_read; - let tell_pos_post_read; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - check!(read_stream.seek(SeekFrom::Start(set_cursor))); - tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0))); - check!(read_stream.read(&mut read_mem)); - tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0))); - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, &message[4..8]); - assert_eq!(tell_pos_pre_read, set_cursor); - assert_eq!(tell_pos_post_read, message.len() as u64); - } - - #[test] - fn file_test_io_seek_and_write() { - let initial_msg = "food-is-yummy"; - let overwrite_msg = "-the-bar!!"; - let final_msg = "foo-the-bar!!"; - let seek_idx = 3; - let mut read_mem = [0; 13]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(initial_msg.as_bytes())); - check!(rw_stream.seek(SeekFrom::Start(seek_idx))); - check!(rw_stream.write(overwrite_msg.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - check!(read_stream.read(&mut read_mem)); - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert!(read_str == final_msg); - } - - #[test] - fn file_test_io_seek_shakedown() { - // 01234567890123 - let initial_msg = "qwer-asdf-zxcv"; - let chunk_one: &str = "qwer"; - let chunk_two: &str = "asdf"; - let chunk_three: &str = "zxcv"; - let mut read_mem = [0; 4]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(initial_msg.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - - check!(read_stream.seek(SeekFrom::End(-4))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three); - - check!(read_stream.seek(SeekFrom::Current(-9))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two); - - check!(read_stream.seek(SeekFrom::Start(0))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one); - } - check!(fs::remove_file(filename)); - } - - #[test] - fn file_test_io_eof() { - let tmpdir = tmpdir(); - let filename = tmpdir.join("file_rt_io_file_test_eof.txt"); - let mut buf = [0; 256]; - { - let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); - let mut rw = check!(oo.open(&filename)); - assert_eq!(check!(rw.read(&mut buf)), 0); - assert_eq!(check!(rw.read(&mut buf)), 0); - } - check!(fs::remove_file(&filename)); - } - - #[test] - #[cfg(unix)] - fn file_test_io_read_write_at() { - use crate::os::unix::fs::FileExt; - - let tmpdir = tmpdir(); - let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt"); - let mut buf = [0; 256]; - let write1 = "asdf"; - let write2 = "qwer-"; - let write3 = "-zxcv"; - let content = "qwer-asdf-zxcv"; - { - let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); - let mut rw = check!(oo.open(&filename)); - assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); - assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0")); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); - assert_eq!(check!(rw.read(&mut buf)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); - assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - } - { - let mut read = check!(File::open(&filename)); - assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); - assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(read.read(&mut buf)), write3.len()); - assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.read_at(&mut buf, 14)), 0); - assert_eq!(check!(read.read_at(&mut buf, 15)), 0); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - } - check!(fs::remove_file(&filename)); - } - - #[test] - #[cfg(unix)] - fn set_get_unix_permissions() { - use crate::os::unix::fs::PermissionsExt; - - let tmpdir = tmpdir(); - let filename = &tmpdir.join("set_get_unix_permissions"); - check!(fs::create_dir(filename)); - let mask = 0o7777; - - check!(fs::set_permissions(filename, fs::Permissions::from_mode(0))); - let metadata0 = check!(fs::metadata(filename)); - assert_eq!(mask & metadata0.permissions().mode(), 0); - - check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777))); - let metadata1 = check!(fs::metadata(filename)); - #[cfg(all(unix, not(target_os = "vxworks")))] - assert_eq!(mask & metadata1.permissions().mode(), 0o1777); - #[cfg(target_os = "vxworks")] - assert_eq!(mask & metadata1.permissions().mode(), 0o0777); - } - - #[test] - #[cfg(windows)] - fn file_test_io_seek_read_write() { - use crate::os::windows::fs::FileExt; - - let tmpdir = tmpdir(); - let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt"); - let mut buf = [0; 256]; - let write1 = "asdf"; - let write2 = "qwer-"; - let write3 = "-zxcv"; - let content = "qwer-asdf-zxcv"; - { - let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); - let mut rw = check!(oo.open(&filename)); - assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0); - assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); - assert_eq!(check!(rw.read(&mut buf)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len()); - assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); - assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14); - } - { - let mut read = check!(File::open(&filename)); - assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); - assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); - assert_eq!(check!(read.read(&mut buf)), write3.len()); - assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek_read(&mut buf, 14)), 0); - assert_eq!(check!(read.seek_read(&mut buf, 15)), 0); - } - check!(fs::remove_file(&filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_file() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); - { - let mut opts = OpenOptions::new(); - let mut fs = check!(opts.read(true).write(true).create(true).open(filename)); - let msg = "hw"; - fs.write(msg.as_bytes()).unwrap(); - - let fstat_res = check!(fs.metadata()); - assert!(fstat_res.is_file()); - } - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_file()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_file()); - check!(fs::remove_file(filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_dir() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_dir"); - check!(fs::create_dir(filename)); - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_dir()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_dir()); - check!(fs::remove_dir(filename)); - } - - #[test] - fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("fileinfo_false_on_dir"); - check!(fs::create_dir(dir)); - assert!(!dir.is_file()); - check!(fs::remove_dir(dir)); - } - - #[test] - fn file_test_fileinfo_check_exists_before_and_after_file_creation() { - let tmpdir = tmpdir(); - let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); - check!(check!(File::create(file)).write(b"foo")); - assert!(file.exists()); - check!(fs::remove_file(file)); - assert!(!file.exists()); - } - - #[test] - fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("before_and_after_dir"); - assert!(!dir.exists()); - check!(fs::create_dir(dir)); - assert!(dir.exists()); - assert!(dir.is_dir()); - check!(fs::remove_dir(dir)); - assert!(!dir.exists()); - } - - #[test] - fn file_test_directoryinfo_readdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("di_readdir"); - check!(fs::create_dir(dir)); - let prefix = "foo"; - for n in 0..3 { - let f = dir.join(&format!("{}.txt", n)); - let mut w = check!(File::create(&f)); - let msg_str = format!("{}{}", prefix, n.to_string()); - let msg = msg_str.as_bytes(); - check!(w.write(msg)); - } - let files = check!(fs::read_dir(dir)); - let mut mem = [0; 4]; - for f in files { - let f = f.unwrap().path(); - { - let n = f.file_stem().unwrap(); - check!(check!(File::open(&f)).read(&mut mem)); - let read_str = str::from_utf8(&mem).unwrap(); - let expected = format!("{}{}", prefix, n.to_str().unwrap()); - assert_eq!(expected, read_str); - } - check!(fs::remove_file(&f)); - } - check!(fs::remove_dir(dir)); - } - - #[test] - fn file_create_new_already_exists_error() { - let tmpdir = tmpdir(); - let file = &tmpdir.join("file_create_new_error_exists"); - check!(fs::File::create(file)); - let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err(); - assert_eq!(e.kind(), ErrorKind::AlreadyExists); - } - - #[test] - fn mkdir_path_already_exists_error() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("mkdir_error_twice"); - check!(fs::create_dir(dir)); - let e = fs::create_dir(dir).unwrap_err(); - assert_eq!(e.kind(), ErrorKind::AlreadyExists); - } - - #[test] - fn recursive_mkdir() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1/d2"); - check!(fs::create_dir_all(&dir)); - assert!(dir.is_dir()) - } - - #[test] - fn recursive_mkdir_failure() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1"); - let file = dir.join("f1"); - - check!(fs::create_dir_all(&dir)); - check!(File::create(&file)); - - let result = fs::create_dir_all(&file); - - assert!(result.is_err()); - } - - #[test] - fn concurrent_recursive_mkdir() { - for _ in 0..100 { - let dir = tmpdir(); - let mut dir = dir.join("a"); - for _ in 0..40 { - dir = dir.join("a"); - } - let mut join = vec![]; - for _ in 0..8 { - let dir = dir.clone(); - join.push(thread::spawn(move || { - check!(fs::create_dir_all(&dir)); - })) - } - - // No `Display` on result of `join()` - join.drain(..).map(|join| join.join().unwrap()).count(); - } - } - - #[test] - fn recursive_mkdir_slash() { - check!(fs::create_dir_all(Path::new("/"))); - } - - #[test] - fn recursive_mkdir_dot() { - check!(fs::create_dir_all(Path::new("."))); - } - - #[test] - fn recursive_mkdir_empty() { - check!(fs::create_dir_all(Path::new(""))); - } - - #[test] - fn recursive_rmdir() { - let tmpdir = tmpdir(); - let d1 = tmpdir.join("d1"); - let dt = d1.join("t"); - let dtt = dt.join("t"); - let d2 = tmpdir.join("d2"); - let canary = d2.join("do_not_delete"); - check!(fs::create_dir_all(&dtt)); - check!(fs::create_dir_all(&d2)); - check!(check!(File::create(&canary)).write(b"foo")); - check!(symlink_junction(&d2, &dt.join("d2"))); - let _ = symlink_file(&canary, &d1.join("canary")); - check!(fs::remove_dir_all(&d1)); - - assert!(!d1.is_dir()); - assert!(canary.exists()); - } - - #[test] - fn recursive_rmdir_of_symlink() { - // test we do not recursively delete a symlink but only dirs. - let tmpdir = tmpdir(); - let link = tmpdir.join("d1"); - let dir = tmpdir.join("d2"); - let canary = dir.join("do_not_delete"); - check!(fs::create_dir_all(&dir)); - check!(check!(File::create(&canary)).write(b"foo")); - check!(symlink_junction(&dir, &link)); - check!(fs::remove_dir_all(&link)); - - assert!(!link.is_dir()); - assert!(canary.exists()); - } - - #[test] - // only Windows makes a distinction between file and directory symlinks. - #[cfg(windows)] - fn recursive_rmdir_of_file_symlink() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - let f1 = tmpdir.join("f1"); - let f2 = tmpdir.join("f2"); - check!(check!(File::create(&f1)).write(b"foo")); - check!(symlink_file(&f1, &f2)); - match fs::remove_dir_all(&f2) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn unicode_path_is_dir() { - assert!(Path::new(".").is_dir()); - assert!(!Path::new("test/stdtest/fs.rs").is_dir()); - - let tmpdir = tmpdir(); - - let mut dirpath = tmpdir.path().to_path_buf(); - dirpath.push("test-가一ー你好"); - check!(fs::create_dir(&dirpath)); - assert!(dirpath.is_dir()); - - let mut filepath = dirpath; - filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); - check!(File::create(&filepath)); // ignore return; touch only - assert!(!filepath.is_dir()); - assert!(filepath.exists()); - } - - #[test] - fn unicode_path_exists() { - assert!(Path::new(".").exists()); - assert!(!Path::new("test/nonexistent-bogus-path").exists()); - - let tmpdir = tmpdir(); - let unicode = tmpdir.path(); - let unicode = unicode.join("test-각丁ー再见"); - check!(fs::create_dir(&unicode)); - assert!(unicode.exists()); - assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); - } - - #[test] - fn copy_file_does_not_exist() { - let from = Path::new("test/nonexistent-bogus-path"); - let to = Path::new("test/other-bogus-path"); - - match fs::copy(&from, &to) { - Ok(..) => panic!(), - Err(..) => { - assert!(!from.exists()); - assert!(!to.exists()); - } - } - } - - #[test] - fn copy_src_does_not_exist() { - let tmpdir = tmpdir(); - let from = Path::new("test/nonexistent-bogus-path"); - let to = tmpdir.join("out.txt"); - check!(check!(File::create(&to)).write(b"hello")); - assert!(fs::copy(&from, &to).is_err()); - assert!(!from.exists()); - let mut v = Vec::new(); - check!(check!(File::open(&to)).read_to_end(&mut v)); - assert_eq!(v, b"hello"); - } - - #[test] - fn copy_file_ok() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write(b"hello")); - check!(fs::copy(&input, &out)); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"hello"); - - assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions()); - } - - #[test] - fn copy_file_dst_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - check!(File::create(&out)); - match fs::copy(&*out, tmpdir.path()) { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[test] - fn copy_file_dst_exists() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in"); - let output = tmpdir.join("out"); - - check!(check!(File::create(&input)).write("foo".as_bytes())); - check!(check!(File::create(&output)).write("bar".as_bytes())); - check!(fs::copy(&input, &output)); - - let mut v = Vec::new(); - check!(check!(File::open(&output)).read_to_end(&mut v)); - assert_eq!(v, b"foo".to_vec()); - } - - #[test] - fn copy_file_src_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - match fs::copy(tmpdir.path(), &out) { - Ok(..) => panic!(), - Err(..) => {} - } - assert!(!out.exists()); - } - - #[test] - fn copy_file_preserves_perm_bits() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - let attr = check!(check!(File::create(&input)).metadata()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(fs::set_permissions(&input, p)); - check!(fs::copy(&input, &out)); - assert!(check!(out.metadata()).permissions().readonly()); - check!(fs::set_permissions(&input, attr.permissions())); - check!(fs::set_permissions(&out, attr.permissions())); - } - - #[test] - #[cfg(windows)] - fn copy_file_preserves_streams() { - let tmp = tmpdir(); - check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes())); - assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0); - assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0); - let mut v = Vec::new(); - check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v)); - assert_eq!(v, b"carrot".to_vec()); - } - - #[test] - fn copy_file_returns_metadata_len() { - let tmp = tmpdir(); - let in_path = tmp.join("in.txt"); - let out_path = tmp.join("out.txt"); - check!(check!(File::create(&in_path)).write(b"lettuce")); - #[cfg(windows)] - check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot")); - let copied_len = check!(fs::copy(&in_path, &out_path)); - assert_eq!(check!(out_path.metadata()).len(), copied_len); - } - - #[test] - fn copy_file_follows_dst_symlink() { - let tmp = tmpdir(); - if !got_symlink_permission(&tmp) { - return; - }; - - let in_path = tmp.join("in.txt"); - let out_path = tmp.join("out.txt"); - let out_path_symlink = tmp.join("out_symlink.txt"); - - check!(fs::write(&in_path, "foo")); - check!(fs::write(&out_path, "bar")); - check!(symlink_file(&out_path, &out_path_symlink)); - - check!(fs::copy(&in_path, &out_path_symlink)); - - assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink()); - assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec()); - assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec()); - } - - #[test] - fn symlinks_work() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write("foobar".as_bytes())); - check!(symlink_file(&input, &out)); - assert!(check!(out.symlink_metadata()).file_type().is_symlink()); - assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"foobar".to_vec()); - } - - #[test] - fn symlink_noexist() { - // Symlinks can point to things that don't exist - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - // Use a relative path for testing. Symlinks get normalized by Windows, - // so we may not get the same path back for absolute paths - check!(symlink_file(&"foo", &tmpdir.join("bar"))); - assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo"); - } - - #[test] - fn read_link() { - if cfg!(windows) { - // directory symlink - assert_eq!( - check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(), - r"C:\ProgramData" - ); - // junction - assert_eq!( - check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(), - r"C:\Users\Default" - ); - // junction with special permissions - assert_eq!( - check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(), - r"C:\Users" - ); - } - let tmpdir = tmpdir(); - let link = tmpdir.join("link"); - if !got_symlink_permission(&tmpdir) { - return; - }; - check!(symlink_file(&"foo", &link)); - assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo"); - } - - #[test] - fn readlink_not_symlink() { - let tmpdir = tmpdir(); - match fs::read_link(tmpdir.path()) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn links_work() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write("foobar".as_bytes())); - check!(fs::hard_link(&input, &out)); - assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); - assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len()); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"foobar".to_vec()); - - // can't link to yourself - match fs::hard_link(&input, &input) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - // can't link to something that doesn't exist - match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn chmod_works() { - let tmpdir = tmpdir(); - let file = tmpdir.join("in.txt"); - - check!(File::create(&file)); - let attr = check!(fs::metadata(&file)); - assert!(!attr.permissions().readonly()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(fs::set_permissions(&file, p.clone())); - let attr = check!(fs::metadata(&file)); - assert!(attr.permissions().readonly()); - - match fs::set_permissions(&tmpdir.join("foo"), p.clone()) { - Ok(..) => panic!("wanted an error"), - Err(..) => {} - } - - p.set_readonly(false); - check!(fs::set_permissions(&file, p)); - } - - #[test] - fn fchmod_works() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let file = check!(File::create(&path)); - let attr = check!(fs::metadata(&path)); - assert!(!attr.permissions().readonly()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(file.set_permissions(p.clone())); - let attr = check!(fs::metadata(&path)); - assert!(attr.permissions().readonly()); - - p.set_readonly(false); - check!(file.set_permissions(p)); - } - - #[test] - fn sync_doesnt_kill_anything() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::create(&path)); - check!(file.sync_all()); - check!(file.sync_data()); - check!(file.write(b"foo")); - check!(file.sync_all()); - check!(file.sync_data()); - } - - #[test] - fn truncate_works() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::create(&path)); - check!(file.write(b"foo")); - check!(file.sync_all()); - - // Do some simple things with truncation - assert_eq!(check!(file.metadata()).len(), 3); - check!(file.set_len(10)); - assert_eq!(check!(file.metadata()).len(), 10); - check!(file.write(b"bar")); - check!(file.sync_all()); - assert_eq!(check!(file.metadata()).len(), 10); - - let mut v = Vec::new(); - check!(check!(File::open(&path)).read_to_end(&mut v)); - assert_eq!(v, b"foobar\0\0\0\0".to_vec()); - - // Truncate to a smaller length, don't seek, and then write something. - // Ensure that the intermediate zeroes are all filled in (we have `seek`ed - // past the end of the file). - check!(file.set_len(2)); - assert_eq!(check!(file.metadata()).len(), 2); - check!(file.write(b"wut")); - check!(file.sync_all()); - assert_eq!(check!(file.metadata()).len(), 9); - let mut v = Vec::new(); - check!(check!(File::open(&path)).read_to_end(&mut v)); - assert_eq!(v, b"fo\0\0\0\0wut".to_vec()); - } - - #[test] - fn open_flavors() { - use crate::fs::OpenOptions as OO; - fn c(t: &T) -> T { - t.clone() - } - - let tmpdir = tmpdir(); - - let mut r = OO::new(); - r.read(true); - let mut w = OO::new(); - w.write(true); - let mut rw = OO::new(); - rw.read(true).write(true); - let mut a = OO::new(); - a.append(true); - let mut ra = OO::new(); - ra.read(true).append(true); - - #[cfg(windows)] - let invalid_options = 87; // ERROR_INVALID_PARAMETER - #[cfg(all(unix, not(target_os = "vxworks")))] - let invalid_options = "Invalid argument"; - #[cfg(target_os = "vxworks")] - let invalid_options = "invalid argument"; - - // Test various combinations of creation modes and access modes. - // - // Allowed: - // creation mode | read | write | read-write | append | read-append | - // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:| - // not set (open existing) | X | X | X | X | X | - // create | | X | X | X | X | - // truncate | | X | X | | | - // create and truncate | | X | X | | | - // create_new | | X | X | X | X | - // - // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it. - - // write-only - check!(c(&w).create_new(true).open(&tmpdir.join("a"))); - check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a"))); - check!(c(&w).truncate(true).open(&tmpdir.join("a"))); - check!(c(&w).create(true).open(&tmpdir.join("a"))); - check!(c(&w).open(&tmpdir.join("a"))); - - // read-only - error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options); - error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options); - error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options); - error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options); - check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only - - // read-write - check!(c(&rw).create_new(true).open(&tmpdir.join("c"))); - check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c"))); - check!(c(&rw).truncate(true).open(&tmpdir.join("c"))); - check!(c(&rw).create(true).open(&tmpdir.join("c"))); - check!(c(&rw).open(&tmpdir.join("c"))); - - // append - check!(c(&a).create_new(true).open(&tmpdir.join("d"))); - error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options); - error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options); - check!(c(&a).create(true).open(&tmpdir.join("d"))); - check!(c(&a).open(&tmpdir.join("d"))); - - // read-append - check!(c(&ra).create_new(true).open(&tmpdir.join("e"))); - error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options); - error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options); - check!(c(&ra).create(true).open(&tmpdir.join("e"))); - check!(c(&ra).open(&tmpdir.join("e"))); - - // Test opening a file without setting an access mode - let mut blank = OO::new(); - error!(blank.create(true).open(&tmpdir.join("f")), invalid_options); - - // Test write works - check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes())); - - // Test write fails for read-only - check!(r.open(&tmpdir.join("h"))); - { - let mut f = check!(r.open(&tmpdir.join("h"))); - assert!(f.write("wut".as_bytes()).is_err()); - } - - // Test write overwrites - { - let mut f = check!(c(&w).open(&tmpdir.join("h"))); - check!(f.write("baz".as_bytes())); - } - { - let mut f = check!(c(&r).open(&tmpdir.join("h"))); - let mut b = vec![0; 6]; - check!(f.read(&mut b)); - assert_eq!(b, "bazbar".as_bytes()); - } - - // Test truncate works - { - let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h"))); - check!(f.write("foo".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); - - // Test append works - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); - { - let mut f = check!(c(&a).open(&tmpdir.join("h"))); - check!(f.write("bar".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6); - - // Test .append(true) equals .write(true).append(true) - { - let mut f = check!(c(&w).append(true).open(&tmpdir.join("h"))); - check!(f.write("baz".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9); - } - - #[test] - fn _assert_send_sync() { - fn _assert_send_sync() {} - _assert_send_sync::(); - } - - #[test] - fn binary_file() { - let mut bytes = [0; 1024]; - StdRng::from_entropy().fill_bytes(&mut bytes); - - let tmpdir = tmpdir(); - - check!(check!(File::create(&tmpdir.join("test"))).write(&bytes)); - let mut v = Vec::new(); - check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v)); - assert!(v == &bytes[..]); - } - - #[test] - fn write_then_read() { - let mut bytes = [0; 1024]; - StdRng::from_entropy().fill_bytes(&mut bytes); - - let tmpdir = tmpdir(); - - check!(fs::write(&tmpdir.join("test"), &bytes[..])); - let v = check!(fs::read(&tmpdir.join("test"))); - assert!(v == &bytes[..]); - - check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF])); - error_contains!( - fs::read_to_string(&tmpdir.join("not-utf8")), - "stream did not contain valid UTF-8" - ); - - let s = "𐁁𐀓𐀠𐀴𐀍"; - check!(fs::write(&tmpdir.join("utf8"), s.as_bytes())); - let string = check!(fs::read_to_string(&tmpdir.join("utf8"))); - assert_eq!(string, s); - } - - #[test] - fn file_try_clone() { - let tmpdir = tmpdir(); - - let mut f1 = check!( - OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test")) - ); - let mut f2 = check!(f1.try_clone()); - - check!(f1.write_all(b"hello world")); - check!(f1.seek(SeekFrom::Start(2))); - - let mut buf = vec![]; - check!(f2.read_to_end(&mut buf)); - assert_eq!(buf, b"llo world"); - drop(f2); - - check!(f1.write_all(b"!")); - } - - #[test] - #[cfg(not(windows))] - fn unlink_readonly() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(File::create(&path)); - let mut perm = check!(fs::metadata(&path)).permissions(); - perm.set_readonly(true); - check!(fs::set_permissions(&path, perm)); - check!(fs::remove_file(&path)); - } - - #[test] - fn mkdir_trailing_slash() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(fs::create_dir_all(&path.join("a/"))); - } - - #[test] - fn canonicalize_works_simple() { - let tmpdir = tmpdir(); - let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); - let file = tmpdir.join("test"); - File::create(&file).unwrap(); - assert_eq!(fs::canonicalize(&file).unwrap(), file); - } - - #[test] - fn realpath_works() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); - let file = tmpdir.join("test"); - let dir = tmpdir.join("test2"); - let link = dir.join("link"); - let linkdir = tmpdir.join("test3"); - - File::create(&file).unwrap(); - fs::create_dir(&dir).unwrap(); - symlink_file(&file, &link).unwrap(); - symlink_dir(&dir, &linkdir).unwrap(); - - assert!(link.symlink_metadata().unwrap().file_type().is_symlink()); - - assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir); - assert_eq!(fs::canonicalize(&file).unwrap(), file); - assert_eq!(fs::canonicalize(&link).unwrap(), file); - assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir); - assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file); - } - - #[test] - fn realpath_works_tricky() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); - let a = tmpdir.join("a"); - let b = a.join("b"); - let c = b.join("c"); - let d = a.join("d"); - let e = d.join("e"); - let f = a.join("f"); - - fs::create_dir_all(&b).unwrap(); - fs::create_dir_all(&d).unwrap(); - File::create(&f).unwrap(); - if cfg!(not(windows)) { - symlink_file("../d/e", &c).unwrap(); - symlink_file("../f", &e).unwrap(); - } - if cfg!(windows) { - symlink_file(r"..\d\e", &c).unwrap(); - symlink_file(r"..\f", &e).unwrap(); - } - - assert_eq!(fs::canonicalize(&c).unwrap(), f); - assert_eq!(fs::canonicalize(&e).unwrap(), f); - } - - #[test] - fn dir_entry_methods() { - let tmpdir = tmpdir(); - - fs::create_dir_all(&tmpdir.join("a")).unwrap(); - File::create(&tmpdir.join("b")).unwrap(); - - for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) { - let fname = file.file_name(); - match fname.to_str() { - Some("a") => { - assert!(file.file_type().unwrap().is_dir()); - assert!(file.metadata().unwrap().is_dir()); - } - Some("b") => { - assert!(file.file_type().unwrap().is_file()); - assert!(file.metadata().unwrap().is_file()); - } - f => panic!("unknown file name: {:?}", f), - } - } - } - - #[test] - fn dir_entry_debug() { - let tmpdir = tmpdir(); - File::create(&tmpdir.join("b")).unwrap(); - let mut read_dir = tmpdir.path().read_dir().unwrap(); - let dir_entry = read_dir.next().unwrap().unwrap(); - let actual = format!("{:?}", dir_entry); - let expected = format!("DirEntry({:?})", dir_entry.0.path()); - assert_eq!(actual, expected); - } - - #[test] - fn read_dir_not_found() { - let res = fs::read_dir("/path/that/does/not/exist"); - assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound); - } - - #[test] - fn create_dir_all_with_junctions() { - let tmpdir = tmpdir(); - let target = tmpdir.join("target"); - - let junction = tmpdir.join("junction"); - let b = junction.join("a/b"); - - let link = tmpdir.join("link"); - let d = link.join("c/d"); - - fs::create_dir(&target).unwrap(); - - check!(symlink_junction(&target, &junction)); - check!(fs::create_dir_all(&b)); - // the junction itself is not a directory, but `is_dir()` on a Path - // follows links - assert!(junction.is_dir()); - assert!(b.exists()); - - if !got_symlink_permission(&tmpdir) { - return; - }; - check!(symlink_dir(&target, &link)); - check!(fs::create_dir_all(&d)); - assert!(link.is_dir()); - assert!(d.exists()); - } - - #[test] - fn metadata_access_times() { - let tmpdir = tmpdir(); - - let b = tmpdir.join("b"); - File::create(&b).unwrap(); - - let a = check!(fs::metadata(&tmpdir.path())); - let b = check!(fs::metadata(&b)); - - assert_eq!(check!(a.accessed()), check!(a.accessed())); - assert_eq!(check!(a.modified()), check!(a.modified())); - assert_eq!(check!(b.accessed()), check!(b.modified())); - - if cfg!(target_os = "macos") || cfg!(target_os = "windows") { - check!(a.created()); - check!(b.created()); - } - - if cfg!(target_os = "linux") { - // Not always available - match (a.created(), b.created()) { - (Ok(t1), Ok(t2)) => assert!(t1 <= t2), - (Err(e1), Err(e2)) - if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other => {} - (a, b) => panic!( - "creation time must be always supported or not supported: {:?} {:?}", - a, b, - ), - } - } - } -} diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs new file mode 100644 index 0000000000..65a29076fe --- /dev/null +++ b/library/std/src/fs/tests.rs @@ -0,0 +1,1339 @@ +use crate::io::prelude::*; + +use crate::fs::{self, File, OpenOptions}; +use crate::io::{ErrorKind, SeekFrom}; +use crate::path::Path; +use crate::str; +use crate::sys_common::io::test::{tmpdir, TempDir}; +use crate::thread; + +use rand::{rngs::StdRng, RngCore, SeedableRng}; + +#[cfg(unix)] +use crate::os::unix::fs::symlink as symlink_dir; +#[cfg(unix)] +use crate::os::unix::fs::symlink as symlink_file; +#[cfg(unix)] +use crate::os::unix::fs::symlink as symlink_junction; +#[cfg(windows)] +use crate::os::windows::fs::{symlink_dir, symlink_file}; +#[cfg(windows)] +use crate::sys::fs::symlink_junction; + +macro_rules! check { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("{} failed with: {}", stringify!($e), e), + } + }; +} + +#[cfg(windows)] +macro_rules! error { + ($e:expr, $s:expr) => { + match $e { + Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), + Err(ref err) => assert!( + err.raw_os_error() == Some($s), + format!("`{}` did not have a code of `{}`", err, $s) + ), + } + }; +} + +#[cfg(unix)] +macro_rules! error { + ($e:expr, $s:expr) => { + error_contains!($e, $s) + }; +} + +macro_rules! error_contains { + ($e:expr, $s:expr) => { + match $e { + Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), + Err(ref err) => { + assert!(err.to_string().contains($s), format!("`{}` did not contain `{}`", err, $s)) + } + } + }; +} + +// Several test fail on windows if the user does not have permission to +// create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of +// disabling these test on Windows, use this function to test whether we +// have permission, and return otherwise. This way, we still don't run these +// tests most of the time, but at least we do if the user has the right +// permissions. +pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { + if cfg!(unix) { + return true; + } + let link = tmpdir.join("some_hopefully_unique_link_name"); + + match symlink_file(r"nonexisting_target", link) { + Ok(_) => true, + // ERROR_PRIVILEGE_NOT_HELD = 1314 + Err(ref err) if err.raw_os_error() == Some(1314) => false, + Err(_) => true, + } +} + +#[test] +fn file_test_io_smoke_test() { + let message = "it's alright. have a good time"; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test.txt"); + { + let mut write_stream = check!(File::create(filename)); + check!(write_stream.write(message.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + let mut read_buf = [0; 1028]; + let read_str = match check!(read_stream.read(&mut read_buf)) { + 0 => panic!("shouldn't happen"), + n => str::from_utf8(&read_buf[..n]).unwrap().to_string(), + }; + assert_eq!(read_str, message); + } + check!(fs::remove_file(filename)); +} + +#[test] +fn invalid_path_raises() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_that_does_not_exist.txt"); + let result = File::open(filename); + + #[cfg(all(unix, not(target_os = "vxworks")))] + error!(result, "No such file or directory"); + #[cfg(target_os = "vxworks")] + error!(result, "no such file or directory"); + #[cfg(windows)] + error!(result, 2); // ERROR_FILE_NOT_FOUND +} + +#[test] +fn file_test_iounlinking_invalid_path_should_raise_condition() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); + + let result = fs::remove_file(filename); + + #[cfg(all(unix, not(target_os = "vxworks")))] + error!(result, "No such file or directory"); + #[cfg(target_os = "vxworks")] + error!(result, "no such file or directory"); + #[cfg(windows)] + error!(result, 2); // ERROR_FILE_NOT_FOUND +} + +#[test] +fn file_test_io_non_positional_read() { + let message: &str = "ten-four"; + let mut read_mem = [0; 8]; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(message.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + { + let read_buf = &mut read_mem[0..4]; + check!(read_stream.read(read_buf)); + } + { + let read_buf = &mut read_mem[4..8]; + check!(read_stream.read(read_buf)); + } + } + check!(fs::remove_file(filename)); + let read_str = str::from_utf8(&read_mem).unwrap(); + assert_eq!(read_str, message); +} + +#[test] +fn file_test_io_seek_and_tell_smoke_test() { + let message = "ten-four"; + let mut read_mem = [0; 4]; + let set_cursor = 4 as u64; + let tell_pos_pre_read; + let tell_pos_post_read; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(message.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + check!(read_stream.seek(SeekFrom::Start(set_cursor))); + tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0))); + check!(read_stream.read(&mut read_mem)); + tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0))); + } + check!(fs::remove_file(filename)); + let read_str = str::from_utf8(&read_mem).unwrap(); + assert_eq!(read_str, &message[4..8]); + assert_eq!(tell_pos_pre_read, set_cursor); + assert_eq!(tell_pos_post_read, message.len() as u64); +} + +#[test] +fn file_test_io_seek_and_write() { + let initial_msg = "food-is-yummy"; + let overwrite_msg = "-the-bar!!"; + let final_msg = "foo-the-bar!!"; + let seek_idx = 3; + let mut read_mem = [0; 13]; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(initial_msg.as_bytes())); + check!(rw_stream.seek(SeekFrom::Start(seek_idx))); + check!(rw_stream.write(overwrite_msg.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + check!(read_stream.read(&mut read_mem)); + } + check!(fs::remove_file(filename)); + let read_str = str::from_utf8(&read_mem).unwrap(); + assert!(read_str == final_msg); +} + +#[test] +fn file_test_io_seek_shakedown() { + // 01234567890123 + let initial_msg = "qwer-asdf-zxcv"; + let chunk_one: &str = "qwer"; + let chunk_two: &str = "asdf"; + let chunk_three: &str = "zxcv"; + let mut read_mem = [0; 4]; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(initial_msg.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + + check!(read_stream.seek(SeekFrom::End(-4))); + check!(read_stream.read(&mut read_mem)); + assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three); + + check!(read_stream.seek(SeekFrom::Current(-9))); + check!(read_stream.read(&mut read_mem)); + assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two); + + check!(read_stream.seek(SeekFrom::Start(0))); + check!(read_stream.read(&mut read_mem)); + assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one); + } + check!(fs::remove_file(filename)); +} + +#[test] +fn file_test_io_eof() { + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_eof.txt"); + let mut buf = [0; 256]; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + assert_eq!(check!(rw.read(&mut buf)), 0); + assert_eq!(check!(rw.read(&mut buf)), 0); + } + check!(fs::remove_file(&filename)); +} + +#[test] +#[cfg(unix)] +fn file_test_io_read_write_at() { + use crate::os::unix::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt"); + let mut buf = [0; 256]; + let write1 = "asdf"; + let write2 = "qwer-"; + let write3 = "-zxcv"; + let content = "qwer-asdf-zxcv"; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0")); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.read(&mut buf)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + } + { + let mut read = check!(File::open(&filename)); + assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(read.read(&mut buf)), write3.len()); + assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.read_at(&mut buf, 14)), 0); + assert_eq!(check!(read.read_at(&mut buf, 15)), 0); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + } + check!(fs::remove_file(&filename)); +} + +#[test] +#[cfg(unix)] +fn set_get_unix_permissions() { + use crate::os::unix::fs::PermissionsExt; + + let tmpdir = tmpdir(); + let filename = &tmpdir.join("set_get_unix_permissions"); + check!(fs::create_dir(filename)); + let mask = 0o7777; + + check!(fs::set_permissions(filename, fs::Permissions::from_mode(0))); + let metadata0 = check!(fs::metadata(filename)); + assert_eq!(mask & metadata0.permissions().mode(), 0); + + check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777))); + let metadata1 = check!(fs::metadata(filename)); + #[cfg(all(unix, not(target_os = "vxworks")))] + assert_eq!(mask & metadata1.permissions().mode(), 0o1777); + #[cfg(target_os = "vxworks")] + assert_eq!(mask & metadata1.permissions().mode(), 0o0777); +} + +#[test] +#[cfg(windows)] +fn file_test_io_seek_read_write() { + use crate::os::windows::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt"); + let mut buf = [0; 256]; + let write1 = "asdf"; + let write2 = "qwer-"; + let write3 = "-zxcv"; + let content = "qwer-asdf-zxcv"; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0); + assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.read(&mut buf)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len()); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14); + } + { + let mut read = check!(File::open(&filename)); + assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.read(&mut buf)), write3.len()); + assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek_read(&mut buf, 14)), 0); + assert_eq!(check!(read.seek_read(&mut buf, 15)), 0); + } + check!(fs::remove_file(&filename)); +} + +#[test] +fn file_test_stat_is_correct_on_is_file() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); + { + let mut opts = OpenOptions::new(); + let mut fs = check!(opts.read(true).write(true).create(true).open(filename)); + let msg = "hw"; + fs.write(msg.as_bytes()).unwrap(); + + let fstat_res = check!(fs.metadata()); + assert!(fstat_res.is_file()); + } + let stat_res_fn = check!(fs::metadata(filename)); + assert!(stat_res_fn.is_file()); + let stat_res_meth = check!(filename.metadata()); + assert!(stat_res_meth.is_file()); + check!(fs::remove_file(filename)); +} + +#[test] +fn file_test_stat_is_correct_on_is_dir() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_stat_correct_on_is_dir"); + check!(fs::create_dir(filename)); + let stat_res_fn = check!(fs::metadata(filename)); + assert!(stat_res_fn.is_dir()); + let stat_res_meth = check!(filename.metadata()); + assert!(stat_res_meth.is_dir()); + check!(fs::remove_dir(filename)); +} + +#[test] +fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("fileinfo_false_on_dir"); + check!(fs::create_dir(dir)); + assert!(!dir.is_file()); + check!(fs::remove_dir(dir)); +} + +#[test] +fn file_test_fileinfo_check_exists_before_and_after_file_creation() { + let tmpdir = tmpdir(); + let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); + check!(check!(File::create(file)).write(b"foo")); + assert!(file.exists()); + check!(fs::remove_file(file)); + assert!(!file.exists()); +} + +#[test] +fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("before_and_after_dir"); + assert!(!dir.exists()); + check!(fs::create_dir(dir)); + assert!(dir.exists()); + assert!(dir.is_dir()); + check!(fs::remove_dir(dir)); + assert!(!dir.exists()); +} + +#[test] +fn file_test_directoryinfo_readdir() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("di_readdir"); + check!(fs::create_dir(dir)); + let prefix = "foo"; + for n in 0..3 { + let f = dir.join(&format!("{}.txt", n)); + let mut w = check!(File::create(&f)); + let msg_str = format!("{}{}", prefix, n.to_string()); + let msg = msg_str.as_bytes(); + check!(w.write(msg)); + } + let files = check!(fs::read_dir(dir)); + let mut mem = [0; 4]; + for f in files { + let f = f.unwrap().path(); + { + let n = f.file_stem().unwrap(); + check!(check!(File::open(&f)).read(&mut mem)); + let read_str = str::from_utf8(&mem).unwrap(); + let expected = format!("{}{}", prefix, n.to_str().unwrap()); + assert_eq!(expected, read_str); + } + check!(fs::remove_file(&f)); + } + check!(fs::remove_dir(dir)); +} + +#[test] +fn file_create_new_already_exists_error() { + let tmpdir = tmpdir(); + let file = &tmpdir.join("file_create_new_error_exists"); + check!(fs::File::create(file)); + let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err(); + assert_eq!(e.kind(), ErrorKind::AlreadyExists); +} + +#[test] +fn mkdir_path_already_exists_error() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("mkdir_error_twice"); + check!(fs::create_dir(dir)); + let e = fs::create_dir(dir).unwrap_err(); + assert_eq!(e.kind(), ErrorKind::AlreadyExists); +} + +#[test] +fn recursive_mkdir() { + let tmpdir = tmpdir(); + let dir = tmpdir.join("d1/d2"); + check!(fs::create_dir_all(&dir)); + assert!(dir.is_dir()) +} + +#[test] +fn recursive_mkdir_failure() { + let tmpdir = tmpdir(); + let dir = tmpdir.join("d1"); + let file = dir.join("f1"); + + check!(fs::create_dir_all(&dir)); + check!(File::create(&file)); + + let result = fs::create_dir_all(&file); + + assert!(result.is_err()); +} + +#[test] +fn concurrent_recursive_mkdir() { + for _ in 0..100 { + let dir = tmpdir(); + let mut dir = dir.join("a"); + for _ in 0..40 { + dir = dir.join("a"); + } + let mut join = vec![]; + for _ in 0..8 { + let dir = dir.clone(); + join.push(thread::spawn(move || { + check!(fs::create_dir_all(&dir)); + })) + } + + // No `Display` on result of `join()` + join.drain(..).map(|join| join.join().unwrap()).count(); + } +} + +#[test] +fn recursive_mkdir_slash() { + check!(fs::create_dir_all(Path::new("/"))); +} + +#[test] +fn recursive_mkdir_dot() { + check!(fs::create_dir_all(Path::new("."))); +} + +#[test] +fn recursive_mkdir_empty() { + check!(fs::create_dir_all(Path::new(""))); +} + +#[test] +fn recursive_rmdir() { + let tmpdir = tmpdir(); + let d1 = tmpdir.join("d1"); + let dt = d1.join("t"); + let dtt = dt.join("t"); + let d2 = tmpdir.join("d2"); + let canary = d2.join("do_not_delete"); + check!(fs::create_dir_all(&dtt)); + check!(fs::create_dir_all(&d2)); + check!(check!(File::create(&canary)).write(b"foo")); + check!(symlink_junction(&d2, &dt.join("d2"))); + let _ = symlink_file(&canary, &d1.join("canary")); + check!(fs::remove_dir_all(&d1)); + + assert!(!d1.is_dir()); + assert!(canary.exists()); +} + +#[test] +fn recursive_rmdir_of_symlink() { + // test we do not recursively delete a symlink but only dirs. + let tmpdir = tmpdir(); + let link = tmpdir.join("d1"); + let dir = tmpdir.join("d2"); + let canary = dir.join("do_not_delete"); + check!(fs::create_dir_all(&dir)); + check!(check!(File::create(&canary)).write(b"foo")); + check!(symlink_junction(&dir, &link)); + check!(fs::remove_dir_all(&link)); + + assert!(!link.is_dir()); + assert!(canary.exists()); +} + +#[test] +// only Windows makes a distinction between file and directory symlinks. +#[cfg(windows)] +fn recursive_rmdir_of_file_symlink() { + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + let f1 = tmpdir.join("f1"); + let f2 = tmpdir.join("f2"); + check!(check!(File::create(&f1)).write(b"foo")); + check!(symlink_file(&f1, &f2)); + match fs::remove_dir_all(&f2) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } +} + +#[test] +fn unicode_path_is_dir() { + assert!(Path::new(".").is_dir()); + assert!(!Path::new("test/stdtest/fs.rs").is_dir()); + + let tmpdir = tmpdir(); + + let mut dirpath = tmpdir.path().to_path_buf(); + dirpath.push("test-가一ー你好"); + check!(fs::create_dir(&dirpath)); + assert!(dirpath.is_dir()); + + let mut filepath = dirpath; + filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); + check!(File::create(&filepath)); // ignore return; touch only + assert!(!filepath.is_dir()); + assert!(filepath.exists()); +} + +#[test] +fn unicode_path_exists() { + assert!(Path::new(".").exists()); + assert!(!Path::new("test/nonexistent-bogus-path").exists()); + + let tmpdir = tmpdir(); + let unicode = tmpdir.path(); + let unicode = unicode.join("test-각丁ー再见"); + check!(fs::create_dir(&unicode)); + assert!(unicode.exists()); + assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); +} + +#[test] +fn copy_file_does_not_exist() { + let from = Path::new("test/nonexistent-bogus-path"); + let to = Path::new("test/other-bogus-path"); + + match fs::copy(&from, &to) { + Ok(..) => panic!(), + Err(..) => { + assert!(!from.exists()); + assert!(!to.exists()); + } + } +} + +#[test] +fn copy_src_does_not_exist() { + let tmpdir = tmpdir(); + let from = Path::new("test/nonexistent-bogus-path"); + let to = tmpdir.join("out.txt"); + check!(check!(File::create(&to)).write(b"hello")); + assert!(fs::copy(&from, &to).is_err()); + assert!(!from.exists()); + let mut v = Vec::new(); + check!(check!(File::open(&to)).read_to_end(&mut v)); + assert_eq!(v, b"hello"); +} + +#[test] +fn copy_file_ok() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + check!(check!(File::create(&input)).write(b"hello")); + check!(fs::copy(&input, &out)); + let mut v = Vec::new(); + check!(check!(File::open(&out)).read_to_end(&mut v)); + assert_eq!(v, b"hello"); + + assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions()); +} + +#[test] +fn copy_file_dst_dir() { + let tmpdir = tmpdir(); + let out = tmpdir.join("out"); + + check!(File::create(&out)); + match fs::copy(&*out, tmpdir.path()) { + Ok(..) => panic!(), + Err(..) => {} + } +} + +#[test] +fn copy_file_dst_exists() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in"); + let output = tmpdir.join("out"); + + check!(check!(File::create(&input)).write("foo".as_bytes())); + check!(check!(File::create(&output)).write("bar".as_bytes())); + check!(fs::copy(&input, &output)); + + let mut v = Vec::new(); + check!(check!(File::open(&output)).read_to_end(&mut v)); + assert_eq!(v, b"foo".to_vec()); +} + +#[test] +fn copy_file_src_dir() { + let tmpdir = tmpdir(); + let out = tmpdir.join("out"); + + match fs::copy(tmpdir.path(), &out) { + Ok(..) => panic!(), + Err(..) => {} + } + assert!(!out.exists()); +} + +#[test] +fn copy_file_preserves_perm_bits() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + let attr = check!(check!(File::create(&input)).metadata()); + let mut p = attr.permissions(); + p.set_readonly(true); + check!(fs::set_permissions(&input, p)); + check!(fs::copy(&input, &out)); + assert!(check!(out.metadata()).permissions().readonly()); + check!(fs::set_permissions(&input, attr.permissions())); + check!(fs::set_permissions(&out, attr.permissions())); +} + +#[test] +#[cfg(windows)] +fn copy_file_preserves_streams() { + let tmp = tmpdir(); + check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes())); + assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0); + assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0); + let mut v = Vec::new(); + check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v)); + assert_eq!(v, b"carrot".to_vec()); +} + +#[test] +fn copy_file_returns_metadata_len() { + let tmp = tmpdir(); + let in_path = tmp.join("in.txt"); + let out_path = tmp.join("out.txt"); + check!(check!(File::create(&in_path)).write(b"lettuce")); + #[cfg(windows)] + check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot")); + let copied_len = check!(fs::copy(&in_path, &out_path)); + assert_eq!(check!(out_path.metadata()).len(), copied_len); +} + +#[test] +fn copy_file_follows_dst_symlink() { + let tmp = tmpdir(); + if !got_symlink_permission(&tmp) { + return; + }; + + let in_path = tmp.join("in.txt"); + let out_path = tmp.join("out.txt"); + let out_path_symlink = tmp.join("out_symlink.txt"); + + check!(fs::write(&in_path, "foo")); + check!(fs::write(&out_path, "bar")); + check!(symlink_file(&out_path, &out_path_symlink)); + + check!(fs::copy(&in_path, &out_path_symlink)); + + assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink()); + assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec()); + assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec()); +} + +#[test] +fn symlinks_work() { + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + check!(check!(File::create(&input)).write("foobar".as_bytes())); + check!(symlink_file(&input, &out)); + assert!(check!(out.symlink_metadata()).file_type().is_symlink()); + assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); + let mut v = Vec::new(); + check!(check!(File::open(&out)).read_to_end(&mut v)); + assert_eq!(v, b"foobar".to_vec()); +} + +#[test] +fn symlink_noexist() { + // Symlinks can point to things that don't exist + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + // Use a relative path for testing. Symlinks get normalized by Windows, + // so we may not get the same path back for absolute paths + check!(symlink_file(&"foo", &tmpdir.join("bar"))); + assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo"); +} + +#[test] +fn read_link() { + if cfg!(windows) { + // directory symlink + assert_eq!( + check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(), + r"C:\ProgramData" + ); + // junction + assert_eq!( + check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(), + r"C:\Users\Default" + ); + // junction with special permissions + assert_eq!( + check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(), + r"C:\Users" + ); + } + let tmpdir = tmpdir(); + let link = tmpdir.join("link"); + if !got_symlink_permission(&tmpdir) { + return; + }; + check!(symlink_file(&"foo", &link)); + assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo"); +} + +#[test] +fn readlink_not_symlink() { + let tmpdir = tmpdir(); + match fs::read_link(tmpdir.path()) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } +} + +#[test] +fn links_work() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + check!(check!(File::create(&input)).write("foobar".as_bytes())); + check!(fs::hard_link(&input, &out)); + assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); + assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len()); + let mut v = Vec::new(); + check!(check!(File::open(&out)).read_to_end(&mut v)); + assert_eq!(v, b"foobar".to_vec()); + + // can't link to yourself + match fs::hard_link(&input, &input) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } + // can't link to something that doesn't exist + match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } +} + +#[test] +fn chmod_works() { + let tmpdir = tmpdir(); + let file = tmpdir.join("in.txt"); + + check!(File::create(&file)); + let attr = check!(fs::metadata(&file)); + assert!(!attr.permissions().readonly()); + let mut p = attr.permissions(); + p.set_readonly(true); + check!(fs::set_permissions(&file, p.clone())); + let attr = check!(fs::metadata(&file)); + assert!(attr.permissions().readonly()); + + match fs::set_permissions(&tmpdir.join("foo"), p.clone()) { + Ok(..) => panic!("wanted an error"), + Err(..) => {} + } + + p.set_readonly(false); + check!(fs::set_permissions(&file, p)); +} + +#[test] +fn fchmod_works() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let file = check!(File::create(&path)); + let attr = check!(fs::metadata(&path)); + assert!(!attr.permissions().readonly()); + let mut p = attr.permissions(); + p.set_readonly(true); + check!(file.set_permissions(p.clone())); + let attr = check!(fs::metadata(&path)); + assert!(attr.permissions().readonly()); + + p.set_readonly(false); + check!(file.set_permissions(p)); +} + +#[test] +fn sync_doesnt_kill_anything() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let mut file = check!(File::create(&path)); + check!(file.sync_all()); + check!(file.sync_data()); + check!(file.write(b"foo")); + check!(file.sync_all()); + check!(file.sync_data()); +} + +#[test] +fn truncate_works() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let mut file = check!(File::create(&path)); + check!(file.write(b"foo")); + check!(file.sync_all()); + + // Do some simple things with truncation + assert_eq!(check!(file.metadata()).len(), 3); + check!(file.set_len(10)); + assert_eq!(check!(file.metadata()).len(), 10); + check!(file.write(b"bar")); + check!(file.sync_all()); + assert_eq!(check!(file.metadata()).len(), 10); + + let mut v = Vec::new(); + check!(check!(File::open(&path)).read_to_end(&mut v)); + assert_eq!(v, b"foobar\0\0\0\0".to_vec()); + + // Truncate to a smaller length, don't seek, and then write something. + // Ensure that the intermediate zeroes are all filled in (we have `seek`ed + // past the end of the file). + check!(file.set_len(2)); + assert_eq!(check!(file.metadata()).len(), 2); + check!(file.write(b"wut")); + check!(file.sync_all()); + assert_eq!(check!(file.metadata()).len(), 9); + let mut v = Vec::new(); + check!(check!(File::open(&path)).read_to_end(&mut v)); + assert_eq!(v, b"fo\0\0\0\0wut".to_vec()); +} + +#[test] +fn open_flavors() { + use crate::fs::OpenOptions as OO; + fn c(t: &T) -> T { + t.clone() + } + + let tmpdir = tmpdir(); + + let mut r = OO::new(); + r.read(true); + let mut w = OO::new(); + w.write(true); + let mut rw = OO::new(); + rw.read(true).write(true); + let mut a = OO::new(); + a.append(true); + let mut ra = OO::new(); + ra.read(true).append(true); + + #[cfg(windows)] + let invalid_options = 87; // ERROR_INVALID_PARAMETER + #[cfg(all(unix, not(target_os = "vxworks")))] + let invalid_options = "Invalid argument"; + #[cfg(target_os = "vxworks")] + let invalid_options = "invalid argument"; + + // Test various combinations of creation modes and access modes. + // + // Allowed: + // creation mode | read | write | read-write | append | read-append | + // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:| + // not set (open existing) | X | X | X | X | X | + // create | | X | X | X | X | + // truncate | | X | X | | | + // create and truncate | | X | X | | | + // create_new | | X | X | X | X | + // + // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it. + + // write-only + check!(c(&w).create_new(true).open(&tmpdir.join("a"))); + check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a"))); + check!(c(&w).truncate(true).open(&tmpdir.join("a"))); + check!(c(&w).create(true).open(&tmpdir.join("a"))); + check!(c(&w).open(&tmpdir.join("a"))); + + // read-only + error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options); + error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options); + error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options); + error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options); + check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only + + // read-write + check!(c(&rw).create_new(true).open(&tmpdir.join("c"))); + check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c"))); + check!(c(&rw).truncate(true).open(&tmpdir.join("c"))); + check!(c(&rw).create(true).open(&tmpdir.join("c"))); + check!(c(&rw).open(&tmpdir.join("c"))); + + // append + check!(c(&a).create_new(true).open(&tmpdir.join("d"))); + error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options); + error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options); + check!(c(&a).create(true).open(&tmpdir.join("d"))); + check!(c(&a).open(&tmpdir.join("d"))); + + // read-append + check!(c(&ra).create_new(true).open(&tmpdir.join("e"))); + error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options); + error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options); + check!(c(&ra).create(true).open(&tmpdir.join("e"))); + check!(c(&ra).open(&tmpdir.join("e"))); + + // Test opening a file without setting an access mode + let mut blank = OO::new(); + error!(blank.create(true).open(&tmpdir.join("f")), invalid_options); + + // Test write works + check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes())); + + // Test write fails for read-only + check!(r.open(&tmpdir.join("h"))); + { + let mut f = check!(r.open(&tmpdir.join("h"))); + assert!(f.write("wut".as_bytes()).is_err()); + } + + // Test write overwrites + { + let mut f = check!(c(&w).open(&tmpdir.join("h"))); + check!(f.write("baz".as_bytes())); + } + { + let mut f = check!(c(&r).open(&tmpdir.join("h"))); + let mut b = vec![0; 6]; + check!(f.read(&mut b)); + assert_eq!(b, "bazbar".as_bytes()); + } + + // Test truncate works + { + let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h"))); + check!(f.write("foo".as_bytes())); + } + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); + + // Test append works + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); + { + let mut f = check!(c(&a).open(&tmpdir.join("h"))); + check!(f.write("bar".as_bytes())); + } + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6); + + // Test .append(true) equals .write(true).append(true) + { + let mut f = check!(c(&w).append(true).open(&tmpdir.join("h"))); + check!(f.write("baz".as_bytes())); + } + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9); +} + +#[test] +fn _assert_send_sync() { + fn _assert_send_sync() {} + _assert_send_sync::(); +} + +#[test] +fn binary_file() { + let mut bytes = [0; 1024]; + StdRng::from_entropy().fill_bytes(&mut bytes); + + let tmpdir = tmpdir(); + + check!(check!(File::create(&tmpdir.join("test"))).write(&bytes)); + let mut v = Vec::new(); + check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v)); + assert!(v == &bytes[..]); +} + +#[test] +fn write_then_read() { + let mut bytes = [0; 1024]; + StdRng::from_entropy().fill_bytes(&mut bytes); + + let tmpdir = tmpdir(); + + check!(fs::write(&tmpdir.join("test"), &bytes[..])); + let v = check!(fs::read(&tmpdir.join("test"))); + assert!(v == &bytes[..]); + + check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF])); + error_contains!( + fs::read_to_string(&tmpdir.join("not-utf8")), + "stream did not contain valid UTF-8" + ); + + let s = "𐁁𐀓𐀠𐀴𐀍"; + check!(fs::write(&tmpdir.join("utf8"), s.as_bytes())); + let string = check!(fs::read_to_string(&tmpdir.join("utf8"))); + assert_eq!(string, s); +} + +#[test] +fn file_try_clone() { + let tmpdir = tmpdir(); + + let mut f1 = + check!(OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test"))); + let mut f2 = check!(f1.try_clone()); + + check!(f1.write_all(b"hello world")); + check!(f1.seek(SeekFrom::Start(2))); + + let mut buf = vec![]; + check!(f2.read_to_end(&mut buf)); + assert_eq!(buf, b"llo world"); + drop(f2); + + check!(f1.write_all(b"!")); +} + +#[test] +#[cfg(not(windows))] +fn unlink_readonly() { + let tmpdir = tmpdir(); + let path = tmpdir.join("file"); + check!(File::create(&path)); + let mut perm = check!(fs::metadata(&path)).permissions(); + perm.set_readonly(true); + check!(fs::set_permissions(&path, perm)); + check!(fs::remove_file(&path)); +} + +#[test] +fn mkdir_trailing_slash() { + let tmpdir = tmpdir(); + let path = tmpdir.join("file"); + check!(fs::create_dir_all(&path.join("a/"))); +} + +#[test] +fn canonicalize_works_simple() { + let tmpdir = tmpdir(); + let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); + let file = tmpdir.join("test"); + File::create(&file).unwrap(); + assert_eq!(fs::canonicalize(&file).unwrap(), file); +} + +#[test] +fn realpath_works() { + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); + let file = tmpdir.join("test"); + let dir = tmpdir.join("test2"); + let link = dir.join("link"); + let linkdir = tmpdir.join("test3"); + + File::create(&file).unwrap(); + fs::create_dir(&dir).unwrap(); + symlink_file(&file, &link).unwrap(); + symlink_dir(&dir, &linkdir).unwrap(); + + assert!(link.symlink_metadata().unwrap().file_type().is_symlink()); + + assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir); + assert_eq!(fs::canonicalize(&file).unwrap(), file); + assert_eq!(fs::canonicalize(&link).unwrap(), file); + assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir); + assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file); +} + +#[test] +fn realpath_works_tricky() { + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); + let a = tmpdir.join("a"); + let b = a.join("b"); + let c = b.join("c"); + let d = a.join("d"); + let e = d.join("e"); + let f = a.join("f"); + + fs::create_dir_all(&b).unwrap(); + fs::create_dir_all(&d).unwrap(); + File::create(&f).unwrap(); + if cfg!(not(windows)) { + symlink_file("../d/e", &c).unwrap(); + symlink_file("../f", &e).unwrap(); + } + if cfg!(windows) { + symlink_file(r"..\d\e", &c).unwrap(); + symlink_file(r"..\f", &e).unwrap(); + } + + assert_eq!(fs::canonicalize(&c).unwrap(), f); + assert_eq!(fs::canonicalize(&e).unwrap(), f); +} + +#[test] +fn dir_entry_methods() { + let tmpdir = tmpdir(); + + fs::create_dir_all(&tmpdir.join("a")).unwrap(); + File::create(&tmpdir.join("b")).unwrap(); + + for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) { + let fname = file.file_name(); + match fname.to_str() { + Some("a") => { + assert!(file.file_type().unwrap().is_dir()); + assert!(file.metadata().unwrap().is_dir()); + } + Some("b") => { + assert!(file.file_type().unwrap().is_file()); + assert!(file.metadata().unwrap().is_file()); + } + f => panic!("unknown file name: {:?}", f), + } + } +} + +#[test] +fn dir_entry_debug() { + let tmpdir = tmpdir(); + File::create(&tmpdir.join("b")).unwrap(); + let mut read_dir = tmpdir.path().read_dir().unwrap(); + let dir_entry = read_dir.next().unwrap().unwrap(); + let actual = format!("{:?}", dir_entry); + let expected = format!("DirEntry({:?})", dir_entry.0.path()); + assert_eq!(actual, expected); +} + +#[test] +fn read_dir_not_found() { + let res = fs::read_dir("/path/that/does/not/exist"); + assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound); +} + +#[test] +fn create_dir_all_with_junctions() { + let tmpdir = tmpdir(); + let target = tmpdir.join("target"); + + let junction = tmpdir.join("junction"); + let b = junction.join("a/b"); + + let link = tmpdir.join("link"); + let d = link.join("c/d"); + + fs::create_dir(&target).unwrap(); + + check!(symlink_junction(&target, &junction)); + check!(fs::create_dir_all(&b)); + // the junction itself is not a directory, but `is_dir()` on a Path + // follows links + assert!(junction.is_dir()); + assert!(b.exists()); + + if !got_symlink_permission(&tmpdir) { + return; + }; + check!(symlink_dir(&target, &link)); + check!(fs::create_dir_all(&d)); + assert!(link.is_dir()); + assert!(d.exists()); +} + +#[test] +fn metadata_access_times() { + let tmpdir = tmpdir(); + + let b = tmpdir.join("b"); + File::create(&b).unwrap(); + + let a = check!(fs::metadata(&tmpdir.path())); + let b = check!(fs::metadata(&b)); + + assert_eq!(check!(a.accessed()), check!(a.accessed())); + assert_eq!(check!(a.modified()), check!(a.modified())); + assert_eq!(check!(b.accessed()), check!(b.modified())); + + if cfg!(target_os = "macos") || cfg!(target_os = "windows") { + check!(a.created()); + check!(b.created()); + } + + if cfg!(target_os = "linux") { + // Not always available + match (a.created(), b.created()) { + (Ok(t1), Ok(t2)) => assert!(t1 <= t2), + (Err(e1), Err(e2)) + if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other => {} + (a, b) => { + panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,) + } + } + } +} diff --git a/library/std/src/future.rs b/library/std/src/future.rs index 89dd9fb9b2..9d9c36e9af 100644 --- a/library/std/src/future.rs +++ b/library/std/src/future.rs @@ -9,7 +9,7 @@ pub use core::future::Future; pub use core::future::{from_generator, get_context, ResumeTy}; #[doc(inline)] -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use core::future::{pending, ready, Pending, Ready}; #[doc(inline)] diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered.rs index f3aadf29b2..97c4b87979 100644 --- a/library/std/src/io/buffered.rs +++ b/library/std/src/io/buffered.rs @@ -1,5 +1,8 @@ //! Buffering wrappers for I/O traits +#[cfg(test)] +mod tests; + use crate::io::prelude::*; use crate::cmp; @@ -383,6 +386,51 @@ impl Seek for BufReader { self.discard_buffer(); Ok(result) } + + /// Returns the current seek position from the start of the stream. + /// + /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` + /// but does not flush the internal buffer. Due to this optimization the + /// function does not guarantee that calling `.into_inner()` immediately + /// afterwards will yield the underlying reader at the same position. Use + /// [`BufReader::seek`] instead if you require that guarantee. + /// + /// # Panics + /// + /// This function will panic if the position of the inner reader is smaller + /// than the amount of buffered data. That can happen if the inner reader + /// has an incorrect implementation of [`Seek::stream_position`], or if the + /// position has gone out of sync due to calling [`Seek::seek`] directly on + /// the underlying reader. + /// + /// # Example + /// + /// ```no_run + /// #![feature(seek_convenience)] + /// use std::{ + /// io::{self, BufRead, BufReader, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = BufReader::new(File::open("foo.txt")?); + /// + /// let before = f.stream_position()?; + /// f.read_line(&mut String::new())?; + /// let after = f.stream_position()?; + /// + /// println!("The first line was {} bytes long", after - before); + /// Ok(()) + /// } + /// ``` + fn stream_position(&mut self) -> io::Result { + let remainder = (self.cap - self.pos) as u64; + self.inner.stream_position().map(|pos| { + pos.checked_sub(remainder).expect( + "overflow when subtracting remaining buffer size from inner stream position", + ) + }) + } } /// Wraps a writer and buffers its output. @@ -517,33 +565,81 @@ impl BufWriter { BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } } + /// Send data in our local buffer into the inner writer, looping as + /// necessary until either it's all been sent or an error occurs. + /// + /// Because all the data in the buffer has been reported to our owner as + /// "successfully written" (by returning nonzero success values from + /// `write`), any 0-length writes from `inner` must be reported as i/o + /// errors from this method. fn flush_buf(&mut self) -> io::Result<()> { - let mut written = 0; - let len = self.buf.len(); - let mut ret = Ok(()); - while written < len { + /// Helper struct to ensure the buffer is updated after all the writes + /// are complete. It tracks the number of written bytes and drains them + /// all from the front of the buffer when dropped. + struct BufGuard<'a> { + buffer: &'a mut Vec, + written: usize, + } + + impl<'a> BufGuard<'a> { + fn new(buffer: &'a mut Vec) -> Self { + Self { buffer, written: 0 } + } + + /// The unwritten part of the buffer + fn remaining(&self) -> &[u8] { + &self.buffer[self.written..] + } + + /// Flag some bytes as removed from the front of the buffer + fn consume(&mut self, amt: usize) { + self.written += amt; + } + + /// true if all of the bytes have been written + fn done(&self) -> bool { + self.written >= self.buffer.len() + } + } + + impl Drop for BufGuard<'_> { + fn drop(&mut self) { + if self.written > 0 { + self.buffer.drain(..self.written); + } + } + } + + let mut guard = BufGuard::new(&mut self.buf); + let inner = self.inner.as_mut().unwrap(); + while !guard.done() { self.panicked = true; - let r = self.inner.as_mut().unwrap().write(&self.buf[written..]); + let r = inner.write(guard.remaining()); self.panicked = false; match r { Ok(0) => { - ret = - Err(Error::new(ErrorKind::WriteZero, "failed to write the buffered data")); - break; + return Err(Error::new( + ErrorKind::WriteZero, + "failed to write the buffered data", + )); } - Ok(n) => written += n, + Ok(n) => guard.consume(n), Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } + Err(e) => return Err(e), } } - if written > 0 { - self.buf.drain(..written); - } - ret + Ok(()) + } + + /// Buffer some data without flushing it, regardless of the size of the + /// data. Writes as much as possible without exceeding capacity. Returns + /// the number of bytes written. + fn write_to_buf(&mut self, buf: &[u8]) -> usize { + let available = self.buf.capacity() - self.buf.len(); + let amt_to_buffer = available.min(buf.len()); + self.buf.extend_from_slice(&buf[..amt_to_buffer]); + amt_to_buffer } /// Gets a reference to the underlying writer. @@ -656,13 +752,35 @@ impl Write for BufWriter { if self.buf.len() + buf.len() > self.buf.capacity() { self.flush_buf()?; } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 if buf.len() >= self.buf.capacity() { self.panicked = true; let r = self.get_mut().write(buf); self.panicked = false; r } else { - self.buf.write(buf) + self.buf.extend_from_slice(buf); + Ok(buf.len()) + } + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + // Normally, `write_all` just calls `write` in a loop. We can do better + // by calling `self.get_mut().write_all()` directly, which avoids + // round trips through the buffer in the event of a series of partial + // writes in some circumstances. + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_all(buf); + self.panicked = false; + r + } else { + self.buf.extend_from_slice(buf); + Ok(()) } } @@ -671,13 +789,15 @@ impl Write for BufWriter { if self.buf.len() + total_len > self.buf.capacity() { self.flush_buf()?; } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 if total_len >= self.buf.capacity() { self.panicked = true; let r = self.get_mut().write_vectored(bufs); self.panicked = false; r } else { - self.buf.write_vectored(bufs) + bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); + Ok(total_len) } } @@ -709,7 +829,8 @@ impl Seek for BufWriter { /// /// Seeking always writes out the internal buffer before seeking. fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.flush_buf().and_then(|_| self.get_mut().seek(pos)) + self.flush_buf()?; + self.get_mut().seek(pos) } } @@ -816,6 +937,274 @@ impl fmt::Display for IntoInnerError { } } +/// Private helper struct for implementing the line-buffered writing logic. +/// This shim temporarily wraps a BufWriter, and uses its internals to +/// implement a line-buffered writer (specifically by using the internal +/// methods like write_to_buf and flush_buf). In this way, a more +/// efficient abstraction can be created than one that only had access to +/// `write` and `flush`, without needlessly duplicating a lot of the +/// implementation details of BufWriter. This also allows existing +/// `BufWriters` to be temporarily given line-buffering logic; this is what +/// enables Stdout to be alternately in line-buffered or block-buffered mode. +#[derive(Debug)] +pub(super) struct LineWriterShim<'a, W: Write> { + buffer: &'a mut BufWriter, +} + +impl<'a, W: Write> LineWriterShim<'a, W> { + pub fn new(buffer: &'a mut BufWriter) -> Self { + Self { buffer } + } + + /// Get a mutable reference to the inner writer (that is, the writer + /// wrapped by the BufWriter). Be careful with this writer, as writes to + /// it will bypass the buffer. + fn inner_mut(&mut self) -> &mut W { + self.buffer.get_mut() + } + + /// Get the content currently buffered in self.buffer + fn buffered(&self) -> &[u8] { + self.buffer.buffer() + } + + /// Flush the buffer iff the last byte is a newline (indicating that an + /// earlier write only succeeded partially, and we want to retry flushing + /// the buffered line before continuing with a subsequent write) + fn flush_if_completed_line(&mut self) -> io::Result<()> { + match self.buffered().last().copied() { + Some(b'\n') => self.buffer.flush_buf(), + _ => Ok(()), + } + } +} + +impl<'a, W: Write> Write for LineWriterShim<'a, W> { + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. Returns the number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. If that write only reports a partial + /// success, the remaining data will be buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it ends with a + /// newline, even if the incoming data does not contain any newlines. + fn write(&mut self, buf: &[u8]) -> io::Result { + let newline_idx = match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + return self.buffer.write(buf); + } + // Otherwise, arrange for the lines to be written directly to the + // inner writer. + Some(newline_idx) => newline_idx + 1, + }; + + // Flush existing content to prepare for our write. We have to do this + // before attempting to write `buf` in order to maintain consistency; + // if we add `buf` to the buffer then try to flush it all at once, + // we're obligated to return Ok(), which would mean suppressing any + // errors that occur during flush. + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let lines = &buf[..newline_idx]; + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.buffer.panicked here. + let flushed = self.inner_mut().write(lines)?; + + // If buffer returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Now that the write has succeeded, buffer the rest (or as much of + // the rest as possible). If there were any unwritten newlines, we + // only buffer out to the last unwritten newline that fits in the + // buffer; this helps prevent flushing partial lines on subsequent + // calls to LineWriterShim::write. + + // Handle the cases in order of most-common to least-common, under + // the presumption that most writes succeed in totality, and that most + // writes are smaller than the buffer. + // - Is this a partial line (ie, no newlines left in the unwritten tail) + // - If not, does the data out to the last unwritten newline fit in + // the buffer? + // - If not, scan for the last newline that *does* fit in the buffer + let tail = if flushed >= newline_idx { + &buf[flushed..] + } else if newline_idx - flushed <= self.buffer.capacity() { + &buf[flushed..newline_idx] + } else { + let scan_area = &buf[flushed..]; + let scan_area = &scan_area[..self.buffer.capacity()]; + match memchr::memrchr(b'\n', scan_area) { + Some(newline_idx) => &scan_area[..newline_idx + 1], + None => scan_area, + } + }; + + let buffered = self.buffer.write_to_buf(tail); + Ok(flushed + buffered) + } + + fn flush(&mut self) -> io::Result<()> { + self.buffer.flush() + } + + /// Write some vectored data into this BufReader with line buffering. This + /// means that, if any newlines are present in the data, the data up to + /// and including the buffer containing the last newline is sent directly + /// to the inner writer, and the data after it is buffered. Returns the + /// number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines. + /// + /// Because sorting through an array of `IoSlice` can be a bit convoluted, + /// This method differs from write in the following ways: + /// + /// - It attempts to write the full content of all the buffers up to and + /// including the one containing the last newline. This means that it + /// may attempt to write a partial line, that buffer has data past the + /// newline. + /// - If the write only reports partial success, it does not attempt to + /// find the precise location of the written bytes and buffer the rest. + /// + /// If the underlying vector doesn't support vectored writing, we instead + /// simply write the first non-empty buffer with `write`. This way, we + /// get the benefits of more granular partial-line handling without losing + /// anything in efficiency + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + // If there's no specialized behavior for write_vectored, just use + // write. This has the benefit of more granular partial-line handling. + if !self.is_write_vectored() { + return match bufs.iter().find(|buf| !buf.is_empty()) { + Some(buf) => self.write(buf), + None => Ok(0), + }; + } + + // Find the buffer containing the last newline + let last_newline_buf_idx = bufs + .iter() + .enumerate() + .rev() + .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); + + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write + let last_newline_buf_idx = match last_newline_buf_idx { + // No newlines; just do a normal buffered write + None => { + self.flush_if_completed_line()?; + return self.buffer.write_vectored(bufs); + } + Some(i) => i, + }; + + // Flush existing content to prepare for our write + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.panicked here. + let flushed = self.inner_mut().write_vectored(lines)?; + + // If inner returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Don't try to reconstruct the exact amount written; just bail + // in the event of a partial write + let lines_len = lines.iter().map(|buf| buf.len()).sum(); + if flushed < lines_len { + return Ok(flushed); + } + + // Now that the write has succeeded, buffer the rest (or as much of the + // rest as possible) + let buffered: usize = tail + .iter() + .filter(|buf| !buf.is_empty()) + .map(|buf| self.buffer.write_to_buf(buf)) + .take_while(|&n| n > 0) + .sum(); + + Ok(flushed + buffered) + } + + fn is_write_vectored(&self) -> bool { + self.buffer.is_write_vectored() + } + + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines, even if the incoming data does not contain any newlines. + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + self.buffer.write_all(buf) + } + Some(newline_idx) => { + let (lines, tail) = buf.split_at(newline_idx + 1); + + if self.buffered().is_empty() { + self.inner_mut().write_all(lines)?; + } else { + // If there is any buffered data, we add the incoming lines + // to that buffer before flushing, which saves us at least + // one write call. We can't really do this with `write`, + // since we can't do this *and* not suppress errors *and* + // report a consistent state to the caller in a return + // value, but here in write_all it's fine. + self.buffer.write_all(lines)?; + self.buffer.flush_buf()?; + } + + self.buffer.write_all(tail) + } + } + } +} + /// Wraps a writer and buffers output to it, flushing whenever a newline /// (`0x0a`, `'\n'`) is detected. /// @@ -881,7 +1270,6 @@ impl fmt::Display for IntoInnerError { #[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter { inner: BufWriter, - need_flush: bool, } impl LineWriter { @@ -922,7 +1310,7 @@ impl LineWriter { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: W) -> LineWriter { - LineWriter { inner: BufWriter::with_capacity(capacity, inner), need_flush: false } + LineWriter { inner: BufWriter::with_capacity(capacity, inner) } } /// Gets a reference to the underlying writer. @@ -996,110 +1384,40 @@ impl LineWriter { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result>> { - self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { - IntoInnerError(LineWriter { inner: buf, need_flush: false }, e) - }) + self.inner + .into_inner() + .map_err(|IntoInnerError(buf, e)| IntoInnerError(LineWriter { inner: buf }, e)) } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for LineWriter { fn write(&mut self, buf: &[u8]) -> io::Result { - if self.need_flush { - self.flush()?; - } - - // Find the last newline character in the buffer provided. If found then - // we're going to write all the data up to that point and then flush, - // otherwise we just write the whole block to the underlying writer. - let i = match memchr::memrchr(b'\n', buf) { - Some(i) => i, - None => return self.inner.write(buf), - }; - - // Ok, we're going to write a partial amount of the data given first - // followed by flushing the newline. After we've successfully written - // some data then we *must* report that we wrote that data, so future - // errors are ignored. We set our internal `need_flush` flag, though, in - // case flushing fails and we need to try it first next time. - let n = self.inner.write(&buf[..=i])?; - self.need_flush = true; - if self.flush().is_err() || n != i + 1 { - return Ok(n); - } + LineWriterShim::new(&mut self.inner).write(buf) + } - // At this point we successfully wrote `i + 1` bytes and flushed it out, - // meaning that the entire line is now flushed out on the screen. While - // we can attempt to finish writing the rest of the data provided. - // Remember though that we ignore errors here as we've successfully - // written data, so we need to report that. - match self.inner.write(&buf[i + 1..]) { - Ok(i) => Ok(n + i), - Err(_) => Ok(n), - } + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() } - // Vectored writes are very similar to the writes above, but adjusted for - // the list of buffers that we have to write. fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - if self.need_flush { - self.flush()?; - } + LineWriterShim::new(&mut self.inner).write_vectored(bufs) + } - // Find the last newline, and failing that write the whole buffer - let last_newline = bufs.iter().enumerate().rev().find_map(|(i, buf)| { - let pos = memchr::memrchr(b'\n', buf)?; - Some((i, pos)) - }); - let (i, j) = match last_newline { - Some(pair) => pair, - None => return self.inner.write_vectored(bufs), - }; - let (prefix, suffix) = bufs.split_at(i); - let (buf, suffix) = suffix.split_at(1); - let buf = &buf[0]; - - // Write everything up to the last newline, flushing afterwards. Note - // that only if we finished our entire `write_vectored` do we try the - // subsequent - // `write` - let mut n = 0; - let prefix_amt = prefix.iter().map(|i| i.len()).sum(); - if prefix_amt > 0 { - n += self.inner.write_vectored(prefix)?; - self.need_flush = true; - } - if n == prefix_amt { - match self.inner.write(&buf[..=j]) { - Ok(m) => n += m, - Err(e) if n == 0 => return Err(e), - Err(_) => return Ok(n), - } - self.need_flush = true; - } - if self.flush().is_err() || n != j + 1 + prefix_amt { - return Ok(n); - } + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } - // ... and now write out everything remaining - match self.inner.write(&buf[j + 1..]) { - Ok(i) => n += i, - Err(_) => return Ok(n), - } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all(buf) + } - if suffix.iter().map(|s| s.len()).sum::() == 0 { - return Ok(n); - } - match self.inner.write_vectored(suffix) { - Ok(i) => Ok(n + i), - Err(_) => Ok(n), - } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all_vectored(bufs) } - fn flush(&mut self) -> io::Result<()> { - self.inner.flush()?; - self.need_flush = false; - Ok(()) + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_fmt(fmt) } } @@ -1118,584 +1436,3 @@ where .finish() } } - -#[cfg(test)] -mod tests { - use crate::io::prelude::*; - use crate::io::{self, BufReader, BufWriter, IoSlice, LineWriter, SeekFrom}; - use crate::sync::atomic::{AtomicUsize, Ordering}; - use crate::thread; - - /// A dummy reader intended at testing short-reads propagation. - pub struct ShortReader { - lengths: Vec, - } - - impl Read for ShortReader { - fn read(&mut self, _: &mut [u8]) -> io::Result { - if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) } - } - } - - #[test] - fn test_buffered_reader() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, inner); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 3); - assert_eq!(buf, [5, 6, 7]); - assert_eq!(reader.buffer(), []); - - let mut buf = [0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 2); - assert_eq!(buf, [0, 1]); - assert_eq!(reader.buffer(), []); - - let mut buf = [0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - assert_eq!(buf, [2]); - assert_eq!(reader.buffer(), [3]); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - assert_eq!(buf, [3, 0, 0]); - assert_eq!(reader.buffer(), []); - - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - assert_eq!(buf, [4, 0, 0]); - assert_eq!(reader.buffer(), []); - - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_buffered_reader_seek() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); - - assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); - assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); - reader.consume(1); - assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); - } - - #[test] - fn test_buffered_reader_seek_relative() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); - - assert!(reader.seek_relative(3).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert!(reader.seek_relative(0).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert!(reader.seek_relative(1).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[1][..])); - assert!(reader.seek_relative(-1).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert!(reader.seek_relative(2).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..])); - } - - #[test] - fn test_buffered_reader_invalidated_after_read() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); - - assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); - reader.consume(3); - - let mut buffer = [0, 0, 0, 0, 0]; - assert_eq!(reader.read(&mut buffer).ok(), Some(5)); - assert_eq!(buffer, [0, 1, 2, 3, 4]); - - assert!(reader.seek_relative(-2).is_ok()); - let mut buffer = [0, 0]; - assert_eq!(reader.read(&mut buffer).ok(), Some(2)); - assert_eq!(buffer, [3, 4]); - } - - #[test] - fn test_buffered_reader_invalidated_after_seek() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); - - assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); - reader.consume(3); - - assert!(reader.seek(SeekFrom::Current(5)).is_ok()); - - assert!(reader.seek_relative(-2).is_ok()); - let mut buffer = [0, 0]; - assert_eq!(reader.read(&mut buffer).ok(), Some(2)); - assert_eq!(buffer, [3, 4]); - } - - #[test] - fn test_buffered_reader_seek_underflow() { - // gimmick reader that yields its position modulo 256 for each byte - struct PositionReader { - pos: u64, - } - impl Read for PositionReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let len = buf.len(); - for x in buf { - *x = self.pos as u8; - self.pos = self.pos.wrapping_add(1); - } - Ok(len) - } - } - impl Seek for PositionReader { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - match pos { - SeekFrom::Start(n) => { - self.pos = n; - } - SeekFrom::Current(n) => { - self.pos = self.pos.wrapping_add(n as u64); - } - SeekFrom::End(n) => { - self.pos = u64::MAX.wrapping_add(n as u64); - } - } - Ok(self.pos) - } - } - - let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); - assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5)); - assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); - // the following seek will require two underlying seeks - let expected = 9223372036854775802; - assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected)); - assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); - // seeking to 0 should empty the buffer. - assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); - assert_eq!(reader.get_ref().pos, expected); - } - - #[test] - fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() { - // gimmick reader that returns Err after first seek - struct ErrAfterFirstSeekReader { - first_seek: bool, - } - impl Read for ErrAfterFirstSeekReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - for x in &mut *buf { - *x = 0; - } - Ok(buf.len()) - } - } - impl Seek for ErrAfterFirstSeekReader { - fn seek(&mut self, _: SeekFrom) -> io::Result { - if self.first_seek { - self.first_seek = false; - Ok(0) - } else { - Err(io::Error::new(io::ErrorKind::Other, "oh no!")) - } - } - } - - let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true }); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..])); - - // The following seek will require two underlying seeks. The first will - // succeed but the second will fail. This should still invalidate the - // buffer. - assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err()); - assert_eq!(reader.buffer().len(), 0); - } - - #[test] - fn test_buffered_writer() { - let inner = Vec::new(); - let mut writer = BufWriter::with_capacity(2, inner); - - writer.write(&[0, 1]).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.write(&[2]).unwrap(); - assert_eq!(writer.buffer(), [2]); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.write(&[3]).unwrap(); - assert_eq!(writer.buffer(), [2, 3]); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.flush().unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - writer.write(&[4]).unwrap(); - writer.write(&[5]).unwrap(); - assert_eq!(writer.buffer(), [4, 5]); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - writer.write(&[6]).unwrap(); - assert_eq!(writer.buffer(), [6]); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); - - writer.write(&[7, 8]).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); - - writer.write(&[9, 10, 11]).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - - writer.flush().unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - } - - #[test] - fn test_buffered_writer_inner_flushes() { - let mut w = BufWriter::with_capacity(3, Vec::new()); - w.write(&[0, 1]).unwrap(); - assert_eq!(*w.get_ref(), []); - let w = w.into_inner().unwrap(); - assert_eq!(w, [0, 1]); - } - - #[test] - fn test_buffered_writer_seek() { - let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); - w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); - w.write_all(&[6, 7]).unwrap(); - assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); - assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); - assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); - w.write_all(&[8, 9]).unwrap(); - assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); - } - - #[test] - fn test_read_until() { - let inner: &[u8] = &[0, 1, 2, 1, 0]; - let mut reader = BufReader::with_capacity(2, inner); - let mut v = Vec::new(); - reader.read_until(0, &mut v).unwrap(); - assert_eq!(v, [0]); - v.truncate(0); - reader.read_until(2, &mut v).unwrap(); - assert_eq!(v, [1, 2]); - v.truncate(0); - reader.read_until(1, &mut v).unwrap(); - assert_eq!(v, [1]); - v.truncate(0); - reader.read_until(8, &mut v).unwrap(); - assert_eq!(v, [0]); - v.truncate(0); - reader.read_until(9, &mut v).unwrap(); - assert_eq!(v, []); - } - - #[test] - fn test_line_buffer_fail_flush() { - // Issue #32085 - struct FailFlushWriter<'a>(&'a mut Vec); - - impl Write for FailFlushWriter<'_> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.extend_from_slice(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::new(io::ErrorKind::Other, "flush failed")) - } - } - - let mut buf = Vec::new(); - { - let mut writer = LineWriter::new(FailFlushWriter(&mut buf)); - let to_write = b"abc\ndef"; - if let Ok(written) = writer.write(to_write) { - assert!(written < to_write.len(), "didn't flush on new line"); - // PASS - return; - } - } - assert!(buf.is_empty(), "write returned an error but wrote data"); - } - - #[test] - fn test_line_buffer() { - let mut writer = LineWriter::new(Vec::new()); - writer.write(&[0]).unwrap(); - assert_eq!(*writer.get_ref(), []); - writer.write(&[1]).unwrap(); - assert_eq!(*writer.get_ref(), []); - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); - writer.write(&[3, b'\n']).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); - } - - #[test] - fn test_read_line() { - let in_buf: &[u8] = b"a\nb\nc"; - let mut reader = BufReader::with_capacity(2, in_buf); - let mut s = String::new(); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "a\n"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "b\n"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "c"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, ""); - } - - #[test] - fn test_lines() { - let in_buf: &[u8] = b"a\nb\nc"; - let reader = BufReader::with_capacity(2, in_buf); - let mut it = reader.lines(); - assert_eq!(it.next().unwrap().unwrap(), "a".to_string()); - assert_eq!(it.next().unwrap().unwrap(), "b".to_string()); - assert_eq!(it.next().unwrap().unwrap(), "c".to_string()); - assert!(it.next().is_none()); - } - - #[test] - fn test_short_reads() { - let inner = ShortReader { lengths: vec![0, 1, 2, 0, 1, 0] }; - let mut reader = BufReader::new(inner); - let mut buf = [0, 0]; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.read(&mut buf).unwrap(), 2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - #[should_panic] - fn dont_panic_in_drop_on_panicked_flush() { - struct FailFlushWriter; - - impl Write for FailFlushWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::last_os_error()) - } - } - - let writer = FailFlushWriter; - let _writer = BufWriter::new(writer); - - // If writer panics *again* due to the flush error then the process will - // abort. - panic!(); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn panic_in_write_doesnt_flush_in_drop() { - static WRITES: AtomicUsize = AtomicUsize::new(0); - - struct PanicWriter; - - impl Write for PanicWriter { - fn write(&mut self, _: &[u8]) -> io::Result { - WRITES.fetch_add(1, Ordering::SeqCst); - panic!(); - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - } - - thread::spawn(|| { - let mut writer = BufWriter::new(PanicWriter); - let _ = writer.write(b"hello world"); - let _ = writer.flush(); - }) - .join() - .unwrap_err(); - - assert_eq!(WRITES.load(Ordering::SeqCst), 1); - } - - #[bench] - fn bench_buffered_reader(b: &mut test::Bencher) { - b.iter(|| BufReader::new(io::empty())); - } - - #[bench] - fn bench_buffered_writer(b: &mut test::Bencher) { - b.iter(|| BufWriter::new(io::sink())); - } - - struct AcceptOneThenFail { - written: bool, - flushed: bool, - } - - impl Write for AcceptOneThenFail { - fn write(&mut self, data: &[u8]) -> io::Result { - if !self.written { - assert_eq!(data, b"a\nb\n"); - self.written = true; - Ok(data.len()) - } else { - Err(io::Error::new(io::ErrorKind::NotFound, "test")) - } - } - - fn flush(&mut self) -> io::Result<()> { - assert!(self.written); - assert!(!self.flushed); - self.flushed = true; - Err(io::Error::new(io::ErrorKind::Other, "test")) - } - } - - #[test] - fn erroneous_flush_retried() { - let a = AcceptOneThenFail { written: false, flushed: false }; - - let mut l = LineWriter::new(a); - assert_eq!(l.write(b"a\nb\na").unwrap(), 4); - assert!(l.get_ref().written); - assert!(l.get_ref().flushed); - l.get_mut().flushed = false; - - assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other) - } - - #[test] - fn line_vectored() { - let mut a = LineWriter::new(Vec::new()); - assert_eq!( - a.write_vectored(&[ - IoSlice::new(&[]), - IoSlice::new(b"\n"), - IoSlice::new(&[]), - IoSlice::new(b"a"), - ]) - .unwrap(), - 2, - ); - assert_eq!(a.get_ref(), b"\n"); - - assert_eq!( - a.write_vectored(&[ - IoSlice::new(&[]), - IoSlice::new(b"b"), - IoSlice::new(&[]), - IoSlice::new(b"a"), - IoSlice::new(&[]), - IoSlice::new(b"c"), - ]) - .unwrap(), - 3, - ); - assert_eq!(a.get_ref(), b"\n"); - a.flush().unwrap(); - assert_eq!(a.get_ref(), b"\nabac"); - assert_eq!(a.write_vectored(&[]).unwrap(), 0); - assert_eq!( - a.write_vectored(&[ - IoSlice::new(&[]), - IoSlice::new(&[]), - IoSlice::new(&[]), - IoSlice::new(&[]), - ]) - .unwrap(), - 0, - ); - assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3); - assert_eq!(a.get_ref(), b"\nabaca\n"); - } - - #[test] - fn line_vectored_partial_and_errors() { - enum Call { - Write { inputs: Vec<&'static [u8]>, output: io::Result }, - Flush { output: io::Result<()> }, - } - struct Writer { - calls: Vec, - } - - impl Write for Writer { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.write_vectored(&[IoSlice::new(buf)]) - } - - fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result { - match self.calls.pop().unwrap() { - Call::Write { inputs, output } => { - assert_eq!(inputs, buf.iter().map(|b| &**b).collect::>()); - output - } - _ => panic!("unexpected call to write"), - } - } - - fn flush(&mut self) -> io::Result<()> { - match self.calls.pop().unwrap() { - Call::Flush { output } => output, - _ => panic!("unexpected call to flush"), - } - } - } - - impl Drop for Writer { - fn drop(&mut self) { - if !thread::panicking() { - assert_eq!(self.calls.len(), 0); - } - } - } - - // partial writes keep going - let mut a = LineWriter::new(Writer { calls: Vec::new() }); - a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap(); - a.get_mut().calls.push(Call::Flush { output: Ok(()) }); - a.get_mut().calls.push(Call::Write { inputs: vec![b"bcx\n"], output: Ok(4) }); - a.get_mut().calls.push(Call::Write { inputs: vec![b"abcx\n"], output: Ok(1) }); - a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap(); - a.get_mut().calls.push(Call::Flush { output: Ok(()) }); - a.flush().unwrap(); - - // erroneous writes stop and don't write more - a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Err(err()) }); - assert_eq!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).unwrap(), 2); - a.get_mut().calls.push(Call::Flush { output: Ok(()) }); - a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Ok(2) }); - a.flush().unwrap(); - - fn err() -> io::Error { - io::Error::new(io::ErrorKind::Other, "x") - } - } -} diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs new file mode 100644 index 0000000000..66a64f667b --- /dev/null +++ b/library/std/src/io/buffered/tests.rs @@ -0,0 +1,958 @@ +use crate::io::prelude::*; +use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom}; +use crate::panic; +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::thread; + +/// A dummy reader intended at testing short-reads propagation. +pub struct ShortReader { + lengths: Vec, +} + +// FIXME: rustfmt and tidy disagree about the correct formatting of this +// function. This leads to issues for users with editors configured to +// rustfmt-on-save. +impl Read for ShortReader { + fn read(&mut self, _: &mut [u8]) -> io::Result { + if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) } + } +} + +#[test] +fn test_buffered_reader() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, inner); + + let mut buf = [0, 0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 3); + assert_eq!(buf, [5, 6, 7]); + assert_eq!(reader.buffer(), []); + + let mut buf = [0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 2); + assert_eq!(buf, [0, 1]); + assert_eq!(reader.buffer(), []); + + let mut buf = [0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 1); + assert_eq!(buf, [2]); + assert_eq!(reader.buffer(), [3]); + + let mut buf = [0, 0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 1); + assert_eq!(buf, [3, 0, 0]); + assert_eq!(reader.buffer(), []); + + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 1); + assert_eq!(buf, [4, 0, 0]); + assert_eq!(reader.buffer(), []); + + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_buffered_reader_seek() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); + assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); + reader.consume(1); + assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); +} + +#[test] +fn test_buffered_reader_seek_relative() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert!(reader.seek_relative(3).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(0).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(1).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[1][..])); + assert!(reader.seek_relative(-1).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(2).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..])); +} + +#[test] +fn test_buffered_reader_stream_position() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert_eq!(reader.stream_position().ok(), Some(0)); + assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); + assert_eq!(reader.stream_position().ok(), Some(3)); + // relative seeking within the buffer and reading position should keep the buffer + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(0).is_ok()); + assert_eq!(reader.stream_position().ok(), Some(3)); + assert_eq!(reader.buffer(), &[0, 1][..]); + assert!(reader.seek_relative(1).is_ok()); + assert_eq!(reader.stream_position().ok(), Some(4)); + assert_eq!(reader.buffer(), &[1][..]); + assert!(reader.seek_relative(-1).is_ok()); + assert_eq!(reader.stream_position().ok(), Some(3)); + assert_eq!(reader.buffer(), &[0, 1][..]); + // relative seeking outside the buffer will discard it + assert!(reader.seek_relative(2).is_ok()); + assert_eq!(reader.stream_position().ok(), Some(5)); + assert_eq!(reader.buffer(), &[][..]); +} + +#[test] +fn test_buffered_reader_stream_position_panic() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(4, io::Cursor::new(inner)); + + // cause internal buffer to be filled but read only partially + let mut buffer = [0, 0]; + assert!(reader.read_exact(&mut buffer).is_ok()); + // rewinding the internal reader will cause buffer to loose sync + let inner = reader.get_mut(); + assert!(inner.seek(SeekFrom::Start(0)).is_ok()); + // overflow when subtracting the remaining buffer size from current position + let result = panic::catch_unwind(panic::AssertUnwindSafe(|| reader.stream_position().ok())); + assert!(result.is_err()); +} + +#[test] +fn test_buffered_reader_invalidated_after_read() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); + + assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); + reader.consume(3); + + let mut buffer = [0, 0, 0, 0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(5)); + assert_eq!(buffer, [0, 1, 2, 3, 4]); + + assert!(reader.seek_relative(-2).is_ok()); + let mut buffer = [0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(2)); + assert_eq!(buffer, [3, 4]); +} + +#[test] +fn test_buffered_reader_invalidated_after_seek() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); + + assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); + reader.consume(3); + + assert!(reader.seek(SeekFrom::Current(5)).is_ok()); + + assert!(reader.seek_relative(-2).is_ok()); + let mut buffer = [0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(2)); + assert_eq!(buffer, [3, 4]); +} + +#[test] +fn test_buffered_reader_seek_underflow() { + // gimmick reader that yields its position modulo 256 for each byte + struct PositionReader { + pos: u64, + } + impl Read for PositionReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = buf.len(); + for x in buf { + *x = self.pos as u8; + self.pos = self.pos.wrapping_add(1); + } + Ok(len) + } + } + impl Seek for PositionReader { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + match pos { + SeekFrom::Start(n) => { + self.pos = n; + } + SeekFrom::Current(n) => { + self.pos = self.pos.wrapping_add(n as u64); + } + SeekFrom::End(n) => { + self.pos = u64::MAX.wrapping_add(n as u64); + } + } + Ok(self.pos) + } + } + + let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); + assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // the following seek will require two underlying seeks + let expected = 9223372036854775802; + assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // seeking to 0 should empty the buffer. + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); + assert_eq!(reader.get_ref().pos, expected); +} + +#[test] +fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() { + // gimmick reader that returns Err after first seek + struct ErrAfterFirstSeekReader { + first_seek: bool, + } + impl Read for ErrAfterFirstSeekReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + for x in &mut *buf { + *x = 0; + } + Ok(buf.len()) + } + } + impl Seek for ErrAfterFirstSeekReader { + fn seek(&mut self, _: SeekFrom) -> io::Result { + if self.first_seek { + self.first_seek = false; + Ok(0) + } else { + Err(io::Error::new(io::ErrorKind::Other, "oh no!")) + } + } + } + + let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true }); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..])); + + // The following seek will require two underlying seeks. The first will + // succeed but the second will fail. This should still invalidate the + // buffer. + assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err()); + assert_eq!(reader.buffer().len(), 0); +} + +#[test] +fn test_buffered_writer() { + let inner = Vec::new(); + let mut writer = BufWriter::with_capacity(2, inner); + + writer.write(&[0, 1]).unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.write(&[2]).unwrap(); + assert_eq!(writer.buffer(), [2]); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.write(&[3]).unwrap(); + assert_eq!(writer.buffer(), [2, 3]); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.flush().unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + + writer.write(&[4]).unwrap(); + writer.write(&[5]).unwrap(); + assert_eq!(writer.buffer(), [4, 5]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + + writer.write(&[6]).unwrap(); + assert_eq!(writer.buffer(), [6]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); + + writer.write(&[7, 8]).unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); + + writer.write(&[9, 10, 11]).unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + + writer.flush().unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); +} + +#[test] +fn test_buffered_writer_inner_flushes() { + let mut w = BufWriter::with_capacity(3, Vec::new()); + w.write(&[0, 1]).unwrap(); + assert_eq!(*w.get_ref(), []); + let w = w.into_inner().unwrap(); + assert_eq!(w, [0, 1]); +} + +#[test] +fn test_buffered_writer_seek() { + let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); + w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); + w.write_all(&[6, 7]).unwrap(); + assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); + assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); + assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); + w.write_all(&[8, 9]).unwrap(); + assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); +} + +#[test] +fn test_read_until() { + let inner: &[u8] = &[0, 1, 2, 1, 0]; + let mut reader = BufReader::with_capacity(2, inner); + let mut v = Vec::new(); + reader.read_until(0, &mut v).unwrap(); + assert_eq!(v, [0]); + v.truncate(0); + reader.read_until(2, &mut v).unwrap(); + assert_eq!(v, [1, 2]); + v.truncate(0); + reader.read_until(1, &mut v).unwrap(); + assert_eq!(v, [1]); + v.truncate(0); + reader.read_until(8, &mut v).unwrap(); + assert_eq!(v, [0]); + v.truncate(0); + reader.read_until(9, &mut v).unwrap(); + assert_eq!(v, []); +} + +#[test] +fn test_line_buffer() { + let mut writer = LineWriter::new(Vec::new()); + writer.write(&[0]).unwrap(); + assert_eq!(*writer.get_ref(), []); + writer.write(&[1]).unwrap(); + assert_eq!(*writer.get_ref(), []); + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); + writer.write(&[3, b'\n']).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); +} + +#[test] +fn test_read_line() { + let in_buf: &[u8] = b"a\nb\nc"; + let mut reader = BufReader::with_capacity(2, in_buf); + let mut s = String::new(); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "a\n"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "b\n"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "c"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, ""); +} + +#[test] +fn test_lines() { + let in_buf: &[u8] = b"a\nb\nc"; + let reader = BufReader::with_capacity(2, in_buf); + let mut it = reader.lines(); + assert_eq!(it.next().unwrap().unwrap(), "a".to_string()); + assert_eq!(it.next().unwrap().unwrap(), "b".to_string()); + assert_eq!(it.next().unwrap().unwrap(), "c".to_string()); + assert!(it.next().is_none()); +} + +#[test] +fn test_short_reads() { + let inner = ShortReader { lengths: vec![0, 1, 2, 0, 1, 0] }; + let mut reader = BufReader::new(inner); + let mut buf = [0, 0]; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +#[should_panic] +fn dont_panic_in_drop_on_panicked_flush() { + struct FailFlushWriter; + + impl Write for FailFlushWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { + Err(io::Error::last_os_error()) + } + } + + let writer = FailFlushWriter; + let _writer = BufWriter::new(writer); + + // If writer panics *again* due to the flush error then the process will + // abort. + panic!(); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn panic_in_write_doesnt_flush_in_drop() { + static WRITES: AtomicUsize = AtomicUsize::new(0); + + struct PanicWriter; + + impl Write for PanicWriter { + fn write(&mut self, _: &[u8]) -> io::Result { + WRITES.fetch_add(1, Ordering::SeqCst); + panic!(); + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + thread::spawn(|| { + let mut writer = BufWriter::new(PanicWriter); + let _ = writer.write(b"hello world"); + let _ = writer.flush(); + }) + .join() + .unwrap_err(); + + assert_eq!(WRITES.load(Ordering::SeqCst), 1); +} + +#[bench] +fn bench_buffered_reader(b: &mut test::Bencher) { + b.iter(|| BufReader::new(io::empty())); +} + +#[bench] +fn bench_buffered_writer(b: &mut test::Bencher) { + b.iter(|| BufWriter::new(io::sink())); +} + +/// A simple `Write` target, designed to be wrapped by `LineWriter` / +/// `BufWriter` / etc, that can have its `write` & `flush` behavior +/// configured +#[derive(Default, Clone)] +struct ProgrammableSink { + // Writes append to this slice + pub buffer: Vec, + + // Flush sets this flag + pub flushed: bool, + + // If true, writes will always be an error + pub always_write_error: bool, + + // If true, flushes will always be an error + pub always_flush_error: bool, + + // If set, only up to this number of bytes will be written in a single + // call to `write` + pub accept_prefix: Option, + + // If set, counts down with each write, and writes return an error + // when it hits 0 + pub max_writes: Option, + + // If set, attempting to write when max_writes == Some(0) will be an + // error; otherwise, it will return Ok(0). + pub error_after_max_writes: bool, +} + +impl Write for ProgrammableSink { + fn write(&mut self, data: &[u8]) -> io::Result { + if self.always_write_error { + return Err(io::Error::new(io::ErrorKind::Other, "test - always_write_error")); + } + + match self.max_writes { + Some(0) if self.error_after_max_writes => { + return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes")); + } + Some(0) => return Ok(0), + Some(ref mut count) => *count -= 1, + None => {} + } + + let len = match self.accept_prefix { + None => data.len(), + Some(prefix) => data.len().min(prefix), + }; + + let data = &data[..len]; + self.buffer.extend_from_slice(data); + + Ok(len) + } + + fn flush(&mut self) -> io::Result<()> { + if self.always_flush_error { + Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error")) + } else { + self.flushed = true; + Ok(()) + } + } +} + +/// Previously the `LineWriter` could successfully write some bytes but +/// then fail to report that it has done so. Additionally, an erroneous +/// flush after a successful write was permanently ignored. +/// +/// Test that a line writer correctly reports the number of written bytes, +/// and that it attempts to flush buffered lines from previous writes +/// before processing new data +/// +/// Regression test for #37807 +#[test] +fn erroneous_flush_retried() { + let writer = ProgrammableSink { + // Only write up to 4 bytes at a time + accept_prefix: Some(4), + + // Accept the first two writes, then error the others + max_writes: Some(2), + error_after_max_writes: true, + + ..Default::default() + }; + + // This should write the first 4 bytes. The rest will be buffered, out + // to the last newline. + let mut writer = LineWriter::new(writer); + assert_eq!(writer.write(b"a\nb\nc\nd\ne").unwrap(), 8); + + // This write should attempt to flush "c\nd\n", then buffer "e". No + // errors should happen here because no further writes should be + // attempted against `writer`. + assert_eq!(writer.write(b"e").unwrap(), 1); + assert_eq!(&writer.get_ref().buffer, b"a\nb\nc\nd\n"); +} + +#[test] +fn line_vectored() { + let mut a = LineWriter::new(Vec::new()); + assert_eq!( + a.write_vectored(&[ + IoSlice::new(&[]), + IoSlice::new(b"\n"), + IoSlice::new(&[]), + IoSlice::new(b"a"), + ]) + .unwrap(), + 2, + ); + assert_eq!(a.get_ref(), b"\n"); + + assert_eq!( + a.write_vectored(&[ + IoSlice::new(&[]), + IoSlice::new(b"b"), + IoSlice::new(&[]), + IoSlice::new(b"a"), + IoSlice::new(&[]), + IoSlice::new(b"c"), + ]) + .unwrap(), + 3, + ); + assert_eq!(a.get_ref(), b"\n"); + a.flush().unwrap(); + assert_eq!(a.get_ref(), b"\nabac"); + assert_eq!(a.write_vectored(&[]).unwrap(), 0); + assert_eq!( + a.write_vectored(&[ + IoSlice::new(&[]), + IoSlice::new(&[]), + IoSlice::new(&[]), + IoSlice::new(&[]), + ]) + .unwrap(), + 0, + ); + assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3); + assert_eq!(a.get_ref(), b"\nabaca\nb"); +} + +#[test] +fn line_vectored_partial_and_errors() { + use crate::collections::VecDeque; + + enum Call { + Write { inputs: Vec<&'static [u8]>, output: io::Result }, + Flush { output: io::Result<()> }, + } + + #[derive(Default)] + struct Writer { + calls: VecDeque, + } + + impl Write for Writer { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.write_vectored(&[IoSlice::new(buf)]) + } + + fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result { + match self.calls.pop_front().expect("unexpected call to write") { + Call::Write { inputs, output } => { + assert_eq!(inputs, buf.iter().map(|b| &**b).collect::>()); + output + } + Call::Flush { .. } => panic!("unexpected call to write; expected a flush"), + } + } + + fn is_write_vectored(&self) -> bool { + true + } + + fn flush(&mut self) -> io::Result<()> { + match self.calls.pop_front().expect("Unexpected call to flush") { + Call::Flush { output } => output, + Call::Write { .. } => panic!("unexpected call to flush; expected a write"), + } + } + } + + impl Drop for Writer { + fn drop(&mut self) { + if !thread::panicking() { + assert_eq!(self.calls.len(), 0); + } + } + } + + // partial writes keep going + let mut a = LineWriter::new(Writer::default()); + a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap(); + + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"abc"], output: Ok(1) }); + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"bc"], output: Ok(2) }); + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\n"], output: Ok(2) }); + + a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap(); + + a.get_mut().calls.push_back(Call::Flush { output: Ok(()) }); + a.flush().unwrap(); + + // erroneous writes stop and don't write more + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\na"], output: Err(err()) }); + a.get_mut().calls.push_back(Call::Flush { output: Ok(()) }); + assert!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).is_err()); + a.flush().unwrap(); + + fn err() -> io::Error { + io::Error::new(io::ErrorKind::Other, "x") + } +} + +/// Test that, in cases where vectored writing is not enabled, the +/// LineWriter uses the normal `write` call, which more-correctly handles +/// partial lines +#[test] +fn line_vectored_ignored() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::new(writer); + + let content = [ + IoSlice::new(&[]), + IoSlice::new(b"Line 1\nLine"), + IoSlice::new(b" 2\nLine 3\nL"), + IoSlice::new(&[]), + IoSlice::new(&[]), + IoSlice::new(b"ine 4"), + IoSlice::new(b"\nLine 5\n"), + ]; + + let count = writer.write_vectored(&content).unwrap(); + assert_eq!(count, 11); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + let count = writer.write_vectored(&content[2..]).unwrap(); + assert_eq!(count, 11); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); + + let count = writer.write_vectored(&content[5..]).unwrap(); + assert_eq!(count, 5); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); + + let count = writer.write_vectored(&content[6..]).unwrap(); + assert_eq!(count, 8); + assert_eq!( + writer.get_ref().buffer.as_slice(), + b"Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n".as_ref() + ); +} + +/// Test that, given this input: +/// +/// Line 1\n +/// Line 2\n +/// Line 3\n +/// Line 4 +/// +/// And given a result that only writes to midway through Line 2 +/// +/// That only up to the end of Line 3 is buffered +/// +/// This behavior is desirable because it prevents flushing partial lines +#[test] +fn partial_write_buffers_line() { + let writer = ProgrammableSink { accept_prefix: Some(13), ..Default::default() }; + let mut writer = LineWriter::new(writer); + + assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3\nLine4").unwrap(), 21); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2"); + + assert_eq!(writer.write(b"Line 4").unwrap(), 6); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); +} + +/// Test that, given this input: +/// +/// Line 1\n +/// Line 2\n +/// Line 3 +/// +/// And given that the full write of lines 1 and 2 was successful +/// That data up to Line 3 is buffered +#[test] +fn partial_line_buffered_after_line_write() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::new(writer); + + assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3").unwrap(), 20); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\n"); + + assert!(writer.flush().is_ok()); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3"); +} + +/// Test that, given a partial line that exceeds the length of +/// LineBuffer's buffer (that is, without a trailing newline), that that +/// line is written to the inner writer +#[test] +fn long_line_flushed() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::with_capacity(5, writer); + + assert_eq!(writer.write(b"0123456789").unwrap(), 10); + assert_eq!(&writer.get_ref().buffer, b"0123456789"); +} + +/// Test that, given a very long partial line *after* successfully +/// flushing a complete line, that that line is buffered unconditionally, +/// and no additional writes take place. This assures the property that +/// `write` should make at-most-one attempt to write new data. +#[test] +fn line_long_tail_not_flushed() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::with_capacity(5, writer); + + // Assert that Line 1\n is flushed, and 01234 is buffered + assert_eq!(writer.write(b"Line 1\n0123456789").unwrap(), 12); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + // Because the buffer is full, this subsequent write will flush it + assert_eq!(writer.write(b"5").unwrap(), 1); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n01234"); +} + +/// Test that, if an attempt to pre-flush buffered data returns Ok(0), +/// this is propagated as an error. +#[test] +fn line_buffer_write0_error() { + let writer = ProgrammableSink { + // Accept one write, then return Ok(0) on subsequent ones + max_writes: Some(1), + + ..Default::default() + }; + let mut writer = LineWriter::new(writer); + + // This should write "Line 1\n" and buffer "Partial" + assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + // This will attempt to flush "partial", which will return Ok(0), which + // needs to be an error, because we've already informed the client + // that we accepted the write. + let err = writer.write(b" Line End\n").unwrap_err(); + assert_eq!(err.kind(), ErrorKind::WriteZero); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); +} + +/// Test that, if a write returns Ok(0) after a successful pre-flush, this +/// is propagated as Ok(0) +#[test] +fn line_buffer_write0_normal() { + let writer = ProgrammableSink { + // Accept two writes, then return Ok(0) on subsequent ones + max_writes: Some(2), + + ..Default::default() + }; + let mut writer = LineWriter::new(writer); + + // This should write "Line 1\n" and buffer "Partial" + assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + // This will flush partial, which will succeed, but then return Ok(0) + // when flushing " Line End\n" + assert_eq!(writer.write(b" Line End\n").unwrap(), 0); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial"); +} + +/// LineWriter has a custom `write_all`; make sure it works correctly +#[test] +fn line_write_all() { + let writer = ProgrammableSink { + // Only write 5 bytes at a time + accept_prefix: Some(5), + ..Default::default() + }; + let mut writer = LineWriter::new(writer); + + writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial").unwrap(); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\nLine 4\n"); + writer.write_all(b" Line 5\n").unwrap(); + assert_eq!( + writer.get_ref().buffer.as_slice(), + b"Line 1\nLine 2\nLine 3\nLine 4\nPartial Line 5\n".as_ref(), + ); +} + +#[test] +fn line_write_all_error() { + let writer = ProgrammableSink { + // Only accept up to 3 writes of up to 5 bytes each + accept_prefix: Some(5), + max_writes: Some(3), + ..Default::default() + }; + + let mut writer = LineWriter::new(writer); + let res = writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial"); + assert!(res.is_err()); + // An error from write_all leaves everything in an indeterminate state, + // so there's nothing else to test here +} + +/// Under certain circumstances, the old implementation of LineWriter +/// would try to buffer "to the last newline" but be forced to buffer +/// less than that, leading to inappropriate partial line writes. +/// Regression test for that issue. +#[test] +fn partial_multiline_buffering() { + let writer = ProgrammableSink { + // Write only up to 5 bytes at a time + accept_prefix: Some(5), + ..Default::default() + }; + + let mut writer = LineWriter::with_capacity(10, writer); + + let content = b"AAAAABBBBB\nCCCCDDDDDD\nEEE"; + + // When content is written, LineWriter will try to write blocks A, B, + // C, and D. Only block A will succeed. Under the old behavior, LineWriter + // would then try to buffer B, C and D, but because its capacity is 10, + // it will only be able to buffer B and C. We don't want to buffer + // partial lines concurrent with whole lines, so the correct behavior + // is to buffer only block B (out to the newline) + assert_eq!(writer.write(content).unwrap(), 11); + assert_eq!(writer.get_ref().buffer, *b"AAAAA"); + + writer.flush().unwrap(); + assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB\n"); +} + +/// Same as test_partial_multiline_buffering, but in the event NO full lines +/// fit in the buffer, just buffer as much as possible +#[test] +fn partial_multiline_buffering_without_full_line() { + let writer = ProgrammableSink { + // Write only up to 5 bytes at a time + accept_prefix: Some(5), + ..Default::default() + }; + + let mut writer = LineWriter::with_capacity(5, writer); + + let content = b"AAAAABBBBBBBBBB\nCCCCC\nDDDDD"; + + // When content is written, LineWriter will try to write blocks A, B, + // and C. Only block A will succeed. Under the old behavior, LineWriter + // would then try to buffer B and C, but because its capacity is 5, + // it will only be able to buffer part of B. Because it's not possible + // for it to buffer any complete lines, it should buffer as much of B as + // possible + assert_eq!(writer.write(content).unwrap(), 10); + assert_eq!(writer.get_ref().buffer, *b"AAAAA"); + + writer.flush().unwrap(); + assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB"); +} + +#[derive(Debug, Clone, PartialEq, Eq)] +enum RecordedEvent { + Write(String), + Flush, +} + +#[derive(Debug, Clone, Default)] +struct WriteRecorder { + pub events: Vec, +} + +impl Write for WriteRecorder { + fn write(&mut self, buf: &[u8]) -> io::Result { + use crate::str::from_utf8; + + self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string())); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + self.events.push(RecordedEvent::Flush); + Ok(()) + } +} + +/// Test that a normal, formatted writeln only results in a single write +/// call to the underlying writer. A naive implementation of +/// LineWriter::write_all results in two writes: one of the buffered data, +/// and another of the final substring in the formatted set +#[test] +fn single_formatted_write() { + let writer = WriteRecorder::default(); + let mut writer = LineWriter::new(writer); + + // Under a naive implementation of LineWriter, this will result in two + // writes: "hello, world" and "!\n", because write() has to flush the + // buffer before attempting to write the last "!\n". write_all shouldn't + // have this limitation. + writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap(); + assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]); +} diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 58343f66f3..5733735dc4 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::io::prelude::*; use crate::cmp; @@ -447,531 +450,3 @@ impl Write for Cursor> { Ok(()) } } - -#[cfg(test)] -mod tests { - use crate::io::prelude::*; - use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom}; - - #[test] - fn test_vec_writer() { - let mut writer = Vec::new(); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) - .unwrap(), - 3 - ); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(writer, b); - } - - #[test] - fn test_mem_writer() { - let mut writer = Cursor::new(Vec::new()); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) - .unwrap(), - 3 - ); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn test_mem_mut_writer() { - let mut vec = Vec::new(); - let mut writer = Cursor::new(&mut vec); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) - .unwrap(), - 3 - ); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn test_box_slice_writer() { - let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write(&[8, 9]).unwrap(), 1); - assert_eq!(writer.write(&[10]).unwrap(), 0); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(&**writer.get_ref(), b); - } - - #[test] - fn test_box_slice_writer_vectored() { - let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7]),]) - .unwrap(), - 7, - ); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write_vectored(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(&**writer.get_ref(), b); - } - - #[test] - fn test_buf_writer() { - let mut buf = [0 as u8; 9]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write(&[8, 9]).unwrap(), 1); - assert_eq!(writer.write(&[10]).unwrap(), 0); - } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_vectored() { - let mut buf = [0 as u8; 9]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],) - .unwrap(), - 7, - ); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write_vectored(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); - } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_seek() { - let mut buf = [0 as u8; 8]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[1]).unwrap(), 1); - assert_eq!(writer.position(), 1); - - assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2); - assert_eq!(writer.position(), 2); - assert_eq!(writer.write(&[2]).unwrap(), 1); - assert_eq!(writer.position(), 3); - - assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[3]).unwrap(), 1); - assert_eq!(writer.position(), 2); - - assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); - assert_eq!(writer.position(), 7); - assert_eq!(writer.write(&[4]).unwrap(), 1); - assert_eq!(writer.position(), 8); - } - let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_error() { - let mut buf = [0 as u8; 2]; - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[0, 0]).unwrap(), 1); - assert_eq!(writer.write(&[0, 0]).unwrap(), 0); - } - - #[test] - fn test_mem_reader() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_mem_reader_vectored() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); - let mut buf = []; - assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]) - .unwrap(), - 1, - ); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf1 = [0; 4]; - let mut buf2 = [0; 4]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),]) - .unwrap(), - 7, - ); - let b1: &[_] = &[1, 2, 3, 4]; - let b2: &[_] = &[5, 6, 7]; - assert_eq!(buf1, b1); - assert_eq!(&buf2[..3], b2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_boxed_slice_reader() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_boxed_slice_reader_vectored() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); - let mut buf = []; - assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]) - .unwrap(), - 1, - ); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf1 = [0; 4]; - let mut buf2 = [0; 4]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) - .unwrap(), - 7, - ); - let b1: &[_] = &[1, 2, 3, 4]; - let b2: &[_] = &[5, 6, 7]; - assert_eq!(buf1, b1); - assert_eq!(&buf2[..3], b2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn read_to_end() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); - let mut v = Vec::new(); - reader.read_to_end(&mut v).unwrap(); - assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); - } - - #[test] - fn test_slice_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let reader = &mut &in_buf[..]; - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.len(), 7); - let b: &[_] = &[0]; - assert_eq!(&buf[..], b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.len(), 3); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(&buf[..], b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_slice_reader_vectored() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let reader = &mut &in_buf[..]; - let mut buf = []; - assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); - let mut buf = [0]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]) - .unwrap(), - 1, - ); - assert_eq!(reader.len(), 7); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf1 = [0; 4]; - let mut buf2 = [0; 4]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) - .unwrap(), - 7, - ); - let b1: &[_] = &[1, 2, 3, 4]; - let b2: &[_] = &[5, 6, 7]; - assert_eq!(buf1, b1); - assert_eq!(&buf2[..3], b2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_read_exact() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let reader = &mut &in_buf[..]; - let mut buf = []; - assert!(reader.read_exact(&mut buf).is_ok()); - let mut buf = [8]; - assert!(reader.read_exact(&mut buf).is_ok()); - assert_eq!(buf[0], 0); - assert_eq!(reader.len(), 7); - let mut buf = [0, 0, 0, 0, 0, 0, 0]; - assert!(reader.read_exact(&mut buf).is_ok()); - assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]); - assert_eq!(reader.len(), 0); - let mut buf = [0]; - assert!(reader.read_exact(&mut buf).is_err()); - } - - #[test] - fn test_buf_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = Cursor::new(&in_buf[..]); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn seek_past_end() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.read(&mut [0]).unwrap(), 0); - - let mut r = Cursor::new(vec![10]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.read(&mut [0]).unwrap(), 0); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 0); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 0); - } - - #[test] - fn seek_past_i64() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - - let mut r = Cursor::new(vec![10]); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - } - - #[test] - fn seek_before_0() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut r = Cursor::new(vec![10]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - } - - #[test] - fn test_seekable_mem_writer() { - let mut writer = Cursor::new(Vec::::new()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[3, 4]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3); - assert_eq!(writer.write(&[0, 1]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); - assert_eq!(writer.write(&[1, 2]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10); - assert_eq!(writer.write(&[1]).unwrap(), 1); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn vec_seek_past_end() { - let mut r = Cursor::new(Vec::new()); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 1); - } - - #[test] - fn vec_seek_before_0() { - let mut r = Cursor::new(Vec::new()); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - } - - #[test] - #[cfg(target_pointer_width = "32")] - fn vec_seek_and_write_past_usize_max() { - let mut c = Cursor::new(Vec::new()); - c.set_position(usize::MAX as u64 + 1); - assert!(c.write_all(&[1, 2, 3]).is_err()); - } - - #[test] - fn test_partial_eq() { - assert_eq!(Cursor::new(Vec::::new()), Cursor::new(Vec::::new())); - } - - #[test] - fn test_eq() { - struct AssertEq(pub T); - - let _: AssertEq>> = AssertEq(Cursor::new(Vec::new())); - } -} diff --git a/library/std/src/io/cursor/tests.rs b/library/std/src/io/cursor/tests.rs new file mode 100644 index 0000000000..80d88ca66f --- /dev/null +++ b/library/std/src/io/cursor/tests.rs @@ -0,0 +1,516 @@ +use crate::io::prelude::*; +use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom}; + +#[test] +fn test_vec_writer() { + let mut writer = Vec::new(); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!( + writer + .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) + .unwrap(), + 3 + ); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(writer, b); +} + +#[test] +fn test_mem_writer() { + let mut writer = Cursor::new(Vec::new()); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!( + writer + .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) + .unwrap(), + 3 + ); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(&writer.get_ref()[..], b); +} + +#[test] +fn test_mem_mut_writer() { + let mut vec = Vec::new(); + let mut writer = Cursor::new(&mut vec); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!( + writer + .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) + .unwrap(), + 3 + ); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(&writer.get_ref()[..], b); +} + +#[test] +fn test_box_slice_writer() { + let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write(&[8, 9]).unwrap(), 1); + assert_eq!(writer.write(&[10]).unwrap(), 0); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(&**writer.get_ref(), b); +} + +#[test] +fn test_box_slice_writer_vectored() { + let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!( + writer.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7]),]).unwrap(), + 7, + ); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write_vectored(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(&**writer.get_ref(), b); +} + +#[test] +fn test_buf_writer() { + let mut buf = [0 as u8; 9]; + { + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write(&[8, 9]).unwrap(), 1); + assert_eq!(writer.write(&[10]).unwrap(), 0); + } + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(buf, b); +} + +#[test] +fn test_buf_writer_vectored() { + let mut buf = [0 as u8; 9]; + { + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!( + writer + .write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],) + .unwrap(), + 7, + ); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write_vectored(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); + } + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(buf, b); +} + +#[test] +fn test_buf_writer_seek() { + let mut buf = [0 as u8; 8]; + { + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[1]).unwrap(), 1); + assert_eq!(writer.position(), 1); + + assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2); + assert_eq!(writer.position(), 2); + assert_eq!(writer.write(&[2]).unwrap(), 1); + assert_eq!(writer.position(), 3); + + assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[3]).unwrap(), 1); + assert_eq!(writer.position(), 2); + + assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); + assert_eq!(writer.position(), 7); + assert_eq!(writer.write(&[4]).unwrap(), 1); + assert_eq!(writer.position(), 8); + } + let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; + assert_eq!(buf, b); +} + +#[test] +fn test_buf_writer_error() { + let mut buf = [0 as u8; 2]; + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[0, 0]).unwrap(), 1); + assert_eq!(writer.write(&[0, 0]).unwrap(), 0); +} + +#[test] +fn test_mem_reader() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_mem_reader_vectored() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); + let mut buf = []; + assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!( + reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(), + 1, + ); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf1 = [0; 4]; + let mut buf2 = [0; 4]; + assert_eq!( + reader + .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),]) + .unwrap(), + 7, + ); + let b1: &[_] = &[1, 2, 3, 4]; + let b2: &[_] = &[5, 6, 7]; + assert_eq!(buf1, b1); + assert_eq!(&buf2[..3], b2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_boxed_slice_reader() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_boxed_slice_reader_vectored() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); + let mut buf = []; + assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!( + reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(), + 1, + ); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf1 = [0; 4]; + let mut buf2 = [0; 4]; + assert_eq!( + reader + .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) + .unwrap(), + 7, + ); + let b1: &[_] = &[1, 2, 3, 4]; + let b2: &[_] = &[5, 6, 7]; + assert_eq!(buf1, b1); + assert_eq!(&buf2[..3], b2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn read_to_end() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); + let mut v = Vec::new(); + reader.read_to_end(&mut v).unwrap(); + assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); +} + +#[test] +fn test_slice_reader() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let reader = &mut &in_buf[..]; + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.len(), 7); + let b: &[_] = &[0]; + assert_eq!(&buf[..], b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.len(), 3); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(&buf[..], b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_slice_reader_vectored() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let reader = &mut &in_buf[..]; + let mut buf = []; + assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); + let mut buf = [0]; + assert_eq!( + reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(), + 1, + ); + assert_eq!(reader.len(), 7); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf1 = [0; 4]; + let mut buf2 = [0; 4]; + assert_eq!( + reader + .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) + .unwrap(), + 7, + ); + let b1: &[_] = &[1, 2, 3, 4]; + let b2: &[_] = &[5, 6, 7]; + assert_eq!(buf1, b1); + assert_eq!(&buf2[..3], b2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_read_exact() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let reader = &mut &in_buf[..]; + let mut buf = []; + assert!(reader.read_exact(&mut buf).is_ok()); + let mut buf = [8]; + assert!(reader.read_exact(&mut buf).is_ok()); + assert_eq!(buf[0], 0); + assert_eq!(reader.len(), 7); + let mut buf = [0, 0, 0, 0, 0, 0, 0]; + assert!(reader.read_exact(&mut buf).is_ok()); + assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]); + assert_eq!(reader.len(), 0); + let mut buf = [0]; + assert!(reader.read_exact(&mut buf).is_err()); +} + +#[test] +fn test_buf_reader() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let mut reader = Cursor::new(&in_buf[..]); + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn seek_past_end() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[..]); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.read(&mut [0]).unwrap(), 0); + + let mut r = Cursor::new(vec![10]); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.read(&mut [0]).unwrap(), 0); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[..]); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 0); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 0); +} + +#[test] +fn seek_past_i64() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[..]); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + + let mut r = Cursor::new(vec![10]); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[..]); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); +} + +#[test] +fn seek_before_0() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[..]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut r = Cursor::new(vec![10]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[..]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert!(r.seek(SeekFrom::End(-2)).is_err()); +} + +#[test] +fn test_seekable_mem_writer() { + let mut writer = Cursor::new(Vec::::new()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[3, 4]).unwrap(), 2); + let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3); + assert_eq!(writer.write(&[0, 1]).unwrap(), 2); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); + assert_eq!(writer.write(&[1, 2]).unwrap(), 2); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10); + assert_eq!(writer.write(&[1]).unwrap(), 1); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; + assert_eq!(&writer.get_ref()[..], b); +} + +#[test] +fn vec_seek_past_end() { + let mut r = Cursor::new(Vec::new()); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 1); +} + +#[test] +fn vec_seek_before_0() { + let mut r = Cursor::new(Vec::new()); + assert!(r.seek(SeekFrom::End(-2)).is_err()); +} + +#[test] +#[cfg(target_pointer_width = "32")] +fn vec_seek_and_write_past_usize_max() { + let mut c = Cursor::new(Vec::new()); + c.set_position(usize::MAX as u64 + 1); + assert!(c.write_all(&[1, 2, 3]).is_err()); +} + +#[test] +fn test_partial_eq() { + assert_eq!(Cursor::new(Vec::::new()), Cursor::new(Vec::::new())); +} + +#[test] +fn test_eq() { + struct AssertEq(pub T); + + let _: AssertEq>> = AssertEq(Cursor::new(Vec::new())); +} diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index e6eda2caf7..ba0f0a0cd7 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::convert::From; use crate::error; use crate::fmt; @@ -574,60 +577,3 @@ fn _assert_error_is_sync_send() { fn _is_sync_send() {} _is_sync_send::(); } - -#[cfg(test)] -mod test { - use super::{Custom, Error, ErrorKind, Repr}; - use crate::error; - use crate::fmt; - use crate::sys::decode_error_kind; - use crate::sys::os::error_string; - - #[test] - fn test_debug_error() { - let code = 6; - let msg = error_string(code); - let kind = decode_error_kind(code); - let err = Error { - repr: Repr::Custom(box Custom { - kind: ErrorKind::InvalidInput, - error: box Error { repr: super::Repr::Os(code) }, - }), - }; - let expected = format!( - "Custom {{ \ - kind: InvalidInput, \ - error: Os {{ \ - code: {:?}, \ - kind: {:?}, \ - message: {:?} \ - }} \ - }}", - code, kind, msg - ); - assert_eq!(format!("{:?}", err), expected); - } - - #[test] - fn test_downcasting() { - #[derive(Debug)] - struct TestError; - - impl fmt::Display for TestError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("asdf") - } - } - - impl error::Error for TestError {} - - // we have to call all of these UFCS style right now since method - // resolution won't implicitly drop the Send+Sync bounds - let mut err = Error::new(ErrorKind::Other, TestError); - assert!(err.get_ref().unwrap().is::()); - assert_eq!("asdf", err.get_ref().unwrap().to_string()); - assert!(err.get_mut().unwrap().is::()); - let extracted = err.into_inner().unwrap(); - extracted.downcast::().unwrap(); - } -} diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs new file mode 100644 index 0000000000..0cce9368c8 --- /dev/null +++ b/library/std/src/io/error/tests.rs @@ -0,0 +1,53 @@ +use super::{Custom, Error, ErrorKind, Repr}; +use crate::error; +use crate::fmt; +use crate::sys::decode_error_kind; +use crate::sys::os::error_string; + +#[test] +fn test_debug_error() { + let code = 6; + let msg = error_string(code); + let kind = decode_error_kind(code); + let err = Error { + repr: Repr::Custom(box Custom { + kind: ErrorKind::InvalidInput, + error: box Error { repr: super::Repr::Os(code) }, + }), + }; + let expected = format!( + "Custom {{ \ + kind: InvalidInput, \ + error: Os {{ \ + code: {:?}, \ + kind: {:?}, \ + message: {:?} \ + }} \ + }}", + code, kind, msg + ); + assert_eq!(format!("{:?}", err), expected); +} + +#[test] +fn test_downcasting() { + #[derive(Debug)] + struct TestError; + + impl fmt::Display for TestError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("asdf") + } + } + + impl error::Error for TestError {} + + // we have to call all of these UFCS style right now since method + // resolution won't implicitly drop the Send+Sync bounds + let mut err = Error::new(ErrorKind::Other, TestError); + assert!(err.get_ref().unwrap().is::()); + assert_eq!("asdf", err.get_ref().unwrap().to_string()); + assert!(err.get_mut().unwrap().is::()); + let extracted = err.into_inner().unwrap(); + extracted.downcast::().unwrap(); +} diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 01dff0b3eb..e09e7ba978 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::cmp; use crate::fmt; use crate::io::{ @@ -397,64 +400,3 @@ impl Write for Vec { Ok(()) } } - -#[cfg(test)] -mod tests { - use crate::io::prelude::*; - - #[bench] - fn bench_read_slice(b: &mut test::Bencher) { - let buf = [5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) - } - - #[bench] - fn bench_write_slice(b: &mut test::Bencher) { - let mut buf = [0; 1024]; - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) - } - - #[bench] - fn bench_read_vec(b: &mut test::Bencher) { - let buf = vec![5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) - } - - #[bench] - fn bench_write_vec(b: &mut test::Bencher) { - let mut buf = Vec::with_capacity(1024); - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) - } -} diff --git a/library/std/src/io/impls/tests.rs b/library/std/src/io/impls/tests.rs new file mode 100644 index 0000000000..d1cd84a67a --- /dev/null +++ b/library/std/src/io/impls/tests.rs @@ -0,0 +1,57 @@ +use crate::io::prelude::*; + +#[bench] +fn bench_read_slice(b: &mut test::Bencher) { + let buf = [5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in 0..8 { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) +} + +#[bench] +fn bench_write_slice(b: &mut test::Bencher) { + let mut buf = [0; 1024]; + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in 0..8 { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) +} + +#[bench] +fn bench_read_vec(b: &mut test::Bencher) { + let buf = vec![5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in 0..8 { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) +} + +#[bench] +fn bench_write_vec(b: &mut test::Bencher) { + let mut buf = Vec::with_capacity(1024); + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in 0..8 { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) +} diff --git a/library/std/src/io/lazy.rs b/library/std/src/io/lazy.rs deleted file mode 100644 index 1968d498bb..0000000000 --- a/library/std/src/io/lazy.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::cell::Cell; -use crate::ptr; -use crate::sync::Arc; -use crate::sys_common; -use crate::sys_common::mutex::Mutex; - -pub struct Lazy { - // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly! - lock: Mutex, - ptr: Cell<*mut Arc>, -} - -#[inline] -const fn done() -> *mut Arc { - 1_usize as *mut _ -} - -unsafe impl Sync for Lazy {} - -impl Lazy { - pub const fn new() -> Lazy { - Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()) } - } -} - -impl Lazy { - /// Safety: `init` must not call `get` on the variable that is being - /// initialized. - pub unsafe fn get(&'static self, init: fn() -> Arc) -> Option> { - let _guard = self.lock.lock(); - let ptr = self.ptr.get(); - if ptr.is_null() { - Some(self.init(init)) - } else if ptr == done() { - None - } else { - Some((*ptr).clone()) - } - } - - // Must only be called with `lock` held - unsafe fn init(&'static self, init: fn() -> Arc) -> Arc { - // If we successfully register an at exit handler, then we cache the - // `Arc` allocation in our own internal box (it will get deallocated by - // the at exit handler). Otherwise we just return the freshly allocated - // `Arc`. - let registered = sys_common::at_exit(move || { - let ptr = { - let _guard = self.lock.lock(); - self.ptr.replace(done()) - }; - drop(Box::from_raw(ptr)) - }); - // This could reentrantly call `init` again, which is a problem - // because our `lock` allows reentrancy! - // That's why `get` is unsafe and requires the caller to ensure no reentrancy happens. - let ret = init(); - if registered.is_ok() { - self.ptr.set(Box::into_raw(Box::new(ret.clone()))); - } - ret - } -} diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 462b696db4..d9d0380781 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -249,6 +249,9 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(test)] +mod tests; + use crate::cmp; use crate::fmt; use crate::memchr; @@ -282,7 +285,6 @@ mod buffered; mod cursor; mod error; mod impls; -mod lazy; pub mod prelude; mod stdio; mod util; @@ -2481,501 +2483,3 @@ impl Iterator for Lines { } } } - -#[cfg(test)] -mod tests { - use super::{repeat, Cursor, SeekFrom}; - use crate::cmp::{self, min}; - use crate::io::prelude::*; - use crate::io::{self, IoSlice, IoSliceMut}; - use crate::ops::Deref; - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn read_until() { - let mut buf = Cursor::new(&b"12"[..]); - let mut v = Vec::new(); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2); - assert_eq!(v, b"12"); - - let mut buf = Cursor::new(&b"1233"[..]); - let mut v = Vec::new(); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3); - assert_eq!(v, b"123"); - v.truncate(0); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1); - assert_eq!(v, b"3"); - v.truncate(0); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0); - assert_eq!(v, []); - } - - #[test] - fn split() { - let buf = Cursor::new(&b"12"[..]); - let mut s = buf.split(b'3'); - assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); - assert!(s.next().is_none()); - - let buf = Cursor::new(&b"1233"[..]); - let mut s = buf.split(b'3'); - assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); - assert_eq!(s.next().unwrap().unwrap(), vec![]); - assert!(s.next().is_none()); - } - - #[test] - fn read_line() { - let mut buf = Cursor::new(&b"12"[..]); - let mut v = String::new(); - assert_eq!(buf.read_line(&mut v).unwrap(), 2); - assert_eq!(v, "12"); - - let mut buf = Cursor::new(&b"12\n\n"[..]); - let mut v = String::new(); - assert_eq!(buf.read_line(&mut v).unwrap(), 3); - assert_eq!(v, "12\n"); - v.truncate(0); - assert_eq!(buf.read_line(&mut v).unwrap(), 1); - assert_eq!(v, "\n"); - v.truncate(0); - assert_eq!(buf.read_line(&mut v).unwrap(), 0); - assert_eq!(v, ""); - } - - #[test] - fn lines() { - let buf = Cursor::new(&b"12\r"[..]); - let mut s = buf.lines(); - assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string()); - assert!(s.next().is_none()); - - let buf = Cursor::new(&b"12\r\n\n"[..]); - let mut s = buf.lines(); - assert_eq!(s.next().unwrap().unwrap(), "12".to_string()); - assert_eq!(s.next().unwrap().unwrap(), "".to_string()); - assert!(s.next().is_none()); - } - - #[test] - fn read_to_end() { - let mut c = Cursor::new(&b""[..]); - let mut v = Vec::new(); - assert_eq!(c.read_to_end(&mut v).unwrap(), 0); - assert_eq!(v, []); - - let mut c = Cursor::new(&b"1"[..]); - let mut v = Vec::new(); - assert_eq!(c.read_to_end(&mut v).unwrap(), 1); - assert_eq!(v, b"1"); - - let cap = 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); - assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len()); - assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len()); - assert_eq!(v, data); - } - - #[test] - fn read_to_string() { - let mut c = Cursor::new(&b""[..]); - let mut v = String::new(); - assert_eq!(c.read_to_string(&mut v).unwrap(), 0); - assert_eq!(v, ""); - - let mut c = Cursor::new(&b"1"[..]); - let mut v = String::new(); - assert_eq!(c.read_to_string(&mut v).unwrap(), 1); - assert_eq!(v, "1"); - - let mut c = Cursor::new(&b"\xff"[..]); - let mut v = String::new(); - assert!(c.read_to_string(&mut v).is_err()); - } - - #[test] - fn read_exact() { - let mut buf = [0; 4]; - - let mut c = Cursor::new(&b""[..]); - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - - let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..])); - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"1234"); - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"5678"); - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - } - - #[test] - fn read_exact_slice() { - let mut buf = [0; 4]; - - let mut c = &b""[..]; - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - - let mut c = &b"123"[..]; - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - // make sure the optimized (early returning) method is being used - assert_eq!(&buf, &[0; 4]); - - let mut c = &b"1234"[..]; - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"1234"); - - let mut c = &b"56789"[..]; - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"5678"); - assert_eq!(c, b"9"); - } - - #[test] - fn take_eof() { - struct R; - - impl Read for R { - fn read(&mut self, _: &mut [u8]) -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, "")) - } - } - impl BufRead for R { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - Err(io::Error::new(io::ErrorKind::Other, "")) - } - fn consume(&mut self, _amt: usize) {} - } - - let mut buf = [0; 1]; - assert_eq!(0, R.take(0).read(&mut buf).unwrap()); - assert_eq!(b"", R.take(0).fill_buf().unwrap()); - } - - fn cmp_bufread(mut br1: Br1, mut br2: Br2, exp: &[u8]) { - let mut cat = Vec::new(); - loop { - let consume = { - let buf1 = br1.fill_buf().unwrap(); - let buf2 = br2.fill_buf().unwrap(); - let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() }; - assert_eq!(buf1[..minlen], buf2[..minlen]); - cat.extend_from_slice(&buf1[..minlen]); - minlen - }; - if consume == 0 { - break; - } - br1.consume(consume); - br2.consume(consume); - } - assert_eq!(br1.fill_buf().unwrap().len(), 0); - assert_eq!(br2.fill_buf().unwrap().len(), 0); - assert_eq!(&cat[..], &exp[..]) - } - - #[test] - fn chain_bufread() { - let testdata = b"ABCDEFGHIJKL"; - let chain1 = - (&testdata[..3]).chain(&testdata[3..6]).chain(&testdata[6..9]).chain(&testdata[9..]); - let chain2 = (&testdata[..4]).chain(&testdata[4..8]).chain(&testdata[8..]); - cmp_bufread(chain1, chain2, &testdata[..]); - } - - #[test] - fn chain_zero_length_read_is_not_eof() { - let a = b"A"; - let b = b"B"; - let mut s = String::new(); - let mut chain = (&a[..]).chain(&b[..]); - chain.read(&mut []).unwrap(); - chain.read_to_string(&mut s).unwrap(); - assert_eq!("AB", s); - } - - #[bench] - #[cfg_attr(target_os = "emscripten", ignore)] - fn bench_read_to_end(b: &mut test::Bencher) { - b.iter(|| { - let mut lr = repeat(1).take(10000000); - let mut vec = Vec::with_capacity(1024); - super::read_to_end(&mut lr, &mut vec) - }); - } - - #[test] - fn seek_len() -> io::Result<()> { - let mut c = Cursor::new(vec![0; 15]); - assert_eq!(c.stream_len()?, 15); - - c.seek(SeekFrom::End(0))?; - let old_pos = c.stream_position()?; - assert_eq!(c.stream_len()?, 15); - assert_eq!(c.stream_position()?, old_pos); - - c.seek(SeekFrom::Start(7))?; - c.seek(SeekFrom::Current(2))?; - let old_pos = c.stream_position()?; - assert_eq!(c.stream_len()?, 15); - assert_eq!(c.stream_position()?, old_pos); - - Ok(()) - } - - #[test] - fn seek_position() -> io::Result<()> { - // All `asserts` are duplicated here to make sure the method does not - // change anything about the seek state. - let mut c = Cursor::new(vec![0; 15]); - assert_eq!(c.stream_position()?, 0); - assert_eq!(c.stream_position()?, 0); - - c.seek(SeekFrom::End(0))?; - assert_eq!(c.stream_position()?, 15); - assert_eq!(c.stream_position()?, 15); - - c.seek(SeekFrom::Start(7))?; - c.seek(SeekFrom::Current(2))?; - assert_eq!(c.stream_position()?, 9); - assert_eq!(c.stream_position()?, 9); - - c.seek(SeekFrom::End(-3))?; - c.seek(SeekFrom::Current(1))?; - c.seek(SeekFrom::Current(-5))?; - assert_eq!(c.stream_position()?, 8); - assert_eq!(c.stream_position()?, 8); - - Ok(()) - } - - // A simple example reader which uses the default implementation of - // read_to_end. - struct ExampleSliceReader<'a> { - slice: &'a [u8], - } - - impl<'a> Read for ExampleSliceReader<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let len = cmp::min(self.slice.len(), buf.len()); - buf[..len].copy_from_slice(&self.slice[..len]); - self.slice = &self.slice[len..]; - Ok(len) - } - } - - #[test] - fn test_read_to_end_capacity() -> io::Result<()> { - let input = &b"foo"[..]; - - // read_to_end() generally needs to over-allocate, both for efficiency - // and so that it can distinguish EOF. Assert that this is the case - // with this simple ExampleSliceReader struct, which uses the default - // implementation of read_to_end. Even though vec1 is allocated with - // exactly enough capacity for the read, read_to_end will allocate more - // space here. - let mut vec1 = Vec::with_capacity(input.len()); - ExampleSliceReader { slice: input }.read_to_end(&mut vec1)?; - assert_eq!(vec1.len(), input.len()); - assert!(vec1.capacity() > input.len(), "allocated more"); - - // However, std::io::Take includes an implementation of read_to_end - // that will not allocate when the limit has already been reached. In - // this case, vec2 never grows. - let mut vec2 = Vec::with_capacity(input.len()); - ExampleSliceReader { slice: input }.take(input.len() as u64).read_to_end(&mut vec2)?; - assert_eq!(vec2.len(), input.len()); - assert_eq!(vec2.capacity(), input.len(), "did not allocate more"); - - Ok(()) - } - - #[test] - fn io_slice_mut_advance() { - let mut buf1 = [1; 8]; - let mut buf2 = [2; 16]; - let mut buf3 = [3; 8]; - let mut bufs = &mut [ - IoSliceMut::new(&mut buf1), - IoSliceMut::new(&mut buf2), - IoSliceMut::new(&mut buf3), - ][..]; - - // Only in a single buffer.. - bufs = IoSliceMut::advance(bufs, 1); - assert_eq!(bufs[0].deref(), [1; 7].as_ref()); - assert_eq!(bufs[1].deref(), [2; 16].as_ref()); - assert_eq!(bufs[2].deref(), [3; 8].as_ref()); - - // Removing a buffer, leaving others as is. - bufs = IoSliceMut::advance(bufs, 7); - assert_eq!(bufs[0].deref(), [2; 16].as_ref()); - assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - - // Removing a buffer and removing from the next buffer. - bufs = IoSliceMut::advance(bufs, 18); - assert_eq!(bufs[0].deref(), [3; 6].as_ref()); - } - - #[test] - fn io_slice_mut_advance_empty_slice() { - let empty_bufs = &mut [][..]; - // Shouldn't panic. - IoSliceMut::advance(empty_bufs, 1); - } - - #[test] - fn io_slice_mut_advance_beyond_total_length() { - let mut buf1 = [1; 8]; - let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..]; - - // Going beyond the total length should be ok. - bufs = IoSliceMut::advance(bufs, 9); - assert!(bufs.is_empty()); - } - - #[test] - fn io_slice_advance() { - let buf1 = [1; 8]; - let buf2 = [2; 16]; - let buf3 = [3; 8]; - let mut bufs = &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..]; - - // Only in a single buffer.. - bufs = IoSlice::advance(bufs, 1); - assert_eq!(bufs[0].deref(), [1; 7].as_ref()); - assert_eq!(bufs[1].deref(), [2; 16].as_ref()); - assert_eq!(bufs[2].deref(), [3; 8].as_ref()); - - // Removing a buffer, leaving others as is. - bufs = IoSlice::advance(bufs, 7); - assert_eq!(bufs[0].deref(), [2; 16].as_ref()); - assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - - // Removing a buffer and removing from the next buffer. - bufs = IoSlice::advance(bufs, 18); - assert_eq!(bufs[0].deref(), [3; 6].as_ref()); - } - - #[test] - fn io_slice_advance_empty_slice() { - let empty_bufs = &mut [][..]; - // Shouldn't panic. - IoSlice::advance(empty_bufs, 1); - } - - #[test] - fn io_slice_advance_beyond_total_length() { - let buf1 = [1; 8]; - let mut bufs = &mut [IoSlice::new(&buf1)][..]; - - // Going beyond the total length should be ok. - bufs = IoSlice::advance(bufs, 9); - assert!(bufs.is_empty()); - } - - /// Create a new writer that reads from at most `n_bufs` and reads - /// `per_call` bytes (in total) per call to write. - fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { - TestWriter { n_bufs, per_call, written: Vec::new() } - } - - struct TestWriter { - n_bufs: usize, - per_call: usize, - written: Vec, - } - - impl Write for TestWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.write_vectored(&[IoSlice::new(buf)]) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let mut left = self.per_call; - let mut written = 0; - for buf in bufs.iter().take(self.n_bufs) { - let n = min(left, buf.len()); - self.written.extend_from_slice(&buf[0..n]); - left -= n; - written += n; - } - Ok(written) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - } - - #[test] - fn test_writer_read_from_one_buf() { - let mut writer = test_writer(1, 2); - - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.write_vectored(&[]).unwrap(), 0); - - // Read at most 2 bytes. - assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2); - let bufs = &[IoSlice::new(&[2, 2, 2])]; - assert_eq!(writer.write_vectored(bufs).unwrap(), 2); - - // Only read from first buf. - let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])]; - assert_eq!(writer.write_vectored(bufs).unwrap(), 1); - - assert_eq!(writer.written, &[1, 1, 2, 2, 3]); - } - - #[test] - fn test_writer_read_from_multiple_bufs() { - let mut writer = test_writer(3, 3); - - // Read at most 3 bytes from two buffers. - let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])]; - assert_eq!(writer.write_vectored(bufs).unwrap(), 3); - - // Read at most 3 bytes from three buffers. - let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])]; - assert_eq!(writer.write_vectored(bufs).unwrap(), 3); - - assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]); - } - - #[test] - fn test_write_all_vectored() { - #[rustfmt::skip] // Becomes unreadable otherwise. - let tests: Vec<(_, &'static [u8])> = vec![ - (vec![], &[]), - (vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]), - (vec![IoSlice::new(&[1])], &[1]), - (vec![IoSlice::new(&[1, 2])], &[1, 2]), - (vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]), - (vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]), - (vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), - (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]), - (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]), - (vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]), - (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]), - ]; - - let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]; - - for (n_bufs, per_call) in writer_configs.iter().copied() { - for (mut input, wanted) in tests.clone().into_iter() { - let mut writer = test_writer(n_bufs, per_call); - assert!(writer.write_all_vectored(&mut *input).is_ok()); - assert_eq!(&*writer.written, &*wanted); - } - } - } -} diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 3943c66aad..36b4940159 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -1,30 +1,49 @@ #![cfg_attr(test, allow(unused))] +#[cfg(test)] +mod tests; + use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; -use crate::io::lazy::Lazy; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; -use crate::sync::{Arc, Mutex, MutexGuard, Once}; +use crate::lazy::SyncOnceCell; +use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sync::{Mutex, MutexGuard}; use crate::sys::stdio; +use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread::LocalKey; thread_local! { - /// Stdout used by print! and println! macros + /// Used by the test crate to capture the output of the print! and println! macros. static LOCAL_STDOUT: RefCell>> = { RefCell::new(None) } } thread_local! { - /// Stderr used by eprint! and eprintln! macros, and panics + /// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics. static LOCAL_STDERR: RefCell>> = { RefCell::new(None) } } +/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used. +/// +/// If both are None and were never set on any thread, this flag is set to +/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all +/// threads, saving some time and memory registering an unused thread local. +/// +/// Note about memory ordering: This contains information about whether two +/// thread local variables might be in use. Although this is a global flag, the +/// memory ordering between threads does not matter: we only want this flag to +/// have a consistent order between set_print/set_panic and print_to *within +/// the same thread*. Within the same thread, things always have a perfectly +/// consistent order. So Ordering::Relaxed is fine. +static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false); + /// A handle to a raw instance of the standard input stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via @@ -214,7 +233,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdin { - inner: Arc>>, + inner: &'static Mutex>, } /// A locked reference to the `Stdin` handle. @@ -289,15 +308,11 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy>> = Lazy::new(); - return Stdin { - inner: unsafe { INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown") }, - }; - - fn stdin_init() -> Arc>> { - // This must not reentrantly access `INSTANCE` - let stdin = stdin_raw(); - Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); + Stdin { + inner: INSTANCE.get_or_init(|| { + Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) + }), } } @@ -473,7 +488,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: Arc>>>, + inner: &'static ReentrantMutex>>, } /// A locked reference to the `Stdout` handle. @@ -531,19 +546,27 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: Lazy>>> = Lazy::new(); - return Stdout { - inner: unsafe { INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown") }, - }; - - fn stdout_init() -> Arc>>> { - // This must not reentrantly access `INSTANCE` - let stdout = stdout_raw(); - unsafe { - let ret = Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout)))); - ret.init(); - ret - } + static INSTANCE: SyncOnceCell>>> = + SyncOnceCell::new(); + Stdout { + inner: INSTANCE.get_or_init(|| unsafe { + let _ = sys_common::at_exit(|| { + if let Some(instance) = INSTANCE.get() { + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // 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) = instance.try_lock() { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); + } + } + }); + let r = ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))); + r.init(); + r + }), } } @@ -583,6 +606,32 @@ impl fmt::Debug for Stdout { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + (&*self).write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (&*self).write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (&*self).write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + (&*self).write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + (&*self).write_fmt(args) + } +} + +#[stable(feature = "write_mt", since = "1.48.0")] +impl Write for &Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) } @@ -606,6 +655,7 @@ impl Write for Stdout { self.lock().write_fmt(args) } } + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StdoutLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -711,16 +761,15 @@ pub fn stderr() -> Stderr { // // This has the added benefit of allowing `stderr` to be usable during // process shutdown as well! - static INSTANCE: ReentrantMutex> = - unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }; + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); - // When accessing stderr we need one-time initialization of the reentrant - // mutex. Afterwards we can just always use the now-filled-in `INSTANCE` value. - static INIT: Once = Once::new(); - INIT.call_once(|| unsafe { - INSTANCE.init(); - }); - Stderr { inner: &INSTANCE } + Stderr { + inner: INSTANCE.get_or_init(|| unsafe { + let r = ReentrantMutex::new(RefCell::new(stderr_raw())); + r.init(); + r + }), + } } impl Stderr { @@ -759,6 +808,32 @@ impl fmt::Debug for Stderr { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + (&*self).write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (&*self).write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (&*self).write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + (&*self).write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + (&*self).write_fmt(args) + } +} + +#[stable(feature = "write_mt", since = "1.48.0")] +impl Write for &Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) } @@ -782,6 +857,7 @@ impl Write for Stderr { self.lock().write_fmt(args) } } + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StderrLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -829,10 +905,18 @@ impl fmt::Debug for StderrLock<'_> { #[doc(hidden)] pub fn set_panic(sink: Option>) -> Option> { use crate::mem; - LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) + if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) { + // LOCAL_STDERR is definitely None since LOCAL_STREAMS is false. + return None; + } + let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( + |mut s| { + let _ = s.flush(); + Some(s) + }, + ); + LOCAL_STREAMS.store(true, Ordering::Relaxed); + s } /// Resets the thread-local stdout handle to the specified writer @@ -852,10 +936,18 @@ pub fn set_panic(sink: Option>) -> Option>) -> Option> { use crate::mem; - LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) + if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) { + // LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false. + return None; + } + let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( + |mut s| { + let _ = s.flush(); + Some(s) + }, + ); + LOCAL_STREAMS.store(true, Ordering::Relaxed); + s } /// Write `args` to output stream `local_s` if possible, `global_s` @@ -876,20 +968,26 @@ fn print_to( ) where T: Write, { - let result = local_s - .try_with(|s| { - // Note that we completely remove a local sink to write to in case - // our printing recursively panics/prints, so the recursive - // panic/print goes to the global sink instead of our local sink. - let prev = s.borrow_mut().take(); - if let Some(mut w) = prev { - let result = w.write_fmt(args); - *s.borrow_mut() = Some(w); - return result; - } - global_s().write_fmt(args) + let result = LOCAL_STREAMS + .load(Ordering::Relaxed) + .then(|| { + local_s + .try_with(|s| { + // Note that we completely remove a local sink to write to in case + // our printing recursively panics/prints, so the recursive + // panic/print goes to the global sink instead of our local sink. + let prev = s.borrow_mut().take(); + if let Some(mut w) = prev { + let result = w.write_fmt(args); + *s.borrow_mut() = Some(w); + return result; + } + global_s().write_fmt(args) + }) + .ok() }) - .unwrap_or_else(|_| global_s().write_fmt(args)); + .flatten() + .unwrap_or_else(|| global_s().write_fmt(args)); if let Err(e) = result { panic!("failed printing to {}: {}", label, e); @@ -920,54 +1018,3 @@ pub fn _eprint(args: fmt::Arguments<'_>) { #[cfg(test)] pub use realstd::io::{_eprint, _print}; - -#[cfg(test)] -mod tests { - use super::*; - use crate::panic::{RefUnwindSafe, UnwindSafe}; - use crate::thread; - - #[test] - fn stdout_unwind_safe() { - assert_unwind_safe::(); - } - #[test] - fn stdoutlock_unwind_safe() { - assert_unwind_safe::>(); - assert_unwind_safe::>(); - } - #[test] - fn stderr_unwind_safe() { - assert_unwind_safe::(); - } - #[test] - fn stderrlock_unwind_safe() { - assert_unwind_safe::>(); - assert_unwind_safe::>(); - } - - fn assert_unwind_safe() {} - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn panic_doesnt_poison() { - thread::spawn(|| { - let _a = stdin(); - let _a = _a.lock(); - let _a = stdout(); - let _a = _a.lock(); - let _a = stderr(); - let _a = _a.lock(); - panic!(); - }) - .join() - .unwrap_err(); - - let _a = stdin(); - let _a = _a.lock(); - let _a = stdout(); - let _a = _a.lock(); - let _a = stderr(); - let _a = _a.lock(); - } -} diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs new file mode 100644 index 0000000000..04af500268 --- /dev/null +++ b/library/std/src/io/stdio/tests.rs @@ -0,0 +1,47 @@ +use super::*; +use crate::panic::{RefUnwindSafe, UnwindSafe}; +use crate::thread; + +#[test] +fn stdout_unwind_safe() { + assert_unwind_safe::(); +} +#[test] +fn stdoutlock_unwind_safe() { + assert_unwind_safe::>(); + assert_unwind_safe::>(); +} +#[test] +fn stderr_unwind_safe() { + assert_unwind_safe::(); +} +#[test] +fn stderrlock_unwind_safe() { + assert_unwind_safe::>(); + assert_unwind_safe::>(); +} + +fn assert_unwind_safe() {} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn panic_doesnt_poison() { + thread::spawn(|| { + let _a = stdin(); + let _a = _a.lock(); + let _a = stdout(); + let _a = _a.lock(); + let _a = stderr(); + let _a = _a.lock(); + panic!(); + }) + .join() + .unwrap_err(); + + let _a = stdin(); + let _a = _a.lock(); + let _a = stdout(); + let _a = _a.lock(); + let _a = stderr(); + let _a = _a.lock(); +} diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs new file mode 100644 index 0000000000..913b28538b --- /dev/null +++ b/library/std/src/io/tests.rs @@ -0,0 +1,494 @@ +use super::{repeat, Cursor, SeekFrom}; +use crate::cmp::{self, min}; +use crate::io::prelude::*; +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::ops::Deref; + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn read_until() { + let mut buf = Cursor::new(&b"12"[..]); + let mut v = Vec::new(); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2); + assert_eq!(v, b"12"); + + let mut buf = Cursor::new(&b"1233"[..]); + let mut v = Vec::new(); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3); + assert_eq!(v, b"123"); + v.truncate(0); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1); + assert_eq!(v, b"3"); + v.truncate(0); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0); + assert_eq!(v, []); +} + +#[test] +fn split() { + let buf = Cursor::new(&b"12"[..]); + let mut s = buf.split(b'3'); + assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); + assert!(s.next().is_none()); + + let buf = Cursor::new(&b"1233"[..]); + let mut s = buf.split(b'3'); + assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); + assert_eq!(s.next().unwrap().unwrap(), vec![]); + assert!(s.next().is_none()); +} + +#[test] +fn read_line() { + let mut buf = Cursor::new(&b"12"[..]); + let mut v = String::new(); + assert_eq!(buf.read_line(&mut v).unwrap(), 2); + assert_eq!(v, "12"); + + let mut buf = Cursor::new(&b"12\n\n"[..]); + let mut v = String::new(); + assert_eq!(buf.read_line(&mut v).unwrap(), 3); + assert_eq!(v, "12\n"); + v.truncate(0); + assert_eq!(buf.read_line(&mut v).unwrap(), 1); + assert_eq!(v, "\n"); + v.truncate(0); + assert_eq!(buf.read_line(&mut v).unwrap(), 0); + assert_eq!(v, ""); +} + +#[test] +fn lines() { + let buf = Cursor::new(&b"12\r"[..]); + let mut s = buf.lines(); + assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string()); + assert!(s.next().is_none()); + + let buf = Cursor::new(&b"12\r\n\n"[..]); + let mut s = buf.lines(); + assert_eq!(s.next().unwrap().unwrap(), "12".to_string()); + assert_eq!(s.next().unwrap().unwrap(), "".to_string()); + assert!(s.next().is_none()); +} + +#[test] +fn read_to_end() { + let mut c = Cursor::new(&b""[..]); + let mut v = Vec::new(); + assert_eq!(c.read_to_end(&mut v).unwrap(), 0); + assert_eq!(v, []); + + let mut c = Cursor::new(&b"1"[..]); + let mut v = Vec::new(); + assert_eq!(c.read_to_end(&mut v).unwrap(), 1); + assert_eq!(v, b"1"); + + let cap = 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); + assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len()); + assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len()); + assert_eq!(v, data); +} + +#[test] +fn read_to_string() { + let mut c = Cursor::new(&b""[..]); + let mut v = String::new(); + assert_eq!(c.read_to_string(&mut v).unwrap(), 0); + assert_eq!(v, ""); + + let mut c = Cursor::new(&b"1"[..]); + let mut v = String::new(); + assert_eq!(c.read_to_string(&mut v).unwrap(), 1); + assert_eq!(v, "1"); + + let mut c = Cursor::new(&b"\xff"[..]); + let mut v = String::new(); + assert!(c.read_to_string(&mut v).is_err()); +} + +#[test] +fn read_exact() { + let mut buf = [0; 4]; + + let mut c = Cursor::new(&b""[..]); + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); + + let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..])); + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"1234"); + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"5678"); + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); +} + +#[test] +fn read_exact_slice() { + let mut buf = [0; 4]; + + let mut c = &b""[..]; + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); + + let mut c = &b"123"[..]; + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); + // make sure the optimized (early returning) method is being used + assert_eq!(&buf, &[0; 4]); + + let mut c = &b"1234"[..]; + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"1234"); + + let mut c = &b"56789"[..]; + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"5678"); + assert_eq!(c, b"9"); +} + +#[test] +fn take_eof() { + struct R; + + impl Read for R { + fn read(&mut self, _: &mut [u8]) -> io::Result { + Err(io::Error::new(io::ErrorKind::Other, "")) + } + } + impl BufRead for R { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + Err(io::Error::new(io::ErrorKind::Other, "")) + } + fn consume(&mut self, _amt: usize) {} + } + + let mut buf = [0; 1]; + assert_eq!(0, R.take(0).read(&mut buf).unwrap()); + assert_eq!(b"", R.take(0).fill_buf().unwrap()); +} + +fn cmp_bufread(mut br1: Br1, mut br2: Br2, exp: &[u8]) { + let mut cat = Vec::new(); + loop { + let consume = { + let buf1 = br1.fill_buf().unwrap(); + let buf2 = br2.fill_buf().unwrap(); + let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() }; + assert_eq!(buf1[..minlen], buf2[..minlen]); + cat.extend_from_slice(&buf1[..minlen]); + minlen + }; + if consume == 0 { + break; + } + br1.consume(consume); + br2.consume(consume); + } + assert_eq!(br1.fill_buf().unwrap().len(), 0); + assert_eq!(br2.fill_buf().unwrap().len(), 0); + assert_eq!(&cat[..], &exp[..]) +} + +#[test] +fn chain_bufread() { + let testdata = b"ABCDEFGHIJKL"; + let chain1 = + (&testdata[..3]).chain(&testdata[3..6]).chain(&testdata[6..9]).chain(&testdata[9..]); + let chain2 = (&testdata[..4]).chain(&testdata[4..8]).chain(&testdata[8..]); + cmp_bufread(chain1, chain2, &testdata[..]); +} + +#[test] +fn chain_zero_length_read_is_not_eof() { + let a = b"A"; + let b = b"B"; + let mut s = String::new(); + let mut chain = (&a[..]).chain(&b[..]); + chain.read(&mut []).unwrap(); + chain.read_to_string(&mut s).unwrap(); + assert_eq!("AB", s); +} + +#[bench] +#[cfg_attr(target_os = "emscripten", ignore)] +fn bench_read_to_end(b: &mut test::Bencher) { + b.iter(|| { + let mut lr = repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + super::read_to_end(&mut lr, &mut vec) + }); +} + +#[test] +fn seek_len() -> io::Result<()> { + let mut c = Cursor::new(vec![0; 15]); + assert_eq!(c.stream_len()?, 15); + + c.seek(SeekFrom::End(0))?; + let old_pos = c.stream_position()?; + assert_eq!(c.stream_len()?, 15); + assert_eq!(c.stream_position()?, old_pos); + + c.seek(SeekFrom::Start(7))?; + c.seek(SeekFrom::Current(2))?; + let old_pos = c.stream_position()?; + assert_eq!(c.stream_len()?, 15); + assert_eq!(c.stream_position()?, old_pos); + + Ok(()) +} + +#[test] +fn seek_position() -> io::Result<()> { + // All `asserts` are duplicated here to make sure the method does not + // change anything about the seek state. + let mut c = Cursor::new(vec![0; 15]); + assert_eq!(c.stream_position()?, 0); + assert_eq!(c.stream_position()?, 0); + + c.seek(SeekFrom::End(0))?; + assert_eq!(c.stream_position()?, 15); + assert_eq!(c.stream_position()?, 15); + + c.seek(SeekFrom::Start(7))?; + c.seek(SeekFrom::Current(2))?; + assert_eq!(c.stream_position()?, 9); + assert_eq!(c.stream_position()?, 9); + + c.seek(SeekFrom::End(-3))?; + c.seek(SeekFrom::Current(1))?; + c.seek(SeekFrom::Current(-5))?; + assert_eq!(c.stream_position()?, 8); + assert_eq!(c.stream_position()?, 8); + + Ok(()) +} + +// A simple example reader which uses the default implementation of +// read_to_end. +struct ExampleSliceReader<'a> { + slice: &'a [u8], +} + +impl<'a> Read for ExampleSliceReader<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = cmp::min(self.slice.len(), buf.len()); + buf[..len].copy_from_slice(&self.slice[..len]); + self.slice = &self.slice[len..]; + Ok(len) + } +} + +#[test] +fn test_read_to_end_capacity() -> io::Result<()> { + let input = &b"foo"[..]; + + // read_to_end() generally needs to over-allocate, both for efficiency + // and so that it can distinguish EOF. Assert that this is the case + // with this simple ExampleSliceReader struct, which uses the default + // implementation of read_to_end. Even though vec1 is allocated with + // exactly enough capacity for the read, read_to_end will allocate more + // space here. + let mut vec1 = Vec::with_capacity(input.len()); + ExampleSliceReader { slice: input }.read_to_end(&mut vec1)?; + assert_eq!(vec1.len(), input.len()); + assert!(vec1.capacity() > input.len(), "allocated more"); + + // However, std::io::Take includes an implementation of read_to_end + // that will not allocate when the limit has already been reached. In + // this case, vec2 never grows. + let mut vec2 = Vec::with_capacity(input.len()); + ExampleSliceReader { slice: input }.take(input.len() as u64).read_to_end(&mut vec2)?; + assert_eq!(vec2.len(), input.len()); + assert_eq!(vec2.capacity(), input.len(), "did not allocate more"); + + Ok(()) +} + +#[test] +fn io_slice_mut_advance() { + let mut buf1 = [1; 8]; + let mut buf2 = [2; 16]; + let mut buf3 = [3; 8]; + let mut bufs = &mut [ + IoSliceMut::new(&mut buf1), + IoSliceMut::new(&mut buf2), + IoSliceMut::new(&mut buf3), + ][..]; + + // Only in a single buffer.. + bufs = IoSliceMut::advance(bufs, 1); + assert_eq!(bufs[0].deref(), [1; 7].as_ref()); + assert_eq!(bufs[1].deref(), [2; 16].as_ref()); + assert_eq!(bufs[2].deref(), [3; 8].as_ref()); + + // Removing a buffer, leaving others as is. + bufs = IoSliceMut::advance(bufs, 7); + assert_eq!(bufs[0].deref(), [2; 16].as_ref()); + assert_eq!(bufs[1].deref(), [3; 8].as_ref()); + + // Removing a buffer and removing from the next buffer. + bufs = IoSliceMut::advance(bufs, 18); + assert_eq!(bufs[0].deref(), [3; 6].as_ref()); +} + +#[test] +fn io_slice_mut_advance_empty_slice() { + let empty_bufs = &mut [][..]; + // Shouldn't panic. + IoSliceMut::advance(empty_bufs, 1); +} + +#[test] +fn io_slice_mut_advance_beyond_total_length() { + let mut buf1 = [1; 8]; + let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..]; + + // Going beyond the total length should be ok. + bufs = IoSliceMut::advance(bufs, 9); + assert!(bufs.is_empty()); +} + +#[test] +fn io_slice_advance() { + let buf1 = [1; 8]; + let buf2 = [2; 16]; + let buf3 = [3; 8]; + let mut bufs = &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..]; + + // Only in a single buffer.. + bufs = IoSlice::advance(bufs, 1); + assert_eq!(bufs[0].deref(), [1; 7].as_ref()); + assert_eq!(bufs[1].deref(), [2; 16].as_ref()); + assert_eq!(bufs[2].deref(), [3; 8].as_ref()); + + // Removing a buffer, leaving others as is. + bufs = IoSlice::advance(bufs, 7); + assert_eq!(bufs[0].deref(), [2; 16].as_ref()); + assert_eq!(bufs[1].deref(), [3; 8].as_ref()); + + // Removing a buffer and removing from the next buffer. + bufs = IoSlice::advance(bufs, 18); + assert_eq!(bufs[0].deref(), [3; 6].as_ref()); +} + +#[test] +fn io_slice_advance_empty_slice() { + let empty_bufs = &mut [][..]; + // Shouldn't panic. + IoSlice::advance(empty_bufs, 1); +} + +#[test] +fn io_slice_advance_beyond_total_length() { + let buf1 = [1; 8]; + let mut bufs = &mut [IoSlice::new(&buf1)][..]; + + // Going beyond the total length should be ok. + bufs = IoSlice::advance(bufs, 9); + assert!(bufs.is_empty()); +} + +/// Create a new writer that reads from at most `n_bufs` and reads +/// `per_call` bytes (in total) per call to write. +fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { + TestWriter { n_bufs, per_call, written: Vec::new() } +} + +struct TestWriter { + n_bufs: usize, + per_call: usize, + written: Vec, +} + +impl Write for TestWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.write_vectored(&[IoSlice::new(buf)]) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let mut left = self.per_call; + let mut written = 0; + for buf in bufs.iter().take(self.n_bufs) { + let n = min(left, buf.len()); + self.written.extend_from_slice(&buf[0..n]); + left -= n; + written += n; + } + Ok(written) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[test] +fn test_writer_read_from_one_buf() { + let mut writer = test_writer(1, 2); + + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.write_vectored(&[]).unwrap(), 0); + + // Read at most 2 bytes. + assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2); + let bufs = &[IoSlice::new(&[2, 2, 2])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 2); + + // Only read from first buf. + let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 1); + + assert_eq!(writer.written, &[1, 1, 2, 2, 3]); +} + +#[test] +fn test_writer_read_from_multiple_bufs() { + let mut writer = test_writer(3, 3); + + // Read at most 3 bytes from two buffers. + let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 3); + + // Read at most 3 bytes from three buffers. + let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 3); + + assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]); +} + +#[test] +fn test_write_all_vectored() { + #[rustfmt::skip] // Becomes unreadable otherwise. + let tests: Vec<(_, &'static [u8])> = vec![ + (vec![], &[]), + (vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]), + (vec![IoSlice::new(&[1])], &[1]), + (vec![IoSlice::new(&[1, 2])], &[1, 2]), + (vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]), + (vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]), + (vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]), + (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]), + ]; + + let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]; + + for (n_bufs, per_call) in writer_configs.iter().copied() { + for (mut input, wanted) in tests.clone().into_iter() { + let mut writer = test_writer(n_bufs, per_call); + assert!(writer.write_all_vectored(&mut *input).is_ok()); + assert_eq!(&*writer.written, &*wanted); + } + } +} diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index a093b745b0..dc05b9648f 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -1,5 +1,8 @@ #![allow(missing_copy_implementations)] +#[cfg(test)] +mod tests; + use crate::fmt; use crate::io::{self, BufRead, ErrorKind, Initializer, IoSlice, IoSliceMut, Read, Write}; use crate::mem::MaybeUninit; @@ -49,24 +52,27 @@ where W: Write, { let mut buf = MaybeUninit::<[u8; super::DEFAULT_BUF_SIZE]>::uninit(); - // FIXME(#53491): This is calling `get_mut` and `get_ref` on an uninitialized - // `MaybeUninit`. Revisit this once we decided whether that is valid or not. - // This is still technically undefined behavior due to creating a reference - // to uninitialized data, but within libstd we can rely on more guarantees - // than if this code were in an external lib. + // FIXME: #42788 + // + // - This creates a (mut) reference to a slice of + // _uninitialized_ integers, which is **undefined behavior** + // + // - Only the standard library gets to soundly "ignore" this, + // based on its privileged knowledge of unstable rustc + // internals; unsafe { - reader.initializer().initialize(buf.get_mut()); + reader.initializer().initialize(buf.assume_init_mut()); } let mut written = 0; loop { - let len = match reader.read(unsafe { buf.get_mut() }) { + let len = match reader.read(unsafe { buf.assume_init_mut() }) { Ok(0) => return Ok(written), Ok(len) => len, Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), }; - writer.write_all(unsafe { &buf.get_ref()[..len] })?; + writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?; written += len as u64; } } @@ -248,58 +254,33 @@ impl Write for Sink { } } -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Sink { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Sink { .. }") - } -} - -#[cfg(test)] -mod tests { - use crate::io::prelude::*; - use crate::io::{copy, empty, repeat, sink}; - - #[test] - fn copy_copies() { - let mut r = repeat(0).take(4); - let mut w = sink(); - assert_eq!(copy(&mut r, &mut w).unwrap(), 4); - - let mut r = repeat(0).take(1 << 17); - assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); +#[stable(feature = "write_mt", since = "1.48.0")] +impl Write for &Sink { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) } - #[test] - fn sink_sinks() { - let mut s = sink(); - assert_eq!(s.write(&[]).unwrap(), 0); - assert_eq!(s.write(&[0]).unwrap(), 1); - assert_eq!(s.write(&[0; 1024]).unwrap(), 1024); - assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024); + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) } - #[test] - fn empty_reads() { - let mut e = empty(); - assert_eq!(e.read(&mut []).unwrap(), 0); - assert_eq!(e.read(&mut [0]).unwrap(), 0); - assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); - assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0); + #[inline] + fn is_write_vectored(&self) -> bool { + true } - #[test] - fn repeat_repeats() { - let mut r = repeat(4); - let mut b = [0; 1024]; - assert_eq!(r.read(&mut b).unwrap(), 1024); - assert!(b.iter().all(|b| *b == 4)); + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) } +} - #[test] - fn take_some_bytes() { - assert_eq!(repeat(4).take(100).bytes().count(), 100); - assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4); - assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20); +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Sink { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Sink { .. }") } } diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs new file mode 100644 index 0000000000..e5e32ecb40 --- /dev/null +++ b/library/std/src/io/util/tests.rs @@ -0,0 +1,45 @@ +use crate::io::prelude::*; +use crate::io::{copy, empty, repeat, sink}; + +#[test] +fn copy_copies() { + let mut r = repeat(0).take(4); + let mut w = sink(); + assert_eq!(copy(&mut r, &mut w).unwrap(), 4); + + let mut r = repeat(0).take(1 << 17); + assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); +} + +#[test] +fn sink_sinks() { + let mut s = sink(); + assert_eq!(s.write(&[]).unwrap(), 0); + assert_eq!(s.write(&[0]).unwrap(), 1); + assert_eq!(s.write(&[0; 1024]).unwrap(), 1024); + assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024); +} + +#[test] +fn empty_reads() { + let mut e = empty(); + assert_eq!(e.read(&mut []).unwrap(), 0); + assert_eq!(e.read(&mut [0]).unwrap(), 0); + assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); + assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0); +} + +#[test] +fn repeat_repeats() { + let mut r = repeat(4); + let mut b = [0; 1024]; + assert_eq!(r.read(&mut b).unwrap(), 1024); + assert!(b.iter().all(|b| *b == 4)); +} + +#[test] +fn take_some_bytes() { + assert_eq!(repeat(4).take(100).bytes().count(), 100); + assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4); + assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20); +} diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index af25c39fcc..54ce0e7b83 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -107,7 +107,7 @@ mod break_keyword {} /// Sometimes a certain value is used many times throughout a program, and it can become /// inconvenient to copy it over and over. What's more, it's not always possible or desirable to /// make it a variable that gets carried around to each function that needs it. In these cases, the -/// `const` keyword provides a convenient alternative to code duplication. +/// `const` keyword provides a convenient alternative to code duplication: /// /// ```rust /// const THING: u32 = 0xABAD1DEA; @@ -115,10 +115,12 @@ mod break_keyword {} /// let foo = 123 + THING; /// ``` /// -/// Constants must be explicitly typed, unlike with `let` you can't ignore its type and let the -/// compiler figure it out. Any constant value can be defined in a const, which in practice happens -/// to be most things that would be reasonable to have a constant (barring `const fn`s). For -/// example, you can't have a File as a `const`. +/// Constants must be explicitly typed; unlike with `let`, you can't ignore their type and let the +/// compiler figure it out. Any constant value can be defined in a `const`, which in practice happens +/// to be most things that would be reasonable to have in a constant (barring `const fn`s). For +/// example, you can't have a [`File`] as a `const`. +/// +/// [`File`]: crate::fs::File /// /// The only lifetime allowed in a constant is `'static`, which is the lifetime that encompasses /// all others in a Rust program. For example, if you wanted to define a constant string, it would @@ -128,7 +130,7 @@ mod break_keyword {} /// const WORDS: &'static str = "hello rust!"; /// ``` /// -/// Thanks to static lifetime elision, you usually don't have to explicitly use 'static: +/// Thanks to static lifetime elision, you usually don't have to explicitly use `'static`: /// /// ```rust /// const WORDS: &str = "hello convenience!"; @@ -136,19 +138,19 @@ mod break_keyword {} /// /// `const` items looks remarkably similar to `static` items, which introduces some confusion as /// to which one should be used at which times. To put it simply, constants are inlined wherever -/// they're used, making using them identical to simply replacing the name of the const with its -/// value. Static variables on the other hand point to a single location in memory, which all +/// they're used, making using them identical to simply replacing the name of the `const` with its +/// value. Static variables, on the other hand, point to a single location in memory, which all /// accesses share. This means that, unlike with constants, they can't have destructors, and act as /// a single value across the entire codebase. /// -/// Constants, as with statics, should always be in SCREAMING_SNAKE_CASE. +/// Constants, like statics, should always be in `SCREAMING_SNAKE_CASE`. /// /// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const -/// T` and `*mut T`. More about that can be read at the [pointer] primitive part of the Rust docs. +/// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive]. /// -/// For more detail on `const`, see the [Rust Book] or the [Reference] +/// For more detail on `const`, see the [Rust Book] or the [Reference]. /// -/// [pointer]: primitive.pointer.html +/// [pointer primitive]: primitive.pointer.html /// [Rust Book]: /// ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants /// [Reference]: ../reference/items/constant-items.html diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index f0548582d2..e0095e64fa 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -1,9 +1,13 @@ //! Lazy values and one-time initialization of static data. +#[cfg(test)] +mod tests; + use crate::{ cell::{Cell, UnsafeCell}, fmt, - mem::{self, MaybeUninit}, + marker::PhantomData, + mem::MaybeUninit, ops::{Deref, Drop}, panic::{RefUnwindSafe, UnwindSafe}, sync::Once, @@ -43,6 +47,26 @@ pub struct SyncOnceCell { once: Once, // Whether or not the value is initialized is tracked by `state_and_queue`. value: UnsafeCell>, + /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl. + /// + /// ```compile_fail,E0597 + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncOnceCell; + /// + /// struct A<'a>(&'a str); + /// + /// impl<'a> Drop for A<'a> { + /// fn drop(&mut self) {} + /// } + /// + /// let cell = SyncOnceCell::new(); + /// { + /// let s = String::new(); + /// let _ = cell.set(A(&s)); + /// } + /// ``` + _marker: PhantomData, } // Why do we need `T: Send`? @@ -116,7 +140,11 @@ impl SyncOnceCell { /// Creates a new empty cell. #[unstable(feature = "once_cell", issue = "74465")] pub const fn new() -> SyncOnceCell { - SyncOnceCell { once: Once::new(), value: UnsafeCell::new(MaybeUninit::uninit()) } + SyncOnceCell { + once: Once::new(), + value: UnsafeCell::new(MaybeUninit::uninit()), + _marker: PhantomData, + } } /// Gets the reference to the underlying value. @@ -265,7 +293,7 @@ impl SyncOnceCell { debug_assert!(self.is_initialized()); - // Safety: The inner value has been initialized + // SAFETY: The inner value has been initialized Ok(unsafe { self.get_unchecked() }) } @@ -288,13 +316,7 @@ impl SyncOnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn into_inner(mut self) -> Option { - // Safety: Safe because we immediately free `self` without dropping - let inner = unsafe { self.take_inner() }; - - // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set - // the state to uninitialized. - mem::ManuallyDrop::new(self); - inner + self.take() } /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state. @@ -320,22 +342,12 @@ impl SyncOnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn take(&mut self) -> Option { - mem::take(self).into_inner() - } - - /// Takes the wrapped value out of a `SyncOnceCell`. - /// Afterwards the cell is no longer initialized. - /// - /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell - /// are valid. Only used by `into_inner` and `drop`. - unsafe fn take_inner(&mut self) -> Option { - // The mutable reference guarantees there are no other threads that can observe us - // taking out the wrapped value. - // Right after this function `self` is supposed to be freed, so it makes little sense - // to atomically set the state to uninitialized. if self.is_initialized() { - let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit())); - Some(value.into_inner().assume_init()) + self.once = Once::new(); + // SAFETY: `self.value` is initialized and contains a valid `T`. + // `self.once` is reset, so `is_initialized()` will be false again + // which prevents the value from being read twice. + unsafe { Some((&mut *self.value.get()).assume_init_read()) } } else { None } @@ -376,21 +388,24 @@ impl SyncOnceCell { /// Safety: The value must be initialized unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); - (&*self.value.get()).get_ref() + (&*self.value.get()).assume_init_ref() } /// Safety: The value must be initialized unsafe fn get_unchecked_mut(&mut self) -> &mut T { debug_assert!(self.is_initialized()); - (&mut *self.value.get()).get_mut() + (&mut *self.value.get()).assume_init_mut() } } unsafe impl<#[may_dangle] T> Drop for SyncOnceCell { fn drop(&mut self) { - // Safety: The cell is being dropped, so it can't be accessed again. - // We also don't touch the `T`, which validates our usage of #[may_dangle]. - unsafe { self.take_inner() }; + if self.is_initialized() { + // Safety: The cell is initialized and being dropped, so it can't + // be accessed again. We also don't touch the `T` other than + // dropping it, which validates our usage of #[may_dangle]. + unsafe { (&mut *self.value.get()).assume_init_drop() }; + } } } @@ -506,333 +521,3 @@ impl Default for SyncLazy { SyncLazy::new(T::default) } } - -#[cfg(test)] -mod tests { - use crate::{ - lazy::{Lazy, SyncLazy, SyncOnceCell}, - panic, - sync::{ - atomic::{AtomicUsize, Ordering::SeqCst}, - mpsc::channel, - Mutex, - }, - thread, - }; - - #[test] - fn lazy_default() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - - struct Foo(u8); - impl Default for Foo { - fn default() -> Self { - CALLED.fetch_add(1, SeqCst); - Foo(42) - } - } - - let lazy: Lazy> = <_>::default(); - - assert_eq!(CALLED.load(SeqCst), 0); - - assert_eq!(lazy.lock().unwrap().0, 42); - assert_eq!(CALLED.load(SeqCst), 1); - - lazy.lock().unwrap().0 = 21; - - assert_eq!(lazy.lock().unwrap().0, 21); - assert_eq!(CALLED.load(SeqCst), 1); - } - - #[test] - fn lazy_poisoning() { - let x: Lazy = Lazy::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); - assert!(res.is_err()); - } - } - - fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { - thread::spawn(f).join().unwrap() - } - - #[test] - fn sync_once_cell() { - static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); - - assert!(ONCE_CELL.get().is_none()); - - spawn_and_wait(|| { - ONCE_CELL.get_or_init(|| 92); - assert_eq!(ONCE_CELL.get(), Some(&92)); - }); - - ONCE_CELL.get_or_init(|| panic!("Kabom!")); - assert_eq!(ONCE_CELL.get(), Some(&92)); - } - - #[test] - fn sync_once_cell_get_mut() { - let mut c = SyncOnceCell::new(); - assert!(c.get_mut().is_none()); - c.set(90).unwrap(); - *c.get_mut().unwrap() += 2; - assert_eq!(c.get_mut(), Some(&mut 92)); - } - - #[test] - fn sync_once_cell_get_unchecked() { - let c = SyncOnceCell::new(); - c.set(92).unwrap(); - unsafe { - assert_eq!(c.get_unchecked(), &92); - } - } - - #[test] - fn sync_once_cell_drop() { - static DROP_CNT: AtomicUsize = AtomicUsize::new(0); - struct Dropper; - impl Drop for Dropper { - fn drop(&mut self) { - DROP_CNT.fetch_add(1, SeqCst); - } - } - - let x = SyncOnceCell::new(); - spawn_and_wait(move || { - x.get_or_init(|| Dropper); - assert_eq!(DROP_CNT.load(SeqCst), 0); - drop(x); - }); - - assert_eq!(DROP_CNT.load(SeqCst), 1); - } - - #[test] - fn sync_once_cell_drop_empty() { - let x = SyncOnceCell::::new(); - drop(x); - } - - #[test] - fn clone() { - let s = SyncOnceCell::new(); - let c = s.clone(); - assert!(c.get().is_none()); - - s.set("hello".to_string()).unwrap(); - let c = s.clone(); - assert_eq!(c.get().map(String::as_str), Some("hello")); - } - - #[test] - fn get_or_try_init() { - let cell: SyncOnceCell = SyncOnceCell::new(); - assert!(cell.get().is_none()); - - let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); - assert!(res.is_err()); - assert!(!cell.is_initialized()); - assert!(cell.get().is_none()); - - assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); - - assert_eq!( - cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), - Ok(&"hello".to_string()) - ); - assert_eq!(cell.get(), Some(&"hello".to_string())); - } - - #[test] - fn from_impl() { - assert_eq!(SyncOnceCell::from("value").get(), Some(&"value")); - assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar")); - } - - #[test] - fn partialeq_impl() { - assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value")); - assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar")); - - assert!(SyncOnceCell::::new() == SyncOnceCell::new()); - assert!(SyncOnceCell::::new() != SyncOnceCell::from("value".to_owned())); - } - - #[test] - fn into_inner() { - let cell: SyncOnceCell = SyncOnceCell::new(); - assert_eq!(cell.into_inner(), None); - let cell = SyncOnceCell::new(); - cell.set("hello".to_string()).unwrap(); - assert_eq!(cell.into_inner(), Some("hello".to_string())); - } - - #[test] - fn sync_lazy_new() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - static SYNC_LAZY: SyncLazy = SyncLazy::new(|| { - CALLED.fetch_add(1, SeqCst); - 92 - }); - - assert_eq!(CALLED.load(SeqCst), 0); - - spawn_and_wait(|| { - let y = *SYNC_LAZY - 30; - assert_eq!(y, 62); - assert_eq!(CALLED.load(SeqCst), 1); - }); - - let y = *SYNC_LAZY - 30; - assert_eq!(y, 62); - assert_eq!(CALLED.load(SeqCst), 1); - } - - #[test] - fn sync_lazy_default() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - - struct Foo(u8); - impl Default for Foo { - fn default() -> Self { - CALLED.fetch_add(1, SeqCst); - Foo(42) - } - } - - let lazy: SyncLazy> = <_>::default(); - - assert_eq!(CALLED.load(SeqCst), 0); - - assert_eq!(lazy.lock().unwrap().0, 42); - assert_eq!(CALLED.load(SeqCst), 1); - - lazy.lock().unwrap().0 = 21; - - assert_eq!(lazy.lock().unwrap().0, 21); - assert_eq!(CALLED.load(SeqCst), 1); - } - - #[test] - fn static_sync_lazy() { - static XS: SyncLazy> = SyncLazy::new(|| { - let mut xs = Vec::new(); - xs.push(1); - xs.push(2); - xs.push(3); - xs - }); - - spawn_and_wait(|| { - assert_eq!(&*XS, &vec![1, 2, 3]); - }); - - assert_eq!(&*XS, &vec![1, 2, 3]); - } - - #[test] - fn static_sync_lazy_via_fn() { - fn xs() -> &'static Vec { - static XS: SyncOnceCell> = SyncOnceCell::new(); - XS.get_or_init(|| { - let mut xs = Vec::new(); - xs.push(1); - xs.push(2); - xs.push(3); - xs - }) - } - assert_eq!(xs(), &vec![1, 2, 3]); - } - - #[test] - fn sync_lazy_poisoning() { - let x: SyncLazy = SyncLazy::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(|| x.len()); - assert!(res.is_err()); - } - } - - #[test] - fn is_sync_send() { - fn assert_traits() {} - assert_traits::>(); - assert_traits::>(); - } - - #[test] - fn eval_once_macro() { - macro_rules! eval_once { - (|| -> $ty:ty { - $($body:tt)* - }) => {{ - static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new(); - fn init() -> $ty { - $($body)* - } - ONCE_CELL.get_or_init(init) - }}; - } - - let fib: &'static Vec = eval_once! { - || -> Vec { - let mut res = vec![1, 1]; - for i in 0..10 { - let next = res[i] + res[i + 1]; - res.push(next); - } - res - } - }; - assert_eq!(fib[5], 8) - } - - #[test] - fn sync_once_cell_does_not_leak_partially_constructed_boxes() { - static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); - - let n_readers = 10; - let n_writers = 3; - const MSG: &str = "Hello, World"; - - let (tx, rx) = channel(); - - for _ in 0..n_readers { - let tx = tx.clone(); - thread::spawn(move || { - loop { - if let Some(msg) = ONCE_CELL.get() { - tx.send(msg).unwrap(); - break; - } - #[cfg(target_env = "sgx")] - crate::thread::yield_now(); - } - }); - } - for _ in 0..n_writers { - thread::spawn(move || { - let _ = ONCE_CELL.set(MSG.to_owned()); - }); - } - - for _ in 0..n_readers { - let msg = rx.recv().unwrap(); - assert_eq!(msg, MSG); - } - } - - #[test] - fn dropck() { - let cell = SyncOnceCell::new(); - { - let s = String::new(); - cell.set(&s).unwrap(); - } - } -} diff --git a/library/std/src/lazy/tests.rs b/library/std/src/lazy/tests.rs new file mode 100644 index 0000000000..a170edbd99 --- /dev/null +++ b/library/std/src/lazy/tests.rs @@ -0,0 +1,323 @@ +use crate::{ + lazy::{Lazy, SyncLazy, SyncOnceCell}, + panic, + sync::{ + atomic::{AtomicUsize, Ordering::SeqCst}, + mpsc::channel, + Mutex, + }, + thread, +}; + +#[test] +fn lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: Lazy> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); +} + +#[test] +fn lazy_poisoning() { + let x: Lazy = Lazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); + assert!(res.is_err()); + } +} + +fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { + thread::spawn(f).join().unwrap() +} + +#[test] +fn sync_once_cell() { + static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); + + assert!(ONCE_CELL.get().is_none()); + + spawn_and_wait(|| { + ONCE_CELL.get_or_init(|| 92); + assert_eq!(ONCE_CELL.get(), Some(&92)); + }); + + ONCE_CELL.get_or_init(|| panic!("Kabom!")); + assert_eq!(ONCE_CELL.get(), Some(&92)); +} + +#[test] +fn sync_once_cell_get_mut() { + let mut c = SyncOnceCell::new(); + assert!(c.get_mut().is_none()); + c.set(90).unwrap(); + *c.get_mut().unwrap() += 2; + assert_eq!(c.get_mut(), Some(&mut 92)); +} + +#[test] +fn sync_once_cell_get_unchecked() { + let c = SyncOnceCell::new(); + c.set(92).unwrap(); + unsafe { + assert_eq!(c.get_unchecked(), &92); + } +} + +#[test] +fn sync_once_cell_drop() { + static DROP_CNT: AtomicUsize = AtomicUsize::new(0); + struct Dropper; + impl Drop for Dropper { + fn drop(&mut self) { + DROP_CNT.fetch_add(1, SeqCst); + } + } + + let x = SyncOnceCell::new(); + spawn_and_wait(move || { + x.get_or_init(|| Dropper); + assert_eq!(DROP_CNT.load(SeqCst), 0); + drop(x); + }); + + assert_eq!(DROP_CNT.load(SeqCst), 1); +} + +#[test] +fn sync_once_cell_drop_empty() { + let x = SyncOnceCell::::new(); + drop(x); +} + +#[test] +fn clone() { + let s = SyncOnceCell::new(); + let c = s.clone(); + assert!(c.get().is_none()); + + s.set("hello".to_string()).unwrap(); + let c = s.clone(); + assert_eq!(c.get().map(String::as_str), Some("hello")); +} + +#[test] +fn get_or_try_init() { + let cell: SyncOnceCell = SyncOnceCell::new(); + assert!(cell.get().is_none()); + + let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); + assert!(res.is_err()); + assert!(!cell.is_initialized()); + assert!(cell.get().is_none()); + + assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + + assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string())); + assert_eq!(cell.get(), Some(&"hello".to_string())); +} + +#[test] +fn from_impl() { + assert_eq!(SyncOnceCell::from("value").get(), Some(&"value")); + assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar")); +} + +#[test] +fn partialeq_impl() { + assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value")); + assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar")); + + assert!(SyncOnceCell::::new() == SyncOnceCell::new()); + assert!(SyncOnceCell::::new() != SyncOnceCell::from("value".to_owned())); +} + +#[test] +fn into_inner() { + let cell: SyncOnceCell = SyncOnceCell::new(); + assert_eq!(cell.into_inner(), None); + let cell = SyncOnceCell::new(); + cell.set("hello".to_string()).unwrap(); + assert_eq!(cell.into_inner(), Some("hello".to_string())); +} + +#[test] +fn sync_lazy_new() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + static SYNC_LAZY: SyncLazy = SyncLazy::new(|| { + CALLED.fetch_add(1, SeqCst); + 92 + }); + + assert_eq!(CALLED.load(SeqCst), 0); + + spawn_and_wait(|| { + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); + }); + + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); +} + +#[test] +fn sync_lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: SyncLazy> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); +} + +#[test] +fn static_sync_lazy() { + static XS: SyncLazy> = SyncLazy::new(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }); + + spawn_and_wait(|| { + assert_eq!(&*XS, &vec![1, 2, 3]); + }); + + assert_eq!(&*XS, &vec![1, 2, 3]); +} + +#[test] +fn static_sync_lazy_via_fn() { + fn xs() -> &'static Vec { + static XS: SyncOnceCell> = SyncOnceCell::new(); + XS.get_or_init(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }) + } + assert_eq!(xs(), &vec![1, 2, 3]); +} + +#[test] +fn sync_lazy_poisoning() { + let x: SyncLazy = SyncLazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(|| x.len()); + assert!(res.is_err()); + } +} + +#[test] +fn is_sync_send() { + fn assert_traits() {} + assert_traits::>(); + assert_traits::>(); +} + +#[test] +fn eval_once_macro() { + macro_rules! eval_once { + (|| -> $ty:ty { + $($body:tt)* + }) => {{ + static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new(); + fn init() -> $ty { + $($body)* + } + ONCE_CELL.get_or_init(init) + }}; + } + + let fib: &'static Vec = eval_once! { + || -> Vec { + let mut res = vec![1, 1]; + for i in 0..10 { + let next = res[i] + res[i + 1]; + res.push(next); + } + res + } + }; + assert_eq!(fib[5], 8) +} + +#[test] +fn sync_once_cell_does_not_leak_partially_constructed_boxes() { + static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); + + let n_readers = 10; + let n_writers = 3; + const MSG: &str = "Hello, World"; + + let (tx, rx) = channel(); + + for _ in 0..n_readers { + let tx = tx.clone(); + thread::spawn(move || { + loop { + if let Some(msg) = ONCE_CELL.get() { + tx.send(msg).unwrap(); + break; + } + #[cfg(target_env = "sgx")] + crate::thread::yield_now(); + } + }); + } + for _ in 0..n_writers { + thread::spawn(move || { + let _ = ONCE_CELL.set(MSG.to_owned()); + }); + } + + for _ in 0..n_readers { + let msg = rx.recv().unwrap(); + assert_eq!(msg, MSG); + } +} + +#[test] +fn dropck() { + let cell = SyncOnceCell::new(); + { + let s = String::new(); + cell.set(&s).unwrap(); + } +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 1142b74ff0..b2bd5f4da5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -226,9 +226,9 @@ #![feature(asm)] #![feature(associated_type_bounds)] #![feature(atomic_mut_ptr)] +#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(c_variadic)] -#![feature(can_vector)] #![feature(cfg_accessible)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] @@ -237,17 +237,23 @@ #![feature(clamp)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] +#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))] #![feature(const_fn_transmute)] +#![feature(const_fn)] +#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))] +#![feature(const_ip)] +#![feature(const_ipv6)] #![feature(const_raw_ptr_deref)] +#![feature(const_ipv4)] #![feature(container_error_extra)] #![feature(core_intrinsics)] #![feature(custom_test_frameworks)] #![feature(decl_macro)] -#![feature(doc_alias)] +#![cfg_attr(bootstrap, feature(doc_alias))] #![feature(doc_cfg)] #![feature(doc_keyword)] #![feature(doc_masked)] -#![cfg_attr(not(bootstrap), feature(doc_spotlight))] +#![feature(doc_spotlight)] #![feature(dropck_eyepatch)] #![feature(duration_constants)] #![feature(exact_size_is_empty)] @@ -256,18 +262,15 @@ #![feature(external_doc)] #![feature(fn_traits)] #![feature(format_args_nl)] -#![feature(future_readiness_fns)] #![feature(gen_future)] #![feature(generator_trait)] #![feature(global_asm)] -#![feature(hash_raw_entry)] #![feature(hashmap_internals)] #![feature(int_error_internals)] #![feature(int_error_matching)] #![feature(integer_atomics)] #![feature(into_future)] #![feature(lang_items)] -#![feature(libc)] #![feature(link_args)] #![feature(linkage)] #![feature(llvm_asm)] @@ -308,12 +311,15 @@ #![feature(str_internals)] #![feature(test)] #![feature(thread_local)] +#![feature(thread_local_internals)] #![feature(toowned_clone_into)] #![feature(total_cmp)] #![feature(trace_macros)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unsafe_block_in_unsafe_fn)] +#![feature(unsafe_cell_get_mut)] +#![feature(unsafe_cell_raw_get)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] diff --git a/library/std/src/memchr.rs b/library/std/src/memchr.rs index d69294b2d2..86a08f75a8 100644 --- a/library/std/src/memchr.rs +++ b/library/std/src/memchr.rs @@ -1,6 +1,9 @@ // Original implementation taken from rust-memchr. // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch +#[cfg(test)] +mod tests; + /// A safe interface to `memchr`. /// /// Returns the index corresponding to the first occurrence of `needle` in @@ -44,90 +47,3 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option { pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { crate::sys::memchr::memrchr(needle, haystack) } - -#[cfg(test)] -mod tests { - // test the implementations for the current platform - use super::{memchr, memrchr}; - - #[test] - fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); - } - - #[test] - fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); - } - - #[test] - fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); - } - - #[test] - fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); - } - - #[test] - fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); - } - - #[test] - fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); - } - - #[test] - fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); - } - - #[test] - fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); - } - - #[test] - fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); - } - - #[test] - fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); - } - - #[test] - fn each_alignment() { - let mut data = [1u8; 64]; - let needle = 2; - let pos = 40; - data[pos] = needle; - for start in 0..16 { - assert_eq!(Some(pos - start), memchr(needle, &data[start..])); - } - } -} diff --git a/library/std/src/memchr/tests.rs b/library/std/src/memchr/tests.rs new file mode 100644 index 0000000000..557d749c7f --- /dev/null +++ b/library/std/src/memchr/tests.rs @@ -0,0 +1,86 @@ +// Original implementation taken from rust-memchr. +// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch + +// test the implementations for the current platform +use super::{memchr, memrchr}; + +#[test] +fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); +} + +#[test] +fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); +} + +#[test] +fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); +} + +#[test] +fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); +} + +#[test] +fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); +} + +#[test] +fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); +} + +#[test] +fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); +} + +#[test] +fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); +} + +#[test] +fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); +} + +#[test] +fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); +} + +#[test] +fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); +} + +#[test] +fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); +} + +#[test] +fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); +} + +#[test] +fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); +} + +#[test] +fn each_alignment() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memchr(needle, &data[start..])); + } +} diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index d7d96862b2..e213963d25 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::cmp::Ordering; use crate::convert::TryInto; use crate::fmt; @@ -210,8 +213,6 @@ impl SocketAddr { /// /// [IP address]: IpAddr /// [`IPv4` address]: IpAddr::V4 - /// [`false`]: ../../std/primitive.bool.html - /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -232,8 +233,6 @@ impl SocketAddr { /// /// [IP address]: IpAddr /// [`IPv6` address]: IpAddr::V6 - /// [`false`]: ../../std/primitive.bool.html - /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -746,9 +745,9 @@ impl hash::Hash for SocketAddrV6 { /// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: /// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// -/// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation +/// * `(`[`&str`]`, `[`u16`]`)`: [`&str`] should be either a string representation /// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host -/// name. +/// 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 @@ -991,236 +990,3 @@ impl ToSocketAddrs for String { (&**self).to_socket_addrs() } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - 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: &'static 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!("{:<20}", socket), "192.168.0.1:8080 "); - assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080"); - assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 "); - assert_eq!(format!("{:.10}", socket), "192.168.0."); - } - - #[test] - fn socket_v6_to_str() { - let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap(); - - assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::"); - } - - #[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/addr/tests.rs b/library/std/src/net/addr/tests.rs new file mode 100644 index 0000000000..cee9087e13 --- /dev/null +++ b/library/std/src/net/addr/tests.rs @@ -0,0 +1,229 @@ +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: &'static 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!("{:<20}", socket), "192.168.0.1:8080 "); + assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080"); + assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 "); + assert_eq!(format!("{:.10}", socket), "192.168.0."); +} + +#[test] +fn socket_v6_to_str() { + let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap(); + + assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::"); +} + +#[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/ip.rs b/library/std/src/net/ip.rs index 85bb6b60e6..f01a7b72a6 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -6,6 +6,10 @@ issue = "27709" )] +// 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::hash; @@ -136,8 +140,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_unspecified()`] and /// [`Ipv6Addr::is_unspecified()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -146,8 +148,9 @@ impl IpAddr { /// 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_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_unspecified(&self) -> bool { + pub const fn is_unspecified(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_unspecified(), IpAddr::V6(ip) => ip.is_unspecified(), @@ -159,8 +162,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_loopback()`] and /// [`Ipv6Addr::is_loopback()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -169,8 +170,9 @@ impl IpAddr { /// 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_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_loopback(&self) -> bool { + pub const fn is_loopback(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_loopback(), IpAddr::V6(ip) => ip.is_loopback(), @@ -182,8 +184,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_global()`] and /// [`Ipv6Addr::is_global()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -194,7 +194,8 @@ impl IpAddr { /// 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); /// ``` - pub fn is_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + pub const fn is_global(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_global(), IpAddr::V6(ip) => ip.is_global(), @@ -206,8 +207,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_multicast()`] and /// [`Ipv6Addr::is_multicast()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -216,8 +215,9 @@ impl IpAddr { /// 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_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_multicast(&self) -> bool { + pub const fn is_multicast(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_multicast(), IpAddr::V6(ip) => ip.is_multicast(), @@ -229,8 +229,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_documentation()`] and /// [`Ipv6Addr::is_documentation()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -244,7 +242,8 @@ impl IpAddr { /// true /// ); /// ``` - pub fn is_documentation(&self) -> bool { + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + pub const fn is_documentation(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_documentation(), IpAddr::V6(ip) => ip.is_documentation(), @@ -254,8 +253,6 @@ impl IpAddr { /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] /// otherwise. /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html /// [`IPv4` address]: IpAddr::V4 /// /// # Examples @@ -274,8 +271,6 @@ impl IpAddr { /// Returns [`true`] if this address is an [`IPv6` address], and [`false`] /// otherwise. /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html /// [`IPv6` address]: IpAddr::V6 /// /// # Examples @@ -361,8 +356,9 @@ impl Ipv4Addr { /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!(addr.octets(), [127, 0, 0, 1]); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn octets(&self) -> [u8; 4] { + pub const fn octets(&self) -> [u8; 4] { // This returns the order we want because s_addr is stored in big-endian. self.inner.s_addr.to_ne_bytes() } @@ -372,7 +368,6 @@ impl Ipv4Addr { /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7]. /// - /// [`true`]: ../../std/primitive.bool.html /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html /// /// # Examples @@ -393,7 +388,6 @@ impl Ipv4Addr { /// /// This property is defined by [IETF RFC 1122]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 /// /// # Examples @@ -404,8 +398,9 @@ impl 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_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_loopback(&self) -> bool { + pub const fn is_loopback(&self) -> bool { self.octets()[0] == 127 } @@ -417,7 +412,6 @@ impl Ipv4Addr { /// - 172.16.0.0/12 /// - 192.168.0.0/16 /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 /// /// # Examples @@ -433,8 +427,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_private(&self) -> bool { + pub const fn is_private(&self) -> bool { match self.octets() { [10, ..] => true, [172, b, ..] if b >= 16 && b <= 31 => true, @@ -447,7 +442,6 @@ impl Ipv4Addr { /// /// This property is defined by [IETF RFC 3927]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 /// /// # Examples @@ -459,8 +453,9 @@ impl Ipv4Addr { /// 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_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_link_local(&self) -> bool { + pub const fn is_link_local(&self) -> bool { match self.octets() { [169, 254, ..] => true, _ => false, @@ -486,8 +481,6 @@ impl Ipv4Addr { /// - addresses reserved for networking devices benchmarking (see /// [`Ipv4Addr::is_benchmarking()`]) /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml /// /// # Examples @@ -538,10 +531,13 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); /// ``` - pub fn is_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + 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(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a { + if u32::from_be_bytes(self.octets()) == 0xc0000009 + || u32::from_be_bytes(self.octets()) == 0xc000000a + { return true; } !self.is_private() @@ -560,7 +556,6 @@ impl Ipv4Addr { /// Returns [`true`] if this address is part of the Shared Address Space defined in /// [IETF RFC 6598] (`100.64.0.0/10`). /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 /// /// # Examples @@ -573,7 +568,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); /// ``` - pub fn is_shared(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) } @@ -586,7 +582,6 @@ impl Ipv4Addr { /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723]) /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155]) /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890 /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600 /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723 @@ -605,7 +600,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); /// ``` - pub fn is_ietf_protocol_assignment(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 } @@ -613,7 +609,6 @@ impl Ipv4Addr { /// 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`. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 /// [errata 423]: https://www.rfc-editor.org/errata/eid423 /// @@ -628,7 +623,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); /// ``` - pub fn is_benchmarking(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 } @@ -637,7 +633,6 @@ impl Ipv4Addr { /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since /// it is obviously not reserved for future use. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 /// /// # Warning @@ -660,7 +655,8 @@ impl Ipv4Addr { /// // 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); /// ``` - pub fn is_reserved(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() } @@ -669,7 +665,6 @@ impl Ipv4Addr { /// Multicast addresses have a most significant octet between 224 and 239, /// and is defined by [IETF RFC 5771]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 /// /// # Examples @@ -681,8 +676,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_multicast(&self) -> bool { + pub const fn is_multicast(&self) -> bool { self.octets()[0] >= 224 && self.octets()[0] <= 239 } @@ -690,7 +686,6 @@ impl Ipv4Addr { /// /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 /// /// # Examples @@ -701,9 +696,10 @@ impl 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_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_broadcast(&self) -> bool { - self == &Self::BROADCAST + 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. @@ -714,7 +710,6 @@ impl Ipv4Addr { /// - 198.51.100.0/24 (TEST-NET-2) /// - 203.0.113.0/24 (TEST-NET-3) /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 /// /// # Examples @@ -727,8 +722,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_documentation(&self) -> bool { + pub const fn is_documentation(&self) -> bool { match self.octets() { [192, 0, 2, _] => true, [198, 51, 100, _] => true, @@ -741,6 +737,9 @@ impl Ipv4Addr { /// /// a.b.c.d becomes ::a.b.c.d /// + /// This isn't typically the method you want; these addresses don't typically + /// function on modern systems. Use `to_ipv6_mapped` instead. + /// /// [`IPv6` address]: Ipv6Addr /// /// # Examples @@ -753,10 +752,13 @@ impl Ipv4Addr { /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) /// ); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv6_compatible(&self) -> Ipv6Addr { + pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d]) + Ipv6Addr { + inner: c::in6_addr { s6_addr: [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]. @@ -773,10 +775,13 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv6_mapped(&self) -> Ipv6Addr { + pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d]) + Ipv6Addr { + inner: c::in6_addr { s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] }, + } } } @@ -1098,8 +1103,9 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn segments(&self) -> [u16; 8] { + pub const fn segments(&self) -> [u16; 8] { // All elements in `s6_addr` 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.inner.s6_addr) }; @@ -1120,7 +1126,6 @@ impl Ipv6Addr { /// /// This property is defined in [IETF RFC 4291]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples @@ -1131,16 +1136,16 @@ impl 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_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_unspecified(&self) -> bool { - self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] + 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 a loopback address (::1). /// /// This property is defined in [IETF RFC 4291]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples @@ -1151,9 +1156,10 @@ impl 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_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_loopback(&self) -> bool { - self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] + 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. @@ -1164,9 +1170,6 @@ impl Ipv6Addr { /// - link-local and unique local unicast addresses /// - interface-, link-, realm-, admin- and site-local multicast addresses /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -1178,7 +1181,8 @@ impl Ipv6Addr { /// 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); /// ``` - pub fn is_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_global(&self) -> bool { match self.multicast_scope() { Some(Ipv6MulticastScope::Global) => true, None => self.is_unicast_global(), @@ -1192,8 +1196,6 @@ impl Ipv6Addr { /// /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -1204,7 +1206,8 @@ impl 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); /// ``` - pub fn is_unique_local(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } @@ -1225,8 +1228,6 @@ impl Ipv6Addr { /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. /// If you need a less strict validation use [`Ipv6Addr::is_unicast_link_local()`] instead. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -1259,7 +1260,8 @@ impl Ipv6Addr { /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - pub fn is_unicast_link_local_strict(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_link_local_strict(&self) -> bool { (self.segments()[0] & 0xffff) == 0xfe80 && (self.segments()[1] & 0xffff) == 0 && (self.segments()[2] & 0xffff) == 0 @@ -1284,8 +1286,6 @@ impl Ipv6Addr { /// If you need a strict validation fully compliant with the RFC, use /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -1316,7 +1316,8 @@ impl Ipv6Addr { /// /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - pub fn is_unicast_link_local(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } @@ -1331,7 +1332,6 @@ impl Ipv6Addr { /// +----------+-------------------------+----------------------------+ /// ``` /// - /// [`true`]: ../../std/primitive.bool.html /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 /// /// # Examples @@ -1355,7 +1355,8 @@ impl Ipv6Addr { /// addresses. /// /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 - pub fn is_unicast_site_local(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 } @@ -1364,7 +1365,6 @@ impl Ipv6Addr { /// /// This property is defined in [IETF RFC 3849]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 /// /// # Examples @@ -1377,7 +1377,8 @@ impl 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); /// ``` - pub fn is_documentation(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } @@ -1399,7 +1400,6 @@ impl Ipv6Addr { /// Global Unicast). /// ``` /// - /// [`true`]: ../../std/primitive.bool.html /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 /// /// # Examples @@ -1412,7 +1412,8 @@ impl 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); /// ``` - pub fn is_unicast_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_global(&self) -> bool { !self.is_multicast() && !self.is_loopback() && !self.is_unicast_link_local() @@ -1436,7 +1437,8 @@ impl Ipv6Addr { /// ); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); /// ``` - pub fn multicast_scope(&self) -> Option { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn multicast_scope(&self) -> Option { if self.is_multicast() { match self.segments()[0] & 0x000f { 1 => Some(Ipv6MulticastScope::InterfaceLocal), @@ -1457,7 +1459,6 @@ impl Ipv6Addr { /// /// This property is defined by [IETF RFC 4291]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples @@ -1468,8 +1469,9 @@ impl 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_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_multicast(&self) -> bool { + pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 } @@ -1494,7 +1496,8 @@ impl Ipv6Addr { /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` - pub fn to_ipv4_mapped(&self) -> Option { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + 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)) @@ -1521,8 +1524,9 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), /// Some(Ipv4Addr::new(0, 0, 0, 1))); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv4(&self) -> Option { + 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(); @@ -1895,862 +1899,3 @@ impl From<[u16; 8]> for IpAddr { IpAddr::V6(Ipv6Addr::from(segments)) } } - -// Tests for this module -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - 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); - } - - #[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()); - } - - #[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; - - 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()); - } - }}; - } - - 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; - - 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"); - check!("198.18.54.2"); - check!("198.19.255.255"); - // 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!("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 ietf_protocol_assignment: u16 = 1 << 9; - 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 & ietf_protocol_assignment) == ietf_protocol_assignment { - assert!(ip!($s).is_ietf_protocol_assignment()); - } else { - assert!(!ip!($s).is_ietf_protocol_assignment()); - } - - 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 ietf_protocol_assignment: u16 = 1 << 9; - 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", ietf_protocol_assignment); - check!("192.0.0.255", ietf_protocol_assignment); - check!("192.0.0.100", ietf_protocol_assignment); - 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: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let unique_local: u16 = 1 << 2; - let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_link_local_strict: u16 = 1 << 5; - let unicast_site_local: u16 = 1 << 6; - let unicast_global: u16 = 1 << 7; - let documentation: u16 = 1 << 8; - let multicast_interface_local: u16 = 1 << 9; - let multicast_link_local: u16 = 1 << 10; - let multicast_realm_local: u16 = 1 << 11; - let multicast_admin_local: u16 = 1 << 12; - let multicast_site_local: u16 = 1 << 13; - let multicast_organization_local: u16 = 1 << 14; - let multicast_global: u16 = 1 << 15; - let multicast: u16 = 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_link_local_strict) == unicast_link_local_strict { - assert!(ip!($s).is_unicast_link_local_strict()); - } else { - assert!(!ip!($s).is_unicast_link_local_strict()); - } - if ($mask & unicast_site_local) == unicast_site_local { - assert!(ip!($s).is_unicast_site_local()); - } else { - assert!(!ip!($s).is_unicast_site_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 & 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: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let unique_local: u16 = 1 << 2; - let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_link_local_strict: u16 = 1 << 5; - let unicast_site_local: u16 = 1 << 6; - let unicast_global: u16 = 1 << 7; - let documentation: u16 = 1 << 8; - let multicast_interface_local: u16 = 1 << 9; - let multicast_link_local: u16 = 1 << 10; - let multicast_realm_local: u16 = 1 << 11; - let multicast_admin_local: u16 = 1 << 12; - let multicast_site_local: u16 = 1 << 13; - let multicast_organization_local: u16 = 1 << 14; - let multicast_global: u16 = 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 | unicast_link_local_strict - ); - - 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 | unicast_link_local_strict - ); - - 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_site_local | 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!( - "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_contructors() { - 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()); - } -} diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs new file mode 100644 index 0000000000..d9fbdd1b5e --- /dev/null +++ b/library/std/src/net/ip/tests.rs @@ -0,0 +1,939 @@ +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); +} + +#[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()); +} + +#[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; + + 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()); + } + }}; + } + + 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; + + 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"); + check!("198.18.54.2"); + check!("198.19.255.255"); + // 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!("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 ietf_protocol_assignment: u16 = 1 << 9; + 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 & ietf_protocol_assignment) == ietf_protocol_assignment { + assert!(ip!($s).is_ietf_protocol_assignment()); + } else { + assert!(!ip!($s).is_ietf_protocol_assignment()); + } + + 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 ietf_protocol_assignment: u16 = 1 << 9; + 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", ietf_protocol_assignment); + check!("192.0.0.255", ietf_protocol_assignment); + check!("192.0.0.100", ietf_protocol_assignment); + 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: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let unique_local: u16 = 1 << 2; + let global: u16 = 1 << 3; + let unicast_link_local: u16 = 1 << 4; + let unicast_link_local_strict: u16 = 1 << 5; + let unicast_site_local: u16 = 1 << 6; + let unicast_global: u16 = 1 << 7; + let documentation: u16 = 1 << 8; + let multicast_interface_local: u16 = 1 << 9; + let multicast_link_local: u16 = 1 << 10; + let multicast_realm_local: u16 = 1 << 11; + let multicast_admin_local: u16 = 1 << 12; + let multicast_site_local: u16 = 1 << 13; + let multicast_organization_local: u16 = 1 << 14; + let multicast_global: u16 = 1 << 15; + let multicast: u16 = 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_link_local_strict) == unicast_link_local_strict { + assert!(ip!($s).is_unicast_link_local_strict()); + } else { + assert!(!ip!($s).is_unicast_link_local_strict()); + } + if ($mask & unicast_site_local) == unicast_site_local { + assert!(ip!($s).is_unicast_site_local()); + } else { + assert!(!ip!($s).is_unicast_site_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 & 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: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let unique_local: u16 = 1 << 2; + let global: u16 = 1 << 3; + let unicast_link_local: u16 = 1 << 4; + let unicast_link_local_strict: u16 = 1 << 5; + let unicast_site_local: u16 = 1 << 6; + let unicast_global: u16 = 1 << 7; + let documentation: u16 = 1 << 8; + let multicast_interface_local: u16 = 1 << 9; + let multicast_link_local: u16 = 1 << 10; + let multicast_realm_local: u16 = 1 << 11; + let multicast_admin_local: u16 = 1 << 12; + let multicast_site_local: u16 = 1 << 13; + let multicast_organization_local: u16 = 1 << 14; + let multicast_global: u16 = 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 | unicast_link_local_strict + ); + + 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 | unicast_link_local_strict + ); + + 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_site_local | 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!( + "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_contructors() { + 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_IETF_PROTOCOL_ASSIGNMENT: bool = IP_ADDRESS.is_ietf_protocol_assignment(); + assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); + + 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_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict(); + assert!(!IS_UNICAST_LINK_LOCAL_STRICT); + + const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); + assert!(!IS_UNICAST_LINK_LOCAL); + + const IS_UNICAST_SITE_LOCAL: bool = IP_ADDRESS.is_unicast_site_local(); + assert!(!IS_UNICAST_SITE_LOCAL); + + const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + 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); +} diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index a425aca5a6..0570a7c41b 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -3,6 +3,9 @@ //! This module is "publicly exported" through the `FromStr` implementations //! below. +#[cfg(test)] +mod tests; + use crate::error::Error; use crate::fmt; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; @@ -321,146 +324,3 @@ impl Error for AddrParseError { "invalid IP address syntax" } } - -#[cfg(test)] -mod tests { - // FIXME: These tests are all excellent candidates for AFL fuzz testing - use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; - use crate::str::FromStr; - - const PORT: u16 = 8080; - - const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1); - const IPV4_STR: &str = "192.168.0.1"; - const IPV4_STR_PORT: &str = "192.168.0.1:8080"; - - const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1); - const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; - const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; - const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; - const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; - - #[test] - fn parse_ipv4() { - let result: Ipv4Addr = IPV4_STR.parse().unwrap(); - assert_eq!(result, IPV4); - - assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err()); - } - - #[test] - fn parse_ipv6() { - let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap(); - assert_eq!(result, IPV6); - - let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap(); - assert_eq!(result, IPV6); - - let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap(); - assert_eq!(result, IPV6); - - assert!(Ipv6Addr::from_str(IPV4_STR).is_err()); - assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err()); - assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err()); - } - - #[test] - fn parse_ip() { - let result: IpAddr = IPV4_STR.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV4)); - - let result: IpAddr = IPV6_STR_FULL.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV6)); - - let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV6)); - - let result: IpAddr = IPV6_STR_V4.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV6)); - - assert!(IpAddr::from_str(IPV4_STR_PORT).is_err()); - assert!(IpAddr::from_str(IPV6_STR_PORT).is_err()); - } - - #[test] - fn parse_socket_v4() { - let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddrV4::new(IPV4, PORT)); - - assert!(SocketAddrV4::from_str(IPV4_STR).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err()); - } - - #[test] - fn parse_socket_v6() { - let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0)); - - assert!(SocketAddrV6::from_str(IPV4_STR).is_err()); - assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err()); - assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err()); - assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err()); - } - - #[test] - fn parse_socket() { - let result: SocketAddr = IPV4_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddr::from((IPV4, PORT))); - - let result: SocketAddr = IPV6_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddr::from((IPV6, PORT))); - - assert!(SocketAddr::from_str(IPV4_STR).is_err()); - assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err()); - assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(SocketAddr::from_str(IPV6_STR_V4).is_err()); - } - - #[test] - fn ipv6_corner_cases() { - let result: Ipv6Addr = "1::".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0)); - - let result: Ipv6Addr = "1:1::".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0)); - - let result: Ipv6Addr = "::1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - - let result: Ipv6Addr = "::1:1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1)); - - let result: Ipv6Addr = "::".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - - let result: Ipv6Addr = "::192.168.0.1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1)); - - let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1)); - - let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1)); - } - - // Things that might not seem like failures but are - #[test] - fn ipv6_corner_failures() { - // No IP address before the :: - assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err()); - - // :: must have at least 1 set of zeroes - assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err()); - - // Need brackets for a port - assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err()); - } -} diff --git a/library/std/src/net/parser/tests.rs b/library/std/src/net/parser/tests.rs new file mode 100644 index 0000000000..ecf5a782c0 --- /dev/null +++ b/library/std/src/net/parser/tests.rs @@ -0,0 +1,139 @@ +// FIXME: These tests are all excellent candidates for AFL fuzz testing +use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use crate::str::FromStr; + +const PORT: u16 = 8080; + +const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1); +const IPV4_STR: &str = "192.168.0.1"; +const IPV4_STR_PORT: &str = "192.168.0.1:8080"; + +const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1); +const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; +const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; +const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; +const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; + +#[test] +fn parse_ipv4() { + let result: Ipv4Addr = IPV4_STR.parse().unwrap(); + assert_eq!(result, IPV4); + + assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_ipv6() { + let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap(); + assert_eq!(result, IPV6); + + let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap(); + assert_eq!(result, IPV6); + + let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap(); + assert_eq!(result, IPV6); + + assert!(Ipv6Addr::from_str(IPV4_STR).is_err()); + assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err()); + assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_ip() { + let result: IpAddr = IPV4_STR.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV4)); + + let result: IpAddr = IPV6_STR_FULL.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + let result: IpAddr = IPV6_STR_V4.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + assert!(IpAddr::from_str(IPV4_STR_PORT).is_err()); + assert!(IpAddr::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_socket_v4() { + let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddrV4::new(IPV4, PORT)); + + assert!(SocketAddrV4::from_str(IPV4_STR).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_socket_v6() { + let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0)); + + assert!(SocketAddrV6::from_str(IPV4_STR).is_err()); + assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err()); +} + +#[test] +fn parse_socket() { + let result: SocketAddr = IPV4_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddr::from((IPV4, PORT))); + + let result: SocketAddr = IPV6_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddr::from((IPV6, PORT))); + + assert!(SocketAddr::from_str(IPV4_STR).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_V4).is_err()); +} + +#[test] +fn ipv6_corner_cases() { + let result: Ipv6Addr = "1::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "1:1::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "::1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + + let result: Ipv6Addr = "::1:1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1)); + + let result: Ipv6Addr = "::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "::192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1)); + + let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1)); + + let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1)); +} + +// Things that might not seem like failures but are +#[test] +fn ipv6_corner_failures() { + // No IP address before the :: + assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err()); + + // :: must have at least 1 set of zeroes + assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err()); + + // Need brackets for a port + assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err()); +} diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index a76c9c46c0..58c6343ea3 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -1,4 +1,8 @@ #![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +mod tests; + use crate::io::prelude::*; use crate::fmt; @@ -936,869 +940,3 @@ impl fmt::Debug for TcpListener { self.0.fmt(f) } } - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] -mod tests { - use crate::fmt; - use crate::io::prelude::*; - use crate::io::{ErrorKind, IoSlice, IoSliceMut}; - use crate::net::test::{next_test_ip4, next_test_ip6}; - use crate::net::*; - use crate::sync::mpsc::channel; - use crate::thread; - use crate::time::{Duration, Instant}; - - fn each_ip(f: &mut dyn FnMut(SocketAddr)) { - f(next_test_ip4()); - f(next_test_ip6()); - } - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - }; - } - - #[test] - fn bind_error() { - match TcpListener::bind("1.1.1.1:9999") { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), - } - } - - #[test] - fn connect_error() { - match TcpStream::connect("0.0.0.0:1") { - Ok(..) => panic!(), - Err(e) => assert!( - e.kind() == ErrorKind::ConnectionRefused - || e.kind() == ErrorKind::InvalidInput - || e.kind() == ErrorKind::AddrInUse - || e.kind() == ErrorKind::AddrNotAvailable, - "bad error: {} {:?}", - e, - e.kind() - ), - } - } - - #[test] - fn listen_localhost() { - let socket_addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&socket_addr)); - - let _t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); - t!(stream.write(&[144])); - }); - - let mut stream = t!(listener.accept()).0; - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 144); - } - - #[test] - fn connect_loopback() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let host = match addr { - SocketAddr::V4(..) => "127.0.0.1", - SocketAddr::V6(..) => "::1", - }; - let mut stream = t!(TcpStream::connect(&(host, addr.port()))); - t!(stream.write(&[66])); - }); - - let mut stream = t!(acceptor.accept()).0; - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 66); - }) - } - - #[test] - fn smoke_test() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&addr)); - t!(stream.write(&[99])); - tx.send(t!(stream.local_addr())).unwrap(); - }); - - let (mut stream, addr) = t!(acceptor.accept()); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 99); - assert_eq!(addr, t!(rx.recv())); - }) - } - - #[test] - fn read_eof() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let _stream = t!(TcpStream::connect(&addr)); - // Close - }); - - let mut stream = t!(acceptor.accept()).0; - let mut buf = [0]; - let nread = t!(stream.read(&mut buf)); - assert_eq!(nread, 0); - let nread = t!(stream.read(&mut buf)); - assert_eq!(nread, 0); - }) - } - - #[test] - fn write_close() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - drop(t!(TcpStream::connect(&addr))); - tx.send(()).unwrap(); - }); - - let mut stream = t!(acceptor.accept()).0; - rx.recv().unwrap(); - let buf = [0]; - match stream.write(&buf) { - Ok(..) => {} - Err(e) => { - assert!( - e.kind() == ErrorKind::ConnectionReset - || e.kind() == ErrorKind::BrokenPipe - || e.kind() == ErrorKind::ConnectionAborted, - "unknown error: {}", - e - ); - } - } - }) - } - - #[test] - fn multiple_connect_serial() { - each_ip(&mut |addr| { - let max = 10; - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - for _ in 0..max { - let mut stream = t!(TcpStream::connect(&addr)); - t!(stream.write(&[99])); - } - }); - - for stream in acceptor.incoming().take(max) { - let mut stream = t!(stream); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert_eq!(buf[0], 99); - } - }) - } - - #[test] - fn multiple_connect_interleaved_greedy_schedule() { - const MAX: usize = 10; - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let acceptor = acceptor; - for (i, stream) in acceptor.incoming().enumerate().take(MAX) { - // Start another thread to handle the connection - let _t = thread::spawn(move || { - let mut stream = t!(stream); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == i as u8); - }); - } - }); - - connect(0, addr); - }); - - fn connect(i: usize, addr: SocketAddr) { - if i == MAX { - return; - } - - let t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&addr)); - // Connect again before writing - connect(i + 1, addr); - t!(stream.write(&[i as u8])); - }); - t.join().ok().expect("thread panicked"); - } - } - - #[test] - fn multiple_connect_interleaved_lazy_schedule() { - const MAX: usize = 10; - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - for stream in acceptor.incoming().take(MAX) { - // Start another thread to handle the connection - let _t = thread::spawn(move || { - let mut stream = t!(stream); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 99); - }); - } - }); - - connect(0, addr); - }); - - fn connect(i: usize, addr: SocketAddr) { - if i == MAX { - return; - } - - let t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&addr)); - connect(i + 1, addr); - t!(stream.write(&[99])); - }); - t.join().ok().expect("thread panicked"); - } - } - - #[test] - fn socket_and_peer_name() { - each_ip(&mut |addr| { - let listener = t!(TcpListener::bind(&addr)); - let so_name = t!(listener.local_addr()); - assert_eq!(addr, so_name); - let _t = thread::spawn(move || { - t!(listener.accept()); - }); - - let stream = t!(TcpStream::connect(&addr)); - assert_eq!(addr, t!(stream.peer_addr())); - }) - } - - #[test] - fn partial_read() { - each_ip(&mut |addr| { - let (tx, rx) = channel(); - let srv = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move || { - let mut cl = t!(srv.accept()).0; - cl.write(&[10]).unwrap(); - let mut b = [0]; - t!(cl.read(&mut b)); - tx.send(()).unwrap(); - }); - - let mut c = t!(TcpStream::connect(&addr)); - let mut b = [0; 10]; - assert_eq!(c.read(&mut b).unwrap(), 1); - t!(c.write(&[1])); - rx.recv().unwrap(); - }) - } - - #[test] - fn read_vectored() { - each_ip(&mut |addr| { - let srv = t!(TcpListener::bind(&addr)); - let mut s1 = t!(TcpStream::connect(&addr)); - let mut s2 = t!(srv.accept()).0; - - let len = s1.write(&[10, 11, 12]).unwrap(); - assert_eq!(len, 3); - - let mut a = []; - let mut b = [0]; - let mut c = [0; 3]; - let len = t!(s2.read_vectored(&mut [ - IoSliceMut::new(&mut a), - IoSliceMut::new(&mut b), - IoSliceMut::new(&mut c) - ],)); - assert!(len > 0); - assert_eq!(b, [10]); - // some implementations don't support readv, so we may only fill the first buffer - assert!(len == 1 || c == [11, 12, 0]); - }) - } - - #[test] - fn write_vectored() { - each_ip(&mut |addr| { - let srv = t!(TcpListener::bind(&addr)); - let mut s1 = t!(TcpStream::connect(&addr)); - let mut s2 = t!(srv.accept()).0; - - let a = []; - let b = [10]; - let c = [11, 12]; - t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)])); - - let mut buf = [0; 4]; - let len = t!(s2.read(&mut buf)); - // some implementations don't support writev, so we may only write the first buffer - if len == 1 { - assert_eq!(buf, [10, 0, 0, 0]); - } else { - assert_eq!(len, 3); - assert_eq!(buf, [10, 11, 12, 0]); - } - }) - } - - #[test] - fn double_bind() { - each_ip(&mut |addr| { - let listener1 = t!(TcpListener::bind(&addr)); - match TcpListener::bind(&addr) { - Ok(listener2) => panic!( - "This system (perhaps due to options set by TcpListener::bind) \ - permits double binding: {:?} and {:?}", - listener1, listener2 - ), - Err(e) => { - assert!( - e.kind() == ErrorKind::ConnectionRefused - || e.kind() == ErrorKind::Other - || e.kind() == ErrorKind::AddrInUse, - "unknown error: {} {:?}", - e, - e.kind() - ); - } - } - }) - } - - #[test] - fn tcp_clone_smoke() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let mut s = t!(TcpStream::connect(&addr)); - let mut buf = [0, 0]; - assert_eq!(s.read(&mut buf).unwrap(), 1); - assert_eq!(buf[0], 1); - t!(s.write(&[2])); - }); - - let mut s1 = t!(acceptor.accept()).0; - let s2 = t!(s1.try_clone()); - - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move || { - let mut s2 = s2; - rx1.recv().unwrap(); - t!(s2.write(&[1])); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - assert_eq!(s1.read(&mut buf).unwrap(), 1); - rx2.recv().unwrap(); - }) - } - - #[test] - fn tcp_clone_two_read() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move || { - let mut s = t!(TcpStream::connect(&addr)); - t!(s.write(&[1])); - rx.recv().unwrap(); - t!(s.write(&[2])); - rx.recv().unwrap(); - }); - - let mut s1 = t!(acceptor.accept()).0; - let s2 = t!(s1.try_clone()); - - let (done, rx) = channel(); - let _t = thread::spawn(move || { - let mut s2 = s2; - let mut buf = [0, 0]; - t!(s2.read(&mut buf)); - tx2.send(()).unwrap(); - done.send(()).unwrap(); - }); - let mut buf = [0, 0]; - t!(s1.read(&mut buf)); - tx1.send(()).unwrap(); - - rx.recv().unwrap(); - }) - } - - #[test] - fn tcp_clone_two_write() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let mut s = t!(TcpStream::connect(&addr)); - let mut buf = [0, 1]; - t!(s.read(&mut buf)); - t!(s.read(&mut buf)); - }); - - let mut s1 = t!(acceptor.accept()).0; - let s2 = t!(s1.try_clone()); - - let (done, rx) = channel(); - let _t = thread::spawn(move || { - let mut s2 = s2; - t!(s2.write(&[1])); - done.send(()).unwrap(); - }); - t!(s1.write(&[2])); - - rx.recv().unwrap(); - }) - } - - #[test] - // FIXME: https://github.com/fortanix/rust-sgx/issues/110 - #[cfg_attr(target_env = "sgx", ignore)] - fn shutdown_smoke() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move || { - let mut c = t!(a.accept()).0; - let mut b = [0]; - assert_eq!(c.read(&mut b).unwrap(), 0); - t!(c.write(&[1])); - }); - - let mut s = t!(TcpStream::connect(&addr)); - t!(s.shutdown(Shutdown::Write)); - assert!(s.write(&[1]).is_err()); - let mut b = [0, 0]; - assert_eq!(t!(s.read(&mut b)), 1); - assert_eq!(b[0], 1); - }) - } - - #[test] - // FIXME: https://github.com/fortanix/rust-sgx/issues/110 - #[cfg_attr(target_env = "sgx", ignore)] - fn close_readwrite_smoke() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let (tx, rx) = channel::<()>(); - let _t = thread::spawn(move || { - let _s = t!(a.accept()); - let _ = rx.recv(); - }); - - let mut b = [0]; - let mut s = t!(TcpStream::connect(&addr)); - let mut s2 = t!(s.try_clone()); - - // closing should prevent reads/writes - t!(s.shutdown(Shutdown::Write)); - assert!(s.write(&[0]).is_err()); - t!(s.shutdown(Shutdown::Read)); - assert_eq!(s.read(&mut b).unwrap(), 0); - - // closing should affect previous handles - assert!(s2.write(&[0]).is_err()); - assert_eq!(s2.read(&mut b).unwrap(), 0); - - // closing should affect new handles - let mut s3 = t!(s.try_clone()); - assert!(s3.write(&[0]).is_err()); - assert_eq!(s3.read(&mut b).unwrap(), 0); - - // make sure these don't die - let _ = s2.shutdown(Shutdown::Read); - let _ = s2.shutdown(Shutdown::Write); - let _ = s3.shutdown(Shutdown::Read); - let _ = s3.shutdown(Shutdown::Write); - drop(tx); - }) - } - - #[test] - #[cfg(unix)] // test doesn't work on Windows, see #31657 - fn close_read_wakes_up() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let (tx1, rx) = channel::<()>(); - let _t = thread::spawn(move || { - let _s = t!(a.accept()); - let _ = rx.recv(); - }); - - let s = t!(TcpStream::connect(&addr)); - let s2 = t!(s.try_clone()); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let mut s2 = s2; - assert_eq!(t!(s2.read(&mut [0])), 0); - tx.send(()).unwrap(); - }); - // this should wake up the child thread - t!(s.shutdown(Shutdown::Read)); - - // this test will never finish if the child doesn't wake up - rx.recv().unwrap(); - drop(tx1); - }) - } - - #[test] - fn clone_while_reading() { - each_ip(&mut |addr| { - let accept = t!(TcpListener::bind(&addr)); - - // Enqueue a thread to write to a socket - let (tx, rx) = channel(); - let (txdone, rxdone) = channel(); - let txdone2 = txdone.clone(); - let _t = thread::spawn(move || { - let mut tcp = t!(TcpStream::connect(&addr)); - rx.recv().unwrap(); - t!(tcp.write(&[0])); - txdone2.send(()).unwrap(); - }); - - // Spawn off a reading clone - let tcp = t!(accept.accept()).0; - let tcp2 = t!(tcp.try_clone()); - let txdone3 = txdone.clone(); - let _t = thread::spawn(move || { - let mut tcp2 = tcp2; - t!(tcp2.read(&mut [0])); - txdone3.send(()).unwrap(); - }); - - // Try to ensure that the reading clone is indeed reading - for _ in 0..50 { - thread::yield_now(); - } - - // clone the handle again while it's reading, then let it finish the - // read. - let _ = t!(tcp.try_clone()); - tx.send(()).unwrap(); - rxdone.recv().unwrap(); - rxdone.recv().unwrap(); - }) - } - - #[test] - fn clone_accept_smoke() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let a2 = t!(a.try_clone()); - - let _t = thread::spawn(move || { - let _ = TcpStream::connect(&addr); - }); - let _t = thread::spawn(move || { - let _ = TcpStream::connect(&addr); - }); - - t!(a.accept()); - t!(a2.accept()); - }) - } - - #[test] - fn clone_accept_concurrent() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let a2 = t!(a.try_clone()); - - let (tx, rx) = channel(); - let tx2 = tx.clone(); - - let _t = thread::spawn(move || { - tx.send(t!(a.accept())).unwrap(); - }); - let _t = thread::spawn(move || { - tx2.send(t!(a2.accept())).unwrap(); - }); - - let _t = thread::spawn(move || { - let _ = TcpStream::connect(&addr); - }); - let _t = thread::spawn(move || { - let _ = TcpStream::connect(&addr); - }); - - rx.recv().unwrap(); - rx.recv().unwrap(); - }) - } - - #[test] - fn debug() { - #[cfg(not(target_env = "sgx"))] - fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { - addr - } - #[cfg(target_env = "sgx")] - fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { - addr.to_string() - } - - #[cfg(target_env = "sgx")] - use crate::os::fortanix_sgx::io::AsRawFd; - #[cfg(unix)] - use crate::os::unix::io::AsRawFd; - #[cfg(not(windows))] - fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { - addr.as_raw_fd() - } - #[cfg(windows)] - fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug { - addr.as_raw_socket() - } - - let inner_name = if cfg!(windows) { "socket" } else { "fd" }; - let socket_addr = next_test_ip4(); - - let listener = t!(TcpListener::bind(&socket_addr)); - let compare = format!( - "TcpListener {{ addr: {:?}, {}: {:?} }}", - render_socket_addr(&socket_addr), - inner_name, - render_inner(&listener) - ); - assert_eq!(format!("{:?}", listener), compare); - - let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); - let compare = format!( - "TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}", - render_socket_addr(&stream.local_addr().unwrap()), - render_socket_addr(&stream.peer_addr().unwrap()), - inner_name, - render_inner(&stream) - ); - assert_eq!(format!("{:?}", stream), compare); - } - - // FIXME: re-enabled openbsd tests once their socket timeout code - // no longer has rounding errors. - // VxWorks ignores SO_SNDTIMEO. - #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - #[test] - fn timeouts() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - let dur = Duration::new(15410, 0); - - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.read_timeout())); - - assert_eq!(None, t!(stream.write_timeout())); - - t!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.write_timeout())); - - t!(stream.set_read_timeout(None)); - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_write_timeout(None)); - assert_eq!(None, t!(stream.write_timeout())); - drop(listener); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - fn test_read_timeout() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - let start = Instant::now(); - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - assert!(start.elapsed() > Duration::from_millis(400)); - drop(listener); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - fn test_read_with_timeout() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut other_end = t!(listener.accept()).0; - t!(other_end.write_all(b"hello world")); - - let mut buf = [0; 11]; - t!(stream.read(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let start = Instant::now(); - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - assert!(start.elapsed() > Duration::from_millis(400)); - drop(listener); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_timeout_zero_duration() { - let addr = next_test_ip4(); - - let listener = t!(TcpListener::bind(&addr)); - let stream = t!(TcpStream::connect(&addr)); - - let result = stream.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = stream.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - drop(listener); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] - fn nodelay() { - let addr = next_test_ip4(); - let _listener = t!(TcpListener::bind(&addr)); - - let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - - assert_eq!(false, t!(stream.nodelay())); - t!(stream.set_nodelay(true)); - assert_eq!(true, t!(stream.nodelay())); - t!(stream.set_nodelay(false)); - assert_eq!(false, t!(stream.nodelay())); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] - fn ttl() { - let ttl = 100; - - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - t!(listener.set_ttl(ttl)); - assert_eq!(ttl, t!(listener.ttl())); - - let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - - t!(stream.set_ttl(ttl)); - assert_eq!(ttl, t!(stream.ttl())); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] - fn set_nonblocking() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - t!(listener.set_nonblocking(true)); - t!(listener.set_nonblocking(false)); - - let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); - - t!(stream.set_nonblocking(false)); - t!(stream.set_nonblocking(true)); - - let mut buf = [0]; - match stream.read(&mut buf) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), - } - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - fn peek() { - each_ip(&mut |addr| { - let (txdone, rxdone) = channel(); - - let srv = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move || { - let mut cl = t!(srv.accept()).0; - cl.write(&[1, 3, 3, 7]).unwrap(); - t!(rxdone.recv()); - }); - - let mut c = t!(TcpStream::connect(&addr)); - let mut b = [0; 10]; - for _ in 1..3 { - let len = c.peek(&mut b).unwrap(); - assert_eq!(len, 4); - } - let len = c.read(&mut b).unwrap(); - assert_eq!(len, 4); - - t!(c.set_nonblocking(true)); - match c.peek(&mut b) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), - } - t!(txdone.send(())); - }) - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - fn connect_timeout_valid() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap(); - } -} diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs new file mode 100644 index 0000000000..abe9bc24ce --- /dev/null +++ b/library/std/src/net/tcp/tests.rs @@ -0,0 +1,862 @@ +use crate::fmt; +use crate::io::prelude::*; +use crate::io::{ErrorKind, IoSlice, IoSliceMut}; +use crate::net::test::{next_test_ip4, next_test_ip6}; +use crate::net::*; +use crate::sync::mpsc::channel; +use crate::thread; +use crate::time::{Duration, Instant}; + +fn each_ip(f: &mut dyn FnMut(SocketAddr)) { + f(next_test_ip4()); + f(next_test_ip6()); +} + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + }; +} + +#[test] +fn bind_error() { + match TcpListener::bind("1.1.1.1:9999") { + Ok(..) => panic!(), + Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), + } +} + +#[test] +fn connect_error() { + match TcpStream::connect("0.0.0.0:1") { + Ok(..) => panic!(), + Err(e) => assert!( + e.kind() == ErrorKind::ConnectionRefused + || e.kind() == ErrorKind::InvalidInput + || e.kind() == ErrorKind::AddrInUse + || e.kind() == ErrorKind::AddrNotAvailable, + "bad error: {} {:?}", + e, + e.kind() + ), + } +} + +#[test] +fn listen_localhost() { + let socket_addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&socket_addr)); + + let _t = thread::spawn(move || { + let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); + t!(stream.write(&[144])); + }); + + let mut stream = t!(listener.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 144); +} + +#[test] +fn connect_loopback() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let host = match addr { + SocketAddr::V4(..) => "127.0.0.1", + SocketAddr::V6(..) => "::1", + }; + let mut stream = t!(TcpStream::connect(&(host, addr.port()))); + t!(stream.write(&[66])); + }); + + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 66); + }) +} + +#[test] +fn smoke_test() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + let mut stream = t!(TcpStream::connect(&addr)); + t!(stream.write(&[99])); + tx.send(t!(stream.local_addr())).unwrap(); + }); + + let (mut stream, addr) = t!(acceptor.accept()); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 99); + assert_eq!(addr, t!(rx.recv())); + }) +} + +#[test] +fn read_eof() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let _stream = t!(TcpStream::connect(&addr)); + // Close + }); + + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + let nread = t!(stream.read(&mut buf)); + assert_eq!(nread, 0); + let nread = t!(stream.read(&mut buf)); + assert_eq!(nread, 0); + }) +} + +#[test] +fn write_close() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + drop(t!(TcpStream::connect(&addr))); + tx.send(()).unwrap(); + }); + + let mut stream = t!(acceptor.accept()).0; + rx.recv().unwrap(); + let buf = [0]; + match stream.write(&buf) { + Ok(..) => {} + Err(e) => { + assert!( + e.kind() == ErrorKind::ConnectionReset + || e.kind() == ErrorKind::BrokenPipe + || e.kind() == ErrorKind::ConnectionAborted, + "unknown error: {}", + e + ); + } + } + }) +} + +#[test] +fn multiple_connect_serial() { + each_ip(&mut |addr| { + let max = 10; + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + for _ in 0..max { + let mut stream = t!(TcpStream::connect(&addr)); + t!(stream.write(&[99])); + } + }); + + for stream in acceptor.incoming().take(max) { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert_eq!(buf[0], 99); + } + }) +} + +#[test] +fn multiple_connect_interleaved_greedy_schedule() { + const MAX: usize = 10; + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let acceptor = acceptor; + for (i, stream) in acceptor.incoming().enumerate().take(MAX) { + // Start another thread to handle the connection + let _t = thread::spawn(move || { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == i as u8); + }); + } + }); + + connect(0, addr); + }); + + fn connect(i: usize, addr: SocketAddr) { + if i == MAX { + return; + } + + let t = thread::spawn(move || { + let mut stream = t!(TcpStream::connect(&addr)); + // Connect again before writing + connect(i + 1, addr); + t!(stream.write(&[i as u8])); + }); + t.join().ok().expect("thread panicked"); + } +} + +#[test] +fn multiple_connect_interleaved_lazy_schedule() { + const MAX: usize = 10; + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + for stream in acceptor.incoming().take(MAX) { + // Start another thread to handle the connection + let _t = thread::spawn(move || { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 99); + }); + } + }); + + connect(0, addr); + }); + + fn connect(i: usize, addr: SocketAddr) { + if i == MAX { + return; + } + + let t = thread::spawn(move || { + let mut stream = t!(TcpStream::connect(&addr)); + connect(i + 1, addr); + t!(stream.write(&[99])); + }); + t.join().ok().expect("thread panicked"); + } +} + +#[test] +fn socket_and_peer_name() { + each_ip(&mut |addr| { + let listener = t!(TcpListener::bind(&addr)); + let so_name = t!(listener.local_addr()); + assert_eq!(addr, so_name); + let _t = thread::spawn(move || { + t!(listener.accept()); + }); + + let stream = t!(TcpStream::connect(&addr)); + assert_eq!(addr, t!(stream.peer_addr())); + }) +} + +#[test] +fn partial_read() { + each_ip(&mut |addr| { + let (tx, rx) = channel(); + let srv = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move || { + let mut cl = t!(srv.accept()).0; + cl.write(&[10]).unwrap(); + let mut b = [0]; + t!(cl.read(&mut b)); + tx.send(()).unwrap(); + }); + + let mut c = t!(TcpStream::connect(&addr)); + let mut b = [0; 10]; + assert_eq!(c.read(&mut b).unwrap(), 1); + t!(c.write(&[1])); + rx.recv().unwrap(); + }) +} + +#[test] +fn read_vectored() { + each_ip(&mut |addr| { + let srv = t!(TcpListener::bind(&addr)); + let mut s1 = t!(TcpStream::connect(&addr)); + let mut s2 = t!(srv.accept()).0; + + let len = s1.write(&[10, 11, 12]).unwrap(); + assert_eq!(len, 3); + + let mut a = []; + let mut b = [0]; + let mut c = [0; 3]; + let len = t!(s2.read_vectored(&mut [ + IoSliceMut::new(&mut a), + IoSliceMut::new(&mut b), + IoSliceMut::new(&mut c) + ],)); + assert!(len > 0); + assert_eq!(b, [10]); + // some implementations don't support readv, so we may only fill the first buffer + assert!(len == 1 || c == [11, 12, 0]); + }) +} + +#[test] +fn write_vectored() { + each_ip(&mut |addr| { + let srv = t!(TcpListener::bind(&addr)); + let mut s1 = t!(TcpStream::connect(&addr)); + let mut s2 = t!(srv.accept()).0; + + let a = []; + let b = [10]; + let c = [11, 12]; + t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)])); + + let mut buf = [0; 4]; + let len = t!(s2.read(&mut buf)); + // some implementations don't support writev, so we may only write the first buffer + if len == 1 { + assert_eq!(buf, [10, 0, 0, 0]); + } else { + assert_eq!(len, 3); + assert_eq!(buf, [10, 11, 12, 0]); + } + }) +} + +#[test] +fn double_bind() { + each_ip(&mut |addr| { + let listener1 = t!(TcpListener::bind(&addr)); + match TcpListener::bind(&addr) { + Ok(listener2) => panic!( + "This system (perhaps due to options set by TcpListener::bind) \ + permits double binding: {:?} and {:?}", + listener1, listener2 + ), + Err(e) => { + assert!( + e.kind() == ErrorKind::ConnectionRefused + || e.kind() == ErrorKind::Other + || e.kind() == ErrorKind::AddrInUse, + "unknown error: {} {:?}", + e, + e.kind() + ); + } + } + }) +} + +#[test] +fn tcp_clone_smoke() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let mut s = t!(TcpStream::connect(&addr)); + let mut buf = [0, 0]; + assert_eq!(s.read(&mut buf).unwrap(), 1); + assert_eq!(buf[0], 1); + t!(s.write(&[2])); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move || { + let mut s2 = s2; + rx1.recv().unwrap(); + t!(s2.write(&[1])); + tx2.send(()).unwrap(); + }); + tx1.send(()).unwrap(); + let mut buf = [0, 0]; + assert_eq!(s1.read(&mut buf).unwrap(), 1); + rx2.recv().unwrap(); + }) +} + +#[test] +fn tcp_clone_two_read() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + let (tx1, rx) = channel(); + let tx2 = tx1.clone(); + + let _t = thread::spawn(move || { + let mut s = t!(TcpStream::connect(&addr)); + t!(s.write(&[1])); + rx.recv().unwrap(); + t!(s.write(&[2])); + rx.recv().unwrap(); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (done, rx) = channel(); + let _t = thread::spawn(move || { + let mut s2 = s2; + let mut buf = [0, 0]; + t!(s2.read(&mut buf)); + tx2.send(()).unwrap(); + done.send(()).unwrap(); + }); + let mut buf = [0, 0]; + t!(s1.read(&mut buf)); + tx1.send(()).unwrap(); + + rx.recv().unwrap(); + }) +} + +#[test] +fn tcp_clone_two_write() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let mut s = t!(TcpStream::connect(&addr)); + let mut buf = [0, 1]; + t!(s.read(&mut buf)); + t!(s.read(&mut buf)); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (done, rx) = channel(); + let _t = thread::spawn(move || { + let mut s2 = s2; + t!(s2.write(&[1])); + done.send(()).unwrap(); + }); + t!(s1.write(&[2])); + + rx.recv().unwrap(); + }) +} + +#[test] +// FIXME: https://github.com/fortanix/rust-sgx/issues/110 +#[cfg_attr(target_env = "sgx", ignore)] +fn shutdown_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move || { + let mut c = t!(a.accept()).0; + let mut b = [0]; + assert_eq!(c.read(&mut b).unwrap(), 0); + t!(c.write(&[1])); + }); + + let mut s = t!(TcpStream::connect(&addr)); + t!(s.shutdown(Shutdown::Write)); + assert!(s.write(&[1]).is_err()); + let mut b = [0, 0]; + assert_eq!(t!(s.read(&mut b)), 1); + assert_eq!(b[0], 1); + }) +} + +#[test] +// FIXME: https://github.com/fortanix/rust-sgx/issues/110 +#[cfg_attr(target_env = "sgx", ignore)] +fn close_readwrite_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let (tx, rx) = channel::<()>(); + let _t = thread::spawn(move || { + let _s = t!(a.accept()); + let _ = rx.recv(); + }); + + let mut b = [0]; + let mut s = t!(TcpStream::connect(&addr)); + let mut s2 = t!(s.try_clone()); + + // closing should prevent reads/writes + t!(s.shutdown(Shutdown::Write)); + assert!(s.write(&[0]).is_err()); + t!(s.shutdown(Shutdown::Read)); + assert_eq!(s.read(&mut b).unwrap(), 0); + + // closing should affect previous handles + assert!(s2.write(&[0]).is_err()); + assert_eq!(s2.read(&mut b).unwrap(), 0); + + // closing should affect new handles + let mut s3 = t!(s.try_clone()); + assert!(s3.write(&[0]).is_err()); + assert_eq!(s3.read(&mut b).unwrap(), 0); + + // make sure these don't die + let _ = s2.shutdown(Shutdown::Read); + let _ = s2.shutdown(Shutdown::Write); + let _ = s3.shutdown(Shutdown::Read); + let _ = s3.shutdown(Shutdown::Write); + drop(tx); + }) +} + +#[test] +#[cfg(unix)] // test doesn't work on Windows, see #31657 +fn close_read_wakes_up() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let (tx1, rx) = channel::<()>(); + let _t = thread::spawn(move || { + let _s = t!(a.accept()); + let _ = rx.recv(); + }); + + let s = t!(TcpStream::connect(&addr)); + let s2 = t!(s.try_clone()); + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + let mut s2 = s2; + assert_eq!(t!(s2.read(&mut [0])), 0); + tx.send(()).unwrap(); + }); + // this should wake up the child thread + t!(s.shutdown(Shutdown::Read)); + + // this test will never finish if the child doesn't wake up + rx.recv().unwrap(); + drop(tx1); + }) +} + +#[test] +fn clone_while_reading() { + each_ip(&mut |addr| { + let accept = t!(TcpListener::bind(&addr)); + + // Enqueue a thread to write to a socket + let (tx, rx) = channel(); + let (txdone, rxdone) = channel(); + let txdone2 = txdone.clone(); + let _t = thread::spawn(move || { + let mut tcp = t!(TcpStream::connect(&addr)); + rx.recv().unwrap(); + t!(tcp.write(&[0])); + txdone2.send(()).unwrap(); + }); + + // Spawn off a reading clone + let tcp = t!(accept.accept()).0; + let tcp2 = t!(tcp.try_clone()); + let txdone3 = txdone.clone(); + let _t = thread::spawn(move || { + let mut tcp2 = tcp2; + t!(tcp2.read(&mut [0])); + txdone3.send(()).unwrap(); + }); + + // Try to ensure that the reading clone is indeed reading + for _ in 0..50 { + thread::yield_now(); + } + + // clone the handle again while it's reading, then let it finish the + // read. + let _ = t!(tcp.try_clone()); + tx.send(()).unwrap(); + rxdone.recv().unwrap(); + rxdone.recv().unwrap(); + }) +} + +#[test] +fn clone_accept_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let a2 = t!(a.try_clone()); + + let _t = thread::spawn(move || { + let _ = TcpStream::connect(&addr); + }); + let _t = thread::spawn(move || { + let _ = TcpStream::connect(&addr); + }); + + t!(a.accept()); + t!(a2.accept()); + }) +} + +#[test] +fn clone_accept_concurrent() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let a2 = t!(a.try_clone()); + + let (tx, rx) = channel(); + let tx2 = tx.clone(); + + let _t = thread::spawn(move || { + tx.send(t!(a.accept())).unwrap(); + }); + let _t = thread::spawn(move || { + tx2.send(t!(a2.accept())).unwrap(); + }); + + let _t = thread::spawn(move || { + let _ = TcpStream::connect(&addr); + }); + let _t = thread::spawn(move || { + let _ = TcpStream::connect(&addr); + }); + + rx.recv().unwrap(); + rx.recv().unwrap(); + }) +} + +#[test] +fn debug() { + #[cfg(not(target_env = "sgx"))] + fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { + addr + } + #[cfg(target_env = "sgx")] + fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { + addr.to_string() + } + + #[cfg(target_env = "sgx")] + use crate::os::fortanix_sgx::io::AsRawFd; + #[cfg(unix)] + use crate::os::unix::io::AsRawFd; + #[cfg(not(windows))] + fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { + addr.as_raw_fd() + } + #[cfg(windows)] + fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug { + addr.as_raw_socket() + } + + let inner_name = if cfg!(windows) { "socket" } else { "fd" }; + let socket_addr = next_test_ip4(); + + let listener = t!(TcpListener::bind(&socket_addr)); + let compare = format!( + "TcpListener {{ addr: {:?}, {}: {:?} }}", + render_socket_addr(&socket_addr), + inner_name, + render_inner(&listener) + ); + assert_eq!(format!("{:?}", listener), compare); + + let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); + let compare = format!( + "TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}", + render_socket_addr(&stream.local_addr().unwrap()), + render_socket_addr(&stream.peer_addr().unwrap()), + inner_name, + render_inner(&stream) + ); + assert_eq!(format!("{:?}", stream), compare); +} + +// FIXME: re-enabled openbsd tests once their socket timeout code +// no longer has rounding errors. +// VxWorks ignores SO_SNDTIMEO. +#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +#[test] +fn timeouts() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + let dur = Duration::new(15410, 0); + + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.read_timeout())); + + assert_eq!(None, t!(stream.write_timeout())); + + t!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.write_timeout())); + + t!(stream.set_read_timeout(None)); + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_write_timeout(None)); + assert_eq!(None, t!(stream.write_timeout())); + drop(listener); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +fn test_read_timeout() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + let start = Instant::now(); + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); + assert!(start.elapsed() > Duration::from_millis(400)); + drop(listener); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +fn test_read_with_timeout() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut other_end = t!(listener.accept()).0; + t!(other_end.write_all(b"hello world")); + + let mut buf = [0; 11]; + t!(stream.read(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let start = Instant::now(); + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); + assert!(start.elapsed() > Duration::from_millis(400)); + drop(listener); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_timeout_zero_duration() { + let addr = next_test_ip4(); + + let listener = t!(TcpListener::bind(&addr)); + let stream = t!(TcpStream::connect(&addr)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] +fn nodelay() { + let addr = next_test_ip4(); + let _listener = t!(TcpListener::bind(&addr)); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + assert_eq!(false, t!(stream.nodelay())); + t!(stream.set_nodelay(true)); + assert_eq!(true, t!(stream.nodelay())); + t!(stream.set_nodelay(false)); + assert_eq!(false, t!(stream.nodelay())); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] +fn ttl() { + let ttl = 100; + + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + t!(listener.set_ttl(ttl)); + assert_eq!(ttl, t!(listener.ttl())); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + t!(stream.set_ttl(ttl)); + assert_eq!(ttl, t!(stream.ttl())); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] +fn set_nonblocking() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + t!(listener.set_nonblocking(true)); + t!(listener.set_nonblocking(false)); + + let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + t!(stream.set_nonblocking(false)); + t!(stream.set_nonblocking(true)); + + let mut buf = [0]; + match stream.read(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +fn peek() { + each_ip(&mut |addr| { + let (txdone, rxdone) = channel(); + + let srv = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move || { + let mut cl = t!(srv.accept()).0; + cl.write(&[1, 3, 3, 7]).unwrap(); + t!(rxdone.recv()); + }); + + let mut c = t!(TcpStream::connect(&addr)); + let mut b = [0; 10]; + for _ in 1..3 { + let len = c.peek(&mut b).unwrap(); + assert_eq!(len, 4); + } + let len = c.read(&mut b).unwrap(); + assert_eq!(len, 4); + + t!(c.set_nonblocking(true)); + match c.peek(&mut b) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } + t!(txdone.send(())); + }) +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +fn connect_timeout_valid() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap(); +} diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index d730b2b87a..17e3e4497c 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] +mod tests; + use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; @@ -798,380 +801,3 @@ impl fmt::Debug for UdpSocket { self.0.fmt(f) } } - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] -mod tests { - use crate::io::ErrorKind; - use crate::net::test::{next_test_ip4, next_test_ip6}; - use crate::net::*; - use crate::sync::mpsc::channel; - use crate::sys_common::AsInner; - use crate::thread; - use crate::time::{Duration, Instant}; - - fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { - f(next_test_ip4(), next_test_ip4()); - f(next_test_ip6(), next_test_ip6()); - } - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - }; - } - - #[test] - fn bind_error() { - match UdpSocket::bind("1.1.1.1:9999") { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), - } - } - - #[test] - fn socket_smoke_test_ip4() { - each_ip(&mut |server_ip, client_ip| { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - - let _t = thread::spawn(move || { - let client = t!(UdpSocket::bind(&client_ip)); - rx1.recv().unwrap(); - t!(client.send_to(&[99], &server_ip)); - tx2.send(()).unwrap(); - }); - - let server = t!(UdpSocket::bind(&server_ip)); - tx1.send(()).unwrap(); - let mut buf = [0]; - let (nread, src) = t!(server.recv_from(&mut buf)); - assert_eq!(nread, 1); - assert_eq!(buf[0], 99); - assert_eq!(src, client_ip); - rx2.recv().unwrap(); - }) - } - - #[test] - fn socket_name() { - each_ip(&mut |addr, _| { - let server = t!(UdpSocket::bind(&addr)); - assert_eq!(addr, t!(server.local_addr())); - }) - } - - #[test] - fn socket_peer() { - each_ip(&mut |addr1, addr2| { - let server = t!(UdpSocket::bind(&addr1)); - assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected); - t!(server.connect(&addr2)); - assert_eq!(addr2, t!(server.peer_addr())); - }) - } - - #[test] - fn udp_clone_smoke() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); - - let _t = thread::spawn(move || { - let mut buf = [0, 0]; - assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); - assert_eq!(buf[0], 1); - t!(sock2.send_to(&[2], &addr1)); - }); - - let sock3 = t!(sock1.try_clone()); - - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move || { - rx1.recv().unwrap(); - t!(sock3.send_to(&[1], &addr2)); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); - rx2.recv().unwrap(); - }) - } - - #[test] - fn udp_clone_two_read() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move || { - t!(sock2.send_to(&[1], &addr1)); - rx.recv().unwrap(); - t!(sock2.send_to(&[2], &addr1)); - rx.recv().unwrap(); - }); - - let sock3 = t!(sock1.try_clone()); - - let (done, rx) = channel(); - let _t = thread::spawn(move || { - let mut buf = [0, 0]; - t!(sock3.recv_from(&mut buf)); - tx2.send(()).unwrap(); - done.send(()).unwrap(); - }); - let mut buf = [0, 0]; - t!(sock1.recv_from(&mut buf)); - tx1.send(()).unwrap(); - - rx.recv().unwrap(); - }) - } - - #[test] - fn udp_clone_two_write() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); - - let (tx, rx) = channel(); - let (serv_tx, serv_rx) = channel(); - - let _t = thread::spawn(move || { - let mut buf = [0, 1]; - rx.recv().unwrap(); - t!(sock2.recv_from(&mut buf)); - serv_tx.send(()).unwrap(); - }); - - let sock3 = t!(sock1.try_clone()); - - let (done, rx) = channel(); - let tx2 = tx.clone(); - let _t = thread::spawn(move || { - match sock3.send_to(&[1], &addr2) { - Ok(..) => { - let _ = tx2.send(()); - } - Err(..) => {} - } - done.send(()).unwrap(); - }); - match sock1.send_to(&[2], &addr2) { - Ok(..) => { - let _ = tx.send(()); - } - Err(..) => {} - } - drop(tx); - - rx.recv().unwrap(); - serv_rx.recv().unwrap(); - }) - } - - #[test] - fn debug() { - let name = if cfg!(windows) { "socket" } else { "fd" }; - let socket_addr = next_test_ip4(); - - let udpsock = t!(UdpSocket::bind(&socket_addr)); - let udpsock_inner = udpsock.0.socket().as_inner(); - let compare = - format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner); - assert_eq!(format!("{:?}", udpsock), compare); - } - - // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code - // no longer has rounding errors. - // VxWorks ignores SO_SNDTIMEO. - #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] - #[test] - fn timeouts() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - let dur = Duration::new(15410, 0); - - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.read_timeout())); - - assert_eq!(None, t!(stream.write_timeout())); - - t!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.write_timeout())); - - t!(stream.set_read_timeout(None)); - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_write_timeout(None)); - assert_eq!(None, t!(stream.write_timeout())); - } - - #[test] - fn test_read_timeout() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - - let start = Instant::now(); - loop { - let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); - if kind != ErrorKind::Interrupted { - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - break; - } - } - assert!(start.elapsed() > Duration::from_millis(400)); - } - - #[test] - fn test_read_with_timeout() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - t!(stream.send_to(b"hello world", &addr)); - - let mut buf = [0; 11]; - t!(stream.recv_from(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let start = Instant::now(); - loop { - let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); - if kind != ErrorKind::Interrupted { - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - break; - } - } - assert!(start.elapsed() > Duration::from_millis(400)); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_timeout_zero_duration() { - let addr = next_test_ip4(); - - let socket = t!(UdpSocket::bind(&addr)); - - let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - } - - #[test] - fn connect_send_recv() { - let addr = next_test_ip4(); - - let socket = t!(UdpSocket::bind(&addr)); - t!(socket.connect(addr)); - - t!(socket.send(b"hello world")); - - let mut buf = [0; 11]; - t!(socket.recv(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - } - - #[test] - fn connect_send_peek_recv() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); - t!(socket.connect(addr)); - - t!(socket.send(b"hello world")); - - for _ in 1..3 { - let mut buf = [0; 11]; - let size = t!(socket.peek(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - } - - let mut buf = [0; 11]; - let size = t!(socket.recv(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - }) - } - - #[test] - fn peek_from() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); - t!(socket.send_to(b"hello world", &addr)); - - for _ in 1..3 { - let mut buf = [0; 11]; - let (size, _) = t!(socket.peek_from(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - } - - let mut buf = [0; 11]; - let (size, _) = t!(socket.recv_from(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - }) - } - - #[test] - fn ttl() { - let ttl = 100; - - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - - t!(stream.set_ttl(ttl)); - assert_eq!(ttl, t!(stream.ttl())); - } - - #[test] - fn set_nonblocking() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); - - t!(socket.set_nonblocking(true)); - t!(socket.set_nonblocking(false)); - - t!(socket.connect(addr)); - - t!(socket.set_nonblocking(false)); - t!(socket.set_nonblocking(true)); - - let mut buf = [0]; - match socket.recv(&mut buf) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), - } - }) - } -} diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs new file mode 100644 index 0000000000..658369f79a --- /dev/null +++ b/library/std/src/net/udp/tests.rs @@ -0,0 +1,372 @@ +use crate::io::ErrorKind; +use crate::net::test::{next_test_ip4, next_test_ip6}; +use crate::net::*; +use crate::sync::mpsc::channel; +use crate::sys_common::AsInner; +use crate::thread; +use crate::time::{Duration, Instant}; + +fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { + f(next_test_ip4(), next_test_ip4()); + f(next_test_ip6(), next_test_ip6()); +} + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + }; +} + +#[test] +fn bind_error() { + match UdpSocket::bind("1.1.1.1:9999") { + Ok(..) => panic!(), + Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), + } +} + +#[test] +fn socket_smoke_test_ip4() { + each_ip(&mut |server_ip, client_ip| { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + + let _t = thread::spawn(move || { + let client = t!(UdpSocket::bind(&client_ip)); + rx1.recv().unwrap(); + t!(client.send_to(&[99], &server_ip)); + tx2.send(()).unwrap(); + }); + + let server = t!(UdpSocket::bind(&server_ip)); + tx1.send(()).unwrap(); + let mut buf = [0]; + let (nread, src) = t!(server.recv_from(&mut buf)); + assert_eq!(nread, 1); + assert_eq!(buf[0], 99); + assert_eq!(src, client_ip); + rx2.recv().unwrap(); + }) +} + +#[test] +fn socket_name() { + each_ip(&mut |addr, _| { + let server = t!(UdpSocket::bind(&addr)); + assert_eq!(addr, t!(server.local_addr())); + }) +} + +#[test] +fn socket_peer() { + each_ip(&mut |addr1, addr2| { + let server = t!(UdpSocket::bind(&addr1)); + assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected); + t!(server.connect(&addr2)); + assert_eq!(addr2, t!(server.peer_addr())); + }) +} + +#[test] +fn udp_clone_smoke() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + + let _t = thread::spawn(move || { + let mut buf = [0, 0]; + assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); + assert_eq!(buf[0], 1); + t!(sock2.send_to(&[2], &addr1)); + }); + + let sock3 = t!(sock1.try_clone()); + + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move || { + rx1.recv().unwrap(); + t!(sock3.send_to(&[1], &addr2)); + tx2.send(()).unwrap(); + }); + tx1.send(()).unwrap(); + let mut buf = [0, 0]; + assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); + rx2.recv().unwrap(); + }) +} + +#[test] +fn udp_clone_two_read() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + let (tx1, rx) = channel(); + let tx2 = tx1.clone(); + + let _t = thread::spawn(move || { + t!(sock2.send_to(&[1], &addr1)); + rx.recv().unwrap(); + t!(sock2.send_to(&[2], &addr1)); + rx.recv().unwrap(); + }); + + let sock3 = t!(sock1.try_clone()); + + let (done, rx) = channel(); + let _t = thread::spawn(move || { + let mut buf = [0, 0]; + t!(sock3.recv_from(&mut buf)); + tx2.send(()).unwrap(); + done.send(()).unwrap(); + }); + let mut buf = [0, 0]; + t!(sock1.recv_from(&mut buf)); + tx1.send(()).unwrap(); + + rx.recv().unwrap(); + }) +} + +#[test] +fn udp_clone_two_write() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + + let (tx, rx) = channel(); + let (serv_tx, serv_rx) = channel(); + + let _t = thread::spawn(move || { + let mut buf = [0, 1]; + rx.recv().unwrap(); + t!(sock2.recv_from(&mut buf)); + serv_tx.send(()).unwrap(); + }); + + let sock3 = t!(sock1.try_clone()); + + let (done, rx) = channel(); + let tx2 = tx.clone(); + let _t = thread::spawn(move || { + match sock3.send_to(&[1], &addr2) { + Ok(..) => { + let _ = tx2.send(()); + } + Err(..) => {} + } + done.send(()).unwrap(); + }); + match sock1.send_to(&[2], &addr2) { + Ok(..) => { + let _ = tx.send(()); + } + Err(..) => {} + } + drop(tx); + + rx.recv().unwrap(); + serv_rx.recv().unwrap(); + }) +} + +#[test] +fn debug() { + let name = if cfg!(windows) { "socket" } else { "fd" }; + let socket_addr = next_test_ip4(); + + let udpsock = t!(UdpSocket::bind(&socket_addr)); + let udpsock_inner = udpsock.0.socket().as_inner(); + let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner); + assert_eq!(format!("{:?}", udpsock), compare); +} + +// FIXME: re-enabled openbsd/netbsd tests once their socket timeout code +// no longer has rounding errors. +// VxWorks ignores SO_SNDTIMEO. +#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] +#[test] +fn timeouts() { + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + let dur = Duration::new(15410, 0); + + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.read_timeout())); + + assert_eq!(None, t!(stream.write_timeout())); + + t!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.write_timeout())); + + t!(stream.set_read_timeout(None)); + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_write_timeout(None)); + assert_eq!(None, t!(stream.write_timeout())); +} + +#[test] +fn test_read_timeout() { + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + + let start = Instant::now(); + loop { + let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); + if kind != ErrorKind::Interrupted { + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); + break; + } + } + assert!(start.elapsed() > Duration::from_millis(400)); +} + +#[test] +fn test_read_with_timeout() { + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + t!(stream.send_to(b"hello world", &addr)); + + let mut buf = [0; 11]; + t!(stream.recv_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let start = Instant::now(); + loop { + let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); + if kind != ErrorKind::Interrupted { + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); + break; + } + } + assert!(start.elapsed() > Duration::from_millis(400)); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_timeout_zero_duration() { + let addr = next_test_ip4(); + + let socket = t!(UdpSocket::bind(&addr)); + + let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); +} + +#[test] +fn connect_send_recv() { + let addr = next_test_ip4(); + + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.connect(addr)); + + t!(socket.send(b"hello world")); + + let mut buf = [0; 11]; + t!(socket.recv(&mut buf)); + assert_eq!(b"hello world", &buf[..]); +} + +#[test] +fn connect_send_peek_recv() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.connect(addr)); + + t!(socket.send(b"hello world")); + + for _ in 1..3 { + let mut buf = [0; 11]; + let size = t!(socket.peek(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + } + + let mut buf = [0; 11]; + let size = t!(socket.recv(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + }) +} + +#[test] +fn peek_from() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.send_to(b"hello world", &addr)); + + for _ in 1..3 { + let mut buf = [0; 11]; + let (size, _) = t!(socket.peek_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + } + + let mut buf = [0; 11]; + let (size, _) = t!(socket.recv_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + }) +} + +#[test] +fn ttl() { + let ttl = 100; + + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + + t!(stream.set_ttl(ttl)); + assert_eq!(ttl, t!(stream.ttl())); +} + +#[test] +fn set_nonblocking() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + + t!(socket.set_nonblocking(true)); + t!(socket.set_nonblocking(false)); + + t!(socket.connect(addr)); + + t!(socket.set_nonblocking(false)); + t!(socket.set_nonblocking(true)); + + let mut buf = [0]; + match socket.recv(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } + }) +} diff --git a/library/std/src/num.rs b/library/std/src/num.rs index b496c16a74..0f1c596268 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -6,6 +6,12 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] +#[cfg(test)] +mod tests; + +#[cfg(test)] +mod benches; + #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; #[stable(feature = "rust1", since = "1.0.0")] @@ -48,250 +54,3 @@ where assert_eq!(ten.div(two), ten / two); assert_eq!(ten.rem(two), ten % two); } - -#[cfg(test)] -mod tests { - use crate::ops::Mul; - - #[test] - fn test_saturating_add_uint() { - assert_eq!(3_usize.saturating_add(5_usize), 8_usize); - assert_eq!(3_usize.saturating_add(usize::MAX - 1), usize::MAX); - assert_eq!(usize::MAX.saturating_add(usize::MAX), usize::MAX); - assert_eq!((usize::MAX - 2).saturating_add(1), usize::MAX - 1); - } - - #[test] - fn test_saturating_sub_uint() { - assert_eq!(5_usize.saturating_sub(3_usize), 2_usize); - assert_eq!(3_usize.saturating_sub(5_usize), 0_usize); - assert_eq!(0_usize.saturating_sub(1_usize), 0_usize); - assert_eq!((usize::MAX - 1).saturating_sub(usize::MAX), 0); - } - - #[test] - fn test_saturating_add_int() { - assert_eq!(3i32.saturating_add(5), 8); - assert_eq!(3isize.saturating_add(isize::MAX - 1), isize::MAX); - assert_eq!(isize::MAX.saturating_add(isize::MAX), isize::MAX); - assert_eq!((isize::MAX - 2).saturating_add(1), isize::MAX - 1); - assert_eq!(3i32.saturating_add(-5), -2); - assert_eq!(isize::MIN.saturating_add(-1), isize::MIN); - assert_eq!((-2isize).saturating_add(-isize::MAX), isize::MIN); - } - - #[test] - fn test_saturating_sub_int() { - assert_eq!(3i32.saturating_sub(5), -2); - assert_eq!(isize::MIN.saturating_sub(1), isize::MIN); - assert_eq!((-2isize).saturating_sub(isize::MAX), isize::MIN); - assert_eq!(3i32.saturating_sub(-5), 8); - assert_eq!(3isize.saturating_sub(-(isize::MAX - 1)), isize::MAX); - assert_eq!(isize::MAX.saturating_sub(-isize::MAX), isize::MAX); - assert_eq!((isize::MAX - 2).saturating_sub(-1), isize::MAX - 1); - } - - #[test] - fn test_checked_add() { - let five_less = usize::MAX - 5; - assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5)); - assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4)); - assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3)); - assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2)); - assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1)); - assert_eq!(five_less.checked_add(5), Some(usize::MAX)); - assert_eq!(five_less.checked_add(6), None); - assert_eq!(five_less.checked_add(7), None); - } - - #[test] - fn test_checked_sub() { - assert_eq!(5_usize.checked_sub(0), Some(5)); - assert_eq!(5_usize.checked_sub(1), Some(4)); - assert_eq!(5_usize.checked_sub(2), Some(3)); - assert_eq!(5_usize.checked_sub(3), Some(2)); - assert_eq!(5_usize.checked_sub(4), Some(1)); - assert_eq!(5_usize.checked_sub(5), Some(0)); - assert_eq!(5_usize.checked_sub(6), None); - assert_eq!(5_usize.checked_sub(7), None); - } - - #[test] - fn test_checked_mul() { - let third = usize::MAX / 3; - assert_eq!(third.checked_mul(0), Some(0)); - assert_eq!(third.checked_mul(1), Some(third)); - assert_eq!(third.checked_mul(2), Some(third * 2)); - assert_eq!(third.checked_mul(3), Some(third * 3)); - assert_eq!(third.checked_mul(4), None); - } - - macro_rules! test_is_power_of_two { - ($test_name:ident, $T:ident) => { - fn $test_name() { - #![test] - assert_eq!((0 as $T).is_power_of_two(), false); - assert_eq!((1 as $T).is_power_of_two(), true); - assert_eq!((2 as $T).is_power_of_two(), true); - assert_eq!((3 as $T).is_power_of_two(), false); - assert_eq!((4 as $T).is_power_of_two(), true); - assert_eq!((5 as $T).is_power_of_two(), false); - assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true); - } - }; - } - - test_is_power_of_two! { test_is_power_of_two_u8, u8 } - test_is_power_of_two! { test_is_power_of_two_u16, u16 } - test_is_power_of_two! { test_is_power_of_two_u32, u32 } - test_is_power_of_two! { test_is_power_of_two_u64, u64 } - test_is_power_of_two! { test_is_power_of_two_uint, usize } - - macro_rules! test_next_power_of_two { - ($test_name:ident, $T:ident) => { - fn $test_name() { - #![test] - assert_eq!((0 as $T).next_power_of_two(), 1); - let mut next_power = 1; - for i in 1 as $T..40 { - assert_eq!(i.next_power_of_two(), next_power); - if i == next_power { - next_power *= 2 - } - } - } - }; - } - - test_next_power_of_two! { test_next_power_of_two_u8, u8 } - test_next_power_of_two! { test_next_power_of_two_u16, u16 } - test_next_power_of_two! { test_next_power_of_two_u32, u32 } - test_next_power_of_two! { test_next_power_of_two_u64, u64 } - test_next_power_of_two! { test_next_power_of_two_uint, usize } - - macro_rules! test_checked_next_power_of_two { - ($test_name:ident, $T:ident) => { - fn $test_name() { - #![test] - assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); - let smax = $T::MAX >> 1; - assert_eq!(smax.checked_next_power_of_two(), Some(smax + 1)); - assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1)); - assert_eq!((smax + 2).checked_next_power_of_two(), None); - assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None); - assert_eq!($T::MAX.checked_next_power_of_two(), None); - let mut next_power = 1; - for i in 1 as $T..40 { - assert_eq!(i.checked_next_power_of_two(), Some(next_power)); - if i == next_power { - next_power *= 2 - } - } - } - }; - } - - test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize } - - #[test] - fn test_pow() { - fn naive_pow + Copy>(one: T, base: T, exp: usize) -> T { - (0..exp).fold(one, |acc, _| acc * base) - } - macro_rules! assert_pow { - (($num:expr, $exp:expr) => $expected:expr) => {{ - let result = $num.pow($exp); - assert_eq!(result, $expected); - assert_eq!(result, naive_pow(1, $num, $exp)); - }}; - } - assert_pow!((3u32, 0 ) => 1); - assert_pow!((5u32, 1 ) => 5); - assert_pow!((-4i32, 2 ) => 16); - assert_pow!((8u32, 3 ) => 512); - assert_pow!((2u64, 50) => 1125899906842624); - } - - #[test] - fn test_uint_to_str_overflow() { - let mut u8_val: u8 = 255; - assert_eq!(u8_val.to_string(), "255"); - - u8_val = u8_val.wrapping_add(1); - assert_eq!(u8_val.to_string(), "0"); - - let mut u16_val: u16 = 65_535; - assert_eq!(u16_val.to_string(), "65535"); - - u16_val = u16_val.wrapping_add(1); - assert_eq!(u16_val.to_string(), "0"); - - let mut u32_val: u32 = 4_294_967_295; - assert_eq!(u32_val.to_string(), "4294967295"); - - u32_val = u32_val.wrapping_add(1); - assert_eq!(u32_val.to_string(), "0"); - - let mut u64_val: u64 = 18_446_744_073_709_551_615; - assert_eq!(u64_val.to_string(), "18446744073709551615"); - - u64_val = u64_val.wrapping_add(1); - assert_eq!(u64_val.to_string(), "0"); - } - - fn from_str(t: &str) -> Option { - crate::str::FromStr::from_str(t).ok() - } - - #[test] - fn test_uint_from_str_overflow() { - let mut u8_val: u8 = 255; - assert_eq!(from_str::("255"), Some(u8_val)); - assert_eq!(from_str::("256"), None); - - u8_val = u8_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u8_val)); - assert_eq!(from_str::("-1"), None); - - let mut u16_val: u16 = 65_535; - assert_eq!(from_str::("65535"), Some(u16_val)); - assert_eq!(from_str::("65536"), None); - - u16_val = u16_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u16_val)); - assert_eq!(from_str::("-1"), None); - - let mut u32_val: u32 = 4_294_967_295; - assert_eq!(from_str::("4294967295"), Some(u32_val)); - assert_eq!(from_str::("4294967296"), None); - - u32_val = u32_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u32_val)); - assert_eq!(from_str::("-1"), None); - - let mut u64_val: u64 = 18_446_744_073_709_551_615; - assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); - assert_eq!(from_str::("18446744073709551616"), None); - - u64_val = u64_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u64_val)); - assert_eq!(from_str::("-1"), None); - } -} - -#[cfg(test)] -mod bench { - use test::Bencher; - - #[bench] - fn bench_pow_function(b: &mut Bencher) { - let v = (0..1024).collect::>(); - b.iter(|| { - v.iter().fold(0u32, |old, new| old.pow(*new as u32)); - }); - } -} diff --git a/library/std/src/num/benches.rs b/library/std/src/num/benches.rs new file mode 100644 index 0000000000..233ea0506c --- /dev/null +++ b/library/std/src/num/benches.rs @@ -0,0 +1,9 @@ +use test::Bencher; + +#[bench] +fn bench_pow_function(b: &mut Bencher) { + let v = (0..1024).collect::>(); + b.iter(|| { + v.iter().fold(0u32, |old, new| old.pow(*new as u32)); + }); +} diff --git a/library/std/src/num/tests.rs b/library/std/src/num/tests.rs new file mode 100644 index 0000000000..2f50b73f49 --- /dev/null +++ b/library/std/src/num/tests.rs @@ -0,0 +1,230 @@ +use crate::ops::Mul; + +#[test] +fn test_saturating_add_uint() { + assert_eq!(3_usize.saturating_add(5_usize), 8_usize); + assert_eq!(3_usize.saturating_add(usize::MAX - 1), usize::MAX); + assert_eq!(usize::MAX.saturating_add(usize::MAX), usize::MAX); + assert_eq!((usize::MAX - 2).saturating_add(1), usize::MAX - 1); +} + +#[test] +fn test_saturating_sub_uint() { + assert_eq!(5_usize.saturating_sub(3_usize), 2_usize); + assert_eq!(3_usize.saturating_sub(5_usize), 0_usize); + assert_eq!(0_usize.saturating_sub(1_usize), 0_usize); + assert_eq!((usize::MAX - 1).saturating_sub(usize::MAX), 0); +} + +#[test] +fn test_saturating_add_int() { + assert_eq!(3i32.saturating_add(5), 8); + assert_eq!(3isize.saturating_add(isize::MAX - 1), isize::MAX); + assert_eq!(isize::MAX.saturating_add(isize::MAX), isize::MAX); + assert_eq!((isize::MAX - 2).saturating_add(1), isize::MAX - 1); + assert_eq!(3i32.saturating_add(-5), -2); + assert_eq!(isize::MIN.saturating_add(-1), isize::MIN); + assert_eq!((-2isize).saturating_add(-isize::MAX), isize::MIN); +} + +#[test] +fn test_saturating_sub_int() { + assert_eq!(3i32.saturating_sub(5), -2); + assert_eq!(isize::MIN.saturating_sub(1), isize::MIN); + assert_eq!((-2isize).saturating_sub(isize::MAX), isize::MIN); + assert_eq!(3i32.saturating_sub(-5), 8); + assert_eq!(3isize.saturating_sub(-(isize::MAX - 1)), isize::MAX); + assert_eq!(isize::MAX.saturating_sub(-isize::MAX), isize::MAX); + assert_eq!((isize::MAX - 2).saturating_sub(-1), isize::MAX - 1); +} + +#[test] +fn test_checked_add() { + let five_less = usize::MAX - 5; + assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5)); + assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4)); + assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3)); + assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2)); + assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1)); + assert_eq!(five_less.checked_add(5), Some(usize::MAX)); + assert_eq!(five_less.checked_add(6), None); + assert_eq!(five_less.checked_add(7), None); +} + +#[test] +fn test_checked_sub() { + assert_eq!(5_usize.checked_sub(0), Some(5)); + assert_eq!(5_usize.checked_sub(1), Some(4)); + assert_eq!(5_usize.checked_sub(2), Some(3)); + assert_eq!(5_usize.checked_sub(3), Some(2)); + assert_eq!(5_usize.checked_sub(4), Some(1)); + assert_eq!(5_usize.checked_sub(5), Some(0)); + assert_eq!(5_usize.checked_sub(6), None); + assert_eq!(5_usize.checked_sub(7), None); +} + +#[test] +fn test_checked_mul() { + let third = usize::MAX / 3; + assert_eq!(third.checked_mul(0), Some(0)); + assert_eq!(third.checked_mul(1), Some(third)); + assert_eq!(third.checked_mul(2), Some(third * 2)); + assert_eq!(third.checked_mul(3), Some(third * 3)); + assert_eq!(third.checked_mul(4), None); +} + +macro_rules! test_is_power_of_two { + ($test_name:ident, $T:ident) => { + fn $test_name() { + #![test] + assert_eq!((0 as $T).is_power_of_two(), false); + assert_eq!((1 as $T).is_power_of_two(), true); + assert_eq!((2 as $T).is_power_of_two(), true); + assert_eq!((3 as $T).is_power_of_two(), false); + assert_eq!((4 as $T).is_power_of_two(), true); + assert_eq!((5 as $T).is_power_of_two(), false); + assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true); + } + }; +} + +test_is_power_of_two! { test_is_power_of_two_u8, u8 } +test_is_power_of_two! { test_is_power_of_two_u16, u16 } +test_is_power_of_two! { test_is_power_of_two_u32, u32 } +test_is_power_of_two! { test_is_power_of_two_u64, u64 } +test_is_power_of_two! { test_is_power_of_two_uint, usize } + +macro_rules! test_next_power_of_two { + ($test_name:ident, $T:ident) => { + fn $test_name() { + #![test] + assert_eq!((0 as $T).next_power_of_two(), 1); + let mut next_power = 1; + for i in 1 as $T..40 { + assert_eq!(i.next_power_of_two(), next_power); + if i == next_power { + next_power *= 2 + } + } + } + }; +} + +test_next_power_of_two! { test_next_power_of_two_u8, u8 } +test_next_power_of_two! { test_next_power_of_two_u16, u16 } +test_next_power_of_two! { test_next_power_of_two_u32, u32 } +test_next_power_of_two! { test_next_power_of_two_u64, u64 } +test_next_power_of_two! { test_next_power_of_two_uint, usize } + +macro_rules! test_checked_next_power_of_two { + ($test_name:ident, $T:ident) => { + fn $test_name() { + #![test] + assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); + let smax = $T::MAX >> 1; + assert_eq!(smax.checked_next_power_of_two(), Some(smax + 1)); + assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1)); + assert_eq!((smax + 2).checked_next_power_of_two(), None); + assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None); + assert_eq!($T::MAX.checked_next_power_of_two(), None); + let mut next_power = 1; + for i in 1 as $T..40 { + assert_eq!(i.checked_next_power_of_two(), Some(next_power)); + if i == next_power { + next_power *= 2 + } + } + } + }; +} + +test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 } +test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 } +test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 } +test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 } +test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize } + +#[test] +fn test_pow() { + fn naive_pow + Copy>(one: T, base: T, exp: usize) -> T { + (0..exp).fold(one, |acc, _| acc * base) + } + macro_rules! assert_pow { + (($num:expr, $exp:expr) => $expected:expr) => {{ + let result = $num.pow($exp); + assert_eq!(result, $expected); + assert_eq!(result, naive_pow(1, $num, $exp)); + }}; + } + assert_pow!((3u32, 0 ) => 1); + assert_pow!((5u32, 1 ) => 5); + assert_pow!((-4i32, 2 ) => 16); + assert_pow!((8u32, 3 ) => 512); + assert_pow!((2u64, 50) => 1125899906842624); +} + +#[test] +fn test_uint_to_str_overflow() { + let mut u8_val: u8 = 255; + assert_eq!(u8_val.to_string(), "255"); + + u8_val = u8_val.wrapping_add(1); + assert_eq!(u8_val.to_string(), "0"); + + let mut u16_val: u16 = 65_535; + assert_eq!(u16_val.to_string(), "65535"); + + u16_val = u16_val.wrapping_add(1); + assert_eq!(u16_val.to_string(), "0"); + + let mut u32_val: u32 = 4_294_967_295; + assert_eq!(u32_val.to_string(), "4294967295"); + + u32_val = u32_val.wrapping_add(1); + assert_eq!(u32_val.to_string(), "0"); + + let mut u64_val: u64 = 18_446_744_073_709_551_615; + assert_eq!(u64_val.to_string(), "18446744073709551615"); + + u64_val = u64_val.wrapping_add(1); + assert_eq!(u64_val.to_string(), "0"); +} + +fn from_str(t: &str) -> Option { + crate::str::FromStr::from_str(t).ok() +} + +#[test] +fn test_uint_from_str_overflow() { + let mut u8_val: u8 = 255; + assert_eq!(from_str::("255"), Some(u8_val)); + assert_eq!(from_str::("256"), None); + + u8_val = u8_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u8_val)); + assert_eq!(from_str::("-1"), None); + + let mut u16_val: u16 = 65_535; + assert_eq!(from_str::("65535"), Some(u16_val)); + assert_eq!(from_str::("65536"), None); + + u16_val = u16_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u16_val)); + assert_eq!(from_str::("-1"), None); + + let mut u32_val: u32 = 4_294_967_295; + assert_eq!(from_str::("4294967295"), Some(u32_val)); + assert_eq!(from_str::("4294967296"), None); + + u32_val = u32_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u32_val)); + assert_eq!(from_str::("-1"), None); + + let mut u64_val: u64 = 18_446_744_073_709_551_615; + assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); + assert_eq!(from_str::("18446744073709551616"), None); + + u64_val = u64_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u64_val)); + assert_eq!(from_str::("-1"), None); +} diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs index cae65f1218..ff23c3d67e 100644 --- a/library/std/src/os/linux/fs.rs +++ b/library/std/src/os/linux/fs.rs @@ -1,3 +1,5 @@ +//! Linux-specific extensions to primitives in the `std::fs` module. + #![stable(feature = "metadata_ext", since = "1.1.0")] use crate::fs::Metadata; @@ -196,7 +198,7 @@ pub trait MetadataExt { fn st_atime(&self) -> i64; /// Returns the last access time of the file, in nanoseconds since [`st_atime`]. /// - /// [`st_atime`]: #tymethod.st_atime + /// [`st_atime`]: Self::st_atime /// /// # Examples /// @@ -232,7 +234,7 @@ pub trait MetadataExt { fn st_mtime(&self) -> i64; /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`]. /// - /// [`st_mtime`]: #tymethod.st_mtime + /// [`st_mtime`]: Self::st_mtime /// /// # Examples /// @@ -268,7 +270,7 @@ pub trait MetadataExt { fn st_ctime(&self) -> i64; /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`]. /// - /// [`st_ctime`]: #tymethod.st_ctime + /// [`st_ctime`]: Self::st_ctime /// /// # Examples /// diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs index d35307162c..f179a52433 100644 --- a/library/std/src/os/linux/mod.rs +++ b/library/std/src/os/linux/mod.rs @@ -1,4 +1,4 @@ -//! Linux-specific definitions +//! Linux-specific definitions. #![stable(feature = "raw_ext", since = "1.1.0")] diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index eb8589eb58..617c4098aa 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -1,4 +1,4 @@ -//! Linux-specific raw type definitions +//! Linux-specific raw type definitions. #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated( @@ -29,6 +29,7 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; target_arch = "x86", target_arch = "le32", target_arch = "powerpc", + target_arch = "sparc", target_arch = "arm", target_arch = "asmjs", target_arch = "wasm32" @@ -170,63 +171,63 @@ mod arch { #[cfg(target_arch = "hexagon")] mod arch { - use crate::os::raw::{c_int, c_long, c_longlong, c_ulonglong}; + use crate::os::raw::{c_int, c_long, c_uint}; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type blkcnt_t = c_longlong; + pub type blkcnt_t = i64; #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = c_long; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type ino_t = c_ulonglong; + pub type ino_t = u64; #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = c_uint; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type off_t = c_longlong; + pub type off_t = i64; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type time_t = c_long; + pub type time_t = i64; #[repr(C)] #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: ::dev_t, + pub st_dev: u64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: ::c_ulonglong, + pub st_ino: u64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: ::c_uint, + pub st_mode: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: ::c_uint, + pub st_nlink: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: ::c_uint, + pub st_uid: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: ::c_uint, + pub st_gid: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: ::c_ulonglong, + pub st_rdev: u64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: ::c_ulong, + pub __pad1: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: ::c_longlong, + pub st_size: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: ::blksize_t, + pub st_blksize: i32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: ::c_int, + pub __pad2: i32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: ::blkcnt_t, + pub st_blocks: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: ::time_t, + pub st_atime: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: ::c_long, + pub st_atime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: ::time_t, + pub st_mtime: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: ::c_long, + pub st_mtime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: ::time_t, + pub st_ctime: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: ::c_long, + pub st_ctime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad3: [::c_int; 2], + pub __pad3: [c_int; 2], } } @@ -234,7 +235,8 @@ mod arch { target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "riscv32" ))] mod arch { pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 47daf0cce1..16272aa057 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -8,6 +8,9 @@ #![stable(feature = "raw_os", since = "1.1.0")] +#[cfg(test)] +mod tests; + #[doc(include = "char.md")] #[cfg(any( all( @@ -19,7 +22,8 @@ target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "riscv32" ) ), all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), @@ -62,7 +66,8 @@ pub type c_char = u8; target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "riscv32" ) ), all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), @@ -144,24 +149,3 @@ pub type c_double = f64; #[stable(feature = "raw_os", since = "1.1.0")] #[doc(no_inline)] pub use core::ffi::c_void; - -#[cfg(test)] -#[allow(unused_imports)] -mod tests { - use crate::any::TypeId; - use crate::mem; - - macro_rules! ok { - ($($t:ident)*) => {$( - assert!(TypeId::of::() == TypeId::of::(), - "{} is wrong", stringify!($t)); - )*} - } - - #[test] - fn same() { - use crate::os::raw; - ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong - c_longlong c_ulonglong c_float c_double); - } -} diff --git a/library/std/src/os/raw/tests.rs b/library/std/src/os/raw/tests.rs new file mode 100644 index 0000000000..e7bb7d7e73 --- /dev/null +++ b/library/std/src/os/raw/tests.rs @@ -0,0 +1,15 @@ +use crate::any::TypeId; + +macro_rules! ok { + ($($t:ident)*) => {$( + assert!(TypeId::of::() == TypeId::of::(), + "{} is wrong", stringify!($t)); + )*} +} + +#[test] +fn same() { + use crate::os::raw; + ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong + c_longlong c_ulonglong c_float c_double); +} diff --git a/library/std/src/os/redox/fs.rs b/library/std/src/os/redox/fs.rs index 94d65651da..0f179c8b83 100644 --- a/library/std/src/os/redox/fs.rs +++ b/library/std/src/os/redox/fs.rs @@ -200,7 +200,7 @@ pub trait MetadataExt { fn st_atime(&self) -> i64; /// Returns the last access time of the file, in nanoseconds since [`st_atime`]. /// - /// [`st_atime`]: #tymethod.st_atime + /// [`st_atime`]: Self::st_atime /// /// # Examples /// @@ -236,7 +236,7 @@ pub trait MetadataExt { fn st_mtime(&self) -> i64; /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`]. /// - /// [`st_mtime`]: #tymethod.st_mtime + /// [`st_mtime`]: Self::st_mtime /// /// # Examples /// @@ -272,7 +272,7 @@ pub trait MetadataExt { fn st_ctime(&self) -> i64; /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`]. /// - /// [`st_ctime`]: #tymethod.st_ctime + /// [`st_ctime`]: Self::st_ctime /// /// # Examples /// diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 8fcb24033b..4281867314 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -232,16 +232,16 @@ impl RefUnwindSafe for RwLock {} #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicIsize {} #[cfg(target_has_atomic_load_store = "8")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI8 {} #[cfg(target_has_atomic_load_store = "16")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI16 {} #[cfg(target_has_atomic_load_store = "32")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI32 {} #[cfg(target_has_atomic_load_store = "64")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI64 {} #[cfg(target_has_atomic_load_store = "128")] #[unstable(feature = "integer_atomics", issue = "32976")] @@ -251,16 +251,16 @@ impl RefUnwindSafe for atomic::AtomicI128 {} #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicUsize {} #[cfg(target_has_atomic_load_store = "8")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU8 {} #[cfg(target_has_atomic_load_store = "16")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU16 {} #[cfg(target_has_atomic_load_store = "32")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU32 {} #[cfg(target_has_atomic_load_store = "64")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU64 {} #[cfg(target_has_atomic_load_store = "128")] #[unstable(feature = "integer_atomics", issue = "32976")] @@ -359,6 +359,9 @@ impl Future for AssertUnwindSafe { /// aborting the process as well. This function *only* catches unwinding panics, /// not those that abort the process. /// +/// Also note that unwinding into Rust code with a foreign exception (e.g. a +/// an exception thrown from C++ code) is undefined behavior. +/// /// # Examples /// /// ``` @@ -408,3 +411,6 @@ pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { pub fn resume_unwind(payload: Box) -> ! { panicking::rust_panic_without_hook(payload) } + +#[cfg(test)] +mod tests; diff --git a/src/test/ui/panics/panic-safe.rs b/library/std/src/panic/tests.rs similarity index 77% rename from src/test/ui/panics/panic-safe.rs rename to library/std/src/panic/tests.rs index 9867cc5640..b37d74011c 100644 --- a/src/test/ui/panics/panic-safe.rs +++ b/library/std/src/panic/tests.rs @@ -1,16 +1,18 @@ -// run-pass #![allow(dead_code)] -use std::panic::{UnwindSafe, AssertUnwindSafe}; -use std::cell::RefCell; -use std::sync::{Mutex, RwLock, Arc}; -use std::rc::Rc; +use crate::cell::RefCell; +use crate::panic::{AssertUnwindSafe, UnwindSafe}; +use crate::rc::Rc; +use crate::sync::{Arc, Mutex, RwLock}; -struct Foo { a: i32 } +struct Foo { + a: i32, +} fn assert() {} -fn main() { +#[test] +fn panic_safety_traits() { assert::(); assert::<&i32>(); assert::<*mut i32>(); @@ -32,13 +34,16 @@ fn main() { assert::>(); assert::>(); - trait Trait: UnwindSafe {} - assert::>(); + { + trait Trait: UnwindSafe {} + assert::>(); + } fn bar() { assert::>(); assert::>(); } + fn baz() { assert::>(); assert::>(); diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 08d363a9a2..8dceb12de8 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -60,6 +60,14 @@ extern "C" fn __rust_drop_panic() -> ! { rtabort!("Rust panics must be rethrown"); } +/// This function is called by the panic runtime if it catches an exception +/// object which does not correspond to a Rust panic. +#[cfg(not(test))] +#[rustc_std_internal_symbol] +extern "C" fn __rust_foreign_exception() -> ! { + rtabort!("Rust cannot catch foreign exceptions"); +} + #[derive(Copy, Clone)] enum Hook { Default, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index afdbdbeac3..6fa73042a3 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! Cross-platform path manipulation. //! //! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`] @@ -60,6 +58,10 @@ //! [`push`]: PathBuf::push #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(test)] +mod tests; use crate::borrow::{Borrow, Cow}; use crate::cmp; @@ -293,7 +295,8 @@ fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { unsafe { &*(s as *const OsStr as *const [u8]) } } unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - &*(s as *const [u8] as *const OsStr) + // SAFETY: see the comment of `os_str_as_u8_slice` + unsafe { &*(s as *const [u8] as *const OsStr) } } // Detect scheme on Redox @@ -313,24 +316,21 @@ fn has_physical_root(s: &[u8], prefix: Option>) -> bool { // basic workhorse for splitting stem and extension fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { - unsafe { - if os_str_as_u8_slice(file) == b".." { - return (Some(file), None); - } - - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. + if os_str_as_u8_slice(file) == b".." { + return (Some(file), None); + } - let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); - let after = iter.next(); - let before = iter.next(); - if before == Some(b"") { - (Some(file), None) - } else { - (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) - } + // The unsafety here stems from converting between &OsStr and &[u8] + // and back. This is safe to do because (1) we only look at ASCII + // contents of the encoding and (2) new &OsStr values are produced + // only from ASCII-bounded slices of existing &OsStr values. + let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); + let after = iter.next(); + let before = iter.next(); + if before == Some(b"") { + (Some(file), None) + } else { + unsafe { (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) } } } @@ -1701,7 +1701,7 @@ impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. unsafe fn from_u8_slice(s: &[u8]) -> &Path { - Path::new(u8_slice_as_os_str(s)) + unsafe { Path::new(u8_slice_as_os_str(s)) } } // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] { @@ -1838,7 +1838,7 @@ impl Path { // FIXME: Allow Redox prefixes self.has_root() || has_redox_scheme(self.as_u8_slice()) } else { - self.has_root() && (cfg!(unix) || self.prefix().is_some()) + self.has_root() && (cfg!(any(unix, target_os = "wasi")) || self.prefix().is_some()) } } @@ -2741,1401 +2741,3 @@ impl Error for StripPrefixError { "prefix not found" } } - -#[cfg(test)] -mod tests { - use super::*; - - use crate::rc::Rc; - use crate::sync::Arc; - - macro_rules! t( - ($path:expr, iter: $iter:expr) => ( - { - let path = Path::new($path); - - // Forward iteration - let comps = path.iter() - .map(|p| p.to_string_lossy().into_owned()) - .collect::>(); - let exp: &[&str] = &$iter; - let exps = exp.iter().map(|s| s.to_string()).collect::>(); - assert!(comps == exps, "iter: Expected {:?}, found {:?}", - exps, comps); - - // Reverse iteration - let comps = Path::new($path).iter().rev() - .map(|p| p.to_string_lossy().into_owned()) - .collect::>(); - let exps = exps.into_iter().rev().collect::>(); - assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}", - exps, comps); - } - ); - - ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => ( - { - let path = Path::new($path); - - let act_root = path.has_root(); - assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}", - $has_root, act_root); - - let act_abs = path.is_absolute(); - assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}", - $is_absolute, act_abs); - } - ); - - ($path:expr, parent: $parent:expr, file_name: $file:expr) => ( - { - let path = Path::new($path); - - let parent = path.parent().map(|p| p.to_str().unwrap()); - let exp_parent: Option<&str> = $parent; - assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}", - exp_parent, parent); - - let file = path.file_name().map(|p| p.to_str().unwrap()); - let exp_file: Option<&str> = $file; - assert!(file == exp_file, "file_name: Expected {:?}, found {:?}", - exp_file, file); - } - ); - - ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => ( - { - let path = Path::new($path); - - let stem = path.file_stem().map(|p| p.to_str().unwrap()); - let exp_stem: Option<&str> = $file_stem; - assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}", - exp_stem, stem); - - let ext = path.extension().map(|p| p.to_str().unwrap()); - let exp_ext: Option<&str> = $extension; - assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}", - exp_ext, ext); - } - ); - - ($path:expr, iter: $iter:expr, - has_root: $has_root:expr, is_absolute: $is_absolute:expr, - parent: $parent:expr, file_name: $file:expr, - file_stem: $file_stem:expr, extension: $extension:expr) => ( - { - t!($path, iter: $iter); - t!($path, has_root: $has_root, is_absolute: $is_absolute); - t!($path, parent: $parent, file_name: $file); - t!($path, file_stem: $file_stem, extension: $extension); - } - ); - ); - - #[test] - fn into() { - use crate::borrow::Cow; - - let static_path = Path::new("/home/foo"); - let static_cow_path: Cow<'static, Path> = static_path.into(); - let pathbuf = PathBuf::from("/home/foo"); - - { - let path: &Path = &pathbuf; - let borrowed_cow_path: Cow<'_, Path> = path.into(); - - assert_eq!(static_cow_path, borrowed_cow_path); - } - - let owned_cow_path: Cow<'static, Path> = pathbuf.into(); - - assert_eq!(static_cow_path, owned_cow_path); - } - - #[test] - #[cfg(unix)] - pub fn test_decompositions_unix() { - t!("", - iter: [], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/", - iter: ["/"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("/foo", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/foo/", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("/foo/bar", - iter: ["/", "foo", "bar"], - has_root: true, - is_absolute: true, - parent: Some("/foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("///foo///", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("///foo///bar", - iter: ["/", "foo", "bar"], - has_root: true, - is_absolute: true, - parent: Some("///foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./.", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("/..", - iter: ["/", ".."], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("../", - iter: [".."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/.", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/..", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/./", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/./bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("foo/../", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/../bar", - iter: ["foo", "..", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo/.."), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./a", - iter: [".", "a"], - has_root: false, - is_absolute: false, - parent: Some("."), - file_name: Some("a"), - file_stem: Some("a"), - extension: None - ); - - t!(".", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("./", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("a/b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a//b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/./b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/b/c", - iter: ["a", "b", "c"], - has_root: false, - is_absolute: false, - parent: Some("a/b"), - file_name: Some("c"), - file_stem: Some("c"), - extension: None - ); - - t!(".foo", - iter: [".foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some(".foo"), - file_stem: Some(".foo"), - extension: None - ); - } - - #[test] - #[cfg(windows)] - pub fn test_decompositions_windows() { - t!("", - iter: [], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/", - iter: ["\\"], - has_root: true, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\", - iter: ["\\"], - has_root: true, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("c:", - iter: ["c:"], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("c:\\", - iter: ["c:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("c:/", - iter: ["c:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("/foo", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/foo/", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("/foo/bar", - iter: ["\\", "foo", "bar"], - has_root: true, - is_absolute: false, - parent: Some("/foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("///foo///", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("///foo///bar", - iter: ["\\", "foo", "bar"], - has_root: true, - is_absolute: false, - parent: Some("///foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./.", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("/..", - iter: ["\\", ".."], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("../", - iter: [".."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/.", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/..", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/./", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/./bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("foo/../", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/../bar", - iter: ["foo", "..", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo/.."), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./a", - iter: [".", "a"], - has_root: false, - is_absolute: false, - parent: Some("."), - file_name: Some("a"), - file_stem: Some("a"), - extension: None - ); - - t!(".", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("./", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("a/b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a//b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/./b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/b/c", - iter: ["a", "b", "c"], - has_root: false, - is_absolute: false, - parent: Some("a/b"), - file_name: Some("c"), - file_stem: Some("c"), - extension: None); - - t!("a\\b\\c", - iter: ["a", "b", "c"], - has_root: false, - is_absolute: false, - parent: Some("a\\b"), - file_name: Some("c"), - file_stem: Some("c"), - extension: None - ); - - t!("\\a", - iter: ["\\", "a"], - has_root: true, - is_absolute: false, - parent: Some("\\"), - file_name: Some("a"), - file_stem: Some("a"), - extension: None - ); - - t!("c:\\foo.txt", - iter: ["c:", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("c:\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\server\\share\\foo.txt", - iter: ["\\\\server\\share", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\server\\share\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\server\\share", - iter: ["\\\\server\\share", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\server", - iter: ["\\", "server"], - has_root: true, - is_absolute: false, - parent: Some("\\"), - file_name: Some("server"), - file_stem: Some("server"), - extension: None - ); - - t!("\\\\?\\bar\\foo.txt", - iter: ["\\\\?\\bar", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\bar\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\?\\bar", - iter: ["\\\\?\\bar"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\", - iter: ["\\\\?\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\UNC\\server\\share\\foo.txt", - iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\UNC\\server\\share\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\?\\UNC\\server", - iter: ["\\\\?\\UNC\\server"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\UNC\\", - iter: ["\\\\?\\UNC\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\C:\\foo.txt", - iter: ["\\\\?\\C:", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\C:\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\?\\C:\\", - iter: ["\\\\?\\C:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\C:", - iter: ["\\\\?\\C:"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\foo/bar", - iter: ["\\\\?\\foo/bar"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\C:/foo", - iter: ["\\\\?\\C:/foo"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\.\\foo\\bar", - iter: ["\\\\.\\foo", "\\", "bar"], - has_root: true, - is_absolute: true, - parent: Some("\\\\.\\foo\\"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("\\\\.\\foo", - iter: ["\\\\.\\foo", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\.\\foo/bar", - iter: ["\\\\.\\foo/bar", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\.\\foo\\bar/baz", - iter: ["\\\\.\\foo", "\\", "bar", "baz"], - has_root: true, - is_absolute: true, - parent: Some("\\\\.\\foo\\bar"), - file_name: Some("baz"), - file_stem: Some("baz"), - extension: None - ); - - t!("\\\\.\\", - iter: ["\\\\.\\", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\a\\b\\", - iter: ["\\\\?\\a", "\\", "b"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\a\\"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - } - - #[test] - pub fn test_stem_ext() { - t!("foo", - file_stem: Some("foo"), - extension: None - ); - - t!("foo.", - file_stem: Some("foo"), - extension: Some("") - ); - - t!(".foo", - file_stem: Some(".foo"), - extension: None - ); - - t!("foo.txt", - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("foo.bar.txt", - file_stem: Some("foo.bar"), - extension: Some("txt") - ); - - t!("foo.bar.", - file_stem: Some("foo.bar"), - extension: Some("") - ); - - t!(".", file_stem: None, extension: None); - - t!("..", file_stem: None, extension: None); - - t!("", file_stem: None, extension: None); - } - - #[test] - pub fn test_push() { - macro_rules! tp( - ($path:expr, $push:expr, $expected:expr) => ( { - let mut actual = PathBuf::from($path); - actual.push($push); - assert!(actual.to_str() == Some($expected), - "pushing {:?} onto {:?}: Expected {:?}, got {:?}", - $push, $path, $expected, actual.to_str().unwrap()); - }); - ); - - if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { - tp!("", "foo", "foo"); - tp!("foo", "bar", "foo/bar"); - tp!("foo/", "bar", "foo/bar"); - tp!("foo//", "bar", "foo//bar"); - tp!("foo/.", "bar", "foo/./bar"); - tp!("foo./.", "bar", "foo././bar"); - tp!("foo", "", "foo/"); - tp!("foo", ".", "foo/."); - tp!("foo", "..", "foo/.."); - tp!("foo", "/", "/"); - tp!("/foo/bar", "/", "/"); - tp!("/foo/bar", "/baz", "/baz"); - tp!("/foo/bar", "./baz", "/foo/bar/./baz"); - } else { - tp!("", "foo", "foo"); - tp!("foo", "bar", r"foo\bar"); - tp!("foo/", "bar", r"foo/bar"); - tp!(r"foo\", "bar", r"foo\bar"); - tp!("foo//", "bar", r"foo//bar"); - tp!(r"foo\\", "bar", r"foo\\bar"); - tp!("foo/.", "bar", r"foo/.\bar"); - tp!("foo./.", "bar", r"foo./.\bar"); - tp!(r"foo\.", "bar", r"foo\.\bar"); - tp!(r"foo.\.", "bar", r"foo.\.\bar"); - tp!("foo", "", "foo\\"); - tp!("foo", ".", r"foo\."); - tp!("foo", "..", r"foo\.."); - tp!("foo", "/", "/"); - tp!("foo", r"\", r"\"); - tp!("/foo/bar", "/", "/"); - tp!(r"\foo\bar", r"\", r"\"); - tp!("/foo/bar", "/baz", "/baz"); - tp!("/foo/bar", r"\baz", r"\baz"); - tp!("/foo/bar", "./baz", r"/foo/bar\./baz"); - tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz"); - - tp!("c:\\", "windows", "c:\\windows"); - tp!("c:", "windows", "c:windows"); - - tp!("a\\b\\c", "d", "a\\b\\c\\d"); - tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d"); - tp!("a\\b", "c\\d", "a\\b\\c\\d"); - tp!("a\\b", "\\c\\d", "\\c\\d"); - tp!("a\\b", ".", "a\\b\\."); - tp!("a\\b", "..\\c", "a\\b\\..\\c"); - tp!("a\\b", "C:a.txt", "C:a.txt"); - tp!("a\\b", "C:\\a.txt", "C:\\a.txt"); - tp!("C:\\a", "C:\\b.txt", "C:\\b.txt"); - tp!("C:\\a\\b\\c", "C:d", "C:d"); - tp!("C:a\\b\\c", "C:d", "C:d"); - tp!("C:", r"a\b\c", r"C:a\b\c"); - tp!("C:", r"..\a", r"C:..\a"); - tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar"); - tp!("\\\\server\\share\\foo", "C:baz", "C:baz"); - tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d"); - tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d"); - tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d"); - tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz"); - tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar"); - tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a"); - tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a"); - - // Note: modified from old path API - tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo"); - - tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share"); - tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz"); - tp!("\\\\.\\foo\\bar", "C:a", "C:a"); - // again, not sure about the following, but I'm assuming \\.\ should be verbatim - tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); - - tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one - } - } - - #[test] - pub fn test_pop() { - macro_rules! tp( - ($path:expr, $expected:expr, $output:expr) => ( { - let mut actual = PathBuf::from($path); - let output = actual.pop(); - assert!(actual.to_str() == Some($expected) && output == $output, - "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}", - $path, $expected, $output, - actual.to_str().unwrap(), output); - }); - ); - - tp!("", "", false); - tp!("/", "/", false); - tp!("foo", "", true); - tp!(".", "", true); - tp!("/foo", "/", true); - tp!("/foo/bar", "/foo", true); - tp!("foo/bar", "foo", true); - tp!("foo/.", "", true); - tp!("foo//bar", "foo", true); - - if cfg!(windows) { - tp!("a\\b\\c", "a\\b", true); - tp!("\\a", "\\", true); - tp!("\\", "\\", false); - - tp!("C:\\a\\b", "C:\\a", true); - tp!("C:\\a", "C:\\", true); - tp!("C:\\", "C:\\", false); - tp!("C:a\\b", "C:a", true); - tp!("C:a", "C:", true); - tp!("C:", "C:", false); - tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true); - tp!("\\\\server\\share\\a", "\\\\server\\share\\", true); - tp!("\\\\server\\share", "\\\\server\\share", false); - tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true); - tp!("\\\\?\\a\\b", "\\\\?\\a\\", true); - tp!("\\\\?\\a", "\\\\?\\a", false); - tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true); - tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true); - tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false); - tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true); - tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true); - tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false); - tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true); - tp!("\\\\.\\a\\b", "\\\\.\\a\\", true); - tp!("\\\\.\\a", "\\\\.\\a", false); - - tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true); - } - } - - #[test] - pub fn test_set_file_name() { - macro_rules! tfn( - ($path:expr, $file:expr, $expected:expr) => ( { - let mut p = PathBuf::from($path); - p.set_file_name($file); - assert!(p.to_str() == Some($expected), - "setting file name of {:?} to {:?}: Expected {:?}, got {:?}", - $path, $file, $expected, - p.to_str().unwrap()); - }); - ); - - tfn!("foo", "foo", "foo"); - tfn!("foo", "bar", "bar"); - tfn!("foo", "", ""); - tfn!("", "foo", "foo"); - if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { - tfn!(".", "foo", "./foo"); - tfn!("foo/", "bar", "bar"); - tfn!("foo/.", "bar", "bar"); - tfn!("..", "foo", "../foo"); - tfn!("foo/..", "bar", "foo/../bar"); - tfn!("/", "foo", "/foo"); - } else { - tfn!(".", "foo", r".\foo"); - tfn!(r"foo\", "bar", r"bar"); - tfn!(r"foo\.", "bar", r"bar"); - tfn!("..", "foo", r"..\foo"); - tfn!(r"foo\..", "bar", r"foo\..\bar"); - tfn!(r"\", "foo", r"\foo"); - } - } - - #[test] - pub fn test_set_extension() { - macro_rules! tfe( - ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( { - let mut p = PathBuf::from($path); - let output = p.set_extension($ext); - assert!(p.to_str() == Some($expected) && output == $output, - "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}", - $path, $ext, $expected, $output, - p.to_str().unwrap(), output); - }); - ); - - tfe!("foo", "txt", "foo.txt", true); - tfe!("foo.bar", "txt", "foo.txt", true); - tfe!("foo.bar.baz", "txt", "foo.bar.txt", true); - tfe!(".test", "txt", ".test.txt", true); - tfe!("foo.txt", "", "foo", true); - tfe!("foo", "", "foo", true); - tfe!("", "foo", "", false); - tfe!(".", "foo", ".", false); - tfe!("foo/", "bar", "foo.bar", true); - tfe!("foo/.", "bar", "foo.bar", true); - tfe!("..", "foo", "..", false); - tfe!("foo/..", "bar", "foo/..", false); - tfe!("/", "foo", "/", false); - } - - #[test] - fn test_eq_receivers() { - use crate::borrow::Cow; - - let borrowed: &Path = Path::new("foo/bar"); - let mut owned: PathBuf = PathBuf::new(); - owned.push("foo"); - owned.push("bar"); - let borrowed_cow: Cow<'_, Path> = borrowed.into(); - let owned_cow: Cow<'_, Path> = owned.clone().into(); - - macro_rules! t { - ($($current:expr),+) => { - $( - assert_eq!($current, borrowed); - assert_eq!($current, owned); - assert_eq!($current, borrowed_cow); - assert_eq!($current, owned_cow); - )+ - } - } - - t!(borrowed, owned, borrowed_cow, owned_cow); - } - - #[test] - pub fn test_compare() { - use crate::collections::hash_map::DefaultHasher; - use crate::hash::{Hash, Hasher}; - - fn hash(t: T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() - } - - macro_rules! tc( - ($path1:expr, $path2:expr, eq: $eq:expr, - starts_with: $starts_with:expr, ends_with: $ends_with:expr, - relative_from: $relative_from:expr) => ({ - let path1 = Path::new($path1); - let path2 = Path::new($path2); - - let eq = path1 == path2; - assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}", - $path1, $path2, $eq, eq); - assert!($eq == (hash(path1) == hash(path2)), - "{:?} == {:?}, expected {:?}, got {} and {}", - $path1, $path2, $eq, hash(path1), hash(path2)); - - let starts_with = path1.starts_with(path2); - assert!(starts_with == $starts_with, - "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2, - $starts_with, starts_with); - - let ends_with = path1.ends_with(path2); - assert!(ends_with == $ends_with, - "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2, - $ends_with, ends_with); - - let relative_from = path1.strip_prefix(path2) - .map(|p| p.to_str().unwrap()) - .ok(); - let exp: Option<&str> = $relative_from; - assert!(relative_from == exp, - "{:?}.strip_prefix({:?}), expected {:?}, got {:?}", - $path1, $path2, exp, relative_from); - }); - ); - - tc!("", "", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo", "", - eq: false, - starts_with: true, - ends_with: true, - relative_from: Some("foo") - ); - - tc!("", "foo", - eq: false, - starts_with: false, - ends_with: false, - relative_from: None - ); - - tc!("foo", "foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo/", "foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo/bar", "foo", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("bar") - ); - - tc!("foo/bar/baz", "foo/bar", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("baz") - ); - - tc!("foo/bar", "foo/bar/baz", - eq: false, - starts_with: false, - ends_with: false, - relative_from: None - ); - - tc!("./foo/bar/", ".", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("foo/bar") - ); - - if cfg!(windows) { - tc!(r"C:\src\rust\cargo-test\test\Cargo.toml", - r"c:\src\rust\cargo-test\test", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("Cargo.toml") - ); - - tc!(r"c:\foo", r"C:\foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - } - } - - #[test] - fn test_components_debug() { - let path = Path::new("/tmp"); - - let mut components = path.components(); - - let expected = "Components([RootDir, Normal(\"tmp\")])"; - let actual = format!("{:?}", components); - assert_eq!(expected, actual); - - let _ = components.next().unwrap(); - let expected = "Components([Normal(\"tmp\")])"; - let actual = format!("{:?}", components); - assert_eq!(expected, actual); - - let _ = components.next().unwrap(); - let expected = "Components([])"; - let actual = format!("{:?}", components); - assert_eq!(expected, actual); - } - - #[cfg(unix)] - #[test] - fn test_iter_debug() { - let path = Path::new("/tmp"); - - let mut iter = path.iter(); - - let expected = "Iter([\"/\", \"tmp\"])"; - let actual = format!("{:?}", iter); - assert_eq!(expected, actual); - - let _ = iter.next().unwrap(); - let expected = "Iter([\"tmp\"])"; - let actual = format!("{:?}", iter); - assert_eq!(expected, actual); - - let _ = iter.next().unwrap(); - let expected = "Iter([])"; - let actual = format!("{:?}", iter); - assert_eq!(expected, actual); - } - - #[test] - fn into_boxed() { - let orig: &str = "some/sort/of/path"; - let path = Path::new(orig); - let boxed: Box = Box::from(path); - let path_buf = path.to_owned().into_boxed_path().into_path_buf(); - assert_eq!(path, &*boxed); - assert_eq!(&*boxed, &*path_buf); - assert_eq!(&*path_buf, path); - } - - #[test] - fn test_clone_into() { - let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious"); - let path = Path::new("short"); - path.clone_into(&mut path_buf); - assert_eq!(path, path_buf); - assert!(path_buf.into_os_string().capacity() >= 15); - } - - #[test] - fn display_format_flags() { - assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b"); - assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b"); - } - - #[test] - fn into_rc() { - let orig = "hello/world"; - let path = Path::new(orig); - let rc: Rc = Rc::from(path); - let arc: Arc = Arc::from(path); - - assert_eq!(&*rc, path); - assert_eq!(&*arc, path); - - let rc2: Rc = Rc::from(path.to_owned()); - let arc2: Arc = Arc::from(path.to_owned()); - - assert_eq!(&*rc2, path); - assert_eq!(&*arc2, path); - } -} diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs new file mode 100644 index 0000000000..ff94fda5a2 --- /dev/null +++ b/library/std/src/path/tests.rs @@ -0,0 +1,1394 @@ +use super::*; + +use crate::rc::Rc; +use crate::sync::Arc; + +macro_rules! t( + ($path:expr, iter: $iter:expr) => ( + { + let path = Path::new($path); + + // Forward iteration + let comps = path.iter() + .map(|p| p.to_string_lossy().into_owned()) + .collect::>(); + let exp: &[&str] = &$iter; + let exps = exp.iter().map(|s| s.to_string()).collect::>(); + assert!(comps == exps, "iter: Expected {:?}, found {:?}", + exps, comps); + + // Reverse iteration + let comps = Path::new($path).iter().rev() + .map(|p| p.to_string_lossy().into_owned()) + .collect::>(); + let exps = exps.into_iter().rev().collect::>(); + assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}", + exps, comps); + } + ); + + ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => ( + { + let path = Path::new($path); + + let act_root = path.has_root(); + assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}", + $has_root, act_root); + + let act_abs = path.is_absolute(); + assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}", + $is_absolute, act_abs); + } + ); + + ($path:expr, parent: $parent:expr, file_name: $file:expr) => ( + { + let path = Path::new($path); + + let parent = path.parent().map(|p| p.to_str().unwrap()); + let exp_parent: Option<&str> = $parent; + assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}", + exp_parent, parent); + + let file = path.file_name().map(|p| p.to_str().unwrap()); + let exp_file: Option<&str> = $file; + assert!(file == exp_file, "file_name: Expected {:?}, found {:?}", + exp_file, file); + } + ); + + ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => ( + { + let path = Path::new($path); + + let stem = path.file_stem().map(|p| p.to_str().unwrap()); + let exp_stem: Option<&str> = $file_stem; + assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}", + exp_stem, stem); + + let ext = path.extension().map(|p| p.to_str().unwrap()); + let exp_ext: Option<&str> = $extension; + assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}", + exp_ext, ext); + } + ); + + ($path:expr, iter: $iter:expr, + has_root: $has_root:expr, is_absolute: $is_absolute:expr, + parent: $parent:expr, file_name: $file:expr, + file_stem: $file_stem:expr, extension: $extension:expr) => ( + { + t!($path, iter: $iter); + t!($path, has_root: $has_root, is_absolute: $is_absolute); + t!($path, parent: $parent, file_name: $file); + t!($path, file_stem: $file_stem, extension: $extension); + } + ); +); + +#[test] +fn into() { + use crate::borrow::Cow; + + let static_path = Path::new("/home/foo"); + let static_cow_path: Cow<'static, Path> = static_path.into(); + let pathbuf = PathBuf::from("/home/foo"); + + { + let path: &Path = &pathbuf; + let borrowed_cow_path: Cow<'_, Path> = path.into(); + + assert_eq!(static_cow_path, borrowed_cow_path); + } + + let owned_cow_path: Cow<'static, Path> = pathbuf.into(); + + assert_eq!(static_cow_path, owned_cow_path); +} + +#[test] +#[cfg(unix)] +pub fn test_decompositions_unix() { + t!("", + iter: [], + has_root: false, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("/", + iter: ["/"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("/foo", + iter: ["/", "foo"], + has_root: true, + is_absolute: true, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("/foo/", + iter: ["/", "foo"], + has_root: true, + is_absolute: true, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/bar", + iter: ["foo", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("/foo/bar", + iter: ["/", "foo", "bar"], + has_root: true, + is_absolute: true, + parent: Some("/foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("///foo///", + iter: ["/", "foo"], + has_root: true, + is_absolute: true, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("///foo///bar", + iter: ["/", "foo", "bar"], + has_root: true, + is_absolute: true, + parent: Some("///foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("./.", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("/..", + iter: ["/", ".."], + has_root: true, + is_absolute: true, + parent: Some("/"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("../", + iter: [".."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/.", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/..", + iter: ["foo", ".."], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/./", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/./bar", + iter: ["foo", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("foo/../", + iter: ["foo", ".."], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/../bar", + iter: ["foo", "..", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo/.."), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("./a", + iter: [".", "a"], + has_root: false, + is_absolute: false, + parent: Some("."), + file_name: Some("a"), + file_stem: Some("a"), + extension: None + ); + + t!(".", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("./", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("a/b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a//b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a/./b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a/b/c", + iter: ["a", "b", "c"], + has_root: false, + is_absolute: false, + parent: Some("a/b"), + file_name: Some("c"), + file_stem: Some("c"), + extension: None + ); + + t!(".foo", + iter: [".foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some(".foo"), + file_stem: Some(".foo"), + extension: None + ); +} + +#[test] +#[cfg(windows)] +pub fn test_decompositions_windows() { + t!("", + iter: [], + has_root: false, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("/", + iter: ["\\"], + has_root: true, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\", + iter: ["\\"], + has_root: true, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("c:", + iter: ["c:"], + has_root: false, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("c:\\", + iter: ["c:", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("c:/", + iter: ["c:", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("/foo", + iter: ["\\", "foo"], + has_root: true, + is_absolute: false, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("/foo/", + iter: ["\\", "foo"], + has_root: true, + is_absolute: false, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/bar", + iter: ["foo", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("/foo/bar", + iter: ["\\", "foo", "bar"], + has_root: true, + is_absolute: false, + parent: Some("/foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("///foo///", + iter: ["\\", "foo"], + has_root: true, + is_absolute: false, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("///foo///bar", + iter: ["\\", "foo", "bar"], + has_root: true, + is_absolute: false, + parent: Some("///foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("./.", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("/..", + iter: ["\\", ".."], + has_root: true, + is_absolute: false, + parent: Some("/"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("../", + iter: [".."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/.", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/..", + iter: ["foo", ".."], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/./", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/./bar", + iter: ["foo", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("foo/../", + iter: ["foo", ".."], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/../bar", + iter: ["foo", "..", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo/.."), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("./a", + iter: [".", "a"], + has_root: false, + is_absolute: false, + parent: Some("."), + file_name: Some("a"), + file_stem: Some("a"), + extension: None + ); + + t!(".", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("./", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("a/b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a//b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a/./b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a/b/c", + iter: ["a", "b", "c"], + has_root: false, + is_absolute: false, + parent: Some("a/b"), + file_name: Some("c"), + file_stem: Some("c"), + extension: None); + + t!("a\\b\\c", + iter: ["a", "b", "c"], + has_root: false, + is_absolute: false, + parent: Some("a\\b"), + file_name: Some("c"), + file_stem: Some("c"), + extension: None + ); + + t!("\\a", + iter: ["\\", "a"], + has_root: true, + is_absolute: false, + parent: Some("\\"), + file_name: Some("a"), + file_stem: Some("a"), + extension: None + ); + + t!("c:\\foo.txt", + iter: ["c:", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("c:\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\server\\share\\foo.txt", + iter: ["\\\\server\\share", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\server\\share\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\server\\share", + iter: ["\\\\server\\share", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\server", + iter: ["\\", "server"], + has_root: true, + is_absolute: false, + parent: Some("\\"), + file_name: Some("server"), + file_stem: Some("server"), + extension: None + ); + + t!("\\\\?\\bar\\foo.txt", + iter: ["\\\\?\\bar", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\bar\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\?\\bar", + iter: ["\\\\?\\bar"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\", + iter: ["\\\\?\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\UNC\\server\\share\\foo.txt", + iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\UNC\\server\\share\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\?\\UNC\\server", + iter: ["\\\\?\\UNC\\server"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\UNC\\", + iter: ["\\\\?\\UNC\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\C:\\foo.txt", + iter: ["\\\\?\\C:", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\C:\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\?\\C:\\", + iter: ["\\\\?\\C:", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\C:", + iter: ["\\\\?\\C:"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\foo/bar", + iter: ["\\\\?\\foo/bar"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\C:/foo", + iter: ["\\\\?\\C:/foo"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\.\\foo\\bar", + iter: ["\\\\.\\foo", "\\", "bar"], + has_root: true, + is_absolute: true, + parent: Some("\\\\.\\foo\\"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("\\\\.\\foo", + iter: ["\\\\.\\foo", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\.\\foo/bar", + iter: ["\\\\.\\foo/bar", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\.\\foo\\bar/baz", + iter: ["\\\\.\\foo", "\\", "bar", "baz"], + has_root: true, + is_absolute: true, + parent: Some("\\\\.\\foo\\bar"), + file_name: Some("baz"), + file_stem: Some("baz"), + extension: None + ); + + t!("\\\\.\\", + iter: ["\\\\.\\", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\a\\b\\", + iter: ["\\\\?\\a", "\\", "b"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\a\\"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); +} + +#[test] +pub fn test_stem_ext() { + t!("foo", + file_stem: Some("foo"), + extension: None + ); + + t!("foo.", + file_stem: Some("foo"), + extension: Some("") + ); + + t!(".foo", + file_stem: Some(".foo"), + extension: None + ); + + t!("foo.txt", + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("foo.bar.txt", + file_stem: Some("foo.bar"), + extension: Some("txt") + ); + + t!("foo.bar.", + file_stem: Some("foo.bar"), + extension: Some("") + ); + + t!(".", file_stem: None, extension: None); + + t!("..", file_stem: None, extension: None); + + t!("", file_stem: None, extension: None); +} + +#[test] +pub fn test_push() { + macro_rules! tp( + ($path:expr, $push:expr, $expected:expr) => ( { + let mut actual = PathBuf::from($path); + actual.push($push); + assert!(actual.to_str() == Some($expected), + "pushing {:?} onto {:?}: Expected {:?}, got {:?}", + $push, $path, $expected, actual.to_str().unwrap()); + }); + ); + + if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { + tp!("", "foo", "foo"); + tp!("foo", "bar", "foo/bar"); + tp!("foo/", "bar", "foo/bar"); + tp!("foo//", "bar", "foo//bar"); + tp!("foo/.", "bar", "foo/./bar"); + tp!("foo./.", "bar", "foo././bar"); + tp!("foo", "", "foo/"); + tp!("foo", ".", "foo/."); + tp!("foo", "..", "foo/.."); + tp!("foo", "/", "/"); + tp!("/foo/bar", "/", "/"); + tp!("/foo/bar", "/baz", "/baz"); + tp!("/foo/bar", "./baz", "/foo/bar/./baz"); + } else { + tp!("", "foo", "foo"); + tp!("foo", "bar", r"foo\bar"); + tp!("foo/", "bar", r"foo/bar"); + tp!(r"foo\", "bar", r"foo\bar"); + tp!("foo//", "bar", r"foo//bar"); + tp!(r"foo\\", "bar", r"foo\\bar"); + tp!("foo/.", "bar", r"foo/.\bar"); + tp!("foo./.", "bar", r"foo./.\bar"); + tp!(r"foo\.", "bar", r"foo\.\bar"); + tp!(r"foo.\.", "bar", r"foo.\.\bar"); + tp!("foo", "", "foo\\"); + tp!("foo", ".", r"foo\."); + tp!("foo", "..", r"foo\.."); + tp!("foo", "/", "/"); + tp!("foo", r"\", r"\"); + tp!("/foo/bar", "/", "/"); + tp!(r"\foo\bar", r"\", r"\"); + tp!("/foo/bar", "/baz", "/baz"); + tp!("/foo/bar", r"\baz", r"\baz"); + tp!("/foo/bar", "./baz", r"/foo/bar\./baz"); + tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz"); + + tp!("c:\\", "windows", "c:\\windows"); + tp!("c:", "windows", "c:windows"); + + tp!("a\\b\\c", "d", "a\\b\\c\\d"); + tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d"); + tp!("a\\b", "c\\d", "a\\b\\c\\d"); + tp!("a\\b", "\\c\\d", "\\c\\d"); + tp!("a\\b", ".", "a\\b\\."); + tp!("a\\b", "..\\c", "a\\b\\..\\c"); + tp!("a\\b", "C:a.txt", "C:a.txt"); + tp!("a\\b", "C:\\a.txt", "C:\\a.txt"); + tp!("C:\\a", "C:\\b.txt", "C:\\b.txt"); + tp!("C:\\a\\b\\c", "C:d", "C:d"); + tp!("C:a\\b\\c", "C:d", "C:d"); + tp!("C:", r"a\b\c", r"C:a\b\c"); + tp!("C:", r"..\a", r"C:..\a"); + tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar"); + tp!("\\\\server\\share\\foo", "C:baz", "C:baz"); + tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d"); + tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d"); + tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d"); + tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz"); + tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar"); + tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a"); + tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a"); + + // Note: modified from old path API + tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo"); + + tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share"); + tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz"); + tp!("\\\\.\\foo\\bar", "C:a", "C:a"); + // again, not sure about the following, but I'm assuming \\.\ should be verbatim + tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); + + tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one + } +} + +#[test] +pub fn test_pop() { + macro_rules! tp( + ($path:expr, $expected:expr, $output:expr) => ( { + let mut actual = PathBuf::from($path); + let output = actual.pop(); + assert!(actual.to_str() == Some($expected) && output == $output, + "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}", + $path, $expected, $output, + actual.to_str().unwrap(), output); + }); + ); + + tp!("", "", false); + tp!("/", "/", false); + tp!("foo", "", true); + tp!(".", "", true); + tp!("/foo", "/", true); + tp!("/foo/bar", "/foo", true); + tp!("foo/bar", "foo", true); + tp!("foo/.", "", true); + tp!("foo//bar", "foo", true); + + if cfg!(windows) { + tp!("a\\b\\c", "a\\b", true); + tp!("\\a", "\\", true); + tp!("\\", "\\", false); + + tp!("C:\\a\\b", "C:\\a", true); + tp!("C:\\a", "C:\\", true); + tp!("C:\\", "C:\\", false); + tp!("C:a\\b", "C:a", true); + tp!("C:a", "C:", true); + tp!("C:", "C:", false); + tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true); + tp!("\\\\server\\share\\a", "\\\\server\\share\\", true); + tp!("\\\\server\\share", "\\\\server\\share", false); + tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true); + tp!("\\\\?\\a\\b", "\\\\?\\a\\", true); + tp!("\\\\?\\a", "\\\\?\\a", false); + tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true); + tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true); + tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false); + tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true); + tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true); + tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false); + tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true); + tp!("\\\\.\\a\\b", "\\\\.\\a\\", true); + tp!("\\\\.\\a", "\\\\.\\a", false); + + tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true); + } +} + +#[test] +pub fn test_set_file_name() { + macro_rules! tfn( + ($path:expr, $file:expr, $expected:expr) => ( { + let mut p = PathBuf::from($path); + p.set_file_name($file); + assert!(p.to_str() == Some($expected), + "setting file name of {:?} to {:?}: Expected {:?}, got {:?}", + $path, $file, $expected, + p.to_str().unwrap()); + }); + ); + + tfn!("foo", "foo", "foo"); + tfn!("foo", "bar", "bar"); + tfn!("foo", "", ""); + tfn!("", "foo", "foo"); + if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { + tfn!(".", "foo", "./foo"); + tfn!("foo/", "bar", "bar"); + tfn!("foo/.", "bar", "bar"); + tfn!("..", "foo", "../foo"); + tfn!("foo/..", "bar", "foo/../bar"); + tfn!("/", "foo", "/foo"); + } else { + tfn!(".", "foo", r".\foo"); + tfn!(r"foo\", "bar", r"bar"); + tfn!(r"foo\.", "bar", r"bar"); + tfn!("..", "foo", r"..\foo"); + tfn!(r"foo\..", "bar", r"foo\..\bar"); + tfn!(r"\", "foo", r"\foo"); + } +} + +#[test] +pub fn test_set_extension() { + macro_rules! tfe( + ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( { + let mut p = PathBuf::from($path); + let output = p.set_extension($ext); + assert!(p.to_str() == Some($expected) && output == $output, + "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}", + $path, $ext, $expected, $output, + p.to_str().unwrap(), output); + }); + ); + + tfe!("foo", "txt", "foo.txt", true); + tfe!("foo.bar", "txt", "foo.txt", true); + tfe!("foo.bar.baz", "txt", "foo.bar.txt", true); + tfe!(".test", "txt", ".test.txt", true); + tfe!("foo.txt", "", "foo", true); + tfe!("foo", "", "foo", true); + tfe!("", "foo", "", false); + tfe!(".", "foo", ".", false); + tfe!("foo/", "bar", "foo.bar", true); + tfe!("foo/.", "bar", "foo.bar", true); + tfe!("..", "foo", "..", false); + tfe!("foo/..", "bar", "foo/..", false); + tfe!("/", "foo", "/", false); +} + +#[test] +fn test_eq_receivers() { + use crate::borrow::Cow; + + let borrowed: &Path = Path::new("foo/bar"); + let mut owned: PathBuf = PathBuf::new(); + owned.push("foo"); + owned.push("bar"); + let borrowed_cow: Cow<'_, Path> = borrowed.into(); + let owned_cow: Cow<'_, Path> = owned.clone().into(); + + macro_rules! t { + ($($current:expr),+) => { + $( + assert_eq!($current, borrowed); + assert_eq!($current, owned); + assert_eq!($current, borrowed_cow); + assert_eq!($current, owned_cow); + )+ + } + } + + t!(borrowed, owned, borrowed_cow, owned_cow); +} + +#[test] +pub fn test_compare() { + use crate::collections::hash_map::DefaultHasher; + use crate::hash::{Hash, Hasher}; + + fn hash(t: T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + macro_rules! tc( + ($path1:expr, $path2:expr, eq: $eq:expr, + starts_with: $starts_with:expr, ends_with: $ends_with:expr, + relative_from: $relative_from:expr) => ({ + let path1 = Path::new($path1); + let path2 = Path::new($path2); + + let eq = path1 == path2; + assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}", + $path1, $path2, $eq, eq); + assert!($eq == (hash(path1) == hash(path2)), + "{:?} == {:?}, expected {:?}, got {} and {}", + $path1, $path2, $eq, hash(path1), hash(path2)); + + let starts_with = path1.starts_with(path2); + assert!(starts_with == $starts_with, + "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2, + $starts_with, starts_with); + + let ends_with = path1.ends_with(path2); + assert!(ends_with == $ends_with, + "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2, + $ends_with, ends_with); + + let relative_from = path1.strip_prefix(path2) + .map(|p| p.to_str().unwrap()) + .ok(); + let exp: Option<&str> = $relative_from; + assert!(relative_from == exp, + "{:?}.strip_prefix({:?}), expected {:?}, got {:?}", + $path1, $path2, exp, relative_from); + }); + ); + + tc!("", "", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo", "", + eq: false, + starts_with: true, + ends_with: true, + relative_from: Some("foo") + ); + + tc!("", "foo", + eq: false, + starts_with: false, + ends_with: false, + relative_from: None + ); + + tc!("foo", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo/", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo/bar", "foo", + eq: false, + starts_with: true, + ends_with: false, + relative_from: Some("bar") + ); + + tc!("foo/bar/baz", "foo/bar", + eq: false, + starts_with: true, + ends_with: false, + relative_from: Some("baz") + ); + + tc!("foo/bar", "foo/bar/baz", + eq: false, + starts_with: false, + ends_with: false, + relative_from: None + ); + + tc!("./foo/bar/", ".", + eq: false, + starts_with: true, + ends_with: false, + relative_from: Some("foo/bar") + ); + + if cfg!(windows) { + tc!(r"C:\src\rust\cargo-test\test\Cargo.toml", + r"c:\src\rust\cargo-test\test", + eq: false, + starts_with: true, + ends_with: false, + relative_from: Some("Cargo.toml") + ); + + tc!(r"c:\foo", r"C:\foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + } +} + +#[test] +fn test_components_debug() { + let path = Path::new("/tmp"); + + let mut components = path.components(); + + let expected = "Components([RootDir, Normal(\"tmp\")])"; + let actual = format!("{:?}", components); + assert_eq!(expected, actual); + + let _ = components.next().unwrap(); + let expected = "Components([Normal(\"tmp\")])"; + let actual = format!("{:?}", components); + assert_eq!(expected, actual); + + let _ = components.next().unwrap(); + let expected = "Components([])"; + let actual = format!("{:?}", components); + assert_eq!(expected, actual); +} + +#[cfg(unix)] +#[test] +fn test_iter_debug() { + let path = Path::new("/tmp"); + + let mut iter = path.iter(); + + let expected = "Iter([\"/\", \"tmp\"])"; + let actual = format!("{:?}", iter); + assert_eq!(expected, actual); + + let _ = iter.next().unwrap(); + let expected = "Iter([\"tmp\"])"; + let actual = format!("{:?}", iter); + assert_eq!(expected, actual); + + let _ = iter.next().unwrap(); + let expected = "Iter([])"; + let actual = format!("{:?}", iter); + assert_eq!(expected, actual); +} + +#[test] +fn into_boxed() { + let orig: &str = "some/sort/of/path"; + let path = Path::new(orig); + let boxed: Box = Box::from(path); + let path_buf = path.to_owned().into_boxed_path().into_path_buf(); + assert_eq!(path, &*boxed); + assert_eq!(&*boxed, &*path_buf); + assert_eq!(&*path_buf, path); +} + +#[test] +fn test_clone_into() { + let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious"); + let path = Path::new("short"); + path.clone_into(&mut path_buf); + assert_eq!(path, path_buf); + assert!(path_buf.into_os_string().capacity() >= 15); +} + +#[test] +fn display_format_flags() { + assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b"); + assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b"); +} + +#[test] +fn into_rc() { + let orig = "hello/world"; + let path = Path::new(orig); + let rc: Rc = Rc::from(path); + let arc: Arc = Arc::from(path); + + assert_eq!(&*rc, path); + assert_eq!(&*arc, path); + + let rc2: Rc = Rc::from(path.to_owned()); + let arc2: Arc = Arc::from(path.to_owned()); + + assert_eq!(&*rc2, path); + assert_eq!(&*arc2, path); +} diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 710c616be7..c7a7c779d3 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -75,7 +75,7 @@ //! [`std::result`]: crate::result //! [`std::slice`]: crate::slice //! [`std::string`]: crate::string -//! [`std::vec`]: ../vec/index.html +//! [`std::vec`]: mod@crate::vec //! [`to_owned`]: crate::borrow::ToOwned::to_owned //! [book-closures]: ../../book/ch13-01-closures.html //! [book-dtor]: ../../book/ch15-03-drop.html diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index be7fd0dd6c..81bbf37637 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1,7 +1,6 @@ #[doc(primitive = "bool")] #[doc(alias = "true")] #[doc(alias = "false")] -// /// The boolean type. /// /// The `bool` represents a value, which could only be either `true` or `false`. If you cast @@ -12,18 +11,17 @@ /// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc., /// which allow us to perform boolean operations using `&`, `|` and `!`. /// -/// `if` always demands a `bool` value. [`assert!`], being an important macro in testing, -/// checks whether an expression returns `true`. +/// `if` always demands a `bool` value. [`assert!`], which is an important macro in testing, +/// checks whether an expression returns `true` and panics if it isn't. /// /// ``` /// let bool_val = true & false | false; /// assert!(!bool_val); /// ``` /// -/// [`assert!`]: macro.assert.html -/// [`BitAnd`]: ops/trait.BitAnd.html -/// [`BitOr`]: ops/trait.BitOr.html -/// [`Not`]: ops/trait.Not.html +/// [`BitAnd`]: ops::BitAnd +/// [`BitOr`]: ops::BitOr +/// [`Not`]: ops::Not /// /// # Examples /// @@ -46,7 +44,7 @@ /// } /// ``` /// -/// Also, since `bool` implements the [`Copy`](marker/trait.Copy.html) trait, we don't +/// Also, since `bool` implements the [`Copy`] trait, we don't /// have to worry about the move semantics (just like the integer and float primitives). /// /// Now an example of `bool` cast to integer type: @@ -100,8 +98,8 @@ mod prim_bool {} /// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another /// behaviour of the `!` type - expressions with type `!` will coerce into any other type. /// -/// [`u32`]: primitive.str.html -/// [`exit`]: process/fn.exit.html +/// [`u32`]: prim@u32 +/// [`exit`]: process::exit /// /// # `!` and generics /// @@ -185,26 +183,58 @@ mod prim_bool {} /// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok` /// because `!` coerces to `Result` automatically. /// -/// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str -/// [`Result`]: result/enum.Result.html -/// [`Result`]: result/enum.Result.html -/// [`Result`]: result/enum.Result.html -/// [`Ok`]: result/enum.Result.html#variant.Ok -/// [`String`]: string/struct.String.html -/// [`Err`]: result/enum.Result.html#variant.Err -/// [`FromStr`]: str/trait.FromStr.html +/// [`String::from_str`]: str::FromStr::from_str +/// [`Result`]: Result +/// [`Result`]: Result +/// [`Result`]: Result +/// [`String`]: string::String +/// [`FromStr`]: str::FromStr /// /// # `!` and traits /// /// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` -/// which doesn't `panic!`. As it turns out, most traits can have an `impl` for `!`. Take [`Debug`] +/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` where `!` +/// does not have an `impl` of `Trait` cannot diverge as their only possible code path. In other +/// words, they can't return `!` from every code path. As an example, this code doesn't compile: +/// +/// ```compile_fail +/// use core::ops::Add; +/// +/// fn foo() -> impl Add { +/// unimplemented!() +/// } +/// ``` +/// +/// But this code does: +/// +/// ``` +/// use core::ops::Add; +/// +/// fn foo() -> impl Add { +/// if true { +/// unimplemented!() +/// } else { +/// 0 +/// } +/// } +/// ``` +/// +/// The reason is that, in the first example, there are many possible types that `!` could coerce +/// to, because many types implement `Add`. However, in the second example, +/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type +/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375] +/// for more information on this quirk of `!`. +/// +/// [#36375]: https://github.com/rust-lang/rust/issues/36375 +/// +/// As it turns out, though, most traits can have an `impl` for `!`. Take [`Debug`] /// for example: /// /// ``` /// #![feature(never_type)] /// # use std::fmt; /// # trait Debug { -/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; +/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; /// # } /// impl Debug for ! { /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -233,11 +263,9 @@ mod prim_bool {} /// `impl` for this which simply panics, but the same is true for any type (we could `impl /// Default` for (eg.) [`File`] by just making [`default()`] panic.) /// -/// [`fmt::Result`]: fmt/type.Result.html -/// [`File`]: fs/struct.File.html -/// [`Debug`]: fmt/trait.Debug.html -/// [`Default`]: default/trait.Default.html -/// [`default()`]: default/trait.Default.html#tymethod.default +/// [`File`]: fs::File +/// [`Debug`]: fmt::Debug +/// [`default()`]: Default::default /// #[unstable(feature = "never_type", issue = "35121")] mod prim_never {} @@ -356,11 +384,12 @@ mod prim_char {} #[stable(feature = "rust1", since = "1.0.0")] mod prim_unit {} +#[doc(alias = "ptr")] #[doc(primitive = "pointer")] // /// Raw, unsafe pointers, `*const T`, and `*mut T`. /// -/// *[See also the `std::ptr` module](ptr/index.html).* +/// *[See also the `std::ptr` module][`ptr`].* /// /// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. /// Raw pointers can be unaligned or [`null`]. However, when a raw pointer is @@ -439,13 +468,13 @@ mod prim_unit {} /// but C APIs hand out a lot of pointers generally, so are a common source /// of raw pointers in Rust. /// -/// [`null`]: ../std/ptr/fn.null.html -/// [`null_mut`]: ../std/ptr/fn.null_mut.html +/// [`null`]: ptr::null +/// [`null_mut`]: ptr::null_mut /// [`is_null`]: ../std/primitive.pointer.html#method.is_null /// [`offset`]: ../std/primitive.pointer.html#method.offset -/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw -/// [`drop`]: ../std/mem/fn.drop.html -/// [`write`]: ../std/ptr/fn.write.html +/// [`into_raw`]: Box::into_raw +/// [`drop`]: mem::drop +/// [`write`]: ptr::write #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} @@ -458,32 +487,32 @@ mod prim_pointer {} /// /// * A list with each element, i.e., `[x, y, z]`. /// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. -/// The type of `x` must be [`Copy`][copy]. +/// The type of `x` must be [`Copy`]. /// /// Arrays of *any* size implement the following traits if the element type allows it: /// -/// - [`Debug`][debug] -/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) -/// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] -/// - [`Hash`][hash] -/// - [`AsRef`][asref], [`AsMut`][asmut] -/// - [`Borrow`][borrow], [`BorrowMut`][borrowmut] +/// - [`Debug`] +/// - [`IntoIterator`] (implemented for `&[T; N]` and `&mut [T; N]`) +/// - [`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] +/// - [`Hash`] +/// - [`AsRef`], [`AsMut`] +/// - [`Borrow`], [`BorrowMut`] /// -/// Arrays of sizes from 0 to 32 (inclusive) implement [`Default`][default] trait +/// Arrays of sizes from 0 to 32 (inclusive) implement [`Default`] trait /// if the element type allows it. As a stopgap, trait implementations are /// statically generated up to size 32. /// -/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy] -/// and [`Clone`][clone] if the element type is [`Clone`][clone]. This works -/// because [`Copy`][copy] and [`Clone`][clone] traits are specially known +/// Arrays of *any* size are [`Copy`] if the element type is [`Copy`] +/// and [`Clone`] if the element type is [`Clone`]. This works +/// because [`Copy`] and [`Clone`] traits are specially known /// to the compiler. /// /// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on /// an array. Indeed, this provides most of the API for working with arrays. /// Slices have a dynamic size and do not coerce to arrays. /// -/// You can move elements out of an array with a slice pattern. If you want -/// one element, see [`mem::replace`][replace]. +/// You can move elements out of an array with a [slice pattern]. If you want +/// one element, see [`mem::replace`]. /// /// # Examples /// @@ -524,7 +553,7 @@ mod prim_pointer {} /// for x in &array { } /// ``` /// -/// You can use a slice pattern to move elements out of an array: +/// You can use a [slice pattern] to move elements out of an array: /// /// ``` /// fn move_away(_: String) { /* Do interesting things. */ } @@ -535,23 +564,11 @@ mod prim_pointer {} /// ``` /// /// [slice]: primitive.slice.html -/// [copy]: marker/trait.Copy.html -/// [clone]: clone/trait.Clone.html -/// [debug]: fmt/trait.Debug.html -/// [intoiterator]: iter/trait.IntoIterator.html -/// [partialeq]: cmp/trait.PartialEq.html -/// [partialord]: cmp/trait.PartialOrd.html -/// [eq]: cmp/trait.Eq.html -/// [ord]: cmp/trait.Ord.html -/// [hash]: hash/trait.Hash.html -/// [asref]: convert/trait.AsRef.html -/// [asmut]: convert/trait.AsMut.html -/// [borrow]: borrow/trait.Borrow.html -/// [borrowmut]: borrow/trait.BorrowMut.html -/// [default]: default/trait.Default.html -/// [replace]: mem/fn.replace.html -/// [`IntoIterator`]: iter/trait.IntoIterator.html -/// +/// [`Debug`]: fmt::Debug +/// [`Hash`]: hash::Hash +/// [`Borrow`]: borrow::Borrow +/// [`BorrowMut`]: borrow::BorrowMut +/// [slice pattern]: ../reference/patterns.html#slice-patterns #[stable(feature = "rust1", since = "1.0.0")] mod prim_array {} @@ -563,7 +580,7 @@ mod prim_array {} /// means that elements are laid out so that every element is the same /// distance from its neighbors. /// -/// *[See also the `std::slice` module](slice/index.html).* +/// *[See also the `std::slice` module][`crate::slice`].* /// /// Slices are a view into a block of memory represented as a pointer and a /// length. @@ -608,7 +625,7 @@ mod prim_slice {} // /// String slices. /// -/// *[See also the `std::str` module](str/index.html).* +/// *[See also the `std::str` module][`crate::str`].* /// /// The `str` type, also called a 'string slice', is the most primitive string /// type. It is usually seen in its borrowed form, `&str`. It is also the type @@ -660,8 +677,8 @@ mod prim_slice {} /// assert_eq!(s, Ok(story)); /// ``` /// -/// [`as_ptr`]: #method.as_ptr -/// [`len`]: #method.len +/// [`as_ptr`]: str::as_ptr +/// [`len`]: str::len /// /// Note: This example shows the internals of `&str`. `unsafe` should not be /// used to get a string slice under normal circumstances. Use `as_str` @@ -729,15 +746,8 @@ mod prim_str {} /// * [`Default`] /// * [`Hash`] /// -/// [`Clone`]: clone/trait.Clone.html -/// [`Copy`]: marker/trait.Copy.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`Eq`]: cmp/trait.Eq.html -/// [`PartialOrd`]: cmp/trait.PartialOrd.html -/// [`Ord`]: cmp/trait.Ord.html -/// [`Debug`]: fmt/trait.Debug.html -/// [`Default`]: default/trait.Default.html -/// [`Hash`]: hash/trait.Hash.html +/// [`Debug`]: fmt::Debug +/// [`Hash`]: hash::Hash /// /// Due to a temporary restriction in Rust's type system, these traits are only /// implemented on tuples of arity 12 or less. In the future, this may change. @@ -810,7 +820,7 @@ mod prim_tuple {} /// /// For more information on floating point numbers, see [Wikipedia][wikipedia]. /// -/// *[See also the `std::f32::consts` module](f32/consts/index.html).* +/// *[See also the `std::f32::consts` module][`crate::f32::consts`].* /// /// [wikipedia]: https://en.wikipedia.org/wiki/Single-precision_floating-point_format #[stable(feature = "rust1", since = "1.0.0")] @@ -819,13 +829,14 @@ mod prim_f32 {} #[doc(primitive = "f64")] /// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008). /// -/// This type is very similar to [`f32`](primitive.f32.html), but has increased +/// This type is very similar to [`f32`], but has increased /// precision by using twice as many bits. Please see [the documentation for -/// `f32`](primitive.f32.html) or [Wikipedia on double precision +/// `f32`][`f32`] or [Wikipedia on double precision /// values][wikipedia] for more information. /// -/// *[See also the `std::f64::consts` module](f64/consts/index.html).* +/// *[See also the `std::f64::consts` module][`crate::f64::consts`].* /// +/// [`f32`]: prim@f32 /// [wikipedia]: https://en.wikipedia.org/wiki/Double-precision_floating-point_format #[stable(feature = "rust1", since = "1.0.0")] mod prim_f64 {} @@ -945,9 +956,6 @@ mod prim_usize {} /// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while /// [`PartialEq`] compares values. /// -/// [`ptr::eq`]: ptr/fn.eq.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// /// ``` /// use std::ptr; /// @@ -979,11 +987,9 @@ mod prim_usize {} /// * [`Borrow`] /// * [`Pointer`] /// -/// [`Copy`]: marker/trait.Copy.html -/// [`Clone`]: clone/trait.Clone.html -/// [`Deref`]: ops/trait.Deref.html -/// [`Borrow`]: borrow/trait.Borrow.html -/// [`Pointer`]: fmt/trait.Pointer.html +/// [`Deref`]: ops::Deref +/// [`Borrow`]: borrow::Borrow +/// [`Pointer`]: fmt::Pointer /// /// `&mut T` references get all of the above except `Copy` and `Clone` (to prevent creating /// multiple simultaneous mutable borrows), plus the following, regardless of the type of its @@ -992,8 +998,8 @@ mod prim_usize {} /// * [`DerefMut`] /// * [`BorrowMut`] /// -/// [`DerefMut`]: ops/trait.DerefMut.html -/// [`BorrowMut`]: borrow/trait.BorrowMut.html +/// [`DerefMut`]: ops::DerefMut +/// [`BorrowMut`]: borrow::BorrowMut /// /// The following traits are implemented on `&T` references if the underlying `T` also implements /// that trait: @@ -1008,18 +1014,10 @@ mod prim_usize {} /// * [`Hash`] /// * [`ToSocketAddrs`] /// -/// [`std::fmt`]: fmt/index.html -/// [`fmt::Write`]: fmt/trait.Write.html -/// [`PartialOrd`]: cmp/trait.PartialOrd.html -/// [`Ord`]: cmp/trait.Ord.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`Eq`]: cmp/trait.Eq.html -/// [`AsRef`]: convert/trait.AsRef.html -/// [`Fn`]: ops/trait.Fn.html -/// [`FnMut`]: ops/trait.FnMut.html -/// [`FnOnce`]: ops/trait.FnOnce.html -/// [`Hash`]: hash/trait.Hash.html -/// [`ToSocketAddrs`]: net/trait.ToSocketAddrs.html +/// [`std::fmt`]: fmt +/// ['Pointer`]: fmt::Pointer +/// [`Hash`]: hash::Hash +/// [`ToSocketAddrs`]: net::ToSocketAddrs /// /// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T` /// implements that trait: @@ -1038,17 +1036,11 @@ mod prim_usize {} /// * [`Seek`] /// * [`BufRead`] /// -/// [`AsMut`]: convert/trait.AsMut.html -/// [`Iterator`]: iter/trait.Iterator.html -/// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html -/// [`ExactSizeIterator`]: iter/trait.ExactSizeIterator.html -/// [`FusedIterator`]: iter/trait.FusedIterator.html -/// [`TrustedLen`]: iter/trait.TrustedLen.html -/// [`Send`]: marker/trait.Send.html -/// [`io::Write`]: io/trait.Write.html -/// [`Read`]: io/trait.Read.html -/// [`Seek`]: io/trait.Seek.html -/// [`BufRead`]: io/trait.BufRead.html +/// [`FusedIterator`]: iter::FusedIterator +/// [`TrustedLen`]: iter::TrustedLen +/// [`Seek`]: io::Seek +/// [`BufRead`]: io::BufRead +/// [`Read`]: io::Read /// /// Note that due to method call deref coercion, simply calling a trait method will act like they /// work on references as well as they do on owned values! The implementations described here are @@ -1063,9 +1055,9 @@ mod prim_ref {} /// /// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].* /// -/// [`Fn`]: ops/trait.Fn.html -/// [`FnMut`]: ops/trait.FnMut.html -/// [`FnOnce`]: ops/trait.FnOnce.html +/// [`Fn`]: ops::Fn +/// [`FnMut`]: ops::FnMut +/// [`FnOnce`]: ops::FnOnce /// /// Function pointers are pointers that point to *code*, not data. They can be called /// just like functions. Like references, function pointers are, among other things, assumed to @@ -1177,14 +1169,8 @@ mod prim_ref {} /// * [`Pointer`] /// * [`Debug`] /// -/// [`Clone`]: clone/trait.Clone.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`Eq`]: cmp/trait.Eq.html -/// [`PartialOrd`]: cmp/trait.PartialOrd.html -/// [`Ord`]: cmp/trait.Ord.html -/// [`Hash`]: hash/trait.Hash.html -/// [`Pointer`]: fmt/trait.Pointer.html -/// [`Debug`]: fmt/trait.Debug.html +/// [`Hash`]: hash::Hash +/// [`Pointer`]: fmt::Pointer /// /// Due to a temporary restriction in Rust's type system, these traits are only implemented on /// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this @@ -1193,7 +1179,5 @@ mod prim_ref {} /// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe* /// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits /// are specially known to the compiler. -/// -/// [`Copy`]: marker/trait.Copy.html #[stable(feature = "rust1", since = "1.0.0")] mod prim_fn {} diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c42bc10965..3d238b7f76 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -95,6 +95,10 @@ //! [`Read`]: io::Read #![stable(feature = "process", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] +mod tests; use crate::io::prelude::*; @@ -106,6 +110,8 @@ use crate::path::Path; use crate::str; use crate::sys::pipe::{read2, AnonPipe}; use crate::sys::process as imp; +#[unstable(feature = "command_access", issue = "44434")] +pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// Representation of a running or exited child process. @@ -245,6 +251,25 @@ pub struct ChildStdin { #[stable(feature = "process", since = "1.0.0")] impl Write for ChildStdin { + fn write(&mut self, buf: &[u8]) -> io::Result { + (&*self).write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (&*self).write_vectored(bufs) + } + + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } +} + +#[stable(feature = "write_mt", since = "1.48.0")] +impl Write for &ChildStdin { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } @@ -318,7 +343,8 @@ impl Read for ChildStdout { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } @@ -378,7 +404,8 @@ impl Read for ChildStderr { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } @@ -869,6 +896,98 @@ impl Command { .map(Child::from_inner) .and_then(|mut p| p.wait()) } + + /// Returns the path to the program that was given to [`Command::new`]. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::process::Command; + /// + /// let cmd = Command::new("echo"); + /// assert_eq!(cmd.get_program(), "echo"); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_program(&self) -> &OsStr { + self.inner.get_program() + } + + /// Returns an iterator of the arguments that will be passed to the program. + /// + /// This does not include the path to the program as the first argument; + /// it only includes the arguments specified with [`Command::arg`] and + /// [`Command::args`]. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::ffi::OsStr; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("echo"); + /// cmd.arg("first").arg("second"); + /// let args: Vec<&OsStr> = cmd.get_args().collect(); + /// assert_eq!(args, &["first", "second"]); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_args(&self) -> CommandArgs<'_> { + CommandArgs { inner: self.inner.get_args() } + } + + /// Returns an iterator of the environment variables that will be set when + /// the process is spawned. + /// + /// Each element is a tuple `(&OsStr, Option<&OsStr>)`, where the first + /// value is the key, and the second is the value, which is [`None`] if + /// the environment variable is to be explicitly removed. + /// + /// This only includes environment variables explicitly set with + /// [`Command::env`], [`Command::envs`], and [`Command::env_remove`]. It + /// does not include environment variables that will be inherited by the + /// child process. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::ffi::OsStr; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("ls"); + /// cmd.env("TERM", "dumb").env_remove("TZ"); + /// let envs: Vec<(&OsStr, Option<&OsStr>)> = cmd.get_envs().collect(); + /// assert_eq!(envs, &[ + /// (OsStr::new("TERM"), Some(OsStr::new("dumb"))), + /// (OsStr::new("TZ"), None) + /// ]); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.inner.get_envs() + } + + /// Returns the working directory for the child process. + /// + /// This returns [`None`] if the working directory will not be changed. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::path::Path; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("ls"); + /// assert_eq!(cmd.get_current_dir(), None); + /// cmd.current_dir("/bin"); + /// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin"))); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_current_dir(&self) -> Option<&Path> { + self.inner.get_current_dir() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -893,6 +1012,37 @@ impl AsInnerMut for Command { } } +/// An iterator over the command arguments. +/// +/// This struct is created by [`Command::get_args`]. See its documentation for +/// more. +#[unstable(feature = "command_access", issue = "44434")] +#[derive(Debug)] +pub struct CommandArgs<'a> { + inner: imp::CommandArgs<'a>, +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.inner.next() + } + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.inner.len() + } + fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + /// The output of a finished process. /// /// This is returned in a Result by either the [`output`] method of a @@ -1702,411 +1852,3 @@ impl Termination for ExitCode { self.0.as_i32() } } - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] -mod tests { - use crate::io::prelude::*; - - use super::{Command, Output, Stdio}; - use crate::io::ErrorKind; - use crate::str; - - // FIXME(#10380) these tests should not all be ignored on android. - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn smoke() { - let p = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 0"]).spawn() - } else { - Command::new("true").spawn() - }; - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn smoke_failure() { - match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn exit_reported_right() { - let p = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).spawn() - } else { - Command::new("false").spawn() - }; - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().code() == Some(1)); - drop(p.wait()); - } - - #[test] - #[cfg(unix)] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn signal_reported_right() { - use crate::os::unix::process::ExitStatusExt; - - let mut p = - Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap(); - p.kill().unwrap(); - match p.wait().unwrap().signal() { - Some(9) => {} - result => panic!("not terminated by signal 9 (instead, {:?})", result), - } - } - - pub fn run_output(mut cmd: Command) -> String { - let p = cmd.spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.stdout.is_some()); - let mut ret = String::new(); - p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap(); - assert!(p.wait().unwrap().success()); - return ret; - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn stdout_works() { - if cfg!(target_os = "windows") { - let mut cmd = Command::new("cmd"); - cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "foobar\r\n"); - } else { - let mut cmd = Command::new("echo"); - cmd.arg("foobar").stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "foobar\n"); - } - } - - #[test] - #[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)] - fn set_current_dir_works() { - let mut cmd = Command::new("/bin/sh"); - cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "/\n"); - } - - #[test] - #[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)] - fn stdin_works() { - let mut p = Command::new("/bin/sh") - .arg("-c") - .arg("read line; echo $line") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .unwrap(); - p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap(); - drop(p.stdin.take()); - let mut out = String::new(); - p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap(); - assert!(p.wait().unwrap().success()); - assert_eq!(out, "foobar\n"); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_process_status() { - let mut status = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap() - } else { - Command::new("false").status().unwrap() - }; - assert!(status.code() == Some(1)); - - status = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap() - } else { - Command::new("true").status().unwrap() - }; - assert!(status.success()); - } - - #[test] - fn test_process_output_fail_to_start() { - match Command::new("/no-binary-by-this-name-should-exist").output() { - Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound), - Ok(..) => panic!(), - } - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_process_output_output() { - let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap() - } else { - Command::new("echo").arg("hello").output().unwrap() - }; - let output_str = str::from_utf8(&stdout).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - assert_eq!(stderr, Vec::new()); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_process_output_error() { - let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap() - } else { - Command::new("mkdir").arg("./").output().unwrap() - }; - - assert!(status.code() == Some(1)); - assert_eq!(stdout, Vec::new()); - assert!(!stderr.is_empty()); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_finish_once() { - let mut prog = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() - } else { - Command::new("false").spawn().unwrap() - }; - assert!(prog.wait().unwrap().code() == Some(1)); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_finish_twice() { - let mut prog = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() - } else { - Command::new("false").spawn().unwrap() - }; - assert!(prog.wait().unwrap().code() == Some(1)); - assert!(prog.wait().unwrap().code() == Some(1)); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_wait_with_output_once() { - let prog = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap() - } else { - Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap() - }; - - let Output { status, stdout, stderr } = prog.wait_with_output().unwrap(); - let output_str = str::from_utf8(&stdout).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - assert_eq!(stderr, Vec::new()); - } - - #[cfg(all(unix, not(target_os = "android")))] - pub fn env_cmd() -> Command { - Command::new("env") - } - #[cfg(target_os = "android")] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("/system/bin/sh"); - cmd.arg("-c").arg("set"); - cmd - } - - #[cfg(windows)] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("cmd"); - cmd.arg("/c").arg("set"); - cmd - } - - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_override_env() { - use crate::env; - - // In some build environments (such as chrooted Nix builds), `env` can - // only be found in the explicitly-provided PATH env variable, not in - // default places such as /bin or /usr/bin. So we need to pass through - // PATH to our sub-process. - let mut cmd = env_cmd(); - cmd.env_clear().env("RUN_TEST_NEW_ENV", "123"); - if let Some(p) = env::var_os("PATH") { - cmd.env("PATH", &p); - } - let result = cmd.output().unwrap(); - let output = String::from_utf8_lossy(&result.stdout).to_string(); - - assert!( - output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", - output - ); - } - - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_add_to_env() { - let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap(); - let output = String::from_utf8_lossy(&result.stdout).to_string(); - - assert!( - output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", - output - ); - } - - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_capture_env_at_spawn() { - use crate::env; - - let mut cmd = env_cmd(); - cmd.env("RUN_TEST_NEW_ENV1", "123"); - - // This variable will not be present if the environment has already - // been captured above. - env::set_var("RUN_TEST_NEW_ENV2", "456"); - let result = cmd.output().unwrap(); - env::remove_var("RUN_TEST_NEW_ENV2"); - - let output = String::from_utf8_lossy(&result.stdout).to_string(); - - assert!( - output.contains("RUN_TEST_NEW_ENV1=123"), - "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}", - output - ); - assert!( - output.contains("RUN_TEST_NEW_ENV2=456"), - "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}", - output - ); - } - - // Regression tests for #30858. - #[test] - fn test_interior_nul_in_progname_is_error() { - match Command::new("has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_arg_is_error() { - match Command::new("echo").arg("has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_args_is_error() { - match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_current_dir_is_error() { - match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - // Regression tests for #30862. - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_interior_nul_in_env_key_is_error() { - match env_cmd().env("has-some-\0\0s-inside", "value").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_interior_nul_in_env_value_is_error() { - match env_cmd().env("key", "has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - /// Tests that process creation flags work by debugging a process. - /// Other creation flags make it hard or impossible to detect - /// behavioral changes in the process. - #[test] - #[cfg(windows)] - fn test_creation_flags() { - use crate::os::windows::process::CommandExt; - use crate::sys::c::{BOOL, DWORD, INFINITE}; - #[repr(C, packed)] - struct DEBUG_EVENT { - pub event_code: DWORD, - pub process_id: DWORD, - pub thread_id: DWORD, - // This is a union in the real struct, but we don't - // need this data for the purposes of this test. - pub _junk: [u8; 164], - } - - extern "system" { - fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; - fn ContinueDebugEvent( - dwProcessId: DWORD, - dwThreadId: DWORD, - dwContinueStatus: DWORD, - ) -> BOOL; - } - - const DEBUG_PROCESS: DWORD = 1; - const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; - const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; - - let mut child = Command::new("cmd") - .creation_flags(DEBUG_PROCESS) - .stdin(Stdio::piped()) - .spawn() - .unwrap(); - child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); - let mut events = 0; - let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] }; - loop { - if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { - panic!("WaitForDebugEvent failed!"); - } - events += 1; - - if event.event_code == EXIT_PROCESS_DEBUG_EVENT { - break; - } - - if unsafe { - ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED) - } == 0 - { - panic!("ContinueDebugEvent failed!"); - } - } - assert!(events > 0); - } - - #[test] - fn test_command_implements_send_sync() { - fn take_send_sync_type(_: T) {} - take_send_sync_type(Command::new("")) - } -} diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs new file mode 100644 index 0000000000..05e093434b --- /dev/null +++ b/library/std/src/process/tests.rs @@ -0,0 +1,401 @@ +use crate::io::prelude::*; + +use super::{Command, Output, Stdio}; +use crate::io::ErrorKind; +use crate::str; + +// FIXME(#10380) these tests should not all be ignored on android. + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn smoke() { + let p = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 0"]).spawn() + } else { + Command::new("true").spawn() + }; + assert!(p.is_ok()); + let mut p = p.unwrap(); + assert!(p.wait().unwrap().success()); +} + +#[test] +#[cfg_attr(target_os = "android", ignore)] +fn smoke_failure() { + match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() { + Ok(..) => panic!(), + Err(..) => {} + } +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn exit_reported_right() { + let p = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).spawn() + } else { + Command::new("false").spawn() + }; + assert!(p.is_ok()); + let mut p = p.unwrap(); + assert!(p.wait().unwrap().code() == Some(1)); + drop(p.wait()); +} + +#[test] +#[cfg(unix)] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn signal_reported_right() { + use crate::os::unix::process::ExitStatusExt; + + let mut p = + Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap(); + p.kill().unwrap(); + match p.wait().unwrap().signal() { + Some(9) => {} + result => panic!("not terminated by signal 9 (instead, {:?})", result), + } +} + +pub fn run_output(mut cmd: Command) -> String { + let p = cmd.spawn(); + assert!(p.is_ok()); + let mut p = p.unwrap(); + assert!(p.stdout.is_some()); + let mut ret = String::new(); + p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap(); + assert!(p.wait().unwrap().success()); + return ret; +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn stdout_works() { + if cfg!(target_os = "windows") { + let mut cmd = Command::new("cmd"); + cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped()); + assert_eq!(run_output(cmd), "foobar\r\n"); + } else { + let mut cmd = Command::new("echo"); + cmd.arg("foobar").stdout(Stdio::piped()); + assert_eq!(run_output(cmd), "foobar\n"); + } +} + +#[test] +#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)] +fn set_current_dir_works() { + let mut cmd = Command::new("/bin/sh"); + cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped()); + assert_eq!(run_output(cmd), "/\n"); +} + +#[test] +#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)] +fn stdin_works() { + let mut p = Command::new("/bin/sh") + .arg("-c") + .arg("read line; echo $line") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap(); + drop(p.stdin.take()); + let mut out = String::new(); + p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap(); + assert!(p.wait().unwrap().success()); + assert_eq!(out, "foobar\n"); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_process_status() { + let mut status = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap() + } else { + Command::new("false").status().unwrap() + }; + assert!(status.code() == Some(1)); + + status = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap() + } else { + Command::new("true").status().unwrap() + }; + assert!(status.success()); +} + +#[test] +fn test_process_output_fail_to_start() { + match Command::new("/no-binary-by-this-name-should-exist").output() { + Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound), + Ok(..) => panic!(), + } +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_process_output_output() { + let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap() + } else { + Command::new("echo").arg("hello").output().unwrap() + }; + let output_str = str::from_utf8(&stdout).unwrap(); + + assert!(status.success()); + assert_eq!(output_str.trim().to_string(), "hello"); + assert_eq!(stderr, Vec::new()); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_process_output_error() { + let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap() + } else { + Command::new("mkdir").arg("./").output().unwrap() + }; + + assert!(status.code() == Some(1)); + assert_eq!(stdout, Vec::new()); + assert!(!stderr.is_empty()); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_finish_once() { + let mut prog = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() + } else { + Command::new("false").spawn().unwrap() + }; + assert!(prog.wait().unwrap().code() == Some(1)); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_finish_twice() { + let mut prog = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() + } else { + Command::new("false").spawn().unwrap() + }; + assert!(prog.wait().unwrap().code() == Some(1)); + assert!(prog.wait().unwrap().code() == Some(1)); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_wait_with_output_once() { + let prog = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap() + } else { + Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap() + }; + + let Output { status, stdout, stderr } = prog.wait_with_output().unwrap(); + let output_str = str::from_utf8(&stdout).unwrap(); + + assert!(status.success()); + assert_eq!(output_str.trim().to_string(), "hello"); + assert_eq!(stderr, Vec::new()); +} + +#[cfg(all(unix, not(target_os = "android")))] +pub fn env_cmd() -> Command { + Command::new("env") +} +#[cfg(target_os = "android")] +pub fn env_cmd() -> Command { + let mut cmd = Command::new("/system/bin/sh"); + cmd.arg("-c").arg("set"); + cmd +} + +#[cfg(windows)] +pub fn env_cmd() -> Command { + let mut cmd = Command::new("cmd"); + cmd.arg("/c").arg("set"); + cmd +} + +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_override_env() { + use crate::env; + + // In some build environments (such as chrooted Nix builds), `env` can + // only be found in the explicitly-provided PATH env variable, not in + // default places such as /bin or /usr/bin. So we need to pass through + // PATH to our sub-process. + let mut cmd = env_cmd(); + cmd.env_clear().env("RUN_TEST_NEW_ENV", "123"); + if let Some(p) = env::var_os("PATH") { + cmd.env("PATH", &p); + } + let result = cmd.output().unwrap(); + let output = String::from_utf8_lossy(&result.stdout).to_string(); + + assert!( + output.contains("RUN_TEST_NEW_ENV=123"), + "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", + output + ); +} + +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_add_to_env() { + let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap(); + let output = String::from_utf8_lossy(&result.stdout).to_string(); + + assert!( + output.contains("RUN_TEST_NEW_ENV=123"), + "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", + output + ); +} + +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_capture_env_at_spawn() { + use crate::env; + + let mut cmd = env_cmd(); + cmd.env("RUN_TEST_NEW_ENV1", "123"); + + // This variable will not be present if the environment has already + // been captured above. + env::set_var("RUN_TEST_NEW_ENV2", "456"); + let result = cmd.output().unwrap(); + env::remove_var("RUN_TEST_NEW_ENV2"); + + let output = String::from_utf8_lossy(&result.stdout).to_string(); + + assert!( + output.contains("RUN_TEST_NEW_ENV1=123"), + "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}", + output + ); + assert!( + output.contains("RUN_TEST_NEW_ENV2=456"), + "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}", + output + ); +} + +// Regression tests for #30858. +#[test] +fn test_interior_nul_in_progname_is_error() { + match Command::new("has-some-\0\0s-inside").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +#[test] +fn test_interior_nul_in_arg_is_error() { + match Command::new("echo").arg("has-some-\0\0s-inside").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +#[test] +fn test_interior_nul_in_args_is_error() { + match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +#[test] +fn test_interior_nul_in_current_dir_is_error() { + match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +// Regression tests for #30862. +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_interior_nul_in_env_key_is_error() { + match env_cmd().env("has-some-\0\0s-inside", "value").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_interior_nul_in_env_value_is_error() { + match env_cmd().env("key", "has-some-\0\0s-inside").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +/// Tests that process creation flags work by debugging a process. +/// Other creation flags make it hard or impossible to detect +/// behavioral changes in the process. +#[test] +#[cfg(windows)] +fn test_creation_flags() { + use crate::os::windows::process::CommandExt; + use crate::sys::c::{BOOL, DWORD, INFINITE}; + #[repr(C, packed)] + struct DEBUG_EVENT { + pub event_code: DWORD, + pub process_id: DWORD, + pub thread_id: DWORD, + // This is a union in the real struct, but we don't + // need this data for the purposes of this test. + pub _junk: [u8; 164], + } + + extern "system" { + fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; + fn ContinueDebugEvent( + dwProcessId: DWORD, + dwThreadId: DWORD, + dwContinueStatus: DWORD, + ) -> BOOL; + } + + const DEBUG_PROCESS: DWORD = 1; + const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; + const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; + + let mut child = + Command::new("cmd").creation_flags(DEBUG_PROCESS).stdin(Stdio::piped()).spawn().unwrap(); + child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); + let mut events = 0; + let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] }; + loop { + if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { + panic!("WaitForDebugEvent failed!"); + } + events += 1; + + if event.event_code == EXIT_PROCESS_DEBUG_EVENT { + break; + } + + if unsafe { + ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED) + } == 0 + { + panic!("ContinueDebugEvent failed!"); + } + } + assert!(events > 0); +} + +#[test] +fn test_command_implements_send_sync() { + fn take_send_sync_type(_: T) {} + take_send_sync_type(Command::new("")) +} diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 23c989fd2f..eab26b6c71 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::fmt; use crate::sync::{Condvar, Mutex}; @@ -13,7 +16,7 @@ use crate::sync::{Condvar, Mutex}; /// let mut handles = Vec::with_capacity(10); /// let barrier = Arc::new(Barrier::new(10)); /// for _ in 0..10 { -/// let c = barrier.clone(); +/// let c = Arc::clone(&barrier); /// // The same messages will be printed together. /// // You will NOT see any interleaving. /// handles.push(thread::spawn(move|| { @@ -40,11 +43,8 @@ struct BarrierState { generation_id: usize, } -/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`] -/// have rendezvoused. -/// -/// [`wait`]: struct.Barrier.html#method.wait -/// [`Barrier`]: struct.Barrier.html +/// A `BarrierWaitResult` is returned by [`Barrier::wait()`] when all threads +/// in the [`Barrier`] have rendezvoused. /// /// # Examples /// @@ -67,10 +67,10 @@ impl fmt::Debug for Barrier { impl Barrier { /// Creates a new barrier that can block a given number of threads. /// - /// A barrier will block `n`-1 threads which call [`wait`] and then wake up - /// all threads at once when the `n`th thread calls [`wait`]. + /// A barrier will block `n`-1 threads which call [`wait()`] and then wake + /// up all threads at once when the `n`th thread calls [`wait()`]. /// - /// [`wait`]: #method.wait + /// [`wait()`]: Barrier::wait /// /// # Examples /// @@ -94,12 +94,9 @@ impl Barrier { /// be used continuously. /// /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that - /// returns `true` from [`is_leader`] when returning from this function, and - /// all other threads will receive a result that will return `false` from - /// [`is_leader`]. - /// - /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html - /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader + /// returns `true` from [`BarrierWaitResult::is_leader()`] when returning + /// from this function, and all other threads will receive a result that + /// will return `false` from [`BarrierWaitResult::is_leader()`]. /// /// # Examples /// @@ -110,7 +107,7 @@ impl Barrier { /// let mut handles = Vec::with_capacity(10); /// let barrier = Arc::new(Barrier::new(10)); /// for _ in 0..10 { - /// let c = barrier.clone(); + /// let c = Arc::clone(&barrier); /// // The same messages will be printed together. /// // You will NOT see any interleaving. /// handles.push(thread::spawn(move|| { @@ -153,13 +150,12 @@ impl fmt::Debug for BarrierWaitResult { } impl BarrierWaitResult { - /// Returns `true` if this thread from [`wait`] is the "leader thread". + /// Returns `true` if this thread is the "leader thread" for the call to + /// [`Barrier::wait()`]. /// /// Only one thread will have `true` returned from their result, all other /// threads will have `false` returned. /// - /// [`wait`]: struct.Barrier.html#method.wait - /// /// # Examples /// /// ``` @@ -174,42 +170,3 @@ impl BarrierWaitResult { self.0 } } - -#[cfg(test)] -mod tests { - use crate::sync::mpsc::{channel, TryRecvError}; - use crate::sync::{Arc, Barrier}; - use crate::thread; - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_barrier() { - const N: usize = 10; - - let barrier = Arc::new(Barrier::new(N)); - let (tx, rx) = channel(); - - for _ in 0..N - 1 { - let c = barrier.clone(); - let tx = tx.clone(); - thread::spawn(move || { - tx.send(c.wait().is_leader()).unwrap(); - }); - } - - // At this point, all spawned threads should be blocked, - // so we shouldn't get anything from the port - assert!(matches!(rx.try_recv(), Err(TryRecvError::Empty))); - - let mut leader_found = barrier.wait().is_leader(); - - // Now, the barrier is cleared and we should get data. - for _ in 0..N - 1 { - if rx.recv().unwrap() { - assert!(!leader_found); - leader_found = true; - } - } - assert!(leader_found); - } -} diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/src/sync/barrier/tests.rs new file mode 100644 index 0000000000..834a3e7515 --- /dev/null +++ b/library/std/src/sync/barrier/tests.rs @@ -0,0 +1,35 @@ +use crate::sync::mpsc::{channel, TryRecvError}; +use crate::sync::{Arc, Barrier}; +use crate::thread; + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_barrier() { + const N: usize = 10; + + let barrier = Arc::new(Barrier::new(N)); + let (tx, rx) = channel(); + + for _ in 0..N - 1 { + let c = barrier.clone(); + let tx = tx.clone(); + thread::spawn(move || { + tx.send(c.wait().is_leader()).unwrap(); + }); + } + + // At this point, all spawned threads should be blocked, + // so we shouldn't get anything from the port + assert!(matches!(rx.try_recv(), Err(TryRecvError::Empty))); + + let mut leader_found = barrier.wait().is_leader(); + + // Now, the barrier is cleared and we should get data. + for _ in 0..N - 1 { + if rx.recv().unwrap() { + assert!(!leader_found); + leader_found = true; + } + } + assert!(leader_found); +} diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 4efd86aa3e..1376d8ebe8 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::fmt; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::{mutex, MutexGuard, PoisonError}; @@ -33,7 +36,7 @@ impl WaitTimeoutResult { /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; @@ -75,13 +78,9 @@ impl WaitTimeoutResult { /// and a mutex. The predicate is always verified inside of the mutex before /// determining that a thread must block. /// -/// Functions in this module will block the current **thread** of execution and -/// are bindings to system-provided condition variables where possible. Note -/// that this module places one additional restriction over the system condition -/// variables: each condvar can be used with precisely one mutex at runtime. Any -/// attempt to use multiple mutexes on the same condition variable will result -/// in a runtime panic. If this is not desired, then the unsafe primitives in -/// `sys` do not have this restriction but may result in undefined behavior. +/// Functions in this module will block the current **thread** of execution. +/// Note that any attempt to use multiple mutexes on the same condition +/// variable may result in a runtime panic. /// /// # Examples /// @@ -90,7 +89,7 @@ impl WaitTimeoutResult { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); -/// let pair2 = pair.clone(); +/// let pair2 = Arc::clone(&pair); /// /// // Inside of our lock, spawn a new thread, and then wait for it to start. /// thread::spawn(move|| { @@ -156,10 +155,8 @@ impl Condvar { /// /// # Panics /// - /// This function will [`panic!`] if it is used with more than one mutex - /// over time. Each condition variable is dynamically bound to exactly one - /// mutex to ensure defined behavior across platforms. If this functionality - /// is not desired, then unsafe primitives in `sys` are provided. + /// This function may [`panic!`] if it is used with more than one mutex + /// over time. /// /// [`notify_one`]: Self::notify_one /// [`notify_all`]: Self::notify_all @@ -173,7 +170,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -229,7 +226,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(true), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -288,7 +285,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -360,7 +357,7 @@ impl Condvar { /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -429,7 +426,7 @@ impl Condvar { /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(true), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -493,7 +490,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -533,7 +530,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -556,8 +553,8 @@ impl Condvar { unsafe { self.inner.notify_all() } } - fn verify(&self, mutex: &sys_mutex::Mutex) { - let addr = mutex as *const _ as usize; + fn verify(&self, mutex: &sys_mutex::MovableMutex) { + let addr = mutex.raw() as *const _ as usize; match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) { // If we got out 0, then we have successfully bound the mutex to // this cvar. @@ -598,218 +595,3 @@ impl Drop for Condvar { unsafe { self.inner.destroy() } } } - -#[cfg(test)] -mod tests { - use crate::sync::atomic::{AtomicBool, Ordering}; - use crate::sync::mpsc::channel; - use crate::sync::{Arc, Condvar, Mutex}; - use crate::thread; - use crate::time::Duration; - - #[test] - fn smoke() { - let c = Condvar::new(); - c.notify_one(); - c.notify_all(); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn notify_one() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let g = m.lock().unwrap(); - let _t = thread::spawn(move || { - let _g = m2.lock().unwrap(); - c2.notify_one(); - }); - let g = c.wait(g).unwrap(); - drop(g); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn notify_all() { - const N: usize = 10; - - let data = Arc::new((Mutex::new(0), Condvar::new())); - let (tx, rx) = channel(); - for _ in 0..N { - let data = data.clone(); - let tx = tx.clone(); - thread::spawn(move || { - let &(ref lock, ref cond) = &*data; - let mut cnt = lock.lock().unwrap(); - *cnt += 1; - if *cnt == N { - tx.send(()).unwrap(); - } - while *cnt != 0 { - cnt = cond.wait(cnt).unwrap(); - } - tx.send(()).unwrap(); - }); - } - drop(tx); - - let &(ref lock, ref cond) = &*data; - rx.recv().unwrap(); - let mut cnt = lock.lock().unwrap(); - *cnt = 0; - cond.notify_all(); - drop(cnt); - - for _ in 0..N { - rx.recv().unwrap(); - } - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_while() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair2 = pair.clone(); - - // Inside of our lock, spawn a new thread, and then wait for it to start. - thread::spawn(move || { - let &(ref lock, ref cvar) = &*pair2; - let mut started = lock.lock().unwrap(); - *started = true; - // We notify the condvar that the value has changed. - cvar.notify_one(); - }); - - // Wait for the thread to start up. - let &(ref lock, ref cvar) = &*pair; - let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started); - assert!(*guard.unwrap()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_wait() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - loop { - let g = m.lock().unwrap(); - let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap(); - // spurious wakeups mean this isn't necessarily true - // so execute test again, if not timeout - if !no_timeout.timed_out() { - continue; - } - - break; - } - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_while_wait() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - let g = m.lock().unwrap(); - let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap(); - // no spurious wakeups. ensure it timed-out - assert!(wait.timed_out()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_while_instant_satisfy() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - let g = m.lock().unwrap(); - let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap(); - // ensure it didn't time-out even if we were not given any time. - assert!(!wait.timed_out()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_while_wake() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair_copy = pair.clone(); - - let &(ref m, ref c) = &*pair; - let g = m.lock().unwrap(); - let _t = thread::spawn(move || { - let &(ref lock, ref cvar) = &*pair_copy; - let mut started = lock.lock().unwrap(); - thread::sleep(Duration::from_millis(1)); - *started = true; - cvar.notify_one(); - }); - let (g2, wait) = c - .wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified) - .unwrap(); - // ensure it didn't time-out even if we were not given any time. - assert!(!wait.timed_out()); - assert!(*g2); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_wake() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - loop { - let g = m.lock().unwrap(); - - let c2 = c.clone(); - let m2 = m.clone(); - - let notified = Arc::new(AtomicBool::new(false)); - let notified_copy = notified.clone(); - - let t = thread::spawn(move || { - let _g = m2.lock().unwrap(); - thread::sleep(Duration::from_millis(1)); - notified_copy.store(true, Ordering::SeqCst); - c2.notify_one(); - }); - let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap(); - assert!(!timeout_res.timed_out()); - // spurious wakeups mean this isn't necessarily true - // so execute test again, if not notified - if !notified.load(Ordering::SeqCst) { - t.join().unwrap(); - continue; - } - drop(g); - - t.join().unwrap(); - - break; - } - } - - #[test] - #[should_panic] - #[cfg_attr(target_os = "emscripten", ignore)] - fn two_mutexes() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock().unwrap(); - let _t = thread::spawn(move || { - let _g = m2.lock().unwrap(); - c2.notify_one(); - }); - g = c.wait(g).unwrap(); - drop(g); - - let m = Mutex::new(()); - let _ = c.wait(m.lock().unwrap()).unwrap(); - } -} diff --git a/library/std/src/sync/condvar/tests.rs b/library/std/src/sync/condvar/tests.rs new file mode 100644 index 0000000000..86d099ee3a --- /dev/null +++ b/library/std/src/sync/condvar/tests.rs @@ -0,0 +1,211 @@ +use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sync::mpsc::channel; +use crate::sync::{Arc, Condvar, Mutex}; +use crate::thread; +use crate::time::Duration; + +#[test] +fn smoke() { + let c = Condvar::new(); + c.notify_one(); + c.notify_all(); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn notify_one() { + let m = Arc::new(Mutex::new(())); + let m2 = m.clone(); + let c = Arc::new(Condvar::new()); + let c2 = c.clone(); + + let g = m.lock().unwrap(); + let _t = thread::spawn(move || { + let _g = m2.lock().unwrap(); + c2.notify_one(); + }); + let g = c.wait(g).unwrap(); + drop(g); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn notify_all() { + const N: usize = 10; + + let data = Arc::new((Mutex::new(0), Condvar::new())); + let (tx, rx) = channel(); + for _ in 0..N { + let data = data.clone(); + let tx = tx.clone(); + thread::spawn(move || { + let &(ref lock, ref cond) = &*data; + let mut cnt = lock.lock().unwrap(); + *cnt += 1; + if *cnt == N { + tx.send(()).unwrap(); + } + while *cnt != 0 { + cnt = cond.wait(cnt).unwrap(); + } + tx.send(()).unwrap(); + }); + } + drop(tx); + + let &(ref lock, ref cond) = &*data; + rx.recv().unwrap(); + let mut cnt = lock.lock().unwrap(); + *cnt = 0; + cond.notify_all(); + drop(cnt); + + for _ in 0..N { + rx.recv().unwrap(); + } +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_while() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + // Inside of our lock, spawn a new thread, and then wait for it to start. + thread::spawn(move || { + let &(ref lock, ref cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_one(); + }); + + // Wait for the thread to start up. + let &(ref lock, ref cvar) = &*pair; + let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started); + assert!(*guard.unwrap()); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_wait() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + loop { + let g = m.lock().unwrap(); + let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap(); + // spurious wakeups mean this isn't necessarily true + // so execute test again, if not timeout + if !no_timeout.timed_out() { + continue; + } + + break; + } +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_while_wait() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + let g = m.lock().unwrap(); + let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap(); + // no spurious wakeups. ensure it timed-out + assert!(wait.timed_out()); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_while_instant_satisfy() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + let g = m.lock().unwrap(); + let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap(); + // ensure it didn't time-out even if we were not given any time. + assert!(!wait.timed_out()); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_while_wake() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair_copy = pair.clone(); + + let &(ref m, ref c) = &*pair; + let g = m.lock().unwrap(); + let _t = thread::spawn(move || { + let &(ref lock, ref cvar) = &*pair_copy; + let mut started = lock.lock().unwrap(); + thread::sleep(Duration::from_millis(1)); + *started = true; + cvar.notify_one(); + }); + let (g2, wait) = c + .wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified) + .unwrap(); + // ensure it didn't time-out even if we were not given any time. + assert!(!wait.timed_out()); + assert!(*g2); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_wake() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + loop { + let g = m.lock().unwrap(); + + let c2 = c.clone(); + let m2 = m.clone(); + + let notified = Arc::new(AtomicBool::new(false)); + let notified_copy = notified.clone(); + + let t = thread::spawn(move || { + let _g = m2.lock().unwrap(); + thread::sleep(Duration::from_millis(1)); + notified_copy.store(true, Ordering::SeqCst); + c2.notify_one(); + }); + let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap(); + assert!(!timeout_res.timed_out()); + // spurious wakeups mean this isn't necessarily true + // so execute test again, if not notified + if !notified.load(Ordering::SeqCst) { + t.join().unwrap(); + continue; + } + drop(g); + + t.join().unwrap(); + + break; + } +} + +#[test] +#[should_panic] +#[cfg_attr(target_os = "emscripten", ignore)] +fn two_mutexes() { + let m = Arc::new(Mutex::new(())); + let m2 = m.clone(); + let c = Arc::new(Condvar::new()); + let c2 = c.clone(); + + let mut g = m.lock().unwrap(); + let _t = thread::spawn(move || { + let _g = m2.lock().unwrap(); + c2.notify_one(); + }); + g = c.wait(g).unwrap(); + drop(g); + + let m = Mutex::new(()); + let _ = c.wait(m.lock().unwrap()).unwrap(); +} diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index ac83017d9e..dc13c9433f 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -108,6 +108,12 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +#[cfg(all(test, not(target_os = "emscripten")))] +mod sync_tests; + // A description of how Rust's channel implementation works // // Channels are supposed to be the basic building block for all other @@ -1525,6 +1531,11 @@ impl error::Error for TrySendError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From> for TrySendError { + /// Converts a `SendError` into a `TrySendError`. + /// + /// This conversion always returns a `TrySendError::Disconnected` containing the data in the `SendError`. + /// + /// No data is allocated on the heap. fn from(err: SendError) -> TrySendError { match err { SendError(t) => TrySendError::Disconnected(t), @@ -1570,6 +1581,11 @@ impl error::Error for TryRecvError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for TryRecvError { + /// Converts a `RecvError` into a `TryRecvError`. + /// + /// This conversion always returns `TryRecvError::Disconnected`. + /// + /// No data is allocated on the heap. fn from(err: RecvError) -> TryRecvError { match err { RecvError => TryRecvError::Disconnected, @@ -1600,1370 +1616,14 @@ impl error::Error for RecvTimeoutError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for RecvTimeoutError { + /// Converts a `RecvError` into a `RecvTimeoutError`. + /// + /// This conversion always returns `RecvTimeoutError::Disconnected`. + /// + /// No data is allocated on the heap. fn from(err: RecvError) -> RecvTimeoutError { match err { RecvError => RecvTimeoutError::Disconnected, } } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::*; - use crate::env; - use crate::thread; - use crate::time::{Duration, Instant}; - - pub fn stress_factor() -> usize { - match env::var("RUST_TEST_STRESS") { - Ok(val) => val.parse().unwrap(), - Err(..) => 1, - } - } - - #[test] - fn smoke() { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn drop_full() { - let (tx, _rx) = channel::>(); - tx.send(box 1).unwrap(); - } - - #[test] - fn drop_full_shared() { - let (tx, _rx) = channel::>(); - drop(tx.clone()); - drop(tx.clone()); - tx.send(box 1).unwrap(); - } - - #[test] - fn smoke_shared() { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - let tx = tx.clone(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn smoke_threads() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - tx.send(1).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn smoke_port_gone() { - let (tx, rx) = channel::(); - drop(rx); - assert!(tx.send(1).is_err()); - } - - #[test] - fn smoke_shared_port_gone() { - let (tx, rx) = channel::(); - drop(rx); - assert!(tx.send(1).is_err()) - } - - #[test] - fn smoke_shared_port_gone2() { - let (tx, rx) = channel::(); - drop(rx); - let tx2 = tx.clone(); - drop(tx); - assert!(tx2.send(1).is_err()); - } - - #[test] - fn port_gone_concurrent() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() {} - } - - #[test] - fn port_gone_concurrent_shared() { - let (tx, rx) = channel::(); - let tx2 = tx.clone(); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() && tx2.send(1).is_ok() {} - } - - #[test] - fn smoke_chan_gone() { - let (tx, rx) = channel::(); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn smoke_chan_gone_shared() { - let (tx, rx) = channel::<()>(); - let tx2 = tx.clone(); - drop(tx); - drop(tx2); - assert!(rx.recv().is_err()); - } - - #[test] - fn chan_gone_concurrent() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - tx.send(1).unwrap(); - tx.send(1).unwrap(); - }); - while rx.recv().is_ok() {} - } - - #[test] - fn stress() { - let (tx, rx) = channel::(); - let t = thread::spawn(move || { - for _ in 0..10000 { - tx.send(1).unwrap(); - } - }); - for _ in 0..10000 { - assert_eq!(rx.recv().unwrap(), 1); - } - t.join().ok().expect("thread panicked"); - } - - #[test] - fn stress_shared() { - const AMT: u32 = 10000; - const NTHREADS: u32 = 8; - let (tx, rx) = channel::(); - - let t = thread::spawn(move || { - for _ in 0..AMT * NTHREADS { - assert_eq!(rx.recv().unwrap(), 1); - } - match rx.try_recv() { - Ok(..) => panic!(), - _ => {} - } - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..AMT { - tx.send(1).unwrap(); - } - }); - } - drop(tx); - t.join().ok().expect("thread panicked"); - } - - #[test] - fn send_from_outside_runtime() { - let (tx1, rx1) = channel::<()>(); - let (tx2, rx2) = channel::(); - let t1 = thread::spawn(move || { - tx1.send(()).unwrap(); - for _ in 0..40 { - assert_eq!(rx2.recv().unwrap(), 1); - } - }); - rx1.recv().unwrap(); - let t2 = thread::spawn(move || { - for _ in 0..40 { - tx2.send(1).unwrap(); - } - }); - t1.join().ok().expect("thread panicked"); - t2.join().ok().expect("thread panicked"); - } - - #[test] - fn recv_from_outside_runtime() { - let (tx, rx) = channel::(); - let t = thread::spawn(move || { - for _ in 0..40 { - assert_eq!(rx.recv().unwrap(), 1); - } - }); - for _ in 0..40 { - tx.send(1).unwrap(); - } - t.join().ok().expect("thread panicked"); - } - - #[test] - fn no_runtime() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - let t1 = thread::spawn(move || { - assert_eq!(rx1.recv().unwrap(), 1); - tx2.send(2).unwrap(); - }); - let t2 = thread::spawn(move || { - tx1.send(1).unwrap(); - assert_eq!(rx2.recv().unwrap(), 2); - }); - t1.join().ok().expect("thread panicked"); - t2.join().ok().expect("thread panicked"); - } - - #[test] - fn oneshot_single_thread_close_port_first() { - // Simple test of closing without sending - let (_tx, rx) = channel::(); - drop(rx); - } - - #[test] - fn oneshot_single_thread_close_chan_first() { - // Simple test of closing without sending - let (tx, _rx) = channel::(); - drop(tx); - } - - #[test] - fn oneshot_single_thread_send_port_close() { - // Testing that the sender cleans up the payload if receiver is closed - let (tx, rx) = channel::>(); - drop(rx); - assert!(tx.send(box 0).is_err()); - } - - #[test] - fn oneshot_single_thread_recv_chan_close() { - // Receiving on a closed chan will panic - let res = thread::spawn(move || { - let (tx, rx) = channel::(); - drop(tx); - rx.recv().unwrap(); - }) - .join(); - // What is our res? - assert!(res.is_err()); - } - - #[test] - fn oneshot_single_thread_send_then_recv() { - let (tx, rx) = channel::>(); - tx.send(box 10).unwrap(); - assert!(*rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_open() { - let (tx, rx) = channel::(); - assert!(tx.send(10).is_ok()); - assert!(rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_closed() { - let (tx, rx) = channel::(); - drop(rx); - assert!(tx.send(10).is_err()); - } - - #[test] - fn oneshot_single_thread_try_recv_open() { - let (tx, rx) = channel::(); - tx.send(10).unwrap(); - assert!(rx.recv() == Ok(10)); - } - - #[test] - fn oneshot_single_thread_try_recv_closed() { - let (tx, rx) = channel::(); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn oneshot_single_thread_peek_data() { - let (tx, rx) = channel::(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - tx.send(10).unwrap(); - assert_eq!(rx.try_recv(), Ok(10)); - } - - #[test] - fn oneshot_single_thread_peek_close() { - let (tx, rx) = channel::(); - drop(tx); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } - - #[test] - fn oneshot_single_thread_peek_open() { - let (_tx, rx) = channel::(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - } - - #[test] - fn oneshot_multi_task_recv_then_send() { - let (tx, rx) = channel::>(); - let _t = thread::spawn(move || { - assert!(*rx.recv().unwrap() == 10); - }); - - tx.send(box 10).unwrap(); - } - - #[test] - fn oneshot_multi_task_recv_then_close() { - let (tx, rx) = channel::>(); - let _t = thread::spawn(move || { - drop(tx); - }); - let res = thread::spawn(move || { - assert!(*rx.recv().unwrap() == 10); - }) - .join(); - assert!(res.is_err()); - } - - #[test] - fn oneshot_multi_thread_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - drop(rx); - }); - drop(tx); - } - } - - #[test] - fn oneshot_multi_thread_send_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - drop(rx); - }); - let _ = thread::spawn(move || { - tx.send(1).unwrap(); - }) - .join(); - } - } - - #[test] - fn oneshot_multi_thread_recv_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::(); - thread::spawn(move || { - let res = thread::spawn(move || { - rx.recv().unwrap(); - }) - .join(); - assert!(res.is_err()); - }); - let _t = thread::spawn(move || { - thread::spawn(move || { - drop(tx); - }); - }); - } - } - - #[test] - fn oneshot_multi_thread_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::>(); - let _t = thread::spawn(move || { - tx.send(box 10).unwrap(); - }); - assert!(*rx.recv().unwrap() == 10); - } - } - - #[test] - fn stream_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel(); - - send(tx, 0); - recv(rx, 0); - - fn send(tx: Sender>, i: i32) { - if i == 10 { - return; - } - - thread::spawn(move || { - tx.send(box i).unwrap(); - send(tx, i + 1); - }); - } - - fn recv(rx: Receiver>, i: i32) { - if i == 10 { - return; - } - - thread::spawn(move || { - assert!(*rx.recv().unwrap() == i); - recv(rx, i + 1); - }); - } - } - } - - #[test] - fn oneshot_single_thread_recv_timeout() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); - tx.send(()).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); - } - - #[test] - fn stress_recv_timeout_two_threads() { - let (tx, rx) = channel(); - let stress = stress_factor() + 100; - let timeout = Duration::from_millis(100); - - thread::spawn(move || { - for i in 0..stress { - if i % 2 == 0 { - thread::sleep(timeout * 2); - } - tx.send(1usize).unwrap(); - } - }); - - let mut recv_count = 0; - loop { - match rx.recv_timeout(timeout) { - Ok(n) => { - assert_eq!(n, 1usize); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, stress); - } - - #[test] - fn recv_timeout_upgrade() { - let (tx, rx) = channel::<()>(); - let timeout = Duration::from_millis(1); - let _tx_clone = tx.clone(); - - let start = Instant::now(); - assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); - assert!(Instant::now() >= start + timeout); - } - - #[test] - fn stress_recv_timeout_shared() { - let (tx, rx) = channel(); - let stress = stress_factor() + 100; - - for i in 0..stress { - let tx = tx.clone(); - thread::spawn(move || { - thread::sleep(Duration::from_millis(i as u64 * 10)); - tx.send(1usize).unwrap(); - }); - } - - drop(tx); - - let mut recv_count = 0; - loop { - match rx.recv_timeout(Duration::from_millis(10)) { - Ok(n) => { - assert_eq!(n, 1usize); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, stress); - } - - #[test] - fn very_long_recv_timeout_wont_panic() { - let (tx, rx) = channel::<()>(); - let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX))); - thread::sleep(Duration::from_secs(1)); - assert!(tx.send(()).is_ok()); - assert_eq!(join_handle.join().unwrap(), Ok(())); - } - - #[test] - fn recv_a_lot() { - // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = channel(); - for _ in 0..10000 { - tx.send(()).unwrap(); - } - for _ in 0..10000 { - rx.recv().unwrap(); - } - } - - #[test] - fn shared_recv_timeout() { - let (tx, rx) = channel(); - let total = 5; - for _ in 0..total { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(()).unwrap(); - }); - } - - for _ in 0..total { - rx.recv().unwrap(); - } - - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); - tx.send(()).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); - } - - #[test] - fn shared_chan_stress() { - let (tx, rx) = channel(); - let total = stress_factor() + 100; - for _ in 0..total { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(()).unwrap(); - }); - } - - for _ in 0..total { - rx.recv().unwrap(); - } - } - - #[test] - fn test_nested_recv_iter() { - let (tx, rx) = channel::(); - let (total_tx, total_rx) = channel::(); - - let _t = thread::spawn(move || { - let mut acc = 0; - for x in rx.iter() { - acc += x; - } - total_tx.send(acc).unwrap(); - }); - - tx.send(3).unwrap(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - drop(tx); - assert_eq!(total_rx.recv().unwrap(), 6); - } - - #[test] - fn test_recv_iter_break() { - let (tx, rx) = channel::(); - let (count_tx, count_rx) = channel(); - - let _t = thread::spawn(move || { - let mut count = 0; - for x in rx.iter() { - if count >= 3 { - break; - } else { - count += x; - } - } - count_tx.send(count).unwrap(); - }); - - tx.send(2).unwrap(); - tx.send(2).unwrap(); - tx.send(2).unwrap(); - let _ = tx.send(2); - drop(tx); - assert_eq!(count_rx.recv().unwrap(), 4); - } - - #[test] - fn test_recv_try_iter() { - let (request_tx, request_rx) = channel(); - let (response_tx, response_rx) = channel(); - - // Request `x`s until we have `6`. - let t = thread::spawn(move || { - let mut count = 0; - loop { - for x in response_rx.try_iter() { - count += x; - if count == 6 { - return count; - } - } - request_tx.send(()).unwrap(); - } - }); - - for _ in request_rx.iter() { - if response_tx.send(2).is_err() { - break; - } - } - - assert_eq!(t.join().unwrap(), 6); - } - - #[test] - fn test_recv_into_iter_owned() { - let mut iter = { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - - rx.into_iter() - }; - assert_eq!(iter.next().unwrap(), 1); - assert_eq!(iter.next().unwrap(), 2); - assert_eq!(iter.next().is_none(), true); - } - - #[test] - fn test_recv_into_iter_borrowed() { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - drop(tx); - let mut iter = (&rx).into_iter(); - assert_eq!(iter.next().unwrap(), 1); - assert_eq!(iter.next().unwrap(), 2); - assert_eq!(iter.next().is_none(), true); - } - - #[test] - fn try_recv_states() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::<()>(); - let (tx3, rx3) = channel::<()>(); - let _t = thread::spawn(move || { - rx2.recv().unwrap(); - tx1.send(1).unwrap(); - tx3.send(()).unwrap(); - rx2.recv().unwrap(); - drop(tx1); - tx3.send(()).unwrap(); - }); - - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); - } - - // This bug used to end up in a livelock inside of the Receiver destructor - // because the internal state of the Shared packet was corrupted - #[test] - fn destroy_upgraded_shared_port_when_sender_still_active() { - let (tx, rx) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move || { - rx.recv().unwrap(); // wait on a oneshot - drop(rx); // destroy a shared - tx2.send(()).unwrap(); - }); - // make sure the other thread has gone to sleep - for _ in 0..5000 { - thread::yield_now(); - } - - // upgrade to a shared chan and send a message - let t = tx.clone(); - drop(tx); - t.send(()).unwrap(); - - // wait for the child thread to exit before we exit - rx2.recv().unwrap(); - } - - #[test] - fn issue_32114() { - let (tx, _) = channel(); - let _ = tx.send(123); - assert_eq!(tx.send(123), Err(SendError(123))); - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod sync_tests { - use super::*; - use crate::env; - use crate::thread; - use crate::time::Duration; - - pub fn stress_factor() -> usize { - match env::var("RUST_TEST_STRESS") { - Ok(val) => val.parse().unwrap(), - Err(..) => 1, - } - } - - #[test] - fn smoke() { - let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn drop_full() { - let (tx, _rx) = sync_channel::>(1); - tx.send(box 1).unwrap(); - } - - #[test] - fn smoke_shared() { - let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - let tx = tx.clone(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn recv_timeout() { - let (tx, rx) = sync_channel::(1); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); - tx.send(1).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); - } - - #[test] - fn smoke_threads() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - tx.send(1).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn smoke_port_gone() { - let (tx, rx) = sync_channel::(0); - drop(rx); - assert!(tx.send(1).is_err()); - } - - #[test] - fn smoke_shared_port_gone2() { - let (tx, rx) = sync_channel::(0); - drop(rx); - let tx2 = tx.clone(); - drop(tx); - assert!(tx2.send(1).is_err()); - } - - #[test] - fn port_gone_concurrent() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() {} - } - - #[test] - fn port_gone_concurrent_shared() { - let (tx, rx) = sync_channel::(0); - let tx2 = tx.clone(); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() && tx2.send(1).is_ok() {} - } - - #[test] - fn smoke_chan_gone() { - let (tx, rx) = sync_channel::(0); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn smoke_chan_gone_shared() { - let (tx, rx) = sync_channel::<()>(0); - let tx2 = tx.clone(); - drop(tx); - drop(tx2); - assert!(rx.recv().is_err()); - } - - #[test] - fn chan_gone_concurrent() { - let (tx, rx) = sync_channel::(0); - thread::spawn(move || { - tx.send(1).unwrap(); - tx.send(1).unwrap(); - }); - while rx.recv().is_ok() {} - } - - #[test] - fn stress() { - let (tx, rx) = sync_channel::(0); - thread::spawn(move || { - for _ in 0..10000 { - tx.send(1).unwrap(); - } - }); - for _ in 0..10000 { - assert_eq!(rx.recv().unwrap(), 1); - } - } - - #[test] - fn stress_recv_timeout_two_threads() { - let (tx, rx) = sync_channel::(0); - - thread::spawn(move || { - for _ in 0..10000 { - tx.send(1).unwrap(); - } - }); - - let mut recv_count = 0; - loop { - match rx.recv_timeout(Duration::from_millis(1)) { - Ok(v) => { - assert_eq!(v, 1); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, 10000); - } - - #[test] - fn stress_recv_timeout_shared() { - const AMT: u32 = 1000; - const NTHREADS: u32 = 8; - let (tx, rx) = sync_channel::(0); - let (dtx, drx) = sync_channel::<()>(0); - - thread::spawn(move || { - let mut recv_count = 0; - loop { - match rx.recv_timeout(Duration::from_millis(10)) { - Ok(v) => { - assert_eq!(v, 1); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, AMT * NTHREADS); - assert!(rx.try_recv().is_err()); - - dtx.send(()).unwrap(); - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..AMT { - tx.send(1).unwrap(); - } - }); - } - - drop(tx); - - drx.recv().unwrap(); - } - - #[test] - fn stress_shared() { - const AMT: u32 = 1000; - const NTHREADS: u32 = 8; - let (tx, rx) = sync_channel::(0); - let (dtx, drx) = sync_channel::<()>(0); - - thread::spawn(move || { - for _ in 0..AMT * NTHREADS { - assert_eq!(rx.recv().unwrap(), 1); - } - match rx.try_recv() { - Ok(..) => panic!(), - _ => {} - } - dtx.send(()).unwrap(); - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..AMT { - tx.send(1).unwrap(); - } - }); - } - drop(tx); - drx.recv().unwrap(); - } - - #[test] - fn oneshot_single_thread_close_port_first() { - // Simple test of closing without sending - let (_tx, rx) = sync_channel::(0); - drop(rx); - } - - #[test] - fn oneshot_single_thread_close_chan_first() { - // Simple test of closing without sending - let (tx, _rx) = sync_channel::(0); - drop(tx); - } - - #[test] - fn oneshot_single_thread_send_port_close() { - // Testing that the sender cleans up the payload if receiver is closed - let (tx, rx) = sync_channel::>(0); - drop(rx); - assert!(tx.send(box 0).is_err()); - } - - #[test] - fn oneshot_single_thread_recv_chan_close() { - // Receiving on a closed chan will panic - let res = thread::spawn(move || { - let (tx, rx) = sync_channel::(0); - drop(tx); - rx.recv().unwrap(); - }) - .join(); - // What is our res? - assert!(res.is_err()); - } - - #[test] - fn oneshot_single_thread_send_then_recv() { - let (tx, rx) = sync_channel::>(1); - tx.send(box 10).unwrap(); - assert!(*rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_open() { - let (tx, rx) = sync_channel::(1); - assert_eq!(tx.try_send(10), Ok(())); - assert!(rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_closed() { - let (tx, rx) = sync_channel::(0); - drop(rx); - assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); - } - - #[test] - fn oneshot_single_thread_try_send_closed2() { - let (tx, _rx) = sync_channel::(0); - assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); - } - - #[test] - fn oneshot_single_thread_try_recv_open() { - let (tx, rx) = sync_channel::(1); - tx.send(10).unwrap(); - assert!(rx.recv() == Ok(10)); - } - - #[test] - fn oneshot_single_thread_try_recv_closed() { - let (tx, rx) = sync_channel::(0); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn oneshot_single_thread_try_recv_closed_with_data() { - let (tx, rx) = sync_channel::(1); - tx.send(10).unwrap(); - drop(tx); - assert_eq!(rx.try_recv(), Ok(10)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } - - #[test] - fn oneshot_single_thread_peek_data() { - let (tx, rx) = sync_channel::(1); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - tx.send(10).unwrap(); - assert_eq!(rx.try_recv(), Ok(10)); - } - - #[test] - fn oneshot_single_thread_peek_close() { - let (tx, rx) = sync_channel::(0); - drop(tx); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } - - #[test] - fn oneshot_single_thread_peek_open() { - let (_tx, rx) = sync_channel::(0); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - } - - #[test] - fn oneshot_multi_task_recv_then_send() { - let (tx, rx) = sync_channel::>(0); - let _t = thread::spawn(move || { - assert!(*rx.recv().unwrap() == 10); - }); - - tx.send(box 10).unwrap(); - } - - #[test] - fn oneshot_multi_task_recv_then_close() { - let (tx, rx) = sync_channel::>(0); - let _t = thread::spawn(move || { - drop(tx); - }); - let res = thread::spawn(move || { - assert!(*rx.recv().unwrap() == 10); - }) - .join(); - assert!(res.is_err()); - } - - #[test] - fn oneshot_multi_thread_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - drop(rx); - }); - drop(tx); - } - } - - #[test] - fn oneshot_multi_thread_send_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - drop(rx); - }); - let _ = thread::spawn(move || { - tx.send(1).unwrap(); - }) - .join(); - } - } - - #[test] - fn oneshot_multi_thread_recv_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - let res = thread::spawn(move || { - rx.recv().unwrap(); - }) - .join(); - assert!(res.is_err()); - }); - let _t = thread::spawn(move || { - thread::spawn(move || { - drop(tx); - }); - }); - } - } - - #[test] - fn oneshot_multi_thread_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::>(0); - let _t = thread::spawn(move || { - tx.send(box 10).unwrap(); - }); - assert!(*rx.recv().unwrap() == 10); - } - } - - #[test] - fn stream_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::>(0); - - send(tx, 0); - recv(rx, 0); - - fn send(tx: SyncSender>, i: i32) { - if i == 10 { - return; - } - - thread::spawn(move || { - tx.send(box i).unwrap(); - send(tx, i + 1); - }); - } - - fn recv(rx: Receiver>, i: i32) { - if i == 10 { - return; - } - - thread::spawn(move || { - assert!(*rx.recv().unwrap() == i); - recv(rx, i + 1); - }); - } - } - } - - #[test] - fn recv_a_lot() { - // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = sync_channel(10000); - for _ in 0..10000 { - tx.send(()).unwrap(); - } - for _ in 0..10000 { - rx.recv().unwrap(); - } - } - - #[test] - fn shared_chan_stress() { - let (tx, rx) = sync_channel(0); - let total = stress_factor() + 100; - for _ in 0..total { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(()).unwrap(); - }); - } - - for _ in 0..total { - rx.recv().unwrap(); - } - } - - #[test] - fn test_nested_recv_iter() { - let (tx, rx) = sync_channel::(0); - let (total_tx, total_rx) = sync_channel::(0); - - let _t = thread::spawn(move || { - let mut acc = 0; - for x in rx.iter() { - acc += x; - } - total_tx.send(acc).unwrap(); - }); - - tx.send(3).unwrap(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - drop(tx); - assert_eq!(total_rx.recv().unwrap(), 6); - } - - #[test] - fn test_recv_iter_break() { - let (tx, rx) = sync_channel::(0); - let (count_tx, count_rx) = sync_channel(0); - - let _t = thread::spawn(move || { - let mut count = 0; - for x in rx.iter() { - if count >= 3 { - break; - } else { - count += x; - } - } - count_tx.send(count).unwrap(); - }); - - tx.send(2).unwrap(); - tx.send(2).unwrap(); - tx.send(2).unwrap(); - let _ = tx.try_send(2); - drop(tx); - assert_eq!(count_rx.recv().unwrap(), 4); - } - - #[test] - fn try_recv_states() { - let (tx1, rx1) = sync_channel::(1); - let (tx2, rx2) = sync_channel::<()>(1); - let (tx3, rx3) = sync_channel::<()>(1); - let _t = thread::spawn(move || { - rx2.recv().unwrap(); - tx1.send(1).unwrap(); - tx3.send(()).unwrap(); - rx2.recv().unwrap(); - drop(tx1); - tx3.send(()).unwrap(); - }); - - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); - } - - // This bug used to end up in a livelock inside of the Receiver destructor - // because the internal state of the Shared packet was corrupted - #[test] - fn destroy_upgraded_shared_port_when_sender_still_active() { - let (tx, rx) = sync_channel::<()>(0); - let (tx2, rx2) = sync_channel::<()>(0); - let _t = thread::spawn(move || { - rx.recv().unwrap(); // wait on a oneshot - drop(rx); // destroy a shared - tx2.send(()).unwrap(); - }); - // make sure the other thread has gone to sleep - for _ in 0..5000 { - thread::yield_now(); - } - - // upgrade to a shared chan and send a message - let t = tx.clone(); - drop(tx); - t.send(()).unwrap(); - - // wait for the child thread to exit before we exit - rx2.recv().unwrap(); - } - - #[test] - fn send1() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - assert_eq!(tx.send(1), Ok(())); - } - - #[test] - fn send2() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - drop(rx); - }); - assert!(tx.send(1).is_err()); - } - - #[test] - fn send3() { - let (tx, rx) = sync_channel::(1); - assert_eq!(tx.send(1), Ok(())); - let _t = thread::spawn(move || { - drop(rx); - }); - assert!(tx.send(1).is_err()); - } - - #[test] - fn send4() { - let (tx, rx) = sync_channel::(0); - let tx2 = tx.clone(); - let (done, donerx) = channel(); - let done2 = done.clone(); - let _t = thread::spawn(move || { - assert!(tx.send(1).is_err()); - done.send(()).unwrap(); - }); - let _t = thread::spawn(move || { - assert!(tx2.send(2).is_err()); - done2.send(()).unwrap(); - }); - drop(rx); - donerx.recv().unwrap(); - donerx.recv().unwrap(); - } - - #[test] - fn try_send1() { - let (tx, _rx) = sync_channel::(0); - assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); - } - - #[test] - fn try_send2() { - let (tx, _rx) = sync_channel::(1); - assert_eq!(tx.try_send(1), Ok(())); - assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); - } - - #[test] - fn try_send3() { - let (tx, rx) = sync_channel::(1); - assert_eq!(tx.try_send(1), Ok(())); - drop(rx); - assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); - } - - #[test] - fn issue_15761() { - fn repro() { - let (tx1, rx1) = sync_channel::<()>(3); - let (tx2, rx2) = sync_channel::<()>(3); - - let _t = thread::spawn(move || { - rx1.recv().unwrap(); - tx2.try_send(()).unwrap(); - }); - - tx1.try_send(()).unwrap(); - rx2.recv().unwrap(); - } - - for _ in 0..100 { - repro() - } - } -} diff --git a/library/std/src/sync/mpsc/mpsc_queue.rs b/library/std/src/sync/mpsc/mpsc_queue.rs index 6e7a7be443..42bc639dc2 100644 --- a/library/std/src/sync/mpsc/mpsc_queue.rs +++ b/library/std/src/sync/mpsc/mpsc_queue.rs @@ -11,6 +11,9 @@ // http://www.1024cores.net/home/lock-free-algorithms // /queues/non-intrusive-mpsc-node-based-queue +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + pub use self::PopResult::*; use core::cell::UnsafeCell; @@ -112,54 +115,3 @@ impl Drop for Queue { } } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::{Data, Empty, Inconsistent, Queue}; - use crate::sync::mpsc::channel; - use crate::sync::Arc; - use crate::thread; - - #[test] - fn test_full() { - let q: Queue> = Queue::new(); - q.push(box 1); - q.push(box 2); - } - - #[test] - fn test() { - let nthreads = 8; - let nmsgs = 1000; - let q = Queue::new(); - match q.pop() { - Empty => {} - Inconsistent | Data(..) => panic!(), - } - let (tx, rx) = channel(); - let q = Arc::new(q); - - for _ in 0..nthreads { - let tx = tx.clone(); - let q = q.clone(); - thread::spawn(move || { - for i in 0..nmsgs { - q.push(i); - } - tx.send(()).unwrap(); - }); - } - - let mut i = 0; - while i < nthreads * nmsgs { - match q.pop() { - Empty | Inconsistent => {} - Data(_) => i += 1, - } - } - drop(tx); - for _ in 0..nthreads { - rx.recv().unwrap(); - } - } -} diff --git a/library/std/src/sync/mpsc/mpsc_queue/tests.rs b/library/std/src/sync/mpsc/mpsc_queue/tests.rs new file mode 100644 index 0000000000..348b83424b --- /dev/null +++ b/library/std/src/sync/mpsc/mpsc_queue/tests.rs @@ -0,0 +1,47 @@ +use super::{Data, Empty, Inconsistent, Queue}; +use crate::sync::mpsc::channel; +use crate::sync::Arc; +use crate::thread; + +#[test] +fn test_full() { + let q: Queue> = Queue::new(); + q.push(box 1); + q.push(box 2); +} + +#[test] +fn test() { + let nthreads = 8; + let nmsgs = 1000; + let q = Queue::new(); + match q.pop() { + Empty => {} + Inconsistent | Data(..) => panic!(), + } + let (tx, rx) = channel(); + let q = Arc::new(q); + + for _ in 0..nthreads { + let tx = tx.clone(); + let q = q.clone(); + thread::spawn(move || { + for i in 0..nmsgs { + q.push(i); + } + tx.send(()).unwrap(); + }); + } + + let mut i = 0; + while i < nthreads * nmsgs { + match q.pop() { + Empty | Inconsistent => {} + Data(_) => i += 1, + } + } + drop(tx); + for _ in 0..nthreads { + rx.recv().unwrap(); + } +} diff --git a/library/std/src/sync/mpsc/spsc_queue.rs b/library/std/src/sync/mpsc/spsc_queue.rs index 0274268f69..9bf99f193c 100644 --- a/library/std/src/sync/mpsc/spsc_queue.rs +++ b/library/std/src/sync/mpsc/spsc_queue.rs @@ -6,6 +6,9 @@ // http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use core::cell::UnsafeCell; use core::ptr; @@ -231,108 +234,3 @@ impl Drop for Queue { - assert_eq!(&*vec, &[1]); - } - None => unreachable!(), - } - - match queue.pop() { - Some(vec) => { - assert_eq!(&*vec, &[1]); - } - None => unreachable!(), - } - } - } - - #[test] - fn drop_full() { - unsafe { - let q: Queue> = Queue::with_additions(0, (), ()); - q.push(box 1); - q.push(box 2); - } - } - - #[test] - fn smoke_bound() { - unsafe { - let q = Queue::with_additions(0, (), ()); - q.push(1); - q.push(2); - assert_eq!(q.pop(), Some(1)); - assert_eq!(q.pop(), Some(2)); - assert_eq!(q.pop(), None); - q.push(3); - q.push(4); - assert_eq!(q.pop(), Some(3)); - assert_eq!(q.pop(), Some(4)); - assert_eq!(q.pop(), None); - } - } - - #[test] - fn stress() { - unsafe { - stress_bound(0); - stress_bound(1); - } - - unsafe fn stress_bound(bound: usize) { - let q = Arc::new(Queue::with_additions(bound, (), ())); - - let (tx, rx) = channel(); - let q2 = q.clone(); - let _t = thread::spawn(move || { - for _ in 0..100000 { - loop { - match q2.pop() { - Some(1) => break, - Some(_) => panic!(), - None => {} - } - } - } - tx.send(()).unwrap(); - }); - for _ in 0..100000 { - q.push(1); - } - rx.recv().unwrap(); - } - } -} diff --git a/library/std/src/sync/mpsc/spsc_queue/tests.rs b/library/std/src/sync/mpsc/spsc_queue/tests.rs new file mode 100644 index 0000000000..e4fd15cbbd --- /dev/null +++ b/library/std/src/sync/mpsc/spsc_queue/tests.rs @@ -0,0 +1,101 @@ +use super::Queue; +use crate::sync::mpsc::channel; +use crate::sync::Arc; +use crate::thread; + +#[test] +fn smoke() { + unsafe { + let queue = Queue::with_additions(0, (), ()); + queue.push(1); + queue.push(2); + assert_eq!(queue.pop(), Some(1)); + assert_eq!(queue.pop(), Some(2)); + assert_eq!(queue.pop(), None); + queue.push(3); + queue.push(4); + assert_eq!(queue.pop(), Some(3)); + assert_eq!(queue.pop(), Some(4)); + assert_eq!(queue.pop(), None); + } +} + +#[test] +fn peek() { + unsafe { + let queue = Queue::with_additions(0, (), ()); + queue.push(vec![1]); + + // Ensure the borrowchecker works + match queue.peek() { + Some(vec) => { + assert_eq!(&*vec, &[1]); + } + None => unreachable!(), + } + + match queue.pop() { + Some(vec) => { + assert_eq!(&*vec, &[1]); + } + None => unreachable!(), + } + } +} + +#[test] +fn drop_full() { + unsafe { + let q: Queue> = Queue::with_additions(0, (), ()); + q.push(box 1); + q.push(box 2); + } +} + +#[test] +fn smoke_bound() { + unsafe { + let q = Queue::with_additions(0, (), ()); + q.push(1); + q.push(2); + assert_eq!(q.pop(), Some(1)); + assert_eq!(q.pop(), Some(2)); + assert_eq!(q.pop(), None); + q.push(3); + q.push(4); + assert_eq!(q.pop(), Some(3)); + assert_eq!(q.pop(), Some(4)); + assert_eq!(q.pop(), None); + } +} + +#[test] +fn stress() { + unsafe { + stress_bound(0); + stress_bound(1); + } + + unsafe fn stress_bound(bound: usize) { + let q = Arc::new(Queue::with_additions(bound, (), ())); + + let (tx, rx) = channel(); + let q2 = q.clone(); + let _t = thread::spawn(move || { + for _ in 0..100000 { + loop { + match q2.pop() { + Some(1) => break, + Some(_) => panic!(), + None => {} + } + } + } + tx.send(()).unwrap(); + }); + for _ in 0..100000 { + 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 new file mode 100644 index 0000000000..0052a38f7b --- /dev/null +++ b/library/std/src/sync/mpsc/sync_tests.rs @@ -0,0 +1,647 @@ +use super::*; +use crate::env; +use crate::thread; +use crate::time::Duration; + +pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } +} + +#[test] +fn smoke() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn drop_full() { + let (tx, _rx) = sync_channel::>(1); + tx.send(box 1).unwrap(); +} + +#[test] +fn smoke_shared() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn recv_timeout() { + let (tx, rx) = sync_channel::(1); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(1).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); +} + +#[test] +fn smoke_threads() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn smoke_port_gone() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert!(tx.send(1).is_err()); +} + +#[test] +fn smoke_shared_port_gone2() { + let (tx, rx) = sync_channel::(0); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); +} + +#[test] +fn port_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} +} + +#[test] +fn port_gone_concurrent_shared() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} +} + +#[test] +fn smoke_chan_gone() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn smoke_chan_gone_shared() { + let (tx, rx) = sync_channel::<()>(0); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); +} + +#[test] +fn chan_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} +} + +#[test] +fn stress() { + let (tx, rx) = sync_channel::(0); + thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } +} + +#[test] +fn stress_recv_timeout_two_threads() { + let (tx, rx) = sync_channel::(0); + + thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(1)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, 10000); +} + +#[test] +fn stress_recv_timeout_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + thread::spawn(move || { + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, AMT * NTHREADS); + assert!(rx.try_recv().is_err()); + + dtx.send(()).unwrap(); + }); + + for _ in 0..NTHREADS { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + } + + drop(tx); + + drx.recv().unwrap(); +} + +#[test] +fn stress_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + dtx.send(()).unwrap(); + }); + + for _ in 0..NTHREADS { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + } + drop(tx); + drx.recv().unwrap(); +} + +#[test] +fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = sync_channel::(0); + drop(rx); +} + +#[test] +fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = sync_channel::(0); + drop(tx); +} + +#[test] +fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = sync_channel::>(0); + drop(rx); + assert!(tx.send(box 0).is_err()); +} + +#[test] +fn oneshot_single_thread_recv_chan_close() { + // Receiving on a closed chan will panic + let res = thread::spawn(move || { + let (tx, rx) = sync_channel::(0); + drop(tx); + rx.recv().unwrap(); + }) + .join(); + // What is our res? + assert!(res.is_err()); +} + +#[test] +fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = sync_channel::>(1); + tx.send(box 10).unwrap(); + assert!(*rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_open() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(10), Ok(())); + assert!(rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); +} + +#[test] +fn oneshot_single_thread_try_send_closed2() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); +} + +#[test] +fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); +} + +#[test] +fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn oneshot_single_thread_try_recv_closed_with_data() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + drop(tx); + assert_eq!(rx.try_recv(), Ok(10)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn oneshot_single_thread_peek_data() { + let (tx, rx) = sync_channel::(1); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); +} + +#[test] +fn oneshot_single_thread_peek_close() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn oneshot_single_thread_peek_open() { + let (_tx, rx) = sync_channel::(0); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = sync_channel::>(0); + let _t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(box 10).unwrap(); +} + +#[test] +fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = sync_channel::>(0); + let _t = thread::spawn(move || { + drop(tx); + }); + let res = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }) + .join(); + assert!(res.is_err()); +} + +#[test] +fn oneshot_multi_thread_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + drop(rx); + }); + drop(tx); + } +} + +#[test] +fn oneshot_multi_thread_send_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + drop(rx); + }); + let _ = thread::spawn(move || { + tx.send(1).unwrap(); + }) + .join(); + } +} + +#[test] +fn oneshot_multi_thread_recv_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + let res = thread::spawn(move || { + rx.recv().unwrap(); + }) + .join(); + assert!(res.is_err()); + }); + let _t = thread::spawn(move || { + thread::spawn(move || { + drop(tx); + }); + }); + } +} + +#[test] +fn oneshot_multi_thread_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::>(0); + let _t = thread::spawn(move || { + tx.send(box 10).unwrap(); + }); + assert!(*rx.recv().unwrap() == 10); + } +} + +#[test] +fn stream_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::>(0); + + send(tx, 0); + recv(rx, 0); + + fn send(tx: SyncSender>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + tx.send(box i).unwrap(); + send(tx, i + 1); + }); + } + + fn recv(rx: Receiver>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + }); + } + } +} + +#[test] +fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = sync_channel(10000); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } +} + +#[test] +fn shared_chan_stress() { + let (tx, rx) = sync_channel(0); + let total = stress_factor() + 100; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } +} + +#[test] +fn test_nested_recv_iter() { + let (tx, rx) = sync_channel::(0); + let (total_tx, total_rx) = sync_channel::(0); + + let _t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); +} + +#[test] +fn test_recv_iter_break() { + let (tx, rx) = sync_channel::(0); + let (count_tx, count_rx) = sync_channel(0); + + let _t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.try_send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); +} + +#[test] +fn try_recv_states() { + let (tx1, rx1) = sync_channel::(1); + let (tx2, rx2) = sync_channel::<()>(1); + let (tx3, rx3) = sync_channel::<()>(1); + let _t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); +} + +// This bug used to end up in a livelock inside of the Receiver destructor +// because the internal state of the Shared packet was corrupted +#[test] +fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = sync_channel::<()>(0); + let (tx2, rx2) = sync_channel::<()>(0); + let _t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let t = tx.clone(); + drop(tx); + t.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); +} + +#[test] +fn send1() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + assert_eq!(tx.send(1), Ok(())); +} + +#[test] +fn send2() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); +} + +#[test] +fn send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.send(1), Ok(())); + let _t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); +} + +#[test] +fn send4() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let (done, donerx) = channel(); + let done2 = done.clone(); + let _t = thread::spawn(move || { + assert!(tx.send(1).is_err()); + done.send(()).unwrap(); + }); + let _t = thread::spawn(move || { + assert!(tx2.send(2).is_err()); + done2.send(()).unwrap(); + }); + drop(rx); + donerx.recv().unwrap(); + donerx.recv().unwrap(); +} + +#[test] +fn try_send1() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); +} + +#[test] +fn try_send2() { + let (tx, _rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); +} + +#[test] +fn try_send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + drop(rx); + assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); +} + +#[test] +fn issue_15761() { + fn repro() { + let (tx1, rx1) = sync_channel::<()>(3); + let (tx2, rx2) = sync_channel::<()>(3); + + let _t = thread::spawn(move || { + rx1.recv().unwrap(); + tx2.try_send(()).unwrap(); + }); + + tx1.try_send(()).unwrap(); + rx2.recv().unwrap(); + } + + for _ in 0..100 { + repro() + } +} diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/src/sync/mpsc/tests.rs new file mode 100644 index 0000000000..184ce193cb --- /dev/null +++ b/library/std/src/sync/mpsc/tests.rs @@ -0,0 +1,706 @@ +use super::*; +use crate::env; +use crate::thread; +use crate::time::{Duration, Instant}; + +pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } +} + +#[test] +fn smoke() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn drop_full() { + let (tx, _rx) = channel::>(); + tx.send(box 1).unwrap(); +} + +#[test] +fn drop_full_shared() { + let (tx, _rx) = channel::>(); + drop(tx.clone()); + drop(tx.clone()); + tx.send(box 1).unwrap(); +} + +#[test] +fn smoke_shared() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn smoke_threads() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn smoke_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()); +} + +#[test] +fn smoke_shared_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()) +} + +#[test] +fn smoke_shared_port_gone2() { + let (tx, rx) = channel::(); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); +} + +#[test] +fn port_gone_concurrent() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} +} + +#[test] +fn port_gone_concurrent_shared() { + let (tx, rx) = channel::(); + let tx2 = tx.clone(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} +} + +#[test] +fn smoke_chan_gone() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn smoke_chan_gone_shared() { + let (tx, rx) = channel::<()>(); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); +} + +#[test] +fn chan_gone_concurrent() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} +} + +#[test] +fn stress() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().ok().expect("thread panicked"); +} + +#[test] +fn stress_shared() { + const AMT: u32 = 10000; + const NTHREADS: u32 = 8; + let (tx, rx) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + }); + + for _ in 0..NTHREADS { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + } + drop(tx); + t.join().ok().expect("thread panicked"); +} + +#[test] +fn send_from_outside_runtime() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + tx1.send(()).unwrap(); + for _ in 0..40 { + assert_eq!(rx2.recv().unwrap(), 1); + } + }); + rx1.recv().unwrap(); + let t2 = thread::spawn(move || { + for _ in 0..40 { + tx2.send(1).unwrap(); + } + }); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); +} + +#[test] +fn recv_from_outside_runtime() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..40 { + assert_eq!(rx.recv().unwrap(), 1); + } + }); + for _ in 0..40 { + tx.send(1).unwrap(); + } + t.join().ok().expect("thread panicked"); +} + +#[test] +fn no_runtime() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + assert_eq!(rx1.recv().unwrap(), 1); + tx2.send(2).unwrap(); + }); + let t2 = thread::spawn(move || { + tx1.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 2); + }); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); +} + +#[test] +fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = channel::(); + drop(rx); +} + +#[test] +fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = channel::(); + drop(tx); +} + +#[test] +fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = channel::>(); + drop(rx); + assert!(tx.send(box 0).is_err()); +} + +#[test] +fn oneshot_single_thread_recv_chan_close() { + // Receiving on a closed chan will panic + let res = thread::spawn(move || { + let (tx, rx) = channel::(); + drop(tx); + rx.recv().unwrap(); + }) + .join(); + // What is our res? + assert!(res.is_err()); +} + +#[test] +fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = channel::>(); + tx.send(box 10).unwrap(); + assert!(*rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_open() { + let (tx, rx) = channel::(); + assert!(tx.send(10).is_ok()); + assert!(rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(10).is_err()); +} + +#[test] +fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = channel::(); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); +} + +#[test] +fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn oneshot_single_thread_peek_data() { + let (tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); +} + +#[test] +fn oneshot_single_thread_peek_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn oneshot_single_thread_peek_open() { + let (_tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(box 10).unwrap(); +} + +#[test] +fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + drop(tx); + }); + let res = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }) + .join(); + assert!(res.is_err()); +} + +#[test] +fn oneshot_multi_thread_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + drop(rx); + }); + drop(tx); + } +} + +#[test] +fn oneshot_multi_thread_send_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + drop(rx); + }); + let _ = thread::spawn(move || { + tx.send(1).unwrap(); + }) + .join(); + } +} + +#[test] +fn oneshot_multi_thread_recv_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + thread::spawn(move || { + let res = thread::spawn(move || { + rx.recv().unwrap(); + }) + .join(); + assert!(res.is_err()); + }); + let _t = thread::spawn(move || { + thread::spawn(move || { + drop(tx); + }); + }); + } +} + +#[test] +fn oneshot_multi_thread_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + tx.send(box 10).unwrap(); + }); + assert!(*rx.recv().unwrap() == 10); + } +} + +#[test] +fn stream_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel(); + + send(tx, 0); + recv(rx, 0); + + fn send(tx: Sender>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + tx.send(box i).unwrap(); + send(tx, i + 1); + }); + } + + fn recv(rx: Receiver>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + }); + } + } +} + +#[test] +fn oneshot_single_thread_recv_timeout() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); +} + +#[test] +fn stress_recv_timeout_two_threads() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + let timeout = Duration::from_millis(100); + + thread::spawn(move || { + for i in 0..stress { + if i % 2 == 0 { + thread::sleep(timeout * 2); + } + tx.send(1usize).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(timeout) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); +} + +#[test] +fn recv_timeout_upgrade() { + let (tx, rx) = channel::<()>(); + let timeout = Duration::from_millis(1); + let _tx_clone = tx.clone(); + + let start = Instant::now(); + assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); + assert!(Instant::now() >= start + timeout); +} + +#[test] +fn stress_recv_timeout_shared() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + + for i in 0..stress { + let tx = tx.clone(); + thread::spawn(move || { + thread::sleep(Duration::from_millis(i as u64 * 10)); + tx.send(1usize).unwrap(); + }); + } + + drop(tx); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); +} + +#[test] +fn very_long_recv_timeout_wont_panic() { + let (tx, rx) = channel::<()>(); + let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX))); + thread::sleep(Duration::from_secs(1)); + assert!(tx.send(()).is_ok()); + assert_eq!(join_handle.join().unwrap(), Ok(())); +} + +#[test] +fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = channel(); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } +} + +#[test] +fn shared_recv_timeout() { + let (tx, rx) = channel(); + let total = 5; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); +} + +#[test] +fn shared_chan_stress() { + let (tx, rx) = channel(); + let total = stress_factor() + 100; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } +} + +#[test] +fn test_nested_recv_iter() { + let (tx, rx) = channel::(); + let (total_tx, total_rx) = channel::(); + + let _t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); +} + +#[test] +fn test_recv_iter_break() { + let (tx, rx) = channel::(); + let (count_tx, count_rx) = channel(); + + let _t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); +} + +#[test] +fn test_recv_try_iter() { + let (request_tx, request_rx) = channel(); + let (response_tx, response_rx) = channel(); + + // Request `x`s until we have `6`. + let t = thread::spawn(move || { + let mut count = 0; + loop { + for x in response_rx.try_iter() { + count += x; + if count == 6 { + return count; + } + } + request_tx.send(()).unwrap(); + } + }); + + for _ in request_rx.iter() { + if response_tx.send(2).is_err() { + break; + } + } + + assert_eq!(t.join().unwrap(), 6); +} + +#[test] +fn test_recv_into_iter_owned() { + let mut iter = { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + rx.into_iter() + }; + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn test_recv_into_iter_borrowed() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + let mut iter = (&rx).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn try_recv_states() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let _t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); +} + +// This bug used to end up in a livelock inside of the Receiver destructor +// because the internal state of the Shared packet was corrupted +#[test] +fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let t = tx.clone(); + drop(tx); + t.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); +} + +#[test] +fn issue_32114() { + let (tx, _) = channel(); + let _ = tx.send(123); + assert_eq!(tx.send(123), Err(SendError(123))); +} diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index d7a4f00305..e8f5a6f429 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::cell::UnsafeCell; use crate::fmt; use crate::mem; @@ -85,7 +88,7 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; /// use std::thread; /// /// let lock = Arc::new(Mutex::new(0_u32)); -/// let lock2 = lock.clone(); +/// let lock2 = Arc::clone(&lock); /// /// let _ = thread::spawn(move || -> () { /// // This thread will acquire the mutex first, unwrapping the result of @@ -163,12 +166,7 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")] pub struct Mutex { - // Note that this mutex is in a *box*, not inlined into the struct itself. - // Once a native mutex has been used once, its address can never change (it - // can't be moved). This mutex type can be safely moved at any time, so to - // ensure that the native mutex is used correctly we box the inner mutex to - // give it a constant address. - inner: Box, + inner: sys::MovableMutex, poison: poison::Flag, data: UnsafeCell, } @@ -215,15 +213,11 @@ impl Mutex { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> Mutex { - let mut m = Mutex { - inner: box sys::Mutex::new(), + Mutex { + inner: sys::MovableMutex::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t), - }; - unsafe { - m.inner.init(); } - m } } @@ -256,7 +250,7 @@ impl Mutex { /// use std::thread; /// /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// /// thread::spawn(move || { /// *c_mutex.lock().unwrap() = 10; @@ -292,7 +286,7 @@ impl Mutex { /// use std::thread; /// /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// /// thread::spawn(move || { /// let mut lock = c_mutex.try_lock(); @@ -328,7 +322,7 @@ impl Mutex { /// use std::thread; /// /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// /// let _ = thread::spawn(move || { /// let _lock = c_mutex.lock().unwrap(); @@ -375,7 +369,6 @@ impl Mutex { (ptr::read(inner), ptr::read(poison), ptr::read(data)) }; mem::forget(self); - inner.destroy(); // Keep in sync with the `Drop` impl. drop(inner); poison::map_result(poison.borrow(), |_| data.into_inner()) @@ -403,25 +396,11 @@ impl Mutex { /// ``` #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner mutex. - let data = unsafe { &mut *self.data.get() }; + let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |_| data) } } -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex { - fn drop(&mut self) { - // This is actually safe b/c we know that there is no further usage of - // this mutex (it's up to the user to arrange for a mutex to get - // dropped, that's not our job) - // - // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`. - unsafe { self.inner.destroy() } - } -} - #[stable(feature = "mutex_from", since = "1.24.0")] impl From for Mutex { /// Creates a new mutex in an unlocked state ready for use. @@ -508,252 +487,10 @@ impl fmt::Display for MutexGuard<'_, T> { } } -pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { +pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::MovableMutex { &guard.lock.inner } pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { &guard.lock.poison } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::sync::atomic::{AtomicUsize, Ordering}; - use crate::sync::mpsc::channel; - use crate::sync::{Arc, Condvar, Mutex}; - use crate::thread; - - struct Packet(Arc<(Mutex, Condvar)>); - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let m = Mutex::new(()); - drop(m.lock().unwrap()); - drop(m.lock().unwrap()); - } - - #[test] - fn lots_and_lots() { - const J: u32 = 1000; - const K: u32 = 3; - - let m = Arc::new(Mutex::new(0)); - - fn inc(m: &Mutex) { - for _ in 0..J { - *m.lock().unwrap() += 1; - } - } - - let (tx, rx) = channel(); - for _ in 0..K { - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - } - - drop(tx); - for _ in 0..2 * K { - rx.recv().unwrap(); - } - assert_eq!(*m.lock().unwrap(), J * K * 2); - } - - #[test] - fn try_lock() { - let m = Mutex::new(()); - *m.try_lock().unwrap() = (); - } - - #[test] - fn test_into_inner() { - let m = Mutex::new(NonCopy(10)); - assert_eq!(m.into_inner().unwrap(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = Mutex::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner().unwrap(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_into_inner_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { - Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), - } - } - - #[test] - fn test_get_mut() { - let mut m = Mutex::new(NonCopy(10)); - *m.get_mut().unwrap() = NonCopy(20); - assert_eq!(m.into_inner().unwrap(), NonCopy(20)); - } - - #[test] - fn test_get_mut_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { - Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), - } - } - - #[test] - fn test_mutex_arc_condvar() { - let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - // wait until parent gets in - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let mut lock = lock.lock().unwrap(); - *lock = true; - cvar.notify_one(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock().unwrap(); - tx.send(()).unwrap(); - assert!(!*lock); - while !*lock { - lock = cvar.wait(lock).unwrap(); - } - } - - #[test] - fn test_arc_condvar_poison() { - let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - - let _t = thread::spawn(move || -> () { - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let _g = lock.lock().unwrap(); - cvar.notify_one(); - // Parent should fail when it wakes up. - panic!(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock().unwrap(); - tx.send(()).unwrap(); - while *lock == 1 { - match cvar.wait(lock) { - Ok(l) => { - lock = l; - assert_eq!(*lock, 1); - } - Err(..) => break, - } - } - } - - #[test] - fn test_mutex_arc_poison() { - let arc = Arc::new(Mutex::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - let lock = arc2.lock().unwrap(); - assert_eq!(*lock, 2); - }) - .join(); - assert!(arc.lock().is_err()); - assert!(arc.is_poisoned()); - } - - #[test] - fn test_mutex_arc_nested() { - // Tests nested mutexes and access - // to underlying data. - let arc = Arc::new(Mutex::new(1)); - let arc2 = Arc::new(Mutex::new(arc)); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let lock = arc2.lock().unwrap(); - let lock2 = lock.lock().unwrap(); - assert_eq!(*lock2, 1); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_mutex_arc_access_in_unwind() { - let arc = Arc::new(Mutex::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || -> () { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - *self.i.lock().unwrap() += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.lock().unwrap(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_mutex_unsized() { - let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock().unwrap(), comp); - } -} diff --git a/library/std/src/sync/mutex/tests.rs b/library/std/src/sync/mutex/tests.rs new file mode 100644 index 0000000000..a1b5aeddcb --- /dev/null +++ b/library/std/src/sync/mutex/tests.rs @@ -0,0 +1,238 @@ +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::mpsc::channel; +use crate::sync::{Arc, Condvar, Mutex}; +use crate::thread; + +struct Packet(Arc<(Mutex, Condvar)>); + +#[derive(Eq, PartialEq, Debug)] +struct NonCopy(i32); + +#[test] +fn smoke() { + let m = Mutex::new(()); + drop(m.lock().unwrap()); + drop(m.lock().unwrap()); +} + +#[test] +fn lots_and_lots() { + const J: u32 = 1000; + const K: u32 = 3; + + let m = Arc::new(Mutex::new(0)); + + fn inc(m: &Mutex) { + for _ in 0..J { + *m.lock().unwrap() += 1; + } + } + + let (tx, rx) = channel(); + for _ in 0..K { + let tx2 = tx.clone(); + let m2 = m.clone(); + thread::spawn(move || { + inc(&m2); + tx2.send(()).unwrap(); + }); + let tx2 = tx.clone(); + let m2 = m.clone(); + thread::spawn(move || { + inc(&m2); + tx2.send(()).unwrap(); + }); + } + + drop(tx); + for _ in 0..2 * K { + rx.recv().unwrap(); + } + assert_eq!(*m.lock().unwrap(), J * K * 2); +} + +#[test] +fn try_lock() { + let m = Mutex::new(()); + *m.try_lock().unwrap() = (); +} + +#[test] +fn test_into_inner() { + let m = Mutex::new(NonCopy(10)); + assert_eq!(m.into_inner().unwrap(), NonCopy(10)); +} + +#[test] +fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = Mutex::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner().unwrap(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); +} + +#[test] +fn test_into_inner_poison() { + let m = Arc::new(Mutex::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.lock().unwrap(); + panic!("test panic in inner thread to poison mutex"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().into_inner() { + Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), + Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), + } +} + +#[test] +fn test_get_mut() { + let mut m = Mutex::new(NonCopy(10)); + *m.get_mut().unwrap() = NonCopy(20); + assert_eq!(m.into_inner().unwrap(), NonCopy(20)); +} + +#[test] +fn test_get_mut_poison() { + let m = Arc::new(Mutex::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.lock().unwrap(); + panic!("test panic in inner thread to poison mutex"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().get_mut() { + Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), + Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), + } +} + +#[test] +fn test_mutex_arc_condvar() { + let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); + let packet2 = Packet(packet.0.clone()); + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + // wait until parent gets in + rx.recv().unwrap(); + let &(ref lock, ref cvar) = &*packet2.0; + let mut lock = lock.lock().unwrap(); + *lock = true; + cvar.notify_one(); + }); + + let &(ref lock, ref cvar) = &*packet.0; + let mut lock = lock.lock().unwrap(); + tx.send(()).unwrap(); + assert!(!*lock); + while !*lock { + lock = cvar.wait(lock).unwrap(); + } +} + +#[test] +fn test_arc_condvar_poison() { + let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); + let packet2 = Packet(packet.0.clone()); + let (tx, rx) = channel(); + + let _t = thread::spawn(move || -> () { + rx.recv().unwrap(); + let &(ref lock, ref cvar) = &*packet2.0; + let _g = lock.lock().unwrap(); + cvar.notify_one(); + // Parent should fail when it wakes up. + panic!(); + }); + + let &(ref lock, ref cvar) = &*packet.0; + let mut lock = lock.lock().unwrap(); + tx.send(()).unwrap(); + while *lock == 1 { + match cvar.wait(lock) { + Ok(l) => { + lock = l; + assert_eq!(*lock, 1); + } + Err(..) => break, + } + } +} + +#[test] +fn test_mutex_arc_poison() { + let arc = Arc::new(Mutex::new(1)); + assert!(!arc.is_poisoned()); + let arc2 = arc.clone(); + let _ = thread::spawn(move || { + let lock = arc2.lock().unwrap(); + assert_eq!(*lock, 2); + }) + .join(); + assert!(arc.lock().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] +fn test_mutex_arc_nested() { + // Tests nested mutexes and access + // to underlying data. + let arc = Arc::new(Mutex::new(1)); + let arc2 = Arc::new(Mutex::new(arc)); + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + let lock = arc2.lock().unwrap(); + let lock2 = lock.lock().unwrap(); + assert_eq!(*lock2, 1); + tx.send(()).unwrap(); + }); + rx.recv().unwrap(); +} + +#[test] +fn test_mutex_arc_access_in_unwind() { + let arc = Arc::new(Mutex::new(1)); + let arc2 = arc.clone(); + let _ = thread::spawn(move || -> () { + struct Unwinder { + i: Arc>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + *self.i.lock().unwrap() += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }) + .join(); + let lock = arc.lock().unwrap(); + assert_eq!(*lock, 2); +} + +#[test] +fn test_mutex_unsized() { + let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); + { + let b = &mut *mutex.lock().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*mutex.lock().unwrap(), comp); +} diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 714ec3e878..de5ddf1daf 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -84,6 +84,9 @@ // processor. Because both use Acquire ordering such a reordering is not // allowed, so no need for SeqCst. +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::cell::Cell; use crate::fmt; use crate::marker; @@ -92,10 +95,7 @@ use crate::thread::{self, Thread}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related -/// functionality. This type can only be constructed with the [`Once::new`] -/// constructor. -/// -/// [`Once::new`]: struct.Once.html#method.new +/// functionality. This type can only be constructed with [`Once::new()`]. /// /// # Examples /// @@ -123,11 +123,8 @@ unsafe impl Sync for Once {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for Once {} -/// State yielded to [`call_once_force`]’s closure parameter. The state can be -/// used to query the poison status of the [`Once`]. -/// -/// [`call_once_force`]: struct.Once.html#method.call_once_force -/// [`Once`]: struct.Once.html +/// State yielded to [`Once::call_once_force()`]’s closure parameter. The state +/// can be used to query the poison status of the [`Once`]. #[unstable(feature = "once_poison", issue = "33577")] #[derive(Debug)] pub struct OnceState { @@ -137,8 +134,6 @@ pub struct OnceState { /// Initialization value for static [`Once`] values. /// -/// [`Once`]: struct.Once.html -/// /// # Examples /// /// ``` @@ -188,6 +183,7 @@ struct WaiterQueue<'a> { impl Once { /// Creates a new `Once` value. + #[inline] #[stable(feature = "once_new", since = "1.2.0")] #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] pub const fn new() -> Once { @@ -208,7 +204,7 @@ impl Once { /// happens-before relation between the closure and code executing after the /// return). /// - /// If the given closure recursively invokes `call_once` on the same `Once` + /// If the given closure recursively invokes `call_once` on the same [`Once`] /// instance the exact behavior is not specified, allowed outcomes are /// a panic or a deadlock. /// @@ -245,7 +241,7 @@ impl Once { /// /// The closure `f` will only be executed once if this is called /// concurrently amongst many threads. If that closure panics, however, then - /// it will *poison* this `Once` instance, causing all future invocations of + /// it will *poison* this [`Once`] instance, causing all future invocations of /// `call_once` to also panic. /// /// This is similar to [poisoning with mutexes][poison]. @@ -265,21 +261,21 @@ impl Once { self.call_inner(false, &mut |_| f.take().unwrap()()); } - /// Performs the same function as [`call_once`] except ignores poisoning. + /// Performs the same function as [`call_once()`] except ignores poisoning. /// - /// Unlike [`call_once`], if this `Once` has been poisoned (i.e., a previous - /// call to `call_once` or `call_once_force` caused a panic), calling - /// `call_once_force` will still invoke the closure `f` and will _not_ - /// result in an immediate panic. If `f` panics, the `Once` will remain - /// in a poison state. If `f` does _not_ panic, the `Once` will no - /// longer be in a poison state and all future calls to `call_once` or - /// `call_once_force` will be no-ops. + /// Unlike [`call_once()`], if this [`Once`] has been poisoned (i.e., a previous + /// call to [`call_once()`] or [`call_once_force()`] caused a panic), calling + /// [`call_once_force()`] will still invoke the closure `f` and will _not_ + /// result in an immediate panic. If `f` panics, the [`Once`] will remain + /// in a poison state. If `f` does _not_ panic, the [`Once`] will no + /// longer be in a poison state and all future calls to [`call_once()`] or + /// [`call_once_force()`] will be no-ops. /// /// The closure `f` is yielded a [`OnceState`] structure which can be used - /// to query the poison status of the `Once`. + /// to query the poison status of the [`Once`]. /// - /// [`call_once`]: struct.Once.html#method.call_once - /// [`OnceState`]: struct.OnceState.html + /// [`call_once()`]: Once::call_once + /// [`call_once_force()`]: Once::call_once_force /// /// # Examples /// @@ -325,18 +321,20 @@ impl Once { self.call_inner(true, &mut |p| f.take().unwrap()(p)); } - /// Returns `true` if some `call_once` call has completed + /// Returns `true` if some [`call_once()`] call has completed /// successfully. Specifically, `is_completed` will return false in /// the following situations: - /// * `call_once` was not called at all, - /// * `call_once` was called, but has not yet completed, - /// * the `Once` instance is poisoned + /// * [`call_once()`] was not called at all, + /// * [`call_once()`] was called, but has not yet completed, + /// * the [`Once`] instance is poisoned /// - /// This function returning `false` does not mean that `Once` has not been + /// This function returning `false` does not mean that [`Once`] has not been /// executed. For example, it may have been executed in the time between /// when `is_completed` starts executing and when it returns, in which case /// the `false` return value would be stale (but still permissible). /// + /// [`call_once()`]: Once::call_once + /// /// # Examples /// /// ``` @@ -515,14 +513,11 @@ impl Drop for WaiterQueue<'_> { impl OnceState { /// Returns `true` if the associated [`Once`] was poisoned prior to the - /// invocation of the closure passed to [`call_once_force`]. - /// - /// [`call_once_force`]: struct.Once.html#method.call_once_force - /// [`Once`]: struct.Once.html + /// invocation of the closure passed to [`Once::call_once_force()`]. /// /// # Examples /// - /// A poisoned `Once`: + /// A poisoned [`Once`]: /// /// ``` /// #![feature(once_poison)] @@ -543,7 +538,7 @@ impl OnceState { /// }); /// ``` /// - /// An unpoisoned `Once`: + /// An unpoisoned [`Once`]: /// /// ``` /// #![feature(once_poison)] @@ -561,130 +556,8 @@ impl OnceState { } /// Poison the associated [`Once`] without explicitly panicking. - /// - /// [`Once`]: struct.Once.html // NOTE: This is currently only exposed for the `lazy` module pub(crate) fn poison(&self) { self.set_state_on_drop_to.set(POISONED); } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::Once; - use crate::panic; - use crate::sync::mpsc::channel; - use crate::thread; - - #[test] - fn smoke_once() { - static O: Once = Once::new(); - let mut a = 0; - O.call_once(|| a += 1); - assert_eq!(a, 1); - O.call_once(|| a += 1); - assert_eq!(a, 1); - } - - #[test] - fn stampede_once() { - static O: Once = Once::new(); - static mut RUN: bool = false; - - let (tx, rx) = channel(); - for _ in 0..10 { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..4 { - thread::yield_now() - } - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - tx.send(()).unwrap(); - }); - } - - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - - for _ in 0..10 { - rx.recv().unwrap(); - } - } - - #[test] - fn poison_bad() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // poisoning propagates - let t = panic::catch_unwind(|| { - O.call_once(|| {}); - }); - assert!(t.is_err()); - - // we can subvert poisoning, however - let mut called = false; - O.call_once_force(|p| { - called = true; - assert!(p.poisoned()) - }); - assert!(called); - - // once any success happens, we stop propagating the poison - O.call_once(|| {}); - } - - #[test] - fn wait_for_force_to_finish() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // make sure someone's waiting inside the once via a force - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let t1 = thread::spawn(move || { - O.call_once_force(|p| { - assert!(p.poisoned()); - tx1.send(()).unwrap(); - rx2.recv().unwrap(); - }); - }); - - rx1.recv().unwrap(); - - // put another waiter on the once - let t2 = thread::spawn(|| { - let mut called = false; - O.call_once(|| { - called = true; - }); - assert!(!called); - }); - - tx2.send(()).unwrap(); - - assert!(t1.join().is_ok()); - assert!(t2.join().is_ok()); - } -} diff --git a/library/std/src/sync/once/tests.rs b/library/std/src/sync/once/tests.rs new file mode 100644 index 0000000000..fae2752526 --- /dev/null +++ b/library/std/src/sync/once/tests.rs @@ -0,0 +1,116 @@ +use super::Once; +use crate::panic; +use crate::sync::mpsc::channel; +use crate::thread; + +#[test] +fn smoke_once() { + static O: Once = Once::new(); + let mut a = 0; + O.call_once(|| a += 1); + assert_eq!(a, 1); + O.call_once(|| a += 1); + assert_eq!(a, 1); +} + +#[test] +fn stampede_once() { + static O: Once = Once::new(); + static mut RUN: bool = false; + + let (tx, rx) = channel(); + for _ in 0..10 { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..4 { + thread::yield_now() + } + unsafe { + O.call_once(|| { + assert!(!RUN); + RUN = true; + }); + assert!(RUN); + } + tx.send(()).unwrap(); + }); + } + + unsafe { + O.call_once(|| { + assert!(!RUN); + RUN = true; + }); + assert!(RUN); + } + + for _ in 0..10 { + rx.recv().unwrap(); + } +} + +#[test] +fn poison_bad() { + static O: Once = Once::new(); + + // poison the once + let t = panic::catch_unwind(|| { + O.call_once(|| panic!()); + }); + assert!(t.is_err()); + + // poisoning propagates + let t = panic::catch_unwind(|| { + O.call_once(|| {}); + }); + assert!(t.is_err()); + + // we can subvert poisoning, however + let mut called = false; + O.call_once_force(|p| { + called = true; + assert!(p.poisoned()) + }); + assert!(called); + + // once any success happens, we stop propagating the poison + O.call_once(|| {}); +} + +#[test] +fn wait_for_force_to_finish() { + static O: Once = Once::new(); + + // poison the once + let t = panic::catch_unwind(|| { + O.call_once(|| panic!()); + }); + assert!(t.is_err()); + + // make sure someone's waiting inside the once via a force + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let t1 = thread::spawn(move || { + O.call_once_force(|p| { + assert!(p.poisoned()); + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + }); + }); + + rx1.recv().unwrap(); + + // put another waiter on the once + let t2 = thread::spawn(|| { + let mut called = false; + O.call_once(|| { + called = true; + }); + assert!(!called); + }); + + tx2.send(()).unwrap(); + + assert!(t1.join().is_ok()); + assert!(t2.join().is_ok()); +} diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 586093c916..d967779ce3 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::cell::UnsafeCell; use crate::fmt; use crate::mem; @@ -162,7 +165,7 @@ impl RwLock { /// use std::thread; /// /// let lock = Arc::new(RwLock::new(1)); - /// let c_lock = lock.clone(); + /// let c_lock = Arc::clone(&lock); /// /// let n = lock.read().unwrap(); /// assert_eq!(*n, 1); @@ -318,7 +321,7 @@ impl RwLock { /// use std::thread; /// /// let lock = Arc::new(RwLock::new(0)); - /// let c_lock = lock.clone(); + /// let c_lock = Arc::clone(&lock); /// /// let _ = thread::spawn(move || { /// let _lock = c_lock.write().unwrap(); @@ -401,9 +404,7 @@ impl RwLock { /// ``` #[stable(feature = "rwlock_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner lock. - let data = unsafe { &mut *self.data.get() }; + let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |_| data) } } @@ -538,254 +539,3 @@ impl Drop for RwLockWriteGuard<'_, T> { } } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::sync::atomic::{AtomicUsize, Ordering}; - use crate::sync::mpsc::channel; - use crate::sync::{Arc, RwLock, TryLockError}; - use crate::thread; - use rand::{self, Rng}; - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let l = RwLock::new(()); - drop(l.read().unwrap()); - drop(l.write().unwrap()); - drop((l.read().unwrap(), l.read().unwrap())); - drop(l.write().unwrap()); - } - - #[test] - fn frob() { - const N: u32 = 10; - const M: usize = 1000; - - let r = Arc::new(RwLock::new(())); - - let (tx, rx) = channel::<()>(); - for _ in 0..N { - let tx = tx.clone(); - let r = r.clone(); - thread::spawn(move || { - let mut rng = rand::thread_rng(); - for _ in 0..M { - if rng.gen_bool(1.0 / (N as f64)) { - drop(r.write().unwrap()); - } else { - drop(r.read().unwrap()); - } - } - drop(tx); - }); - } - drop(tx); - let _ = rx.recv(); - } - - #[test] - fn test_rw_arc_poison_wr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }) - .join(); - assert!(arc.read().is_err()); - } - - #[test] - fn test_rw_arc_poison_ww() { - let arc = Arc::new(RwLock::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }) - .join(); - assert!(arc.write().is_err()); - assert!(arc.is_poisoned()); - } - - #[test] - fn test_rw_arc_no_poison_rr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!(); - }) - .join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 1); - } - #[test] - fn test_rw_arc_no_poison_rw() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!() - }) - .join(); - let lock = arc.write().unwrap(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc() { - let arc = Arc::new(RwLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - thread::spawn(move || { - let mut lock = arc2.write().unwrap(); - for _ in 0..10 { - let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - } - tx.send(()).unwrap(); - }); - - // Readers try to catch the writer in the act - let mut children = Vec::new(); - for _ in 0..5 { - let arc3 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc3.read().unwrap(); - assert!(*lock >= 0); - })); - } - - // Wait for children to pass their asserts - for r in children { - assert!(r.join().is_ok()); - } - - // Wait for writer to finish - rx.recv().unwrap(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 10); - } - - #[test] - fn test_rw_arc_access_in_unwind() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || -> () { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - let mut lock = self.i.write().unwrap(); - *lock += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_rwlock_unsized() { - let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); - { - let b = &mut *rw.write().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*rw.read().unwrap(), comp); - } - - #[test] - fn test_rwlock_try_write() { - let lock = RwLock::new(0isize); - let read_guard = lock.read().unwrap(); - - let write_result = lock.try_write(); - match write_result { - Err(TryLockError::WouldBlock) => (), - Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"), - Err(_) => assert!(false, "unexpected error"), - } - - drop(read_guard); - } - - #[test] - fn test_into_inner() { - let m = RwLock::new(NonCopy(10)); - assert_eq!(m.into_inner().unwrap(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = RwLock::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner().unwrap(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_into_inner_poison() { - let m = Arc::new(RwLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison RwLock"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { - Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x), - } - } - - #[test] - fn test_get_mut() { - let mut m = RwLock::new(NonCopy(10)); - *m.get_mut().unwrap() = NonCopy(20); - assert_eq!(m.into_inner().unwrap(), NonCopy(20)); - } - - #[test] - fn test_get_mut_poison() { - let m = Arc::new(RwLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison RwLock"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { - Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x), - } - } -} diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs new file mode 100644 index 0000000000..e9b74fb3ec --- /dev/null +++ b/library/std/src/sync/rwlock/tests.rs @@ -0,0 +1,247 @@ +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::mpsc::channel; +use crate::sync::{Arc, RwLock, TryLockError}; +use crate::thread; +use rand::{self, Rng}; + +#[derive(Eq, PartialEq, Debug)] +struct NonCopy(i32); + +#[test] +fn smoke() { + let l = RwLock::new(()); + drop(l.read().unwrap()); + drop(l.write().unwrap()); + drop((l.read().unwrap(), l.read().unwrap())); + drop(l.write().unwrap()); +} + +#[test] +fn frob() { + const N: u32 = 10; + const M: usize = 1000; + + let r = Arc::new(RwLock::new(())); + + let (tx, rx) = channel::<()>(); + for _ in 0..N { + let tx = tx.clone(); + let r = r.clone(); + thread::spawn(move || { + let mut rng = rand::thread_rng(); + for _ in 0..M { + if rng.gen_bool(1.0 / (N as f64)) { + drop(r.write().unwrap()); + } else { + drop(r.read().unwrap()); + } + } + drop(tx); + }); + } + drop(tx); + let _ = rx.recv(); +} + +#[test] +fn test_rw_arc_poison_wr() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }) + .join(); + assert!(arc.read().is_err()); +} + +#[test] +fn test_rw_arc_poison_ww() { + let arc = Arc::new(RwLock::new(1)); + assert!(!arc.is_poisoned()); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }) + .join(); + assert!(arc.write().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] +fn test_rw_arc_no_poison_rr() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!(); + }) + .join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 1); +} +#[test] +fn test_rw_arc_no_poison_rw() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!() + }) + .join(); + let lock = arc.write().unwrap(); + assert_eq!(*lock, 1); +} + +#[test] +fn test_rw_arc() { + let arc = Arc::new(RwLock::new(0)); + let arc2 = arc.clone(); + let (tx, rx) = channel(); + + thread::spawn(move || { + let mut lock = arc2.write().unwrap(); + for _ in 0..10 { + let tmp = *lock; + *lock = -1; + thread::yield_now(); + *lock = tmp + 1; + } + tx.send(()).unwrap(); + }); + + // Readers try to catch the writer in the act + let mut children = Vec::new(); + for _ in 0..5 { + let arc3 = arc.clone(); + children.push(thread::spawn(move || { + let lock = arc3.read().unwrap(); + assert!(*lock >= 0); + })); + } + + // Wait for children to pass their asserts + for r in children { + assert!(r.join().is_ok()); + } + + // Wait for writer to finish + rx.recv().unwrap(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 10); +} + +#[test] +fn test_rw_arc_access_in_unwind() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _ = thread::spawn(move || -> () { + struct Unwinder { + i: Arc>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + let mut lock = self.i.write().unwrap(); + *lock += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }) + .join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 2); +} + +#[test] +fn test_rwlock_unsized() { + let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); + { + let b = &mut *rw.write().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*rw.read().unwrap(), comp); +} + +#[test] +fn test_rwlock_try_write() { + let lock = RwLock::new(0isize); + let read_guard = lock.read().unwrap(); + + let write_result = lock.try_write(); + match write_result { + Err(TryLockError::WouldBlock) => (), + Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"), + Err(_) => assert!(false, "unexpected error"), + } + + drop(read_guard); +} + +#[test] +fn test_into_inner() { + let m = RwLock::new(NonCopy(10)); + assert_eq!(m.into_inner().unwrap(), NonCopy(10)); +} + +#[test] +fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = RwLock::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner().unwrap(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); +} + +#[test] +fn test_into_inner_poison() { + let m = Arc::new(RwLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison RwLock"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().into_inner() { + Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), + Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x), + } +} + +#[test] +fn test_get_mut() { + let mut m = RwLock::new(NonCopy(10)); + *m.get_mut().unwrap() = NonCopy(20); + assert_eq!(m.into_inner().unwrap(), NonCopy(20)); +} + +#[test] +fn test_get_mut_poison() { + let m = Arc::new(RwLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison RwLock"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().get_mut() { + Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), + Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x), + } +} diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs index 72c1b8511c..7727293927 100644 --- a/library/std/src/sys/hermit/args.rs +++ b/library/std/src/sys/hermit/args.rs @@ -57,11 +57,11 @@ mod imp { use crate::ptr; use crate::sys_common::os_str_bytes::*; - use crate::sys_common::mutex::Mutex; + use crate::sys_common::mutex::StaticMutex; static mut ARGC: isize = 0; static mut ARGV: *const *const u8 = ptr::null(); - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { let _guard = LOCK.lock(); diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs index 57fd7efdd4..ffa234fccf 100644 --- a/library/std/src/sys/sgx/abi/mem.rs +++ b/library/std/src/sys/sgx/abi/mem.rs @@ -21,8 +21,15 @@ extern "C" { #[inline(always)] #[unstable(feature = "sgx_platform", issue = "56975")] pub fn image_base() -> u64 { - let base; - unsafe { llvm_asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) }; + let base: u64; + unsafe { + asm!( + "lea IMAGE_BASE(%rip), {}", + lateout(reg) base, + // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9. + options(att_syntax, nostack, preserves_flags, nomem, pure), + ) + }; base } diff --git a/library/std/src/sys/sgx/abi/tls.rs b/library/std/src/sys/sgx/abi/tls.rs index 2b0485c4f0..0d8952b2f2 100644 --- a/library/std/src/sys/sgx/abi/tls.rs +++ b/library/std/src/sys/sgx/abi/tls.rs @@ -1,3 +1,5 @@ +mod sync_bitset; + use self::sync_bitset::*; use crate::cell::Cell; use crate::mem; @@ -125,117 +127,3 @@ impl Tls { TLS_KEY_IN_USE.clear(key.to_index()); } } - -mod sync_bitset { - use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS}; - use crate::iter::{Enumerate, Peekable}; - use crate::slice::Iter; - use crate::sync::atomic::{AtomicUsize, Ordering}; - - /// A bitset that can be used synchronously. - pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]); - - pub(super) const SYNC_BITSET_INIT: SyncBitset = - SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]); - - impl SyncBitset { - pub fn get(&self, index: usize) -> bool { - let (hi, lo) = Self::split(index); - (self.0[hi].load(Ordering::Relaxed) & lo) != 0 - } - - /// Not atomic. - pub fn iter(&self) -> SyncBitsetIter<'_> { - SyncBitsetIter { iter: self.0.iter().enumerate().peekable(), elem_idx: 0 } - } - - pub fn clear(&self, index: usize) { - let (hi, lo) = Self::split(index); - self.0[hi].fetch_and(!lo, Ordering::Relaxed); - } - - /// Sets any unset bit. Not atomic. Returns `None` if all bits were - /// observed to be set. - pub fn set(&self) -> Option { - 'elems: for (idx, elem) in self.0.iter().enumerate() { - let mut current = elem.load(Ordering::Relaxed); - loop { - if 0 == !current { - continue 'elems; - } - let trailing_ones = (!current).trailing_zeros() as usize; - match elem.compare_exchange( - current, - current | (1 << trailing_ones), - Ordering::AcqRel, - Ordering::Relaxed, - ) { - Ok(_) => return Some(idx * USIZE_BITS + trailing_ones), - Err(previous) => current = previous, - } - } - } - None - } - - fn split(index: usize) -> (usize, usize) { - (index / USIZE_BITS, 1 << (index % USIZE_BITS)) - } - } - - pub(super) struct SyncBitsetIter<'a> { - iter: Peekable>>, - elem_idx: usize, - } - - impl<'a> Iterator for SyncBitsetIter<'a> { - type Item = usize; - - fn next(&mut self) -> Option { - self.iter.peek().cloned().and_then(|(idx, elem)| { - let elem = elem.load(Ordering::Relaxed); - let low_mask = (1 << self.elem_idx) - 1; - let next = elem & !low_mask; - let next_idx = next.trailing_zeros() as usize; - self.elem_idx = next_idx + 1; - if self.elem_idx >= 64 { - self.elem_idx = 0; - self.iter.next(); - } - match next_idx { - 64 => self.next(), - _ => Some(idx * USIZE_BITS + next_idx), - } - }) - } - } - - #[cfg(test)] - mod tests { - use super::*; - - fn test_data(bitset: [usize; 2], bit_indices: &[usize]) { - let set = SyncBitset([AtomicUsize::new(bitset[0]), AtomicUsize::new(bitset[1])]); - assert_eq!(set.iter().collect::>(), bit_indices); - for &i in bit_indices { - assert!(set.get(i)); - } - } - - #[test] - fn iter() { - test_data([0b0110_1001, 0], &[0, 3, 5, 6]); - test_data([0x8000_0000_0000_0000, 0x8000_0000_0000_0001], &[63, 64, 127]); - test_data([0, 0], &[]); - } - - #[test] - fn set_get_clear() { - let set = SYNC_BITSET_INIT; - let key = set.set().unwrap(); - assert!(set.get(key)); - set.clear(key); - assert!(!set.get(key)); - } - } -} diff --git a/library/std/src/sys/sgx/abi/tls/sync_bitset.rs b/library/std/src/sys/sgx/abi/tls/sync_bitset.rs new file mode 100644 index 0000000000..4eeff8f6ef --- /dev/null +++ b/library/std/src/sys/sgx/abi/tls/sync_bitset.rs @@ -0,0 +1,85 @@ +#[cfg(test)] +mod tests; + +use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS}; +use crate::iter::{Enumerate, Peekable}; +use crate::slice::Iter; +use crate::sync::atomic::{AtomicUsize, Ordering}; + +/// A bitset that can be used synchronously. +pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]); + +pub(super) const SYNC_BITSET_INIT: SyncBitset = + SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]); + +impl SyncBitset { + pub fn get(&self, index: usize) -> bool { + let (hi, lo) = Self::split(index); + (self.0[hi].load(Ordering::Relaxed) & lo) != 0 + } + + /// Not atomic. + pub fn iter(&self) -> SyncBitsetIter<'_> { + SyncBitsetIter { iter: self.0.iter().enumerate().peekable(), elem_idx: 0 } + } + + pub fn clear(&self, index: usize) { + let (hi, lo) = Self::split(index); + self.0[hi].fetch_and(!lo, Ordering::Relaxed); + } + + /// Sets any unset bit. Not atomic. Returns `None` if all bits were + /// observed to be set. + pub fn set(&self) -> Option { + 'elems: for (idx, elem) in self.0.iter().enumerate() { + let mut current = elem.load(Ordering::Relaxed); + loop { + if 0 == !current { + continue 'elems; + } + let trailing_ones = (!current).trailing_zeros() as usize; + match elem.compare_exchange( + current, + current | (1 << trailing_ones), + Ordering::AcqRel, + Ordering::Relaxed, + ) { + Ok(_) => return Some(idx * USIZE_BITS + trailing_ones), + Err(previous) => current = previous, + } + } + } + None + } + + fn split(index: usize) -> (usize, usize) { + (index / USIZE_BITS, 1 << (index % USIZE_BITS)) + } +} + +pub(super) struct SyncBitsetIter<'a> { + iter: Peekable>>, + elem_idx: usize, +} + +impl<'a> Iterator for SyncBitsetIter<'a> { + type Item = usize; + + fn next(&mut self) -> Option { + self.iter.peek().cloned().and_then(|(idx, elem)| { + let elem = elem.load(Ordering::Relaxed); + let low_mask = (1 << self.elem_idx) - 1; + let next = elem & !low_mask; + let next_idx = next.trailing_zeros() as usize; + self.elem_idx = next_idx + 1; + if self.elem_idx >= 64 { + self.elem_idx = 0; + self.iter.next(); + } + match next_idx { + 64 => self.next(), + _ => Some(idx * USIZE_BITS + next_idx), + } + }) + } +} diff --git a/library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs b/library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs new file mode 100644 index 0000000000..d7eb2e139d --- /dev/null +++ b/library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs @@ -0,0 +1,25 @@ +use super::*; + +fn test_data(bitset: [usize; 2], bit_indices: &[usize]) { + let set = SyncBitset([AtomicUsize::new(bitset[0]), AtomicUsize::new(bitset[1])]); + assert_eq!(set.iter().collect::>(), bit_indices); + for &i in bit_indices { + assert!(set.get(i)); + } +} + +#[test] +fn iter() { + test_data([0b0110_1001, 0], &[0, 3, 5, 6]); + test_data([0x8000_0000_0000_0000, 0x8000_0000_0000_0001], &[63, 64, 127]); + test_data([0, 0], &[]); +} + +#[test] +fn set_get_clear() { + let set = SYNC_BITSET_INIT; + let key = set.set().unwrap(); + assert!(set.get(key)); + set.clear(key); + assert!(!set.get(key)); +} diff --git a/library/std/src/sys/sgx/ext/arch.rs b/library/std/src/sys/sgx/ext/arch.rs index 0c97a87e2e..7488e7e5dc 100644 --- a/library/std/src/sys/sgx/ext/arch.rs +++ b/library/std/src/sys/sgx/ext/arch.rs @@ -31,13 +31,13 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result, u32> let mut out = MaybeUninit::uninit(); let error; - llvm_asm!( - "enclu" - : "={eax}"(error) - : "{eax}"(ENCLU_EGETKEY), - "{rbx}"(request), - "{rcx}"(out.as_mut_ptr()) - : "flags" + asm!( + "enclu", + inlateout("eax") ENCLU_EGETKEY => error, + in("rbx") request, + in("rcx") out.as_mut_ptr(), + // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9. + options(att_syntax, nostack), ); match error { @@ -60,13 +60,14 @@ pub fn ereport( unsafe { let mut report = MaybeUninit::uninit(); - llvm_asm!( - "enclu" - : /* no output registers */ - : "{eax}"(ENCLU_EREPORT), - "{rbx}"(targetinfo), - "{rcx}"(reportdata), - "{rdx}"(report.as_mut_ptr()) + asm!( + "enclu", + in("eax") ENCLU_EREPORT, + in("rbx") targetinfo, + in("rcx") reportdata, + in("rdx") report.as_mut_ptr(), + // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9. + options(att_syntax, preserves_flags, nostack), ); report.assume_init() diff --git a/library/std/src/sys/sgx/fs.rs b/library/std/src/sys/sgx/fs.rs deleted file mode 100644 index ecb5b51ccc..0000000000 --- a/library/std/src/sys/sgx/fs.rs +++ /dev/null @@ -1,308 +0,0 @@ -use crate::ffi::OsString; -use crate::fmt; -use crate::hash::{Hash, Hasher}; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; -use crate::path::{Path, PathBuf}; -use crate::sys::time::SystemTime; -use crate::sys::{unsupported, Void}; - -pub struct File(Void); - -pub struct FileAttr(Void); - -pub struct ReadDir(Void); - -pub struct DirEntry(Void); - -#[derive(Clone, Debug)] -pub struct OpenOptions {} - -pub struct FilePermissions(Void); - -pub struct FileType(Void); - -#[derive(Debug)] -pub struct DirBuilder {} - -impl FileAttr { - pub fn size(&self) -> u64 { - match self.0 {} - } - - pub fn perm(&self) -> FilePermissions { - match self.0 {} - } - - pub fn file_type(&self) -> FileType { - match self.0 {} - } - - pub fn modified(&self) -> io::Result { - match self.0 {} - } - - pub fn accessed(&self) -> io::Result { - match self.0 {} - } - - pub fn created(&self) -> io::Result { - match self.0 {} - } -} - -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - match self.0 {} - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - match self.0 {} - } - - pub fn set_readonly(&mut self, _readonly: bool) { - match self.0 {} - } -} - -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - match self.0 {} - } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - match self.0 {} - } -} - -impl Eq for FilePermissions {} - -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - match self.0 {} - } - - pub fn is_file(&self) -> bool { - match self.0 {} - } - - pub fn is_symlink(&self) -> bool { - match self.0 {} - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - match self.0 {} - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - match self.0 {} - } -} - -impl Eq for FileType {} - -impl Hash for FileType { - fn hash(&self, _h: &mut H) { - match self.0 {} - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - match self.0 {} - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - match self.0 {} - } - - pub fn file_name(&self) -> OsString { - match self.0 {} - } - - pub fn metadata(&self) -> io::Result { - match self.0 {} - } - - pub fn file_type(&self) -> io::Result { - match self.0 {} - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions {} - } - - pub fn read(&mut self, _read: bool) {} - pub fn write(&mut self, _write: bool) {} - pub fn append(&mut self, _append: bool) {} - pub fn truncate(&mut self, _truncate: bool) {} - pub fn create(&mut self, _create: bool) {} - pub fn create_new(&mut self, _create_new: bool) {} -} - -impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() - } - - pub fn file_attr(&self) -> io::Result { - match self.0 {} - } - - pub fn fsync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn datasync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn truncate(&self, _size: u64) -> io::Result<()> { - match self.0 {} - } - - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn flush(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder {} - } - - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() - } -} - -impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -pub fn readdir(_p: &Path) -> io::Result { - unsupported() -} - -pub fn unlink(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - unsupported() -} - -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} -} - -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() -} - -pub fn readlink(_p: &Path) -> io::Result { - unsupported() -} - -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn stat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn lstat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn canonicalize(_p: &Path) -> io::Result { - unsupported() -} - -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} diff --git a/library/std/src/sys/sgx/io.rs b/library/std/src/sys/sgx/io.rs deleted file mode 100644 index d5f475b431..0000000000 --- a/library/std/src/sys/sgx/io.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::mem; - -#[derive(Copy, Clone)] -pub struct IoSlice<'a>(&'a [u8]); - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - self.0 = &self.0[n..] - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0 - } -} - -pub struct IoSliceMut<'a>(&'a mut [u8]); - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - let slice = mem::replace(&mut self.0, &mut []); - let (_, remaining) = slice.split_at_mut(n); - self.0 = remaining; - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0 - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - self.0 - } -} diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index 1d32eb2542..1abd91e75e 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -17,14 +17,18 @@ pub mod condvar; pub mod env; pub mod ext; pub mod fd; +#[path = "../unsupported/fs.rs"] pub mod fs; +#[path = "../unsupported/io.rs"] pub mod io; pub mod memchr; pub mod mutex; pub mod net; pub mod os; pub mod path; +#[path = "../unsupported/pipe.rs"] pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; pub mod rwlock; pub mod stack_overflow; diff --git a/library/std/src/sys/sgx/pipe.rs b/library/std/src/sys/sgx/pipe.rs deleted file mode 100644 index 10d0925823..0000000000 --- a/library/std/src/sys/sgx/pipe.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::sys::Void; - -pub struct AnonPipe(Void); - -impl AnonPipe { - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/library/std/src/sys/sgx/process.rs b/library/std/src/sys/sgx/process.rs deleted file mode 100644 index 4702e5c549..0000000000 --- a/library/std/src/sys/sgx/process.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::ffi::OsStr; -use crate::fmt; -use crate::io; -use crate::sys::fs::File; -use crate::sys::pipe::AnonPipe; -use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; - -pub use crate::ffi::OsString as EnvKey; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } - } - - pub fn arg(&mut self, _arg: &OsStr) {} - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) {} - - pub fn stdin(&mut self, _stdin: Stdio) {} - - pub fn stdout(&mut self, _stdout: Stdio) {} - - pub fn stderr(&mut self, _stderr: Stdio) {} - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus {} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs index 722b4f5e0b..3bf2a7d8fb 100644 --- a/library/std/src/sys/sgx/rwlock.rs +++ b/library/std/src/sys/sgx/rwlock.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::num::NonZeroUsize; use super::waitqueue::{ @@ -198,50 +201,3 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { (*p).unlock(); return 0; } - -#[cfg(test)] -mod tests { - use super::*; - use crate::mem::{self, MaybeUninit}; - use core::array::FixedSizeArray; - - // Verify that the bytes of initialized RWLock are the same as in - // libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to - // be changed too. - #[test] - fn test_c_rwlock_initializer() { - #[rustfmt::skip] - const RWLOCK_INIT: &[u8] = &[ - /* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - ]; - - #[inline(never)] - fn zero_stack() { - test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed()); - } - - #[inline(never)] - unsafe fn rwlock_new(init: &mut MaybeUninit) { - init.write(RWLock::new()); - } - - unsafe { - // try hard to make sure that the padding/unused bytes in RWLock - // get initialized as 0. If the assertion below fails, that might - // just be an issue with the test code and not with the value of - // RWLOCK_INIT. - zero_stack(); - let mut init = MaybeUninit::::zeroed(); - rwlock_new(&mut init); - assert_eq!(mem::transmute::<_, [u8; 144]>(init.assume_init()).as_slice(), RWLOCK_INIT) - }; - } -} diff --git a/library/std/src/sys/sgx/rwlock/tests.rs b/library/std/src/sys/sgx/rwlock/tests.rs new file mode 100644 index 0000000000..17c9e72ee3 --- /dev/null +++ b/library/std/src/sys/sgx/rwlock/tests.rs @@ -0,0 +1,31 @@ +use super::*; + +// Verify that the byte pattern libunwind uses to initialize an RWLock is +// equivalent to the value of RWLock::new(). If the value changes, +// `src/UnwindRustSgx.h` in libunwind needs to be changed too. +#[test] +fn test_c_rwlock_initializer() { + #[rustfmt::skip] + const C_RWLOCK_INIT: &[u8] = &[ + /* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + + // For the test to work, we need the padding/unused bytes in RWLock to be + // initialized as 0. In practice, this is the case with statics. + static RUST_RWLOCK_INIT: RWLock = RWLock::new(); + + unsafe { + // If the assertion fails, that not necessarily an issue with the value + // of C_RWLOCK_INIT. It might just be an issue with the way padding + // bytes are initialized in the test code. + assert_eq!(&crate::mem::transmute_copy::<_, [u8; 144]>(&RUST_RWLOCK_INIT), C_RWLOCK_INIT); + }; +} diff --git a/library/std/src/sys/sgx/waitqueue.rs b/library/std/src/sys/sgx/waitqueue.rs index 070afa55f3..e464dc3ee9 100644 --- a/library/std/src/sys/sgx/waitqueue.rs +++ b/library/std/src/sys/sgx/waitqueue.rs @@ -9,6 +9,18 @@ //! Since userspace may send spurious wake-ups, the wakeup event state is //! recorded in the enclave. The wakeup event state is protected by a spinlock. //! The queue and associated wait state are stored in a `WaitVariable`. + +#[cfg(test)] +mod tests; + +/// A doubly-linked list where callers are in charge of memory allocation +/// of the nodes in the list. +mod unsafe_list; + +/// Trivial spinlock-based implementation of `sync::Mutex`. +// FIXME: Perhaps use Intel TSX to avoid locking? +mod spin_mutex; + use crate::num::NonZeroUsize; use crate::ops::{Deref, DerefMut}; use crate::time::Duration; @@ -231,389 +243,3 @@ impl WaitQueue { } } } - -/// A doubly-linked list where callers are in charge of memory allocation -/// of the nodes in the list. -mod unsafe_list { - use crate::mem; - use crate::ptr::NonNull; - - pub struct UnsafeListEntry { - next: NonNull>, - prev: NonNull>, - value: Option, - } - - impl UnsafeListEntry { - fn dummy() -> Self { - UnsafeListEntry { next: NonNull::dangling(), prev: NonNull::dangling(), value: None } - } - - pub fn new(value: T) -> Self { - UnsafeListEntry { value: Some(value), ..Self::dummy() } - } - } - - pub struct UnsafeList { - head_tail: NonNull>, - head_tail_entry: Option>, - } - - impl UnsafeList { - pub const fn new() -> Self { - unsafe { - UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } - } - } - - unsafe fn init(&mut self) { - if self.head_tail_entry.is_none() { - self.head_tail_entry = Some(UnsafeListEntry::dummy()); - self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap()); - self.head_tail.as_mut().next = self.head_tail; - self.head_tail.as_mut().prev = self.head_tail; - } - } - - pub fn is_empty(&self) -> bool { - unsafe { - if self.head_tail_entry.is_some() { - let first = self.head_tail.as_ref().next; - if first == self.head_tail { - // ,-------> /---------\ next ---, - // | |head_tail| | - // `--- prev \---------/ <-------` - rtassert!(self.head_tail.as_ref().prev == first); - true - } else { - false - } - } else { - true - } - } - } - - /// Pushes an entry onto the back of the list. - /// - /// # Safety - /// - /// The entry must remain allocated until the entry is removed from the - /// list AND the caller who popped is done using the entry. Special - /// care must be taken in the caller of `push` to ensure unwinding does - /// not destroy the stack frame containing the entry. - pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry) -> &'a T { - self.init(); - - // BEFORE: - // /---------\ next ---> /---------\ - // ... |prev_tail| |head_tail| ... - // \---------/ <--- prev \---------/ - // - // AFTER: - // /---------\ next ---> /-----\ next ---> /---------\ - // ... |prev_tail| |entry| |head_tail| ... - // \---------/ <--- prev \-----/ <--- prev \---------/ - let mut entry = NonNull::new_unchecked(entry); - let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry); - entry.as_mut().prev = prev_tail; - entry.as_mut().next = self.head_tail; - prev_tail.as_mut().next = entry; - // unwrap ok: always `Some` on non-dummy entries - (*entry.as_ptr()).value.as_ref().unwrap() - } - - /// Pops an entry from the front of the list. - /// - /// # Safety - /// - /// The caller must make sure to synchronize ending the borrow of the - /// return value and deallocation of the containing entry. - pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> { - self.init(); - - if self.is_empty() { - None - } else { - // BEFORE: - // /---------\ next ---> /-----\ next ---> /------\ - // ... |head_tail| |first| |second| ... - // \---------/ <--- prev \-----/ <--- prev \------/ - // - // AFTER: - // /---------\ next ---> /------\ - // ... |head_tail| |second| ... - // \---------/ <--- prev \------/ - let mut first = self.head_tail.as_mut().next; - let mut second = first.as_mut().next; - self.head_tail.as_mut().next = second; - second.as_mut().prev = self.head_tail; - first.as_mut().next = NonNull::dangling(); - first.as_mut().prev = NonNull::dangling(); - // unwrap ok: always `Some` on non-dummy entries - Some((*first.as_ptr()).value.as_ref().unwrap()) - } - } - - /// Removes an entry from the list. - /// - /// # Safety - /// - /// The caller must ensure that `entry` has been pushed onto `self` - /// prior to this call and has not moved since then. - pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry) { - rtassert!(!self.is_empty()); - // BEFORE: - // /----\ next ---> /-----\ next ---> /----\ - // ... |prev| |entry| |next| ... - // \----/ <--- prev \-----/ <--- prev \----/ - // - // AFTER: - // /----\ next ---> /----\ - // ... |prev| |next| ... - // \----/ <--- prev \----/ - let mut prev = entry.prev; - let mut next = entry.next; - prev.as_mut().next = next; - next.as_mut().prev = prev; - entry.next = NonNull::dangling(); - entry.prev = NonNull::dangling(); - } - } - - #[cfg(test)] - mod tests { - use super::*; - use crate::cell::Cell; - - unsafe fn assert_empty(list: &mut UnsafeList) { - assert!(list.pop().is_none(), "assertion failed: list is not empty"); - } - - #[test] - fn init_empty() { - unsafe { - assert_empty(&mut UnsafeList::::new()); - } - } - - #[test] - fn push_pop() { - unsafe { - let mut node = UnsafeListEntry::new(1234); - let mut list = UnsafeList::new(); - assert_eq!(list.push(&mut node), &1234); - assert_eq!(list.pop().unwrap(), &1234); - assert_empty(&mut list); - } - } - - #[test] - fn push_remove() { - unsafe { - let mut node = UnsafeListEntry::new(1234); - let mut list = UnsafeList::new(); - assert_eq!(list.push(&mut node), &1234); - list.remove(&mut node); - assert_empty(&mut list); - } - } - - #[test] - fn push_remove_pop() { - unsafe { - let mut node1 = UnsafeListEntry::new(11); - let mut node2 = UnsafeListEntry::new(12); - let mut node3 = UnsafeListEntry::new(13); - let mut node4 = UnsafeListEntry::new(14); - let mut node5 = UnsafeListEntry::new(15); - let mut list = UnsafeList::new(); - assert_eq!(list.push(&mut node1), &11); - assert_eq!(list.push(&mut node2), &12); - assert_eq!(list.push(&mut node3), &13); - assert_eq!(list.push(&mut node4), &14); - assert_eq!(list.push(&mut node5), &15); - - list.remove(&mut node1); - assert_eq!(list.pop().unwrap(), &12); - list.remove(&mut node3); - assert_eq!(list.pop().unwrap(), &14); - list.remove(&mut node5); - assert_empty(&mut list); - - assert_eq!(list.push(&mut node1), &11); - assert_eq!(list.pop().unwrap(), &11); - assert_empty(&mut list); - - assert_eq!(list.push(&mut node3), &13); - assert_eq!(list.push(&mut node4), &14); - list.remove(&mut node3); - list.remove(&mut node4); - assert_empty(&mut list); - } - } - - #[test] - fn complex_pushes_pops() { - unsafe { - let mut node1 = UnsafeListEntry::new(1234); - let mut node2 = UnsafeListEntry::new(4567); - let mut node3 = UnsafeListEntry::new(9999); - let mut node4 = UnsafeListEntry::new(8642); - let mut list = UnsafeList::new(); - list.push(&mut node1); - list.push(&mut node2); - assert_eq!(list.pop().unwrap(), &1234); - list.push(&mut node3); - assert_eq!(list.pop().unwrap(), &4567); - assert_eq!(list.pop().unwrap(), &9999); - assert_empty(&mut list); - list.push(&mut node4); - assert_eq!(list.pop().unwrap(), &8642); - assert_empty(&mut list); - } - } - - #[test] - fn cell() { - unsafe { - let mut node = UnsafeListEntry::new(Cell::new(0)); - let mut list = UnsafeList::new(); - let noderef = list.push(&mut node); - assert_eq!(noderef.get(), 0); - list.pop().unwrap().set(1); - assert_empty(&mut list); - assert_eq!(noderef.get(), 1); - } - } - } -} - -/// Trivial spinlock-based implementation of `sync::Mutex`. -// FIXME: Perhaps use Intel TSX to avoid locking? -mod spin_mutex { - use crate::cell::UnsafeCell; - use crate::ops::{Deref, DerefMut}; - use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering}; - - #[derive(Default)] - pub struct SpinMutex { - value: UnsafeCell, - lock: AtomicBool, - } - - unsafe impl Send for SpinMutex {} - unsafe impl Sync for SpinMutex {} - - pub struct SpinMutexGuard<'a, T: 'a> { - mutex: &'a SpinMutex, - } - - impl<'a, T> !Send for SpinMutexGuard<'a, T> {} - unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {} - - impl SpinMutex { - pub const fn new(value: T) -> Self { - SpinMutex { value: UnsafeCell::new(value), lock: AtomicBool::new(false) } - } - - #[inline(always)] - pub fn lock(&self) -> SpinMutexGuard<'_, T> { - loop { - match self.try_lock() { - None => { - while self.lock.load(Ordering::Relaxed) { - spin_loop_hint() - } - } - Some(guard) => return guard, - } - } - } - - #[inline(always)] - pub fn try_lock(&self) -> Option> { - if !self.lock.compare_and_swap(false, true, Ordering::Acquire) { - Some(SpinMutexGuard { mutex: self }) - } else { - None - } - } - } - - /// Lock the Mutex or return false. - pub macro try_lock_or_false($e:expr) { - if let Some(v) = $e.try_lock() { v } else { return false } - } - - impl<'a, T> Deref for SpinMutexGuard<'a, T> { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.mutex.value.get() } - } - } - - impl<'a, T> DerefMut for SpinMutexGuard<'a, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.mutex.value.get() } - } - } - - impl<'a, T> Drop for SpinMutexGuard<'a, T> { - fn drop(&mut self) { - self.mutex.lock.store(false, Ordering::Release) - } - } - - #[cfg(test)] - mod tests { - #![allow(deprecated)] - - use super::*; - use crate::sync::Arc; - use crate::thread; - use crate::time::Duration; - - #[test] - fn sleep() { - let mutex = Arc::new(SpinMutex::::default()); - let mutex2 = mutex.clone(); - let guard = mutex.lock(); - let t1 = thread::spawn(move || { - *mutex2.lock() = 1; - }); - - thread::sleep(Duration::from_millis(50)); - - assert_eq!(*guard, 0); - drop(guard); - t1.join().unwrap(); - assert_eq!(*mutex.lock(), 1); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::sync::Arc; - use crate::thread; - - #[test] - fn queue() { - let wq = Arc::new(SpinMutex::>::default()); - let wq2 = wq.clone(); - - let locked = wq.lock(); - - let t1 = thread::spawn(move || { - // if we obtain the lock, the main thread should be waiting - assert!(WaitQueue::notify_one(wq2.lock()).is_ok()); - }); - - WaitQueue::wait(locked, || {}); - - t1.join().unwrap(); - } -} diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs new file mode 100644 index 0000000000..d99ce895da --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs @@ -0,0 +1,76 @@ +#[cfg(test)] +mod tests; + +use crate::cell::UnsafeCell; +use crate::ops::{Deref, DerefMut}; +use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering}; + +#[derive(Default)] +pub struct SpinMutex { + value: UnsafeCell, + lock: AtomicBool, +} + +unsafe impl Send for SpinMutex {} +unsafe impl Sync for SpinMutex {} + +pub struct SpinMutexGuard<'a, T: 'a> { + mutex: &'a SpinMutex, +} + +impl<'a, T> !Send for SpinMutexGuard<'a, T> {} +unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {} + +impl SpinMutex { + pub const fn new(value: T) -> Self { + SpinMutex { value: UnsafeCell::new(value), lock: AtomicBool::new(false) } + } + + #[inline(always)] + pub fn lock(&self) -> SpinMutexGuard<'_, T> { + loop { + match self.try_lock() { + None => { + while self.lock.load(Ordering::Relaxed) { + spin_loop_hint() + } + } + Some(guard) => return guard, + } + } + } + + #[inline(always)] + pub fn try_lock(&self) -> Option> { + if !self.lock.compare_and_swap(false, true, Ordering::Acquire) { + Some(SpinMutexGuard { mutex: self }) + } else { + None + } + } +} + +/// Lock the Mutex or return false. +pub macro try_lock_or_false($e:expr) { + if let Some(v) = $e.try_lock() { v } else { return false } +} + +impl<'a, T> Deref for SpinMutexGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.mutex.value.get() } + } +} + +impl<'a, T> DerefMut for SpinMutexGuard<'a, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.mutex.value.get() } + } +} + +impl<'a, T> Drop for SpinMutexGuard<'a, T> { + fn drop(&mut self) { + self.mutex.lock.store(false, Ordering::Release) + } +} diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs new file mode 100644 index 0000000000..4c5994bea6 --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs @@ -0,0 +1,23 @@ +#![allow(deprecated)] + +use super::*; +use crate::sync::Arc; +use crate::thread; +use crate::time::Duration; + +#[test] +fn sleep() { + let mutex = Arc::new(SpinMutex::::default()); + let mutex2 = mutex.clone(); + let guard = mutex.lock(); + let t1 = thread::spawn(move || { + *mutex2.lock() = 1; + }); + + thread::sleep(Duration::from_millis(50)); + + assert_eq!(*guard, 0); + drop(guard); + t1.join().unwrap(); + assert_eq!(*mutex.lock(), 1); +} diff --git a/library/std/src/sys/sgx/waitqueue/tests.rs b/library/std/src/sys/sgx/waitqueue/tests.rs new file mode 100644 index 0000000000..bf91fdd08e --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/tests.rs @@ -0,0 +1,20 @@ +use super::*; +use crate::sync::Arc; +use crate::thread; + +#[test] +fn queue() { + let wq = Arc::new(SpinMutex::>::default()); + let wq2 = wq.clone(); + + let locked = wq.lock(); + + let t1 = thread::spawn(move || { + // if we obtain the lock, the main thread should be waiting + assert!(WaitQueue::notify_one(wq2.lock()).is_ok()); + }); + + WaitQueue::wait(locked, || {}); + + t1.join().unwrap(); +} diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs new file mode 100644 index 0000000000..7a24654273 --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs @@ -0,0 +1,146 @@ +#[cfg(test)] +mod tests; + +use crate::mem; +use crate::ptr::NonNull; + +pub struct UnsafeListEntry { + next: NonNull>, + prev: NonNull>, + value: Option, +} + +impl UnsafeListEntry { + fn dummy() -> Self { + UnsafeListEntry { next: NonNull::dangling(), prev: NonNull::dangling(), value: None } + } + + pub fn new(value: T) -> Self { + UnsafeListEntry { value: Some(value), ..Self::dummy() } + } +} + +pub struct UnsafeList { + head_tail: NonNull>, + head_tail_entry: Option>, +} + +impl UnsafeList { + pub const fn new() -> Self { + unsafe { UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } } + } + + unsafe fn init(&mut self) { + if self.head_tail_entry.is_none() { + self.head_tail_entry = Some(UnsafeListEntry::dummy()); + self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap()); + self.head_tail.as_mut().next = self.head_tail; + self.head_tail.as_mut().prev = self.head_tail; + } + } + + pub fn is_empty(&self) -> bool { + unsafe { + if self.head_tail_entry.is_some() { + let first = self.head_tail.as_ref().next; + if first == self.head_tail { + // ,-------> /---------\ next ---, + // | |head_tail| | + // `--- prev \---------/ <-------` + rtassert!(self.head_tail.as_ref().prev == first); + true + } else { + false + } + } else { + true + } + } + } + + /// Pushes an entry onto the back of the list. + /// + /// # Safety + /// + /// The entry must remain allocated until the entry is removed from the + /// list AND the caller who popped is done using the entry. Special + /// care must be taken in the caller of `push` to ensure unwinding does + /// not destroy the stack frame containing the entry. + pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry) -> &'a T { + self.init(); + + // BEFORE: + // /---------\ next ---> /---------\ + // ... |prev_tail| |head_tail| ... + // \---------/ <--- prev \---------/ + // + // AFTER: + // /---------\ next ---> /-----\ next ---> /---------\ + // ... |prev_tail| |entry| |head_tail| ... + // \---------/ <--- prev \-----/ <--- prev \---------/ + let mut entry = NonNull::new_unchecked(entry); + let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry); + entry.as_mut().prev = prev_tail; + entry.as_mut().next = self.head_tail; + prev_tail.as_mut().next = entry; + // unwrap ok: always `Some` on non-dummy entries + (*entry.as_ptr()).value.as_ref().unwrap() + } + + /// Pops an entry from the front of the list. + /// + /// # Safety + /// + /// The caller must make sure to synchronize ending the borrow of the + /// return value and deallocation of the containing entry. + pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> { + self.init(); + + if self.is_empty() { + None + } else { + // BEFORE: + // /---------\ next ---> /-----\ next ---> /------\ + // ... |head_tail| |first| |second| ... + // \---------/ <--- prev \-----/ <--- prev \------/ + // + // AFTER: + // /---------\ next ---> /------\ + // ... |head_tail| |second| ... + // \---------/ <--- prev \------/ + let mut first = self.head_tail.as_mut().next; + let mut second = first.as_mut().next; + self.head_tail.as_mut().next = second; + second.as_mut().prev = self.head_tail; + first.as_mut().next = NonNull::dangling(); + first.as_mut().prev = NonNull::dangling(); + // unwrap ok: always `Some` on non-dummy entries + Some((*first.as_ptr()).value.as_ref().unwrap()) + } + } + + /// Removes an entry from the list. + /// + /// # Safety + /// + /// The caller must ensure that `entry` has been pushed onto `self` + /// prior to this call and has not moved since then. + pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry) { + rtassert!(!self.is_empty()); + // BEFORE: + // /----\ next ---> /-----\ next ---> /----\ + // ... |prev| |entry| |next| ... + // \----/ <--- prev \-----/ <--- prev \----/ + // + // AFTER: + // /----\ next ---> /----\ + // ... |prev| |next| ... + // \----/ <--- prev \----/ + let mut prev = entry.prev; + let mut next = entry.next; + prev.as_mut().next = next; + next.as_mut().prev = prev; + entry.next = NonNull::dangling(); + entry.prev = NonNull::dangling(); + } +} diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs new file mode 100644 index 0000000000..1f031ed195 --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs @@ -0,0 +1,103 @@ +use super::*; +use crate::cell::Cell; + +unsafe fn assert_empty(list: &mut UnsafeList) { + assert!(list.pop().is_none(), "assertion failed: list is not empty"); +} + +#[test] +fn init_empty() { + unsafe { + assert_empty(&mut UnsafeList::::new()); + } +} + +#[test] +fn push_pop() { + unsafe { + let mut node = UnsafeListEntry::new(1234); + let mut list = UnsafeList::new(); + assert_eq!(list.push(&mut node), &1234); + assert_eq!(list.pop().unwrap(), &1234); + assert_empty(&mut list); + } +} + +#[test] +fn push_remove() { + unsafe { + let mut node = UnsafeListEntry::new(1234); + let mut list = UnsafeList::new(); + assert_eq!(list.push(&mut node), &1234); + list.remove(&mut node); + assert_empty(&mut list); + } +} + +#[test] +fn push_remove_pop() { + unsafe { + let mut node1 = UnsafeListEntry::new(11); + let mut node2 = UnsafeListEntry::new(12); + let mut node3 = UnsafeListEntry::new(13); + let mut node4 = UnsafeListEntry::new(14); + let mut node5 = UnsafeListEntry::new(15); + let mut list = UnsafeList::new(); + assert_eq!(list.push(&mut node1), &11); + assert_eq!(list.push(&mut node2), &12); + assert_eq!(list.push(&mut node3), &13); + assert_eq!(list.push(&mut node4), &14); + assert_eq!(list.push(&mut node5), &15); + + list.remove(&mut node1); + assert_eq!(list.pop().unwrap(), &12); + list.remove(&mut node3); + assert_eq!(list.pop().unwrap(), &14); + list.remove(&mut node5); + assert_empty(&mut list); + + assert_eq!(list.push(&mut node1), &11); + assert_eq!(list.pop().unwrap(), &11); + assert_empty(&mut list); + + assert_eq!(list.push(&mut node3), &13); + assert_eq!(list.push(&mut node4), &14); + list.remove(&mut node3); + list.remove(&mut node4); + assert_empty(&mut list); + } +} + +#[test] +fn complex_pushes_pops() { + unsafe { + let mut node1 = UnsafeListEntry::new(1234); + let mut node2 = UnsafeListEntry::new(4567); + let mut node3 = UnsafeListEntry::new(9999); + let mut node4 = UnsafeListEntry::new(8642); + let mut list = UnsafeList::new(); + list.push(&mut node1); + list.push(&mut node2); + assert_eq!(list.pop().unwrap(), &1234); + list.push(&mut node3); + assert_eq!(list.pop().unwrap(), &4567); + assert_eq!(list.pop().unwrap(), &9999); + assert_empty(&mut list); + list.push(&mut node4); + assert_eq!(list.pop().unwrap(), &8642); + assert_empty(&mut list); + } +} + +#[test] +fn cell() { + unsafe { + let mut node = UnsafeListEntry::new(Cell::new(0)); + let mut list = UnsafeList::new(); + let noderef = list.push(&mut node); + assert_eq!(noderef.get(), 0); + list.pop().unwrap().set(1); + assert_empty(&mut list); + assert_eq!(noderef.get(), 1); + } +} diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs index 8e19393546..964abe8b8c 100644 --- a/library/std/src/sys/unix/alloc.rs +++ b/library/std/src/sys/unix/alloc.rs @@ -52,46 +52,48 @@ unsafe impl GlobalAlloc for System { } } -#[cfg(any( - target_os = "android", - target_os = "illumos", - target_os = "redox", - target_os = "solaris" -))] -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - // On android we currently target API level 9 which unfortunately - // doesn't have the `posix_memalign` API used below. Instead we use - // `memalign`, but this unfortunately has the property on some systems - // where the memory returned cannot be deallocated by `free`! - // - // Upon closer inspection, however, this appears to work just fine with - // Android, so for this platform we should be fine to call `memalign` - // (which is present in API level 9). Some helpful references could - // possibly be chromium using memalign [1], attempts at documenting that - // memalign + free is ok [2] [3], or the current source of chromium - // which still uses memalign on android [4]. - // - // [1]: https://codereview.chromium.org/10796020/ - // [2]: https://code.google.com/p/android/issues/detail?id=35391 - // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 - // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ - // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut u8 -} - -#[cfg(not(any( - target_os = "android", - target_os = "illumos", - target_os = "redox", - target_os = "solaris" -)))] -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - let mut out = ptr::null_mut(); - // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. - // Since these are all powers of 2, we can just use max. - let align = layout.align().max(crate::mem::size_of::()); - let ret = libc::posix_memalign(&mut out, align, layout.size()); - if ret != 0 { ptr::null_mut() } else { out as *mut u8 } +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "android", + target_os = "illumos", + target_os = "redox", + target_os = "solaris" + ))] { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + // On android we currently target API level 9 which unfortunately + // doesn't have the `posix_memalign` API used below. Instead we use + // `memalign`, but this unfortunately has the property on some systems + // where the memory returned cannot be deallocated by `free`! + // + // Upon closer inspection, however, this appears to work just fine with + // Android, so for this platform we should be fine to call `memalign` + // (which is present in API level 9). Some helpful references could + // possibly be chromium using memalign [1], attempts at documenting that + // memalign + free is ok [2] [3], or the current source of chromium + // which still uses memalign on android [4]. + // + // [1]: https://codereview.chromium.org/10796020/ + // [2]: https://code.google.com/p/android/issues/detail?id=35391 + // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 + // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ + // /memory/aligned_memory.cc + libc::memalign(layout.align(), layout.size()) as *mut u8 + } + } else if #[cfg(target_os = "wasi")] { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + libc::aligned_alloc(layout.align(), layout.size()) as *mut u8 + } + } else { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + let mut out = ptr::null_mut(); + // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. + // Since these are all powers of 2, we can just use max. + let align = layout.align().max(crate::mem::size_of::()); + let ret = libc::posix_memalign(&mut out, align, layout.size()); + if ret != 0 { ptr::null_mut() } else { out as *mut u8 } + } + } } diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index 9bc44a5948..f7c3f16371 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -80,13 +80,13 @@ mod imp { use crate::ptr; use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering}; - use crate::sys_common::mutex::Mutex; + use crate::sys_common::mutex::StaticMutex; static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); // We never call `ENV_LOCK.init()`, so it is UB to attempt to // acquire this mutex reentrantly! - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); unsafe fn really_init(argc: isize, argv: *const *const u8) { let _guard = LOCK.lock(); diff --git a/library/std/src/sys/unix/ext/ffi.rs b/library/std/src/sys/unix/ext/ffi.rs index 76b34a6b5d..123f85deaf 100644 --- a/library/std/src/sys/unix/ext/ffi.rs +++ b/library/std/src/sys/unix/ext/ffi.rs @@ -1,4 +1,4 @@ -//! Unix-specific extension to the primitives in the `std::ffi` module +//! Unix-specific extension to the primitives in the `std::ffi` module. //! //! # Examples //! diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index b590a0280d..4b9f4ceb29 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -8,6 +8,9 @@ use crate::path::Path; use crate::sys; use crate::sys::platform::fs::MetadataExt as UnixMetadataExt; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; +// Used for `File::read` on intra-doc links +#[allow(unused_imports)] +use io::{Read, Write}; /// Unix-specific extensions to [`fs::File`]. #[stable(feature = "file_offset", since = "1.15.0")] @@ -24,7 +27,7 @@ pub trait FileExt { /// Note that similar to [`File::read`], it is not an error to return with a /// short read. /// - /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read + /// [`File::read`]: fs::File::read /// /// # Examples /// @@ -127,7 +130,7 @@ pub trait FileExt { /// Note that similar to [`File::write`], it is not an error to return a /// short write. /// - /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write + /// [`File::write`]: fs::File::write /// /// # Examples /// @@ -425,7 +428,7 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; - /// use std::io; + /// use std::io; /// /// fn main() -> io::Result<()> { /// let meta = fs::metadata("some_file")?; @@ -833,15 +836,6 @@ impl DirEntryExt for fs::DirEntry { /// /// The `dst` path will be a symbolic link pointing to the `src` path. /// -/// # Note -/// -/// On Windows, you must specify whether a symbolic link points to a file -/// or directory. Use `os::windows::fs::symlink_file` to create a -/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a -/// symbolic link to a directory. Additionally, the process must have -/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a -/// symbolic link. -/// /// # Examples /// /// ```no_run diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs index 5077e2e28d..ef3c689bd3 100644 --- a/library/std/src/sys/unix/ext/io.rs +++ b/library/std/src/sys/unix/ext/io.rs @@ -1,4 +1,4 @@ -//! Unix-specific extensions to general I/O primitives +//! Unix-specific extensions to general I/O primitives. #![stable(feature = "rust1", since = "1.0.0")] @@ -25,6 +25,19 @@ pub trait AsRawFd { /// This method does **not** pass ownership of the raw file descriptor /// to the caller. The descriptor is only guaranteed to be valid while /// the original object has not yet been destroyed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::unix::io::{AsRawFd, RawFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// // Note that `raw_fd` is only valid as long as `f` exists. + /// let raw_fd: RawFd = f.as_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_fd(&self) -> RawFd; } @@ -45,6 +58,21 @@ pub trait FromRawFd { /// descriptor they are wrapping. Usage of this function could /// accidentally allow violating this contract which can cause memory /// unsafety in code that relies on it being true. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// // SAFETY: no other functions should call `from_raw_fd`, so there + /// // is only one owner for the file descriptor. + /// let f = unsafe { File::from_raw_fd(raw_fd) }; + /// # Ok::<(), io::Error>(()) + /// ``` #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_fd(fd: RawFd) -> Self; } @@ -58,10 +86,41 @@ pub trait IntoRawFd { /// This function **transfers ownership** of the underlying file descriptor /// to the caller. Callers are then the unique owners of the file descriptor /// and must close the descriptor once it's no longer needed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::unix::io::{IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` #[stable(feature = "into_raw_os", since = "1.4.0")] fn into_raw_fd(self) -> RawFd; } +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl AsRawFd for RawFd { + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl IntoRawFd for RawFd { + fn into_raw_fd(self) -> RawFd { + self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl FromRawFd for RawFd { + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { diff --git a/library/std/src/sys/unix/ext/mod.rs b/library/std/src/sys/unix/ext/mod.rs index cbdb1c1004..f435468809 100644 --- a/library/std/src/sys/unix/ext/mod.rs +++ b/library/std/src/sys/unix/ext/mod.rs @@ -37,6 +37,18 @@ pub mod process; pub mod raw; pub mod thread; +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub mod ucred; + /// A prelude for conveniently writing platform-specific code. /// /// Includes all extension traits, and some important type definitions. diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index 55803ddfc4..3d2366554b 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -1,6 +1,9 @@ +//! Unix-specific networking functionality. + #![stable(feature = "unix_socket", since = "1.10.0")] -//! Unix-specific networking functionality +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] @@ -27,6 +30,29 @@ use crate::sys::{self, cvt}; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; use crate::time::Duration; +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +use crate::os::unix::ucred; + +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use ucred::UCred; + #[cfg(any( target_os = "linux", target_os = "android", @@ -402,6 +428,34 @@ impl UnixStream { SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) } + /// Gets the peer credentials for this Unix domain socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peer_credentials_unix_socket)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" + ))] + pub fn peer_cred(&self) -> io::Result { + ucred::peer_cred(self) + } + /// Sets the read timeout for the socket. /// /// If the provided value is [`None`], then [`read`] calls will block @@ -591,6 +645,32 @@ impl UnixStream { pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.0.shutdown(how) } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } } #[stable(feature = "unix_socket", since = "1.10.0")] @@ -1288,6 +1368,33 @@ impl UnixDatagram { SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) } + fn recv_from_flags( + &self, + buf: &mut [u8], + flags: libc::c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut count = 0; + let addr = SocketAddr::new(|addr, len| unsafe { + count = libc::recvfrom( + *self.0.as_inner(), + buf.as_mut_ptr() as *mut _, + buf.len(), + flags, + addr, + len, + ); + if count > 0 { + 1 + } else if count == 0 { + 0 + } else { + -1 + } + })?; + + Ok((count as usize, addr)) + } + /// Receives data from the socket. /// /// On success, returns the number of bytes read and the address from @@ -1308,26 +1415,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - let mut count = 0; - let addr = SocketAddr::new(|addr, len| unsafe { - count = libc::recvfrom( - *self.0.as_inner(), - buf.as_mut_ptr() as *mut _, - buf.len(), - 0, - addr, - len, - ); - if count > 0 { - 1 - } else if count == 0 { - 0 - } else { - -1 - } - })?; - - Ok((count as usize, addr)) + self.recv_from_flags(buf, 0) } /// Receives data from the socket. @@ -1598,6 +1686,64 @@ impl UnixDatagram { pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.0.shutdown(how) } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives a single datagram message on the socket, without removing it from the + /// queue. On success, returns the number of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, libc::MSG_PEEK) + } } #[stable(feature = "unix_socket", since = "1.10.0")] @@ -1620,382 +1766,3 @@ impl IntoRawFd for UnixDatagram { self.0.into_inner() } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod test { - use crate::io::prelude::*; - use crate::io::{self, ErrorKind}; - use crate::sys_common::io::test::tmpdir; - use crate::thread; - use crate::time::Duration; - - use super::*; - - macro_rules! or_panic { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{}", e), - } - }; - } - - #[test] - fn basic() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world!"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - let mut buf = [0; 5]; - or_panic!(stream.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(stream.write_all(msg2)); - }); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname()); - or_panic!(stream.write_all(msg1)); - let mut buf = vec![]; - or_panic!(stream.read_to_end(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(stream); - - thread.join().unwrap(); - } - - #[test] - fn vectored() { - let (mut s1, mut s2) = or_panic!(UnixStream::pair()); - - let len = or_panic!(s1.write_vectored(&[ - IoSlice::new(b"hello"), - IoSlice::new(b" "), - IoSlice::new(b"world!") - ],)); - assert_eq!(len, 12); - - let mut buf1 = [0; 6]; - let mut buf2 = [0; 7]; - let len = or_panic!( - s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) - ); - assert_eq!(len, 12); - assert_eq!(&buf1, b"hello "); - assert_eq!(&buf2, b"world!\0"); - } - - #[test] - fn pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (mut s1, mut s2) = or_panic!(UnixStream::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.write_all(msg2)); - }); - - or_panic!(s2.write_all(msg1)); - let mut buf = vec![]; - or_panic!(s2.read_to_end(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); - } - - #[test] - fn try_clone() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - or_panic!(stream.write_all(msg1)); - or_panic!(stream.write_all(msg2)); - }); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - let mut stream2 = or_panic!(stream.try_clone()); - - let mut buf = [0; 5]; - or_panic!(stream.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(stream2.read(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - - thread.join().unwrap(); - } - - #[test] - fn iter() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - for stream in listener.incoming().take(2) { - let mut stream = or_panic!(stream); - let mut buf = [0]; - or_panic!(stream.read(&mut buf)); - } - }); - - for _ in 0..2 { - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.write_all(&[0])); - } - - thread.join().unwrap(); - } - - #[test] - fn long_path() { - let dir = tmpdir(); - let socket_path = dir.path().join( - "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ - sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf", - ); - match UnixStream::connect(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixListener::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixDatagram::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - } - - #[test] - fn timeouts() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let stream = or_panic!(UnixStream::connect(&socket_path)); - let dur = Duration::new(15410, 0); - - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.read_timeout())); - - assert_eq!(None, or_panic!(stream.write_timeout())); - - or_panic!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.write_timeout())); - - or_panic!(stream.set_read_timeout(None)); - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_write_timeout(None)); - assert_eq!(None, or_panic!(stream.write_timeout())); - } - - #[test] - fn test_read_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - } - - #[test] - fn test_read_with_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut other_end = or_panic!(listener.accept()).0; - or_panic!(other_end.write_all(b"hello world")); - - let mut buf = [0; 11]; - or_panic!(stream.read(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_unix_stream_timeout_zero_duration() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let stream = or_panic!(UnixStream::connect(&socket_path)); - - let result = stream.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = stream.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - drop(listener); - } - - #[test] - fn test_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::bind(&path2)); - - let msg = b"hello world"; - or_panic!(sock1.send_to(msg, &path2)); - let mut buf = [0; 11]; - or_panic!(sock2.recv_from(&mut buf)); - assert_eq!(msg, &buf[..]); - } - - #[test] - fn test_unnamed_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - - let msg = b"hello world"; - or_panic!(sock2.send_to(msg, &path1)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); - } - - #[test] - fn test_connect_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let bsock1 = or_panic!(UnixDatagram::bind(&path1)); - let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - let sock = or_panic!(UnixDatagram::unbound()); - or_panic!(sock.connect(&path1)); - - // Check send() - let msg = b"hello there"; - or_panic!(sock.send(msg)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); - - // Changing default socket works too - or_panic!(sock.connect(&path2)); - or_panic!(sock.send(msg)); - or_panic!(bsock2.recv_from(&mut buf)); - } - - #[test] - fn test_unix_datagram_recv() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - or_panic!(sock2.connect(&path1)); - - let msg = b"hello world"; - or_panic!(sock2.send(msg)); - let mut buf = [0; 11]; - let size = or_panic!(sock1.recv(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); - } - - #[test] - fn datagram_pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (s1, s2) = or_panic!(UnixDatagram::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.recv(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.send(msg2)); - }); - - or_panic!(s2.send(msg1)); - let mut buf = [0; 6]; - or_panic!(s2.recv(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_unix_datagram_timeout_zero_duration() { - let dir = tmpdir(); - let path = dir.path().join("sock"); - - let datagram = or_panic!(UnixDatagram::bind(&path)); - - let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - } - - #[test] - fn abstract_namespace_not_allowed() { - assert!(UnixStream::connect("\0asdf").is_err()); - } -} diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs new file mode 100644 index 0000000000..ee73a6ed53 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -0,0 +1,454 @@ +use crate::io::prelude::*; +use crate::io::{self, ErrorKind}; +use crate::sys_common::io::test::tmpdir; +use crate::thread; +use crate::time::Duration; + +use super::*; + +macro_rules! or_panic { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{}", e), + } + }; +} + +#[test] +fn basic() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + let msg1 = b"hello"; + let msg2 = b"world!"; + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream.write_all(msg2)); + }); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname()); + or_panic!(stream.write_all(msg1)); + let mut buf = vec![]; + or_panic!(stream.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(stream); + + thread.join().unwrap(); +} + +#[test] +fn vectored() { + let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + + let len = or_panic!(s1.write_vectored(&[ + IoSlice::new(b"hello"), + IoSlice::new(b" "), + IoSlice::new(b"world!") + ],)); + assert_eq!(len, 12); + + let mut buf1 = [0; 6]; + let mut buf2 = [0; 7]; + let len = + or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)); + assert_eq!(len, 12); + assert_eq!(&buf1, b"hello "); + assert_eq!(&buf2, b"world!\0"); +} + +#[test] +fn pair() { + let msg1 = b"hello"; + let msg2 = b"world!"; + + let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + let thread = thread::spawn(move || { + // s1 must be moved in or the test will hang! + let mut buf = [0; 5]; + or_panic!(s1.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(s1.write_all(msg2)); + }); + + or_panic!(s2.write_all(msg1)); + let mut buf = vec![]; + or_panic!(s2.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(s2); + + thread.join().unwrap(); +} + +#[test] +fn try_clone() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + let msg1 = b"hello"; + let msg2 = b"world"; + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + or_panic!(stream.write_all(msg1)); + or_panic!(stream.write_all(msg2)); + }); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + let mut stream2 = or_panic!(stream.try_clone()); + + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream2.read(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + + thread.join().unwrap(); +} + +#[test] +fn iter() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + for stream in listener.incoming().take(2) { + let mut stream = or_panic!(stream); + let mut buf = [0]; + or_panic!(stream.read(&mut buf)); + } + }); + + for _ in 0..2 { + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.write_all(&[0])); + } + + thread.join().unwrap(); +} + +#[test] +fn long_path() { + let dir = tmpdir(); + let socket_path = dir.path().join( + "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ + sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf", + ); + match UnixStream::connect(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } + + match UnixListener::bind(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } + + match UnixDatagram::bind(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } +} + +#[test] +fn timeouts() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let stream = or_panic!(UnixStream::connect(&socket_path)); + let dur = Duration::new(15410, 0); + + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.read_timeout())); + + assert_eq!(None, or_panic!(stream.write_timeout())); + + or_panic!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.write_timeout())); + + or_panic!(stream.set_read_timeout(None)); + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_write_timeout(None)); + assert_eq!(None, or_panic!(stream.write_timeout())); +} + +#[test] +fn test_read_timeout() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); +} + +#[test] +fn test_read_with_timeout() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut other_end = or_panic!(listener.accept()).0; + or_panic!(other_end.write_all(b"hello world")); + + let mut buf = [0; 11]; + or_panic!(stream.read(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_unix_stream_timeout_zero_duration() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let stream = or_panic!(UnixStream::connect(&socket_path)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); +} + +#[test] +fn test_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::bind(&path2)); + + let msg = b"hello world"; + or_panic!(sock1.send_to(msg, &path2)); + let mut buf = [0; 11]; + or_panic!(sock2.recv_from(&mut buf)); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_unnamed_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + + let msg = b"hello world"; + or_panic!(sock2.send_to(msg, &path1)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert!(addr.is_unnamed()); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_connect_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + let sock = or_panic!(UnixDatagram::unbound()); + or_panic!(sock.connect(&path1)); + + // Check send() + let msg = b"hello there"; + or_panic!(sock.send(msg)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert!(addr.is_unnamed()); + assert_eq!(msg, &buf[..]); + + // Changing default socket works too + or_panic!(sock.connect(&path2)); + or_panic!(sock.send(msg)); + or_panic!(bsock2.recv_from(&mut buf)); +} + +#[test] +fn test_unix_datagram_recv() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn datagram_pair() { + let msg1 = b"hello"; + let msg2 = b"world!"; + + let (s1, s2) = or_panic!(UnixDatagram::pair()); + let thread = thread::spawn(move || { + // s1 must be moved in or the test will hang! + let mut buf = [0; 5]; + or_panic!(s1.recv(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(s1.send(msg2)); + }); + + or_panic!(s2.send(msg1)); + let mut buf = [0; 6]; + or_panic!(s2.recv(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(s2); + + thread.join().unwrap(); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_unix_datagram_timeout_zero_duration() { + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let datagram = or_panic!(UnixDatagram::bind(&path)); + + let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); +} + +#[test] +fn abstract_namespace_not_allowed() { + assert!(UnixStream::connect("\0asdf").is_err()); +} + +#[test] +fn test_unix_stream_peek() { + let (txdone, rxdone) = crate::sync::mpsc::channel(); + + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + or_panic!(stream.write_all(&[1, 3, 3, 7])); + or_panic!(rxdone.recv()); + }); + + let mut stream = or_panic!(UnixStream::connect(&path)); + let mut buf = [0; 10]; + for _ in 0..2 { + assert_eq!(or_panic!(stream.peek(&mut buf)), 4); + } + assert_eq!(or_panic!(stream.read(&mut buf)), 4); + + or_panic!(stream.set_nonblocking(true)); + match stream.peek(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error: {}", e), + } + + or_panic!(txdone.send(())); + thread.join().unwrap(); +} + +#[test] +fn test_unix_datagram_peek() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let size = or_panic!(sock1.peek(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_unix_datagram_peek_from() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let (size, _) = or_panic!(sock1.peek_from(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} diff --git a/library/std/src/sys/unix/ext/raw.rs b/library/std/src/sys/unix/ext/raw.rs index 40fa53d484..3199a0bff0 100644 --- a/library/std/src/sys/unix/ext/raw.rs +++ b/library/std/src/sys/unix/ext/raw.rs @@ -1,4 +1,4 @@ -//! Unix-specific primitives available on all unix platforms +//! Unix-specific primitives available on all unix platforms. #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated( diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs new file mode 100644 index 0000000000..ed7516c7f2 --- /dev/null +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -0,0 +1,97 @@ +//! Unix peer credentials. + +// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on +// GitHub. +// +// For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13 +// Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work. + +use libc::{gid_t, pid_t, uid_t}; + +/// Credentials for a UNIX process for credentials passing. +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct UCred { + /// The UID part of the peer credential. This is the effective UID of the process at the domain + /// socket's endpoint. + pub uid: uid_t, + /// The GID part of the peer credential. This is the effective GID of the process at the domain + /// socket's endpoint. + pub gid: gid_t, + /// The PID part of the peer credential. This field is optional because the PID part of the + /// peer credentials is not supported on every platform. On platforms where the mechanism to + /// discover the PID exists, this field will be populated to the PID of the process at the + /// domain socket's endpoint. Otherwise, it will be set to None. + pub pid: Option, +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use self::impl_linux::peer_cred; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use self::impl_bsd::peer_cred; + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub mod impl_linux { + use super::UCred; + use crate::os::unix::io::AsRawFd; + use crate::os::unix::net::UnixStream; + use crate::{io, mem}; + use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED}; + + pub fn peer_cred(socket: &UnixStream) -> io::Result { + let ucred_size = mem::size_of::(); + + // Trivial sanity checks. + assert!(mem::size_of::() <= mem::size_of::()); + assert!(ucred_size <= u32::MAX as usize); + + let mut ucred_size = ucred_size as socklen_t; + let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 }; + + unsafe { + let ret = getsockopt( + socket.as_raw_fd(), + SOL_SOCKET, + SO_PEERCRED, + &mut ucred as *mut ucred as *mut c_void, + &mut ucred_size, + ); + + if ret == 0 && ucred_size as usize == mem::size_of::() { + Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) }) + } else { + Err(io::Error::last_os_error()) + } + } + } +} + +#[cfg(any( + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "openbsd" +))] +pub mod impl_bsd { + use super::UCred; + use crate::io; + use crate::os::unix::io::AsRawFd; + use crate::os::unix::net::UnixStream; + + pub fn peer_cred(socket: &UnixStream) -> io::Result { + let mut cred = UCred { uid: 1, gid: 1, pid: None }; + unsafe { + let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid); + + if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) } + } + } +} diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/sys/unix/ext/ucred/tests.rs new file mode 100644 index 0000000000..451b534b26 --- /dev/null +++ b/library/std/src/sys/unix/ext/ucred/tests.rs @@ -0,0 +1,25 @@ +use crate::os::unix::net::UnixStream; +use libc::{getegid, geteuid}; + +#[test] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +fn test_socket_pair() { + // Create two connected sockets and get their peer credentials. They should be equal. + let (sock_a, sock_b) = UnixStream::pair().unwrap(); + let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap()); + assert_eq!(cred_a, cred_b); + + // Check that the UID and GIDs match up. + let uid = unsafe { geteuid() }; + let gid = unsafe { getegid() }; + assert_eq!(cred_a.uid, uid); + assert_eq!(cred_a.gid, gid); +} diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index ba169b251b..2224a055d6 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -1,10 +1,11 @@ #![unstable(reason = "not public", issue = "none", feature = "fd")] +#[cfg(test)] +mod tests; + use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; use crate::mem; -#[cfg(not(any(target_os = "redox", target_env = "newlib")))] -use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::cvt; use crate::sys_common::AsInner; @@ -28,24 +29,35 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1; #[cfg(not(target_os = "macos"))] const READ_LIMIT: usize = libc::ssize_t::MAX as usize; -#[cfg(not(any(target_os = "redox", target_env = "newlib")))] -fn max_iov() -> usize { - static LIM: AtomicUsize = AtomicUsize::new(0); - - let mut lim = LIM.load(Ordering::Relaxed); - if lim == 0 { - let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) }; - - // 16 is the minimum value required by POSIX. - lim = if ret > 0 { ret as usize } else { 16 }; - LIM.store(lim, Ordering::Relaxed); - } +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +const fn max_iov() -> usize { + libc::IOV_MAX as usize +} - lim +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] +const fn max_iov() -> usize { + libc::UIO_MAXIOV as usize } -#[cfg(any(target_os = "redox", target_env = "newlib"))] -fn max_iov() -> usize { +#[cfg(not(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +)))] +const fn max_iov() -> usize { 16 // The minimum value required by POSIX. } @@ -279,16 +291,3 @@ impl Drop for FileDesc { let _ = unsafe { libc::close(self.fd) }; } } - -#[cfg(test)] -mod tests { - use super::{FileDesc, IoSlice}; - use core::mem::ManuallyDrop; - - #[test] - fn limit_vector_count() { - let stdout = ManuallyDrop::new(FileDesc { fd: 1 }); - let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); - assert!(stdout.write_vectored(&bufs).is_ok()); - } -} diff --git a/library/std/src/sys/unix/fd/tests.rs b/library/std/src/sys/unix/fd/tests.rs new file mode 100644 index 0000000000..a932043cbc --- /dev/null +++ b/library/std/src/sys/unix/fd/tests.rs @@ -0,0 +1,9 @@ +use super::{FileDesc, IoSlice}; +use core::mem::ManuallyDrop; + +#[test] +fn limit_vector_count() { + let stdout = ManuallyDrop::new(FileDesc { fd: 1 }); + let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); + assert!(stdout.write_vectored(&bufs).is_ok()); +} diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index acb18e6d06..566ac0920d 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1140,14 +1140,14 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } let (mut reader, reader_metadata) = open_from(from)?; - let len = reader_metadata.len(); + let max_len = u64::MAX; let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); let mut written = 0u64; - while written < len { + while written < max_len { let copy_result = if has_copy_file_range { - let bytes_to_copy = cmp::min(len - written, usize::MAX as u64) as usize; + let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64) as usize; let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically @@ -1162,7 +1162,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { }; if let Err(ref copy_err) = copy_result { match copy_err.raw_os_error() { - Some(libc::ENOSYS) | Some(libc::EPERM) => { + Some(libc::ENOSYS | libc::EPERM | libc::EOPNOTSUPP) => { HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); } _ => {} @@ -1173,18 +1173,25 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { Err(io::Error::from_raw_os_error(libc::ENOSYS)) }; match copy_result { + Ok(0) if written == 0 => { + // fallback to work around several kernel bugs where copy_file_range will fail to + // copy any bytes and return 0 instead of an error if + // - reading virtual files from the proc filesystem which appear to have 0 size + // but are not empty. noted in coreutils to affect kernels at least up to 5.6.19. + // - copying from an overlay filesystem in docker. reported to occur on fedora 32. + return io::copy(&mut reader, &mut writer); + } + Ok(0) => return Ok(written), // reached EOF Ok(ret) => written += ret as u64, Err(err) => { match err.raw_os_error() { - Some(os_err) - if os_err == libc::ENOSYS - || os_err == libc::EXDEV - || os_err == libc::EINVAL - || os_err == libc::EPERM => - { + Some( + libc::ENOSYS | libc::EXDEV | libc::EINVAL | libc::EPERM | libc::EOPNOTSUPP, + ) => { // Try fallback io::copy if either: // - Kernel version is < 4.5 (ENOSYS) // - Files are mounted on different fs (EXDEV) + // - copy_file_range is broken in various ways on RHEL/CentOS 7 (EOPNOTSUPP) // - copy_file_range is disallowed, for example by seccomp (EPERM) // - copy_file_range cannot be used with pipes or device nodes (EINVAL) assert_eq!(written, 0); diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs new file mode 100644 index 0000000000..e6f0c48c59 --- /dev/null +++ b/library/std/src/sys/unix/futex.rs @@ -0,0 +1,37 @@ +#![cfg(any(target_os = "linux", target_os = "android"))] + +use crate::convert::TryInto; +use crate::ptr::null; +use crate::sync::atomic::AtomicI32; +use crate::time::Duration; + +pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option) { + let timespec = timeout.and_then(|d| { + Some(libc::timespec { + // Sleep forever if the timeout is longer than fits in a timespec. + tv_sec: d.as_secs().try_into().ok()?, + // This conversion never truncates, as subsec_nanos is always <1e9. + tv_nsec: d.subsec_nanos() as _, + }) + }); + unsafe { + libc::syscall( + libc::SYS_futex, + futex as *const AtomicI32, + libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG, + expected, + timespec.as_ref().map_or(null(), |d| d as *const libc::timespec), + ); + } +} + +pub fn futex_wake(futex: &AtomicI32) { + unsafe { + libc::syscall( + libc::SYS_futex, + futex as *const AtomicI32, + libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG, + 1, + ); + } +} diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index eddf00d397..776f4f18ec 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -49,6 +49,7 @@ pub mod env; pub mod ext; pub mod fd; pub mod fs; +pub mod futex; pub mod io; #[cfg(target_os = "l4re")] mod l4re; @@ -75,6 +76,13 @@ pub use crate::sys_common::os_str_bytes as os_str; #[cfg(not(test))] pub fn init() { + // 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. + unsafe { + sanitize_standard_fds(); + } + // By default, some platforms will send a *signal* when an EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE // handler, causing it to kill the program, which isn't exactly what we @@ -86,6 +94,62 @@ pub fn init() { reset_sigpipe(); } + cfg_if::cfg_if! { + if #[cfg(miri)] { + // The standard fds are always available in Miri. + unsafe fn sanitize_standard_fds() {} + } else if #[cfg(not(any( + target_os = "emscripten", + target_os = "fuchsia", + // The poll on Darwin doesn't set POLLNVAL for closed fds. + target_os = "macos", + target_os = "ios", + target_os = "redox", + )))] { + // In the case when all file descriptors are open, the poll has been + // observed to perform better than fcntl (on GNU/Linux). + unsafe fn sanitize_standard_fds() { + use crate::sys::os::errno; + let pfds: &mut [_] = &mut [ + libc::pollfd { fd: 0, events: 0, revents: 0 }, + libc::pollfd { fd: 1, events: 0, revents: 0 }, + libc::pollfd { fd: 2, events: 0, revents: 0 }, + ]; + while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 { + if errno() == libc::EINTR { + continue; + } + libc::abort(); + } + for pfd in pfds { + if pfd.revents & libc::POLLNVAL == 0 { + continue; + } + if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + // If the stream is closed but we failed to reopen it, abort the + // process. Otherwise we wouldn't preserve the safety of + // operations on the corresponding Rust object Stdin, Stdout, or + // Stderr. + libc::abort(); + } + } + } + } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] { + unsafe fn sanitize_standard_fds() { + use crate::sys::os::errno; + for fd in 0..3 { + if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { + if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + libc::abort(); + } + } + } + } + } else { + unsafe fn sanitize_standard_fds() {} + } + } + #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 2fcb5b9c4e..c9f9ed01e1 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -2,6 +2,9 @@ #![allow(unused_imports)] // lots of cfg code here +#[cfg(all(test, target_env = "gnu"))] +mod tests; + use crate::os::unix::prelude::*; use crate::error::Error as StdError; @@ -18,7 +21,7 @@ use crate::slice; use crate::str; use crate::sys::cvt; use crate::sys::fd; -use crate::sys_common::mutex::{Mutex, MutexGuard}; +use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; use crate::vec; use libc::{c_char, c_int, c_void}; @@ -467,10 +470,9 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> MutexGuard<'static> { - // We never call `ENV_LOCK.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static ENV_LOCK: Mutex = Mutex::new(); +pub unsafe fn env_lock() -> StaticMutexGuard<'static> { + // It is UB to attempt to acquire this mutex reentrantly! + static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() } @@ -645,30 +647,3 @@ fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { _ => None, } } - -#[cfg(all(test, target_env = "gnu"))] -mod test { - use super::*; - - #[test] - fn test_glibc_version() { - // This mostly just tests that the weak linkage doesn't panic wildly... - glibc_version(); - } - - #[test] - fn test_parse_glibc_version() { - let cases = [ - ("0.0", Some((0, 0))), - ("01.+2", Some((1, 2))), - ("3.4.5.six", Some((3, 4))), - ("1", None), - ("1.-2", None), - ("1.foo", None), - ("foo.1", None), - ]; - for &(version_str, parsed) in cases.iter() { - assert_eq!(parsed, parse_glibc_version(version_str)); - } - } -} diff --git a/library/std/src/sys/unix/os/tests.rs b/library/std/src/sys/unix/os/tests.rs new file mode 100644 index 0000000000..0e1dcb390a --- /dev/null +++ b/library/std/src/sys/unix/os/tests.rs @@ -0,0 +1,23 @@ +use super::*; + +#[test] +fn test_glibc_version() { + // This mostly just tests that the weak linkage doesn't panic wildly... + glibc_version(); +} + +#[test] +fn test_parse_glibc_version() { + let cases = [ + ("0.0", Some((0, 0))), + ("01.+2", Some((1, 2))), + ("3.4.5.six", Some((3, 4))), + ("1", None), + ("1.-2", None), + ("1.foo", None), + ("foo.1", None), + ]; + for &(version_str, parsed) in cases.iter() { + assert_eq!(parsed, parse_glibc_version(version_str)); + } +} diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index 553e980f08..1b7b93f9d4 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -1,6 +1,7 @@ -pub use self::process_common::{Command, ExitCode, Stdio, StdioPipes}; +pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::{ExitStatus, Process}; pub use crate::ffi::OsString as EnvKey; +pub use crate::sys_common::process::CommandEnvs; mod process_common; #[cfg(not(target_os = "fuchsia"))] diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 6e33cdd3c4..9ddd4ad400 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -1,14 +1,18 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::os::unix::prelude::*; use crate::collections::BTreeMap; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io; +use crate::path::Path; use crate::ptr; use crate::sys::fd::FileDesc; use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; @@ -181,11 +185,30 @@ impl Command { pub fn saw_nul(&self) -> bool { self.saw_nul } + + pub fn get_program(&self) -> &OsStr { + OsStr::from_bytes(self.program.as_bytes()) + } + + pub fn get_args(&self) -> CommandArgs<'_> { + let mut iter = self.args.iter(); + iter.next(); + CommandArgs { iter } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes()))) + } + pub fn get_argv(&self) -> &Vec<*const c_char> { &self.argv.0 } - pub fn get_program(&self) -> &CStr { + pub fn get_program_cstr(&self) -> &CStr { &*self.program } @@ -400,70 +423,31 @@ impl ExitCode { } } -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::*; - - use crate::ffi::OsStr; - use crate::mem; - use crate::ptr; - use crate::sys::cvt; - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - }; +pub struct CommandArgs<'a> { + iter: crate::slice::Iter<'a, CString>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes())) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() } +} - // See #14232 for more information, but it appears that signal delivery to a - // newly spawned process may just be raced in the macOS, so to prevent this - // test from being flaky we ignore it on macOS. - #[test] - #[cfg_attr(target_os = "macos", ignore)] - // When run under our current QEMU emulation test suite this test fails, - // although the reason isn't very clear as to why. For now this test is - // ignored there. - #[cfg_attr(target_arch = "arm", ignore)] - #[cfg_attr(target_arch = "aarch64", ignore)] - #[cfg_attr(target_arch = "riscv64", ignore)] - fn test_process_mask() { - unsafe { - // Test to make sure that a signal mask does not get inherited. - let mut cmd = Command::new(OsStr::new("cat")); - - let mut set = mem::MaybeUninit::::uninit(); - let mut old_set = mem::MaybeUninit::::uninit(); - t!(cvt(sigemptyset(set.as_mut_ptr()))); - t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT))); - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr()))); - - cmd.stdin(Stdio::MakePipe); - cmd.stdout(Stdio::MakePipe); - - let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true)); - let stdin_write = pipes.stdin.take().unwrap(); - let stdout_read = pipes.stdout.take().unwrap(); - - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut()))); - - t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT))); - // We need to wait until SIGINT is definitely delivered. The - // easiest way is to write something to cat, and try to read it - // back: if SIGINT is unmasked, it'll get delivered when cat is - // next scheduled. - let _ = stdin_write.write(b"Hello"); - drop(stdin_write); - - // Either EOF or failure (EPIPE) is okay. - let mut buf = [0; 5]; - if let Ok(ret) = stdout_read.read(&mut buf) { - assert_eq!(ret, 0); - } +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} - t!(cat.wait()); - } +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.clone()).finish() } } diff --git a/library/std/src/sys/unix/process/process_common/tests.rs b/library/std/src/sys/unix/process/process_common/tests.rs new file mode 100644 index 0000000000..e72fbf0beb --- /dev/null +++ b/library/std/src/sys/unix/process/process_common/tests.rs @@ -0,0 +1,64 @@ +use super::*; + +use crate::ffi::OsStr; +use crate::mem; +use crate::ptr; +use crate::sys::cvt; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + }; +} + +// See #14232 for more information, but it appears that signal delivery to a +// newly spawned process may just be raced in the macOS, so to prevent this +// test from being flaky we ignore it on macOS. +#[test] +#[cfg_attr(target_os = "macos", ignore)] +// When run under our current QEMU emulation test suite this test fails, +// although the reason isn't very clear as to why. For now this test is +// ignored there. +#[cfg_attr(target_arch = "arm", ignore)] +#[cfg_attr(target_arch = "aarch64", ignore)] +#[cfg_attr(target_arch = "riscv64", ignore)] +fn test_process_mask() { + unsafe { + // Test to make sure that a signal mask does not get inherited. + let mut cmd = Command::new(OsStr::new("cat")); + + let mut set = mem::MaybeUninit::::uninit(); + let mut old_set = mem::MaybeUninit::::uninit(); + t!(cvt(sigemptyset(set.as_mut_ptr()))); + t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT))); + t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr()))); + + cmd.stdin(Stdio::MakePipe); + cmd.stdout(Stdio::MakePipe); + + let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true)); + let stdin_write = pipes.stdin.take().unwrap(); + let stdout_read = pipes.stdout.take().unwrap(); + + t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut()))); + + t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT))); + // We need to wait until SIGINT is definitely delivered. The + // easiest way is to write something to cat, and try to read it + // back: if SIGINT is unmasked, it'll get delivered when cat is + // next scheduled. + let _ = stdin_write.write(b"Hello"); + drop(stdin_write); + + // Either EOF or failure (EPIPE) is okay. + let mut buf = [0; 5]; + if let Ok(ret) = stdout_read.read(&mut buf) { + assert_eq!(ret, 0); + } + + t!(cat.wait()); + } +} diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index 6daf2885ba..b64636c3f3 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -118,8 +118,9 @@ impl Command { FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE - | FDIO_SPAWN_CLONE_ENVIRON, // this is ignored when envp is non-null - self.get_program().as_ptr(), + | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null + | FDIO_SPAWN_CLONE_UTC_CLOCK, + self.get_program_cstr().as_ptr(), self.get_argv().as_ptr(), envp, actions.len() as size_t, diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 0f349dfa30..32f456266c 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -67,7 +67,7 @@ impl Command { // pipe I/O up to PIPE_BUF bytes should be atomic, and then // we want to be sure we *don't* run at_exit destructors as // we're being torn down regardless - assert!(output.write(&bytes).is_ok()); + rtassert!(output.write(&bytes).is_ok()); libc::_exit(1) } n => n, @@ -245,14 +245,15 @@ impl Command { *sys::os::environ() = envp.as_ptr(); } - libc::execvp(self.get_program().as_ptr(), self.get_argv().as_ptr()); + libc::execvp(self.get_program_cstr().as_ptr(), self.get_argv().as_ptr()); Err(io::Error::last_os_error()) } #[cfg(not(any( target_os = "macos", target_os = "freebsd", - all(target_os = "linux", target_env = "gnu") + all(target_os = "linux", target_env = "gnu"), + all(target_os = "linux", target_env = "musl"), )))] fn posix_spawn( &mut self, @@ -267,7 +268,8 @@ impl Command { #[cfg(any( target_os = "macos", target_os = "freebsd", - all(target_os = "linux", target_env = "gnu") + all(target_os = "linux", target_env = "gnu"), + all(target_os = "linux", target_env = "musl"), ))] fn posix_spawn( &mut self, @@ -297,10 +299,10 @@ impl Command { } } - // Solaris and glibc 2.29+ can set a new working directory, and maybe - // others will gain this non-POSIX function too. We'll check for this - // weak symbol as soon as it's needed, so we can return early otherwise - // to do a manual chdir before exec. + // Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory, + // and maybe others will gain this non-POSIX function too. We'll check + // for this weak symbol as soon as it's needed, so we can return early + // otherwise to do a manual chdir before exec. weak! { fn posix_spawn_file_actions_addchdir_np( *mut libc::posix_spawn_file_actions_t, @@ -383,7 +385,7 @@ impl Command { let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); let ret = libc::posix_spawnp( &mut p.pid, - self.get_program().as_ptr(), + self.get_program_cstr().as_ptr(), file_actions.0.as_ptr(), attrs.0.as_ptr(), self.get_argv().as_ptr() as *const _, @@ -459,7 +461,15 @@ impl ExitStatus { } fn exited(&self) -> bool { - unsafe { libc::WIFEXITED(self.0) } + // On Linux-like OSes this function is safe, on others it is not. See + // libc issue: https://github.com/rust-lang/libc/issues/1888. + #[cfg_attr( + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + allow(unused_unsafe) + )] + unsafe { + libc::WIFEXITED(self.0) + } } pub fn success(&self) -> bool { @@ -467,10 +477,22 @@ impl ExitStatus { } pub fn code(&self) -> Option { + // On Linux-like OSes this function is safe, on others it is not. See + // libc issue: https://github.com/rust-lang/libc/issues/1888. + #[cfg_attr( + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + allow(unused_unsafe) + )] if self.exited() { Some(unsafe { libc::WEXITSTATUS(self.0) }) } else { None } } pub fn signal(&self) -> Option { + // On Linux-like OSes this function is safe, on others it is not. See + // libc issue: https://github.com/rust-lang/libc/issues/1888. + #[cfg_attr( + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + allow(unused_unsafe) + )] if !self.exited() { Some(unsafe { libc::WTERMSIG(self.0) }) } else { None } } } diff --git a/library/std/src/sys/unix/process/zircon.rs b/library/std/src/sys/unix/process/zircon.rs index 750b8f0762..69ec275c2b 100644 --- a/library/std/src/sys/unix/process/zircon.rs +++ b/library/std/src/sys/unix/process/zircon.rs @@ -138,6 +138,7 @@ pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002; pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004; pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008; pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010; +pub const FDIO_SPAWN_CLONE_UTC_CLOCK: u32 = 0x0020; pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF; // fdio_spawn_etc actions diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 04da9812dd..652219e28f 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -294,6 +294,7 @@ pub mod guard { unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + #[cfg(target_os = "freebsd")] assert_eq!(libc::pthread_attr_init(&mut attr), 0); #[cfg(target_os = "freebsd")] let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); @@ -305,7 +306,9 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); ret = Some(stackaddr); } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + if e == 0 || cfg!(target_os = "freebsd") { + assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + } ret } @@ -403,6 +406,7 @@ pub mod guard { pub unsafe fn current() -> Option { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + #[cfg(target_os = "freebsd")] assert_eq!(libc::pthread_attr_init(&mut attr), 0); #[cfg(target_os = "freebsd")] let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); @@ -446,7 +450,9 @@ pub mod guard { Some(stackaddr..stackaddr + guardsize) }; } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + if e == 0 || cfg!(target_os = "freebsd") { + assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + } ret } } diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index ecb5b51ccc..faa53b6a74 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -233,10 +233,6 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { match self.0 {} } - - pub fn diverge(&self) -> ! { - match self.0 {} - } } impl DirBuilder { diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs index 87f655eecd..8ba870c5db 100644 --- a/library/std/src/sys/unsupported/mod.rs +++ b/library/std/src/sys/unsupported/mod.rs @@ -8,6 +8,7 @@ pub mod io; pub mod mutex; pub mod net; pub mod os; +#[path = "../unix/path.rs"] pub mod path; pub mod pipe; pub mod process; diff --git a/library/std/src/sys/unsupported/path.rs b/library/std/src/sys/unsupported/path.rs deleted file mode 100644 index 840a7ae042..0000000000 --- a/library/std/src/sys/unsupported/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option> { - None -} - -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 4702e5c549..3ede2291d5 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -1,10 +1,12 @@ use crate::ffi::OsStr; use crate::fmt; use crate::io; +use crate::marker::PhantomData; +use crate::path::Path; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; pub use crate::ffi::OsString as EnvKey; @@ -49,6 +51,22 @@ impl Command { pub fn stderr(&mut self, _stderr: Stdio) {} + pub fn get_program(&self) -> &OsStr { + panic!("unsupported") + } + + pub fn get_args(&self) -> CommandArgs<'_> { + CommandArgs { _p: PhantomData } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + None + } + pub fn spawn( &mut self, _default: Stdio, @@ -65,8 +83,8 @@ impl From for Stdio { } impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() + fn from(_file: File) -> Stdio { + panic!("unsupported") } } @@ -147,3 +165,22 @@ impl Process { match self.0 {} } } + +pub struct CommandArgs<'a> { + _p: PhantomData<&'a ()>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + None + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> {} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().finish() + } +} diff --git a/library/std/src/sys/vxworks/args.rs b/library/std/src/sys/vxworks/args.rs index adff6c489b..30cf7a707c 100644 --- a/library/std/src/sys/vxworks/args.rs +++ b/library/std/src/sys/vxworks/args.rs @@ -57,11 +57,11 @@ mod imp { use crate::marker::PhantomData; use crate::ptr; - use crate::sys_common::mutex::Mutex; + use crate::sys_common::mutex::StaticMutex; static mut ARGC: isize = 0; static mut ARGV: *const *const u8 = ptr::null(); - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { let _guard = LOCK.lock(); diff --git a/library/std/src/sys/vxworks/ext/fs.rs b/library/std/src/sys/vxworks/ext/fs.rs index 4ff86daf0d..68dc21b806 100644 --- a/library/std/src/sys/vxworks/ext/fs.rs +++ b/library/std/src/sys/vxworks/ext/fs.rs @@ -427,7 +427,7 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; - /// use std::io; + /// use std::io; /// /// fn main() -> io::Result<()> { /// let meta = fs::metadata("some_file")?; @@ -774,15 +774,6 @@ impl DirEntryExt for fs::DirEntry { /// /// The `dst` path will be a symbolic link pointing to the `src` path. /// -/// # Note -/// -/// On Windows, you must specify whether a symbolic link points to a file -/// or directory. Use `os::windows::fs::symlink_file` to create a -/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a -/// symbolic link to a directory. Additionally, the process must have -/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a -/// symbolic link. -/// /// # Examples /// /// ```no_run diff --git a/library/std/src/sys/vxworks/ext/io.rs b/library/std/src/sys/vxworks/ext/io.rs index 25c6e26d96..8b5a2d12af 100644 --- a/library/std/src/sys/vxworks/ext/io.rs +++ b/library/std/src/sys/vxworks/ext/io.rs @@ -63,6 +63,25 @@ pub trait IntoRawFd { fn into_raw_fd(self) -> RawFd; } +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl AsRawFd for RawFd { + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl IntoRawFd for RawFd { + fn into_raw_fd(self) -> RawFd { + self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl FromRawFd for RawFd { + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { diff --git a/library/std/src/sys/vxworks/fd.rs b/library/std/src/sys/vxworks/fd.rs index ea18684692..d58468ad53 100644 --- a/library/std/src/sys/vxworks/fd.rs +++ b/library/std/src/sys/vxworks/fd.rs @@ -53,7 +53,7 @@ impl FileDesc { } #[inline] - fn is_read_vectored(&self) -> bool { + pub fn is_read_vectored(&self) -> bool { true } diff --git a/library/std/src/sys/vxworks/net.rs b/library/std/src/sys/vxworks/net.rs index 32c27ab6e9..7613fbec46 100644 --- a/library/std/src/sys/vxworks/net.rs +++ b/library/std/src/sys/vxworks/net.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, taget_env = "gnu"))] +mod tests; + use crate::cmp; use crate::ffi::CStr; use crate::io; @@ -330,30 +333,3 @@ fn on_resolver_failure() { #[cfg(not(target_env = "gnu"))] fn on_resolver_failure() {} - -#[cfg(all(test, taget_env = "gnu"))] -mod test { - use super::*; - - #[test] - fn test_res_init() { - // This mostly just tests that the weak linkage doesn't panic wildly... - res_init_if_glibc_before_2_26().unwrap(); - } - - #[test] - fn test_parse_glibc_version() { - let cases = [ - ("0.0", Some((0, 0))), - ("01.+2", Some((1, 2))), - ("3.4.5.six", Some((3, 4))), - ("1", None), - ("1.-2", None), - ("1.foo", None), - ("foo.1", None), - ]; - for &(version_str, parsed) in cases.iter() { - assert_eq!(parsed, parse_glibc_version(version_str)); - } - } -} diff --git a/library/std/src/sys/vxworks/net/tests.rs b/library/std/src/sys/vxworks/net/tests.rs new file mode 100644 index 0000000000..e7c6e348f8 --- /dev/null +++ b/library/std/src/sys/vxworks/net/tests.rs @@ -0,0 +1,23 @@ +use super::*; + +#[test] +fn test_res_init() { + // This mostly just tests that the weak linkage doesn't panic wildly... + res_init_if_glibc_before_2_26().unwrap(); +} + +#[test] +fn test_parse_glibc_version() { + let cases = [ + ("0.0", Some((0, 0))), + ("01.+2", Some((1, 2))), + ("3.4.5.six", Some((3, 4))), + ("1", None), + ("1.-2", None), + ("1.foo", None), + ("foo.1", None), + ]; + for &(version_str, parsed) in cases.iter() { + assert_eq!(parsed, parse_glibc_version(version_str)); + } +} diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs index 1fadf71613..08394a8d29 100644 --- a/library/std/src/sys/vxworks/os.rs +++ b/library/std/src/sys/vxworks/os.rs @@ -10,7 +10,7 @@ use crate::path::{self, Path, PathBuf}; use crate::slice; use crate::str; use crate::sys::cvt; -use crate::sys_common::mutex::{Mutex, MutexGuard}; +use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; use libc::{self, c_char /*,c_void */, c_int}; /*use sys::fd; this one is probably important */ use crate::vec; @@ -212,10 +212,9 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> MutexGuard<'static> { - // We never call `ENV_LOCK.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static ENV_LOCK: Mutex = Mutex::new(); +pub unsafe fn env_lock() -> StaticMutexGuard<'static> { + // It is UB to attempt to acquire this mutex reentrantly! + static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() } diff --git a/library/std/src/sys/vxworks/process/process_common.rs b/library/std/src/sys/vxworks/process/process_common.rs index bbbd5eda77..6473a0c3ce 100644 --- a/library/std/src/sys/vxworks/process/process_common.rs +++ b/library/std/src/sys/vxworks/process/process_common.rs @@ -351,8 +351,7 @@ impl ExitStatus { } fn exited(&self) -> bool { - /*unsafe*/ - { libc::WIFEXITED(self.0) } + libc::WIFEXITED(self.0) } pub fn success(&self) -> bool { @@ -360,19 +359,11 @@ impl ExitStatus { } pub fn code(&self) -> Option { - if self.exited() { - Some(/*unsafe*/ { libc::WEXITSTATUS(self.0) }) - } else { - None - } + if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } } pub fn signal(&self) -> Option { - if !self.exited() { - Some(/*unsafe*/ { libc::WTERMSIG(self.0) }) - } else { - None - } + if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } } } diff --git a/library/std/src/sys/vxworks/thread_local_dtor.rs b/library/std/src/sys/vxworks/thread_local_dtor.rs index 3f73f6c490..5391ed83eb 100644 --- a/library/std/src/sys/vxworks/thread_local_dtor.rs +++ b/library/std/src/sys/vxworks/thread_local_dtor.rs @@ -2,6 +2,6 @@ #![unstable(feature = "thread_local_internals", issue = "none")] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { - use crate::sys_common::thread_local::register_dtor_fallback; + use crate::sys_common::thread_local_dtor::register_dtor_fallback; register_dtor_fallback(t, dtor); } diff --git a/library/std/src/sys/wasi/alloc.rs b/library/std/src/sys/wasi/alloc.rs deleted file mode 100644 index 57187851a1..0000000000 --- a/library/std/src/sys/wasi/alloc.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::alloc::{GlobalAlloc, Layout, System}; -use crate::ptr; -use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN}; - -#[stable(feature = "alloc_system_type", since = "1.28.0")] -unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut u8 - } else { - libc::aligned_alloc(layout.align(), layout.size()) as *mut u8 - } - } - - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut u8 - } else { - let ptr = self.alloc(layout.clone()); - if !ptr.is_null() { - ptr::write_bytes(ptr, 0, layout.size()); - } - ptr - } - } - - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - libc::free(ptr as *mut libc::c_void) - } - - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 - } else { - realloc_fallback(self, ptr, layout, new_size) - } - } -} diff --git a/library/std/src/sys/wasi/args.rs b/library/std/src/sys/wasi/args.rs index 02aa68d6f3..9a27218e1f 100644 --- a/library/std/src/sys/wasi/args.rs +++ b/library/std/src/sys/wasi/args.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::ffi::{CStr, OsStr, OsString}; use crate::marker::PhantomData; use crate::os::wasi::ffi::OsStrExt; diff --git a/library/std/src/sys/wasi/ext/fs.rs b/library/std/src/sys/wasi/ext/fs.rs index f41c6626cc..4f7cf6018d 100644 --- a/library/std/src/sys/wasi/ext/fs.rs +++ b/library/std/src/sys/wasi/ext/fs.rs @@ -1,5 +1,6 @@ //! WASI-specific extensions to primitives in the `std::fs` module. +#![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "wasi_ext", issue = "none")] use crate::fs::{self, File, Metadata, OpenOptions}; @@ -9,8 +10,6 @@ use crate::sys::fs::osstr2str; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; /// WASI-specific extensions to [`File`]. -/// -/// [`File`]: ../../../../std/fs/struct.File.html pub trait FileExt { /// Reads a number of bytes starting from a given offset. /// @@ -23,8 +22,6 @@ pub trait FileExt { /// /// Note that similar to [`File::read`], it is not an error to return with a /// short read. - /// - /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { let bufs = &mut [IoSliceMut::new(buf)]; self.read_vectored_at(bufs, offset) @@ -41,8 +38,6 @@ pub trait FileExt { /// /// Note that similar to [`File::read_vectored`], it is not an error to /// return with a short read. - /// - /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read_vectored fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result; /// Reads the exact number of byte required to fill `buf` from the given offset. @@ -54,8 +49,7 @@ pub trait FileExt { /// /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. /// - /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact - /// [`read_at`]: #tymethod.read_at + /// [`read_at`]: FileExt::read_at /// /// # Errors /// @@ -73,9 +67,6 @@ pub trait FileExt { /// If this function returns an error, it is unspecified how many bytes it /// has read, but it will never read more than would be necessary to /// completely fill the buffer. - /// - /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof #[stable(feature = "rw_exact_all_at", since = "1.33.0")] fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { @@ -111,8 +102,6 @@ pub trait FileExt { /// /// Note that similar to [`File::write`], it is not an error to return a /// short write. - /// - /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { let bufs = &[IoSlice::new(buf)]; self.write_vectored_at(bufs, offset) @@ -132,8 +121,6 @@ pub trait FileExt { /// /// Note that similar to [`File::write_vectored`], it is not an error to return a /// short write. - /// - /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write_vectored fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result; /// Attempts to write an entire buffer starting from a given offset. @@ -155,8 +142,7 @@ pub trait FileExt { /// This function will return the first error of /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. /// - /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`write_at`]: #tymethod.write_at + /// [`write_at`]: FileExt::write_at #[stable(feature = "rw_exact_all_at", since = "1.33.0")] fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { @@ -289,8 +275,6 @@ impl FileExt for fs::File { } /// WASI-specific extensions to [`fs::OpenOptions`]. -/// -/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html pub trait OpenOptionsExt { /// Pass custom `dirflags` argument to `path_open`. /// @@ -406,8 +390,6 @@ impl OpenOptionsExt for OpenOptions { } /// WASI-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html pub trait MetadataExt { /// Returns the `st_dev` field of the internal `filestat_t` fn dev(&self) -> u64; @@ -448,8 +430,6 @@ impl MetadataExt for fs::Metadata { /// /// Adds support for special WASI file types such as block/character devices, /// pipes, and sockets. -/// -/// [`FileType`]: ../../../../std/fs/struct.FileType.html pub trait FileTypeExt { /// Returns `true` if this file type is a block device. fn is_block_device(&self) -> bool; @@ -477,8 +457,6 @@ impl FileTypeExt for fs::FileType { } /// WASI-specific extension methods for [`fs::DirEntry`]. -/// -/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html pub trait DirEntryExt { /// Returns the underlying `d_ino` field of the `dirent_t` fn ino(&self) -> u64; diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs index e849400d67..661214e8f4 100644 --- a/library/std/src/sys/wasi/ext/io.rs +++ b/library/std/src/sys/wasi/ext/io.rs @@ -1,5 +1,6 @@ //! WASI-specific extensions to general I/O primitives +#![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "wasi_ext", issue = "none")] use crate::fs; @@ -51,6 +52,25 @@ pub trait IntoRawFd { fn into_raw_fd(self) -> RawFd; } +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl AsRawFd for RawFd { + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl IntoRawFd for RawFd { + fn into_raw_fd(self) -> RawFd { + self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl FromRawFd for RawFd { + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} + impl AsRawFd for net::TcpStream { fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().as_raw() diff --git a/library/std/src/sys/wasi/ext/mod.rs b/library/std/src/sys/wasi/ext/mod.rs index 58c8c46c96..1cda30edca 100644 --- a/library/std/src/sys/wasi/ext/mod.rs +++ b/library/std/src/sys/wasi/ext/mod.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + pub mod ffi; pub mod fs; pub mod io; diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index 8458ded5db..ba66eba2ad 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -1,3 +1,4 @@ +#![deny(unsafe_op_in_unsafe_fn)] #![allow(dead_code)] use super::err2io; diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 8408756f1b..93a92b49cf 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; diff --git a/library/std/src/sys/wasi/io.rs b/library/std/src/sys/wasi/io.rs index 0ad2e15285..ee017d13a4 100644 --- a/library/std/src/sys/wasi/io.rs +++ b/library/std/src/sys/wasi/io.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::marker::PhantomData; use crate::slice; diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index 2704ff484f..a7a4407ac3 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -17,6 +17,7 @@ use crate::io as std_io; use crate::mem; +#[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; #[path = "../unsupported/cmath.rs"] @@ -33,8 +34,11 @@ pub mod net; pub mod os; pub use crate::sys_common::os_str_bytes as os_str; pub mod ext; +#[path = "../unix/path.rs"] pub mod path; +#[path = "../unsupported/pipe.rs"] pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; #[path = "../unsupported/rwlock.rs"] pub mod rwlock; diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index e186453588..8fd4bb76d8 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::convert::TryFrom; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs index 8052c0aa8a..33c796ae94 100644 --- a/library/std/src/sys/wasi/os.rs +++ b/library/std/src/sys/wasi/os.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::any::Any; use crate::error::Error as StdError; use crate::ffi::{CStr, CString, OsStr, OsString}; diff --git a/library/std/src/sys/wasi/path.rs b/library/std/src/sys/wasi/path.rs deleted file mode 100644 index 840a7ae042..0000000000 --- a/library/std/src/sys/wasi/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option> { - None -} - -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/wasi/pipe.rs b/library/std/src/sys/wasi/pipe.rs deleted file mode 100644 index 10d0925823..0000000000 --- a/library/std/src/sys/wasi/pipe.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::sys::Void; - -pub struct AnonPipe(Void); - -impl AnonPipe { - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/library/std/src/sys/wasi/process.rs b/library/std/src/sys/wasi/process.rs deleted file mode 100644 index 7156c9ab92..0000000000 --- a/library/std/src/sys/wasi/process.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::ffi::OsStr; -use crate::fmt; -use crate::io; -use crate::sys::fs::File; -use crate::sys::pipe::AnonPipe; -use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; - -pub use crate::ffi::OsString as EnvKey; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } - } - - pub fn arg(&mut self, _arg: &OsStr) {} - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) {} - - pub fn stdin(&mut self, _stdin: Stdio) {} - - pub fn stdout(&mut self, _stdout: Stdio) {} - - pub fn stderr(&mut self, _stderr: Stdio) {} - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(_file: File) -> Stdio { - panic!("unsupported") - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus {} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 23baafabf7..d82f6f4118 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::sys::fd::WasiFd; diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index 0d39b1cec3..8eaa5f09cb 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::ffi::CStr; use crate::io; use crate::mem; diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs index 80ec317b5a..2e720d1160 100644 --- a/library/std/src/sys/wasi/time.rs +++ b/library/std/src/sys/wasi/time.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::time::Duration; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 3de5890404..2934ea59ab 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -27,7 +27,7 @@ pub mod io; pub mod net; #[path = "../unsupported/os.rs"] pub mod os; -#[path = "../unsupported/path.rs"] +#[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index 5fbea2a291..bcc2ea9ae0 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -1,5 +1,8 @@ #![allow(dead_code)] // runtime init functions not used during testing +#[cfg(test)] +mod tests; + use crate::ffi::OsString; use crate::fmt; use crate::os::windows::prelude::*; @@ -198,69 +201,3 @@ impl ExactSizeIterator for Args { self.parsed_args_list.len() } } - -#[cfg(test)] -mod tests { - use crate::ffi::OsString; - use crate::sys::windows::args::*; - - fn chk(string: &str, parts: &[&str]) { - let mut wide: Vec = OsString::from(string).encode_wide().collect(); - wide.push(0); - let parsed = unsafe { - parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE")) - }; - let expected: Vec = parts.iter().map(|k| OsString::from(k)).collect(); - assert_eq!(parsed.as_slice(), expected.as_slice()); - } - - #[test] - fn empty() { - chk("", &["TEST.EXE"]); - chk("\0", &["TEST.EXE"]); - } - - #[test] - fn single_words() { - chk("EXE one_word", &["EXE", "one_word"]); - chk("EXE a", &["EXE", "a"]); - chk("EXE 😅", &["EXE", "😅"]); - chk("EXE 😅🤦", &["EXE", "😅🤦"]); - } - - #[test] - fn official_examples() { - chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]); - chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]); - chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]); - chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]); - } - - #[test] - fn whitespace_behavior() { - chk(r#" test"#, &["", "test"]); - chk(r#" test"#, &["", "test"]); - chk(r#" test test2"#, &["", "test", "test2"]); - chk(r#" test test2"#, &["", "test", "test2"]); - chk(r#"test test2 "#, &["test", "test2"]); - chk(r#"test test2 "#, &["test", "test2"]); - chk(r#"test "#, &["test"]); - } - - #[test] - fn genius_quotes() { - chk(r#"EXE "" """#, &["EXE", "", ""]); - chk(r#"EXE "" """"#, &["EXE", "", "\""]); - chk( - r#"EXE "this is """all""" in the same argument""#, - &["EXE", "this is \"all\" in the same argument"], - ); - chk(r#"EXE "a"""#, &["EXE", "a\""]); - chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]); - // quotes cannot be escaped in command names - chk(r#""EXE" check"#, &["EXE", "check"]); - chk(r#""EXE check""#, &["EXE check"]); - chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]); - chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]); - } -} diff --git a/library/std/src/sys/windows/args/tests.rs b/library/std/src/sys/windows/args/tests.rs new file mode 100644 index 0000000000..756a4361ea --- /dev/null +++ b/library/std/src/sys/windows/args/tests.rs @@ -0,0 +1,61 @@ +use crate::ffi::OsString; +use crate::sys::windows::args::*; + +fn chk(string: &str, parts: &[&str]) { + let mut wide: Vec = OsString::from(string).encode_wide().collect(); + wide.push(0); + let parsed = + unsafe { parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE")) }; + let expected: Vec = parts.iter().map(|k| OsString::from(k)).collect(); + assert_eq!(parsed.as_slice(), expected.as_slice()); +} + +#[test] +fn empty() { + chk("", &["TEST.EXE"]); + chk("\0", &["TEST.EXE"]); +} + +#[test] +fn single_words() { + chk("EXE one_word", &["EXE", "one_word"]); + chk("EXE a", &["EXE", "a"]); + chk("EXE 😅", &["EXE", "😅"]); + chk("EXE 😅🤦", &["EXE", "😅🤦"]); +} + +#[test] +fn official_examples() { + chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]); + chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]); + chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]); + chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]); +} + +#[test] +fn whitespace_behavior() { + chk(r#" test"#, &["", "test"]); + chk(r#" test"#, &["", "test"]); + chk(r#" test test2"#, &["", "test", "test2"]); + chk(r#" test test2"#, &["", "test", "test2"]); + chk(r#"test test2 "#, &["test", "test2"]); + chk(r#"test test2 "#, &["test", "test2"]); + chk(r#"test "#, &["test"]); +} + +#[test] +fn genius_quotes() { + chk(r#"EXE "" """#, &["EXE", "", ""]); + chk(r#"EXE "" """"#, &["EXE", "", "\""]); + chk( + r#"EXE "this is """all""" in the same argument""#, + &["EXE", "this is \"all\" in the same argument"], + ); + chk(r#"EXE "a"""#, &["EXE", "a\""]); + chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]); + // quotes cannot be escaped in command names + chk(r#""EXE" check"#, &["EXE", "check"]); + chk(r#""EXE check""#, &["EXE check"]); + chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]); + chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]); +} diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index f440442ca3..559c4dc9c7 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -1032,7 +1032,7 @@ extern "system" { // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn! { - kernel32: + "kernel32": pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, _lpTargetFileName: LPCWSTR, diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index d6d433f9d0..3f25f05e1b 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -12,7 +12,6 @@ //! function is available but afterwards it's just a load and a jump. use crate::ffi::CString; -use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::c; pub fn lookup(module: &str, symbol: &str) -> Option { @@ -28,45 +27,69 @@ pub fn lookup(module: &str, symbol: &str) -> Option { } } -pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, fallback: usize) -> usize { - let value = lookup(module, symbol).unwrap_or(fallback); - ptr.store(value, Ordering::SeqCst); - value -} - macro_rules! compat_fn { - ($module:ident: $( + ($module:literal: $( $(#[$meta:meta])* - pub fn $symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty { - $($body:expr);* - } + pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $body:block )*) => ($( - #[allow(unused_variables)] $(#[$meta])* - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { + pub mod $symbol { + use super::*; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::mem; + type F = unsafe extern "system" fn($($argtype),*) -> $rettype; static PTR: AtomicUsize = AtomicUsize::new(0); + #[allow(unused_variables)] + unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype $body + + /// This address is stored in `PTR` to incidate an unavailable API. + /// + /// This way, call() will end up calling fallback() if it is unavailable. + /// + /// This is a `static` to avoid rustc duplicating `fn fallback()` + /// into both load() and is_available(), which would break + /// is_available()'s comparison. By using the same static variable + /// in both places, they'll refer to the same (copy of the) + /// function. + /// + /// LLVM merging the address of fallback with other functions + /// (because of unnamed_addr) is fine, since it's only compared to + /// an address from GetProcAddress from an external dll. + static FALLBACK: F = fallback; + + #[cold] fn load() -> usize { - crate::sys::compat::store_func(&PTR, - stringify!($module), - stringify!($symbol), - fallback as usize) + // There is no locking here. It's okay if this is executed by multiple threads in + // parallel. `lookup` will result in the same value, and it's okay if they overwrite + // eachothers result as long as they do so atomically. We don't need any guarantees + // about memory ordering, as this involves just a single atomic variable which is + // not used to protect or order anything else. + let addr = crate::sys::compat::lookup($module, stringify!($symbol)) + .unwrap_or(FALLBACK as usize); + PTR.store(addr, Ordering::Relaxed); + addr } - unsafe extern "system" fn fallback($($argname: $argtype),*) - -> $rettype { - $($body);* + + fn addr() -> usize { + match PTR.load(Ordering::Relaxed) { + 0 => load(), + addr => addr, + } + } + + #[allow(dead_code)] + pub fn is_available() -> bool { + addr() != FALLBACK as usize } - let addr = match PTR.load(Ordering::SeqCst) { - 0 => load(), - n => n, - }; - mem::transmute::(addr)($($argname),*) + pub unsafe fn call($($argname: $argtype),*) -> $rettype { + mem::transmute::(addr())($($argname),*) + } } + + pub use $symbol::call as $symbol; )*) } diff --git a/library/std/src/sys/windows/ext/io.rs b/library/std/src/sys/windows/ext/io.rs index 4573ee5893..e75f9a4bfd 100644 --- a/library/std/src/sys/windows/ext/io.rs +++ b/library/std/src/sys/windows/ext/io.rs @@ -1,3 +1,5 @@ +//! Windows-specific extensions to general I/O primitives. + #![stable(feature = "rust1", since = "1.0.0")] use crate::fs; diff --git a/library/std/src/sys/windows/ext/raw.rs b/library/std/src/sys/windows/ext/raw.rs index 7f2a287782..5014e008eb 100644 --- a/library/std/src/sys/windows/ext/raw.rs +++ b/library/std/src/sys/windows/ext/raw.rs @@ -1,4 +1,4 @@ -//! Windows-specific primitives +//! Windows-specific primitives. #![stable(feature = "raw_ext", since = "1.1.0")] diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index a0d5a7471d..8178e6806b 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -306,10 +306,20 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { /// that function for more information on `__fastfail` #[allow(unreachable_code)] pub fn abort_internal() -> ! { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + const FAST_FAIL_FATAL_APP_EXIT: usize = 7; unsafe { - llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - crate::intrinsics::unreachable(); + cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT); + crate::intrinsics::unreachable(); + } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { + asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT); + crate::intrinsics::unreachable(); + } else if #[cfg(target_arch = "aarch64")] { + asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT); + crate::intrinsics::unreachable(); + } + } } crate::intrinsics::abort(); } diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index 63dfc64090..e2aaca59fe 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -19,24 +19,28 @@ //! CriticalSection is used and we keep track of who's holding the mutex to //! detect recursive locks. -use crate::cell::UnsafeCell; +use crate::cell::{Cell, UnsafeCell}; use crate::mem::{self, MaybeUninit}; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::c; -use crate::sys::compat; pub struct Mutex { + // This is either directly an SRWLOCK (if supported), or a Box otherwise. lock: AtomicUsize, - held: UnsafeCell, } unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} +struct Inner { + remutex: ReentrantMutex, + held: Cell, +} + #[derive(Clone, Copy)] enum Kind { - SRWLock = 1, - CriticalSection = 2, + SRWLock, + CriticalSection, } #[inline] @@ -51,7 +55,6 @@ impl Mutex { // This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly // initializing an SRWLOCK here. lock: AtomicUsize::new(0), - held: UnsafeCell::new(false), } } #[inline] @@ -60,10 +63,11 @@ impl Mutex { match kind() { Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)), Kind::CriticalSection => { - let re = self.remutex(); - (*re).lock(); - if !self.flag_locked() { - (*re).unlock(); + let inner = &*self.inner(); + inner.remutex.lock(); + if inner.held.replace(true) { + // It was already locked, so we got a recursive lock which we do not want. + inner.remutex.unlock(); panic!("cannot recursively lock a mutex"); } } @@ -73,23 +77,27 @@ impl Mutex { match kind() { Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0, Kind::CriticalSection => { - let re = self.remutex(); - if !(*re).try_lock() { + let inner = &*self.inner(); + if !inner.remutex.try_lock() { false - } else if self.flag_locked() { - true - } else { - (*re).unlock(); + } else if inner.held.replace(true) { + // It was already locked, so we got a recursive lock which we do not want. + inner.remutex.unlock(); false + } else { + true } } } } pub unsafe fn unlock(&self) { - *self.held.get() = false; match kind() { Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), - Kind::CriticalSection => (*self.remutex()).unlock(), + Kind::CriticalSection => { + let inner = &*(self.lock.load(Ordering::SeqCst) as *const Inner); + inner.held.set(false); + inner.remutex.unlock(); + } } } pub unsafe fn destroy(&self) { @@ -97,60 +105,35 @@ impl Mutex { Kind::SRWLock => {} Kind::CriticalSection => match self.lock.load(Ordering::SeqCst) { 0 => {} - n => { - Box::from_raw(n as *mut ReentrantMutex).destroy(); - } + n => Box::from_raw(n as *mut Inner).remutex.destroy(), }, } } - unsafe fn remutex(&self) -> *mut ReentrantMutex { + unsafe fn inner(&self) -> *const Inner { match self.lock.load(Ordering::SeqCst) { 0 => {} - n => return n as *mut _, + n => return n as *const _, } - let re = box ReentrantMutex::uninitialized(); - re.init(); - let re = Box::into_raw(re); - match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { - 0 => re, + let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) }; + inner.remutex.init(); + let inner = Box::into_raw(inner); + match self.lock.compare_and_swap(0, inner as usize, Ordering::SeqCst) { + 0 => inner, n => { - Box::from_raw(re).destroy(); - n as *mut _ + Box::from_raw(inner).remutex.destroy(); + n as *const _ } } } - - unsafe fn flag_locked(&self) -> bool { - if *self.held.get() { - false - } else { - *self.held.get() = true; - true - } - } } fn kind() -> Kind { - static KIND: AtomicUsize = AtomicUsize::new(0); - - let val = KIND.load(Ordering::SeqCst); - if val == Kind::SRWLock as usize { - return Kind::SRWLock; - } else if val == Kind::CriticalSection as usize { - return Kind::CriticalSection; - } - - let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") { - None => Kind::CriticalSection, - Some(..) => Kind::SRWLock, - }; - KIND.store(ret as usize, Ordering::SeqCst); - ret + if c::AcquireSRWLockExclusive::is_available() { Kind::SRWLock } else { Kind::CriticalSection } } pub struct ReentrantMutex { - inner: UnsafeCell>, + inner: MaybeUninit>, } unsafe impl Send for ReentrantMutex {} @@ -158,27 +141,27 @@ unsafe impl Sync for ReentrantMutex {} impl ReentrantMutex { pub const fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) } + ReentrantMutex { inner: MaybeUninit::uninit() } } pub unsafe fn init(&self) { - c::InitializeCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::InitializeCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } pub unsafe fn lock(&self) { - c::EnterCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::EnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } #[inline] pub unsafe fn try_lock(&self) -> bool { - c::TryEnterCriticalSection((&mut *self.inner.get()).as_mut_ptr()) != 0 + c::TryEnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())) != 0 } pub unsafe fn unlock(&self) { - c::LeaveCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::LeaveCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } pub unsafe fn destroy(&self) { - c::DeleteCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::DeleteCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } } diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index a0da2498bb..77c378a66a 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -2,6 +2,9 @@ #![allow(nonstandard_style)] +#[cfg(test)] +mod tests; + use crate::os::windows::prelude::*; use crate::error::Error as StdError; @@ -328,20 +331,3 @@ pub fn exit(code: i32) -> ! { pub fn getpid() -> u32 { unsafe { c::GetCurrentProcessId() as u32 } } - -#[cfg(test)] -mod tests { - use crate::io::Error; - use crate::sys::c; - - // tests `error_string` above - #[test] - fn ntstatus_error() { - const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001; - assert!( - !Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _) - .to_string() - .contains("FormatMessageW() returned error") - ); - } -} diff --git a/library/std/src/sys/windows/os/tests.rs b/library/std/src/sys/windows/os/tests.rs new file mode 100644 index 0000000000..458d6e11c2 --- /dev/null +++ b/library/std/src/sys/windows/os/tests.rs @@ -0,0 +1,13 @@ +use crate::io::Error; +use crate::sys::c; + +// tests `error_string` above +#[test] +fn ntstatus_error() { + const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001; + assert!( + !Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _) + .to_string() + .contains("FormatMessageW() returned error") + ); +} diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 2f5fc72ab4..7e09a4fd56 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -77,14 +77,14 @@ impl Buf { } pub fn as_slice(&self) -> &Slice { - // Safety: Slice is just a wrapper for Wtf8, + // SAFETY: Slice is just a wrapper for Wtf8, // and self.inner.as_slice() returns &Wtf8. // Therefore, transmuting &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } pub fn as_mut_slice(&mut self) -> &mut Slice { - // Safety: Slice is just a wrapper for Wtf8, + // SAFETY: Slice is just a wrapper for Wtf8, // and self.inner.as_mut_slice() returns &mut Wtf8. // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. // Additionally, care should be taken to ensure the slice diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 7d6d4775ee..243065b94b 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -1,5 +1,8 @@ #![unstable(feature = "process_internals", issue = "none")] +#[cfg(test)] +mod tests; + use crate::borrow::Borrow; use crate::collections::BTreeMap; use crate::env; @@ -19,7 +22,7 @@ use crate::sys::handle::Handle; use crate::sys::mutex::Mutex; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::sys_common::AsInner; use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; @@ -131,6 +134,23 @@ impl Command { self.flags = flags; } + pub fn get_program(&self) -> &OsStr { + &self.program + } + + pub fn get_args(&self) -> CommandArgs<'_> { + let iter = self.args.iter(); + CommandArgs { iter } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + self.cwd.as_ref().map(|cwd| Path::new(cwd)) + } + pub fn spawn( &mut self, default: Stdio, @@ -527,40 +547,31 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { } } -#[cfg(test)] -mod tests { - use super::make_command_line; - use crate::ffi::{OsStr, OsString}; - - #[test] - fn test_make_command_line() { - fn test_wrapper(prog: &str, args: &[&str]) -> String { - let command_line = &make_command_line( - OsStr::new(prog), - &args.iter().map(|a| OsString::from(a)).collect::>(), - ) - .unwrap(); - String::from_utf16(command_line).unwrap() - } +pub struct CommandArgs<'a> { + iter: crate::slice::Iter<'a, OsString>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next().map(|s| s.as_ref()) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} - assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc"); - - assert_eq!( - test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), - "\"C:\\Program Files\\blah\\blah.exe\" aaa" - ); - assert_eq!( - test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), - "\"C:\\Program Files\\test\" aa\\\"bb" - ); - assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\""); - assert_eq!( - test_wrapper("echo", &["\" \\\" \\", "\\"]), - "\"echo\" \"\\\" \\\\\\\" \\\\\" \\" - ); - assert_eq!( - test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]), - "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\"" - ); +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.clone()).finish() } } diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs new file mode 100644 index 0000000000..81627ad139 --- /dev/null +++ b/library/std/src/sys/windows/process/tests.rs @@ -0,0 +1,31 @@ +use super::make_command_line; +use crate::ffi::{OsStr, OsString}; + +#[test] +fn test_make_command_line() { + fn test_wrapper(prog: &str, args: &[&str]) -> String { + let command_line = &make_command_line( + OsStr::new(prog), + &args.iter().map(|a| OsString::from(a)).collect::>(), + ) + .unwrap(); + String::from_utf16(command_line).unwrap() + } + + assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc"); + + assert_eq!( + test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), + "\"C:\\Program Files\\blah\\blah.exe\" aaa" + ); + assert_eq!( + test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), + "\"C:\\Program Files\\test\" aa\\\"bb" + ); + assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\""); + assert_eq!(test_wrapper("echo", &["\" \\\" \\", "\\"]), "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"); + assert_eq!( + test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]), + "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\"" + ); +} diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys_common/alloc.rs index c669410078..6c1bc0d839 100644 --- a/library/std/src/sys_common/alloc.rs +++ b/library/std/src/sys_common/alloc.rs @@ -12,9 +12,11 @@ use crate::ptr; target_arch = "mips", target_arch = "powerpc", target_arch = "powerpc64", + target_arch = "sparc", target_arch = "asmjs", target_arch = "wasm32", - target_arch = "hexagon" + target_arch = "hexagon", + target_arch = "riscv32" )))] pub const MIN_ALIGN: usize = 8; #[cfg(all(any( diff --git a/library/std/src/sys_common/at_exit_imp.rs b/library/std/src/sys_common/at_exit_imp.rs index 6b799db856..90d5d3a789 100644 --- a/library/std/src/sys_common/at_exit_imp.rs +++ b/library/std/src/sys_common/at_exit_imp.rs @@ -4,7 +4,7 @@ use crate::mem; use crate::ptr; -use crate::sys_common::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; type Queue = Vec>; @@ -12,9 +12,8 @@ type Queue = Vec>; // on poisoning and this module needs to operate at a lower level than requiring // the thread infrastructure to be in place (useful on the borders of // initialization/destruction). -// We never call `LOCK.init()`, so it is UB to attempt to -// acquire this mutex reentrantly! -static LOCK: Mutex = Mutex::new(); +// It is UB to attempt to acquire this mutex reentrantly! +static LOCK: StaticMutex = StaticMutex::new(); static mut QUEUE: *mut Queue = ptr::null_mut(); const DONE: *mut Queue = 1_usize as *mut _; diff --git a/library/std/src/sys_common/bytestring.rs b/library/std/src/sys_common/bytestring.rs index dccc3bc4a1..97fba60c27 100644 --- a/library/std/src/sys_common/bytestring.rs +++ b/library/std/src/sys_common/bytestring.rs @@ -1,5 +1,8 @@ #![allow(dead_code)] +#[cfg(test)] +mod tests; + use crate::fmt::{Formatter, Result, Write}; use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; @@ -21,26 +24,3 @@ pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter<'_>) -> Result { } f.write_str("\"") } - -#[cfg(test)] -mod tests { - use super::*; - use crate::fmt::{Debug, Formatter, Result}; - - #[test] - fn smoke() { - struct Helper<'a>(&'a [u8]); - - impl Debug for Helper<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - debug_fmt_bytestring(self.0, f) - } - } - - let input = b"\xF0hello,\tworld"; - let expected = r#""\xF0hello,\tworld""#; - let output = format!("{:?}", Helper(input)); - - assert!(output == expected); - } -} diff --git a/library/std/src/sys_common/bytestring/tests.rs b/library/std/src/sys_common/bytestring/tests.rs new file mode 100644 index 0000000000..1685f087d1 --- /dev/null +++ b/library/std/src/sys_common/bytestring/tests.rs @@ -0,0 +1,19 @@ +use super::*; +use crate::fmt::{Debug, Formatter, Result}; + +#[test] +fn smoke() { + struct Helper<'a>(&'a [u8]); + + impl Debug for Helper<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + debug_fmt_bytestring(self.0, f) + } + } + + let input = b"\xF0hello,\tworld"; + let expected = r#""\xF0hello,\tworld""#; + let output = format!("{:?}", Helper(input)); + + assert!(output == expected); +} diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs index f9611bc6f7..a48d301f81 100644 --- a/library/std/src/sys_common/condvar.rs +++ b/library/std/src/sys_common/condvar.rs @@ -1,5 +1,5 @@ use crate::sys::condvar as imp; -use crate::sys_common::mutex::{self, Mutex}; +use crate::sys_common::mutex::MovableMutex; use crate::time::Duration; /// An OS-based condition variable. @@ -46,8 +46,8 @@ impl Condvar { /// Behavior is also undefined if more than one mutex is used concurrently /// on this condition variable. #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - self.0.wait(mutex::raw(mutex)) + pub unsafe fn wait(&self, mutex: &MovableMutex) { + self.0.wait(mutex.raw()) } /// Waits for a signal on the specified mutex with a timeout duration @@ -57,8 +57,8 @@ impl Condvar { /// Behavior is also undefined if more than one mutex is used concurrently /// on this condition variable. #[inline] - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - self.0.wait_timeout(mutex::raw(mutex), dur) + pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool { + self.0.wait_timeout(mutex.raw(), dur) } /// Deallocates all resources associated with this condition variable. diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 840f9093e0..234b257aa9 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -15,6 +15,9 @@ #![allow(missing_docs)] #![allow(missing_debug_implementations)] +#[cfg(test)] +mod tests; + use crate::sync::Once; use crate::sys; @@ -63,6 +66,7 @@ pub mod thread; pub mod thread_info; pub mod thread_local_dtor; pub mod thread_local_key; +pub mod thread_parker; pub mod util; pub mod wtf8; @@ -141,8 +145,3 @@ pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 { // r < denom, so (denom*numer) is the upper bound of (r*numer) q * numer + r * numer / denom } - -#[test] -fn test_muldiv() { - assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); -} diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index e66d899414..93ec7d89bc 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -1,101 +1,106 @@ use crate::sys::mutex as imp; -/// An OS-based mutual exclusion lock. +/// An OS-based mutual exclusion lock, meant for use in static variables. +/// +/// This mutex has a const constructor ([`StaticMutex::new`]), does not +/// implement `Drop` to cleanup resources, and causes UB when moved or used +/// reentrantly. +/// +/// This mutex does not implement poisoning. /// -/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of -/// this mutex is unsafe and it is recommended to instead use the safe wrapper -/// at the top level of the crate instead of this type. -pub struct Mutex(imp::Mutex); +/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and +/// `destroy()`. +pub struct StaticMutex(imp::Mutex); -unsafe impl Sync for Mutex {} +unsafe impl Sync for StaticMutex {} -impl Mutex { +impl StaticMutex { /// Creates a new mutex for use. /// /// Behavior is undefined if the mutex is moved after it is /// first used with any of the functions below. - /// Also, until `init` is called, behavior is undefined if this - /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock` - /// are called by the thread currently holding the lock. + /// Also, the behavior is undefined if this mutex is ever used reentrantly, + /// i.e., `lock` is called by the thread currently holding the lock. #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")] - pub const fn new() -> Mutex { - Mutex(imp::Mutex::new()) + pub const fn new() -> Self { + Self(imp::Mutex::new()) } - /// Prepare the mutex for use. + /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex + /// will be unlocked. /// - /// This should be called once the mutex is at a stable memory address. - /// If called, this must be the very first thing that happens to the mutex. - /// Calling it in parallel with or after any operation (including another - /// `init()`) is undefined behavior. + /// It is undefined behaviour to call this function while locked, or if the + /// mutex has been moved since the last time this was called. #[inline] - pub unsafe fn init(&mut self) { - self.0.init() + pub unsafe fn lock(&self) -> StaticMutexGuard<'_> { + self.0.lock(); + StaticMutexGuard(&self.0) } +} - /// Locks the mutex blocking the current thread until it is available. - /// - /// Behavior is undefined if the mutex has been moved between this and any - /// previous function call. +#[must_use] +pub struct StaticMutexGuard<'a>(&'a imp::Mutex); + +impl Drop for StaticMutexGuard<'_> { #[inline] - pub unsafe fn raw_lock(&self) { - self.0.lock() + fn drop(&mut self) { + unsafe { + self.0.unlock(); + } } +} - /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex - /// will be unlocked. +/// An OS-based mutual exclusion lock. +/// +/// This mutex does *not* have a const constructor, cleans up its resources in +/// its `Drop` implementation, may safely be moved (when not borrowed), and +/// does not cause UB when used reentrantly. +/// +/// This mutex does not implement poisoning. +/// +/// This is a wrapper around `Box`, to allow the object to be moved +/// without moving the raw mutex. +pub struct MovableMutex(Box); + +unsafe impl Sync for MovableMutex {} + +impl MovableMutex { + /// Creates a new mutex. + pub fn new() -> Self { + let mut mutex = box imp::Mutex::new(); + unsafe { mutex.init() }; + Self(mutex) + } + + pub(crate) fn raw(&self) -> &imp::Mutex { + &self.0 + } + + /// Locks the mutex blocking the current thread until it is available. #[inline] - pub unsafe fn lock(&self) -> MutexGuard<'_> { - self.raw_lock(); - MutexGuard(&self.0) + pub fn raw_lock(&self) { + unsafe { self.0.lock() } } /// Attempts to lock the mutex without blocking, returning whether it was /// successfully acquired or not. - /// - /// Behavior is undefined if the mutex has been moved between this and any - /// previous function call. #[inline] - pub unsafe fn try_lock(&self) -> bool { - self.0.try_lock() + pub fn try_lock(&self) -> bool { + unsafe { self.0.try_lock() } } /// Unlocks the mutex. /// /// Behavior is undefined if the current thread does not actually hold the /// mutex. - /// - /// Consider switching from the pair of raw_lock() and raw_unlock() to - /// lock() whenever possible. #[inline] pub unsafe fn raw_unlock(&self) { self.0.unlock() } - - /// Deallocates all resources associated with this mutex. - /// - /// Behavior is undefined if there are current or will be future users of - /// this mutex. - #[inline] - pub unsafe fn destroy(&self) { - self.0.destroy() - } } -// not meant to be exported to the outside world, just the containing module -pub fn raw(mutex: &Mutex) -> &imp::Mutex { - &mutex.0 -} - -#[must_use] -/// A simple RAII utility for the above Mutex without the poisoning semantics. -pub struct MutexGuard<'a>(&'a imp::Mutex); - -impl Drop for MutexGuard<'_> { - #[inline] +impl Drop for MovableMutex { fn drop(&mut self) { - unsafe { - self.0.unlock(); - } + unsafe { self.0.destroy() }; } } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 0bb136078b..48ba4ddfc0 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::cmp; use crate::convert::{TryFrom, TryInto}; use crate::ffi::CString; @@ -672,26 +675,3 @@ impl fmt::Debug for UdpSocket { res.field(name, &self.inner.as_inner()).finish() } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::collections::HashMap; - - #[test] - fn no_lookup_host_duplicates() { - let mut addrs = HashMap::new(); - let lh = match LookupHost::try_from(("localhost", 0)) { - Ok(lh) => lh, - Err(e) => panic!("couldn't resolve `localhost': {}", e), - }; - for sa in lh { - *addrs.entry(sa).or_insert(0) += 1; - } - assert_eq!( - addrs.iter().filter(|&(_, &v)| v > 1).collect::>(), - vec![], - "There should be no duplicate localhost entries" - ); - } -} diff --git a/library/std/src/sys_common/net/tests.rs b/library/std/src/sys_common/net/tests.rs new file mode 100644 index 0000000000..7d45621e09 --- /dev/null +++ b/library/std/src/sys_common/net/tests.rs @@ -0,0 +1,19 @@ +use super::*; +use crate::collections::HashMap; + +#[test] +fn no_lookup_host_duplicates() { + let mut addrs = HashMap::new(); + let lh = match LookupHost::try_from(("localhost", 0)) { + Ok(lh) => lh, + Err(e) => panic!("couldn't resolve `localhost': {}", e), + }; + for sa in lh { + *addrs.entry(sa).or_insert(0) += 1; + } + assert_eq!( + addrs.iter().filter(|&(_, &v)| v > 1).collect::>(), + vec![], + "There should be no duplicate localhost entries" + ); +} diff --git a/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys_common/os_str_bytes.rs index 984c032e2a..497e5fc7bd 100644 --- a/library/std/src/sys_common/os_str_bytes.rs +++ b/library/std/src/sys_common/os_str_bytes.rs @@ -106,7 +106,7 @@ impl Buf { #[inline] pub fn as_slice(&self) -> &Slice { - // Safety: Slice just wraps [u8], + // SAFETY: Slice just wraps [u8], // and &*self.inner is &[u8], therefore // transmuting &[u8] to &Slice is safe. unsafe { mem::transmute(&*self.inner) } @@ -114,7 +114,7 @@ impl Buf { #[inline] pub fn as_mut_slice(&mut self) -> &mut Slice { - // Safety: Slice just wraps [u8], + // SAFETY: Slice just wraps [u8], // and &mut *self.inner is &mut [u8], therefore // transmuting &mut [u8] to &mut Slice is safe. unsafe { mem::transmute(&mut *self.inner) } @@ -232,23 +232,17 @@ impl Slice { } /// Platform-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an [`OsString`] from a byte vector. /// /// See the module documentation for an example. - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] fn from_vec(vec: Vec) -> Self; /// Yields the underlying byte vector of this [`OsString`]. /// /// See the module documentation for an example. - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] fn into_vec(self) -> Vec; } @@ -264,23 +258,17 @@ impl OsStringExt for OsString { } /// Platform-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] /// Creates an [`OsStr`] from a byte slice. /// /// See the module documentation for an example. - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html fn from_bytes(slice: &[u8]) -> &Self; /// Gets the underlying byte view of the [`OsStr`] slice. /// /// See the module documentation for an example. - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] fn as_bytes(&self) -> &[u8]; } diff --git a/library/std/src/sys_common/poison.rs b/library/std/src/sys_common/poison.rs index 285851d631..2ab2c700a1 100644 --- a/library/std/src/sys_common/poison.rs +++ b/library/std/src/sys_common/poison.rs @@ -3,6 +3,9 @@ use crate::fmt; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::thread; +#[allow(unused_imports)] // for intra-doc links +use crate::sync::{Mutex, RwLock}; + pub struct Flag { failed: AtomicBool, } @@ -62,7 +65,7 @@ pub struct Guard { /// let mutex = Arc::new(Mutex::new(1)); /// /// // poison the mutex -/// let c_mutex = mutex.clone(); +/// let c_mutex = Arc::clone(&mutex); /// let _ = thread::spawn(move || { /// let mut data = c_mutex.lock().unwrap(); /// *data = 2; @@ -77,9 +80,6 @@ pub struct Guard { /// } /// }; /// ``` -/// -/// [`Mutex`]: ../../std/sync/struct.Mutex.html -/// [`RwLock`]: ../../std/sync/struct.RwLock.html #[stable(feature = "rust1", since = "1.0.0")] pub struct PoisonError { guard: T, @@ -89,12 +89,9 @@ pub struct PoisonError { /// can occur while trying to acquire a lock, from the [`try_lock`] method on a /// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`]. /// -/// [`Mutex`]: struct.Mutex.html -/// [`RwLock`]: struct.RwLock.html -/// [`TryLockResult`]: type.TryLockResult.html -/// [`try_lock`]: struct.Mutex.html#method.try_lock -/// [`try_read`]: struct.RwLock.html#method.try_read -/// [`try_write`]: struct.RwLock.html#method.try_write +/// [`try_lock`]: Mutex::try_lock +/// [`try_read`]: RwLock::try_read +/// [`try_write`]: RwLock::try_write #[stable(feature = "rust1", since = "1.0.0")] pub enum TryLockError { /// The lock could not be acquired because another thread failed while holding @@ -115,9 +112,7 @@ pub enum TryLockError { /// the associated guard, and it can be acquired through the [`into_inner`] /// method. /// -/// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok -/// [`Err`]: ../../std/result/enum.Result.html#variant.Err -/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner +/// [`into_inner`]: PoisonError::into_inner #[stable(feature = "rust1", since = "1.0.0")] pub type LockResult = Result>; @@ -126,9 +121,6 @@ pub type LockResult = Result>; /// For more information, see [`LockResult`]. A `TryLockResult` doesn't /// necessarily hold the associated guard in the [`Err`] type as the lock may not /// have been acquired for other reasons. -/// -/// [`LockResult`]: ../../std/sync/type.LockResult.html -/// [`Err`]: ../../std/result/enum.Result.html#variant.Err #[stable(feature = "rust1", since = "1.0.0")] pub type TryLockResult = Result>; @@ -158,9 +150,6 @@ impl PoisonError { /// Creates a `PoisonError`. /// /// This is generally created by methods like [`Mutex::lock`] or [`RwLock::read`]. - /// - /// [`Mutex::lock`]: ../../std/sync/struct.Mutex.html#method.lock - /// [`RwLock::read`]: ../../std/sync/struct.RwLock.html#method.read #[stable(feature = "sync_poison", since = "1.2.0")] pub fn new(guard: T) -> PoisonError { PoisonError { guard } @@ -179,7 +168,7 @@ impl PoisonError { /// let mutex = Arc::new(Mutex::new(HashSet::new())); /// /// // poison the mutex - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// let _ = thread::spawn(move || { /// let mut data = c_mutex.lock().unwrap(); /// data.insert(10); diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs index f3a2962098..fe89b11043 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys_common/process.rs @@ -92,4 +92,41 @@ impl CommandEnv { self.saw_path = true; } } + + pub fn iter(&self) -> CommandEnvs<'_> { + let iter = self.vars.iter(); + CommandEnvs { iter } + } +} + +/// An iterator over the command environment variables. +/// +/// This struct is created by +/// [`Command::get_envs`][crate::process::Command::get_envs]. See its +/// documentation for more. +#[unstable(feature = "command_access", issue = "44434")] +#[derive(Debug)] +pub struct CommandEnvs<'a> { + iter: crate::collections::btree_map::Iter<'a, EnvKey, Option>, +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> Iterator for CommandEnvs<'a> { + type Item = (&'a OsStr, Option<&'a OsStr>); + fn next(&mut self) -> Option { + self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> ExactSizeIterator for CommandEnvs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } } diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 4f19bbc467..162eab2388 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::fmt; use crate::marker; use crate::ops::Deref; @@ -34,9 +37,7 @@ impl RefUnwindSafe for ReentrantMutex {} /// guarded data. #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { - // funny underscores due to how Deref currently works (it disregards field - // privacy). - __lock: &'a ReentrantMutex, + lock: &'a ReentrantMutex, } impl !marker::Send for ReentrantMutexGuard<'_, T> {} @@ -126,7 +127,7 @@ impl fmt::Debug for ReentrantMutex { impl<'mutex, T> ReentrantMutexGuard<'mutex, T> { fn new(lock: &'mutex ReentrantMutex) -> ReentrantMutexGuard<'mutex, T> { - ReentrantMutexGuard { __lock: lock } + ReentrantMutexGuard { lock } } } @@ -134,7 +135,7 @@ impl Deref for ReentrantMutexGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - &self.__lock.data + &self.lock.data } } @@ -142,83 +143,7 @@ impl Drop for ReentrantMutexGuard<'_, T> { #[inline] fn drop(&mut self) { unsafe { - self.__lock.inner.unlock(); - } - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::cell::RefCell; - use crate::sync::Arc; - use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; - use crate::thread; - - #[test] - fn smoke() { - let m = unsafe { - let m = ReentrantMutex::new(()); - m.init(); - m - }; - { - let a = m.lock(); - { - let b = m.lock(); - { - let c = m.lock(); - assert_eq!(*c, ()); - } - assert_eq!(*b, ()); - } - assert_eq!(*a, ()); - } - } - - #[test] - fn is_mutex() { - let m = unsafe { - let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - m.init(); - m - }; - let m2 = m.clone(); - let lock = m.lock(); - let child = thread::spawn(move || { - let lock = m2.lock(); - assert_eq!(*lock.borrow(), 4950); - }); - for i in 0..100 { - let lock = m.lock(); - *lock.borrow_mut() += i; - } - drop(lock); - child.join().unwrap(); - } - - #[test] - fn trylock_works() { - let m = unsafe { - let m = Arc::new(ReentrantMutex::new(())); - m.init(); - m - }; - let m2 = m.clone(); - let _lock = m.try_lock(); - let _lock2 = m.try_lock(); - thread::spawn(move || { - let lock = m2.try_lock(); - assert!(lock.is_none()); - }) - .join() - .unwrap(); - let _lock3 = m.try_lock(); - } - - pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); - impl Drop for Answer<'_> { - fn drop(&mut self) { - *self.0.borrow_mut() = 42; + self.lock.inner.unlock(); } } } diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sys_common/remutex/tests.rs new file mode 100644 index 0000000000..9c686e579d --- /dev/null +++ b/library/std/src/sys_common/remutex/tests.rs @@ -0,0 +1,72 @@ +use crate::cell::RefCell; +use crate::sync::Arc; +use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; +use crate::thread; + +#[test] +fn smoke() { + let m = unsafe { + let m = ReentrantMutex::new(()); + m.init(); + m + }; + { + let a = m.lock(); + { + let b = m.lock(); + { + let c = m.lock(); + assert_eq!(*c, ()); + } + assert_eq!(*b, ()); + } + assert_eq!(*a, ()); + } +} + +#[test] +fn is_mutex() { + let m = unsafe { + let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); + m.init(); + m + }; + let m2 = m.clone(); + let lock = m.lock(); + let child = thread::spawn(move || { + let lock = m2.lock(); + assert_eq!(*lock.borrow(), 4950); + }); + for i in 0..100 { + let lock = m.lock(); + *lock.borrow_mut() += i; + } + drop(lock); + child.join().unwrap(); +} + +#[test] +fn trylock_works() { + let m = unsafe { + let m = Arc::new(ReentrantMutex::new(())); + m.init(); + m + }; + let m2 = m.clone(); + let _lock = m.try_lock(); + let _lock2 = m.try_lock(); + thread::spawn(move || { + let lock = m2.try_lock(); + assert!(lock.is_none()); + }) + .join() + .unwrap(); + let _lock3 = m.try_lock(); +} + +pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); +impl Drop for Answer<'_> { + fn drop(&mut self) { + *self.0.borrow_mut() = 42; + } +} diff --git a/library/std/src/sys_common/tests.rs b/library/std/src/sys_common/tests.rs new file mode 100644 index 0000000000..1b6446db52 --- /dev/null +++ b/library/std/src/sys_common/tests.rs @@ -0,0 +1,6 @@ +use super::mul_div_u64; + +#[test] +fn test_muldiv() { + assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); +} diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index ac5b128298..dbcb7b3626 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -48,9 +48,12 @@ #![unstable(feature = "thread_local_internals", issue = "none")] #![allow(dead_code)] // sys isn't exported yet +#[cfg(test)] +mod tests; + use crate::sync::atomic::{self, AtomicUsize, Ordering}; use crate::sys::thread_local_key as imp; -use crate::sys_common::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; /// A type for TLS keys that are statically allocated. /// @@ -114,6 +117,7 @@ pub struct Key { pub const INIT: StaticKey = StaticKey::new(None); impl StaticKey { + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const fn new(dtor: Option) -> StaticKey { StaticKey { key: atomic::AtomicUsize::new(0), dtor } } @@ -153,7 +157,7 @@ impl StaticKey { if imp::requires_synchronized_create() { // We never call `INIT_LOCK.init()`, so it is UB to attempt to // acquire this mutex reentrantly! - static INIT_LOCK: Mutex = Mutex::new(); + static INIT_LOCK: StaticMutex = StaticMutex::new(); let _guard = INIT_LOCK.lock(); let mut key = self.key.load(Ordering::SeqCst); if key == 0 { @@ -231,41 +235,3 @@ impl Drop for Key { // unsafe { imp::destroy(self.key) } } } - -#[cfg(test)] -mod tests { - use super::{Key, StaticKey}; - - fn assert_sync() {} - fn assert_send() {} - - #[test] - fn smoke() { - assert_sync::(); - assert_send::(); - - let k1 = Key::new(None); - 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 _); - assert_eq!(k1.get() as usize, 1); - assert_eq!(k2.get() as usize, 2); - } - - #[test] - fn statik() { - static K1: StaticKey = StaticKey::new(None); - static K2: StaticKey = StaticKey::new(None); - - unsafe { - assert!(K1.get().is_null()); - assert!(K2.get().is_null()); - K1.set(1 as *mut _); - K2.set(2 as *mut _); - assert_eq!(K1.get() as usize, 1); - assert_eq!(K2.get() as usize, 2); - } - } -} diff --git a/library/std/src/sys_common/thread_local_key/tests.rs b/library/std/src/sys_common/thread_local_key/tests.rs new file mode 100644 index 0000000000..968738a418 --- /dev/null +++ b/library/std/src/sys_common/thread_local_key/tests.rs @@ -0,0 +1,34 @@ +use super::{Key, StaticKey}; + +fn assert_sync() {} +fn assert_send() {} + +#[test] +fn smoke() { + assert_sync::(); + assert_send::(); + + let k1 = Key::new(None); + 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 _); + assert_eq!(k1.get() as usize, 1); + assert_eq!(k2.get() as usize, 2); +} + +#[test] +fn statik() { + static K1: StaticKey = StaticKey::new(None); + static K2: StaticKey = StaticKey::new(None); + + unsafe { + assert!(K1.get().is_null()); + assert!(K2.get().is_null()); + K1.set(1 as *mut _); + K2.set(2 as *mut _); + assert_eq!(K1.get() as usize, 1); + assert_eq!(K2.get() as usize, 2); + } +} diff --git a/library/std/src/sys_common/thread_parker/futex.rs b/library/std/src/sys_common/thread_parker/futex.rs new file mode 100644 index 0000000000..a5d4927dcc --- /dev/null +++ b/library/std/src/sys_common/thread_parker/futex.rs @@ -0,0 +1,93 @@ +use crate::sync::atomic::AtomicI32; +use crate::sync::atomic::Ordering::{Acquire, Release}; +use crate::sys::futex::{futex_wait, futex_wake}; +use crate::time::Duration; + +const PARKED: i32 = -1; +const EMPTY: i32 = 0; +const NOTIFIED: i32 = 1; + +pub struct Parker { + state: AtomicI32, +} + +// Notes about memory ordering: +// +// Memory ordering is only relevant for the relative ordering of operations +// between different variables. Even Ordering::Relaxed guarantees a +// monotonic/consistent order when looking at just a single atomic variable. +// +// So, since this parker is just a single atomic variable, we only need to look +// at the ordering guarantees we need to provide to the 'outside world'. +// +// The only memory ordering guarantee that parking and unparking provide, is +// that things which happened before unpark() are visible on the thread +// returning from park() afterwards. Otherwise, it was effectively unparked +// before unpark() was called while still consuming the 'token'. +// +// In other words, unpark() needs to synchronize with the part of park() that +// consumes the token and returns. +// +// This is done with a release-acquire synchronization, by using +// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using +// Ordering::Acquire when checking for this state in park(). +impl Parker { + #[inline] + pub const fn new() -> Self { + Parker { state: AtomicI32::new(EMPTY) } + } + + // Assumes this is only called by the thread that owns the Parker, + // which means that `self.state != PARKED`. + pub unsafe fn park(&self) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + loop { + // Wait for something to happen, assuming it's still set to PARKED. + futex_wait(&self.state, PARKED, None); + // Change NOTIFIED=>EMPTY and return in that case. + if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED { + return; + } else { + // Spurious wake up. We loop to try again. + } + } + } + + // Assumes this is only called by the thread that owns the Parker, + // which means that `self.state != PARKED`. + pub unsafe fn park_timeout(&self, timeout: Duration) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + // Wait for something to happen, assuming it's still set to PARKED. + futex_wait(&self.state, PARKED, Some(timeout)); + // This is not just a store, because we need to establish a + // release-acquire ordering with unpark(). + if self.state.swap(EMPTY, Acquire) == NOTIFIED { + // Woke up because of unpark(). + } else { + // Timeout or spurious wake up. + // We return either way, because we can't easily tell if it was the + // timeout or not. + } + } + + #[inline] + pub fn unpark(&self) { + // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and + // wake the thread in the first case. + // + // Note that even NOTIFIED=>NOTIFIED results in a write. This is on + // purpose, to make sure every unpark() has a release-acquire ordering + // with park(). + if self.state.swap(NOTIFIED, Release) == PARKED { + futex_wake(&self.state); + } + } +} diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs new file mode 100644 index 0000000000..14cfa958e5 --- /dev/null +++ b/library/std/src/sys_common/thread_parker/generic.rs @@ -0,0 +1,119 @@ +//! Parker implementaiton based on a Mutex and Condvar. + +use crate::sync::atomic::AtomicUsize; +use crate::sync::atomic::Ordering::SeqCst; +use crate::sync::{Condvar, Mutex}; +use crate::time::Duration; + +const EMPTY: usize = 0; +const PARKED: usize = 1; +const NOTIFIED: usize = 2; + +pub struct Parker { + state: AtomicUsize, + lock: Mutex<()>, + cvar: Condvar, +} + +impl Parker { + pub fn new() -> Self { + Parker { state: AtomicUsize::new(EMPTY), lock: Mutex::new(()), cvar: Condvar::new() } + } + + // This implementaiton 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) { + // 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 + let mut m = self.lock.lock().unwrap(); + 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); + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => panic!("inconsistent park state"), + } + loop { + m = self.cvar.wait(m).unwrap(); + match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { + Ok(_) => return, // got a notification + Err(_) => {} // spurious wakeup, go back to sleep + } + } + } + + // This implementaiton doesn't require `unsafe`, but other implementations + // may assume this is only called by the thread that owns the Parker. + pub unsafe fn park_timeout(&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; + } + let m = self.lock.lock().unwrap(); + 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); + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => 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. + let (_m, _result) = self.cvar.wait_timeout(m, dur).unwrap(); + match self.state.swap(EMPTY, SeqCst) { + NOTIFIED => {} // got a notification, hurray! + PARKED => {} // no notification, alas + n => panic!("inconsistent park_timeout state: {}", n), + } + } + + pub fn unpark(&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`. + drop(self.lock.lock().unwrap()); + self.cvar.notify_one() + } +} diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs new file mode 100644 index 0000000000..23c17c8e2c --- /dev/null +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -0,0 +1,9 @@ +cfg_if::cfg_if! { + if #[cfg(any(target_os = "linux", target_os = "android"))] { + mod futex; + pub use futex::Parker; + } else { + mod generic; + pub use generic::Parker; + } +} diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index bdb6a05464..7d4b0d5283 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -15,6 +15,9 @@ // unix (it's mostly used on windows), so don't worry about dead code here. #![allow(dead_code)] +#[cfg(test)] +mod tests; + use core::str::next_code_point; use crate::borrow::Cow; @@ -879,407 +882,3 @@ impl Hash for Wtf8 { 0xfeu8.hash(state) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::borrow::Cow; - - #[test] - fn code_point_from_u32() { - assert!(CodePoint::from_u32(0).is_some()); - assert!(CodePoint::from_u32(0xD800).is_some()); - assert!(CodePoint::from_u32(0x10FFFF).is_some()); - assert!(CodePoint::from_u32(0x110000).is_none()); - } - - #[test] - fn code_point_to_u32() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0).to_u32(), 0); - assert_eq!(c(0xD800).to_u32(), 0xD800); - assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF); - } - - #[test] - fn code_point_from_char() { - assert_eq!(CodePoint::from_char('a').to_u32(), 0x61); - assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9); - } - - #[test] - fn code_point_to_string() { - assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061"); - assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9"); - } - - #[test] - fn code_point_to_char() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0x61).to_char(), Some('a')); - assert_eq!(c(0x1F4A9).to_char(), Some('💩')); - assert_eq!(c(0xD800).to_char(), None); - } - - #[test] - fn code_point_to_char_lossy() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0x61).to_char_lossy(), 'a'); - assert_eq!(c(0x1F4A9).to_char_lossy(), '💩'); - assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}'); - } - - #[test] - fn wtf8buf_new() { - assert_eq!(Wtf8Buf::new().bytes, b""); - } - - #[test] - fn wtf8buf_from_str() { - assert_eq!(Wtf8Buf::from_str("").bytes, b""); - assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_from_string() { - assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b""); - assert_eq!( - Wtf8Buf::from_string(String::from("aé 💩")).bytes, - b"a\xC3\xA9 \xF0\x9F\x92\xA9" - ); - } - - #[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" - ); - } - - #[test] - fn wtf8buf_push_str() { - let mut string = Wtf8Buf::new(); - assert_eq!(string.bytes, b""); - string.push_str("aé 💩"); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_push_char() { - let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); - string.push_char('💩'); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_push() { - let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); - string.push(CodePoint::from_char('💩')); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - - let mut string = Wtf8Buf::new(); - string.push(c(0xD83D)); // lead - 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 - 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 - 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 - 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 - string.push(c(0xDC00)); // trail - assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0x61)); // not surrogate, < 3 bytes - string.push(c(0xDC00)); // trail - assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xDC00)); // trail - assert_eq!(string.bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_push_wtf8() { - let mut string = Wtf8Buf::from_str("aé"); - 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"); - - fn w(v: &[u8]) -> &Wtf8 { - unsafe { Wtf8::from_bytes_unchecked(v) } - } - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\xBD")); // lead - string.push_wtf8(w(b"\xED\xB2\xA9")); // trail - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\xBD")); // lead - 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"); - - 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"); - - 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"); - - 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"); - - 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"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_truncate() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(1); - assert_eq!(string.bytes, b"a"); - } - - #[test] - #[should_panic] - fn wtf8buf_truncate_fail_code_point_boundary() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(2); - } - - #[test] - #[should_panic] - fn wtf8buf_truncate_fail_longer() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(4); - } - - #[test] - fn wtf8buf_into_string() { - let mut string = Wtf8Buf::from_str("aé 💩"); - assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩"))); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.clone().into_string(), Err(string)); - } - - #[test] - fn wtf8buf_into_string_lossy() { - let mut string = Wtf8Buf::from_str("aé 💩"); - assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩")); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�")); - } - - #[test] - 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(&[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"); - } - - #[test] - fn wtf8buf_extend() { - fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf { - fn c(value: &u32) -> CodePoint { - CodePoint::from_u32(*value).unwrap() - } - let mut string = initial.iter().map(c).collect::(); - string.extend(extended.iter().map(c)); - string - } - - assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - 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"); - } - - #[test] - fn wtf8buf_show() { - let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); - } - - #[test] - fn wtf8buf_as_slice() { - assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé")); - } - - #[test] - fn wtf8buf_show_str() { - let text = "a\té 💩\r"; - let string = Wtf8Buf::from_str(text); - assert_eq!(format!("{:?}", text), format!("{:?}", string)); - } - - #[test] - fn wtf8_from_str() { - assert_eq!(&Wtf8::from_str("").bytes, b""); - assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8_len() { - assert_eq!(Wtf8::from_str("").len(), 0); - assert_eq!(Wtf8::from_str("aé 💩").len(), 8); - } - - #[test] - fn wtf8_slice() { - assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 "); - } - - #[test] - #[should_panic] - fn wtf8_slice_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[2..4]; - } - - #[test] - fn wtf8_slice_from() { - assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - #[should_panic] - fn wtf8_slice_from_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[2..]; - } - - #[test] - fn wtf8_slice_to() { - assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 "); - } - - #[test] - #[should_panic] - fn wtf8_slice_to_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[5..]; - } - - #[test] - fn wtf8_ascii_byte_at() { - let slice = Wtf8::from_str("aé 💩"); - assert_eq!(slice.ascii_byte_at(0), b'a'); - assert_eq!(slice.ascii_byte_at(1), b'\xFF'); - assert_eq!(slice.ascii_byte_at(2), b'\xFF'); - assert_eq!(slice.ascii_byte_at(3), b' '); - assert_eq!(slice.ascii_byte_at(4), b'\xFF'); - } - - #[test] - fn wtf8_code_points() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - fn cp(string: &Wtf8Buf) -> Vec> { - string.code_points().map(|c| c.to_char()).collect::>() - } - let mut string = Wtf8Buf::from_str("é "); - assert_eq!(cp(&string), [Some('é'), Some(' ')]); - string.push(c(0xD83D)); - assert_eq!(cp(&string), [Some('é'), Some(' '), None]); - string.push(c(0xDCA9)); - assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]); - } - - #[test] - fn wtf8_as_str() { - assert_eq!(Wtf8::from_str("").as_str(), Some("")); - assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩")); - let mut string = Wtf8Buf::new(); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.as_str(), None); - } - - #[test] - fn wtf8_to_string_lossy() { - assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed("")); - assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩")); - let mut string = Wtf8Buf::from_str("aé 💩"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�")); - assert_eq!(string.to_string_lossy(), expected); - } - - #[test] - fn wtf8_display() { - fn d(b: &[u8]) -> String { - (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string() - } - - assert_eq!("", d("".as_bytes())); - assert_eq!("aé 💩", d("aé 💩".as_bytes())); - - let mut string = Wtf8Buf::from_str("aé 💩"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!("aé 💩�", d(string.as_inner())); - } - - #[test] - fn wtf8_encode_wide() { - let mut string = Wtf8Buf::from_str("aé "); - string.push(CodePoint::from_u32(0xD83D).unwrap()); - string.push_char('💩'); - assert_eq!( - string.encode_wide().collect::>(), - vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9] - ); - } -} diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs new file mode 100644 index 0000000000..385e01f92f --- /dev/null +++ b/library/std/src/sys_common/wtf8/tests.rs @@ -0,0 +1,397 @@ +use super::*; +use crate::borrow::Cow; + +#[test] +fn code_point_from_u32() { + assert!(CodePoint::from_u32(0).is_some()); + assert!(CodePoint::from_u32(0xD800).is_some()); + assert!(CodePoint::from_u32(0x10FFFF).is_some()); + assert!(CodePoint::from_u32(0x110000).is_none()); +} + +#[test] +fn code_point_to_u32() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0).to_u32(), 0); + assert_eq!(c(0xD800).to_u32(), 0xD800); + assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF); +} + +#[test] +fn code_point_from_char() { + assert_eq!(CodePoint::from_char('a').to_u32(), 0x61); + assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9); +} + +#[test] +fn code_point_to_string() { + assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061"); + assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9"); +} + +#[test] +fn code_point_to_char() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0x61).to_char(), Some('a')); + assert_eq!(c(0x1F4A9).to_char(), Some('💩')); + assert_eq!(c(0xD800).to_char(), None); +} + +#[test] +fn code_point_to_char_lossy() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0x61).to_char_lossy(), 'a'); + assert_eq!(c(0x1F4A9).to_char_lossy(), '💩'); + assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}'); +} + +#[test] +fn wtf8buf_new() { + assert_eq!(Wtf8Buf::new().bytes, b""); +} + +#[test] +fn wtf8buf_from_str() { + assert_eq!(Wtf8Buf::from_str("").bytes, b""); + assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8buf_from_string() { + assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b""); + assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[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" + ); +} + +#[test] +fn wtf8buf_push_str() { + let mut string = Wtf8Buf::new(); + assert_eq!(string.bytes, b""); + string.push_str("aé 💩"); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8buf_push_char() { + let mut string = Wtf8Buf::from_str("aé "); + assert_eq!(string.bytes, b"a\xC3\xA9 "); + string.push_char('💩'); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8buf_push() { + let mut string = Wtf8Buf::from_str("aé "); + assert_eq!(string.bytes, b"a\xC3\xA9 "); + string.push(CodePoint::from_char('💩')); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + + let mut string = Wtf8Buf::new(); + string.push(c(0xD83D)); // lead + 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 + 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 + 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 + 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 + string.push(c(0xDC00)); // trail + assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + + let mut string = Wtf8Buf::new(); + string.push(c(0x61)); // not surrogate, < 3 bytes + string.push(c(0xDC00)); // trail + assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); + + let mut string = Wtf8Buf::new(); + string.push(c(0xDC00)); // trail + assert_eq!(string.bytes, b"\xED\xB0\x80"); +} + +#[test] +fn wtf8buf_push_wtf8() { + let mut string = Wtf8Buf::from_str("aé"); + 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"); + + fn w(v: &[u8]) -> &Wtf8 { + unsafe { Wtf8::from_bytes_unchecked(v) } + } + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\xBD")); // lead + string.push_wtf8(w(b"\xED\xB2\xA9")); // trail + assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\xBD")); // lead + 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"); + + 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"); + + 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"); + + 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"); + + 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"); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xB0\x80")); // trail + assert_eq!(string.bytes, b"\xED\xB0\x80"); +} + +#[test] +fn wtf8buf_truncate() { + let mut string = Wtf8Buf::from_str("aé"); + string.truncate(1); + assert_eq!(string.bytes, b"a"); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_fail_code_point_boundary() { + let mut string = Wtf8Buf::from_str("aé"); + string.truncate(2); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_fail_longer() { + let mut string = Wtf8Buf::from_str("aé"); + string.truncate(4); +} + +#[test] +fn wtf8buf_into_string() { + let mut string = Wtf8Buf::from_str("aé 💩"); + assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩"))); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(string.clone().into_string(), Err(string)); +} + +#[test] +fn wtf8buf_into_string_lossy() { + let mut string = Wtf8Buf::from_str("aé 💩"); + assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩")); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�")); +} + +#[test] +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(&[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"); +} + +#[test] +fn wtf8buf_extend() { + fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf { + fn c(value: &u32) -> CodePoint { + CodePoint::from_u32(*value).unwrap() + } + let mut string = initial.iter().map(c).collect::(); + string.extend(extended.iter().map(c)); + string + } + + assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + + 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"); +} + +#[test] +fn wtf8buf_show() { + let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); +} + +#[test] +fn wtf8buf_as_slice() { + assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé")); +} + +#[test] +fn wtf8buf_show_str() { + let text = "a\té 💩\r"; + let string = Wtf8Buf::from_str(text); + assert_eq!(format!("{:?}", text), format!("{:?}", string)); +} + +#[test] +fn wtf8_from_str() { + assert_eq!(&Wtf8::from_str("").bytes, b""); + assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8_len() { + assert_eq!(Wtf8::from_str("").len(), 0); + assert_eq!(Wtf8::from_str("aé 💩").len(), 8); +} + +#[test] +fn wtf8_slice() { + assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 "); +} + +#[test] +#[should_panic] +fn wtf8_slice_not_code_point_boundary() { + &Wtf8::from_str("aé 💩")[2..4]; +} + +#[test] +fn wtf8_slice_from() { + assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +#[should_panic] +fn wtf8_slice_from_not_code_point_boundary() { + &Wtf8::from_str("aé 💩")[2..]; +} + +#[test] +fn wtf8_slice_to() { + assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 "); +} + +#[test] +#[should_panic] +fn wtf8_slice_to_not_code_point_boundary() { + &Wtf8::from_str("aé 💩")[5..]; +} + +#[test] +fn wtf8_ascii_byte_at() { + let slice = Wtf8::from_str("aé 💩"); + assert_eq!(slice.ascii_byte_at(0), b'a'); + assert_eq!(slice.ascii_byte_at(1), b'\xFF'); + assert_eq!(slice.ascii_byte_at(2), b'\xFF'); + assert_eq!(slice.ascii_byte_at(3), b' '); + assert_eq!(slice.ascii_byte_at(4), b'\xFF'); +} + +#[test] +fn wtf8_code_points() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + fn cp(string: &Wtf8Buf) -> Vec> { + string.code_points().map(|c| c.to_char()).collect::>() + } + let mut string = Wtf8Buf::from_str("é "); + assert_eq!(cp(&string), [Some('é'), Some(' ')]); + string.push(c(0xD83D)); + assert_eq!(cp(&string), [Some('é'), Some(' '), None]); + string.push(c(0xDCA9)); + assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]); +} + +#[test] +fn wtf8_as_str() { + assert_eq!(Wtf8::from_str("").as_str(), Some("")); + assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩")); + let mut string = Wtf8Buf::new(); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(string.as_str(), None); +} + +#[test] +fn wtf8_to_string_lossy() { + assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed("")); + assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩")); + let mut string = Wtf8Buf::from_str("aé 💩"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�")); + assert_eq!(string.to_string_lossy(), expected); +} + +#[test] +fn wtf8_display() { + fn d(b: &[u8]) -> String { + (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string() + } + + assert_eq!("", d("".as_bytes())); + assert_eq!("aé 💩", d("aé 💩".as_bytes())); + + let mut string = Wtf8Buf::from_str("aé 💩"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!("aé 💩�", d(string.as_inner())); +} + +#[test] +fn wtf8_encode_wide() { + let mut string = Wtf8Buf::from_str("aé "); + string.push(CodePoint::from_u32(0xD83D).unwrap()); + string.push_char('💩'); + assert_eq!( + string.encode_wide().collect::>(), + vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9] + ); +} diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index a4562967f0..d8db5d1aa6 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -2,6 +2,12 @@ #![unstable(feature = "thread_local_internals", issue = "none")] +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +#[cfg(test)] +mod dynamic_tests; + use crate::error::Error; use crate::fmt; @@ -219,6 +225,7 @@ impl LocalKey { reason = "recently added to create a key", issue = "none" )] + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey { LocalKey { inner } } @@ -282,15 +289,23 @@ mod lazy { } pub unsafe fn get(&self) -> Option<&'static T> { - (*self.inner.get()).as_ref() + // SAFETY: The caller must ensure no reference is ever handed out to + // the inner cell nor mutable reference to the Option inside said + // cell. This make it safe to hand a reference, though the lifetime + // of 'static is itself unsafe, making the get method unsafe. + unsafe { (*self.inner.get()).as_ref() } } + /// The caller must ensure that no reference is active: this method + /// needs unique access. pub unsafe fn initialize T>(&self, init: F) -> &'static T { // Execute the initialization up front, *then* move it into our slot, // just in case initialization fails. let value = init(); let ptr = self.inner.get(); + // SAFETY: + // // note that this can in theory just be `*ptr = Some(value)`, but due to // the compiler will currently codegen that pattern with something like: // @@ -303,22 +318,36 @@ mod lazy { // value (an aliasing violation). To avoid setting the "I'm running a // destructor" flag we just use `mem::replace` which should sequence the // operations a little differently and make this safe to call. - let _ = mem::replace(&mut *ptr, Some(value)); - - // After storing `Some` we want to get a reference to the contents of - // what we just stored. While we could use `unwrap` here and it should - // always work it empirically doesn't seem to always get optimized away, - // which means that using something like `try_with` can pull in - // panicking code and cause a large size bloat. - match *ptr { - Some(ref x) => x, - None => hint::unreachable_unchecked(), + // + // The precondition also ensures that we are the only one accessing + // `self` at the moment so replacing is fine. + unsafe { + let _ = mem::replace(&mut *ptr, Some(value)); + } + + // SAFETY: With the call to `mem::replace` it is guaranteed there is + // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked` + // will never be reached. + unsafe { + // After storing `Some` we want to get a reference to the contents of + // what we just stored. While we could use `unwrap` here and it should + // always work it empirically doesn't seem to always get optimized away, + // which means that using something like `try_with` can pull in + // panicking code and cause a large size bloat. + match *ptr { + Some(ref x) => x, + None => hint::unreachable_unchecked(), + } } } + /// The other methods hand out references while taking &self. + /// As such, callers of this method must ensure no `&` and `&mut` are + /// available and used at the same time. #[allow(unused)] pub unsafe fn take(&mut self) -> Option { - (*self.inner.get()).take() + // SAFETY: See doc comment for this method. + unsafe { (*self.inner.get()).take() } } } } @@ -349,10 +378,17 @@ pub mod statik { } pub unsafe fn get(&self, init: fn() -> T) -> Option<&'static T> { - let value = match self.inner.get() { - Some(ref value) => value, - None => self.inner.initialize(init), + // SAFETY: The caller must ensure no reference is ever handed out to + // the inner cell nor mutable reference to the Option inside said + // cell. This make it safe to hand a reference, though the lifetime + // of 'static is itself unsafe, making the get method unsafe. + let value = unsafe { + match self.inner.get() { + Some(ref value) => value, + None => self.inner.initialize(init), + } }; + Some(value) } } @@ -407,9 +443,18 @@ pub mod fast { } pub unsafe fn get T>(&self, init: F) -> Option<&'static T> { - match self.inner.get() { - Some(val) => Some(val), - None => self.try_initialize(init), + // SAFETY: See the definitions of `LazyKeyInner::get` and + // `try_initialize` for more informations. + // + // The caller must ensure no mutable references are ever active to + // the inner cell or the inner T when this is called. + // The `try_initialize` is dependant on the passed `init` function + // for this. + unsafe { + match self.inner.get() { + Some(val) => Some(val), + None => self.try_initialize(init), + } } } @@ -418,13 +463,14 @@ pub mod fast { // thread_local's, or it is being recursively initialized. // // Macos: Inlining this function can cause two `tlv_get_addr` calls to - // be performed for every call to `Key::get`. The #[cold] hint makes - // that less likely. + // be performed for every call to `Key::get`. // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 - #[cold] + #[inline(never)] unsafe fn try_initialize T>(&self, init: F) -> Option<&'static T> { - if !mem::needs_drop::() || self.try_register_dtor() { - Some(self.inner.initialize(init)) + // SAFETY: See comment above (this function doc). + if !mem::needs_drop::() || unsafe { self.try_register_dtor() } { + // SAFETY: See comment above (his function doc). + Some(unsafe { self.inner.initialize(init) }) } else { None } @@ -436,8 +482,12 @@ pub mod fast { unsafe fn try_register_dtor(&self) -> bool { match self.dtor_state.get() { DtorState::Unregistered => { - // dtor registration happens before initialization. - register_dtor(self as *const _ as *mut u8, destroy_value::); + // SAFETY: dtor registration happens before initialization. + // Passing `self` as a pointer while using `destroy_value` + // is safe because the function will build a pointer to a + // Key, which is the type of self and so find the correct + // size. + unsafe { register_dtor(self as *const _ as *mut u8, destroy_value::) }; self.dtor_state.set(DtorState::Registered); true } @@ -453,13 +503,21 @@ pub mod fast { unsafe extern "C" fn destroy_value(ptr: *mut u8) { let ptr = ptr as *mut Key; + // SAFETY: + // + // The pointer `ptr` has been built just above and comes from + // `try_register_dtor` where it is originally a Key coming from `self`, + // making it non-NUL and of the correct type. + // // Right before we run the user destructor be sure to set the // `Option` to `None`, and `dtor_state` to `RunningOrHasRun`. This // causes future calls to `get` to run `try_initialize_drop` again, // which will now fail, and return `None`. - let value = (*ptr).inner.take(); - (*ptr).dtor_state.set(DtorState::RunningOrHasRun); - drop(value); + unsafe { + let value = (*ptr).inner.take(); + (*ptr).dtor_state.set(DtorState::RunningOrHasRun); + drop(value); + } } } @@ -492,25 +550,35 @@ pub mod os { } impl Key { + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const fn new() -> Key { Key { os: OsStaticKey::new(Some(destroy_value::)), marker: marker::PhantomData } } + /// It is a requirement for the caller to ensure that no mutable + /// reference is active when this method is called. pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> { - let ptr = self.os.get() as *mut Value; + // SAFETY: See the documentation for this method. + let ptr = unsafe { self.os.get() as *mut Value }; if ptr as usize > 1 { - if let Some(ref value) = (*ptr).inner.get() { + // SAFETY: the check ensured the pointer is safe (its destructor + // is not running) + it is coming from a trusted source (self). + if let Some(ref value) = unsafe { (*ptr).inner.get() } { return Some(value); } } - self.try_initialize(init) + // SAFETY: At this point we are sure we have no value and so + // initializing (or trying to) is safe. + unsafe { self.try_initialize(init) } } // `try_initialize` is only called once per os thread local variable, // except in corner cases where thread_local dtors reference other // thread_local's, or it is being recursively initialized. unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> { - let ptr = self.os.get() as *mut Value; + // SAFETY: No mutable references are ever handed out meaning getting + // the value is ok. + let ptr = unsafe { self.os.get() as *mut Value }; if ptr as usize == 1 { // destructor is running return None; @@ -521,18 +589,26 @@ pub mod os { // local copy, so do that now. let ptr: Box> = box Value { inner: LazyKeyInner::new(), key: self }; let ptr = Box::into_raw(ptr); - self.os.set(ptr as *mut u8); + // SAFETY: At this point we are sure there is no value inside + // ptr so setting it will not affect anyone else. + unsafe { + self.os.set(ptr as *mut u8); + } ptr } else { // recursive initialization ptr }; - Some((*ptr).inner.initialize(init)) + // SAFETY: ptr has been ensured as non-NUL just above an so can be + // dereferenced safely. + unsafe { Some((*ptr).inner.initialize(init)) } } } unsafe extern "C" fn destroy_value(ptr: *mut u8) { + // SAFETY: + // // The OS TLS ensures that this key contains a NULL value when this // destructor starts to run. We set it back to a sentinel value of 1 to // ensure that any future calls to `get` for this thread will return @@ -540,210 +616,12 @@ pub mod os { // // Note that to prevent an infinite loop we reset it back to null right // before we return from the destructor ourselves. - let ptr = Box::from_raw(ptr as *mut Value); - let key = ptr.key; - key.os.set(1 as *mut u8); - drop(ptr); - key.os.set(ptr::null_mut()); - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::cell::{Cell, UnsafeCell}; - use crate::sync::mpsc::{channel, Sender}; - use crate::thread; - - struct Foo(Sender<()>); - - impl Drop for Foo { - fn drop(&mut self) { - let Foo(ref s) = *self; - s.send(()).unwrap(); - } - } - - #[test] - fn smoke_no_dtor() { - thread_local!(static FOO: Cell = Cell::new(1)); - - FOO.with(|f| { - assert_eq!(f.get(), 1); - f.set(2); - }); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - FOO.with(|f| { - assert_eq!(f.get(), 1); - }); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - - FOO.with(|f| { - assert_eq!(f.get(), 2); - }); - } - - #[test] - fn states() { - struct Foo; - impl Drop for Foo { - fn drop(&mut self) { - assert!(FOO.try_with(|_| ()).is_err()); - } - } - thread_local!(static FOO: Foo = Foo); - - thread::spawn(|| { - assert!(FOO.try_with(|_| ()).is_ok()); - }) - .join() - .ok() - .expect("thread panicked"); - } - - #[test] - fn smoke_dtor() { - thread_local!(static FOO: UnsafeCell> = UnsafeCell::new(None)); - - let (tx, rx) = channel(); - let _t = thread::spawn(move || unsafe { - let mut tx = Some(tx); - FOO.with(|f| { - *f.get() = Some(Foo(tx.take().unwrap())); - }); - }); - rx.recv().unwrap(); - } - - #[test] - fn circular() { - struct S1; - struct S2; - thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); - thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); - static mut HITS: u32 = 0; - - impl Drop for S1 { - fn drop(&mut self) { - unsafe { - HITS += 1; - if K2.try_with(|_| ()).is_err() { - assert_eq!(HITS, 3); - } else { - if HITS == 1 { - K2.with(|s| *s.get() = Some(S2)); - } else { - assert_eq!(HITS, 3); - } - } - } - } - } - impl Drop for S2 { - fn drop(&mut self) { - unsafe { - HITS += 1; - assert!(K1.try_with(|_| ()).is_ok()); - assert_eq!(HITS, 2); - K1.with(|s| *s.get() = Some(S1)); - } - } - } - - thread::spawn(move || { - drop(S1); - }) - .join() - .ok() - .expect("thread panicked"); - } - - #[test] - fn self_referential() { - struct S1; - thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); - - impl Drop for S1 { - fn drop(&mut self) { - assert!(K1.try_with(|_| ()).is_err()); - } - } - - thread::spawn(move || unsafe { - K1.with(|s| *s.get() = Some(S1)); - }) - .join() - .ok() - .expect("thread panicked"); - } - - // Note that this test will deadlock if TLS destructors aren't run (this - // requires the destructor to be run to pass the test). - #[test] - fn dtors_in_dtors_in_dtors() { - struct S1(Sender<()>); - thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); - thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); - - impl Drop for S1 { - fn drop(&mut self) { - let S1(ref tx) = *self; - unsafe { - let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone()))); - } - } - } - - let (tx, rx) = channel(); - let _t = thread::spawn(move || unsafe { - let mut tx = Some(tx); - K1.with(|s| *s.get() = Some(S1(tx.take().unwrap()))); - }); - rx.recv().unwrap(); - } -} - -#[cfg(test)] -mod dynamic_tests { - use crate::cell::RefCell; - use crate::collections::HashMap; - - #[test] - fn smoke() { - fn square(i: i32) -> i32 { - i * i - } - thread_local!(static FOO: i32 = square(3)); - - FOO.with(|f| { - assert_eq!(*f, 9); - }); - } - - #[test] - fn hashmap() { - fn map() -> RefCell> { - let mut m = HashMap::new(); - m.insert(1, 2); - RefCell::new(m) + unsafe { + let ptr = Box::from_raw(ptr as *mut Value); + let key = ptr.key; + key.os.set(1 as *mut u8); + drop(ptr); + key.os.set(ptr::null_mut()); } - thread_local!(static FOO: RefCell> = map()); - - FOO.with(|map| { - assert_eq!(map.borrow()[&1], 2); - }); - } - - #[test] - fn refcell_vec() { - thread_local!(static FOO: RefCell> = RefCell::new(vec![1, 2, 3])); - - FOO.with(|vec| { - assert_eq!(vec.borrow().len(), 3); - vec.borrow_mut().push(4); - assert_eq!(vec.borrow()[3], 4); - }); } } diff --git a/library/std/src/thread/local/dynamic_tests.rs b/library/std/src/thread/local/dynamic_tests.rs new file mode 100644 index 0000000000..dd18004164 --- /dev/null +++ b/library/std/src/thread/local/dynamic_tests.rs @@ -0,0 +1,40 @@ +use crate::cell::RefCell; +use crate::collections::HashMap; +use crate::thread_local; + +#[test] +fn smoke() { + fn square(i: i32) -> i32 { + i * i + } + thread_local!(static FOO: i32 = square(3)); + + FOO.with(|f| { + assert_eq!(*f, 9); + }); +} + +#[test] +fn hashmap() { + fn map() -> RefCell> { + let mut m = HashMap::new(); + m.insert(1, 2); + RefCell::new(m) + } + thread_local!(static FOO: RefCell> = map()); + + FOO.with(|map| { + assert_eq!(map.borrow()[&1], 2); + }); +} + +#[test] +fn refcell_vec() { + thread_local!(static FOO: RefCell> = RefCell::new(vec![1, 2, 3])); + + FOO.with(|vec| { + assert_eq!(vec.borrow().len(), 3); + vec.borrow_mut().push(4); + assert_eq!(vec.borrow()[3], 4); + }); +} diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs new file mode 100644 index 0000000000..4fb0a08908 --- /dev/null +++ b/library/std/src/thread/local/tests.rs @@ -0,0 +1,154 @@ +use crate::cell::{Cell, UnsafeCell}; +use crate::sync::mpsc::{channel, Sender}; +use crate::thread; +use crate::thread_local; + +struct Foo(Sender<()>); + +impl Drop for Foo { + fn drop(&mut self) { + let Foo(ref s) = *self; + s.send(()).unwrap(); + } +} + +#[test] +fn smoke_no_dtor() { + thread_local!(static FOO: Cell = Cell::new(1)); + + FOO.with(|f| { + assert_eq!(f.get(), 1); + f.set(2); + }); + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + FOO.with(|f| { + assert_eq!(f.get(), 1); + }); + tx.send(()).unwrap(); + }); + rx.recv().unwrap(); + + FOO.with(|f| { + assert_eq!(f.get(), 2); + }); +} + +#[test] +fn states() { + struct Foo; + impl Drop for Foo { + fn drop(&mut self) { + assert!(FOO.try_with(|_| ()).is_err()); + } + } + thread_local!(static FOO: Foo = Foo); + + thread::spawn(|| { + assert!(FOO.try_with(|_| ()).is_ok()); + }) + .join() + .ok() + .expect("thread panicked"); +} + +#[test] +fn smoke_dtor() { + thread_local!(static FOO: UnsafeCell> = UnsafeCell::new(None)); + + let (tx, rx) = channel(); + let _t = thread::spawn(move || unsafe { + let mut tx = Some(tx); + FOO.with(|f| { + *f.get() = Some(Foo(tx.take().unwrap())); + }); + }); + rx.recv().unwrap(); +} + +#[test] +fn circular() { + struct S1; + struct S2; + thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); + thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); + static mut HITS: u32 = 0; + + impl Drop for S1 { + fn drop(&mut self) { + unsafe { + HITS += 1; + if K2.try_with(|_| ()).is_err() { + assert_eq!(HITS, 3); + } else { + if HITS == 1 { + K2.with(|s| *s.get() = Some(S2)); + } else { + assert_eq!(HITS, 3); + } + } + } + } + } + impl Drop for S2 { + fn drop(&mut self) { + unsafe { + HITS += 1; + assert!(K1.try_with(|_| ()).is_ok()); + assert_eq!(HITS, 2); + K1.with(|s| *s.get() = Some(S1)); + } + } + } + + thread::spawn(move || { + drop(S1); + }) + .join() + .ok() + .expect("thread panicked"); +} + +#[test] +fn self_referential() { + struct S1; + thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); + + impl Drop for S1 { + fn drop(&mut self) { + assert!(K1.try_with(|_| ()).is_err()); + } + } + + thread::spawn(move || unsafe { + K1.with(|s| *s.get() = Some(S1)); + }) + .join() + .ok() + .expect("thread panicked"); +} + +// Note that this test will deadlock if TLS destructors aren't run (this +// requires the destructor to be run to pass the test). +#[test] +fn dtors_in_dtors_in_dtors() { + struct S1(Sender<()>); + thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); + thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); + + impl Drop for S1 { + fn drop(&mut self) { + let S1(ref tx) = *self; + unsafe { + let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone()))); + } + } + } + + let (tx, rx) = channel(); + let _t = thread::spawn(move || unsafe { + let mut tx = Some(tx); + K1.with(|s| *s.get() = Some(S1(tx.take().unwrap()))); + }); + rx.recv().unwrap(); +} diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 0b9849517c..087175bb92 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -144,6 +144,10 @@ //! [`with`]: LocalKey::with #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; use crate::any::Any; use crate::cell::UnsafeCell; @@ -155,13 +159,12 @@ use crate::num::NonZeroU64; use crate::panic; use crate::panicking; use crate::str; -use crate::sync::atomic::AtomicUsize; -use crate::sync::atomic::Ordering::SeqCst; -use crate::sync::{Arc, Condvar, Mutex}; +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; use crate::sys_common::{AsInner, IntoInner}; use crate::time::Duration; @@ -453,14 +456,23 @@ impl Builder { imp::Thread::set_name(name); } - thread_info::set(imp::guard::current(), their_thread); + // SAFETY: the stack guard passed is the one for the current thread. + // This means the current thread's stack and the new thread's stack + // are properly set and protected from each other. + thread_info::set(unsafe { imp::guard::current() }, their_thread); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { crate::sys_common::backtrace::__rust_begin_short_backtrace(f) })); - *their_packet.get() = Some(try_result); + // SAFETY: `their_packet` as been built just above and moved by the + // closure (it is an Arc<...>) and `my_packet` will be stored in the + // same `JoinInner` as this closure meaning the mutation will be + // safe (not modify it and affect a value far away). + unsafe { *their_packet.get() = Some(try_result) }; }; Ok(JoinHandle(JoinInner { + // SAFETY: + // // `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed // through FFI or otherwise used with low-level threading primitives that have no // notion of or way to enforce lifetimes. @@ -472,12 +484,14 @@ impl Builder { // Similarly, the `sys` implementation must guarantee that no references to the closure // exist after the thread has terminated, which is signaled by `Thread::join` // returning. - native: Some(imp::Thread::new( - stack_size, - mem::transmute::, Box>(Box::new( - main, - )), - )?), + native: unsafe { + Some(imp::Thread::new( + stack_size, + mem::transmute::, Box>( + Box::new(main), + ), + )?) + }, thread: my_thread, packet: Packet(my_packet), })) @@ -652,6 +666,8 @@ pub fn current() -> Thread { /// /// [`channel`]: crate::sync::mpsc /// [`join`]: JoinHandle::join +/// [`Condvar`]: crate::sync::Condvar +/// [`Mutex`]: crate::sync::Mutex #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { imp::Thread::yield_now() @@ -697,6 +713,8 @@ pub fn yield_now() { /// panic!() /// } /// ``` +/// +/// [Mutex]: crate::sync::Mutex #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn panicking() -> bool { @@ -764,11 +782,6 @@ pub fn sleep(dur: Duration) { imp::Thread::sleep(dur) } -// constants for park/unpark -const EMPTY: usize = 0; -const PARKED: usize = 1; -const NOTIFIED: usize = 2; - /// Blocks unless or until the current thread's token is made available. /// /// A call to `park` does not guarantee that the thread will remain parked @@ -855,45 +868,11 @@ const NOTIFIED: usize = 2; /// /// [`unpark`]: Thread::unpark /// [`thread::park_timeout`]: park_timeout -// -// The implementation currently uses the trivial strategy of a Mutex+Condvar -// with wakeup flag, which does not actually allow spurious wakeups. In the -// future, this will be implemented in a more efficient way, perhaps along the lines of -// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp -// or futuxes, and in either case may allow spurious wakeups. #[stable(feature = "rust1", since = "1.0.0")] pub fn park() { - let thread = current(); - - // If we were previously notified then we consume this notification and - // return quickly. - if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { - return; - } - - // Otherwise we need to coordinate going to sleep - let mut m = thread.inner.lock.lock().unwrap(); - match thread.inner.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 = thread.inner.state.swap(EMPTY, SeqCst); - assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); - return; - } // should consume this notification, so prohibit spurious wakeups in next park. - Err(_) => panic!("inconsistent park state"), - } - loop { - m = thread.inner.cvar.wait(m).unwrap(); - match thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { - Ok(_) => return, // got a notification - Err(_) => {} // spurious wakeup, go back to sleep - } + // SAFETY: park_timeout is called on the parker owned by this thread. + unsafe { + current().inner.parker.park(); } } @@ -955,35 +934,9 @@ pub fn park_timeout_ms(ms: u32) { /// ``` #[stable(feature = "park_timeout", since = "1.4.0")] pub fn park_timeout(dur: Duration) { - let thread = current(); - - // Like `park` above we have a fast path for an already-notified thread, and - // afterwards we start coordinating for a sleep. - // return quickly. - if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { - return; - } - let m = thread.inner.lock.lock().unwrap(); - match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { - Ok(_) => {} - Err(NOTIFIED) => { - // We must read again here, see `park`. - let old = thread.inner.state.swap(EMPTY, SeqCst); - assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); - return; - } // should consume this notification, so prohibit spurious wakeups in next park. - Err(_) => 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. - let (_m, _result) = thread.inner.cvar.wait_timeout(m, dur).unwrap(); - match thread.inner.state.swap(EMPTY, SeqCst) { - NOTIFIED => {} // got a notification, hurray! - PARKED => {} // no notification, alas - n => panic!("inconsistent park_timeout state: {}", n), + // SAFETY: park_timeout is called on the parker owned by this thread. + unsafe { + current().inner.parker.park_timeout(dur); } } @@ -1019,9 +972,8 @@ pub struct ThreadId(NonZeroU64); impl ThreadId { // Generate a new unique thread ID. fn new() -> ThreadId { - // We never call `GUARD.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static GUARD: mutex::Mutex = mutex::Mutex::new(); + // It is UB to attempt to acquire this mutex reentrantly! + static GUARD: mutex::StaticMutex = mutex::StaticMutex::new(); static mut COUNTER: u64 = 1; unsafe { @@ -1062,11 +1014,7 @@ impl ThreadId { struct Inner { name: Option, // Guaranteed to be UTF-8 id: ThreadId, - - // state for thread park/unpark - state: AtomicUsize, - lock: Mutex<()>, - cvar: Condvar, + parker: Parker, } #[derive(Clone)] @@ -1100,13 +1048,7 @@ impl Thread { let cname = name.map(|n| CString::new(n).expect("thread name may not contain interior null bytes")); Thread { - inner: Arc::new(Inner { - name: cname, - id: ThreadId::new(), - state: AtomicUsize::new(EMPTY), - lock: Mutex::new(()), - cvar: Condvar::new(), - }), + inner: Arc::new(Inner { name: cname, id: ThreadId::new(), parker: Parker::new() }), } } @@ -1141,33 +1083,9 @@ impl Thread { /// parked_thread.join().unwrap(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn unpark(&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.inner.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`. - drop(self.inner.lock.lock().unwrap()); - self.inner.cvar.notify_one() + self.inner.parker.unpark(); } /// Gets the thread's unique identifier. @@ -1470,273 +1388,3 @@ fn _assert_sync_and_send() { _assert_both::>(); _assert_both::(); } - -//////////////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////////////// - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::Builder; - use crate::any::Any; - use crate::mem; - use crate::result; - use crate::sync::mpsc::{channel, Sender}; - use crate::thread::{self, ThreadId}; - use crate::time::Duration; - - // !!! These tests are dangerous. If something is buggy, they will hang, !!! - // !!! instead of exiting cleanly. This might wedge the buildbots. !!! - - #[test] - fn test_unnamed_thread() { - thread::spawn(move || { - assert!(thread::current().name().is_none()); - }) - .join() - .ok() - .expect("thread panicked"); - } - - #[test] - fn test_named_thread() { - Builder::new() - .name("ada lovelace".to_string()) - .spawn(move || { - assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); - }) - .unwrap() - .join() - .unwrap(); - } - - #[test] - #[should_panic] - fn test_invalid_named_thread() { - let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {}); - } - - #[test] - fn test_run_basic() { - let (tx, rx) = channel(); - thread::spawn(move || { - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_join_panic() { - match thread::spawn(move || panic!()).join() { - result::Result::Err(_) => (), - result::Result::Ok(()) => panic!(), - } - } - - #[test] - fn test_spawn_sched() { - let (tx, rx) = channel(); - - fn f(i: i32, tx: Sender<()>) { - let tx = tx.clone(); - thread::spawn(move || { - if i == 0 { - tx.send(()).unwrap(); - } else { - f(i - 1, tx); - } - }); - } - f(10, tx); - rx.recv().unwrap(); - } - - #[test] - fn test_spawn_sched_childs_on_default_sched() { - let (tx, rx) = channel(); - - thread::spawn(move || { - thread::spawn(move || { - tx.send(()).unwrap(); - }); - }); - - rx.recv().unwrap(); - } - - fn avoid_copying_the_body(spawnfn: F) - where - F: FnOnce(Box), - { - let (tx, rx) = channel(); - - let x: Box<_> = box 1; - let x_in_parent = (&*x) as *const i32 as usize; - - spawnfn(Box::new(move || { - let x_in_child = (&*x) as *const i32 as usize; - tx.send(x_in_child).unwrap(); - })); - - let x_in_child = rx.recv().unwrap(); - assert_eq!(x_in_parent, x_in_child); - } - - #[test] - fn test_avoid_copying_the_body_spawn() { - avoid_copying_the_body(|v| { - thread::spawn(move || v()); - }); - } - - #[test] - fn test_avoid_copying_the_body_thread_spawn() { - avoid_copying_the_body(|f| { - thread::spawn(move || { - f(); - }); - }) - } - - #[test] - fn test_avoid_copying_the_body_join() { - avoid_copying_the_body(|f| { - let _ = thread::spawn(move || f()).join(); - }) - } - - #[test] - fn test_child_doesnt_ref_parent() { - // If the child refcounts the parent thread, this will stack overflow when - // climbing the thread tree to dereference each ancestor. (See #1789) - // (well, it would if the constant were 8000+ - I lowered it to be more - // valgrind-friendly. try this at home, instead..!) - const GENERATIONS: u32 = 16; - fn child_no(x: u32) -> Box { - return Box::new(move || { - if x < GENERATIONS { - thread::spawn(move || child_no(x + 1)()); - } - }); - } - thread::spawn(|| child_no(0)()); - } - - #[test] - fn test_simple_newsched_spawn() { - thread::spawn(move || {}); - } - - #[test] - fn test_try_panic_message_static_str() { - match thread::spawn(move || { - panic!("static string"); - }) - .join() - { - Err(e) => { - type T = &'static str; - assert!(e.is::()); - assert_eq!(*e.downcast::().unwrap(), "static string"); - } - Ok(()) => panic!(), - } - } - - #[test] - fn test_try_panic_message_owned_str() { - match thread::spawn(move || { - panic!("owned string".to_string()); - }) - .join() - { - Err(e) => { - type T = String; - assert!(e.is::()); - assert_eq!(*e.downcast::().unwrap(), "owned string".to_string()); - } - Ok(()) => panic!(), - } - } - - #[test] - fn test_try_panic_message_any() { - match thread::spawn(move || { - panic!(box 413u16 as Box); - }) - .join() - { - Err(e) => { - type T = Box; - assert!(e.is::()); - let any = e.downcast::().unwrap(); - assert!(any.is::()); - assert_eq!(*any.downcast::().unwrap(), 413); - } - Ok(()) => panic!(), - } - } - - #[test] - fn test_try_panic_message_unit_struct() { - struct Juju; - - match thread::spawn(move || panic!(Juju)).join() { - Err(ref e) if e.is::() => {} - Err(_) | Ok(()) => panic!(), - } - } - - #[test] - fn test_park_timeout_unpark_before() { - for _ in 0..10 { - thread::current().unpark(); - thread::park_timeout(Duration::from_millis(u32::MAX as u64)); - } - } - - #[test] - fn test_park_timeout_unpark_not_called() { - for _ in 0..10 { - thread::park_timeout(Duration::from_millis(10)); - } - } - - #[test] - fn test_park_timeout_unpark_called_other_thread() { - for _ in 0..10 { - let th = thread::current(); - - let _guard = thread::spawn(move || { - super::sleep(Duration::from_millis(50)); - th.unpark(); - }); - - thread::park_timeout(Duration::from_millis(u32::MAX as u64)); - } - } - - #[test] - fn sleep_ms_smoke() { - thread::sleep(Duration::from_millis(2)); - } - - #[test] - fn test_size_of_option_thread_id() { - assert_eq!(mem::size_of::>(), mem::size_of::()); - } - - #[test] - fn test_thread_id_equal() { - assert!(thread::current().id() == thread::current().id()); - } - - #[test] - fn test_thread_id_not_equal() { - let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap(); - assert!(thread::current().id() != spawned_id); - } - - // NOTE: the corresponding test for stderr is in ui/thread-stderr, due - // to the test harness apparently interfering with stderr configuration. -} diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs new file mode 100644 index 0000000000..16ad366fc1 --- /dev/null +++ b/library/std/src/thread/tests.rs @@ -0,0 +1,262 @@ +use super::Builder; +use crate::any::Any; +use crate::mem; +use crate::result; +use crate::sync::mpsc::{channel, Sender}; +use crate::thread::{self, ThreadId}; +use crate::time::Duration; + +// !!! These tests are dangerous. If something is buggy, they will hang, !!! +// !!! instead of exiting cleanly. This might wedge the buildbots. !!! + +#[test] +fn test_unnamed_thread() { + thread::spawn(move || { + assert!(thread::current().name().is_none()); + }) + .join() + .ok() + .expect("thread panicked"); +} + +#[test] +fn test_named_thread() { + Builder::new() + .name("ada lovelace".to_string()) + .spawn(move || { + assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); + }) + .unwrap() + .join() + .unwrap(); +} + +#[test] +#[should_panic] +fn test_invalid_named_thread() { + let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {}); +} + +#[test] +fn test_run_basic() { + let (tx, rx) = channel(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + rx.recv().unwrap(); +} + +#[test] +fn test_join_panic() { + match thread::spawn(move || panic!()).join() { + result::Result::Err(_) => (), + result::Result::Ok(()) => panic!(), + } +} + +#[test] +fn test_spawn_sched() { + let (tx, rx) = channel(); + + fn f(i: i32, tx: Sender<()>) { + let tx = tx.clone(); + thread::spawn(move || { + if i == 0 { + tx.send(()).unwrap(); + } else { + f(i - 1, tx); + } + }); + } + f(10, tx); + rx.recv().unwrap(); +} + +#[test] +fn test_spawn_sched_childs_on_default_sched() { + let (tx, rx) = channel(); + + thread::spawn(move || { + thread::spawn(move || { + tx.send(()).unwrap(); + }); + }); + + rx.recv().unwrap(); +} + +fn avoid_copying_the_body(spawnfn: F) +where + F: FnOnce(Box), +{ + let (tx, rx) = channel(); + + let x: Box<_> = box 1; + let x_in_parent = (&*x) as *const i32 as usize; + + spawnfn(Box::new(move || { + let x_in_child = (&*x) as *const i32 as usize; + tx.send(x_in_child).unwrap(); + })); + + let x_in_child = rx.recv().unwrap(); + assert_eq!(x_in_parent, x_in_child); +} + +#[test] +fn test_avoid_copying_the_body_spawn() { + avoid_copying_the_body(|v| { + thread::spawn(move || v()); + }); +} + +#[test] +fn test_avoid_copying_the_body_thread_spawn() { + avoid_copying_the_body(|f| { + thread::spawn(move || { + f(); + }); + }) +} + +#[test] +fn test_avoid_copying_the_body_join() { + avoid_copying_the_body(|f| { + let _ = thread::spawn(move || f()).join(); + }) +} + +#[test] +fn test_child_doesnt_ref_parent() { + // If the child refcounts the parent thread, this will stack overflow when + // climbing the thread tree to dereference each ancestor. (See #1789) + // (well, it would if the constant were 8000+ - I lowered it to be more + // valgrind-friendly. try this at home, instead..!) + const GENERATIONS: u32 = 16; + fn child_no(x: u32) -> Box { + return Box::new(move || { + if x < GENERATIONS { + thread::spawn(move || child_no(x + 1)()); + } + }); + } + thread::spawn(|| child_no(0)()); +} + +#[test] +fn test_simple_newsched_spawn() { + thread::spawn(move || {}); +} + +#[test] +fn test_try_panic_message_static_str() { + match thread::spawn(move || { + panic!("static string"); + }) + .join() + { + Err(e) => { + type T = &'static str; + assert!(e.is::()); + assert_eq!(*e.downcast::().unwrap(), "static string"); + } + Ok(()) => panic!(), + } +} + +#[test] +fn test_try_panic_message_owned_str() { + match thread::spawn(move || { + panic!("owned string".to_string()); + }) + .join() + { + Err(e) => { + type T = String; + assert!(e.is::()); + assert_eq!(*e.downcast::().unwrap(), "owned string".to_string()); + } + Ok(()) => panic!(), + } +} + +#[test] +fn test_try_panic_message_any() { + match thread::spawn(move || { + panic!(box 413u16 as Box); + }) + .join() + { + Err(e) => { + type T = Box; + assert!(e.is::()); + let any = e.downcast::().unwrap(); + assert!(any.is::()); + assert_eq!(*any.downcast::().unwrap(), 413); + } + Ok(()) => panic!(), + } +} + +#[test] +fn test_try_panic_message_unit_struct() { + struct Juju; + + match thread::spawn(move || panic!(Juju)).join() { + Err(ref e) if e.is::() => {} + Err(_) | Ok(()) => panic!(), + } +} + +#[test] +fn test_park_timeout_unpark_before() { + for _ in 0..10 { + thread::current().unpark(); + thread::park_timeout(Duration::from_millis(u32::MAX as u64)); + } +} + +#[test] +fn test_park_timeout_unpark_not_called() { + for _ in 0..10 { + thread::park_timeout(Duration::from_millis(10)); + } +} + +#[test] +fn test_park_timeout_unpark_called_other_thread() { + for _ in 0..10 { + let th = thread::current(); + + let _guard = thread::spawn(move || { + super::sleep(Duration::from_millis(50)); + th.unpark(); + }); + + thread::park_timeout(Duration::from_millis(u32::MAX as u64)); + } +} + +#[test] +fn sleep_ms_smoke() { + thread::sleep(Duration::from_millis(2)); +} + +#[test] +fn test_size_of_option_thread_id() { + assert_eq!(mem::size_of::>(), mem::size_of::()); +} + +#[test] +fn test_thread_id_equal() { + assert!(thread::current().id() == thread::current().id()); +} + +#[test] +fn test_thread_id_not_equal() { + let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap(); + assert!(thread::current().id() != spawned_id); +} + +// NOTE: the corresponding test for stderr is in ui/thread-stderr, due +// to the test harness apparently interfering with stderr configuration. diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 02161ecb4c..e7df384114 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -12,12 +12,15 @@ #![stable(feature = "time", since = "1.3.0")] +#[cfg(test)] +mod tests; + use crate::cmp; use crate::error::Error; use crate::fmt; use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::sys::time; -use crate::sys_common::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; use crate::sys_common::FromInner; #[stable(feature = "time", since = "1.3.0")] @@ -156,10 +159,10 @@ pub struct Instant(time::Instant); /// | CloudABI | [clock_time_get (Realtime Clock)] | /// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | /// | UNIX | [clock_gettime (Realtime Clock)] | -/// | DARWIN | [gettimeofday] | +/// | Darwin | [gettimeofday] | /// | VXWorks | [clock_gettime (Realtime Clock)] | /// | WASI | [__wasi_clock_time_get (Realtime Clock)] | -/// | Windows | [GetSystemTimeAsFileTime] | +/// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] | /// /// [clock_time_get (Realtime Clock)]: https://nuxi.nl/cloudabi/#clock_time_get /// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time @@ -167,6 +170,7 @@ pub struct Instant(time::Instant); /// [gettimeofday]: http://man7.org/linux/man-pages/man2/gettimeofday.2.html /// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime /// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#clock_time_get +/// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime /// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime /// /// **Disclaimer:** These system calls might change over time. @@ -239,7 +243,7 @@ impl Instant { return Instant(os_now); } - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); static mut LAST_NOW: time::Instant = time::Instant::zero(); unsafe { let _lock = LOCK.lock(); @@ -456,12 +460,13 @@ impl SystemTime { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::time::SystemTime; /// /// let sys_time = SystemTime::now(); - /// let difference = sys_time.duration_since(sys_time) - /// .expect("Clock may have gone backwards"); + /// let new_sys_time = SystemTime::now(); + /// let difference = new_sys_time.duration_since(sys_time) + /// .expect("Clock may have gone backwards"); /// println!("{:?}", difference); /// ``` #[stable(feature = "time2", since = "1.8.0")] @@ -629,172 +634,3 @@ impl FromInner for SystemTime { SystemTime(time) } } - -#[cfg(test)] -mod tests { - use super::{Duration, Instant, SystemTime, UNIX_EPOCH}; - - macro_rules! assert_almost_eq { - ($a:expr, $b:expr) => {{ - let (a, b) = ($a, $b); - if a != b { - let (a, b) = if a > b { (a, b) } else { (b, a) }; - assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b); - } - }}; - } - - #[test] - fn instant_monotonic() { - let a = Instant::now(); - let b = Instant::now(); - assert!(b >= a); - } - - #[test] - fn instant_elapsed() { - let a = Instant::now(); - a.elapsed(); - } - - #[test] - fn instant_math() { - let a = Instant::now(); - let b = Instant::now(); - println!("a: {:?}", a); - println!("b: {:?}", b); - let dur = b.duration_since(a); - println!("dur: {:?}", dur); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - - let second = Duration::new(1, 0); - assert_almost_eq!(a - second + second, a); - assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); - - // checked_add_duration will not panic on overflow - let mut maybe_t = Some(Instant::now()); - let max_duration = Duration::from_secs(u64::MAX); - // in case `Instant` can store `>= now + max_duration`. - for _ in 0..2 { - maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); - } - assert_eq!(maybe_t, None); - - // checked_add_duration calculates the right time and will work for another year - let year = Duration::from_secs(60 * 60 * 24 * 365); - assert_eq!(a + year, a.checked_add(year).unwrap()); - } - - #[test] - fn instant_math_is_associative() { - let now = Instant::now(); - let offset = Duration::from_millis(5); - // Changing the order of instant math shouldn't change the results, - // especially when the expression reduces to X + identity. - assert_eq!((now + offset) - now, (now - now) + offset); - } - - #[test] - #[should_panic] - fn instant_duration_since_panic() { - let a = Instant::now(); - (a - Duration::new(1, 0)).duration_since(a); - } - - #[test] - fn instant_checked_duration_since_nopanic() { - let now = Instant::now(); - let earlier = now - Duration::new(1, 0); - let later = now + Duration::new(1, 0); - assert_eq!(earlier.checked_duration_since(now), None); - assert_eq!(later.checked_duration_since(now), Some(Duration::new(1, 0))); - assert_eq!(now.checked_duration_since(now), Some(Duration::new(0, 0))); - } - - #[test] - fn instant_saturating_duration_since_nopanic() { - let a = Instant::now(); - let ret = (a - Duration::new(1, 0)).saturating_duration_since(a); - assert_eq!(ret, Duration::new(0, 0)); - } - - #[test] - fn system_time_math() { - let a = SystemTime::now(); - let b = SystemTime::now(); - match b.duration_since(a) { - Ok(dur) if dur == Duration::new(0, 0) => { - assert_almost_eq!(a, b); - } - Ok(dur) => { - assert!(b > a); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - } - Err(dur) => { - let dur = dur.duration(); - assert!(a > b); - assert_almost_eq!(b + dur, a); - assert_almost_eq!(a - dur, b); - } - } - - let second = Duration::new(1, 0); - assert_almost_eq!(a.duration_since(a - second).unwrap(), second); - assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second); - - assert_almost_eq!(a - second + second, a); - assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); - - let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); - let one_second_from_epoch2 = - UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); - assert_eq!(one_second_from_epoch, one_second_from_epoch2); - - // checked_add_duration will not panic on overflow - let mut maybe_t = Some(SystemTime::UNIX_EPOCH); - let max_duration = Duration::from_secs(u64::MAX); - // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`. - for _ in 0..2 { - maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); - } - assert_eq!(maybe_t, None); - - // checked_add_duration calculates the right time and will work for another year - let year = Duration::from_secs(60 * 60 * 24 * 365); - assert_eq!(a + year, a.checked_add(year).unwrap()); - } - - #[test] - fn system_time_elapsed() { - let a = SystemTime::now(); - drop(a.elapsed()); - } - - #[test] - fn since_epoch() { - let ts = SystemTime::now(); - let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap(); - let b = ts.duration_since(UNIX_EPOCH).unwrap(); - assert!(b > a); - assert_eq!(b - a, Duration::new(1, 0)); - - let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; - - // Right now for CI this test is run in an emulator, and apparently the - // aarch64 emulator's sense of time is that we're still living in the - // 70s. This is also true for riscv (also qemu) - // - // Otherwise let's assume that we're all running computers later than - // 2000. - if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") { - assert!(a > thirty_years); - } - - // let's assume that we're all running computers earlier than 2090. - // Should give us ~70 years to fix this! - let hundred_twenty_years = thirty_years * 4; - assert!(a < hundred_twenty_years); - } -} diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs new file mode 100644 index 0000000000..783bf49f31 --- /dev/null +++ b/library/std/src/time/tests.rs @@ -0,0 +1,165 @@ +use super::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +macro_rules! assert_almost_eq { + ($a:expr, $b:expr) => {{ + let (a, b) = ($a, $b); + if a != b { + let (a, b) = if a > b { (a, b) } else { (b, a) }; + assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b); + } + }}; +} + +#[test] +fn instant_monotonic() { + let a = Instant::now(); + let b = Instant::now(); + assert!(b >= a); +} + +#[test] +fn instant_elapsed() { + let a = Instant::now(); + a.elapsed(); +} + +#[test] +fn instant_math() { + let a = Instant::now(); + let b = Instant::now(); + println!("a: {:?}", a); + println!("b: {:?}", b); + let dur = b.duration_since(a); + println!("dur: {:?}", dur); + assert_almost_eq!(b - dur, a); + assert_almost_eq!(a + dur, b); + + let second = Duration::new(1, 0); + assert_almost_eq!(a - second + second, a); + assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); + + // checked_add_duration will not panic on overflow + let mut maybe_t = Some(Instant::now()); + let max_duration = Duration::from_secs(u64::MAX); + // in case `Instant` can store `>= now + max_duration`. + for _ in 0..2 { + maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); + } + assert_eq!(maybe_t, None); + + // checked_add_duration calculates the right time and will work for another year + let year = Duration::from_secs(60 * 60 * 24 * 365); + assert_eq!(a + year, a.checked_add(year).unwrap()); +} + +#[test] +fn instant_math_is_associative() { + let now = Instant::now(); + let offset = Duration::from_millis(5); + // Changing the order of instant math shouldn't change the results, + // especially when the expression reduces to X + identity. + assert_eq!((now + offset) - now, (now - now) + offset); +} + +#[test] +#[should_panic] +fn instant_duration_since_panic() { + let a = Instant::now(); + (a - Duration::new(1, 0)).duration_since(a); +} + +#[test] +fn instant_checked_duration_since_nopanic() { + let now = Instant::now(); + let earlier = now - Duration::new(1, 0); + let later = now + Duration::new(1, 0); + assert_eq!(earlier.checked_duration_since(now), None); + assert_eq!(later.checked_duration_since(now), Some(Duration::new(1, 0))); + assert_eq!(now.checked_duration_since(now), Some(Duration::new(0, 0))); +} + +#[test] +fn instant_saturating_duration_since_nopanic() { + let a = Instant::now(); + let ret = (a - Duration::new(1, 0)).saturating_duration_since(a); + assert_eq!(ret, Duration::new(0, 0)); +} + +#[test] +fn system_time_math() { + let a = SystemTime::now(); + let b = SystemTime::now(); + match b.duration_since(a) { + Ok(dur) if dur == Duration::new(0, 0) => { + assert_almost_eq!(a, b); + } + Ok(dur) => { + assert!(b > a); + assert_almost_eq!(b - dur, a); + assert_almost_eq!(a + dur, b); + } + Err(dur) => { + let dur = dur.duration(); + assert!(a > b); + assert_almost_eq!(b + dur, a); + assert_almost_eq!(a - dur, b); + } + } + + let second = Duration::new(1, 0); + assert_almost_eq!(a.duration_since(a - second).unwrap(), second); + assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second); + + assert_almost_eq!(a - second + second, a); + assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); + + let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); + let one_second_from_epoch2 = + UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); + assert_eq!(one_second_from_epoch, one_second_from_epoch2); + + // checked_add_duration will not panic on overflow + let mut maybe_t = Some(SystemTime::UNIX_EPOCH); + let max_duration = Duration::from_secs(u64::MAX); + // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`. + for _ in 0..2 { + maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); + } + assert_eq!(maybe_t, None); + + // checked_add_duration calculates the right time and will work for another year + let year = Duration::from_secs(60 * 60 * 24 * 365); + assert_eq!(a + year, a.checked_add(year).unwrap()); +} + +#[test] +fn system_time_elapsed() { + let a = SystemTime::now(); + drop(a.elapsed()); +} + +#[test] +fn since_epoch() { + let ts = SystemTime::now(); + let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap(); + let b = ts.duration_since(UNIX_EPOCH).unwrap(); + assert!(b > a); + assert_eq!(b - a, Duration::new(1, 0)); + + let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; + + // Right now for CI this test is run in an emulator, and apparently the + // aarch64 emulator's sense of time is that we're still living in the + // 70s. This is also true for riscv (also qemu) + // + // Otherwise let's assume that we're all running computers later than + // 2000. + if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") { + assert!(a > thirty_years); + } + + // let's assume that we're all running computers earlier than 2090. + // Should give us ~70 years to fix this! + let hundred_twenty_years = thirty_years * 4; + assert!(a < hundred_twenty_years); +} diff --git a/library/stdarch/crates/core_arch/avx512f.md b/library/stdarch/crates/core_arch/avx512f.md new file mode 100644 index 0000000000..c978a63461 --- /dev/null +++ b/library/stdarch/crates/core_arch/avx512f.md @@ -0,0 +1,1418 @@ +

["AVX512F"]

+ + * [x] [`_mm512_abs_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_epi32&expand=5236) + * [x] [`_mm512_abs_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_epi64&expand=5236) + * [x] [`_mm512_abs_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_pd&expand=5236) + * [x] [`_mm512_abs_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_ps&expand=5236) + * [x] [`_mm512_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_epi32&expand=5236) + * [x] [`_mm512_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_epi64&expand=5236) + * [x] [`_mm512_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_pd&expand=5236) + * [x] [`_mm512_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_ps&expand=5236) + * [x] [`_mm512_add_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_round_pd&expand=5236) + * [x] [`_mm512_add_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_round_ps&expand=5236) + * [ ] [`_mm512_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_alignr_epi32&expand=5236) + * [ ] [`_mm512_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_alignr_epi64&expand=5236) + * [x] [`_mm512_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_and_epi32&expand=5236) + * [x] [`_mm512_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_and_epi64&expand=5236) + * [x] [`_mm512_and_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_and_si512&expand=5236) + * [ ] [`_mm512_andnot_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_andnot_epi32&expand=5236) + * [ ] [`_mm512_andnot_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_andnot_epi64&expand=5236) + * [ ] [`_mm512_andnot_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_andnot_si512&expand=5236) + * [ ] [`_mm512_broadcast_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcast_f32x4&expand=5236) + * [ ] [`_mm512_broadcast_f64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcast_f64x4&expand=5236) + * [ ] [`_mm512_broadcast_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcast_i32x4&expand=5236) + * [ ] [`_mm512_broadcast_i64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcast_i64x4&expand=5236) + * [ ] [`_mm512_broadcastd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastd_epi32&expand=5236) + * [ ] [`_mm512_broadcastq_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastq_epi64&expand=5236) + * [ ] [`_mm512_broadcastsd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastsd_pd&expand=5236) + * [ ] [`_mm512_broadcastss_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastss_ps&expand=5236) + * [ ] [`_mm512_castpd128_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd128_pd512&expand=5236) + * [ ] [`_mm512_castpd256_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd256_pd512&expand=5236) + * [ ] [`_mm512_castpd512_pd128`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd512_pd128&expand=5236) + * [ ] [`_mm512_castpd512_pd256`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd512_pd256&expand=5236) + * [ ] [`_mm512_castpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd_ps&expand=5236) + * [ ] [`_mm512_castpd_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd_si512&expand=5236) + * [ ] [`_mm512_castps128_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps128_ps512&expand=5236) + * [ ] [`_mm512_castps256_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps256_ps512&expand=5236) + * [ ] [`_mm512_castps512_ps128`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps512_ps128&expand=5236) + * [ ] [`_mm512_castps512_ps256`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps512_ps256&expand=5236) + * [ ] [`_mm512_castps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps_pd&expand=5236) + * [ ] [`_mm512_castps_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps_si512&expand=5236) + * [ ] [`_mm512_castsi128_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi128_si512&expand=5236) + * [ ] [`_mm512_castsi256_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi256_si512&expand=5236) + * [ ] [`_mm512_castsi512_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi512_pd&expand=5236) + * [ ] [`_mm512_castsi512_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi512_ps&expand=5236) + * [ ] [`_mm512_castsi512_si128`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi512_si128&expand=5236) + * [ ] [`_mm512_castsi512_si256`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi512_si256&expand=5236) + * [x] [`_mm512_cmp_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epi32_mask&expand=5236) + * [x] [`_mm512_cmp_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epi64_mask&expand=5236) + * [x] [`_mm512_cmp_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epu32_mask&expand=5236) + * [x] [`_mm512_cmp_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epu64_mask&expand=5236) + * [x] [`_mm512_cmp_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_pd_mask&expand=5236) + * [x] [`_mm512_cmp_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_ps_mask&expand=5236) + * [x] [`_mm512_cmp_round_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_round_pd_mask&expand=5236) + * [x] [`_mm512_cmp_round_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_round_ps_mask&expand=5236) + * [x] [`_mm512_cmpeq_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epi32_mask&expand=5236) + * [x] [`_mm512_cmpeq_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epi64_mask&expand=5236) + * [x] [`_mm512_cmpeq_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epu32_mask&expand=5236) + * [x] [`_mm512_cmpeq_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epu64_mask&expand=5236) + * [x] [`_mm512_cmpeq_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_pd_mask&expand=5236) + * [x] [`_mm512_cmpeq_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_ps_mask&expand=5236) + * [x] [`_mm512_cmpge_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epi32_mask&expand=5236) + * [x] [`_mm512_cmpge_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epi64_mask&expand=5236) + * [x] [`_mm512_cmpge_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epu32_mask&expand=5236) + * [x] [`_mm512_cmpge_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epu64_mask&expand=5236) + * [x] [`_mm512_cmpgt_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epi32_mask&expand=5236) + * [x] [`_mm512_cmpgt_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epi64_mask&expand=5236) + * [x] [`_mm512_cmpgt_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epu32_mask&expand=5236) + * [x] [`_mm512_cmpgt_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epu64_mask&expand=5236) + * [x] [`_mm512_cmple_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epi32_mask&expand=5236) + * [x] [`_mm512_cmple_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epi64_mask&expand=5236) + * [x] [`_mm512_cmple_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epu32_mask&expand=5236) + * [x] [`_mm512_cmple_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epu64_mask&expand=5236) + * [x] [`_mm512_cmple_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_pd_mask&expand=5236) + * [x] [`_mm512_cmple_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_ps_mask&expand=5236) + * [x] [`_mm512_cmplt_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epi32_mask&expand=5236) + * [x] [`_mm512_cmplt_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epi64_mask&expand=5236) + * [x] [`_mm512_cmplt_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epu32_mask&expand=5236) + * [x] [`_mm512_cmplt_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epu64_mask&expand=5236) + * [x] [`_mm512_cmplt_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_pd_mask&expand=5236) + * [x] [`_mm512_cmplt_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_ps_mask&expand=5236) + * [x] [`_mm512_cmpneq_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epi32_mask&expand=5236) + * [x] [`_mm512_cmpneq_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epi64_mask&expand=5236) + * [x] [`_mm512_cmpneq_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epu32_mask&expand=5236) + * [x] [`_mm512_cmpneq_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epu64_mask&expand=5236) + * [x] [`_mm512_cmpneq_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_pd_mask&expand=5236) + * [x] [`_mm512_cmpneq_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_ps_mask&expand=5236) + * [x] [`_mm512_cmpnle_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnle_pd_mask&expand=5236) + * [x] [`_mm512_cmpnle_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnle_ps_mask&expand=5236) + * [x] [`_mm512_cmpnlt_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnlt_pd_mask&expand=5236) + * [x] [`_mm512_cmpnlt_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnlt_ps_mask&expand=5236) + * [x] [`_mm512_cmpord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpord_pd_mask&expand=5236) + * [x] [`_mm512_cmpord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpord_ps_mask&expand=5236) + * [x] [`_mm512_cmpunord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpunord_pd_mask&expand=5236) + * [x] [`_mm512_cmpunord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpunord_ps_mask&expand=5236) + * [ ] [`_mm512_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundepi32_ps&expand=5236) + * [ ] [`_mm512_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundepu32_ps&expand=5236) + * [ ] [`_mm512_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_epi32&expand=5236) + * [ ] [`_mm512_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_epu32&expand=5236) + * [ ] [`_mm512_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_ps&expand=5236) + * [ ] [`_mm512_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundph_ps&expand=5236) + * [x] [`_mm512_cvt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_epi32&expand=5236) + * [x] [`_mm512_cvt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_epu32&expand=5236) + * [x] [`_mm512_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_pd&expand=5236) + * [ ] [`_mm512_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_ph&expand=5236) + * [ ] [`_mm512_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi16_epi32&expand=5236) + * [ ] [`_mm512_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi16_epi64&expand=5236) + * [ ] [`_mm512_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi16&expand=5236) + * [ ] [`_mm512_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi64&expand=5236) + * [ ] [`_mm512_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi8&expand=5236) + * [ ] [`_mm512_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_pd&expand=5236) + * [ ] [`_mm512_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_ps&expand=5236) + * [ ] [`_mm512_cvtepi32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32lo_pd&expand=5236) + * [ ] [`_mm512_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi16&expand=5236) + * [ ] [`_mm512_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi32&expand=5236) + * [ ] [`_mm512_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi8&expand=5236) + * [ ] [`_mm512_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi8_epi32&expand=5236) + * [ ] [`_mm512_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi8_epi64&expand=5236) + * [ ] [`_mm512_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu16_epi32&expand=5236) + * [ ] [`_mm512_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu16_epi64&expand=5236) + * [ ] [`_mm512_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_epi64&expand=5236) + * [ ] [`_mm512_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_pd&expand=5236) + * [ ] [`_mm512_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_ps&expand=5236) + * [ ] [`_mm512_cvtepu32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32lo_pd&expand=5236) + * [ ] [`_mm512_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu8_epi32&expand=5236) + * [ ] [`_mm512_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu8_epi64&expand=5236) + * [x] [`_mm512_cvtpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_epi32&expand=5236) + * [x] [`_mm512_cvtpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_epu32&expand=5236) + * [ ] [`_mm512_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_ps&expand=5236) + * [ ] [`_mm512_cvtpd_pslo`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_pslo&expand=5236) + * [ ] [`_mm512_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtph_ps&expand=5236) + * [x] [`_mm512_cvtps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_epi32&expand=5236) + * [x] [`_mm512_cvtps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_epu32&expand=5236) + * [ ] [`_mm512_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_pd&expand=5236) + * [ ] [`_mm512_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_ph&expand=5236) + * [ ] [`_mm512_cvtpslo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpslo_pd&expand=5236) + * [ ] [`_mm512_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi32_epi16&expand=5236) + * [ ] [`_mm512_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi32_epi8&expand=5236) + * [ ] [`_mm512_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi16&expand=5236) + * [ ] [`_mm512_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi32&expand=5236) + * [ ] [`_mm512_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi8&expand=5236) + * [x] [`_mm512_cvtt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundpd_epi32&expand=5236) + * [x] [`_mm512_cvtt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundpd_epu32&expand=5236) + * [x] [`_mm512_cvtt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundps_epi32&expand=5236) + * [x] [`_mm512_cvtt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundps_epu32&expand=5236) + * [x] [`_mm512_cvttpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttpd_epi32&expand=5236) + * [x] [`_mm512_cvttpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttpd_epu32&expand=5236) + * [x] [`_mm512_cvttps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttps_epi32&expand=5236) + * [x] [`_mm512_cvttps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttps_epu32&expand=5236) + * [ ] [`_mm512_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi32_epi16&expand=5236) + * [ ] [`_mm512_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi32_epi8&expand=5236) + * [ ] [`_mm512_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi16&expand=5236) + * [ ] [`_mm512_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi32&expand=5236) + * [ ] [`_mm512_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi8&expand=5236) + * [x] [`_mm512_div_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_pd&expand=5236) + * [x] [`_mm512_div_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_ps&expand=5236) + * [x] [`_mm512_div_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_round_pd&expand=5236) + * [x] [`_mm512_div_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_round_ps&expand=5236) + * [x] [`_mm512_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extractf32x4_ps&expand=5236) + * [ ] [`_mm512_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extractf64x4_pd&expand=5236) + * [ ] [`_mm512_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extracti32x4_epi32&expand=5236) + * [ ] [`_mm512_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extracti64x4_epi64&expand=5236) + * [ ] [`_mm512_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_pd&expand=5236) + * [ ] [`_mm512_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_ps&expand=5236) + * [ ] [`_mm512_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_round_pd&expand=5236) + * [ ] [`_mm512_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_round_ps&expand=5236) + * [x] [`_mm512_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_pd&expand=5236) + * [x] [`_mm512_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_ps&expand=5236) + * [x] [`_mm512_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_round_pd&expand=5236) + * [x] [`_mm512_fmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_round_ps&expand=5236) + * [x] [`_mm512_fmaddsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmaddsub_pd&expand=5236) + * [x] [`_mm512_fmaddsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmaddsub_ps&expand=5236) + * [x] [`_mm512_fmaddsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmaddsub_round_pd&expand=5236) + * [x] [`_mm512_fmaddsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmaddsub_round_ps&expand=5236) + * [x] [`_mm512_fmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsub_pd&expand=5236) + * [x] [`_mm512_fmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsub_ps&expand=5236) + * [x] [`_mm512_fmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsub_round_pd&expand=5236) + * [x] [`_mm512_fmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsub_round_ps&expand=5236) + * [x] [`_mm512_fmsubadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsubadd_pd&expand=5236) + * [x] [`_mm512_fmsubadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsubadd_ps&expand=5236) + * [x] [`_mm512_fmsubadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsubadd_round_pd&expand=5236) + * [x] [`_mm512_fmsubadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsubadd_round_ps&expand=5236) + * [x] [`_mm512_fnmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmadd_pd&expand=5236) + * [x] [`_mm512_fnmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmadd_ps&expand=5236) + * [x] [`_mm512_fnmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmadd_round_pd&expand=5236) + * [x] [`_mm512_fnmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmadd_round_ps&expand=5236) + * [x] [`_mm512_fnmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmsub_pd&expand=5236) + * [x] [`_mm512_fnmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmsub_ps&expand=5236) + * [x] [`_mm512_fnmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmsub_round_pd&expand=5236) + * [x] [`_mm512_fnmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmsub_round_ps&expand=5236) + * [x] [`_mm512_getexp_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getexp_pd&expand=5236) + * [x] [`_mm512_getexp_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getexp_ps&expand=5236) + * [x] [`_mm512_getexp_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getexp_round_pd&expand=5236) + * [x] [`_mm512_getexp_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getexp_round_ps&expand=5236) + * [x] [`_mm512_getmant_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getmant_pd&expand=5236) + * [x] [`_mm512_getmant_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getmant_ps&expand=5236) + * [x] [`_mm512_getmant_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getmant_round_pd&expand=5236) + * [x] [`_mm512_getmant_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getmant_round_ps&expand=5236) + * [ ] [`_mm512_i32extgather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32extgather_epi32&expand=5236) + * [ ] [`_mm512_i32extgather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32extgather_ps&expand=5236) + * [ ] [`_mm512_i32extscatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32extscatter_epi32&expand=5236) + * [ ] [`_mm512_i32extscatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32extscatter_ps&expand=5236) + * [x] [`_mm512_i32gather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi32&expand=5236) + * [x] [`_mm512_i32gather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi64&expand=5236) + * [x] [`_mm512_i32gather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_pd&expand=5236) + * [x] [`_mm512_i32gather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_ps&expand=5236) + * [ ] [`_mm512_i32loextgather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loextgather_epi64&expand=5236) + * [ ] [`_mm512_i32loextgather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loextgather_pd&expand=5236) + * [ ] [`_mm512_i32loextscatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loextscatter_epi64&expand=5236) + * [ ] [`_mm512_i32loextscatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loextscatter_pd&expand=5236) + * [ ] [`_mm512_i32logather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32logather_epi64&expand=5236) + * [ ] [`_mm512_i32logather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32logather_pd&expand=5236) + * [ ] [`_mm512_i32loscatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loscatter_pd&expand=5236) + * [x] [`_mm512_i32scatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_epi32&expand=5236) + * [x] [`_mm512_i32scatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_epi64&expand=5236) + * [x] [`_mm512_i32scatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_pd&expand=5236) + * [x] [`_mm512_i32scatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_ps&expand=5236) + * [x] [`_mm512_i64gather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi32&expand=5236) + * [x] [`_mm512_i64gather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi64&expand=5236) + * [x] [`_mm512_i64gather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_pd&expand=5236) + * [x] [`_mm512_i64gather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_ps&expand=5236) + * [x] [`_mm512_i64scatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi32&expand=5236) + * [x] [`_mm512_i64scatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi64&expand=5236) + * [x] [`_mm512_i64scatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_pd&expand=5236) + * [x] [`_mm512_i64scatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_ps&expand=5236) + * [ ] [`_mm512_insertf32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_insertf32x4&expand=5236) + * [ ] [`_mm512_insertf64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_insertf64x4&expand=5236) + * [ ] [`_mm512_inserti32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_inserti32x4&expand=5236) + * [ ] [`_mm512_inserti64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_inserti64x4&expand=5236) + * [ ] [`_mm512_int2mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_int2mask&expand=5236) + * [x] [`_mm512_kand`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kand&expand=5236) + * [x] [`_mm512_kandn`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kandn&expand=5236) + * [x] [`_mm512_kmov`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kmov&expand=5236) + * [x] [`_mm512_knot`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_knot&expand=5236) + * [x] [`_mm512_kor`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kor&expand=5236) + * [ ] [`_mm512_kortestc`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kortestc&expand=5236) + * [ ] [`_mm512_kortestz`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kortestz&expand=5236) + * [ ] [`_mm512_kunpackb`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kunpackb&expand=5236) + * [x] [`_mm512_kxnor`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kxnor&expand=5236) + * [x] [`_mm512_kxor`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kxor&expand=5236) + * [ ] [`_mm512_load_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_epi32&expand=5236) + * [ ] [`_mm512_load_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_epi64&expand=5236) + * [ ] [`_mm512_load_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_pd&expand=5236) + * [ ] [`_mm512_load_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_ps&expand=5236) + * [ ] [`_mm512_load_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_si512&expand=5236) + * [x] [`_mm512_loadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_pd&expand=5236) + * [x] [`_mm512_loadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_ps&expand=5236) + * [ ] [`_mm512_loadu_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_si512&expand=5236) + * [x] [`_mm512_mask2_permutex2var_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_epi32&expand=5236) + * [x] [`_mm512_mask2_permutex2var_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_epi64&expand=5236) + * [x] [`_mm512_mask2_permutex2var_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_pd&expand=5236) + * [x] [`_mm512_mask2_permutex2var_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_ps&expand=5236) + * [ ] [`_mm512_mask2int`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2int&expand=5236) + * [x] [`_mm512_mask3_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_pd&expand=5236) + * [x] [`_mm512_mask3_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_ps&expand=5236) + * [x] [`_mm512_mask3_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_round_pd&expand=5236) + * [x] [`_mm512_mask3_fmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_round_ps&expand=5236) + * [x] [`_mm512_mask3_fmaddsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmaddsub_pd&expand=5236) + * [x] [`_mm512_mask3_fmaddsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmaddsub_ps&expand=5236) + * [x] [`_mm512_mask3_fmaddsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmaddsub_round_pd&expand=5236) + * [x] [`_mm512_mask3_fmaddsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmaddsub_round_ps&expand=5236) + * [x] [`_mm512_mask3_fmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsub_pd&expand=5236) + * [x] [`_mm512_mask3_fmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsub_ps&expand=5236) + * [x] [`_mm512_mask3_fmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsub_round_pd&expand=5236) + * [x] [`_mm512_mask3_fmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsub_round_ps&expand=5236) + * [x] [`_mm512_mask3_fmsubadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsubadd_pd&expand=5236) + * [x] [`_mm512_mask3_fmsubadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsubadd_ps&expand=5236) + * [x] [`_mm512_mask3_fmsubadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsubadd_round_pd&expand=5236) + * [x] [`_mm512_mask3_fmsubadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsubadd_round_ps&expand=5236) + * [x] [`_mm512_mask3_fnmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmadd_pd&expand=5236) + * [x] [`_mm512_mask3_fnmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmadd_ps&expand=5236) + * [x] [`_mm512_mask3_fnmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmadd_round_pd&expand=5236) + * [x] [`_mm512_mask3_fnmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmadd_round_ps&expand=5236) + * [x] [`_mm512_mask3_fnmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmsub_pd&expand=5236) + * [x] [`_mm512_mask3_fnmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmsub_ps&expand=5236) + * [x] [`_mm512_mask3_fnmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmsub_round_pd&expand=5236) + * [x] [`_mm512_mask3_fnmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmsub_round_ps&expand=5236) + * [x] [`_mm512_mask_abs_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_epi32&expand=5236) + * [x] [`_mm512_mask_abs_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_epi64&expand=5236) + * [x] [`_mm512_mask_abs_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_pd&expand=5236) + * [x] [`_mm512_mask_abs_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_ps&expand=5236) + * [x] [`_mm512_mask_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_epi32&expand=5236) + * [x] [`_mm512_mask_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_epi64&expand=5236) + * [x] [`_mm512_mask_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_pd&expand=5236) + * [x] [`_mm512_mask_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_ps&expand=5236) + * [x] [`_mm512_mask_add_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_round_pd&expand=5236) + * [x] [`_mm512_mask_add_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_round_ps&expand=5236) + * [ ] [`_mm512_mask_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_alignr_epi32&expand=5236) + * [ ] [`_mm512_mask_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_alignr_epi64&expand=5236) + * [x] [`_mm512_mask_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_and_epi32&expand=5236) + * [x] [`_mm512_mask_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_and_epi64&expand=5236) + * [ ] [`_mm512_mask_andnot_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_andnot_epi32&expand=5236) + * [ ] [`_mm512_mask_andnot_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_andnot_epi64&expand=5236) + * [ ] [`_mm512_mask_blend_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_epi32&expand=5236) + * [ ] [`_mm512_mask_blend_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_epi64&expand=5236) + * [ ] [`_mm512_mask_blend_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_pd&expand=5236) + * [ ] [`_mm512_mask_blend_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_ps&expand=5236) + * [ ] [`_mm512_mask_broadcast_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcast_f32x4&expand=5236) + * [ ] [`_mm512_mask_broadcast_f64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcast_f64x4&expand=5236) + * [ ] [`_mm512_mask_broadcast_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcast_i32x4&expand=5236) + * [ ] [`_mm512_mask_broadcast_i64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcast_i64x4&expand=5236) + * [ ] [`_mm512_mask_broadcastd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastd_epi32&expand=5236) + * [ ] [`_mm512_mask_broadcastq_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastq_epi64&expand=5236) + * [ ] [`_mm512_mask_broadcastsd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastsd_pd&expand=5236) + * [ ] [`_mm512_mask_broadcastss_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastss_ps&expand=5236) + * [x] [`_mm512_mask_cmp_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmp_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmp_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmp_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmp_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmp_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmp_round_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_round_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmp_round_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_round_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpge_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmpge_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmpge_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmpge_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmpgt_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmpgt_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmpgt_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmpgt_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmple_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmple_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmple_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmple_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmple_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmple_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpnle_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnle_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpnle_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnle_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpnlt_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnlt_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpnlt_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnlt_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpord_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpord_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpunord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpunord_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpunord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpunord_ps_mask&expand=5236) + * [ ] [`_mm512_mask_compress_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_epi32&expand=5236) + * [ ] [`_mm512_mask_compress_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_epi64&expand=5236) + * [ ] [`_mm512_mask_compress_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_pd&expand=5236) + * [ ] [`_mm512_mask_compress_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_ps&expand=5236) + * [ ] [`_mm512_mask_compressstoreu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi32&expand=5236) + * [ ] [`_mm512_mask_compressstoreu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi64&expand=5236) + * [ ] [`_mm512_mask_compressstoreu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_pd&expand=5236) + * [ ] [`_mm512_mask_compressstoreu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_ps&expand=5236) + * [ ] [`_mm512_mask_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundepi32_ps&expand=5236) + * [ ] [`_mm512_mask_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundepu32_ps&expand=5236) + * [ ] [`_mm512_mask_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_epi32&expand=5236) + * [ ] [`_mm512_mask_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_epu32&expand=5236) + * [ ] [`_mm512_mask_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_ps&expand=5236) + * [ ] [`_mm512_mask_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundph_ps&expand=5236) + * [x] [`_mm512_mask_cvt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_epi32&expand=5236) + * [x] [`_mm512_mask_cvt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_epu32&expand=5236) + * [ ] [`_mm512_mask_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_pd&expand=5236) + * [ ] [`_mm512_mask_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_ph&expand=5236) + * [ ] [`_mm512_mask_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi16_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi16_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_pd&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_ps&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_storeu_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtepi32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32lo_pd&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_storeu_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_storeu_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi8_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi8_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu16_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu16_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_pd&expand=5236) + * [ ] [`_mm512_mask_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_ps&expand=5236) + * [ ] [`_mm512_mask_cvtepu32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32lo_pd&expand=5236) + * [ ] [`_mm512_mask_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu8_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu8_epi64&expand=5236) + * [x] [`_mm512_mask_cvtpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_epi32&expand=5236) + * [x] [`_mm512_mask_cvtpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_epu32&expand=5236) + * [ ] [`_mm512_mask_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_ps&expand=5236) + * [ ] [`_mm512_mask_cvtpd_pslo`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_pslo&expand=5236) + * [ ] [`_mm512_mask_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtph_ps&expand=5236) + * [x] [`_mm512_mask_cvtps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_epi32&expand=5236) + * [x] [`_mm512_mask_cvtps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_epu32&expand=5236) + * [x] [`_mm512_mask_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_pd&expand=5236) + * [ ] [`_mm512_mask_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_ph&expand=5236) + * [ ] [`_mm512_mask_cvtpslo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpslo_pd&expand=5236) + * [ ] [`_mm512_mask_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtsepi32_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtsepi32_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_storeu_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_storeu_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_storeu_epi8&expand=5236) + * [x] [`_mm512_mask_cvtt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtt_roundpd_epi32&expand=5236) + * [x] [`_mm512_mask_cvtt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtt_roundpd_epu32&expand=5236) + * [x] [`_mm512_mask_cvtt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtt_roundps_epi32&expand=5236) + * [x] [`_mm512_mask_cvtt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtt_roundps_epu32&expand=5236) + * [x] [`_mm512_mask_cvttpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttpd_epi32&expand=5236) + * [x] [`_mm512_mask_cvttpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttpd_epu32&expand=5236) + * [x] [`_mm512_mask_cvttps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttps_epi32&expand=5236) + * [x] [`_mm512_mask_cvttps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttps_epu32&expand=5236) + * [ ] [`_mm512_mask_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtusepi32_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtusepi32_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_storeu_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_storeu_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_storeu_epi8&expand=5236) + * [x] [`_mm512_mask_div_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_pd&expand=5236) + * [x] [`_mm512_mask_div_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_ps&expand=5236) + * [x] [`_mm512_mask_div_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_round_pd&expand=5236) + * [x] [`_mm512_mask_div_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_round_ps&expand=5236) + * [ ] [`_mm512_mask_expand_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_epi32&expand=5236) + * [ ] [`_mm512_mask_expand_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_epi64&expand=5236) + * [ ] [`_mm512_mask_expand_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_pd&expand=5236) + * [ ] [`_mm512_mask_expand_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_ps&expand=5236) + * [ ] [`_mm512_mask_expandloadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi32&expand=5236) + * [ ] [`_mm512_mask_expandloadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi64&expand=5236) + * [ ] [`_mm512_mask_expandloadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_pd&expand=5236) + * [ ] [`_mm512_mask_expandloadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_ps&expand=5236) + * [ ] [`_mm512_mask_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extractf32x4_ps&expand=5236) + * [ ] [`_mm512_mask_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extractf64x4_pd&expand=5236) + * [ ] [`_mm512_mask_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extracti32x4_epi32&expand=5236) + * [ ] [`_mm512_mask_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extracti64x4_epi64&expand=5236) + * [ ] [`_mm512_mask_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_pd&expand=5236) + * [ ] [`_mm512_mask_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_ps&expand=5236) + * [ ] [`_mm512_mask_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_round_pd&expand=5236) + * [ ] [`_mm512_mask_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_round_ps&expand=5236) + * [x] [`_mm512_mask_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_pd&expand=5236) + * [x] [`_mm512_mask_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_ps&expand=5236) + * [x] [`_mm512_mask_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_round_pd&expand=5236) + * [x] [`_mm512_mask_fmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_round_ps&expand=5236) + * [x] [`_mm512_mask_fmaddsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmaddsub_pd&expand=5236) + * [x] [`_mm512_mask_fmaddsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmaddsub_ps&expand=5236) + * [x] [`_mm512_mask_fmaddsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmaddsub_round_pd&expand=5236) + * [x] [`_mm512_mask_fmaddsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmaddsub_round_ps&expand=5236) + * [x] [`_mm512_mask_fmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsub_pd&expand=5236) + * [x] [`_mm512_mask_fmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsub_ps&expand=5236) + * [x] [`_mm512_mask_fmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsub_round_pd&expand=5236) + * [x] [`_mm512_mask_fmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsub_round_ps&expand=5236) + * [x] [`_mm512_mask_fmsubadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsubadd_pd&expand=5236) + * [x] [`_mm512_mask_fmsubadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsubadd_ps&expand=5236) + * [x] [`_mm512_mask_fmsubadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsubadd_round_pd&expand=5236) + * [x] [`_mm512_mask_fmsubadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsubadd_round_ps&expand=5236) + * [x] [`_mm512_mask_fnmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmadd_pd&expand=5236) + * [x] [`_mm512_mask_fnmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmadd_ps&expand=5236) + * [x] [`_mm512_mask_fnmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmadd_round_pd&expand=5236) + * [x] [`_mm512_mask_fnmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmadd_round_ps&expand=5236) + * [x] [`_mm512_mask_fnmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmsub_pd&expand=5236) + * [x] [`_mm512_mask_fnmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmsub_ps&expand=5236) + * [x] [`_mm512_mask_fnmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmsub_round_pd&expand=5236) + * [x] [`_mm512_mask_fnmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmsub_round_ps&expand=5236) + * [x] [`_mm512_mask_getexp_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getexp_pd&expand=5236) + * [x] [`_mm512_mask_getexp_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getexp_ps&expand=5236) + * [x] [`_mm512_mask_getexp_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getexp_round_pd&expand=5236) + * [x] [`_mm512_mask_getexp_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getexp_round_ps&expand=5236) + * [x] [`_mm512_mask_getmant_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getmant_pd&expand=5236) + * [x] [`_mm512_mask_getmant_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getmant_ps&expand=5236) + * [x] [`_mm512_mask_getmant_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getmant_round_pd&expand=5236) + * [x] [`_mm512_mask_getmant_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getmant_round_ps&expand=5236) + * [ ] [`_mm512_mask_i32extgather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32extgather_epi32&expand=5236) + * [ ] [`_mm512_mask_i32extgather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32extgather_ps&expand=5236) + * [ ] [`_mm512_mask_i32extscatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32extscatter_epi32&expand=5236) + * [ ] [`_mm512_mask_i32extscatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32extscatter_ps&expand=5236) + * [x] [`_mm512_mask_i32gather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi32&expand=5236) + * [x] [`_mm512_mask_i32gather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi64&expand=5236) + * [x] [`_mm512_mask_i32gather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_pd&expand=5236) + * [x] [`_mm512_mask_i32gather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_ps&expand=5236) + * [ ] [`_mm512_mask_i32loextgather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loextgather_epi64&expand=5236) + * [ ] [`_mm512_mask_i32loextgather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loextgather_pd&expand=5236) + * [ ] [`_mm512_mask_i32loextscatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loextscatter_epi64&expand=5236) + * [ ] [`_mm512_mask_i32loextscatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loextscatter_pd&expand=5236) + * [ ] [`_mm512_mask_i32logather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32logather_epi64&expand=5236) + * [ ] [`_mm512_mask_i32logather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32logather_pd&expand=5236) + * [ ] [`_mm512_mask_i32loscatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loscatter_pd&expand=5236) + * [x] [`_mm512_mask_i32scatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi32&expand=5236) + * [x] [`_mm512_mask_i32scatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi64&expand=5236) + * [x] [`_mm512_mask_i32scatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_pd&expand=5236) + * [x] [`_mm512_mask_i32scatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_ps&expand=5236) + * [x] [`_mm512_mask_i64gather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi32&expand=5236) + * [x] [`_mm512_mask_i64gather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi64&expand=5236) + * [x] [`_mm512_mask_i64gather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_pd&expand=5236) + * [x] [`_mm512_mask_i64gather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_ps&expand=5236) + * [x] [`_mm512_mask_i64scatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi32&expand=5236) + * [x] [`_mm512_mask_i64scatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi64&expand=5236) + * [x] [`_mm512_mask_i64scatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_pd&expand=5236) + * [x] [`_mm512_mask_i64scatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_ps&expand=5236) + * [ ] [`_mm512_mask_insertf32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_insertf32x4&expand=5236) + * [ ] [`_mm512_mask_insertf64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_insertf64x4&expand=5236) + * [ ] [`_mm512_mask_inserti32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_inserti32x4&expand=5236) + * [ ] [`_mm512_mask_inserti64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_inserti64x4&expand=5236) + * [ ] [`_mm512_mask_load_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_load_epi32&expand=5236) + * [ ] [`_mm512_mask_load_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_load_epi64&expand=5236) + * [ ] [`_mm512_mask_load_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_load_pd&expand=5236) + * [ ] [`_mm512_mask_load_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_load_ps&expand=5236) + * [ ] [`_mm512_mask_loadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_loadu_epi32&expand=5236) + * [ ] [`_mm512_mask_loadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_loadu_epi64&expand=5236) + * [ ] [`_mm512_mask_loadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_loadu_pd&expand=5236) + * [ ] [`_mm512_mask_loadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_loadu_ps&expand=5236) + * [x] [`_mm512_mask_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epi32&expand=5236) + * [x] [`_mm512_mask_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epi64&expand=5236) + * [x] [`_mm512_mask_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epu32&expand=5236) + * [x] [`_mm512_mask_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epu64&expand=5236) + * [x] [`_mm512_mask_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_pd&expand=5236) + * [x] [`_mm512_mask_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_ps&expand=5236) + * [x] [`_mm512_mask_max_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_round_pd&expand=5236) + * [x] [`_mm512_mask_max_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_round_ps&expand=5236) + * [x] [`_mm512_mask_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epi32&expand=5236) + * [x] [`_mm512_mask_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epi64&expand=5236) + * [x] [`_mm512_mask_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epu32&expand=5236) + * [x] [`_mm512_mask_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epu64&expand=5236) + * [x] [`_mm512_mask_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_pd&expand=5236) + * [x] [`_mm512_mask_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_ps&expand=5236) + * [x] [`_mm512_mask_min_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_round_pd&expand=5236) + * [x] [`_mm512_mask_min_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_round_ps&expand=5236) + * [ ] [`_mm512_mask_mov_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi32&expand=5236) + * [ ] [`_mm512_mask_mov_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi64&expand=5236) + * [ ] [`_mm512_mask_mov_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_pd&expand=5236) + * [ ] [`_mm512_mask_mov_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_ps&expand=5236) + * [x] [`_mm512_mask_movedup_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_movedup_pd&expand=5236) + * [x] [`_mm512_mask_movehdup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_movehdup_ps&expand=5236) + * [x] [`_mm512_mask_moveldup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_moveldup_ps&expand=5236) + * [x] [`_mm512_mask_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_epi32&expand=5236) + * [x] [`_mm512_mask_mul_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_epu32&expand=5236) + * [x] [`_mm512_mask_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_pd&expand=5236) + * [x] [`_mm512_mask_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_ps&expand=5236) + * [x] [`_mm512_mask_mul_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_round_pd&expand=5236) + * [x] [`_mm512_mask_mul_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_round_ps&expand=5236) + * [x] [`_mm512_mask_mullo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mullo_epi32&expand=5236) + * [x] [`_mm512_mask_mullox_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mullox_epi64&expand=5236) + * [x] [`_mm512_mask_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_or_epi32&expand=5236) + * [x] [`_mm512_mask_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_or_epi64&expand=5236) + * [x] [`_mm512_mask_permute_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permute_pd&expand=5236) + * [x] [`_mm512_mask_permute_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permute_ps&expand=5236) + * [x] [`_mm512_mask_permutevar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutevar_epi32&expand=5236) + * [x] [`_mm512_mask_permutevar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutevar_pd&expand=5236) + * [x] [`_mm512_mask_permutevar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutevar_ps&expand=5236) + * [x] [`_mm512_mask_permutex2var_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex2var_epi32&expand=5236) + * [x] [`_mm512_mask_permutex2var_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex2var_epi64&expand=5236) + * [x] [`_mm512_mask_permutex2var_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex2var_pd&expand=5236) + * [x] [`_mm512_mask_permutex2var_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex2var_ps&expand=5236) + * [x] [`_mm512_mask_permutex_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex_epi64&expand=5236) + * [x] [`_mm512_mask_permutex_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex_pd&expand=5236) + * [x] [`_mm512_mask_permutexvar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_epi32&expand=5236) + * [x] [`_mm512_mask_permutexvar_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_epi64&expand=5236) + * [x] [`_mm512_mask_permutexvar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_pd&expand=5236) + * [x] [`_mm512_mask_permutexvar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_ps&expand=5236) + * [x] [`_mm512_mask_rcp14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rcp14_pd&expand=5236) + * [x] [`_mm512_mask_rcp14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rcp14_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_pd&expand=5236) + * [ ] [`_mm512_mask_reduce_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_and_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_and_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epu32&expand=5236) + * [ ] [`_mm512_mask_reduce_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epu64&expand=5236) + * [ ] [`_mm512_mask_reduce_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_pd&expand=5236) + * [ ] [`_mm512_mask_reduce_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epu32&expand=5236) + * [ ] [`_mm512_mask_reduce_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epu64&expand=5236) + * [ ] [`_mm512_mask_reduce_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_pd&expand=5236) + * [ ] [`_mm512_mask_reduce_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_mul_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_pd&expand=5236) + * [ ] [`_mm512_mask_reduce_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_or_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_or_epi64&expand=5236) + * [x] [`_mm512_mask_rol_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rol_epi32&expand=5236) + * [x] [`_mm512_mask_rol_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rol_epi64&expand=5236) + * [x] [`_mm512_mask_rolv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rolv_epi32&expand=5236) + * [x] [`_mm512_mask_rolv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rolv_epi64&expand=5236) + * [x] [`_mm512_mask_ror_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ror_epi32&expand=5236) + * [x] [`_mm512_mask_ror_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ror_epi64&expand=5236) + * [x] [`_mm512_mask_rorv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rorv_epi32&expand=5236) + * [x] [`_mm512_mask_rorv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rorv_epi64&expand=5236) + * [ ] [`_mm512_mask_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_pd&expand=5236) + * [ ] [`_mm512_mask_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_ps&expand=5236) + * [ ] [`_mm512_mask_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_round_pd&expand=5236) + * [ ] [`_mm512_mask_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_round_ps&expand=5236) + * [x] [`_mm512_mask_rsqrt14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rsqrt14_pd&expand=5236) + * [x] [`_mm512_mask_rsqrt14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rsqrt14_ps&expand=5236) + * [ ] [`_mm512_mask_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_pd&expand=5236) + * [ ] [`_mm512_mask_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_ps&expand=5236) + * [ ] [`_mm512_mask_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_round_pd&expand=5236) + * [ ] [`_mm512_mask_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_round_ps&expand=5236) + * [x] [`_mm512_mask_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_set1_epi32&expand=5236) + * [x] [`_mm512_mask_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_set1_epi64&expand=5236) + * [x] [`_mm512_mask_shuffle_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_epi32&expand=5236) + * [x] [`_mm512_mask_shuffle_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_f32x4&expand=5236) + * [x] [`_mm512_mask_shuffle_f64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_f64x2&expand=5236) + * [x] [`_mm512_mask_shuffle_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_i32x4&expand=5236) + * [x] [`_mm512_mask_shuffle_i64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_i64x2&expand=5236) + * [x] [`_mm512_mask_shuffle_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_pd&expand=5236) + * [x] [`_mm512_mask_shuffle_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_ps&expand=5236) + * [x] [`_mm512_mask_sll_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sll_epi32&expand=5236) + * [x] [`_mm512_mask_sll_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sll_epi64&expand=5236) + * [x] [`_mm512_mask_slli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_slli_epi32&expand=5236) + * [x] [`_mm512_mask_slli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_slli_epi64&expand=5236) + * [x] [`_mm512_mask_sllv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sllv_epi32&expand=5236) + * [x] [`_mm512_mask_sllv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sllv_epi64&expand=5236) + * [x] [`_mm512_mask_sqrt_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sqrt_pd&expand=5236) + * [x] [`_mm512_mask_sqrt_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sqrt_ps&expand=5236) + * [x] [`_mm512_mask_sqrt_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sqrt_round_pd&expand=5236) + * [x] [`_mm512_mask_sqrt_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sqrt_round_ps&expand=5236) + * [x] [`_mm512_mask_sra_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sra_epi32&expand=5236) + * [x] [`_mm512_mask_sra_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sra_epi64&expand=5236) + * [x] [`_mm512_mask_srai_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srai_epi32&expand=5236) + * [x] [`_mm512_mask_srai_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srai_epi64&expand=5236) + * [x] [`_mm512_mask_srav_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srav_epi32&expand=5236) + * [x] [`_mm512_mask_srav_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srav_epi64&expand=5236) + * [x] [`_mm512_mask_srl_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srl_epi32&expand=5236) + * [x] [`_mm512_mask_srl_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srl_epi64&expand=5236) + * [x] [`_mm512_mask_srli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srli_epi32&expand=5236) + * [x] [`_mm512_mask_srli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srli_epi64&expand=5236) + * [x] [`_mm512_mask_srlv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srlv_epi32&expand=5236) + * [x] [`_mm512_mask_srlv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srlv_epi64&expand=5236) + * [ ] [`_mm512_mask_store_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_store_epi32&expand=5236) + * [ ] [`_mm512_mask_store_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_store_epi64&expand=5236) + * [ ] [`_mm512_mask_store_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_store_pd&expand=5236) + * [ ] [`_mm512_mask_store_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_store_ps&expand=5236) + * [ ] [`_mm512_mask_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_storeu_epi32&expand=5236) + * [ ] [`_mm512_mask_storeu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_storeu_epi64&expand=5236) + * [ ] [`_mm512_mask_storeu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_storeu_pd&expand=5236) + * [ ] [`_mm512_mask_storeu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_storeu_ps&expand=5236) + * [x] [`_mm512_mask_sub_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_epi32&expand=5236) + * [x] [`_mm512_mask_sub_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_epi64&expand=5236) + * [x] [`_mm512_mask_sub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_pd&expand=5236) + * [x] [`_mm512_mask_sub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_ps&expand=5236) + * [x] [`_mm512_mask_sub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_round_pd&expand=5236) + * [x] [`_mm512_mask_sub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_round_ps&expand=5236) + * [ ] [`_mm512_mask_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ternarylogic_epi32&expand=5236) + * [ ] [`_mm512_mask_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ternarylogic_epi64&expand=5236) + * [ ] [`_mm512_mask_test_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi32_mask&expand=5236) + * [ ] [`_mm512_mask_test_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi64_mask&expand=5236) + * [ ] [`_mm512_mask_testn_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi32_mask&expand=5236) + * [ ] [`_mm512_mask_testn_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi64_mask&expand=5236) + * [ ] [`_mm512_mask_unpackhi_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_epi32&expand=5236) + * [ ] [`_mm512_mask_unpackhi_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_epi64&expand=5236) + * [ ] [`_mm512_mask_unpackhi_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_pd&expand=5236) + * [ ] [`_mm512_mask_unpackhi_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_ps&expand=5236) + * [ ] [`_mm512_mask_unpacklo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_epi32&expand=5236) + * [ ] [`_mm512_mask_unpacklo_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_epi64&expand=5236) + * [ ] [`_mm512_mask_unpacklo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_pd&expand=5236) + * [ ] [`_mm512_mask_unpacklo_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_ps&expand=5236) + * [x] [`_mm512_mask_xor_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_xor_epi32&expand=5236) + * [x] [`_mm512_mask_xor_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_xor_epi64&expand=5236) + * [x] [`_mm512_maskz_abs_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_abs_epi32&expand=5236) + * [x] [`_mm512_maskz_abs_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_abs_epi64&expand=5236) + * [x] [`_mm512_maskz_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_epi32&expand=5236) + * [x] [`_mm512_maskz_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_epi64&expand=5236) + * [x] [`_mm512_maskz_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_pd&expand=5236) + * [x] [`_mm512_maskz_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_ps&expand=5236) + * [x] [`_mm512_maskz_add_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_round_pd&expand=5236) + * [x] [`_mm512_maskz_add_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_round_ps&expand=5236) + * [ ] [`_mm512_maskz_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_alignr_epi32&expand=5236) + * [ ] [`_mm512_maskz_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_alignr_epi64&expand=5236) + * [x] [`_mm512_maskz_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_and_epi32&expand=5236) + * [x] [`_mm512_maskz_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_and_epi64&expand=5236) + * [ ] [`_mm512_maskz_andnot_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_andnot_epi32&expand=5236) + * [ ] [`_mm512_maskz_andnot_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_andnot_epi64&expand=5236) + * [ ] [`_mm512_maskz_broadcast_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcast_f32x4&expand=5236) + * [ ] [`_mm512_maskz_broadcast_f64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcast_f64x4&expand=5236) + * [ ] [`_mm512_maskz_broadcast_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcast_i32x4&expand=5236) + * [ ] [`_mm512_maskz_broadcast_i64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcast_i64x4&expand=5236) + * [ ] [`_mm512_maskz_broadcastd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastd_epi32&expand=5236) + * [ ] [`_mm512_maskz_broadcastq_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastq_epi64&expand=5236) + * [ ] [`_mm512_maskz_broadcastsd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastsd_pd&expand=5236) + * [ ] [`_mm512_maskz_broadcastss_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastss_ps&expand=5236) + * [ ] [`_mm512_maskz_compress_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_epi32&expand=5236) + * [ ] [`_mm512_maskz_compress_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_epi64&expand=5236) + * [ ] [`_mm512_maskz_compress_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_pd&expand=5236) + * [ ] [`_mm512_maskz_compress_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_ps&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundepi32_ps&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundepu32_ps&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_ps&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundph_ps&expand=5236) + * [x] [`_mm512_maskz_cvt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_epi32&expand=5236) + * [x] [`_mm512_maskz_cvt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_pd&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_ph&expand=5236) + * [ ] [`_mm512_maskz_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi16_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi16_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi8&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_pd&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_ps&expand=5236) + * [ ] [`_mm512_maskz_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi8&expand=5236) + * [ ] [`_mm512_maskz_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi8_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi8_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu16_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu16_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_pd&expand=5236) + * [ ] [`_mm512_maskz_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_ps&expand=5236) + * [ ] [`_mm512_maskz_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu8_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu8_epi64&expand=5236) + * [x] [`_mm512_maskz_cvtpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_ps&expand=5236) + * [ ] [`_mm512_maskz_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtph_ps&expand=5236) + * [x] [`_mm512_maskz_cvtps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_pd&expand=5236) + * [ ] [`_mm512_maskz_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_ph&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi32_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi32_epi8&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi8&expand=5236) + * [x] [`_mm512_maskz_cvtt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundpd_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundpd_epu32&expand=5236) + * [x] [`_mm512_maskz_cvtt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundps_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundps_epu32&expand=5236) + * [x] [`_mm512_maskz_cvttpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttpd_epi32&expand=5236) + * [x] [`_mm512_maskz_cvttpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttpd_epu32&expand=5236) + * [x] [`_mm512_maskz_cvttps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttps_epi32&expand=5236) + * [x] [`_mm512_maskz_cvttps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttps_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi32_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi32_epi8&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi8&expand=5236) + * [x] [`_mm512_maskz_div_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_pd&expand=5236) + * [x] [`_mm512_maskz_div_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_ps&expand=5236) + * [x] [`_mm512_maskz_div_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_round_pd&expand=5236) + * [x] [`_mm512_maskz_div_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_round_ps&expand=5236) + * [ ] [`_mm512_maskz_expand_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_epi32&expand=5236) + * [ ] [`_mm512_maskz_expand_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_epi64&expand=5236) + * [ ] [`_mm512_maskz_expand_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_pd&expand=5236) + * [ ] [`_mm512_maskz_expand_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_ps&expand=5236) + * [ ] [`_mm512_maskz_expandloadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi32&expand=5236) + * [ ] [`_mm512_maskz_expandloadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi64&expand=5236) + * [ ] [`_mm512_maskz_expandloadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_pd&expand=5236) + * [ ] [`_mm512_maskz_expandloadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_ps&expand=5236) + * [ ] [`_mm512_maskz_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extractf32x4_ps&expand=5236) + * [ ] [`_mm512_maskz_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extractf64x4_pd&expand=5236) + * [ ] [`_mm512_maskz_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extracti32x4_epi32&expand=5236) + * [ ] [`_mm512_maskz_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extracti64x4_epi64&expand=5236) + * [ ] [`_mm512_maskz_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_pd&expand=5236) + * [ ] [`_mm512_maskz_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_ps&expand=5236) + * [ ] [`_mm512_maskz_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_round_pd&expand=5236) + * [ ] [`_mm512_maskz_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_round_ps&expand=5236) + * [x] [`_mm512_maskz_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_pd&expand=5236) + * [x] [`_mm512_maskz_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_ps&expand=5236) + * [x] [`_mm512_maskz_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_round_pd&expand=5236) + * [x] [`_mm512_maskz_fmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_round_ps&expand=5236) + * [x] [`_mm512_maskz_fmaddsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmaddsub_pd&expand=5236) + * [x] [`_mm512_maskz_fmaddsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmaddsub_ps&expand=5236) + * [x] [`_mm512_maskz_fmaddsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmaddsub_round_pd&expand=5236) + * [x] [`_mm512_maskz_fmaddsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmaddsub_round_ps&expand=5236) + * [x] [`_mm512_maskz_fmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsub_pd&expand=5236) + * [x] [`_mm512_maskz_fmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsub_ps&expand=5236) + * [x] [`_mm512_maskz_fmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsub_round_pd&expand=5236) + * [x] [`_mm512_maskz_fmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsub_round_ps&expand=5236) + * [x] [`_mm512_maskz_fmsubadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsubadd_pd&expand=5236) + * [x] [`_mm512_maskz_fmsubadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsubadd_ps&expand=5236) + * [x] [`_mm512_maskz_fmsubadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsubadd_round_pd&expand=5236) + * [x] [`_mm512_maskz_fmsubadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsubadd_round_ps&expand=5236) + * [x] [`_mm512_maskz_fnmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmadd_pd&expand=5236) + * [x] [`_mm512_maskz_fnmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmadd_ps&expand=5236) + * [x] [`_mm512_maskz_fnmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmadd_round_pd&expand=5236) + * [x] [`_mm512_maskz_fnmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmadd_round_ps&expand=5236) + * [x] [`_mm512_maskz_fnmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmsub_pd&expand=5236) + * [x] [`_mm512_maskz_fnmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmsub_ps&expand=5236) + * [x] [`_mm512_maskz_fnmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmsub_round_pd&expand=5236) + * [x] [`_mm512_maskz_fnmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmsub_round_ps&expand=5236) + * [x] [`_mm512_maskz_getexp_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getexp_pd&expand=5236) + * [x] [`_mm512_maskz_getexp_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getexp_ps&expand=5236) + * [x] [`_mm512_maskz_getexp_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getexp_round_pd&expand=5236) + * [x] [`_mm512_maskz_getexp_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getexp_round_ps&expand=5236) + * [x] [`_mm512_maskz_getmant_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getmant_pd&expand=5236) + * [x] [`_mm512_maskz_getmant_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getmant_ps&expand=5236) + * [x] [`_mm512_maskz_getmant_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getmant_round_pd&expand=5236) + * [x] [`_mm512_maskz_getmant_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getmant_round_ps&expand=5236) + * [ ] [`_mm512_maskz_insertf32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_insertf32x4&expand=5236) + * [ ] [`_mm512_maskz_insertf64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_insertf64x4&expand=5236) + * [ ] [`_mm512_maskz_inserti32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_inserti32x4&expand=5236) + * [ ] [`_mm512_maskz_inserti64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_inserti64x4&expand=5236) + * [ ] [`_mm512_maskz_load_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_load_epi32&expand=5236) + * [ ] [`_mm512_maskz_load_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_load_epi64&expand=5236) + * [ ] [`_mm512_maskz_load_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_load_pd&expand=5236) + * [ ] [`_mm512_maskz_load_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_load_ps&expand=5236) + * [ ] [`_mm512_maskz_loadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_loadu_epi32&expand=5236) + * [ ] [`_mm512_maskz_loadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_loadu_epi64&expand=5236) + * [ ] [`_mm512_maskz_loadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_loadu_pd&expand=5236) + * [ ] [`_mm512_maskz_loadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_loadu_ps&expand=5236) + * [x] [`_mm512_maskz_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epi32&expand=5236) + * [x] [`_mm512_maskz_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epi64&expand=5236) + * [x] [`_mm512_maskz_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epu32&expand=5236) + * [x] [`_mm512_maskz_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epu64&expand=5236) + * [x] [`_mm512_maskz_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_pd&expand=5236) + * [x] [`_mm512_maskz_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_ps&expand=5236) + * [x] [`_mm512_maskz_max_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_round_pd&expand=5236) + * [x] [`_mm512_maskz_max_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_round_ps&expand=5236) + * [x] [`_mm512_maskz_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epi32&expand=5236) + * [x] [`_mm512_maskz_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epi64&expand=5236) + * [x] [`_mm512_maskz_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epu32&expand=5236) + * [x] [`_mm512_maskz_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epu64&expand=5236) + * [x] [`_mm512_maskz_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_pd&expand=5236) + * [x] [`_mm512_maskz_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_ps&expand=5236) + * [x] [`_mm512_maskz_min_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_round_pd&expand=5236) + * [x] [`_mm512_maskz_min_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_round_ps&expand=5236) + * [ ] [`_mm512_maskz_mov_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi32&expand=5236) + * [ ] [`_mm512_maskz_mov_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi64&expand=5236) + * [ ] [`_mm512_maskz_mov_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_pd&expand=5236) + * [ ] [`_mm512_maskz_mov_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_ps&expand=5236) + * [x] [`_mm512_maskz_movedup_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_movedup_pd&expand=5236) + * [x] [`_mm512_maskz_movehdup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_movehdup_ps&expand=5236) + * [x] [`_mm512_maskz_moveldup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_moveldup_ps&expand=5236) + * [x] [`_mm512_maskz_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_epi32&expand=5236) + * [x] [`_mm512_maskz_mul_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_epu32&expand=5236) + * [x] [`_mm512_maskz_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_pd&expand=5236) + * [x] [`_mm512_maskz_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_ps&expand=5236) + * [x] [`_mm512_maskz_mul_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_round_pd&expand=5236) + * [x] [`_mm512_maskz_mul_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_round_ps&expand=5236) + * [x] [`_mm512_maskz_mullo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mullo_epi32&expand=5236) + * [x] [`_mm512_maskz_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_or_epi32&expand=5236) + * [x] [`_mm512_maskz_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_or_epi64&expand=5236) + * [x] [`_mm512_maskz_permute_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permute_pd&expand=5236) + * [x] [`_mm512_maskz_permute_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permute_ps&expand=5236) + * [x] [`_mm512_maskz_permutevar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutevar_pd&expand=5236) + * [x] [`_mm512_maskz_permutevar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutevar_ps&expand=5236) + * [x] [`_mm512_maskz_permutex2var_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex2var_epi32&expand=5236) + * [x] [`_mm512_maskz_permutex2var_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex2var_epi64&expand=5236) + * [x] [`_mm512_maskz_permutex2var_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex2var_pd&expand=5236) + * [x] [`_mm512_maskz_permutex2var_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex2var_ps&expand=5236) + * [x] [`_mm512_maskz_permutex_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex_epi64&expand=5236) + * [x] [`_mm512_maskz_permutex_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex_pd&expand=5236) + * [x] [`_mm512_maskz_permutexvar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutexvar_epi32&expand=5236) + * [x] [`_mm512_maskz_permutexvar_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutexvar_epi64&expand=5236) + * [x] [`_mm512_maskz_permutexvar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutexvar_pd&expand=5236) + * [x] [`_mm512_maskz_permutexvar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutexvar_ps&expand=5236) + * [x] [`_mm512_maskz_rcp14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rcp14_pd&expand=5236) + * [x] [`_mm512_maskz_rcp14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rcp14_ps&expand=5236) + * [x] [`_mm512_maskz_rol_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rol_epi32&expand=5236) + * [x] [`_mm512_maskz_rol_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rol_epi64&expand=5236) + * [x] [`_mm512_maskz_rolv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rolv_epi32&expand=5236) + * [x] [`_mm512_maskz_rolv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rolv_epi64&expand=5236) + * [x] [`_mm512_maskz_ror_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ror_epi32&expand=5236) + * [x] [`_mm512_maskz_ror_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ror_epi64&expand=5236) + * [x] [`_mm512_maskz_rorv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rorv_epi32&expand=5236) + * [x] [`_mm512_maskz_rorv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rorv_epi64&expand=5236) + * [ ] [`_mm512_maskz_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_pd&expand=5236) + * [ ] [`_mm512_maskz_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_ps&expand=5236) + * [ ] [`_mm512_maskz_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_round_pd&expand=5236) + * [ ] [`_mm512_maskz_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_round_ps&expand=5236) + * [x] [`_mm512_maskz_rsqrt14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rsqrt14_pd&expand=5236) + * [x] [`_mm512_maskz_rsqrt14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rsqrt14_ps&expand=5236) + * [ ] [`_mm512_maskz_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_pd&expand=5236) + * [ ] [`_mm512_maskz_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_ps&expand=5236) + * [ ] [`_mm512_maskz_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_round_pd&expand=5236) + * [ ] [`_mm512_maskz_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_round_ps&expand=5236) + * [ ] [`_mm512_maskz_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi32&expand=5236) + * [ ] [`_mm512_maskz_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi64&expand=5236) + * [x] [`_mm512_maskz_shuffle_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_epi32&expand=5236) + * [x] [`_mm512_maskz_shuffle_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_f32x4&expand=5236) + * [x] [`_mm512_maskz_shuffle_f64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_f64x2&expand=5236) + * [x] [`_mm512_maskz_shuffle_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_i32x4&expand=5236) + * [x] [`_mm512_maskz_shuffle_i64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_i64x2&expand=5236) + * [x] [`_mm512_maskz_shuffle_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_pd&expand=5236) + * [x] [`_mm512_maskz_shuffle_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_ps&expand=5236) + * [x] [`_mm512_maskz_sll_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sll_epi32&expand=5236) + * [x] [`_mm512_maskz_sll_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sll_epi64&expand=5236) + * [x] [`_mm512_maskz_slli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_slli_epi32&expand=5236) + * [x] [`_mm512_maskz_slli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_slli_epi64&expand=5236) + * [x] [`_mm512_maskz_sllv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sllv_epi32&expand=5236) + * [x] [`_mm512_maskz_sllv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sllv_epi64&expand=5236) + * [x] [`_mm512_maskz_sqrt_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sqrt_pd&expand=5236) + * [x] [`_mm512_maskz_sqrt_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sqrt_ps&expand=5236) + * [x] [`_mm512_maskz_sqrt_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sqrt_round_pd&expand=5236) + * [x] [`_mm512_maskz_sqrt_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sqrt_round_ps&expand=5236) + * [x] [`_mm512_maskz_sra_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sra_epi32&expand=5236) + * [x] [`_mm512_maskz_sra_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sra_epi64&expand=5236) + * [x] [`_mm512_maskz_srai_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srai_epi32&expand=5236) + * [x] [`_mm512_maskz_srai_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srai_epi64&expand=5236) + * [x] [`_mm512_maskz_srav_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srav_epi32&expand=5236) + * [x] [`_mm512_maskz_srav_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srav_epi64&expand=5236) + * [x] [`_mm512_maskz_srl_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srl_epi32&expand=5236) + * [x] [`_mm512_maskz_srl_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srl_epi64&expand=5236) + * [x] [`_mm512_maskz_srli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srli_epi32&expand=5236) + * [x] [`_mm512_maskz_srli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srli_epi64&expand=5236) + * [x] [`_mm512_maskz_srlv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srlv_epi32&expand=5236) + * [x] [`_mm512_maskz_srlv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srlv_epi64&expand=5236) + * [x] [`_mm512_maskz_sub_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_epi32&expand=5236) + * [x] [`_mm512_maskz_sub_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_epi64&expand=5236) + * [x] [`_mm512_maskz_sub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_pd&expand=5236) + * [x] [`_mm512_maskz_sub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_ps&expand=5236) + * [x] [`_mm512_maskz_sub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_round_pd&expand=5236) + * [x] [`_mm512_maskz_sub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_round_ps&expand=5236) + * [ ] [`_mm512_maskz_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ternarylogic_epi32&expand=5236) + * [ ] [`_mm512_maskz_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ternarylogic_epi64&expand=5236) + * [ ] [`_mm512_maskz_unpackhi_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_epi32&expand=5236) + * [ ] [`_mm512_maskz_unpackhi_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_epi64&expand=5236) + * [ ] [`_mm512_maskz_unpackhi_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_pd&expand=5236) + * [ ] [`_mm512_maskz_unpackhi_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_ps&expand=5236) + * [ ] [`_mm512_maskz_unpacklo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_epi32&expand=5236) + * [ ] [`_mm512_maskz_unpacklo_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_epi64&expand=5236) + * [ ] [`_mm512_maskz_unpacklo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_pd&expand=5236) + * [ ] [`_mm512_maskz_unpacklo_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_ps&expand=5236) + * [x] [`_mm512_maskz_xor_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_xor_epi32&expand=5236) + * [x] [`_mm512_maskz_xor_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_xor_epi64&expand=5236) + * [x] [`_mm512_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epi32&expand=5236) + * [x] [`_mm512_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epi64&expand=5236) + * [x] [`_mm512_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epu32&expand=5236) + * [x] [`_mm512_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epu64&expand=5236) + * [x] [`_mm512_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_pd&expand=5236) + * [x] [`_mm512_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_ps&expand=5236) + * [x] [`_mm512_max_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_round_pd&expand=5236) + * [x] [`_mm512_max_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_round_ps&expand=5236) + * [x] [`_mm512_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epi32&expand=5236) + * [x] [`_mm512_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epi64&expand=5236) + * [x] [`_mm512_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epu32&expand=5236) + * [x] [`_mm512_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epu64&expand=5236) + * [x] [`_mm512_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_pd&expand=5236) + * [x] [`_mm512_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_ps&expand=5236) + * [x] [`_mm512_min_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_round_pd&expand=5236) + * [x] [`_mm512_min_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_round_ps&expand=5236) + * [x] [`_mm512_movedup_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movedup_pd&expand=5236) + * [x] [`_mm512_movehdup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movehdup_ps&expand=5236) + * [x] [`_mm512_moveldup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_moveldup_ps&expand=5236) + * [x] [`_mm512_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_epi32&expand=5236) + * [x] [`_mm512_mul_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_epu32&expand=5236) + * [x] [`_mm512_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_pd&expand=5236) + * [x] [`_mm512_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_ps&expand=5236) + * [x] [`_mm512_mul_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_round_pd&expand=5236) + * [x] [`_mm512_mul_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_round_ps&expand=5236) + * [x] [`_mm512_mullo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mullo_epi32&expand=5236) + * [x] [`_mm512_mullox_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mullox_epi64&expand=5236) + * [x] [`_mm512_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_or_epi32&expand=5236) + * [x] [`_mm512_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_or_epi64&expand=5236) + * [x] [`_mm512_or_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_or_si512&expand=5236) + * [x] [`_mm512_permute_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permute_pd&expand=5236) + * [x] [`_mm512_permute_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permute_ps&expand=5236) + * [x] [`_mm512_permutevar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutevar_epi32&expand=5236) + * [x] [`_mm512_permutevar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutevar_pd&expand=5236) + * [x] [`_mm512_permutevar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutevar_ps&expand=5236) + * [x] [`_mm512_permutex2var_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex2var_epi32&expand=5236) + * [x] [`_mm512_permutex2var_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex2var_epi64&expand=5236) + * [x] [`_mm512_permutex2var_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex2var_pd&expand=5236) + * [x] [`_mm512_permutex2var_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex2var_ps&expand=5236) + * [x] [`_mm512_permutex_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex_epi64&expand=5236) + * [x] [`_mm512_permutex_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex_pd&expand=5236) + * [x] [`_mm512_permutexvar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_epi32&expand=5236) + * [x] [`_mm512_permutexvar_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_epi64&expand=5236) + * [x] [`_mm512_permutexvar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_pd&expand=5236) + * [x] [`_mm512_permutexvar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_ps&expand=5236) + * [x] [`_mm512_rcp14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rcp14_pd&expand=5236) + * [x] [`_mm512_rcp14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rcp14_ps&expand=5236) + * [ ] [`_mm512_reduce_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_epi32&expand=5236) + * [ ] [`_mm512_reduce_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_epi64&expand=5236) + * [ ] [`_mm512_reduce_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_pd&expand=5236) + * [ ] [`_mm512_reduce_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_ps&expand=5236) + * [ ] [`_mm512_reduce_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_and_epi32&expand=5236) + * [ ] [`_mm512_reduce_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_and_epi64&expand=5236) + * [ ] [`_mm512_reduce_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epi32&expand=5236) + * [ ] [`_mm512_reduce_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epi64&expand=5236) + * [ ] [`_mm512_reduce_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epu32&expand=5236) + * [ ] [`_mm512_reduce_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epu64&expand=5236) + * [ ] [`_mm512_reduce_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_pd&expand=5236) + * [ ] [`_mm512_reduce_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_ps&expand=5236) + * [ ] [`_mm512_reduce_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epi32&expand=5236) + * [ ] [`_mm512_reduce_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epi64&expand=5236) + * [ ] [`_mm512_reduce_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epu32&expand=5236) + * [ ] [`_mm512_reduce_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epu64&expand=5236) + * [ ] [`_mm512_reduce_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_pd&expand=5236) + * [ ] [`_mm512_reduce_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_ps&expand=5236) + * [ ] [`_mm512_reduce_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_epi32&expand=5236) + * [ ] [`_mm512_reduce_mul_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_epi64&expand=5236) + * [ ] [`_mm512_reduce_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_pd&expand=5236) + * [ ] [`_mm512_reduce_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_ps&expand=5236) + * [ ] [`_mm512_reduce_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_or_epi32&expand=5236) + * [ ] [`_mm512_reduce_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_or_epi64&expand=5236) + * [x] [`_mm512_rol_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rol_epi32&expand=5236) + * [x] [`_mm512_rol_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rol_epi64&expand=5236) + * [x] [`_mm512_rolv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rolv_epi32&expand=5236) + * [x] [`_mm512_rolv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rolv_epi64&expand=5236) + * [x] [`_mm512_ror_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ror_epi32&expand=5236) + * [x] [`_mm512_ror_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ror_epi64&expand=5236) + * [x] [`_mm512_rorv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rorv_epi32&expand=5236) + * [x] [`_mm512_rorv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rorv_epi64&expand=5236) + * [ ] [`_mm512_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_pd&expand=5236) + * [ ] [`_mm512_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_ps&expand=5236) + * [ ] [`_mm512_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_round_pd&expand=5236) + * [ ] [`_mm512_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_round_ps&expand=5236) + * [x] [`_mm512_rsqrt14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rsqrt14_pd&expand=5236) + * [x] [`_mm512_rsqrt14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rsqrt14_ps&expand=5236) + * [ ] [`_mm512_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_pd&expand=5236) + * [ ] [`_mm512_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_ps&expand=5236) + * [ ] [`_mm512_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_round_pd&expand=5236) + * [ ] [`_mm512_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_round_ps&expand=5236) + * [ ] [`_mm512_set1_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi16&expand=5236) + * [ ] [`_mm512_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi32&expand=5236) + * [ ] [`_mm512_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi64&expand=5236) + * [ ] [`_mm512_set1_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi8&expand=5236) + * [ ] [`_mm512_set1_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_pd&expand=5236) + * [ ] [`_mm512_set1_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_ps&expand=5236) + * [ ] [`_mm512_set4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_epi32&expand=5236) + * [ ] [`_mm512_set4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_epi64&expand=5236) + * [ ] [`_mm512_set4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_pd&expand=5236) + * [ ] [`_mm512_set4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_ps&expand=5236) + * [ ] [`_mm512_set_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi16&expand=5236) + * [ ] [`_mm512_set_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi32&expand=5236) + * [x] [`_mm512_set_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi64&expand=5236) + * [ ] [`_mm512_set_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi8&expand=5236) + * [x] [`_mm512_set_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_pd&expand=5236) + * [x] [`_mm512_set_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_ps&expand=5236) + * [ ] [`_mm512_setr4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_epi32&expand=5236) + * [ ] [`_mm512_setr4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_epi64&expand=5236) + * [ ] [`_mm512_setr4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_pd&expand=5236) + * [ ] [`_mm512_setr4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_ps&expand=5236) + * [x] [`_mm512_setr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_epi32&expand=5236) + * [x] [`_mm512_setr_epi64`](https:/software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_epi64&expand=5236) + * [x] [`_mm512_setr_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_pd&expand=5236) + * [x] [`_mm512_setr_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_ps&expand=5236) + * [ ] [`_mm512_setzero_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_epi32&expand=5236) + * [x] [`_mm512_setzero_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_pd&expand=5236) + * [x] [`_mm512_setzero_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_ps&expand=5236) + * [x] [`_mm512_setzero_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_si512&expand=5236) + * [ ] [`_mm512_setzero`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero&expand=5236) + * [x] [`_mm512_shuffle_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_epi32&expand=5236) + * [x] [`_mm512_shuffle_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_f32x4&expand=5236) + * [x] [`_mm512_shuffle_f64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_f64x2&expand=5236) + * [x] [`_mm512_shuffle_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_i32x4&expand=5236) + * [x] [`_mm512_shuffle_i64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_i64x2&expand=5236) + * [x] [`_mm512_shuffle_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_pd&expand=5236) + * [x] [`_mm512_shuffle_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_ps&expand=5236) + * [x] [`_mm512_sll_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sll_epi32&expand=5236) + * [x] [`_mm512_sll_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sll_epi64&expand=5236) + * [x] [`_mm512_slli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_slli_epi32&expand=5236) + * [x] [`_mm512_slli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_slli_epi64&expand=5236) + * [x] [`_mm512_sllv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sllv_epi32&expand=5236) + * [x] [`_mm512_sllv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sllv_epi64&expand=5236) + * [x] [`_mm512_sqrt_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sqrt_pd&expand=5236) + * [x] [`_mm512_sqrt_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sqrt_ps&expand=5236) + * [x] [`_mm512_sqrt_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sqrt_round_pd&expand=5236) + * [x] [`_mm512_sqrt_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sqrt_round_ps&expand=5236) + * [x] [`_mm512_sra_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sra_epi32&expand=5236) + * [x] [`_mm512_sra_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sra_epi64&expand=5236) + * [x] [`_mm512_srai_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srai_epi32&expand=5236) + * [x] [`_mm512_srai_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srai_epi64&expand=5236) + * [x] [`_mm512_srav_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srav_epi32&expand=5236) + * [x] [`_mm512_srav_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srav_epi64&expand=5236) + * [x] [`_mm512_srl_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srl_epi32&expand=5236) + * [x] [`_mm512_srl_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srl_epi64&expand=5236) + * [x] [`_mm512_srli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srli_epi32&expand=5236) + * [x] [`_mm512_srli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srli_epi64&expand=5236) + * [x] [`_mm512_srlv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srlv_epi32&expand=5236) + * [x] [`_mm512_srlv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srlv_epi64&expand=5236) + * [ ] [`_mm512_store_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_epi32&expand=5236) + * [ ] [`_mm512_store_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_epi64&expand=5236) + * [ ] [`_mm512_store_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_pd&expand=5236) + * [ ] [`_mm512_store_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_ps&expand=5236) + * [ ] [`_mm512_store_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_si512&expand=5236) + * [x] [`_mm512_storeu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_pd&expand=5236) + * [x] [`_mm512_storeu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_ps&expand=5236) + * [ ] [`_mm512_storeu_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_si512&expand=5236) + * [ ] [`_mm512_stream_load_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_load_si512&expand=5236) + * [ ] [`_mm512_stream_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_pd&expand=5236) + * [ ] [`_mm512_stream_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_ps&expand=5236) + * [ ] [`_mm512_stream_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_si512&expand=5236) + * [x] [`_mm512_sub_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_epi32&expand=5236) + * [x] [`_mm512_sub_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_epi64&expand=5236) + * [x] [`_mm512_sub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_pd&expand=5236) + * [x] [`_mm512_sub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_ps&expand=5236) + * [x] [`_mm512_sub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_round_pd&expand=5236) + * [x] [`_mm512_sub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_round_ps&expand=5236) + * [ ] [`_mm512_svml_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_svml_round_pd&expand=5236) + * [ ] [`_mm512_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ternarylogic_epi32&expand=5236) + * [ ] [`_mm512_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ternarylogic_epi64&expand=5236) + * [ ] [`_mm512_test_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi32_mask&expand=5236) + * [ ] [`_mm512_test_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi64_mask&expand=5236) + * [ ] [`_mm512_testn_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi32_mask&expand=5236) + * [ ] [`_mm512_testn_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi64_mask&expand=5236) + * [ ] [`_mm512_undefined_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_epi32&expand=5236) + * [x] [`_mm512_undefined_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_pd&expand=5236) + * [x] [`_mm512_undefined_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_ps&expand=5236) + * [ ] [`_mm512_undefined`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined&expand=5236) + * [ ] [`_mm512_unpackhi_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_epi32&expand=5236) + * [ ] [`_mm512_unpackhi_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_epi64&expand=5236) + * [ ] [`_mm512_unpackhi_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_pd&expand=5236) + * [ ] [`_mm512_unpackhi_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_ps&expand=5236) + * [ ] [`_mm512_unpacklo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_epi32&expand=5236) + * [ ] [`_mm512_unpacklo_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_epi64&expand=5236) + * [ ] [`_mm512_unpacklo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_pd&expand=5236) + * [ ] [`_mm512_unpacklo_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_ps&expand=5236) + * [x] [`_mm512_xor_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_xor_epi32&expand=5236) + * [x] [`_mm512_xor_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_xor_epi64&expand=5236) + * [x] [`_mm512_xor_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_xor_si512&expand=5236) + * [ ] [`_mm512_zextpd128_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextpd128_pd512&expand=5236) + * [ ] [`_mm512_zextpd256_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextpd256_pd512&expand=5236) + * [ ] [`_mm512_zextps128_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextps128_ps512&expand=5236) + * [ ] [`_mm512_zextps256_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextps256_ps512&expand=5236) + * [ ] [`_mm512_zextsi128_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextsi128_si512&expand=5236) + * [ ] [`_mm512_zextsi256_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextsi256_si512&expand=5236) + * [ ] [`_mm_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_sd&expand=5236) + * [ ] [`_mm_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_ss&expand=5236) + * [x] [`_mm_cmp_round_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_sd_mask&expand=5236) + * [x] [`_mm_cmp_round_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_ss_mask&expand=5236) + * [x] [`_mm_cmp_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_sd_mask&expand=5236) + * [x] [`_mm_cmp_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_ss_mask&expand=5236) + * [ ] [`_mm_comi_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comi_round_sd&expand=5236) + * [ ] [`_mm_comi_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comi_round_ss&expand=5236) + * [ ] [`_mm_cvt_roundi32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi32_ss&expand=5236) + * [ ] [`_mm_cvt_roundi64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi64_sd&expand=5236) + * [ ] [`_mm_cvt_roundi64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi64_ss&expand=5236) + * [ ] [`_mm_cvt_roundsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_i32&expand=5236) + * [ ] [`_mm_cvt_roundsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_i64&expand=5236) + * [ ] [`_mm_cvt_roundsd_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_si32&expand=5236) + * [ ] [`_mm_cvt_roundsd_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_si64&expand=5236) + * [ ] [`_mm_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_ss&expand=5236) + * [ ] [`_mm_cvt_roundsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_u32&expand=5236) + * [ ] [`_mm_cvt_roundsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_u64&expand=5236) + * [ ] [`_mm_cvt_roundsi32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi32_ss&expand=5236) + * [ ] [`_mm_cvt_roundsi64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi64_sd&expand=5236) + * [ ] [`_mm_cvt_roundsi64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi64_ss&expand=5236) + * [ ] [`_mm_cvt_roundss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_i32&expand=5236) + * [ ] [`_mm_cvt_roundss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_i64&expand=5236) + * [ ] [`_mm_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_sd&expand=5236) + * [ ] [`_mm_cvt_roundss_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_si32&expand=5236) + * [ ] [`_mm_cvt_roundss_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_si64&expand=5236) + * [ ] [`_mm_cvt_roundss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_u32&expand=5236) + * [ ] [`_mm_cvt_roundss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_u64&expand=5236) + * [ ] [`_mm_cvt_roundu32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu32_ss&expand=5236) + * [ ] [`_mm_cvt_roundu64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu64_sd&expand=5236) + * [ ] [`_mm_cvt_roundu64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu64_ss&expand=5236) + * [ ] [`_mm_cvti32_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti32_sd&expand=5236) + * [ ] [`_mm_cvti32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti32_ss&expand=5236) + * [ ] [`_mm_cvti64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti64_sd&expand=5236) + * [ ] [`_mm_cvti64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti64_ss&expand=5236) + * [ ] [`_mm_cvtsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_i32&expand=5236) + * [ ] [`_mm_cvtsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_i64&expand=5236) + * [ ] [`_mm_cvtsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_u32&expand=5236) + * [ ] [`_mm_cvtsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_u64&expand=5236) + * [ ] [`_mm_cvtss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_i32&expand=5236) + * [ ] [`_mm_cvtss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_i64&expand=5236) + * [ ] [`_mm_cvtss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_u32&expand=5236) + * [ ] [`_mm_cvtss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_u64&expand=5236) + * [ ] [`_mm_cvtt_roundsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_i32&expand=5236) + * [ ] [`_mm_cvtt_roundsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_i64&expand=5236) + * [ ] [`_mm_cvtt_roundsd_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_si32&expand=5236) + * [ ] [`_mm_cvtt_roundsd_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_si64&expand=5236) + * [ ] [`_mm_cvtt_roundsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_u32&expand=5236) + * [ ] [`_mm_cvtt_roundsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_u64&expand=5236) + * [ ] [`_mm_cvtt_roundss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_i32&expand=5236) + * [ ] [`_mm_cvtt_roundss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_i64&expand=5236) + * [ ] [`_mm_cvtt_roundss_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_si32&expand=5236) + * [ ] [`_mm_cvtt_roundss_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_si64&expand=5236) + * [ ] [`_mm_cvtt_roundss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_u32&expand=5236) + * [ ] [`_mm_cvtt_roundss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_u64&expand=5236) + * [ ] [`_mm_cvttsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_i32&expand=5236) + * [ ] [`_mm_cvttsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_i64&expand=5236) + * [ ] [`_mm_cvttsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_u32&expand=5236) + * [ ] [`_mm_cvttsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_u64&expand=5236) + * [ ] [`_mm_cvttss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_i32&expand=5236) + * [ ] [`_mm_cvttss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_i64&expand=5236) + * [ ] [`_mm_cvttss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_u32&expand=5236) + * [ ] [`_mm_cvttss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_u64&expand=5236) + * [ ] [`_mm_cvtu32_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu32_sd&expand=5236) + * [ ] [`_mm_cvtu32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu32_ss&expand=5236) + * [ ] [`_mm_cvtu64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_sd&expand=5236) + * [ ] [`_mm_cvtu64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_ss&expand=5236) + * [ ] [`_mm_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_round_sd&expand=5236) + * [ ] [`_mm_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_round_ss&expand=5236) + * [ ] [`_mm_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_round_sd&expand=5236) + * [ ] [`_mm_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_round_ss&expand=5236) + * [ ] [`_mm_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_sd&expand=5236) + * [ ] [`_mm_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_ss&expand=5236) + * [ ] [`_mm_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd_round_sd&expand=5236) + * [ ] [`_mm_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd_round_ss&expand=5236) + * [ ] [`_mm_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmsub_round_sd&expand=5236) + * [ ] [`_mm_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmsub_round_ss&expand=5236) + * [ ] [`_mm_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmadd_round_sd&expand=5236) + * [ ] [`_mm_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmadd_round_ss&expand=5236) + * [ ] [`_mm_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmsub_round_sd&expand=5236) + * [ ] [`_mm_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmsub_round_ss&expand=5236) + * [ ] [`_mm_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_round_sd&expand=5236) + * [ ] [`_mm_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_round_ss&expand=5236) + * [ ] [`_mm_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_sd&expand=5236) + * [ ] [`_mm_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_ss&expand=5236) + * [ ] [`_mm_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_round_sd&expand=5236) + * [ ] [`_mm_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_round_ss&expand=5236) + * [ ] [`_mm_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_sd&expand=5236) + * [ ] [`_mm_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_ss&expand=5236) + * [ ] [`_mm_mask3_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_round_sd&expand=5236) + * [ ] [`_mm_mask3_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_round_ss&expand=5236) + * [ ] [`_mm_mask3_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_sd&expand=5236) + * [ ] [`_mm_mask3_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_ss&expand=5236) + * [ ] [`_mm_mask3_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_round_sd&expand=5236) + * [ ] [`_mm_mask3_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_round_ss&expand=5236) + * [ ] [`_mm_mask3_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_sd&expand=5236) + * [ ] [`_mm_mask3_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_ss&expand=5236) + * [ ] [`_mm_mask3_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_round_sd&expand=5236) + * [ ] [`_mm_mask3_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_round_ss&expand=5236) + * [ ] [`_mm_mask3_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_sd&expand=5236) + * [ ] [`_mm_mask3_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_ss&expand=5236) + * [ ] [`_mm_mask3_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_round_sd&expand=5236) + * [ ] [`_mm_mask3_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_round_ss&expand=5236) + * [ ] [`_mm_mask3_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_sd&expand=5236) + * [ ] [`_mm_mask3_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_ss&expand=5236) + * [ ] [`_mm_mask_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_round_sd&expand=5236) + * [ ] [`_mm_mask_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_round_ss&expand=5236) + * [ ] [`_mm_mask_add_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_sd&expand=5236) + * [ ] [`_mm_mask_add_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_ss&expand=5236) + * [x] [`_mm_mask_cmp_round_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_sd_mask&expand=5236) + * [x] [`_mm_mask_cmp_round_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_ss_mask&expand=5236) + * [x] [`_mm_mask_cmp_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_sd_mask&expand=5236) + * [x] [`_mm_mask_cmp_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_ss_mask&expand=5236) + * [ ] [`_mm_mask_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvt_roundsd_ss&expand=5236) + * [ ] [`_mm_mask_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvt_roundss_sd&expand=5236) + * [ ] [`_mm_mask_cvtsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvtsd_ss&expand=5236) + * [ ] [`_mm_mask_cvtss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvtss_sd&expand=5236) + * [ ] [`_mm_mask_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_round_sd&expand=5236) + * [ ] [`_mm_mask_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_round_ss&expand=5236) + * [ ] [`_mm_mask_div_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_sd&expand=5236) + * [ ] [`_mm_mask_div_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_ss&expand=5236) + * [ ] [`_mm_mask_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_round_sd&expand=5236) + * [ ] [`_mm_mask_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_round_ss&expand=5236) + * [ ] [`_mm_mask_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_sd&expand=5236) + * [ ] [`_mm_mask_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_ss&expand=5236) + * [ ] [`_mm_mask_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_round_sd&expand=5236) + * [ ] [`_mm_mask_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_round_ss&expand=5236) + * [ ] [`_mm_mask_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_sd&expand=5236) + * [ ] [`_mm_mask_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_ss&expand=5236) + * [ ] [`_mm_mask_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_round_sd&expand=5236) + * [ ] [`_mm_mask_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_round_ss&expand=5236) + * [ ] [`_mm_mask_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_sd&expand=5236) + * [ ] [`_mm_mask_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_ss&expand=5236) + * [ ] [`_mm_mask_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_round_sd&expand=5236) + * [ ] [`_mm_mask_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_round_ss&expand=5236) + * [ ] [`_mm_mask_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_sd&expand=5236) + * [ ] [`_mm_mask_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_ss&expand=5236) + * [ ] [`_mm_mask_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_round_sd&expand=5236) + * [ ] [`_mm_mask_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_round_ss&expand=5236) + * [ ] [`_mm_mask_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_sd&expand=5236) + * [ ] [`_mm_mask_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_ss&expand=5236) + * [ ] [`_mm_mask_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_round_sd&expand=5236) + * [ ] [`_mm_mask_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_round_ss&expand=5236) + * [ ] [`_mm_mask_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_sd&expand=5236) + * [ ] [`_mm_mask_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_ss&expand=5236) + * [ ] [`_mm_mask_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_round_sd&expand=5236) + * [ ] [`_mm_mask_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_round_ss&expand=5236) + * [ ] [`_mm_mask_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_sd&expand=5236) + * [ ] [`_mm_mask_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_ss&expand=5236) + * [ ] [`_mm_mask_load_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_load_sd&expand=5236) + * [ ] [`_mm_mask_load_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_load_ss&expand=5236) + * [ ] [`_mm_mask_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_round_sd&expand=5236) + * [ ] [`_mm_mask_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_round_ss&expand=5236) + * [ ] [`_mm_mask_max_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_sd&expand=5236) + * [ ] [`_mm_mask_max_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_ss&expand=5236) + * [ ] [`_mm_mask_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_round_sd&expand=5236) + * [ ] [`_mm_mask_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_round_ss&expand=5236) + * [ ] [`_mm_mask_min_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_sd&expand=5236) + * [ ] [`_mm_mask_min_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_ss&expand=5236) + * [ ] [`_mm_mask_move_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_move_sd&expand=5236) + * [ ] [`_mm_mask_move_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_move_ss&expand=5236) + * [ ] [`_mm_mask_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_round_sd&expand=5236) + * [ ] [`_mm_mask_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_round_ss&expand=5236) + * [ ] [`_mm_mask_mul_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_sd&expand=5236) + * [ ] [`_mm_mask_mul_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_ss&expand=5236) + * [ ] [`_mm_mask_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rcp14_sd&expand=5236) + * [ ] [`_mm_mask_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rcp14_ss&expand=5236) + * [ ] [`_mm_mask_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_round_sd&expand=5236) + * [ ] [`_mm_mask_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_round_ss&expand=5236) + * [ ] [`_mm_mask_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_sd&expand=5236) + * [ ] [`_mm_mask_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_ss&expand=5236) + * [ ] [`_mm_mask_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rsqrt14_sd&expand=5236) + * [ ] [`_mm_mask_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rsqrt14_ss&expand=5236) + * [ ] [`_mm_mask_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_round_sd&expand=5236) + * [ ] [`_mm_mask_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_round_ss&expand=5236) + * [ ] [`_mm_mask_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_sd&expand=5236) + * [ ] [`_mm_mask_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_ss&expand=5236) + * [ ] [`_mm_mask_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_round_sd&expand=5236) + * [ ] [`_mm_mask_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_round_ss&expand=5236) + * [ ] [`_mm_mask_sqrt_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_sd&expand=5236) + * [ ] [`_mm_mask_sqrt_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_ss&expand=5236) + * [ ] [`_mm_mask_store_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_store_sd&expand=5236) + * [ ] [`_mm_mask_store_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_store_ss&expand=5236) + * [ ] [`_mm_mask_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_round_sd&expand=5236) + * [ ] [`_mm_mask_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_round_ss&expand=5236) + * [ ] [`_mm_mask_sub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_sd&expand=5236) + * [ ] [`_mm_mask_sub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_ss&expand=5236) + * [ ] [`_mm_maskz_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_sd&expand=5236) + * [ ] [`_mm_maskz_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_ss&expand=5236) + * [ ] [`_mm_maskz_add_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_sd&expand=5236) + * [ ] [`_mm_maskz_add_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_ss&expand=5236) + * [ ] [`_mm_maskz_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvt_roundsd_ss&expand=5236) + * [ ] [`_mm_maskz_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvt_roundss_sd&expand=5236) + * [ ] [`_mm_maskz_cvtsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvtsd_ss&expand=5236) + * [ ] [`_mm_maskz_cvtss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvtss_sd&expand=5236) + * [ ] [`_mm_maskz_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_round_sd&expand=5236) + * [ ] [`_mm_maskz_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_round_ss&expand=5236) + * [ ] [`_mm_maskz_div_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_sd&expand=5236) + * [ ] [`_mm_maskz_div_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_ss&expand=5236) + * [ ] [`_mm_maskz_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_round_sd&expand=5236) + * [ ] [`_mm_maskz_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_round_ss&expand=5236) + * [ ] [`_mm_maskz_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_sd&expand=5236) + * [ ] [`_mm_maskz_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_ss&expand=5236) + * [ ] [`_mm_maskz_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_round_sd&expand=5236) + * [ ] [`_mm_maskz_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_round_ss&expand=5236) + * [ ] [`_mm_maskz_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_sd&expand=5236) + * [ ] [`_mm_maskz_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_ss&expand=5236) + * [ ] [`_mm_maskz_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_round_sd&expand=5236) + * [ ] [`_mm_maskz_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_round_ss&expand=5236) + * [ ] [`_mm_maskz_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_sd&expand=5236) + * [ ] [`_mm_maskz_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_ss&expand=5236) + * [ ] [`_mm_maskz_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_round_sd&expand=5236) + * [ ] [`_mm_maskz_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_round_ss&expand=5236) + * [ ] [`_mm_maskz_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_sd&expand=5236) + * [ ] [`_mm_maskz_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_ss&expand=5236) + * [ ] [`_mm_maskz_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_round_sd&expand=5236) + * [ ] [`_mm_maskz_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_round_ss&expand=5236) + * [ ] [`_mm_maskz_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_sd&expand=5236) + * [ ] [`_mm_maskz_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_ss&expand=5236) + * [ ] [`_mm_maskz_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_round_sd&expand=5236) + * [ ] [`_mm_maskz_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_round_ss&expand=5236) + * [ ] [`_mm_maskz_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_sd&expand=5236) + * [ ] [`_mm_maskz_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_ss&expand=5236) + * [ ] [`_mm_maskz_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_round_sd&expand=5236) + * [ ] [`_mm_maskz_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_round_ss&expand=5236) + * [ ] [`_mm_maskz_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_sd&expand=5236) + * [ ] [`_mm_maskz_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_ss&expand=5236) + * [ ] [`_mm_maskz_load_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_load_sd&expand=5236) + * [ ] [`_mm_maskz_load_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_load_ss&expand=5236) + * [ ] [`_mm_maskz_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_round_sd&expand=5236) + * [ ] [`_mm_maskz_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_round_ss&expand=5236) + * [ ] [`_mm_maskz_max_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_sd&expand=5236) + * [ ] [`_mm_maskz_max_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_ss&expand=5236) + * [ ] [`_mm_maskz_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_round_sd&expand=5236) + * [ ] [`_mm_maskz_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_round_ss&expand=5236) + * [ ] [`_mm_maskz_min_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_sd&expand=5236) + * [ ] [`_mm_maskz_min_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_ss&expand=5236) + * [ ] [`_mm_maskz_move_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_move_sd&expand=5236) + * [ ] [`_mm_maskz_move_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_move_ss&expand=5236) + * [ ] [`_mm_maskz_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_round_sd&expand=5236) + * [ ] [`_mm_maskz_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_round_ss&expand=5236) + * [ ] [`_mm_maskz_mul_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_sd&expand=5236) + * [ ] [`_mm_maskz_mul_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_ss&expand=5236) + * [ ] [`_mm_maskz_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rcp14_sd&expand=5236) + * [ ] [`_mm_maskz_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rcp14_ss&expand=5236) + * [ ] [`_mm_maskz_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_round_sd&expand=5236) + * [ ] [`_mm_maskz_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_round_ss&expand=5236) + * [ ] [`_mm_maskz_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_sd&expand=5236) + * [ ] [`_mm_maskz_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_ss&expand=5236) + * [ ] [`_mm_maskz_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rsqrt14_sd&expand=5236) + * [ ] [`_mm_maskz_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rsqrt14_ss&expand=5236) + * [ ] [`_mm_maskz_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_round_sd&expand=5236) + * [ ] [`_mm_maskz_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_round_ss&expand=5236) + * [ ] [`_mm_maskz_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_sd&expand=5236) + * [ ] [`_mm_maskz_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_ss&expand=5236) + * [ ] [`_mm_maskz_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_round_sd&expand=5236) + * [ ] [`_mm_maskz_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_round_ss&expand=5236) + * [ ] [`_mm_maskz_sqrt_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_sd&expand=5236) + * [ ] [`_mm_maskz_sqrt_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_ss&expand=5236) + * [ ] [`_mm_maskz_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_round_sd&expand=5236) + * [ ] [`_mm_maskz_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_round_ss&expand=5236) + * [ ] [`_mm_maskz_sub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_sd&expand=5236) + * [ ] [`_mm_maskz_sub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_ss&expand=5236) + * [ ] [`_mm_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_round_sd&expand=5236) + * [ ] [`_mm_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_round_ss&expand=5236) + * [ ] [`_mm_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_round_sd&expand=5236) + * [ ] [`_mm_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_round_ss&expand=5236) + * [ ] [`_mm_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_round_sd&expand=5236) + * [ ] [`_mm_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_round_ss&expand=5236) + * [ ] [`_mm_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp14_sd&expand=5236) + * [ ] [`_mm_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp14_ss&expand=5236) + * [ ] [`_mm_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_round_sd&expand=5236) + * [ ] [`_mm_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_round_ss&expand=5236) + * [ ] [`_mm_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_sd&expand=5236) + * [ ] [`_mm_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_ss&expand=5236) + * [ ] [`_mm_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt14_sd&expand=5236) + * [ ] [`_mm_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt14_ss&expand=5236) + * [ ] [`_mm_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_round_sd&expand=5236) + * [ ] [`_mm_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_round_ss&expand=5236) + * [ ] [`_mm_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_sd&expand=5236) + * [ ] [`_mm_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_ss&expand=5236) + * [ ] [`_mm_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_round_sd&expand=5236) + * [ ] [`_mm_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_round_ss&expand=5236) + * [ ] [`_mm_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_round_sd&expand=5236) + * [ ] [`_mm_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_round_ss&expand=5236) + +

diff --git a/library/stdarch/crates/core_arch/src/aarch64/mod.rs b/library/stdarch/crates/core_arch/src/aarch64/mod.rs index eefdae6738..ec2c6924b9 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/mod.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/mod.rs @@ -15,14 +15,15 @@ pub use self::neon::*; mod crypto; pub use self::crypto::*; -#[cfg(not(bootstrap))] mod tme; -#[cfg(not(bootstrap))] pub use self::tme::*; mod crc; pub use self::crc::*; +mod prefetch; +pub use self::prefetch::*; + pub use super::acle::*; #[cfg(test)] 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 66da36463a..438b1ac771 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs @@ -82,8 +82,41 @@ extern "C" { #[link_name = "llvm.aarch64.neon.pmull64"] fn vmull_p64_(a: i64, b: i64) -> int8x16_t; + #[link_name = "llvm.aarch64.neon.addp.v8i16"] + fn vpaddq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + #[link_name = "llvm.aarch64.neon.addp.v4i32"] + fn vpaddq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; #[link_name = "llvm.aarch64.neon.addp.v16i8"] - fn vpaddq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; + fn vpaddq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + + #[link_name = "llvm.aarch64.neon.saddv.i32.v4i16"] + fn vaddv_s16_(a: int16x4_t) -> i16; + #[link_name = "llvm.aarch64.neon.saddv.i32.v2i32"] + fn vaddv_s32_(a: int32x2_t) -> i32; + #[link_name = "llvm.aarch64.neon.saddv.i32.v8i8"] + fn vaddv_s8_(a: int8x8_t) -> i8; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v4i16"] + fn vaddv_u16_(a: uint16x4_t) -> u16; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v2i32"] + fn vaddv_u32_(a: uint32x2_t) -> u32; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v8i8"] + fn vaddv_u8_(a: uint8x8_t) -> u8; + #[link_name = "llvm.aarch64.neon.saddv.i32.v8i16"] + fn vaddvq_s16_(a: int16x8_t) -> i16; + #[link_name = "llvm.aarch64.neon.saddv.i32.v4i32"] + fn vaddvq_s32_(a: int32x4_t) -> i32; + #[link_name = "llvm.aarch64.neon.saddv.i32.v16i8"] + fn vaddvq_s8_(a: int8x16_t) -> i8; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v8i16"] + fn vaddvq_u16_(a: uint16x8_t) -> u16; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v4i32"] + fn vaddvq_u32_(a: uint32x4_t) -> u32; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v16i8"] + fn vaddvq_u8_(a: uint8x16_t) -> u8; + #[link_name = "llvm.aarch64.neon.saddv.i64.v2i64"] + fn vaddvq_s64_(a: int64x2_t) -> i64; + #[link_name = "llvm.aarch64.neon.uaddv.i64.v2i64"] + fn vaddvq_u64_(a: uint64x2_t) -> u64; #[link_name = "llvm.aarch64.neon.smaxv.i8.v8i8"] fn vmaxv_s8_(a: int8x8_t) -> i8; @@ -252,6 +285,11 @@ extern "C" { b3: int8x16_t, c: uint8x16_t, ) -> int8x16_t; + + #[link_name = "llvm.aarch64.neon.fcvtzu.v4i32.v4f32"] + fn vcvtq_u32_f32_(a: float32x4_t) -> uint32x4_t; + #[link_name = "llvm.aarch64.neon.fcvtzs.v4i32.v4f32"] + fn vcvtq_s32_f32_(a: float32x4_t) -> int32x4_t; } /// Absolute Value (wrapping). @@ -276,12 +314,160 @@ pub unsafe fn vabsq_s64(a: int64x2_t) -> int64x2_t { vabsq_s64_(a) } +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + vpaddq_s16_(a, b) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + transmute(vpaddq_s16_(transmute(a), transmute(b))) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + vpaddq_s32_(a, b) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { + transmute(vpaddq_s32_(transmute(a), transmute(b))) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + vpaddq_s8_(a, b) +} /// Add pairwise #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(addp))] pub unsafe fn vpaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - vpaddq_u8_(a, b) + transmute(vpaddq_s8_(transmute(a), transmute(b))) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddd_s64(a: int64x2_t) -> i64 { + transmute(vaddvq_u64_(transmute(a))) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddd_u64(a: uint64x2_t) -> u64 { + transmute(vaddvq_u64_(transmute(a))) +} + +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddv_s16(a: int16x4_t) -> i16 { + vaddv_s16_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vaddv_s32(a: int32x2_t) -> i32 { + vaddv_s32_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddv_s8(a: int8x8_t) -> i8 { + vaddv_s8_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddv_u16(a: uint16x4_t) -> u16 { + vaddv_u16_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vaddv_u32(a: uint32x2_t) -> u32 { + vaddv_u32_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddv_u8(a: uint8x8_t) -> u8 { + vaddv_u8_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_s16(a: int16x8_t) -> i16 { + vaddvq_s16_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_s32(a: int32x4_t) -> i32 { + vaddvq_s32_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_s8(a: int8x16_t) -> i8 { + vaddvq_s8_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_u16(a: uint16x8_t) -> u16 { + vaddvq_u16_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_u32(a: uint32x4_t) -> u32 { + vaddvq_u32_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_u8(a: uint8x16_t) -> u8 { + vaddvq_u8_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vaddvq_s64(a: int64x2_t) -> i64 { + vaddvq_s64_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vaddvq_u64(a: uint64x2_t) -> u64 { + vaddvq_u64_(a) } /// Polynomial multiply long @@ -308,6 +494,22 @@ pub unsafe fn vaddq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { simd_add(a, b) } +/// Vector add. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(add))] +pub unsafe fn vadd_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { + simd_add(a, b) +} + +/// Vector add. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(add))] +pub unsafe fn vadd_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { + simd_add(a, b) +} + /// Vector add. #[inline] #[target_feature(enable = "neon")] @@ -1602,6 +1804,60 @@ pub unsafe fn vqtbx4q_p8(a: poly8x16_t, t: poly8x16x4_t, idx: uint8x16_t) -> pol )) } +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_f32(addr: *const f32) -> float32x4_t { + use crate::core_arch::simd::f32x4; + transmute(f32x4::new( + *addr, + *addr.offset(1), + *addr.offset(2), + *addr.offset(3), + )) +} + +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_s32(addr: *const i32) -> int32x4_t { + use crate::core_arch::simd::i32x4; + transmute(i32x4::new( + *addr, + *addr.offset(1), + *addr.offset(2), + *addr.offset(3), + )) +} + +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_u32(addr: *const u32) -> uint32x4_t { + use crate::core_arch::simd::u32x4; + transmute(u32x4::new( + *addr, + *addr.offset(1), + *addr.offset(2), + *addr.offset(3), + )) +} + +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(fcvtzs))] +pub unsafe fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { + vcvtq_s32_f32_(a) +} + +/// Floating-point Convert to Unsigned fixed-point, rounding toward Zero (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(fcvtzu))] +pub unsafe fn vcvtq_u32_f32(a: float32x4_t) -> uint32x4_t { + vcvtq_u32_f32_(a) +} + #[cfg(test)] mod tests { use crate::core_arch::aarch64::test_support::*; @@ -1610,6 +1866,116 @@ mod tests { use std::mem::transmute; use stdarch_test::simd_test; + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_s32_f32() { + let f = f32x4::new(-1., 2., 3., 4.); + let e = i32x4::new(-1, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + assert_eq!(r, e); + + let f = f32x4::new(10e37, 2., 3., 4.); + let e = i32x4::new(0x7fffffff, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + assert_eq!(r, e); + + let f = f32x4::new(-10e37, 2., 3., 4.); + let e = i32x4::new(-0x80000000, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_u32_f32() { + let f = f32x4::new(1., 2., 3., 4.); + let e = u32x4::new(1, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + assert_eq!(r, e); + + let f = f32x4::new(-1., 2., 3., 4.); + let e = u32x4::new(0, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + assert_eq!(r, e); + + let f = f32x4::new(10e37, 2., 3., 4.); + let e = u32x4::new(0xffffffff, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_f32() { + let e = f32x4::new(1., 2., 3., 4.); + let f = [0., 1., 2., 3., 4.]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: f32x4 = transmute(vld1q_f32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_s32() { + let e = i32x4::new(1, 2, 3, 4); + let f = [0, 1, 2, 3, 4]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: i32x4 = transmute(vld1q_s32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_u32() { + let e = u32x4::new(1, 2, 3, 4); + let f = [0, 1, 2, 3, 4]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: u32x4 = transmute(vld1q_u32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_s16() { + let a = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b = i16x8::new(0, -1, -2, -3, -4, -5, -6, -7); + let r: i16x8 = transmute(vpaddq_s16(transmute(a), transmute(b))); + let e = i16x8::new(3, 7, 11, 15, -1, -5, -9, -13); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_s32() { + let a = i32x4::new(1, 2, 3, 4); + let b = i32x4::new(0, -1, -2, -3); + let r: i32x4 = transmute(vpaddq_s32(transmute(a), transmute(b))); + let e = i32x4::new(3, 7, -1, -5); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_s8() { + let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = i8x16::new( + 0, -1, -2, -3, -4, -5, -6, -7, -8, -8, -10, -11, -12, -13, -14, -15, + ); + let r: i8x16 = transmute(vpaddq_s8(transmute(a), transmute(b))); + let e = i8x16::new( + 3, 7, 11, 15, 19, 23, 27, 31, -1, -5, -9, -13, -16, -21, -25, -29, + ); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_u16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b = u16x8::new(17, 18, 19, 20, 20, 21, 22, 23); + let r: u16x8 = transmute(vpaddq_u16(transmute(a), transmute(b))); + let e = u16x8::new(1, 5, 9, 13, 35, 39, 41, 45); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_u32() { + let a = u32x4::new(0, 1, 2, 3); + let b = u32x4::new(17, 18, 19, 20); + let r: u32x4 = transmute(vpaddq_u32(transmute(a), transmute(b))); + let e = u32x4::new(1, 5, 35, 39); + assert_eq!(r, e); + } #[simd_test(enable = "neon")] unsafe fn test_vpaddq_u8() { let a = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); @@ -1620,6 +1986,20 @@ mod tests { let e: i8x16 = transmute(vpaddq_u8(transmute(a), transmute(b))); assert_eq!(r, e); } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddd_s64() { + let a = i64x2::new(2, -3); + let r: i64 = transmute(vpaddd_s64(transmute(a))); + let e = -1_i64; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddd_u64() { + let a = i64x2::new(2, 3); + let r: u64 = transmute(vpaddd_u64(transmute(a))); + let e = 5_u64; + assert_eq!(r, e); + } #[simd_test(enable = "neon")] unsafe fn test_vmull_p64() { @@ -1669,6 +2049,24 @@ mod tests { assert_eq!(r, e); } + #[simd_test(enable = "neon")] + unsafe fn test_vadd_s64() { + let a = 1_i64; + let b = 8_i64; + let e = 9_i64; + let r: i64 = transmute(vadd_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vadd_u64() { + let a = 1_u64; + let b = 8_u64; + let e = 9_u64; + let r: u64 = transmute(vadd_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] unsafe fn test_vaddd_s64() { let a = 1_i64; @@ -2560,6 +2958,105 @@ mod tests { let e = i64x2::new(i64::MIN, i64::MAX); assert_eq!(r, e); } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_s16() { + let a = i16x4::new(1, 2, 3, -4); + let r: i16 = transmute(vaddv_s16(transmute(a))); + let e = 2_i16; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_u16() { + let a = u16x4::new(1, 2, 3, 4); + let r: u16 = transmute(vaddv_u16(transmute(a))); + let e = 10_u16; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_s32() { + let a = i32x2::new(1, -2); + let r: i32 = transmute(vaddv_s32(transmute(a))); + let e = -1_i32; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_u32() { + let a = u32x2::new(1, 2); + let r: u32 = transmute(vaddv_u32(transmute(a))); + let e = 3_u32; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_s8() { + let a = i8x8::new(1, 2, 3, 4, 5, 6, 7, -8); + let r: i8 = transmute(vaddv_s8(transmute(a))); + let e = 20_i8; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_u8() { + let a = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u8 = transmute(vaddv_u8(transmute(a))); + let e = 36_u8; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_s16() { + let a = i16x8::new(1, 2, 3, 4, 5, 6, 7, -8); + let r: i16 = transmute(vaddvq_s16(transmute(a))); + let e = 20_i16; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_u16() { + let a = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u16 = transmute(vaddvq_u16(transmute(a))); + let e = 36_u16; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_s32() { + let a = i32x4::new(1, 2, 3, -4); + let r: i32 = transmute(vaddvq_s32(transmute(a))); + let e = 2_i32; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_u32() { + let a = u32x4::new(1, 2, 3, 4); + let r: u32 = transmute(vaddvq_u32(transmute(a))); + let e = 10_u32; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_s8() { + let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -16); + let r: i8 = transmute(vaddvq_s8(transmute(a))); + let e = 104_i8; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_u8() { + let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r: u8 = transmute(vaddvq_u8(transmute(a))); + let e = 136_u8; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_s64() { + let a = i64x2::new(1, -2); + let r: i64 = transmute(vaddvq_s64(transmute(a))); + let e = -1_i64; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_u64() { + let a = u64x2::new(1, 2); + let r: u64 = transmute(vaddvq_u64(transmute(a))); + let e = 3_u64; + assert_eq!(r, e); + } } #[cfg(test)] diff --git a/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs b/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs new file mode 100644 index 0000000000..0c50be5ec0 --- /dev/null +++ b/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs @@ -0,0 +1,89 @@ +#[cfg(test)] +use stdarch_test::assert_instr; + +extern "C" { + #[link_name = "llvm.prefetch"] + fn prefetch(p: *const i8, rw: i32, loc: i32, ty: i32); +} + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_READ: i32 = 0; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_WRITE: i32 = 1; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_LOCALITY0: i32 = 0; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_LOCALITY1: i32 = 1; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_LOCALITY2: i32 = 2; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_LOCALITY3: i32 = 3; + +/// Fetch the cache line that contains address `p` using the given `rw` and `locality`. +/// +/// The `rw` must be one of: +/// +/// * [`_PREFETCH_READ`](constant._PREFETCH_READ.html): the prefetch is preparing +/// for a read. +/// +/// * [`_PREFETCH_WRITE`](constant._PREFETCH_WRITE.html): the prefetch is preparing +/// for a write. +/// +/// The `locality` must be one of: +/// +/// * [`_PREFETCH_LOCALITY0`](constant._PREFETCH_LOCALITY0.html): Streaming or +/// non-temporal prefetch, for data that is used only once. +/// +/// * [`_PREFETCH_LOCALITY1`](constant._PREFETCH_LOCALITY1.html): Fetch into level 3 cache. +/// +/// * [`_PREFETCH_LOCALITY2`](constant._PREFETCH_LOCALITY2.html): Fetch into level 2 cache. +/// +/// * [`_PREFETCH_LOCALITY3`](constant._PREFETCH_LOCALITY3.html): Fetch into level 1 cache. +/// +/// The prefetch memory instructions signal to the memory system that memory accesses +/// from a specified address are likely to occur in the near future. The memory system +/// can respond by taking actions that are expected to speed up the memory access when +/// they do occur, such as preloading the specified address into one or more caches. +/// Because these signals are only hints, it is valid for a particular CPU to treat +/// any or all prefetch instructions as a NOP. +/// +/// +/// [Arm's documentation](https://developer.arm.com/documentation/den0024/a/the-a64-instruction-set/memory-access-instructions/prefetching-memory?lang=en) +#[inline(always)] +#[cfg_attr(test, assert_instr("prfm pldl1strm", rw = _PREFETCH_READ, locality = _PREFETCH_LOCALITY0))] +#[cfg_attr(test, assert_instr("prfm pldl3keep", rw = _PREFETCH_READ, locality = _PREFETCH_LOCALITY1))] +#[cfg_attr(test, assert_instr("prfm pldl2keep", rw = _PREFETCH_READ, locality = _PREFETCH_LOCALITY2))] +#[cfg_attr(test, assert_instr("prfm pldl1keep", rw = _PREFETCH_READ, locality = _PREFETCH_LOCALITY3))] +#[cfg_attr(test, assert_instr("prfm pstl1strm", rw = _PREFETCH_WRITE, locality = _PREFETCH_LOCALITY0))] +#[cfg_attr(test, assert_instr("prfm pstl3keep", rw = _PREFETCH_WRITE, locality = _PREFETCH_LOCALITY1))] +#[cfg_attr(test, assert_instr("prfm pstl2keep", rw = _PREFETCH_WRITE, locality = _PREFETCH_LOCALITY2))] +#[cfg_attr(test, assert_instr("prfm pstl1keep", rw = _PREFETCH_WRITE, locality = _PREFETCH_LOCALITY3))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _prefetch(p: *const i8, rw: i32, locality: i32) { + // We use the `llvm.prefetch` instrinsic with `cache type` = 1 (data cache). + // `rw` and `strategy` are based on the function parameters. + macro_rules! pref { + ($rdwr:expr, $local:expr) => { + match ($rdwr, $local) { + (0, 0) => prefetch(p, 0, 0, 1), + (0, 1) => prefetch(p, 0, 1, 1), + (0, 2) => prefetch(p, 0, 2, 1), + (0, 3) => prefetch(p, 0, 3, 1), + (1, 0) => prefetch(p, 1, 0, 1), + (1, 1) => prefetch(p, 1, 1, 1), + (1, 2) => prefetch(p, 1, 2, 1), + (1, 3) => prefetch(p, 1, 3, 1), + (_, _) => panic!( + "Illegal (rw, locality) pair in prefetch, value ({}, {}).", + $rdwr, $local + ), + } + }; + } + pref!(rw, locality); +} diff --git a/library/stdarch/crates/core_arch/src/arm/mod.rs b/library/stdarch/crates/core_arch/src/arm/mod.rs index bd902dc607..ff983b34b8 100644 --- a/library/stdarch/crates/core_arch/src/arm/mod.rs +++ b/library/stdarch/crates/core_arch/src/arm/mod.rs @@ -19,19 +19,9 @@ mod v7; #[cfg(any(target_arch = "aarch64", target_feature = "v7"))] pub use self::v7::*; -// NEON is supported on AArch64, and on ARM when built with the v7 and neon -// features. Building ARM without neon produces incorrect codegen. -#[cfg(any( - target_arch = "aarch64", - all(target_feature = "v7", target_feature = "neon"), - dox -))] +#[cfg(any(target_arch = "aarch64", target_feature = "v7", dox))] mod neon; -#[cfg(any( - target_arch = "aarch64", - all(target_feature = "v7", target_feature = "neon"), - dox -))] +#[cfg(any(target_arch = "aarch64", target_feature = "v7", dox))] pub use self::neon::*; #[cfg(any(target_arch = "aarch64", target_feature = "v7"))] diff --git a/library/stdarch/crates/core_arch/src/arm/neon/mod.rs b/library/stdarch/crates/core_arch/src/arm/neon/mod.rs index b39b1191e3..03fa069c11 100644 --- a/library/stdarch/crates/core_arch/src/arm/neon/mod.rs +++ b/library/stdarch/crates/core_arch/src/arm/neon/mod.rs @@ -175,6 +175,26 @@ extern "C" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpmaxs.v2f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxp.v2f32")] fn vpmaxf_v2f32(a: float32x2_t, b: float32x2_t) -> float32x2_t; + + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v4i16")] + fn vpadd_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v2i32")] + fn vpadd_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v8i8")] + fn vpadd_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v16i8")] + fn vpaddq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v4f32")] + fn vmaxq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v4f32")] + fn vminq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; } #[cfg(target_arch = "arm")] @@ -204,6 +224,10 @@ extern "C" { d: int8x8_t, e: int8x8_t, ) -> int8x8_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1.v4f32.p0i8")] + fn vld1q_v4f32(addr: *const u8, align: u32) -> float32x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1.v4i32.p0i8")] + fn vld1q_v4i32(addr: *const u8, align: u32) -> int32x4_t; } /// Absolute value (wrapping). @@ -261,6 +285,61 @@ pub unsafe fn vabsq_s32(a: int32x4_t) -> int32x4_t { vabsq_s32_(a) } +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + vpadd_s16_(a, b) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + vpadd_s32_(a, b) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + vpadd_s8_(a, b) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + transmute(vpadd_s16_(transmute(a), transmute(b))) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + transmute(vpadd_s32_(transmute(a), transmute(b))) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + transmute(vpadd_s8_(transmute(a), transmute(b))) +} + /// Unsigned saturating extract narrow. #[inline] #[target_feature(enable = "neon")] @@ -1243,11 +1322,8 @@ pub unsafe fn vtbx4_p8(a: poly8x8_t, b: poly8x8x4_t, c: uint8x8_t) -> poly8x8_t // `mov` seems to be an acceptable intrinsic to compile to // #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(vmov, imm5 = 1))] pub unsafe fn vgetq_lane_u64(v: uint64x2_t, imm5: i32) -> u64 { - if (imm5) < 0 || (imm5) > 1 { - unreachable_unchecked() - } - let imm5 = (imm5 & 0b1) as u32; - simd_extract(v, imm5) + assert!(imm5 >= 0 && imm5 <= 1); + simd_extract(v, imm5 as u32) } /// Move vector element to general-purpose register @@ -1260,9 +1336,7 @@ pub unsafe fn vgetq_lane_u64(v: uint64x2_t, imm5: i32) -> u64 { // FIXME: no 32bit this seems to be turned into two vmov.32 instructions // validate correctness pub unsafe fn vget_lane_u64(v: uint64x1_t, imm5: i32) -> u64 { - if imm5 != 0 { - unreachable_unchecked() - } + assert!(imm5 == 0); simd_extract(v, 0) } @@ -1274,11 +1348,8 @@ pub unsafe fn vget_lane_u64(v: uint64x1_t, imm5: i32) -> u64 { #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u16", imm5 = 2))] #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, imm5 = 2))] pub unsafe fn vgetq_lane_u16(v: uint16x8_t, imm5: i32) -> u16 { - if (imm5) < 0 || (imm5) > 7 { - unreachable_unchecked() - } - let imm5 = (imm5 & 0b111) as u32; - simd_extract(v, imm5) + assert!(imm5 >= 0 && imm5 <= 7); + simd_extract(v, imm5 as u32) } /// Move vector element to general-purpose register @@ -1289,11 +1360,20 @@ pub unsafe fn vgetq_lane_u16(v: uint16x8_t, imm5: i32) -> u16 { #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 2))] #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, imm5 = 2))] pub unsafe fn vgetq_lane_u32(v: uint32x4_t, imm5: i32) -> u32 { - if (imm5) < 0 || (imm5) > 3 { - unreachable_unchecked() - } - let imm5 = (imm5 & 0b11) as u32; - simd_extract(v, imm5) + assert!(imm5 >= 0 && imm5 <= 3); + simd_extract(v, imm5 as u32) +} + +/// Move vector element to general-purpose register +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_args_required_const(1)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, imm5 = 2))] +pub unsafe fn vgetq_lane_s32(v: int32x4_t, imm5: i32) -> i32 { + assert!(imm5 >= 0 && imm5 <= 3); + simd_extract(v, imm5 as u32) } /// Move vector element to general-purpose register @@ -1304,11 +1384,8 @@ pub unsafe fn vgetq_lane_u32(v: uint32x4_t, imm5: i32) -> u32 { #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u8", imm5 = 2))] #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, imm5 = 2))] pub unsafe fn vget_lane_u8(v: uint8x8_t, imm5: i32) -> u8 { - if (imm5) < 0 || (imm5) > 7 { - unreachable_unchecked() - } - let imm5 = (imm5 & 7) as u32; - simd_extract(v, imm5) + assert!(imm5 >= 0 && imm5 <= 7); + simd_extract(v, imm5 as u32) } /// Duplicate vector element to vector or scalar @@ -1699,6 +1776,93 @@ pub unsafe fn vld1q_u8(addr: *const u8) -> uint8x16_t { ptr::read(addr as *const uint8x16_t) } +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vld1.32"))] +pub unsafe fn vld1q_s32(addr: *const i32) -> int32x4_t { + vld1q_v4i32(addr as *const u8, 4) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vld1.32"))] +pub unsafe fn vld1q_u32(addr: *const u32) -> uint32x4_t { + transmute(vld1q_v4i32(addr as *const u8, 4)) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vld1.32"))] +pub unsafe fn vld1q_f32(addr: *const f32) -> float32x4_t { + vld1q_v4f32(addr as *const u8, 4) +} + +/// Load one single-element structure and Replicate to all lanes (of one register). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_f32(addr: *const f32) -> float32x4_t { + use crate::core_arch::simd::f32x4; + let v = *addr; + transmute(f32x4::new(v, v, v, v)) +} + +// These float-to-int implementations have undefined behaviour when `a` overflows +// the destination type. Clang has the same problem: https://llvm.org/PR47510 + +/// Floating-point Convert to Signed fixed-point, rounding toward Zero (vector) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vcvt.s32.f32"))] +pub unsafe fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { + use crate::core_arch::simd::{f32x4, i32x4}; + transmute(simd_cast::<_, i32x4>(transmute::<_, f32x4>(a))) +} + +/// Floating-point Convert to Unsigned fixed-point, rounding toward Zero (vector) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vcvt.u32.f32"))] +pub unsafe fn vcvtq_u32_f32(a: float32x4_t) -> uint32x4_t { + use crate::core_arch::simd::{f32x4, u32x4}; + transmute(simd_cast::<_, u32x4>(transmute::<_, f32x4>(a))) +} + +/// Floating-point minimum (vector). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmin.f32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmin))] +pub unsafe fn vminq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + vminq_f32_(a, b) +} + +/// Floating-point maxmimum (vector). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmax.f32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmax))] +pub unsafe fn vmaxq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + vmaxq_f32_(a, b) +} + #[cfg(test)] mod tests { use super::*; @@ -1723,6 +1887,65 @@ mod tests { assert_eq!(r, e); } + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_f32() { + let e = f32x4::new(1., 2., 3., 4.); + let f = [0., 1., 2., 3., 4.]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: f32x4 = transmute(vld1q_f32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_s32() { + let e = i32x4::new(1, 2, 3, 4); + let f = [0, 1, 2, 3, 4]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: i32x4 = transmute(vld1q_s32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_u32() { + let e = u32x4::new(1, 2, 3, 4); + let f = [0, 1, 2, 3, 4]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: u32x4 = transmute(vld1q_u32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_f32() { + let e = f32x4::new(1., 1., 1., 1.); + let f = [1., 2., 3., 4.]; + let r: f32x4 = transmute(vld1q_dup_f32(f.as_ptr())); + assert_eq!(r, e); + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_s32_f32() { + let f = f32x4::new(-1., 2., 3., 4.); + let e = i32x4::new(-1, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + assert_eq!(r, e); + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_u32_f32() { + let f = f32x4::new(1., 2., 3., 4.); + let e = u32x4::new(1, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] unsafe fn test_vget_lane_u8() { let v = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); @@ -1737,6 +1960,13 @@ mod tests { assert_eq!(r, 2); } + #[simd_test(enable = "neon")] + unsafe fn test_vgetq_lane_s32() { + let v = i32x4::new(1, 2, 3, 4); + let r = vgetq_lane_s32(transmute(v), 1); + assert_eq!(r, 2); + } + #[simd_test(enable = "neon")] unsafe fn test_vget_lane_u64() { let v: u64 = 1; @@ -4063,6 +4293,70 @@ mod tests { let e = i32x4::new(i32::MIN, i32::MAX, 0, 1); assert_eq!(r, e); } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_s16() { + let a = i16x4::new(1, 2, 3, 4); + let b = i16x4::new(0, -1, -2, -3); + let r: i16x4 = transmute(vpadd_s16(transmute(a), transmute(b))); + let e = i16x4::new(3, 7, -1, -5); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_s32() { + let a = i32x2::new(1, 2); + let b = i32x2::new(0, -1); + let r: i32x2 = transmute(vpadd_s32(transmute(a), transmute(b))); + let e = i32x2::new(3, -1); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_s8() { + let a = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b = i8x8::new(0, -1, -2, -3, -4, -5, -6, -7); + let r: i8x8 = transmute(vpadd_s8(transmute(a), transmute(b))); + let e = i8x8::new(3, 7, 11, 15, -1, -5, -9, -13); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_u16() { + let a = u16x4::new(1, 2, 3, 4); + let b = u16x4::new(30, 31, 32, 33); + let r: u16x4 = transmute(vpadd_u16(transmute(a), transmute(b))); + let e = u16x4::new(3, 7, 61, 65); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_u32() { + let a = u32x2::new(1, 2); + let b = u32x2::new(30, 31); + let r: u32x2 = transmute(vpadd_u32(transmute(a), transmute(b))); + let e = u32x2::new(3, 61); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_u8() { + let a = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b = u8x8::new(30, 31, 32, 33, 34, 35, 36, 37); + let r: u8x8 = transmute(vpadd_u8(transmute(a), transmute(b))); + let e = u8x8::new(3, 7, 11, 15, 61, 65, 69, 73); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vminq_f32() { + let a = f32x4::new(1., -2., 3., -4.); + let b = f32x4::new(0., 3., 2., 8.); + let e = f32x4::new(0., -2., 2., -4.); + let r: f32x4 = transmute(vminq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_f32() { + let a = f32x4::new(1., -2., 3., -4.); + let b = f32x4::new(0., 3., 2., 8.); + let e = f32x4::new(1., 3., 3., 8.); + let r: f32x4 = transmute(vmaxq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } } #[cfg(test)] diff --git a/library/stdarch/crates/core_arch/src/lib.rs b/library/stdarch/crates/core_arch/src/lib.rs index aa8d4c9820..5638ccc11e 100644 --- a/library/stdarch/crates/core_arch/src/lib.rs +++ b/library/stdarch/crates/core_arch/src/lib.rs @@ -6,6 +6,7 @@ #![feature( const_fn, const_fn_union, + const_fn_transmute, const_generics, custom_inner_attributes, link_llvm_intrinsics, @@ -21,7 +22,6 @@ stdsimd, staged_api, doc_cfg, - mmx_target_feature, tbm_target_feature, sse4a_target_feature, arm_target_feature, diff --git a/library/stdarch/crates/core_arch/src/simd.rs b/library/stdarch/crates/core_arch/src/simd.rs index 202df0143c..4b71d6c2bf 100644 --- a/library/stdarch/crates/core_arch/src/simd.rs +++ b/library/stdarch/crates/core_arch/src/simd.rs @@ -90,16 +90,44 @@ simd_ty!(i16x2[i16]: i16, i16 | x0, x1); // 64-bit wide types: -simd_ty!(u8x8[u8]: - u8, u8, u8, u8, u8, u8, u8, u8 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + u8x8[u8]: u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); simd_ty!(u16x4[u16]: u16, u16, u16, u16 | x0, x1, x2, x3); simd_ty!(u32x2[u32]: u32, u32 | x0, x1); simd_ty!(u64x1[u64]: u64 | x1); -simd_ty!(i8x8[i8]: - i8, i8, i8, i8, i8, i8, i8, i8 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + i8x8[i8]: i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); simd_ty!(i16x4[i16]: i16, i16, i16, i16 | x0, x1, x2, x3); simd_ty!(i32x2[i32]: i32, i32 | x0, x1); simd_ty!(i64x1[i64]: i64 | x1); @@ -108,116 +136,576 @@ simd_ty!(f32x2[f32]: f32, f32 | x0, x1); // 128-bit wide types: -simd_ty!(u8x16[u8]: - u8, u8, u8, u8, u8, u8, u8, u8, - u8, u8, u8, u8, u8, u8, u8, u8 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 +simd_ty!( + u8x16[u8]: u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_ty!( + u16x8[u16]: u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 ); -simd_ty!(u16x8[u16]: - u16, u16, u16, u16, u16, u16, u16, u16 - | x0, x1, x2, x3, x4, x5, x6, x7); simd_ty!(u32x4[u32]: u32, u32, u32, u32 | x0, x1, x2, x3); simd_ty!(u64x2[u64]: u64, u64 | x0, x1); -simd_ty!(i8x16[i8]: - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 +simd_ty!( + i8x16[i8]: i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_ty!( + i16x8[i16]: i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 ); -simd_ty!(i16x8[i16]: - i16, i16, i16, i16, i16, i16, i16, i16 - | x0, x1, x2, x3, x4, x5, x6, x7); simd_ty!(i32x4[i32]: i32, i32, i32, i32 | x0, x1, x2, x3); simd_ty!(i64x2[i64]: i64, i64 | x0, x1); simd_ty!(f32x4[f32]: f32, f32, f32, f32 | x0, x1, x2, x3); simd_ty!(f64x2[f64]: f64, f64 | x0, x1); -simd_m_ty!(m8x16[i8]: - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 +simd_m_ty!( + m8x16[i8]: i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_m_ty!( + m16x8[i16]: i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 ); -simd_m_ty!(m16x8[i16]: - i16, i16, i16, i16, i16, i16, i16, i16 - | x0, x1, x2, x3, x4, x5, x6, x7); simd_m_ty!(m32x4[i32]: i32, i32, i32, i32 | x0, x1, x2, x3); simd_m_ty!(m64x2[i64]: i64, i64 | x0, x1); // 256-bit wide types: -simd_ty!(u8x32[u8]: - u8, u8, u8, u8, u8, u8, u8, u8, - u8, u8, u8, u8, u8, u8, u8, u8, - u8, u8, u8, u8, u8, u8, u8, u8, - u8, u8, u8, u8, u8, u8, u8, u8 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, - x24, x25, x26, x27, x28, x29, x30, x31 -); -simd_ty!(u16x16[u16]: - u16, u16, u16, u16, u16, u16, u16, u16, - u16, u16, u16, u16, u16, u16, u16, u16 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 -); -simd_ty!(u32x8[u32]: - u32, u32, u32, u32, u32, u32, u32, u32 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + u8x32[u8]: u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29, + x30, + x31 +); +simd_ty!( + u16x16[u16]: u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_ty!( + u32x8[u32]: u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); simd_ty!(u64x4[u64]: u64, u64, u64, u64 | x0, x1, x2, x3); -simd_ty!(i8x32[i8]: - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, - x24, x25, x26, x27, x28, x29, x30, x31 -); -simd_ty!(i16x16[i16]: - i16, i16, i16, i16, i16, i16, i16, i16, - i16, i16, i16, i16, i16, i16, i16, i16 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 -); -simd_ty!(i32x8[i32]: - i32, i32, i32, i32, i32, i32, i32, i32 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + i8x32[i8]: i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29, + x30, + x31 +); +simd_ty!( + i16x16[i16]: i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_ty!( + i32x8[i32]: i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); simd_ty!(i64x4[i64]: i64, i64, i64, i64 | x0, x1, x2, x3); -simd_ty!(f32x8[f32]: - f32, f32, f32, f32, f32, f32, f32, f32 | - x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + f32x8[f32]: f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); // 512-bit wide types: -simd_ty!(i32x16[i32]: - i32, i32, i32, i32, i32, i32, i32, i32, - i32, i32, i32, i32, i32, i32, i32, i32 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15); - -simd_ty!(u32x16[u32]: - u32, u32, u32, u32, u32, u32, u32, u32, - u32, u32, u32, u32, u32, u32, u32, u32 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15); - -simd_ty!(f32x16[f32]: - f32, f32, f32, f32, f32, f32, f32, f32, - f32, f32, f32, f32, f32, f32, f32, f32 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15); - -simd_ty!(i64x8[i64]: - i64, i64, i64, i64, i64, i64, i64, i64 - | x0, x1, x2, x3, x4, x5, x6, x7); - -simd_ty!(u64x8[u64]: - u64, u64, u64, u64, u64, u64, u64, u64 - | x0, x1, x2, x3, x4, x5, x6, x7); - -simd_ty!(f64x8[f64]: - f64, f64, f64, f64, f64, f64, f64, f64 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + i32x16[i32]: i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); + +simd_ty!( + u32x16[u32]: u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); + +simd_ty!( + f32x16[f32]: f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); + +simd_ty!( + i64x8[i64]: i64, + i64, + i64, + i64, + i64, + i64, + i64, + i64 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); + +simd_ty!( + u64x8[u64]: u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); + +simd_ty!( + f64x8[f64]: f64, + f64, + f64, + f64, + f64, + f64, + f64, + f64 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); diff --git a/library/stdarch/crates/core_arch/src/simd_llvm.rs b/library/stdarch/crates/core_arch/src/simd_llvm.rs index 02934f7cb8..f472b86f8b 100644 --- a/library/stdarch/crates/core_arch/src/simd_llvm.rs +++ b/library/stdarch/crates/core_arch/src/simd_llvm.rs @@ -1,6 +1,4 @@ -//! LLVM's simd platform intrinsics -//! -//! TODO: should use `link_llvm_intrinsic` instead: issue #112 +//! LLVM's SIMD platform intrinsics extern "platform-intrinsic" { //pub fn simd_select_bitmask diff --git a/library/stdarch/crates/core_arch/src/wasm32/simd128.rs b/library/stdarch/crates/core_arch/src/wasm32/simd128.rs index 798035d76a..bb8e238a91 100644 --- a/library/stdarch/crates/core_arch/src/wasm32/simd128.rs +++ b/library/stdarch/crates/core_arch/src/wasm32/simd128.rs @@ -24,7 +24,7 @@ types! { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait v128Ext: Sized { unsafe fn as_v128(self) -> v128; diff --git a/library/stdarch/crates/core_arch/src/x86/avx.rs b/library/stdarch/crates/core_arch/src/x86/avx.rs index e3f80733f5..0b6f13fe82 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx.rs @@ -1423,7 +1423,7 @@ pub unsafe fn _mm256_permute2f128_pd(a: __m256d, b: __m256d, imm8: i32) -> __m25 constify_imm8!(imm8, call) } -/// Shuffles 258-bits (composed of integer data) selected by `imm8` +/// Shuffles 128-bits (composed of integer data) selected by `imm8` /// from `a` and `b`. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_permute2f128_si256) diff --git a/library/stdarch/crates/core_arch/src/x86/avx2.rs b/library/stdarch/crates/core_arch/src/x86/avx2.rs index 15060a5e38..87af536cc9 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx2.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx2.rs @@ -3289,7 +3289,7 @@ pub unsafe fn _mm256_sub_epi16(a: __m256i, b: __m256i) -> __m256i { transmute(simd_sub(a.as_i16x16(), b.as_i16x16())) } -/// Subtract packed 32-bit integers in `b` from packed 16-bit integers in `a` +/// Subtract packed 32-bit integers in `b` from packed 32-bit integers in `a` /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_sub_epi32) #[inline] @@ -3300,7 +3300,7 @@ pub unsafe fn _mm256_sub_epi32(a: __m256i, b: __m256i) -> __m256i { transmute(simd_sub(a.as_i32x8(), b.as_i32x8())) } -/// Subtract packed 64-bit integers in `b` from packed 16-bit integers in `a` +/// Subtract packed 64-bit integers in `b` from packed 64-bit integers in `a` /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_sub_epi64) #[inline] @@ -3311,7 +3311,7 @@ pub unsafe fn _mm256_sub_epi64(a: __m256i, b: __m256i) -> __m256i { transmute(simd_sub(a.as_i64x4(), b.as_i64x4())) } -/// Subtract packed 8-bit integers in `b` from packed 16-bit integers in `a` +/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a` /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_sub_epi8) #[inline] @@ -3743,9 +3743,14 @@ pub unsafe fn _mm256_xor_si256(a: __m256i, b: __m256i) -> __m256i { // This intrinsic has no corresponding instruction. #[rustc_args_required_const(1)] #[stable(feature = "simd_x86", since = "1.27.0")] -pub unsafe fn _mm256_extract_epi8(a: __m256i, imm8: i32) -> i8 { - let imm8 = (imm8 & 31) as u32; - simd_extract(a.as_i8x32(), imm8 as u32) +pub unsafe fn _mm256_extract_epi8(a: __m256i, imm8: i32) -> i32 { + let a = a.as_u8x32(); + macro_rules! call { + ($imm5:expr) => { + simd_extract::<_, u8>(a, $imm5) as i32 + }; + } + constify_imm5!(imm8, call) } /// Extracts a 16-bit integer from `a`, selected with `imm8`. Returns a 32-bit @@ -3759,9 +3764,14 @@ pub unsafe fn _mm256_extract_epi8(a: __m256i, imm8: i32) -> i8 { // This intrinsic has no corresponding instruction. #[rustc_args_required_const(1)] #[stable(feature = "simd_x86", since = "1.27.0")] -pub unsafe fn _mm256_extract_epi16(a: __m256i, imm8: i32) -> i16 { - let imm8 = (imm8 & 15) as u32; - simd_extract(a.as_i16x16(), imm8) +pub unsafe fn _mm256_extract_epi16(a: __m256i, imm8: i32) -> i32 { + let a = a.as_u16x16(); + macro_rules! call { + ($imm4:expr) => { + simd_extract::<_, u16>(a, $imm4) as i32 + }; + } + constify_imm4!((imm8 & 15), call) } /// Extracts a 32-bit integer from `a`, selected with `imm8`. @@ -6120,7 +6130,7 @@ mod tests { ); let r1 = _mm256_extract_epi8(a, 0); let r2 = _mm256_extract_epi8(a, 35); - assert_eq!(r1, -1); + assert_eq!(r1, 0xFF); assert_eq!(r2, 3); } @@ -6133,7 +6143,7 @@ mod tests { ); let r1 = _mm256_extract_epi16(a, 0); let r2 = _mm256_extract_epi16(a, 19); - assert_eq!(r1, -1); + assert_eq!(r1, 0xFFFF); assert_eq!(r2, 3); } diff --git a/library/stdarch/crates/core_arch/src/x86/avx512f.rs b/library/stdarch/crates/core_arch/src/x86/avx512f.rs index 4744b435dd..3f9bbfb3e1 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512f.rs @@ -49,3235 +49,16891 @@ pub unsafe fn _mm512_maskz_abs_epi32(k: __mmask16, a: __m512i) -> __m512i { transmute(simd_select_bitmask(k, abs, zero)) } -/// Returns vector of type `__m512d` with all elements set to zero. +/// Compute the absolute value of packed signed 64-bit integers in a, and store the unsigned results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_abs_epi64&expand=48) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vxorps))] -pub unsafe fn _mm512_setzero_pd() -> __m512d { - // All-0 is a properly initialized __m512d - mem::zeroed() +#[cfg_attr(test, assert_instr(vpabsq))] +pub unsafe fn _mm512_abs_epi64(a: __m512i) -> __m512i { + let a = a.as_i64x8(); + // all-0 is a properly initialized i64x8 + let zero: i64x8 = mem::zeroed(); + let sub = simd_sub(zero, a); + let cmp: i64x8 = simd_gt(a, zero); + transmute(simd_select(cmp, a, sub)) } -/// Returns vector of type `__m512d` with all elements set to zero. +/// Compute the absolute value of packed signed 64-bit integers in a, and store the unsigned results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_abs_epi64&expand=49) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vxorps))] -pub unsafe fn _mm512_setzero_ps() -> __m512 { - // All-0 is a properly initialized __m512 - mem::zeroed() +#[cfg_attr(test, assert_instr(vpabsq))] +pub unsafe fn _mm512_mask_abs_epi64(src: __m512i, k: __mmask8, a: __m512i) -> __m512i { + let abs = _mm512_abs_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, abs, src.as_i64x8())) } -/// Returns vector of type `__m512i` with all elements set to zero. +/// Compute the absolute value of packed signed 64-bit integers in a, and store the unsigned results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_si512) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_abs_epi64&expand=50) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vxorps))] -pub unsafe fn _mm512_setzero_si512() -> __m512i { - // All-0 is a properly initialized __m512i - mem::zeroed() +#[cfg_attr(test, assert_instr(vpabsq))] +pub unsafe fn _mm512_maskz_abs_epi64(k: __mmask8, a: __m512i) -> __m512i { + let abs = _mm512_abs_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, abs, zero)) } -/// Sets packed 32-bit integers in `dst` with the supplied values in reverse -/// order. +/// Finds the absolute value of each packed single-precision (32-bit) floating-point element in v2, storing the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_abs_ps&expand=65) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_setr_epi32( - e15: i32, - e14: i32, - e13: i32, - e12: i32, - e11: i32, - e10: i32, - e9: i32, - e8: i32, - e7: i32, - e6: i32, - e5: i32, - e4: i32, - e3: i32, - e2: i32, - e1: i32, - e0: i32, -) -> __m512i { - let r = i32x16( - e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0, - ); - transmute(r) +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_abs_ps(v2: __m512) -> __m512 { + let a = _mm512_set1_epi32(0x7FFFFFFF); // from LLVM code + let b = transmute::(v2.as_f32x16()); + let abs = _mm512_and_epi32(a, b); + transmute(abs) } -/// Gather double-precision (64-bit) floating-point elements from memory using 32-bit indices. +/// Finds the absolute value of each packed single-precision (32-bit) floating-point element in v2, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_abs_ps&expand=66) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherdpd, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i32gather_pd(offsets: __m256i, slice: *const u8, scale: i32) -> __m512d { - let zero = _mm512_setzero_pd().as_f64x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherdpd(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpandd))] +pub unsafe fn _mm512_mask_abs_ps(src: __m512, k: __mmask16, v2: __m512) -> __m512 { + let abs = _mm512_abs_ps(v2).as_f32x16(); + transmute(simd_select_bitmask(k, abs, src.as_f32x16())) } -/// Gather double-precision (64-bit) floating-point elements from memory using 32-bit indices. +/// Finds the absolute value of each packed double-precision (64-bit) floating-point element in v2, storing the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_abs_pd&expand=60) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherdpd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32gather_pd( - src: __m512d, - mask: __mmask8, - offsets: __m256i, - slice: *const u8, - scale: i32, -) -> __m512d { - let src = src.as_f64x8(); - let slice = slice as *const i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherdpd(src, slice, offsets, mask as i8, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_abs_pd(v2: __m512d) -> __m512d { + let a = _mm512_set1_epi64(0x7FFFFFFFFFFFFFFF); // from LLVM code + let b = transmute::(v2.as_f64x8()); + let abs = _mm512_and_epi64(a, b); + transmute(abs) } -/// Gather double-precision (64-bit) floating-point elements from memory using 64-bit indices. +/// Finds the absolute value of each packed double-precision (64-bit) floating-point element in v2, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_abs_pd&expand=61) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherqpd, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i64gather_pd(offsets: __m512i, slice: *const u8, scale: i32) -> __m512d { - let zero = _mm512_setzero_pd().as_f64x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherqpd(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_mask_abs_pd(src: __m512d, k: __mmask8, v2: __m512d) -> __m512d { + let abs = _mm512_abs_pd(v2).as_f64x8(); + transmute(simd_select_bitmask(k, abs, src.as_f64x8())) } -/// Gather double-precision (64-bit) floating-point elements from memory using 64-bit indices. +/// Add packed 32-bit integers in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_epi32&expand=100) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherqpd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64gather_pd( - src: __m512d, - mask: __mmask8, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m512d { - let src = src.as_f64x8(); - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherqpd(src, slice, offsets, mask as i8, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpaddd))] +pub unsafe fn _mm512_add_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_add(a.as_i32x16(), b.as_i32x16())) } -/// Gather single-precision (32-bit) floating-point elements from memory using 64-bit indices. +/// Add packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_epi32&expand=101) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherqps, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i64gather_ps(offsets: __m512i, slice: *const u8, scale: i32) -> __m256 { - let zero = _mm256_setzero_ps().as_f32x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherqps(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpaddd))] +pub unsafe fn _mm512_mask_add_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, add, src.as_i32x16())) } -/// Gather single-precision (32-bit) floating-point elements from memory using 64-bit indices. +/// Add packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_epi32&expand=102) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherqps, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64gather_ps( - src: __m256, - mask: __mmask8, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m256 { - let src = src.as_f32x8(); - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherqps(src, slice, offsets, mask as i8, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpaddd))] +pub unsafe fn _mm512_maskz_add_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, add, zero)) } -/// Gather single-precision (32-bit) floating-point elements from memory using 32-bit indices. +/// Add packed 64-bit integers in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_epi64&expand=109) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherdps, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i32gather_ps(offsets: __m512i, slice: *const u8, scale: i32) -> __m512 { - let zero = _mm512_setzero_ps().as_f32x16(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vgatherdps(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpaddq))] +pub unsafe fn _mm512_add_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_add(a.as_i64x8(), b.as_i64x8())) } -/// Gather single-precision (32-bit) floating-point elements from memory using 32-bit indices. +/// Add packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_epi64&expand=110) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherdps, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32gather_ps( - src: __m512, - mask: __mmask16, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m512 { - let src = src.as_f32x16(); - let slice = slice as *const i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vgatherdps(src, slice, offsets, mask as i16, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpaddq))] +pub unsafe fn _mm512_mask_add_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, add, src.as_i64x8())) } -/// Gather 32-bit integers from memory using 32-bit indices. +/// Add packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_epi64&expand=111) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherdd, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i32gather_epi32(offsets: __m512i, slice: *const u8, scale: i32) -> __m512i { - let zero = _mm512_setzero_si512().as_i32x16(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vpgatherdd(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpaddq))] +pub unsafe fn _mm512_maskz_add_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, add, zero)) } -/// Gather 32-bit integers from memory using 32-bit indices. +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_ps&expand=139) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherdd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32gather_epi32( - src: __m512i, - mask: __mmask16, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m512i { - let src = src.as_i32x16(); - let mask = mask as i16; - let slice = slice as *const i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vpgatherdd(src, slice, offsets, mask, $imm8) - }; - } - let r = constify_imm8!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vaddps))] +pub unsafe fn _mm512_add_ps(a: __m512, b: __m512) -> __m512 { + transmute(simd_add(a.as_f32x16(), b.as_f32x16())) } -/// Gather 64-bit integers from memory using 32-bit indices. +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_ps&expand=140) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherdq, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i32gather_epi64(offsets: __m256i, slice: *const u8, scale: i32) -> __m512i { - let zero = _mm512_setzero_si512().as_i64x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherdq(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vaddps))] +pub unsafe fn _mm512_mask_add_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let add = _mm512_add_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, add, src.as_f32x16())) } -/// Gather 64-bit integers from memory using 32-bit indices. +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_ps&expand=141) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherdq, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32gather_epi64( - src: __m512i, - mask: __mmask8, - offsets: __m256i, - slice: *const u8, - scale: i32, -) -> __m512i { - let src = src.as_i64x8(); - let mask = mask as i8; - let slice = slice as *const i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherdq(src, slice, offsets, mask, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vaddps))] +pub unsafe fn _mm512_maskz_add_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let add = _mm512_add_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, add, zero)) } -/// Gather 64-bit integers from memory using 64-bit indices. +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_pd&expand=127) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherqq, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i64gather_epi64(offsets: __m512i, slice: *const u8, scale: i32) -> __m512i { - let zero = _mm512_setzero_si512().as_i64x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherqq(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vaddpd))] +pub unsafe fn _mm512_add_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(simd_add(a.as_f64x8(), b.as_f64x8())) } -/// Gather 64-bit integers from memory using 64-bit indices. +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_pd&expand=128) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherqq, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64gather_epi64( - src: __m512i, - mask: __mmask8, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m512i { - let src = src.as_i64x8(); - let mask = mask as i8; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherqq(src, slice, offsets, mask, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vaddpd))] +pub unsafe fn _mm512_mask_add_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let add = _mm512_add_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, add, src.as_f64x8())) } -/// Gather 32-bit integers from memory using 64-bit indices. +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_pd&expand=129) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherqd, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i64gather_epi32(offsets: __m512i, slice: *const u8, scale: i32) -> __m256i { - let zeros = _mm256_setzero_si256().as_i32x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherqd(zeros, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vaddpd))] +pub unsafe fn _mm512_maskz_add_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let add = _mm512_add_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, add, zero)) } -/// Gather 32-bit integers from memory using 64-bit indices. +/// Subtract packed 32-bit integers in b from packed 32-bit integers in a, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_epi32&expand=5694) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherqd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64gather_epi32( - src: __m256i, - mask: __mmask8, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m256i { - let src = src.as_i32x8(); - let mask = mask as i8; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherqd(src, slice, offsets, mask, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpsubd))] +pub unsafe fn _mm512_sub_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_sub(a.as_i32x16(), b.as_i32x16())) } -/// Scatter double-precision (64-bit) floating-point elements from memory using 32-bit indices. +/// Subtract packed 32-bit integers in b from packed 32-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_epi32&expand=5692) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterdpd, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i32scatter_pd(slice: *mut u8, offsets: __m256i, src: __m512d, scale: i32) { - let src = src.as_f64x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterdpd(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpsubd))] +pub unsafe fn _mm512_mask_sub_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, sub, src.as_i32x16())) } -/// Scatter double-precision (64-bit) floating-point elements from src into memory using 32-bit indices. +/// Subtract packed 32-bit integers in b from packed 32-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_epi32&expand=5693) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterdpd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32scatter_pd( - slice: *mut u8, - mask: __mmask8, - offsets: __m256i, - src: __m512d, - scale: i32, -) { - let src = src.as_f64x8(); - let slice = slice as *mut i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterdpd(slice, mask as i8, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpsubd))] +pub unsafe fn _mm512_maskz_sub_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, sub, zero)) } -/// Scatter double-precision (64-bit) floating-point elements from src into memory using 64-bit indices. +/// Subtract packed 64-bit integers in b from packed 64-bit integers in a, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_epi64&expand=5703) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterqpd, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i64scatter_pd(slice: *mut u8, offsets: __m512i, src: __m512d, scale: i32) { - let src = src.as_f64x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterqpd(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpsubq))] +pub unsafe fn _mm512_sub_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_sub(a.as_i64x8(), b.as_i64x8())) } -/// Scatter double-precision (64-bit) floating-point elements from src into memory using 64-bit indices. +/// Subtract packed 64-bit integers in b from packed 64-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_epi64&expand=5701) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterqpd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64scatter_pd( - slice: *mut u8, - mask: __mmask8, - offsets: __m512i, - src: __m512d, - scale: i32, -) { - let src = src.as_f64x8(); - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterqpd(slice, mask as i8, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpsubq))] +pub unsafe fn _mm512_mask_sub_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, sub, src.as_i64x8())) } -/// Scatter single-precision (32-bit) floating-point elements from memory using 32-bit indices. +/// Subtract packed 64-bit integers in b from packed 64-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_epi64&expand=5702) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterdps, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i32scatter_ps(slice: *mut u8, offsets: __m512i, src: __m512, scale: i32) { - let src = src.as_f32x16(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vscatterdps(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpsubq))] +pub unsafe fn _mm512_maskz_sub_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_sub_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, add, zero)) } -/// Scatter single-precision (32-bit) floating-point elements from src into memory using 32-bit indices. +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_ps&expand=5733) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterdps, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32scatter_ps( - slice: *mut u8, - mask: __mmask16, - offsets: __m512i, - src: __m512, - scale: i32, -) { - let src = src.as_f32x16(); - let slice = slice as *mut i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vscatterdps(slice, mask as i16, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vsubps))] +pub unsafe fn _mm512_sub_ps(a: __m512, b: __m512) -> __m512 { + transmute(simd_sub(a.as_f32x16(), b.as_f32x16())) } -/// Scatter single-precision (32-bit) floating-point elements from src into memory using 64-bit indices. +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_ps&expand=5731) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterqps, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i64scatter_ps(slice: *mut u8, offsets: __m512i, src: __m256, scale: i32) { - let src = src.as_f32x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterqps(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vsubps))] +pub unsafe fn _mm512_mask_sub_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let sub = _mm512_sub_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, sub, src.as_f32x16())) } -/// Scatter single-precision (32-bit) floating-point elements from src into memory using 64-bit indices. +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_ps&expand=5732) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterqps, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64scatter_ps( - slice: *mut u8, - mask: __mmask8, - offsets: __m512i, - src: __m256, - scale: i32, -) { - let src = src.as_f32x8(); - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterqps(slice, mask as i8, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vsubps))] +pub unsafe fn _mm512_maskz_sub_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let sub = _mm512_sub_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, sub, zero)) } -/// Scatter 64-bit integers from src into memory using 32-bit indices. +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_pd&expand=5721) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterdq, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i32scatter_epi64(slice: *mut u8, offsets: __m256i, src: __m512i, scale: i32) { - let src = src.as_i64x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterdq(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vsubpd))] +pub unsafe fn _mm512_sub_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(simd_sub(a.as_f64x8(), b.as_f64x8())) } -/// Scatter 64-bit integers from src into memory using 32-bit indices. +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_pd&expand=5719) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterdq, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32scatter_epi64( - slice: *mut u8, - mask: __mmask8, - offsets: __m256i, - src: __m512i, - scale: i32, -) { - let src = src.as_i64x8(); - let mask = mask as i8; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterdq(slice, mask, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vsubpd))] +pub unsafe fn _mm512_mask_sub_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let sub = _mm512_sub_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, sub, src.as_f64x8())) } -/// Scatter 64-bit integers from src into memory using 64-bit indices. +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_pd&expand=5720) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterqq, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i64scatter_epi64(slice: *mut u8, offsets: __m512i, src: __m512i, scale: i32) { - let src = src.as_i64x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterqq(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vsubpd))] +pub unsafe fn _mm512_maskz_sub_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let sub = _mm512_sub_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, sub, zero)) } -/// Scatter 64-bit integers from src into memory using 64-bit indices. +/// Multiply the low signed 32-bit integers from each packed 64-bit element in a and b, and store the signed 64-bit results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_epi32&expand=3907) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterqq, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64scatter_epi64( - slice: *mut u8, - mask: __mmask8, - offsets: __m512i, - src: __m512i, - scale: i32, -) { - let src = src.as_i64x8(); - let mask = mask as i8; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterqq(slice, mask, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmuldq))] +pub unsafe fn _mm512_mul_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmuldq(a.as_i32x16(), b.as_i32x16())) } -/// Scatter 32-bit integers from src into memory using 32-bit indices. +/// Multiply the low signed 32-bit integers from each packed 64-bit element in a and b, and store the signed 64-bit results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_epi32&expand=3905) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterdd, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i32scatter_epi32(slice: *mut u8, offsets: __m512i, src: __m512i, scale: i32) { - let src = src.as_i32x16(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vpscatterdd(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmuldq))] +pub unsafe fn _mm512_mask_mul_epi32(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mul_epi32(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, mul, src.as_i64x8())) } -/// Scatter 32-bit integers from src into memory using 32-bit indices. +/// Multiply the low signed 32-bit integers from each packed 64-bit element in a and b, and store the signed 64-bit results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_epi32&expand=3906) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterdd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32scatter_epi32( - slice: *mut u8, - mask: __mmask16, - offsets: __m512i, - src: __m512i, - scale: i32, -) { - let src = src.as_i32x16(); - let mask = mask as i16; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vpscatterdd(slice, mask, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmuldq))] +pub unsafe fn _mm512_maskz_mul_epi32(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mul_epi32(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, mul, zero)) } -/// Scatter 32-bit integers from src into memory using 64-bit indices. +/// Multiply the packed 32-bit integers in a and b, producing intermediate 64-bit integers, and store the low 32 bits of the intermediate integers in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mullo_epi&expand=4005) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterqd, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i64scatter_epi32(slice: *mut u8, offsets: __m512i, src: __m256i, scale: i32) { - let src = src.as_i32x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterqd(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmulld))] +pub unsafe fn _mm512_mullo_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_mul(a.as_i32x16(), b.as_i32x16())) } -/// Scatter 32-bit integers from src into memory using 64-bit indices. +/// Multiply the packed 32-bit integers in a and b, producing intermediate 64-bit integers, and store the low 32 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mullo_epi32&expand=4003) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterqd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64scatter_epi32( - slice: *mut u8, - mask: __mmask8, - offsets: __m512i, - src: __m256i, - scale: i32, -) { - let src = src.as_i32x8(); - let mask = mask as i8; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterqd(slice, mask, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmulld))] +pub unsafe fn _mm512_mask_mullo_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let mul = _mm512_mullo_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, mul, src.as_i32x16())) } -/// Sets packed 32-bit integers in `dst` with the supplied values. +/// Multiply the packed 32-bit integers in a and b, producing intermediate 64-bit integers, and store the low 32 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mullo_epi32&expand=4004) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set_ps( - e0: f32, - e1: f32, - e2: f32, - e3: f32, - e4: f32, - e5: f32, - e6: f32, - e7: f32, - e8: f32, - e9: f32, - e10: f32, - e11: f32, - e12: f32, - e13: f32, - e14: f32, - e15: f32, -) -> __m512 { - _mm512_setr_ps( - e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0, - ) +#[cfg_attr(test, assert_instr(vpmulld))] +pub unsafe fn _mm512_maskz_mullo_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mullo_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, mul, zero)) } -/// Sets packed 32-bit integers in `dst` with the supplied values in -/// reverse order. +/// Multiplies elements in packed 64-bit integer vectors a and b together, storing the lower 64 bits of the result in dst. /// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mullox_epi64&expand=4017) +/// +/// This intrinsic generates a sequence of instructions, which may perform worse than a native instruction. Consider the performance impact of this intrinsic. #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_setr_ps( - e0: f32, - e1: f32, - e2: f32, - e3: f32, - e4: f32, - e5: f32, - e6: f32, - e7: f32, - e8: f32, - e9: f32, - e10: f32, - e11: f32, - e12: f32, - e13: f32, - e14: f32, - e15: f32, -) -> __m512 { - let r = f32x16::new( - e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, - ); - transmute(r) +pub unsafe fn _mm512_mullox_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_mul(a.as_i64x8(), b.as_i64x8())) } -/// Broadcast 64-bit float `a` to all elements of `dst`. +/// Multiplies elements in packed 64-bit integer vectors a and b together, storing the lower 64 bits of the result in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mullox&expand=4016) +/// +/// This intrinsic generates a sequence of instructions, which may perform worse than a native instruction. Consider the performance impact of this intrinsic. #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set1_pd(a: f64) -> __m512d { - transmute(f64x8::splat(a)) +pub unsafe fn _mm512_mask_mullox_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + b: __m512i, +) -> __m512i { + let mul = _mm512_mullox_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, mul, src.as_i64x8())) } -/// Broadcast 32-bit float `a` to all elements of `dst`. +/// Multiply the low unsigned 32-bit integers from each packed 64-bit element in a and b, and store the unsigned 64-bit results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_epu32&expand=3916) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set1_ps(a: f32) -> __m512 { - transmute(f32x16::splat(a)) +#[cfg_attr(test, assert_instr(vpmuludq))] +pub unsafe fn _mm512_mul_epu32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmuludq(a.as_u32x16(), b.as_u32x16())) } -/// Sets packed 32-bit integers in `dst` with the supplied values. +/// Multiply the low unsigned 32-bit integers from each packed 64-bit element in a and b, and store the unsigned 64-bit results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_epu32&expand=3914) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set_epi32( - e15: i32, - e14: i32, - e13: i32, - e12: i32, - e11: i32, - e10: i32, - e9: i32, - e8: i32, - e7: i32, - e6: i32, - e5: i32, - e4: i32, - e3: i32, - e2: i32, - e1: i32, - e0: i32, -) -> __m512i { - _mm512_setr_epi32( - e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, - ) +#[cfg_attr(test, assert_instr(vpmuludq))] +pub unsafe fn _mm512_mask_mul_epu32(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mul_epu32(a, b).as_u64x8(); + transmute(simd_select_bitmask(k, mul, src.as_u64x8())) } -/// Broadcast 32-bit integer `a` to all elements of `dst`. +/// Multiply the low unsigned 32-bit integers from each packed 64-bit element in a and b, and store the unsigned 64-bit results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_epu32&expand=3915) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set1_epi32(a: i32) -> __m512i { - transmute(i32x16::splat(a)) +#[cfg_attr(test, assert_instr(vpmuludq))] +pub unsafe fn _mm512_maskz_mul_epu32(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mul_epu32(a, b).as_u64x8(); + let zero = _mm512_setzero_si512().as_u64x8(); + transmute(simd_select_bitmask(k, mul, zero)) } -/// Broadcast 64-bit integer `a` to all elements of `dst`. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm512_mul_ps&expand=3934) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set1_epi64(a: i64) -> __m512i { - transmute(i64x8::splat(a)) +#[cfg_attr(test, assert_instr(vmulps))] +pub unsafe fn _mm512_mul_ps(a: __m512, b: __m512) -> __m512 { + transmute(simd_mul(a.as_f32x16(), b.as_f32x16())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). RM. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_ps&expand=3932) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmplt_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_LT_OS) +#[cfg_attr(test, assert_instr(vmulps))] +pub unsafe fn _mm512_mask_mul_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let mul = _mm512_mul_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, mul, src.as_f32x16())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_ps&expand=3933) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmplt_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_LT_OS) +#[cfg_attr(test, assert_instr(vmulps))] +pub unsafe fn _mm512_maskz_mul_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let mul = _mm512_mul_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mul, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnlt_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_pd&expand=3925) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpnlt_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_NLT_US) +#[cfg_attr(test, assert_instr(vmulpd))] +pub unsafe fn _mm512_mul_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(simd_mul(a.as_f64x8(), b.as_f64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). RM. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnlt_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_pd&expand=3923) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpnlt_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_NLT_US) +#[cfg_attr(test, assert_instr(vmulpd))] +pub unsafe fn _mm512_mask_mul_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let mul = _mm512_mul_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, mul, src.as_f64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_pd&expand=3924) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmple_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_LE_OS) +#[cfg_attr(test, assert_instr(vmulpd))] +pub unsafe fn _mm512_maskz_mul_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let mul = _mm512_mul_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, mul, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_ps&expand=2162) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmple_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_LE_OS) +#[cfg_attr(test, assert_instr(vdivps))] +pub unsafe fn _mm512_div_ps(a: __m512, b: __m512) -> __m512 { + transmute(simd_div(a.as_f32x16(), b.as_f32x16())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnle_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_ps&expand=2163) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpnle_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_NLE_US) +#[cfg_attr(test, assert_instr(vdivps))] +pub unsafe fn _mm512_mask_div_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let div = _mm512_div_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, div, src.as_f32x16())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnle_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_ps&expand=2164) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpnle_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_NLE_US) +#[cfg_attr(test, assert_instr(vdivps))] +pub unsafe fn _mm512_maskz_div_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let div = _mm512_div_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, div, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for equality, and store the results in a mask vector. +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_pd&expand=2153) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpeq_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_EQ_OQ) +#[cfg_attr(test, assert_instr(vdivpd))] +pub unsafe fn _mm512_div_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(simd_div(a.as_f64x8(), b.as_f64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_pd&expand=2154) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpeq_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_EQ_OQ) +#[cfg_attr(test, assert_instr(vdivpd))] +pub unsafe fn _mm512_mask_div_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let div = _mm512_div_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, div, src.as_f64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for inequality, and store the results in a mask vector. +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_pd&expand=2155) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpneq_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_NEQ_UQ) +#[cfg_attr(test, assert_instr(vdivpd))] +pub unsafe fn _mm512_maskz_div_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let div = _mm512_div_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, div, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed signed 32-bit integers in a and b, and store packed maximum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_epi32&expand=3582) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpneq_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_NEQ_UQ) +#[cfg_attr(test, assert_instr(vpmaxsd))] +pub unsafe fn _mm512_max_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxsd(a.as_i32x16(), b.as_i32x16())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// Compare packed signed 32-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_epi32&expand=3580) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmp_ps_mask(a: __m512, b: __m512, op: i32) -> __mmask16 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr) => { - vcmpps( - a.as_f32x16(), - b.as_f32x16(), - $imm5, - neg_one, - _MM_FROUND_CUR_DIRECTION, - ) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmaxsd))] +pub unsafe fn _mm512_mask_max_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, max, src.as_i32x16())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed signed 32-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_epi32&expand=3581) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_ps_mask(m: __mmask16, a: __m512, b: __m512, op: i32) -> __mmask16 { - macro_rules! call { - ($imm5:expr) => { - vcmpps( - a.as_f32x16(), - b.as_f32x16(), - $imm5, - m as i16, - _MM_FROUND_CUR_DIRECTION, - ) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmaxsd))] +pub unsafe fn _mm512_maskz_max_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// Compare packed signed 64-bit integers in a and b, and store packed maximum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_epi64&expand=3591) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2, 3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm512_cmp_round_ps_mask(a: __m512, b: __m512, op: i32, sae: i32) -> __mmask16 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpps(a.as_f32x16(), b.as_f32x16(), $imm5, neg_one, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmaxsq))] +pub unsafe fn _mm512_max_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxsq(a.as_i64x8(), b.as_i64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed signed 64-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_epi64&expand=3589) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3, 4)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm512_mask_cmp_round_ps_mask( - m: __mmask16, - a: __m512, - b: __m512, - op: i32, - sae: i32, -) -> __mmask16 { - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpps(a.as_f32x16(), b.as_f32x16(), $imm5, m as i16, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmaxsq))] +pub unsafe fn _mm512_mask_max_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, max, src.as_i64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// Compare packed signed 64-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_epi64&expand=3590) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmpord_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_ORD_Q) +#[cfg_attr(test, assert_instr(vpmaxsq))] +pub unsafe fn _mm512_maskz_max_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_ps&expand=3655) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmpord_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_ORD_Q) +#[cfg_attr(test, assert_instr(vmaxps))] +pub unsafe fn _mm512_max_ps(a: __m512, b: __m512) -> __m512 { + transmute(vmaxps( + a.as_f32x16(), + b.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_ps&expand=3653) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmpunord_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_UNORD_Q) +#[cfg_attr(test, assert_instr(vmaxps))] +pub unsafe fn _mm512_mask_max_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let max = _mm512_max_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_ps&expand=3654) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmpunord_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_UNORD_Q) +#[cfg_attr(test, assert_instr(vmaxps))] +pub unsafe fn _mm512_maskz_max_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let max = _mm512_max_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than, and store the results in a mask vector. +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_pd&expand=3645) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmplt_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_LT_OS) +#[cfg_attr(test, assert_instr(vmaxpd))] +pub unsafe fn _mm512_max_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(vmaxpd(a.as_f64x8(), b.as_f64x8(), _MM_FROUND_CUR_DIRECTION)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_pd&expand=3643) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmplt_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_LT_OS) +#[cfg_attr(test, assert_instr(vmaxpd))] +pub unsafe fn _mm512_mask_max_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let max = _mm512_max_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnlt_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_pd&expand=3644) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpnlt_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_NLT_US) +#[cfg_attr(test, assert_instr(vmaxpd))] +pub unsafe fn _mm512_maskz_max_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let max = _mm512_max_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed unsigned 32-bit integers in a and b, and store packed maximum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnlt_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_epu32&expand=3618) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpnlt_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NLT_US) +#[cfg_attr(test, assert_instr(vpmaxud))] +pub unsafe fn _mm512_max_epu32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxud(a.as_u32x16(), b.as_u32x16())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector. +/// Compare packed unsigned 32-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_epu32&expand=3616) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmple_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_LE_OS) +#[cfg_attr(test, assert_instr(vpmaxud))] +pub unsafe fn _mm512_mask_max_epu32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu32(a, b).as_u32x16(); + transmute(simd_select_bitmask(k, max, src.as_u32x16())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed unsigned 32-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_epu32&expand=3617) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmple_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_LE_OS) +#[cfg_attr(test, assert_instr(vpmaxud))] +pub unsafe fn _mm512_maskz_max_epu32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu32(a, b).as_u32x16(); + let zero = _mm512_setzero_si512().as_u32x16(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// Compare packed unsigned 64-bit integers in a and b, and store packed maximum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnle_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=max_epu64&expand=3627) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpnle_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_NLE_US) +#[cfg_attr(test, assert_instr(vpmaxuq))] +pub unsafe fn _mm512_max_epu64(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxuq(a.as_u64x8(), b.as_u64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed unsigned 64-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnle_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_epu64&expand=3625) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpnle_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NLE_US) +#[cfg_attr(test, assert_instr(vpmaxuq))] +pub unsafe fn _mm512_mask_max_epu64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu64(a, b).as_u64x8(); + transmute(simd_select_bitmask(k, max, src.as_u64x8())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for equality, and store the results in a mask vector. +/// Compare packed unsigned 64-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_epu&expand=3626) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpeq_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_EQ_OQ) +#[cfg_attr(test, assert_instr(vpmaxuq))] +pub unsafe fn _mm512_maskz_max_epu64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu64(a, b).as_u64x8(); + let zero = _mm512_setzero_si512().as_u64x8(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed signed 32-bit integers in a and b, and store packed minimum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_epi32&expand=3696) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpeq_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_EQ_OQ) +#[cfg_attr(test, assert_instr(vpminsd))] +pub unsafe fn _mm512_min_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminsd(a.as_i32x16(), b.as_i32x16())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for inequality, and store the results in a mask vector. +/// Compare packed signed 32-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_epi32&expand=3694) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpneq_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_NEQ_UQ) +#[cfg_attr(test, assert_instr(vpminsd))] +pub unsafe fn _mm512_mask_min_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, max, src.as_i32x16())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed signed 32-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_epi32&expand=3695) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpneq_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NEQ_UQ) +#[cfg_attr(test, assert_instr(vpminsd))] +pub unsafe fn _mm512_maskz_min_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// Compare packed signed 64-bit integers in a and b, and store packed minimum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_epi64&expand=3705) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmp_pd_mask(a: __m512d, b: __m512d, op: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr) => { - vcmppd( - a.as_f64x8(), - b.as_f64x8(), - $imm5, - neg_one, - _MM_FROUND_CUR_DIRECTION, - ) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpminsq))] +pub unsafe fn _mm512_min_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminsq(a.as_i64x8(), b.as_i64x8())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed signed 64-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_epi64&expand=3703) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_pd_mask(m: __mmask8, a: __m512d, b: __m512d, op: i32) -> __mmask8 { - macro_rules! call { - ($imm5:expr) => { - vcmppd( - a.as_f64x8(), - b.as_f64x8(), - $imm5, - m as i8, - _MM_FROUND_CUR_DIRECTION, - ) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpminsq))] +pub unsafe fn _mm512_mask_min_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, max, src.as_i64x8())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// Compare packed signed 64-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_epi64&expand=3704) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2, 3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm512_cmp_round_pd_mask(a: __m512d, b: __m512d, op: i32, sae: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmppd(a.as_f64x8(), b.as_f64x8(), $imm5, neg_one, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpminsq))] +pub unsafe fn _mm512_maskz_min_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_ps&expand=3769) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3, 4)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm512_mask_cmp_round_pd_mask( - m: __mmask8, - a: __m512d, - b: __m512d, - op: i32, - sae: i32, -) -> __mmask8 { - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmppd(a.as_f64x8(), b.as_f64x8(), $imm5, m as i8, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vminps))] +pub unsafe fn _mm512_min_ps(a: __m512, b: __m512) -> __m512 { + transmute(vminps( + a.as_f32x16(), + b.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_ps&expand=3767) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmpord_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_ORD_Q) +#[cfg_attr(test, assert_instr(vminps))] +pub unsafe fn _mm512_mask_min_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let max = _mm512_min_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_ps&expand=3768) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmpord_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_ORD_Q) +#[cfg_attr(test, assert_instr(vminps))] +pub unsafe fn _mm512_maskz_min_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let max = _mm512_min_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_pd&expand=3759) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmpunord_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_UNORD_Q) +#[cfg_attr(test, assert_instr(vminpd))] +pub unsafe fn _mm512_min_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(vminpd(a.as_f64x8(), b.as_f64x8(), _MM_FROUND_CUR_DIRECTION)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_pd&expand=3757) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmpunord_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_UNORD_Q) +#[cfg_attr(test, assert_instr(vminpd))] +pub unsafe fn _mm512_mask_min_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let max = _mm512_min_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_ss_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_pd&expand=3758) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_cmp_ss_mask(a: __m128, b: __m128, op: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr) => { - vcmpss(a, b, $imm5, neg_one, _MM_FROUND_CUR_DIRECTION) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vminpd))] +pub unsafe fn _mm512_maskz_min_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let max = _mm512_min_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// Compare packed unsigned 32-bit integers in a and b, and store packed minimum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_ss_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_epu32&expand=3732) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_mask_cmp_ss_mask(m: __mmask8, a: __m128, b: __m128, op: i32) -> __mmask8 { - macro_rules! call { - ($imm5:expr) => { - vcmpss(a, b, $imm5, m as i8, _MM_FROUND_CUR_DIRECTION) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpminud))] +pub unsafe fn _mm512_min_epu32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminud(a.as_u32x16(), b.as_u32x16())) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// Compare packed unsigned 32-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_ss_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_epu32&expand=3730) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2, 3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_cmp_round_ss_mask(a: __m128, b: __m128, op: i32, sae: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpss(a, b, $imm5, neg_one, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpminud))] +pub unsafe fn _mm512_mask_min_epu32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epu32(a, b).as_u32x16(); + transmute(simd_select_bitmask(k, max, src.as_u32x16())) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// Compare packed unsigned 32-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_ss_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_epu32&expand=3731) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3, 4)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_mask_cmp_round_ss_mask( - m: __mmask8, - a: __m128, - b: __m128, - op: i32, - sae: i32, -) -> __mmask8 { - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpss(a, b, $imm5, m as i8, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpminud))] +pub unsafe fn _mm512_maskz_min_epu32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epu32(a, b).as_u32x16(); + let zero = _mm512_setzero_si512().as_u32x16(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// Compare packed unsigned 64-bit integers in a and b, and store packed minimum values in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_sd_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_epu64&expand=3741) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_cmp_sd_mask(a: __m128d, b: __m128d, op: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr) => { - vcmpsd(a, b, $imm5, neg_one, _MM_FROUND_CUR_DIRECTION) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpminuq))] +pub unsafe fn _mm512_min_epu64(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminuq(a.as_u64x8(), b.as_u64x8())) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// Compare packed unsigned 64-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_sd_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_epu64&expand=3739) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_mask_cmp_sd_mask(m: __mmask8, a: __m128d, b: __m128d, op: i32) -> __mmask8 { - macro_rules! call { - ($imm5:expr) => { - vcmpsd(a, b, $imm5, m as i8, _MM_FROUND_CUR_DIRECTION) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpminuq))] +pub unsafe fn _mm512_mask_min_epu64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epu64(a, b).as_u64x8(); + transmute(simd_select_bitmask(k, max, src.as_u64x8())) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// Compare packed unsigned 64-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_sd_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_epu64&expand=3740) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2, 3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_cmp_round_sd_mask(a: __m128d, b: __m128d, op: i32, sae: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpsd(a, b, $imm5, neg_one, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpminuq))] +pub unsafe fn _mm512_maskz_min_epu64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epu64(a, b).as_u64x8(); + let zero = _mm512_setzero_si512().as_u64x8(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_sd_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_ps&expand=5371) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3, 4)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_mask_cmp_round_sd_mask( - m: __mmask8, - a: __m128d, - b: __m128d, - op: i32, - sae: i32, -) -> __mmask8 { - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpsd(a, b, $imm5, m as i8, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vsqrtps))] +pub unsafe fn _mm512_sqrt_ps(a: __m512) -> __m512 { + transmute(vsqrtps(a.as_f32x16(), _MM_FROUND_CUR_DIRECTION)) } -/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector. +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_ps&expand=5369) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmplt_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_lt(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vsqrtps))] +pub unsafe fn _mm512_mask_sqrt_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + let sqrt = _mm512_sqrt_ps(a).as_f32x16(); + transmute(simd_select_bitmask(k, sqrt, src.as_f32x16())) } -/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_ps&expand=5370) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmplt_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmplt_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vsqrtps))] +pub unsafe fn _mm512_maskz_sqrt_ps(k: __mmask16, a: __m512) -> __m512 { + let sqrt = _mm512_sqrt_ps(a).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, sqrt, zero)) } -/// Compare packed unsigned 32-bit integers in a and b for greater-than, and store the results in a mask vector. +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_pd&expand=5362) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpgt_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_gt(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vsqrtpd))] +pub unsafe fn _mm512_sqrt_pd(a: __m512d) -> __m512d { + transmute(vsqrtpd(a.as_f64x8(), _MM_FROUND_CUR_DIRECTION)) } -/// Compare packed unsigned 32-bit integers in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_pd&expand=5360) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpgt_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpgt_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vsqrtpd))] +pub unsafe fn _mm512_mask_sqrt_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + let sqrt = _mm512_sqrt_pd(a).as_f64x8(); + transmute(simd_select_bitmask(k, sqrt, src.as_f64x8())) } -/// Compare packed unsigned 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_pd&expand=5361) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmple_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_le(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vsqrtpd))] +pub unsafe fn _mm512_maskz_sqrt_pd(k: __mmask8, a: __m512d) -> __m512d { + let sqrt = _mm512_sqrt_pd(a).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, sqrt, zero)) } -/// Compare packed unsigned 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=fmadd_ps&expand=2557) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmple_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmple_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +pub unsafe fn _mm512_fmadd_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + transmute(vfmadd132ps( + a.as_f32x16(), + b.as_f32x16(), + c.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed unsigned 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_ps&expand=2558) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpge_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_ge(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +pub unsafe fn _mm512_mask_fmadd_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fmadd = _mm512_fmadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmadd, a.as_f32x16())) } -/// Compare packed unsigned 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_ps&expand=2560) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpge_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpge_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +pub unsafe fn _mm512_maskz_fmadd_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fmadd = _mm512_fmadd_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmadd, zero)) } -/// Compare packed unsigned 32-bit integers in a and b for equality, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_ps&expand=2559) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpeq_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_eq(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +pub unsafe fn _mm512_mask3_fmadd_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fmadd = _mm512_fmadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmadd, c.as_f32x16())) } -/// Compare packed unsigned 32-bit integers in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_pd&expand=2545) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpeq_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpeq_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +pub unsafe fn _mm512_fmadd_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + transmute(vfmadd132pd( + a.as_f64x8(), + b.as_f64x8(), + c.as_f64x8(), + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed unsigned 32-bit integers in a and b for inequality, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_pd&expand=2546) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpneq_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_ne(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +pub unsafe fn _mm512_mask_fmadd_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fmadd = _mm512_fmadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmadd, a.as_f64x8())) } -/// Compare packed unsigned 32-bit integers in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epu32_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_pd&expand=2548) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpneq_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpneq_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +pub unsafe fn _mm512_maskz_fmadd_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fmadd = _mm512_fmadd_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmadd, zero)) } -/// Compare packed unsigned 32-bit integers in a and b based on the comparison operand specified by op. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu32_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_pd&expand=2547) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_cmp_epu32_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask16 { - let neg_one = -1; - macro_rules! call { - ($imm3:expr) => { - vpcmpud(a.as_i32x16(), b.as_i32x16(), $imm3, neg_one) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +pub unsafe fn _mm512_mask3_fmadd_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fmadd = _mm512_fmadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmadd, c.as_f64x8())) } -/// Compare packed unsigned 32-bit integers in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu32_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_ps&expand=2643) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_epu32_mask( - m: __mmask16, - a: __m512i, - b: __m512i, - op: _MM_CMPINT_ENUM, -) -> __mmask16 { - macro_rules! call { - ($imm3:expr) => { - vpcmpud(a.as_i32x16(), b.as_i32x16(), $imm3, m as i16) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generate vfmadd, gcc generate vfmsub +pub unsafe fn _mm512_fmsub_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + transmute(vfmadd132ps( + a.as_f32x16(), + b.as_f32x16(), + sub, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_ps&expand=2644) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmplt_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_lt(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generate vfmadd, gcc generate vfmsub +pub unsafe fn _mm512_mask_fmsub_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fmsub = _mm512_fmsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmsub, a.as_f32x16())) } -/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_ps&expand=2646) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmplt_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmplt_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generate vfmadd, gcc generate vfmsub +pub unsafe fn _mm512_maskz_fmsub_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fmsub = _mm512_fmsub_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmsub, zero)) } -/// Compare packed signed 32-bit integers in a and b for greater-than, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_ps&expand=2645) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpgt_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_gt(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generate vfmadd, gcc generate vfmsub +pub unsafe fn _mm512_mask3_fmsub_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fmsub = _mm512_fmsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmsub, c.as_f32x16())) } -/// Compare packed signed 32-bit integers in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_pd&expand=2631) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpgt_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpgt_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang fmadd, gcc fmsub +pub unsafe fn _mm512_fmsub_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + transmute(vfmadd132pd( + a.as_f64x8(), + b.as_f64x8(), + sub, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed signed 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_pd&expand=2632) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmple_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_le(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang fmadd, gcc fmsub +pub unsafe fn _mm512_mask_fmsub_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fmsub = _mm512_fmsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmsub, a.as_f64x8())) } -/// Compare packed signed 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_pd&expand=2634) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmple_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmple_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang fmadd, gcc fmsub +pub unsafe fn _mm512_maskz_fmsub_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fmsub = _mm512_fmsub_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmsub, zero)) } -/// Compare packed signed 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_pd&expand=2633) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpge_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_ge(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang fmadd, gcc fmsub +pub unsafe fn _mm512_mask3_fmsub_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fmsub = _mm512_fmsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmsub, c.as_f64x8())) } -/// Compare packed signed 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_ps&expand=2611) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpge_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpge_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +pub unsafe fn _mm512_fmaddsub_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + transmute(vfmaddsub213ps( + a.as_f32x16(), + b.as_f32x16(), + c.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed signed 32-bit integers in a and b for equality, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_ps&expand=2612) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpeq_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_eq(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +pub unsafe fn _mm512_mask_fmaddsub_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fmaddsub = _mm512_fmaddsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f32x16())) } -/// Compare packed signed 32-bit integers in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_ps&expand=2614) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpeq_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpeq_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +pub unsafe fn _mm512_maskz_fmaddsub_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fmaddsub = _mm512_fmaddsub_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) } -/// Compare packed signed 32-bit integers in a and b for inequality, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_ps&expand=2613) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpneq_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_ne(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +pub unsafe fn _mm512_mask3_fmaddsub_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fmaddsub = _mm512_fmaddsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f32x16())) } -/// Compare packed signed 32-bit integers in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_pd&expand=2599) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpneq_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpneq_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +pub unsafe fn _mm512_fmaddsub_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + transmute(vfmaddsub213pd( + a.as_f64x8(), + b.as_f64x8(), + c.as_f64x8(), + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed signed 32-bit integers in a and b based on the comparison operand specified by op. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi32_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_pd&expand=2600) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_cmp_epi32_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask16 { - let neg_one = -1; - macro_rules! call { - ($imm3:expr) => { - vpcmpd(a.as_i32x16(), b.as_i32x16(), $imm3, neg_one) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +pub unsafe fn _mm512_mask_fmaddsub_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fmaddsub = _mm512_fmaddsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f64x8())) } -/// Compare packed signed 32-bit integers in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi32_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_pd&expand=2602) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_epi32_mask( - m: __mmask16, - a: __m512i, - b: __m512i, - op: _MM_CMPINT_ENUM, -) -> __mmask16 { - macro_rules! call { - ($imm3:expr) => { - vpcmpd(a.as_i32x16(), b.as_i32x16(), $imm3, m as i16) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +pub unsafe fn _mm512_maskz_fmaddsub_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fmaddsub = _mm512_fmaddsub_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) } -/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_ps&expand=2613) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmplt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_lt(a.as_u64x8(), b.as_u64x8())) +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +pub unsafe fn _mm512_mask3_fmaddsub_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fmaddsub = _mm512_fmaddsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f64x8())) } -/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_ps&expand=2691) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmplt_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmplt_epu64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +pub unsafe fn _mm512_fmsubadd_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + transmute(vfmaddsub213ps( + a.as_f32x16(), + b.as_f32x16(), + sub, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed unsigned 64-bit integers in a and b for greater-than, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_ps&expand=2692) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpgt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_gt(a.as_u64x8(), b.as_u64x8())) +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +pub unsafe fn _mm512_mask_fmsubadd_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fmsubadd = _mm512_fmsubadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f32x16())) } -/// Compare packed unsigned 64-bit integers in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_ps&expand=2694) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpgt_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpgt_epu64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +pub unsafe fn _mm512_maskz_fmsubadd_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fmsubadd = _mm512_fmsubadd_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmsubadd, zero)) } -/// Compare packed unsigned 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_ps&expand=2693) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmple_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_le(a.as_u64x8(), b.as_u64x8())) +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +pub unsafe fn _mm512_mask3_fmsubadd_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fmsubadd = _mm512_fmsubadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f32x16())) } -/// Compare packed unsigned 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_pd&expand=2679) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmple_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmple_epu64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +pub unsafe fn _mm512_fmsubadd_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + transmute(vfmaddsub213pd( + a.as_f64x8(), + b.as_f64x8(), + sub, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed unsigned 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_pd&expand=2680) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpge_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_ge(a.as_u64x8(), b.as_u64x8())) +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +pub unsafe fn _mm512_mask_fmsubadd_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fmsubadd = _mm512_fmsubadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f64x8())) } -/// Compare packed unsigned 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_pd&expand=2682) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpge_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpge_epu64_mask(b, a) & m +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +pub unsafe fn _mm512_maskz_fmsubadd_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fmsubadd = _mm512_fmsubadd_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmsubadd, zero)) } -/// Compare packed unsigned 64-bit integers in a and b for equality, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_pd&expand=2681) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpeq_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_eq(a.as_u64x8(), b.as_u64x8())) +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +pub unsafe fn _mm512_mask3_fmsubadd_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fmsubadd = _mm512_fmsubadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f64x8())) } -/// Compare packed unsigned 64-bit integers in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_ps&expand=2723) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpeq_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpeq_epu64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +pub unsafe fn _mm512_fnmadd_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + transmute(vfmadd132ps( + sub, + b.as_f32x16(), + c.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed unsigned 64-bit integers in a and b for inequality, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_ps&expand=2724) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpneq_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_ne(a.as_u64x8(), b.as_u64x8())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +pub unsafe fn _mm512_mask_fnmadd_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fnmadd = _mm512_fnmadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fnmadd, a.as_f32x16())) } -/// Compare packed unsigned 64-bit integers in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epu64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_ps&expand=2726) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpneq_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpneq_epu64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +pub unsafe fn _mm512_maskz_fnmadd_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fnmadd = _mm512_fnmadd_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fnmadd, zero)) } -/// Compare packed unsigned 64-bit integers in a and b based on the comparison operand specified by op. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_ps&expand=2725) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_cmp_epu64_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm3:expr) => { - vpcmpuq(a.as_i64x8(), b.as_i64x8(), $imm3, neg_one) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +pub unsafe fn _mm512_mask3_fnmadd_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fnmadd = _mm512_fnmadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fnmadd, c.as_f32x16())) } -/// Compare packed unsigned 64-bit integers in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_pd&expand=2711) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_epu64_mask( - m: __mmask8, - a: __m512i, - b: __m512i, - op: _MM_CMPINT_ENUM, -) -> __mmask8 { - macro_rules! call { - ($imm3:expr) => { - vpcmpuq(a.as_i64x8(), b.as_i64x8(), $imm3, m as i8) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +pub unsafe fn _mm512_fnmadd_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + transmute(vfmadd132pd( + sub, + b.as_f64x8(), + c.as_f64x8(), + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed signed 64-bit integers in a and b for less-than, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_pd&expand=2712) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmplt_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_lt(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +pub unsafe fn _mm512_mask_fnmadd_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fnmadd = _mm512_fnmadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fnmadd, a.as_f64x8())) } -/// Compare packed signed 64-bit integers in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_pd&expand=2714) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmplt_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmplt_epi64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +pub unsafe fn _mm512_maskz_fnmadd_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fnmadd = _mm512_fnmadd_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fnmadd, zero)) } -/// Compare packed signed 64-bit integers in a and b for greater-than, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_pd&expand=2713) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpgt_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_gt(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +pub unsafe fn _mm512_mask3_fnmadd_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fnmadd = _mm512_fnmadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fnmadd, c.as_f64x8())) } -/// Compare packed signed 64-bit integers in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_ps&expand=2771) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpgt_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpgt_epi64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +pub unsafe fn _mm512_fnmsub_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + transmute(vfmadd132ps( + suba, + b.as_f32x16(), + subc, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed signed 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_ps&expand=2772) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmple_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_le(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +pub unsafe fn _mm512_mask_fnmsub_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fnmsub = _mm512_fnmsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fnmsub, a.as_f32x16())) } -/// Compare packed signed 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_ps&expand=2774) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmple_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmple_epi64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +pub unsafe fn _mm512_maskz_fnmsub_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fnmsub = _mm512_fnmsub_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fnmsub, zero)) } -/// Compare packed signed 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_ps&expand=2773) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpge_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_ge(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +pub unsafe fn _mm512_mask3_fnmsub_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fnmsub = _mm512_fnmsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fnmsub, c.as_f32x16())) } -/// Compare packed signed 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_pd&expand=2759) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpge_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpge_epi64_mask(b, a) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +pub unsafe fn _mm512_fnmsub_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + transmute(vfmadd132pd( + suba, + b.as_f64x8(), + subc, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Compare packed signed 64-bit integers in a and b for equality, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_pd&expand=2760) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpeq_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_eq(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +pub unsafe fn _mm512_mask_fnmsub_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fnmsub = _mm512_fnmsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fnmsub, a.as_f64x8())) } -/// Compare packed signed 64-bit integers in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_pd&expand=2762) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpeq_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpeq_epi64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +pub unsafe fn _mm512_maskz_fnmsub_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fnmsub = _mm512_fnmsub_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fnmsub, zero)) } -/// Compare packed signed 64-bit integers in a and b for inequality, and store the results in a mask vector. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_pd&expand=2761) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpneq_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_ne(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +pub unsafe fn _mm512_mask3_fnmsub_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fnmsub = _mm512_fnmsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fnmsub, c.as_f64x8())) } -/// Compare packed signed 64-bit integers in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compute the approximate reciprocal of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rcp14_ps&expand=4502) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpneq_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpneq_epi64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vrcp14ps))] +pub unsafe fn _mm512_rcp14_ps(a: __m512) -> __m512 { + transmute(vrcp14ps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + )) } -/// Compare packed signed 64-bit integers in a and b based on the comparison operand specified by op. +/// Compute the approximate reciprocal of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rcp14_ps&expand=4500) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_cmp_epi64_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm3:expr) => { - vpcmpq(a.as_i64x8(), b.as_i64x8(), $imm3, neg_one) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vrcp14ps))] +pub unsafe fn _mm512_mask_rcp14_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + transmute(vrcp14ps(a.as_f32x16(), src.as_f32x16(), k)) } -/// Compare packed signed 64-bit integers in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Compute the approximate reciprocal of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rcp14_ps&expand=4501) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_epi64_mask( - m: __mmask8, - a: __m512i, - b: __m512i, - op: _MM_CMPINT_ENUM, -) -> __mmask8 { - macro_rules! call { - ($imm3:expr) => { - vpcmpq(a.as_i64x8(), b.as_i64x8(), $imm3, m as i8) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vrcp14ps))] +pub unsafe fn _mm512_maskz_rcp14_ps(k: __mmask16, a: __m512) -> __m512 { + transmute(vrcp14ps(a.as_f32x16(), _mm512_setzero_ps().as_f32x16(), k)) } -/// Returns vector of type `__m512d` with undefined elements. +/// Compute the approximate reciprocal of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rcp14_pd&expand=4493) #[inline] #[target_feature(enable = "avx512f")] -// This intrinsic has no corresponding instruction. -pub unsafe fn _mm512_undefined_pd() -> __m512d { - _mm512_set1_pd(0.0) +#[cfg_attr(test, assert_instr(vrcp14pd))] +pub unsafe fn _mm512_rcp14_pd(a: __m512d) -> __m512d { + transmute(vrcp14pd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + )) } -/// Returns vector of type `__m512` with undefined elements. +/// Compute the approximate reciprocal of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rcp14_pd&expand=4491) #[inline] #[target_feature(enable = "avx512f")] -// This intrinsic has no corresponding instruction. -pub unsafe fn _mm512_undefined_ps() -> __m512 { - _mm512_set1_ps(0.0) +#[cfg_attr(test, assert_instr(vrcp14pd))] +pub unsafe fn _mm512_mask_rcp14_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + transmute(vrcp14pd(a.as_f64x8(), src.as_f64x8(), k)) } -/// Loads 512-bits (composed of 8 packed double-precision (64-bit) -/// floating-point elements) from memory into result. -/// `mem_addr` does not need to be aligned on any particular boundary. +/// Compute the approximate reciprocal of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rcp14_pd&expand=4492) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovups))] -pub unsafe fn _mm512_loadu_pd(mem_addr: *const f64) -> __m512d { - ptr::read_unaligned(mem_addr as *const __m512d) +#[cfg_attr(test, assert_instr(vrcp14pd))] +pub unsafe fn _mm512_maskz_rcp14_pd(k: __mmask8, a: __m512d) -> __m512d { + transmute(vrcp14pd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k)) } -/// Stores 512-bits (composed of 8 packed double-precision (64-bit) -/// floating-point elements) from `a` into memory. -/// `mem_addr` does not need to be aligned on any particular boundary. +/// Compute the approximate reciprocal square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rsqrt14_ps&expand=4819) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovups))] -pub unsafe fn _mm512_storeu_pd(mem_addr: *mut f64, a: __m512d) { - ptr::write_unaligned(mem_addr as *mut __m512d, a); +#[cfg_attr(test, assert_instr(vrsqrt14ps))] +pub unsafe fn _mm512_rsqrt14_ps(a: __m512) -> __m512 { + transmute(vrsqrt14ps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + )) } -/// Loads 512-bits (composed of 16 packed single-precision (32-bit) -/// floating-point elements) from memory into result. -/// `mem_addr` does not need to be aligned on any particular boundary. +/// Compute the approximate reciprocal square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rsqrt14_ps&expand=4817) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovups))] -pub unsafe fn _mm512_loadu_ps(mem_addr: *const f32) -> __m512 { - ptr::read_unaligned(mem_addr as *const __m512) +#[cfg_attr(test, assert_instr(vrsqrt14ps))] +pub unsafe fn _mm512_mask_rsqrt14_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + transmute(vrsqrt14ps(a.as_f32x16(), src.as_f32x16(), k)) } -/// Stores 512-bits (composed of 16 packed single-precision (32-bit) -/// floating-point elements) from `a` into memory. -/// `mem_addr` does not need to be aligned on any particular boundary. +/// Compute the approximate reciprocal square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rsqrt14_ps&expand=4818) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovups))] -#[stable(feature = "simd_x86", since = "1.27.0")] -pub unsafe fn _mm512_storeu_ps(mem_addr: *mut f32, a: __m512) { - ptr::write_unaligned(mem_addr as *mut __m512, a); +#[cfg_attr(test, assert_instr(vrsqrt14ps))] +pub unsafe fn _mm512_maskz_rsqrt14_ps(k: __mmask16, a: __m512) -> __m512 { + transmute(vrsqrt14ps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + k, + )) } -/// Sets packed 64-bit integers in `dst` with the supplied values in -/// reverse order. +/// Compute the approximate reciprocal square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rsqrt14_pd&expand=4812) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_setr_pd( - e0: f64, - e1: f64, - e2: f64, - e3: f64, - e4: f64, - e5: f64, - e6: f64, - e7: f64, -) -> __m512d { - let r = f64x8::new(e0, e1, e2, e3, e4, e5, e6, e7); - transmute(r) +#[cfg_attr(test, assert_instr(vrsqrt14pd))] +pub unsafe fn _mm512_rsqrt14_pd(a: __m512d) -> __m512d { + transmute(vrsqrt14pd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + )) } -/// Sets packed 64-bit integers in `dst` with the supplied values. +/// Compute the approximate reciprocal square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. /// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rsqrt14_pd&expand=4810) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set_pd( - e0: f64, - e1: f64, - e2: f64, - e3: f64, - e4: f64, - e5: f64, - e6: f64, - e7: f64, -) -> __m512d { - _mm512_setr_pd(e7, e6, e5, e4, e3, e2, e1, e0) +#[cfg_attr(test, assert_instr(vrsqrt14pd))] +pub unsafe fn _mm512_mask_rsqrt14_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + transmute(vrsqrt14pd(a.as_f64x8(), src.as_f64x8(), k)) } -/// Equal -pub const _MM_CMPINT_EQ: _MM_CMPINT_ENUM = 0x00; -/// Less-than -pub const _MM_CMPINT_LT: _MM_CMPINT_ENUM = 0x01; -/// Less-than-or-equal -pub const _MM_CMPINT_LE: _MM_CMPINT_ENUM = 0x02; -/// False -pub const _MM_CMPINT_FALSE: _MM_CMPINT_ENUM = 0x03; -/// Not-equal -pub const _MM_CMPINT_NE: _MM_CMPINT_ENUM = 0x04; -/// Not less-than -pub const _MM_CMPINT_NLT: _MM_CMPINT_ENUM = 0x05; -/// Not less-than-or-equal -pub const _MM_CMPINT_NLE: _MM_CMPINT_ENUM = 0x06; -/// True -pub const _MM_CMPINT_TRUE: _MM_CMPINT_ENUM = 0x07; +/// Compute the approximate reciprocal square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rsqrt14_pd&expand=4811) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14pd))] +pub unsafe fn _mm512_maskz_rsqrt14_pd(k: __mmask8, a: __m512d) -> __m512d { + transmute(vrsqrt14pd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k)) +} -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.x86.avx512.gather.dpd.512"] - fn vgatherdpd(src: f64x8, slice: *const i8, offsets: i32x8, mask: i8, scale: i32) -> f64x8; - #[link_name = "llvm.x86.avx512.gather.dps.512"] - fn vgatherdps(src: f32x16, slice: *const i8, offsets: i32x16, mask: i16, scale: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.gather.qpd.512"] - fn vgatherqpd(src: f64x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> f64x8; - #[link_name = "llvm.x86.avx512.gather.qps.512"] - fn vgatherqps(src: f32x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> f32x8; - #[link_name = "llvm.x86.avx512.gather.dpq.512"] - fn vpgatherdq(src: i64x8, slice: *const i8, offsets: i32x8, mask: i8, scale: i32) -> i64x8; - #[link_name = "llvm.x86.avx512.gather.dpi.512"] - fn vpgatherdd(src: i32x16, slice: *const i8, offsets: i32x16, mask: i16, scale: i32) -> i32x16; - #[link_name = "llvm.x86.avx512.gather.qpq.512"] - fn vpgatherqq(src: i64x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> i64x8; - #[link_name = "llvm.x86.avx512.gather.qpi.512"] - fn vpgatherqd(src: i32x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> i32x8; +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_ps&expand=2844) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps))] +pub unsafe fn _mm512_getexp_ps(a: __m512) -> __m512 { + transmute(vgetexpps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} - #[link_name = "llvm.x86.avx512.scatter.dpd.512"] - fn vscatterdpd(slice: *mut i8, mask: i8, offsets: i32x8, src: f64x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.dps.512"] - fn vscatterdps(slice: *mut i8, mask: i16, offsets: i32x16, src: f32x16, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.qpd.512"] - fn vscatterqpd(slice: *mut i8, mask: i8, offsets: i64x8, src: f64x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.qps.512"] - fn vscatterqps(slice: *mut i8, mask: i8, offsets: i64x8, src: f32x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.dpq.512"] - fn vpscatterdq(slice: *mut i8, mask: i8, offsets: i32x8, src: i64x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.dpi.512"] - fn vpscatterdd(slice: *mut i8, mask: i16, offsets: i32x16, src: i32x16, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.qpq.512"] - fn vpscatterqq(slice: *mut i8, mask: i8, offsets: i64x8, src: i64x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.qpi.512"] - fn vpscatterqd(slice: *mut i8, mask: i8, offsets: i64x8, src: i32x8, scale: i32); +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_ps&expand=2845) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps))] +pub unsafe fn _mm512_mask_getexp_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + transmute(vgetexpps( + a.as_f32x16(), + src.as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} - #[link_name = "llvm.x86.avx512.mask.cmp.ss"] - fn vcmpss(a: __m128, b: __m128, op: i32, m: i8, sae: i32) -> i8; - #[link_name = "llvm.x86.avx512.mask.cmp.sd"] - fn vcmpsd(a: __m128d, b: __m128d, op: i32, m: i8, sae: i32) -> i8; - #[link_name = "llvm.x86.avx512.mask.cmp.ps.512"] - fn vcmpps(a: f32x16, b: f32x16, op: i32, m: i16, sae: i32) -> i16; - #[link_name = "llvm.x86.avx512.mask.cmp.pd.512"] - fn vcmppd(a: f64x8, b: f64x8, op: i32, m: i8, sae: i32) -> i8; - #[link_name = "llvm.x86.avx512.mask.ucmp.q.512"] - fn vpcmpuq(a: i64x8, b: i64x8, op: i32, m: i8) -> i8; - #[link_name = "llvm.x86.avx512.mask.cmp.q.512"] - fn vpcmpq(a: i64x8, b: i64x8, op: i32, m: i8) -> i8; - #[link_name = "llvm.x86.avx512.mask.ucmp.d.512"] - fn vpcmpud(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; - #[link_name = "llvm.x86.avx512.mask.cmp.d.512"] - fn vpcmpd(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_ps&expand=2846) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps))] +pub unsafe fn _mm512_maskz_getexp_ps(k: __mmask16, a: __m512) -> __m512 { + transmute(vgetexpps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) } -#[cfg(test)] -mod tests { - use std; - use stdarch_test::simd_test; +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_pd&expand=2835) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd))] +pub unsafe fn _mm512_getexp_pd(a: __m512d) -> __m512d { + transmute(vgetexppd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} - use crate::core_arch::x86::*; - use crate::hint::black_box; +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_pd&expand=2836) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd))] +pub unsafe fn _mm512_mask_getexp_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + transmute(vgetexppd( + a.as_f64x8(), + src.as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_abs_epi32() { - #[rustfmt::skip] - let a = _mm512_setr_epi32( - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - ); - let r = _mm512_abs_epi32(a); - let e = _mm512_setr_epi32( - 0, - 1, - 1, - i32::MAX, - i32::MAX.wrapping_add(1), - 100, - 100, - 32, - 0, - 1, - 1, - i32::MAX, - i32::MAX.wrapping_add(1), - 100, - 100, - 32, - ); - assert_eq_m512i(r, e); +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_pd&expand=2837) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd))] +pub unsafe fn _mm512_maskz_getexp_pd(k: __mmask8, a: __m512d) -> __m512d { + transmute(vgetexppd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_ps&expand=2880) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _mm512_getmant_ps( + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512 { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4, + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + ) + }; } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_abs_epi32() { - #[rustfmt::skip] - let a = _mm512_setr_epi32( - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - ); - let r = _mm512_mask_abs_epi32(a, 0, a); - assert_eq_m512i(r, a); - let r = _mm512_mask_abs_epi32(a, 0b11111111, a); - let e = _mm512_setr_epi32( - 0, - 1, - 1, - i32::MAX, - i32::MAX.wrapping_add(1), - 100, - 100, - 32, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - assert_eq_m512i(r, e); +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_ps&expand=2881) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_mask_getmant_ps( + src: __m512, + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512 { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4, + src.as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_abs_epi32() { - #[rustfmt::skip] - let a = _mm512_setr_epi32( - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - ); - let r = _mm512_maskz_abs_epi32(0, a); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_abs_epi32(0b11111111, a); - let e = _mm512_setr_epi32( - 0, - 1, - 1, - i32::MAX, - i32::MAX.wrapping_add(1), - 100, - 100, - 32, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - assert_eq_m512i(r, e); +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_ps&expand=2882) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm512_maskz_getmant_ps( + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512 { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4, + _mm512_setzero_ps().as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32gather_ps() { - let mut arr = [0f32; 256]; - for i in 0..256 { - arr[i] = i as f32; - } - // A multiplier of 4 is word-addressing - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 120, 128, 136, 144, 152, 160, 168, 176); - let r = _mm512_i32gather_ps(index, arr.as_ptr() as *const u8, 4); - #[rustfmt::skip] - assert_eq_m512(r, _mm512_setr_ps(0., 16., 32., 48., 64., 80., 96., 112., - 120., 128., 136., 144., 152., 160., 168., 176.)); +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_pd&expand=2871) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _mm512_getmant_pd( + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512d { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4, + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + ) + }; } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32gather_ps() { - let mut arr = [0f32; 256]; - for i in 0..256 { - arr[i] = i as f32; - } - let src = _mm512_set1_ps(2.); - let mask = 0b10101010_10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 120, 128, 136, 144, 152, 160, 168, 176); - // A multiplier of 4 is word-addressing - let r = _mm512_mask_i32gather_ps(src, mask, index, arr.as_ptr() as *const u8, 4); - #[rustfmt::skip] - assert_eq_m512(r, _mm512_setr_ps(2., 16., 2., 48., 2., 80., 2., 112., - 2., 128., 2., 144., 2., 160., 2., 176.)); +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_pd&expand=2872) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_mask_getmant_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512d { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4, + src.as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32gather_epi32() { - let mut arr = [0i32; 256]; - for i in 0..256 { - arr[i] = i as i32; - } - // A multiplier of 4 is word-addressing - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 120, 128, 136, 144, 152, 160, 168, 176); - let r = _mm512_i32gather_epi32(index, arr.as_ptr() as *const u8, 4); - #[rustfmt::skip] - assert_eq_m512i(r, _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 120, 128, 136, 144, 152, 160, 168, 176)); +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_pd&expand=2873) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm512_maskz_getmant_pd( + k: __mmask8, + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512d { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4, + _mm512_setzero_pd().as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32gather_epi32() { - let mut arr = [0i32; 256]; - for i in 0..256 { - arr[i] = i as i32; - } - let src = _mm512_set1_epi32(2); - let mask = 0b10101010_10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - // A multiplier of 4 is word-addressing - let r = _mm512_mask_i32gather_epi32(src, mask, index, arr.as_ptr() as *const u8, 4); - #[rustfmt::skip] - assert_eq_m512i(r, _mm512_setr_epi32(2, 16, 2, 48, 2, 80, 2, 112, - 2, 144, 2, 176, 2, 208, 2, 240)); +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_round_ps&expand=145) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_add_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vaddps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32scatter_ps() { - let mut arr = [0f32; 256]; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - let src = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - // A multiplier of 4 is word-addressing - _mm512_i32scatter_ps(arr.as_mut_ptr() as *mut u8, index, src, 4); - let mut expected = [0f32; 256]; - for i in 0..16 { - expected[i * 16] = (i + 1) as f32; - } - assert_eq!(&arr[..], &expected[..],); +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_round_ps&expand=146) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_add_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vaddps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let addround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, addround, src.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32scatter_ps() { - let mut arr = [0f32; 256]; - let mask = 0b10101010_10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - let src = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - // A multiplier of 4 is word-addressing - _mm512_mask_i32scatter_ps(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); - let mut expected = [0f32; 256]; - for i in 0..8 { - expected[i * 32 + 16] = 2. * (i + 1) as f32; - } - assert_eq!(&arr[..], &expected[..],); +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_round_ps&expand=147) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_add_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vaddps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let addround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, addround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32scatter_epi32() { - let mut arr = [0i32; 256]; - #[rustfmt::skip] - - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - let src = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - // A multiplier of 4 is word-addressing - _mm512_i32scatter_epi32(arr.as_mut_ptr() as *mut u8, index, src, 4); - let mut expected = [0i32; 256]; - for i in 0..16 { - expected[i * 16] = (i + 1) as i32; - } - assert_eq!(&arr[..], &expected[..],); +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_round_pd&expand=142) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_add_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vaddpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32scatter_epi32() { - let mut arr = [0i32; 256]; - let mask = 0b10101010_10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - let src = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - // A multiplier of 4 is word-addressing - _mm512_mask_i32scatter_epi32(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); - let mut expected = [0i32; 256]; - for i in 0..8 { - expected[i * 32 + 16] = 2 * (i + 1) as i32; - } - assert_eq!(&arr[..], &expected[..],); +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_round_pd&expand=143) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_add_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vaddpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let addround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, addround, src.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmplt_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let m = _mm512_cmplt_ps_mask(a, b); - assert_eq!(m, 0b00000101_00000101); +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_round_pd&expand=144) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_add_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vaddpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let addround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, addround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmplt_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmplt_ps_mask(mask, a, b); - assert_eq!(r, 0b00000100_00000100); +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_round_ps&expand=5739) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_sub_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsubps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpnlt_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - assert_eq!(_mm512_cmpnlt_ps_mask(a, b), !_mm512_cmplt_ps_mask(a, b)); +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_round_ps&expand=5737) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_sub_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsubps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let subround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, subround, src.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpnlt_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01111010_01111010; - assert_eq!(_mm512_mask_cmpnlt_ps_mask(mask, a, b), 0b01111010_01111010); +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_round_ps&expand=5738) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_sub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsubps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let subround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, subround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpnle_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let m = _mm512_cmpnle_ps_mask(b, a); - assert_eq!(m, 0b00001101_00001101); +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_round_pd&expand=5736) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_sub_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsubpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpnle_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmpnle_ps_mask(mask, b, a); - assert_eq!(r, 0b00000100_00000100); +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_round_pd&expand=5734) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_sub_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsubpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let subround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, subround, src.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmple_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - assert_eq!(_mm512_cmple_ps_mask(a, b), 0b00100101_00100101); +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_round_pd&expand=5735) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_sub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsubpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let subround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, subround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmple_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01111010_01111010; - assert_eq!(_mm512_mask_cmple_ps_mask(mask, a, b), 0b00100000_00100000); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_round_ps&expand=3940) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_mul_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmulps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpeq_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); - let m = _mm512_cmpeq_ps_mask(b, a); - assert_eq!(m, 0b11001101_11001101); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_round_ps&expand=3938) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_mul_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmulps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let mulround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, mulround, src.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpeq_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpeq_ps_mask(mask, b, a); - assert_eq!(r, 0b01001000_01001000); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_round_ps&expand=3939) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_mul_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmulps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let mulround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mulround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpneq_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); - let m = _mm512_cmpneq_ps_mask(b, a); - assert_eq!(m, 0b00110010_00110010); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_round_pd&expand=3937) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_mul_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmulpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpneq_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpneq_ps_mask(mask, b, a); - assert_eq!(r, 0b00110010_00110010) +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_round_pd&expand=3935) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_mul_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmulpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let mulround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, mulround, src.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let m = _mm512_cmp_ps_mask(a, b, _CMP_LT_OQ); - assert_eq!(m, 0b00000101_00000101); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_round_ps&expand=3939) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_mul_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmulpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let mulround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, mulround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmp_ps_mask(mask, a, b, _CMP_LT_OQ); - assert_eq!(r, 0b00000100_00000100); +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_round_ps&expand=2168) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_div_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vdivps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_round_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let m = _mm512_cmp_round_ps_mask(a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 0b00000101_00000101); +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_round_ps&expand=2169) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_div_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vdivps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let divround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, divround, src.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_round_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmp_round_ps_mask(mask, a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); - assert_eq!(r, 0b00000100_00000100); +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_round_ps&expand=2170) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_div_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vdivps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; } + let divround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, divround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpord_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., - f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); - #[rustfmt::skip] - let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., - f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); - let m = _mm512_cmpord_ps_mask(a, b); - assert_eq!(m, 0b00000101_00000101); +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, =and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_round_pd&expand=2165) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_div_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vdivpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpord_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., - f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); - #[rustfmt::skip] - let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., - f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); - let mask = 0b11000011_11000011; - let m = _mm512_mask_cmpord_ps_mask(mask, a, b); - assert_eq!(m, 0b00000001_00000001); +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_round_pd&expand=2166) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_div_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vdivpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let divround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, divround, src.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpunord_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., - f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); - #[rustfmt::skip] - let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., - f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); - let m = _mm512_cmpunord_ps_mask(a, b); - - assert_eq!(m, 0b11111010_11111010); +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_round_pd&expand=2167) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_div_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vdivpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; } + let divround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, divround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpunord_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., - f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); - #[rustfmt::skip] - let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., - f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); - let mask = 0b00001111_00001111; - let m = _mm512_mask_cmpunord_ps_mask(mask, a, b); - assert_eq!(m, 0b000001010_00001010); +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_round_ps&expand=5377) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_sqrt_round_ps(a: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsqrtps(a.as_f32x16(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm_cmp_ss_mask() { - let a = _mm_setr_ps(2., 1., 1., 1.); - let b = _mm_setr_ps(1., 2., 2., 2.); - let m = _mm_cmp_ss_mask(a, b, _CMP_GE_OS); - assert_eq!(m, 1); +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_round_ps&expand=5375) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_sqrt_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsqrtps(a.as_f32x16(), $imm4) + }; } + let sqrtround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, sqrtround, src.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm_mask_cmp_ss_mask() { - let a = _mm_setr_ps(2., 1., 1., 1.); - let b = _mm_setr_ps(1., 2., 2., 2.); - let m = _mm_mask_cmp_ss_mask(0b10, a, b, _CMP_GE_OS); - assert_eq!(m, 0); - let m = _mm_mask_cmp_ss_mask(0b1, a, b, _CMP_GE_OS); - assert_eq!(m, 1); +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_round_ps&expand=5376) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_sqrt_round_ps(k: __mmask16, a: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsqrtps(a.as_f32x16(), $imm4) + }; } + let sqrtround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, sqrtround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm_cmp_round_ss_mask() { - let a = _mm_setr_ps(2., 1., 1., 1.); - let b = _mm_setr_ps(1., 2., 2., 2.); - let m = _mm_cmp_round_ss_mask(a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 1); +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_round_pd&expand=5374) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_sqrt_round_pd(a: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsqrtpd(a.as_f64x8(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm_mask_cmp_round_ss_mask() { - let a = _mm_setr_ps(2., 1., 1., 1.); - let b = _mm_setr_ps(1., 2., 2., 2.); - let m = _mm_mask_cmp_round_ss_mask(0b10, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 0); - let m = _mm_mask_cmp_round_ss_mask(0b1, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 1); +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_round_pd&expand=5372) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_sqrt_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsqrtpd(a.as_f64x8(), $imm4) + }; } + let sqrtround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, sqrtround, src.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm_cmp_sd_mask() { - let a = _mm_setr_pd(2., 1.); - let b = _mm_setr_pd(1., 2.); - let m = _mm_cmp_sd_mask(a, b, _CMP_GE_OS); - assert_eq!(m, 1); - } - - #[simd_test(enable = "avx512f")] - unsafe fn test_mm_mask_cmp_sd_mask() { - let a = _mm_setr_pd(2., 1.); - let b = _mm_setr_pd(1., 2.); - let m = _mm_mask_cmp_sd_mask(0b10, a, b, _CMP_GE_OS); - assert_eq!(m, 0); - let m = _mm_mask_cmp_sd_mask(0b1, a, b, _CMP_GE_OS); - assert_eq!(m, 1); +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_round_pd&expand=5373) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_sqrt_round_pd(k: __mmask8, a: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsqrtpd(a.as_f64x8(), $imm4) + }; } + let sqrtround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, sqrtround, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm_cmp_round_sd_mask() { - let a = _mm_setr_pd(2., 1.); - let b = _mm_setr_pd(1., 2.); - let m = _mm_cmp_round_sd_mask(a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 1); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_round_ps&expand=2565) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm_mask_cmp_round_sd_mask() { - let a = _mm_setr_pd(2., 1.); - let b = _mm_setr_pd(1., 2.); - let m = _mm_mask_cmp_round_sd_mask(0b10, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 0); - let m = _mm_mask_cmp_round_sd_mask(0b1, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 1); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_round_ps&expand=2566) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmadd_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; } + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, a.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmplt_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmplt_epu32_mask(a, b); - assert_eq!(m, 0b11001111_11001111); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in a using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_round_ps&expand=2568) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmadd_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; } + let fmadd = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmadd, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmplt_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmplt_epu32_mask(mask, a, b); - assert_eq!(r, 0b01001010_01001010); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_round_ps&expand=2567) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmadd_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; } + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, c.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpgt_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmpgt_epu32_mask(b, a); - assert_eq!(m, 0b11001111_11001111); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_round_pd&expand=2561) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmadd_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpgt_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpgt_epu32_mask(mask, b, a); - assert_eq!(r, 0b01001010_01001010); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_round_pd&expand=2562) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmadd_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; } + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, a.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmple_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - assert_eq!( - _mm512_cmple_epu32_mask(a, b), - !_mm512_cmpgt_epu32_mask(a, b) - ) +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_round_pd&expand=2564) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmadd_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; } + let fmadd = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmadd, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmple_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - assert_eq!( - _mm512_mask_cmple_epu32_mask(mask, a, b), - 0b01111010_01111010 - ); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_round_pd&expand=2563) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; } + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, c.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpge_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - assert_eq!( - _mm512_cmpge_epu32_mask(a, b), - !_mm512_cmplt_epu32_mask(a, b) - ) +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_round_ps&expand=2651) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpge_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - assert_eq!(_mm512_mask_cmpge_epu32_mask(mask, a, b), 0b01100000_0110000); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_round_ps&expand=2652) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmsub_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, a.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpeq_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let m = _mm512_cmpeq_epu32_mask(b, a); - assert_eq!(m, 0b11001111_11001111); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_round_ps&expand=2654) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmsub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpeq_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpeq_epu32_mask(mask, b, a); - assert_eq!(r, 0b01001010_01001010); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_round_ps&expand=2653) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmsub_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, c.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpneq_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let m = _mm512_cmpneq_epu32_mask(b, a); - assert_eq!(m, !_mm512_cmpeq_epu32_mask(b, a)); - } - - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpneq_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, -100, 100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, -100, 100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpneq_epu32_mask(mask, b, a); - assert_eq!(r, 0b00110010_00110010); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_round_pd&expand=2647) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmsub_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmp_epu32_mask(a, b, _MM_CMPINT_LT); - assert_eq!(m, 0b11001111_11001111); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_round_pd&expand=2648) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmsub_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, a.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LT); - assert_eq!(r, 0b01001010_01001010); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_round_pd&expand=2650) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmsub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmplt_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmplt_epi32_mask(a, b); - assert_eq!(m, 0b00000101_00000101); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_round_pd&expand=2649) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, c.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmplt_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmplt_epi32_mask(mask, a, b); - assert_eq!(r, 0b00000100_00000100); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_round_ps&expand=2619) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmaddsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpgt_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmpgt_epi32_mask(b, a); - assert_eq!(m, 0b00000101_00000101); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_round_ps&expand=2620) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmaddsub_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; } + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpgt_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmpgt_epi32_mask(mask, b, a); - assert_eq!(r, 0b00000100_00000100); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_round_ps&expand=2622) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmaddsub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; } + let fmaddsub = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmple_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - assert_eq!( - _mm512_cmple_epi32_mask(a, b), - !_mm512_cmpgt_epi32_mask(a, b) - ) +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_round_ps&expand=2621) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmaddsub_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; } + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f32x16())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmple_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - assert_eq!(_mm512_mask_cmple_epi32_mask(mask, a, b), 0b01100000_0110000); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_round_pd&expand=2615) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmaddsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpge_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - assert_eq!( - _mm512_cmpge_epi32_mask(a, b), - !_mm512_cmplt_epi32_mask(a, b) - ) +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_round_pd&expand=2616) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmaddsub_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; } + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpge_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - assert_eq!( - _mm512_mask_cmpge_epi32_mask(mask, a, b), - 0b01111010_01111010 - ); +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_round_pd&expand=2618) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmaddsub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; } + let fmaddsub = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpeq_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let m = _mm512_cmpeq_epi32_mask(b, a); - assert_eq!(m, 0b11001111_11001111); +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_round_pd&expand=2617) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmaddsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; } + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f64x8())) +} - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpeq_epi32_mask() { +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_round_ps&expand=2699) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmsubadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_round_ps&expand=2700) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmsubadd_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_round_ps&expand=2702) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmsubadd_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_round_ps&expand=2701) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmsubadd_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_round_pd&expand=2695) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmsubadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_round_pd&expand=2696) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmsubadd_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_round_pd&expand=2698) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmsubadd_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_round_pd&expand=2697) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmsubadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_round_ps&expand=2731) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_round_ps&expand=2732) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmadd_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_round_ps&expand=2734) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmadd_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_round_ps&expand=2733) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmadd_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_pd&expand=2711) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmadd_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_round_pd&expand=2728) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmadd_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_round_pd&expand=2730) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmadd_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_round_pd&expand=2729) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_round_ps&expand=2779) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_round_ps&expand=2780) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmsub_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_round_ps&expand=2782) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmsub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_round_ps&expand=2781) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmsub_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_round_pd&expand=2775) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmsub_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_round_pd&expand=2776) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmsub_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_round_pd&expand=2778) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmsub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_round_pd&expand=2777) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, c.as_f64x8())) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=max_round_ps&expand=3662) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_max_round_ps(a: __m512, b: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_round_ps&expand=3660) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_max_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_round_ps&expand=3661) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_max_round_ps(k: __mmask16, a: __m512, b: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_round_pd&expand=3659) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_max_round_pd(a: __m512d, b: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_round_pd&expand=3657) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_max_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_round_pd&expand=3658) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_max_round_pd(k: __mmask8, a: __m512d, b: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_round_ps&expand=3776) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_min_round_ps(a: __m512, b: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vminps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_round_ps&expand=3774) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_min_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vminps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_round_ps&expand=3775) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_min_round_ps(k: __mmask16, a: __m512, b: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vminps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_round_pd&expand=3773) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_min_round_pd(a: __m512d, b: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_round_pd&expand=3771) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_min_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_round_pd&expand=3772) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_min_round_pd(k: __mmask8, a: __m512d, b: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_round_ps&expand=2850) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_getexp_round_ps(a: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vgetexpps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_round_ps&expand=2851) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_getexp_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vgetexpps(a.as_f32x16(), src.as_f32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_round_ps&expand=2852) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_getexp_round_ps(k: __mmask16, a: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vgetexpps(a.as_f32x16(), _mm512_setzero_ps().as_f32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_round_pd&expand=2847) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_getexp_round_pd(a: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vgetexppd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_round_pd&expand=2848) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_getexp_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vgetexppd(a.as_f64x8(), src.as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_round_pd&expand=2849) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_getexp_round_pd(k: __mmask8, a: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vgetexppd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_round_ps&expand=2886) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(1, 2, 3)] +pub unsafe fn _mm512_getmant_round_ps( + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_round_ps&expand=2887) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(3, 4, 5)] +pub unsafe fn _mm512_mask_getmant_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4_1, + src.as_f32x16(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_round_ps&expand=2888) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(2, 3, 4)] +pub unsafe fn _mm512_maskz_getmant_round_ps( + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_ps().as_f32x16(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_round_pd&expand=2883) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(1, 2, 3)] +pub unsafe fn _mm512_getmant_round_pd( + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_round_pd&expand=2884) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(3, 4, 5)] +pub unsafe fn _mm512_mask_getmant_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4_1, + src.as_f64x8(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_round_pd&expand=2885) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(2, 3, 4)] +pub unsafe fn _mm512_maskz_getmant_round_pd( + k: __mmask8, + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_pd().as_f64x8(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=cvtps_epi32&expand=1737) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq))] +pub unsafe fn _mm512_cvtps_epi32(a: __m512) -> __m512i { + transmute(vcvtps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_epi32&expand=1738) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq))] +pub unsafe fn _mm512_mask_cvtps_epi32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2dq( + a.as_f32x16(), + src.as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtps_epi32&expand=1739) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq))] +pub unsafe fn _mm512_maskz_cvtps_epi32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtps_epu32&expand=1755) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq))] +pub unsafe fn _mm512_cvtps_epu32(a: __m512) -> __m512i { + transmute(vcvtps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_u32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_epu32&expand=1756) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq))] +pub unsafe fn _mm512_mask_cvtps_epu32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2udq( + a.as_f32x16(), + src.as_u32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=maskz_cvt_roundps_epu32&expand=1343) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq))] +pub unsafe fn _mm512_maskz_cvtps_epu32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_u32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtps_pd&expand=1769) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_cvtps_pd(a: __m256) -> __m512d { + transmute(vcvtps2pd( + a.as_f32x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_pd&expand=1770) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_mask_cvtps_pd(src: __m512d, k: __mmask8, a: __m256) -> __m512d { + transmute(vcvtps2pd( + a.as_f32x8(), + src.as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtps_pd&expand=1771) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_maskz_cvtps_pd(k: __mmask8, a: __m256) -> __m512d { + transmute(vcvtps2pd( + a.as_f32x8(), + _mm512_setzero_pd().as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundps_epi32&expand=1335) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundps_epi32(a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epi32&expand=1336) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundps_epi32( + src: __m512i, + k: __mmask16, + a: __m512, + rounding: i32, +) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2dq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundps_epi32&expand=1337) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundps_epi32(k: __mmask16, a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2dq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundps_epu32&expand=1341) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundps_epu32(a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_u32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epu32&expand=1342) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundps_epu32( + src: __m512i, + k: __mmask16, + a: __m512, + rounding: i32, +) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2udq(a.as_f32x16(), src.as_u32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=maskz_cvt_roundps_epu32&expand=1343) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundps_epu32(k: __mmask16, a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2udq(a.as_f32x16(), _mm512_setzero_si512().as_u32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=cvt_roundps_pd&expand=1347) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundps_pd(a: __m256, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vcvtps2pd( + a.as_f32x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epi32&expand=1336) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundps_pd( + src: __m512d, + k: __mmask8, + a: __m256, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vcvtps2pd(a.as_f32x8(), src.as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundps_epi32&expand=1337) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundps_pd(k: __mmask8, a: __m256, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vcvtps2pd(a.as_f32x8(), _mm512_setzero_pd().as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundps_epi32&expand=1916) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundps_epi32(a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundps_epi32&expand=1917) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundps_epi32( + src: __m512i, + k: __mmask16, + a: __m512, + sae: i32, +) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2dq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epi32&expand=1918) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundps_epi32(k: __mmask16, a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2dq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundps_epu32&expand=1922) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundps_epu32(a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundps_epu32&expand=1923) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundps_epu32( + src: __m512i, + k: __mmask16, + a: __m512, + sae: i32, +) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2udq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epu32&expand=1924) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundps_epu32(k: __mmask16, a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2udq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundpd_epi32&expand=1904) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundpd_epi32(a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundpd_epi32&expand=1905) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundpd_epi32( + src: __m256i, + k: __mmask8, + a: __m512d, + sae: i32, +) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2dq(a.as_f64x8(), src.as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epi32&expand=1918) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundpd_epi32(k: __mmask8, a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2dq(a.as_f64x8(), _mm256_setzero_si256().as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundpd_epu32&expand=1910) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundpd_epu32(a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundpd_epu32&expand=1911) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundpd_epu32( + src: __m256i, + k: __mmask8, + a: __m512d, + sae: i32, +) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2udq(a.as_f64x8(), src.as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttps_epi32&expand=1984) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq))] +pub unsafe fn _mm512_cvttps_epi32(a: __m512) -> __m512i { + transmute(vcvttps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttps_epi32&expand=1985) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq))] +pub unsafe fn _mm512_mask_cvttps_epi32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2dq( + a.as_f32x16(), + src.as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttps_epi32&expand=1986) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq))] +pub unsafe fn _mm512_maskz_cvttps_epi32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttps_epu32&expand=2002) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq))] +pub unsafe fn _mm512_cvttps_epu32(a: __m512) -> __m512i { + transmute(vcvttps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttps_epu32&expand=2003) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq))] +pub unsafe fn _mm512_mask_cvttps_epu32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2udq( + a.as_f32x16(), + src.as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttps_epu32&expand=2004) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq))] +pub unsafe fn _mm512_maskz_cvttps_epu32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundpd_epu32&expand=1912) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundpd_epu32(k: __mmask8, a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2udq(a.as_f64x8(), _mm256_setzero_si256().as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttpd_epi32&expand=1947) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq))] +pub unsafe fn _mm512_cvttpd_epi32(a: __m512d) -> __m256i { + transmute(vcvttpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttpd_epi32&expand=1948) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq))] +pub unsafe fn _mm512_mask_cvttpd_epi32(src: __m256i, k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2dq( + a.as_f64x8(), + src.as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttpd_epi32&expand=1949) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq))] +pub unsafe fn _mm512_maskz_cvttpd_epi32(k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttpd_epu32&expand=1965) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq))] +pub unsafe fn _mm512_cvttpd_epu32(a: __m512d) -> __m256i { + transmute(vcvttpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttpd_epu32&expand=1966) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq))] +pub unsafe fn _mm512_mask_cvttpd_epu32(src: __m256i, k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2udq( + a.as_f64x8(), + src.as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttpd_epu32&expand=1967) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq))] +pub unsafe fn _mm512_maskz_cvttpd_epu32(k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Returns vector of type `__m512d` with all elements set to zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vxorps))] +pub unsafe fn _mm512_setzero_pd() -> __m512d { + // All-0 is a properly initialized __m512d + mem::zeroed() +} + +/// Returns vector of type `__m512d` with all elements set to zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vxorps))] +pub unsafe fn _mm512_setzero_ps() -> __m512 { + // All-0 is a properly initialized __m512 + mem::zeroed() +} + +/// Returns vector of type `__m512i` with all elements set to zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_si512) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vxorps))] +pub unsafe fn _mm512_setzero_si512() -> __m512i { + // All-0 is a properly initialized __m512i + mem::zeroed() +} + +/// Sets packed 32-bit integers in `dst` with the supplied values in reverse +/// order. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr_epi32( + e15: i32, + e14: i32, + e13: i32, + e12: i32, + e11: i32, + e10: i32, + e9: i32, + e8: i32, + e7: i32, + e6: i32, + e5: i32, + e4: i32, + e3: i32, + e2: i32, + e1: i32, + e0: i32, +) -> __m512i { + let r = i32x16( + e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0, + ); + transmute(r) +} + +/// Gather double-precision (64-bit) floating-point elements from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherdpd, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i32gather_pd(offsets: __m256i, slice: *const u8, scale: i32) -> __m512d { + let zero = _mm512_setzero_pd().as_f64x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherdpd(zero, slice, offsets, neg_one, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather double-precision (64-bit) floating-point elements from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherdpd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32gather_pd( + src: __m512d, + mask: __mmask8, + offsets: __m256i, + slice: *const u8, + scale: i32, +) -> __m512d { + let src = src.as_f64x8(); + let slice = slice as *const i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherdpd(src, slice, offsets, mask as i8, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather double-precision (64-bit) floating-point elements from memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherqpd, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i64gather_pd(offsets: __m512i, slice: *const u8, scale: i32) -> __m512d { + let zero = _mm512_setzero_pd().as_f64x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherqpd(zero, slice, offsets, neg_one, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather double-precision (64-bit) floating-point elements from memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherqpd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64gather_pd( + src: __m512d, + mask: __mmask8, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m512d { + let src = src.as_f64x8(); + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherqpd(src, slice, offsets, mask as i8, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather single-precision (32-bit) floating-point elements from memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherqps, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i64gather_ps(offsets: __m512i, slice: *const u8, scale: i32) -> __m256 { + let zero = _mm256_setzero_ps().as_f32x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherqps(zero, slice, offsets, neg_one, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather single-precision (32-bit) floating-point elements from memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherqps, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64gather_ps( + src: __m256, + mask: __mmask8, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m256 { + let src = src.as_f32x8(); + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherqps(src, slice, offsets, mask as i8, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather single-precision (32-bit) floating-point elements from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherdps, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i32gather_ps(offsets: __m512i, slice: *const u8, scale: i32) -> __m512 { + let zero = _mm512_setzero_ps().as_f32x16(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vgatherdps(zero, slice, offsets, neg_one, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather single-precision (32-bit) floating-point elements from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherdps, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32gather_ps( + src: __m512, + mask: __mmask16, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m512 { + let src = src.as_f32x16(); + let slice = slice as *const i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vgatherdps(src, slice, offsets, mask as i16, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 32-bit integers from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherdd, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i32gather_epi32(offsets: __m512i, slice: *const u8, scale: i32) -> __m512i { + let zero = _mm512_setzero_si512().as_i32x16(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpgatherdd(zero, slice, offsets, neg_one, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 32-bit integers from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherdd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32gather_epi32( + src: __m512i, + mask: __mmask16, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m512i { + let src = src.as_i32x16(); + let mask = mask as i16; + let slice = slice as *const i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpgatherdd(src, slice, offsets, mask, $imm8) + }; + } + let r = constify_imm8!(scale, call); + transmute(r) +} + +/// Gather 64-bit integers from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherdq, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i32gather_epi64(offsets: __m256i, slice: *const u8, scale: i32) -> __m512i { + let zero = _mm512_setzero_si512().as_i64x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherdq(zero, slice, offsets, neg_one, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 64-bit integers from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherdq, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32gather_epi64( + src: __m512i, + mask: __mmask8, + offsets: __m256i, + slice: *const u8, + scale: i32, +) -> __m512i { + let src = src.as_i64x8(); + let mask = mask as i8; + let slice = slice as *const i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherdq(src, slice, offsets, mask, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 64-bit integers from memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherqq, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i64gather_epi64(offsets: __m512i, slice: *const u8, scale: i32) -> __m512i { + let zero = _mm512_setzero_si512().as_i64x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherqq(zero, slice, offsets, neg_one, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 64-bit integers from memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherqq, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64gather_epi64( + src: __m512i, + mask: __mmask8, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m512i { + let src = src.as_i64x8(); + let mask = mask as i8; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherqq(src, slice, offsets, mask, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 32-bit integers from memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherqd, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i64gather_epi32(offsets: __m512i, slice: *const u8, scale: i32) -> __m256i { + let zeros = _mm256_setzero_si256().as_i32x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherqd(zeros, slice, offsets, neg_one, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 32-bit integers from memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherqd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64gather_epi32( + src: __m256i, + mask: __mmask8, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m256i { + let src = src.as_i32x8(); + let mask = mask as i8; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherqd(src, slice, offsets, mask, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Scatter double-precision (64-bit) floating-point elements from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterdpd, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i32scatter_pd(slice: *mut u8, offsets: __m256i, src: __m512d, scale: i32) { + let src = src.as_f64x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterdpd(slice, neg_one, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter double-precision (64-bit) floating-point elements from src into memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterdpd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32scatter_pd( + slice: *mut u8, + mask: __mmask8, + offsets: __m256i, + src: __m512d, + scale: i32, +) { + let src = src.as_f64x8(); + let slice = slice as *mut i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterdpd(slice, mask as i8, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter double-precision (64-bit) floating-point elements from src into memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterqpd, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i64scatter_pd(slice: *mut u8, offsets: __m512i, src: __m512d, scale: i32) { + let src = src.as_f64x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterqpd(slice, neg_one, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter double-precision (64-bit) floating-point elements from src into memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterqpd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64scatter_pd( + slice: *mut u8, + mask: __mmask8, + offsets: __m512i, + src: __m512d, + scale: i32, +) { + let src = src.as_f64x8(); + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterqpd(slice, mask as i8, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter single-precision (32-bit) floating-point elements from memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterdps, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i32scatter_ps(slice: *mut u8, offsets: __m512i, src: __m512, scale: i32) { + let src = src.as_f32x16(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vscatterdps(slice, neg_one, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter single-precision (32-bit) floating-point elements from src into memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterdps, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32scatter_ps( + slice: *mut u8, + mask: __mmask16, + offsets: __m512i, + src: __m512, + scale: i32, +) { + let src = src.as_f32x16(); + let slice = slice as *mut i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vscatterdps(slice, mask as i16, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter single-precision (32-bit) floating-point elements from src into memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterqps, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i64scatter_ps(slice: *mut u8, offsets: __m512i, src: __m256, scale: i32) { + let src = src.as_f32x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterqps(slice, neg_one, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter single-precision (32-bit) floating-point elements from src into memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterqps, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64scatter_ps( + slice: *mut u8, + mask: __mmask8, + offsets: __m512i, + src: __m256, + scale: i32, +) { + let src = src.as_f32x8(); + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterqps(slice, mask as i8, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter 64-bit integers from src into memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterdq, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i32scatter_epi64(slice: *mut u8, offsets: __m256i, src: __m512i, scale: i32) { + let src = src.as_i64x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterdq(slice, neg_one, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter 64-bit integers from src into memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterdq, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32scatter_epi64( + slice: *mut u8, + mask: __mmask8, + offsets: __m256i, + src: __m512i, + scale: i32, +) { + let src = src.as_i64x8(); + let mask = mask as i8; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterdq(slice, mask, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter 64-bit integers from src into memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterqq, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i64scatter_epi64(slice: *mut u8, offsets: __m512i, src: __m512i, scale: i32) { + let src = src.as_i64x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterqq(slice, neg_one, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter 64-bit integers from src into memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterqq, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64scatter_epi64( + slice: *mut u8, + mask: __mmask8, + offsets: __m512i, + src: __m512i, + scale: i32, +) { + let src = src.as_i64x8(); + let mask = mask as i8; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterqq(slice, mask, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter 32-bit integers from src into memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterdd, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i32scatter_epi32(slice: *mut u8, offsets: __m512i, src: __m512i, scale: i32) { + let src = src.as_i32x16(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpscatterdd(slice, neg_one, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter 32-bit integers from src into memory using 32-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterdd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32scatter_epi32( + slice: *mut u8, + mask: __mmask16, + offsets: __m512i, + src: __m512i, + scale: i32, +) { + let src = src.as_i32x16(); + let mask = mask as i16; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpscatterdd(slice, mask, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter 32-bit integers from src into memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterqd, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i64scatter_epi32(slice: *mut u8, offsets: __m512i, src: __m256i, scale: i32) { + let src = src.as_i32x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterqd(slice, neg_one, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Scatter 32-bit integers from src into memory using 64-bit indices. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterqd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64scatter_epi32( + slice: *mut u8, + mask: __mmask8, + offsets: __m512i, + src: __m256i, + scale: i32, +) { + let src = src.as_i32x8(); + let mask = mask as i8; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterqd(slice, mask, offsets, src, $imm8) + }; + } + constify_imm8_gather!(scale, call); +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rol_epi32&expand=4685) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_rol_epi32(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprold(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rol_epi32&expand=4683) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_rol_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprold(a.as_i32x16(), $imm8) + }; + } + let rol = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, rol, src.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rol_epi32&expand=4684) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_rol_epi32(k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprold(a.as_i32x16(), $imm8) + }; + } + let rol = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ror_epi32&expand=4721) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_ror_epi32(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprord(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ror_epi32&expand=4719) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 123))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_ror_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprord(a.as_i32x16(), $imm8) + }; + } + let ror = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, ror, src.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ror_epi32&expand=4720) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 123))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_ror_epi32(k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprord(a.as_i32x16(), $imm8) + }; + } + let ror = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, ror, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rol_epi64&expand=4694) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_rol_epi64(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprolq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rol_epi64&expand=4692) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_rol_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprolq(a.as_i64x8(), $imm8) + }; + } + let rol = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, rol, src.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rol_epi64&expand=4693) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_rol_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprolq(a.as_i64x8(), $imm8) + }; + } + let rol = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ror_epi64&expand=4730) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_ror_epi64(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprorq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ror_epi64&expand=4728) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_ror_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprorq(a.as_i64x8(), $imm8) + }; + } + let ror = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, ror, src.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ror_epi64&expand=4729) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_ror_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprorq(a.as_i64x8(), $imm8) + }; + } + let ror = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, ror, zero)) +} + +/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_slli_epi32&expand=5310) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_slli_epi32(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsllid(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_slli_epi32&expand=5308) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_slli_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsllid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_slli_epi32&expand=5309) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_slli_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsllid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srli_epi32&expand=5522) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srli_epi32(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrlid(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srli_epi32&expand=5520) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srli_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrlid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srli_epi32&expand=5521) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srli_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrlid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_slli_epi64&expand=5319) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_slli_epi64(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpslliq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_slli_epi64&expand=5317) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_slli_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpslliq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_slli_epi64&expand=5318) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_slli_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpslliq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srli_epi64&expand=5531) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srli_epi64(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrliq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srli_epi64&expand=5529) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srli_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrliq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srli_epi64&expand=5530) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srli_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrliq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sll_epi32&expand=5280) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld))] +pub unsafe fn _mm512_sll_epi32(a: __m512i, count: __m128i) -> __m512i { + transmute(vpslld(a.as_i32x16(), count.as_i32x4())) +} + +/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sll_epi32&expand=5278) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld))] +pub unsafe fn _mm512_mask_sll_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sll_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi32&expand=5279) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld))] +pub unsafe fn _mm512_maskz_sll_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sll_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srl_epi32&expand=5492) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld))] +pub unsafe fn _mm512_srl_epi32(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrld(a.as_i32x16(), count.as_i32x4())) +} + +/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srl_epi32&expand=5490) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld))] +pub unsafe fn _mm512_mask_srl_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_srl_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srl_epi32&expand=5491) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld))] +pub unsafe fn _mm512_maskz_srl_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_srl_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sll_epi64&expand=5289) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq))] +pub unsafe fn _mm512_sll_epi64(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsllq(a.as_i64x8(), count.as_i64x2())) +} + +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sll_epi64&expand=5287) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq))] +pub unsafe fn _mm512_mask_sll_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sll_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi64&expand=5288) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq))] +pub unsafe fn _mm512_maskz_sll_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sll_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srl_epi64&expand=5501) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq))] +pub unsafe fn _mm512_srl_epi64(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrlq(a.as_i64x8(), count.as_i64x2())) +} + +/// Shift packed 64-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srl_epi64&expand=5499) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq))] +pub unsafe fn _mm512_mask_srl_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_srl_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi64&expand=5288) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq))] +pub unsafe fn _mm512_maskz_srl_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_srl_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sra_epi32&expand=5407) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad))] +pub unsafe fn _mm512_sra_epi32(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrad(a.as_i32x16(), count.as_i32x4())) +} + +/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sra_epi32&expand=5405) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad))] +pub unsafe fn _mm512_mask_sra_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sra_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sra_epi32&expand=5406) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad))] +pub unsafe fn _mm512_maskz_sra_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sra_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sra_epi64&expand=5416) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq))] +pub unsafe fn _mm512_sra_epi64(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsraq(a.as_i64x8(), count.as_i64x2())) +} + +/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sra_epi64&expand=5414) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq))] +pub unsafe fn _mm512_mask_sra_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sra_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sra_epi64&expand=5415) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq))] +pub unsafe fn _mm512_maskz_sra_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sra_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srai_epi32&expand=5436) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srai_epi32(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraid(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srai_epi32&expand=5434) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srai_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srai_epi32&expand=5435) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srai_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srai_epi64&expand=5445) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srai_epi64(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraiq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srai_epi64&expand=5443) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srai_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraiq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srai_epi64&expand=5444) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srai_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraiq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srav_epi32&expand=5465) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravd))] +pub unsafe fn _mm512_srav_epi32(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsravd(a.as_i32x16(), count.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srav_epi32&expand=5463) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravd))] +pub unsafe fn _mm512_mask_srav_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srav_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srav_epi32&expand=5464) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravd))] +pub unsafe fn _mm512_maskz_srav_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srav_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srav_epi64&expand=5474) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravq))] +pub unsafe fn _mm512_srav_epi64(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsravq(a.as_i64x8(), count.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srav_epi64&expand=5472) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravq))] +pub unsafe fn _mm512_mask_srav_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srav_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srav_epi64&expand=5473) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravq))] +pub unsafe fn _mm512_maskz_srav_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srav_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rolv_epi32&expand=4703) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvd))] +pub unsafe fn _mm512_rolv_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vprolvd(a.as_i32x16(), b.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rolv_epi32&expand=4701) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvd))] +pub unsafe fn _mm512_mask_rolv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let rol = _mm512_rolv_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, rol, src.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rolv_epi32&expand=4702) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvd))] +pub unsafe fn _mm512_maskz_rolv_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let rol = _mm512_rolv_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rorv_epi32&expand=4739) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvd))] +pub unsafe fn _mm512_rorv_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vprorvd(a.as_i32x16(), b.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rorv_epi32&expand=4737) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvd))] +pub unsafe fn _mm512_mask_rorv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let ror = _mm512_rorv_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, ror, src.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rorv_epi32&expand=4738) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvd))] +pub unsafe fn _mm512_maskz_rorv_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let ror = _mm512_rorv_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, ror, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rolv_epi64&expand=4712) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvq))] +pub unsafe fn _mm512_rolv_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vprolvq(a.as_i64x8(), b.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rolv_epi64&expand=4710) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvq))] +pub unsafe fn _mm512_mask_rolv_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let rol = _mm512_rolv_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, rol, src.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rolv_epi64&expand=4711) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvq))] +pub unsafe fn _mm512_maskz_rolv_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let rol = _mm512_rolv_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rorv_epi64&expand=4748) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvq))] +pub unsafe fn _mm512_rorv_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vprorvq(a.as_i64x8(), b.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rorv_epi64&expand=4746) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvq))] +pub unsafe fn _mm512_mask_rorv_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let ror = _mm512_rorv_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, ror, src.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rorv_epi64&expand=4747) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvq))] +pub unsafe fn _mm512_maskz_rorv_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let ror = _mm512_rorv_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, ror, zero)) +} + +/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sllv_epi32&expand=5342) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvd))] +pub unsafe fn _mm512_sllv_epi32(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsllvd(a.as_i32x16(), count.as_i32x16())) +} + +/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sllv_epi32&expand=5340) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvd))] +pub unsafe fn _mm512_mask_sllv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_sllv_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sllv_epi32&expand=5341) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvd))] +pub unsafe fn _mm512_maskz_sllv_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_sllv_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srlv_epi32&expand=5554) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvd))] +pub unsafe fn _mm512_srlv_epi32(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsrlvd(a.as_i32x16(), count.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srlv_epi32&expand=5552) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvd))] +pub unsafe fn _mm512_mask_srlv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srlv_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srlv_epi32&expand=5553) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvd))] +pub unsafe fn _mm512_maskz_srlv_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srlv_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sllv_epi64&expand=5351) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvq))] +pub unsafe fn _mm512_sllv_epi64(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsllvq(a.as_i64x8(), count.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sllv_epi64&expand=5349) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvq))] +pub unsafe fn _mm512_mask_sllv_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_sllv_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sllv_epi64&expand=5350) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvq))] +pub unsafe fn _mm512_maskz_sllv_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_sllv_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srlv_epi64&expand=5563) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvq))] +pub unsafe fn _mm512_srlv_epi64(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsrlvq(a.as_i64x8(), count.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mask_srlv_epi64&expand=5561) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvq))] +pub unsafe fn _mm512_mask_srlv_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srlv_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srlv_epi64&expand=5562) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvq))] +pub unsafe fn _mm512_maskz_srlv_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srlv_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permute_ps&expand=4170) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permute_ps(a: __m512, imm8: i32) -> __m512 { + macro_rules! call { + ($imm8:expr) => { + vpermilps(a.as_f32x16(), _mm512_set1_epi32($imm8).as_i32x16()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permute_ps&expand=4168) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permute_ps(src: __m512, k: __mmask16, a: __m512, imm8: i32) -> __m512 { + macro_rules! call { + ($imm8:expr) => { + vpermilps(a.as_f32x16(), _mm512_set1_epi32($imm8).as_i32x16()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permute_ps&expand=4169) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permute_ps(k: __mmask16, a: __m512, imm8: i32) -> __m512 { + macro_rules! call { + ($imm8:expr) => { + vpermilps(a.as_f32x16(), _mm512_set1_epi32($imm8).as_i32x16()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permute_pd&expand=4161) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permute_pd(a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermilpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permute_pd&expand=4159) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permute_pd(src: __m512d, k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermilpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permute_pd&expand=4160) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permute_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermilpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex_epi64&expand=4208) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] +//shoud be vpermq, but generate vpermpd. It generates vpermq with mask. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permutex_epi64(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpermq(a.as_i64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex_epi64&expand=4206) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpbroadcast, imm8 = 0b11111111))] //shoud be vpermq. change to vpbroadcast becaise CI Windows +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permutex_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + imm8: i32, +) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpermq(a.as_i64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_i64x8())) +} + +/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex_epi64&expand=4207) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpbroadcast, imm8 = 0b11111111))] //shoud be vpermq. change to vpbroadcast becaise CI Windows +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permutex_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpermq(a.as_i64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex_pd&expand=4214) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permutex_pd(a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex_pd&expand=4212) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permutex_pd(src: __m512d, k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex_pd&expand=4213) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permutex_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. Note that this intrinsic shuffles across 128-bit lanes, unlike past intrinsics that use the permutevar name. This intrinsic is identical to _mm512_permutexvar_epi32, and it is recommended that you use that intrinsic name. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_epi32&expand=4182) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermd, but generate vpermps. It generates vpermd with mask +pub unsafe fn _mm512_permutevar_epi32(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermd(a.as_i32x16(), idx.as_i32x16())) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). Note that this intrinsic shuffles across 128-bit lanes, unlike past intrinsics that use the permutevar name. This intrinsic is identical to _mm512_mask_permutexvar_epi32, and it is recommended that you use that intrinsic name. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_epi32&expand=4181) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermd))] +pub unsafe fn _mm512_mask_permutevar_epi32( + src: __m512i, + k: __mmask16, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutevar_epi32(idx, a).as_i32x16(); + transmute(simd_select_bitmask(k, permute, src.as_i32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_ps&expand=4200) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps))] +pub unsafe fn _mm512_permutevar_ps(a: __m512, b: __m512i) -> __m512 { + transmute(vpermilps(a.as_f32x16(), b.as_i32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_ps&expand=4198) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps))] +pub unsafe fn _mm512_mask_permutevar_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512i, +) -> __m512 { + let permute = _mm512_permutevar_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, permute, src.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutevar_ps&expand=4199) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps))] +pub unsafe fn _mm512_maskz_permutevar_ps(k: __mmask16, a: __m512, b: __m512i) -> __m512 { + let permute = _mm512_permutevar_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_pd&expand=4191) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd))] +pub unsafe fn _mm512_permutevar_pd(a: __m512d, b: __m512i) -> __m512d { + transmute(vpermilpd(a.as_f64x8(), b.as_i64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_pd&expand=4189) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd))] +pub unsafe fn _mm512_mask_permutevar_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512i, +) -> __m512d { + let permute = _mm512_permutevar_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutevar_pd&expand=4190) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd))] +pub unsafe fn _mm512_maskz_permutevar_pd(k: __mmask8, a: __m512d, b: __m512i) -> __m512d { + let permute = _mm512_permutevar_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_epi32&expand=4301) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermd, but generate vpermps. It generates vpermd with mask +pub unsafe fn _mm512_permutexvar_epi32(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermd(a.as_i32x16(), idx.as_i32x16())) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_epi32&expand=4299) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermd))] +pub unsafe fn _mm512_mask_permutexvar_epi32( + src: __m512i, + k: __mmask16, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutexvar_epi32(idx, a).as_i32x16(); + transmute(simd_select_bitmask(k, permute, src.as_i32x16())) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_epi32&expand=4300) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermd))] +pub unsafe fn _mm512_maskz_permutexvar_epi32(k: __mmask16, idx: __m512i, a: __m512i) -> __m512i { + let permute = _mm512_permutexvar_epi32(idx, a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_epi64&expand=4307) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermq, but generate vpermpd. It generates vpermd with mask +pub unsafe fn _mm512_permutexvar_epi64(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermq(a.as_i64x8(), idx.as_i64x8())) +} + +/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_epi64&expand=4305) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermq))] +pub unsafe fn _mm512_mask_permutexvar_epi64( + src: __m512i, + k: __mmask8, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutexvar_epi64(idx, a).as_i64x8(); + transmute(simd_select_bitmask(k, permute, src.as_i64x8())) +} + +/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_epi64&expand=4306) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermq))] +pub unsafe fn _mm512_maskz_permutexvar_epi64(k: __mmask8, idx: __m512i, a: __m512i) -> __m512i { + let permute = _mm512_permutexvar_epi64(idx, a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_ps&expand=4200) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermps))] +pub unsafe fn _mm512_permutexvar_ps(idx: __m512i, a: __m512) -> __m512 { + transmute(vpermps(a.as_f32x16(), idx.as_i32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_ps&expand=4326) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermps))] +pub unsafe fn _mm512_mask_permutexvar_ps( + src: __m512, + k: __mmask16, + idx: __m512i, + a: __m512, +) -> __m512 { + let permute = _mm512_permutexvar_ps(idx, a).as_f32x16(); + transmute(simd_select_bitmask(k, permute, src.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_ps&expand=4327) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermps))] +pub unsafe fn _mm512_maskz_permutexvar_ps(k: __mmask16, idx: __m512i, a: __m512) -> __m512 { + let permute = _mm512_permutexvar_ps(idx, a).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_pd&expand=4322) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermpd))] +pub unsafe fn _mm512_permutexvar_pd(idx: __m512i, a: __m512d) -> __m512d { + transmute(vpermpd(a.as_f64x8(), idx.as_i64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_pd&expand=4320) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermpd))] +pub unsafe fn _mm512_mask_permutexvar_pd( + src: __m512d, + k: __mmask8, + idx: __m512i, + a: __m512d, +) -> __m512d { + let permute = _mm512_permutexvar_pd(idx, a).as_f64x8(); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_pd&expand=4321) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermpd))] +pub unsafe fn _mm512_maskz_permutexvar_pd(k: __mmask8, idx: __m512i, a: __m512d) -> __m512d { + let permute = _mm512_permutexvar_pd(idx, a).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_epi32&expand=4238) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2d or vpermt2d +pub unsafe fn _mm512_permutex2var_epi32(a: __m512i, idx: __m512i, b: __m512i) -> __m512i { + transmute(vpermi2d(a.as_i32x16(), idx.as_i32x16(), b.as_i32x16())) +} + +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_epi32&expand=4235) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermt2d))] +pub unsafe fn _mm512_mask_permutex2var_epi32( + a: __m512i, + k: __mmask16, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); + transmute(simd_select_bitmask(k, permute, a.as_i32x16())) +} + +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_epi32&expand=4237) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2d or vpermt2d +pub unsafe fn _mm512_maskz_permutex2var_epi32( + k: __mmask16, + a: __m512i, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_epi32&expand=4236) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermi2d))] +pub unsafe fn _mm512_mask2_permutex2var_epi32( + a: __m512i, + idx: __m512i, + k: __mmask16, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); + transmute(simd_select_bitmask(k, permute, idx.as_i32x16())) +} + +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_epi64&expand=4250) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2q or vpermt2q +pub unsafe fn _mm512_permutex2var_epi64(a: __m512i, idx: __m512i, b: __m512i) -> __m512i { + transmute(vpermi2q(a.as_i64x8(), idx.as_i64x8(), b.as_i64x8())) +} + +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_epi64&expand=4247) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermt2q))] +pub unsafe fn _mm512_mask_permutex2var_epi64( + a: __m512i, + k: __mmask8, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); + transmute(simd_select_bitmask(k, permute, a.as_i64x8())) +} + +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_epi64&expand=4249) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2q or vpermt2q +pub unsafe fn _mm512_maskz_permutex2var_epi64( + k: __mmask8, + a: __m512i, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_epi64&expand=4248) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermi2q))] +pub unsafe fn _mm512_mask2_permutex2var_epi64( + a: __m512i, + idx: __m512i, + k: __mmask8, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); + transmute(simd_select_bitmask(k, permute, idx.as_i64x8())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_ps&expand=4286) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2ps or vpermt2ps +pub unsafe fn _mm512_permutex2var_ps(a: __m512, idx: __m512i, b: __m512) -> __m512 { + transmute(vpermi2ps(a.as_f32x16(), idx.as_i32x16(), b.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_ps&expand=4283) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermt2ps))] +pub unsafe fn _mm512_mask_permutex2var_ps( + a: __m512, + k: __mmask16, + idx: __m512i, + b: __m512, +) -> __m512 { + let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); + transmute(simd_select_bitmask(k, permute, a.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_ps&expand=4285) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2ps or vpermt2ps +pub unsafe fn _mm512_maskz_permutex2var_ps( + k: __mmask16, + a: __m512, + idx: __m512i, + b: __m512, +) -> __m512 { + let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_ps&expand=4284) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermi2ps, but it shows vpermt2ps +pub unsafe fn _mm512_mask2_permutex2var_ps( + a: __m512, + idx: __m512i, + k: __mmask16, + b: __m512, +) -> __m512 { + let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_pd&expand=4274) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2pd or vpermt2pd +pub unsafe fn _mm512_permutex2var_pd(a: __m512d, idx: __m512i, b: __m512d) -> __m512d { + transmute(vpermi2pd(a.as_f64x8(), idx.as_i64x8(), b.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_pd&expand=4271) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermt2pd))] +pub unsafe fn _mm512_mask_permutex2var_pd( + a: __m512d, + k: __mmask8, + idx: __m512i, + b: __m512d, +) -> __m512d { + let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); + transmute(simd_select_bitmask(k, permute, a.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_pd&expand=4273) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2pd or vpermt2pd +pub unsafe fn _mm512_maskz_permutex2var_pd( + k: __mmask8, + a: __m512d, + idx: __m512i, + b: __m512d, +) -> __m512d { + let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set) +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_pd&expand=4272) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermi2pd, but it shows vpermt2pd +pub unsafe fn _mm512_mask2_permutex2var_pd( + a: __m512d, + idx: __m512i, + k: __mmask8, + b: __m512d, +) -> __m512d { + let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_epi32&expand=5150) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_shuffle_epi32(a: __m512i, imm8: _MM_PERM_ENUM) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + a, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let r: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + transmute(r) +} + +/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_epi32&expand=5148) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpshufd, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_shuffle_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + imm8: _MM_PERM_ENUM, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + a, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + transmute(simd_select_bitmask(k, shuffle, src.as_i32x16())) +} + +/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_epi32&expand=5149) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpshufd, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_shuffle_epi32(k: __mmask16, a: __m512i, imm8: _MM_PERM_ENUM) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + a, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_ps&expand=5203) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_ps(a: __m512, b: __m512, imm8: i32) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + } +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_ps&expand=5201) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + imm8: i32, +) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_ps&expand=5202) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_ps(k: __mmask16, a: __m512, b: __m512, imm8: i32) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_pd&expand=5192) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_pd(a: __m512d, b: __m512d, imm8: i32) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle8 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle7 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 7) & 0x1 { + 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), + _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), + } + }; + } + macro_rules! shuffle6 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { + match (imm8 >> 6) & 0x1 { + 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), + _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), + } + }; + } + macro_rules! shuffle5 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { + match (imm8 >> 5) & 0x1 { + 0 => shuffle6!($a, $b, $c, $d, $e, 12), + _ => shuffle6!($a, $b, $c, $d, $e, 13), + } + }; + } + macro_rules! shuffle4 { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + match (imm8 >> 4) & 0x1 { + 0 => shuffle5!($a, $b, $c, $d, 4), + _ => shuffle5!($a, $b, $c, $d, 5), + } + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr) => { + match (imm8 >> 3) & 0x1 { + 0 => shuffle4!($a, $b, $c, 10), + _ => shuffle4!($a, $b, $c, 11), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr) => { + match (imm8 >> 2) & 0x1 { + 0 => shuffle3!($a, $b, 2), + _ => shuffle3!($a, $b, 3), + } + }; + } + macro_rules! shuffle1 { + ($a:expr) => { + match (imm8 >> 1) & 0x1 { + 0 => shuffle2!($a, 8), + _ => shuffle2!($a, 9), + } + }; + } + match imm8 & 0x1 { + 0 => shuffle1!(0), + _ => shuffle1!(1), + } +} + +/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_pd&expand=5190) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, +) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle8 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle7 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 7) & 0x1 { + 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), + _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), + } + }; + } + macro_rules! shuffle6 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { + match (imm8 >> 6) & 0x1 { + 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), + _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), + } + }; + } + macro_rules! shuffle5 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { + match (imm8 >> 5) & 0x1 { + 0 => shuffle6!($a, $b, $c, $d, $e, 12), + _ => shuffle6!($a, $b, $c, $d, $e, 13), + } + }; + } + macro_rules! shuffle4 { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + match (imm8 >> 4) & 0x1 { + 0 => shuffle5!($a, $b, $c, $d, 4), + _ => shuffle5!($a, $b, $c, $d, 5), + } + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr) => { + match (imm8 >> 3) & 0x1 { + 0 => shuffle4!($a, $b, $c, 10), + _ => shuffle4!($a, $b, $c, 11), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr) => { + match (imm8 >> 2) & 0x1 { + 0 => shuffle3!($a, $b, 2), + _ => shuffle3!($a, $b, 3), + } + }; + } + macro_rules! shuffle1 { + ($a:expr) => { + match (imm8 >> 1) & 0x1 { + 0 => shuffle2!($a, 8), + _ => shuffle2!($a, 9), + } + }; + } + let shuffle = match imm8 & 0x1 { + 0 => shuffle1!(0), + _ => shuffle1!(1), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_pd&expand=5191) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_pd(k: __mmask8, a: __m512d, b: __m512d, imm8: i32) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle8 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle7 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 7) & 0x1 { + 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), + _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), + } + }; + } + macro_rules! shuffle6 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { + match (imm8 >> 6) & 0x1 { + 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), + _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), + } + }; + } + macro_rules! shuffle5 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { + match (imm8 >> 5) & 0x1 { + 0 => shuffle6!($a, $b, $c, $d, $e, 12), + _ => shuffle6!($a, $b, $c, $d, $e, 13), + } + }; + } + macro_rules! shuffle4 { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + match (imm8 >> 4) & 0x1 { + 0 => shuffle5!($a, $b, $c, $d, 4), + _ => shuffle5!($a, $b, $c, $d, 5), + } + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr) => { + match (imm8 >> 3) & 0x1 { + 0 => shuffle4!($a, $b, $c, 10), + _ => shuffle4!($a, $b, $c, 11), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr) => { + match (imm8 >> 2) & 0x1 { + 0 => shuffle3!($a, $b, 2), + _ => shuffle3!($a, $b, 3), + } + }; + } + macro_rules! shuffle1 { + ($a:expr) => { + match (imm8 >> 1) & 0x1 { + 0 => shuffle2!($a, 8), + _ => shuffle2!($a, 9), + } + }; + } + let shuffle = match imm8 & 0x1 { + 0 => shuffle1!(0), + _ => shuffle1!(1), + }; + + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_i32&expand=5177) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] //should be vshufi32x4, but generate vshufi64x2 +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_i32x4(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + let b = b.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let r: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + transmute(r) +} + +/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_i32x&expand=5175) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_i32x4( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + let b = b.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_i32x16())) +} + +/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_i32&expand=5176) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_i32x4( + k: __mmask16, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + let b = b.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_i64x2&expand=5183) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_i64x2(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + } +} + +/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_i64x&expand=5181) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_i64x2( + src: __m512i, + k: __mmask8, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_i64x8())) +} + +/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_i64&expand=5182) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_i64x2( + k: __mmask8, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_f32x4&expand=5165) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] //should be vshuff32x4, but generate vshuff64x2 +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_f32x4(a: __m512, b: __m512, imm8: i32) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + } +} + +/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_f32&expand=5163) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_f32x4( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + imm8: i32, +) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f32x16())) +} + +/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_f32&expand=5164) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_f32x4(k: __mmask16, a: __m512, b: __m512, imm8: i32) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_f64x2&expand=5171) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_f64x2(a: __m512d, b: __m512d, imm8: i32) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + } +} + +/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_f64x2&expand=5169) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_f64x2( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, +) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f64x8())) +} + +/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_f64x2&expand=5170) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_f64x2( + k: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, +) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Extract 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from a, selected with imm8, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_extractf32x4_ps&expand=2442) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf32x4, imm8 = 3) +)] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_extractf32x4_ps(a: __m512, imm8: i32) -> __m128 { + match imm8 & 0x3 { + 0 => simd_shuffle4(a, _mm512_undefined_ps(), [0, 1, 2, 3]), + 1 => simd_shuffle4(a, _mm512_undefined_ps(), [4, 5, 6, 7]), + 2 => simd_shuffle4(a, _mm512_undefined_ps(), [8, 9, 10, 11]), + _ => simd_shuffle4(a, _mm512_undefined_ps(), [12, 13, 14, 15]), + } +} + +/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_moveldup_ps&expand=3862) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovsldup))] +pub unsafe fn _mm512_moveldup_ps(a: __m512) -> __m512 { + let r: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); + transmute(r) +} + +/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_moveldup_ps&expand=3860) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovsldup))] +pub unsafe fn _mm512_mask_moveldup_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); + transmute(simd_select_bitmask(k, mov, src.as_f32x16())) +} + +/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_moveldup_ps&expand=3861) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovsldup))] +pub unsafe fn _mm512_maskz_moveldup_ps(k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_movehdup_ps&expand=3852) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovshdup))] +pub unsafe fn _mm512_movehdup_ps(a: __m512) -> __m512 { + let r: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); + transmute(r) +} + +/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_movehdup&expand=3850) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovshdup))] +pub unsafe fn _mm512_mask_movehdup_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); + transmute(simd_select_bitmask(k, mov, src.as_f32x16())) +} + +/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_moveh&expand=3851) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovshdup))] +pub unsafe fn _mm512_maskz_movehdup_ps(k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_movedup_pd&expand=3843) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovddup))] +pub unsafe fn _mm512_movedup_pd(a: __m512d) -> __m512d { + let r: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); + transmute(r) +} + +/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_movedup_pd&expand=3841) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovddup))] +pub unsafe fn _mm512_mask_movedup_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + let mov: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); + transmute(simd_select_bitmask(k, mov, src.as_f64x8())) +} + +/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_movedup_pd&expand=3842) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovddup))] +pub unsafe fn _mm512_maskz_movedup_pd(k: __mmask8, a: __m512d) -> __m512d { + let mov: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_epi32&expand=272) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] //should be vpandd, but generate vpandq +pub unsafe fn _mm512_and_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_and(a.as_i32x16(), b.as_i32x16())) +} + +/// Performs element-by-element bitwise AND between packed 32-bit integer elements of v2 and v3, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_and_epi32&expand=273) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandd))] +pub unsafe fn _mm512_mask_and_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, and, src.as_i32x16())) +} + +/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_and_epi32&expand=274) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandd))] +pub unsafe fn _mm512_maskz_and_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, and, zero)) +} + +/// Compute the bitwise AND of 512 bits (composed of packed 64-bit integers) in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_epi64&expand=279) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_and_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_and(a.as_i64x8(), b.as_i64x8())) +} + +/// Compute the bitwise AND of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_and_epi64&expand=280) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_mask_and_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, and, src.as_i64x8())) +} + +/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_and_Epi32&expand=274) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_maskz_and_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, and, zero)) +} + +/// Compute the bitwise AND of 512 bits (representing integer data) in a and b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_si512&expand=302) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_and_si512(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_and(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_epi32&expand=4042) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_or_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_or(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_or_epi32&expand=4040) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpord))] +pub unsafe fn _mm512_mask_or_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, or, src.as_i32x16())) +} + +/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_or_epi32&expand=4041) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpord))] +pub unsafe fn _mm512_maskz_or_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, or, zero)) +} + +/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the resut in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_epi64&expand=4051) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_or_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_or(a.as_i64x8(), b.as_i64x8())) +} + +/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_or_epi64&expand=4049) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_mask_or_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, or, src.as_i64x8())) +} + +/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_or_epi64&expand=4050) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_maskz_or_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, or, zero)) +} + +/// Compute the bitwise OR of 512 bits (representing integer data) in a and b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_si512&expand=4072) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_or_si512(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_or(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_epi32&expand=6142) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_xor_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_xor(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_xor_epi32&expand=6140) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxord))] +pub unsafe fn _mm512_mask_xor_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, xor, src.as_i32x16())) +} + +/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_xor_epi32&expand=6141) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxord))] +pub unsafe fn _mm512_maskz_xor_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, xor, zero)) +} + +/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_epi64&expand=6151) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_xor_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_xor(a.as_i64x8(), b.as_i64x8())) +} + +/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_xor_epi64&expand=6149) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_mask_xor_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, xor, src.as_i64x8())) +} + +/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_xor_epi64&expand=6150) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_maskz_xor_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, xor, zero)) +} + +/// Compute the bitwise XOR of 512 bits (representing integer data) in a and b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_si512&expand=6172) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_xor_si512(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_xor(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise AND of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kand_mask16&expand=3212) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandw +pub unsafe fn _kand_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a & b) +} + +/// Compute the bitwise AND of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kand&expand=3210) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandw +pub unsafe fn _mm512_kand(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a & b) +} + +/// Compute the bitwise OR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kor_mask16&expand=3239) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(or))] // generate normal or code instead of korw +pub unsafe fn _kor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a | b) +} + +/// Compute the bitwise OR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kor&expand=3237) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(or))] // generate normal or code instead of korw +pub unsafe fn _mm512_kor(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a | b) +} + +/// Compute the bitwise XOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kxor_mask16&expand=3291) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal xor code instead of kxorw +pub unsafe fn _kxor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a ^ b) +} + +/// Compute the bitwise XOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kxor&expand=3289) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal xor code instead of kxorw +pub unsafe fn _mm512_kxor(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a ^ b) +} + +/// Compute the bitwise NOT of 16-bit mask a, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=knot_mask16&expand=3233) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _knot_mask16(a: __mmask16) -> __mmask16 { + transmute(a ^ 0b11111111_11111111) +} + +/// Compute the bitwise NOT of 16-bit mask a, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_knot&expand=3231) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_knot(a: __mmask16) -> __mmask16 { + transmute(a ^ 0b11111111_11111111) +} + +/// Compute the bitwise NOT of 16-bit masks a and then AND with b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kandn_mask16&expand=3218) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(not))] // generate normal and, not code instead of kandnw +pub unsafe fn _kandn_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_kand(_mm512_knot(a), b) +} + +/// Compute the bitwise NOT of 16-bit masks a and then AND with b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kandn&expand=3216) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(not))] // generate normal and code instead of kandw +pub unsafe fn _mm512_kandn(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_kand(_mm512_knot(a), b) +} + +/// Compute the bitwise XNOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kxnor_mask16&expand=3285) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal xor, not code instead of kxnorw +pub unsafe fn _kxnor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_knot(_mm512_kxor(a, b)) +} + +/// Compute the bitwise XNOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kxnor&expand=3283) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kandw +pub unsafe fn _mm512_kxnor(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_knot(_mm512_kxor(a, b)) +} + +/// Copy 16-bit mask a to k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm512_kmov&expand=3228) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kmovw +pub unsafe fn _mm512_kmov(a: __mmask16) -> __mmask16 { + let r: u16 = a; + transmute(r) +} + +/// Sets packed 32-bit integers in `dst` with the supplied values. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_ps) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set_ps( + e0: f32, + e1: f32, + e2: f32, + e3: f32, + e4: f32, + e5: f32, + e6: f32, + e7: f32, + e8: f32, + e9: f32, + e10: f32, + e11: f32, + e12: f32, + e13: f32, + e14: f32, + e15: f32, +) -> __m512 { + _mm512_setr_ps( + e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0, + ) +} + +/// Sets packed 32-bit integers in `dst` with the supplied values in +/// reverse order. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_ps) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr_ps( + e0: f32, + e1: f32, + e2: f32, + e3: f32, + e4: f32, + e5: f32, + e6: f32, + e7: f32, + e8: f32, + e9: f32, + e10: f32, + e11: f32, + e12: f32, + e13: f32, + e14: f32, + e15: f32, +) -> __m512 { + let r = f32x16::new( + e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, + ); + transmute(r) +} + +/// Broadcast 64-bit float `a` to all elements of `dst`. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_pd(a: f64) -> __m512d { + transmute(f64x8::splat(a)) +} + +/// Broadcast 32-bit float `a` to all elements of `dst`. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_ps(a: f32) -> __m512 { + transmute(f32x16::splat(a)) +} + +/// Sets packed 32-bit integers in `dst` with the supplied values. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set_epi32( + e15: i32, + e14: i32, + e13: i32, + e12: i32, + e11: i32, + e10: i32, + e9: i32, + e8: i32, + e7: i32, + e6: i32, + e5: i32, + e4: i32, + e3: i32, + e2: i32, + e1: i32, + e0: i32, +) -> __m512i { + _mm512_setr_epi32( + e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, + ) +} + +/// Broadcast 32-bit integer `a` to all elements of `dst`. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_epi32(a: i32) -> __m512i { + transmute(i32x16::splat(a)) +} + +/// Broadcast 64-bit integer `a` to all elements of `dst`. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_epi64(a: i64) -> __m512i { + transmute(i64x8::splat(a)) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmplt_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_LT_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmplt_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(m, a, b, _CMP_LT_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnlt_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpnlt_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_NLT_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnlt_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpnlt_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(m, a, b, _CMP_NLT_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmple_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_LE_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmple_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(m, a, b, _CMP_LE_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnle_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpnle_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_NLE_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnle_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpnle_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(m, a, b, _CMP_NLE_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for equality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpeq_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_EQ_OQ) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for equality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpeq_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(m, a, b, _CMP_EQ_OQ) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for inequality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpneq_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_NEQ_UQ) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for inequality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_ps_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpneq_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(m, a, b, _CMP_NEQ_UQ) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_ps_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_cmp_ps_mask(a: __m512, b: __m512, op: i32) -> __mmask16 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr) => { + vcmpps( + a.as_f32x16(), + b.as_f32x16(), + $imm5, + neg_one, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm5!(op, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op, +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_ps_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_mask_cmp_ps_mask(m: __mmask16, a: __m512, b: __m512, op: i32) -> __mmask16 { + macro_rules! call { + ($imm5:expr) => { + vcmpps( + a.as_f32x16(), + b.as_f32x16(), + $imm5, + m as i16, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm5!(op, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_ps_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2, 3)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm512_cmp_round_ps_mask(a: __m512, b: __m512, op: i32, sae: i32) -> __mmask16 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpps(a.as_f32x16(), b.as_f32x16(), $imm5, neg_one, $imm4) + }; + } + let r = constify_imm5_sae!(op, sae, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op, +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_ps_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3, 4)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm512_mask_cmp_round_ps_mask( + m: __mmask16, + a: __m512, + b: __m512, + op: i32, + sae: i32, +) -> __mmask16 { + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpps(a.as_f32x16(), b.as_f32x16(), $imm5, m as i16, $imm4) + }; + } + let r = constify_imm5_sae!(op, sae, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_ps_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_cmpord_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_ORD_Q) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_ps_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_mask_cmpord_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(m, a, b, _CMP_ORD_Q) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_ps_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_cmpunord_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_UNORD_Q) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_ps_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_mask_cmpunord_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(m, a, b, _CMP_UNORD_Q) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmplt_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_LT_OS) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmplt_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(m, a, b, _CMP_LT_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnlt_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpnlt_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_NLT_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnlt_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpnlt_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NLT_US) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmple_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_LE_OS) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmple_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(m, a, b, _CMP_LE_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnle_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpnle_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_NLE_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnle_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpnle_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NLE_US) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for equality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpeq_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_EQ_OQ) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for equality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpeq_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(m, a, b, _CMP_EQ_OQ) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for inequality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpneq_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_NEQ_UQ) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for inequality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_pd_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpneq_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NEQ_UQ) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_pd_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_cmp_pd_mask(a: __m512d, b: __m512d, op: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr) => { + vcmppd( + a.as_f64x8(), + b.as_f64x8(), + $imm5, + neg_one, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm5!(op, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op, +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_pd_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_mask_cmp_pd_mask(m: __mmask8, a: __m512d, b: __m512d, op: i32) -> __mmask8 { + macro_rules! call { + ($imm5:expr) => { + vcmppd( + a.as_f64x8(), + b.as_f64x8(), + $imm5, + m as i8, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm5!(op, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_pd_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2, 3)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm512_cmp_round_pd_mask(a: __m512d, b: __m512d, op: i32, sae: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmppd(a.as_f64x8(), b.as_f64x8(), $imm5, neg_one, $imm4) + }; + } + let r = constify_imm5_sae!(op, sae, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op, +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_pd_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3, 4)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm512_mask_cmp_round_pd_mask( + m: __mmask8, + a: __m512d, + b: __m512d, + op: i32, + sae: i32, +) -> __mmask8 { + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmppd(a.as_f64x8(), b.as_f64x8(), $imm5, m as i8, $imm4) + }; + } + let r = constify_imm5_sae!(op, sae, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_pd_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_cmpord_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_ORD_Q) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_pd_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_mask_cmpord_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(m, a, b, _CMP_ORD_Q) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_pd_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_cmpunord_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_UNORD_Q) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_pd_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, op = 0))] +pub unsafe fn _mm512_mask_cmpunord_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(m, a, b, _CMP_UNORD_Q) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_ss_mask&expand=5236,755,757) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm_cmp_ss_mask(a: __m128, b: __m128, op: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr) => { + vcmpss(a, b, $imm5, neg_one, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm5!(op, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_ss_mask&expand=5236,755,757) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm_mask_cmp_ss_mask(m: __mmask8, a: __m128, b: __m128, op: i32) -> __mmask8 { + macro_rules! call { + ($imm5:expr) => { + vcmpss(a, b, $imm5, m as i8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm5!(op, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_ss_mask&expand=5236,755,757) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2, 3)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm_cmp_round_ss_mask(a: __m128, b: __m128, op: i32, sae: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpss(a, b, $imm5, neg_one, $imm4) + }; + } + let r = constify_imm5_sae!(op, sae, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_ss_mask&expand=5236,755,757) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3, 4)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm_mask_cmp_round_ss_mask( + m: __mmask8, + a: __m128, + b: __m128, + op: i32, + sae: i32, +) -> __mmask8 { + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpss(a, b, $imm5, m as i8, $imm4) + }; + } + let r = constify_imm5_sae!(op, sae, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_sd_mask&expand=5236,755,757) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm_cmp_sd_mask(a: __m128d, b: __m128d, op: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr) => { + vcmpsd(a, b, $imm5, neg_one, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm5!(op, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_sd_mask&expand=5236,755,757) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm_mask_cmp_sd_mask(m: __mmask8, a: __m128d, b: __m128d, op: i32) -> __mmask8 { + macro_rules! call { + ($imm5:expr) => { + vcmpsd(a, b, $imm5, m as i8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm5!(op, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_sd_mask&expand=5236,755,757) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2, 3)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm_cmp_round_sd_mask(a: __m128d, b: __m128d, op: i32, sae: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpsd(a, b, $imm5, neg_one, $imm4) + }; + } + let r = constify_imm5_sae!(op, sae, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_sd_mask&expand=5236,755,757) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3, 4)] +#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] +pub unsafe fn _mm_mask_cmp_round_sd_mask( + m: __mmask8, + a: __m128d, + b: __m128d, + op: i32, + sae: i32, +) -> __mmask8 { + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpsd(a, b, $imm5, m as i8, $imm4) + }; + } + let r = constify_imm5_sae!(op, sae, call); + transmute(r) +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_lt(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmplt_epu32_mask(a, b) & m +} + +/// Compare packed unsigned 32-bit integers in a and b for greater-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_gt(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for greater-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpgt_epu32_mask(a, b) & m +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_le(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmple_epu32_mask(a, b) & m +} + +/// Compare packed unsigned 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_ge(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpge_epu32_mask(a, b) & m +} + +/// Compare packed unsigned 32-bit integers in a and b for equality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_eq(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for equality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpeq_epu32_mask(a, b) & m +} + +/// Compare packed unsigned 32-bit integers in a and b for inequality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epu32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_ne(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for inequality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epu32_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpneq_epu32_mask(a, b) & m +} + +/// Compare packed unsigned 32-bit integers in a and b based on the comparison operand specified by op. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu32_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, op = 0))] +pub unsafe fn _mm512_cmp_epu32_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask16 { + let neg_one = -1; + macro_rules! call { + ($imm3:expr) => { + vpcmpud(a.as_i32x16(), b.as_i32x16(), $imm3, neg_one) + }; + } + let r = constify_imm3!(op, call); + transmute(r) +} + +/// Compare packed unsigned 32-bit integers in a and b based on the comparison operand specified by op, +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu32_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, op = 0))] +pub unsafe fn _mm512_mask_cmp_epu32_mask( + m: __mmask16, + a: __m512i, + b: __m512i, + op: _MM_CMPINT_ENUM, +) -> __mmask16 { + macro_rules! call { + ($imm3:expr) => { + vpcmpud(a.as_i32x16(), b.as_i32x16(), $imm3, m as i16) + }; + } + let r = constify_imm3!(op, call); + transmute(r) +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_lt(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmplt_epi32_mask(a, b) & m +} + +/// Compare packed signed 32-bit integers in a and b for greater-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_gt(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b for greater-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpgt_epi32_mask(a, b) & m +} + +/// Compare packed signed 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_le(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmple_epi32_mask(a, b) & m +} + +/// Compare packed signed 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_ge(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpge_epi32_mask(a, b) & m +} + +/// Compare packed signed 32-bit integers in a and b for equality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_eq(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b for equality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpeq_epi32_mask(a, b) & m +} + +/// Compare packed signed 32-bit integers in a and b for inequality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_ne(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b for inequality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epi32) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpneq_epi32_mask(a, b) & m +} + +/// Compare packed signed 32-bit integers in a and b based on the comparison operand specified by op. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi32_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, op = 0))] +pub unsafe fn _mm512_cmp_epi32_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask16 { + let neg_one = -1; + macro_rules! call { + ($imm3:expr) => { + vpcmpd(a.as_i32x16(), b.as_i32x16(), $imm3, neg_one) + }; + } + let r = constify_imm3!(op, call); + transmute(r) +} + +/// Compare packed signed 32-bit integers in a and b based on the comparison operand specified by op, +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi32_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, op = 0))] +pub unsafe fn _mm512_mask_cmp_epi32_mask( + m: __mmask16, + a: __m512i, + b: __m512i, + op: _MM_CMPINT_ENUM, +) -> __mmask16 { + macro_rules! call { + ($imm3:expr) => { + vpcmpd(a.as_i32x16(), b.as_i32x16(), $imm3, m as i16) + }; + } + let r = constify_imm3!(op, call); + transmute(r) +} + +/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_lt(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmplt_epu64_mask(a, b) & m +} + +/// Compare packed unsigned 64-bit integers in a and b for greater-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_gt(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for greater-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpgt_epu64_mask(a, b) & m +} + +/// Compare packed unsigned 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_le(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmple_epu64_mask(a, b) & m +} + +/// Compare packed unsigned 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_ge(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpge_epu64_mask(b, a) & m +} + +/// Compare packed unsigned 64-bit integers in a and b for equality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_eq(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for equality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpeq_epu64_mask(a, b) & m +} + +/// Compare packed unsigned 64-bit integers in a and b for inequality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epu64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_ne(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for inequality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epu64_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpneq_epu64_mask(a, b) & m +} + +/// Compare packed unsigned 64-bit integers in a and b based on the comparison operand specified by op. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu64_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, op = 0))] +pub unsafe fn _mm512_cmp_epu64_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm3:expr) => { + vpcmpuq(a.as_i64x8(), b.as_i64x8(), $imm3, neg_one) + }; + } + let r = constify_imm3!(op, call); + transmute(r) +} + +/// Compare packed unsigned 64-bit integers in a and b based on the comparison operand specified by op, +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu64_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, op = 0))] +pub unsafe fn _mm512_mask_cmp_epu64_mask( + m: __mmask8, + a: __m512i, + b: __m512i, + op: _MM_CMPINT_ENUM, +) -> __mmask8 { + macro_rules! call { + ($imm3:expr) => { + vpcmpuq(a.as_i64x8(), b.as_i64x8(), $imm3, m as i8) + }; + } + let r = constify_imm3!(op, call); + transmute(r) +} + +/// Compare packed signed 64-bit integers in a and b for less-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_lt(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for less-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmplt_epi64_mask(a, b) & m +} + +/// Compare packed signed 64-bit integers in a and b for greater-than, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_gt(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for greater-than, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpgt_epi64_mask(a, b) & m +} + +/// Compare packed signed 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_le(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmple_epi64_mask(a, b) & m +} + +/// Compare packed signed 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_ge(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpge_epi64_mask(b, a) & m +} + +/// Compare packed signed 64-bit integers in a and b for equality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_eq(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for equality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpeq_epi64_mask(a, b) & m +} + +/// Compare packed signed 64-bit integers in a and b for inequality, and store the results in a mask vector. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_ne(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for inequality, and store the results in a mask vector k +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epi64) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpneq_epi64_mask(a, b) & m +} + +/// Compare packed signed 64-bit integers in a and b based on the comparison operand specified by op. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi64_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, op = 0))] +pub unsafe fn _mm512_cmp_epi64_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm3:expr) => { + vpcmpq(a.as_i64x8(), b.as_i64x8(), $imm3, neg_one) + }; + } + let r = constify_imm3!(op, call); + transmute(r) +} + +/// Compare packed signed 64-bit integers in a and b based on the comparison operand specified by op, +/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi64_mask) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, op = 0))] +pub unsafe fn _mm512_mask_cmp_epi64_mask( + m: __mmask8, + a: __m512i, + b: __m512i, + op: _MM_CMPINT_ENUM, +) -> __mmask8 { + macro_rules! call { + ($imm3:expr) => { + vpcmpq(a.as_i64x8(), b.as_i64x8(), $imm3, m as i8) + }; + } + let r = constify_imm3!(op, call); + transmute(r) +} + +/// Returns vector of type `__m512d` with undefined elements. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_pd) +#[inline] +#[target_feature(enable = "avx512f")] +// This intrinsic has no corresponding instruction. +pub unsafe fn _mm512_undefined_pd() -> __m512d { + _mm512_set1_pd(0.0) +} + +/// Returns vector of type `__m512` with undefined elements. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_ps) +#[inline] +#[target_feature(enable = "avx512f")] +// This intrinsic has no corresponding instruction. +pub unsafe fn _mm512_undefined_ps() -> __m512 { + _mm512_set1_ps(0.0) +} + +/// Loads 512-bits (composed of 8 packed double-precision (64-bit) +/// floating-point elements) from memory into result. +/// `mem_addr` does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] +pub unsafe fn _mm512_loadu_pd(mem_addr: *const f64) -> __m512d { + ptr::read_unaligned(mem_addr as *const __m512d) +} + +/// Stores 512-bits (composed of 8 packed double-precision (64-bit) +/// floating-point elements) from `a` into memory. +/// `mem_addr` does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] +pub unsafe fn _mm512_storeu_pd(mem_addr: *mut f64, a: __m512d) { + ptr::write_unaligned(mem_addr as *mut __m512d, a); +} + +/// Loads 512-bits (composed of 16 packed single-precision (32-bit) +/// floating-point elements) from memory into result. +/// `mem_addr` does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] +pub unsafe fn _mm512_loadu_ps(mem_addr: *const f32) -> __m512 { + ptr::read_unaligned(mem_addr as *const __m512) +} + +/// Stores 512-bits (composed of 16 packed single-precision (32-bit) +/// floating-point elements) from `a` into memory. +/// `mem_addr` does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _mm512_storeu_ps(mem_addr: *mut f32, a: __m512) { + ptr::write_unaligned(mem_addr as *mut __m512, a); +} + +/// Sets packed 64-bit integers in `dst` with the supplied values in +/// reverse order. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_pd) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr_pd( + e0: f64, + e1: f64, + e2: f64, + e3: f64, + e4: f64, + e5: f64, + e6: f64, + e7: f64, +) -> __m512d { + let r = f64x8::new(e0, e1, e2, e3, e4, e5, e6, e7); + transmute(r) +} + +/// Sets packed 64-bit integers in `dst` with the supplied values. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_pd) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set_pd( + e0: f64, + e1: f64, + e2: f64, + e3: f64, + e4: f64, + e5: f64, + e6: f64, + e7: f64, +) -> __m512d { + _mm512_setr_pd(e7, e6, e5, e4, e3, e2, e1, e0) +} + +/// Equal +pub const _MM_CMPINT_EQ: _MM_CMPINT_ENUM = 0x00; +/// Less-than +pub const _MM_CMPINT_LT: _MM_CMPINT_ENUM = 0x01; +/// Less-than-or-equal +pub const _MM_CMPINT_LE: _MM_CMPINT_ENUM = 0x02; +/// False +pub const _MM_CMPINT_FALSE: _MM_CMPINT_ENUM = 0x03; +/// Not-equal +pub const _MM_CMPINT_NE: _MM_CMPINT_ENUM = 0x04; +/// Not less-than +pub const _MM_CMPINT_NLT: _MM_CMPINT_ENUM = 0x05; +/// Not less-than-or-equal +pub const _MM_CMPINT_NLE: _MM_CMPINT_ENUM = 0x06; +/// True +pub const _MM_CMPINT_TRUE: _MM_CMPINT_ENUM = 0x07; + +/// interval [1, 2) +pub const _MM_MANT_NORM_1_2: _MM_MANTISSA_NORM_ENUM = 0x00; +/// interval [0.5, 2) +pub const _MM_MANT_NORM_P5_2: _MM_MANTISSA_NORM_ENUM = 0x01; +/// interval [0.5, 1) +pub const _MM_MANT_NORM_P5_1: _MM_MANTISSA_NORM_ENUM = 0x02; +/// interval [0.75, 1.5) +pub const _MM_MANT_NORM_P75_1P5: _MM_MANTISSA_NORM_ENUM = 0x03; + +/// sign = sign(SRC) +pub const _MM_MANT_SIGN_SRC: _MM_MANTISSA_SIGN_ENUM = 0x00; +/// sign = 0 +pub const _MM_MANT_SIGN_ZERO: _MM_MANTISSA_SIGN_ENUM = 0x01; +/// DEST = NaN if sign(SRC) = 1 +pub const _MM_MANT_SIGN_NAN: _MM_MANTISSA_SIGN_ENUM = 0x02; + +pub const _MM_PERM_AAAA: _MM_PERM_ENUM = 0x00; +pub const _MM_PERM_AAAB: _MM_PERM_ENUM = 0x01; +pub const _MM_PERM_AAAC: _MM_PERM_ENUM = 0x02; +pub const _MM_PERM_AAAD: _MM_PERM_ENUM = 0x03; +pub const _MM_PERM_AABA: _MM_PERM_ENUM = 0x04; +pub const _MM_PERM_AABB: _MM_PERM_ENUM = 0x05; +pub const _MM_PERM_AABC: _MM_PERM_ENUM = 0x06; +pub const _MM_PERM_AABD: _MM_PERM_ENUM = 0x07; +pub const _MM_PERM_AACA: _MM_PERM_ENUM = 0x08; +pub const _MM_PERM_AACB: _MM_PERM_ENUM = 0x09; +pub const _MM_PERM_AACC: _MM_PERM_ENUM = 0x0A; +pub const _MM_PERM_AACD: _MM_PERM_ENUM = 0x0B; +pub const _MM_PERM_AADA: _MM_PERM_ENUM = 0x0C; +pub const _MM_PERM_AADB: _MM_PERM_ENUM = 0x0D; +pub const _MM_PERM_AADC: _MM_PERM_ENUM = 0x0E; +pub const _MM_PERM_AADD: _MM_PERM_ENUM = 0x0F; +pub const _MM_PERM_ABAA: _MM_PERM_ENUM = 0x10; +pub const _MM_PERM_ABAB: _MM_PERM_ENUM = 0x11; +pub const _MM_PERM_ABAC: _MM_PERM_ENUM = 0x12; +pub const _MM_PERM_ABAD: _MM_PERM_ENUM = 0x13; +pub const _MM_PERM_ABBA: _MM_PERM_ENUM = 0x14; +pub const _MM_PERM_ABBB: _MM_PERM_ENUM = 0x15; +pub const _MM_PERM_ABBC: _MM_PERM_ENUM = 0x16; +pub const _MM_PERM_ABBD: _MM_PERM_ENUM = 0x17; +pub const _MM_PERM_ABCA: _MM_PERM_ENUM = 0x18; +pub const _MM_PERM_ABCB: _MM_PERM_ENUM = 0x19; +pub const _MM_PERM_ABCC: _MM_PERM_ENUM = 0x1A; +pub const _MM_PERM_ABCD: _MM_PERM_ENUM = 0x1B; +pub const _MM_PERM_ABDA: _MM_PERM_ENUM = 0x1C; +pub const _MM_PERM_ABDB: _MM_PERM_ENUM = 0x1D; +pub const _MM_PERM_ABDC: _MM_PERM_ENUM = 0x1E; +pub const _MM_PERM_ABDD: _MM_PERM_ENUM = 0x1F; +pub const _MM_PERM_ACAA: _MM_PERM_ENUM = 0x20; +pub const _MM_PERM_ACAB: _MM_PERM_ENUM = 0x21; +pub const _MM_PERM_ACAC: _MM_PERM_ENUM = 0x22; +pub const _MM_PERM_ACAD: _MM_PERM_ENUM = 0x23; +pub const _MM_PERM_ACBA: _MM_PERM_ENUM = 0x24; +pub const _MM_PERM_ACBB: _MM_PERM_ENUM = 0x25; +pub const _MM_PERM_ACBC: _MM_PERM_ENUM = 0x26; +pub const _MM_PERM_ACBD: _MM_PERM_ENUM = 0x27; +pub const _MM_PERM_ACCA: _MM_PERM_ENUM = 0x28; +pub const _MM_PERM_ACCB: _MM_PERM_ENUM = 0x29; +pub const _MM_PERM_ACCC: _MM_PERM_ENUM = 0x2A; +pub const _MM_PERM_ACCD: _MM_PERM_ENUM = 0x2B; +pub const _MM_PERM_ACDA: _MM_PERM_ENUM = 0x2C; +pub const _MM_PERM_ACDB: _MM_PERM_ENUM = 0x2D; +pub const _MM_PERM_ACDC: _MM_PERM_ENUM = 0x2E; +pub const _MM_PERM_ACDD: _MM_PERM_ENUM = 0x2F; +pub const _MM_PERM_ADAA: _MM_PERM_ENUM = 0x30; +pub const _MM_PERM_ADAB: _MM_PERM_ENUM = 0x31; +pub const _MM_PERM_ADAC: _MM_PERM_ENUM = 0x32; +pub const _MM_PERM_ADAD: _MM_PERM_ENUM = 0x33; +pub const _MM_PERM_ADBA: _MM_PERM_ENUM = 0x34; +pub const _MM_PERM_ADBB: _MM_PERM_ENUM = 0x35; +pub const _MM_PERM_ADBC: _MM_PERM_ENUM = 0x36; +pub const _MM_PERM_ADBD: _MM_PERM_ENUM = 0x37; +pub const _MM_PERM_ADCA: _MM_PERM_ENUM = 0x38; +pub const _MM_PERM_ADCB: _MM_PERM_ENUM = 0x39; +pub const _MM_PERM_ADCC: _MM_PERM_ENUM = 0x3A; +pub const _MM_PERM_ADCD: _MM_PERM_ENUM = 0x3B; +pub const _MM_PERM_ADDA: _MM_PERM_ENUM = 0x3C; +pub const _MM_PERM_ADDB: _MM_PERM_ENUM = 0x3D; +pub const _MM_PERM_ADDC: _MM_PERM_ENUM = 0x3E; +pub const _MM_PERM_ADDD: _MM_PERM_ENUM = 0x3F; +pub const _MM_PERM_BAAA: _MM_PERM_ENUM = 0x40; +pub const _MM_PERM_BAAB: _MM_PERM_ENUM = 0x41; +pub const _MM_PERM_BAAC: _MM_PERM_ENUM = 0x42; +pub const _MM_PERM_BAAD: _MM_PERM_ENUM = 0x43; +pub const _MM_PERM_BABA: _MM_PERM_ENUM = 0x44; +pub const _MM_PERM_BABB: _MM_PERM_ENUM = 0x45; +pub const _MM_PERM_BABC: _MM_PERM_ENUM = 0x46; +pub const _MM_PERM_BABD: _MM_PERM_ENUM = 0x47; +pub const _MM_PERM_BACA: _MM_PERM_ENUM = 0x48; +pub const _MM_PERM_BACB: _MM_PERM_ENUM = 0x49; +pub const _MM_PERM_BACC: _MM_PERM_ENUM = 0x4A; +pub const _MM_PERM_BACD: _MM_PERM_ENUM = 0x4B; +pub const _MM_PERM_BADA: _MM_PERM_ENUM = 0x4C; +pub const _MM_PERM_BADB: _MM_PERM_ENUM = 0x4D; +pub const _MM_PERM_BADC: _MM_PERM_ENUM = 0x4E; +pub const _MM_PERM_BADD: _MM_PERM_ENUM = 0x4F; +pub const _MM_PERM_BBAA: _MM_PERM_ENUM = 0x50; +pub const _MM_PERM_BBAB: _MM_PERM_ENUM = 0x51; +pub const _MM_PERM_BBAC: _MM_PERM_ENUM = 0x52; +pub const _MM_PERM_BBAD: _MM_PERM_ENUM = 0x53; +pub const _MM_PERM_BBBA: _MM_PERM_ENUM = 0x54; +pub const _MM_PERM_BBBB: _MM_PERM_ENUM = 0x55; +pub const _MM_PERM_BBBC: _MM_PERM_ENUM = 0x56; +pub const _MM_PERM_BBBD: _MM_PERM_ENUM = 0x57; +pub const _MM_PERM_BBCA: _MM_PERM_ENUM = 0x58; +pub const _MM_PERM_BBCB: _MM_PERM_ENUM = 0x59; +pub const _MM_PERM_BBCC: _MM_PERM_ENUM = 0x5A; +pub const _MM_PERM_BBCD: _MM_PERM_ENUM = 0x5B; +pub const _MM_PERM_BBDA: _MM_PERM_ENUM = 0x5C; +pub const _MM_PERM_BBDB: _MM_PERM_ENUM = 0x5D; +pub const _MM_PERM_BBDC: _MM_PERM_ENUM = 0x5E; +pub const _MM_PERM_BBDD: _MM_PERM_ENUM = 0x5F; +pub const _MM_PERM_BCAA: _MM_PERM_ENUM = 0x60; +pub const _MM_PERM_BCAB: _MM_PERM_ENUM = 0x61; +pub const _MM_PERM_BCAC: _MM_PERM_ENUM = 0x62; +pub const _MM_PERM_BCAD: _MM_PERM_ENUM = 0x63; +pub const _MM_PERM_BCBA: _MM_PERM_ENUM = 0x64; +pub const _MM_PERM_BCBB: _MM_PERM_ENUM = 0x65; +pub const _MM_PERM_BCBC: _MM_PERM_ENUM = 0x66; +pub const _MM_PERM_BCBD: _MM_PERM_ENUM = 0x67; +pub const _MM_PERM_BCCA: _MM_PERM_ENUM = 0x68; +pub const _MM_PERM_BCCB: _MM_PERM_ENUM = 0x69; +pub const _MM_PERM_BCCC: _MM_PERM_ENUM = 0x6A; +pub const _MM_PERM_BCCD: _MM_PERM_ENUM = 0x6B; +pub const _MM_PERM_BCDA: _MM_PERM_ENUM = 0x6C; +pub const _MM_PERM_BCDB: _MM_PERM_ENUM = 0x6D; +pub const _MM_PERM_BCDC: _MM_PERM_ENUM = 0x6E; +pub const _MM_PERM_BCDD: _MM_PERM_ENUM = 0x6F; +pub const _MM_PERM_BDAA: _MM_PERM_ENUM = 0x70; +pub const _MM_PERM_BDAB: _MM_PERM_ENUM = 0x71; +pub const _MM_PERM_BDAC: _MM_PERM_ENUM = 0x72; +pub const _MM_PERM_BDAD: _MM_PERM_ENUM = 0x73; +pub const _MM_PERM_BDBA: _MM_PERM_ENUM = 0x74; +pub const _MM_PERM_BDBB: _MM_PERM_ENUM = 0x75; +pub const _MM_PERM_BDBC: _MM_PERM_ENUM = 0x76; +pub const _MM_PERM_BDBD: _MM_PERM_ENUM = 0x77; +pub const _MM_PERM_BDCA: _MM_PERM_ENUM = 0x78; +pub const _MM_PERM_BDCB: _MM_PERM_ENUM = 0x79; +pub const _MM_PERM_BDCC: _MM_PERM_ENUM = 0x7A; +pub const _MM_PERM_BDCD: _MM_PERM_ENUM = 0x7B; +pub const _MM_PERM_BDDA: _MM_PERM_ENUM = 0x7C; +pub const _MM_PERM_BDDB: _MM_PERM_ENUM = 0x7D; +pub const _MM_PERM_BDDC: _MM_PERM_ENUM = 0x7E; +pub const _MM_PERM_BDDD: _MM_PERM_ENUM = 0x7F; +pub const _MM_PERM_CAAA: _MM_PERM_ENUM = 0x80; +pub const _MM_PERM_CAAB: _MM_PERM_ENUM = 0x81; +pub const _MM_PERM_CAAC: _MM_PERM_ENUM = 0x82; +pub const _MM_PERM_CAAD: _MM_PERM_ENUM = 0x83; +pub const _MM_PERM_CABA: _MM_PERM_ENUM = 0x84; +pub const _MM_PERM_CABB: _MM_PERM_ENUM = 0x85; +pub const _MM_PERM_CABC: _MM_PERM_ENUM = 0x86; +pub const _MM_PERM_CABD: _MM_PERM_ENUM = 0x87; +pub const _MM_PERM_CACA: _MM_PERM_ENUM = 0x88; +pub const _MM_PERM_CACB: _MM_PERM_ENUM = 0x89; +pub const _MM_PERM_CACC: _MM_PERM_ENUM = 0x8A; +pub const _MM_PERM_CACD: _MM_PERM_ENUM = 0x8B; +pub const _MM_PERM_CADA: _MM_PERM_ENUM = 0x8C; +pub const _MM_PERM_CADB: _MM_PERM_ENUM = 0x8D; +pub const _MM_PERM_CADC: _MM_PERM_ENUM = 0x8E; +pub const _MM_PERM_CADD: _MM_PERM_ENUM = 0x8F; +pub const _MM_PERM_CBAA: _MM_PERM_ENUM = 0x90; +pub const _MM_PERM_CBAB: _MM_PERM_ENUM = 0x91; +pub const _MM_PERM_CBAC: _MM_PERM_ENUM = 0x92; +pub const _MM_PERM_CBAD: _MM_PERM_ENUM = 0x93; +pub const _MM_PERM_CBBA: _MM_PERM_ENUM = 0x94; +pub const _MM_PERM_CBBB: _MM_PERM_ENUM = 0x95; +pub const _MM_PERM_CBBC: _MM_PERM_ENUM = 0x96; +pub const _MM_PERM_CBBD: _MM_PERM_ENUM = 0x97; +pub const _MM_PERM_CBCA: _MM_PERM_ENUM = 0x98; +pub const _MM_PERM_CBCB: _MM_PERM_ENUM = 0x99; +pub const _MM_PERM_CBCC: _MM_PERM_ENUM = 0x9A; +pub const _MM_PERM_CBCD: _MM_PERM_ENUM = 0x9B; +pub const _MM_PERM_CBDA: _MM_PERM_ENUM = 0x9C; +pub const _MM_PERM_CBDB: _MM_PERM_ENUM = 0x9D; +pub const _MM_PERM_CBDC: _MM_PERM_ENUM = 0x9E; +pub const _MM_PERM_CBDD: _MM_PERM_ENUM = 0x9F; +pub const _MM_PERM_CCAA: _MM_PERM_ENUM = 0xA0; +pub const _MM_PERM_CCAB: _MM_PERM_ENUM = 0xA1; +pub const _MM_PERM_CCAC: _MM_PERM_ENUM = 0xA2; +pub const _MM_PERM_CCAD: _MM_PERM_ENUM = 0xA3; +pub const _MM_PERM_CCBA: _MM_PERM_ENUM = 0xA4; +pub const _MM_PERM_CCBB: _MM_PERM_ENUM = 0xA5; +pub const _MM_PERM_CCBC: _MM_PERM_ENUM = 0xA6; +pub const _MM_PERM_CCBD: _MM_PERM_ENUM = 0xA7; +pub const _MM_PERM_CCCA: _MM_PERM_ENUM = 0xA8; +pub const _MM_PERM_CCCB: _MM_PERM_ENUM = 0xA9; +pub const _MM_PERM_CCCC: _MM_PERM_ENUM = 0xAA; +pub const _MM_PERM_CCCD: _MM_PERM_ENUM = 0xAB; +pub const _MM_PERM_CCDA: _MM_PERM_ENUM = 0xAC; +pub const _MM_PERM_CCDB: _MM_PERM_ENUM = 0xAD; +pub const _MM_PERM_CCDC: _MM_PERM_ENUM = 0xAE; +pub const _MM_PERM_CCDD: _MM_PERM_ENUM = 0xAF; +pub const _MM_PERM_CDAA: _MM_PERM_ENUM = 0xB0; +pub const _MM_PERM_CDAB: _MM_PERM_ENUM = 0xB1; +pub const _MM_PERM_CDAC: _MM_PERM_ENUM = 0xB2; +pub const _MM_PERM_CDAD: _MM_PERM_ENUM = 0xB3; +pub const _MM_PERM_CDBA: _MM_PERM_ENUM = 0xB4; +pub const _MM_PERM_CDBB: _MM_PERM_ENUM = 0xB5; +pub const _MM_PERM_CDBC: _MM_PERM_ENUM = 0xB6; +pub const _MM_PERM_CDBD: _MM_PERM_ENUM = 0xB7; +pub const _MM_PERM_CDCA: _MM_PERM_ENUM = 0xB8; +pub const _MM_PERM_CDCB: _MM_PERM_ENUM = 0xB9; +pub const _MM_PERM_CDCC: _MM_PERM_ENUM = 0xBA; +pub const _MM_PERM_CDCD: _MM_PERM_ENUM = 0xBB; +pub const _MM_PERM_CDDA: _MM_PERM_ENUM = 0xBC; +pub const _MM_PERM_CDDB: _MM_PERM_ENUM = 0xBD; +pub const _MM_PERM_CDDC: _MM_PERM_ENUM = 0xBE; +pub const _MM_PERM_CDDD: _MM_PERM_ENUM = 0xBF; +pub const _MM_PERM_DAAA: _MM_PERM_ENUM = 0xC0; +pub const _MM_PERM_DAAB: _MM_PERM_ENUM = 0xC1; +pub const _MM_PERM_DAAC: _MM_PERM_ENUM = 0xC2; +pub const _MM_PERM_DAAD: _MM_PERM_ENUM = 0xC3; +pub const _MM_PERM_DABA: _MM_PERM_ENUM = 0xC4; +pub const _MM_PERM_DABB: _MM_PERM_ENUM = 0xC5; +pub const _MM_PERM_DABC: _MM_PERM_ENUM = 0xC6; +pub const _MM_PERM_DABD: _MM_PERM_ENUM = 0xC7; +pub const _MM_PERM_DACA: _MM_PERM_ENUM = 0xC8; +pub const _MM_PERM_DACB: _MM_PERM_ENUM = 0xC9; +pub const _MM_PERM_DACC: _MM_PERM_ENUM = 0xCA; +pub const _MM_PERM_DACD: _MM_PERM_ENUM = 0xCB; +pub const _MM_PERM_DADA: _MM_PERM_ENUM = 0xCC; +pub const _MM_PERM_DADB: _MM_PERM_ENUM = 0xCD; +pub const _MM_PERM_DADC: _MM_PERM_ENUM = 0xCE; +pub const _MM_PERM_DADD: _MM_PERM_ENUM = 0xCF; +pub const _MM_PERM_DBAA: _MM_PERM_ENUM = 0xD0; +pub const _MM_PERM_DBAB: _MM_PERM_ENUM = 0xD1; +pub const _MM_PERM_DBAC: _MM_PERM_ENUM = 0xD2; +pub const _MM_PERM_DBAD: _MM_PERM_ENUM = 0xD3; +pub const _MM_PERM_DBBA: _MM_PERM_ENUM = 0xD4; +pub const _MM_PERM_DBBB: _MM_PERM_ENUM = 0xD5; +pub const _MM_PERM_DBBC: _MM_PERM_ENUM = 0xD6; +pub const _MM_PERM_DBBD: _MM_PERM_ENUM = 0xD7; +pub const _MM_PERM_DBCA: _MM_PERM_ENUM = 0xD8; +pub const _MM_PERM_DBCB: _MM_PERM_ENUM = 0xD9; +pub const _MM_PERM_DBCC: _MM_PERM_ENUM = 0xDA; +pub const _MM_PERM_DBCD: _MM_PERM_ENUM = 0xDB; +pub const _MM_PERM_DBDA: _MM_PERM_ENUM = 0xDC; +pub const _MM_PERM_DBDB: _MM_PERM_ENUM = 0xDD; +pub const _MM_PERM_DBDC: _MM_PERM_ENUM = 0xDE; +pub const _MM_PERM_DBDD: _MM_PERM_ENUM = 0xDF; +pub const _MM_PERM_DCAA: _MM_PERM_ENUM = 0xE0; +pub const _MM_PERM_DCAB: _MM_PERM_ENUM = 0xE1; +pub const _MM_PERM_DCAC: _MM_PERM_ENUM = 0xE2; +pub const _MM_PERM_DCAD: _MM_PERM_ENUM = 0xE3; +pub const _MM_PERM_DCBA: _MM_PERM_ENUM = 0xE4; +pub const _MM_PERM_DCBB: _MM_PERM_ENUM = 0xE5; +pub const _MM_PERM_DCBC: _MM_PERM_ENUM = 0xE6; +pub const _MM_PERM_DCBD: _MM_PERM_ENUM = 0xE7; +pub const _MM_PERM_DCCA: _MM_PERM_ENUM = 0xE8; +pub const _MM_PERM_DCCB: _MM_PERM_ENUM = 0xE9; +pub const _MM_PERM_DCCC: _MM_PERM_ENUM = 0xEA; +pub const _MM_PERM_DCCD: _MM_PERM_ENUM = 0xEB; +pub const _MM_PERM_DCDA: _MM_PERM_ENUM = 0xEC; +pub const _MM_PERM_DCDB: _MM_PERM_ENUM = 0xED; +pub const _MM_PERM_DCDC: _MM_PERM_ENUM = 0xEE; +pub const _MM_PERM_DCDD: _MM_PERM_ENUM = 0xEF; +pub const _MM_PERM_DDAA: _MM_PERM_ENUM = 0xF0; +pub const _MM_PERM_DDAB: _MM_PERM_ENUM = 0xF1; +pub const _MM_PERM_DDAC: _MM_PERM_ENUM = 0xF2; +pub const _MM_PERM_DDAD: _MM_PERM_ENUM = 0xF3; +pub const _MM_PERM_DDBA: _MM_PERM_ENUM = 0xF4; +pub const _MM_PERM_DDBB: _MM_PERM_ENUM = 0xF5; +pub const _MM_PERM_DDBC: _MM_PERM_ENUM = 0xF6; +pub const _MM_PERM_DDBD: _MM_PERM_ENUM = 0xF7; +pub const _MM_PERM_DDCA: _MM_PERM_ENUM = 0xF8; +pub const _MM_PERM_DDCB: _MM_PERM_ENUM = 0xF9; +pub const _MM_PERM_DDCC: _MM_PERM_ENUM = 0xFA; +pub const _MM_PERM_DDCD: _MM_PERM_ENUM = 0xFB; +pub const _MM_PERM_DDDA: _MM_PERM_ENUM = 0xFC; +pub const _MM_PERM_DDDB: _MM_PERM_ENUM = 0xFD; +pub const _MM_PERM_DDDC: _MM_PERM_ENUM = 0xFE; +pub const _MM_PERM_DDDD: _MM_PERM_ENUM = 0xFF; + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.x86.avx512.pmul.dq.512"] + fn vpmuldq(a: i32x16, b: i32x16) -> i64x8; + #[link_name = "llvm.x86.avx512.pmulu.dq.512"] + fn vpmuludq(a: u32x16, b: u32x16) -> u64x8; + + #[link_name = "llvm.x86.avx512.mask.pmaxs.d.512"] + fn vpmaxsd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.pmaxs.q.512"] + fn vpmaxsq(a: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.pmins.d.512"] + fn vpminsd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.pmins.q.512"] + fn vpminsq(a: i64x8, b: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.mask.pmaxu.d.512"] + fn vpmaxud(a: u32x16, b: u32x16) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.pmaxu.q.512"] + fn vpmaxuq(a: u64x8, b: u64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.pminu.d.512"] + fn vpminud(a: u32x16, b: u32x16) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.pminu.q.512"] + fn vpminuq(a: u64x8, b: u64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.sqrt.ps.512"] + fn vsqrtps(a: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.sqrt.pd.512"] + fn vsqrtpd(a: f64x8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.vfmadd.ps.512"] + fn vfmadd132ps(a: f32x16, b: f32x16, c: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.vfmadd.pd.512"] + fn vfmadd132pd(a: f64x8, b: f64x8, c: f64x8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.vfmaddsub.ps.512"] + fn vfmaddsub213ps(a: f32x16, b: f32x16, c: f32x16, d: i32) -> f32x16; //from clang + #[link_name = "llvm.x86.avx512.vfmaddsub.pd.512"] + fn vfmaddsub213pd(a: f64x8, b: f64x8, c: f64x8, d: i32) -> f64x8; //from clang + + #[link_name = "llvm.x86.avx512.add.ps.512"] + fn vaddps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.add.pd.512"] + fn vaddpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.sub.ps.512"] + fn vsubps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.sub.pd.512"] + fn vsubpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.mul.ps.512"] + fn vmulps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mul.pd.512"] + fn vmulpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.div.ps.512"] + fn vdivps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.div.pd.512"] + fn vdivpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.max.ps.512"] + fn vmaxps(a: f32x16, b: f32x16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.max.pd.512"] + fn vmaxpd(a: f64x8, b: f64x8, sae: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.min.ps.512"] + fn vminps(a: f32x16, b: f32x16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.min.pd.512"] + fn vminpd(a: f64x8, b: f64x8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.getexp.ps.512"] + fn vgetexpps(a: f32x16, src: f32x16, m: u16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.getexp.pd.512"] + fn vgetexppd(a: f64x8, src: f64x8, m: u8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.getmant.ps.512"] + fn vgetmantps(a: f32x16, mantissas: i32, src: f32x16, m: u16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.getmant.pd.512"] + fn vgetmantpd(a: f64x8, mantissas: i32, src: f64x8, m: u8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.rcp14.ps.512"] + fn vrcp14ps(a: f32x16, src: f32x16, m: u16) -> f32x16; + #[link_name = "llvm.x86.avx512.rcp14.pd.512"] + fn vrcp14pd(a: f64x8, src: f64x8, m: u8) -> f64x8; + #[link_name = "llvm.x86.avx512.rsqrt14.ps.512"] + fn vrsqrt14ps(a: f32x16, src: f32x16, m: u16) -> f32x16; + #[link_name = "llvm.x86.avx512.rsqrt14.pd.512"] + fn vrsqrt14pd(a: f64x8, src: f64x8, m: u8) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.cvtps2dq.512"] + fn vcvtps2dq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.cvtps2udq.512"] + fn vcvtps2udq(a: f32x16, src: u32x16, mask: u16, rounding: i32) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.cvtps2pd.512"] + fn vcvtps2pd(a: f32x8, src: f64x8, mask: u8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.cvttps2dq.512"] + fn vcvttps2dq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.cvttps2udq.512"] + fn vcvttps2udq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.cvttpd2dq.512"] + fn vcvttpd2dq(a: f64x8, src: i32x8, mask: u8, rounding: i32) -> i32x8; + #[link_name = "llvm.x86.avx512.mask.cvttpd2udq.512"] + fn vcvttpd2udq(a: f64x8, src: i32x8, mask: u8, rounding: i32) -> u32x8; + + #[link_name = "llvm.x86.avx512.gather.dpd.512"] + fn vgatherdpd(src: f64x8, slice: *const i8, offsets: i32x8, mask: i8, scale: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.gather.dps.512"] + fn vgatherdps(src: f32x16, slice: *const i8, offsets: i32x16, mask: i16, scale: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.gather.qpd.512"] + fn vgatherqpd(src: f64x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.gather.qps.512"] + fn vgatherqps(src: f32x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> f32x8; + #[link_name = "llvm.x86.avx512.gather.dpq.512"] + fn vpgatherdq(src: i64x8, slice: *const i8, offsets: i32x8, mask: i8, scale: i32) -> i64x8; + #[link_name = "llvm.x86.avx512.gather.dpi.512"] + fn vpgatherdd(src: i32x16, slice: *const i8, offsets: i32x16, mask: i16, scale: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.gather.qpq.512"] + fn vpgatherqq(src: i64x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> i64x8; + #[link_name = "llvm.x86.avx512.gather.qpi.512"] + fn vpgatherqd(src: i32x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> i32x8; + + #[link_name = "llvm.x86.avx512.scatter.dpd.512"] + fn vscatterdpd(slice: *mut i8, mask: i8, offsets: i32x8, src: f64x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.dps.512"] + fn vscatterdps(slice: *mut i8, mask: i16, offsets: i32x16, src: f32x16, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.qpd.512"] + fn vscatterqpd(slice: *mut i8, mask: i8, offsets: i64x8, src: f64x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.qps.512"] + fn vscatterqps(slice: *mut i8, mask: i8, offsets: i64x8, src: f32x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.dpq.512"] + fn vpscatterdq(slice: *mut i8, mask: i8, offsets: i32x8, src: i64x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.dpi.512"] + fn vpscatterdd(slice: *mut i8, mask: i16, offsets: i32x16, src: i32x16, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.qpq.512"] + fn vpscatterqq(slice: *mut i8, mask: i8, offsets: i64x8, src: i64x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.qpi.512"] + fn vpscatterqd(slice: *mut i8, mask: i8, offsets: i64x8, src: i32x8, scale: i32); + + #[link_name = "llvm.x86.avx512.mask.cmp.ss"] + fn vcmpss(a: __m128, b: __m128, op: i32, m: i8, sae: i32) -> i8; + #[link_name = "llvm.x86.avx512.mask.cmp.sd"] + fn vcmpsd(a: __m128d, b: __m128d, op: i32, m: i8, sae: i32) -> i8; + #[link_name = "llvm.x86.avx512.mask.cmp.ps.512"] + fn vcmpps(a: f32x16, b: f32x16, op: i32, m: i16, sae: i32) -> i16; + #[link_name = "llvm.x86.avx512.mask.cmp.pd.512"] + fn vcmppd(a: f64x8, b: f64x8, op: i32, m: i8, sae: i32) -> i8; + #[link_name = "llvm.x86.avx512.mask.ucmp.q.512"] + fn vpcmpuq(a: i64x8, b: i64x8, op: i32, m: i8) -> i8; + #[link_name = "llvm.x86.avx512.mask.cmp.q.512"] + fn vpcmpq(a: i64x8, b: i64x8, op: i32, m: i8) -> i8; + #[link_name = "llvm.x86.avx512.mask.ucmp.d.512"] + fn vpcmpud(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; + #[link_name = "llvm.x86.avx512.mask.cmp.d.512"] + fn vpcmpd(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; + + #[link_name = "llvm.x86.avx512.mask.prol.d.512"] + fn vprold(a: i32x16, i8: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.pror.d.512"] + fn vprord(a: i32x16, i8: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.prol.q.512"] + fn vprolq(a: i64x8, i8: i32) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.pror.q.512"] + fn vprorq(a: i64x8, i8: i32) -> i64x8; + + #[link_name = "llvm.x86.avx512.mask.prolv.d.512"] + fn vprolvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.prorv.d.512"] + fn vprorvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.prolv.q.512"] + fn vprolvq(a: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.prorv.q.512"] + fn vprorvq(a: i64x8, b: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.psllv.d.512"] + fn vpsllvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.psrlv.d.512"] + fn vpsrlvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.psllv.q.512"] + fn vpsllvq(a: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.psrlv.q.512"] + fn vpsrlvq(a: i64x8, b: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.pslli.d.512"] + fn vpsllid(a: i32x16, imm8: u32) -> i32x16; + #[link_name = "llvm.x86.avx512.psrli.d.512"] + fn vpsrlid(a: i32x16, imm8: u32) -> i32x16; + #[link_name = "llvm.x86.avx512.pslli.q.512"] + fn vpslliq(a: i64x8, imm8: u32) -> i64x8; + #[link_name = "llvm.x86.avx512.psrli.q.512"] + fn vpsrliq(a: i64x8, imm8: u32) -> i64x8; + + #[link_name = "llvm.x86.avx512.psll.d.512"] + fn vpslld(a: i32x16, count: i32x4) -> i32x16; + #[link_name = "llvm.x86.avx512.psrl.d.512"] + fn vpsrld(a: i32x16, count: i32x4) -> i32x16; + #[link_name = "llvm.x86.avx512.psll.q.512"] + fn vpsllq(a: i64x8, count: i64x2) -> i64x8; + #[link_name = "llvm.x86.avx512.psrl.q.512"] + fn vpsrlq(a: i64x8, count: i64x2) -> i64x8; + + #[link_name = "llvm.x86.avx512.psra.d.512"] + fn vpsrad(a: i32x16, count: i32x4) -> i32x16; + #[link_name = "llvm.x86.avx512.psra.q.512"] + fn vpsraq(a: i64x8, count: i64x2) -> i64x8; + + #[link_name = "llvm.x86.avx512.psrai.d.512"] + fn vpsraid(a: i32x16, imm8: u32) -> i32x16; + #[link_name = "llvm.x86.avx512.psrai.q.512"] + fn vpsraiq(a: i64x8, imm8: u32) -> i64x8; + + #[link_name = "llvm.x86.avx512.psrav.d.512"] + fn vpsravd(a: i32x16, count: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.psrav.q.512"] + fn vpsravq(a: i64x8, count: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.vpermilvar.ps.512"] + fn vpermilps(a: f32x16, b: i32x16) -> f32x16; + #[link_name = "llvm.x86.avx512.vpermilvar.pd.512"] + fn vpermilpd(a: f64x8, b: i64x8) -> f64x8; + + #[link_name = "llvm.x86.avx512.permvar.si.512"] + fn vpermd(a: i32x16, idx: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.permvar.di.512"] + fn vpermq(a: i64x8, idx: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.permvar.sf.512"] + fn vpermps(a: f32x16, idx: i32x16) -> f32x16; + #[link_name = "llvm.x86.avx512.permvar.df.512"] + fn vpermpd(a: f64x8, idx: i64x8) -> f64x8; + + #[link_name = "llvm.x86.avx512.vpermi2var.d.512"] + fn vpermi2d(a: i32x16, idx: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.vpermi2var.q.512"] + fn vpermi2q(a: i64x8, idx: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.vpermi2var.ps.512"] + fn vpermi2ps(a: f32x16, idx: i32x16, b: f32x16) -> f32x16; + #[link_name = "llvm.x86.avx512.vpermi2var.pd.512"] + fn vpermi2pd(a: f64x8, idx: i64x8, b: f64x8) -> f64x8; +} + +#[cfg(test)] +mod tests { + use std; + use stdarch_test::simd_test; + + use crate::core_arch::x86::*; + use crate::hint::black_box; + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_abs_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let r = _mm512_abs_epi32(a); + let e = _mm512_setr_epi32( + 0, + 1, + 1, + i32::MAX, + i32::MAX.wrapping_add(1), + 100, + 100, + 32, + 0, + 1, + 1, + i32::MAX, + i32::MAX.wrapping_add(1), + 100, + 100, + 32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_abs_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let r = _mm512_mask_abs_epi32(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_abs_epi32(a, 0b00000000_11111111, a); + let e = _mm512_setr_epi32( + 0, + 1, + 1, + i32::MAX, + i32::MAX.wrapping_add(1), + 100, + 100, + 32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_abs_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let r = _mm512_maskz_abs_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_abs_epi32(0b00000000_11111111, a); + let e = _mm512_setr_epi32( + 0, + 1, + 1, + i32::MAX, + i32::MAX.wrapping_add(1), + 100, + 100, + 32, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_abs_ps() { + #[rustfmt::skip] + let a = _mm512_setr_ps( + 0., 1., -1., f32::MAX, + f32::MIN, 100., -100., -32., + 0., 1., -1., f32::MAX, + f32::MIN, 100., -100., -32., + ); + let r = _mm512_abs_ps(a); + let e = _mm512_setr_ps( + 0., + 1., + 1., + f32::MAX, + f32::MAX, + 100., + 100., + 32., + 0., + 1., + 1., + f32::MAX, + f32::MAX, + 100., + 100., + 32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_abs_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let r = _mm512_mask_abs_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_abs_ps(a, 0b00000000_11111111, a); + let e = _mm512_setr_ps( + 0., + 1., + 1., + f32::MAX, + f32::MAX, + 100., + 100., + 32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_add_epi32(a, b); + let e = _mm512_setr_epi32( + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_mask_add_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_add_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_add_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_add_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_add_ps(a, b); + let e = _mm512_setr_ps( + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_mask_add_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_add_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_maskz_add_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_add_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_sub_epi32(a, b); + let e = _mm512_setr_epi32( + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_mask_sub_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_sub_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_sub_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sub_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_sub_ps(a, b); + let e = _mm512_setr_ps( + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_mask_sub_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_sub_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_maskz_sub_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sub_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mullo_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(2); + let r = _mm512_mullo_epi32(a, b); + let e = _mm512_setr_epi32( + 0, 2, -2, -2, 0, 200, -200, -64, 0, 2, -2, -2, 0, 200, -200, -64, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mullo_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(2); + let r = _mm512_mask_mullo_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mullo_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + 0, + 2, + -2, + -2, + 0, + 200, + -200, + -64, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mullo_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(2); + let r = _mm512_maskz_mullo_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mullo_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 2, -2, -2, 0, 200, -200, -64, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(2.); + let r = _mm512_mul_ps(a, b); + let e = _mm512_setr_ps( + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(2.); + let r = _mm512_mask_mul_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_mul_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(2.); + let r = _mm512_maskz_mul_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_mul_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_div_ps() { + let a = _mm512_setr_ps( + 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., + ); + let b = _mm512_setr_ps( + 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., + ); + let r = _mm512_div_ps(a, b); + let e = _mm512_setr_ps( + 0., + 0.5, + -0.5, + -1., + 50., + f32::INFINITY, + -50., + -16., + 0., + 0.5, + -0.5, + 500., + f32::NEG_INFINITY, + 50., + -50., + -16., + ); + assert_eq_m512(r, e); // 0/0 = NAN + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_div_ps() { + let a = _mm512_setr_ps( + 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., + ); + let b = _mm512_setr_ps( + 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., + ); + let r = _mm512_mask_div_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_div_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 0.5, + -0.5, + -1., + 50., + f32::INFINITY, + -50., + -16., + 0., + 1., + -1., + 1000., + -131., + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_div_ps() { + let a = _mm512_setr_ps( + 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., + ); + let b = _mm512_setr_ps( + 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., + ); + let r = _mm512_maskz_div_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_div_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 0.5, + -0.5, + -1., + 50., + f32::INFINITY, + -50., + -16., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epi32(a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_max_ps(a, b); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_max_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_max_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_max_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_max_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epu32(a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epu32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epu32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epu32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epu32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epi32(a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_min_ps(a, b); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 7., 6., 5., 4., 3., 2., 1., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_min_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_min_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_min_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_min_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epu32(a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epu32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epu32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epu32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epu32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sqrt_ps() { + let a = _mm512_setr_ps( + 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., + ); + let r = _mm512_sqrt_ps(a); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sqrt_ps() { + let a = _mm512_setr_ps( + 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., + ); + let r = _mm512_mask_sqrt_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_sqrt_ps(a, 0b00000000_11111111, a); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 64., 81., 100., 121., 144., 169., 196., 225., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sqrt_ps() { + let a = _mm512_setr_ps( + 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., + ); + let r = _mm512_maskz_sqrt_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sqrt_ps(0b00000000_11111111, a); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmadd_ps(a, b, c); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmadd_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmadd_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmadd_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmadd_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmadd_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmadd_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmsub_ps(a, b, c); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmsub_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsub_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmsub_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsub_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmsub_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsub_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmaddsub_ps(a, b, c); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 7., 10., 9., 12., 11., 14., 13., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmaddsub_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmaddsub_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmaddsub_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmaddsub_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmaddsub_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmaddsub_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmsubadd_ps(a, b, c); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 9., 8., 11., 10., 13., 12., 15., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmsubadd_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsubadd_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmsubadd_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsubadd_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmsubadd_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsubadd_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fnmadd_ps(a, b, c); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., -7., -8., -9., -10., -11., -12., -13., -14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fnmadd_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmadd_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fnmadd_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmadd_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fnmadd_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmadd_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fnmsub_ps(a, b, c); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., -9., -10., -11., -12., -13., -14., -15., -16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fnmsub_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmsub_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fnmsub_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmsub_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fnmsub_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmsub_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rcp14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_rcp14_ps(a); + let e = _mm512_set1_ps(0.33333206); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rcp14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_rcp14_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_rcp14_ps(a, 0b11111111_00000000, a); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 0.33333206, 0.33333206, 0.33333206, 0.33333206, + 0.33333206, 0.33333206, 0.33333206, 0.33333206, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rcp14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_rcp14_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_rcp14_ps(0b11111111_00000000, a); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0.33333206, 0.33333206, 0.33333206, 0.33333206, + 0.33333206, 0.33333206, 0.33333206, 0.33333206, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rsqrt14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_rsqrt14_ps(a); + let e = _mm512_set1_ps(0.5773392); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rsqrt14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_rsqrt14_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_rsqrt14_ps(a, 0b11111111_00000000, a); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 0.5773392, 0.5773392, 0.5773392, 0.5773392, 0.5773392, + 0.5773392, 0.5773392, 0.5773392, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rsqrt14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_rsqrt14_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_rsqrt14_ps(0b11111111_00000000, a); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0.5773392, 0.5773392, 0.5773392, 0.5773392, 0.5773392, + 0.5773392, 0.5773392, 0.5773392, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_getexp_ps(a); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_getexp_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_getexp_ps(a, 0b11111111_00000000, a); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_getexp_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_getexp_ps(0b11111111_00000000, a); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_getmant_ps(a, _MM_MANT_NORM_P75_1P5, _MM_MANT_SIGN_NAN); + let e = _mm512_set1_ps(1.25); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_mask_getmant_ps(a, 0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512(r, a); + let r = _mm512_mask_getmant_ps( + a, + 0b11111111_00000000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + ); + let e = _mm512_setr_ps( + 10., 10., 10., 10., 10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_maskz_getmant_ps(0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = + _mm512_maskz_getmant_ps(0b11111111_00000000, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(-1.); + let r = _mm512_add_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., + 0.5, + 1., + 2.5, + 3., + 4.5, + 5., + 6.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + let r = _mm512_add_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., 0.5, 1., 2.5, 3., 4.5, 5., 6.5, 7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(-1.); + let r = _mm512_mask_add_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_add_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(-1.); + let r = _mm512_maskz_add_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_add_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_sub_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., + 0.5, + 1., + 2.5, + 3., + 4.5, + 5., + 6.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + let r = _mm512_sub_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., 0.5, 1., 2.5, 3., 4.5, 5., 6.5, 7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_mask_sub_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_sub_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_maskz_sub_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sub_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_round_ps() { + let a = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 8., + 9.5, + 10., + 11.5, + 12., + 13.5, + 14., + 0.00000000000000000000007, + ); + let b = _mm512_set1_ps(0.1); + let r = _mm512_mul_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 0., + 0.15, + 0.2, + 0.35, + 0.4, + 0.55, + 0.6, + 0.75, + 0.8, + 0.95, + 1.0, + 1.15, + 1.2, + 1.35, + 1.4, + 0.000000000000000000000007000001, + ); + assert_eq_m512(r, e); + let r = _mm512_mul_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 0., + 0.14999999, + 0.2, + 0.35, + 0.4, + 0.54999995, + 0.59999996, + 0.75, + 0.8, + 0.95, + 1.0, + 1.15, + 1.1999999, + 1.3499999, + 1.4, + 0.000000000000000000000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_round_ps() { + let a = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 8., + 9.5, + 10., + 11.5, + 12., + 13.5, + 14., + 0.00000000000000000000007, + ); + let b = _mm512_set1_ps(0.1); + let r = _mm512_mask_mul_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_mul_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 0.8, + 0.95, + 1.0, + 1.15, + 1.2, + 1.35, + 1.4, + 0.000000000000000000000007000001, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_round_ps() { + let a = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 8., + 9.5, + 10., + 11.5, + 12., + 13.5, + 14., + 0.00000000000000000000007, + ); + let b = _mm512_set1_ps(0.1); + let r = _mm512_maskz_mul_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_mul_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0.8, + 0.95, + 1.0, + 1.15, + 1.2, + 1.35, + 1.4, + 0.000000000000000000000007000001, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_div_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_div_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.33333334); + assert_eq_m512(r, e); + let r = _mm512_div_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.3333333); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_div_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_mask_div_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_div_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 0.33333334, 0.33333334, 0.33333334, 0.33333334, + 0.33333334, 0.33333334, 0.33333334, 0.33333334, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_div_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_maskz_div_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_div_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0.33333334, 0.33333334, 0.33333334, 0.33333334, + 0.33333334, 0.33333334, 0.33333334, 0.33333334, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sqrt_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_sqrt_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.7320508); + assert_eq_m512(r, e); + let r = _mm512_sqrt_round_ps(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.7320509); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sqrt_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_sqrt_round_ps(a, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_sqrt_round_ps( + a, + 0b11111111_00000000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 1.7320508, 1.7320508, 1.7320508, 1.7320508, 1.7320508, + 1.7320508, 1.7320508, 1.7320508, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sqrt_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_sqrt_round_ps(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sqrt_round_ps( + 0b11111111_00000000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1.7320508, 1.7320508, 1.7320508, 1.7320508, 1.7320508, + 1.7320508, 1.7320508, 1.7320508, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fmadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fmadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask_fmadd_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fmadd_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_maskz_fmadd_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmadd_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask3_fmadd_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmadd_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -1., + -1., + -1., + -1., + -1., + -1., + -1., + -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = _mm512_fmsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fmsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask_fmsub_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsub_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_maskz_fmsub_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsub_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask3_fmsub_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsub_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 1., + 1., + 1., + 1., + 1., + 1., + 1., + 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fmaddsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + ); + assert_eq_m512(r, e); + let r = _mm512_fmaddsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + -0.9999999, 1., -0.9999999, 1., -0.9999999, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask_fmaddsub_round_ps( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, a); + let r = _mm512_mask_fmaddsub_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_maskz_fmaddsub_round_ps( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmaddsub_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask3_fmaddsub_round_ps( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmaddsub_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + -1., + -1., + -1., + -1., + -1., + -1., + -1., + -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fmsubadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + ); + assert_eq_m512(r, e); + let r = _mm512_fmsubadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask_fmsubadd_round_ps( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsubadd_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_maskz_fmsubadd_round_ps( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsubadd_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask3_fmsubadd_round_ps( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsubadd_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -1., + -1., + -1., + -1., + -1., + -1., + -1., + -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = _mm512_fnmadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fnmadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask_fnmadd_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmadd_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, + 0.00000007, 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_maskz_fnmadd_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmadd_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask3_fnmadd_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmadd_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fnmsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fnmsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask_fnmsub_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmsub_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, + 0.00000007, 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_maskz_fnmsub_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmsub_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask3_fnmsub_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmsub_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, -1., -1., -1., -1., -1., -1., -1., -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_max_round_ps(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_max_round_ps(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, a); + let r = _mm512_mask_max_round_ps(a, 0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_max_round_ps(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_max_round_ps(0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_min_round_ps(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 7., 6., 5., 4., 3., 2., 1., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_min_round_ps(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, a); + let r = _mm512_mask_min_round_ps(a, 0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_min_round_ps(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_min_round_ps(0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_getexp_round_ps(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + let r = _mm512_getexp_round_ps(a, _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_getexp_round_ps(a, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, a); + let r = _mm512_mask_getexp_round_ps(a, 0b11111111_00000000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_getexp_round_ps(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_getexp_round_ps(0b11111111_00000000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_round_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_getmant_round_ps( + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_set1_ps(1.25); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_round_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_mask_getmant_round_ps( + a, + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512(r, a); + let r = _mm512_mask_getmant_round_ps( + a, + 0b11111111_00000000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_ps( + 10., 10., 10., 10., 10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_round_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_maskz_getmant_round_ps( + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_getmant_round_ps( + 0b11111111_00000000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtps_epi32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtps_epi32(a); + let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtps_epi32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtps_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtps_epi32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtps_epi32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtps_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtps_epi32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtps_epu32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtps_epu32(a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtps_epu32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtps_epu32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtps_epu32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtps_epu32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtps_epu32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtps_epu32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + let r = _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = + _mm512_mask_cvt_roundps_epi32(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvt_roundps_epi32( + src, + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvt_roundps_epi32(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvt_roundps_epi32( + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvt_roundps_epu32(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + let r = _mm512_cvt_roundps_epu32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = + _mm512_mask_cvt_roundps_epu32(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvt_roundps_epu32( + src, + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvt_roundps_epu32(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvt_roundps_epu32( + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtt_roundps_epi32(a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtt_roundps_epi32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtt_roundps_epi32(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtt_roundps_epi32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtt_roundps_epi32(0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtt_roundps_epu32(a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtt_roundps_epu32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtt_roundps_epu32(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtt_roundps_epu32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtt_roundps_epu32(0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvttps_epi32(a); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvttps_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvttps_epi32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvttps_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvttps_epi32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvttps_epu32(a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvttps_epu32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvttps_epu32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvttps_epu32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvttps_epu32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32gather_ps() { + let mut arr = [0f32; 256]; + for i in 0..256 { + arr[i] = i as f32; + } + // A multiplier of 4 is word-addressing + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 120, 128, 136, 144, 152, 160, 168, 176); + let r = _mm512_i32gather_ps(index, arr.as_ptr() as *const u8, 4); + #[rustfmt::skip] + assert_eq_m512(r, _mm512_setr_ps(0., 16., 32., 48., 64., 80., 96., 112., + 120., 128., 136., 144., 152., 160., 168., 176.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32gather_ps() { + let mut arr = [0f32; 256]; + for i in 0..256 { + arr[i] = i as f32; + } + let src = _mm512_set1_ps(2.); + let mask = 0b10101010_10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 120, 128, 136, 144, 152, 160, 168, 176); + // A multiplier of 4 is word-addressing + let r = _mm512_mask_i32gather_ps(src, mask, index, arr.as_ptr() as *const u8, 4); + #[rustfmt::skip] + assert_eq_m512(r, _mm512_setr_ps(2., 16., 2., 48., 2., 80., 2., 112., + 2., 128., 2., 144., 2., 160., 2., 176.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32gather_epi32() { + let mut arr = [0i32; 256]; + for i in 0..256 { + arr[i] = i as i32; + } + // A multiplier of 4 is word-addressing + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 120, 128, 136, 144, 152, 160, 168, 176); + let r = _mm512_i32gather_epi32(index, arr.as_ptr() as *const u8, 4); + #[rustfmt::skip] + assert_eq_m512i(r, _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 120, 128, 136, 144, 152, 160, 168, 176)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32gather_epi32() { + let mut arr = [0i32; 256]; + for i in 0..256 { + arr[i] = i as i32; + } + let src = _mm512_set1_epi32(2); + let mask = 0b10101010_10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + // A multiplier of 4 is word-addressing + let r = _mm512_mask_i32gather_epi32(src, mask, index, arr.as_ptr() as *const u8, 4); + #[rustfmt::skip] + assert_eq_m512i(r, _mm512_setr_epi32(2, 16, 2, 48, 2, 80, 2, 112, + 2, 144, 2, 176, 2, 208, 2, 240)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32scatter_ps() { + let mut arr = [0f32; 256]; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + let src = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + // A multiplier of 4 is word-addressing + _mm512_i32scatter_ps(arr.as_mut_ptr() as *mut u8, index, src, 4); + let mut expected = [0f32; 256]; + for i in 0..16 { + expected[i * 16] = (i + 1) as f32; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32scatter_ps() { + let mut arr = [0f32; 256]; + let mask = 0b10101010_10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + let src = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + // A multiplier of 4 is word-addressing + _mm512_mask_i32scatter_ps(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); + let mut expected = [0f32; 256]; + for i in 0..8 { + expected[i * 32 + 16] = 2. * (i + 1) as f32; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32scatter_epi32() { + let mut arr = [0i32; 256]; + #[rustfmt::skip] + + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + let src = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + // A multiplier of 4 is word-addressing + _mm512_i32scatter_epi32(arr.as_mut_ptr() as *mut u8, index, src, 4); + let mut expected = [0i32; 256]; + for i in 0..16 { + expected[i * 16] = (i + 1) as i32; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32scatter_epi32() { + let mut arr = [0i32; 256]; + let mask = 0b10101010_10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + let src = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + // A multiplier of 4 is word-addressing + _mm512_mask_i32scatter_epi32(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); + let mut expected = [0i32; 256]; + for i in 0..8 { + expected[i * 32 + 16] = 2 * (i + 1) as i32; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmplt_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let m = _mm512_cmplt_ps_mask(a, b); + assert_eq!(m, 0b00000101_00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmplt_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmplt_ps_mask(mask, a, b); + assert_eq!(r, 0b00000100_00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpnlt_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + assert_eq!(_mm512_cmpnlt_ps_mask(a, b), !_mm512_cmplt_ps_mask(a, b)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpnlt_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01111010_01111010; + assert_eq!(_mm512_mask_cmpnlt_ps_mask(mask, a, b), 0b01111010_01111010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpnle_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let m = _mm512_cmpnle_ps_mask(b, a); + assert_eq!(m, 0b00001101_00001101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpnle_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmpnle_ps_mask(mask, b, a); + assert_eq!(r, 0b00000100_00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmple_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + assert_eq!(_mm512_cmple_ps_mask(a, b), 0b00100101_00100101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmple_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01111010_01111010; + assert_eq!(_mm512_mask_cmple_ps_mask(mask, a, b), 0b00100000_00100000); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpeq_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); + let m = _mm512_cmpeq_ps_mask(b, a); + assert_eq!(m, 0b11001101_11001101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpeq_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpeq_ps_mask(mask, b, a); + assert_eq!(r, 0b01001000_01001000); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpneq_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); + let m = _mm512_cmpneq_ps_mask(b, a); + assert_eq!(m, 0b00110010_00110010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpneq_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpneq_ps_mask(mask, b, a); + assert_eq!(r, 0b00110010_00110010) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmp_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let m = _mm512_cmp_ps_mask(a, b, _CMP_LT_OQ); + assert_eq!(m, 0b00000101_00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmp_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmp_ps_mask(mask, a, b, _CMP_LT_OQ); + assert_eq!(r, 0b00000100_00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmp_round_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let m = _mm512_cmp_round_ps_mask(a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 0b00000101_00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmp_round_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmp_round_ps_mask(mask, a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); + assert_eq!(r, 0b00000100_00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpord_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., + f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); + #[rustfmt::skip] + let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., + f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); + let m = _mm512_cmpord_ps_mask(a, b); + assert_eq!(m, 0b00000101_00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpord_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., + f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); + #[rustfmt::skip] + let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., + f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); + let mask = 0b11000011_11000011; + let m = _mm512_mask_cmpord_ps_mask(mask, a, b); + assert_eq!(m, 0b00000001_00000001); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpunord_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., + f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); + #[rustfmt::skip] + let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., + f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); + let m = _mm512_cmpunord_ps_mask(a, b); + + assert_eq!(m, 0b11111010_11111010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpunord_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., + f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); + #[rustfmt::skip] + let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., + f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); + let mask = 0b00001111_00001111; + let m = _mm512_mask_cmpunord_ps_mask(mask, a, b); + assert_eq!(m, 0b000001010_00001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cmp_ss_mask() { + let a = _mm_setr_ps(2., 1., 1., 1.); + let b = _mm_setr_ps(1., 2., 2., 2.); + let m = _mm_cmp_ss_mask(a, b, _CMP_GE_OS); + assert_eq!(m, 1); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_cmp_ss_mask() { + let a = _mm_setr_ps(2., 1., 1., 1.); + let b = _mm_setr_ps(1., 2., 2., 2.); + let m = _mm_mask_cmp_ss_mask(0b10, a, b, _CMP_GE_OS); + assert_eq!(m, 0); + let m = _mm_mask_cmp_ss_mask(0b1, a, b, _CMP_GE_OS); + assert_eq!(m, 1); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cmp_round_ss_mask() { + let a = _mm_setr_ps(2., 1., 1., 1.); + let b = _mm_setr_ps(1., 2., 2., 2.); + let m = _mm_cmp_round_ss_mask(a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 1); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_cmp_round_ss_mask() { + let a = _mm_setr_ps(2., 1., 1., 1.); + let b = _mm_setr_ps(1., 2., 2., 2.); + let m = _mm_mask_cmp_round_ss_mask(0b10, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 0); + let m = _mm_mask_cmp_round_ss_mask(0b1, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 1); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cmp_sd_mask() { + let a = _mm_setr_pd(2., 1.); + let b = _mm_setr_pd(1., 2.); + let m = _mm_cmp_sd_mask(a, b, _CMP_GE_OS); + assert_eq!(m, 1); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_cmp_sd_mask() { + let a = _mm_setr_pd(2., 1.); + let b = _mm_setr_pd(1., 2.); + let m = _mm_mask_cmp_sd_mask(0b10, a, b, _CMP_GE_OS); + assert_eq!(m, 0); + let m = _mm_mask_cmp_sd_mask(0b1, a, b, _CMP_GE_OS); + assert_eq!(m, 1); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cmp_round_sd_mask() { + let a = _mm_setr_pd(2., 1.); + let b = _mm_setr_pd(1., 2.); + let m = _mm_cmp_round_sd_mask(a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 1); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_cmp_round_sd_mask() { + let a = _mm_setr_pd(2., 1.); + let b = _mm_setr_pd(1., 2.); + let m = _mm_mask_cmp_round_sd_mask(0b10, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 0); + let m = _mm_mask_cmp_round_sd_mask(0b1, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 1); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmplt_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmplt_epu32_mask(a, b); + assert_eq!(m, 0b11001111_11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmplt_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmplt_epu32_mask(mask, a, b); + assert_eq!(r, 0b01001010_01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpgt_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmpgt_epu32_mask(b, a); + assert_eq!(m, 0b11001111_11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpgt_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpgt_epu32_mask(mask, b, a); + assert_eq!(r, 0b01001010_01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmple_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + assert_eq!( + _mm512_cmple_epu32_mask(a, b), + !_mm512_cmpgt_epu32_mask(a, b) + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmple_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + assert_eq!( + _mm512_mask_cmple_epu32_mask(mask, a, b), + 0b01111010_01111010 + ); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpge_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + assert_eq!( + _mm512_cmpge_epu32_mask(a, b), + !_mm512_cmplt_epu32_mask(a, b) + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpge_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + assert_eq!(_mm512_mask_cmpge_epu32_mask(mask, a, b), 0b01100000_0110000); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpeq_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let m = _mm512_cmpeq_epu32_mask(b, a); + assert_eq!(m, 0b11001111_11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpeq_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpeq_epu32_mask(mask, b, a); + assert_eq!(r, 0b01001010_01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpneq_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let m = _mm512_cmpneq_epu32_mask(b, a); + assert_eq!(m, !_mm512_cmpeq_epu32_mask(b, a)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpneq_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, -100, 100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, -100, 100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpneq_epu32_mask(mask, b, a); + assert_eq!(r, 0b00110010_00110010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmp_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmp_epu32_mask(a, b, _MM_CMPINT_LT); + assert_eq!(m, 0b11001111_11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmp_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!(r, 0b01001010_01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmplt_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmplt_epi32_mask(a, b); + assert_eq!(m, 0b00000101_00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmplt_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmplt_epi32_mask(mask, a, b); + assert_eq!(r, 0b00000100_00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpgt_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmpgt_epi32_mask(b, a); + assert_eq!(m, 0b00000101_00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpgt_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmpgt_epi32_mask(mask, b, a); + assert_eq!(r, 0b00000100_00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmple_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + assert_eq!( + _mm512_cmple_epi32_mask(a, b), + !_mm512_cmpgt_epi32_mask(a, b) + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmple_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + assert_eq!(_mm512_mask_cmple_epi32_mask(mask, a, b), 0b01100000_0110000); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpge_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + assert_eq!( + _mm512_cmpge_epi32_mask(a, b), + !_mm512_cmplt_epi32_mask(a, b) + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpge_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + assert_eq!( + _mm512_mask_cmpge_epi32_mask(mask, a, b), + 0b01111010_01111010 + ); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpeq_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let m = _mm512_cmpeq_epi32_mask(b, a); + assert_eq!(m, 0b11001111_11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpeq_epi32_mask() { #[rustfmt::skip] let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); @@ -3290,166 +16946,2209 @@ mod tests { } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpneq_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let m = _mm512_cmpneq_epi32_mask(b, a); - assert_eq!(m, !_mm512_cmpeq_epi32_mask(b, a)); - } + unsafe fn test_mm512_cmpneq_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let m = _mm512_cmpneq_epi32_mask(b, a); + assert_eq!(m, !_mm512_cmpeq_epi32_mask(b, a)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpneq_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, -100, 100, + 0, 1, -1, 13, i32::MAX, i32::MIN, -100, 100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpneq_epi32_mask(mask, b, a); + assert_eq!(r, 0b00110010_00110010) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmp_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmp_epi32_mask(a, b, _MM_CMPINT_LT); + assert_eq!(m, 0b00000101_00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmp_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!(r, 0b00000100_00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_set_epi32() { + let r = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i( + r, + _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_setr_epi32() { + let r = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i( + r, + _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_set1_epi32() { + let r = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, _mm512_set1_epi32(2)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_setzero_si512() { + assert_eq_m512i(_mm512_set1_epi32(0), _mm512_setzero_si512()); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_set_ps() { + let r = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512( + r, + _mm512_set_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ), + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_setr_ps() { + let r = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512( + r, + _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ), + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_set1_ps() { + #[rustfmt::skip] + let expected = _mm512_set_ps(2., 2., 2., 2., 2., 2., 2., 2., + 2., 2., 2., 2., 2., 2., 2., 2.); + assert_eq_m512(expected, _mm512_set1_ps(2.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_setzero_ps() { + assert_eq_m512(_mm512_setzero_ps(), _mm512_set1_ps(0.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_loadu_pd() { + let a = &[4., 3., 2., 5., 8., 9., 64., 50.]; + let p = a.as_ptr(); + let r = _mm512_loadu_pd(black_box(p)); + let e = _mm512_setr_pd(4., 3., 2., 5., 8., 9., 64., 50.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_storeu_pd() { + let a = _mm512_set1_pd(9.); + let mut r = _mm512_undefined_pd(); + _mm512_storeu_pd(&mut r as *mut _ as *mut f64, a); + assert_eq_m512d(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_loadu_ps() { + let a = &[ + 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., + ]; + let p = a.as_ptr(); + let r = _mm512_loadu_ps(black_box(p)); + let e = _mm512_setr_ps( + 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_storeu_ps() { + let a = _mm512_set1_ps(9.); + let mut r = _mm512_undefined_ps(); + _mm512_storeu_ps(&mut r as *mut _ as *mut f32, a); + assert_eq_m512(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_setr_pd() { + let r = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_set_pd() { + let r = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, _mm512_set_pd(7., 6., 5., 4., 3., 2., 1., 0.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rol_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_rol_epi32(a, 1); + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rol_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_mask_rol_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rol_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rol_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let r = _mm512_maskz_rol_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rol_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_ror_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_ror_epi32(a, 1); + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_ror_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_mask_ror_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_ror_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_ror_epi32() { + let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + let r = _mm512_maskz_ror_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_ror_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_slli_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_slli_epi32(a, 1); + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_slli_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_mask_slli_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_slli_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_slli_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let r = _mm512_maskz_slli_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_slli_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srli_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_srli_epi32(a, 1); + let e = _mm512_set_epi32(0 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srli_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_mask_srli_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srli_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(0 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srli_epi32() { + let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0); + let r = _mm512_maskz_srli_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srli_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0 << 31); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rolv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_rolv_epi32(a, b); + + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rolv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_rolv_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rolv_epi32(a, 0b11111111_11111111, a, b); + + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rolv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_rolv_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rolv_epi32(0b00000000_11111111, a, b); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rorv_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_rorv_epi32(a, b); + + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rorv_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_rorv_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rorv_epi32(a, 0b11111111_11111111, a, b); + + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rorv_epi32() { + let a = _mm512_set_epi32(3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + let b = _mm512_set_epi32(2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_rorv_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rorv_epi32(0b00000000_11111111, a, b); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sllv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_sllv_epi32(a, count); + + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sllv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_sllv_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sllv_epi32(a, 0b11111111_11111111, a, count); + + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sllv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let count = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_sllv_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sllv_epi32(0b00000000_11111111, a, count); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srlv_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_srlv_epi32(a, count); + + let e = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srlv_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_srlv_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srlv_epi32(a, 0b11111111_11111111, a, count); + + let e = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srlv_epi32() { + let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0); + let count = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_srlv_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srlv_epi32(0b00000000_11111111, a, count); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sll_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_sll_epi32(a, count); + let e = _mm512_set_epi32( + 0, + 1 << 2, + 1 << 3, + 1 << 4, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sll_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_mask_sll_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sll_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32( + 0, + 1 << 2, + 1 << 3, + 1 << 4, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sll_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 31, + ); + let count = _mm_set_epi32(2, 0, 0, 2); + let r = _mm512_maskz_sll_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sll_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srl_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_srl_epi32(a, count); + let e = _mm512_set_epi32(1 << 29, 0, 0, 1 << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srl_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_mask_srl_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srl_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32(1 << 29, 0, 0, 1 << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srl_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 31, + ); + let count = _mm_set_epi32(2, 0, 0, 2); + let r = _mm512_maskz_srl_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srl_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 29); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sra_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + let count = _mm_set_epi32(1, 0, 0, 2); + let r = _mm512_sra_epi32(a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sra_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_mask_sra_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sra_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sra_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, -14); + let count = _mm_set_epi32(2, 0, 0, 2); + let r = _mm512_maskz_sra_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sra_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srav_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm512_srav_epi32(a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srav_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16); + let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + let r = _mm512_mask_srav_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srav_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srav_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, -14); + let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2); + let r = _mm512_maskz_srav_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srav_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srai_epi32() { + let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, -15); + let r = _mm512_srai_epi32(a, 2); + let e = _mm512_set_epi32(2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srai_epi32() { + let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, -15); + let r = _mm512_mask_srai_epi32(a, 0, a, 2); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srai_epi32(a, 0b11111111_11111111, a, 2); + let e = _mm512_set_epi32(2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srai_epi32() { + let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, -15); + let r = _mm512_maskz_srai_epi32(0, a, 2); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srai_epi32(0b00000000_11111111, a, 2); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permute_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_permute_ps(a, 1); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permute_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_mask_permute_ps(a, 0b00000000_00000000, a, 1); + assert_eq_m512(r, a); + let r = _mm512_mask_permute_ps(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permute_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_maskz_permute_ps(0, a, 1); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permute_ps(0b00000000_11111111, a, 1); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutevar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_permutevar_epi32(idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutevar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_mask_permutevar_epi32(a, 0, idx, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutevar_epi32(a, 0b11111111_11111111, idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutevar_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_permutevar_ps(a, b); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutevar_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_mask_permutevar_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_permutevar_ps(a, 0b11111111_11111111, a, b); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutevar_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_permutevar_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permutevar_ps(0b00000000_11111111, a, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_permutexvar_epi32(idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutexvar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_mask_permutexvar_epi32(a, 0, idx, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutexvar_epi32(a, 0b11111111_11111111, idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_permutexvar_epi32(0, idx, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutexvar_epi32(0b00000000_11111111, idx, a); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_ps() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_permutexvar_ps(idx, a); + let e = _mm512_set1_ps(14.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutexvar_ps() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_mask_permutexvar_ps(a, 0, idx, a); + assert_eq_m512(r, a); + let r = _mm512_mask_permutexvar_ps(a, 0b11111111_11111111, idx, a); + let e = _mm512_set1_ps(14.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_ps() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_maskz_permutexvar_ps(0, idx, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permutexvar_ps(0b00000000_11111111, idx, a); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 14., 14., 14., 14., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_epi32(100); + let r = _mm512_permutex2var_epi32(a, idx, b); + let e = _mm512_set_epi32( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_epi32(100); + let r = _mm512_mask_permutex2var_epi32(a, 0, idx, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutex2var_epi32(a, 0b11111111_11111111, idx, b); + let e = _mm512_set_epi32( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_epi32(100); + let r = _mm512_maskz_permutex2var_epi32(0, a, idx, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutex2var_epi32(0b00000000_11111111, a, idx, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 10, 100, 9, 100, 8, 100, 7, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask2_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1000, + 1 << 4, + 2000, + 1 << 4, + 3000, + 1 << 4, + 4000, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_epi32(100); + let r = _mm512_mask2_permutex2var_epi32(a, idx, 0, b); + assert_eq_m512i(r, idx); + let r = _mm512_mask2_permutex2var_epi32(a, idx, 0b00000000_11111111, b); + let e = _mm512_set_epi32( + 1000, + 1 << 4, + 2000, + 1 << 4, + 3000, + 1 << 4, + 4000, + 1 << 4, + 10, + 100, + 9, + 100, + 8, + 100, + 7, + 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_permutex2var_ps(a, idx, b); + let e = _mm512_set_ps( + 14., 100., 13., 100., 12., 100., 11., 100., 10., 100., 9., 100., 8., 100., 7., 100., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_mask_permutex2var_ps(a, 0, idx, b); + assert_eq_m512(r, a); + let r = _mm512_mask_permutex2var_ps(a, 0b11111111_11111111, idx, b); + let e = _mm512_set_ps( + 14., 100., 13., 100., 12., 100., 11., 100., 10., 100., 9., 100., 8., 100., 7., 100., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_maskz_permutex2var_ps(0, a, idx, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permutex2var_ps(0b00000000_11111111, a, idx, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 100., 9., 100., 8., 100., 7., 100., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask2_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_mask2_permutex2var_ps(a, idx, 0, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_mask2_permutex2var_ps(a, idx, 0b00000000_11111111, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 100., 9., 100., 8., 100., 7., 100., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_epi32() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let r = _mm512_shuffle_epi32(a, _MM_PERM_AADD); + let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 8, 8, 1, 1, 16, 16, 9, 9); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_epi32() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let r = _mm512_mask_shuffle_epi32(a, 0, a, _MM_PERM_AADD); + assert_eq_m512i(r, a); + let r = _mm512_mask_shuffle_epi32(a, 0b11111111_11111111, a, _MM_PERM_AADD); + let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 8, 8, 1, 1, 16, 16, 9, 9); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_epi32() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let r = _mm512_maskz_shuffle_epi32(0, a, _MM_PERM_AADD); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_shuffle_epi32(0b00000000_11111111, a, _MM_PERM_AADD); + let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_ps() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_shuffle_ps(a, b, 0x0F); + let e = _mm512_setr_ps( + 8., 8., 2., 2., 16., 16., 10., 10., 8., 8., 2., 2., 16., 16., 10., 10., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_ps() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_mask_shuffle_ps(a, 0, a, b, 0x0F); + assert_eq_m512(r, a); + let r = _mm512_mask_shuffle_ps(a, 0b11111111_11111111, a, b, 0x0F); + let e = _mm512_setr_ps( + 8., 8., 2., 2., 16., 16., 10., 10., 8., 8., 2., 2., 16., 16., 10., 10., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_ps() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_maskz_shuffle_ps(0, a, b, 0x0F); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_shuffle_ps(0b00000000_11111111, a, b, 0x0F); + let e = _mm512_setr_ps( + 8., 8., 2., 2., 16., 16., 10., 10., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_i32x4() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_shuffle_i32x4(a, b, 0b00000000); + let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 2, 3, 6, 7, 2, 3, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_i32x4() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_mask_shuffle_i32x4(a, 0, a, b, 0b00000000); + assert_eq_m512i(r, a); + let r = _mm512_mask_shuffle_i32x4(a, 0b11111111_11111111, a, b, 0b00000000); + let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 2, 3, 6, 7, 2, 3, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_i32x4() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_maskz_shuffle_i32x4(0, a, b, 0b00000000); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_shuffle_i32x4(0b00000000_11111111, a, b, 0b00000000); + let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_f32x4() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_shuffle_f32x4(a, b, 0b00000000); + let e = _mm512_setr_ps( + 1., 4., 5., 8., 1., 4., 5., 8., 2., 3., 6., 7., 2., 3., 6., 7., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_f32x4() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_mask_shuffle_f32x4(a, 0, a, b, 0b00000000); + assert_eq_m512(r, a); + let r = _mm512_mask_shuffle_f32x4(a, 0b11111111_11111111, a, b, 0b00000000); + let e = _mm512_setr_ps( + 1., 4., 5., 8., 1., 4., 5., 8., 2., 3., 6., 7., 2., 3., 6., 7., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_f32x4() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_maskz_shuffle_f32x4(0, a, b, 0b00000000); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_shuffle_f32x4(0b00000000_11111111, a, b, 0b00000000); + let e = _mm512_setr_ps( + 1., 4., 5., 8., 1., 4., 5., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_extractf32x4_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_extractf32x4_ps(a, 0x1); + let e = _mm_setr_ps(5., 6., 7., 8.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_moveldup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_moveldup_ps(a); + let e = _mm512_setr_ps( + 1., 1., 3., 3., 5., 5., 7., 7., 9., 9., 11., 11., 13., 13., 15., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_moveldup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_mask_moveldup_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_moveldup_ps(a, 0b11111111_11111111, a); + let e = _mm512_setr_ps( + 1., 1., 3., 3., 5., 5., 7., 7., 9., 9., 11., 11., 13., 13., 15., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_moveldup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_maskz_moveldup_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_moveldup_ps(0b00000000_11111111, a); + let e = _mm512_setr_ps( + 1., 1., 3., 3., 5., 5., 7., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_movehdup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_movehdup_ps(a); + let e = _mm512_setr_ps( + 2., 2., 4., 4., 6., 6., 8., 8., 10., 10., 12., 12., 14., 14., 16., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_movehdup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_mask_movehdup_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_movehdup_ps(a, 0b11111111_11111111, a); + let e = _mm512_setr_ps( + 2., 2., 4., 4., 6., 6., 8., 8., 10., 10., 12., 12., 14., 14., 16., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_movehdup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_maskz_movehdup_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_movehdup_ps(0b00000000_11111111, a); + let e = _mm512_setr_ps( + 2., 2., 4., 4., 6., 6., 8., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_and_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_and_epi32(a, b); + let e = _mm512_set_epi32(1 << 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_and_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_mask_and_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_and_epi32(a, 0b01111111_11111111, a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_and_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_maskz_and_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_and_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_and_si512() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_and_epi32(a, b); + let e = _mm512_set_epi32(1 << 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_or_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_or_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_or_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_mask_or_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_or_epi32(a, 0b11111111_11111111, a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_or_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_maskz_or_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_or_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32( + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_or_si512() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_or_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_xor_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_xor_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_xor_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_mask_xor_epi32(a, 0, a, b); + assert_eq_m512i(r, a); - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpneq_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, -100, 100, - 0, 1, -1, 13, i32::MAX, i32::MIN, -100, 100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpneq_epi32_mask(mask, b, a); - assert_eq!(r, 0b00110010_00110010) + let r = _mm512_mask_xor_epi32(a, 0b01111111_11111111, a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmp_epi32_mask(a, b, _MM_CMPINT_LT); - assert_eq!(m, 0b00000101_00000101); - } + unsafe fn test_mm512_maskz_xor_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_maskz_xor_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LT); - assert_eq!(r, 0b00000100_00000100); + let r = _mm512_maskz_xor_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set_epi32() { - let r = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i( - r, - _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), - ) + unsafe fn test_mm512_xor_si512() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_xor_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setr_epi32() { - let r = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i( - r, - _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), - ) + unsafe fn test_mm512_kand() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b11001100_00110011; + let r = _mm512_kand(a, b); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set1_epi32() { - let r = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - assert_eq_m512i(r, _mm512_set1_epi32(2)); + unsafe fn test_kand_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b11001100_00110011; + let r = _kand_mask16(a, b); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setzero_si512() { - assert_eq_m512i(_mm512_set1_epi32(0), _mm512_setzero_si512()); + unsafe fn test_mm512_kor() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kor(a, b); + let e: u16 = 0b11101110_00111011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set_ps() { - let r = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - assert_eq_m512( - r, - _mm512_set_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ), - ) + unsafe fn test_kor_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kor_mask16(a, b); + let e: u16 = 0b11101110_00111011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setr_ps() { - let r = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - assert_eq_m512( - r, - _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ), - ) + unsafe fn test_mm512_kxor() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kxor(a, b); + let e: u16 = 0b11100010_00111000; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set1_ps() { - #[rustfmt::skip] - let expected = _mm512_set_ps(2., 2., 2., 2., 2., 2., 2., 2., - 2., 2., 2., 2., 2., 2., 2., 2.); - assert_eq_m512(expected, _mm512_set1_ps(2.)); + unsafe fn test_kxor_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kxor_mask16(a, b); + let e: u16 = 0b11100010_00111000; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setzero_ps() { - assert_eq_m512(_mm512_setzero_ps(), _mm512_set1_ps(0.)); + unsafe fn test_mm512_knot() { + let a: u16 = 0b11001100_00110011; + let r = _mm512_knot(a); + let e: u16 = 0b00110011_11001100; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_loadu_pd() { - let a = &[4., 3., 2., 5., 8., 9., 64., 50.]; - let p = a.as_ptr(); - let r = _mm512_loadu_pd(black_box(p)); - let e = _mm512_setr_pd(4., 3., 2., 5., 8., 9., 64., 50.); - assert_eq_m512d(r, e); + unsafe fn test_knot_mask16() { + let a: u16 = 0b11001100_00110011; + let r = _knot_mask16(a); + let e: u16 = 0b00110011_11001100; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_storeu_pd() { - let a = _mm512_set1_pd(9.); - let mut r = _mm512_undefined_pd(); - _mm512_storeu_pd(&mut r as *mut _ as *mut f64, a); - assert_eq_m512d(r, a); + unsafe fn test_mm512_kandn() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kandn(a, b); + let e: u16 = 0b00100010_00001000; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_loadu_ps() { - let a = &[ - 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., - ]; - let p = a.as_ptr(); - let r = _mm512_loadu_ps(black_box(p)); - let e = _mm512_setr_ps( - 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., - ); - assert_eq_m512(r, e); + unsafe fn test_kandn_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kandn_mask16(a, b); + let e: u16 = 0b00100010_00001000; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_storeu_ps() { - let a = _mm512_set1_ps(9.); - let mut r = _mm512_undefined_ps(); - _mm512_storeu_ps(&mut r as *mut _ as *mut f32, a); - assert_eq_m512(r, a); + unsafe fn test_mm512_kxnor() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kxnor(a, b); + let e: u16 = 0b00011101_11000111; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setr_pd() { - let r = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); - assert_eq_m512d(r, _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.)); + unsafe fn test_kxnor_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kxnor_mask16(a, b); + let e: u16 = 0b00011101_11000111; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set_pd() { - let r = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); - assert_eq_m512d(r, _mm512_set_pd(7., 6., 5., 4., 3., 2., 1., 0.)); + unsafe fn test_mm512_kmov() { + let a: u16 = 0b11001100_00110011; + let r = _mm512_kmov(a); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); } } diff --git a/library/stdarch/crates/core_arch/src/x86/macros.rs b/library/stdarch/crates/core_arch/src/x86/macros.rs index b1b7697623..891286df4e 100644 --- a/library/stdarch/crates/core_arch/src/x86/macros.rs +++ b/library/stdarch/crates/core_arch/src/x86/macros.rs @@ -216,6 +216,523 @@ macro_rules! constify_imm8_gather { }; } +// For round instructions, the only valid values for rounding are 4, 8, 9, 10 and 11. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm4_round { + ($imm8:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm8) & 0b1111 { + 4 => $expand!(4), + 8 => $expand!(8), + 9 => $expand!(9), + 10 => $expand!(10), + 11 => $expand!(11), + _ => panic!("Invalid round value"), + } + }; +} + +// For sae instructions, the only valid values for sae are 4 and 8. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm4_sae { + ($imm8:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm8) & 0b1111 { + 4 => $expand!(4), + 8 => $expand!(8), + _ => panic!("Invalid sae value"), + } + }; +} + +// Two mantissas parameters. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm4_mantissas { + ($imm4:expr, $imm2:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm4, $imm2) { + (0, 0) => $expand!(0, 0), + (0, 1) => $expand!(0, 1), + (0, 2) => $expand!(0, 2), + (0, 3) => $expand!(0, 3), + (1, 0) => $expand!(1, 0), + (1, 1) => $expand!(1, 1), + (1, 2) => $expand!(1, 2), + (1, 3) => $expand!(1, 3), + (2, 0) => $expand!(2, 0), + (2, 1) => $expand!(2, 1), + (2, 2) => $expand!(2, 2), + (2, 3) => $expand!(2, 3), + (3, 0) => $expand!(3, 0), + (3, 1) => $expand!(3, 1), + (3, 2) => $expand!(3, 2), + (3, 3) => $expand!(3, 3), + (4, 0) => $expand!(4, 0), + (4, 1) => $expand!(4, 1), + (4, 2) => $expand!(4, 2), + (4, 3) => $expand!(4, 3), + (5, 0) => $expand!(5, 0), + (5, 1) => $expand!(5, 1), + (5, 2) => $expand!(5, 2), + (5, 3) => $expand!(5, 3), + (6, 0) => $expand!(6, 0), + (6, 1) => $expand!(6, 1), + (6, 2) => $expand!(6, 2), + (6, 3) => $expand!(6, 3), + (7, 0) => $expand!(7, 0), + (7, 1) => $expand!(7, 1), + (7, 2) => $expand!(7, 2), + (7, 3) => $expand!(7, 3), + (8, 0) => $expand!(8, 0), + (8, 1) => $expand!(8, 1), + (8, 2) => $expand!(8, 2), + (8, 3) => $expand!(8, 3), + (9, 0) => $expand!(9, 0), + (9, 1) => $expand!(9, 1), + (9, 2) => $expand!(9, 2), + (9, 3) => $expand!(9, 3), + (10, 0) => $expand!(10, 0), + (10, 1) => $expand!(10, 1), + (10, 2) => $expand!(10, 2), + (10, 3) => $expand!(10, 3), + (11, 0) => $expand!(11, 0), + (11, 1) => $expand!(11, 1), + (11, 2) => $expand!(11, 2), + (11, 3) => $expand!(11, 3), + (12, 0) => $expand!(12, 0), + (12, 1) => $expand!(12, 1), + (12, 2) => $expand!(12, 2), + (12, 3) => $expand!(12, 3), + (13, 0) => $expand!(13, 0), + (13, 1) => $expand!(13, 1), + (13, 2) => $expand!(13, 2), + (13, 3) => $expand!(13, 3), + (14, 0) => $expand!(14, 0), + (14, 1) => $expand!(14, 1), + (14, 2) => $expand!(14, 2), + (14, 3) => $expand!(14, 3), + (15, 0) => $expand!(15, 0), + (15, 1) => $expand!(15, 1), + (15, 2) => $expand!(15, 2), + (15, 3) => $expand!(15, 3), + (_, _) => panic!("Invalid sae value"), + } + }; +} + +// Include mantissas parameters. +// For sae instructions, the only valid values for sae are 4 and 8. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm4_mantissas_sae { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm4_1, $imm2, $imm4_2) { + (0, 0, 4) => $expand!(0, 0, 4), + (0, 0, 8) => $expand!(0, 0, 8), + (0, 1, 4) => $expand!(0, 1, 4), + (0, 1, 8) => $expand!(0, 1, 8), + (0, 2, 4) => $expand!(0, 2, 4), + (0, 2, 8) => $expand!(0, 2, 8), + (0, 3, 4) => $expand!(0, 3, 4), + (0, 3, 8) => $expand!(0, 3, 8), + (1, 0, 4) => $expand!(1, 0, 4), + (1, 0, 8) => $expand!(1, 0, 8), + (1, 1, 4) => $expand!(1, 1, 4), + (1, 1, 8) => $expand!(1, 1, 8), + (1, 2, 4) => $expand!(1, 2, 4), + (1, 2, 8) => $expand!(1, 2, 8), + (1, 3, 4) => $expand!(1, 3, 4), + (1, 3, 8) => $expand!(1, 3, 8), + (2, 0, 4) => $expand!(2, 0, 4), + (2, 0, 8) => $expand!(2, 0, 8), + (2, 1, 4) => $expand!(2, 1, 4), + (2, 1, 8) => $expand!(2, 1, 8), + (2, 2, 4) => $expand!(2, 2, 4), + (2, 2, 8) => $expand!(2, 2, 8), + (2, 3, 4) => $expand!(2, 3, 4), + (2, 3, 8) => $expand!(2, 3, 8), + (3, 0, 4) => $expand!(3, 0, 4), + (3, 0, 8) => $expand!(3, 0, 8), + (3, 1, 4) => $expand!(3, 1, 4), + (3, 1, 8) => $expand!(3, 1, 8), + (3, 2, 4) => $expand!(3, 2, 4), + (3, 2, 8) => $expand!(3, 2, 8), + (3, 3, 4) => $expand!(3, 3, 4), + (3, 3, 8) => $expand!(3, 3, 8), + (4, 0, 4) => $expand!(4, 0, 4), + (4, 0, 8) => $expand!(4, 0, 8), + (4, 1, 4) => $expand!(4, 1, 4), + (4, 1, 8) => $expand!(4, 1, 8), + (4, 2, 4) => $expand!(4, 2, 4), + (4, 2, 8) => $expand!(4, 2, 8), + (4, 3, 4) => $expand!(4, 3, 4), + (4, 3, 8) => $expand!(4, 3, 8), + (5, 0, 4) => $expand!(5, 0, 4), + (5, 0, 8) => $expand!(5, 0, 8), + (5, 1, 4) => $expand!(5, 1, 4), + (5, 1, 8) => $expand!(5, 1, 8), + (5, 2, 4) => $expand!(5, 2, 4), + (5, 2, 8) => $expand!(5, 2, 8), + (5, 3, 4) => $expand!(5, 3, 4), + (5, 3, 8) => $expand!(5, 3, 8), + (6, 0, 4) => $expand!(6, 0, 4), + (6, 0, 8) => $expand!(6, 0, 8), + (6, 1, 4) => $expand!(6, 1, 4), + (6, 1, 8) => $expand!(6, 1, 8), + (6, 2, 4) => $expand!(6, 2, 4), + (6, 2, 8) => $expand!(6, 2, 8), + (6, 3, 4) => $expand!(6, 3, 4), + (6, 3, 8) => $expand!(6, 3, 8), + (7, 0, 4) => $expand!(7, 0, 4), + (7, 0, 8) => $expand!(7, 0, 8), + (7, 1, 4) => $expand!(7, 1, 4), + (7, 1, 8) => $expand!(7, 1, 8), + (7, 2, 4) => $expand!(7, 2, 4), + (7, 2, 8) => $expand!(7, 2, 8), + (7, 3, 4) => $expand!(7, 3, 4), + (7, 3, 8) => $expand!(7, 3, 8), + (8, 0, 4) => $expand!(8, 0, 4), + (8, 0, 8) => $expand!(8, 0, 8), + (8, 1, 4) => $expand!(8, 1, 4), + (8, 1, 8) => $expand!(8, 1, 8), + (8, 2, 4) => $expand!(8, 2, 4), + (8, 2, 8) => $expand!(8, 2, 8), + (8, 3, 4) => $expand!(8, 3, 4), + (8, 3, 8) => $expand!(8, 3, 8), + (9, 0, 4) => $expand!(9, 0, 4), + (9, 0, 8) => $expand!(9, 0, 8), + (9, 1, 4) => $expand!(9, 1, 4), + (9, 1, 8) => $expand!(9, 1, 8), + (9, 2, 4) => $expand!(9, 2, 4), + (9, 2, 8) => $expand!(9, 2, 8), + (9, 3, 4) => $expand!(9, 3, 4), + (9, 3, 8) => $expand!(9, 3, 8), + (10, 0, 4) => $expand!(10, 0, 4), + (10, 0, 8) => $expand!(10, 0, 8), + (10, 1, 4) => $expand!(10, 1, 4), + (10, 1, 8) => $expand!(10, 1, 8), + (10, 2, 4) => $expand!(10, 2, 4), + (10, 2, 8) => $expand!(10, 2, 8), + (10, 3, 4) => $expand!(10, 3, 4), + (10, 3, 8) => $expand!(10, 3, 8), + (11, 0, 4) => $expand!(11, 0, 4), + (11, 0, 8) => $expand!(11, 0, 8), + (11, 1, 4) => $expand!(11, 1, 4), + (11, 1, 8) => $expand!(11, 1, 8), + (11, 2, 4) => $expand!(11, 2, 4), + (11, 2, 8) => $expand!(11, 2, 8), + (11, 3, 4) => $expand!(11, 3, 4), + (11, 3, 8) => $expand!(11, 3, 8), + (12, 0, 4) => $expand!(12, 0, 4), + (12, 0, 8) => $expand!(12, 0, 8), + (12, 1, 4) => $expand!(12, 1, 4), + (12, 1, 8) => $expand!(12, 1, 8), + (12, 2, 4) => $expand!(12, 2, 4), + (12, 2, 8) => $expand!(12, 2, 8), + (12, 3, 4) => $expand!(12, 3, 4), + (12, 3, 8) => $expand!(12, 3, 8), + (13, 0, 4) => $expand!(13, 0, 4), + (13, 0, 8) => $expand!(13, 0, 8), + (13, 1, 4) => $expand!(13, 1, 4), + (13, 1, 8) => $expand!(13, 1, 8), + (13, 2, 4) => $expand!(13, 2, 4), + (13, 2, 8) => $expand!(13, 2, 8), + (13, 3, 4) => $expand!(13, 3, 4), + (13, 3, 8) => $expand!(13, 3, 8), + (14, 0, 4) => $expand!(14, 0, 4), + (14, 0, 8) => $expand!(14, 0, 8), + (14, 1, 4) => $expand!(14, 1, 4), + (14, 1, 8) => $expand!(14, 1, 8), + (14, 2, 4) => $expand!(14, 2, 4), + (14, 2, 8) => $expand!(14, 2, 8), + (14, 3, 4) => $expand!(14, 3, 4), + (14, 3, 8) => $expand!(14, 3, 8), + (15, 0, 4) => $expand!(15, 0, 4), + (15, 0, 8) => $expand!(15, 0, 8), + (15, 1, 4) => $expand!(15, 1, 4), + (15, 1, 8) => $expand!(15, 1, 8), + (15, 2, 4) => $expand!(15, 2, 4), + (15, 2, 8) => $expand!(15, 2, 8), + (15, 3, 4) => $expand!(15, 3, 4), + (15, 3, 8) => $expand!(15, 3, 8), + (_, _, _) => panic!("Invalid sae value"), + } + }; +} + +// Constifies 8 bits along with an sae option without rounding control. +// The only valid values are 0 to 255. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm8_sae { + ($imm8:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm8) & 0b1111_1111 { + 0 => $expand!(0), + 1 => $expand!(1), + 2 => $expand!(2), + 3 => $expand!(3), + 4 => $expand!(4), + 5 => $expand!(5), + 6 => $expand!(6), + 7 => $expand!(7), + 8 => $expand!(8), + 9 => $expand!(9), + 10 => $expand!(10), + 11 => $expand!(11), + 12 => $expand!(12), + 13 => $expand!(13), + 14 => $expand!(14), + 15 => $expand!(15), + 16 => $expand!(16), + 17 => $expand!(17), + 18 => $expand!(18), + 19 => $expand!(19), + 20 => $expand!(20), + 21 => $expand!(21), + 22 => $expand!(22), + 23 => $expand!(23), + 24 => $expand!(24), + 25 => $expand!(25), + 26 => $expand!(26), + 27 => $expand!(27), + 28 => $expand!(28), + 29 => $expand!(29), + 30 => $expand!(30), + 31 => $expand!(31), + 32 => $expand!(32), + 33 => $expand!(33), + 34 => $expand!(34), + 35 => $expand!(35), + 36 => $expand!(36), + 37 => $expand!(37), + 38 => $expand!(38), + 39 => $expand!(39), + 40 => $expand!(40), + 41 => $expand!(41), + 42 => $expand!(42), + 43 => $expand!(43), + 44 => $expand!(44), + 45 => $expand!(45), + 46 => $expand!(46), + 47 => $expand!(47), + 48 => $expand!(48), + 49 => $expand!(49), + 50 => $expand!(50), + 51 => $expand!(51), + 52 => $expand!(52), + 53 => $expand!(53), + 54 => $expand!(54), + 55 => $expand!(55), + 56 => $expand!(56), + 57 => $expand!(57), + 58 => $expand!(58), + 59 => $expand!(59), + 60 => $expand!(60), + 61 => $expand!(61), + 62 => $expand!(62), + 63 => $expand!(63), + 64 => $expand!(64), + 65 => $expand!(65), + 66 => $expand!(66), + 67 => $expand!(67), + 68 => $expand!(68), + 69 => $expand!(69), + 70 => $expand!(70), + 71 => $expand!(71), + 72 => $expand!(72), + 73 => $expand!(73), + 74 => $expand!(74), + 75 => $expand!(75), + 76 => $expand!(76), + 77 => $expand!(77), + 78 => $expand!(78), + 79 => $expand!(79), + 80 => $expand!(80), + 81 => $expand!(81), + 82 => $expand!(82), + 83 => $expand!(83), + 84 => $expand!(84), + 85 => $expand!(85), + 86 => $expand!(86), + 87 => $expand!(87), + 88 => $expand!(88), + 89 => $expand!(89), + 90 => $expand!(90), + 91 => $expand!(91), + 92 => $expand!(92), + 93 => $expand!(93), + 94 => $expand!(94), + 95 => $expand!(95), + 96 => $expand!(96), + 97 => $expand!(97), + 98 => $expand!(98), + 99 => $expand!(99), + 100 => $expand!(100), + 101 => $expand!(101), + 102 => $expand!(102), + 103 => $expand!(103), + 104 => $expand!(104), + 105 => $expand!(105), + 106 => $expand!(106), + 107 => $expand!(107), + 108 => $expand!(108), + 109 => $expand!(109), + 110 => $expand!(110), + 111 => $expand!(111), + 112 => $expand!(112), + 113 => $expand!(113), + 114 => $expand!(114), + 115 => $expand!(115), + 116 => $expand!(116), + 117 => $expand!(117), + 118 => $expand!(118), + 119 => $expand!(119), + 120 => $expand!(120), + 121 => $expand!(121), + 122 => $expand!(122), + 123 => $expand!(123), + 124 => $expand!(124), + 125 => $expand!(125), + 126 => $expand!(126), + 127 => $expand!(127), + 128 => $expand!(128), + 129 => $expand!(129), + 130 => $expand!(130), + 131 => $expand!(131), + 132 => $expand!(132), + 133 => $expand!(133), + 134 => $expand!(134), + 135 => $expand!(135), + 136 => $expand!(136), + 137 => $expand!(137), + 138 => $expand!(138), + 139 => $expand!(139), + 140 => $expand!(140), + 141 => $expand!(141), + 142 => $expand!(142), + 143 => $expand!(143), + 144 => $expand!(144), + 145 => $expand!(145), + 146 => $expand!(146), + 147 => $expand!(147), + 148 => $expand!(148), + 149 => $expand!(149), + 150 => $expand!(150), + 151 => $expand!(151), + 152 => $expand!(152), + 153 => $expand!(153), + 154 => $expand!(154), + 155 => $expand!(155), + 156 => $expand!(156), + 157 => $expand!(157), + 158 => $expand!(158), + 159 => $expand!(159), + 160 => $expand!(160), + 161 => $expand!(161), + 162 => $expand!(162), + 163 => $expand!(163), + 164 => $expand!(164), + 165 => $expand!(165), + 166 => $expand!(166), + 167 => $expand!(167), + 168 => $expand!(168), + 169 => $expand!(169), + 170 => $expand!(170), + 171 => $expand!(171), + 172 => $expand!(172), + 173 => $expand!(173), + 174 => $expand!(174), + 175 => $expand!(175), + 176 => $expand!(176), + 177 => $expand!(177), + 178 => $expand!(178), + 179 => $expand!(179), + 180 => $expand!(180), + 181 => $expand!(181), + 182 => $expand!(182), + 183 => $expand!(183), + 184 => $expand!(184), + 185 => $expand!(185), + 186 => $expand!(186), + 187 => $expand!(187), + 188 => $expand!(188), + 189 => $expand!(189), + 190 => $expand!(190), + 191 => $expand!(191), + 192 => $expand!(192), + 193 => $expand!(193), + 194 => $expand!(194), + 195 => $expand!(195), + 196 => $expand!(196), + 197 => $expand!(197), + 198 => $expand!(198), + 199 => $expand!(199), + 200 => $expand!(200), + 201 => $expand!(201), + 202 => $expand!(202), + 203 => $expand!(203), + 204 => $expand!(204), + 205 => $expand!(205), + 206 => $expand!(206), + 207 => $expand!(207), + 208 => $expand!(208), + 209 => $expand!(209), + 210 => $expand!(210), + 211 => $expand!(211), + 212 => $expand!(212), + 213 => $expand!(213), + 214 => $expand!(214), + 215 => $expand!(215), + 216 => $expand!(216), + 217 => $expand!(217), + 218 => $expand!(218), + 219 => $expand!(219), + 220 => $expand!(220), + 221 => $expand!(221), + 222 => $expand!(222), + 223 => $expand!(223), + 224 => $expand!(224), + 225 => $expand!(225), + 226 => $expand!(226), + 227 => $expand!(227), + 228 => $expand!(228), + 229 => $expand!(229), + 230 => $expand!(230), + 231 => $expand!(231), + 232 => $expand!(232), + 233 => $expand!(233), + 234 => $expand!(234), + 235 => $expand!(235), + 236 => $expand!(236), + 237 => $expand!(237), + 238 => $expand!(238), + 239 => $expand!(239), + 240 => $expand!(240), + 241 => $expand!(241), + 242 => $expand!(242), + 243 => $expand!(243), + 244 => $expand!(244), + 245 => $expand!(245), + 246 => $expand!(246), + 247 => $expand!(247), + 248 => $expand!(248), + 249 => $expand!(249), + 250 => $expand!(250), + 251 => $expand!(251), + 252 => $expand!(252), + 253 => $expand!(253), + 254 => $expand!(254), + 255 => $expand!(255), + _ => panic!("Invalid sae value"), + } + }; +} + #[cfg(test)] macro_rules! assert_approx_eq { ($a:expr, $b:expr, $eps:expr) => {{ diff --git a/library/stdarch/crates/core_arch/src/x86/mmx.rs b/library/stdarch/crates/core_arch/src/x86/mmx.rs deleted file mode 100644 index 3947f2bea6..0000000000 --- a/library/stdarch/crates/core_arch/src/x86/mmx.rs +++ /dev/null @@ -1,786 +0,0 @@ -//! `i586` MMX instruction set. -//! -//! The intrinsics here roughly correspond to those in the `mmintrin.h` C -//! header. -//! -//! The reference is [Intel 64 and IA-32 Architectures Software Developer's -//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref]. -//! -//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf - -use crate::{ - core_arch::{simd::*, x86::*}, - mem::transmute, -}; - -#[cfg(test)] -use stdarch_test::assert_instr; - -/// Constructs a 64-bit integer vector initialized to zero. -#[inline] -#[target_feature(enable = "mmx")] -// FIXME: this produces a movl instead of xorps on x86 -// FIXME: this produces a xor intrinsic instead of xorps on x86_64 -#[cfg_attr(all(test, target_arch = "x86_64"), assert_instr(xor))] -pub unsafe fn _mm_setzero_si64() -> __m64 { - transmute(0_i64) -} - -/// Adds packed 8-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddb))] -pub unsafe fn _mm_add_pi8(a: __m64, b: __m64) -> __m64 { - paddb(a, b) -} - -/// Adds packed 8-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddb))] -pub unsafe fn _m_paddb(a: __m64, b: __m64) -> __m64 { - _mm_add_pi8(a, b) -} - -/// Adds packed 16-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddw))] -pub unsafe fn _mm_add_pi16(a: __m64, b: __m64) -> __m64 { - paddw(a, b) -} - -/// Adds packed 16-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddw))] -pub unsafe fn _m_paddw(a: __m64, b: __m64) -> __m64 { - _mm_add_pi16(a, b) -} - -/// Adds packed 32-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddd))] -pub unsafe fn _mm_add_pi32(a: __m64, b: __m64) -> __m64 { - paddd(a, b) -} - -/// Adds packed 32-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddd))] -pub unsafe fn _m_paddd(a: __m64, b: __m64) -> __m64 { - _mm_add_pi32(a, b) -} - -/// Adds packed 8-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddsb))] -pub unsafe fn _mm_adds_pi8(a: __m64, b: __m64) -> __m64 { - paddsb(a, b) -} - -/// Adds packed 8-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddsb))] -pub unsafe fn _m_paddsb(a: __m64, b: __m64) -> __m64 { - _mm_adds_pi8(a, b) -} - -/// Adds packed 16-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddsw))] -pub unsafe fn _mm_adds_pi16(a: __m64, b: __m64) -> __m64 { - paddsw(a, b) -} - -/// Adds packed 16-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddsw))] -pub unsafe fn _m_paddsw(a: __m64, b: __m64) -> __m64 { - _mm_adds_pi16(a, b) -} - -/// Adds packed unsigned 8-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddusb))] -pub unsafe fn _mm_adds_pu8(a: __m64, b: __m64) -> __m64 { - paddusb(a, b) -} - -/// Adds packed unsigned 8-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddusb))] -pub unsafe fn _m_paddusb(a: __m64, b: __m64) -> __m64 { - _mm_adds_pu8(a, b) -} - -/// Adds packed unsigned 16-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddusw))] -pub unsafe fn _mm_adds_pu16(a: __m64, b: __m64) -> __m64 { - paddusw(a, b) -} - -/// Adds packed unsigned 16-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddusw))] -pub unsafe fn _m_paddusw(a: __m64, b: __m64) -> __m64 { - _mm_adds_pu16(a, b) -} - -/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubb))] -pub unsafe fn _mm_sub_pi8(a: __m64, b: __m64) -> __m64 { - psubb(a, b) -} - -/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubb))] -pub unsafe fn _m_psubb(a: __m64, b: __m64) -> __m64 { - _mm_sub_pi8(a, b) -} - -/// Subtract packed 16-bit integers in `b` from packed 16-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubw))] -pub unsafe fn _mm_sub_pi16(a: __m64, b: __m64) -> __m64 { - psubw(a, b) -} - -/// Subtract packed 16-bit integers in `b` from packed 16-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubw))] -pub unsafe fn _m_psubw(a: __m64, b: __m64) -> __m64 { - _mm_sub_pi16(a, b) -} - -/// Subtract packed 32-bit integers in `b` from packed 32-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubd))] -pub unsafe fn _mm_sub_pi32(a: __m64, b: __m64) -> __m64 { - psubd(a, b) -} - -/// Subtract packed 32-bit integers in `b` from packed 32-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubd))] -pub unsafe fn _m_psubd(a: __m64, b: __m64) -> __m64 { - _mm_sub_pi32(a, b) -} - -/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a` -/// using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubsb))] -pub unsafe fn _mm_subs_pi8(a: __m64, b: __m64) -> __m64 { - psubsb(a, b) -} - -/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a` -/// using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubsb))] -pub unsafe fn _m_psubsb(a: __m64, b: __m64) -> __m64 { - _mm_subs_pi8(a, b) -} - -/// Subtract packed 16-bit integers in `b` from packed 16-bit integers in `a` -/// using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubsw))] -pub unsafe fn _mm_subs_pi16(a: __m64, b: __m64) -> __m64 { - psubsw(a, b) -} - -/// Subtract packed 16-bit integers in `b` from packed 16-bit integers in `a` -/// using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubsw))] -pub unsafe fn _m_psubsw(a: __m64, b: __m64) -> __m64 { - _mm_subs_pi16(a, b) -} - -/// Subtract packed unsigned 8-bit integers in `b` from packed unsigned 8-bit -/// integers in `a` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubusb))] -pub unsafe fn _mm_subs_pu8(a: __m64, b: __m64) -> __m64 { - psubusb(a, b) -} - -/// Subtract packed unsigned 8-bit integers in `b` from packed unsigned 8-bit -/// integers in `a` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubusb))] -pub unsafe fn _m_psubusb(a: __m64, b: __m64) -> __m64 { - _mm_subs_pu8(a, b) -} - -/// Subtract packed unsigned 16-bit integers in `b` from packed unsigned -/// 16-bit integers in `a` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubusw))] -pub unsafe fn _mm_subs_pu16(a: __m64, b: __m64) -> __m64 { - psubusw(a, b) -} - -/// Subtract packed unsigned 16-bit integers in `b` from packed unsigned -/// 16-bit integers in `a` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubusw))] -pub unsafe fn _m_psubusw(a: __m64, b: __m64) -> __m64 { - _mm_subs_pu16(a, b) -} - -/// Converts packed 16-bit integers from `a` and `b` to packed 8-bit integers -/// using signed saturation. -/// -/// Positive values greater than 0x7F are saturated to 0x7F. Negative values -/// less than 0x80 are saturated to 0x80. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(packsswb))] -pub unsafe fn _mm_packs_pi16(a: __m64, b: __m64) -> __m64 { - packsswb(a, b) -} - -/// Converts packed 32-bit integers from `a` and `b` to packed 16-bit integers -/// using signed saturation. -/// -/// Positive values greater than 0x7F are saturated to 0x7F. Negative values -/// less than 0x80 are saturated to 0x80. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(packssdw))] -pub unsafe fn _mm_packs_pi32(a: __m64, b: __m64) -> __m64 { - packssdw(a, b) -} - -/// Compares whether each element of `a` is greater than the corresponding -/// element of `b` returning `0` for `false` and `-1` for `true`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(pcmpgtb))] -pub unsafe fn _mm_cmpgt_pi8(a: __m64, b: __m64) -> __m64 { - pcmpgtb(a, b) -} - -/// Compares whether each element of `a` is greater than the corresponding -/// element of `b` returning `0` for `false` and `-1` for `true`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(pcmpgtw))] -pub unsafe fn _mm_cmpgt_pi16(a: __m64, b: __m64) -> __m64 { - pcmpgtw(a, b) -} - -/// Compares whether each element of `a` is greater than the corresponding -/// element of `b` returning `0` for `false` and `-1` for `true`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(pcmpgtd))] -pub unsafe fn _mm_cmpgt_pi32(a: __m64, b: __m64) -> __m64 { - pcmpgtd(a, b) -} - -/// Unpacks the upper two elements from two `i16x4` vectors and interleaves -/// them into the result: `[a.2, b.2, a.3, b.3]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpckhwd))] // FIXME punpcklbw expected -pub unsafe fn _mm_unpackhi_pi16(a: __m64, b: __m64) -> __m64 { - punpckhwd(a, b) -} - -/// Unpacks the upper four elements from two `i8x8` vectors and interleaves -/// them into the result: `[a.4, b.4, a.5, b.5, a.6, b.6, a.7, b.7]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpckhbw))] -pub unsafe fn _mm_unpackhi_pi8(a: __m64, b: __m64) -> __m64 { - punpckhbw(a, b) -} - -/// Unpacks the lower four elements from two `i8x8` vectors and interleaves -/// them into the result: `[a.0, b.0, a.1, b.1, a.2, b.2, a.3, b.3]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpcklbw))] -pub unsafe fn _mm_unpacklo_pi8(a: __m64, b: __m64) -> __m64 { - punpcklbw(a, b) -} - -/// Unpacks the lower two elements from two `i16x4` vectors and interleaves -/// them into the result: `[a.0 b.0 a.1 b.1]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpcklwd))] -pub unsafe fn _mm_unpacklo_pi16(a: __m64, b: __m64) -> __m64 { - punpcklwd(a, b) -} - -/// Unpacks the upper element from two `i32x2` vectors and interleaves them -/// into the result: `[a.1, b.1]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpckhdq))] -pub unsafe fn _mm_unpackhi_pi32(a: __m64, b: __m64) -> __m64 { - punpckhdq(a, b) -} - -/// Unpacks the lower element from two `i32x2` vectors and interleaves them -/// into the result: `[a.0, b.0]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpckldq))] -pub unsafe fn _mm_unpacklo_pi32(a: __m64, b: __m64) -> __m64 { - punpckldq(a, b) -} - -/// Sets packed 16-bit integers in dst with the supplied values. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set_pi16(e3: i16, e2: i16, e1: i16, e0: i16) -> __m64 { - _mm_setr_pi16(e0, e1, e2, e3) -} - -/// Sets packed 32-bit integers in dst with the supplied values. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set_pi32(e1: i32, e0: i32) -> __m64 { - _mm_setr_pi32(e0, e1) -} - -/// Sets packed 8-bit integers in dst with the supplied values. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set_pi8(e7: i8, e6: i8, e5: i8, e4: i8, e3: i8, e2: i8, e1: i8, e0: i8) -> __m64 { - _mm_setr_pi8(e0, e1, e2, e3, e4, e5, e6, e7) -} - -/// Broadcasts 16-bit integer a to all all elements of dst. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set1_pi16(a: i16) -> __m64 { - _mm_setr_pi16(a, a, a, a) -} - -/// Broadcasts 32-bit integer a to all all elements of dst. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set1_pi32(a: i32) -> __m64 { - _mm_setr_pi32(a, a) -} - -/// Broadcasts 8-bit integer a to all all elements of dst. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set1_pi8(a: i8) -> __m64 { - _mm_setr_pi8(a, a, a, a, a, a, a, a) -} - -/// Sets packed 16-bit integers in dst with the supplied values in reverse -/// order. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_setr_pi16(e0: i16, e1: i16, e2: i16, e3: i16) -> __m64 { - transmute(i16x4::new(e0, e1, e2, e3)) -} - -/// Sets packed 32-bit integers in dst with the supplied values in reverse -/// order. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_setr_pi32(e0: i32, e1: i32) -> __m64 { - transmute(i32x2::new(e0, e1)) -} - -/// Sets packed 8-bit integers in dst with the supplied values in reverse order. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_setr_pi8( - e0: i8, - e1: i8, - e2: i8, - e3: i8, - e4: i8, - e5: i8, - e6: i8, - e7: i8, -) -> __m64 { - transmute(i8x8::new(e0, e1, e2, e3, e4, e5, e6, e7)) -} - -/// Empty the MMX state, which marks the x87 FPU registers as available for use -/// by x87 instructions. This instruction must be used at the end of all MMX -/// technology procedures. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(emms))] -pub unsafe fn _mm_empty() { - emms() -} - -/// Empty the MMX state, which marks the x87 FPU registers as available for use -/// by x87 instructions. This instruction must be used at the end of all MMX -/// technology procedures. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(emms))] -pub unsafe fn _m_empty() { - emms() -} - -/// Copies 32-bit integer `a` to the lower elements of the return value, and zero -/// the upper element of the return value. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_cvtsi32_si64(a: i32) -> __m64 { - transmute(i32x2::new(a, 0)) -} - -/// Return the lower 32-bit integer in `a`. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_cvtsi64_si32(a: __m64) -> i32 { - let r: i32x2 = transmute(a); - r.0 -} - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.x86.mmx.padd.b"] - fn paddb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.padd.w"] - fn paddw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.padd.d"] - fn paddd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.padds.b"] - fn paddsb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.padds.w"] - fn paddsw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.paddus.b"] - fn paddusb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.paddus.w"] - fn paddusw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psub.b"] - fn psubb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psub.w"] - fn psubw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psub.d"] - fn psubd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psubs.b"] - fn psubsb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psubs.w"] - fn psubsw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psubus.b"] - fn psubusb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psubus.w"] - fn psubusw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.packsswb"] - fn packsswb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.packssdw"] - fn packssdw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pcmpgt.b"] - fn pcmpgtb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pcmpgt.w"] - fn pcmpgtw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pcmpgt.d"] - fn pcmpgtd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpckhwd"] - fn punpckhwd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpcklwd"] - fn punpcklwd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpckhbw"] - fn punpckhbw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpcklbw"] - fn punpcklbw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpckhdq"] - fn punpckhdq(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpckldq"] - fn punpckldq(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.emms"] - fn emms(); -} - -#[cfg(test)] -mod tests { - use crate::core_arch::x86::*; - use stdarch_test::simd_test; - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_setzero_si64() { - let r: __m64 = transmute(0_i64); - assert_eq_m64(r, _mm_setzero_si64()); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_add_pi8() { - let a = _mm_setr_pi8(-1, -1, 1, 1, -1, 0, 1, 0); - let b = _mm_setr_pi8(-127, 101, 99, 126, 0, -1, 0, 1); - let e = _mm_setr_pi8(-128, 100, 100, 127, -1, -1, 1, 1); - assert_eq_m64(e, _mm_add_pi8(a, b)); - assert_eq_m64(e, _m_paddb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_add_pi16() { - let a = _mm_setr_pi16(-1, -1, 1, 1); - let b = _mm_setr_pi16(i16::MIN + 1, 30001, -30001, i16::MAX - 1); - let e = _mm_setr_pi16(i16::MIN, 30000, -30000, i16::MAX); - assert_eq_m64(e, _mm_add_pi16(a, b)); - assert_eq_m64(e, _m_paddw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_add_pi32() { - let a = _mm_setr_pi32(1, -1); - let b = _mm_setr_pi32(i32::MAX - 1, i32::MIN + 1); - let e = _mm_setr_pi32(i32::MAX, i32::MIN); - assert_eq_m64(e, _mm_add_pi32(a, b)); - assert_eq_m64(e, _m_paddd(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_adds_pi8() { - let a = _mm_setr_pi8(-100, -1, 1, 100, -1, 0, 1, 0); - let b = _mm_setr_pi8(-100, 1, -1, 100, 0, -1, 0, 1); - let e = _mm_setr_pi8(i8::MIN, 0, 0, i8::MAX, -1, -1, 1, 1); - assert_eq_m64(e, _mm_adds_pi8(a, b)); - assert_eq_m64(e, _m_paddsb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_adds_pi16() { - let a = _mm_setr_pi16(-32000, 32000, 4, 0); - let b = _mm_setr_pi16(-32000, 32000, -5, 1); - let e = _mm_setr_pi16(i16::MIN, i16::MAX, -1, 1); - assert_eq_m64(e, _mm_adds_pi16(a, b)); - assert_eq_m64(e, _m_paddsw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_adds_pu8() { - let a = _mm_setr_pi8(0, 1, 2, 3, 4, 5, 6, 200u8 as i8); - let b = _mm_setr_pi8(0, 10, 20, 30, 40, 50, 60, 200u8 as i8); - let e = _mm_setr_pi8(0, 11, 22, 33, 44, 55, 66, u8::MAX as i8); - assert_eq_m64(e, _mm_adds_pu8(a, b)); - assert_eq_m64(e, _m_paddusb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_adds_pu16() { - let a = _mm_setr_pi16(0, 1, 2, 60000u16 as i16); - let b = _mm_setr_pi16(0, 10, 20, 60000u16 as i16); - let e = _mm_setr_pi16(0, 11, 22, u16::MAX as i16); - assert_eq_m64(e, _mm_adds_pu16(a, b)); - assert_eq_m64(e, _m_paddusw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_sub_pi8() { - let a = _mm_setr_pi8(0, 0, 1, 1, -1, -1, 0, 0); - let b = _mm_setr_pi8(-1, 1, -2, 2, 100, -100, -127, 127); - let e = _mm_setr_pi8(1, -1, 3, -1, -101, 99, 127, -127); - assert_eq_m64(e, _mm_sub_pi8(a, b)); - assert_eq_m64(e, _m_psubb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_sub_pi16() { - let a = _mm_setr_pi16(-20000, -20000, 20000, 30000); - let b = _mm_setr_pi16(-10000, 10000, -10000, 30000); - let e = _mm_setr_pi16(-10000, -30000, 30000, 0); - assert_eq_m64(e, _mm_sub_pi16(a, b)); - assert_eq_m64(e, _m_psubw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_sub_pi32() { - let a = _mm_setr_pi32(500_000, -500_000); - let b = _mm_setr_pi32(500_000, 500_000); - let e = _mm_setr_pi32(0, -1_000_000); - assert_eq_m64(e, _mm_sub_pi32(a, b)); - assert_eq_m64(e, _m_psubd(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_subs_pi8() { - let a = _mm_setr_pi8(-100, 100, 0, 0, 0, 0, -5, 5); - let b = _mm_setr_pi8(100, -100, i8::MIN, 127, -1, 1, 3, -3); - let e = _mm_setr_pi8(i8::MIN, i8::MAX, i8::MAX, -127, 1, -1, -8, 8); - assert_eq_m64(e, _mm_subs_pi8(a, b)); - assert_eq_m64(e, _m_psubsb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_subs_pi16() { - let a = _mm_setr_pi16(-20000, 20000, 0, 0); - let b = _mm_setr_pi16(20000, -20000, -1, 1); - let e = _mm_setr_pi16(i16::MIN, i16::MAX, 1, -1); - assert_eq_m64(e, _mm_subs_pi16(a, b)); - assert_eq_m64(e, _m_psubsw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_subs_pu8() { - let a = _mm_setr_pi8(50, 10, 20, 30, 40, 60, 70, 80); - let b = _mm_setr_pi8(60, 20, 30, 40, 30, 20, 10, 0); - let e = _mm_setr_pi8(0, 0, 0, 0, 10, 40, 60, 80); - assert_eq_m64(e, _mm_subs_pu8(a, b)); - assert_eq_m64(e, _m_psubusb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_subs_pu16() { - let a = _mm_setr_pi16(10000, 200, 0, 44444u16 as i16); - let b = _mm_setr_pi16(20000, 300, 1, 11111); - let e = _mm_setr_pi16(0, 0, 0, 33333u16 as i16); - assert_eq_m64(e, _mm_subs_pu16(a, b)); - assert_eq_m64(e, _m_psubusw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_packs_pi16() { - let a = _mm_setr_pi16(-1, 2, -3, 4); - let b = _mm_setr_pi16(-5, 6, -7, 8); - let r = _mm_setr_pi8(-1, 2, -3, 4, -5, 6, -7, 8); - assert_eq_m64(r, _mm_packs_pi16(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_packs_pi32() { - let a = _mm_setr_pi32(-1, 2); - let b = _mm_setr_pi32(-5, 6); - let r = _mm_setr_pi16(-1, 2, -5, 6); - assert_eq_m64(r, _mm_packs_pi32(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cmpgt_pi8() { - let a = _mm_setr_pi8(0, 1, 2, 3, 4, 5, 6, 7); - let b = _mm_setr_pi8(8, 7, 6, 5, 4, 3, 2, 1); - let r = _mm_setr_pi8(0, 0, 0, 0, 0, -1, -1, -1); - assert_eq_m64(r, _mm_cmpgt_pi8(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cmpgt_pi16() { - let a = _mm_setr_pi16(0, 1, 2, 3); - let b = _mm_setr_pi16(4, 3, 2, 1); - let r = _mm_setr_pi16(0, 0, 0, -1); - assert_eq_m64(r, _mm_cmpgt_pi16(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cmpgt_pi32() { - let a = _mm_setr_pi32(0, 3); - let b = _mm_setr_pi32(1, 2); - let r0 = _mm_setr_pi32(0, -1); - let r1 = _mm_setr_pi32(-1, 0); - - assert_eq_m64(r0, _mm_cmpgt_pi32(a, b)); - assert_eq_m64(r1, _mm_cmpgt_pi32(b, a)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpackhi_pi8() { - let a = _mm_setr_pi8(0, 3, 4, 7, 8, 11, 12, 15); - let b = _mm_setr_pi8(1, 2, 5, 6, 9, 10, 13, 14); - let r = _mm_setr_pi8(8, 9, 11, 10, 12, 13, 15, 14); - - assert_eq_m64(r, _mm_unpackhi_pi8(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpacklo_pi8() { - let a = _mm_setr_pi8(0, 1, 2, 3, 4, 5, 6, 7); - let b = _mm_setr_pi8(8, 9, 10, 11, 12, 13, 14, 15); - let r = _mm_setr_pi8(0, 8, 1, 9, 2, 10, 3, 11); - assert_eq_m64(r, _mm_unpacklo_pi8(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpackhi_pi16() { - let a = _mm_setr_pi16(0, 1, 2, 3); - let b = _mm_setr_pi16(4, 5, 6, 7); - let r = _mm_setr_pi16(2, 6, 3, 7); - assert_eq_m64(r, _mm_unpackhi_pi16(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpacklo_pi16() { - let a = _mm_setr_pi16(0, 1, 2, 3); - let b = _mm_setr_pi16(4, 5, 6, 7); - let r = _mm_setr_pi16(0, 4, 1, 5); - assert_eq_m64(r, _mm_unpacklo_pi16(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpackhi_pi32() { - let a = _mm_setr_pi32(0, 3); - let b = _mm_setr_pi32(1, 2); - let r = _mm_setr_pi32(3, 2); - - assert_eq_m64(r, _mm_unpackhi_pi32(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpacklo_pi32() { - let a = _mm_setr_pi32(0, 3); - let b = _mm_setr_pi32(1, 2); - let r = _mm_setr_pi32(0, 1); - - assert_eq_m64(r, _mm_unpacklo_pi32(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_empty() { - _mm_empty(); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_m_empty() { - _m_empty(); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cvtsi32_si64() { - let a = _mm_cvtsi32_si64(42); - let b = _mm_setr_pi32(42, 0); - assert_eq_m64(a, b); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cvtsi64_si32() { - let a = _mm_setr_pi32(42, 666); - let b = _mm_cvtsi64_si32(a); - assert_eq!(b, 42); - } -} diff --git a/library/stdarch/crates/core_arch/src/x86/mod.rs b/library/stdarch/crates/core_arch/src/x86/mod.rs index 60eb890c2f..abe99f23a2 100644 --- a/library/stdarch/crates/core_arch/src/x86/mod.rs +++ b/library/stdarch/crates/core_arch/src/x86/mod.rs @@ -6,50 +6,6 @@ use crate::{intrinsics, marker::Sized, mem::transmute}; mod macros; types! { - /// 64-bit wide integer vector type, x86-specific - /// - /// This type is the same as the `__m64` type defined by Intel, - /// representing a 64-bit SIMD register. Usage of this type typically - /// corresponds to the `mmx` target feature. - /// - /// Internally this type may be viewed as: - /// - /// * `i8x8` - eight `i8` variables packed together - /// * `i16x4` - four `i16` variables packed together - /// * `i32x2` - two `i32` variables packed together - /// - /// (as well as unsigned versions). Each intrinsic may interpret the - /// internal bits differently, check the documentation of the intrinsic - /// to see how it's being used. - /// - /// Note that this means that an instance of `__m64` typically just means - /// a "bag of bits" which is left up to interpretation at the point of use. - /// - /// Most intrinsics using `__m64` are prefixed with `_mm_` and the - /// integer types tend to correspond to suffixes like "pi8" or "pi32" (not - /// to be confused with "epiXX", used for `__m128i`). - /// - /// # Examples - /// - /// ``` - /// # #![feature(stdsimd, mmx_target_feature)] - /// #[cfg(target_arch = "x86")] - /// use std::arch::x86::*; - /// #[cfg(target_arch = "x86_64")] - /// use std::arch::x86_64::*; - /// - /// # fn main() { - /// # #[target_feature(enable = "mmx")] - /// # unsafe fn foo() { - /// let all_bytes_zero = _mm_setzero_si64(); - /// let all_bytes_one = _mm_set1_pi8(1); - /// let two_i32 = _mm_set_pi32(1, 2); - /// # } - /// # if is_x86_feature_detected!("mmx") { unsafe { foo() } } - /// # } - /// ``` - pub struct __m64(i64); - /// 128-bit wide integer vector type, x86-specific /// /// This type is the same as the `__m128i` type defined by Intel, @@ -354,56 +310,25 @@ pub type __mmask8 = u8; #[allow(non_camel_case_types)] pub type _MM_CMPINT_ENUM = i32; -#[cfg(test)] -mod test; -#[cfg(test)] -pub use self::test::*; - +/// The `MM_MANTISSA_NORM_ENUM` type used to specify mantissa normalized operations in AVX-512 intrinsics. #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] -pub(crate) trait m64Ext: Sized { - fn as_m64(self) -> __m64; - - #[inline] - fn as_u8x8(self) -> crate::core_arch::simd::u8x8 { - unsafe { transmute(self.as_m64()) } - } +pub type _MM_MANTISSA_NORM_ENUM = i32; - #[inline] - fn as_u16x4(self) -> crate::core_arch::simd::u16x4 { - unsafe { transmute(self.as_m64()) } - } - - #[inline] - fn as_u32x2(self) -> crate::core_arch::simd::u32x2 { - unsafe { transmute(self.as_m64()) } - } - - #[inline] - fn as_i8x8(self) -> crate::core_arch::simd::i8x8 { - unsafe { transmute(self.as_m64()) } - } - - #[inline] - fn as_i16x4(self) -> crate::core_arch::simd::i16x4 { - unsafe { transmute(self.as_m64()) } - } +/// The `MM_MANTISSA_SIGN_ENUM` type used to specify mantissa signed operations in AVX-512 intrinsics. +#[allow(non_camel_case_types)] +pub type _MM_MANTISSA_SIGN_ENUM = i32; - #[inline] - fn as_i32x2(self) -> crate::core_arch::simd::i32x2 { - unsafe { transmute(self.as_m64()) } - } -} +/// The `MM_PERM_ENUM` type used to specify shuffle operations in AVX-512 intrinsics. +#[allow(non_camel_case_types)] +pub type _MM_PERM_ENUM = i32; -impl m64Ext for __m64 { - #[inline] - fn as_m64(self) -> Self { - self - } -} +#[cfg(test)] +mod test; +#[cfg(test)] +pub use self::test::*; #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m128iExt: Sized { fn as_m128i(self) -> __m128i; @@ -456,7 +381,7 @@ impl m128iExt for __m128i { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m256iExt: Sized { fn as_m256i(self) -> __m256i; @@ -509,7 +434,7 @@ impl m256iExt for __m256i { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m256Ext: Sized { fn as_m256(self) -> __m256; @@ -527,7 +452,7 @@ impl m256Ext for __m256 { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m512iExt: Sized { fn as_m512i(self) -> __m512i; @@ -560,7 +485,7 @@ impl m512iExt for __m512i { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m512Ext: Sized { fn as_m512(self) -> __m512; @@ -578,7 +503,7 @@ impl m512Ext for __m512 { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m512dExt: Sized { fn as_m512d(self) -> __m512d; @@ -649,9 +574,6 @@ mod tbm; #[cfg(not(stdarch_intel_sde))] pub use self::tbm::*; -mod mmx; -pub use self::mmx::*; - mod pclmulqdq; pub use self::pclmulqdq::*; diff --git a/library/stdarch/crates/core_arch/src/x86/sse.rs b/library/stdarch/crates/core_arch/src/x86/sse.rs index c01aa1bc9f..ba3efae3c9 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse.rs @@ -1115,33 +1115,6 @@ pub unsafe fn _mm_movemask_ps(a: __m128) -> i32 { movmskps(a) } -/// Sets the upper two single-precision floating-point values with 64 bits of -/// data loaded from the address `p`; the lower two values are passed through -/// from `a`. -#[inline] -#[target_feature(enable = "sse")] -#[cfg_attr(test, assert_instr(movhps))] -// TODO: this function is actually not limited to floats, but that's what -// what matches the C type most closely: `(__m128, *const __m64) -> __m128`. -pub unsafe fn _mm_loadh_pi(a: __m128, p: *const __m64) -> __m128 { - let q = p as *const f32x2; - let b: f32x2 = *q; - let bb = simd_shuffle4(b, b, [0, 1, 0, 1]); - simd_shuffle4(a, bb, [0, 1, 4, 5]) -} - -/// Loads two floats from `p` into the lower half of a `__m128`. The upper half -/// is copied from the upper half of `a`. -#[inline] -#[target_feature(enable = "sse")] -#[cfg_attr(test, assert_instr(movlps))] -pub unsafe fn _mm_loadl_pi(a: __m128, p: *const __m64) -> __m128 { - let q = p as *const f32x2; - let b: f32x2 = *q; - let bb = simd_shuffle4(b, b, [0, 1, 0, 1]); - simd_shuffle4(a, bb, [4, 5, 2, 3]) -} - /// Construct a `__m128` with the lowest element read from `p` and the other /// elements set to zero. /// @@ -1270,72 +1243,6 @@ pub unsafe fn _mm_loadu_si64(mem_addr: *const u8) -> __m128i { transmute(i64x2(0, ptr::read_unaligned(mem_addr as *const i64))) } -/// Stores the upper half of `a` (64 bits) into memory. -/// -/// This intrinsic corresponds to the `MOVHPS` instruction. The compiler may -/// choose to generate an equivalent sequence of other instructions. -#[inline] -#[target_feature(enable = "sse")] -// On i686 and up LLVM actually generates MOVHPD instead of MOVHPS, that's -// fine. -// On i586 (no SSE2) it just generates plain MOV instructions. -#[cfg_attr( - all(test, any(target_arch = "x86_64", target_feature = "sse2"), - not(target_os = "windows")), - // assert_instr(movhpd) - assert_instr(movhps) // LLVM7 prefers single-precision instructions -)] -pub unsafe fn _mm_storeh_pi(p: *mut __m64, a: __m128) { - #[cfg(target_arch = "x86")] - { - // If this is a `f64x2` then on i586, LLVM generates fldl & fstpl which - // is just silly - let a64: u64x2 = mem::transmute(a); - let a_hi = a64.extract(1); - *(p as *mut u64) = a_hi; - } - #[cfg(target_arch = "x86_64")] - { - // If this is a `u64x2` LLVM generates a pshufd + movq, but we really - // want a a MOVHPD or MOVHPS here. - let a64: f64x2 = mem::transmute(a); - let a_hi = a64.extract(1); - *p = mem::transmute(a_hi); - } -} - -/// Stores the lower half of `a` (64 bits) into memory. -/// -/// This intrinsic corresponds to the `MOVQ` instruction. The compiler may -/// choose to generate an equivalent sequence of other instructions. -#[inline] -#[target_feature(enable = "sse")] -// On i586 the codegen just generates plane MOVs. No need to test for that. -#[cfg_attr( - all( - test, - any(target_arch = "x86_64", target_feature = "sse2"), - not(target_os = "windows") - ), - assert_instr(movlps) -)] -pub unsafe fn _mm_storel_pi(p: *mut __m64, a: __m128) { - #[cfg(target_arch = "x86")] - { - // Same as for _mm_storeh_pi: i586 code gen would use floating point - // stack. - let a64: u64x2 = mem::transmute(a); - let a_hi = a64.extract(0); - *(p as *mut u64) = a_hi; - } - #[cfg(target_arch = "x86_64")] - { - let a64: f64x2 = mem::transmute(a); - let a_hi = a64.extract(0); - *p = mem::transmute(a_hi); - } -} - /// Stores the lowest 32 bit float of `a` into memory. /// /// This intrinsic corresponds to the `MOVSS` instruction. @@ -1985,42 +1892,6 @@ extern "C" { fn prefetch(p: *const i8, rw: i32, loc: i32, ty: i32); #[link_name = "llvm.x86.sse.cmp.ss"] fn cmpss(a: __m128, b: __m128, imm8: i8) -> __m128; - #[link_name = "llvm.x86.mmx.movnt.dq"] - fn movntdq(a: *mut __m64, b: __m64); - #[link_name = "llvm.x86.sse.cvtpi2ps"] - fn cvtpi2ps(a: __m128, b: __m64) -> __m128; - #[link_name = "llvm.x86.mmx.maskmovq"] - fn maskmovq(a: __m64, mask: __m64, mem_addr: *mut i8); - #[link_name = "llvm.x86.mmx.pextr.w"] - fn pextrw(a: __m64, imm8: i32) -> i32; - #[link_name = "llvm.x86.mmx.pinsr.w"] - fn pinsrw(a: __m64, d: i32, imm8: i32) -> __m64; - #[link_name = "llvm.x86.mmx.pmovmskb"] - fn pmovmskb(a: __m64) -> i32; - #[link_name = "llvm.x86.sse.pshuf.w"] - fn pshufw(a: __m64, imm8: i8) -> __m64; - #[link_name = "llvm.x86.mmx.pmaxs.w"] - fn pmaxsw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmaxu.b"] - fn pmaxub(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmins.w"] - fn pminsw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pminu.b"] - fn pminub(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmulhu.w"] - fn pmulhuw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmull.w"] - fn pmullw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pavg.b"] - fn pavgb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pavg.w"] - fn pavgw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psad.bw"] - fn psadbw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.sse.cvtps2pi"] - fn cvtps2pi(a: __m128) -> __m64; - #[link_name = "llvm.x86.sse.cvttps2pi"] - fn cvttps2pi(a: __m128) -> __m64; } /// Stores `a` into the memory at `mem_addr` using a non-temporal memory hint. @@ -2038,463 +1909,6 @@ pub unsafe fn _mm_stream_ps(mem_addr: *mut f32, a: __m128) { intrinsics::nontemporal_store(mem_addr as *mut __m128, a); } -/// Stores 64-bits of integer data from a into memory using a non-temporal -/// memory hint. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(movntq))] -pub unsafe fn _mm_stream_pi(mem_addr: *mut __m64, a: __m64) { - movntdq(mem_addr, a) -} - -/// Compares the packed 16-bit signed integers of `a` and `b` writing the -/// greatest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmaxsw))] -pub unsafe fn _mm_max_pi16(a: __m64, b: __m64) -> __m64 { - pmaxsw(a, b) -} - -/// Compares the packed 16-bit signed integers of `a` and `b` writing the -/// greatest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmaxsw))] -pub unsafe fn _m_pmaxsw(a: __m64, b: __m64) -> __m64 { - _mm_max_pi16(a, b) -} - -/// Compares the packed 8-bit signed integers of `a` and `b` writing the -/// greatest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmaxub))] -pub unsafe fn _mm_max_pu8(a: __m64, b: __m64) -> __m64 { - pmaxub(a, b) -} - -/// Compares the packed 8-bit signed integers of `a` and `b` writing the -/// greatest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmaxub))] -pub unsafe fn _m_pmaxub(a: __m64, b: __m64) -> __m64 { - _mm_max_pu8(a, b) -} - -/// Compares the packed 16-bit signed integers of `a` and `b` writing the -/// smallest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pminsw))] -pub unsafe fn _mm_min_pi16(a: __m64, b: __m64) -> __m64 { - pminsw(a, b) -} - -/// Compares the packed 16-bit signed integers of `a` and `b` writing the -/// smallest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pminsw))] -pub unsafe fn _m_pminsw(a: __m64, b: __m64) -> __m64 { - _mm_min_pi16(a, b) -} - -/// Compares the packed 8-bit signed integers of `a` and `b` writing the -/// smallest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pminub))] -pub unsafe fn _mm_min_pu8(a: __m64, b: __m64) -> __m64 { - pminub(a, b) -} - -/// Compares the packed 8-bit signed integers of `a` and `b` writing the -/// smallest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pminub))] -pub unsafe fn _m_pminub(a: __m64, b: __m64) -> __m64 { - _mm_min_pu8(a, b) -} - -/// Multiplies packed 16-bit unsigned integer values and writes the -/// high-order 16 bits of each 32-bit product to the corresponding bits in -/// the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmulhuw))] -pub unsafe fn _mm_mulhi_pu16(a: __m64, b: __m64) -> __m64 { - pmulhuw(a, b) -} - -/// Multiplies packed 16-bit integer values and writes the -/// low-order 16 bits of each 32-bit product to the corresponding bits in -/// the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmullw))] -pub unsafe fn _mm_mullo_pi16(a: __m64, b: __m64) -> __m64 { - pmullw(a, b) -} - -/// Multiplies packed 16-bit unsigned integer values and writes the -/// high-order 16 bits of each 32-bit product to the corresponding bits in -/// the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmulhuw))] -pub unsafe fn _m_pmulhuw(a: __m64, b: __m64) -> __m64 { - _mm_mulhi_pu16(a, b) -} - -/// Computes the rounded averages of the packed unsigned 8-bit integer -/// values and writes the averages to the corresponding bits in the -/// destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pavgb))] -pub unsafe fn _mm_avg_pu8(a: __m64, b: __m64) -> __m64 { - pavgb(a, b) -} - -/// Computes the rounded averages of the packed unsigned 8-bit integer -/// values and writes the averages to the corresponding bits in the -/// destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pavgb))] -pub unsafe fn _m_pavgb(a: __m64, b: __m64) -> __m64 { - _mm_avg_pu8(a, b) -} - -/// Computes the rounded averages of the packed unsigned 16-bit integer -/// values and writes the averages to the corresponding bits in the -/// destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pavgw))] -pub unsafe fn _mm_avg_pu16(a: __m64, b: __m64) -> __m64 { - pavgw(a, b) -} - -/// Computes the rounded averages of the packed unsigned 16-bit integer -/// values and writes the averages to the corresponding bits in the -/// destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pavgw))] -pub unsafe fn _m_pavgw(a: __m64, b: __m64) -> __m64 { - _mm_avg_pu16(a, b) -} - -/// Subtracts the corresponding 8-bit unsigned integer values of the two -/// 64-bit vector operands and computes the absolute value for each of the -/// difference. Then sum of the 8 absolute differences is written to the -/// bits `[15:0]` of the destination; the remaining bits `[63:16]` are cleared. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(psadbw))] -pub unsafe fn _mm_sad_pu8(a: __m64, b: __m64) -> __m64 { - psadbw(a, b) -} - -/// Subtracts the corresponding 8-bit unsigned integer values of the two -/// 64-bit vector operands and computes the absolute value for each of the -/// difference. Then sum of the 8 absolute differences is written to the -/// bits `[15:0]` of the destination; the remaining bits `[63:16]` are cleared. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(psadbw))] -pub unsafe fn _m_psadbw(a: __m64, b: __m64) -> __m64 { - _mm_sad_pu8(a, b) -} - -/// Converts two elements of a 64-bit vector of `[2 x i32]` into two -/// floating point values and writes them to the lower 64-bits of the -/// destination. The remaining higher order elements of the destination are -/// copied from the corresponding elements in the first operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpi32_ps(a: __m128, b: __m64) -> __m128 { - cvtpi2ps(a, b) -} - -/// Converts two elements of a 64-bit vector of `[2 x i32]` into two -/// floating point values and writes them to the lower 64-bits of the -/// destination. The remaining higher order elements of the destination are -/// copied from the corresponding elements in the first operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvt_pi2ps(a: __m128, b: __m64) -> __m128 { - _mm_cvtpi32_ps(a, b) -} - -/// Converts the lower 4 8-bit values of `a` into a 128-bit vector of 4 `f32`s. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpi8_ps(a: __m64) -> __m128 { - let b = _mm_setzero_si64(); - let b = _mm_cmpgt_pi8(b, a); - let b = _mm_unpacklo_pi8(a, b); - _mm_cvtpi16_ps(b) -} - -/// Converts the lower 4 8-bit values of `a` into a 128-bit vector of 4 `f32`s. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpu8_ps(a: __m64) -> __m128 { - let b = _mm_setzero_si64(); - let b = _mm_unpacklo_pi8(a, b); - _mm_cvtpi16_ps(b) -} - -/// Converts a 64-bit vector of `i16`s into a 128-bit vector of 4 `f32`s. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpi16_ps(a: __m64) -> __m128 { - let b = _mm_setzero_si64(); - let b = _mm_cmpgt_pi16(b, a); - let c = _mm_unpackhi_pi16(a, b); - let r = _mm_setzero_ps(); - let r = cvtpi2ps(r, c); - let r = _mm_movelh_ps(r, r); - let c = _mm_unpacklo_pi16(a, b); - cvtpi2ps(r, c) -} - -/// Converts a 64-bit vector of `i16`s into a 128-bit vector of 4 `f32`s. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpu16_ps(a: __m64) -> __m128 { - let b = _mm_setzero_si64(); - let c = _mm_unpackhi_pi16(a, b); - let r = _mm_setzero_ps(); - let r = cvtpi2ps(r, c); - let r = _mm_movelh_ps(r, r); - let c = _mm_unpacklo_pi16(a, b); - cvtpi2ps(r, c) -} - -/// Converts the two 32-bit signed integer values from each 64-bit vector -/// operand of `[2 x i32]` into a 128-bit vector of `[4 x float]`. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpi32x2_ps(a: __m64, b: __m64) -> __m128 { - let c = _mm_setzero_ps(); - let c = _mm_cvtpi32_ps(c, b); - let c = _mm_movelh_ps(c, c); - _mm_cvtpi32_ps(c, a) -} - -/// Conditionally copies the values from each 8-bit element in the first -/// 64-bit integer vector operand to the specified memory location, as -/// specified by the most significant bit in the corresponding element in the -/// second 64-bit integer vector operand. -/// -/// To minimize caching, the data is flagged as non-temporal -/// (unlikely to be used again soon). -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(maskmovq))] -pub unsafe fn _mm_maskmove_si64(a: __m64, mask: __m64, mem_addr: *mut i8) { - maskmovq(a, mask, mem_addr) -} - -/// Conditionally copies the values from each 8-bit element in the first -/// 64-bit integer vector operand to the specified memory location, as -/// specified by the most significant bit in the corresponding element in the -/// second 64-bit integer vector operand. -/// -/// To minimize caching, the data is flagged as non-temporal -/// (unlikely to be used again soon). -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(maskmovq))] -pub unsafe fn _m_maskmovq(a: __m64, mask: __m64, mem_addr: *mut i8) { - _mm_maskmove_si64(a, mask, mem_addr) -} - -/// Extracts 16-bit element from a 64-bit vector of `[4 x i16]` and -/// returns it, as specified by the immediate integer operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pextrw, imm2 = 0))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm_extract_pi16(a: __m64, imm2: i32) -> i32 { - macro_rules! call { - ($imm2:expr) => { - pextrw(a, $imm2) as i32 - }; - } - constify_imm2!(imm2, call) -} - -/// Extracts 16-bit element from a 64-bit vector of `[4 x i16]` and -/// returns it, as specified by the immediate integer operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pextrw, imm2 = 0))] -#[rustc_args_required_const(1)] -pub unsafe fn _m_pextrw(a: __m64, imm2: i32) -> i32 { - macro_rules! call { - ($imm2:expr) => { - pextrw(a, $imm2) as i32 - }; - } - constify_imm2!(imm2, call) -} - -/// Copies data from the 64-bit vector of `[4 x i16]` to the destination, -/// and inserts the lower 16-bits of an integer operand at the 16-bit offset -/// specified by the immediate operand `n`. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pinsrw, imm2 = 0))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm_insert_pi16(a: __m64, d: i32, imm2: i32) -> __m64 { - macro_rules! call { - ($imm2:expr) => { - pinsrw(a, d, $imm2) - }; - } - constify_imm2!(imm2, call) -} - -/// Copies data from the 64-bit vector of `[4 x i16]` to the destination, -/// and inserts the lower 16-bits of an integer operand at the 16-bit offset -/// specified by the immediate operand `n`. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pinsrw, imm2 = 0))] -#[rustc_args_required_const(2)] -pub unsafe fn _m_pinsrw(a: __m64, d: i32, imm2: i32) -> __m64 { - macro_rules! call { - ($imm2:expr) => { - pinsrw(a, d, $imm2) - }; - } - constify_imm2!(imm2, call) -} - -/// Takes the most significant bit from each 8-bit element in a 64-bit -/// integer vector to create a 16-bit mask value. Zero-extends the value to -/// 32-bit integer and writes it to the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmovmskb))] -pub unsafe fn _mm_movemask_pi8(a: __m64) -> i32 { - pmovmskb(a) -} - -/// Takes the most significant bit from each 8-bit element in a 64-bit -/// integer vector to create a 16-bit mask value. Zero-extends the value to -/// 32-bit integer and writes it to the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmovmskb))] -pub unsafe fn _m_pmovmskb(a: __m64) -> i32 { - _mm_movemask_pi8(a) -} - -/// Shuffles the 4 16-bit integers from a 64-bit integer vector to the -/// destination, as specified by the immediate value operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pshufw, imm8 = 0))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm_shuffle_pi16(a: __m64, imm8: i32) -> __m64 { - macro_rules! call { - ($imm8:expr) => { - pshufw(a, $imm8) - }; - } - constify_imm8!(imm8, call) -} - -/// Shuffles the 4 16-bit integers from a 64-bit integer vector to the -/// destination, as specified by the immediate value operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pshufw, imm8 = 0))] -#[rustc_args_required_const(1)] -pub unsafe fn _m_pshufw(a: __m64, imm8: i32) -> __m64 { - macro_rules! call { - ($imm8:expr) => { - pshufw(a, $imm8) - }; - } - constify_imm8!(imm8, call) -} - -/// Converts the two lower packed single-precision (32-bit) floating-point -/// elements in `a` to packed 32-bit integers with truncation. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvttps2pi))] -pub unsafe fn _mm_cvttps_pi32(a: __m128) -> __m64 { - cvttps2pi(a) -} - -/// Converts the two lower packed single-precision (32-bit) floating-point -/// elements in `a` to packed 32-bit integers with truncation. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvttps2pi))] -pub unsafe fn _mm_cvtt_ps2pi(a: __m128) -> __m64 { - _mm_cvttps_pi32(a) -} - -/// Converts the two lower packed single-precision (32-bit) floating-point -/// elements in `a` to packed 32-bit integers. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtps2pi))] -pub unsafe fn _mm_cvtps_pi32(a: __m128) -> __m64 { - cvtps2pi(a) -} - -/// Converts the two lower packed single-precision (32-bit) floating-point -/// elements in `a` to packed 32-bit integers. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtps2pi))] -pub unsafe fn _mm_cvt_ps2pi(a: __m128) -> __m64 { - _mm_cvtps_pi32(a) -} - -/// Converts packed single-precision (32-bit) floating-point elements in `a` to -/// packed 16-bit integers. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtps2pi))] -pub unsafe fn _mm_cvtps_pi16(a: __m128) -> __m64 { - let b = _mm_cvtps_pi32(a); - let a = _mm_movehl_ps(a, a); - let c = _mm_cvtps_pi32(a); - _mm_packs_pi32(b, c) -} - -/// Converts packed single-precision (32-bit) floating-point elements in `a` to -/// packed 8-bit integers, and returns theem in the lower 4 elements of the -/// result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtps2pi))] -pub unsafe fn _mm_cvtps_pi8(a: __m128) -> __m64 { - let b = _mm_cvtps_pi16(a); - let c = _mm_setzero_si64(); - _mm_packs_pi16(b, c) -} - #[cfg(test)] mod tests { use crate::{hint::black_box, mem::transmute}; @@ -3593,24 +3007,6 @@ mod tests { assert_eq_m128(r, _mm_setr_ps(1.0, 2.0, 5.0, 6.0)); } - #[simd_test(enable = "sse")] - unsafe fn test_mm_loadh_pi() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let x: [f32; 4] = [5.0, 6.0, 7.0, 8.0]; - let p = x[..].as_ptr(); - let r = _mm_loadh_pi(a, p as *const _); - assert_eq_m128(r, _mm_setr_ps(1.0, 2.0, 5.0, 6.0)); - } - - #[simd_test(enable = "sse")] - unsafe fn test_mm_loadl_pi() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let x: [f32; 4] = [5.0, 6.0, 7.0, 8.0]; - let p = x[..].as_ptr(); - let r = _mm_loadl_pi(a, p as *const _); - assert_eq_m128(r, _mm_setr_ps(5.0, 6.0, 3.0, 4.0)); - } - #[simd_test(enable = "sse")] unsafe fn test_mm_load_ss() { let a = 42.0f32; @@ -3684,28 +3080,6 @@ mod tests { assert_eq_m128i(r, _mm_set_epi64x(5, 0)); } - #[simd_test(enable = "sse")] - unsafe fn test_mm_storeh_pi() { - let mut vals = [0.0f32; 8]; - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - _mm_storeh_pi(vals.as_mut_ptr() as *mut _, a); - - assert_eq!(vals[0], 3.0); - assert_eq!(vals[1], 4.0); - assert_eq!(vals[2], 0.0); - } - - #[simd_test(enable = "sse")] - unsafe fn test_mm_storel_pi() { - let mut vals = [0.0f32; 8]; - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - _mm_storel_pi(vals.as_mut_ptr() as *mut _, a); - - assert_eq!(vals[0], 1.0); - assert_eq!(vals[1], 2.0); - assert_eq!(vals[2], 0.0); - } - #[simd_test(enable = "sse")] unsafe fn test_mm_store_ss() { let mut vals = [0.0f32; 8]; @@ -3926,254 +3300,4 @@ mod tests { assert_eq!(mem.data[i], get_m128(a, i)); } } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_stream_pi() { - let a = transmute(i8x8::new(0, 0, 0, 0, 0, 0, 0, 7)); - let mut mem = boxed::Box::<__m64>::new(transmute(i8x8::splat(1))); - _mm_stream_pi(&mut *mem as *mut _ as *mut _, a); - assert_eq_m64(a, *mem); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_max_pi16() { - let a = _mm_setr_pi16(-1, 6, -3, 8); - let b = _mm_setr_pi16(5, -2, 7, -4); - let r = _mm_setr_pi16(5, 6, 7, 8); - - assert_eq_m64(r, _mm_max_pi16(a, b)); - assert_eq_m64(r, _m_pmaxsw(a, b)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_max_pu8() { - let a = _mm_setr_pi8(2, 6, 3, 8, 2, 6, 3, 8); - let b = _mm_setr_pi8(5, 2, 7, 4, 5, 2, 7, 4); - let r = _mm_setr_pi8(5, 6, 7, 8, 5, 6, 7, 8); - - assert_eq_m64(r, _mm_max_pu8(a, b)); - assert_eq_m64(r, _m_pmaxub(a, b)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_min_pi16() { - let a = _mm_setr_pi16(-1, 6, -3, 8); - let b = _mm_setr_pi16(5, -2, 7, -4); - let r = _mm_setr_pi16(-1, -2, -3, -4); - - assert_eq_m64(r, _mm_min_pi16(a, b)); - assert_eq_m64(r, _m_pminsw(a, b)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_min_pu8() { - let a = _mm_setr_pi8(2, 6, 3, 8, 2, 6, 3, 8); - let b = _mm_setr_pi8(5, 2, 7, 4, 5, 2, 7, 4); - let r = _mm_setr_pi8(2, 2, 3, 4, 2, 2, 3, 4); - - assert_eq_m64(r, _mm_min_pu8(a, b)); - assert_eq_m64(r, _m_pminub(a, b)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_mulhi_pu16() { - let (a, b) = (_mm_set1_pi16(1000), _mm_set1_pi16(1001)); - let r = _mm_mulhi_pu16(a, b); - assert_eq_m64(r, _mm_set1_pi16(15)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_mullo_pi16() { - let (a, b) = (_mm_set1_pi16(1000), _mm_set1_pi16(1001)); - let r = _mm_mullo_pi16(a, b); - assert_eq_m64(r, _mm_set1_pi16(17960)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_m_pmulhuw() { - let (a, b) = (_mm_set1_pi16(1000), _mm_set1_pi16(1001)); - let r = _m_pmulhuw(a, b); - assert_eq_m64(r, _mm_set1_pi16(15)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_avg_pu8() { - let (a, b) = (_mm_set1_pi8(3), _mm_set1_pi8(9)); - let r = _mm_avg_pu8(a, b); - assert_eq_m64(r, _mm_set1_pi8(6)); - - let r = _m_pavgb(a, b); - assert_eq_m64(r, _mm_set1_pi8(6)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_avg_pu16() { - let (a, b) = (_mm_set1_pi16(3), _mm_set1_pi16(9)); - let r = _mm_avg_pu16(a, b); - assert_eq_m64(r, _mm_set1_pi16(6)); - - let r = _m_pavgw(a, b); - assert_eq_m64(r, _mm_set1_pi16(6)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_sad_pu8() { - #[rustfmt::skip] - let a = _mm_setr_pi8( - 255u8 as i8, 254u8 as i8, 253u8 as i8, 252u8 as i8, - 1, 2, 3, 4, - ); - let b = _mm_setr_pi8(0, 0, 0, 0, 2, 1, 2, 1); - let r = _mm_sad_pu8(a, b); - assert_eq_m64(r, _mm_setr_pi16(1020, 0, 0, 0)); - - let r = _m_psadbw(a, b); - assert_eq_m64(r, _mm_setr_pi16(1020, 0, 0, 0)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpi32_ps() { - let a = _mm_setr_ps(0., 0., 3., 4.); - let b = _mm_setr_pi32(1, 2); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpi32_ps(a, b); - assert_eq_m128(r, expected); - - let r = _mm_cvt_pi2ps(a, b); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpi16_ps() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpi16_ps(a); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpu16_ps() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpu16_ps(a); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpi8_ps() { - let a = _mm_setr_pi8(1, 2, 3, 4, 5, 6, 7, 8); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpi8_ps(a); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpu8_ps() { - let a = _mm_setr_pi8(1, 2, 3, 4, 5, 6, 7, 8); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpu8_ps(a); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpi32x2_ps() { - let a = _mm_setr_pi32(1, 2); - let b = _mm_setr_pi32(3, 4); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpi32x2_ps(a, b); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_maskmove_si64() { - let a = _mm_set1_pi8(9); - let mask = _mm_setr_pi8(0, 0, 0x80u8 as i8, 0, 0, 0, 0, 0); - let mut r = _mm_set1_pi8(0); - _mm_maskmove_si64(a, mask, &mut r as *mut _ as *mut i8); - let e = _mm_setr_pi8(0, 0, 9, 0, 0, 0, 0, 0); - assert_eq_m64(r, e); - - let mut r = _mm_set1_pi8(0); - _m_maskmovq(a, mask, &mut r as *mut _ as *mut i8); - assert_eq_m64(r, e); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_extract_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let r = _mm_extract_pi16(a, 0); - assert_eq!(r, 1); - let r = _mm_extract_pi16(a, 1); - assert_eq!(r, 2); - - let r = _m_pextrw(a, 1); - assert_eq!(r, 2); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_insert_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let r = _mm_insert_pi16(a, 0, 0b0); - let expected = _mm_setr_pi16(0, 2, 3, 4); - assert_eq_m64(r, expected); - let r = _mm_insert_pi16(a, 0, 0b10); - let expected = _mm_setr_pi16(1, 2, 0, 4); - assert_eq_m64(r, expected); - - let r = _m_pinsrw(a, 0, 0b10); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_movemask_pi8() { - let a = _mm_setr_pi16(0b1000_0000, 0b0100_0000, 0b1000_0000, 0b0100_0000); - let r = _mm_movemask_pi8(a); - assert_eq!(r, 0b10001); - - let r = _m_pmovmskb(a); - assert_eq!(r, 0b10001); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_shuffle_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let r = _mm_shuffle_pi16(a, 0b00_01_01_11); - let expected = _mm_setr_pi16(4, 2, 2, 1); - assert_eq_m64(r, expected); - - let r = _m_pshufw(a, 0b00_01_01_11); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtps_pi32() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let r = _mm_setr_pi32(1, 2); - - assert_eq_m64(r, _mm_cvtps_pi32(a)); - assert_eq_m64(r, _mm_cvt_ps2pi(a)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvttps_pi32() { - let a = _mm_setr_ps(7.0, 2.0, 3.0, 4.0); - let r = _mm_setr_pi32(7, 2); - - assert_eq_m64(r, _mm_cvttps_pi32(a)); - assert_eq_m64(r, _mm_cvtt_ps2pi(a)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtps_pi16() { - let a = _mm_setr_ps(7.0, 2.0, 3.0, 4.0); - let r = _mm_setr_pi16(7, 2, 3, 4); - assert_eq_m64(r, _mm_cvtps_pi16(a)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtps_pi8() { - let a = _mm_setr_ps(7.0, 2.0, 3.0, 4.0); - let r = _mm_setr_pi8(7, 2, 3, 4, 0, 0, 0, 0); - assert_eq_m64(r, _mm_cvtps_pi8(a)); - } } diff --git a/library/stdarch/crates/core_arch/src/x86/sse2.rs b/library/stdarch/crates/core_arch/src/x86/sse2.rs index 90a2cf7a70..b6c19cdef4 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse2.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse2.rs @@ -2958,113 +2958,6 @@ pub unsafe fn _mm_unpacklo_pd(a: __m128d, b: __m128d) -> __m128d { simd_shuffle2(a, b, [0, 2]) } -/// Adds two signed or unsigned 64-bit integer values, returning the -/// lower 64 bits of the sum. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(paddq))] -pub unsafe fn _mm_add_si64(a: __m64, b: __m64) -> __m64 { - paddq(a, b) -} - -/// Multiplies 32-bit unsigned integer values contained in the lower bits -/// of the two 64-bit integer vectors and returns the 64-bit unsigned -/// product. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(pmuludq))] -pub unsafe fn _mm_mul_su32(a: __m64, b: __m64) -> __m64 { - pmuludq2(a, b) -} - -/// Subtracts signed or unsigned 64-bit integer values and writes the -/// difference to the corresponding bits in the destination. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(psubq))] -pub unsafe fn _mm_sub_si64(a: __m64, b: __m64) -> __m64 { - psubq(a, b) -} - -/// Converts the two signed 32-bit integer elements of a 64-bit vector of -/// `[2 x i32]` into two double-precision floating-point values, returned in a -/// 128-bit vector of `[2 x double]`. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2pd))] -pub unsafe fn _mm_cvtpi32_pd(a: __m64) -> __m128d { - cvtpi2pd(a) -} - -/// Initializes both 64-bit values in a 128-bit vector of `[2 x i64]` with -/// the specified 64-bit integer values. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// no particular instruction to test -pub unsafe fn _mm_set_epi64(e1: __m64, e0: __m64) -> __m128i { - _mm_set_epi64x(transmute(e1), transmute(e0)) -} - -/// Initializes both values in a 128-bit vector of `[2 x i64]` with the -/// specified 64-bit value. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// no particular instruction to test -pub unsafe fn _mm_set1_epi64(a: __m64) -> __m128i { - _mm_set_epi64x(transmute(a), transmute(a)) -} - -/// Constructs a 128-bit integer vector, initialized in reverse order -/// with the specified 64-bit integral values. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// no particular instruction to test -pub unsafe fn _mm_setr_epi64(e1: __m64, e0: __m64) -> __m128i { - _mm_set_epi64x(transmute(e0), transmute(e1)) -} - -/// Returns the lower 64 bits of a 128-bit integer vector as a 64-bit -/// integer. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// #[cfg_attr(test, assert_instr(movdq2q))] // FIXME: llvm codegens wrong -// instr? -pub unsafe fn _mm_movepi64_pi64(a: __m128i) -> __m64 { - transmute(simd_extract::<_, i64>(a.as_i64x2(), 0)) -} - -/// Moves the 64-bit operand to a 128-bit integer vector, zeroing the -/// upper bits. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// #[cfg_attr(test, assert_instr(movq2dq))] // FIXME: llvm codegens wrong -// instr? -pub unsafe fn _mm_movpi64_epi64(a: __m64) -> __m128i { - _mm_set_epi64x(0, transmute(a)) -} - -/// Converts the two double-precision floating-point elements of a -/// 128-bit vector of `[2 x double]` into two signed 32-bit integer values, -/// returned in a 64-bit vector of `[2 x i32]`. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(cvtpd2pi))] -pub unsafe fn _mm_cvtpd_pi32(a: __m128d) -> __m64 { - cvtpd2pi(a) -} - -/// Converts the two double-precision floating-point elements of a -/// 128-bit vector of `[2 x double]` into two signed 32-bit integer values, -/// returned in a 64-bit vector of `[2 x i32]`. -/// If the result of either conversion is inexact, the result is truncated -/// (rounded towards zero) regardless of the current MXCSR setting. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(cvttpd2pi))] -pub unsafe fn _mm_cvttpd_pi32(a: __m128d) -> __m64 { - cvttpd2pi(a) -} - #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.sse2.pause"] @@ -3207,18 +3100,6 @@ extern "C" { fn storeudq(mem_addr: *mut i8, a: __m128i); #[link_name = "llvm.x86.sse2.storeu.pd"] fn storeupd(mem_addr: *mut i8, a: __m128d); - #[link_name = "llvm.x86.mmx.padd.q"] - fn paddq(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmulu.dq"] - fn pmuludq2(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psub.q"] - fn psubq(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.sse.cvtpi2pd"] - fn cvtpi2pd(a: __m64) -> __m128d; - #[link_name = "llvm.x86.sse.cvtpd2pi"] - fn cvtpd2pi(a: __m128d) -> __m64; - #[link_name = "llvm.x86.sse.cvttpd2pi"] - fn cvttpd2pi(a: __m128d) -> __m64; } #[cfg(test)] @@ -5208,87 +5089,4 @@ mod tests { let r = _mm_castsi128_ps(a); assert_eq_m128(r, expected); } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_add_si64() { - let a = 1i64; - let b = 2i64; - let expected = 3i64; - let r = _mm_add_si64(transmute(a), transmute(b)); - assert_eq!(transmute::<__m64, i64>(r), expected); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_mul_su32() { - let a = _mm_setr_pi32(1, 2); - let b = _mm_setr_pi32(3, 4); - let expected = 3u64; - let r = _mm_mul_su32(a, b); - assert_eq_m64(r, transmute(expected)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_sub_si64() { - let a = 1i64; - let b = 2i64; - let expected = -1i64; - let r = _mm_sub_si64(transmute(a), transmute(b)); - assert_eq!(transmute::<__m64, i64>(r), expected); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_cvtpi32_pd() { - let a = _mm_setr_pi32(1, 2); - let expected = _mm_setr_pd(1., 2.); - let r = _mm_cvtpi32_pd(a); - assert_eq_m128d(r, expected); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_set_epi64() { - let r = _mm_set_epi64(transmute(1i64), transmute(2i64)); - assert_eq_m128i(r, _mm_setr_epi64x(2, 1)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_set1_epi64() { - let r = _mm_set1_epi64(transmute(1i64)); - assert_eq_m128i(r, _mm_setr_epi64x(1, 1)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_setr_epi64() { - let r = _mm_setr_epi64(transmute(1i64), transmute(2i64)); - assert_eq_m128i(r, _mm_setr_epi64x(1, 2)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_movepi64_pi64() { - let r = _mm_movepi64_pi64(_mm_setr_epi64x(5, 0)); - assert_eq_m64(r, _mm_setr_pi8(5, 0, 0, 0, 0, 0, 0, 0)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_movpi64_epi64() { - let r = _mm_movpi64_epi64(_mm_setr_pi8(5, 0, 0, 0, 0, 0, 0, 0)); - assert_eq_m128i(r, _mm_setr_epi64x(5, 0)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_cvtpd_pi32() { - let a = _mm_setr_pd(5., 0.); - let r = _mm_cvtpd_pi32(a); - assert_eq_m64(r, _mm_setr_pi32(5, 0)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_cvttpd_pi32() { - let a = _mm_setr_pd(5., 0.); - let r = _mm_cvttpd_pi32(a); - assert_eq_m64(r, _mm_setr_pi32(5, 0)); - - let a = _mm_setr_pd(f64::NEG_INFINITY, f64::NAN); - let r = _mm_cvttpd_pi32(a); - assert_eq_m64(r, _mm_setr_pi32(i32::MIN, i32::MIN)); - } } diff --git a/library/stdarch/crates/core_arch/src/x86/sse42.rs b/library/stdarch/crates/core_arch/src/x86/sse42.rs index d4d8aa644e..cce05e864c 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse42.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse42.rs @@ -261,20 +261,6 @@ pub unsafe fn _mm_cmpistrm(a: __m128i, b: __m128i, imm8: i32) -> __m128i { /// # } /// ``` /// -/// [`_SIDD_UBYTE_OPS`]: constant._SIDD_UBYTE_OPS.html -/// [`_SIDD_UWORD_OPS`]: constant._SIDD_UWORD_OPS.html -/// [`_SIDD_SBYTE_OPS`]: constant._SIDD_SBYTE_OPS.html -/// [`_SIDD_SWORD_OPS`]: constant._SIDD_SWORD_OPS.html -/// [`_SIDD_CMP_EQUAL_ANY`]: constant._SIDD_CMP_EQUAL_ANY.html -/// [`_SIDD_CMP_RANGES`]: constant._SIDD_CMP_RANGES.html -/// [`_SIDD_CMP_EQUAL_EACH`]: constant._SIDD_CMP_EQUAL_EACH.html -/// [`_SIDD_CMP_EQUAL_ORDERED`]: constant._SIDD_CMP_EQUAL_ORDERED.html -/// [`_SIDD_POSITIVE_POLARITY`]: constant._SIDD_POSITIVE_POLARITY.html -/// [`_SIDD_NEGATIVE_POLARITY`]: constant._SIDD_NEGATIVE_POLARITY.html -/// [`_SIDD_LEAST_SIGNIFICANT`]: constant._SIDD_LEAST_SIGNIFICANT.html -/// [`_SIDD_MOST_SIGNIFICANT`]: constant._SIDD_MOST_SIGNIFICANT.html -/// [`_mm_cmpestri`]: fn._mm_cmpestri.html -/// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpistri) #[inline] #[target_feature(enable = "sse4.2")] diff --git a/library/stdarch/crates/core_arch/src/x86/ssse3.rs b/library/stdarch/crates/core_arch/src/x86/ssse3.rs index 6a45603e44..669f51ce7b 100644 --- a/library/stdarch/crates/core_arch/src/x86/ssse3.rs +++ b/library/stdarch/crates/core_arch/src/x86/ssse3.rs @@ -299,169 +299,6 @@ pub unsafe fn _mm_sign_epi32(a: __m128i, b: __m128i) -> __m128i { transmute(psignd128(a.as_i32x4(), b.as_i32x4())) } -/// Computes the absolute value of packed 8-bit integers in `a` and -/// return the unsigned results. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pabsb))] -pub unsafe fn _mm_abs_pi8(a: __m64) -> __m64 { - pabsb(a) -} - -/// Computes the absolute value of packed 8-bit integers in `a`, and returns the -/// unsigned results. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pabsw))] -pub unsafe fn _mm_abs_pi16(a: __m64) -> __m64 { - pabsw(a) -} - -/// Computes the absolute value of packed 32-bit integers in `a`, and returns the -/// unsigned results. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pabsd))] -pub unsafe fn _mm_abs_pi32(a: __m64) -> __m64 { - pabsd(a) -} - -/// Shuffles packed 8-bit integers in `a` according to shuffle control mask in -/// the corresponding 8-bit element of `b`, and returns the results -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pshufb))] -pub unsafe fn _mm_shuffle_pi8(a: __m64, b: __m64) -> __m64 { - pshufb(a, b) -} - -/// Concatenates the two 64-bit integer vector operands, and right-shifts -/// the result by the number of bytes specified in the immediate operand. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(palignr, n = 15))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm_alignr_pi8(a: __m64, b: __m64, n: i32) -> __m64 { - macro_rules! call { - ($imm8:expr) => { - palignrb(a, b, $imm8) - }; - } - constify_imm8!(n, call) -} - -/// Horizontally adds the adjacent pairs of values contained in 2 packed -/// 64-bit vectors of `[4 x i16]`. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phaddw))] -pub unsafe fn _mm_hadd_pi16(a: __m64, b: __m64) -> __m64 { - phaddw(a, b) -} - -/// Horizontally adds the adjacent pairs of values contained in 2 packed -/// 64-bit vectors of `[2 x i32]`. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phaddd))] -pub unsafe fn _mm_hadd_pi32(a: __m64, b: __m64) -> __m64 { - phaddd(a, b) -} - -/// Horizontally adds the adjacent pairs of values contained in 2 packed -/// 64-bit vectors of `[4 x i16]`. Positive sums greater than 7FFFh are -/// saturated to 7FFFh. Negative sums less than 8000h are saturated to 8000h. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phaddsw))] -pub unsafe fn _mm_hadds_pi16(a: __m64, b: __m64) -> __m64 { - phaddsw(a, b) -} - -/// Horizontally subtracts the adjacent pairs of values contained in 2 -/// packed 64-bit vectors of `[4 x i16]`. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phsubw))] -pub unsafe fn _mm_hsub_pi16(a: __m64, b: __m64) -> __m64 { - phsubw(a, b) -} - -/// Horizontally subtracts the adjacent pairs of values contained in 2 -/// packed 64-bit vectors of `[2 x i32]`. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phsubd))] -pub unsafe fn _mm_hsub_pi32(a: __m64, b: __m64) -> __m64 { - phsubd(a, b) -} - -/// Horizontally subtracts the adjacent pairs of values contained in 2 -/// packed 64-bit vectors of `[4 x i16]`. Positive differences greater than -/// 7FFFh are saturated to 7FFFh. Negative differences less than 8000h are -/// saturated to 8000h. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phsubsw))] -pub unsafe fn _mm_hsubs_pi16(a: __m64, b: __m64) -> __m64 { - phsubsw(a, b) -} - -/// Multiplies corresponding pairs of packed 8-bit unsigned integer -/// values contained in the first source operand and packed 8-bit signed -/// integer values contained in the second source operand, adds pairs of -/// contiguous products with signed saturation, and writes the 16-bit sums to -/// the corresponding bits in the destination. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pmaddubsw))] -pub unsafe fn _mm_maddubs_pi16(a: __m64, b: __m64) -> __m64 { - pmaddubsw(a, b) -} - -/// Multiplies packed 16-bit signed integer values, truncates the 32-bit -/// products to the 18 most significant bits by right-shifting, rounds the -/// truncated value by adding 1, and writes bits `[16:1]` to the destination. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pmulhrsw))] -pub unsafe fn _mm_mulhrs_pi16(a: __m64, b: __m64) -> __m64 { - pmulhrsw(a, b) -} - -/// Negates packed 8-bit integers in `a` when the corresponding signed 8-bit -/// integer in `b` is negative, and returns the results. -/// Element in result are zeroed out when the corresponding element in `b` is -/// zero. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(psignb))] -pub unsafe fn _mm_sign_pi8(a: __m64, b: __m64) -> __m64 { - psignb(a, b) -} - -/// Negates packed 16-bit integers in `a` when the corresponding signed 16-bit -/// integer in `b` is negative, and returns the results. -/// Element in result are zeroed out when the corresponding element in `b` is -/// zero. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(psignw))] -pub unsafe fn _mm_sign_pi16(a: __m64, b: __m64) -> __m64 { - psignw(a, b) -} - -/// Negates packed 32-bit integers in `a` when the corresponding signed 32-bit -/// integer in `b` is negative, and returns the results. -/// Element in result are zeroed out when the corresponding element in `b` is -/// zero. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(psignd))] -pub unsafe fn _mm_sign_pi32(a: __m64, b: __m64) -> __m64 { - psignd(a, b) -} - #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.ssse3.pabs.b.128"] @@ -508,54 +345,6 @@ extern "C" { #[link_name = "llvm.x86.ssse3.psign.d.128"] fn psignd128(a: i32x4, b: i32x4) -> i32x4; - - #[link_name = "llvm.x86.ssse3.pabs.b"] - fn pabsb(a: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pabs.w"] - fn pabsw(a: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pabs.d"] - fn pabsd(a: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pshuf.b"] - fn pshufb(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.mmx.palignr.b"] - fn palignrb(a: __m64, b: __m64, n: u8) -> __m64; - - #[link_name = "llvm.x86.ssse3.phadd.w"] - fn phaddw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phadd.d"] - fn phaddd(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phadd.sw"] - fn phaddsw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phsub.w"] - fn phsubw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phsub.d"] - fn phsubd(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phsub.sw"] - fn phsubsw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pmadd.ub.sw"] - fn pmaddubsw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pmul.hr.sw"] - fn pmulhrsw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.psign.b"] - fn psignb(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.psign.w"] - fn psignw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.psign.d"] - fn psignd(a: __m64, b: __m64) -> __m64; } #[cfg(test)] @@ -761,138 +550,4 @@ mod tests { let r = _mm_sign_epi32(a, b); assert_eq_m128i(r, expected); } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_abs_pi8() { - let r = _mm_abs_pi8(_mm_set1_pi8(-5)); - assert_eq_m64(r, _mm_set1_pi8(5)); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_abs_pi16() { - let r = _mm_abs_pi16(_mm_set1_pi16(-5)); - assert_eq_m64(r, _mm_set1_pi16(5)); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_abs_pi32() { - let r = _mm_abs_pi32(_mm_set1_pi32(-5)); - assert_eq_m64(r, _mm_set1_pi32(5)); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_shuffle_pi8() { - let a = _mm_setr_pi8(1, 2, 3, 4, 5, 6, 7, 8); - let b = _mm_setr_pi8(4, 128u8 as i8, 4, 3, 24, 12, 6, 19); - let expected = _mm_setr_pi8(5, 0, 5, 4, 1, 5, 7, 4); - let r = _mm_shuffle_pi8(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_alignr_pi8() { - let a = _mm_setr_pi32(0x89ABCDEF_u32 as i32, 0x01234567_u32 as i32); - let b = _mm_setr_pi32(0xBBAA9988_u32 as i32, 0xFFDDEECC_u32 as i32); - let r = _mm_alignr_pi8(a, b, 4); - assert_eq_m64(r, transmute(0x89abcdefffddeecc_u64)); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hadd_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(4, 128, 4, 3); - let expected = _mm_setr_pi16(3, 7, 132, 7); - let r = _mm_hadd_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hadd_pi32() { - let a = _mm_setr_pi32(1, 2); - let b = _mm_setr_pi32(4, 128); - let expected = _mm_setr_pi32(3, 132); - let r = _mm_hadd_pi32(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hadds_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(32767, 1, -32768, -1); - let expected = _mm_setr_pi16(3, 7, 32767, -32768); - let r = _mm_hadds_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hsub_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(4, 128, 4, 3); - let expected = _mm_setr_pi16(-1, -1, -124, 1); - let r = _mm_hsub_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hsub_pi32() { - let a = _mm_setr_pi32(1, 2); - let b = _mm_setr_pi32(4, 128); - let expected = _mm_setr_pi32(-1, -124); - let r = _mm_hsub_pi32(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hsubs_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(4, 128, 4, 3); - let expected = _mm_setr_pi16(-1, -1, -124, 1); - let r = _mm_hsubs_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_maddubs_pi16() { - let a = _mm_setr_pi8(1, 2, 3, 4, 5, 6, 7, 8); - let b = _mm_setr_pi8(4, 63, 4, 3, 24, 12, 6, 19); - let expected = _mm_setr_pi16(130, 24, 192, 194); - let r = _mm_maddubs_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_mulhrs_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(4, 32767, -1, -32768); - let expected = _mm_setr_pi16(0, 2, 0, -4); - let r = _mm_mulhrs_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_sign_pi8() { - let a = _mm_setr_pi8(1, 2, 3, 4, -5, -6, 7, 8); - let b = _mm_setr_pi8(4, 64, 0, 3, 1, -1, -2, 1); - let expected = _mm_setr_pi8(1, 2, 0, 4, -5, 6, -7, 8); - let r = _mm_sign_pi8(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_sign_pi16() { - let a = _mm_setr_pi16(-1, 2, 3, 4); - let b = _mm_setr_pi16(1, -1, 1, 0); - let expected = _mm_setr_pi16(-1, -2, 3, 0); - let r = _mm_sign_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_sign_pi32() { - let a = _mm_setr_pi32(-1, 2); - let b = _mm_setr_pi32(1, 0); - let expected = _mm_setr_pi32(-1, 0); - let r = _mm_sign_pi32(a, b); - assert_eq_m64(r, expected); - } } diff --git a/library/stdarch/crates/core_arch/src/x86/test.rs b/library/stdarch/crates/core_arch/src/x86/test.rs index b9c4537da5..a3ca0e0820 100644 --- a/library/stdarch/crates/core_arch/src/x86/test.rs +++ b/library/stdarch/crates/core_arch/src/x86/test.rs @@ -2,15 +2,6 @@ use crate::core_arch::x86::*; -#[target_feature(enable = "mmx")] -pub unsafe fn assert_eq_m64(a: __m64, b: __m64) { - union A { - a: __m64, - b: u64, - } - assert_eq!(A { a }.b, A { a: b }.b) -} - #[target_feature(enable = "sse2")] pub unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) { union A { diff --git a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs index ce2970ee51..036cf36c74 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs @@ -50,808 +50,4390 @@ mod tests { use crate::core_arch::x86_64::*; #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setzero_pd() { - assert_eq_m512d(_mm512_setzero_pd(), _mm512_set1_pd(0.)); + unsafe fn test_mm512_abs_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let r = _mm512_abs_epi64(a); + let e = _mm512_setr_epi64(0, 1, 1, i64::MAX, i64::MAX.wrapping_add(1), 100, 100, 32); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set1_pd() { - let expected = _mm512_set_pd(2., 2., 2., 2., 2., 2., 2., 2.); - assert_eq_m512d(expected, _mm512_set1_pd(2.)); - } - - unsafe fn test_mm512_set1_epi64() { - let r = _mm512_set_epi64(2, 2, 2, 2, 2, 2, 2, 2); - assert_eq_m512i(r, _mm512_set1_epi64(2)); + unsafe fn test_mm512_mask_abs_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let r = _mm512_mask_abs_epi64(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_abs_epi64(a, 0b00001111, a); + let e = _mm512_setr_epi64(0, 1, 1, i64::MAX, i64::MIN, 100, -100, -32); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmplt_pd_mask() { + unsafe fn test_mm512_maskz_abs_epi64() { #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let m = _mm512_cmplt_pd_mask(a, b); - assert_eq!(m, 0b00000101); + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let r = _mm512_maskz_abs_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_abs_epi64(0b00001111, a); + let e = _mm512_setr_epi64(0, 1, 1, i64::MAX, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmplt_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let mask = 0b01100110; - let r = _mm512_mask_cmplt_pd_mask(mask, a, b); - assert_eq!(r, 0b00000100); + unsafe fn test_mm512_abs_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let r = _mm512_abs_pd(a); + let e = _mm512_setr_pd(0., 1., 1., f64::MAX, f64::MAX, 100., 100., 32.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpnlt_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - assert_eq!(_mm512_cmpnlt_pd_mask(a, b), !_mm512_cmplt_pd_mask(a, b)); + unsafe fn test_mm512_mask_abs_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let r = _mm512_mask_abs_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_abs_pd(a, 0b00001111, a); + let e = _mm512_setr_pd(0., 1., 1., f64::MAX, f64::MIN, 100., -100., -32.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpnlt_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let mask = 0b01111010; - assert_eq!(_mm512_mask_cmpnlt_pd_mask(mask, a, b), 0b01111010); + unsafe fn test_mm512_add_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_add_epi64(a, b); + let e = _mm512_setr_epi64(1, 2, 0, i64::MIN, i64::MIN + 1, 101, -99, -31); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmple_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - assert_eq!(_mm512_cmple_pd_mask(a, b), 0b00100101); + unsafe fn test_mm512_mask_add_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_mask_add_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_add_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(1, 2, 0, i64::MIN, i64::MIN, 100, -100, -32); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmple_pd_mask() { + unsafe fn test_mm512_maskz_add_epi64() { #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let mask = 0b01111010; - assert_eq!(_mm512_mask_cmple_pd_mask(mask, a, b), 0b00100000); + let a = _mm512_setr_epi64( + 0, 1, -1, i64::MAX, + i64::MIN, 100, -100, -32 + ); + let b = _mm512_set1_epi64(1); + let r = _mm512_maskz_add_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_add_epi64(0b00001111, a, b); + let e = _mm512_setr_epi64(1, 2, 0, i64::MIN, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpnle_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let m = _mm512_cmpnle_pd_mask(b, a); - assert_eq!(m, 0b00001101); + unsafe fn test_mm512_add_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_add_pd(a, b); + let e = _mm512_setr_pd(1., 2., 0., f64::MAX, f64::MIN + 1., 101., -99., -31.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpnle_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let mask = 0b01100110; - let r = _mm512_mask_cmpnle_pd_mask(mask, b, a); - assert_eq!(r, 0b00000100); + unsafe fn test_mm512_mask_add_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_mask_add_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_add_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd(1., 2., 0., f64::MAX, f64::MIN, 100., -100., -32.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpeq_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, f64::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_pd(0., 1., 13., 42., f64::MAX, f64::MIN, f64::NAN, -100.); - let m = _mm512_cmpeq_pd_mask(b, a); - assert_eq!(m, 0b11001101); + unsafe fn test_mm512_maskz_add_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_maskz_add_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_add_pd(0b00001111, a, b); + let e = _mm512_setr_pd(1., 2., 0., f64::MAX, 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpeq_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, f64::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_pd(0., 1., 13., 42., f64::MAX, f64::MIN, f64::NAN, -100.); - let mask = 0b01111010; - let r = _mm512_mask_cmpeq_pd_mask(mask, b, a); - assert_eq!(r, 0b01001000); + unsafe fn test_mm512_sub_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_sub_epi64(a, b); + let e = _mm512_setr_epi64(-1, 0, -2, i64::MAX - 1, i64::MAX, 99, -101, -33); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpneq_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, f64::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_pd(0., 1., 13., 42., f64::MAX, f64::MIN, f64::NAN, -100.); - let m = _mm512_cmpneq_pd_mask(b, a); - assert_eq!(m, 0b00110010); + unsafe fn test_mm512_mask_sub_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_mask_sub_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_sub_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(-1, 0, -2, i64::MAX - 1, i64::MIN, 100, -100, -32); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpneq_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, f64::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_pd(0., 1., 13., 42., f64::MAX, f64::MIN, f64::NAN, -100.); - let mask = 0b01111010; - let r = _mm512_mask_cmpneq_pd_mask(mask, b, a); - assert_eq!(r, 0b00110010) + unsafe fn test_mm512_maskz_sub_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_maskz_sub_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sub_epi64(0b00001111, a, b); + let e = _mm512_setr_epi64(-1, 0, -2, i64::MAX - 1, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let m = _mm512_cmp_pd_mask(a, b, _CMP_LT_OQ); - assert_eq!(m, 0b00000101); + unsafe fn test_mm512_sub_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_sub_pd(a, b); + let e = _mm512_setr_pd(-1., 0., -2., f64::MAX - 1., f64::MIN, 99., -101., -33.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let mask = 0b01100110; - let r = _mm512_mask_cmp_pd_mask(mask, a, b, _CMP_LT_OQ); - assert_eq!(r, 0b00000100); + unsafe fn test_mm512_mask_sub_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_mask_sub_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_sub_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd(-1., 0., -2., f64::MAX - 1., f64::MIN, 100., -100., -32.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_round_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let m = _mm512_cmp_round_pd_mask(a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 0b00000101); + unsafe fn test_mm512_maskz_sub_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_maskz_sub_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_sub_pd(0b00001111, a, b); + let e = _mm512_setr_pd(-1., 0., -2., f64::MAX - 1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_round_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, 100., -100.); - let b = _mm512_set1_pd(-1.); - let mask = 0b01100110; - let r = _mm512_mask_cmp_round_pd_mask(mask, a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); - assert_eq!(r, 0b00000100); + unsafe fn test_mm512_mul_epi32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_mul_epi32(a, b); + let e = _mm512_set_epi64(15, 13, 11, 9, 7, 5, 3, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpord_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(f64::NAN, f64::MAX, f64::NAN, f64::MIN, f64::NAN, -1., f64::NAN, 0.); - #[rustfmt::skip] - let b = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::MIN, f64::MAX, -1., 0.); - let m = _mm512_cmpord_pd_mask(a, b); - assert_eq!(m, 0b00000101); + unsafe fn test_mm512_mask_mul_epi32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_mask_mul_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mul_epi32(a, 0b00001111, a, b); + let e = _mm512_set_epi64( + 1 | 1 << 32, + 1 | 1 << 32, + 1 | 1 << 32, + 1 | 1 << 32, + 7, + 5, + 3, + 1, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpord_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(f64::NAN, f64::MAX, f64::NAN, f64::MIN, f64::NAN, -1., f64::NAN, 0.); - #[rustfmt::skip] - let b = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::MIN, f64::MAX, -1., 0.); - let mask = 0b11000011; - let m = _mm512_mask_cmpord_pd_mask(mask, a, b); - assert_eq!(m, 0b00000001); + unsafe fn test_mm512_maskz_mul_epi32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_maskz_mul_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mul_epi32(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 7, 5, 3, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpunord_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(f64::NAN, f64::MAX, f64::NAN, f64::MIN, f64::NAN, -1., f64::NAN, 0.); - #[rustfmt::skip] - let b = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::MIN, f64::MAX, -1., 0.); - let m = _mm512_cmpunord_pd_mask(a, b); - - assert_eq!(m, 0b11111010); + unsafe fn test_mm512_mul_epu32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_mul_epu32(a, b); + let e = _mm512_set_epi64(15, 13, 11, 9, 7, 5, 3, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpunord_pd_mask() { - #[rustfmt::skip] - let a = _mm512_set_pd(f64::NAN, f64::MAX, f64::NAN, f64::MIN, f64::NAN, -1., f64::NAN, 0.); - #[rustfmt::skip] - let b = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::MIN, f64::MAX, -1., 0.); - let mask = 0b00001111; - let m = _mm512_mask_cmpunord_pd_mask(mask, a, b); - assert_eq!(m, 0b000001010); + unsafe fn test_mm512_mask_mul_epu32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_mask_mul_epu32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mul_epu32(a, 0b00001111, a, b); + let e = _mm512_set_epi64( + 1 | 1 << 32, + 1 | 1 << 32, + 1 | 1 << 32, + 1 | 1 << 32, + 7, + 5, + 3, + 1, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmplt_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let m = _mm512_cmplt_epu64_mask(a, b); - assert_eq!(m, 0b11001111); + unsafe fn test_mm512_maskz_mul_epu32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_maskz_mul_epu32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mul_epu32(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 7, 5, 3, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmplt_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01111010; - let r = _mm512_mask_cmplt_epu64_mask(mask, a, b); - assert_eq!(r, 0b01001010); + unsafe fn test_mm512_mullox_epi64() { + let a = _mm512_setr_epi64(0, 1, i64::MAX, i64::MIN, i64::MAX, 100, -100, -32); + let b = _mm512_set1_epi64(2); + let r = _mm512_mullox_epi64(a, b); + let e = _mm512_setr_epi64(0, 2, -2, 0, -2, 200, -200, -64); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpgt_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let m = _mm512_cmpgt_epu64_mask(b, a); - assert_eq!(m, 0b11001111); + unsafe fn test_mm512_mask_mullox_epi64() { + let a = _mm512_setr_epi64(0, 1, i64::MAX, i64::MIN, i64::MAX, 100, -100, -32); + let b = _mm512_set1_epi64(2); + let r = _mm512_mask_mullox_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mullox_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(0, 2, -2, 0, i64::MAX, 100, -100, -32); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpgt_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01111010; - let r = _mm512_mask_cmpgt_epu64_mask(mask, b, a); - assert_eq!(r, 0b01001010); + unsafe fn test_mm512_mul_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_set1_pd(2.); + let r = _mm512_mul_pd(a, b); + let e = _mm512_setr_pd( + 0., + 2., + f64::INFINITY, + f64::NEG_INFINITY, + f64::INFINITY, + f64::NEG_INFINITY, + -200., + -64., + ); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmple_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - assert_eq!( - _mm512_cmple_epu64_mask(a, b), - !_mm512_cmpgt_epu64_mask(a, b) - ) + unsafe fn test_mm512_mask_mul_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_set1_pd(2.); + let r = _mm512_mask_mul_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_mul_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd( + 0., + 2., + f64::INFINITY, + f64::NEG_INFINITY, + f64::MAX, + f64::MIN, + -100., + -32., + ); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmple_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01111010; - assert_eq!(_mm512_mask_cmple_epu64_mask(mask, a, b), 0b01111010); + unsafe fn test_mm512_maskz_mul_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_set1_pd(2.); + let r = _mm512_maskz_mul_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_mul_pd(0b00001111, a, b); + let e = _mm512_setr_pd(0., 2., f64::INFINITY, f64::NEG_INFINITY, 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpge_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - assert_eq!( - _mm512_cmpge_epu64_mask(a, b), - !_mm512_cmplt_epu64_mask(a, b) + unsafe fn test_mm512_div_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_setr_pd(2., 2., 0., 0., 0., 0., 2., 2.); + let r = _mm512_div_pd(a, b); + let e = _mm512_setr_pd( + 0., + 0.5, + f64::INFINITY, + f64::NEG_INFINITY, + f64::INFINITY, + f64::NEG_INFINITY, + -50., + -16., ); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpge_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01111010; - assert_eq!(_mm512_mask_cmpge_epu64_mask(mask, a, b), 0b01111010); + unsafe fn test_mm512_mask_div_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_setr_pd(2., 2., 0., 0., 0., 0., 2., 2.); + let r = _mm512_mask_div_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_div_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd( + 0., + 0.5, + f64::INFINITY, + f64::NEG_INFINITY, + f64::MAX, + f64::MIN, + -100., + -32., + ); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpeq_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); - let m = _mm512_cmpeq_epu64_mask(b, a); - assert_eq!(m, 0b11001111); + unsafe fn test_mm512_maskz_div_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_setr_pd(2., 2., 0., 0., 0., 0., 2., 2.); + let r = _mm512_maskz_div_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_div_pd(0b00001111, a, b); + let e = _mm512_setr_pd(0., 0.5, f64::INFINITY, f64::NEG_INFINITY, 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpeq_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); - let mask = 0b01111010; - let r = _mm512_mask_cmpeq_epu64_mask(mask, b, a); - assert_eq!(r, 0b01001010); + unsafe fn test_mm512_max_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epi64(a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 4, 5, 6, 7); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpneq_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); - let m = _mm512_cmpneq_epu64_mask(b, a); - assert_eq!(m, !_mm512_cmpeq_epu64_mask(b, a)); + unsafe fn test_mm512_mask_max_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 4, 5, 6, 7); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpneq_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, -100, 100); - let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); - let mask = 0b01111010; - let r = _mm512_mask_cmpneq_epu64_mask(mask, b, a); - assert_eq!(r, 0b00110010); + unsafe fn test_mm512_maskz_max_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epi64(0b00001111, a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let m = _mm512_cmp_epu64_mask(a, b, _MM_CMPINT_LT); - assert_eq!(m, 0b11001111); + unsafe fn test_mm512_max_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_max_pd(a, b); + let e = _mm512_setr_pd(7., 6., 5., 4., 4., 5., 6., 7.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_epu64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01111010; - let r = _mm512_mask_cmp_epu64_mask(mask, a, b, _MM_CMPINT_LT); - assert_eq!(r, 0b01001010); + unsafe fn test_mm512_mask_max_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_mask_max_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_max_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd(7., 6., 5., 4., 4., 5., 6., 7.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmplt_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let m = _mm512_cmplt_epi64_mask(a, b); - assert_eq!(m, 0b00000101); + unsafe fn test_mm512_maskz_max_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_maskz_max_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_max_pd(0b00001111, a, b); + let e = _mm512_setr_pd(7., 6., 5., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmplt_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01100110; - let r = _mm512_mask_cmplt_epi64_mask(mask, a, b); - assert_eq!(r, 0b00000100); + unsafe fn test_mm512_max_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epu64(a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 4, 5, 6, 7); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpgt_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let m = _mm512_cmpgt_epi64_mask(b, a); - assert_eq!(m, 0b00000101); + unsafe fn test_mm512_mask_max_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epu64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epu64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 4, 5, 6, 7); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpgt_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01100110; - let r = _mm512_mask_cmpgt_epi64_mask(mask, b, a); - assert_eq!(r, 0b00000100); + unsafe fn test_mm512_maskz_max_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epu64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epu64(0b00001111, a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmple_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - assert_eq!( - _mm512_cmple_epi64_mask(a, b), - !_mm512_cmpgt_epi64_mask(a, b) - ) + unsafe fn test_mm512_min_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epi64(a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 3, 2, 1, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmple_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01111010; - assert_eq!(_mm512_mask_cmple_epi64_mask(mask, a, b), 0b00110000); + unsafe fn test_mm512_mask_min_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpge_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - assert_eq!( - _mm512_cmpge_epi64_mask(a, b), - !_mm512_cmplt_epi64_mask(a, b) - ) + unsafe fn test_mm512_maskz_min_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epi64(0b00001111, a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpge_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01111010; - assert_eq!(_mm512_mask_cmpge_epi64_mask(mask, a, b), 0b0110000); + unsafe fn test_mm512_min_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_min_pd(a, b); + let e = _mm512_setr_pd(0., 1., 2., 3., 3., 2., 1., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpeq_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); - let m = _mm512_cmpeq_epi64_mask(b, a); - assert_eq!(m, 0b11001111); + unsafe fn test_mm512_mask_min_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_mask_min_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_min_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpeq_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); - let mask = 0b01111010; - let r = _mm512_mask_cmpeq_epi64_mask(mask, b, a); - assert_eq!(r, 0b01001010); + unsafe fn test_mm512_maskz_min_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_maskz_min_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_min_pd(0b00001111, a, b); + let e = _mm512_setr_pd(0., 1., 2., 3., 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set_epi64() { - let r = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); - assert_eq_m512i(r, _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0)) + unsafe fn test_mm512_min_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epu64(a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 3, 2, 1, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setr_epi64() { - let r = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); - assert_eq_m512i(r, _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0)) + unsafe fn test_mm512_mask_min_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epu64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epu64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + assert_eq_m512i(r, e); } - unsafe fn test_mm512_cmpneq_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); - let m = _mm512_cmpneq_epi64_mask(b, a); - assert_eq!(m, !_mm512_cmpeq_epi64_mask(b, a)); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epu64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epu64(0b00001111, a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpneq_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, -100, 100); - let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); - let mask = 0b01111010; - let r = _mm512_mask_cmpneq_epi64_mask(mask, b, a); - assert_eq!(r, 0b00110010) + unsafe fn test_mm512_sqrt_pd() { + let a = _mm512_setr_pd(0., 1., 4., 9., 16., 25., 36., 49.); + let r = _mm512_sqrt_pd(a); + let e = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let m = _mm512_cmp_epi64_mask(a, b, _MM_CMPINT_LT); - assert_eq!(m, 0b00000101); + unsafe fn test_mm512_mask_sqrt_pd() { + let a = _mm512_setr_pd(0., 1., 4., 9., 16., 25., 36., 49.); + let r = _mm512_mask_sqrt_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_sqrt_pd(a, 0b00001111, a); + let e = _mm512_setr_pd(0., 1., 2., 3., 16., 25., 36., 49.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_epi64_mask() { - let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); - let b = _mm512_set1_epi64(-1); - let mask = 0b01100110; - let r = _mm512_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_LT); - assert_eq!(r, 0b00000100); + unsafe fn test_mm512_maskz_sqrt_pd() { + let a = _mm512_setr_pd(0., 1., 4., 9., 16., 25., 36., 49.); + let r = _mm512_maskz_sqrt_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_sqrt_pd(0b00001111, a); + let e = _mm512_setr_pd(0., 1., 2., 3., 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32gather_pd() { - let mut arr = [0f64; 128]; - for i in 0..128 { - arr[i] = i as f64; - } - // A multiplier of 8 is word-addressing - #[rustfmt::skip] - let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); - let r = _mm512_i32gather_pd(index, arr.as_ptr() as *const u8, 8); - assert_eq_m512d(r, _mm512_setr_pd(0., 16., 32., 48., 64., 80., 96., 112.)); + unsafe fn test_mm512_fmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fmadd_pd(a, b, c); + let e = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32gather_pd() { - let mut arr = [0f64; 128]; - for i in 0..128 { - arr[i] = i as f64; - } - let src = _mm512_set1_pd(2.); - let mask = 0b10101010; - #[rustfmt::skip] - let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); - // A multiplier of 8 is word-addressing - let r = _mm512_mask_i32gather_pd(src, mask, index, arr.as_ptr() as *const u8, 8); - assert_eq_m512d(r, _mm512_setr_pd(2., 16., 2., 48., 2., 80., 2., 112.)); + unsafe fn test_mm512_mask_fmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fmadd_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmadd_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(1., 2., 3., 4., 1., 1., 1., 1.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i64gather_pd() { - let mut arr = [0f64; 128]; - for i in 0..128 { - arr[i] = i as f64; - } - // A multiplier of 8 is word-addressing - #[rustfmt::skip] - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let r = _mm512_i64gather_pd(index, arr.as_ptr() as *const u8, 8); - assert_eq_m512d(r, _mm512_setr_pd(0., 16., 32., 48., 64., 80., 96., 112.)); + unsafe fn test_mm512_maskz_fmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fmadd_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmadd_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(1., 2., 3., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i64gather_pd() { - let mut arr = [0f64; 128]; - for i in 0..128 { - arr[i] = i as f64; - } - let src = _mm512_set1_pd(2.); - let mask = 0b10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - // A multiplier of 8 is word-addressing - let r = _mm512_mask_i64gather_pd(src, mask, index, arr.as_ptr() as *const u8, 8); - assert_eq_m512d(r, _mm512_setr_pd(2., 16., 2., 48., 2., 80., 2., 112.)); + unsafe fn test_mm512_mask3_fmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fmadd_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmadd_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(1., 2., 3., 4., 2., 2., 2., 2.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i64gather_ps() { - let mut arr = [0f32; 128]; - for i in 0..128 { - arr[i] = i as f32; - } - // A multiplier of 4 is word-addressing - #[rustfmt::skip] - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let r = _mm512_i64gather_ps(index, arr.as_ptr() as *const u8, 4); - assert_eq_m256(r, _mm256_setr_ps(0., 16., 32., 48., 64., 80., 96., 112.)); + unsafe fn test_mm512_fmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fmsub_pd(a, b, c); + let e = _mm512_setr_pd(-1., 0., 1., 2., 3., 4., 5., 6.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i64gather_ps() { - let mut arr = [0f32; 128]; - for i in 0..128 { - arr[i] = i as f32; - } - let src = _mm256_set1_ps(2.); - let mask = 0b10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - // A multiplier of 4 is word-addressing - let r = _mm512_mask_i64gather_ps(src, mask, index, arr.as_ptr() as *const u8, 4); - assert_eq_m256(r, _mm256_setr_ps(2., 16., 2., 48., 2., 80., 2., 112.)); + unsafe fn test_mm512_mask_fmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fmsub_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmsub_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(-1., 0., 1., 2., 1., 1., 1., 1.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32gather_epi64() { - let mut arr = [0i64; 128]; - for i in 0..128i64 { - arr[i as usize] = i; - } - // A multiplier of 8 is word-addressing - #[rustfmt::skip] - let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); - let r = _mm512_i32gather_epi64(index, arr.as_ptr() as *const u8, 8); - assert_eq_m512i(r, _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112)); + unsafe fn test_mm512_maskz_fmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fmsub_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmsub_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(-1., 0., 1., 2., 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32gather_epi64() { - let mut arr = [0i64; 128]; - for i in 0..128i64 { - arr[i as usize] = i; - } - let src = _mm512_set1_epi64(2); - let mask = 0b10101010; - #[rustfmt::skip] - let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); - // A multiplier of 8 is word-addressing - let r = _mm512_mask_i32gather_epi64(src, mask, index, arr.as_ptr() as *const u8, 8); - assert_eq_m512i(r, _mm512_setr_epi64(2, 16, 2, 48, 2, 80, 2, 112)); + unsafe fn test_mm512_mask3_fmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fmsub_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmsub_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(-1., 0., 1., 2., 2., 2., 2., 2.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i64gather_epi64() { - let mut arr = [0i64; 128]; - for i in 0..128i64 { - arr[i as usize] = i; - } - // A multiplier of 8 is word-addressing - #[rustfmt::skip] - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let r = _mm512_i64gather_epi64(index, arr.as_ptr() as *const u8, 8); - assert_eq_m512i(r, _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112)); + unsafe fn test_mm512_fmaddsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fmaddsub_pd(a, b, c); + let e = _mm512_setr_pd(-1., 2., 1., 4., 3., 6., 5., 8.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i64gather_epi64() { - let mut arr = [0i64; 128]; - for i in 0..128i64 { - arr[i as usize] = i; - } - let src = _mm512_set1_epi64(2); - let mask = 0b10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - // A multiplier of 8 is word-addressing - let r = _mm512_mask_i64gather_epi64(src, mask, index, arr.as_ptr() as *const u8, 8); - assert_eq_m512i(r, _mm512_setr_epi64(2, 16, 2, 48, 2, 80, 2, 112)); + unsafe fn test_mm512_mask_fmaddsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fmaddsub_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmaddsub_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(-1., 2., 1., 4., 1., 1., 1., 1.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i64gather_epi32() { - let mut arr = [0i64; 128]; - for i in 0..128i64 { - arr[i as usize] = i; - } - // A multiplier of 8 is word-addressing - #[rustfmt::skip] - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let r = _mm512_i64gather_epi32(index, arr.as_ptr() as *const u8, 8); - assert_eq_m256i(r, _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112)); + unsafe fn test_mm512_maskz_fmaddsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fmaddsub_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmaddsub_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(-1., 2., 1., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i64gather_epi32() { - let mut arr = [0i64; 128]; - for i in 0..128i64 { - arr[i as usize] = i; - } - let src = _mm256_set1_epi32(2); - let mask = 0b10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - // A multiplier of 8 is word-addressing - let r = _mm512_mask_i64gather_epi32(src, mask, index, arr.as_ptr() as *const u8, 8); - assert_eq_m256i(r, _mm256_setr_epi32(2, 16, 2, 48, 2, 80, 2, 112)); + unsafe fn test_mm512_mask3_fmaddsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fmaddsub_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmaddsub_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(-1., 2., 1., 4., 2., 2., 2., 2.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32scatter_pd() { - let mut arr = [0f64; 128]; - let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); - // A multiplier of 8 is word-addressing - _mm512_i32scatter_pd(arr.as_mut_ptr() as *mut u8, index, src, 8); - let mut expected = [0f64; 128]; - for i in 0..8 { - expected[i * 16] = (i + 1) as f64; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_fmsubadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fmsubadd_pd(a, b, c); + let e = _mm512_setr_pd(1., 0., 3., 2., 5., 4., 7., 6.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32scatter_pd() { - let mut arr = [0f64; 128]; - let mask = 0b10101010; - let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); - // A multiplier of 8 is word-addressing - _mm512_mask_i32scatter_pd(arr.as_mut_ptr() as *mut u8, mask, index, src, 8); - let mut expected = [0f64; 128]; - for i in 0..4 { - expected[i * 32 + 16] = 2. * (i + 1) as f64; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_mask_fmsubadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fmsubadd_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmsubadd_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(1., 0., 3., 2., 1., 1., 1., 1.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i64scatter_pd() { - let mut arr = [0f64; 128]; - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); - // A multiplier of 8 is word-addressing - _mm512_i64scatter_pd(arr.as_mut_ptr() as *mut u8, index, src, 8); - let mut expected = [0f64; 128]; - for i in 0..8 { - expected[i * 16] = (i + 1) as f64; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_maskz_fmsubadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fmsubadd_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmsubadd_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(1., 0., 3., 2., 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i64scatter_pd() { - let mut arr = [0f64; 128]; - let mask = 0b10101010; - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); - // A multiplier of 8 is word-addressing - _mm512_mask_i64scatter_pd(arr.as_mut_ptr() as *mut u8, mask, index, src, 8); - let mut expected = [0f64; 128]; - for i in 0..4 { - expected[i * 32 + 16] = 2. * (i + 1) as f64; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_mask3_fmsubadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fmsubadd_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmsubadd_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(1., 0., 3., 2., 2., 2., 2., 2.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i64scatter_ps() { - let mut arr = [0f32; 128]; - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm256_setr_ps(1., 2., 3., 4., 5., 6., 7., 8.); - // A multiplier of 4 is word-addressing - _mm512_i64scatter_ps(arr.as_mut_ptr() as *mut u8, index, src, 4); - let mut expected = [0f32; 128]; - for i in 0..8 { - expected[i * 16] = (i + 1) as f32; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_fnmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fnmadd_pd(a, b, c); + let e = _mm512_setr_pd(1., 0., -1., -2., -3., -4., -5., -6.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i64scatter_ps() { - let mut arr = [0f32; 128]; - let mask = 0b10101010; - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm256_setr_ps(1., 2., 3., 4., 5., 6., 7., 8.); - // A multiplier of 4 is word-addressing - _mm512_mask_i64scatter_ps(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); - let mut expected = [0f32; 128]; - for i in 0..4 { - expected[i * 32 + 16] = 2. * (i + 1) as f32; + unsafe fn test_mm512_mask_fnmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fnmadd_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fnmadd_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(1., 0., -1., -2., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fnmadd_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fnmadd_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(1., 0., -1., -2., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fnmadd_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fnmadd_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(1., 0., -1., -2., 2., 2., 2., 2.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fnmsub_pd(a, b, c); + let e = _mm512_setr_pd(-1., -2., -3., -4., -5., -6., -7., -8.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fnmsub_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fnmsub_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(-1., -2., -3., -4., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fnmsub_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fnmsub_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(-1., -2., -3., -4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fnmsub_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fnmsub_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(-1., -2., -3., -4., 2., 2., 2., 2.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rcp14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_rcp14_pd(a); + let e = _mm512_set1_pd(0.3333320617675781); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rcp14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_rcp14_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_rcp14_pd(a, 0b11110000, a); + let e = _mm512_setr_pd( + 3., + 3., + 3., + 3., + 0.3333320617675781, + 0.3333320617675781, + 0.3333320617675781, + 0.3333320617675781, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rcp14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_rcp14_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_rcp14_pd(0b11110000, a); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 0.3333320617675781, + 0.3333320617675781, + 0.3333320617675781, + 0.3333320617675781, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rsqrt14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_rsqrt14_pd(a); + let e = _mm512_set1_pd(0.5773391723632813); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rsqrt14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_rsqrt14_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_rsqrt14_pd(a, 0b11110000, a); + let e = _mm512_setr_pd( + 3., + 3., + 3., + 3., + 0.5773391723632813, + 0.5773391723632813, + 0.5773391723632813, + 0.5773391723632813, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rsqrt14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_rsqrt14_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_rsqrt14_pd(0b11110000, a); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 0.5773391723632813, + 0.5773391723632813, + 0.5773391723632813, + 0.5773391723632813, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_getexp_pd(a); + let e = _mm512_set1_pd(1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_getexp_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_getexp_pd(a, 0b11110000, a); + let e = _mm512_setr_pd(3., 3., 3., 3., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_getexp_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_getexp_pd(0b11110000, a); + let e = _mm512_setr_pd(0., 0., 0., 0., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_getmant_pd(a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm512_set1_pd(1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_mask_getmant_pd(a, 0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512d(r, a); + let r = _mm512_mask_getmant_pd(a, 0b11110000, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm512_setr_pd(10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_maskz_getmant_pd(0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_getmant_pd(0b11110000, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm512_setr_pd(0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvtps_pd(a); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm512_set1_pd(0.); + let r = _mm512_mask_cvtps_pd(src, 0, a); + assert_eq_m512d(r, src); + let r = _mm512_mask_cvtps_pd(src, 0b00001111, a); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvtps_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_cvtps_pd(0b00001111, a); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvtt_roundpd_epi32(a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvtt_roundpd_epi32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtt_roundpd_epi32(src, 0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvtt_roundpd_epi32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtt_roundpd_epi32(0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvtt_roundpd_epu32(a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvtt_roundpd_epu32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtt_roundpd_epu32(src, 0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvtt_roundpd_epu32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtt_roundpd_epu32(0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvttpd_epi32(a); + let e = _mm256_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvttpd_epi32(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvttpd_epi32(src, 0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvttpd_epi32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvttpd_epi32(0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvttpd_epu32(a); + let e = _mm256_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvttpd_epu32(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvttpd_epu32(src, 0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvttpd_epu32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvttpd_epu32(0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(-1.); + let r = _mm512_add_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + let r = _mm512_add_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(-1.); + let r = _mm512_mask_add_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_add_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(8., 9.5, 10., 11.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(-1.); + let r = _mm512_maskz_add_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_add_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(0., 0., 0., 0., 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(1.); + let r = _mm512_sub_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + let r = _mm512_sub_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(1.); + let r = _mm512_mask_sub_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_sub_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(8., 9.5, 10., 11.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(1.); + let r = _mm512_maskz_sub_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_sub_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(0., 0., 0., 0., 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.); + let b = _mm512_set1_pd(0.1); + let r = _mm512_mul_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd( + 0.8, + 0.9500000000000001, + 1., + 1.1500000000000001, + 1.2000000000000002, + 1.35, + 1.4000000000000001, + 0., + ); + assert_eq_m512d(r, e); + let r = _mm512_mul_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(0.8, 0.95, 1.0, 1.15, 1.2, 1.3499999999999999, 1.4, 0.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.); + let b = _mm512_set1_pd(0.1); + let r = _mm512_mask_mul_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_mul_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 8., + 9.5, + 10., + 11.5, + 1.2000000000000002, + 1.35, + 1.4000000000000001, + 0., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.); + let b = _mm512_set1_pd(0.1); + let r = _mm512_maskz_mul_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_mul_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 1.2000000000000002, + 1.35, + 1.4000000000000001, + 0., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_div_round_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_div_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(0.3333333333333333); + assert_eq_m512d(r, e); + let r = _mm512_div_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(0.33333333333333334); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_div_round_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_mask_div_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_div_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 1., + 1., + 1., + 1., + 0.3333333333333333, + 0.3333333333333333, + 0.3333333333333333, + 0.3333333333333333, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_div_round_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_maskz_div_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_div_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 0.3333333333333333, + 0.3333333333333333, + 0.3333333333333333, + 0.3333333333333333, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sqrt_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_sqrt_round_pd(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(1.7320508075688772); + assert_eq_m512d(r, e); + let r = _mm512_sqrt_round_pd(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(1.7320508075688774); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sqrt_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_sqrt_round_pd(a, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_sqrt_round_pd( + a, + 0b11110000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 3., + 3., + 3., + 3., + 1.7320508075688772, + 1.7320508075688772, + 1.7320508075688772, + 1.7320508075688772, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sqrt_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_sqrt_round_pd(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_sqrt_round_pd( + 0b11110000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 1.7320508075688772, + 1.7320508075688772, + 1.7320508075688772, + 1.7320508075688772, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_fmadd_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(-1.); + assert_eq_m512d(r, e); + let r = _mm512_fmadd_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(-0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_mask_fmadd_round_pd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmadd_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + -1., + -1., + -1., + -1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_maskz_fmadd_round_pd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmadd_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., -1., -1., -1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_mask3_fmadd_round_pd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmadd_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., -1., -1., -1., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = _mm512_fmsub_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(-1.); + assert_eq_m512d(r, e); + let r = _mm512_fmsub_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(-0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_mask_fmsub_round_pd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmsub_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + -1., + -1., + -1., + -1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_maskz_fmsub_round_pd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmsub_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., -1., -1., -1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_mask3_fmsub_round_pd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmsub_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., -1., -1., -1., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmaddsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_fmaddsub_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(1., -1., 1., -1., 1., -1., 1., -1.); + assert_eq_m512d(r, e); + let r = _mm512_fmaddsub_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd( + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmaddsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_mask_fmaddsub_round_pd( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmaddsub_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 1., + -1., + 1., + -1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmaddsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_maskz_fmaddsub_round_pd( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmaddsub_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., -1., 1., -1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmaddsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_mask3_fmaddsub_round_pd( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmaddsub_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., -1., 1., -1., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsubadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_fmsubadd_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(-1., 1., -1., 1., -1., 1., -1., 1.); + assert_eq_m512d(r, e); + let r = _mm512_fmsubadd_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd( + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsubadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_mask_fmsubadd_round_pd( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmsubadd_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + -1., + 1., + -1., + 1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsubadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_maskz_fmsubadd_round_pd( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmsubadd_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., 1., -1., 1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsubadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_mask3_fmsubadd_round_pd( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmsubadd_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., 1., -1., 1., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = _mm512_fnmadd_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(1.); + assert_eq_m512d(r, e); + let r = _mm512_fnmadd_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_mask_fnmadd_round_pd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_fnmadd_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 1., + 1., + 1., + 1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_maskz_fnmadd_round_pd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fnmadd_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., 1., 1., 1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_mask3_fnmadd_round_pd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fnmadd_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_fnmsub_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(1.); + assert_eq_m512d(r, e); + let r = _mm512_fnmsub_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_mask_fnmsub_round_pd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_fnmsub_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 1., + 1., + 1., + 1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_maskz_fnmsub_round_pd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fnmsub_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., 1., 1., 1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_mask3_fnmsub_round_pd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fnmsub_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., 1., 1., 1., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_max_round_pd(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(7., 6., 5., 4., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_mask_max_round_pd(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, a); + let r = _mm512_mask_max_round_pd(a, 0b00001111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(7., 6., 5., 4., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_maskz_max_round_pd(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_max_round_pd(0b00001111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(7., 6., 5., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_min_round_pd(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., 1., 2., 3., 3., 2., 1., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_mask_min_round_pd(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, a); + let r = _mm512_mask_min_round_pd(a, 0b00001111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_maskz_min_round_pd(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_min_round_pd(0b00001111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., 1., 2., 3., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_getexp_round_pd(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_pd(1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_getexp_round_pd(a, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, a); + let r = _mm512_mask_getexp_round_pd(a, 0b11110000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(3., 3., 3., 3., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_getexp_round_pd(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_getexp_round_pd(0b11110000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., 0., 0., 0., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_round_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_getmant_round_pd( + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_set1_pd(1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_round_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_mask_getmant_round_pd( + a, + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512d(r, a); + let r = _mm512_mask_getmant_round_pd( + a, + 0b11110000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_pd(10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_round_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_maskz_getmant_round_pd( + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_getmant_round_pd( + 0b11110000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_pd(0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvt_roundps_pd(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm512_set1_pd(0.); + let r = _mm512_mask_cvt_roundps_pd(src, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, src); + let r = _mm512_mask_cvt_roundps_pd(src, 0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvt_roundps_pd(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_cvt_roundps_pd(0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_setzero_pd() { + assert_eq_m512d(_mm512_setzero_pd(), _mm512_set1_pd(0.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_set1_pd() { + let expected = _mm512_set_pd(2., 2., 2., 2., 2., 2., 2., 2.); + assert_eq_m512d(expected, _mm512_set1_pd(2.)); + } + + unsafe fn test_mm512_set1_epi64() { + let r = _mm512_set_epi64(2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, _mm512_set1_epi64(2)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmplt_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let m = _mm512_cmplt_pd_mask(a, b); + assert_eq!(m, 0b00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmplt_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let mask = 0b01100110; + let r = _mm512_mask_cmplt_pd_mask(mask, a, b); + assert_eq!(r, 0b00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpnlt_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + assert_eq!(_mm512_cmpnlt_pd_mask(a, b), !_mm512_cmplt_pd_mask(a, b)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpnlt_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let mask = 0b01111010; + assert_eq!(_mm512_mask_cmpnlt_pd_mask(mask, a, b), 0b01111010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmple_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + assert_eq!(_mm512_cmple_pd_mask(a, b), 0b00100101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmple_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let mask = 0b01111010; + assert_eq!(_mm512_mask_cmple_pd_mask(mask, a, b), 0b00100000); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpnle_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let m = _mm512_cmpnle_pd_mask(b, a); + assert_eq!(m, 0b00001101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpnle_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., f64::MAX, f64::NAN, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let mask = 0b01100110; + let r = _mm512_mask_cmpnle_pd_mask(mask, b, a); + assert_eq!(r, 0b00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpeq_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, f64::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_pd(0., 1., 13., 42., f64::MAX, f64::MIN, f64::NAN, -100.); + let m = _mm512_cmpeq_pd_mask(b, a); + assert_eq!(m, 0b11001101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpeq_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, f64::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_pd(0., 1., 13., 42., f64::MAX, f64::MIN, f64::NAN, -100.); + let mask = 0b01111010; + let r = _mm512_mask_cmpeq_pd_mask(mask, b, a); + assert_eq!(r, 0b01001000); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpneq_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, f64::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_pd(0., 1., 13., 42., f64::MAX, f64::MIN, f64::NAN, -100.); + let m = _mm512_cmpneq_pd_mask(b, a); + assert_eq!(m, 0b00110010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpneq_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, f64::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_pd(0., 1., 13., 42., f64::MAX, f64::MIN, f64::NAN, -100.); + let mask = 0b01111010; + let r = _mm512_mask_cmpneq_pd_mask(mask, b, a); + assert_eq!(r, 0b00110010) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmp_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let m = _mm512_cmp_pd_mask(a, b, _CMP_LT_OQ); + assert_eq!(m, 0b00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmp_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let mask = 0b01100110; + let r = _mm512_mask_cmp_pd_mask(mask, a, b, _CMP_LT_OQ); + assert_eq!(r, 0b00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmp_round_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let m = _mm512_cmp_round_pd_mask(a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 0b00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmp_round_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(0., 1., -1., 13., f64::MAX, f64::MIN, 100., -100.); + let b = _mm512_set1_pd(-1.); + let mask = 0b01100110; + let r = _mm512_mask_cmp_round_pd_mask(mask, a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); + assert_eq!(r, 0b00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpord_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(f64::NAN, f64::MAX, f64::NAN, f64::MIN, f64::NAN, -1., f64::NAN, 0.); + #[rustfmt::skip] + let b = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::MIN, f64::MAX, -1., 0.); + let m = _mm512_cmpord_pd_mask(a, b); + assert_eq!(m, 0b00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpord_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(f64::NAN, f64::MAX, f64::NAN, f64::MIN, f64::NAN, -1., f64::NAN, 0.); + #[rustfmt::skip] + let b = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::MIN, f64::MAX, -1., 0.); + let mask = 0b11000011; + let m = _mm512_mask_cmpord_pd_mask(mask, a, b); + assert_eq!(m, 0b00000001); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpunord_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(f64::NAN, f64::MAX, f64::NAN, f64::MIN, f64::NAN, -1., f64::NAN, 0.); + #[rustfmt::skip] + let b = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::MIN, f64::MAX, -1., 0.); + let m = _mm512_cmpunord_pd_mask(a, b); + + assert_eq!(m, 0b11111010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpunord_pd_mask() { + #[rustfmt::skip] + let a = _mm512_set_pd(f64::NAN, f64::MAX, f64::NAN, f64::MIN, f64::NAN, -1., f64::NAN, 0.); + #[rustfmt::skip] + let b = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::MIN, f64::MAX, -1., 0.); + let mask = 0b00001111; + let m = _mm512_mask_cmpunord_pd_mask(mask, a, b); + assert_eq!(m, 0b000001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmplt_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let m = _mm512_cmplt_epu64_mask(a, b); + assert_eq!(m, 0b11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmplt_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01111010; + let r = _mm512_mask_cmplt_epu64_mask(mask, a, b); + assert_eq!(r, 0b01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpgt_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let m = _mm512_cmpgt_epu64_mask(b, a); + assert_eq!(m, 0b11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpgt_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01111010; + let r = _mm512_mask_cmpgt_epu64_mask(mask, b, a); + assert_eq!(r, 0b01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmple_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + assert_eq!( + _mm512_cmple_epu64_mask(a, b), + !_mm512_cmpgt_epu64_mask(a, b) + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmple_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01111010; + assert_eq!(_mm512_mask_cmple_epu64_mask(mask, a, b), 0b01111010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpge_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + assert_eq!( + _mm512_cmpge_epu64_mask(a, b), + !_mm512_cmplt_epu64_mask(a, b) + ); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpge_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01111010; + assert_eq!(_mm512_mask_cmpge_epu64_mask(mask, a, b), 0b01111010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpeq_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); + let m = _mm512_cmpeq_epu64_mask(b, a); + assert_eq!(m, 0b11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpeq_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); + let mask = 0b01111010; + let r = _mm512_mask_cmpeq_epu64_mask(mask, b, a); + assert_eq!(r, 0b01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpneq_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); + let m = _mm512_cmpneq_epu64_mask(b, a); + assert_eq!(m, !_mm512_cmpeq_epu64_mask(b, a)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpneq_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, -100, 100); + let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); + let mask = 0b01111010; + let r = _mm512_mask_cmpneq_epu64_mask(mask, b, a); + assert_eq!(r, 0b00110010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmp_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let m = _mm512_cmp_epu64_mask(a, b, _MM_CMPINT_LT); + assert_eq!(m, 0b11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmp_epu64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01111010; + let r = _mm512_mask_cmp_epu64_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!(r, 0b01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmplt_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let m = _mm512_cmplt_epi64_mask(a, b); + assert_eq!(m, 0b00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmplt_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01100110; + let r = _mm512_mask_cmplt_epi64_mask(mask, a, b); + assert_eq!(r, 0b00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpgt_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let m = _mm512_cmpgt_epi64_mask(b, a); + assert_eq!(m, 0b00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpgt_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01100110; + let r = _mm512_mask_cmpgt_epi64_mask(mask, b, a); + assert_eq!(r, 0b00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmple_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + assert_eq!( + _mm512_cmple_epi64_mask(a, b), + !_mm512_cmpgt_epi64_mask(a, b) + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmple_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01111010; + assert_eq!(_mm512_mask_cmple_epi64_mask(mask, a, b), 0b00110000); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpge_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + assert_eq!( + _mm512_cmpge_epi64_mask(a, b), + !_mm512_cmplt_epi64_mask(a, b) + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpge_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01111010; + assert_eq!(_mm512_mask_cmpge_epi64_mask(mask, a, b), 0b0110000); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpeq_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); + let m = _mm512_cmpeq_epi64_mask(b, a); + assert_eq!(m, 0b11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpeq_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); + let mask = 0b01111010; + let r = _mm512_mask_cmpeq_epi64_mask(mask, b, a); + assert_eq!(r, 0b01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_set_epi64() { + let r = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + assert_eq_m512i(r, _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0)) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_setr_epi64() { + let r = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + assert_eq_m512i(r, _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0)) + } + + unsafe fn test_mm512_cmpneq_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); + let m = _mm512_cmpneq_epi64_mask(b, a); + assert_eq!(m, !_mm512_cmpeq_epi64_mask(b, a)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpneq_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, -100, 100); + let b = _mm512_set_epi64(0, 1, 13, 42, i64::MAX, i64::MIN, 100, -100); + let mask = 0b01111010; + let r = _mm512_mask_cmpneq_epi64_mask(mask, b, a); + assert_eq!(r, 0b00110010) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmp_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let m = _mm512_cmp_epi64_mask(a, b, _MM_CMPINT_LT); + assert_eq!(m, 0b00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmp_epi64_mask() { + let a = _mm512_set_epi64(0, 1, -1, 13, i64::MAX, i64::MIN, 100, -100); + let b = _mm512_set1_epi64(-1); + let mask = 0b01100110; + let r = _mm512_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!(r, 0b00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32gather_pd() { + let mut arr = [0f64; 128]; + for i in 0..128 { + arr[i] = i as f64; + } + // A multiplier of 8 is word-addressing + #[rustfmt::skip] + let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); + let r = _mm512_i32gather_pd(index, arr.as_ptr() as *const u8, 8); + assert_eq_m512d(r, _mm512_setr_pd(0., 16., 32., 48., 64., 80., 96., 112.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32gather_pd() { + let mut arr = [0f64; 128]; + for i in 0..128 { + arr[i] = i as f64; + } + let src = _mm512_set1_pd(2.); + let mask = 0b10101010; + #[rustfmt::skip] + let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); + // A multiplier of 8 is word-addressing + let r = _mm512_mask_i32gather_pd(src, mask, index, arr.as_ptr() as *const u8, 8); + assert_eq_m512d(r, _mm512_setr_pd(2., 16., 2., 48., 2., 80., 2., 112.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i64gather_pd() { + let mut arr = [0f64; 128]; + for i in 0..128 { + arr[i] = i as f64; + } + // A multiplier of 8 is word-addressing + #[rustfmt::skip] + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let r = _mm512_i64gather_pd(index, arr.as_ptr() as *const u8, 8); + assert_eq_m512d(r, _mm512_setr_pd(0., 16., 32., 48., 64., 80., 96., 112.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i64gather_pd() { + let mut arr = [0f64; 128]; + for i in 0..128 { + arr[i] = i as f64; + } + let src = _mm512_set1_pd(2.); + let mask = 0b10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + // A multiplier of 8 is word-addressing + let r = _mm512_mask_i64gather_pd(src, mask, index, arr.as_ptr() as *const u8, 8); + assert_eq_m512d(r, _mm512_setr_pd(2., 16., 2., 48., 2., 80., 2., 112.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i64gather_ps() { + let mut arr = [0f32; 128]; + for i in 0..128 { + arr[i] = i as f32; + } + // A multiplier of 4 is word-addressing + #[rustfmt::skip] + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let r = _mm512_i64gather_ps(index, arr.as_ptr() as *const u8, 4); + assert_eq_m256(r, _mm256_setr_ps(0., 16., 32., 48., 64., 80., 96., 112.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i64gather_ps() { + let mut arr = [0f32; 128]; + for i in 0..128 { + arr[i] = i as f32; + } + let src = _mm256_set1_ps(2.); + let mask = 0b10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + // A multiplier of 4 is word-addressing + let r = _mm512_mask_i64gather_ps(src, mask, index, arr.as_ptr() as *const u8, 4); + assert_eq_m256(r, _mm256_setr_ps(2., 16., 2., 48., 2., 80., 2., 112.)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32gather_epi64() { + let mut arr = [0i64; 128]; + for i in 0..128i64 { + arr[i as usize] = i; + } + // A multiplier of 8 is word-addressing + #[rustfmt::skip] + let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); + let r = _mm512_i32gather_epi64(index, arr.as_ptr() as *const u8, 8); + assert_eq_m512i(r, _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32gather_epi64() { + let mut arr = [0i64; 128]; + for i in 0..128i64 { + arr[i as usize] = i; + } + let src = _mm512_set1_epi64(2); + let mask = 0b10101010; + #[rustfmt::skip] + let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); + // A multiplier of 8 is word-addressing + let r = _mm512_mask_i32gather_epi64(src, mask, index, arr.as_ptr() as *const u8, 8); + assert_eq_m512i(r, _mm512_setr_epi64(2, 16, 2, 48, 2, 80, 2, 112)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i64gather_epi64() { + let mut arr = [0i64; 128]; + for i in 0..128i64 { + arr[i as usize] = i; + } + // A multiplier of 8 is word-addressing + #[rustfmt::skip] + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let r = _mm512_i64gather_epi64(index, arr.as_ptr() as *const u8, 8); + assert_eq_m512i(r, _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i64gather_epi64() { + let mut arr = [0i64; 128]; + for i in 0..128i64 { + arr[i as usize] = i; + } + let src = _mm512_set1_epi64(2); + let mask = 0b10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + // A multiplier of 8 is word-addressing + let r = _mm512_mask_i64gather_epi64(src, mask, index, arr.as_ptr() as *const u8, 8); + assert_eq_m512i(r, _mm512_setr_epi64(2, 16, 2, 48, 2, 80, 2, 112)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i64gather_epi32() { + let mut arr = [0i64; 128]; + for i in 0..128i64 { + arr[i as usize] = i; + } + // A multiplier of 8 is word-addressing + #[rustfmt::skip] + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let r = _mm512_i64gather_epi32(index, arr.as_ptr() as *const u8, 8); + assert_eq_m256i(r, _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i64gather_epi32() { + let mut arr = [0i64; 128]; + for i in 0..128i64 { + arr[i as usize] = i; + } + let src = _mm256_set1_epi32(2); + let mask = 0b10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + // A multiplier of 8 is word-addressing + let r = _mm512_mask_i64gather_epi32(src, mask, index, arr.as_ptr() as *const u8, 8); + assert_eq_m256i(r, _mm256_setr_epi32(2, 16, 2, 48, 2, 80, 2, 112)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32scatter_pd() { + let mut arr = [0f64; 128]; + let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + // A multiplier of 8 is word-addressing + _mm512_i32scatter_pd(arr.as_mut_ptr() as *mut u8, index, src, 8); + let mut expected = [0f64; 128]; + for i in 0..8 { + expected[i * 16] = (i + 1) as f64; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32scatter_pd() { + let mut arr = [0f64; 128]; + let mask = 0b10101010; + let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + // A multiplier of 8 is word-addressing + _mm512_mask_i32scatter_pd(arr.as_mut_ptr() as *mut u8, mask, index, src, 8); + let mut expected = [0f64; 128]; + for i in 0..4 { + expected[i * 32 + 16] = 2. * (i + 1) as f64; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i64scatter_pd() { + let mut arr = [0f64; 128]; + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + // A multiplier of 8 is word-addressing + _mm512_i64scatter_pd(arr.as_mut_ptr() as *mut u8, index, src, 8); + let mut expected = [0f64; 128]; + for i in 0..8 { + expected[i * 16] = (i + 1) as f64; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i64scatter_pd() { + let mut arr = [0f64; 128]; + let mask = 0b10101010; + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + // A multiplier of 8 is word-addressing + _mm512_mask_i64scatter_pd(arr.as_mut_ptr() as *mut u8, mask, index, src, 8); + let mut expected = [0f64; 128]; + for i in 0..4 { + expected[i * 32 + 16] = 2. * (i + 1) as f64; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i64scatter_ps() { + let mut arr = [0f32; 128]; + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm256_setr_ps(1., 2., 3., 4., 5., 6., 7., 8.); + // A multiplier of 4 is word-addressing + _mm512_i64scatter_ps(arr.as_mut_ptr() as *mut u8, index, src, 4); + let mut expected = [0f32; 128]; + for i in 0..8 { + expected[i * 16] = (i + 1) as f32; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i64scatter_ps() { + let mut arr = [0f32; 128]; + let mask = 0b10101010; + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm256_setr_ps(1., 2., 3., 4., 5., 6., 7., 8.); + // A multiplier of 4 is word-addressing + _mm512_mask_i64scatter_ps(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); + let mut expected = [0f32; 128]; + for i in 0..4 { + expected[i * 32 + 16] = 2. * (i + 1) as f32; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32scatter_epi64() { + let mut arr = [0i64; 128]; + let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); + // A multiplier of 8 is word-addressing + _mm512_i32scatter_epi64(arr.as_mut_ptr() as *mut u8, index, src, 8); + let mut expected = [0i64; 128]; + for i in 0..8 { + expected[i * 16] = (i + 1) as i64; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32scatter_epi64() { + let mut arr = [0i64; 128]; + let mask = 0b10101010; + let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); + // A multiplier of 8 is word-addressing + _mm512_mask_i32scatter_epi64(arr.as_mut_ptr() as *mut u8, mask, index, src, 8); + let mut expected = [0i64; 128]; + for i in 0..4 { + expected[i * 32 + 16] = 2 * (i + 1) as i64; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i64scatter_epi64() { + let mut arr = [0i64; 128]; + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); + // A multiplier of 8 is word-addressing + _mm512_i64scatter_epi64(arr.as_mut_ptr() as *mut u8, index, src, 8); + let mut expected = [0i64; 128]; + for i in 0..8 { + expected[i * 16] = (i + 1) as i64; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i64scatter_epi64() { + let mut arr = [0i64; 128]; + let mask = 0b10101010; + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); + // A multiplier of 8 is word-addressing + _mm512_mask_i64scatter_epi64(arr.as_mut_ptr() as *mut u8, mask, index, src, 8); + let mut expected = [0i64; 128]; + for i in 0..4 { + expected[i * 32 + 16] = 2 * (i + 1) as i64; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i64scatter_epi32() { + let mut arr = [0i32; 128]; + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); + // A multiplier of 4 is word-addressing + _mm512_i64scatter_epi32(arr.as_mut_ptr() as *mut u8, index, src, 4); + let mut expected = [0i32; 128]; + for i in 0..8 { + expected[i * 16] = (i + 1) as i32; + } + assert_eq!(&arr[..], &expected[..],); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i64scatter_epi32() { + let mut arr = [0i32; 128]; + let mask = 0b10101010; + let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); + let src = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); + // A multiplier of 4 is word-addressing + _mm512_mask_i64scatter_epi32(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); + let mut expected = [0i32; 128]; + for i in 0..4 { + expected[i * 32 + 16] = 2 * (i + 1) as i32; } assert_eq!(&arr[..], &expected[..],); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32scatter_epi64() { - let mut arr = [0i64; 128]; - let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); - // A multiplier of 8 is word-addressing - _mm512_i32scatter_epi64(arr.as_mut_ptr() as *mut u8, index, src, 8); - let mut expected = [0i64; 128]; - for i in 0..8 { - expected[i * 16] = (i + 1) as i64; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_rol_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_rol_epi64(a, 1); + let e = _mm512_set_epi64( + 1 << 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rol_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_mask_rol_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rol_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64( + 1 << 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rol_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 63, + ); + let r = _mm512_maskz_rol_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rol_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 33, 1 << 33, 1 << 33, 1 << 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_ror_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_ror_epi64(a, 1); + let e = _mm512_set_epi64( + 1 << 63, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_ror_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_mask_ror_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_ror_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64( + 1 << 63, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_ror_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let r = _mm512_maskz_ror_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_ror_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 31, 1 << 31, 1 << 31, 1 << 63); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_slli_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_slli_epi64(a, 1); + let e = _mm512_set_epi64( + 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_slli_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_mask_slli_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_slli_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64( + 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_slli_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 63, + ); + let r = _mm512_maskz_slli_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_slli_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 33, 1 << 33, 1 << 33, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srli_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_srli_epi64(a, 1); + let e = _mm512_set_epi64( + 0, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srli_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_mask_srli_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srli_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64( + 0, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srli_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let r = _mm512_maskz_srli_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srli_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 31, 1 << 31, 1 << 31, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rolv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_rolv_epi64(a, b); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 34, + 1 << 35, + 1 << 36, + 1 << 37, + 1 << 38, + 1 << 39, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rolv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_rolv_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rolv_epi64(a, 0b11111111, a, b); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 34, + 1 << 35, + 1 << 36, + 1 << 37, + 1 << 38, + 1 << 39, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rolv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 62, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 2); + let r = _mm512_maskz_rolv_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rolv_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 36, 1 << 37, 1 << 38, 1 << 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rorv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_rorv_epi64(a, b); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 30, + 1 << 29, + 1 << 28, + 1 << 27, + 1 << 26, + 1 << 25, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rorv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_rorv_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rorv_epi64(a, 0b11111111, a, b); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 30, + 1 << 29, + 1 << 28, + 1 << 27, + 1 << 26, + 1 << 25, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rorv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 2); + let r = _mm512_maskz_rorv_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rorv_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 28, 1 << 27, 1 << 26, 1 << 62); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sllv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm512_set_epi64(0, 2, 2, 3, 4, 5, 6, 7); + let r = _mm512_sllv_epi64(a, count); + let e = _mm512_set_epi64( + 1 << 32, + 0, + 1 << 34, + 1 << 35, + 1 << 36, + 1 << 37, + 1 << 38, + 1 << 39, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sllv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_sllv_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sllv_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 33, + 0, + 1 << 35, + 1 << 36, + 1 << 37, + 1 << 38, + 1 << 39, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sllv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 63, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 1); + let r = _mm512_maskz_sllv_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sllv_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 36, 1 << 37, 1 << 38, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srlv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_srlv_epi64(a, count); + let e = _mm512_set_epi64( + 1 << 32, + 0, + 1 << 30, + 1 << 29, + 1 << 28, + 1 << 27, + 1 << 26, + 1 << 25, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srlv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_srlv_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srlv_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64( + 1 << 32, + 0, + 1 << 30, + 1 << 29, + 1 << 28, + 1 << 27, + 1 << 26, + 1 << 25, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srlv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_maskz_srlv_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srlv_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 28, 1 << 27, 1 << 26, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sll_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_sll_epi64(a, count); + let e = _mm512_set_epi64( + 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + + let count = _mm_set_epi64x(1, 0); + let r = _mm512_sll_epi64(a, count); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sll_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_mask_sll_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sll_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64( + 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sll_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 63, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_maskz_sll_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sll_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 33, 1 << 33, 1 << 33, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srl_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_srl_epi64(a, count); + let e = _mm512_set_epi64( + 0, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srl_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_mask_srl_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srl_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64( + 0, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srl_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_maskz_srl_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srl_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 31, 1 << 31, 1 << 31, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32scatter_epi64() { - let mut arr = [0i64; 128]; - let mask = 0b10101010; - let index = _mm256_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); - // A multiplier of 8 is word-addressing - _mm512_mask_i32scatter_epi64(arr.as_mut_ptr() as *mut u8, mask, index, src, 8); - let mut expected = [0i64; 128]; - for i in 0..4 { - expected[i * 32 + 16] = 2 * (i + 1) as i64; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_sra_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm_set_epi64x(0, 2); + let r = _mm512_sra_epi64(a, count); + let e = _mm512_set_epi64(0, -2, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i64scatter_epi64() { - let mut arr = [0i64; 128]; - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); - // A multiplier of 8 is word-addressing - _mm512_i64scatter_epi64(arr.as_mut_ptr() as *mut u8, index, src, 8); - let mut expected = [0i64; 128]; - for i in 0..8 { - expected[i * 16] = (i + 1) as i64; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_mask_sra_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm_set_epi64x(0, 2); + let r = _mm512_mask_sra_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sra_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64(0, -2, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i64scatter_epi64() { - let mut arr = [0i64; 128]; - let mask = 0b10101010; - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); - // A multiplier of 8 is word-addressing - _mm512_mask_i64scatter_epi64(arr.as_mut_ptr() as *mut u8, mask, index, src, 8); - let mut expected = [0i64; 128]; - for i in 0..4 { - expected[i * 32 + 16] = 2 * (i + 1) as i64; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_maskz_sra_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm_set_epi64x(0, 2); + let r = _mm512_maskz_sra_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sra_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i64scatter_epi32() { - let mut arr = [0i32; 128]; - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); - // A multiplier of 4 is word-addressing - _mm512_i64scatter_epi32(arr.as_mut_ptr() as *mut u8, index, src, 4); - let mut expected = [0i32; 128]; - for i in 0..8 { - expected[i * 16] = (i + 1) as i32; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_srav_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm512_set_epi64(2, 2, 0, 0, 0, 0, 2, 1); + let r = _mm512_srav_epi64(a, count); + let e = _mm512_set_epi64(0, -2, 0, 0, 0, 0, 3, -8); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i64scatter_epi32() { - let mut arr = [0i32; 128]; - let mask = 0b10101010; - let index = _mm512_setr_epi64(0, 16, 32, 48, 64, 80, 96, 112); - let src = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); - // A multiplier of 4 is word-addressing - _mm512_mask_i64scatter_epi32(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); - let mut expected = [0i32; 128]; - for i in 0..4 { - expected[i * 32 + 16] = 2 * (i + 1) as i32; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_mask_srav_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm512_set_epi64(2, 2, 0, 0, 0, 0, 2, 1); + let r = _mm512_mask_srav_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srav_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64(0, -2, 0, 0, 0, 0, 3, -8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srav_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm512_set_epi64(2, 2, 0, 0, 0, 0, 2, 1); + let r = _mm512_maskz_srav_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srav_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 3, -8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srai_epi64() { + let a = _mm512_set_epi64(1, -4, 15, 0, 0, 0, 0, -16); + let r = _mm512_srai_epi64(a, 2); + let e = _mm512_set_epi64(0, -1, 3, 0, 0, 0, 0, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srai_epi64() { + let a = _mm512_set_epi64(1, -4, 15, 0, 0, 0, 0, -16); + let r = _mm512_mask_srai_epi64(a, 0, a, 2); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srai_epi64(a, 0b11111111, a, 2); + let e = _mm512_set_epi64(0, -1, 3, 0, 0, 0, 0, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srai_epi64() { + let a = _mm512_set_epi64(1, -4, 15, 0, 0, 0, 0, -16); + let r = _mm512_maskz_srai_epi64(0, a, 2); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srai_epi64(0b00001111, a, 2); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permute_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_permute_pd(a, 1); + let e = _mm512_set_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permute_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_mask_permute_pd(a, 0, a, 1); + assert_eq_m512d(r, a); + let r = _mm512_mask_permute_pd(a, 0b11111111, a, 1); + let e = _mm512_set_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permute_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_maskz_permute_pd(0, a, 1); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permute_pd(0b00001111, a, 1); + let e = _mm512_set_pd(0., 0., 0., 0., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_permutex_epi64(a, 1); + let e = _mm512_set_epi64(6, 6, 6, 6, 6, 6, 6, 6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_permutex_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutex_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64(6, 6, 6, 6, 6, 6, 6, 6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_maskz_permutex_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutex_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 6, 6, 6, 6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_permutex_pd(a, 1); + let e = _mm512_set_pd(6., 6., 6., 6., 6., 6., 6., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_mask_permutex_pd(a, 0, a, 1); + assert_eq_m512d(r, a); + let r = _mm512_mask_permutex_pd(a, 0b11111111, a, 1); + let e = _mm512_set_pd(6., 6., 6., 6., 6., 6., 6., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_maskz_permutex_pd(0, a, 1); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permutex_pd(0b00001111, a, 1); + let e = _mm512_set_pd(0., 0., 0., 0., 6., 6., 6., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutevar_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_set1_epi64(1); + let r = _mm512_permutevar_pd(a, b); + let e = _mm512_set_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutevar_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_set1_epi64(1); + let r = _mm512_mask_permutevar_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_permutevar_pd(a, 0b11111111, a, b); + let e = _mm512_set_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutevar_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_set1_epi64(1); + let r = _mm512_maskz_permutevar_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permutevar_pd(0b00001111, a, b); + let e = _mm512_set_pd(0., 0., 0., 0., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_epi64() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_permutexvar_epi64(idx, a); + let e = _mm512_set1_epi64(6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutexvar_epi64() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_permutexvar_epi64(a, 0, idx, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutexvar_epi64(a, 0b11111111, idx, a); + let e = _mm512_set1_epi64(6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_epi64() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_maskz_permutexvar_epi64(0, idx, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutexvar_epi64(0b00001111, idx, a); + let e = _mm512_set_epi64(0, 0, 0, 0, 6, 6, 6, 6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_pd() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_permutexvar_pd(idx, a); + let e = _mm512_set1_pd(6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutexvar_pd() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_mask_permutexvar_pd(a, 0, idx, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_permutexvar_pd(a, 0b11111111, idx, a); + let e = _mm512_set1_pd(6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_pd() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_maskz_permutexvar_pd(0, idx, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permutexvar_pd(0b00001111, idx, a); + let e = _mm512_set_pd(0., 0., 0., 0., 6., 6., 6., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex2var_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_epi64(100); + let r = _mm512_permutex2var_epi64(a, idx, b); + let e = _mm512_set_epi64(6, 100, 5, 100, 4, 100, 3, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex2var_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_epi64(100); + let r = _mm512_mask_permutex2var_epi64(a, 0, idx, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutex2var_epi64(a, 0b11111111, idx, b); + let e = _mm512_set_epi64(6, 100, 5, 100, 4, 100, 3, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex2var_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_epi64(100); + let r = _mm512_maskz_permutex2var_epi64(0, a, idx, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutex2var_epi64(0b00001111, a, idx, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 4, 100, 3, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask2_permutex2var_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm512_set_epi64(1000, 1 << 3, 2000, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_epi64(100); + let r = _mm512_mask2_permutex2var_epi64(a, idx, 0, b); + assert_eq_m512i(r, idx); + let r = _mm512_mask2_permutex2var_epi64(a, idx, 0b00001111, b); + let e = _mm512_set_epi64(1000, 1 << 3, 2000, 1 << 3, 4, 100, 3, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex2var_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_pd(100.); + let r = _mm512_permutex2var_pd(a, idx, b); + let e = _mm512_set_pd(6., 100., 5., 100., 4., 100., 3., 100.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex2var_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_pd(100.); + let r = _mm512_mask_permutex2var_pd(a, 0, idx, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_permutex2var_pd(a, 0b11111111, idx, b); + let e = _mm512_set_pd(6., 100., 5., 100., 4., 100., 3., 100.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex2var_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_pd(100.); + let r = _mm512_maskz_permutex2var_pd(0, a, idx, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permutex2var_pd(0b00001111, a, idx, b); + let e = _mm512_set_pd(0., 0., 0., 0., 4., 100., 3., 100.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask2_permutex2var_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_pd(100.); + let r = _mm512_mask2_permutex2var_pd(a, idx, 0, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_mask2_permutex2var_pd(a, idx, 0b00001111, b); + let e = _mm512_set_pd(0., 0., 0., 0., 4., 100., 3., 100.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_pd() { + let a = _mm512_setr_pd(1., 4., 5., 8., 1., 4., 5., 8.); + let b = _mm512_setr_pd(2., 3., 6., 7., 2., 3., 6., 7.); + let r = _mm512_shuffle_pd( + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + let e = _mm512_setr_pd(4., 3., 8., 7., 4., 3., 8., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_pd() { + let a = _mm512_setr_pd(1., 4., 5., 8., 1., 4., 5., 8.); + let b = _mm512_setr_pd(2., 3., 6., 7., 2., 3., 6., 7.); + let r = _mm512_mask_shuffle_pd( + a, + 0, + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + assert_eq_m512d(r, a); + let r = _mm512_mask_shuffle_pd( + a, + 0b11111111, + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + let e = _mm512_setr_pd(4., 3., 8., 7., 4., 3., 8., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_pd() { + let a = _mm512_setr_pd(1., 4., 5., 8., 1., 4., 5., 8.); + let b = _mm512_setr_pd(2., 3., 6., 7., 2., 3., 6., 7.); + let r = _mm512_maskz_shuffle_pd( + 0, + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_shuffle_pd( + 0b00001111, + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + let e = _mm512_setr_pd(4., 3., 8., 7., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_i64x2() { + let a = _mm512_setr_epi64(1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi64(2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_shuffle_i64x2(a, b, 0b00000000); + let e = _mm512_setr_epi64(1, 4, 1, 4, 2, 3, 2, 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_i64x2() { + let a = _mm512_setr_epi64(1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi64(2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_mask_shuffle_i64x2(a, 0, a, b, 0b00000000); + assert_eq_m512i(r, a); + let r = _mm512_mask_shuffle_i64x2(a, 0b11111111, a, b, 0b00000000); + let e = _mm512_setr_epi64(1, 4, 1, 4, 2, 3, 2, 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_i64x2() { + let a = _mm512_setr_epi64(1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi64(2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_maskz_shuffle_i64x2(0, a, b, 0b00000000); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_shuffle_i64x2(0b00001111, a, b, 0b00000000); + let e = _mm512_setr_epi64(1, 4, 1, 4, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_f64x2() { + let a = _mm512_setr_pd(1., 4., 5., 8., 9., 12., 13., 16.); + let b = _mm512_setr_pd(2., 3., 6., 7., 10., 11., 14., 15.); + let r = _mm512_shuffle_f64x2(a, b, 0b00000000); + let e = _mm512_setr_pd(1., 4., 1., 4., 2., 3., 2., 3.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_f64x2() { + let a = _mm512_setr_pd(1., 4., 5., 8., 9., 12., 13., 16.); + let b = _mm512_setr_pd(2., 3., 6., 7., 10., 11., 14., 15.); + let r = _mm512_mask_shuffle_f64x2(a, 0, a, b, 0b00000000); + assert_eq_m512d(r, a); + let r = _mm512_mask_shuffle_f64x2(a, 0b11111111, a, b, 0b00000000); + let e = _mm512_setr_pd(1., 4., 1., 4., 2., 3., 2., 3.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_f64x2() { + let a = _mm512_setr_pd(1., 4., 5., 8., 9., 12., 13., 16.); + let b = _mm512_setr_pd(2., 3., 6., 7., 10., 11., 14., 15.); + let r = _mm512_maskz_shuffle_f64x2(0, a, b, 0b00000000); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_shuffle_f64x2(0b00001111, a, b, 0b00000000); + let e = _mm512_setr_pd(1., 4., 1., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_movedup_pd() { + let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + let r = _mm512_movedup_pd(a); + let e = _mm512_setr_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_movedup_pd() { + let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + let r = _mm512_mask_movedup_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_movedup_pd(a, 0b11111111, a); + let e = _mm512_setr_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_movedup_pd() { + let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + let r = _mm512_maskz_movedup_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_movedup_pd(0b00001111, a); + let e = _mm512_setr_pd(1., 1., 3., 3., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_and_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_and_epi64(a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_and_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_mask_and_epi64(a, 0, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + + let r = _mm512_mask_and_epi64(a, 0b01111111, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_and_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_maskz_and_epi64(0, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + + let r = _mm512_maskz_and_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_and_si512() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_and_epi64(a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_or_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_or_epi64(a, b); + let e = _mm512_set_epi64( + 1 << 0 | 1 << 13 | 1 << 15, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 2 | 1 << 3, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_or_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_mask_or_epi64(a, 0, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + + let r = _mm512_mask_or_epi64(a, 0b11111111, a, b); + let e = _mm512_set_epi64( + 1 << 0 | 1 << 13 | 1 << 15, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 2 | 1 << 3, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_or_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_maskz_or_epi64(0, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + + let r = _mm512_maskz_or_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_or_si512() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_or_epi64(a, b); + let e = _mm512_set_epi64( + 1 << 0 | 1 << 13 | 1 << 15, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 2 | 1 << 3, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_xor_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_xor_epi64(a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 13 | 1 << 15, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_xor_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_mask_xor_epi64(a, 0, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + + let r = _mm512_mask_xor_epi64(a, 0b11111111, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 13 | 1 << 15, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_xor_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_maskz_xor_epi64(0, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + + let r = _mm512_maskz_xor_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_xor_si512() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_xor_epi64(a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 13 | 1 << 15, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); } } diff --git a/library/stdarch/crates/simd-test-macro/src/lib.rs b/library/stdarch/crates/simd-test-macro/src/lib.rs index 6df48b1e6a..8e65c43992 100644 --- a/library/stdarch/crates/simd-test-macro/src/lib.rs +++ b/library/stdarch/crates/simd-test-macro/src/lib.rs @@ -44,8 +44,6 @@ pub fn simd_test( .map(String::from) .collect(); - let mmx = target_features.iter().any(|s| s.starts_with("mmx")); - let enable_feature = string(enable_feature); let item = TokenStream::from(item); let name = find_name(item.clone()); @@ -106,15 +104,6 @@ pub fn simd_test( TokenStream::new() }; - let emms = if mmx { - // note: if the test requires MMX we need to clear the FPU - // registers once the test finishes before interfacing with - // other x87 code: - quote! { unsafe { super::_mm_empty() }; } - } else { - TokenStream::new() - }; - let ret: TokenStream = quote_spanned! { proc_macro2::Span::call_site() => #[allow(non_snake_case)] @@ -123,7 +112,6 @@ pub fn simd_test( fn #name() { if #force_test | (#cfg_target_features) { let v = unsafe { #name() }; - #emms return v; } else { ::stdarch_test::assert_skip_test_ok(stringify!(#name)); diff --git a/library/stdarch/crates/std_detect/src/detect/cache.rs b/library/stdarch/crates/std_detect/src/detect/cache.rs index 6bcbace4bb..e79c96dafa 100644 --- a/library/stdarch/crates/std_detect/src/detect/cache.rs +++ b/library/stdarch/crates/std_detect/src/detect/cache.rs @@ -43,7 +43,6 @@ impl Default for Initializer { // the one fitting our cache. impl Initializer { /// Tests the `bit` of the cache. - #[allow(dead_code)] #[inline] pub(crate) fn test(self, bit: u32) -> bool { debug_assert!( @@ -80,60 +79,65 @@ impl Initializer { // Note: on x64, we only use the first slot static CACHE: [Cache; 2] = [Cache::uninitialized(), Cache::uninitialized()]; -/// Feature cache with capacity for `usize::MAX - 1` features. +/// Feature cache with capacity for `size_of::() * 8 - 1` features. /// -/// Note: the last feature bit is used to represent an -/// uninitialized cache. +/// Note: 0 is used to represent an uninitialized cache, and (at least) the most +/// significant bit is set on any cache which has been initialized. /// -/// Note: we can use `Relaxed` atomic operations, because we are only interested -/// in the effects of operations on a single memory location. That is, we only -/// need "modification order", and not the full-blown "happens before". However, -/// we use `SeqCst` just to be on the safe side. +/// Note: we use `Relaxed` atomic operations, because we are only interested in +/// the effects of operations on a single memory location. That is, we only need +/// "modification order", and not the full-blown "happens before". struct Cache(AtomicUsize); impl Cache { const CAPACITY: u32 = (core::mem::size_of::() * 8 - 1) as u32; const MASK: usize = (1 << Cache::CAPACITY) - 1; + const INITIALIZED_BIT: usize = 1usize << Cache::CAPACITY; /// Creates an uninitialized cache. #[allow(clippy::declare_interior_mutable_const)] const fn uninitialized() -> Self { - Cache(AtomicUsize::new(usize::MAX)) - } - /// Is the cache uninitialized? - #[inline] - pub(crate) fn is_uninitialized(&self) -> bool { - self.0.load(Ordering::SeqCst) == usize::MAX + Cache(AtomicUsize::new(0)) } - /// Is the `bit` in the cache set? + /// Is the `bit` in the cache set? Returns `None` if the cache has not been initialized. #[inline] - pub(crate) fn test(&self, bit: u32) -> bool { - test_bit(self.0.load(Ordering::SeqCst) as u64, bit) + pub(crate) fn test(&self, bit: u32) -> Option { + let cached = self.0.load(Ordering::Relaxed); + if cached == 0 { + None + } else { + Some(test_bit(cached as u64, bit)) + } } /// Initializes the cache. #[inline] - fn initialize(&self, value: usize) { - self.0.store(value, Ordering::SeqCst); + fn initialize(&self, value: usize) -> usize { + debug_assert_eq!((value & !Cache::MASK), 0); + self.0 + .store(value | Cache::INITIALIZED_BIT, Ordering::Relaxed); + value } } cfg_if::cfg_if! { if #[cfg(feature = "std_detect_env_override")] { - #[inline(never)] - fn initialize(mut value: Initializer) { + #[inline] + fn initialize(mut value: Initializer) -> Initializer { if let Ok(disable) = crate::env::var("RUST_STD_DETECT_UNSTABLE") { for v in disable.split(" ") { let _ = super::Feature::from_str(v).map(|v| value.unset(v as u32)); } } do_initialize(value); + value } } else { #[inline] - fn initialize(value: Initializer) { + fn initialize(value: Initializer) -> Initializer { do_initialize(value); + value } } } @@ -144,8 +148,22 @@ fn do_initialize(value: Initializer) { CACHE[1].initialize((value.0 >> Cache::CAPACITY) as usize & Cache::MASK); } +// We only have to detect features once, and it's fairly costly, so hint to LLVM +// that it should assume that cache hits are more common than misses (which is +// the point of caching). It's possibly unfortunate that this function needs to +// reach across modules like this to call `os::detect_features`, but it produces +// the best code out of several attempted variants. +// +// The `Initializer` that the cache was initialized with is returned, so that +// the caller can call `test()` on it without having to load the value from the +// cache again. +#[cold] +fn detect_and_initialize() -> Initializer { + initialize(super::os::detect_features()) +} + /// Tests the `bit` of the storage. If the storage has not been initialized, -/// initializes it with the result of `f()`. +/// initializes it with the result of `os::detect_features()`. /// /// On its first invocation, it detects the CPU features and caches them in the /// `CACHE` global variable as an `AtomicU64`. @@ -157,18 +175,13 @@ fn do_initialize(value: Initializer) { /// variable `RUST_STD_DETECT_UNSTABLE` and uses its its content to disable /// Features that would had been otherwise detected. #[inline] -pub(crate) fn test(bit: u32, f: F) -> bool -where - F: FnOnce() -> Initializer, -{ - let (bit, idx) = if bit < Cache::CAPACITY { +pub(crate) fn test(bit: u32) -> bool { + let (relative_bit, idx) = if bit < Cache::CAPACITY { (bit, 0) } else { (bit - Cache::CAPACITY, 1) }; - - if CACHE[idx].is_uninitialized() { - initialize(f()) - } - CACHE[idx].test(bit) + CACHE[idx] + .test(relative_bit) + .unwrap_or_else(|| detect_and_initialize().test(bit)) } diff --git a/library/stdarch/crates/std_detect/src/detect/mod.rs b/library/stdarch/crates/std_detect/src/detect/mod.rs index c44f44c1b3..7aedef47d6 100644 --- a/library/stdarch/crates/std_detect/src/detect/mod.rs +++ b/library/stdarch/crates/std_detect/src/detect/mod.rs @@ -120,7 +120,7 @@ cfg_if! { #[inline] #[allow(dead_code)] fn check_for(x: Feature) -> bool { - cache::test(x as u32, self::os::detect_features) + cache::test(x as u32) } /// Returns an `Iterator` where diff --git a/library/stdarch/crates/stdarch-test/src/lib.rs b/library/stdarch/crates/stdarch-test/src/lib.rs index c66b6a8d9d..03711e911e 100644 --- a/library/stdarch/crates/stdarch-test/src/lib.rs +++ b/library/stdarch/crates/stdarch-test/src/lib.rs @@ -3,7 +3,6 @@ //! This basically just disassembles the current executable and then parses the //! output once globally and then provides the `assert` function which makes //! assertions about the disassembly of a function. -#![feature(vec_leak)] #![allow(clippy::missing_docs_in_private_items, clippy::print_stdout)] extern crate assert_instr_macro; diff --git a/library/stdarch/crates/stdarch-verify/src/lib.rs b/library/stdarch/crates/stdarch-verify/src/lib.rs index 37224013f0..6d9dfe6229 100644 --- a/library/stdarch/crates/stdarch-verify/src/lib.rs +++ b/library/stdarch/crates/stdarch-verify/src/lib.rs @@ -148,6 +148,9 @@ fn to_type(t: &syn::Type) -> proc_macro2::TokenStream { "__mmask8" => quote! { &MMASK8 }, "__mmask16" => quote! { &MMASK16 }, "_MM_CMPINT_ENUM" => quote! { &MM_CMPINT_ENUM }, + "_MM_MANTISSA_NORM_ENUM" => quote! { &MM_MANTISSA_NORM_ENUM }, + "_MM_MANTISSA_SIGN_ENUM" => quote! { &MM_MANTISSA_SIGN_ENUM }, + "_MM_PERM_ENUM" => quote! { &MM_PERM_ENUM }, "__m64" => quote! { &M64 }, "bool" => quote! { &BOOL }, "f32" => quote! { &F32 }, diff --git a/library/stdarch/crates/stdarch-verify/tests/arm.rs b/library/stdarch/crates/stdarch-verify/tests/arm.rs index b877b1e869..26239a43aa 100644 --- a/library/stdarch/crates/stdarch-verify/tests/arm.rs +++ b/library/stdarch/crates/stdarch-verify/tests/arm.rs @@ -330,6 +330,7 @@ fn verify_all_signatures() { "_rbit_u64", "_cls_u32", "_cls_u64", + "_prefetch", ]; if !skip.contains(&rust.name) { println!( @@ -350,7 +351,7 @@ fn verify_all_signatures() { // Skip some intrinsics that aren't NEON and are located in different // places than the whitelists below. match rust.name { - "brk" | "__breakpoint" | "udf" => continue, + "brk" | "__breakpoint" | "udf" | "_prefetch" => continue, _ => {} } let arm = match map.get(rust.name) { diff --git a/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs b/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs index b6f3b01f56..d9adf91999 100644 --- a/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs +++ b/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs @@ -56,6 +56,9 @@ static M512D: Type = Type::M512D; static MMASK8: Type = Type::MMASK8; static MMASK16: Type = Type::MMASK16; static MM_CMPINT_ENUM: Type = Type::MM_CMPINT_ENUM; +static MM_MANTISSA_NORM_ENUM: Type = Type::MM_MANTISSA_NORM_ENUM; +static MM_MANTISSA_SIGN_ENUM: Type = Type::MM_MANTISSA_SIGN_ENUM; +static MM_PERM_ENUM: Type = Type::MM_PERM_ENUM; static TUPLE: Type = Type::Tuple; static CPUID: Type = Type::CpuidResult; @@ -81,6 +84,9 @@ enum Type { MMASK8, MMASK16, MM_CMPINT_ENUM, + MM_MANTISSA_NORM_ENUM, + MM_MANTISSA_SIGN_ENUM, + MM_PERM_ENUM, Tuple, CpuidResult, Never, @@ -323,8 +329,6 @@ fn verify_all_signatures() { // take a signed-integer. This breaks `_MM_SHUFFLE` for // `_mm_shuffle_ps`: "_mm_shuffle_ps" => continue, - // FIXME(#867) - "_mm256_extract_epi8" | "_mm256_extract_epi16" => continue, _ => {} } @@ -676,6 +680,9 @@ fn equate(t: &Type, intel: &str, intrinsic: &str, is_const: bool) -> Result<(), (&Type::MMASK8, "__mmask8") => {} (&Type::MMASK16, "__mmask16") => {} (&Type::MM_CMPINT_ENUM, "_MM_CMPINT_ENUM") => {} + (&Type::MM_MANTISSA_NORM_ENUM, "_MM_MANTISSA_NORM_ENUM") => {} + (&Type::MM_MANTISSA_SIGN_ENUM, "_MM_MANTISSA_SIGN_ENUM") => {} + (&Type::MM_PERM_ENUM, "_MM_PERM_ENUM") => {} // This is a macro (?) in C which seems to mutate its arguments, but // that means that we're taking pointers to arguments in rust diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 7b76dc83aa..e44c781113 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -25,6 +25,7 @@ proc_macro = { path = "../proc_macro" } default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] backtrace = ["std/backtrace"] compiler-builtins-c = ["std/compiler-builtins-c"] +compiler-builtins-mem = ["std/compiler-builtins-mem"] llvm-libunwind = ["std/llvm-libunwind"] panic-unwind = ["std/panic_unwind"] panic_immediate_abort = ["std/panic_immediate_abort"] diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs index e92e5b9829..10546de176 100644 --- a/library/test/src/bench.rs +++ b/library/test/src/bench.rs @@ -61,15 +61,15 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String { let median = bs.ns_iter_summ.median as usize; let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; - output - .write_fmt(format_args!( - "{:>11} ns/iter (+/- {})", - fmt_thousands_sep(median, ','), - fmt_thousands_sep(deviation, ',') - )) - .unwrap(); + write!( + output, + "{:>11} ns/iter (+/- {})", + fmt_thousands_sep(median, ','), + fmt_thousands_sep(deviation, ',') + ) + .unwrap(); if bs.mb_s != 0 { - output.write_fmt(format_args!(" = {} MB/s", bs.mb_s)).unwrap(); + write!(output, " = {} MB/s", bs.mb_s).unwrap(); } output } @@ -83,9 +83,9 @@ fn fmt_thousands_sep(mut n: usize, sep: char) -> String { let base = 10_usize.pow(pow); if pow == 0 || trailing || n / base != 0 { if !trailing { - output.write_fmt(format_args!("{}", n / base)).unwrap(); + write!(output, "{}", n / base).unwrap(); } else { - output.write_fmt(format_args!("{:03}", n / base)).unwrap(); + write!(output, "{:03}", n / base).unwrap(); } if pow != 0 { output.push(sep); @@ -98,10 +98,6 @@ fn fmt_thousands_sep(mut n: usize, sep: char) -> String { output } -fn ns_from_dur(dur: Duration) -> u64 { - dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64) -} - fn ns_iter_inner(inner: &mut F, k: u64) -> u64 where F: FnMut() -> T, @@ -110,7 +106,7 @@ where for _ in 0..k { black_box(inner()); } - ns_from_dur(start.elapsed()) + start.elapsed().as_nanos() as u64 } pub fn iter(inner: &mut F) -> stats::Summary @@ -163,7 +159,7 @@ where return summ5; } - total_run = total_run + loop_run; + total_run += loop_run; // Longest we ever run for is 3s. if total_run > Duration::from_secs(3) { return summ5; diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 4a93e084df..8c90b57b3b 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -139,7 +139,7 @@ impl PrettyFormatter { stdouts.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); stdouts.push_str(&output); - stdouts.push_str("\n"); + stdouts.push('\n'); } } if !stdouts.is_empty() { diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index 5a264d2005..1ae7846a99 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -114,7 +114,7 @@ impl TerseFormatter { stdouts.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); stdouts.push_str(&output); - stdouts.push_str("\n"); + stdouts.push('\n'); } } if !stdouts.is_empty() { @@ -140,7 +140,7 @@ impl TerseFormatter { fail_out.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); fail_out.push_str(&output); - fail_out.push_str("\n"); + fail_out.push('\n'); } } if !fail_out.is_empty() { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 6bd708ef48..b0b81f85fe 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -29,6 +29,7 @@ #![feature(staged_api)] #![feature(termination_trait_lib)] #![feature(test)] +#![feature(total_cmp)] // Public reexports pub use self::bench::{black_box, Bencher}; @@ -236,11 +237,9 @@ where let event = TestEvent::TeFiltered(filtered_descs); notify_about_test_event(event)?; - let (filtered_tests, filtered_benchs): (Vec<_>, _) = - filtered_tests.into_iter().partition(|e| match e.testfn { - StaticTestFn(_) | DynTestFn(_) => true, - _ => false, - }); + let (filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests + .into_iter() + .partition(|e| matches!(e.testfn, StaticTestFn(_) | DynTestFn(_))); let concurrency = opts.test_threads.unwrap_or_else(get_concurrency); diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index c02f93bf9d..53f3889447 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -1,29 +1,13 @@ #![allow(missing_docs)] #![allow(deprecated)] // Float -use std::cmp::Ordering::{self, Equal, Greater, Less}; use std::mem; #[cfg(test)] mod tests; -fn local_cmp(x: f64, y: f64) -> Ordering { - // arbitrarily decide that NaNs are larger than everything. - if y.is_nan() { - Less - } else if x.is_nan() { - Greater - } else if x < y { - Less - } else if x == y { - Equal - } else { - Greater - } -} - fn local_sort(v: &mut [f64]) { - v.sort_by(|x: &f64, y: &f64| local_cmp(*x, *y)); + v.sort_by(|x: &f64, y: &f64| x.total_cmp(y)); } /// Trait that provides simple descriptive statistics on a univariate set of numeric samples. @@ -215,7 +199,7 @@ impl Stats for [f64] { let mut v: f64 = 0.0; for s in self { let x = *s - mean; - v = v + x * x; + v += x * x; } // N.B., this is _supposed to be_ len-1, not len. If you // change it back to len, you will be calculating a diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 0c57861f70..806df572cf 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -51,10 +51,10 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "s390x")] pub const unwinder_private_data_size: usize = 2; -#[cfg(target_arch = "sparc64")] +#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] pub const unwinder_private_data_size: usize = 2; -#[cfg(target_arch = "riscv64")] +#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] pub const unwinder_private_data_size: usize = 2; #[cfg(target_os = "emscripten")] diff --git a/src/README.md b/src/README.md index 2f8e9da179..ef0dec1c45 100644 --- a/src/README.md +++ b/src/README.md @@ -1,5 +1,5 @@ This directory contains the source code of the rust project, including: -- `rustc` and its tests +- The test suite - The bootstrapping build system - Various submodules for tools, like rustdoc, rls, etc. diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md new file mode 100644 index 0000000000..fe426c4cec --- /dev/null +++ b/src/bootstrap/CHANGELOG.md @@ -0,0 +1,47 @@ +# Changelog + +All notable changes to bootstrap will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [Non-breaking changes since the last major version] + +None. + +## [Version 2] - 2020-09-25 + +- `host` now defaults to the value of `build` in all cases + + Previously `host` defaulted to an empty list when `target` was overridden, and to `build` otherwise + +### Non-breaking changes + +- Add `x.py setup` [#76631](https://github.com/rust-lang/rust/pull/76631) +- Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626) +- Optionally, download LLVM from CI on Linux and NixOS + + [#76439](https://github.com/rust-lang/rust/pull/76349) + + [#76667](https://github.com/rust-lang/rust/pull/76667) + + [#76708](https://github.com/rust-lang/rust/pull/76708) +- Distribute rustc sources as part of `rustc-dev` [#76856](https://github.com/rust-lang/rust/pull/76856) +- Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625) +- Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588) +- Add sample defaults for x.py [#76628](https://github.com/rust-lang/rust/pull/76628) +- Add `--keep-stage-std`, which behaves like `keep-stage` but allows the stage + 0 compiler artifacts (i.e., stage1/bin/rustc) to be rebuilt if changed + [#77120](https://github.com/rust-lang/rust/pull/77120). + + +## [Version 1] - 2020-09-11 + +This is the first changelog entry, and it does not attempt to be an exhaustive list of features in x.py. +Instead, this documents the changes to bootstrap in the past 2 months. + +- Improve defaults in `x.py` [#73964](https://github.com/rust-lang/rust/pull/73964) + (see [blog post] for details) +- Set `ninja = true` by default [#74922](https://github.com/rust-lang/rust/pull/74922) +- Avoid trying to inversely cross-compile for build triple from host triples [#76415](https://github.com/rust-lang/rust/pull/76415) +- Allow blessing expect-tests in tools [#75975](https://github.com/rust-lang/rust/pull/75975) +- `x.py check` checks tests/examples/benches [#76258](https://github.com/rust-lang/rust/pull/76258) +- Fix `rust.use-lld` when linker is not set [#76326](https://github.com/rust-lang/rust/pull/76326) +- Build tests with LLD if `use-lld = true` was passed [#76378](https://github.com/rust-lang/rust/pull/76378) + +[blog post]: https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index c4918d7f2e..e04128d1b0 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -3,9 +3,9 @@ authors = ["The Rust Project Developers"] name = "bootstrap" version = "0.0.0" edition = "2018" +build = "build.rs" [lib] -name = "bootstrap" path = "lib.rs" doctest = false @@ -49,6 +49,7 @@ lazy_static = "1.3.0" time = "0.1" ignore = "0.4.10" opener = "0.4" +merge = "0.1.0" [target.'cfg(windows)'.dependencies.winapi] version = "0.3" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 86de3d5c6d..bc8bae14b2 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -26,10 +26,10 @@ The script accepts commands, flags, and arguments to determine what to do: ``` # build the whole compiler - ./x.py build + ./x.py build --stage 2 # build the stage1 compiler - ./x.py build --stage 1 + ./x.py build # build stage0 libstd ./x.py build --stage 0 library/std @@ -43,8 +43,8 @@ The script accepts commands, flags, and arguments to determine what to do: that belong to stage n or earlier: ``` - # keep old build products for stage 0 and build stage 1 - ./x.py build --keep-stage 0 --stage 1 + # build stage 1, keeping old build products for stage 0 + ./x.py build --keep-stage 0 ``` * `test` - a command for executing unit tests. Like the `build` command this @@ -123,24 +123,8 @@ that (b) leverage Rust as much as possible! ## Incremental builds -You can configure rustbuild to use incremental compilation. Because -incremental is new and evolving rapidly, if you want to use it, it is -recommended that you replace the snapshot with a locally installed -nightly build of rustc. You will want to keep this up to date. - -To follow this course of action, first thing you will want to do is to -install a nightly, presumably using `rustup`. You will then want to -configure your directory to use this build, like so: - -```sh -# configure to use local rust instead of downloading a beta. -# `--local-rust-root` is optional here. If elided, we will -# use whatever rustc we find on your PATH. -$ ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild -``` - -After that, you can use the `--incremental` flag to actually do -incremental builds: +You can configure rustbuild to use incremental compilation with the +`--incremental` flag: ```sh $ ./x.py build --incremental @@ -150,9 +134,7 @@ The `--incremental` flag will store incremental compilation artifacts in `build//stage0-incremental`. Note that we only use incremental compilation for the stage0 -> stage1 compilation -- this is because the stage1 compiler is changing, and we don't try to cache and reuse -incremental artifacts across different versions of the compiler. For -this reason, `--incremental` defaults to `--stage 1` (though you can -manually select a higher stage, if you prefer). +incremental artifacts across different versions of the compiler. You can always drop the `--incremental` to build as normal (but you will still be using the local nightly as your bootstrap). @@ -274,7 +256,7 @@ directory, but rather the compiler is split into three different Cargo projects: * `library/std` - the standard library * `library/test` - testing support, depends on libstd -* `src/rustc` - the actual compiler itself +* `compiler/rustc` - the actual compiler itself Each "project" has a corresponding Cargo.lock file with all dependencies, and this means that building the compiler involves running Cargo three times. The @@ -331,8 +313,22 @@ are: `Config` struct. * Adding a sanity check? Take a look at `bootstrap/sanity.rs`. -If you have any questions feel free to reach out on `#infra` channel in the -[Rust Discord server][rust-discord] or ask on internals.rust-lang.org. When +If you make a major change, please remember to: + ++ Update `VERSION` in `src/bootstrap/main.rs`. +* Update `changelog-seen = N` in `config.toml.example`. +* Add an entry in `src/bootstrap/CHANGELOG.md`. + +A 'major change' includes + +* A new option or +* A change in the default options. + +Changes that do not affect contributors to the compiler or users +building rustc from source don't need an update to `VERSION`. + +If you have any questions feel free to reach out on the `#t-infra` channel in +the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When you encounter bugs, please file issues on the rust-lang/rust issue tracker. -[rust-discord]: https://discord.gg/rust-lang +[rust-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index b67486c962..d31f95ee5e 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -7,10 +7,58 @@ use std::env; -use bootstrap::{Build, Config}; +use bootstrap::{Build, Config, Subcommand}; fn main() { let args = env::args().skip(1).collect::>(); let config = Config::parse(&args); + + let changelog_suggestion = check_version(&config); + + // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the + // changelog warning, not the `x.py setup` message. + let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. }); + if suggest_setup { + println!("warning: you have not made a `config.toml`"); + println!("help: consider running `x.py setup` or copying `config.toml.example`"); + } else if let Some(suggestion) = &changelog_suggestion { + println!("{}", suggestion); + } + Build::new(config).build(); + + if suggest_setup { + println!("warning: you have not made a `config.toml`"); + println!("help: consider running `x.py setup` or copying `config.toml.example`"); + } else if let Some(suggestion) = &changelog_suggestion { + println!("{}", suggestion); + } + + if suggest_setup || changelog_suggestion.is_some() { + println!("note: this message was printed twice to make it more likely to be seen"); + } +} + +fn check_version(config: &Config) -> Option { + const VERSION: usize = 2; + + let mut msg = String::new(); + + let suggestion = if let Some(seen) = config.changelog_seen { + if seen != VERSION { + msg.push_str("warning: there have been changes to x.py since you last updated.\n"); + format!("update `config.toml` to use `changelog-seen = {}` instead", VERSION) + } else { + return None; + } + } else { + msg.push_str("warning: x.py has made several changes recently you may want to look at\n"); + format!("add `changelog-seen = {}` at the top of `config.toml`", VERSION) + }; + + msg.push_str("help: consider looking at the changes in `src/bootstrap/CHANGELOG.md`\n"); + msg.push_str("note: to silence this warning, "); + msg.push_str(&suggestion); + + Some(msg) } diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 4dd71ebade..3694bdbf67 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -112,6 +112,9 @@ fn main() { if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { cmd.arg(format!("-Clinker={}", host_linker)); } + if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() { + cmd.arg("-Clink-args=-fuse-ld=lld"); + } if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") { if s == "true" { diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index ab846adf94..cb58eb89ad 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -42,11 +42,14 @@ fn main() { if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } - if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") { + if let Some(linker) = env::var_os("RUSTDOC_LINKER") { let mut arg = OsString::from("-Clinker="); arg.push(&linker); cmd.arg(arg); } + if env::var_os("RUSTDOC_FUSE_LD_LLD").is_some() { + cmd.arg("-Clink-args=-fuse-ld=lld"); + } // Needed to be able to run all rustdoc tests. if let Some(ref x) = env::var_os("RUSTDOC_RESOURCE_SUFFIX") { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c3f1bac177..5c9184f450 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -14,8 +14,17 @@ import tempfile from time import time - -def get(url, path, verbose=False): +def support_xz(): + try: + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + temp_path = temp_file.name + with tarfile.open(temp_path, "w:xz"): + pass + return True + except tarfile.CompressionError: + return False + +def get(url, path, verbose=False, do_verify=True): suffix = '.sha256' sha_url = url + suffix with tempfile.NamedTemporaryFile(delete=False) as temp_file: @@ -24,19 +33,20 @@ def get(url, path, verbose=False): sha_path = sha_file.name try: - download(sha_path, sha_url, False, verbose) - if os.path.exists(path): - if verify(path, sha_path, False): - if verbose: - print("using already-download file", path) - return - else: - if verbose: - print("ignoring already-download file", - path, "due to failed verification") - os.unlink(path) + if do_verify: + download(sha_path, sha_url, False, verbose) + if os.path.exists(path): + if verify(path, sha_path, False): + if verbose: + print("using already-download file", path) + return + else: + if verbose: + print("ignoring already-download file", + path, "due to failed verification") + os.unlink(path) download(temp_path, url, True, verbose) - if not verify(temp_path, sha_path, verbose): + if do_verify and not verify(temp_path, sha_path, verbose): raise RuntimeError("failed verification") if verbose: print("moving {} to {}".format(temp_path, path)) @@ -365,16 +375,6 @@ class RustBuild(object): cargo_channel = self.cargo_channel rustfmt_channel = self.rustfmt_channel - def support_xz(): - try: - with tempfile.NamedTemporaryFile(delete=False) as temp_file: - temp_path = temp_file.name - with tarfile.open(temp_path, "w:xz"): - pass - return True - except tarfile.CompressionError: - return False - if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.program_out_of_date(self.rustc_stamp())): @@ -398,14 +398,6 @@ class RustBuild(object): with output(self.rustc_stamp()) as rust_stamp: rust_stamp.write(self.date) - # This is required so that we don't mix incompatible MinGW - # libraries/binaries that are included in rust-std with - # the system MinGW ones. - if "pc-windows-gnu" in self.build: - filename = "rust-mingw-{}-{}{}".format( - rustc_channel, self.build, tarball_suffix) - self._download_stage0_helper(filename, "rust-mingw", tarball_suffix) - if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.program_out_of_date(self.cargo_stamp())): @@ -431,6 +423,32 @@ class RustBuild(object): with output(self.rustfmt_stamp()) as rustfmt_stamp: rustfmt_stamp.write(self.date + self.rustfmt_channel) + if self.downloading_llvm(): + # We want the most recent LLVM submodule update to avoid downloading + # LLVM more often than necessary. + # + # This git command finds that commit SHA, looking for bors-authored + # merges that modified src/llvm-project. + # + # This works even in a repository that has not yet initialized + # submodules. + llvm_sha = subprocess.check_output([ + "git", "log", "--author=bors", "--format=%H", "-n1", + "-m", "--first-parent", + "--", "src/llvm-project" + ]).decode(sys.getdefaultencoding()).strip() + llvm_assertions = self.get_toml('assertions', 'llvm') == 'true' + if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)): + self._download_ci_llvm(llvm_sha, llvm_assertions) + for binary in ["llvm-config", "FileCheck"]: + self.fix_bin_or_dylib("{}/bin/{}".format(self.llvm_root(), binary)) + with output(self.llvm_stamp()) as llvm_stamp: + llvm_stamp.write(self.date + llvm_sha + str(llvm_assertions)) + + def downloading_llvm(self): + opt = self.get_toml('download-ci-llvm', 'llvm') + return opt == "true" + def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None): if date is None: date = self.date @@ -445,6 +463,25 @@ class RustBuild(object): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose) + def _download_ci_llvm(self, llvm_sha, llvm_assertions): + cache_prefix = "llvm-{}-{}".format(llvm_sha, llvm_assertions) + cache_dst = os.path.join(self.build_dir, "cache") + rustc_cache = os.path.join(cache_dst, cache_prefix) + if not os.path.exists(rustc_cache): + os.makedirs(rustc_cache) + + url = "https://ci-artifacts.rust-lang.org/rustc-builds/{}".format(llvm_sha) + if llvm_assertions: + url = url.replace('rustc-builds', 'rustc-builds-alt') + tarball_suffix = '.tar.xz' if support_xz() else '.tar.gz' + filename = "rust-dev-nightly-" + self.build + tarball_suffix + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get("{}/{}".format(url, filename), tarball, verbose=self.verbose, do_verify=False) + unpack(tarball, tarball_suffix, self.llvm_root(), + match="rust-dev", + verbose=self.verbose) + def fix_bin_or_dylib(self, fname): """Modifies the interpreter section of 'fname' to fix the dynamic linker, or the RPATH section, to fix the dynamic library search path @@ -566,6 +603,17 @@ class RustBuild(object): """ return os.path.join(self.bin_root(), '.rustfmt-stamp') + def llvm_stamp(self): + """Return the path for .rustfmt-stamp + + >>> rb = RustBuild() + >>> rb.build_dir = "build" + >>> rb.llvm_stamp() == os.path.join("build", "ci-llvm", ".llvm-stamp") + True + """ + return os.path.join(self.llvm_root(), '.llvm-stamp') + + def program_out_of_date(self, stamp_path, extra=""): """Check if the given program stamp is out of date""" if not os.path.exists(stamp_path) or self.clean: @@ -589,6 +637,22 @@ class RustBuild(object): """ return os.path.join(self.build_dir, self.build, "stage0") + def llvm_root(self): + """Return the CI LLVM root directory + + >>> rb = RustBuild() + >>> rb.build_dir = "build" + >>> rb.llvm_root() == os.path.join("build", "ci-llvm") + True + + When the 'build' property is given should be a nested directory: + + >>> rb.build = "devel" + >>> rb.llvm_root() == os.path.join("build", "devel", "ci-llvm") + True + """ + return os.path.join(self.build_dir, self.build, "ci-llvm") + def get_toml(self, key, section=None): """Returns the value of the given key in config.toml, otherwise returns None @@ -714,7 +778,6 @@ class RustBuild(object): # See also: . if "CARGO_BUILD_TARGET" in env: del env["CARGO_BUILD_TARGET"] - env["RUSTC_BOOTSTRAP"] = '1' env["CARGO_TARGET_DIR"] = build_dir env["RUSTC"] = self.rustc() env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ @@ -829,8 +892,9 @@ class RustBuild(object): submodules_names = [] for module in submodules: if module.endswith("llvm-project"): - if self.get_toml('llvm-config') and self.get_toml('lld') != 'true': - continue + if self.get_toml('llvm-config') or self.get_toml('download-ci-llvm') == 'true': + if self.get_toml('lld') != 'true': + continue check = self.check_submodule(module, slow_submodules) filtered_submodules.append((module, check)) submodules_names.append(module) @@ -914,7 +978,6 @@ def bootstrap(help_triggered): parser = argparse.ArgumentParser(description='Build rust') parser.add_argument('--config') parser.add_argument('--build') - parser.add_argument('--src') parser.add_argument('--clean', action='store_true') parser.add_argument('-v', '--verbose', action='count', default=0) @@ -923,7 +986,7 @@ def bootstrap(help_triggered): # Configure initial bootstrap build = RustBuild() - build.rust_root = args.src or os.path.abspath(os.path.join(__file__, '../../..')) + build.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) build.verbose = args.verbose build.clean = args.clean @@ -980,18 +1043,12 @@ def bootstrap(help_triggered): args = [build.bootstrap_binary()] args.extend(sys.argv[1:]) env = os.environ.copy() - env["BUILD"] = build.build - env["SRC"] = build.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) env["BOOTSTRAP_PYTHON"] = sys.executable env["BUILD_DIR"] = build.build_dir env["RUSTC_BOOTSTRAP"] = '1' - env["CARGO"] = build.cargo() - env["RUSTC"] = build.rustc() if toml_path: env["BOOTSTRAP_CONFIG"] = toml_path - if build.rustfmt(): - env["RUSTFMT"] = build.rustfmt() run(args, env=env, verbose=build.verbose) diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs new file mode 100644 index 0000000000..d40b924e0f --- /dev/null +++ b/src/bootstrap/build.rs @@ -0,0 +1,26 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rustc-env=BUILD_TRIPLE={}", env::var("HOST").unwrap()); + + // This may not be a canonicalized path. + let mut rustc = PathBuf::from(env::var_os("RUSTC").unwrap()); + + if rustc.is_relative() { + for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { + let absolute = dir.join(&rustc); + if absolute.exists() { + rustc = absolute; + break; + } + } + } + assert!(rustc.is_absolute()); + + // FIXME: if the path is not utf-8, this is going to break. Unfortunately + // Cargo doesn't have a way for us to specify non-utf-8 paths easily, so + // we'll need to invent some encoding scheme if this becomes a problem. + println!("cargo:rustc-env=RUSTC={}", rustc.to_str().unwrap()); +} diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 6446fa7550..3fa77982a9 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -87,11 +87,16 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { pub struct RunConfig<'a> { pub builder: &'a Builder<'a>, - pub host: TargetSelection, pub target: TargetSelection, pub path: PathBuf, } +impl RunConfig<'_> { + pub fn build_triple(&self) -> TargetSelection { + self.builder.build.build + } +} + struct StepDescription { default: bool, only_hosts: bool, @@ -165,29 +170,13 @@ impl StepDescription { pathset, self.name, builder.config.exclude ); } - let hosts = &builder.hosts; // Determine the targets participating in this rule. - let targets = if self.only_hosts { - if builder.config.skip_only_host_steps { - return; // don't run anything - } else { - &builder.hosts - } - } else { - &builder.targets - }; + let targets = if self.only_hosts { &builder.hosts } else { &builder.targets }; - for host in hosts { - for target in targets { - let run = RunConfig { - builder, - path: pathset.path(builder), - host: *host, - target: *target, - }; - (self.make_run)(run); - } + for target in targets { + let run = RunConfig { builder, path: pathset.path(builder), target: *target }; + (self.make_run)(run); } } @@ -204,37 +193,37 @@ impl StepDescription { ); } - if paths.is_empty() { - for (desc, should_run) in v.iter().zip(should_runs) { + if paths.is_empty() || builder.config.include_default_paths { + for (desc, should_run) in v.iter().zip(&should_runs) { if desc.default && should_run.is_really_default { for pathset in &should_run.paths { desc.maybe_run(builder, pathset); } } } - } else { - for path in paths { - // strip CurDir prefix if present - let path = match path.strip_prefix(".") { - Ok(p) => p, - Err(_) => path, - }; + } - let mut attempted_run = false; - for (desc, should_run) in v.iter().zip(&should_runs) { - if let Some(suite) = should_run.is_suite_path(path) { - attempted_run = true; - desc.maybe_run(builder, suite); - } else if let Some(pathset) = should_run.pathset_for_path(path) { - attempted_run = true; - desc.maybe_run(builder, pathset); - } - } + for path in paths { + // strip CurDir prefix if present + let path = match path.strip_prefix(".") { + Ok(p) => p, + Err(_) => path, + }; - if !attempted_run { - panic!("error: no rules matched {}", path.display()); + let mut attempted_run = false; + for (desc, should_run) in v.iter().zip(&should_runs) { + if let Some(suite) = should_run.is_suite_path(path) { + attempted_run = true; + desc.maybe_run(builder, suite); + } else if let Some(pathset) = should_run.pathset_for_path(path) { + attempted_run = true; + desc.maybe_run(builder, pathset); } } + + if !attempted_run { + panic!("error: no rules matched {}", path.display()); + } } } } @@ -382,7 +371,7 @@ impl<'a> Builder<'a> { native::Lld ), Kind::Check | Kind::Clippy | Kind::Fix | Kind::Format => { - describe!(check::Std, check::Rustc, check::Rustdoc, check::Clippy) + describe!(check::Std, check::Rustc, check::Rustdoc, check::Clippy, check::Bootstrap) } Kind::Test => describe!( crate::toolstate::ToolStateCheck, @@ -471,7 +460,9 @@ impl<'a> Builder<'a> { dist::Clippy, dist::Miri, dist::LlvmTools, + dist::RustDev, dist::Extended, + dist::BuildManifest, dist::HashSign ), Kind::Install => describe!( @@ -487,7 +478,7 @@ impl<'a> Builder<'a> { install::Src, install::Rustc ), - Kind::Run => describe!(run::ExpandYamlAnchors,), + Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest,), } } @@ -528,23 +519,9 @@ impl<'a> Builder<'a> { } fn new_internal(build: &Build, kind: Kind, paths: Vec) -> Builder<'_> { - let top_stage = if let Some(explicit_stage) = build.config.stage { - explicit_stage - } else { - // See https://github.com/rust-lang/compiler-team/issues/326 - match kind { - Kind::Doc => 0, - Kind::Build | Kind::Test => 1, - Kind::Bench | Kind::Dist | Kind::Install => 2, - // These are all bootstrap tools, which don't depend on the compiler. - // The stage we pass shouldn't matter, but use 0 just in case. - Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => 0, - } - }; - Builder { build, - top_stage, + top_stage: build.config.stage, kind, cache: Cache::new(), stack: RefCell::new(Vec::new()), @@ -565,23 +542,12 @@ impl<'a> Builder<'a> { Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]), Subcommand::Install { ref paths } => (Kind::Install, &paths[..]), Subcommand::Run { ref paths } => (Kind::Run, &paths[..]), - Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(), - }; - - let this = Self::new_internal(build, kind, paths.to_owned()); - - // CI should always run stage 2 builds, unless it specifically states otherwise - #[cfg(not(test))] - if build.config.stage.is_none() && build.ci_env != crate::CiEnv::None { - match kind { - Kind::Test | Kind::Doc | Kind::Build | Kind::Bench | Kind::Dist | Kind::Install => { - assert_eq!(this.top_stage, 2) - } - Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => {} + Subcommand::Format { .. } | Subcommand::Clean { .. } | Subcommand::Setup { .. } => { + panic!() } - } + }; - this + Self::new_internal(build, kind, paths.to_owned()) } pub fn execute_cli(&self) { @@ -712,7 +678,7 @@ impl<'a> Builder<'a> { /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic /// library lookup path. - pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) { + pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) { // Windows doesn't need dylib path munging because the dlls for the // compiler live next to the compiler and the system will find them // automatically. @@ -720,7 +686,7 @@ impl<'a> Builder<'a> { return; } - add_dylib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command); + add_dylib_path(vec![self.rustc_libdir(compiler)], cmd); } /// Gets a path to the compiler specified. @@ -755,8 +721,11 @@ impl<'a> Builder<'a> { cmd.env_remove("MAKEFLAGS"); cmd.env_remove("MFLAGS"); - if let Some(linker) = self.linker(compiler.host, true) { - cmd.env("RUSTC_TARGET_LINKER", linker); + if let Some(linker) = self.linker(compiler.host) { + cmd.env("RUSTDOC_LINKER", linker); + } + if self.is_fuse_ld_lld(compiler.host) { + cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } cmd } @@ -796,7 +765,7 @@ impl<'a> Builder<'a> { if cmd == "doc" || cmd == "rustdoc" { let my_out = match mode { // This is the intended out directory for compiler documentation. - Mode::Rustc | Mode::ToolRustc | Mode::Codegen => self.compiler_doc_out(target), + Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target), Mode::Std => out_dir.join(target.triple).join("doc"), _ => panic!("doc mode {:?} not expected", mode), }; @@ -811,7 +780,7 @@ impl<'a> Builder<'a> { format!("CARGO_PROFILE_{}_{}", profile, name) }; - // See comment in librustc_llvm/build.rs for why this is necessary, largely llvm-config + // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config // needs to not accidentally link to libLLVM in stage0/lib. cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var()); if let Some(e) = env::var_os(util::dylib_path_var()) { @@ -828,9 +797,9 @@ impl<'a> Builder<'a> { // scripts can do less work (i.e. not building/requiring LLVM). if cmd == "check" || cmd == "clippy" || cmd == "fix" { // If we've not yet built LLVM, or it's stale, then bust - // the librustc_llvm cache. That will always work, even though it + // the rustc_llvm cache. That will always work, even though it // may mean that on the next non-check build we'll need to rebuild - // librustc_llvm. But if LLVM is stale, that'll be a tiny amount + // rustc_llvm. But if LLVM is stale, that'll be a tiny amount // of work comparitively, and we'd likely need to rebuild it anyway, // so that's okay. if crate::native::prebuilt_llvm_config(self, target).is_err() { @@ -874,7 +843,7 @@ impl<'a> Builder<'a> { match mode { Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {} - Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { + Mode::Rustc | Mode::ToolRustc => { // Build proc macros both for the host and the target if target != compiler.host && cmd != "check" { cargo.arg("-Zdual-proc-macros"); @@ -1041,20 +1010,18 @@ impl<'a> Builder<'a> { } } - // FIXME: Don't use LLD with MSVC if we're compiling libtest, since it fails to link it. - // See https://github.com/rust-lang/rust/issues/68647. - let can_use_lld = mode != Mode::Std; - - if let Some(host_linker) = self.linker(compiler.host, can_use_lld) { + if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); } + if self.is_fuse_ld_lld(compiler.host) { + cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1"); + } - if let Some(target_linker) = self.linker(target, can_use_lld) { + if let Some(target_linker) = self.linker(target) { let target = crate::envify(&target.triple); cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker); } - - if self.config.use_lld && !target.contains("msvc") { + if self.is_fuse_ld_lld(target) { rustflags.arg("-Clink-args=-fuse-ld=lld"); } @@ -1063,7 +1030,7 @@ impl<'a> Builder<'a> { } let debuginfo_level = match mode { - Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, + Mode::Rustc => self.config.rust_debuginfo_level_rustc, Mode::Std => self.config.rust_debuginfo_level_std, Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => { self.config.rust_debuginfo_level_tools @@ -1079,6 +1046,11 @@ impl<'a> Builder<'a> { }, ); + if self.config.cmd.bless() { + // Bless `expect!` tests. + cargo.env("UPDATE_EXPECT", "1"); + } + if !mode.is_tool() { cargo.env("RUSTC_FORCE_UNSTABLE", "1"); } @@ -1195,7 +1167,7 @@ impl<'a> Builder<'a> { rustdocflags.arg("-Winvalid_codeblock_attributes"); } - if let Mode::Rustc | Mode::Codegen = mode { + if mode == Mode::Rustc { rustflags.arg("-Zunstable-options"); rustflags.arg("-Wrustc::internal"); } @@ -1232,7 +1204,7 @@ impl<'a> Builder<'a> { cargo.env(format!("CC_{}", target.triple), &cc); let cflags = self.cflags(target, GitRepo::Rustc).join(" "); - cargo.env(format!("CFLAGS_{}", target.triple), cflags.clone()); + cargo.env(format!("CFLAGS_{}", target.triple), &cflags); if let Some(ar) = self.ar(target) { let ranlib = format!("{} s", ar.display()); @@ -1358,7 +1330,7 @@ impl<'a> Builder<'a> { // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of // linking all deps statically into the dylib. - if let Mode::Std | Mode::Rustc | Mode::Codegen = mode { + if matches!(mode, Mode::Std | Mode::Rustc) { rustflags.arg("-Cprefer-dynamic"); } @@ -1417,7 +1389,7 @@ impl<'a> Builder<'a> { (out, dur - deps) }; - if self.config.print_step_timings && dur > Duration::from_millis(100) { + if self.config.print_step_timings && !self.config.dry_run { println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis()); } @@ -1511,6 +1483,10 @@ impl Cargo { self.command.env(key.as_ref(), value.as_ref()); self } + + pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) { + builder.add_rustc_lib_path(compiler, &mut self.command); + } } impl From for Command { diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index 111971534b..a367aa5349 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -2,13 +2,16 @@ use super::*; use crate::config::{Config, TargetSelection}; use std::thread; -fn configure(host: &[&str], target: &[&str]) -> Config { - let mut config = Config::default_opts(); +fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { + let mut config = Config::parse(&[cmd.to_owned()]); // don't save toolstates config.save_toolstates = None; - config.skip_only_host_steps = false; config.dry_run = true; + config.ninja_in_file = false; // try to avoid spurious failures in dist where we create/delete each others file + config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap()); + config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap()); + config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap()); let dir = config .out .join("tmp-rustbuild-tests") @@ -16,16 +19,8 @@ fn configure(host: &[&str], target: &[&str]) -> Config { t!(fs::create_dir_all(&dir)); config.out = dir; config.build = TargetSelection::from_user("A"); - config.hosts = vec![config.build] - .into_iter() - .chain(host.iter().map(|s| TargetSelection::from_user(s))) - .collect::>(); - config.targets = config - .hosts - .clone() - .into_iter() - .chain(target.iter().map(|s| TargetSelection::from_user(s))) - .collect::>(); + config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect(); + config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect(); config } @@ -41,7 +36,7 @@ mod defaults { #[test] fn build_default() { - let build = Build::new(configure(&[], &[])); + let build = Build::new(configure("build", &["A"], &["A"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); @@ -69,7 +64,7 @@ mod defaults { #[test] fn build_stage_0() { - let config = Config { stage: Some(0), ..configure(&[], &[]) }; + let config = Config { stage: 0, ..configure("build", &["A"], &["A"]) }; let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); @@ -89,9 +84,57 @@ mod defaults { assert!(builder.cache.all::().is_empty()); } + #[test] + fn build_cross_compile() { + let config = Config { stage: 1, ..configure("build", &["A", "B"], &["A", "B"]) }; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); + + // Ideally, this build wouldn't actually have `target: a` + // rustdoc/rustcc/std here (the user only requested a host=B build, so + // there's not really a need for us to build for target A in this case + // (since we're producing stage 1 libraries/binaries). But currently + // rustbuild is just a bit buggy here; this should be fixed though. + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, + compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, + tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, + ], + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b }, + ] + ); + } + #[test] fn doc_default() { - let mut config = configure(&[], &[]); + let mut config = configure("doc", &["A"], &["A"]); config.compiler_docs = true; config.cmd = Subcommand::Doc { paths: Vec::new(), open: false }; let build = Build::new(config); @@ -125,12 +168,12 @@ mod dist { use pretty_assertions::assert_eq; fn configure(host: &[&str], target: &[&str]) -> Config { - Config { stage: Some(2), ..super::configure(host, target) } + Config { stage: 2, ..super::configure("dist", host, target) } } #[test] fn dist_baseline() { - let build = Build::new(configure(&[], &[])); + let build = Build::new(configure(&["A"], &["A"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -156,7 +199,7 @@ mod dist { #[test] fn dist_with_targets() { - let build = Build::new(configure(&[], &["B"])); + let build = Build::new(configure(&["A"], &["A", "B"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -187,7 +230,7 @@ mod dist { #[test] fn dist_with_hosts() { - let build = Build::new(configure(&["B"], &[])); + let build = Build::new(configure(&["A", "B"], &["A", "B"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -216,6 +259,16 @@ mod dist { dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, + ], + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -223,7 +276,7 @@ mod dist { fn dist_only_cross_host() { let a = TargetSelection::from_user("A"); let b = TargetSelection::from_user("B"); - let mut build = Build::new(configure(&["B"], &[])); + let mut build = Build::new(configure(&["A", "B"], &["A", "B"])); build.config.docs = false; build.config.extended = true; build.hosts = vec![b]; @@ -245,7 +298,7 @@ mod dist { #[test] fn dist_with_targets_and_hosts() { - let build = Build::new(configure(&["B"], &["C"])); + let build = Build::new(configure(&["A", "B"], &["A", "B", "C"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -280,40 +333,26 @@ mod dist { } #[test] - fn dist_with_target_flag() { - let mut config = configure(&["B"], &["C"]); - config.skip_only_host_steps = true; // as-if --target=C was passed + fn dist_with_empty_host() { + let config = configure(&[], &["C"]); let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); let c = TargetSelection::from_user("C"); - assert_eq!( - first(builder.cache.all::()), - &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },] - ); - assert_eq!( - first(builder.cache.all::()), - &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },] - ); - assert_eq!(first(builder.cache.all::()), &[]); + assert_eq!(first(builder.cache.all::()), &[dist::Docs { host: c },]); + assert_eq!(first(builder.cache.all::()), &[dist::Mingw { host: c },]); assert_eq!( first(builder.cache.all::()), - &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - ] + &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },] ); - assert_eq!(first(builder.cache.all::()), &[]); } #[test] fn dist_with_same_targets_and_hosts() { - let build = Build::new(configure(&["B"], &["B"])); + let build = Build::new(configure(&["A", "B"], &["A", "B"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -366,11 +405,11 @@ mod dist { #[test] fn build_all() { - let build = Build::new(configure(&["B"], &["C"])); + let build = Build::new(configure(&["A", "B"], &["A", "B", "C"])); let mut builder = Builder::new(&build); builder.run_step_descriptions( &Builder::get_step_descriptions(Kind::Build), - &["src/rustc".into(), "library/std".into()], + &["compiler/rustc".into(), "library/std".into()], ); let a = TargetSelection::from_user("A"); @@ -383,12 +422,9 @@ mod dist { compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c }, ] ); assert!(!builder.cache.all::().is_empty()); @@ -398,24 +434,20 @@ mod dist { compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: b }, ] ); } #[test] - fn build_with_target_flag() { - let mut config = configure(&["B"], &["C"]); - config.skip_only_host_steps = true; + fn build_with_empty_host() { + let config = configure(&[], &["C"]); let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); let c = TargetSelection::from_user("C"); assert_eq!( @@ -423,13 +455,7 @@ mod dist { &[ compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c }, ] ); assert_eq!( @@ -438,7 +464,6 @@ mod dist { compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } }, ] ); assert_eq!( @@ -446,15 +471,14 @@ mod dist { &[ compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); } #[test] fn test_with_no_doc_stage0() { - let mut config = configure(&[], &[]); - config.stage = Some(0); + let mut config = configure(&["A"], &["A"]); + config.stage = 0; config.cmd = Subcommand::Test { paths: vec!["library/std".into()], test_args: vec![], @@ -493,7 +517,7 @@ mod dist { #[test] fn test_exclude() { - let mut config = configure(&[], &[]); + let mut config = configure(&["A"], &["A"]); config.exclude = vec!["src/tools/tidy".into()]; config.cmd = Subcommand::Test { paths: Vec::new(), @@ -520,7 +544,7 @@ mod dist { #[test] fn doc_ci() { - let mut config = configure(&[], &[]); + let mut config = configure(&["A"], &["A"]); config.compiler_docs = true; config.cmd = Subcommand::Doc { paths: Vec::new(), open: false }; let build = Build::new(config); @@ -549,7 +573,7 @@ mod dist { #[test] fn test_docs() { // Behavior of `x.py test` doing various documentation tests. - let mut config = configure(&[], &[]); + let mut config = configure(&["A"], &["A"]); config.cmd = Subcommand::Test { paths: vec![], test_args: vec![], diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 7ff00d85dd..d50e4cf526 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -132,7 +132,8 @@ pub fn find(build: &mut Build) { false }; - if cxx_configured { + // for VxWorks, record CXX compiler which will be used in lib.rs:linker() + if cxx_configured || target.contains("vxworks") { let compiler = cfg.get_compiler(); build.cxx.insert(target, compiler); } diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 51a9b0e0a5..2b82f6c30b 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -12,9 +12,6 @@ use build_helper::output; use crate::Build; -// The version number -pub const CFG_RELEASE_NUM: &str = "1.47.0"; - pub struct GitInfo { inner: Option, } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 9f34bb4e6c..ead0bd0413 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -66,6 +66,43 @@ impl Step for Std { let libdir = builder.sysroot_libdir(compiler, target); let hostdir = builder.sysroot_libdir(compiler, compiler.host); add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); + + // Then run cargo again, once we've put the rmeta files for the library + // crates into the sysroot. This is needed because e.g., core's tests + // depend on `libtest` -- Cargo presumes it will exist, but it doesn't + // since we initialize with an empty sysroot. + // + // Currently only the "libtest" tree of crates does this. + + let mut cargo = builder.cargo( + compiler, + Mode::Std, + SourceType::InTree, + target, + cargo_subcommand(builder.kind), + ); + std_cargo(builder, target, compiler.stage, &mut cargo); + cargo.arg("--all-targets"); + + // Explicitly pass -p for all dependencies krates -- this will force cargo + // to also check the tests/benches/examples for these crates, rather + // than just the leaf crate. + for krate in builder.in_tree_crates("test") { + cargo.arg("-p").arg(krate.name); + } + + builder.info(&format!( + "Checking std test/bench/example targets ({} -> {})", + &compiler.host, target + )); + run_cargo( + builder, + cargo, + args(builder.kind), + &libstd_test_stamp(builder, compiler, target), + vec![], + true, + ); } } @@ -106,6 +143,14 @@ impl Step for Rustc { cargo_subcommand(builder.kind), ); rustc_cargo(builder, &mut cargo, target); + cargo.arg("--all-targets"); + + // Explicitly pass -p for all compiler krates -- this will force cargo + // to also check the tests/benches/examples for these crates, rather + // than just the leaf crate. + for krate in builder.in_tree_crates("rustc-main") { + cargo.arg("-p").arg(krate.name); + } builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target)); run_cargo( @@ -149,7 +194,7 @@ macro_rules! tool_check_step { builder.ensure(Rustc { target }); - let cargo = prepare_tool_cargo( + let mut cargo = prepare_tool_cargo( builder, compiler, Mode::ToolRustc, @@ -160,12 +205,14 @@ macro_rules! tool_check_step { &[], ); - println!( + cargo.arg("--all-targets"); + + builder.info(&format!( "Checking {} artifacts ({} -> {})", stringify!($name).to_lowercase(), &compiler.host.triple, target.triple - ); + )); run_cargo( builder, cargo, @@ -202,12 +249,24 @@ tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree); // rejected. tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree); +tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree); + /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") } +/// Cargo's output path for the standard library in a given stage, compiled +/// by a particular compiler for the specified target. +fn libstd_test_stamp( + builder: &Builder<'_>, + compiler: Compiler, + target: TargetSelection, +) -> PathBuf { + builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp") +} + /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 373e240cb8..40bf6c4829 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -45,7 +45,7 @@ impl Step for Std { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Std { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -59,7 +59,9 @@ impl Step for Std { let target = self.target; let compiler = self.compiler; - if builder.config.keep_stage.contains(&compiler.stage) { + if builder.config.keep_stage.contains(&compiler.stage) + || builder.config.keep_stage_std.contains(&compiler.stage) + { builder.info("Warning: Using a potentially old libstd. This may not behave well."); builder.ensure(StdLink { compiler, target_compiler: compiler, target }); return; @@ -385,7 +387,7 @@ impl Step for StartupObjects { fn make_run(run: RunConfig<'_>) { run.builder.ensure(StartupObjects { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -449,12 +451,12 @@ impl Step for Rustc { const DEFAULT: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/rustc") + run.path("compiler/rustc") } fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustc { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -472,6 +474,7 @@ impl Step for Rustc { if builder.config.keep_stage.contains(&compiler.stage) { builder.info("Warning: Using a potentially old librustc. This may not behave well."); + builder.info("Warning: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); builder.ensure(RustcLink { compiler, target_compiler: compiler, target }); return; } @@ -524,7 +527,7 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelec .arg("--features") .arg(builder.rustc_features()) .arg("--manifest-path") - .arg(builder.src.join("src/rustc/Cargo.toml")); + .arg(builder.src.join("compiler/rustc/Cargo.toml")); rustc_cargo_env(builder, cargo, target); } @@ -560,7 +563,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS } // Pass down configuration from the LLVM build into the build of - // librustc_llvm and librustc_codegen_llvm. + // rustc_llvm and rustc_codegen_llvm. // // Note that this is disabled if LLVM itself is disabled or we're in a check // build. If we are in a check build we still go ahead here presuming we've @@ -579,7 +582,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { cargo.env("CFG_LLVM_ROOT", s); } - // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm. + // Some LLVM linker flags (-L and -l) may be needed to link rustc_llvm. if let Some(ref s) = builder.config.llvm_ldflags { cargo.env("LLVM_LINKER_FLAGS", s); } @@ -593,7 +596,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS let file = compiler_file(builder, builder.cxx(target).unwrap(), target, "libstdc++.a"); cargo.env("LLVM_STATIC_STDCPP", file); } - if builder.config.llvm_link_shared || builder.config.llvm_thin_lto { + if builder.config.llvm_link_shared { cargo.env("LLVM_LINK_SHARED", "1"); } if builder.config.llvm_use_libcxx { @@ -819,7 +822,7 @@ impl Step for Assemble { // Link the compiler binary itself into place let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host); - let rustc = out_dir.join(exe("rustc_binary", host)); + let rustc = out_dir.join(exe("rustc-main", host)); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); let compiler = builder.rustc(target_compiler); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 8b8b01b115..8985d1fbd0 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -10,14 +10,25 @@ use std::ffi::OsString; use std::fmt; use std::fs; use std::path::{Path, PathBuf}; -use std::process; use crate::cache::{Interned, INTERNER}; use crate::flags::Flags; pub use crate::flags::Subcommand; +use crate::util::exe; use build_helper::t; +use merge::Merge; use serde::Deserialize; +macro_rules! check_ci_llvm { + ($name:expr) => { + assert!( + $name.is_none(), + "setting {} is incompatible with download-ci-llvm.", + stringify!($name) + ); + }; +} + /// Global configuration for the entire build and/or bootstrap. /// /// This structure is derived from a combination of both `config.toml` and @@ -31,8 +42,10 @@ use serde::Deserialize; /// `config.toml.example`. #[derive(Default)] pub struct Config { + pub changelog_seen: Option, pub ccache: Option, - pub ninja: bool, + /// Call Build::ninja() instead of this. + pub ninja_in_file: bool, pub verbose: usize, pub submodules: bool, pub fast_submodules: bool, @@ -48,17 +61,19 @@ pub struct Config { pub profiler: bool, pub ignore_git: bool, pub exclude: Vec, + pub include_default_paths: bool, pub rustc_error_format: Option, pub json_output: bool, pub test_compare_mode: bool, pub llvm_libunwind: bool, - pub skip_only_host_steps: bool, - pub on_fail: Option, - pub stage: Option, + pub stage: u32, pub keep_stage: Vec, + pub keep_stage_std: Vec, pub src: PathBuf, + // defaults to `config.toml` + pub config: PathBuf, pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, @@ -83,6 +98,7 @@ pub struct Config { pub llvm_version_suffix: Option, pub llvm_use_linker: Option, pub llvm_allow_old_toolchain: Option, + pub llvm_from_ci: bool, pub use_lld: bool, pub lld_enabled: bool, @@ -99,6 +115,7 @@ pub struct Config { pub rust_codegen_units_std: Option, pub rust_debug_assertions: bool, pub rust_debug_assertions_std: bool, + pub rust_debug_logging: bool, pub rust_debuginfo_level_rustc: u32, pub rust_debuginfo_level_std: u32, pub rust_debuginfo_level_tools: u32, @@ -259,28 +276,51 @@ impl Target { #[derive(Deserialize, Default)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct TomlConfig { + changelog_seen: Option, build: Option, install: Option, llvm: Option, rust: Option, target: Option>, dist: Option, + profile: Option, +} + +impl Merge for TomlConfig { + fn merge( + &mut self, + TomlConfig { build, install, llvm, rust, dist, target, profile: _, changelog_seen: _ }: Self, + ) { + fn do_merge(x: &mut Option, y: Option) { + if let Some(new) = y { + if let Some(original) = x { + original.merge(new); + } else { + *x = Some(new); + } + } + }; + do_merge(&mut self.build, build); + do_merge(&mut self.install, install); + do_merge(&mut self.llvm, llvm); + do_merge(&mut self.rust, rust); + do_merge(&mut self.dist, dist); + assert!(target.is_none(), "merging target-specific config is not currently supported"); + } } /// TOML representation of various global build decisions. -#[derive(Deserialize, Default, Clone)] +#[derive(Deserialize, Default, Clone, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Build { build: Option, - #[serde(default)] - host: Vec, - #[serde(default)] - target: Vec, + host: Option>, + target: Option>, // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable build_dir: Option, cargo: Option, rustc: Option, - rustfmt: Option, /* allow bootstrap.py to use rustfmt key */ + rustfmt: Option, docs: Option, compiler_docs: Option, submodules: Option, @@ -301,10 +341,16 @@ struct Build { configure_args: Option>, local_rebuild: Option, print_step_timings: Option, + doc_stage: Option, + build_stage: Option, + test_stage: Option, + install_stage: Option, + dist_stage: Option, + bench_stage: Option, } /// TOML representation of various global install decisions. -#[derive(Deserialize, Default, Clone)] +#[derive(Deserialize, Default, Clone, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Install { prefix: Option, @@ -321,7 +367,7 @@ struct Install { } /// TOML representation of how the LLVM build is configured. -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Llvm { skip_rebuild: Option, @@ -345,9 +391,10 @@ struct Llvm { use_libcxx: Option, use_linker: Option, allow_old_toolchain: Option, + download_ci_llvm: Option, } -#[derive(Deserialize, Default, Clone)] +#[derive(Deserialize, Default, Clone, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Dist { sign_folder: Option, @@ -371,7 +418,7 @@ impl Default for StringOrBool { } /// TOML representation of how the Rust build is configured. -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Rust { optimize: Option, @@ -380,6 +427,7 @@ struct Rust { codegen_units_std: Option, debug_assertions: Option, debug_assertions_std: Option, + debug_logging: Option, debuginfo_level: Option, debuginfo_level_rustc: Option, debuginfo_level_std: Option, @@ -415,7 +463,7 @@ struct Rust { } /// TOML representation of how each build target is configured. -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct TomlTarget { cc: Option, @@ -450,6 +498,7 @@ impl Config { pub fn default_opts() -> Config { let mut config = Config::default(); config.llvm_optimize = true; + config.ninja_in_file = true; config.llvm_version_check = true; config.backtrace = true; config.rust_optimize = true; @@ -467,31 +516,33 @@ impl Config { config.missing_tools = false; // set by bootstrap.py - config.build = TargetSelection::from_user(&env::var("BUILD").expect("'BUILD' to be set")); - config.src = Config::path_from_python("SRC"); + config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + // Undo `src/bootstrap` + config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned(); config.out = Config::path_from_python("BUILD_DIR"); - config.initial_rustc = Config::path_from_python("RUSTC"); - config.initial_cargo = Config::path_from_python("CARGO"); - config.initial_rustfmt = env::var_os("RUSTFMT").map(Config::normalize_python_path); + config.initial_cargo = PathBuf::from(env!("CARGO")); + config.initial_rustc = PathBuf::from(env!("RUSTC")); config } pub fn parse(args: &[String]) -> Config { let flags = Flags::parse(&args); - let file = flags.config.clone(); + let mut config = Config::default_opts(); config.exclude = flags.exclude; + config.include_default_paths = flags.include_default_paths; config.rustc_error_format = flags.rustc_error_format; config.json_output = flags.json_output; config.on_fail = flags.on_fail; - config.stage = flags.stage; config.jobs = flags.jobs.map(threads_from_config); config.cmd = flags.cmd; config.incremental = flags.incremental; config.dry_run = flags.dry_run; config.keep_stage = flags.keep_stage; + config.keep_stage_std = flags.keep_stage_std; config.bindir = "bin".into(); // default if let Some(value) = flags.deny_warnings { config.deny_warnings = value; @@ -503,48 +554,56 @@ impl Config { config.out = dir; } - // If --target was specified but --host wasn't specified, don't run any host-only tests. - let has_hosts = !flags.host.is_empty(); - let has_targets = !flags.target.is_empty(); - config.skip_only_host_steps = !has_hosts && has_targets; - - let toml = file - .map(|file| { - let contents = t!(fs::read_to_string(&file)); - match toml::from_str(&contents) { - Ok(table) => table, - Err(err) => { - println!( - "failed to parse TOML configuration '{}': {}", - file.display(), - err - ); - process::exit(2); - } + #[cfg(test)] + let get_toml = |_| TomlConfig::default(); + #[cfg(not(test))] + let get_toml = |file: &Path| { + use std::process; + + let contents = t!(fs::read_to_string(file), "`include` config not found"); + match toml::from_str(&contents) { + Ok(table) => table, + Err(err) => { + println!("failed to parse TOML configuration '{}': {}", file.display(), err); + process::exit(2); } - }) - .unwrap_or_else(TomlConfig::default); - - let build = toml.build.clone().unwrap_or_default(); - // set by bootstrap.py - config.hosts.push(config.build); - for host in build.host.iter().map(|h| TargetSelection::from_user(h)) { - if !config.hosts.contains(&host) { - config.hosts.push(host); } + }; + + let mut toml = flags.config.as_deref().map(get_toml).unwrap_or_else(TomlConfig::default); + if let Some(include) = &toml.profile { + let mut include_path = config.src.clone(); + include_path.push("src"); + include_path.push("bootstrap"); + include_path.push("defaults"); + include_path.push(format!("config.toml.{}", include)); + let included_toml = get_toml(&include_path); + toml.merge(included_toml); } - for target in config - .hosts - .iter() - .copied() - .chain(build.target.iter().map(|h| TargetSelection::from_user(h))) - { - if !config.targets.contains(&target) { - config.targets.push(target); - } + + config.changelog_seen = toml.changelog_seen; + if let Some(cfg) = flags.config { + config.config = cfg; } - config.hosts = if !flags.host.is_empty() { flags.host } else { config.hosts }; - config.targets = if !flags.target.is_empty() { flags.target } else { config.targets }; + + let build = toml.build.unwrap_or_default(); + + config.hosts = if let Some(arg_host) = flags.host { + arg_host + } else if let Some(file_host) = build.host { + file_host.iter().map(|h| TargetSelection::from_user(h)).collect() + } else { + vec![config.build] + }; + config.targets = if let Some(arg_target) = flags.target { + arg_target + } else if let Some(file_target) = build.target { + file_target.iter().map(|h| TargetSelection::from_user(h)).collect() + } else { + // If target is *not* configured, then default to the host + // toolchains. + config.hosts.clone() + }; config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); @@ -559,6 +618,9 @@ impl Config { set(&mut config.full_bootstrap, build.full_bootstrap); set(&mut config.extended, build.extended); config.tools = build.tools; + if build.rustfmt.is_some() { + config.initial_rustfmt = build.rustfmt; + } set(&mut config.verbose, build.verbose); set(&mut config.sanitizers, build.sanitizers); set(&mut config.profiler, build.profiler); @@ -566,16 +628,62 @@ impl Config { set(&mut config.configure_args, build.configure_args); set(&mut config.local_rebuild, build.local_rebuild); set(&mut config.print_step_timings, build.print_step_timings); + + // See https://github.com/rust-lang/compiler-team/issues/326 + config.stage = match config.cmd { + Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0), + Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1), + Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1), + Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2), + Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2), + Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2), + // These are all bootstrap tools, which don't depend on the compiler. + // The stage we pass shouldn't matter, but use 0 just in case. + Subcommand::Clean { .. } + | Subcommand::Check { .. } + | Subcommand::Clippy { .. } + | Subcommand::Fix { .. } + | Subcommand::Run { .. } + | Subcommand::Setup { .. } + | Subcommand::Format { .. } => flags.stage.unwrap_or(0), + }; + + // CI should always run stage 2 builds, unless it specifically states otherwise + #[cfg(not(test))] + if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None { + match config.cmd { + Subcommand::Test { .. } + | Subcommand::Doc { .. } + | Subcommand::Build { .. } + | Subcommand::Bench { .. } + | Subcommand::Dist { .. } + | Subcommand::Install { .. } => { + assert_eq!( + config.stage, 2, + "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`", + config.stage, + ); + } + Subcommand::Clean { .. } + | Subcommand::Check { .. } + | Subcommand::Clippy { .. } + | Subcommand::Fix { .. } + | Subcommand::Run { .. } + | Subcommand::Setup { .. } + | Subcommand::Format { .. } => {} + } + } + config.verbose = cmp::max(config.verbose, flags.verbose); - if let Some(ref install) = toml.install { - config.prefix = install.prefix.clone().map(PathBuf::from); - config.sysconfdir = install.sysconfdir.clone().map(PathBuf::from); - config.datadir = install.datadir.clone().map(PathBuf::from); - config.docdir = install.docdir.clone().map(PathBuf::from); - set(&mut config.bindir, install.bindir.clone().map(PathBuf::from)); - config.libdir = install.libdir.clone().map(PathBuf::from); - config.mandir = install.mandir.clone().map(PathBuf::from); + if let Some(install) = toml.install { + config.prefix = install.prefix.map(PathBuf::from); + config.sysconfdir = install.sysconfdir.map(PathBuf::from); + config.datadir = install.datadir.map(PathBuf::from); + config.docdir = install.docdir.map(PathBuf::from); + set(&mut config.bindir, install.bindir.map(PathBuf::from)); + config.libdir = install.libdir.map(PathBuf::from); + config.mandir = install.mandir.map(PathBuf::from); } // We want the llvm-skip-rebuild flag to take precedence over the @@ -589,6 +697,7 @@ impl Config { let mut debug = None; let mut debug_assertions = None; let mut debug_assertions_std = None; + let mut debug_logging = None; let mut debuginfo_level = None; let mut debuginfo_level_rustc = None; let mut debuginfo_level_std = None; @@ -597,7 +706,7 @@ impl Config { let mut optimize = None; let mut ignore_git = None; - if let Some(ref llvm) = toml.llvm { + if let Some(llvm) = toml.llvm { match llvm.ccache { Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()), Some(StringOrBool::Bool(true)) => { @@ -605,7 +714,7 @@ impl Config { } Some(StringOrBool::Bool(false)) | None => {} } - set(&mut config.ninja, llvm.ninja); + set(&mut config.ninja_in_file, llvm.ninja); llvm_assertions = llvm.assertions; llvm_skip_rebuild = llvm_skip_rebuild.or(llvm.skip_rebuild); set(&mut config.llvm_optimize, llvm.optimize); @@ -626,12 +735,50 @@ impl Config { set(&mut config.llvm_use_libcxx, llvm.use_libcxx); config.llvm_use_linker = llvm.use_linker.clone(); config.llvm_allow_old_toolchain = llvm.allow_old_toolchain; + config.llvm_from_ci = llvm.download_ci_llvm.unwrap_or(false); + + if config.llvm_from_ci { + // None of the LLVM options, except assertions, are supported + // when using downloaded LLVM. We could just ignore these but + // that's potentially confusing, so force them to not be + // explicitly set. The defaults and CI defaults don't + // necessarily match but forcing people to match (somewhat + // arbitrary) CI configuration locally seems bad/hard. + check_ci_llvm!(llvm.optimize); + check_ci_llvm!(llvm.thin_lto); + check_ci_llvm!(llvm.release_debuginfo); + check_ci_llvm!(llvm.link_shared); + check_ci_llvm!(llvm.static_libstdcpp); + check_ci_llvm!(llvm.targets); + check_ci_llvm!(llvm.experimental_targets); + check_ci_llvm!(llvm.link_jobs); + check_ci_llvm!(llvm.link_shared); + check_ci_llvm!(llvm.clang_cl); + check_ci_llvm!(llvm.version_suffix); + check_ci_llvm!(llvm.cflags); + check_ci_llvm!(llvm.cxxflags); + check_ci_llvm!(llvm.ldflags); + check_ci_llvm!(llvm.use_libcxx); + check_ci_llvm!(llvm.use_linker); + check_ci_llvm!(llvm.allow_old_toolchain); + + // CI-built LLVM is shared + config.llvm_link_shared = true; + } + + if config.llvm_thin_lto { + // If we're building with ThinLTO on, we want to link to LLVM + // shared, to avoid re-doing ThinLTO (which happens in the link + // step) with each stage. + config.llvm_link_shared = true; + } } - if let Some(ref rust) = toml.rust { + if let Some(rust) = toml.rust { debug = rust.debug; debug_assertions = rust.debug_assertions; debug_assertions_std = rust.debug_assertions_std; + debug_logging = rust.debug_logging; debuginfo_level = rust.debuginfo_level; debuginfo_level_rustc = rust.debuginfo_level_rustc; debuginfo_level_std = rust.debuginfo_level_std; @@ -647,7 +794,7 @@ impl Config { set(&mut config.test_compare_mode, rust.test_compare_mode); set(&mut config.llvm_libunwind, rust.llvm_libunwind); set(&mut config.backtrace, rust.backtrace); - set(&mut config.channel, rust.channel.clone()); + set(&mut config.channel, rust.channel); set(&mut config.rust_dist_src, rust.dist_src); set(&mut config.verbose_tests, rust.verbose_tests); // in the case "false" is set explicitly, do not overwrite the command line args @@ -658,9 +805,9 @@ impl Config { set(&mut config.lld_enabled, rust.lld); set(&mut config.llvm_tools_enabled, rust.llvm_tools); config.rustc_parallel = rust.parallel_compiler.unwrap_or(false); - config.rustc_default_linker = rust.default_linker.clone(); - config.musl_root = rust.musl_root.clone().map(PathBuf::from); - config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); + config.rustc_default_linker = rust.default_linker; + config.musl_root = rust.musl_root.map(PathBuf::from); + config.save_toolstates = rust.save_toolstates.map(PathBuf::from); set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings)); set(&mut config.backtrace_on_ice, rust.backtrace_on_ice); set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir); @@ -677,9 +824,9 @@ impl Config { config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); } - if let Some(ref t) = toml.target { + if let Some(t) = toml.target { for (triple, cfg) in t { - let mut target = Target::from_triple(triple); + let mut target = Target::from_triple(&triple); if let Some(ref s) = cfg.llvm_config { target.llvm_config = Some(config.src.join(s)); @@ -693,35 +840,52 @@ impl Config { if let Some(s) = cfg.no_std { target.no_std = s; } - target.cc = cfg.cc.clone().map(PathBuf::from); - target.cxx = cfg.cxx.clone().map(PathBuf::from); - target.ar = cfg.ar.clone().map(PathBuf::from); - target.ranlib = cfg.ranlib.clone().map(PathBuf::from); - target.linker = cfg.linker.clone().map(PathBuf::from); + target.cc = cfg.cc.map(PathBuf::from); + target.cxx = cfg.cxx.map(PathBuf::from); + target.ar = cfg.ar.map(PathBuf::from); + target.ranlib = cfg.ranlib.map(PathBuf::from); + target.linker = cfg.linker.map(PathBuf::from); target.crt_static = cfg.crt_static; - target.musl_root = cfg.musl_root.clone().map(PathBuf::from); - target.musl_libdir = cfg.musl_libdir.clone().map(PathBuf::from); - target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from); - target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); + target.musl_root = cfg.musl_root.map(PathBuf::from); + target.musl_libdir = cfg.musl_libdir.map(PathBuf::from); + target.wasi_root = cfg.wasi_root.map(PathBuf::from); + target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from); - config.target_config.insert(TargetSelection::from_user(triple), target); + config.target_config.insert(TargetSelection::from_user(&triple), target); } } - if let Some(ref t) = toml.dist { - config.dist_sign_folder = t.sign_folder.clone().map(PathBuf::from); - config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from); - config.dist_upload_addr = t.upload_addr.clone(); + if config.llvm_from_ci { + let triple = &config.build.triple; + let mut build_target = config + .target_config + .entry(config.build) + .or_insert_with(|| Target::from_triple(&triple)); + + 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))); + } + + if let Some(t) = toml.dist { + config.dist_sign_folder = t.sign_folder.map(PathBuf::from); + config.dist_gpg_password_file = t.gpg_password_file.map(PathBuf::from); + config.dist_upload_addr = t.upload_addr; set(&mut config.rust_dist_src, t.src_tarball); set(&mut config.missing_tools, t.missing_tools); } + // Cargo does not provide a RUSTFMT environment variable, so we + // synthesize it manually. Note that we also later check the config.toml + // and set this to that path if necessary. + let rustfmt = config.initial_rustc.with_file_name(exe("rustfmt", config.build)); + config.initial_rustfmt = if rustfmt.exists() { Some(rustfmt) } else { None }; + // Now that we've reached the end of our configuration, infer the // default values for all options that we haven't otherwise stored yet. - set(&mut config.initial_rustc, build.rustc.map(PathBuf::from)); - set(&mut config.initial_cargo, build.cargo.map(PathBuf::from)); - config.llvm_skip_rebuild = llvm_skip_rebuild.unwrap_or(false); let default = false; @@ -735,6 +899,8 @@ impl Config { config.rust_debug_assertions_std = debug_assertions_std.unwrap_or(config.rust_debug_assertions); + config.rust_debug_logging = debug_logging.unwrap_or(config.rust_debug_assertions); + let with_defaults = |debuginfo_level_specific: Option| { debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { 1 diff --git a/src/bootstrap/defaults/README.md b/src/bootstrap/defaults/README.md new file mode 100644 index 0000000000..f5b96db1b0 --- /dev/null +++ b/src/bootstrap/defaults/README.md @@ -0,0 +1,12 @@ +# About bootstrap defaults + +These defaults are intended to be a good starting point for working with x.py, +with the understanding that no one set of defaults make sense for everyone. + +They are still experimental, and we'd appreciate your help improving them! +If you use a setting that's not in these defaults that you think +others would benefit from, please [file an issue] or make a PR with the changes. +Similarly, if one of these defaults doesn't match what you use personally, +please open an issue to get it changed. + +[file an issue]: https://github.com/rust-lang/rust/issues/new/choose diff --git a/src/bootstrap/defaults/config.toml.codegen b/src/bootstrap/defaults/config.toml.codegen new file mode 100644 index 0000000000..a9505922ca --- /dev/null +++ b/src/bootstrap/defaults/config.toml.codegen @@ -0,0 +1,13 @@ +# These defaults are meant for contributors to the compiler who modify codegen or LLVM +[llvm] +# This enables debug-assertions in LLVM, +# catching logic errors in codegen much earlier in the process. +assertions = true + +[rust] +# This enables `RUSTC_LOG=debug`, avoiding confusing situations +# where adding `debug!()` appears to do nothing. +# However, it makes running the compiler slightly slower. +debug-logging = true +# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. +incremental = true diff --git a/src/bootstrap/defaults/config.toml.compiler b/src/bootstrap/defaults/config.toml.compiler new file mode 100644 index 0000000000..4772de8a2c --- /dev/null +++ b/src/bootstrap/defaults/config.toml.compiler @@ -0,0 +1,8 @@ +# These defaults are meant for contributors to the compiler who do not modify codegen or LLVM +[rust] +# This enables `RUSTC_LOG=debug`, avoiding confusing situations +# where adding `debug!()` appears to do nothing. +# However, it makes running the compiler slightly slower. +debug-logging = true +# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. +incremental = true diff --git a/src/bootstrap/defaults/config.toml.library b/src/bootstrap/defaults/config.toml.library new file mode 100644 index 0000000000..e4316f4d86 --- /dev/null +++ b/src/bootstrap/defaults/config.toml.library @@ -0,0 +1,10 @@ +# These defaults are meant for contributors to the standard library and documentation. +[build] +# When building the standard library, you almost never want to build the compiler itself. +build-stage = 0 +test-stage = 0 +bench-stage = 0 + +[rust] +# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. +incremental = true diff --git a/src/bootstrap/defaults/config.toml.user b/src/bootstrap/defaults/config.toml.user new file mode 100644 index 0000000000..6647061d88 --- /dev/null +++ b/src/bootstrap/defaults/config.toml.user @@ -0,0 +1,9 @@ +# These defaults are meant for users and distro maintainers building from source, without intending to make multiple changes. +[build] +# When compiling from source, you almost always want a full stage 2 build, +# which has all the latest optimizations from nightly. +build-stage = 2 +test-stage = 2 +doc-stage = 2 +# When compiling from source, you usually want all tools. +extended = true diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index d021feafbe..1887b805da 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -18,7 +18,6 @@ use build_helper::{output, t}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; -use crate::channel; use crate::compile; use crate::config::TargetSelection; use crate::tool::{self, Tool}; @@ -27,27 +26,10 @@ use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; use time::{self, Timespec}; pub fn pkgname(builder: &Builder<'_>, component: &str) -> String { - if component == "cargo" { - format!("{}-{}", component, builder.cargo_package_vers()) - } else if component == "rls" { - format!("{}-{}", component, builder.rls_package_vers()) - } else if component == "rust-analyzer" { - format!("{}-{}", component, builder.rust_analyzer_package_vers()) - } else if component == "clippy" { - format!("{}-{}", component, builder.clippy_package_vers()) - } else if component == "miri" { - format!("{}-{}", component, builder.miri_package_vers()) - } else if component == "rustfmt" { - format!("{}-{}", component, builder.rustfmt_package_vers()) - } else if component == "llvm-tools" { - format!("{}-{}", component, builder.llvm_tools_package_vers()) - } else { - assert!(component.starts_with("rust")); - format!("{}-{}", component, builder.rust_package_vers()) - } + format!("{}-{}", component, builder.rust_package_vers()) } -fn distdir(builder: &Builder<'_>) -> PathBuf { +pub(crate) fn distdir(builder: &Builder<'_>) -> PathBuf { builder.out.join("dist") } @@ -323,8 +305,8 @@ fn make_win_dist( // Warn windows-gnu users that the bundled GCC cannot compile C files builder.create( &target_bin_dir.join("GCC-WARNING.txt"), - "gcc.exe contained in this folder cannot be used for compiling C files - it is only\ - used as a linker. In order to be able to compile projects containing C code use\ + "gcc.exe contained in this folder cannot be used for compiling C files - it is only \ + used as a linker. In order to be able to compile projects containing C code use \ the GCC provided by MinGW or Cygwin.", ); @@ -569,7 +551,7 @@ impl Step for Rustc { &page_dst, &[ ("", &month_year), - ("", channel::CFG_RELEASE_NUM), + ("", &builder.version), ], ); } @@ -605,7 +587,9 @@ impl Step for DebuggerScripts { fn make_run(run: RunConfig<'_>) { run.builder.ensure(DebuggerScripts { - sysroot: run.builder.sysroot(run.builder.compiler(run.builder.top_stage, run.host)), + sysroot: run + .builder + .sysroot(run.builder.compiler(run.builder.top_stage, run.build_triple())), host: run.target, }); } @@ -791,6 +775,18 @@ impl Step for RustcDev { let stamp = compile::librustc_stamp(builder, compiler_to_use, target); copy_target_libs(builder, target, &image, &stamp); + // Copy compiler sources. + let dst_src = image.join("lib/rustlib/rustc-src/rust"); + t!(fs::create_dir_all(&dst_src)); + + let src_files = ["Cargo.lock"]; + // This is the reduced set of paths which will become the rustc-dev component + // (essentially the compiler crates and all of their path dependencies). + copy_src_dirs(builder, &builder.src, &["compiler"], &[], &dst_src); + for file in src_files.iter() { + builder.copy(&builder.src.join(file), &dst_src.join(file)); + } + let mut cmd = rust_installer(builder); cmd.arg("generate") .arg("--product-name=Rust") @@ -1020,7 +1016,7 @@ impl Step for Src { copy_src_dirs( builder, &builder.src, - &["library"], + &["library", "src/llvm-project/libunwind"], &[ // not needed and contains symlinks which rustup currently // chokes on when unpacking. @@ -1097,7 +1093,7 @@ impl Step for PlainSourceTarball { "Cargo.toml", "Cargo.lock", ]; - let src_dirs = ["src", "library"]; + let src_dirs = ["src", "compiler", "library"]; copy_src_dirs(builder, &builder.src, &src_dirs, &[], &plain_dst_src); @@ -2287,9 +2283,9 @@ impl Step for Extended { } fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) { - let mut parts = channel::CFG_RELEASE_NUM.split('.'); + let mut parts = builder.version.split('.'); cmd.env("CFG_RELEASE_INFO", builder.rust_version()) - .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM) + .env("CFG_RELEASE_NUM", &builder.version) .env("CFG_RELEASE", builder.rust_release()) .env("CFG_VER_MAJOR", parts.next().unwrap()) .env("CFG_VER_MINOR", parts.next().unwrap()) @@ -2355,15 +2351,9 @@ impl Step for HashSign { cmd.arg(sign); cmd.arg(distdir(builder)); cmd.arg(today.trim()); - cmd.arg(builder.rust_package_vers()); cmd.arg(addr); - cmd.arg(builder.package_vers(&builder.release_num("cargo"))); - cmd.arg(builder.package_vers(&builder.release_num("rls"))); - cmd.arg(builder.package_vers(&builder.release_num("rust-analyzer/crates/rust-analyzer"))); - cmd.arg(builder.package_vers(&builder.release_num("clippy"))); - cmd.arg(builder.package_vers(&builder.release_num("miri"))); - cmd.arg(builder.package_vers(&builder.release_num("rustfmt"))); - cmd.arg(builder.llvm_tools_package_vers()); + cmd.arg(&builder.config.channel); + cmd.env("BUILD_MANIFEST_LEGACY", "1"); builder.create_dir(&distdir(builder)); @@ -2380,26 +2370,29 @@ impl Step for HashSign { /// Note: This function does not yet support Windows, but we also don't support /// linking LLVM tools dynamically on Windows yet. fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) { - let src_libdir = builder.llvm_out(target).join("lib"); + if !builder.config.llvm_link_shared { + // We do not need to copy LLVM files into the sysroot if it is not + // dynamically linked; it is already included into librustc_llvm + // statically. + return; + } + // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib + // instead of libLLVM-11-rust-....dylib, as on linux. It's not entirely + // clear why this is the case, though. llvm-config will emit the versioned + // paths and we don't want those in the sysroot (as we're expecting + // unversioned paths). if target.contains("apple-darwin") { + let src_libdir = builder.llvm_out(target).join("lib"); let llvm_dylib_path = src_libdir.join("libLLVM.dylib"); if llvm_dylib_path.exists() { builder.install(&llvm_dylib_path, dst_libdir, 0o644); } - return; - } - - // Usually libLLVM.so is a symlink to something like libLLVM-6.0.so. - // Since tools link to the latter rather than the former, we have to - // follow the symlink to find out what to distribute. - let llvm_dylib_path = src_libdir.join("libLLVM.so"); - if llvm_dylib_path.exists() { - let llvm_dylib_path = llvm_dylib_path.canonicalize().unwrap_or_else(|e| { - panic!("dist: Error calling canonicalize path `{}`: {}", llvm_dylib_path.display(), e); - }); - - builder.install(&llvm_dylib_path, dst_libdir, 0o644); + } else if let Ok(llvm_config) = crate::native::prebuilt_llvm_config(builder, target) { + let files = output(Command::new(llvm_config).arg("--libfiles")); + for file in files.lines() { + builder.install(Path::new(file), dst_libdir, 0o644); + } } } @@ -2499,3 +2492,161 @@ impl Step for LlvmTools { Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) } } + +// Tarball intended for internal consumption to ease rustc/std development. +// +// Should not be considered stable by end users. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct RustDev { + pub target: TargetSelection, +} + +impl Step for RustDev { + type Output = Option; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("rust-dev") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustDev { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> Option { + let target = self.target; + + /* run only if llvm-config isn't used */ + if let Some(config) = builder.config.target_config.get(&target) { + if let Some(ref _s) = config.llvm_config { + builder.info(&format!("Skipping RustDev ({}): external LLVM", target)); + return None; + } + } + + builder.info(&format!("Dist RustDev ({})", target)); + let _time = timeit(builder); + let src = builder.src.join("src/llvm-project/llvm"); + let name = pkgname(builder, "rust-dev"); + + let tmp = tmpdir(builder); + let image = tmp.join("rust-dev-image"); + drop(fs::remove_dir_all(&image)); + + // Prepare the image directory + let dst_bindir = image.join("bin"); + t!(fs::create_dir_all(&dst_bindir)); + + let exe = builder.llvm_out(target).join("bin").join(exe("llvm-config", target)); + builder.install(&exe, &dst_bindir, 0o755); + builder.install(&builder.llvm_filecheck(target), &dst_bindir, 0o755); + + // Copy the include directory as well; needed mostly to build + // librustc_llvm properly (e.g., llvm-config.h is in here). But also + // just broadly useful to be able to link against the bundled LLVM. + builder.cp_r(&builder.llvm_out(target).join("include"), &image.join("include")); + + // Copy libLLVM.so to the target lib dir as well, so the RPATH like + // `$ORIGIN/../lib` can find it. It may also be used as a dependency + // of `rustc-dev` to support the inherited `-lLLVM` when using the + // compiler libraries. + maybe_install_llvm(builder, target, &image.join("lib")); + + // Prepare the overlay + let overlay = tmp.join("rust-dev-overlay"); + drop(fs::remove_dir_all(&overlay)); + builder.create_dir(&overlay); + builder.install(&src.join("README.txt"), &overlay, 0o644); + builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644); + builder.create(&overlay.join("version"), &builder.rust_version()); + + // Generate the installer tarball + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=rust-dev-installed.") + .arg("--image-dir") + .arg(&image) + .arg("--work-dir") + .arg(&tmpdir(builder)) + .arg("--output-dir") + .arg(&distdir(builder)) + .arg("--non-installed-overlay") + .arg(&overlay) + .arg(format!("--package-name={}-{}", name, target.triple)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=rust-dev"); + + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) + } +} + +/// Tarball containing a prebuilt version of the build-manifest tool, intented to be used by the +/// release process to avoid cloning the monorepo and building stuff. +/// +/// Should not be considered stable by end users. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct BuildManifest { + pub target: TargetSelection, +} + +impl Step for BuildManifest { + type Output = PathBuf; + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/build-manifest") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(BuildManifest { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + let build_manifest = builder.tool_exe(Tool::BuildManifest); + + let name = pkgname(builder, "build-manifest"); + let tmp = tmpdir(builder); + + // Prepare the image. + let image = tmp.join("build-manifest-image"); + let image_bin = image.join("bin"); + let _ = fs::remove_dir_all(&image); + t!(fs::create_dir_all(&image_bin)); + builder.install(&build_manifest, &image_bin, 0o755); + + // Prepare the overlay. + let overlay = tmp.join("build-manifest-overlay"); + let _ = fs::remove_dir_all(&overlay); + builder.create_dir(&overlay); + builder.create(&overlay.join("version"), &builder.rust_version()); + for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] { + builder.install(&builder.src.join(file), &overlay, 0o644); + } + + // Create the final tarball. + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=build-manifest installed.") + .arg("--image-dir") + .arg(&image) + .arg("--work-dir") + .arg(&tmpdir(builder)) + .arg("--output-dir") + .arg(&distdir(builder)) + .arg("--non-installed-overlay") + .arg(&overlay) + .arg(format!("--package-name={}-{}", name, self.target.triple)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=build-manifest"); + + builder.run(&mut cmd); + distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple)) + } +} diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 2a8f43950d..aa670bd9a2 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -66,7 +66,6 @@ book!( Nomicon, "src/doc/nomicon", "nomicon"; Reference, "src/doc/reference", "reference"; RustByExample, "src/doc/rust-by-example", "rust-by-example"; - RustcBook, "src/doc/rustc", "rustc"; RustdocBook, "src/doc/rustdoc", "rustdoc"; ); @@ -434,7 +433,7 @@ impl Step for Std { .arg("-Z") .arg("unstable-options") .arg("--resource-suffix") - .arg(crate::channel::CFG_RELEASE_NUM) + .arg(&builder.version) .arg("--index-page") .arg(&builder.src.join("src/doc/index.md")); @@ -660,7 +659,7 @@ impl Step for ErrorIndex { let mut index = tool::ErrorIndex::command(builder, self.compiler); index.arg("html"); index.arg(out.join("error-index.html")); - index.arg(crate::channel::CFG_RELEASE_NUM); + index.arg(&builder.version); builder.run(&mut index); } @@ -694,6 +693,7 @@ impl Step for UnstableBookGen { builder.remove_dir(&out); let mut cmd = builder.tool_cmd(Tool::UnstableBookGen); cmd.arg(builder.src.join("library")); + cmd.arg(builder.src.join("compiler")); cmd.arg(builder.src.join("src")); cmd.arg(out); @@ -717,3 +717,72 @@ fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> symlink_dir(config, src, dst) } + +#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustcBook { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for RustcBook { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let builder = run.builder; + run.path("src/doc/rustc").default_condition(builder.config.docs) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustcBook { + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + target: run.target, + }); + } + + /// Builds the rustc book. + /// + /// The lints are auto-generated by a tool, and then merged into the book + /// in the "md-doc" directory in the build output directory. Then + /// "rustbook" is used to convert it to HTML. + fn run(self, builder: &Builder<'_>) { + let out_base = builder.md_doc_out(self.target).join("rustc"); + t!(fs::create_dir_all(&out_base)); + let out_listing = out_base.join("src/lints"); + builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base); + builder.info(&format!("Generating lint docs ({})", self.target)); + + let rustc = builder.rustc(self.compiler); + // The tool runs `rustc` for extracting output examples, so it needs a + // functional sysroot. + builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); + let mut cmd = builder.tool_cmd(Tool::LintDocs); + cmd.arg("--src"); + cmd.arg(builder.src.join("compiler")); + cmd.arg("--out"); + cmd.arg(&out_listing); + cmd.arg("--rustc"); + cmd.arg(&rustc); + cmd.arg("--rustc-target").arg(&self.target.rustc_target_arg()); + if builder.config.verbose() { + cmd.arg("--verbose"); + } + // If the lib directories are in an unusual location (changed in + // config.toml), then this needs to explicitly update the dylib search + // path. + builder.add_rustc_lib_path(self.compiler, &mut cmd); + builder.run(&mut cmd); + // Run rustbook/mdbook to generate the HTML pages. + builder.ensure(RustbookSrc { + target: self.target, + name: INTERNER.intern_str("rustc"), + src: INTERNER.intern_path(out_base), + }); + if is_explicit_request(builder, "src/doc/rustc") { + let out = builder.doc_out(self.target); + let index = out.join("rustc").join("index.html"); + open(builder, &index); + } + } +} diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 38b3a32e3b..4bf4a19363 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -7,6 +7,7 @@ use std::env; use std::path::PathBuf; use std::process; +use build_helper::t; use getopts::Options; use crate::builder::Builder; @@ -19,14 +20,16 @@ pub struct Flags { pub on_fail: Option, pub stage: Option, pub keep_stage: Vec, + pub keep_stage_std: Vec, - pub host: Vec, - pub target: Vec, + pub host: Option>, + pub target: Option>, pub config: Option, pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, pub exclude: Vec, + pub include_default_paths: bool, pub rustc_error_format: Option, pub json_output: bool, pub dry_run: bool, @@ -88,6 +91,9 @@ pub enum Subcommand { Run { paths: Vec, }, + Setup { + path: String, + }, } impl Default for Subcommand { @@ -98,7 +104,6 @@ impl Default for Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { - let mut extra_help = String::new(); let mut subcommand_help = String::from( "\ Usage: x.py [options] [...] @@ -129,6 +134,11 @@ To learn more about a subcommand, run `./x.py -h`", opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); opts.optmulti("", "exclude", "build paths to exclude", "PATH"); + opts.optflag( + "", + "include-default-paths", + "include default paths in addition to the provided ones", + ); opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optflag("", "dry-run", "dry run; don't build anything"); opts.optopt( @@ -145,6 +155,13 @@ To learn more about a subcommand, run `./x.py -h`", (pass multiple times to keep e.g., both stages 0 and 1)", "N", ); + opts.optmulti( + "", + "keep-stage-std", + "stage(s) of the standard library to keep without recompiling \ + (pass multiple times to keep e.g., both stages 0 and 1)", + "N", + ); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); let j_msg = format!( "number of jobs to run in parallel; \ @@ -170,16 +187,6 @@ To learn more about a subcommand, run `./x.py -h`", "VALUE", ); - // fn usage() - let usage = - |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { - println!("{}", opts.usage(subcommand_help)); - if !extra_help.is_empty() { - println!("{}", extra_help); - } - process::exit(exit_code); - }; - // We can't use getopt to parse the options until we have completed specifying which // options are valid, but under the current implementation, some options are conditional on // the subcommand. Therefore we must manually identify the subcommand first, so that we can @@ -202,6 +209,7 @@ To learn more about a subcommand, run `./x.py -h`", || (s == "install") || (s == "run") || (s == "r") + || (s == "setup") }); let subcommand = match subcommand { Some(s) => s, @@ -263,12 +271,38 @@ To learn more about a subcommand, run `./x.py -h`", _ => {} }; + // fn usage() + let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! { + let mut extra_help = String::new(); + + // All subcommands except `clean` can have an optional "Available paths" section + if verbose { + let config = Config::parse(&["build".to_string()]); + let build = Build::new(config); + + let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); + extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); + } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") { + extra_help.push_str( + format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand) + .as_str(), + ); + } + + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; + // Done specifying what options are possible, so do the getopts parsing let matches = opts.parse(&args[..]).unwrap_or_else(|e| { // Invalid argument/option format println!("\n{}\n", e); - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, false, &subcommand_help); }); + // Extra sanity check to make sure we didn't hit this crazy corner case: // // ./x.py --frobulate clean build @@ -385,7 +419,7 @@ Arguments: ./x.py test src/test/ui --bless ./x.py test src/test/ui --compare-mode nll - Note that `test src/test/* --stage N` does NOT depend on `build src/rustc --stage N`; + Note that `test src/test/* --stage N` does NOT depend on `build compiler/rustc --stage N`; just like `build library/std --stage N` it tests the compiler produced by the previous stage. @@ -430,30 +464,28 @@ Arguments: At least a tool needs to be called.", ); } + "setup" => { + subcommand_help.push_str( + "\n +Arguments: + This subcommand accepts a 'profile' to use for builds. For example: + + ./x.py setup library + + The profile is optional and you will be prompted interactively if it is not given.", + ); + } _ => {} }; // Get any optional paths which occur after the subcommand - let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); + let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); - - // All subcommands except `clean` can have an optional "Available paths" section - if matches.opt_present("verbose") { - let config = Config::parse(&["build".to_string()]); - let build = Build::new(config); - - let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); - extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); - } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") { - extra_help.push_str( - format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand) - .as_str(), - ); - } + let verbose = matches.opt_present("verbose"); // User passed in -h/--help? if matches.opt_present("help") { - usage(0, &opts, &subcommand_help, &extra_help); + usage(0, &opts, verbose, &subcommand_help); } let cmd = match subcommand.as_str() { @@ -483,7 +515,7 @@ Arguments: "clean" => { if !paths.is_empty() { println!("\nclean does not take a path argument\n"); - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, verbose, &subcommand_help); } Subcommand::Clean { all: matches.opt_present("all") } @@ -494,12 +526,26 @@ Arguments: "run" | "r" => { if paths.is_empty() { println!("\nrun requires at least a path!\n"); - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, verbose, &subcommand_help); } Subcommand::Run { paths } } + "setup" => { + let path = if paths.len() > 1 { + println!("\nat most one profile can be passed to setup\n"); + usage(1, &opts, verbose, &subcommand_help) + } else if let Some(path) = paths.pop() { + t!(path.into_os_string().into_string().map_err(|path| format!( + "{} is not a valid UTF8 string", + path.to_string_lossy() + ))) + } else { + t!(crate::setup::interactive_path()) + }; + Subcommand::Setup { path } + } _ => { - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, verbose, &subcommand_help); } }; @@ -508,7 +554,9 @@ Arguments: println!("--stage not supported for x.py check, always treated as stage 0"); process::exit(1); } - if matches.opt_str("keep-stage").is_some() { + if matches.opt_str("keep-stage").is_some() + || matches.opt_str("keep-stage-std").is_some() + { println!("--keep-stage not supported for x.py check, only one stage available"); process::exit(1); } @@ -526,14 +574,31 @@ Arguments: .into_iter() .map(|j| j.parse().expect("`keep-stage` should be a number")) .collect(), - host: split(&matches.opt_strs("host")) - .into_iter() - .map(|x| TargetSelection::from_user(&x)) - .collect::>(), - target: split(&matches.opt_strs("target")) + keep_stage_std: matches + .opt_strs("keep-stage-std") .into_iter() - .map(|x| TargetSelection::from_user(&x)) - .collect::>(), + .map(|j| j.parse().expect("`keep-stage-std` should be a number")) + .collect(), + host: if matches.opt_present("host") { + Some( + split(&matches.opt_strs("host")) + .into_iter() + .map(|x| TargetSelection::from_user(&x)) + .collect::>(), + ) + } else { + None + }, + target: if matches.opt_present("target") { + Some( + split(&matches.opt_strs("target")) + .into_iter() + .map(|x| TargetSelection::from_user(&x)) + .collect::>(), + ) + } else { + None + }, config: cfg_file, jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")), cmd, @@ -542,6 +607,7 @@ Arguments: .into_iter() .map(|p| p.into()) .collect::>(), + include_default_paths: matches.opt_present("include-default-paths"), deny_warnings: parse_deny_warnings(&matches), llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map( |s| s.parse::().expect("`llvm-skip-rebuild` should be either true or false"), @@ -620,7 +686,7 @@ impl Subcommand { } fn split(s: &[String]) -> Vec { - s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect() + s.iter().flat_map(|s| s.split(',')).filter(|s| !s.is_empty()).map(|s| s.to_string()).collect() } fn parse_deny_warnings(matches: &getopts::Matches) -> Option { diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 6f93082e67..0ae9f9712d 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -105,15 +105,13 @@ pub fn format(build: &Build, check: bool) { eprintln!("./x.py fmt is not supported on this channel"); std::process::exit(1); }); - let src = build.src.clone(); - let walker = WalkBuilder::new(&build.src).types(matcher).overrides(ignore_fmt).build_parallel(); + let src = &build.src; + let walker = WalkBuilder::new(src).types(matcher).overrides(ignore_fmt).build_parallel(); walker.run(|| { - let src = src.clone(); - let rustfmt_path = rustfmt_path.clone(); Box::new(move |entry| { let entry = t!(entry); if entry.file_type().map_or(false, |t| t.is_file()) { - rustfmt(&src, &rustfmt_path, &entry.path(), check); + rustfmt(src, &rustfmt_path, &entry.path(), check); } ignore::WalkState::Continue }) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index d9ee3bc90f..074f5cd73f 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -192,7 +192,7 @@ install!((self, builder, _config), builder.ensure(dist::Docs { host: self.target }); install_docs(builder, self.compiler.stage, self.target); }; - Std, "library/std", true, only_hosts: true, { + Std, "library/std", true, only_hosts: false, { for target in &builder.targets { builder.ensure(dist::Std { compiler: self.compiler, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a42ee11bd6..852316a8d8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -103,8 +103,6 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -#![feature(drain_filter)] - use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::env; @@ -143,6 +141,7 @@ mod metadata; mod native; mod run; mod sanity; +mod setup; mod test; mod tool; mod toolstate; @@ -167,7 +166,7 @@ mod job { use crate::cache::{Interned, INTERNER}; pub use crate::config::Config; -use crate::flags::Subcommand; +pub use crate::flags::Subcommand; const LLVM_TOOLS: &[&str] = &[ "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility @@ -220,6 +219,9 @@ pub struct Build { /// User-specified configuration from `config.toml`. config: Config, + // Version information + version: String, + // Properties derived from the above configuration src: PathBuf, out: PathBuf, @@ -300,9 +302,6 @@ pub enum Mode { /// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory. Rustc, - /// Build codegen libraries, placing output in the "stageN-codegen" directory - Codegen, - /// Build a tool, placing output in the "stage0-bootstrap-tools" /// directory. This is for miscellaneous sets of tools that are built /// using the bootstrap stage0 compiler in its entirety (target libraries @@ -385,6 +384,10 @@ impl Build { .unwrap() .to_path_buf(); + let version = std::fs::read_to_string(src.join("src").join("version")) + .expect("failed to read src/version"); + let version = version.trim(); + let mut build = Build { initial_rustc: config.initial_rustc.clone(), initial_cargo: config.initial_cargo.clone(), @@ -400,6 +403,7 @@ impl Build { targets: config.targets.clone(), config, + version: version.to_string(), src, out, @@ -438,8 +442,7 @@ impl Build { .next() .unwrap() .trim(); - let my_version = channel::CFG_RELEASE_NUM; - if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { + if local_release.split('.').take(2).eq(version.split('.').take(2)) { build.verbose(&format!("auto-detected local-rebuild {}", local_release)); build.local_rebuild = true; } @@ -468,6 +471,10 @@ impl Build { return clean::clean(self, all); } + if let Subcommand::Setup { path: include_name } = &self.config.cmd { + return setup::setup(&self.config.src, include_name); + } + { let builder = builder::Builder::new(&self); if let Some(path) = builder.paths.get(0) { @@ -546,6 +553,16 @@ impl Build { if self.config.llvm_enabled() { features.push_str(" llvm"); } + + // If debug logging is on, then we want the default for tracing: + // https://github.com/tokio-rs/tracing/blob/3dd5c03d907afdf2c39444a29931833335171554/tracing/src/level_filters.rs#L26 + // which is everything (including debug/trace/etc.) + // if its unset, if debug_assertions is on, then debug_logging will also be on + // as well as tracing *ignoring* this feature when debug_assertions is on + if !self.config.rust_debug_logging { + features.push_str(" max_level_info"); + } + features } @@ -572,7 +589,6 @@ impl Build { let suffix = match mode { Mode::Std => "-std", Mode::Rustc => "-rustc", - Mode::Codegen => "-codegen", Mode::ToolBootstrap => "-bootstrap-tools", Mode::ToolStd | Mode::ToolRustc => "-tools", }; @@ -617,6 +633,10 @@ 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(), None => true, @@ -650,7 +670,7 @@ impl Build { } } else { let base = self.llvm_out(self.config.build).join("build"); - let base = if !self.config.ninja && self.config.build.contains("msvc") { + let base = if !self.ninja() && self.config.build.contains("msvc") { if self.config.llvm_optimize { if self.config.llvm_release_debuginfo { base.join("RelWithDebInfo") @@ -777,7 +797,7 @@ impl Build { match which { GitRepo::Rustc => { - let sha = self.rust_sha().unwrap_or(channel::CFG_RELEASE_NUM); + let sha = self.rust_sha().unwrap_or(&self.version); Some(format!("/rustc/{}", sha)) } GitRepo::Llvm => Some(String::from("/rustc/llvm")), @@ -850,22 +870,32 @@ impl Build { } /// Returns the path to the linker for the given target if it needs to be overridden. - fn linker(&self, target: TargetSelection, can_use_lld: bool) -> Option<&Path> { + fn linker(&self, target: TargetSelection) -> Option<&Path> { if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref()) { Some(linker) + } else if target.contains("vxworks") { + // need to use CXX compiler as linker to resolve the exception functions + // that are only existed in CXX libraries + Some(self.cxx[&target].path()) } else if target != self.config.build && util::use_host_linker(target) && !target.contains("msvc") { Some(self.cc(target)) - } else if can_use_lld && self.config.use_lld && self.build == target { + } else if self.config.use_lld && !self.is_fuse_ld_lld(target) && self.build == target { Some(&self.initial_lld) } else { None } } + // LLD is used through `-fuse-ld=lld` rather than directly. + // Only MSVC targets use LLD directly at the moment. + fn is_fuse_ld_lld(&self, target: TargetSelection) -> bool { + self.config.use_lld && !target.contains("msvc") + } + /// Returns if this target should statically link the C runtime, if specified fn crt_static(&self, target: TargetSelection) -> Option { if target.contains("pc-windows-msvc") { @@ -998,7 +1028,7 @@ impl Build { /// Returns the value of `release` above for Rust itself. fn rust_release(&self) -> String { - self.release(channel::CFG_RELEASE_NUM) + self.release(&self.version) } /// Returns the "package version" for a component given the `num` release @@ -1018,41 +1048,7 @@ impl Build { /// Returns the value of `package_vers` above for Rust itself. fn rust_package_vers(&self) -> String { - self.package_vers(channel::CFG_RELEASE_NUM) - } - - /// Returns the value of `package_vers` above for Cargo - fn cargo_package_vers(&self) -> String { - self.package_vers(&self.release_num("cargo")) - } - - /// Returns the value of `package_vers` above for rls - fn rls_package_vers(&self) -> String { - self.package_vers(&self.release_num("rls")) - } - - /// Returns the value of `package_vers` above for rust-analyzer - fn rust_analyzer_package_vers(&self) -> String { - self.package_vers(&self.release_num("rust-analyzer/crates/rust-analyzer")) - } - - /// Returns the value of `package_vers` above for clippy - fn clippy_package_vers(&self) -> String { - self.package_vers(&self.release_num("clippy")) - } - - /// Returns the value of `package_vers` above for miri - fn miri_package_vers(&self) -> String { - self.package_vers(&self.release_num("miri")) - } - - /// Returns the value of `package_vers` above for rustfmt - fn rustfmt_package_vers(&self) -> String { - self.package_vers(&self.release_num("rustfmt")) - } - - fn llvm_tools_package_vers(&self) -> String { - self.package_vers(channel::CFG_RELEASE_NUM) + self.package_vers(&self.version) } fn llvm_tools_vers(&self) -> String { @@ -1069,7 +1065,7 @@ impl Build { /// Note that this is a descriptive string which includes the commit date, /// sha, version, etc. fn rust_version(&self) -> String { - self.rust_info.version(self, channel::CFG_RELEASE_NUM) + self.rust_info.version(self, &self.version) } /// Returns the full commit hash. @@ -1324,6 +1320,43 @@ impl Build { } fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f)); } + + /// Returns if config.ninja is enabled, and checks for ninja existence, + /// exiting with a nicer error message if not. + fn ninja(&self) -> bool { + let mut cmd_finder = crate::sanity::Finder::new(); + + if self.config.ninja_in_file { + // Some Linux distros rename `ninja` to `ninja-build`. + // CMake can work with either binary name. + if cmd_finder.maybe_have("ninja-build").is_none() + && cmd_finder.maybe_have("ninja").is_none() + { + eprintln!( + " +Couldn't find required command: ninja +You should install ninja, or set ninja=false in config.toml +" + ); + std::process::exit(1); + } + } + + // If ninja isn't enabled but we're building for MSVC then we try + // doubly hard to enable it. It was realized in #43767 that the msbuild + // CMake generator for MSVC doesn't respect configuration options like + // disabling LLVM assertions, which can often be quite important! + // + // In these cases we automatically enable Ninja if we find it in the + // environment. + if !self.config.ninja_in_file && self.config.build.contains("msvc") { + if cmd_finder.maybe_have("ninja").is_some() { + return true; + } + } + + self.config.ninja_in_file + } } #[cfg(unix)] diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 97d9dbdd63..6bba00ee85 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -19,7 +19,6 @@ use std::process::Command; use build_helper::{output, t}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::channel; use crate::config::TargetSelection; use crate::util::{self, exe}; use crate::GitRepo; @@ -56,7 +55,7 @@ pub fn prebuilt_llvm_config( let out_dir = builder.llvm_out(target); let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); - if !builder.config.build.contains("msvc") || builder.config.ninja { + if !builder.config.build.contains("msvc") || builder.ninja() { llvm_config_ret_dir.push("build"); } llvm_config_ret_dir.push("bin"); @@ -129,6 +128,12 @@ impl Step for Llvm { Err(m) => m, }; + if builder.config.llvm_link_shared + && (target.contains("windows") || target.contains("apple-darwin")) + { + panic!("shared linking to LLVM is not currently supported on {}", target.triple); + } + builder.info(&format!("Building LLVM for {}", target)); t!(stamp.remove()); let _time = util::timeit(&builder); @@ -169,7 +174,6 @@ impl Step for Llvm { .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_BENCHMARKS", "OFF") - .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") .define("LLVM_ENABLE_BINDINGS", "OFF") @@ -178,11 +182,9 @@ impl Step for Llvm { .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native); - if !target.contains("netbsd") && target != "aarch64-apple-darwin" { + if target != "aarch64-apple-darwin" { cfg.define("LLVM_ENABLE_ZLIB", "ON"); } else { - // FIXME: Enable zlib on NetBSD too - // https://github.com/rust-lang/rust/pull/72696#issuecomment-641517185 cfg.define("LLVM_ENABLE_ZLIB", "OFF"); } @@ -208,7 +210,10 @@ impl Step for Llvm { // which saves both memory during parallel links and overall disk space // for the tools. We don't do this on every platform as it doesn't work // equally well everywhere. - if builder.llvm_link_tools_dynamically(target) { + // + // If we're not linking rustc to a dynamic LLVM, though, then don't link + // tools to it. + if builder.llvm_link_tools_dynamically(target) && builder.config.llvm_link_shared { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } @@ -295,7 +300,7 @@ impl Step for Llvm { // release number on the dev channel. cfg.define("LLVM_VERSION_SUFFIX", "-rust-dev"); } else { - let suffix = format!("-rust-{}-{}", channel::CFG_RELEASE_NUM, builder.config.channel); + let suffix = format!("-rust-{}-{}", builder.version, builder.config.channel); cfg.define("LLVM_VERSION_SUFFIX", suffix); } @@ -307,10 +312,6 @@ impl Step for Llvm { cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES"); } - if let Some(ref python) = builder.config.python { - cfg.define("PYTHON_EXECUTABLE", python); - } - configure_cmake(builder, target, &mut cfg, true); // FIXME: we don't actually need to build all LLVM tools and all LLVM @@ -365,7 +366,7 @@ fn configure_cmake( // own build directories. cfg.env("DESTDIR", ""); - if builder.config.ninja { + if builder.ninja() { cfg.generator("Ninja"); } cfg.target(&target.triple).host(&builder.config.build.triple); @@ -397,7 +398,7 @@ fn configure_cmake( // MSVC with CMake uses msbuild by default which doesn't respect these // vars that we'd otherwise configure. In that case we just skip this // entirely. - if target.contains("msvc") && !builder.config.ninja { + if target.contains("msvc") && !builder.ninja() { return; } @@ -407,7 +408,7 @@ fn configure_cmake( }; // Handle msvc + ninja + ccache specially (this is what the bots use) - if target.contains("msvc") && builder.config.ninja && builder.config.ccache.is_some() { + if target.contains("msvc") && builder.ninja() && builder.config.ccache.is_some() { let mut wrap_cc = env::current_exe().expect("failed to get cwd"); wrap_cc.set_file_name("sccache-plus-cl.exe"); @@ -629,7 +630,14 @@ impl Step for TestHelpers { if builder.config.dry_run { return; } - let target = self.target; + // The x86_64-fortanix-unknown-sgx target doesn't have a working C + // toolchain. However, some x86_64 ELF objects can be linked + // without issues. Use this hack to compile the test helpers. + let target = if self.target == "x86_64-fortanix-unknown-sgx" { + TargetSelection::from_user("x86_64-unknown-linux-gnu") + } else { + self.target + }; let dst = builder.test_helpers_out(target); let src = builder.src.join("src/test/auxiliary/rust_test_helpers.c"); if up_to_date(&src, &dst.join("librust_test_helpers.a")) { @@ -653,7 +661,6 @@ impl Step for TestHelpers { } cfg.compiler(builder.cc(target)); } - cfg.cargo_metadata(false) .out_dir(&dst) .target(&target.triple) diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 9005347142..7c64e5a0aa 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -1,5 +1,7 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::dist::distdir; use crate::tool::Tool; +use build_helper::output; use std::process::Command; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -10,7 +12,7 @@ impl Step for ExpandYamlAnchors { /// Runs the `expand-yaml_anchors` tool. /// - /// This tool in `src/tools` read the CI configuration files written in YAML and expands the + /// This tool in `src/tools` reads the CI configuration files written in YAML and expands the /// anchors in them, since GitHub Actions doesn't support them. fn run(self, builder: &Builder<'_>) { builder.info("Expanding YAML anchors in the GitHub Actions configuration"); @@ -41,3 +43,42 @@ fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool { } true } + +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +pub struct BuildManifest; + +impl Step for BuildManifest { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/build-manifest") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(BuildManifest); + } + + fn run(self, builder: &Builder<'_>) { + // This gets called by `promote-release` + // (https://github.com/rust-lang/promote-release). + let mut cmd = builder.tool_cmd(Tool::BuildManifest); + let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n") + }); + let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n") + }); + + let today = output(Command::new("date").arg("+%Y-%m-%d")); + + cmd.arg(sign); + cmd.arg(distdir(builder)); + cmd.arg(today.trim()); + cmd.arg(addr); + cmd.arg(&builder.config.channel); + + builder.create_dir(&distdir(builder)); + builder.run(&mut cmd); + } +} diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index f89bef50de..6826d177a4 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -20,18 +20,18 @@ use build_helper::{output, t}; use crate::config::Target; use crate::Build; -struct Finder { +pub struct Finder { cache: HashMap>, path: OsString, } impl Finder { - fn new() -> Self { + pub fn new() -> Self { Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() } } - fn maybe_have>(&mut self, cmd: S) -> Option { - let cmd: OsString = cmd.as_ref().into(); + pub fn maybe_have>(&mut self, cmd: S) -> Option { + let cmd: OsString = cmd.into(); let path = &self.path; self.cache .entry(cmd.clone()) @@ -54,7 +54,7 @@ impl Finder { .clone() } - fn must_have>(&mut self, cmd: S) -> PathBuf { + pub fn must_have>(&mut self, cmd: S) -> PathBuf { self.maybe_have(&cmd).unwrap_or_else(|| { panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref()); }) @@ -95,30 +95,6 @@ pub fn check(build: &mut Build) { cmd_finder.must_have("cmake"); } - // Ninja is currently only used for LLVM itself. - if building_llvm { - if build.config.ninja { - // Some Linux distros rename `ninja` to `ninja-build`. - // CMake can work with either binary name. - if cmd_finder.maybe_have("ninja-build").is_none() { - cmd_finder.must_have("ninja"); - } - } - - // If ninja isn't enabled but we're building for MSVC then we try - // doubly hard to enable it. It was realized in #43767 that the msbuild - // CMake generator for MSVC doesn't respect configuration options like - // disabling LLVM assertions, which can often be quite important! - // - // In these cases we automatically enable Ninja if we find it in the - // environment. - if !build.config.ninja && build.config.build.contains("msvc") { - if cmd_finder.maybe_have("ninja").is_some() { - build.config.ninja = true; - } - } - } - build.config.python = build .config .python diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs new file mode 100644 index 0000000000..9d3a889aa0 --- /dev/null +++ b/src/bootstrap/setup.rs @@ -0,0 +1,88 @@ +use crate::t; +use std::path::{Path, PathBuf}; +use std::{ + env, fs, + io::{self, Write}, +}; + +pub fn setup(src_path: &Path, include_name: &str) { + let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); + + if cfg_file.as_ref().map_or(false, |f| f.exists()) { + let file = cfg_file.unwrap(); + println!( + "error: you asked `x.py` to setup a new config file, but one already exists at `{}`", + file.display() + ); + println!( + "help: try adding `profile = \"{}\"` at the top of {}", + include_name, + file.display() + ); + println!( + "note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}", + src_path.display(), + include_name + ); + std::process::exit(1); + } + + let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml")); + let settings = format!( + "# Includes one of the default files in src/bootstrap/defaults\n\ + profile = \"{}\"\n", + include_name + ); + t!(fs::write(path, settings)); + + let include_path = + format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name); + println!("`x.py` will now use the configuration at {}", include_path); + + let suggestions = match include_name { + "codegen" | "compiler" => &["check", "build", "test"][..], + "library" => &["check", "build", "test library/std", "doc"], + "user" => &["dist", "build"], + _ => return, + }; + + println!("To get started, try one of the following commands:"); + for cmd in suggestions { + println!("- `x.py {}`", cmd); + } + + if include_name != "user" { + println!( + "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" + ); + } +} + +// Used to get the path for `Subcommand::Setup` +pub fn interactive_path() -> io::Result { + let mut input = String::new(); + println!( + "Welcome to the Rust project! What do you want to do with x.py? +a) Contribute to the standard library +b) Contribute to the compiler +c) Contribute to the compiler, and also modify LLVM or codegen +d) Install Rust from source" + ); + let template = loop { + print!("Please choose one (a/b/c/d): "); + io::stdout().flush()?; + io::stdin().read_line(&mut input)?; + break match input.trim().to_lowercase().as_str() { + "a" | "lib" | "library" => "library", + "b" | "compiler" => "compiler", + "c" | "llvm" => "llvm", + "d" | "user" | "maintainer" => "maintainer", + _ => { + println!("error: unrecognized option '{}'", input.trim()); + println!("note: press Ctrl+C to exit"); + continue; + } + }; + }; + Ok(template.to_owned()) +} diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index afa72b5d58..00522ee6b6 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -270,7 +270,7 @@ impl Step for Rls { &[], ); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); cargo.arg("--").args(builder.config.cmd.test_args()); if try_run(builder, &mut cargo.into()) { @@ -328,7 +328,7 @@ impl Step for Rustfmt { t!(fs::create_dir_all(&dir)); cargo.env("RUSTFMT_TEST_DIR", dir); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); if try_run(builder, &mut cargo.into()) { builder.save_toolstate("rustfmt", ToolState::TestPass); @@ -449,7 +449,7 @@ impl Step for Miri { cargo.arg("--").args(builder.config.cmd.test_args()); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); if !try_run(builder, &mut cargo.into()) { return; @@ -554,7 +554,7 @@ impl Step for Clippy { cargo.arg("--").args(builder.config.cmd.test_args()); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); builder.run(&mut cargo.into()); } @@ -584,7 +584,7 @@ impl Step for RustdocTheme { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); + let compiler = run.builder.compiler(run.builder.top_stage, run.target); run.builder.ensure(RustdocTheme { compiler }); } @@ -600,8 +600,11 @@ impl Step for RustdocTheme { .env("CFG_RELEASE_CHANNEL", &builder.config.channel) .env("RUSTDOC_REAL", builder.rustdoc(self.compiler)) .env("RUSTC_BOOTSTRAP", "1"); - if let Some(linker) = builder.linker(self.compiler.host, true) { - cmd.env("RUSTC_TARGET_LINKER", linker); + if let Some(linker) = builder.linker(self.compiler.host) { + cmd.env("RUSTDOC_LINKER", linker); + } + if builder.is_fuse_ld_lld(self.compiler.host) { + cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } try_run(builder, &mut cmd); } @@ -633,7 +636,7 @@ impl Step for RustdocJSStd { .arg("--crate-name") .arg("std") .arg("--resource-suffix") - .arg(crate::channel::CFG_RELEASE_NUM) + .arg(&builder.version) .arg("--doc-folder") .arg(builder.doc_out(self.target)) .arg("--test-folder") @@ -648,7 +651,6 @@ impl Step for RustdocJSStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocJSNotStd { - pub host: TargetSelection, pub target: TargetSelection, pub compiler: Compiler, } @@ -663,8 +665,8 @@ impl Step for RustdocJSNotStd { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocJSNotStd { host: run.host, target: run.target, compiler }); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + run.builder.ensure(RustdocJSNotStd { target: run.target, compiler }); } fn run(self, builder: &Builder<'_>) { @@ -685,7 +687,6 @@ impl Step for RustdocJSNotStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocUi { - pub host: TargetSelection, pub target: TargetSelection, pub compiler: Compiler, } @@ -700,8 +701,8 @@ impl Step for RustdocUi { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocUi { host: run.host, target: run.target, compiler }); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + run.builder.ensure(RustdocUi { target: run.target, compiler }); } fn run(self, builder: &Builder<'_>) { @@ -734,7 +735,7 @@ impl Step for Tidy { /// for the `dev` or `nightly` channels. fn run(self, builder: &Builder<'_>) { let mut cmd = builder.tool_cmd(Tool::Tidy); - cmd.arg(builder.src.join("src")); + cmd.arg(&builder.src); cmd.arg(&builder.initial_cargo); if builder.is_verbose() { cmd.arg("--verbose"); @@ -870,7 +871,7 @@ macro_rules! test_definitions { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); run.builder.ensure($name { compiler, target: run.target }); } @@ -1061,17 +1062,22 @@ impl Step for Compiletest { flags.push("-Zunstable-options".to_string()); flags.push(builder.config.cmd.rustc_args().join(" ")); - // Don't use LLD here since we want to test that rustc finds and uses a linker by itself. - if let Some(linker) = builder.linker(target, false) { + if let Some(linker) = builder.linker(target) { cmd.arg("--linker").arg(linker); } let mut hostflags = flags.clone(); hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); + if builder.is_fuse_ld_lld(compiler.host) { + hostflags.push("-Clink-args=-fuse-ld=lld".to_string()); + } cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); let mut targetflags = flags; targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); + if builder.is_fuse_ld_lld(target) { + targetflags.push("-Clink-args=-fuse-ld=lld".to_string()); + } cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); cmd.arg("--docck-python").arg(builder.python()); @@ -1275,6 +1281,8 @@ impl Step for Compiletest { cmd.arg("--rustfix-coverage"); } + cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo); + builder.ci_env.force_coloring_in_ci(&mut cmd); builder.info(&format!( @@ -1414,7 +1422,7 @@ macro_rules! test_book { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.target), }); } @@ -1461,7 +1469,7 @@ impl Step for ErrorIndex { // error_index_generator depends on librustdoc. Use the compiler that // is normally used to build rustdoc for other tests (like compiletest // tests in src/test/rustdoc) so that it shares the same artifacts. - let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host); + let compiler = run.builder.compiler_for(run.builder.top_stage, run.target, run.target); run.builder.ensure(ErrorIndex { compiler }); } @@ -1565,7 +1573,7 @@ impl Step for CrateLibrustc { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); for krate in builder.in_tree_crates("rustc-main") { if krate.path.ends_with(&run.path) { @@ -1612,7 +1620,7 @@ impl Step for CrateNotDefault { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); let test_kind = builder.kind.into(); @@ -1660,7 +1668,7 @@ impl Step for Crate { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); let make = |mode: Mode, krate: &CargoCrate| { let test_kind = builder.kind.into(); @@ -1754,11 +1762,6 @@ impl Step for Crate { cargo.arg("--quiet"); } - if builder.config.cmd.bless() { - // Bless `expect!` tests. - cargo.env("UPDATE_EXPECT", "1"); - } - if target.contains("emscripten") { cargo.env( format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), @@ -1805,7 +1808,7 @@ impl Step for CrateRustdoc { let test_kind = builder.kind.into(); - builder.ensure(CrateRustdoc { host: run.host, test_kind }); + builder.ensure(CrateRustdoc { host: run.target, test_kind }); } fn run(self, builder: &Builder<'_>) { @@ -2021,6 +2024,8 @@ impl Step for Bootstrap { .current_dir(builder.src.join("src/bootstrap")) .env("RUSTFLAGS", "-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) + .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out) + .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo) .env("RUSTC_BOOTSTRAP", "1") .env("RUSTC", &builder.initial_rustc); if let Some(flags) = option_env!("RUSTFLAGS") { @@ -2051,7 +2056,6 @@ impl Step for Bootstrap { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct TierCheck { pub compiler: Compiler, - target: TargetSelection, } impl Step for TierCheck { @@ -2064,18 +2068,19 @@ impl Step for TierCheck { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host); - run.builder.ensure(TierCheck { compiler, target: run.host }); + let compiler = + run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target); + run.builder.ensure(TierCheck { compiler }); } /// Tests the Platform Support page in the rustc book. fn run(self, builder: &Builder<'_>) { - builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); + builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host }); let mut cargo = tool::prepare_tool_cargo( builder, self.compiler, - Mode::ToolRustc, - self.target, + Mode::ToolStd, + self.compiler.host, "run", "src/tools/tier-check", SourceType::InTree, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index fe3f1e7802..290e374485 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -7,7 +7,6 @@ use std::process::{exit, Command}; use build_helper::t; use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; -use crate::channel; use crate::channel::GitInfo; use crate::compile; use crate::config::TargetSelection; @@ -162,13 +161,15 @@ impl Step for ToolBuild { "the following dependencies are duplicated although they \ have the same features enabled:" ); - for (id, cur, prev) in duplicates.drain_filter(|(_, cur, prev)| cur.2 == prev.2) { + let (same, different): (Vec<_>, Vec<_>) = + duplicates.into_iter().partition(|(_, cur, prev)| cur.2 == prev.2); + for (id, cur, prev) in same { println!(" {}", id); // same features println!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1); } println!("the following dependencies have different features:"); - for (id, cur, prev) in duplicates { + for (id, cur, prev) in different { println!(" {}", id); let cur_features: HashSet<_> = cur.2.into_iter().collect(); let prev_features: HashSet<_> = prev.2.into_iter().collect(); @@ -253,7 +254,7 @@ pub fn prepare_tool_cargo( cargo.env("CFG_RELEASE", builder.rust_release()); cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel); cargo.env("CFG_VERSION", builder.rust_version()); - cargo.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM); + cargo.env("CFG_RELEASE_NUM", &builder.version); let info = GitInfo::new(builder.config.ignore_git, &dir); if let Some(sha) = info.sha() { @@ -365,6 +366,7 @@ bootstrap_tool!( RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true; RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes"; ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; + LintDocs, "src/tools/lint-docs", "lint-docs"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] @@ -467,8 +469,13 @@ impl Step for Rustdoc { } fn make_run(run: RunConfig<'_>) { - run.builder - .ensure(Rustdoc { compiler: run.builder.compiler(run.builder.top_stage, run.host) }); + run.builder.ensure(Rustdoc { + // Note: this is somewhat unique in that we actually want a *target* + // compiler here, because rustdoc *is* a compiler. We won't be using + // this as the compiler to build with, but rather this is "what + // compiler are we producing"? + compiler: run.builder.compiler(run.builder.top_stage, run.target), + }); } fn run(self, builder: &Builder<'_>) -> PathBuf { @@ -697,6 +704,10 @@ impl<'a> Builder<'a> { } add_dylib_path(lib_paths, &mut cmd); + + // Provide a RUSTC for this command to use. + cmd.env("RUSTC", &self.initial_rustc); + cmd } } diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml index 04c7820b45..2420f1b7f1 100644 --- a/src/build_helper/Cargo.toml +++ b/src/build_helper/Cargo.toml @@ -5,5 +5,4 @@ authors = ["The Rust Project Developers"] edition = "2018" [lib] -name = "build_helper" path = "lib.rs" diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index 2185b0d30d..37c2e9bc35 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -18,45 +18,9 @@ trigger: - auto jobs: -- job: macOS +- job: Dummy timeoutInMinutes: 600 pool: - vmImage: macos-10.15 + vmImage: ubuntu-16.04 steps: - - template: steps/run.yml - variables: - # We're still uploading macOS builds from Azure Pipelines. - - group: prod-credentials - strategy: - matrix: - # OSX builders running tests, these run the full test suite. - # NO_DEBUG_ASSERTIONS=1 to make them go faster, but also do have some - # runners that run `//ignore-debug` tests. - # - # Note that the compiler is compiled to target 10.8 here because the Xcode - # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. - x86_64-apple: - SCRIPT: ./x.py --stage 2 test - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - - dist-x86_64-apple: - SCRIPT: ./x.py dist - INITIAL_RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - - dist-x86_64-apple-alt: - SCRIPT: ./x.py dist - INITIAL_RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 + - bash: echo "We're running this job since bors is still gating on Azure" diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml deleted file mode 100644 index 34fc4d76fa..0000000000 --- a/src/ci/azure-pipelines/steps/run.yml +++ /dev/null @@ -1,142 +0,0 @@ -##################################### -## READ BEFORE CHANGING THIS ## -##################################### - -# We're in the process of evaluating GitHub Actions as a possible replacement -# for Azure Pipelines, and at the moment the configuration is duplicated -# between the two CI providers. Be sure to also change the configuration in -# src/ci/github-actions when changing this file. - -##################################### - -# FIXME(linux): need to configure core dumps, enable them, and then dump -# backtraces on failure from all core dumps: -# -# - bash: sudo apt install gdb -# - bash: sudo sh -c 'echo "/checkout/obj/cores/core.%p.%E" > /proc/sys/kernel/core_pattern' -# -# Check travis config for `gdb --batch` command to print all crash logs - -steps: - -# Configure our CI_JOB_NAME variable which log analyzers can use for the main -# step to see what's going on. -- bash: | - builder=$(echo $AGENT_JOBNAME | cut -d ' ' -f 2) - echo "##vso[task.setvariable variable=CI_JOB_NAME]$builder" - displayName: Configure Job Name - -# Disable automatic line ending conversion, which is enabled by default on -# Azure's Windows image. Having the conversion enabled caused regressions both -# in our test suite (it broke miri tests) and in the ecosystem, since we -# started shipping install scripts with CRLF endings instead of the old LF. -# -# Note that we do this a couple times during the build as the PATH and current -# user/directory change, e.g. when mingw is enabled. -- bash: git config --global core.autocrlf false - displayName: "Disable git automatic line ending conversion" - -- checkout: self - fetchDepth: 2 - -- bash: src/ci/scripts/setup-environment.sh - displayName: Setup environment - -- bash: src/ci/scripts/clean-disk.sh - displayName: Clean disk - -- bash: src/ci/scripts/should-skip-this.sh - displayName: Decide whether to run this job - -- bash: src/ci/scripts/collect-cpu-stats.sh - displayName: Collect CPU-usage statistics in the background - -- bash: src/ci/scripts/dump-environment.sh - displayName: Show the current environment - -- bash: src/ci/scripts/install-sccache.sh - displayName: Install sccache - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-clang.sh - displayName: Install clang - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-wix.sh - displayName: Install wix - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/symlink-build-dir.sh - displayName: Ensure the build happens on a partition with enough space - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/disable-git-crlf-conversion.sh - displayName: "Disable git automatic line ending conversion (on C:/)" - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-msys2.sh - displayName: Install msys2 - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-mingw.sh - displayName: Install MinGW - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-ninja.sh - displayName: Install ninja - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/enable-docker-ipv6.sh - displayName: Enable IPv6 on Docker - condition: and(succeeded(), not(variables.SKIP_JOB)) - -# Disable automatic line ending conversion (again). On Windows, when we're -# installing dependencies, something switches the git configuration directory or -# re-enables autocrlf. We've not tracked down the exact cause -- and there may -# be multiple -- but this should ensure submodules are checked out with the -# appropriate line endings. -- bash: src/ci/scripts/disable-git-crlf-conversion.sh - displayName: Disable git automatic line ending conversion - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/checkout-submodules.sh - displayName: Checkout submodules - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/verify-line-endings.sh - displayName: Verify line endings - condition: and(succeeded(), not(variables.SKIP_JOB)) - -# Ensure the `aws` CLI is installed so we can deploy later on, cache docker -# images, etc. -- bash: src/ci/scripts/install-awscli.sh - condition: and(succeeded(), not(variables.SKIP_JOB)) - displayName: Install awscli - -- bash: src/ci/scripts/run-build-from-ci.sh - timeoutInMinutes: 600 - env: - AWS_ACCESS_KEY_ID: $(SCCACHE_AWS_ACCESS_KEY_ID) - AWS_SECRET_ACCESS_KEY: $(SCCACHE_AWS_SECRET_ACCESS_KEY) - TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) - condition: and(succeeded(), not(variables.SKIP_JOB)) - displayName: Run build - -- bash: src/ci/scripts/upload-artifacts.sh - env: - AWS_ACCESS_KEY_ID: $(UPLOAD_AWS_ACCESS_KEY_ID) - AWS_SECRET_ACCESS_KEY: $(UPLOAD_AWS_SECRET_ACCESS_KEY) - displayName: Upload artifacts - # Adding a condition on DEPLOY=1 or DEPLOY_ALT=1 is not needed as all deploy - # builders *should* have the AWS credentials available. Still, explicitly - # adding the condition is helpful as this way CI will not silently skip - # deploying artifacts from a dist builder if the variables are misconfigured, - # erroring about invalid credentials instead. - condition: | - and( - succeeded(), not(variables.SKIP_JOB), - or( - variables.UPLOAD_AWS_SECRET_ACCESS_KEY, - eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1') - ) - ) diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile index b6cf60a5e1..e54d0eafb4 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:20.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile index add2647fa1..f675252fb1 100644 --- a/src/ci/docker/host-x86_64/arm-android/Dockerfile +++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile @@ -31,7 +31,7 @@ ENV TARGETS=arm-linux-androideabi ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 -ENV SCRIPT python3 ../x.py --stage 2 test --target $TARGETS +ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile index 1f3092c551..9370f5debb 100644 --- a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile @@ -14,6 +14,7 @@ RUN apt-get update -y && apt-get install -y --no-install-recommends \ libc6-dev \ libc6-dev-armhf-cross \ make \ + ninja-build \ python3 \ qemu-system-arm \ xz-utils @@ -57,7 +58,7 @@ RUN curl https://www.busybox.net/downloads/busybox-1.21.1.tar.bz2 | tar xjf - && # Download the ubuntu rootfs, which we'll use as a chroot for all our tests. WORKDIR /tmp RUN mkdir rootfs/ubuntu -RUN curl http://cdimage.ubuntu.com/ubuntu-base/releases/16.04/release/ubuntu-base-16.04-core-armhf.tar.gz | \ +RUN curl http://cdimage.ubuntu.com/ubuntu-base/releases/16.04/release/ubuntu-base-16.04.6-base-armhf.tar.gz | \ tar xzf - -C rootfs/ubuntu && \ cd rootfs && mkdir proc sys dev etc etc/init.d @@ -78,6 +79,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --qemu-armhf-rootfs=/tmp/rootfs -ENV SCRIPT python3 ../x.py --stage 2 test --target arm-unknown-linux-gnueabihf +ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target arm-unknown-linux-gnueabihf ENV NO_CHANGE_USER=1 diff --git a/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile b/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile index a4d9f53eba..e04f6409f5 100644 --- a/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -33,7 +34,7 @@ ENV EMCC_CFLAGS=-O1 # Emscripten installation is user-specific ENV NO_CHANGE_USER=1 -ENV SCRIPT python3 ../x.py --stage 2 test --target $TARGETS +ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS # This is almost identical to the wasm32-unknown-emscripten target, so # running with assertions again is not useful diff --git a/src/ci/docker/host-x86_64/disabled/dist-powerpcspe-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-powerpcspe-linux/Dockerfile index 19df9d6cf6..34c4874121 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-powerpcspe-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-powerpcspe-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/disabled/dist-sparc64-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-sparc64-linux/Dockerfile index 62d0bfc71b..a8e7583ccb 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-sparc64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-sparc64-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/disabled/dist-x86_64-dragonfly/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-x86_64-dragonfly/Dockerfile index 5e743f0818..5d594a8058 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-x86_64-dragonfly/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-x86_64-dragonfly/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile index 61b3179d55..5ddd3f1803 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libcurl4-openssl-dev \ libssl-dev \ make \ + ninja-build \ nasm \ pkg-config \ python3 \ diff --git a/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile index b32c498c74..e9188b42f5 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile @@ -19,4 +19,4 @@ ENV \ CXX_x86_64_unknown_redox=x86_64-unknown-redox-g++ ENV RUST_CONFIGURE_ARGS --enable-extended -ENV SCRIPT python3 ../x.py dist --target x86_64-unknown-redox +ENV SCRIPT python3 ../x.py dist --host='' --target x86_64-unknown-redox diff --git a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile index e3c35000eb..3c39a63849 100644 --- a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile @@ -20,6 +20,7 @@ RUN apt-get update -y && apt-get install -y --no-install-recommends \ libc6-dev \ libc6-dev-riscv64-cross \ make \ + ninja-build \ patch \ python3 \ qemu-system-misc \ diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index 6d38e19956..258dcea06e 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -32,7 +32,7 @@ ENV RUST_CONFIGURE_ARGS \ --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \ --disable-docs -ENV SCRIPT python3 ../x.py dist --target $TARGETS +ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile index ba93f6ad82..88b13eab2d 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile @@ -6,6 +6,14 @@ RUN sh /scripts/cross-apt-packages.sh COPY scripts/crosstool-ng-1.24.sh /scripts/ RUN sh /scripts/crosstool-ng-1.24.sh +WORKDIR /build + +COPY scripts/musl-toolchain.sh /build/ +# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well +RUN CFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ + CXXFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ + bash musl-toolchain.sh aarch64 && rm -rf build + COPY scripts/rustbuild-setup.sh /scripts/ RUN sh /scripts/rustbuild-setup.sh USER rustbuild @@ -25,7 +33,8 @@ ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ -ENV HOSTS=arm-unknown-linux-gnueabi +ENV HOSTS=arm-unknown-linux-gnueabi,aarch64-unknown-linux-musl -ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs --musl-root-aarch64=/usr/local/aarch64-linux-musl \ + --set target.aarch64-unknown-linux-musl.crt-static=false ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config b/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config index 1dcdbd1a90..66709a4004 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config +++ b/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config @@ -14,6 +14,7 @@ CT_CONFIGURE_has_autoconf_2_65_or_newer=y CT_CONFIGURE_has_autoreconf_2_65_or_newer=y CT_CONFIGURE_has_automake_1_15_or_newer=y CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y +CT_CONFIGURE_has_python_3_4_or_newer=y CT_CONFIGURE_has_bison_2_7_or_newer=y CT_CONFIGURE_has_python=y CT_CONFIGURE_has_git=y @@ -132,12 +133,6 @@ CT_ARCH_ARM=y # CT_ARCH_XTENSA is not set CT_ARCH="arm" CT_ARCH_CHOICE_KSYM="ARM" -# CT_ARCH_ALPHA_EV4 is not set -# CT_ARCH_ALPHA_EV45 is not set -# CT_ARCH_ALPHA_EV5 is not set -# CT_ARCH_ALPHA_EV56 is not set -# CT_ARCH_ALPHA_EV6 is not set -# CT_ARCH_ALPHA_EV67 is not set CT_ARCH_CPU="" CT_ARCH_TUNE="" CT_ARCH_ARM_SHOW=y @@ -371,8 +366,6 @@ CT_ALL_BINUTILS_CHOICES="BINUTILS" # C-library # CT_LIBC_GLIBC=y -# CT_LIBC_NEWLIB is not set -# CT_LIBC_NONE is not set # CT_LIBC_UCLIBC is not set CT_LIBC="glibc" CT_LIBC_CHOICE_KSYM="GLIBC" @@ -389,6 +382,7 @@ CT_GLIBC_USE="GLIBC" CT_GLIBC_PKG_NAME="glibc" CT_GLIBC_SRC_RELEASE=y CT_GLIBC_PATCH_ORDER="global" +# CT_GLIBC_V_2_29 is not set # CT_GLIBC_V_2_28 is not set # CT_GLIBC_V_2_27 is not set # CT_GLIBC_V_2_26 is not set @@ -407,7 +401,6 @@ CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" CT_GLIBC_SIGNATURE_FORMAT="packed/.sig" CT_GLIBC_2_29_or_older=y CT_GLIBC_older_than_2_29=y -CT_GLIBC_REQUIRE_older_than_2_29=y CT_GLIBC_2_27_or_older=y CT_GLIBC_older_than_2_27=y CT_GLIBC_2_26_or_older=y @@ -447,12 +440,6 @@ CT_GLIBC_FORCE_UNWIND=y CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y # CT_GLIBC_KERNEL_VERSION_CHOSEN is not set CT_GLIBC_MIN_KERNEL="3.2.101" -# CT_GLIBC_SSP_DEFAULT is not set -# CT_GLIBC_SSP_NO is not set -# CT_GLIBC_SSP_YES is not set -# CT_GLIBC_SSP_ALL is not set -# CT_GLIBC_SSP_STRONG is not set -# CT_NEWLIB_USE_REDHAT is not set CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC" CT_LIBC_SUPPORT_THREADS_ANY=y CT_LIBC_SUPPORT_THREADS_NATIVE=y 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 162d7a1345..c734202eef 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 @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++-multilib \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -46,5 +47,5 @@ ENV CFLAGS_i586_unknown_linux_musl=-Wa,-mrelax-relocations=no ENV TARGETS=i586-unknown-linux-gnu,i686-unknown-linux-musl ENV SCRIPT \ - python3 ../x.py --stage 2 test --target $TARGETS && \ - python3 ../x.py dist --target $TARGETS,i586-unknown-linux-musl + python3 ../x.py --stage 2 test --host='' --target $TARGETS && \ + python3 ../x.py dist --host='' --target $TARGETS,i586-unknown-linux-musl diff --git a/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile index bbbd632c6b..7db6e58c4d 100644 --- a/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile index 9a051caa06..22d7cbb0d1 100644 --- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile @@ -93,6 +93,7 @@ ENV RUST_CONFIGURE_ARGS \ --enable-profiler \ --set target.i686-unknown-linux-gnu.linker=clang \ --build=i686-unknown-linux-gnu \ + --set llvm.ninja=false \ --set rust.jemalloc ENV SCRIPT python2.7 ../x.py dist --build $HOSTS --host $HOSTS --target $HOSTS ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=clang 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 57a7fc25b5..cb5c17c25a 100644 --- a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ 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 63f1028e2b..31146e3ead 100644 --- a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ 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 a51edbc9c7..dadd50a7e6 100644 --- a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ 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 908cef90ce..d2d65565b1 100644 --- a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index fdd777e824..104b608529 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -15,6 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libncurses-dev \ gawk \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -83,10 +84,6 @@ RUN env \ CXX=arm-linux-gnueabihf-g++ CXXFLAGS="-march=armv7-a" \ bash musl.sh armv7hf && \ env \ - CC=aarch64-linux-gnu-gcc \ - CXX=aarch64-linux-gnu-g++ \ - bash musl.sh aarch64 && \ - env \ CC=mips-openwrt-linux-gcc \ CXX=mips-openwrt-linux-g++ \ bash musl.sh mips && \ @@ -129,7 +126,6 @@ ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf ENV TARGETS=$TARGETS,armv5te-unknown-linux-gnueabi ENV TARGETS=$TARGETS,armv5te-unknown-linux-musleabi ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf -ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl ENV TARGETS=$TARGETS,aarch64-unknown-none ENV TARGETS=$TARGETS,aarch64-unknown-none-softfloat ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu @@ -184,7 +180,6 @@ ENV RUST_CONFIGURE_ARGS \ --musl-root-arm=/musl-arm \ --musl-root-armhf=/musl-armhf \ --musl-root-armv7hf=/musl-armv7hf \ - --musl-root-aarch64=/musl-aarch64 \ --musl-root-mips=/musl-mips \ --musl-root-mipsel=/musl-mipsel \ --musl-root-mips64=/musl-mips64 \ @@ -192,8 +187,8 @@ ENV RUST_CONFIGURE_ARGS \ --disable-docs ENV SCRIPT \ - python3 ../x.py --stage 2 test --target $RUN_MAKE_TARGETS src/test/run-make && \ - python3 ../x.py dist --target $TARGETS + python3 ../x.py --stage 2 test --host='' --target $RUN_MAKE_TARGETS src/test/run-make && \ + python3 ../x.py dist --host='' --target $TARGETS # sccache COPY scripts/sccache.sh /scripts/ 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 3081f29aef..47a66f7480 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -110,4 +110,4 @@ ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs \ --set target.wasm32-wasi.wasi-root=/wasm32-wasi \ --musl-root-armv7=/musl-armv7 -ENV SCRIPT python3 ../x.py dist --target $TARGETS +ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-cloudabi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-cloudabi-toolchain.sh index 3354a796c3..b7ff6cd4e4 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-cloudabi-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-cloudabi-toolchain.sh @@ -16,6 +16,7 @@ apt-get install -y --no-install-recommends \ git \ lld-5.0 \ make \ + ninja-build \ python \ sudo \ xz-utils diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index bfc768f993..1075947c9c 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 7681eaef60..f5c4d638c1 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -96,8 +96,11 @@ ENV RUST_CONFIGURE_ARGS \ --set target.x86_64-unknown-linux-gnu.ar=/rustroot/bin/llvm-ar \ --set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \ --set llvm.thin-lto=false \ + --set llvm.ninja=false \ --set rust.jemalloc -ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS \ + --include-default-paths \ + src/tools/build-manifest ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh deleted file mode 100755 index 38fea2a809..0000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - - -cd git-2.10.0 -make configure -hide_output ./configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf git-2.10.0 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh deleted file mode 100755 index b623e53583..0000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x - -cd linux-3.2.84 -hide_output make mrproper -hide_output make INSTALL_HDR_PATH=dest headers_install - -find dest/include \( -name .install -o -name ..install.cmd \) -delete -yes | cp -fr dest/include/* /usr/include - -cd .. -rm -rf linux-3.2.84 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh deleted file mode 100755 index a678d353d5..0000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl https://www.cpan.org/src/5.0/perl-5.28.0.tar.gz | \ - tar xzf - - -cd perl-5.28.0 - -# Gotta do some hackery to tell python about our custom OpenSSL build, but other -# than that fairly normal. -CC=gcc \ -CFLAGS='-I /rustroot/include -fgnu89-inline' \ -LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ - hide_output ./configure.gnu -hide_output make -j10 -hide_output make install - -cd .. -rm -rf perl-5.28.0 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile index ab6515cd1f..904ee64db3 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ wget \ curl \ @@ -33,6 +34,7 @@ ENV HOSTS=x86_64-unknown-linux-musl ENV RUST_CONFIGURE_ARGS \ --musl-root-x86_64=/usr/local/x86_64-linux-musl \ --enable-extended \ + --enable-profiler \ --enable-lld \ --set target.x86_64-unknown-linux-musl.crt-static=false \ --build $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 cb507dced4..930061fca6 100644 --- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++-multilib \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index 9d319017d7..ea178bcf4f 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++-multilib \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index b902eda87b..8fc9a009dc 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index c55a284e13..8653aecc12 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -40,7 +41,7 @@ ENV RUST_CONFIGURE_ARGS \ ENV NO_DEBUG_ASSERTIONS=1 ENV WASM_TARGETS=wasm32-unknown-unknown -ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --target $WASM_TARGETS \ +ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \ src/test/run-make \ src/test/ui \ src/test/compile-fail \ @@ -49,13 +50,13 @@ ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --target $WASM_TARGETS \ library/core ENV NVPTX_TARGETS=nvptx64-nvidia-cuda -ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --target $NVPTX_TARGETS \ +ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $NVPTX_TARGETS \ src/test/run-make \ src/test/assembly ENV MUSL_TARGETS=x86_64-unknown-linux-musl \ CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \ CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++ -ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --target $MUSL_TARGETS +ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $MUSL_TARGETS ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT diff --git a/src/ci/docker/host-x86_64/wasm32/Dockerfile b/src/ci/docker/host-x86_64/wasm32/Dockerfile index e00177b4a6..096b664534 100644 --- a/src/ci/docker/host-x86_64/wasm32/Dockerfile +++ b/src/ci/docker/host-x86_64/wasm32/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -52,7 +53,7 @@ ENV NO_CHANGE_USER=1 # FIXME: Re-enable these tests once https://github.com/rust-lang/cargo/pull/7476 # is picked up by CI -ENV SCRIPT python3 ../x.py test --stage 2 --target $TARGETS \ +ENV SCRIPT python3 ../x.py test --stage 2 --host='' --target $TARGETS \ --exclude library/core \ --exclude library/alloc \ --exclude library/proc_macro \ 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 86ac0256d2..a109b36066 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 @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ 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 c1cb20b631..fe956b9c7b 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 @@ -3,6 +3,7 @@ FROM ubuntu:19.10 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ 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 68e89a7bad..5f98edf617 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 @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile index 5c971c73c9..34c6396b7b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile @@ -4,6 +4,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ g++-arm-linux-gnueabi \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -44,7 +45,7 @@ ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \ # on the `x86_64` host when they're built as `armv5te` binaries. # (we're only interested in the MIR output, so this doesn't matter) python2.7 ../x.py --stage 2 test src/test/mir-opt --pass=build \ - --target=armv5te-unknown-linux-gnueabi && \ + --host='' --target=armv5te-unknown-linux-gnueabi && \ # Run the UI test suite again, but in `--pass=check` mode # # This is intended to make sure that both `--pass=check` continues to diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile index 41e83c69e5..f4071961f8 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ 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 ef17f0507a..89171a6f21 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 @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index f8bacf79ac..527b539f68 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:19.10 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/scripts/android-base-apt-get.sh b/src/ci/docker/scripts/android-base-apt-get.sh index 391b68ea63..1795b1696d 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 \ git \ libssl-dev \ make \ + ninja-build \ pkg-config \ python3 \ sudo \ diff --git a/src/ci/docker/scripts/cross-apt-packages.sh b/src/ci/docker/scripts/cross-apt-packages.sh index 7030cd74ca..2de376443a 100644 --- a/src/ci/docker/scripts/cross-apt-packages.sh +++ b/src/ci/docker/scripts/cross-apt-packages.sh @@ -17,6 +17,7 @@ apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ libtool-bin \ make \ + ninja-build \ patch \ pkg-config \ python3 \ diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index db2def483a..101716d160 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -103,13 +103,6 @@ x--expand-yaml-anchors--remove: with: fetch-depth: 2 - - name: configure GitHub Actions to kill the build when outdated - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master - with: - github_token: "${{ secrets.github_token }}" - if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' - <<: *step - # Rust Log Analyzer can't currently detect the PR number of a GitHub # Actions build on its own, so a hint in the log message is needed to # point it in the right direction. @@ -133,6 +126,13 @@ x--expand-yaml-anchors--remove: run: src/ci/scripts/should-skip-this.sh <<: *step + - name: configure GitHub Actions to kill the build when outdated + uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master + with: + github_token: "${{ secrets.github_token }}" + if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' + <<: *step + - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh <<: *step @@ -284,18 +284,6 @@ jobs: CI_ONLY_WHEN_SUBMODULES_CHANGED: 1 <<: *job-linux-xl - try: - <<: *base-ci-job - name: try - env: - <<: [*shared-ci-variables, *prod-variables] - if: github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust' - strategy: - matrix: - include: - - name: dist-x86_64-linux - <<: *job-linux-xl - auto: <<: *base-ci-job name: auto @@ -378,7 +366,8 @@ jobs: - name: dist-x86_64-illumos <<: *job-linux-xl - - name: dist-x86_64-linux + - &dist-x86_64-linux + name: dist-x86_64-linux <<: *job-linux-xl - name: dist-x86_64-linux-alt @@ -432,6 +421,42 @@ jobs: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json <<: *job-linux-xl + #################### + # macOS Builders # + #################### + + - name: dist-x86_64-apple + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-macos-xl + + - name: dist-x86_64-apple-alt + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + + - name: x86_64-apple + env: + SCRIPT: ./x.py --stage 2 test + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + ###################### # Windows Builders # ###################### @@ -489,7 +514,7 @@ jobs: # # We are using MinGW with POSIX threads since LLVM requires # C++'s std::thread which is disabled in libstdc++ with win32 threads. - # FIXME: Libc++ doesn't have this limitation so we can avoid + # FIXME: Libc++ doesn't have this limitation so we can avoid # winpthreads if we switch to it. # # Instead of relying on the MinGW version installed on CI we download @@ -521,7 +546,7 @@ jobs: - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler CUSTOM_MINGW: 1 # FIXME(#59637) NO_DEBUG_ASSERTIONS: 1 @@ -531,7 +556,7 @@ jobs: - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler CUSTOM_MINGW: 1 <<: *job-windows-xl @@ -539,6 +564,7 @@ jobs: env: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-msvc + --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools --enable-profiler @@ -550,7 +576,8 @@ jobs: env: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-msvc - --target=i586-pc-windows-msvc + --host=i686-pc-windows-msvc + --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler SCRIPT: python x.py dist @@ -596,41 +623,16 @@ jobs: - name: aarch64-gnu <<: *job-aarch64-linux - #################### - # macOS Builders # - #################### - - - name: dist-x86_64-apple - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-macos-xl - - - name: dist-x86_64-apple-alt - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - - - name: x86_64-apple - env: - SCRIPT: ./x.py --stage 2 test - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl + try: + <<: *base-ci-job + name: try + env: + <<: [*shared-ci-variables, *prod-variables] + if: github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust' + strategy: + matrix: + include: + - *dist-x86_64-linux master: name: master diff --git a/src/ci/run.sh b/src/ci/run.sh index 59510f5945..8681f84f6a 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -63,7 +63,7 @@ fi # # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable` # either automatically or manually. -export RUST_RELEASE_CHANNEL=stable +export RUST_RELEASE_CHANNEL=beta # Always set the release channel for bootstrap; this is normally not important (i.e., only dist # builds would seem to matter) but in practice bootstrap wants to know whether we're targeting @@ -104,6 +104,8 @@ if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ] RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools" fi +export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1 + # Print the date from the local machine and the date from an external source to # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure # Pipelines it happened that the certificates were marked as expired. diff --git a/src/ci/scripts/symlink-build-dir.sh b/src/ci/scripts/symlink-build-dir.sh index 28d8aa3b6e..23849f7047 100755 --- a/src/ci/scripts/symlink-build-dir.sh +++ b/src/ci/scripts/symlink-build-dir.sh @@ -12,22 +12,4 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isWindows && isAzurePipelines; then cmd //c "mkdir c:\\MORE_SPACE" cmd //c "mklink /J build c:\\MORE_SPACE" -elif isLinux && isGitHubActions && ! isSelfHostedGitHubActions; then - sudo mkdir -p /mnt/more-space - sudo chown -R "$(whoami):" /mnt/more-space - - # Switch the whole workspace to the /mnt partition, which has more space. - # We don't just symlink the `obj` directory as doing that creates problems - # with the docker container. - current_dir="$(readlink -f "$(pwd)")" - cd /tmp - mv "${current_dir}" /mnt/more-space/workspace - ln -s /mnt/more-space/workspace "${current_dir}" - cd "${current_dir}" - - # Move the Docker data directory to /mnt - sudo systemctl stop docker.service - sudo mv /var/lib/docker /mnt/docker - sudo ln -s /mnt/docker /var/lib/docker - sudo systemctl start docker.service fi diff --git a/src/doc/book/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/output.txt b/src/doc/book/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/output.txt index be3ef310f8..273b34711a 100644 --- a/src/doc/book/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/output.txt +++ b/src/doc/book/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/output.txt @@ -1,6 +1,15 @@ $ cargo run Compiling arrays v0.1.0 (file:///projects/arrays) - Finished dev [unoptimized + debuginfo] target(s) in 0.31s - Running `target/debug/arrays` -thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:5:19 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +error: this operation will panic at runtime + --> src/main.rs:5:19 + | +5 | let element = a[index]; + | ^^^^^^^^ index out of bounds: the len is 5 but the index is 10 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to previous error + +error: could not compile `arrays`. + +To learn more, run the command again with --verbose. diff --git a/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs b/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs index 814fddc509..df33743f78 100644 --- a/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs +++ b/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs @@ -1,5 +1,5 @@ fn largest(list: &[T]) -> &T { - let mut largest = list[0]; + let mut largest = &list[0]; for item in list { if item > largest { diff --git a/src/doc/book/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs b/src/doc/book/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs index 6284f4f291..becae97e07 100644 --- a/src/doc/book/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs +++ b/src/doc/book/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs @@ -1,3 +1,7 @@ +#![allow(unused_variables)] +fn main() {} + +// ANCHOR: here #[cfg(test)] mod tests { #[test] @@ -9,3 +13,4 @@ mod tests { } } } +// ANCHOR_END: here diff --git a/src/doc/book/src/appendix-06-translation.md b/src/doc/book/src/appendix-06-translation.md index 035fbcaff6..cbd39743c9 100644 --- a/src/doc/book/src/appendix-06-translation.md +++ b/src/doc/book/src/appendix-06-translation.md @@ -24,3 +24,4 @@ For resources in languages other than English. Most are still in progress; see - [Svenska](https://github.com/sebras/book) - [Farsi](https://github.com/pomokhtari/rust-book-fa) - [Deutsch](https://github.com/rust-lang-de/rustbook-de) +- [Turkish](https://github.com/RustDili/dokuman/tree/master/ceviriler), [online](https://rustdili.github.io/) diff --git a/src/doc/book/src/ch03-02-data-types.md b/src/doc/book/src/ch03-02-data-types.md index f76d54bd59..62111c7241 100644 --- a/src/doc/book/src/ch03-02-data-types.md +++ b/src/doc/book/src/ch03-02-data-types.md @@ -320,7 +320,7 @@ compile but exit with an error when it runs: Filename: src/main.rs -```rust,ignore,panics +```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/src/main.rs}} ``` diff --git a/src/doc/book/src/ch11-01-writing-tests.md b/src/doc/book/src/ch11-01-writing-tests.md index 996816bce2..f486a5cdf8 100644 --- a/src/doc/book/src/ch11-01-writing-tests.md +++ b/src/doc/book/src/ch11-01-writing-tests.md @@ -507,7 +507,7 @@ that use `Result`! Here’s the test from Listing 11-1, rewritten to use `Result` and return an `Err` instead of panicking: ```rust -{{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs}} +{{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs:here}} ``` The `it_works` function now has a return type, `Result<(), String>`. In the diff --git a/src/doc/edition-guide/src/rust-next/const-fn.md b/src/doc/edition-guide/src/rust-next/const-fn.md index 2f504d1f3b..65f640f70b 100644 --- a/src/doc/edition-guide/src/rust-next/const-fn.md +++ b/src/doc/edition-guide/src/rust-next/const-fn.md @@ -230,7 +230,7 @@ const fn foo() { ![Minimum Rust version: 1.33](https://img.shields.io/badge/Minimum%20Rust%20Version-1.33-brightgreen.svg) -YOu can call an `unsafe fn` inside a `const fn`: +You can call an `unsafe fn` inside a `const fn`: ``` const unsafe fn foo() -> i32 { 5 } @@ -238,4 +238,4 @@ const unsafe fn foo() -> i32 { 5 } const fn bar() -> i32 { unsafe { foo() } } -``` \ No newline at end of file +``` diff --git a/src/doc/embedded-book/src/intro/install.md b/src/doc/embedded-book/src/intro/install.md index 6dd61f8286..343f762cab 100644 --- a/src/doc/embedded-book/src/intro/install.md +++ b/src/doc/embedded-book/src/intro/install.md @@ -17,7 +17,7 @@ rustc 1.31.1 (b6c32da9b 2018-12-18) For bandwidth and disk usage concerns the default installation only supports native compilation. To add cross compilation support for the ARM Cortex-M architectures choose one of the following compilation targets. For the STM32F3DISCOVERY -board used for the examples in this book, use the final `thumbv7em-none-eabihf` target. +board used for the examples in this book, use the `thumbv7em-none-eabihf` target. Cortex-M0, M0+, and M1 (ARMv6-M architecture): ``` console @@ -39,6 +39,22 @@ Cortex-M4F and M7F with hardware floating point (ARMv7E-M architecture): $ rustup target add thumbv7em-none-eabihf ``` +Cortex-M23 (ARMv8-M architecture): +``` console +$ rustup target add thumbv8m.base-none-eabi +``` + +Cortex-M33 and M35P (ARMv8-M architecture): +``` console +$ rustup target add thumbv8m.main-none-eabi +``` + +Cortex-M33F and M35PF with hardware floating point (ARMv8-M architecture): +``` console +$ rustup target add thumbv8m.main-none-eabihf +``` + + ### `cargo-binutils` ``` console diff --git a/src/doc/nomicon/src/vec-final.md b/src/doc/nomicon/src/vec-final.md index 8c86641bd5..eb749a4758 100644 --- a/src/doc/nomicon/src/vec-final.md +++ b/src/doc/nomicon/src/vec-final.md @@ -47,7 +47,7 @@ impl RawVec { let c: NonNull = self.ptr.into(); let ptr = Global.grow(c.cast(), Layout::array::(self.cap).unwrap(), - Layout::array::(new_cap).unwrap().size()); + Layout::array::(new_cap).unwrap()); (new_cap, ptr) }; diff --git a/src/doc/reference/src/behavior-considered-undefined.md b/src/doc/reference/src/behavior-considered-undefined.md index d2488591c7..f1ad30ada3 100644 --- a/src/doc/reference/src/behavior-considered-undefined.md +++ b/src/doc/reference/src/behavior-considered-undefined.md @@ -57,6 +57,11 @@ code. > **Note**: `rustc` achieves this with the unstable > `rustc_layout_scalar_valid_range_*` attributes. +**Note:** Uninitialized memory is also implicitly invalid for any type that has +a restricted set of valid values. In other words, the only cases in which +reading uninitialized memory is permitted are inside `union`s and in "padding" +(the gaps between the fields/elements of a type). + A reference/pointer is "dangling" if it is null or not all of the bytes it points to are part of the same allocation (so in particular they all have to be part of *some* allocation). The span of bytes it points to is determined by the diff --git a/src/doc/reference/src/const_eval.md b/src/doc/reference/src/const_eval.md index 2c4fbe9bad..b3d087f326 100644 --- a/src/doc/reference/src/const_eval.md +++ b/src/doc/reference/src/const_eval.md @@ -64,7 +64,24 @@ A _const context_ is one of the following: A _const fn_ is a function that one is permitted to call from a const context. Declaring a function `const` has no effect on any existing uses, it only restricts the types that arguments and the -return type may use, as well as prevent various expressions from being used within it. +return type may use, as well as prevent various expressions from being used within it. You can freely do anything with a const function that +you can do with a regular function. + +When called from a const context, the function is interpreted by the +compiler at compile time. The interpretation happens in the +environment of the compilation target and not the host. So `usize` is +`32` bits if you are compiling against a `32` bit system, irrelevant +of whether you are building on a `64` bit or a `32` bit system. + +Const functions have various restrictions to make sure that they can be +evaluated at compile-time. It is, for example, not possible to write a random +number generator as a const function. Calling a const function at compile-time +will always yield the same result as calling it at runtime, even when called +multiple times. There's one exception to this rule: if you are doing complex +floating point operations in extreme situations, then you might get (very +slightly) different results. It is advisable to not make array lengths and enum +discriminants depend on floating point computations. + Notable features that const contexts have, but const fn haven't are: diff --git a/src/doc/reference/src/expressions/match-expr.md b/src/doc/reference/src/expressions/match-expr.md index 9a0cb8d610..6d9f3f2afe 100644 --- a/src/doc/reference/src/expressions/match-expr.md +++ b/src/doc/reference/src/expressions/match-expr.md @@ -66,7 +66,7 @@ Multiple match patterns may be joined with the `|` operator. Each pattern will b tested in left-to-right sequence until a successful match is found. ```rust -# let x = 9; +let x = 9; let message = match x { 0 | 1 => "not many", 2 ..= 9 => "a few", diff --git a/src/doc/reference/src/items/functions.md b/src/doc/reference/src/items/functions.md index 138f1169e3..15b8cc10b4 100644 --- a/src/doc/reference/src/items/functions.md +++ b/src/doc/reference/src/items/functions.md @@ -183,58 +183,9 @@ aborts the process by executing an illegal instruction. ## Const functions -Functions qualified with the `const` keyword are const functions, as are +Functions qualified with the `const` keyword are [const functions], as are [tuple struct] and [tuple variant] constructors. _Const functions_ can be -called from within [const context]s. When called from a const context, the -function is interpreted by the compiler at compile time. The interpretation -happens in the environment of the compilation target and not the host. So -`usize` is `32` bits if you are compiling against a `32` bit system, irrelevant -of whether you are building on a `64` bit or a `32` bit system. - -If a const function is called outside a [const context], it is indistinguishable -from any other function. You can freely do anything with a const function that -you can do with a regular function. - -Const functions have various restrictions to make sure that they can be -evaluated at compile-time. It is, for example, not possible to write a random -number generator as a const function. Calling a const function at compile-time -will always yield the same result as calling it at runtime, even when called -multiple times. There's one exception to this rule: if you are doing complex -floating point operations in extreme situations, then you might get (very -slightly) different results. It is advisable to not make array lengths and enum -discriminants depend on floating point computations. - -Exhaustive list of permitted structures in const functions: - -> **Note**: this list is more restrictive than what you can write in -> regular constants - -* Type parameters where the parameters only have any [trait bounds] - of the following kind: - * lifetimes - * `Sized` or [`?Sized`] - - This means that ``, ``, and `` - are all permitted. - - This rule also applies to type parameters of impl blocks that - contain const methods. - - This does not apply to tuple struct and tuple variant constructors. - -* Arithmetic and comparison operators on integers -* All boolean operators except for `&&` and `||` which are banned since - they are short-circuiting. -* Any kind of aggregate constructor (array, `struct`, `enum`, tuple, ...) -* Calls to other *safe* const functions (whether by function call or method call) -* Index expressions on arrays and slices -* Field accesses on structs and tuples -* Reading from constants (but not statics, not even taking a reference to a static) -* `&` and `*` (only dereferencing of references, not raw pointers) -* Casts except for raw pointer to integer casts -* `unsafe` blocks and `const unsafe fn` are allowed, but the body/block may only do - the following unsafe operations: - * calls to const unsafe functions +called from within [const context]s. ## Async functions @@ -396,6 +347,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [_WhereClause_]: generics.md#where-clauses [_OuterAttribute_]: ../attributes.md [const context]: ../const_eval.md#const-context +[const functions]: ../const_eval.md#const-functions [tuple struct]: structs.md [tuple variant]: enumerations.md [external block]: external-blocks.md @@ -416,10 +368,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [`doc`]: ../../rustdoc/the-doc-attribute.html [`must_use`]: ../attributes/diagnostics.md#the-must_use-attribute [patterns]: ../patterns.md -[`?Sized`]: ../trait-bounds.md#sized -[trait bounds]: ../trait-bounds.md [`export_name`]: ../abi.md#the-export_name-attribute [`link_section`]: ../abi.md#the-link_section-attribute [`no_mangle`]: ../abi.md#the-no_mangle-attribute -[external_block_abi]: external-blocks.md#abi [built-in attributes]: ../attributes.html#built-in-attributes-index diff --git a/src/doc/reference/src/linkage.md b/src/doc/reference/src/linkage.md index 264d3f024a..4a8ed96a96 100644 --- a/src/doc/reference/src/linkage.md +++ b/src/doc/reference/src/linkage.md @@ -41,10 +41,10 @@ be ignored in favor of only building the artifacts specified by command line. the compiler will never attempt to link to `staticlib` outputs. The purpose of this output type is to create a static library containing all of the local crate's code along with all upstream dependencies. The static - library is actually a `*.a` archive on linux and osx and a `*.lib` file on - windows. This format is recommended for use in situations such as linking - Rust code into an existing non-Rust application because it will not have - dynamic dependencies on other Rust code. + library is actually a `*.a` archive on linux and osx and windows(MinGW), and + a `*.lib` file on windows(MSVC). This format is recommended for use in + situations such as linking Rust code into an existing non-Rust application + because it will not have dynamic dependencies on other Rust code. * `--crate-type=cdylib`, `#[crate_type = "cdylib"]` - A dynamic system library will be produced. This is used when compiling diff --git a/src/doc/reference/src/patterns.md b/src/doc/reference/src/patterns.md index 88940641c6..b9c1b9690b 100644 --- a/src/doc/reference/src/patterns.md +++ b/src/doc/reference/src/patterns.md @@ -2,10 +2,15 @@ > **Syntax**\ > _Pattern_ :\ +>       _PatternWithoutRange_\ +>    | [_RangePattern_] +> +> _PatternWithoutRange_ :\ >       [_LiteralPattern_]\ >    | [_IdentifierPattern_]\ >    | [_WildcardPattern_]\ ->    | [_RangePattern_]\ +>    | [_RestPattern_]\ +>    | [_ObsoleteRangePattern_]\ >    | [_ReferencePattern_]\ >    | [_StructPattern_]\ >    | [_TupleStructPattern_]\ @@ -248,6 +253,9 @@ copying or moving what was matched. [Path patterns](#path-patterns) take precedence over identifier patterns. It is an error if `ref` or `ref mut` is specified and the identifier shadows a constant. +Identifier patterns are irrefutable if the `@` subpattern is irrefutable or +the subpattern is not specified. + ### Binding modes To service better ergonomics, patterns operate in different *binding modes* in @@ -317,12 +325,67 @@ if let Some(_) = x {} The wildcard pattern is always irrefutable. +## Rest patterns + +> **Syntax**\ +> _RestPattern_ :\ +>    `..` + +The _rest pattern_ (the `..` token) acts as a variable-length pattern which +matches zero or more elements that haven't been matched already before and +after. It may only be used in [tuple](#tuple-patterns), [tuple +struct](#tuple-struct-patterns), and [slice](#slice-patterns) patterns, and +may only appear once as one of the elements in those patterns. It is also +allowed in an [identifier pattern](#identifier-patterns) for [slice +patterns](#slice-patterns) only. + +The rest pattern is always irrefutable. + +Examples: + +```rust +# let words = vec!["a", "b", "c"]; +# let slice = &words[..]; +match slice { + [] => println!("slice is empty"), + [one] => println!("single element {}", one), + [head, tail @ ..] => println!("head={} tail={:?}", head, tail), +} + +match slice { + // Ignore everything but the last element, which must be "!". + [.., "!"] => println!("!!!"), + + // `start` is a slice of everything except the last element, which must be "z". + [start @ .., "z"] => println!("starts with: {:?}", start), + + // `end` is a slice of everything but the first element, which must be "a". + ["a", end @ ..] => println!("ends with: {:?}", end), + + rest => println!("{:?}", rest), +} + +if let [.., penultimate, _] = slice { + println!("next to last is {}", penultimate); +} + +# let tuple = (1, 2, 3, 4, 5); +// Rest patterns may also be used in tuple and tuple struct patterns. +match tuple { + (1, .., y, z) => println!("y={} z={}", y, z), + (.., 5) => println!("tail must be 5"), + (..) => println!("matches everything else"), +} +``` + ## Range patterns > **Syntax**\ > _RangePattern_ :\ ->      _RangePatternBound_ `..=` _RangePatternBound_\ ->    | _RangePatternBound_ `...` _RangePatternBound_ +>    _RangePatternBound_ `..=` _RangePatternBound_ +> +> _ObsoleteRangePattern_ :\ +>    _RangePatternBound_ `...` _RangePatternBound_ > > _RangePatternBound_ :\ >       [CHAR_LITERAL]\ @@ -429,7 +492,7 @@ ranges containing all Unicode Scalar Values: `'\u{0000}'..='\u{D7FF}'` and > **Syntax**\ > _ReferencePattern_ :\ ->    (`&`|`&&`) `mut`? _Pattern_ +>    (`&`|`&&`) `mut`? [_PatternWithoutRange_] Reference patterns dereference the pointers that are being matched and, thus, borrow them. @@ -559,8 +622,7 @@ A struct pattern is refutable when one of its subpatterns is refutable. >    [_PathInExpression_] `(` _TupleStructItems_? `)` > > _TupleStructItems_ :\ ->       [_Pattern_] ( `,` [_Pattern_] )\* `,`?\ ->    | ([_Pattern_] `,`)\* `..` (`,` [_Pattern_])* `,`? +>    [_Pattern_] ( `,` [_Pattern_] )\* `,`? Tuple struct patterns match tuple struct and enum values that match all criteria defined by its subpatterns. They are also used to [destructure](#destructuring) a tuple struct or @@ -576,13 +638,16 @@ A tuple struct pattern is refutable when one of its subpatterns is refutable. > > _TuplePatternItems_ :\ >       [_Pattern_] `,`\ ->    | [_Pattern_] (`,` [_Pattern_])+ `,`?\ ->    | ([_Pattern_] `,`)\* `..` (`,` [_Pattern_])* `,`? +>    | [_RestPattern_]\ +>    | [_Pattern_] (`,` [_Pattern_])+ `,`? Tuple patterns match tuple values that match all criteria defined by its subpatterns. They are also used to [destructure](#destructuring) a tuple. -This pattern is refutable when one of its subpatterns is refutable. +The form `(..)` with a single [_RestPattern_] is a special form that does not +require a comma, and matches a tuple of any size. + +The tuple pattern is refutable when one of its subpatterns is refutable. ## Grouped patterns @@ -607,7 +672,10 @@ match int_reference { > **Syntax**\ > _SlicePattern_ :\ ->    `[` [_Pattern_] \(`,` [_Pattern_])\* `,`? `]` +>    `[` _SlicePatternItems_? `]` +> +> _SlicePatternItems_ :\ +>    [_Pattern_] \(`,` [_Pattern_])\* `,`? Slice patterns can match both arrays of fixed size and slices of dynamic size. ```rust @@ -628,6 +696,11 @@ match v[..] { }; ``` +Slice patterns are irrefutable when matching an array as long as each element +is irrefutable. When matching a slice, it is irrefutable only in the form with +a single `..` [rest pattern](#rest-patterns) or [identifier +pattern](#identifier-patterns) with the `..` rest pattern as a subpattern. + ## Path patterns > **Syntax**\ @@ -658,12 +731,15 @@ refer to refutable constants or enum variants for enums with multiple variants. [_IdentifierPattern_]: #identifier-patterns [_LiteralPattern_]: #literal-patterns [_MacroInvocation_]: macros.md#macro-invocation +[_ObsoleteRangePattern_]: #range-patterns [_PathInExpression_]: paths.md#paths-in-expressions [_PathPattern_]: #path-patterns [_Pattern_]: #patterns +[_PatternWithoutRange_]: #patterns [_QualifiedPathInExpression_]: paths.md#qualified-paths [_RangePattern_]: #range-patterns [_ReferencePattern_]: #reference-patterns +[_RestPattern_]: #rest-patterns [_SlicePattern_]: #slice-patterns [_StructPattern_]: #struct-patterns [_TuplePattern_]: #tuple-patterns diff --git a/src/doc/reference/src/type-coercions.md b/src/doc/reference/src/type-coercions.md index 377afe769b..d578e042a1 100644 --- a/src/doc/reference/src/type-coercions.md +++ b/src/doc/reference/src/type-coercions.md @@ -1,10 +1,13 @@ # Type coercions -Coercions are defined in [RFC 401]. [RFC 1558] then expanded on that. -A coercion is implicit and has no syntax. +**Type coercions** are implicit operations that change the type of a value. +They happen automatically at specific locations and are highly restricted in +what types actually coerce. -[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md -[RFC 1558]: https://github.com/rust-lang/rfcs/blob/master/text/1558-closure-to-fn-coercion.md +Any conversions allowed by coercion can also be explicitly performed by the +[type cast operator], `as`. + +Coercions are originally defined in [RFC 401] and expanded upon in [RFC 1558]. ## Coercion sites @@ -15,52 +18,53 @@ sites are: * `let` statements where an explicit type is given. - For example, `42` is coerced to have type `i8` in the following: + For example, `&mut 42` is coerced to have type `&i8` in the following: ```rust - let _: i8 = 42; + let _: &i8 = &mut 42; ``` -* `static` and `const` statements (similar to `let` statements). +* `static` and `const` item declarations (similar to `let` statements). * Arguments for function calls The value being coerced is the actual parameter, and it is coerced to the type of the formal parameter. - For example, `42` is coerced to have type `i8` in the following: + For example, `&mut 42` is coerced to have type `&i8` in the following: ```rust - fn bar(_: i8) { } + fn bar(_: &i8) { } fn main() { - bar(42); + bar(&mut 42); } ``` For method calls, the receiver (`self` parameter) can only take advantage of [unsized coercions](#unsized-coercions). -* Instantiations of struct or variant fields +* Instantiations of struct, union, or enum variant fields - For example, `42` is coerced to have type `i8` in the following: + For example, `&mut 42` is coerced to have type `&i8` in the following: ```rust - struct Foo { x: i8 } + struct Foo<'a> { x: &'a i8 } fn main() { - Foo { x: 42 }; + Foo { x: &mut 42 }; } ``` - -* Function results, either the final line of a block if it is not + +* Function results—either the final line of a block if it is not semicolon-terminated or any expression in a `return` statement - For example, `42` is coerced to have type `i8` in the following: + For example, `x` is coerced to have type `&dyn Display` in the following: ```rust - fn foo() -> i8 { - 42 + use std::fmt::Display; + fn foo(x: &u32) -> &dyn Display { + x } ``` @@ -91,7 +95,7 @@ the block has a known type. Coercion is allowed between the following types: -* `T` to `U` if `T` is a subtype of `U` (*reflexive case*) +* `T` to `U` if `T` is a [subtype] of `U` (*reflexive case*) * `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3` (*transitive case*) @@ -164,8 +168,7 @@ an implementation of `Unsize` for `T` will be provided: * `[T; n]` to `[T]`. -* `T` to `U`, when `U` is a trait object type and either `T` implements `U` or - `T` is a trait object for a subtrait of `U`. +* `T` to `dyn U`, when `T` implements `U + Sized`, and `U` is [object safe]. * `Foo<..., T, ...>` to `Foo<..., U, ...>`, when: * `Foo` is a struct. @@ -182,5 +185,10 @@ unsized coercion to `Foo`. > has been stabilized, the traits themselves are not yet stable and therefore > can't be used directly in stable Rust. +[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md +[RFC 1558]: https://github.com/rust-lang/rfcs/blob/master/text/1558-closure-to-fn-coercion.md +[subtype]: subtyping.md +[object safe]: items/traits.md#object-safety +[type cast operator]: expressions/operator-expr.md#type-cast-expressions [`Unsize`]: ../std/marker/trait.Unsize.html [`CoerceUnsized`]: ../std/ops/trait.CoerceUnsized.html diff --git a/src/doc/reference/src/type-layout.md b/src/doc/reference/src/type-layout.md index 3adbdc95f1..c450195b47 100644 --- a/src/doc/reference/src/type-layout.md +++ b/src/doc/reference/src/type-layout.md @@ -174,7 +174,8 @@ layout such as reinterpreting values as a different type. Because of this dual purpose, it is possible to create types that are not useful for interfacing with the C programming language. -This representation can be applied to structs, unions, and enums. +This representation can be applied to structs, unions, and enums. The exception +is [zero-variant enums] for which the `C` representation is an error. #### \#[repr(C)] Structs @@ -273,9 +274,9 @@ assert_eq!(std::mem::size_of::(), 8); // Size of 6 from b, assert_eq!(std::mem::align_of::(), 4); // From a ``` -#### \#[repr(C)] Enums +#### \#[repr(C)] Field-less Enums -For [C-like enumerations], the `C` representation has the size and alignment of +For [field-less enums], the `C` representation has the size and alignment of the default `enum` size and alignment for the target platform's C ABI. > Note: The enum representation in C is implementation defined, so this is @@ -285,21 +286,80 @@ the default `enum` size and alignment for the target platform's C ABI.
Warning: There are crucial differences between an `enum` in the C language and -Rust's C-like enumerations with this representation. An `enum` in C is +Rust's [field-less enums] with this representation. An `enum` in C is mostly a `typedef` plus some named constants; in other words, an object of an `enum` type can hold any integer value. For example, this is often used for -bitflags in `C`. In contrast, Rust’s C-like enumerations can only legally hold -the discriminant values, everything else is undefined behaviour. Therefore, -using a C-like enumeration in FFI to model a C `enum` is often wrong. +bitflags in `C`. In contrast, Rust’s [field-less enums] can only legally hold +the discrimnant values, everything else is [undefined behavior]. Therefore, +using a field-less enum in FFI to model a C `enum` is often wrong.
-It is an error for [zero-variant enumerations] to have the `C` representation. +#### \#[repr(C)] Enums With Fields -For all other enumerations, the layout is unspecified. +The representation of a `repr(C)` enum with fields is a `repr(C)` struct with +two fields, also called a "tagged union" in C: -Likewise, combining the `C` representation with a primitive representation, the -layout is unspecified. +- a `repr(C)` version of the enum with all fields removed ("the tag") +- a `repr(C)` union of `repr(C)` structs for the fields of each variant that had + them ("the payload") + +> Note: Due to the representation of `repr(C)` structs and unions, if a variant +> has a single field there is no difference between putting that field directly +> in the union or wrapping it in a struct; any system which wishes to manipulate +> such an `enum`'s representation may therefore use whichever form is more +> convenient or consistent for them. + +```rust +// This Enum has the same representation as ... +#[repr(C)] +enum MyEnum { + A(u32), + B(f32, u64), + C { x: u32, y: u8 }, + D, + } + +// ... this struct. +#[repr(C)] +struct MyEnumRepr { + tag: MyEnumDiscriminant, + payload: MyEnumFields, +} + +// This is the discriminant enum. +#[repr(C)] +enum MyEnumDiscriminant { A, B, C, D } + +// This is the variant union. +#[repr(C)] +union MyEnumFields { + A: MyAFields, + B: MyBFields, + C: MyCFields, + D: MyDFields, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct MyAFields(u32); + +#[repr(C)] +#[derive(Copy, Clone)] +struct MyBFields(f32, u64); + +#[repr(C)] +#[derive(Copy, Clone)] +struct MyCFields { x: u32, y: u8 } + +// This struct could be omitted (it is a zero-sized type), and it must be in +// C/C++ headers. +#[repr(C)] +#[derive(Copy, Clone)] +struct MyDFields; +``` + +> Note: `union`s with non-`Copy` fields are unstable, see [55149]. ### Primitive representations @@ -307,18 +367,135 @@ The *primitive representations* are the representations with the same names as the primitive integer types. That is: `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, and `isize`. -Primitive representations can only be applied to enumerations. +Primitive representations can only be applied to enumerations and have +different behavior whether the enum has fields or no fields. It is an error +for [zero-variant enumerations] to have a primitive representation. Combining +two primitive representations together is an error. + +#### Primitive Representation of Field-less Enums + +For [field-less enums], primitive representations set the size and alignment to +be the same as the primitive type of the same name. For example, a field-less +enum with a `u8` representation can only have discriminants between 0 and 255 +inclusive. -For [C-like enumerations], they set the size and alignment to be the same as the -primitive type of the same name. For example, a C-like enumeration with a `u8` -representation can only have discriminants between 0 and 255 inclusive. +#### Primitive Representation of Enums With Fields -It is an error for [zero-variant enumerations] to have a primitive -representation. +The representation of a primitive representation enum is a `repr(C)` union of +`repr(C)` structs for each variant with a field. The first field of each struct +in the union is the primitive representation version of the enum with all fields +removed ("the tag") and the remaining fields are the fields of that variant. -For all other enumerations, the layout is unspecified. +> Note: This representation is unchanged if the tag is given its own member in +> the union, should that make manipulation more clear for you (although to +> follow the C++ standard the tag member should be wrapped in a `struct`). + +```rust +// This enum has the same representation as ... +#[repr(u8)] +enum MyEnum { + A(u32), + B(f32, u64), + C { x: u32, y: u8 }, + D, + } + +// ... this union. +#[repr(C)] +union MyEnumRepr { + A: MyVariantA, + B: MyVariantB, + C: MyVariantC, + D: MyVariantD, +} + +// This is the discriminant enum. +#[repr(u8)] +#[derive(Copy, Clone)] +enum MyEnumDiscriminant { A, B, C, D } + +#[repr(C)] +#[derive(Clone, Copy)] +struct MyVariantA(MyEnumDiscriminant, u32); + +#[repr(C)] +#[derive(Clone, Copy)] +struct MyVariantB(MyEnumDiscriminant, f32, u64); + +#[repr(C)] +#[derive(Clone, Copy)] +struct MyVariantC { tag: MyEnumDiscriminant, x: u32, y: u8 } + +#[repr(C)] +#[derive(Clone, Copy)] +struct MyVariantD(MyEnumDiscriminant); +``` + +> Note: `union`s with non-`Copy` fields are unstable, see [55149]. + +#### Combining primitive representations of enums with fields and \#[repr(C)] + +For enums with fields, it is also possible to combine `repr(C)` and a +primitive representation (e.g., `repr(C, u8)`). This modifies the [`repr(C)`] by +changing the representation of the discriminant enum to the chosen primitive +instead. So, if you chose the `u8` representation, then the discriminant enum +would have a size and alignment of 1 byte. + +The discriminant enum from the example [earlier][`repr(C)`] then becomes: + +```rust +#[repr(C, u8)] // `u8` was added +enum MyEnum { + A(u32), + B(f32, u64), + C { x: u32, y: u8 }, + D, + } + +// ... + +#[repr(u8)] // So `u8` is used here instead of `C` +enum MyEnumDiscriminant { A, B, C, D } + +// ... +``` + +For example, with a `repr(C, u8)` enum it is not possible to have 257 unique +discriminants ("tags") whereas the same enum with only a `repr(C)` attribute +will compile without any problems. + +Using a primitive representation in addition to `repr(C)` can change the size of +an enum from the `repr(C)` form: + +```rust +#[repr(C)] +enum EnumC { + Variant0(u8), + Variant1, +} + +#[repr(C, u8)] +enum Enum8 { + Variant0(u8), + Variant1, +} + +#[repr(C, u16)] +enum Enum16 { + Variant0(u8), + Variant1, +} + +// The size of the C representation is platform dependant +assert_eq!(std::mem::size_of::(), 8); +// One byte for the discriminant and one byte for the value in Enum8::Variant0 +assert_eq!(std::mem::size_of::(), 2); +// Two bytes for the discriminant and one byte for the value in Enum16::Variant0 +// plus one byte of padding. +assert_eq!(std::mem::size_of::(), 4); +``` -Likewise, combining two primitive representations together is unspecified. +[`repr(C)`]: #reprc-enums-with-fields ### The alignment modifiers @@ -379,12 +556,14 @@ used with any other representation. [`align_of`]: ../std/mem/fn.align_of.html [`size_of`]: ../std/mem/fn.size_of.html [`Sized`]: ../std/marker/trait.Sized.html +[`Copy`]: ../std/marker/trait.Copy.html [dynamically sized types]: dynamically-sized-types.md -[C-like enumerations]: items/enumerations.md#custom-discriminant-values-for-fieldless-enumerations +[field-less enums]: items/enumerations.md#custom-discriminant-values-for-fieldless-enumerations [enumerations]: items/enumerations.md -[zero-variant enumerations]: items/enumerations.md#zero-variant-enums +[zero-variant enums]: items/enumerations.md#zero-variant-enums [undefined behavior]: behavior-considered-undefined.md [27060]: https://github.com/rust-lang/rust/issues/27060 +[55149]: https://github.com/rust-lang/rust/issues/55149 [`PhantomData`]: special-types-and-traits.md#phantomdatat [Default]: #the-default-representation [`C`]: #the-c-representation diff --git a/src/doc/rust-by-example/src/SUMMARY.md b/src/doc/rust-by-example/src/SUMMARY.md index 093d3af8ee..dfefcd5b90 100644 --- a/src/doc/rust-by-example/src/SUMMARY.md +++ b/src/doc/rust-by-example/src/SUMMARY.md @@ -82,8 +82,8 @@ - [File hierarchy](mod/split.md) - [Crates](crates.md) - - [Library](crates/lib.md) - - [`extern crate`](crates/link.md) + - [Creating a Library](crates/lib.md) + - [Using a Library](crates/using_lib.md) - [Cargo](cargo.md) - [Dependencies](cargo/deps.md) diff --git a/src/doc/rust-by-example/src/crates/lib.md b/src/doc/rust-by-example/src/crates/lib.md index 20b4cac59e..44593f3bb0 100644 --- a/src/doc/rust-by-example/src/crates/lib.md +++ b/src/doc/rust-by-example/src/crates/lib.md @@ -1,4 +1,4 @@ -# Library +# Creating a Library Let's create a library, and then see how to link it to another crate. diff --git a/src/doc/rust-by-example/src/crates/link.md b/src/doc/rust-by-example/src/crates/link.md deleted file mode 100644 index 828fbdbeba..0000000000 --- a/src/doc/rust-by-example/src/crates/link.md +++ /dev/null @@ -1,29 +0,0 @@ -# `extern crate` - -To link a crate to this new library, the `extern crate` declaration must be -used. This will not only link the library, but also import all its items under -a module named the same as the library. The visibility rules that apply to -modules also apply to libraries. - -```rust,ignore -// Link to `library`, import items under the `rary` module -extern crate rary; - -fn main() { - rary::public_function(); - - // Error! `private_function` is private - //rary::private_function(); - - rary::indirect_access(); -} -``` - -```txt -# Where library.rlib is the path to the compiled library, assumed that it's -# in the same directory here: -$ rustc executable.rs --extern rary=library.rlib && ./executable -called rary's `public_function()` -called rary's `indirect_access()`, that -> called rary's `private_function()` -``` diff --git a/src/doc/rust-by-example/src/crates/using_lib.md b/src/doc/rust-by-example/src/crates/using_lib.md new file mode 100644 index 0000000000..102080700f --- /dev/null +++ b/src/doc/rust-by-example/src/crates/using_lib.md @@ -0,0 +1,27 @@ +# Using a Library + +To link a crate to this new library you may use `rustc`'s `--extern` flag. All +of its items will then be imported under a module named the same as the library. +This module generally behaves the same way as any other module. + +```rust,ignore +// extern crate rary; // May be required for Rust 2015 edition or earlier + +fn main() { + rary::public_function(); + + // Error! `private_function` is private + //rary::private_function(); + + rary::indirect_access(); +} +``` + +```txt +# Where library.rlib is the path to the compiled library, assumed that it's +# in the same directory here: +$ rustc executable.rs --extern rary=library.rlib --edition=2018 && ./executable +called rary's `public_function()` +called rary's `indirect_access()`, that +> called rary's `private_function()` +``` diff --git a/src/doc/rust-by-example/src/custom_types/structs.md b/src/doc/rust-by-example/src/custom_types/structs.md index b7f84c2fa4..97bd46ba2a 100644 --- a/src/doc/rust-by-example/src/custom_types/structs.md +++ b/src/doc/rust-by-example/src/custom_types/structs.md @@ -9,9 +9,8 @@ There are three types of structures ("structs") that can be created using the ```rust,editable #[derive(Debug)] -struct Person<'a> { - // The 'a defines a lifetime - name: &'a str, +struct Person { + name: String, age: u8, } @@ -38,7 +37,7 @@ struct Rectangle { fn main() { // Create struct with field init shorthand - let name = "Peter"; + let name = String::from("Peter"); let age = 27; let peter = Person { name, age }; @@ -93,9 +92,8 @@ fn main() { ### See also: -[`attributes`][attributes], [lifetime][lifetime] and [destructuring][destructuring] +[`attributes`][attributes], and [destructuring][destructuring] [attributes]: ../attribute.md [c_struct]: https://en.wikipedia.org/wiki/Struct_(C_programming_language) [destructuring]: ../flow_control/match/destructuring.md -[lifetime]: ../scope/lifetime.md diff --git a/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md b/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md index e8acd25197..392b783aed 100644 --- a/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md +++ b/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md @@ -4,6 +4,7 @@ An alternative to boxing errors is to wrap them in your own error type. ```rust,editable use std::error; +use std::error::Error as _; use std::num::ParseIntError; use std::fmt; @@ -22,8 +23,10 @@ impl fmt::Display for DoubleError { match *self { DoubleError::EmptyVec => write!(f, "please use a vector with at least one element"), - // This is a wrapper, so defer to the underlying types' implementation of `fmt`. - DoubleError::Parse(ref e) => e.fmt(f), + // The wrapped error contains additional information and is available + // via the source() method. + DoubleError::Parse(..) => + write!(f, "the provided string could not be parsed as int"), } } } @@ -51,6 +54,8 @@ impl From for DoubleError { fn double_first(vec: Vec<&str>) -> Result { let first = vec.first().ok_or(DoubleError::EmptyVec)?; + // Here we implicitly use the `ParseIntError` implementation of `From` (which + // we defined above) in order to create a `DoubleError`. let parsed = first.parse::()?; Ok(2 * parsed) @@ -59,7 +64,12 @@ fn double_first(vec: Vec<&str>) -> Result { fn print(result: Result) { match result { Ok(n) => println!("The first doubled is {}", n), - Err(e) => println!("Error: {}", e), + Err(e) => { + println!("Error: {}", e); + if let Some(source) = e.source() { + println!(" Caused by: {}", source); + } + }, } } diff --git a/src/doc/rust-by-example/src/error/panic.md b/src/doc/rust-by-example/src/error/panic.md index a690642539..5524dbf6f2 100644 --- a/src/doc/rust-by-example/src/error/panic.md +++ b/src/doc/rust-by-example/src/error/panic.md @@ -1,19 +1,19 @@ # `panic` -The simplest error handling mechanism we will see is `panic`. It prints an -error message, starts unwinding the stack, and usually exits the program. -Here, we explicitly call `panic` on our error condition: +The simplest error handling mechanism we will see is `panic`. It prints an +error message, starts unwinding the stack, and usually exits the program. +Here, we explicitly call `panic` on our error condition: ```rust,editable,ignore,mdbook-runnable -fn give_princess(gift: &str) { - // Princesses hate snakes, so we need to stop if she disapproves! - if gift == "snake" { panic!("AAAaaaaa!!!!"); } +fn drink(beverage: &str) { + // You shouldn't drink too much sugary beverages. + if beverage == "lemonade" { panic!("AAAaaaaa!!!!"); } - println!("I love {}s!!!!!", gift); + println!("Some refreshing {} is all I need.", beverage); } fn main() { - give_princess("teddy bear"); - give_princess("snake"); + drink("water"); + drink("lemonade"); } ``` diff --git a/src/doc/rust-by-example/src/mod/use.md b/src/doc/rust-by-example/src/mod/use.md index 8860bc20b4..7a57272b15 100644 --- a/src/doc/rust-by-example/src/mod/use.md +++ b/src/doc/rust-by-example/src/mod/use.md @@ -4,8 +4,6 @@ The `use` declaration can be used to bind a full path to a new name, for easier access. It is often used like this: ```rust,editable,ignore -// extern crate deeply; // normally, this would exist and not be commented out! - use crate::deeply::nested::{ my_first_function, my_second_function, diff --git a/src/doc/rust-by-example/src/primitives/array.md b/src/doc/rust-by-example/src/primitives/array.md index f612c1dbc2..50ea52fca4 100644 --- a/src/doc/rust-by-example/src/primitives/array.md +++ b/src/doc/rust-by-example/src/primitives/array.md @@ -1,10 +1,10 @@ # Arrays and Slices An array is a collection of objects of the same type `T`, stored in contiguous -memory. Arrays are created using brackets `[]`, and their size, which is known -at compile time, is part of their type signature `[T; size]`. +memory. Arrays are created using brackets `[]`, and their length, which is known +at compile time, is part of their type signature `[T; length]`. -Slices are similar to arrays, but their size is not known at compile time. +Slices are similar to arrays, but their length is not known at compile time. Instead, a slice is a two-word object, the first word is a pointer to the data, and the second word is the length of the slice. The word size is the same as usize, determined by the processor architecture eg 64 bits on an x86-64. @@ -31,8 +31,8 @@ fn main() { println!("first element of the array: {}", xs[0]); println!("second element of the array: {}", xs[1]); - // `len` returns the size of the array - println!("array size: {}", xs.len()); + // `len` returns the count of elements in the array + println!("number of elements in array: {}", xs.len()); // Arrays are stack allocated println!("array occupies {} bytes", mem::size_of_val(&xs)); diff --git a/src/doc/rust-by-example/src/std_misc/threads.md b/src/doc/rust-by-example/src/std_misc/threads.md index 7a9b2cf22d..2f37d1c4a3 100644 --- a/src/doc/rust-by-example/src/std_misc/threads.md +++ b/src/doc/rust-by-example/src/std_misc/threads.md @@ -6,7 +6,7 @@ function, the argument of this function is a moving closure. ```rust,editable use std::thread; -static NTHREADS: i32 = 10; +const NTHREADS: u32 = 10; // This is the `main` thread fn main() { diff --git a/src/doc/rust-by-example/src/testing/integration_testing.md b/src/doc/rust-by-example/src/testing/integration_testing.md index 2ab0d85a6e..a4345ae945 100644 --- a/src/doc/rust-by-example/src/testing/integration_testing.md +++ b/src/doc/rust-by-example/src/testing/integration_testing.md @@ -10,7 +10,7 @@ Cargo looks for integration tests in `tests` directory next to `src`. File `src/lib.rs`: ```rust,ignore -// Assume that crate is called adder, will have to extern it in integration test. +// Define this in a crate called `adder`. pub fn add(a: i32, b: i32) -> i32 { a + b } @@ -19,9 +19,6 @@ pub fn add(a: i32, b: i32) -> i32 { File with test: `tests/integration_test.rs`: ```rust,ignore -// extern crate we're testing, same as any other code would do. -extern crate adder; - #[test] fn test_add() { assert_eq!(adder::add(3, 2), 5); @@ -66,9 +63,6 @@ pub fn setup() { File with test: `tests/integration_test.rs` ```rust,ignore -// extern crate we're testing, same as any other code will do. -extern crate adder; - // importing common module. mod common; diff --git a/src/doc/rust-by-example/src/trait/clone.md b/src/doc/rust-by-example/src/trait/clone.md index 1b9d953b71..5d6747a47b 100644 --- a/src/doc/rust-by-example/src/trait/clone.md +++ b/src/doc/rust-by-example/src/trait/clone.md @@ -30,9 +30,9 @@ fn main() { let pair = Pair(Box::new(1), Box::new(2)); println!("original: {:?}", pair); - // Copy `pair` into `moved_pair`, moves resources + // Move `pair` into `moved_pair`, moves resources let moved_pair = pair; - println!("copy: {:?}", moved_pair); + println!("moved: {:?}", moved_pair); // Error! `pair` has lost its resources //println!("original: {:?}", pair); diff --git a/src/doc/rust-by-example/src/variable_bindings/scope.md b/src/doc/rust-by-example/src/variable_bindings/scope.md index d9639b42e3..9e3c79e3ee 100644 --- a/src/doc/rust-by-example/src/variable_bindings/scope.md +++ b/src/doc/rust-by-example/src/variable_bindings/scope.md @@ -1,9 +1,7 @@ # Scope and Shadowing Variable bindings have a scope, and are constrained to live in a *block*. A -block is a collection of statements enclosed by braces `{}`. Also, [variable -shadowing][variable-shadow] is allowed. - +block is a collection of statements enclosed by braces `{}`. ```rust,editable,ignore,mdbook-runnable fn main() { // This binding lives in the main function @@ -15,11 +13,6 @@ fn main() { let short_lived_binding = 2; println!("inner short: {}", short_lived_binding); - - // This binding *shadows* the outer one - let long_lived_binding = 5_f32; - - println!("inner long: {}", long_lived_binding); } // End of the block @@ -28,12 +21,26 @@ fn main() { // FIXME ^ Comment out this line println!("outer long: {}", long_lived_binding); - - // This binding also *shadows* the previous binding - let long_lived_binding = 'a'; - - println!("outer long: {}", long_lived_binding); } ``` +Also, [variable shadowing][variable-shadow] is allowed. +```rust,editable,ignore,mdbook-runnable +fn main() { + let shadowed_binding = 1; + { + println!("before being shadowed: {}", shadowed_binding); + + // This binding *shadows* the outer one + let shadowed_binding = "abc"; + + println!("shadowed in inner block: {}", shadowed_binding); + } + println!("outside inner block: {}", shadowed_binding); + + // This binding *shadows* the previous binding + let shadowed_binding = 2; + println!("shadowed in outer block: {}", shadowed_binding); +} +``` [variable-shadow]: https://en.wikipedia.org/wiki/Variable_shadowing diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 7b0280d5b7..bed10ca16d 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -44,13 +44,13 @@ incremental builds the default is 256 which allows caching to be more granular. ## control-flow-guard -This flag controls whether LLVM enables the Windows [Control Flow -Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) -platform security feature. This flag is currently ignored for non-Windows targets. +This flag controls whether LLVM enables the Windows [Control Flow +Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) +platform security feature. This flag is currently ignored for non-Windows targets. It takes one of the following values: * `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard. -* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this +* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this should only be used for testing purposes as it does not provide security enforcement). * `n`, `no`, `off`: do not enable Control Flow Guard (the default). @@ -200,6 +200,18 @@ the following values: An example of when this flag might be useful is when trying to construct code coverage metrics. +## link-self-contained + +On targets that support it this flag controls whether the linker will use libraries and objects +shipped with Rust instead or those in the system. +It takes one of the following values: + +* no value: rustc will use heuristic to disable self-contained mode if system has necessary tools. +* `y`, `yes`, `on`: use only libraries/objects shipped with Rust. +* `n`, `no`, or `off`: rely on the user or the linker to provide non-Rust libraries/objects. + +This allows overriding cases when detection fails or user wants to use shipped libraries. + ## linker This flag controls which linker `rustc` invokes to link your code. It takes a diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index c0b14352b7..18f1be6a1f 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -89,6 +89,28 @@ rustc -Clinker-plugin-lto="/path/to/LLVMgold.so" -L. -Copt-level=2 ./main.rs ## Toolchain Compatibility + + In order for this kind of LTO to work, the LLVM linker plugin must be able to handle the LLVM bitcode produced by both `rustc` and `clang`. @@ -100,17 +122,20 @@ LLVM. However, the approximation is usually reliable. The following table shows known good combinations of toolchain versions. -| | Clang 7 | Clang 8 | Clang 9 | -|-----------|-----------|-----------|-----------| -| Rust 1.34 | ✗ | ✓ | ✗ | -| Rust 1.35 | ✗ | ✓ | ✗ | -| Rust 1.36 | ✗ | ✓ | ✗ | -| Rust 1.37 | ✗ | ✓ | ✗ | -| Rust 1.38 | ✗ | ✗ | ✓ | -| Rust 1.39 | ✗ | ✗ | ✓ | -| Rust 1.40 | ✗ | ✗ | ✓ | -| Rust 1.41 | ✗ | ✗ | ✓ | -| Rust 1.42 | ✗ | ✗ | ✓ | -| Rust 1.43 | ✗ | ✗ | ✓ | +| Rust Version | Clang Version | +|--------------|---------------| +| Rust 1.34 | Clang 8 | +| Rust 1.35 | Clang 8 | +| Rust 1.36 | Clang 8 | +| Rust 1.37 | Clang 8 | +| Rust 1.38 | Clang 9 | +| Rust 1.39 | Clang 9 | +| Rust 1.40 | Clang 9 | +| Rust 1.41 | Clang 9 | +| Rust 1.42 | Clang 9 | +| Rust 1.43 | Clang 9 | +| Rust 1.44 | Clang 9 | +| Rust 1.45 | Clang 10 | +| Rust 1.46 | Clang 10 | Note that the compatibility policy for this feature might change in the future. diff --git a/src/doc/rustc/src/lints/groups.md b/src/doc/rustc/src/lints/groups.md index 049e59b651..44cf42ff0d 100644 --- a/src/doc/rustc/src/lints/groups.md +++ b/src/doc/rustc/src/lints/groups.md @@ -14,14 +14,7 @@ $ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals Here's a list of each lint group, and the lints that they are made up of: -| group | description | lints | -|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| nonstandard-style | Violation of standard naming conventions | non-camel-case-types, non-snake-case, non-upper-case-globals | -| warnings | all lints that would be issuing warnings | all lints that would be issuing warnings | -| edition-2018 | Lints that will be turned into errors in Rust 2018 | tyvar-behind-raw-pointer | -| rust-2018-idioms | Lints to nudge you toward idiomatic features of Rust 2018 | bare-trait-object, unreachable-pub | -| unused | These lints detect things being declared but not used | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens | -| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision | +{{groups-table}} Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`. diff --git a/src/doc/rustc/src/lints/index.md b/src/doc/rustc/src/lints/index.md index 9010d436eb..029c9edc1b 100644 --- a/src/doc/rustc/src/lints/index.md +++ b/src/doc/rustc/src/lints/index.md @@ -26,3 +26,35 @@ warning: unused variable: `x` This is the `unused_variables` lint, and it tells you that you've introduced a variable that you don't use in your code. That's not *wrong*, so it's not an error, but it might be a bug, so you get a warning. + +## Future-incompatible lints + +Sometimes the compiler needs to be changed to fix an issue that can cause +existing code to stop compiling. "Future-incompatible" lints are issued in +these cases to give users of Rust a smooth transition to the new behavior. +Initially, the compiler will continue to accept the problematic code and issue +a warning. The warning has a description of the problem, a notice that this +will become an error in the future, and a link to a tracking issue that +provides detailed information and an opportunity for feedback. This gives +users some time to fix the code to accommodate the change. After some time, +the warning may become an error. + +The following is an example of what a future-incompatible looks like: + +```text +warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> lint_example.rs:11:13 + | +11 | let y = &x.data.0; + | ^^^^^^^^^ + | + = note: `#[warn(safe_packed_borrows)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior +``` + +For more information about the process and policy of future-incompatible +changes, see [RFC 1589]. + +[RFC 1589]: https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md index d3dfc3197e..95dd60bebf 100644 --- a/src/doc/rustc/src/lints/listing/allowed-by-default.md +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -1,453 +1,3 @@ # Allowed-by-default lints -These lints are all set to the 'allow' level by default. As such, they won't show up -unless you set them to a higher lint level with a flag or attribute. - -## anonymous-parameters - -This lint detects anonymous parameters. Some example code that triggers this lint: - -```rust -trait Foo { - fn foo(usize); -} -``` - -When set to 'deny', this will produce: - -```text -error: use of deprecated anonymous parameter - --> src/lib.rs:5:11 - | -5 | fn foo(usize); - | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41686 -``` - -This syntax is mostly a historical accident, and can be worked around quite -easily: - -```rust -trait Foo { - fn foo(_: usize); -} -``` - -## bare-trait-object - -This lint suggests using `dyn Trait` for trait objects. Some example code -that triggers this lint: - -```rust -#![feature(dyn_trait)] - -trait Trait { } - -fn takes_trait_object(_: Box) { -} -``` - -When set to 'deny', this will produce: - -```text -error: trait objects without an explicit `dyn` are deprecated - --> src/lib.rs:7:30 - | -7 | fn takes_trait_object(_: Box) { - | ^^^^^ help: use `dyn`: `dyn Trait` - | -``` - -To fix it, do as the help message suggests: - -```rust -#![feature(dyn_trait)] -#![deny(bare_trait_objects)] - -trait Trait { } - -fn takes_trait_object(_: Box) { -} -``` - -## box-pointers - -This lints use of the Box type. Some example code that triggers this lint: - -```rust -struct Foo { - x: Box, -} -``` - -When set to 'deny', this will produce: - -```text -error: type uses owned (Box type) pointers: std::boxed::Box - --> src/lib.rs:6:5 - | -6 | x: Box //~ ERROR type uses owned - | ^^^^^^^^^^^^^ - | -``` - -This lint is mostly historical, and not particularly useful. `Box` used to -be built into the language, and the only way to do heap allocation. Today's -Rust can call into other allocators, etc. - -## elided-lifetime-in-path - -This lint detects the use of hidden lifetime parameters. Some example code -that triggers this lint: - -```rust -struct Foo<'a> { - x: &'a u32 -} - -fn foo(x: &Foo) { -} -``` - -When set to 'deny', this will produce: - -```text -error: hidden lifetime parameters are deprecated, try `Foo<'_>` - --> src/lib.rs:5:12 - | -5 | fn foo(x: &Foo) { - | ^^^ - | -``` - -Lifetime elision elides this lifetime, but that is being deprecated. - -## missing-copy-implementations - -This lint detects potentially-forgotten implementations of `Copy`. Some -example code that triggers this lint: - -```rust -pub struct Foo { - pub field: i32 -} -``` - -When set to 'deny', this will produce: - -```text -error: type could implement `Copy`; consider adding `impl Copy` - --> src/main.rs:3:1 - | -3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy` -4 | | pub field: i32 -5 | | } - | |_^ - | -``` - -You can fix the lint by deriving `Copy`. - -This lint is set to 'allow' because this code isn't bad; it's common to write -newtypes like this specifically so that a `Copy` type is no longer `Copy`. - -## missing-debug-implementations - -This lint detects missing implementations of `fmt::Debug`. Some example code -that triggers this lint: - -```rust -pub struct Foo; -``` - -When set to 'deny', this will produce: - -```text -error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation - --> src/main.rs:3:1 - | -3 | pub struct Foo; - | ^^^^^^^^^^^^^^^ - | -``` - -You can fix the lint by deriving `Debug`. - -## missing-docs - -This lint detects missing documentation for public items. Some example code -that triggers this lint: - -```rust -pub fn foo() {} -``` - -When set to 'deny', this will produce: - -```text -error: missing documentation for crate - --> src/main.rs:1:1 - | -1 | / #![deny(missing_docs)] -2 | | -3 | | pub fn foo() {} -4 | | -5 | | fn main() {} - | |____________^ - | - -error: missing documentation for a function - --> src/main.rs:3:1 - | -3 | pub fn foo() {} - | ^^^^^^^^^^^^ - -``` - -To fix the lint, add documentation to all items. - -## single-use-lifetimes - -This lint detects lifetimes that are only used once. Some example code that -triggers this lint: - -```rust -struct Foo<'x> { - x: &'x u32 -} -``` - -When set to 'deny', this will produce: - -```text -error: lifetime name `'x` only used once - --> src/main.rs:3:12 - | -3 | struct Foo<'x> { - | ^^ - | -``` - -## trivial-casts - -This lint detects trivial casts which could be removed. Some example code -that triggers this lint: - -```rust -let x: &u32 = &42; -let _ = x as *const u32; -``` - -When set to 'deny', this will produce: - -```text -error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable - --> src/main.rs:5:13 - | -5 | let _ = x as *const u32; - | ^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> src/main.rs:1:9 - | -1 | #![deny(trivial_casts)] - | ^^^^^^^^^^^^^ -``` - -## trivial-numeric-casts - -This lint detects trivial casts of numeric types which could be removed. Some -example code that triggers this lint: - -```rust -let x = 42i32 as i32; -``` - -When set to 'deny', this will produce: - -```text -error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable - --> src/main.rs:4:13 - | -4 | let x = 42i32 as i32; - | ^^^^^^^^^^^^ - | -``` - -## unreachable-pub - -This lint triggers for `pub` items not reachable from the crate root. Some -example code that triggers this lint: - -```rust -mod foo { - pub mod bar { - - } -} -``` - -When set to 'deny', this will produce: - -```text -error: unreachable `pub` item - --> src/main.rs:4:5 - | -4 | pub mod bar { - | ---^^^^^^^^ - | | - | help: consider restricting its visibility: `pub(crate)` - | -``` - -## unsafe-code - -This lint catches usage of `unsafe` code. Some example code that triggers this lint: - -```rust -fn main() { - unsafe { - - } -} -``` - -When set to 'deny', this will produce: - -```text -error: usage of an `unsafe` block - --> src/main.rs:4:5 - | -4 | / unsafe { -5 | | -6 | | } - | |_____^ - | -``` - -## unstable-features - -This lint is deprecated and no longer used. - -## unused-extern-crates - -This lint guards against `extern crate` items that are never used. Some -example code that triggers this lint: - -```rust,ignore -extern crate semver; -``` - -When set to 'deny', this will produce: - -```text -error: unused extern crate - --> src/main.rs:3:1 - | -3 | extern crate semver; - | ^^^^^^^^^^^^^^^^^^^^ - | -``` - -## unused-import-braces - -This lint catches unnecessary braces around an imported item. Some example -code that triggers this lint: - -```rust -use test::{A}; - -pub mod test { - pub struct A; -} -# fn main() {} -``` - -When set to 'deny', this will produce: - -```text -error: braces around A is unnecessary - --> src/main.rs:3:1 - | -3 | use test::{A}; - | ^^^^^^^^^^^^^^ - | -``` - -To fix it, `use test::A;` - -## unused-qualifications - -This lint detects unnecessarily qualified names. Some example code that triggers this lint: - -```rust -mod foo { - pub fn bar() {} -} - -fn main() { - use foo::bar; - foo::bar(); -} -``` - -When set to 'deny', this will produce: - -```text -error: unnecessary qualification - --> src/main.rs:9:5 - | -9 | foo::bar(); - | ^^^^^^^^ - | -``` - -You can call `bar()` directly, without the `foo::`. - -## unused-results - -This lint checks for the unused result of an expression in a statement. Some -example code that triggers this lint: - -```rust,no_run -fn foo() -> T { panic!() } - -fn main() { - foo::(); -} -``` - -When set to 'deny', this will produce: - -```text -error: unused result - --> src/main.rs:6:5 - | -6 | foo::(); - | ^^^^^^^^^^^^^^^ - | -``` - -## variant-size-differences - -This lint detects enums with widely varying variant sizes. Some example code that triggers this lint: - -```rust -enum En { - V0(u8), - VBig([u8; 1024]), -} -``` - -When set to 'deny', this will produce: - -```text -error: enum variant is more than three times larger (1024 bytes) than the next largest - --> src/main.rs:5:5 - | -5 | VBig([u8; 1024]), //~ ERROR variant is more than three times larger - | ^^^^^^^^^^^^^^^^ - | -``` +This file is auto-generated by the lint-docs script. diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md index dc5a9e44ac..3c1452d646 100644 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -1,212 +1,3 @@ # Deny-by-default lints -These lints are all set to the 'deny' level by default. - -## exceeding-bitshifts - -This lint detects that a shift exceeds the type's number of bits. Some -example code that triggers this lint: - -```rust,ignore -1_i32 << 32; -``` - -This will produce: - -```text -error: bitshift exceeds the type's number of bits - --> src/main.rs:2:5 - | -2 | 1_i32 << 32; - | ^^^^^^^^^^^ - | -``` - -## invalid-type-param-default - -This lint detects type parameter default erroneously allowed in invalid location. Some -example code that triggers this lint: - -```rust,ignore -fn foo(t: T) {} -``` - -This will produce: - -```text -error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions. - --> src/main.rs:4:8 - | -4 | fn foo(t: T) {} - | ^ - | - = note: `#[deny(invalid_type_param_default)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #36887 -``` - -## missing-fragment-specifier - -The missing_fragment_specifier warning is issued when an unused pattern in a -`macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not -followed by a fragment specifier (e.g. `:expr`). - -This warning can always be fixed by removing the unused pattern in the -`macro_rules!` macro definition. - -## mutable-transmutes - -This lint catches transmuting from `&T` to `&mut T` because it is undefined -behavior. Some example code that triggers this lint: - -```rust,ignore -unsafe { - let y = std::mem::transmute::<&i32, &mut i32>(&5); -} -``` - -This will produce: - -```text -error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell - --> src/main.rs:3:17 - | -3 | let y = std::mem::transmute::<&i32, &mut i32>(&5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -``` - - -## no-mangle-const-items - -This lint detects any `const` items with the `#[no_mangle]` attribute. -Constants do not have their symbols exported, and therefore, this probably -means you meant to use a `static`, not a `const`. Some example code that -triggers this lint: - -```rust,ignore -#[no_mangle] -const FOO: i32 = 5; -``` - -This will produce: - -```text -error: const items should never be `#[no_mangle]` - --> src/main.rs:3:1 - | -3 | const FOO: i32 = 5; - | -----^^^^^^^^^^^^^^ - | | - | help: try a static value: `pub static` - | -``` - -## overflowing-literals - -This lint detects literal out of range for its type. Some -example code that triggers this lint: - -```rust,compile_fail -let x: u8 = 1000; -``` - -This will produce: - -```text -error: literal out of range for u8 - --> src/main.rs:2:17 - | -2 | let x: u8 = 1000; - | ^^^^ - | -``` - -## patterns-in-fns-without-body - -This lint detects patterns in functions without body were that were -previously erroneously allowed. Some example code that triggers this lint: - -```rust,compile_fail -trait Trait { - fn foo(mut arg: u8); -} -``` - -This will produce: - -```text -warning: patterns aren't allowed in methods without bodies - --> src/main.rs:2:12 - | -2 | fn foo(mut arg: u8); - | ^^^^^^^ - | - = note: `#[warn(patterns_in_fns_without_body)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #35203 -``` - -To fix this, remove the pattern; it can be used in the implementation without -being used in the definition. That is: - -```rust -trait Trait { - fn foo(arg: u8); -} - -impl Trait for i32 { - fn foo(mut arg: u8) { - - } -} -``` - -## pub-use-of-private-extern-crate - -This lint detects a specific situation of re-exporting a private `extern crate`; - -## unknown-crate-types - -This lint detects an unknown crate type found in a `#[crate_type]` directive. Some -example code that triggers this lint: - -```rust,ignore -#![crate_type="lol"] -``` - -This will produce: - -```text -error: invalid `crate_type` value - --> src/lib.rs:1:1 - | -1 | #![crate_type="lol"] - | ^^^^^^^^^^^^^^^^^^^^ - | -``` - -## const-err - -This lint detects expressions that will always panic at runtime and would be an -error in a `const` context. - -```rust,ignore -let _ = [0; 4][4]; -``` - -This will produce: - -```text -error: index out of bounds: the len is 4 but the index is 4 - --> src/lib.rs:1:9 - | -1 | let _ = [0; 4][4]; - | ^^^^^^^^^ - | -``` - -## order-dependent-trait-objects - -This lint detects a trait coherency violation that would allow creating two -trait impls for the same dynamic trait object involving marker traits. +This file is auto-generated by the lint-docs script. diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md index 386f6008d0..eebc022a82 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -1,903 +1,3 @@ # Warn-by-default lints -These lints are all set to the 'warn' level by default. - -## const-err - -This lint detects an erroneous expression while doing constant evaluation. Some -example code that triggers this lint: - -```rust,ignore -let b = 200u8 + 200u8; -``` - -This will produce: - -```text -warning: attempt to add with overflow - --> src/main.rs:2:9 - | -2 | let b = 200u8 + 200u8; - | ^^^^^^^^^^^^^ - | -``` - -## dead-code - -This lint detects unused, unexported items. Some -example code that triggers this lint: - -```rust -fn foo() {} -``` - -This will produce: - -```text -warning: function is never used: `foo` - --> src/lib.rs:2:1 - | -2 | fn foo() {} - | ^^^^^^^^ - | -``` - -## deprecated - -This lint detects use of deprecated items. Some -example code that triggers this lint: - -```rust -#[deprecated] -fn foo() {} - -fn bar() { - foo(); -} -``` - -This will produce: - -```text -warning: use of deprecated item 'foo' - --> src/lib.rs:7:5 - | -7 | foo(); - | ^^^ - | -``` - -## illegal-floating-point-literal-pattern - -This lint detects floating-point literals used in patterns. Some example code -that triggers this lint: - -```rust -let x = 42.0; - -match x { - 5.0 => {}, - _ => {}, -} -``` - -This will produce: - -```text -warning: floating-point literals cannot be used in patterns - --> src/main.rs:4:9 - | -4 | 5.0 => {}, - | ^^^ - | - = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 -``` - -## improper-ctypes - -This lint detects proper use of libc types in foreign modules. Some -example code that triggers this lint: - -```rust -extern "C" { - static STATIC: String; -} -``` - -This will produce: - -```text -warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a `#[repr(C)]` attribute to the type - --> src/main.rs:2:20 - | -2 | static STATIC: String; - | ^^^^^^ - | -``` - -## late-bound-lifetime-arguments - -This lint detects generic lifetime arguments in path segments with -late bound lifetime parameters. Some example code that triggers this lint: - -```rust -struct S; - -impl S { - fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} -} - -fn main() { - S.late::<'static>(&0, &0); -} -``` - -This will produce: - -```text -warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> src/main.rs:8:14 - | -4 | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} - | -- the late bound lifetime parameter is introduced here -... -8 | S.late::<'static>(&0, &0); - | ^^^^^^^ - | - = note: `#[warn(late_bound_lifetime_arguments)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #42868 -``` - -## non-camel-case-types - -This lint detects types, variants, traits and type parameters that don't have -camel case names. Some example code that triggers this lint: - -```rust -struct s; -``` - -This will produce: - -```text -warning: type `s` should have a camel case name such as `S` - --> src/main.rs:1:1 - | -1 | struct s; - | ^^^^^^^^^ - | -``` - -## non-shorthand-field-patterns - -This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some -example code that triggers this lint: - -```rust -struct Point { - x: i32, - y: i32, -} - - -fn main() { - let p = Point { - x: 5, - y: 5, - }; - - match p { - Point { x: x, y: y } => (), - } -} -``` - -This will produce: - -```text -warning: the `x:` in this pattern is redundant - --> src/main.rs:14:17 - | -14 | Point { x: x, y: y } => (), - | --^^ - | | - | help: remove this - | - -warning: the `y:` in this pattern is redundant - --> src/main.rs:14:23 - | -14 | Point { x: x, y: y } => (), - | --^^ - | | - | help: remove this - -``` - -## non-snake-case - -This lint detects variables, methods, functions, lifetime parameters and -modules that don't have snake case names. Some example code that triggers -this lint: - -```rust -let X = 5; -``` - -This will produce: - -```text -warning: variable `X` should have a snake case name such as `x` - --> src/main.rs:2:9 - | -2 | let X = 5; - | ^ - | -``` - -## non-upper-case-globals - -This lint detects static constants that don't have uppercase identifiers. -Some example code that triggers this lint: - -```rust -static x: i32 = 5; -``` - -This will produce: - -```text -warning: static variable `x` should have an upper case name such as `X` - --> src/main.rs:1:1 - | -1 | static x: i32 = 5; - | ^^^^^^^^^^^^^^^^^^ - | -``` - -## no-mangle-generic-items - -This lint detects generic items must be mangled. Some -example code that triggers this lint: - -```rust -#[no_mangle] -fn foo(t: T) { - -} -``` - -This will produce: - -```text -warning: functions generic over types must be mangled - --> src/main.rs:2:1 - | -1 | #[no_mangle] - | ------------ help: remove this attribute -2 | / fn foo(t: T) { -3 | | -4 | | } - | |_^ - | -``` - -## path-statements - -This lint detects path statements with no effect. Some example code that -triggers this lint: - -```rust -let x = 42; - -x; -``` - -This will produce: - -```text -warning: path statement with no effect - --> src/main.rs:3:5 - | -3 | x; - | ^^ - | -``` - -## private-in-public - -This lint detects private items in public interfaces not caught by the old implementation. Some -example code that triggers this lint: - -```rust,ignore -pub trait Trait { - type A; -} - -pub struct S; - -mod foo { - struct Z; - - impl ::Trait for ::S { - type A = Z; - } -} -# fn main() {} -``` - -This will produce: - -```text -error[E0446]: private type `foo::Z` in public interface - --> src/main.rs:11:9 - | -11 | type A = Z; - | ^^^^^^^^^^^ can't leak private type -``` - -## private-no-mangle-fns - -This lint detects functions marked `#[no_mangle]` that are also private. -Given that private functions aren't exposed publicly, and `#[no_mangle]` -controls the public symbol, this combination is erroneous. Some example code -that triggers this lint: - -```rust -#[no_mangle] -fn foo() {} -``` - -This will produce: - -```text -warning: function is marked `#[no_mangle]`, but not exported - --> src/main.rs:2:1 - | -2 | fn foo() {} - | -^^^^^^^^^^ - | | - | help: try making it public: `pub` - | -``` - -To fix this, either make it public or remove the `#[no_mangle]`. - -## private-no-mangle-statics - -This lint detects any statics marked `#[no_mangle]` that are private. -Given that private statics aren't exposed publicly, and `#[no_mangle]` -controls the public symbol, this combination is erroneous. Some example code -that triggers this lint: - -```rust -#[no_mangle] -static X: i32 = 4; -``` - -This will produce: - -```text -warning: static is marked `#[no_mangle]`, but not exported - --> src/main.rs:2:1 - | -2 | static X: i32 = 4; - | -^^^^^^^^^^^^^^^^^ - | | - | help: try making it public: `pub` - | -``` - -To fix this, either make it public or remove the `#[no_mangle]`. - -## renamed-and-removed-lints - -This lint detects lints that have been renamed or removed. Some -example code that triggers this lint: - -```rust -#![deny(raw_pointer_derive)] -``` - -This will produce: - -```text -warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok - --> src/main.rs:1:9 - | -1 | #![deny(raw_pointer_derive)] - | ^^^^^^^^^^^^^^^^^^ - | -``` - -To fix this, either remove the lint or use the new name. - -## safe-packed-borrows - -This lint detects borrowing a field in the interior of a packed structure -with alignment other than 1. Some example code that triggers this lint: - -```rust -#[repr(packed)] -pub struct Unaligned(pub T); - -pub struct Foo { - start: u8, - data: Unaligned, -} - -fn main() { - let x = Foo { start: 0, data: Unaligned(1) }; - let y = &x.data.0; -} -``` - -This will produce: - -```text -warning: borrow of packed field requires unsafe function or block (error E0133) - --> src/main.rs:11:13 - | -11 | let y = &x.data.0; - | ^^^^^^^^^ - | - = note: `#[warn(safe_packed_borrows)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 -``` - -## stable-features - -This lint detects a `#[feature]` attribute that's since been made stable. Some -example code that triggers this lint: - -```rust -#![feature(test_accepted_feature)] -``` - -This will produce: - -```text -warning: this feature has been stable since 1.0.0. Attribute no longer needed - --> src/main.rs:1:12 - | -1 | #![feature(test_accepted_feature)] - | ^^^^^^^^^^^^^^^^^^^^^ - | -``` - -To fix, simply remove the `#![feature]` attribute, as it's no longer needed. - -## type-alias-bounds - -This lint detects bounds in type aliases. These are not currently enforced. -Some example code that triggers this lint: - -```rust -#[allow(dead_code)] -type SendVec = Vec; -``` - -This will produce: - -```text -warning: bounds on generic parameters are not enforced in type aliases - --> src/lib.rs:2:17 - | -2 | type SendVec = Vec; - | ^^^^ - | - = note: `#[warn(type_alias_bounds)]` on by default - = help: the bound will not be checked when the type alias is used, and should be removed -``` - -## tyvar-behind-raw-pointer - -This lint detects raw pointer to an inference variable. Some -example code that triggers this lint: - -```rust -let data = std::ptr::null(); -let _ = &data as *const *const (); - -if data.is_null() {} -``` - -This will produce: - -```text -warning: type annotations needed - --> src/main.rs:4:13 - | -4 | if data.is_null() {} - | ^^^^^^^ - | - = note: `#[warn(tyvar_behind_raw_pointer)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! - = note: for more information, see issue #46906 -``` - -## unconditional-recursion - -This lint detects functions that cannot return without calling themselves. -Some example code that triggers this lint: - -```rust -fn foo() { - foo(); -} -``` - -This will produce: - -```text -warning: function cannot return without recursing - --> src/main.rs:1:1 - | -1 | fn foo() { - | ^^^^^^^^ cannot return without recursing -2 | foo(); - | ----- recursive call site - | -``` - -## unknown-lints - -This lint detects unrecognized lint attribute. Some -example code that triggers this lint: - -```rust,ignore -#[allow(not_a_real_lint)] -``` - -This will produce: - -```text -warning: unknown lint: `not_a_real_lint` - --> src/main.rs:1:10 - | -1 | #![allow(not_a_real_lint)] - | ^^^^^^^^^^^^^^^ - | -``` - -## unreachable-code - -This lint detects unreachable code paths. Some example code that -triggers this lint: - -```rust,no_run -panic!("we never go past here!"); - -let x = 5; -``` - -This will produce: - -```text -warning: unreachable statement - --> src/main.rs:4:5 - | -4 | let x = 5; - | ^^^^^^^^^^ - | -``` - -## unreachable-patterns - -This lint detects unreachable patterns. Some -example code that triggers this lint: - -```rust -let x = 5; -match x { - y => (), - 5 => (), -} -``` - -This will produce: - -```text -warning: unreachable pattern - --> src/main.rs:5:5 - | -5 | 5 => (), - | ^ - | -``` - -The `y` pattern will always match, so the five is impossible to reach. -Remember, match arms match in order, you probably wanted to put the `5` case -above the `y` case. - -## unstable-name-collision - -This lint detects that you've used a name that the standard library plans to -add in the future, which means that your code may fail to compile without -additional type annotations in the future. Either rename, or add those -annotations now. - -## unused-allocation - -This lint detects unnecessary allocations that can be eliminated. - -## unused-assignments - -This lint detects assignments that will never be read. Some -example code that triggers this lint: - -```rust -let mut x = 5; -x = 6; -``` - -This will produce: - -```text -warning: value assigned to `x` is never read - --> src/main.rs:4:5 - | -4 | x = 6; - | ^ - | -``` - -## unused-attributes - -This lint detects attributes that were not used by the compiler. Some -example code that triggers this lint: - -```rust -#![macro_export] -``` - -This will produce: - -```text -warning: unused attribute - --> src/main.rs:1:1 - | -1 | #![macro_export] - | ^^^^^^^^^^^^^^^^ - | -``` - -## unused-comparisons - -This lint detects comparisons made useless by limits of the types involved. Some -example code that triggers this lint: - -```rust -fn foo(x: u8) { - x >= 0; -} -``` - -This will produce: - -```text -warning: comparison is useless due to type limits - --> src/main.rs:6:5 - | -6 | x >= 0; - | ^^^^^^ - | -``` - -## unused-doc-comment - -This lint detects doc comments that aren't used by rustdoc. Some -example code that triggers this lint: - -```rust -/// docs for x -let x = 12; -``` - -This will produce: - -```text -warning: doc comment not used by rustdoc - --> src/main.rs:2:5 - | -2 | /// docs for x - | ^^^^^^^^^^^^^^ - | -``` - -## unused-features - -This lint detects unused or unknown features found in crate-level `#[feature]` directives. -To fix this, simply remove the feature flag. - -## unused-imports - -This lint detects imports that are never used. Some -example code that triggers this lint: - -```rust -use std::collections::HashMap; -``` - -This will produce: - -```text -warning: unused import: `std::collections::HashMap` - --> src/main.rs:1:5 - | -1 | use std::collections::HashMap; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -``` - -## unused-macros - -This lint detects macros that were not used. Some example code that -triggers this lint: - -```rust -macro_rules! unused { - () => {}; -} - -fn main() { -} -``` - -This will produce: - -```text -warning: unused macro definition - --> src/main.rs:1:1 - | -1 | / macro_rules! unused { -2 | | () => {}; -3 | | } - | |_^ - | -``` - -## unused-must-use - -This lint detects unused result of a type flagged as `#[must_use]`. Some -example code that triggers this lint: - -```rust -fn returns_result() -> Result<(), ()> { - Ok(()) -} - -fn main() { - returns_result(); -} -``` - -This will produce: - -```text -warning: unused `std::result::Result` that must be used - --> src/main.rs:6:5 - | -6 | returns_result(); - | ^^^^^^^^^^^^^^^^^ - | -``` - -## unused-mut - -This lint detects mut variables which don't need to be mutable. Some -example code that triggers this lint: - -```rust -let mut x = 5; -``` - -This will produce: - -```text -warning: variable does not need to be mutable - --> src/main.rs:2:9 - | -2 | let mut x = 5; - | ----^ - | | - | help: remove this `mut` - | -``` - -## unused-parens - -This lint detects `if`, `match`, `while` and `return` with parentheses; they -do not need them. Some example code that triggers this lint: - -```rust -if(true) {} -``` - -This will produce: - -```text -warning: unnecessary parentheses around `if` condition - --> src/main.rs:2:7 - | -2 | if(true) {} - | ^^^^^^ help: remove these parentheses - | -``` - -## unused-unsafe - -This lint detects unnecessary use of an `unsafe` block. Some -example code that triggers this lint: - -```rust -unsafe {} -``` - -This will produce: - -```text -warning: unnecessary `unsafe` block - --> src/main.rs:2:5 - | -2 | unsafe {} - | ^^^^^^ unnecessary `unsafe` block - | -``` - -## unused-variables - -This lint detects variables which are not used in any way. Some -example code that triggers this lint: - -```rust -let x = 5; -``` - -This will produce: - -```text -warning: unused variable: `x` - --> src/main.rs:2:9 - | -2 | let x = 5; - | ^ help: consider using `_x` instead - | -``` - -## warnings - -This lint is a bit special; by changing its level, you change every other warning -that would produce a warning to whatever value you'd like: - -```rust -#![deny(warnings)] -``` - -As such, you won't ever trigger this lint in your code directly. - -## while-true - -This lint detects `while true { }`. Some example code that triggers this -lint: - -```rust,no_run -while true { - -} -``` - -This will produce: - -```text -warning: denote infinite loops with `loop { ... }` - --> src/main.rs:2:5 - | -2 | while true { - | ^^^^^^^^^^ help: use `loop` - | -``` +This file is auto-generated by the lint-docs script. diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 2187485383..6c605f045e 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -57,12 +57,12 @@ Specifically, these platforms are required to have each of the following: target | std | host | notes -------|-----|------|------- -`aarch64-apple-ios` | ✓[^apple] | | ARM64 iOS +`aarch64-apple-ios` | ✓ | | ARM64 iOS `aarch64-fuchsia` | ✓ | | ARM64 Fuchsia `aarch64-linux-android` | ✓ | | ARM64 Android `aarch64-pc-windows-msvc` | ✓ | | ARM64 Windows MSVC `aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17) -`aarch64-unknown-linux-musl` | ✓ | | ARM64 Linux with MUSL +`aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL `aarch64-unknown-none` | * | | Bare ARM64, hardfloat `aarch64-unknown-none-softfloat` | * | | Bare ARM64, softfloat `arm-linux-androideabi` | ✓ | | ARMv7 Android @@ -118,11 +118,11 @@ target | std | host | notes `thumbv7neon-unknown-linux-gnueabihf` | ✓ | | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23) `thumbv8m.base-none-eabi` | * | | ARMv8-M Baseline `thumbv8m.main-none-eabi` | * | | ARMv8-M Mainline -`thumbv8m.main-none-eabihf` | * | | ARMv8-M Baseline, hardfloat +`thumbv8m.main-none-eabihf` | * | | ARMv8-M Mainline, hardfloat `wasm32-unknown-emscripten` | ✓ | | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | | WebAssembly `wasm32-wasi` | ✓ | | WebAssembly with WASI -`x86_64-apple-ios` | ✓[^apple] | | 64-bit x86 iOS +`x86_64-apple-ios` | ✓ | | 64-bit x86 iOS `x86_64-fortanix-unknown-sgx` | ✓ | | [Fortanix ABI] for 64-bit Intel SGX `x86_64-fuchsia` | ✓ | | 64-bit Fuchsia `x86_64-linux-android` | ✓ | | 64-bit x86 Android @@ -146,7 +146,7 @@ not available. target | std | host | notes -------|-----|------|------- `aarch64-apple-darwin` | ? | | ARM64 macOS -`aarch64-apple-tvos` | *[^apple] | | ARM64 tvOS +`aarch64-apple-tvos` | * | | ARM64 tvOS `aarch64-unknown-cloudabi` | ✓ | | ARM64 CloudABI `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ? | | @@ -158,16 +158,16 @@ target | std | host | notes `armv4t-unknown-linux-gnueabi` | ? | | `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD `armv6-unknown-netbsd-eabihf` | ? | | -`armv7-apple-ios` | ✓[^apple] | | ARMv7 iOS, Cortex-a8 +`armv7-apple-ios` | ✓ | | ARMv7 iOS, Cortex-a8 `armv7-unknown-cloudabi-eabihf` | ✓ | | ARMv7 CloudABI, hardfloat `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD `armv7-unknown-netbsd-eabihf` | ? | | `armv7-wrs-vxworks-eabihf` | ? | | `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat -`armv7s-apple-ios` | ✓[^apple] | | -`avr-unknown-unknown` | ? | | AVR +`armv7s-apple-ios` | ✓ | | +`avr-unknown-gnu-atmega328` | ✗ | | AVR. Requires `-Z build-std=core` `hexagon-unknown-linux-musl` | ? | | -`i386-apple-ios` | ✓[^apple] | | 32-bit x86 iOS +`i386-apple-ios` | ✓ | | 32-bit x86 iOS `i686-apple-darwin` | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) `i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support `i686-unknown-cloudabi` | ✓ | | 32-bit CloudABI @@ -195,6 +195,7 @@ target | std | host | notes `powerpc64-unknown-linux-musl` | ? | | `powerpc64-wrs-vxworks` | ? | | `powerpc64le-unknown-linux-musl` | ? | | +`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 `sparc64-unknown-openbsd` | ? | | @@ -202,8 +203,8 @@ target | std | host | notes `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL `thumbv4t-none-eabi` | * | | ARMv4T T32 -`x86_64-apple-ios-macabi` | ✓[^apple] | | Apple Catalyst -`x86_64-apple-tvos` | *[^apple] | | x86 64-bit tvOS +`x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst +`x86_64-apple-tvos` | * | | x86 64-bit tvOS `x86_64-linux-kernel` | * | | Linux kernel modules `x86_64-pc-solaris` | ? | | `x86_64-pc-windows-msvc` | ✓ | | 64-bit Windows XP support @@ -220,4 +221,3 @@ target | std | host | notes `x86_64-wrs-vxworks` | ? | | [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets -[^apple]: These targets are only available on macOS. diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md index f982863e67..93454b4f90 100644 --- a/src/doc/rustdoc/src/SUMMARY.md +++ b/src/doc/rustdoc/src/SUMMARY.md @@ -5,6 +5,7 @@ - [Command-line arguments](command-line-arguments.md) - [The `#[doc]` attribute](the-doc-attribute.md) - [Documentation tests](documentation-tests.md) +- [Linking to items by name](linking-to-items-by-name.md) - [Lints](lints.md) - [Passes](passes.md) - [Advanced Features](advanced-features.md) diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 7c12d23e64..8c7926f116 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -32,3 +32,19 @@ pub struct UnixToken; Here, the respective tokens can only be used by dependent crates on their respective platforms, but they will both appear in documentation. + +## Add aliases for an item in documentation search + +This feature allows you to add alias(es) to an item when using the `rustdoc` search through the +`doc(alias)` attribute. Example: + +```rust,no_run +#[doc(alias = "x")] +#[doc(alias = "big")] +pub struct BigX; +``` + +Then, when looking for it through the `rustdoc` search, if you enter "x" or +"big", search will show the `BigX` struct first. + +There are some limitations on the doc alias names though: you can't use `"` or whitespace. diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md new file mode 100644 index 0000000000..5e46ef583f --- /dev/null +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -0,0 +1,65 @@ +# Linking to items by name + +Rustdoc is capable of directly linking to other rustdoc pages in Markdown documentation using the path of item as a link. + +For example, in the following code all of the links will link to the rustdoc page for `Bar`: + +```rust +/// This struct is not [Bar] +pub struct Foo1; + +/// This struct is also not [bar](Bar) +pub struct Foo2; + +/// This struct is also not [bar][b] +/// +/// [b]: Bar +pub struct Foo3; + +/// This struct is also not [`Bar`] +pub struct Foo4; + +pub struct Bar; +``` + +You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. Backticks around the link will be stripped. + +```rust,edition2018 +use std::sync::mpsc::Receiver; + +/// This is an version of [`Receiver`], with support for [`std::future`]. +/// +/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`]. +pub struct AsyncReceiver { + sender: Receiver +} + +impl AsyncReceiver { + pub async fn recv() -> T { + unimplemented!() + } +} +``` + +You can also link to sections using URL fragment specifiers: + +```rust +/// This is a special implementation of [positional parameters] +/// +/// [positional parameters]: std::fmt#formatting-parameters +struct MySpecialFormatter; +``` + +Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: + +```rust +/// See also: [`Foo`](struct@Foo) +struct Bar; + +/// This is different from [`Foo`](fn@Foo) +struct Foo {} + +fn Foo() {} +``` + +Note: Because of how `macro_rules` macros are scoped in Rust, the intra-doc links of a `macro_rules` macro will be resolved relative to the crate root, as opposed to the module it is defined in. diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index d1d6bc1c1f..3e632a0644 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -13,20 +13,95 @@ Here is the list of the lints provided by `rustdoc`: ## broken_intra_doc_links -This lint **warns by default** and is **nightly-only**. This lint detects when -an intra-doc link fails to get resolved. For example: +This lint **warns by default**. This lint detects when an [intra-doc link] fails to get resolved. For example: + + [intra-doc link]: linking-to-items-by-name.html ```rust -/// I want to link to [`Inexistent`] but it doesn't exist! +/// I want to link to [`Nonexistent`] but it doesn't exist! pub fn foo() {} ``` You'll get a warning saying: ```text -error: `[`Inexistent`]` cannot be resolved, ignoring it... +warning: unresolved link to `Nonexistent` + --> test.rs:1:24 + | +1 | /// I want to link to [`Nonexistent`] but it doesn't exist! + | ^^^^^^^^^^^^^ no item named `Nonexistent` in `test` +``` + +It will also warn when there is an ambiguity and suggest how to disambiguate: + +```rust +/// [`Foo`] +pub fn function() {} + +pub enum Foo {} + +pub fn Foo(){} +``` + +```text +warning: `Foo` is both an enum and a function + --> test.rs:1:6 + | +1 | /// [`Foo`] + | ^^^^^ ambiguous link + | + = note: `#[warn(broken_intra_doc_links)]` on by default +help: to link to the enum, prefix with the item type + | +1 | /// [`enum@Foo`] + | ^^^^^^^^^^ +help: to link to the function, add parentheses + | +1 | /// [`Foo()`] + | ^^^^^^^ + +``` + +## private_intra_doc_links + +This lint **warns by default**. This lint detects when [intra-doc links] from public to private items. +For example: + +```rust +/// [private] +pub fn public() {} +fn private() {} +``` + +This gives a warning that the link will be broken when it appears in your documentation: + +```text +warning: public documentation for `public` links to private item `private` + --> priv.rs:1:6 + | +1 | /// [private] + | ^^^^^^^ this item is private + | + = note: `#[warn(private_intra_doc_links)]` on by default + = note: this link will resolve properly if you pass `--document-private-items` +``` + +Note that this has different behavior depending on whether you pass `--document-private-items` or not! +If you document private items, then it will still generate a link, despite the warning: + +```text +warning: public documentation for `public` links to private item `private` + --> priv.rs:1:6 + | +1 | /// [private] + | ^^^^^^^ this item is private + | + = note: `#[warn(private_intra_doc_links)]` on by default + = note: this link resolves only because you passed `--document-private-items`, but will break without ``` +[intra-doc links]: linking-to-items-by-name.html + ## missing_docs This lint is **allowed by default**. It detects items missing documentation. @@ -49,9 +124,33 @@ warning: missing documentation for a function | ^^^^^^^^^^^^^^^^^^^^^ ``` +## missing_crate_level_docs + +This lint is **allowed by default**. It detects if there is no documentation +at the crate root. For example: + +```rust +#![warn(missing_crate_level_docs)] +``` + +This will generate the following warning: + +```text +warning: no documentation found for this crate's top-level module + | + = help: The following guide may be of use: + https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html +``` + +This is currently "allow" by default, but it is intended to make this a +warning in the future. This is intended as a means to introduce new users on +*how* to document their crate by pointing them to some instructions on how to +get started, without providing overwhelming warnings like `missing_docs` +might. + ## missing_doc_code_examples -This lint is **allowed by default**. It detects when a documentation block +This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block is missing a code example. For example: ```rust @@ -117,3 +216,37 @@ warning: Documentation test in private item 8 | | /// ``` | |___________^ ``` + +## invalid_codeblock_attributes + +This lint **warns by default**. It detects code block attributes in +documentation examples that have potentially mis-typed values. For example: + +```rust +/// Example. +/// +/// ```should-panic +/// assert_eq!(1, 2); +/// ``` +pub fn foo() {} +``` + +Which will give: + +```text +warning: unknown attribute `should-panic`. Did you mean `should_panic`? + --> src/lib.rs:1:1 + | +1 | / /// Example. +2 | | /// +3 | | /// ```should-panic +4 | | /// assert_eq!(1, 2); +5 | | /// ``` + | |_______^ + | + = note: `#[warn(invalid_codeblock_attributes)]` on by default + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running +``` + +In the example above, the correct form is `should_panic`. This helps detect +typo mistakes for some common attributes. diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 2f49fc8a41..e4d8818b56 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -38,63 +38,6 @@ future. Attempting to use these error numbers on stable will result in the code sample being interpreted as plain text. -### Linking to items by name - -Rustdoc is capable of directly linking to other rustdoc pages in Markdown documentation using the path of item as a link. - -For example, in the following code all of the links will link to the rustdoc page for `Bar`: - -```rust -/// This struct is not [Bar] -pub struct Foo1; - -/// This struct is also not [bar](Bar) -pub struct Foo2; - -/// This struct is also not [bar][b] -/// -/// [b]: Bar -pub struct Foo3; - -/// This struct is also not [`Bar`] -pub struct Foo4; - -pub struct Bar; -``` - -You can refer to anything in scope, and use paths, including `Self`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. - -```rust,edition2018 -use std::sync::mpsc::Receiver; - -/// This is an version of [`Receiver`], with support for [`std::future`]. -/// -/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`]. -pub struct AsyncReceiver { - sender: Receiver -} - -impl AsyncReceiver { - pub async fn recv() -> T { - unimplemented!() - } -} -``` - -Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: - -```rust -/// See also: [`Foo`](struct@Foo) -struct Bar; - -/// This is different from [`Foo`](fn@Foo) -struct Foo {} - -fn Foo() {} -``` - -Note: Because of how `macro_rules` macros are scoped in Rust, the intra-doc links of a `macro_rules` macro will be resolved relative to the crate root, as opposed to the module it is defined in. - ## Extensions to the `#[doc]` attribute These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler @@ -207,22 +150,6 @@ issue][issue-include]. [unstable-include]: ../unstable-book/language-features/external-doc.html [issue-include]: https://github.com/rust-lang/rust/issues/44732 -### Add aliases for an item in documentation search - -This feature allows you to add alias(es) to an item when using the `rustdoc` search through the -`doc(alias)` attribute. Example: - -```rust,no_run -#![feature(doc_alias)] - -#[doc(alias = "x")] -#[doc(alias = "big")] -pub struct BigX; -``` - -Then, when looking for it through the `rustdoc` search, if you enter "x" or -"big", search will show the `BigX` struct first. - ## Unstable command-line arguments These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index adcebc832b..7a38c96d71 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -93,6 +93,29 @@ passes `-L`, a flag that helps rustdoc find the dependencies your code relies on. If our project used dependencies, we'd get documentation for them as well! +## Outer and inner documentation + +The `///` syntax is used to document the item present after it. +That's why it is called an outer documentation. +There is another syntax: `//!`, which is used to document the +item it is present inside. It is called an inner documentation. +It is often used when documenting the entire crate, +because nothing comes before it: it is the root of the crate. +So in order to document an entire crate, you need to use `//!` syntax. +For example: + +``` rust +//! This is my first rust crate +``` + +When used in the crate root, it documents the item it is inside, +which is the crate itself. + +For more information about the `//!` syntax, see [the Book]. + +[the Book]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#commenting-contained-items + + ## Using standalone Markdown files `rustdoc` can also generate HTML from standalone Markdown files. Let's diff --git a/src/doc/unstable-book/src/compiler-flags/tls-model.md b/src/doc/unstable-book/src/compiler-flags/tls-model.md index 0aefaa7fb0..cd625f3fd0 100644 --- a/src/doc/unstable-book/src/compiler-flags/tls-model.md +++ b/src/doc/unstable-book/src/compiler-flags/tls-model.md @@ -22,4 +22,4 @@ The TLS data must not be in a library loaded after startup (via `dlopen`). but not in a shared library, and is accessed only from that executable. `rustc` and LLVM may use a more optimized model than specified if they know that we are producing -and executable rather than a library, or that the `static` item is private enough. +an executable rather than a library, or that the `static` item is private enough. diff --git a/src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md b/src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md new file mode 100644 index 0000000000..8e46e227c2 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md @@ -0,0 +1,8 @@ +# `unsound-mir-opts` + +-------------------- + +The `-Zunsound-mir-opts` compiler flag enables [MIR optimization passes] which can cause unsound behavior. +This flag should only be used by MIR optimization tests in the rustc test suite. + +[MIR optimization passes]: https://rustc-dev-guide.rust-lang.org/mir/optimizations.html diff --git a/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md new file mode 100644 index 0000000000..338fbc4b2b --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md @@ -0,0 +1,81 @@ +# `cmse_nonsecure_entry` + +The tracking issue for this feature is: [#75835] + +[#75835]: https://github.com/rust-lang/rust/issues/75835 + +------------------------ + +The [TrustZone-M +feature](https://developer.arm.com/documentation/100690/latest/) is available +for targets with the Armv8-M architecture profile (`thumbv8m` in their target +name). +LLVM, the Rust compiler and the linker are providing +[support](https://developer.arm.com/documentation/ecm0359818/latest/) for the +TrustZone-M feature. + +One of the things provided, with this unstable feature, is the +`cmse_nonsecure_entry` attribute. This attribute marks a Secure function as an +entry function (see [section +5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details). +With this attribute, the compiler will do the following: +* add a special symbol on the function which is the `__acle_se_` prefix and the + standard function name +* constrain the number of parameters to avoid using the Non-Secure stack +* before returning from the function, clear registers that might contain Secure + information +* use the `BXNS` instruction to return + +Because the stack can not be used to pass parameters, there will be compilation +errors if: +* the total size of all parameters is too big (for example more than four 32 + bits integers) +* the entry function is not using a C ABI + +The special symbol `__acle_se_` will be used by the linker to generate a secure +gateway veneer. + + + +``` rust,ignore +#![feature(cmse_nonsecure_entry)] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function(input: u32) -> u32 { + input + 6 +} +``` + +``` text +$ rustc --emit obj --crate-type lib --target thumbv8m.main-none-eabi function.rs +$ arm-none-eabi-objdump -D function.o + +00000000 : + 0: b580 push {r7, lr} + 2: 466f mov r7, sp + 4: b082 sub sp, #8 + 6: 9001 str r0, [sp, #4] + 8: 1d81 adds r1, r0, #6 + a: 460a mov r2, r1 + c: 4281 cmp r1, r0 + e: 9200 str r2, [sp, #0] + 10: d30b bcc.n 2a + 12: e7ff b.n 14 + 14: 9800 ldr r0, [sp, #0] + 16: b002 add sp, #8 + 18: e8bd 4080 ldmia.w sp!, {r7, lr} + 1c: 4671 mov r1, lr + 1e: 4672 mov r2, lr + 20: 4673 mov r3, lr + 22: 46f4 mov ip, lr + 24: f38e 8800 msr CPSR_f, lr + 28: 4774 bxns lr + 2a: f240 0000 movw r0, #0 + 2e: f2c0 0000 movt r0, #0 + 32: f240 0200 movw r2, #0 + 36: f2c0 0200 movt r2, #0 + 3a: 211c movs r1, #28 + 3c: f7ff fffe bl 0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E> + 40: defe udf #254 ; 0xfe +``` diff --git a/src/doc/unstable-book/src/language-features/doc-alias.md b/src/doc/unstable-book/src/language-features/doc-alias.md deleted file mode 100644 index 647ac0cf66..0000000000 --- a/src/doc/unstable-book/src/language-features/doc-alias.md +++ /dev/null @@ -1,23 +0,0 @@ -# `doc_alias` - -The tracking issue for this feature is: [#50146] - -[#50146]: https://github.com/rust-lang/rust/issues/50146 - ------------------------- - -You can add alias(es) to an item when using the `rustdoc` search through the -`doc(alias)` attribute. Example: - -```rust,no_run -#![feature(doc_alias)] - -#[doc(alias = "x")] -#[doc(alias = "big")] -pub struct BigX; -``` - -Then, when looking for it through the `rustdoc` search, if you enter "x" or -"big", search will show the `BigX` struct first. - -Note that this feature is currently hidden behind the `feature(doc_alias)` gate. diff --git a/src/doc/unstable-book/src/language-features/ffi-const.md b/src/doc/unstable-book/src/language-features/ffi-const.md index 9a1ced4033..24a3044375 100644 --- a/src/doc/unstable-book/src/language-features/ffi-const.md +++ b/src/doc/unstable-book/src/language-features/ffi-const.md @@ -1,5 +1,9 @@ # `ffi_const` +The tracking issue for this feature is: [#58328] + +------ + The `#[ffi_const]` attribute applies clang's `const` attribute to foreign functions declarations. @@ -42,6 +46,7 @@ implemented in this way on all of them. It is therefore also worth verifying that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the `#[ffi_const]`. +[#58328]: https://github.com/rust-lang/rust/issues/58328 [ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html [GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute [IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm diff --git a/src/doc/unstable-book/src/language-features/ffi-pure.md b/src/doc/unstable-book/src/language-features/ffi-pure.md index 7bfd7a378f..4aef4eeab5 100644 --- a/src/doc/unstable-book/src/language-features/ffi-pure.md +++ b/src/doc/unstable-book/src/language-features/ffi-pure.md @@ -1,5 +1,9 @@ # `ffi_pure` +The tracking issue for this feature is: [#58329] + +------ + The `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign functions declarations. @@ -46,6 +50,7 @@ that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the `#[ffi_pure]`. +[#58329]: https://github.com/rust-lang/rust/issues/58329 [ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html [GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute [IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md index 2967200faf..1d9409ee9e 100644 --- a/src/doc/unstable-book/src/language-features/rustc-attrs.md +++ b/src/doc/unstable-book/src/language-features/rustc-attrs.md @@ -13,8 +13,8 @@ The `rustc_attrs` feature allows debugging rustc type layouts by using with `cargo check`) as an alternative to `rustc -Z print-type-sizes` that is way more verbose. -Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `abi`. -Note that it only work best with sized type without generics. +Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`, +`abi`. Note that it only works on sized types without generics. ## Examples diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 28a5fe31fc..af39424ec6 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -27,6 +27,7 @@ Inline assembly is currently supported on the following architectures: - RISC-V - NVPTX - Hexagon +- MIPS32 ## Basic usage @@ -345,6 +346,25 @@ The `h` modifier will emit the register name for the high byte of that register If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use. +## Memory address operands + +Sometimes assembly instructions require operands passed via memory addresses/memory locations. +You have to manually use the memory address syntax specified by the respectively architectures. +For example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/outputs in `[]` +to indicate they are memory operands: + +```rust,allow_fail +# #![feature(asm, llvm_asm)] +# fn load_fpu_control_word(control: u16) { +unsafe { + asm!("fldcw [{}]", in(reg) &control, options(nostack)); + + // Previously this would have been written with the deprecated `llvm_asm!` like this + llvm_asm!("fldcw $0" :: "m" (control) :: "volatile"); +} +# } +``` + ## Options By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better. @@ -390,7 +410,7 @@ reg_spec := / "" operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_" reg_operand := dir_spec "(" reg_spec ")" operand_expr operand := reg_operand / "const" const_expr / "sym" path -option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "att_syntax" +option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" options := "options(" option *["," option] [","] ")" asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")" ``` @@ -493,6 +513,8 @@ Here is the list of currently supported register classes: | ARM | `qreg` | `q[0-15]` | `w` | | ARM | `qreg_low8` | `q[0-7]` | `t` | | ARM | `qreg_low4` | `q[0-3]` | `x` | +| MIPS32 | `reg` | `$[2-25]` | `r` | +| MIPS32 | `freg` | `$f[0-31]` | `f` | | NVPTX | `reg16` | None\* | `h` | | NVPTX | `reg32` | None\* | `r` | | NVPTX | `reg64` | None\* | `l` | @@ -528,6 +550,8 @@ Each register class has constraints on which value types they can be used with. | ARM | `sreg` | `vfp2` | `i32`, `f32` | | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` | | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` | +| MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | +| MIPS32 | `freg` | None | `f32` | | NVPTX | `reg16` | None | `i8`, `i16` | | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | @@ -576,6 +600,7 @@ Some registers have multiple names. These are all treated by the compiler as ide | ARM | `r13` | `sp` | | ARM | `r14` | `lr` | | ARM | `r15` | `pc` | +| MIPS32 | `$[2-25]` | Please [see the Wikipedia page][mips-regs] | | RISC-V | `x0` | `zero` | | RISC-V | `x1` | `ra` | | RISC-V | `x2` | `sp` | @@ -596,12 +621,14 @@ Some registers have multiple names. These are all treated by the compiler as ide | Hexagon | `r30` | `fr` | | Hexagon | `r31` | `lr` | +[mips-regs]: https://en.wikibooks.org/wiki/MIPS_Assembly/Register_File#Registers + Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. | +| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. | | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. | | ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. | | x86 | `k0` | This is a constant zero register which can't be modified. | @@ -610,6 +637,11 @@ Some registers cannot be used for input or output operands: | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). | | AArch64 | `xzr` | This is a constant zero register which can't be modified. | | ARM | `pc` | This is the program counter, not a real register. | +| MIPS32 | `$0` or `$zero` | This is a constant zero register which can't be modified. | +| MIPS32 | `$1` or `$at` | Reserved for assembler. | +| MIPS32 | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | +| MIPS32 | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | +| MIPS32 | `$ra` | Return address cannot be used as inputs or outputs. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | @@ -657,6 +689,8 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | ARM | `dreg` | None | `d0` | `P` | | ARM | `qreg` | None | `q0` | `q` | | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` | +| MIPS32 | `reg` | None | `$2` | None | +| MIPS32 | `freg` | None | `$f0` | None | | NVPTX | `reg16` | None | `rs0` | None | | NVPTX | `reg32` | None | `r0` | None | | NVPTX | `reg64` | None | `rd0` | None | diff --git a/src/doc/unstable-book/src/library-features/llvm-asm.md b/src/doc/unstable-book/src/library-features/llvm-asm.md index da01d9228f..a2f029db29 100644 --- a/src/doc/unstable-book/src/library-features/llvm-asm.md +++ b/src/doc/unstable-book/src/library-features/llvm-asm.md @@ -159,12 +159,12 @@ specify some extra info about the inline assembly: Current valid options are: -1. *volatile* - specifying this is analogous to +1. `volatile` - specifying this is analogous to `__asm__ __volatile__ (...)` in gcc/clang. -2. *alignstack* - certain instructions expect the stack to be +2. `alignstack` - certain instructions expect the stack to be aligned a certain way (i.e. SSE) and specifying this indicates to the compiler to insert its usual stack alignment code -3. *intel* - use intel syntax instead of the default AT&T. +3. `intel` - use intel syntax instead of the default AT&T. ```rust # #![feature(llvm_asm)] diff --git a/src/doc/unstable-book/src/library-features/slice-check-range.md b/src/doc/unstable-book/src/library-features/slice-check-range.md new file mode 100644 index 0000000000..83e5738cf5 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/slice-check-range.md @@ -0,0 +1,10 @@ +# `slice_check_range` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`slice::check_range`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`slice::check_range`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.check_range diff --git a/src/etc/gdb_lookup.py b/src/etc/gdb_lookup.py index 2a46eaadad..a5a1824c84 100644 --- a/src/etc/gdb_lookup.py +++ b/src/etc/gdb_lookup.py @@ -69,9 +69,9 @@ def lookup(valobj): else: return StdOldHashMapProvider(valobj) if rust_type == RustType.STD_HASH_SET: - hash_map = valobj["map"] + hash_map = valobj[valobj.type.fields()[0]] if is_hashbrown_hashmap(hash_map): - return StdHashMapProvider(hash_map, show_values=False) + return StdHashMapProvider(valobj, show_values=False) else: return StdOldHashMapProvider(hash_map, show_values=False) diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index 67f99ec4e4..bae51e6f9e 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -347,7 +347,7 @@ class StdHashMapProvider: self.valobj = valobj self.show_values = show_values - table = self.valobj["base"]["table"] + table = self.table() capacity = int(table["bucket_mask"]) + 1 ctrl = table["ctrl"]["pointer"] @@ -368,6 +368,18 @@ class StdHashMapProvider: if is_presented: self.valid_indices.append(idx) + def table(self): + if self.show_values: + hashbrown_hashmap = self.valobj["base"] + elif self.valobj.type.fields()[0].name == "map": + # BACKCOMPAT: rust 1.47 + # HashSet wraps std::collections::HashMap, which wraps hashbrown::HashMap + hashbrown_hashmap = self.valobj["map"]["base"] + else: + # HashSet wraps hashbrown::HashSet, which wraps hashbrown::HashMap + hashbrown_hashmap = self.valobj["base"]["map"] + return hashbrown_hashmap["table"] + def to_string(self): if self.show_values: return "HashMap(size={})".format(self.size) diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index 13420fbaf0..3cee51982b 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -94,7 +94,7 @@ def synthetic_lookup(valobj, dict): if rust_type == RustType.STD_HASH_SET: hash_map = valobj.GetChildAtIndex(0) if is_hashbrown_hashmap(hash_map): - return StdHashMapSyntheticProvider(hash_map, dict, show_values=False) + return StdHashMapSyntheticProvider(valobj, dict, show_values=False) else: return StdOldHashMapSyntheticProvider(hash_map, dict, show_values=False) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 19da75c35b..64cb983794 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -526,7 +526,7 @@ class StdHashMapSyntheticProvider: def update(self): # type: () -> None - table = self.valobj.GetChildMemberWithName("base").GetChildMemberWithName("table") + table = self.table() capacity = table.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 1 ctrl = table.GetChildMemberWithName("ctrl").GetChildAtIndex(0) @@ -552,6 +552,17 @@ class StdHashMapSyntheticProvider: if is_present: self.valid_indices.append(idx) + def table(self): + # type: () -> SBValue + if self.show_values: + hashbrown_hashmap = self.valobj.GetChildMemberWithName("base") + else: + # BACKCOMPAT: rust 1.47 + # HashSet wraps either std HashMap or hashbrown::HashSet, which both + # wrap hashbrown::HashMap, so either way we "unwrap" twice. + hashbrown_hashmap = self.valobj.GetChildAtIndex(0).GetChildAtIndex(0) + return hashbrown_hashmap.GetChildMemberWithName("table") + def has_children(self): # type: () -> bool return True diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index f791979800..9550c25f2f 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -5,7 +5,7 @@ Current std impls: std::collections::hash::set::HashSet is implemented in terms of... - std::collections::hash::map::HashMap is implemented in terms of... + hashbrown::set::HashSet is implemented in terms of... hashbrown::map::HashMap is implemented in terms of... hashbrown::raw::RawTable<(K, V)> @@ -50,22 +50,22 @@ - {{ size={map.base.table.items} }} + {{ size={base.map.table.items} }} - map.base.table.items - map.base.table.items + map.base.table.growth_left - map.base.hash_builder + base.map.table.items + base.map.table.items + base.map.table.growth_left + base.map.hash_builder - - map.base.table.items + + base.map.table.items - + n-- - (($T1*)map.base.table.ctrl.pointer)[-(i + 1)] + (($T1*)base.map.table.ctrl.pointer)[-(i + 1)] i++ diff --git a/src/librustc_ast/Cargo.toml b/src/librustc_ast/Cargo.toml deleted file mode 100644 index 73c5e33753..0000000000 --- a/src/librustc_ast/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ast" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ast" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_serialize = { path = "../librustc_serialize" } -tracing = "0.1" -rustc_span = { path = "../librustc_span" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_macros = { path = "../librustc_macros" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -bitflags = "1.2.1" diff --git a/src/librustc_ast_lowering/Cargo.toml b/src/librustc_ast_lowering/Cargo.toml deleted file mode 100644 index bf7e69a31a..0000000000 --- a/src/librustc_ast_lowering/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ast_lowering" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ast_lowering" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -tracing = "0.1" -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_span = { path = "../librustc_span" } -rustc_errors = { path = "../librustc_errors" } -rustc_session = { path = "../librustc_session" } -rustc_ast = { path = "../librustc_ast" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_ast_passes/Cargo.toml b/src/librustc_ast_passes/Cargo.toml deleted file mode 100644 index 6db9bce316..0000000000 --- a/src/librustc_ast_passes/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ast_passes" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ast_passes" -path = "lib.rs" - -[dependencies] -itertools = "0.8" -tracing = "0.1" -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_parse = { path = "../librustc_parse" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_ast_pretty/Cargo.toml b/src/librustc_ast_pretty/Cargo.toml deleted file mode 100644 index d26205c791..0000000000 --- a/src/librustc_ast_pretty/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ast_pretty" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ast_pretty" -path = "lib.rs" -doctest = false - -[dependencies] -tracing = "0.1" -rustc_span = { path = "../librustc_span" } -rustc_ast = { path = "../librustc_ast" } -rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_attr/Cargo.toml b/src/librustc_attr/Cargo.toml deleted file mode 100644 index 35bdf747f0..0000000000 --- a/src/librustc_attr/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_attr" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_attr" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_errors = { path = "../librustc_errors" } -rustc_span = { path = "../librustc_span" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_feature = { path = "../librustc_feature" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_macros = { path = "../librustc_macros" } -rustc_session = { path = "../librustc_session" } -rustc_ast = { path = "../librustc_ast" } -version_check = "0.9" diff --git a/src/librustc_builtin_macros/Cargo.toml b/src/librustc_builtin_macros/Cargo.toml deleted file mode 100644 index dee6fed317..0000000000 --- a/src/librustc_builtin_macros/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_builtin_macros" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_builtin_macros" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_parse_format = { path = "../librustc_parse_format" } -tracing = "0.1" -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_parse = { path = "../librustc_parse" } -rustc_target = { path = "../librustc_target" } -rustc_session = { path = "../librustc_session" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } -rustc_expand = { path = "../librustc_expand" } -rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml deleted file mode 100644 index 2e4b9f22f8..0000000000 --- a/src/librustc_codegen_llvm/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_codegen_llvm" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_codegen_llvm" -path = "lib.rs" -test = false -doctest = false - -[dependencies] -bitflags = "1.0" -flate2 = "1.0" -libc = "0.2" -measureme = "0.7.1" -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc-demangle = "0.1" -rustc_attr = { path = "../librustc_attr" } -rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_fs_util = { path = "../librustc_fs_util" } -rustc_hir = { path = "../librustc_hir" } -rustc_incremental = { path = "../librustc_incremental" } -rustc_index = { path = "../librustc_index" } -rustc_llvm = { path = "../librustc_llvm" } -rustc_session = { path = "../librustc_session" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_target = { path = "../librustc_target" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml deleted file mode 100644 index 5707d3cd0e..0000000000 --- a/src/librustc_codegen_ssa/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_codegen_ssa" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_codegen_ssa" -path = "lib.rs" -test = false - -[dependencies] -bitflags = "1.2.1" -cc = "1.0.1" -num_cpus = "1.0" -memmap = "0.7" -tracing = "0.1" -libc = "0.2.50" -jobserver = "0.1.11" -tempfile = "3.1" -pathdiff = "0.2.0" - -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_middle = { path = "../librustc_middle" } -rustc_apfloat = { path = "../librustc_apfloat" } -rustc_attr = { path = "../librustc_attr" } -rustc_symbol_mangling = { path = "../librustc_symbol_mangling" } -rustc_data_structures = { path = "../librustc_data_structures"} -rustc_errors = { path = "../librustc_errors" } -rustc_fs_util = { path = "../librustc_fs_util" } -rustc_hir = { path = "../librustc_hir" } -rustc_incremental = { path = "../librustc_incremental" } -rustc_index = { path = "../librustc_index" } -rustc_macros = { path = "../librustc_macros" } -rustc_target = { path = "../librustc_target" } -rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_codegen_ssa/traits/declare.rs b/src/librustc_codegen_ssa/traits/declare.rs deleted file mode 100644 index 690aacd205..0000000000 --- a/src/librustc_codegen_ssa/traits/declare.rs +++ /dev/null @@ -1,65 +0,0 @@ -use super::BackendTypes; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::{Instance, Ty}; -use rustc_target::abi::call::FnAbi; - -pub trait DeclareMethods<'tcx>: BackendTypes { - /// Declare a global value. - /// - /// If there’s a value with the same name already declared, the function will - /// return its Value instead. - fn declare_global(&self, name: &str, ty: Self::Type) -> Self::Value; - - /// Declare a C ABI function. - /// - /// Only use this for foreign function ABIs and glue. For Rust functions use - /// `declare_fn` instead. - /// - /// If there’s a value with the same name already declared, the function will - /// update the declaration and return existing Value instead. - fn declare_cfn(&self, name: &str, fn_type: Self::Type) -> Self::Function; - - /// Declare a Rust function. - /// - /// If there’s a value with the same name already declared, the function will - /// update the declaration and return existing Value instead. - fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Function; - - /// Declare a global with an intention to define it. - /// - /// Use this function when you intend to define a global. This function will - /// return `None` if the name already has a definition associated with it. In that - /// case an error should be reported to the user, because it usually happens due - /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes). - fn define_global(&self, name: &str, ty: Self::Type) -> Option; - - /// Declare a private global - /// - /// Use this function when you intend to define a global without a name. - fn define_private_global(&self, ty: Self::Type) -> Self::Value; - - /// Gets declared value by name. - fn get_declared_value(&self, name: &str) -> Option; - - /// Gets defined or externally defined (AvailableExternally linkage) value by - /// name. - fn get_defined_value(&self, name: &str) -> Option; -} - -pub trait PreDefineMethods<'tcx>: BackendTypes { - fn predefine_static( - &self, - def_id: DefId, - linkage: Linkage, - visibility: Visibility, - symbol_name: &str, - ); - fn predefine_fn( - &self, - instance: Instance<'tcx>, - linkage: Linkage, - visibility: Visibility, - symbol_name: &str, - ); -} diff --git a/src/librustc_data_structures/jobserver.rs b/src/librustc_data_structures/jobserver.rs deleted file mode 100644 index a811c88839..0000000000 --- a/src/librustc_data_structures/jobserver.rs +++ /dev/null @@ -1,42 +0,0 @@ -pub use jobserver_crate::Client; -use lazy_static::lazy_static; - -lazy_static! { - // We can only call `from_env` once per process - - // Note that this is unsafe because it may misinterpret file descriptors - // on Unix as jobserver file descriptors. We hopefully execute this near - // the beginning of the process though to ensure we don't get false - // positives, or in other words we try to execute this before we open - // any file descriptors ourselves. - // - // Pick a "reasonable maximum" if we don't otherwise have - // a jobserver in our environment, capping out at 32 so we - // don't take everything down by hogging the process run queue. - // The fixed number is used to have deterministic compilation - // across machines. - // - // Also note that we stick this in a global because there could be - // multiple rustc instances in this process, and the jobserver is - // per-process. - static ref GLOBAL_CLIENT: Client = unsafe { - Client::from_env().unwrap_or_else(|| { - let client = Client::new(32).expect("failed to create jobserver"); - // Acquire a token for the main thread which we can release later - client.acquire_raw().ok(); - client - }) - }; -} - -pub fn client() -> Client { - GLOBAL_CLIENT.clone() -} - -pub fn acquire_thread() { - GLOBAL_CLIENT.acquire_raw().ok(); -} - -pub fn release_thread() { - GLOBAL_CLIENT.release_raw().ok(); -} diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml deleted file mode 100644 index 46331c6311..0000000000 --- a/src/librustc_driver/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_driver" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_driver" -path = "lib.rs" -crate-type = ["dylib"] - -[dependencies] -lazy_static = "1.0" -libc = "0.2" -tracing = { version = "0.1.18", features = ["release_max_level_info"] } -tracing-subscriber = { version = "0.2.10", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } -rustc_middle = { path = "../librustc_middle" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_target = { path = "../librustc_target" } -rustc_lint = { path = "../librustc_lint" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } -rustc_metadata = { path = "../librustc_metadata" } -rustc_mir = { path = "../librustc_mir" } -rustc_parse = { path = "../librustc_parse" } -rustc_plugin_impl = { path = "../librustc_plugin_impl" } -rustc_save_analysis = { path = "../librustc_save_analysis" } -rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } -rustc_session = { path = "../librustc_session" } -rustc_error_codes = { path = "../librustc_error_codes" } -rustc_interface = { path = "../librustc_interface" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } - -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] } - -[features] -llvm = ['rustc_interface/llvm'] diff --git a/src/librustc_error_codes/error_codes/E0019.md b/src/librustc_error_codes/error_codes/E0019.md deleted file mode 100644 index 7832468a53..0000000000 --- a/src/librustc_error_codes/error_codes/E0019.md +++ /dev/null @@ -1,36 +0,0 @@ -A function call isn't allowed in the const's initialization expression -because the expression's value must be known at compile-time. - -Erroneous code example: - -```compile_fail,E0019 -#![feature(box_syntax)] - -fn main() { - struct MyOwned; - - static STATIC11: Box = box MyOwned; // error! -} -``` - -Remember: you can't use a function call inside a const's initialization -expression! However, you can totally use it anywhere else: - -``` -enum Test { - V1 -} - -impl Test { - fn func(&self) -> i32 { - 12 - } -} - -fn main() { - const FOO: Test = Test::V1; - - FOO.func(); // here is good - let x = FOO.func(); // or even here! -} -``` diff --git a/src/librustc_error_codes/error_codes/E0433.md b/src/librustc_error_codes/error_codes/E0433.md deleted file mode 100644 index f9e333e8cc..0000000000 --- a/src/librustc_error_codes/error_codes/E0433.md +++ /dev/null @@ -1,17 +0,0 @@ -An undeclared type or module was used. - -Erroneous code example: - -```compile_fail,E0433 -let map = HashMap::new(); -// error: failed to resolve: use of undeclared type or module `HashMap` -``` - -Please verify you didn't misspell the type/module's name or that you didn't -forget to import it: - - -``` -use std::collections::HashMap; // HashMap has been imported. -let map: HashMap = HashMap::new(); // So it can be used! -``` diff --git a/src/librustc_expand/Cargo.toml b/src/librustc_expand/Cargo.toml deleted file mode 100644 index 55a1862971..0000000000 --- a/src/librustc_expand/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_expand" -version = "0.0.0" -edition = "2018" -build = false - -[lib] -name = "rustc_expand" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_serialize = { path = "../librustc_serialize" } -tracing = "0.1" -rustc_span = { path = "../librustc_span" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_ast_passes = { path = "../librustc_ast_passes" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_macros = { path = "../librustc_macros" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_parse = { path = "../librustc_parse" } -rustc_session = { path = "../librustc_session" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_expand/parse/lexer/tests.rs b/src/librustc_expand/parse/lexer/tests.rs deleted file mode 100644 index 8718444428..0000000000 --- a/src/librustc_expand/parse/lexer/tests.rs +++ /dev/null @@ -1,252 +0,0 @@ -use rustc_ast::ast::AttrStyle; -use rustc_ast::token::{self, CommentKind, Token, TokenKind}; -use rustc_data_structures::sync::Lrc; -use rustc_errors::{emitter::EmitterWriter, Handler}; -use rustc_parse::lexer::StringReader; -use rustc_session::parse::ParseSess; -use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::symbol::Symbol; -use rustc_span::with_default_session_globals; -use rustc_span::{BytePos, Span}; - -use std::io; -use std::path::PathBuf; - -fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = EmitterWriter::new( - Box::new(io::sink()), - Some(sm.clone()), - false, - false, - false, - None, - false, - ); - ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm) -} - -// Creates a string reader for the given string. -fn setup<'a>(sm: &SourceMap, sess: &'a ParseSess, teststr: String) -> StringReader<'a> { - let sf = sm.new_source_file(PathBuf::from(teststr.clone()).into(), teststr); - StringReader::new(sess, sf, None) -} - -#[test] -fn t1() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - let mut string_reader = setup( - &sm, - &sh, - "/* my source file */ fn main() { println!(\"zebra\"); }\n".to_string(), - ); - assert_eq!(string_reader.next_token(), token::Comment); - assert_eq!(string_reader.next_token(), token::Whitespace); - let tok1 = string_reader.next_token(); - let tok2 = Token::new(mk_ident("fn"), Span::with_root_ctxt(BytePos(21), BytePos(23))); - assert_eq!(tok1.kind, tok2.kind); - assert_eq!(tok1.span, tok2.span); - assert_eq!(string_reader.next_token(), token::Whitespace); - // Read another token. - let tok3 = string_reader.next_token(); - assert_eq!(string_reader.pos(), BytePos(28)); - let tok4 = Token::new(mk_ident("main"), Span::with_root_ctxt(BytePos(24), BytePos(28))); - assert_eq!(tok3.kind, tok4.kind); - assert_eq!(tok3.span, tok4.span); - - assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren)); - assert_eq!(string_reader.pos(), BytePos(29)) - }) -} - -// Checks that the given reader produces the desired stream -// of tokens (stop checking after exhausting `expected`). -fn check_tokenization(mut string_reader: StringReader<'_>, expected: Vec) { - for expected_tok in &expected { - assert_eq!(&string_reader.next_token(), expected_tok); - } -} - -// Makes the identifier by looking up the string in the interner. -fn mk_ident(id: &str) -> TokenKind { - token::Ident(Symbol::intern(id), false) -} - -fn mk_lit(kind: token::LitKind, symbol: &str, suffix: Option<&str>) -> TokenKind { - TokenKind::lit(kind, Symbol::intern(symbol), suffix.map(Symbol::intern)) -} - -#[test] -fn doublecolon_parsing() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a b".to_string()), - vec![mk_ident("a"), token::Whitespace, mk_ident("b")], - ); - }) -} - -#[test] -fn doublecolon_parsing_2() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a::b".to_string()), - vec![mk_ident("a"), token::Colon, token::Colon, mk_ident("b")], - ); - }) -} - -#[test] -fn doublecolon_parsing_3() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a ::b".to_string()), - vec![mk_ident("a"), token::Whitespace, token::Colon, token::Colon, mk_ident("b")], - ); - }) -} - -#[test] -fn doublecolon_parsing_4() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a:: b".to_string()), - vec![mk_ident("a"), token::Colon, token::Colon, token::Whitespace, mk_ident("b")], - ); - }) -} - -#[test] -fn character_a() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'a'".to_string()).next_token(), mk_lit(token::Char, "a", None),); - }) -} - -#[test] -fn character_space() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "' '".to_string()).next_token(), mk_lit(token::Char, " ", None),); - }) -} - -#[test] -fn character_escaped() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "'\\n'".to_string()).next_token(), - mk_lit(token::Char, "\\n", None), - ); - }) -} - -#[test] -fn lifetime_name() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "'abc".to_string()).next_token(), - token::Lifetime(Symbol::intern("'abc")), - ); - }) -} - -#[test] -fn raw_string() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), - mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None), - ); - }) -} - -#[test] -fn literal_suffixes() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - macro_rules! test { - ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!( - setup(&sm, &sh, format!("{}suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, Some("suffix")), - ); - // with a whitespace separator - assert_eq!( - setup(&sm, &sh, format!("{} suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, None), - ); - }}; - } - - test!("'a'", Char, "a"); - test!("b'a'", Byte, "a"); - test!("\"a\"", Str, "a"); - test!("b\"a\"", ByteStr, "a"); - test!("1234", Integer, "1234"); - test!("0b101", Integer, "0b101"); - test!("0xABC", Integer, "0xABC"); - test!("1.0", Float, "1.0"); - test!("1.0e10", Float, "1.0e10"); - - assert_eq!( - setup(&sm, &sh, "2us".to_string()).next_token(), - mk_lit(token::Integer, "2", Some("us")), - ); - assert_eq!( - setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::StrRaw(3), "raw", Some("suffix")), - ); - assert_eq!( - setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::ByteStrRaw(3), "raw", Some("suffix")), - ); - }) -} - -#[test] -fn nested_block_comments() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - let mut lexer = setup(&sm, &sh, "/* /* */ */'a'".to_string()); - assert_eq!(lexer.next_token(), token::Comment); - assert_eq!(lexer.next_token(), mk_lit(token::Char, "a", None)); - }) -} - -#[test] -fn crlf_comments() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - let mut lexer = setup(&sm, &sh, "// test\r\n/// test\r\n".to_string()); - let comment = lexer.next_token(); - assert_eq!(comment.kind, token::Comment); - assert_eq!((comment.span.lo(), comment.span.hi()), (BytePos(0), BytePos(7))); - assert_eq!(lexer.next_token(), token::Whitespace); - assert_eq!( - lexer.next_token(), - token::DocComment(CommentKind::Line, AttrStyle::Outer, Symbol::intern(" test")) - ); - }) -} diff --git a/src/librustc_feature/Cargo.toml b/src/librustc_feature/Cargo.toml deleted file mode 100644 index 96fd15ef30..0000000000 --- a/src/librustc_feature/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_feature" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_feature" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_data_structures = { path = "../librustc_data_structures" } -lazy_static = "1.0.0" -rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_hir/Cargo.toml b/src/librustc_hir/Cargo.toml deleted file mode 100644 index a473a8edcd..0000000000 --- a/src/librustc_hir/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_hir" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_hir" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_target = { path = "../librustc_target" } -rustc_macros = { path = "../librustc_macros" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_span = { path = "../librustc_span" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -lazy_static = "1" -tracing = "0.1" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_hir_pretty/Cargo.toml b/src/librustc_hir_pretty/Cargo.toml deleted file mode 100644 index ccd3e9b6e4..0000000000 --- a/src/librustc_hir_pretty/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_hir_pretty" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_hir_pretty" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_span = { path = "../librustc_span" } -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml deleted file mode 100644 index 1f7e372541..0000000000 --- a/src/librustc_incremental/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_incremental" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_incremental" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_graphviz = { path = "../librustc_graphviz" } -tracing = "0.1" -rand = "0.7" -rustc_middle = { path = "../librustc_middle" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_hir = { path = "../librustc_hir" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -rustc_macros = { path = "../librustc_macros" } -rustc_span = { path = "../librustc_span" } -rustc_fs_util = { path = "../librustc_fs_util" } -rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_infer/Cargo.toml b/src/librustc_infer/Cargo.toml deleted file mode 100644 index a0fcc881e4..0000000000 --- a/src/librustc_infer/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_infer" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_infer" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_graphviz = { path = "../librustc_graphviz" } -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_macros = { path = "../librustc_macros" } -rustc_session = { path = "../librustc_session" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_span = { path = "../librustc_span" } -rustc_target = { path = "../librustc_target" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -arrayvec = { version = "0.5.1", default-features = false } -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml deleted file mode 100644 index b9837c6ade..0000000000 --- a/src/librustc_interface/Cargo.toml +++ /dev/null @@ -1,57 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_interface" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_interface" -path = "lib.rs" -doctest = false - -[dependencies] -libc = "0.2" -tracing = "0.1" -rayon = { version = "0.3.0", package = "rustc-rayon" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } -rustc_attr = { path = "../librustc_attr" } -rustc_builtin_macros = { path = "../librustc_builtin_macros" } -rustc_expand = { path = "../librustc_expand" } -rustc_parse = { path = "../librustc_parse" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_middle = { path = "../librustc_middle" } -rustc_ast_lowering = { path = "../librustc_ast_lowering" } -rustc_ast_passes = { path = "../librustc_ast_passes" } -rustc_incremental = { path = "../librustc_incremental" } -rustc_traits = { path = "../librustc_traits" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } -rustc_symbol_mangling = { path = "../librustc_symbol_mangling" } -rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true } -rustc_hir = { path = "../librustc_hir" } -rustc_metadata = { path = "../librustc_metadata" } -rustc_mir = { path = "../librustc_mir" } -rustc_mir_build = { path = "../librustc_mir_build" } -rustc_passes = { path = "../librustc_passes" } -rustc_typeck = { path = "../librustc_typeck" } -rustc_lint = { path = "../librustc_lint" } -rustc_errors = { path = "../librustc_errors" } -rustc_plugin_impl = { path = "../librustc_plugin_impl" } -rustc_privacy = { path = "../librustc_privacy" } -rustc_resolve = { path = "../librustc_resolve" } -rustc_trait_selection = { path = "../librustc_trait_selection" } -rustc_ty = { path = "../librustc_ty" } -tempfile = "3.0.5" -once_cell = "1" - -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["libloaderapi"] } - -[dev-dependencies] -rustc_target = { path = "../librustc_target" } - -[features] -llvm = ['rustc_codegen_llvm'] diff --git a/src/librustc_lexer/src/tests.rs b/src/librustc_lexer/src/tests.rs deleted file mode 100644 index a1ea5ceb1f..0000000000 --- a/src/librustc_lexer/src/tests.rs +++ /dev/null @@ -1,167 +0,0 @@ -use super::*; - -use expect_test::{expect, Expect}; - -fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option) { - let s = &format!("r{}", s); - let mut cursor = Cursor::new(s); - cursor.bump(); - let (n_hashes, err) = cursor.raw_double_quoted_string(0); - assert_eq!(n_hashes, expected_hashes); - assert_eq!(err, expected_err); -} - -#[test] -fn test_naked_raw_str() { - check_raw_str(r#""abc""#, 0, None); -} - -#[test] -fn test_raw_no_start() { - check_raw_str(r##""abc"#"##, 0, None); -} - -#[test] -fn test_too_many_terminators() { - // this error is handled in the parser later - check_raw_str(r###"#"abc"##"###, 1, None); -} - -#[test] -fn test_unterminated() { - check_raw_str( - r#"#"abc"#, - 1, - Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }), - ); - check_raw_str( - r###"##"abc"#"###, - 2, - Some(RawStrError::NoTerminator { - expected: 2, - found: 1, - possible_terminator_offset: Some(7), - }), - ); - // We're looking for "# not just any # - check_raw_str( - r###"##"abc#"###, - 2, - Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }), - ) -} - -#[test] -fn test_invalid_start() { - check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' })); -} - -#[test] -fn test_unterminated_no_pound() { - // https://github.com/rust-lang/rust/issues/70677 - check_raw_str( - r#"""#, - 0, - Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }), - ); -} - -#[test] -fn test_valid_shebang() { - // https://github.com/rust-lang/rust/issues/70528 - let input = "#!/usr/bin/rustrun\nlet x = 5;"; - assert_eq!(strip_shebang(input), Some(18)); -} - -#[test] -fn test_invalid_shebang_valid_rust_syntax() { - // https://github.com/rust-lang/rust/issues/70528 - let input = "#! [bad_attribute]"; - assert_eq!(strip_shebang(input), None); -} - -#[test] -fn test_shebang_second_line() { - // Because shebangs are interpreted by the kernel, they must be on the first line - let input = "\n#!/bin/bash"; - assert_eq!(strip_shebang(input), None); -} - -#[test] -fn test_shebang_space() { - let input = "#! /bin/bash"; - assert_eq!(strip_shebang(input), Some(input.len())); -} - -#[test] -fn test_shebang_empty_shebang() { - let input = "#! \n[attribute(foo)]"; - assert_eq!(strip_shebang(input), None); -} - -#[test] -fn test_invalid_shebang_comment() { - let input = "#!//bin/ami/a/comment\n["; - assert_eq!(strip_shebang(input), None) -} - -#[test] -fn test_invalid_shebang_another_comment() { - let input = "#!/*bin/ami/a/comment*/\n[attribute"; - assert_eq!(strip_shebang(input), None) -} - -#[test] -fn test_shebang_valid_rust_after() { - let input = "#!/*bin/ami/a/comment*/\npub fn main() {}"; - assert_eq!(strip_shebang(input), Some(23)) -} - -#[test] -fn test_shebang_followed_by_attrib() { - let input = "#!/bin/rust-scripts\n#![allow_unused(true)]"; - assert_eq!(strip_shebang(input), Some(19)); -} - -fn check_lexing(src: &str, expect: Expect) { - let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect(); - expect.assert_eq(&actual) -} - -#[test] -fn comment_flavors() { - check_lexing( - r" -// line -//// line as well -/// outer doc line -//! inner doc line -/* block */ -/**/ -/*** also block */ -/** outer doc block */ -/*! inner doc block */ -", - expect![[r#" - Token { kind: Whitespace, len: 1 } - Token { kind: LineComment { doc_style: None }, len: 7 } - Token { kind: Whitespace, len: 1 } - Token { kind: LineComment { doc_style: None }, len: 17 } - Token { kind: Whitespace, len: 1 } - Token { kind: LineComment { doc_style: Some(Outer) }, len: 18 } - Token { kind: Whitespace, len: 1 } - Token { kind: LineComment { doc_style: Some(Inner) }, len: 18 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: None, terminated: true }, len: 4 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: None, terminated: true }, len: 18 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: Some(Outer), terminated: true }, len: 22 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: Some(Inner), terminated: true }, len: 22 } - Token { kind: Whitespace, len: 1 } - "#]], - ) -} diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml deleted file mode 100644 index d779f15f19..0000000000 --- a/src/librustc_lint/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_lint" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_lint" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -unicode-security = "0.0.5" -rustc_middle = { path = "../librustc_middle" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_attr = { path = "../librustc_attr" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_feature = { path = "../librustc_feature" } -rustc_index = { path = "../librustc_index" } -rustc_session = { path = "../librustc_session" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml deleted file mode 100644 index af6aacfd64..0000000000 --- a/src/librustc_metadata/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_metadata" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_metadata" -path = "lib.rs" -doctest = false - -[dependencies] -flate2 = "1.0" -libc = "0.2" -tracing = "0.1" -memmap = "0.7" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } -rustc_target = { path = "../librustc_target" } -rustc_index = { path = "../librustc_index" } -rustc_macros = { path = "../librustc_macros" } -rustc_serialize = { path = "../librustc_serialize" } -stable_deref_trait = "1.0.0" -rustc_ast = { path = "../librustc_ast" } -rustc_expand = { path = "../librustc_expand" } -rustc_span = { path = "../librustc_span" } -rustc_session = { path = "../librustc_session" } - -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] } diff --git a/src/librustc_middle/Cargo.toml b/src/librustc_middle/Cargo.toml deleted file mode 100644 index ae09420d4a..0000000000 --- a/src/librustc_middle/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_middle" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_middle" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -bitflags = "1.2.1" -tracing = "0.1" -rustc-rayon-core = "0.3.0" -polonius-engine = "0.12.0" -rustc_apfloat = { path = "../librustc_apfloat" } -rustc_attr = { path = "../librustc_attr" } -rustc_feature = { path = "../librustc_feature" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_macros = { path = "../librustc_macros" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_query_system = { path = "../librustc_query_system" } -rustc_errors = { path = "../librustc_errors" } -rustc_index = { path = "../librustc_index" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -byteorder = { version = "1.3" } -chalk-ir = "0.14.0" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -arrayvec = { version = "0.5.1", default-features = false } -measureme = "0.7.1" -rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_middle/ty/print/obsolete.rs b/src/librustc_middle/ty/print/obsolete.rs deleted file mode 100644 index 2ea7cd2a6d..0000000000 --- a/src/librustc_middle/ty/print/obsolete.rs +++ /dev/null @@ -1,251 +0,0 @@ -//! Allows for producing a unique string key for a mono item. -//! These keys are used by the handwritten auto-tests, so they need to be -//! predictable and human-readable. -//! -//! Note: A lot of this could looks very similar to what's already in `ty::print`. -//! FIXME(eddyb) implement a custom `PrettyPrinter` for this. - -use crate::bug; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, Const, Instance, Ty, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use std::fmt::Write; -use std::iter; - -/// Same as `unique_type_name()` but with the result pushed onto the given -/// `output` parameter. -pub struct DefPathBasedNames<'tcx> { - tcx: TyCtxt<'tcx>, - omit_disambiguators: bool, - omit_local_crate_name: bool, -} - -impl DefPathBasedNames<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, omit_disambiguators: bool, omit_local_crate_name: bool) -> Self { - DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name } - } - - // Pushes the type name of the specified type to the provided string. - // If `debug` is true, printing normally unprintable types is allowed - // (e.g. `ty::GeneratorWitness`). This parameter should only be set when - // this method is being used for logging purposes (e.g. with `debug!` or `info!`) - // When being used for codegen purposes, `debug` should be set to `false` - // in order to catch unexpected types that should never end up in a type name. - pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) { - match t.kind { - ty::Bool => output.push_str("bool"), - ty::Char => output.push_str("char"), - ty::Str => output.push_str("str"), - ty::Never => output.push_str("!"), - ty::Int(ty) => output.push_str(ty.name_str()), - ty::Uint(ty) => output.push_str(ty.name_str()), - ty::Float(ty) => output.push_str(ty.name_str()), - ty::Adt(adt_def, substs) => { - self.push_def_path(adt_def.did, output); - self.push_generic_params(substs, iter::empty(), output, debug); - } - ty::Tuple(component_types) => { - output.push('('); - for component_type in component_types { - self.push_type_name(component_type.expect_ty(), output, debug); - output.push_str(", "); - } - if !component_types.is_empty() { - output.pop(); - output.pop(); - } - output.push(')'); - } - ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => { - output.push('*'); - match mutbl { - hir::Mutability::Not => output.push_str("const "), - hir::Mutability::Mut => output.push_str("mut "), - } - - self.push_type_name(inner_type, output, debug); - } - ty::Ref(_, inner_type, mutbl) => { - output.push('&'); - output.push_str(mutbl.prefix_str()); - - self.push_type_name(inner_type, output, debug); - } - ty::Array(inner_type, len) => { - output.push('['); - self.push_type_name(inner_type, output, debug); - let len = len.eval_usize(self.tcx, ty::ParamEnv::reveal_all()); - write!(output, "; {}", len).unwrap(); - output.push(']'); - } - ty::Slice(inner_type) => { - output.push('['); - self.push_type_name(inner_type, output, debug); - output.push(']'); - } - ty::Dynamic(ref trait_data, ..) => { - if let Some(principal) = trait_data.principal() { - self.push_def_path(principal.def_id(), output); - self.push_generic_params( - principal.skip_binder().substs, - trait_data.projection_bounds(), - output, - debug, - ); - } else { - output.push_str("dyn '_"); - } - } - ty::Foreign(did) => self.push_def_path(did, output), - ty::FnDef(..) | ty::FnPtr(_) => { - let sig = t.fn_sig(self.tcx); - output.push_str(sig.unsafety().prefix_str()); - - let abi = sig.abi(); - if abi != ::rustc_target::spec::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - - let sig = - self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - - if !sig.inputs().is_empty() { - for ¶meter_type in sig.inputs() { - self.push_type_name(parameter_type, output, debug); - output.push_str(", "); - } - output.pop(); - output.pop(); - } - - if sig.c_variadic { - if !sig.inputs().is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); - } - } - - output.push(')'); - - if !sig.output().is_unit() { - output.push_str(" -> "); - self.push_type_name(sig.output(), output, debug); - } - } - ty::Generator(def_id, substs, _) | ty::Closure(def_id, substs) => { - self.push_def_path(def_id, output); - let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id)); - let substs = substs.truncate_to(self.tcx, generics); - self.push_generic_params(substs, iter::empty(), output, debug); - } - ty::Param(_) => { - output.push_str(&t.to_string()); - } - ty::Error(_) - | ty::Bound(..) - | ty::Infer(_) - | ty::Placeholder(..) - | ty::Projection(..) - | ty::GeneratorWitness(_) - | ty::Opaque(..) => { - if debug { - output.push_str(&format!("`{:?}`", t)); - } else { - bug!( - "DefPathBasedNames: trying to create type name for unexpected type: {:?}", - t, - ); - } - } - } - } - - // Pushes the the name of the specified const to the provided string. - // If `debug` is true, the unprintable types of constants will be printed with `fmt::Debug` - // (see `push_type_name` for more details). - pub fn push_const_name(&self, ct: &Const<'tcx>, output: &mut String, debug: bool) { - write!(output, "{}", ct).unwrap(); - output.push_str(": "); - self.push_type_name(ct.ty, output, debug); - } - - pub fn push_def_path(&self, def_id: DefId, output: &mut String) { - let def_path = self.tcx.def_path(def_id); - - // some_crate:: - if !(self.omit_local_crate_name && def_id.is_local()) { - output.push_str(&self.tcx.crate_name(def_path.krate).as_str()); - output.push_str("::"); - } - - // foo::bar::ItemName:: - for part in self.tcx.def_path(def_id).data { - if self.omit_disambiguators { - write!(output, "{}::", part.data.as_symbol()).unwrap(); - } else { - write!(output, "{}[{}]::", part.data.as_symbol(), part.disambiguator).unwrap(); - } - } - - // remove final "::" - output.pop(); - output.pop(); - } - - fn push_generic_params( - &self, - substs: SubstsRef<'tcx>, - projections: I, - output: &mut String, - debug: bool, - ) where - I: Iterator>, - { - let mut projections = projections.peekable(); - if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() { - return; - } - - output.push('<'); - - for type_parameter in substs.types() { - self.push_type_name(type_parameter, output, debug); - output.push_str(", "); - } - - for projection in projections { - let projection = projection.skip_binder(); - let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str(); - output.push_str(name); - output.push_str("="); - self.push_type_name(projection.ty, output, debug); - output.push_str(", "); - } - - for const_parameter in substs.consts() { - self.push_const_name(const_parameter, output, debug); - output.push_str(", "); - } - - output.pop(); - output.pop(); - - output.push('>'); - } - - pub fn push_instance_as_string( - &self, - instance: Instance<'tcx>, - output: &mut String, - debug: bool, - ) { - self.push_def_path(instance.def_id(), output); - self.push_generic_params(instance.substs, iter::empty(), output, debug); - } -} diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml deleted file mode 100644 index 2693d29e41..0000000000 --- a/src/librustc_mir/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_mir" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_mir" -path = "lib.rs" -doctest = false - -[dependencies] -either = "1.5.0" -rustc_graphviz = { path = "../librustc_graphviz" } -itertools = "0.8" -tracing = "0.1" -log_settings = "0.1.1" -polonius-engine = "0.12.0" -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_infer = { path = "../librustc_infer" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_macros = { path = "../librustc_macros" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_session = { path = "../librustc_session" } -rustc_target = { path = "../librustc_target" } -rustc_trait_selection = { path = "../librustc_trait_selection" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_apfloat = { path = "../librustc_apfloat" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs deleted file mode 100644 index 81c1b0b5bd..0000000000 --- a/src/librustc_mir/transform/check_consts/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Check the bodies of `const`s, `static`s and `const fn`s for illegal operations. -//! -//! This module will eventually replace the parts of `qualify_consts.rs` that check whether a local -//! has interior mutability or needs to be dropped, as well as the visitor that emits errors when -//! it finds operations that are invalid in a certain context. - -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::mir; -use rustc_middle::ty::{self, TyCtxt}; - -pub use self::qualifs::Qualif; - -mod ops; -pub mod post_drop_elaboration; -pub mod qualifs; -mod resolver; -pub mod validation; - -/// Information about the item currently being const-checked, as well as a reference to the global -/// context. -pub struct ConstCx<'mir, 'tcx> { - pub body: &'mir mir::Body<'tcx>, - pub tcx: TyCtxt<'tcx>, - pub def_id: LocalDefId, - pub param_env: ty::ParamEnv<'tcx>, - pub const_kind: Option, -} - -impl ConstCx<'mir, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'mir mir::Body<'tcx>) -> Self { - let param_env = tcx.param_env(def_id); - Self::new_with_param_env(tcx, def_id, body, param_env) - } - - pub fn new_with_param_env( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - body: &'mir mir::Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - let const_kind = tcx.hir().body_const_context(def_id); - ConstCx { body, tcx, def_id: def_id, param_env, const_kind } - } - - /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.). - /// - /// Panics if this `Item` is not const. - pub fn const_kind(&self) -> hir::ConstContext { - self.const_kind.expect("`const_kind` must not be called on a non-const fn") - } -} - -/// Returns `true` if this `DefId` points to one of the official `panic` lang items. -pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn() -} diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs deleted file mode 100644 index ea025f208e..0000000000 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ /dev/null @@ -1,393 +0,0 @@ -//! Concrete error types for all operations which may be invalid in a certain const context. - -use rustc_errors::struct_span_err; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_session::config::nightly_options; -use rustc_session::parse::feature_err; -use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol}; - -use super::ConstCx; - -/// Emits an error if `op` is not allowed in the given const context. -pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { - debug!("illegal_op: op={:?}", op); - - if op.is_allowed_in_item(ccx) { - return; - } - - if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { - ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate()); - return; - } - - op.emit_error(ccx, span); -} - -/// An operation that is not *always* allowed in a const context. -pub trait NonConstOp: std::fmt::Debug { - /// Returns the `Symbol` corresponding to the feature gate that would enable this operation, - /// or `None` if such a feature gate does not exist. - fn feature_gate() -> Option { - None - } - - /// Returns `true` if this operation is allowed in the given item. - /// - /// This check should assume that we are not in a non-const `fn`, where all operations are - /// legal. - /// - /// By default, it returns `true` if and only if this operation has a corresponding feature - /// gate and that gate is enabled. - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - Self::feature_gate().map_or(false, |gate| ccx.tcx.features().enabled(gate)) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0019, - "{} contains unimplemented expression type", - ccx.const_kind() - ); - if let Some(feat) = Self::feature_gate() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feat)); - } - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "A function call isn't allowed in the const's initialization expression \ - because the expression's value must be known at compile-time.", - ); - err.note( - "Remember: you can't use a function call inside a const's initialization \ - expression! However, you can use it anywhere else.", - ); - } - err.emit(); - } -} - -/// A function call where the callee is a pointer. -#[derive(Debug)] -pub struct FnCallIndirect; -impl NonConstOp for FnCallIndirect { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = - ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn"); - err.emit(); - } -} - -/// A function call where the callee is not marked as `const`. -#[derive(Debug)] -pub struct FnCallNonConst(pub DefId); -impl NonConstOp for FnCallNonConst { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "calls in {}s are limited to constant functions, \ - tuple structs and tuple variants", - ccx.const_kind(), - ); - err.emit(); - } -} - -/// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function. -/// -/// Contains the name of the feature that would allow the use of this function. -#[derive(Debug)] -pub struct FnCallUnstable(pub DefId, pub Symbol); -impl NonConstOp for FnCallUnstable { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - 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)), - ); - if nightly_options::is_nightly_build() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); - } - err.emit(); - } -} - -#[derive(Debug)] -pub struct HeapAllocation; -impl NonConstOp for HeapAllocation { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = struct_span_err!( - ccx.tcx.sess, - 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.emit(); - } -} - -#[derive(Debug)] -pub struct InlineAsm; -impl NonConstOp for InlineAsm {} - -#[derive(Debug)] -pub struct LiveDrop(pub Option); -impl NonConstOp for LiveDrop { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut diagnostic = struct_span_err!( - ccx.tcx.sess, - span, - E0493, - "destructors cannot be evaluated at compile-time" - ); - diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())); - if let Some(span) = self.0 { - diagnostic.span_label(span, "value is dropped here"); - } - diagnostic.emit(); - } -} - -#[derive(Debug)] -pub struct CellBorrow; -impl NonConstOp for CellBorrow { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - struct_span_err!( - ccx.tcx.sess, - span, - E0492, - "cannot borrow a constant which may contain \ - interior mutability, create a static instead" - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct MutBorrow; -impl NonConstOp for MutBorrow { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - // Forbid everywhere except in const fn - ccx.const_kind() == hir::ConstContext::ConstFn - && ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_mut_refs) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("mutable references are not allowed in {}s", ccx.const_kind()), - ) - } else { - struct_span_err!( - ccx.tcx.sess, - span, - E0764, - "mutable references are not allowed in {}s", - ccx.const_kind(), - ) - }; - err.span_label(span, "`&mut` is only allowed in `const fn`".to_string()); - 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.", - ); - } - err.emit(); - } -} - -#[derive(Debug)] -pub struct MutAddressOf; -impl NonConstOp for MutAddressOf { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("`&raw mut` is not allowed in {}s", ccx.const_kind()), - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct MutDeref; -impl NonConstOp for MutDeref { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) - } -} - -#[derive(Debug)] -pub struct Panic; -impl NonConstOp for Panic { - fn feature_gate() -> Option { - Some(sym::const_panic) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_panic, - span, - &format!("panicking in {}s is unstable", ccx.const_kind()), - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct RawPtrComparison; -impl NonConstOp for RawPtrComparison { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = ccx - .tcx - .sess - .struct_span_err(span, "pointers cannot be reliably compared during const eval."); - err.note( - "see issue #53020 \ - for more information", - ); - err.emit(); - } -} - -#[derive(Debug)] -pub struct RawPtrDeref; -impl NonConstOp for RawPtrDeref { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_deref) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_raw_ptr_deref, - span, - &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),), - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct RawPtrToIntCast; -impl NonConstOp for RawPtrToIntCast { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_to_usize_cast) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_raw_ptr_to_usize_cast, - span, - &format!("casting pointers to integers in {}s is unstable", ccx.const_kind(),), - ) - .emit(); - } -} - -/// An access to a (non-thread-local) `static`. -#[derive(Debug)] -pub struct StaticAccess; -impl NonConstOp for StaticAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - matches!(ccx.const_kind(), hir::ConstContext::Static(_)) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0013, - "{}s cannot refer to statics", - ccx.const_kind() - ); - err.help( - "consider extracting the value of the `static` to a `const`, and referring to that", - ); - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "`static` and `const` variables can refer to other `const` variables. \ - A `const` variable, however, cannot refer to a `static` variable.", - ); - err.help("To fix this, the value can be extracted to a `const` and then used."); - } - err.emit(); - } -} - -/// An access to a thread-local `static`. -#[derive(Debug)] -pub struct ThreadLocalAccess; -impl NonConstOp for ThreadLocalAccess { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - struct_span_err!( - ccx.tcx.sess, - span, - E0625, - "thread-local statics cannot be \ - accessed at compile-time" - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct UnionAccess; -impl NonConstOp for UnionAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - // Union accesses are stable in all contexts except `const fn`. - ccx.const_kind() != hir::ConstContext::ConstFn - || ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_fn_union) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_fn_union, - span, - "unions in const fn are unstable", - ) - .emit(); - } -} diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs deleted file mode 100644 index 7967137e01..0000000000 --- a/src/librustc_mir/transform/instcombine.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Performs various peephole optimizations. - -use crate::transform::{MirPass, MirSource}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::Mutability; -use rustc_index::vec::Idx; -use rustc_middle::mir::visit::{MutVisitor, Visitor}; -use rustc_middle::mir::{ - Body, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, -}; -use rustc_middle::ty::{self, TyCtxt}; -use std::mem; - -pub struct InstCombine; - -impl<'tcx> MirPass<'tcx> for InstCombine { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { - // First, find optimization opportunities. This is done in a pre-pass to keep the MIR - // read-only so that we can do global analyses on the MIR in the process (e.g. - // `Place::ty()`). - let optimizations = { - let mut optimization_finder = OptimizationFinder::new(body, tcx); - optimization_finder.visit_body(body); - optimization_finder.optimizations - }; - - // Then carry out those optimizations. - MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body); - } -} - -pub struct InstCombineVisitor<'tcx> { - optimizations: OptimizationList<'tcx>, - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { - if self.optimizations.and_stars.remove(&location) { - debug!("replacing `&*`: {:?}", rvalue); - let new_place = match rvalue { - Rvalue::Ref(_, _, place) => { - if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() { - place.projection = self.tcx().intern_place_elems(&[proj_r]); - - Place { - // Replace with dummy - local: mem::replace(&mut place.local, Local::new(0)), - projection: self.tcx().intern_place_elems(proj_l), - } - } else { - unreachable!(); - } - } - _ => bug!("Detected `&*` but didn't find `&*`!"), - }; - *rvalue = Rvalue::Use(Operand::Copy(new_place)) - } - - if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { - debug!("replacing `Len([_; N])`: {:?}", rvalue); - *rvalue = Rvalue::Use(Operand::Constant(box constant)); - } - - self.super_rvalue(rvalue, location) - } -} - -/// Finds optimization opportunities on the MIR. -struct OptimizationFinder<'b, 'tcx> { - body: &'b Body<'tcx>, - tcx: TyCtxt<'tcx>, - optimizations: OptimizationList<'tcx>, -} - -impl OptimizationFinder<'b, 'tcx> { - fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx> { - OptimizationFinder { body, tcx, optimizations: OptimizationList::default() } - } -} - -impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - if let Rvalue::Ref(_, _, place) = rvalue { - if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } = - place.as_ref() - { - // The dereferenced place must have type `&_`. - let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty; - if let ty::Ref(_, _, Mutability::Not) = ty.kind { - self.optimizations.and_stars.insert(location); - } - } - } - - if let Rvalue::Len(ref place) = *rvalue { - let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; - if let ty::Array(_, len) = place_ty.kind { - let span = self.body.source_info(location).span; - let constant = Constant { span, literal: len, user_ty: None }; - self.optimizations.arrays_lengths.insert(location, constant); - } - } - - self.super_rvalue(rvalue, location) - } -} - -#[derive(Default)] -struct OptimizationList<'tcx> { - and_stars: FxHashSet, - arrays_lengths: FxHashMap>, -} diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs deleted file mode 100644 index f60e6da714..0000000000 --- a/src/librustc_mir/transform/instrument_coverage.rs +++ /dev/null @@ -1,247 +0,0 @@ -use crate::transform::{MirPass, MirSource}; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_middle::hir; -use rustc_middle::ich::StableHashingContext; -use rustc_middle::mir; -use rustc_middle::mir::coverage::*; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{BasicBlock, Coverage, CoverageInfo, Location, Statement, StatementKind}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::DefId; -use rustc_span::{FileName, Pos, RealFileName, Span, Symbol}; - -/// Inserts call to count_code_region() as a placeholder to be replaced during code generation with -/// the intrinsic llvm.instrprof.increment. -pub struct InstrumentCoverage; - -/// The `query` provider for `CoverageInfo`, requested by `codegen_intrinsic_call()` when -/// constructing the arguments for `llvm.instrprof.increment`. -pub(crate) fn provide(providers: &mut Providers) { - providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id); -} - -struct CoverageVisitor { - info: CoverageInfo, -} - -impl Visitor<'_> for CoverageVisitor { - fn visit_coverage(&mut self, coverage: &Coverage, _location: Location) { - match coverage.kind { - CoverageKind::Counter { id, .. } => { - let counter_id = u32::from(id); - self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1); - } - CoverageKind::Expression { id, .. } => { - let expression_index = u32::MAX - u32::from(id); - self.info.num_expressions = - std::cmp::max(self.info.num_expressions, expression_index + 1); - } - _ => {} - } - } -} - -fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> CoverageInfo { - let mir_body = tcx.optimized_mir(mir_def_id); - - // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected - // counters, with each counter having a counter ID from `0..num_counters-1`. MIR optimization - // may split and duplicate some BasicBlock sequences. Simply counting the calls may not - // work; but computing the num_counters by adding `1` to the highest counter_id (for a given - // instrumented function) is valid. - // - // `num_expressions` is the number of counter expressions added to the MIR body. Both - // `num_counters` and `num_expressions` are used to initialize new vectors, during backend - // code generate, to lookup counters and expressions by simple u32 indexes. - let mut coverage_visitor = - CoverageVisitor { info: CoverageInfo { num_counters: 0, num_expressions: 0 } }; - - coverage_visitor.visit_body(mir_body); - coverage_visitor.info -} - -impl<'tcx> MirPass<'tcx> for InstrumentCoverage { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &mut mir::Body<'tcx>) { - // If the InstrumentCoverage pass is called on promoted MIRs, skip them. - // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601 - if src.promoted.is_none() { - Instrumentor::new(tcx, src, mir_body).inject_counters(); - } - } -} - -struct Instrumentor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - mir_def_id: DefId, - mir_body: &'a mut mir::Body<'tcx>, - hir_body: &'tcx rustc_hir::Body<'tcx>, - function_source_hash: Option, - num_counters: u32, - num_expressions: u32, -} - -impl<'a, 'tcx> Instrumentor<'a, 'tcx> { - fn new(tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { - let mir_def_id = src.def_id(); - let hir_body = hir_body(tcx, mir_def_id); - Self { - tcx, - mir_def_id, - mir_body, - hir_body, - function_source_hash: None, - num_counters: 0, - num_expressions: 0, - } - } - - /// Counter IDs start from zero and go up. - fn next_counter(&mut self) -> CounterValueReference { - assert!(self.num_counters < u32::MAX - self.num_expressions); - let next = self.num_counters; - self.num_counters += 1; - CounterValueReference::from(next) - } - - /// Expression IDs start from u32::MAX and go down because a CounterExpression can reference - /// (add or subtract counts) of both Counter regions and CounterExpression regions. The counter - /// expression operand IDs must be unique across both types. - fn next_expression(&mut self) -> InjectedExpressionIndex { - assert!(self.num_counters < u32::MAX - self.num_expressions); - let next = u32::MAX - self.num_expressions; - self.num_expressions += 1; - InjectedExpressionIndex::from(next) - } - - fn function_source_hash(&mut self) -> u64 { - match self.function_source_hash { - Some(hash) => hash, - None => { - let hash = hash_mir_source(self.tcx, self.hir_body); - self.function_source_hash.replace(hash); - hash - } - } - } - - fn inject_counters(&mut self) { - let body_span = self.hir_body.value.span; - debug!("instrumenting {:?}, span: {:?}", self.mir_def_id, body_span); - - // FIXME(richkadel): As a first step, counters are only injected at the top of each - // function. The complete solution will inject counters at each conditional code branch. - let block = rustc_middle::mir::START_BLOCK; - let counter = self.make_counter(); - self.inject_statement(counter, body_span, block); - - // FIXME(richkadel): The next step to implement source based coverage analysis will be - // instrumenting branches within functions, and some regions will be counted by "counter - // expression". The function to inject counter expression is implemented. Replace this - // "fake use" with real use. - let fake_use = false; - if fake_use { - let add = false; - let fake_counter = CoverageKind::Counter { - function_source_hash: self.function_source_hash(), - id: CounterValueReference::from_u32(1), - }; - let fake_expression = CoverageKind::Expression { - id: InjectedExpressionIndex::from(u32::MAX - 1), - lhs: ExpressionOperandId::from_u32(1), - op: Op::Add, - rhs: ExpressionOperandId::from_u32(2), - }; - - let lhs = fake_counter.as_operand_id(); - let op = if add { Op::Add } else { Op::Subtract }; - let rhs = fake_expression.as_operand_id(); - - let block = rustc_middle::mir::START_BLOCK; - - let expression = self.make_expression(lhs, op, rhs); - self.inject_statement(expression, body_span, block); - } - } - - fn make_counter(&mut self) -> CoverageKind { - CoverageKind::Counter { - function_source_hash: self.function_source_hash(), - id: self.next_counter(), - } - } - - fn make_expression( - &mut self, - lhs: ExpressionOperandId, - op: Op, - rhs: ExpressionOperandId, - ) -> CoverageKind { - CoverageKind::Expression { id: self.next_expression(), lhs, op, rhs } - } - - fn inject_statement(&mut self, coverage_kind: CoverageKind, span: Span, block: BasicBlock) { - let code_region = make_code_region(self.tcx, &span); - debug!(" injecting statement {:?} covering {:?}", coverage_kind, code_region); - - let data = &mut self.mir_body[block]; - let source_info = data.terminator().source_info; - let statement = Statement { - source_info, - kind: StatementKind::Coverage(box Coverage { kind: coverage_kind, code_region }), - }; - data.statements.push(statement); - } -} - -/// Convert the Span into its file name, start line and column, and end line and column -fn make_code_region<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> CodeRegion { - let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(span.lo()); - let end = if span.hi() == span.lo() { - start.clone() - } else { - let end = source_map.lookup_char_pos(span.hi()); - debug_assert_eq!( - start.file.name, - end.file.name, - "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!", - span.lo(), - start, - span.hi(), - end - ); - end - }; - match &start.file.name { - FileName::Real(RealFileName::Named(path)) => CodeRegion { - file_name: Symbol::intern(&path.to_string_lossy()), - start_line: start.line as u32, - start_col: start.col.to_u32() + 1, - end_line: end.line as u32, - end_col: end.col.to_u32() + 1, - }, - _ => bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name), - } -} - -fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { - let hir_node = tcx.hir().get_if_local(def_id).expect("DefId is local"); - let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); - tcx.hir().body(fn_body_id) -} - -fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { - let mut hcx = tcx.create_no_span_stable_hashing_context(); - hash(&mut hcx, &hir_body.value).to_smaller_hash() -} - -fn hash( - hcx: &mut StableHashingContext<'tcx>, - node: &impl HashStable>, -) -> Fingerprint { - let mut stable_hasher = StableHasher::new(); - node.hash_stable(hcx, &mut stable_hasher); - stable_hasher.finish() -} diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs deleted file mode 100644 index 26db4600a2..0000000000 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ /dev/null @@ -1,464 +0,0 @@ -use rustc_attr as attr; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::*; -use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; -use rustc_target::spec::abi::Abi::RustIntrinsic; -use std::borrow::Cow; - -type McfResult = Result<(), (Span, Cow<'static, str>)>; - -pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -> McfResult { - // Prevent const trait methods from being annotated as `stable`. - if tcx.features().staged_api { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { - return Err((body.span, "trait methods cannot be stable const fn".into())); - } - } - - let mut current = def_id; - loop { - let predicates = tcx.predicates_of(current); - for (predicate, _) in predicates.predicates { - match predicate.skip_binders() { - ty::PredicateAtom::RegionOutlives(_) - | ty::PredicateAtom::TypeOutlives(_) - | ty::PredicateAtom::WellFormed(_) - | ty::PredicateAtom::Projection(_) - | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => continue, - ty::PredicateAtom::ObjectSafe(_) => { - bug!("object safe predicate on function: {:#?}", predicate) - } - ty::PredicateAtom::ClosureKind(..) => { - bug!("closure kind predicate on function: {:#?}", predicate) - } - ty::PredicateAtom::Subtype(_) => { - bug!("subtype predicate on function: {:#?}", predicate) - } - ty::PredicateAtom::Trait(pred, constness) => { - if Some(pred.def_id()) == tcx.lang_items().sized_trait() { - continue; - } - match pred.self_ty().kind { - ty::Param(ref p) => { - // Allow `T: ?const Trait` - if constness == hir::Constness::NotConst - && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out) - { - continue; - } - - let generics = tcx.generics_of(current); - let def = generics.type_param(p, tcx); - let span = tcx.def_span(def.def_id); - return Err(( - span, - "trait bounds other than `Sized` \ - on const fn parameters are unstable" - .into(), - )); - } - // other kinds of bounds are either tautologies - // or cause errors in other passes - _ => continue, - } - } - } - } - match predicates.parent { - Some(parent) => current = parent, - None => break, - } - } - - for local in &body.local_decls { - check_ty(tcx, local.ty, local.source_info.span, def_id)?; - } - // impl trait is gone in MIR, so check the return type manually - check_ty( - tcx, - tcx.fn_sig(def_id).output().skip_binder(), - body.local_decls.iter().next().unwrap().source_info.span, - def_id, - )?; - - for bb in body.basic_blocks() { - check_terminator(tcx, body, def_id, bb.terminator())?; - for stmt in &bb.statements { - check_statement(tcx, body, def_id, stmt)?; - } - } - Ok(()) -} - -fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult { - for arg in ty.walk() { - let ty = match arg.unpack() { - GenericArgKind::Type(ty) => ty, - - // No constraints on lifetimes or constants, except potentially - // constants' types, but `walk` will get to them as well. - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, - }; - - match ty.kind { - ty::Ref(_, _, hir::Mutability::Mut) => { - if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) { - return Err((span, "mutable references in const fn are unstable".into())); - } - } - ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), - ty::FnPtr(..) => { - if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) { - return Err((span, "function pointers in const fn are unstable".into())); - } - } - ty::Dynamic(preds, _) => { - for pred in preds.iter() { - match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) - | ty::ExistentialPredicate::Projection(_) => { - return Err(( - span, - "trait bounds other than `Sized` \ - on const fn parameters are unstable" - .into(), - )); - } - ty::ExistentialPredicate::Trait(trait_ref) => { - if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { - return Err(( - span, - "trait bounds other than `Sized` \ - on const fn parameters are unstable" - .into(), - )); - } - } - } - } - } - _ => {} - } - } - Ok(()) -} - -fn check_rvalue( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - def_id: DefId, - rvalue: &Rvalue<'tcx>, - span: Span, -) -> McfResult { - match rvalue { - Rvalue::ThreadLocalRef(_) => { - Err((span, "cannot access thread local storage in const fn".into())) - } - Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => { - check_operand(tcx, operand, span, def_id, body) - } - Rvalue::Len(place) - | Rvalue::Discriminant(place) - | Rvalue::Ref(_, _, place) - | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, def_id, body), - Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { - use rustc_middle::ty::cast::CastTy; - let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - match (cast_in, cast_out) { - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - Err((span, "casting pointers to ints is unstable in const fn".into())) - } - _ => check_operand(tcx, operand, span, def_id, body), - } - } - Rvalue::Cast( - CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), - operand, - _, - ) => check_operand(tcx, operand, span, def_id, body), - Rvalue::Cast( - CastKind::Pointer( - PointerCast::UnsafeFnPointer - | PointerCast::ClosureFnPointer(_) - | PointerCast::ReifyFnPointer, - ), - _, - _, - ) => Err((span, "function pointer casts are not allowed in const fn".into())), - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), op, cast_ty) => { - let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) { - deref_ty.ty - } else { - // We cannot allow this for now. - return Err(( - span, - "unsizing casts are only allowed for references right now".into(), - )); - }; - let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); - if let ty::Slice(_) | ty::Str = unsized_ty.kind { - check_operand(tcx, op, span, def_id, body)?; - // Casting/coercing things to slices is fine. - Ok(()) - } else { - // We just can't allow trait objects until we have figured out trait method calls. - Err((span, "unsizing casts are not allowed in const fn".into())) - } - } - // binops are fine on integers - Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - check_operand(tcx, lhs, span, def_id, body)?; - check_operand(tcx, rhs, span, def_id, body)?; - let ty = lhs.ty(body, tcx); - if ty.is_integral() || ty.is_bool() || ty.is_char() { - Ok(()) - } else { - Err((span, "only int, `bool` and `char` operations are stable in const fn".into())) - } - } - Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()), - Rvalue::NullaryOp(NullOp::Box, _) => { - Err((span, "heap allocations are not allowed in const fn".into())) - } - Rvalue::UnaryOp(_, operand) => { - let ty = operand.ty(body, tcx); - if ty.is_integral() || ty.is_bool() { - check_operand(tcx, operand, span, def_id, body) - } else { - Err((span, "only int and `bool` operations are stable in const fn".into())) - } - } - Rvalue::Aggregate(_, operands) => { - for operand in operands { - check_operand(tcx, operand, span, def_id, body)?; - } - Ok(()) - } - } -} - -fn check_statement( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - def_id: DefId, - statement: &Statement<'tcx>, -) -> McfResult { - let span = statement.source_info.span; - match &statement.kind { - StatementKind::Assign(box (place, rval)) => { - check_place(tcx, *place, span, def_id, body)?; - check_rvalue(tcx, body, def_id, rval, span) - } - - StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, def_id, body), - - // just an assignment - StatementKind::SetDiscriminant { place, .. } => { - check_place(tcx, **place, span, def_id, body) - } - - StatementKind::LlvmInlineAsm { .. } => { - Err((span, "cannot use inline assembly in const fn".into())) - } - - // These are all NOPs - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag { .. } - | StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::Nop => Ok(()), - } -} - -fn check_operand( - tcx: TyCtxt<'tcx>, - operand: &Operand<'tcx>, - span: Span, - def_id: DefId, - body: &Body<'tcx>, -) -> McfResult { - match operand { - Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, def_id, body), - Operand::Constant(c) => match c.check_static_ptr(tcx) { - Some(_) => Err((span, "cannot access `static` items in const fn".into())), - None => Ok(()), - }, - } -} - -fn check_place( - tcx: TyCtxt<'tcx>, - place: Place<'tcx>, - span: Span, - def_id: DefId, - body: &Body<'tcx>, -) -> McfResult { - let mut cursor = place.projection.as_ref(); - while let &[ref proj_base @ .., elem] = cursor { - cursor = proj_base; - match elem { - ProjectionElem::Field(..) => { - let base_ty = Place::ty_from(place.local, &proj_base, body, tcx).ty; - if let Some(def) = base_ty.ty_adt_def() { - // No union field accesses in `const fn` - if def.is_union() { - if !feature_allowed(tcx, def_id, sym::const_fn_union) { - return Err((span, "accessing union fields is unstable".into())); - } - } - } - } - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Downcast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::Deref - | ProjectionElem::Index(_) => {} - } - } - - Ok(()) -} - -/// Returns `true` if the given feature gate is allowed within the function with the given `DefId`. -fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { - // All features require that the corresponding gate be enabled, - // even if the function has `#[allow_internal_unstable(the_gate)]`. - if !tcx.features().enabled(feature_gate) { - return false; - } - - // If this crate is not using stability attributes, or this function is not claiming to be a - // stable `const fn`, that is all that is required. - if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { - return true; - } - - // However, we cannot allow stable `const fn`s to use unstable features without an explicit - // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) -} - -/// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`. -pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { - // All features require that the corresponding gate be enabled, - // even if the function has `#[allow_internal_unstable(the_gate)]`. - if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_gate) { - return false; - } - - // If this crate is not using stability attributes, or this function is not claiming to be a - // stable `const fn`, that is all that is required. - if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { - return true; - } - - // However, we cannot allow stable `const fn`s to use unstable features without an explicit - // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) -} - -fn check_terminator( - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - def_id: DefId, - terminator: &Terminator<'tcx>, -) -> McfResult { - let span = terminator.source_info.span; - match &terminator.kind { - TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::Goto { .. } - | TerminatorKind::Return - | TerminatorKind::Resume - | TerminatorKind::Unreachable => Ok(()), - - TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, def_id, body), - TerminatorKind::DropAndReplace { place, value, .. } => { - check_place(tcx, *place, span, def_id, body)?; - check_operand(tcx, value, span, def_id, body) - } - - TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => { - check_operand(tcx, discr, span, def_id, body) - } - - TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), - TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { - Err((span, "const fn generators are unstable".into())) - } - - TerminatorKind::Call { - func, - args, - from_hir_call: _, - destination: _, - cleanup: _, - fn_span: _, - } => { - let fn_ty = func.ty(body, tcx); - if let ty::FnDef(fn_def_id, _) = fn_ty.kind { - // Allow unstable const if we opt in by using #[allow_internal_unstable] - // on function or macro declaration. - if !crate::const_eval::is_min_const_fn(tcx, fn_def_id) - && !crate::const_eval::is_unstable_const_fn(tcx, fn_def_id) - .map(|feature| { - span.allows_unstable(feature) - || lib_feature_allowed(tcx, def_id, feature) - }) - .unwrap_or(false) - { - return Err(( - span, - format!( - "can only call other `const fn` within a `const fn`, \ - but `{:?}` is not stable as `const fn`", - func, - ) - .into(), - )); - } - - // HACK: This is to "unstabilize" the `transmute` intrinsic - // within const fns. `transmute` is allowed in all other const contexts. - // This won't really scale to more intrinsics or functions. Let's allow const - // transmutes in const fn before we add more hacks to this. - if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic - && tcx.item_name(fn_def_id) == sym::transmute - && !feature_allowed(tcx, def_id, sym::const_fn_transmute) - { - return Err(( - span, - "can only call `transmute` from const items, not `const fn`".into(), - )); - } - - check_operand(tcx, func, span, fn_def_id, body)?; - - for arg in args { - check_operand(tcx, arg, span, fn_def_id, body)?; - } - Ok(()) - } else { - Err((span, "can only call other const fns within const fn".into())) - } - } - - TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { - check_operand(tcx, cond, span, def_id, body) - } - - TerminatorKind::InlineAsm { .. } => { - Err((span, "cannot use inline assembly in const fn".into())) - } - } -} diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml deleted file mode 100644 index 97621f205f..0000000000 --- a/src/librustc_mir_build/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_mir_build" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_mir_build" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_apfloat = { path = "../librustc_apfloat" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_infer = { path = "../librustc_infer" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_target = { path = "../librustc_target" } -rustc_trait_selection = { path = "../librustc_trait_selection" } -rustc_ast = { path = "../librustc_ast" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir_build/thir/pattern/const_to_pat.rs b/src/librustc_mir_build/thir/pattern/const_to_pat.rs deleted file mode 100644 index f6d3ccc1ae..0000000000 --- a/src/librustc_mir_build/thir/pattern/const_to_pat.rs +++ /dev/null @@ -1,306 +0,0 @@ -use rustc_hir as hir; -use rustc_index::vec::Idx; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_middle::mir::Field; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::lint; -use rustc_span::Span; -use rustc_trait_selection::traits::predicate_for_trait_def; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; - -use std::cell::Cell; - -use super::{FieldPat, Pat, PatCtxt, PatKind}; - -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). - pub(super) fn const_to_pat( - &self, - cv: &'tcx ty::Const<'tcx>, - id: hir::HirId, - span: Span, - mir_structural_match_violation: bool, - ) -> Pat<'tcx> { - debug!("const_to_pat: cv={:#?} id={:?}", cv, id); - debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span); - - self.tcx.infer_ctxt().enter(|infcx| { - let mut convert = ConstToPat::new(self, id, span, infcx); - convert.to_pat(cv, mir_structural_match_violation) - }) - } -} - -struct ConstToPat<'a, 'tcx> { - id: hir::HirId, - span: Span, - param_env: ty::ParamEnv<'tcx>, - - // This tracks if we signal some hard error for a given const value, so that - // we will not subsequently issue an irrelevant lint for the same const - // value. - saw_const_match_error: Cell, - - // inference context used for checking `T: Structural` bounds. - infcx: InferCtxt<'a, 'tcx>, - - include_lint_checks: bool, -} - -impl<'a, 'tcx> ConstToPat<'a, 'tcx> { - fn new( - pat_ctxt: &PatCtxt<'_, 'tcx>, - id: hir::HirId, - span: Span, - infcx: InferCtxt<'a, 'tcx>, - ) -> Self { - ConstToPat { - id, - span, - infcx, - param_env: pat_ctxt.param_env, - include_lint_checks: pat_ctxt.include_lint_checks, - saw_const_match_error: Cell::new(false), - } - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn search_for_structural_match_violation( - &self, - ty: Ty<'tcx>, - ) -> Option> { - traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty) - } - - fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { - ty.is_structural_eq_shallow(self.infcx.tcx) - } - - fn to_pat( - &mut self, - cv: &'tcx ty::Const<'tcx>, - mir_structural_match_violation: bool, - ) -> Pat<'tcx> { - // 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 - // invoked except by this method. - // - // once indirect_structural_match is a full fledged error, this - // level of indirection can be eliminated - - let inlined_const_as_pat = self.recur(cv); - - if self.include_lint_checks && !self.saw_const_match_error.get() { - // If we were able to successfully convert the const to some pat, - // double-check that all types in the const implement `Structural`. - - let structural = self.search_for_structural_match_violation(cv.ty); - debug!( - "search_for_structural_match_violation cv.ty: {:?} returned: {:?}", - cv.ty, structural - ); - - // This can occur because const qualification treats all associated constants as - // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them - // before it runs. - // - // FIXME(#73448): Find a way to bring const qualification into parity with - // `search_for_structural_match_violation`. - if structural.is_none() && mir_structural_match_violation { - warn!("MIR const-checker found novel structural match violation. See #73448."); - return inlined_const_as_pat; - } - - if let Some(non_sm_ty) = structural { - let msg = match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt_def) => { - let path = self.tcx().def_path_str(adt_def.did); - format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ) - } - traits::NonStructuralMatchTy::Dynamic => { - "trait objects cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Opaque => { - "opaque types cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Generator => { - "generators cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Closure => { - "closures cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Param => { - bug!("use of a constant whose type is a parameter inside a pattern") - } - traits::NonStructuralMatchTy::Projection => { - bug!("use of a constant whose type is a projection inside a pattern") - } - traits::NonStructuralMatchTy::Foreign => { - bug!("use of a value of a foreign type inside a pattern") - } - }; - - // double-check there even *is* a semantic `PartialEq` to dispatch to. - // - // (If there isn't, then we can safely issue a hard - // error, because that's never worked, due to compiler - // using `PartialEq::eq` in this scenario in the past.) - // - // Note: To fix rust-lang/rust#65466, one could lift this check - // *before* any structural-match checking, and unconditionally error - // if `PartialEq` is not implemented. However, that breaks stable - // code at the moment, because types like `for <'a> fn(&'a ())` do - // not *yet* implement `PartialEq`. So for now we leave this here. - let ty_is_partial_eq: bool = { - let partial_eq_trait_id = - self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); - let obligation: PredicateObligation<'_> = predicate_for_trait_def( - self.tcx(), - self.param_env, - ObligationCause::misc(self.span, self.id), - partial_eq_trait_id, - 0, - cv.ty, - &[], - ); - // FIXME: should this call a `predicate_must_hold` variant instead? - self.infcx.predicate_may_hold(&obligation) - }; - - if !ty_is_partial_eq { - // span_fatal avoids ICE from resolution of non-existent method (rare case). - self.tcx().sess.span_fatal(self.span, &msg); - } else if mir_structural_match_violation { - self.tcx().struct_span_lint_hir( - lint::builtin::INDIRECT_STRUCTURAL_MATCH, - self.id, - self.span, - |lint| lint.build(&msg).emit(), - ); - } else { - debug!( - "`search_for_structural_match_violation` found one, but `CustomEq` was \ - not in the qualifs for that `const`" - ); - } - } - } - - inlined_const_as_pat - } - - // Recursive helper for `to_pat`; invoke that (instead of calling this directly). - fn recur(&self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> { - let id = self.id; - let span = self.span; - let tcx = self.tcx(); - let param_env = self.param_env; - - let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| { - vals.iter() - .enumerate() - .map(|(idx, val)| { - let field = Field::new(idx); - FieldPat { field, pattern: self.recur(val) } - }) - .collect() - }; - - let kind = match cv.ty.kind { - ty::Float(_) => { - tcx.struct_span_lint_hir( - lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - id, - span, - |lint| lint.build("floating-point types cannot be used in patterns").emit(), - ); - PatKind::Constant { value: cv } - } - ty::Adt(adt_def, _) if adt_def.is_union() => { - // Matching on union fields is unsafe, we can't hide it in constants - self.saw_const_match_error.set(true); - tcx.sess.span_err(span, "cannot use unions in constant patterns"); - PatKind::Wild - } - // keep old code until future-compat upgraded to errors. - ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { - debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty); - let path = tcx.def_path_str(adt_def.did); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ); - self.saw_const_match_error.set(true); - tcx.sess.span_err(span, &msg); - PatKind::Wild - } - // keep old code until future-compat upgraded to errors. - ty::Ref(_, adt_ty @ ty::TyS { kind: ty::Adt(_, _), .. }, _) - if !self.type_marked_structural(adt_ty) => - { - let adt_def = - if let ty::Adt(adt_def, _) = adt_ty.kind { adt_def } else { unreachable!() }; - - debug!( - "adt_def {:?} has !type_marked_structural for adt_ty: {:?}", - adt_def, adt_ty - ); - - // HACK(estebank): Side-step ICE #53708, but anything other than erroring here - // would be wrong. Returnging `PatKind::Wild` is not technically correct. - let path = tcx.def_path_str(adt_def.did); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ); - self.saw_const_match_error.set(true); - tcx.sess.span_err(span, &msg); - PatKind::Wild - } - ty::Adt(adt_def, substs) if adt_def.is_enum() => { - let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Variant { - adt_def, - substs, - variant_index: destructured - .variant - .expect("destructed const of adt without variant id"), - subpatterns: field_pats(destructured.fields), - } - } - ty::Adt(_, _) => { - let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Leaf { subpatterns: field_pats(destructured.fields) } - } - ty::Tuple(_) => { - let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Leaf { subpatterns: field_pats(destructured.fields) } - } - ty::Array(..) => PatKind::Array { - prefix: tcx - .destructure_const(param_env.and(cv)) - .fields - .iter() - .map(|val| self.recur(val)) - .collect(), - slice: None, - suffix: Vec::new(), - }, - _ => PatKind::Constant { value: cv }, - }; - - Pat { span, ty: cv.ty, kind: Box::new(kind) } - } -} diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml deleted file mode 100644 index 31d858849a..0000000000 --- a/src/librustc_parse/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_parse" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_parse" -path = "lib.rs" -doctest = false - -[dependencies] -bitflags = "1.0" -tracing = "0.1" -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_feature = { path = "../librustc_feature" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_errors = { path = "../librustc_errors" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_ast = { path = "../librustc_ast" } -unicode-normalization = "0.1.11" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_parse_format/Cargo.toml b/src/librustc_parse_format/Cargo.toml deleted file mode 100644 index 646509569f..0000000000 --- a/src/librustc_parse_format/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_parse_format" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_parse_format" -path = "lib.rs" - -[dependencies] -rustc_span = { path = "../librustc_span" } -rustc_lexer = { path = "../librustc_lexer" } diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml deleted file mode 100644 index db481c0d0d..0000000000 --- a/src/librustc_passes/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_passes" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_passes" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_session = { path = "../librustc_session" } -rustc_target = { path = "../librustc_target" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_plugin_impl/Cargo.toml b/src/librustc_plugin_impl/Cargo.toml deleted file mode 100644 index 38cfbd48de..0000000000 --- a/src/librustc_plugin_impl/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_plugin_impl" -version = "0.0.0" -build = false -edition = "2018" - -[lib] -name = "rustc_plugin_impl" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_middle = { path = "../librustc_middle" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_lint = { path = "../librustc_lint" } -rustc_metadata = { path = "../librustc_metadata" } -rustc_ast = { path = "../librustc_ast" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_privacy/Cargo.toml b/src/librustc_privacy/Cargo.toml deleted file mode 100644 index 3641f0f8a3..0000000000 --- a/src/librustc_privacy/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_privacy" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_privacy" -path = "lib.rs" - -[dependencies] -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_typeck = { path = "../librustc_typeck" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_data_structures = { path = "../librustc_data_structures" } -tracing = "0.1" diff --git a/src/librustc_query_system/Cargo.toml b/src/librustc_query_system/Cargo.toml deleted file mode 100644 index 1e89d379cb..0000000000 --- a/src/librustc_query_system/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_query_system" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_query_system" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -tracing = "0.1" -rustc-rayon-core = "0.3.0" -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_macros = { path = "../librustc_macros" } -rustc_index = { path = "../librustc_index" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_span = { path = "../librustc_span" } -parking_lot = "0.10" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml deleted file mode 100644 index e5260866f2..0000000000 --- a/src/librustc_resolve/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_resolve" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_resolve" -path = "lib.rs" -test = false -doctest = false - -[dependencies] -bitflags = "1.2.1" -tracing = "0.1" -rustc_ast = { path = "../librustc_ast" } -rustc_arena = { path = "../librustc_arena" } -rustc_middle = { path = "../librustc_middle" } -rustc_ast_lowering = { path = "../librustc_ast_lowering" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_expand = { path = "../librustc_expand" } -rustc_feature = { path = "../librustc_feature" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_metadata = { path = "../librustc_metadata" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml deleted file mode 100644 index 3c2edc1fa5..0000000000 --- a/src/librustc_save_analysis/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_save_analysis" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_save_analysis" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_ast = { path = "../librustc_ast" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } -rustc_parse = { path = "../librustc_parse" } -serde_json = "1" -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rls-data = "0.19" -rls-span = "0.5" diff --git a/src/librustc_session/Cargo.toml b/src/librustc_session/Cargo.toml deleted file mode 100644 index 208bba1d96..0000000000 --- a/src/librustc_session/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_session" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_session" -path = "lib.rs" - -[dependencies] -bitflags = "1.2.1" -getopts = "0.2" -rustc_macros = { path = "../librustc_macros" } -tracing = "0.1" -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_target = { path = "../librustc_target" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_span = { path = "../librustc_span" } -rustc_fs_util = { path = "../librustc_fs_util" } -num_cpus = "1.0" -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs deleted file mode 100644 index 144a06a491..0000000000 --- a/src/librustc_session/lint/builtin.rs +++ /dev/null @@ -1,635 +0,0 @@ -//! Some lints that are built in to the compiler. -//! -//! These are the built-in lints that are emitted direct in the main -//! compiler code, rather than using their own custom pass. Those -//! lints are all available in `rustc_lint::builtin`. - -use crate::lint::FutureIncompatibleInfo; -use crate::{declare_lint, declare_lint_pass}; -use rustc_span::edition::Edition; -use rustc_span::symbol::sym; - -declare_lint! { - pub ILL_FORMED_ATTRIBUTE_INPUT, - Deny, - "ill-formed attribute inputs that were previously accepted and used in practice", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #57571 ", - edition: None, - }; - crate_level_only -} - -declare_lint! { - pub CONFLICTING_REPR_HINTS, - Deny, - "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #68585 ", - edition: None, - }; -} - -declare_lint! { - pub META_VARIABLE_MISUSE, - Allow, - "possible meta-variable misuse at macro definition" -} - -declare_lint! { - pub INCOMPLETE_INCLUDE, - Deny, - "trailing content in included file" -} - -declare_lint! { - pub ARITHMETIC_OVERFLOW, - Deny, - "arithmetic operation overflows" -} - -declare_lint! { - pub UNCONDITIONAL_PANIC, - Deny, - "operation will cause a panic at runtime" -} - -declare_lint! { - pub CONST_ERR, - Deny, - "constant evaluation detected erroneous expression", - report_in_external_macro -} - -declare_lint! { - pub UNUSED_IMPORTS, - Warn, - "imports that are never used" -} - -declare_lint! { - pub UNUSED_EXTERN_CRATES, - Allow, - "extern crates that are never used" -} - -declare_lint! { - pub UNUSED_CRATE_DEPENDENCIES, - Allow, - "crate dependencies that are never used", - crate_level_only -} - -declare_lint! { - pub UNUSED_QUALIFICATIONS, - Allow, - "detects unnecessarily qualified names" -} - -declare_lint! { - pub UNKNOWN_LINTS, - Warn, - "unrecognized lint attribute" -} - -declare_lint! { - pub UNUSED_VARIABLES, - Warn, - "detect variables which are not used in any way" -} - -declare_lint! { - pub UNUSED_ASSIGNMENTS, - Warn, - "detect assignments that will never be read" -} - -declare_lint! { - pub DEAD_CODE, - Warn, - "detect unused, unexported items" -} - -declare_lint! { - pub UNUSED_ATTRIBUTES, - Warn, - "detects attributes that were not used by the compiler" -} - -declare_lint! { - pub UNREACHABLE_CODE, - Warn, - "detects unreachable code paths", - report_in_external_macro -} - -declare_lint! { - pub UNREACHABLE_PATTERNS, - Warn, - "detects unreachable patterns" -} - -declare_lint! { - pub OVERLAPPING_PATTERNS, - Warn, - "detects overlapping patterns" -} - -declare_lint! { - pub BINDINGS_WITH_VARIANT_NAME, - Warn, - "detects pattern bindings with the same name as one of the matched variants" -} - -declare_lint! { - pub UNUSED_MACROS, - Warn, - "detects macros that were not used" -} - -declare_lint! { - pub WARNINGS, - Warn, - "mass-change the level for lints which produce warnings" -} - -declare_lint! { - pub UNUSED_FEATURES, - Warn, - "unused features found in crate-level `#[feature]` directives" -} - -declare_lint! { - pub STABLE_FEATURES, - Warn, - "stable features found in `#[feature]` directive" -} - -declare_lint! { - pub UNKNOWN_CRATE_TYPES, - Deny, - "unknown crate type found in `#[crate_type]` directive", - crate_level_only -} - -declare_lint! { - pub TRIVIAL_CASTS, - Allow, - "detects trivial casts which could be removed" -} - -declare_lint! { - pub TRIVIAL_NUMERIC_CASTS, - Allow, - "detects trivial casts of numeric types which could be removed" -} - -declare_lint! { - pub PRIVATE_IN_PUBLIC, - Warn, - "detect private items in public interfaces not caught by the old implementation", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #34537 ", - edition: None, - }; -} - -declare_lint! { - pub EXPORTED_PRIVATE_DEPENDENCIES, - Warn, - "public interface leaks type from a private dependency" -} - -declare_lint! { - pub PUB_USE_OF_PRIVATE_EXTERN_CRATE, - Deny, - "detect public re-exports of private extern crates", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #34537 ", - edition: None, - }; -} - -declare_lint! { - pub INVALID_TYPE_PARAM_DEFAULT, - Deny, - "type parameter default erroneously allowed in invalid location", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #36887 ", - edition: None, - }; -} - -declare_lint! { - pub RENAMED_AND_REMOVED_LINTS, - Warn, - "lints that have been renamed or removed" -} - -declare_lint! { - pub UNALIGNED_REFERENCES, - Allow, - "detects unaligned references to fields of packed structs", -} - -declare_lint! { - pub SAFE_PACKED_BORROWS, - Warn, - "safe borrows of fields of packed structs were erroneously allowed", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #46043 ", - edition: None, - }; -} - -declare_lint! { - pub PATTERNS_IN_FNS_WITHOUT_BODY, - Deny, - "patterns in functions without body were erroneously allowed", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #35203 ", - edition: None, - }; -} - -declare_lint! { - pub MISSING_FRAGMENT_SPECIFIER, - Deny, - "detects missing fragment specifiers in unused `macro_rules!` patterns", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #40107 ", - edition: None, - }; -} - -declare_lint! { - pub LATE_BOUND_LIFETIME_ARGUMENTS, - Warn, - "detects generic lifetime arguments in path segments with late bound lifetime parameters", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #42868 ", - edition: None, - }; -} - -declare_lint! { - pub ORDER_DEPENDENT_TRAIT_OBJECTS, - Deny, - "trait-object types were treated as different depending on marker-trait order", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #56484 ", - edition: None, - }; -} - -declare_lint! { - pub COHERENCE_LEAK_CHECK, - Warn, - "distinct impls distinguished only by the leak-check code", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #56105 ", - edition: None, - }; -} - -declare_lint! { - pub DEPRECATED, - Warn, - "detects use of deprecated items", - report_in_external_macro -} - -declare_lint! { - pub UNUSED_UNSAFE, - Warn, - "unnecessary use of an `unsafe` block" -} - -declare_lint! { - pub UNUSED_MUT, - Warn, - "detect mut variables which don't need to be mutable" -} - -declare_lint! { - pub UNCONDITIONAL_RECURSION, - Warn, - "functions that cannot return without calling themselves" -} - -declare_lint! { - pub SINGLE_USE_LIFETIMES, - Allow, - "detects lifetime parameters that are only used once" -} - -declare_lint! { - pub UNUSED_LIFETIMES, - Allow, - "detects lifetime parameters that are never used" -} - -declare_lint! { - pub TYVAR_BEHIND_RAW_POINTER, - Warn, - "raw pointer to an inference variable", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #46906 ", - edition: Some(Edition::Edition2018), - }; -} - -declare_lint! { - pub ELIDED_LIFETIMES_IN_PATHS, - Allow, - "hidden lifetime parameters in types are deprecated", - crate_level_only -} - -declare_lint! { - pub BARE_TRAIT_OBJECTS, - Warn, - "suggest using `dyn Trait` for trait objects" -} - -declare_lint! { - pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - Allow, - "fully qualified paths that start with a module name \ - instead of `crate`, `self`, or an extern crate name", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #53130 ", - edition: Some(Edition::Edition2018), - }; -} - -declare_lint! { - pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - Warn, - "floating-point literals cannot be used in patterns", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #41620 ", - edition: None, - }; -} - -declare_lint! { - pub UNSTABLE_NAME_COLLISIONS, - Warn, - "detects name collision with an existing but unstable method", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #48919 ", - edition: None, - // Note: this item represents future incompatibility of all unstable functions in the - // standard library, and thus should never be removed or changed to an error. - }; -} - -declare_lint! { - pub IRREFUTABLE_LET_PATTERNS, - Warn, - "detects irrefutable patterns in if-let and while-let statements" -} - -declare_lint! { - pub UNUSED_LABELS, - Warn, - "detects labels that are never used" -} - -declare_lint! { - pub BROKEN_INTRA_DOC_LINKS, - Warn, - "failures in resolving intra-doc link targets" -} - -declare_lint! { - pub INVALID_CODEBLOCK_ATTRIBUTES, - Warn, - "codeblock attribute looks a lot like a known one" -} - -declare_lint! { - pub MISSING_CRATE_LEVEL_DOCS, - Allow, - "detects crates with no crate-level documentation" -} - -declare_lint! { - pub MISSING_DOC_CODE_EXAMPLES, - Allow, - "detects publicly-exported items without code samples in their documentation" -} - -declare_lint! { - pub PRIVATE_DOC_TESTS, - Allow, - "detects code samples in docs of private items not documented by rustdoc" -} - -declare_lint! { - pub WHERE_CLAUSES_OBJECT_SAFETY, - Warn, - "checks the object safety of where clauses", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #51443 ", - edition: None, - }; -} - -declare_lint! { - pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - Warn, - "detects proc macro derives using inaccessible names from parent modules", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #50504 ", - edition: None, - }; -} - -declare_lint! { - pub MACRO_USE_EXTERN_CRATE, - Allow, - "the `#[macro_use]` attribute is now deprecated in favor of using macros \ - via the module system" -} - -declare_lint! { - pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, - Deny, - "macro-expanded `macro_export` macros from the current crate \ - cannot be referred to by absolute paths", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #52234 ", - edition: None, - }; - crate_level_only -} - -declare_lint! { - pub EXPLICIT_OUTLIVES_REQUIREMENTS, - Allow, - "outlives requirements can be inferred" -} - -declare_lint! { - pub INDIRECT_STRUCTURAL_MATCH, - // defaulting to allow until rust-lang/rust#62614 is fixed. - Allow, - "pattern with const indirectly referencing non-structural-match type", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #62411 ", - edition: None, - }; -} - -declare_lint! { - pub DEPRECATED_IN_FUTURE, - Allow, - "detects use of items that will be deprecated in a future version", - report_in_external_macro -} - -declare_lint! { - pub AMBIGUOUS_ASSOCIATED_ITEMS, - Deny, - "ambiguous associated items", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #57644 ", - edition: None, - }; -} - -declare_lint! { - pub MUTABLE_BORROW_RESERVATION_CONFLICT, - Warn, - "reservation of a two-phased borrow conflicts with other shared borrows", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #59159 ", - edition: None, - }; -} - -declare_lint! { - pub SOFT_UNSTABLE, - Deny, - "a feature gate that doesn't break dependent crates", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #64266 ", - edition: None, - }; -} - -declare_lint! { - pub INLINE_NO_SANITIZE, - Warn, - "detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`", -} - -declare_lint! { - pub ASM_SUB_REGISTER, - Warn, - "using only a subset of a register for inline asm inputs", -} - -declare_lint! { - pub UNSAFE_OP_IN_UNSAFE_FN, - Allow, - "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", - @feature_gate = sym::unsafe_block_in_unsafe_fn; -} - -declare_lint! { - pub CENUM_IMPL_DROP_CAST, - Warn, - "a C-like enum implementing Drop is cast", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #73333 ", - edition: None, - }; -} - -declare_lint_pass! { - /// Does nothing as a lint pass, but registers some `Lint`s - /// that are used by other parts of the compiler. - HardwiredLints => [ - ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - ARITHMETIC_OVERFLOW, - UNCONDITIONAL_PANIC, - UNUSED_IMPORTS, - UNUSED_EXTERN_CRATES, - UNUSED_CRATE_DEPENDENCIES, - UNUSED_QUALIFICATIONS, - UNKNOWN_LINTS, - UNUSED_VARIABLES, - UNUSED_ASSIGNMENTS, - DEAD_CODE, - UNREACHABLE_CODE, - UNREACHABLE_PATTERNS, - OVERLAPPING_PATTERNS, - BINDINGS_WITH_VARIANT_NAME, - UNUSED_MACROS, - WARNINGS, - UNUSED_FEATURES, - STABLE_FEATURES, - UNKNOWN_CRATE_TYPES, - TRIVIAL_CASTS, - TRIVIAL_NUMERIC_CASTS, - PRIVATE_IN_PUBLIC, - EXPORTED_PRIVATE_DEPENDENCIES, - PUB_USE_OF_PRIVATE_EXTERN_CRATE, - INVALID_TYPE_PARAM_DEFAULT, - CONST_ERR, - RENAMED_AND_REMOVED_LINTS, - UNALIGNED_REFERENCES, - SAFE_PACKED_BORROWS, - PATTERNS_IN_FNS_WITHOUT_BODY, - MISSING_FRAGMENT_SPECIFIER, - LATE_BOUND_LIFETIME_ARGUMENTS, - ORDER_DEPENDENT_TRAIT_OBJECTS, - COHERENCE_LEAK_CHECK, - DEPRECATED, - UNUSED_UNSAFE, - UNUSED_MUT, - UNCONDITIONAL_RECURSION, - SINGLE_USE_LIFETIMES, - UNUSED_LIFETIMES, - UNUSED_LABELS, - TYVAR_BEHIND_RAW_POINTER, - ELIDED_LIFETIMES_IN_PATHS, - BARE_TRAIT_OBJECTS, - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - UNSTABLE_NAME_COLLISIONS, - IRREFUTABLE_LET_PATTERNS, - BROKEN_INTRA_DOC_LINKS, - INVALID_CODEBLOCK_ATTRIBUTES, - MISSING_CRATE_LEVEL_DOCS, - MISSING_DOC_CODE_EXAMPLES, - PRIVATE_DOC_TESTS, - WHERE_CLAUSES_OBJECT_SAFETY, - PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - MACRO_USE_EXTERN_CRATE, - MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, - ILL_FORMED_ATTRIBUTE_INPUT, - CONFLICTING_REPR_HINTS, - META_VARIABLE_MISUSE, - DEPRECATED_IN_FUTURE, - AMBIGUOUS_ASSOCIATED_ITEMS, - MUTABLE_BORROW_RESERVATION_CONFLICT, - INDIRECT_STRUCTURAL_MATCH, - SOFT_UNSTABLE, - INLINE_NO_SANITIZE, - ASM_SUB_REGISTER, - UNSAFE_OP_IN_UNSAFE_FN, - INCOMPLETE_INCLUDE, - CENUM_IMPL_DROP_CAST, - ] -} - -declare_lint! { - pub UNUSED_DOC_COMMENTS, - Warn, - "detects doc comments that aren't used by rustdoc" -} - -declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); diff --git a/src/librustc_span/Cargo.toml b/src/librustc_span/Cargo.toml deleted file mode 100644 index dd4928d4e3..0000000000 --- a/src/librustc_span/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_span" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_span" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_serialize = { path = "../librustc_serialize" } -rustc_macros = { path = "../librustc_macros" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_arena = { path = "../librustc_arena" } -scoped-tls = "1.0" -unicode-width = "0.1.4" -cfg-if = "0.1.2" -tracing = "0.1" -sha-1 = "0.8" -md-5 = "0.8" diff --git a/src/librustc_symbol_mangling/Cargo.toml b/src/librustc_symbol_mangling/Cargo.toml deleted file mode 100644 index b44c0e4e02..0000000000 --- a/src/librustc_symbol_mangling/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_symbol_mangling" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_symbol_mangling" -path = "lib.rs" -doctest = false - -[dependencies] -tracing = "0.1" -punycode = "0.4.0" -rustc-demangle = "0.1.16" - -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_middle = { path = "../librustc_middle" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_target/Cargo.toml b/src/librustc_target/Cargo.toml deleted file mode 100644 index d2b50f44e4..0000000000 --- a/src/librustc_target/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_target" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_target" -path = "lib.rs" - -[dependencies] -bitflags = "1.2.1" -tracing = "0.1" -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_macros = { path = "../librustc_macros" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_span = { path = "../librustc_span" } -rustc_index = { path = "../librustc_index" } diff --git a/src/librustc_target/spec/apple_sdk_base.rs b/src/librustc_target/spec/apple_sdk_base.rs deleted file mode 100644 index 0d0a0da9d1..0000000000 --- a/src/librustc_target/spec/apple_sdk_base.rs +++ /dev/null @@ -1,151 +0,0 @@ -use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; -use std::env; -use std::io; -use std::path::Path; -use std::process::Command; - -use Arch::*; -#[allow(non_camel_case_types)] -#[derive(Copy, Clone)] -pub enum Arch { - Armv7, - Armv7s, - Arm64, - I386, - X86_64, - X86_64_macabi, -} - -#[allow(non_camel_case_types)] -#[derive(Copy, Clone)] -pub enum AppleOS { - tvOS, - iOS, -} - -impl Arch { - pub fn to_string(self) -> &'static str { - match self { - Armv7 => "armv7", - Armv7s => "armv7s", - Arm64 => "arm64", - I386 => "i386", - X86_64 => "x86_64", - X86_64_macabi => "x86_64", - } - } -} - -pub fn get_sdk_root(sdk_name: &str) -> Result { - // Following what clang does - // (https://github.com/llvm/llvm-project/blob/ - // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678) - // to allow the SDK path to be set. (For clang, xcrun sets - // SDKROOT; for rustc, the user or build system can set it, or we - // can fall back to checking for xcrun on PATH.) - if let Ok(sdkroot) = env::var("SDKROOT") { - let p = Path::new(&sdkroot); - match sdk_name { - // Ignore `SDKROOT` if it's clearly set for the wrong platform. - "appletvos" - if sdkroot.contains("TVSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} - "appletvsimulator" - if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {} - "iphoneos" - if sdkroot.contains("iPhoneSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} - "iphonesimulator" - if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => { - } - "macosx10.15" - if sdkroot.contains("iPhoneOS.platform") - || sdkroot.contains("iPhoneSimulator.platform") => {} - // Ignore `SDKROOT` if it's not a valid path. - _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {} - _ => return Ok(sdkroot), - } - } - let res = - Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then( - |output| { - if output.status.success() { - Ok(String::from_utf8(output.stdout).unwrap()) - } else { - let error = String::from_utf8(output.stderr); - let error = format!("process exit with error: {}", error.unwrap()); - Err(io::Error::new(io::ErrorKind::Other, &error[..])) - } - }, - ); - - match res { - Ok(output) => Ok(output.trim().to_string()), - Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)), - } -} - -fn build_pre_link_args(arch: Arch, os: AppleOS) -> Result { - let sdk_name = match (arch, os) { - (Arm64, AppleOS::tvOS) => "appletvos", - (X86_64, AppleOS::tvOS) => "appletvsimulator", - (Armv7, AppleOS::iOS) => "iphoneos", - (Armv7s, AppleOS::iOS) => "iphoneos", - (Arm64, AppleOS::iOS) => "iphoneos", - (I386, AppleOS::iOS) => "iphonesimulator", - (X86_64, AppleOS::iOS) => "iphonesimulator", - (X86_64_macabi, AppleOS::iOS) => "macosx10.15", - _ => unreachable!(), - }; - - let arch_name = arch.to_string(); - - let sdk_root = get_sdk_root(sdk_name)?; - - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - "-arch".to_string(), - arch_name.to_string(), - "-isysroot".to_string(), - sdk_root.clone(), - "-Wl,-syslibroot".to_string(), - sdk_root, - ], - ); - - Ok(args) -} - -fn target_cpu(arch: Arch) -> String { - match arch { - Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher - Armv7s => "cortex-a9", - Arm64 => "apple-a7", - I386 => "yonah", - X86_64 => "core2", - X86_64_macabi => "core2", - } - .to_string() -} - -fn link_env_remove(arch: Arch) -> Vec { - match arch { - Armv7 | Armv7s | Arm64 | I386 | X86_64 => vec!["MACOSX_DEPLOYMENT_TARGET".to_string()], - X86_64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()], - } -} - -pub fn opts(arch: Arch, os: AppleOS) -> Result { - let pre_link_args = build_pre_link_args(arch, os)?; - Ok(TargetOptions { - cpu: target_cpu(arch), - executables: true, - pre_link_args, - link_env_remove: link_env_remove(arch), - has_elf_tls: false, - eliminate_frame_pointer: false, - ..super::apple_base::opts() - }) -} diff --git a/src/librustc_target/spec/avr_unknown_unknown.rs b/src/librustc_target/spec/avr_unknown_unknown.rs deleted file mode 100644 index f90a8def0a..0000000000 --- a/src/librustc_target/spec/avr_unknown_unknown.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; - -pub fn target() -> TargetResult { - Ok(Target { - llvm_target: "avr-unknown-unknown".to_string(), - target_endian: "little".to_string(), - target_pointer_width: "16".to_string(), - data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(), - arch: "avr".to_string(), - linker_flavor: LinkerFlavor::Gcc, - target_os: "unknown".to_string(), - target_env: "".to_string(), - target_vendor: "unknown".to_string(), - target_c_int_width: 16.to_string(), - options: super::freestanding_base::opts(), - }) -} diff --git a/src/librustc_target/spec/freestanding_base.rs b/src/librustc_target/spec/freestanding_base.rs deleted file mode 100644 index c338856228..0000000000 --- a/src/librustc_target/spec/freestanding_base.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; -use std::default::Default; - -pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - - args.insert( - LinkerFlavor::Gcc, - vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), - ], - ); - - TargetOptions { - dynamic_linking: false, - executables: true, - linker_is_gnu: true, - has_rpath: false, - pre_link_args: args, - position_independent_executables: false, - eh_frame_header: false, - ..Default::default() - } -} diff --git a/src/librustc_trait_selection/Cargo.toml b/src/librustc_trait_selection/Cargo.toml deleted file mode 100644 index 444023baa6..0000000000 --- a/src/librustc_trait_selection/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_trait_selection" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_trait_selection" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_parse_format = { path = "../librustc_parse_format" } -tracing = "0.1" -rustc_attr = { path = "../librustc_attr" } -rustc_middle = { path = "../librustc_middle" } -rustc_ast = { path = "../librustc_ast" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_infer = { path = "../librustc_infer" } -rustc_macros = { path = "../librustc_macros" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_target = { path = "../librustc_target" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_trait_selection/traits/chalk_fulfill.rs b/src/librustc_trait_selection/traits/chalk_fulfill.rs deleted file mode 100644 index 0097097707..0000000000 --- a/src/librustc_trait_selection/traits/chalk_fulfill.rs +++ /dev/null @@ -1,267 +0,0 @@ -//! Defines a Chalk-based `TraitEngine` - -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferCtxt; -use crate::traits::query::NoSolution; -use crate::traits::{ - ChalkEnvironmentAndGoal, ChalkEnvironmentClause, FulfillmentError, FulfillmentErrorCode, - ObligationCause, PredicateObligation, SelectionError, TraitEngine, -}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, Ty, TyCtxt}; - -pub struct FulfillmentContext<'tcx> { - obligations: FxIndexSet>, -} - -impl FulfillmentContext<'tcx> { - crate fn new() -> Self { - FulfillmentContext { obligations: FxIndexSet::default() } - } -} - -fn environment<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, -) -> &'tcx ty::List> { - use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind}; - use rustc_middle::ty::subst::GenericArgKind; - - debug!("environment(def_id = {:?})", def_id); - - // The environment of an impl Trait type is its defining function's environment. - if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { - return environment(tcx, parent); - } - - // Compute the bounds on `Self` and the type parameters. - let ty::InstantiatedPredicates { predicates, .. } = - tcx.predicates_of(def_id).instantiate_identity(tcx); - - let clauses = predicates.into_iter().map(ChalkEnvironmentClause::Predicate); - - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let node = tcx.hir().get(hir_id); - - enum NodeKind { - TraitImpl, - InherentImpl, - Fn, - Other, - }; - - let node_kind = match node { - Node::TraitItem(item) => match item.kind { - TraitItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - Node::ImplItem(item) => match item.kind { - ImplItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - Node::Item(item) => match item.kind { - ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl, - ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl, - ItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - // FIXME: closures? - _ => NodeKind::Other, - }; - - // FIXME(eddyb) isn't the unordered nature of this a hazard? - let mut inputs = FxIndexSet::default(); - - match node_kind { - // In a trait impl, we assume that the header trait ref and all its - // constituents are well-formed. - NodeKind::TraitImpl => { - let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl"); - - // FIXME(chalk): this has problems because of late-bound regions - //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk())); - inputs.extend(trait_ref.substs.iter()); - } - - // In an inherent impl, we assume that the receiver type and all its - // constituents are well-formed. - NodeKind::InherentImpl => { - let self_ty = tcx.type_of(def_id); - inputs.extend(self_ty.walk()); - } - - // In an fn, we assume that the arguments and all their constituents are - // well-formed. - NodeKind::Fn => { - let fn_sig = tcx.fn_sig(def_id); - let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); - - inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); - } - - NodeKind::Other => (), - } - let input_clauses = inputs.into_iter().filter_map(|arg| { - match arg.unpack() { - GenericArgKind::Type(ty) => Some(ChalkEnvironmentClause::TypeFromEnv(ty)), - - // FIXME(eddyb) no WF conditions from lifetimes? - GenericArgKind::Lifetime(_) => None, - - // FIXME(eddyb) support const generics in Chalk - GenericArgKind::Const(_) => None, - } - }); - - tcx.mk_chalk_environment_clause_list(clauses.chain(input_clauses)) -} - -/// We need to wrap a `ty::Predicate` in an elaborated environment *before* we -/// canonicalize. This is due to the fact that we insert extra clauses into the -/// environment for all input types (`FromEnv`). -fn in_environment( - infcx: &InferCtxt<'_, 'tcx>, - obligation: &PredicateObligation<'tcx>, -) -> ChalkEnvironmentAndGoal<'tcx> { - assert!(!infcx.is_in_snapshot()); - let obligation = infcx.resolve_vars_if_possible(obligation); - - let environment = match obligation.param_env.def_id { - Some(def_id) => environment(infcx.tcx, def_id), - None if obligation.param_env.caller_bounds().is_empty() => ty::List::empty(), - // FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl - // and ui/generics/generic-static-methods - //_ => bug!("non-empty `ParamEnv` with no def-id"), - _ => ty::List::empty(), - }; - - ChalkEnvironmentAndGoal { environment, goal: obligation.predicate } -} - -impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { - fn normalize_projection_type( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - _param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - _cause: ObligationCause<'tcx>, - ) -> Ty<'tcx> { - infcx.tcx.mk_ty(ty::Projection(projection_ty)) - } - - fn register_predicate_obligation( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligation: PredicateObligation<'tcx>, - ) { - assert!(!infcx.is_in_snapshot()); - let obligation = infcx.resolve_vars_if_possible(&obligation); - - self.obligations.insert(obligation); - } - - fn select_all_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec>> { - self.select_where_possible(infcx)?; - - if self.obligations.is_empty() { - Ok(()) - } else { - let errors = self - .obligations - .iter() - .map(|obligation| FulfillmentError { - obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeAmbiguity, - points_at_arg_span: false, - }) - .collect(); - Err(errors) - } - } - - fn select_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec>> { - let mut errors = Vec::new(); - let mut next_round = FxIndexSet::default(); - let mut making_progress; - - loop { - making_progress = false; - - // We iterate over all obligations, and record if we are able - // to unambiguously prove at least one obligation. - for obligation in self.obligations.drain(..) { - let goal_in_environment = in_environment(infcx, &obligation); - let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = - infcx.canonicalize_query(&goal_in_environment, &mut orig_values); - - match infcx.tcx.evaluate_goal(canonical_goal) { - Ok(response) => { - if response.is_proven() { - making_progress = true; - - match infcx.instantiate_query_response_and_region_obligations( - &obligation.cause, - obligation.param_env, - &orig_values, - &response, - ) { - Ok(infer_ok) => next_round.extend( - infer_ok.obligations.into_iter().map(|obligation| { - assert!(!infcx.is_in_snapshot()); - infcx.resolve_vars_if_possible(&obligation) - }), - ), - - Err(_err) => errors.push(FulfillmentError { - obligation, - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), - points_at_arg_span: false, - }), - } - } else { - // Ambiguous: retry at next round. - next_round.insert(obligation); - } - } - - Err(NoSolution) => errors.push(FulfillmentError { - obligation, - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), - points_at_arg_span: false, - }), - } - } - next_round = std::mem::replace(&mut self.obligations, next_round); - - if !making_progress { - break; - } - } - - if errors.is_empty() { Ok(()) } else { Err(errors) } - } - - fn pending_obligations(&self) -> Vec> { - self.obligations.iter().cloned().collect() - } -} diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml deleted file mode 100644 index f5545f5629..0000000000 --- a/src/librustc_traits/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_traits" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_traits" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -chalk-ir = "0.14.0" -chalk-solve = "0.14.0" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_infer = { path = "../librustc_infer" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_traits/chalk/mod.rs b/src/librustc_traits/chalk/mod.rs deleted file mode 100644 index f18b4ca65f..0000000000 --- a/src/librustc_traits/chalk/mod.rs +++ /dev/null @@ -1,229 +0,0 @@ -//! Calls `chalk-solve` to solve a `ty::Predicate` -//! -//! In order to call `chalk-solve`, this file must convert a -//! `ChalkCanonicalGoal` into a Chalk ucanonical goal. It then calls Chalk, and -//! converts the answer back into rustc solution. - -crate mod db; -crate mod lowering; - -use rustc_data_structures::fx::FxHashMap; - -use rustc_index::vec::IndexVec; - -use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; -use rustc_middle::traits::ChalkRustInterner; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{ - self, Bound, BoundVar, ParamTy, Region, RegionKind, Ty, TyCtxt, TypeFoldable, -}; - -use rustc_infer::infer::canonical::{ - Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, -}; -use rustc_infer::traits::{self, ChalkCanonicalGoal}; - -use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase; -use crate::chalk::lowering::{LowerInto, ParamsSubstitutor}; - -use chalk_solve::Solution; - -crate fn provide(p: &mut Providers) { - *p = Providers { evaluate_goal, ..*p }; -} - -crate fn evaluate_goal<'tcx>( - tcx: TyCtxt<'tcx>, - obligation: ChalkCanonicalGoal<'tcx>, -) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> { - let interner = ChalkRustInterner { tcx }; - - // Chalk doesn't have a notion of `Params`, so instead we use placeholders. - let mut params_substitutor = ParamsSubstitutor::new(tcx); - let obligation = obligation.fold_with(&mut params_substitutor); - let _params: FxHashMap = params_substitutor.params; - let max_universe = obligation.max_universe.index(); - - let _lowered_goal: chalk_ir::UCanonical< - chalk_ir::InEnvironment>>, - > = chalk_ir::UCanonical { - canonical: chalk_ir::Canonical { - binders: chalk_ir::CanonicalVarKinds::from( - &interner, - obligation.variables.iter().map(|v| match v.kind { - CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(), - CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(), - CanonicalVarKind::Ty(ty) => match ty { - CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General), - chalk_ir::UniverseIndex { counter: ui.index() }, - ), - CanonicalTyVarKind::Int => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Integer), - chalk_ir::UniverseIndex::root(), - ), - CanonicalTyVarKind::Float => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Float), - chalk_ir::UniverseIndex::root(), - ), - }, - CanonicalVarKind::Region(ui) => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Lifetime, - chalk_ir::UniverseIndex { counter: ui.index() }, - ), - CanonicalVarKind::Const(_ui) => unimplemented!(), - CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(), - }), - ), - value: obligation.value.lower_into(&interner), - }, - universes: max_universe + 1, - }; - - let solver_choice = chalk_solve::SolverChoice::SLG { max_size: 32, expected_answers: None }; - let mut solver = solver_choice.into_solver::>(); - - let db = ChalkRustIrDatabase { tcx, interner }; - let solution = solver.solve(&db, &_lowered_goal); - - // Ideally, the code to convert *back* to rustc types would live close to - // the code to convert *from* rustc types. Right now though, we don't - // really need this and so it's really minimal. - // Right now, we also treat a `Unique` solution the same as - // `Ambig(Definite)`. This really isn't right. - let make_solution = |_subst: chalk_ir::Substitution<_>| { - let mut var_values: IndexVec> = IndexVec::new(); - _subst.parameters(&interner).iter().for_each(|p| { - // FIXME(chalk): we should move this elsewhere, since this is - // essentially inverse of lowering a `GenericArg`. - let _data = p.data(&interner); - match _data { - chalk_ir::GenericArgData::Ty(_t) => { - use chalk_ir::TyData; - use rustc_ast as ast; - - let _data = _t.data(&interner); - let kind = match _data { - TyData::Apply(_application_ty) => match _application_ty.name { - chalk_ir::TypeName::Adt(_struct_id) => unimplemented!(), - chalk_ir::TypeName::Scalar(scalar) => match scalar { - chalk_ir::Scalar::Bool => ty::Bool, - chalk_ir::Scalar::Char => ty::Char, - chalk_ir::Scalar::Int(int_ty) => match int_ty { - chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize), - chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8), - chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16), - chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32), - chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64), - chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128), - }, - chalk_ir::Scalar::Uint(int_ty) => match int_ty { - chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize), - chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8), - chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16), - chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32), - chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64), - chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128), - }, - chalk_ir::Scalar::Float(float_ty) => match float_ty { - chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32), - chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64), - }, - }, - chalk_ir::TypeName::Array => unimplemented!(), - chalk_ir::TypeName::FnDef(_) => unimplemented!(), - chalk_ir::TypeName::Closure(_) => unimplemented!(), - chalk_ir::TypeName::Never => unimplemented!(), - chalk_ir::TypeName::Tuple(_size) => unimplemented!(), - chalk_ir::TypeName::Slice => unimplemented!(), - chalk_ir::TypeName::Raw(_) => unimplemented!(), - chalk_ir::TypeName::Ref(_) => unimplemented!(), - chalk_ir::TypeName::Str => unimplemented!(), - chalk_ir::TypeName::OpaqueType(_ty) => unimplemented!(), - chalk_ir::TypeName::AssociatedType(_assoc_ty) => unimplemented!(), - chalk_ir::TypeName::Error => unimplemented!(), - }, - TyData::Placeholder(_placeholder) => { - unimplemented!(); - } - TyData::Alias(_alias_ty) => unimplemented!(), - TyData::Function(_quantified_ty) => unimplemented!(), - TyData::BoundVar(_bound) => Bound( - ty::DebruijnIndex::from_usize(_bound.debruijn.depth() as usize), - ty::BoundTy { - var: ty::BoundVar::from_usize(_bound.index), - kind: ty::BoundTyKind::Anon, - }, - ), - TyData::InferenceVar(_, _) => unimplemented!(), - TyData::Dyn(_) => unimplemented!(), - }; - let _ty: Ty<'_> = tcx.mk_ty(kind); - let _arg: GenericArg<'_> = _ty.into(); - var_values.push(_arg); - } - chalk_ir::GenericArgData::Lifetime(_l) => { - let _data = _l.data(&interner); - let _lifetime: Region<'_> = match _data { - chalk_ir::LifetimeData::BoundVar(_var) => { - tcx.mk_region(RegionKind::ReLateBound( - rustc_middle::ty::DebruijnIndex::from_usize( - _var.debruijn.depth() as usize - ), - rustc_middle::ty::BoundRegion::BrAnon(_var.index as u32), - )) - } - chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), - chalk_ir::LifetimeData::Placeholder(_index) => unimplemented!(), - chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(), - }; - let _arg: GenericArg<'_> = _lifetime.into(); - var_values.push(_arg); - } - chalk_ir::GenericArgData::Const(_) => unimplemented!(), - } - }); - let sol = Canonical { - max_universe: ty::UniverseIndex::from_usize(0), - variables: obligation.variables.clone(), - value: QueryResponse { - var_values: CanonicalVarValues { var_values }, - region_constraints: QueryRegionConstraints::default(), - certainty: Certainty::Proven, - value: (), - }, - }; - &*tcx.arena.alloc(sol) - }; - solution - .map(|s| match s { - Solution::Unique(_subst) => { - // FIXME(chalk): handle constraints - make_solution(_subst.value.subst) - } - Solution::Ambig(_guidance) => { - match _guidance { - chalk_solve::Guidance::Definite(_subst) => make_solution(_subst.value), - chalk_solve::Guidance::Suggested(_) => unimplemented!(), - chalk_solve::Guidance::Unknown => { - // chalk_fulfill doesn't use the var_values here, so - // let's just ignore that - let sol = Canonical { - max_universe: ty::UniverseIndex::from_usize(0), - variables: obligation.variables.clone(), - value: QueryResponse { - var_values: CanonicalVarValues { var_values: IndexVec::new() } - .make_identity(tcx), - region_constraints: QueryRegionConstraints::default(), - certainty: Certainty::Ambiguous, - value: (), - }, - }; - &*tcx.arena.alloc(sol) - } - } - } - }) - .ok_or(traits::query::NoSolution) -} diff --git a/src/librustc_ty/Cargo.toml b/src/librustc_ty/Cargo.toml deleted file mode 100644 index adc9740c2c..0000000000 --- a/src/librustc_ty/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ty" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ty" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_infer = { path = "../librustc_infer" } -rustc_span = { path = "../librustc_span" } -rustc_session = { path = "../librustc_session" } -rustc_target = { path = "../librustc_target" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml deleted file mode 100644 index 82c6ac7a0c..0000000000 --- a/src/librustc_typeck/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_typeck" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_typeck" -path = "lib.rs" -test = false -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } -rustc_target = { path = "../librustc_target" } -rustc_session = { path = "../librustc_session" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_index = { path = "../librustc_index" } -rustc_infer = { path = "../librustc_infer" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 1354ef5cbd..a40a44fe27 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -5,15 +5,17 @@ version = "0.0.0" edition = "2018" [lib] -name = "rustdoc" path = "lib.rs" [dependencies] -pulldown-cmark = { version = "0.7", default-features = false } +pulldown-cmark = { version = "0.8", default-features = false } minifier = "0.0.33" rayon = { version = "0.3.0", package = "rustc-rayon" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.0" tempfile = "3" -itertools = "0.8" +itertools = "0.9" + +[dev-dependencies] +expect-test = "1.0" diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 3d2785541b..de5a9a6155 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { ); let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap(); let may_apply = self.cx.tcx.infer_ctxt().enter(|infcx| { - match trait_ref.self_ty().kind { + match trait_ref.self_ty().kind() { ty::Param(_) => {} _ => return false, } @@ -75,8 +75,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { } }); debug!( - "get_blanket_impls: found applicable impl: {}\ - for trait_ref={:?}, ty={:?}", + "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}", may_apply, trait_ref, ty ); if !may_apply { diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index ab0b332ee1..c039b18117 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -135,7 +135,7 @@ impl Cfg { /// Renders the configuration for human display, as a short HTML description. pub(crate) fn render_short_html(&self) -> String { - let mut msg = Html(self, true).to_string(); + let mut msg = Display(self, Format::ShortHtml).to_string(); if self.should_capitalize_first_letter() { if let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) { msg[i..i + 1].make_ascii_uppercase(); @@ -148,7 +148,11 @@ impl Cfg { pub(crate) fn render_long_html(&self) -> String { let on = if self.should_use_with_in_description() { "with" } else { "on" }; - let mut msg = format!("This is supported {} {}", on, Html(self, false)); + let mut msg = format!( + "This is supported {} {}", + on, + Display(self, Format::LongHtml) + ); if self.should_append_only_to_description() { msg.push_str(" only"); } @@ -156,6 +160,17 @@ impl Cfg { msg } + /// Renders the configuration for long display, as a long plain text description. + pub(crate) fn render_long_plain(&self) -> String { + let on = if self.should_use_with_in_description() { "with" } else { "on" }; + + let mut msg = format!("This is supported {} {}", on, Display(self, Format::LongPlain)); + if self.should_append_only_to_description() { + msg.push_str(" only"); + } + msg + } + fn should_capitalize_first_letter(&self) -> bool { match *self { Cfg::False | Cfg::True | Cfg::Not(..) => true, @@ -286,9 +301,31 @@ impl ops::BitOr for Cfg { } } -/// Pretty-print wrapper for a `Cfg`. Also indicates whether the "short-form" rendering should be -/// used. -struct Html<'a>(&'a Cfg, bool); +#[derive(Clone, Copy)] +enum Format { + LongHtml, + LongPlain, + ShortHtml, +} + +impl Format { + fn is_long(self) -> bool { + match self { + Format::LongHtml | Format::LongPlain => true, + Format::ShortHtml => false, + } + } + + fn is_html(self) -> bool { + match self { + Format::LongHtml | Format::ShortHtml => true, + Format::LongPlain => false, + } + } +} + +/// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used. +struct Display<'a>(&'a Cfg, Format); fn write_with_opt_paren( fmt: &mut fmt::Formatter<'_>, @@ -305,7 +342,7 @@ fn write_with_opt_paren( Ok(()) } -impl<'a> fmt::Display for Html<'a> { +impl<'a> fmt::Display for Display<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match *self.0 { Cfg::Not(ref child) => match **child { @@ -314,31 +351,86 @@ impl<'a> fmt::Display for Html<'a> { if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " }; for (i, sub_cfg) in sub_cfgs.iter().enumerate() { fmt.write_str(if i == 0 { "neither " } else { separator })?; - write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?; + write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?; } Ok(()) } - ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple, self.1)), - ref c => write!(fmt, "not ({})", Html(c, self.1)), + ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Display(simple, self.1)), + ref c => write!(fmt, "not ({})", Display(c, self.1)), }, Cfg::Any(ref sub_cfgs) => { let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " }; + + let short_longhand = self.1.is_long() && { + let all_crate_features = sub_cfgs + .iter() + .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_)))); + let all_target_features = sub_cfgs + .iter() + .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_)))); + + if all_crate_features { + fmt.write_str("crate features ")?; + true + } else if all_target_features { + fmt.write_str("target features ")?; + true + } else { + false + } + }; + for (i, sub_cfg) in sub_cfgs.iter().enumerate() { if i != 0 { fmt.write_str(separator)?; } - write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?; + if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { + if self.1.is_html() { + write!(fmt, "{}", feat)?; + } else { + write!(fmt, "`{}`", feat)?; + } + } else { + write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?; + } } Ok(()) } Cfg::All(ref sub_cfgs) => { + let short_longhand = self.1.is_long() && { + let all_crate_features = sub_cfgs + .iter() + .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_)))); + let all_target_features = sub_cfgs + .iter() + .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_)))); + + if all_crate_features { + fmt.write_str("crate features ")?; + true + } else if all_target_features { + fmt.write_str("target features ")?; + true + } else { + false + } + }; + for (i, sub_cfg) in sub_cfgs.iter().enumerate() { if i != 0 { fmt.write_str(" and ")?; } - write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg, self.1))?; + if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { + if self.1.is_html() { + write!(fmt, "{}", feat)?; + } else { + write!(fmt, "`{}`", feat)?; + } + } else { + write_with_opt_paren(fmt, !sub_cfg.is_simple(), Display(sub_cfg, self.1))?; + } } Ok(()) } @@ -406,26 +498,39 @@ impl<'a> fmt::Display for Html<'a> { }, (sym::target_endian, Some(endian)) => return write!(fmt, "{}-endian", endian), (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{}-bit", bits), - (sym::target_feature, Some(feat)) => { - if self.1 { - return write!(fmt, "{}", feat); - } else { + (sym::target_feature, Some(feat)) => match self.1 { + Format::LongHtml => { return write!(fmt, "target feature {}", feat); } - } + Format::LongPlain => return write!(fmt, "target feature `{}`", feat), + Format::ShortHtml => return write!(fmt, "{}", feat), + }, + (sym::feature, Some(feat)) => match self.1 { + Format::LongHtml => { + return write!(fmt, "crate feature {}", feat); + } + Format::LongPlain => return write!(fmt, "crate feature `{}`", feat), + Format::ShortHtml => return write!(fmt, "{}", feat), + }, _ => "", }; if !human_readable.is_empty() { fmt.write_str(human_readable) } else if let Some(v) = value { - write!( - fmt, - "{}=\"{}\"", - Escape(&name.as_str()), - Escape(&v.as_str()) - ) - } else { + if self.1.is_html() { + write!( + fmt, + r#"{}="{}""#, + Escape(&name.as_str()), + Escape(&v.as_str()) + ) + } else { + write!(fmt, r#"`{}="{}"`"#, name, v) + } + } else if self.1.is_html() { write!(fmt, "{}", Escape(&name.as_str())) + } else { + write!(fmt, "`{}`", name) } } } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 96f0a1b7a7..794a7bcaf1 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -391,26 +391,25 @@ fn test_render_long_html() { (word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")) .render_long_html(), "This is supported on Unix and Windows and debug-assertions enabled\ - only." + only." ); assert_eq!( (word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")) .render_long_html(), "This is supported on Unix or Windows or debug-assertions enabled\ - only." + only." ); assert_eq!( (!(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))) .render_long_html(), "This is supported on neither Unix nor Windows nor debug-assertions \ - enabled." + enabled." ); assert_eq!( ((word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) | (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))) .render_long_html(), - "This is supported on Unix and x86-64, or Windows and 64-bit \ - only." + "This is supported on Unix and x86-64, or Windows and 64-bit only." ); assert_eq!( (!(word_cfg("unix") & word_cfg("windows"))).render_long_html(), @@ -420,7 +419,7 @@ fn test_render_long_html() { ((word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")) .render_long_html(), "This is supported on (debug-assertions enabled or Windows) and Unix\ - only." + only." ); assert_eq!( name_value_cfg("target_feature", "sse2").render_long_html(), @@ -430,7 +429,7 @@ fn test_render_long_html() { (name_value_cfg("target_arch", "x86_64") & name_value_cfg("target_feature", "sse2")) .render_long_html(), "This is supported on x86-64 and target feature \ - sse2 only." + sse2 only." ); }) } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f67b689bb0..31e8c32f06 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -306,15 +306,17 @@ fn merge_attrs( attrs: Attrs<'_>, other_attrs: Option>, ) -> clean::Attributes { - let mut merged_attrs: Vec = Vec::with_capacity(attrs.len()); - // If we have additional attributes (from a re-export), + // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export // doc comments show up before the original doc comments // when we render them. - if let Some(a) = other_attrs { - merged_attrs.extend(a.iter().cloned()); - } - merged_attrs.extend(attrs.to_vec()); + let merged_attrs = if let Some(inner) = other_attrs { + let mut both = inner.to_vec(); + both.extend_from_slice(attrs); + both + } else { + attrs.to_vec() + }; merged_attrs.clean(cx) } @@ -350,14 +352,22 @@ pub fn build_impl( } } - let for_ = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { self_ty, .. } => self_ty.clean(cx), - _ => panic!("did given to build_impl was not an impl"), + let impl_item = match did.as_local() { + Some(did) => { + let hir_id = tcx.hir().local_def_id_to_hir_id(did); + match tcx.hir().expect_item(hir_id).kind { + hir::ItemKind::Impl { self_ty, ref generics, ref items, .. } => { + Some((self_ty, generics, items)) + } + _ => panic!("`DefID` passed to `build_impl` is not an `impl"), + } } - } else { - tcx.type_of(did).clean(cx) + None => None, + }; + + let for_ = match impl_item { + Some((self_ty, _, _)) => self_ty.clean(cx), + None => tcx.type_of(did).clean(cx), }; // Only inline impl if the implementing type is @@ -377,17 +387,12 @@ pub fn build_impl( } let predicates = tcx.explicit_predicates_of(did); - let (trait_items, generics) = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { ref generics, ref items, .. } => ( - items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), - generics.clean(cx), - ), - _ => panic!("did given to build_impl was not an impl"), - } - } else { - ( + let (trait_items, generics) = match impl_item { + Some((_, generics, items)) => ( + items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), + generics.clean(cx), + ), + None => ( tcx.associated_items(did) .in_definition_order() .filter_map(|item| { @@ -399,7 +404,7 @@ pub fn build_impl( }) .collect::>(), clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)), - ) + ), }; let polarity = tcx.impl_polarity(did); let trait_ = associated_trait.clean(cx).map(|bound| match bound { @@ -629,7 +634,9 @@ pub fn record_extern_trait(cx: &DocContext<'_>, did: DefId) { } } - cx.active_extern_traits.borrow_mut().insert(did); + { + cx.active_extern_traits.borrow_mut().insert(did); + } debug!("record_extern_trait: {:?}", did); let trait_ = build_external_trait(cx, did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 14e0fa7eab..788bb5e787 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::middle::stability; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; -use rustc_mir::const_eval::is_min_const_fn; +use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, Pos}; @@ -256,7 +256,7 @@ impl Clean for doctree::Module<'_> { // determine if we should display the inner contents or // the outer `mod` item for the source code. - let whence = { + let span = { let sm = cx.sess().source_map(); let outer = sm.lookup_char_pos(self.where_outer.lo()); let inner = sm.lookup_char_pos(self.where_inner.lo()); @@ -272,7 +272,7 @@ impl Clean for doctree::Module<'_> { Item { name: Some(name), attrs, - source: whence.clean(cx), + source: span.clean(cx), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), @@ -508,7 +508,8 @@ impl<'a> Clean> for ty::Predicate<'a> { | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => panic!("not user writable"), + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => panic!("not user writable"), } } } @@ -764,17 +765,17 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx let param_idx = (|| { match p.skip_binders() { ty::PredicateAtom::Trait(pred, _constness) => { - if let ty::Param(param) = pred.self_ty().kind { + if let ty::Param(param) = pred.self_ty().kind() { return Some(param.index); } } ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { - if let ty::Param(param) = ty.kind { + if let ty::Param(param) = ty.kind() { return Some(param.index); } } ty::PredicateAtom::Projection(p) => { - if let ty::Param(param) = p.projection_ty.self_ty().kind { + if let ty::Param(param) = p.projection_ty.self_ty().kind() { projection = Some(ty::Binder::bind(p)); return Some(param.index); } @@ -839,7 +840,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx let mut where_predicates = where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::>(); - // Type parameters and have a Sized bound by default unless removed with + // Type parameters have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with // a Sized bound, removing the bounds as we find them. // @@ -900,7 +901,9 @@ impl Clean for doctree::Function<'_> { enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx))); let did = cx.tcx.hir().local_def_id(self.id); - let constness = if is_min_const_fn(cx.tcx, did.to_def_id()) { + let constness = if is_const_fn(cx.tcx, did.to_def_id()) + && !is_unstable_const_fn(cx.tcx, did.to_def_id()).is_some() + { hir::Constness::Const } else { hir::Constness::NotConst @@ -909,7 +912,7 @@ impl Clean for doctree::Function<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), @@ -1017,7 +1020,7 @@ impl Clean for doctree::Trait<'_> { Item { name: Some(self.name.clean(cx)), attrs, - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1041,7 +1044,7 @@ impl Clean for doctree::TraitAlias<'_> { Item { name: Some(self.name.clean(cx)), attrs, - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1108,7 +1111,7 @@ impl Clean for hir::TraitItem<'_> { hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let mut m = (sig, &self.generics, body, None).clean(cx); if m.header.constness == hir::Constness::Const - && !is_min_const_fn(cx.tcx, local_did.to_def_id()) + && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { m.header.constness = hir::Constness::NotConst; } @@ -1121,7 +1124,7 @@ impl Clean for hir::TraitItem<'_> { let (all_types, ret_types) = get_all_types(&generics, &decl, cx); let mut t = TyMethod { header: sig.header, decl, generics, all_types, ret_types }; if t.header.constness == hir::Constness::Const - && !is_min_const_fn(cx.tcx, local_did.to_def_id()) + && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { t.header.constness = hir::Constness::NotConst; } @@ -1154,7 +1157,7 @@ impl Clean for hir::ImplItem<'_> { hir::ImplItemKind::Fn(ref sig, body) => { let mut m = (sig, &self.generics, body, Some(self.defaultness)).clean(cx); if m.header.constness == hir::Constness::Const - && !is_min_const_fn(cx.tcx, local_did.to_def_id()) + && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { m.header.constness = hir::Constness::NotConst; } @@ -1206,7 +1209,7 @@ impl Clean for ty::AssocItem { let self_arg_ty = sig.input(0).skip_binder(); if self_arg_ty == self_ty { decl.inputs.values[0].type_ = Generic(String::from("Self")); - } else if let ty::Ref(_, ty, _) = self_arg_ty.kind { + } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { if ty == self_ty { match decl.inputs.values[0].type_ { BorrowedRef { ref mut type_, .. } => { @@ -1364,16 +1367,16 @@ impl Clean for hir::Ty<'_> { TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), TyKind::Array(ref ty, ref length) => { let def_id = cx.tcx.hir().local_def_id(length.hir_id); - let length = match cx.tcx.const_eval_poly(def_id.to_def_id()) { - Ok(length) => { - print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize)) - } - Err(_) => cx - .sess() - .source_map() - .span_to_snippet(cx.tcx.def_span(def_id)) - .unwrap_or_else(|_| "_".to_string()), - }; + // NOTE(min_const_generics): We can't use `const_eval_poly` for constants + // as we currently do not supply the parent generics to anonymous constants + // but do allow `ConstKind::Param`. + // + // `const_eval_poly` tries to to first substitute generic parameters which + // results in an ICE while manually constructing the constant and using `eval` + // does nothing for `ConstKind::Param`. + let ct = ty::Const::from_anon_const(cx.tcx, def_id); + let param_env = cx.tcx.param_env(def_id); + let length = print_const(cx, ct.eval(cx.tcx, param_env)); Array(box ty.clean(cx), length) } TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), @@ -1511,7 +1514,7 @@ impl Clean for hir::Ty<'_> { TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { let mut res = Res::Err; let ty = hir_ty_to_ty(cx.tcx, self); - if let ty::Projection(proj) = ty.kind { + if let ty::Projection(proj) = ty.kind() { res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id); } let trait_path = hir::Path { span: self.span, res, segments: &[] }; @@ -1554,7 +1557,7 @@ impl Clean for hir::Ty<'_> { impl<'tcx> Clean for Ty<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> Type { debug!("cleaning type: {:?}", self); - match self.kind { + match *self.kind() { ty::Never => Never, ty::Bool => Primitive(PrimitiveType::Bool), ty::Char => Primitive(PrimitiveType::Char), @@ -1827,7 +1830,7 @@ impl Clean for doctree::Struct<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1847,7 +1850,7 @@ impl Clean for doctree::Union<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1877,7 +1880,7 @@ impl Clean for doctree::Enum<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1896,7 +1899,7 @@ impl Clean for doctree::Variant<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: Inherited, stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), @@ -2044,7 +2047,7 @@ impl Clean for doctree::Typedef<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2059,7 +2062,7 @@ impl Clean for doctree::OpaqueTy<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2090,7 +2093,7 @@ impl Clean for doctree::Static<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2111,7 +2114,7 @@ impl Clean for doctree::Constant<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2165,7 +2168,7 @@ impl Clean> for doctree::Impl<'_> { let make_item = |trait_: Option, for_: Type, items: Vec| Item { name: None, attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2216,7 +2219,7 @@ impl Clean> for doctree::ExternCrate<'_> { vec![Item { name: None, attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX }, visibility: self.vis.clean(cx), stability: None, @@ -2281,7 +2284,7 @@ impl Clean> for doctree::Import<'_> { vec![Item { name: None, attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: DefId::local(CRATE_DEF_INDEX), visibility: self.vis.clean(cx), stability: None, @@ -2323,7 +2326,7 @@ impl Clean for doctree::ForeignItem<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2339,7 +2342,7 @@ impl Clean for doctree::Macro<'_> { Item { name: Some(name.clone()), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: Public, stability: cx.stability(self.hid).clean(cx), deprecation: cx.deprecation(self.hid).clean(cx), @@ -2364,7 +2367,7 @@ impl Clean for doctree::ProcMacro<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: Public, stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a458cdab30..8fbfb04bac 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -118,7 +118,7 @@ impl Item { self.attrs.collapsed_doc_value() } - pub fn links(&self) -> Vec<(String, String)> { + pub fn links(&self) -> Vec { self.attrs.links(&self.def_id.krate) } @@ -425,10 +425,38 @@ pub struct Attributes { pub cfg: Option>, pub span: Option, /// map from Rust paths to resolved defs and potential URL fragments - pub links: Vec<(String, Option, Option)>, + pub links: Vec, pub inner_docs: bool, } +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +/// A link that has not yet been rendered. +/// +/// This link will be turned into a rendered link by [`Attributes::links`] +pub struct ItemLink { + /// The original link written in the markdown + pub(crate) link: String, + /// The link text displayed in the HTML. + /// + /// 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: Option, + /// The url fragment to append to the link + pub(crate) fragment: Option, +} + +pub struct RenderedLink { + /// The text the link was original written as. + /// + /// This could potentially include disambiguators and backticks. + pub(crate) original_text: String, + /// The text to display in the HTML + pub(crate) new_text: String, + /// The URL to put in the `href` + pub(crate) href: String, +} + impl Attributes { /// Extracts the content from an attribute `#[doc(cfg(content))]`. pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { @@ -605,21 +633,25 @@ impl Attributes { /// Gets links as a vector /// /// Cache must be populated before call - pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> { + pub fn links(&self, krate: &CrateNum) -> Vec { use crate::html::format::href; use crate::html::render::CURRENT_DEPTH; self.links .iter() - .filter_map(|&(ref s, did, ref fragment)| { - match did { + .filter_map(|ItemLink { link: s, link_text, did, fragment }| { + match *did { Some(did) => { if let Some((mut href, ..)) = href(did) { if let Some(ref fragment) = *fragment { href.push_str("#"); href.push_str(fragment); } - Some((s.clone(), href)) + Some(RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href, + }) } else { None } @@ -639,16 +671,17 @@ impl Attributes { }; // This is a primitive so the url is done "by hand". let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); - Some(( - s.clone(), - format!( + Some(RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href: format!( "{}{}std/primitive.{}.html{}", url, if !url.ends_with('/') { "/" } else { "" }, &fragment[..tail], &fragment[tail..] ), - )) + }) } else { panic!("This isn't a primitive?!"); } @@ -662,7 +695,7 @@ impl Attributes { self.other_attrs .lists(sym::doc) .filter(|a| a.has_name(sym::alias)) - .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) + .filter_map(|a| a.value_str().map(|s| s.to_string())) .filter(|v| !v.is_empty()) .collect::>() } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 75fdcd5ec1..58b76d24a5 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -130,7 +130,7 @@ pub fn external_generic_args( None } GenericArgKind::Type(ty) => { - ty_kind = Some(&ty.kind); + ty_kind = Some(ty.kind()); Some(GenericArg::Type(ty.clean(cx))) } GenericArgKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), @@ -422,14 +422,13 @@ pub fn name_from_pat(p: &hir::Pat<'_>) -> String { PatKind::Ref(ref p, _) => name_from_pat(&**p), PatKind::Lit(..) => { warn!( - "tried to get argument name from PatKind::Lit, \ - which is silly in function arguments" + "tried to get argument name from PatKind::Lit, which is silly in function arguments" ); "()".to_string() } PatKind::Range(..) => panic!( "tried to get argument name from PatKind::Range, \ - which is not allowed in function arguments" + which is not allowed in function arguments" ), PatKind::Slice(ref begin, ref mid, ref end) => { let begin = begin.iter().map(|p| name_from_pat(&**p)); @@ -473,7 +472,7 @@ pub fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { pub fn print_evaluated_const(cx: &DocContext<'_>, def_id: DefId) -> Option { cx.tcx.const_eval_poly(def_id).ok().and_then(|val| { let ty = cx.tcx.type_of(def_id); - match (val, &ty.kind) { + match (val, ty.kind()) { (_, &ty::Ref(..)) => None, (ConstValue::Scalar(_), &ty::Adt(_, _)) => None, (ConstValue::Scalar(_), _) => { @@ -498,7 +497,7 @@ fn format_integer_with_underscore_sep(num: &str) -> String { fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const<'tcx>) -> 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.val, &ct.ty.kind) { + match (ct.val, ct.ty.kind()) { (ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })), ty::Uint(ui)) => { format!("{}{}", format_integer_with_underscore_sep(&data.to_string()), ui.name_str()) } @@ -602,7 +601,7 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { }, Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias), Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), - Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id, + Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id, _ => return res.def_id(), }; if did.is_local() { diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 4f751decc8..a5fc075781 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -83,9 +83,9 @@ pub struct Options { /// Codegen options strings to hand to the compiler. pub codegen_options_strs: Vec, /// Debugging (`-Z`) options to pass to the compiler. - pub debugging_options: DebuggingOptions, + pub debugging_opts: DebuggingOptions, /// Debugging (`-Z`) options strings to pass to the compiler. - pub debugging_options_strs: Vec, + pub debugging_opts_strs: Vec, /// The target used to compile the crate against. pub target: TargetTriple, /// Edition used when reading the crate. Defaults to "2015". Also used by default when @@ -318,9 +318,9 @@ impl Options { let error_format = config::parse_error_format(&matches, color, json_rendered); let codegen_options = build_codegen_options(matches, error_format); - let debugging_options = build_debugging_options(matches, error_format); + let debugging_opts = build_debugging_options(matches, error_format); - let diag = new_handler(error_format, None, &debugging_options); + let diag = new_handler(error_format, None, &debugging_opts); // check for deprecated options check_deprecated_options(&matches, &diag); @@ -365,7 +365,7 @@ impl Options { .iter() .map(|s| SearchPath::from_cli_opt(s, error_format)) .collect(); - let externs = parse_externs(&matches, &debugging_options, error_format); + let externs = parse_externs(&matches, &debugging_opts, error_format); let extern_html_root_urls = match parse_extern_html_roots(&matches) { Ok(ex) => ex, Err(err) => { @@ -416,14 +416,12 @@ impl Options { return Err(1); } else if !ret.is_empty() { diag.struct_warn(&format!( - "theme file \"{}\" is missing CSS rules from the \ - default theme", + "theme file \"{}\" is missing CSS rules from the default theme", theme_s )) .warn("the theme may appear incorrect when loaded") .help(&format!( - "to see what rules are missing, call `rustdoc \ - --check-theme \"{}\"`", + "to see what rules are missing, call `rustdoc --check-theme \"{}\"`", theme_s )) .emit(); @@ -546,7 +544,7 @@ impl Options { let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from); let test_builder = matches.opt_str("test-builder").map(PathBuf::from); let codegen_options_strs = matches.opt_strs("C"); - let debugging_options_strs = matches.opt_strs("Z"); + let debugging_opts_strs = matches.opt_strs("Z"); let lib_strs = matches.opt_strs("L"); let extern_strs = matches.opt_strs("extern"); let runtool = matches.opt_str("runtool"); @@ -569,8 +567,8 @@ impl Options { cfgs, codegen_options, codegen_options_strs, - debugging_options, - debugging_options_strs, + debugging_opts, + debugging_opts_strs, target, edition, maybe_sysroot, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7a0cf3717c..391859050e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -234,7 +234,7 @@ pub fn new_handler( /// It returns a tuple containing: /// * Vector of tuples of lints' name and their associated "max" level /// * HashMap of lint id with their associated "max" level -pub fn init_lints( +pub(crate) fn init_lints( mut allowed_lints: Vec, lint_opts: Vec<(String, lint::Level)>, filter_call: F, @@ -257,7 +257,7 @@ where .filter_map(|lint| { // Permit feature-gated lints to avoid feature errors when trying to // allow all lints. - if lint.name == warnings_lint_name || lint.feature_gate.is_some() { + if lint.feature_gate.is_some() || allowed_lints.iter().any(|l| lint.name == l) { None } else { filter_call(lint) @@ -294,7 +294,7 @@ pub fn run_core( externs, mut cfgs, codegen_options, - debugging_options, + debugging_opts, target, edition, maybe_sysroot, @@ -328,19 +328,23 @@ pub fn run_core( let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name; let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name; let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name; + let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name; + let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name; // In addition to those specific lints, we also need to allow those given through // command line, otherwise they'll get ignored and we don't want that. - let allowed_lints = vec![ + let lints_to_show = vec![ intra_link_resolution_failure_name.to_owned(), missing_docs.to_owned(), missing_doc_example.to_owned(), private_doc_tests.to_owned(), no_crate_level_docs.to_owned(), invalid_codeblock_attributes_name.to_owned(), + renamed_and_removed_lints.to_owned(), + unknown_lints.to_owned(), ]; - let (lint_opts, lint_caps) = init_lints(allowed_lints, lint_opts, |lint| { + let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| { if lint.name == intra_link_resolution_failure_name || lint.name == invalid_codeblock_attributes_name { @@ -358,13 +362,13 @@ pub fn run_core( search_paths: libs, crate_types, lint_opts: if !display_warnings { lint_opts } else { vec![] }, - lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)), + lint_cap, cg: codegen_options, externs, target_triple: target, unstable_features: UnstableFeatures::from_environment(), actually_rustdoc: true, - debugging_opts: debugging_options, + debugging_opts, error_format, edition, describe_lints, @@ -415,6 +419,7 @@ pub fn run_core( (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id) }; }), + make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), }; @@ -435,6 +440,7 @@ pub fn run_core( resolver.borrow_mut().access(|resolver| { sess.time("load_extern_crates", || { for extern_name in &extern_names { + debug!("loading extern crate {}", extern_name); resolver .resolve_str_path_error( DUMMY_SP, @@ -556,8 +562,7 @@ fn run_global_ctxt( if let Some(ref m) = krate.module { if let None | Some("") = m.doc_value() { let help = "The following guide may be of use:\n\ - https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation\ - .html"; + https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html"; tcx.struct_lint_node( rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS, ctxt.as_local_hir_id(m.def_id).unwrap(), @@ -576,7 +581,7 @@ fn run_global_ctxt( .struct_warn(&format!("the `#![doc({})]` attribute is considered deprecated", name)); msg.warn( "see issue #44136 \ - for more information", + for more information", ); if name == "no_default_passes" { @@ -609,7 +614,7 @@ fn run_global_ctxt( report_deprecated_attr("plugins = \"...\"", diag); eprintln!( "WARNING: `#![doc(plugins = \"...\")]` \ - no longer functions; see CVE-2018-1000622" + no longer functions; see CVE-2018-1000622" ); continue; } diff --git a/src/librustdoc/test.rs b/src/librustdoc/doctest.rs similarity index 99% rename from src/librustdoc/test.rs rename to src/librustdoc/doctest.rs index 693d5b9fb0..7a6c9eabb5 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/doctest.rs @@ -95,6 +95,7 @@ pub fn run(options: Options) -> Result<(), ErrorReported> { lint_caps, register_lints: None, override_queries: None, + make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), }; @@ -281,7 +282,7 @@ fn run_test( for codegen_options_str in &options.codegen_options_strs { compiler.arg("-C").arg(&codegen_options_str); } - for debugging_option_str in &options.debugging_options_strs { + for debugging_option_str in &options.debugging_opts_strs { compiler.arg("-Z").arg(&debugging_option_str); } if no_run && !compile_fail { diff --git a/src/librustdoc/test/tests.rs b/src/librustdoc/doctest/tests.rs similarity index 100% rename from src/librustdoc/test/tests.rs rename to src/librustdoc/doctest/tests.rs diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 98125adbde..cfa51dcf4f 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -89,7 +89,7 @@ pub struct Struct<'hir> { pub generics: &'hir hir::Generics<'hir>, pub attrs: &'hir [ast::Attribute], pub fields: &'hir [hir::StructField<'hir>], - pub whence: Span, + pub span: Span, } pub struct Union<'hir> { @@ -100,7 +100,7 @@ pub struct Union<'hir> { pub generics: &'hir hir::Generics<'hir>, pub attrs: &'hir [ast::Attribute], pub fields: &'hir [hir::StructField<'hir>], - pub whence: Span, + pub span: Span, } pub struct Enum<'hir> { @@ -109,7 +109,7 @@ pub struct Enum<'hir> { pub generics: &'hir hir::Generics<'hir>, pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, - pub whence: Span, + pub span: Span, pub name: Symbol, } @@ -118,7 +118,7 @@ pub struct Variant<'hir> { pub id: hir::HirId, pub attrs: &'hir [ast::Attribute], pub def: &'hir hir::VariantData<'hir>, - pub whence: Span, + pub span: Span, } pub struct Function<'hir> { @@ -128,7 +128,7 @@ pub struct Function<'hir> { pub name: Symbol, pub vis: &'hir hir::Visibility<'hir>, pub header: hir::FnHeader, - pub whence: Span, + pub span: Span, pub generics: &'hir hir::Generics<'hir>, pub body: hir::BodyId, } @@ -139,7 +139,7 @@ pub struct Typedef<'hir> { pub name: Symbol, pub id: hir::HirId, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -148,7 +148,7 @@ pub struct OpaqueTy<'hir> { pub name: Symbol, pub id: hir::HirId, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -161,7 +161,7 @@ pub struct Static<'hir> { pub attrs: &'hir [ast::Attribute], pub vis: &'hir hir::Visibility<'hir>, pub id: hir::HirId, - pub whence: Span, + pub span: Span, } pub struct Constant<'hir> { @@ -171,7 +171,7 @@ pub struct Constant<'hir> { pub attrs: &'hir [ast::Attribute], pub vis: &'hir hir::Visibility<'hir>, pub id: hir::HirId, - pub whence: Span, + pub span: Span, } pub struct Trait<'hir> { @@ -183,7 +183,7 @@ pub struct Trait<'hir> { pub bounds: &'hir [hir::GenericBound<'hir>], pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -193,7 +193,7 @@ pub struct TraitAlias<'hir> { pub bounds: &'hir [hir::GenericBound<'hir>], pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -208,7 +208,7 @@ pub struct Impl<'hir> { pub for_: &'hir hir::Ty<'hir>, pub items: Vec<&'hir hir::ImplItem<'hir>>, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, pub id: hir::HirId, } @@ -219,7 +219,7 @@ pub struct ForeignItem<'hir> { pub name: Symbol, pub kind: &'hir hir::ForeignItemKind<'hir>, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, } // For Macro we store the DefId instead of the NodeId, since we also create @@ -229,7 +229,7 @@ pub struct Macro<'hir> { pub hid: hir::HirId, pub def_id: hir::def_id::DefId, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub matchers: Vec, pub imported_from: Option, } @@ -240,7 +240,7 @@ pub struct ExternCrate<'hir> { pub path: Option, pub vis: &'hir hir::Visibility<'hir>, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, } pub struct Import<'hir> { @@ -250,7 +250,7 @@ pub struct Import<'hir> { pub attrs: &'hir [ast::Attribute], pub path: &'hir hir::Path<'hir>, pub glob: bool, - pub whence: Span, + pub span: Span, } pub struct ProcMacro<'hir> { @@ -259,7 +259,7 @@ pub struct ProcMacro<'hir> { pub kind: MacroKind, pub helpers: Vec, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, } pub fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType { diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 0a85cb1d5a..d4ada3278e 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -93,15 +93,11 @@ pub trait DocFolder: Sized { c.module = c.module.take().and_then(|module| self.fold_item(module)); { - let mut guard = c.external_traits.borrow_mut(); - let external_traits = std::mem::replace(&mut *guard, Default::default()); - *guard = external_traits - .into_iter() - .map(|(k, mut v)| { - v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); - (k, v) - }) - .collect(); + let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; + for (k, mut v) in external_traits { + v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); + c.external_traits.borrow_mut().insert(k, v); + } } c } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 99b31473f8..b99321e848 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -16,7 +16,7 @@ use crate::formats::item_type::ItemType; use crate::formats::Impl; use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation}; use crate::html::render::IndexItem; -use crate::html::render::{plain_summary_line, shorten}; +use crate::html::render::{plain_text_summary, shorten}; thread_local!(crate static CACHE_KEY: RefCell> = Default::default()); @@ -313,7 +313,7 @@ impl DocFolder for Cache { ty: item.type_(), name: s.to_string(), path: path.join("::"), - desc: shorten(plain_summary_line(item.doc_value())), + desc: shorten(plain_text_summary(item.doc_value())), parent, parent_idx: None, search_type: get_index_search_type(&item), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 699f8c36cb..2da9c68b19 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -833,7 +833,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> write!( f, "
{name}", + title=\"type {path}::{name}\">{name}", url = url, shortty = ItemType::AssocType, name = name, diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index d4302d0cb5..4769edc50f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -7,18 +7,12 @@ use crate::html::escape::Escape; -use std::fmt::Display; -use std::io; -use std::io::prelude::*; +use std::fmt::{Display, Write}; +use std::iter::Peekable; -use rustc_ast::token::{self, Token}; -use rustc_data_structures::sync::Lrc; -use rustc_parse::lexer; -use rustc_session::parse::ParseSess; -use rustc_span::hygiene::SyntaxContext; -use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, sym}; -use rustc_span::{BytePos, FileName, SourceFile, Span}; +use rustc_lexer::{LiteralKind, TokenKind}; +use rustc_span::symbol::Ident; +use rustc_span::with_default_session_globals; /// Highlights `src`, returning the HTML output. pub fn render_with_highlighting( @@ -28,71 +22,41 @@ pub fn render_with_highlighting( tooltip: Option<(&str, &str)>, ) -> String { debug!("highlighting: ================\n{}\n==============", src); - let mut out = Vec::new(); + let mut out = String::with_capacity(src.len()); if let Some((tooltip, class)) = tooltip { write!( out, "
ⓘ{}
", + class='tooltiptext'>{}

`]: ../pin/struct.Pin.html -/// [`pin module`]: ../../std/pin/index.html +/// [`mem::replace`]: crate::mem::replace +/// [Pin]: crate::pin::Pin +/// [`pin` module]: crate::pin #[stable(feature = "pin", since = "1.33.0")] #[rustc_on_unimplemented( on(_Self = "std::future::Future", note = "consider using `Box::pin`",), diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index e45aa86c07..d86939454b 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -15,50 +15,33 @@ use crate::ptr; /// be exposed through a public safe API. /// Correspondingly, `ManuallyDrop::drop` is unsafe. /// -/// # Examples +/// # `ManuallyDrop` and drop order. /// -/// This wrapper can be used to enforce a particular drop order on fields, regardless -/// of how they are defined in the struct: +/// Rust has a well-defined [drop order] of values. To make sure that fields or +/// locals are dropped in a specific order, reorder the declarations such that +/// the implicit drop order is the correct one. /// -/// ```rust -/// use std::mem::ManuallyDrop; -/// struct Peach; -/// struct Banana; -/// struct Melon; -/// struct FruitBox { -/// // Immediately clear there’s something non-trivial going on with these fields. -/// peach: ManuallyDrop, -/// melon: Melon, // Field that’s independent of the other two. -/// banana: ManuallyDrop, -/// } +/// It is possible to use `ManuallyDrop` to control the drop order, but this +/// requires unsafe code and is hard to do correctly in the presence of +/// unwinding. /// -/// impl Drop for FruitBox { -/// fn drop(&mut self) { -/// unsafe { -/// // Explicit ordering in which field destructors are run specified in the intuitive -/// // location – the destructor of the structure containing the fields. -/// // Moreover, one can now reorder fields within the struct however much they want. -/// ManuallyDrop::drop(&mut self.peach); -/// ManuallyDrop::drop(&mut self.banana); -/// } -/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets -/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. -/// } -/// } -/// ``` +/// For example, if you want to make sure that a specific field is dropped after +/// the others, make it the last field of a struct: /// -/// However, care should be taken when using this pattern as it can lead to *leak amplification*. -/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field -/// would also be leaked. +/// ``` +/// struct Context; /// -/// In contrast, the automatically-generated compiler drop implementation would have ensured -/// that all fields are dropped even in the presence of panics. This is especially important when -/// working with [pinned] data, where reusing the memory without calling the destructor could lead -/// to Undefined Behaviour. +/// struct Widget { +/// children: Vec, +/// // `context` will be dropped after `children`. +/// // Rust guarantees that fields are dropped in the order of declaration. +/// context: Context, +/// } +/// ``` /// +/// [drop order]: https://doc.rust-lang.org/reference/destructors.html /// [`mem::zeroed`]: crate::mem::zeroed /// [`MaybeUninit`]: crate::mem::MaybeUninit -/// [pinned]: crate::pin #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -74,8 +57,12 @@ impl ManuallyDrop { /// /// ```rust /// use std::mem::ManuallyDrop; - /// ManuallyDrop::new(Box::new(())); + /// let mut x = ManuallyDrop::new(String::from("Hello World!")); + /// x.truncate(5); // You can still safely operate on the value + /// assert_eq!(*x, "Hello"); + /// // But `Drop` will not be run here /// ``` + #[must_use = "if you don't need the wrapper, you can use `mem::forget` instead"] #[stable(feature = "manually_drop", since = "1.20.0")] #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")] #[inline(always)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index d2d65fd2fa..e629d28eae 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -2,8 +2,7 @@ use crate::any::type_name; use crate::fmt; use crate::intrinsics; use crate::mem::ManuallyDrop; - -// ignore-tidy-undocumented-unsafe +use crate::ptr; /// A wrapper type to construct uninitialized instances of `T`. /// @@ -281,7 +280,7 @@ impl MaybeUninit { /// # Examples /// /// ```no_run - /// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice_assume_init)] + /// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice)] /// /// use std::mem::MaybeUninit; /// @@ -293,7 +292,7 @@ impl MaybeUninit { /// fn read(buf: &mut [MaybeUninit]) -> &[u8] { /// unsafe { /// let len = read_into_buffer(buf.as_mut_ptr() as *mut u8, buf.len()); - /// MaybeUninit::slice_get_ref(&buf[..len]) + /// MaybeUninit::slice_assume_init_ref(&buf[..len]) /// } /// } /// @@ -303,17 +302,10 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] #[inline(always)] pub fn uninit_array() -> [Self; LEN] { + // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. unsafe { MaybeUninit::<[MaybeUninit; LEN]>::uninit().assume_init() } } - /// A promotable constant, equivalent to `uninit()`. - #[unstable( - feature = "internal_uninit_const", - issue = "none", - reason = "hack to work around promotability" - )] - pub const UNINIT: Self = Self::uninit(); - /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being /// filled with `0` bytes. It depends on `T` whether that already makes for /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, @@ -354,6 +346,7 @@ impl MaybeUninit { #[rustc_diagnostic_item = "maybe_uninit_zeroed"] pub fn zeroed() -> MaybeUninit { let mut u = MaybeUninit::::uninit(); + // SAFETY: `u.as_mut_ptr()` points to allocated memory. unsafe { u.as_mut_ptr().write_bytes(0u8, 1); } @@ -367,10 +360,9 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] pub fn write(&mut self, val: T) -> &mut T { - unsafe { - self.value = ManuallyDrop::new(val); - self.get_mut() - } + *self = MaybeUninit::new(val); + // SAFETY: We just initialized this value. + unsafe { self.assume_init_mut() } } /// Gets a pointer to the contained value. Reading from this pointer or turning it @@ -472,6 +464,8 @@ impl MaybeUninit { /// *immediate* undefined behavior, but will cause undefined behavior with most /// safe operations (including dropping it). /// + /// [`Vec`]: ../../std/vec/struct.Vec.html + /// /// # Examples /// /// Correct usage of this method: @@ -520,8 +514,8 @@ impl MaybeUninit { /// this initialization invariant. /// /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. When using - /// multiple copies of the data (by calling `read` multiple times, or first - /// calling `read` and then [`assume_init`]), it is your responsibility + /// multiple copies of the data (by calling `assume_init_read` multiple times, or first + /// calling `assume_init_read` and then [`assume_init`]), it is your responsibility /// to ensure that that data may indeed be duplicated. /// /// [inv]: #initialization-invariant @@ -537,16 +531,16 @@ impl MaybeUninit { /// /// let mut x = MaybeUninit::::uninit(); /// x.write(13); - /// let x1 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; /// // `u32` is `Copy`, so we may read multiple times. - /// let x2 = unsafe { x.read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// assert_eq!(x1, x2); /// /// let mut x = MaybeUninit::>>::uninit(); /// x.write(None); - /// let x1 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; /// // Duplicating a `None` value is okay, so we may read multiple times. - /// let x2 = unsafe { x.read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// assert_eq!(x1, x2); /// ``` /// @@ -558,14 +552,14 @@ impl MaybeUninit { /// /// let mut x = MaybeUninit::>>::uninit(); /// x.write(Some(vec![0,1,2])); - /// let x1 = unsafe { x.read() }; - /// let x2 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// // We now created two copies of the same vector, leading to a double-free ⚠️ when /// // they both get dropped! /// ``` #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub unsafe fn read(&self) -> T { + pub unsafe fn assume_init_read(&self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // Reading from `self.as_ptr()` is safe since `self` should be initialized. unsafe { @@ -574,6 +568,34 @@ impl MaybeUninit { } } + /// Drops the contained value in place. + /// + /// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is + /// in an initialized state. Calling this when the content is not yet fully + /// initialized causes undefined behavior. + /// + /// On top of that, all additional invariants of the type `T` must be + /// satisfied, as the `Drop` implementation of `T` (or its members) may + /// rely on this. For example, a `1`-initialized [`Vec`] is considered + /// initialized (under the current implementation; this does not constitute + /// a stable guarantee) because the only requirement the compiler knows + /// about it is that the data pointer must be non-null. Dropping such a + /// `Vec` however will cause undefined behaviour. + /// + /// [`assume_init`]: MaybeUninit::assume_init + /// [`Vec`]: ../../std/vec/struct.Vec.html + #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + pub unsafe fn assume_init_drop(&mut self) { + // SAFETY: the caller must guarantee that `self` is initialized and + // satisfies all invariants of `T`. + // Dropping the value in place is safe if that is the case. + unsafe { ptr::drop_in_place(self.as_mut_ptr()) } + } + /// Gets a shared reference to the contained value. /// /// This can be useful when we want to access a `MaybeUninit` that has been @@ -600,8 +622,8 @@ impl MaybeUninit { /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to /// // create a shared reference to it: /// let x: &Vec = unsafe { - /// // Safety: `x` has been initialized. - /// x.get_ref() + /// // SAFETY: `x` has been initialized. + /// x.assume_init_ref() /// }; /// assert_eq!(x, &vec![1, 2, 3]); /// ``` @@ -613,7 +635,7 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::>::uninit(); - /// let x_vec: &Vec = unsafe { x.get_ref() }; + /// let x_vec: &Vec = unsafe { x.assume_init_ref() }; /// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️ /// ``` /// @@ -624,14 +646,14 @@ impl MaybeUninit { /// let b = MaybeUninit::>::uninit(); /// // Initialize the `MaybeUninit` using `Cell::set`: /// unsafe { - /// b.get_ref().set(true); - /// // ^^^^^^^^^^^ - /// // Reference to an uninitialized `Cell`: UB! + /// b.assume_init_ref().set(true); + /// // ^^^^^^^^^^^^^^^ + /// // Reference to an uninitialized `Cell`: UB! /// } /// ``` #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] - pub unsafe fn get_ref(&self) -> &T { + pub unsafe fn assume_init_ref(&self) -> &T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { @@ -650,7 +672,7 @@ impl MaybeUninit { /// /// Calling this when the content is not yet fully initialized causes undefined /// behavior: it is up to the caller to guarantee that the `MaybeUninit` really - /// is in an initialized state. For instance, `.get_mut()` cannot be used to + /// is in an initialized state. For instance, `.assume_init_mut()` cannot be used to /// initialize a `MaybeUninit`. /// /// # Examples @@ -677,8 +699,8 @@ impl MaybeUninit { /// // To assert our buffer has been initialized without copying it, we upgrade /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`: /// let buf: &mut [u8; 2048] = unsafe { - /// // Safety: `buf` has been initialized. - /// buf.get_mut() + /// // SAFETY: `buf` has been initialized. + /// buf.assume_init_mut() /// }; /// /// // Now we can use `buf` as a normal slice: @@ -691,7 +713,7 @@ impl MaybeUninit { /// /// ### *Incorrect* usages of this method: /// - /// You cannot use `.get_mut()` to initialize a value: + /// You cannot use `.assume_init_mut()` to initialize a value: /// /// ```rust,no_run /// #![feature(maybe_uninit_ref)] @@ -699,7 +721,7 @@ impl MaybeUninit { /// /// let mut b = MaybeUninit::::uninit(); /// unsafe { - /// *b.get_mut() = true; + /// *b.assume_init_mut() = true; /// // We have created a (mutable) reference to an uninitialized `bool`! /// // This is undefined behavior. ⚠️ /// } @@ -716,8 +738,8 @@ impl MaybeUninit { /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]> /// { /// let mut buffer = MaybeUninit::<[u8; 64]>::uninit(); - /// reader.read_exact(unsafe { buffer.get_mut() })?; - /// // ^^^^^^^^^^^^^^^^ + /// reader.read_exact(unsafe { buffer.assume_init_mut() })?; + /// // ^^^^^^^^^^^^^^^^^^^^^^^^ /// // (mutable) reference to uninitialized memory! /// // This is undefined behavior. /// Ok(unsafe { buffer.assume_init() }) @@ -737,23 +759,23 @@ impl MaybeUninit { /// /// let foo: Foo = unsafe { /// let mut foo = MaybeUninit::::uninit(); - /// ptr::write(&mut foo.get_mut().a as *mut u32, 1337); - /// // ^^^^^^^^^^^^^ + /// ptr::write(&mut foo.assume_init_mut().a as *mut u32, 1337); + /// // ^^^^^^^^^^^^^^^^^^^^^ /// // (mutable) reference to uninitialized memory! /// // This is undefined behavior. - /// ptr::write(&mut foo.get_mut().b as *mut u8, 42); - /// // ^^^^^^^^^^^^^ + /// ptr::write(&mut foo.assume_init_mut().b as *mut u8, 42); + /// // ^^^^^^^^^^^^^^^^^^^^^ /// // (mutable) reference to uninitialized memory! /// // This is undefined behavior. /// foo.assume_init() /// }; /// ``` - // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references + // FIXME(#76092): We currently rely on the above being incorrect, i.e., we have references // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make // a final decision about the rules before stabilization. #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] - pub unsafe fn get_mut(&mut self) -> &mut T { + pub unsafe fn assume_init_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { @@ -769,9 +791,13 @@ impl MaybeUninit { /// It is up to the caller to guarantee that the `MaybeUninit` elements /// really are in an initialized state. /// Calling this when the content is not yet fully initialized causes undefined behavior. - #[unstable(feature = "maybe_uninit_slice_assume_init", issue = "none")] + /// + /// See [`assume_init_ref`] for more details and examples. + /// + /// [`assume_init_ref`]: MaybeUninit::assume_init_ref + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub unsafe fn slice_get_ref(slice: &[Self]) -> &[T] { + pub unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { // SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that // `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`. // The pointer obtained is valid since it refers to memory owned by `slice` which is a @@ -786,9 +812,13 @@ impl MaybeUninit { /// It is up to the caller to guarantee that the `MaybeUninit` elements /// really are in an initialized state. /// Calling this when the content is not yet fully initialized causes undefined behavior. - #[unstable(feature = "maybe_uninit_slice_assume_init", issue = "none")] + /// + /// See [`assume_init_mut`] for more details and examples. + /// + /// [`assume_init_mut`]: MaybeUninit::assume_init_mut + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub unsafe fn slice_get_mut(slice: &mut [Self]) -> &mut [T] { + pub unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a // mutable reference which is also guaranteed to be valid for writes. unsafe { &mut *(slice as *mut [Self] as *mut [T]) } @@ -797,14 +827,14 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn first_ptr(this: &[MaybeUninit]) -> *const T { + pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this as *const [MaybeUninit] as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn first_ptr_mut(this: &mut [MaybeUninit]) -> *mut T { + pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this as *mut [MaybeUninit] as *mut T } } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 9107c570a8..aa1b5529df 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -31,10 +31,10 @@ pub use crate::intrinsics::transmute; /// forever in an unreachable state. However, it does not guarantee that pointers /// to this memory will remain valid. /// -/// * If you want to leak memory, see [`Box::leak`][leak]. -/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. +/// * If you want to leak memory, see [`Box::leak`]. +/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`]. /// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`][drop]. +/// [`mem::drop`]. /// /// # Safety /// @@ -132,28 +132,22 @@ pub use crate::intrinsics::transmute; /// ownership to `s` — the final step of interacting with `v` to dispose of it without /// running its destructor is entirely avoided. /// -/// [drop]: fn.drop.html -/// [uninit]: fn.uninitialized.html -/// [clone]: ../clone/trait.Clone.html -/// [swap]: fn.swap.html -/// [box]: ../../std/boxed/struct.Box.html -/// [leak]: ../../std/boxed/struct.Box.html#method.leak -/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Box::leak`]: ../../std/boxed/struct.Box.html#method.leak +/// [`Box::into_raw`]: ../../std/boxed/struct.Box.html#method.into_raw +/// [`mem::drop`]: drop /// [ub]: ../../reference/behavior-considered-undefined.html -/// [`ManuallyDrop`]: struct.ManuallyDrop.html #[inline] #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn forget(t: T) { - ManuallyDrop::new(t); + let _ = ManuallyDrop::new(t); } /// Like [`forget`], but also accepts unsized values. /// /// This function is just a shim intended to be removed when the `unsized_locals` feature gets /// stabilized. -/// -/// [`forget`]: fn.forget.html #[inline] #[unstable(feature = "forget_unsized", issue = "none")] pub fn forget_unsized(t: T) { @@ -301,7 +295,7 @@ pub fn forget_unsized(t: T) { /// assert_eq!(2, mem::size_of::()); /// ``` /// -/// [alignment]: ./fn.align_of.html +/// [alignment]: align_of #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] @@ -365,7 +359,6 @@ pub const fn size_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html -/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html /// /// # Examples /// @@ -501,7 +494,6 @@ pub const fn align_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html -/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html /// /// # Examples /// @@ -540,7 +532,7 @@ pub unsafe fn align_of_val_raw(val: *const T) -> usize { /// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop /// values one at a time and should use this API. /// -/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html +/// [`drop_in_place`]: crate::ptr::drop_in_place /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// /// # Examples @@ -595,9 +587,9 @@ pub const fn needs_drop() -> bool { /// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. /// It is useful for FFI sometimes, but should generally be avoided. /// -/// [zeroed]: union.MaybeUninit.html#method.zeroed +/// [zeroed]: MaybeUninit::zeroed /// [ub]: ../../reference/behavior-considered-undefined.html -/// [inv]: union.MaybeUninit.html#initialization-invariant +/// [inv]: MaybeUninit#initialization-invariant /// /// # Examples /// @@ -650,10 +642,10 @@ pub unsafe fn zeroed() -> T { /// (Notice that the rules around uninitialized integers are not finalized yet, but /// until they are, it is advisable to avoid them.) /// -/// [`MaybeUninit`]: union.MaybeUninit.html -/// [uninit]: union.MaybeUninit.html#method.uninit -/// [assume_init]: union.MaybeUninit.html#method.assume_init -/// [inv]: union.MaybeUninit.html#initialization-invariant +/// [`MaybeUninit`]: MaybeUninit +/// [uninit]: MaybeUninit::uninit +/// [assume_init]: MaybeUninit::assume_init +/// [inv]: MaybeUninit#initialization-invariant #[inline(always)] #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] @@ -686,9 +678,6 @@ pub unsafe fn uninitialized() -> T { /// assert_eq!(42, x); /// assert_eq!(5, y); /// ``` -/// -/// [`replace`]: fn.replace.html -/// [`take`]: fn.take.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { @@ -754,10 +743,6 @@ pub fn swap(x: &mut T, y: &mut T) { /// assert_eq!(buffer.get_and_reset(), vec![0, 1]); /// assert_eq!(buffer.buf.len(), 0); /// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`replace`]: fn.replace.html -/// [`swap`]: fn.swap.html #[inline] #[stable(feature = "mem_take", since = "1.40.0")] pub fn take(dest: &mut T) -> T { @@ -822,10 +807,6 @@ pub fn take(dest: &mut T) -> T { /// assert_eq!(buffer.replace_index(0, 2), 0); /// assert_eq!(buffer.buf[0], 2); /// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`swap`]: fn.swap.html -/// [`take`]: fn.take.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] @@ -851,7 +832,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Because `_x` is moved into the function, it is automatically dropped before /// the function returns. /// -/// [drop]: ../ops/trait.Drop.html +/// [drop]: Drop /// /// # Examples /// @@ -894,8 +875,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("x: {}, y: {}", x, y.0); // still available /// ``` /// -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`Copy`]: ../../std/marker/trait.Copy.html +/// [`RefCell`]: crate::cell::RefCell #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) {} @@ -914,7 +894,6 @@ pub fn drop(_x: T) {} /// `T`. /// /// [ub]: ../../reference/behavior-considered-undefined.html -/// [size_of]: fn.size_of.html /// /// # Examples /// @@ -960,8 +939,6 @@ pub unsafe fn transmute_copy(src: &T) -> U { /// Opaque type representing the discriminant of an enum. /// /// See the [`discriminant`] function in this module for more information. -/// -/// [`discriminant`]: fn.discriminant.html #[stable(feature = "discriminant_value", since = "1.21.0")] pub struct Discriminant(::Discriminant); diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 6f16b93d04..6a1a1e1976 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -20,7 +20,6 @@ #![macro_use] use crate::intrinsics; -use crate::mem; /// Arithmetic operations required by bignums. pub trait FullOps: Sized { @@ -58,25 +57,22 @@ macro_rules! impl_full_ops { // This cannot overflow; // the output is between `0` and `2^nbits * (2^nbits - 1)`. // FIXME: will LLVM optimize this into ADC or similar? - let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (carry as $bigty); - ((v >> nbits) as $ty, v as $ty) + ((v >> <$ty>::BITS) as $ty, v as $ty) } fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) { // This cannot overflow; // the output is between `0` and `2^nbits * (2^nbits - 1)`. - let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) + (carry as $bigty); - ((v >> nbits) as $ty, v as $ty) + ((v >> <$ty>::BITS) as $ty, v as $ty) } fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) { debug_assert!(borrow < other); // This cannot overflow; the output is between `0` and `other * (2^nbits - 1)`. - let nbits = mem::size_of::<$ty>() * 8; - let lhs = ((borrow as $bigty) << nbits) | (self as $bigty); + let lhs = ((borrow as $bigty) << <$ty>::BITS) | (self as $bigty); let rhs = other as $bigty; ((lhs / rhs) as $ty, (lhs % rhs) as $ty) } @@ -128,13 +124,11 @@ macro_rules! define_bignum { /// Makes a bignum from `u64` value. pub fn from_u64(mut v: u64) -> $name { - use crate::mem; - let mut base = [0; $n]; let mut sz = 0; while v > 0 { base[sz] = v as $ty; - v >>= mem::size_of::<$ty>() * 8; + v >>= <$ty>::BITS; sz += 1; } $name { size: sz, base: base } @@ -150,9 +144,7 @@ macro_rules! define_bignum { /// Returns the `i`-th bit where bit 0 is the least significant one. /// In other words, the bit with weight `2^i`. pub fn get_bit(&self, i: usize) -> u8 { - use crate::mem; - - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let d = i / digitbits; let b = i % digitbits; ((self.base[d] >> b) & 1) as u8 @@ -166,8 +158,6 @@ macro_rules! define_bignum { /// Returns the number of bits necessary to represent this value. Note that zero /// is considered to need 0 bits. pub fn bit_length(&self) -> usize { - use crate::mem; - // Skip over the most significant digits which are zero. let digits = self.digits(); let zeros = digits.iter().rev().take_while(|&&x| x == 0).count(); @@ -180,7 +170,7 @@ macro_rules! define_bignum { } // This could be optimized with leading_zeros() and bit shifts, but that's // probably not worth the hassle. - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let mut i = nonzero.len() * digitbits - 1; while self.get_bit(i) == 0 { i -= 1; @@ -265,9 +255,7 @@ macro_rules! define_bignum { /// Multiplies itself by `2^bits` and returns its own mutable reference. pub fn mul_pow2(&mut self, bits: usize) -> &mut $name { - use crate::mem; - - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let digits = bits / digitbits; let bits = bits % digitbits; @@ -393,13 +381,11 @@ macro_rules! define_bignum { /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the /// remainder. pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) { - use crate::mem; - // Stupid slow base-2 long division taken from // https://en.wikipedia.org/wiki/Division_algorithm // FIXME use a greater base ($ty) for the long division. assert!(!d.is_zero()); - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; for digit in &mut q.base[..] { *digit = 0; } @@ -462,10 +448,8 @@ macro_rules! define_bignum { impl crate::fmt::Debug for $name { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - use crate::mem; - let sz = if self.size < 1 { 1 } else { self.size }; - let digitlen = mem::size_of::<$ty>() * 2; + let digitlen = <$ty>::BITS as usize / 4; write!(f, "{:#x}", self.base[sz - 1])?; for &v in self.base[..sz - 1].iter().rev() { diff --git a/library/core/src/num/dec2flt/algorithm.rs b/library/core/src/num/dec2flt/algorithm.rs index aaeb4d8a22..a5fbdc6ee2 100644 --- a/library/core/src/num/dec2flt/algorithm.rs +++ b/library/core/src/num/dec2flt/algorithm.rs @@ -60,12 +60,19 @@ mod fpu_precision { fn set_cw(cw: u16) { // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with // any `u16` - unsafe { llvm_asm!("fldcw $0" :: "m" (cw) :: "volatile") } + unsafe { + asm!( + "fldcw ({})", + in(reg) &cw, + // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. + options(att_syntax, nostack), + ) + } } /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`. pub fn set_precision() -> FPUControlWord { - let cw = 0u16; + let mut cw = 0_u16; // Compute the value for the Precision Control field that is appropriate for `T`. let cw_precision = match size_of::() { @@ -78,7 +85,14 @@ mod fpu_precision { // `FPUControlWord` structure is dropped // SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with // any `u16` - unsafe { llvm_asm!("fnstcw $0" : "=*m" (&cw) ::: "volatile") } + unsafe { + asm!( + "fnstcw ({})", + in(reg) &mut cw, + // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. + options(att_syntax, nostack), + ) + } // Set the control word to the desired precision. This is achieved by masking away the old // precision (bits 8 and 9, 0x300) and replacing it with the precision flag computed above. diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index c83c6b0ecc..6f3a3a8674 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -167,9 +167,15 @@ from_str_float_impl!(f64); /// This error is used as the error type for the [`FromStr`] implementation /// for [`f32`] and [`f64`]. /// -/// [`FromStr`]: ../str/trait.FromStr.html -/// [`f32`]: ../../std/primitive.f32.html -/// [`f64`]: ../../std/primitive.f64.html +/// # Example +/// +/// ``` +/// use std::str::FromStr; +/// +/// if let Err(e) = f64::from_str("a.12") { +/// println!("Failed conversion to f64: {}", e); +/// } +/// ``` #[derive(Debug, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct ParseFloatError { diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs new file mode 100644 index 0000000000..aab1715518 --- /dev/null +++ b/library/core/src/num/error.rs @@ -0,0 +1,151 @@ +//! Error types for conversion to integral types. + +use crate::convert::Infallible; +use crate::fmt; + +/// The error type returned when a checked integral type conversion fails. +#[stable(feature = "try_from", since = "1.34.0")] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct TryFromIntError(pub(crate) ()); + +impl TryFromIntError { + #[unstable( + feature = "int_error_internals", + reason = "available through Error trait and this method should \ + not be exposed publicly", + issue = "none" + )] + #[doc(hidden)] + pub fn __description(&self) -> &str { + "out of range integral type conversion attempted" + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl fmt::Display for TryFromIntError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.__description().fmt(fmt) + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl From for TryFromIntError { + fn from(x: Infallible) -> TryFromIntError { + match x {} + } +} + +#[unstable(feature = "never_type", issue = "35121")] +impl From for TryFromIntError { + fn from(never: !) -> TryFromIntError { + // Match rather than coerce to make sure that code like + // `From for TryFromIntError` above will keep working + // when `Infallible` becomes an alias to `!`. + match never {} + } +} + +/// An error which can be returned when parsing an integer. +/// +/// This error is used as the error type for the `from_str_radix()` functions +/// on the primitive integer types, such as [`i8::from_str_radix`]. +/// +/// # Potential causes +/// +/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace +/// in the string e.g., when it is obtained from the standard input. +/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing. +/// +/// [`str.trim()`]: ../../std/primitive.str.html#method.trim +/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix +/// +/// # Example +/// +/// ``` +/// if let Err(e) = i32::from_str_radix("a12", 10) { +/// println!("Failed conversion to i32: {}", e); +/// } +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseIntError { + pub(super) kind: IntErrorKind, +} + +/// Enum to store the various types of errors that can cause parsing an integer to fail. +/// +/// # Example +/// +/// ``` +/// #![feature(int_error_matching)] +/// +/// # fn main() { +/// if let Err(e) = i32::from_str_radix("a12", 10) { +/// println!("Failed conversion to i32: {:?}", e.kind()); +/// } +/// # } +/// ``` +#[unstable( + feature = "int_error_matching", + reason = "it can be useful to match errors when making error messages \ + for integer parsing", + issue = "22639" +)] +#[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub enum IntErrorKind { + /// Value being parsed is empty. + /// + /// Among other causes, this variant will be constructed when parsing an empty string. + Empty, + /// Contains an invalid digit. + /// + /// Among other causes, this variant will be constructed when parsing a string that + /// contains a letter. + InvalidDigit, + /// Integer is too large to store in target integer type. + Overflow, + /// Integer is too small to store in target integer type. + Underflow, + /// Value was Zero + /// + /// This variant will be emitted when the parsing string has a value of zero, which + /// would be illegal for non-zero types. + Zero, +} + +impl ParseIntError { + /// Outputs the detailed cause of parsing an integer failing. + #[unstable( + feature = "int_error_matching", + reason = "it can be useful to match errors when making error messages \ + for integer parsing", + issue = "22639" + )] + pub fn kind(&self) -> &IntErrorKind { + &self.kind + } + #[unstable( + feature = "int_error_internals", + reason = "available through Error trait and this method should \ + not be exposed publicly", + issue = "none" + )] + #[doc(hidden)] + pub fn __description(&self) -> &str { + match self.kind { + IntErrorKind::Empty => "cannot parse integer from empty string", + IntErrorKind::InvalidDigit => "invalid digit found in string", + IntErrorKind::Overflow => "number too large to fit in target type", + IntErrorKind::Underflow => "number too small to fit in target type", + IntErrorKind::Zero => "number would be zero for non-zero type", + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseIntError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.__description().fmt(f) + } +} diff --git a/library/core/src/num/flt2dec/mod.rs b/library/core/src/num/flt2dec/mod.rs index 9bf56e93d8..e8f9d6574e 100644 --- a/library/core/src/num/flt2dec/mod.rs +++ b/library/core/src/num/flt2dec/mod.rs @@ -124,6 +124,8 @@ functions. pub use self::decoder::{decode, DecodableFloat, Decoded, FullDecoded}; +use crate::mem::MaybeUninit; + pub mod decoder; pub mod estimator; @@ -140,23 +142,23 @@ pub mod strategy { /// The exact formula is `ceil(# bits in mantissa * log_10 2 + 1)`. pub const MAX_SIG_DIGITS: usize = 17; -/// When `d[..n]` contains decimal digits, increase the last digit and propagate carry. -/// Returns a next digit when it causes the length change. +/// When `d` contains decimal digits, increase the last digit and propagate carry. +/// Returns a next digit when it causes the length to change. #[doc(hidden)] -pub fn round_up(d: &mut [u8], n: usize) -> Option { - match d[..n].iter().rposition(|&c| c != b'9') { +pub fn round_up(d: &mut [u8]) -> Option { + match d.iter().rposition(|&c| c != b'9') { Some(i) => { // d[i+1..n] is all nines d[i] += 1; - for j in i + 1..n { + for j in i + 1..d.len() { d[j] = b'0'; } None } - None if n > 0 => { + None if d.len() > 0 => { // 999..999 rounds to 1000..000 with an increased exponent d[0] = b'1'; - for j in 1..n { + for j in 1..d.len() { d[j] = b'0'; } Some(b'0') @@ -281,7 +283,7 @@ fn digits_to_dec_str<'a>( buf: &'a [u8], exp: i16, frac_digits: usize, - parts: &'a mut [Part<'a>], + parts: &'a mut [MaybeUninit>], ) -> &'a [Part<'a>] { assert!(!buf.is_empty()); assert!(buf[0] > b'0'); @@ -303,38 +305,44 @@ fn digits_to_dec_str<'a>( if exp <= 0 { // the decimal point is before rendered digits: [0.][000...000][1234][____] let minus_exp = -(exp as i32) as usize; - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(minus_exp); - parts[2] = Part::Copy(buf); + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(minus_exp)); + parts[2] = MaybeUninit::new(Part::Copy(buf)); if frac_digits > buf.len() && frac_digits - buf.len() > minus_exp { - parts[3] = Part::Zero((frac_digits - buf.len()) - minus_exp); - &parts[..4] + parts[3] = MaybeUninit::new(Part::Zero((frac_digits - buf.len()) - minus_exp)); + // SAFETY: we just initialized the elements `..4`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..4]) } } else { - &parts[..3] + // SAFETY: we just initialized the elements `..3`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..3]) } } } else { let exp = exp as usize; if exp < buf.len() { // the decimal point is inside rendered digits: [12][.][34][____] - parts[0] = Part::Copy(&buf[..exp]); - parts[1] = Part::Copy(b"."); - parts[2] = Part::Copy(&buf[exp..]); + parts[0] = MaybeUninit::new(Part::Copy(&buf[..exp])); + parts[1] = MaybeUninit::new(Part::Copy(b".")); + parts[2] = MaybeUninit::new(Part::Copy(&buf[exp..])); if frac_digits > buf.len() - exp { - parts[3] = Part::Zero(frac_digits - (buf.len() - exp)); - &parts[..4] + parts[3] = MaybeUninit::new(Part::Zero(frac_digits - (buf.len() - exp))); + // SAFETY: we just initialized the elements `..4`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..4]) } } else { - &parts[..3] + // SAFETY: we just initialized the elements `..3`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..3]) } } } else { // the decimal point is after rendered digits: [1234][____0000] or [1234][__][.][__]. - parts[0] = Part::Copy(buf); - parts[1] = Part::Zero(exp - buf.len()); + parts[0] = MaybeUninit::new(Part::Copy(buf)); + parts[1] = MaybeUninit::new(Part::Zero(exp - buf.len())); if frac_digits > 0 { - parts[2] = Part::Copy(b"."); - parts[3] = Part::Zero(frac_digits); - &parts[..4] + parts[2] = MaybeUninit::new(Part::Copy(b".")); + parts[3] = MaybeUninit::new(Part::Zero(frac_digits)); + // SAFETY: we just initialized the elements `..4`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..4]) } } else { - &parts[..2] + // SAFETY: we just initialized the elements `..2`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) } } } } @@ -354,7 +362,7 @@ fn digits_to_exp_str<'a>( exp: i16, min_ndigits: usize, upper: bool, - parts: &'a mut [Part<'a>], + parts: &'a mut [MaybeUninit>], ) -> &'a [Part<'a>] { assert!(!buf.is_empty()); assert!(buf[0] > b'0'); @@ -362,15 +370,15 @@ fn digits_to_exp_str<'a>( let mut n = 0; - parts[n] = Part::Copy(&buf[..1]); + parts[n] = MaybeUninit::new(Part::Copy(&buf[..1])); n += 1; if buf.len() > 1 || min_ndigits > 1 { - parts[n] = Part::Copy(b"."); - parts[n + 1] = Part::Copy(&buf[1..]); + parts[n] = MaybeUninit::new(Part::Copy(b".")); + parts[n + 1] = MaybeUninit::new(Part::Copy(&buf[1..])); n += 2; if min_ndigits > buf.len() { - parts[n] = Part::Zero(min_ndigits - buf.len()); + parts[n] = MaybeUninit::new(Part::Zero(min_ndigits - buf.len())); n += 1; } } @@ -378,13 +386,14 @@ fn digits_to_exp_str<'a>( // 0.1234 x 10^exp = 1.234 x 10^(exp-1) let exp = exp as i32 - 1; // avoid underflow when exp is i16::MIN if exp < 0 { - parts[n] = Part::Copy(if upper { b"E-" } else { b"e-" }); - parts[n + 1] = Part::Num(-exp as u16); + parts[n] = MaybeUninit::new(Part::Copy(if upper { b"E-" } else { b"e-" })); + parts[n + 1] = MaybeUninit::new(Part::Num(-exp as u16)); } else { - parts[n] = Part::Copy(if upper { b"E" } else { b"e" }); - parts[n + 1] = Part::Num(exp as u16); + parts[n] = MaybeUninit::new(Part::Copy(if upper { b"E" } else { b"e" })); + parts[n + 1] = MaybeUninit::new(Part::Num(exp as u16)); } - &parts[..n + 2] + // SAFETY: we just initialized the elements `..n + 2`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..n + 2]) } } /// Sign formatting options. @@ -446,6 +455,7 @@ fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static /// (which can be an empty string if no sign is rendered). /// /// `format_shortest` should be the underlying digit-generation function. +/// It should return the part of the buffer that it initialized. /// You probably would want `strategy::grisu::format_shortest` for this. /// /// `frac_digits` can be less than the number of actual fractional digits in `v`; @@ -461,12 +471,12 @@ pub fn to_shortest_str<'a, T, F>( v: T, sign: Sign, frac_digits: usize, - buf: &'a mut [u8], - parts: &'a mut [Part<'a>], + buf: &'a mut [MaybeUninit], + parts: &'a mut [MaybeUninit>], ) -> Formatted<'a> where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { assert!(parts.len() >= 4); assert!(buf.len() >= MAX_SIG_DIGITS); @@ -475,27 +485,37 @@ where let sign = determine_sign(sign, &full_decoded, negative); match full_decoded { FullDecoded::Nan => { - parts[0] = Part::Copy(b"NaN"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Infinite => { - parts[0] = Part::Copy(b"inf"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"inf")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Zero => { if frac_digits > 0 { // [0.][0000] - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(frac_digits); - Formatted { sign, parts: &parts[..2] } + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(frac_digits)); + Formatted { + sign, + // SAFETY: we just initialized the elements `..2`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) }, + } } else { - parts[0] = Part::Copy(b"0"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"0")); + Formatted { + sign, + // SAFETY: we just initialized the elements `..1`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + } } } FullDecoded::Finite(ref decoded) => { - let (len, exp) = format_shortest(decoded, buf); - Formatted { sign, parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) } + let (buf, exp) = format_shortest(decoded, buf); + Formatted { sign, parts: digits_to_dec_str(buf, exp, frac_digits, parts) } } } } @@ -509,6 +529,7 @@ where /// an empty string if no sign is rendered). /// /// `format_shortest` should be the underlying digit-generation function. +/// It should return the part of the buffer that it initialized. /// You probably would want `strategy::grisu::format_shortest` for this. /// /// The `dec_bounds` is a tuple `(lo, hi)` such that the number is formatted @@ -525,12 +546,12 @@ pub fn to_shortest_exp_str<'a, T, F>( sign: Sign, dec_bounds: (i16, i16), upper: bool, - buf: &'a mut [u8], - parts: &'a mut [Part<'a>], + buf: &'a mut [MaybeUninit], + parts: &'a mut [MaybeUninit>], ) -> Formatted<'a> where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { assert!(parts.len() >= 6); assert!(buf.len() >= MAX_SIG_DIGITS); @@ -540,28 +561,31 @@ where let sign = determine_sign(sign, &full_decoded, negative); match full_decoded { FullDecoded::Nan => { - parts[0] = Part::Copy(b"NaN"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Infinite => { - parts[0] = Part::Copy(b"inf"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"inf")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Zero => { parts[0] = if dec_bounds.0 <= 0 && 0 < dec_bounds.1 { - Part::Copy(b"0") + MaybeUninit::new(Part::Copy(b"0")) } else { - Part::Copy(if upper { b"0E0" } else { b"0e0" }) + MaybeUninit::new(Part::Copy(if upper { b"0E0" } else { b"0e0" })) }; - Formatted { sign, parts: &parts[..1] } + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Finite(ref decoded) => { - let (len, exp) = format_shortest(decoded, buf); + let (buf, exp) = format_shortest(decoded, buf); let vis_exp = exp as i32 - 1; let parts = if dec_bounds.0 as i32 <= vis_exp && vis_exp < dec_bounds.1 as i32 { - digits_to_dec_str(&buf[..len], exp, 0, parts) + digits_to_dec_str(buf, exp, 0, parts) } else { - digits_to_exp_str(&buf[..len], exp, 0, upper, parts) + digits_to_exp_str(buf, exp, 0, upper, parts) }; Formatted { sign, parts } } @@ -600,6 +624,7 @@ fn estimate_max_buf_len(exp: i16) -> usize { /// an empty string if no sign is rendered). /// /// `format_exact` should be the underlying digit-generation function. +/// It should return the part of the buffer that it initialized. /// You probably would want `strategy::grisu::format_exact` for this. /// /// The byte buffer should be at least `ndigits` bytes long unless `ndigits` is @@ -613,12 +638,12 @@ pub fn to_exact_exp_str<'a, T, F>( sign: Sign, ndigits: usize, upper: bool, - buf: &'a mut [u8], - parts: &'a mut [Part<'a>], + buf: &'a mut [MaybeUninit], + parts: &'a mut [MaybeUninit>], ) -> Formatted<'a> where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { assert!(parts.len() >= 6); assert!(ndigits > 0); @@ -627,23 +652,33 @@ where let sign = determine_sign(sign, &full_decoded, negative); match full_decoded { FullDecoded::Nan => { - parts[0] = Part::Copy(b"NaN"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Infinite => { - parts[0] = Part::Copy(b"inf"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"inf")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Zero => { if ndigits > 1 { // [0.][0000][e0] - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(ndigits - 1); - parts[2] = Part::Copy(if upper { b"E0" } else { b"e0" }); - Formatted { sign, parts: &parts[..3] } + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(ndigits - 1)); + parts[2] = MaybeUninit::new(Part::Copy(if upper { b"E0" } else { b"e0" })); + Formatted { + sign, + // SAFETY: we just initialized the elements `..3`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..3]) }, + } } else { - parts[0] = Part::Copy(if upper { b"0E0" } else { b"0e0" }); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(if upper { b"0E0" } else { b"0e0" })); + Formatted { + sign, + // SAFETY: we just initialized the elements `..1`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + } } } FullDecoded::Finite(ref decoded) => { @@ -651,8 +686,8 @@ where assert!(buf.len() >= ndigits || buf.len() >= maxlen); let trunc = if ndigits < maxlen { ndigits } else { maxlen }; - let (len, exp) = format_exact(decoded, &mut buf[..trunc], i16::MIN); - Formatted { sign, parts: digits_to_exp_str(&buf[..len], exp, ndigits, upper, parts) } + let (buf, exp) = format_exact(decoded, &mut buf[..trunc], i16::MIN); + Formatted { sign, parts: digits_to_exp_str(buf, exp, ndigits, upper, parts) } } } } @@ -665,6 +700,7 @@ where /// (which can be an empty string if no sign is rendered). /// /// `format_exact` should be the underlying digit-generation function. +/// It should return the part of the buffer that it initialized. /// You probably would want `strategy::grisu::format_exact` for this. /// /// The byte buffer should be enough for the output unless `frac_digits` is @@ -677,12 +713,12 @@ pub fn to_exact_fixed_str<'a, T, F>( v: T, sign: Sign, frac_digits: usize, - buf: &'a mut [u8], - parts: &'a mut [Part<'a>], + buf: &'a mut [MaybeUninit], + parts: &'a mut [MaybeUninit>], ) -> Formatted<'a> where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { assert!(parts.len() >= 4); @@ -690,22 +726,32 @@ where let sign = determine_sign(sign, &full_decoded, negative); match full_decoded { FullDecoded::Nan => { - parts[0] = Part::Copy(b"NaN"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Infinite => { - parts[0] = Part::Copy(b"inf"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"inf")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Zero => { if frac_digits > 0 { // [0.][0000] - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(frac_digits); - Formatted { sign, parts: &parts[..2] } + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(frac_digits)); + Formatted { + sign, + // SAFETY: we just initialized the elements `..2`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) }, + } } else { - parts[0] = Part::Copy(b"0"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"0")); + Formatted { + sign, + // SAFETY: we just initialized the elements `..1`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + } } } FullDecoded::Finite(ref decoded) => { @@ -716,23 +762,31 @@ where // `format_exact` will end rendering digits much earlier in this case, // because we are strictly limited by `maxlen`. let limit = if frac_digits < 0x8000 { -(frac_digits as i16) } else { i16::MIN }; - let (len, exp) = format_exact(decoded, &mut buf[..maxlen], limit); + let (buf, exp) = format_exact(decoded, &mut buf[..maxlen], limit); if exp <= limit { // the restriction couldn't been met, so this should render like zero no matter // `exp` was. this does not include the case that the restriction has been met // only after the final rounding-up; it's a regular case with `exp = limit + 1`. - debug_assert_eq!(len, 0); + debug_assert_eq!(buf.len(), 0); if frac_digits > 0 { // [0.][0000] - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(frac_digits); - Formatted { sign, parts: &parts[..2] } + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(frac_digits)); + Formatted { + sign, + // SAFETY: we just initialized the elements `..2`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) }, + } } else { - parts[0] = Part::Copy(b"0"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"0")); + Formatted { + sign, + // SAFETY: we just initialized the elements `..1`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + } } } else { - Formatted { sign, parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) } + Formatted { sign, parts: digits_to_dec_str(buf, exp, frac_digits, parts) } } } } diff --git a/library/core/src/num/flt2dec/strategy/dragon.rs b/library/core/src/num/flt2dec/strategy/dragon.rs index c8de000435..8ced5971ec 100644 --- a/library/core/src/num/flt2dec/strategy/dragon.rs +++ b/library/core/src/num/flt2dec/strategy/dragon.rs @@ -5,6 +5,7 @@ //! quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. use crate::cmp::Ordering; +use crate::mem::MaybeUninit; use crate::num::bignum::Big32x40 as Big; use crate::num::bignum::Digit32 as Digit; @@ -97,7 +98,10 @@ fn div_rem_upto_16<'a>( } /// The shortest mode implementation for Dragon. -pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp*/ i16) { +pub fn format_shortest<'a>( + d: &Decoded, + buf: &'a mut [MaybeUninit], +) -> (/*digits*/ &'a [u8], /*exp*/ i16) { // the number `v` to format is known to be: // - equal to `mant * 2^exp`; // - preceded by `(mant - 2 * minus) * 2^exp` in the original type; and @@ -186,7 +190,7 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp // generate one digit: `d[n] = floor(mant / scale) < 10`. let (d, _) = div_rem_upto_16(&mut mant, &scale, &scale2, &scale4, &scale8); debug_assert!(d < 10); - buf[i] = b'0' + d; + buf[i] = MaybeUninit::new(b'0' + d); i += 1; // this is a simplified description of the modified Dragon algorithm. @@ -241,18 +245,24 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp // if rounding up changes the length, the exponent should also change. // it seems that this condition is very hard to satisfy (possibly impossible), // but we are just being safe and consistent here. - if let Some(c) = round_up(buf, i) { - buf[i] = c; + // SAFETY: we initialized that memory above. + if let Some(c) = round_up(unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..i]) }) { + buf[i] = MaybeUninit::new(c); i += 1; k += 1; } } - (i, k) + // SAFETY: we initialized that memory above. + (unsafe { MaybeUninit::slice_assume_init_ref(&buf[..i]) }, k) } /// The exact and fixed mode implementation for Dragon. -pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usize, /*exp*/ i16) { +pub fn format_exact<'a>( + d: &Decoded, + buf: &'a mut [MaybeUninit], + limit: i16, +) -> (/*digits*/ &'a [u8], /*exp*/ i16) { assert!(d.mant > 0); assert!(d.minus > 0); assert!(d.plus > 0); @@ -319,9 +329,10 @@ pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usi // following digits are all zeroes, we stop here // do *not* try to perform rounding! rather, fill remaining digits. for c in &mut buf[i..len] { - *c = b'0'; + *c = MaybeUninit::new(b'0'); } - return (len, k); + // SAFETY: we initialized that memory above. + return (unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, k); } let mut d = 0; @@ -343,7 +354,7 @@ pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usi } debug_assert!(mant < scale); debug_assert!(d < 10); - buf[i] = b'0' + d; + buf[i] = MaybeUninit::new(b'0' + d); mant.mul_small(10); } } @@ -353,21 +364,25 @@ pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usi // round to even (i.e., avoid rounding up when the prior digit is even). let order = mant.cmp(scale.mul_small(5)); if order == Ordering::Greater - || (order == Ordering::Equal && (len == 0 || buf[len - 1] & 1 == 1)) + || (order == Ordering::Equal + // SAFETY: `buf[len-1]` is initialized. + && (len == 0 || unsafe { buf[len - 1].assume_init() } & 1 == 1)) { // if rounding up changes the length, the exponent should also change. // but we've been requested a fixed number of digits, so do not alter the buffer... - if let Some(c) = round_up(buf, len) { + // SAFETY: we initialized that memory above. + if let Some(c) = round_up(unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..len]) }) { // ...unless we've been requested the fixed precision instead. // we also need to check that, if the original buffer was empty, // the additional digit can only be added when `k == limit` (edge case). k += 1; if k > limit && len < buf.len() { - buf[len] = c; + buf[len] = MaybeUninit::new(c); len += 1; } } } - (len, k) + // SAFETY: we initialized that memory above. + (unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, k) } diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs index 1e2db212dd..a4cb51c629 100644 --- a/library/core/src/num/flt2dec/strategy/grisu.rs +++ b/library/core/src/num/flt2dec/strategy/grisu.rs @@ -5,6 +5,7 @@ //! [^1]: Florian Loitsch. 2010. Printing floating-point numbers quickly and //! accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. +use crate::mem::MaybeUninit; use crate::num::diy_float::Fp; use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS}; @@ -161,10 +162,10 @@ pub fn max_pow10_no_more_than(x: u32) -> (u8, u32) { /// The shortest mode implementation for Grisu. /// /// It returns `None` when it would return an inexact representation otherwise. -pub fn format_shortest_opt( +pub fn format_shortest_opt<'a>( d: &Decoded, - buf: &mut [u8], -) -> Option<(/*#digits*/ usize, /*exp*/ i16)> { + buf: &'a mut [MaybeUninit], +) -> Option<(/*digits*/ &'a [u8], /*exp*/ i16)> { assert!(d.mant > 0); assert!(d.minus > 0); assert!(d.plus > 0); @@ -266,14 +267,23 @@ pub fn format_shortest_opt( let q = remainder / ten_kappa; let r = remainder % ten_kappa; debug_assert!(q < 10); - buf[i] = b'0' + q as u8; + buf[i] = MaybeUninit::new(b'0' + q as u8); i += 1; let plus1rem = ((r as u64) << e) + plus1frac; // == (plus1 % 10^kappa) * 2^e if plus1rem < delta1 { // `plus1 % 10^kappa < delta1 = plus1 - minus1`; we've found the correct `kappa`. let ten_kappa = (ten_kappa as u64) << e; // scale 10^kappa back to the shared exponent - return round_and_weed(&mut buf[..i], exp, plus1rem, delta1, plus1 - v.f, ten_kappa, 1); + return round_and_weed( + // SAFETY: we initialized that memory above. + unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..i]) }, + exp, + plus1rem, + delta1, + plus1 - v.f, + ten_kappa, + 1, + ); } // break the loop when we have rendered all integral digits. @@ -310,13 +320,14 @@ pub fn format_shortest_opt( let q = remainder >> e; let r = remainder & ((1 << e) - 1); debug_assert!(q < 10); - buf[i] = b'0' + q as u8; + buf[i] = MaybeUninit::new(b'0' + q as u8); i += 1; if r < threshold { let ten_kappa = 1 << e; // implicit divisor return round_and_weed( - &mut buf[..i], + // SAFETY: we initialized that memory above. + unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..i]) }, exp, r, threshold, @@ -355,7 +366,7 @@ pub fn format_shortest_opt( plus1v: u64, ten_kappa: u64, ulp: u64, - ) -> Option<(usize, i16)> { + ) -> Option<(&[u8], i16)> { assert!(!buf.is_empty()); // produce two approximations to `v` (actually `plus1 - v`) within 1.5 ulps. @@ -437,20 +448,22 @@ pub fn format_shortest_opt( // this is too liberal, though, so we reject any `w(n)` not between `plus0` and `minus0`, // i.e., `plus1 - plus1w(n) <= minus0` or `plus1 - plus1w(n) >= plus0`. we utilize the facts // that `threshold = plus1 - minus1` and `plus1 - plus0 = minus0 - minus1 = 2 ulp`. - if 2 * ulp <= plus1w && plus1w <= threshold - 4 * ulp { - Some((buf.len(), exp)) - } else { - None - } + if 2 * ulp <= plus1w && plus1w <= threshold - 4 * ulp { Some((buf, exp)) } else { None } } } /// The shortest mode implementation for Grisu with Dragon fallback. /// /// This should be used for most cases. -pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp*/ i16) { +pub fn format_shortest<'a>( + d: &Decoded, + buf: &'a mut [MaybeUninit], +) -> (/*digits*/ &'a [u8], /*exp*/ i16) { use crate::num::flt2dec::strategy::dragon::format_shortest as fallback; - match format_shortest_opt(d, buf) { + // SAFETY: The borrow checker is not smart enough to let us use `buf` + // in the second branch, so we launder the lifetime here. But we only re-use + // `buf` if `format_shortest_opt` returned `None` so this is okay. + match format_shortest_opt(d, unsafe { &mut *(buf as *mut _) }) { Some(ret) => ret, None => fallback(d, buf), } @@ -459,11 +472,11 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp /// The exact and fixed mode implementation for Grisu. /// /// It returns `None` when it would return an inexact representation otherwise. -pub fn format_exact_opt( +pub fn format_exact_opt<'a>( d: &Decoded, - buf: &mut [u8], + buf: &'a mut [MaybeUninit], limit: i16, -) -> Option<(/*#digits*/ usize, /*exp*/ i16)> { +) -> Option<(/*digits*/ &'a [u8], /*exp*/ i16)> { assert!(d.mant > 0); assert!(d.mant < (1 << 61)); // we need at least three bits of additional precision assert!(!buf.is_empty()); @@ -510,7 +523,11 @@ pub fn format_exact_opt( // thus we are being sloppy here and widen the error range by a factor of 10. // this will increase the false negative rate, but only very, *very* slightly; // it can only matter noticeably when the mantissa is bigger than 60 bits. - return possibly_round(buf, 0, exp, limit, v.f / 10, (max_ten_kappa as u64) << e, err << e); + // + // SAFETY: `len=0`, so the obligation of having initialized this memory is trivial. + return unsafe { + possibly_round(buf, 0, exp, limit, v.f / 10, (max_ten_kappa as u64) << e, err << e) + }; } else if ((exp as i32 - limit as i32) as usize) < buf.len() { (exp - limit) as usize } else { @@ -534,13 +551,16 @@ pub fn format_exact_opt( let q = remainder / ten_kappa; let r = remainder % ten_kappa; debug_assert!(q < 10); - buf[i] = b'0' + q as u8; + buf[i] = MaybeUninit::new(b'0' + q as u8); i += 1; // is the buffer full? run the rounding pass with the remainder. if i == len { let vrem = ((r as u64) << e) + vfrac; // == (v % 10^kappa) * 2^e - return possibly_round(buf, len, exp, limit, vrem, (ten_kappa as u64) << e, err << e); + // SAFETY: we have initialized `len` many bytes. + return unsafe { + possibly_round(buf, len, exp, limit, vrem, (ten_kappa as u64) << e, err << e) + }; } // break the loop when we have rendered all integral digits. @@ -585,12 +605,13 @@ pub fn format_exact_opt( let q = remainder >> e; let r = remainder & ((1 << e) - 1); debug_assert!(q < 10); - buf[i] = b'0' + q as u8; + buf[i] = MaybeUninit::new(b'0' + q as u8); i += 1; // is the buffer full? run the rounding pass with the remainder. if i == len { - return possibly_round(buf, len, exp, limit, r, 1 << e, err); + // SAFETY: we have initialized `len` many bytes. + return unsafe { possibly_round(buf, len, exp, limit, r, 1 << e, err) }; } // restore invariants @@ -610,15 +631,17 @@ pub fn format_exact_opt( // - `remainder = (v % 10^kappa) * k` // - `ten_kappa = 10^kappa * k` // - `ulp = 2^-e * k` - fn possibly_round( - buf: &mut [u8], + // + // SAFETY: the first `len` bytes of `buf` must be initialized. + unsafe fn possibly_round( + buf: &mut [MaybeUninit], mut len: usize, mut exp: i16, limit: i16, remainder: u64, ten_kappa: u64, ulp: u64, - ) -> Option<(usize, i16)> { + ) -> Option<(&[u8], i16)> { debug_assert!(remainder < ten_kappa); // 10^kappa @@ -677,7 +700,8 @@ pub fn format_exact_opt( // we've already verified that `ulp < 10^kappa / 2`, so as long as // `10^kappa` did not overflow after all, the second check is fine. if ten_kappa - remainder > remainder && ten_kappa - 2 * remainder >= 2 * ulp { - return Some((len, exp)); + // SAFETY: our caller initialized that memory. + return Some((unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, exp)); } // :<------- remainder ------>| : @@ -698,17 +722,21 @@ pub fn format_exact_opt( // as `10^kappa` is never zero). also note that `remainder - ulp <= 10^kappa`, // so the second check does not overflow. if remainder > ulp && ten_kappa - (remainder - ulp) <= remainder - ulp { - if let Some(c) = round_up(buf, len) { + if let Some(c) = + // SAFETY: our caller must have initialized that memory. + round_up(unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..len]) }) + { // only add an additional digit when we've been requested the fixed precision. // we also need to check that, if the original buffer was empty, // the additional digit can only be added when `exp == limit` (edge case). exp += 1; if exp > limit && len < buf.len() { - buf[len] = c; + buf[len] = MaybeUninit::new(c); len += 1; } } - return Some((len, exp)); + // SAFETY: we and our caller initialized that memory. + return Some((unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, exp)); } // otherwise we are doomed (i.e., some values between `v - 1 ulp` and `v + 1 ulp` are @@ -720,9 +748,16 @@ pub fn format_exact_opt( /// The exact and fixed mode implementation for Grisu with Dragon fallback. /// /// This should be used for most cases. -pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usize, /*exp*/ i16) { +pub fn format_exact<'a>( + d: &Decoded, + buf: &'a mut [MaybeUninit], + limit: i16, +) -> (/*digits*/ &'a [u8], /*exp*/ i16) { use crate::num::flt2dec::strategy::dragon::format_exact as fallback; - match format_exact_opt(d, buf, limit) { + // SAFETY: The borrow checker is not smart enough to let us use `buf` + // in the second branch, so we launder the lifetime here. But we only re-use + // `buf` if `format_exact_opt` returned `None` so this is okay. + match format_exact_opt(d, unsafe { &mut *(buf as *mut _) }, limit) { Some(ret) => ret, None => fallback(d, buf, limit), } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index ffd30b03f2..369175fb6a 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1,49 +1,2201 @@ -#![doc(hidden)] - -macro_rules! doc_comment { - ($x:expr, $($tt:tt)*) => { - #[doc = $x] - $($tt)* - }; -} - -macro_rules! int_module { - ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]);); - ($T:ident, #[$attr:meta]) => ( +macro_rules! int_impl { + ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, + $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, + $reversed:expr, $le_bytes:expr, $be_bytes:expr, + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { doc_comment! { concat!("The smallest value that can be represented by this integer type. -Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead. # Examples -```rust -// deprecated way -let min = std::", stringify!($T), "::MIN; +Basic usage: -// intended way -let min = ", stringify!($T), "::MIN; ``` -"), - #[$attr] - pub const MIN: $T = $T::MIN; +", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");", +$EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; } doc_comment! { concat!("The largest value that can be represented by this integer type. -Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead. # Examples -```rust -// deprecated way -let max = std::", stringify!($T), "::MAX; +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");", +$EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MAX: Self = !Self::MIN; + } + + doc_comment! { + concat!("The size of this integer type in bits. + +# Examples + +``` +", $Feature, "#![feature(int_bits_const)] +assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[unstable(feature = "int_bits_const", issue = "76904")] + pub const BITS: u32 = $BITS; + } + + doc_comment! { + concat!("Converts a string slice in a given base to an integer. + +The string is expected to be an optional `+` or `-` sign followed by digits. +Leading and trailing whitespace represent an error. Digits are a subset of these characters, +depending on `radix`: + + * `0-9` + * `a-z` + * `A-Z` + +# Panics + +This function panics if `radix` is not in the range from 2 to 36. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_str_radix(src: &str, radix: u32) -> Result { + from_str_radix(src, radix) + } + } + + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b100_0000", stringify!($SelfT), "; -// intended way -let max = ", stringify!($T), "::MAX; +assert_eq!(n.count_ones(), 1);", +$EndFeature, " ``` "), - #[$attr] - pub const MAX: $T = $T::MAX; + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } + } + + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = -1", stringify!($SelfT), "; + +assert_eq!(n.leading_zeros(), 0);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + (self as $UnsignedT).leading_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = -4", stringify!($SelfT), "; + +assert_eq!(n.trailing_zeros(), 2);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + (self as $UnsignedT).trailing_zeros() + } + } + + doc_comment! { + concat!("Returns the number of leading ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = -1", stringify!($SelfT), "; + +assert_eq!(n.leading_ones(), ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn leading_ones(self) -> u32 { + (self as $UnsignedT).leading_ones() + } + } + + doc_comment! { + concat!("Returns the number of trailing ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 3", stringify!($SelfT), "; + +assert_eq!(n.trailing_ones(), 2);", +$EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn trailing_ones(self) -> u32 { + (self as $UnsignedT).trailing_ones() + } + } + + doc_comment! { + concat!("Shifts the bits to the left by a specified amount, `n`, +wrapping the truncated bits to the end of the resulting integer. + +Please note this isn't the same operation as the `<<` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_op, stringify!($SelfT), "; +let m = ", $rot_result, "; + +assert_eq!(n.rotate_left(", $rot, "), m); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn rotate_left(self, n: u32) -> Self { + (self as $UnsignedT).rotate_left(n) as Self + } + } + + doc_comment! { + concat!("Shifts the bits to the right by a specified amount, `n`, +wrapping the truncated bits to the beginning of the resulting +integer. + +Please note this isn't the same operation as the `>>` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_result, stringify!($SelfT), "; +let m = ", $rot_op, "; + +assert_eq!(n.rotate_right(", $rot, "), m); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn rotate_right(self, n: u32) -> Self { + (self as $UnsignedT).rotate_right(n) as Self + } + } + + doc_comment! { + concat!("Reverses the byte order of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; + +let m = n.swap_bytes(); + +assert_eq!(m, ", $swapped, "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn swap_bytes(self) -> Self { + (self as $UnsignedT).swap_bytes() as Self + } + } + + doc_comment! { + concat!("Reverses the bit pattern of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; +let m = n.reverse_bits(); + +assert_eq!(m, ", $reversed, "); +```"), + #[stable(feature = "reverse_bits", since = "1.37.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + #[must_use] + pub const fn reverse_bits(self) -> Self { + (self as $UnsignedT).reverse_bits() as Self + } + } + + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(", stringify!($SelfT), "::from_be(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(", stringify!($SelfT), "::from_le(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Checked integer addition. Computes `self + rhs`, returning `None` +if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1)); +assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), +"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_add(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_add`. + unsafe { intrinsics::unchecked_add(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1)); +assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), +"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_sub`. + unsafe { intrinsics::unchecked_sub(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), +"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_mul(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), +"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_mul`. + unsafe { intrinsics::unchecked_mul(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0` +or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::MIN + 1).checked_div(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + // SAFETY: div by zero and by INT_MIN have been checked above + Some(unsafe { intrinsics::unchecked_div(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, +returning `None` if `rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +assert_eq!((", stringify!($SelfT), +"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + Some(self.div_euclid(rhs)) + } + } + } + + doc_comment! { + concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if +`rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + // SAFETY: div by zero and by INT_MIN have been checked above + Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` +if `rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + Some(self.rem_euclid(rhs)) + } + } + } + + doc_comment! { + concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[inline] + pub const fn checked_neg(self) -> Option { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger +than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_shl(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is +larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_shr(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked absolute value. Computes `self.abs()`, returning `None` if +`self == MIN`. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[inline] + pub const fn checked_abs(self) -> Option { + if self.is_negative() { + self.checked_neg() + } else { + Some(self) + } + } + } + + doc_comment! { + concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", +$EndFeature, " +```"), + + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_pow(self, mut exp: u32) -> Option { + if exp == 0 { + return Some(1); + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = try_opt!(acc.checked_mul(base)); + } + exp /= 2; + base = try_opt!(base.checked_mul(base)); + } + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + Some(try_opt!(acc.checked_mul(base))) + } + } + + doc_comment! { + concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric +bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT), +"::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT), +"::MIN);", +$EndFeature, " +```"), + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add(self, rhs: Self) -> Self { + intrinsics::saturating_add(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT), +"::MIN); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT), +"::MAX);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_sub(self, rhs: Self) -> Self { + intrinsics::saturating_sub(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` +instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); +assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT), +"::MAX); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT), +"::MIN + 1);", +$EndFeature, " +```"), + + #[stable(feature = "saturating_neg", since = "1.45.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_neg(self) -> Self { + intrinsics::saturating_sub(0, self) + } + } + + doc_comment! { + concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == +MIN` instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT), +"::MAX); +assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT), +"::MAX);", +$EndFeature, " +```"), + + #[stable(feature = "saturating_neg", since = "1.45.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_abs(self) -> Self { + if self.is_negative() { + self.saturating_neg() + } else { + self + } + } + } + + doc_comment! { + concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(x) => x, + None => if (self < 0) == (rhs < 0) { + Self::MAX + } else { + Self::MIN + } + } + } + } + + doc_comment! { + concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Some(x) => x, + None if self < 0 && exp % 2 == 1 => Self::MIN, + None => Self::MAX, + } + } + } + + doc_comment! { + concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the +boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); +assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT), +"::MIN + 1);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_add(self, rhs: Self) -> Self { + intrinsics::wrapping_add(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the +boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); +assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ", +stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_sub(self, rhs: Self) -> Self { + intrinsics::wrapping_sub(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at +the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); +assert_eq!(11i8.wrapping_mul(12), -124);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_mul(self, rhs: Self) -> Self { + intrinsics::wrapping_mul(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the +boundary of the type. + +The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where +`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value +that is too large to represent in the type. In such a case, this function returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); +assert_eq!((-128i8).wrapping_div(-1), -128);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div(self, rhs: Self) -> Self { + self.overflowing_div(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`, +wrapping around at the boundary of the type. + +Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value +for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the +type. In this case, this method returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); +assert_eq!((-128i8).wrapping_div_euclid(-1), -128); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { + self.overflowing_div_euclid(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the +boundary of the type. + +Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` +invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, +this function returns `0`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); +assert_eq!((-128i8).wrapping_rem(-1), 0);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem(self, rhs: Self) -> Self { + self.overflowing_rem(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around +at the boundary of the type. + +Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value +for the type). In this case, this method returns 0. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); +assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { + self.overflowing_rem_euclid(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary +of the type. + +The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN` +is the negative minimal value for the type); this is a positive value that is too large to represent +in the type. In such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); +assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT), +"::MIN);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } + } + + doc_comment! { + concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes +any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to +the range of the type, rather than the bits shifted out of the LHS being returned to the other end. +The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); +assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_shl(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` +removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted +to the range of the type, rather than the bits shifted out of the LHS being returned to the other +end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); +assert_eq!((-128i16).wrapping_shr(64), -128);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_shr(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at +the boundary of the type. + +The only case where such wrapping can occur is when one takes the absolute value of the negative +minimal value for the type; this is a positive value that is too large to represent in the type. In +such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100); +assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT), +"::MIN); +assert_eq!((-128i8).wrapping_abs() as u8, 128);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[allow(unused_attributes)] + #[inline] + pub const fn wrapping_abs(self) -> Self { + if self.is_negative() { + self.wrapping_neg() + } else { + self + } + } + } + + doc_comment! { + concat!("Computes the absolute value of `self` without any wrapping +or panicking. + + +# Examples + +Basic usage: + +``` +", $Feature, "#![feature(unsigned_abs)] +assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), "); +assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), "); +assert_eq!((-128i8).unsigned_abs(), 128u8);", +$EndFeature, " +```"), + #[unstable(feature = "unsigned_abs", issue = "74913")] + #[inline] + pub const fn unsigned_abs(self) -> $UnsignedT { + self.wrapping_abs() as $UnsignedT + } + } + + doc_comment! { + concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81); +assert_eq!(3i8.wrapping_pow(5), -13); +assert_eq!(3i8.wrapping_pow(6), -39);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + exp /= 2; + base = base.wrapping_mul(base); + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.wrapping_mul(base) + } + } + + doc_comment! { + concat!("Calculates `self` + `rhs` + +Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), +"::MIN, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates `self` - `rhs` + +Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow +would occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), +"::MAX, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates the multiplication of `self` and `rhs`. + +Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow +would occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); +assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates the divisor when `self` is divided by `rhs`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then self is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), +"::MIN, true));", +$EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { + if unlikely!(self == Self::MIN && rhs == -1) { + (self, true) + } else { + (self / rhs, false) + } + } + } + + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then `self` is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), +"::MIN, true)); +```"), + #[inline] + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + if unlikely!(self == Self::MIN && rhs == -1) { + (self, true) + } else { + (self.div_euclid(rhs), false) + } + } + } + + doc_comment! { + concat!("Calculates the remainder when `self` is divided by `rhs`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));", +$EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + if unlikely!(self == Self::MIN && rhs == -1) { + (0, true) + } else { + (self % rhs, false) + } + } + } + + + doc_comment! { + concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { + if unlikely!(self == Self::MIN && rhs == -1) { + (0, true) + } else { + (self.rem_euclid(rhs), false) + } + } + } + + + doc_comment! { + concat!("Negates self, overflowing if this is equal to the minimum value. + +Returns a tuple of the negated version of self along with a boolean indicating whether an overflow +happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the +minimum value will be returned again and `true` will be returned for an overflow happening. + +# Examples + +Basic usage: + +``` +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), +"::MIN, true));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[allow(unused_attributes)] + pub const fn overflowing_neg(self) -> (Self, bool) { + if unlikely!(self == Self::MIN) { + (Self::MIN, true) + } else { + (-self, false) + } + } + } + + doc_comment! { + concat!("Shifts self left by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false)); +assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Shifts self right by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Computes the absolute value of `self`. + +Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow +happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type + ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned +for an overflow happening. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); +assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false)); +assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT), +"::MIN, true));", +$EndFeature, " +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn overflowing_abs(self) -> (Self, bool) { + (self.wrapping_abs(), self == Self::MIN) + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +Returns a tuple of the exponentiation along with a bool indicating +whether an overflow happened. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false)); +assert_eq!(3i8.overflowing_pow(5), (-13, true));", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { + if exp == 0 { + return (1,false); + } + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + exp /= 2; + r = base.overflowing_mul(base); + base = r.0; + overflown |= r.1; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + r = acc.overflowing_mul(base); + r.1 |= overflown; + r + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type + +assert_eq!(x.pow(5), 32);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; + } + exp /= 2; + base = base * base; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc * base + } + } + + doc_comment! { + concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. + +This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`, +with `0 <= self.rem_euclid(rhs) < rhs`. + +In other words, the result is `self / rhs` rounded to the integer `n` +such that `self >= n * rhs`. +If `self > 0`, this is equal to round towards zero (the default in Rust); +if `self < 0`, this is equal to round towards +/- infinity. + +# Panics + +This function will panic if `rhs` is 0 or the division results in overflow. + +# Examples + +Basic usage: + +``` +let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1 +assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1 +assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 +assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn div_euclid(self, rhs: Self) -> Self { + let q = self / rhs; + if self % rhs < 0 { + return if rhs > 0 { q - 1 } else { q + 1 } + } + q + } + } + + + doc_comment! { + concat!("Calculates the least nonnegative remainder of `self (mod rhs)`. + +This is done as if by the Euclidean division algorithm -- given +`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and +`0 <= r < abs(rhs)`. + +# Panics + +This function will panic if `rhs` is 0 or the division results in overflow. + +# Examples + +Basic usage: + +``` +let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.rem_euclid(b), 3); +assert_eq!((-a).rem_euclid(b), 1); +assert_eq!(a.rem_euclid(-b), 3); +assert_eq!((-a).rem_euclid(-b), 1); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn rem_euclid(self, rhs: Self) -> Self { + let r = self % rhs; + if r < 0 { + if rhs < 0 { + r - rhs + } else { + r + rhs + } + } else { + r + } + } + } + + doc_comment! { + concat!("Computes the absolute value of `self`. + +# Overflow behavior + +The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an +`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that +code in debug mode will trigger a panic on this case and optimized code will return `", +stringify!($SelfT), "::MIN` without a panic. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10); +assert_eq!((-10", stringify!($SelfT), ").abs(), 10);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[allow(unused_attributes)] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn abs(self) -> Self { + // Note that the #[inline] above means that the overflow + // semantics of the subtraction depend on the crate we're being + // inlined into. + if self.is_negative() { + -self + } else { + self + } + } + } + + doc_comment! { + concat!("Returns a number representing sign of `self`. + + - `0` if the number is zero + - `1` if the number is positive + - `-1` if the number is negative + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1); +assert_eq!(0", stringify!($SelfT), ".signum(), 0); +assert_eq!((-10", stringify!($SelfT), ").signum(), -1);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")] + #[inline] + pub const fn signum(self) -> Self { + match self { + n if n > 0 => 1, + 0 => 0, + _ => -1, + } + } + } + + doc_comment! { + concat!("Returns `true` if `self` is positive and `false` if the number is zero or +negative. + +# Examples + +Basic usage: + +``` +", $Feature, "assert!(10", stringify!($SelfT), ".is_positive()); +assert!(!(-10", stringify!($SelfT), ").is_positive());", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn is_positive(self) -> bool { self > 0 } + } + + doc_comment! { + concat!("Returns `true` if `self` is negative and `false` if the number is zero or +positive. + +# Examples + +Basic usage: + +``` +", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative()); +assert!(!10", stringify!($SelfT), ".is_negative());", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn is_negative(self) -> bool { self < 0 } + } + + doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +big-endian (network) byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); +assert_eq!(bytes, ", $be_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { + self.to_be().to_ne_bytes() + } + } + +doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +little-endian byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); +assert_eq!(bytes, ", $le_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { + self.to_le().to_ne_bytes() + } + } + + doc_comment! { + concat!(" +Return the memory representation of this integer as a byte array in +native byte order. + +As the target platform's native endianness is used, portable code +should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, +instead. +", +$to_xe_bytes_doc, +" +[`to_be_bytes`]: #method.to_be_bytes +[`to_le_bytes`]: #method.to_le_bytes + +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); +assert_eq!( + bytes, + if cfg!(target_endian = \"big\") { + ", $be_bytes, " + } else { + ", $le_bytes, " + } +); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute them to arrays of bytes + #[allow_internal_unstable(const_fn_transmute)] + #[inline] + pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + // SAFETY: integers are plain old datatypes so we can always transmute them to + // arrays of bytes + unsafe { mem::transmute(self) } + } + } + +doc_comment! { + concat!("Create an integer value from its representation as a byte array in +big endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_be(Self::from_ne_bytes(bytes)) + } + } + +doc_comment! { + concat!(" +Create an integer value from its representation as a byte array in +little endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + } + + doc_comment! { + concat!("Create an integer value from its memory representation as a byte +array in native endianness. + +As the target platform's native endianness is used, portable code +likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as +appropriate instead. + +[`from_be_bytes`]: #method.from_be_bytes +[`from_le_bytes`]: #method.from_le_bytes +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { + ", $be_bytes, " +} else { + ", $le_bytes, " +}); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute to them + #[allow_internal_unstable(const_fn_transmute)] + #[inline] + pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + // SAFETY: integers are plain old datatypes so we can always transmute to them + unsafe { mem::transmute(bytes) } + } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause a compilation warning, +new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. + +Returns the smallest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] + #[rustc_promotable] + #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")] + pub const fn min_value() -> Self { + Self::MIN + } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause a compilation warning, +new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. + +Returns the largest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] + #[rustc_promotable] + #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] + pub const fn max_value() -> Self { + Self::MAX + } } - ) + } } diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 7a88cfbb74..4f64e30ccf 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1,4512 +1,157 @@ -// ignore-tidy-filelength - -//! Numeric traits and functions for the built-in numeric types. - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::convert::Infallible; -use crate::fmt; -use crate::intrinsics; -use crate::mem; -use crate::ops::{BitOr, BitOrAssign}; -use crate::str::FromStr; - -// Used because the `?` operator is not allowed in a const context. -macro_rules! try_opt { - ($e:expr) => { - match $e { - Some(x) => x, - None => return None, - } - }; -} - -#[allow_internal_unstable(const_likely)] -macro_rules! unlikely { - ($e: expr) => { - intrinsics::unlikely($e) - }; -} - -macro_rules! impl_nonzero_fmt { - ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { - $( - #[$stability] - impl fmt::$Trait for $Ty { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.get().fmt(f) - } - } - )+ - } -} - -macro_rules! doc_comment { - ($x:expr, $($tt:tt)*) => { - #[doc = $x] - $($tt)* - }; -} - -macro_rules! nonzero_integers { - ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => { - $( - doc_comment! { - concat!("An integer that is known not to equal zero. - -This enables some memory layout optimization. -For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`: - -```rust -use std::mem::size_of; -assert_eq!(size_of::>(), size_of::<", stringify!($Int), -">()); -```"), - #[$stability] - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] - #[repr(transparent)] - #[rustc_layout_scalar_valid_range_start(1)] - #[rustc_nonnull_optimization_guaranteed] - pub struct $Ty($Int); - } - - impl $Ty { - /// Creates a non-zero without checking the value. - /// - /// # Safety - /// - /// The value must not be zero. - #[$stability] - #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] - #[inline] - pub const unsafe fn new_unchecked(n: $Int) -> Self { - // SAFETY: this is guaranteed to be safe by the caller. - unsafe { Self(n) } - } - - /// Creates a non-zero if the given value is not zero. - #[$stability] - #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] - #[inline] - pub const fn new(n: $Int) -> Option { - if n != 0 { - // SAFETY: we just checked that there's no `0` - Some(unsafe { Self(n) }) - } else { - None - } - } - - /// Returns the value as a primitive type. - #[$stability] - #[inline] - #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] - pub const fn get(self) -> $Int { - self.0 - } - - } - - #[stable(feature = "from_nonzero", since = "1.31.0")] - impl From<$Ty> for $Int { - doc_comment! { - concat!( -"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"), - fn from(nonzero: $Ty) -> Self { - nonzero.0 - } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr for $Ty { - type Output = Self; - #[inline] - fn bitor(self, rhs: Self) -> Self::Output { - // Safety: since `self` and `rhs` are both nonzero, the - // result of the bitwise-or will be nonzero. - unsafe { $Ty::new_unchecked(self.get() | rhs.get()) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr<$Int> for $Ty { - type Output = Self; - #[inline] - fn bitor(self, rhs: $Int) -> Self::Output { - // Safety: since `self` is nonzero, the result of the - // bitwise-or will be nonzero regardless of the value of - // `rhs`. - unsafe { $Ty::new_unchecked(self.get() | rhs) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr<$Ty> for $Int { - type Output = $Ty; - #[inline] - fn bitor(self, rhs: $Ty) -> Self::Output { - // Safety: since `rhs` is nonzero, the result of the - // bitwise-or will be nonzero regardless of the value of - // `self`. - unsafe { $Ty::new_unchecked(self | rhs.get()) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOrAssign for $Ty { - #[inline] - fn bitor_assign(&mut self, rhs: Self) { - *self = *self | rhs; - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOrAssign<$Int> for $Ty { - #[inline] - fn bitor_assign(&mut self, rhs: $Int) { - *self = *self | rhs; - } - } - - impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty - } - )+ - } -} - -nonzero_integers! { - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); -} - -macro_rules! from_str_radix_nzint_impl { - ($($t:ty)*) => {$( - #[stable(feature = "nonzero_parse", since = "1.35.0")] - impl FromStr for $t { - type Err = ParseIntError; - fn from_str(src: &str) -> Result { - Self::new(from_str_radix(src, 10)?) - .ok_or(ParseIntError { - kind: IntErrorKind::Zero - }) - } - } - )*} -} - -from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize -NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } - -/// Provides intentionally-wrapped arithmetic on `T`. -/// -/// Operations like `+` on `u32` values are intended to never overflow, -/// and in some debug configurations overflow is detected and results -/// in a panic. While most arithmetic falls into this category, some -/// code explicitly expects and relies upon modular arithmetic (e.g., -/// hashing). -/// -/// Wrapping arithmetic can be achieved either through methods like -/// `wrapping_add`, or through the `Wrapping` type, which says that -/// all standard arithmetic operations on the underlying value are -/// intended to have wrapping semantics. -/// -/// The underlying value can be retrieved through the `.0` index of the -/// `Wrapping` tuple. -/// -/// # Examples -/// -/// ``` -/// use std::num::Wrapping; -/// -/// let zero = Wrapping(0u32); -/// let one = Wrapping(1u32); -/// -/// assert_eq!(u32::MAX, (zero - one).0); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] -#[repr(transparent)] -pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_display", since = "1.10.0")] -impl fmt::Display for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::Binary for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::Octal for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::LowerHex for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::UpperHex for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -// All these modules are technically private and only exposed for coretests: -pub mod bignum; -pub mod dec2flt; -pub mod diy_float; -pub mod flt2dec; - -mod wrapping; - -macro_rules! usize_isize_to_xe_bytes_doc { - () => { - " - -**Note**: This function returns an array of length 2, 4 or 8 bytes -depending on the target pointer size. - -" - }; -} - -macro_rules! usize_isize_from_xe_bytes_doc { - () => { - " - -**Note**: This function takes an array of length 2, 4 or 8 bytes -depending on the target pointer size. - -" - }; -} - -macro_rules! int_impl { - ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, - $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, - $reversed:expr, $le_bytes:expr, $be_bytes:expr, - $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { - doc_comment! { - concat!("The smallest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");", -$EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; - } - - doc_comment! { - concat!("The largest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");", -$EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX: Self = !Self::MIN; - } - - doc_comment! { - concat!("Converts a string slice in a given base to an integer. - -The string is expected to be an optional `+` or `-` sign followed by digits. -Leading and trailing whitespace represent an error. Digits are a subset of these characters, -depending on `radix`: - - * `0-9` - * `a-z` - * `A-Z` - -# Panics - -This function panics if `radix` is not in the range from 2 to 36. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) - } - } - - doc_comment! { - concat!("Returns the number of ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b100_0000", stringify!($SelfT), "; - -assert_eq!(n.count_ones(), 1);", -$EndFeature, " -``` -"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } - } - - doc_comment! { - concat!("Returns the number of zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - - doc_comment! { - concat!("Returns the number of leading zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = -1", stringify!($SelfT), "; - -assert_eq!(n.leading_zeros(), 0);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn leading_zeros(self) -> u32 { - (self as $UnsignedT).leading_zeros() - } - } - - doc_comment! { - concat!("Returns the number of trailing zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = -4", stringify!($SelfT), "; - -assert_eq!(n.trailing_zeros(), 2);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn trailing_zeros(self) -> u32 { - (self as $UnsignedT).trailing_zeros() - } - } - - doc_comment! { - concat!("Returns the number of leading ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = -1", stringify!($SelfT), "; - -assert_eq!(n.leading_ones(), ", stringify!($BITS), ");", -$EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn leading_ones(self) -> u32 { - (self as $UnsignedT).leading_ones() - } - } - - doc_comment! { - concat!("Returns the number of trailing ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 3", stringify!($SelfT), "; - -assert_eq!(n.trailing_ones(), 2);", -$EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn trailing_ones(self) -> u32 { - (self as $UnsignedT).trailing_ones() - } - } - - doc_comment! { - concat!("Shifts the bits to the left by a specified amount, `n`, -wrapping the truncated bits to the end of the resulting integer. - -Please note this isn't the same operation as the `<<` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_op, stringify!($SelfT), "; -let m = ", $rot_result, "; - -assert_eq!(n.rotate_left(", $rot, "), m); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn rotate_left(self, n: u32) -> Self { - (self as $UnsignedT).rotate_left(n) as Self - } - } - - doc_comment! { - concat!("Shifts the bits to the right by a specified amount, `n`, -wrapping the truncated bits to the beginning of the resulting -integer. - -Please note this isn't the same operation as the `>>` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_result, stringify!($SelfT), "; -let m = ", $rot_op, "; - -assert_eq!(n.rotate_right(", $rot, "), m); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn rotate_right(self, n: u32) -> Self { - (self as $UnsignedT).rotate_right(n) as Self - } - } - - doc_comment! { - concat!("Reverses the byte order of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; - -let m = n.swap_bytes(); - -assert_eq!(m, ", $swapped, "); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn swap_bytes(self) -> Self { - (self as $UnsignedT).swap_bytes() as Self - } - } - - doc_comment! { - concat!("Reverses the bit pattern of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; -let m = n.reverse_bits(); - -assert_eq!(m, ", $reversed, "); -```"), - #[stable(feature = "reverse_bits", since = "1.37.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - #[must_use] - pub const fn reverse_bits(self) -> Self { - (self as $UnsignedT).reverse_bits() as Self - } - } - - doc_comment! { - concat!("Converts an integer from big endian to the target's endianness. - -On big endian this is a no-op. On little endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(", stringify!($SelfT), "::from_be(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn from_be(x: Self) -> Self { - #[cfg(target_endian = "big")] - { - x - } - #[cfg(not(target_endian = "big"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts an integer from little endian to the target's endianness. - -On little endian this is a no-op. On big endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(", stringify!($SelfT), "::from_le(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn from_le(x: Self) -> Self { - #[cfg(target_endian = "little")] - { - x - } - #[cfg(not(target_endian = "little"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to big endian from the target's endianness. - -On big endian this is a no-op. On little endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(n.to_be(), n) -} else { - assert_eq!(n.to_be(), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn to_be(self) -> Self { // or not to be? - #[cfg(target_endian = "big")] - { - self - } - #[cfg(not(target_endian = "big"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to little endian from the target's endianness. - -On little endian this is a no-op. On big endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(n.to_le(), n) -} else { - assert_eq!(n.to_le(), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn to_le(self) -> Self { - #[cfg(target_endian = "little")] - { - self - } - #[cfg(not(target_endian = "little"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Checked integer addition. Computes `self + rhs`, returning `None` -if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), -"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1)); -assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_add(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), -"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_add(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_add`. - unsafe { intrinsics::unchecked_add(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), -"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1)); -assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_sub(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), -"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_sub`. - unsafe { intrinsics::unchecked_sub(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), -"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_mul(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), -"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_mul`. - unsafe { intrinsics::unchecked_mul(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0` -or the division results in overflow. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), -"::MIN + 1).checked_div(-1), Some(", stringify!($Max), ")); -assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None); -assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - // SAFETY: div by zero and by INT_MIN have been checked above - Some(unsafe { intrinsics::unchecked_div(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, -returning `None` if `rhs == 0` or the division results in overflow. - -# Examples - -Basic usage: - -``` -assert_eq!((", stringify!($SelfT), -"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), ")); -assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None); -assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - Some(self.div_euclid(rhs)) - } - } - } - - doc_comment! { - concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if -`rhs == 0` or the division results in overflow. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); -assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - // SAFETY: div by zero and by INT_MIN have been checked above - Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` -if `rhs == 0` or the division results in overflow. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); -assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - Some(self.rem_euclid(rhs)) - } - } - } - - doc_comment! { - concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5)); -assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[inline] - pub const fn checked_neg(self) -> Option { - let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger -than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); -assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_shl(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is -larger than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_shr(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked absolute value. Computes `self.abs()`, returning `None` if -`self == MIN`. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5)); -assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[inline] - pub const fn checked_abs(self) -> Option { - if self.is_negative() { - self.checked_neg() - } else { - Some(self) - } - } - } - - doc_comment! { - concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", -$EndFeature, " -```"), - - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_pow(self, mut exp: u32) -> Option { - if exp == 0 { - return Some(1); - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = try_opt!(acc.checked_mul(base)); - } - exp /= 2; - base = try_opt!(base.checked_mul(base)); - } - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - Some(try_opt!(acc.checked_mul(base))) - } - } - - doc_comment! { - concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric -bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT), -"::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT), -"::MIN);", -$EndFeature, " -```"), - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_add(self, rhs: Self) -> Self { - intrinsics::saturating_add(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the -numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT), -"::MIN); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT), -"::MAX);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_sub(self, rhs: Self) -> Self { - intrinsics::saturating_sub(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` -instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); -assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT), -"::MAX); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT), -"::MIN + 1);", -$EndFeature, " -```"), - - #[stable(feature = "saturating_neg", since = "1.45.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_neg(self) -> Self { - intrinsics::saturating_sub(0, self) - } - } - - doc_comment! { - concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == -MIN` instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); -assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT), -"::MAX); -assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT), -"::MAX);", -$EndFeature, " -```"), - - #[stable(feature = "saturating_neg", since = "1.45.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_abs(self) -> Self { - if self.is_negative() { - self.saturating_neg() - } else { - self - } - } - } - - doc_comment! { - concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the -numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_mul(self, rhs: Self) -> Self { - match self.checked_mul(rhs) { - Some(x) => x, - None => if (self < 0) == (rhs < 0) { - Self::MAX - } else { - Self::MIN - } - } - } - } - - doc_comment! { - concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, -saturating at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_pow(self, exp: u32) -> Self { - match self.checked_pow(exp) { - Some(x) => x, - None if self < 0 && exp % 2 == 1 => Self::MIN, - None => Self::MAX, - } - } - } - - doc_comment! { - concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the -boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); -assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT), -"::MIN + 1);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::wrapping_add(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the -boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); -assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ", -stringify!($SelfT), "::MAX);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::wrapping_sub(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at -the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); -assert_eq!(11i8.wrapping_mul(12), -124);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::wrapping_mul(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the -boundary of the type. - -The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where -`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value -that is too large to represent in the type. In such a case, this function returns `MIN` itself. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); -assert_eq!((-128i8).wrapping_div(-1), -128);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div(self, rhs: Self) -> Self { - self.overflowing_div(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`, -wrapping around at the boundary of the type. - -Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value -for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the -type. In this case, this method returns `MIN` itself. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); -assert_eq!((-128i8).wrapping_div_euclid(-1), -128); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { - self.overflowing_div_euclid(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the -boundary of the type. - -Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` -invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, -this function returns `0`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); -assert_eq!((-128i8).wrapping_rem(-1), 0);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem(self, rhs: Self) -> Self { - self.overflowing_rem(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around -at the boundary of the type. - -Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value -for the type). In this case, this method returns 0. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); -assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { - self.overflowing_rem_euclid(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary -of the type. - -The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN` -is the negative minimal value for the type); this is a positive value that is too large to represent -in the type. In such a case, this function returns `MIN` itself. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); -assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT), -"::MIN);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 - } - } - - doc_comment! { - concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes -any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to -the range of the type, rather than the bits shifted out of the LHS being returned to the other end. -The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); -assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_shl(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` -removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted -to the range of the type, rather than the bits shifted out of the LHS being returned to the other -end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); -assert_eq!((-128i16).wrapping_shr(64), -128);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_shr(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at -the boundary of the type. - -The only case where such wrapping can occur is when one takes the absolute value of the negative -minimal value for the type; this is a positive value that is too large to represent in the type. In -such a case, this function returns `MIN` itself. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); -assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100); -assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT), -"::MIN); -assert_eq!((-128i8).wrapping_abs() as u8, 128);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[allow(unused_attributes)] - #[inline] - pub const fn wrapping_abs(self) -> Self { - if self.is_negative() { - self.wrapping_neg() - } else { - self - } - } - } - - doc_comment! { - concat!("Computes the absolute value of `self` without any wrapping -or panicking. - - -# Examples - -Basic usage: - -``` -", $Feature, "#![feature(unsigned_abs)] -assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), "); -assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), "); -assert_eq!((-128i8).unsigned_abs(), 128u8);", -$EndFeature, " -```"), - #[unstable(feature = "unsigned_abs", issue = "74913")] - #[inline] - pub const fn unsigned_abs(self) -> $UnsignedT { - self.wrapping_abs() as $UnsignedT - } - } - - doc_comment! { - concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81); -assert_eq!(3i8.wrapping_pow(5), -13); -assert_eq!(3i8.wrapping_pow(6), -39);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - } - exp /= 2; - base = base.wrapping_mul(base); - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.wrapping_mul(base) - } - } - - doc_comment! { - concat!("Calculates `self` + `rhs` - -Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would -occur. If an overflow would have occurred then the wrapped value is returned. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); -assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), -"::MIN, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates `self` - `rhs` - -Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow -would occur. If an overflow would have occurred then the wrapped value is returned. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), -"::MAX, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates the multiplication of `self` and `rhs`. - -Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow -would occur. If an overflow would have occurred then the wrapped value is returned. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); -assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates the divisor when `self` is divided by `rhs`. - -Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would -occur. If an overflow would occur then self is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), -"::MIN, true));", -$EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (self, true) - } else { - (self / rhs, false) - } - } - } - - doc_comment! { - concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. - -Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would -occur. If an overflow would occur then `self` is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), -"::MIN, true)); -```"), - #[inline] - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (self, true) - } else { - (self.div_euclid(rhs), false) - } - } - } - - doc_comment! { - concat!("Calculates the remainder when `self` is divided by `rhs`. - -Returns a tuple of the remainder after dividing along with a boolean indicating whether an -arithmetic overflow would occur. If an overflow would occur then 0 is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));", -$EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (0, true) - } else { - (self % rhs, false) - } - } - } - - - doc_comment! { - concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`. - -Returns a tuple of the remainder after dividing along with a boolean indicating whether an -arithmetic overflow would occur. If an overflow would occur then 0 is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (0, true) - } else { - (self.rem_euclid(rhs), false) - } - } - } - - - doc_comment! { - concat!("Negates self, overflowing if this is equal to the minimum value. - -Returns a tuple of the negated version of self along with a boolean indicating whether an overflow -happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the -minimum value will be returned again and `true` will be returned for an overflow happening. - -# Examples - -Basic usage: - -``` -assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), -"::MIN, true));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[allow(unused_attributes)] - pub const fn overflowing_neg(self) -> (Self, bool) { - if unlikely!(self == Self::MIN) { - (Self::MIN, true) - } else { - (-self, false) - } - } - } - - doc_comment! { - concat!("Shifts self left by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean indicating whether the shift -value was larger than or equal to the number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then used to perform the shift. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false)); -assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Shifts self right by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean indicating whether the shift -value was larger than or equal to the number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then used to perform the shift. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); -assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Computes the absolute value of `self`. - -Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow -happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type - ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned -for an overflow happening. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); -assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false)); -assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT), -"::MIN, true));", -$EndFeature, " -```"), - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn overflowing_abs(self) -> (Self, bool) { - (self.wrapping_abs(), self == Self::MIN) - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -Returns a tuple of the exponentiation along with a bool indicating -whether an overflow happened. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false)); -assert_eq!(3i8.overflowing_pow(5), (-13, true));", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { - if exp == 0 { - return (1,false); - } - let mut base = self; - let mut acc: Self = 1; - let mut overflown = false; - // Scratch space for storing results of overflowing_mul. - let mut r; - - while exp > 1 { - if (exp & 1) == 1 { - r = acc.overflowing_mul(base); - acc = r.0; - overflown |= r.1; - } - exp /= 2; - r = base.overflowing_mul(base); - base = r.0; - overflown |= r.1; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - r = acc.overflowing_mul(base); - r.1 |= overflown; - r - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -# Examples - -Basic usage: - -``` -", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type - -assert_eq!(x.pow(5), 32);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; - } - exp /= 2; - base = base * base; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc * base - } - } - - doc_comment! { - concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. - -This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`, -with `0 <= self.rem_euclid(rhs) < rhs`. - -In other words, the result is `self / rhs` rounded to the integer `n` -such that `self >= n * rhs`. -If `self > 0`, this is equal to round towards zero (the default in Rust); -if `self < 0`, this is equal to round towards +/- infinity. - -# Panics - -This function will panic if `rhs` is 0 or the division results in overflow. - -# Examples - -Basic usage: - -``` -let a: ", stringify!($SelfT), " = 7; // or any other integer type -let b = 4; - -assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1 -assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1 -assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 -assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn div_euclid(self, rhs: Self) -> Self { - let q = self / rhs; - if self % rhs < 0 { - return if rhs > 0 { q - 1 } else { q + 1 } - } - q - } - } - - - doc_comment! { - concat!("Calculates the least nonnegative remainder of `self (mod rhs)`. - -This is done as if by the Euclidean division algorithm -- given -`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and -`0 <= r < abs(rhs)`. - -# Panics - -This function will panic if `rhs` is 0 or the division results in overflow. - -# Examples - -Basic usage: - -``` -let a: ", stringify!($SelfT), " = 7; // or any other integer type -let b = 4; - -assert_eq!(a.rem_euclid(b), 3); -assert_eq!((-a).rem_euclid(b), 1); -assert_eq!(a.rem_euclid(-b), 3); -assert_eq!((-a).rem_euclid(-b), 1); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn rem_euclid(self, rhs: Self) -> Self { - let r = self % rhs; - if r < 0 { - if rhs < 0 { - r - rhs - } else { - r + rhs - } - } else { - r - } - } - } - - doc_comment! { - concat!("Computes the absolute value of `self`. - -# Overflow behavior - -The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an -`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that -code in debug mode will trigger a panic on this case and optimized code will return `", -stringify!($SelfT), "::MIN` without a panic. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10); -assert_eq!((-10", stringify!($SelfT), ").abs(), 10);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[allow(unused_attributes)] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn abs(self) -> Self { - // Note that the #[inline] above means that the overflow - // semantics of the subtraction depend on the crate we're being - // inlined into. - if self.is_negative() { - -self - } else { - self - } - } - } - - doc_comment! { - concat!("Returns a number representing sign of `self`. - - - `0` if the number is zero - - `1` if the number is positive - - `-1` if the number is negative - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1); -assert_eq!(0", stringify!($SelfT), ".signum(), 0); -assert_eq!((-10", stringify!($SelfT), ").signum(), -1);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")] - #[inline] - pub const fn signum(self) -> Self { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, - } - } - } - - doc_comment! { - concat!("Returns `true` if `self` is positive and `false` if the number is zero or -negative. - -# Examples - -Basic usage: - -``` -", $Feature, "assert!(10", stringify!($SelfT), ".is_positive()); -assert!(!(-10", stringify!($SelfT), ").is_positive());", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn is_positive(self) -> bool { self > 0 } - } - - doc_comment! { - concat!("Returns `true` if `self` is negative and `false` if the number is zero or -positive. - -# Examples - -Basic usage: - -``` -", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative()); -assert!(!10", stringify!($SelfT), ".is_negative());", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn is_negative(self) -> bool { self < 0 } - } - - doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -big-endian (network) byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); -assert_eq!(bytes, ", $be_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { - self.to_be().to_ne_bytes() - } - } - -doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -little-endian byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); -assert_eq!(bytes, ", $le_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { - self.to_le().to_ne_bytes() - } - } - - doc_comment! { - concat!(" -Return the memory representation of this integer as a byte array in -native byte order. - -As the target platform's native endianness is used, portable code -should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, -instead. -", -$to_xe_bytes_doc, -" -[`to_be_bytes`]: #method.to_be_bytes -[`to_le_bytes`]: #method.to_le_bytes - -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); -assert_eq!( - bytes, - if cfg!(target_endian = \"big\") { - ", $be_bytes, " - } else { - ", $le_bytes, " - } -); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - // SAFETY: const sound because integers are plain old datatypes so we can always - // transmute them to arrays of bytes - #[allow_internal_unstable(const_fn_transmute)] - #[inline] - pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { - // SAFETY: integers are plain old datatypes so we can always transmute them to - // arrays of bytes - unsafe { mem::transmute(self) } - } - } - -doc_comment! { - concat!("Create an integer value from its representation as a byte array in -big endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_be(Self::from_ne_bytes(bytes)) - } - } - -doc_comment! { - concat!(" -Create an integer value from its representation as a byte array in -little endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_le(Self::from_ne_bytes(bytes)) - } - } - - doc_comment! { - concat!("Create an integer value from its memory representation as a byte -array in native endianness. - -As the target platform's native endianness is used, portable code -likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as -appropriate instead. - -[`from_be_bytes`]: #method.from_be_bytes -[`from_le_bytes`]: #method.from_le_bytes -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { - ", $be_bytes, " -} else { - ", $le_bytes, " -}); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - // SAFETY: const sound because integers are plain old datatypes so we can always - // transmute to them - #[allow_internal_unstable(const_fn_transmute)] - #[inline] - pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { - // SAFETY: integers are plain old datatypes so we can always transmute to them - unsafe { mem::transmute(bytes) } - } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. - -Returns the smallest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[inline(always)] - #[rustc_promotable] - #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")] - pub const fn min_value() -> Self { - Self::MIN - } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. - -Returns the largest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[inline(always)] - #[rustc_promotable] - #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - pub const fn max_value() -> Self { - Self::MAX - } - } - } -} - -#[lang = "i8"] -impl i8 { - int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", - "[0x12]", "[0x12]", "", "" } -} - -#[lang = "i16"] -impl i16 { - int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", - "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } -} - -#[lang = "i32"] -impl i32 { - int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", - "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78]", "", "" } -} - -#[lang = "i64"] -impl i64 { - int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12, - "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", - "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } -} - -#[lang = "i128"] -impl i128 { - int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "", "", 16, - "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", - "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48", - "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ - 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ - 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" } -} - -#[cfg(target_pointer_width = "16")] -#[lang = "isize"] -impl isize { - int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", - "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } -} - -#[cfg(target_pointer_width = "32")] -#[lang = "isize"] -impl isize { - int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", - "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } -} - -#[cfg(target_pointer_width = "64")] -#[lang = "isize"] -impl isize { - int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", - 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", - "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } -} - -macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr, - $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, - $reversed:expr, $le_bytes:expr, $be_bytes:expr, - $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { - doc_comment! { - concat!("The smallest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN: Self = 0; - } - - doc_comment! { - concat!("The largest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");", -$EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX: Self = !0; - } - - doc_comment! { - concat!("Converts a string slice in a given base to an integer. - -The string is expected to be an optional `+` sign -followed by digits. -Leading and trailing whitespace represent an error. -Digits are a subset of these characters, depending on `radix`: - -* `0-9` -* `a-z` -* `A-Z` - -# Panics - -This function panics if `radix` is not in the range from 2 to 36. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) - } - } - - doc_comment! { - concat!("Returns the number of ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b01001100", stringify!($SelfT), "; - -assert_eq!(n.count_ones(), 3);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn count_ones(self) -> u32 { - intrinsics::ctpop(self as $ActualT) as u32 - } - } - - doc_comment! { - concat!("Returns the number of zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - - doc_comment! { - concat!("Returns the number of leading zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2; - -assert_eq!(n.leading_zeros(), 2);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn leading_zeros(self) -> u32 { - intrinsics::ctlz(self as $ActualT) as u32 - } - } - - doc_comment! { - concat!("Returns the number of trailing zeros in the binary representation -of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b0101000", stringify!($SelfT), "; - -assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn trailing_zeros(self) -> u32 { - intrinsics::cttz(self) as u32 - } - } - - doc_comment! { - concat!("Returns the number of leading ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2); - -assert_eq!(n.leading_ones(), 2);", $EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn leading_ones(self) -> u32 { - (!self).leading_zeros() - } - } - - doc_comment! { - concat!("Returns the number of trailing ones in the binary representation -of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b1010111", stringify!($SelfT), "; - -assert_eq!(n.trailing_ones(), 3);", $EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn trailing_ones(self) -> u32 { - (!self).trailing_zeros() - } - } - - doc_comment! { - concat!("Shifts the bits to the left by a specified amount, `n`, -wrapping the truncated bits to the end of the resulting integer. - -Please note this isn't the same operation as the `<<` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_op, stringify!($SelfT), "; -let m = ", $rot_result, "; - -assert_eq!(n.rotate_left(", $rot, "), m); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn rotate_left(self, n: u32) -> Self { - intrinsics::rotate_left(self, n as $SelfT) - } - } - - doc_comment! { - concat!("Shifts the bits to the right by a specified amount, `n`, -wrapping the truncated bits to the beginning of the resulting -integer. - -Please note this isn't the same operation as the `>>` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_result, stringify!($SelfT), "; -let m = ", $rot_op, "; - -assert_eq!(n.rotate_right(", $rot, "), m); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn rotate_right(self, n: u32) -> Self { - intrinsics::rotate_right(self, n as $SelfT) - } - } - - doc_comment! { - concat!(" -Reverses the byte order of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; -let m = n.swap_bytes(); - -assert_eq!(m, ", $swapped, "); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn swap_bytes(self) -> Self { - intrinsics::bswap(self as $ActualT) as Self - } - } - - doc_comment! { - concat!("Reverses the bit pattern of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; -let m = n.reverse_bits(); - -assert_eq!(m, ", $reversed, "); -```"), - #[stable(feature = "reverse_bits", since = "1.37.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - #[must_use] - pub const fn reverse_bits(self) -> Self { - intrinsics::bitreverse(self as $ActualT) as Self - } - } - - doc_comment! { - concat!("Converts an integer from big endian to the target's endianness. - -On big endian this is a no-op. On little endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(", stringify!($SelfT), "::from_be(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn from_be(x: Self) -> Self { - #[cfg(target_endian = "big")] - { - x - } - #[cfg(not(target_endian = "big"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts an integer from little endian to the target's endianness. - -On little endian this is a no-op. On big endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(", stringify!($SelfT), "::from_le(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn from_le(x: Self) -> Self { - #[cfg(target_endian = "little")] - { - x - } - #[cfg(not(target_endian = "little"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to big endian from the target's endianness. - -On big endian this is a no-op. On little endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(n.to_be(), n) -} else { - assert_eq!(n.to_be(), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn to_be(self) -> Self { // or not to be? - #[cfg(target_endian = "big")] - { - self - } - #[cfg(not(target_endian = "big"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to little endian from the target's endianness. - -On little endian this is a no-op. On big endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(n.to_le(), n) -} else { - assert_eq!(n.to_le(), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn to_le(self) -> Self { - #[cfg(target_endian = "little")] - { - self - } - #[cfg(not(target_endian = "little"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Checked integer addition. Computes `self + rhs`, returning `None` -if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ", -"Some(", stringify!($SelfT), "::MAX - 1)); -assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_add(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), -"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_add(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_add`. - unsafe { intrinsics::unchecked_add(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer subtraction. Computes `self - rhs`, returning -`None` if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0)); -assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_sub(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), -"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_sub`. - unsafe { intrinsics::unchecked_sub(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer multiplication. Computes `self * rhs`, returning -`None` if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_mul(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), -"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_mul`. - unsafe { intrinsics::unchecked_mul(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer division. Computes `self / rhs`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); -assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - // SAFETY: div by zero has been checked above and unsigned types have no other - // failure modes for division - Some(unsafe { intrinsics::unchecked_div(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); -assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - Some(self.div_euclid(rhs)) - } - } - } - - - doc_comment! { - concat!("Checked integer remainder. Computes `self % rhs`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - // SAFETY: div by zero has been checked above and unsigned types have no other - // failure modes for division - Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - Some(self.rem_euclid(rhs)) - } - } - } - - doc_comment! { - concat!("Checked negation. Computes `-self`, returning `None` unless `self == -0`. - -Note that negating any positive integer will overflow. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0)); -assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[inline] - pub const fn checked_neg(self) -> Option { - let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift left. Computes `self << rhs`, returning `None` -if `rhs` is larger than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_shl(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift right. Computes `self >> rhs`, returning `None` -if `rhs` is larger than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_shr(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_pow(self, mut exp: u32) -> Option { - if exp == 0 { - return Some(1); - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = try_opt!(acc.checked_mul(base)); - } - exp /= 2; - base = try_opt!(base.checked_mul(base)); - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - - Some(try_opt!(acc.checked_mul(base))) - } - } - - doc_comment! { - concat!("Saturating integer addition. Computes `self + rhs`, saturating at -the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);", -$EndFeature, " -```"), - - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_add(self, rhs: Self) -> Self { - intrinsics::saturating_add(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer subtraction. Computes `self - rhs`, saturating -at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); -assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_sub(self, rhs: Self) -> Self { - intrinsics::saturating_sub(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer multiplication. Computes `self * rhs`, -saturating at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20); -assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT), -"::MAX);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_mul(self, rhs: Self) -> Self { - match self.checked_mul(rhs) { - Some(x) => x, - None => Self::MAX, - } - } - } - - doc_comment! { - concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, -saturating at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_pow(self, exp: u32) -> Self { - match self.checked_pow(exp) { - Some(x) => x, - None => Self::MAX, - } - } - } - - doc_comment! { - concat!("Wrapping (modular) addition. Computes `self + rhs`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255); -assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::wrapping_add(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) subtraction. Computes `self - rhs`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0); -assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::wrapping_sub(self, rhs) - } - } - - /// Wrapping (modular) multiplication. Computes `self * - /// rhs`, wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u8` is used here. - /// - /// ``` - /// assert_eq!(10u8.wrapping_mul(12), 120); - /// assert_eq!(25u8.wrapping_mul(12), 44); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::wrapping_mul(self, rhs) - } - - doc_comment! { - concat!("Wrapping (modular) division. Computes `self / rhs`. -Wrapped division on unsigned types is just normal division. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div(self, rhs: Self) -> Self { - self / rhs - } - } - - doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`. -Wrapped division on unsigned types is just normal division. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self.wrapping_div(rhs)`. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { - self / rhs - } - } - - doc_comment! { - concat!("Wrapping (modular) remainder. Computes `self % rhs`. -Wrapped remainder calculation on unsigned types is -just the regular remainder calculation. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem(self, rhs: Self) -> Self { - self % rhs - } - } - - doc_comment! { - concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`. -Wrapped modulo calculation on unsigned types is -just the regular remainder calculation. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self.wrapping_rem(rhs)`. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { - self % rhs - } - } - - /// Wrapping (modular) negation. Computes `-self`, - /// wrapping around at the boundary of the type. - /// - /// Since unsigned types do not have negative equivalents - /// all applications of this function will wrap (except for `-0`). - /// For values smaller than the corresponding signed type's maximum - /// the result is the same as casting the corresponding signed value. - /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where - /// `MAX` is the corresponding signed type's maximum. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `i8` is used here. - /// - /// ``` - /// assert_eq!(100i8.wrapping_neg(), -100); - /// assert_eq!((-128i8).wrapping_neg(), -128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[inline] - pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 - } - - doc_comment! { - concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, -where `mask` removes any high-order bits of `rhs` that -would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-left; the -RHS of a wrapping shift-left is restricted to the range -of the type, rather than the bits shifted out of the LHS -being returned to the other end. The primitive integer -types all implement a [`rotate_left`](#method.rotate_left) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128); -assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_shl(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, -where `mask` removes any high-order bits of `rhs` that -would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-right; the -RHS of a wrapping shift-right is restricted to the range -of the type, rather than the bits shifted out of the LHS -being returned to the other end. The primitive integer -types all implement a [`rotate_right`](#method.rotate_right) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1); -assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_shr(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243); -assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - } - exp /= 2; - base = base.wrapping_mul(base); - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.wrapping_mul(base) - } - } - - doc_comment! { - concat!("Calculates `self` + `rhs` - -Returns a tuple of the addition along with a boolean indicating -whether an arithmetic overflow would occur. If an overflow would -have occurred then the wrapped value is returned. - -# Examples - -Basic usage - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); -assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates `self` - `rhs` - -Returns a tuple of the subtraction along with a boolean indicating -whether an arithmetic overflow would occur. If an overflow would -have occurred then the wrapped value is returned. - -# Examples - -Basic usage - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); -assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - /// Calculates the multiplication of `self` and `rhs`. - /// - /// Returns a tuple of the multiplication along with a boolean - /// indicating whether an arithmetic overflow would occur. If an - /// overflow would have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. - /// - /// ``` - /// assert_eq!(5u32.overflowing_mul(2), (10, false)); - /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true)); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - - doc_comment! { - concat!("Calculates the divisor when `self` is divided by `rhs`. - -Returns a tuple of the divisor along with a boolean indicating -whether an arithmetic overflow would occur. Note that for unsigned -integers overflow never occurs, so the second value is always -`false`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - (self / rhs, false) - } - } - - doc_comment! { - concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. - -Returns a tuple of the divisor along with a boolean indicating -whether an arithmetic overflow would occur. Note that for unsigned -integers overflow never occurs, so the second value is always -`false`. -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self.overflowing_div(rhs)`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); -```"), - #[inline] - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - (self / rhs, false) - } - } - - doc_comment! { - concat!("Calculates the remainder when `self` is divided by `rhs`. - -Returns a tuple of the remainder after dividing along with a boolean -indicating whether an arithmetic overflow would occur. Note that for -unsigned integers overflow never occurs, so the second value is -always `false`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - (self % rhs, false) - } - } - - doc_comment! { - concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division. - -Returns a tuple of the modulo after dividing along with a boolean -indicating whether an arithmetic overflow would occur. Note that for -unsigned integers overflow never occurs, so the second value is -always `false`. -Since, for the positive integers, all common -definitions of division are equal, this operation -is exactly equal to `self.overflowing_rem(rhs)`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); -```"), - #[inline] - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - (self % rhs, false) - } - } - - doc_comment! { - concat!("Negates self in an overflowing fashion. - -Returns `!self + 1` using wrapping operations to return the value -that represents the negation of this unsigned value. Note that for -positive unsigned values overflow always occurs, but negating 0 does -not overflow. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false)); -assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), -", true));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - pub const fn overflowing_neg(self) -> (Self, bool) { - ((!self).wrapping_add(1), self != 0) - } - } - - doc_comment! { - concat!("Shifts self left by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean -indicating whether the shift value was larger than or equal to the -number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then -used to perform the shift. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false)); -assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Shifts self right by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean -indicating whether the shift value was larger than or equal to the -number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then -used to perform the shift. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); -assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -Returns a tuple of the exponentiation along with a bool indicating -whether an overflow happened. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false)); -assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { - if exp == 0{ - return (1,false); - } - let mut base = self; - let mut acc: Self = 1; - let mut overflown = false; - // Scratch space for storing results of overflowing_mul. - let mut r; - - while exp > 1 { - if (exp & 1) == 1 { - r = acc.overflowing_mul(base); - acc = r.0; - overflown |= r.1; - } - exp /= 2; - r = base.overflowing_mul(base); - base = r.0; - overflown |= r.1; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - r = acc.overflowing_mul(base); - r.1 |= overflown; - - r - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; - } - exp /= 2; - base = base * base; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc * base - } - } - - doc_comment! { - concat!("Performs Euclidean division. - -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self / rhs`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn div_euclid(self, rhs: Self) -> Self { - self / rhs - } - } - - - doc_comment! { - concat!("Calculates the least remainder of `self (mod rhs)`. - -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self % rhs`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn rem_euclid(self, rhs: Self) -> Self { - self % rhs - } - } - - doc_comment! { - concat!("Returns `true` if and only if `self == 2^k` for some `k`. - -# Examples - -Basic usage: +//! Numeric traits and functions for the built-in numeric types. -``` -", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two()); -assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")] - #[inline] - pub const fn is_power_of_two(self) -> bool { - self.count_ones() == 1 - } - } +#![stable(feature = "rust1", since = "1.0.0")] - // Returns one less than next power of two. - // (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8) - // - // 8u8.one_less_than_next_power_of_two() == 7 - // 6u8.one_less_than_next_power_of_two() == 7 - // - // This method cannot overflow, as in the `next_power_of_two` - // overflow cases it instead ends up returning the maximum value - // of the type, and can return 0 for 0. - #[inline] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - const fn one_less_than_next_power_of_two(self) -> Self { - if self <= 1 { return 0; } +use crate::intrinsics; +use crate::mem; +use crate::str::FromStr; - let p = self - 1; - // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros. - // That means the shift is always in-bounds, and some processors - // (such as intel pre-haswell) have more efficient ctlz - // intrinsics when the argument is non-zero. - let z = unsafe { intrinsics::ctlz_nonzero(p) }; - <$SelfT>::MAX >> z +// Used because the `?` operator is not allowed in a const context. +macro_rules! try_opt { + ($e:expr) => { + match $e { + Some(x) => x, + None => return None, } + }; +} - doc_comment! { - concat!("Returns the smallest power of two greater than or equal to `self`. - -When return value overflows (i.e., `self > (1 << (N-1))` for type -`uN`), it panics in debug mode and return value is wrapped to 0 in -release mode (the only situation in which method can return 0). - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2); -assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn next_power_of_two(self) -> Self { - self.one_less_than_next_power_of_two() + 1 - } - } +#[allow_internal_unstable(const_likely)] +macro_rules! unlikely { + ($e: expr) => { + intrinsics::unlikely($e) + }; +} - doc_comment! { - concat!("Returns the smallest power of two greater than or equal to `n`. If -the next power of two is greater than the type's maximum value, -`None` is returned, otherwise the power of two is wrapped in `Some`. +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} -# Examples +// All these modules are technically private and only exposed for coretests: +pub mod bignum; +pub mod dec2flt; +pub mod diy_float; +pub mod flt2dec; -Basic usage: +#[macro_use] +mod int_macros; // import int_impl! +#[macro_use] +mod uint_macros; // import uint_impl! -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), -".checked_next_power_of_two(), Some(2)); -assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);", -$EndFeature, " -```"), - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - pub const fn checked_next_power_of_two(self) -> Option { - self.one_less_than_next_power_of_two().checked_add(1) - } - } +mod error; +mod nonzero; +mod wrapping; - doc_comment! { - concat!("Returns the smallest power of two greater than or equal to `n`. If -the next power of two is greater than the type's maximum value, -the return value is wrapped to `0`. +#[stable(feature = "rust1", since = "1.0.0")] +pub use wrapping::Wrapping; -# Examples +#[stable(feature = "rust1", since = "1.0.0")] +pub use dec2flt::ParseFloatError; -Basic usage: +#[stable(feature = "rust1", since = "1.0.0")] +pub use error::ParseIntError; -``` -#![feature(wrapping_next_power_of_two)] -", $Feature, " -assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2); -assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4); -assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);", -$EndFeature, " -```"), - #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", - reason = "needs decision on wrapping behaviour")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - pub const fn wrapping_next_power_of_two(self) -> Self { - self.one_less_than_next_power_of_two().wrapping_add(1) - } - } +#[stable(feature = "nonzero", since = "1.28.0")] +pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; - doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -big-endian (network) byte order. -", -$to_xe_bytes_doc, -" -# Examples +#[stable(feature = "signed_nonzero", since = "1.34.0")] +pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); -assert_eq!(bytes, ", $be_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { - self.to_be().to_ne_bytes() - } - } +#[stable(feature = "try_from", since = "1.34.0")] +pub use error::TryFromIntError; - doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -little-endian byte order. -", -$to_xe_bytes_doc, -" -# Examples +#[unstable(feature = "int_error_matching", issue = "22639")] +pub use error::IntErrorKind; -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); -assert_eq!(bytes, ", $le_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { - self.to_le().to_ne_bytes() - } - } +macro_rules! usize_isize_to_xe_bytes_doc { + () => { + " - doc_comment! { - concat!(" -Return the memory representation of this integer as a byte array in -native byte order. +**Note**: This function returns an array of length 2, 4 or 8 bytes +depending on the target pointer size. -As the target platform's native endianness is used, portable code -should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, -instead. -", -$to_xe_bytes_doc, " -[`to_be_bytes`]: #method.to_be_bytes -[`to_le_bytes`]: #method.to_le_bytes + }; +} -# Examples +macro_rules! usize_isize_from_xe_bytes_doc { + () => { + " -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); -assert_eq!( - bytes, - if cfg!(target_endian = \"big\") { - ", $be_bytes, " - } else { - ", $le_bytes, " - } -); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - // SAFETY: const sound because integers are plain old datatypes so we can always - // transmute them to arrays of bytes - #[allow_internal_unstable(const_fn_transmute)] - #[inline] - pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { - // SAFETY: integers are plain old datatypes so we can always transmute them to - // arrays of bytes - unsafe { mem::transmute(self) } - } - } +**Note**: This function takes an array of length 2, 4 or 8 bytes +depending on the target pointer size. - doc_comment! { - concat!("Create a native endian integer value from its representation -as a byte array in big endian. -", -$from_xe_bytes_doc, " -# Examples - -``` -let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) + }; } -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_be(Self::from_ne_bytes(bytes)) - } - } - - doc_comment! { - concat!(" -Create a native endian integer value from its representation -as a byte array in little endian. -", -$from_xe_bytes_doc, -" -# Examples -``` -let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) +#[lang = "i8"] +impl i8 { + int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", + "[0x12]", "[0x12]", "", "" } } -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_le(Self::from_ne_bytes(bytes)) - } - } - - doc_comment! { - concat!("Create a native endian integer value from its memory representation -as a byte array in native endianness. - -As the target platform's native endianness is used, portable code -likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as -appropriate instead. - -[`from_be_bytes`]: #method.from_be_bytes -[`from_le_bytes`]: #method.from_le_bytes -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { - ", $be_bytes, " -} else { - ", $le_bytes, " -}); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; -fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) +#[lang = "i16"] +impl i16 { + int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", + "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - // SAFETY: const sound because integers are plain old datatypes so we can always - // transmute to them - #[allow_internal_unstable(const_fn_transmute)] - #[inline] - pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { - // SAFETY: integers are plain old datatypes so we can always transmute to them - unsafe { mem::transmute(bytes) } - } - } - doc_comment! { - concat!("**This method is soft-deprecated.** +#[lang = "i32"] +impl i32 { + int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", + "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78]", "", "" } +} -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. +#[lang = "i64"] +impl i64 { + int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12, + "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", + "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } +} -Returns the smallest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_promotable] - #[inline(always)] - #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - pub const fn min_value() -> Self { Self::MIN } - } +#[lang = "i128"] +impl i128 { + int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, + 170141183460469231731687303715884105727, "", "", 16, + "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", + "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48", + "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ + 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ + 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" } +} - doc_comment! { - concat!("**This method is soft-deprecated.** +#[cfg(target_pointer_width = "16")] +#[lang = "isize"] +impl isize { + int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", + "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } +} -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. +#[cfg(target_pointer_width = "32")] +#[lang = "isize"] +impl isize { + int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", + "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } +} -Returns the largest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_promotable] - #[inline(always)] - #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - pub const fn max_value() -> Self { Self::MAX } - } - } +#[cfg(target_pointer_width = "64")] +#[lang = "isize"] +impl isize { + int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", + 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", + "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[lang = "u8"] @@ -5115,6 +760,16 @@ pub enum FpCategory { Normal, } +#[doc(hidden)] +trait FromStrRadixHelper: PartialOrd + Copy { + fn min_value() -> Self; + fn max_value() -> Self; + fn from_u32(u: u32) -> Self; + fn checked_mul(&self, other: u32) -> Option; + fn checked_sub(&self, other: u32) -> Option; + fn checked_add(&self, other: u32) -> Option; +} + macro_rules! from_str_radix_int_impl { ($($t:ty)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] @@ -5128,58 +783,6 @@ macro_rules! from_str_radix_int_impl { } from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } -/// The error type returned when a checked integral type conversion fails. -#[stable(feature = "try_from", since = "1.34.0")] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct TryFromIntError(pub(crate) ()); - -impl TryFromIntError { - #[unstable( - feature = "int_error_internals", - reason = "available through Error trait and this method should \ - not be exposed publicly", - issue = "none" - )] - #[doc(hidden)] - pub fn __description(&self) -> &str { - "out of range integral type conversion attempted" - } -} - -#[stable(feature = "try_from", since = "1.34.0")] -impl fmt::Display for TryFromIntError { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - self.__description().fmt(fmt) - } -} - -#[stable(feature = "try_from", since = "1.34.0")] -impl From for TryFromIntError { - fn from(x: Infallible) -> TryFromIntError { - match x {} - } -} - -#[unstable(feature = "never_type", issue = "35121")] -impl From for TryFromIntError { - fn from(never: !) -> TryFromIntError { - // Match rather than coerce to make sure that code like - // `From for TryFromIntError` above will keep working - // when `Infallible` becomes an alias to `!`. - match never {} - } -} - -#[doc(hidden)] -trait FromStrRadixHelper: PartialOrd + Copy { - fn min_value() -> Self; - fn max_value() -> Self; - fn from_u32(u: u32) -> Self; - fn checked_mul(&self, other: u32) -> Option; - fn checked_sub(&self, other: u32) -> Option; - fn checked_add(&self, other: u32) -> Option; -} - macro_rules! doit { ($($t:ty)*) => ($(impl FromStrRadixHelper for $t { #[inline] @@ -5272,91 +875,3 @@ fn from_str_radix(src: &str, radix: u32) -> Result &IntErrorKind { - &self.kind - } - #[unstable( - feature = "int_error_internals", - reason = "available through Error trait and this method should \ - not be exposed publicly", - issue = "none" - )] - #[doc(hidden)] - pub fn __description(&self) -> &str { - match self.kind { - IntErrorKind::Empty => "cannot parse integer from empty string", - IntErrorKind::InvalidDigit => "invalid digit found in string", - IntErrorKind::Overflow => "number too large to fit in target type", - IntErrorKind::Underflow => "number too small to fit in target type", - IntErrorKind::Zero => "number would be zero for non-zero type", - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseIntError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.__description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -pub use crate::num::dec2flt::ParseFloatError; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs new file mode 100644 index 0000000000..382f799bfe --- /dev/null +++ b/library/core/src/num/nonzero.rs @@ -0,0 +1,190 @@ +//! Definitions of integer that is known not to equal zero. + +use crate::fmt; +use crate::ops::{BitOr, BitOrAssign}; +use crate::str::FromStr; + +use super::from_str_radix; +use super::{IntErrorKind, ParseIntError}; + +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} + +macro_rules! impl_nonzero_fmt { + ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + $( + #[$stability] + impl fmt::$Trait for $Ty { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } + } + )+ + } +} + +macro_rules! nonzero_integers { + ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => { + $( + doc_comment! { + concat!("An integer that is known not to equal zero. + +This enables some memory layout optimization. +For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`: + +```rust +use std::mem::size_of; +assert_eq!(size_of::>(), size_of::<", stringify!($Int), +">()); +```"), + #[$stability] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + #[repr(transparent)] + #[rustc_layout_scalar_valid_range_start(1)] + #[rustc_nonnull_optimization_guaranteed] + pub struct $Ty($Int); + } + + impl $Ty { + /// Creates a non-zero without checking the value. + /// + /// # Safety + /// + /// The value must not be zero. + #[$stability] + #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] + #[inline] + pub const unsafe fn new_unchecked(n: $Int) -> Self { + // SAFETY: this is guaranteed to be safe by the caller. + unsafe { Self(n) } + } + + /// Creates a non-zero if the given value is not zero. + #[$stability] + #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] + #[inline] + pub const fn new(n: $Int) -> Option { + if n != 0 { + // SAFETY: we just checked that there's no `0` + Some(unsafe { Self(n) }) + } else { + None + } + } + + /// Returns the value as a primitive type. + #[$stability] + #[inline] + #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] + pub const fn get(self) -> $Int { + self.0 + } + + } + + #[stable(feature = "from_nonzero", since = "1.31.0")] + impl From<$Ty> for $Int { + doc_comment! { + concat!( +"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"), + fn from(nonzero: $Ty) -> Self { + nonzero.0 + } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOr for $Ty { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + // SAFETY: since `self` and `rhs` are both nonzero, the + // result of the bitwise-or will be nonzero. + unsafe { $Ty::new_unchecked(self.get() | rhs.get()) } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOr<$Int> for $Ty { + type Output = Self; + #[inline] + fn bitor(self, rhs: $Int) -> Self::Output { + // SAFETY: since `self` is nonzero, the result of the + // bitwise-or will be nonzero regardless of the value of + // `rhs`. + unsafe { $Ty::new_unchecked(self.get() | rhs) } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOr<$Ty> for $Int { + type Output = $Ty; + #[inline] + fn bitor(self, rhs: $Ty) -> Self::Output { + // SAFETY: since `rhs` is nonzero, the result of the + // bitwise-or will be nonzero regardless of the value of + // `self`. + unsafe { $Ty::new_unchecked(self | rhs.get()) } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOrAssign for $Ty { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = *self | rhs; + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOrAssign<$Int> for $Ty { + #[inline] + fn bitor_assign(&mut self, rhs: $Int) { + *self = *self | rhs; + } + } + + impl_nonzero_fmt! { + #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + } + )+ + } +} + +nonzero_integers! { + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); +} + +macro_rules! from_str_radix_nzint_impl { + ($($t:ty)*) => {$( + #[stable(feature = "nonzero_parse", since = "1.35.0")] + impl FromStr for $t { + type Err = ParseIntError; + fn from_str(src: &str) -> Result { + Self::new(from_str_radix(src, 10)?) + .ok_or(ParseIntError { + kind: IntErrorKind::Zero + }) + } + } + )*} +} + +from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize +NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } diff --git a/library/core/src/num/i128.rs b/library/core/src/num/shells/i128.rs similarity index 100% rename from library/core/src/num/i128.rs rename to library/core/src/num/shells/i128.rs diff --git a/library/core/src/num/i16.rs b/library/core/src/num/shells/i16.rs similarity index 100% rename from library/core/src/num/i16.rs rename to library/core/src/num/shells/i16.rs diff --git a/library/core/src/num/i32.rs b/library/core/src/num/shells/i32.rs similarity index 100% rename from library/core/src/num/i32.rs rename to library/core/src/num/shells/i32.rs diff --git a/library/core/src/num/i64.rs b/library/core/src/num/shells/i64.rs similarity index 100% rename from library/core/src/num/i64.rs rename to library/core/src/num/shells/i64.rs diff --git a/library/core/src/num/i8.rs b/library/core/src/num/shells/i8.rs similarity index 100% rename from library/core/src/num/i8.rs rename to library/core/src/num/shells/i8.rs diff --git a/library/core/src/num/shells/int_macros.rs b/library/core/src/num/shells/int_macros.rs new file mode 100644 index 0000000000..ffd30b03f2 --- /dev/null +++ b/library/core/src/num/shells/int_macros.rs @@ -0,0 +1,49 @@ +#![doc(hidden)] + +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} + +macro_rules! int_module { + ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]);); + ($T:ident, #[$attr:meta]) => ( + doc_comment! { + concat!("The smallest value that can be represented by this integer type. +Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead. + +# Examples + +```rust +// deprecated way +let min = std::", stringify!($T), "::MIN; + +// intended way +let min = ", stringify!($T), "::MIN; +``` +"), + #[$attr] + pub const MIN: $T = $T::MIN; + } + + doc_comment! { + concat!("The largest value that can be represented by this integer type. +Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead. + +# Examples + +```rust +// deprecated way +let max = std::", stringify!($T), "::MAX; + +// intended way +let max = ", stringify!($T), "::MAX; +``` +"), + #[$attr] + pub const MAX: $T = $T::MAX; + } + ) +} diff --git a/library/core/src/num/isize.rs b/library/core/src/num/shells/isize.rs similarity index 100% rename from library/core/src/num/isize.rs rename to library/core/src/num/shells/isize.rs diff --git a/library/core/src/num/u128.rs b/library/core/src/num/shells/u128.rs similarity index 100% rename from library/core/src/num/u128.rs rename to library/core/src/num/shells/u128.rs diff --git a/library/core/src/num/u16.rs b/library/core/src/num/shells/u16.rs similarity index 100% rename from library/core/src/num/u16.rs rename to library/core/src/num/shells/u16.rs diff --git a/library/core/src/num/u32.rs b/library/core/src/num/shells/u32.rs similarity index 100% rename from library/core/src/num/u32.rs rename to library/core/src/num/shells/u32.rs diff --git a/library/core/src/num/u64.rs b/library/core/src/num/shells/u64.rs similarity index 100% rename from library/core/src/num/u64.rs rename to library/core/src/num/shells/u64.rs diff --git a/library/core/src/num/u8.rs b/library/core/src/num/shells/u8.rs similarity index 100% rename from library/core/src/num/u8.rs rename to library/core/src/num/shells/u8.rs diff --git a/library/core/src/num/usize.rs b/library/core/src/num/shells/usize.rs similarity index 100% rename from library/core/src/num/usize.rs rename to library/core/src/num/shells/usize.rs diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs new file mode 100644 index 0000000000..234c309961 --- /dev/null +++ b/library/core/src/num/uint_macros.rs @@ -0,0 +1,1955 @@ +macro_rules! uint_impl { + ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr, + $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, + $reversed:expr, $le_bytes:expr, $be_bytes:expr, + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { + doc_comment! { + concat!("The smallest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MIN: Self = 0; + } + + doc_comment! { + concat!("The largest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");", +$EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MAX: Self = !0; + } + + doc_comment! { + concat!("The size of this integer type in bits. + +# Examples + +``` +", $Feature, "#![feature(int_bits_const)] +assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[unstable(feature = "int_bits_const", issue = "76904")] + pub const BITS: u32 = $BITS; + } + + doc_comment! { + concat!("Converts a string slice in a given base to an integer. + +The string is expected to be an optional `+` sign +followed by digits. +Leading and trailing whitespace represent an error. +Digits are a subset of these characters, depending on `radix`: + +* `0-9` +* `a-z` +* `A-Z` + +# Panics + +This function panics if `radix` is not in the range from 2 to 36. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_str_radix(src: &str, radix: u32) -> Result { + from_str_radix(src, radix) + } + } + + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b01001100", stringify!($SelfT), "; + +assert_eq!(n.count_ones(), 3);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn count_ones(self) -> u32 { + intrinsics::ctpop(self as $ActualT) as u32 + } + } + + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2; + +assert_eq!(n.leading_zeros(), 2);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + intrinsics::ctlz(self as $ActualT) as u32 + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation +of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b0101000", stringify!($SelfT), "; + +assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + intrinsics::cttz(self) as u32 + } + } + + doc_comment! { + concat!("Returns the number of leading ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2); + +assert_eq!(n.leading_ones(), 2);", $EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn leading_ones(self) -> u32 { + (!self).leading_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing ones in the binary representation +of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b1010111", stringify!($SelfT), "; + +assert_eq!(n.trailing_ones(), 3);", $EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn trailing_ones(self) -> u32 { + (!self).trailing_zeros() + } + } + + doc_comment! { + concat!("Shifts the bits to the left by a specified amount, `n`, +wrapping the truncated bits to the end of the resulting integer. + +Please note this isn't the same operation as the `<<` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_op, stringify!($SelfT), "; +let m = ", $rot_result, "; + +assert_eq!(n.rotate_left(", $rot, "), m); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn rotate_left(self, n: u32) -> Self { + intrinsics::rotate_left(self, n as $SelfT) + } + } + + doc_comment! { + concat!("Shifts the bits to the right by a specified amount, `n`, +wrapping the truncated bits to the beginning of the resulting +integer. + +Please note this isn't the same operation as the `>>` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_result, stringify!($SelfT), "; +let m = ", $rot_op, "; + +assert_eq!(n.rotate_right(", $rot, "), m); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn rotate_right(self, n: u32) -> Self { + intrinsics::rotate_right(self, n as $SelfT) + } + } + + doc_comment! { + concat!(" +Reverses the byte order of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; +let m = n.swap_bytes(); + +assert_eq!(m, ", $swapped, "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn swap_bytes(self) -> Self { + intrinsics::bswap(self as $ActualT) as Self + } + } + + doc_comment! { + concat!("Reverses the bit pattern of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; +let m = n.reverse_bits(); + +assert_eq!(m, ", $reversed, "); +```"), + #[stable(feature = "reverse_bits", since = "1.37.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + #[must_use] + pub const fn reverse_bits(self) -> Self { + intrinsics::bitreverse(self as $ActualT) as Self + } + } + + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(", stringify!($SelfT), "::from_be(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(", stringify!($SelfT), "::from_le(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Checked integer addition. Computes `self + rhs`, returning `None` +if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ", +"Some(", stringify!($SelfT), "::MAX - 1)); +assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), +"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_add(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_add`. + unsafe { intrinsics::unchecked_add(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer subtraction. Computes `self - rhs`, returning +`None` if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0)); +assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), +"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_sub`. + unsafe { intrinsics::unchecked_sub(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer multiplication. Computes `self * rhs`, returning +`None` if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_mul(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), +"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_mul`. + unsafe { intrinsics::unchecked_mul(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer division. Computes `self / rhs`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + // SAFETY: div by zero has been checked above and unsigned types have no other + // failure modes for division + Some(unsafe { intrinsics::unchecked_div(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + Some(self.div_euclid(rhs)) + } + } + } + + + doc_comment! { + concat!("Checked integer remainder. Computes `self % rhs`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + // SAFETY: div by zero has been checked above and unsigned types have no other + // failure modes for division + Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + Some(self.rem_euclid(rhs)) + } + } + } + + doc_comment! { + concat!("Checked negation. Computes `-self`, returning `None` unless `self == +0`. + +Note that negating any positive integer will overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0)); +assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[inline] + pub const fn checked_neg(self) -> Option { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift left. Computes `self << rhs`, returning `None` +if `rhs` is larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_shl(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift right. Computes `self >> rhs`, returning `None` +if `rhs` is larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_shr(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_pow(self, mut exp: u32) -> Option { + if exp == 0 { + return Some(1); + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = try_opt!(acc.checked_mul(base)); + } + exp /= 2; + base = try_opt!(base.checked_mul(base)); + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + + Some(try_opt!(acc.checked_mul(base))) + } + } + + doc_comment! { + concat!("Saturating integer addition. Computes `self + rhs`, saturating at +the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_add(self, rhs: Self) -> Self { + intrinsics::saturating_add(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating +at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); +assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_sub(self, rhs: Self) -> Self { + intrinsics::saturating_sub(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer multiplication. Computes `self * rhs`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20); +assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT), +"::MAX);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(x) => x, + None => Self::MAX, + } + } + } + + doc_comment! { + concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Some(x) => x, + None => Self::MAX, + } + } + } + + doc_comment! { + concat!("Wrapping (modular) addition. Computes `self + rhs`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255); +assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_add(self, rhs: Self) -> Self { + intrinsics::wrapping_add(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) subtraction. Computes `self - rhs`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0); +assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_sub(self, rhs: Self) -> Self { + intrinsics::wrapping_sub(self, rhs) + } + } + + /// Wrapping (modular) multiplication. Computes `self * + /// rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u8` is used here. + /// + /// ``` + /// assert_eq!(10u8.wrapping_mul(12), 120); + /// assert_eq!(25u8.wrapping_mul(12), 44); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_mul(self, rhs: Self) -> Self { + intrinsics::wrapping_mul(self, rhs) + } + + doc_comment! { + concat!("Wrapping (modular) division. Computes `self / rhs`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div(self, rhs: Self) -> Self { + self / rhs + } + } + + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.wrapping_div(rhs)`. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { + self / rhs + } + } + + doc_comment! { + concat!("Wrapping (modular) remainder. Computes `self % rhs`. +Wrapped remainder calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem(self, rhs: Self) -> Self { + self % rhs + } + } + + doc_comment! { + concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`. +Wrapped modulo calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.wrapping_rem(rhs)`. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { + self % rhs + } + } + + /// Wrapping (modular) negation. Computes `-self`, + /// wrapping around at the boundary of the type. + /// + /// Since unsigned types do not have negative equivalents + /// all applications of this function will wrap (except for `-0`). + /// For values smaller than the corresponding signed type's maximum + /// the result is the same as casting the corresponding signed value. + /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where + /// `MAX` is the corresponding signed type's maximum. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i8` is used here. + /// + /// ``` + /// assert_eq!(100i8.wrapping_neg(), -100); + /// assert_eq!((-128i8).wrapping_neg(), -128); + /// ``` + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[inline] + pub const fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } + + doc_comment! { + concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, +where `mask` removes any high-order bits of `rhs` that +would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-left; the +RHS of a wrapping shift-left is restricted to the range +of the type, rather than the bits shifted out of the LHS +being returned to the other end. The primitive integer +types all implement a [`rotate_left`](#method.rotate_left) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128); +assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_shl(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, +where `mask` removes any high-order bits of `rhs` that +would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-right; the +RHS of a wrapping shift-right is restricted to the range +of the type, rather than the bits shifted out of the LHS +being returned to the other end. The primitive integer +types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1); +assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_shr(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243); +assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + exp /= 2; + base = base.wrapping_mul(base); + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.wrapping_mul(base) + } + } + + doc_comment! { + concat!("Calculates `self` + `rhs` + +Returns a tuple of the addition along with a boolean indicating +whether an arithmetic overflow would occur. If an overflow would +have occurred then the wrapped value is returned. + +# Examples + +Basic usage + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates `self` - `rhs` + +Returns a tuple of the subtraction along with a boolean indicating +whether an arithmetic overflow would occur. If an overflow would +have occurred then the wrapped value is returned. + +# Examples + +Basic usage + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); +assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + /// Calculates the multiplication of `self` and `rhs`. + /// + /// Returns a tuple of the multiplication along with a boolean + /// indicating whether an arithmetic overflow would occur. If an + /// overflow would have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// assert_eq!(5u32.overflowing_mul(2), (10, false)); + /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true)); + /// ``` + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + + doc_comment! { + concat!("Calculates the divisor when `self` is divided by `rhs`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } + } + + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.overflowing_div(rhs)`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); +```"), + #[inline] + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } + } + + doc_comment! { + concat!("Calculates the remainder when `self` is divided by `rhs`. + +Returns a tuple of the remainder after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } + } + + doc_comment! { + concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division. + +Returns a tuple of the modulo after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. +Since, for the positive integers, all common +definitions of division are equal, this operation +is exactly equal to `self.overflowing_rem(rhs)`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); +```"), + #[inline] + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } + } + + doc_comment! { + concat!("Negates self in an overflowing fashion. + +Returns `!self + 1` using wrapping operations to return the value +that represents the negation of this unsigned value. Note that for +positive unsigned values overflow always occurs, but negating 0 does +not overflow. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false)); +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), +", true));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + pub const fn overflowing_neg(self) -> (Self, bool) { + ((!self).wrapping_add(1), self != 0) + } + } + + doc_comment! { + concat!("Shifts self left by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean +indicating whether the shift value was larger than or equal to the +number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then +used to perform the shift. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false)); +assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Shifts self right by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean +indicating whether the shift value was larger than or equal to the +number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then +used to perform the shift. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +Returns a tuple of the exponentiation along with a bool indicating +whether an overflow happened. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false)); +assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { + if exp == 0{ + return (1,false); + } + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + exp /= 2; + r = base.overflowing_mul(base); + base = r.0; + overflown |= r.1; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + r = acc.overflowing_mul(base); + r.1 |= overflown; + + r + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; + } + exp /= 2; + base = base * base; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc * base + } + } + + doc_comment! { + concat!("Performs Euclidean division. + +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self / rhs`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn div_euclid(self, rhs: Self) -> Self { + self / rhs + } + } + + + doc_comment! { + concat!("Calculates the least remainder of `self (mod rhs)`. + +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self % rhs`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn rem_euclid(self, rhs: Self) -> Self { + self % rhs + } + } + + doc_comment! { + concat!("Returns `true` if and only if `self == 2^k` for some `k`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two()); +assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")] + #[inline] + pub const fn is_power_of_two(self) -> bool { + self.count_ones() == 1 + } + } + + // Returns one less than next power of two. + // (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8) + // + // 8u8.one_less_than_next_power_of_two() == 7 + // 6u8.one_less_than_next_power_of_two() == 7 + // + // This method cannot overflow, as in the `next_power_of_two` + // overflow cases it instead ends up returning the maximum value + // of the type, and can return 0 for 0. + #[inline] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + const fn one_less_than_next_power_of_two(self) -> Self { + if self <= 1 { return 0; } + + let p = self - 1; + // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros. + // That means the shift is always in-bounds, and some processors + // (such as intel pre-haswell) have more efficient ctlz + // intrinsics when the argument is non-zero. + let z = unsafe { intrinsics::ctlz_nonzero(p) }; + <$SelfT>::MAX >> z + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `self`. + +When return value overflows (i.e., `self > (1 << (N-1))` for type +`uN`), it panics in debug mode and return value is wrapped to 0 in +release mode (the only situation in which method can return 0). + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two() + 1 + } + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `n`. If +the next power of two is greater than the type's maximum value, +`None` is returned, otherwise the power of two is wrapped in `Some`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), +".checked_next_power_of_two(), Some(2)); +assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);", +$EndFeature, " +```"), + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + pub const fn checked_next_power_of_two(self) -> Option { + self.one_less_than_next_power_of_two().checked_add(1) + } + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `n`. If +the next power of two is greater than the type's maximum value, +the return value is wrapped to `0`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_next_power_of_two)] +", $Feature, " +assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4); +assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);", +$EndFeature, " +```"), + #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", + reason = "needs decision on wrapping behaviour")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + pub const fn wrapping_next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two().wrapping_add(1) + } + } + + doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +big-endian (network) byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); +assert_eq!(bytes, ", $be_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { + self.to_be().to_ne_bytes() + } + } + + doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +little-endian byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); +assert_eq!(bytes, ", $le_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { + self.to_le().to_ne_bytes() + } + } + + doc_comment! { + concat!(" +Return the memory representation of this integer as a byte array in +native byte order. + +As the target platform's native endianness is used, portable code +should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, +instead. +", +$to_xe_bytes_doc, +" +[`to_be_bytes`]: #method.to_be_bytes +[`to_le_bytes`]: #method.to_le_bytes + +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); +assert_eq!( + bytes, + if cfg!(target_endian = \"big\") { + ", $be_bytes, " + } else { + ", $le_bytes, " + } +); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute them to arrays of bytes + #[allow_internal_unstable(const_fn_transmute)] + #[inline] + pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + // SAFETY: integers are plain old datatypes so we can always transmute them to + // arrays of bytes + unsafe { mem::transmute(self) } + } + } + + doc_comment! { + concat!("Create a native endian integer value from its representation +as a byte array in big endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_be(Self::from_ne_bytes(bytes)) + } + } + + doc_comment! { + concat!(" +Create a native endian integer value from its representation +as a byte array in little endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + } + + doc_comment! { + concat!("Create a native endian integer value from its memory representation +as a byte array in native endianness. + +As the target platform's native endianness is used, portable code +likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as +appropriate instead. + +[`from_be_bytes`]: #method.from_be_bytes +[`from_le_bytes`]: #method.from_le_bytes +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { + ", $be_bytes, " +} else { + ", $le_bytes, " +}); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute to them + #[allow_internal_unstable(const_fn_transmute)] + #[inline] + pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + // SAFETY: integers are plain old datatypes so we can always transmute to them + unsafe { mem::transmute(bytes) } + } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause compilation warning, +new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. + +Returns the smallest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_promotable] + #[inline(always)] + #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] + pub const fn min_value() -> Self { Self::MIN } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause compilation warning, +new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. + +Returns the largest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_promotable] + #[inline(always)] + #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] + pub const fn max_value() -> Self { Self::MAX } + } + } +} diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index f6acb8f8b9..5324dfdedd 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -1,6 +1,83 @@ -use super::Wrapping; +//! Definitions of `Wrapping`. + +use crate::fmt; +use crate::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign}; +use crate::ops::{BitXor, BitXorAssign, Div, DivAssign}; +use crate::ops::{Mul, MulAssign, Neg, Not, Rem, RemAssign}; +use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; + +/// Provides intentionally-wrapped arithmetic on `T`. +/// +/// Operations like `+` on `u32` values are intended to never overflow, +/// and in some debug configurations overflow is detected and results +/// in a panic. While most arithmetic falls into this category, some +/// code explicitly expects and relies upon modular arithmetic (e.g., +/// hashing). +/// +/// Wrapping arithmetic can be achieved either through methods like +/// `wrapping_add`, or through the `Wrapping` type, which says that +/// all standard arithmetic operations on the underlying value are +/// intended to have wrapping semantics. +/// +/// The underlying value can be retrieved through the `.0` index of the +/// `Wrapping` tuple. +/// +/// # Examples +/// +/// ``` +/// use std::num::Wrapping; +/// +/// let zero = Wrapping(0u32); +/// let one = Wrapping(1u32); +/// +/// assert_eq!(u32::MAX, (zero - one).0); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] +#[repr(transparent)] +pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_display", since = "1.10.0")] +impl fmt::Display for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::Binary for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} -use crate::ops::*; +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::Octal for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::LowerHex for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::UpperHex for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} #[allow(unused_macros)] macro_rules! sh_impl_signed { diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 622a138abe..19f86ced50 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -78,6 +78,12 @@ pub trait Add { type Output; /// Performs the `+` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 + 1, 13); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn add(self, rhs: Rhs) -> Self::Output; @@ -122,10 +128,10 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// } /// /// impl Sub for Point { -/// type Output = Point; +/// type Output = Self; /// -/// fn sub(self, other: Point) -> Point { -/// Point { +/// fn sub(self, other: Self) -> Self::Output { +/// Self { /// x: self.x - other.x, /// y: self.y - other.y, /// } @@ -178,6 +184,12 @@ pub trait Sub { type Output; /// Performs the `-` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 - 1, 11); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn sub(self, rhs: Rhs) -> Self::Output; @@ -229,7 +241,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. /// let gcd = gcd(numerator, denominator); -/// Rational { +/// Self { /// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } @@ -243,7 +255,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// fn mul(self, rhs: Self) -> Self { /// let numerator = self.numerator * rhs.numerator; /// let denominator = self.denominator * rhs.denominator; -/// Rational::new(numerator, denominator) +/// Self::new(numerator, denominator) /// } /// } /// @@ -279,7 +291,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// type Output = Self; /// /// fn mul(self, rhs: Scalar) -> Self::Output { -/// Vector { value: self.value.iter().map(|v| v * rhs.value).collect() } +/// Self { value: self.value.iter().map(|v| v * rhs.value).collect() } /// } /// } /// @@ -300,6 +312,12 @@ pub trait Mul { type Output; /// Performs the `*` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 * 2, 24); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn mul(self, rhs: Rhs) -> Self::Output; @@ -351,7 +369,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. /// let gcd = gcd(numerator, denominator); -/// Rational { +/// Self { /// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } @@ -369,7 +387,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// /// let numerator = self.numerator * rhs.denominator; /// let denominator = self.denominator * rhs.numerator; -/// Rational::new(numerator, denominator) +/// Self::new(numerator, denominator) /// } /// } /// @@ -405,7 +423,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// type Output = Self; /// /// fn div(self, rhs: Scalar) -> Self::Output { -/// Vector { value: self.value.iter().map(|v| v / rhs.value).collect() } +/// Self { value: self.value.iter().map(|v| v / rhs.value).collect() } /// } /// } /// @@ -426,6 +444,12 @@ pub trait Div { type Output; /// Performs the `/` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 / 2, 6); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn div(self, rhs: Rhs) -> Self::Output; @@ -491,7 +515,7 @@ div_impl_float! { f32 f64 } /// let len = self.slice.len(); /// let rem = len % modulus; /// let start = len - rem; -/// SplitSlice {slice: &self.slice[start..]} +/// Self {slice: &self.slice[start..]} /// } /// } /// @@ -513,6 +537,12 @@ pub trait Rem { type Output; /// Performs the `%` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 % 10, 2); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn rem(self, rhs: Rhs) -> Self::Output; @@ -585,7 +615,7 @@ rem_impl_float! { f32 f64 } /// } /// /// impl Neg for Sign { -/// type Output = Sign; +/// type Output = Self; /// /// fn neg(self) -> Self::Output { /// match self { @@ -612,6 +642,13 @@ pub trait Neg { type Output; /// Performs the unary `-` operation. + /// + /// # Example + /// + /// ``` + /// let x: i32 = 12; + /// assert_eq!(-x, -12); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn neg(self) -> Self::Output; @@ -673,6 +710,14 @@ neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "+=")] pub trait AddAssign { /// Performs the `+=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x += 1; + /// assert_eq!(x, 13); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn add_assign(&mut self, rhs: Rhs); } @@ -731,6 +776,14 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "-=")] pub trait SubAssign { /// Performs the `-=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x -= 1; + /// assert_eq!(x, 11); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn sub_assign(&mut self, rhs: Rhs); } @@ -780,6 +833,14 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "*=")] pub trait MulAssign { /// Performs the `*=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x *= 2; + /// assert_eq!(x, 24); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn mul_assign(&mut self, rhs: Rhs); } @@ -829,6 +890,14 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "/=")] pub trait DivAssign { /// Performs the `/=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x /= 2; + /// assert_eq!(x, 6); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn div_assign(&mut self, rhs: Rhs); } @@ -881,6 +950,14 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "%=")] pub trait RemAssign { /// Performs the `%=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x %= 10; + /// assert_eq!(x, 2); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn rem_assign(&mut self, rhs: Rhs); } diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index bcfff4a223..6120da50c3 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -15,7 +15,7 @@ /// } /// /// impl Not for Answer { -/// type Output = Answer; +/// type Output = Self; /// /// fn not(self) -> Self::Output { /// match self { @@ -36,6 +36,15 @@ pub trait Not { type Output; /// Performs the unary `!` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(!true, false); + /// assert_eq!(!false, true); + /// assert_eq!(!1u8, 254); + /// assert_eq!(!0u8, 255); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn not(self) -> Self::Output; @@ -76,7 +85,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// // rhs is the "right-hand side" of the expression `a & b` /// fn bitand(self, rhs: Self) -> Self::Output { -/// Scalar(self.0 & rhs.0) +/// Self(self.0 & rhs.0) /// } /// } /// @@ -97,10 +106,13 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitAnd for BooleanVector { /// type Output = Self; /// -/// fn bitand(self, BooleanVector(rhs): Self) -> Self::Output { -/// let BooleanVector(lhs) = self; +/// fn bitand(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x && *y).collect()) +/// Self(lhs.iter() +/// .zip(rhs.iter()) +/// .map(|(x, y)| *x && *y) +/// .collect()) /// } /// } /// @@ -122,6 +134,15 @@ pub trait BitAnd { type Output; /// Performs the `&` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true & false, false); + /// assert_eq!(true & true, true); + /// assert_eq!(5u8 & 1u8, 1); + /// assert_eq!(5u8 & 2u8, 0); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitand(self, rhs: Rhs) -> Self::Output; @@ -161,8 +182,8 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// type Output = Self; /// /// // rhs is the "right-hand side" of the expression `a | b` -/// fn bitor(self, rhs: Self) -> Self { -/// Scalar(self.0 | rhs.0) +/// fn bitor(self, rhs: Self) -> Self::Output { +/// Self(self.0 | rhs.0) /// } /// } /// @@ -183,10 +204,10 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitOr for BooleanVector { /// type Output = Self; /// -/// fn bitor(self, BooleanVector(rhs): Self) -> Self::Output { -/// let BooleanVector(lhs) = self; +/// fn bitor(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) +/// Self(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) /// } /// } /// @@ -208,6 +229,15 @@ pub trait BitOr { type Output; /// Performs the `|` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true | false, true); + /// assert_eq!(false | false, false); + /// assert_eq!(5u8 | 1u8, 5); + /// assert_eq!(5u8 | 2u8, 7); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitor(self, rhs: Rhs) -> Self::Output; @@ -248,7 +278,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// // rhs is the "right-hand side" of the expression `a ^ b` /// fn bitxor(self, rhs: Self) -> Self::Output { -/// Scalar(self.0 ^ rhs.0) +/// Self(self.0 ^ rhs.0) /// } /// } /// @@ -269,13 +299,13 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitXor for BooleanVector { /// type Output = Self; /// -/// fn bitxor(self, BooleanVector(rhs): Self) -> Self::Output { -/// let BooleanVector(lhs) = self; +/// fn bitxor(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter() -/// .zip(rhs.iter()) -/// .map(|(x, y)| (*x || *y) && !(*x && *y)) -/// .collect()) +/// Self(lhs.iter() +/// .zip(rhs.iter()) +/// .map(|(x, y)| (*x || *y) && !(*x && *y)) +/// .collect()) /// } /// } /// @@ -297,6 +327,15 @@ pub trait BitXor { type Output; /// Performs the `^` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true ^ false, true); + /// assert_eq!(true ^ true, false); + /// assert_eq!(5u8 ^ 1u8, 4); + /// assert_eq!(5u8 ^ 2u8, 7); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitxor(self, rhs: Rhs) -> Self::Output; @@ -339,9 +378,9 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl Shl for Scalar { /// type Output = Self; /// -/// fn shl(self, Scalar(rhs): Self) -> Scalar { -/// let Scalar(lhs) = self; -/// Scalar(lhs << rhs) +/// fn shl(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; +/// Self(lhs << rhs) /// } /// } /// @@ -364,10 +403,10 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// fn shl(self, rhs: usize) -> Self::Output { /// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(rhs); -/// let mut spun_vector: Vec = vec![]; +/// let mut spun_vector = vec![]; /// spun_vector.extend_from_slice(b); /// spun_vector.extend_from_slice(a); -/// SpinVector { vec: spun_vector } +/// Self { vec: spun_vector } /// } /// } /// @@ -387,6 +426,13 @@ pub trait Shl { type Output; /// Performs the `<<` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(5u8 << 1, 10); + /// assert_eq!(1u8 << 1, 2); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shl(self, rhs: Rhs) -> Self::Output; @@ -450,9 +496,9 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// impl Shr for Scalar { /// type Output = Self; /// -/// fn shr(self, Scalar(rhs): Self) -> Scalar { -/// let Scalar(lhs) = self; -/// Scalar(lhs >> rhs) +/// fn shr(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; +/// Self(lhs >> rhs) /// } /// } /// @@ -475,10 +521,10 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// fn shr(self, rhs: usize) -> Self::Output { /// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(self.vec.len() - rhs); -/// let mut spun_vector: Vec = vec![]; +/// let mut spun_vector = vec![]; /// spun_vector.extend_from_slice(b); /// spun_vector.extend_from_slice(a); -/// SpinVector { vec: spun_vector } +/// Self { vec: spun_vector } /// } /// } /// @@ -498,6 +544,13 @@ pub trait Shr { type Output; /// Performs the `>>` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(5u8 >> 1, 2); + /// assert_eq!(2u8 >> 1, 1); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shr(self, rhs: Rhs) -> Self::Output; @@ -556,7 +609,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// impl BitAndAssign for Scalar { /// // rhs is the "right-hand side" of the expression `a &= b` /// fn bitand_assign(&mut self, rhs: Self) { -/// *self = Scalar(self.0 & rhs.0) +/// *self = Self(self.0 & rhs.0) /// } /// } /// @@ -590,11 +643,11 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// // `rhs` is the "right-hand side" of the expression `a &= b`. /// fn bitand_assign(&mut self, rhs: Self) { /// assert_eq!(self.0.len(), rhs.0.len()); -/// *self = BooleanVector(self.0 -/// .iter() -/// .zip(rhs.0.iter()) -/// .map(|(x, y)| *x && *y) -/// .collect()); +/// *self = Self(self.0 +/// .iter() +/// .zip(rhs.0.iter()) +/// .map(|(x, y)| *x && *y) +/// .collect()); /// } /// } /// @@ -612,6 +665,26 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } )] pub trait BitAndAssign { /// Performs the `&=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x &= false; + /// assert_eq!(x, false); + /// + /// let mut x = true; + /// x &= true; + /// assert_eq!(x, true); + /// + /// let mut x: u8 = 5; + /// x &= 1; + /// assert_eq!(x, 1); + /// + /// let mut x: u8 = 5; + /// x &= 2; + /// assert_eq!(x, 0); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitand_assign(&mut self, rhs: Rhs); } @@ -663,6 +736,26 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait BitOrAssign { /// Performs the `|=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x |= false; + /// assert_eq!(x, true); + /// + /// let mut x = false; + /// x |= false; + /// assert_eq!(x, false); + /// + /// let mut x: u8 = 5; + /// x |= 1; + /// assert_eq!(x, 5); + /// + /// let mut x: u8 = 5; + /// x |= 2; + /// assert_eq!(x, 7); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitor_assign(&mut self, rhs: Rhs); } @@ -714,6 +807,26 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait BitXorAssign { /// Performs the `^=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x ^= false; + /// assert_eq!(x, true); + /// + /// let mut x = true; + /// x ^= true; + /// assert_eq!(x, false); + /// + /// let mut x: u8 = 5; + /// x ^= 1; + /// assert_eq!(x, 4); + /// + /// let mut x: u8 = 5; + /// x ^= 2; + /// assert_eq!(x, 7); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitxor_assign(&mut self, rhs: Rhs); } @@ -763,6 +876,18 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait ShlAssign { /// Performs the `<<=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x: u8 = 5; + /// x <<= 1; + /// assert_eq!(x, 10); + /// + /// let mut x: u8 = 1; + /// x <<= 1; + /// assert_eq!(x, 2); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shl_assign(&mut self, rhs: Rhs); } @@ -833,6 +958,18 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } )] pub trait ShrAssign { /// Performs the `>>=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x: u8 = 5; + /// x >>= 1; + /// assert_eq!(x, 2); + /// + /// let mut x: u8 = 2; + /// x >>= 1; + /// assert_eq!(x, 1); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shr_assign(&mut self, rhs: Rhs); } diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs new file mode 100644 index 0000000000..b0c7dc1a51 --- /dev/null +++ b/library/core/src/ops/control_flow.rs @@ -0,0 +1,110 @@ +use crate::ops::Try; + +/// Used to make try_fold closures more like normal loops +#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ControlFlow { + /// Continue in the loop, using the given value for the next iteration + Continue(C), + /// Exit the loop, yielding the given value + Break(B), +} + +#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +impl Try for ControlFlow { + type Ok = C; + type Error = B; + #[inline] + fn into_result(self) -> Result { + match self { + ControlFlow::Continue(y) => Ok(y), + ControlFlow::Break(x) => Err(x), + } + } + #[inline] + fn from_error(v: Self::Error) -> Self { + ControlFlow::Break(v) + } + #[inline] + fn from_ok(v: Self::Ok) -> Self { + ControlFlow::Continue(v) + } +} + +impl ControlFlow { + /// Converts the `ControlFlow` into an `Option` which is `Some` if the + /// `ControlFlow` was `Break` and `None` otherwise. + #[inline] + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub fn break_value(self) -> Option { + match self { + ControlFlow::Continue(..) => None, + ControlFlow::Break(x) => Some(x), + } + } +} + +impl ControlFlow { + /// Create a `ControlFlow` from any type implementing `Try`. + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[inline] + pub fn from_try(r: R) -> Self { + match Try::into_result(r) { + Ok(v) => ControlFlow::Continue(v), + Err(v) => ControlFlow::Break(Try::from_error(v)), + } + } + + /// Convert a `ControlFlow` into any type implementing `Try`; + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[inline] + pub fn into_try(self) -> R { + match self { + ControlFlow::Continue(v) => Try::from_ok(v), + ControlFlow::Break(v) => v, + } + } +} + +impl ControlFlow<(), B> { + /// It's frequently the case that there's no value needed with `Continue`, + /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// let last_used = (1..10).chain(20..25).try_for_each(|x| { + /// partial_sum += x; + /// if partial_sum > 100 { ControlFlow::Break(x) } + /// else { ControlFlow::CONTINUE } + /// }); + /// assert_eq!(last_used.break_value(), Some(22)); + /// ``` + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub const CONTINUE: Self = ControlFlow::Continue(()); +} + +impl ControlFlow { + /// APIs like `try_for_each` don't need values with `Break`, + /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// (1..10).chain(20..25).try_for_each(|x| { + /// if partial_sum > 100 { ControlFlow::BREAK } + /// else { partial_sum += x; ControlFlow::CONTINUE } + /// }); + /// assert_eq!(partial_sum, 108); + /// ``` + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub const BREAK: Self = ControlFlow::Break(()); +} diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index d6c097eee1..245152e549 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -63,11 +63,13 @@ pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "deref_target"] type Target: ?Sized; /// Dereferences the value. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "deref_method"] fn deref(&self) -> &Self::Target; } diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index c19bd6e441..354ad6b7b7 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -49,18 +49,18 @@ //! } //! //! impl Add for Point { -//! type Output = Point; +//! type Output = Self; //! -//! fn add(self, other: Point) -> Point { -//! Point {x: self.x + other.x, y: self.y + other.y} +//! fn add(self, other: Self) -> Self { +//! Self {x: self.x + other.x, y: self.y + other.y} //! } //! } //! //! impl Sub for Point { -//! type Output = Point; +//! type Output = Self; //! -//! fn sub(self, other: Point) -> Point { -//! Point {x: self.x - other.x, y: self.y - other.y} +//! fn sub(self, other: Self) -> Self { +//! Self {x: self.x - other.x, y: self.y - other.y} //! } //! } //! @@ -140,6 +140,7 @@ mod arith; mod bit; +mod control_flow; mod deref; mod drop; mod function; @@ -191,3 +192,6 @@ pub use self::unsize::CoerceUnsized; #[unstable(feature = "dispatch_from_dyn", issue = "none")] pub use self::unsize::DispatchFromDyn; + +#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +pub use self::control_flow::ControlFlow; diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index d10829832d..2eaf7601e5 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -36,7 +36,7 @@ use crate::hash::Hash; /// ``` /// /// [slicing index]: crate::slice::SliceIndex -#[cfg_attr(not(bootstrap), lang = "RangeFull")] +#[lang = "RangeFull"] #[doc(alias = "..")] #[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] @@ -69,7 +69,7 @@ impl fmt::Debug for RangeFull { /// assert_eq!(arr[1.. 3], [ 1,2 ]); // Range /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` -#[cfg_attr(not(bootstrap), lang = "Range")] +#[lang = "Range"] #[doc(alias = "..")] #[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -172,7 +172,7 @@ impl> Range { /// assert_eq!(arr[1.. 3], [ 1,2 ]); /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` -#[cfg_attr(not(bootstrap), lang = "RangeFrom")] +#[lang = "RangeFrom"] #[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -253,7 +253,7 @@ impl> RangeFrom { /// ``` /// /// [slicing index]: crate::slice::SliceIndex -#[cfg_attr(not(bootstrap), lang = "RangeTo")] +#[lang = "RangeTo"] #[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] @@ -322,7 +322,7 @@ impl> RangeTo { /// assert_eq!(arr[1.. 3], [ 1,2 ]); /// assert_eq!(arr[1..=3], [ 1,2,3 ]); // RangeInclusive /// ``` -#[cfg_attr(not(bootstrap), lang = "RangeInclusive")] +#[lang = "RangeInclusive"] #[doc(alias = "..=")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] @@ -354,7 +354,7 @@ impl RangeInclusive { /// /// assert_eq!(3..=5, RangeInclusive::new(3, 5)); /// ``` - #[cfg_attr(not(bootstrap), lang = "range_inclusive_new")] + #[lang = "range_inclusive_new"] #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] #[rustc_promotable] @@ -543,7 +543,7 @@ impl> RangeInclusive { /// ``` /// /// [slicing index]: crate::slice::SliceIndex -#[cfg_attr(not(bootstrap), lang = "RangeToInclusive")] +#[lang = "RangeToInclusive"] #[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "inclusive_range", since = "1.26.0")] diff --git a/library/core/src/ops/try.rs b/library/core/src/ops/try.rs index e6b05cc641..3bede56997 100644 --- a/library/core/src/ops/try.rs +++ b/library/core/src/ops/try.rs @@ -43,19 +43,19 @@ pub trait Try { /// in the return type of the enclosing scope (which must itself implement /// `Try`). Specifically, the value `X::from_error(From::from(e))` /// is returned, where `X` is the return type of the enclosing function. - #[cfg_attr(not(bootstrap), lang = "into_result")] + #[lang = "into_result"] #[unstable(feature = "try_trait", issue = "42327")] fn into_result(self) -> Result; /// Wrap an error value to construct the composite result. For example, /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. - #[cfg_attr(not(bootstrap), lang = "from_error")] + #[lang = "from_error"] #[unstable(feature = "try_trait", issue = "42327")] fn from_error(v: Self::Error) -> Self; /// Wrap an OK value to construct the composite result. For example, /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. - #[cfg_attr(not(bootstrap), lang = "from_ok")] + #[lang = "from_ok"] #[unstable(feature = "try_trait", issue = "42327")] fn from_ok(v: Self::Ok) -> Self; } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index b6aa2c6697..0cfb4af59b 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -70,10 +70,23 @@ //! } //! ``` //! -//! This usage of [`Option`] to create safe nullable pointers is so -//! common that Rust does special optimizations to make the -//! representation of [`Option`]`<`[`Box`]`>` a single pointer. Optional pointers -//! in Rust are stored as efficiently as any other pointer type. +//! # Representation +//! +//! Rust guarantees to optimize the following types `T` such that +//! [`Option`] has the same size as `T`: +//! +//! * [`Box`] +//! * `&U` +//! * `&mut U` +//! * `fn`, `extern "C" fn` +//! * [`num::NonZero*`] +//! * [`ptr::NonNull`] +//! * `#[repr(transparent)]` struct around one of the types in this list. +//! +//! It is further guaranteed that, for the cases above, one can +//! [`mem::transmute`] from all valid values of `T` to `Option` and +//! from `Some::(_)` to `T` (but transmuting `None::` to `T` +//! is undefined behaviour). //! //! # Examples //! @@ -144,11 +157,11 @@ use crate::{ #[stable(feature = "rust1", since = "1.0.0")] pub enum Option { /// No value - #[cfg_attr(not(bootstrap), lang = "None")] + #[lang = "None"] #[stable(feature = "rust1", since = "1.0.0")] None, /// Some value `T` - #[cfg_attr(not(bootstrap), lang = "Some")] + #[lang = "Some"] #[stable(feature = "rust1", since = "1.0.0")] Some(#[stable(feature = "rust1", since = "1.0.0")] T), } @@ -175,7 +188,7 @@ impl Option { /// ``` #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_some(&self) -> bool { matches!(*self, Some(_)) @@ -195,7 +208,7 @@ impl Option { #[must_use = "if you intended to assert that this doesn't have a value, consider \ `.and_then(|| panic!(\"`Option` had a value when expected `None`\"))` instead"] #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_none(&self) -> bool { !self.is_some() @@ -254,7 +267,7 @@ impl Option { /// println!("still can print text: {:?}", text); /// ``` #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn as_ref(&self) -> Option<&T> { match *self { @@ -1502,8 +1515,6 @@ unsafe impl TrustedLen for IterMut<'_, A> {} /// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. /// /// This `struct` is created by the [`Option::into_iter`] function. -/// -/// [`Option::into_iter`]: enum.Option.html#method.into_iter #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 316ecafe57..34a974b827 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -92,8 +92,6 @@ impl<'a> PanicInfo<'a> { /// If the `panic!` macro from the `core` crate (not from `std`) /// was used with a formatting string and some additional arguments, /// returns that message ready to be used for example with [`fmt::write`] - /// - /// [`fmt::write`]: ../fmt/fn.write.html #[unstable(feature = "panic_info_message", issue = "66745")] pub fn message(&self) -> Option<&fmt::Arguments<'_>> { self.message @@ -105,8 +103,6 @@ impl<'a> PanicInfo<'a> { /// This method will currently always return [`Some`], but this may change /// in future versions. /// - /// [`Some`]: ../../std/option/enum.Option.html#variant.Some - /// /// # Examples /// /// ```should_panic @@ -153,10 +149,7 @@ impl fmt::Display for PanicInfo<'_> { /// A struct containing information about the location of a panic. /// -/// This structure is created by the [`location`] method of [`PanicInfo`]. -/// -/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location -/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html +/// This structure is created by [`PanicInfo::location()`]. /// /// # Examples /// @@ -232,7 +225,7 @@ impl<'a> Location<'a> { /// assert_ne!(this_location.column(), another_location.column()); /// ``` #[stable(feature = "track_caller", since = "1.46.0")] - #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] + #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] #[track_caller] pub const fn caller() -> &'static Location<'static> { crate::intrinsics::caller_location() diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 290aa797fd..9f0284d5d9 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -471,10 +471,11 @@ impl> Pin

", class, tooltip ) .unwrap(); } - let sess = ParseSess::with_silent_emitter(); - let source_file = sess - .source_map() - .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src); + write_header(&mut out, class); + write_code(&mut out, &src); + write_footer(&mut out, playground_button); - let classifier_source_file = Lrc::clone(&source_file); - let highlight_result = rustc_driver::catch_fatal_errors(|| { - let mut classifier = Classifier::new(&sess, classifier_source_file); - - let mut highlighted_source = vec![]; - if classifier.write_source(&mut highlighted_source).is_err() { - Err(()) - } else { - Ok(String::from_utf8_lossy(&highlighted_source).into_owned()) - } - }) - .unwrap_or(Err(())); - - match highlight_result { - Ok(highlighted_source) => { - write_header(class, &mut out).unwrap(); - write!(out, "{}", highlighted_source).unwrap(); - write_footer(&mut out, playground_button).unwrap(); - } - Err(()) => { - // Get the source back out of the source map to avoid a copy in the happy path. - let span = - Span::new(BytePos(0), BytePos(source_file.byte_length()), SyntaxContext::root()); - let src = sess - .source_map() - .span_to_snippet(span) - .expect("could not retrieve snippet from artificial source file"); - - // If errors are encountered while trying to highlight, just emit - // the unhighlighted source. - write!(out, "
{}
", Escape(&src)).unwrap(); - } - } + out +} - String::from_utf8_lossy(&out[..]).into_owned() +fn write_header(out: &mut String, class: Option<&str>) { + write!(out, "
\n", class.unwrap_or_default())
+        .unwrap()
 }
 
-/// Processes a program (nested in the internal `lexer`), classifying strings of
-/// text by highlighting category (`Class`). Calls out to a `Writer` to write
-/// each span of text in sequence.
-struct Classifier<'sess> {
-    lexer: lexer::StringReader<'sess>,
-    peek_token: Option,
-    source_map: &'sess SourceMap,
+fn write_code(out: &mut String, src: &str) {
+    Classifier::new(src).highlight(&mut |highlight| {
+        match highlight {
+            Highlight::Token { text, class } => string(out, Escape(text), class),
+            Highlight::EnterSpan { class } => enter_span(out, class),
+            Highlight::ExitSpan => exit_span(out),
+        };
+    });
+}
 
-    // State of the classifier.
-    in_attribute: bool,
-    in_macro: bool,
-    in_macro_nonterminal: bool,
+fn write_footer(out: &mut String, playground_button: Option<&str>) {
+    write!(out, "
{}
\n", playground_button.unwrap_or_default()).unwrap() } /// How a span of text is classified. Mostly corresponds to token kinds. @@ -119,335 +83,265 @@ enum Class { QuestionMark, } -/// Trait that controls writing the output of syntax highlighting. Users should -/// implement this trait to customize writing output. -/// -/// The classifier will call into the `Writer` implementation as it finds spans -/// of text to highlight. Exactly how that text should be highlighted is up to -/// the implementation. -trait Writer { - /// Called when we start processing a span of text that should be highlighted. - /// The `Class` argument specifies how it should be highlighted. - fn enter_span(&mut self, _: Class) -> io::Result<()>; - - /// Called at the end of a span of highlighted text. - fn exit_span(&mut self) -> io::Result<()>; - - /// Called for a span of text. If the text should be highlighted differently from the - /// surrounding text, then the `Class` argument will be a value other than `None`. - /// - /// The following sequences of callbacks are equivalent: - /// ```plain - /// enter_span(Foo), string("text", None), exit_span() - /// string("text", Foo) - /// ``` - /// The latter can be thought of as a shorthand for the former, which is - /// more flexible. - fn string(&mut self, text: T, klass: Class) -> io::Result<()>; -} - -// Implement `Writer` for anything that can be written to, this just implements -// the default rustdoc behaviour. -impl Writer for U { - fn string(&mut self, text: T, klass: Class) -> io::Result<()> { - match klass { - Class::None => write!(self, "{}", text), - klass => write!(self, "{}", klass.rustdoc_class(), text), +impl Class { + /// Returns the css class expected by rustdoc for each `Class`. + fn as_html(self) -> &'static str { + match self { + Class::None => "", + Class::Comment => "comment", + Class::DocComment => "doccomment", + Class::Attribute => "attribute", + 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::Lifetime => "lifetime", + Class::PreludeTy => "prelude-ty", + Class::PreludeVal => "prelude-val", + Class::QuestionMark => "question-mark", } } - - fn enter_span(&mut self, klass: Class) -> io::Result<()> { - write!(self, "", klass.rustdoc_class()) - } - - fn exit_span(&mut self) -> io::Result<()> { - write!(self, "") - } } -#[derive(Debug)] -enum HighlightError { - LexError, - IoError(io::Error), +enum Highlight<'a> { + Token { text: &'a str, class: Class }, + EnterSpan { class: Class }, + ExitSpan, } -impl From for HighlightError { - fn from(err: io::Error) -> Self { - HighlightError::IoError(err) - } +struct TokenIter<'a> { + src: &'a str, } -impl<'sess> Classifier<'sess> { - fn new(sess: &ParseSess, source_file: Lrc) -> Classifier<'_> { - let lexer = lexer::StringReader::new(sess, source_file, None); - - Classifier { - lexer, - peek_token: None, - source_map: sess.source_map(), - in_attribute: false, - in_macro: false, - in_macro_nonterminal: false, +impl Iterator for TokenIter<'a> { + type Item = (TokenKind, &'a str); + fn next(&mut self) -> Option<(TokenKind, &'a str)> { + if self.src.is_empty() { + return None; } + let token = rustc_lexer::first_token(self.src); + let (text, rest) = self.src.split_at(token.len); + self.src = rest; + Some((token.kind, text)) } +} - /// Gets the next token out of the lexer. - fn try_next_token(&mut self) -> Result { - if let Some(token) = self.peek_token.take() { - return Ok(token); - } - let token = self.lexer.next_token(); - if let token::Unknown(..) = &token.kind { - return Err(HighlightError::LexError); - } - Ok(token) - } +/// Processes program tokens, classifying strings of text by highlighting +/// category (`Class`). +struct Classifier<'a> { + tokens: Peekable>, + in_attribute: bool, + in_macro: bool, + in_macro_nonterminal: bool, +} - fn peek(&mut self) -> Result<&Token, HighlightError> { - if self.peek_token.is_none() { - let token = self.lexer.next_token(); - if let token::Unknown(..) = &token.kind { - return Err(HighlightError::LexError); - } - self.peek_token = Some(token); - } - Ok(self.peek_token.as_ref().unwrap()) +impl<'a> Classifier<'a> { + fn new(src: &str) -> Classifier<'_> { + let tokens = TokenIter { src }.peekable(); + Classifier { tokens, in_attribute: false, in_macro: false, in_macro_nonterminal: false } } - /// Exhausts the `lexer` writing the output into `out`. + /// Exhausts the `Classifier` writing the output into `sink`. /// /// The general structure for this method is to iterate over each token, - /// possibly giving it an HTML span with a class specifying what flavor of token - /// is used. All source code emission is done as slices from the source map, - /// not from the tokens themselves, in order to stay true to the original - /// source. - fn write_source(&mut self, out: &mut W) -> Result<(), HighlightError> { - loop { - let mut next = self.try_next_token()?; - if next == token::Eof { - break; - } - - // Glue any tokens that need to be glued. - if let Some(joint) = next.glue(self.peek()?) { - next = joint; - let _ = self.try_next_token()?; + /// possibly giving it an HTML span with a class specifying what flavor of + /// token is used. + fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) { + with_default_session_globals(|| { + while let Some((token, text)) = self.tokens.next() { + self.advance(token, text, sink); } - - self.write_token(out, next)?; - } - - Ok(()) + }) } - // Handles an individual token from the lexer. - fn write_token(&mut self, out: &mut W, token: Token) -> Result<(), HighlightError> { - let klass = match token.kind { - token::Shebang(s) => { - out.string(Escape(&s.as_str()), Class::None)?; - return Ok(()); - } - - token::Whitespace | token::Unknown(..) => Class::None, - token::Comment => Class::Comment, - token::DocComment(..) => Class::DocComment, - - // If this '&' or '*' token is followed by a non-whitespace token, assume that it's the - // reference or dereference operator or a reference or pointer type, instead of the - // bit-and or multiplication operator. - token::BinOp(token::And | token::Star) if self.peek()? != &token::Whitespace => { - Class::RefKeyWord + /// Single step of highlighting. This will classify `token`, but maybe also + /// a couple of following ones as well. + fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) { + let lookahead = self.peek(); + let class = match token { + TokenKind::Whitespace => Class::None, + TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => { + if doc_style.is_some() { + Class::DocComment + } else { + Class::Comment + } } - // Consider this as part of a macro invocation if there was a // leading identifier. - token::Not if self.in_macro => { + TokenKind::Bang if self.in_macro => { self.in_macro = false; Class::Macro } + // Assume that '&' or '*' is the reference or dereference operator + // or a reference or pointer type. Unless, of course, it looks like + // a logical and or a multiplication operator: `&&` or `* `. + TokenKind::Star => match lookahead { + Some(TokenKind::Whitespace) => Class::Op, + _ => Class::RefKeyWord, + }, + TokenKind::And => match lookahead { + Some(TokenKind::And) => { + let _and = self.tokens.next(); + sink(Highlight::Token { text: "&&", class: Class::Op }); + return; + } + Some(TokenKind::Eq) => { + let _eq = self.tokens.next(); + sink(Highlight::Token { text: "&=", class: Class::Op }); + return; + } + Some(TokenKind::Whitespace) => Class::Op, + _ => Class::RefKeyWord, + }, + // Operators. - token::Eq - | token::Lt - | token::Le - | token::EqEq - | token::Ne - | token::Ge - | token::Gt - | token::AndAnd - | token::OrOr - | token::Not - | token::BinOp(..) - | token::RArrow - | token::BinOpEq(..) - | token::FatArrow => Class::Op, + TokenKind::Minus + | TokenKind::Plus + | TokenKind::Or + | TokenKind::Slash + | TokenKind::Caret + | TokenKind::Percent + | TokenKind::Bang + | TokenKind::Eq + | TokenKind::Lt + | TokenKind::Gt => Class::Op, // Miscellaneous, no highlighting. - token::Dot - | token::DotDot - | token::DotDotDot - | token::DotDotEq - | token::Comma - | token::Semi - | token::Colon - | token::ModSep - | token::LArrow - | token::OpenDelim(_) - | token::CloseDelim(token::Brace | token::Paren | token::NoDelim) => Class::None, - - token::Question => Class::QuestionMark, - - token::Dollar => { - if self.peek()?.is_ident() { + TokenKind::Dot + | TokenKind::Semi + | TokenKind::Comma + | TokenKind::OpenParen + | TokenKind::CloseParen + | TokenKind::OpenBrace + | TokenKind::CloseBrace + | TokenKind::OpenBracket + | TokenKind::At + | TokenKind::Tilde + | TokenKind::Colon + | TokenKind::Unknown => Class::None, + + TokenKind::Question => Class::QuestionMark, + + TokenKind::Dollar => match lookahead { + Some(TokenKind::Ident) => { self.in_macro_nonterminal = true; Class::MacroNonTerminal - } else { - Class::None } - } + _ => Class::None, + }, // This might be the start of an attribute. We're going to want to // continue highlighting it as an attribute until the ending ']' is // seen, so skip out early. Down below we terminate the attribute // span when we see the ']'. - token::Pound => { - // We can't be sure that our # begins an attribute (it could - // just be appearing in a macro) until we read either `#![` or - // `#[` from the input stream. - // - // We don't want to start highlighting as an attribute until - // we're confident there is going to be a ] coming up, as - // otherwise # tokens in macros highlight the rest of the input - // as an attribute. - - // Case 1: #![inner_attribute] - if self.peek()? == &token::Not { - self.try_next_token()?; // NOTE: consumes `!` token! - if self.peek()? == &token::OpenDelim(token::Bracket) { + TokenKind::Pound => { + match lookahead { + // Case 1: #![inner_attribute] + Some(TokenKind::Bang) => { + let _not = self.tokens.next().unwrap(); + if let Some(TokenKind::OpenBracket) = self.peek() { + self.in_attribute = true; + sink(Highlight::EnterSpan { class: Class::Attribute }); + } + sink(Highlight::Token { text: "#", class: Class::None }); + sink(Highlight::Token { text: "!", class: Class::None }); + return; + } + // Case 2: #[outer_attribute] + Some(TokenKind::OpenBracket) => { self.in_attribute = true; - out.enter_span(Class::Attribute)?; + sink(Highlight::EnterSpan { class: Class::Attribute }); } - out.string("#", Class::None)?; - out.string("!", Class::None)?; - return Ok(()); - } - - // Case 2: #[outer_attribute] - if self.peek()? == &token::OpenDelim(token::Bracket) { - self.in_attribute = true; - out.enter_span(Class::Attribute)?; + _ => (), } - out.string("#", Class::None)?; - return Ok(()); + Class::None } - token::CloseDelim(token::Bracket) => { + TokenKind::CloseBracket => { if self.in_attribute { self.in_attribute = false; - out.string("]", Class::None)?; - out.exit_span()?; - return Ok(()); - } else { - Class::None + sink(Highlight::Token { text: "]", class: Class::None }); + sink(Highlight::ExitSpan); + return; } + Class::None } - - token::Literal(lit) => { - match lit.kind { - // Text literals. - token::Byte - | token::Char - | token::Err - | token::ByteStr - | token::ByteStrRaw(..) - | token::Str - | token::StrRaw(..) => Class::String, - - // Number literals. - token::Integer | token::Float => Class::Number, - - token::Bool => panic!("literal token contains `Lit::Bool`"), - } + TokenKind::Literal { kind, .. } => match kind { + // Text literals. + LiteralKind::Byte { .. } + | LiteralKind::Char { .. } + | LiteralKind::Str { .. } + | LiteralKind::ByteStr { .. } + | LiteralKind::RawStr { .. } + | LiteralKind::RawByteStr { .. } => Class::String, + // Number literals. + LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number, + }, + TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => { + self.in_macro = true; + Class::Macro } - - // Keywords are also included in the identifier set. - token::Ident(name, is_raw) => match name { - kw::Ref | kw::Mut if !is_raw => Class::RefKeyWord, - - kw::SelfLower | kw::SelfUpper => Class::Self_, - kw::False | kw::True if !is_raw => Class::Bool, - - sym::Option | sym::Result => Class::PreludeTy, - sym::Some | sym::None | sym::Ok | sym::Err => Class::PreludeVal, - - _ if token.is_reserved_ident() => Class::KeyWord, - - _ => { - if self.in_macro_nonterminal { - self.in_macro_nonterminal = false; - Class::MacroNonTerminal - } else if self.peek()? == &token::Not { - self.in_macro = true; - Class::Macro - } else { - Class::Ident - } + TokenKind::Ident => match text { + "ref" | "mut" => Class::RefKeyWord, + "self" | "Self" => Class::Self_, + "false" | "true" => Class::Bool, + "Option" | "Result" => Class::PreludeTy, + "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, + // Keywords are also included in the identifier set. + _ if Ident::from_str(text).is_reserved() => Class::KeyWord, + _ if self.in_macro_nonterminal => { + self.in_macro_nonterminal = false; + Class::MacroNonTerminal } + _ => Class::Ident, }, - - token::Lifetime(..) => Class::Lifetime, - - token::Eof - | token::Interpolated(..) - | token::Tilde - | token::At - | token::SingleQuote => Class::None, + TokenKind::RawIdent => Class::Ident, + TokenKind::Lifetime { .. } => Class::Lifetime, }; - // Anything that didn't return above is the simple case where we the // class just spans a single token, so we can use the `string` method. - out.string(Escape(&self.snip(token.span)), klass)?; - - Ok(()) + sink(Highlight::Token { text, class }); } - // Helper function to get a snippet from the source_map. - fn snip(&self, sp: Span) -> String { - self.source_map.span_to_snippet(sp).unwrap() + fn peek(&mut self) -> Option { + self.tokens.peek().map(|(toke_kind, _text)| *toke_kind) } } -impl Class { - /// Returns the css class expected by rustdoc for each `Class`. - fn rustdoc_class(self) -> &'static str { - match self { - Class::None => "", - Class::Comment => "comment", - Class::DocComment => "doccomment", - Class::Attribute => "attribute", - 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::Lifetime => "lifetime", - Class::PreludeTy => "prelude-ty", - Class::PreludeVal => "prelude-val", - Class::QuestionMark => "question-mark", - } - } +/// Called when we start processing a span of text that should be highlighted. +/// The `Class` argument specifies how it should be highlighted. +fn enter_span(out: &mut String, klass: Class) { + write!(out, "", klass.as_html()).unwrap() } -fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> { - write!(out, "
\n", class.unwrap_or(""))
+/// Called at the end of a span of highlighted text.
+fn exit_span(out: &mut String) {
+    write!(out, "").unwrap()
 }
 
-fn write_footer(out: &mut dyn Write, playground_button: Option<&str>) -> io::Result<()> {
-    write!(out, "
{}
\n", if let Some(button) = playground_button { button } else { "" }) +/// Called for a span of text. If the text should be highlighted differently +/// from the surrounding text, then the `Class` argument will be a value other +/// than `None`. +/// +/// The following sequences of callbacks are equivalent: +/// ```plain +/// enter_span(Foo), string("text", None), exit_span() +/// string("text", Foo) +/// ``` +/// The latter can be thought of as a shorthand for the former, which is more +/// flexible. +fn string(out: &mut String, text: T, klass: Class) { + match klass { + Class::None => write!(out, "{}", text).unwrap(), + klass => write!(out, "{}", klass.as_html(), text).unwrap(), + } } #[cfg(test)] diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html new file mode 100644 index 0000000000..d937246f46 --- /dev/null +++ b/src/librustdoc/html/highlight/fixtures/sample.html @@ -0,0 +1,27 @@ + + +
#![crate_type = "lib"]
+
+#[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);
+}
+
+macro_rules! bar {
+    ($foo:tt) => {};
+}
+
diff --git a/src/librustdoc/html/highlight/fixtures/sample.rs b/src/librustdoc/html/highlight/fixtures/sample.rs new file mode 100644 index 0000000000..956fdbe090 --- /dev/null +++ b/src/librustdoc/html/highlight/fixtures/sample.rs @@ -0,0 +1,16 @@ +#![crate_type = "lib"] + +#[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); +} + +macro_rules! bar { + ($foo:tt) => {}; +} diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 21e476cbe0..c79471b1fa 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,82 +1,25 @@ -use rustc_session::parse::ParseSess; -use rustc_span::edition::Edition; -use rustc_span::with_session_globals; -use rustc_span::FileName; - -use super::Classifier; - -fn highlight(src: &str) -> String { - let mut out = vec![]; - - with_session_globals(Edition::Edition2018, || { - let sess = ParseSess::with_silent_emitter(); - let source_file = sess.source_map().new_source_file( - FileName::Custom(String::from("rustdoc-highlighting")), - src.to_owned(), - ); - - let mut classifier = Classifier::new(&sess, source_file); - classifier.write_source(&mut out).unwrap(); - }); - - String::from_utf8(out).unwrap() -} - -#[test] -fn function() { - assert_eq!( - highlight("fn main() {}"), - r#"fn main() {}"#, - ); -} - -#[test] -fn statement() { - assert_eq!( - highlight("let foo = true;"), - concat!( - r#"let foo "#, - r#"= true;"#, - ), - ); -} - -#[test] -fn inner_attr() { - assert_eq!( - highlight(r##"#![crate_type = "lib"]"##), - concat!( - r##"#![crate_type "##, - r##"= "lib"]"##, - ), - ); -} +use super::write_code; +use expect_test::expect_file; #[test] -fn outer_attr() { - assert_eq!( - highlight(r##"#[cfg(target_os = "linux")]"##), - concat!( - r##"#[cfg("##, - r##"target_os = "##, - r##""linux")]"##, - ), - ); +fn test_html_highlighting() { + let src = include_str!("fixtures/sample.rs"); + let html = { + let mut out = String::new(); + write_code(&mut out, src); + format!("{}
{}
\n", STYLE, out) + }; + expect_file!["fixtures/sample.html"].assert_eq(&html); } -#[test] -fn mac() { - assert_eq!( - highlight("mac!(foo bar)"), - concat!( - r#"mac!("#, - r#"foo bar)"#, - ), - ); -} - -// Regression test for #72684 -#[test] -fn andand() { - assert_eq!(highlight("&&"), r#"&&"#); -} +const STYLE: &str = r#" + +"#; diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index fd67a66395..7239b3c5ba 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -158,7 +158,9 @@ pub fn render( keywords = page.keywords, favicon = if layout.favicon.is_empty() { format!( - r#""#, + r##" + +"##, static_root_path = static_root_path, suffix = page.resource_suffix ) @@ -210,8 +212,8 @@ pub fn render( .collect::(), filter_crates = if layout.generate_search_filter { "" + \ + " } else { "" }, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b2589e5b80..6c0f1c02ac 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,18 +27,18 @@ use rustc_session::lint; use rustc_span::edition::Edition; use rustc_span::Span; use std::borrow::Cow; -use std::cell::RefCell; use std::collections::VecDeque; use std::default::Default; use std::fmt::Write; use std::ops::Range; use std::str; +use crate::clean::RenderedLink; +use crate::doctest; use crate::html::highlight; use crate::html::toc::TocBuilder; -use crate::test; -use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; +use pulldown_cmark::{html, BrokenLink, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; #[cfg(test)] mod tests; @@ -52,7 +52,7 @@ fn opts() -> Options { pub struct Markdown<'a>( pub &'a str, /// A list of link replacements. - pub &'a [(String, String)], + pub &'a [RenderedLink], /// The current list of used header IDs. pub &'a mut IdMap, /// Whether to allow the use of explicit error codes in doctest lang strings. @@ -78,7 +78,7 @@ pub struct MarkdownHtml<'a>( pub &'a Option, ); /// A tuple struct like `Markdown` that renders only the first paragraph. -pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]); +pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [RenderedLink]); #[derive(Copy, Clone, PartialEq, Debug)] pub enum ErrorCodes { @@ -243,7 +243,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .collect::>>() .join("\n"); let krate = krate.as_ref().map(|s| &**s); - let (test, _) = test::make_test(&test, krate, false, &Default::default(), edition); + let (test, _) = doctest::make_test(&test, krate, false, &Default::default(), edition); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let edition_string = format!("&edition={}", edition); @@ -337,31 +337,107 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { } /// Make headings links with anchor IDs and build up TOC. -struct LinkReplacer<'a, 'b, I: Iterator>> { +struct LinkReplacer<'a, I: Iterator>> { inner: I, - links: &'b [(String, String)], + links: &'a [RenderedLink], + shortcut_link: Option<&'a RenderedLink>, } -impl<'a, 'b, I: Iterator>> LinkReplacer<'a, 'b, I> { - fn new(iter: I, links: &'b [(String, String)]) -> Self { - LinkReplacer { inner: iter, links } +impl<'a, I: Iterator>> LinkReplacer<'a, I> { + fn new(iter: I, links: &'a [RenderedLink]) -> Self { + LinkReplacer { inner: iter, links, shortcut_link: None } } } -impl<'a, 'b, I: Iterator>> Iterator for LinkReplacer<'a, 'b, I> { +impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { type Item = Event<'a>; fn next(&mut self) -> Option { - let event = self.inner.next(); - if let Some(Event::Start(Tag::Link(kind, dest, text))) = event { - if let Some(&(_, ref replace)) = self.links.iter().find(|link| link.0 == *dest) { - Some(Event::Start(Tag::Link(kind, replace.to_owned().into(), text))) - } else { - Some(Event::Start(Tag::Link(kind, dest, text))) + use pulldown_cmark::LinkType; + + let mut event = self.inner.next(); + + // Replace intra-doc links and remove disambiguators from shortcut links (`[fn@f]`). + match &mut event { + // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]` + // Remove any disambiguator. + Some(Event::Start(Tag::Link( + // [fn@f] or [fn@f][] + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest, + title, + ))) => { + debug!("saw start of shortcut link to {} with title {}", dest, title); + // If this is a shortcut link, it was resolved by the broken_link_callback. + // So the URL will already be updated properly. + let link = self.links.iter().find(|&link| *link.href == **dest); + // Since this is an external iterator, we can't replace the inner text just yet. + // Store that we saw a link so we know to replace it later. + if let Some(link) = link { + trace!("it matched"); + assert!(self.shortcut_link.is_none(), "shortcut links cannot be nested"); + self.shortcut_link = Some(link); + } } - } else { - event + // Now that we're done with the shortcut link, don't replace any more text. + Some(Event::End(Tag::Link( + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest, + _, + ))) => { + debug!("saw end of shortcut link to {}", dest); + if self.links.iter().find(|&link| *link.href == **dest).is_some() { + assert!(self.shortcut_link.is_some(), "saw closing link without opening tag"); + self.shortcut_link = None; + } + } + // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link. + // [`fn@f`] + Some(Event::Code(text)) => { + trace!("saw code {}", text); + if let Some(link) = self.shortcut_link { + trace!("original text was {}", link.original_text); + // NOTE: this only replaces if the code block is the *entire* text. + // If only part of the link has code highlighting, the disambiguator will not be removed. + // e.g. [fn@`f`] + // This is a limitation from `collect_intra_doc_links`: it passes a full link, + // and does not distinguish at all between code blocks. + // So we could never be sure we weren't replacing too much: + // [fn@my_`f`unc] is treated the same as [my_func()] in that pass. + // + // NOTE: &[1..len() - 1] is to strip the backticks + if **text == link.original_text[1..link.original_text.len() - 1] { + debug!("replacing {} with {}", text, link.new_text); + *text = CowStr::Borrowed(&link.new_text); + } + } + } + // Replace plain text in links, but only in the middle of a shortcut link. + // [fn@f] + Some(Event::Text(text)) => { + trace!("saw text {}", text); + if let Some(link) = self.shortcut_link { + trace!("original text was {}", link.original_text); + // NOTE: same limitations as `Event::Code` + if **text == *link.original_text { + debug!("replacing {} with {}", text, link.new_text); + *text = CowStr::Borrowed(&link.new_text); + } + } + } + // If this is a link, but not a shortcut link, + // replace the URL, since the broken_link_callback was not called. + Some(Event::Start(Tag::Link(_, dest, _))) => { + if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) { + *dest = CowStr::Borrowed(link.href.as_ref()); + } + } + // Anything else couldn't have been a valid Rust path, so no need to replace the text. + _ => {} } + + // Yield the modified event + event } } @@ -519,8 +595,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { Some(Event::FootnoteReference(ref reference)) => { let entry = self.get_entry(&reference); let reference = format!( - "{0}\ - ", + "{0}", (*entry).1 ); return Some(Event::Html(reference.into())); @@ -568,7 +643,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { } } -pub fn find_testable_code( +pub fn find_testable_code( doc: &str, tests: &mut T, error_codes: ErrorCodes, @@ -855,15 +930,17 @@ impl Markdown<'_> { if md.is_empty() { return String::new(); } - let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { - Some((replace.clone(), s.to_owned())) + let mut replacer = |broken_link: BrokenLink<'_>| { + if let Some(link) = + links.iter().find(|link| &*link.original_text == broken_link.reference) + { + Some((link.href.as_str().into(), link.new_text.as_str().into())) } else { None } }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&replacer)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -933,9 +1010,11 @@ impl MarkdownSummaryLine<'_> { return String::new(); } - let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { - Some((replace.clone(), s.to_owned())) + let mut replacer = |broken_link: BrokenLink<'_>| { + if let Some(link) = + links.iter().find(|link| &*link.original_text == broken_link.reference) + { + Some((link.href.as_str().into(), link.new_text.as_str().into())) } else { None } @@ -944,7 +1023,7 @@ impl MarkdownSummaryLine<'_> { let p = Parser::new_with_broken_link_callback( md, Options::ENABLE_STRIKETHROUGH, - Some(&replacer), + Some(&mut replacer), ); let mut s = String::new(); @@ -955,44 +1034,33 @@ impl MarkdownSummaryLine<'_> { } } -pub fn plain_summary_line(md: &str) -> String { - struct ParserWrapper<'a> { - inner: Parser<'a>, - is_in: isize, - is_first: bool, +/// Renders the first paragraph of the provided markdown as plain text. +/// +/// - Headings, links, and formatting are stripped. +/// - Inline code is rendered as-is, surrounded by backticks. +/// - HTML and code blocks are ignored. +pub fn plain_text_summary(md: &str) -> String { + if md.is_empty() { + return String::new(); } - impl<'a> Iterator for ParserWrapper<'a> { - type Item = String; - - fn next(&mut self) -> Option { - let next_event = self.inner.next()?; - let (ret, is_in) = match next_event { - Event::Start(Tag::Paragraph) => (None, 1), - Event::Start(Tag::Heading(_)) => (None, 1), - Event::Code(code) => (Some(format!("`{}`", code)), 0), - Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), - Event::End(Tag::Paragraph | Tag::Heading(_)) => (None, -1), - _ => (None, 0), - }; - if is_in > 0 || (is_in < 0 && self.is_in > 0) { - self.is_in += is_in; - } - if ret.is_some() { - self.is_first = false; - ret - } else { - Some(String::new()) + let mut s = String::with_capacity(md.len() * 3 / 2); + + for event in Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH) { + match &event { + Event::Text(text) => s.push_str(text), + Event::Code(code) => { + s.push('`'); + s.push_str(code); + s.push('`'); } + Event::HardBreak | Event::SoftBreak => s.push(' '), + Event::Start(Tag::CodeBlock(..)) => break, + Event::End(Tag::Paragraph) => break, + _ => (), } } - let mut s = String::with_capacity(md.len() * 3 / 2); - let p = ParserWrapper { - inner: Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH), - is_in: 0, - is_first: true, - }; - p.filter(|t| !t.is_empty()).for_each(|i| s.push_str(&i)); + s } @@ -1002,7 +1070,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } let mut links = vec![]; - let shortcut_links = RefCell::new(vec![]); + let mut shortcut_links = vec![]; { let locate = |s: &str| unsafe { @@ -1019,11 +1087,13 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } }; - let push = |_: &str, s: &str| { - shortcut_links.borrow_mut().push((s.to_owned(), locate(s))); + let mut push = |link: BrokenLink<'_>| { + // FIXME: use `link.span` instead of `locate` + // (doing it now includes the `[]` as well as the text) + shortcut_links.push((link.reference.to_owned(), locate(link.reference))); None }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&push)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)); // There's no need to thread an IdMap through to here because // the IDs generated aren't going to be emitted anywhere. @@ -1041,8 +1111,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } } - let mut shortcut_links = shortcut_links.into_inner(); - links.extend(shortcut_links.drain(..)); + links.append(&mut shortcut_links); links } diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 783977d285..8e618733f0 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -1,4 +1,4 @@ -use super::plain_summary_line; +use super::plain_text_summary; use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use std::cell::RefCell; @@ -140,25 +140,26 @@ fn test_header() { t( "# Foo bar", - "

\ - Foo bar

", + "

Foo bar

", ); t( "## Foo-bar_baz qux", - "

Foo-bar_baz qux

", + "

\ + Foo-bar_baz qux

", ); t( "### **Foo** *bar* baz!?!& -_qux_-%", "

\ - Foo \ - bar baz!?!& -qux-%

", + Foo \ + bar baz!?!& -qux-%\ + ", ); t( "#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux", "

\ - Foo? & *bar?!* \ - baz ❤ #qux

", + Foo? & *bar?!* \ + baz ❤ #qux\ + ", ); } @@ -174,54 +175,55 @@ fn test_header_ids_multiple_blocks() { t( &mut map, "# Example", - "

\ - Example

", + "

Example

", ); t( &mut map, "# Panics", - "

\ - Panics

", + "

Panics

", ); t( &mut map, "# Example", - "

\ - Example

", + "

Example

", ); t( &mut map, "# Main", - "

\ - Main

", + "

Main

", ); t( &mut map, "# Example", - "

\ - Example

", + "

Example

", ); t( &mut map, "# Panics", - "

\ - Panics

", + "

Panics

", ); } #[test] -fn test_plain_summary_line() { +fn test_plain_text_summary() { fn t(input: &str, expect: &str) { - let output = plain_summary_line(input); + let output = plain_text_summary(input); assert_eq!(output, expect, "original: {}", input); } t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); + t("**bold**", "bold"); + t("Multi-line\nsummary", "Multi-line summary"); + t("Hard-break \nsummary", "Hard-break summary"); + t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)"); t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); t("code `let x = i32;` ...", "code `let x = i32;` ..."); t("type `Type<'static>` ...", "type `Type<'static>` ..."); t("# top header", "top header"); t("## header", "header"); + t("first paragraph\n\nsecond paragraph", "first paragraph"); + t("```\nfn main() {}\n```", ""); + t("
hello
", ""); } #[test] diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index ccc0764562..cf785d362c 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -9,7 +9,7 @@ use crate::clean::types::GetDefId; use crate::clean::{self, AttributesExt}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::html::render::{plain_summary_line, shorten}; +use crate::html::render::{plain_text_summary, shorten}; use crate::html::render::{Generic, IndexItem, IndexItemFunctionType, RenderType, TypeWithKind}; /// Indicates where an external crate can be found. @@ -78,7 +78,7 @@ pub fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { ty: item.type_(), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), - desc: shorten(plain_summary_line(item.doc_value())), + desc: shorten(plain_text_summary(item.doc_value())), parent: Some(did), parent_idx: None, search_type: get_index_search_type(&item), @@ -127,7 +127,7 @@ pub fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let crate_doc = krate .module .as_ref() - .map(|module| shorten(plain_summary_line(module.doc_value()))) + .map(|module| shorten(plain_text_summary(module.doc_value()))) .unwrap_or(String::new()); #[derive(Serialize)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d17961521c..8b5ba7a239 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -63,9 +63,8 @@ use rustc_span::symbol::{sym, Symbol}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; -use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, TypeKind}; -use crate::config::RenderInfo; -use crate::config::RenderOptions; +use crate::clean::{self, AttributesExt, Deprecation, GetDefId, RenderedLink, SelfTy, TypeKind}; +use crate::config::{RenderInfo, RenderOptions}; use crate::docfs::{DocFS, PathError}; use crate::doctree; use crate::error::Error; @@ -755,7 +754,9 @@ fn write_shared( write(cx.path("rust-logo.png"), static_files::RUST_LOGO)?; } if (*cx.shared).layout.favicon.is_empty() { - write(cx.path("favicon.ico"), static_files::RUST_FAVICON)?; + write(cx.path("favicon.svg"), static_files::RUST_FAVICON_SVG)?; + write(cx.path("favicon-16x16.png"), static_files::RUST_FAVICON_PNG_16)?; + write(cx.path("favicon-32x32.png"), static_files::RUST_FAVICON_PNG_32)?; } write(cx.path("brush.svg"), static_files::BRUSH_SVG)?; write(cx.path("wheel.svg"), static_files::WHEEL_SVG)?; @@ -1061,12 +1062,17 @@ themePicker.onblur = handleThemeButtonsBlur; let content = format!( "

\ - List of all crates\ -

    {}
", + List of all crates\ + \ +
    {}
", krates .iter() .map(|s| { - format!("
  • {}
  • ", ensure_trailing_slash(s), s) + format!( + "
  • {}
  • ", + ensure_trailing_slash(s), + s + ) }) .collect::() ); @@ -1307,15 +1313,16 @@ impl AllTypes { write!( f, "

    \ - \ - \ - \ - []\ - \ - - - List of all items\ -

    " + \ + \ + \ + []\ + \ + + + List of all items\ + " ); print_entries(f, &self.structs, "Structs", "structs"); print_entries(f, &self.enums, "Enums", "enums"); @@ -1345,20 +1352,20 @@ impl Setting { match *self { Setting::Section { ref description, ref sub_settings } => format!( "
    \ -
    {}
    \ -
    {}
    -
    ", +
    {}
    \ +
    {}
    + ", description, sub_settings.iter().map(|s| s.display()).collect::() ), Setting::Entry { ref js_data_name, ref description, ref default_value } => format!( "
    \ - \ -
    {}
    \ -
    ", + \ +
    {}
    \ + ", js_data_name, if *default_value { " checked" } else { "" }, description, @@ -1502,6 +1509,7 @@ impl Context { } } + /// Construct a map of items shown in the sidebar to a plain-text summary of their docs. fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap> { // BTreeMap instead of HashMap to get a sorted output let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new(); @@ -1518,7 +1526,7 @@ impl Context { let short = short.to_string(); map.entry(short) .or_default() - .push((myname, Some(plain_summary_line(item.doc_value())))); + .push((myname, Some(plain_text_summary(item.doc_value())))); } if self.shared.sort_modules_alphabetically { @@ -1724,22 +1732,15 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } +/// Renders the first paragraph of the given markdown as plain text, making it suitable for +/// contexts like alt-text or the search index. +/// +/// If no markdown is supplied, the empty string is returned. +/// +/// See [`markdown::plain_text_summary`] for further details. #[inline] -crate fn plain_summary_line(s: Option<&str>) -> String { - let s = s.unwrap_or(""); - // This essentially gets the first paragraph of text in one line. - let mut line = s - .lines() - .skip_while(|line| line.chars().all(|c| c.is_whitespace())) - .take_while(|line| line.chars().any(|c| !c.is_whitespace())) - .fold(String::new(), |mut acc, line| { - acc.push_str(line); - acc.push(' '); - acc - }); - // remove final whitespace - line.pop(); - markdown::plain_summary_line(&line[..]) +crate fn plain_text_summary(s: Option<&str>) -> String { + s.map(markdown::plain_text_summary).unwrap_or_default() } crate fn shorten(s: String) -> String { @@ -1774,7 +1775,7 @@ fn render_markdown( w: &mut Buffer, cx: &Context, md_text: &str, - links: Vec<(String, String)>, + links: Vec, prefix: &str, is_hidden: bool, ) { @@ -1796,25 +1797,35 @@ fn render_markdown( ) } +/// Writes a documentation block containing only the first paragraph of the documentation. If the +/// docs are longer, a "Read more" link is appended to the end. fn document_short( w: &mut Buffer, - cx: &Context, item: &clean::Item, link: AssocItemLink<'_>, prefix: &str, is_hidden: bool, ) { if let Some(s) = item.doc_value() { - let markdown = if s.contains('\n') { - format!( - "{} [Read more]({})", - &plain_summary_line(Some(s)), - naive_assoc_href(item, link) - ) - } else { - plain_summary_line(Some(s)) - }; - render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden); + let mut summary_html = MarkdownSummaryLine(s, &item.links()).into_string(); + + if s.contains('\n') { + let link = format!(r#" Read more"#, naive_assoc_href(item, link)); + + if let Some(idx) = summary_html.rfind("

    ") { + summary_html.insert_str(idx, &link); + } else { + summary_html.push_str(&link); + } + } + + write!( + w, + "
    {}{}
    ", + if is_hidden { " hidden" } else { "" }, + prefix, + summary_html, + ); } else if !prefix.is_empty() { write!( w, @@ -1872,30 +1883,29 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { write!( w, "Non-exhaustive structs could have additional fields added in future. \ - Therefore, non-exhaustive structs cannot be constructed in external crates \ - using the traditional Struct {{ .. }} syntax; cannot be \ - matched against without a wildcard ..; and \ - struct update syntax will not work." + Therefore, non-exhaustive structs cannot be constructed in external crates \ + using the traditional Struct {{ .. }} syntax; cannot be \ + matched against without a wildcard ..; and \ + struct update syntax will not work." ); } else if item.is_enum() { write!( w, "Non-exhaustive enums could have additional variants added in future. \ - Therefore, when matching against variants of non-exhaustive enums, an \ - extra wildcard arm must be added to account for any future variants." + Therefore, when matching against variants of non-exhaustive enums, an \ + extra wildcard arm must be added to account for any future variants." ); } else if item.is_variant() { write!( w, "Non-exhaustive enum variants could have additional fields added in future. \ - Therefore, non-exhaustive enum variants cannot be constructed in external \ - crates and cannot be matched against." + Therefore, non-exhaustive enum variants cannot be constructed in external \ + crates and cannot be matched against." ); } else { write!( w, - "This type will require a wildcard arm in any match statements or \ - constructors." + "This type will require a wildcard arm in any match statements or constructors." ); } @@ -2092,12 +2102,11 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: let doc_value = myitem.doc_value().unwrap_or(""); write!( w, - "\ - \ - {name}{unsafety_flag}\ - {stab_tags}{docs}\ - ", + "\ + {name}{unsafety_flag}\ + {stab_tags}{docs}\ + ", name = *myitem.name.as_ref().unwrap(), stab_tags = stability_tags(myitem), docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(), @@ -2126,8 +2135,8 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: fn stability_tags(item: &clean::Item) -> String { let mut tags = String::new(); - fn tag_html(class: &str, contents: &str) -> String { - format!(r#"{}"#, class, contents) + fn tag_html(class: &str, title: &str, contents: &str) -> String { + format!(r#"{}"#, class, Escape(title), contents) } // The trailing space after each tag is to space it properly against the rest of the docs. @@ -2136,7 +2145,7 @@ fn stability_tags(item: &clean::Item) -> String { if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) { message = "Deprecation planned"; } - tags += &tag_html("deprecated", message); + tags += &tag_html("deprecated", "", message); } // The "rustc_private" crates are permanently unstable so it makes no sense @@ -2147,11 +2156,11 @@ fn stability_tags(item: &clean::Item) -> String { .map(|s| s.level == stability::Unstable && s.feature != "rustc_private") == Some(true) { - tags += &tag_html("unstable", "Experimental"); + tags += &tag_html("unstable", "", "Experimental"); } if let Some(ref cfg) = item.attrs.cfg { - tags += &tag_html("portability", &cfg.render_short_html()); + tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html()); } tags @@ -2246,8 +2255,7 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons write!( w, - "{vis}const \ - {name}: {typ}", + "{vis}const {name}: {typ}", vis = it.visibility.print_with_space(), name = it.name.as_ref().unwrap(), typ = c.type_.print(), @@ -2281,8 +2289,7 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static render_attributes(w, it, false); write!( w, - "{vis}static {mutability}\ - {name}: {typ}", + "{vis}static {mutability} {name}: {typ}", vis = it.visibility.print_with_space(), mutability = s.mutability.print_with_space(), name = it.name.as_ref().unwrap(), @@ -2308,7 +2315,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func write!( w, "{vis}{constness}{asyncness}{unsafety}{abi}fn \ - {name}{generics}{decl}{spotlight}{where_clause}", + {name}{generics}{decl}{spotlight}{where_clause}", vis = it.visibility.print_with_space(), constness = f.header.constness.print_with_space(), asyncness = f.header.asyncness.print_with_space(), @@ -2499,10 +2506,9 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { write!( w, - " -

    \ - {1}\ -

    {2}", + "

    \ + {1}\ +

    {2}", id, title, extra_content ) } @@ -2831,7 +2837,7 @@ fn render_assoc_item( write!( w, "{}{}{}{}{}{}{}fn {name}\ - {generics}{decl}{spotlight}{where_clause}", + {generics}{decl}{spotlight}{where_clause}", if parent == ItemType::Trait { " " } else { "" }, meth.visibility.print_with_space(), header.constness.print_with_space(), @@ -2906,9 +2912,9 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct write!( w, "\ - \ - {name}: {ty}\ - ", + \ + {name}: {ty}\ +
    ", item_type = ItemType::StructField, id = id, name = field.name.as_ref().unwrap(), @@ -2950,9 +2956,9 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, write!( w, "\ - \ - {name}: {ty}\ - ", + \ + {name}: {ty}\ + ", id = id, name = name, shortty = ItemType::StructField, @@ -3077,9 +3083,9 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca write!( w, "\ - \ - {f}: {t}\ - ", + \ + {f}: {t}\ + ", id = id, f = field.name.as_ref().unwrap(), t = ty.print() @@ -3292,23 +3298,19 @@ fn render_assoc_items( AssocItemRender::All => { write!( w, - "\ -

    \ - Implementations\ -

    \ - " + "

    \ + Implementations\ +

    " ); RenderMode::Normal } AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { write!( w, - "\ -

    \ - Methods from {}<Target = {}>\ - \ -

    \ - ", + "

    \ + Methods from {}<Target = {}>\ + \ +

    ", trait_.print(), type_.print() ); @@ -3355,11 +3357,10 @@ fn render_assoc_items( if !impls.is_empty() { write!( w, - "\ -

    \ - Trait Implementations\ -

    \ -
    {}
    ", + "

    \ + Trait Implementations\ +

    \ +
    {}
    ", impls ); } @@ -3367,13 +3368,11 @@ fn render_assoc_items( if !synthetic.is_empty() { write!( w, - "\ -

    \ - Auto Trait Implementations\ - \ -

    \ -
    \ - " + "

    \ + Auto Trait Implementations\ + \ +

    \ +
    " ); render_impls(cx, w, &synthetic, containing_item, cache); write!(w, "
    "); @@ -3382,13 +3381,11 @@ fn render_assoc_items( if !blanket_impl.is_empty() { write!( w, - "\ -

    \ - Blanket Implementations\ - \ -

    \ -
    \ - " + "

    \ + Blanket Implementations\ + \ +

    \ +
    " ); render_impls(cx, w, &blanket_impl, containing_item, cache); write!(w, "
    "); @@ -3469,7 +3466,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String { if out.is_empty() { out.push_str(&format!( "

    Notable traits for {}

    \ - ", + ", impl_.for_.print() )); trait_.push_str(&impl_.for_.print().to_string()); @@ -3685,7 +3682,7 @@ fn render_impl( } else if show_def_docs { // In case the item isn't documented, // provide short documentation from the trait. - document_short(w, cx, it, link, "", is_hidden); + document_short(w, it, link, "", is_hidden); } } } else { @@ -3697,7 +3694,7 @@ fn render_impl( } else { document_stability(w, cx, item, is_hidden); if show_def_docs { - document_short(w, cx, item, link, "", is_hidden); + document_short(w, item, link, "", is_hidden); } } } @@ -3905,8 +3902,8 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca write!( buffer, "
    \ -

    Version {}

    \ -
    ", +

    Version {}

    \ +
    ", Escape(version) ); } @@ -4181,7 +4178,7 @@ fn sidebar_struct(buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) { if let doctree::Plain = s.struct_type { sidebar.push_str(&format!( "Fields\ -
    {}
    ", +
    {}
    ", fields )); } @@ -4308,8 +4305,8 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { res.sort(); sidebar.push_str(&format!( "\ - Implementations on Foreign Types
    {}
    ", + Implementations on Foreign Types\ +
    {}
    ", res.into_iter() .map(|(name, id)| format!("{}", id, Escape(&name))) .collect::>() diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index aaa73b100c..02a7362bb3 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -52,7 +52,7 @@ impl<'a> DocFolder for SourceCollector<'a> { Err(e) => { println!( "warning: source code was requested to be rendered, \ - but processing `{}` had an error: {}", + but processing `{}` had an error: {}", item.source.filename, e ); println!(" skipping rendering of source code"); diff --git a/src/librustdoc/html/static/favicon-16x16.png b/src/librustdoc/html/static/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..7cfe6c13550d31bc31355616bbb9cb77fd1b25ef GIT binary patch literal 2214 zcmai0eOwb|96wBnh5{uNA5FX#8j9O(4yl)LyARcIVNxmKrUYOD%pfJyWON=)B<95>De^Rm5G6M}j3YLqKtM+@IBeEw z^+wbz;o5ak@SEL6xUikVXe8WJEFP9pGywO3uTmwxha}|Wr z9u|-rLXDJ)G2t{3kpl`W;YO%bBuJ+P21kd?(GxW6gW)vnCxqExX54RUQWHS;@lhhf zJ|gVd``1Y^@=zFJJK>(g3hajVzz_h_1Q{78U@+bBlQht;p6z!frXHv{LPhwYz<<`72lXv!(d1nyYeRki} zG-TB$r};*eD+wIao;8*Q1z1lX*pMIAo8KMMp3kpQSfT>9<7X{yl)7mmZ&HHTmt$V^;c~|?Lwt01Kia(Ww7QAk1 z37VI_XzHZ4&TD(hrV_xFzrp5h zIDA-gJMuv0N4O`)y}GEDLzI5DRqcQGw4eZ{gx8^nswsmyuR8`H8qrt&We_mQ?E71KoB@x@ws?}G)`?crAQn;UN4 z6pH^kmG!J);&{3;dAl$;_(V^Szpt%NFJJz= zy0-T8z<~J6?w>4P{r&x!3m1l6=;+9(f6gXZaCUdB?(m(=>C3y+SzUDzf4JRP!@oM< Yn%3fx65vtoO=gysTc){dn_8A;mgY3Mwv7J;8=I#3|L3_2=X>9CzO#MjlI-o}Hd}k4HUfc| zO?4;xz;Be|o}mdpp_rIq1VX(S^!1nc(>w`mA>W+E5rzWha=r-05eTA#T*P9B0}@my z5C#fJ=%K5nXcWjHq5Z6AIGV@>;DPQjVt^jw<;#uoG@8VBUyC+h;}WB70)unGigVUEN8lP&?d-=HgyFX$qkP$GnQLeX>ppKUP> zf1wDc@9QdZmgs9_8ts46`TWnqfFzVCI1wL{`k7CEZvgp5ivX+-012gHHb9921d^r7 zOepd~@CM~Tgg+VN0|E%nE(yIF|1U7$8=#9YLMW!gO$Ct97D^pO<_J_iD-7@hITGHq ztxxNofFSJOfWor~siL$D0SL!3wZBrw{}V<++u-4*QWRVX1$-5nt^+~o9ZkrAom;Kc z`UFv3T)f3XE*Jr0kdK=)ib`>@wy?9d#^BAT0)dN0fOSD`G?^uVS$G^Chr!ukEO5RS zHUvvN0cQn^1l*KAN;Z5JI4lY4|M3+ajUvJtG#bGjgd{?7v~p>x&FMholr$wqfXegak(Iz&S(^TbignHAV!(e zSYp&_3zQ<56`$+McmQno+fiaa`iNDWy}z9#V!sH3s3iR3u)=y%Yw!?&rwMj?oWR2L zKmr8t6cWSZCPU1#K_FBTLAXF)6b6AXO_8QFtRka%~Izh4ror z*EZ_|=QE<;c-&c(KbCDA2%Is!@H+g)rZQ&0D#{5Cz@kMoLfJM}sdZNl#oCX>4%v0a znisL7DOS0$j+g^6mUBlNs`}n%hY?$wJRPq86v`{7)93jX?p_lVRnlJ&&afZLZ#&hz zO*L;r_Yz7At=pnIS&x1(ID65shfw2gS^Mv+f$LH_YO+OYq_KaMk=!7=N$s8 zYVb^P@k%r7@*~gE_dVG>kS=f8ngJ&BpPbVtC(o&BusyzO&arf-3>V3FCjyziw}vL} z9Oh8PdKp&CrT}9PWUANt^pi0gLS2UocM;D-O-_!s-5S<7^r8#bN(^WZTqFPeacoP0 zy)NeEyBWEQyN`L_-b6@Dk~P_QYzX;bVSD#L!3h)D<2bbqiwl3s9^aQ+(V3xBlAVY} z((ZcO3=N+xYIsemXzw|b7b4Ro^u(3l)Me_0bv4ljj>4afnIiW92!WV2PjRatG7sv* zpP6bZ*~!;`Yi0U6&-pUA8W*JpZr^s@LEElz(fOFOSxl}IQgcO)DY)q9iK>b%>u&__ zvRF9OMNB(k`N6GOoqZPEZY5um`P|9V%DR}L>-`rGr4p1@kcTSTc%3vbz{xP`*qS+< zRl?zRy}OoBI<{=+M)PZfMxH~$tT?`djmk)EW4fNbO1!E#X-UWeTiuEXf-vFTtUuHS z%c>{aPOG#ca`;4~smG4gTVB7OEBF6ZZRp{SU~?`nB*f81&>>G@IbC>r8?!JFg9}h z32oc#$D||Zkr31zZ$H2E5}cLQ$@}*M)^!a&yv*?R?TI>OXd04|dAgFp%d+PC2!;8l zk|J<;{INS(HnDoo>swFLhh7Tjp3`(h%_%E5>*@Eb%#s#0aLuc*=6Z?Q$bk9d*ai8|Oy~^8zMPyKV`^t-=c~-|`ud_RhdcWd7D=8|%sj<> zA7A=zVZ6Jv>@X*rAYDtLP#zQjJCTOAsM><&`NGa(hEys=@*n4N#$HYUv+miL+Q_QJePvpR)YMcigQ0iSd;4*>-39u=C2}WQ!>F$6s;U`Vok8)> zNF&uFB_#(}ht)T>wN-X>bZBR7R4>U&`(V;9b#d9Esik%3RtbL3Y$H1{`GS946ZEnj z)7IL0;h&yB z^p~mghPtj97>Q&~mJ1n?k&&4}bb4yGLqc9k%6GjzJw+4wiJI<(-Hv-%0sGtYHon}` z(C0xfVU=q#n9SUQ0v{5Iw72I~7NR3A6DYM+KY^*`<- zHk2kfhb5Je4BJD-A+*@(Gwzg%9mTv3ayQk{wy-2a6X6N$1FCQN-$_u`h zo18qe^Qvs!8RogQw9RQ1N3ymRCRN~cdV70oENMpeakk-FFJ8RhWafCb46iJ+^&ad^ zbP5f6i)%}2YFfYXikJcbK!CyS>ZjW3s>QKmc`-3D9aXiWUpTLR8`n#Y>~Ar~&P}d! zh#PM#ivK`>$!Te6A(`0*94>bo)K}kh|2~z)S^~G|Br#^#G~juD(&ERuvQ~k5((c6I z$LnlbhQ{cDfgV)q%*x8jil>pTZf*vKhCL51h1b>9$tRdzq4z!*>5mR~sTq8qYG(R0 z^v`Ab#-mp!`BolVW9>Fmp7j>C(^~?|`pkkF0tfqmbA6Ml6`Ne%l@YX&ivPz{iWfQ0 IIpoLx0#^I3DgXcg literal 0 HcmV?d00001 diff --git a/src/librustdoc/html/static/favicon.ico b/src/librustdoc/html/static/favicon.ico deleted file mode 100644 index b8ad23769ac8d06eb5973bfb3d2acbf385240f98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23229 zcmeHvc|28H|Nn80c^;Zf$(*SSWu`JD(V;RG>6p@BE^{)JxkzQmP>~SI(4dfxF(slB z5)PR%L}d!)x0ZYM{hrRHTlcx&;g8>bJ@5Nj>$5(?d#%0p+H0?)2Zf?QQKG7KHQB}0m;J^5csADJ;Ux=>OHY2a((G>5y2ee}sw(wi6T`3%ZKV`TrFyPF# zt&A6CYgvuX>mI3Y4iczsT`%x-^H<4K|4iTE5A( zW;pTj)bS=iyy&B$FLZTz6sqXlO(QRPaGH6uCn|hQsGKO}S@_hL9R`fA>g_4(3L74) z=Mhj5{S+k^;9h$yrFNWoZS_9MkBle@w7uv}e0VO(;)O~BN_s=I~%uGO3%LKPp+NC_VOjyiikz7Wk2r6 z?y}oVo2#KHaFYG54CD?V{U0f#D6deJ(I;O>8=(|PlNQygb8S{K1o10}pnz1B`0*i@@Sg+EVqi&Sp>fWfI-G0X^^q3yS z7IcPUOtbmMGonZH6ft-&(L(KE8mn4Qj0<&B11j?I=GmZA?qTQH-`$art_&Zcb9PQo zG0QgY8$X9r!P{{pK4q7mw;k*Tp%SM}MKtFE!;oThbJs zORbMuJC$t^=d_P``$YQNa31F8=u<4JeOjkJXsPq;bqM%)JjBVO(}HWxT)Rh0-c{gn z)s)>SmgjB)Iwm;tBNMrrXVw+p@v^sZ)Ft3>#T*Zt!bf;^-!%`}l4o64g0Xbh#d+fl z2nP4|PddH*ek-}Q0c%SyjhRbgaoiL|-QXf1VQPD@dt&7L({KlR{m6%oT=&oTJT&!_ zqpV87@R;29lTpQt3>x!spW?3)0~*VR#*xSQUCx*uV3n7fe$wEeA0}3G+4S6;(^0D` zr{_vBu6S!+@gUJay@HLKba{5S=}%;PZa=_?b>+@?bQjTpYVa zQxR2AD(!hy-&dB4S(rSj(hw07+1Qn;gE+|6Q9Y^juK`zGqWNJ z&Q^uw#K`wwZkX?3cAhLei_KHfQec)?Md3f{;wR~`UEqSt`N6B!Z$F8RW=ANwbDs~r z9d73)pocEO%%8w_5 zINB&w?%vVRYAXt;d^GeG+pC5*!RrJ@hx!kH$F8pGV2z6vMI}+Zz_j=_-}Y+vtS&s} z5|Sj{l*eyb>EY=7MEUIjOLt4X%i(4Zwzi+15&oh&Zcf-w$S^4hp$&C86_Mf=*|U$( zg6BxUoJ6;lRep1(I5?gif4^i<%cSZI%@n2jY3*T?dR6_aLsP3t;xP9qL_)4Q7NmUT zcfxqwt`PIF=Bo%l$u%>U&`urbD>LB5sS^7%t=R;#T|An@F=Ap88RN*@G=hfA|#>lbNTDBHD3Z^a}2)@(uJa2 z1pM(erS6|p2vxGNB0;N$`3hoF6)o{1iLdGkMO*LEi99`+`Le6t^4^89vUuyuAG2;OiPC>^h?*>zPN>H#OS^pWzyR5Y+sBDTF%C4V`Te#=bIs?Ji;C($TzLB zoV=gS1zsem65Qvnqh35J5}$C!@)TapH(NXLpNt+qG-;`Hktse>dlxMq9cF$-B8Xe& zVGUO0*$ws!w|MAyP`Tlwj`LhewJltkeOhnInQ2D%Y&(7$FWx=6PgzY4c4Hc49@koR zlAxG3%O`waMu66LeJCb#??>w=3qH-y;(~mSFjMrEDcj?8xVi0j1ehM^HTI8CyY`Hy z%)Q=)uJ{GNrTERxgQ#||W*xn3|0?#VASWgZi#;56egl`+`_-=S&~2%OiFZxTehUO(tOY$aNH^|NWHbP;A^jVcUNCvoA-d}y$1dY zzHxp1_nEv51-mYPH7mO(fSI%`xAu1u&u=IbO~;f3O?~}TD9h4*#$welW;aVU6<)@2 zvg?k#QIaO5_M?49caCmK&J65$G=$lFSFOiYfZIyKoi8i(>o(k@T!}O8*ldOLwf5r) z&-LCj3bV;e7iC`2+<9GWx95HR&;;ycXuaC~o105|Jm#45W-0HN9QZ&j@Fr70PPOmG zrqJa@< z2HvsFF=t{30z9;=;SiP3`fQ(GM;He3cdL*W=p06eca&dD5apWqHHu+8Yg}j^}?nbJe$b zK`eWZ=x3#ociv6U$Fm=DSbFG5?lnFh9@3jjJ1^*x$?>ow{A6L+&PPLbX2o4;H`7^+ z`&i@mcBJRVRnbb4(06r}@^2TtBk29}|sh_~cUeIQofh+od5^Y_A?ZI&k_# zZhC5qH%04)W1SE3gJN~vrG+8+uf0m|H`Szq*Ba&0W$ zK63L-sne||uRCfq$WHUC?|jert;(lYWxEd#UHWGR+@_38SHe}9n_|7gxOduJ;P|Rh zQ<#I&TX{sEM)qp((-Bsy3+`5LJ~OG+eXvSPj^Lmugi7S)8^wE!bYXx!-G;a z*63s5t^zq$;azq88_ljh*WVCI`<0zJJ+Z(_bK1qo%*o(c%leIIk1#5H;6696yBAbW zROWQDBws4J5^}|w30EYfK>f5KFZLKSN;J4EAu`SSa>F&HFOAM8mAn0}X3kr9Dp>nT zD+DWQ)#}Y_>*p7xZW+A9!|r9yC*P8w4qgxkCB+pyQVaC4wg!@V*gfA_^tP!m9dC%n zUCb+%quVTGQ;p5;pu_4lRJv)Zh8|JfMH#1iq|(xIvN&DAbnUwVt+iFwi9HX{ijuv0 zhou%yNg9=owzZ`XWIkbHT=BVThvq)}5>PCS;2r!RFF%H|Jg7hv3x%Vv*DHT} zUHu?1Fi^3*aNesqHa~o1Ab+B|KrB$A=h5!fLB$6z$(^jsS^H{;5oI|koHuJMdBd5# zCRE*YO|a4#j>`cb9@I?MYU5i}g2#NCTf#eQ+rY$MpA`Ej($udZ=X<6OPwZj48nODvHWt_U=_#x2<5Vbm+aSf_Jk@ z{`J$9H?7m&GLm zE_%10XB50$&w|SwOPe`~RoPByW!2Nbl~^XxLs+mhE8V-oTr_vfaavD?9BV(1ql1+N zLVlVfs1=)I4p1xdm-{W~577B^?aEa#d=fI~ET|r>x6@zioncM*3N`f1x;LRVxBh98sF}~*6f|XRp|$CVXg5b$ta6odify782stoPy)kjV{wsceTYVk& zr4nAsEbUWTTu~fqgR6iqX243q=z77~cpZ*Mr#hb1Q?5%4%Mr4`aIw zzt`d4VtbP;-Dev^v9=8Qsm_^b2Zug&{p0d+RVvL^G++1k91J(kXKhs$FLrH8)4n%i zgc&xuoLe1Uy4u&w_-2v{%gi-XKjn&y8~Jypbi4K&SmziY+tXm){ld)a$rnQc);-H* z^$0`O#fPmMJdfu_So1Qx#KE(A0uj;zQY#%n}T%5Y*^Z4le<^p;`!}&Xk`0^ zoo9Dv8EO;uqiXNA=*qD?pgDK1N2^9LhR*8C5w46d1;YYPg^Rc@@W?YbMATDRZfwt@ zJw-DTBY)00gHR^@=^^b*=%#aawyRuLiL|ff+}F1AfM$j)N6}gCHC`8ejImcJ?|;s| zIkCUeaL$E5i@PVwc&t(w&%e!P>cFL&b(`oT&E|dfNbGeJo!T_JYkyk>*8r>6c<-brx&Z+8#s2NR7~kKJ{HeuIe8^Fb`$gN^?B$L zpXQRtEJ@WJo;4>D>7VL0RZN!-d8%|625X)bemwG30#Ajv%}Z2?)_Ttx{Ap9Z?>?o+ znqe~q`115EYhFh+zn8sa;<{GAS#|ave!u198G+=~ROz)fFL~m77;$ujM?=k1el6SCab~{;X6L@krdJ2VWrtk4_ z8uTt>v`Fbwbz@;|kI&ipuCvixAAOrE726ae#JqbdyYiWEOV{~xx@LEe#^&yE`&Qtm z6t0;ZmSUZBu|0WellM?@{6^&%O>u|3+=q2Mxhz-Lc-rJ@dNpfXy359S&SuZwm#Wz* z{JPDM$3BGhqxgEw-dS-RCQn%@T*Ip;6FjWQ4`rMnPQhF0~*~*If`S%=C238dNibP{LQBgiHBP%ym?vk zW~WtSDR15K_?)i&SwzHWe50j%!MU;r->=-13k|`#3B=<#@}li-ispMn6?W8k^e$BB zSPeufJkfgW(QwR&LJ~7CNcZNG&3a$|_gKm53e9~I>w8qIDD}6CNEG=rYuM>*zc3WS z(T18)&o_vfJVda{OO&|qI-K!5wp~Fgsrp9mtsYgaO9aO~N7>ScR+bJ4TDl+9e=u6l zwX3Z${A^CaH=*9qNbuh5WV|>m+}tr@Upf?w-?lkPM$GaOdruJKHAQ)Cv-2%^+ty+jx)D8lvH$C53ab(BT(Bok5&{vR#};~-ytXd z>juN8y7%QBc;m2lE(lHIEThn;*k%tOl@-=6zdLjDpygpD7<{Q;^IW^>GZF>o!UF@7@v6jp(-<9 zZmmSR*rooeci9O+ZcWdgquMud4EK69x8&38ssgJ&w=t(Vey&$VhyvCOx{Z&!wmE_KL&i6bd2gJbEt`s<12KxdkG4^=|v8e;P=9 zdjLI?!l6_heuA;)xWF)&xdp97%5BMK1e4NJxs7>*l)b=$nrYP7u%mmMWKC97YX4z< zvynBTZkt`W$K!D?hFWE3Me`@v+EIjlwkM%|y1&ji*OqB;IZ=-OOAguaQ`PFWJ^h zGdG%vhKoQ!*b=CxthDum+YETs*9SVI=S0OD^Ve|lSg#PFdiz4NRU&}Tr+MzeJB!Pj z0Z$L0UkGhz9N+L#nKFRmVPFqO^aT4cpXMs7F5~1-uOwXSbAe%pu)f>HOj$9Pk0kTc z1uJW{mgfqj6?F5`>$*2zKl>tWyd%7VMx}n2W2>o79b2iv&&(#` zxf)~qVR{o~>5#<4bpD5L342#uV1JmUP$h$RqH1nFf2FI%acliZ$YlAuUJqK)LQa?c z6!$mT4k);DH&P|9nzi2WS>%8P^8>~~mDoY2ikt@grtsOzHv;N<1YF+N&V?v4ygKQa zb@k$~{56JFl%kvgmA8?CeEHoVu3}W4kA#a|hsOzU>3a3{j<+wm^eRW?+w%(d{JKSE(kx^NH6M!5)n~ge|);7U{jM^piaeO77TbB zML9p&dHsMn9lbLq;rNKQUp9l9W(+e0K}(+cRK(MXY2^V-i*<_sebf30>fCz%{dDw4 zqYVw;qzW`_@RZP2)_Uh@E>D#qln{KQdjI*Nv_0$@>D4(KTm(#UG+}OXPB_9g-0-^A zX4Y*n4Y48lN+!LZ-bh5cga{d3$W(qVr*4XieILjWK|gqOebji0#nys|k2Jz7x$5+c z!`oS|&Ai@6v%8TyGu05AKBKzon2lf7iR?tpcLqw_-jM;A(xchD`$Y?xrI{00-i;X_ z+*p3U3>^K@SVZ+bl}P+xx!IF1+i%aPmPh#stGXU0oPC~;j@F!n)$A2>t7pyTm|HYE z`>mf+8q^iLHG#(~R;Kz=^Lh%j}}(Fzh^UYmm!OdbCT5DKve=lQr+zjA_tuoJ#q$ck|cOD5-#? zf_XMOw~MCr+3L)%N5H33Wdh})mCvjDwd(q^Y<%;4e78+aP-1&`67FzDFk5$xs^QD< za}jrQFi9aU)A~l)#Z4g`J8wUZU0FN8h)X->r+J>~t%A*`riAP%)2s&0YrX2miQsu^ z&N^&&ZR=;DYh&8?uP4*FT;^e&H4(e?HKg_IXStTu^&wc>>f&=*=L^{hm!4iQ>kf;zMrNgr8hFGc6zg zu^KHZc=a{b7TvF}eIjaa=~1>WZ-F68k6m@*RIg>i)Vh^>j2E=#)GlmJuH8@7+BB-g z#AGns3%-Edx#BLR(?-lRFkElvv9_jgSM4@FxYKLw8{5@s%?QH!&>h7xO83^OELt4n z5vXch9Wz@L)^&4rydVchPf6Ou-3w7o11oGB4q3N$RwI^n_9LZ=)qa51)O53^D$t^6+GDQy+`lMrp$-OknTlY^0Xe-(mz5Kwm zhP$jsD^A3Ge(#C{at>VK%oO9J`4O+<@+bXwhkmZJ+I>eb7VC_^t}$^`6iXFh;Wfw= zIv8QslCL`SLOrW%?cVSdMID?MH%h$SXIhorg^vZ&mXq93e;Kac)z%I zJZmZvUv4=WBH#CzhUZ}Zkvxi=D&5)@+YCm)9F!`M?vYK1ye0A|kSXTnp(Jm%8BUiN zQzExG=UpKuTH10_hE5i821mrs54z!X;u_#DwV@hx+_ny%1WqJWf1+byz24y zl0jR4ZH|!OIV+_qU#sR33Cqd(LhcXroQah4YUOIDTR#r+n&CS=v(yu(1iJ@BvAs@` zyPr-K0CwOIp%}i3zZ75Q-cpiqVUW{zJ{U^-gr@S zgS8=Q8IIBe3A86KdA?ZfT-kGZRh*-R0pn$YV`eJ{_w~-`n^q^1ZIxo|3)Vk(vSEF- z)(_>y79`Nu6m&IF3|nn;=c}2bD0V$EY{p#hl@y(cLe2DjtX}Lh{Nq}>_s`lMqR6!JuS~ymb8Nr(qY+kJG)1OO z_w!-zW)7K@mY0>7?W|iWWv5Rvv}2UkB*a~NS9oK;v4C0$3!6yu3!7t8l@IA=iad5U zVQtx6c0KJsw?e(oc=epQQcQ}B?o*G7N``>u&)GJYwDZClg+xZC)>f)0t1|@ZNz1&$ z7JiV+$#*_8jw@k#G{jdrxh!C`}G(teoo)wb8ITM&z@?Eja?1D zF*anpD&|yHYrJM%4Zrdi)%;M?jx}Z+bywdUv!FP+Zl1a1;{3bv>wTABKib61RzDWF zE2Lp%D9^DilFiv}Gu@3J)bo_7RJN-KZ+m#3V<-muSXnFcP7_1E=0u5a^W%G#NH-F}IW^_V?$=shKfneNqg`gZGSMV)fkvi}md-|&b%!&+(cW=D2 zvYZ^Ca~u&%v}<8jjB#!K+Ihrs^C!dFaEsHt{bN=B=uk#~@Wnr7qm+8lWj}4wVW}+T*IFwToOa((RZ6#ujC{raUjyhW%vozZdX%~68vcU`qq>}lN@ ztvM~7qt?#}jF(V4ZeqOd8pi0=OohMUxZxXTtBS>#(J6WtyHNAnQ`s$|`Br0%{Vp4L zFN`_t(0R|=_LX9+v$U9{y(%dwf4=GNivnp;i%4Nf)JW8ga;}~xoVg}-qLLPKa;vbU$o-m8#NZq%(d6gw_%iS&MCW+adJzOes)PhzV!r#Fx-9pcpyi~ zwpGW|FSPS>am|JwVs2_|)OgRz#3Z$8`C`QaP4%%yslo?z9)Ta`QM%e#t=k&7p!J{( ze(^`)0N~I1%Uuf#3#k8(|NSvo?*9Cao{vw^2|yk30p)yv0+PBqv_b0si6oyh|0EXR zq6Q!UeSus7Fb6ONpaftHut0=paft6K=}Qql9d<}#uogQ{``~i2eHo(Id=h>MJ)fP+@U{= z1!KbUng2%q0mK~t2Iu8s1pJ%)0bhRrI6lV!ZUHQpcOJA=0GtAV^FRuKj|f;c0Pq7S z2Y|NA#mNJ0Fc-|}zg%B_b^Z|JkmpJPdP{(Q0N54{ux7bjFyKT8VhNO}HhCd~U)3rn__`ZVoM*e61qLp42fNp3Bd&o@*+9A9V33Z^&1c03XU-mYC#~+D_ND#9I02$|{WEW_sfEgHRQ`|1(vj7h!vpc z1|Ypxkee}VMtCC<>Oh+^06G5=pgRNb=l99a_#^R_k{|{t7t(SWXrqA~;04OE0OC9PpX>%lnIH3(wF<&!IGk`inph--+vB{bxLgZR?;d2?U7xPN4fspGkCZe+S<| z(8i0H+l8bZa$A9LfH4t39lSvMK@$6EP;Mfr|19@^+6Lzf6_LYJVovh@{<&5myb($C z699hX^X)(7^{f6@AqRK?4yHu@ zUTToDe2Kh}%kO-@|Lpt(p3}g8MEc7Yd0&@ugfRgM0hYUWzjJ;9&qz)K1OO~`u2c;4 zY)kR@Cpr)duA3zQiiJq=>gCpwIwZsHY$MQ0A{3m@-k@G z0U!X7bBA>Ya(kryEB6%If*5}}2O`S_-|=!tT%r#K=x&hM1(CKBZDc_^^j(TKqWd?_ zZ~Z|I*oVJ6KYs>nJOMTXBmqDU@Jtz*7m=W>2mozf03aO6WgcjQxnNFz@_r-rUmbtM zo;YT3E|TY4u3ka(f%l^OH~a!fb1ql@hy2eFd2|8!ck}8!uz_p2Fu)|ha{YvQ7z@UP z<^Rs#j|4${xVBOPz<1owIKejfJInW9uww-_FeZ%s!#eYCjz4)UkgE>>?nw>;knUUI z9vuSdA9>xE=mUNK$9_LufJ)sgue+W!+kMqn*;bi@%!}> z{ej;=|0{n#K>j@c|N4J@8~rzr1q=_r!-(>`{~z^!`$hR3N9_;WzoSr#l7K?dz&awY zv5Zr}I(p0eRwzUKzjp&UkM{q*bqkOv|L-U$Sr!(?q2yawm;rJeg_=Qu9WjvOP|iTf zwB!Z)_@ZU!aNH>70B^<7Q8C7pJxex5l#*A^0xcqC z7yt!80uitbbqc>62pEEqTEyS^fVhkRuK?hlG!p=>zeNDZJMcbH2iu?xv}OFexPO-) z#DM4Z767UM$eRDF68b=2`2W(gA+`qy$#2z_ggfU>OFmfJ0$q((3IPjjreM~<9jywi=9oQTPfct3p z-H7b5VXOplTk`zC2HtNt=A`|G=Tx=;@EyPS8zp%h(mJq#&&L>m0|5LML;3+@!q|V# zhb8jE`GVL(3HPUPEb0Irk>**h4D4XPs{vr&VLr&4G^PdOOPU|pz-J83S<<<7AF=s6 z31cp01L7giCgcEP!yJpxCSnhLfet>iq&$DAjKl!G`~dJ=`d9p3k@6+xhwH|#`2Jvn zeA?w|~x_djzZdPI`8!7|j7UO-0! z@R{5W)J*`^0+6l?NS-i~_!PhfuIEVGCL}(zA<-|k6LoM+fLIN1iQER%`;i!+Y){q> zb5W4wCtYt~4sOJEsr+QI5YFV%6^Q}tc>&DH{1V9WlRkH=5Z`~8AD)+y|LzIDc}Y2v z<|iNjE5KG1a`=b&VIEJU51_09kPm?5Cm(;(`8NRUt^s@_86U)NQ9?cG1#H=u;z{EF z71%@ri~u09Navpd(8Ff}ww(olB>t2F&&6^G9scA-2r{ z*+MMCXKI>Q{(-}<=!l#cfbB_uSgCEq_po(Dkt54n&z@Vk;2j|apfki|T(I4IyhNKB*- z?3UVpbOHTF#O7Be@Yw(WeUbj)LHVcq4c*8VgbOH+8-Av z!}$i!d}aWU+))1Q{);5Wa{JG55a%L*9st}|z_V32Zy}Ez05Jfh&p6Br`wjc^%ll6f z9+AKg##nAnN`N*^q77+ZNqv5M|4ot~&IbzsIA_V@!+JXa=^m5R2KqqXKlhtRTtt%3 zKSWP1K@9k8!f}Rc6!I(=fif~Kuncp;xV}QbGStccU`$d0ZOi~S z07&O5eCI)s>YxoXi7UMK&=>g)AHEw;1Bd{iiGXFOL-wN3_RkogjO2yS4L@mY(lTrV zfHsiN4cG=G>@UI(?zOLxK@`+E0pNUuZKV5gWULVXrQ}xN1J|#m+K_REZN30-eMRgV zKp6+H8sIfi51&g907qiI3rKi>riguk`)0%+t{;%^0}>q`+QAFxrU0NX#8;w@)E|jM zDi1F@|KShc9ncqYfHuMar2fUAz77EX22uh5ZRP=>4%)&x^i3p|n}Mt%mSG$G=4%9i zYYws=LA?|}AOI{wU()*rb<1G}v;_e`KFB;;oX?3rfVPYC zhd6Ge^LGNY1ptVUj1}xJ + + + + diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 462a696dee..1b3eb2011a 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -92,6 +92,7 @@ function defocusSearchBar() { var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") === "true"; var search_input = getSearchInput(); var searchTimeout = null; + var toggleAllDocsId = "toggle-all-docs"; // On the search screen, so you remain on the last tab you opened. // @@ -344,6 +345,7 @@ function defocusSearchBar() { } function getHelpElement() { + buildHelperPopup(); return document.getElementById("help"); } @@ -1396,8 +1398,8 @@ function defocusSearchBar() { // "current" is used to know which tab we're looking into. var current = 0; onEachLazy(document.getElementById("results").childNodes, function(e) { - onEachLazy(e.getElementsByClassName("highlighted"), function(e) { - actives[current].push(e); + onEachLazy(e.getElementsByClassName("highlighted"), function(h_e) { + actives[current].push(h_e); }); current += 1; }); @@ -1576,14 +1578,21 @@ function defocusSearchBar() { } function showResults(results) { - if (results.others.length === 1 && - getCurrentValue("rustdoc-go-to-only-result") === "true") { + var search = getSearchElement(); + if (results.others.length === 1 + && getCurrentValue("rustdoc-go-to-only-result") === "true" + // By default, the search DOM element is "empty" (meaning it has no children not + // text content). Once a search has been run, it won't be empty, even if you press + // ESC or empty the search input (which also "cancels" the search). + && (!search.firstChild || search.firstChild.innerText !== getSearchLoadingText())) + { var elem = document.createElement("a"); elem.href = results.others[0].href; elem.style.display = "none"; // For firefox, we need the element to be in the DOM so it can be clicked. document.body.appendChild(elem); elem.click(); + return; } var query = getQuery(search_input.value); @@ -1602,7 +1611,6 @@ function defocusSearchBar() { "
    " + ret_others[0] + ret_in_args[0] + ret_returned[0] + "
    "; - var search = getSearchElement(); search.innerHTML = output; showSearchResults(search); var tds = search.getElementsByTagName("td"); @@ -2114,7 +2122,7 @@ function defocusSearchBar() { } function toggleAllDocs(pageId, fromAutoCollapse) { - var innerToggle = document.getElementById("toggle-all-docs"); + var innerToggle = document.getElementById(toggleAllDocsId); if (!innerToggle) { return; } @@ -2307,11 +2315,6 @@ function defocusSearchBar() { } } - var toggles = document.getElementById("toggle-all-docs"); - if (toggles) { - toggles.onclick = toggleAllDocs; - } - function insertAfter(newNode, referenceNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } @@ -2361,6 +2364,11 @@ function defocusSearchBar() { } (function() { + var toggles = document.getElementById(toggleAllDocsId); + if (toggles) { + toggles.onclick = toggleAllDocs; + } + var toggle = createSimpleToggle(false); var hideMethodDocs = getCurrentValue("rustdoc-auto-hide-method-docs") === "true"; var hideImplementors = getCurrentValue("rustdoc-auto-collapse-implementors") !== "false"; @@ -2679,6 +2687,10 @@ function defocusSearchBar() { } } + function getSearchLoadingText() { + return "Loading search results..."; + } + if (search_input) { search_input.onfocus = function() { putBackSearch(this); @@ -2688,7 +2700,7 @@ function defocusSearchBar() { var params = getQueryStringParams(); if (params && params.search) { var search = getSearchElement(); - search.innerHTML = "

    Loading search results...

    "; + search.innerHTML = "

    " + getSearchLoadingText() + "

    "; showSearchResults(search); } @@ -2728,10 +2740,17 @@ function defocusSearchBar() { }); } + function enableSearchInput() { + if (search_input) { + search_input.removeAttribute('disabled'); + } + } + window.addSearchOptions = function(crates) { var elem = document.getElementById("crate-search"); if (!elem) { + enableSearchInput(); return; } var crates_text = []; @@ -2769,10 +2788,7 @@ function defocusSearchBar() { elem.value = savedCrate; } } - - if (search_input) { - search_input.removeAttribute('disabled'); - } + enableSearchInput(); }; function buildHelperPopup() { @@ -2797,8 +2813,8 @@ function defocusSearchBar() { var infos = [ "Prefix searches with a type followed by a colon (e.g., fn:) to \ - restrict the search to a given type.", - "Accepted types are: fn, mod, struct, \ + restrict the search to a given item kind.", + "Accepted kinds are: fn, mod, struct, \ enum, trait, type, macro, \ and const.", "Search functions by type signature (e.g., vec -> usize or \ @@ -2818,12 +2834,12 @@ function defocusSearchBar() { popup.appendChild(container); insertAfter(popup, getSearchElement()); + // So that it's only built once and then it'll do nothing when called! + buildHelperPopup = function() {}; } onHashChange(null); window.onhashchange = onHashChange; - - buildHelperPopup(); }()); // This is required in firefox. Explanations: when going back in the history, firefox doesn't re-run diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 346ceacc92..935b96e51f 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -126,6 +126,10 @@ h1, h2, h3, h4, font-family: "Fira Sans", sans-serif; } +.content ul.crate a.crate { + font: 16px/1.6 "Fira Sans"; +} + ol, ul { padding-left: 25px; } @@ -1290,7 +1294,7 @@ h4 > .notable-traits { #theme-choices > button { border: none; width: 100%; - padding: 4px; + padding: 4px 8px; text-align: center; background: rgba(0,0,0,0); } diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index 6e8db1e9eb..3b15b21889 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -129,9 +129,10 @@ pre { color: #ffb44c; } -.line-numbers span { color: #5c6773ab; } +.line-numbers span { color: #5c6773; } .line-numbers .line-highlighted { - background-color: rgba(255, 236, 164, 0.06) !important; + color: #708090; + background-color: rgba(255, 236, 164, 0.06); padding-right: 4px; border-right: 1px solid #ffb44c; } @@ -495,6 +496,7 @@ kbd { #theme-picker, #settings-menu, .help-button { border-color: #5c6773; background-color: #0f1419; + color: #fff; } #theme-picker > img, #settings-menu > img { @@ -513,11 +515,11 @@ kbd { } #theme-choices > button:not(:first-child) { - border-top-color: #c5c5c5; + border-top-color: #5c6773; } #theme-choices > button:hover, #theme-choices > button:focus { - background-color: rgba(70, 70, 70, 0.33); + background-color: rgba(110, 110, 110, 0.33); } @media (max-width: 700px) { diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index eeb1f0a3d4..f5a8533776 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -389,6 +389,7 @@ kbd { #theme-picker, #settings-menu, .help-button { border-color: #e0e0e0; background: #f0f0f0; + color: #000; } #theme-picker:hover, #theme-picker:focus, diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 6bd7e53cdf..213c7f3aab 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -53,8 +53,10 @@ pub static LICENSE_MIT: &[u8] = include_bytes!("static/LICENSE-MIT.txt"); /// The contents of `rust-logo.png`, the default icon of the documentation. pub static RUST_LOGO: &[u8] = include_bytes!("static/rust-logo.png"); -/// The contents of `favicon.ico`, the default favicon of the documentation. -pub static RUST_FAVICON: &[u8] = include_bytes!("static/favicon.ico"); +/// The default documentation favicons (SVG and PNG fallbacks) +pub static RUST_FAVICON_SVG: &[u8] = include_bytes!("static/favicon.svg"); +pub static RUST_FAVICON_PNG_16: &[u8] = include_bytes!("static/favicon-16x16.png"); +pub static RUST_FAVICON_PNG_32: &[u8] = include_bytes!("static/favicon-32x32.png"); /// The built-in themes given to every documentation site. pub mod themes { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 6d79924a06..7762e8f8d4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -16,6 +16,16 @@ #[macro_use] extern crate lazy_static; +#[macro_use] +extern crate tracing; + +// N.B. these need `extern crate` even in 2018 edition +// because they're loaded implicitly from the sysroot. +// The reason they're loaded from the sysroot is because +// the rustdoc artifacts aren't stored in rustc's cargo target directory. +// So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates. +// +// Dependencies listed in Cargo.toml do not need `extern crate`. extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; @@ -42,8 +52,6 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; extern crate test as testing; -#[macro_use] -extern crate tracing; use std::default::Default; use std::env; @@ -64,13 +72,13 @@ mod docfs; mod doctree; #[macro_use] mod error; +mod doctest; mod fold; crate mod formats; pub mod html; mod json; mod markdown; mod passes; -mod test; mod theme; mod visit_ast; mod visit_lib; @@ -153,7 +161,7 @@ fn opts() -> Vec { "", "passes", "list of passes to also run, you might want to pass it multiple times; a value of \ - `list` will print available passes", + `list` will print available passes", "PASSES", ) }), @@ -183,7 +191,7 @@ fn opts() -> Vec { "", "html-in-header", "files to include inline in the section of a rendered Markdown file \ - or generated documentation", + or generated documentation", "FILES", ) }), @@ -192,7 +200,7 @@ fn opts() -> Vec { "", "html-before-content", "files to include inline between and the content of a rendered \ - Markdown file or generated documentation", + Markdown file or generated documentation", "FILES", ) }), @@ -201,7 +209,7 @@ fn opts() -> Vec { "", "html-after-content", "files to include inline between the content and of a rendered \ - Markdown file or generated documentation", + Markdown file or generated documentation", "FILES", ) }), @@ -210,7 +218,7 @@ fn opts() -> Vec { "", "markdown-before-content", "files to include inline between and the content of a rendered \ - Markdown file or generated documentation", + Markdown file or generated documentation", "FILES", ) }), @@ -219,7 +227,7 @@ fn opts() -> Vec { "", "markdown-after-content", "files to include inline between the content and of a rendered \ - Markdown file or generated documentation", + Markdown file or generated documentation", "FILES", ) }), @@ -234,8 +242,8 @@ fn opts() -> Vec { "e", "extend-css", "To add some CSS rules with a given file to generate doc with your \ - own theme. However, your theme might break if the rustdoc's generated HTML \ - changes, so be careful!", + own theme. However, your theme might break if the rustdoc's generated HTML \ + changes, so be careful!", "PATH", ) }), @@ -248,7 +256,7 @@ fn opts() -> Vec { "", "playground-url", "URL to send code snippets to, may be reset by --markdown-playground-url \ - or `#![doc(html_playground_url=...)]`", + or `#![doc(html_playground_url=...)]`", "URL", ) }), @@ -281,7 +289,7 @@ fn opts() -> Vec { "", "resource-suffix", "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \ - \"light-suffix.css\"", + \"light-suffix.css\"", "PATH", ) }), @@ -343,7 +351,7 @@ fn opts() -> Vec { "", "static-root-path", "Path string to force loading static files from in output pages. \ - If not set, uses combinations of '../' to reach the documentation root.", + If not set, uses combinations of '../' to reach the documentation root.", "PATH", ) }), @@ -472,11 +480,11 @@ fn run_renderer( } fn main_options(options: config::Options) -> MainResult { - let diag = core::new_handler(options.error_format, None, &options.debugging_options); + let diag = core::new_handler(options.error_format, None, &options.debugging_opts); match (options.should_test, options.markdown_input()) { (true, true) => return wrap_return(&diag, markdown::test(options)), - (true, false) => return test::run(options), + (true, false) => return doctest::run(options), (false, true) => { return wrap_return( &diag, @@ -488,7 +496,7 @@ fn main_options(options: config::Options) -> MainResult { // need to move these items separately because we lose them by the time the closure is called, // but we can't crates the Handler ahead of time because it's not Send - let diag_opts = (options.error_format, options.edition, options.debugging_options.clone()); + let diag_opts = (options.error_format, options.edition, options.debugging_opts.clone()); let show_coverage = options.show_coverage; // First, parse the crate and extract all relevant information. diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 89d184e35c..3a87e1c46a 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -7,10 +7,10 @@ use rustc_span::edition::Edition; use rustc_span::source_map::DUMMY_SP; use crate::config::{Options, RenderOptions}; +use crate::doctest::{Collector, TestOptions}; use crate::html::escape::Escape; use crate::html::markdown; use crate::html::markdown::{find_testable_code, ErrorCodes, IdMap, Markdown, MarkdownWithToc}; -use crate::test::{Collector, TestOptions}; /// Separate any lines at the start of the file that begin with `# ` or `%`. fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index d1f2c12ccd..beb1f13ca6 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,7 +1,6 @@ -use rustc_ast::token; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler}; -use rustc_parse::lexer::StringReader as Lexer; +use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{FileName, InnerSpan}; @@ -28,49 +27,34 @@ struct SyntaxChecker<'a, 'tcx> { impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) { - let buffered_messages = Lrc::new(Lock::new(vec![])); - - let emitter = BufferEmitter { messages: Lrc::clone(&buffered_messages) }; + let buffer = Lrc::new(Lock::new(Buffer::default())); + let emitter = BufferEmitter { buffer: Lrc::clone(&buffer) }; let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let handler = Handler::with_emitter(false, None, Box::new(emitter)); + let source = dox[code_block.code].to_owned(); let sess = ParseSess::with_span_handler(handler, sm); - let source_file = sess.source_map().new_source_file( - FileName::Custom(String::from("doctest")), - dox[code_block.code].to_owned(), - ); - - let validation_status = rustc_driver::catch_fatal_errors(|| { - let mut has_syntax_errors = false; - let mut only_whitespace = true; - // even if there is a syntax error, we need to run the lexer over the whole file - let mut lexer = Lexer::new(&sess, source_file, None); - loop { - match lexer.next_token().kind { - token::Eof => break, - token::Whitespace => (), - token::Unknown(..) => has_syntax_errors = true, - _ => only_whitespace = false, - } - } - if has_syntax_errors { - Some(CodeBlockInvalid::SyntaxError) - } else if only_whitespace { - Some(CodeBlockInvalid::Empty) - } else { - None - } + let is_empty = rustc_driver::catch_fatal_errors(|| { + parse_stream_from_source_str( + FileName::Custom(String::from("doctest")), + source, + &sess, + None, + ) + .is_empty() }) - .unwrap_or(Some(CodeBlockInvalid::SyntaxError)); + .unwrap_or(false); + let buffer = buffer.borrow(); - if let Some(code_block_invalid) = validation_status { + if buffer.has_errors || is_empty { let mut diag = if let Some(sp) = super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs) { - let warning_message = match code_block_invalid { - CodeBlockInvalid::SyntaxError => "could not parse code block as Rust code", - CodeBlockInvalid::Empty => "Rust code block is empty", + let warning_message = if buffer.has_errors { + "could not parse code block as Rust code" + } else { + "Rust code block is empty" }; let mut diag = self.cx.sess().struct_span_warn(sp, warning_message); @@ -102,7 +86,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { }; // FIXME(#67563): Provide more context for these errors by displaying the spans inline. - for message in buffered_messages.borrow().iter() { + for message in buffer.messages.iter() { diag.note(&message); } @@ -125,21 +109,26 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { } } +#[derive(Default)] +struct Buffer { + messages: Vec, + has_errors: bool, +} + struct BufferEmitter { - messages: Lrc>>, + buffer: Lrc>, } impl Emitter for BufferEmitter { fn emit_diagnostic(&mut self, diag: &Diagnostic) { - self.messages.borrow_mut().push(format!("error from rustc: {}", diag.message[0].0)); + let mut buffer = self.buffer.borrow_mut(); + buffer.messages.push(format!("error from rustc: {}", diag.message[0].0)); + if diag.is_error() { + buffer.has_errors = true; + } } fn source_map(&self) -> Option<&Lrc> { None } } - -enum CodeBlockInvalid { - SyntaxError, - Empty, -} diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index bf091a0a62..cf94ea384f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -2,7 +2,6 @@ use rustc_ast as ast; use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::SyntaxExtensionKind; -use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::def::{ DefKind, @@ -12,13 +11,17 @@ use rustc_hir::def::{ use rustc_hir::def_id::DefId; use rustc_middle::ty; use rustc_resolve::ParentScope; -use rustc_session::lint; +use rustc_session::lint::{ + builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}, + Lint, +}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; +use std::borrow::Cow; use std::cell::Cell; use std::ops::Range; @@ -37,28 +40,48 @@ pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass { }; pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { - if !UnstableFeatures::from_environment().is_nightly_build() { - krate - } else { - let mut coll = LinkCollector::new(cx); + let mut coll = LinkCollector::new(cx); + coll.fold_crate(krate) +} - coll.fold_crate(krate) +enum ErrorKind<'a> { + Resolve(Box>), + AnchorFailure(AnchorFailure), +} + +impl<'a> From> for ErrorKind<'a> { + fn from(err: ResolutionFailure<'a>) -> Self { + ErrorKind::Resolve(box err) } } -enum ErrorKind { - ResolutionFailure, - AnchorFailure(AnchorFailure), +#[derive(Debug)] +enum ResolutionFailure<'a> { + /// This resolved, but with the wrong namespace. + /// `Namespace` is the expected namespace (as opposed to the actual). + WrongNamespace(Res, Namespace), + /// The link failed to resolve. `resolution_failure` should look to see if there's + /// a more helpful error that can be given. + NotResolved { module_id: DefId, partial_res: Option, unresolved: Cow<'a, str> }, + /// should not ever happen + NoParentItem, + /// used to communicate that this should be ignored, but shouldn't be reported to the user + Dummy, +} + +impl ResolutionFailure<'a> { + // This resolved fully (not just partially) but is erroneous for some other reason + fn full_res(&self) -> Option { + match self { + Self::WrongNamespace(res, _) => Some(*res), + _ => None, + } + } } enum AnchorFailure { MultipleAnchors, - Primitive, - Variant, - AssocConstant, - AssocType, - Field, - Method, + RustdocAnchorConflict(Res), } struct LinkCollector<'a, 'tcx> { @@ -68,7 +91,7 @@ struct LinkCollector<'a, 'tcx> { /// This is used to store the kind of associated items, /// because `clean` and the disambiguator code expect them to be different. /// See the code for associated items on inherent impls for details. - kind_side_channel: Cell>, + kind_side_channel: Cell>, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { @@ -78,17 +101,28 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn variant_field( &self, - path_str: &str, + path_str: &'path str, current_item: &Option, module_id: DefId, - ) -> Result<(Res, Option), ErrorKind> { + ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; + let no_res = || ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: path_str.into(), + }; + debug!("looking for enum variant {}", path_str); let mut split = path_str.rsplitn(3, "::"); - let variant_field_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; - let variant_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let (variant_field_str, variant_field_name) = split + .next() + .map(|f| (f, Symbol::intern(f))) + .expect("fold_item should ensure link is non-empty"); + let (variant_str, variant_name) = + // we're not sure this is a variant at all, so use the full string + // If there's no second component, the link looks like `[path]`. + // So there's no partial res and we should say the whole link failed to resolve. + split.next().map(|f| (f, Symbol::intern(f))).ok_or_else(no_res)?; let path = split .next() .map(|f| { @@ -99,14 +133,17 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - .ok_or(ErrorKind::ResolutionFailure)?; - let (_, ty_res) = cx + // If there's no third component, we saw `[a::b]` before and it failed to resolve. + // So there's no partial res. + .ok_or_else(no_res)?; + let ty_res = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }) - .map_err(|_| ErrorKind::ResolutionFailure)?; + .map(|(_, res)| res) + .unwrap_or(Res::Err); if let Res::Err = ty_res { - return Err(ErrorKind::ResolutionFailure); + return Err(no_res().into()); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { @@ -118,31 +155,47 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) .any(|item| item.ident.name == variant_name) { - return Err(ErrorKind::ResolutionFailure); + // This is just to let `fold_item` know that this shouldn't be considered; + // it's a bug for the error to make it to the user + return Err(ResolutionFailure::Dummy.into()); } - match cx.tcx.type_of(did).kind { + match cx.tcx.type_of(did).kind() { ty::Adt(def, _) if def.is_enum() => { if def.all_fields().any(|item| item.ident.name == variant_field_name) { Ok(( ty_res, Some(format!( "variant.{}.field.{}", - variant_name, variant_field_name + variant_str, variant_field_name )), )) } else { - Err(ErrorKind::ResolutionFailure) + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(Res::Def(DefKind::Enum, def.did)), + unresolved: variant_field_str.into(), + } + .into()) } } - _ => Err(ErrorKind::ResolutionFailure), + _ => unreachable!(), } } - _ => Err(ErrorKind::ResolutionFailure), + _ => Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(ty_res), + unresolved: variant_str.into(), + } + .into()), } } /// Resolves a string as a macro. - fn macro_resolve(&self, path_str: &str, parent_id: Option) -> Option { + fn macro_resolve( + &self, + path_str: &'a str, + module_id: DefId, + ) -> Result> { let cx = self.cx; let path = ast::Path::from_ident(Ident::from_str(path_str)); cx.enter_resolver(|resolver| { @@ -154,275 +207,349 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { false, ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { - return Some(res.map_id(|_| panic!("unexpected id"))); + return Ok(res.map_id(|_| panic!("unexpected id"))); } } if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { - return Some(res.map_id(|_| panic!("unexpected id"))); + return Ok(res.map_id(|_| panic!("unexpected id"))); } - if let Some(module_id) = parent_id { - if let Ok((_, res)) = - resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id) - { - // don't resolve builtins like `#[derive]` - if let Res::Def(..) = res { - let res = res.map_id(|_| panic!("unexpected node_id")); - return Some(res); - } + debug!("resolving {} as a macro in the module {:?}", path_str, module_id); + if let Ok((_, res)) = + resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id) + { + // don't resolve builtins like `#[derive]` + if let Res::Def(..) = res { + let res = res.map_id(|_| panic!("unexpected node_id")); + return Ok(res); } - } else { - debug!("attempting to resolve item without parent module: {}", path_str); } - None + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: path_str.into(), + }) }) } + /// Resolves a string as a path within a particular namespace. Also returns an optional /// URL fragment in the case of variants and methods. - fn resolve( + fn resolve<'path>( &self, - path_str: &str, + path_str: &'path str, ns: Namespace, current_item: &Option, - parent_id: Option, + module_id: DefId, extra_fragment: &Option, - ) -> Result<(Res, Option), ErrorKind> { + ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; - // In case we're in a module, try to resolve the relative path. - if let Some(module_id) = parent_id { - let result = cx.enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) - }); - debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); - let result = match result { - Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure), - _ => result.map_err(|_| ErrorKind::ResolutionFailure), - }; + let result = cx.enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) + }); + debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); + let result = match result { + Ok((_, Res::Err)) => Err(()), + x => x, + }; - if let Ok((_, res)) = result { - let res = res.map_id(|_| panic!("unexpected node_id")); - // In case this is a trait item, skip the - // early return and try looking for the trait. - let value = match res { - Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true, - Res::Def(DefKind::AssocTy, _) => false, - Res::Def(DefKind::Variant, _) => { - return handle_variant(cx, res, extra_fragment); - } - // Not a trait item; just return what we found. - Res::PrimTy(..) => { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); - } - return Ok((res, Some(path_str.to_owned()))); - } - Res::Def(DefKind::Mod, _) => { - return Ok((res, extra_fragment.clone())); - } - _ => { - return Ok((res, extra_fragment.clone())); + if let Ok((_, res)) = result { + let res = res.map_id(|_| panic!("unexpected node_id")); + // In case this is a trait item, skip the + // early return and try looking for the trait. + let value = match res { + Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true, + Res::Def(DefKind::AssocTy, _) => false, + Res::Def(DefKind::Variant, _) => { + return handle_variant(cx, res, extra_fragment); + } + // Not a trait item; just return what we found. + Res::PrimTy(ty) => { + if extra_fragment.is_some() { + return Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )); } - }; - - if value != (ns == ValueNS) { - return Err(ErrorKind::ResolutionFailure); + return Ok((res, Some(ty.name_str().to_owned()))); + } + Res::Def(DefKind::Mod, _) => { + return Ok((res, extra_fragment.clone())); } - } else if let Some((path, prim)) = is_primitive(path_str, ns) { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); + _ => { + return Ok((res, extra_fragment.clone())); } - return Ok((prim, Some(path.to_owned()))); + }; + + if value != (ns == ValueNS) { + return Err(ResolutionFailure::WrongNamespace(res, ns).into()); + } + // FIXME: why is this necessary? + } else if let Some((path, prim)) = is_primitive(path_str, ns) { + if extra_fragment.is_some() { + return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim))); } + return Ok((prim, Some(path.to_owned()))); + } - // Try looking for methods and associated items. - let mut split = path_str.rsplitn(2, "::"); - let item_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; - let path = split - .next() - .map(|f| { - if f == "self" || f == "Self" { - if let Some(name) = current_item.as_ref() { - return name.clone(); - } - } - f.to_owned() - }) - .ok_or(ErrorKind::ResolutionFailure)?; - - if let Some((path, prim)) = is_primitive(&path, TypeNS) { - for &impl_ in primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)? { - let link = cx - .tcx - .associated_items(impl_) - .find_by_name_and_namespace( - cx.tcx, - Ident::with_dummy_span(item_name), - ns, - impl_, - ) - .and_then(|item| match item.kind { - ty::AssocKind::Fn => Some("method"), - _ => None, - }) - .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name)))); - if let Some(link) = link { - return Ok(link); + // Try looking for methods and associated items. + let mut split = path_str.rsplitn(2, "::"); + // this can be an `unwrap()` because we ensure the link is never empty + let (item_str, item_name) = split.next().map(|i| (i, Symbol::intern(i))).unwrap(); + let path_root = split + .next() + .map(|f| { + if f == "self" || f == "Self" { + if let Some(name) = current_item.as_ref() { + return name.clone(); } } - return Err(ErrorKind::ResolutionFailure); + f.to_owned() + }) + // If there's no `::`, it's not an associated item. + // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. + .ok_or_else(|| { + debug!("found no `::`, assumming {} was correctly not in scope", item_name); + ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: item_str.into(), + } + })?; + + if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { + let impls = + primitive_impl(cx, &path).ok_or_else(|| ResolutionFailure::NotResolved { + module_id, + partial_res: Some(prim), + unresolved: item_str.into(), + })?; + for &impl_ in impls { + let link = cx + .tcx + .associated_items(impl_) + .find_by_name_and_namespace( + cx.tcx, + Ident::with_dummy_span(item_name), + ns, + impl_, + ) + .map(|item| match item.kind { + ty::AssocKind::Fn => "method", + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + }) + .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_str)))); + if let Some(link) = link { + return Ok(link); + } } + debug!( + "returning primitive error for {}::{} in {} namespace", + path, + item_name, + ns.descr() + ); + return Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(prim), + unresolved: item_str.into(), + } + .into()); + } - let (_, ty_res) = cx - .enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) - }) - .map_err(|_| ErrorKind::ResolutionFailure)?; - if let Res::Err = ty_res { + let ty_res = cx + .enter_resolver(|resolver| { + // only types can have associated items + resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) + }) + .map(|(_, res)| res); + let ty_res = match ty_res { + Err(()) | Ok(Res::Err) => { return if ns == Namespace::ValueNS { self.variant_field(path_str, current_item, module_id) } else { - Err(ErrorKind::ResolutionFailure) + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: path_root.into(), + } + .into()) }; } - let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); - let res = match ty_res { - Res::Def( - DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, - did, - ) => { - debug!("looking for associated item named {} for item {:?}", item_name, did); - // Checks if item_name belongs to `impl SomeItem` - let kind = cx - .tcx - .inherent_impls(did) - .iter() - .flat_map(|&imp| { - cx.tcx.associated_items(imp).find_by_name_and_namespace( - cx.tcx, - Ident::with_dummy_span(item_name), - ns, - imp, - ) - }) - .map(|item| item.kind) - // There should only ever be one associated item that matches from any inherent impl - .next() - // Check if item_name belongs to `impl SomeTrait for SomeItem` - // This gives precedence to `impl SomeItem`: - // Although having both would be ambiguous, use impl version for compat. sake. - // To handle that properly resolve() would have to support - // something like [`ambi_fn`](::ambi_fn) - .or_else(|| { - let kind = resolve_associated_trait_item( - did, module_id, item_name, ns, &self.cx, - ); - debug!("got associated item kind {:?}", kind); - kind - }); - - if let Some(kind) = kind { - let out = match kind { - ty::AssocKind::Fn => "method", - ty::AssocKind::Const => "associatedconstant", - ty::AssocKind::Type => "associatedtype", - }; - Some(if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if kind == ty::AssocKind::Fn { - AnchorFailure::Method + Ok(res) => res, + }; + let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); + let res = match ty_res { + Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => { + debug!("looking for associated item named {} for item {:?}", item_name, did); + // Checks if item_name belongs to `impl SomeItem` + let assoc_item = cx + .tcx + .inherent_impls(did) + .iter() + .flat_map(|&imp| { + cx.tcx.associated_items(imp).find_by_name_and_namespace( + cx.tcx, + Ident::with_dummy_span(item_name), + ns, + imp, + ) + }) + .map(|item| (item.kind, item.def_id)) + // There should only ever be one associated item that matches from any inherent impl + .next() + // Check if item_name belongs to `impl SomeTrait for SomeItem` + // This gives precedence to `impl SomeItem`: + // Although having both would be ambiguous, use impl version for compat. sake. + // To handle that properly resolve() would have to support + // something like [`ambi_fn`](::ambi_fn) + .or_else(|| { + let kind = + resolve_associated_trait_item(did, module_id, item_name, ns, &self.cx); + debug!("got associated item kind {:?}", kind); + kind + }); + + if let Some((kind, id)) = assoc_item { + let out = match kind { + ty::AssocKind::Fn => "method", + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + }; + Some(if extra_fragment.is_some() { + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res))) + } else { + // HACK(jynelson): `clean` expects the type, not the associated item. + // but the disambiguator logic expects the associated item. + // Store the kind in a side channel so that only the disambiguator logic looks at it. + self.kind_side_channel.set(Some((kind.as_def_kind(), id))); + Ok((ty_res, Some(format!("{}.{}", out, item_str)))) + }) + } else if ns == Namespace::ValueNS { + debug!("looking for variants or fields named {} for {:?}", item_name, did); + match cx.tcx.type_of(did).kind() { + ty::Adt(def, _) => { + let field = if def.is_enum() { + def.all_fields().find(|item| item.ident.name == item_name) } else { - AnchorFailure::AssocConstant - })) - } else { - // HACK(jynelson): `clean` expects the type, not the associated item. - // but the disambiguator logic expects the associated item. - // Store the kind in a side channel so that only the disambiguator logic looks at it. - self.kind_side_channel.set(Some(kind.as_def_kind())); - Ok((ty_res, Some(format!("{}.{}", out, item_name)))) - }) - } else if ns == Namespace::ValueNS { - match cx.tcx.type_of(did).kind { - ty::Adt(def, _) => { - let field = if def.is_enum() { - def.all_fields().find(|item| item.ident.name == item_name) - } else { - def.non_enum_variant() - .fields - .iter() - .find(|item| item.ident.name == item_name) - }; - field.map(|item| { - if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if def.is_enum() { - AnchorFailure::Variant + def.non_enum_variant() + .fields + .iter() + .find(|item| item.ident.name == item_name) + }; + field.map(|item| { + if extra_fragment.is_some() { + let res = Res::Def( + if def.is_enum() { + DefKind::Variant } else { - AnchorFailure::Field - })) - } else { - Ok(( - ty_res, - Some(format!( - "{}.{}", - if def.is_enum() { - "variant" - } else { - "structfield" - }, - item.ident - )), - )) - } - }) + DefKind::Field + }, + item.did, + ); + Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )) + } else { + Ok(( + ty_res, + Some(format!( + "{}.{}", + if def.is_enum() { "variant" } else { "structfield" }, + item.ident + )), + )) + } + }) + } + _ => None, + } + } else { + // We already know this isn't in ValueNS, so no need to check variant_field + return Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(ty_res), + unresolved: item_str.into(), + } + .into()); + } + } + Res::Def(DefKind::Trait, did) => cx + .tcx + .associated_items(did) + .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did) + .map(|item| { + let kind = match item.kind { + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + ty::AssocKind::Fn => { + if item.defaultness.has_value() { + "method" + } else { + "tymethod" } - _ => None, } + }; + + if extra_fragment.is_some() { + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res))) } else { - // We already know this isn't in ValueNS, so no need to check variant_field - return Err(ErrorKind::ResolutionFailure); + let res = Res::Def(item.kind.as_def_kind(), item.def_id); + Ok((res, Some(format!("{}.{}", kind, item_str)))) } + }), + _ => None, + }; + res.unwrap_or_else(|| { + if ns == Namespace::ValueNS { + self.variant_field(path_str, current_item, module_id) + } else { + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(ty_res), + unresolved: item_str.into(), } - Res::Def(DefKind::Trait, did) => cx - .tcx - .associated_items(did) - .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did) - .map(|item| { - let kind = match item.kind { - ty::AssocKind::Const => "associatedconstant", - ty::AssocKind::Type => "associatedtype", - ty::AssocKind::Fn => { - if item.defaultness.has_value() { - "method" - } else { - "tymethod" - } - } - }; + .into()) + } + }) + } - if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const { - AnchorFailure::AssocConstant - } else if item.kind == ty::AssocKind::Type { - AnchorFailure::AssocType - } else { - AnchorFailure::Method - })) - } else { - let res = Res::Def(item.kind.as_def_kind(), item.def_id); - Ok((res, Some(format!("{}.{}", kind, item_name)))) - } - }), - _ => None, - }; - res.unwrap_or_else(|| { - if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id) - } else { - Err(ErrorKind::ResolutionFailure) + /// Used for reporting better errors. + /// + /// Returns whether the link resolved 'fully' in another namespace. + /// 'fully' here means that all parts of the link resolved, not just some path segments. + /// This returns the `Res` even if it was erroneous for some reason + /// (such as having invalid URL fragments or being in the wrong namespace). + fn check_full_res( + &self, + ns: Namespace, + path_str: &str, + module_id: DefId, + current_item: &Option, + extra_fragment: &Option, + ) -> Option { + let check_full_res_inner = |this: &Self, result: Result>| { + let res = match result { + Ok(res) => Some(res), + Err(ErrorKind::Resolve(box kind)) => kind.full_res(), + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => { + Some(res) } - }) - } else { - debug!("attempting to resolve item without parent module: {}", path_str); - Err(ErrorKind::ResolutionFailure) + Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, + }; + this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) + }; + // cannot be used for macro namespace + let check_full_res = |this: &Self, ns| { + let result = this.resolve(path_str, ns, current_item, module_id, extra_fragment); + check_full_res_inner(this, result.map(|(res, _)| res)) + }; + let check_full_res_macro = |this: &Self| { + let result = this.macro_resolve(path_str, module_id); + check_full_res_inner(this, result.map_err(ErrorKind::from)) + }; + match ns { + Namespace::MacroNS => check_full_res_macro(self), + Namespace::TypeNS | Namespace::ValueNS => check_full_res(self, ns), } } } @@ -433,7 +560,7 @@ fn resolve_associated_trait_item( item_name: Symbol, ns: Namespace, cx: &DocContext<'_>, -) -> Option { +) -> Option<(ty::AssocKind, DefId)> { let ty = cx.tcx.type_of(did); // First consider automatic impls: `impl From for T` let implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did); @@ -461,7 +588,7 @@ fn resolve_associated_trait_item( // but provided methods come directly from `tcx`. // Fortunately, we don't need the whole method, we just need to know // what kind of associated item it is. - Some((assoc.def_id, kind)) + Some((kind, assoc.def_id)) }); let assoc = items.next(); debug_assert_eq!(items.count(), 0); @@ -483,7 +610,7 @@ fn resolve_associated_trait_item( ns, trait_, ) - .map(|assoc| (assoc.def_id, assoc.kind)) + .map(|assoc| (assoc.kind, assoc.def_id)) } } _ => panic!("get_impls returned something that wasn't an impl"), @@ -500,12 +627,12 @@ fn resolve_associated_trait_item( cx.tcx .associated_items(trait_) .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_) - .map(|assoc| (assoc.def_id, assoc.kind)) + .map(|assoc| (assoc.kind, assoc.def_id)) })); } // FIXME: warn about ambiguity debug!("the candidates were {:?}", candidates); - candidates.pop().map(|(_, kind)| kind) + candidates.pop() } /// Given a type, return all traits in scope in `module` implemented by that type. @@ -534,19 +661,21 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl"); // Check if these are the same type. let impl_type = trait_ref.self_ty(); - debug!( + trace!( "comparing type {} with kind {:?} against type {:?}", - impl_type, impl_type.kind, type_ + impl_type, + impl_type.kind(), + type_ ); // Fast path: if this is a primitive simple `==` will work saw_impl = impl_type == ty - || match impl_type.kind { + || match impl_type.kind() { // Check if these are the same def_id ty::Adt(def, _) => { debug!("adt def_id: {:?}", def.did); def.did == type_ } - ty::Foreign(def_id) => def_id == type_, + ty::Foreign(def_id) => *def_id == type_, _ => false, }; }); @@ -558,10 +687,10 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx /// Check for resolve collisions between a trait and its derive /// /// These are common and we should just resolve to the trait in that case -fn is_derive_trait_collision(ns: &PerNS>) -> bool { +fn is_derive_trait_collision(ns: &PerNS>>) -> bool { if let PerNS { - type_ns: Some((Res::Def(DefKind::Trait, _), _)), - macro_ns: Some((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), + type_ns: Ok((Res::Def(DefKind::Trait, _), _)), + macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), .. } = *ns { @@ -578,6 +707,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let parent_node = if item.is_fake() { // FIXME: is this correct? None + // If we're documenting the crate root itself, it has no parent. Use the root instead. + } else if item.def_id.is_top_level_module() { + Some(item.def_id) } else { let mut current = item.def_id; // The immediate parent might not always be a module. @@ -589,6 +721,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } current = parent; } else { + debug!( + "{:?} has no parent (kind={:?}, original was {:?})", + current, + self.cx.tcx.def_kind(current), + item.def_id + ); break None; } } @@ -629,7 +767,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { self.mod_ids.push(item.def_id); } - let cx = self.cx; let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); trace!("got documentation '{}'", dox); @@ -671,329 +808,452 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }); for (ori_link, link_range) in markdown_links(&dox) { - trace!("considering link '{}'", ori_link); + self.resolve_link( + &mut item, + &dox, + ¤t_item, + parent_node, + &parent_name, + ori_link, + link_range, + ); + } - // Bail early for real links. - if ori_link.contains('/') { - continue; + if item.is_mod() && !item.attrs.inner_docs { + self.mod_ids.push(item.def_id); + } + + if item.is_mod() { + let ret = self.fold_item_recur(item); + + self.mod_ids.pop(); + + ret + } else { + self.fold_item_recur(item) + } + } +} + +impl LinkCollector<'_, '_> { + fn resolve_link( + &self, + item: &mut Item, + dox: &str, + current_item: &Option, + parent_node: Option, + parent_name: &Option, + ori_link: String, + link_range: Option>, + ) { + trace!("considering link '{}'", ori_link); + + // Bail early for real links. + if ori_link.contains('/') { + return; + } + + // [] is mostly likely not supposed to be a link + if ori_link.is_empty() { + return; + } + + let cx = self.cx; + let link = ori_link.replace("`", ""); + let parts = link.split('#').collect::>(); + let (link, extra_fragment) = if parts.len() > 2 { + anchor_failure(cx, &item, &link, dox, link_range, AnchorFailure::MultipleAnchors); + return; + } else if parts.len() == 2 { + if parts[0].trim().is_empty() { + // This is an anchor to an element of the current page, nothing to do in here! + return; } + (parts[0], Some(parts[1].to_owned())) + } else { + (parts[0], None) + }; + let resolved_self; + let link_text; + let mut path_str; + let disambiguator; + let (mut res, mut fragment) = { + path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { + disambiguator = Some(d); + path + } else { + disambiguator = None; + &link + } + .trim(); - // [] is mostly likely not supposed to be a link - if ori_link.is_empty() { - continue; + if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) { + return; } - let link = ori_link.replace("`", ""); - let parts = link.split('#').collect::>(); - let (link, extra_fragment) = if parts.len() > 2 { - anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors); - continue; - } else if parts.len() == 2 { - if parts[0].trim().is_empty() { - // This is an anchor to an element of the current page, nothing to do in here! - continue; - } - (parts[0].to_owned(), Some(parts[1].to_owned())) + // We stripped `()` and `!` when parsing the disambiguator. + // Add them back to be displayed, but not prefix disambiguators. + link_text = disambiguator + .map(|d| d.display_for(path_str)) + .unwrap_or_else(|| path_str.to_owned()); + + // In order to correctly resolve intra-doc-links we need to + // pick a base AST node to work from. If the documentation for + // this module came from an inner comment (//!) then we anchor + // our name resolution *inside* the module. If, on the other + // hand it was an outer comment (///) then we anchor the name + // resolution in the parent module on the basis that the names + // used are more likely to be intended to be parent names. For + // this, we set base_node to None for inner comments since + // we've already pushed this node onto the resolution stack but + // for outer comments we explicitly try and resolve against the + // parent_node first. + let base_node = if item.is_mod() && item.attrs.inner_docs { + self.mod_ids.last().copied() } else { - (parts[0].to_owned(), None) + parent_node }; - let resolved_self; - let mut path_str; - let disambiguator; - let (mut res, mut fragment) = { - path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { - disambiguator = Some(d); - path - } else { - disambiguator = None; - &link - } - .trim(); - if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) { - continue; + let mut module_id = if let Some(id) = base_node { + id + } else { + debug!("attempting to resolve item without parent module: {}", path_str); + let err_kind = ResolutionFailure::NoParentItem.into(); + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![err_kind], + ); + return; + }; + + // replace `Self` with suitable item's parent name + if path_str.starts_with("Self::") { + if let Some(ref name) = parent_name { + resolved_self = format!("{}::{}", name, &path_str[6..]); + path_str = &resolved_self; } + } else if path_str.starts_with("crate::") { + use rustc_span::def_id::CRATE_DEF_INDEX; + + // HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented. + // But rustdoc wants it to mean the crate this item was originally present in. + // To work around this, remove it and resolve relative to the crate root instead. + // HACK(jynelson)(2): If we just strip `crate::` then suddenly primitives become ambiguous + // (consider `crate::char`). Instead, change it to `self::`. This works because 'self' is now the crate root. + resolved_self = format!("self::{}", &path_str["crate::".len()..]); + path_str = &resolved_self; + module_id = DefId { krate: item.def_id.krate, index: CRATE_DEF_INDEX }; + } - // In order to correctly resolve intra-doc-links we need to - // pick a base AST node to work from. If the documentation for - // this module came from an inner comment (//!) then we anchor - // our name resolution *inside* the module. If, on the other - // hand it was an outer comment (///) then we anchor the name - // resolution in the parent module on the basis that the names - // used are more likely to be intended to be parent names. For - // this, we set base_node to None for inner comments since - // we've already pushed this node onto the resolution stack but - // for outer comments we explicitly try and resolve against the - // parent_node first. - let base_node = if item.is_mod() && item.attrs.inner_docs { - self.mod_ids.last().copied() - } else { - parent_node - }; + match self.resolve_with_disambiguator( + disambiguator, + item, + dox, + path_str, + current_item, + module_id, + extra_fragment, + &ori_link, + link_range.clone(), + ) { + Some(x) => x, + None => return, + } + }; - // replace `Self` with suitable item's parent name - if path_str.starts_with("Self::") { - if let Some(ref name) = parent_name { - resolved_self = format!("{}::{}", name, &path_str[6..]); - path_str = &resolved_self; + // Check for a primitive which might conflict with a module + // Report the ambiguity and require that the user specify which one they meant. + // FIXME: could there ever be a primitive not in the type namespace? + if matches!( + disambiguator, + None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) + ) && !matches!(res, Res::PrimTy(_)) + { + if let Some((path, prim)) = is_primitive(path_str, TypeNS) { + // `prim@char` + if matches!(disambiguator, Some(Disambiguator::Primitive)) { + if fragment.is_some() { + anchor_failure( + cx, + &item, + path_str, + dox, + link_range, + AnchorFailure::RustdocAnchorConflict(prim), + ); + return; } + res = prim; + fragment = Some(path.to_owned()); + } else { + // `[char]` when a `char` module is in scope + let candidates = vec![res, prim]; + ambiguity_error(cx, &item, path_str, dox, link_range, candidates); + return; } + } + } - match disambiguator.map(Disambiguator::ns) { - Some(ns @ (ValueNS | TypeNS)) => { - match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) - { - Ok(res) => res, - Err(ErrorKind::ResolutionFailure) => { - resolution_failure(cx, &item, path_str, &dox, link_range); - // This could just be a normal link or a broken link - // we could potentially check if something is - // "intra-doc-link-like" and warn in that case. - continue; - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - } + let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { + // The resolved item did not match the disambiguator; give a better error than 'not found' + let msg = format!("incompatible link kind for `{}`", path_str); + let callback = |diag: &mut DiagnosticBuilder<'_>, sp| { + let note = format!( + "this link resolved to {} {}, which is not {} {}", + resolved.article(), + resolved.descr(), + specified.article(), + specified.descr() + ); + diag.note(¬e); + suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range); + }; + report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, &item, dox, &link_range, callback); + }; + if let Res::PrimTy(..) = res { + match disambiguator { + Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { + item.attrs.links.push(ItemLink { + link: ori_link, + link_text, + did: None, + fragment, + }); + } + Some(other) => { + report_mismatch(other, Disambiguator::Primitive); + return; + } + } + } else { + debug!("intra-doc link to {} resolved to {:?}", path_str, res); + + // Disallow e.g. linking to enums with `struct@` + if let Res::Def(kind, _) = res { + debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); + match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) { + | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) + // NOTE: this allows 'method' to mean both normal functions and associated functions + // This can't cause ambiguity because both are in the same namespace. + | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn))) + // These are namespaces; allow anything in the namespace to match + | (_, Some(Disambiguator::Namespace(_))) + // If no disambiguator given, allow anything + | (_, None) + // All of these are valid, so do nothing + => {} + (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} + (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { + report_mismatch(specified, Disambiguator::Kind(kind)); + return; } - None => { - // Try everything! - let mut candidates = PerNS { - macro_ns: self - .macro_resolve(path_str, base_node) - .map(|res| (res, extra_fragment.clone())), - type_ns: match self.resolve( - path_str, - TypeNS, - ¤t_item, - base_node, - &extra_fragment, - ) { - Ok(res) => { - debug!("got res in TypeNS: {:?}", res); - Some(res) - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - Err(ErrorKind::ResolutionFailure) => None, - }, - value_ns: match self.resolve( - path_str, - ValueNS, - ¤t_item, - base_node, - &extra_fragment, - ) { - Ok(res) => Some(res), - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - Err(ErrorKind::ResolutionFailure) => None, - } - .and_then(|(res, fragment)| { - // Constructors are picked up in the type namespace. - match res { - Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => None, - _ => match (fragment, extra_fragment) { - (Some(fragment), Some(_)) => { - // Shouldn't happen but who knows? - Some((res, Some(fragment))) - } - (fragment, None) | (None, fragment) => { - Some((res, fragment)) - } - }, - } - }), - }; + } + } - if candidates.is_empty() { - resolution_failure(cx, &item, path_str, &dox, link_range); - // this could just be a normal link - continue; - } + // item can be non-local e.g. when using #[doc(primitive = "pointer")] + if let Some((src_id, dst_id)) = res + .opt_def_id() + .and_then(|def_id| def_id.as_local()) + .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id))) + { + use rustc_hir::def_id::LOCAL_CRATE; - let len = candidates.clone().present_items().count(); + let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id); + let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id); - if len == 1 { - candidates.present_items().next().unwrap() - } else if len == 2 && is_derive_trait_collision(&candidates) { - candidates.type_ns.unwrap() - } else { - if is_derive_trait_collision(&candidates) { - candidates.macro_ns = None; + if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src) + && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst) + { + privacy_error(cx, &item, &path_str, dox, link_range); + } + } + let id = register_res(cx, res); + item.attrs.links.push(ItemLink { link: ori_link, link_text, did: Some(id), fragment }); + } + } + + fn resolve_with_disambiguator( + &self, + disambiguator: Option, + item: &mut Item, + dox: &str, + path_str: &str, + current_item: &Option, + base_node: DefId, + extra_fragment: Option, + ori_link: &str, + link_range: Option>, + ) -> Option<(Res, Option)> { + match disambiguator.map(Disambiguator::ns) { + Some(ns @ (ValueNS | TypeNS)) => { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { + Ok(res) => Some(res), + Err(ErrorKind::Resolve(box mut kind)) => { + // We only looked in one namespace. Try to give a better error if possible. + if kind.full_res().is_none() { + let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; + // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator` + // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach + for &new_ns in &[other_ns, MacroNS] { + if let Some(res) = self.check_full_res( + new_ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, ns); + break; + } } - let candidates = - candidates.map(|candidate| candidate.map(|(res, _)| res)); - let candidates = [TypeNS, ValueNS, MacroNS] - .iter() - .filter_map(|&ns| candidates[ns].map(|res| (res, ns))); - ambiguity_error( - cx, - &item, - path_str, - &dox, - link_range, - candidates.collect(), - ); - continue; } + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![kind], + ); + // This could just be a normal link or a broken link + // we could potentially check if something is + // "intra-doc-link-like" and warn in that case. + return None; } - Some(MacroNS) => { - if let Some(res) = self.macro_resolve(path_str, base_node) { - (res, extra_fragment) - } else { - resolution_failure(cx, &item, path_str, &dox, link_range); - continue; - } + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(self.cx, &item, &ori_link, dox, link_range, msg); + return None; } } - }; - - // Check for a primitive which might conflict with a module - // Report the ambiguity and require that the user specify which one they meant. - // FIXME: could there ever be a primitive not in the type namespace? - if matches!( - disambiguator, - None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) - ) && !matches!(res, Res::PrimTy(_)) - { - if let Some((path, prim)) = is_primitive(path_str, TypeNS) { - // `prim@char` - if matches!(disambiguator, Some(Disambiguator::Primitive)) { - if fragment.is_some() { - anchor_failure( - cx, - &item, - path_str, - &dox, - link_range, - AnchorFailure::Primitive, - ); - continue; + } + None => { + // Try everything! + let mut candidates = PerNS { + macro_ns: self + .macro_resolve(path_str, base_node) + .map(|res| (res, extra_fragment.clone())), + type_ns: match self.resolve( + path_str, + TypeNS, + ¤t_item, + base_node, + &extra_fragment, + ) { + Ok(res) => { + debug!("got res in TypeNS: {:?}", res); + Ok(res) } - res = prim; - fragment = Some(path.to_owned()); - } else { - // `[char]` when a `char` module is in scope - let candidates = vec![(res, TypeNS), (prim, TypeNS)]; - ambiguity_error(cx, &item, path_str, &dox, link_range, candidates); - continue; + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(self.cx, &item, ori_link, dox, link_range, msg); + return None; + } + Err(ErrorKind::Resolve(box kind)) => Err(kind), + }, + value_ns: match self.resolve( + path_str, + ValueNS, + ¤t_item, + base_node, + &extra_fragment, + ) { + Ok(res) => Ok(res), + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(self.cx, &item, ori_link, dox, link_range, msg); + return None; + } + Err(ErrorKind::Resolve(box kind)) => Err(kind), } - } - } + .and_then(|(res, fragment)| { + // Constructors are picked up in the type namespace. + match res { + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { + Err(ResolutionFailure::WrongNamespace(res, TypeNS)) + } + _ => match (fragment, extra_fragment) { + (Some(fragment), Some(_)) => { + // Shouldn't happen but who knows? + Ok((res, Some(fragment))) + } + (fragment, None) | (None, fragment) => Ok((res, fragment)), + }, + } + }), + }; - let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { - // The resolved item did not match the disambiguator; give a better error than 'not found' - let msg = format!("incompatible link kind for `{}`", path_str); - report_diagnostic(cx, &msg, &item, &dox, link_range.clone(), |diag, sp| { - let note = format!( - "this link resolved to {} {}, which is not {} {}", - resolved.article(), - resolved.descr(), - specified.article(), - specified.descr() + let len = candidates.iter().filter(|res| res.is_ok()).count(); + + if len == 0 { + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + candidates.into_iter().filter_map(|res| res.err()).collect(), ); - let suggestion = resolved.display_for(path_str); - let help_msg = - format!("to link to the {}, use its disambiguator", resolved.descr()); - diag.note(¬e); - if let Some(sp) = sp { - diag.span_suggestion( - sp, - &help_msg, - suggestion, - Applicability::MaybeIncorrect, - ); - } else { - diag.help(&format!("{}: {}", help_msg, suggestion)); - } - }); - }; - if let Res::PrimTy(_) = res { - match disambiguator { - Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { - item.attrs.links.push((ori_link, None, fragment)) - } - Some(other) => { - report_mismatch(other, Disambiguator::Primitive); - continue; - } + // this could just be a normal link + return None; } - } else { - debug!("intra-doc link to {} resolved to {:?}", path_str, res); - - // Disallow e.g. linking to enums with `struct@` - if let Res::Def(kind, _) = res { - debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); - match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) { - | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) - // NOTE: this allows 'method' to mean both normal functions and associated functions - // This can't cause ambiguity because both are in the same namespace. - | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn))) - // These are namespaces; allow anything in the namespace to match - | (_, Some(Disambiguator::Namespace(_))) - // If no disambiguator given, allow anything - | (_, None) - // All of these are valid, so do nothing - => {} - (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} - (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { - report_mismatch(specified, Disambiguator::Kind(kind)); - continue; - } + + if len == 1 { + Some(candidates.into_iter().filter_map(|res| res.ok()).next().unwrap()) + } else if len == 2 && is_derive_trait_collision(&candidates) { + Some(candidates.type_ns.unwrap()) + } else { + if is_derive_trait_collision(&candidates) { + candidates.macro_ns = Err(ResolutionFailure::Dummy); } + // If we're reporting an ambiguity, don't mention the namespaces that failed + let candidates = candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); + ambiguity_error( + self.cx, + &item, + path_str, + dox, + link_range, + candidates.present_items().collect(), + ); + return None; } - - // item can be non-local e.g. when using #[doc(primitive = "pointer")] - if let Some((src_id, dst_id)) = res - .opt_def_id() - .and_then(|def_id| def_id.as_local()) - .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id))) - { - use rustc_hir::def_id::LOCAL_CRATE; - - let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id); - let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id); - - if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src) - && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst) - { - privacy_error(cx, &item, &path_str, &dox, link_range); - continue; + } + Some(MacroNS) => { + match self.macro_resolve(path_str, base_node) { + Ok(res) => Some((res, extra_fragment)), + Err(mut kind) => { + // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. + for &ns in &[TypeNS, ValueNS] { + if let Some(res) = self.check_full_res( + ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, MacroNS); + break; + } + } + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![kind], + ); + return None; } } - let id = register_res(cx, res); - item.attrs.links.push((ori_link, Some(id), fragment)); } } - - if item.is_mod() && !item.attrs.inner_docs { - self.mod_ids.push(item.def_id); - } - - if item.is_mod() { - let ret = self.fold_item_recur(item); - - self.mod_ids.pop(); - - ret - } else { - self.fold_item_recur(item) - } - } - - // FIXME: if we can resolve intra-doc links from other crates, we can use the stock - // `fold_crate`, but until then we should avoid scanning `krate.external_traits` since those - // will never resolve properly - fn fold_crate(&mut self, mut c: Crate) -> Crate { - c.module = c.module.take().and_then(|module| self.fold_item(module)); - - c } } @@ -1005,6 +1265,18 @@ enum Disambiguator { } impl Disambiguator { + /// The text that should be displayed when the path is rendered as HTML. + /// + /// NOTE: `path` is not the original link given by the user, but a name suitable for passing to `resolve`. + fn display_for(&self, path: &str) -> String { + match self { + // FIXME: this will have different output if the user had `m!()` originally. + Self::Kind(DefKind::Macro(MacroKind::Bang)) => format!("{}!", path), + Self::Kind(DefKind::Fn) => format!("{}()", path), + _ => path.to_owned(), + } + } + /// (disambiguator, path_str) fn from_str(link: &str) -> Result<(Self, &str), ()> { use Disambiguator::{Kind, Namespace as NS, Primitive}; @@ -1047,17 +1319,27 @@ impl Disambiguator { } } - fn display_for(self, path_str: &str) -> String { + /// WARNING: panics on `Res::Err` + fn from_res(res: Res) -> Self { + match res { + Res::Def(kind, _) => Disambiguator::Kind(kind), + Res::PrimTy(_) => Disambiguator::Primitive, + _ => Disambiguator::Namespace(res.ns().expect("can't call `from_res` on Res::err")), + } + } + + fn suggestion(self) -> Suggestion { let kind = match self { - Disambiguator::Primitive => return format!("prim@{}", path_str), + Disambiguator::Primitive => return Suggestion::Prefix("prim"), Disambiguator::Kind(kind) => kind, Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"), }; if kind == DefKind::Macro(MacroKind::Bang) { - return format!("{}!", path_str); + return Suggestion::Macro; } else if kind == DefKind::Fn || kind == DefKind::AssocFn { - return format!("{}()", path_str); + return Suggestion::Function; } + let prefix = match kind { DefKind::Struct => "struct", DefKind::Enum => "enum", @@ -1079,7 +1361,8 @@ impl Disambiguator { Namespace::MacroNS => "macro", }, }; - format!("{}@{}", prefix, path_str) + + Suggestion::Prefix(prefix) } fn ns(self) -> Namespace { @@ -1111,6 +1394,31 @@ impl Disambiguator { } } +enum Suggestion { + Prefix(&'static str), + Function, + Macro, +} + +impl Suggestion { + fn descr(&self) -> Cow<'static, str> { + match self { + Self::Prefix(x) => format!("prefix with `{}@`", x).into(), + Self::Function => "add parentheses".into(), + Self::Macro => "add an exclamation mark".into(), + } + } + + fn as_help(&self, path_str: &str) -> String { + // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` + match self { + Self::Prefix(prefix) => format!("{}@{}", prefix, path_str), + Self::Function => format!("{}()", path_str), + Self::Macro => format!("{}!", path_str), + } + } +} + /// Reports a diagnostic for an intra-doc link. /// /// If no link range is provided, or the source span of the link cannot be determined, the span of @@ -1123,10 +1431,11 @@ impl Disambiguator { /// to it. fn report_diagnostic( cx: &DocContext<'_>, + lint: &'static Lint, msg: &str, item: &Item, dox: &str, - link_range: Option>, + link_range: &Option>, decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option), ) { let hir_id = match cx.as_local_hir_id(item.def_id) { @@ -1141,7 +1450,7 @@ fn report_diagnostic( let attrs = &item.attrs; let sp = span_of_attrs(attrs).unwrap_or(item.source.span()); - cx.tcx.struct_span_lint_hir(lint::builtin::BROKEN_INTRA_DOC_LINKS, hir_id, sp, |lint| { + cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |lint| { let mut diag = lint.build(msg); let span = link_range @@ -1162,7 +1471,7 @@ fn report_diagnostic( // Print the line containing the `link_range` and manually mark it with '^'s. diag.note(&format!( "the link appears in this line:\n\n{line}\n\ - {indicator: , + collector: &LinkCollector<'_, '_>, item: &Item, path_str: &str, + disambiguator: Option, dox: &str, link_range: Option>, + kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { report_diagnostic( - cx, + collector.cx, + BROKEN_INTRA_DOC_LINKS, &format!("unresolved link to `{}`", path_str), item, dox, - link_range, + &link_range, |diag, sp| { - if let Some(sp) = sp { - diag.span_label(sp, "unresolved link"); - } + let item = |res: Res| { + format!( + "the {} `{}`", + res.descr(), + collector.cx.tcx.item_name(res.def_id()).to_string() + ) + }; + let assoc_item_not_allowed = |res: Res| { + let def_id = res.def_id(); + let name = collector.cx.tcx.item_name(def_id); + format!( + "`{}` is {} {}, not a module or type, and cannot have associated items", + name, + res.article(), + res.descr() + ) + }; + // ignore duplicates + let mut variants_seen = SmallVec::<[_; 3]>::new(); + for mut failure in kinds { + let variant = std::mem::discriminant(&failure); + if variants_seen.contains(&variant) { + continue; + } + variants_seen.push(variant); + + if let ResolutionFailure::NotResolved { module_id, partial_res, unresolved } = + &mut failure + { + use DefKind::*; + + let module_id = *module_id; + // FIXME(jynelson): this might conflict with my `Self` fix in #76467 + // FIXME: maybe use itertools `collect_tuple` instead? + fn split(path: &str) -> Option<(&str, &str)> { + let mut splitter = path.rsplitn(2, "::"); + splitter.next().and_then(|right| splitter.next().map(|left| (left, right))) + } - diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + // Check if _any_ parent of the path gets resolved. + // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. + let mut name = path_str; + 'outer: loop { + let (start, end) = if let Some(x) = split(name) { + x + } else { + // avoid bug that marked [Quux::Z] as missing Z, not Quux + if partial_res.is_none() { + *unresolved = name.into(); + } + break; + }; + name = start; + for &ns in &[TypeNS, ValueNS, MacroNS] { + if let Some(res) = + collector.check_full_res(ns, &start, module_id, &None, &None) + { + debug!("found partial_res={:?}", res); + *partial_res = Some(res); + *unresolved = end.into(); + break 'outer; + } + } + *unresolved = end.into(); + } + + let last_found_module = match *partial_res { + Some(Res::Def(DefKind::Mod, id)) => Some(id), + None => Some(module_id), + _ => None, + }; + // See if this was a module: `[path]` or `[std::io::nope]` + if let Some(module) = last_found_module { + let module_name = collector.cx.tcx.item_name(module); + let note = format!( + "the module `{}` contains no item named `{}`", + module_name, unresolved + ); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + // If the link has `::` in it, assume it was meant to be an intra-doc link. + // Otherwise, the `[]` might be unrelated. + // FIXME: don't show this for autolinks (`<>`), `()` style links, or reference links + if !path_str.contains("::") { + diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + } + continue; + } + + // Otherwise, it must be an associated item or variant + let res = partial_res.expect("None case was handled by `last_found_module`"); + let diagnostic_name; + let (kind, name) = match res { + Res::Def(kind, def_id) => { + diagnostic_name = collector.cx.tcx.item_name(def_id).as_str(); + (Some(kind), &*diagnostic_name) + } + Res::PrimTy(ty) => (None, ty.name_str()), + _ => unreachable!("only ADTs and primitives are in scope at module level"), + }; + let path_description = if let Some(kind) = kind { + match kind { + Mod | ForeignMod => "inner item", + Struct => "field or associated item", + Enum | Union => "variant or associated item", + Variant + | Field + | Closure + | Generator + | AssocTy + | AssocConst + | AssocFn + | Fn + | Macro(_) + | Const + | ConstParam + | ExternCrate + | Use + | LifetimeParam + | Ctor(_, _) + | AnonConst => { + let note = assoc_item_not_allowed(res); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + return; + } + Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam + | Static => "associated item", + Impl | GlobalAsm => unreachable!("not a path"), + } + } else { + "associated item" + }; + let note = format!( + "the {} `{}` has no {} named `{}`", + res.descr(), + name, + disambiguator.map_or(path_description, |d| d.descr()), + unresolved, + ); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + + continue; + } + let note = match failure { + ResolutionFailure::NotResolved { .. } => unreachable!("handled above"), + ResolutionFailure::Dummy => continue, + ResolutionFailure::WrongNamespace(res, expected_ns) => { + if let Res::Def(kind, _) = res { + let disambiguator = Disambiguator::Kind(kind); + suggest_disambiguator( + disambiguator, + diag, + path_str, + dox, + sp, + &link_range, + ) + } + + format!( + "this link resolves to {}, which is not in the {} namespace", + item(res), + expected_ns.descr() + ) + } + ResolutionFailure::NoParentItem => { + diag.level = rustc_errors::Level::Bug; + "all intra doc links should have a parent item".to_owned() + } + }; + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + } }, ); } @@ -1210,31 +1704,14 @@ fn anchor_failure( ) { let msg = match failure { AnchorFailure::MultipleAnchors => format!("`{}` contains multiple anchors", path_str), - AnchorFailure::Primitive - | AnchorFailure::Variant - | AnchorFailure::AssocConstant - | AnchorFailure::AssocType - | AnchorFailure::Field - | AnchorFailure::Method => { - let kind = match failure { - AnchorFailure::Primitive => "primitive type", - AnchorFailure::Variant => "enum variant", - AnchorFailure::AssocConstant => "associated constant", - AnchorFailure::AssocType => "associated type", - AnchorFailure::Field => "struct field", - AnchorFailure::Method => "method", - AnchorFailure::MultipleAnchors => unreachable!("should be handled already"), - }; - - format!( - "`{}` contains an anchor, but links to {kind}s are already anchored", - path_str, - kind = kind - ) - } + AnchorFailure::RustdocAnchorConflict(res) => format!( + "`{}` contains an anchor, but links to {kind}s are already anchored", + path_str, + kind = res.descr(), + ), }; - report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "contains invalid anchor"); } @@ -1247,12 +1724,12 @@ fn ambiguity_error( path_str: &str, dox: &str, link_range: Option>, - candidates: Vec<(Res, Namespace)>, + candidates: Vec, ) { let mut msg = format!("`{}` is ", path_str); match candidates.as_slice() { - [(first_def, _), (second_def, _)] => { + [first_def, second_def] => { msg += &format!( "both {} {} and {} {}", first_def.article(), @@ -1263,7 +1740,7 @@ fn ambiguity_error( } _ => { let mut candidates = candidates.iter().peekable(); - while let Some((res, _)) = candidates.next() { + while let Some(res) = candidates.next() { if candidates.peek().is_some() { msg += &format!("{} {}, ", res.article(), res.descr()); } else { @@ -1273,55 +1750,43 @@ fn ambiguity_error( } } - report_diagnostic(cx, &msg, item, dox, link_range.clone(), |diag, sp| { + report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "ambiguous link"); + } else { + diag.note("ambiguous link"); + } - let link_range = link_range.expect("must have a link range if we have a span"); - - for (res, ns) in candidates { - let (action, mut suggestion) = match res { - Res::Def(DefKind::AssocFn | DefKind::Fn, _) => { - ("add parentheses", format!("{}()", path_str)) - } - Res::Def(DefKind::Macro(MacroKind::Bang), _) => { - ("add an exclamation mark", format!("{}!", path_str)) - } - _ => { - let type_ = match (res, ns) { - (Res::PrimTy(_), _) => "prim", - (Res::Def(DefKind::Const, _), _) => "const", - (Res::Def(DefKind::Static, _), _) => "static", - (Res::Def(DefKind::Struct, _), _) => "struct", - (Res::Def(DefKind::Enum, _), _) => "enum", - (Res::Def(DefKind::Union, _), _) => "union", - (Res::Def(DefKind::Trait, _), _) => "trait", - (Res::Def(DefKind::Mod, _), _) => "module", - (_, TypeNS) => "type", - (_, ValueNS) => "value", - (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => "derive", - (_, MacroNS) => "macro", - }; + for res in candidates { + let disambiguator = Disambiguator::from_res(res); + suggest_disambiguator(disambiguator, diag, path_str, dox, sp, &link_range); + } + }); +} - // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` - ("prefix with the item type", format!("{}@{}", type_, path_str)) - } - }; +fn suggest_disambiguator( + disambiguator: Disambiguator, + diag: &mut DiagnosticBuilder<'_>, + path_str: &str, + dox: &str, + sp: Option, + link_range: &Option>, +) { + let suggestion = disambiguator.suggestion(); + let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr()); - if dox.bytes().nth(link_range.start) == Some(b'`') { - suggestion = format!("`{}`", suggestion); - } + if let Some(sp) = sp { + let link_range = link_range.as_ref().expect("must have a link range if we have a span"); + let msg = if dox.bytes().nth(link_range.start) == Some(b'`') { + format!("`{}`", suggestion.as_help(path_str)) + } else { + suggestion.as_help(path_str) + }; - // FIXME: Create a version of this suggestion for when we don't have the span. - diag.span_suggestion( - sp, - &format!("to link to the {}, {}", res.descr(), action), - suggestion, - Applicability::MaybeIncorrect, - ); - } - } - }); + diag.span_suggestion(sp, &help, msg, Applicability::MaybeIncorrect); + } else { + diag.help(&format!("{}: {}", help, suggestion.as_help(path_str))); + } } fn privacy_error( @@ -1335,7 +1800,7 @@ fn privacy_error( let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); - report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + report_diagnostic(cx, PRIVATE_INTRA_DOC_LINKS, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "this item is private"); } @@ -1354,16 +1819,16 @@ fn handle_variant( cx: &DocContext<'_>, res: Res, extra_fragment: &Option, -) -> Result<(Res, Option), ErrorKind> { +) -> Result<(Res, Option), ErrorKind<'static>> { use rustc_middle::ty::DefIdTree; if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Variant)); + return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))); } let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent } else { - return Err(ErrorKind::ResolutionFailure); + return Err(ResolutionFailure::NoParentItem.into()); }; let parent_def = Res::Def(DefKind::Enum, parent); let variant = cx.tcx.expect_variant_res(res); diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 367f93cfd3..78af9f9b85 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -8,7 +8,7 @@ use crate::clean; use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use crate::html::markdown::{find_testable_code, ErrorCodes, LangString}; +use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; use rustc_session::lint; pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { @@ -48,15 +48,11 @@ pub(crate) struct Tests { pub(crate) found_tests: usize, } -impl Tests { - pub(crate) fn new() -> Tests { - Tests { found_tests: 0 } - } -} - -impl crate::test::Tester for Tests { - fn add_test(&mut self, _: String, _: LangString, _: usize) { - self.found_tests += 1; +impl crate::doctest::Tester for Tests { + fn add_test(&mut self, _: String, config: LangString, _: usize) { + if config.rust && config.ignore == Ignore::None { + self.found_tests += 1; + } } } @@ -85,7 +81,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { } }; - let mut tests = Tests::new(); + let mut tests = Tests { found_tests: 0 }; find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 0eebdbd87e..75a6596666 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -284,8 +284,7 @@ impl<'a> DocFolder for ImplStripper<'a> { if let Some(did) = typaram.def_id() { if did.is_local() && !self.retained.contains(&did) { debug!( - "ImplStripper: stripped item in trait's generics; \ - removing impl" + "ImplStripper: stripped item in trait's generics; removing impl" ); return None; } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index f244956e50..9173d8e960 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -9,7 +9,7 @@ pub const STRIP_PRIVATE: Pass = Pass { name: "strip-private", run: strip_private, description: "strips all private items from a crate which cannot be seen externally, \ - implies strip-priv-imports", + implies strip-priv-imports", }; /// Strip private items from the point of view of a crate or externally from a diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ac9f839600..33578dc061 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, generics, fields: sd.fields(), - whence: item.span, + span: item.span, } } @@ -120,7 +120,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, generics, fields: sd.fields(), - whence: item.span, + span: item.span, } } @@ -142,14 +142,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: v.id, attrs: &v.attrs, def: &v.data, - whence: v.span, + span: v.span, }) .collect(), vis: &it.vis, generics, attrs: &it.attrs, id: it.hir_id, - whence: it.span, + span: it.span, } } @@ -208,7 +208,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { kind, helpers, attrs: &item.attrs, - whence: item.span, + span: item.span, }); } None => { @@ -218,7 +218,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, decl, name, - whence: item.span, + span: item.span, generics, header, body, @@ -402,7 +402,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { path: orig_name.map(|x| x.to_string()), vis: &item.vis, attrs: &item.attrs, - whence: item.span, + span: item.span, }) } hir::ItemKind::Use(_, hir::UseKind::ListStem) => {} @@ -444,7 +444,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, path, glob: is_glob, - whence: item.span, + span: item.span, }); } hir::ItemKind::Mod(ref m) => { @@ -476,7 +476,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { name: ident.name, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.typedefs.push(t); @@ -487,7 +487,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { name: ident.name, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.opaque_tys.push(t); @@ -500,7 +500,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: item.hir_id, name: ident.name, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.statics.push(s); @@ -515,7 +515,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: item.hir_id, name: ident.name, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.constants.push(s); @@ -532,7 +532,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { bounds, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.traits.push(t); @@ -544,7 +544,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { bounds, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.trait_aliases.push(t); @@ -577,7 +577,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { items, attrs: &item.attrs, id: item.hir_id, - whence: item.span, + span: item.span, vis: &item.vis, }; om.impls.push(i); @@ -603,7 +603,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { kind: &item.kind, vis: &item.vis, attrs: &item.attrs, - whence: item.span, + span: item.span, }); } @@ -623,7 +623,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { def_id: self.cx.tcx.hir().local_def_id(def.hir_id).to_def_id(), attrs: &def.attrs, name: renamed.unwrap_or(def.ident.name), - whence: def.span, + span: def.span, matchers, imported_from: None, } diff --git a/src/stage0.txt b/src/stage0.txt index 67c19a3380..2f34956479 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,15 +12,15 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.(x+1).0` for Cargo where they were released on `date`. -date: 2020-08-27 -rustc: 1.46.0 -cargo: 0.47.0 +date: 2020-10-08 +rustc: 1.47.0 +cargo: 0.48.0 # We use a nightly rustfmt to format the source because it solves some # bootstrapping issues with use of new syntax in this repo. If you're looking at # the beta/stable branch, this key should be omitted, as we don't want to depend # on rustfmt from nightly there. -#rustfmt: nightly-2020-07-12 +# rustfmt: nightly-2020-07-12 # When making a stable release the process currently looks like: # diff --git a/src/test/assembly/asm/aarch64-types.rs b/src/test/assembly/asm/aarch64-types.rs index e39f74c916..8dd1f3c873 100644 --- a/src/test/assembly/asm/aarch64-types.rs +++ b/src/test/assembly/asm/aarch64-types.rs @@ -96,6 +96,17 @@ pub unsafe fn sym_static() { asm!("adr x0, {}", sym extern_static); } +// Regression test for #75761 +// CHECK-LABEL: issue_75761: +// CHECK: str {{.*}}x30 +// CHECK: //APP +// CHECK: //NO_APP +// CHECK: ldr {{.*}}x30 +#[no_mangle] +pub unsafe fn issue_75761() { + asm!("", out("v0") _, out("x30") _); +} + macro_rules! check { ($func:ident $ty:ident $class:ident $mov:literal $modifier:literal) => { #[no_mangle] @@ -553,8 +564,3 @@ check_reg!(v0_f32x4 f32x4 "s0" "fmov"); // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_f64x2 f64x2 "s0" "fmov"); - -// Regression test for #75761 -pub unsafe fn issue_75761() { - asm!("", out("v0") _, out("x30") _); -} diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs new file mode 100644 index 0000000000..b195ed88c7 --- /dev/null +++ b/src/test/assembly/asm/mips-types.rs @@ -0,0 +1,191 @@ +// no-system-llvm +// assembly-output: emit-asm +// compile-flags: --target mips-unknown-linux-gnu +// needs-llvm-components: mips + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!("move {}, {}", out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!("move ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: lw $3, %got(extern_static) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + dont_merge(stringify!($func)); + + asm!("la $v1, {}", sym extern_static); +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: lw $3, %got(extern_func) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + dont_merge(stringify!($func)); + + asm!("la $v1, {}", sym extern_func); +} + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn reg_f32(x: f32) -> f32 { + dont_merge("reg_f32"); + let y; + asm!("mov.s {}, {}", out(freg) y, in(freg) x); + y +} + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: mov.s $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn f0_f32(x: f32) -> f32 { + dont_merge("f0_f32"); + let y; + asm!("mov.s $f0, $f0", lateout("$f0") y, in("$f0") x); + y +} + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg); + +// CHECK-LABEL: reg_f32_soft: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32_soft, f32, reg); + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg); + +// CHECK-LABEL: reg_u8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_u8, u8, reg); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg); + +// CHECK-LABEL: t0_ptr: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_ptr, ptr, "$t0"); + +// CHECK-LABEL: t0_i32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i32, i32, "$t0"); + +// CHECK-LABEL: t0_f32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_f32, f32, "$t0"); + +// CHECK-LABEL: t0_i8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i8, i8, "$t0"); + +// CHECK-LABEL: t0_u8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_u8, u8, "$t0"); + +// CHECK-LABEL: t0_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i16, i16, "$t0"); + +// CHECK-LABEL: r8_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i16, i16, "$8"); diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs new file mode 100644 index 0000000000..79d82cf70d --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -0,0 +1,17 @@ +// Test LVI load hardening on SGX enclave code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern fn plus_one(r: &mut u64) { + *r = *r + 1; +} + +// CHECK: plus_one +// CHECK: lfence +// CHECK-NEXT: addq +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs new file mode 100644 index 0000000000..a21ef6b758 --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs @@ -0,0 +1,12 @@ +// Test LVI ret hardening on generic rust code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern fn myret() {} +// CHECK: myret: +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs new file mode 100644 index 0000000000..7e440169ed --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs @@ -0,0 +1,41 @@ +// Test LVI load hardening on SGX inline assembly code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#![feature(asm)] + +#[no_mangle] +pub extern fn get(ptr: *const u64) -> u64 { + let value : u64; + unsafe { + asm!(".start_inline_asm:", + "mov {}, [{}]", + ".end_inline_asm:", + out(reg) value, + in(reg) ptr); + } + value +} + +// CHECK: get +// CHECK: .start_inline_asm +// CHECK-NEXT: movq +// CHECK-NEXT: lfence +// CHECK-NEXT: .end_inline_asm + +#[no_mangle] +pub extern fn myret() { + unsafe { + asm!(".start_myret_inline_asm: + ret + .end_myret_inline_asm:"); + } +} + +// CHECK: myret +// CHECK: .start_myret_inline_asm +// CHECK-NEXT: shlq $0, (%rsp) +// CHECK-NEXT: lfence +// CHECK-NEXT: retq diff --git a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs index e1991046d4..7289ceee95 100644 --- a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs +++ b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs @@ -6,15 +6,15 @@ // aux-build:cgu_generic_function.rs extern crate cgu_generic_function; -//~ MONO_ITEM fn cross_crate_generic_functions::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn cgu_generic_function::bar[0] - //~ MONO_ITEM fn cgu_generic_function::foo[0] + //~ MONO_ITEM fn cgu_generic_function::bar:: + //~ MONO_ITEM fn cgu_generic_function::foo:: let _ = cgu_generic_function::foo(1u32); - //~ MONO_ITEM fn cgu_generic_function::bar[0] - //~ MONO_ITEM fn cgu_generic_function::foo[0] + //~ MONO_ITEM fn cgu_generic_function::bar:: + //~ MONO_ITEM fn cgu_generic_function::foo:: let _ = cgu_generic_function::foo(2u64); // This should not introduce a codegen item diff --git a/src/test/codegen-units/item-collection/cross-crate-trait-method.rs b/src/test/codegen-units/item-collection/cross-crate-trait-method.rs index 442438b64b..dc0984c8a9 100644 --- a/src/test/codegen-units/item-collection/cross-crate-trait-method.rs +++ b/src/test/codegen-units/item-collection/cross-crate-trait-method.rs @@ -8,7 +8,7 @@ extern crate cgu_export_trait_method; use cgu_export_trait_method::Trait; -//~ MONO_ITEM fn cross_crate_trait_method::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { // The object code of these methods is contained in the external crate, so @@ -19,31 +19,31 @@ fn start(_: isize, _: *const *const u8) -> isize { // Currently, no object code is generated for trait methods with default // implementations, unless they are actually called from somewhere. Therefore // we cannot import the implementations and have to create our own inline. - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] + //~ MONO_ITEM fn ::with_default_impl let _ = Trait::with_default_impl(0u32); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] + //~ MONO_ITEM fn ::with_default_impl let _ = Trait::with_default_impl('c'); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn ::with_default_impl_generic::<&str> let _ = Trait::with_default_impl_generic(0u32, "abc"); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn ::with_default_impl_generic:: let _ = Trait::with_default_impl_generic(0u32, false); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn ::with_default_impl_generic:: let _ = Trait::with_default_impl_generic('x', 1i16); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn ::with_default_impl_generic:: let _ = Trait::with_default_impl_generic('y', 0i32); - //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] + //~ MONO_ITEM fn ::without_default_impl_generic:: let _: (u32, char) = Trait::without_default_impl_generic('c'); - //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] + //~ MONO_ITEM fn ::without_default_impl_generic:: let _: (u32, bool) = Trait::without_default_impl_generic(false); - //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] + //~ MONO_ITEM fn ::without_default_impl_generic:: let _: (char, char) = Trait::without_default_impl_generic('c'); - //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] + //~ MONO_ITEM fn ::without_default_impl_generic:: let _: (char, bool) = Trait::without_default_impl_generic(false); 0 diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs index 27fb3cb138..adde5745fe 100644 --- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs +++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -4,19 +4,19 @@ #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ drop_in_place_intrinsic-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(StructWithDtor)) @@ drop_in_place_intrinsic-cgu.0[Internal] struct StructWithDtor(u32); impl Drop for StructWithDtor { - //~ MONO_ITEM fn drop_in_place_intrinsic::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } -//~ MONO_ITEM fn drop_in_place_intrinsic::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<[StructWithDtor; 2]> - shim(Some([StructWithDtor; 2])) @@ drop_in_place_intrinsic-cgu.0[Internal] let x = [StructWithDtor(0), StructWithDtor(1)]; drop_slice_in_place(&x); @@ -24,13 +24,13 @@ fn start(_: isize, _: *const *const u8) -> isize { 0 } -//~ MONO_ITEM fn drop_in_place_intrinsic::drop_slice_in_place[0] +//~ MONO_ITEM fn drop_slice_in_place fn drop_slice_in_place(x: &[StructWithDtor]) { unsafe { // This is the interesting thing in this test case: Normally we would // not have drop-glue for the unsized [StructWithDtor]. This has to be // generated though when the drop_in_place() intrinsic is used. - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic-cgu.0[Internal] - ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]); + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<[StructWithDtor]> - shim(Some([StructWithDtor])) @@ drop_in_place_intrinsic-cgu.0[Internal] + ::std::intrinsics::drop_in_place(x as *const _ as *mut [StructWithDtor]); } } diff --git a/src/test/codegen-units/item-collection/function-as-argument.rs b/src/test/codegen-units/item-collection/function-as-argument.rs index 3f61f124d2..2329dec385 100644 --- a/src/test/codegen-units/item-collection/function-as-argument.rs +++ b/src/test/codegen-units/item-collection/function-as-argument.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] @@ -13,26 +14,26 @@ fn take_fn_pointer(f: fn(T1, T2), x: T1, y: T2) { (f)(x, y) } -//~ MONO_ITEM fn function_as_argument::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn function_as_argument::take_fn_once[0] - //~ MONO_ITEM fn function_as_argument::function[0] - //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] + //~ MONO_ITEM fn take_fn_once::}> + //~ MONO_ITEM fn function:: + //~ MONO_ITEM fn } as std::ops::FnOnce<(u32, &str)>>::call_once - shim(fn(u32, &str) {function::}) take_fn_once(function, 0u32, "abc"); - //~ MONO_ITEM fn function_as_argument::take_fn_once[0] - //~ MONO_ITEM fn function_as_argument::function[0] - //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] + //~ MONO_ITEM fn take_fn_once::}> + //~ MONO_ITEM fn function:: + //~ MONO_ITEM fn } as std::ops::FnOnce<(char, f64)>>::call_once - shim(fn(char, f64) {function::}) take_fn_once(function, 'c', 0f64); - //~ MONO_ITEM fn function_as_argument::take_fn_pointer[0] - //~ MONO_ITEM fn function_as_argument::function[0] + //~ MONO_ITEM fn take_fn_pointer:: + //~ MONO_ITEM fn function:: take_fn_pointer(function, 0i32, ()); - //~ MONO_ITEM fn function_as_argument::take_fn_pointer[0] - //~ MONO_ITEM fn function_as_argument::function[0] + //~ MONO_ITEM fn take_fn_pointer:: + //~ MONO_ITEM fn function:: take_fn_pointer(function, 0f32, 0i64); 0 diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs index 675bdfdb4d..45e4a0d6d7 100644 --- a/src/test/codegen-units/item-collection/generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs @@ -37,22 +37,22 @@ enum EnumNoDrop { struct NonGenericNoDrop(i32); struct NonGenericWithDrop(i32); -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ generic_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(NonGenericWithDrop)) @@ generic_drop_glue-cgu.0[Internal] impl Drop for NonGenericWithDrop { - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } -//~ MONO_ITEM fn generic_drop_glue::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(StructWithDrop)) @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = StructWithDrop { x: 0i8, y: 'a' }.x; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(StructWithDrop<&str, NonGenericNoDrop>)) @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y; // Should produce no drop glue @@ -60,18 +60,18 @@ fn start(_: isize, _: *const *const u8) -> isize { // This is supposed to generate drop-glue because it contains a field that // needs to be dropped. - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(StructNoDrop)) @@ generic_drop_glue-cgu.0[Internal] let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(EnumWithDrop)) @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = match EnumWithDrop::A::(0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as i32 }; - //~MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(EnumWithDrop)) @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = match EnumWithDrop::B::(1.0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as f64 diff --git a/src/test/codegen-units/item-collection/generic-functions.rs b/src/test/codegen-units/item-collection/generic-functions.rs index 8390970420..04383bb8ed 100644 --- a/src/test/codegen-units/item-collection/generic-functions.rs +++ b/src/test/codegen-units/item-collection/generic-functions.rs @@ -16,39 +16,39 @@ fn foo3(a: T1, b: T2, c: T3) -> (T1, T2, T3) { } // This function should be instantiated even if no used -//~ MONO_ITEM fn generic_functions::lifetime_only[0] +//~ MONO_ITEM fn lifetime_only pub fn lifetime_only<'a>(a: &'a u32) -> &'a u32 { a } -//~ MONO_ITEM fn generic_functions::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn generic_functions::foo1[0] + //~ MONO_ITEM fn foo1:: let _ = foo1(2i32); - //~ MONO_ITEM fn generic_functions::foo1[0] + //~ MONO_ITEM fn foo1:: let _ = foo1(2i64); - //~ MONO_ITEM fn generic_functions::foo1[0]<&str> + //~ MONO_ITEM fn foo1::<&str> let _ = foo1("abc"); - //~ MONO_ITEM fn generic_functions::foo1[0] + //~ MONO_ITEM fn foo1:: let _ = foo1('v'); - //~ MONO_ITEM fn generic_functions::foo2[0] + //~ MONO_ITEM fn foo2:: let _ = foo2(2i32, 2i32); - //~ MONO_ITEM fn generic_functions::foo2[0] + //~ MONO_ITEM fn foo2:: let _ = foo2(2i64, "abc"); - //~ MONO_ITEM fn generic_functions::foo2[0]<&str, usize> + //~ MONO_ITEM fn foo2::<&str, usize> let _ = foo2("a", 2usize); - //~ MONO_ITEM fn generic_functions::foo2[0] + //~ MONO_ITEM fn foo2:: let _ = foo2('v', ()); - //~ MONO_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn foo3:: let _ = foo3(2i32, 2i32, 2i32); - //~ MONO_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn foo3:: let _ = foo3(2i64, "abc", 'c'); - //~ MONO_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn foo3:: let _ = foo3(0i16, "a", 2usize); - //~ MONO_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn foo3:: let _ = foo3('v', (), ()); 0 diff --git a/src/test/codegen-units/item-collection/generic-impl.rs b/src/test/codegen-units/item-collection/generic-impl.rs index 571bb4fa86..dd5367ef03 100644 --- a/src/test/codegen-units/item-collection/generic-impl.rs +++ b/src/test/codegen-units/item-collection/generic-impl.rs @@ -30,41 +30,41 @@ pub struct LifeTimeOnly<'a> { impl<'a> LifeTimeOnly<'a> { - //~ MONO_ITEM fn generic_impl::{{impl}}[1]::foo[0] + //~ MONO_ITEM fn LifeTimeOnly::foo pub fn foo(&self) {} - //~ MONO_ITEM fn generic_impl::{{impl}}[1]::bar[0] + //~ MONO_ITEM fn LifeTimeOnly::bar pub fn bar(&'a self) {} - //~ MONO_ITEM fn generic_impl::{{impl}}[1]::baz[0] + //~ MONO_ITEM fn LifeTimeOnly::baz pub fn baz<'b>(&'b self) {} pub fn non_instantiated(&self) {} } -//~ MONO_ITEM fn generic_impl::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0] - //~ MONO_ITEM fn generic_impl::id[0] - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0] + //~ MONO_ITEM fn Struct::::new + //~ MONO_ITEM fn id:: + //~ MONO_ITEM fn Struct::::get:: let _ = Struct::new(0i32).get(0i16); - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0] - //~ MONO_ITEM fn generic_impl::id[0] - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0] + //~ MONO_ITEM fn Struct::::new + //~ MONO_ITEM fn id:: + //~ MONO_ITEM fn Struct::::get:: let _ = Struct::new(0i64).get(0i16); - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0] - //~ MONO_ITEM fn generic_impl::id[0] - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0] + //~ MONO_ITEM fn Struct::::new + //~ MONO_ITEM fn id:: + //~ MONO_ITEM fn Struct::::get:: let _ = Struct::new('c').get(0i16); - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0]<&str> - //~ MONO_ITEM fn generic_impl::id[0]<&str> - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0], i16> + //~ MONO_ITEM fn Struct::<&str>::new + //~ MONO_ITEM fn id::<&str> + //~ MONO_ITEM fn Struct::>::get:: let _ = Struct::new(Struct::new("str")).get(0i16); - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0]> - //~ MONO_ITEM fn generic_impl::id[0]> + //~ MONO_ITEM fn Struct::>::new + //~ MONO_ITEM fn id::> let _ = (Struct::new(Struct::new("str")).f)(Struct::new("str")); 0 diff --git a/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs b/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs index e45644cd37..c01398eb23 100644 --- a/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs +++ b/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs @@ -11,14 +11,14 @@ trait SomeTrait { // discovered. pub fn generic_function(x: T) -> (T, i32) { impl SomeTrait for i64 { - //~ MONO_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn generic_function::::foo fn foo(&self) {} } (x, 0) } -//~ MONO_ITEM fn impl_in_non_instantiated_generic::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { 0i64.foo(); diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index db0390b58c..63966a7ec9 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -19,20 +19,20 @@ impl Trait for Struct { fn bar(&self) {} } -//~ MONO_ITEM fn instantiation_through_vtable::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { let s1 = Struct { _a: 0u32 }; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable-cgu.0[Internal] - //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] - //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal] + //~ MONO_ITEM fn as Trait>::foo + //~ MONO_ITEM fn as Trait>::bar let _ = &s1 as &Trait; let s1 = Struct { _a: 0u64 }; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable-cgu.0[Internal] - //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] - //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal] + //~ MONO_ITEM fn as Trait>::foo + //~ MONO_ITEM fn as Trait>::bar let _ = &s1 as &Trait; 0 diff --git a/src/test/codegen-units/item-collection/items-within-generic-items.rs b/src/test/codegen-units/item-collection/items-within-generic-items.rs index 10bc52f6a8..d37d7f7d9b 100644 --- a/src/test/codegen-units/item-collection/items-within-generic-items.rs +++ b/src/test/codegen-units/item-collection/items-within-generic-items.rs @@ -4,13 +4,13 @@ #![feature(start)] fn generic_fn(a: T) -> (T, i32) { - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[0] + //~ MONO_ITEM fn generic_fn::nested_fn fn nested_fn(a: i32) -> i32 { a + 1 } let x = { - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[1] + //~ MONO_ITEM fn generic_fn::nested_fn fn nested_fn(a: i32) -> i32 { a + 2 } @@ -21,14 +21,14 @@ fn generic_fn(a: T) -> (T, i32) { return (a, x + nested_fn(0)); } -//~ MONO_ITEM fn items_within_generic_items::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0] + //~ MONO_ITEM fn generic_fn:: let _ = generic_fn(0i64); - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0] + //~ MONO_ITEM fn generic_fn:: let _ = generic_fn(0u16); - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0] + //~ MONO_ITEM fn generic_fn:: let _ = generic_fn(0i8); 0 diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs index a899b8b2c8..b583771681 100644 --- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs @@ -5,13 +5,13 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(StructWithDrop)) @@ non_generic_drop_glue-cgu.0[Internal] struct StructWithDrop { x: i32 } impl Drop for StructWithDrop { - //~ MONO_ITEM fn non_generic_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } @@ -19,13 +19,13 @@ struct StructNoDrop { x: i32 } -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(EnumWithDrop)) @@ non_generic_drop_glue-cgu.0[Internal] enum EnumWithDrop { A(i32) } impl Drop for EnumWithDrop { - //~ MONO_ITEM fn non_generic_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } @@ -33,7 +33,7 @@ enum EnumNoDrop { A(i32) } -//~ MONO_ITEM fn non_generic_drop_glue::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { let _ = StructWithDrop { x: 0 }.x; diff --git a/src/test/codegen-units/item-collection/non-generic-functions.rs b/src/test/codegen-units/item-collection/non-generic-functions.rs index 26d2fb1b42..092e64562c 100644 --- a/src/test/codegen-units/item-collection/non-generic-functions.rs +++ b/src/test/codegen-units/item-collection/non-generic-functions.rs @@ -3,24 +3,24 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn non_generic_functions::foo[0] +//~ MONO_ITEM fn foo fn foo() { { - //~ MONO_ITEM fn non_generic_functions::foo[0]::foo[0] + //~ MONO_ITEM fn foo::foo fn foo() {} foo(); } { - //~ MONO_ITEM fn non_generic_functions::foo[0]::foo[1] + //~ MONO_ITEM fn foo::foo fn foo() {} foo(); } } -//~ MONO_ITEM fn non_generic_functions::bar[0] +//~ MONO_ITEM fn bar fn bar() { - //~ MONO_ITEM fn non_generic_functions::bar[0]::baz[0] + //~ MONO_ITEM fn bar::baz fn baz() {} baz(); } @@ -28,38 +28,38 @@ fn bar() { struct Struct { _x: i32 } impl Struct { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn Struct::foo fn foo() { { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[0] + //~ MONO_ITEM fn Struct::foo::foo fn foo() {} foo(); } { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[1] + //~ MONO_ITEM fn Struct::foo::foo fn foo() {} foo(); } } - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::bar[0] + //~ MONO_ITEM fn Struct::bar fn bar(&self) { { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[0] + //~ MONO_ITEM fn Struct::bar::foo fn foo() {} foo(); } { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[1] + //~ MONO_ITEM fn Struct::bar::foo fn foo() {} foo(); } } } -//~ MONO_ITEM fn non_generic_functions::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { foo(); diff --git a/src/test/codegen-units/item-collection/overloaded-operators.rs b/src/test/codegen-units/item-collection/overloaded-operators.rs index 0b4c97723d..2be7eba1d8 100644 --- a/src/test/codegen-units/item-collection/overloaded-operators.rs +++ b/src/test/codegen-units/item-collection/overloaded-operators.rs @@ -12,7 +12,7 @@ pub struct Indexable { impl Index for Indexable { type Output = u8; - //~ MONO_ITEM fn overloaded_operators::{{impl}}[0]::index[0] + //~ MONO_ITEM fn >::index fn index(&self, index: usize) -> &Self::Output { if index >= 3 { &self.data[0] @@ -23,7 +23,7 @@ impl Index for Indexable { } impl IndexMut for Indexable { - //~ MONO_ITEM fn overloaded_operators::{{impl}}[1]::index_mut[0] + //~ MONO_ITEM fn >::index_mut fn index_mut(&mut self, index: usize) -> &mut Self::Output { if index >= 3 { &mut self.data[0] @@ -34,8 +34,8 @@ impl IndexMut for Indexable { } -//~ MONO_ITEM fn overloaded_operators::{{impl}}[5]::eq[0] -//~ MONO_ITEM fn overloaded_operators::{{impl}}[5]::ne[0] +//~ MONO_ITEM fn ::eq +//~ MONO_ITEM fn ::ne #[derive(PartialEq)] pub struct Equatable(u32); @@ -43,7 +43,7 @@ pub struct Equatable(u32); impl Add for Equatable { type Output = u32; - //~ MONO_ITEM fn overloaded_operators::{{impl}}[2]::add[0] + //~ MONO_ITEM fn >::add fn add(self, rhs: u32) -> u32 { self.0 + rhs } @@ -52,7 +52,7 @@ impl Add for Equatable { impl Deref for Equatable { type Target = u32; - //~ MONO_ITEM fn overloaded_operators::{{impl}}[3]::deref[0] + //~ MONO_ITEM fn ::deref fn deref(&self) -> &Self::Target { &self.0 } diff --git a/src/test/codegen-units/item-collection/static-init.rs b/src/test/codegen-units/item-collection/static-init.rs index 9d79171c4c..287ec8f24e 100644 --- a/src/test/codegen-units/item-collection/static-init.rs +++ b/src/test/codegen-units/item-collection/static-init.rs @@ -6,10 +6,10 @@ pub static FN : fn() = foo::; pub fn foo() { } -//~ MONO_ITEM fn static_init::foo[0] -//~ MONO_ITEM static static_init::FN[0] +//~ MONO_ITEM fn foo:: +//~ MONO_ITEM static FN -//~ MONO_ITEM fn static_init::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { 0 diff --git a/src/test/codegen-units/item-collection/statics-and-consts.rs b/src/test/codegen-units/item-collection/statics-and-consts.rs index 7e28ba58b6..49a8d3dff6 100644 --- a/src/test/codegen-units/item-collection/statics-and-consts.rs +++ b/src/test/codegen-units/item-collection/statics-and-consts.rs @@ -37,7 +37,7 @@ fn foo() { }; } -//~ MONO_ITEM fn statics_and_consts::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { foo(); @@ -46,9 +46,9 @@ fn start(_: isize, _: *const *const u8) -> isize { 0 } -//~ MONO_ITEM static statics_and_consts::STATIC1[0] +//~ MONO_ITEM static STATIC1 -//~ MONO_ITEM fn statics_and_consts::foo[0] -//~ MONO_ITEM static statics_and_consts::foo[0]::STATIC2[0] -//~ MONO_ITEM static statics_and_consts::foo[0]::STATIC2[1] -//~ MONO_ITEM static statics_and_consts::foo[0]::STATIC2[2] +//~ MONO_ITEM fn foo +//~ MONO_ITEM static foo::STATIC2 +//~ MONO_ITEM static foo::STATIC2 +//~ MONO_ITEM static foo::STATIC2 diff --git a/src/test/codegen-units/item-collection/trait-implementations.rs b/src/test/codegen-units/item-collection/trait-implementations.rs index f090c0c8d1..a816cb0324 100644 --- a/src/test/codegen-units/item-collection/trait-implementations.rs +++ b/src/test/codegen-units/item-collection/trait-implementations.rs @@ -10,7 +10,7 @@ pub trait SomeTrait { impl SomeTrait for i64 { - //~ MONO_ITEM fn trait_implementations::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn ::foo fn foo(&self) {} fn bar(&self, _: T) {} @@ -18,7 +18,7 @@ impl SomeTrait for i64 { impl SomeTrait for i32 { - //~ MONO_ITEM fn trait_implementations::{{impl}}[1]::foo[0] + //~ MONO_ITEM fn ::foo fn foo(&self) {} fn bar(&self, _: T) {} @@ -32,7 +32,7 @@ pub trait SomeGenericTrait { // Concrete impl of generic trait impl SomeGenericTrait for f64 { - //~ MONO_ITEM fn trait_implementations::{{impl}}[2]::foo[0] + //~ MONO_ITEM fn >::foo fn foo(&self, _: u32) {} fn bar(&self, _: u32, _: T2) {} @@ -45,28 +45,28 @@ impl SomeGenericTrait for f32 { fn bar(&self, _: T, _: T2) {} } -//~ MONO_ITEM fn trait_implementations::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn trait_implementations::{{impl}}[1]::bar[0] + //~ MONO_ITEM fn ::bar:: 0i32.bar('x'); - //~ MONO_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<&str> + //~ MONO_ITEM fn >::bar::<&str> 0f64.bar(0u32, "&str"); - //~ MONO_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<()> + //~ MONO_ITEM fn >::bar::<()> 0f64.bar(0u32, ()); - //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::foo[0] + //~ MONO_ITEM fn >::foo 0f32.foo('x'); - //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::foo[0] + //~ MONO_ITEM fn >::foo 0f32.foo(-1i64); - //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::bar[0] + //~ MONO_ITEM fn >::bar::<()> 0f32.bar(0u32, ()); - //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<&str, &str> + //~ MONO_ITEM fn >::bar::<&str> 0f32.bar("&str", "&str"); 0 diff --git a/src/test/codegen-units/item-collection/trait-method-as-argument.rs b/src/test/codegen-units/item-collection/trait-method-as-argument.rs index 27ace8e31a..6817b33c61 100644 --- a/src/test/codegen-units/item-collection/trait-method-as-argument.rs +++ b/src/test/codegen-units/item-collection/trait-method-as-argument.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] @@ -26,33 +27,33 @@ fn take_foo_mut T>(mut f: F, arg: T) -> T { (f)(arg) } -//~ MONO_ITEM fn trait_method_as_argument::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn trait_method_as_argument::take_foo_once[0] u32> - //~ MONO_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0] - //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] u32, (u32)> + //~ MONO_ITEM fn take_foo_once:: u32 {::foo}> + //~ MONO_ITEM fn ::foo + //~ MONO_ITEM fn u32 {::foo} as std::ops::FnOnce<(u32,)>>::call_once - shim(fn(u32) -> u32 {::foo}) take_foo_once(Trait::foo, 0u32); - //~ MONO_ITEM fn trait_method_as_argument::take_foo_once[0] char> - //~ MONO_ITEM fn trait_method_as_argument::Trait[0]::foo[0] - //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] char, (char)> + //~ MONO_ITEM fn take_foo_once:: char {::foo}> + //~ MONO_ITEM fn ::foo + //~ MONO_ITEM fn char {::foo} as std::ops::FnOnce<(char,)>>::call_once - shim(fn(char) -> char {::foo}) take_foo_once(Trait::foo, 'c'); - //~ MONO_ITEM fn trait_method_as_argument::take_foo[0] u32> - //~ MONO_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] u32, (u32)> + //~ MONO_ITEM fn take_foo:: u32 {::foo}> + //~ MONO_ITEM fn u32 {::foo} as std::ops::Fn<(u32,)>>::call - shim(fn(u32) -> u32 {::foo}) take_foo(Trait::foo, 0u32); - //~ MONO_ITEM fn trait_method_as_argument::take_foo[0] char> - //~ MONO_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] char, (char)> + //~ MONO_ITEM fn take_foo:: char {::foo}> + //~ MONO_ITEM fn char {::foo} as std::ops::Fn<(char,)>>::call - shim(fn(char) -> char {::foo}) take_foo(Trait::foo, 'c'); - //~ MONO_ITEM fn trait_method_as_argument::take_foo_mut[0] u32> - //~ MONO_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] char, (char)> + //~ MONO_ITEM fn take_foo_mut:: u32 {::foo}> + //~ MONO_ITEM fn u32 {::foo} as std::ops::FnMut<(u32,)>>::call_mut - shim(fn(u32) -> u32 {::foo}) take_foo_mut(Trait::foo, 0u32); - //~ MONO_ITEM fn trait_method_as_argument::take_foo_mut[0] char> - //~ MONO_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] u32, (u32)> + //~ MONO_ITEM fn take_foo_mut:: char {::foo}> + //~ MONO_ITEM fn char {::foo} as std::ops::FnMut<(char,)>>::call_mut - shim(fn(char) -> char {::foo}) take_foo_mut(Trait::foo, 'c'); 0 diff --git a/src/test/codegen-units/item-collection/trait-method-default-impl.rs b/src/test/codegen-units/item-collection/trait-method-default-impl.rs index 6cf59fdc39..bfcdb6fa14 100644 --- a/src/test/codegen-units/item-collection/trait-method-default-impl.rs +++ b/src/test/codegen-units/item-collection/trait-method-default-impl.rs @@ -13,7 +13,7 @@ impl SomeTrait for i8 { // For the non-generic foo(), we should generate a codegen-item even if it // is not called anywhere - //~ MONO_ITEM fn trait_method_default_impl::SomeTrait[0]::foo[0] + //~ MONO_ITEM fn ::foo } trait SomeGenericTrait { @@ -27,7 +27,7 @@ impl SomeGenericTrait for i32 { // For the non-generic foo(), we should generate a codegen-item even if it // is not called anywhere - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0] + //~ MONO_ITEM fn >::foo } // Non-generic impl of generic trait @@ -36,25 +36,25 @@ impl SomeGenericTrait for u32 { // since nothing is monomorphic here, nothing should be generated unless used somewhere. } -//~ MONO_ITEM fn trait_method_default_impl::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0] + //~ MONO_ITEM fn ::bar:: let _ = 1i8.bar('c'); - //~ MONO_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0] + //~ MONO_ITEM fn ::bar::<&str> let _ = 2i8.bar("&str"); - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn >::bar:: 0i32.bar(0u64, 'c'); - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn >::bar::<&str> 0i32.bar(0u64, "&str"); - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn >::bar::<&[char; 1]> 0u32.bar(0i8, &['c']); - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn >::bar::<()> 0u32.bar(0i16, ()); 0 diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs index 7e29af4353..c0489a6a25 100644 --- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs +++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs @@ -5,15 +5,15 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Root)) @@ transitive_drop_glue-cgu.0[Internal] struct Root(Intermediate); -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Intermediate)) @@ transitive_drop_glue-cgu.0[Internal] struct Intermediate(Leaf); -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Leaf)) @@ transitive_drop_glue-cgu.0[Internal] struct Leaf; impl Drop for Leaf { - //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } @@ -25,21 +25,21 @@ impl Drop for LeafGen { fn drop(&mut self) {} } -//~ MONO_ITEM fn transitive_drop_glue::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { let _ = Root(Intermediate(Leaf)); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(RootGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(IntermediateGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(LeafGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = RootGen(IntermediateGen(LeafGen(0u32))); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(RootGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(IntermediateGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(LeafGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = RootGen(IntermediateGen(LeafGen(0i16))); 0 diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs index d77de53ce0..d34835ae69 100644 --- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs +++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs @@ -5,22 +5,22 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ tuple_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Dropped)) @@ tuple_drop_glue-cgu.0[Internal] struct Dropped; impl Drop for Dropped { - //~ MONO_ITEM fn tuple_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } -//~ MONO_ITEM fn tuple_drop_glue::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<(u32, Dropped)> - shim(Some((u32, Dropped))) @@ tuple_drop_glue-cgu.0[Internal] let x = (0u32, Dropped); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<(i16, (Dropped, bool))> - shim(Some((i16, (Dropped, bool)))) @@ tuple_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<(Dropped, bool)> - shim(Some((Dropped, bool))) @@ tuple_drop_glue-cgu.0[Internal] let x = (0i16, (Dropped, true)); 0 diff --git a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs index ec6be0ecf4..17b92eae00 100644 --- a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs +++ b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs @@ -3,7 +3,7 @@ #![deny(dead_code)] #![crate_type = "rlib"] -//~ MONO_ITEM fn unreferenced_const_fn::foo[0] @@ unreferenced_const_fn-cgu.0[External] +//~ MONO_ITEM fn foo @@ unreferenced_const_fn-cgu.0[External] pub const fn foo(x: u32) -> u32 { x + 0xf00 } diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index 1ed60dcf26..9421bf106b 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -43,19 +43,19 @@ struct Wrapper(*const T); impl, U: ?Sized> CoerceUnsized> for Wrapper {} -//~ MONO_ITEM fn unsizing::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { // simple case let bool_sized = &true; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] - //~ MONO_ITEM fn unsizing::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn ::foo let _bool_unsized = bool_sized as &Trait; let char_sized = &'a'; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] - //~ MONO_ITEM fn unsizing::{{impl}}[1]::foo[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn ::foo let _char_unsized = char_sized as &Trait; // struct field @@ -64,14 +64,14 @@ fn start(_: isize, _: *const *const u8) -> isize { _b: 2, _c: 3.0f64 }; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] - //~ MONO_ITEM fn unsizing::{{impl}}[2]::foo[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn ::foo let _struct_unsized = struct_sized as &Struct; // custom coercion let wrapper_sized = Wrapper(&0u32); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] - //~ MONO_ITEM fn unsizing::{{impl}}[3]::foo[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn ::foo let _wrapper_sized = wrapper_sized as Wrapper; 0 diff --git a/src/test/codegen-units/item-collection/unused-traits-and-generics.rs b/src/test/codegen-units/item-collection/unused-traits-and-generics.rs index 4a5e294ea0..561dc1a5c0 100644 --- a/src/test/codegen-units/item-collection/unused-traits-and-generics.rs +++ b/src/test/codegen-units/item-collection/unused-traits-and-generics.rs @@ -74,4 +74,4 @@ impl NonGeneric { } // Only the non-generic methods should be instantiated: -//~ MONO_ITEM fn unused_traits_and_generics::{{impl}}[3]::foo[0] +//~ MONO_ITEM fn NonGeneric::foo diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index 1cb8538223..3de1bdb86c 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -12,13 +12,13 @@ // aux-build:cgu_extern_drop_glue.rs extern crate cgu_extern_drop_glue; -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-fallback.cgu[External] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(cgu_extern_drop_glue::Struct)) @@ extern_drop_glue-fallback.cgu[External] struct LocalStruct(cgu_extern_drop_glue::Struct); -//~ MONO_ITEM fn extern_drop_glue::user[0] @@ extern_drop_glue[External] +//~ MONO_ITEM fn user @@ extern_drop_glue[External] pub fn user() { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-fallback.cgu[External] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(LocalStruct)) @@ extern_drop_glue-fallback.cgu[External] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } @@ -27,9 +27,9 @@ pub mod mod1 { struct LocalStruct(cgu_extern_drop_glue::Struct); - //~ MONO_ITEM fn extern_drop_glue::mod1[0]::user[0] @@ extern_drop_glue-mod1[External] + //~ MONO_ITEM fn mod1::user @@ extern_drop_glue-mod1[External] pub fn user() { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-fallback.cgu[External] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(mod1::LocalStruct)) @@ extern_drop_glue-fallback.cgu[External] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } } diff --git a/src/test/codegen-units/partitioning/extern-generic.rs b/src/test/codegen-units/partitioning/extern-generic.rs index 88d6116a98..02930f96bd 100644 --- a/src/test/codegen-units/partitioning/extern-generic.rs +++ b/src/test/codegen-units/partitioning/extern-generic.rs @@ -9,7 +9,7 @@ // aux-build:cgu_generic_function.rs extern crate cgu_generic_function; -//~ MONO_ITEM fn extern_generic::user[0] @@ extern_generic[Internal] +//~ MONO_ITEM fn user @@ extern_generic[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } @@ -17,7 +17,7 @@ fn user() { mod mod1 { use cgu_generic_function; - //~ MONO_ITEM fn extern_generic::mod1[0]::user[0] @@ extern_generic-mod1[Internal] + //~ MONO_ITEM fn mod1::user @@ extern_generic-mod1[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } @@ -25,7 +25,7 @@ mod mod1 { mod mod1 { use cgu_generic_function; - //~ MONO_ITEM fn extern_generic::mod1[0]::mod1[0]::user[0] @@ extern_generic-mod1-mod1[Internal] + //~ MONO_ITEM fn mod1::mod1::user @@ extern_generic-mod1-mod1[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } @@ -35,18 +35,18 @@ mod mod1 { mod mod2 { use cgu_generic_function; - //~ MONO_ITEM fn extern_generic::mod2[0]::user[0] @@ extern_generic-mod2[Internal] + //~ MONO_ITEM fn mod2::user @@ extern_generic-mod2[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } } mod mod3 { - //~ MONO_ITEM fn extern_generic::mod3[0]::non_user[0] @@ extern_generic-mod3[Internal] + //~ MONO_ITEM fn mod3::non_user @@ extern_generic-mod3[Internal] fn non_user() {} } // Make sure the two generic functions from the extern crate get instantiated // once for the current crate -//~ MONO_ITEM fn cgu_generic_function::foo[0]<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] -//~ MONO_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] +//~ MONO_ITEM fn cgu_generic_function::foo::<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] +//~ MONO_ITEM fn cgu_generic_function::bar::<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] diff --git a/src/test/codegen-units/partitioning/incremental-merging.rs b/src/test/codegen-units/partitioning/incremental-merging.rs index ca2df19096..91ae602293 100644 --- a/src/test/codegen-units/partitioning/incremental-merging.rs +++ b/src/test/codegen-units/partitioning/incremental-merging.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // We specify -C incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/incremental-merging @@ -14,28 +13,28 @@ // while `ccc` and `ddd` are supposed to stay untouched. pub mod aaa { - //~ MONO_ITEM fn incremental_merging::aaa[0]::foo[0] @@ incremental_merging-aaa--incremental_merging-bbb[External] + //~ MONO_ITEM fn aaa::foo @@ incremental_merging-aaa--incremental_merging-bbb[External] pub fn foo(a: u64) -> u64 { a + 1 } } pub mod bbb { - //~ MONO_ITEM fn incremental_merging::bbb[0]::foo[0] @@ incremental_merging-aaa--incremental_merging-bbb[External] + //~ MONO_ITEM fn bbb::foo @@ incremental_merging-aaa--incremental_merging-bbb[External] pub fn foo(a: u64, b: u64) -> u64 { a + b + 1 } } pub mod ccc { - //~ MONO_ITEM fn incremental_merging::ccc[0]::foo[0] @@ incremental_merging-ccc[External] + //~ MONO_ITEM fn ccc::foo @@ incremental_merging-ccc[External] pub fn foo(a: u64, b: u64, c: u64) -> u64 { a + b + c + 1 } } pub mod ddd { - //~ MONO_ITEM fn incremental_merging::ddd[0]::foo[0] @@ incremental_merging-ddd[External] + //~ MONO_ITEM fn ddd::foo @@ incremental_merging-ddd[External] pub fn foo(a: u64, b: u64, c: u64, d: u64) -> u64 { a + b + c + d + 1 } diff --git a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs index 7afeb0a0f3..410b77b005 100644 --- a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -12,10 +12,10 @@ extern crate cgu_explicit_inlining; // This test makes sure that items inlined from external crates are privately // instantiated in every codegen unit they are used in. -//~ MONO_ITEM fn cgu_explicit_inlining::inlined[0] @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod1[Internal] -//~ MONO_ITEM fn cgu_explicit_inlining::always_inlined[0] @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod2[Internal] +//~ MONO_ITEM fn cgu_explicit_inlining::inlined @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod1[Internal] +//~ MONO_ITEM fn cgu_explicit_inlining::always_inlined @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod2[Internal] -//~ MONO_ITEM fn inlining_from_extern_crate::user[0] @@ inlining_from_extern_crate[External] +//~ MONO_ITEM fn user @@ inlining_from_extern_crate[External] pub fn user() { cgu_explicit_inlining::inlined(); @@ -28,7 +28,7 @@ pub fn user() pub mod mod1 { use cgu_explicit_inlining; - //~ MONO_ITEM fn inlining_from_extern_crate::mod1[0]::user[0] @@ inlining_from_extern_crate-mod1[External] + //~ MONO_ITEM fn mod1::user @@ inlining_from_extern_crate-mod1[External] pub fn user() { cgu_explicit_inlining::inlined(); @@ -41,7 +41,7 @@ pub mod mod1 { pub mod mod2 { use cgu_explicit_inlining; - //~ MONO_ITEM fn inlining_from_extern_crate::mod2[0]::user[0] @@ inlining_from_extern_crate-mod2[External] + //~ MONO_ITEM fn mod2::user @@ inlining_from_extern_crate-mod2[External] pub fn user() { cgu_explicit_inlining::always_inlined(); diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index c082b40827..98108615ce 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -8,22 +8,22 @@ #![allow(dead_code)] #![crate_type = "rlib"] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-fallback.cgu[External] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Struct)) @@ local_drop_glue-fallback.cgu[External] struct Struct { _a: u32, } impl Drop for Struct { - //~ MONO_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue-fallback.cgu[External] + //~ MONO_ITEM fn ::drop @@ local_drop_glue-fallback.cgu[External] fn drop(&mut self) {} } -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-fallback.cgu[External] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Outer)) @@ local_drop_glue-fallback.cgu[External] struct Outer { _a: Struct, } -//~ MONO_ITEM fn local_drop_glue::user[0] @@ local_drop_glue[External] +//~ MONO_ITEM fn user @@ local_drop_glue[External] pub fn user() { let _ = Outer { _a: Struct { _a: 0 } }; } @@ -31,14 +31,14 @@ pub fn user() { pub mod mod1 { use super::Struct; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-fallback.cgu[External] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(mod1::Struct2)) @@ local_drop_glue-fallback.cgu[External] struct Struct2 { _a: Struct, - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, local_drop_glue::Struct[0])> @@ local_drop_glue-fallback.cgu[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<(u32, Struct)> - shim(Some((u32, Struct))) @@ local_drop_glue-fallback.cgu[Internal] _b: (u32, Struct), } - //~ MONO_ITEM fn local_drop_glue::mod1[0]::user[0] @@ local_drop_glue-mod1[External] + //~ MONO_ITEM fn mod1::user @@ local_drop_glue-mod1[External] pub fn user() { let _ = Struct2 { _a: Struct { _a: 0 }, _b: (0, Struct { _a: 0 }) }; } diff --git a/src/test/codegen-units/partitioning/local-generic.rs b/src/test/codegen-units/partitioning/local-generic.rs index 4518166a1c..9a7743bbf4 100644 --- a/src/test/codegen-units/partitioning/local-generic.rs +++ b/src/test/codegen-units/partitioning/local-generic.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // We specify -C incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/local-generic @@ -6,13 +5,13 @@ #![allow(dead_code)] #![crate_type="lib"] -//~ MONO_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] -//~ MONO_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] -//~ MONO_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] -//~ MONO_ITEM fn local_generic::generic[0]<&str> @@ local_generic.volatile[External] +//~ MONO_ITEM fn generic:: @@ local_generic.volatile[External] +//~ MONO_ITEM fn generic:: @@ local_generic.volatile[External] +//~ MONO_ITEM fn generic:: @@ local_generic.volatile[External] +//~ MONO_ITEM fn generic::<&str> @@ local_generic.volatile[External] pub fn generic(x: T) -> T { x } -//~ MONO_ITEM fn local_generic::user[0] @@ local_generic[Internal] +//~ MONO_ITEM fn user @@ local_generic[Internal] fn user() { let _ = generic(0u32); } @@ -20,7 +19,7 @@ fn user() { mod mod1 { pub use super::generic; - //~ MONO_ITEM fn local_generic::mod1[0]::user[0] @@ local_generic-mod1[Internal] + //~ MONO_ITEM fn mod1::user @@ local_generic-mod1[Internal] fn user() { let _ = generic(0u64); } @@ -28,7 +27,7 @@ mod mod1 { mod mod1 { use super::generic; - //~ MONO_ITEM fn local_generic::mod1[0]::mod1[0]::user[0] @@ local_generic-mod1-mod1[Internal] + //~ MONO_ITEM fn mod1::mod1::user @@ local_generic-mod1-mod1[Internal] fn user() { let _ = generic('c'); } @@ -38,7 +37,7 @@ mod mod1 { mod mod2 { use super::generic; - //~ MONO_ITEM fn local_generic::mod2[0]::user[0] @@ local_generic-mod2[Internal] + //~ MONO_ITEM fn mod2::user @@ local_generic-mod2[Internal] fn user() { let _ = generic("abc"); } diff --git a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs index 6322f55d2b..a24943348f 100644 --- a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs +++ b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs @@ -9,7 +9,7 @@ mod inline { - //~ MONO_ITEM fn local_inlining_but_not_all::inline[0]::inlined_function[0] @@ local_inlining_but_not_all-inline[External] + //~ MONO_ITEM fn inline::inlined_function @@ local_inlining_but_not_all-inline[External] #[inline] pub fn inlined_function() { @@ -20,7 +20,7 @@ mod inline { pub mod user1 { use super::inline; - //~ MONO_ITEM fn local_inlining_but_not_all::user1[0]::foo[0] @@ local_inlining_but_not_all-user1[External] + //~ MONO_ITEM fn user1::foo @@ local_inlining_but_not_all-user1[External] pub fn foo() { inline::inlined_function(); } @@ -29,7 +29,7 @@ pub mod user1 { pub mod user2 { use super::inline; - //~ MONO_ITEM fn local_inlining_but_not_all::user2[0]::bar[0] @@ local_inlining_but_not_all-user2[External] + //~ MONO_ITEM fn user2::bar @@ local_inlining_but_not_all-user2[External] pub fn bar() { inline::inlined_function(); } @@ -37,7 +37,7 @@ pub mod user2 { pub mod non_user { - //~ MONO_ITEM fn local_inlining_but_not_all::non_user[0]::baz[0] @@ local_inlining_but_not_all-non_user[External] + //~ MONO_ITEM fn non_user::baz @@ local_inlining_but_not_all-non_user[External] pub fn baz() { } diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index d75dfc9126..0cc652eeb5 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -10,7 +10,7 @@ mod inline { // Important: This function should show up in all codegen units where it is inlined - //~ MONO_ITEM fn local_inlining::inline[0]::inlined_function[0] @@ local_inlining-user1[Internal] local_inlining-user2[Internal] + //~ MONO_ITEM fn inline::inlined_function @@ local_inlining-user1[Internal] local_inlining-user2[Internal] #[inline(always)] pub fn inlined_function() { @@ -21,7 +21,7 @@ mod inline { pub mod user1 { use super::inline; - //~ MONO_ITEM fn local_inlining::user1[0]::foo[0] @@ local_inlining-user1[External] + //~ MONO_ITEM fn user1::foo @@ local_inlining-user1[External] pub fn foo() { inline::inlined_function(); } @@ -30,7 +30,7 @@ pub mod user1 { pub mod user2 { use super::inline; - //~ MONO_ITEM fn local_inlining::user2[0]::bar[0] @@ local_inlining-user2[External] + //~ MONO_ITEM fn user2::bar @@ local_inlining-user2[External] pub fn bar() { inline::inlined_function(); } @@ -38,7 +38,7 @@ pub mod user2 { pub mod non_user { - //~ MONO_ITEM fn local_inlining::non_user[0]::baz[0] @@ local_inlining-non_user[External] + //~ MONO_ITEM fn non_user::baz @@ local_inlining-non_user[External] pub fn baz() { } diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index 3cf0396686..0c8a67aeb3 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -9,7 +9,7 @@ mod inline { - //~ MONO_ITEM fn local_transitive_inlining::inline[0]::inlined_function[0] @@ local_transitive_inlining-indirect_user[Internal] + //~ MONO_ITEM fn inline::inlined_function @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn inlined_function() { @@ -20,7 +20,7 @@ mod inline { mod direct_user { use super::inline; - //~ MONO_ITEM fn local_transitive_inlining::direct_user[0]::foo[0] @@ local_transitive_inlining-indirect_user[Internal] + //~ MONO_ITEM fn direct_user::foo @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn foo() { inline::inlined_function(); @@ -30,7 +30,7 @@ mod direct_user { pub mod indirect_user { use super::direct_user; - //~ MONO_ITEM fn local_transitive_inlining::indirect_user[0]::bar[0] @@ local_transitive_inlining-indirect_user[External] + //~ MONO_ITEM fn indirect_user::bar @@ local_transitive_inlining-indirect_user[External] pub fn bar() { direct_user::foo(); } @@ -38,7 +38,7 @@ pub mod indirect_user { pub mod non_user { - //~ MONO_ITEM fn local_transitive_inlining::non_user[0]::baz[0] @@ local_transitive_inlining-non_user[External] + //~ MONO_ITEM fn non_user::baz @@ local_transitive_inlining-non_user[External] pub fn baz() { } diff --git a/src/test/codegen-units/partitioning/regular-modules.rs b/src/test/codegen-units/partitioning/regular-modules.rs index c8ceeafd0b..f9b8f52b0b 100644 --- a/src/test/codegen-units/partitioning/regular-modules.rs +++ b/src/test/codegen-units/partitioning/regular-modules.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // We specify -C incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/regular-modules @@ -6,67 +5,67 @@ #![allow(dead_code)] #![crate_type="lib"] -//~ MONO_ITEM fn regular_modules::foo[0] @@ regular_modules[Internal] +//~ MONO_ITEM fn foo @@ regular_modules[Internal] fn foo() {} -//~ MONO_ITEM fn regular_modules::bar[0] @@ regular_modules[Internal] +//~ MONO_ITEM fn bar @@ regular_modules[Internal] fn bar() {} -//~ MONO_ITEM static regular_modules::BAZ[0] @@ regular_modules[Internal] +//~ MONO_ITEM static BAZ @@ regular_modules[Internal] static BAZ: u64 = 0; mod mod1 { - //~ MONO_ITEM fn regular_modules::mod1[0]::foo[0] @@ regular_modules-mod1[Internal] + //~ MONO_ITEM fn mod1::foo @@ regular_modules-mod1[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod1[0]::bar[0] @@ regular_modules-mod1[Internal] + //~ MONO_ITEM fn mod1::bar @@ regular_modules-mod1[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod1[0]::BAZ[0] @@ regular_modules-mod1[Internal] + //~ MONO_ITEM static mod1::BAZ @@ regular_modules-mod1[Internal] static BAZ: u64 = 0; mod mod1 { - //~ MONO_ITEM fn regular_modules::mod1[0]::mod1[0]::foo[0] @@ regular_modules-mod1-mod1[Internal] + //~ MONO_ITEM fn mod1::mod1::foo @@ regular_modules-mod1-mod1[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod1[0]::mod1[0]::bar[0] @@ regular_modules-mod1-mod1[Internal] + //~ MONO_ITEM fn mod1::mod1::bar @@ regular_modules-mod1-mod1[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod1[0]::mod1[0]::BAZ[0] @@ regular_modules-mod1-mod1[Internal] + //~ MONO_ITEM static mod1::mod1::BAZ @@ regular_modules-mod1-mod1[Internal] static BAZ: u64 = 0; } mod mod2 { - //~ MONO_ITEM fn regular_modules::mod1[0]::mod2[0]::foo[0] @@ regular_modules-mod1-mod2[Internal] + //~ MONO_ITEM fn mod1::mod2::foo @@ regular_modules-mod1-mod2[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod1[0]::mod2[0]::bar[0] @@ regular_modules-mod1-mod2[Internal] + //~ MONO_ITEM fn mod1::mod2::bar @@ regular_modules-mod1-mod2[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod1[0]::mod2[0]::BAZ[0] @@ regular_modules-mod1-mod2[Internal] + //~ MONO_ITEM static mod1::mod2::BAZ @@ regular_modules-mod1-mod2[Internal] static BAZ: u64 = 0; } } mod mod2 { - //~ MONO_ITEM fn regular_modules::mod2[0]::foo[0] @@ regular_modules-mod2[Internal] + //~ MONO_ITEM fn mod2::foo @@ regular_modules-mod2[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod2[0]::bar[0] @@ regular_modules-mod2[Internal] + //~ MONO_ITEM fn mod2::bar @@ regular_modules-mod2[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod2[0]::BAZ[0] @@ regular_modules-mod2[Internal] + //~ MONO_ITEM static mod2::BAZ @@ regular_modules-mod2[Internal] static BAZ: u64 = 0; mod mod1 { - //~ MONO_ITEM fn regular_modules::mod2[0]::mod1[0]::foo[0] @@ regular_modules-mod2-mod1[Internal] + //~ MONO_ITEM fn mod2::mod1::foo @@ regular_modules-mod2-mod1[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod2[0]::mod1[0]::bar[0] @@ regular_modules-mod2-mod1[Internal] + //~ MONO_ITEM fn mod2::mod1::bar @@ regular_modules-mod2-mod1[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod2[0]::mod1[0]::BAZ[0] @@ regular_modules-mod2-mod1[Internal] + //~ MONO_ITEM static mod2::mod1::BAZ @@ regular_modules-mod2-mod1[Internal] static BAZ: u64 = 0; } mod mod2 { - //~ MONO_ITEM fn regular_modules::mod2[0]::mod2[0]::foo[0] @@ regular_modules-mod2-mod2[Internal] + //~ MONO_ITEM fn mod2::mod2::foo @@ regular_modules-mod2-mod2[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod2[0]::mod2[0]::bar[0] @@ regular_modules-mod2-mod2[Internal] + //~ MONO_ITEM fn mod2::mod2::bar @@ regular_modules-mod2-mod2[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod2[0]::mod2[0]::BAZ[0] @@ regular_modules-mod2-mod2[Internal] + //~ MONO_ITEM static mod2::mod2::BAZ @@ regular_modules-mod2-mod2[Internal] static BAZ: u64 = 0; } } diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs index 99142dd6b7..eb3196439b 100644 --- a/src/test/codegen-units/partitioning/shared-generics.rs +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -9,10 +9,10 @@ // aux-build:shared_generics_aux.rs extern crate shared_generics_aux; -//~ MONO_ITEM fn shared_generics::foo[0] +//~ MONO_ITEM fn foo pub fn foo() { - //~ MONO_ITEM fn shared_generics_aux::generic_fn[0] @@ shared_generics_aux-in-shared_generics.volatile[External] + //~ MONO_ITEM fn shared_generics_aux::generic_fn:: @@ shared_generics_aux-in-shared_generics.volatile[External] let _ = shared_generics_aux::generic_fn(0u16, 1u16); // This should not generate a monomorphization because it's already diff --git a/src/test/codegen-units/partitioning/statics.rs b/src/test/codegen-units/partitioning/statics.rs index 5eac046b81..02d6467577 100644 --- a/src/test/codegen-units/partitioning/statics.rs +++ b/src/test/codegen-units/partitioning/statics.rs @@ -4,34 +4,34 @@ #![crate_type="rlib"] -//~ MONO_ITEM static statics::FOO[0] @@ statics[Internal] +//~ MONO_ITEM static FOO @@ statics[Internal] static FOO: u32 = 0; -//~ MONO_ITEM static statics::BAR[0] @@ statics[Internal] +//~ MONO_ITEM static BAR @@ statics[Internal] static BAR: u32 = 0; -//~ MONO_ITEM fn statics::function[0] @@ statics[External] +//~ MONO_ITEM fn function @@ statics[External] pub fn function() { - //~ MONO_ITEM static statics::function[0]::FOO[0] @@ statics[Internal] + //~ MONO_ITEM static function::FOO @@ statics[Internal] static FOO: u32 = 0; - //~ MONO_ITEM static statics::function[0]::BAR[0] @@ statics[Internal] + //~ MONO_ITEM static function::BAR @@ statics[Internal] static BAR: u32 = 0; } pub mod mod1 { - //~ MONO_ITEM static statics::mod1[0]::FOO[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static mod1::FOO @@ statics-mod1[Internal] static FOO: u32 = 0; - //~ MONO_ITEM static statics::mod1[0]::BAR[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static mod1::BAR @@ statics-mod1[Internal] static BAR: u32 = 0; - //~ MONO_ITEM fn statics::mod1[0]::function[0] @@ statics-mod1[External] + //~ MONO_ITEM fn mod1::function @@ statics-mod1[External] pub fn function() { - //~ MONO_ITEM static statics::mod1[0]::function[0]::FOO[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static mod1::function::FOO @@ statics-mod1[Internal] static FOO: u32 = 0; - //~ MONO_ITEM static statics::mod1[0]::function[0]::BAR[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static mod1::function::BAR @@ statics-mod1[Internal] static BAR: u32 = 0; } } diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index 5a1d95d266..03dbac6179 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -28,7 +28,7 @@ mod mod1 { fn do_something_else(&self, x: T) -> T { x } } - //~ MONO_ITEM fn vtable_through_const::mod1[0]::id[0] @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn mod1::id:: @@ vtable_through_const-mod1.volatile[Internal] fn id(x: T) -> T { x } // These are referenced, so they produce mono-items (see start()) @@ -43,8 +43,8 @@ mod mod1 { fn do_something_else(&self) {} } - //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait2[0]::do_something[0] @@ vtable_through_const-mod1.volatile[Internal] - //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait2[0]::do_something_else[0] @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn ::do_something @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn ::do_something_else @@ vtable_through_const-mod1.volatile[Internal] impl Trait2 for u32 {} pub trait Trait2Gen { @@ -63,30 +63,30 @@ mod mod1 { pub const ID_I64: fn(i64) -> i64 = id::; } -//~ MONO_ITEM fn vtable_through_const::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ vtable_through_const[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ vtable_through_const[Internal] // Since Trait1::do_something() is instantiated via its default implementation, // it is considered a generic and is instantiated here only because it is // referenced in this module. - //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something_else[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn ::do_something_else @@ vtable_through_const-mod1.volatile[External] // Although it is never used, Trait1::do_something_else() has to be // instantiated locally here too, otherwise the <&u32 as &Trait1> vtable // could not be fully constructed. - //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn ::do_something @@ vtable_through_const-mod1.volatile[External] mod1::TRAIT1_REF.do_something(); // Same as above - //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something[0] @@ vtable_through_const-mod1.volatile[External] - //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something_else[0] @@ vtable_through_const-mod1.volatile[External] - //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[3]::do_something[0] @@ vtable_through_const-mod1.volatile[Internal] - //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[3]::do_something_else[0] @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn >::do_something @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn >::do_something_else @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn >::do_something @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn >::do_something_else @@ vtable_through_const-mod1.volatile[Internal] mod1::TRAIT1_GEN_REF.do_something(0u8); - //~ MONO_ITEM fn vtable_through_const::mod1[0]::id[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn mod1::id:: @@ vtable_through_const-mod1.volatile[External] mod1::ID_CHAR('x'); 0 diff --git a/src/test/codegen-units/polymorphization/unused_type_parameters.rs b/src/test/codegen-units/polymorphization/unused_type_parameters.rs index 403f68bb17..c2e06d067d 100644 --- a/src/test/codegen-units/polymorphization/unused_type_parameters.rs +++ b/src/test/codegen-units/polymorphization/unused_type_parameters.rs @@ -1,5 +1,4 @@ // compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1 -// ignore-tidy-linelength #![crate_type = "rlib"] @@ -10,44 +9,44 @@ mod functions { // Function doesn't have any type parameters to be unused. pub fn no_parameters() {} -//~ MONO_ITEM fn unused_type_parameters::functions[0]::no_parameters[0] +//~ MONO_ITEM fn functions::no_parameters // Function has an unused type parameter. pub fn unused() { } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::unused[0] +//~ MONO_ITEM fn functions::unused:: // Function uses type parameter in value of a binding. pub fn used_binding_value() { let _: T = Default::default(); } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0] -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0] +//~ MONO_ITEM fn functions::used_binding_value:: +//~ MONO_ITEM fn functions::used_binding_value:: // Function uses type parameter in type of a binding. pub fn used_binding_type() { let _: Option = None; } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0] -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0] +//~ MONO_ITEM fn functions::used_binding_type:: +//~ MONO_ITEM fn functions::used_binding_type:: // Function uses type parameter in argument. pub fn used_argument(_: T) { } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0] -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0] +//~ MONO_ITEM fn functions::used_argument:: +//~ MONO_ITEM fn functions::used_argument:: // // Function uses type parameter in substitutions to another function. pub fn used_substs() { unused::() } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0] -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0] +//~ MONO_ITEM fn functions::used_substs:: +//~ MONO_ITEM fn functions::used_substs:: } @@ -57,7 +56,7 @@ mod closures { let _ = || {}; } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::no_parameters[0] +//~ MONO_ITEM fn closures::no_parameters // Function has an unused type parameter in parent and closure. pub fn unused() -> u32 { @@ -65,8 +64,8 @@ mod closures { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0] +//~ MONO_ITEM fn closures::unused::::{closure#0} +//~ MONO_ITEM fn closures::unused:: // Function has an unused type parameter in closure, but not in parent. pub fn used_parent() -> u32 { @@ -75,9 +74,9 @@ mod closures { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0] +//~ MONO_ITEM fn closures::used_parent::::{closure#0} +//~ MONO_ITEM fn closures::used_parent:: +//~ MONO_ITEM fn closures::used_parent:: // Function uses type parameter in value of a binding in closure. pub fn used_binding_value() -> T { @@ -89,10 +88,10 @@ mod closures { x() } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0] u64, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0] +//~ MONO_ITEM fn closures::used_binding_value::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_value::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_value:: +//~ MONO_ITEM fn closures::used_binding_value:: // Function uses type parameter in type of a binding in closure. pub fn used_binding_type() -> Option { @@ -104,10 +103,10 @@ mod closures { x() } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0] core::option[0]::Option[0], ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0] core::option[0]::Option[0], ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0] +//~ MONO_ITEM fn closures::used_binding_type::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_type::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_type:: +//~ MONO_ITEM fn closures::used_binding_type:: // Function and closure uses type parameter in argument. pub fn used_argument(t: T) -> u32 { @@ -115,10 +114,10 @@ mod closures { x(t) } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0] +//~ MONO_ITEM fn closures::used_argument::::{closure#0} +//~ MONO_ITEM fn closures::used_argument::::{closure#0} +//~ MONO_ITEM fn closures::used_argument:: +//~ MONO_ITEM fn closures::used_argument:: // Closure uses type parameter in argument. pub fn used_argument_closure() -> u32 { @@ -127,10 +126,10 @@ mod closures { x(t) } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0] +//~ MONO_ITEM fn closures::used_argument_closure::::{closure#0} +//~ MONO_ITEM fn closures::used_argument_closure::::{closure#0} +//~ MONO_ITEM fn closures::used_argument_closure:: +//~ MONO_ITEM fn closures::used_argument_closure:: // Closure uses type parameter as upvar. pub fn used_upvar() -> T { @@ -139,10 +138,10 @@ mod closures { y() } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0] u32, (u32)> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0] u64, (u64)> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0] +//~ MONO_ITEM fn closures::used_upvar::::{closure#0} +//~ MONO_ITEM fn closures::used_upvar::::{closure#0} +//~ MONO_ITEM fn closures::used_upvar:: +//~ MONO_ITEM fn closures::used_upvar:: // Closure uses type parameter in substitutions to another function. pub fn used_substs() { @@ -150,10 +149,10 @@ mod closures { x() } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0] +//~ MONO_ITEM fn closures::used_substs::::{closure#0} +//~ MONO_ITEM fn closures::used_substs::::{closure#0} +//~ MONO_ITEM fn closures::used_substs:: +//~ MONO_ITEM fn closures::used_substs:: } mod methods { @@ -164,29 +163,29 @@ mod methods { pub fn unused_impl() { } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_impl[0] +//~ MONO_ITEM fn methods::Foo::::unused_impl // Function has an unused type parameter from impl and fn. pub fn unused_both() { } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_both[0] +//~ MONO_ITEM fn methods::Foo::::unused_both:: // Function uses type parameter from impl. pub fn used_impl() { let _: F = Default::default(); } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0] +//~ MONO_ITEM fn methods::Foo::::used_impl +//~ MONO_ITEM fn methods::Foo::::used_impl // Function uses type parameter from impl. pub fn used_fn() { let _: G = Default::default(); } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0] +//~ MONO_ITEM fn methods::Foo::::used_fn:: +//~ MONO_ITEM fn methods::Foo::::used_fn:: // Function uses type parameter from impl. pub fn used_both() { @@ -194,16 +193,16 @@ mod methods { let _: G = Default::default(); } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0] +//~ MONO_ITEM fn methods::Foo::::used_both:: +//~ MONO_ITEM fn methods::Foo::::used_both:: // Function uses type parameter in substitutions to another function. pub fn used_substs() { super::functions::unused::() } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0] +//~ MONO_ITEM fn methods::Foo::::used_substs +//~ MONO_ITEM fn methods::Foo::::used_substs // Function has an unused type parameter from impl and fn. pub fn closure_unused_all() -> u32 { @@ -211,8 +210,8 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0] +//~ MONO_ITEM fn methods::Foo::::closure_unused_all::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_unused_all:: // Function uses type parameter from impl and fn in closure. pub fn closure_used_both() -> u32 { @@ -225,10 +224,10 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0] +//~ MONO_ITEM fn methods::Foo::::closure_used_both::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_both::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_both:: +//~ MONO_ITEM fn methods::Foo::::closure_used_both:: // Function uses type parameter from fn in closure. pub fn closure_used_fn() -> u32 { @@ -240,10 +239,10 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0] +//~ MONO_ITEM fn methods::Foo::::closure_used_fn::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_fn::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_fn:: +//~ MONO_ITEM fn methods::Foo::::closure_used_fn:: // Function uses type parameter from impl in closure. pub fn closure_used_impl() -> u32 { @@ -255,10 +254,10 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0] +//~ MONO_ITEM fn methods::Foo::::closure_used_impl::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_impl::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_impl:: +//~ MONO_ITEM fn methods::Foo::::closure_used_impl:: // Closure uses type parameter in substitutions to another function. pub fn closure_used_substs() { @@ -266,10 +265,10 @@ mod methods { x() } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0] +//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_substs +//~ MONO_ITEM fn methods::Foo::::closure_used_substs } } @@ -306,8 +305,8 @@ fn dispatch() { let _ = methods::Foo::::closure_used_substs(); } -//~ MONO_ITEM fn unused_type_parameters::dispatch[0] -//~ MONO_ITEM fn unused_type_parameters::dispatch[0] +//~ MONO_ITEM fn dispatch:: +//~ MONO_ITEM fn dispatch:: pub fn foo() { // Generate two copies of each function to check that where the type parameter is unused, @@ -316,8 +315,8 @@ pub fn foo() { dispatch::(); } -//~ MONO_ITEM fn unused_type_parameters::foo[0] @@ unused_type_parameters-cgu.0[External] +//~ MONO_ITEM fn foo @@ unused_type_parameters-cgu.0[External] // These are all the items that aren't relevant to the test. -//~ MONO_ITEM fn core::default[0]::{{impl}}[6]::default[0] -//~ MONO_ITEM fn core::default[0]::{{impl}}[7]::default[0] +//~ MONO_ITEM fn ::default +//~ MONO_ITEM fn ::default diff --git a/src/test/codegen/avr/avr-func-addrspace.rs b/src/test/codegen/avr/avr-func-addrspace.rs index 6d25ca56f1..0f15729158 100644 --- a/src/test/codegen/avr/avr-func-addrspace.rs +++ b/src/test/codegen/avr/avr-func-addrspace.rs @@ -1,4 +1,4 @@ -// compile-flags: -O --target=avr-unknown-unknown --crate-type=rlib +// compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib // needs-llvm-components: avr // This test validates that function pointers can be stored in global variables diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index 318f9b0eec..fcb9002986 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -14,7 +14,7 @@ // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @alloc20, i32 0, i32 0, i32 0), {{.*}} +// CHECK: [[LOW_HIGH:@alloc[0-9]+]] = {{.*}}, align 4 #[derive(Copy, Clone)] // repr(i16) is required for the {low,high}_align_const test @@ -43,7 +43,7 @@ pub fn inline_enum_const() -> E { #[no_mangle] pub fn low_align_const() -> E { // Check that low_align_const and high_align_const use the same constant - // CHECK: load %"E"*, %"E"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E"**), + // CHECK: memcpy.p0i8.p0i8.i{{(32|64)}}(i8* align 2 %1, i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i{{(32|64)}} 8, i1 false) *&E::A(0) } @@ -51,6 +51,6 @@ pub fn low_align_const() -> E { #[no_mangle] pub fn high_align_const() -> E { // Check that low_align_const and high_align_const use the same constant - // CHECK: load %"E"*, %"E"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E"**), + // CHECK: memcpy.p0i8.p0i8.i{{(32|64)}}(i8* align 4 %1, i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i{{(32|64)}} 8, i1 false) *&E::A(0) } diff --git a/src/test/codegen/enum-bounds-check-derived-idx.rs b/src/test/codegen/enum-bounds-check-derived-idx.rs new file mode 100644 index 0000000000..7e3773b6a3 --- /dev/null +++ b/src/test/codegen/enum-bounds-check-derived-idx.rs @@ -0,0 +1,25 @@ +// This test checks an optimization that is not guaranteed to work. This test case should not block +// a future LLVM update. +// compile-flags: -O +// min-llvm-version: 11.0 + +#![crate_type = "lib"] + +pub enum Bar { + A = 1, + B = 3, +} + +// CHECK-LABEL: @lookup_inc +#[no_mangle] +pub fn lookup_inc(buf: &[u8; 5], f: Bar) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize + 1] +} + +// CHECK-LABEL: @lookup_dec +#[no_mangle] +pub fn lookup_dec(buf: &[u8; 5], f: Bar) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize - 1] +} diff --git a/src/test/codegen/enum-bounds-check-issue-13926.rs b/src/test/codegen/enum-bounds-check-issue-13926.rs new file mode 100644 index 0000000000..ad029f0fa7 --- /dev/null +++ b/src/test/codegen/enum-bounds-check-issue-13926.rs @@ -0,0 +1,19 @@ +// This test checks an optimization that is not guaranteed to work. This test case should not block +// a future LLVM update. +// compile-flags: -O +// min-llvm-version: 11.0 + +#![crate_type = "lib"] + +#[repr(u8)] +pub enum Exception { + Low = 5, + High = 10, +} + +// CHECK-LABEL: @access +#[no_mangle] +pub fn access(array: &[usize; 12], exc: Exception) -> usize { + // CHECK-NOT: panic_bounds_check + array[(exc as u8 - 4) as usize] +} diff --git a/src/test/codegen/enum-bounds-check.rs b/src/test/codegen/enum-bounds-check.rs index 21a27c9f35..17322d5911 100644 --- a/src/test/codegen/enum-bounds-check.rs +++ b/src/test/codegen/enum-bounds-check.rs @@ -12,3 +12,15 @@ pub fn lookup(buf: &[u8; 2], f: Foo) -> u8 { // CHECK-NOT: panic_bounds_check buf[f as usize] } + +pub enum Bar { + A = 2, + B = 3 +} + +// CHECK-LABEL: @lookup_unmodified +#[no_mangle] +pub fn lookup_unmodified(buf: &[u8; 5], f: Bar) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize] +} diff --git a/src/test/codegen/issue-27130.rs b/src/test/codegen/issue-27130.rs new file mode 100644 index 0000000000..7ae78782ff --- /dev/null +++ b/src/test/codegen/issue-27130.rs @@ -0,0 +1,22 @@ +// compile-flags: -O +// min-llvm-version: 11.0 + +#![crate_type = "lib"] + +// CHECK-LABEL: @trim_in_place +#[no_mangle] +pub fn trim_in_place(a: &mut &[u8]) { + while a.first() == Some(&42) { + // CHECK-NOT: slice_index_order_fail + *a = &a[1..]; + } +} + +// CHECK-LABEL: @trim_in_place2 +#[no_mangle] +pub fn trim_in_place2(a: &mut &[u8]) { + while let Some(&42) = a.first() { + // CHECK-NOT: slice_index_order_fail + *a = &a[2..]; + } +} diff --git a/src/test/codegen/issue-34634.rs b/src/test/codegen/issue-34634.rs new file mode 100644 index 0000000000..6c18adbcb3 --- /dev/null +++ b/src/test/codegen/issue-34634.rs @@ -0,0 +1,16 @@ +// Test that `wrapping_div` only checks divisor once. +// This test checks that there is only a single compare agains -1 and -1 is not present as a +// switch case (the second check present until rustc 1.12). +// This test also verifies that a single panic call is generated (for the division by zero case). + +// compile-flags: -O +#![crate_type = "lib"] + +// CHECK-LABEL: @f +#[no_mangle] +pub fn f(x: i32, y: i32) -> i32 { + // CHECK-COUNT-1: icmp eq i32 %y, -1 + // CHECK-COUNT-1: panic + // CHECK-NOT: i32 -1, label + x.wrapping_div(y) +} diff --git a/src/test/codegen/issue-73396-bounds-check-after-position.rs b/src/test/codegen/issue-73396-bounds-check-after-position.rs new file mode 100644 index 0000000000..e5f3ae45c0 --- /dev/null +++ b/src/test/codegen/issue-73396-bounds-check-after-position.rs @@ -0,0 +1,78 @@ +// min-llvm-version: 11.0.0 +// compile-flags: -O +// ignore-debug: the debug assertions get in the way +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted when slicing or indexing +// with an index from `position()` or `rposition()`. + +// CHECK-LABEL: @position_slice_to_no_bounds_check +#[no_mangle] +pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @position_slice_from_no_bounds_check +#[no_mangle] +pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @position_index_no_bounds_check +#[no_mangle] +pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} +// CHECK-LABEL: @rposition_slice_to_no_bounds_check +#[no_mangle] +pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @rposition_slice_from_no_bounds_check +#[no_mangle] +pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @rposition_index_no_bounds_check +#[no_mangle] +pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} diff --git a/src/test/codegen/issue-75659.rs b/src/test/codegen/issue-75659.rs new file mode 100644 index 0000000000..d093c841d6 --- /dev/null +++ b/src/test/codegen/issue-75659.rs @@ -0,0 +1,63 @@ +// This test checks that the call to memchr/slice_contains is optimized away +// when searching in small slices. + +// compile-flags: -O +// only-x86_64 + +#![crate_type = "lib"] + +// CHECK-LABEL: @foo1 +#[no_mangle] +pub fn foo1(x: u8, data: &[u8; 1]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo2 +#[no_mangle] +pub fn foo2(x: u8, data: &[u8; 2]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo3 +#[no_mangle] +pub fn foo3(x: u8, data: &[u8; 3]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo4 +#[no_mangle] +pub fn foo4(x: u8, data: &[u8; 4]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo8 +#[no_mangle] +pub fn foo8(x: u8, data: &[u8; 8]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo8_i8 +#[no_mangle] +pub fn foo8_i8(x: i8, data: &[i8; 8]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + !data.contains(&x) +} + +// Check that the general case isn't inlined +// CHECK-LABEL: @foo80 +#[no_mangle] +pub fn foo80(x: u8, data: &[u8; 80]) -> bool { + // CHECK: call core::slice::memchr + data.contains(&x) +} diff --git a/src/test/codegen/return-value-in-reg.rs b/src/test/codegen/return-value-in-reg.rs new file mode 100644 index 0000000000..4bc0136c5e --- /dev/null +++ b/src/test/codegen/return-value-in-reg.rs @@ -0,0 +1,32 @@ +//! This test checks that types of up to 128 bits are returned by-value instead of via out-pointer. + +// compile-flags: -C no-prepopulate-passes -O +// only-x86_64 + +#![crate_type = "lib"] + +pub struct S { + a: u64, + b: u32, + c: u32, +} + +// CHECK: define i128 @modify(%S* noalias nocapture dereferenceable(16) %s) +#[no_mangle] +pub fn modify(s: S) -> S { + S { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c } +} + +#[repr(packed)] +pub struct TooBig { + a: u64, + b: u32, + c: u32, + d: u8, +} + +// CHECK: define void @m_big(%TooBig* [[ATTRS:.*sret.*]], %TooBig* [[ATTRS2:.*]] %s) +#[no_mangle] +pub fn m_big(s: TooBig) -> TooBig { + TooBig { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c, d: s.d + s.d } +} diff --git a/src/test/codegen/try_identity.rs b/src/test/codegen/try_identity.rs index 30e7adfddf..d30b706eaf 100644 --- a/src/test/codegen/try_identity.rs +++ b/src/test/codegen/try_identity.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=2 +// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=2 -Zunsound-mir-opts // Ensure that `x?` has no overhead on `Result` due to identity `match`es in lowering. // This requires inlining to trigger the MIR optimizations in `SimplifyArmIdentity`. diff --git a/src/test/codegen/tuple-layout-opt.rs b/src/test/codegen/tuple-layout-opt.rs new file mode 100644 index 0000000000..e86c75f3f4 --- /dev/null +++ b/src/test/codegen/tuple-layout-opt.rs @@ -0,0 +1,36 @@ +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +// Test that tuples get optimized layout, in particular with a ZST in the last field (#63244) + +#![crate_type="lib"] + +type ScalarZstLast = (u128, ()); +// CHECK: define i128 @test_ScalarZstLast(i128 %_1) +#[no_mangle] +pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { loop {} } + +type ScalarZstFirst = ((), u128); +// CHECK: define i128 @test_ScalarZstFirst(i128 %_1) +#[no_mangle] +pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { loop {} } + +type ScalarPairZstLast = (u8, u128, ()); +// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { loop {} } + +type ScalarPairZstFirst = ((), u8, u128); +// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1) +#[no_mangle] +pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { loop {} } + +type ScalarPairLotsOfZsts = ((), u8, (), u128, ()); +// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { loop {} } + +type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ()); +// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { loop {} } diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs deleted file mode 100644 index 9a58ef1c37..0000000000 --- a/src/test/codegen/x86_mmx.rs +++ /dev/null @@ -1,27 +0,0 @@ -// ignore-arm -// ignore-aarch64 -// ignore-emscripten -// ignore-mips -// ignore-mips64 -// ignore-powerpc -// ignore-powerpc64 -// ignore-powerpc64le -// ignore-riscv64 -// ignore-sparc -// ignore-sparc64 -// ignore-s390x -// compile-flags: -O - -#![feature(repr_simd)] -#![crate_type="lib"] - -#[repr(simd)] -#[derive(Clone, Copy)] -pub struct i8x8(u64); - -#[no_mangle] -pub fn a(a: &mut i8x8, b: i8x8) -> i8x8 { - // CHECK-LABEL: define void @a(x86_mmx*{{.*}}, x86_mmx*{{.*}}, x86_mmx*{{.*}}) - *a = b; - return b -} diff --git a/src/test/codegen/zst-offset.rs b/src/test/codegen/zst-offset.rs new file mode 100644 index 0000000000..0c015fca32 --- /dev/null +++ b/src/test/codegen/zst-offset.rs @@ -0,0 +1,43 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd)] + +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +#[no_mangle] +pub fn helper(_: usize) { +} + +// Check that we correctly generate a GEP for a ZST that is not included in Scalar layout +// CHECK-LABEL: @scalar_layout +#[no_mangle] +pub fn scalar_layout(s: &(u64, ())) { +// CHECK: [[X0:%[0-9]+]] = bitcast i64* %s to i8* +// CHECK-NEXT: [[X1:%[0-9]+]] = getelementptr i8, i8* [[X0]], [[USIZE]] 8 + let x = &s.1; + &x; // keep variable in an alloca +} + +// Check that we correctly generate a GEP for a ZST that is not included in ScalarPair layout +// CHECK-LABEL: @scalarpair_layout +#[no_mangle] +pub fn scalarpair_layout(s: &(u64, u32, ())) { +// CHECK: [[X0:%[0-9]+]] = bitcast { i64, i32 }* %s to i8* +// CHECK-NEXT: [[X1:%[0-9]+]] = getelementptr i8, i8* [[X0]], [[USIZE]] 12 + let x = &s.2; + &x; // keep variable in an alloca +} + +#[repr(simd)] +pub struct U64x4(u64, u64, u64, u64); + +// Check that we correctly generate a GEP for a ZST that is not included in Vector layout +// CHECK-LABEL: @vector_layout +#[no_mangle] +pub fn vector_layout(s: &(U64x4, ())) { +// CHECK: [[X0:%[0-9]+]] = bitcast <4 x i64>* %s to i8* +// CHECK-NEXT: [[X1:%[0-9]+]] = getelementptr i8, i8* [[X0]], [[USIZE]] 32 + let x = &s.1; + &x; // keep variable in an alloca +} diff --git a/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs b/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs index 3e5cdad7ab..b9ef2f3294 100644 --- a/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs +++ b/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs @@ -11,3 +11,5 @@ use core::panic::PanicInfo; fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} +#[lang = "eh_catch_typeinfo"] +static EH_CATCH_TYPEINFO: u8 = 0; diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs index 7dbf7d1a38..68a4d414ff 100644 --- a/src/test/compile-fail/consts/const-fn-error.rs +++ b/src/test/compile-fail/consts/const-fn-error.rs @@ -5,9 +5,9 @@ const X : usize = 2; const fn f(x: usize) -> usize { let mut sum = 0; for i in 0..x { - //~^ ERROR E0015 - //~| ERROR E0015 - //~| ERROR E0658 + //~^ ERROR mutable references + //~| ERROR calls in constant functions + //~| ERROR calls in constant functions //~| ERROR E0080 //~| ERROR E0744 sum += i; diff --git a/src/test/compile-fail/issue-43733-2.rs b/src/test/compile-fail/issue-43733-2.rs index dae27c4785..61dd3a923f 100644 --- a/src/test/compile-fail/issue-43733-2.rs +++ b/src/test/compile-fail/issue-43733-2.rs @@ -22,7 +22,7 @@ impl Key { use std::thread::__FastLocalKeyInner as Key; static __KEY: Key<()> = Key::new(); -//~^ ERROR `std::cell::UnsafeCell>` cannot be shared between threads +//~^ ERROR `UnsafeCell>` cannot be shared between threads //~| ERROR cannot be shared between threads safely [E0277] fn main() {} diff --git a/src/test/compile-fail/issue-44415.rs b/src/test/compile-fail/issue-44415.rs index 763f857487..71e764620d 100644 --- a/src/test/compile-fail/issue-44415.rs +++ b/src/test/compile-fail/issue-44415.rs @@ -4,7 +4,7 @@ use std::intrinsics; struct Foo { bytes: [u8; unsafe { intrinsics::size_of::() }], - //~^ ERROR cycle detected when const-evaluating + checking + //~^ ERROR cycle detected when simplifying constant for the type system x: usize, } diff --git a/src/test/compile-fail/must_use-in-stdlib-traits.rs b/src/test/compile-fail/must_use-in-stdlib-traits.rs index 39472ae11f..70dddf61fb 100644 --- a/src/test/compile-fail/must_use-in-stdlib-traits.rs +++ b/src/test/compile-fail/must_use-in-stdlib-traits.rs @@ -39,9 +39,9 @@ fn square_fn() -> impl Fn(u32) -> u32 { } fn main() { - iterator(); //~ ERROR unused implementer of `std::iter::Iterator` that must be used - future(); //~ ERROR unused implementer of `std::future::Future` that must be used - square_fn_once(); //~ ERROR unused implementer of `std::ops::FnOnce` that must be used - square_fn_mut(); //~ ERROR unused implementer of `std::ops::FnMut` that must be used - square_fn(); //~ ERROR unused implementer of `std::ops::Fn` that must be used + iterator(); //~ ERROR unused implementer of `Iterator` that must be used + future(); //~ ERROR unused implementer of `Future` that must be used + square_fn_once(); //~ ERROR unused implementer of `FnOnce` that must be used + square_fn_mut(); //~ ERROR unused implementer of `FnMut` that must be used + square_fn(); //~ ERROR unused implementer of `Fn` that must be used } diff --git a/src/test/debuginfo/pretty-std-collections-hash.rs b/src/test/debuginfo/pretty-std-collections-hash.rs index e8f52deabd..9f59936a92 100644 --- a/src/test/debuginfo/pretty-std-collections-hash.rs +++ b/src/test/debuginfo/pretty-std-collections-hash.rs @@ -1,3 +1,7 @@ +// CDB doesn't like how libstd.natvis casts to tuples before this version. +// https://github.com/rust-lang/rust/issues/76352#issuecomment-687640746 +// min-cdb-version: 10.0.18362.1 + // cdb-only // compile-flags:-g diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs index 2a1056df4c..02c9a0c579 100644 --- a/src/test/incremental/dirty_clean.rs +++ b/src/test/incremental/dirty_clean.rs @@ -27,7 +27,7 @@ mod y { #[rustc_clean(label="typeck", cfg="cfail2")] pub fn y() { - //[cfail2]~^ ERROR `typeck(y::y)` should be clean but is not + //[cfail2]~^ ERROR `typeck(y)` should be clean but is not x::x(); } } @@ -35,6 +35,6 @@ mod y { mod z { #[rustc_dirty(label="typeck", cfg="cfail2")] pub fn z() { - //[cfail2]~^ ERROR `typeck(z::z)` should be dirty but is not + //[cfail2]~^ ERROR `typeck(z)` should be dirty but is not } } diff --git a/src/test/incremental/issue-54242.rs b/src/test/incremental/issue-54242.rs index 1c700d44dd..25dc7cdf12 100644 --- a/src/test/incremental/issue-54242.rs +++ b/src/test/incremental/issue-54242.rs @@ -11,7 +11,7 @@ impl Tr for str { type Arr = [u8; 8]; #[cfg(cfail)] type Arr = [u8; Self::C]; - //[cfail]~^ ERROR cycle detected when const-evaluating + //[cfail]~^ ERROR cycle detected when simplifying constant } fn main() {} diff --git a/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff new file mode 100644 index 0000000000..28b8329606 --- /dev/null +++ b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff @@ -0,0 +1,28 @@ +- // MIR for `encode` before SimplifyBranchSame ++ // MIR for `encode` after SimplifyBranchSame + + fn encode(_1: Type) -> Type { + debug v => _1; // in scope 0 at $DIR/76803_regression.rs:10:15: 10:16 + let mut _0: Type; // return place in scope 0 at $DIR/76803_regression.rs:10:27: 10:31 + let mut _2: isize; // in scope 0 at $DIR/76803_regression.rs:12:9: 12:16 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 + } + + bb1: { + _0 = move _1; // scope 0 at $DIR/76803_regression.rs:13:14: 13:15 + goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 + } + + bb2: { + discriminant(_0) = 1; // scope 0 at $DIR/76803_regression.rs:12:20: 12:27 + goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 + } + + bb3: { + return; // scope 0 at $DIR/76803_regression.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/76803_regression.rs b/src/test/mir-opt/76803_regression.rs new file mode 100644 index 0000000000..05dc3c9784 --- /dev/null +++ b/src/test/mir-opt/76803_regression.rs @@ -0,0 +1,19 @@ +// compile-flags: -Z mir-opt-level=1 +// EMIT_MIR 76803_regression.encode.SimplifyBranchSame.diff + +#[derive(Debug, Eq, PartialEq)] +pub enum Type { + A, + B, +} + +pub fn encode(v: Type) -> Type { + match v { + Type::A => Type::B, + _ => v, + } +} + +fn main() { + assert_eq!(Type::B, encode(Type::A)); +} diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir similarity index 96% rename from src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit rename to src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir index 2216c2bc92..deb5dbad7d 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir @@ -48,7 +48,7 @@ fn main() -> () { _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 - assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 } bb2: { diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir similarity index 96% rename from src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit rename to src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir index 2216c2bc92..deb5dbad7d 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir @@ -48,7 +48,7 @@ fn main() -> () { _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 - assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 } bb2: { diff --git a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 06869735f1..50326253ce 100644 --- a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -35,7 +35,7 @@ fn main() -> () { _2 = move _3; // scope 2 at $DIR/basic_assignment.rs:16:5: 16:24 StorageDead(_3); // scope 2 at $DIR/basic_assignment.rs:16:23: 16:24 StorageLive(_4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 - _4 = std::option::Option::>::None; // scope 2 at $DIR/basic_assignment.rs:18:36: 18:40 + _4 = Option::>::None; // scope 2 at $DIR/basic_assignment.rs:18:36: 18:40 FakeRead(ForLet, _4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 AscribeUserType(_4, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/basic_assignment.rs:18:17: 18:33 StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15 diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index 46dbb997ef..408efb4cad 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -38,7 +38,7 @@ fn main() -> () { StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _3 = std::mem::drop::>(move _4) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + _3 = std::mem::drop::>(move _4) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 // + literal: Const { ty: fn(std::boxed::Box) {std::mem::drop::>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.64bit b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff similarity index 94% rename from src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.64bit rename to src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff index 61e987cc68..979e5bc4d2 100644 --- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.64bit +++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff @@ -32,7 +32,7 @@ - _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 } bb1: { @@ -44,7 +44,7 @@ - _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 - assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 } bb2: { diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.32bit b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff similarity index 94% rename from src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.32bit rename to src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff index 61e987cc68..979e5bc4d2 100644 --- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.32bit +++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff @@ -32,7 +32,7 @@ - _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 } bb1: { @@ -44,7 +44,7 @@ - _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 - assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 } bb2: { diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir similarity index 76% rename from src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit rename to src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir index 09a4eca938..8b09eade06 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 - _2 = const {alloc0: &&[(std::option::Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + _2 = const {alloc0: &&[(Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 // ty::Const // + ty: &&[(std::option::Option, &[&str])] // + val: Value(Scalar(alloc0)) @@ -24,42 +24,42 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 4) { - ╾─alloc17─╼ 03 00 00 00 │ ╾──╼.... + ╾─alloc14─╼ 03 00 00 00 │ ╾──╼.... } -alloc17 (size: 48, align: 4) { +alloc14 (size: 48, align: 4) { 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc4──╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc13─╼ 03 00 00 00 │ ....*...╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc7──╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc11─╼ 03 00 00 00 │ ....*...╾──╼.... } alloc4 (size: 0, align: 4) {} -alloc8 (size: 16, align: 4) { - ╾─alloc7──╼ 03 00 00 00 ╾─alloc9──╼ 03 00 00 00 │ ╾──╼....╾──╼.... +alloc7 (size: 16, align: 4) { + ╾─alloc6──╼ 03 00 00 00 ╾─alloc8──╼ 03 00 00 00 │ ╾──╼....╾──╼.... } -alloc7 (size: 3, align: 1) { +alloc6 (size: 3, align: 1) { 66 6f 6f │ foo } -alloc9 (size: 3, align: 1) { +alloc8 (size: 3, align: 1) { 62 61 72 │ bar } -alloc13 (size: 24, align: 4) { - 0x00 │ ╾─alloc12─╼ 03 00 00 00 ╾─alloc14─╼ 03 00 00 00 │ ╾──╼....╾──╼.... - 0x10 │ ╾─alloc15─╼ 04 00 00 00 │ ╾──╼.... +alloc11 (size: 24, align: 4) { + 0x00 │ ╾─alloc10─╼ 03 00 00 00 ╾─alloc12─╼ 03 00 00 00 │ ╾──╼....╾──╼.... + 0x10 │ ╾─alloc13─╼ 04 00 00 00 │ ╾──╼.... } -alloc12 (size: 3, align: 1) { +alloc10 (size: 3, align: 1) { 6d 65 68 │ meh } -alloc14 (size: 3, align: 1) { +alloc12 (size: 3, align: 1) { 6d 6f 70 │ mop } -alloc15 (size: 4, align: 1) { +alloc13 (size: 4, align: 1) { 6d c3 b6 70 │ m..p } diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir similarity index 76% rename from src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit rename to src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir index b10cc3e098..2853a0ac18 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 - _2 = const {alloc0: &&[(std::option::Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + _2 = const {alloc0: &&[(Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 // ty::Const // + ty: &&[(std::option::Option, &[&str])] // + val: Value(Scalar(alloc0)) @@ -24,46 +24,46 @@ fn main() -> () { } alloc0 (static: FOO, size: 16, align: 8) { - ╾───────alloc17───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc17 (size: 72, align: 8) { +alloc14 (size: 72, align: 8) { 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc4────────╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc8────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc13───────╼ │ ....*...╾──────╼ + 0x20 │ ╾───────alloc7────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc11───────╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } alloc4 (size: 0, align: 8) {} -alloc8 (size: 32, align: 8) { - 0x00 │ ╾───────alloc7────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ +alloc7 (size: 32, align: 8) { + 0x00 │ ╾───────alloc6────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾───────alloc8────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc7 (size: 3, align: 1) { +alloc6 (size: 3, align: 1) { 66 6f 6f │ foo } -alloc9 (size: 3, align: 1) { +alloc8 (size: 3, align: 1) { 62 61 72 │ bar } -alloc13 (size: 48, align: 8) { - 0x00 │ ╾───────alloc12───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x20 │ ╾───────alloc15───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ +alloc11 (size: 48, align: 8) { + 0x00 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾───────alloc12───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x20 │ ╾───────alloc13───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc12 (size: 3, align: 1) { +alloc10 (size: 3, align: 1) { 6d 65 68 │ meh } -alloc14 (size: 3, align: 1) { +alloc12 (size: 3, align: 1) { 6d 6f 70 │ mop } -alloc15 (size: 4, align: 1) { +alloc13 (size: 4, align: 1) { 6d c3 b6 70 │ m..p } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir similarity index 77% rename from src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit rename to src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir index 19cbab74ab..710ffeeda0 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 - _2 = const {alloc0: &&[(std::option::Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + _2 = const {alloc0: &&[(Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 // ty::Const // + ty: &&[(std::option::Option, &[&u8])] // + val: Value(Scalar(alloc0)) @@ -24,41 +24,41 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 4) { - ╾─alloc23─╼ 03 00 00 00 │ ╾──╼.... + ╾─alloc20─╼ 03 00 00 00 │ ╾──╼.... } -alloc23 (size: 48, align: 4) { +alloc20 (size: 48, align: 4) { 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc13─╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc21─╼ 03 00 00 00 │ ....*...╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc12─╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc19─╼ 03 00 00 00 │ ....*...╾──╼.... } alloc8 (size: 0, align: 4) {} -alloc13 (size: 8, align: 4) { - ╾─alloc11─╼ ╾─alloc12─╼ │ ╾──╼╾──╼ +alloc12 (size: 8, align: 4) { + ╾─alloc10─╼ ╾─alloc11─╼ │ ╾──╼╾──╼ } -alloc11 (size: 1, align: 1) { +alloc10 (size: 1, align: 1) { 05 │ . } -alloc12 (size: 1, align: 1) { +alloc11 (size: 1, align: 1) { 06 │ . } -alloc21 (size: 12, align: 4) { - ╾─a17+0x3─╼ ╾─alloc18─╼ ╾─a20+0x2─╼ │ ╾──╼╾──╼╾──╼ +alloc19 (size: 12, align: 4) { + ╾─a15+0x3─╼ ╾─alloc16─╼ ╾─a18+0x2─╼ │ ╾──╼╾──╼╾──╼ } -alloc17 (size: 4, align: 1) { +alloc15 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc18 (size: 1, align: 1) { +alloc16 (size: 1, align: 1) { 2a │ * } -alloc20 (size: 4, align: 1) { +alloc18 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir similarity index 75% rename from src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit rename to src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir index 4dd960c8dd..97a7f76f6b 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 - _2 = const {alloc0: &&[(std::option::Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + _2 = const {alloc0: &&[(Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 // ty::Const // + ty: &&[(std::option::Option, &[&u8])] // + val: Value(Scalar(alloc0)) @@ -24,44 +24,44 @@ fn main() -> () { } alloc0 (static: FOO, size: 16, align: 8) { - ╾───────alloc23───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾───────alloc20───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc23 (size: 72, align: 8) { +alloc20 (size: 72, align: 8) { 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc8────────╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc13───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc21───────╼ │ ....*...╾──────╼ + 0x20 │ ╾───────alloc12───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc19───────╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } alloc8 (size: 0, align: 8) {} -alloc13 (size: 16, align: 8) { - ╾───────alloc11───────╼ ╾───────alloc12───────╼ │ ╾──────╼╾──────╼ +alloc12 (size: 16, align: 8) { + ╾───────alloc10───────╼ ╾───────alloc11───────╼ │ ╾──────╼╾──────╼ } -alloc11 (size: 1, align: 1) { +alloc10 (size: 1, align: 1) { 05 │ . } -alloc12 (size: 1, align: 1) { +alloc11 (size: 1, align: 1) { 06 │ . } -alloc21 (size: 24, align: 8) { - 0x00 │ ╾─────alloc17+0x3─────╼ ╾───────alloc18───────╼ │ ╾──────╼╾──────╼ - 0x10 │ ╾─────alloc20+0x2─────╼ │ ╾──────╼ +alloc19 (size: 24, align: 8) { + 0x00 │ ╾─────alloc15+0x3─────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼ + 0x10 │ ╾─────alloc18+0x2─────╼ │ ╾──────╼ } -alloc17 (size: 4, align: 1) { +alloc15 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc18 (size: 1, align: 1) { +alloc16 (size: 1, align: 1) { 2a │ * } -alloc20 (size: 4, align: 1) { +alloc18 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit rename to src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit rename to src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 6acb8e46e7..c8c15792a2 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -22,7 +22,7 @@ - // + ty: &i32 - // + val: Value(Scalar(alloc0)) + // + ty: &[&i32; 1] -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34 - // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) } @@ -30,7 +30,7 @@ - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 _0 = core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 2f7a2d7288..ddf79fca9f 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -24,7 +24,7 @@ - // + ty: &i32 - // + val: Value(Scalar(alloc2)) + // + ty: &[&i32; 1] -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43 - // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) } @@ -32,7 +32,7 @@ - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 _0 = core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff similarity index 86% rename from src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff index 1ccda1c500..4664934690 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff @@ -20,9 +20,9 @@ _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32 _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33 - _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:5:18: 5:33 -- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 + _5 = const true; // scope 0 at $DIR/array_index.rs:5:18: 5:33 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 } bb1: { diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff similarity index 86% rename from src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff index 1ccda1c500..4664934690 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff @@ -20,9 +20,9 @@ _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32 _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33 - _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:5:18: 5:33 -- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 + _5 = const true; // scope 0 at $DIR/array_index.rs:5:18: 5:33 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 } bb1: { diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff index 30ff6ec860..ba081f95fa 100644 --- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff @@ -24,21 +24,21 @@ StorageLive(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 - _3 = _1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 - _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 -- assert(!move _4, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 +- assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + _3 = const 0_i32; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 + _4 = const true; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 -+ assert(!const true, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 } bb1: { - _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 - _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 - _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 -- assert(!move _7, "attempt to compute `{} / {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 +- assert(!move _7, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + _5 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + _6 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + _7 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 -+ assert(!const false, "attempt to compute `{} / {}` which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 } bb2: { diff --git a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff index 6e6ce0a613..a843cacf4d 100644 --- a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff @@ -24,21 +24,21 @@ StorageLive(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 - _3 = _1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 - _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 -- assert(!move _4, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 +- assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + _3 = const 0_i32; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 + _4 = const true; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 -+ assert(!const true, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 } bb1: { - _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 - _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 - _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 -- assert(!move _7, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 +- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + _5 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + _6 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + _7 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 -+ assert(!const false, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 } bb2: { diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff similarity index 89% rename from src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 245a7de5e9..8c10b3518d 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -28,10 +28,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // ty::Const // + ty: &[i32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 @@ -42,9 +42,9 @@ _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 - _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 -- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 -+ assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 } bb1: { diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff similarity index 89% rename from src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 245a7de5e9..8c10b3518d 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -28,10 +28,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // ty::Const // + ty: &[i32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 @@ -42,9 +42,9 @@ _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 - _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 -- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 -+ assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 } bb1: { diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff index 125d150d3d..f01676b6da 100644 --- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff @@ -12,7 +12,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/checked_add.rs:5:9: 5:10 - _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 -- assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 +- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 + _2 = const (2_u32, false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 + // ty::Const + // + ty: (u32, bool) @@ -20,7 +20,7 @@ + // mir::Constant + // + span: $DIR/checked_add.rs:5:18: 5:23 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 } bb1: { diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index bfc848bbfc..6034645864 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -16,13 +16,13 @@ StorageLive(_1); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:9: 7:10 StorageLive(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:30 StorageLive(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 - _3 = const main::FOO; // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 + _3 = const FOO; // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), const_param_did: None }, [], None) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, [], None) // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), const_param_did: None }, [], None) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, [], None) } _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 _1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39 diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff index b55e3a6353..80b7e7ecdd 100644 --- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff +++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff @@ -22,7 +22,7 @@ bb2: { StorageLive(_2); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff index e37d0a3ed9..8c7b35887c 100644 --- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff @@ -15,7 +15,7 @@ StorageLive(_2); // scope 0 at $DIR/indirect.rs:5:13: 5:25 - _2 = const 2_u32 as u8 (Misc); // scope 0 at $DIR/indirect.rs:5:13: 5:25 - _3 = CheckedAdd(_2, const 1_u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29 -- assert(!move (_3.1: bool), "attempt to compute `{} + {}` which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 +- assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 + _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25 + _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:5:13: 5:29 + // ty::Const @@ -24,7 +24,7 @@ + // mir::Constant + // + span: $DIR/indirect.rs:5:13: 5:29 + // + literal: Const { ty: (u8, bool), val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 } bb1: { diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff similarity index 86% rename from src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff index b1a9e1cb5d..fa790822b6 100644 --- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff @@ -20,9 +20,9 @@ _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 - _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 -- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 } bb1: { diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff similarity index 86% rename from src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff index b1a9e1cb5d..fa790822b6 100644 --- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff @@ -20,9 +20,9 @@ _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 - _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 -- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 } bb1: { diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff similarity index 89% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff index 2c8e7ada39..53ffc01cca 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff @@ -25,7 +25,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -- assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 +- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + // ty::Const + // + ty: (i32, bool) @@ -33,7 +33,7 @@ + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 } bb1: { @@ -46,9 +46,9 @@ _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33 _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 - _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -- assert(move _7, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + _7 = const true; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 } bb2: { diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff similarity index 89% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff index 2c8e7ada39..53ffc01cca 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff @@ -25,7 +25,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -- assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 +- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + // ty::Const + // + ty: (i32, bool) @@ -33,7 +33,7 @@ + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 } bb1: { @@ -46,9 +46,9 @@ _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33 _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 - _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -- assert(move _7, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + _7 = const true; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 } bb2: { diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir similarity index 100% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir similarity index 100% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff index 31061233ee..4fd1b8b227 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -14,10 +14,10 @@ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref.rs:5:6: 5:10 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 - _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff index c9caf07a73..e7ebfee7f3 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff @@ -17,10 +17,10 @@ + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + // ty::Const + // + ty: &i32 -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref.rs:5:6: 5:10 -+ // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 - StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index e9398df132..812c7c9771 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -14,10 +14,10 @@ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 // ty::Const // + ty: &(i32, i32) - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref_project.rs:5:6: 5:17 - // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff index 43e4b32a6c..588c291bcc 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff @@ -17,10 +17,10 @@ + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + // ty::Const + // + ty: &(i32, i32) -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref_project.rs:5:6: 5:17 -+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 - StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff similarity index 88% rename from src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff index f14004fc25..98f409f326 100644 --- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff @@ -22,9 +22,9 @@ _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27 _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28 - _6 = Lt(_4, _5); // scope 0 at $DIR/repeat.rs:6:18: 6:28 -- assert(move _6, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 + _6 = const true; // scope 0 at $DIR/repeat.rs:6:18: 6:28 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 } bb1: { diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff similarity index 88% rename from src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff index f14004fc25..98f409f326 100644 --- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff @@ -22,9 +22,9 @@ _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27 _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28 - _6 = Lt(_4, _5); // scope 0 at $DIR/repeat.rs:6:18: 6:28 -- assert(move _6, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 + _6 = const true; // scope 0 at $DIR/repeat.rs:6:18: 6:28 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 } bb1: { diff --git a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff index d61a04d1e0..fc8a543723 100644 --- a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff +++ b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff @@ -7,7 +7,7 @@ bb0: { - _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10 -- assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 +- assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 + _1 = const (4_u32, false); // scope 0 at $DIR/return_place.rs:6:5: 6:10 + // ty::Const + // + ty: (u32, bool) @@ -15,7 +15,7 @@ + // mir::Constant + // + span: $DIR/return_place.rs:6:5: 6:10 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 } bb1: { diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff similarity index 87% rename from src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index 02c4391baf..240cc8e231 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -21,10 +21,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // ty::Const // + ty: &[u32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 @@ -33,10 +33,10 @@ _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32 - _7 = Len((*_2)); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 -- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 } bb1: { diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff similarity index 87% rename from src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index 02c4391baf..240cc8e231 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -21,10 +21,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // ty::Const // + ty: &[u32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 @@ -33,10 +33,10 @@ _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32 - _7 = Len((*_2)); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 -- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 } bb1: { diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs index ee460a488b..8283ec73d0 100644 --- a/src/test/mir-opt/copy_propagation.rs +++ b/src/test/mir-opt/copy_propagation.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zunsound-mir-opts // EMIT_MIR copy_propagation.test.CopyPropagation.diff fn test(x: u32) -> u32 { diff --git a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff index f2838638ac..152d159063 100644 --- a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff @@ -2,24 +2,19 @@ + // MIR for `test` after CopyPropagation fn test(_1: u32) -> u32 { - debug x => _1; // in scope 0 at $DIR/copy_propagation.rs:3:9: 3:10 - let mut _0: u32; // return place in scope 0 at $DIR/copy_propagation.rs:3:20: 3:23 - let _2: u32; // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 + debug x => _1; // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 + let mut _0: u32; // return place in scope 0 at $DIR/copy_propagation.rs:4:20: 4:23 + let _2: u32; // in scope 0 at $DIR/copy_propagation.rs:5:9: 5:10 scope 1 { -- debug y => _2; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10 -+ debug y => _1; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10 + debug y => _0; // in scope 1 at $DIR/copy_propagation.rs:5:9: 5:10 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 -- _2 = _1; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14 -- _0 = _2; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6 -- StorageDead(_2); // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2 -+ nop; // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 -+ nop; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14 -+ _0 = _1; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6 -+ nop; // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2 - return; // scope 0 at $DIR/copy_propagation.rs:6:2: 6:2 + nop; // scope 0 at $DIR/copy_propagation.rs:5:9: 5:10 + _0 = _1; // scope 0 at $DIR/copy_propagation.rs:5:13: 5:14 + nop; // scope 1 at $DIR/copy_propagation.rs:6:5: 6:6 + nop; // scope 0 at $DIR/copy_propagation.rs:7:1: 7:2 + return; // scope 0 at $DIR/copy_propagation.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff index a4d60ae25d..8aab2299d2 100644 --- a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff @@ -6,15 +6,15 @@ let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30 let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 scope 1 { - debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 + debug y => _0; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 } bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 - _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 + _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12 - _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 + nop; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2 } } diff --git a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff index b20003bd7c..1ea51fec71 100644 --- a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff @@ -7,10 +7,10 @@ let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2 } diff --git a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff index d07a4c0541..48ab37a239 100644 --- a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff @@ -8,10 +8,10 @@ let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 - _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 + _1 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14 // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar()) } @@ -19,8 +19,8 @@ bb1: { StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 - _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2 } diff --git a/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff new file mode 100644 index 0000000000..9c213eaed3 --- /dev/null +++ b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff @@ -0,0 +1,73 @@ +- // MIR for `main` before DestinationPropagation ++ // MIR for `main` after DestinationPropagation + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/branch.rs:12:11: 12:11 + let _1: i32; // in scope 0 at $DIR/branch.rs:13:9: 13:10 + let mut _3: bool; // in scope 0 at $DIR/branch.rs:15:16: 15:22 + let _4: i32; // in scope 0 at $DIR/branch.rs:18:9: 18:14 + scope 1 { +- debug x => _1; // in scope 1 at $DIR/branch.rs:13:9: 13:10 ++ debug x => _2; // in scope 1 at $DIR/branch.rs:13:9: 13:10 + let _2: i32; // in scope 1 at $DIR/branch.rs:15:9: 15:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/branch.rs:15:9: 15:10 + } + } + + bb0: { +- StorageLive(_1); // scope 0 at $DIR/branch.rs:13:9: 13:10 +- _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 ++ nop; // scope 0 at $DIR/branch.rs:13:9: 13:10 ++ _2 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 + // mir::Constant + // + span: $DIR/branch.rs:13:13: 13:16 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } + } + + bb1: { +- StorageLive(_2); // scope 1 at $DIR/branch.rs:15:9: 15:10 ++ nop; // scope 1 at $DIR/branch.rs:15:9: 15:10 + StorageLive(_3); // scope 1 at $DIR/branch.rs:15:16: 15:22 + _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:15:16: 15:22 + // mir::Constant + // + span: $DIR/branch.rs:15:16: 15:20 + // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar()) } + } + + bb2: { + switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 1 at $DIR/branch.rs:15:13: 20:6 + } + + bb3: { + StorageLive(_4); // scope 1 at $DIR/branch.rs:18:9: 18:14 + _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:18:9: 18:14 + // mir::Constant + // + span: $DIR/branch.rs:18:9: 18:12 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } + } + + bb4: { +- _2 = _1; // scope 1 at $DIR/branch.rs:16:9: 16:10 ++ nop; // scope 1 at $DIR/branch.rs:16:9: 16:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6 + } + + bb5: { + StorageDead(_4); // scope 1 at $DIR/branch.rs:18:14: 18:15 +- _2 = _1; // scope 1 at $DIR/branch.rs:19:9: 19:10 ++ nop; // scope 1 at $DIR/branch.rs:19:9: 19:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6 + } + + bb6: { + StorageDead(_3); // scope 1 at $DIR/branch.rs:20:6: 20:7 + _0 = const (); // scope 0 at $DIR/branch.rs:12:11: 21:2 +- StorageDead(_2); // scope 1 at $DIR/branch.rs:21:1: 21:2 +- StorageDead(_1); // scope 0 at $DIR/branch.rs:21:1: 21:2 ++ nop; // scope 1 at $DIR/branch.rs:21:1: 21:2 ++ nop; // scope 0 at $DIR/branch.rs:21:1: 21:2 + return; // scope 0 at $DIR/branch.rs:21:2: 21:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/branch.rs b/src/test/mir-opt/dest-prop/branch.rs new file mode 100644 index 0000000000..7e0e40671d --- /dev/null +++ b/src/test/mir-opt/dest-prop/branch.rs @@ -0,0 +1,21 @@ +//! Tests that assignment in both branches of an `if` are eliminated. + +fn val() -> i32 { + 1 +} + +fn cond() -> bool { + true +} + +// EMIT_MIR branch.main.DestinationPropagation.diff +fn main() { + let x = val(); + + let y = if cond() { + x + } else { + val(); + x + }; +} diff --git a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff new file mode 100644 index 0000000000..881c296cee --- /dev/null +++ b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff @@ -0,0 +1,72 @@ +- // MIR for `main` before DestinationPropagation ++ // MIR for `main` after DestinationPropagation + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:8:11: 8:11 + let mut _1: i32; // in scope 0 at $DIR/cycle.rs:9:9: 9:14 + let mut _4: i32; // in scope 0 at $DIR/cycle.rs:12:9: 12:10 + let _5: (); // in scope 0 at $DIR/cycle.rs:14:5: 14:12 + let mut _6: i32; // in scope 0 at $DIR/cycle.rs:14:10: 14:11 + scope 1 { +- debug x => _1; // in scope 1 at $DIR/cycle.rs:9:9: 9:14 ++ debug x => _4; // in scope 1 at $DIR/cycle.rs:9:9: 9:14 + let _2: i32; // in scope 1 at $DIR/cycle.rs:10:9: 10:10 + scope 2 { +- debug y => _2; // in scope 2 at $DIR/cycle.rs:10:9: 10:10 ++ debug y => _4; // in scope 2 at $DIR/cycle.rs:10:9: 10:10 + let _3: i32; // in scope 2 at $DIR/cycle.rs:11:9: 11:10 + scope 3 { +- debug z => _3; // in scope 3 at $DIR/cycle.rs:11:9: 11:10 ++ debug z => _4; // in scope 3 at $DIR/cycle.rs:11:9: 11:10 + scope 4 { + debug _x => _6; // in scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + } + } + } + + bb0: { +- StorageLive(_1); // scope 0 at $DIR/cycle.rs:9:9: 9:14 +- _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 ++ nop; // scope 0 at $DIR/cycle.rs:9:9: 9:14 ++ _4 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 + // mir::Constant + // + span: $DIR/cycle.rs:9:17: 9:20 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } + } + + bb1: { +- StorageLive(_2); // scope 1 at $DIR/cycle.rs:10:9: 10:10 +- _2 = _1; // scope 1 at $DIR/cycle.rs:10:13: 10:14 +- StorageLive(_3); // scope 2 at $DIR/cycle.rs:11:9: 11:10 +- _3 = _2; // scope 2 at $DIR/cycle.rs:11:13: 11:14 +- StorageLive(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10 +- _4 = _3; // scope 3 at $DIR/cycle.rs:12:9: 12:10 +- _1 = move _4; // scope 3 at $DIR/cycle.rs:12:5: 12:10 +- StorageDead(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10 ++ nop; // scope 1 at $DIR/cycle.rs:10:9: 10:10 ++ nop; // scope 1 at $DIR/cycle.rs:10:13: 10:14 ++ nop; // scope 2 at $DIR/cycle.rs:11:9: 11:10 ++ nop; // scope 2 at $DIR/cycle.rs:11:13: 11:14 ++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 ++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 ++ nop; // scope 3 at $DIR/cycle.rs:12:5: 12:10 ++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 + StorageLive(_5); // scope 3 at $DIR/cycle.rs:14:5: 14:12 + StorageLive(_6); // scope 3 at $DIR/cycle.rs:14:10: 14:11 +- _6 = _1; // scope 3 at $DIR/cycle.rs:14:10: 14:11 ++ _6 = _4; // scope 3 at $DIR/cycle.rs:14:10: 14:11 + _5 = const (); // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + StorageDead(_6); // scope 3 at $DIR/cycle.rs:14:11: 14:12 + StorageDead(_5); // scope 3 at $DIR/cycle.rs:14:12: 14:13 + _0 = const (); // scope 0 at $DIR/cycle.rs:8:11: 15:2 +- StorageDead(_3); // scope 2 at $DIR/cycle.rs:15:1: 15:2 +- StorageDead(_2); // scope 1 at $DIR/cycle.rs:15:1: 15:2 +- StorageDead(_1); // scope 0 at $DIR/cycle.rs:15:1: 15:2 ++ nop; // scope 2 at $DIR/cycle.rs:15:1: 15:2 ++ nop; // scope 1 at $DIR/cycle.rs:15:1: 15:2 ++ nop; // scope 0 at $DIR/cycle.rs:15:1: 15:2 + return; // scope 0 at $DIR/cycle.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/cycle.rs b/src/test/mir-opt/dest-prop/cycle.rs new file mode 100644 index 0000000000..7fbffb1335 --- /dev/null +++ b/src/test/mir-opt/dest-prop/cycle.rs @@ -0,0 +1,15 @@ +//! Tests that cyclic assignments don't hang DestinationPropagation, and result in reasonable code. + +fn val() -> i32 { + 1 +} + +// EMIT_MIR cycle.main.DestinationPropagation.diff +fn main() { + let mut x = val(); + let y = x; + let z = y; + x = z; + + drop(x); +} diff --git a/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff new file mode 100644 index 0000000000..3475d41b50 --- /dev/null +++ b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff @@ -0,0 +1,39 @@ +- // MIR for `nrvo` before DestinationPropagation ++ // MIR for `nrvo` after DestinationPropagation + + fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] { + debug init => _1; // in scope 0 at $DIR/simple.rs:4:9: 4:13 + let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/simple.rs:4:39: 4:49 + let mut _2: [u8; 1024]; // in scope 0 at $DIR/simple.rs:5:9: 5:16 + let _3: (); // in scope 0 at $DIR/simple.rs:6:5: 6:19 + let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/simple.rs:6:5: 6:9 + let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 + let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 + scope 1 { + debug buf => _2; // in scope 1 at $DIR/simple.rs:5:9: 5:16 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/simple.rs:5:9: 5:16 + _2 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 + StorageLive(_3); // scope 1 at $DIR/simple.rs:6:5: 6:19 + StorageLive(_4); // scope 1 at $DIR/simple.rs:6:5: 6:9 + _4 = _1; // scope 1 at $DIR/simple.rs:6:5: 6:9 + StorageLive(_5); // scope 1 at $DIR/simple.rs:6:10: 6:18 + StorageLive(_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 + _6 = &mut _2; // scope 1 at $DIR/simple.rs:6:10: 6:18 + _5 = &mut (*_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 + _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/simple.rs:6:5: 6:19 + } + + bb1: { + StorageDead(_5); // scope 1 at $DIR/simple.rs:6:18: 6:19 + StorageDead(_4); // scope 1 at $DIR/simple.rs:6:18: 6:19 + StorageDead(_6); // scope 1 at $DIR/simple.rs:6:19: 6:20 + StorageDead(_3); // scope 1 at $DIR/simple.rs:6:19: 6:20 + _0 = _2; // scope 1 at $DIR/simple.rs:7:5: 7:8 + StorageDead(_2); // scope 0 at $DIR/simple.rs:8:1: 8:2 + return; // scope 0 at $DIR/simple.rs:8:2: 8:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/simple.rs b/src/test/mir-opt/dest-prop/simple.rs new file mode 100644 index 0000000000..4655f96699 --- /dev/null +++ b/src/test/mir-opt/dest-prop/simple.rs @@ -0,0 +1,14 @@ +//! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too. + +// EMIT_MIR simple.nrvo.DestinationPropagation.diff +fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { + let mut buf = [0; 1024]; + init(&mut buf); + buf +} + +fn main() { + let _ = nrvo(|buf| { + buf[4] = 4; + }); +} diff --git a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff new file mode 100644 index 0000000000..f15e7bcb2f --- /dev/null +++ b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff @@ -0,0 +1,42 @@ +- // MIR for `main` before DestinationPropagation ++ // MIR for `main` after DestinationPropagation + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/union.rs:8:11: 8:11 + let _1: main::Un; // in scope 0 at $DIR/union.rs:13:9: 13:11 + let mut _2: u32; // in scope 0 at $DIR/union.rs:13:23: 13:28 + let _3: (); // in scope 0 at $DIR/union.rs:15:5: 15:27 + let mut _4: u32; // in scope 0 at $DIR/union.rs:15:10: 15:26 + scope 1 { + debug un => _1; // in scope 1 at $DIR/union.rs:13:9: 13:11 + scope 2 { + } + scope 3 { + debug _x => _4; // in scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/union.rs:13:9: 13:11 + StorageLive(_2); // scope 0 at $DIR/union.rs:13:23: 13:28 + _2 = val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28 + // mir::Constant + // + span: $DIR/union.rs:13:23: 13:26 + // + literal: Const { ty: fn() -> u32 {val}, val: Value(Scalar()) } + } + + bb1: { + (_1.0: u32) = move _2; // scope 0 at $DIR/union.rs:13:14: 13:30 + StorageDead(_2); // scope 0 at $DIR/union.rs:13:29: 13:30 + StorageLive(_3); // scope 1 at $DIR/union.rs:15:5: 15:27 + StorageLive(_4); // scope 1 at $DIR/union.rs:15:10: 15:26 + _4 = (_1.0: u32); // scope 2 at $DIR/union.rs:15:19: 15:24 + _3 = const (); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + StorageDead(_4); // scope 1 at $DIR/union.rs:15:26: 15:27 + StorageDead(_3); // scope 1 at $DIR/union.rs:15:27: 15:28 + _0 = const (); // scope 0 at $DIR/union.rs:8:11: 16:2 + StorageDead(_1); // scope 0 at $DIR/union.rs:16:1: 16:2 + return; // scope 0 at $DIR/union.rs:16:2: 16:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/union.rs b/src/test/mir-opt/dest-prop/union.rs new file mode 100644 index 0000000000..b9d831389e --- /dev/null +++ b/src/test/mir-opt/dest-prop/union.rs @@ -0,0 +1,16 @@ +//! Tests that projections through unions cancel `DestinationPropagation`. + +fn val() -> u32 { + 1 +} + +// EMIT_MIR union.main.DestinationPropagation.diff +fn main() { + union Un { + us: u32, + } + + let un = Un { us: val() }; + + drop(unsafe { un.us }); +} diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..386726bfdd --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -0,0 +1,77 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:3:9: 3:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:3:25: 3:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:3:44: 3:47 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:4:16: 4:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:4:16: 4:17 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 +- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 + } + + bb1: { ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 + } + + bb2: { +- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 +- switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 +- } +- +- bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + _9 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:5:31: 5:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 + } + +- bb4: { ++ bb3: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:8:1: 8:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:8:2: 8:2 ++ } ++ ++ bb4: { ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..bc5934dec8 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -0,0 +1,91 @@ +- // MIR for `opt2` before EarlyOtherwiseBranch ++ // MIR for `opt2` after EarlyOtherwiseBranch + + fn opt2(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:11:9: 11:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:11:25: 11:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:11:44: 11:47 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + let _10: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 ++ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 +- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ switchInt(move _12) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 + } + + bb1: { +- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 +- switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 +- } +- +- bb2: { ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 + } + +- bb3: { +- _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 +- switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 +- } +- +- bb4: { ++ bb2: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:13:31: 13:32 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 + } + +- bb5: { ++ bb3: { + _0 = const 0_u32; // scope 0 at $DIR/early_otherwise_branch.rs:14:25: 14:26 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 + } + +- bb6: { ++ bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:17:1: 17:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2 ++ } ++ ++ bb5: { ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.rs b/src/test/mir-opt/early_otherwise_branch.rs new file mode 100644 index 0000000000..7700344208 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.rs @@ -0,0 +1,22 @@ +// compile-flags: -Z mir-opt-level=3 +// EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +fn opt1(x: Option, y: Option) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + _ => 1, + } +} + +// EMIT_MIR early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +fn opt2(x: Option, y: Option) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + (None, None) => 0, + _ => 1, + } +} + +fn main() { + opt1(None, Some(0)); + opt2(None, Some(0)); +} diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..b0357f1aec --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -0,0 +1,99 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: Option, _2: Option, _3: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:9: 4:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:25: 4:26 + debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:41: 4:42 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:60: 4:63 + let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 + let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + let _13: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 ++ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 ++ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + scope 1 { + debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + } + + bb0: { + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 +- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ switchInt(move _15) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 + } + + bb1: { ++ StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 +- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 + } + + bb2: { +- _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 +- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 +- } +- +- bb3: { + _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 +- switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 ++ switchInt(move _8) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + } + +- bb4: { ++ bb3: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + _11 = (((_4.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + _12 = (((_4.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + _13 = (((_4.2: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 +- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 + } + +- bb5: { ++ bb4: { + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:1: 9:2 + return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:2: 9:2 ++ } ++ ++ bb5: { ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs new file mode 100644 index 0000000000..1d6877d67d --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs @@ -0,0 +1,13 @@ +// compile-flags: -Z mir-opt-level=3 + +// EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +fn opt1(x: Option, y: Option, z: Option) -> u32 { + match (x, y, z) { + (Some(a), Some(b), Some(c)) => 0, + _ => 1, + } +} + +fn main() { + opt1(None, Some(0), None); +} diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs new file mode 100644 index 0000000000..98a275c18a --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_68867.rs @@ -0,0 +1,33 @@ +// ignore-tidy-linelength +// compile-flags: -Z mir-opt-level=3 -Zunsound-mir-opts + +// example from #68867 +type CSSFloat = f32; + +pub enum ViewportPercentageLength { + Vw(CSSFloat), + Vh(CSSFloat), + Vmin(CSSFloat), + Vmax(CSSFloat), +} + +// EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-after-copy-prop.after +#[no_mangle] +pub extern "C" fn try_sum( + x: &ViewportPercentageLength, + other: &ViewportPercentageLength, +) -> Result { + use self::ViewportPercentageLength::*; + Ok(match (x, other) { + (&Vw(one), &Vw(other)) => Vw(one + other), + (&Vh(one), &Vh(other)) => Vh(one + other), + (&Vmin(one), &Vmin(other)) => Vmin(one + other), + (&Vmax(one), &Vmax(other)) => Vmax(one + other), + _ => return Err(()), + }) +} + +fn main() { + try_sum(&ViewportPercentageLength::Vw(1.0), &ViewportPercentageLength::Vw(2.0)); +} diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff new file mode 100644 index 0000000000..2cf5dd49d6 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff @@ -0,0 +1,304 @@ +- // MIR for `try_sum` before EarlyOtherwiseBranch ++ // MIR for `try_sum` after SimplifyBranches-after-copy-prop + + fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:6 + debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 19:10 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:6: 20:42 + let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 + let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + scope 1 { +- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ debug one => _15; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ debug other => _16; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + } + scope 2 { +- debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 +- debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 ++ debug one => _20; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 ++ debug other => _21; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + } + scope 3 { +- debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ debug one => _25; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ debug other => _26; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + } + scope 4 { +- debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 +- debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 ++ debug one => _30; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 ++ debug other => _31; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + } + + bb0: { +- StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 +- StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 +- _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 +- StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 +- _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 +- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 +- (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 +- StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 +- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 ++ (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 ++ (_4.1: &ViewportPercentageLength) = move _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 +- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + } + + bb1: { +- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- } +- +- bb2: { ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:27: 27:28 +- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 +- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + } + ++ bb2: { ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ _15 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ _16 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ } ++ + bb3: { +- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 +- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 ++ _20 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 ++ _21 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + + bb4: { +- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 +- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ _25 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ _26 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + + bb5: { +- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 +- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 ++ _30 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 ++ _31 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + + bb6: { +- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 +- _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 +- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 +- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 +- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 +- StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 +- _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 +- _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 +- StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 +- StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 +- ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 +- discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 +- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 ++ discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 ++ return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 + } + + bb7: { +- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 +- _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 +- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 +- _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 +- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 +- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 +- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 +- StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 +- _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 +- _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 +- StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 +- StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 +- ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 +- discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 +- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- } +- +- bb8: { +- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 +- _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 +- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 +- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 +- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 +- StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 +- _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 +- _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 +- StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 +- StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 +- ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 +- discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 +- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- } +- +- bb9: { +- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 +- _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 +- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 +- _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 +- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 +- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 +- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 +- StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 +- _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 +- _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 +- StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 +- StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 +- ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 +- discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 +- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- } +- +- bb10: { +- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 +- discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 +- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 +- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 +- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..a80bf2ac01 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -0,0 +1,216 @@ +- // MIR for `try_sum` before EarlyOtherwiseBranch ++ // MIR for `try_sum` after EarlyOtherwiseBranch + + fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:6 + debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 19:10 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:6: 20:42 + let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 + let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + scope 1 { + debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + } + scope 2 { + debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + } + scope 3 { + debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + } + scope 4 { + debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 +- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + } + + bb1: { +- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- } +- +- bb2: { ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:27: 27:28 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + } + +- bb3: { +- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 +- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 +- } +- +- bb4: { +- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 +- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 +- } +- +- bb5: { +- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 +- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 +- } +- +- bb6: { ++ bb2: { + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 + StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 + ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 + discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 + StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + +- bb7: { ++ bb3: { + StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 + StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 + ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 + discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 + StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 + StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 + StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + +- bb8: { ++ bb4: { + StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 + StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 + ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 + discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 + StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + +- bb9: { ++ bb5: { + StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 + StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 + ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 + discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 + StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 + StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 + StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + +- bb10: { ++ bb6: { + ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 + discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 ++ } ++ ++ bb7: { ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..9a6094f12d --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff @@ -0,0 +1,90 @@ +- // MIR for `noopt1` before EarlyOtherwiseBranch ++ // MIR for `noopt1` after EarlyOtherwiseBranch + + fn noopt1(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:11: 7:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:27: 7:28 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:46: 7:49 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + let _10: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + } + scope 2 { + debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + } + scope 3 { + debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 + switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 + } + + bb1: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 + switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 + } + + bb2: { + _0 = const 3_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 + switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 + } + + bb4: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 + } + + bb5: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _11 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _0 = const 1_u32; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 + } + + bb6: { + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + _12 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + _0 = const 2_u32; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 + } + + bb7: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:1: 14:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:2: 14:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..c3aecb4529 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff @@ -0,0 +1,60 @@ +- // MIR for `noopt2` before EarlyOtherwiseBranch ++ // MIR for `noopt2` after EarlyOtherwiseBranch + + fn noopt2(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:11: 18:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:27: 18:28 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:47: 18:50 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 + switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 + } + + bb1: { + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:14: 21:15 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 22:6 + } + + bb2: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 22:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:1: 23:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:2: 23:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs new file mode 100644 index 0000000000..bd15f520df --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs @@ -0,0 +1,28 @@ +// compile-flags: -Z mir-opt-level=3 + +// must not optimize as it does not follow the pattern of +// left and right hand side being the same variant + +// EMIT_MIR early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff +fn noopt1(x: Option, y: Option) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + (Some(a), None) => 1, + (None, Some(b)) => 2, + (None, None) => 3, + } +} + +// must not optimize as the types being matched on are not identical +// EMIT_MIR early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff +fn noopt2(x: Option, y: Option) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + _ => 1, + } +} + +fn main() { + noopt1(None, Some(0)); + noopt2(None, Some(true)); +} diff --git a/src/test/mir-opt/equal_true.opt.InstCombine.diff b/src/test/mir-opt/equal_true.opt.InstCombine.diff new file mode 100644 index 0000000000..a26776e70d --- /dev/null +++ b/src/test/mir-opt/equal_true.opt.InstCombine.diff @@ -0,0 +1,35 @@ +- // MIR for `opt` before InstCombine ++ // MIR for `opt` after InstCombine + + fn opt(_1: bool) -> i32 { + debug x => _1; // in scope 0 at $DIR/equal_true.rs:3:8: 3:9 + let mut _0: i32; // return place in scope 0 at $DIR/equal_true.rs:3:20: 3:23 + let mut _2: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:17 + let mut _3: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/equal_true.rs:4:8: 4:17 + StorageLive(_3); // scope 0 at $DIR/equal_true.rs:4:8: 4:9 + _3 = _1; // scope 0 at $DIR/equal_true.rs:4:8: 4:9 +- _2 = Eq(move _3, const true); // scope 0 at $DIR/equal_true.rs:4:8: 4:17 ++ _2 = move _3; // scope 0 at $DIR/equal_true.rs:4:8: 4:17 + StorageDead(_3); // scope 0 at $DIR/equal_true.rs:4:16: 4:17 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 + } + + bb1: { + _0 = const 1_i32; // scope 0 at $DIR/equal_true.rs:4:31: 4:32 + goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 + } + + bb2: { + _0 = const 0_i32; // scope 0 at $DIR/equal_true.rs:4:20: 4:21 + goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/equal_true.rs:5:1: 5:2 + return; // scope 0 at $DIR/equal_true.rs:5:2: 5:2 + } + } + diff --git a/src/test/mir-opt/equal_true.rs b/src/test/mir-opt/equal_true.rs new file mode 100644 index 0000000000..994cd194a4 --- /dev/null +++ b/src/test/mir-opt/equal_true.rs @@ -0,0 +1,9 @@ +// EMIT_MIR equal_true.opt.InstCombine.diff + +fn opt(x: bool) -> i32 { + if x == true { 0 } else { 1 } +} + +fn main() { + opt(true); +} diff --git a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir index 28364d4fbf..0db0f8349b 100644 --- a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir @@ -1,6 +1,6 @@ // MIR for `match_tuple` after SimplifyCfg-initial -fn match_tuple(_1: (u32, bool, std::option::Option, u32)) -> u32 { +fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { debug x => _1; // in scope 0 at $DIR/exponential-or.rs:6:16: 6:17 let mut _0: u32; // return place in scope 0 at $DIR/exponential-or.rs:6:53: 6:56 let mut _2: isize; // in scope 0 at $DIR/exponential-or.rs:8:37: 8:48 diff --git a/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir b/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir index 199cbcf837..bcc6042f2f 100644 --- a/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir +++ b/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir @@ -1,7 +1,7 @@ // MIR for `std::ops::Fn::call` before AddMovesForPackedDrops -fn std::ops::Fn::call(_1: *const fn(), _2: Args) -> >::Output { - let mut _0: >::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL +fn std::ops::Fn::call(_1: *const fn(), _2: ()) -> >::Output { + let mut _0: >::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL bb0: { _0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index 9bf666bc76..bb79cd80e5 100644 --- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -1,7 +1,7 @@ - // MIR for `float_to_exponential_common` before ConstProp + // MIR for `float_to_exponential_common` after ConstProp - fn float_to_exponential_common(_1: &mut std::fmt::Formatter, _2: &T, _3: bool) -> std::result::Result<(), std::fmt::Error> { + fn float_to_exponential_common(_1: &mut Formatter, _2: &T, _3: bool) -> std::result::Result<(), std::fmt::Error> { debug fmt => _1; // in scope 0 at $DIR/funky_arms.rs:11:35: 11:38 debug num => _2; // in scope 0 at $DIR/funky_arms.rs:11:60: 11:63 debug upper => _3; // in scope 0 at $DIR/funky_arms.rs:11:69: 11:74 @@ -38,7 +38,7 @@ StorageLive(_4); // scope 0 at $DIR/funky_arms.rs:15:9: 15:19 StorageLive(_5); // scope 0 at $DIR/funky_arms.rs:15:22: 15:25 _5 = &(*_1); // scope 0 at $DIR/funky_arms.rs:15:22: 15:25 - _4 = std::fmt::Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 + _4 = Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 // mir::Constant // + span: $DIR/funky_arms.rs:15:26: 15:35 // + literal: Const { ty: for<'r> fn(&'r std::fmt::Formatter) -> bool {std::fmt::Formatter::sign_plus}, val: Value(Scalar()) } @@ -64,7 +64,7 @@ StorageLive(_7); // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 StorageLive(_8); // scope 2 at $DIR/funky_arms.rs:24:30: 24:33 _8 = &(*_1); // scope 2 at $DIR/funky_arms.rs:24:30: 24:33 - _7 = std::fmt::Formatter::precision(move _8) -> bb5; // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 + _7 = Formatter::precision(move _8) -> bb5; // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 // mir::Constant // + span: $DIR/funky_arms.rs:24:34: 24:43 // + literal: Const { ty: for<'r> fn(&'r std::fmt::Formatter) -> std::option::Option {std::fmt::Formatter::precision}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/generator-drop-cleanup.rs b/src/test/mir-opt/generator-drop-cleanup.rs index f4fc2aec70..82c1292cbd 100644 --- a/src/test/mir-opt/generator-drop-cleanup.rs +++ b/src/test/mir-opt/generator-drop-cleanup.rs @@ -5,7 +5,7 @@ // Regression test for #58892, generator drop shims should not have blocks // spuriously marked as cleanup -// EMIT_MIR generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir +// EMIT_MIR generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir fn main() { let gen = || { let _s = String::new(); diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index ae9faaefdd..b72170adec 100644 --- a/src/test/mir-opt/generator-storage-dead-unwind.rs +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -17,7 +17,7 @@ struct Bar(i32); fn take(_x: T) {} -// EMIT_MIR generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir +// EMIT_MIR generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir fn main() { let _gen = || { let a = Foo(5); diff --git a/src/test/mir-opt/generator-tiny.rs b/src/test/mir-opt/generator-tiny.rs index 0e79f16255..7dad63a61d 100644 --- a/src/test/mir-opt/generator-tiny.rs +++ b/src/test/mir-opt/generator-tiny.rs @@ -14,7 +14,7 @@ impl Drop for HasDrop { fn callee() {} -// EMIT_MIR generator_tiny.main-{{closure}}.generator_resume.0.mir +// EMIT_MIR generator_tiny.main-{closure#0}.generator_resume.0.mir fn main() { let _gen = |_x: u8| { let _d = HasDrop; diff --git a/src/test/mir-opt/generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir similarity index 95% rename from src/test/mir-opt/generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir rename to src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir index bd64a31663..31f85469c2 100644 --- a/src/test/mir-opt/generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir +++ b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir @@ -1,4 +1,4 @@ -// MIR for `main::{{closure}}#0` 0 generator_drop +// MIR for `main::{closure#0}` 0 generator_drop /* generator_layout = GeneratorLayout { field_tys: { _0: std::string::String, @@ -14,7 +14,7 @@ }, } */ -fn main::{{closure}}#0(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {std::string::String, ()}]) -> () { +fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {String, ()}]) -> () { let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15 diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir similarity index 97% rename from src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir rename to src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir index b6cda80683..b76e41230e 100644 --- a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir +++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir @@ -1,6 +1,6 @@ -// MIR for `main::{{closure}}#0` before StateTransform +// MIR for `main::{closure#0}` before StateTransform -fn main::{{closure}}#0(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6 {Foo, Bar, ()}], _2: ()) -> () +fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6 {Foo, Bar, ()}], _2: ()) -> () yields () { let mut _0: (); // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 22:19 diff --git a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir similarity index 95% rename from src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir rename to src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir index 691f5eedad..990aa1ec08 100644 --- a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir +++ b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir @@ -1,4 +1,4 @@ -// MIR for `main::{{closure}}#0` 0 generator_resume +// MIR for `main::{closure#0}` 0 generator_resume /* generator_layout = GeneratorLayout { field_tys: {}, variant_fields: { @@ -10,7 +10,7 @@ storage_conflicts: BitMatrix(0x0) {}, } */ -fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> std::ops::GeneratorState<(), ()> { +fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> GeneratorState<(), ()> { debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15 diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot b/src/test/mir-opt/graphviz.main.mir_map.0.dot index f5d8b84812..df4f11f0f2 100644 --- a/src/test/mir-opt/graphviz.main.mir_map.0.dot +++ b/src/test/mir-opt/graphviz.main.mir_map.0.dot @@ -1,7 +1,7 @@ digraph Mir_0_3 { - graph [fontname="monospace"]; - node [fontname="monospace"]; - edge [fontname="monospace"]; + graph [fontname="Courier, monospace"]; + node [fontname="Courier, monospace"]; + edge [fontname="Courier, monospace"]; label=>; bb0__0_3 [shape="none", label=<
    0
    _0 = const ()
    goto
    >]; bb1__0_3 [shape="none", label=<
    1
    resume
    >]; diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir b/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir new file mode 100644 index 0000000000..df4f11f0f2 --- /dev/null +++ b/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir @@ -0,0 +1,10 @@ +digraph Mir_0_3 { + graph [fontname="Courier, monospace"]; + node [fontname="Courier, monospace"]; + edge [fontname="Courier, monospace"]; + label=>; + bb0__0_3 [shape="none", label=<
    0
    _0 = const ()
    goto
    >]; + bb1__0_3 [shape="none", label=<
    1
    resume
    >]; + bb2__0_3 [shape="none", label=<
    2
    return
    >]; + bb0__0_3 -> bb2__0_3 [label=""]; +} diff --git a/src/test/mir-opt/if-condition-int.rs b/src/test/mir-opt/if-condition-int.rs new file mode 100644 index 0000000000..b34389a0ab --- /dev/null +++ b/src/test/mir-opt/if-condition-int.rs @@ -0,0 +1,65 @@ +// compile-flags: -O +// EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.opt_i8.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff + +fn opt_u32(x: u32) -> u32 { + if x == 42 { 0 } else { 1 } +} + +// don't opt: it is already optimal to switch on the bool +fn dont_opt_bool(x: bool) -> u32 { + if x { 0 } else { 1 } +} + +fn opt_char(x: char) -> u32 { + if x == 'x' { 0 } else { 1 } +} + +fn opt_i8(x: i8) -> u32 { + if x == 42 { 0 } else { 1 } +} + +fn opt_negative(x: i32) -> u32 { + if x == -42 { 0 } else { 1 } +} + +fn opt_multiple_ifs(x: u32) -> u32 { + if x == 42 { + 0 + } else if x != 21 { + 1 + } else { + 2 + } +} + +// test that we optimize, but do not remove the b statement, as that is used later on +fn dont_remove_comparison(a: i8) -> i32 { + let b = a == 17; + match b { + false => 10 + b as i32, + true => 100 + b as i32, + } +} + +// test that we do not optimize on floats +fn dont_opt_floats(a: f32) -> i32 { + if a == -42.0 { 0 } else { 1 } +} + +fn main() { + opt_u32(0); + opt_char('0'); + opt_i8(22); + dont_opt_bool(false); + opt_negative(0); + opt_multiple_ifs(0); + dont_remove_comparison(11); + dont_opt_floats(1.0); +} diff --git a/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..993ff660ca --- /dev/null +++ b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff @@ -0,0 +1,30 @@ +- // MIR for `dont_opt_bool` before SimplifyComparisonIntegral ++ // MIR for `dont_opt_bool` after SimplifyComparisonIntegral + + fn dont_opt_bool(_1: bool) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:16:18: 16:19 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:16:30: 16:33 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 + _2 = _1; // scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26 + } + + bb1: { + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:17:23: 17:24 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26 + } + + bb2: { + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:17:12: 17:13 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:18:1: 18:2 + return; // scope 0 at $DIR/if-condition-int.rs:18:2: 18:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..8ae9168c95 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff @@ -0,0 +1,37 @@ +- // MIR for `dont_opt_floats` before SimplifyComparisonIntegral ++ // MIR for `dont_opt_floats` after SimplifyComparisonIntegral + + fn dont_opt_floats(_1: f32) -> i32 { + debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:52:20: 52:21 + let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:52:31: 52:34 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 + let mut _3: f32; // in scope 0 at $DIR/if-condition-int.rs:53:8: 53:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:53:8: 53:9 + _2 = Eq(move _3, const -42f32); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 + // mir::Constant + // + span: $DIR/if-condition-int.rs:53:13: 53:18 + // + literal: Const { ty: f32, val: Value(Scalar(0xc2280000)) } + StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:53:17: 53:18 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35 + } + + bb1: { + _0 = const 1_i32; // scope 0 at $DIR/if-condition-int.rs:53:32: 53:33 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35 + } + + bb2: { + _0 = const 0_i32; // scope 0 at $DIR/if-condition-int.rs:53:21: 53:22 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:54:1: 54:2 + return; // scope 0 at $DIR/if-condition-int.rs:54:2: 54:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..b590be5370 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff @@ -0,0 +1,58 @@ +- // MIR for `dont_remove_comparison` before SimplifyComparisonIntegral ++ // MIR for `dont_remove_comparison` after SimplifyComparisonIntegral + + fn dont_remove_comparison(_1: i8) -> i32 { + debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:43:27: 43:28 + let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:43:37: 43:40 + let _2: bool; // in scope 0 at $DIR/if-condition-int.rs:44:9: 44:10 + let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:44:13: 44:14 + let mut _4: i32; // in scope 0 at $DIR/if-condition-int.rs:46:23: 46:31 + let mut _5: bool; // in scope 0 at $DIR/if-condition-int.rs:46:23: 46:24 + let mut _6: i32; // in scope 0 at $DIR/if-condition-int.rs:47:23: 47:31 + let mut _7: bool; // in scope 0 at $DIR/if-condition-int.rs:47:23: 47:24 + scope 1 { + debug b => _2; // in scope 1 at $DIR/if-condition-int.rs:44:9: 44:10 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:44:9: 44:10 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:14 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:44:13: 44:14 +- _2 = Eq(move _3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:20 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:44:19: 44:20 +- switchInt(_2) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14 ++ _2 = Eq(_3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:20 ++ nop; // scope 0 at $DIR/if-condition-int.rs:44:19: 44:20 ++ switchInt(move _3) -> [17_i8: bb1, otherwise: bb2]; // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14 + } + + bb1: { ++ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14 + StorageLive(_6); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:31 + StorageLive(_7); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:24 + _7 = _2; // scope 1 at $DIR/if-condition-int.rs:47:23: 47:24 + _6 = move _7 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:31 + StorageDead(_7); // scope 1 at $DIR/if-condition-int.rs:47:30: 47:31 + _0 = Add(const 100_i32, move _6); // scope 1 at $DIR/if-condition-int.rs:47:17: 47:31 + StorageDead(_6); // scope 1 at $DIR/if-condition-int.rs:47:30: 47:31 + goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:45:5: 48:6 + } + + bb2: { ++ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14 + StorageLive(_4); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:31 + StorageLive(_5); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:24 + _5 = _2; // scope 1 at $DIR/if-condition-int.rs:46:23: 46:24 + _4 = move _5 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:31 + StorageDead(_5); // scope 1 at $DIR/if-condition-int.rs:46:30: 46:31 + _0 = Add(const 10_i32, move _4); // scope 1 at $DIR/if-condition-int.rs:46:18: 46:31 + StorageDead(_4); // scope 1 at $DIR/if-condition-int.rs:46:30: 46:31 + goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:45:5: 48:6 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:49:1: 49:2 + return; // scope 0 at $DIR/if-condition-int.rs:49:2: 49:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..ae0960028a --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff @@ -0,0 +1,39 @@ +- // MIR for `opt_char` before SimplifyComparisonIntegral ++ // MIR for `opt_char` after SimplifyComparisonIntegral + + fn opt_char(_1: char) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:20:13: 20:14 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:20:25: 20:28 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 + let mut _3: char; // in scope 0 at $DIR/if-condition-int.rs:21:8: 21:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:21:8: 21:9 +- _2 = Eq(move _3, const 'x'); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:15: 21:16 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 ++ _2 = Eq(_3, const 'x'); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 ++ nop; // scope 0 at $DIR/if-condition-int.rs:21:15: 21:16 ++ switchInt(move _3) -> ['x': bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:21:30: 21:31 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:21:19: 21:20 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:22:1: 22:2 + return; // scope 0 at $DIR/if-condition-int.rs:22:2: 22:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..8d59e51ac2 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff @@ -0,0 +1,39 @@ +- // MIR for `opt_i8` before SimplifyComparisonIntegral ++ // MIR for `opt_i8` after SimplifyComparisonIntegral + + fn opt_i8(_1: i8) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:24:11: 24:12 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:24:21: 24:24 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 + let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:25:8: 25:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:25:8: 25:9 +- _2 = Eq(move _3, const 42_i8); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:14: 25:15 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 ++ _2 = Eq(_3, const 42_i8); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:25:14: 25:15 ++ switchInt(move _3) -> [42_i8: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:25:29: 25:30 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:25:18: 25:19 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:26:1: 26:2 + return; // scope 0 at $DIR/if-condition-int.rs:26:2: 26:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..c4975661ef --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff @@ -0,0 +1,65 @@ +- // MIR for `opt_multiple_ifs` before SimplifyComparisonIntegral ++ // MIR for `opt_multiple_ifs` after SimplifyComparisonIntegral + + fn opt_multiple_ifs(_1: u32) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:32:21: 32:22 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:32:32: 32:35 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 + let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:33:8: 33:9 + let mut _4: bool; // in scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 + let mut _5: u32; // in scope 0 at $DIR/if-condition-int.rs:35:15: 35:16 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:33:8: 33:9 +- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:14: 33:15 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 ++ _2 = Eq(_3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:33:14: 33:15 ++ switchInt(move _3) -> [42_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + StorageLive(_4); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 + StorageLive(_5); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:16 + _5 = _1; // scope 0 at $DIR/if-condition-int.rs:35:15: 35:16 +- _4 = Ne(move _5, const 21_u32); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 +- StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:21: 35:22 +- switchInt(_4) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 ++ _4 = Ne(_5, const 21_u32); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 ++ nop; // scope 0 at $DIR/if-condition-int.rs:35:21: 35:22 ++ switchInt(move _5) -> [21_u32: bb3, otherwise: bb4]; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:34:9: 34:10 + goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + } + + bb3: { ++ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + _0 = const 2_u32; // scope 0 at $DIR/if-condition-int.rs:38:9: 38:10 + goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + } + + bb4: { ++ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:36:9: 36:10 + goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + } + + bb5: { + StorageDead(_4); // scope 0 at $DIR/if-condition-int.rs:39:5: 39:6 + goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + } + + bb6: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:40:1: 40:2 + return; // scope 0 at $DIR/if-condition-int.rs:40:2: 40:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..d7f544e44c --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff @@ -0,0 +1,39 @@ +- // MIR for `opt_negative` before SimplifyComparisonIntegral ++ // MIR for `opt_negative` after SimplifyComparisonIntegral + + fn opt_negative(_1: i32) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:28:17: 28:18 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:28:28: 28:31 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 + let mut _3: i32; // in scope 0 at $DIR/if-condition-int.rs:29:8: 29:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:29:8: 29:9 +- _2 = Eq(move _3, const -42_i32); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:15: 29:16 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 ++ _2 = Eq(_3, const -42_i32); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 ++ nop; // scope 0 at $DIR/if-condition-int.rs:29:15: 29:16 ++ switchInt(move _3) -> [-42_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:29:30: 29:31 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:29:19: 29:20 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:30:1: 30:2 + return; // scope 0 at $DIR/if-condition-int.rs:30:2: 30:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..51e00e680c --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff @@ -0,0 +1,39 @@ +- // MIR for `opt_u32` before SimplifyComparisonIntegral ++ // MIR for `opt_u32` after SimplifyComparisonIntegral + + fn opt_u32(_1: u32) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:11:12: 11:13 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:11:23: 11:26 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 + let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:12:8: 12:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:12:8: 12:9 +- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:14: 12:15 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 ++ _2 = Eq(_3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:12:14: 12:15 ++ switchInt(move _3) -> [42_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:12:29: 12:30 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:12:18: 12:19 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:13:1: 13:2 + return; // scope 0 at $DIR/if-condition-int.rs:13:2: 13:2 + } + } + diff --git a/src/test/mir-opt/inline/inline-async.rs b/src/test/mir-opt/inline/inline-async.rs new file mode 100644 index 0000000000..5c838159b9 --- /dev/null +++ b/src/test/mir-opt/inline/inline-async.rs @@ -0,0 +1,18 @@ +// Checks that inliner doesn't introduce cycles when optimizing generators. +// The outcome of optimization is not verfied, just the absence of the cycle. +// Regression test for #76181. +// +// edition:2018 + +#![crate_type = "lib"] + +pub struct S; + +impl S { + pub async fn g(&mut self) { + self.h(); + } + pub fn h(&mut self) { + let _ = self.g(); + } +} diff --git a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs index 218bc3553a..d76bc33f52 100644 --- a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z span_free_formats +// compile-flags: -Z span_free_formats -Zunsound-mir-opts // Tests that MIR inliner can handle closure arguments, // even when (#45894) diff --git a/src/test/mir-opt/inline/inline-compatibility.rs b/src/test/mir-opt/inline/inline-compatibility.rs new file mode 100644 index 0000000000..ff9049edb4 --- /dev/null +++ b/src/test/mir-opt/inline/inline-compatibility.rs @@ -0,0 +1,39 @@ +// Checks that only functions with compatible attributes are inlined. +// +// only-x86_64 +// needs-sanitizer-address +// compile-flags: -Zsanitizer=address + +#![crate_type = "lib"] +#![feature(no_sanitize)] +#![feature(target_feature_11)] + +// EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff +#[target_feature(enable = "sse2")] +pub unsafe fn inlined_target_feature() { + target_feature(); +} + +// EMIT_MIR inline_compatibility.not_inlined_target_feature.Inline.diff +pub unsafe fn not_inlined_target_feature() { + target_feature(); +} + +// EMIT_MIR inline_compatibility.inlined_no_sanitize.Inline.diff +#[no_sanitize(address)] +pub unsafe fn inlined_no_sanitize() { + no_sanitize(); +} + +// EMIT_MIR inline_compatibility.not_inlined_no_sanitize.Inline.diff +pub unsafe fn not_inlined_no_sanitize() { + no_sanitize(); +} + +#[inline] +#[target_feature(enable = "sse2")] +pub unsafe fn target_feature() {} + +#[inline] +#[no_sanitize(address, memory)] +pub unsafe fn no_sanitize() {} diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index 9d490f047f..4d623297f8 100644 --- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -4,13 +4,15 @@ fn bar() -> bool { let mut _0: bool; // return place in scope 0 at $DIR/inline-any-operand.rs:10:13: 10:17 let _1: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:11:9: 11:10 let mut _2: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:6 - let mut _3: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 - let mut _4: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _5: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _6: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 scope 1 { debug f => _1; // in scope 1 at $DIR/inline-any-operand.rs:11:9: 11:10 scope 2 { - debug x => _3; // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9 - debug y => _4; // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17 + debug x => _5; // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9 + debug y => _6; // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17 + let mut _3: i32; // in scope 2 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _4: i32; // in scope 2 at $DIR/inline-any-operand.rs:12:5: 12:13 } } @@ -22,9 +24,19 @@ fn bar() -> bool { // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar()) } StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 _2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 - _3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 - _4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_5); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + _5 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_6); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + _6 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_3); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6 + _3 = _5; // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6 + StorageLive(_4); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + _4 = _6; // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 _0 = Eq(move _3, move _4); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11 + StorageDead(_4); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + StorageDead(_3); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + StorageDead(_6); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageDead(_5); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13 StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2 return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2 diff --git a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir index b40a8047c4..c970b1bfac 100644 --- a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir @@ -4,8 +4,8 @@ fn foo(_1: T, _2: i32) -> i32 { debug _t => _1; // in scope 0 at $DIR/inline-closure.rs:10:17: 10:19 debug q => _2; // in scope 0 at $DIR/inline-closure.rs:10:24: 10:25 let mut _0: i32; // return place in scope 0 at $DIR/inline-closure.rs:10:35: 10:38 - let _3: [closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure.rs:11:9: 11:10 - let mut _4: &[closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure.rs:12:5: 12:6 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:11:9: 11:10 + let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:12:5: 12:6 let mut _5: (i32, i32); // in scope 0 at $DIR/inline-closure.rs:12:5: 12:12 let mut _6: i32; // in scope 0 at $DIR/inline-closure.rs:12:7: 12:8 let mut _7: i32; // in scope 0 at $DIR/inline-closure.rs:12:10: 12:11 @@ -30,9 +30,13 @@ fn foo(_1: T, _2: i32) -> i32 { _7 = _2; // scope 1 at $DIR/inline-closure.rs:12:10: 12:11 (_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 (_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _0 = _8; // scope 2 at $DIR/inline-closure.rs:11:22: 11:24 + StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir index f6dd741364..2f2db51ec8 100644 --- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir @@ -4,18 +4,19 @@ fn foo(_1: T, _2: &i32) -> i32 { debug _t => _1; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:17: 11:19 debug q => _2; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:24: 11:25 let mut _0: i32; // return place in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:36: 11:39 - let _3: [closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 - let mut _4: &[closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 + let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6 let mut _5: (&i32, &i32); // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 let mut _6: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:7: 16:8 let mut _7: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 - let mut _8: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 let mut _9: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + let mut _10: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 scope 1 { debug x => _3; // in scope 1 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 scope 2 { - debug r => _8; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:14: 12:15 - debug _s => _9; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:23: 12:25 + debug r => _9; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:14: 12:15 + debug _s => _10; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:23: 12:25 + let _8: &i32; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 } } scope 3 { @@ -33,9 +34,16 @@ fn foo(_1: T, _2: &i32) -> i32 { _7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 (_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 (_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18 + StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + _9 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_10); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + _10 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_8); // scope 2 at $DIR/inline-closure-borrows-arg.rs:13:13: 13:21 + _8 = _9; // scope 2 at $DIR/inline-closure-borrows-arg.rs:13:24: 13:27 + _0 = (*_9); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18 + StorageDead(_8); // scope 2 at $DIR/inline-closure-borrows-arg.rs:15:5: 15:6 + StorageDead(_10); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index e2b5d6567c..5138b50c9f 100644 --- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -4,21 +4,20 @@ fn foo(_1: T, _2: i32) -> (i32, T) { debug t => _1; // in scope 0 at $DIR/inline-closure-captures.rs:10:17: 10:18 debug q => _2; // in scope 0 at $DIR/inline-closure-captures.rs:10:23: 10:24 let mut _0: (i32, T); // return place in scope 0 at $DIR/inline-closure-captures.rs:10:34: 10:42 - let _3: [closure@foo::{{closure}}#0 q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10 let mut _4: &i32; // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 let mut _5: &T; // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 - let mut _6: &[closure@foo::{{closure}}#0 q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6 + let mut _6: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6 let mut _7: (i32,); // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 let mut _8: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:7: 12:8 - let mut _11: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 + let mut _10: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 scope 1 { debug x => _3; // in scope 1 at $DIR/inline-closure-captures.rs:11:9: 11:10 scope 2 { - debug _q => _11; // in scope 2 at $DIR/inline-closure-captures.rs:11:14: 11:16 + debug _q => _10; // in scope 2 at $DIR/inline-closure-captures.rs:11:14: 11:16 debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline-closure-captures.rs:10:23: 10:24 debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:10:17: 10:18 - let mut _9: i32; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9 - let mut _10: T; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9 + let mut _9: T; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9 } } @@ -38,15 +37,14 @@ fn foo(_1: T, _2: i32) -> (i32, T) { StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 _8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 (_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 - _11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 - StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 - _9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 - StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 - _10 = (*((*_6).1: &T)); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 - (_0.0: i32) = move _9; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 - (_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 - StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 + StorageLive(_10); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + _10 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + (_0.0: i32) = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + _9 = (*((*_6).1: &T)); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + (_0.1: T) = move _9; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 + StorageDead(_10); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff new file mode 100644 index 0000000000..7b0ecaffdd --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff @@ -0,0 +1,25 @@ +- // MIR for `inlined_no_sanitize` before Inline ++ // MIR for `inlined_no_sanitize` after Inline + + fn inlined_no_sanitize() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:24:37: 24:37 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:25:5: 25:18 ++ scope 1 { ++ } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:25:5: 25:18 +- _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:25:5: 25:18 +- // mir::Constant +- // + span: $DIR/inline-compatibility.rs:25:5: 25:16 +- // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar()) } +- } +- +- bb1: { ++ _1 = const (); // scope 1 at $DIR/inline-compatibility.rs:39:29: 39:31 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:25:18: 25:19 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:24:37: 26:2 + return; // scope 0 at $DIR/inline-compatibility.rs:26:2: 26:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff new file mode 100644 index 0000000000..f55eae6c50 --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff @@ -0,0 +1,25 @@ +- // MIR for `inlined_target_feature` before Inline ++ // MIR for `inlined_target_feature` after Inline + + fn inlined_target_feature() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:13:40: 13:40 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:14:5: 14:21 ++ scope 1 { ++ } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:14:5: 14:21 +- _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:14:5: 14:21 +- // mir::Constant +- // + span: $DIR/inline-compatibility.rs:14:5: 14:19 +- // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar()) } +- } +- +- bb1: { ++ _1 = const (); // scope 1 at $DIR/inline-compatibility.rs:35:32: 35:34 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:14:21: 14:22 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:13:40: 15:2 + return; // scope 0 at $DIR/inline-compatibility.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff new file mode 100644 index 0000000000..651eadc1e8 --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff @@ -0,0 +1,22 @@ +- // MIR for `not_inlined_no_sanitize` before Inline ++ // MIR for `not_inlined_no_sanitize` after Inline + + fn not_inlined_no_sanitize() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:29:41: 29:41 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:30:5: 30:18 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:30:5: 30:18 + _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:30:5: 30:18 + // mir::Constant + // + span: $DIR/inline-compatibility.rs:30:5: 30:16 + // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar()) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:30:18: 30:19 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:29:41: 31:2 + return; // scope 0 at $DIR/inline-compatibility.rs:31:2: 31:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff new file mode 100644 index 0000000000..55b9edf3ad --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff @@ -0,0 +1,22 @@ +- // MIR for `not_inlined_target_feature` before Inline ++ // MIR for `not_inlined_target_feature` after Inline + + fn not_inlined_target_feature() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:18:44: 18:44 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:19:5: 19:21 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:19:5: 19:21 + _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:19:5: 19:21 + // mir::Constant + // + span: $DIR/inline-compatibility.rs:19:5: 19:19 + // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar()) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:19:21: 19:22 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:18:44: 20:2 + return; // scope 0 at $DIR/inline-compatibility.rs:20:2: 20:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff similarity index 89% rename from src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit rename to src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff index 0957698820..2d52f034e5 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff @@ -17,9 +17,9 @@ StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = std::vec::Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- (*_2) = Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: std::ptr::Unique:: { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL ++ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL + // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -54,7 +54,7 @@ - } - - bb4 (cleanup): { -- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>) {alloc::alloc::box_free::>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff similarity index 89% rename from src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit rename to src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff index ab065fc3d2..d4e2df6fbf 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff @@ -17,9 +17,9 @@ StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = std::vec::Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- (*_2) = Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: std::ptr::Unique:: { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL ++ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL + // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -54,7 +54,7 @@ - } - - bb4 (cleanup): { -- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>) {alloc::alloc::box_free::>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir index 29327108f3..5258f67ebd 100644 --- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir @@ -35,10 +35,10 @@ fn bar() -> bool { _10 = const bar::promoted[1]; // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $DIR/inline-retag.rs:12:7: 12:9 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[1])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[1])) } Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 _4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 @@ -49,10 +49,10 @@ fn bar() -> bool { _9 = const bar::promoted[0]; // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/inline-retag.rs:12:11: 12:14 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[0])) } Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 _7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 diff --git a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff index e97191b53e..2ffc025235 100644 --- a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff @@ -12,7 +12,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/inline-specialization.rs:5:9: 5:10 -- _1 = as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38 +- _1 = as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38 - // mir::Constant - // + span: $DIR/inline-specialization.rs:5:13: 5:36 - // + literal: Const { ty: fn() -> u32 { as Foo>::bar}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir index 00e3ef06a4..0954620596 100644 --- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir @@ -7,6 +7,7 @@ fn test2(_1: &dyn X) -> bool { let mut _3: &dyn X; // in scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 scope 1 { debug x => _2; // in scope 1 at $DIR/inline-trait-method_2.rs:9:9: 9:10 + let mut _4: &dyn X; // in scope 1 at $DIR/inline-trait-method_2.rs:5:5: 5:12 } bb0: { @@ -15,13 +16,16 @@ fn test2(_1: &dyn X) -> bool { _3 = &(*_1); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 StorageDead(_3); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 - _0 = ::y(move _2) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 + StorageLive(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:6 + _4 = _2; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:6 + _0 = ::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 // mir::Constant // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8 // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {::y}, val: Value(Scalar()) } } bb1: { + StorageDead(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:9: 10:10 StorageDead(_2); // scope 0 at $DIR/inline-trait-method_2.rs:5:11: 5:12 return; // scope 0 at $DIR/inline-trait-method_2.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir index 6add8d9d75..c9a6aed3d4 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir @@ -1,6 +1,6 @@ // MIR for `b` after Inline -fn b(_1: &mut std::boxed::Box) -> &mut T { +fn b(_1: &mut Box) -> &mut T { debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:7:13: 7:14 let mut _0: &mut T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:7:32: 7:38 let mut _2: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir index 51bda6d334..89f8aae73c 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir @@ -1,6 +1,6 @@ // MIR for `d` after Inline -fn d(_1: &std::boxed::Box) -> &T { +fn d(_1: &Box) -> &T { debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:17:13: 17:14 let mut _0: &T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:17:28: 17:30 let _2: &T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 diff --git a/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff new file mode 100644 index 0000000000..1d20e17a84 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff @@ -0,0 +1,92 @@ +- // MIR for `deep_opt` before InstCombine ++ // MIR for `deep_opt` after InstCombine + + fn deep_opt() -> (u64, u64, u64) { + let mut _0: (u64, u64, u64); // return place in scope 0 at $DIR/inst_combine_deref.rs:11:18: 11:33 + let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11 + let mut _10: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:6: 21:8 + let mut _11: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:10: 21:12 + let mut _12: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:14: 21:16 + scope 1 { + debug x1 => _1; // in scope 1 at $DIR/inst_combine_deref.rs:12:9: 12:11 + let _2: u64; // in scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11 + scope 2 { + debug x2 => _2; // in scope 2 at $DIR/inst_combine_deref.rs:13:9: 13:11 + let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11 + scope 3 { + debug x3 => _3; // in scope 3 at $DIR/inst_combine_deref.rs:14:9: 14:11 + let _4: &u64; // in scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11 + scope 4 { + debug y1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:15:9: 15:11 + let _5: &u64; // in scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11 + scope 5 { + debug y2 => _5; // in scope 5 at $DIR/inst_combine_deref.rs:16:9: 16:11 + let _6: &u64; // in scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11 + scope 6 { + debug y3 => _6; // in scope 6 at $DIR/inst_combine_deref.rs:17:9: 17:11 + let _7: u64; // in scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11 + scope 7 { + debug z1 => _7; // in scope 7 at $DIR/inst_combine_deref.rs:18:9: 18:11 + let _8: u64; // in scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11 + scope 8 { + debug z2 => _8; // in scope 8 at $DIR/inst_combine_deref.rs:19:9: 19:11 + let _9: u64; // in scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11 + scope 9 { + debug z3 => _9; // in scope 9 at $DIR/inst_combine_deref.rs:20:9: 20:11 + } + } + } + } + } + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11 + _1 = const 1_u64; // scope 0 at $DIR/inst_combine_deref.rs:12:14: 12:15 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11 + _2 = const 2_u64; // scope 1 at $DIR/inst_combine_deref.rs:13:14: 13:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11 + _3 = const 3_u64; // scope 2 at $DIR/inst_combine_deref.rs:14:14: 14:15 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11 + _4 = &_1; // scope 3 at $DIR/inst_combine_deref.rs:15:14: 15:17 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11 + _5 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:16:14: 16:17 + StorageLive(_6); // scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11 + _6 = &_3; // scope 5 at $DIR/inst_combine_deref.rs:17:14: 17:17 + StorageLive(_7); // scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11 +- _7 = (*_4); // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17 ++ _7 = _1; // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17 + StorageLive(_8); // scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11 +- _8 = (*_5); // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17 ++ _8 = _2; // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17 + StorageLive(_9); // scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11 +- _9 = (*_6); // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17 ++ _9 = _3; // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17 + StorageLive(_10); // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8 + _10 = _7; // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8 + StorageLive(_11); // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12 + _11 = _8; // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12 + StorageLive(_12); // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16 + _12 = _9; // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16 + (_0.0: u64) = move _10; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17 + (_0.1: u64) = move _11; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17 + (_0.2: u64) = move _12; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17 + StorageDead(_12); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17 + StorageDead(_11); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17 + StorageDead(_10); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17 + StorageDead(_9); // scope 8 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_8); // scope 7 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_7); // scope 6 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_6); // scope 5 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:22:1: 22:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:22:2: 22:2 + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff new file mode 100644 index 0000000000..23c18bde22 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff @@ -0,0 +1,85 @@ +- // MIR for `do_not_miscompile` before InstCombine ++ // MIR for `do_not_miscompile` after InstCombine + + fn do_not_miscompile() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inst_combine_deref.rs:54:24: 54:24 + let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10 + let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12 + let _6: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12 + let _7: (); // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23 + let mut _8: bool; // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23 + let mut _9: bool; // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:21 + let mut _10: i32; // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:15 + let mut _11: !; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + scope 1 { + debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:55:9: 55:10 + let _2: i32; // in scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10 + scope 2 { + debug a => _2; // in scope 2 at $DIR/inst_combine_deref.rs:56:9: 56:10 + let mut _3: &i32; // in scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14 + scope 3 { + debug y => _3; // in scope 3 at $DIR/inst_combine_deref.rs:57:9: 57:14 + let _4: &mut &i32; // in scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10 + scope 4 { + debug z => _4; // in scope 4 at $DIR/inst_combine_deref.rs:58:9: 58:10 + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10 + _1 = const 42_i32; // scope 0 at $DIR/inst_combine_deref.rs:55:13: 55:15 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10 + _2 = const 99_i32; // scope 1 at $DIR/inst_combine_deref.rs:56:13: 56:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14 + _3 = &_1; // scope 2 at $DIR/inst_combine_deref.rs:57:17: 57:19 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10 + _4 = &mut _3; // scope 3 at $DIR/inst_combine_deref.rs:58:13: 58:19 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 + StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 + _6 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 +- _5 = &(*_6); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 ++ _5 = _6; // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 + (*_4) = move _5; // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:12 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:59:11: 59:12 + StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:59:12: 59:13 + StorageLive(_7); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageLive(_8); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageLive(_9); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21 + StorageLive(_10); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15 + _10 = (*_3); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15 + _9 = Eq(move _10, const 99_i32); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21 + StorageDead(_10); // scope 4 at $DIR/inst_combine_deref.rs:60:20: 60:21 + _8 = Not(move _9); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageDead(_9); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 + switchInt(_8) -> [false: bb1, otherwise: bb2]; // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + } + + bb1: { + _7 = const (); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageDead(_8); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 + StorageDead(_7); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 + _0 = const (); // scope 0 at $DIR/inst_combine_deref.rs:54:24: 61:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:61:1: 61:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:61:1: 61:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:61:1: 61:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:61:1: 61:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:61:2: 61:2 + } + + bb2: { + StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic::<&str>(const "assertion failed: *y == 99"); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } + // ty::Const + // + ty: &str + // + val: Value(Slice { data: Allocation { bytes: [97, 115, 115, 101, 114, 116, 105, 111, 110, 32, 102, 97, 105, 108, 101, 100, 58, 32, 42, 121, 32, 61, 61, 32, 57, 57], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [67108863], len: Size { raw: 26 } }, size: Size { raw: 26 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 26 }) + // mir::Constant + // + span: $DIR/inst_combine_deref.rs:1:1: 1:1 + // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [97, 115, 115, 101, 114, 116, 105, 111, 110, 32, 102, 97, 105, 108, 101, 100, 58, 32, 42, 121, 32, 61, 61, 32, 57, 57], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [67108863], len: Size { raw: 26 } }, size: Size { raw: 26 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 26 }) } + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff new file mode 100644 index 0000000000..69036491a1 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff @@ -0,0 +1,53 @@ +- // MIR for `dont_opt` before InstCombine ++ // MIR for `dont_opt` after InstCombine + + fn dont_opt() -> u64 { + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:43:18: 43:21 + let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10 + let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:48:10: 48:14 + scope 1 { + debug y => _1; // in scope 1 at $DIR/inst_combine_deref.rs:44:9: 44:10 + let _2: &i32; // in scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13 + scope 2 { + debug _ref => _2; // in scope 2 at $DIR/inst_combine_deref.rs:45:9: 45:13 + let _3: i32; // in scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10 + scope 3 { + debug x => _3; // in scope 3 at $DIR/inst_combine_deref.rs:46:9: 46:10 + let mut _4: &i32; // in scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15 + scope 4 { + debug _1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:47:9: 47:15 + let _6: i32; // in scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11 + scope 5 { + debug _4 => _6; // in scope 5 at $DIR/inst_combine_deref.rs:49:9: 49:11 + } + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10 + _1 = const 5_i32; // scope 0 at $DIR/inst_combine_deref.rs:44:13: 44:14 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13 + _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:45:16: 45:18 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10 + _3 = const 5_i32; // scope 2 at $DIR/inst_combine_deref.rs:46:13: 46:14 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15 + _4 = &_3; // scope 3 at $DIR/inst_combine_deref.rs:47:18: 47:20 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14 +- _5 = &(*_2); // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14 ++ _5 = _2; // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14 + _4 = move _5; // scope 4 at $DIR/inst_combine_deref.rs:48:5: 48:14 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:48:13: 48:14 + StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11 + _6 = (*_4); // scope 4 at $DIR/inst_combine_deref.rs:49:14: 49:17 + _0 = const 0_u64; // scope 5 at $DIR/inst_combine_deref.rs:50:5: 50:6 + StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:51:1: 51:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:51:2: 51:2 + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff new file mode 100644 index 0000000000..c867543d05 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff @@ -0,0 +1,44 @@ +- // MIR for `opt_struct` before InstCombine ++ // MIR for `opt_struct` after InstCombine + + fn opt_struct(_1: S) -> u64 { + debug s => _1; // in scope 0 at $DIR/inst_combine_deref.rs:30:15: 30:16 + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:30:24: 30:27 + let _2: &u64; // in scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10 + let mut _5: u64; // in scope 0 at $DIR/inst_combine_deref.rs:34:5: 34:7 + let mut _6: u64; // in scope 0 at $DIR/inst_combine_deref.rs:34:10: 34:11 + scope 1 { + debug a => _2; // in scope 1 at $DIR/inst_combine_deref.rs:31:9: 31:10 + let _3: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10 + scope 2 { + debug b => _3; // in scope 2 at $DIR/inst_combine_deref.rs:32:9: 32:10 + let _4: u64; // in scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10 + scope 3 { + debug x => _4; // in scope 3 at $DIR/inst_combine_deref.rs:33:9: 33:10 + } + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10 + _2 = &(_1.0: u64); // scope 0 at $DIR/inst_combine_deref.rs:31:13: 31:17 + StorageLive(_3); // scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10 + _3 = &(_1.1: u64); // scope 1 at $DIR/inst_combine_deref.rs:32:13: 32:17 + StorageLive(_4); // scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10 +- _4 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15 ++ _4 = (_1.0: u64); // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15 + StorageLive(_5); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7 +- _5 = (*_3); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7 ++ _5 = (_1.1: u64); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7 + StorageLive(_6); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + _6 = _4; // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + _0 = Add(move _5, move _6); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:11 + StorageDead(_6); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + StorageDead(_5); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + StorageDead(_4); // scope 2 at $DIR/inst_combine_deref.rs:35:1: 35:2 + StorageDead(_3); // scope 1 at $DIR/inst_combine_deref.rs:35:1: 35:2 + StorageDead(_2); // scope 0 at $DIR/inst_combine_deref.rs:35:1: 35:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:35:2: 35:2 + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.rs b/src/test/mir-opt/inst_combine_deref.rs new file mode 100644 index 0000000000..78361c3366 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.rs @@ -0,0 +1,69 @@ +// compile-flags: -O -Zunsound-mir-opts +// EMIT_MIR inst_combine_deref.simple_opt.InstCombine.diff +fn simple_opt() -> u64 { + let x = 5; + let y = &x; + let z = *y; + z +} + +// EMIT_MIR inst_combine_deref.deep_opt.InstCombine.diff +fn deep_opt() -> (u64, u64, u64) { + let x1 = 1; + let x2 = 2; + let x3 = 3; + let y1 = &x1; + let y2 = &x2; + let y3 = &x3; + let z1 = *y1; + let z2 = *y2; + let z3 = *y3; + (z1, z2, z3) +} + +struct S { + a: u64, + b: u64, +} + +// EMIT_MIR inst_combine_deref.opt_struct.InstCombine.diff +fn opt_struct(s: S) -> u64 { + let a = &s.a; + let b = &s.b; + let x = *a; + *b + x +} + +// EMIT_MIR inst_combine_deref.dont_opt.InstCombine.diff +// do not optimize a sequence looking like this: +// _1 = &_2; +// _1 = _3; +// _4 = *_1; +// as the _1 = _3 assignment makes it not legal to replace the last statement with _4 = _2 +fn dont_opt() -> u64 { + let y = 5; + let _ref = &y; + let x = 5; + let mut _1 = &x; + _1 = _ref; + let _4 = *_1; + 0 +} + +// EMIT_MIR inst_combine_deref.do_not_miscompile.InstCombine.diff +fn do_not_miscompile() { + let x = 42; + let a = 99; + let mut y = &x; + let z = &mut y; + *z = &a; + assert!(*y == 99); +} + +fn main() { + simple_opt(); + deep_opt(); + opt_struct(S { a: 0, b: 1 }); + dont_opt(); + do_not_miscompile(); +} diff --git a/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff new file mode 100644 index 0000000000..f52dfe379c --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff @@ -0,0 +1,34 @@ +- // MIR for `simple_opt` before InstCombine ++ // MIR for `simple_opt` after InstCombine + + fn simple_opt() -> u64 { + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:3:20: 3:23 + let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10 + scope 1 { + debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:4:9: 4:10 + let _2: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/inst_combine_deref.rs:5:9: 5:10 + let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10 + scope 3 { + debug z => _3; // in scope 3 at $DIR/inst_combine_deref.rs:6:9: 6:10 + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10 + _1 = const 5_u64; // scope 0 at $DIR/inst_combine_deref.rs:4:13: 4:14 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10 + _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:5:13: 5:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10 +- _3 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15 ++ _3 = _1; // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15 + _0 = _3; // scope 3 at $DIR/inst_combine_deref.rs:7:5: 7:6 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:8:1: 8:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:8:1: 8:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:8:1: 8:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:8:2: 8:2 + } + } + diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index 01d837d155..5b2572655c 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -6,7 +6,7 @@ bb0: { _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 -+ Coverage { kind: Counter { function_source_hash: 10208505205182607101, id: CounterValueReference(0) }, code_region: /the/src/instrument_coverage.rs:19:18 - 21:2 }; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 ++ Coverage::Counter(0) for /the/src/instrument_coverage.rs:19:18 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 return; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 43c8be8f45..03affed050 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -8,7 +8,7 @@ let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10 bb0: { -+ Coverage { kind: Counter { function_source_hash: 16004455475339839479, id: CounterValueReference(0) }, code_region: /the/src/instrument_coverage.rs:10:11 - 16:2 }; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 ++ Coverage::Counter(0) for /the/src/instrument_coverage.rs:10:11 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } diff --git a/src/test/mir-opt/issue-41697.rs b/src/test/mir-opt/issue-41697.rs index 2c4f754484..5c34d8e68d 100644 --- a/src/test/mir-opt/issue-41697.rs +++ b/src/test/mir-opt/issue-41697.rs @@ -14,7 +14,7 @@ trait Foo { } // EMIT_MIR_FOR_EACH_BIT_WIDTH -// EMIT_MIR issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir +// EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir impl Foo for [u8; 1+1] { fn get(&self) -> [u8; 2] { *self diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir similarity index 69% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit rename to src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir index 1cef88fd10..f1f4b97035 100644 --- a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir @@ -1,12 +1,12 @@ -// MIR for `::{{constant}}#0` after SimplifyCfg-promote-consts +// MIR for `::{constant#0}` after SimplifyCfg-promote-consts -::{{constant}}#0: usize = { +::{constant#0}: usize = { let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 bb0: { _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 - assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } bb1 (cleanup): { diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir similarity index 69% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit rename to src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir index 1cef88fd10..f1f4b97035 100644 --- a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir @@ -1,12 +1,12 @@ -// MIR for `::{{constant}}#0` after SimplifyCfg-promote-consts +// MIR for `::{constant#0}` after SimplifyCfg-promote-consts -::{{constant}}#0: usize = { +::{constant#0}: usize = { let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 bb0: { _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 - assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } bb1 (cleanup): { diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index c71ae93462..137d9a8247 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -1,6 +1,6 @@ // MIR for `test` before ElaborateDrops -fn test() -> std::option::Option> { +fn test() -> Option> { let mut _0: std::option::Option>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30 let mut _1: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 let mut _2: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 @@ -29,8 +29,8 @@ fn test() -> std::option::Option> { _2 = Box(u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _4 = std::option::Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as std::ops::Try>::into_result(move _4) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _3 = as Try>::into_result(move _4) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result}, val: Value(Scalar()) } @@ -69,7 +69,7 @@ fn test() -> std::option::Option> { StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = >::from(move _9) -> [return: bb8, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = >::from(move _9) -> [return: bb8, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {>::from}, val: Value(Scalar()) } @@ -81,7 +81,7 @@ fn test() -> std::option::Option> { bb8: { StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as std::ops::Try>::from_error(move _8) -> [return: bb9, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = > as Try>::from_error(move _8) -> [return: bb9, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error}, val: Value(Scalar()) } @@ -106,7 +106,7 @@ fn test() -> std::option::Option> { bb12: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 - _0 = std::option::Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.bar.mir_map.0.mir.32bit rename to src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.bar.mir_map.0.mir.64bit rename to src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir similarity index 88% rename from src/test/mir-opt/issue_72181.foo.mir_map.0.mir.32bit rename to src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir index 972a36a30a..c94f6c28cd 100644 --- a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.32bit +++ b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir @@ -12,7 +12,7 @@ fn foo(_1: [(Never, u32); 1]) -> u32 { _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 - assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 } bb1 (cleanup): { diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir similarity index 88% rename from src/test/mir-opt/issue_72181.foo.mir_map.0.mir.64bit rename to src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir index 972a36a30a..c94f6c28cd 100644 --- a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.64bit +++ b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir @@ -12,7 +12,7 @@ fn foo(_1: [(Never, u32); 1]) -> u32 { _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 - assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 } bb1 (cleanup): { diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir similarity index 95% rename from src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit rename to src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir index 89b6012149..e003dc2aad 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir @@ -48,7 +48,7 @@ fn main() -> () { _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 - assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 } bb3: { diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir similarity index 95% rename from src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit rename to src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir index 89b6012149..e003dc2aad 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir @@ -48,7 +48,7 @@ fn main() -> () { _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 - assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 } bb3: { diff --git a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir index b3aea29f13..d9e5d2c389 100644 --- a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir @@ -21,7 +21,7 @@ fn main() -> () { StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 _3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 - _2 = std::intrinsics::transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 + _2 = transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 // mir::Constant // + span: $DIR/issue-72181-1.rs:17:9: 17:40 // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff similarity index 56% rename from src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit rename to src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index b940f1a929..ef7c73068f 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -3,66 +3,65 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - let mut _4: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27 + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _3: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _9: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _11: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL let _13: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _14: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _15: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _16: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _17: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _18: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _14: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _15: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _16: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _17: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _19: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _21: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _24: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _25: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _26: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _21: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _22: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL scope 1 { - debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 - let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 + debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 4 { debug left_val => _7; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL debug right_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _22: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _23: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 5 { - debug arg0 => _22; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg0 => _25; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg1 => _28; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 6 { - debug x => _22; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _28: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _24; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _23: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _24: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _25: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL } scope 8 { - debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug x => _28; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _26: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _28: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL } } scope 10 { - debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => _29; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _31; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _29: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _30: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _31: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL } } } } scope 2 { - debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _3; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -70,31 +69,29 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - StorageLive(_3); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - _4 = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - ((_3 as Some).0: i32) = move _4; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28 - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _3; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_4 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + discriminant(_4) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + (_5.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) } - StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } + (_5.1: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -109,99 +106,88 @@ bb1: { StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _14 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &[&str; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } - StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _29 = move _14 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _18 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_17.0: &&i32) = &_18; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _20 = _8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _19 = &_20; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _21 = &_8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_18.0: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - (_18.1: &&i32) = move _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + (_17.1: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _25 = (_17.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _28 = (_17.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _24 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } - StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _28 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _23 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _24) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } bb3: { - StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _29 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } bb4: { - (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageLive(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _27 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _23; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _27 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } - StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _30 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _26 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } bb5: { - StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _31 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } bb6: { - (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _17 = [move _24, move _26]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _16 = &_17; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_32) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.0: &[&str]) = move _14; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _26; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _16 = [move _21, move _22]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + _15 = &_16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _31 = move _15 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + discriminant(_30) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.0: &[&str]) = move _29; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff similarity index 56% rename from src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit rename to src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index b940f1a929..ef7c73068f 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -3,66 +3,65 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - let mut _4: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27 + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _3: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _9: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _11: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL let _13: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _14: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _15: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _16: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _17: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _18: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _14: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _15: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _16: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _17: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _19: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _21: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _24: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _25: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _26: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _21: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _22: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL scope 1 { - debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 - let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 + debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 4 { debug left_val => _7; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL debug right_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _22: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _23: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 5 { - debug arg0 => _22; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg0 => _25; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg1 => _28; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 6 { - debug x => _22; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _28: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _24; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _23: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _24: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _25: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL } scope 8 { - debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug x => _28; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _26: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _28: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL } } scope 10 { - debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => _29; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _31; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _29: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _30: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _31: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL } } } } scope 2 { - debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _3; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -70,31 +69,29 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - StorageLive(_3); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - _4 = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - ((_3 as Some).0: i32) = move _4; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28 - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _3; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_4 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + discriminant(_4) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + (_5.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) } - StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } + (_5.1: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -109,99 +106,88 @@ bb1: { StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _14 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &[&str; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } - StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _29 = move _14 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _18 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_17.0: &&i32) = &_18; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _20 = _8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _19 = &_20; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _21 = &_8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_18.0: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - (_18.1: &&i32) = move _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + (_17.1: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _25 = (_17.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _28 = (_17.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _24 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } - StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _28 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _23 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _24) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } bb3: { - StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _29 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } bb4: { - (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageLive(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _27 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _23; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _27 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } - StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _30 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _26 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } bb5: { - StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _31 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } bb6: { - (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _17 = [move _24, move _26]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _16 = &_17; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_32) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.0: &[&str]) = move _14; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _26; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _16 = [move _21, move _22]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + _15 = &_16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _31 = move _15 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + discriminant(_30) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.0: &[&str]) = move _29; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff similarity index 92% rename from src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit rename to src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff index 586a9f7624..1a6ee724cb 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff @@ -106,7 +106,7 @@ _0 = const (); // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 + return; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 } bb2: { @@ -129,10 +129,10 @@ _45 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } _11 = _45; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -153,14 +153,10 @@ StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_15) -> [false: bb4, otherwise: bb5]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_15) -> [false: bb3, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb3: { - return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 - } - - bb4: { _8 = const (); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -170,10 +166,10 @@ _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } - bb5: { + bb4: { StorageLive(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL @@ -184,10 +180,10 @@ _44 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &[&str; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _25 = _44; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _24 = _25; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _23 = move _24 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -217,31 +213,31 @@ StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _39 = _36; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _40 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _40 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_46); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _47 = _40; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _46 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _46 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb5; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } - bb6: { + bb5: { StorageDead(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_48); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _49 = _39; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _48 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } - bb7: { + bb6: { StorageDead(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL @@ -253,31 +249,31 @@ StorageLive(_42); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _42 = _37; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_43); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _43 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _43 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_50); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _51 = _43; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _50 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _50 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb7; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } - bb8: { + bb7: { StorageDead(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_52); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _53 = _42; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _52 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } - bb9: { + bb8: { StorageDead(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL @@ -310,7 +306,7 @@ StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _21 = &_22; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _20 = _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff similarity index 92% rename from src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit rename to src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff index 586a9f7624..1a6ee724cb 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff @@ -106,7 +106,7 @@ _0 = const (); // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 + return; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 } bb2: { @@ -129,10 +129,10 @@ _45 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } _11 = _45; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -153,14 +153,10 @@ StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_15) -> [false: bb4, otherwise: bb5]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_15) -> [false: bb3, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb3: { - return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 - } - - bb4: { _8 = const (); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -170,10 +166,10 @@ _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } - bb5: { + bb4: { StorageLive(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL @@ -184,10 +180,10 @@ _44 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &[&str; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _25 = _44; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _24 = _25; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _23 = move _24 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -217,31 +213,31 @@ StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _39 = _36; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _40 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _40 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_46); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _47 = _40; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _46 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _46 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb5; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } - bb6: { + bb5: { StorageDead(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_48); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _49 = _39; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _48 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } - bb7: { + bb6: { StorageDead(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL @@ -253,31 +249,31 @@ StorageLive(_42); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _42 = _37; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_43); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _43 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _43 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_50); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _51 = _43; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _50 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _50 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb7; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } - bb8: { + bb7: { StorageDead(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_52); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _53 = _42; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _52 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } - bb9: { + bb8: { StorageDead(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL @@ -310,7 +306,7 @@ StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _21 = &_22; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _20 = _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_76432.rs b/src/test/mir-opt/issue_76432.rs new file mode 100644 index 0000000000..c8b405ca8e --- /dev/null +++ b/src/test/mir-opt/issue_76432.rs @@ -0,0 +1,16 @@ +// Check that we do not insert StorageDead at each target if StorageDead was never seen + +// EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff +use std::fmt::Debug; + +fn test(x: T) { + let v: &[T] = &[x, x, x]; + match v { + [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], + _ => unreachable!(), + }; +} + +fn main() { + test(0u32); +} diff --git a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..499134b699 --- /dev/null +++ b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -0,0 +1,116 @@ +- // MIR for `test` before SimplifyComparisonIntegral ++ // MIR for `test` after SimplifyComparisonIntegral + + fn test(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/issue_76432.rs:6:38: 6:39 + let mut _0: (); // return place in scope 0 at $DIR/issue_76432.rs:6:44: 6:44 + let _2: &[T]; // in scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + let mut _3: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _4: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _5: [T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + let mut _6: T; // in scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + let mut _7: T; // in scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + let mut _8: T; // in scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + let _9: [*const T; 3]; // in scope 0 at $DIR/issue_76432.rs:8:5: 11:6 + let mut _10: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _11: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _12: bool; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _16: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _17: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _18: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 + let mut _19: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 + let mut _20: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 + let mut _21: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 + let mut _22: !; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + scope 1 { + debug v => _2; // in scope 1 at $DIR/issue_76432.rs:7:9: 7:10 + let _13: &T; // in scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + let _14: &T; // in scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + let _15: &T; // in scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + scope 2 { + debug v1 => _13; // in scope 2 at $DIR/issue_76432.rs:9:10: 9:16 + debug v2 => _14; // in scope 2 at $DIR/issue_76432.rs:9:18: 9:24 + debug v3 => _15; // in scope 2 at $DIR/issue_76432.rs:9:26: 9:32 + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + StorageLive(_3); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_4); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_5); // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageLive(_6); // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + _6 = _1; // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + StorageLive(_7); // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + _7 = _1; // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + StorageLive(_8); // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _8 = _1; // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageDead(_8); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_7); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + _4 = &_5; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _3 = _4; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:7:29: 7:30 + StorageLive(_9); // scope 1 at $DIR/issue_76432.rs:8:5: 11:6 + _10 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + _11 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 +- _12 = Eq(move _10, const 3_usize); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 +- switchInt(move _12) -> [false: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 ++ nop; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 ++ switchInt(move _10) -> [3_usize: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + } + + bb1: { + StorageLive(_22); // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic::<&str>(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } + // ty::Const + // + ty: &str + // + val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, size: Size { raw: 40 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, size: Size { raw: 40 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) } + } + + bb2: { + StorageLive(_13); // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + _13 = &(*_2)[0 of 3]; // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + StorageLive(_14); // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + _14 = &(*_2)[1 of 3]; // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + StorageLive(_15); // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + _15 = &(*_2)[2 of 3]; // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + StorageLive(_16); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_17); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + _17 = &raw const (*_13); // scope 2 at $DIR/issue_76432.rs:9:38: 9:40 + _16 = _17; // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_18); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_19); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + _19 = &raw const (*_14); // scope 2 at $DIR/issue_76432.rs:9:54: 9:56 + _18 = _19; // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_20); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + StorageLive(_21); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _21 = &raw const (*_15); // scope 2 at $DIR/issue_76432.rs:9:70: 9:72 + _20 = _21; // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _9 = [move _16, move _18, move _20]; // scope 2 at $DIR/issue_76432.rs:9:37: 9:85 + StorageDead(_21); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_20); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_19); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_18); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_17); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_16); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_15); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_14); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_13); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_9); // scope 1 at $DIR/issue_76432.rs:11:6: 11:7 + _0 = const (); // scope 0 at $DIR/issue_76432.rs:6:44: 12:2 + StorageDead(_5); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + StorageDead(_2); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + return; // scope 0 at $DIR/issue_76432.rs:12:2: 12:2 + } + } + diff --git a/src/test/mir-opt/issues/issue-75439.rs b/src/test/mir-opt/issues/issue-75439.rs new file mode 100644 index 0000000000..44d6bc619d --- /dev/null +++ b/src/test/mir-opt/issues/issue-75439.rs @@ -0,0 +1,21 @@ +// EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff + +#![feature(const_fn_transmute)] +#![feature(or_patterns)] + +use std::mem::transmute; + +pub fn foo(bytes: [u8; 16]) -> Option<[u8; 4]> { + // big endian `u32`s + let dwords: [u32; 4] = unsafe { transmute(bytes) }; + const FF: u32 = 0x0000_ffff_u32.to_be(); + if let [0, 0, 0 | FF, ip] = dwords { + Some(unsafe { transmute(ip) }) + } else { + None + } +} + +fn main() { + let _ = foo([0; 16]); +} diff --git a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff new file mode 100644 index 0000000000..43422b36e1 --- /dev/null +++ b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -0,0 +1,87 @@ +- // MIR for `foo` before MatchBranchSimplification ++ // MIR for `foo` after MatchBranchSimplification + + fn foo(_1: [u8; 16]) -> Option<[u8; 4]> { + debug bytes => _1; // in scope 0 at $DIR/issue-75439.rs:8:12: 8:17 + let mut _0: std::option::Option<[u8; 4]>; // return place in scope 0 at $DIR/issue-75439.rs:8:32: 8:47 + let _2: [u32; 4]; // in scope 0 at $DIR/issue-75439.rs:10:9: 10:15 + let mut _3: [u8; 16]; // in scope 0 at $DIR/issue-75439.rs:10:47: 10:52 + let mut _5: [u8; 4]; // in scope 0 at $DIR/issue-75439.rs:13:14: 13:38 + let mut _6: u32; // in scope 0 at $DIR/issue-75439.rs:13:33: 13:35 + scope 1 { + debug dwords => _2; // in scope 1 at $DIR/issue-75439.rs:10:9: 10:15 + let _4: u32; // in scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + scope 3 { + debug ip => _4; // in scope 3 at $DIR/issue-75439.rs:12:27: 12:29 + scope 4 { + } + } + } + scope 2 { + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-75439.rs:10:9: 10:15 + StorageLive(_3); // scope 2 at $DIR/issue-75439.rs:10:47: 10:52 + _3 = _1; // scope 2 at $DIR/issue-75439.rs:10:47: 10:52 + _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue-75439.rs:10:37: 10:53 + // mir::Constant + // + span: $DIR/issue-75439.rs:10:37: 10:46 + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {std::intrinsics::transmute::<[u8; 16], [u32; 4]>}, val: Value(Scalar()) } + } + + bb1: { + StorageDead(_3); // scope 2 at $DIR/issue-75439.rs:10:52: 10:53 + switchInt(_2[0 of 4]) -> [0_u32: bb2, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:13: 12:14 + } + + bb2: { + switchInt(_2[1 of 4]) -> [0_u32: bb3, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:16: 12:17 + } + + bb3: { + switchInt(_2[2 of 4]) -> [0_u32: bb6, 4294901760_u32: bb7, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:19: 12:20 + } + + bb4: { + discriminant(_0) = 0; // scope 1 at $DIR/issue-75439.rs:15:9: 15:13 + goto -> bb9; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb5: { + StorageLive(_5); // scope 3 at $DIR/issue-75439.rs:13:14: 13:38 + StorageLive(_6); // scope 4 at $DIR/issue-75439.rs:13:33: 13:35 + _6 = _4; // scope 4 at $DIR/issue-75439.rs:13:33: 13:35 + _5 = transmute::(move _6) -> bb8; // scope 4 at $DIR/issue-75439.rs:13:23: 13:36 + // mir::Constant + // + span: $DIR/issue-75439.rs:13:23: 13:32 + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {std::intrinsics::transmute::}, val: Value(Scalar()) } + } + + bb6: { + StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + _4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + goto -> bb5; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb7: { + StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + _4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + goto -> bb5; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb8: { + StorageDead(_6); // scope 4 at $DIR/issue-75439.rs:13:35: 13:36 + ((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue-75439.rs:13:9: 13:39 + discriminant(_0) = 1; // scope 3 at $DIR/issue-75439.rs:13:9: 13:39 + StorageDead(_5); // scope 3 at $DIR/issue-75439.rs:13:38: 13:39 + StorageDead(_4); // scope 1 at $DIR/issue-75439.rs:14:5: 14:6 + goto -> bb9; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb9: { + StorageDead(_2); // scope 0 at $DIR/issue-75439.rs:17:1: 17:2 + return; // scope 0 at $DIR/issue-75439.rs:17:2: 17:2 + } + } + diff --git a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 7a7d86f98a..8062f33a86 100644 --- a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -1,7 +1,7 @@ - // MIR for `complicated_match` after SimplifyCfg-initial + // MIR for `complicated_match` after ElaborateDrops - fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 { + fn complicated_match(_1: bool, _2: (bool, bool, String)) -> i32 { debug cond => _1; // in scope 0 at $DIR/match-arm-scopes.rs:13:22: 13:26 debug items => _2; // in scope 0 at $DIR/match-arm-scopes.rs:13:34: 13:39 let mut _0: i32; // return place in scope 0 at $DIR/match-arm-scopes.rs:13:66: 13:69 diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index c0249d134f..e09d32c729 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -26,7 +26,7 @@ fn full_tested_match() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6 StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 - _2 = std::option::Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 + _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16 switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16 @@ -58,10 +58,10 @@ fn full_tested_match() -> () { _11 = const full_tested_match::promoted[0]; // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 // ty::Const // + ty: &std::option::Option - // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/match_false_edges.rs:16:14: 16:15 - // + literal: Const { ty: &std::option::Option, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &std::option::Option, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, [], Some(promoted[0])) } _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27 diff --git a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir index a2ad5be265..a6c492581f 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir @@ -25,7 +25,7 @@ fn full_tested_match2() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6 StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 - _2 = std::option::Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 + _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16 switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16 diff --git a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir index b7322e7da0..1d451cef2a 100644 --- a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir @@ -36,7 +36,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6 StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 - _2 = std::option::Option::::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 + _2 = Option::::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 _4 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17 switchInt(move _4) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17 diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff similarity index 70% rename from src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff index 3f01719e01..648cf241cb 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff @@ -2,83 +2,83 @@ + // MIR for `bar` after MatchBranchSimplification fn bar(_1: i32) -> (bool, bool, bool, bool) { - debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9 - let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43 - let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6 - let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:12:8: 12:9 + let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:12:19: 12:43 + let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:18:5: 33:6 + let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16 scope 1 { - debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 scope 2 { - debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10 - let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 scope 3 { - debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10 - let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 scope 4 { - debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:16:9: 16:10 } } } } bb0: { - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 - StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 - StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 - StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 -- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 -+ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 -+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 -+ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 -+ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 -+ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 + StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 +- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 ++ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 ++ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 ++ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 ++ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 ++ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 } bb1: { - _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21 - _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21 + _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 } bb2: { - _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 - _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 + _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 } bb3: { - StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7 - StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 - _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 - (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2 + StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:33:6: 33:7 + StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16 + _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16 + (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:36:2: 36:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff similarity index 70% rename from src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff index 3f01719e01..648cf241cb 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff @@ -2,83 +2,83 @@ + // MIR for `bar` after MatchBranchSimplification fn bar(_1: i32) -> (bool, bool, bool, bool) { - debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9 - let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43 - let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6 - let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:12:8: 12:9 + let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:12:19: 12:43 + let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:18:5: 33:6 + let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16 scope 1 { - debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 scope 2 { - debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10 - let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 scope 3 { - debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10 - let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 scope 4 { - debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:16:9: 16:10 } } } } bb0: { - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 - StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 - StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 - StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 -- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 -+ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 -+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 -+ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 -+ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 -+ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 + StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 +- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 ++ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 ++ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 ++ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 ++ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 ++ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 } bb1: { - _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21 - _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21 + _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 } bb2: { - _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 - _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 + _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 } bb3: { - StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7 - StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 - _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 - (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2 + StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:33:6: 33:7 + StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16 + _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16 + (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:36:2: 36:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff similarity index 77% rename from src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff index 883a4e1470..a52abfb1a7 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff @@ -1,18 +1,18 @@ - // MIR for `foo` before MatchBranchSimplification + // MIR for `foo` after MatchBranchSimplification - fn foo(_1: std::option::Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25 + fn foo(_1: Option<()>) -> () { + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:6:8: 6:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 + let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 bb0: { StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 -- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 + _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 +- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 } bb1: { @@ -26,17 +26,17 @@ } bb3: { - switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 + switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 - goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 + goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb5: { - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:10:1: 10:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff similarity index 77% rename from src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff index 883a4e1470..a52abfb1a7 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff @@ -1,18 +1,18 @@ - // MIR for `foo` before MatchBranchSimplification + // MIR for `foo` after MatchBranchSimplification - fn foo(_1: std::option::Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25 + fn foo(_1: Option<()>) -> () { + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:6:8: 6:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 + let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 bb0: { StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 -- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 + _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 +- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 } bb1: { @@ -26,17 +26,17 @@ } bb3: { - switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 + switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 - goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 + goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb5: { - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:10:1: 10:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs index ebc88d2fbd..54b79a8426 100644 --- a/src/test/mir-opt/matches_reduce_branches.rs +++ b/src/test/mir-opt/matches_reduce_branches.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zunsound-mir-opts // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff diff --git a/src/test/mir-opt/multiple_return_terminators.rs b/src/test/mir-opt/multiple_return_terminators.rs new file mode 100644 index 0000000000..b73a51d483 --- /dev/null +++ b/src/test/mir-opt/multiple_return_terminators.rs @@ -0,0 +1,14 @@ +// compile-flags: -Z mir-opt-level=3 +// EMIT_MIR multiple_return_terminators.test.MultipleReturnTerminators.diff + +fn test(x: bool) { + if x { + // test + } else { + // test + } +} + +fn main() { + test(true) +} diff --git a/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff b/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff new file mode 100644 index 0000000000..997c021d2e --- /dev/null +++ b/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff @@ -0,0 +1,30 @@ +- // MIR for `test` before MultipleReturnTerminators ++ // MIR for `test` after MultipleReturnTerminators + + fn test(_1: bool) -> () { + debug x => _1; // in scope 0 at $DIR/multiple_return_terminators.rs:4:9: 4:10 + let mut _0: (); // return place in scope 0 at $DIR/multiple_return_terminators.rs:4:18: 4:18 + let mut _2: bool; // in scope 0 at $DIR/multiple_return_terminators.rs:5:8: 5:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/multiple_return_terminators.rs:5:8: 5:9 + _2 = _1; // scope 0 at $DIR/multiple_return_terminators.rs:5:8: 5:9 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/multiple_return_terminators.rs:5:5: 9:6 + } + + bb1: { + _0 = const (); // scope 0 at $DIR/multiple_return_terminators.rs:7:12: 9:6 + goto -> bb3; // scope 0 at $DIR/multiple_return_terminators.rs:5:5: 9:6 + } + + bb2: { + _0 = const (); // scope 0 at $DIR/multiple_return_terminators.rs:5:10: 7:6 + goto -> bb3; // scope 0 at $DIR/multiple_return_terminators.rs:5:5: 9:6 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/multiple_return_terminators.rs:10:1: 10:2 + return; // scope 0 at $DIR/multiple_return_terminators.rs:10:2: 10:2 + } + } + diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir similarity index 97% rename from src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit rename to src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 2885dd8eb7..91135fbf41 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -52,7 +52,7 @@ fn main() -> () { _3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 } bb1 (cleanup): { diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir similarity index 97% rename from src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit rename to src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 3820f70d51..23dcab656c 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -52,7 +52,7 @@ fn main() -> () { _3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 } bb1 (cleanup): { diff --git a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir index e90364c1cc..5de8e98ced 100644 --- a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir @@ -1,6 +1,6 @@ // MIR for `unwrap` after SimplifyCfg-elaborate-drops -fn unwrap(_1: std::option::Option) -> T { +fn unwrap(_1: Option) -> T { debug opt => _1; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:14: 7:17 let mut _0: T; // return place in scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:33: 7:34 let mut _2: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16 @@ -20,7 +20,7 @@ fn unwrap(_1: std::option::Option) -> T { bb1: { StorageLive(_4); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic::<&str>(const "explicit panic") -> bb4; // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic::<&str>(const "explicit panic") -> bb4; // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir index 5e1866fbc5..495c7f24c8 100644 --- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir @@ -20,7 +20,7 @@ fn main() -> () { // + span: $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [], len: Size { raw: 0 } }, size: Size { raw: 0 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 0 }) } _3 = &(*_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 - _2 = ::to_string(move _3) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 + _2 = ::to_string(move _3) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32 // + literal: Const { ty: for<'r> fn(&'r str) -> std::string::String {::to_string}, val: Value(Scalar()) } @@ -32,7 +32,7 @@ fn main() -> () { bb2: { StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34 - _1 = std::mem::drop::(move _2) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 + _1 = std::mem::drop::(move _2) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19 // + literal: Const { ty: fn(std::string::String) {std::mem::drop::}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff new file mode 100644 index 0000000000..39830946ae --- /dev/null +++ b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff @@ -0,0 +1,68 @@ +- // MIR for `opt` before InstCombine ++ // MIR for `opt` after InstCombine + + fn opt(_1: Option<()>) -> bool { + debug x => _1; // in scope 0 at $DIR/not_equal_false.rs:3:8: 3:9 + let mut _0: bool; // return place in scope 0 at $DIR/not_equal_false.rs:3:26: 3:30 + let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _3: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + let mut _4: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _5: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + + bb0: { + StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _3 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + switchInt(move _3) -> [0_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + } + + bb1: { + _0 = const true; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + + bb2: { + _0 = const false; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + + bb3: { + StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _5 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + switchInt(move _5) -> [1_isize: bb9, otherwise: bb8]; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + } + + bb4: { + StorageDead(_4); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 + StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 + return; // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2 + } + + bb5: { + _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb6: { + _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb7: { + switchInt(move _2) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + + bb8: { + _4 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb9: { + _4 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb10: { + switchInt(move _4) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + } + diff --git a/src/test/mir-opt/not_equal_false.rs b/src/test/mir-opt/not_equal_false.rs new file mode 100644 index 0000000000..a98a2834e8 --- /dev/null +++ b/src/test/mir-opt/not_equal_false.rs @@ -0,0 +1,9 @@ +// EMIT_MIR not_equal_false.opt.InstCombine.diff + +fn opt(x: Option<()>) -> bool { + matches!(x, None) || matches!(x, Some(_)) +} + +fn main() { + opt(None); +} diff --git a/src/test/mir-opt/nrvo-simple.rs b/src/test/mir-opt/nrvo-simple.rs index f0eb711b3f..ab46d7b94c 100644 --- a/src/test/mir-opt/nrvo-simple.rs +++ b/src/test/mir-opt/nrvo-simple.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmir-opt-level=1 + // EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { let mut buf = [0; 1024]; diff --git a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff index 924e87ea8c..f438eaa002 100644 --- a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff +++ b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff @@ -2,39 +2,42 @@ + // MIR for `nrvo` after RenameReturnPlace fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] { - debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:2:9: 2:13 -- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:2:39: 2:49 -+ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16 - let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16 - let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:4:5: 4:19 - let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:4:5: 4:9 - let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:4:10: 4:18 - let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:4:10: 4:18 + debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:4:9: 4:13 +- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:4:39: 4:49 ++ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 + let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 + let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:19 + let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:9 + let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18 + let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18 scope 1 { -- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:3:9: 3:16 -+ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:3:9: 3:16 +- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16 ++ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16 -- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28 -+ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28 - StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 - StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 -- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 -+ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - _3 = move _1(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 +- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 +- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28 ++ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28 + StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19 + StorageLive(_4); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9 + _4 = _1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9 + StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 +- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 ++ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19 } bb1: { - StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:4:18: 4:19 - StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 - StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 -- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:5:5: 5:8 -- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:6:1: 6:2 - return; // scope 0 at $DIR/nrvo-simple.rs:6:2: 6:2 + StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19 + StorageDead(_4); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19 + StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20 + StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20 +- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:7:5: 7:8 +- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:8:1: 8:2 + return; // scope 0 at $DIR/nrvo-simple.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir similarity index 100% rename from src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit rename to src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir similarity index 100% rename from src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit rename to src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir diff --git a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff index 2b7e4bbffe..47027311b4 100644 --- a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff +++ b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff @@ -1,7 +1,7 @@ - // MIR for `match_guard` before CleanupNonCodegenStatements + // MIR for `match_guard` after CleanupNonCodegenStatements - fn match_guard(_1: std::option::Option<&&i32>, _2: bool) -> i32 { + fn match_guard(_1: Option<&&i32>, _2: bool) -> i32 { debug x => _1; // in scope 0 at $DIR/remove_fake_borrows.rs:6:16: 6:17 debug c => _2; // in scope 0 at $DIR/remove_fake_borrows.rs:6:34: 6:35 let mut _0: i32; // return place in scope 0 at $DIR/remove_fake_borrows.rs:6:46: 6:49 diff --git a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff new file mode 100644 index 0000000000..787cf6f97c --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff @@ -0,0 +1,32 @@ +- // MIR for `cannot_opt_generic` before RemoveUnneededDrops ++ // MIR for `cannot_opt_generic` after RemoveUnneededDrops + + fn cannot_opt_generic(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:20:26: 20:27 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:20:32: 20:32 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:21:5: 21:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:21:5: 21:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:20:1: 22:2 + } + + bb2: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:21:11: 21:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:21:12: 21:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:20:32: 22:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:22:2: 22:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff new file mode 100644 index 0000000000..52e182eeb4 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff @@ -0,0 +1,32 @@ +- // MIR for `dont_opt` before RemoveUnneededDrops ++ // MIR for `dont_opt` after RemoveUnneededDrops + + fn dont_opt(_1: Vec) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:8:13: 8:14 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:8:27: 8:27 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:9:5: 9:12 + let mut _3: std::vec::Vec; // in scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:9:5: 9:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:8:1: 10:2 + } + + bb2: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:9:11: 9:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:9:12: 9:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:8:27: 10:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:10:2: 10:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff new file mode 100644 index 0000000000..bc9e1344f3 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -0,0 +1,28 @@ +- // MIR for `opt` before RemoveUnneededDrops ++ // MIR for `opt` after RemoveUnneededDrops + + fn opt(_1: bool) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:3:8: 3:9 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:3:17: 3:17 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:4:5: 4:12 + let mut _3: bool; // in scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:4:5: 4:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- } +- +- bb1: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:4:11: 4:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:4:12: 4:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:3:17: 5:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:5:2: 5:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff new file mode 100644 index 0000000000..5c8b1d1372 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -0,0 +1,28 @@ +- // MIR for `opt_generic_copy` before RemoveUnneededDrops ++ // MIR for `opt_generic_copy` after RemoveUnneededDrops + + fn opt_generic_copy(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:13:30: 13:31 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:13:36: 13:36 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:14:5: 14:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:14:5: 14:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- } +- +- bb1: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:14:11: 14:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:14:12: 14:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:13:36: 15:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.rs b/src/test/mir-opt/remove_unneeded_drops.rs new file mode 100644 index 0000000000..1052f28867 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.rs @@ -0,0 +1,29 @@ +// ignore-wasm32-bare compiled with panic=abort by default +// EMIT_MIR remove_unneeded_drops.opt.RemoveUnneededDrops.diff +fn opt(x: bool) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff +fn dont_opt(x: Vec) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +fn opt_generic_copy(x: T) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff +// since the pass is not running on monomorphisized code, +// we can't (but probably should) optimize this +fn cannot_opt_generic(x: T) { + drop(x); +} + +fn main() { + opt(true); + opt_generic_copy(42); + cannot_opt_generic(42); + dont_opt(vec![true]); +} diff --git a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir index b10ca21831..d0268cf207 100644 --- a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir +++ b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` after SimplifyCfg-make_shim +// MIR for `drop_in_place` after SimplifyCfg-make_shim -fn std::intrinsics::drop_in_place(_1: *mut Test) -> () { +fn drop_in_place(_1: *mut Test) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: &mut Test; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -8,7 +8,7 @@ fn std::intrinsics::drop_in_place(_1: *mut Test) -> () { bb0: { Retag([raw] _1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _3 = ::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = ::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut Test) {::drop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir similarity index 88% rename from src/test/mir-opt/retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir rename to src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir index 01f5fbb7d2..0b8c4d25d2 100644 --- a/src/test/mir-opt/retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir @@ -1,6 +1,6 @@ -// MIR for `main::{{closure}}#0` after SimplifyCfg-elaborate-drops +// MIR for `main::{closure#0}` after SimplifyCfg-elaborate-drops -fn main::{{closure}}#0(_1: &[closure@main::{{closure}}#0], _2: &i32) -> &i32 { +fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 { debug x => _2; // in scope 0 at $DIR/retag.rs:40:32: 40:33 let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:40:44: 40:48 let _3: &i32; // in scope 0 at $DIR/retag.rs:41:13: 41:15 diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index 5a79466ede..52f422d831 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -10,7 +10,7 @@ fn main() -> () { let mut _7: &mut i32; // in scope 0 at $DIR/retag.rs:32:29: 32:35 let mut _9: &mut i32; // in scope 0 at $DIR/retag.rs:33:19: 33:20 let mut _12: *mut i32; // in scope 0 at $DIR/retag.rs:36:18: 36:29 - let mut _14: [closure@main::{{closure}}#0]; // in scope 0 at $DIR/retag.rs:40:31: 43:6 + let mut _14: [closure@main::{closure#0}]; // in scope 0 at $DIR/retag.rs:40:31: 43:6 let mut _16: for<'r> fn(&'r i32) -> &'r i32; // in scope 0 at $DIR/retag.rs:44:14: 44:15 let mut _17: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 let _18: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 @@ -118,9 +118,9 @@ fn main() -> () { StorageDead(_2); // scope 1 at $DIR/retag.rs:37:5: 37:6 StorageLive(_13); // scope 1 at $DIR/retag.rs:40:9: 40:10 StorageLive(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6 - _14 = [closure@main::{{closure}}#0]; // scope 1 at $DIR/retag.rs:40:31: 43:6 + _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6 // closure - // + def_id: DefId(0:14 ~ retag[317d]::main[0]::{{closure}}[0]) + // + def_id: DefId(0:14 ~ retag[317d]::main::{closure#0}) // + substs: [ // i8, // for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32, @@ -157,10 +157,10 @@ fn main() -> () { _27 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:47:21: 47:23 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/retag.rs:47:21: 47:23 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, [], Some(promoted[0])) } Retag(_27); // scope 7 at $DIR/retag.rs:47:21: 47:23 _23 = &(*_27); // scope 7 at $DIR/retag.rs:47:21: 47:23 Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 12d7cb30d9..d0ea2cfb18 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -6,8 +6,8 @@ struct Test(i32); -// EMIT_MIR retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir -// EMIT_MIR retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir +// EMIT_MIR retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir +// EMIT_MIR retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir impl Test { // Make sure we run the pass on a method, not just on bare functions. fn foo<'x>(&self, x: &'x mut i32) -> &'x mut i32 { @@ -25,7 +25,7 @@ impl Drop for Test { } // EMIT_MIR retag.main.SimplifyCfg-elaborate-drops.after.mir -// EMIT_MIR retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir +// EMIT_MIR retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir fn main() { let mut x = 0; { diff --git a/src/test/mir-opt/retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir similarity index 100% rename from src/test/mir-opt/retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir rename to src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir diff --git a/src/test/mir-opt/retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir similarity index 100% rename from src/test/mir-opt/retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir rename to src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir diff --git a/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff b/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff new file mode 100644 index 0000000000..c3e503bf2c --- /dev/null +++ b/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff @@ -0,0 +1,72 @@ +- // MIR for `try_identity` before DestinationPropagation ++ // MIR for `try_identity` after DestinationPropagation + + fn try_identity(_1: std::result::Result) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 + scope 1 { + debug y => _2; // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 + } + scope 2 { + debug err => _6; // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 + scope 3 { + scope 7 { + debug t => _9; // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL + } + scope 8 { + debug v => _8; // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 + } + } + } + scope 4 { + debug val => _10; // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 + scope 5 { + } + } + scope 6 { +- debug self => _4; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL ++ debug self => _0; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 +- _3 = move _4; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 ++ nop; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL ++ nop; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + } + + bb1: { +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 + } + + bb2: { + return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 + } + } + diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.32bit b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.32bit rename to src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.64bit b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.64bit rename to src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/simplify-arm.rs b/src/test/mir-opt/simplify-arm.rs index 9d81b7f01c..a7df786357 100644 --- a/src/test/mir-opt/simplify-arm.rs +++ b/src/test/mir-opt/simplify-arm.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z mir-opt-level=2 +// compile-flags: -Z mir-opt-level=2 -Zunsound-mir-opts // EMIT_MIR simplify_arm.id.SimplifyArmIdentity.diff // EMIT_MIR simplify_arm.id.SimplifyBranchSame.diff // EMIT_MIR simplify_arm.id_result.SimplifyArmIdentity.diff diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs index cf8940ec33..84f57deccf 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs +++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zunsound-mir-opts + fn map(x: Option>) -> Option> { match x { None => None, diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff index ecb4384fc6..e390662307 100644 --- a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff @@ -1,7 +1,7 @@ - // MIR for `id` before SimplifyArmIdentity + // MIR for `id` after SimplifyArmIdentity - fn id(_1: std::option::Option) -> std::option::Option { + fn id(_1: Option) -> Option { debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8 let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35 let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff index fb75eb5603..81a0e6ba0b 100644 --- a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff @@ -1,7 +1,7 @@ - // MIR for `id` before SimplifyBranchSame + // MIR for `id` after SimplifyBranchSame - fn id(_1: std::option::Option) -> std::option::Option { + fn id(_1: Option) -> Option { debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8 let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35 let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 @@ -13,24 +13,27 @@ bb0: { _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 - switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 +- switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 ++ goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 } bb1: { - discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 - } - - bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 - } - - bb3: { +- discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 +- } +- +- bb2: { +- unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 +- } +- +- bb3: { _0 = move _1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 ++ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 } - bb4: { +- bb4: { ++ bb2: { return; // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff similarity index 100% rename from src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit rename to src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff similarity index 100% rename from src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit rename to src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff similarity index 56% rename from src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit rename to src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff index 4418c9f12b..760fb747f7 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff @@ -1,26 +1,26 @@ - // MIR for `map` before SimplifyLocals + // MIR for `map` after SimplifyLocals - fn map(_1: std::option::Option>) -> std::option::Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46 -- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 + fn map(_1: Option>) -> Option> { + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 +- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 } bb0: { -- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 - _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27 -- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2 +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 + _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff similarity index 56% rename from src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit rename to src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff index 4418c9f12b..760fb747f7 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff @@ -1,26 +1,26 @@ - // MIR for `map` before SimplifyLocals + // MIR for `map` after SimplifyLocals - fn map(_1: std::option::Option>) -> std::option::Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46 -- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 + fn map(_1: Option>) -> Option> { + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 +- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 } bb0: { -- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 - _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27 -- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2 +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 + _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index fa127de13d..eb307de207 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -1,6 +1,8 @@ +// compile-flags: -Zunsound-mir-opts // EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff // EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir +// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff fn try_identity(x: Result) -> Result { let y = x?; diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff new file mode 100644 index 0000000000..2af387a73b --- /dev/null +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -0,0 +1,68 @@ +- // MIR for `try_identity` before DestinationPropagation ++ // MIR for `try_identity` after DestinationPropagation + + fn try_identity(_1: std::result::Result) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + scope 1 { + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + } + scope 2 { + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 + scope 3 { + scope 7 { + debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + } + scope 8 { + debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 + } + } + } + scope 4 { + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 + scope 5 { + } + } + scope 6 { +- debug self => _4; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL ++ debug self => _0; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 +- _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 ++ nop; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL ++ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + } + + bb1: { +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + } + } + diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff index 26ce290b54..284ebfab9a 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff @@ -2,25 +2,25 @@ + // MIR for `try_identity` after SimplifyArmIdentity fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { -- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 -+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 +- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 ++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { -- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 -+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 +- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 ++ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { - debug t => _9; // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -29,13 +29,13 @@ scope 8 { - debug v => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 } } } scope 4 { -- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 -+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 +- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 ++ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } @@ -44,55 +44,51 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -- _2 = _10; // scope 5 at $DIR/simplify_try.rs:6:13: 6:15 -- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 -- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:7:8: 7:9 -- _11 = _2; // scope 1 at $DIR/simplify_try.rs:7:8: 7:9 -- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:7:9: 7:10 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 +- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- _2 = _10; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 +- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 +- _11 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 +- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } bb2: { -- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 -- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 -- _9 = _6; // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 +- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- _9 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - _8 = move _9; // scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL -- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 +- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - StorageLive(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - _12 = move _8; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _12; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL -- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 -- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 +- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _0 = move _3; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - } - - bb3: { - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir index dc4aae176f..ceb5bfb19a 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir @@ -1,35 +1,35 @@ // MIR for `try_identity` after SimplifyBranchSame fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 8 { debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } @@ -38,24 +38,20 @@ fn try_identity(_1: std::result::Result) -> std::result::Result bb1; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb2; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 - } - - bb2: { - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir index d65a2b12c0..508f2705d0 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir @@ -1,13 +1,13 @@ // MIR for `try_identity` after SimplifyLocals fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -18,16 +18,16 @@ fn try_identity(_1: std::result::Result) -> std::result::Result ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } scope 6 { - debug self => _1; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL + debug self => _0; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL } bb0: { - _0 = move _1; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simplify_try_if_let.rs b/src/test/mir-opt/simplify_try_if_let.rs index b37db73842..fba67de403 100644 --- a/src/test/mir-opt/simplify_try_if_let.rs +++ b/src/test/mir-opt/simplify_try_if_let.rs @@ -1,5 +1,8 @@ -// compile-flags: -Zmir-opt-level=1 -// EMIT_MIR simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff +// compile-flags: -Zmir-opt-level=1 -Zunsound-mir-opts +// ignore-test +// FIXME: the pass is unsound and causes ICEs in the MIR validator + +// EMIT_MIR simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff use std::ptr::NonNull; @@ -19,7 +22,7 @@ impl LinkedList { pub fn append(&mut self, other: &mut Self) { match self.tail { - None => { }, + None => {} Some(mut tail) => { // `as_mut` is okay here because we have exclusive access to the entirety // of both lists. diff --git a/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff similarity index 88% rename from src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff rename to src/test/mir-opt/simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff index 51a1e6ba4c..11f6b53374 100644 --- a/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff @@ -18,7 +18,8 @@ debug tail => _4; // in scope 1 at $DIR/simplify_try_if_let.rs:23:18: 23:26 let _8: std::ptr::NonNull; // in scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 scope 2 { - debug other_head => _8; // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39 +- debug other_head => _8; // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39 ++ debug other_head => ((_9 as Some).0: std::ptr::NonNull); // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39 scope 3 { } } @@ -35,7 +36,7 @@ StorageLive(_5); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60 StorageLive(_6); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53 _6 = &mut ((*_2).0: std::option::Option>); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53 - _5 = std::option::Option::>::take(move _6) -> bb4; // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60 + _5 = Option::>::take(move _6) -> bb4; // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60 // mir::Constant // + span: $DIR/simplify_try_if_let.rs:26:54: 26:58 // + literal: Const { ty: for<'r> fn(&'r mut std::option::Option>) -> std::option::Option> {std::option::Option::>::take}, val: Value(Scalar()) } @@ -65,15 +66,16 @@ StorageLive(_8); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 _8 = ((_5 as Some).0: std::ptr::NonNull); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 StorageLive(_9); // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 - StorageLive(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 - _10 = _8; // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 - ((_9 as Some).0: std::ptr::NonNull) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 - discriminant(_9) = 1; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 - StorageDead(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62 +- StorageLive(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 +- _10 = _8; // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 +- ((_9 as Some).0: std::ptr::NonNull) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 +- discriminant(_9) = 1; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 +- StorageDead(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62 ++ _9 = move _5; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 StorageLive(_11); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 StorageLive(_12); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 _12 = &mut _4; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 - _11 = std::ptr::NonNull::::as_mut(move _12) -> bb7; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 + _11 = NonNull::::as_mut(move _12) -> bb7; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 // mir::Constant // + span: $DIR/simplify_try_if_let.rs:28:30: 28:36 // + literal: Const { ty: for<'r> unsafe fn(&'r mut std::ptr::NonNull) -> &'r mut Node {std::ptr::NonNull::::as_mut}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs index 3b98b8474e..0fd32906db 100644 --- a/src/test/mir-opt/slice-drop-shim.rs +++ b/src/test/mir-opt/slice-drop-shim.rs @@ -1,7 +1,7 @@ // compile-flags: -Zmir-opt-level=0 // EMIT_MIR_FOR_EACH_BIT_WIDTH -// EMIT_MIR core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir +// EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir fn main() { let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_); } diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.64bit b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir similarity index 97% rename from src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.64bit rename to src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir index 50cfe19974..8051c61bce 100644 --- a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.64bit +++ b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () { +fn drop_in_place(_1: *mut [String]) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.32bit b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir similarity index 97% rename from src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.32bit rename to src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir index 50cfe19974..8051c61bce 100644 --- a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.32bit +++ b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () { +fn drop_in_place(_1: *mut [String]) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/src/test/mir-opt/spanview-block.rs b/src/test/mir-opt/spanview-block.rs new file mode 100644 index 0000000000..fc1d6e0ede --- /dev/null +++ b/src/test/mir-opt/spanview-block.rs @@ -0,0 +1,5 @@ +// Test spanview block output +// compile-flags: -Z dump-mir-spanview=block + +// EMIT_MIR spanview_block.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview-statement.rs b/src/test/mir-opt/spanview-statement.rs new file mode 100644 index 0000000000..a43ad5e71a --- /dev/null +++ b/src/test/mir-opt/spanview-statement.rs @@ -0,0 +1,5 @@ +// Test spanview output (the default value for `-Z dump-mir-spanview` is "statement") +// compile-flags: -Z dump-mir-spanview + +// EMIT_MIR spanview_statement.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview-terminator.rs b/src/test/mir-opt/spanview-terminator.rs new file mode 100644 index 0000000000..92e1411ead --- /dev/null +++ b/src/test/mir-opt/spanview-terminator.rs @@ -0,0 +1,5 @@ +// Test spanview terminator output +// compile-flags: -Z dump-mir-spanview=terminator + +// EMIT_MIR spanview_terminator.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html b/src/test/mir-opt/spanview_block.main.mir_map.0.html new file mode 100644 index 0000000000..8f6b130797 --- /dev/null +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() 0⦊{}⦉02⦊‸⦉2
    + + diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir new file mode 100644 index 0000000000..8f6b130797 --- /dev/null +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() 0⦊{}⦉02⦊‸⦉2
    + + diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html b/src/test/mir-opt/spanview_statement.main.mir_map.0.html new file mode 100644 index 0000000000..072d22473a --- /dev/null +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() 0[0]⦊{}⦉0[0]0:Goto⦊‸⦉0:Goto2:Return⦊‸⦉2:Return
    + + diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir new file mode 100644 index 0000000000..072d22473a --- /dev/null +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() 0[0]⦊{}⦉0[0]0:Goto⦊‸⦉0:Goto2:Return⦊‸⦉2:Return
    + + diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html new file mode 100644 index 0000000000..e023f0f8ae --- /dev/null +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html @@ -0,0 +1,66 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() {}0:Goto⦊‸⦉0:Goto2:Return⦊‸⦉2:Return
    + + diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir new file mode 100644 index 0000000000..e023f0f8ae --- /dev/null +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir @@ -0,0 +1,66 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() {}0:Goto⦊‸⦉0:Goto2:Return⦊‸⦉2:Return
    + + diff --git a/src/test/mir-opt/storage_ranges.main.nll.0.mir b/src/test/mir-opt/storage_ranges.main.nll.0.mir index 707caf57c6..6fa83d3de6 100644 --- a/src/test/mir-opt/storage_ranges.main.nll.0.mir +++ b/src/test/mir-opt/storage_ranges.main.nll.0.mir @@ -45,7 +45,7 @@ fn main() -> () { StorageLive(_4); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 StorageLive(_5); // scope 1 at $DIR/storage_ranges.rs:6:23: 6:24 _5 = _1; // scope 1 at $DIR/storage_ranges.rs:6:23: 6:24 - _4 = std::option::Option::::Some(move _5); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 + _4 = Option::::Some(move _5); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 StorageDead(_5); // scope 1 at $DIR/storage_ranges.rs:6:24: 6:25 _3 = &_4; // scope 1 at $DIR/storage_ranges.rs:6:17: 6:25 FakeRead(ForLet, _3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14 diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs index 249a851af2..c68ec21a03 100644 --- a/src/test/mir-opt/unusual-item-types.rs +++ b/src/test/mir-opt/unusual-item-types.rs @@ -5,25 +5,25 @@ struct A; -// EMIT_MIR unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir +// EMIT_MIR unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir impl A { const ASSOCIATED_CONSTANT: i32 = 2; } // See #59021 -// EMIT_MIR unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir +// EMIT_MIR unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir enum Test { X(usize), Y { a: usize }, } -// EMIT_MIR unusual_item_types.E-V-{{constant}}.mir_map.0.mir +// EMIT_MIR unusual_item_types.E-V-{constant#0}.mir_map.0.mir enum E { V = 5, } fn main() { let f = Test::X as fn(usize) -> Test; -// EMIT_MIR core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir +// EMIT_MIR core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir let v = Vec::::new(); } diff --git a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir similarity index 85% rename from src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit rename to src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir index 315525e08c..f11fce891f 100644 --- a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit +++ b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir @@ -1,6 +1,6 @@ -// MIR for `E::V::{{constant}}#0` 0 mir_map +// MIR for `E::V::{constant#0}` 0 mir_map -E::V::{{constant}}#0: isize = { +E::V::{constant#0}: isize = { let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 bb0: { diff --git a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir similarity index 85% rename from src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit rename to src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir index 315525e08c..f11fce891f 100644 --- a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit +++ b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir @@ -1,6 +1,6 @@ -// MIR for `E::V::{{constant}}#0` 0 mir_map +// MIR for `E::V::{constant#0}` 0 mir_map -E::V::{{constant}}#0: isize = { +E::V::{constant#0}: isize = { let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 bb0: { diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.32bit b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.32bit rename to src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.64bit b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.64bit rename to src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir similarity index 84% rename from src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit rename to src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir index 1f5804e0b2..2d96f64aeb 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { +fn drop_in_place(_1: *mut Vec) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: &mut std::vec::Vec; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -35,7 +35,7 @@ fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { bb7: { _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _3 = as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = as Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut std::vec::Vec) { as std::ops::Drop>::drop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir similarity index 84% rename from src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit rename to src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir index 1f5804e0b2..2d96f64aeb 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { +fn drop_in_place(_1: *mut Vec) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: &mut std::vec::Vec; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -35,7 +35,7 @@ fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { bb7: { _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _3 = as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = as Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut std::vec::Vec) { as std::ops::Drop>::drop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.32bit b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.32bit rename to src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.64bit b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.64bit rename to src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit rename to src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit rename to src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit rename to src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit rename to src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 0e45b6f04a..7b0a00282f 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -32,34 +32,34 @@ pub fn bar() ({ ({ let res = ((::alloc::fmt::format as - for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((::core::fmt::Arguments::new_v1 - as - fn(&[&'static str], &[std::fmt::ArgumentV1]) -> std::fmt::Arguments {std::fmt::Arguments::new_v1})((&([("test" - as - &str)] - as - [&str; 1]) - as - &[&str; 1]), - (&(match (() - as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1; 0]), - } - as - [std::fmt::ArgumentV1; 0]) - as - &[std::fmt::ArgumentV1; 0])) - as - std::fmt::Arguments)) - as std::string::String); - (res as std::string::String) - } as std::string::String); + for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 + as + fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" + as + &str)] + as + [&str; 1]) + as + &[&str; 1]), + (&(match (() + as + ()) + { + () + => + ([] + as + [ArgumentV1; 0]), + } + as + [ArgumentV1; 0]) + as + &[ArgumentV1; 0])) + as + Arguments)) + as String); + (res as String) + } as String); } as ()) pub type Foo = [i32; (3 as usize)]; pub struct Bar { diff --git a/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp b/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp index b0fd65f88e..8182021a2c 100644 --- a/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp +++ b/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp @@ -23,15 +23,15 @@ struct drop_check { extern "C" { void rust_catch_callback(void (*cb)(), bool* rust_ok); - static void callback() { + void throw_cxx_exception() { println("throwing C++ exception"); throw exception(); } - void throw_cxx_exception() { + void test_cxx_exception() { bool rust_ok = false; try { - rust_catch_callback(callback, &rust_ok); + rust_catch_callback(throw_cxx_exception, &rust_ok); assert(false && "unreachable"); } catch (exception e) { println("caught C++ exception"); diff --git a/src/test/run-make-fulldeps/foreign-exceptions/foo.rs b/src/test/run-make-fulldeps/foreign-exceptions/foo.rs index 9c2045c8c8..b5c8c1962a 100644 --- a/src/test/run-make-fulldeps/foreign-exceptions/foo.rs +++ b/src/test/run-make-fulldeps/foreign-exceptions/foo.rs @@ -1,5 +1,5 @@ -// Tests that C++ exceptions can unwind through Rust code, run destructors and -// are ignored by catch_unwind. Also tests that Rust panics can unwind through +// Tests that C++ exceptions can unwind through Rust code run destructors and +// are caught by catch_unwind. Also tests that Rust panics can unwind through // C++ code. // For linking libstdc++ on MinGW @@ -17,7 +17,7 @@ impl<'a> Drop for DropCheck<'a> { } extern "C" { - fn throw_cxx_exception(); + fn test_cxx_exception(); #[unwind(allowed)] fn cxx_catch_callback(cb: extern "C" fn(), ok: *mut bool); @@ -26,15 +26,12 @@ extern "C" { #[no_mangle] #[unwind(allowed)] extern "C" fn rust_catch_callback(cb: extern "C" fn(), rust_ok: &mut bool) { - let _caught_unwind = catch_unwind(AssertUnwindSafe(|| { - let _drop = DropCheck(rust_ok); - cb(); - unreachable!("should have unwound instead of returned"); - })); - unreachable!("catch_unwind should not have caught foreign exception"); + let _drop = DropCheck(rust_ok); + cb(); + unreachable!("should have unwound instead of returned"); } -fn throw_rust_panic() { +fn test_rust_panic() { #[unwind(allowed)] extern "C" fn callback() { println!("throwing rust panic"); @@ -60,6 +57,6 @@ fn throw_rust_panic() { } fn main() { - unsafe { throw_cxx_exception() }; - throw_rust_panic(); + unsafe { test_cxx_exception() }; + test_rust_panic(); } diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile new file mode 100644 index 0000000000..cb081fb641 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile @@ -0,0 +1,81 @@ +# needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. + +-include ../instrument-coverage/coverage_tools.mk + +BASEDIR=../instrument-coverage-cov-reports-base +SOURCEDIR=../instrument-coverage + +all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) + +# Ensure there are no `expected` results for tests that may have been removed or renamed +.PHONY: clear_expected_if_blessed +clear_expected_if_blessed: +ifdef RUSTC_BLESS_TEST + rm -f expected_export_coverage.*.json + rm -f typical_show_coverage.*.txt +endif + +-include clear_expected_if_blessed + +%: $(SOURCEDIR)/%.rs + # Compile the test program with "experimental" coverage instrumentation and generate relevant MIR. + # + # FIXME(richkadel): `-Zexperimental-coverage` to `-Zinstrument-coverage` once we are + # satisfied with the branch-level instrumentation. + $(RUSTC) $(SOURCEDIR)/$@.rs \ + -Zexperimental-coverage \ + -Clink-dead-code=$(LINK_DEAD_CODE) + + # Run it in order to generate some profiling data, + # with `LLVM_PROFILE_FILE=` environment variable set to + # output the coverage stats for this run. + LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \ + $(call RUN,$@) + + # Postprocess the profiling data so it can be used by the llvm-cov tool + "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \ + "$(TMPDIR)"/$@.profraw \ + -o "$(TMPDIR)"/$@.profdata + + # Generate a coverage report using `llvm-cov show`. The output ordering + # can be non-deterministic, so ignore the return status. If the test fails + # when comparing the JSON `export`, the `show` output may be useful when + # debugging. + "$(LLVM_BIN_DIR)"/llvm-cov show \ + --Xdemangler="$(RUST_DEMANGLER)" \ + --show-line-counts-or-regions \ + --instr-profile="$(TMPDIR)"/$@.profdata \ + $(call BIN,"$(TMPDIR)"/$@) \ + > "$(TMPDIR)"/actual_show_coverage.$@.txt + +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/actual_show_coverage.$@.txt typical_show_coverage.$@.txt +else + # Compare the show coverage output (`--bless` refreshes `typical` files) + $(DIFF) typical_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ + >&2 echo 'diff failed for `llvm-cov show` on $@ (might not be an error)' +endif + + # Generate a coverage report in JSON, using `llvm-cov export`, and fail if + # there are differences from the expected output. + "$(LLVM_BIN_DIR)"/llvm-cov export \ + --summary-only \ + --instr-profile="$(TMPDIR)"/$@.profdata \ + $(call BIN,"$(TMPDIR)"/$@) \ + | "$(PYTHON)" $(BASEDIR)/prettify_json.py \ + > "$(TMPDIR)"/actual_export_coverage.$@.json + +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/actual_export_coverage.$@.json expected_export_coverage.$@.json +else + # Check that exported JSON coverage data matches what we expect (`--bless` refreshes `expected`) + $(DIFF) expected_export_coverage.$@.json "$(TMPDIR)"/actual_export_coverage.$@.json +endif diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json new file mode 100644 index 0000000000..b9041ebebe --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/coverage_of_if_else.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 46, + "covered": 19, + "percent": 41.30434782608695 + }, + "regions": { + "count": 75, + "covered": 23, + "notcovered": 52, + "percent": 30.666666666666664 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 46, + "covered": 19, + "percent": 41.30434782608695 + }, + "regions": { + "count": 75, + "covered": 23, + "notcovered": 52, + "percent": 30.666666666666664 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/prettify_json.py b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/prettify_json.py similarity index 100% rename from src/test/run-make-fulldeps/instrument-coverage/prettify_json.py rename to src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/prettify_json.py diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt new file mode 100644 index 0000000000..0c71155960 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt @@ -0,0 +1,64 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | let mut countdown = 0; + 5| 2| if true { + ^1 + 6| 2| countdown = 10; + 7| 2| } + 8| | + 9| 2| if countdown > 7 { + ^1 + 10| 2| countdown -= 4; + ^1 + 11| 2| } else if countdown > 2 { + ^0 ^0 + 12| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 13| 0| countdown = 0; + 14| 0| } + 15| 0| countdown -= 5; + 16| 0| } else { + 17| 0| return; + 18| 0| } + 19| 0| + 20| 0| let mut countdown = 0; + 21| 2| if true { + ^1 + 22| 2| countdown = 10; + 23| 2| } + 24| 0| + 25| 2| if countdown > 7 { + ^1 + 26| 2| countdown -= 4; + ^1 + 27| 2| } else if countdown > 2 { + ^0 ^0 + 28| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 29| 0| countdown = 0; + 30| 0| } + 31| 0| countdown -= 5; + 32| 0| } else { + 33| 0| return; + 34| 0| } + 35| 0| + 36| 0| let mut countdown = 0; + 37| 2| if true { + ^1 + 38| 2| countdown = 10; + 39| 2| } + 40| 0| + 41| 2| if countdown > 7 { + ^1 + 42| 2| countdown -= 4; + ^1 + 43| 2| } else if countdown > 2 { + ^0 ^0 + 44| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 45| 0| countdown = 0; + 46| 0| } + 47| 0| countdown -= 5; + 48| 0| } else { + 49| 0| return; + 50| 0| } + 51| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile new file mode 100644 index 0000000000..ab826d07e0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile @@ -0,0 +1,15 @@ +# needs-profiler-support +# ignore-msvc +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. + +# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 +LINK_DEAD_CODE=yes + +-include ../instrument-coverage-cov-reports-base/Makefile + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json new file mode 100644 index 0000000000..b9041ebebe --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/coverage_of_if_else.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 46, + "covered": 19, + "percent": 41.30434782608695 + }, + "regions": { + "count": 75, + "covered": 23, + "notcovered": 52, + "percent": 30.666666666666664 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 46, + "covered": 19, + "percent": 41.30434782608695 + }, + "regions": { + "count": 75, + "covered": 23, + "notcovered": 52, + "percent": 30.666666666666664 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt new file mode 100644 index 0000000000..0c71155960 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt @@ -0,0 +1,64 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | let mut countdown = 0; + 5| 2| if true { + ^1 + 6| 2| countdown = 10; + 7| 2| } + 8| | + 9| 2| if countdown > 7 { + ^1 + 10| 2| countdown -= 4; + ^1 + 11| 2| } else if countdown > 2 { + ^0 ^0 + 12| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 13| 0| countdown = 0; + 14| 0| } + 15| 0| countdown -= 5; + 16| 0| } else { + 17| 0| return; + 18| 0| } + 19| 0| + 20| 0| let mut countdown = 0; + 21| 2| if true { + ^1 + 22| 2| countdown = 10; + 23| 2| } + 24| 0| + 25| 2| if countdown > 7 { + ^1 + 26| 2| countdown -= 4; + ^1 + 27| 2| } else if countdown > 2 { + ^0 ^0 + 28| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 29| 0| countdown = 0; + 30| 0| } + 31| 0| countdown -= 5; + 32| 0| } else { + 33| 0| return; + 34| 0| } + 35| 0| + 36| 0| let mut countdown = 0; + 37| 2| if true { + ^1 + 38| 2| countdown = 10; + 39| 2| } + 40| 0| + 41| 2| if countdown > 7 { + ^1 + 42| 2| countdown -= 4; + ^1 + 43| 2| } else if countdown > 2 { + ^0 ^0 + 44| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 45| 0| countdown = 0; + 46| 0| } + 47| 0| countdown -= 5; + 48| 0| } else { + 49| 0| return; + 50| 0| } + 51| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile new file mode 100644 index 0000000000..f623248ab5 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile @@ -0,0 +1,65 @@ +# needs-profiler-support + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. + +-include ../instrument-coverage/coverage_tools.mk + +BASEDIR=../instrument-coverage-llvm-ir-base + +ifeq ($(UNAME),Darwin) + INSTR_PROF_DATA_SUFFIX=,regular,live_support + DATA_SECTION_PREFIX=__DATA, + LLVM_COV_SECTION_PREFIX=__LLVM_COV, +else + INSTR_PROF_DATA_SUFFIX= + DATA_SECTION_PREFIX= + LLVM_COV_SECTION_PREFIX= +endif + +ifeq ($(LINK_DEAD_CODE),yes) + DEFINE_INTERNAL=define hidden +else + DEFINE_INTERNAL=define internal +endif + +ifdef IS_WINDOWS + LLVM_FILECHECK_OPTIONS=\ + -check-prefixes=CHECK,WINDOWS \ + -DPRIVATE_GLOBAL='internal global' \ + -DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \ + -DINSTR_PROF_DATA='.lprfd$$M' \ + -DINSTR_PROF_NAME='.lprfn$$M' \ + -DINSTR_PROF_CNTS='.lprfc$$M' \ + -DINSTR_PROF_VALS='.lprfv$$M' \ + -DINSTR_PROF_VNODES='.lprfnd$$M' \ + -DINSTR_PROF_COVMAP='.lcovmap$$M' \ + -DINSTR_PROF_ORDERFILE='.lorderfile$$M' +else + LLVM_FILECHECK_OPTIONS=\ + -check-prefixes=CHECK \ + -DPRIVATE_GLOBAL='private global' \ + -DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \ + -DINSTR_PROF_DATA='$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)' \ + -DINSTR_PROF_NAME='$(DATA_SECTION_PREFIX)__llvm_prf_names' \ + -DINSTR_PROF_CNTS='$(DATA_SECTION_PREFIX)__llvm_prf_cnts' \ + -DINSTR_PROF_VALS='$(DATA_SECTION_PREFIX)__llvm_prf_vals' \ + -DINSTR_PROF_VNODES='$(DATA_SECTION_PREFIX)__llvm_prf_vnds' \ + -DINSTR_PROF_COVMAP='$(LLVM_COV_SECTION_PREFIX)__llvm_covmap' \ + -DINSTR_PROF_ORDERFILE='$(DATA_SECTION_PREFIX)__llvm_orderfile' +endif + +all: + # Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR + # + # Note: `-Clink-dead-code=no` disables the option, needed because the option is automatically + # enabled for some platforms, but not for Windows MSVC (due to Issue #76038). The state of this + # option affects the generated MIR and coverage, so it is enabled for tests to ensure the + # tests results are the same across platforms. + $(RUSTC) $(BASEDIR)/testprog.rs \ + -Zinstrument-coverage \ + -Clink-dead-code=$(LINK_DEAD_CODE) \ + --emit=llvm-ir + + cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" $(BASEDIR)/filecheck.testprog.txt $(LLVM_FILECHECK_OPTIONS) diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/filecheck.testprog.txt b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/filecheck.testprog.txt new file mode 100644 index 0000000000..0a3c4aedd5 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/filecheck.testprog.txt @@ -0,0 +1,49 @@ +# Check for metadata, variables, declarations, and function definitions injected +# into LLVM IR when compiling with -Zinstrument-coverage. + +WINDOWS: $__llvm_profile_runtime_user = comdat any + +CHECK: @__llvm_coverage_mapping = internal constant +CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8 + +WINDOWS: @__llvm_profile_runtime = external global i32 + +CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]] +CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8 + +CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]] +CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, +CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8 + +CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]] +CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8 + +CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]] +CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main, +CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8 + +CHECK: @__llvm_prf_nm = private constant +CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1 + +CHECK: @llvm.used = appending global +CHECK-SAME: i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*) +WINDOWS-SAME: i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*) +CHECK-SAME: i8* bitcast ({ {{.*}} }* @__profd__R{{[a-zA-Z0-9_]*}}testprog4main to i8*) +CHECK-SAME: i8* getelementptr inbounds ({{.*}}* @__llvm_prf_nm, i32 0, i32 0) +CHECK-SAME: section "llvm.metadata" + +CHECK: [[DEFINE_INTERNAL]] { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { +CHECK-NEXT: start: +CHECK-NOT: bb{{[0-9]+}}: +CHECK: %pgocount = load i64, i64* getelementptr inbounds +CHECK-SAME: * @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, + +CHECK: declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] + +WINDOWS: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { +WINDOWS-NEXT: %1 = load i32, i32* @__llvm_profile_runtime +WINDOWS-NEXT: ret i32 %1 +WINDOWS-NEXT: } + +CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind } +WINDOWS: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline } diff --git a/src/test/run-make-fulldeps/instrument-coverage/testprog.rs b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/testprog.rs similarity index 100% rename from src/test/run-make-fulldeps/instrument-coverage/testprog.rs rename to src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/testprog.rs diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile new file mode 100644 index 0000000000..ba2126a6b3 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile @@ -0,0 +1,11 @@ +# needs-profiler-support +# ignore-msvc + +# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 +LINK_DEAD_CODE=yes + +-include ../instrument-coverage-llvm-ir-base/Makefile + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. \ No newline at end of file diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile new file mode 100644 index 0000000000..5cd425979e --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile @@ -0,0 +1,42 @@ +# needs-profiler-support + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. + +-include ../instrument-coverage/coverage_tools.mk + +SOURCEDIR=../instrument-coverage + +all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) + +# Ensure there are no `expected` results for tests that may have been removed or renamed +.PHONY: clear_expected_if_blessed +clear_expected_if_blessed: +ifdef RUSTC_BLESS_TEST + rm -rf expected_mir_dump.*/ +endif + +-include clear_expected_if_blessed + +%: $(SOURCEDIR)/%.rs + # Compile the test program with "experimental" coverage instrumentation and generate relevant MIR. + # + # FIXME(richkadel): `-Zexperimental-coverage` to `-Zinstrument-coverage` once we are + # satisfied with the branch-level instrumentation. + $(RUSTC) $(SOURCEDIR)/$@.rs \ + -Zexperimental-coverage \ + -Clink-dead-code=$(LINK_DEAD_CODE) \ + -Zdump-mir=InstrumentCoverage \ + -Zdump-mir-dir="$(TMPDIR)"/mir_dump.$@ + +ifdef RUSTC_BLESS_TEST + mkdir -p expected_mir_dump.$@ + cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html expected_mir_dump.$@/ +else + # Check that the selected `mir_dump` files match what we expect (`--bless` refreshes `expected`) + mkdir -p "$(TMPDIR)"/actual_mir_dump.$@ + rm -f "$(TMPDIR)"/actual_mir_dump.$@/* + cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html "$(TMPDIR)"/actual_mir_dump.$@/ + $(DIFF) -r expected_mir_dump.$@/ "$(TMPDIR)"/actual_mir_dump.$@/ +endif diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000..94abe11896 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,808 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() { + let mut countdown = 0; + 2⦊4⦊3⦊if 0⦊true⦉0 { + countdown = 10; + }⦉3⦉4⦉2 + + 6⦊9⦊25⦊if 5⦊countdown > 7⦉5 { + 8⦊countdown -= 4⦉8; + } else 10⦊if 7⦊countdown > 2⦉7 { + 22⦊23⦊21⦊if 14⦊15⦊16⦊13⦊20⦊12⦊18⦊19⦊17⦊countdown < 1 || countdown > 5⦉17⦉19⦉18 || countdown != 9⦉12⦉20⦉13⦉16⦉15⦉14 { + countdown = 0; + 24⦊}⦉22⦉23⦉21⦉21 + countdown -= 5⦉24; + } else { + 27⦊11⦊return; + }⦉11⦉6⦉9⦉25⦉25⦉25⦉10⦉10⦉10⦉11 + + let mut countdown = 0; + 30⦊31⦊29⦊if 28⦊true⦉28 { + countdown = 10; + }⦉29⦉31⦉30 + + 33⦊52⦊36⦊if 32⦊countdown > 7⦉32 { + 35⦊countdown -= 4⦉35; + } else 37⦊if 34⦊countdown > 2⦉34 { + 48⦊50⦊49⦊if 39⦊47⦊40⦊43⦊42⦊41⦊46⦊45⦊44⦊countdown < 1 || countdown > 5⦉44⦉45⦉46 || countdown != 9⦉41⦉42⦉43⦉40⦉47⦉39 { + countdown = 0; + 51⦊}⦉48⦉50⦉49⦉49 + countdown -= 5⦉51; + } else { + 38⦊return; + }⦉33⦉52⦉36⦉36⦉36⦉37⦉37⦉37 + + let mut countdown = 0; + 56⦊54⦊55⦊if 53⦊true⦉53 { + countdown = 10; + }⦉55⦉54⦉56 + + 61⦊58⦊77⦊if 57⦊countdown > 7⦉57 { + 60⦊countdown -= 4⦉60; + } else 62⦊if 59⦊countdown > 2⦉59 { + 75⦊74⦊73⦊if 67⦊68⦊65⦊72⦊64⦊66⦊69⦊71⦊70⦊countdown < 1 || countdown > 5⦉70⦉71⦉69 || countdown != 9⦉66⦉64⦉72⦉65⦉68⦉67 { + countdown = 0; + 76⦊}⦉75⦉74⦉73⦉73 + countdown -= 5⦉76; + } else { + 63⦊return; + }⦉61⦉58⦉77⦉77⦉77⦉62⦉62⦉62 +78⦊}⦉78⦉63⦉38⦉2726⦊‸⦉26
    + + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile new file mode 100644 index 0000000000..0578949b3c --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile @@ -0,0 +1,11 @@ +# needs-profiler-support +# ignore-msvc + +# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 +LINK_DEAD_CODE=yes + +-include ../instrument-coverage-mir-cov-html-base/Makefile + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. \ No newline at end of file diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000..94abe11896 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,808 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() { + let mut countdown = 0; + 2⦊4⦊3⦊if 0⦊true⦉0 { + countdown = 10; + }⦉3⦉4⦉2 + + 6⦊9⦊25⦊if 5⦊countdown > 7⦉5 { + 8⦊countdown -= 4⦉8; + } else 10⦊if 7⦊countdown > 2⦉7 { + 22⦊23⦊21⦊if 14⦊15⦊16⦊13⦊20⦊12⦊18⦊19⦊17⦊countdown < 1 || countdown > 5⦉17⦉19⦉18 || countdown != 9⦉12⦉20⦉13⦉16⦉15⦉14 { + countdown = 0; + 24⦊}⦉22⦉23⦉21⦉21 + countdown -= 5⦉24; + } else { + 27⦊11⦊return; + }⦉11⦉6⦉9⦉25⦉25⦉25⦉10⦉10⦉10⦉11 + + let mut countdown = 0; + 30⦊31⦊29⦊if 28⦊true⦉28 { + countdown = 10; + }⦉29⦉31⦉30 + + 33⦊52⦊36⦊if 32⦊countdown > 7⦉32 { + 35⦊countdown -= 4⦉35; + } else 37⦊if 34⦊countdown > 2⦉34 { + 48⦊50⦊49⦊if 39⦊47⦊40⦊43⦊42⦊41⦊46⦊45⦊44⦊countdown < 1 || countdown > 5⦉44⦉45⦉46 || countdown != 9⦉41⦉42⦉43⦉40⦉47⦉39 { + countdown = 0; + 51⦊}⦉48⦉50⦉49⦉49 + countdown -= 5⦉51; + } else { + 38⦊return; + }⦉33⦉52⦉36⦉36⦉36⦉37⦉37⦉37 + + let mut countdown = 0; + 56⦊54⦊55⦊if 53⦊true⦉53 { + countdown = 10; + }⦉55⦉54⦉56 + + 61⦊58⦊77⦊if 57⦊countdown > 7⦉57 { + 60⦊countdown -= 4⦉60; + } else 62⦊if 59⦊countdown > 2⦉59 { + 75⦊74⦊73⦊if 67⦊68⦊65⦊72⦊64⦊66⦊69⦊71⦊70⦊countdown < 1 || countdown > 5⦉70⦉71⦉69 || countdown != 9⦉66⦉64⦉72⦉65⦉68⦉67 { + countdown = 0; + 76⦊}⦉75⦉74⦉73⦉73 + countdown -= 5⦉76; + } else { + 63⦊return; + }⦉61⦉58⦉77⦉77⦉77⦉62⦉62⦉62 +78⦊}⦉78⦉63⦉38⦉2726⦊‸⦉26
    + + diff --git a/src/test/run-make-fulldeps/instrument-coverage/Makefile b/src/test/run-make-fulldeps/instrument-coverage/Makefile deleted file mode 100644 index 4392cfec08..0000000000 --- a/src/test/run-make-fulldeps/instrument-coverage/Makefile +++ /dev/null @@ -1,103 +0,0 @@ -# needs-profiler-support -# ignore-msvc - -# FIXME(richkadel): Debug the following problem, and reenable on Windows (by -# removing the `# ignore-msvc` directive above). The current implementation -# generates a segfault when running the instrumented `testprog` executable, -# after the `main()` function completes, but before the process terminates. -# This most likely points to a problem generating the LLVM "testprog.profraw" -# file. - --include ../tools.mk - -UNAME = $(shell uname) - -ifeq ($(UNAME),Darwin) - INSTR_PROF_DATA_SUFFIX=,regular,live_support - DATA_SECTION_PREFIX=__DATA, - LLVM_COV_SECTION_PREFIX=__LLVM_COV, -else - INSTR_PROF_DATA_SUFFIX= - DATA_SECTION_PREFIX= - LLVM_COV_SECTION_PREFIX= -endif - -# This test makes sure that LLVM coverage maps are genereated in LLVM IR. - -COMMON_FLAGS=-Zinstrument-coverage - -all: - # Compile the test program with instrumentation, and also generate LLVM IR - $(RUSTC) $(COMMON_FLAGS) testprog.rs \ - --emit=link,llvm-ir - - # check the LLVM IR -ifdef IS_WIN32 - cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt \ - -check-prefixes=CHECK,WIN32 \ - -DPRIVATE_GLOBAL="internal global" \ - -DINSTR_PROF_DATA=".lprfd$$M" \ - -DINSTR_PROF_NAME=".lprfn$$M" \ - -DINSTR_PROF_CNTS=".lprfc$$M" \ - -DINSTR_PROF_VALS=".lprfv$$M" \ - -DINSTR_PROF_VNODES=".lprfnd$$M" \ - -DINSTR_PROF_COVMAP=".lcovmap$$M" \ - -DINSTR_PROF_ORDERFILE=".lorderfile$$M" -else - cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt \ - -check-prefixes=CHECK \ - -DPRIVATE_GLOBAL="private global" \ - -DINSTR_PROF_DATA="$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)" \ - -DINSTR_PROF_NAME="$(DATA_SECTION_PREFIX)__llvm_prf_names" \ - -DINSTR_PROF_CNTS="$(DATA_SECTION_PREFIX)__llvm_prf_cnts" \ - -DINSTR_PROF_VALS="$(DATA_SECTION_PREFIX)__llvm_prf_vals" \ - -DINSTR_PROF_VNODES="$(DATA_SECTION_PREFIX)__llvm_prf_vnds" \ - -DINSTR_PROF_COVMAP="$(LLVM_COV_SECTION_PREFIX)__llvm_covmap" \ - -DINSTR_PROF_ORDERFILE="$(DATA_SECTION_PREFIX)__llvm_orderfile" -endif - - # Run it in order to generate some profiling data, - # with `LLVM_PROFILE_FILE=` environment variable set to - # output the coverage stats for this run. - LLVM_PROFILE_FILE="$(TMPDIR)"/testprog.profraw \ - $(call RUN,testprog) - - # Postprocess the profiling data so it can be used by the llvm-cov tool - "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \ - "$(TMPDIR)"/testprog.profraw \ - -o "$(TMPDIR)"/testprog.profdata - - # Generate a coverage report using `llvm-cov show`. The output ordering - # can be non-deterministic, so ignore the return status. If the test fails - # when comparing the JSON `export`, the `show` output may be useful when - # debugging. - "$(LLVM_BIN_DIR)"/llvm-cov show \ - --Xdemangler="$(RUST_DEMANGLER)" \ - --show-line-counts-or-regions \ - --instr-profile="$(TMPDIR)"/testprog.profdata \ - $(call BIN,"$(TMPDIR)"/testprog) \ - > "$(TMPDIR)"/actual_show_coverage.txt - -ifdef RUSTC_BLESS_TEST - cp "$(TMPDIR)"/actual_show_coverage.txt typical_show_coverage.txt -else - # Compare the show coverage output - $(DIFF) typical_show_coverage.txt "$(TMPDIR)"/actual_show_coverage.txt || \ - >&2 echo 'diff failed for `llvm-cov show` (might not be an error)' -endif - - # Generate a coverage report in JSON, using `llvm-cov export`, and fail if - # there are differences from the expected output. - "$(LLVM_BIN_DIR)"/llvm-cov export \ - --summary-only \ - --instr-profile="$(TMPDIR)"/testprog.profdata \ - $(call BIN,"$(TMPDIR)"/testprog) \ - | "$(PYTHON)" prettify_json.py \ - > "$(TMPDIR)"/actual_export_coverage.json - -ifdef RUSTC_BLESS_TEST - cp "$(TMPDIR)"/actual_export_coverage.json expected_export_coverage.json -else - # Check that the exported JSON coverage data matches what we expect - $(DIFF) expected_export_coverage.json "$(TMPDIR)"/actual_export_coverage.json -endif diff --git a/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir b/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir new file mode 100644 index 0000000000..d57f66a448 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir @@ -0,0 +1,3 @@ +# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-* + +# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests. \ No newline at end of file diff --git a/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs b/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs new file mode 100644 index 0000000000..91741cf8f0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs @@ -0,0 +1,51 @@ +#![allow(unused_assignments)] + +fn main() { + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/coverage_tools.mk b/src/test/run-make-fulldeps/instrument-coverage/coverage_tools.mk new file mode 100644 index 0000000000..ad5f465c54 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/coverage_tools.mk @@ -0,0 +1,39 @@ +# Common Makefile include for Rust `run-make-fulldeps/instrument-coverage-* tests. Include this +# file with the line: +# +# -include ../instrument-coverage/coverage_tools.mk +# +# To enable the Rust compiler option `-C link-dead-code`, also set the following variable +# *BEFORE* the `-include` line: +# +# LINK_DEAD_CODE=yes + +-include ../tools.mk + +ifndef LINK_DEAD_CODE + LINK_DEAD_CODE=no +endif + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw` +# file, required for coverage reports. +# +# Enabling `-C link-dead-code` is preferred when compiling with `-Z instrument-coverage`, so +# `-C link-dead-code` is automatically enabled for all platform targets _except_ MSVC. +# +# Making the state of `-C link-dead-code` platform-dependent creates a problem for cross-platform +# tests because the injected counters, coverage reports, and some low-level output can be different, +# depending on the `-C link-dead-code` setting. For example, coverage reports will not report any +# coverage for a dead code region when the `-C link-dead-code` option is disabled, but with the +# option enabled, those same regions will show coverage counter values (of zero, of course). +# +# To ensure cross-platform `-Z instrument-coverage` generate consistent output, the +# `-C link-dead-code` option is always explicitly enabled or disabled. +# +# Since tests that execute binaries enabled with both `-Z instrument-coverage` and +# `-C link-dead-code` are known to fail, those tests will need the `# ignore-msvc` setting. +# +# If and when the above issue is resolved, the `# ignore-msvc` option can be removed, and the +# tests can be simplified to always test with `-C link-dead-code`. + +UNAME = $(shell uname) diff --git a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json b/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json deleted file mode 100644 index 75bec80bdf..0000000000 --- a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "testprog.rs", - "summary": { - "functions": { - "count": 7, - "covered": 5, - "percent": 71.42857142857143 - }, - "instantiations": { - "count": 8, - "covered": 6, - "percent": 75 - }, - "lines": { - "count": 30, - "covered": 25, - "percent": 83.33333333333334 - }, - "regions": { - "count": 7, - "covered": 5, - "notcovered": 2, - "percent": 71.42857142857143 - } - } - } - ], - "totals": { - "functions": { - "count": 7, - "covered": 5, - "percent": 71.42857142857143 - }, - "instantiations": { - "count": 8, - "covered": 6, - "percent": 75 - }, - "lines": { - "count": 30, - "covered": 25, - "percent": 83.33333333333334 - }, - "regions": { - "count": 7, - "covered": 5, - "notcovered": 2, - "percent": 71.42857142857143 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt b/src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt deleted file mode 100644 index 5a7cc9a188..0000000000 --- a/src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt +++ /dev/null @@ -1,51 +0,0 @@ -# Check for metadata, variables, declarations, and function definitions injected -# into LLVM IR when compiling with -Zinstrument-coverage. - -WIN32: $__llvm_profile_runtime_user = comdat any - -CHECK: @__llvm_coverage_mapping = internal constant -CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8 - -WIN32: @__llvm_profile_runtime = external global i32 - -CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]] -CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8 - -CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]] -CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, -CHECK-SAME: ()* @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called to i8*), -CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8 - -CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]] -CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8 - -CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]] -CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main, -CHECK-SAME: ()* @_R{{[a-zA-Z0-9_]+}}testprog4main to i8*), -CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8 - -CHECK: @__llvm_prf_nm = private constant -CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1 - -CHECK: @llvm.used = appending global -CHECK-SAME: i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*) -WIN32-SAME: i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*) -CHECK-SAME: i8* bitcast ({ {{.*}} }* @__profd__R{{[a-zA-Z0-9_]*}}testprog4main to i8*) -CHECK-SAME: i8* getelementptr inbounds ({{.*}}* @__llvm_prf_nm, i32 0, i32 0) -CHECK-SAME: section "llvm.metadata" - -CHECK: define hidden { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { -CHECK-NEXT: start: -CHECK-NOT: bb{{[0-9]+}}: -CHECK: %pgocount = load i64, i64* getelementptr inbounds -CHECK-SAME: * @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, - -CHECK: declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] - -WIN32: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { -WIN32-NEXT: %1 = load i32, i32* @__llvm_profile_runtime -WIN32-NEXT: ret i32 %1 -WIN32-NEXT: } - -CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind } -WIN32: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline } \ No newline at end of file diff --git a/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt b/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt deleted file mode 100644 index ae123afff0..0000000000 --- a/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt +++ /dev/null @@ -1,55 +0,0 @@ - 1| 2|pub fn will_be_called() -> &'static str { - 2| 2| let val = "called"; - 3| 2| println!("{}", val); - 4| 2| val - 5| 2|} - 6| | - 7| 0|pub fn will_not_be_called() -> bool { - 8| 0| println!("should not have been called"); - 9| 0| false - 10| 0|} - 11| | - 12| |pub fn print(left: &str, value: T, right: &str) - 13| |where - 14| | T: std::fmt::Display, - 15| 1|{ - 16| 1| println!("{}{}{}", left, value, right); - 17| 1|} - 18| | - 19| |pub fn wrap_with(inner: T, should_wrap: bool, wrapper: F) - 20| |where - 21| | F: FnOnce(&T) - 22| 2|{ - 23| 2| if should_wrap { - 24| 2| wrapper(&inner) - 25| 2| } - 26| 2|} - ------------------ - | testprog[317d481089b8c8fe]::wrap_with::: - | 22| 1|{ - | 23| 1| if should_wrap { - | 24| 1| wrapper(&inner) - | 25| 1| } - | 26| 1|} - ------------------ - | testprog[317d481089b8c8fe]::wrap_with::: - | 22| 1|{ - | 23| 1| if should_wrap { - | 24| 1| wrapper(&inner) - | 25| 1| } - | 26| 1|} - ------------------ - 27| | - 28| 1|fn main() { - 29| 1| let less = 1; - 30| 1| let more = 100; - 31| 1| - 32| 1| if less < more { - 33| 1| wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** ")); - 34| 1| wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** ")); - ^0 - 35| 1| } else { - 36| 1| wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, "")); - 37| 1| } - 38| 1|} - diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index af84faa751..2636423c1a 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -60,6 +60,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { lint_caps: Default::default(), register_lints: None, override_queries: None, + make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), }; diff --git a/src/test/run-make-fulldeps/issue-69368/a.rs b/src/test/run-make-fulldeps/issue-69368/a.rs index 726db87463..7d339c5a5d 100644 --- a/src/test/run-make-fulldeps/issue-69368/a.rs +++ b/src/test/run-make-fulldeps/issue-69368/a.rs @@ -14,3 +14,8 @@ pub fn panic_handler(_: &core::panic::PanicInfo) -> ! { extern "C" fn __rust_drop_panic() -> ! { loop {} } + +#[no_mangle] +extern "C" fn __rust_foreign_exception() -> ! { + loop {} +} diff --git a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile index c13297b3a6..18828b66ce 100644 --- a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile +++ b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile index 6c70d951c3..f1ac39aa0e 100644 --- a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-gen/Makefile b/src/test/run-make-fulldeps/pgo-gen/Makefile index 3b66427c14..69b19801bf 100644 --- a/src/test/run-make-fulldeps/pgo-gen/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile index e61018752c..876a9b2c43 100644 --- a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile +++ b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-use/Makefile b/src/test/run-make-fulldeps/pgo-use/Makefile index 61a7358775..cb5e9e9a45 100644 --- a/src/test/run-make-fulldeps/pgo-use/Makefile +++ b/src/test/run-make-fulldeps/pgo-use/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index f9b6d34229..634c9ece3f 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -11,8 +11,8 @@ BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)' RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) RUSTDOC := $(BARE_RUSTDOC) -L $(TARGET_RPATH_DIR) ifdef RUSTC_LINKER -RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER) -RUSTDOC := $(RUSTDOC) -Clinker=$(RUSTC_LINKER) +RUSTC := $(RUSTC) -Clinker='$(RUSTC_LINKER)' +RUSTDOC := $(RUSTDOC) -Clinker='$(RUSTC_LINKER)' endif #CC := $(CC) -L $(TMPDIR) HTMLDOCCK := '$(PYTHON)' '$(S)/src/etc/htmldocck.py' diff --git a/src/test/run-make-fulldeps/type-mismatch-same-crate-name/Makefile b/src/test/run-make-fulldeps/type-mismatch-same-crate-name/Makefile index 9fd1377322..802b3df460 100644 --- a/src/test/run-make-fulldeps/type-mismatch-same-crate-name/Makefile +++ b/src/test/run-make-fulldeps/type-mismatch-same-crate-name/Makefile @@ -11,9 +11,9 @@ all: tr -d '\r\n' | $(CGREP) -e \ "mismatched types.*\ crateB::try_foo\(foo2\);.*\ - expected struct \`crateA::foo::Foo\`, found struct \`crateA::Foo\`.*\ + expected struct \`crateA::foo::Foo\`, found struct \`Foo\`.*\ different versions of crate \`crateA\`.*\ mismatched types.*\ crateB::try_bar\(bar2\);.*\ - expected trait \`crateA::bar::Bar\`, found trait \`crateA::Bar\`.*\ + expected trait \`crateA::bar::Bar\`, found trait \`Bar\`.*\ different versions of crate \`crateA\`" diff --git a/src/test/run-make/thumb-none-cortex-m/Makefile b/src/test/run-make/thumb-none-cortex-m/Makefile index 36e51bcab6..13385369e4 100644 --- a/src/test/run-make/thumb-none-cortex-m/Makefile +++ b/src/test/run-make/thumb-none-cortex-m/Makefile @@ -35,4 +35,4 @@ all: # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. - cd $(WORK_DIR) && cd $(CRATE) && env RUSTC_BOOTSTRAP=1 $(CARGO) build --target $(TARGET) -v + cd $(WORK_DIR) && cd $(CRATE) && env RUSTC_BOOTSTRAP=1 $(BOOTSTRAP_CARGO) build --target $(TARGET) -v diff --git a/src/test/run-make/thumb-none-qemu/script.sh b/src/test/run-make/thumb-none-qemu/script.sh index c5cbff5c3c..045d02a8ed 100644 --- a/src/test/run-make/thumb-none-qemu/script.sh +++ b/src/test/run-make/thumb-none-qemu/script.sh @@ -12,8 +12,8 @@ pushd $WORK_DIR # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. env RUSTC_BOOTSTRAP=1 RUSTFLAGS="-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x" \ - $CARGO run --target $TARGET | grep "x = 42" + $BOOTSTRAP_CARGO run --target $TARGET | grep "x = 42" env RUSTC_BOOTSTRAP=1 RUSTFLAGS="-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x" \ - $CARGO run --target $TARGET --release | grep "x = 42" + $BOOTSTRAP_CARGO run --target $TARGET --release | grep "x = 42" popd popd diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile new file mode 100644 index 0000000000..6a04d34391 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile @@ -0,0 +1,23 @@ +-include ../../run-make-fulldeps/tools.mk + +#only-x86_64-fortanix-unknown-sgx + +# For cargo setting +export RUSTC := $(RUSTC_ORIGINAL) +export LD_LIBRARY_PATH := $(HOST_RPATH_DIR) +# We need to be outside of 'src' dir in order to run cargo +export WORK_DIR := $(TMPDIR) +export TEST_DIR := $(shell pwd) + +## clean up unused env variables which might cause harm. +unexport RUSTC_LINKER +unexport RUSTC_BOOTSTRAP +unexport RUST_BUILD_STAGE +unexport RUST_TEST_THREADS +unexport RUST_TEST_TMPDIR +unexport AR +unexport CC +unexport CXX + +all: + bash script.sh diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks new file mode 100644 index 0000000000..e839c200bb --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks @@ -0,0 +1,8 @@ +CHECK: cc_plus_one_asm +CHECK-NEXT: movl +CHECK-NEXT: lfence +CHECK-NEXT: inc +CHECK-NEXT: notq (%rsp) +CHECK-NEXT: notq (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks new file mode 100644 index 0000000000..b93b33afb3 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks @@ -0,0 +1,6 @@ +CHECK: cc_plus_one_c +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks new file mode 100644 index 0000000000..d1fae3d495 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks @@ -0,0 +1,15 @@ +CHECK: cc_plus_one_c_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks new file mode 100644 index 0000000000..f96f152c02 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks @@ -0,0 +1,6 @@ +CHECK: cc_plus_one_cxx +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks new file mode 100644 index 0000000000..e704bf4172 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks @@ -0,0 +1,16 @@ +CHECK: cc_plus_one_cxx_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: movl +CHECK: lfence +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks new file mode 100644 index 0000000000..78b18ccbfc --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks @@ -0,0 +1,7 @@ +CHECK: cmake_plus_one_asm +CHECK-NEXT: movl +CHECK-NEXT: lfence +CHECK-NEXT: incl +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks new file mode 100644 index 0000000000..f551356b2f --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks @@ -0,0 +1,6 @@ +CHECK: cmake_plus_one_c +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks new file mode 100644 index 0000000000..87c806f137 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks @@ -0,0 +1,16 @@ +CHECK: cmake_plus_one_c_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: movl +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks new file mode 100644 index 0000000000..4b66cc5bc8 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks @@ -0,0 +1,2 @@ +CHECK: cmake_plus_one_c_global_asm +CHECK: lfence diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks new file mode 100644 index 0000000000..0f403e0203 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks @@ -0,0 +1,6 @@ +CHECK: cmake_plus_one_cxx +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks new file mode 100644 index 0000000000..9cac8711ea --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks @@ -0,0 +1,16 @@ +CHECK: cmake_plus_one_cxx_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: movl +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks new file mode 100644 index 0000000000..d4a3d44790 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks @@ -0,0 +1,2 @@ +CHECK: cmake_plus_one_cxx_global_asm +CHECK: lfence diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml new file mode 100644 index 0000000000..8949068658 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "enclave" +version = "0.1.0" +authors = ["Raoul Strackx "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[build-dependencies] +cc = "1.0" +cmake = "0.1" diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs new file mode 100644 index 0000000000..3a7aa1be86 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs @@ -0,0 +1,30 @@ +fn main() { + cc::Build::new() + .file("foo.c") + .compile("foo_c"); + + cc::Build::new() + .file("foo_asm.s") + .compile("foo_asm"); + + cc::Build::new() + .cpp(true) + .cpp_set_stdlib(None) + .file("foo_cxx.cpp") + .compile("foo_cxx"); + + // When the cmake crate detects the clang compiler, it passes the + // "--target" argument to the linker which subsequently fails. The + // `CMAKE_C_COMPILER_FORCED` option makes sure that `cmake` does not + // tries to test the compiler. From version 3.6 the option + // `CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY` can be used + // https://cmake.org/cmake/help/v3.5/module/CMakeForceCompiler.html + let dst = cmake::Config::new("libcmake_foo") + .build_target("cmake_foo") + .define("CMAKE_C_COMPILER_FORCED", "1") + .define("CMAKE_CXX_COMPILER_FORCED", "1") + .define("CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY", "1") + .build(); + println!("cargo:rustc-link-search=native={}/build/", dst.display()); + println!("cargo:rustc-link-lib=static=cmake_foo"); +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c new file mode 100644 index 0000000000..dd76d4f303 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c @@ -0,0 +1,18 @@ +int cc_plus_one_c(int *arg) { + return *arg + 1; +} + +int cc_plus_one_c_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s new file mode 100644 index 0000000000..6d56214e87 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s @@ -0,0 +1,7 @@ + .text + .global cc_plus_one_asm + .type cc_plus_one_asm, @function +cc_plus_one_asm: + movl (%rdi), %eax + inc %eax + retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp new file mode 100644 index 0000000000..ac6f64ac41 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp @@ -0,0 +1,21 @@ +extern "C" int cc_plus_one_cxx(int *arg); +extern "C" int cc_plus_one_cxx_asm(int *arg); + +int cc_plus_one_cxx(int *arg) { + return *arg + 1; +} + +int cc_plus_one_cxx_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt new file mode 100644 index 0000000000..27cdf2ecf8 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt @@ -0,0 +1,33 @@ +enable_language(C CXX ASM) + +set(C_SOURCES + src/foo.c + ) + +set_source_files_properties(${C_SOURCES} + PROPERTIES + LANGUAGE C) + +set(CXX_SOURCES + src/foo_cxx.cpp + ) + +set_source_files_properties(${CXX_SOURCES} + PROPERTIES + LANGUAGE CXX) + +set(ASM_SOURCES + src/foo_asm.s + ) + +set_source_files_properties(${ASM_SOURCES} + PROPERTIES + LANGUAGE ASM) + +set(SOURCES + ${C_SOURCES} + ${CXX_SOURCES} + ${ASM_SOURCES}) + +add_library(cmake_foo STATIC + ${SOURCES}) diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c new file mode 100644 index 0000000000..c3b731a2d5 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c @@ -0,0 +1,26 @@ +int cmake_plus_one_c(int *arg) { + return *arg + 1; +} + +int cmake_plus_one_c_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} + +asm(".text\n" +" .global cmake_plus_one_c_global_asm\n" +" .type cmake_plus_one_c_global_asm, @function\n" +"cmake_plus_one_c_global_asm:\n" +" movl (%rdi), %eax\n" +" inc %eax\n" +" retq\n" ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s new file mode 100644 index 0000000000..64b6b430ee --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s @@ -0,0 +1,7 @@ + .text + .global cmake_plus_one_asm + .type cmake_plus_one_asm, @function +cmake_plus_one_asm: + movl (%rdi), %eax + inc %eax + retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp new file mode 100644 index 0000000000..824e2afebc --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp @@ -0,0 +1,29 @@ +extern "C" int cmake_plus_one_cxx(int *arg); +extern "C" int cmake_plus_one_cxx_asm(int *arg); + +int cmake_plus_one_cxx(int *arg) { + return *arg + 1; +} + +int cmake_plus_one_cxx_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} + +asm(".text\n" +" .global cmake_plus_one_cxx_global_asm\n" +" .type cmake_plus_one_cxx_global_asm, @function\n" +"cmake_plus_one_cxx_global_asm:\n" +" movl (%rdi), %eax\n" +" inc %eax\n" +" retq\n" ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs new file mode 100644 index 0000000000..8e91a8d842 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs @@ -0,0 +1,48 @@ +#![feature(global_asm)] + +global_asm!( r#" + .text + .global rust_plus_one_global_asm + .type rust_plus_one_global_asm, @function +rust_plus_one_global_asm: + movl (%rdi), %eax + inc %eax + retq +"# ); + +extern { + fn cc_plus_one_c(arg : &u32) -> u32; + fn cc_plus_one_c_asm(arg : &u32) -> u32; + fn cc_plus_one_cxx(arg : &u32) -> u32; + fn cc_plus_one_cxx_asm(arg : &u32) -> u32; + fn cc_plus_one_asm(arg : &u32) -> u32; + fn cmake_plus_one_c(arg : &u32) -> u32; + fn cmake_plus_one_c_asm(arg : &u32) -> u32; + fn cmake_plus_one_cxx(arg : &u32) -> u32; + fn cmake_plus_one_cxx_asm(arg : &u32) -> u32; + fn cmake_plus_one_c_global_asm(arg : &u32) -> u32; + fn cmake_plus_one_cxx_global_asm(arg : &u32) -> u32; + fn cmake_plus_one_asm(arg : &u32) -> u32; + fn rust_plus_one_global_asm(arg : &u32) -> u32; +} + +fn main() { + let value : u32 = 41; + let question = "Answer to the Ultimate Question of Life, the Universe, and Everything:"; + + unsafe{ + println!("{}: {}!", question,rust_plus_one_global_asm(&value)); + println!("{}: {}!", question,cc_plus_one_c(&value)); + println!("{}: {}!", question,cc_plus_one_c_asm(&value)); + println!("{}: {}!", question,cc_plus_one_cxx(&value)); + println!("{}: {}!", question,cc_plus_one_cxx_asm(&value)); + println!("{}: {}!", question,cc_plus_one_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_c(&value)); + println!("{}: {}!", question,cmake_plus_one_c_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_cxx(&value)); + println!("{}: {}!", question,cmake_plus_one_cxx_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_c_global_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_cxx_global_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_asm(&value)); + } +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks new file mode 100644 index 0000000000..15211e3ade --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks @@ -0,0 +1,8 @@ +CHECK: libunwind::Registers_x86_64::jumpto +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks new file mode 100644 index 0000000000..0fe88141b2 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks @@ -0,0 +1,7 @@ +CHECK: print +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: popq +CHECK: callq 0x{{[[:xdigit:]]*}} <_Unwind_Resume> +CHECK-NEXT: ud2 diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks new file mode 100644 index 0000000000..fe6777537f --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks @@ -0,0 +1,2 @@ +CHECK: rust_plus_one_global_asm +CHECK: lfence diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh new file mode 100644 index 0000000000..ec93c98016 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -0,0 +1,57 @@ +set -exuo pipefail + +function build { + CRATE=enclave + + mkdir -p $WORK_DIR + pushd $WORK_DIR + rm -rf $CRATE + cp -a $TEST_DIR/enclave . + pushd $CRATE + echo ${WORK_DIR} + # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. + # These come from the top-level Rust workspace, that this crate is not a + # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. + env RUSTC_BOOTSTRAP=1 + cargo -v run --target $TARGET + popd + popd +} + +function check { + local func=$1 + local checks="${TEST_DIR}/$2" + local asm=$(mktemp) + local objdump="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/llvm-objdump" + local filecheck="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/FileCheck" + + ${objdump} --disassemble-symbols=${func} --demangle \ + ${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave > ${asm} + ${filecheck} --input-file ${asm} ${checks} +} + +build + +check unw_getcontext unw_getcontext.checks +check "libunwind::Registers_x86_64::jumpto()" jumpto.checks +check "std::io::stdio::_print::h87f0c238421c45bc" print.checks +check rust_plus_one_global_asm rust_plus_one_global_asm.checks \ + || echo "warning: module level assembly currently not hardened" + +check cc_plus_one_c cc_plus_one_c.checks +check cc_plus_one_c_asm cc_plus_one_c_asm.checks +check cc_plus_one_cxx cc_plus_one_cxx.checks +check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks +check cc_plus_one_asm cc_plus_one_asm.checks \ + || echo "warning: the cc crate forwards assembly files to the CC compiler." \ + "Clang uses its own intergrated assembler, which does not include the LVI passes." + +check cmake_plus_one_c cmake_plus_one_c.checks +check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks +check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks \ + || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_cxx cmake_plus_one_cxx.checks +check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks +check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks \ + || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_asm cmake_plus_one_asm.checks diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks new file mode 100644 index 0000000000..4b7615b115 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks @@ -0,0 +1,6 @@ +CHECK: unw_getcontext +CHECK: lfence +CHECK: lfence +CHECK: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr index 8827c9351a..92d27179e8 100644 --- a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr @@ -2,14 +2,13 @@ error: unresolved link to `S::fmt` --> $DIR/assoc-item-not-in-scope.rs:4:14 | LL | /// Link to [`S::fmt`] - | ^^^^^^^^ unresolved link + | ^^^^^^^^ the struct `S` has no field or associated item named `fmt` | note: the lint level is defined here --> $DIR/assoc-item-not-in-scope.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs index b02cc1a454..c8bec39fad 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.rs +++ b/src/test/rustdoc-ui/check-doc-alias-attr.rs @@ -7,4 +7,10 @@ pub struct Bar; #[doc(alias)] //~ ERROR #[doc(alias = 0)] //~ ERROR #[doc(alias("bar"))] //~ ERROR +#[doc(alias = "\"")] //~ ERROR +#[doc(alias = "\n")] //~ ERROR +#[doc(alias = " +")] //~^ ERROR +#[doc(alias = " ")] //~ ERROR +#[doc(alias = "\t")] //~ ERROR pub struct Foo; diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr index 268230ab44..be7d7b3dbe 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr @@ -16,5 +16,37 @@ error: doc alias attribute expects a string: #[doc(alias = "0")] LL | #[doc(alias("bar"))] | ^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: '\"' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:10:7 + | +LL | #[doc(alias = "\"")] + | ^^^^^^^^^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:11:7 + | +LL | #[doc(alias = "\n")] + | ^^^^^^^^^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:12:7 + | +LL | #[doc(alias = " + | _______^ +LL | | ")] + | |_^ + +error: ' ' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:14:7 + | +LL | #[doc(alias = " ")] + | ^^^^^^^^^^^ + +error: '\t' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:15:7 + | +LL | #[doc(alias = "\t")] + | ^^^^^^^^^^^^ + +error: aborting due to 8 previous errors diff --git a/src/test/rustdoc-ui/coverage/doc-examples.stdout b/src/test/rustdoc-ui/coverage/doc-examples.stdout index 10ed13c9ff..8188740f87 100644 --- a/src/test/rustdoc-ui/coverage/doc-examples.stdout +++ b/src/test/rustdoc-ui/coverage/doc-examples.stdout @@ -1,7 +1,7 @@ +-------------------------------------+------------+------------+------------+------------+ | File | Documented | Percentage | Examples | Percentage | +-------------------------------------+------------+------------+------------+------------+ -| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 2 | 50.0% | +| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 25.0% | +-------------------------------------+------------+------------+------------+------------+ -| Total | 4 | 100.0% | 2 | 50.0% | +| Total | 4 | 100.0% | 1 | 25.0% | +-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index 7530e3ad0f..33260fa0e1 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -2,7 +2,7 @@ error: unresolved link to `v2` --> $DIR/deny-intra-link-resolution-failure.rs:3:6 | LL | /// [v2] - | ^^ unresolved link + | ^^ the module `deny_intra_link_resolution_failure` contains no item named `v2` | note: the lint level is defined here --> $DIR/deny-intra-link-resolution-failure.rs:1:9 diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.rs b/src/test/rustdoc-ui/doc-alias-assoc-const.rs new file mode 100644 index 0000000000..73e23c152f --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-assoc-const.rs @@ -0,0 +1,22 @@ +#![feature(doc_alias)] +#![feature(trait_alias)] + +pub struct Foo; + +pub trait Bar { + const BAZ: u8; +} + +impl Bar for Foo { + #[doc(alias = "CONST_BAZ")] //~ ERROR + const BAZ: u8 = 0; +} + +impl Foo { + #[doc(alias = "CONST_FOO")] // ok! + pub const FOO: u8 = 0; + + pub fn bar() -> u8 { + Self::FOO + } +} diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.stderr b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr new file mode 100644 index 0000000000..3c64548cc2 --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr @@ -0,0 +1,8 @@ +error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block + --> $DIR/doc-alias-assoc-const.rs:11:11 + | +LL | #[doc(alias = "CONST_BAZ")] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs index fcbd7cabc6..90cdb5127b 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.rs +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -2,7 +2,7 @@ // FIXME: if/when the output of the test harness can be tested on its own, this test should be // adapted to use that, and that normalize line can go away -// compile-flags:--test +// compile-flags:--test --test-args --test-threads=1 // rustc-env:RUST_BACKTRACE=0 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // failure-status: 101 diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs index acce0f77a2..2319de5568 100644 --- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs @@ -5,7 +5,7 @@ pub async fn f() -> impl std::fmt::Debug { #[derive(Debug)] enum E { - //~^ ERROR recursive type `f::{{closure}}#0::E` has infinite size + //~^ ERROR recursive type `f::{closure#0}::E` has infinite size This(E), Unit, } diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index f1c07e31cd..771fc2204f 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -2,14 +2,13 @@ error: unresolved link to `TypeAlias::hoge` --> $DIR/intra-doc-alias-ice.rs:5:30 | LL | /// [broken cross-reference](TypeAlias::hoge) - | ^^^^^^^^^^^^^^^ unresolved link + | ^^^^^^^^^^^^^^^ the type alias `TypeAlias` has no associated item named `hoge` | note: the lint level is defined here --> $DIR/intra-doc-alias-ice.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.rs b/src/test/rustdoc-ui/intra-link-double-anchor.rs new file mode 100644 index 0000000000..a01211c4f3 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-double-anchor.rs @@ -0,0 +1,7 @@ +// check-pass + +// regression test for #73264 +// should only give one error +/// docs [label][with#anchor#error] +//~^ WARNING multiple anchors +pub struct S; diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.stderr b/src/test/rustdoc-ui/intra-link-double-anchor.stderr new file mode 100644 index 0000000000..3282ec8b79 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-double-anchor.stderr @@ -0,0 +1,10 @@ +warning: `with#anchor#error` contains multiple anchors + --> $DIR/intra-link-double-anchor.rs:5:18 + | +LL | /// docs [label][with#anchor#error] + | ^^^^^^^^^^^^^^^^^ contains invalid anchor + | + = note: `#[warn(broken_intra_doc_links)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs new file mode 100644 index 0000000000..0278caf308 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -0,0 +1,105 @@ +#![deny(broken_intra_doc_links)] +//~^ NOTE lint level is defined + +// FIXME: this should say that it was skipped (maybe an allowed by default lint?) +/// [] + +/// [path::to::nonexistent::module] +//~^ ERROR unresolved link +//~| NOTE `intra_link_errors` contains no item named `path` + +/// [path::to::nonexistent::macro!] +//~^ ERROR unresolved link +//~| NOTE `intra_link_errors` contains no item named `path` + +/// [type@path::to::nonexistent::type] +//~^ ERROR unresolved link +//~| NOTE `intra_link_errors` contains no item named `path` + +/// [std::io::not::here] +//~^ ERROR unresolved link +//~| NOTE `io` contains no item named `not` + +/// [type@std::io::not::here] +//~^ ERROR unresolved link +//~| NOTE `io` contains no item named `not` + +/// [std::io::Error::x] +//~^ ERROR unresolved link +//~| NOTE the struct `Error` has no field + +/// [std::io::ErrorKind::x] +//~^ ERROR unresolved link +//~| NOTE the enum `ErrorKind` has no variant + +/// [f::A] +//~^ ERROR unresolved link +//~| NOTE `f` is a function, not a module + +/// [f::A!] +//~^ ERROR unresolved link +//~| NOTE `f` is a function, not a module + +/// [S::A] +//~^ ERROR unresolved link +//~| NOTE struct `S` has no field or associated item + +/// [S::fmt] +//~^ ERROR unresolved link +//~| NOTE struct `S` has no field or associated item + +/// [E::D] +//~^ ERROR unresolved link +//~| NOTE enum `E` has no variant or associated item + +/// [u8::not_found] +//~^ ERROR unresolved link +//~| NOTE the builtin type `u8` has no associated item named `not_found` + +/// [std::primitive::u8::not_found] +//~^ ERROR unresolved link +//~| NOTE the builtin type `u8` has no associated item named `not_found` + +/// [type@Vec::into_iter] +//~^ ERROR unresolved link +//~| HELP to link to the associated function, add parentheses +//~| NOTE this link resolves to the associated function `into_iter` + +/// [S!] +//~^ ERROR unresolved link +//~| HELP to link to the struct, prefix with `struct@` +//~| NOTE this link resolves to the struct `S` +pub fn f() {} +#[derive(Debug)] +pub struct S; + +pub enum E { A, B, C } + +/// [type@S::h] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace +impl S { + pub fn h() {} +} + +/// [type@T::g] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace + +/// [T::h!] +//~^ ERROR unresolved link +//~| NOTE `T` has no macro named `h` +pub trait T { + fn g() {} +} + +/// [m()] +//~^ ERROR unresolved link +//~| HELP to link to the macro +//~| NOTE not in the value namespace +#[macro_export] +macro_rules! m { + () => {}; +} diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr new file mode 100644 index 0000000000..b63f799535 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -0,0 +1,143 @@ +error: unresolved link to `path::to::nonexistent::module` + --> $DIR/intra-link-errors.rs:7:6 + | +LL | /// [path::to::nonexistent::module] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path` + | +note: the lint level is defined here + --> $DIR/intra-link-errors.rs:1:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `path::to::nonexistent::macro` + --> $DIR/intra-link-errors.rs:11:6 + | +LL | /// [path::to::nonexistent::macro!] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path` + +error: unresolved link to `path::to::nonexistent::type` + --> $DIR/intra-link-errors.rs:15:6 + | +LL | /// [type@path::to::nonexistent::type] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path` + +error: unresolved link to `std::io::not::here` + --> $DIR/intra-link-errors.rs:19:6 + | +LL | /// [std::io::not::here] + | ^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not` + +error: unresolved link to `std::io::not::here` + --> $DIR/intra-link-errors.rs:23:6 + | +LL | /// [type@std::io::not::here] + | ^^^^^^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not` + +error: unresolved link to `std::io::Error::x` + --> $DIR/intra-link-errors.rs:27:6 + | +LL | /// [std::io::Error::x] + | ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x` + +error: unresolved link to `std::io::ErrorKind::x` + --> $DIR/intra-link-errors.rs:31:6 + | +LL | /// [std::io::ErrorKind::x] + | ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x` + +error: unresolved link to `f::A` + --> $DIR/intra-link-errors.rs:35:6 + | +LL | /// [f::A] + | ^^^^ `f` is a function, not a module or type, and cannot have associated items + +error: unresolved link to `f::A` + --> $DIR/intra-link-errors.rs:39:6 + | +LL | /// [f::A!] + | ^^^^^ `f` is a function, not a module or type, and cannot have associated items + +error: unresolved link to `S::A` + --> $DIR/intra-link-errors.rs:43:6 + | +LL | /// [S::A] + | ^^^^ the struct `S` has no field or associated item named `A` + +error: unresolved link to `S::fmt` + --> $DIR/intra-link-errors.rs:47:6 + | +LL | /// [S::fmt] + | ^^^^^^ the struct `S` has no field or associated item named `fmt` + +error: unresolved link to `E::D` + --> $DIR/intra-link-errors.rs:51:6 + | +LL | /// [E::D] + | ^^^^ the enum `E` has no variant or associated item named `D` + +error: unresolved link to `u8::not_found` + --> $DIR/intra-link-errors.rs:55:6 + | +LL | /// [u8::not_found] + | ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` + +error: unresolved link to `std::primitive::u8::not_found` + --> $DIR/intra-link-errors.rs:59:6 + | +LL | /// [std::primitive::u8::not_found] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` + +error: unresolved link to `Vec::into_iter` + --> $DIR/intra-link-errors.rs:63:6 + | +LL | /// [type@Vec::into_iter] + | ^^^^^^^^^^^^^^^^^^^ + | | + | this link resolves to the associated function `into_iter`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `Vec::into_iter()` + +error: unresolved link to `S` + --> $DIR/intra-link-errors.rs:68:6 + | +LL | /// [S!] + | ^^ + | | + | this link resolves to the struct `S`, which is not in the macro namespace + | help: to link to the struct, prefix with `struct@`: `struct@S` + +error: unresolved link to `T::g` + --> $DIR/intra-link-errors.rs:86:6 + | +LL | /// [type@T::g] + | ^^^^^^^^^ + | | + | this link resolves to the associated function `g`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `T::g()` + +error: unresolved link to `T::h` + --> $DIR/intra-link-errors.rs:91:6 + | +LL | /// [T::h!] + | ^^^^^ the trait `T` has no macro named `h` + +error: unresolved link to `S::h` + --> $DIR/intra-link-errors.rs:78:6 + | +LL | /// [type@S::h] + | ^^^^^^^^^ + | | + | this link resolves to the associated function `h`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `S::h()` + +error: unresolved link to `m` + --> $DIR/intra-link-errors.rs:98:6 + | +LL | /// [m()] + | ^^^ + | | + | this link resolves to the macro `m`, which is not in the value namespace + | help: to link to the macro, add an exclamation mark: `m!` + +error: aborting due to 20 previous errors + diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.rs b/src/test/rustdoc-ui/intra-link-prim-conflict.rs index 34276fbcf2..85738ceae8 100644 --- a/src/test/rustdoc-ui/intra-link-prim-conflict.rs +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.rs @@ -18,13 +18,13 @@ /// [struct@char] //~^ ERROR incompatible link -//~| HELP use its disambiguator +//~| HELP prefix with `mod@` //~| NOTE resolved to a module pub mod char {} pub mod inner { //! [struct@char] //~^ ERROR incompatible link - //~| HELP use its disambiguator + //~| HELP prefix with `prim@` //~| NOTE resolved to a builtin type } diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr index b28a442666..43587a8002 100644 --- a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr @@ -9,11 +9,11 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the module, prefix with the item type +help: to link to the module, prefix with `mod@` | -LL | /// [module@char] - | ^^^^^^^^^^^ -help: to link to the builtin type, prefix with the item type +LL | /// [mod@char] + | ^^^^^^^^ +help: to link to the builtin type, prefix with `prim@` | LL | /// [prim@char] | ^^^^^^^^^ @@ -24,11 +24,11 @@ error: `char` is both a module and a builtin type LL | /// [type@char] | ^^^^^^^^^ ambiguous link | -help: to link to the module, prefix with the item type +help: to link to the module, prefix with `mod@` | -LL | /// [module@char] - | ^^^^^^^^^^^ -help: to link to the builtin type, prefix with the item type +LL | /// [mod@char] + | ^^^^^^^^ +help: to link to the builtin type, prefix with `prim@` | LL | /// [prim@char] | ^^^^^^^^^ @@ -37,7 +37,7 @@ error: incompatible link kind for `char` --> $DIR/intra-link-prim-conflict.rs:19:6 | LL | /// [struct@char] - | ^^^^^^^^^^^ help: to link to the module, use its disambiguator: `mod@char` + | ^^^^^^^^^^^ help: to link to the module, prefix with `mod@`: `mod@char` | = note: this link resolved to a module, which is not a struct @@ -45,7 +45,7 @@ error: incompatible link kind for `char` --> $DIR/intra-link-prim-conflict.rs:26:10 | LL | //! [struct@char] - | ^^^^^^^^^^^ help: to link to the builtin type, use its disambiguator: `prim@char` + | ^^^^^^^^^^^ help: to link to the builtin type, prefix with `prim@`: `prim@char` | = note: this link resolved to a builtin type, which is not a struct diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index 6b0ff8f116..d946aa9398 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -2,7 +2,7 @@ error: unresolved link to `i` --> $DIR/intra-link-span-ice-55723.rs:9:10 | LL | /// (arr[i]) - | ^ unresolved link + | ^ the module `intra_link_span_ice_55723` contains no item named `i` | note: the lint level is defined here --> $DIR/intra-link-span-ice-55723.rs:1:9 diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr index 35262c1b61..17891ca05e 100644 --- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the struct, prefix with the item type +help: to link to the struct, prefix with `struct@` | LL | /// [`struct@ambiguous`] is ambiguous. | ^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ error: `ambiguous` is both a struct and a function LL | /// [ambiguous] is ambiguous. | ^^^^^^^^^ ambiguous link | -help: to link to the struct, prefix with the item type +help: to link to the struct, prefix with `struct@` | LL | /// [struct@ambiguous] is ambiguous. | ^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ error: `multi_conflict` is a struct, a function, and a macro LL | /// [`multi_conflict`] is a three-way conflict. | ^^^^^^^^^^^^^^^^ ambiguous link | -help: to link to the struct, prefix with the item type +help: to link to the struct, prefix with `struct@` | LL | /// [`struct@multi_conflict`] is a three-way conflict. | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,11 +58,11 @@ error: `type_and_value` is both a module and a constant LL | /// Ambiguous [type_and_value]. | ^^^^^^^^^^^^^^ ambiguous link | -help: to link to the module, prefix with the item type +help: to link to the module, prefix with `mod@` | -LL | /// Ambiguous [module@type_and_value]. - | ^^^^^^^^^^^^^^^^^^^^^ -help: to link to the constant, prefix with the item type +LL | /// Ambiguous [mod@type_and_value]. + | ^^^^^^^^^^^^^^^^^^ +help: to link to the constant, prefix with `const@` | LL | /// Ambiguous [const@type_and_value]. | ^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ error: `foo::bar` is both an enum and a function LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. | ^^^^^^^^^^ ambiguous link | -help: to link to the enum, prefix with the item type +help: to link to the enum, prefix with `enum@` | LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`]. | ^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/intra-links-anchors.stderr b/src/test/rustdoc-ui/intra-links-anchors.stderr index e737b84320..1825a4ad1f 100644 --- a/src/test/rustdoc-ui/intra-links-anchors.stderr +++ b/src/test/rustdoc-ui/intra-links-anchors.stderr @@ -1,4 +1,4 @@ -error: `Foo::f#hola` contains an anchor, but links to struct fields are already anchored +error: `Foo::f#hola` contains an anchor, but links to fields are already anchored --> $DIR/intra-links-anchors.rs:25:15 | LL | /// Or maybe [Foo::f#hola]. @@ -16,13 +16,13 @@ error: `hello#people#!` contains multiple anchors LL | /// Another anchor error: [hello#people#!]. | ^^^^^^^^^^^^^^ contains invalid anchor -error: `Enum::A#whatever` contains an anchor, but links to enum variants are already anchored +error: `Enum::A#whatever` contains an anchor, but links to variants are already anchored --> $DIR/intra-links-anchors.rs:37:28 | LL | /// Damn enum's variants: [Enum::A#whatever]. | ^^^^^^^^^^^^^^^^ contains invalid anchor -error: `u32#hello` contains an anchor, but links to primitive types are already anchored +error: `u32#hello` contains an anchor, but links to builtin types are already anchored --> $DIR/intra-links-anchors.rs:43:6 | LL | /// [u32#hello] diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs index 1a7a2fce7a..b9c8e033b1 100644 --- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs @@ -14,55 +14,55 @@ trait T {} /// Link to [struct@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `enum@` /// Link to [mod@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `enum@` /// Link to [union@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `enum@` /// Link to [trait@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `enum@` /// Link to [struct@T] //~^ ERROR incompatible link kind for `T` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `trait@` /// Link to [derive@m] //~^ ERROR incompatible link kind for `m` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP add an exclamation mark /// Link to [const@s] //~^ ERROR incompatible link kind for `s` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `static@` /// Link to [static@c] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `const@` /// Link to [fn@c] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `const@` /// Link to [c()] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `const@` /// Link to [const@f] //~^ ERROR incompatible link kind for `f` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP add parentheses pub fn f() {} diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr index 9edf838f9d..2e732baf6e 100644 --- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr @@ -2,7 +2,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:14:14 | LL | /// Link to [struct@S] - | ^^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | ^^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | note: the lint level is defined here --> $DIR/intra-links-disambiguator-mismatch.rs:1:9 @@ -15,7 +15,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:19:14 | LL | /// Link to [mod@S] - | ^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | ^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a module @@ -23,7 +23,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:24:14 | LL | /// Link to [union@S] - | ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a union @@ -31,7 +31,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:29:14 | LL | /// Link to [trait@S] - | ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a trait @@ -39,7 +39,7 @@ error: incompatible link kind for `T` --> $DIR/intra-links-disambiguator-mismatch.rs:34:14 | LL | /// Link to [struct@T] - | ^^^^^^^^ help: to link to the trait, use its disambiguator: `trait@T` + | ^^^^^^^^ help: to link to the trait, prefix with `trait@`: `trait@T` | = note: this link resolved to a trait, which is not a struct @@ -47,7 +47,7 @@ error: incompatible link kind for `m` --> $DIR/intra-links-disambiguator-mismatch.rs:39:14 | LL | /// Link to [derive@m] - | ^^^^^^^^ help: to link to the macro, use its disambiguator: `m!` + | ^^^^^^^^ help: to link to the macro, add an exclamation mark: `m!` | = note: this link resolved to a macro, which is not a derive macro @@ -55,7 +55,7 @@ error: incompatible link kind for `s` --> $DIR/intra-links-disambiguator-mismatch.rs:44:14 | LL | /// Link to [const@s] - | ^^^^^^^ help: to link to the static, use its disambiguator: `static@s` + | ^^^^^^^ help: to link to the static, prefix with `static@`: `static@s` | = note: this link resolved to a static, which is not a constant @@ -63,7 +63,7 @@ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:49:14 | LL | /// Link to [static@c] - | ^^^^^^^^ help: to link to the constant, use its disambiguator: `const@c` + | ^^^^^^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a static @@ -71,7 +71,7 @@ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:54:14 | LL | /// Link to [fn@c] - | ^^^^ help: to link to the constant, use its disambiguator: `const@c` + | ^^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a function @@ -79,7 +79,7 @@ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:59:14 | LL | /// Link to [c()] - | ^^^ help: to link to the constant, use its disambiguator: `const@c` + | ^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a function @@ -87,7 +87,7 @@ error: incompatible link kind for `f` --> $DIR/intra-links-disambiguator-mismatch.rs:64:14 | LL | /// Link to [const@f] - | ^^^^^^^ help: to link to the function, use its disambiguator: `f()` + | ^^^^^^^ help: to link to the function, add parentheses: `f()` | = note: this link resolved to a function, which is not a constant diff --git a/src/test/rustdoc-ui/intra-links-private.private.stderr b/src/test/rustdoc-ui/intra-links-private.private.stderr index 77c4b67a65..eeef24b479 100644 --- a/src/test/rustdoc-ui/intra-links-private.private.stderr +++ b/src/test/rustdoc-ui/intra-links-private.private.stderr @@ -4,7 +4,7 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` LL | /// docs [DontDocMe] | ^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link resolves only because you passed `--document-private-items`, but will break without warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/intra-links-private.public.stderr b/src/test/rustdoc-ui/intra-links-private.public.stderr index 312a78e8c3..3f7b17586f 100644 --- a/src/test/rustdoc-ui/intra-links-private.public.stderr +++ b/src/test/rustdoc-ui/intra-links-private.public.stderr @@ -4,7 +4,7 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` LL | /// docs [DontDocMe] | ^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link will resolve properly if you pass `--document-private-items` warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index 1e3a26fadf..76a2ac0c8c 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -2,7 +2,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:7:6 | LL | /// [error] - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning_crlf` contains no item named `error` | = note: `#[warn(broken_intra_doc_links)]` on by default = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -11,7 +11,7 @@ warning: unresolved link to `error1` --> $DIR/intra-links-warning-crlf.rs:12:11 | LL | /// docs [error1] - | ^^^^^^ unresolved link + | ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error1` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -19,7 +19,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning-crlf.rs:15:11 | LL | /// docs [error2] - | ^^^^^^ unresolved link + | ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error2` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -27,7 +27,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:23:20 | LL | * It also has an [error]. - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning_crlf` contains no item named `error` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 53f2476295..09db465df5 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -2,56 +2,45 @@ warning: unresolved link to `Foo::baz` --> $DIR/intra-links-warning.rs:3:23 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ unresolved link + | ^^^^^^^^ the struct `Foo` has no field or associated item named `baz` | = note: `#[warn(broken_intra_doc_links)]` on by default - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^^^ the module `intra_links_warning` contains no item named `Bar` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^ the module `intra_links_warning` contains no item named `Qux` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^ the module `intra_links_warning` contains no item named `Qux` warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 | LL | /// [Qux:Y] - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning` contains no item named `Qux:Y` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -59,7 +48,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 | LL | * time to introduce a link [error]*/ - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning` contains no item named `error` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -67,7 +56,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:64:30 | LL | * time to introduce a link [error] - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning` contains no item named `error` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -81,6 +70,7 @@ LL | #[doc = "single line [error]"] single line [error] ^^^^^ + = note: the module `intra_links_warning` contains no item named `error` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -93,6 +83,7 @@ LL | #[doc = "single line with \"escaping\" [error]"] single line with "escaping" [error] ^^^^^ + = note: the module `intra_links_warning` contains no item named `error` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -107,13 +98,14 @@ LL | | /// [error] [error] ^^^^^ + = note: the module `intra_links_warning` contains no item named `error` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` --> $DIR/intra-links-warning.rs:80:11 | LL | /// docs [error1] - | ^^^^^^ unresolved link + | ^^^^^^ the module `intra_links_warning` contains no item named `error1` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -121,7 +113,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning.rs:82:11 | LL | /// docs [error2] - | ^^^^^^ unresolved link + | ^^^^^^ the module `intra_links_warning` contains no item named `error2` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -129,7 +121,7 @@ warning: unresolved link to `BarA` --> $DIR/intra-links-warning.rs:21:10 | LL | /// bar [BarA] bar - | ^^^^ unresolved link + | ^^^^ the module `intra_links_warning` contains no item named `BarA` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -137,7 +129,7 @@ warning: unresolved link to `BarB` --> $DIR/intra-links-warning.rs:27:9 | LL | * bar [BarB] bar - | ^^^^ unresolved link + | ^^^^ the module `intra_links_warning` contains no item named `BarB` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -145,7 +137,7 @@ warning: unresolved link to `BarC` --> $DIR/intra-links-warning.rs:34:6 | LL | bar [BarC] bar - | ^^^^ unresolved link + | ^^^^ the module `intra_links_warning` contains no item named `BarC` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -159,6 +151,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] bar [BarD] bar ^^^^ + = note: the module `intra_links_warning` contains no item named `BarD` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarF` @@ -174,6 +167,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); bar [BarF] bar ^^^^ + = note: the module `intra_links_warning` contains no item named `BarF` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/rustdoc-ui/issue-74134.private.stderr b/src/test/rustdoc-ui/issue-74134.private.stderr index 5877210914..b802d7e125 100644 --- a/src/test/rustdoc-ui/issue-74134.private.stderr +++ b/src/test/rustdoc-ui/issue-74134.private.stderr @@ -4,7 +4,7 @@ warning: public documentation for `public_item` links to private item `PrivateTy LL | /// [`PrivateType`] | ^^^^^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link resolves only because you passed `--document-private-items`, but will break without warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr index b5bea19094..40aa2ece1a 100644 --- a/src/test/rustdoc-ui/issue-74134.public.stderr +++ b/src/test/rustdoc-ui/issue-74134.public.stderr @@ -4,7 +4,7 @@ warning: public documentation for `public_item` links to private item `PrivateTy LL | /// [`PrivateType`] | ^^^^^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link will resolve properly if you pass `--document-private-items` warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 04296d2e44..4e9134ea46 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -32,7 +32,7 @@ error: unresolved link to `error` --> $DIR/lint-group.rs:9:29 | LL | /// what up, let's make an [error] - | ^^^^^ unresolved link + | ^^^^^ the module `lint_group` contains no item named `error` | note: the lint level is defined here --> $DIR/lint-group.rs:7:9 diff --git a/src/test/rustdoc-ui/private-doc-test.rs b/src/test/rustdoc-ui/private-doc-test.rs new file mode 100644 index 0000000000..379fa45f9f --- /dev/null +++ b/src/test/rustdoc-ui/private-doc-test.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(private_doc_tests)] + +mod foo { + /// private doc test + /// + /// ```ignore (used for testing ignored doc tests) + /// assert!(false); + /// ``` + fn bar() {} +} diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.rs b/src/test/rustdoc-ui/unknown-renamed-lints.rs new file mode 100644 index 0000000000..7faa82ea42 --- /dev/null +++ b/src/test/rustdoc-ui/unknown-renamed-lints.rs @@ -0,0 +1,8 @@ +#![deny(unknown_lints)] +//~^ NOTE lint level is defined +#![deny(renamed_and_removed_lints)] +//~^ NOTE lint level is defined +#![deny(x)] +//~^ ERROR unknown lint +#![deny(intra_doc_link_resolution_failure)] +//~^ ERROR lint `intra_doc_link_resolution_failure` has been renamed diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.stderr b/src/test/rustdoc-ui/unknown-renamed-lints.stderr new file mode 100644 index 0000000000..f0917f194b --- /dev/null +++ b/src/test/rustdoc-ui/unknown-renamed-lints.stderr @@ -0,0 +1,28 @@ +error: unknown lint: `x` + --> $DIR/unknown-renamed-lints.rs:5:9 + | +LL | #![deny(x)] + | ^ + | +note: the lint level is defined here + --> $DIR/unknown-renamed-lints.rs:1:9 + | +LL | #![deny(unknown_lints)] + | ^^^^^^^^^^^^^ + +error: lint `intra_doc_link_resolution_failure` has been renamed to `broken_intra_doc_links` + --> $DIR/unknown-renamed-lints.rs:7:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `broken_intra_doc_links` + | +note: the lint level is defined here + --> $DIR/unknown-renamed-lints.rs:3:9 + | +LL | #![deny(renamed_and_removed_lints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Compilation failed, aborting rustdoc + +error: aborting due to 3 previous errors + diff --git a/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs b/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs new file mode 100644 index 0000000000..a37848e23d --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs @@ -0,0 +1,5 @@ +#![crate_name = "inner"] + +/// Links to [crate::g] +pub fn f() {} +pub fn g() {} diff --git a/src/test/rustdoc/auxiliary/intra-link-pub-use.rs b/src/test/rustdoc/auxiliary/intra-link-pub-use.rs new file mode 100644 index 0000000000..a4db2ffc44 --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-link-pub-use.rs @@ -0,0 +1,4 @@ +#![crate_name = "inner"] + +/// Documentation, including a link to [std::ptr] +pub fn f() {} diff --git a/src/test/rustdoc/bad-codeblock-syntax.rs b/src/test/rustdoc/bad-codeblock-syntax.rs index afef86ec9c..920877028d 100644 --- a/src/test/rustdoc/bad-codeblock-syntax.rs +++ b/src/test/rustdoc/bad-codeblock-syntax.rs @@ -1,33 +1,33 @@ // @has bad_codeblock_syntax/fn.foo.html -// @has - '//*[@class="docblock"]/pre/code' '\_' +// @has - '//*[@class="docblock"]' '\_' /// ``` /// \_ /// ``` pub fn foo() {} // @has bad_codeblock_syntax/fn.bar.html -// @has - '//*[@class="docblock"]/pre/code' '`baz::foobar`' +// @has - '//*[@class="docblock"]' '`baz::foobar`' /// ``` /// `baz::foobar` /// ``` pub fn bar() {} // @has bad_codeblock_syntax/fn.quux.html -// @has - '//*[@class="docblock"]/pre/code' '\_' +// @has - '//*[@class="docblock"]' '\_' /// ```rust /// \_ /// ``` pub fn quux() {} // @has bad_codeblock_syntax/fn.ok.html -// @has - '//*[@class="docblock"]/pre/code[@class="language-text"]' '\_' +// @has - '//*[@class="docblock"]' '\_' /// ```text /// \_ /// ``` pub fn ok() {} // @has bad_codeblock_syntax/fn.escape.html -// @has - '//*[@class="docblock"]/pre/code' '\_ ' +// @has - '//*[@class="docblock"]' '\_ ' /// ``` /// \_ /// @@ -35,7 +35,7 @@ pub fn ok() {} pub fn escape() {} // @has bad_codeblock_syntax/fn.unterminated.html -// @has - '//*[@class="docblock"]/pre/code' '"unterminated' +// @has - '//*[@class="docblock"]' '"unterminated' /// ``` /// "unterminated /// ``` diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index c5016c650e..b3fbe377f0 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -12,7 +12,7 @@ #[rustc_const_unstable(feature="foo", issue = "none")] pub const unsafe fn foo() -> u32 { 42 } -// @has 'foo/fn.foo2.html' '//pre' 'pub fn foo2() -> u32' +// @has 'foo/fn.foo2.html' '//pre' 'pub const fn foo2() -> u32' #[unstable(feature = "humans", issue = "none")] pub const fn foo2() -> u32 { 42 } @@ -21,7 +21,7 @@ pub const fn foo2() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn bar2() -> u32 { 42 } -// @has 'foo/fn.foo2_gated.html' '//pre' 'pub unsafe fn foo2_gated() -> u32' +// @has 'foo/fn.foo2_gated.html' '//pre' 'pub const unsafe fn foo2_gated() -> u32' #[unstable(feature = "foo2", issue = "none")] pub const unsafe fn foo2_gated() -> u32 { 42 } @@ -30,7 +30,7 @@ pub const unsafe fn foo2_gated() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const unsafe fn bar2_gated() -> u32 { 42 } -// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub unsafe fn bar_not_gated() -> u32' +// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32' pub const unsafe fn bar_not_gated() -> u32 { 42 } pub struct Foo; diff --git a/src/test/rustdoc/const-generics/type-alias.rs b/src/test/rustdoc/const-generics/type-alias.rs new file mode 100644 index 0000000000..3064d0701e --- /dev/null +++ b/src/test/rustdoc/const-generics/type-alias.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength +#![feature(min_const_generics)] +#![crate_name = "foo"] + +// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex = [i64; D];' +pub type CellIndex = [i64; D]; diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs index 9ccc5d7882..47ba362c97 100644 --- a/src/test/rustdoc/duplicate-cfg.rs +++ b/src/test/rustdoc/duplicate-cfg.rs @@ -3,22 +3,34 @@ #![crate_name = "foo"] #![feature(doc_cfg)] +// @has 'foo/index.html' +// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$' +// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only' + // @has 'foo/struct.Foo.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.' +// @has '-' '//*[@class="stab portability"]' 'sync' #[doc(cfg(feature = "sync"))] #[doc(cfg(feature = "sync"))] pub struct Foo; +// @has 'foo/bar/index.html' +// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$' +// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only' + // @has 'foo/bar/struct.Bar.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub mod bar { #[doc(cfg(feature = "sync"))] pub struct Bar; } +// @has 'foo/baz/index.html' +// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send$' +// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate features `sync` and `send` only' + // @has 'foo/baz/struct.Baz.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(all(feature = "sync", feature = "send")))] pub mod baz { #[doc(cfg(feature = "sync"))] @@ -26,15 +38,19 @@ pub mod baz { } // @has 'foo/qux/struct.Qux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(feature = "sync"))] pub mod qux { #[doc(cfg(all(feature = "sync", feature = "send")))] pub struct Qux; } +// @has 'foo/quux/index.html' +// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send and foo and bar$' +// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` and crate feature `send` and `foo` and `bar` only' + // @has 'foo/quux/struct.Quux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" and foo and bar only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.' #[doc(cfg(all(feature = "sync", feature = "send", foo)))] pub mod quux { #[doc(cfg(all(feature = "send", feature = "sync", bar)))] diff --git a/src/test/rustdoc/index-page.rs b/src/test/rustdoc/index-page.rs index f0476f083b..be668a1276 100644 --- a/src/test/rustdoc/index-page.rs +++ b/src/test/rustdoc/index-page.rs @@ -6,6 +6,6 @@ // @has foo/../index.html // @has - '//span[@class="in-band"]' 'List of all crates' -// @has - '//ul[@class="mod"]//a[@href="foo/index.html"]' 'foo' -// @has - '//ul[@class="mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' +// @has - '//ul[@class="crate mod"]//a[@href="foo/index.html"]' 'foo' +// @has - '//ul[@class="crate mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' pub struct Foo; diff --git a/src/test/rustdoc/intra-doc-crate/traits.rs b/src/test/rustdoc/intra-doc-crate/traits.rs index 07f9fb6331..07decb4801 100644 --- a/src/test/rustdoc/intra-doc-crate/traits.rs +++ b/src/test/rustdoc/intra-doc-crate/traits.rs @@ -1,5 +1,3 @@ -// ignore-test -// ^ this is https://github.com/rust-lang/rust/issues/73829 // aux-build:traits.rs // build-aux-docs // ignore-tidy-line-length diff --git a/src/test/rustdoc/intra-doc-link-private.rs b/src/test/rustdoc/intra-doc-link-private.rs new file mode 100644 index 0000000000..f86ca44403 --- /dev/null +++ b/src/test/rustdoc/intra-doc-link-private.rs @@ -0,0 +1,6 @@ +#![crate_name = "private"] +// compile-flags: --document-private-items +/// docs [DontDocMe] +// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html"]' 'DontDocMe' +pub struct DocMe; +struct DontDocMe; diff --git a/src/test/rustdoc/intra-link-associated-items.rs b/src/test/rustdoc/intra-link-associated-items.rs index 16a21e3374..daf7075a91 100644 --- a/src/test/rustdoc/intra-link-associated-items.rs +++ b/src/test/rustdoc/intra-link-associated-items.rs @@ -3,8 +3,10 @@ /// [`std::collections::BTreeMap::into_iter`] /// [`String::from`] is ambiguous as to which `From` impl +/// [Vec::into_iter()] uses a disambiguator // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter' // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from' +// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter' pub fn foo() {} /// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input] diff --git a/src/test/rustdoc/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-link-cross-crate-crate.rs new file mode 100644 index 0000000000..edf544708b --- /dev/null +++ b/src/test/rustdoc/intra-link-cross-crate-crate.rs @@ -0,0 +1,6 @@ +// aux-build:intra-link-cross-crate-crate.rs +// build-aux-docs +#![crate_name = "outer"] +extern crate inner; +// @has outer/fn.f.html '//a[@href="../inner/fn.g.html"]' "crate::g" +pub use inner::f; diff --git a/src/test/rustdoc/intra-link-disambiguators-removed.rs b/src/test/rustdoc/intra-link-disambiguators-removed.rs new file mode 100644 index 0000000000..26d05b484b --- /dev/null +++ b/src/test/rustdoc/intra-link-disambiguators-removed.rs @@ -0,0 +1,51 @@ +// ignore-tidy-linelength +#![deny(intra_doc_link_resolution_failure)] +// first try backticks +/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`] +// @has intra_link_disambiguators_removed/struct.AtDisambiguator.html +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"][code]' "Name" +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name" +pub struct AtDisambiguator; + +/// fn: [`Name()`], macro: [`Name!`] +// @has intra_link_disambiguators_removed/struct.SymbolDisambiguator.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name()" +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name!" +pub struct SymbolDisambiguator; + +// Now make sure that backticks aren't added if they weren't already there +/// [fn@Name] +// @has intra_link_disambiguators_removed/trait.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "Name" +// @!has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" + +// FIXME: this will turn !() into ! alone +/// [Name!()] +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name!" +pub trait Name {} + +#[allow(non_snake_case)] + +// Try collapsed reference links +/// [macro@Name][] +// @has intra_link_disambiguators_removed/fn.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name" + +// Try links that have the same text as a generated URL +/// Weird URL aligned [../intra_link_disambiguators_removed/macro.Name.html][trait@Name] +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "../intra_link_disambiguators_removed/macro.Name.html" +pub fn Name() {} + +#[macro_export] +// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks. +/// [fn@Na`m`e] +// @has intra_link_disambiguators_removed/macro.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "fn@Name" + +// It also doesn't handle any case where the code block isn't the whole link text: +/// [trait@`Name`] +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "trait@Name" +macro_rules! Name { + () => () +} diff --git a/src/test/rustdoc/intra-link-prim-assoc.rs b/src/test/rustdoc/intra-link-prim-assoc.rs new file mode 100644 index 0000000000..c0066885e1 --- /dev/null +++ b/src/test/rustdoc/intra-link-prim-assoc.rs @@ -0,0 +1,5 @@ +// ignore-tidy-linelength +#![deny(broken_intra_doc_links)] + +//! [i32::MAX] +// @has intra_link_prim_assoc/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX" diff --git a/src/test/rustdoc/intra-link-pub-use.rs b/src/test/rustdoc/intra-link-pub-use.rs new file mode 100644 index 0000000000..dd52249abc --- /dev/null +++ b/src/test/rustdoc/intra-link-pub-use.rs @@ -0,0 +1,27 @@ +// aux-build: intra-link-pub-use.rs +#![deny(broken_intra_doc_links)] +#![crate_name = "outer"] + +extern crate inner; + +/// [mod@std::env] [g] + +// FIXME: This can't be tested because rustdoc doesn't show documentation on pub re-exports. +// Until then, comment out the `htmldocck` test. +// This test still does something; namely check that no incorrect errors are emitted when +// documenting the re-export. + +// @has outer/index.html +// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env" +// @ has - '//a[@href="../outer/fn.f.html"]' "g" +pub use f as g; + +// FIXME: same as above +/// [std::env] +extern crate self as _; + +// Make sure the documentation is actually correct by documenting an inlined re-export +/// [mod@std::env] +// @has outer/fn.f.html +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/index.html"]' "std::env" +pub use inner::f; diff --git a/src/test/rustdoc/issue-76501.rs b/src/test/rustdoc/issue-76501.rs new file mode 100644 index 0000000000..605059fe0d --- /dev/null +++ b/src/test/rustdoc/issue-76501.rs @@ -0,0 +1,18 @@ +#![feature(const_fn)] + +// @has 'issue_76501/fn.bloop.html' '//pre' 'pub const fn bloop() -> i32' +/// A useless function that always returns 1. +pub const fn bloop() -> i32 { + 1 +} + +/// A struct. +pub struct Struct {} + +impl Struct { + // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn blurp() -> i32' + /// A useless function that always returns 1. + pub const fn blurp() -> i32 { + 1 + } +} diff --git a/src/test/rustdoc/plain-text-summaries.rs b/src/test/rustdoc/plain-text-summaries.rs new file mode 100644 index 0000000000..c995ccbf0a --- /dev/null +++ b/src/test/rustdoc/plain-text-summaries.rs @@ -0,0 +1,26 @@ +#![crate_type = "lib"] +#![crate_name = "summaries"] + +//! This summary has a [link] and `code`. +//! +//! This is the second paragraph. +//! +//! [link]: https://example.com + +// @has search-index.js 'This summary has a link and `code`.' +// @!has - 'second paragraph' + +/// This `code` should be in backticks. +/// +/// This text should not be rendered. +pub struct Sidebar; + +// @has summaries/sidebar-items.js 'This `code` should be in backticks.' +// @!has - 'text should not be rendered' + +/// ```text +/// this block should not be rendered +/// ``` +pub struct Sidebar2; + +// @!has summaries/sidebar-items.js 'block should not be rendered' diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs index 819ef05174..8f69b894a2 100644 --- a/src/test/rustdoc/primitive-link.rs +++ b/src/test/rustdoc/primitive-link.rs @@ -4,6 +4,13 @@ // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32' // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str' + +// FIXME: this doesn't resolve +// @ has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX' /// It contains [`u32`] and [i64]. +/// It also links to [std::primitive::i32], [std::primitive::str], +/// and [`std::primitive::i32::MAX`]. pub struct Foo; diff --git a/src/test/rustdoc/trait-impl.rs b/src/test/rustdoc/trait-impl.rs new file mode 100644 index 0000000000..3bcaa3bb67 --- /dev/null +++ b/src/test/rustdoc/trait-impl.rs @@ -0,0 +1,46 @@ +pub trait Trait { + /// Some long docs here. + /// + /// These docs are long enough that a link will be added to the end. + fn a(); + + /// These docs contain a [reference link]. + /// + /// [reference link]: https://example.com + fn b(); + + /// ``` + /// This code block should not be in the output, but a Read more link should be generated + /// ``` + fn c(); + + /// Escaped formatting a\*b\*c\* works + fn d(); +} + +pub struct Struct; + +impl Trait for Struct { + // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../div/p' 'Some long docs' + // @!has - '//*[@id="method.a"]/../div/p' 'link will be added' + // @has - '//*[@id="method.a"]/../div/p/a' 'Read more' + // @has - '//*[@id="method.a"]/../div/p/a/@href' 'trait.Trait.html' + fn a() {} + + // @has trait_impl/struct.Struct.html '//*[@id="method.b"]/../div/p' 'These docs contain' + // @has - '//*[@id="method.b"]/../div/p/a' 'reference link' + // @has - '//*[@id="method.b"]/../div/p/a/@href' 'https://example.com' + // @has - '//*[@id="method.b"]/../div/p/a' 'Read more' + // @has - '//*[@id="method.b"]/../div/p/a/@href' 'trait.Trait.html' + fn b() {} + + // @!has trait_impl/struct.Struct.html '//*[@id="method.c"]/../div/p' 'code block' + // @has - '//*[@id="method.c"]/../div/p/a' 'Read more' + // @has - '//*[@id="method.c"]/../div/p/a/@href' 'trait.Trait.html' + fn c() {} + + // @has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p' \ + // 'Escaped formatting a*b*c* works' + // @!has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p/em' + fn d() {} +} diff --git a/src/test/ui-fulldeps/auxiliary/proc-macro-panic.rs b/src/test/ui-fulldeps/auxiliary/proc-macro-panic.rs new file mode 100644 index 0000000000..fc15bb9c59 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/proc-macro-panic.rs @@ -0,0 +1,13 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::{TokenStream, Ident, Span}; + +#[proc_macro] +pub fn panic_in_libproc_macro(_: TokenStream) -> TokenStream { + Ident::new("", Span::call_site()); + TokenStream::new() +} diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs index e97dcab6ae..0025b47403 100644 --- a/src/test/ui-fulldeps/compiler-calls.rs +++ b/src/test/ui-fulldeps/compiler-calls.rs @@ -26,7 +26,13 @@ fn main() { let mut count = 1; let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; rustc_driver::catch_fatal_errors(|| { - rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok(); + rustc_driver::run_compiler( + &args, + &mut TestCalls { count: &mut count }, + None, + None, + None, + ).ok(); }).ok(); assert_eq!(count, 2); } diff --git a/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr b/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr index 98c1a22bd1..4299688221 100644 --- a/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr +++ b/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr @@ -7,7 +7,7 @@ LL | } | - | | | `arena` dropped here while still borrowed - | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `rustc_arena::TypedArena` + | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `TypedArena` error: aborting due to previous error diff --git a/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr index 22c7487e8f..ccffee9cdb 100644 --- a/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr +++ b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr @@ -7,7 +7,7 @@ LL | } | - | | | `arena` dropped here while still borrowed - | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `rustc_arena::TypedArena` + | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `TypedArena` error: aborting due to previous error diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs new file mode 100644 index 0000000000..f58446d559 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs @@ -0,0 +1,33 @@ +// NOTE: This test doesn't actually require `fulldeps` +// so we could instead use it as an `ui` test. +// +// Considering that all other `internal-lints` are tested here +// this seems like the cleaner solution though. +#![feature(rustc_attrs)] +#![deny(rustc::ty_pass_by_reference)] +#![allow(unused)] + +#[rustc_diagnostic_item = "TyCtxt"] +struct TyCtxt<'tcx> { + inner: &'tcx (), +} + +impl<'tcx> TyCtxt<'tcx> { + fn by_value(self) {} // OK + fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference +} + + +struct TyS<'tcx> { + inner: &'tcx (), +} + +#[rustc_diagnostic_item = "Ty"] +type Ty<'tcx> = &'tcx TyS<'tcx>; + +impl<'tcx> TyS<'tcx> { + fn by_value(self: Ty<'tcx>) {} + fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference +} + +fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr new file mode 100644 index 0000000000..b846b30f4e --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr @@ -0,0 +1,20 @@ +error: passing `TyCtxt<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:17:15 + | +LL | fn by_ref(&self) {} + | ^^^^^ help: try passing by value: `TyCtxt<'tcx>` + | +note: the lint level is defined here + --> $DIR/pass_ty_by_ref_self.rs:7:9 + | +LL | #![deny(rustc::ty_pass_by_reference)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: passing `Ty<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:30:21 + | +LL | fn by_ref(self: &Ty<'tcx>) {} + | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.rs b/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.rs new file mode 100644 index 0000000000..981abb4e2c --- /dev/null +++ b/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.rs @@ -0,0 +1,17 @@ +// aux-build:proc-macro-panic.rs +// edition:2018 +// ignore-stage1 +// only-linux +// +// FIXME: This should be a normal (stage1, all platforms) test in +// src/test/ui/proc-macro once issue #59998 is fixed. + +// Regression test for issue #76270 +// Tests that we don't print an ICE message when a panic +// occurs in libproc-macro (when `-Z proc-macro-backtrace` is not specified) + +extern crate proc_macro_panic; + +proc_macro_panic::panic_in_libproc_macro!(); //~ ERROR proc macro panicked + +fn main() {} diff --git a/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr b/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr new file mode 100644 index 0000000000..e472242ce4 --- /dev/null +++ b/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/issue-76270-panic-in-libproc-macro.rs:15:1 + | +LL | proc_macro_panic::panic_in_libproc_macro!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: message: `""` is not a valid identifier + +error: aborting due to previous error + diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 633d153e39..caf55bec53 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -62,7 +62,7 @@ fn expr(kind: ExprKind) -> P { fn make_x() -> P { let seg = PathSegment::from_ident(Ident::from_str("x")); - let path = Path { segments: vec![seg], span: DUMMY_SP }; + let path = Path { segments: vec![seg], span: DUMMY_SP, tokens: None }; expr(ExprKind::Path(None, path)) } @@ -113,6 +113,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { id: DUMMY_NODE_ID, rules: BlockCheckMode::Default, span: DUMMY_SP, + tokens: None, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); }, diff --git a/src/test/ui-fulldeps/session-derive-errors.rs b/src/test/ui-fulldeps/session-derive-errors.rs new file mode 100644 index 0000000000..7967b32a4a --- /dev/null +++ b/src/test/ui-fulldeps/session-derive-errors.rs @@ -0,0 +1,260 @@ +// check-fail +// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)] + +#![feature(rustc_private)] +#![crate_type = "lib"] + +extern crate rustc_span; +use rustc_span::Span; +use rustc_span::symbol::Ident; + +extern crate rustc_macros; +use rustc_macros::SessionDiagnostic; + +extern crate rustc_middle; +use rustc_middle::ty::Ty; + +extern crate rustc_errors; +use rustc_errors::Applicability; + +extern crate rustc_session; + +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[error = "E0123"] +struct Hello {} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +//~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs +enum SessionDiagnosticOnEnum { + Foo, + Bar, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[label = "This is in the wrong place"] +//~^ ERROR `#[label = ...]` is not a valid SessionDiagnostic struct attribute +struct WrongPlace {} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct WrongPlaceField { + #[suggestion = "this is the wrong kind of attribute"] +//~^ ERROR `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute + sp: Span, +} + +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[error = "E0123"] +#[error = "E0456"] //~ ERROR `error` specified multiple times +struct ErrorSpecifiedTwice {} + +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[error = "E0123"] +#[lint = "some_useful_lint"] //~ ERROR `lint` specified when `error` was already specified +struct LintSpecifiedAfterError {} + +#[derive(SessionDiagnostic)] +#[message = "Some lint message"] +#[error = "E0123"] +struct LintButHasErrorCode {} + +#[derive(SessionDiagnostic)] +struct ErrorCodeNotProvided {} //~ ERROR `code` not specified + +// FIXME: Uncomment when emitting lints is supported. +/* +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[lint = "clashing_extern_declarations"] +#[lint = "improper_ctypes"] // FIXME: ERROR `lint` specified multiple times +struct LintSpecifiedTwice {} + +#[derive(SessionDiagnostic)] +#[lint = "Some lint message"] +#[message = "Some error message"] +#[error = "E0123"] // ERROR `error` specified when `lint` was already specified +struct ErrorSpecifiedAfterLint {} +*/ + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct ErrorWithField { + name: String, + #[message = "This error has a field, and references {name}"] + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct ErrorWithMessageAppliedToField { + #[message = "this message is applied to a String field"] + //~^ ERROR the `#[message = "..."]` attribute can only be applied to fields of type Span + name: String, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "This error has a field, and references {name}"] +//~^ ERROR `name` doesn't refer to a field on this type +struct ErrorWithNonexistentField { + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "This is missing a closing brace: {name"] +//~^ ERROR invalid format string: expected `'}'` +struct ErrorMissingClosingBrace { + name: String, + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "This is missing an opening brace: name}"] +//~^ ERROR invalid format string: unmatched `}` +struct ErrorMissingOpeningBrace { + name: String, + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "Something something"] +struct LabelOnSpan { + #[label = "See here"] + sp: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "Something something"] +struct LabelOnNonSpan { + #[label = "See here"] + //~^ ERROR The `#[label = ...]` attribute can only be applied to fields of type Span + id: u32, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct Suggest { + #[suggestion(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion_short(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion_hidden(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion_verbose(message = "This is a suggestion", code = "This is the suggested code")] + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithoutCode { + #[suggestion(message = "This is a suggestion")] + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithBadKey { + #[suggestion(nonsense = "This is nonsense")] + //~^ ERROR `nonsense` is not a valid key for `#[suggestion(...)]` + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithShorthandMsg { + #[suggestion(msg = "This is a suggestion")] + //~^ ERROR `msg` is not a valid key for `#[suggestion(...)]` + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithoutMsg { + #[suggestion(code = "This is suggested code")] + //~^ ERROR missing suggestion message + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithTypesSwapped { + #[suggestion(message = "This is a message", code = "This is suggested code")] + suggestion: (Applicability, Span), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithWrongTypeApplicabilityOnly { + #[suggestion(message = "This is a message", code = "This is suggested code")] + //~^ ERROR wrong field type for suggestion + suggestion: Applicability, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithSpanOnly{ + #[suggestion(message = "This is a message", code = "This is suggested code")] + suggestion: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithDuplicateSpanAndApplicability { + #[suggestion(message = "This is a message", code = "This is suggested code")] + //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one Span + suggestion: (Span, Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithDuplicateApplicabilityAndSpan { + #[suggestion(message = "This is a message", code = "This is suggested code")] + //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one + suggestion: (Applicability, Applicability, Span), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct WrongKindOfAnnotation { + #[label("wrong kind of annotation for label")] + //~^ ERROR invalid annotation list `#[label(...)]` + z: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "Something something else"] +struct OptionsInErrors { + #[label = "Label message"] + label: Option, + #[suggestion(message = "suggestion message")] + opt_sugg: Option<(Span, Applicability)>, +} + +#[derive(SessionDiagnostic)] +#[error = "E0456"] +struct MoveOutOfBorrowError<'tcx> { + name: Ident, + ty: Ty<'tcx>, + #[message = "cannot move {ty} out of borrow"] + #[label = "cannot move out of borrow"] + span: Span, + #[label = "`{ty}` first borrowed here"] + other_span: Span, + #[suggestion(message = "consider cloning here", code = "{name}.clone()")] + opt_sugg: Option<(Span, Applicability)>, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct ErrorWithLifetime<'a> { + #[message = "Some message that references {name}"] + span: Span, + name: &'a str, +} diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr new file mode 100644 index 0000000000..b4830743e3 --- /dev/null +++ b/src/test/ui-fulldeps/session-derive-errors.stderr @@ -0,0 +1,124 @@ +error: `#[derive(SessionDiagnostic)]` can only be used on structs + --> $DIR/session-derive-errors.rs:28:1 + | +LL | #[error = "E0123"] + | ^^^^^^^^^^^^^^^^^^ + +error: `#[label = ...]` is not a valid SessionDiagnostic struct attribute + --> $DIR/session-derive-errors.rs:37:1 + | +LL | #[label = "This is in the wrong place"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute + --> $DIR/session-derive-errors.rs:44:5 + | +LL | #[suggestion = "this is the wrong kind of attribute"] + | ^ + +error: `error` specified multiple times + --> $DIR/session-derive-errors.rs:52:11 + | +LL | #[error = "E0456"] + | ^^^^^^^ + +error: `lint` specified when `error` was already specified + --> $DIR/session-derive-errors.rs:58:10 + | +LL | #[lint = "some_useful_lint"] + | ^^^^^^^^^^^^^^^^^^ + +error: `code` not specified + --> $DIR/session-derive-errors.rs:67:1 + | +LL | struct ErrorCodeNotProvided {} + | ^^^^^^ + | + = help: use the [code = "..."] attribute to set this diagnostic's error code + +error: the `#[message = "..."]` attribute can only be applied to fields of type Span + --> $DIR/session-derive-errors.rs:95:5 + | +LL | #[message = "this message is applied to a String field"] + | ^ + +error: `name` doesn't refer to a field on this type + --> $DIR/session-derive-errors.rs:102:1 + | +LL | #[message = "This error has a field, and references {name}"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/session-derive-errors.rs:110:1 + | +LL | #[error = "E0123"] + | - because of this opening brace +LL | #[message = "This is missing a closing brace: {name"] + | ^ expected `'}'` in format string + | + = note: if you intended to print `{`, you can escape it using `{{` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: invalid format string: unmatched `}` found + --> $DIR/session-derive-errors.rs:119:1 + | +LL | #[message = "This is missing an opening brace: name}"] + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: The `#[label = ...]` attribute can only be applied to fields of type Span + --> $DIR/session-derive-errors.rs:138:5 + | +LL | #[label = "See here"] + | ^ + +error: `nonsense` is not a valid key for `#[suggestion(...)]` + --> $DIR/session-derive-errors.rs:163:18 + | +LL | #[suggestion(nonsense = "This is nonsense")] + | ^^^^^^^^ + +error: `msg` is not a valid key for `#[suggestion(...)]` + --> $DIR/session-derive-errors.rs:171:18 + | +LL | #[suggestion(msg = "This is a suggestion")] + | ^^^ + +error: missing suggestion message + --> $DIR/session-derive-errors.rs:179:7 + | +LL | #[suggestion(code = "This is suggested code")] + | ^^^^^^^^^^ + | + = help: provide a suggestion message using #[suggestion(message = "...")] + +error: wrong field type for suggestion + --> $DIR/session-derive-errors.rs:194:5 + | +LL | #[suggestion(message = "This is a message", code = "This is suggested code")] + | ^ + | + = help: #[suggestion(...)] should be applied to fields of type Span or (Span, Applicability) + +error: type of field annotated with `#[suggestion(...)]` contains more than one Span + --> $DIR/session-derive-errors.rs:209:5 + | +LL | #[suggestion(message = "This is a message", code = "This is suggested code")] + | ^ + +error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability + --> $DIR/session-derive-errors.rs:217:5 + | +LL | #[suggestion(message = "This is a message", code = "This is suggested code")] + | ^ + +error: invalid annotation list `#[label(...)]` + --> $DIR/session-derive-errors.rs:225:7 + | +LL | #[label("wrong kind of annotation for label")] + | ^^^^^ + +error: aborting due to 18 previous errors + diff --git a/src/test/ui/access-mode-in-closures.stderr b/src/test/ui/access-mode-in-closures.stderr index 349e3f4a83..c32e944afe 100644 --- a/src/test/ui/access-mode-in-closures.stderr +++ b/src/test/ui/access-mode-in-closures.stderr @@ -5,7 +5,7 @@ LL | match *s { S(v) => v } | ^^ - | | | | | data moved here - | | move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait + | | move occurs because `v` has type `Vec`, which does not implement the `Copy` trait | help: consider borrowing here: `&*s` error: aborting due to previous error diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index a6c2317c73..dfb5d3e9e3 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -10,6 +10,7 @@ extern crate helper; use std::alloc::{self, AllocRef, Global, Layout, System}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::ptr::NonNull; static HITS: AtomicUsize = AtomicUsize::new(0); @@ -18,12 +19,12 @@ struct A; unsafe impl alloc::GlobalAlloc for A { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { HITS.fetch_add(1, Ordering::SeqCst); - System.alloc(layout) + alloc::GlobalAlloc::alloc(&System, layout) } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); - System.dealloc(ptr, layout) + AllocRef::dealloc(&System, NonNull::new(ptr).unwrap(), layout) } } diff --git a/src/test/ui/allocator/not-an-allocator.stderr b/src/test/ui/allocator/not-an-allocator.stderr index 0d52a23c1f..c0ea8ff47e 100644 --- a/src/test/ui/allocator/not-an-allocator.stderr +++ b/src/test/ui/allocator/not-an-allocator.stderr @@ -1,35 +1,35 @@ -error[E0277]: the trait bound `usize: std::alloc::GlobalAlloc` is not satisfied +error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:1 | LL | static A: usize = 0; - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::alloc::GlobalAlloc` is not implemented for `usize` + | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | = note: required by `std::alloc::GlobalAlloc::alloc` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `usize: std::alloc::GlobalAlloc` is not satisfied +error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:1 | LL | static A: usize = 0; - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::alloc::GlobalAlloc` is not implemented for `usize` + | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | = note: required by `std::alloc::GlobalAlloc::dealloc` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `usize: std::alloc::GlobalAlloc` is not satisfied +error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:1 | LL | static A: usize = 0; - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::alloc::GlobalAlloc` is not implemented for `usize` + | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | = note: required by `std::alloc::GlobalAlloc::realloc` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `usize: std::alloc::GlobalAlloc` is not satisfied +error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:1 | LL | static A: usize = 0; - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::alloc::GlobalAlloc` is not implemented for `usize` + | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | = note: required by `std::alloc::GlobalAlloc::alloc_zeroed` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr index de478417d0..576fcc6fad 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -59,7 +59,7 @@ error[E0631]: type mismatch in closure arguments LL | g1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | - | expected signature of `for<'r> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>) -> _` + | expected signature of `for<'r> fn(&'r (), Box<(dyn for<'s> Fn(&'s ()) + 'static)>) -> _` ... LL | fn g1(_: F) where F: Fn(&(), Box) {} | ------------------------- required by this bound in `g1` @@ -81,7 +81,7 @@ error[E0631]: type mismatch in closure arguments LL | g3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | - | expected signature of `for<'s> fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` + | expected signature of `for<'s> fn(&'s (), Box<(dyn for<'r> Fn(&'r ()) + 'static)>) -> _` ... LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} | ------------------------------------ required by this bound in `g3` @@ -103,7 +103,7 @@ error[E0631]: type mismatch in closure arguments LL | h1(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | - | expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box<(dyn for<'t0> std::ops::Fn(&'t0 ()) + 'static)>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` + | expected signature of `for<'r, 's> fn(&'r (), Box<(dyn for<'t0> Fn(&'t0 ()) + 'static)>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` ... LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} | -------------------------------------------- required by this bound in `h1` @@ -114,7 +114,7 @@ error[E0631]: type mismatch in closure arguments LL | h2(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | - | expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` + | expected signature of `for<'r, 't0> fn(&'r (), Box<(dyn for<'s> Fn(&'s ()) + 'static)>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` ... LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} | --------------------------------------------------------- required by this bound in `h2` diff --git a/src/test/ui/array-slice-vec/arr_cycle.rs b/src/test/ui/array-slice-vec/arr_cycle.rs deleted file mode 100644 index c262b5a1ff..0000000000 --- a/src/test/ui/array-slice-vec/arr_cycle.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -use std::cell::Cell; - -#[derive(Debug)] -struct B<'a> { - a: [Cell>>; 2] -} - -impl<'a> B<'a> { - fn new() -> B<'a> { - B { a: [Cell::new(None), Cell::new(None)] } - } -} - -fn f() { - let (b1, b2, b3); - b1 = B::new(); - b2 = B::new(); - b3 = B::new(); - b1.a[0].set(Some(&b2)); - b1.a[1].set(Some(&b3)); - b2.a[0].set(Some(&b2)); - b2.a[1].set(Some(&b3)); - b3.a[0].set(Some(&b1)); - b3.a[1].set(Some(&b2)); -} - -fn main() { - f(); -} diff --git a/src/test/ui/array-slice-vec/slice-2.rs b/src/test/ui/array-slice-vec/slice-2.rs deleted file mode 100644 index 01733f4823..0000000000 --- a/src/test/ui/array-slice-vec/slice-2.rs +++ /dev/null @@ -1,62 +0,0 @@ -// run-pass - -// Test slicing expressions on slices and Vecs. - - -fn main() { - let x: &[isize] = &[1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); - - let x: Vec = vec![1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); - - let x: &mut [isize] = &mut [1, 2, 3, 4, 5]; - { - let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5]; - assert_eq!(&mut x[..], cmp); - } - { - let cmp: &mut [isize] = &mut [3, 4, 5]; - assert_eq!(&mut x[2..], cmp); - } - { - let cmp: &mut [isize] = &mut [1, 2, 3]; - assert_eq!(&mut x[..3], cmp); - } - { - let cmp: &mut [isize] = &mut [2, 3, 4]; - assert_eq!(&mut x[1..4], cmp); - } - - let mut x: Vec = vec![1, 2, 3, 4, 5]; - { - let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5]; - assert_eq!(&mut x[..], cmp); - } - { - let cmp: &mut [isize] = &mut [3, 4, 5]; - assert_eq!(&mut x[2..], cmp); - } - { - let cmp: &mut [isize] = &mut [1, 2, 3]; - assert_eq!(&mut x[..3], cmp); - } - { - let cmp: &mut [isize] = &mut [2, 3, 4]; - assert_eq!(&mut x[1..4], cmp); - } -} diff --git a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.rs b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.rs index 34adb42a32..521b898e7f 100644 --- a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.rs +++ b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.rs @@ -1,7 +1,7 @@ fn main() { match "foo".to_string() { ['f', 'o', ..] => {} - //~^ ERROR expected an array or slice, found `std::string::String` + //~^ ERROR expected an array or slice, found `String` _ => { } }; diff --git a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr index c4548142c1..20a5b99845 100644 --- a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr +++ b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr @@ -4,11 +4,11 @@ error[E0425]: cannot find value `does_not_exist` in this scope LL | match does_not_exist { | ^^^^^^^^^^^^^^ not found in this scope -error[E0529]: expected an array or slice, found `std::string::String` +error[E0529]: expected an array or slice, found `String` --> $DIR/slice-pat-type-mismatches.rs:3:9 | LL | ['f', 'o', ..] => {} - | ^^^^^^^^^^^^^^ pattern cannot match with input type `std::string::String` + | ^^^^^^^^^^^^^^ pattern cannot match with input type `String` error[E0527]: pattern requires 1 element but array has 3 --> $DIR/slice-pat-type-mismatches.rs:18:9 diff --git a/src/test/ui/array-slice-vec/vec-concat.rs b/src/test/ui/array-slice-vec/vec-concat.rs deleted file mode 100644 index 1f493679b7..0000000000 --- a/src/test/ui/array-slice-vec/vec-concat.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass - -use std::vec; - -pub fn main() { - let a: Vec = vec![1, 2, 3, 4, 5]; - let b: Vec = vec![6, 7, 8, 9, 0]; - let mut v: Vec = a; - v.extend_from_slice(&b); - println!("{}", v[9]); - assert_eq!(v[0], 1); - assert_eq!(v[7], 8); - assert_eq!(v[9], 0); -} diff --git a/src/test/ui/array-slice-vec/vec-growth.rs b/src/test/ui/array-slice-vec/vec-growth.rs deleted file mode 100644 index b09f08bb85..0000000000 --- a/src/test/ui/array-slice-vec/vec-growth.rs +++ /dev/null @@ -1,16 +0,0 @@ -// run-pass - - - -pub fn main() { - let mut v = vec![1]; - v.push(2); - v.push(3); - v.push(4); - v.push(5); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - assert_eq!(v[3], 4); - assert_eq!(v[4], 5); -} diff --git a/src/test/ui/array-slice-vec/vec-push.rs b/src/test/ui/array-slice-vec/vec-push.rs deleted file mode 100644 index 466ab3fab1..0000000000 --- a/src/test/ui/array-slice-vec/vec-push.rs +++ /dev/null @@ -1,3 +0,0 @@ -// run-pass - -pub fn main() { let mut v = vec![1, 2, 3]; v.push(1); } diff --git a/src/test/ui/array-slice-vec/vec-slice-drop.rs b/src/test/ui/array-slice-vec/vec-slice-drop.rs deleted file mode 100644 index 3a9ea86af3..0000000000 --- a/src/test/ui/array-slice-vec/vec-slice-drop.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -#![allow(non_camel_case_types)] - -use std::cell::Cell; - -// Make sure that destructors get run on slice literals -struct foo<'a> { - x: &'a Cell, -} - -impl<'a> Drop for foo<'a> { - fn drop(&mut self) { - self.x.set(self.x.get() + 1); - } -} - -fn foo(x: &Cell) -> foo { - foo { - x: x - } -} - -pub fn main() { - let x = &Cell::new(0); - { - let l = &[foo(x)]; - assert_eq!(l[0].x.get(), 0); - } - assert_eq!(x.get(), 1); -} diff --git a/src/test/ui/array-slice-vec/vec-slice.rs b/src/test/ui/array-slice-vec/vec-slice.rs deleted file mode 100644 index 1f090ddd9c..0000000000 --- a/src/test/ui/array-slice-vec/vec-slice.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - - -pub fn main() { - let v = vec![1,2,3,4,5]; - let v2 = &v[1..3]; - assert_eq!(v2[0], 2); - assert_eq!(v2[1], 3); -} diff --git a/src/test/ui/array-slice-vec/vec-to_str.rs b/src/test/ui/array-slice-vec/vec-to_str.rs deleted file mode 100644 index a11cfc8e9b..0000000000 --- a/src/test/ui/array-slice-vec/vec-to_str.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - - -pub fn main() { - assert_eq!(format!("{:?}", vec![0, 1]), "[0, 1]".to_string()); - - let foo = vec![3, 4]; - let bar: &[isize] = &[4, 5]; - - assert_eq!(format!("{:?}", foo), "[3, 4]"); - assert_eq!(format!("{:?}", bar), "[4, 5]"); -} diff --git a/src/test/ui/array-slice-vec/vec.rs b/src/test/ui/array-slice-vec/vec.rs deleted file mode 100644 index e76c1ab440..0000000000 --- a/src/test/ui/array-slice-vec/vec.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - - - -pub fn main() { - let v: Vec = vec![10, 20]; - assert_eq!(v[0], 10); - assert_eq!(v[1], 20); - let mut x: usize = 0; - assert_eq!(v[x], 10); - assert_eq!(v[x + 1], 20); - x = x + 1; - assert_eq!(v[x], 20); - assert_eq!(v[x - 1], 10); -} diff --git a/src/test/ui/array-slice-vec/vec_cycle.rs b/src/test/ui/array-slice-vec/vec_cycle.rs deleted file mode 100644 index 82bce43728..0000000000 --- a/src/test/ui/array-slice-vec/vec_cycle.rs +++ /dev/null @@ -1,39 +0,0 @@ -// run-pass - -use std::cell::Cell; - -#[derive(Debug)] -struct C<'a> { - v: Vec>>>, -} - -impl<'a> C<'a> { - fn new() -> C<'a> { - C { v: Vec::new() } - } -} - -fn f() { - let (mut c1, mut c2, mut c3); - c1 = C::new(); - c2 = C::new(); - c3 = C::new(); - - c1.v.push(Cell::new(None)); - c1.v.push(Cell::new(None)); - c2.v.push(Cell::new(None)); - c2.v.push(Cell::new(None)); - c3.v.push(Cell::new(None)); - c3.v.push(Cell::new(None)); - - c1.v[0].set(Some(&c2)); - c1.v[1].set(Some(&c3)); - c2.v[0].set(Some(&c2)); - c2.v[1].set(Some(&c3)); - c3.v[0].set(Some(&c1)); - c3.v[1].set(Some(&c2)); -} - -fn main() { - f(); -} diff --git a/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs b/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs deleted file mode 100644 index 1a3606d5e8..0000000000 --- a/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-pass - -use std::cell::Cell; - -#[derive(Debug)] -struct Refs<'a> { - v: Vec>>>, -} - -#[derive(Debug)] -struct C<'a> { - refs: Refs<'a>, -} - -impl<'a> Refs<'a> { - fn new() -> Refs<'a> { - Refs { v: Vec::new() } - } -} - -impl<'a> C<'a> { - fn new() -> C<'a> { - C { refs: Refs::new() } - } -} - -fn f() { - let (mut c1, mut c2, mut c3); - c1 = C::new(); - c2 = C::new(); - c3 = C::new(); - - c1.refs.v.push(Cell::new(None)); - c1.refs.v.push(Cell::new(None)); - c2.refs.v.push(Cell::new(None)); - c2.refs.v.push(Cell::new(None)); - c3.refs.v.push(Cell::new(None)); - c3.refs.v.push(Cell::new(None)); - - c1.refs.v[0].set(Some(&c2)); - c1.refs.v[1].set(Some(&c3)); - c2.refs.v[0].set(Some(&c2)); - c2.refs.v[1].set(Some(&c3)); - c3.refs.v[0].set(Some(&c1)); - c3.refs.v[1].set(Some(&c2)); -} - -fn main() { - f(); -} diff --git a/src/test/ui/array_const_index-0.rs b/src/test/ui/array_const_index-0.rs index 3422aeae8c..4021dfcc6e 100644 --- a/src/test/ui/array_const_index-0.rs +++ b/src/test/ui/array_const_index-0.rs @@ -1,6 +1,6 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; -//~^ index out of bounds: the len is 0 but the index is 1 +//~^ index out of bounds: the length is 0 but the index is 1 //~| ERROR any use of this value will cause an error fn main() { diff --git a/src/test/ui/array_const_index-0.stderr b/src/test/ui/array_const_index-0.stderr index 16ebc4a577..7ccc3aa087 100644 --- a/src/test/ui/array_const_index-0.stderr +++ b/src/test/ui/array_const_index-0.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const B: i32 = (&A)[1]; | ---------------^^^^^^^- | | - | index out of bounds: the len is 0 but the index is 1 + | index out of bounds: the length is 0 but the index is 1 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/array_const_index-1.rs b/src/test/ui/array_const_index-1.rs index 1f77cb6a39..d0ee1796c0 100644 --- a/src/test/ui/array_const_index-1.rs +++ b/src/test/ui/array_const_index-1.rs @@ -1,6 +1,6 @@ const A: [i32; 0] = []; const B: i32 = A[1]; -//~^ index out of bounds: the len is 0 but the index is 1 +//~^ index out of bounds: the length is 0 but the index is 1 //~| ERROR any use of this value will cause an error fn main() { diff --git a/src/test/ui/array_const_index-1.stderr b/src/test/ui/array_const_index-1.stderr index 98a64eaadc..37de61b9df 100644 --- a/src/test/ui/array_const_index-1.stderr +++ b/src/test/ui/array_const_index-1.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const B: i32 = A[1]; | ---------------^^^^- | | - | index out of bounds: the len is 0 but the index is 1 + | index out of bounds: the length is 0 but the index is 1 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr index 1f11d19c70..556e83fdb0 100644 --- a/src/test/ui/asm/type-check-1.stderr +++ b/src/test/ui/asm/type-check-1.stderr @@ -16,7 +16,7 @@ error[E0277]: the size for values of type `[u64]` cannot be known at compilation LL | asm!("{}", in(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u64]` + = help: the trait `Sized` is not implemented for `[u64]` = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time @@ -25,7 +25,7 @@ error[E0277]: the size for values of type `[u64]` cannot be known at compilation LL | asm!("{}", out(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u64]` + = help: the trait `Sized` is not implemented for `[u64]` = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time @@ -34,7 +34,7 @@ error[E0277]: the size for values of type `[u64]` cannot be known at compilation LL | asm!("{}", inout(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u64]` + = help: the trait `Sized` is not implemented for `[u64]` = note: all inline asm arguments must have a statically known size error: aborting due to 5 previous errors diff --git a/src/test/ui/asm/type-check-2.rs b/src/test/ui/asm/type-check-2.rs index 1652e9e4c9..01c8b4eb65 100644 --- a/src/test/ui/asm/type-check-2.rs +++ b/src/test/ui/asm/type-check-2.rs @@ -78,7 +78,7 @@ fn main() { asm!("{}", in(reg) |x: i32| x); //~^ ERROR cannot use value of type asm!("{}", in(reg) vec![0]); - //~^ ERROR cannot use value of type `std::vec::Vec` for inline assembly + //~^ ERROR cannot use value of type `Vec` for inline assembly asm!("{}", in(reg) (1, 2, 3)); //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly asm!("{}", in(reg) [1, 2, 3]); diff --git a/src/test/ui/asm/type-check-2.stderr b/src/test/ui/asm/type-check-2.stderr index dc7949534f..a520bea8f1 100644 --- a/src/test/ui/asm/type-check-2.stderr +++ b/src/test/ui/asm/type-check-2.stderr @@ -26,7 +26,7 @@ LL | asm!("{}", in(reg) |x: i32| x); | = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly -error: cannot use value of type `std::vec::Vec` for inline assembly +error: cannot use value of type `Vec` for inline assembly --> $DIR/type-check-2.rs:80:28 | LL | asm!("{}", in(reg) vec![0]); diff --git a/src/test/ui/asm/type-check-3.rs b/src/test/ui/asm/type-check-3.rs index 0f803eff17..6890baead8 100644 --- a/src/test/ui/asm/type-check-3.rs +++ b/src/test/ui/asm/type-check-3.rs @@ -12,9 +12,9 @@ fn main() { asm!("{}", in(reg) 0i128); //~^ ERROR type `i128` cannot be used with this register class asm!("{}", in(reg) _mm_setzero_ps()); - //~^ ERROR type `std::arch::x86_64::__m128` cannot be used with this register class + //~^ ERROR type `__m128` cannot be used with this register class asm!("{}", in(reg) _mm256_setzero_ps()); - //~^ ERROR type `std::arch::x86_64::__m256` cannot be used with this register class + //~^ ERROR type `__m256` cannot be used with this register class asm!("{}", in(xmm_reg) 0u8); //~^ ERROR type `u8` cannot be used with this register class asm!("{:e}", in(reg) 0i32); diff --git a/src/test/ui/asm/type-check-3.stderr b/src/test/ui/asm/type-check-3.stderr index 01dbe78db8..42497456ac 100644 --- a/src/test/ui/asm/type-check-3.stderr +++ b/src/test/ui/asm/type-check-3.stderr @@ -6,7 +6,7 @@ LL | asm!("{}", in(reg) 0i128); | = note: register class `reg` supports these types: i16, i32, i64, f32, f64 -error: type `std::arch::x86_64::__m128` cannot be used with this register class +error: type `__m128` cannot be used with this register class --> $DIR/type-check-3.rs:14:28 | LL | asm!("{}", in(reg) _mm_setzero_ps()); @@ -14,7 +14,7 @@ LL | asm!("{}", in(reg) _mm_setzero_ps()); | = note: register class `reg` supports these types: i16, i32, i64, f32, f64 -error: type `std::arch::x86_64::__m256` cannot be used with this register class +error: type `__m256` cannot be used with this register class --> $DIR/type-check-3.rs:16:28 | LL | asm!("{}", in(reg) _mm256_setzero_ps()); diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.stderr b/src/test/ui/associated-const/defaults-cyclic-fail.stderr index e6075f7457..616ac9053f 100644 --- a/src/test/ui/associated-const/defaults-cyclic-fail.stderr +++ b/src/test/ui/associated-const/defaults-cyclic-fail.stderr @@ -1,38 +1,38 @@ error[E0391]: cycle detected when normalizing `<() as Tr>::A` | -note: ...which requires const-evaluating + checking `Tr::A`... +note: ...which requires simplifying constant for the type system `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | LL | const A: u8 = Self::B; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Tr::A`... +note: ...which requires simplifying constant for the type system `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | LL | const A: u8 = Self::B; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Tr::A`... +note: ...which requires const-evaluating + checking `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | LL | const A: u8 = Self::B; | ^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `<() as Tr>::B`... -note: ...which requires const-evaluating + checking `Tr::B`... +note: ...which requires simplifying constant for the type system `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Tr::B`... +note: ...which requires simplifying constant for the type system `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Tr::B`... +note: ...which requires const-evaluating + checking `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires normalizing `<() as Tr>::A`, completing the cycle -note: cycle used when const-evaluating `main::promoted[2]` +note: cycle used when const-evaluating + checking `main::promoted[2]` --> $DIR/defaults-cyclic-fail.rs:14:1 | LL | fn main() { diff --git a/src/test/ui/associated-const/defaults-not-assumed-fail.stderr b/src/test/ui/associated-const/defaults-not-assumed-fail.stderr index c1b08010cd..1497633c26 100644 --- a/src/test/ui/associated-const/defaults-not-assumed-fail.stderr +++ b/src/test/ui/associated-const/defaults-not-assumed-fail.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const B: u8 = Self::A + 1; | --------------^^^^^^^^^^^- | | - | attempt to compute `u8::MAX + 1_u8` which would overflow + | attempt to compute `u8::MAX + 1_u8`, which would overflow | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr index 724823e364..f59287bce7 100644 --- a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr +++ b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22 | LL | const NEG: i32 = -i32::MIN + T::NEG; - | ^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,25 +10,25 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35 | LL | const NEG_REV: i32 = T::NEG + (-i32::MIN); - | ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22 | LL | const ADD: i32 = (i32::MAX+1) + T::ADD; - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36 | LL | const ADD_REV: i32 = T::ADD + (i32::MAX+1); - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22 | LL | const DIV: i32 = (1/0) + T::DIV; - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -36,19 +36,19 @@ error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35 | LL | const DIV_REV: i32 = T::DIV + (1/0); - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22 | LL | const OOB: i32 = [1][1] + T::OOB; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35 | LL | const OOB_REV: i32 = T::OOB + [1][1]; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr index 724823e364..f59287bce7 100644 --- a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr +++ b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22 | LL | const NEG: i32 = -i32::MIN + T::NEG; - | ^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,25 +10,25 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35 | LL | const NEG_REV: i32 = T::NEG + (-i32::MIN); - | ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22 | LL | const ADD: i32 = (i32::MAX+1) + T::ADD; - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36 | LL | const ADD_REV: i32 = T::ADD + (i32::MAX+1); - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22 | LL | const DIV: i32 = (1/0) + T::DIV; - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -36,19 +36,19 @@ error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35 | LL | const DIV_REV: i32 = T::DIV + (1/0); - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22 | LL | const OOB: i32 = [1][1] + T::OOB; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35 | LL | const OOB_REV: i32 = T::OOB + [1][1]; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr index 724823e364..f59287bce7 100644 --- a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr +++ b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22 | LL | const NEG: i32 = -i32::MIN + T::NEG; - | ^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,25 +10,25 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35 | LL | const NEG_REV: i32 = T::NEG + (-i32::MIN); - | ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22 | LL | const ADD: i32 = (i32::MAX+1) + T::ADD; - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36 | LL | const ADD_REV: i32 = T::ADD + (i32::MAX+1); - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22 | LL | const DIV: i32 = (1/0) + T::DIV; - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -36,19 +36,19 @@ error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35 | LL | const DIV_REV: i32 = T::DIV + (1/0); - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22 | LL | const OOB: i32 = [1][1] + T::OOB; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35 | LL | const OOB_REV: i32 = T::OOB + [1][1]; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index 1b4326ea56..d9bb738656 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -1,31 +1,31 @@ -error[E0391]: cycle detected when const-evaluating + checking `IMPL_REF_BAR` +error[E0391]: cycle detected when simplifying constant for the type system `IMPL_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... +note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `IMPL_REF_BAR`... +note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `::BAR`... -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `::BAR`... +note: ...which requires const-evaluating + checking `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; @@ -36,7 +36,7 @@ note: ...which requires optimizing MIR for ` $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... +note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `DEFAULT_REF_BAR`... +note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `::BAR`... -note: ...which requires const-evaluating + checking `FooDefault::BAR`... +note: ...which requires simplifying constant for the type system `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `FooDefault::BAR`... +note: ...which requires simplifying constant for the type system `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `FooDefault::BAR`... +note: ...which requires const-evaluating + checking `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; @@ -36,7 +36,7 @@ note: ...which requires optimizing MIR for `FooDefault::BAR`... LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `DEFAULT_REF_BAR`... - = note: ...which again requires const-evaluating + checking `DEFAULT_REF_BAR`, completing the cycle + = note: ...which again requires simplifying constant for the type system `DEFAULT_REF_BAR`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr index 78ce1a28a3..62d2051b6c 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr @@ -1,31 +1,31 @@ -error[E0391]: cycle detected when const-evaluating + checking `TRAIT_REF_BAR` +error[E0391]: cycle detected when simplifying constant for the type system `TRAIT_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... +note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `TRAIT_REF_BAR`... +note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `::BAR`... -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `::BAR`... +note: ...which requires const-evaluating + checking `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; @@ -36,7 +36,7 @@ note: ...which requires optimizing MIR for `>; - //~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `String: Copy` is not satisfied fn func() -> Self::Out { Box::new(AssocNoCopy) diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr index b6b49c2e90..5236f0efa8 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:26:28 | LL | type Out = Box>; - | ^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs index 3db5e468b3..556d8900d1 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - // NOTE: rustc cannot currently handle bounds of the form `for<'a> >::Assoc: Baz`. // This should hopefully be fixed with Chalk. @@ -29,15 +27,15 @@ trait Case1 { pub struct S1; impl Case1 for S1 { -//~^ ERROR `>::App` doesn't implement `std::fmt::Debug` [E0277] +//~^ ERROR `>::App` doesn't implement `Debug` [E0277] type C = Once>; } fn assume_case1() { -//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` [E0277] -//~| ERROR `<::C as std::iter::Iterator>::Item` is not an iterator [E0277] -//~| ERROR `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely [E0277] -//~| ERROR `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely [E0277] +//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `Debug` [E0277] +//~| ERROR `<::C as Iterator>::Item` is not an iterator [E0277] +//~| ERROR `<::C as Iterator>::Item` cannot be sent between threads safely [E0277] +//~| ERROR `<::C as Iterator>::Item` cannot be shared between threads safely [E0277] fn assert_a<_0, A>() where A: Iterator, _0: Debug {} assert_a::<_, T::A>(); diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr index cbacc3610d..49b5e7fbb8 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -1,5 +1,5 @@ -error[E0277]: `>::App` doesn't implement `std::fmt::Debug` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:31:6 +error[E0277]: `>::App` doesn't implement `Debug` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:29:6 | LL | trait Case1 { | ----- required by a bound in this @@ -8,24 +8,24 @@ LL | Debug | ----- required by this bound in `Case1` ... LL | impl Case1 for S1 { - | ^^^^^ `>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^ `>::App` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `for<'a> std::fmt::Debug` is not implemented for `>::App` + = help: the trait `for<'a> Debug` is not implemented for `>::App` -error[E0277]: `<::C as std::iter::Iterator>::Item` is not an iterator - --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20 +error[E0277]: `<::C as Iterator>::Item` is not an iterator + --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20 | LL | fn assume_case1() { - | ^^^^^ `<::C as std::iter::Iterator>::Item` is not an iterator + | ^^^^^ `<::C as Iterator>::Item` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `<::C as std::iter::Iterator>::Item` + = help: the trait `Iterator` is not implemented for `<::C as Iterator>::Item` help: consider further restricting the associated type | -LL | fn assume_case1() where <::C as std::iter::Iterator>::Item: std::iter::Iterator { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn assume_case1() where <::C as Iterator>::Item: Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20 +error[E0277]: `<::C as Iterator>::Item` cannot be sent between threads safely + --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20 | LL | trait Case1 { | ----- required by a bound in this @@ -34,16 +34,16 @@ LL | Send + Iterator() { - | ^^^^^ `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely + | ^^^^^ `<::C as Iterator>::Item` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `<::C as std::iter::Iterator>::Item` + = help: the trait `Send` is not implemented for `<::C as Iterator>::Item` help: consider further restricting the associated type | -LL | fn assume_case1() where <::C as std::iter::Iterator>::Item: std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn assume_case1() where <::C as Iterator>::Item: Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20 +error[E0277]: `<::C as Iterator>::Item` cannot be shared between threads safely + --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20 | LL | trait Case1 { | ----- required by a bound in this @@ -52,16 +52,16 @@ LL | > + Sync>; | ---- required by this bound in `Case1` ... LL | fn assume_case1() { - | ^^^^^ `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely + | ^^^^^ `<::C as Iterator>::Item` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `<::C as std::iter::Iterator>::Item` + = help: the trait `Sync` is not implemented for `<::C as Iterator>::Item` help: consider further restricting the associated type | -LL | fn assume_case1() where <::C as std::iter::Iterator>::Item: std::marker::Sync { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn assume_case1() where <::C as Iterator>::Item: Sync { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20 +error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `Debug` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20 | LL | trait Case1 { | ----- required by a bound in this @@ -70,9 +70,9 @@ LL | Debug | ----- required by this bound in `Case1` ... LL | fn assume_case1() { - | ^^^^^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `for<'a> std::fmt::Debug` is not implemented for `<_ as Lam<&'a u8>>::App` + = help: the trait `for<'a> Debug` is not implemented for `<_ as Lam<&'a u8>>::App` error: aborting due to 5 previous errors diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs index 8b5c521943..39df9ba02f 100644 --- a/src/test/ui/associated-type-bounds/duplicate.rs +++ b/src/test/ui/associated-type-bounds/duplicate.rs @@ -8,173 +8,152 @@ use std::iter; struct SI1> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SI2> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SI3> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SW1 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SW2 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SW3 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EI1> { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EI2> { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EI3> { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EW1 where T: Iterator { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EW2 where T: Iterator { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EW3 where T: Iterator { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UI1> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UI2> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UI3> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UW1 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UW2 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UW3 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FI1>() {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FI2>() {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FI3>() {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FW1() where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FW2() where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FW3() where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FRPIT1() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT2() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT3() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FAPIT1(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FAPIT2(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FAPIT3(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] const CIT1: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] const CIT2: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] const CIT3: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] static SIT1: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] static SIT2: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] static SIT3: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn lit1() { let _: impl Iterator = iter::empty(); } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn lit2() { let _: impl Iterator = iter::empty(); } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn lit3() { let _: impl Iterator = iter::empty(); } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAI1> = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAI2> = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAI3> = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAW1 where T: Iterator = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAW2 where T: Iterator = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAW3 where T: Iterator = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI1> = impl Copy; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI2> = impl Copy; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI3> = impl Copy; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI4 = impl Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI5 = impl Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI6 = impl Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRI1> {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRI2> {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRI3> {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRS1: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRS2: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRS3: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRW1 where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRW2 where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRW3 where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRSW1 where Self: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] +//~| ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRSW2 where Self: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] +//~| ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRSW3 where Self: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] +//~| ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRA1 { type A: Iterator; } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRA2 { type A: Iterator; } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRA3 { type A: Iterator; } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TADyn1 = dyn Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TADyn2 = Box>; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TADyn3 = dyn Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn main() {} diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr index 712211e60c..77cd88e524 100644 --- a/src/test/ui/associated-type-bounds/duplicate.stderr +++ b/src/test/ui/associated-type-bounds/duplicate.stderr @@ -7,7 +7,7 @@ LL | #![feature(impl_trait_in_bindings)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #63065 for more information -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:10:36 | LL | struct SI1> { f: T } @@ -15,7 +15,7 @@ LL | struct SI1> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:12:36 | LL | struct SI2> { f: T } @@ -23,7 +23,7 @@ LL | struct SI2> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:14:39 | LL | struct SI3> { f: T } @@ -31,7 +31,7 @@ LL | struct SI3> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:16:45 | LL | struct SW1 where T: Iterator { f: T } @@ -39,7 +39,7 @@ LL | struct SW1 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:18:45 | LL | struct SW2 where T: Iterator { f: T } @@ -47,7 +47,7 @@ LL | struct SW2 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:20:48 | LL | struct SW3 where T: Iterator { f: T } @@ -55,7 +55,7 @@ LL | struct SW3 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:23:34 | LL | enum EI1> { V(T) } @@ -63,7 +63,7 @@ LL | enum EI1> { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:25:34 | LL | enum EI2> { V(T) } @@ -71,7 +71,7 @@ LL | enum EI2> { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:27:37 | LL | enum EI3> { V(T) } @@ -79,7 +79,7 @@ LL | enum EI3> { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:29:43 | LL | enum EW1 where T: Iterator { V(T) } @@ -87,7 +87,7 @@ LL | enum EW1 where T: Iterator { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:31:43 | LL | enum EW2 where T: Iterator { V(T) } @@ -95,7 +95,7 @@ LL | enum EW2 where T: Iterator { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:33:46 | LL | enum EW3 where T: Iterator { V(T) } @@ -103,7 +103,7 @@ LL | enum EW3 where T: Iterator { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:36:35 | LL | union UI1> { f: T } @@ -111,7 +111,7 @@ LL | union UI1> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:38:35 | LL | union UI2> { f: T } @@ -119,7 +119,7 @@ LL | union UI2> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:40:38 | LL | union UI3> { f: T } @@ -127,7 +127,7 @@ LL | union UI3> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:42:44 | LL | union UW1 where T: Iterator { f: T } @@ -135,7 +135,7 @@ LL | union UW1 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:44:44 | LL | union UW2 where T: Iterator { f: T } @@ -143,7 +143,7 @@ LL | union UW2 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:46:47 | LL | union UW3 where T: Iterator { f: T } @@ -151,7 +151,7 @@ LL | union UW3 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:49:32 | LL | fn FI1>() {} @@ -159,7 +159,7 @@ LL | fn FI1>() {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:51:32 | LL | fn FI2>() {} @@ -167,7 +167,7 @@ LL | fn FI2>() {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:53:35 | LL | fn FI3>() {} @@ -175,7 +175,7 @@ LL | fn FI3>() {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:55:43 | LL | fn FW1() where T: Iterator {} @@ -183,7 +183,7 @@ LL | fn FW1() where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:57:43 | LL | fn FW2() where T: Iterator {} @@ -191,7 +191,7 @@ LL | fn FW2() where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:59:46 | LL | fn FW3() where T: Iterator {} @@ -199,498 +199,366 @@ LL | fn FW3() where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:68:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:65:40 | LL | fn FAPIT1(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:70:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:67:40 | LL | fn FAPIT2(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:72:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:69:43 | LL | fn FAPIT3(_: impl Iterator) {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:75:39 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:72:39 | LL | const CIT1: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:77:39 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:74:39 | LL | const CIT2: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:79:42 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:76:42 | LL | const CIT3: impl Iterator = iter::empty(); | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:81:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:78:40 | LL | static SIT1: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:83:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:80:40 | LL | static SIT2: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:85:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:82:43 | LL | static SIT3: impl Iterator = iter::empty(); | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:88:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:85:46 | LL | fn lit1() { let _: impl Iterator = iter::empty(); } | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:90:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:87:46 | LL | fn lit2() { let _: impl Iterator = iter::empty(); } | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:92:49 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:89:49 | LL | fn lit3() { let _: impl Iterator = iter::empty(); } | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:95:35 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:92:35 | LL | type TAI1> = T; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:97:35 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:94:35 | LL | type TAI2> = T; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:99:38 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:96:38 | LL | type TAI3> = T; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:101:44 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:98:44 | LL | type TAW1 where T: Iterator = T; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:103:44 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:100:44 | LL | type TAW2 where T: Iterator = T; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:105:47 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:102:47 | LL | type TAW3 where T: Iterator = T; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:108:36 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:105:36 | LL | type ETAI1> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:62:42 - | -LL | fn FRPIT1() -> impl Iterator { iter::empty() } - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:64:42 - | -LL | fn FRPIT2() -> impl Iterator { iter::empty() } - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:66:45 - | -LL | fn FRPIT3() -> impl Iterator { iter::empty() } - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error: could not find defining uses - --> $DIR/duplicate.rs:108:51 - | -LL | type ETAI1> = impl Copy; - | ^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:111:36 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:107:36 | LL | type ETAI2> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:111:51 - | -LL | type ETAI2> = impl Copy; - | ^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:114:39 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:109:39 | LL | type ETAI3> = impl Copy; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:114:57 - | -LL | type ETAI3> = impl Copy; - | ^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:117:14 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:117:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:111:40 | LL | type ETAI4 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:122:14 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:122:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:113:40 | LL | type ETAI5 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:127:14 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:127:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:115:43 | LL | type ETAI6 = impl Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:133:36 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:118:36 | LL | trait TRI1> {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:135:36 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:120:36 | LL | trait TRI2> {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:137:39 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:122:39 | LL | trait TRI3> {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:139:34 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:124:34 | LL | trait TRS1: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:141:34 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:126:34 | LL | trait TRS2: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:143:37 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:128:37 | LL | trait TRS3: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:145:45 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:130:45 | LL | trait TRW1 where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:147:45 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:132:45 | LL | trait TRW2 where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:149:48 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:134:48 | LL | trait TRW3 where T: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:151:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:136:46 | LL | trait TRSW1 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:151:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:136:46 | LL | trait TRSW1 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:154:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:139:46 | LL | trait TRSW2 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:154:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:139:46 | LL | trait TRSW2 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:157:49 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:142:49 | LL | trait TRSW3 where Self: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:157:49 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:142:49 | LL | trait TRSW3 where Self: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:160:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:145:43 | LL | trait TRA1 { type A: Iterator; } | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:162:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:147:43 | LL | trait TRA2 { type A: Iterator; } | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:164:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:149:46 | LL | trait TRA3 { type A: Iterator; } | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:167:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:152:40 | LL | type TADyn1 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:171:44 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:154:44 | LL | type TADyn2 = Box>; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:175:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:156:43 | LL | type TADyn3 = dyn Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:117:28 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:117:40 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:122:28 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:122:40 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:127:28 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:127:43 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:167:28 - | -LL | type TADyn1 = dyn Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:167:40 - | -LL | type TADyn1 = dyn Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:171:32 - | -LL | type TADyn2 = Box>; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:171:44 - | -LL | type TADyn2 = Box>; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:175:28 - | -LL | type TADyn3 = dyn Iterator; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:175:43 - | -LL | type TADyn3 = dyn Iterator; - | ^^^^^^^^^^^^^ - -error: aborting due to 90 previous errors; 1 warning emitted +error: aborting due to 69 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0719`. diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs index b74c03829b..5af0573875 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.rs +++ b/src/test/ui/associated-type-bounds/inside-adt.rs @@ -3,32 +3,27 @@ struct S1 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses struct S2 { f: Box> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses struct S3 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses enum E1 { V(dyn Iterator) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` enum E2 { V(Box>) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses enum E3 { V(dyn Iterator) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` union U1 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` union U2 { f: Box> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses union U3 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` fn main() {} diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr index a532bb0c76..74e858ca86 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.stderr +++ b/src/test/ui/associated-type-bounds/inside-adt.stderr @@ -5,106 +5,125 @@ LL | struct S1 { f: dyn Iterator } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:7:33 + --> $DIR/inside-adt.rs:6:33 | LL | struct S2 { f: Box> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:10:29 + --> $DIR/inside-adt.rs:8:29 | LL | struct S3 { f: dyn Iterator } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:14:26 + --> $DIR/inside-adt.rs:11:26 | LL | enum E1 { V(dyn Iterator) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:17:30 + --> $DIR/inside-adt.rs:14:30 | LL | enum E2 { V(Box>) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:20:26 + --> $DIR/inside-adt.rs:16:26 | LL | enum E3 { V(dyn Iterator) } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:24:28 + --> $DIR/inside-adt.rs:20:28 | LL | union U1 { f: dyn Iterator } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:27:32 + --> $DIR/inside-adt.rs:23:32 | LL | union U2 { f: Box> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:30:28 + --> $DIR/inside-adt.rs:25:28 | LL | union U3 { f: dyn Iterator } | ^^^^^^^^^^^^^ -error: could not find defining uses - --> $DIR/inside-adt.rs:4:29 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:11:13 | -LL | struct S1 { f: dyn Iterator } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:7:33 +LL | enum E1 { V(dyn Iterator) } + | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -LL | struct S2 { f: Box> } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:10:29 + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size | -LL | struct S3 { f: dyn Iterator } - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:14:26 +LL | enum E1 { V(&dyn Iterator) } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | enum E1 { V(dyn Iterator) } - | ^^^^^^^^^^ +LL | enum E1 { V(Box>) } + | ^^^^ ^ -error: could not find defining uses - --> $DIR/inside-adt.rs:17:30 - | -LL | enum E2 { V(Box>) } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:20:26 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:16:13 | LL | enum E3 { V(dyn Iterator) } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | enum E3 { V(&dyn Iterator) } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | enum E3 { V(Box>) } + | ^^^^ ^ -error: could not find defining uses - --> $DIR/inside-adt.rs:24:28 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:20:15 | LL | union U1 { f: dyn Iterator } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:27:32 + | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -LL | union U2 { f: Box> } - | ^^^^^^^^^^ + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | union U1 { f: &dyn Iterator } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | union U1 { f: Box> } + | ^^^^ ^ -error: could not find defining uses - --> $DIR/inside-adt.rs:30:28 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:25:15 | LL | union U3 { f: dyn Iterator } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | union U3 { f: &dyn Iterator } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | union U3 { f: Box> } + | ^^^^ ^ -error: aborting due to 18 previous errors +error: aborting due to 13 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr index 77835c5f67..289911779f 100644 --- a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -14,7 +14,7 @@ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:25:10 | LL | type X = std::ops::Deref::Target; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Target` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Target` error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:11:23 diff --git a/src/test/ui/associated-types/associated-types-issue-20346.stderr b/src/test/ui/associated-types/associated-types-issue-20346.stderr index db35c1af17..7193d4163b 100644 --- a/src/test/ui/associated-types/associated-types-issue-20346.stderr +++ b/src/test/ui/associated-types/associated-types-issue-20346.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as Iterator>::Item == std::option::Option` +error[E0271]: type mismatch resolving ` as Iterator>::Item == Option` --> $DIR/associated-types-issue-20346.rs:34:5 | LL | fn is_iterator_of>(_: &I) {} @@ -8,9 +8,9 @@ LL | fn test_adapter>>(it: I) { | - this type parameter ... LL | is_iterator_of::, _>(&adapter); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found type parameter `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found type parameter `T` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found type `T` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr index 82c0eba87e..9f1abf2a6c 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -1,10 +1,10 @@ -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == i32` +error[E0271]: type mismatch resolving ` as Iterator>::Item == i32` --> $DIR/associated-types-overridden-binding-2.rs:6:43 | LL | let _: &dyn I32Iterator = &vec![42].into_iter(); | ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | - = note: required for the cast to the object type `dyn std::iter::Iterator` + = note: required for the cast to the object type `dyn Iterator` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr index b8321ce5b2..87612679af 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr @@ -1,18 +1,18 @@ -error[E0284]: type annotations needed: cannot satisfy `::Item == i32` +error[E0284]: type annotations needed: cannot satisfy `::Item == i32` --> $DIR/associated-types-overridden-binding.rs:4:12 | LL | trait Foo: Iterator {} | ---------- required by this bound in `Foo` LL | trait Bar: Foo {} - | ^^^^^^^^^^^^^^^ cannot satisfy `::Item == i32` + | ^^^^^^^^^^^^^^^ cannot satisfy `::Item == i32` -error[E0284]: type annotations needed: cannot satisfy `::Item == i32` +error[E0284]: type annotations needed: cannot satisfy `::Item == i32` --> $DIR/associated-types-overridden-binding.rs:7:21 | LL | trait I32Iterator = Iterator; | ---------- required by this bound in `I32Iterator` LL | trait U32Iterator = I32Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Item == i32` + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Item == i32` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-unsized.fixed b/src/test/ui/associated-types/associated-types-unsized.fixed index 9837796e30..328c8f944e 100644 --- a/src/test/ui/associated-types/associated-types-unsized.fixed +++ b/src/test/ui/associated-types/associated-types-unsized.fixed @@ -6,7 +6,7 @@ trait Get { fn get(&self) -> ::Value; } -fn foo(t: T) where ::Value: std::marker::Sized { +fn foo(t: T) where ::Value: Sized { let x = t.get(); //~ ERROR the size for values of type } diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr index e96d0e0eff..c2af548300 100644 --- a/src/test/ui/associated-types/associated-types-unsized.stderr +++ b/src/test/ui/associated-types/associated-types-unsized.stderr @@ -4,13 +4,13 @@ error[E0277]: the size for values of type `::Value` cannot be known at LL | let x = t.get(); | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `::Value` + = help: the trait `Sized` is not implemented for `::Value` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature help: consider further restricting the associated type | -LL | fn foo(t: T) where ::Value: std::marker::Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo(t: T) where ::Value: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/defaults-suitability.rs b/src/test/ui/associated-types/defaults-suitability.rs index 2be01cba10..30c2555df8 100644 --- a/src/test/ui/associated-types/defaults-suitability.rs +++ b/src/test/ui/associated-types/defaults-suitability.rs @@ -13,12 +13,12 @@ struct NotClone; // Assoc. type bounds must hold for the default type trait Tr { type Ty: Clone = NotClone; - //~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `NotClone: Clone` is not satisfied } // Where-clauses defined on the trait must also be considered trait Tr2 where Self::Ty: Clone { - //~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `NotClone: Clone` is not satisfied type Ty = NotClone; } @@ -31,7 +31,7 @@ trait Tr3 { // Involved type parameters must fulfill all bounds required by defaults that mention them trait Foo { type Bar: Clone = Vec; - //~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `T: Clone` is not satisfied } trait Bar: Sized { @@ -55,7 +55,7 @@ trait C where // Test that we get all expected errors if that default is unsuitable trait D where Vec: Clone, - //~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `NotClone: Clone` is not satisfied Self::Assoc: IsU8, //~^ ERROR the trait bound `NotClone: IsU8` is not satisfied bool: IsU8, @@ -70,7 +70,7 @@ trait D where // `Clone`. trait Foo2 { type Bar: Clone = Vec; - //~^ ERROR the trait bound `>::Baz: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `>::Baz: Clone` is not satisfied type Baz = T; } @@ -79,7 +79,7 @@ trait Foo2 { // this would be accepted. trait Foo25 { type Bar: Clone = Vec; - //~^ ERROR the trait bound `>::Baz: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `>::Baz: Clone` is not satisfied type Baz = T; } @@ -88,7 +88,7 @@ trait Foo25 { trait Foo3 where Self::Bar: Clone, Self::Baz: Clone, - //~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `T: Clone` is not satisfied { type Bar = Vec; type Baz = T; diff --git a/src/test/ui/associated-types/defaults-suitability.stderr b/src/test/ui/associated-types/defaults-suitability.stderr index 4ff4ee542b..c2ad4c5824 100644 --- a/src/test/ui/associated-types/defaults-suitability.stderr +++ b/src/test/ui/associated-types/defaults-suitability.stderr @@ -1,33 +1,33 @@ -error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NotClone: Clone` is not satisfied --> $DIR/defaults-suitability.rs:15:14 | LL | trait Tr { | -------- required by `Tr` LL | type Ty: Clone = NotClone; - | ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone` + | ^^^^^ the trait `Clone` is not implemented for `NotClone` -error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NotClone: Clone` is not satisfied --> $DIR/defaults-suitability.rs:20:27 | LL | trait Tr2 where Self::Ty: Clone { | --------------------------^^^^^ | | | - | | the trait `std::clone::Clone` is not implemented for `NotClone` + | | the trait `Clone` is not implemented for `NotClone` | required by `Tr2` -error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/defaults-suitability.rs:33:15 | LL | trait Foo { | ------------ required by `Foo` LL | type Bar: Clone = Vec; - | ^^^^^ the trait `std::clone::Clone` is not implemented for `T` + | ^^^^^ the trait `Clone` is not implemented for `T` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec` + = note: required because of the requirements on the impl of `Clone` for `Vec` help: consider restricting type parameter `T` | -LL | trait Foo { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait Foo { + | ^^^^^^^ error[E0277]: the trait bound `(): Foo` is not satisfied --> $DIR/defaults-suitability.rs:39:17 @@ -66,12 +66,12 @@ LL | | type Assoc = NotClone; LL | | } | |_- required by `D` -error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NotClone: Clone` is not satisfied --> $DIR/defaults-suitability.rs:57:23 | LL | / trait D where LL | | Vec: Clone, - | | ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone` + | | ^^^^^ the trait `Clone` is not implemented for `NotClone` LL | | LL | | Self::Assoc: IsU8, ... | @@ -79,43 +79,43 @@ LL | | type Assoc = NotClone; LL | | } | |_- required by `D` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec` + = note: required because of the requirements on the impl of `Clone` for `Vec` -error[E0277]: the trait bound `>::Baz: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:72:15 | LL | trait Foo2 { | ------------- required by `Foo2` LL | type Bar: Clone = Vec; - | ^^^^^ the trait `std::clone::Clone` is not implemented for `>::Baz` + | ^^^^^ the trait `Clone` is not implemented for `>::Baz` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<>::Baz>` + = note: required because of the requirements on the impl of `Clone` for `Vec<>::Baz>` help: consider further restricting the associated type | -LL | trait Foo2 where >::Baz: std::clone::Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Foo2 where >::Baz: Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `>::Baz: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:81:15 | LL | trait Foo25 { | --------------------- required by `Foo25` LL | type Bar: Clone = Vec; - | ^^^^^ the trait `std::clone::Clone` is not implemented for `>::Baz` + | ^^^^^ the trait `Clone` is not implemented for `>::Baz` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<>::Baz>` + = note: required because of the requirements on the impl of `Clone` for `Vec<>::Baz>` help: consider further restricting the associated type | -LL | trait Foo25 where >::Baz: std::clone::Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Foo25 where >::Baz: Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/defaults-suitability.rs:90:16 | LL | / trait Foo3 where LL | | Self::Bar: Clone, LL | | Self::Baz: Clone, - | | ^^^^^ the trait `std::clone::Clone` is not implemented for `T` + | | ^^^^^ the trait `Clone` is not implemented for `T` LL | | ... | LL | | type Baz = T; @@ -124,8 +124,8 @@ LL | | } | help: consider further restricting type parameter `T` | -LL | Self::Baz: Clone, T: std::clone::Clone - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | Self::Baz: Clone, T: Clone + | ^^^^^^^^^^ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/defaults-suitability.rs:27:5 @@ -136,9 +136,9 @@ LL | type Ty = Vec<[u8]>; ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | LL | pub struct Vec { - | - required by this bound in `std::vec::Vec` + | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` error: aborting due to 11 previous errors diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.rs b/src/test/ui/associated-types/defaults-unsound-62211-1.rs index c8b4734d6e..f283d22b3c 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-1.rs +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.rs @@ -19,9 +19,9 @@ trait UncheckedCopy: Sized { // This Output is said to be Copy. Yet we default to Self // and it's accepted, not knowing if Self ineed is Copy type Output: Copy - //~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Self: Copy` is not satisfied + Deref - //~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied + //~^ ERROR the trait bound `Self: Deref` is not satisfied + AddAssign<&'static str> //~^ ERROR cannot add-assign `&'static str` to `Self` + From @@ -40,9 +40,9 @@ trait UncheckedCopy: Sized { impl UncheckedCopy for T {} //~^ ERROR `T` doesn't implement `std::fmt::Display` -//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied +//~| ERROR the trait bound `T: Deref` is not satisfied //~| ERROR cannot add-assign `&'static str` to `T` -//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied +//~| ERROR the trait bound `T: Copy` is not satisfied fn bug(origin: T) { let origin = T::make_origin(origin); diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr index 2ba854eac4..29a7c2eab4 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Self: Copy` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:21:18 | LL | trait UncheckedCopy: Sized { | -------------------------- required by `UncheckedCopy` ... LL | type Output: Copy - | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` + | ^^^^ the trait `Copy` is not implemented for `Self` | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::marker::Copy { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + Copy { + | ^^^^^^ error[E0277]: cannot add-assign `&'static str` to `Self` --> $DIR/defaults-unsound-62211-1.rs:25:7 @@ -23,22 +23,22 @@ LL | + AddAssign<&'static str> | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + AddAssign<&'static str> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `Self: Deref` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:23:7 | LL | trait UncheckedCopy: Sized { | -------------------------- required by `UncheckedCopy` ... LL | + Deref - | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self` | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::ops::Deref { - | ^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + Deref { + | ^^^^^^^ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-1.rs:28:7 @@ -73,7 +73,7 @@ help: consider restricting type parameter `T` LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `T: Deref` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:41:9 | LL | trait UncheckedCopy: Sized { @@ -83,12 +83,12 @@ LL | + Deref | ------------------- required by this bound in `UncheckedCopy` ... LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Deref` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^ +LL | impl UncheckedCopy for T {} + | ^^^^^^^ error[E0277]: cannot add-assign `&'static str` to `T` --> $DIR/defaults-unsound-62211-1.rs:41:9 @@ -104,10 +104,10 @@ LL | impl UncheckedCopy for T {} | help: consider restricting type parameter `T` | -LL | impl> UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl> UncheckedCopy for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:41:9 | LL | trait UncheckedCopy: Sized { @@ -117,12 +117,12 @@ LL | type Output: Copy | ---- required by this bound in `UncheckedCopy` ... LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^^^ +LL | impl UncheckedCopy for T {} + | ^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.rs b/src/test/ui/associated-types/defaults-unsound-62211-2.rs index aa343e759a..5518cda370 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-2.rs +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.rs @@ -19,9 +19,9 @@ trait UncheckedCopy: Sized { // This Output is said to be Copy. Yet we default to Self // and it's accepted, not knowing if Self ineed is Copy type Output: Copy - //~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Self: Copy` is not satisfied + Deref - //~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied + //~^ ERROR the trait bound `Self: Deref` is not satisfied + AddAssign<&'static str> //~^ ERROR cannot add-assign `&'static str` to `Self` + From @@ -40,9 +40,9 @@ trait UncheckedCopy: Sized { impl UncheckedCopy for T {} //~^ ERROR `T` doesn't implement `std::fmt::Display` -//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied +//~| ERROR the trait bound `T: Deref` is not satisfied //~| ERROR cannot add-assign `&'static str` to `T` -//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied +//~| ERROR the trait bound `T: Copy` is not satisfied fn bug(origin: T) { let origin = T::make_origin(origin); diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr index d4fd0ca98e..49c66093bf 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Self: Copy` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:21:18 | LL | trait UncheckedCopy: Sized { | -------------------------- required by `UncheckedCopy` ... LL | type Output: Copy - | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` + | ^^^^ the trait `Copy` is not implemented for `Self` | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::marker::Copy { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + Copy { + | ^^^^^^ error[E0277]: cannot add-assign `&'static str` to `Self` --> $DIR/defaults-unsound-62211-2.rs:25:7 @@ -23,22 +23,22 @@ LL | + AddAssign<&'static str> | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + AddAssign<&'static str> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `Self: Deref` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:23:7 | LL | trait UncheckedCopy: Sized { | -------------------------- required by `UncheckedCopy` ... LL | + Deref - | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self` | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::ops::Deref { - | ^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + Deref { + | ^^^^^^^ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-2.rs:28:7 @@ -73,7 +73,7 @@ help: consider restricting type parameter `T` LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `T: Deref` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:41:9 | LL | trait UncheckedCopy: Sized { @@ -83,12 +83,12 @@ LL | + Deref | ------------------- required by this bound in `UncheckedCopy` ... LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Deref` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^ +LL | impl UncheckedCopy for T {} + | ^^^^^^^ error[E0277]: cannot add-assign `&'static str` to `T` --> $DIR/defaults-unsound-62211-2.rs:41:9 @@ -104,10 +104,10 @@ LL | impl UncheckedCopy for T {} | help: consider restricting type parameter `T` | -LL | impl> UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl> UncheckedCopy for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:41:9 | LL | trait UncheckedCopy: Sized { @@ -117,12 +117,12 @@ LL | type Output: Copy | ---- required by this bound in `UncheckedCopy` ... LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^^^ +LL | impl UncheckedCopy for T {} + | ^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-1.rs index 497b86eeab..cdf32dd82a 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-1.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.rs @@ -10,7 +10,7 @@ where impl X<'_> for i32 { type U = str; - //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` + //~^ ERROR the trait bound `for<'b> >::U: Clone` } fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr index 7ef2faef9c..c9255c91d2 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-1.rs:12:14 | LL | trait X<'a> @@ -8,11 +8,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for `>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr index 2a364d349d..20b6659bbc 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr @@ -5,7 +5,7 @@ LL | 1u32.f("abc"); | ^ method not found in `u32` | = note: the method `f` exists but the following trait bounds were not satisfied: - `>::U: std::clone::Clone` + `>::U: Clone` which is required by `u32: X` error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.rs b/src/test/ui/associated-types/hr-associated-type-bound-object.rs index 7c64ae38ca..e19c918c3d 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-object.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.rs @@ -5,7 +5,7 @@ where type U: ?Sized; } fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { - //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> >::U: Clone` is not satisfied <>::U>::clone(x); } diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr index db966875c7..225b18a3b0 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-object.rs:7:13 | LL | trait X<'a> @@ -8,11 +8,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { - | ^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | ^^^^^ the trait `for<'b> Clone` is not implemented for `>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs index a65f8a8c49..0a81f373ad 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs @@ -12,7 +12,7 @@ where impl<'a> Y<'a, u8> for u8 { type V = str; - //~^ ERROR the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> >::V: Clone` is not satisfied } fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr index 347a5818dc..7af261e4b3 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::V: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-1.rs:14:14 | LL | trait Y<'a, T: ?Sized> @@ -8,11 +8,11 @@ LL | for<'b> >::V: Clone, | ----- required by this bound in `Y` ... LL | type V = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::V` + | ^^^ the trait `for<'b> Clone` is not implemented for `>::V` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs index 9f849b0327..5db619dc98 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs @@ -1,8 +1,8 @@ trait Z<'a, T: ?Sized> where T: Z<'a, u16>, - //~^ the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied - //~| the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + //~^ the trait bound `for<'b> >::W: Clone` is not satisfied + //~| the trait bound `for<'b> >::W: Clone` is not satisfied for<'b> >::W: Clone, { type W: ?Sized; @@ -13,7 +13,7 @@ where impl<'a> Z<'a, u16> for u16 { type W = str; - //~^ ERROR the trait bound `for<'b> >::W: std::clone::Clone + //~^ ERROR the trait bound `for<'b> >::W: Clone } fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr index e06777e36a..9a70194379 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -1,20 +1,20 @@ -error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::W: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:3:8 | LL | trait Z<'a, T: ?Sized> | - required by a bound in this LL | where LL | T: Z<'a, u16>, - | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` + | ^^^^^^^^^^ the trait `for<'b> Clone` is not implemented for `>::W` ... LL | for<'b> >::W: Clone, | ----- required by this bound in `Z` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::W: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:15:14 | LL | trait Z<'a, T: ?Sized> @@ -24,27 +24,27 @@ LL | for<'b> >::W: Clone, | ----- required by this bound in `Z` ... LL | type W = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` + | ^^^ the trait `for<'b> Clone` is not implemented for `>::W` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::W: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:3:8 | LL | trait Z<'a, T: ?Sized> | - required by a bound in this LL | where LL | T: Z<'a, u16>, - | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` + | ^^^^^^^^^^ the trait `for<'b> Clone` is not implemented for `>::W` ... LL | for<'b> >::W: Clone, | ----- required by this bound in `Z` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to 3 previous errors diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs index 9aca59f8ce..1af63bf907 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - trait X<'a, T> where for<'b> T: X<'b, T>, @@ -13,7 +11,7 @@ where impl X<'_, (T,)> for (S,) { type U = str; - //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr index ff56f60e4c..48c4d77dcc 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr @@ -1,5 +1,5 @@ -error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-3.rs:15:14 +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-3.rs:13:14 | LL | trait X<'a, T> | - required by a bound in this @@ -8,11 +8,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs index ffe43c674c..6f06b925bd 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs @@ -11,7 +11,7 @@ where impl X<'_, T> for (S,) { type U = str; - //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr index c41efb8b6e..111ca8566b 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-4.rs:13:14 | LL | trait X<'a, T> @@ -8,11 +8,11 @@ LL | for<'b> <(T,) as X<'b, T>>::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, T>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for `<(T,) as X<'b, T>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs index dcca0b3ce9..ec627c7f7e 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - trait Cycle: Sized { type Next: Cycle; } @@ -26,14 +24,14 @@ where impl X<'_, Vec> for S { type U = str; - //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied - //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> as X<'b, Box>>::U: Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied } impl X<'_, Box> for S { type U = str; - //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied - //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> as X<'b, Box>>::U: Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr index 39c191e974..81eceb4666 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -1,5 +1,5 @@ -error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:28:14 +error[E0277]: the trait bound `for<'b> as X<'b, Box>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:26:14 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this @@ -8,14 +8,14 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for ` as X<'b, Box>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:28:14 +error[E0277]: the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:26:14 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this @@ -24,14 +24,14 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for ` as X<'b, Vec>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:34:14 +error[E0277]: the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:32:14 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this @@ -40,14 +40,14 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for ` as X<'b, Vec>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:34:14 +error[E0277]: the trait bound `for<'b> as X<'b, Box>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:32:14 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this @@ -56,11 +56,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for ` as X<'b, Box>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to 4 previous errors diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs index 4b8018cb43..04b88c7f4f 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs @@ -12,7 +12,7 @@ where impl X<'_, T> for (S,) { //~^ ERROR the trait bound `for<'b> T: X<'b, T>` is not satisfied type U = str; - //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> >::U: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr index 83845d3a94..2efdb2445a 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:14:14 | LL | trait X<'a, T> @@ -8,11 +8,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for `>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:12:12 diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.rs b/src/test/ui/associated-types/hr-associated-type-projection-1.rs index 0d4567a55f..1270cd6706 100644 --- a/src/test/ui/associated-types/hr-associated-type-projection-1.rs +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.rs @@ -11,9 +11,9 @@ where } impl UnsafeCopy<'_, T> for T { - //~^ ERROR the trait bound `>::Item: std::ops::Deref` is not satisfied + //~^ ERROR the trait bound `>::Item: Deref` is not satisfied type Item = T; - //~^ ERROR the trait bound `for<'b> >::Item: std::ops::Deref + //~^ ERROR the trait bound `for<'b> >::Item: Deref } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr index 5ab57410c4..cf4ec0babf 100644 --- a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::Item: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `for<'b> >::Item: Deref` is not satisfied --> $DIR/hr-associated-type-projection-1.rs:15:17 | LL | trait UnsafeCopy<'a, T: Copy> @@ -8,22 +8,22 @@ LL | for<'b> >::Item: std::ops::Deref, | --------------------------- required by this bound in `UnsafeCopy` ... LL | type Item = T; - | ^ the trait `for<'b> std::ops::Deref` is not implemented for `>::Item` + | ^ the trait `for<'b> Deref` is not implemented for `>::Item` | = help: the following implementations were found: - <&T as std::ops::Deref> - <&mut T as std::ops::Deref> + <&T as Deref> + <&mut T as Deref> -error[E0277]: the trait bound `>::Item: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `>::Item: Deref` is not satisfied --> $DIR/hr-associated-type-projection-1.rs:13:33 | LL | impl UnsafeCopy<'_, T> for T { - | ^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `>::Item` + | ^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `>::Item` | help: consider further restricting the associated type | -LL | impl UnsafeCopy<'_, T> for T where >::Item: std::ops::Deref { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl UnsafeCopy<'_, T> for T where >::Item: Deref { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/issue-43924.stderr b/src/test/ui/associated-types/issue-43924.stderr index f21846fd82..661730bcd7 100644 --- a/src/test/ui/associated-types/issue-43924.stderr +++ b/src/test/ui/associated-types/issue-43924.stderr @@ -1,12 +1,12 @@ -error[E0277]: the trait bound `(dyn std::string::ToString + 'static): std::default::Default` is not satisfied +error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied --> $DIR/issue-43924.rs:7:15 | LL | trait Foo { | -------------------------------- required by `Foo` LL | type Out: Default + ToString + ?Sized = dyn ToString; - | ^^^^^^^ the trait `std::default::Default` is not implemented for `(dyn std::string::ToString + 'static)` + | ^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)` -error[E0277]: the trait bound `(dyn std::string::ToString + 'static): std::default::Default` is not satisfied +error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied --> $DIR/issue-43924.rs:10:6 | LL | trait Foo { @@ -15,9 +15,9 @@ LL | type Out: Default + ToString + ?Sized = dyn ToString; | ------- required by this bound in `Foo` ... LL | impl Foo for () {} - | ^^^^^^^^ the trait `std::default::Default` is not implemented for `(dyn std::string::ToString + 'static)` + | ^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)` -error[E0277]: the trait bound `(dyn std::string::ToString + 'static): std::default::Default` is not satisfied +error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied --> $DIR/issue-43924.rs:11:6 | LL | trait Foo { @@ -26,7 +26,7 @@ LL | type Out: Default + ToString + ?Sized = dyn ToString; | ------- required by this bound in `Foo` ... LL | impl Foo for () {} - | ^^^^^^^^ the trait `std::default::Default` is not implemented for `(dyn std::string::ToString + 'static)` + | ^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)` error: aborting due to 3 previous errors diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr index be3b61665b..ddc0bf436f 100644 --- a/src/test/ui/associated-types/issue-63593.stderr +++ b/src/test/ui/associated-types/issue-63593.stderr @@ -8,8 +8,8 @@ LL | type This = Self; | help: consider further restricting `Self` | -LL | trait MyTrait: std::marker::Sized { - | ^^^^^^^^^^^^^^^^^^^^ +LL | trait MyTrait: Sized { + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/missing-associated-types.stderr b/src/test/ui/associated-types/missing-associated-types.stderr index 49003c7445..63164480a0 100644 --- a/src/test/ui/associated-types/missing-associated-types.stderr +++ b/src/test/ui/associated-types/missing-associated-types.stderr @@ -6,10 +6,10 @@ LL | type Foo = dyn Add + Sub + X + Y; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::ops::Add + std::ops::Sub + X + Y {}` + = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + X + Y {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Sub`) must be specified +error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `Add`), `Output` (from trait `Mul`), `Output` (from trait `Sub`) must be specified --> $DIR/missing-associated-types.rs:12:21 | LL | type A; @@ -35,10 +35,10 @@ LL | type Bar = dyn Add + Sub + X + Z; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::ops::Add + std::ops::Sub + X + Z {}` + = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + X + Z {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0191]: the value of the associated types `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Sub`) must be specified +error[E0191]: the value of the associated types `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `Add`), `Output` (from trait `Div`), `Output` (from trait `Div`), `Output` (from trait `Mul`), `Output` (from trait `Sub`) must be specified --> $DIR/missing-associated-types.rs:15:21 | LL | type A; @@ -49,7 +49,7 @@ LL | type B; LL | type Bar = dyn Add + Sub + X + Z; | ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated types `A`, `B`, `Output` must be specified | | | | - | | | associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + | | | associated types `Output` (from trait `Mul`), `Output` (from trait `Div`) must be specified | | associated type `Output` must be specified | associated type `Output` must be specified | @@ -71,10 +71,10 @@ LL | type Baz = dyn Add + Sub + Y; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::ops::Add + std::ops::Sub + Y {}` + = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + Y {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified +error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified --> $DIR/missing-associated-types.rs:18:21 | LL | type A; @@ -99,10 +99,10 @@ LL | type Bat = dyn Add + Sub + Fine; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::ops::Add + std::ops::Sub + Fine {}` + = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + Fine {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0191]: the value of the associated types `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified +error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified --> $DIR/missing-associated-types.rs:21:21 | LL | type Bat = dyn Add + Sub + Fine; @@ -115,11 +115,11 @@ help: specify the associated types LL | type Bat = dyn Add + Sub + Fine; | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0191]: the value of the associated types `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`) must be specified +error[E0191]: the value of the associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified --> $DIR/missing-associated-types.rs:24:21 | LL | type Bal = dyn X; - | ^^^^^^ associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + | ^^^^^^ associated types `Output` (from trait `Mul`), `Output` (from trait `Div`) must be specified | = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr index cfdf5bd53e..8fdca54d2d 100644 --- a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr +++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr @@ -7,12 +7,12 @@ LL | trait ArithmeticOps: Add + Sub + Mul ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | LL | pub trait Add { - | --- required by this bound in `std::ops::Add` + | --- required by this bound in `Add` | help: consider further restricting `Self` | -LL | trait ArithmeticOps: Add + Sub + Mul + Div + std::marker::Sized {} - | ^^^^^^^^^^^^^^^^^^^^ +LL | trait ArithmeticOps: Add + Sub + Mul + Div + Sized {} + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index d0942f78bb..3d7d476cf6 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index dc06fd74a4..a4ce6061b4 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs index 971d447633..5bc7069ff8 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -4,7 +4,6 @@ // 3. get targeted by `?` and not the parent function. // // edition:2018 -// ignore-tidy-linelength fn main() {} @@ -16,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 { return 0u8; }; let _: &dyn Future = █ - //~^ ERROR type mismatch resolving `::Output == ()` + //~^ ERROR type mismatch resolving `::Output == ()` } async fn return_targets_async_block_not_async_fn() -> u8 { @@ -25,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 { return 0u8; }; let _: &dyn Future = █ - //~^ ERROR type mismatch resolving `::Output == ()` + //~^ ERROR type mismatch resolving `::Output == ()` } fn no_break_in_async_block() { diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index 46a132da30..dbdfb2e71e 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -1,5 +1,5 @@ error[E0267]: `break` inside of an `async` block - --> $DIR/async-block-control-flow-static-semantics.rs:33:9 + --> $DIR/async-block-control-flow-static-semantics.rs:32:9 | LL | async { | ___________- @@ -9,7 +9,7 @@ LL | | }; | |_____- enclosing `async` block error[E0267]: `break` inside of an `async` block - --> $DIR/async-block-control-flow-static-semantics.rs:40:13 + --> $DIR/async-block-control-flow-static-semantics.rs:39:13 | LL | async { | _______________- @@ -19,7 +19,7 @@ LL | | }; | |_________- enclosing `async` block error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:22:58 + --> $DIR/async-block-control-flow-static-semantics.rs:21:58 | LL | async fn return_targets_async_block_not_async_fn() -> u8 { | __________________________________________________________^ @@ -31,32 +31,32 @@ LL | | LL | | } | |_^ expected `u8`, found `()` -error[E0271]: type mismatch resolving `::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:27:39 +error[E0271]: type mismatch resolving `::Output == ()` + --> $DIR/async-block-control-flow-static-semantics.rs:26:39 | LL | let _: &dyn Future = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast to the object type `dyn std::future::Future` + = note: required for the cast to the object type `dyn Future` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:13:43 + --> $DIR/async-block-control-flow-static-semantics.rs:12:43 | LL | fn return_targets_async_block_not_fn() -> u8 { | --------------------------------- ^^ expected `u8`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0271]: type mismatch resolving `::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:18:39 +error[E0271]: type mismatch resolving `::Output == ()` + --> $DIR/async-block-control-flow-static-semantics.rs:17:39 | LL | let _: &dyn Future = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast to the object type `dyn std::future::Future` + = note: required for the cast to the object type `dyn Future` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:48:44 + --> $DIR/async-block-control-flow-static-semantics.rs:47:44 | LL | fn rethrow_targets_async_block_not_fn() -> Result { | ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `()` @@ -67,7 +67,7 @@ LL | fn rethrow_targets_async_block_not_fn() -> Result { found unit type `()` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:57:50 + --> $DIR/async-block-control-flow-static-semantics.rs:56:50 | LL | fn rethrow_targets_async_block_not_async_fn() -> Result { | ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `()` diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr index 9523f040aa..d808a5939b 100644 --- a/src/test/ui/async-await/async-error-span.stderr +++ b/src/test/ui/async-await/async-error-span.stderr @@ -7,7 +7,7 @@ LL | LL | panic!() | -------- this returned value is of type `!` | - = help: the trait `std::future::Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()` = note: the return type of a function must have a statically known size error[E0698]: type inside `async fn` body must be known in this context diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index d36d59f1f6..cd0db4cc01 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -7,12 +7,12 @@ LL | fn assert_send(_: impl Send) {} LL | assert_send(local_dropped_before_await()); | ^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:24:5 | LL | let x = non_send(); - | - has type `impl std::fmt::Debug` which is not `Send` + | - has type `impl Debug` which is not `Send` LL | drop(x); LL | fut().await; | ^^^^^^^^^^^ await occurs here, with `x` maybe used later @@ -28,12 +28,12 @@ LL | fn assert_send(_: impl Send) {} LL | assert_send(non_send_temporary_in_match()); | ^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:33:20 | LL | match Some(non_send()) { - | ---------- has type `impl std::fmt::Debug` which is not `Send` + | ---------- has type `impl Debug` which is not `Send` LL | Some(_) => fut().await, | ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later ... @@ -49,12 +49,12 @@ LL | fn assert_send(_: impl Send) {} LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` | - = help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write` + = help: the trait `Send` is not implemented for `dyn std::fmt::Write` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:42:9 | LL | let f: &mut std::fmt::Formatter = panic!(); - | - has type `&mut std::fmt::Formatter<'_>` which is not `Send` + | - has type `&mut Formatter<'_>` which is not `Send` LL | if non_sync().fmt(f).unwrap() == () { LL | fut().await; | ^^^^^^^^^^^ await occurs here, with `f` maybe used later diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs index cebff3be6b..337487fc80 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs @@ -14,7 +14,7 @@ async fn foo2() -> Result<(), ()> { } async fn foo3() -> Result<(), ()> { let _ = await bar()?; //~ ERROR incorrect use of `await` - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } async fn foo21() -> Result<(), ()> { @@ -62,7 +62,7 @@ fn foo10() -> Result<(), ()> { fn foo11() -> Result<(), ()> { let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks //~^ ERROR incorrect use of `await` - //~| ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~| ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } fn foo12() -> Result<(), ()> { diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 96158fc0e0..6a653fc060 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -233,26 +233,26 @@ LL | let foo = || { LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/incorrect-syntax-suggestions.rs:16:19 | LL | let _ = await bar()?; | ^^^^^^ | | - | the `?` operator cannot be applied to type `impl std::future::Future` + | the `?` operator cannot be applied to type `impl Future` | help: consider using `.await` here: `bar().await?` | - = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `impl Future` + = note: required by `into_result` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/incorrect-syntax-suggestions.rs:63:19 | LL | let _ = await bar()?; - | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future` + | ^^^^^^ the `?` operator cannot be applied to type `impl Future` | - = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `impl Future` + = note: required by `into_result` error: aborting due to 36 previous errors diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr index dc3a4752fb..e70ed9badb 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.stderr +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -8,7 +8,7 @@ LL | take_u32(x) | ^ expected `u32`, found opaque type | = note: expected type `u32` - found opaque type `impl std::future::Future` + found opaque type `impl Future` error: aborting due to previous error diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs index 13b45df64e..b1216ff4c4 100644 --- a/src/test/ui/async-await/issue-61076.rs +++ b/src/test/ui/async-await/issue-61076.rs @@ -6,6 +6,26 @@ use core::task::{Context, Poll}; struct T; +struct Tuple(i32); + +struct Struct { + a: i32 +} + +impl Struct { + fn method(&self) {} +} + +impl Future for Struct { + type Output = Struct; + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { Poll::Pending } +} + +impl Future for Tuple { + type Output = Tuple; + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { Poll::Pending } +} + impl Future for T { type Output = Result<(), ()>; @@ -19,14 +39,35 @@ async fn foo() -> Result<(), ()> { } async fn bar() -> Result<(), ()> { - foo()?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } +async fn struct_() -> Struct { + Struct { a: 1 } +} + +async fn tuple() -> Tuple { + Tuple(1i32) +} + async fn baz() -> Result<(), ()> { let t = T; - t?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + t?; //~ ERROR the `?` operator can only be applied to values that implement `Try` + + let _: i32 = tuple().0; //~ ERROR no field `0` + + let _: i32 = struct_().a; //~ ERROR no field `a` + + struct_().method(); //~ ERROR no method named + Ok(()) } +async fn match_() { + match tuple() { + Tuple(_) => {} //~ ERROR mismatched types + } +} + fn main() {} diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr index e71f4e7136..f1f1b2d443 100644 --- a/src/test/ui/async-await/issue-61076.stderr +++ b/src/test/ui/async-await/issue-61076.stderr @@ -1,17 +1,17 @@ -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` - --> $DIR/issue-61076.rs:22:5 +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/issue-61076.rs:42:5 | LL | foo()?; | ^^^^^^ | | - | the `?` operator cannot be applied to type `impl std::future::Future` + | the `?` operator cannot be applied to type `impl Future` | help: consider using `.await` here: `foo().await?` | - = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `impl Future` + = note: required by `into_result` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` - --> $DIR/issue-61076.rs:28:5 +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/issue-61076.rs:56:5 | LL | t?; | ^^ @@ -19,9 +19,59 @@ LL | t?; | the `?` operator cannot be applied to type `T` | help: consider using `.await` here: `t.await?` | - = help: the trait `std::ops::Try` is not implemented for `T` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `T` + = note: required by `into_result` -error: aborting due to 2 previous errors +error[E0609]: no field `0` on type `impl Future` + --> $DIR/issue-61076.rs:58:26 + | +LL | let _: i32 = tuple().0; + | ^ + | +help: consider awaiting before field access + | +LL | let _: i32 = tuple().await.0; + | ^^^^^^ + +error[E0609]: no field `a` on type `impl Future` + --> $DIR/issue-61076.rs:60:28 + | +LL | let _: i32 = struct_().a; + | ^ + | +help: consider awaiting before field access + | +LL | let _: i32 = struct_().await.a; + | ^^^^^^ + +error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope + --> $DIR/issue-61076.rs:62:15 + | +LL | struct_().method(); + | ^^^^^^ method not found in `impl Future` + | +help: consider awaiting before this method call + | +LL | struct_().await.method(); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-61076.rs:69:9 + | +LL | async fn tuple() -> Tuple { + | ----- the `Output` of this `async fn`'s expected opaque type +... +LL | Tuple(_) => {} + | ^^^^^^^^ expected opaque type, found struct `Tuple` + | + = note: expected opaque type `impl Future` + found struct `Tuple` +help: consider awaiting on the future + | +LL | match tuple().await { + | ^^^^^^ + +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0308, E0599, E0609. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-64130-1-sync.stderr b/src/test/ui/async-await/issue-64130-1-sync.stderr index 42e9e4642c..ab73236800 100644 --- a/src/test/ui/async-await/issue-64130-1-sync.stderr +++ b/src/test/ui/async-await/issue-64130-1-sync.stderr @@ -7,7 +7,7 @@ LL | fn is_sync(t: T) { } LL | is_sync(bar()); | ^^^^^^^ future returned by `bar` is not `Sync` | - = help: within `impl std::future::Future`, the trait `std::marker::Sync` is not implemented for `Foo` + = help: within `impl Future`, the trait `Sync` is not implemented for `Foo` note: future is not `Sync` as this value is used across an await --> $DIR/issue-64130-1-sync.rs:15:5 | diff --git a/src/test/ui/async-await/issue-64130-2-send.stderr b/src/test/ui/async-await/issue-64130-2-send.stderr index f6f834618d..5f7440a72d 100644 --- a/src/test/ui/async-await/issue-64130-2-send.stderr +++ b/src/test/ui/async-await/issue-64130-2-send.stderr @@ -7,7 +7,7 @@ LL | fn is_send(t: T) { } LL | is_send(bar()); | ^^^^^^^ future returned by `bar` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `Foo` + = help: within `impl Future`, the trait `Send` is not implemented for `Foo` note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-2-send.rs:15:5 | diff --git a/src/test/ui/async-await/issue-64130-3-other.rs b/src/test/ui/async-await/issue-64130-3-other.rs index b819970d59..133152c309 100644 --- a/src/test/ui/async-await/issue-64130-3-other.rs +++ b/src/test/ui/async-await/issue-64130-3-other.rs @@ -22,5 +22,5 @@ async fn baz() { } fn main() { is_qux(bar()); - //~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future` + //~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl Future` } diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr index 3475b66b37..4bf43f14cc 100644 --- a/src/test/ui/async-await/issue-64130-3-other.stderr +++ b/src/test/ui/async-await/issue-64130-3-other.stderr @@ -1,14 +1,14 @@ -error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future` +error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future` --> $DIR/issue-64130-3-other.rs:24:5 | LL | fn is_qux(t: T) { } | --- required by this bound in `is_qux` LL | LL | async fn bar() { - | - within this `impl std::future::Future` + | - within this `impl Future` ... LL | is_qux(bar()); - | ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo` + | ^^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo` | = help: the following implementations were found: diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr index fc231d394c..440ea0a38e 100644 --- a/src/test/ui/async-await/issue-64130-4-async-move.stderr +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -11,9 +11,9 @@ LL | | let _x = get().await; ... | LL | | } LL | | } - | |_____- this returned value is of type `impl std::future::Future` + | |_____- this returned value is of type `impl Future` | - = help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)` + = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)` note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-4-async-move.rs:21:26 | diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr index f72757339c..2d6615cd5d 100644 --- a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -7,12 +7,12 @@ LL | fn is_send(t: T) { } LL | is_send(foo()); | ^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>` + = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>` note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-non-send-future-diags.rs:15:5 | LL | let g = x.lock().unwrap(); - | - has type `std::sync::MutexGuard<'_, u32>` which is not `Send` + | - has type `MutexGuard<'_, u32>` which is not `Send` LL | baz().await; | ^^^^^^^^^^^ await occurs here, with `g` maybe used later LL | } diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.stderr b/src/test/ui/async-await/issue-67252-unnamed-future.stderr index b43478ee20..741623040c 100644 --- a/src/test/ui/async-await/issue-67252-unnamed-future.stderr +++ b/src/test/ui/async-await/issue-67252-unnamed-future.stderr @@ -7,7 +7,7 @@ LL | fn spawn(_: T) {} LL | spawn(async { | ^^^^^ future created by async block is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*mut ()` + = help: within `impl Future`, the trait `Send` is not implemented for `*mut ()` note: future is not `Send` as this value is used across an await --> $DIR/issue-67252-unnamed-future.rs:20:9 | diff --git a/src/test/ui/async-await/issue-68112.rs b/src/test/ui/async-await/issue-68112.rs index 11b1783680..bfabf81d1f 100644 --- a/src/test/ui/async-await/issue-68112.rs +++ b/src/test/ui/async-await/issue-68112.rs @@ -58,7 +58,7 @@ fn test2() { ready(0).await; }; require_send(send_fut); - //~^ ERROR `std::cell::RefCell` cannot be shared between threads safely + //~^ ERROR `RefCell` cannot be shared between threads safely } fn main() {} diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index 6ded3e475b..e97d088cf3 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -7,12 +7,12 @@ LL | fn require_send(_: impl Send) {} LL | require_send(send_fut); | ^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = help: the trait `Sync` is not implemented for `RefCell` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:31:17 | LL | let _ = non_send_fut.await; - | ^^^^^^^^^^^^ await occurs here on type `impl std::future::Future`, which is not `Send` + | ^^^^^^^^^^^^ await occurs here on type `impl Future`, which is not `Send` error: future cannot be sent between threads safely --> $DIR/issue-68112.rs:43:5 @@ -23,33 +23,33 @@ LL | fn require_send(_: impl Send) {} LL | require_send(send_fut); | ^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = help: the trait `Sync` is not implemented for `RefCell` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:40:17 | LL | let _ = make_non_send_future1().await; - | ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl std::future::Future`, which is not `Send` + | ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future`, which is not `Send` -error[E0277]: `std::cell::RefCell` cannot be shared between threads safely +error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/issue-68112.rs:60:5 | LL | fn require_send(_: impl Send) {} | ---- required by this bound in `require_send` ... LL | require_send(send_fut); - | ^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely - | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc>` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36 t:std::sync::Arc> {}]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 t:std::sync::Arc> {}]>` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `{std::future::ResumeTy, impl std::future::Future, (), i32, Ready}` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]>` - = note: required because it appears within the type `impl std::future::Future` + | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell` + = note: required because of the requirements on the impl of `Send` for `Arc>` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]>` + = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `{ResumeTy, impl Future, (), i32, Ready}` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready}]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready}]>` + = note: required because it appears within the type `impl Future` error: aborting due to 3 previous errors diff --git a/src/test/ui/async-await/issue-68523.rs b/src/test/ui/async-await/issue-68523.rs index e6250c40c7..718c597e71 100644 --- a/src/test/ui/async-await/issue-68523.rs +++ b/src/test/ui/async-await/issue-68523.rs @@ -2,6 +2,6 @@ async fn main() -> Result { //~^ ERROR `main` function is not allowed to be `async` -//~^^ ERROR `main` has invalid return type `impl std::future::Future` +//~^^ ERROR `main` has invalid return type `impl Future` Ok(1) } diff --git a/src/test/ui/async-await/issue-68523.stderr b/src/test/ui/async-await/issue-68523.stderr index 62e37cf262..6f67af04cd 100644 --- a/src/test/ui/async-await/issue-68523.stderr +++ b/src/test/ui/async-await/issue-68523.stderr @@ -1,8 +1,8 @@ -error[E0277]: `main` has invalid return type `impl std::future::Future` +error[E0277]: `main` has invalid return type `impl Future` --> $DIR/issue-68523.rs:3:20 | LL | async fn main() -> Result { - | ^^^^^^^^^^^^^^^ `main` can only return types that implement `std::process::Termination` + | ^^^^^^^^^^^^^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr index badb7ae9f6..fb1f8e4ffd 100644 --- a/src/test/ui/async-await/issue-70594.stderr +++ b/src/test/ui/async-await/issue-70594.stderr @@ -24,8 +24,8 @@ error[E0277]: `()` is not a future LL | [1; ().await]; | ^^^^^^^^ `()` is not a future | - = help: the trait `std::future::Future` is not implemented for `()` - = note: required by `std::future::Future::poll` + = help: the trait `Future` is not implemented for `()` + = note: required by `poll` error: aborting due to 4 previous errors diff --git a/src/test/ui/async-await/issue-70818.stderr b/src/test/ui/async-await/issue-70818.stderr index 2166420070..364194bea1 100644 --- a/src/test/ui/async-await/issue-70818.stderr +++ b/src/test/ui/async-await/issue-70818.stderr @@ -5,7 +5,7 @@ LL | fn foo(ty: T, ty1: U) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` LL | LL | async { (ty, ty1) } - | ------------------- this returned value is of type `impl std::future::Future` + | ------------------- this returned value is of type `impl Future` | note: captured value is not `Send` --> $DIR/issue-70818.rs:6:18 @@ -15,8 +15,8 @@ LL | async { (ty, ty1) } = note: the return type of a function must have a statically known size help: consider restricting type parameter `U` | -LL | fn foo(ty: T, ty1: U) -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo(ty: T, ty1: U) -> impl Future + Send { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/async-await/issue-71137.stderr b/src/test/ui/async-await/issue-71137.stderr index 788a9bc2c7..85cc7069b6 100644 --- a/src/test/ui/async-await/issue-71137.stderr +++ b/src/test/ui/async-await/issue-71137.stderr @@ -7,12 +7,12 @@ LL | fn fake_spawn(f: F) { } LL | fake_spawn(wrong_mutex()); | ^^^^^^^^^^ future returned by `wrong_mutex` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, i32>` + = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>` note: future is not `Send` as this value is used across an await --> $DIR/issue-71137.rs:12:5 | LL | let mut guard = m.lock().unwrap(); - | --------- has type `std::sync::MutexGuard<'_, i32>` which is not `Send` + | --------- has type `MutexGuard<'_, i32>` which is not `Send` LL | (async { "right"; }).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `mut guard` maybe used later LL | *guard += 1; diff --git a/src/test/ui/async-await/issue-72442.stderr b/src/test/ui/async-await/issue-72442.stderr index 3b909689b5..52245b6312 100644 --- a/src/test/ui/async-await/issue-72442.stderr +++ b/src/test/ui/async-await/issue-72442.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::option::Option<&str>: std::convert::AsRef` is not satisfied +error[E0277]: the trait bound `Option<&str>: AsRef` is not satisfied --> $DIR/issue-72442.rs:12:36 | LL | let mut f = File::open(path.to_str())?; - | ^^^^^^^^^^^^^ the trait `std::convert::AsRef` is not implemented for `std::option::Option<&str>` + | ^^^^^^^^^^^^^ the trait `AsRef` is not implemented for `Option<&str>` | ::: $SRC_DIR/std/src/fs.rs:LL:COL | LL | pub fn open>(path: P) -> io::Result { - | ----------- required by this bound in `std::fs::File::open` + | ----------- required by this bound in `File::open` error: aborting due to previous error diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.stderr b/src/test/ui/async-await/issue-72590-type-error-sized.stderr index 762afa6450..785fe21dd3 100644 --- a/src/test/ui/async-await/issue-72590-type-error-sized.stderr +++ b/src/test/ui/async-await/issue-72590-type-error-sized.stderr @@ -16,7 +16,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | async fn frob(self) {} | ^^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `str` + = help: within `Foo`, the trait `Sized` is not implemented for `str` = note: required because it appears within the type `Foo` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index e3ba74a03c..c879a65bc7 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -33,8 +33,8 @@ error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future LL | (|_| 2333).await; | ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future | - = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` - = note: required by `std::future::Future::poll` + = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` + = note: required by `poll` error: aborting due to 4 previous errors diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs index 2f80435046..4f160fccc0 100644 --- a/src/test/ui/async-await/issues/issue-65159.rs +++ b/src/test/ui/async-await/issues/issue-65159.rs @@ -5,7 +5,7 @@ async fn copy() -> Result<()> //~ ERROR wrong number of type arguments { Ok(()) - //~^ type annotations needed + //~^ ERROR type annotations needed } fn main() { } diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr index 49cd30e11a..e4b2725686 100644 --- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr @@ -7,7 +7,7 @@ LL | fn assert_send(_: T) {} LL | assert_send(async { | ^^^^^^^^^^^ future created by async block is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*const u8` + = help: within `impl Future`, the trait `Send` is not implemented for `*const u8` note: future is not `Send` as this value is used across an await --> $DIR/issue-65436-raw-ptr-not-send.rs:14:9 | diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs index c8c2702ec4..b7a976a0af 100644 --- a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs +++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs @@ -8,7 +8,7 @@ impl Ia { async fn crash(self) { Self::partial(self.0); - Self::full(self); //~ ERROR use of moved value: `self` + Self::full(self); //~ ERROR use of partially moved value: `self` } } diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr index 9177b83dd4..e2a7353987 100644 --- a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr +++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `self` +error[E0382]: use of partially moved value: `self` --> $DIR/issue-66958-non-copy-infered-type-arg.rs:11:20 | LL | Self::partial(self.0); - | ------ value moved here + | ------ value partially moved here LL | Self::full(self); | ^^^^ value used here after partial move | - = note: move occurs because `self.0` has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because `self.0` has type `S`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-67893.rs b/src/test/ui/async-await/issues/issue-67893.rs index 9679e3807b..f34ce8081c 100644 --- a/src/test/ui/async-await/issues/issue-67893.rs +++ b/src/test/ui/async-await/issues/issue-67893.rs @@ -7,5 +7,5 @@ fn g(_: impl Send) {} fn main() { g(issue_67893::run()) - //~^ ERROR: `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely + //~^ ERROR: `MutexGuard<'_, ()>` cannot be sent between threads safely } diff --git a/src/test/ui/async-await/issues/issue-67893.stderr b/src/test/ui/async-await/issues/issue-67893.stderr index 343a35a166..af09f0a27b 100644 --- a/src/test/ui/async-await/issues/issue-67893.stderr +++ b/src/test/ui/async-await/issues/issue-67893.stderr @@ -1,23 +1,23 @@ -error[E0277]: `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely +error[E0277]: `MutexGuard<'_, ()>` cannot be sent between threads safely --> $DIR/issue-67893.rs:9:5 | LL | fn g(_: impl Send) {} | ---- required by this bound in `g` ... LL | g(issue_67893::run()) - | ^ `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely + | ^ `MutexGuard<'_, ()>` cannot be sent between threads safely | ::: $DIR/auxiliary/issue_67893.rs:7:20 | LL | pub async fn run() { - | - within this `impl std::future::Future` + | - within this `impl Future` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, ()>` - = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {std::future::ResumeTy, std::sync::Arc>, &'r std::sync::Mutex<()>, std::result::Result, std::sync::PoisonError>>, &'t1 std::sync::MutexGuard<'t2, ()>, std::sync::MutexGuard<'t3, ()>, (), impl std::future::Future}` - = note: required because it appears within the type `[static generator@issue_67893::run::{{closure}}#0 for<'r, 's, 't0, 't1, 't2, 't3> {std::future::ResumeTy, std::sync::Arc>, &'r std::sync::Mutex<()>, std::result::Result, std::sync::PoisonError>>, &'t1 std::sync::MutexGuard<'t2, ()>, std::sync::MutexGuard<'t3, ()>, (), impl std::future::Future}]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@issue_67893::run::{{closure}}#0 for<'r, 's, 't0, 't1, 't2, 't3> {std::future::ResumeTy, std::sync::Arc>, &'r std::sync::Mutex<()>, std::result::Result, std::sync::PoisonError>>, &'t1 std::sync::MutexGuard<'t2, ()>, std::sync::MutexGuard<'t3, ()>, (), impl std::future::Future}]>` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` + = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` + = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}` + = note: required because it appears within the type `[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]>` + = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `impl Future` error: aborting due to previous error diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs index 57a9f175ca..b3c59734e0 100644 --- a/src/test/ui/async-await/no-const-async.rs +++ b/src/test/ui/async-await/no-const-async.rs @@ -3,4 +3,3 @@ pub const async fn x() {} //~^ ERROR functions cannot be both `const` and `async` -//~| ERROR `impl Trait` in const fn is unstable diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr index 4e59bb5076..90ec646c8c 100644 --- a/src/test/ui/async-await/no-const-async.stderr +++ b/src/test/ui/async-await/no-const-async.stderr @@ -7,15 +7,5 @@ LL | pub const async fn x() {} | | `async` because of this | `const` because of this -error[E0723]: `impl Trait` in const fn is unstable - --> $DIR/no-const-async.rs:4:24 - | -LL | pub const async fn x() {} - | ^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/async-await/no-move-across-await-struct.stderr b/src/test/ui/async-await/no-move-across-await-struct.stderr index adfae09925..4eaed1cf15 100644 --- a/src/test/ui/async-await/no-move-across-await-struct.stderr +++ b/src/test/ui/async-await/no-move-across-await-struct.stderr @@ -6,7 +6,7 @@ LL | needs_vec(s.x).await; LL | s.x | ^^^ value used here after move | - = note: move occurs because `s.x` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because `s.x` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/async-await/no-move-across-await-tuple.stderr b/src/test/ui/async-await/no-move-across-await-tuple.stderr index a60fd9361a..d750df9918 100644 --- a/src/test/ui/async-await/no-move-across-await-tuple.stderr +++ b/src/test/ui/async-await/no-move-across-await-tuple.stderr @@ -7,7 +7,7 @@ LL | nothing().await; LL | x.1 | ^^^ value used here after move | - = note: move occurs because `x.1` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because `x.1` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr index 2703cec581..ed2c4cbfcc 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.stderr +++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr @@ -11,7 +11,7 @@ LL | take_u32(x) | help: consider using `.await` here: `x.await` | = note: expected type `u32` - found opaque type `impl std::future::Future` + found opaque type `impl Future` error: aborting due to previous error diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 6ac05a87aa..c6355680e2 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -11,7 +11,7 @@ LL | take_u32(x) | help: consider using `.await` here: `x.await` | = note: expected type `u32` - found opaque type `impl std::future::Future` + found opaque type `impl Future` error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:23:5 @@ -23,7 +23,7 @@ LL | dummy() | ^^^^^^^ expected `()`, found opaque type | = note: expected unit type `()` - found opaque type `impl std::future::Future` + found opaque type `impl Future` help: try adding a semicolon | LL | dummy(); diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr index f623511c0e..695d7dd59f 100644 --- a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr +++ b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr @@ -18,7 +18,7 @@ LL | x.await; = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0609]: no field `await` on type `std::pin::Pin<&mut dyn std::future::Future>` +error[E0609]: no field `await` on type `Pin<&mut dyn Future>` --> $DIR/suggest-switching-edition-on-await.rs:31:7 | LL | x.await; diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr index 700296d674..8e7823f357 100644 --- a/src/test/ui/async-await/try-on-option-in-async.stderr +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-in-async.rs:8:9 | LL | async { @@ -10,10 +10,10 @@ LL | | 22 LL | | } | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-in-async.rs:17:9 | LL | let async_closure = async || { @@ -25,10 +25,10 @@ LL | | 22_u32 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `u32` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `u32` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-in-async.rs:26:5 | LL | async fn an_async_function() -> u32 { @@ -40,8 +40,8 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `u32` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `u32` + = note: required by `from_error` error: aborting due to 3 previous errors diff --git a/src/test/ui/atomic-from-mut-not-available.rs b/src/test/ui/atomic-from-mut-not-available.rs new file mode 100644 index 0000000000..bf94616007 --- /dev/null +++ b/src/test/ui/atomic-from-mut-not-available.rs @@ -0,0 +1,7 @@ +// only-x86 +// only-linux + +fn main() { + core::sync::atomic::AtomicU64::from_mut(&mut 0u64); + //~^ ERROR: no function or associated item named `from_mut` found for struct `AtomicU64` +} diff --git a/src/test/ui/atomic-from-mut-not-available.stderr b/src/test/ui/atomic-from-mut-not-available.stderr new file mode 100644 index 0000000000..d1ebca8a29 --- /dev/null +++ b/src/test/ui/atomic-from-mut-not-available.stderr @@ -0,0 +1,9 @@ +error[E0599]: no function or associated item named `from_mut` found for struct `AtomicU64` in the current scope + --> $DIR/atomic-from-mut-not-available.rs:5:36 + | +LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64); + | ^^^^^^^^ function or associated item not found in `AtomicU64` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/attributes/register-attr-tool-prelude.rs b/src/test/ui/attributes/register-attr-tool-prelude.rs index a491773f5e..d217a8146d 100644 --- a/src/test/ui/attributes/register-attr-tool-prelude.rs +++ b/src/test/ui/attributes/register-attr-tool-prelude.rs @@ -7,7 +7,7 @@ #[no_implicit_prelude] mod m { #[attr] //~ ERROR cannot find attribute `attr` in this scope - #[tool::attr] //~ ERROR failed to resolve: use of undeclared type or module `tool` + #[tool::attr] //~ ERROR failed to resolve: use of undeclared crate or module `tool` fn check() {} } diff --git a/src/test/ui/attributes/register-attr-tool-prelude.stderr b/src/test/ui/attributes/register-attr-tool-prelude.stderr index 66a4eeb6aa..905b661206 100644 --- a/src/test/ui/attributes/register-attr-tool-prelude.stderr +++ b/src/test/ui/attributes/register-attr-tool-prelude.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `tool` +error[E0433]: failed to resolve: use of undeclared crate or module `tool` --> $DIR/register-attr-tool-prelude.rs:10:7 | LL | #[tool::attr] - | ^^^^ use of undeclared type or module `tool` + | ^^^^ use of undeclared crate or module `tool` error: cannot find attribute `attr` in this scope --> $DIR/register-attr-tool-prelude.rs:9:7 diff --git a/src/test/ui/auto-ref-slice-plus-ref.stderr b/src/test/ui/auto-ref-slice-plus-ref.stderr index dc7deb8a7c..eb8447ff0f 100644 --- a/src/test/ui/auto-ref-slice-plus-ref.stderr +++ b/src/test/ui/auto-ref-slice-plus-ref.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `test_mut` found for struct `std::vec::Vec<{integer}>` in the current scope +error[E0599]: no method named `test_mut` found for struct `Vec<{integer}>` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:7:7 | LL | a.test_mut(); @@ -11,11 +11,11 @@ note: `MyIter` defines an item `test_mut`, perhaps you need to implement it LL | trait MyIter { | ^^^^^^^^^^^^ -error[E0599]: no method named `test` found for struct `std::vec::Vec<{integer}>` in the current scope +error[E0599]: no method named `test` found for struct `Vec<{integer}>` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:8:7 | LL | a.test(); - | ^^^^ method not found in `std::vec::Vec<{integer}>` + | ^^^^ method not found in `Vec<{integer}>` | = help: items from traits can only be used if the trait is implemented and in scope note: `MyIter` defines an item `test`, perhaps you need to implement it diff --git a/src/test/ui/autoderef-full-lval.rs b/src/test/ui/autoderef-full-lval.rs index 4bef1012e3..f07a2c107b 100644 --- a/src/test/ui/autoderef-full-lval.rs +++ b/src/test/ui/autoderef-full-lval.rs @@ -13,13 +13,13 @@ fn main() { let a: Clam = Clam{x: box 1, y: box 2}; let b: Clam = Clam{x: box 10, y: box 20}; let z: isize = a.x + b.y; - //~^ ERROR cannot add `std::boxed::Box` to `std::boxed::Box` + //~^ ERROR cannot add `Box` to `Box` println!("{}", z); assert_eq!(z, 21); let forty: Fish = Fish{a: box 40}; let two: Fish = Fish{a: box 2}; let answer: isize = forty.a + two.a; - //~^ ERROR cannot add `std::boxed::Box` to `std::boxed::Box` + //~^ ERROR cannot add `Box` to `Box` println!("{}", answer); assert_eq!(answer, 42); } diff --git a/src/test/ui/autoderef-full-lval.stderr b/src/test/ui/autoderef-full-lval.stderr index f094388794..9921ce7c15 100644 --- a/src/test/ui/autoderef-full-lval.stderr +++ b/src/test/ui/autoderef-full-lval.stderr @@ -1,18 +1,18 @@ -error[E0369]: cannot add `std::boxed::Box` to `std::boxed::Box` +error[E0369]: cannot add `Box` to `Box` --> $DIR/autoderef-full-lval.rs:15:24 | LL | let z: isize = a.x + b.y; - | --- ^ --- std::boxed::Box + | --- ^ --- Box | | - | std::boxed::Box + | Box -error[E0369]: cannot add `std::boxed::Box` to `std::boxed::Box` +error[E0369]: cannot add `Box` to `Box` --> $DIR/autoderef-full-lval.rs:21:33 | LL | let answer: isize = forty.a + two.a; - | ------- ^ ----- std::boxed::Box + | ------- ^ ----- Box | | - | std::boxed::Box + | Box error: aborting due to 2 previous errors diff --git a/src/test/ui/auxiliary/using-target-feature-unstable.rs b/src/test/ui/auxiliary/using-target-feature-unstable.rs index 78645c284f..2682028936 100644 --- a/src/test/ui/auxiliary/using-target-feature-unstable.rs +++ b/src/test/ui/auxiliary/using-target-feature-unstable.rs @@ -1,5 +1,5 @@ -#![feature(mmx_target_feature)] +#![feature(avx512_target_feature)] #[inline] -#[target_feature(enable = "mmx")] +#[target_feature(enable = "avx512ifma")] pub unsafe fn foo() {} diff --git a/src/test/ui/bad/bad-const-type.rs b/src/test/ui/bad/bad-const-type.rs index ce9ea7bc9e..934ee353da 100644 --- a/src/test/ui/bad/bad-const-type.rs +++ b/src/test/ui/bad/bad-const-type.rs @@ -1,4 +1,4 @@ static i: String = 10; //~^ ERROR mismatched types -//~| expected struct `std::string::String`, found integer +//~| expected struct `String`, found integer fn main() { println!("{}", i); } diff --git a/src/test/ui/bad/bad-const-type.stderr b/src/test/ui/bad/bad-const-type.stderr index f667779fab..a9c84b4b41 100644 --- a/src/test/ui/bad/bad-const-type.stderr +++ b/src/test/ui/bad/bad-const-type.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | static i: String = 10; | ^^ | | - | expected struct `std::string::String`, found integer + | expected struct `String`, found integer | help: try using a conversion method: `10.to_string()` error: aborting due to previous error diff --git a/src/test/ui/bad/bad-expr-path.stderr b/src/test/ui/bad/bad-expr-path.stderr index 56bb6e2be8..77c48c951a 100644 --- a/src/test/ui/bad/bad-expr-path.stderr +++ b/src/test/ui/bad/bad-expr-path.stderr @@ -23,7 +23,7 @@ LL | fn main(arguments: Vec) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | = note: expected fn pointer `fn()` - found fn pointer `fn(std::vec::Vec)` + found fn pointer `fn(Vec)` error: aborting due to 4 previous errors diff --git a/src/test/ui/bad/bad-expr-path2.stderr b/src/test/ui/bad/bad-expr-path2.stderr index e217c45b26..d06e102717 100644 --- a/src/test/ui/bad/bad-expr-path2.stderr +++ b/src/test/ui/bad/bad-expr-path2.stderr @@ -23,7 +23,7 @@ LL | fn main(arguments: Vec) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | = note: expected fn pointer `fn()` - found fn pointer `fn(std::vec::Vec)` + found fn pointer `fn(Vec)` error: aborting due to 4 previous errors diff --git a/src/test/ui/bad/bad-method-typaram-kind.stderr b/src/test/ui/bad/bad-method-typaram-kind.stderr index fd3999ae6f..5b68d97a9e 100644 --- a/src/test/ui/bad/bad-method-typaram-kind.stderr +++ b/src/test/ui/bad/bad-method-typaram-kind.stderr @@ -6,8 +6,8 @@ LL | 1.bar::(); | help: consider further restricting this bound | -LL | fn foo() { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo() { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/bad/bad-module.rs b/src/test/ui/bad/bad-module.rs index a496c816e9..b23e97c2cf 100644 --- a/src/test/ui/bad/bad-module.rs +++ b/src/test/ui/bad/bad-module.rs @@ -1,7 +1,7 @@ fn main() { let foo = thing::len(Vec::new()); - //~^ ERROR failed to resolve: use of undeclared type or module `thing` + //~^ ERROR failed to resolve: use of undeclared crate or module `thing` let foo = foo::bar::baz(); - //~^ ERROR failed to resolve: use of undeclared type or module `foo` + //~^ ERROR failed to resolve: use of undeclared crate or module `foo` } diff --git a/src/test/ui/bad/bad-module.stderr b/src/test/ui/bad/bad-module.stderr index 45d4c5abd9..581a661981 100644 --- a/src/test/ui/bad/bad-module.stderr +++ b/src/test/ui/bad/bad-module.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `thing` +error[E0433]: failed to resolve: use of undeclared crate or module `thing` --> $DIR/bad-module.rs:2:15 | LL | let foo = thing::len(Vec::new()); - | ^^^^^ use of undeclared type or module `thing` + | ^^^^^ use of undeclared crate or module `thing` -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/bad-module.rs:5:15 | LL | let foo = foo::bar::baz(); - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr index 93984f1c37..b9bce7fb5f 100644 --- a/src/test/ui/bad/bad-sized.stderr +++ b/src/test/ui/bad/bad-sized.stderr @@ -6,7 +6,7 @@ LL | let x: Vec = Vec::new(); | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Trait + std::marker::Sized {}` + = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Trait + Sized {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time @@ -18,9 +18,9 @@ LL | let x: Vec = Vec::new(); ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | LL | pub struct Vec { - | - required by this bound in `std::vec::Vec` + | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` + = help: the trait `Sized` is not implemented for `dyn Trait` error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:37 @@ -28,8 +28,8 @@ error[E0277]: the size for values of type `dyn Trait` cannot be known at compila LL | let x: Vec = Vec::new(); | ^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` - = note: required by `std::vec::Vec::::new` + = help: the trait `Sized` is not implemented for `dyn Trait` + = note: required by `Vec::::new` error: aborting due to 3 previous errors diff --git a/src/test/ui/binding/issue-53114-borrow-checks.stderr b/src/test/ui/binding/issue-53114-borrow-checks.stderr index 2a7a721324..489bf70d92 100644 --- a/src/test/ui/binding/issue-53114-borrow-checks.stderr +++ b/src/test/ui/binding/issue-53114-borrow-checks.stderr @@ -8,26 +8,26 @@ LL | drop(m); LL | match m { _ => { } } // #53114: should eventually be accepted too | ^ value used here after move -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:27:11 | LL | match mm { (_x, _) => { } } - | -- value moved here + | -- value partially moved here LL | match mm { (_, _y) => { } } | ^^ value used here after partial move | - = note: move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:29:11 | LL | match mm { (_, _y) => { } } - | -- value moved here + | -- value partially moved here LL | LL | match mm { (_, _) => { } } | ^^ value used here after partial move | - = note: move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait error[E0382]: use of moved value: `m` --> $DIR/issue-53114-borrow-checks.rs:36:16 @@ -39,26 +39,26 @@ LL | drop(m); LL | if let _ = m { } // #53114: should eventually be accepted too | ^ value used here after move -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:41:22 | LL | if let (_x, _) = mm { } - | -- value moved here + | -- value partially moved here LL | if let (_, _y) = mm { } | ^^ value used here after partial move | - = note: move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:43:21 | LL | if let (_, _y) = mm { } - | -- value moved here + | -- value partially moved here LL | LL | if let (_, _) = mm { } | ^^ value used here after partial move | - = note: move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait error: aborting due to 6 previous errors diff --git a/src/test/ui/binop/binop-bitxor-str.rs b/src/test/ui/binop/binop-bitxor-str.rs index e98ea4df97..3085cce3f3 100644 --- a/src/test/ui/binop/binop-bitxor-str.rs +++ b/src/test/ui/binop/binop-bitxor-str.rs @@ -1,3 +1,3 @@ -// error-pattern:no implementation for `std::string::String ^ std::string::String` +// error-pattern:no implementation for `String ^ String` fn main() { let x = "a".to_string() ^ "b".to_string(); } diff --git a/src/test/ui/binop/binop-bitxor-str.stderr b/src/test/ui/binop/binop-bitxor-str.stderr index 18c1ce0ff0..f236cd61ef 100644 --- a/src/test/ui/binop/binop-bitxor-str.stderr +++ b/src/test/ui/binop/binop-bitxor-str.stderr @@ -1,10 +1,10 @@ -error[E0369]: no implementation for `std::string::String ^ std::string::String` +error[E0369]: no implementation for `String ^ String` --> $DIR/binop-bitxor-str.rs:3:37 | LL | fn main() { let x = "a".to_string() ^ "b".to_string(); } - | --------------- ^ --------------- std::string::String + | --------------- ^ --------------- String | | - | std::string::String + | String error: aborting due to previous error diff --git a/src/test/ui/blind/blind-item-block-middle.stderr b/src/test/ui/blind/blind-item-block-middle.stderr index d8d15615d7..9db11cf159 100644 --- a/src/test/ui/blind/blind-item-block-middle.stderr +++ b/src/test/ui/blind/blind-item-block-middle.stderr @@ -7,7 +7,7 @@ LL | mod foo { pub struct bar; } LL | let bar = 5; | ^^^ | | - | expected integer, found struct `foo::bar` + | expected integer, found struct `bar` | `bar` is interpreted as a unit struct, not a new binding | help: introduce a new binding instead: `other_bar` diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr index 15ca831670..7c3d0165c6 100644 --- a/src/test/ui/block-result/consider-removing-last-semi.stderr +++ b/src/test/ui/block-result/consider-removing-last-semi.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:3:15 | LL | pub fn f() -> String { - | - ^^^^^^ expected struct `std::string::String`, found `()` + | - ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression LL | 0u8; @@ -13,7 +13,7 @@ error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:8:15 | LL | pub fn g() -> String { - | - ^^^^^^ expected struct `std::string::String`, found `()` + | - ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression LL | "this won't work".to_string(); diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr index 707d24cd6a..60aa2c5a6b 100644 --- a/src/test/ui/block-result/issue-13428.stderr +++ b/src/test/ui/block-result/issue-13428.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-13428.rs:3:13 | LL | fn foo() -> String { - | --- ^^^^^^ expected struct `std::string::String`, found `()` + | --- ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression ... @@ -13,7 +13,7 @@ error[E0308]: mismatched types --> $DIR/issue-13428.rs:11:13 | LL | fn bar() -> String { - | --- ^^^^^^ expected struct `std::string::String`, found `()` + | --- ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression LL | "foobar".to_string() diff --git a/src/test/ui/block-result/issue-13624.rs b/src/test/ui/block-result/issue-13624.rs index bd1d0de320..4d2844cc5a 100644 --- a/src/test/ui/block-result/issue-13624.rs +++ b/src/test/ui/block-result/issue-13624.rs @@ -6,7 +6,7 @@ mod a { pub fn get_enum_struct_variant() -> () { Enum::EnumStructVariant { x: 1, y: 2, z: 3 } //~^ ERROR mismatched types - //~| expected `()`, found enum `a::Enum` + //~| expected `()`, found enum `Enum` } } @@ -19,7 +19,7 @@ mod b { match enum_struct_variant { a::Enum::EnumStructVariant { x, y, z } => { //~^ ERROR mismatched types - //~| expected `()`, found enum `a::Enum` + //~| expected `()`, found enum `Enum` } } } diff --git a/src/test/ui/block-result/issue-13624.stderr b/src/test/ui/block-result/issue-13624.stderr index 416f055251..13070b4e82 100644 --- a/src/test/ui/block-result/issue-13624.stderr +++ b/src/test/ui/block-result/issue-13624.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | pub fn get_enum_struct_variant() -> () { | -- expected `()` because of return type LL | Enum::EnumStructVariant { x: 1, y: 2, z: 3 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `a::Enum` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `Enum` error[E0308]: mismatched types --> $DIR/issue-13624.rs:20:9 @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | match enum_struct_variant { | ------------------- this expression has type `()` LL | a::Enum::EnumStructVariant { x, y, z } => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `a::Enum` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `Enum` error: aborting due to 2 previous errors diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr index 560c9c2fbe..09c06e8428 100644 --- a/src/test/ui/block-result/issue-20862.stderr +++ b/src/test/ui/block-result/issue-20862.stderr @@ -7,7 +7,7 @@ LL | |y| x + y | ^^^^^^^^^ expected `()`, found closure | = note: expected unit type `()` - found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]` + found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14]` error[E0618]: expected function, found `()` --> $DIR/issue-20862.rs:7:13 diff --git a/src/test/ui/block-result/issue-22645.stderr b/src/test/ui/block-result/issue-22645.stderr index 79eb1d4b89..6649e67a50 100644 --- a/src/test/ui/block-result/issue-22645.stderr +++ b/src/test/ui/block-result/issue-22645.stderr @@ -6,7 +6,7 @@ LL | b + 3 | = help: the following implementations were found: - = note: required because of the requirements on the impl of `std::ops::Add<{integer}>` for `Bob` + = note: required because of the requirements on the impl of `Add<{integer}>` for `Bob` error[E0308]: mismatched types --> $DIR/issue-22645.rs:15:3 diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index 35ed2763c2..1bf8158927 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -20,7 +20,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:22:5 | LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { - | - move occurs because `x` has type `[std::string::String; 4]`, which does not implement the `Copy` trait + | - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait LL | match x { LL | a @ [.., _] => (), | ----------- value moved here @@ -68,7 +68,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:80:5 | LL | fn bindings_after_at_or_patterns_move(x: Option) { - | - move occurs because `x` has type `std::option::Option`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Option`, which does not implement the `Copy` trait LL | match x { LL | foo @ Some(Test::Foo | Test::Bar) => (), | --------------------------------- @@ -119,7 +119,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:138:5 | LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option; 4]) { - | - move occurs because `x` has type `[std::option::Option; 4]`, which does not implement the `Copy` trait + | - move occurs because `x` has type `[Option; 4]`, which does not implement the `Copy` trait LL | match x { LL | a @ [.., Some(Test::Foo | Test::Bar)] => (), | ------------------------------------- diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs index 75bf320dd5..7a88c3df2e 100644 --- a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs +++ b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs @@ -1,7 +1,7 @@ // Test that attempt to reborrow an `&mut` pointer in an aliasable // location yields an error. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md fn foo(t0: & &mut isize) { let t1 = t0; diff --git a/src/test/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs b/src/test/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs index 2839a9195a..5ef282c0ca 100644 --- a/src/test/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs +++ b/src/test/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs @@ -5,7 +5,7 @@ // Test that freezing an `&mut` pointer while referent is // frozen is legal. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md // pretty-expanded FIXME #23616 diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr index 6f2b20285b..426d5bc472 100644 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | let __isize = &mut x.y; | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:40:19 @@ -12,7 +12,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | let __isize = &mut x.y; | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:48:5 @@ -20,7 +20,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | &mut x.y | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:52:5 @@ -28,7 +28,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | &mut x.y | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:56:5 @@ -36,7 +36,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | x.y = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:60:5 @@ -44,7 +44,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | x.y = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:64:5 @@ -52,7 +52,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | x.y = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:72:5 @@ -60,7 +60,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | x.set(0, 0); | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:76:5 @@ -68,7 +68,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | x.set(0, 0); | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:84:5 @@ -76,7 +76,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | x.y_mut() | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:88:5 @@ -84,7 +84,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | x.y_mut() | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:92:6 @@ -92,7 +92,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | *x.y_mut() = 3; | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:96:6 @@ -100,7 +100,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | *x.y_mut() = 3; | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:100:6 @@ -108,7 +108,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | *x.y_mut() = 3; | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr index 246a7981ae..9ed9d29249 100644 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | let __isize = &mut *x; | ^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-deref.rs:16:19 @@ -12,7 +12,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | let __isize = &mut *x; | ^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-deref.rs:24:5 @@ -20,7 +20,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | &mut **x | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-deref.rs:28:5 @@ -28,7 +28,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | &mut **x | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-deref.rs:32:5 @@ -36,7 +36,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | *x = 3; | ^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-deref.rs:36:5 @@ -44,7 +44,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | **x = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-deref.rs:40:5 @@ -52,7 +52,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | **x = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error: aborting due to 7 previous errors diff --git a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr index 483975e577..7f6c764ec2 100644 --- a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr +++ b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr @@ -30,7 +30,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/borrowck-closures-slice-patterns.rs:25:5 | LL | fn arr_by_move(x: [String; 3]) { - | - move occurs because `x` has type `[std::string::String; 3]`, which does not implement the `Copy` trait + | - move occurs because `x` has type `[String; 3]`, which does not implement the `Copy` trait LL | let f = || { | -- value moved into closure here LL | let [y, z @ ..] = x; @@ -71,7 +71,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/borrowck-closures-slice-patterns.rs:51:5 | LL | fn arr_box_by_move(x: Box<[String; 3]>) { - | - move occurs because `x` has type `std::boxed::Box<[std::string::String; 3]>`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box<[String; 3]>`, which does not implement the `Copy` trait LL | let f = || { | -- value moved into closure here LL | let [y, z @ ..] = *x; diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr index c69237fa95..17b9310661 100644 --- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr +++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `b` --> $DIR/borrowck-consume-unsize-vec.rs:8:13 | LL | fn foo(b: Box<[i32;5]>) { - | - move occurs because `b` has type `std::boxed::Box<[i32; 5]>`, which does not implement the `Copy` trait + | - move occurs because `b` has type `Box<[i32; 5]>`, which does not implement the `Copy` trait LL | consume(b); | - value moved here LL | consume(b); diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr index 356cda01e2..4e20bbf175 100644 --- a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr +++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `b` --> $DIR/borrowck-consume-upcast-box.rs:10:13 | LL | fn foo(b: Box) { - | - move occurs because `b` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `b` has type `Box`, which does not implement the `Copy` trait LL | consume(b); | - value moved here LL | consume(b); diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr index 4144d70cc1..e386aa1f1f 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr @@ -361,7 +361,7 @@ LL | drop(x); LL | drop(x); | ^ value used here after move | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because `x` has type `Vec`, which does not implement the `Copy` trait error: aborting due to 32 previous errors diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr index a2b42fa495..77dda0a32b 100644 --- a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr +++ b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `my_str` --> $DIR/borrowck-drop-from-guard.rs:11:23 | LL | let my_str = "hello".to_owned(); - | ------ move occurs because `my_str` has type `std::string::String`, which does not implement the `Copy` trait + | ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait LL | match Some(42) { LL | Some(_) if { drop(my_str); false } => {} | ------ value moved here diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr index ebdacee7f6..e2c8073241 100644 --- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr +++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr index ebdacee7f6..e2c8073241 100644 --- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr +++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr index 158b2e42f2..f1601336fc 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr @@ -6,7 +6,7 @@ LL | drop(x.b); LL | drop(*x.b); | ^^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:14:10 @@ -16,7 +16,7 @@ LL | let y = A { a: 3, .. x }; LL | drop(*x.b); | ^^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:20:13 @@ -26,7 +26,7 @@ LL | drop(x.b); LL | let p = &x.b; | ^^^^ value borrowed here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:27:13 @@ -36,7 +36,7 @@ LL | let _y = A { a: 3, .. x }; LL | let p = &x.b; | ^^^^ value borrowed here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0505]: cannot move out of `x.b` because it is borrowed --> $DIR/borrowck-field-sensitivity.rs:34:10 @@ -76,7 +76,7 @@ LL | drop(x.b); LL | drop(x.b); | ^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:62:10 @@ -86,7 +86,7 @@ LL | let _y = A { a: 3, .. x }; LL | drop(x.b); | ^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:68:14 @@ -96,7 +96,7 @@ LL | drop(x.b); LL | let _z = A { a: 3, .. x }; | ^^^^^^^^^^^^^^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:74:14 @@ -106,7 +106,7 @@ LL | let _y = A { a: 3, .. x }; LL | let _z = A { a: 4, .. x }; | ^^^^^^^^^^^^^^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/borrowck-field-sensitivity.rs:81:5 diff --git a/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr b/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr index 4c9cfa60ad..e7491afdad 100644 --- a/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr +++ b/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `*x` which is behind a shared reference --> $DIR/borrowck-fn-in-const-a.rs:6:16 | LL | return *x - | ^^ move occurs because `*x` has type `std::string::String`, which does not implement the `Copy` trait + | ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr b/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr index 38e41f315f..2eabc1f1d9 100644 --- a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr +++ b/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr @@ -15,7 +15,7 @@ LL | for &a in &f.a { | -- ^^^^ | || | |data moved here - | |move occurs because `a` has type `std::boxed::Box`, which does not implement the `Copy` trait + | |move occurs because `a` has type `Box`, which does not implement the `Copy` trait | help: consider removing the `&`: `a` error[E0507]: cannot move out of a shared reference @@ -25,7 +25,7 @@ LL | for &a in x.iter() { | -- ^^^^^^^^ | || | |data moved here - | |move occurs because `a` has type `std::boxed::Box`, which does not implement the `Copy` trait + | |move occurs because `a` has type `Box`, which does not implement the `Copy` trait | help: consider removing the `&`: `a` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-in-static.stderr b/src/test/ui/borrowck/borrowck-in-static.stderr index 77d6d7c231..f73c787346 100644 --- a/src/test/ui/borrowck/borrowck-in-static.stderr +++ b/src/test/ui/borrowck/borrowck-in-static.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | Box::new(|| x) - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr index 5880a1abb8..f9ba2ca416 100644 --- a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr +++ b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `*y` which is behind a shared reference LL | let _b = *y; | ^^ | | - | move occurs because `*y` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `*y` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&*y` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr index 0eceaf561b..837bd08253 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr @@ -7,7 +7,7 @@ LL | let _g = to_fn_mut(|| { LL | let _h = to_fn_once(move || -> isize { *bar }); | ^^^^^^^^^^^^^^^^ --- | | | - | | move occurs because `bar` has type `std::boxed::Box`, which does not implement the `Copy` trait + | | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `bar` occurs here diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr index 26de39101f..ead02414a6 100644 --- a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr +++ b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr @@ -34,7 +34,7 @@ LL | n => { | - | | | data moved here - | move occurs because `n` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `n` has type `Box`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr index 7dfae33920..7ac095e808 100644 --- a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `*x` which is behind a raw pointer LL | let y = *x; | ^^ | | - | move occurs because `*x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `*x` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&*x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr index f0a490d359..6b19f9d977 100644 --- a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr +++ b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr @@ -5,7 +5,7 @@ LL | fn arg_item(&_x: &String) {} | ^-- | || | |data moved here - | |move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait + | |move occurs because `_x` has type `String`, which does not implement the `Copy` trait | help: consider removing the `&`: `_x` error[E0507]: cannot move out of a shared reference @@ -15,7 +15,7 @@ LL | with(|&_x| ()) | ^-- | || | |data moved here - | |move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait + | |move occurs because `_x` has type `String`, which does not implement the `Copy` trait | help: consider removing the `&`: `_x` error[E0507]: cannot move out of a shared reference @@ -25,7 +25,7 @@ LL | let &_x = &"hi".to_string(); | --- ^^^^^^^^^^^^^^^^^ | || | |data moved here - | |move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait + | |move occurs because `_x` has type `String`, which does not implement the `Copy` trait | help: consider removing the `&`: `_x` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr index 557e27aae5..44f423c2bd 100644 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr +++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `t` --> $DIR/borrowck-move-moved-value-into-closure.rs:11:12 | LL | let t: Box<_> = box 3; - | - move occurs because `t` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `t` has type `Box`, which does not implement the `Copy` trait LL | LL | call_f(move|| { *t + 1 }); | ------ - variable moved due to use in closure diff --git a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.rs b/src/test/ui/borrowck/borrowck-move-mut-base-ptr.rs index 10fc143725..fa2d5531b1 100644 --- a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.rs +++ b/src/test/ui/borrowck/borrowck-move-mut-base-ptr.rs @@ -1,7 +1,7 @@ // Test that attempt to move `&mut` pointer while pointee is borrowed // yields an error. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs index c1513fcba8..ced4d002b3 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs @@ -20,7 +20,7 @@ fn move_out_from_begin_field_and_end() { [_, _, (_x, _)] => {} } match a { - [.., _y] => {} //~ ERROR use of moved value + [.., _y] => {} //~ ERROR use of partially moved value } } @@ -42,7 +42,7 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _, _] => {} } } @@ -53,7 +53,7 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _, _y @ ..] => {} } } @@ -64,7 +64,7 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _, _] => {} } } @@ -75,7 +75,7 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _, _y @ ..] => {} } } @@ -108,7 +108,7 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr index 84930b000c..3249aae8f4 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr @@ -7,18 +7,18 @@ LL | [_, _, _x] => {} LL | [.., _y] => {} | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a[..]` +error[E0382]: use of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-match.rs:23:14 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here ... LL | [.., _y] => {} | ^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:33:15 @@ -29,51 +29,51 @@ LL | [_, _, (_x, _)] => {} LL | [.., (_y, _)] => {} | ^^ value used here after move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:44:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:55:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:66:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:77:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:89:11 @@ -84,7 +84,7 @@ LL | [_y @ .., _, _] => {} LL | [(_x, _), _, _] => {} | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:99:15 @@ -95,18 +95,18 @@ LL | [_, _, _y @ ..] => {} LL | [.., (_x, _)] => {} | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:110:11 | LL | [x @ .., _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs index 056b8e672b..97db70f34c 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs @@ -15,7 +15,7 @@ fn move_out_from_begin_and_one_from_end() { [_, _, _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., _y, _] => {} } } @@ -26,7 +26,7 @@ fn move_out_from_begin_field_and_end_field() { [_, _, (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (_, _y)] => {} } } @@ -39,7 +39,7 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } @@ -50,7 +50,7 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _] => {} } } @@ -61,7 +61,7 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } @@ -72,7 +72,7 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _] => {} } } @@ -83,7 +83,7 @@ fn move_out_by_const_subslice_and_index_field() { [_, _y @ ..] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [(_x, _), _, _] => {} } } @@ -94,7 +94,7 @@ fn move_out_by_const_subslice_and_end_index_field() { [_y @ .., _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (_x, _)] => {} } } @@ -107,7 +107,7 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr index ff5eab2442..c198002265 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr @@ -1,101 +1,101 @@ -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:17:11 | LL | [_, _, _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:28:11 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:41:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:52:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:63:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:74:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11 | LL | [_, _y @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11 | LL | [_y @ .., _] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11 | LL | [x @ .., _, _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 9 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr index 0ef63105cf..8f2da9d203 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr @@ -7,18 +7,18 @@ LL | [_, _, _x] => {} LL | [.., ref _y] => {} | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a[..]` +error[E0382]: borrow of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:23:14 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here ... LL | [.., ref _y] => {} | ^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-use-match.rs:33:15 @@ -29,51 +29,51 @@ LL | [_, _, (_x, _)] => {} LL | [.., (ref _y, _)] => {} | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:44:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:55:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:66:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:77:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11 @@ -84,7 +84,7 @@ LL | [_y @ .., _, _] => {} LL | [(ref _x, _), _, _] => {} | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15 @@ -95,62 +95,62 @@ LL | [_, _, _y @ ..] => {} LL | [.., (ref _x, _)] => {} | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11 | LL | [x @ .., _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:123:5 | LL | [_, _, _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | a[2] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:131:5 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | a[2].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5 | LL | [_, _, _x @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | a[0] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5 | LL | [_, _, _x @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs index 5afd6835dc..017ca90b81 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs @@ -15,7 +15,7 @@ fn move_out_from_begin_and_one_from_end() { [_, _, _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., ref _y, _] => {} } } @@ -26,7 +26,7 @@ fn move_out_from_begin_field_and_end_field() { [_, _, (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (_, ref _y)] => {} } } @@ -39,7 +39,7 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } @@ -50,7 +50,7 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [ref _y @ .., _] => {} } } @@ -61,7 +61,7 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } @@ -72,7 +72,7 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [ref _y @ .., _] => {} } } @@ -83,7 +83,7 @@ fn move_out_by_const_subslice_and_index_field() { [_, _y @ ..] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [(ref _x, _), _, _] => {} } } @@ -94,7 +94,7 @@ fn move_out_by_const_subslice_and_end_index_field() { [_y @ .., _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (ref _x, _)] => {} } } @@ -107,7 +107,7 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr index a4042ce7db..4b27f03dc4 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr @@ -1,101 +1,101 @@ -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:17:11 | LL | [_, _, _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:28:11 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:41:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:52:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:63:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:74:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11 | LL | [_, _y @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11 | LL | [_y @ .., _] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11 | LL | [x @ .., _, _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 9 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr index 7ad4116645..b0bad6e997 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr @@ -6,17 +6,17 @@ LL | let [_, _, _x] = a; LL | let [.., ref _y] = a; | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a[..]` +error[E0382]: borrow of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:16:14 | LL | let [_, _, (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [.., ref _y] = a; | ^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-use.rs:22:15 @@ -26,47 +26,47 @@ LL | let [_, _, (_x, _)] = a; LL | let [.., (ref _y, _)] = a; | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:30:10 | LL | let [_x, _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [ref _y @ .., _, _] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:36:16 | LL | let [.., _x] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, ref _y @ ..] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:42:10 | LL | let [(_x, _), _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [ref _y @ .., _, _] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:48:16 | LL | let [.., (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, ref _y @ ..] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:54:11 @@ -76,7 +76,7 @@ LL | let [_y @ .., _, _] = a; LL | let [(ref _x, _), _, _] = a; | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:60:15 @@ -86,57 +86,57 @@ LL | let [_, _, _y @ ..] = a; LL | let [.., (ref _x, _)] = a; | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:68:13 | LL | let [x @ .., _] = a; - | ------ value moved here + | ------ value partially moved here LL | let [_, ref _y @ ..] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:76:5 | LL | let [_, _, _x] = a; - | -- value moved here + | -- value partially moved here LL | a[2] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:82:5 | LL | let [_, _, (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | a[2].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:88:5 | LL | let [_, _, _x @ ..] = a; - | ------- value moved here + | ------- value partially moved here LL | a[0] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:94:5 | LL | let [_, _, _x @ ..] = a; - | ------- value moved here + | ------- value partially moved here LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr index b7babd93ed..1fc2b292b8 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr @@ -6,17 +6,17 @@ LL | let [_, _, _x] = a; LL | let [.., _y] = a; | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a[..]` +error[E0382]: use of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array.rs:16:14 | LL | let [_, _, (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [.., _y] = a; | ^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:22:15 @@ -26,47 +26,47 @@ LL | let [_, _, (_x, _)] = a; LL | let [.., (_y, _)] = a; | ^^ value used here after move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:30:10 | LL | let [_x, _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [_y @ .., _, _] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:36:16 | LL | let [.., _x] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, _y @ ..] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:42:10 | LL | let [(_x, _), _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [_y @ .., _, _] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:48:16 | LL | let [.., (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, _y @ ..] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:54:11 @@ -76,7 +76,7 @@ LL | let [_y @ .., _, _] = a; LL | let [(_x, _), _, _] = a; | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:60:15 @@ -86,17 +86,17 @@ LL | let [_, _, _y @ ..] = a; LL | let [.., (_x, _)] = a; | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:68:13 | LL | let [x @ .., _] = a; - | ------ value moved here + | ------ value partially moved here LL | let [_, _y @ ..] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr index 8a94c85ef2..0a29d2bb1d 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of an `Rc` --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14 | LL | let _x = Rc::new(vec![1, 2]).into_iter(); - | ^^^^^^^^^^^^^^^^^^^ move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr index 1501644fac..68994c2071 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of an `Rc` LL | let _x = *Rc::new("hi".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | move occurs because value has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because value has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*Rc::new("hi".to_string())` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr index a2f66f3ec4..7b00ac9f1c 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr @@ -8,7 +8,7 @@ LL | S {f:_s} => {} | -- | | | data moved here - | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:14:20 @@ -17,7 +17,7 @@ LL | let S {f:_s} = S {f:"foo".to_string()}; | -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here | | | data moved here - | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:19 @@ -26,7 +26,7 @@ LL | fn move_in_fn_arg(S {f:_s}: S) { | ^^^^^--^ | | | | | data moved here - | | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | | move occurs because `_s` has type `String`, which does not implement the `Copy` trait | cannot move out of here error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr b/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr index f9a539c1c9..f00181b746 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr @@ -8,7 +8,7 @@ LL | S(_s) => {} | -- | | | data moved here - | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:14:17 @@ -17,7 +17,7 @@ LL | let S(_s) = S("foo".to_string()); | -- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here | | | data moved here - | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:18:19 @@ -26,7 +26,7 @@ LL | fn move_in_fn_arg(S(_s): S) { | ^^--^ | | | | | data moved here - | | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | | move occurs because `_s` has type `String`, which does not implement the `Copy` trait | cannot move out of here error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.stderr index 298482b3c5..e159878619 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.stderr +++ b/src/test/ui/borrowck/borrowck-multiple-captures.stderr @@ -31,7 +31,7 @@ error[E0382]: use of moved value: `x1` --> $DIR/borrowck-multiple-captures.rs:27:19 | LL | let x1: Box<_> = box 1; - | -- move occurs because `x1` has type `std::boxed::Box`, which does not implement the `Copy` trait + | -- move occurs because `x1` has type `Box`, which does not implement the `Copy` trait LL | drop(x1); | -- value moved here ... @@ -45,7 +45,7 @@ error[E0382]: use of moved value: `x2` --> $DIR/borrowck-multiple-captures.rs:27:19 | LL | let x2: Box<_> = box 2; - | -- move occurs because `x2` has type `std::boxed::Box`, which does not implement the `Copy` trait + | -- move occurs because `x2` has type `Box`, which does not implement the `Copy` trait LL | drop(x2); | -- value moved here LL | thread::spawn(move|| { @@ -62,7 +62,7 @@ LL | drop(x); LL | drop(x); | ^ value used here after move | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/borrowck-multiple-captures.rs:38:19 @@ -86,13 +86,13 @@ LL | drop(x); LL | drop(x); | ^ value used here after move | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x` --> $DIR/borrowck-multiple-captures.rs:49:19 | LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | drop(x); | - value moved here LL | thread::spawn(move|| { diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs b/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs index 32caa46647..6174893bae 100644 --- a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs +++ b/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs @@ -1,7 +1,7 @@ // Test that attempt to mutably borrow `&mut` pointer while pointee is // borrowed yields an error. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs index ddc210f9aa..ddf6354c97 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs @@ -18,5 +18,5 @@ fn main() { let v = MyVec::> { data: vec![box 1, box 2, box 3] }; let good = &v[0]; // Shouldn't fail here let bad = v[0]; - //~^ ERROR cannot move out of index of `MyVec>` + //~^ ERROR cannot move out of index of `MyVec>` } diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr index 57f42ede21..2b4293b433 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr @@ -1,10 +1,10 @@ -error[E0507]: cannot move out of index of `MyVec>` +error[E0507]: cannot move out of index of `MyVec>` --> $DIR/borrowck-overloaded-index-move-from-vec.rs:20:15 | LL | let bad = v[0]; | ^^^^ | | - | move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because value has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&v[0]` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr index 5414b01cb0..bacad399eb 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr @@ -26,7 +26,7 @@ error[E0382]: use of moved value: `s` --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 | LL | let mut s = "hello".to_string(); - | ----- move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | ----- move occurs because `s` has type `String`, which does not implement the `Copy` trait ... LL | println!("{}", f[s]); | - value moved here diff --git a/src/test/ui/borrowck/borrowck-reinit.stderr b/src/test/ui/borrowck/borrowck-reinit.stderr index f8f14b6435..22253cd96f 100644 --- a/src/test/ui/borrowck/borrowck-reinit.stderr +++ b/src/test/ui/borrowck/borrowck-reinit.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/borrowck-reinit.rs:6:16 | LL | let mut x = Box::new(0); - | ----- move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ----- move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | drop(x); | - value moved here diff --git a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr index c92c65ba73..af32f27910 100644 --- a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr +++ b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr @@ -14,7 +14,7 @@ LL | let _s2 = T{a: 2, ..s0}; | ^^^^^^^^^^^^^ | | | cannot move out of here - | move occurs because `s0.mv` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `s0.mv` has type `Box`, which does not implement the `Copy` trait error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.rs b/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.rs index 3d40d31922..8170323efc 100644 --- a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.rs +++ b/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.rs @@ -1,7 +1,7 @@ // Test that attempt to swap `&mut` pointer while pointee is borrowed // yields an error. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md use std::mem::swap; diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr index 9f35a4a8d8..7951a5b1b5 100644 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr @@ -14,15 +14,15 @@ LL | let _ = line1.origin.x + 1; | = note: move occurs because `line1.origin` has type `Point`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `line2` +error[E0382]: use of partially moved value: `line2` --> $DIR/borrowck-uninit-field-access.rs:29:5 | LL | let _moved = (line2.origin, line2.middle); - | ------------ value moved here + | ------------ value partially moved here LL | line2.consume(); | ^^^^^ value used here after partial move | - = note: move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait + = note: partial move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr index e2c0852dd8..b4b3bc1ba2 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -22,7 +22,7 @@ LL | LL | _b.use_ref(); | -- borrow later used here -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:34:11 | LL | match vec { @@ -32,7 +32,7 @@ LL | &mut [_a, | -- | | | data moved here - | move occurs because `_a` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `_a` has type `Box`, which does not implement the `Copy` trait | help: consider removing the `&mut` | @@ -44,17 +44,17 @@ LL | .. LL | ] => { | -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:46:13 | LL | let a = vec[0]; | ^^^^^^ | | | cannot move out of here - | move occurs because `vec[_]` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `vec[_]` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&vec[0]` -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:55:11 | LL | match vec { @@ -64,7 +64,7 @@ LL | _b] => {} | -- | | | data moved here - | move occurs because `_b` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `_b` has type `Box`, which does not implement the `Copy` trait | help: consider removing the `&mut` | @@ -73,17 +73,17 @@ LL | LL | _b] => {} | -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:65:13 | LL | let a = vec[0]; | ^^^^^^ | | | cannot move out of here - | move occurs because `vec[_]` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `vec[_]` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&vec[0]` -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:74:11 | LL | match vec { @@ -99,14 +99,14 @@ LL | &mut [_a, _b, _c] => {} | = note: move occurs because these variables have types that don't implement the `Copy` trait -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:85:13 | LL | let a = vec[0]; | ^^^^^^ | | | cannot move out of here - | move occurs because `vec[_]` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `vec[_]` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&vec[0]` error: aborting due to 8 previous errors diff --git a/src/test/ui/borrowck/index-mut-help.stderr b/src/test/ui/borrowck/index-mut-help.stderr index baf649f912..52b9ad496e 100644 --- a/src/test/ui/borrowck/index-mut-help.stderr +++ b/src/test/ui/borrowck/index-mut-help.stderr @@ -1,26 +1,26 @@ -error[E0596]: cannot borrow data in an index of `std::collections::HashMap<&str, std::string::String>` as mutable +error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable --> $DIR/index-mut-help.rs:11:5 | LL | map["peter"].clear(); | ^^^^^^^^^^^^ cannot borrow as mutable | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` -error[E0594]: cannot assign to data in an index of `std::collections::HashMap<&str, std::string::String>` +error[E0594]: cannot assign to data in an index of `HashMap<&str, String>` --> $DIR/index-mut-help.rs:12:5 | LL | map["peter"] = "0".to_string(); | ^^^^^^^^^^^^ cannot assign | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` -error[E0596]: cannot borrow data in an index of `std::collections::HashMap<&str, std::string::String>` as mutable +error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable --> $DIR/index-mut-help.rs:13:13 | LL | let _ = &mut map["peter"]; | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr index ea7df7d5a7..540f7f8a48 100644 --- a/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr +++ b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr index 85c83ec4d7..d33115988a 100644 --- a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr +++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `a` --> $DIR/issue-31287-drop-in-guard.rs:5:9 | LL | let a = Some("...".to_owned()); - | - move occurs because `a` has type `std::option::Option`, which does not implement the `Copy` trait + | - move occurs because `a` has type `Option`, which does not implement the `Copy` trait LL | let b = match a { LL | Some(_) if { drop(a); false } => None, | - value moved here diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr index 604143b4e7..dd3090b30f 100644 --- a/src/test/ui/borrowck/issue-41962.stderr +++ b/src/test/ui/borrowck/issue-41962.stderr @@ -4,7 +4,7 @@ error[E0382]: use of moved value LL | if let Some(thing) = maybe { | ^^^^^ value moved here, in previous iteration of loop | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because value has type `Vec`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `maybe.0` | LL | if let Some(ref thing) = maybe { diff --git a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr b/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr index 249a05192b..eb41af1cea 100644 --- a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr +++ b/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of static item `X` LL | let mut x = X; | ^ | | - | move occurs because `X` has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait + | move occurs because `X` has type `AtomicUsize`, which does not implement the `Copy` trait | help: consider borrowing here: `&X` error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-51415.stderr b/src/test/ui/borrowck/issue-51415.stderr index 96175b1496..a88819efcf 100644 --- a/src/test/ui/borrowck/issue-51415.stderr +++ b/src/test/ui/borrowck/issue-51415.stderr @@ -5,7 +5,7 @@ LL | let opt = a.iter().enumerate().find(|(_, &s)| { | ^^^^^-^ | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr index 3781691ff4..e8a026cfab 100644 --- a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr +++ b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | let _action = move || { | ------- | | | - | | return type of closure is [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15 f:&'2 [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:2:13: 2:23]] + | | return type of closure is [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15] | lifetime `'1` represents this closure's body LL | || f() // The `nested` closure | ^^^^^^ returning this value requires that `'1` must outlive `'2` diff --git a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr index 78d44f3206..1f9cbdb734 100644 --- a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr +++ b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `*array` which is behind a shared reference LL | *array | ^^^^^^ | | - | move occurs because `*array` has type `std::vec::Vec`, which does not implement the `Copy` trait + | move occurs because `*array` has type `Vec`, which does not implement the `Copy` trait | help: consider borrowing here: `&*array` error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index 081ccd3786..fba801983c 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of static item `settings_dir` --> $DIR/issue-64453.rs:14:37 | LL | let settings_data = from_string(settings_dir); - | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants --> $DIR/issue-64453.rs:4:31 diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr index a7cb1c9e22..82c3fe3b12 100644 --- a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -2,25 +2,25 @@ error[E0507]: cannot move out of `*u.a` which is behind a shared reference --> $DIR/move-from-union-field-issue-66500.rs:14:5 | LL | *u.a - | ^^^^ move occurs because `*u.a` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.b` which is behind a mutable reference --> $DIR/move-from-union-field-issue-66500.rs:18:5 | LL | *u.b - | ^^^^ move occurs because `*u.b` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.c` which is behind a raw pointer --> $DIR/move-from-union-field-issue-66500.rs:22:5 | LL | *u.c - | ^^^^ move occurs because `*u.c` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.d` which is behind a raw pointer --> $DIR/move-from-union-field-issue-66500.rs:26:5 | LL | *u.d - | ^^^^ move occurs because `*u.d` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait error: aborting due to 4 previous errors diff --git a/src/test/ui/borrowck/move-in-pattern-mut.rs b/src/test/ui/borrowck/move-in-pattern-mut.rs index 175eb3b7a0..b5c275bf28 100644 --- a/src/test/ui/borrowck/move-in-pattern-mut.rs +++ b/src/test/ui/borrowck/move-in-pattern-mut.rs @@ -15,9 +15,9 @@ fn main() { if let Some(mut x) = s { x = S; } - foo(s); //~ ERROR use of moved value: `s` + foo(s); //~ ERROR use of partially moved value: `s` let mut e = E::V { s: S }; let E::V { s: mut x } = e; x = S; - bar(e); //~ ERROR use of moved value: `e` + bar(e); //~ ERROR use of partially moved value: `e` } diff --git a/src/test/ui/borrowck/move-in-pattern-mut.stderr b/src/test/ui/borrowck/move-in-pattern-mut.stderr index 391638444c..17bc549275 100644 --- a/src/test/ui/borrowck/move-in-pattern-mut.stderr +++ b/src/test/ui/borrowck/move-in-pattern-mut.stderr @@ -1,28 +1,28 @@ -error[E0382]: use of moved value: `s` +error[E0382]: use of partially moved value: `s` --> $DIR/move-in-pattern-mut.rs:18:9 | LL | if let Some(mut x) = s { - | ----- value moved here + | ----- value partially moved here ... LL | foo(s); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `s.0` | LL | if let Some(ref mut x) = s { | ^^^ -error[E0382]: use of moved value: `e` +error[E0382]: use of partially moved value: `e` --> $DIR/move-in-pattern-mut.rs:22:9 | LL | let E::V { s: mut x } = e; - | ----- value moved here + | ----- value partially moved here LL | x = S; LL | bar(e); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `e.s` | LL | let E::V { s: ref mut x } = e; diff --git a/src/test/ui/borrowck/move-in-pattern.fixed b/src/test/ui/borrowck/move-in-pattern.fixed index f55fdcc5f9..145893d334 100644 --- a/src/test/ui/borrowck/move-in-pattern.fixed +++ b/src/test/ui/borrowck/move-in-pattern.fixed @@ -16,9 +16,9 @@ fn main() { if let Some(ref x) = s { let _ = x; } - foo(s); //~ ERROR use of moved value: `s` + foo(s); //~ ERROR use of partially moved value: `s` let e = E::V { s: S }; let E::V { s: ref x } = e; let _ = x; - bar(e); //~ ERROR use of moved value: `e` + bar(e); //~ ERROR use of partially moved value: `e` } diff --git a/src/test/ui/borrowck/move-in-pattern.rs b/src/test/ui/borrowck/move-in-pattern.rs index 7ad04b9490..14851d0f6f 100644 --- a/src/test/ui/borrowck/move-in-pattern.rs +++ b/src/test/ui/borrowck/move-in-pattern.rs @@ -16,9 +16,9 @@ fn main() { if let Some(x) = s { let _ = x; } - foo(s); //~ ERROR use of moved value: `s` + foo(s); //~ ERROR use of partially moved value: `s` let e = E::V { s: S }; let E::V { s: x } = e; let _ = x; - bar(e); //~ ERROR use of moved value: `e` + bar(e); //~ ERROR use of partially moved value: `e` } diff --git a/src/test/ui/borrowck/move-in-pattern.stderr b/src/test/ui/borrowck/move-in-pattern.stderr index c5cb24455e..21ba92f1fc 100644 --- a/src/test/ui/borrowck/move-in-pattern.stderr +++ b/src/test/ui/borrowck/move-in-pattern.stderr @@ -1,28 +1,28 @@ -error[E0382]: use of moved value: `s` +error[E0382]: use of partially moved value: `s` --> $DIR/move-in-pattern.rs:19:9 | LL | if let Some(x) = s { - | - value moved here + | - value partially moved here ... LL | foo(s); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `s.0` | LL | if let Some(ref x) = s { | ^^^ -error[E0382]: use of moved value: `e` +error[E0382]: use of partially moved value: `e` --> $DIR/move-in-pattern.rs:23:9 | LL | let E::V { s: x } = e; - | - value moved here + | - value partially moved here LL | let _ = x; LL | bar(e); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `e.s` | LL | let E::V { s: ref x } = e; diff --git a/src/test/ui/borrowck/or-patterns.stderr b/src/test/ui/borrowck/or-patterns.stderr index d3f3544426..9593b94537 100644 --- a/src/test/ui/borrowck/or-patterns.stderr +++ b/src/test/ui/borrowck/or-patterns.stderr @@ -7,7 +7,7 @@ LL | } LL | &x.0 .0; | ^^^^^^^ value borrowed here after move | - = note: move occurs because `x.0.0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `x.0.1` --> $DIR/or-patterns.rs:12:5 @@ -18,7 +18,7 @@ LL | ((y, _) | (_, y),) => (), LL | &x.0 .1; | ^^^^^^^ value borrowed here after move | - = note: move occurs because `x.0.1` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable --> $DIR/or-patterns.rs:20:5 @@ -76,7 +76,7 @@ LL | let ((y, _) | (_, y),) = x; LL | &x.0 .0; | ^^^^^^^ value borrowed here after move | - = note: move occurs because `x.0.0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `x.0.1` --> $DIR/or-patterns.rs:42:5 @@ -87,7 +87,7 @@ LL | let ((y, _) | (_, y),) = x; LL | &x.0 .1; | ^^^^^^^ value borrowed here after move | - = note: move occurs because `x.0.1` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable --> $DIR/or-patterns.rs:48:5 diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr index 21ae25c16b..50d277a12f 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr @@ -11,7 +11,7 @@ error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:59:11 | LL | fn twice_ten_so i32>(f: Box) { - | - move occurs because `f` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `f` has type `Box`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | @@ -30,7 +30,7 @@ error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:73:11 | LL | fn twice_ten_oo(f: Box i32>) { - | - move occurs because `f` has type `std::boxed::Box i32>`, which does not implement the `Copy` trait + | - move occurs because `f` has type `Box i32>`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index 73cea6fc36..dbba33f018 100644 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -5,7 +5,7 @@ LL | let y = vec![format!("World")]; | - captured outer variable LL | call(|| { LL | y.into_iter(); - | ^ move occurs because `y` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^ move occurs because `y` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/bound-suggestions.fixed b/src/test/ui/bound-suggestions.fixed index 9c98200db5..a3fe67a959 100644 --- a/src/test/ui/bound-suggestions.fixed +++ b/src/test/ui/bound-suggestions.fixed @@ -1,37 +1,41 @@ // run-rustfix +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + #[allow(dead_code)] -fn test_impl(t: impl Sized + std::fmt::Debug) { +fn test_impl(t: impl Sized + Debug) { println!("{:?}", t); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_no_bounds(t: T) { +fn test_no_bounds(t: T) { println!("{:?}", t); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_one_bound(t: T) { +fn test_one_bound(t: T) { println!("{:?}", t); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug, Y: std::fmt::Debug { +fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug, Y: Debug { println!("{:?} {:?}", x, y); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_one_bound_where(x: X) where X: Sized + std::fmt::Debug { +fn test_one_bound_where(x: X) where X: Sized + Debug { println!("{:?}", x); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: std::fmt::Debug { +fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: Debug { println!("{:?}", x); //~^ ERROR doesn't implement } diff --git a/src/test/ui/bound-suggestions.rs b/src/test/ui/bound-suggestions.rs index 562dec9f08..de6133d7f5 100644 --- a/src/test/ui/bound-suggestions.rs +++ b/src/test/ui/bound-suggestions.rs @@ -1,5 +1,9 @@ // run-rustfix +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + #[allow(dead_code)] fn test_impl(t: impl Sized) { println!("{:?}", t); diff --git a/src/test/ui/bound-suggestions.stderr b/src/test/ui/bound-suggestions.stderr index 623252a8c1..010f95d8ad 100644 --- a/src/test/ui/bound-suggestions.stderr +++ b/src/test/ui/bound-suggestions.stderr @@ -1,80 +1,80 @@ -error[E0277]: `impl Sized` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:5:22 +error[E0277]: `impl Sized` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:9:22 | LL | println!("{:?}", t); - | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound | -LL | fn test_impl(t: impl Sized + std::fmt::Debug) { - | ^^^^^^^^^^^^^^^^^ +LL | fn test_impl(t: impl Sized + Debug) { + | ^^^^^^^ -error[E0277]: `T` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:11:22 +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:15:22 | LL | println!("{:?}", t); - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | -LL | fn test_no_bounds(t: T) { - | ^^^^^^^^^^^^^^^^^ +LL | fn test_no_bounds(t: T) { + | ^^^^^^^ -error[E0277]: `T` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:17:22 +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:21:22 | LL | println!("{:?}", t); - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound | -LL | fn test_one_bound(t: T) { - | ^^^^^^^^^^^^^^^^^ +LL | fn test_one_bound(t: T) { + | ^^^^^^^ -error[E0277]: `Y` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:23:30 +error[E0277]: `Y` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:27:30 | LL | println!("{:?} {:?}", x, y); - | ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `Y` | -LL | fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug, Y: std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug, Y: Debug { + | ^^^^^^^^^^ -error[E0277]: `X` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:29:22 +error[E0277]: `X` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:33:22 | LL | println!("{:?}", x); - | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound | -LL | fn test_one_bound_where(x: X) where X: Sized + std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^ +LL | fn test_one_bound_where(x: X) where X: Sized + Debug { + | ^^^^^^^ -error[E0277]: `X` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:35:22 +error[E0277]: `X` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:39:22 | LL | println!("{:?}", x); - | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` | -LL | fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: Debug { + | ^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/box-into-boxed-slice-fail.rs b/src/test/ui/box-into-boxed-slice-fail.rs index 5f8a3fd9d6..49dbb170f8 100644 --- a/src/test/ui/box-into-boxed-slice-fail.rs +++ b/src/test/ui/box-into-boxed-slice-fail.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength #![feature(box_into_boxed_slice)] use std::boxed::Box; @@ -10,6 +9,6 @@ fn main() { //~^^ ERROR the size for values of type `[u8]` cannot be known at compilation time let boxed_trait: Box = Box::new(5u8); let _ = Box::into_boxed_slice(boxed_trait); - //~^ ERROR the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time - //~^^ ERROR the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time + //~^ ERROR the size for values of type `dyn Debug` cannot be known at compilation time + //~^^ ERROR the size for values of type `dyn Debug` cannot be known at compilation time } diff --git a/src/test/ui/box-into-boxed-slice-fail.stderr b/src/test/ui/box-into-boxed-slice-fail.stderr index b3e7b5b4fe..8cfa3668d9 100644 --- a/src/test/ui/box-into-boxed-slice-fail.stderr +++ b/src/test/ui/box-into-boxed-slice-fail.stderr @@ -1,37 +1,37 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/box-into-boxed-slice-fail.rs:8:35 + --> $DIR/box-into-boxed-slice-fail.rs:7:35 | LL | let _ = Box::into_boxed_slice(boxed_slice); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: required by `std::boxed::Box::::into_boxed_slice` + = help: the trait `Sized` is not implemented for `[u8]` + = note: required by `Box::::into_boxed_slice` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/box-into-boxed-slice-fail.rs:8:13 + --> $DIR/box-into-boxed-slice-fail.rs:7:13 | LL | let _ = Box::into_boxed_slice(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: slice and array elements must have `Sized` type -error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time - --> $DIR/box-into-boxed-slice-fail.rs:12:35 +error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time + --> $DIR/box-into-boxed-slice-fail.rs:11:35 | LL | let _ = Box::into_boxed_slice(boxed_trait); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug` - = note: required by `std::boxed::Box::::into_boxed_slice` + = help: the trait `Sized` is not implemented for `dyn Debug` + = note: required by `Box::::into_boxed_slice` -error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time - --> $DIR/box-into-boxed-slice-fail.rs:12:13 +error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time + --> $DIR/box-into-boxed-slice-fail.rs:11:13 | LL | let _ = Box::into_boxed_slice(boxed_trait); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug` + = help: the trait `Sized` is not implemented for `dyn Debug` = note: slice and array elements must have `Sized` type error: aborting due to 4 previous errors diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr index 7ff986ec38..7e8ac113b4 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr @@ -10,8 +10,8 @@ LL | impl Foo for (T,) { } = note: required because it appears within the type `(T,)` help: consider further restricting this bound | -LL | impl Foo for (T,) { } - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for (T,) { } + | ^^^^^^ error[E0277]: `T` cannot be shared between threads safely --> $DIR/builtin-superkinds-double-superkind.rs:9:16 @@ -25,8 +25,8 @@ LL | impl Foo for (T,T) { } = note: required because it appears within the type `(T, T)` help: consider further restricting this bound | -LL | impl Foo for (T,T) { } - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for (T,T) { } + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr index 9ee045edfe..2b4b6e548b 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr @@ -7,13 +7,13 @@ LL | impl RequiresRequiresShareAndSend for X { } ::: $DIR/auxiliary/trait_superkinds_in_metadata.rs:7:58 | LL | pub trait RequiresRequiresShareAndSend : RequiresShare + Send { } - | ---- required by this bound in `trait_superkinds_in_metadata::RequiresRequiresShareAndSend` + | ---- required by this bound in `RequiresRequiresShareAndSend` | = note: required because it appears within the type `X` help: consider further restricting this bound | -LL | impl RequiresRequiresShareAndSend for X { } - | ^^^^^^^^^^^^^^^^^^^ +LL | impl RequiresRequiresShareAndSend for X { } + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-simple.rs b/src/test/ui/builtin-superkinds/builtin-superkinds-simple.rs index afafc09438..1620f8d5cf 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-simple.rs +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-simple.rs @@ -4,6 +4,6 @@ trait Foo : Send { } impl Foo for std::rc::Rc { } -//~^ ERROR `std::rc::Rc` cannot be sent between threads safely +//~^ ERROR `Rc` cannot be sent between threads safely fn main() { } diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-simple.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-simple.stderr index 592cc3b1c4..0abe2052b2 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-simple.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-simple.stderr @@ -1,13 +1,13 @@ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/builtin-superkinds-simple.rs:6:6 | LL | trait Foo : Send { } | ---- required by this bound in `Foo` LL | LL | impl Foo for std::rc::Rc { } - | ^^^ `std::rc::Rc` cannot be sent between threads safely + | ^^^ `Rc` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc` + = help: the trait `Send` is not implemented for `Rc` error: aborting due to previous error diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr index ad80b3fa8d..ff2cd1c4c8 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr @@ -9,8 +9,8 @@ LL | impl Foo for T { } | help: consider further restricting this bound | -LL | impl Foo for T { } - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for T { } + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/by-move-pattern-binding.stderr b/src/test/ui/by-move-pattern-binding.stderr index 1db4e2a66d..0012f67cfa 100644 --- a/src/test/ui/by-move-pattern-binding.stderr +++ b/src/test/ui/by-move-pattern-binding.stderr @@ -8,7 +8,7 @@ LL | &E::Bar(identifier) => f(identifier.clone()) | ------------------- | | | | | data moved here - | | move occurs because `identifier` has type `std::string::String`, which does not implement the `Copy` trait + | | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait | help: consider removing the `&`: `E::Bar(identifier)` error: aborting due to previous error diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index 6562350156..dd67514d02 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -2,7 +2,7 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 | LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `core::ffi::VaListImpl<'1>` + | -- -- has type `VaListImpl<'1>` | | | lifetime `'f` defined here LL | ap @@ -12,7 +12,7 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 | LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `core::ffi::VaListImpl<'1>` + | -- -- has type `VaListImpl<'1>` | | | lifetime `'f` defined here LL | ap @@ -22,7 +22,7 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:14:5 | LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - | -- has type `core::ffi::VaListImpl<'1>` + | -- has type `VaListImpl<'1>` LL | ap | ^^ returning this value requires that `'1` must outlive `'static` @@ -32,16 +32,16 @@ error: lifetime may not live long enough LL | let _ = ap.with_copy(|ap| ap); | --- ^^ returning this value requires that `'1` must outlive `'2` | | | - | | return type of closure is core::ffi::VaList<'2, '_> - | has type `core::ffi::VaList<'1, '_>` + | | return type of closure is VaList<'2, '_> + | has type `VaList<'1, '_>` error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 | LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1; | ^^^^ assignment requires that `'1` must outlive `'2` @@ -49,9 +49,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 | LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1; | ^^^^ assignment requires that `'2` must outlive `'1` @@ -59,9 +59,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:28:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` @@ -69,9 +69,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:28:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` @@ -93,9 +93,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:35:12 | LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1.clone(); | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` @@ -103,9 +103,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:35:12 | LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1.clone(); | ^^^^^^^^^^^ argument requires that `'2` must outlive `'1` diff --git a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr index 9b86f8d4de..3b5b8ea69c 100644 --- a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr +++ b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr @@ -1,4 +1,4 @@ -error[E0620]: cast to unsized type: `&{integer}` as `dyn std::marker::Send` +error[E0620]: cast to unsized type: `&{integer}` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:2:5 | LL | &1 as dyn Send; @@ -6,7 +6,7 @@ LL | &1 as dyn Send; | | | help: try casting to a reference instead: `&dyn Send` -error[E0620]: cast to unsized type: `std::boxed::Box<{integer}>` as `dyn std::marker::Send` +error[E0620]: cast to unsized type: `Box<{integer}>` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5 | LL | Box::new(1) as dyn Send; diff --git a/src/test/ui/casts-differing-anon.stderr b/src/test/ui/casts-differing-anon.stderr index fbbb8e3bb3..a30e9b35f5 100644 --- a/src/test/ui/casts-differing-anon.stderr +++ b/src/test/ui/casts-differing-anon.stderr @@ -1,4 +1,4 @@ -error[E0606]: casting `*mut impl std::fmt::Debug+?Sized` as `*mut impl std::fmt::Debug+?Sized` is invalid +error[E0606]: casting `*mut impl Debug+?Sized` as `*mut impl Debug+?Sized` is invalid --> $DIR/casts-differing-anon.rs:21:13 | LL | b_raw = f_raw as *mut _; diff --git a/src/test/ui/cell-does-not-clone.rs b/src/test/ui/cell-does-not-clone.rs deleted file mode 100644 index 587447b54b..0000000000 --- a/src/test/ui/cell-does-not-clone.rs +++ /dev/null @@ -1,26 +0,0 @@ -// run-pass - -#![allow(dead_code)] - -use std::cell::Cell; - -#[derive(Copy)] -struct Foo { - x: isize -} - -impl Clone for Foo { - fn clone(&self) -> Foo { - // Using Cell in any way should never cause clone() to be - // invoked -- after all, that would permit evil user code to - // abuse `Cell` and trigger crashes. - - panic!(); - } -} - -pub fn main() { - let x = Cell::new(Foo { x: 22 }); - let _y = x.get(); - let _z = x.clone(); -} diff --git a/src/test/ui/chalkify/generic_impls.stderr b/src/test/ui/chalkify/generic_impls.stderr index 4ac57a2f13..a6f5d1a608 100644 --- a/src/test/ui/chalkify/generic_impls.stderr +++ b/src/test/ui/chalkify/generic_impls.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `(std::option::Option, f32): Foo` is not satisfied +error[E0277]: the trait bound `(Option, f32): Foo` is not satisfied --> $DIR/generic_impls.rs:12:13 | LL | fn gimme() { } | --- required by this bound in `gimme` ... LL | gimme::<(Option, f32)>(); - | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(std::option::Option, f32)` + | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(Option, f32)` | = help: the following implementations were found: <(T, u32) as Foo> diff --git a/src/test/ui/chalkify/impl_wf.stderr b/src/test/ui/chalkify/impl_wf.stderr index fb2e0fc1a6..4ca5ae472f 100644 --- a/src/test/ui/chalkify/impl_wf.stderr +++ b/src/test/ui/chalkify/impl_wf.stderr @@ -7,7 +7,7 @@ LL | trait Foo: Sized { } LL | impl Foo for str { } | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` error[E0277]: the trait bound `f32: Foo` is not satisfied --> $DIR/impl_wf.rs:27:17 diff --git a/src/test/ui/chalkify/type_inference.rs b/src/test/ui/chalkify/type_inference.rs index 2b62bf18a7..369777a790 100644 --- a/src/test/ui/chalkify/type_inference.rs +++ b/src/test/ui/chalkify/type_inference.rs @@ -24,5 +24,5 @@ fn main() { // Here we have two solutions so we get back the behavior of the old-style // trait solver. - only_bar(x); //~ ERROR the trait bound `f64: Bar` is not satisfied + only_bar(x); //~ ERROR the trait bound `{float}: Bar` is not satisfied } diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index 5cfb968404..91c46b9531 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -1,11 +1,15 @@ -error[E0277]: the trait bound `f64: Bar` is not satisfied - --> $DIR/type_inference.rs:27:5 +error[E0277]: the trait bound `{float}: Bar` is not satisfied + --> $DIR/type_inference.rs:27:14 | LL | fn only_bar(_x: T) { } | --- required by this bound in `only_bar` ... LL | only_bar(x); - | ^^^^^^^^ the trait `Bar` is not implemented for `f64` + | ^ the trait `Bar` is not implemented for `{float}` + | + = help: the following implementations were found: + + error: aborting due to previous error diff --git a/src/test/ui/chalkify/type_wf.rs b/src/test/ui/chalkify/type_wf.rs index 7c469d99c5..dd83a03fdf 100644 --- a/src/test/ui/chalkify/type_wf.rs +++ b/src/test/ui/chalkify/type_wf.rs @@ -15,7 +15,7 @@ fn main() { x: 5, }; - let s = S { //~ ERROR the trait bound `f64: Foo` is not satisfied + let s = S { //~ ERROR the trait bound `{float}: Foo` is not satisfied x: 5.0, }; diff --git a/src/test/ui/chalkify/type_wf.stderr b/src/test/ui/chalkify/type_wf.stderr index ab585a6ed2..3cd6036945 100644 --- a/src/test/ui/chalkify/type_wf.stderr +++ b/src/test/ui/chalkify/type_wf.stderr @@ -1,11 +1,15 @@ -error[E0277]: the trait bound `f64: Foo` is not satisfied +error[E0277]: the trait bound `{float}: Foo` is not satisfied --> $DIR/type_wf.rs:18:13 | LL | struct S { | ---------------- required by `S` ... LL | let s = S { - | ^ the trait `Foo` is not implemented for `f64` + | ^ the trait `Foo` is not implemented for `{float}` + | + = help: the following implementations were found: + as Foo> + error: aborting due to previous error diff --git a/src/test/ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs index b02cc1a454..c8bec39fad 100644 --- a/src/test/ui/check-doc-alias-attr.rs +++ b/src/test/ui/check-doc-alias-attr.rs @@ -7,4 +7,10 @@ pub struct Bar; #[doc(alias)] //~ ERROR #[doc(alias = 0)] //~ ERROR #[doc(alias("bar"))] //~ ERROR +#[doc(alias = "\"")] //~ ERROR +#[doc(alias = "\n")] //~ ERROR +#[doc(alias = " +")] //~^ ERROR +#[doc(alias = " ")] //~ ERROR +#[doc(alias = "\t")] //~ ERROR pub struct Foo; diff --git a/src/test/ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr index 268230ab44..be7d7b3dbe 100644 --- a/src/test/ui/check-doc-alias-attr.stderr +++ b/src/test/ui/check-doc-alias-attr.stderr @@ -16,5 +16,37 @@ error: doc alias attribute expects a string: #[doc(alias = "0")] LL | #[doc(alias("bar"))] | ^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: '\"' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:10:7 + | +LL | #[doc(alias = "\"")] + | ^^^^^^^^^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:11:7 + | +LL | #[doc(alias = "\n")] + | ^^^^^^^^^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:12:7 + | +LL | #[doc(alias = " + | _______^ +LL | | ")] + | |_^ + +error: ' ' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:14:7 + | +LL | #[doc(alias = " ")] + | ^^^^^^^^^^^ + +error: '\t' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:15:7 + | +LL | #[doc(alias = "\t")] + | ^^^^^^^^^^^^ + +error: aborting due to 8 previous errors diff --git a/src/test/ui/check-static-recursion-foreign.rs b/src/test/ui/check-static-recursion-foreign.rs index 8ca0af8e47..3072deb6c5 100644 --- a/src/test/ui/check-static-recursion-foreign.rs +++ b/src/test/ui/check-static-recursion-foreign.rs @@ -1,6 +1,5 @@ // run-pass -#![allow(dead_code)] // Static recursion check shouldn't fail when given a foreign item (#18279) // aux-build:check_static_recursion_foreign_helper.rs @@ -15,12 +14,10 @@ extern crate libc; use libc::c_int; -#[link_name = "check_static_recursion_foreign_helper"] extern "C" { - #[allow(dead_code)] static test_static: c_int; } -static B: &'static c_int = unsafe { &test_static }; +pub static B: &'static c_int = unsafe { &test_static }; pub fn main() {} diff --git a/src/test/ui/check-static-values-constraints.rs b/src/test/ui/check-static-values-constraints.rs index acfb3b5e44..3d1b5a0822 100644 --- a/src/test/ui/check-static-values-constraints.rs +++ b/src/test/ui/check-static-values-constraints.rs @@ -78,7 +78,6 @@ struct MyOwned; static STATIC11: Box = box MyOwned; //~^ ERROR allocations are not allowed in statics -//~| ERROR static contains unimplemented expression type static mut STATIC12: UnsafeStruct = UnsafeStruct; @@ -93,16 +92,12 @@ static mut STATIC14: SafeStruct = SafeStruct { static STATIC15: &'static [Box] = &[ box MyOwned, //~ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression box MyOwned, //~ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression ]; static STATIC16: (&'static Box, &'static Box) = ( &box MyOwned, //~ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression &box MyOwned, //~ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression ); static mut STATIC17: SafeEnum = SafeEnum::Variant1; @@ -110,11 +105,9 @@ static mut STATIC17: SafeEnum = SafeEnum::Variant1; static STATIC19: Box = box 3; //~^ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression pub fn main() { let y = { static x: Box = box 3; x }; //~^ ERROR allocations are not allowed in statics //~| ERROR cannot move out of static item - //~| ERROR contains unimplemented expression } diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr index b00affdca8..eb640c88e0 100644 --- a/src/test/ui/check-static-values-constraints.stderr +++ b/src/test/ui/check-static-values-constraints.stderr @@ -15,114 +15,58 @@ error[E0010]: allocations are not allowed in statics LL | static STATIC11: Box = box MyOwned; | ^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:79:37 - | -LL | static STATIC11: Box = box MyOwned; - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/check-static-values-constraints.rs:90:32 + --> $DIR/check-static-values-constraints.rs:89:32 | LL | field2: SafeEnum::Variant4("str".to_string()) | ^^^^^^^^^^^^^^^^^ error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:95:5 + --> $DIR/check-static-values-constraints.rs:94:5 | LL | box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:95:9 - | -LL | box MyOwned, - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:97:5 + --> $DIR/check-static-values-constraints.rs:95:5 | LL | box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:97:9 - | -LL | box MyOwned, - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:102:6 + --> $DIR/check-static-values-constraints.rs:99:6 | LL | &box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:102:10 - | -LL | &box MyOwned, - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:104:6 + --> $DIR/check-static-values-constraints.rs:100:6 | LL | &box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:104:10 - | -LL | &box MyOwned, - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:111:5 + --> $DIR/check-static-values-constraints.rs:106:5 | LL | box 3; | ^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:111:9 - | -LL | box 3; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0507]: cannot move out of static item `x` - --> $DIR/check-static-values-constraints.rs:116:45 + --> $DIR/check-static-values-constraints.rs:110:45 | LL | let y = { static x: Box = box 3; x }; | ^ | | - | move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `x` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&x` error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:116:38 + --> $DIR/check-static-values-constraints.rs:110:38 | LL | let y = { static x: Box = box 3; x }; | ^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:116:42 - | -LL | let y = { static x: Box = box 3; x }; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error: aborting due to 17 previous errors +error: aborting due to 10 previous errors -Some errors have detailed explanations: E0010, E0015, E0019, E0493, E0507. +Some errors have detailed explanations: E0010, E0015, E0493, E0507. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/class-cast-to-trait.stderr b/src/test/ui/class-cast-to-trait.stderr index 0f932cda07..56d10d88d8 100644 --- a/src/test/ui/class-cast-to-trait.stderr +++ b/src/test/ui/class-cast-to-trait.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `eat` found for struct `std::boxed::Box` in the current scope +error[E0599]: no method named `eat` found for struct `Box` in the current scope --> $DIR/class-cast-to-trait.rs:53:8 | LL | nyan.eat(); - | ^^^ method not found in `std::boxed::Box` + | ^^^ method not found in `Box` error: aborting due to previous error diff --git a/src/test/ui/closure-expected.rs b/src/test/ui/closure-expected.rs index 9b15a63da2..68cac3dd85 100644 --- a/src/test/ui/closure-expected.rs +++ b/src/test/ui/closure-expected.rs @@ -1,5 +1,5 @@ fn main() { let x = Some(1); let y = x.or_else(4); - //~^ ERROR expected a `std::ops::FnOnce<()>` closure, found `{integer}` + //~^ ERROR expected a `FnOnce<()>` closure, found `{integer}` } diff --git a/src/test/ui/closure-expected.stderr b/src/test/ui/closure-expected.stderr index 687dd97ca6..6c77d08096 100644 --- a/src/test/ui/closure-expected.stderr +++ b/src/test/ui/closure-expected.stderr @@ -1,10 +1,10 @@ -error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `{integer}` +error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` --> $DIR/closure-expected.rs:3:23 | LL | let y = x.or_else(4); | ^ expected an `FnOnce<()>` closure, found `{integer}` | - = help: the trait `std::ops::FnOnce<()>` is not implemented for `{integer}` + = help: the trait `FnOnce<()>` is not implemented for `{integer}` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` error: aborting due to previous error diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr index 273eae9955..48f18b1ebe 100644 --- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr +++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr @@ -9,8 +9,8 @@ LL | fn foo(blk: F) -> X where F: FnOnce() + 'static { | help: consider further restricting this bound | -LL | fn foo(blk: F) -> X where F: FnOnce() + 'static + std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo(blk: F) -> X where F: FnOnce() + 'static + Send { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr index 7df29d5a09..d649eeccb8 100644 --- a/src/test/ui/closures/closure-bounds-subtype.stderr +++ b/src/test/ui/closures/closure-bounds-subtype.stderr @@ -9,8 +9,8 @@ LL | take_const_owned(f); | help: consider further restricting this bound | -LL | fn give_owned(f: F) where F: FnOnce() + Send + std::marker::Sync { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn give_owned(f: F) where F: FnOnce() + Send + Sync { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/closures/closure-move-sync.rs b/src/test/ui/closures/closure-move-sync.rs index 580cd1af4f..ea2d1434c4 100644 --- a/src/test/ui/closures/closure-move-sync.rs +++ b/src/test/ui/closures/closure-move-sync.rs @@ -16,7 +16,7 @@ fn bar() { fn foo() { let (tx, _rx) = channel(); thread::spawn(|| tx.send(()).unwrap()); - //~^ ERROR `std::sync::mpsc::Sender<()>` cannot be shared between threads safely + //~^ ERROR `Sender<()>` cannot be shared between threads safely } fn main() {} diff --git a/src/test/ui/closures/closure-move-sync.stderr b/src/test/ui/closures/closure-move-sync.stderr index f4d08ea5b8..da5e25c0d1 100644 --- a/src/test/ui/closures/closure-move-sync.stderr +++ b/src/test/ui/closures/closure-move-sync.stderr @@ -7,26 +7,26 @@ LL | let t = thread::spawn(|| { ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL | LL | F: Send + 'static, - | ---- required by this bound in `std::thread::spawn` + | ---- required by this bound in `spawn` | - = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<()>` - = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Receiver<()>` - = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6 recv:&std::sync::mpsc::Receiver<()>]` + = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>` + = note: required because of the requirements on the impl of `Send` for `&std::sync::mpsc::Receiver<()>` + = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6]` -error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads safely +error[E0277]: `Sender<()>` cannot be shared between threads safely --> $DIR/closure-move-sync.rs:18:5 | LL | thread::spawn(|| tx.send(()).unwrap()); - | ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared between threads safely + | ^^^^^^^^^^^^^ `Sender<()>` cannot be shared between threads safely | ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL | LL | F: Send + 'static, - | ---- required by this bound in `std::thread::spawn` + | ---- required by this bound in `spawn` | - = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>` - = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<()>` - = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42 tx:&std::sync::mpsc::Sender<()>]` + = help: the trait `Sync` is not implemented for `Sender<()>` + = note: required because of the requirements on the impl of `Send` for `&Sender<()>` + = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42]` error: aborting due to 2 previous errors diff --git a/src/test/ui/closures/closure-no-fn-1.stderr b/src/test/ui/closures/closure-no-fn-1.stderr index 5e76ee5a9a..76136315a1 100644 --- a/src/test/ui/closures/closure-no-fn-1.stderr +++ b/src/test/ui/closures/closure-no-fn-1.stderr @@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; | expected due to this | = note: expected fn pointer `fn(u8) -> u8` - found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:50 a:_]` + found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:50]` error: aborting due to previous error diff --git a/src/test/ui/closures/closure-no-fn-2.stderr b/src/test/ui/closures/closure-no-fn-2.stderr index 07ffd6e5c9..85cbdbe7c1 100644 --- a/src/test/ui/closures/closure-no-fn-2.stderr +++ b/src/test/ui/closures/closure-no-fn-2.stderr @@ -7,7 +7,7 @@ LL | let bar: fn() -> u8 = || { b }; | expected due to this | = note: expected fn pointer `fn() -> u8` - found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:35 b:_]` + found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:35]` error: aborting due to previous error diff --git a/src/test/ui/closures/closure-no-fn-3.stderr b/src/test/ui/closures/closure-no-fn-3.stderr index 4b3b4be798..95683a786b 100644 --- a/src/test/ui/closures/closure-no-fn-3.stderr +++ b/src/test/ui/closures/closure-no-fn-3.stderr @@ -1,4 +1,4 @@ -error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37 b:_]` as `fn() -> u8` +error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37]` as `fn() -> u8` --> $DIR/closure-no-fn-3.rs:6:27 | LL | let baz: fn() -> u8 = (|| { b }) as fn() -> u8; diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr index 3c4ae45076..77c8c7ab79 100644 --- a/src/test/ui/closures/closure-reform-bad.stderr +++ b/src/test/ui/closures/closure-reform-bad.stderr @@ -7,7 +7,7 @@ LL | call_bare(f) | ^ expected fn pointer, found closure | = note: expected fn pointer `for<'r> fn(&'r str)` - found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:50 string:_]` + found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:50]` error: aborting due to previous error diff --git a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr index 63eb0bd8fa..bd2e31648c 100644 --- a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr +++ b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____- `match` arms have incompatible types | = note: expected type `fn(i32, i32) -> i32 {add}` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43 cap:_]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43]` error[E0308]: `match` arms have incompatible types --> $DIR/closure_cap_coerce_many_fail.rs:18:16 @@ -28,7 +28,7 @@ LL | | }; | |_____- `match` arms have incompatible types | = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43 cap:_]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object @@ -38,14 +38,14 @@ error[E0308]: `match` arms have incompatible types LL | let _ = match "+" { | _____________- LL | | "+" => |a, b| (a + b + cap) as i32, - | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]` + | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]` LL | | "-" => |a, b| (a - b) as i32, | | ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure LL | | _ => unimplemented!(), LL | | }; | |_____- `match` arms have incompatible types | - = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]` + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]` found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object @@ -56,15 +56,15 @@ error[E0308]: `match` arms have incompatible types LL | let _ = match "+" { | _____________- LL | | "+" => |a, b| (a + b + cap) as i32, - | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]` + | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]` LL | | "-" => |a, b| (a - b + cap) as i32, | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure LL | | _ => unimplemented!(), LL | | }; | |_____- `match` arms have incompatible types | - = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43 cap:_]` + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr index 9c4b7d529e..df0495cdc4 100644 --- a/src/test/ui/closures/issue-41366.stderr +++ b/src/test/ui/closures/issue-41366.stderr @@ -7,7 +7,7 @@ LL | (&|_| ()) as &dyn for<'x> Fn(>::V); | | found signature of `fn(u16) -> _` | expected signature of `fn(>::V) -> _` | - = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(>::V)` + = note: required for the cast to the object type `dyn for<'x> Fn(>::V)` error: aborting due to previous error diff --git a/src/test/ui/closures/print/closure-print-generic-1.rs b/src/test/ui/closures/print/closure-print-generic-1.rs new file mode 100644 index 0000000000..504b4adbeb --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-1.rs @@ -0,0 +1,23 @@ +fn to_fn_once(f: F) -> F { + f +} + +fn f(y: T) { + struct Foo { + x: U, + }; + + let foo = Foo { x: "x" }; + + let c = to_fn_once(move || { + println!("{} {}", foo.x, y); + }); + + c(); + c(); + //~^ ERROR use of moved value +} + +fn main() { + f("S"); +} diff --git a/src/test/ui/closures/print/closure-print-generic-1.stderr b/src/test/ui/closures/print/closure-print-generic-1.stderr new file mode 100644 index 0000000000..43a12f675f --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-1.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `c` + --> $DIR/closure-print-generic-1.rs:17:5 + | +LL | let c = to_fn_once(move || { + | - move occurs because `c` has type `[closure@$DIR/closure-print-generic-1.rs:12:24: 14:6]`, which does not implement the `Copy` trait +... +LL | c(); + | --- `c` moved due to this call +LL | c(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/closure-print-generic-1.rs:16:5 + | +LL | c(); + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/closures/print/closure-print-generic-2.rs b/src/test/ui/closures/print/closure-print-generic-2.rs new file mode 100644 index 0000000000..3f77fd26b1 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-2.rs @@ -0,0 +1,13 @@ +mod mod1 { + pub fn f(t: T) { + let x = 20; + + let c = || println!("{} {}", t, x); + let c1: () = c; + //~^ ERROR mismatched types + } +} + +fn main() { + mod1::f(5i32); +} diff --git a/src/test/ui/closures/print/closure-print-generic-2.stderr b/src/test/ui/closures/print/closure-print-generic-2.stderr new file mode 100644 index 0000000000..f7cfbd251b --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-2.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/closure-print-generic-2.rs:6:22 + | +LL | let c = || println!("{} {}", t, x); + | -------------------------- the found closure +LL | let c1: () = c; + | -- ^ expected `()`, found closure + | | + | expected due to this + | + = note: expected unit type `()` + found closure `[closure@$DIR/closure-print-generic-2.rs:5:17: 5:43]` +help: use parentheses to call this closure + | +LL | let c1: () = c(); + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs new file mode 100644 index 0000000000..07bf8fe4c0 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs @@ -0,0 +1,16 @@ +// compile-flags: -Ztrim-diagnostic-paths=off -Zverbose + +mod mod1 { + pub fn f(t: T) + { + let x = 20; + + let c = || println!("{} {}", t, x); + let c1 : () = c; + //~^ ERROR mismatched types + } +} + +fn main() { + mod1::f(5i32); +} diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr new file mode 100644 index 0000000000..7fd929221d --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/closure-print-generic-trim-off-verbose-2.rs:9:23 + | +LL | let c = || println!("{} {}", t, x); + | -------------------------- the found closure +LL | let c1 : () = c; + | -- ^ expected `()`, found closure + | | + | expected due to this + | + = note: expected unit type `()` + found closure `[mod1::f::{closure#0} closure_substs=(unavailable)]` +help: use parentheses to call this closure + | +LL | let c1 : () = c(); + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-1.rs b/src/test/ui/closures/print/closure-print-generic-verbose-1.rs new file mode 100644 index 0000000000..67d37f1c59 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-verbose-1.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zverbose + +fn to_fn_once(f: F) -> F { f } + +fn f(y: T) { + struct Foo { + x: U + }; + + let foo = Foo{ x: "x" }; + + let c = to_fn_once(move|| { + println!("{} {}", foo.x, y); + }); + + c(); + c(); + //~^ ERROR use of moved value +} + + +fn main() { + f("S"); +} diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr new file mode 100644 index 0000000000..fdaf353fe3 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `c` + --> $DIR/closure-print-generic-verbose-1.rs:17:5 + | +LL | let c = to_fn_once(move|| { + | - move occurs because `c` has type `[f::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'_#10r str>, T)]`, which does not implement the `Copy` trait +... +LL | c(); + | --- `c` moved due to this call +LL | c(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/closure-print-generic-verbose-1.rs:16:5 + | +LL | c(); + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.rs b/src/test/ui/closures/print/closure-print-generic-verbose-2.rs new file mode 100644 index 0000000000..f460fedffb --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.rs @@ -0,0 +1,16 @@ +// compile-flags: -Zverbose + +mod mod1 { + pub fn f(t: T) + { + let x = 20; + + let c = || println!("{} {}", t, x); + let c1 : () = c; + //~^ ERROR mismatched types + } +} + +fn main() { + mod1::f(5i32); +} diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr new file mode 100644 index 0000000000..680f6ff679 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/closure-print-generic-verbose-2.rs:9:23 + | +LL | let c = || println!("{} {}", t, x); + | -------------------------- the found closure +LL | let c1 : () = c; + | -- ^ expected `()`, found closure + | | + | expected due to this + | + = note: expected unit type `()` + found closure `[f::{closure#0} closure_substs=(unavailable)]` +help: use parentheses to call this closure + | +LL | let c1 : () = c(); + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/print/closure-print-verbose.rs b/src/test/ui/closures/print/closure-print-verbose.rs new file mode 100644 index 0000000000..4b0438a91e --- /dev/null +++ b/src/test/ui/closures/print/closure-print-verbose.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zverbose + +// Same as closure-coerce-fn-1.rs + +// Ensure that capturing closures are never coerced to fns +// Especially interesting as non-capturing closures can be. + +fn main() { + let mut a = 0u8; + let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/closures/print/closure-print-verbose.stderr b/src/test/ui/closures/print/closure-print-verbose.stderr new file mode 100644 index 0000000000..9e07137a24 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-verbose.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/closure-print-verbose.rs:10:29 + | +LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found closure + | | + | expected due to this + | + = note: expected fn pointer `fn(u8) -> u8` + found closure `[main::{closure#0} closure_substs=(unavailable)]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/cmse-nonsecure-entry/gate_test.rs b/src/test/ui/cmse-nonsecure-entry/gate_test.rs new file mode 100644 index 0000000000..02d5f20feb --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/gate_test.rs @@ -0,0 +1,11 @@ +// gate-test-cmse_nonsecure_entry + +#[no_mangle] +#[cmse_nonsecure_entry] +//~^ ERROR [E0775] +//~| ERROR [E0658] +pub extern "C" fn entry_function(input: u32) -> u32 { + input + 6 +} + +fn main() {} diff --git a/src/test/ui/cmse-nonsecure-entry/gate_test.stderr b/src/test/ui/cmse-nonsecure-entry/gate_test.stderr new file mode 100644 index 0000000000..75a29b317d --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/gate_test.stderr @@ -0,0 +1,19 @@ +error[E0658]: the `#[cmse_nonsecure_entry]` attribute is an experimental feature + --> $DIR/gate_test.rs:4:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #75835 for more information + = help: add `#![feature(cmse_nonsecure_entry)]` to the crate attributes to enable + +error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension + --> $DIR/gate_test.rs:4:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0658, E0775. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs b/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs new file mode 100644 index 0000000000..a723eb7347 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs @@ -0,0 +1,11 @@ +// build-pass +// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +// only-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] +#![no_std] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function(a: u32, b: u32, c: u32, d: u32) -> u32 { + a + b + c + d +} diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs b/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs new file mode 100644 index 0000000000..553d3a8cb0 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs @@ -0,0 +1,10 @@ +// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +// only-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] +#![no_std] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 { //~ ERROR + a + b + c + d + e +} diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr b/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr new file mode 100644 index 0000000000..d9956acbe7 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr @@ -0,0 +1,5 @@ +error: :0:0: in function entry_function i32 (i32, i32, i32, i32, i32): secure entry function requires arguments on stack + + +error: aborting due to previous error + diff --git a/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs b/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs new file mode 100644 index 0000000000..3783e27940 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs @@ -0,0 +1,10 @@ +// ignore-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] + +#[no_mangle] +#[cmse_nonsecure_entry] //~ ERROR [E0775] +pub extern "C" fn entry_function(input: u32) -> u32 { + input + 6 +} + +fn main() {} diff --git a/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr b/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr new file mode 100644 index 0000000000..7e8862f9ab --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr @@ -0,0 +1,9 @@ +error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension + --> $DIR/trustzone-only.rs:5:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0775`. diff --git a/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs b/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs new file mode 100644 index 0000000000..611c8643dc --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs @@ -0,0 +1,10 @@ +// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +// only-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] +#![no_std] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub fn entry_function(a: u32, b: u32, c: u32, d: u32) -> u32 { //~ ERROR [E0776] + a + b + c + d +} diff --git a/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr b/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr new file mode 100644 index 0000000000..d6967a11e6 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr @@ -0,0 +1,9 @@ +error[E0776]: `#[cmse_nonsecure_entry]` functions require C ABI + --> $DIR/wrong-abi.rs:7:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0776`. diff --git a/src/test/ui/codemap_tests/bad-format-args.rs b/src/test/ui/codemap_tests/bad-format-args.rs index dff248344a..e89a45a84f 100644 --- a/src/test/ui/codemap_tests/bad-format-args.rs +++ b/src/test/ui/codemap_tests/bad-format-args.rs @@ -1,5 +1,5 @@ fn main() { format!(); //~ ERROR requires at least a format string argument - format!("" 1); //~ ERROR expected token: `,` + format!("" 1); //~ ERROR expected `,`, found `1` format!("", 1 1); //~ ERROR expected one of } diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr index 96d7b07b0e..5ed023e1f2 100644 --- a/src/test/ui/codemap_tests/bad-format-args.stderr +++ b/src/test/ui/codemap_tests/bad-format-args.stderr @@ -6,7 +6,7 @@ LL | format!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected token: `,` +error: expected `,`, found `1` --> $DIR/bad-format-args.rs:3:16 | LL | format!("" 1); diff --git a/src/test/ui/codemap_tests/empty_span.stderr b/src/test/ui/codemap_tests/empty_span.stderr index 1dd99cfd64..e36f59ee54 100644 --- a/src/test/ui/codemap_tests/empty_span.stderr +++ b/src/test/ui/codemap_tests/empty_span.stderr @@ -1,4 +1,4 @@ -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `&'static main::Foo` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `&'static Foo` --> $DIR/empty_span.rs:7:5 | LL | unsafe impl Send for &'static Foo { } diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr index f07959cdd8..958d54bbb1 100644 --- a/src/test/ui/codemap_tests/tab_3.stderr +++ b/src/test/ui/codemap_tests/tab_3.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `some_vec` --> $DIR/tab_3.rs:7:20 | LL | let some_vec = vec!["hi"]; - | -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait + | -------- move occurs because `some_vec` has type `Vec<&str>`, which does not implement the `Copy` trait LL | some_vec.into_iter(); | ----------- `some_vec` moved due to this method call LL | { diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr index 93e16bac13..f0109f22a2 100644 --- a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr +++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | let _ = box { [1, 2, 3] }: Box<[i32]>; | ^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]` | - = note: expected struct `std::boxed::Box<[i32]>` - found struct `std::boxed::Box<[i32; 3]>` + = note: expected struct `Box<[i32]>` + found struct `Box<[i32; 3]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:10:13 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]` | - = note: expected struct `std::boxed::Box<[i32]>` - found struct `std::boxed::Box<[i32; 3]>` + = note: expected struct `Box<[i32]>` + found struct `Box<[i32; 3]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:11:13 @@ -22,35 +22,35 @@ error[E0308]: mismatched types LL | let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[i32]>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]` | - = note: expected struct `std::boxed::Box<[i32]>` - found struct `std::boxed::Box<[i32; 3]>` + = note: expected struct `Box<[i32]>` + found struct `Box<[i32; 3]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:13:13 | LL | let _ = box { |x| (x as u8) }: Box _>; - | ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure + | ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure | - = note: expected struct `std::boxed::Box u8>` - found struct `std::boxed::Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:32]>` + = note: expected struct `Box u8>` + found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:32]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:14:13 | LL | let _ = box if true { false } else { true }: Box; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool` | - = note: expected struct `std::boxed::Box` - found struct `std::boxed::Box` + = note: expected struct `Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:15:13 | LL | let _ = box match true { true => 'a', false => 'b' }: Box; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `char` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char` | - = note: expected struct `std::boxed::Box` - found struct `std::boxed::Box` + = note: expected struct `Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:17:13 @@ -83,27 +83,27 @@ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:21:13 | LL | let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _; - | ^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure + | ^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure | - = note: expected reference `&dyn std::ops::Fn(i32) -> u8` + = note: expected reference `&dyn Fn(i32) -> u8` found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:16: 21:29]` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:22:13 | LL | let _ = &if true { false } else { true }: &dyn Debug; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool` | - = note: expected reference `&dyn std::fmt::Debug` + = note: expected reference `&dyn Debug` found reference `&bool` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:23:13 | LL | let _ = &match true { true => 'a', false => 'b' }: &dyn Debug; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `char` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char` | - = note: expected reference `&dyn std::fmt::Debug` + = note: expected reference `&dyn Debug` found reference `&char` error[E0308]: mismatched types @@ -112,17 +112,17 @@ error[E0308]: mismatched types LL | let _ = Box::new([1, 2, 3]): Box<[i32]>; | ^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]` | - = note: expected struct `std::boxed::Box<[i32]>` - found struct `std::boxed::Box<[i32; 3]>` + = note: expected struct `Box<[i32]>` + found struct `Box<[i32; 3]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:26:13 | LL | let _ = Box::new(|x| (x as u8)): Box _>; - | ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure + | ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure | - = note: expected struct `std::boxed::Box u8>` - found struct `std::boxed::Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:35]>` + = note: expected struct `Box u8>` + found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:35]>` error: aborting due to 14 previous errors diff --git a/src/test/ui/coherence/coherence-blanket-conflicts-with-specific-cross-crate.stderr b/src/test/ui/coherence/coherence-blanket-conflicts-with-specific-cross-crate.stderr index 91cf925e68..a2008f0426 100644 --- a/src/test/ui/coherence/coherence-blanket-conflicts-with-specific-cross-crate.stderr +++ b/src/test/ui/coherence/coherence-blanket-conflicts-with-specific-cross-crate.stderr @@ -5,8 +5,8 @@ LL | impl GoMut for MyThingy { | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `go_trait`: - - impl go_trait::GoMut for G - where G: go_trait::Go; + - impl GoMut for G + where G: Go; error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-cow.re_a.stderr b/src/test/ui/coherence/coherence-cow.re_a.stderr index 06e77b2797..0cf2a406da 100644 --- a/src/test/ui/coherence/coherence-cow.re_a.stderr +++ b/src/test/ui/coherence/coherence-cow.re_a.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-cow.re_b.stderr b/src/test/ui/coherence/coherence-cow.re_b.stderr index 39f211eff3..b523db4da2 100644 --- a/src/test/ui/coherence/coherence-cow.re_b.stderr +++ b/src/test/ui/coherence/coherence-cow.re_b.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Pair,T> { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-cow.re_c.stderr b/src/test/ui/coherence/coherence-cow.re_c.stderr index 94bb0d2166..bd635fc2e8 100644 --- a/src/test/ui/coherence/coherence-cow.re_c.stderr +++ b/src/test/ui/coherence/coherence-cow.re_c.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Pair,U> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-cross-crate-conflict.stderr b/src/test/ui/coherence/coherence-cross-crate-conflict.stderr index c00751a0f2..5381053979 100644 --- a/src/test/ui/coherence/coherence-cross-crate-conflict.stderr +++ b/src/test/ui/coherence/coherence-cross-crate-conflict.stderr @@ -5,7 +5,7 @@ LL | impl Foo for A { | ^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `trait_impl_conflict`: - - impl trait_impl_conflict::Foo for isize; + - impl Foo for isize; error[E0210]: type parameter `A` must be used as the type parameter for some local type (e.g., `MyStruct`) --> $DIR/coherence-cross-crate-conflict.rs:9:6 diff --git a/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr b/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr index 06cfdeb390..a35a95ef4b 100644 --- a/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr +++ b/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Misc for dyn Fundamental {} | ^^^^^^^^^^^^^^---------------------- | | | - | | `dyn coherence_fundamental_trait_lib::Fundamental` is not defined in the current crate + | | `dyn Fundamental` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index 23db5328a7..c364c707ff 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -21,13 +21,13 @@ LL | impl !Send for dyn Marker2 {} | = note: define and implement a trait or new type instead -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:27:1 | LL | impl !Send for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:28:1 | LL | impl !Send for dyn Object + Marker2 {} diff --git a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr index 141ab7771f..b80429794f 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr @@ -21,13 +21,13 @@ LL | unsafe impl Send for dyn Marker2 {} | = note: define and implement a trait or new type instead -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:27:1 | LL | unsafe impl Send for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:28:1 | LL | unsafe impl Send for dyn Object + Marker2 {} diff --git a/src/test/ui/coherence/coherence-impls-copy.stderr b/src/test/ui/coherence/coherence-impls-copy.stderr index be040b38d6..8cc24f099e 100644 --- a/src/test/ui/coherence/coherence-impls-copy.stderr +++ b/src/test/ui/coherence/coherence-impls-copy.stderr @@ -5,7 +5,7 @@ LL | impl Copy for i32 {} | ^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::marker::Copy for i32; + - impl Copy for i32; error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync`: --> $DIR/coherence-impls-copy.rs:29:1 @@ -14,7 +14,7 @@ LL | impl Copy for &'static NotSync {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::marker::Copy for &T + - impl Copy for &T where T: ?Sized; error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`: @@ -24,7 +24,7 @@ LL | impl Copy for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::marker::Copy for &T + - impl Copy for &T where T: ?Sized; error[E0206]: the trait `Copy` may not be implemented for this type diff --git a/src/test/ui/coherence/coherence-impls-send.stderr b/src/test/ui/coherence/coherence-impls-send.stderr index dbfc968332..edca31b5da 100644 --- a/src/test/ui/coherence/coherence-impls-send.stderr +++ b/src/test/ui/coherence/coherence-impls-send.stderr @@ -5,8 +5,8 @@ LL | unsafe impl Send for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::marker::Send for &T - where T: std::marker::Sync, T: ?Sized; + - impl Send for &T + where T: Sync, T: ?Sized; = note: upstream crates may add a new impl of trait `std::marker::Sync` for type `[NotSync]` in future versions error[E0117]: only traits defined in the current crate can be implemented for arbitrary types @@ -20,7 +20,7 @@ LL | unsafe impl Send for (MyType, MyType) {} | = note: define and implement a trait or new type instead -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `&'static NotSync` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `&'static NotSync` --> $DIR/coherence-impls-send.rs:19:1 | LL | unsafe impl Send for &'static NotSync {} diff --git a/src/test/ui/coherence/coherence-orphan.stderr b/src/test/ui/coherence/coherence-orphan.stderr index fb518f8ecb..52d2cc88cb 100644 --- a/src/test/ui/coherence/coherence-orphan.stderr +++ b/src/test/ui/coherence/coherence-orphan.stderr @@ -16,7 +16,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl !Send for Vec { } | ^^^^^^^^^^^^^^^---------- | | | - | | `std::vec::Vec` is not defined in the current crate + | | `Vec` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-overlapping-pairs.stderr b/src/test/ui/coherence/coherence-overlapping-pairs.stderr index 69a4627a7b..c1a02681c1 100644 --- a/src/test/ui/coherence/coherence-overlapping-pairs.stderr +++ b/src/test/ui/coherence/coherence-overlapping-pairs.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for lib::Pair { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-pair-covered-uncovered-1.stderr b/src/test/ui/coherence/coherence-pair-covered-uncovered-1.stderr index f6b9869e17..b18bf44dbd 100644 --- a/src/test/ui/coherence/coherence-pair-covered-uncovered-1.stderr +++ b/src/test/ui/coherence/coherence-pair-covered-uncovered-1.stderr @@ -5,7 +5,7 @@ LL | impl Remote1>> for i32 { } | ^^^^^^^^^^^--------------------------^^^^^--- | | | | | | | `i32` is not defined in the current crate - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-pair-covered-uncovered.stderr b/src/test/ui/coherence/coherence-pair-covered-uncovered.stderr index d1a4993e0f..34fdf64ea1 100644 --- a/src/test/ui/coherence/coherence-pair-covered-uncovered.stderr +++ b/src/test/ui/coherence/coherence-pair-covered-uncovered.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-vec-local-2.stderr b/src/test/ui/coherence/coherence-vec-local-2.stderr index 198314d5ce..567b6a6c17 100644 --- a/src/test/ui/coherence/coherence-vec-local-2.stderr +++ b/src/test/ui/coherence/coherence-vec-local-2.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Vec> { } | ^^^^^^^^^^^^^^^^^^^------------- | | | - | | `std::vec::Vec` is not defined in the current crate + | | `Vec` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-vec-local.stderr b/src/test/ui/coherence/coherence-vec-local.stderr index dc5a0a6895..38464f12a2 100644 --- a/src/test/ui/coherence/coherence-vec-local.stderr +++ b/src/test/ui/coherence/coherence-vec-local.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Vec { } | ^^^^^^^^^^^^^^^^---------- | | | - | | `std::vec::Vec` is not defined in the current crate + | | `Vec` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence_inherent.stderr b/src/test/ui/coherence/coherence_inherent.stderr index 3d37d8af31..6f36f2a751 100644 --- a/src/test/ui/coherence/coherence_inherent.stderr +++ b/src/test/ui/coherence/coherence_inherent.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `the_fn` found for reference `&Lib::TheStruct` in the current scope +error[E0599]: no method named `the_fn` found for reference `&TheStruct` in the current scope --> $DIR/coherence_inherent.rs:31:11 | LL | s.the_fn(); - | ^^^^^^ method not found in `&Lib::TheStruct` + | ^^^^^^ method not found in `&TheStruct` | = help: items from traits can only be used if the trait is in scope = note: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/coherence/coherence_inherent_cc.stderr b/src/test/ui/coherence/coherence_inherent_cc.stderr index d968c8b468..edfe6348d1 100644 --- a/src/test/ui/coherence/coherence_inherent_cc.stderr +++ b/src/test/ui/coherence/coherence_inherent_cc.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `the_fn` found for reference `&coherence_inherent_cc_lib::TheStruct` in the current scope +error[E0599]: no method named `the_fn` found for reference `&TheStruct` in the current scope --> $DIR/coherence_inherent_cc.rs:23:11 | LL | s.the_fn(); - | ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct` + | ^^^^^^ method not found in `&TheStruct` | = help: items from traits can only be used if the trait is in scope = note: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/coherence/coherence_local_err_struct.stderr b/src/test/ui/coherence/coherence_local_err_struct.stderr index 0a1aee9b5c..8c310b318a 100644 --- a/src/test/ui/coherence/coherence_local_err_struct.stderr +++ b/src/test/ui/coherence/coherence_local_err_struct.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl lib::MyCopy for lib::MyStruct { } | ^^^^^^^^^^^^^^^^^^^^^--------------------- | | | - | | `lib::MyStruct` is not defined in the current crate + | | `MyStruct` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/conflicting-impl-with-err.stderr b/src/test/ui/coherence/conflicting-impl-with-err.stderr index a8a5730acc..3009b452dc 100644 --- a/src/test/ui/coherence/conflicting-impl-with-err.stderr +++ b/src/test/ui/coherence/conflicting-impl-with-err.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `nope` +error[E0433]: failed to resolve: use of undeclared crate or module `nope` --> $DIR/conflicting-impl-with-err.rs:4:11 | LL | impl From for Error { - | ^^^^ use of undeclared type or module `nope` + | ^^^^ use of undeclared crate or module `nope` -error[E0433]: failed to resolve: use of undeclared type or module `nope` +error[E0433]: failed to resolve: use of undeclared crate or module `nope` --> $DIR/conflicting-impl-with-err.rs:5:16 | LL | fn from(_: nope::Thing) -> Self { - | ^^^^ use of undeclared type or module `nope` + | ^^^^ use of undeclared crate or module `nope` error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr index a33cff2a4d..bdf19cf00a 100644 --- a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr +++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr @@ -5,7 +5,7 @@ LL | impl Remote1> for i32 { | ^^^^^----------------^^^^^--- | | | | | | | `i32` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -17,7 +17,7 @@ LL | impl Remote1> for f64 { | ^^^^^------------------^^^^^--- | | | | | | | `f64` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -29,7 +29,7 @@ LL | impl Remote1> for f32 { | ^^^^^^^^--------------^^^^^--- | | | | | | | `f32` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr index bd1a933b76..0959e155c5 100644 --- a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr @@ -15,7 +15,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Box> { | ^^^^^^^^^^^^^^^^^^^---------- | | | - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr index 3ca40e0072..b4d559eb1f 100644 --- a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr +++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr @@ -5,7 +5,7 @@ LL | impl Remote1> for i32 { | ^^^^^--------------------^^^^^--- | | | | | | | `i32` is not defined in the current crate - | | `std::string::String` is not defined in the current crate + | | `String` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -17,7 +17,7 @@ LL | impl Remote1>> for f64 { | ^^^^^---------------------^^^^^--- | | | | | | | `f64` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -29,7 +29,7 @@ LL | impl Remote1>> for f32 { | ^^^^^^^^-------------------^^^^^--- | | | | | | | `f32` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr index 95889022bd..7f8ec83b24 100644 --- a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr +++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Rc { | ^^^^^^^^^^^^^^^^--------- | | | - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -15,7 +15,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Arc { | ^^^^^^^^^^^^^^^^^^^------ | | | - | | `std::sync::Arc` is not defined in the current crate + | | `Arc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr index 5d09038076..83a2ae6068 100644 --- a/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr +++ b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr @@ -5,7 +5,7 @@ LL | fn b(&self, x: C) -> C; | ---------------------------- definition of `b` from trait ... LL | fn b(&self, _x: F) -> F { panic!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `F: std::marker::Sync` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `F: Sync` error: aborting due to previous error diff --git a/src/test/ui/compare-method/traits-misc-mismatch-1.stderr b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr index 717c0d2315..da94fc6584 100644 --- a/src/test/ui/compare-method/traits-misc-mismatch-1.stderr +++ b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr @@ -5,7 +5,7 @@ LL | fn test_error1_fn(&self); | -------------------------------- definition of `test_error1_fn` from trait ... LL | fn test_error1_fn(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Ord` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Ord` error[E0276]: impl has stricter requirements than trait --> $DIR/traits-misc-mismatch-1.rs:31:5 @@ -41,7 +41,7 @@ LL | fn test_error7_fn(&self); | ------------------------------- definition of `test_error7_fn` from trait ... LL | fn test_error7_fn(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Eq` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Eq` error[E0276]: impl has stricter requirements than trait --> $DIR/traits-misc-mismatch-1.rs:54:5 diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr index f9dfdddad9..051940bbe9 100644 --- a/src/test/ui/confuse-field-and-method/issue-2392.stderr +++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr @@ -90,7 +90,7 @@ LL | w.wrap.not_closure(); | | | field, not a method -error[E0599]: no method named `closure` found for struct `Obj u32 + 'static)>>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj u32 + 'static)>>` in the current scope --> $DIR/issue-2392.rs:58:24 | LL | struct Obj where F: FnOnce() -> u32 { diff --git a/src/test/ui/confuse-field-and-method/private-field.stderr b/src/test/ui/confuse-field-and-method/private-field.stderr index 82cb235d47..fd98a86474 100644 --- a/src/test/ui/confuse-field-and-method/private-field.stderr +++ b/src/test/ui/confuse-field-and-method/private-field.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `dog_age` found for struct `animal::Dog` in the current scope +error[E0599]: no method named `dog_age` found for struct `Dog` in the current scope --> $DIR/private-field.rs:16:23 | LL | pub struct Dog { diff --git a/src/test/ui/conservative_impl_trait.stderr b/src/test/ui/conservative_impl_trait.stderr index 58223d9d3b..87058c3c29 100644 --- a/src/test/ui/conservative_impl_trait.stderr +++ b/src/test/ui/conservative_impl_trait.stderr @@ -4,7 +4,7 @@ error[E0277]: `()` is not an iterator LL | fn will_ice(something: &u32) -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.full.stderr similarity index 91% rename from src/test/ui/const-generics/argument_order.stderr rename to src/test/ui/const-generics/argument_order.full.stderr index d6546a768d..b52e505070 100644 --- a/src/test/ui/const-generics/argument_order.stderr +++ b/src/test/ui/const-generics/argument_order.full.stderr @@ -1,11 +1,11 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/argument_order.rs:9:32 + --> $DIR/argument_order.rs:12:32 | LL | struct AlsoBad { | -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, const N: usize, T, const M: usize, U>` error[E0747]: lifetime provided when a type was expected - --> $DIR/argument_order.rs:16:23 + --> $DIR/argument_order.rs:20:23 | LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>; | ^^^^^^^ diff --git a/src/test/ui/const-generics/argument_order.min.stderr b/src/test/ui/const-generics/argument_order.min.stderr new file mode 100644 index 0000000000..728ae69b41 --- /dev/null +++ b/src/test/ui/const-generics/argument_order.min.stderr @@ -0,0 +1,30 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/argument_order.rs:6:28 + | +LL | struct Bad { + | -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `` + +error: lifetime parameters must be declared prior to const parameters + --> $DIR/argument_order.rs:12:32 + | +LL | struct AlsoBad { + | -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/argument_order.rs:12:36 + | +LL | struct AlsoBad { + | ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>` + +error[E0747]: lifetime provided when a type was expected + --> $DIR/argument_order.rs:20:23 + | +LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>; + | ^^^^^^^ + | + = note: lifetime arguments must be provided before type arguments + = help: reorder the arguments: lifetimes, then types, then consts: `<'a, 'b, T, U, N, M>` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/const-generics/argument_order.rs b/src/test/ui/const-generics/argument_order.rs index 9e071e674e..507baf5fd7 100644 --- a/src/test/ui/const-generics/argument_order.rs +++ b/src/test/ui/const-generics/argument_order.rs @@ -1,13 +1,17 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Bad { + //[min]~^ ERROR type parameters must be declared prior to const parameters arr: [u8; { N }], another: T, } struct AlsoBad { //~^ ERROR lifetime parameters must be declared prior + //[min]~^^ ERROR type parameters must be declared prior to const parameters a: &'a T, b: &'b U, } diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs index 49fc53b32b..390b6cc204 100644 --- a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs +++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs @@ -1,7 +1,8 @@ // run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr deleted file mode 100644 index e6eb2a0a78..0000000000 --- a/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/array-wrapper-struct-ctor.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs index 901fb5dd05..899a5a1836 100644 --- a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs +++ b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Struct(pub [u8; N]); diff --git a/src/test/ui/const-generics/auxiliary/impl-const.rs b/src/test/ui/const-generics/auxiliary/impl-const.rs index fc993d6392..2e25dadf11 100644 --- a/src/test/ui/const-generics/auxiliary/impl-const.rs +++ b/src/test/ui/const-generics/auxiliary/impl-const.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Num; diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs index aac5d195f7..931f6ade7f 100644 --- a/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs +++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // This test confirms that the types can be inferred correctly for this example with const // generics. Previously this would ICE, and more recently error. diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr deleted file mode 100644 index c5c48d7be4..0000000000 --- a/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/cannot-infer-type-for-const-param.rs:2:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.full.stderr similarity index 84% rename from src/test/ui/const-generics/const-arg-type-arg-misordered.stderr rename to src/test/ui/const-generics/const-arg-type-arg-misordered.full.stderr index 2e2bfed51f..3827002ff4 100644 --- a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.full.stderr @@ -1,5 +1,5 @@ error[E0747]: constant provided when a type was expected - --> $DIR/const-arg-type-arg-misordered.rs:6:35 + --> $DIR/const-arg-type-arg-misordered.rs:8:35 | LL | fn foo() -> Array { | ^ diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.min.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.min.stderr new file mode 100644 index 0000000000..2c5fc8dcc0 --- /dev/null +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.min.stderr @@ -0,0 +1,12 @@ +error[E0747]: constant provided when a type was expected + --> $DIR/const-arg-type-arg-misordered.rs:8:35 + | +LL | fn foo() -> Array { + | ^ + | + = note: type arguments must be provided before constant arguments + = help: reorder the arguments: types, then consts: `` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs index 13ca56ad3e..6680f772fa 100644 --- a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs @@ -1,9 +1,12 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] type Array = [T; N]; -fn foo() -> Array { //~ ERROR constant provided when a type was expected +fn foo() -> Array { + //~^ ERROR constant provided when a type was expected unimplemented!() } diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr similarity index 86% rename from src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr rename to src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr index aefd514f7a..a35c3abc11 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:6:67 + --> $DIR/const-argument-cross-crate-mismatch.rs:7:67 | LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); | ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:8:65 + --> $DIR/const-argument-cross-crate-mismatch.rs:9:65 | LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); | ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr new file mode 100644 index 0000000000..a35c3abc11 --- /dev/null +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/const-argument-cross-crate-mismatch.rs:7:67 + | +LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); + | ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements + +error[E0308]: mismatched types + --> $DIR/const-argument-cross-crate-mismatch.rs:9:65 + | +LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); + | ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs index d863d097d5..9ae2ae50ba 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs @@ -1,4 +1,5 @@ // aux-build:const_generic_lib.rs +// revisions: full min extern crate const_generic_lib; diff --git a/src/test/ui/const-generics/const-argument-cross-crate.rs b/src/test/ui/const-generics/const-argument-cross-crate.rs index 98cf39a7ee..fda3ec3eef 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate.rs +++ b/src/test/ui/const-generics/const-argument-cross-crate.rs @@ -1,4 +1,5 @@ // run-pass +// revisions: full min // aux-build:const_generic_lib.rs extern crate const_generic_lib; diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.full.stderr similarity index 84% rename from src/test/ui/const-generics/const-param-before-other-params.stderr rename to src/test/ui/const-generics/const-param-before-other-params.full.stderr index 1194dd30f6..c2acaabbd8 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.full.stderr @@ -1,5 +1,5 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:4:21 + --> $DIR/const-param-before-other-params.rs:6:21 | LL | fn bar(_: &'a ()) { | --------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const X: ()>` diff --git a/src/test/ui/const-generics/const-param-before-other-params.min.stderr b/src/test/ui/const-generics/const-param-before-other-params.min.stderr new file mode 100644 index 0000000000..c7e6d1be42 --- /dev/null +++ b/src/test/ui/const-generics/const-param-before-other-params.min.stderr @@ -0,0 +1,32 @@ +error: lifetime parameters must be declared prior to const parameters + --> $DIR/const-param-before-other-params.rs:6:21 + | +LL | fn bar(_: &'a ()) { + | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` + +error: type parameters must be declared prior to const parameters + --> $DIR/const-param-before-other-params.rs:11:21 + | +LL | fn foo(_: &T) {} + | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` + +error: `()` is forbidden as the type of a const generic parameter + --> $DIR/const-param-before-other-params.rs:6:17 + | +LL | fn bar(_: &'a ()) { + | ^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `()` is forbidden as the type of a const generic parameter + --> $DIR/const-param-before-other-params.rs:11:17 + | +LL | fn foo(_: &T) {} + | ^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 0d787d9a67..f1be90cf2e 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,10 +1,15 @@ -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn bar(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters + //[min]~^^ ERROR `()` is forbidden as the type of a const generic parameter } fn foo(_: &T) {} +//[min]~^ ERROR type parameters must be declared prior to const parameters +//[min]~^^ ERROR `()` is forbidden as the type of a const generic parameter fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr index ba99c87722..f860788e77 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr @@ -10,7 +10,7 @@ error[E0392]: parameter `T` is never used LL | pub struct Dependent([(); X]); | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr index ba99c87722..f860788e77 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr @@ -10,7 +10,7 @@ error[E0392]: parameter `T` is never used LL | pub struct Dependent([(); X]); | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs b/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs new file mode 100644 index 0000000000..9745dfed46 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs @@ -0,0 +1,9 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +pub fn test1() -> [u8; std::mem::size_of::() - 1] +where + [u8; std::mem::size_of::() - 1]: Sized, +{ + [0; std::mem::size_of::() - 1] +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/closures.rs b/src/test/ui/const-generics/const_evaluatable_checked/closures.rs new file mode 100644 index 0000000000..32f43591e3 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/closures.rs @@ -0,0 +1,6 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +fn test() -> [u8; N + (|| 42)()] {} +//~^ ERROR overly complex generic constant + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr b/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr new file mode 100644 index 0000000000..9f0b7252e8 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr @@ -0,0 +1,12 @@ +error: overly complex generic constant + --> $DIR/closures.rs:3:35 + | +LL | fn test() -> [u8; N + (|| 42)()] {} + | ^^^^-------^^ + | | + | unsupported rvalue + | + = help: consider moving this anonymous constant into a `const` function + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs new file mode 100644 index 0000000000..53b2378438 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs @@ -0,0 +1,15 @@ +// aux-build:const_evaluatable_lib.rs +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +extern crate const_evaluatable_lib; + +fn user() where [u8; std::mem::size_of::() - 1]: Sized { + assert_eq!(const_evaluatable_lib::test1::(), [0; std::mem::size_of::() - 1]); +} + +fn main() { + assert_eq!(const_evaluatable_lib::test1::(), [0; 3]); + user::(); + user::(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs new file mode 100644 index 0000000000..e3a4d9a96a --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs @@ -0,0 +1,14 @@ +// aux-build:const_evaluatable_lib.rs +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +extern crate const_evaluatable_lib; + +fn user() { + let _ = const_evaluatable_lib::test1::(); + //~^ ERROR unconstrained generic constant + //~| ERROR unconstrained generic constant + //~| ERROR unconstrained generic constant + //~| ERROR unconstrained generic constant +} + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr new file mode 100644 index 0000000000..8a298b47ff --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -0,0 +1,50 @@ +error: unconstrained generic constant + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a `where` bound for this expression + --> $DIR/auxiliary/const_evaluatable_lib.rs:6:10 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unconstrained generic constant + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a `where` bound for this expression + --> $DIR/auxiliary/const_evaluatable_lib.rs:4:27 + | +LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unconstrained generic constant + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a `where` bound for this expression + --> $DIR/auxiliary/const_evaluatable_lib.rs:6:10 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unconstrained generic constant + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a `where` bound for this expression + --> $DIR/auxiliary/const_evaluatable_lib.rs:4:27 + | +LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr new file mode 100644 index 0000000000..b2816367ea --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/feature-gate-const_evaluatable_checked.rs:9:30 + | +LL | fn test() -> Arr where Arr: Default { + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr new file mode 100644 index 0000000000..269710db16 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs new file mode 100644 index 0000000000..af3090115f --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs @@ -0,0 +1,17 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +type Arr = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values + +fn test() -> Arr where Arr: Default { + //[full]~^ ERROR constant expression depends + Default::default() +} + +fn main() { + let x = test::<33>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs b/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs new file mode 100644 index 0000000000..1b9ec0108b --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs @@ -0,0 +1,30 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +const fn test_me(a: usize, b: usize) -> usize { + if a < b { + std::mem::size_of::() + } else { + std::usize::MAX + } +} + +fn test_simple() -> [u8; std::mem::size_of::()] +where + [u8; std::mem::size_of::()]: Sized, +{ + [0; std::mem::size_of::()] +} + +fn test_with_args() -> [u8; test_me::(N, N + 1) + N] +where + [u8; test_me::(N, N + 1) + N]: Sized, +{ + [0; test_me::(N, N + 1) + N] +} + +fn main() { + assert_eq!([0; 8], test_simple::()); + assert_eq!([0; 12], test_with_args::()); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs new file mode 100644 index 0000000000..3da4688702 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs @@ -0,0 +1,11 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn test() -> [u8; N - 1] { + //~^ ERROR evaluation of constant + todo!() +} + +fn main() { + test::<0>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr new file mode 100644 index 0000000000..25af18eb16 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/from-sig-fail.rs:4:35 + | +LL | fn test() -> [u8; N - 1] { + | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs new file mode 100644 index 0000000000..5c05a5acfe --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ N > 10 }> { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs b/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs new file mode 100644 index 0000000000..193a365f9b --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs @@ -0,0 +1,25 @@ +// check-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +use std::mem::size_of; + +struct Foo(T); + +impl Foo() }> { + fn test() { + let _: [u8; std::mem::size_of::()]; + } +} + +trait Bar { + fn test_me(); +} + +impl Bar<{ size_of::() }> for Foo { + fn test_me() { + let _: [u8; std::mem::size_of::()]; + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs b/src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs new file mode 100644 index 0000000000..cad06ea400 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs @@ -0,0 +1,24 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +use std::{mem, ptr}; + +fn split_first(arr: [T; N]) -> (T, [T; N - 1]) +where + [T; N - 1]: Sized, +{ + let arr = mem::ManuallyDrop::new(arr); + unsafe { + let head = ptr::read(&arr[0]); + let tail = ptr::read(&arr[1..] as *const [T] as *const [T; N - 1]); + (head, tail) + } +} + +fn main() { + let arr = [0, 1, 2, 3, 4]; + let (head, tail) = split_first(arr); + assert_eq!(head, 0); + assert_eq!(tail, [1, 2, 3, 4]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs b/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs new file mode 100644 index 0000000000..907ea255ab --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ N > 10 }> where Foo<{ N > 10 }>: Sized { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs new file mode 100644 index 0000000000..a6bb39208a --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs @@ -0,0 +1,15 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +// We do not yet want to support let-bindings in abstract consts, +// so this test should keep failing for now. +fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { + //~^ ERROR overly complex generic constant + //~| ERROR overly complex generic constant + Default::default() +} + +fn main() { + let x = test::<31>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr new file mode 100644 index 0000000000..5749defb3e --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -0,0 +1,22 @@ +error: overly complex generic constant + --> $DIR/let-bindings.rs:6:68 + | +LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { + | ^^^^^^-^^^^^^^^^^^^^ + | | + | unsupported statement + | + = help: consider moving this anonymous constant into a `const` function + +error: overly complex generic constant + --> $DIR/let-bindings.rs:6:35 + | +LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { + | ^^^^^^-^^^^^^^^^^^^^ + | | + | unsupported statement + | + = help: consider moving this anonymous constant into a `const` function + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr new file mode 100644 index 0000000000..3cac604a7b --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr @@ -0,0 +1,18 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple.rs:8:53 + | +LL | fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple.rs:8:35 + | +LL | fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs new file mode 100644 index 0000000000..dcf0071cb2 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs @@ -0,0 +1,17 @@ +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + //[min]~^ ERROR generic parameters + //[min]~| ERROR generic parameters + Default::default() +} + +fn main() { + let x = test::<33>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr new file mode 100644 index 0000000000..f95d6d2d57 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/simple_fail.rs:7:33 + | +LL | type Arr = [u8; N - 1]; + | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr new file mode 100644 index 0000000000..042710f132 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple_fail.rs:7:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs new file mode 100644 index 0000000000..b15e0ff183 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -0,0 +1,16 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] +#![allow(incomplete_features)] + +type Arr = [u8; N - 1]; //[full]~ ERROR evaluation of constant +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values + +fn test() -> Arr where Arr: Sized { + todo!() +} + +fn main() { + test::<0>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unop.rs b/src/test/ui/const-generics/const_evaluatable_checked/unop.rs new file mode 100644 index 0000000000..8e0768b1c9 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/unop.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ !(N > 10) }> where Foo<{ !(N > 10) }>: Sized { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr new file mode 100644 index 0000000000..0574ddfb25 --- /dev/null +++ b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/complex-unord-param.rs:9:41 + | +LL | struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { + | ---------------------^----------------------^--------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, A: 'a, T: 'a, const N: usize, const M: usize>` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs index 72967640a8..e83a96388c 100644 --- a/src/test/ui/const-generics/defaults/complex-unord-param.rs +++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs @@ -1,11 +1,13 @@ -// run-pass +// [full] run-pass +// revisions: full min // Checks a complicated usage of unordered params - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { + //[min]~^ ERROR type parameters must be declared prior to const parameters args: &'a [&'a [T; M]; N], specifier: A, } diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr similarity index 87% rename from src/test/ui/const-generics/defaults/intermixed-lifetime.stderr rename to src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr index 0f6d7f1065..9cc3e9c0da 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr @@ -1,11 +1,11 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/intermixed-lifetime.rs:6:28 + --> $DIR/intermixed-lifetime.rs:7:28 | LL | struct Foo(&'a (), T); | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>` error: lifetime parameters must be declared prior to type parameters - --> $DIR/intermixed-lifetime.rs:9:37 + --> $DIR/intermixed-lifetime.rs:11:37 | LL | struct Bar(&'a (), T); | --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>` diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr new file mode 100644 index 0000000000..4d80fdb5bc --- /dev/null +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr @@ -0,0 +1,26 @@ +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:7:28 + | +LL | struct Foo(&'a (), T); + | -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:7:32 + | +LL | struct Foo(&'a (), T); + | ---------------------^------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:11:37 + | +LL | struct Bar(&'a (), T); + | --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:11:28 + | +LL | struct Bar(&'a (), T); + | -----------------^----------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs index ea3a8c14b9..cc0d1c6c0c 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs @@ -1,12 +1,16 @@ +// revisions: full min // Checks that lifetimes cannot be interspersed between consts and types. - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo(&'a (), T); //~^ Error lifetime parameters must be declared prior to const parameters +//[min]~^^ Error type parameters must be declared prior to const parameters struct Bar(&'a (), T); -//~^ Error lifetime parameters must be declared prior to type parameters +//[full]~^ Error lifetime parameters must be declared prior to type parameters +//[min]~^^ Error type parameters must be declared prior to const parameters +//[min]~| Error lifetime parameters must be declared prior to const parameters fn main() {} diff --git a/src/test/ui/const-generics/defaults/simple-defaults.min.stderr b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr new file mode 100644 index 0000000000..59cc6f28af --- /dev/null +++ b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/simple-defaults.rs:9:40 + | +LL | struct FixedOutput<'a, const N: usize, T=u32> { + | ---------------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/simple-defaults.rs b/src/test/ui/const-generics/defaults/simple-defaults.rs index b282dfd37c..78abe35199 100644 --- a/src/test/ui/const-generics/defaults/simple-defaults.rs +++ b/src/test/ui/const-generics/defaults/simple-defaults.rs @@ -1,10 +1,13 @@ -// run-pass +// [full] run-pass +// revisions: min full // Checks some basic test cases for defaults. -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] struct FixedOutput<'a, const N: usize, T=u32> { + //[min]~^ ERROR type parameters must be declared prior to const parameters out: &'a [T; N], } diff --git a/src/test/ui/const-generics/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr similarity index 70% rename from src/test/ui/const-generics/cannot-infer-const-args.full.stderr rename to src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr index 053139787e..b438ed3ad6 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.full.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:12:5 | LL | foo(); - | ^^^ - | - = note: unable to infer the value of a const parameter + | ^^^ cannot infer the value of const parameter `X` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr similarity index 70% rename from src/test/ui/const-generics/cannot-infer-const-args.min.stderr rename to src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr index 053139787e..b438ed3ad6 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.min.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:12:5 | LL | foo(); - | ^^^ - | - = note: unable to infer the value of a const parameter + | ^^^ cannot infer the value of const parameter `X` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/cannot-infer-const-args.rs b/src/test/ui/const-generics/infer/cannot-infer-const-args.rs similarity index 100% rename from src/test/ui/const-generics/cannot-infer-const-args.rs rename to src/test/ui/const-generics/infer/cannot-infer-const-args.rs diff --git a/src/test/ui/const-generics/infer/issue-77092.rs b/src/test/ui/const-generics/infer/issue-77092.rs new file mode 100644 index 0000000000..9a1dd1a825 --- /dev/null +++ b/src/test/ui/const-generics/infer/issue-77092.rs @@ -0,0 +1,16 @@ +#![feature(min_const_generics)] + +use std::convert::TryInto; + +fn take_array_from_mut(data: &mut [T], start: usize) -> &mut [T; N] { + (&mut data[start .. start + N]).try_into().unwrap() +} + +fn main() { + let mut arr = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + + for i in 1 .. 4 { + println!("{:?}", take_array_from_mut(&mut arr, i)); + //~^ ERROR type annotations needed + } +} diff --git a/src/test/ui/const-generics/infer/issue-77092.stderr b/src/test/ui/const-generics/infer/issue-77092.stderr new file mode 100644 index 0000000000..e84ff8baee --- /dev/null +++ b/src/test/ui/const-generics/infer/issue-77092.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/issue-77092.rs:13:26 + | +LL | println!("{:?}", take_array_from_mut(&mut arr, i)); + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{_: usize}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr new file mode 100644 index 0000000000..1fb0b23cf1 --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.full.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/method-chain.rs:21:33 + | +LL | Foo.bar().bar().bar().bar().baz(); + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr new file mode 100644 index 0000000000..1fb0b23cf1 --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.min.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/method-chain.rs:21:33 + | +LL | Foo.bar().bar().bar().bar().baz(); + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.rs b/src/test/ui/const-generics/infer/method-chain.rs new file mode 100644 index 0000000000..9389ca20d1 --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.rs @@ -0,0 +1,22 @@ +// revisions: full min + +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +struct Foo; + +impl Foo { + fn bar(self) -> Foo { + Foo + } + + fn baz(self) -> Foo { + println!("baz: {}", N); + Foo + } +} + +fn main() { + Foo.bar().bar().bar().bar().baz(); //~ ERROR type annotations needed +} diff --git a/src/test/ui/const-generics/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr similarity index 54% rename from src/test/ui/const-generics/uninferred-consts.full.stderr rename to src/test/ui/const-generics/infer/uninferred-consts.full.stderr index 2c5af9e65f..7a451903e9 100644 --- a/src/test/ui/const-generics/uninferred-consts.full.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr @@ -1,10 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/uninferred-consts.rs:14:5 + --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^^^^^^^ - | - = note: unable to infer the value of a const parameter + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr similarity index 54% rename from src/test/ui/const-generics/uninferred-consts.min.stderr rename to src/test/ui/const-generics/infer/uninferred-consts.min.stderr index 2c5af9e65f..7a451903e9 100644 --- a/src/test/ui/const-generics/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -1,10 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/uninferred-consts.rs:14:5 + --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^^^^^^^ - | - = note: unable to infer the value of a const parameter + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/uninferred-consts.rs b/src/test/ui/const-generics/infer/uninferred-consts.rs similarity index 100% rename from src/test/ui/const-generics/uninferred-consts.rs rename to src/test/ui/const-generics/infer/uninferred-consts.rs diff --git a/src/test/ui/const-generics/invalid-enum.rs b/src/test/ui/const-generics/invalid-enum.rs new file mode 100644 index 0000000000..ceb188a0d3 --- /dev/null +++ b/src/test/ui/const-generics/invalid-enum.rs @@ -0,0 +1,39 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +#[derive(PartialEq, Eq)] +enum CompileFlag { + A, + B, +} + +pub fn test_1() {} +pub fn test_2(x: T) {} +pub struct Example{ + x: T, +} + +impl Example { + const ASSOC_FLAG: CompileFlag = CompileFlag::A; +} + +pub fn main() { + test_1::(); + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + test_2::<_, CompileFlag::A>(0); + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + let _: Example = Example { x: 0 }; + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + let _: Example = Example { x: 0 }; + //~^ ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments +} diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr new file mode 100644 index 0000000000..965abbc9cb --- /dev/null +++ b/src/test/ui/const-generics/invalid-enum.stderr @@ -0,0 +1,99 @@ +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:21:12 + | +LL | test_1::(); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:26:15 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:31:18 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:31:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected at most 1, found 2 + --> $DIR/invalid-enum.rs:31:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:36:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected at most 1, found 2 + --> $DIR/invalid-enum.rs:36:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:21:3 + | +LL | test_1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/invalid-enum.rs:21:12 + | +LL | test_1::(); + | ^^^^^^^^^^^^^^ unexpected type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | test_1::<{ CompileFlag::A }>(); + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:26:3 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected 1, found 2 + --> $DIR/invalid-enum.rs:26:15 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ unexpected type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | test_2::<_, { CompileFlag::A }>(0); + | ^ ^ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0107, E0573. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issue-74906.rs b/src/test/ui/const-generics/issue-74906.rs new file mode 100644 index 0000000000..9162d1142b --- /dev/null +++ b/src/test/ui/const-generics/issue-74906.rs @@ -0,0 +1,25 @@ +// edition:2018 +// check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +const SIZE: usize = 16; + +struct Bar {} + +struct Foo {} + +impl Foo { + async fn biz(_: &[[u8; SIZE]]) -> Vec<()> { + vec![] + } + + pub async fn baz(&self) -> Bar { + Self::biz(&vec![]).await; + Bar {} + } +} + +fn main() { } diff --git a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs index 59a4d345cb..7ea8d936d6 100644 --- a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs +++ b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // All of these three items must be in `lib2` to reproduce the error diff --git a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr index d21cd9df05..ef6e60084a 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr @@ -7,17 +7,17 @@ LL | #![cfg_attr(full, feature(const_generics))] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336-2.rs:10:5 | LL | [x; { N }] - | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61336-2.min.stderr b/src/test/ui/const-generics/issues/issue-61336-2.min.stderr index 29ab7b1305..40863a4f71 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.min.stderr @@ -1,14 +1,14 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336-2.rs:10:5 | LL | [x; { N }] - | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-61336-2.rs b/src/test/ui/const-generics/issues/issue-61336-2.rs index 25b9271105..44995157cc 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.rs +++ b/src/test/ui/const-generics/issues/issue-61336-2.rs @@ -8,7 +8,7 @@ fn f(x: T) -> [T; N] { fn g(x: T) -> [T; N] { [x; { N }] - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } fn main() { diff --git a/src/test/ui/const-generics/issues/issue-61336.full.stderr b/src/test/ui/const-generics/issues/issue-61336.full.stderr index d1b5d5eb94..bdfdffd941 100644 --- a/src/test/ui/const-generics/issues/issue-61336.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.full.stderr @@ -7,17 +7,17 @@ LL | #![cfg_attr(full, feature(const_generics))] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336.rs:10:5 | LL | [x; N] - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61336.min.stderr b/src/test/ui/const-generics/issues/issue-61336.min.stderr index bced8bbd82..6c57f9ccbf 100644 --- a/src/test/ui/const-generics/issues/issue-61336.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.min.stderr @@ -1,14 +1,14 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336.rs:10:5 | LL | [x; N] - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-61336.rs b/src/test/ui/const-generics/issues/issue-61336.rs index fb55542a1c..7c34250e6b 100644 --- a/src/test/ui/const-generics/issues/issue-61336.rs +++ b/src/test/ui/const-generics/issues/issue-61336.rs @@ -8,7 +8,7 @@ fn f(x: T) -> [T; N] { fn g(x: T) -> [T; N] { [x; N] - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } fn main() { diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr index 0eee37df3d..1be907b98a 100644 --- a/src/test/ui/const-generics/issues/issue-61336.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.stderr @@ -7,17 +7,17 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336.rs:9:5 | LL | [x; N] - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61935.full.stderr b/src/test/ui/const-generics/issues/issue-61935.full.stderr new file mode 100644 index 0000000000..b805bc0db7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-61935.rs:10:14 + | +LL | Self:FooImpl<{N==0}> + | ^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr new file mode 100644 index 0000000000..e5715ec658 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-61935.rs:10:23 + | +LL | Self:FooImpl<{N==0}> + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs index 0d42ff1895..64257da030 100644 --- a/src/test/ui/const-generics/issues/issue-61935.rs +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -1,12 +1,15 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Foo {} impl Foo for [(); N] where Self:FooImpl<{N==0}> -//~^ERROR constant expression depends on a generic parameter +//[full]~^ERROR constant expression depends on a generic parameter +//[min]~^^ERROR generic parameters must not be used inside of non trivial constant values {} trait FooImpl{} diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr deleted file mode 100644 index a785af5f00..0000000000 --- a/src/test/ui/const-generics/issues/issue-61935.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-61935.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-61935.rs:8:14 - | -LL | Self:FooImpl<{N==0}> - | ^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs index 2f3b5c5dc5..a8fa378035 100644 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs @@ -1,7 +1,9 @@ // run-pass -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub trait BitLen: Sized { const BIT_LEN: usize; @@ -12,5 +14,5 @@ impl BitLen for [u8; L] { } fn main() { - let foo = <[u8; 2]>::BIT_LEN; //~ WARN unused variable + let _foo = <[u8; 2]>::BIT_LEN; } diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr deleted file mode 100644 index a9abb877c0..0000000000 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62187-encountered-polymorphic-const.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: unused variable: `foo` - --> $DIR/issue-62187-encountered-polymorphic-const.rs:15:9 - | -LL | let foo = <[u8; 2]>::BIT_LEN; - | ^^^ help: if this is intentional, prefix it with an underscore: `_foo` - | - = note: `#[warn(unused_variables)]` on by default - -warning: 2 warnings emitted - diff --git a/src/test/ui/const-generics/issues/issue-62220.stderr b/src/test/ui/const-generics/issues/issue-62220.full.stderr similarity index 90% rename from src/test/ui/const-generics/issues/issue-62220.stderr rename to src/test/ui/const-generics/issues/issue-62220.full.stderr index d91d2bb326..120aa8e4af 100644 --- a/src/test/ui/const-generics/issues/issue-62220.stderr +++ b/src/test/ui/const-generics/issues/issue-62220.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-62220.rs:10:27 + --> $DIR/issue-62220.rs:13:27 | LL | pub fn trunc(self) -> (TruncatedVector, T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr new file mode 100644 index 0000000000..943b689bf6 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62220.rs:8:59 + | +LL | pub type TruncatedVector = Vector; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs index 5c4a0d31a8..acb13ad117 100644 --- a/src/test/ui/const-generics/issues/issue-62220.rs +++ b/src/test/ui/const-generics/issues/issue-62220.rs @@ -1,14 +1,17 @@ -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Vector([T; N]); pub type TruncatedVector = Vector; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values impl Vector { /// Drop the last component and return the vector with one fewer dimension. pub fn trunc(self) -> (TruncatedVector, T) { - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter unimplemented!() } } diff --git a/src/test/ui/const-generics/issues/issue-62456.full.stderr b/src/test/ui/const-generics/issues/issue-62456.full.stderr new file mode 100644 index 0000000000..a8d44074db --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-62456.rs:7:20 + | +LL | let _ = [0u64; N + 1]; + | ^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr new file mode 100644 index 0000000000..335f0ead27 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62456.rs:7:20 + | +LL | let _ = [0u64; N + 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs index 37947ad1b3..c96868c00a 100644 --- a/src/test/ui/const-generics/issues/issue-62456.rs +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -1,9 +1,12 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo() { let _ = [0u64; N + 1]; - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr deleted file mode 100644 index 0454fed670..0000000000 --- a/src/test/ui/const-generics/issues/issue-62456.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62456.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-62456.rs:5:20 - | -LL | let _ = [0u64; N + 1]; - | ^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-62504.stderr rename to src/test/ui/const-generics/issues/issue-62504.full.stderr index f09af76325..9c84f06ce9 100644 --- a/src/test/ui/const-generics/issues/issue-62504.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-62504.rs:18:25 + --> $DIR/issue-62504.rs:19:25 | LL | ArrayHolder([0; Self::SIZE]) | ^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-62504.min.stderr b/src/test/ui/const-generics/issues/issue-62504.min.stderr new file mode 100644 index 0000000000..8f79431283 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62504.min.stderr @@ -0,0 +1,14 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/issue-62504.rs:19:25 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^ + | +note: not a concrete type + --> $DIR/issue-62504.rs:17:22 + | +LL | impl ArrayHolder { + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 4e05aadd39..015f170f00 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -1,7 +1,8 @@ -// Regression test for #62504 - -#![feature(const_generics)] +// revisions: full min #![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait HasSize { const SIZE: usize; @@ -16,7 +17,8 @@ struct ArrayHolder([u32; X]); impl ArrayHolder { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic `Self` types are currently } } diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr new file mode 100644 index 0000000000..6903b20fad --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr @@ -0,0 +1,11 @@ +error: `NoMatch` is forbidden as the type of a const generic parameter + --> $DIR/issue-62579-no-match.rs:10:17 + | +LL | fn foo() -> bool { + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.rs b/src/test/ui/const-generics/issues/issue-62579-no-match.rs index 7eaf5eea07..c9853aa916 100644 --- a/src/test/ui/const-generics/issues/issue-62579-no-match.rs +++ b/src/test/ui/const-generics/issues/issue-62579-no-match.rs @@ -1,12 +1,14 @@ -// run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #[derive(PartialEq, Eq)] struct NoMatch; fn foo() -> bool { + //[min]~^ ERROR `NoMatch` is forbidden as the type of a const generic parameter true } diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.stderr deleted file mode 100644 index 9fb9b5b13d..0000000000 --- a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62579-no-match.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.full.stderr similarity index 58% rename from src/test/ui/const-generics/issues/issue-62878.stderr rename to src/test/ui/const-generics/issues/issue-62878.full.stderr index fe0990d824..c8b9db8941 100644 --- a/src/test/ui/const-generics/issues/issue-62878.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.full.stderr @@ -1,37 +1,28 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-62878.rs:3:38 + --> $DIR/issue-62878.rs:6:38 | LL | fn foo() {} | ^ the type must not depend on the parameter `N` -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62878.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - error[E0107]: wrong number of const arguments: expected 2, found 1 - --> $DIR/issue-62878.rs:7:5 + --> $DIR/issue-62878.rs:11:5 | LL | foo::<_, {[1]}>(); | ^^^^^^^^^^^^^^^ expected 2 const arguments error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/issue-62878.rs:7:11 + --> $DIR/issue-62878.rs:11:11 | LL | foo::<_, {[1]}>(); | ^ unexpected type argument error[E0308]: mismatched types - --> $DIR/issue-62878.rs:7:15 + --> $DIR/issue-62878.rs:11:15 | LL | foo::<_, {[1]}>(); | ^^^ expected `usize`, found array `[{integer}; 1]` -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0107, E0308, E0770. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-62878.min.stderr b/src/test/ui/const-generics/issues/issue-62878.min.stderr new file mode 100644 index 0000000000..34edd09b51 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62878.min.stderr @@ -0,0 +1,18 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-62878.rs:6:38 + | +LL | fn foo() {} + | ^ the type must not depend on the parameter `N` + +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-62878.rs:6:33 + | +LL | fn foo() {} + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs index ccc05fdf10..0487dda2fe 100644 --- a/src/test/ui/const-generics/issues/issue-62878.rs +++ b/src/test/ui/const-generics/issues/issue-62878.rs @@ -1,11 +1,15 @@ -#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo() {} //~^ ERROR the type of const parameters must not +//[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() { foo::<_, {[1]}>(); - //~^ ERROR wrong number of const arguments - //~| ERROR wrong number of type arguments - //~| ERROR mismatched types + //[full]~^ ERROR wrong number of const arguments + //[full]~| ERROR wrong number of type arguments + //[full]~| ERROR mismatched types } diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr new file mode 100644 index 0000000000..a20c7264ac --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr @@ -0,0 +1,9 @@ +error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter + --> $DIR/issue-63322-forbid-dyn.rs:10:18 + | +LL | fn test() { + | ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr new file mode 100644 index 0000000000..e6d9fb7a24 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr @@ -0,0 +1,18 @@ +error: `&'static (dyn A + 'static)` is forbidden as the type of a const generic parameter + --> $DIR/issue-63322-forbid-dyn.rs:10:18 + | +LL | fn test() { + | ^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter + --> $DIR/issue-63322-forbid-dyn.rs:10:18 + | +LL | fn test() { + | ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs index 2bcaa27b4d..2194eb97a4 100644 --- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait A {} struct B; @@ -7,6 +9,7 @@ impl A for B {} fn test() { //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` to be used + //[min]~^^ ERROR `&'static (dyn A + 'static)` is forbidden unimplemented!() } diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr deleted file mode 100644 index 32054e4371..0000000000 --- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr +++ /dev/null @@ -1,18 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-63322-forbid-dyn.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter - --> $DIR/issue-63322-forbid-dyn.rs:8:18 - | -LL | fn test() { - | ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq` - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-64494.stderr b/src/test/ui/const-generics/issues/issue-64494.full.stderr similarity index 94% rename from src/test/ui/const-generics/issues/issue-64494.stderr rename to src/test/ui/const-generics/issues/issue-64494.full.stderr index 30dca16964..a97ec9308f 100644 --- a/src/test/ui/const-generics/issues/issue-64494.stderr +++ b/src/test/ui/const-generics/issues/issue-64494.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-64494.rs:14:53 + --> $DIR/issue-64494.rs:16:53 | LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} | ^^^^ @@ -7,7 +7,7 @@ LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-64494.rs:16:53 + --> $DIR/issue-64494.rs:19:53 | LL | impl MyTrait for T where Is<{T::VAL == 6}>: True {} | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-64494.min.stderr b/src/test/ui/const-generics/issues/issue-64494.min.stderr new file mode 100644 index 0000000000..07822f86f5 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-64494.min.stderr @@ -0,0 +1,28 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-64494.rs:16:38 + | +LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} + | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` + | + = note: type parameters are currently not permitted in anonymous constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-64494.rs:19:38 + | +LL | impl MyTrait for T where Is<{T::VAL == 6}>: True {} + | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` + | + = note: type parameters are currently not permitted in anonymous constants + +error[E0119]: conflicting implementations of trait `MyTrait`: + --> $DIR/issue-64494.rs:19:1 + | +LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} + | ------------------------------------ first implementation here +... +LL | impl MyTrait for T where Is<{T::VAL == 6}>: True {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/const-generics/issues/issue-64494.rs b/src/test/ui/const-generics/issues/issue-64494.rs index 4c755530b9..3b598a4152 100644 --- a/src/test/ui/const-generics/issues/issue-64494.rs +++ b/src/test/ui/const-generics/issues/issue-64494.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Foo { const VAL: usize; @@ -12,8 +14,11 @@ struct Is; impl True for Is<{true}> {} impl MyTrait for T where Is<{T::VAL == 5}>: True {} -//~^ ERROR constant expression depends on a generic parameter +//[full]~^ ERROR constant expression depends on a generic parameter +//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values impl MyTrait for T where Is<{T::VAL == 6}>: True {} -//~^ ERROR constant expression depends on a generic parameter +//[full]~^ ERROR constant expression depends on a generic parameter +//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values +//[min]~| ERROR conflicting implementations of trait `MyTrait` fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-64519.rs b/src/test/ui/const-generics/issues/issue-64519.rs index e9391096b0..1ca709d097 100644 --- a/src/test/ui/const-generics/issues/issue-64519.rs +++ b/src/test/ui/const-generics/issues/issue-64519.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo { state: Option<[u8; D]>, diff --git a/src/test/ui/const-generics/issues/issue-66205.full.stderr b/src/test/ui/const-generics/issues/issue-66205.full.stderr new file mode 100644 index 0000000000..a1520912e4 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-66205.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-66205.rs:8:12 + | +LL | fact::<{ N - 1 }>(); + | ^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-66205.min.stderr b/src/test/ui/const-generics/issues/issue-66205.min.stderr new file mode 100644 index 0000000000..86709c389b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-66205.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-66205.rs:8:14 + | +LL | fact::<{ N - 1 }>(); + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 7cedf51ca0..e115eff356 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -1,10 +1,13 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code, unconditional_recursion)] -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete fn fact() { fact::<{ N - 1 }>(); - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-66205.stderr b/src/test/ui/const-generics/issues/issue-66205.stderr deleted file mode 100644 index 1e9c0f2f3d..0000000000 --- a/src/test/ui/const-generics/issues/issue-66205.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-66205.rs:2:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-66205.rs:6:12 - | -LL | fact::<{ N - 1 }>(); - | ^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-66906.rs b/src/test/ui/const-generics/issues/issue-66906.rs index 486c72d8a3..3e048593c9 100644 --- a/src/test/ui/const-generics/issues/issue-66906.rs +++ b/src/test/ui/const-generics/issues/issue-66906.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Tuple; diff --git a/src/test/ui/const-generics/issues/issue-66906.stderr b/src/test/ui/const-generics/issues/issue-66906.stderr deleted file mode 100644 index 8e8b552f90..0000000000 --- a/src/test/ui/const-generics/issues/issue-66906.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-66906.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-67185-1.rs b/src/test/ui/const-generics/issues/issue-67185-1.rs index b08057851a..09d88ef89a 100644 --- a/src/test/ui/const-generics/issues/issue-67185-1.rs +++ b/src/test/ui/const-generics/issues/issue-67185-1.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Baz { type Quaks; diff --git a/src/test/ui/const-generics/issues/issue-67185-1.stderr b/src/test/ui/const-generics/issues/issue-67185-1.stderr deleted file mode 100644 index 9cc797d6d8..0000000000 --- a/src/test/ui/const-generics/issues/issue-67185-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-67185-1.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-67185-2.stderr b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr similarity index 82% rename from src/test/ui/const-generics/issues/issue-67185-2.stderr rename to src/test/ui/const-generics/issues/issue-67185-2.full.stderr index 7d947a907a..78c7ebff05 100644 --- a/src/test/ui/const-generics/issues/issue-67185-2.stderr +++ b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr @@ -1,14 +1,5 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-67185-2.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:15:1 + --> $DIR/issue-67185-2.rs:17:1 | LL | / trait Foo LL | | @@ -26,7 +17,7 @@ LL | | } = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:15:1 + --> $DIR/issue-67185-2.rs:17:1 | LL | / trait Foo LL | | @@ -44,7 +35,7 @@ LL | | } = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:25:6 + --> $DIR/issue-67185-2.rs:27:6 | LL | trait Foo | --- required by a bound in this @@ -60,7 +51,7 @@ LL | impl Foo for FooImpl {} <[u16; 4] as Bar> error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:25:6 + --> $DIR/issue-67185-2.rs:27:6 | LL | trait Foo | --- required by a bound in this @@ -76,7 +67,7 @@ LL | impl Foo for FooImpl {} <[u16; 4] as Bar> error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:29:14 + --> $DIR/issue-67185-2.rs:31:14 | LL | trait Foo | --- required by a bound in this @@ -92,7 +83,7 @@ LL | fn f(_: impl Foo) {} <[u16; 4] as Bar> error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:29:14 + --> $DIR/issue-67185-2.rs:31:14 | LL | trait Foo | --- required by a bound in this @@ -107,6 +98,6 @@ LL | fn f(_: impl Foo) {} <[[u16; 3]; 3] as Bar> <[u16; 4] as Bar> -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-67185-2.min.stderr b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr new file mode 100644 index 0000000000..78c7ebff05 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr @@ -0,0 +1,103 @@ +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | ::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | ::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-67185-2.rs b/src/test/ui/const-generics/issues/issue-67185-2.rs index 111b718dd5..1176d0c690 100644 --- a/src/test/ui/const-generics/issues/issue-67185-2.rs +++ b/src/test/ui/const-generics/issues/issue-67185-2.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Baz { type Quaks; diff --git a/src/test/ui/const-generics/issues/issue-67739.stderr b/src/test/ui/const-generics/issues/issue-67739.full.stderr similarity index 100% rename from src/test/ui/const-generics/issues/issue-67739.stderr rename to src/test/ui/const-generics/issues/issue-67739.full.stderr diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr new file mode 100644 index 0000000000..68f1733dec --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-67739.rs:12:30 + | +LL | [0u8; mem::size_of::()]; + | ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = note: type parameters are currently not permitted in anonymous constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index c8ee182123..72bf3ee960 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -1,7 +1,7 @@ -// Regression test for #67739 - -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::mem; @@ -10,7 +10,8 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::()]; - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values 0 } } diff --git a/src/test/ui/const-generics/issues/issue-68366.full.stderr b/src/test/ui/const-generics/issues/issue-68366.full.stderr new file mode 100644 index 0000000000..ac774f50c7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.full.stderr @@ -0,0 +1,21 @@ +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:12:13 + | +LL | impl Collatz<{Some(N)}> {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:18:12 + | +LL | impl Foo {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr new file mode 100644 index 0000000000..8d34bdc6ea --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr @@ -0,0 +1,29 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-68366.rs:12:37 + | +LL | impl Collatz<{Some(N)}> {} + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:12:13 + | +LL | impl Collatz<{Some(N)}> {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:18:12 + | +LL | impl Foo {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/const-generics/issues/issue-68366.rs b/src/test/ui/const-generics/issues/issue-68366.rs new file mode 100644 index 0000000000..819fcaffea --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.rs @@ -0,0 +1,21 @@ +// Checks that const expressions have a useful note explaining why they can't be evaluated. +// The note should relate to the fact that it cannot be shown forall N that it maps 1-1 to a new +// type. + +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +struct Collatz>; + +impl Collatz<{Some(N)}> {} +//~^ ERROR the const parameter +//[min]~^^ generic parameters must not be used inside of non trivial constant values + +struct Foo; + +impl Foo {} +//~^ ERROR the const parameter + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-68596.rs b/src/test/ui/const-generics/issues/issue-68596.rs index 1f96e7d3b4..3b27d4d68c 100644 --- a/src/test/ui/const-generics/issues/issue-68596.rs +++ b/src/test/ui/const-generics/issues/issue-68596.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct S(u8); diff --git a/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr b/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr new file mode 100644 index 0000000000..81c8f4392c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr @@ -0,0 +1,11 @@ +error: `[usize; 0]` is forbidden as the type of a const generic parameter + --> $DIR/issue-68615-adt.rs:7:23 + | +LL | struct Const {} + | ^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-68615-adt.rs b/src/test/ui/const-generics/issues/issue-68615-adt.rs index 140bb28ec5..d616f3ab95 100644 --- a/src/test/ui/const-generics/issues/issue-68615-adt.rs +++ b/src/test/ui/const-generics/issues/issue-68615-adt.rs @@ -1,8 +1,11 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Const {} +//[min]~^ ERROR `[usize; 0]` is forbidden as the type of a const generic parameter type MyConst = Const<{ [] }>; fn main() { diff --git a/src/test/ui/const-generics/issues/issue-68615-array.min.stderr b/src/test/ui/const-generics/issues/issue-68615-array.min.stderr new file mode 100644 index 0000000000..8f55a92fce --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68615-array.min.stderr @@ -0,0 +1,11 @@ +error: `[usize; 0]` is forbidden as the type of a const generic parameter + --> $DIR/issue-68615-array.rs:7:21 + | +LL | struct Foo {} + | ^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-68615-array.rs b/src/test/ui/const-generics/issues/issue-68615-array.rs index c384bc1e36..24c9a59a18 100644 --- a/src/test/ui/const-generics/issues/issue-68615-array.rs +++ b/src/test/ui/const-generics/issues/issue-68615-array.rs @@ -1,8 +1,11 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo {} +//[min]~^ ERROR `[usize; 0]` is forbidden as the type of a const generic parameter type MyFoo = Foo<{ [] }>; diff --git a/src/test/ui/const-generics/issues/issue-68977.full.stderr b/src/test/ui/const-generics/issues/issue-68977.full.stderr new file mode 100644 index 0000000000..3690bac3eb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-68977.rs:35:44 + | +LL | FxpStorageHelper: FxpStorage, + | ^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-68977.min.stderr b/src/test/ui/const-generics/issues/issue-68977.min.stderr new file mode 100644 index 0000000000..5b2137b244 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.min.stderr @@ -0,0 +1,18 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-68977.rs:29:17 + | +LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; + | ^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `INT_BITS` + | + = help: it is currently only allowed to use either `INT_BITS` or `{ INT_BITS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-68977.rs:29:28 + | +LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; + | ^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `FRAC_BITS` + | + = help: it is currently only allowed to use either `FRAC_BITS` or `{ FRAC_BITS }` as generic constants + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs index 346ea3c204..02e634efec 100644 --- a/src/test/ui/const-generics/issues/issue-68977.rs +++ b/src/test/ui/const-generics/issues/issue-68977.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct PhantomU8; @@ -25,11 +27,13 @@ fxp_storage_impls! { type FxpStorageHelper = PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; + //[min]~^ ERROR generic parameters must not be used inside of non trivial constant values + //[min]~| ERROR generic parameters must not be used inside of non trivial constant values struct Fxp where FxpStorageHelper: FxpStorage, - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter { storage: as FxpStorage>::SInt, } diff --git a/src/test/ui/const-generics/issues/issue-68977.stderr b/src/test/ui/const-generics/issues/issue-68977.stderr deleted file mode 100644 index e1190d9026..0000000000 --- a/src/test/ui/const-generics/issues/issue-68977.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-68977.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-68977.rs:31:44 - | -LL | FxpStorageHelper: FxpStorage, - | ^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-69654-run-pass.rs b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs new file mode 100644 index 0000000000..bbfd2183b0 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs @@ -0,0 +1,18 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features, unused_braces)] + +trait Bar {} +impl Bar for [u8; {7}] {} + +struct Foo {} +impl Foo +where + [u8; N]: Bar<[(); N]>, +{ + fn foo() {} +} + +fn main() { + Foo::foo(); +} diff --git a/src/test/ui/const-generics/issues/issue-69654.rs b/src/test/ui/const-generics/issues/issue-69654.rs new file mode 100644 index 0000000000..7e775999eb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654.rs @@ -0,0 +1,18 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Bar {} +impl Bar for [u8; T] {} +//~^ ERROR expected value, found type parameter `T` + +struct Foo {} +impl Foo +where + [u8; N]: Bar<[(); N]>, +{ + fn foo() {} +} + +fn main() { + Foo::foo(); +} diff --git a/src/test/ui/const-generics/issues/issue-69654.stderr b/src/test/ui/const-generics/issues/issue-69654.stderr new file mode 100644 index 0000000000..70af7bf25d --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654.stderr @@ -0,0 +1,9 @@ +error[E0423]: expected value, found type parameter `T` + --> $DIR/issue-69654.rs:5:25 + | +LL | impl Bar for [u8; T] {} + | ^ not a value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/const-generics/issues/issue-70125-1.rs b/src/test/ui/const-generics/issues/issue-70125-1.rs index 08a8309d43..04175089dc 100644 --- a/src/test/ui/const-generics/issues/issue-70125-1.rs +++ b/src/test/ui/const-generics/issues/issue-70125-1.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] const L: usize = 4; diff --git a/src/test/ui/const-generics/issues/issue-70125-1.stderr b/src/test/ui/const-generics/issues/issue-70125-1.stderr deleted file mode 100644 index 8ad4b25ae5..0000000000 --- a/src/test/ui/const-generics/issues/issue-70125-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-70125-1.rs:2:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-70125-2.rs b/src/test/ui/const-generics/issues/issue-70125-2.rs index fb7d4886a7..ceefc2dcb3 100644 --- a/src/test/ui/const-generics/issues/issue-70125-2.rs +++ b/src/test/ui/const-generics/issues/issue-70125-2.rs @@ -1,7 +1,8 @@ // run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn main() { <()>::foo(); diff --git a/src/test/ui/const-generics/issues/issue-70125-2.stderr b/src/test/ui/const-generics/issues/issue-70125-2.stderr deleted file mode 100644 index c1f9634810..0000000000 --- a/src/test/ui/const-generics/issues/issue-70125-2.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-70125-2.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-70167.rs b/src/test/ui/const-generics/issues/issue-70167.rs index b53cec8007..04c76a4dca 100644 --- a/src/test/ui/const-generics/issues/issue-70167.rs +++ b/src/test/ui/const-generics/issues/issue-70167.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub trait Trait: From<>::Item> { type Item; diff --git a/src/test/ui/const-generics/issues/issue-70167.stderr b/src/test/ui/const-generics/issues/issue-70167.stderr deleted file mode 100644 index 5d647e933c..0000000000 --- a/src/test/ui/const-generics/issues/issue-70167.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-70167.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-70225.rs b/src/test/ui/const-generics/issues/issue-70225.rs new file mode 100644 index 0000000000..8f8d753d0a --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-70225.rs @@ -0,0 +1,21 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] +#![deny(dead_code)] + +// We previously incorrectly linted `L` as unused here. +const L: usize = 3; + +fn main() { + let p = Printer {}; + p.print(); +} + +trait Print { + fn print(&self) -> usize { + 3 + } +} + +struct Printer {} +impl Print for Printer {} diff --git a/src/test/ui/const-generics/issues/issue-71169.stderr b/src/test/ui/const-generics/issues/issue-71169.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-71169.stderr rename to src/test/ui/const-generics/issues/issue-71169.full.stderr index 6d4cf4027c..b87825d20c 100644 --- a/src/test/ui/const-generics/issues/issue-71169.stderr +++ b/src/test/ui/const-generics/issues/issue-71169.full.stderr @@ -1,11 +1,11 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71169.rs:4:43 + --> $DIR/issue-71169.rs:6:43 | LL | fn foo() {} | ^^^ the type must not depend on the parameter `LEN` error: constant expression depends on a generic parameter - --> $DIR/issue-71169.rs:8:14 + --> $DIR/issue-71169.rs:11:14 | LL | foo::<4, DATA>(); | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-71169.min.stderr b/src/test/ui/const-generics/issues/issue-71169.min.stderr new file mode 100644 index 0000000000..79d6344335 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.min.stderr @@ -0,0 +1,18 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71169.rs:6:43 + | +LL | fn foo() {} + | ^^^ the type must not depend on the parameter `LEN` + +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-71169.rs:6:38 + | +LL | fn foo() {} + | ^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71169.rs b/src/test/ui/const-generics/issues/issue-71169.rs index 943a16cfcd..7007ec222c 100644 --- a/src/test/ui/const-generics/issues/issue-71169.rs +++ b/src/test/ui/const-generics/issues/issue-71169.rs @@ -1,10 +1,13 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo() {} //~^ ERROR the type of const parameters must not +//[min]~^^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() { const DATA: [u8; 4] = *b"ABCD"; foo::<4, DATA>(); - //~^ ERROR constant expression depends on + //[full]~^ ERROR constant expression depends on } diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-71381.stderr rename to src/test/ui/const-generics/issues/issue-71381.full.stderr index fd4ebe3dea..453ef00e6d 100644 --- a/src/test/ui/const-generics/issues/issue-71381.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.full.stderr @@ -1,23 +1,23 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71381.rs:13:82 + --> $DIR/issue-71381.rs:15:82 | LL | pub fn call_me(&self) { | ^^^^ the type must not depend on the parameter `Args` error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71381.rs:22:40 + --> $DIR/issue-71381.rs:24:40 | LL | const FN: unsafe extern "C" fn(Args), | ^^^^ the type must not depend on the parameter `Args` error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71381.rs:13:61 + --> $DIR/issue-71381.rs:15:61 | LL | pub fn call_me(&self) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71381.rs:22:19 + --> $DIR/issue-71381.rs:24:19 | LL | const FN: unsafe extern "C" fn(Args), | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-71381.min.stderr b/src/test/ui/const-generics/issues/issue-71381.min.stderr new file mode 100644 index 0000000000..453ef00e6d --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71381.min.stderr @@ -0,0 +1,27 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:15:82 + | +LL | pub fn call_me(&self) { + | ^^^^ the type must not depend on the parameter `Args` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:24:40 + | +LL | const FN: unsafe extern "C" fn(Args), + | ^^^^ the type must not depend on the parameter `Args` + +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71381.rs:15:61 + | +LL | pub fn call_me(&self) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71381.rs:24:19 + | +LL | const FN: unsafe extern "C" fn(Args), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71381.rs b/src/test/ui/const-generics/issues/issue-71381.rs index 08f9482394..65d88e553b 100644 --- a/src/test/ui/const-generics/issues/issue-71381.rs +++ b/src/test/ui/const-generics/issues/issue-71381.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Test(*const usize); diff --git a/src/test/ui/const-generics/issues/issue-71382.stderr b/src/test/ui/const-generics/issues/issue-71382.full.stderr similarity index 85% rename from src/test/ui/const-generics/issues/issue-71382.stderr rename to src/test/ui/const-generics/issues/issue-71382.full.stderr index 1652b0bdfa..3da85ee040 100644 --- a/src/test/ui/const-generics/issues/issue-71382.stderr +++ b/src/test/ui/const-generics/issues/issue-71382.full.stderr @@ -1,5 +1,5 @@ error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71382.rs:15:23 + --> $DIR/issue-71382.rs:17:23 | LL | fn test(&self) { | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-71382.min.stderr b/src/test/ui/const-generics/issues/issue-71382.min.stderr new file mode 100644 index 0000000000..3da85ee040 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71382.min.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71382.rs:17:23 + | +LL | fn test(&self) { + | ^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-71382.rs b/src/test/ui/const-generics/issues/issue-71382.rs index e0cf9812d9..12a7d08382 100644 --- a/src/test/ui/const-generics/issues/issue-71382.rs +++ b/src/test/ui/const-generics/issues/issue-71382.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Test(); diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-71611.stderr rename to src/test/ui/const-generics/issues/issue-71611.full.stderr index e2c9f22361..48d4bb361a 100644 --- a/src/test/ui/const-generics/issues/issue-71611.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.full.stderr @@ -1,11 +1,11 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71611.rs:4:31 + --> $DIR/issue-71611.rs:6:31 | LL | fn func(outer: A) { | ^ the type must not depend on the parameter `A` error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71611.rs:4:21 + --> $DIR/issue-71611.rs:6:21 | LL | fn func(outer: A) { | ^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-71611.min.stderr b/src/test/ui/const-generics/issues/issue-71611.min.stderr new file mode 100644 index 0000000000..48d4bb361a --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71611.min.stderr @@ -0,0 +1,15 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71611.rs:6:31 + | +LL | fn func(outer: A) { + | ^ the type must not depend on the parameter `A` + +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71611.rs:6:21 + | +LL | fn func(outer: A) { + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71611.rs b/src/test/ui/const-generics/issues/issue-71611.rs index 06ff38dec6..9b8e8be6bc 100644 --- a/src/test/ui/const-generics/issues/issue-71611.rs +++ b/src/test/ui/const-generics/issues/issue-71611.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn func(outer: A) { //~^ ERROR: using function pointers as const generic parameters is forbidden diff --git a/src/test/ui/const-generics/issues/issue-72352.stderr b/src/test/ui/const-generics/issues/issue-72352.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-72352.stderr rename to src/test/ui/const-generics/issues/issue-72352.full.stderr index bc48da1039..51f9467846 100644 --- a/src/test/ui/const-generics/issues/issue-72352.stderr +++ b/src/test/ui/const-generics/issues/issue-72352.full.stderr @@ -1,5 +1,5 @@ error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-72352.rs:6:42 + --> $DIR/issue-72352.rs:8:42 | LL | unsafe fn unsafely_do_the_thing usize>(ptr: *const i8) -> usize { | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72352.min.stderr b/src/test/ui/const-generics/issues/issue-72352.min.stderr new file mode 100644 index 0000000000..51f9467846 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72352.min.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-72352.rs:8:42 + | +LL | unsafe fn unsafely_do_the_thing usize>(ptr: *const i8) -> usize { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-72352.rs b/src/test/ui/const-generics/issues/issue-72352.rs index e977af8deb..1517f3dae4 100644 --- a/src/test/ui/const-generics/issues/issue-72352.rs +++ b/src/test/ui/const-generics/issues/issue-72352.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::ffi::{CStr, CString}; diff --git a/src/test/ui/const-generics/issues/issue-72787.stderr b/src/test/ui/const-generics/issues/issue-72787.full.stderr similarity index 88% rename from src/test/ui/const-generics/issues/issue-72787.stderr rename to src/test/ui/const-generics/issues/issue-72787.full.stderr index ed892e46bb..b4c79d4171 100644 --- a/src/test/ui/const-generics/issues/issue-72787.stderr +++ b/src/test/ui/const-generics/issues/issue-72787.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:9:32 + --> $DIR/issue-72787.rs:11:32 | LL | Condition<{ LHS <= RHS }>: True | ^^^^ @@ -7,7 +7,7 @@ LL | Condition<{ LHS <= RHS }>: True = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -15,7 +15,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -23,7 +23,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -31,7 +31,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr new file mode 100644 index 0000000000..d3e9887fe2 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr @@ -0,0 +1,57 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:11:17 + | +LL | Condition<{ LHS <= RHS }>: True + | ^^^ non-trivial anonymous constants must not depend on the parameter `LHS` + | + = help: it is currently only allowed to use either `LHS` or `{ LHS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:11:24 + | +LL | Condition<{ LHS <= RHS }>: True + | ^^^ non-trivial anonymous constants must not depend on the parameter `RHS` + | + = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:26:25 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^ non-trivial anonymous constants must not depend on the parameter `I` + | + = help: it is currently only allowed to use either `I` or `{ I }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:26:36 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^ non-trivial anonymous constants must not depend on the parameter `J` + | + = help: it is currently only allowed to use either `J` or `{ J }` as generic constants + +error[E0283]: type annotations needed + --> $DIR/issue-72787.rs:22:26 + | +LL | pub trait True {} + | -------------- required by this bound in `True` +... +LL | IsLessOrEqual: True, + | ^^^^ cannot infer type for struct `IsLessOrEqual` + | + = note: cannot satisfy `IsLessOrEqual: True` + +error[E0283]: type annotations needed + --> $DIR/issue-72787.rs:22:26 + | +LL | pub trait True {} + | -------------- required by this bound in `True` +... +LL | IsLessOrEqual: True, + | ^^^^ cannot infer type for struct `IsLessOrEqual` + | + = note: cannot satisfy `IsLessOrEqual: True` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs index a368c226ec..45c20191c8 100644 --- a/src/test/ui/const-generics/issues/issue-72787.rs +++ b/src/test/ui/const-generics/issues/issue-72787.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct IsLessOrEqual; pub struct Condition; @@ -7,7 +9,9 @@ pub trait True {} impl True for IsLessOrEqual where Condition<{ LHS <= RHS }>: True -//~^ Error constant expression depends on a generic parameter +//[full]~^ Error constant expression depends on a generic parameter +//[min]~^^ Error generic parameters must not be used inside of non trivial constant values +//[min]~| Error generic parameters must not be used inside of non trivial constant values { } impl True for Condition {} @@ -16,12 +20,16 @@ struct S; impl S where IsLessOrEqual: True, +//[min]~^ Error type annotations needed [E0283] +//[min]~| Error type annotations needed [E0283] IsLessOrEqual: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, -//~^ Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter +//[full]~^ constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[min]~^^^^^ Error generic parameters must not be used inside of non trivial constant values +//[min]~| Error generic parameters must not be used inside of non trivial constant values // Condition<{ 8 - I <= 8 - J }>: True, { fn print() { diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr similarity index 84% rename from src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr rename to src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr index a9f664d0ac..e4105a3df1 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-72819-generic-in-const-eval.rs:7:47 + --> $DIR/issue-72819-generic-in-const-eval.rs:9:47 | LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, | ^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr new file mode 100644 index 0000000000..48a1f0bd19 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72819-generic-in-const-eval.rs:9:17 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs index 225593c317..b653b91d99 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs @@ -1,11 +1,14 @@ // Regression test for #72819: ICE due to failure in resolving the const generic in `Arr`'s type // bounds. +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] -#![feature(const_generics)] -#![allow(incomplete_features)] struct Arr where Assert::<{N < usize::max_value() / 2}>: IsTrue, -//~^ ERROR constant expression depends on a generic parameter +//[full]~^ ERROR constant expression depends on a generic parameter +//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values { } diff --git a/src/test/ui/const-generics/issues/issue-73120.rs b/src/test/ui/const-generics/issues/issue-73120.rs index aea4de39f7..c153a93cde 100644 --- a/src/test/ui/const-generics/issues/issue-73120.rs +++ b/src/test/ui/const-generics/issues/issue-73120.rs @@ -1,3 +1,4 @@ +// revisions: full min // check-pass // aux-build:const_generic_issues_lib.rs extern crate const_generic_issues_lib as lib2; diff --git a/src/test/ui/const-generics/issues/issue-73260.rs b/src/test/ui/const-generics/issues/issue-73260.rs new file mode 100644 index 0000000000..351d6849af --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.rs @@ -0,0 +1,20 @@ +// compile-flags: -Zsave-analysis + +#![feature(const_generics)] +#![allow(incomplete_features)] +struct Arr +where Assert::<{N < usize::max_value() / 2}>: IsTrue, //~ ERROR constant expression +{ +} + +enum Assert {} + +trait IsTrue {} + +impl IsTrue for Assert {} + +fn main() { + let x: Arr<{usize::max_value()}> = Arr {}; + //~^ ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/src/test/ui/const-generics/issues/issue-73260.stderr b/src/test/ui/const-generics/issues/issue-73260.stderr new file mode 100644 index 0000000000..e22612ed5e --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.stderr @@ -0,0 +1,29 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-73260.rs:6:47 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:12 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:40 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-73491.min.stderr b/src/test/ui/const-generics/issues/issue-73491.min.stderr new file mode 100644 index 0000000000..5bf3671d38 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73491.min.stderr @@ -0,0 +1,11 @@ +error: `[u32; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-73491.rs:9:19 + | +LL | fn hoge() {} + | ^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-73491.rs b/src/test/ui/const-generics/issues/issue-73491.rs index 05e1513bb7..4f6c44ad2c 100644 --- a/src/test/ui/const-generics/issues/issue-73491.rs +++ b/src/test/ui/const-generics/issues/issue-73491.rs @@ -1,9 +1,12 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] const LEN: usize = 1024; fn hoge() {} +//[min]~^ ERROR `[u32; _]` is forbidden as the type of a const generic parameter fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-73508.full.stderr b/src/test/ui/const-generics/issues/issue-73508.full.stderr new file mode 100644 index 0000000000..0816bad35b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73508.full.stderr @@ -0,0 +1,8 @@ +error: using raw pointers as const generic parameters is forbidden + --> $DIR/issue-73508.rs:6:33 + | +LL | pub const fn func_name() {} + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-73508.min.stderr b/src/test/ui/const-generics/issues/issue-73508.min.stderr new file mode 100644 index 0000000000..0816bad35b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73508.min.stderr @@ -0,0 +1,8 @@ +error: using raw pointers as const generic parameters is forbidden + --> $DIR/issue-73508.rs:6:33 + | +LL | pub const fn func_name() {} + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-73508.rs b/src/test/ui/const-generics/issues/issue-73508.rs index ba2e2a38e7..21b87f7f90 100644 --- a/src/test/ui/const-generics/issues/issue-73508.rs +++ b/src/test/ui/const-generics/issues/issue-73508.rs @@ -1,4 +1,7 @@ -#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub const fn func_name() {} //~^ ERROR using raw pointers diff --git a/src/test/ui/const-generics/issues/issue-73508.stderr b/src/test/ui/const-generics/issues/issue-73508.stderr deleted file mode 100644 index 23ad1818b6..0000000000 --- a/src/test/ui/const-generics/issues/issue-73508.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-73508.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: using raw pointers as const generic parameters is forbidden - --> $DIR/issue-73508.rs:3:33 - | -LL | pub const fn func_name() {} - | ^^^^^^^^^^ - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-74101.min.stderr b/src/test/ui/const-generics/issues/issue-74101.min.stderr new file mode 100644 index 0000000000..8062faefbe --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74101.min.stderr @@ -0,0 +1,20 @@ +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-74101.rs:7:18 + | +LL | fn test() {} + | ^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-74101.rs:10:21 + | +LL | struct Foo; + | ^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-74101.rs b/src/test/ui/const-generics/issues/issue-74101.rs index 2f427ef3a2..2a7d31ac8d 100644 --- a/src/test/ui/const-generics/issues/issue-74101.rs +++ b/src/test/ui/const-generics/issues/issue-74101.rs @@ -1,9 +1,13 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn test() {} +//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter struct Foo; +//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74255.min.stderr b/src/test/ui/const-generics/issues/issue-74255.min.stderr new file mode 100644 index 0000000000..86937d715c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74255.min.stderr @@ -0,0 +1,11 @@ +error: `IceEnum` is forbidden as the type of a const generic parameter + --> $DIR/issue-74255.rs:15:31 + | +LL | fn ice_struct_fn() {} + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-74255.rs b/src/test/ui/const-generics/issues/issue-74255.rs index 55ccf57dc9..b277c27346 100644 --- a/src/test/ui/const-generics/issues/issue-74255.rs +++ b/src/test/ui/const-generics/issues/issue-74255.rs @@ -1,6 +1,8 @@ -// check-pass -#![feature(const_generics)] -#![allow(dead_code, incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #[derive(PartialEq, Eq)] enum IceEnum { @@ -11,6 +13,7 @@ struct IceStruct; impl IceStruct { fn ice_struct_fn() {} + //[min]~^ ERROR `IceEnum` is forbidden as the type of a const generic parameter } fn main() { diff --git a/src/test/ui/const-generics/issues/issue-74634.rs b/src/test/ui/const-generics/issues/issue-74634.rs new file mode 100644 index 0000000000..0f23fa92c3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.rs @@ -0,0 +1,27 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait If {} +impl If for () {} + +trait IsZero { + type Answer; +} + +struct True; +struct False; + +impl IsZero for () +where (): If<{N == 0}> { //~ERROR constant expression + type Answer = True; +} + +trait Foobar {} + +impl Foobar for () +where (): IsZero {} + +impl Foobar for () +where (): IsZero {} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74634.stderr b/src/test/ui/const-generics/issues/issue-74634.stderr new file mode 100644 index 0000000000..091a1ac7b9 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-74634.rs:15:11 + | +LL | where (): If<{N == 0}> { + | ^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-75047.min.stderr b/src/test/ui/const-generics/issues/issue-75047.min.stderr new file mode 100644 index 0000000000..edc54b082d --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-75047.min.stderr @@ -0,0 +1,11 @@ +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-75047.rs:15:21 + | +LL | struct Foo::value()]>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-75047.rs b/src/test/ui/const-generics/issues/issue-75047.rs index 5d068d851c..7bab7cdd09 100644 --- a/src/test/ui/const-generics/issues/issue-75047.rs +++ b/src/test/ui/const-generics/issues/issue-75047.rs @@ -1,6 +1,8 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Bar(T); @@ -11,5 +13,6 @@ impl Bar { } struct Foo::value()]>; +//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-76595.rs b/src/test/ui/const-generics/issues/issue-76595.rs new file mode 100644 index 0000000000..9fdbbff66e --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.rs @@ -0,0 +1,17 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Bool; + +trait True {} + +impl True for Bool {} + +fn test() where Bool<{core::mem::size_of::() > 4}>: True { + todo!() +} + +fn main() { + test::<2>(); + //~^ ERROR wrong number of type +} diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr new file mode 100644 index 0000000000..f258d29771 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -0,0 +1,9 @@ +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/issue-76595.rs:15:5 + | +LL | test::<2>(); + | ^^^^^^^^^ expected 1 type argument + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr new file mode 100644 index 0000000000..089937e66c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr @@ -0,0 +1,18 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-76701-ty-param-in-const.rs:6:21 + | +LL | fn ty_param() -> [u8; std::mem::size_of::()] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/issue-76701-ty-param-in-const.rs:12:37 + | +LL | fn const_param() -> [u8; N + 1] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr new file mode 100644 index 0000000000..a39495e0b2 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr @@ -0,0 +1,18 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-76701-ty-param-in-const.rs:6:46 + | +LL | fn ty_param() -> [u8; std::mem::size_of::()] { + | ^ non-trivial anonymous constants must not depend on the parameter `T` + | + = note: type parameters are currently not permitted in anonymous constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-76701-ty-param-in-const.rs:12:42 + | +LL | fn const_param() -> [u8; N + 1] { + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs new file mode 100644 index 0000000000..9252b59236 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs @@ -0,0 +1,18 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +fn ty_param() -> [u8; std::mem::size_of::()] { + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values + todo!() +} + +fn const_param() -> [u8; N + 1] { + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values + todo!() +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs b/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs index c22e61d0ce..28f80702dc 100644 --- a/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs +++ b/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait T { fn f(); diff --git a/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr b/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr deleted file mode 100644 index 931701b64b..0000000000 --- a/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue70273-assoc-fn.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/min-and-full-same-time.rs b/src/test/ui/const-generics/min-and-full-same-time.rs new file mode 100644 index 0000000000..2365adc3a8 --- /dev/null +++ b/src/test/ui/const-generics/min-and-full-same-time.rs @@ -0,0 +1,7 @@ +#![feature(const_generics)] +//~^ ERROR features `const_generics` and `min_const_generics` are incompatible +#![allow(incomplete_features)] +#![feature(min_const_generics)] + + +fn main() {} diff --git a/src/test/ui/const-generics/min-and-full-same-time.stderr b/src/test/ui/const-generics/min-and-full-same-time.stderr new file mode 100644 index 0000000000..907fec9bbe --- /dev/null +++ b/src/test/ui/const-generics/min-and-full-same-time.stderr @@ -0,0 +1,13 @@ +error: features `const_generics` and `min_const_generics` are incompatible, using them at the same time is not allowed + --> $DIR/min-and-full-same-time.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ +... +LL | #![feature(min_const_generics)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs new file mode 100644 index 0000000000..02944e2bff --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs @@ -0,0 +1,27 @@ +#![feature(min_const_generics)] + +// This test checks that non-static lifetimes are prohibited under `min_const_generics`. It +// currently emits an error with `min_const_generics`. This will ICE under `const_generics`. + +fn test() {} + +fn issue_75323_and_74447_1<'a>() -> &'a () { + test::<{ let _: &'a (); 3 },>(); + //~^ ERROR a non-static lifetime is not allowed in a `const` + &() +} + +fn issue_75323_and_74447_2() { + test::<{ let _: &(); 3 },>(); +} + +fn issue_75323_and_74447_3() { + test::<{ let _: &'static (); 3 },>(); +} + +fn issue_73375<'a>() { + [(); (|_: &'a u8| (), 0).1]; + //~^ ERROR a non-static lifetime is not allowed in a `const` +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr new file mode 100644 index 0000000000..cdfd491e39 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr @@ -0,0 +1,21 @@ +error[E0658]: a non-static lifetime is not allowed in a `const` + --> $DIR/forbid-non-static-lifetimes.rs:9:22 + | +LL | test::<{ let _: &'a (); 3 },>(); + | ^^ + | + = note: see issue #44580 for more information + = help: add `#![feature(const_generics)]` to the crate attributes to enable + +error[E0658]: a non-static lifetime is not allowed in a `const` + --> $DIR/forbid-non-static-lifetimes.rs:23:16 + | +LL | [(); (|_: &'a u8| (), 0).1]; + | ^^ + | + = note: see issue #44580 for more information + = help: add `#![feature(const_generics)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs new file mode 100644 index 0000000000..0973b373c1 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs @@ -0,0 +1,27 @@ +#![feature(min_const_generics)] + +trait Foo { + fn t1() -> [u8; std::mem::size_of::()]; //~ERROR generic parameters +} + +struct Bar(T); + +impl Bar { + fn t2() -> [u8; std::mem::size_of::()] { todo!() } // ok +} + +impl Bar { + fn t3() -> [u8; std::mem::size_of::()] {} //~ERROR generic `Self` +} + +trait Baz { + fn hey(); +} + +impl Baz for u16 { + fn hey() { + let _: [u8; std::mem::size_of::()]; // ok + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr new file mode 100644 index 0000000000..edb77a8743 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -0,0 +1,22 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/self-ty-in-const-1.rs:4:41 + | +LL | fn t1() -> [u8; std::mem::size_of::()]; + | ^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = note: type parameters are currently not permitted in anonymous constants + +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/self-ty-in-const-1.rs:14:41 + | +LL | fn t3() -> [u8; std::mem::size_of::()] {} + | ^^^^ + | +note: not a concrete type + --> $DIR/self-ty-in-const-1.rs:13:9 + | +LL | impl Bar { + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs new file mode 100644 index 0000000000..e7f80d5008 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs @@ -0,0 +1,21 @@ +#![feature(min_const_generics)] + +struct Bar(T); + +trait Baz { + fn hey(); +} + +impl Baz for u16 { + fn hey() { + let _: [u8; std::mem::size_of::()]; // ok + } +} + +impl Baz for Bar { + fn hey() { + let _: [u8; std::mem::size_of::()]; //~ERROR generic `Self` + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr new file mode 100644 index 0000000000..9ac6410a29 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr @@ -0,0 +1,14 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/self-ty-in-const-2.rs:17:41 + | +LL | let _: [u8; std::mem::size_of::()]; + | ^^^^ + | +note: not a concrete type + --> $DIR/self-ty-in-const-2.rs:15:17 + | +LL | impl Baz for Bar { + | ^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index ded6f882ca..075bdceccf 100644 --- a/src/test/ui/const-generics/nested-type.full.stderr +++ b/src/test/ui/const-generics/nested-type.full.stderr @@ -8,7 +8,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() - | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value` + | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{constant#0}::Foo::<17_usize>::value` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr index 55f6fe7cc1..733b02fa85 100644 --- a/src/test/ui/const-generics/nested-type.min.stderr +++ b/src/test/ui/const-generics/nested-type.min.stderr @@ -24,7 +24,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() - | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value` + | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{constant#0}::Foo::<17_usize>::value` error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/occurs-check/bind-param.rs b/src/test/ui/const-generics/occurs-check/bind-param.rs new file mode 100644 index 0000000000..68d1865000 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/bind-param.rs @@ -0,0 +1,17 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +// This test does not use any "unevaluated" consts, so it should compile just fine. + +fn bind(value: [u8; N]) -> [u8; N] { + todo!() +} + +fn sink(_: [u8; 5]) {} + +fn main() { + let mut arr = Default::default(); + arr = bind(arr); + sink(arr); +} diff --git a/src/test/ui/const-generics/occurs-check/unify-fixpoint.rs b/src/test/ui/const-generics/occurs-check/unify-fixpoint.rs new file mode 100644 index 0000000000..3cb9b7b9da --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-fixpoint.rs @@ -0,0 +1,18 @@ +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +// It depends on how we normalize constants and how const equate works if this +// compiles. +// +// Please ping @lcnr if the output if this test changes. + + +fn bind(value: [u8; N + 2]) -> [u8; N * 2] { + //~^ ERROR constant expression depends on a generic parameter + //~| ERROR constant expression depends on a generic parameter + todo!() +} + +fn main() { + let mut arr = Default::default(); + arr = bind::<2>(arr); +} diff --git a/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr new file mode 100644 index 0000000000..671f1103dc --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr @@ -0,0 +1,27 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unify-fixpoint.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/unify-fixpoint.rs:9:32 + | +LL | fn bind(value: [u8; N + 2]) -> [u8; N * 2] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/unify-fixpoint.rs:9:48 + | +LL | fn bind(value: [u8; N + 2]) -> [u8; N * 2] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs new file mode 100644 index 0000000000..552b1b2a66 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs @@ -0,0 +1,17 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +// This test would try to unify `N` with `N + 1` which must fail the occurs check. + +fn bind(value: [u8; N]) -> [u8; N + 1] { + //~^ ERROR constant expression depends on a generic parameter + todo!() +} + +fn sink(_: [u8; 5]) {} + +fn main() { + let mut arr = Default::default(); + arr = bind(arr); + sink(arr); +} diff --git a/src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr new file mode 100644 index 0000000000..c1ac7eec1e --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/unify-n-nplusone.rs:6:44 + | +LL | fn bind(value: [u8; N]) -> [u8; N + 1] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-1.rs b/src/test/ui/const-generics/occurs-check/unused-substs-1.rs new file mode 100644 index 0000000000..f56687ecd9 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-1.rs @@ -0,0 +1,14 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Bar {} +impl Bar for A<{ 6 + 1 }> {} + +struct A +where + A: Bar; + +fn main() { + let _ = A; +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-2.rs b/src/test/ui/const-generics/occurs-check/unused-substs-2.rs new file mode 100644 index 0000000000..12444ec531 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-2.rs @@ -0,0 +1,27 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// +// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty` we introduced an +// artificial inference cycle. +struct Foo; + +trait Bind { + fn bind() -> (T, Self); +} + +// `N` has to be `ConstKind::Unevaluated`. +impl Bind for Foo<{ 6 + 1 }> { + fn bind() -> (T, Self) { + (panic!(), Foo) + } +} + +fn main() { + let (mut t, foo) = Foo::bind(); + // `t` is `ty::Infer(TyVar(_#1t))` + // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + t = foo; +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-3.rs b/src/test/ui/const-generics/occurs-check/unused-substs-3.rs new file mode 100644 index 0000000000..187e27382f --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-3.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// +// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty` we introduced an +// artificial inference cycle. +fn bind() -> (T, [u8; 6 + 1]) { + todo!() +} + +fn main() { + let (mut t, foo) = bind(); + // `t` is `ty::Infer(TyVar(_#1t))` + // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + t = foo; +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-4.rs b/src/test/ui/const-generics/occurs-check/unused-substs-4.rs new file mode 100644 index 0000000000..8e42ceb6d7 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-4.rs @@ -0,0 +1,12 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn bind(value: [u8; N]) -> [u8; 3 + 4] { + todo!() +} + +fn main() { + let mut arr = Default::default(); + arr = bind(arr); +} diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr index 461822a960..e545ae8571 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr @@ -12,7 +12,7 @@ error: generic parameters must not be used inside of non trivial constant values LL | struct Foo()]>(T, U); | ^ non-trivial anonymous constants must not depend on the parameter `T` | - = help: it is currently only allowed to use either `T` or `{ T }` as generic constants + = note: type parameters are currently not permitted in anonymous constants error: constant values inside of type parameter defaults must not depend on generic parameters --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21 diff --git a/src/test/ui/const-generics/std/const-generics-range.min.stderr b/src/test/ui/const-generics/std/const-generics-range.min.stderr new file mode 100644 index 0000000000..97be6ee644 --- /dev/null +++ b/src/test/ui/const-generics/std/const-generics-range.min.stderr @@ -0,0 +1,56 @@ +error: `std::ops::Range` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:8:24 + | +LL | struct _Range>; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeFrom` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:13:28 + | +LL | struct _RangeFrom>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeFull` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:18:28 + | +LL | struct _RangeFull; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeInclusive` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:24:33 + | +LL | struct _RangeInclusive>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeTo` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:29:26 + | +LL | struct _RangeTo>; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeToInclusive` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:34:35 + | +LL | struct _RangeToInclusive>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/const-generics/std/const-generics-range.rs b/src/test/ui/const-generics/std/const-generics-range.rs index 6d56fe0d7b..136ac35289 100644 --- a/src/test/ui/const-generics/std/const-generics-range.rs +++ b/src/test/ui/const-generics/std/const-generics-range.rs @@ -1,30 +1,38 @@ -// check-pass -#![allow(incomplete_features)] -#![feature(const_generics)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // `Range` should be usable within const generics: struct _Range>; +//[min]~^ ERROR `std::ops::Range` is forbidden const RANGE : _Range<{ 0 .. 1000 }> = _Range; // `RangeFrom` should be usable within const generics: struct _RangeFrom>; +//[min]~^ ERROR `RangeFrom` is forbidden const RANGE_FROM : _RangeFrom<{ 0 .. }> = _RangeFrom; // `RangeFull` should be usable within const generics: struct _RangeFull; +//[min]~^ ERROR `RangeFull` is forbidden const RANGE_FULL : _RangeFull<{ .. }> = _RangeFull; // Regression test for #70155 // `RangeInclusive` should be usable within const generics: struct _RangeInclusive>; +//[min]~^ ERROR `RangeInclusive` is forbidden const RANGE_INCLUSIVE : _RangeInclusive<{ 0 ..= 999 }> = _RangeInclusive; // `RangeTo` should be usable within const generics: struct _RangeTo>; +//[min]~^ ERROR `RangeTo` is forbidden const RANGE_TO : _RangeTo<{ .. 1000 }> = _RangeTo; // `RangeToInclusive` should be usable within const generics: struct _RangeToInclusive>; +//[min]~^ ERROR `RangeToInclusive` is forbidden const RANGE_TO_INCLUSIVE : _RangeToInclusive<{ ..= 999 }> = _RangeToInclusive; pub fn main() {} diff --git a/src/test/ui/const-generics/type-after-const-ok.min.stderr b/src/test/ui/const-generics/type-after-const-ok.min.stderr new file mode 100644 index 0000000000..67a44d2c5b --- /dev/null +++ b/src/test/ui/const-generics/type-after-const-ok.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/type-after-const-ok.rs:9:26 + | +LL | struct A(T); + | -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/type-after-const-ok.rs b/src/test/ui/const-generics/type-after-const-ok.rs index fc977d6617..69227cdf19 100644 --- a/src/test/ui/const-generics/type-after-const-ok.rs +++ b/src/test/ui/const-generics/type-after-const-ok.rs @@ -1,10 +1,12 @@ -// run-pass +// [full] run-pass +// revisions: full min // Verifies that having generic parameters after constants is permitted - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #[allow(dead_code)] struct A(T); +//[min]~^ ERROR type parameters must be declared prior to const parameters fn main() {} diff --git a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs index c8db91b62b..aa85376bf0 100644 --- a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs +++ b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs @@ -1,5 +1,6 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Struct(()); diff --git a/src/test/ui/const-generics/type-dependent/issue-61936.rs b/src/test/ui/const-generics/type-dependent/issue-61936.rs index a7a923c6a5..f3b19109a7 100644 --- a/src/test/ui/const-generics/type-dependent/issue-61936.rs +++ b/src/test/ui/const-generics/type-dependent/issue-61936.rs @@ -1,23 +1,25 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait SliceExt { - fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N>; + fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N>; } impl SliceExt for [T] { - fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N> { - ArrayWindows{ idx: 0, slice: &self } + fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N> { + ArrayWindowsExample{ idx: 0, slice: &self } } } -struct ArrayWindows<'a, T, const N: usize> { +struct ArrayWindowsExample<'a, T, const N: usize> { slice: &'a [T], idx: usize, } -impl <'a, T: Clone, const N: usize> Iterator for ArrayWindows<'a, T, N> { +impl <'a, T: Clone, const N: usize> Iterator for ArrayWindowsExample<'a, T, N> { type Item = [T; N]; fn next(&mut self) -> Option { // Note: this is unsound for some `T` and not meant as an example @@ -43,7 +45,7 @@ const FOUR: usize = 4; fn main() { let v: Vec = vec![0; 100]; - for array in v.as_slice().array_windows::() { + for array in v.as_slice().array_windows_example::() { assert_eq!(array, [0, 0, 0, 0]) } } diff --git a/src/test/ui/const-generics/type-dependent/issue-63695.rs b/src/test/ui/const-generics/type-dependent/issue-63695.rs index f3c2e17759..465b66b09c 100644 --- a/src/test/ui/const-generics/type-dependent/issue-63695.rs +++ b/src/test/ui/const-generics/type-dependent/issue-63695.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait T { fn test(&self) -> i32 { A } diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-1.rs b/src/test/ui/const-generics/type-dependent/issue-67144-1.rs index a3d0595919..3d4910e9e4 100644 --- a/src/test/ui/const-generics/type-dependent/issue-67144-1.rs +++ b/src/test/ui/const-generics/type-dependent/issue-67144-1.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct X; diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-2.rs b/src/test/ui/const-generics/type-dependent/issue-67144-2.rs index c53a149fa8..0868d309b3 100644 --- a/src/test/ui/const-generics/type-dependent/issue-67144-2.rs +++ b/src/test/ui/const-generics/type-dependent/issue-67144-2.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct A; diff --git a/src/test/ui/const-generics/type-dependent/issue-69816.rs b/src/test/ui/const-generics/type-dependent/issue-69816.rs index cbe86cef32..4a374dc1db 100644 --- a/src/test/ui/const-generics/type-dependent/issue-69816.rs +++ b/src/test/ui/const-generics/type-dependent/issue-69816.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait IterExt: Sized + Iterator { fn default_for_size(self) -> [Self::Item; N] diff --git a/src/test/ui/const-generics/type-dependent/issue-70217.rs b/src/test/ui/const-generics/type-dependent/issue-70217.rs index caa611cbd7..ba5a42e47e 100644 --- a/src/test/ui/const-generics/type-dependent/issue-70217.rs +++ b/src/test/ui/const-generics/type-dependent/issue-70217.rs @@ -1,6 +1,9 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min + +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Struct; diff --git a/src/test/ui/const-generics/type-dependent/issue-70507.rs b/src/test/ui/const-generics/type-dependent/issue-70507.rs index 6fcf4116d4..234c09e04a 100644 --- a/src/test/ui/const-generics/type-dependent/issue-70507.rs +++ b/src/test/ui/const-generics/type-dependent/issue-70507.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait ConstChunksExactTrait { fn const_chunks_exact(&self) -> ConstChunksExact<'_, T, {N}>; diff --git a/src/test/ui/const-generics/type-dependent/issue-70586.rs b/src/test/ui/const-generics/type-dependent/issue-70586.rs index 5a0888506e..fd52373cee 100644 --- a/src/test/ui/const-generics/type-dependent/issue-70586.rs +++ b/src/test/ui/const-generics/type-dependent/issue-70586.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::marker::PhantomData; diff --git a/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr b/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr new file mode 100644 index 0000000000..8656239605 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr @@ -0,0 +1,20 @@ +error: `&'static str` is forbidden as the type of a const generic parameter + --> $DIR/issue-71348.rs:11:24 + | +LL | trait Get<'a, const N: &'static str> { + | ^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `&'static str` is forbidden as the type of a const generic parameter + --> $DIR/issue-71348.rs:19:25 + | +LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target + | ^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/type-dependent/issue-71348.rs b/src/test/ui/const-generics/type-dependent/issue-71348.rs index ec22dcdf60..772e179746 100644 --- a/src/test/ui/const-generics/type-dependent/issue-71348.rs +++ b/src/test/ui/const-generics/type-dependent/issue-71348.rs @@ -1,12 +1,15 @@ -// run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo { i: i32, } trait Get<'a, const N: &'static str> { + //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter type Target: 'a; fn get(&'a self) -> &'a Self::Target; @@ -14,6 +17,7 @@ trait Get<'a, const N: &'static str> { impl Foo { fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target + //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter where Self: Get<'a, N>, { diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.full.stderr b/src/test/ui/const-generics/type-dependent/issue-71382.full.stderr new file mode 100644 index 0000000000..da1d3270b7 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71382.full.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71382.rs:17:23 + | +LL | fn test u8>(&self) -> u8 { + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.min.stderr b/src/test/ui/const-generics/type-dependent/issue-71382.min.stderr new file mode 100644 index 0000000000..da1d3270b7 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71382.min.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71382.rs:17:23 + | +LL | fn test u8>(&self) -> u8 { + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.rs b/src/test/ui/const-generics/type-dependent/issue-71382.rs index 05abd48881..497fd1381d 100644 --- a/src/test/ui/const-generics/type-dependent/issue-71382.rs +++ b/src/test/ui/const-generics/type-dependent/issue-71382.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Test; diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.stderr b/src/test/ui/const-generics/type-dependent/issue-71382.stderr deleted file mode 100644 index f441b71031..0000000000 --- a/src/test/ui/const-generics/type-dependent/issue-71382.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-71382.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71382.rs:15:23 - | -LL | fn test u8>(&self) -> u8 { - | ^^^^^^^^^^ - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/type-dependent/issue-71805.rs b/src/test/ui/const-generics/type-dependent/issue-71805.rs index 6823d780ae..2aaf12cea4 100644 --- a/src/test/ui/const-generics/type-dependent/issue-71805.rs +++ b/src/test/ui/const-generics/type-dependent/issue-71805.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::mem::MaybeUninit; diff --git a/src/test/ui/const-generics/type-dependent/issue-73730.rs b/src/test/ui/const-generics/type-dependent/issue-73730.rs index d90cc50ddc..3e53190ee4 100644 --- a/src/test/ui/const-generics/type-dependent/issue-73730.rs +++ b/src/test/ui/const-generics/type-dependent/issue-73730.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Foo<'a, A>: Iterator { fn bar(&mut self) -> *const [A; N]; diff --git a/src/test/ui/const-generics/type-dependent/non-local.rs b/src/test/ui/const-generics/type-dependent/non-local.rs index e6f3eb075f..747664a096 100644 --- a/src/test/ui/const-generics/type-dependent/non-local.rs +++ b/src/test/ui/const-generics/type-dependent/non-local.rs @@ -1,7 +1,9 @@ // aux-build:type_dependent_lib.rs // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] extern crate type_dependent_lib; diff --git a/src/test/ui/const-generics/type-dependent/qpath.rs b/src/test/ui/const-generics/type-dependent/qpath.rs index f3f98e5faf..ec23ff1d22 100644 --- a/src/test/ui/const-generics/type-dependent/qpath.rs +++ b/src/test/ui/const-generics/type-dependent/qpath.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct A; impl A { diff --git a/src/test/ui/const-generics/type-dependent/simple.rs b/src/test/ui/const-generics/type-dependent/simple.rs index cc7c50d8fd..70af655092 100644 --- a/src/test/ui/const-generics/type-dependent/simple.rs +++ b/src/test/ui/const-generics/type-dependent/simple.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct R; diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr b/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr new file mode 100644 index 0000000000..a530e63449 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch.rs:12:27 + | +LL | assert_eq!(R.method::<1u16>(), 1); + | ^^^^ expected `u8`, found `u16` + | +help: change the type of the numeric literal from `u16` to `u8` + | +LL | assert_eq!(R.method::<1u8>(), 1); + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr b/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr new file mode 100644 index 0000000000..a530e63449 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch.rs:12:27 + | +LL | assert_eq!(R.method::<1u16>(), 1); + | ^^^^ expected `u8`, found `u16` + | +help: change the type of the numeric literal from `u16` to `u8` + | +LL | assert_eq!(R.method::<1u8>(), 1); + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.rs b/src/test/ui/const-generics/type-dependent/type-mismatch.rs index 0c71f338bd..67d80973f0 100644 --- a/src/test/ui/const-generics/type-dependent/type-mismatch.rs +++ b/src/test/ui/const-generics/type-dependent/type-mismatch.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct R; diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.stderr b/src/test/ui/const-generics/type-dependent/type-mismatch.stderr deleted file mode 100644 index 5bb7c5b0ea..0000000000 --- a/src/test/ui/const-generics/type-dependent/type-mismatch.stderr +++ /dev/null @@ -1,23 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-mismatch.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error[E0308]: mismatched types - --> $DIR/type-mismatch.rs:10:27 - | -LL | assert_eq!(R.method::<1u16>(), 1); - | ^^^^ expected `u8`, found `u16` - | -help: change the type of the numeric literal from `u16` to `u8` - | -LL | assert_eq!(R.method::<1u8>(), 1); - | ^^^ - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/types-mismatch-const-args.stderr b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr similarity index 64% rename from src/test/ui/const-generics/types-mismatch-const-args.stderr rename to src/test/ui/const-generics/types-mismatch-const-args.full.stderr index 49530c9d24..265e9ee618 100644 --- a/src/test/ui/const-generics/types-mismatch-const-args.stderr +++ b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr @@ -1,14 +1,5 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/types-mismatch-const-args.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - error[E0308]: mismatched types - --> $DIR/types-mismatch-const-args.rs:13:41 + --> $DIR/types-mismatch-const-args.rs:15:41 | LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32` @@ -17,7 +8,7 @@ LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data found type `4_u32` error[E0308]: mismatched types - --> $DIR/types-mismatch-const-args.rs:15:41 + --> $DIR/types-mismatch-const-args.rs:17:41 | LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData }; | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32` @@ -27,6 +18,6 @@ LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data = note: expected struct `A<'a, u16, {2u32}, {3u32}>` found struct `A<'b, u32, {2u32}, {3u32}>` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/types-mismatch-const-args.min.stderr b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr new file mode 100644 index 0000000000..27277f0c0b --- /dev/null +++ b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/types-mismatch-const-args.rs:15:41 + | +LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32` + | | + | expected due to this + | + = note: expected struct `A<'_, _, 2_u32, _>` + found struct `A<'_, _, 4_u32, _>` + +error[E0308]: mismatched types + --> $DIR/types-mismatch-const-args.rs:17:41 + | +LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32` + | | + | expected due to this + | + = note: expected struct `A<'a, u16, _, _>` + found struct `A<'b, u32, _, _>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/types-mismatch-const-args.rs b/src/test/ui/const-generics/types-mismatch-const-args.rs index bf517c1126..34b85304cc 100644 --- a/src/test/ui/const-generics/types-mismatch-const-args.rs +++ b/src/test/ui/const-generics/types-mismatch-const-args.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // tests the diagnostic output of type mismatches for types that have const generics arguments. diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs index 7473718351..45afbdc9ab 100644 --- a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs +++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs @@ -1,7 +1,8 @@ // run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::fmt; diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr deleted file mode 100644 index f41628d5d8..0000000000 --- a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/uninferred-consts-during-codegen-1.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs index 8b95a01047..65ae05e119 100644 --- a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs +++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs @@ -1,7 +1,8 @@ // run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::fmt; diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr deleted file mode 100644 index f1703bc3a2..0000000000 --- a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/uninferred-consts-during-codegen-2.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-suggest-feature.rs b/src/test/ui/const-suggest-feature.rs index 89fafbbe6f..d11b91edb8 100644 --- a/src/test/ui/const-suggest-feature.rs +++ b/src/test/ui/const-suggest-feature.rs @@ -2,8 +2,6 @@ const WRITE: () = unsafe { *std::ptr::null_mut() = 0; //~^ ERROR dereferencing raw pointers in constants is unstable //~| HELP add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable - //~| ERROR constant contains unimplemented expression type - //~| HELP add `#![feature(const_mut_refs)]` to the crate attributes to enable }; fn main() {} diff --git a/src/test/ui/const-suggest-feature.stderr b/src/test/ui/const-suggest-feature.stderr index 6b91df6b42..1ccc3d754f 100644 --- a/src/test/ui/const-suggest-feature.stderr +++ b/src/test/ui/const-suggest-feature.stderr @@ -7,15 +7,6 @@ LL | *std::ptr::null_mut() = 0; = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error[E0019]: constant contains unimplemented expression type - --> $DIR/const-suggest-feature.rs:2:5 - | -LL | *std::ptr::null_mut() = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0019, E0658. -For more information about an error, try `rustc --explain E0019`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const_evaluatable/associated-const.rs b/src/test/ui/const_evaluatable/associated-const.rs new file mode 100644 index 0000000000..a677763225 --- /dev/null +++ b/src/test/ui/const_evaluatable/associated-const.rs @@ -0,0 +1,11 @@ +// check-pass +struct Foo(T); +impl Foo { + const VALUE: usize = std::mem::size_of::(); +} + +fn test() { + let _ = [0; Foo::::VALUE]; +} + +fn main() {} diff --git a/src/test/ui/const_evaluatable/function-call.rs b/src/test/ui/const_evaluatable/function-call.rs new file mode 100644 index 0000000000..b5de66621c --- /dev/null +++ b/src/test/ui/const_evaluatable/function-call.rs @@ -0,0 +1,19 @@ +// check-pass + +const fn foo() -> usize { + // We might instead branch on `std::mem::size_of::<*mut T>() < 8` here, + // which would cause this function to fail on 32 bit systems. + if false { + std::mem::size_of::() + } else { + 8 + } +} + +fn test() { + let _ = [0; foo::()]; + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out +} + +fn main() {} diff --git a/src/test/ui/const_evaluatable/function-call.stderr b/src/test/ui/const_evaluatable/function-call.stderr new file mode 100644 index 0000000000..0d8463714e --- /dev/null +++ b/src/test/ui/const_evaluatable/function-call.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/function-call.rs:14:17 + | +LL | let _ = [0; foo::()]; + | ^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + +warning: 1 warning emitted + diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr index e2a3e4db8a..276fb716d4 100644 --- a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr @@ -2,7 +2,7 @@ warning: this operation will panic at runtime --> $DIR/ice-assert-fail-div-by-zero.rs:11:5 | LL | f.0 / 0; - | ^^^^^^^ attempt to divide _ by zero + | ^^^^^^^ attempt to divide `_` by zero | note: the lint level is defined here --> $DIR/ice-assert-fail-div-by-zero.rs:5:9 diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr index 08c0231536..5916ea6d32 100644 --- a/src/test/ui/consts/array-literal-index-oob.stderr +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -2,7 +2,7 @@ warning: this operation will panic at runtime --> $DIR/array-literal-index-oob.rs:7:8 | LL | &{ [1, 2, 3][4] }; - | ^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 4 + | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 | note: the lint level is defined here --> $DIR/array-literal-index-oob.rs:4:20 diff --git a/src/test/ui/consts/assoc_const_generic_impl.stderr b/src/test/ui/consts/assoc_const_generic_impl.stderr index cd27331ad5..db64ebe0c4 100644 --- a/src/test/ui/consts/assoc_const_generic_impl.stderr +++ b/src/test/ui/consts/assoc_const_generic_impl.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; | -----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | index out of bounds: the len is 1 but the index is 4 + | index out of bounds: the length is 1 but the index is 4 | note: the lint level is defined here --> $DIR/assoc_const_generic_impl.rs:3:9 diff --git a/src/test/ui/consts/async-block.rs b/src/test/ui/consts/async-block.rs new file mode 100644 index 0000000000..1fa2a61609 --- /dev/null +++ b/src/test/ui/consts/async-block.rs @@ -0,0 +1,8 @@ +// From + +// edition:2018 + +const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; +//~^ `async` block + +fn main() {} diff --git a/src/test/ui/consts/async-block.stderr b/src/test/ui/consts/async-block.stderr new file mode 100644 index 0000000000..99f470623a --- /dev/null +++ b/src/test/ui/consts/async-block.stderr @@ -0,0 +1,8 @@ +error: `async` blocks are not allowed in constants + --> $DIR/async-block.rs:5:47 + | +LL | const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/auxiliary/const_fn_lib.rs b/src/test/ui/consts/auxiliary/const_fn_lib.rs index 85714efdbe..bf0b01a2ec 100644 --- a/src/test/ui/consts/auxiliary/const_fn_lib.rs +++ b/src/test/ui/consts/auxiliary/const_fn_lib.rs @@ -1,6 +1,6 @@ // Crate that exports a const fn. Used for testing cross-crate. -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] #![crate_type="rlib"] pub const fn foo() -> usize { 22 } diff --git a/src/test/ui/consts/cast-discriminant-zst-enum.rs b/src/test/ui/consts/cast-discriminant-zst-enum.rs index a772581201..9c02d232e1 100644 --- a/src/test/ui/consts/cast-discriminant-zst-enum.rs +++ b/src/test/ui/consts/cast-discriminant-zst-enum.rs @@ -1,5 +1,7 @@ // run-pass // Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to a i32. +#![feature(test)] +use std::hint::black_box; #[derive(Copy, Clone)] enum Nums { @@ -12,9 +14,6 @@ const NEG_ONE_I32: i32 = Nums::NegOne as i32; const NEG_ONE_I64: i64 = Nums::NegOne as i64; const NEG_ONE_I128: i128 = Nums::NegOne as i128; -#[inline(never)] -fn identity(t: T) -> T { t } - fn test_as_arg(n: Nums) { assert_eq!(-1i8, n as i8); assert_eq!(-1i16, n as i16); @@ -31,11 +30,11 @@ fn main() { assert_eq!(-1i64, kind as i64); assert_eq!(-1i128, kind as i128); - assert_eq!(-1i8, identity(kind) as i8); - assert_eq!(-1i16, identity(kind) as i16); - assert_eq!(-1i32, identity(kind) as i32); - assert_eq!(-1i64, identity(kind) as i64); - assert_eq!(-1i128, identity(kind) as i128); + assert_eq!(-1i8, black_box(kind) as i8); + assert_eq!(-1i16, black_box(kind) as i16); + assert_eq!(-1i32, black_box(kind) as i32); + assert_eq!(-1i64, black_box(kind) as i64); + assert_eq!(-1i128, black_box(kind) as i128); test_as_arg(Nums::NegOne); diff --git a/src/test/ui/consts/const-array-oob.rs b/src/test/ui/consts/const-array-oob.rs index 1174a76ada..eca2fe18ab 100644 --- a/src/test/ui/consts/const-array-oob.rs +++ b/src/test/ui/consts/const-array-oob.rs @@ -5,7 +5,7 @@ const BAR: usize = FOO[5]; // no error, because the error below occurs before re const BLUB: [u32; FOO[4]] = [5, 6]; //~^ ERROR evaluation of constant value failed [E0080] -//~| index out of bounds: the len is 3 but the index is 4 +//~| index out of bounds: the length is 3 but the index is 4 fn main() { let _ = BAR; diff --git a/src/test/ui/consts/const-array-oob.stderr b/src/test/ui/consts/const-array-oob.stderr index f25cac5cdd..1aa3e88e52 100644 --- a/src/test/ui/consts/const-array-oob.stderr +++ b/src/test/ui/consts/const-array-oob.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-array-oob.rs:6:19 | LL | const BLUB: [u32; FOO[4]] = [5, 6]; - | ^^^^^^ index out of bounds: the len is 3 but the index is 4 + | ^^^^^^ index out of bounds: the length is 3 but the index is 4 error: aborting due to previous error diff --git a/src/test/ui/consts/const-block-non-item-statement-3.rs b/src/test/ui/consts/const-block-non-item-statement-3.rs index 10a4c31f24..c513946d18 100644 --- a/src/test/ui/consts/const-block-non-item-statement-3.rs +++ b/src/test/ui/consts/const-block-non-item-statement-3.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(dead_code)] +#![allow(dead_code, unused)] type Array = [u32; { let x = 2; 5 }]; diff --git a/src/test/ui/consts/const-block-non-item-statement-rpass.rs b/src/test/ui/consts/const-block-non-item-statement-rpass.rs index a1b9b586ad..3e52eb50e7 100644 --- a/src/test/ui/consts/const-block-non-item-statement-rpass.rs +++ b/src/test/ui/consts/const-block-non-item-statement-rpass.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(dead_code)] +#![allow(dead_code, unused)] #[repr(u8)] enum Foo { diff --git a/src/test/ui/consts/const-err-early.stderr b/src/test/ui/consts/const-err-early.stderr index 0cb7751819..36b36db7c1 100644 --- a/src/test/ui/consts/const-err-early.stderr +++ b/src/test/ui/consts/const-err-early.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | pub const A: i8 = -std::i8::MIN; | ------------------^^^^^^^^^^^^^- | | - | attempt to negate i8::MIN which would overflow + | attempt to negate `i8::MIN`, which would overflow | note: the lint level is defined here --> $DIR/const-err-early.rs:1:9 @@ -18,7 +18,7 @@ error: any use of this value will cause an error LL | pub const B: u8 = 200u8 + 200u8; | ------------------^^^^^^^^^^^^^- | | - | attempt to compute `200_u8 + 200_u8` which would overflow + | attempt to compute `200_u8 + 200_u8`, which would overflow error: any use of this value will cause an error --> $DIR/const-err-early.rs:5:19 @@ -26,7 +26,7 @@ error: any use of this value will cause an error LL | pub const C: u8 = 200u8 * 4; | ------------------^^^^^^^^^- | | - | attempt to compute `200_u8 * 4_u8` which would overflow + | attempt to compute `200_u8 * 4_u8`, which would overflow error: any use of this value will cause an error --> $DIR/const-err-early.rs:6:19 @@ -34,7 +34,7 @@ error: any use of this value will cause an error LL | pub const D: u8 = 42u8 - (42u8 + 1); | ------------------^^^^^^^^^^^^^^^^^- | | - | attempt to compute `42_u8 - 43_u8` which would overflow + | attempt to compute `42_u8 - 43_u8`, which would overflow error: any use of this value will cause an error --> $DIR/const-err-early.rs:7:19 @@ -42,7 +42,7 @@ error: any use of this value will cause an error LL | pub const E: u8 = [5u8][1]; | ------------------^^^^^^^^- | | - | index out of bounds: the len is 1 but the index is 1 + | index out of bounds: the length is 1 but the index is 1 error: aborting due to 5 previous errors diff --git a/src/test/ui/consts/const-err-multi.stderr b/src/test/ui/consts/const-err-multi.stderr index a0c91ff6b5..5b688d4c6d 100644 --- a/src/test/ui/consts/const-err-multi.stderr +++ b/src/test/ui/consts/const-err-multi.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | pub const A: i8 = -std::i8::MIN; | ------------------^^^^^^^^^^^^^- | | - | attempt to negate i8::MIN which would overflow + | attempt to negate `i8::MIN`, which would overflow | note: the lint level is defined here --> $DIR/const-err-multi.rs:1:9 diff --git a/src/test/ui/consts/const-err.stderr b/src/test/ui/consts/const-err.stderr index ea27aa8fc8..693b74c2c2 100644 --- a/src/test/ui/consts/const-err.stderr +++ b/src/test/ui/consts/const-err.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const FOO: u8 = [5u8][1]; | ----------------^^^^^^^^- | | - | index out of bounds: the len is 1 but the index is 1 + | index out of bounds: the length is 1 but the index is 1 | note: the lint level is defined here --> $DIR/const-err.rs:5:9 diff --git a/src/test/ui/consts/const-err2.noopt.stderr b/src/test/ui/consts/const-err2.noopt.stderr index 687ffc4c4b..2473632cbc 100644 --- a/src/test/ui/consts/const-err2.noopt.stderr +++ b/src/test/ui/consts/const-err2.noopt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:19:13 | LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow + | ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:21:18 | LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow + | ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:23:13 | LL | let b = 200u8 + 200u8 + 200u8; - | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:25:18 | LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:27:13 | LL | let c = 200u8 * 4; - | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:29:13 | LL | let d = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow error: this operation will panic at runtime --> $DIR/const-err2.rs:31:14 | LL | let _e = [5u8][1]; - | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-err2.opt.stderr b/src/test/ui/consts/const-err2.opt.stderr index 687ffc4c4b..2473632cbc 100644 --- a/src/test/ui/consts/const-err2.opt.stderr +++ b/src/test/ui/consts/const-err2.opt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:19:13 | LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow + | ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:21:18 | LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow + | ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:23:13 | LL | let b = 200u8 + 200u8 + 200u8; - | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:25:18 | LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:27:13 | LL | let c = 200u8 * 4; - | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:29:13 | LL | let d = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow error: this operation will panic at runtime --> $DIR/const-err2.rs:31:14 | LL | let _e = [5u8][1]; - | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr index 687ffc4c4b..2473632cbc 100644 --- a/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:19:13 | LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow + | ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:21:18 | LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow + | ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:23:13 | LL | let b = 200u8 + 200u8 + 200u8; - | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:25:18 | LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:27:13 | LL | let c = 200u8 * 4; - | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:29:13 | LL | let d = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow error: this operation will panic at runtime --> $DIR/const-err2.rs:31:14 | LL | let _e = [5u8][1]; - | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs index 4d3c714481..037c6f9f7e 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs @@ -1,7 +1,7 @@ // New test for #53818: modifying static memory at compile-time is not allowed. // The test should never compile successfully -#![feature(const_raw_ptr_deref)] +#![feature(const_raw_ptr_deref, const_mut_refs)] use std::cell::UnsafeCell; @@ -13,7 +13,7 @@ unsafe impl Sync for Foo {} static FOO: Foo = Foo(UnsafeCell::new(42)); static BAR: () = unsafe { - *FOO.0.get() = 5; //~ ERROR contains unimplemented expression type + *FOO.0.get() = 5; //~ ERROR }; fn main() {} diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr index 14dcc07463..296a6bf542 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr @@ -1,11 +1,9 @@ -error[E0019]: static contains unimplemented expression type +error[E0080]: could not evaluate static initializer --> $DIR/assign-to-static-within-other-static-2.rs:16:5 | LL | *FOO.0.get() = 5; - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer error: aborting due to previous error -For more information about this error, try `rustc --explain E0019`. +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr index 62f339809e..65dfbd8097 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; | ------------------^^^^^--------------------------- | | - | attempt to compute `5_u32 - 6_u32` which would overflow + | attempt to compute `5_u32 - 6_u32`, which would overflow | note: the lint level is defined here --> $DIR/conditional_array_execution.rs:3:9 diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr index dd79cbd7e5..0ae51786b3 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-eval-overflow-3.rs:20:11 | LL | = [0; (i8::MAX + 1) as usize]; - | ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr index 3da34fe9af..2696d5a0b3 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -10,7 +10,7 @@ error[E0277]: cannot add `u8` to `i8` LL | = [0; (i8::MAX + 1u8) as usize]; | ^ no implementation for `i8 + u8` | - = help: the trait `std::ops::Add` is not implemented for `i8` + = help: the trait `Add` is not implemented for `i8` error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr index 30c52a82ea..e548fc266c 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-eval-overflow-4.rs:13:13 | LL | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow + | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index e4d256c0ad..e695e9f75f 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -10,7 +10,7 @@ error[E0277]: cannot add `u8` to `i8` LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | ^ no implementation for `i8 + u8` | - = help: the trait `std::ops::Add` is not implemented for `i8` + = help: the trait `Add` is not implemented for `i8` error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:25:13 diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr index 2ad557a711..51a810b8f3 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const VALS_I8: (i8,) = LL | | ( LL | | i8::MIN - 1, - | | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8`, which would overflow LL | | ); | |_______- | @@ -20,7 +20,7 @@ error: any use of this value will cause an error LL | / const VALS_I16: (i16,) = LL | | ( LL | | i16::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16`, which would overflow LL | | ); | |_______- @@ -30,7 +30,7 @@ error: any use of this value will cause an error LL | / const VALS_I32: (i32,) = LL | | ( LL | | i32::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32`, which would overflow LL | | ); | |_______- @@ -40,7 +40,7 @@ error: any use of this value will cause an error LL | / const VALS_I64: (i64,) = LL | | ( LL | | i64::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64`, which would overflow LL | | ); | |_______- @@ -50,7 +50,7 @@ error: any use of this value will cause an error LL | / const VALS_U8: (u8,) = LL | | ( LL | | u8::MIN - 1, - | | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8`, which would overflow LL | | ); | |_______- @@ -59,7 +59,7 @@ error: any use of this value will cause an error | LL | / const VALS_U16: (u16,) = ( LL | | u16::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16`, which would overflow LL | | ); | |_______- @@ -68,7 +68,7 @@ error: any use of this value will cause an error | LL | / const VALS_U32: (u32,) = ( LL | | u32::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow LL | | ); | |_______- @@ -78,7 +78,7 @@ error: any use of this value will cause an error LL | / const VALS_U64: (u64,) = LL | | ( LL | | u64::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64`, which would overflow LL | | ); | |_______- diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr index fce616b296..eec440fcb7 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const VALS_I8: (i8,) = LL | | ( LL | | i8::MAX + 1, - | | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow LL | | ); | |_______- | @@ -20,7 +20,7 @@ error: any use of this value will cause an error LL | / const VALS_I16: (i16,) = LL | | ( LL | | i16::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16`, which would overflow LL | | ); | |_______- @@ -30,7 +30,7 @@ error: any use of this value will cause an error LL | / const VALS_I32: (i32,) = LL | | ( LL | | i32::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow LL | | ); | |_______- @@ -40,7 +40,7 @@ error: any use of this value will cause an error LL | / const VALS_I64: (i64,) = LL | | ( LL | | i64::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64`, which would overflow LL | | ); | |_______- @@ -50,7 +50,7 @@ error: any use of this value will cause an error LL | / const VALS_U8: (u8,) = LL | | ( LL | | u8::MAX + 1, - | | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow LL | | ); | |_______- @@ -59,7 +59,7 @@ error: any use of this value will cause an error | LL | / const VALS_U16: (u16,) = ( LL | | u16::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16`, which would overflow LL | | ); | |_______- @@ -68,7 +68,7 @@ error: any use of this value will cause an error | LL | / const VALS_U32: (u32,) = ( LL | | u32::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32`, which would overflow LL | | ); | |_______- @@ -78,7 +78,7 @@ error: any use of this value will cause an error LL | / const VALS_U64: (u64,) = LL | | ( LL | | u64::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64`, which would overflow LL | | ); | |_______- diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr index 76201524d3..e44f94c202 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const VALS_I8: (i8,) = LL | | ( LL | | i8::MIN * 2, - | | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8`, which would overflow LL | | ); | |_______- | @@ -20,7 +20,7 @@ error: any use of this value will cause an error LL | / const VALS_I16: (i16,) = LL | | ( LL | | i16::MIN * 2, - | | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16`, which would overflow LL | | ); | |_______- @@ -30,7 +30,7 @@ error: any use of this value will cause an error LL | / const VALS_I32: (i32,) = LL | | ( LL | | i32::MIN * 2, - | | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32`, which would overflow LL | | ); | |_______- @@ -40,7 +40,7 @@ error: any use of this value will cause an error LL | / const VALS_I64: (i64,) = LL | | ( LL | | i64::MIN * 2, - | | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64`, which would overflow LL | | ); | |_______- @@ -50,7 +50,7 @@ error: any use of this value will cause an error LL | / const VALS_U8: (u8,) = LL | | ( LL | | u8::MAX * 2, - | | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8`, which would overflow LL | | ); | |_______- @@ -59,7 +59,7 @@ error: any use of this value will cause an error | LL | / const VALS_U16: (u16,) = ( LL | | u16::MAX * 2, - | | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16`, which would overflow LL | | ); | |_______- @@ -68,7 +68,7 @@ error: any use of this value will cause an error | LL | / const VALS_U32: (u32,) = ( LL | | u32::MAX * 2, - | | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32`, which would overflow LL | | ); | |_______- @@ -78,7 +78,7 @@ error: any use of this value will cause an error LL | / const VALS_U64: (u64,) = LL | | ( LL | | u64::MAX * 2, - | | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64`, which would overflow LL | | ); | |_______- diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr index dc2661ee79..8c57fd37e8 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -9,9 +9,9 @@ LL | let x: &'static i32 = &(1 / 0); = note: `#[deny(const_err)]` on by default query stack during panic: -#0 [const_eval_raw] const-evaluating `main::promoted[1]` -#1 [const_eval_validated] const-evaluating + checking `main::promoted[1]` -#2 [const_eval_validated] const-evaluating + checking `main::promoted[1]` +#0 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[1]` +#1 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` +#2 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` #3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` #4 [optimized_mir] optimizing MIR for `main` #5 [collect_and_partition_mono_items] collect_and_partition_mono_items diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index d24491e1bc..fb0ed1bd5a 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -36,7 +36,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:37:5 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -76,7 +76,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:52:5 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc47, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc38, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -100,7 +100,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:61:5 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc62, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc50, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -148,7 +148,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:79:5 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc71, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -188,7 +188,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:94:5 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc101, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -212,7 +212,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:103:5 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc110, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc95, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.stderr b/src/test/ui/consts/const-eval/const_fn_ptr.stderr index d0ae94079d..ab18020056 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr.stderr +++ b/src/test/ui/consts/const-eval/const_fn_ptr.stderr @@ -10,11 +10,23 @@ help: skipping check that does not even have a feature gate | LL | X_CONST(x) | ^^^^^^^^^^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/const_fn_ptr.rs:19:14 + | +LL | const fn foo(x: fn(usize) -> usize, y: usize) -> usize { + | ^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/const_fn_ptr.rs:20:5 + | +LL | x(y) + | ^ help: skipping check that does not even have a feature gate --> $DIR/const_fn_ptr.rs:20:5 | LL | x(y) | ^^^^ -warning: 1 warning emitted +error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr index 90ee2afa31..822d4af830 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -20,6 +20,16 @@ LL | assert_eq!(Z, 4); warning: skipping const checks | +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/const_fn_ptr_fail2.rs:12:14 + | +LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize { + | ^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/const_fn_ptr_fail2.rs:13:5 + | +LL | x(y) + | ^ help: skipping check that does not even have a feature gate --> $DIR/const_fn_ptr_fail2.rs:13:5 | diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_main.rs b/src/test/ui/consts/const-eval/const_panic_libcore_main.rs index 6b86feb592..6b03e847de 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_main.rs +++ b/src/test/ui/consts/const-eval/const_panic_libcore_main.rs @@ -17,6 +17,8 @@ const X: () = unimplemented!(); #[lang = "eh_personality"] fn eh() {} +#[lang = "eh_catch_typeinfo"] +static EH_CATCH_TYPEINFO: u8 = 0; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { diff --git a/src/test/ui/consts/const-eval/double_check2.rs b/src/test/ui/consts/const-eval/double_check2.rs index 8402d62885..81f5dde450 100644 --- a/src/test/ui/consts/const-eval/double_check2.rs +++ b/src/test/ui/consts/const-eval/double_check2.rs @@ -1,3 +1,9 @@ +// check-pass + +// This test exhibits undefined behavior, but it is very expensive and complex to check for such +// UB in constants. +// Thus, we do not detect it if you create references to statics in ways that are UB. + enum Foo { A = 5, B = 42, @@ -13,11 +19,14 @@ union Union { u8: &'static u8, } static BAR: u8 = 5; -static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior - Union { u8: &BAR }.foo, - Union { u8: &BAR }.bar, -)}; -static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))}; -//~^ undefined behavior +static FOO: (&Foo, &Bar) = unsafe { + ( + // undefined behavior + Union { u8: &BAR }.foo, + Union { u8: &BAR }.bar, + ) +}; +static FOO2: (&Foo, &Bar) = unsafe { (std::mem::transmute(&BAR), std::mem::transmute(&BAR)) }; +//^ undefined behavior fn main() {} diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr deleted file mode 100644 index 84f6080915..0000000000 --- a/src/test/ui/consts/const-eval/double_check2.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/double_check2.rs:16:1 - | -LL | / static FOO: (&Foo, &Bar) = unsafe {( -LL | | Union { u8: &BAR }.foo, -LL | | Union { u8: &BAR }.bar, -LL | | )}; - | |___^ type validation failed: encountered 0x05 at .1.., but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - -error[E0080]: it is undefined behavior to use this value - --> $DIR/double_check2.rs:20:1 - | -LL | static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x05 at .1.., but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/erroneous-const.stderr b/src/test/ui/consts/const-eval/erroneous-const.stderr index f06e2c33fd..7087a6f668 100644 --- a/src/test/ui/consts/const-eval/erroneous-const.stderr +++ b/src/test/ui/consts/const-eval/erroneous-const.stderr @@ -2,7 +2,7 @@ warning: this operation will panic at runtime --> $DIR/erroneous-const.rs:6:22 | LL | const VOID: () = [()][2]; - | ^^^^^^^ index out of bounds: the len is 1 but the index is 2 + | ^^^^^^^ index out of bounds: the length is 1 but the index is 2 | note: the lint level is defined here --> $DIR/erroneous-const.rs:2:20 @@ -16,7 +16,7 @@ warning: any use of this value will cause an error LL | const VOID: () = [()][2]; | -----------------^^^^^^^- | | - | index out of bounds: the len is 1 but the index is 2 + | index out of bounds: the length is 1 but the index is 2 | note: the lint level is defined here --> $DIR/erroneous-const.rs:2:9 diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr index 33e60dd7c9..8647da90a3 100644 --- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr +++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; | --------------------------------------------------------^^^^^--- | | - | index out of bounds: the len is 0 but the index is 0 + | index out of bounds: the length is 0 but the index is 0 | note: the lint level is defined here --> $DIR/index-out-of-bounds-never-type.rs:4:9 diff --git a/src/test/ui/consts/const-eval/index_out_of_bounds.stderr b/src/test/ui/consts/const-eval/index_out_of_bounds.stderr index 1b2974e4e3..8bb3a0c67d 100644 --- a/src/test/ui/consts/const-eval/index_out_of_bounds.stderr +++ b/src/test/ui/consts/const-eval/index_out_of_bounds.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/index_out_of_bounds.rs:1:19 | LL | static FOO: i32 = [][0]; - | ^^^^^ index out of bounds: the len is 0 but the index is 0 + | ^^^^^ index out of bounds: the length is 0 but the index is 0 error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr index 4188efd021..d247d691db 100644 --- a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr +++ b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/index_out_of_bounds_propagated.rs:5:5 | LL | array[1]; - | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr index b3e1f496ae..27e067cedb 100644 --- a/src/test/ui/consts/const-eval/issue-43197.stderr +++ b/src/test/ui/consts/const-eval/issue-43197.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const X: u32 = 0 - 1; | ---------------^^^^^- | | - | attempt to compute `0_u32 - 1_u32` which would overflow + | attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/issue-43197.rs:3:9 @@ -18,7 +18,7 @@ warning: any use of this value will cause an error LL | const Y: u32 = foo(0 - 1); | -------------------^^^^^-- | | - | attempt to compute `0_u32 - 1_u32` which would overflow + | attempt to compute `0_u32 - 1_u32`, which would overflow error[E0080]: evaluation of constant expression failed --> $DIR/issue-43197.rs:14:23 diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr index e04bf03a20..ca8885e935 100644 --- a/src/test/ui/consts/const-eval/issue-50814-2.stderr +++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const BAR: usize = [5, 6, 7][T::BOO]; | -------------------^^^^^^^^^^^^^^^^^- | | - | index out of bounds: the len is 3 but the index is 42 + | index out of bounds: the length is 3 but the index is 42 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr index 4be84f8d18..7327138627 100644 --- a/src/test/ui/consts/const-eval/issue-50814.stderr +++ b/src/test/ui/consts/const-eval/issue-50814.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const MAX: u8 = A::MAX + B::MAX; | ----------------^^^^^^^^^^^^^^^- | | - | attempt to compute `u8::MAX + u8::MAX` which would overflow + | attempt to compute `u8::MAX + u8::MAX`, which would overflow | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs index 59d46ea66c..bf8bae5ea2 100644 --- a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs +++ b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) { x diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs index 32f0062168..481e046946 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs @@ -12,14 +12,9 @@ unsafe impl Sync for Foo {} static FOO: Foo = Foo(UnsafeCell::new(42)); -fn foo() {} - static BAR: () = unsafe { *FOO.0.get() = 5; - //~^ contains unimplemented expression - - foo(); - //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants + //~^ mutation through a reference }; fn main() { diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr index 44ae1ecf04..38282c0e30 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -1,18 +1,12 @@ -error[E0019]: static contains unimplemented expression type - --> $DIR/mod-static-with-const-fn.rs:18:5 +error[E0658]: mutation through a reference is not allowed in statics + --> $DIR/mod-static-with-const-fn.rs:16:5 | LL | *FOO.0.get() = 5; | ^^^^^^^^^^^^^^^^ | + = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/mod-static-with-const-fn.rs:21:5 - | -LL | foo(); - | ^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0015, E0019. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr index 52313205dc..ce83d8e9bb 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:12:20 | LL | println!("{}", 0u32 - 1); - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:20 @@ -14,13 +14,13 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:14:14 | LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:16:20 | LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:41 @@ -50,13 +50,13 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:20:14 | LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:22:20 | LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:22:20 @@ -74,7 +74,7 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:26:14 | LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: 10 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr index b411bb2e7f..2c66b175cf 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:14:14 | LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:20 @@ -14,7 +14,7 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:16:20 | LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:41 @@ -44,13 +44,13 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:20:14 | LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:22:20 | LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:22:20 @@ -68,7 +68,7 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:26:14 | LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: 9 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr index 52313205dc..ce83d8e9bb 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:12:20 | LL | println!("{}", 0u32 - 1); - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:20 @@ -14,13 +14,13 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:14:14 | LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:16:20 | LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:41 @@ -50,13 +50,13 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:20:14 | LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:22:20 | LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:22:20 @@ -74,7 +74,7 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:26:14 | LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: 10 warnings emitted diff --git a/src/test/ui/consts/const-eval/pub_const_err.stderr b/src/test/ui/consts/const-eval/pub_const_err.stderr index ecdba2f1c5..5be0fd9672 100644 --- a/src/test/ui/consts/const-eval/pub_const_err.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | pub const Z: u32 = 0 - 1; | -------------------^^^^^- | | - | attempt to compute `0_u32 - 1_u32` which would overflow + | attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/pub_const_err.rs:2:9 diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr index b2b65767dc..55f8a58ea9 100644 --- a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | pub const Z: u32 = 0 - 1; | -------------------^^^^^- | | - | attempt to compute `0_u32 - 1_u32` which would overflow + | attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/pub_const_err_bin.rs:2:9 diff --git a/src/test/ui/consts/const-eval/shift_overflow.stderr b/src/test/ui/consts/const-eval/shift_overflow.stderr index 478769ca9f..e8d4076a61 100644 --- a/src/test/ui/consts/const-eval/shift_overflow.stderr +++ b/src/test/ui/consts/const-eval/shift_overflow.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/shift_overflow.rs:3:9 | LL | X = 1 << ((u32::MAX as u64) + 1), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by 4294967296_u64 which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by `4294967296_u64`, which would overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 7b3ee535c8..db95b996c1 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc13 at .0., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc20 at ., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -42,7 +42,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc25 at .0., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -58,7 +58,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc32 at ., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr index 38e9bdecdb..afd8a4b9e5 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL! LL | | let out_of_bounds_ptr = &ptr[255]; - | | ^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc11 which has size 1 + | | ^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1 LL | | mem::transmute(out_of_bounds_ptr) LL | | } }; | |____- diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index cd270f2a53..429ae69eab 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:23:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc16, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc14, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/unused-broken-const.stderr b/src/test/ui/consts/const-eval/unused-broken-const.stderr index a13cb87788..0cb13790f2 100644 --- a/src/test/ui/consts/const-eval/unused-broken-const.stderr +++ b/src/test/ui/consts/const-eval/unused-broken-const.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const FOO: i32 = [][0]; | -----------------^^^^^- | | - | index out of bounds: the len is 0 but the index is 0 + | index out of bounds: the length is 0 but the index is 0 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs index 6469a65700..e18e0a8357 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs @@ -7,7 +7,7 @@ extern "C" { const extern fn bar() { unsafe { regular_in_block(); - //~^ ERROR: can only call other `const fn` within a `const fn` + //~^ ERROR: calls in constant functions } } @@ -16,7 +16,7 @@ extern fn regular() {} const extern fn foo() { unsafe { regular(); - //~^ ERROR: can only call other `const fn` within a `const fn` + //~^ ERROR: calls in constant functions } } diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr index a9e2bcdbdd..348387ff5f 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -1,21 +1,15 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `regular_in_block` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-extern-fn-call-extern-fn.rs:9:9 | LL | regular_in_block(); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `regular` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-extern-fn-call-extern-fn.rs:18:9 | LL | regular(); | ^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs index 2854c08665..645a957949 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -2,11 +2,12 @@ const extern fn unsize(x: &[u8; 3]) -> &[u8] { x } const unsafe extern "C" fn closure() -> fn() { || {} } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer cast const unsafe extern fn use_float() { 1.0 + 1.0; } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR floating point arithmetic const extern "C" fn ptr_cast(val: *const u8) { val as usize; } -//~^ ERROR casting pointers to ints is unstable in const fn +//~^ ERROR casting pointers to integers fn main() {} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 146d119fc8..694e229080 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -1,30 +1,39 @@ -error[E0723]: function pointers in const fn are unstable +error[E0658]: function pointers cannot appear in constant functions --> $DIR/const-extern-fn-min-const-fn.rs:4:41 | LL | const unsafe extern "C" fn closure() -> fn() { || {} } | ^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/const-extern-fn-min-const-fn.rs:6:38 +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/const-extern-fn-min-const-fn.rs:4:48 + | +LL | const unsafe extern "C" fn closure() -> fn() { || {} } + | ^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const-extern-fn-min-const-fn.rs:7:38 | LL | const unsafe extern fn use_float() { 1.0 + 1.0; } | ^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn - --> $DIR/const-extern-fn-min-const-fn.rs:8:48 +error[E0658]: casting pointers to integers in constant functions is unstable + --> $DIR/const-extern-fn-min-const-fn.rs:9:48 | LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-external-macro-const-err.stderr b/src/test/ui/consts/const-external-macro-const-err.stderr index 06a630d82d..350e4b24de 100644 --- a/src/test/ui/consts/const-external-macro-const-err.stderr +++ b/src/test/ui/consts/const-external-macro-const-err.stderr @@ -2,7 +2,7 @@ error: any use of this value will cause an error --> $DIR/const-external-macro-const-err.rs:12:5 | LL | static_assert!(2 + 2 == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(const_err)]` on by default = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.rs b/src/test/ui/consts/const-fn-not-safe-for-const.rs index 085ff5c58e..0446ece421 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.rs +++ b/src/test/ui/consts/const-fn-not-safe-for-const.rs @@ -1,6 +1,6 @@ // Test that we can't call random fns in a const fn or do other bad things. -#![feature(const_fn, const_transmute)] +#![feature(const_fn, const_fn_transmute)] use std::mem::transmute; diff --git a/src/test/ui/consts/const-len-underflow-separate-spans.stderr b/src/test/ui/consts/const-len-underflow-separate-spans.stderr index eff50587ca..2ab6d0ffde 100644 --- a/src/test/ui/consts/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/consts/const-len-underflow-separate-spans.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const LEN: usize = ONE - TWO; | -------------------^^^^^^^^^- | | - | attempt to compute `1_usize - 2_usize` which would overflow + | attempt to compute `1_usize - 2_usize`, which would overflow | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-len-underflow-subspans.rs b/src/test/ui/consts/const-len-underflow-subspans.rs index 8ef8ef9625..ed77e90784 100644 --- a/src/test/ui/consts/const-len-underflow-subspans.rs +++ b/src/test/ui/consts/const-len-underflow-subspans.rs @@ -7,5 +7,5 @@ const TWO: usize = 2; fn main() { let a: [i8; ONE - TWO] = unimplemented!(); //~^ ERROR evaluation of constant value failed - //~| attempt to compute `1_usize - 2_usize` which would overflow + //~| attempt to compute `1_usize - 2_usize`, which would overflow } diff --git a/src/test/ui/consts/const-len-underflow-subspans.stderr b/src/test/ui/consts/const-len-underflow-subspans.stderr index e52e64b25b..68e958b378 100644 --- a/src/test/ui/consts/const-len-underflow-subspans.stderr +++ b/src/test/ui/consts/const-len-underflow-subspans.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-len-underflow-subspans.rs:8:17 | LL | let a: [i8; ONE - TWO] = unimplemented!(); - | ^^^^^^^^^ attempt to compute `1_usize - 2_usize` which would overflow + | ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs index 2207599815..ce9be4ac5c 100644 --- a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs @@ -2,6 +2,7 @@ fn main() { foo(&mut 5); } -const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable +const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references *x + 1 + } diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr index 83e050c7a5..3f9bd37053 100644 --- a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr @@ -1,12 +1,12 @@ -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/feature-gate-const_mut_refs.rs:5:14 | LL | const fn foo(x: &mut i32) -> i32 { | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-nonzero.rs b/src/test/ui/consts/const-nonzero.rs deleted file mode 100644 index cf6f8c8d69..0000000000 --- a/src/test/ui/consts/const-nonzero.rs +++ /dev/null @@ -1,16 +0,0 @@ -// run-pass - -use std::num::NonZeroU8; - -const X: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; -const Y: u8 = X.get(); - -const ZERO: Option = NonZeroU8::new(0); -const ONE: Option = NonZeroU8::new(1); - -fn main() { - assert_eq!(Y, 5); - - assert!(ZERO.is_none()); - assert_eq!(ONE.unwrap().get(), 1); -} diff --git a/src/test/ui/consts/const-option.rs b/src/test/ui/consts/const-option.rs deleted file mode 100644 index fbf20b9db6..0000000000 --- a/src/test/ui/consts/const-option.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass - -#![feature(const_option)] - -const X: Option = Some(32); -const Y: Option<&i32> = X.as_ref(); - -const IS_SOME: bool = X.is_some(); -const IS_NONE: bool = Y.is_none(); - -fn main() { - assert!(IS_SOME); - assert!(!IS_NONE) -} diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr index 7bb4acb235..3bcf2b2de7 100644 --- a/src/test/ui/consts/const-prop-ice.stderr +++ b/src/test/ui/consts/const-prop-ice.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/const-prop-ice.rs:4:5 | LL | [0; 3][3u64 as usize]; - | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3 + | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 3 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-prop-ice2.stderr b/src/test/ui/consts/const-prop-ice2.stderr index 73405eca34..2b65ffc2db 100644 --- a/src/test/ui/consts/const-prop-ice2.stderr +++ b/src/test/ui/consts/const-prop-ice2.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/const-prop-ice2.rs:6:20 | LL | println!("{}", xs[Enum::One as usize]); - | ^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index f4bff31c99..42e2749b20 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -1,32 +1,32 @@ -error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::bytes::{constant#0}` --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `std::mem::size_of`... +note: ...which requires const-evaluating + checking `std::mem::size_of`... --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | LL | pub const fn size_of() -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... +note: ...which requires simplifying constant for the type system `std::intrinsics::size_of`... --> $SRC_DIR/core/src/intrinsics.rs:LL:COL | LL | pub fn size_of() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `[u8; _]`... - = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle note: cycle used when checking that `Foo` is well-formed --> $DIR/const-size_of-cycle.rs:3:1 | diff --git a/src/test/ui/consts/const-slice-oob.rs b/src/test/ui/consts/const-slice-oob.rs index 1775f35fac..70852f8f56 100644 --- a/src/test/ui/consts/const-slice-oob.rs +++ b/src/test/ui/consts/const-slice-oob.rs @@ -2,7 +2,7 @@ const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; -//~^ index out of bounds: the len is 3 but the index is 5 +//~^ index out of bounds: the length is 3 but the index is 5 //~| ERROR any use of this value will cause an error fn main() { diff --git a/src/test/ui/consts/const-slice-oob.stderr b/src/test/ui/consts/const-slice-oob.stderr index 7e191a6336..0077bafe9e 100644 --- a/src/test/ui/consts/const-slice-oob.stderr +++ b/src/test/ui/consts/const-slice-oob.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const BAR: u32 = FOO[5]; | -----------------^^^^^^- | | - | index out of bounds: the len is 3 but the index is 5 + | index out of bounds: the length is 3 but the index is 5 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-unsized.stderr b/src/test/ui/consts/const-unsized.stderr index bf2844cfb7..27b200648e 100644 --- a/src/test/ui/consts/const-unsized.stderr +++ b/src/test/ui/consts/const-unsized.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:3:16 | LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:6:18 @@ -12,15 +12,15 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | const CONST_FOO: str = *"foo"; | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` -error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:9:18 | LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:12:20 @@ -28,7 +28,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | static STATIC_BAR: str = *"bar"; | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/const-unwrap.stderr b/src/test/ui/consts/const-unwrap.stderr index 7f2c1f4151..6500baab07 100644 --- a/src/test/ui/consts/const-unwrap.stderr +++ b/src/test/ui/consts/const-unwrap.stderr @@ -5,7 +5,7 @@ LL | None => panic!("called `Option::unwrap()` on a `None` value"), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the evaluated program panicked at 'called `Option::unwrap()` on a `None` value', $DIR/const-unwrap.rs:9:38 - | inside `std::option::Option::::unwrap` at $SRC_DIR/core/src/macros/mod.rs:LL:COL + | inside `Option::::unwrap` at $SRC_DIR/core/src/macros/mod.rs:LL:COL | inside `BAR` at $DIR/const-unwrap.rs:9:18 | ::: $DIR/const-unwrap.rs:9:1 diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index 1ad5134e71..d016d236db 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -1,14 +1,10 @@ // run-pass #![feature(const_discriminant)] +#![feature(test)] #![allow(dead_code)] use std::mem::{discriminant, Discriminant}; - -// `discriminant(const_expr)` may get const-propagated. -// As we want to check that const-eval is equal to ordinary exection, -// we wrap `const_expr` with a function which is not const to prevent this. -#[inline(never)] -fn identity(x: T) -> T { x } +use std::hint::black_box; enum Test { A(u8), @@ -31,10 +27,10 @@ const TEST_V: Discriminant = discriminant(&SingleVariant::V); fn main() { assert_eq!(TEST_A, TEST_A_OTHER); - assert_eq!(TEST_A, discriminant(identity(&Test::A(17)))); - assert_eq!(TEST_B, discriminant(identity(&Test::B))); + assert_eq!(TEST_A, discriminant(black_box(&Test::A(17)))); + assert_eq!(TEST_B, discriminant(black_box(&Test::B))); assert_ne!(TEST_A, TEST_B); - assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 }))); + assert_ne!(TEST_B, discriminant(black_box(&Test::C { a: 42, b: 7 }))); - assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V))); + assert_eq!(TEST_V, discriminant(black_box(&SingleVariant::V))); } diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr b/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr new file mode 100644 index 0000000000..ae24f8f650 --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/const_fn_floating_point_arithmetic.rs:20:1 + | +LL | fn main() {} + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.rs b/src/test/ui/consts/const_fn_floating_point_arithmetic.rs new file mode 100644 index 0000000000..5e32482b21 --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.rs @@ -0,0 +1,20 @@ +// gate-test-const_fn_floating_point_arithmetic + +// revisions: stock gated + +#![feature(rustc_attrs)] +#![cfg_attr(gated, feature(const_fn_floating_point_arithmetic))] + +const fn add(f: f32) -> f32 { f + 2.0 } +//[stock]~^ floating point arithmetic +const fn sub(f: f32) -> f32 { 2.0 - f } +//[stock]~^ floating point arithmetic +const fn mul(f: f32, g: f32) -> f32 { f * g } +//[stock]~^ floating point arithmetic +const fn div(f: f32, g: f32) -> f32 { f / g } +//[stock]~^ floating point arithmetic +const fn neg(f: f32) -> f32 { -f } +//[stock]~^ floating point arithmetic + +#[rustc_error] +fn main() {} //[gated]~ fatal error triggered by #[rustc_error] diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr new file mode 100644 index 0000000000..ef7a60faf3 --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr @@ -0,0 +1,48 @@ +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:8:31 + | +LL | const fn add(f: f32) -> f32 { f + 2.0 } + | ^^^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:10:31 + | +LL | const fn sub(f: f32) -> f32 { 2.0 - f } + | ^^^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:12:39 + | +LL | const fn mul(f: f32, g: f32) -> f32 { f * g } + | ^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:14:39 + | +LL | const fn div(f: f32, g: f32) -> f32 { f / g } + | ^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:16:31 + | +LL | const fn neg(f: f32) -> f32 { -f } + | ^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs index 05c53e5edc..ab297f54df 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs @@ -12,7 +12,6 @@ fn main() { match None { consts::SOME => panic!(), //~^ must be annotated with `#[derive(PartialEq, Eq)]` - //~| must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } @@ -20,7 +19,6 @@ fn main() { match None { ::SOME => panic!(), //~^ must be annotated with `#[derive(PartialEq, Eq)]` - //~| must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr index 5d147e32f5..a8066a88c3 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr @@ -1,26 +1,14 @@ -error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/cross-crate-fail.rs:13:9 | LL | consts::SOME => panic!(), | ^^^^^^^^^^^^ -error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:21:9 +error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cross-crate-fail.rs:20:9 | LL | ::SOME => panic!(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:13:9 - | -LL | consts::SOME => panic!(), - | ^^^^^^^^^^^^ - -error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:21:9 - | -LL | ::SOME => panic!(), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs index a1f9838ca0..856d204178 100644 --- a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs +++ b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs @@ -1,8 +1,5 @@ // check-pass -#![warn(indirect_structural_match)] -//~^ NOTE lint level is defined here - struct CustomEq; impl Eq for CustomEq {} @@ -32,7 +29,8 @@ fn main() { BAR_BAZ => panic!(), //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` //~| WARN this was previously accepted - //~| NOTE see issue #62411 + //~| NOTE see issue #73448 + //~| NOTE `#[warn(nontrivial_structural_match)]` on by default _ => {} } } diff --git a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr index 0be1cca806..e51d6f9164 100644 --- a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr +++ b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr @@ -1,16 +1,12 @@ -warning: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/custom-eq-branch-warn.rs:32:9 +warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/custom-eq-branch-warn.rs:29:9 | LL | BAR_BAZ => panic!(), | ^^^^^^^ | -note: the lint level is defined here - --> $DIR/custom-eq-branch-warn.rs:3:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #73448 warning: 1 warning emitted diff --git a/src/test/ui/consts/const_in_pattern/issue-65466.rs b/src/test/ui/consts/const_in_pattern/issue-65466.rs index 0e3e0f6dd8..2b421f4c70 100644 --- a/src/test/ui/consts/const_in_pattern/issue-65466.rs +++ b/src/test/ui/consts/const_in_pattern/issue-65466.rs @@ -1,9 +1,7 @@ -// FIXME: This still ICEs. -// -// ignore-test - #![deny(indirect_structural_match)] +// check-pass + #[derive(PartialEq, Eq)] enum O { Some(*const T), // Can also use PhantomData diff --git a/src/test/ui/consts/const_in_pattern/issue-65466.stderr b/src/test/ui/consts/const_in_pattern/issue-65466.stderr deleted file mode 100644 index 9fe3049d1d..0000000000 --- a/src/test/ui/consts/const_in_pattern/issue-65466.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0601]: `main` function not found in crate `issue_65466` - --> $DIR/issue-65466.rs:1:1 - | -LL | / #![deny(indirect_structural_match)] -LL | | -LL | | #[derive(PartialEq, Eq)] -LL | | enum O { -... | -LL | | } -LL | | } - | |_^ consider adding a `main` function to `$DIR/issue-65466.rs` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs index c7f02c615a..fc80d51c72 100644 --- a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs +++ b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs @@ -20,7 +20,6 @@ fn main() { match Foo::Qux(NoEq) { BAR_BAZ => panic!(), //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } } diff --git a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr index ee78c6f5c3..e505dad69b 100644 --- a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr +++ b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit LL | BAR_BAZ => panic!(), | ^^^^^^^ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/no-eq-branch-fail.rs:21:9 - | -LL | BAR_BAZ => panic!(), - | ^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/consts/const_in_pattern/reject_non_structural.rs b/src/test/ui/consts/const_in_pattern/reject_non_structural.rs index bbeaeea1f8..7a8169bec4 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/src/test/ui/consts/const_in_pattern/reject_non_structural.rs @@ -39,51 +39,41 @@ fn main() { const ENUM: Derive = Derive::Some(NoDerive); match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const FIELD: OND = TrivialEq(Some(NoDerive)).0; match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const NO_DERIVE_SOME: OND = Some(NoDerive); const INDIRECT: OND = NO_DERIVE_SOME; match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const TUPLE: (OND, OND) = (None, Some(NoDerive)); match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const TYPE_ASCRIPTION: OND = Some(NoDerive): OND; match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const ARRAY: [OND; 2] = [None, Some(NoDerive)]; match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const REPEAT: [OND; 2] = [Some(NoDerive); 2]; match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` trait Trait: Sized { const ASSOC: Option; } impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const BLOCK: OND = { NoDerive; Some(NoDerive) }; match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const ADDR_OF: &OND = &Some(NoDerive); match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; diff --git a/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr b/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr index b1310cf101..56405a55d6 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -5,61 +5,61 @@ LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops" | ^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:45:28 + --> $DIR/reject_non_structural.rs:44:28 | LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:51:27 + --> $DIR/reject_non_structural.rs:49:27 | LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; | ^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:56:36 + --> $DIR/reject_non_structural.rs:53:36 | LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:61:28 + --> $DIR/reject_non_structural.rs:57:28 | LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:66:36 + --> $DIR/reject_non_structural.rs:61:36 | LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 + --> $DIR/reject_non_structural.rs:65:33 | LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; | ^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 + --> $DIR/reject_non_structural.rs:65:33 | LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; | ^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:79:28 + --> $DIR/reject_non_structural.rs:71:28 | LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:84:28 + --> $DIR/reject_non_structural.rs:75:28 | LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; | ^^^^^ warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:89:29 + --> $DIR/reject_non_structural.rs:79:29 | LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; | ^^^^^^^ @@ -72,65 +72,5 @@ LL | #![warn(indirect_structural_match)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #62411 -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:40:36 - | -LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; - | ^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:45:28 - | -LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:51:27 - | -LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; - | ^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:56:36 - | -LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:61:28 - | -LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; - | ^^^^^^^^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:66:36 - | -LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 - | -LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; - | ^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 - | -LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; - | ^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:79:28 - | -LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; - | ^^^^^^^^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:84:28 - | -LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; - | ^^^^^ - -error: aborting due to 20 previous errors; 1 warning emitted +error: aborting due to 10 previous errors; 1 warning emitted diff --git a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr index 3e7ed573c7..a24c8d1818 100644 --- a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr +++ b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr @@ -1,34 +1,30 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:26:47 | LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; | ^^^^^ | -note: the lint level is defined here - --> $DIR/warn_corner_cases.rs:15:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #73448 -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:32:47 | LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #73448 -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:38:47 | LL | match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #73448 warning: 3 warnings emitted diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index f993a427b4..2fd6e06067 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -6,23 +6,21 @@ struct S { impl S { const fn foo(&mut self, x: u32) { + //~^ ERROR mutable reference self.state = x; - //~^ contains unimplemented expression } } const FOO: S = { let mut s = S { state: 42 }; - s.foo(3); //~ ERROR mutable references are not allowed in constants + s.foo(3); //~ ERROR mutable reference s }; type Array = [u32; { let mut x = 2; - let y = &mut x; -//~^ ERROR mutable references are not allowed in constants + let y = &mut x; //~ ERROR mutable reference *y = 42; -//~^ ERROR constant contains unimplemented expression type *y }]; diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index dd05a4c0bb..dc86e178a4 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -1,9 +1,10 @@ -error[E0019]: constant function contains unimplemented expression type - --> $DIR/const_let_assign3.rs:9:9 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/const_let_assign3.rs:8:18 | -LL | self.state = x; - | ^^^^^^^^^^^^^^ +LL | const fn foo(&mut self, x: u32) { + | ^^^^^^^^^ | + = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in constants @@ -18,15 +19,7 @@ error[E0764]: mutable references are not allowed in constants LL | let y = &mut x; | ^^^^^^ `&mut` is only allowed in `const fn` -error[E0019]: constant contains unimplemented expression type - --> $DIR/const_let_assign3.rs:24:5 - | -LL | *y = 42; - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0019, E0764. -For more information about an error, try `rustc --explain E0019`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const_let_eq_float.rs b/src/test/ui/consts/const_let_eq_float.rs index bc0ef26eb2..e15f4b804f 100644 --- a/src/test/ui/consts/const_let_eq_float.rs +++ b/src/test/ui/consts/const_let_eq_float.rs @@ -1,6 +1,6 @@ -// build-pass (FIXME(62277): could be check-pass?) +// run-pass -#![feature(const_fn)] +#![feature(const_fn_floating_point_arithmetic)] struct Foo(T); struct Bar { x: T } diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr index 85b38f41c5..31090be090 100644 --- a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr @@ -5,7 +5,7 @@ LL | unsafe { intrinsics::unreachable() } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | | | entering unreachable code - | inside `std::hint::unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL + | inside `unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:9:18 | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:14:28 | diff --git a/src/test/ui/consts/consts-in-patterns.rs b/src/test/ui/consts/consts-in-patterns.rs index d51215447d..0295204c87 100644 --- a/src/test/ui/consts/consts-in-patterns.rs +++ b/src/test/ui/consts/consts-in-patterns.rs @@ -19,8 +19,6 @@ pub fn main() { assert_eq!(y, 2); let z = match &() { ZST => 9, - // FIXME: this should not be required - _ => 42, }; assert_eq!(z, 9); let z = match b"" { diff --git a/src/test/ui/consts/control-flow/drop-pass.rs b/src/test/ui/consts/control-flow/drop-pass.rs index 95f954a59a..2a6d12768c 100644 --- a/src/test/ui/consts/control-flow/drop-pass.rs +++ b/src/test/ui/consts/control-flow/drop-pass.rs @@ -1,6 +1,7 @@ // run-pass // revisions: stock precise +#![allow(unused)] #![cfg_attr(precise, feature(const_precise_live_drops))] // `x` is always moved into the final value and is not dropped inside the initializer. diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs deleted file mode 100644 index c8b3939933..0000000000 --- a/src/test/ui/consts/duration-consts-2.rs +++ /dev/null @@ -1,57 +0,0 @@ -// run-pass - -#![feature(const_panic)] -#![feature(duration_consts_2)] -#![feature(div_duration)] - -use std::time::Duration; - -fn duration() { - const ZERO : Duration = Duration::new(0, 0); - assert_eq!(ZERO, Duration::from_secs(0)); - - const ONE : Duration = Duration::new(0, 1); - assert_eq!(ONE, Duration::from_nanos(1)); - - const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1); - - const MAX_ADD_ZERO : Option = MAX.checked_add(ZERO); - assert_eq!(MAX_ADD_ZERO, Some(MAX)); - - const MAX_ADD_ONE : Option = MAX.checked_add(ONE); - assert_eq!(MAX_ADD_ONE, None); - - const ONE_SUB_ONE : Option = ONE.checked_sub(ONE); - assert_eq!(ONE_SUB_ONE, Some(ZERO)); - - const ZERO_SUB_ONE : Option = ZERO.checked_sub(ONE); - assert_eq!(ZERO_SUB_ONE, None); - - const ONE_MUL_ONE : Option = ONE.checked_mul(1); - assert_eq!(ONE_MUL_ONE, Some(ONE)); - - const MAX_MUL_TWO : Option = MAX.checked_mul(2); - assert_eq!(MAX_MUL_TWO, None); - - const ONE_DIV_ONE : Option = ONE.checked_div(1); - assert_eq!(ONE_DIV_ONE, Some(ONE)); - - const ONE_DIV_ZERO : Option = ONE.checked_div(0); - assert_eq!(ONE_DIV_ZERO, None); - - const MAX_AS_F32 : f32 = MAX.as_secs_f32(); - assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32); - - const MAX_AS_F64 : f64 = MAX.as_secs_f64(); - assert_eq!(MAX_AS_F64, 18446744073709552000.0_f64); - - const ONE_AS_F32 : f32 = ONE.div_duration_f32(ONE); - assert_eq!(ONE_AS_F32, 1.0_f32); - - const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE); - assert_eq!(ONE_AS_F64, 1.0_f64); -} - -fn main() { - duration(); -} diff --git a/src/test/ui/consts/inline_asm.rs b/src/test/ui/consts/inline_asm.rs index c2ab97e54f..b8b755018e 100644 --- a/src/test/ui/consts/inline_asm.rs +++ b/src/test/ui/consts/inline_asm.rs @@ -1,6 +1,6 @@ #![feature(llvm_asm)] const _: () = unsafe { llvm_asm!("nop") }; -//~^ ERROR contains unimplemented expression type +//~^ ERROR inline assembly fn main() {} diff --git a/src/test/ui/consts/inline_asm.stderr b/src/test/ui/consts/inline_asm.stderr index 0a064c8136..6fb6b69d22 100644 --- a/src/test/ui/consts/inline_asm.stderr +++ b/src/test/ui/consts/inline_asm.stderr @@ -1,4 +1,4 @@ -error[E0019]: constant contains unimplemented expression type +error[E0015]: inline assembly is not allowed in constants --> $DIR/inline_asm.rs:3:24 | LL | const _: () = unsafe { llvm_asm!("nop") }; @@ -8,4 +8,4 @@ LL | const _: () = unsafe { llvm_asm!("nop") }; error: aborting due to previous error -For more information about this error, try `rustc --explain E0019`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/is_ascii.rs b/src/test/ui/consts/is_ascii.rs deleted file mode 100644 index d8424549f9..0000000000 --- a/src/test/ui/consts/is_ascii.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - -static X: bool = 'a'.is_ascii(); -static Y: bool = 'ä'.is_ascii(); - -static BX: bool = b'a'.is_ascii(); -static BY: bool = 192u8.is_ascii(); - -fn main() { - assert!(X); - assert!(!Y); - - assert!(BX); - assert!(!BY); -} diff --git a/src/test/ui/consts/issue-37550.rs b/src/test/ui/consts/issue-37550.rs index 04865830df..15877c5374 100644 --- a/src/test/ui/consts/issue-37550.rs +++ b/src/test/ui/consts/issue-37550.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] #![allow(unused_variables)] -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] const fn x() { let t = true; diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs index 9d1a8b5946..90ea217698 100644 --- a/src/test/ui/consts/issue-56164.rs +++ b/src/test/ui/consts/issue-56164.rs @@ -1,12 +1,11 @@ -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] const fn foo() { (||{})() } -//~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple -// variants +//~^ ERROR calls in constant functions const fn bad(input: fn()) { input() - //~^ ERROR function pointers are not allowed in const fn + //~^ ERROR function pointer } fn main() { diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr index d3e9ce379a..500af0a400 100644 --- a/src/test/ui/consts/issue-56164.stderr +++ b/src/test/ui/consts/issue-56164.stderr @@ -5,7 +5,7 @@ LL | const fn foo() { (||{})() } | ^^^^^^^^ error: function pointers are not allowed in const fn - --> $DIR/issue-56164.rs:8:5 + --> $DIR/issue-56164.rs:7:5 | LL | input() | ^^^^^^^ diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr index 815cc9d836..8c839f94e3 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr @@ -8,7 +8,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/issue-68542-closure-in-array-len.rs:6:13 | LL | a: [(); (|| { 0 })()] - | ^^^^^^^^^^^^ calling non-const function `Bug::a::{{constant}}#0::{{closure}}#0` + | ^^^^^^^^^^^^ calling non-const function `Bug::a::{constant#0}::{closure#0}` error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs index 1e495438e8..632335c841 100644 --- a/src/test/ui/consts/match_ice.rs +++ b/src/test/ui/consts/match_ice.rs @@ -9,11 +9,10 @@ fn main() { const C: &S = &S; match C { C => {} - //~^ ERROR to use a constant of type `S` in a pattern, `S` must be annotated with - //~| ERROR to use a constant of type `S` in a pattern, `S` must be annotated with + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` } const K: &T = &T; - match K { //~ ERROR non-exhaustive patterns: `&T` not covered + match K { K => {} } } diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index 5477170fb1..699b4a5e20 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -4,24 +4,5 @@ error: to use a constant of type `S` in a pattern, `S` must be annotated with `# LL | C => {} | ^ -error[E0004]: non-exhaustive patterns: `&T` not covered - --> $DIR/match_ice.rs:16:11 - | -LL | struct T; - | --------- `T` defined here -... -LL | match K { - | ^ pattern `&T` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `&T` - -error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match_ice.rs:11:9 - | -LL | C => {} - | ^ - -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs index 937aae1a8e..dc10db177e 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs @@ -1,12 +1,14 @@ -#![feature(rustc_attrs, staged_api)] +#![feature(rustc_attrs, staged_api, allow_internal_unstable)] +#![feature(const_fn_fn_ptr_basics)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(since="1.0.0", feature = "mep")] -const fn error(_: fn()) {} //~ ERROR function pointers in const fn are unstable +const fn error(_: fn()) {} +//~^ ERROR const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allow_const_fn_ptr] #[rustc_const_stable(since="1.0.0", feature = "mep")] +#[allow_internal_unstable(const_fn_fn_ptr_basics)] const fn compiles(_: fn()) {} fn main() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr index 9a14bcc2f7..a08d57b604 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr @@ -1,12 +1,17 @@ -error[E0723]: function pointers in const fn are unstable - --> $DIR/allow_const_fn_ptr.rs:5:16 +error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]` + --> $DIR/allow_const_fn_ptr.rs:6:16 | LL | const fn error(_: fn()) {} | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | +help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks + | +LL | #[allow_internal_unstable(const_fn_fn_ptr_basics)] + | error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs deleted file mode 100644 index 0f9d372929..0000000000 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(staged_api)] - -#[stable(feature = "rust1", since = "1.0.0")] -const fn error(_: fn()) {} - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allow_const_fn_ptr] -//~^ ERROR internal implementation detail -const fn compiles(_: fn()) {} - -fn main() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr deleted file mode 100644 index 7794cc7583..0000000000 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: internal implementation detail - --> $DIR/allow_const_fn_ptr_feature_gate.rs:7:1 - | -LL | #[rustc_allow_const_fn_ptr] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs index 7aa9bd7e2d..b4e836bbc9 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs @@ -1,11 +1,13 @@ // run-pass +#![feature(allow_internal_unstable)] +#![feature(const_fn_fn_ptr_basics)] #![feature(rustc_attrs, staged_api)] #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allow_const_fn_ptr] #[rustc_const_stable(since="1.0.0", feature = "mep")] +#[allow_internal_unstable(const_fn_fn_ptr_basics)] const fn takes_fn_ptr(_: fn()) {} const FN: fn() = || (); diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs index 3e42cb8c1b..4e1b7bf119 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -1,5 +1,7 @@ const fn foo(a: i32) -> Vec { - vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn + vec![1, 2, 3] + //~^ ERROR allocations are not allowed + //~| ERROR calls in constant functions } fn main() {} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr index 39b223062e..23697a8e11 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -1,13 +1,20 @@ -error[E0723]: heap allocations are not allowed in const fn +error[E0010]: allocations are not allowed in constant functions + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] + | ^^^^^^^^^^^^^ allocation not allowed in constant functions + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/bad_const_fn_body_ice.rs:2:5 | LL | vec![1, 2, 3] | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +Some errors have detailed explanations: E0010, E0015. +For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs index 8d730df16b..b68f47f5cb 100644 --- a/src/test/ui/consts/min_const_fn/cast_errors.rs +++ b/src/test/ui/consts/min_const_fn/cast_errors.rs @@ -2,12 +2,16 @@ fn main() {} const fn unsize(x: &[u8; 3]) -> &[u8] { x } const fn closure() -> fn() { || {} } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer cast const fn closure2() { (|| {}) as fn(); -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer } const fn reify(f: fn()) -> unsafe fn() { f } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer +//~| ERROR function pointer cast const fn reify2() { main as unsafe fn(); } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer cast diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr index 583cb4e972..fb962bdf90 100644 --- a/src/test/ui/consts/min_const_fn/cast_errors.stderr +++ b/src/test/ui/consts/min_const_fn/cast_errors.stderr @@ -1,39 +1,75 @@ -error[E0723]: function pointers in const fn are unstable +error[E0658]: function pointers cannot appear in constant functions --> $DIR/cast_errors.rs:4:23 | LL | const fn closure() -> fn() { || {} } | ^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/cast_errors.rs:7:5 +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:4:30 + | +LL | const fn closure() -> fn() { || {} } + | ^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:8:5 | LL | (|| {}) as fn(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/cast_errors.rs:11:16 + | +LL | const fn reify(f: fn()) -> unsafe fn() { f } + | ^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/cast_errors.rs:10:28 +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/cast_errors.rs:11:28 | LL | const fn reify(f: fn()) -> unsafe fn() { f } | ^^^^^^^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:11:42 + | +LL | const fn reify(f: fn()) -> unsafe fn() { f } + | ^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:15:21 + | +LL | const fn reify2() { main as unsafe fn(); } + | ^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/cast_errors.rs:12:21 +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:15:21 | LL | const fn reify2() { main as unsafe fn(); } - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error: aborting due to 4 previous errors +error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs index c2600f894d..638ff1d8b9 100644 --- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs +++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs @@ -1,5 +1,8 @@ -const fn cmp(x: fn(), y: fn()) -> bool { //~ ERROR function pointers in const fn are unstable +const fn cmp(x: fn(), y: fn()) -> bool { + //~^ ERROR function pointer + //~| ERROR function pointer unsafe { x == y } + //~^ ERROR pointers cannot be reliably compared } fn main() {} diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr index 74e5228d0d..04c2febeb9 100644 --- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr +++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr @@ -1,12 +1,29 @@ -error[E0723]: function pointers in const fn are unstable +error[E0658]: function pointers cannot appear in constant functions --> $DIR/cmp_fn_pointers.rs:1:14 | LL | const fn cmp(x: fn(), y: fn()) -> bool { | ^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/cmp_fn_pointers.rs:1:23 + | +LL | const fn cmp(x: fn(), y: fn()) -> bool { + | ^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error: pointers cannot be reliably compared during const eval. + --> $DIR/cmp_fn_pointers.rs:4:14 + | +LL | unsafe { x == y } + | ^^^^^^ + | + = note: see issue #53020 for more information + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 2ebd9dd10c..e46127c36b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -37,26 +37,34 @@ impl Foo { const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated const fn get(&self) -> &T { &self.0 } const fn get_mut(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references + //~| mutable references + //~| mutable references } impl<'a, T> Foo { const fn new_lt(t: T) -> Self { Foo(t) } const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated const fn get_lt(&'a self) -> &T { &self.0 } const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references + //~| mutable references + //~| mutable references } impl Foo { const fn new_s(t: T) -> Self { Foo(t) } const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors const fn get_s(&self) -> &T { &self.0 } const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references + //~| mutable references + //~| mutable references } impl Foo { const fn get_sq(&self) -> &T { &self.0 } const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references + //~| mutable references + //~| mutable references } @@ -77,29 +85,21 @@ const fn foo11(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable const fn foo11_2(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable -const fn foo19(f: f32) -> f32 { f * 2.0 } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn -const fn foo19_2(f: f32) -> f32 { 2.0 - f } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn -const fn foo19_3(f: f32) -> f32 { -f } -//~^ ERROR only int and `bool` operations are stable in const fn -const fn foo19_4(f: f32, g: f32) -> f32 { f / g } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn static BAR: u32 = 42; -const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn -const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items +const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics +const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot refer to statics const fn foo30(x: *const u32) -> usize { x as usize } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_2(x: *mut u32) -> usize { x as usize } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_6() -> bool { let x = true; x } const fn inc(x: &mut i32) { *x += 1 } -//~^ ERROR mutable references in const fn are unstable +//~^ ERROR mutable references // ok const fn foo36(a: bool, b: bool) -> bool { a && b } @@ -125,17 +125,24 @@ impl Foo { struct AlanTuring(T); const fn no_apit2(_x: AlanTuring) {} //~^ ERROR trait bounds other than `Sized` -const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` -const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` +//~| ERROR destructor +const fn no_apit(_x: impl std::fmt::Debug) {} +//~^ ERROR trait bounds other than `Sized` +//~| ERROR destructor +const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} +//~^ ERROR trait bounds other than `Sized` const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~^ ERROR trait bounds other than `Sized` +//~| ERROR unsizing cast +//~| ERROR unsizing cast const fn no_unsafe() { unsafe {} } const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } -//~^ ERROR trait bounds other than `Sized` +//~^ ERROR unsizing cast const fn no_fn_ptrs(_x: fn()) {} -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer cast diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 9b55b6c6f3..ee5434b147 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -6,174 +6,208 @@ LL | const fn into_inner(self) -> T { self.0 } | | | constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:39:22 + | +LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions --> $DIR/min_const_fn.rs:39:36 | LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:39:45 + | +LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:44:28 + --> $DIR/min_const_fn.rs:46:28 | LL | const fn into_inner_lt(self) -> T { self.0 } | ^^^^ - value is dropped here | | | constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:46:42 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:48:25 + | +LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:48:42 | LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:48:51 + | +LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:51:27 + --> $DIR/min_const_fn.rs:55:27 | LL | const fn into_inner_s(self) -> T { self.0 } | ^^^^ - value is dropped here | | | constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:53:38 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:57:24 | LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^ + | ^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:58:39 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:57:38 | -LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } - | ^^^^^^ +LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:76:16 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:57:47 | -LL | const fn foo11(t: T) -> T { t } - | ^ +LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:78:18 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:64:25 | -LL | const fn foo11_2(t: T) -> T { t } - | ^ +LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:80:33 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:64:39 | -LL | const fn foo19(f: f32) -> f32 { f * 2.0 } - | ^^^^^^^ +LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:82:35 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:64:48 | -LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } - | ^^^^^^^ +LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: only int and `bool` operations are stable in const fn - --> $DIR/min_const_fn.rs:84:35 +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:84:16 | -LL | const fn foo19_3(f: f32) -> f32 { -f } - | ^^ +LL | const fn foo11(t: T) -> T { t } + | ^ | = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:86:43 +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:86:18 | -LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } - | ^^^^^ +LL | const fn foo11_2(t: T) -> T { t } + | ^ | = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: cannot access `static` items in const fn +error[E0013]: constant functions cannot refer to statics --> $DIR/min_const_fn.rs:90:27 | LL | const fn foo25() -> u32 { BAR } | ^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0723]: cannot access `static` items in const fn +error[E0013]: constant functions cannot refer to statics --> $DIR/min_const_fn.rs:91:37 | LL | const fn foo26() -> &'static u32 { &BAR } | ^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:92:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:94:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:96:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:98:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/min_const_fn.rs:101:14 | LL | const fn inc(x: &mut i32) { *x += 1 } | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:110:6 @@ -211,8 +245,16 @@ LL | const fn no_apit2(_x: AlanTuring) {} = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/min_const_fn.rs:126:19 + | +LL | const fn no_apit2(_x: AlanTuring) {} + | ^^ - value is dropped here + | | + | constant functions cannot evaluate destructors + error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:128:22 + --> $DIR/min_const_fn.rs:129:22 | LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -220,8 +262,16 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {} = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/min_const_fn.rs:129:18 + | +LL | const fn no_apit(_x: impl std::fmt::Debug) {} + | ^^ - value is dropped here + | | + | constant functions cannot evaluate destructors + error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:129:23 + --> $DIR/min_const_fn.rs:132:23 | LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} | ^^ @@ -230,7 +280,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:130:32 + --> $DIR/min_const_fn.rs:134:32 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -238,34 +288,61 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:135:41 +error[E0723]: unsizing casts to types besides slices are not allowed in const fn + --> $DIR/min_const_fn.rs:134:63 + | +LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } + | ^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: unsizing casts to types besides slices are not allowed in const fn + --> $DIR/min_const_fn.rs:134:63 + | +LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } + | ^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: unsizing casts to types besides slices are not allowed in const fn + --> $DIR/min_const_fn.rs:141:42 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ | = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:138:21 +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/min_const_fn.rs:144:21 | LL | const fn no_fn_ptrs(_x: fn()) {} | ^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:140:27 +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/min_const_fn.rs:146:27 | LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } | ^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/min_const_fn.rs:146:46 + | +LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } + | ^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error: aborting due to 30 previous errors +error: aborting due to 39 previous errors -Some errors have detailed explanations: E0493, E0723. -For more information about an error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0013, E0493, E0658, E0723. +For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs index 6ca1e59b3a..4a22ef2dff 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs @@ -10,6 +10,6 @@ const fn no_inner_dyn_trait2(x: Hide) { //~^ ERROR trait bounds other than `Sized` } const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } -//~^ ERROR trait bounds other than `Sized` +//~^ ERROR unsizing cast fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr index 17e171c2fc..1394db591c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr @@ -7,7 +7,7 @@ LL | x.0.field; = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0723]: unsizing casts to types besides slices are not allowed in const fn --> $DIR/min_const_fn_dyn.rs:12:66 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs index 584ea46b1a..bc6fe89222 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs @@ -1,3 +1,5 @@ +// gate-test-const_fn_fn_ptr_basics + struct HasPtr { field: fn(), } @@ -9,9 +11,9 @@ fn field() {} const fn no_inner_dyn_trait(_x: Hide) {} const fn no_inner_dyn_trait2(x: Hide) { x.0.field; -//~^ ERROR function pointers in const fn +//~^ ERROR function pointer } const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) } -//~^ ERROR function pointers in const fn +//~^ ERROR function pointer fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr index 58acbb5339..8d82674bbf 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr @@ -1,21 +1,21 @@ -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn_fn_ptr.rs:11:5 +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/min_const_fn_fn_ptr.rs:13:5 | LL | x.0.field; | ^^^^^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn_fn_ptr.rs:14:59 +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/min_const_fn_fn_ptr.rs:16:59 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) } | ^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index df10f3496c..292e2dd167 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, foo, foo2)] +#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` +const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const fn foo2() -> u32 { 42 } @@ -21,12 +21,13 @@ const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` +const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] -// conformity is required, even with `const_fn` feature gate -const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations +// Const-stable functions cannot rely on unstable const-eval features. +const fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -35,6 +36,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` +const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index bef4f240ee..de6a9a1926 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -1,39 +1,41 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:16:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:24:26 | LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_fn_libstd_stability.rs:29:26 | LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | +help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks + | +LL | #[allow_internal_unstable(const_fn_floating_point_arithmetic)] + | -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` - --> $DIR/min_const_fn_libstd_stability.rs:38:32 +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_fn_libstd_stability.rs:39:32 | LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs index 6462d736ad..0c8af5a199 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs @@ -12,5 +12,5 @@ fn main() {} const unsafe fn no_union() { union Foo { x: (), y: () } Foo { x: () }.y - //~^ accessing union fields is unstable + //~^ unions in const fn } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr index 427ecff5c6..322052c28f 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr @@ -25,16 +25,15 @@ LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static u = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error[E0723]: accessing union fields is unstable +error[E0658]: unions in const fn are unstable --> $DIR/min_const_fn_unsafe_bad.rs:14:5 | LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51909 for more information + = help: add `#![feature(const_fn_union)]` to the crate attributes to enable error: aborting due to 4 previous errors -Some errors have detailed explanations: E0658, E0723. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 12b41ee2b0..0f48341ddf 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, foo, foo2)] +#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -13,7 +13,7 @@ const unsafe fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn` +const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const unsafe fn foo2() -> u32 { 42 } @@ -21,12 +21,13 @@ const unsafe fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn` +const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate -const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op +const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -36,6 +37,6 @@ const unsafe fn foo2_gated() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } -//~^ ERROR can only call other `const fn` +//~^ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index c5ff340dfc..f258deb12a 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -1,39 +1,41 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41 | LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 | LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 | LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | +help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks + | +LL | #[allow_internal_unstable(const_fn_floating_point_arithmetic)] + | -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:38:48 +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:39:48 | LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs index 44a6209498..d17dcb2811 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` +const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const fn foo2() -> u32 { 42 } @@ -21,7 +21,7 @@ const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` +const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -30,6 +30,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` +const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index 31ad12c955..891c34a888 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -1,30 +1,26 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32 | LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 | LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` +error: `foo2_gated` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 | LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.rs b/src/test/ui/consts/min_const_fn/mutable_borrow.rs index 89acfea6ed..580b1d50f7 100644 --- a/src/test/ui/consts/min_const_fn/mutable_borrow.rs +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.rs @@ -1,6 +1,6 @@ const fn mutable_ref_in_const() -> u8 { let mut a = 0; - let b = &mut a; //~ ERROR mutable references in const fn + let b = &mut a; //~ ERROR mutable references *b } @@ -9,7 +9,7 @@ struct X; impl X { const fn inherent_mutable_ref_in_const() -> u8 { let mut a = 0; - let b = &mut a; //~ ERROR mutable references in const fn + let b = &mut a; //~ ERROR mutable references *b } } diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr index f5a3c168a8..8e95a4c68a 100644 --- a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr @@ -1,21 +1,21 @@ -error[E0723]: mutable references in const fn are unstable - --> $DIR/mutable_borrow.rs:3:9 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/mutable_borrow.rs:3:13 | LL | let b = &mut a; - | ^ + | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable - --> $DIR/mutable_borrow.rs:12:13 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/mutable_borrow.rs:12:17 | LL | let b = &mut a; - | ^ + | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr index eb250081d6..8fd562c5da 100644 --- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -12,6 +12,16 @@ LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern " warning: skipping const checks | +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/abi-mismatch.rs:9:23 + | +LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) { + | ^^^^^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/abi-mismatch.rs:10:5 + | +LL | my_fn(); + | ^^^^^ help: skipping check that does not even have a feature gate --> $DIR/abi-mismatch.rs:10:5 | diff --git a/src/test/ui/consts/miri_unleashed/box.stderr b/src/test/ui/consts/miri_unleashed/box.stderr index 768b795ca5..66ea9d5924 100644 --- a/src/test/ui/consts/miri_unleashed/box.stderr +++ b/src/test/ui/consts/miri_unleashed/box.stderr @@ -21,7 +21,7 @@ help: skipping check for `const_mut_refs` feature | LL | &mut *(box 0) | ^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/box.rs:10:5 | LL | &mut *(box 0) diff --git a/src/test/ui/consts/miri_unleashed/drop.rs b/src/test/ui/consts/miri_unleashed/drop.rs index 9bd56e81cb..4afa954d90 100644 --- a/src/test/ui/consts/miri_unleashed/drop.rs +++ b/src/test/ui/consts/miri_unleashed/drop.rs @@ -1,5 +1,5 @@ // compile-flags: -Zunleash-the-miri-inside-of-you -// error-pattern: calling non-const function ` as std::ops::Drop>::drop` +// error-pattern: calling non-const function ` as Drop>::drop` #![allow(const_err)] use std::mem::ManuallyDrop; diff --git a/src/test/ui/consts/miri_unleashed/drop.stderr b/src/test/ui/consts/miri_unleashed/drop.stderr index c1ab52435e..eb1b42c57b 100644 --- a/src/test/ui/consts/miri_unleashed/drop.stderr +++ b/src/test/ui/consts/miri_unleashed/drop.stderr @@ -1,22 +1,16 @@ error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { -LL | | // Code here does not matter - this is replaced by the -LL | | // real drop glue by the compiler. -LL | | -LL | | // SAFETY: see comment above -LL | | unsafe { drop_in_place(to_drop) } -LL | | } - | | ^ - | | | - | |_calling non-const function ` as std::ops::Drop>::drop` - | inside `std::intrinsics::drop_in_place::> - shim(Some(std::vec::Vec))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL +LL | pub unsafe fn drop_in_place(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | calling non-const function ` as Drop>::drop` + | inside `drop_in_place::> - shim(Some(Vec))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL | ::: $DIR/drop.rs:18:1 | -LL | }; - | - inside `TEST_BAD` at $DIR/drop.rs:18:1 +LL | }; + | - inside `TEST_BAD` at $DIR/drop.rs:18:1 warning: skipping const checks | diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index 7109ffd8b6..c6180c1e00 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -6,17 +6,17 @@ LL | *OH_YES = 99; warning: skipping const checks | -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:9:26 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:13:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:18:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); @@ -26,7 +26,7 @@ help: skipping check that does not even have a feature gate | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:30:27 | LL | static OH_YES: &mut i32 = &mut 42; diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr index 45e7d5a2cc..7647a9ff4f 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr @@ -30,7 +30,7 @@ help: skipping check that does not even have a feature gate | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references_err.rs:30:25 | LL | const BLUNT: &mut i32 = &mut 42; diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr index 27d2b2df4d..5cef636e0a 100644 --- a/src/test/ui/consts/miri_unleashed/tls.stderr +++ b/src/test/ui/consts/miri_unleashed/tls.stderr @@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:12:25 | LL | unsafe { let _val = A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A[0])) + | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A)) error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A[0])) + | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A)) warning: skipping const checks | diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index a89dcefd83..ebe17e8730 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -5,7 +5,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | ptr_offset_from cannot compute offset of pointers into different allocations. - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `DIFFERENT_ALLOC` at $DIR/offset_from_ub.rs:16:27 | ::: $DIR/offset_from_ub.rs:10:1 @@ -28,7 +28,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | unable to turn bytes into a pointer - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `NOT_PTR` at $DIR/offset_from_ub.rs:22:14 | ::: $DIR/offset_from_ub.rs:20:1 @@ -46,7 +46,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | exact_div: 1_isize cannot be divided by 2_isize without remainder - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `NOT_MULTIPLE_OF_SIZE` at $DIR/offset_from_ub.rs:30:14 | ::: $DIR/offset_from_ub.rs:25:1 @@ -67,7 +67,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: 0x0 is not a valid pointer - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:36:14 | ::: $DIR/offset_from_ub.rs:33:1 @@ -86,7 +86,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | unable to turn bytes into a pointer - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `DIFFERENT_INT` at $DIR/offset_from_ub.rs:43:14 | ::: $DIR/offset_from_ub.rs:39:1 diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index 6245354590..e58db1efaf 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -5,7 +5,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `BEFORE_START` at $DIR/offset_ub.rs:7:46 | ::: $DIR/offset_ub.rs:7:1 @@ -22,7 +22,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1 - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `AFTER_END` at $DIR/offset_ub.rs:8:43 | ::: $DIR/offset_ub.rs:8:1 @@ -37,7 +37,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100 - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45 | ::: $DIR/offset_ub.rs:9:1 @@ -52,7 +52,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `OVERFLOW` at $DIR/offset_ub.rs:11:43 | ::: $DIR/offset_ub.rs:11:1 @@ -67,7 +67,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44 | ::: $DIR/offset_ub.rs:12:1 @@ -82,7 +82,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56 | ::: $DIR/offset_ub.rs:13:1 @@ -97,7 +97,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57 | ::: $DIR/offset_ub.rs:14:1 @@ -112,7 +112,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0 - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:16:50 | ::: $DIR/offset_ub.rs:16:1 @@ -127,7 +127,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | unable to turn bytes into a pointer - | inside `std::ptr::mut_ptr::::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + | inside `ptr::mut_ptr::::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL | inside `DANGLING` at $DIR/offset_ub.rs:17:42 | ::: $DIR/offset_ub.rs:17:1 @@ -142,7 +142,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: 0x0 is not a valid pointer - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:20:50 | ::: $DIR/offset_ub.rs:20:1 @@ -157,7 +157,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | unable to turn bytes into a pointer - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `UNDERFLOW_ABS` at $DIR/offset_ub.rs:23:47 | ::: $DIR/offset_ub.rs:23:1 diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs index 7db970cf13..5e2584a6e9 100644 --- a/src/test/ui/consts/projection_qualif.rs +++ b/src/test/ui/consts/projection_qualif.rs @@ -9,7 +9,6 @@ const FOO: &u32 = { { let b: *mut u32 = &mut a; //~ ERROR mutable references are not allowed in constants unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants - //[stock]~^ contains unimplemented expression } &{a} }; diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr index 212f122864..fad8f011f7 100644 --- a/src/test/ui/consts/projection_qualif.stock.stderr +++ b/src/test/ui/consts/projection_qualif.stock.stderr @@ -13,15 +13,7 @@ LL | unsafe { *b = 5; } = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error[E0019]: constant contains unimplemented expression type - --> $DIR/projection_qualif.rs:11:18 - | -LL | unsafe { *b = 5; } - | ^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0019, E0658, E0764. -For more information about an error, try `rustc --explain E0019`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs new file mode 100644 index 0000000000..8daac75837 --- /dev/null +++ b/src/test/ui/consts/promote-not.rs @@ -0,0 +1,30 @@ +// ignore-tidy-linelength +// Test various things that we do not want to promote. +#![allow(unconditional_panic, const_err)] +#![feature(const_fn, const_fn_union)] + +// We do not promote mutable references. +static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed + +static mut TEST2: &'static mut [i32] = { + let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed + x +}; + +// We do not promote fn calls in `fn`, including `const fn`. +pub const fn promote_cal(b: bool) -> i32 { + const fn foo() { [()][42] } + + if b { + let _x: &'static () = &foo(); //~ ERROR temporary value dropped while borrowed + } + 13 +} + +// We do not promote union field accesses in `fn. +union U { x: i32, y: i32 } +pub const fn promote_union() { + let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed +} + +fn main() {} diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr new file mode 100644 index 0000000000..efe921b601 --- /dev/null +++ b/src/test/ui/consts/promote-not.stderr @@ -0,0 +1,43 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:7:50 + | +LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); + | ----------^^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary which is freed while still in use + | using this value as a static requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:10:18 + | +LL | let x = &mut [1,2,3]; + | ^^^^^^^ creates a temporary which is freed while still in use +LL | x + | - using this value as a static requires that borrow lasts for `'static` +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:19:32 + | +LL | let _x: &'static () = &foo(); + | ----------- ^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:27:29 + | +LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/promotion-mutable-ref.rs b/src/test/ui/consts/promotion-mutable-ref.rs new file mode 100644 index 0000000000..d103c5a9d2 --- /dev/null +++ b/src/test/ui/consts/promotion-mutable-ref.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(const_mut_refs)] + +static mut TEST: i32 = { + // We must not promote this, as CTFE needs to be able to mutate it later. + let x = &mut [1,2,3]; + x[0] += 1; + x[0] +}; + +// This still works -- it's not done via promotion. +#[allow(unused)] +static mut TEST2: &'static mut [i32] = &mut [0,1,2]; + +fn main() { + assert_eq!(unsafe { TEST }, 2); +} diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs index 3c5401e421..5f84030a9e 100644 --- a/src/test/ui/consts/promotion.rs +++ b/src/test/ui/consts/promotion.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // compile-flags: -O diff --git a/src/test/ui/consts/ptr_comparisons.stderr b/src/test/ui/consts/ptr_comparisons.stderr index 493d9be8f7..63faae275d 100644 --- a/src/test/ui/consts/ptr_comparisons.stderr +++ b/src/test/ui/consts/ptr_comparisons.stderr @@ -5,7 +5,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: pointer must be in-bounds at offset $TWO_WORDS, but is outside bounds of alloc2 which has size $WORD - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `_` at $DIR/ptr_comparisons.rs:62:34 | ::: $DIR/ptr_comparisons.rs:62:1 diff --git a/src/test/ui/consts/recursive-zst-static.default.stderr b/src/test/ui/consts/recursive-zst-static.default.stderr index 9042c6f6be..03f8f5c5a0 100644 --- a/src/test/ui/consts/recursive-zst-static.default.stderr +++ b/src/test/ui/consts/recursive-zst-static.default.stderr @@ -1,20 +1,16 @@ -error[E0391]: cycle detected when const-evaluating `FOO` +error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `FOO`... - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `FOO` +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/consts/recursive-zst-static.rs b/src/test/ui/consts/recursive-zst-static.rs index 29a467c006..4e61634b34 100644 --- a/src/test/ui/consts/recursive-zst-static.rs +++ b/src/test/ui/consts/recursive-zst-static.rs @@ -7,7 +7,7 @@ // can depend on this fact and will thus do unsound things when it is violated. // See https://github.com/rust-lang/rust/issues/71078 for more details. -static FOO: () = FOO; //~ cycle detected when const-evaluating `FOO` +static FOO: () = FOO; //~ cycle detected when const-evaluating + checking `FOO` fn main() { FOO diff --git a/src/test/ui/consts/recursive-zst-static.unleash.stderr b/src/test/ui/consts/recursive-zst-static.unleash.stderr index 9042c6f6be..03f8f5c5a0 100644 --- a/src/test/ui/consts/recursive-zst-static.unleash.stderr +++ b/src/test/ui/consts/recursive-zst-static.unleash.stderr @@ -1,20 +1,16 @@ -error[E0391]: cycle detected when const-evaluating `FOO` +error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `FOO`... - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `FOO` +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs index 38f744e99a..d40facf232 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs @@ -14,5 +14,5 @@ const fn copy() -> u32 { fn main() { let _: [u32; 2] = [copy(); 2]; let _: [Option; 2] = [no_copy(); 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Option: Copy` is not satisfied } diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr index 8219d836a2..48092432bb 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Option: Copy` is not satisfied --> $DIR/fn-call-in-non-const.rs:16:31 | LL | let _: [Option; 2] = [no_copy(); 2]; - | ^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to previous error diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs index 3b7d7e5b51..d04b0b7e16 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // ignore-compare-mode-nll // compile-flags: -Z borrowck=migrate #![feature(const_in_array_repeat_expressions)] @@ -13,13 +12,13 @@ mod non_constants { fn no_impl_copy_empty_value_multiple_elements() { let x = None; let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } fn no_impl_copy_value_multiple_elements() { let x = Some(Bar); let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } } diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr index aad6763f15..476d48fd49 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr @@ -1,21 +1,21 @@ -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/migrate-fail.rs:15:37 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/migrate-fail.rs:14:37 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/migrate-fail.rs:21:37 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/migrate-fail.rs:20:37 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs index dc1193a2fe..2d5c59d112 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // ignore-compare-mode-nll #![feature(const_in_array_repeat_expressions, nll)] #![allow(warnings)] @@ -12,13 +11,13 @@ mod non_constants { fn no_impl_copy_empty_value_multiple_elements() { let x = None; let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } fn no_impl_copy_value_multiple_elements() { let x = Some(Bar); let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } } diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr index fd32484ff9..3aa69996ff 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr @@ -1,21 +1,21 @@ -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/nll-fail.rs:14:37 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/nll-fail.rs:13:37 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/nll-fail.rs:20:37 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/nll-fail.rs:19:37 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs index 35484d265b..f8df7aafa6 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength #![feature(const_in_array_repeat_expressions)] #[derive(Copy, Clone)] @@ -6,5 +5,5 @@ struct Foo(T); fn main() { [Foo(String::new()); 4]; - //~^ ERROR the trait bound `Foo: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Foo: Copy` is not satisfied [E0277] } diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr index 186909e469..26de67e50f 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `Foo: std::marker::Copy` is not satisfied - --> $DIR/trait-error.rs:8:5 +error[E0277]: the trait bound `Foo: Copy` is not satisfied + --> $DIR/trait-error.rs:7:5 | LL | [Foo(String::new()); 4]; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Foo` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Foo` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to previous error diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000..651462d7ef --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs @@ -0,0 +1,22 @@ +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops, const_fn)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "foo", since = "1.0.0")] + pub const fn unwrap(self) -> T { + //~^ ERROR destructors cannot be evaluated at compile-time + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr new file mode 100644 index 0000000000..a3f513541d --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr @@ -0,0 +1,12 @@ +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/stable-precise-live-drops-in-libcore.rs:13:25 + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ constant functions cannot evaluate destructors +... +LL | } + | - value is dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs index a6bbe8d6ec..2821d1a015 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs @@ -6,6 +6,5 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; //~^ ERROR mutable references are not allowed in statics -//[stock]~| ERROR static contains unimplemented expression type fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr index 57fb27e642..36c280ca5c 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -4,15 +4,6 @@ error[E0764]: mutable references are not allowed in statics LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn` -error[E0019]: static contains unimplemented expression type - --> $DIR/static_mut_containing_mut_ref2.rs:7:45 - | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0019, E0764. -For more information about an error, try `rustc --explain E0019`. +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index d5816fbb8e..ac104ed4a5 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -20,7 +20,7 @@ error[E0277]: can't compare `[{integer}; _]` with `[{integer}; 0]` LL | [5; Self::HOST_SIZE] == [6; 0] | ^^ no implementation for `[{integer}; _] == [{integer}; 0]` | - = help: the trait `std::cmp::PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]` + = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]` error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs index 67d9f6baca..af6bc2d85f 100644 --- a/src/test/ui/consts/unsizing-cast-non-null.rs +++ b/src/test/ui/consts/unsizing-cast-non-null.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; pub const fn dangling_slice() -> NonNull<[T]> { NonNull::<[T; 0]>::dangling() - //~^ ERROR: unsizing casts are only allowed for references right now + //~^ ERROR: unsizing casts to types besides slices } fn main() {} diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr index 6575355daa..dc08ccd02b 100644 --- a/src/test/ui/consts/unsizing-cast-non-null.stderr +++ b/src/test/ui/consts/unsizing-cast-non-null.stderr @@ -1,4 +1,4 @@ -error[E0723]: unsizing casts are only allowed for references right now +error[E0723]: unsizing casts to types besides slices are not allowed in const fn --> $DIR/unsizing-cast-non-null.rs:6:5 | LL | NonNull::<[T; 0]>::dangling() diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs index 29d3dc18fa..43951c6854 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.rs +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs @@ -6,6 +6,7 @@ #![stable(feature = "core", since = "1.6.0")] #![feature(rustc_const_unstable)] #![feature(staged_api)] +#![feature(const_fn)] enum Opt { Some(T), diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr index be797cae7c..928605356a 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,11 +1,11 @@ error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/unstable-const-fn-in-libcore.rs:23:26 + --> $DIR/unstable-const-fn-in-libcore.rs:24:26 | LL | Opt::None => f(), | ^^^ error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:18:53 + --> $DIR/unstable-const-fn-in-libcore.rs:19:53 | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^ constant functions cannot evaluate destructors @@ -14,7 +14,7 @@ LL | } | - value is dropped here error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:18:47 + --> $DIR/unstable-const-fn-in-libcore.rs:19:47 | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^^^^ constant functions cannot evaluate destructors diff --git a/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000..619084eaa5 --- /dev/null +++ b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs @@ -0,0 +1,23 @@ +// check-pass + +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "foo", issue = "none")] + pub const fn unwrap(self) -> T { + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} diff --git a/src/test/ui/conversion-methods.stderr b/src/test/ui/conversion-methods.stderr index b3621a27ac..4f47e1fd0f 100644 --- a/src/test/ui/conversion-methods.stderr +++ b/src/test/ui/conversion-methods.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let _tis_an_instants_play: String = "'Tis a fond Ambush—"; | ------ ^^^^^^^^^^^^^^^^^^^^^ | | | - | | expected struct `std::string::String`, found `&str` + | | expected struct `String`, found `&str` | | help: try using a conversion method: `"'Tis a fond Ambush—".to_string()` | expected due to this @@ -14,7 +14,7 @@ error[E0308]: mismatched types LL | let _just_to_make_bliss: PathBuf = Path::new("/ern/her/own/surprise"); | ------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | - | | expected struct `std::path::PathBuf`, found `&std::path::Path` + | | expected struct `PathBuf`, found `&Path` | | help: try using a conversion method: `Path::new("/ern/her/own/surprise").to_path_buf()` | expected due to this @@ -24,7 +24,7 @@ error[E0308]: mismatched types LL | let _but_should_the_play: String = 2; // Perhaps surprisingly, we suggest .to_string() here | ------ ^ | | | - | | expected struct `std::string::String`, found integer + | | expected struct `String`, found integer | | help: try using a conversion method: `2.to_string()` | expected due to this @@ -34,11 +34,11 @@ error[E0308]: mismatched types LL | let _prove_piercing_earnest: Vec = &[1, 2, 3]; | ---------- ^^^^^^^^^^ | | | - | | expected struct `std::vec::Vec`, found `&[{integer}; 3]` + | | expected struct `Vec`, found `&[{integer}; 3]` | | help: try using a conversion method: `(&[1, 2, 3]).to_vec()` | expected due to this | - = note: expected struct `std::vec::Vec` + = note: expected struct `Vec` found reference `&[{integer}; 3]` error: aborting due to 4 previous errors diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr index 477a383690..36cf57bd3c 100644 --- a/src/test/ui/copy-a-resource.stderr +++ b/src/test/ui/copy-a-resource.stderr @@ -12,12 +12,12 @@ LL | let _y = x.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here + | the method is available for `Arc` here + | the method is available for `Rc` here | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/cross/cross-borrow-trait.rs b/src/test/ui/cross/cross-borrow-trait.rs index ce42b696dd..180a75e3df 100644 --- a/src/test/ui/cross/cross-borrow-trait.rs +++ b/src/test/ui/cross/cross-borrow-trait.rs @@ -9,5 +9,5 @@ pub fn main() { let x: Box = Box::new(Foo); let _y: &dyn Trait = x; //~ ERROR E0308 //~| expected reference `&dyn Trait` - //~| found struct `std::boxed::Box` + //~| found struct `Box` } diff --git a/src/test/ui/cross/cross-borrow-trait.stderr b/src/test/ui/cross/cross-borrow-trait.stderr index 618f6595d4..f693a3149b 100644 --- a/src/test/ui/cross/cross-borrow-trait.stderr +++ b/src/test/ui/cross/cross-borrow-trait.stderr @@ -4,12 +4,12 @@ error[E0308]: mismatched types LL | let _y: &dyn Trait = x; | ---------- ^ | | | - | | expected `&dyn Trait`, found struct `std::boxed::Box` + | | expected `&dyn Trait`, found struct `Box` | | help: consider borrowing here: `&x` | expected due to this | = note: expected reference `&dyn Trait` - found struct `std::boxed::Box` + found struct `Box` error: aborting due to previous error diff --git a/src/test/ui/custom_test_frameworks/mismatch.rs b/src/test/ui/custom_test_frameworks/mismatch.rs index e6848e2f3b..ac850552b5 100644 --- a/src/test/ui/custom_test_frameworks/mismatch.rs +++ b/src/test/ui/custom_test_frameworks/mismatch.rs @@ -7,4 +7,4 @@ extern crate example_runner; #[test] fn wrong_kind(){} -//~^ ERROR trait bound `test::TestDescAndFn: example_runner::Testable` is not satisfied +//~^ ERROR trait bound `TestDescAndFn: Testable` is not satisfied diff --git a/src/test/ui/custom_test_frameworks/mismatch.stderr b/src/test/ui/custom_test_frameworks/mismatch.stderr index 420ddbc3de..ea4445deb4 100644 --- a/src/test/ui/custom_test_frameworks/mismatch.stderr +++ b/src/test/ui/custom_test_frameworks/mismatch.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `test::TestDescAndFn: example_runner::Testable` is not satisfied +error[E0277]: the trait bound `TestDescAndFn: Testable` is not satisfied --> $DIR/mismatch.rs:9:1 | LL | fn wrong_kind(){} - | ^^^^^^^^^^^^^^^^^ the trait `example_runner::Testable` is not implemented for `test::TestDescAndFn` + | ^^^^^^^^^^^^^^^^^ the trait `Testable` is not implemented for `TestDescAndFn` | - = note: required for the cast to the object type `dyn example_runner::Testable` + = note: required for the cast to the object type `dyn Testable` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr index 164c474183..3d968aa3ea 100644 --- a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr +++ b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr @@ -4,7 +4,7 @@ error: OK LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::x` to `typeck` +error: no path from `x` to `typeck` --> $DIR/dep-graph-caller-callee.rs:31:5 | LL | #[rustc_then_this_would_need(typeck)] diff --git a/src/test/ui/deprecation/deprecation-lint.rs b/src/test/ui/deprecation/deprecation-lint.rs index 1932344fc5..560e296888 100644 --- a/src/test/ui/deprecation/deprecation-lint.rs +++ b/src/test/ui/deprecation/deprecation-lint.rs @@ -314,7 +314,7 @@ mod this_crate { let _ = || { #[deprecated] fn bar() { } - bar(); //~ ERROR use of deprecated function `this_crate::test_fn_closure_body::{{closure}}#0::bar` + bar(); //~ ERROR use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar` }; } diff --git a/src/test/ui/deprecation/deprecation-lint.stderr b/src/test/ui/deprecation/deprecation-lint.stderr index 03a2ec7edc..12c76f0f4a 100644 --- a/src/test/ui/deprecation/deprecation-lint.stderr +++ b/src/test/ui/deprecation/deprecation-lint.stderr @@ -298,7 +298,7 @@ error: use of deprecated associated function `this_crate::Trait::trait_deprecate LL | ... ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: use of deprecated function `this_crate::test_fn_closure_body::{{closure}}#0::bar` +error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar` --> $DIR/deprecation-lint.rs:317:13 | LL | bar(); diff --git a/src/test/ui/deref-lval.rs b/src/test/ui/deref-lval.rs deleted file mode 100644 index f57872f80e..0000000000 --- a/src/test/ui/deref-lval.rs +++ /dev/null @@ -1,11 +0,0 @@ -// run-pass - -#![feature(box_syntax)] - -use std::cell::Cell; - -pub fn main() { - let x: Box<_> = box Cell::new(5); - x.set(1000); - println!("{}", x.get()); -} diff --git a/src/test/ui/deref-suggestion.stderr b/src/test/ui/deref-suggestion.stderr index 89fd7aae3b..f59f05db9c 100644 --- a/src/test/ui/deref-suggestion.stderr +++ b/src/test/ui/deref-suggestion.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo(s); | ^ | | - | expected struct `std::string::String`, found `&std::string::String` + | expected struct `String`, found `&String` | help: try using a conversion method: `s.to_string()` error[E0308]: mismatched types @@ -22,7 +22,7 @@ error[E0308]: mismatched types LL | foo(&"aaa".to_owned()); | ^^^^^^^^^^^^^^^^^ | | - | expected struct `std::string::String`, found `&std::string::String` + | expected struct `String`, found `&String` | help: consider removing the borrow: `"aaa".to_owned()` error[E0308]: mismatched types @@ -31,7 +31,7 @@ error[E0308]: mismatched types LL | foo(&mut "aaa".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ | | - | expected struct `std::string::String`, found `&mut std::string::String` + | expected struct `String`, found `&mut String` | help: consider removing the borrow: `"aaa".to_owned()` error[E0308]: mismatched types diff --git a/src/test/ui/derived-errors/issue-31997-1.stderr b/src/test/ui/derived-errors/issue-31997-1.stderr index 229c5c9e80..6d177666ed 100644 --- a/src/test/ui/derived-errors/issue-31997-1.stderr +++ b/src/test/ui/derived-errors/issue-31997-1.stderr @@ -1,4 +1,4 @@ -error[E0433]: failed to resolve: use of undeclared type or module `HashMap` +error[E0433]: failed to resolve: use of undeclared type `HashMap` --> $DIR/issue-31997-1.rs:20:19 | LL | let mut map = HashMap::new(); diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr index e4d6794bbf..92ba4f0704 100644 --- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr +++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr @@ -5,10 +5,10 @@ LL | struct Bar { | ------------------ | | | method `clone` not found for this - | doesn't satisfy `Bar: std::clone::Clone` + | doesn't satisfy `Bar: Clone` ... LL | struct NotClone; - | ---------------- doesn't satisfy `NotClone: std::clone::Clone` + | ---------------- doesn't satisfy `NotClone: Clone` ... LL | Bar:: { x: 1 }.clone(); | ^^^^^ method not found in `Bar` @@ -18,15 +18,15 @@ LL | Bar:: { x: 1 }.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `NotClone: std::clone::Clone` - which is required by `Bar: std::clone::Clone` + `NotClone: Clone` + which is required by `Bar: Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr b/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr index b3aa886cd4..e892d3f086 100644 --- a/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr +++ b/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr @@ -1,10 +1,10 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/derive-on-trait-item-or-impl-item.rs:2:5 | LL | #[derive(Clone)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/derive-on-trait-item-or-impl-item.rs:10:5 | LL | #[derive(Clone)] @@ -12,3 +12,4 @@ LL | #[derive(Clone)] error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr index bbb8776f4f..aa33faf599 100644 --- a/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Error: Clone` is not satisfied --> $DIR/derives-span-Clone-enum-struct-variant.rs:9:6 | LL | x: Error - | ^^^^^^^^ the trait `std::clone::Clone` is not implemented for `Error` + | ^^^^^^^^ the trait `Clone` is not implemented for `Error` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Clone-enum.stderr b/src/test/ui/derives/derives-span-Clone-enum.stderr index 0e410e795e..e3bc2d6a9a 100644 --- a/src/test/ui/derives/derives-span-Clone-enum.stderr +++ b/src/test/ui/derives/derives-span-Clone-enum.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Error: Clone` is not satisfied --> $DIR/derives-span-Clone-enum.rs:9:6 | LL | Error - | ^^^^^ the trait `std::clone::Clone` is not implemented for `Error` + | ^^^^^ the trait `Clone` is not implemented for `Error` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Clone-struct.stderr b/src/test/ui/derives/derives-span-Clone-struct.stderr index 889128a662..99c0cdecb6 100644 --- a/src/test/ui/derives/derives-span-Clone-struct.stderr +++ b/src/test/ui/derives/derives-span-Clone-struct.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Error: Clone` is not satisfied --> $DIR/derives-span-Clone-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::clone::Clone` is not implemented for `Error` + | ^^^^^^^^ the trait `Clone` is not implemented for `Error` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr b/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr index 0024199ca5..e6d734bfcc 100644 --- a/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Error: Clone` is not satisfied --> $DIR/derives-span-Clone-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::clone::Clone` is not implemented for `Error` + | ^^^^^ the trait `Clone` is not implemented for `Error` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr index 77779a55b6..64caba8e80 100644 --- a/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr @@ -1,13 +1,13 @@ -error[E0277]: `Error` doesn't implement `std::fmt::Debug` +error[E0277]: `Error` doesn't implement `Debug` --> $DIR/derives-span-Debug-enum-struct-variant.rs:9:6 | LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Error` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Error` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Error` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&Error` + = note: required for the cast to the object type `dyn Debug` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Debug-enum.stderr b/src/test/ui/derives/derives-span-Debug-enum.stderr index f64c33c2bc..88b61f3fcc 100644 --- a/src/test/ui/derives/derives-span-Debug-enum.stderr +++ b/src/test/ui/derives/derives-span-Debug-enum.stderr @@ -1,13 +1,13 @@ -error[E0277]: `Error` doesn't implement `std::fmt::Debug` +error[E0277]: `Error` doesn't implement `Debug` --> $DIR/derives-span-Debug-enum.rs:9:6 | LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Error` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Error` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Error` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&Error` + = note: required for the cast to the object type `dyn Debug` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Debug-struct.stderr b/src/test/ui/derives/derives-span-Debug-struct.stderr index 0013bcf832..558a5796d2 100644 --- a/src/test/ui/derives/derives-span-Debug-struct.stderr +++ b/src/test/ui/derives/derives-span-Debug-struct.stderr @@ -1,13 +1,13 @@ -error[E0277]: `Error` doesn't implement `std::fmt::Debug` +error[E0277]: `Error` doesn't implement `Debug` --> $DIR/derives-span-Debug-struct.rs:8:5 | LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Error` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Error` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Error` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&Error` + = note: required for the cast to the object type `dyn Debug` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr b/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr index 7e0039e8a7..73a88a653f 100644 --- a/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr @@ -1,13 +1,13 @@ -error[E0277]: `Error` doesn't implement `std::fmt::Debug` +error[E0277]: `Error` doesn't implement `Debug` --> $DIR/derives-span-Debug-tuple-struct.rs:8:5 | LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Error` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Error` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Error` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&Error` + = note: required for the cast to the object type `dyn Debug` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Default-struct.stderr b/src/test/ui/derives/derives-span-Default-struct.stderr index 492847fc02..d2a5280ac6 100644 --- a/src/test/ui/derives/derives-span-Default-struct.stderr +++ b/src/test/ui/derives/derives-span-Default-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::default::Default` is not satisfied +error[E0277]: the trait bound `Error: Default` is not satisfied --> $DIR/derives-span-Default-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::default::Default` is not implemented for `Error` + | ^^^^^^^^ the trait `Default` is not implemented for `Error` | = note: required by `std::default::Default::default` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Default-tuple-struct.stderr b/src/test/ui/derives/derives-span-Default-tuple-struct.stderr index fa7b27e770..96ff7adc72 100644 --- a/src/test/ui/derives/derives-span-Default-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Default-tuple-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::default::Default` is not satisfied +error[E0277]: the trait bound `Error: Default` is not satisfied --> $DIR/derives-span-Default-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::default::Default` is not implemented for `Error` + | ^^^^^ the trait `Default` is not implemented for `Error` | = note: required by `std::default::Default::default` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr index 698eb8375e..4ad7b94e41 100644 --- a/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Error: Eq` is not satisfied --> $DIR/derives-span-Eq-enum-struct-variant.rs:9:6 | LL | x: Error - | ^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` + | ^^^^^^^^ the trait `Eq` is not implemented for `Error` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Eq-enum.stderr b/src/test/ui/derives/derives-span-Eq-enum.stderr index 7009fcf439..8ee7274933 100644 --- a/src/test/ui/derives/derives-span-Eq-enum.stderr +++ b/src/test/ui/derives/derives-span-Eq-enum.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Error: Eq` is not satisfied --> $DIR/derives-span-Eq-enum.rs:9:6 | LL | Error - | ^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` + | ^^^^^ the trait `Eq` is not implemented for `Error` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Eq-struct.stderr b/src/test/ui/derives/derives-span-Eq-struct.stderr index 7ee0bc59ee..1b751365a3 100644 --- a/src/test/ui/derives/derives-span-Eq-struct.stderr +++ b/src/test/ui/derives/derives-span-Eq-struct.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Error: Eq` is not satisfied --> $DIR/derives-span-Eq-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` + | ^^^^^^^^ the trait `Eq` is not implemented for `Error` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr b/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr index a23b2fbd1c..44b1d2cc02 100644 --- a/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Error: Eq` is not satisfied --> $DIR/derives-span-Eq-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` + | ^^^^^ the trait `Eq` is not implemented for `Error` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr index 3f41918493..9a03153797 100644 --- a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Error: Hash` is not satisfied --> $DIR/derives-span-Hash-enum-struct-variant.rs:9:6 | LL | x: Error - | ^^^^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | ^^^^^^^^ the trait `Hash` is not implemented for `Error` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/derives/derives-span-Hash-enum.stderr b/src/test/ui/derives/derives-span-Hash-enum.stderr index 7f64070ddb..08ddc66dd0 100644 --- a/src/test/ui/derives/derives-span-Hash-enum.stderr +++ b/src/test/ui/derives/derives-span-Hash-enum.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Error: Hash` is not satisfied --> $DIR/derives-span-Hash-enum.rs:8:6 | LL | Error - | ^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | ^^^^^ the trait `Hash` is not implemented for `Error` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/derives/derives-span-Hash-struct.stderr b/src/test/ui/derives/derives-span-Hash-struct.stderr index 4082c6cbd3..a2be46dc77 100644 --- a/src/test/ui/derives/derives-span-Hash-struct.stderr +++ b/src/test/ui/derives/derives-span-Hash-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Error: Hash` is not satisfied --> $DIR/derives-span-Hash-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | ^^^^^^^^ the trait `Hash` is not implemented for `Error` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr b/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr index 7cac216bc1..30cc6dc27a 100644 --- a/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Error: Hash` is not satisfied --> $DIR/derives-span-Hash-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | ^^^^^ the trait `Hash` is not implemented for `Error` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr index d0286ad17e..b0b2321753 100644 --- a/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `Error: Ord` is not satisfied --> $DIR/derives-span-Ord-enum-struct-variant.rs:9:6 | LL | x: Error - | ^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` + | ^^^^^^^^ the trait `Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Ord-enum.stderr b/src/test/ui/derives/derives-span-Ord-enum.stderr index aabbd0a1d1..bc95769294 100644 --- a/src/test/ui/derives/derives-span-Ord-enum.stderr +++ b/src/test/ui/derives/derives-span-Ord-enum.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `Error: Ord` is not satisfied --> $DIR/derives-span-Ord-enum.rs:9:6 | LL | Error - | ^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` + | ^^^^^ the trait `Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Ord-struct.stderr b/src/test/ui/derives/derives-span-Ord-struct.stderr index eaac3dafd0..5f324c131c 100644 --- a/src/test/ui/derives/derives-span-Ord-struct.stderr +++ b/src/test/ui/derives/derives-span-Ord-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `Error: Ord` is not satisfied --> $DIR/derives-span-Ord-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` + | ^^^^^^^^ the trait `Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr b/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr index 0ae36bcb8b..1c277e34ff 100644 --- a/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `Error: Ord` is not satisfied --> $DIR/derives-span-Ord-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` + | ^^^^^ the trait `Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr index 0be75972e8..0736e71460 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-PartialOrd-enum.stderr b/src/test/ui/derives/derives-span-PartialOrd-enum.stderr index 64290023c6..d88321b979 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-enum.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-enum.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-PartialOrd-struct.stderr b/src/test/ui/derives/derives-span-PartialOrd-struct.stderr index dcd81589e9..3023517752 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-struct.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr b/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr index 8dbf103d2d..3abf1ded8d 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr index 5fa2710cba..4919bac526 100644 --- a/src/test/ui/derives/deriving-copyclone.stderr +++ b/src/test/ui/derives/deriving-copyclone.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `C: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `C: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:31:13 | LL | fn is_copy(_: T) {} @@ -7,12 +7,12 @@ LL | fn is_copy(_: T) {} LL | is_copy(B { a: 1, b: C }); | ^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::marker::Copy` + | expected an implementor of trait `Copy` | help: consider borrowing here: `&B { a: 1, b: C }` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `B` + = note: required because of the requirements on the impl of `Copy` for `B` -error[E0277]: the trait bound `C: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `C: Clone` is not satisfied --> $DIR/deriving-copyclone.rs:32:14 | LL | fn is_clone(_: T) {} @@ -21,12 +21,12 @@ LL | fn is_clone(_: T) {} LL | is_clone(B { a: 1, b: C }); | ^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::clone::Clone` + | expected an implementor of trait `Clone` | help: consider borrowing here: `&B { a: 1, b: C }` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `B` + = note: required because of the requirements on the impl of `Clone` for `B` -error[E0277]: the trait bound `D: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `D: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:35:13 | LL | fn is_copy(_: T) {} @@ -35,10 +35,10 @@ LL | fn is_copy(_: T) {} LL | is_copy(B { a: 1, b: D }); | ^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::marker::Copy` + | expected an implementor of trait `Copy` | help: consider borrowing here: `&B { a: 1, b: D }` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `B` + = note: required because of the requirements on the impl of `Copy` for `B` error: aborting due to 3 previous errors diff --git a/src/test/ui/derives/deriving-no-inner-impl-error-message.rs b/src/test/ui/derives/deriving-no-inner-impl-error-message.rs index d3ac5d2fe2..39e41a59ef 100644 --- a/src/test/ui/derives/deriving-no-inner-impl-error-message.rs +++ b/src/test/ui/derives/deriving-no-inner-impl-error-message.rs @@ -8,7 +8,7 @@ struct E { #[derive(Clone)] struct C { x: NoCloneOrEq - //~^ ERROR `NoCloneOrEq: std::clone::Clone` is not satisfied + //~^ ERROR `NoCloneOrEq: Clone` is not satisfied } diff --git a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr index d4995c1d50..1842a88bb2 100644 --- a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr +++ b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr @@ -16,13 +16,13 @@ LL | x: NoCloneOrEq = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `NoCloneOrEq: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NoCloneOrEq: Clone` is not satisfied --> $DIR/deriving-no-inner-impl-error-message.rs:10:5 | LL | x: NoCloneOrEq - | ^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `NoCloneOrEq` + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NoCloneOrEq` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/src/test/ui/derives/deriving-non-type.stderr b/src/test/ui/derives/deriving-non-type.stderr index 563e76dc60..8c9daf4d4b 100644 --- a/src/test/ui/derives/deriving-non-type.stderr +++ b/src/test/ui/derives/deriving-non-type.stderr @@ -1,52 +1,52 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:5:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:8:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:11:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:14:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:17:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:20:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:23:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:26:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:29:1 | LL | #[derive(PartialEq)] @@ -54,3 +54,4 @@ LL | #[derive(PartialEq)] error: aborting due to 9 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/dest-prop/skeptic-miscompile.rs b/src/test/ui/dest-prop/skeptic-miscompile.rs new file mode 100644 index 0000000000..c27a1f0453 --- /dev/null +++ b/src/test/ui/dest-prop/skeptic-miscompile.rs @@ -0,0 +1,24 @@ +// run-pass + +// compile-flags: -Zmir-opt-level=2 + +trait IterExt: Iterator { + fn fold_ex(mut self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x); + } + accum + } +} + +impl IterExt for T {} + +fn main() { + let test = &["\n"]; + test.iter().fold_ex(String::new(), |_, b| b.to_string()); +} diff --git a/src/test/ui/destructure-trait-ref.rs b/src/test/ui/destructure-trait-ref.rs index 34e7cad935..fdc9bbab73 100644 --- a/src/test/ui/destructure-trait-ref.rs +++ b/src/test/ui/destructure-trait-ref.rs @@ -26,7 +26,7 @@ fn main() { let &x = &1isize as &dyn T; //~ ERROR type `&dyn T` cannot be dereferenced let &&x = &(&1isize as &dyn T); //~ ERROR type `&dyn T` cannot be dereferenced let box x = box 1isize as Box; - //~^ ERROR type `std::boxed::Box` cannot be dereferenced + //~^ ERROR type `Box` cannot be dereferenced // n > m let &&x = &1isize as &dyn T; @@ -40,5 +40,5 @@ fn main() { let box box x = box 1isize as Box; //~^ ERROR mismatched types //~| expected trait object `dyn T` - //~| found struct `std::boxed::Box<_>` + //~| found struct `Box<_>` } diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index 1382cf643a..fb43ca760b 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -10,11 +10,11 @@ error[E0033]: type `&dyn T` cannot be dereferenced LL | let &&x = &(&1isize as &dyn T); | ^^ type `&dyn T` cannot be dereferenced -error[E0033]: type `std::boxed::Box` cannot be dereferenced +error[E0033]: type `Box` cannot be dereferenced --> $DIR/destructure-trait-ref.rs:28:9 | LL | let box x = box 1isize as Box; - | ^^^^^ type `std::boxed::Box` cannot be dereferenced + | ^^^^^ type `Box` cannot be dereferenced error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:32:10 @@ -44,12 +44,12 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:40:13 | LL | let box box x = box 1isize as Box; - | ^^^^^ ------------------------ this expression has type `std::boxed::Box` + | ^^^^^ ------------------------ this expression has type `Box` | | - | expected trait object `dyn T`, found struct `std::boxed::Box` + | expected trait object `dyn T`, found struct `Box` | = note: expected trait object `dyn T` - found struct `std::boxed::Box<_>` + found struct `Box<_>` error: aborting due to 6 previous errors diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index c409ea9c65..4835d9ab10 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -110,13 +110,13 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:27:10 | LL | type G = dyn 'static + (Send)::AssocTy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::marker::Send + 'static) as Trait>::AssocTy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Send + 'static) as Trait>::AssocTy` error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:33:10 | LL | type H = Fn(u8) -> (u8)::Output; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::ops::Fn(u8) -> u8 + 'static) as Trait>::Output` + | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as Trait>::Output` error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:37:19 diff --git a/src/test/ui/did_you_mean/issue-40396.rs b/src/test/ui/did_you_mean/issue-40396.rs index e4e94bb949..5497ba2e11 100644 --- a/src/test/ui/did_you_mean/issue-40396.rs +++ b/src/test/ui/did_you_mean/issue-40396.rs @@ -1,8 +1,29 @@ fn main() { (0..13).collect>(); //~^ ERROR comparison operators cannot be chained + //~| HELP use `::<...>` instead Vec::new(); //~^ ERROR comparison operators cannot be chained + //~| HELP use `::<...>` instead (0..13).collect(); //~^ ERROR comparison operators cannot be chained + //~| HELP use `::<...>` instead + let x = std::collections::HashMap::new(); //~ ERROR expected one of + //~^ HELP use `::<...>` instead + let x: () = 42; //~ ERROR mismatched types + let x = { + std::collections::HashMap::new() //~ ERROR expected one of + //~^ HELP use `::<...>` instead + }; + let x: () = 42; //~ ERROR mismatched types + let x = { + std::collections::HashMap::new(); //~ ERROR expected one of + //~^ HELP use `::<...>` instead + let x: () = 42; //~ ERROR mismatched types + }; + { + std::collections::HashMap::new(1, 2); //~ ERROR expected one of + //~^ HELP use `::<...>` instead + let x: () = 32; //~ ERROR mismatched types + }; } diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index 10972697f9..184bcf0c74 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -10,7 +10,7 @@ LL | (0..13).collect::>(); | ^^ error: comparison operators cannot be chained - --> $DIR/issue-40396.rs:4:8 + --> $DIR/issue-40396.rs:5:8 | LL | Vec::new(); | ^ ^ @@ -21,7 +21,7 @@ LL | Vec::::new(); | ^^ error: comparison operators cannot be chained - --> $DIR/issue-40396.rs:6:20 + --> $DIR/issue-40396.rs:8:20 | LL | (0..13).collect(); | ^ ^ @@ -31,5 +31,82 @@ help: use `::<...>` instead of `<...>` to specify type arguments LL | (0..13).collect::(); | ^^ -error: aborting due to 3 previous errors +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` + --> $DIR/issue-40396.rs:11:43 + | +LL | let x = std::collections::HashMap::new(); + | ^ expected one of 7 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | let x = std::collections::HashMap::::new(); + | ^^ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-40396.rs:15:39 + | +LL | std::collections::HashMap::new() + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | std::collections::HashMap::::new() + | ^^ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-40396.rs:20:39 + | +LL | std::collections::HashMap::new(); + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | std::collections::HashMap::::new(); + | ^^ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-40396.rs:25:39 + | +LL | std::collections::HashMap::new(1, 2); + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | std::collections::HashMap::::new(1, 2); + | ^^ + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:13:17 + | +LL | let x: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:18:17 + | +LL | let x: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:22:21 + | +LL | let x: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:27:21 + | +LL | let x: () = 32; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error: aborting due to 11 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr b/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr index 143d7f695c..dbd9dc1bc4 100644 --- a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr +++ b/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr @@ -1,24 +1,24 @@ -error[E0560]: struct `submodule::Demo` has no field named `inocently_mispellable` +error[E0560]: struct `Demo` has no field named `inocently_mispellable` --> $DIR/issue-42599_available_fields_note.rs:16:39 | LL | Self { secret_integer: 2, inocently_mispellable: () } | ^^^^^^^^^^^^^^^^^^^^^ help: a field with a similar name exists: `innocently_misspellable` -error[E0560]: struct `submodule::Demo` has no field named `egregiously_nonexistent_field` +error[E0560]: struct `Demo` has no field named `egregiously_nonexistent_field` --> $DIR/issue-42599_available_fields_note.rs:21:39 | LL | Self { secret_integer: 3, egregiously_nonexistent_field: () } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `submodule::Demo` does not have this field + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Demo` does not have this field | = note: available fields are: `favorite_integer`, `secret_integer`, `innocently_misspellable`, `another_field`, `yet_another_field` ... and 2 others -error[E0609]: no field `inocently_mispellable` on type `submodule::Demo` +error[E0609]: no field `inocently_mispellable` on type `Demo` --> $DIR/issue-42599_available_fields_note.rs:32:41 | LL | let innocent_field_misaccess = demo.inocently_mispellable; | ^^^^^^^^^^^^^^^^^^^^^ help: a field with a similar name exists: `innocently_misspellable` -error[E0609]: no field `egregiously_nonexistent_field` on type `submodule::Demo` +error[E0609]: no field `egregiously_nonexistent_field` on type `Demo` --> $DIR/issue-42599_available_fields_note.rs:35:42 | LL | let egregious_field_misaccess = demo.egregiously_nonexistent_field; diff --git a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr index f194b335fd..0ccccb53aa 100644 --- a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr +++ b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr @@ -21,7 +21,7 @@ error[E0277]: cannot subtract `{integer}` from `{float}` LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s⁻² | ^ no implementation for `{float} - {integer}` | - = help: the trait `std::ops::Sub<{integer}>` is not implemented for `{float}` + = help: the trait `Sub<{integer}>` is not implemented for `{float}` error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index c9a6d42b5c..c5b42416ea 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `K: std::marker::Send` +error[E0275]: overflow evaluating the requirement `K: Send` --> $DIR/recursion_limit.rs:34:5 | LL | fn is_send() { } diff --git a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index 333754891c..a8b160bbb2 100644 --- a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -10,11 +10,11 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy` LL | let _: &'static Copy + 'static; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'static (Copy + 'static)` -error[E0038]: the trait `std::marker::Copy` cannot be made into an object +error[E0038]: the trait `Copy` cannot be made into an object --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 | LL | let _: &Copy + 'static; - | ^^^^^ the trait `std::marker::Copy` cannot be made into an object + | ^^^^^ the trait `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` diff --git a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr index 8c64149a0f..cda81d1366 100644 --- a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr +++ b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr @@ -5,7 +5,7 @@ LL | let X { x: y } = x; | - ^ cannot move out of here | | | data moved here - | move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `y` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr index afc5170e1b..70cdd6446c 100644 --- a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr +++ b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr @@ -8,7 +8,7 @@ LL | X { x: y } => println!("contents: {}", y) | - | | | data moved here - | move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `y` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/disambiguate-identical-names.rs b/src/test/ui/disambiguate-identical-names.rs new file mode 100644 index 0000000000..708d2cd76a --- /dev/null +++ b/src/test/ui/disambiguate-identical-names.rs @@ -0,0 +1,15 @@ +pub mod submod { + // Create ambiguity with the std::vec::Vec item: + pub struct Vec; +} + +fn test(_v: &Vec>) { +} + +fn main() { + let v = std::collections::HashMap::new(); + v.insert(3u8, 1u8); + + test(&v); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/disambiguate-identical-names.stderr b/src/test/ui/disambiguate-identical-names.stderr new file mode 100644 index 0000000000..0c6bd9379f --- /dev/null +++ b/src/test/ui/disambiguate-identical-names.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/disambiguate-identical-names.rs:13:10 + | +LL | test(&v); + | ^^ expected struct `std::vec::Vec`, found struct `HashMap` + | + = note: expected reference `&std::vec::Vec>` + found reference `&HashMap` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr index c10232107e..5d53405579 100644 --- a/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr @@ -8,7 +8,7 @@ LL | } | - | | | `c_shortest` dropped here while still borrowed - | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `other::Dt` + | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `Dt` | = note: values in a scope are dropped in the opposite order they are defined @@ -22,7 +22,7 @@ LL | } | - | | | `c_shortest` dropped here while still borrowed - | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `other::Pt` + | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `Pt` | = note: values in a scope are dropped in the opposite order they are defined diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs index e2e600b17f..558b4342da 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs @@ -29,8 +29,8 @@ enum Wrapper { } fn main() { - let w = //~ ERROR overflow while adding drop-check rules for std::option + let w = //~ ERROR overflow while adding drop-check rules for Option Some(Wrapper::Simple::); - //~^ ERROR overflow while adding drop-check rules for std::option::Option + //~^ ERROR overflow while adding drop-check rules for Option //~| ERROR overflow while adding drop-check rules for Wrapper } diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr index 1c810df242..b24e1d1bf7 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr @@ -1,4 +1,4 @@ -error[E0320]: overflow while adding drop-check rules for std::option::Option> +error[E0320]: overflow while adding drop-check rules for Option> --> $DIR/dropck_no_diverge_on_nonregular_3.rs:32:9 | LL | let w = @@ -6,7 +6,7 @@ LL | let w = | = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -error[E0320]: overflow while adding drop-check rules for std::option::Option> +error[E0320]: overflow while adding drop-check rules for Option> --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:9 | LL | Some(Wrapper::Simple::); diff --git a/src/test/ui/dst/dst-bad-assign-2.stderr b/src/test/ui/dst/dst-bad-assign-2.stderr index a5374aedab..6c9e2971c6 100644 --- a/src/test/ui/dst/dst-bad-assign-2.stderr +++ b/src/test/ui/dst/dst-bad-assign-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `dyn ToBar` cannot be known at compila LL | f5.ptr = *z; | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` + = help: the trait `Sized` is not implemented for `dyn ToBar` = note: the left-hand-side of an assignment must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/dst/dst-bad-assign-3.stderr b/src/test/ui/dst/dst-bad-assign-3.stderr index f8d9300f11..04e4623353 100644 --- a/src/test/ui/dst/dst-bad-assign-3.stderr +++ b/src/test/ui/dst/dst-bad-assign-3.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `dyn ToBar` cannot be known at compila LL | f5.2 = Bar1 {f: 36}; | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` + = help: the trait `Sized` is not implemented for `dyn ToBar` = note: the left-hand-side of an assignment must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/dst/dst-bad-assign.stderr b/src/test/ui/dst/dst-bad-assign.stderr index 8e3eeefb9e..f87a34c6d3 100644 --- a/src/test/ui/dst/dst-bad-assign.stderr +++ b/src/test/ui/dst/dst-bad-assign.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `dyn ToBar` cannot be known at compila LL | f5.ptr = Bar1 {f: 36}; | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` + = help: the trait `Sized` is not implemented for `dyn ToBar` = note: the left-hand-side of an assignment must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/dst/dst-bad-deep-2.stderr b/src/test/ui/dst/dst-bad-deep-2.stderr index d9d6ca3292..b228508141 100644 --- a/src/test/ui/dst/dst-bad-deep-2.stderr +++ b/src/test/ui/dst/dst-bad-deep-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati LL | let h: &(([isize],),) = &(*g,); | ^^^^^ doesn't have a size known at compile-time | - = help: within `(([isize],),)`, the trait `std::marker::Sized` is not implemented for `[isize]` + = help: within `(([isize],),)`, the trait `Sized` is not implemented for `[isize]` = note: required because it appears within the type `([isize],)` = note: required because it appears within the type `(([isize],),)` = note: tuples must have a statically known size to be initialized diff --git a/src/test/ui/dst/dst-bad-deep.stderr b/src/test/ui/dst/dst-bad-deep.stderr index 1304f04f82..ea6b239047 100644 --- a/src/test/ui/dst/dst-bad-deep.stderr +++ b/src/test/ui/dst/dst-bad-deep.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati LL | let h: &Fat> = &Fat { ptr: *g }; | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Fat>`, the trait `std::marker::Sized` is not implemented for `[isize]` + = help: within `Fat>`, the trait `Sized` is not implemented for `[isize]` = note: required because it appears within the type `Fat<[isize]>` = note: required because it appears within the type `Fat>` = note: structs must have a statically known size to be initialized diff --git a/src/test/ui/dst/dst-index.stderr b/src/test/ui/dst/dst-index.stderr index 6cdb0e76e9..6bcd70cbaa 100644 --- a/src/test/ui/dst/dst-index.stderr +++ b/src/test/ui/dst/dst-index.stderr @@ -4,7 +4,7 @@ error[E0161]: cannot move a value of type str: the size of str cannot be statica LL | S[0]; | ^^^^ -error[E0161]: cannot move a value of type dyn std::fmt::Debug: the size of dyn std::fmt::Debug cannot be statically determined +error[E0161]: cannot move a value of type dyn Debug: the size of dyn Debug cannot be statically determined --> $DIR/dst-index.rs:34:5 | LL | T[0]; @@ -20,7 +20,7 @@ error[E0507]: cannot move out of index of `T` --> $DIR/dst-index.rs:34:5 | LL | T[0]; - | ^^^^ move occurs because value has type `dyn std::fmt::Debug`, which does not implement the `Copy` trait + | ^^^^ move occurs because value has type `dyn Debug`, which does not implement the `Copy` trait error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr index da8ead885c..49940112a9 100644 --- a/src/test/ui/dst/dst-object-from-unsized-type.stderr +++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/dst-object-from-unsized-type.rs:8:23 | LL | fn test1(t: &T) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let u: &dyn Foo = t; | ^ doesn't have a size known at compile-time | @@ -12,7 +12,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/dst-object-from-unsized-type.rs:13:23 | LL | fn test2(t: &T) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let v: &dyn Foo = t as &dyn Foo; | ^ doesn't have a size known at compile-time | @@ -24,7 +24,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | let _: &[&dyn Foo] = &["hi"]; | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -33,7 +33,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | let _: &dyn Foo = x as &dyn Foo; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: required for the cast to the object type `dyn Foo` error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-sized-trait-param.stderr b/src/test/ui/dst/dst-sized-trait-param.stderr index 7e90e9ce17..481c01a75e 100644 --- a/src/test/ui/dst/dst-sized-trait-param.stderr +++ b/src/test/ui/dst/dst-sized-trait-param.stderr @@ -7,7 +7,7 @@ LL | LL | impl Foo<[isize]> for usize { } | ^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[isize]` + = help: the trait `Sized` is not implemented for `[isize]` help: consider relaxing the implicit `Sized` restriction | LL | trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized @@ -22,7 +22,7 @@ LL | trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized LL | impl Foo for [usize] { } | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[usize]` + = help: the trait `Sized` is not implemented for `[usize]` error: aborting due to 2 previous errors diff --git a/src/test/ui/dyn-trait-compatibility.rs b/src/test/ui/dyn-trait-compatibility.rs index 2a1cea6c34..d2b02cc2af 100644 --- a/src/test/ui/dyn-trait-compatibility.rs +++ b/src/test/ui/dyn-trait-compatibility.rs @@ -1,7 +1,7 @@ type A0 = dyn; //~^ ERROR cannot find type `dyn` in this scope type A1 = dyn::dyn; -//~^ ERROR use of undeclared type or module `dyn` +//~^ ERROR use of undeclared crate or module `dyn` type A2 = dyn; //~^ ERROR cannot find type `dyn` in this scope //~| ERROR cannot find type `dyn` in this scope @@ -9,6 +9,6 @@ type A2 = dyn; type A3 = dyn<::dyn>; //~^ ERROR cannot find type `dyn` in this scope //~| ERROR cannot find type `dyn` in this scope -//~| ERROR use of undeclared type or module `dyn` +//~| ERROR use of undeclared crate or module `dyn` fn main() {} diff --git a/src/test/ui/dyn-trait-compatibility.stderr b/src/test/ui/dyn-trait-compatibility.stderr index 8fe8ceb4d0..9218ae9d5d 100644 --- a/src/test/ui/dyn-trait-compatibility.stderr +++ b/src/test/ui/dyn-trait-compatibility.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `dyn` +error[E0433]: failed to resolve: use of undeclared crate or module `dyn` --> $DIR/dyn-trait-compatibility.rs:3:11 | LL | type A1 = dyn::dyn; - | ^^^ use of undeclared type or module `dyn` + | ^^^ use of undeclared crate or module `dyn` -error[E0433]: failed to resolve: use of undeclared type or module `dyn` +error[E0433]: failed to resolve: use of undeclared crate or module `dyn` --> $DIR/dyn-trait-compatibility.rs:9:23 | LL | type A3 = dyn<::dyn>; - | ^^^ use of undeclared type or module `dyn` + | ^^^ use of undeclared crate or module `dyn` error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:1:11 diff --git a/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs b/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs new file mode 100644 index 0000000000..26b923f431 --- /dev/null +++ b/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs @@ -0,0 +1,26 @@ +// run-pass + +#![feature(unsized_tuple_coercion)] + +// Ensure that unsizable fields that might be accessed don't get reordered + +fn nonzero_size() { + let sized: (u8, [u32; 2]) = (123, [456, 789]); + let unsize: &(u8, [u32]) = &sized; + assert_eq!(unsize.0, 123); + assert_eq!(unsize.1.len(), 2); + assert_eq!(unsize.1[0], 456); + assert_eq!(unsize.1[1], 789); +} + +fn zst() { + let sized: (u8, [u32; 0]) = (123, []); + let unsize: &(u8, [u32]) = &sized; + assert_eq!(unsize.0, 123); + assert_eq!(unsize.1.len(), 0); +} + +pub fn main() { + nonzero_size(); + zst(); +} diff --git a/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs b/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs new file mode 100644 index 0000000000..b0cefe7703 --- /dev/null +++ b/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs @@ -0,0 +1,22 @@ +// run-pass + +#![feature(unsized_tuple_coercion)] + +// Check that we do not change the offsets of ZST fields when unsizing + +fn scalar_layout() { + let sized: &(u8, [(); 13]) = &(123, [(); 13]); + let unsize: &(u8, [()]) = sized; + assert_eq!(sized.1.as_ptr(), unsize.1.as_ptr()); +} + +fn scalarpair_layout() { + let sized: &(u8, u16, [(); 13]) = &(123, 456, [(); 13]); + let unsize: &(u8, u16, [()]) = sized; + assert_eq!(sized.2.as_ptr(), unsize.2.as_ptr()); +} + +pub fn main() { + scalar_layout(); + scalarpair_layout(); +} diff --git a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr index 52e58aa4c6..0dc5432d28 100644 --- a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr +++ b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr @@ -12,7 +12,7 @@ error[E0392]: parameter `T` is never used LL | enum MyWeirdOption { | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs index 5a528379b0..cdc1db4c0b 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs @@ -1,5 +1,4 @@ // run-pass - #![feature(arbitrary_enum_discriminant, core_intrinsics)] extern crate core; @@ -9,6 +8,8 @@ use core::intrinsics::discriminant_value; enum MyWeirdOption { None = 0, Some(T) = core::mem::size_of::<*mut T>(), + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out } fn main() { diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr new file mode 100644 index 0000000000..906927e705 --- /dev/null +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/issue-70453-polymorphic-ctfe.rs:10:15 + | +LL | Some(T) = core::mem::size_of::<*mut T>(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + +warning: 1 warning emitted + diff --git a/src/test/ui/error-codes/E0004-2.stderr b/src/test/ui/error-codes/E0004-2.stderr index bb155aaf4b..7b3deb1579 100644 --- a/src/test/ui/error-codes/E0004-2.stderr +++ b/src/test/ui/error-codes/E0004-2.stderr @@ -13,7 +13,7 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), | ---- not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `std::option::Option` + = note: the matched value is of type `Option` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0005.stderr b/src/test/ui/error-codes/E0005.stderr index e15189413b..b9f2702e88 100644 --- a/src/test/ui/error-codes/E0005.stderr +++ b/src/test/ui/error-codes/E0005.stderr @@ -11,7 +11,7 @@ LL | None, | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html - = note: the matched value is of type `std::option::Option` + = note: the matched value is of type `Option` help: you might want to use `if let` to ignore the variant that isn't matched | LL | if let Some(y) = x { /* */ } diff --git a/src/test/ui/error-codes/E0007.stderr b/src/test/ui/error-codes/E0007.stderr index 31af917172..89c1051619 100644 --- a/src/test/ui/error-codes/E0007.stderr +++ b/src/test/ui/error-codes/E0007.stderr @@ -8,7 +8,7 @@ error[E0382]: use of moved value --> $DIR/E0007.rs:6:26 | LL | let x = Some("s".to_string()); - | - move occurs because `x` has type `std::option::Option`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Option`, which does not implement the `Copy` trait LL | match x { LL | op_string @ Some(s) => {}, | -----------------^- diff --git a/src/test/ui/error-codes/E0010-teach.rs b/src/test/ui/error-codes/E0010-teach.rs index da51035ab5..fc5dffb37c 100644 --- a/src/test/ui/error-codes/E0010-teach.rs +++ b/src/test/ui/error-codes/E0010-teach.rs @@ -4,6 +4,5 @@ #![allow(warnings)] const CON : Box = box 0; //~ ERROR E0010 -//~^ ERROR constant contains unimplemented expression type fn main() {} diff --git a/src/test/ui/error-codes/E0010-teach.stderr b/src/test/ui/error-codes/E0010-teach.stderr index c15ab5c655..33de9fd685 100644 --- a/src/test/ui/error-codes/E0010-teach.stderr +++ b/src/test/ui/error-codes/E0010-teach.stderr @@ -6,17 +6,6 @@ LL | const CON : Box = box 0; | = 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. -error[E0019]: constant contains unimplemented expression type - --> $DIR/E0010-teach.rs:6:28 - | -LL | const CON : Box = box 0; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: A function call isn't allowed in the const's initialization expression because the expression's value must be known at compile-time. - = note: Remember: you can't use a function call inside a const's initialization expression! However, you can use it anywhere else. - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0010, E0019. -For more information about an error, try `rustc --explain E0010`. +For more information about this error, try `rustc --explain E0010`. diff --git a/src/test/ui/error-codes/E0010.rs b/src/test/ui/error-codes/E0010.rs index 3398e2c28b..e62997640f 100644 --- a/src/test/ui/error-codes/E0010.rs +++ b/src/test/ui/error-codes/E0010.rs @@ -2,6 +2,5 @@ #![allow(warnings)] const CON : Box = box 0; //~ ERROR E0010 -//~^ ERROR constant contains unimplemented expression type fn main() {} diff --git a/src/test/ui/error-codes/E0010.stderr b/src/test/ui/error-codes/E0010.stderr index f49fb9c463..0042333b98 100644 --- a/src/test/ui/error-codes/E0010.stderr +++ b/src/test/ui/error-codes/E0010.stderr @@ -4,15 +4,6 @@ error[E0010]: allocations are not allowed in constants LL | const CON : Box = box 0; | ^^^^^ allocation not allowed in constants -error[E0019]: constant contains unimplemented expression type - --> $DIR/E0010.rs:4:28 - | -LL | const CON : Box = box 0; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0010, E0019. -For more information about an error, try `rustc --explain E0010`. +For more information about this error, try `rustc --explain E0010`. diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index 818dec1207..262f7bc72c 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -3,9 +3,11 @@ const C: i32 = 2; static mut M: i32 = 3; const CR: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764 - //~| ERROR E0019 //~| ERROR cannot borrow + static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index c1d96de1dc..ea591587e6 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -1,42 +1,63 @@ -error[E0764]: mutable references are not allowed in constants +warning: taking a mutable reference to a `const` item --> $DIR/E0017.rs:5:30 | LL | const CR: &'static mut i32 = &mut C; - | ^^^^^^ `&mut` is only allowed in `const fn` - -error[E0019]: static contains unimplemented expression type - --> $DIR/E0017.rs:6:39 + | ^^^^^^ | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0017.rs:2:1 | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + +error[E0764]: mutable references are not allowed in constants + --> $DIR/E0017.rs:5:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable +warning: taking a mutable reference to a `const` item + --> $DIR/E0017.rs:10:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0017.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:9:38 + --> $DIR/E0017.rs:10:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:10:52 + --> $DIR/E0017.rs:12:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0019, E0596, E0764. -For more information about an error, try `rustc --explain E0019`. +Some errors have detailed explanations: E0596, E0764. +For more information about an error, try `rustc --explain E0596`. diff --git a/src/test/ui/error-codes/E0027-teach.rs b/src/test/ui/error-codes/E0027-teach.rs deleted file mode 100644 index 11402f0148..0000000000 --- a/src/test/ui/error-codes/E0027-teach.rs +++ /dev/null @@ -1,15 +0,0 @@ -// compile-flags: -Z teach - -struct Dog { - name: String, - age: u32, -} - -fn main() { - let d = Dog { name: "Rusty".to_string(), age: 8 }; - - match d { - Dog { age: x } => {} - //~^ ERROR pattern does not mention field `name` - } -} diff --git a/src/test/ui/error-codes/E0027-teach.stderr b/src/test/ui/error-codes/E0027-teach.stderr deleted file mode 100644 index aa4cb9d4d1..0000000000 --- a/src/test/ui/error-codes/E0027-teach.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0027]: pattern does not mention field `name` - --> $DIR/E0027-teach.rs:12:9 - | -LL | Dog { age: x } => {} - | ^^^^^^^^^^^^^^ missing field `name` - | - = note: This error indicates that a pattern for a struct fails to specify a sub-pattern for every one of the struct's fields. Ensure that each field from the struct's definition is mentioned in the pattern, or use `..` to ignore unwanted fields. - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/error-codes/E0027.rs b/src/test/ui/error-codes/E0027.rs index b8c6a2b7fc..8d08e17893 100644 --- a/src/test/ui/error-codes/E0027.rs +++ b/src/test/ui/error-codes/E0027.rs @@ -7,7 +7,9 @@ fn main() { let d = Dog { name: "Rusty".to_string(), age: 8 }; match d { - Dog { age: x } => {} - //~^ ERROR pattern does not mention field `name` + Dog { age: x } => {} //~ ERROR pattern does not mention field `name` + } + match d { + Dog {} => {} //~ ERROR pattern does not mention fields `name`, `age` } } diff --git a/src/test/ui/error-codes/E0027.stderr b/src/test/ui/error-codes/E0027.stderr index 4f17bba647..c09f1ff1f2 100644 --- a/src/test/ui/error-codes/E0027.stderr +++ b/src/test/ui/error-codes/E0027.stderr @@ -3,7 +3,31 @@ error[E0027]: pattern does not mention field `name` | LL | Dog { age: x } => {} | ^^^^^^^^^^^^^^ missing field `name` + | +help: include the missing field in the pattern + | +LL | Dog { age: x, name } => {} + | ^^^^^^ +help: if you don't care about this missing field, you can explicitely ignore it + | +LL | Dog { age: x, .. } => {} + | ^^^^ + +error[E0027]: pattern does not mention fields `name`, `age` + --> $DIR/E0027.rs:13:9 + | +LL | Dog {} => {} + | ^^^^^^ missing fields `name`, `age` + | +help: include the missing fields in the pattern + | +LL | Dog { name, age } => {} + | ^^^^^^^^^^^^^ +help: if you don't care about these missing fields, you can explicitely ignore them + | +LL | Dog { .. } => {} + | ^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/error-codes/E0029-teach.rs b/src/test/ui/error-codes/E0029-teach.rs index 83058d397c..3ff8cb348e 100644 --- a/src/test/ui/error-codes/E0029-teach.rs +++ b/src/test/ui/error-codes/E0029-teach.rs @@ -5,7 +5,7 @@ fn main() { match s { "hello" ..= "world" => {} - //~^ ERROR only char and numeric types are allowed in range patterns + //~^ ERROR only `char` and numeric types are allowed in range patterns _ => {} } } diff --git a/src/test/ui/error-codes/E0029-teach.stderr b/src/test/ui/error-codes/E0029-teach.stderr index ec146ca86f..b89b2e7d11 100644 --- a/src/test/ui/error-codes/E0029-teach.stderr +++ b/src/test/ui/error-codes/E0029-teach.stderr @@ -1,4 +1,4 @@ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/E0029-teach.rs:7:9 | LL | "hello" ..= "world" => {} diff --git a/src/test/ui/error-codes/E0029.rs b/src/test/ui/error-codes/E0029.rs index fe0d851832..d9b53e113c 100644 --- a/src/test/ui/error-codes/E0029.rs +++ b/src/test/ui/error-codes/E0029.rs @@ -3,7 +3,7 @@ fn main() { match s { "hello" ..= "world" => {} - //~^ ERROR only char and numeric types are allowed in range patterns + //~^ ERROR only `char` and numeric types are allowed in range patterns _ => {} } } diff --git a/src/test/ui/error-codes/E0029.stderr b/src/test/ui/error-codes/E0029.stderr index e54722ae7b..f7250b39d3 100644 --- a/src/test/ui/error-codes/E0029.stderr +++ b/src/test/ui/error-codes/E0029.stderr @@ -1,4 +1,4 @@ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/E0029.rs:5:9 | LL | "hello" ..= "world" => {} diff --git a/src/test/ui/error-codes/E0067.stderr b/src/test/ui/error-codes/E0067.stderr index fad8270fd5..ec0358cb7d 100644 --- a/src/test/ui/error-codes/E0067.stderr +++ b/src/test/ui/error-codes/E0067.stderr @@ -1,10 +1,10 @@ -error[E0368]: binary assignment operation `+=` cannot be applied to type `std::collections::LinkedList<_>` +error[E0368]: binary assignment operation `+=` cannot be applied to type `LinkedList<_>` --> $DIR/E0067.rs:4:5 | LL | LinkedList::new() += 1; | -----------------^^^^^ | | - | cannot use `+=` on type `std::collections::LinkedList<_>` + | cannot use `+=` on type `LinkedList<_>` error[E0067]: invalid left-hand side of assignment --> $DIR/E0067.rs:4:23 diff --git a/src/test/ui/error-codes/E0070.stderr b/src/test/ui/error-codes/E0070.stderr index d809bb18de..e24d498e35 100644 --- a/src/test/ui/error-codes/E0070.stderr +++ b/src/test/ui/error-codes/E0070.stderr @@ -14,12 +14,6 @@ LL | 1 = 3; | | | cannot assign to this expression -error[E0308]: mismatched types - --> $DIR/E0070.rs:8:25 - | -LL | some_other_func() = 4; - | ^ expected `()`, found integer - error[E0070]: invalid left-hand side of assignment --> $DIR/E0070.rs:8:23 | @@ -28,6 +22,12 @@ LL | some_other_func() = 4; | | | cannot assign to this expression +error[E0308]: mismatched types + --> $DIR/E0070.rs:8:25 + | +LL | some_other_func() = 4; + | ^ expected `()`, found integer + error: aborting due to 4 previous errors Some errors have detailed explanations: E0070, E0308. diff --git a/src/test/ui/error-codes/E0080.rs b/src/test/ui/error-codes/E0080.rs index b31cf2ec44..ea3264b61b 100644 --- a/src/test/ui/error-codes/E0080.rs +++ b/src/test/ui/error-codes/E0080.rs @@ -1,6 +1,6 @@ enum Enum { X = (1 << 500), //~ ERROR E0080 - //~| attempt to shift left by 500_i32 which would overflow + //~| attempt to shift left by `500_i32`, which would overflow Y = (1 / 0) //~ ERROR E0080 } diff --git a/src/test/ui/error-codes/E0080.stderr b/src/test/ui/error-codes/E0080.stderr index 3acd15ff6b..60ed9a4358 100644 --- a/src/test/ui/error-codes/E0080.stderr +++ b/src/test/ui/error-codes/E0080.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/E0080.rs:2:9 | LL | X = (1 << 500), - | ^^^^^^^^^^ attempt to shift left by 500_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `500_i32`, which would overflow error[E0080]: evaluation of constant value failed --> $DIR/E0080.rs:4:9 | LL | Y = (1 / 0) - | ^^^^^^^ attempt to divide 1_isize by zero + | ^^^^^^^ attempt to divide `1_isize` by zero error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0118-2.rs b/src/test/ui/error-codes/E0118-2.rs new file mode 100644 index 0000000000..fe04190162 --- /dev/null +++ b/src/test/ui/error-codes/E0118-2.rs @@ -0,0 +1,8 @@ +struct Foo; + +impl &mut Foo { + //~^ ERROR E0118 + fn bar(self) {} +} + +fn main() {} diff --git a/src/test/ui/error-codes/E0118-2.stderr b/src/test/ui/error-codes/E0118-2.stderr new file mode 100644 index 0000000000..2a1fe23111 --- /dev/null +++ b/src/test/ui/error-codes/E0118-2.stderr @@ -0,0 +1,12 @@ +error[E0118]: no nominal type found for inherent implementation + --> $DIR/E0118-2.rs:3:6 + | +LL | impl &mut Foo { + | ^^^^^^^^ impl requires a nominal type + | + = note: either implement a trait on it or create a newtype to wrap it instead + = note: you could also try moving the reference to uses of `Foo` (such as `self`) within the implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0118`. diff --git a/src/test/ui/error-codes/E0118.stderr b/src/test/ui/error-codes/E0118.stderr index b0afaeb5c1..2693a93213 100644 --- a/src/test/ui/error-codes/E0118.stderr +++ b/src/test/ui/error-codes/E0118.stderr @@ -1,8 +1,8 @@ -error[E0118]: no base type found for inherent implementation +error[E0118]: no nominal type found for inherent implementation --> $DIR/E0118.rs:1:6 | LL | impl (u8, u8) { - | ^^^^^^^^ impl requires a base type + | ^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead diff --git a/src/test/ui/error-codes/E0221.stderr b/src/test/ui/error-codes/E0221.stderr index 0b4819143c..085f80f44f 100644 --- a/src/test/ui/error-codes/E0221.stderr +++ b/src/test/ui/error-codes/E0221.stderr @@ -31,7 +31,7 @@ LL | let _: Self::Err; | ambiguous associated type `Err` | help: use fully qualified syntax to disambiguate: `::Err` | - = note: associated type `Self` could derive from `std::str::FromStr` + = note: associated type `Self` could derive from `FromStr` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0276.stderr b/src/test/ui/error-codes/E0276.stderr index a8b016ebf5..8857e1646e 100644 --- a/src/test/ui/error-codes/E0276.stderr +++ b/src/test/ui/error-codes/E0276.stderr @@ -5,7 +5,7 @@ LL | fn foo(x: T); | ---------------- definition of `foo` from trait ... LL | fn foo(x: T) where T: Copy {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::marker::Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Copy` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0277-2.stderr b/src/test/ui/error-codes/E0277-2.stderr index f5ba46ca01..a0ab1641ca 100644 --- a/src/test/ui/error-codes/E0277-2.stderr +++ b/src/test/ui/error-codes/E0277-2.stderr @@ -7,7 +7,7 @@ LL | fn is_send() { } LL | is_send::(); | ^^^^^^^^^^^^^^ `*const u8` cannot be sent between threads safely | - = help: within `Foo`, the trait `std::marker::Send` is not implemented for `*const u8` + = help: within `Foo`, the trait `Send` is not implemented for `*const u8` = note: required because it appears within the type `Baz` = note: required because it appears within the type `Bar` = note: required because it appears within the type `Foo` diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index 203fc18915..c2e15007cf 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn f(p: Path) { } | ^ doesn't have a size known at compile-time | - = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: required because it appears within the type `std::path::Path` + = help: within `Path`, the trait `Sized` is not implemented for `[u8]` + = note: required because it appears within the type `Path` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/error-codes/E0297.stderr b/src/test/ui/error-codes/E0297.stderr index 9134e90557..ec3452b1dd 100644 --- a/src/test/ui/error-codes/E0297.stderr +++ b/src/test/ui/error-codes/E0297.stderr @@ -9,7 +9,7 @@ LL | for Some(x) in xs {} LL | None, | ---- not covered | - = note: the matched value is of type `std::option::Option` + = note: the matched value is of type `Option` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0308-2.stderr b/src/test/ui/error-codes/E0308-2.stderr index e7c5e4b424..47fea5a23a 100644 --- a/src/test/ui/error-codes/E0308-2.stderr +++ b/src/test/ui/error-codes/E0308-2.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | impl Eq for &dyn DynEq {} | ^^ lifetime mismatch | - = note: expected trait `std::cmp::PartialEq` - found trait `std::cmp::PartialEq` + = note: expected trait `PartialEq` + found trait `PartialEq` note: the lifetime `'_` as defined on the impl at 9:13... --> $DIR/E0308-2.rs:9:13 | diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs index 13131017c2..bb0c4979b9 100644 --- a/src/test/ui/error-codes/E0388.rs +++ b/src/test/ui/error-codes/E0388.rs @@ -2,9 +2,11 @@ static X: i32 = 1; const C: i32 = 2; const CR: &'static mut i32 = &mut C; //~ ERROR E0764 -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0019 - //~| ERROR cannot borrow + //~| WARN taking a mutable +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow //~| ERROR E0764 + static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index f09100bac4..73e0b139cd 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -1,36 +1,57 @@ -error[E0764]: mutable references are not allowed in constants +warning: taking a mutable reference to a `const` item --> $DIR/E0388.rs:4:30 | LL | const CR: &'static mut i32 = &mut C; - | ^^^^^^ `&mut` is only allowed in `const fn` - -error[E0019]: static contains unimplemented expression type - --> $DIR/E0388.rs:5:39 + | ^^^^^^ | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0388.rs:2:1 | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + +error[E0764]: mutable references are not allowed in constants + --> $DIR/E0388.rs:4:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0764]: mutable references are not allowed in statics - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable +warning: taking a mutable reference to a `const` item + --> $DIR/E0388.rs:9:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0388.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in statics - --> $DIR/E0388.rs:8:38 + --> $DIR/E0388.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0019, E0596, E0764. -For more information about an error, try `rustc --explain E0019`. +Some errors have detailed explanations: E0596, E0764. +For more information about an error, try `rustc --explain E0596`. diff --git a/src/test/ui/error-codes/E0392.stderr b/src/test/ui/error-codes/E0392.stderr index 7b0bfe3727..860bf68f01 100644 --- a/src/test/ui/error-codes/E0392.stderr +++ b/src/test/ui/error-codes/E0392.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `T` is never used LL | enum Foo { Bar } | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0433.stderr b/src/test/ui/error-codes/E0433.stderr index d9555e1fcf..265d8885c8 100644 --- a/src/test/ui/error-codes/E0433.stderr +++ b/src/test/ui/error-codes/E0433.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `NonExistingMap` +error[E0433]: failed to resolve: use of undeclared type `NonExistingMap` --> $DIR/E0433.rs:2:15 | LL | let map = NonExistingMap::new(); - | ^^^^^^^^^^^^^^ use of undeclared type or module `NonExistingMap` + | ^^^^^^^^^^^^^^ use of undeclared type `NonExistingMap` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0446.stderr b/src/test/ui/error-codes/E0446.stderr index bb00926097..c538bae2e5 100644 --- a/src/test/ui/error-codes/E0446.stderr +++ b/src/test/ui/error-codes/E0446.stderr @@ -1,8 +1,8 @@ -error[E0446]: private type `foo::Bar` in public interface +error[E0446]: private type `Bar` in public interface --> $DIR/E0446.rs:4:5 | LL | struct Bar(u32); - | - `foo::Bar` declared as private + | - `Bar` declared as private LL | LL | pub fn bar() -> Bar { | ^^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/error-codes/E0451.stderr b/src/test/ui/error-codes/E0451.stderr index bb92c23e0f..419cf117ef 100644 --- a/src/test/ui/error-codes/E0451.stderr +++ b/src/test/ui/error-codes/E0451.stderr @@ -1,10 +1,10 @@ -error[E0451]: field `b` of struct `bar::Foo` is private +error[E0451]: field `b` of struct `Foo` is private --> $DIR/E0451.rs:14:21 | LL | let bar::Foo{a, b} = foo; | ^ private field -error[E0451]: field `b` of struct `bar::Foo` is private +error[E0451]: field `b` of struct `Foo` is private --> $DIR/E0451.rs:18:29 | LL | let f = bar::Foo{ a: 0, b: 0 }; diff --git a/src/test/ui/error-codes/E0507.stderr b/src/test/ui/error-codes/E0507.stderr index 170b883191..cd5e467944 100644 --- a/src/test/ui/error-codes/E0507.stderr +++ b/src/test/ui/error-codes/E0507.stderr @@ -1,4 +1,4 @@ -error[E0507]: cannot move out of dereference of `std::cell::Ref<'_, TheDarkKnight>` +error[E0507]: cannot move out of dereference of `Ref<'_, TheDarkKnight>` --> $DIR/E0507.rs:12:5 | LL | x.borrow().nothing_is_true(); diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr index f23d2008e0..43269c095d 100644 --- a/src/test/ui/error-codes/E0605.stderr +++ b/src/test/ui/error-codes/E0605.stderr @@ -1,4 +1,4 @@ -error[E0605]: non-primitive cast: `u8` as `std::vec::Vec` +error[E0605]: non-primitive cast: `u8` as `Vec` --> $DIR/E0605.rs:3:5 | LL | x as Vec; diff --git a/src/test/ui/error-codes/E0616.stderr b/src/test/ui/error-codes/E0616.stderr index 422bf687e7..da349ed2fd 100644 --- a/src/test/ui/error-codes/E0616.stderr +++ b/src/test/ui/error-codes/E0616.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `x` of struct `a::Foo` is private +error[E0616]: field `x` of struct `Foo` is private --> $DIR/E0616.rs:13:7 | LL | f.x; diff --git a/src/test/ui/error-codes/E0719.stderr b/src/test/ui/error-codes/E0719.stderr index 0e4bbf083b..b342d63433 100644 --- a/src/test/ui/error-codes/E0719.stderr +++ b/src/test/ui/error-codes/E0719.stderr @@ -1,4 +1,4 @@ -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/E0719.rs:1:33 | LL | trait Foo: Iterator {} @@ -6,7 +6,7 @@ LL | trait Foo: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/E0719.rs:6:42 | LL | fn test() -> Box> { diff --git a/src/test/ui/error-codes/e0119/complex-impl.stderr b/src/test/ui/error-codes/e0119/complex-impl.stderr index 2cc09e8b14..d617d81292 100644 --- a/src/test/ui/error-codes/e0119/complex-impl.stderr +++ b/src/test/ui/error-codes/e0119/complex-impl.stderr @@ -5,8 +5,8 @@ LL | impl External for (Q, R) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `complex_impl_support`: - - impl<'a, 'b, 'c, T, U, V, W> complex_impl_support::External for (T, complex_impl_support::M<'a, 'b, 'c, std::boxed::Box, V, W>) - where >::Output == V, ::Item == T, 'b: 'a, T: 'a, U: std::ops::FnOnce<(T,)>, U: 'static, V: std::iter::Iterator, V: std::clone::Clone, W: std::ops::Add, ::Output: std::marker::Copy; + - impl<'a, 'b, 'c, T, U, V, W> External for (T, M<'a, 'b, 'c, Box, V, W>) + where >::Output == V, ::Item == T, 'b: 'a, T: 'a, U: FnOnce<(T,)>, U: 'static, V: Iterator, V: Clone, W: Add, ::Output: Copy; error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/complex-impl.rs:9:1 diff --git a/src/test/ui/error-codes/e0119/conflict-with-std.stderr b/src/test/ui/error-codes/e0119/conflict-with-std.stderr index 3e0c71e907..4b6b4430f3 100644 --- a/src/test/ui/error-codes/e0119/conflict-with-std.stderr +++ b/src/test/ui/error-codes/e0119/conflict-with-std.stderr @@ -5,7 +5,7 @@ LL | impl AsRef for Box { | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `alloc`: - - impl std::convert::AsRef for std::boxed::Box + - impl AsRef for Box where T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: @@ -15,7 +15,7 @@ LL | impl From for S { | ^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::convert::From for T; + - impl From for T; error[E0119]: conflicting implementations of trait `std::convert::TryFrom` for type `X`: --> $DIR/conflict-with-std.rs:19:1 @@ -24,8 +24,8 @@ LL | impl TryFrom for X { | ^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::convert::TryFrom for T - where U: std::convert::Into; + - impl TryFrom for T + where U: Into; error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/e0119/issue-23563.stderr b/src/test/ui/error-codes/e0119/issue-23563.stderr index 8011689880..912a80fec7 100644 --- a/src/test/ui/error-codes/e0119/issue-23563.stderr +++ b/src/test/ui/error-codes/e0119/issue-23563.stderr @@ -5,8 +5,8 @@ LL | impl<'a, T> LolFrom<&'a [T]> for LocalType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `issue_23563_a`: - - impl a::LolFrom for U - where T: a::LolInto; + - impl LolFrom for U + where T: LolInto; error: aborting due to previous error diff --git a/src/test/ui/error-codes/e0119/issue-27403.stderr b/src/test/ui/error-codes/e0119/issue-27403.stderr index cba10432a9..ea74c9b21b 100644 --- a/src/test/ui/error-codes/e0119/issue-27403.stderr +++ b/src/test/ui/error-codes/e0119/issue-27403.stderr @@ -5,8 +5,8 @@ LL | impl Into for GenX { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::convert::Into for T - where U: std::convert::From; + - impl Into for T + where U: From; error: aborting due to previous error diff --git a/src/test/ui/error-codes/e0119/issue-28981.stderr b/src/test/ui/error-codes/e0119/issue-28981.stderr index 2a78cc8b2d..c22cc65c87 100644 --- a/src/test/ui/error-codes/e0119/issue-28981.stderr +++ b/src/test/ui/error-codes/e0119/issue-28981.stderr @@ -5,7 +5,7 @@ LL | impl Deref for Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::ops::Deref for &T + - impl Deref for &T where T: ?Sized; error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g., `MyStruct`) diff --git a/src/test/ui/error-codes/e0119/so-37347311.stderr b/src/test/ui/error-codes/e0119/so-37347311.stderr index f2166de71f..a9fbd0fee4 100644 --- a/src/test/ui/error-codes/e0119/so-37347311.stderr +++ b/src/test/ui/error-codes/e0119/so-37347311.stderr @@ -5,7 +5,7 @@ LL | impl From for MyError { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::convert::From for T; + - impl From for T; error: aborting due to previous error diff --git a/src/test/ui/error-codes/ex-E0611.rs b/src/test/ui/error-codes/ex-E0611.rs index 8460341c44..f18a3619f3 100644 --- a/src/test/ui/error-codes/ex-E0611.rs +++ b/src/test/ui/error-codes/ex-E0611.rs @@ -8,5 +8,5 @@ mod a { fn main() { let y = a::Foo::new(); - y.0; //~ ERROR field `0` of struct `a::Foo` is private + y.0; //~ ERROR field `0` of struct `Foo` is private } diff --git a/src/test/ui/error-codes/ex-E0611.stderr b/src/test/ui/error-codes/ex-E0611.stderr index 2d22bb3951..1da7b33be9 100644 --- a/src/test/ui/error-codes/ex-E0611.stderr +++ b/src/test/ui/error-codes/ex-E0611.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `0` of struct `a::Foo` is private +error[E0616]: field `0` of struct `Foo` is private --> $DIR/ex-E0611.rs:11:6 | LL | y.0; diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 905195d4ad..89a9d965de 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -44,7 +44,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` LL | 0u32 as char; | ^^^^^^^^^^^^ invalid cast -error[E0605]: non-primitive cast: `u8` as `std::vec::Vec` +error[E0605]: non-primitive cast: `u8` as `Vec` --> $DIR/error-festival.rs:29:5 | LL | x as Vec; diff --git a/src/test/ui/error-should-say-copy-not-pod.rs b/src/test/ui/error-should-say-copy-not-pod.rs index be4e451ceb..40c4730ef6 100644 --- a/src/test/ui/error-should-say-copy-not-pod.rs +++ b/src/test/ui/error-should-say-copy-not-pod.rs @@ -3,5 +3,5 @@ fn check_bound(_: T) {} fn main() { - check_bound("nocopy".to_string()); //~ ERROR : std::marker::Copy` is not satisfied + check_bound("nocopy".to_string()); //~ ERROR : Copy` is not satisfied } diff --git a/src/test/ui/error-should-say-copy-not-pod.stderr b/src/test/ui/error-should-say-copy-not-pod.stderr index 96ffa6f3e0..346e882485 100644 --- a/src/test/ui/error-should-say-copy-not-pod.stderr +++ b/src/test/ui/error-should-say-copy-not-pod.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/error-should-say-copy-not-pod.rs:6:17 | LL | fn check_bound(_: T) {} | ---- required by this bound in `check_bound` ... LL | check_bound("nocopy".to_string()); - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` error: aborting due to previous error diff --git a/src/test/ui/estr-subtyping.stderr b/src/test/ui/estr-subtyping.stderr index e5dbab6441..268ec63a80 100644 --- a/src/test/ui/estr-subtyping.stderr +++ b/src/test/ui/estr-subtyping.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | wants_uniq(x); | ^ | | - | expected struct `std::string::String`, found `&str` + | expected struct `String`, found `&str` | help: try using a conversion method: `x.to_string()` error: aborting due to previous error diff --git a/src/test/ui/eval-enum.rs b/src/test/ui/eval-enum.rs index 4ef06c7806..551f10e66e 100644 --- a/src/test/ui/eval-enum.rs +++ b/src/test/ui/eval-enum.rs @@ -1,9 +1,9 @@ enum Test { DivZero = 1/0, - //~^ attempt to divide 1_isize by zero + //~^ attempt to divide `1_isize` by zero //~| ERROR evaluation of constant value failed RemZero = 1%0, - //~^ attempt to calculate the remainder of 1_isize with a divisor of zero + //~^ attempt to calculate the remainder of `1_isize` with a divisor of zero //~| ERROR evaluation of constant value failed } diff --git a/src/test/ui/eval-enum.stderr b/src/test/ui/eval-enum.stderr index dd89a2d7c3..fb4d903489 100644 --- a/src/test/ui/eval-enum.stderr +++ b/src/test/ui/eval-enum.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/eval-enum.rs:2:15 | LL | DivZero = 1/0, - | ^^^ attempt to divide 1_isize by zero + | ^^^ attempt to divide `1_isize` by zero error[E0080]: evaluation of constant value failed --> $DIR/eval-enum.rs:5:15 | LL | RemZero = 1%0, - | ^^^ attempt to calculate the remainder of 1_isize with a divisor of zero + | ^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: aborting due to 2 previous errors diff --git a/src/test/ui/explore-issue-38412.stderr b/src/test/ui/explore-issue-38412.stderr index 1855c0b143..55f43840b9 100644 --- a/src/test/ui/explore-issue-38412.stderr +++ b/src/test/ui/explore-issue-38412.stderr @@ -16,19 +16,19 @@ LL | r.a_unstable_undeclared_pub; = note: see issue #38412 for more information = help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable -error[E0616]: field `b_crate` of struct `pub_and_stability::Record` is private +error[E0616]: field `b_crate` of struct `Record` is private --> $DIR/explore-issue-38412.rs:31:7 | LL | r.b_crate; | ^^^^^^^ private field -error[E0616]: field `c_mod` of struct `pub_and_stability::Record` is private +error[E0616]: field `c_mod` of struct `Record` is private --> $DIR/explore-issue-38412.rs:32:7 | LL | r.c_mod; | ^^^^^ private field -error[E0616]: field `d_priv` of struct `pub_and_stability::Record` is private +error[E0616]: field `d_priv` of struct `Record` is private --> $DIR/explore-issue-38412.rs:33:7 | LL | r.d_priv; @@ -43,19 +43,19 @@ LL | t.2; = note: see issue #38412 for more information = help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable -error[E0616]: field `3` of struct `pub_and_stability::Tuple` is private +error[E0616]: field `3` of struct `Tuple` is private --> $DIR/explore-issue-38412.rs:38:7 | LL | t.3; | ^ private field -error[E0616]: field `4` of struct `pub_and_stability::Tuple` is private +error[E0616]: field `4` of struct `Tuple` is private --> $DIR/explore-issue-38412.rs:39:7 | LL | t.4; | ^ private field -error[E0616]: field `5` of struct `pub_and_stability::Tuple` is private +error[E0616]: field `5` of struct `Tuple` is private --> $DIR/explore-issue-38412.rs:40:7 | LL | t.5; diff --git a/src/test/ui/export-fully-qualified.rs b/src/test/ui/export-fully-qualified.rs index 99cb558908..40f26c7095 100644 --- a/src/test/ui/export-fully-qualified.rs +++ b/src/test/ui/export-fully-qualified.rs @@ -1,9 +1,11 @@ +// ignore-tidy-linelength + // In this test baz isn't resolved when called as foo.baz even though // it's called from inside foo. This is somewhat surprising and may // want to change eventually. mod foo { - pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared type or module `foo` + pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared crate or module `foo` fn baz() { } } diff --git a/src/test/ui/export-fully-qualified.stderr b/src/test/ui/export-fully-qualified.stderr index c2ec160086..a8af0c7c9b 100644 --- a/src/test/ui/export-fully-qualified.stderr +++ b/src/test/ui/export-fully-qualified.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` - --> $DIR/export-fully-qualified.rs:6:20 +error[E0433]: failed to resolve: use of undeclared crate or module `foo` + --> $DIR/export-fully-qualified.rs:8:20 | LL | pub fn bar() { foo::baz(); } - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to previous error diff --git a/src/test/ui/export2.rs b/src/test/ui/export2.rs index 811d96f26d..64ebeddffa 100644 --- a/src/test/ui/export2.rs +++ b/src/test/ui/export2.rs @@ -1,5 +1,5 @@ mod foo { - pub fn x() { bar::x(); } //~ ERROR failed to resolve: use of undeclared type or module `bar` + pub fn x() { bar::x(); } //~ ERROR failed to resolve: use of undeclared crate or module `bar` } mod bar { diff --git a/src/test/ui/export2.stderr b/src/test/ui/export2.stderr index e0cd4404d3..7cf47d0764 100644 --- a/src/test/ui/export2.stderr +++ b/src/test/ui/export2.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `bar` +error[E0433]: failed to resolve: use of undeclared crate or module `bar` --> $DIR/export2.rs:2:18 | LL | pub fn x() { bar::x(); } - | ^^^ use of undeclared type or module `bar` + | ^^^ use of undeclared crate or module `bar` error: aborting due to previous error diff --git a/src/test/ui/exterior.rs b/src/test/ui/exterior.rs deleted file mode 100644 index 6f2c37926b..0000000000 --- a/src/test/ui/exterior.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass - -#![allow(dead_code)] - - -use std::cell::Cell; - -#[derive(Copy, Clone)] -struct Point {x: isize, y: isize, z: isize} - -fn f(p: &Cell) { - assert_eq!(p.get().z, 12); - p.set(Point {x: 10, y: 11, z: 13}); - assert_eq!(p.get().z, 13); -} - -pub fn main() { - let a: Point = Point {x: 10, y: 11, z: 12}; - let b: &Cell = &Cell::new(a); - assert_eq!(b.get().z, 12); - f(b); - assert_eq!(a.z, 12); - assert_eq!(b.get().z, 13); -} diff --git a/src/test/ui/extern-flag/multiple-opts.stderr b/src/test/ui/extern-flag/multiple-opts.stderr index 3bf73d11cf..5088fb1c4d 100644 --- a/src/test/ui/extern-flag/multiple-opts.stderr +++ b/src/test/ui/extern-flag/multiple-opts.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `somedep` +error[E0433]: failed to resolve: use of undeclared crate or module `somedep` --> $DIR/multiple-opts.rs:19:5 | LL | somedep::somefun(); - | ^^^^^^^ use of undeclared type or module `somedep` + | ^^^^^^^ use of undeclared crate or module `somedep` error: aborting due to previous error diff --git a/src/test/ui/extern-flag/noprelude.stderr b/src/test/ui/extern-flag/noprelude.stderr index beb9200ddd..5787872168 100644 --- a/src/test/ui/extern-flag/noprelude.stderr +++ b/src/test/ui/extern-flag/noprelude.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `somedep` +error[E0433]: failed to resolve: use of undeclared crate or module `somedep` --> $DIR/noprelude.rs:6:5 | LL | somedep::somefun(); - | ^^^^^^^ use of undeclared type or module `somedep` + | ^^^^^^^ use of undeclared crate or module `somedep` error: aborting due to previous error diff --git a/src/test/ui/extern-flag/public-and-private.stderr b/src/test/ui/extern-flag/public-and-private.stderr index 94c7deaa80..9dfc10effc 100644 --- a/src/test/ui/extern-flag/public-and-private.stderr +++ b/src/test/ui/extern-flag/public-and-private.stderr @@ -1,4 +1,4 @@ -error: type `somedep::S` from private dependency 'somedep' in public interface +error: type `S` from private dependency 'somedep' in public interface --> $DIR/public-and-private.rs:10:5 | LL | pub field: somedep::S, diff --git a/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs b/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs new file mode 100644 index 0000000000..a1efe18184 --- /dev/null +++ b/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs @@ -0,0 +1,9 @@ +#![feature(extern_types)] + +extern "C" { + pub type CrossCrate; +} + +impl CrossCrate { + pub fn foo(&self) {} +} diff --git a/src/test/ui/extern/extern-types-inherent-impl.rs b/src/test/ui/extern/extern-types-inherent-impl.rs index fc98f55dc0..3f09ac7b8c 100644 --- a/src/test/ui/extern/extern-types-inherent-impl.rs +++ b/src/test/ui/extern/extern-types-inherent-impl.rs @@ -1,19 +1,26 @@ -// run-pass -#![allow(dead_code)] // Test that inherent impls can be defined for extern types. +// check-pass +// aux-build:extern-types-inherent-impl.rs + #![feature(extern_types)] -extern { - type A; +extern crate extern_types_inherent_impl; +use extern_types_inherent_impl::CrossCrate; + +extern "C" { + type Local; } -impl A { - fn foo(&self) { } +impl Local { + fn foo(&self) {} } -fn use_foo(x: &A) { +fn use_foo(x: &Local, y: &CrossCrate) { + Local::foo(x); x.foo(); + CrossCrate::foo(y); + y.foo(); } -fn main() { } +fn main() {} diff --git a/src/test/ui/extern/extern-types-not-sync-send.stderr b/src/test/ui/extern/extern-types-not-sync-send.stderr index a1138c3234..dc9810cfcf 100644 --- a/src/test/ui/extern/extern-types-not-sync-send.stderr +++ b/src/test/ui/extern/extern-types-not-sync-send.stderr @@ -7,7 +7,7 @@ LL | fn assert_sync() { } LL | assert_sync::(); | ^ `A` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `A` + = help: the trait `Sync` is not implemented for `A` error[E0277]: `A` cannot be sent between threads safely --> $DIR/extern-types-not-sync-send.rs:16:19 @@ -18,7 +18,7 @@ LL | fn assert_send() { } LL | assert_send::(); | ^ `A` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `A` + = help: the trait `Send` is not implemented for `A` error: aborting due to 2 previous errors diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr index 8938afd33f..fba919ceff 100644 --- a/src/test/ui/extern/extern-types-unsized.stderr +++ b/src/test/ui/extern/extern-types-unsized.stderr @@ -7,7 +7,7 @@ LL | fn assert_sized() { } LL | assert_sized::(); | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `A` + = help: the trait `Sized` is not implemented for `A` help: consider relaxing the implicit `Sized` restriction | LL | fn assert_sized() { } @@ -22,7 +22,7 @@ LL | fn assert_sized() { } LL | assert_sized::(); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A` + = help: within `Foo`, the trait `Sized` is not implemented for `A` = note: required because it appears within the type `Foo` help: consider relaxing the implicit `Sized` restriction | @@ -38,7 +38,7 @@ LL | fn assert_sized() { } LL | assert_sized::>(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `A` + = help: within `Bar`, the trait `Sized` is not implemented for `A` = note: required because it appears within the type `Bar` help: consider relaxing the implicit `Sized` restriction | @@ -54,7 +54,7 @@ LL | fn assert_sized() { } LL | assert_sized::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Bar>`, the trait `std::marker::Sized` is not implemented for `A` + = help: within `Bar>`, the trait `Sized` is not implemented for `A` = note: required because it appears within the type `Bar` = note: required because it appears within the type `Bar>` help: consider relaxing the implicit `Sized` restriction diff --git a/src/test/ui/extern/extern-wrong-value-type.rs b/src/test/ui/extern/extern-wrong-value-type.rs index aba52427eb..a4d7b00b1c 100644 --- a/src/test/ui/extern/extern-wrong-value-type.rs +++ b/src/test/ui/extern/extern-wrong-value-type.rs @@ -7,5 +7,5 @@ fn main() { // extern functions are extern "C" fn let _x: extern "C" fn() = f; // OK is_fn(f); - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `extern "C" fn() {f}` + //~^ ERROR expected a `Fn<()>` closure, found `extern "C" fn() {f}` } diff --git a/src/test/ui/extern/extern-wrong-value-type.stderr b/src/test/ui/extern/extern-wrong-value-type.stderr index 2cb15f84f6..d92b5f4311 100644 --- a/src/test/ui/extern/extern-wrong-value-type.stderr +++ b/src/test/ui/extern/extern-wrong-value-type.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<()>` closure, found `extern "C" fn() {f}` +error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() {f}` --> $DIR/extern-wrong-value-type.rs:9:11 | LL | fn is_fn(_: F) where F: Fn() {} @@ -7,7 +7,7 @@ LL | fn is_fn(_: F) where F: Fn() {} LL | is_fn(f); | ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` | - = help: the trait `std::ops::Fn<()>` is not implemented for `extern "C" fn() {f}` + = help: the trait `Fn<()>` is not implemented for `extern "C" fn() {f}` = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }` error: aborting due to previous error diff --git a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr index 5a58e57d36..5f78775f54 100644 --- a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr +++ b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[usize]` cannot be known at compilati LL | static symbol: [usize]; | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[usize]` + = help: the trait `Sized` is not implemented for `[usize]` error: aborting due to previous error diff --git a/src/test/ui/fat-ptr-cast.stderr b/src/test/ui/fat-ptr-cast.stderr index 56d5a26beb..0b0c288fe3 100644 --- a/src/test/ui/fat-ptr-cast.stderr +++ b/src/test/ui/fat-ptr-cast.stderr @@ -30,7 +30,7 @@ LL | a as u32; | = help: cast through a raw pointer first -error[E0605]: non-primitive cast: `std::boxed::Box<[i32]>` as `usize` +error[E0605]: non-primitive cast: `Box<[i32]>` as `usize` --> $DIR/fat-ptr-cast.rs:14:5 | LL | b as usize; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs new file mode 100644 index 0000000000..3ac8ba5232 --- /dev/null +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs @@ -0,0 +1,91 @@ +// This is testing whether various builtin attributes signals an +// error or warning when put in "weird" places. +// +// (This file sits on its own because it actually signals an error, +// which would mess up the treatment of other cases in +// issue-43106-gating-of-builtin-attrs.rs) + +// ignore-tidy-linelength + +// Crate-level is accepted, though it is almost certainly unused? +#![inline] + +#[inline] +//~^ ERROR attribute should be applied to function or closure +mod inline { + //~^ NOTE not a function or closure + + mod inner { #![inline] } + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure + + #[inline = "2100"] fn f() { } + //~^ ERROR attribute must be of the form + //~| WARN this was previously accepted + //~| NOTE #[deny(ill_formed_attribute_input)]` on by default + //~| NOTE for more information, see issue #57571 + + #[inline] struct S; + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure + + #[inline] type T = S; + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure + + #[inline] impl S { } + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure +} + +#[no_link] +//~^ ERROR attribute should be applied to an `extern crate` item +mod no_link { + //~^ NOTE not an `extern crate` item + + mod inner { #![no_link] } + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link] fn f() { } + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link] struct S; + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link]type T = S; + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link] impl S { } + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item +} + +#[export_name = "2200"] +//~^ ERROR attribute should be applied to a function or static +mod export_name { + //~^ NOTE not a function or static + + mod inner { #![export_name="2200"] } + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[export_name = "2200"] fn f() { } + + #[export_name = "2200"] struct S; + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[export_name = "2200"] type T = S; + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[export_name = "2200"] impl S { } + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static +} + +fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr new file mode 100644 index 0000000000..c9255d2be1 --- /dev/null +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr @@ -0,0 +1,136 @@ +error: attribute must be of the form `#[inline]` or `#[inline(always|never)]` + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:22:5 + | +LL | #[inline = "2100"] fn f() { } + | ^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(ill_formed_attribute_input)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:13:1 + | +LL | #[inline] + | ^^^^^^^^^ +LL | +LL | / mod inline { +LL | | +LL | | +LL | | mod inner { #![inline] } +... | +LL | | +LL | | } + | |_- not a function or closure + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:41:1 + | +LL | #[no_link] + | ^^^^^^^^^^ +LL | +LL | / mod no_link { +LL | | +LL | | +LL | | mod inner { #![no_link] } +... | +LL | | +LL | | } + | |_- not an `extern crate` item + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:1 + | +LL | #[export_name = "2200"] + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / mod export_name { +LL | | +LL | | +LL | | mod inner { #![export_name="2200"] } +... | +LL | | +LL | | } + | |_- not a function or static + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:18:17 + | +LL | mod inner { #![inline] } + | ------------^^^^^^^^^^-- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:5 + | +LL | #[inline] struct S; + | ^^^^^^^^^ --------- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:5 + | +LL | #[inline] type T = S; + | ^^^^^^^^^ ----------- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:5 + | +LL | #[inline] impl S { } + | ^^^^^^^^^ ---------- not a function or closure + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:17 + | +LL | mod inner { #![no_link] } + | ------------^^^^^^^^^^^-- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5 + | +LL | #[no_link] fn f() { } + | ^^^^^^^^^^ ---------- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5 + | +LL | #[no_link] struct S; + | ^^^^^^^^^^ --------- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5 + | +LL | #[no_link]type T = S; + | ^^^^^^^^^^----------- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:62:5 + | +LL | #[no_link] impl S { } + | ^^^^^^^^^^ ---------- not an `extern crate` item + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:17 + | +LL | mod inner { #![export_name="2200"] } + | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5 + | +LL | #[export_name = "2200"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5 + | +LL | #[export_name = "2200"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5 + | +LL | #[export_name = "2200"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static + +error: aborting due to 17 previous errors + +For more information about this error, try `rustc --explain E0518`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index f702b10ccd..f94434f459 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -31,14 +31,19 @@ // occurrences in the source text. // check-pass +// ignore-tidy-linelength #![feature(test, plugin_registrar)] #![warn(unused_attributes, unknown_lints)] +//~^ NOTE the lint level is defined here +//~| NOTE the lint level is defined here // Exception, a gated and deprecated attribute. -#![plugin_registrar] //~ WARN unused attribute +#![plugin_registrar] +//~^ WARN unused attribute //~| WARN use of deprecated attribute +//~| HELP may be removed in a future compiler version // UNGATED WHITE-LISTED BUILT-IN ATTRIBUTES @@ -72,7 +77,7 @@ #![doc = "2400"] #![cold] #![export_name = "2200"] -// see issue-43106-gating-of-inline.rs +// see issue-43106-gating-of-builtin-attrs-error.rs #![link()] #![link_name = "1900"] #![link_section = "1800"] @@ -88,12 +93,18 @@ #![crate_name = "0900"] #![crate_type = "bin"] // cannot pass "0800" here -#![crate_id = "10"] //~ WARN use of deprecated attribute +#![crate_id = "10"] +//~^ WARN use of deprecated attribute +//~| HELP remove this attribute // FIXME(#44232) we should warn that this isn't used. -#![feature(rust1)] //~ WARN no longer requires an attribute to enable +#![feature(rust1)] +//~^ WARN no longer requires an attribute to enable +//~| NOTE `#[warn(stable_features)]` on by default -#![no_start] //~ WARN use of deprecated attribute +#![no_start] +//~^ WARN use of deprecated attribute +//~| HELP remove this attribute // (cannot easily gating state of crate-level #[no_main]; but non crate-level is below at "0400") #![no_builtins] @@ -217,24 +228,30 @@ mod macro_export { #[plugin_registrar] //~^ WARN unused attribute //~| WARN use of deprecated attribute +//~| HELP may be removed in a future compiler version mod plugin_registrar { mod inner { #![plugin_registrar] } //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version + //~| NOTE `#[warn(deprecated)]` on by default // for `fn f()` case, see gated-plugin_registrar.rs #[plugin_registrar] struct S; //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version #[plugin_registrar] type T = S; //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version #[plugin_registrar] impl S { } //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version } #[main] @@ -355,35 +372,31 @@ mod automatically_derived { } #[no_mangle] +//~^ WARN attribute should be applied to a function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! mod no_mangle { + //~^ NOTE not a function or static mod inner { #![no_mangle] } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[no_mangle] fn f() { } #[no_mangle] struct S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[no_mangle] type T = S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[no_mangle] impl S { } -} - -#[no_link] -//~^ WARN unused attribute -mod no_link { - mod inner { #![no_link] } - //~^ WARN unused attribute - - #[no_link] fn f() { } - //~^ WARN unused attribute - - #[no_link] struct S; - //~^ WARN unused attribute - - #[no_link]type T = S; - //~^ WARN unused attribute - - #[no_link] impl S { } - //~^ WARN unused attribute + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static } #[should_panic] @@ -468,6 +481,7 @@ mod reexport_test_harness_main { mod macro_escape { mod inner { #![macro_escape] } //~^ WARN `#[macro_escape]` is a deprecated synonym for `#[macro_use]` + //~| HELP try an outer attribute: `#[macro_use]` #[macro_escape] fn f() { } //~^ WARN unused attribute @@ -525,73 +539,119 @@ mod doc { } #[cold] +//~^ WARN attribute should be applied to a function +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! mod cold { + //~^ NOTE not a function + mod inner { #![cold] } + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function #[cold] fn f() { } #[cold] struct S; + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function #[cold] type T = S; + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function #[cold] impl S { } -} - -#[export_name = "2200"] -mod export_name { - mod inner { #![export_name="2200"] } - - #[export_name = "2200"] fn f() { } - - #[export_name = "2200"] struct S; - - #[export_name = "2200"] type T = S; - - #[export_name = "2200"] impl S { } -} - -// Note that this is a `check-pass` test, so it -// will never invoke the linker. These are here nonetheless to point -// out that we allow them at non-crate-level (though I do not know -// whether they have the same effect here as at crate-level). - -#[link()] -mod link { - mod inner { #![link()] } - - #[link()] fn f() { } - - #[link()] struct S; - - #[link()] type T = S; - - #[link()] impl S { } + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function } #[link_name = "1900"] +//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! mod link_name { + //~^ NOTE not a foreign function or static + + #[link_name = "1900"] + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| HELP try `#[link(name = "1900")]` instead + extern { } + //~^ NOTE not a foreign function or static + mod inner { #![link_name="1900"] } + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static #[link_name = "1900"] fn f() { } + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static #[link_name = "1900"] struct S; + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static #[link_name = "1900"] type T = S; + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static #[link_name = "1900"] impl S { } + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static } #[link_section = "1800"] +//~^ WARN attribute should be applied to a function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! mod link_section { + //~^ NOTE not a function or static + mod inner { #![link_section="1800"] } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[link_section = "1800"] fn f() { } #[link_section = "1800"] struct S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[link_section = "1800"] type T = S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[link_section = "1800"] impl S { } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static +} + + +// Note that this is a `check-pass` test, so it +// will never invoke the linker. These are here nonetheless to point +// out that we allow them at non-crate-level (though I do not know +// whether they have the same effect here as at crate-level). + +#[link()] +mod link { + mod inner { #![link()] } + + #[link()] fn f() { } + + #[link()] struct S; + + #[link()] type T = S; + + #[link()] impl S { } } struct StructForDeprecated; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 02bed6723b..461c1bd610 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -1,185 +1,185 @@ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:9 | LL | #![warn(x5400)] | ^^^^^ | note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:28 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:51:10 | LL | #![allow(x5300)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:11 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:11 | LL | #![forbid(x5200)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:9 | LL | #![deny(x5100)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:108:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:117:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:136:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:155:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:174:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17 | LL | mod inner { #![plugin_registrar] } | ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version @@ -195,49 +195,274 @@ LL | mod inner { #![plugin_registrar] } = note: `#[warn(deprecated)]` on by default warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5 | LL | #[plugin_registrar] struct S; | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5 | LL | #[plugin_registrar] type T = S; | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 | LL | #[plugin_registrar] impl S { } | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:1 | LL | #[plugin_registrar] | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1 | LL | #![plugin_registrar] | ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `crate_id`: no longer used. - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:91:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:1 | LL | #![crate_id = "10"] | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute warning: use of deprecated attribute `no_start`: no longer used. - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:1 | LL | #![no_start] | ^^^^^^^^^^^^ help: remove this attribute +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ +... +LL | / mod no_mangle { +LL | | +LL | | mod inner { #![no_mangle] } +LL | | +... | +LL | | +LL | | } + | |_- not a function or static + | +note: the lint level is defined here + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:9 + | +LL | #![warn(unused_attributes, unknown_lints)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:1 + | +LL | #[cold] + | ^^^^^^^ +... +LL | / mod cold { +LL | | +LL | | +LL | | mod inner { #![cold] } +... | +LL | | +LL | | } + | |_- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:570:1 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | / mod link_name { +LL | | +LL | | +LL | | #[link_name = "1900"] +... | +LL | | +LL | | } + | |_- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:1 + | +LL | #[link_section = "1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / mod link_section { +LL | | +LL | | +LL | | mod inner { #![link_section="1800"] } +... | +LL | | +LL | | } + | |_- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:17 + | +LL | mod inner { #![no_mangle] } + | ------------^^^^^^^^^^^^^-- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5 + | +LL | #[no_mangle] struct S; + | ^^^^^^^^^^^^ --------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:5 + | +LL | #[no_mangle] type T = S; + | ^^^^^^^^^^^^ ----------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:5 + | +LL | #[no_mangle] impl S { } + | ^^^^^^^^^^^^ ---------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:17 + | +LL | mod inner { #![cold] } + | ------------^^^^^^^^-- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:554:5 + | +LL | #[cold] struct S; + | ^^^^^^^ --------- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5 + | +LL | #[cold] type T = S; + | ^^^^^^^ ----------- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:564:5 + | +LL | #[cold] impl S { } + | ^^^^^^^ ---------- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | extern { } + | ---------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +help: try `#[link(name = "1900")]` instead + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:583:17 + | +LL | mod inner { #![link_name="1900"] } + | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:5 + | +LL | #[link_name = "1900"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:593:5 + | +LL | #[link_name = "1900"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:5 + | +LL | #[link_name = "1900"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:5 + | +LL | #[link_name = "1900"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:17 + | +LL | mod inner { #![link_section="1800"] } + | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:622:5 + | +LL | #[link_section = "1800"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5 + | +LL | #[link_section = "1800"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:632:5 + | +LL | #[link_section = "1800"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:94:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:101:12 | LL | #![feature(rust1)] | ^^^^^ @@ -245,994 +470,952 @@ LL | #![feature(rust1)] = note: `#[warn(stable_features)]` on by default warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:5 | LL | #[macro_use] fn f() { } | ^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:9 - | -LL | #![warn(unused_attributes, unknown_lints)] - | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:199:5 | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:194:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:17 | LL | mod inner { #![macro_export] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:5 | LL | #[macro_export] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:218:5 | LL | #[macro_export] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:210:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:5 | LL | #[macro_export] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5 | LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:1 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17 | LL | mod inner { #![plugin_registrar] } | ^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5 | LL | #[plugin_registrar] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5 | LL | #[plugin_registrar] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 | LL | #[plugin_registrar] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:1 | LL | #[plugin_registrar] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:243:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:17 | LL | mod inner { #![main] } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:265:5 | LL | #[main] struct S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:5 | LL | #[main] type T = S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:254:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5 | LL | #[main] impl S { } | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:240:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:1 | LL | #[main] | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:278:17 | LL | mod inner { #![start] } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:5 | LL | #[start] struct S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:5 | LL | #[start] type T = S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:5 | LL | #[start] impl S { } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:1 | LL | #[start] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:328:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:331:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:348:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:334:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 | LL | #[automatically_derived] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:17 - | -LL | mod inner { #![no_link] } - | ^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 - | -LL | #[no_link] fn f() { } - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5 - | -LL | #[no_link] struct S; - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:5 - | -LL | #[no_link]type T = S; - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5 - | -LL | #[no_link] impl S { } - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:1 - | -LL | #[no_link] - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5 | LL | #[should_panic] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 | LL | #[ignore] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:1 | LL | #[ignore] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:17 | LL | mod inner { #![no_implicit_prelude] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:1 | LL | #[no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:461:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:481:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:1 | LL | #[no_std] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:1 | LL | #[no_std] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:796:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:796:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:1 | LL | #[no_main] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1 | LL | #![plugin_registrar] | ^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1 | LL | #![macro_export] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1 | LL | #![main] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 | LL | #![start] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:57:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | LL | #![repr()] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | LL | #![path = "3800"] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 | LL | #![automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:67:1 | LL | #![no_link] | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 | LL | #![should_panic] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 | LL | #![ignore] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:71:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:76:1 | LL | #![proc_macro_derive()] | ^^^^^^^^^^^^^^^^^^^^^^^ -warning: 203 warnings emitted +warning: 219 warnings emitted diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr index db29a2bddd..ffec76f409 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr @@ -1,28 +1,28 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:4:1 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:7:17 | LL | mod inner { #![derive(Debug)] } | ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]` -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:10:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:23:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:27:5 | LL | #[derive(Debug)] @@ -30,3 +30,4 @@ LL | #[derive(Debug)] error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs b/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs deleted file mode 100644 index 80c602eb00..0000000000 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs +++ /dev/null @@ -1,31 +0,0 @@ -// This is testing whether `#[inline]` signals an error or warning -// when put in "weird" places. -// -// (This file sits on its own because it actually signals an error, -// which would mess up the treatment of other cases in -// issue-43106-gating-of-builtin-attrs.rs) - -// Crate-level is accepted, though it is almost certainly unused? -#![inline] - -#[inline] -//~^ ERROR attribute should be applied to function or closure -mod inline { - mod inner { #![inline] } - //~^ ERROR attribute should be applied to function or closure - - #[inline = "2100"] fn f() { } - //~^ ERROR attribute must be of the form - //~| WARN this was previously accepted - - #[inline] struct S; - //~^ ERROR attribute should be applied to function or closure - - #[inline] type T = S; - //~^ ERROR attribute should be applied to function or closure - - #[inline] impl S { } - //~^ ERROR attribute should be applied to function or closure -} - -fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr deleted file mode 100644 index 0987937192..0000000000 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error: attribute must be of the form `#[inline]` or `#[inline(always|never)]` - --> $DIR/issue-43106-gating-of-inline.rs:17:5 - | -LL | #[inline = "2100"] fn f() { } - | ^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(ill_formed_attribute_input)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:11:1 - | -LL | #[inline] - | ^^^^^^^^^ -LL | -LL | / mod inline { -LL | | mod inner { #![inline] } -LL | | -LL | | -... | -LL | | -LL | | } - | |_- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:14:17 - | -LL | mod inner { #![inline] } - | ------------^^^^^^^^^^-- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:21:5 - | -LL | #[inline] struct S; - | ^^^^^^^^^ --------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:24:5 - | -LL | #[inline] type T = S; - | ^^^^^^^^^ ----------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:27:5 - | -LL | #[inline] impl S { } - | ^^^^^^^^^ ---------- not a function or closure - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0518`. diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs index 6e0b71bc1e..47ca7e3497 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs @@ -23,7 +23,7 @@ impl Foo for Bar { } impl Bar { - fn bar(self: Box>) {} //~ ERROR `std::boxed::Box>` cannot be used as the + fn bar(self: Box>) {} //~ ERROR `Box>` cannot be used as the } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr index f5d74d7a84..a06c4b2b48 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr @@ -18,7 +18,7 @@ LL | fn foo(self: Ptr) {} = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) -error[E0658]: `std::boxed::Box>` cannot be used as the type of `self` without the `arbitrary_self_types` feature +error[E0658]: `Box>` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary-self-types.rs:26:18 | LL | fn bar(self: Box>) {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs index 506b21dc7d..049fdd84d8 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs @@ -87,6 +87,30 @@ fn main() { //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "ptr"); //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "8"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "16"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "32"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "64"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "128"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "ptr"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "8"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "16"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "32"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "64"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "128"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "ptr"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change } #[macro_export] diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr index 6132c53087..16e1dc6440 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr @@ -160,6 +160,114 @@ LL | cfg!(target_has_atomic = "ptr"); = note: see issue #32976 for more information = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable -error: aborting due to 18 previous errors +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:90:10 + | +LL | cfg!(target_has_atomic_load_store = "8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:92:10 + | +LL | cfg!(target_has_atomic_load_store = "16"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:94:10 + | +LL | cfg!(target_has_atomic_load_store = "32"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:96:10 + | +LL | cfg!(target_has_atomic_load_store = "64"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:98:10 + | +LL | cfg!(target_has_atomic_load_store = "128"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:100:10 + | +LL | cfg!(target_has_atomic_load_store = "ptr"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:102:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:104:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "16"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:106:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "32"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:108:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "64"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:110:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "128"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:112:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "ptr"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error: aborting due to 30 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs index 981680b5d1..9007e501bc 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs +++ b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs @@ -6,33 +6,33 @@ struct Foo(u32); const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; const fn transmute_fn() -> u32 { unsafe { mem::transmute(Foo(3)) } } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const fn transmute_fn_intrinsic() -> u32 { unsafe { std::intrinsics::transmute(Foo(3)) } } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const fn transmute_fn_core_intrinsic() -> u32 { unsafe { core::intrinsics::transmute(Foo(3)) } } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const unsafe fn unsafe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const unsafe fn unsafe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const unsafe fn unsafe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` //~| ERROR call to unsafe function is unsafe and requires unsafe function or block const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` //~| ERROR call to unsafe function is unsafe and requires unsafe function or block const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` //~| ERROR call to unsafe function is unsafe and requires unsafe function or block fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr index 44430fd577..08ba14dc40 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr @@ -1,83 +1,92 @@ -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:8:43 | LL | const fn transmute_fn() -> u32 { unsafe { mem::transmute(Foo(3)) } } | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:11:53 | LL | const fn transmute_fn_intrinsic() -> u32 { unsafe { std::intrinsics::transmute(Foo(3)) } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:14:58 | LL | const fn transmute_fn_core_intrinsic() -> u32 { unsafe { core::intrinsics::transmute(Foo(3)) } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:17:48 | LL | const unsafe fn unsafe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:20:58 | LL | const unsafe fn unsafe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:23:63 | LL | const unsafe fn unsafe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:26:39 | LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:30:49 | LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:34:54 | LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/feature-gate-const_fn_transmute.rs:26:39 @@ -105,5 +114,5 @@ LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::tran error: aborting due to 12 previous errors -Some errors have detailed explanations: E0133, E0723. +Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs index c3c554d7d2..5ed302bbff 100644 --- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs +++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength #![allow(warnings)] struct Bar; @@ -6,13 +5,13 @@ struct Bar; // This function would compile with the feature gate, and tests that it is suggested. fn foo() { let arr: [Option; 2] = [None::; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } // This function would not compile with the feature gate, and tests that it is not suggested. fn bar() { let arr: [Option; 2] = [Some("foo".to_string()); 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr index 6772178068..ca1706169a 100644 --- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr @@ -1,23 +1,23 @@ -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:8:36 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36 | LL | let arr: [Option; 2] = [None::; 2]; - | ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied = note: this array initializer can be evaluated at compile-time, see issue #49147 for more information = help: add `#![feature(const_in_array_repeat_expressions)]` to the crate attributes to enable -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:14:36 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:13:36 | LL | let arr: [Option; 2] = [Some("foo".to_string()); 2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.rs b/src/test/ui/feature-gates/feature-gate-doc_alias.rs deleted file mode 100644 index c95722102d..0000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[doc(alias = "foo")] //~ ERROR: `#[doc(alias)]` is experimental -pub struct Foo; - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr deleted file mode 100644 index f66d1602ba..0000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `#[doc(alias)]` is experimental - --> $DIR/feature-gate-doc_alias.rs:1:1 - | -LL | #[doc(alias = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #50146 for more information - = help: add `#![feature(doc_alias)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr index d4c09ec40f..f3fa641209 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -64,13 +64,13 @@ LL | | } = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable -error[E0277]: the trait bound `std::string::String: std::ops::Neg` is not satisfied +error[E0277]: the trait bound `String: Neg` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:36:1 | LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg { LL | | -s LL | | } - | |_^ the trait `std::ops::Neg` is not implemented for `std::string::String` + | |_^ the trait `Neg` is not implemented for `String` | = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -83,7 +83,7 @@ LL | | for _ in 2i32 {} LL | | } | |_^ `i32` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i32` + = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -94,7 +94,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -106,7 +106,7 @@ LL | | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); LL | | } | |_^ doesn't have a size known at compile-time | - = help: within `Dst<(dyn A + 'static)>`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` + = help: within `Dst<(dyn A + 'static)>`, the trait `Sized` is not implemented for `(dyn A + 'static)` = note: required because it appears within the type `Dst<(dyn A + 'static)>` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -119,7 +119,7 @@ LL | | *"Sized".to_string().into_boxed_str() LL | | } | |_^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr index 0195cc1481..29595c9237 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `(dyn std::ops::FnOnce() + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn FnOnce() + 'static)` cannot be known at compilation time --> $DIR/feature-gate-unsized_locals.rs:1:6 | LL | fn f(f: dyn FnOnce()) {} | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)` + = help: the trait `Sized` is not implemented for `(dyn FnOnce() + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/ffi_const.stderr b/src/test/ui/ffi_const.stderr index 623551cc07..bc3c12eaf9 100644 --- a/src/test/ui/ffi_const.stderr +++ b/src/test/ui/ffi_const.stderr @@ -6,3 +6,4 @@ LL | #[ffi_const] error: aborting due to previous error +For more information about this error, try `rustc --explain E0756`. diff --git a/src/test/ui/ffi_pure.stderr b/src/test/ui/ffi_pure.stderr index 3a849c0bca..bc911c85dd 100644 --- a/src/test/ui/ffi_pure.stderr +++ b/src/test/ui/ffi_pure.stderr @@ -6,3 +6,4 @@ LL | #[ffi_pure] error: aborting due to previous error +For more information about this error, try `rustc --explain E0755`. diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.rs b/src/test/ui/fmt/format-args-capture-missing-variables.rs index 3c596ae3bb..3a4b6144b0 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.rs +++ b/src/test/ui/fmt/format-args-capture-missing-variables.rs @@ -5,7 +5,7 @@ fn main() { //~^ ERROR: cannot find value `foo` in this scope //~^^ ERROR: cannot find value `bar` in this scope - format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope + format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope format!("{valuea} {valueb}", valuea=5, valuec=7); //~^ ERROR cannot find value `valueb` in this scope @@ -16,7 +16,7 @@ fn main() { {foo} "##); - //~^^^^^ ERROR: cannot find value `foo` in this scope + //~^^^ ERROR: cannot find value `foo` in this scope - panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope + panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope } diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.stderr b/src/test/ui/fmt/format-args-capture-missing-variables.stderr index c3d740eef9..ec2faa4185 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.stderr +++ b/src/test/ui/fmt/format-args-capture-missing-variables.stderr @@ -7,45 +7,40 @@ LL | format!("{valuea} {valueb}", valuea=5, valuec=7); | formatting specifier missing error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:4:13 + --> $DIR/format-args-capture-missing-variables.rs:4:17 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `bar` in this scope - --> $DIR/format-args-capture-missing-variables.rs:4:13 + --> $DIR/format-args-capture-missing-variables.rs:4:26 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:8:13 + --> $DIR/format-args-capture-missing-variables.rs:8:14 | LL | format!("{foo}"); - | ^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `valueb` in this scope - --> $DIR/format-args-capture-missing-variables.rs:10:13 + --> $DIR/format-args-capture-missing-variables.rs:10:23 | LL | format!("{valuea} {valueb}", valuea=5, valuec=7); - | ^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:14:13 + --> $DIR/format-args-capture-missing-variables.rs:16:9 | -LL | format!(r##" - | _____________^ -LL | | -LL | | {foo} -LL | | -LL | | "##); - | |_______^ not found in this scope +LL | {foo} + | ^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:21:12 + --> $DIR/format-args-capture-missing-variables.rs:21:13 | LL | panic!("{foo} {bar}", bar=1); - | ^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error: aborting due to 7 previous errors diff --git a/src/test/ui/fmt/incorrect-separator.rs b/src/test/ui/fmt/incorrect-separator.rs new file mode 100644 index 0000000000..b8d2e4a347 --- /dev/null +++ b/src/test/ui/fmt/incorrect-separator.rs @@ -0,0 +1,29 @@ +// Allows to track issue #75492: +// https://github.com/rust-lang/rust/issues/75492 + +use std::iter; + +fn main() { + format!("A number: {}". iter::once(42).next().unwrap()); + //~^ ERROR expected `,`, found `.` + + // Other kind of types are also checked: + + format!("A number: {}" / iter::once(42).next().unwrap()); + //~^ ERROR expected `,`, found `/` + + format!("A number: {}"; iter::once(42).next().unwrap()); + //~^ ERROR expected `,`, found `;` + + // Note: this character is an COMBINING COMMA BELOW unicode char + format!("A number: {}" ̦ iter::once(42).next().unwrap()); + //~^ ERROR expected `,`, found `iter` + //~^^ ERROR unknown start of token: \u{326} + + // Here recovery is tested. + // If the `compile_error!` is emitted, then the parser is able to recover + // from the incorrect first separator. + format!("{}". compile_error!("fail")); + //~^ ERROR expected `,`, found `.` + //~^^ ERROR fail +} diff --git a/src/test/ui/fmt/incorrect-separator.stderr b/src/test/ui/fmt/incorrect-separator.stderr new file mode 100644 index 0000000000..5a3e5515bb --- /dev/null +++ b/src/test/ui/fmt/incorrect-separator.stderr @@ -0,0 +1,44 @@ +error: unknown start of token: \u{326} + --> $DIR/incorrect-separator.rs:19:28 + | +LL | format!("A number: {}" ̦ iter::once(42).next().unwrap()); + | ^ + +error: expected `,`, found `.` + --> $DIR/incorrect-separator.rs:7:27 + | +LL | format!("A number: {}". iter::once(42).next().unwrap()); + | ^ expected `,` + +error: expected `,`, found `/` + --> $DIR/incorrect-separator.rs:12:28 + | +LL | format!("A number: {}" / iter::once(42).next().unwrap()); + | ^ expected `,` + +error: expected `,`, found `;` + --> $DIR/incorrect-separator.rs:15:27 + | +LL | format!("A number: {}"; iter::once(42).next().unwrap()); + | ^ expected `,` + +error: expected `,`, found `iter` + --> $DIR/incorrect-separator.rs:19:30 + | +LL | format!("A number: {}" ̦ iter::once(42).next().unwrap()); + | ^^^^ expected `,` + +error: expected `,`, found `.` + --> $DIR/incorrect-separator.rs:26:17 + | +LL | format!("{}". compile_error!("fail")); + | ^ expected `,` + +error: fail + --> $DIR/incorrect-separator.rs:26:19 + | +LL | format!("{}". compile_error!("fail")); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index b3b53971a3..780c71128d 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -7,12 +7,12 @@ LL | fn send(_: T) {} LL | send(format_args!("{:?}", c)); | ^^^^ `core::fmt::Opaque` cannot be shared between threads safely | - = help: within `[std::fmt::ArgumentV1<'_>]`, the trait `std::marker::Sync` is not implemented for `core::fmt::Opaque` + = help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` = note: required because it appears within the type `&core::fmt::Opaque` - = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` - = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` - = note: required because of the requirements on the impl of `std::marker::Send` for `&[std::fmt::ArgumentV1<'_>]` - = note: required because it appears within the type `std::fmt::Arguments<'_>` + = note: required because it appears within the type `ArgumentV1<'_>` + = note: required because it appears within the type `[ArgumentV1<'_>]` + = note: required because of the requirements on the impl of `Send` for `&[ArgumentV1<'_>]` + = note: required because it appears within the type `Arguments<'_>` error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely --> $DIR/send-sync.rs:9:5 @@ -23,12 +23,12 @@ LL | fn sync(_: T) {} LL | sync(format_args!("{:?}", c)); | ^^^^ `core::fmt::Opaque` cannot be shared between threads safely | - = help: within `std::fmt::Arguments<'_>`, the trait `std::marker::Sync` is not implemented for `core::fmt::Opaque` + = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `core::fmt::Opaque` = note: required because it appears within the type `&core::fmt::Opaque` - = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` - = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` - = note: required because it appears within the type `&[std::fmt::ArgumentV1<'_>]` - = note: required because it appears within the type `std::fmt::Arguments<'_>` + = note: required because it appears within the type `ArgumentV1<'_>` + = note: required because it appears within the type `[ArgumentV1<'_>]` + = note: required because it appears within the type `&[ArgumentV1<'_>]` + = note: required because it appears within the type `Arguments<'_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/fn/fn-compare-mismatch.stderr b/src/test/ui/fn/fn-compare-mismatch.stderr index fa74d027f1..326418ecbf 100644 --- a/src/test/ui/fn/fn-compare-mismatch.stderr +++ b/src/test/ui/fn/fn-compare-mismatch.stderr @@ -1,10 +1,10 @@ -error[E0369]: binary operation `==` cannot be applied to type `fn() {main::f}` +error[E0369]: binary operation `==` cannot be applied to type `fn() {f}` --> $DIR/fn-compare-mismatch.rs:4:15 | LL | let x = f == g; - | - ^^ - fn() {main::g} + | - ^^ - fn() {g} | | - | fn() {main::f} + | fn() {f} | help: you might have forgotten to call this function | @@ -21,8 +21,8 @@ error[E0308]: mismatched types LL | let x = f == g; | ^ expected fn item, found a different fn item | - = note: expected fn item `fn() {main::f}` - found fn item `fn() {main::g}` + = note: expected fn item `fn() {f}` + found fn item `fn() {g}` error: aborting due to 2 previous errors diff --git a/src/test/ui/fn/fn-item-type.rs b/src/test/ui/fn/fn-item-type.rs index abae40162a..415e87b42f 100644 --- a/src/test/ui/fn/fn-item-type.rs +++ b/src/test/ui/fn/fn-item-type.rs @@ -28,9 +28,9 @@ fn main() { eq(bar::, bar::>); //~^ ERROR mismatched types - //~| expected fn item `fn(_) -> _ {bar::}` - //~| found fn item `fn(_) -> _ {bar::>}` - //~| expected struct `std::string::String`, found struct `std::vec::Vec` + //~| expected fn item `fn(_) -> _ {bar::}` + //~| found fn item `fn(_) -> _ {bar::>}` + //~| expected struct `String`, found struct `Vec` //~| different `fn` items always have unique types, even if their signatures are the same //~| change the expected type to be function pointer //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer diff --git a/src/test/ui/fn/fn-item-type.stderr b/src/test/ui/fn/fn-item-type.stderr index bfa9efa219..4bd51a668a 100644 --- a/src/test/ui/fn/fn-item-type.stderr +++ b/src/test/ui/fn/fn-item-type.stderr @@ -26,13 +26,13 @@ error[E0308]: mismatched types --> $DIR/fn-item-type.rs:29:23 | LL | eq(bar::, bar::>); - | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec` + | ^^^^^^^^^^^^^^ expected struct `String`, found struct `Vec` | - = note: expected fn item `fn(_) -> _ {bar::}` - found fn item `fn(_) -> _ {bar::>}` + = note: expected fn item `fn(_) -> _ {bar::}` + found fn item `fn(_) -> _ {bar::>}` = note: different `fn` items always have unique types, even if their signatures are the same = help: change the expected type to be function pointer `fn(isize) -> isize` - = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar:: as fn(isize) -> isize` + = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar:: as fn(isize) -> isize` error[E0308]: mismatched types --> $DIR/fn-item-type.rs:39:26 diff --git a/src/test/ui/fn/fn-trait-formatting.rs b/src/test/ui/fn/fn-trait-formatting.rs index 63ab8e88e4..0c389e1dc5 100644 --- a/src/test/ui/fn/fn-trait-formatting.rs +++ b/src/test/ui/fn/fn-trait-formatting.rs @@ -6,16 +6,16 @@ fn main() { let _: () = (box |_: isize| {}) as Box; //~^ ERROR mismatched types //~| expected unit type `()` - //~| found struct `std::boxed::Box` + //~| found struct `Box` let _: () = (box |_: isize, isize| {}) as Box; //~^ ERROR mismatched types //~| expected unit type `()` - //~| found struct `std::boxed::Box` + //~| found struct `Box` let _: () = (box || -> isize { unimplemented!() }) as Box isize>; //~^ ERROR mismatched types //~| expected unit type `()` - //~| found struct `std::boxed::Box isize>` + //~| found struct `Box isize>` needs_fn(1); - //~^ ERROR expected a `std::ops::Fn<(isize,)>` closure, found `{integer}` + //~^ ERROR expected a `Fn<(isize,)>` closure, found `{integer}` } diff --git a/src/test/ui/fn/fn-trait-formatting.stderr b/src/test/ui/fn/fn-trait-formatting.stderr index e3ada4f6ba..5b63b8e228 100644 --- a/src/test/ui/fn/fn-trait-formatting.stderr +++ b/src/test/ui/fn/fn-trait-formatting.stderr @@ -2,36 +2,36 @@ error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:6:17 | LL | let _: () = (box |_: isize| {}) as Box; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `std::boxed::Box` + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | = note: expected unit type `()` - found struct `std::boxed::Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:10:17 | LL | let _: () = (box |_: isize, isize| {}) as Box; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `std::boxed::Box` + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | = note: expected unit type `()` - found struct `std::boxed::Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:14:17 | LL | let _: () = (box || -> isize { unimplemented!() }) as Box isize>; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `std::boxed::Box` + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | = note: expected unit type `()` - found struct `std::boxed::Box isize>` + found struct `Box isize>` -error[E0277]: expected a `std::ops::Fn<(isize,)>` closure, found `{integer}` +error[E0277]: expected a `Fn<(isize,)>` closure, found `{integer}` --> $DIR/fn-trait-formatting.rs:19:14 | LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} @@ -40,7 +40,7 @@ LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} LL | needs_fn(1); | ^ expected an `Fn<(isize,)>` closure, found `{integer}` | - = help: the trait `std::ops::Fn<(isize,)>` is not implemented for `{integer}` + = help: the trait `Fn<(isize,)>` is not implemented for `{integer}` error: aborting due to 4 previous errors diff --git a/src/test/ui/for/for-c-in-str.rs b/src/test/ui/for/for-c-in-str.rs index 1871cf9d23..df66127c60 100644 --- a/src/test/ui/for/for-c-in-str.rs +++ b/src/test/ui/for/for-c-in-str.rs @@ -4,8 +4,8 @@ fn main() { for c in "asdf" { //~^ ERROR `&str` is not an iterator //~| NOTE `&str` is not an iterator - //~| HELP the trait `std::iter::Iterator` is not implemented for `&str` - //~| NOTE required by `std::iter::IntoIterator::into_iter` + //~| HELP the trait `Iterator` is not implemented for `&str` + //~| NOTE required by `into_iter` //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE in this expansion of desugaring of `for` loop diff --git a/src/test/ui/for/for-c-in-str.stderr b/src/test/ui/for/for-c-in-str.stderr index 9185399804..b0f959ba02 100644 --- a/src/test/ui/for/for-c-in-str.stderr +++ b/src/test/ui/for/for-c-in-str.stderr @@ -4,8 +4,8 @@ error[E0277]: `&str` is not an iterator LL | for c in "asdf" { | ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `std::iter::Iterator` is not implemented for `&str` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&str` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/for/for-loop-bogosity.stderr b/src/test/ui/for/for-loop-bogosity.stderr index fe6ac529b4..ccacd655a1 100644 --- a/src/test/ui/for/for-loop-bogosity.stderr +++ b/src/test/ui/for/for-loop-bogosity.stderr @@ -4,8 +4,8 @@ error[E0277]: `MyStruct` is not an iterator LL | for x in bogus { | ^^^^^ `MyStruct` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `MyStruct` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `MyStruct` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/format-ref-cell.rs b/src/test/ui/format-ref-cell.rs deleted file mode 100644 index afb2f8488b..0000000000 --- a/src/test/ui/format-ref-cell.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass - -use std::cell::RefCell; - -pub fn main() { - let name = RefCell::new("rust"); - let what = RefCell::new("rocks"); - let msg = format!("{name} {}", &*what.borrow(), name=&*name.borrow()); - assert_eq!(msg, "rust rocks".to_string()); -} diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs index b4f9a38ff3..1c6b9805b5 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs @@ -4,7 +4,7 @@ fn main() { let x: Option; x = 5; //~^ ERROR mismatched types - //~| expected enum `std::option::Option` + //~| expected enum `Option` //~| found type `{integer}` - //~| expected enum `std::option::Option`, found integer + //~| expected enum `Option`, found integer } diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr index 6a550b93be..b5018b47b7 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | x = 5; | ^ | | - | expected enum `std::option::Option`, found integer + | expected enum `Option`, found integer | help: try using a variant of the expected enum: `Some(5)` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found type `{integer}` error: aborting due to previous error diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.rs b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.rs index 30cb3ee48e..2486ae009c 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.rs +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.rs @@ -5,9 +5,9 @@ use std::option::Option; fn bar(x: usize) -> Option { return x; //~^ ERROR mismatched types - //~| expected enum `std::option::Option` + //~| expected enum `Option` //~| found type `usize` - //~| expected enum `std::option::Option`, found `usize` + //~| expected enum `Option`, found `usize` } fn main() { diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr index ca61fb0c17..b9574e3975 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr @@ -2,14 +2,14 @@ error[E0308]: mismatched types --> $DIR/fully-qualified-type-name4.rs:6:12 | LL | fn bar(x: usize) -> Option { - | ------------- expected `std::option::Option` because of return type + | ------------- expected `Option` because of return type LL | return x; | ^ | | - | expected enum `std::option::Option`, found `usize` + | expected enum `Option`, found `usize` | help: try using a variant of the expected enum: `Some(x)` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found type `usize` error: aborting due to previous error diff --git a/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr b/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr index 635f83bbf4..45cdd3d2dd 100644 --- a/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr +++ b/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr @@ -5,7 +5,7 @@ LL | let _b = A { y: Arc::new(3), ..a }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | | | cannot move out of here - | move occurs because `a.x` has type `std::sync::Arc`, which does not implement the `Copy` trait + | move occurs because `a.x` has type `Arc`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.rs b/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.rs index 7ae53020fe..500633edf1 100644 --- a/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.rs +++ b/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.rs @@ -26,7 +26,7 @@ mod foo { fn main() { let s_1 = foo::make_secrets(3, format!("ess one")); let s_2 = foo::S { b: format!("ess two"), ..s_1 }; // FRU ... - //~^ ERROR field `secret_uid` of struct `foo::S` is private + //~^ ERROR field `secret_uid` of struct `S` is private println!("main forged an S named: {}", s_2.b); // at end of scope, ... both s_1 *and* s_2 get dropped. Boom! } diff --git a/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr b/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr index 2aeffc3e5e..0b8af90b41 100644 --- a/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr +++ b/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr @@ -1,4 +1,4 @@ -error[E0451]: field `secret_uid` of struct `foo::S` is private +error[E0451]: field `secret_uid` of struct `S` is private --> $DIR/functional-struct-update-respects-privacy.rs:28:49 | LL | let s_2 = foo::S { b: format!("ess two"), ..s_1 }; // FRU ... diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr index 9699abd566..16a5ab2cc8 100644 --- a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr +++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as std::ops::Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]` --> $DIR/generator-yielding-or-returning-itself.rs:15:5 | LL | pub fn want_cyclic_generator_return(_: T) @@ -14,7 +14,7 @@ LL | want_cyclic_generator_return(|| { see issue #46062 for more information -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as std::ops::Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` --> $DIR/generator-yielding-or-returning-itself.rs:28:5 | LL | pub fn want_cyclic_generator_yield(_: T) diff --git a/src/test/ui/generator/issue-68112.rs b/src/test/ui/generator/issue-68112.rs index 9ab2abf740..feb07c9bf8 100644 --- a/src/test/ui/generator/issue-68112.rs +++ b/src/test/ui/generator/issue-68112.rs @@ -50,7 +50,7 @@ fn test2() { yield; }; require_send(send_gen); - //~^ ERROR `std::cell::RefCell` cannot be shared between threads safely + //~^ ERROR `RefCell` cannot be shared between threads safely } fn main() {} diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr index 83536f2af1..96a8d6d70e 100644 --- a/src/test/ui/generator/issue-68112.stderr +++ b/src/test/ui/generator/issue-68112.stderr @@ -7,33 +7,33 @@ LL | fn require_send(_: impl Send) {} LL | require_send(send_gen); | ^^^^^^^^^^^^ generator is not `Send` | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = help: the trait `Sync` is not implemented for `RefCell` note: generator is not `Send` as this value is used across a yield --> $DIR/issue-68112.rs:31:9 | LL | let _non_send_gen = make_non_send_generator(); - | ------------- has type `impl std::ops::Generator` which is not `Send` + | ------------- has type `impl Generator` which is not `Send` LL | yield; | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later LL | }; | - `_non_send_gen` is later dropped here -error[E0277]: `std::cell::RefCell` cannot be shared between threads safely +error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/issue-68112.rs:52:5 | LL | fn require_send(_: impl Send) {} | ---- required by this bound in `require_send` ... LL | require_send(send_gen); - | ^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc>` - = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6 t:std::sync::Arc> {()}]` - = note: required because it appears within the type `impl std::ops::Generator` - = note: required because it appears within the type `impl std::ops::Generator` - = note: required because it appears within the type `{impl std::ops::Generator, ()}` - = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6 {impl std::ops::Generator, ()}]` + = help: the trait `Sync` is not implemented for `RefCell` + = note: required because of the requirements on the impl of `Send` for `Arc>` + = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6 {()}]` + = note: required because it appears within the type `impl Generator` + = note: required because it appears within the type `impl Generator` + = note: required because it appears within the type `{impl Generator, ()}` + = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6 {impl Generator, ()}]` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 5df2c1b52f..2384ed3d24 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -1,31 +1,31 @@ -error[E0277]: `std::cell::Cell` cannot be shared between threads safely +error[E0277]: `Cell` cannot be shared between threads safely --> $DIR/not-send-sync.rs:16:5 | LL | fn assert_send(_: T) {} - | ---- required by this bound in `main::assert_send` + | ---- required by this bound in `assert_send` ... LL | assert_send(|| { - | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely + | ^^^^^^^^^^^ `Cell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` - = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell` - = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 a:&std::cell::Cell _]` + = help: the trait `Sync` is not implemented for `Cell` + = note: required because of the requirements on the impl of `Send` for `&Cell` + = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 _]` error: generator cannot be shared between threads safely --> $DIR/not-send-sync.rs:9:5 | LL | fn assert_sync(_: T) {} - | ---- required by this bound in `main::assert_sync` + | ---- required by this bound in `assert_sync` ... LL | assert_sync(|| { | ^^^^^^^^^^^ generator is not `Sync` | - = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` + = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {Cell, ()}]`, the trait `Sync` is not implemented for `Cell` note: generator is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:12:9 | LL | let a = Cell::new(2); - | - has type `std::cell::Cell` which is not `Sync` + | - has type `Cell` which is not `Sync` LL | yield; | ^^^^^ yield occurs here, with `a` maybe used later LL | }); diff --git a/src/test/ui/generator/print/generator-print-verbose-1.rs b/src/test/ui/generator/print/generator-print-verbose-1.rs new file mode 100644 index 0000000000..fe0687722b --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-1.rs @@ -0,0 +1,60 @@ +// compile-flags: -Zverbose + +// Same as: src/test/ui/generator/issue-68112.stderr + +#![feature(generators, generator_trait)] + +use std::{ + cell::RefCell, + sync::Arc, + pin::Pin, + ops::{Generator, GeneratorState}, +}; + +pub struct Ready(Option); +impl Generator<()> for Ready { + type Return = T; + type Yield = (); + fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> { + GeneratorState::Complete(self.0.take().unwrap()) + } +} +pub fn make_gen1(t: T) -> Ready { + Ready(Some(t)) +} + +fn require_send(_: impl Send) {} + +fn make_non_send_generator() -> impl Generator>> { + make_gen1(Arc::new(RefCell::new(0))) +} + +fn test1() { + let send_gen = || { + let _non_send_gen = make_non_send_generator(); + yield; + }; + require_send(send_gen); + //~^ ERROR generator cannot be sent between threads +} + +pub fn make_gen2(t: T) -> impl Generator { + || { + yield; + t + } +} +fn make_non_send_generator2() -> impl Generator>> { + make_gen2(Arc::new(RefCell::new(0))) +} + +fn test2() { + let send_gen = || { + let _non_send_gen = make_non_send_generator2(); + yield; + }; + require_send(send_gen); + //~^ ERROR `RefCell` cannot be shared between threads safely +} + +fn main() {} diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr new file mode 100644 index 0000000000..b5c63584c6 --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr @@ -0,0 +1,40 @@ +error: generator cannot be sent between threads safely + --> $DIR/generator-print-verbose-1.rs:37:5 + | +LL | fn require_send(_: impl Send) {} + | ---- required by this bound in `require_send` +... +LL | require_send(send_gen); + | ^^^^^^^^^^^^ generator is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell` +note: generator is not `Send` as this value is used across a yield + --> $DIR/generator-print-verbose-1.rs:35:9 + | +LL | let _non_send_gen = make_non_send_generator(); + | ------------- has type `Opaque(DefId(0:24 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later +LL | }; + | - `_non_send_gen` is later dropped here + +error[E0277]: `RefCell` cannot be shared between threads safely + --> $DIR/generator-print-verbose-1.rs:56:5 + | +LL | fn require_send(_: impl Send) {} + | ---- required by this bound in `require_send` +... +LL | require_send(send_gen); + | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell` + = note: required because of the requirements on the impl of `Send` for `Arc>` + = note: required because it appears within the type `[make_gen2>>::{closure#0} upvar_tys=(Arc>) {()}]` + = note: required because it appears within the type `Opaque(DefId(0:29 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc>])` + = note: required because it appears within the type `Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])` + = note: required because it appears within the type `{Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}` + = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/print/generator-print-verbose-2.rs b/src/test/ui/generator/print/generator-print-verbose-2.rs new file mode 100644 index 0000000000..d914719cb3 --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-2.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zverbose + +// Same as test/ui/generator/not-send-sync.rs +#![feature(generators)] + +use std::cell::Cell; + +fn main() { + fn assert_sync(_: T) {} + fn assert_send(_: T) {} + + assert_sync(|| { + //~^ ERROR: generator cannot be shared between threads safely + let a = Cell::new(2); + yield; + }); + + let a = Cell::new(2); + assert_send(|| { + //~^ ERROR: E0277 + drop(&a); + yield; + }); +} diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr new file mode 100644 index 0000000000..cc45d5631c --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr @@ -0,0 +1,36 @@ +error[E0277]: `Cell` cannot be shared between threads safely + --> $DIR/generator-print-verbose-2.rs:19:5 + | +LL | fn assert_send(_: T) {} + | ---- required by this bound in `assert_send` +... +LL | assert_send(|| { + | ^^^^^^^^^^^ `Cell` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell` + = note: required because of the requirements on the impl of `Send` for `&'_#3r Cell` + = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell) _#16t]` + +error: generator cannot be shared between threads safely + --> $DIR/generator-print-verbose-2.rs:12:5 + | +LL | fn assert_sync(_: T) {} + | ---- required by this bound in `assert_sync` +... +LL | assert_sync(|| { + | ^^^^^^^^^^^ generator is not `Sync` + | + = help: within `[main::{closure#0} upvar_tys=() {Cell, ()}]`, the trait `Sync` is not implemented for `Cell` +note: generator is not `Sync` as this value is used across a yield + --> $DIR/generator-print-verbose-2.rs:15:9 + | +LL | let a = Cell::new(2); + | - has type `Cell` which is not `Sync` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | }); + | - `a` is later dropped here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/print/generator-print-verbose-3.rs b/src/test/ui/generator/print/generator-print-verbose-3.rs new file mode 100644 index 0000000000..8689539ec8 --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-3.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zverbose + +#![feature(generators, generator_trait)] + +fn main() { + let x = "Type mismatch test"; + let generator :() = || { + //~^ ERROR mismatched types + yield 1i32; + return x + }; +} diff --git a/src/test/ui/generator/print/generator-print-verbose-3.stderr b/src/test/ui/generator/print/generator-print-verbose-3.stderr new file mode 100644 index 0000000000..0ce108dfd6 --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-3.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/generator-print-verbose-3.rs:7:25 + | +LL | let generator :() = || { + | ____________________--___^ + | | | + | | expected due to this +LL | | +LL | | yield 1i32; +LL | | return x +LL | | }; + | |_____^ expected `()`, found generator + | + = note: expected unit type `()` + found generator `[main::{closure#0} upvar_tys=(unavailable) _#5t]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generator/resume-arg-late-bound.stderr b/src/test/ui/generator/resume-arg-late-bound.stderr index c379d9eae8..dc0864165a 100644 --- a/src/test/ui/generator/resume-arg-late-bound.stderr +++ b/src/test/ui/generator/resume-arg-late-bound.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | test(gen); | ^^^^ one type is more general than the other | - = note: expected type `for<'a> std::ops::Generator<&'a mut bool>` - found type `std::ops::Generator<&mut bool>` + = note: expected type `for<'a> Generator<&'a mut bool>` + found type `Generator<&mut bool>` error[E0308]: mismatched types --> $DIR/resume-arg-late-bound.rs:15:5 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | test(gen); | ^^^^ one type is more general than the other | - = note: expected type `for<'a> std::ops::Generator<&'a mut bool>` - found type `std::ops::Generator<&mut bool>` + = note: expected type `for<'a> Generator<&'a mut bool>` + found type `Generator<&mut bool>` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 379bd8ebd1..2bcf66dbea 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -8,7 +8,7 @@ LL | | yield s[..]; LL | | }; | |____^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: the yield type of a generator must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -17,7 +17,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | Pin::new(&mut gen).resume(()); | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/static-generators.rs b/src/test/ui/generator/static-generators.rs index 3980766c42..d098bf1e68 100644 --- a/src/test/ui/generator/static-generators.rs +++ b/src/test/ui/generator/static-generators.rs @@ -12,7 +12,7 @@ fn main() { yield; assert_eq!(b as *const _, &a as *const _); }; - // Safety: We shadow the original generator variable so have no safe API to + // SAFETY: We shadow the original generator variable so have no safe API to // move it after this point. let mut generator = unsafe { Pin::new_unchecked(&mut generator) }; assert_eq!(generator.as_mut().resume(()), GeneratorState::Yielded(())); diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index 3bb899cd89..216b707bb1 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -5,7 +5,7 @@ LL | fn assert_unpin(_: T) { | ----- required by this bound in `assert_unpin` ... LL | assert_unpin(generator); - | ^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` + | ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` error: aborting due to previous error diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr index 8de77798ff..260fbb2ec7 100644 --- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -7,7 +7,7 @@ LL | 5 = note: expected type `std::result::Result<{integer}, _>` found type `{integer}` -error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as std::ops::Generator>::Return == i32` +error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as Generator>::Return == i32` --> $DIR/type-mismatch-signature-deduction.rs:5:13 | LL | fn foo() -> impl Generator { diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr index 4d02f2c46a..c95765d906 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr @@ -5,7 +5,7 @@ LL | type Assoc3; | --------------- definition of `Assoc3` from trait ... LL | type Assoc3 where T: Iterator = Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs index 3ffa6c6eec..77bebc9854 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.rs +++ b/src/test/ui/generic-associated-types/impl_bounds.rs @@ -17,7 +17,7 @@ impl Foo for Fooy { type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); //~^ ERROR lifetime bound not satisfied type C where Self: Copy = String; - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } fn main() {} diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index e06977ebbe..0546e38a33 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -24,18 +24,18 @@ note: but lifetime parameter must outlive the lifetime `'a` as defined on the as LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/impl_bounds.rs:19:5 | LL | type C where Self: Copy = String; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `Fooy` - = note: the requirement `Fooy: std::marker::Copy` appears on the associated impl type but not on the corresponding associated trait type + = note: required because of the requirements on the impl of `Copy` for `Fooy` + = note: the requirement `Fooy: Copy` appears on the associated impl type but not on the corresponding associated trait type help: consider restricting type parameter `T` | -LL | impl Foo for Fooy { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for Fooy { + | ^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr index bc5c40ff02..439b8ab90c 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr @@ -5,7 +5,7 @@ LL | type Assoc3; | --------------- definition of `Assoc3` from trait ... LL | type Assoc3 where T: Iterator = Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs index 71f9b2967d..0020887eae 100644 --- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs @@ -13,7 +13,7 @@ trait UnsafeCopy { impl UnsafeCopy for T { type Item<'a> = T; - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr index 834bc3b787..6ba79dd543 100644 --- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr @@ -7,19 +7,19 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-68641-check-gat-bounds.rs:15:5 | LL | type Item<'a>: Copy; | -------------------- required by `UnsafeCopy::Item` ... LL | type Item<'a> = T; - | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UnsafeCopy for T { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl UnsafeCopy for T { + | ^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs index c99073c132..ff8d2ca05b 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs @@ -13,7 +13,7 @@ trait Fun { impl Fun for T { type F<'a> = Self; - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn<()>` closure, found `T` } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr index 2fe266b801..15a66e25b1 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` +error[E0277]: expected a `Fn<()>` closure, found `T` --> $DIR/issue-68642-broken-llvm-ir.rs:15:5 | LL | type F<'a>: Fn() -> u32; @@ -19,8 +19,8 @@ LL | type F<'a> = Self; = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | -LL | impl> Fun for T { - | ^^^^^^^^^^^^^^^^^^ +LL | impl> Fun for T { + | ^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs index 24133e75cc..2107804a8b 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs @@ -13,7 +13,7 @@ trait Fun { impl Fun for T { type F<'a> = Self; - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn<()>` closure, found `T` } pub fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr index e335523778..9b2ddb2326 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` +error[E0277]: expected a `Fn<()>` closure, found `T` --> $DIR/issue-68643-broken-mir.rs:15:5 | LL | type F<'a>: Fn() -> u32; @@ -19,8 +19,8 @@ LL | type F<'a> = Self; = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | -LL | impl> Fun for T { - | ^^^^^^^^^^^^^^^^^^ +LL | impl> Fun for T { + | ^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs index 22620c61b8..bfe63b1be7 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs @@ -13,7 +13,7 @@ trait Fun { impl Fun for T { type F<'a> = Self; - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn<()>` closure, found `T` } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr index d7a5bb0ebe..f7bfab3505 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` +error[E0277]: expected a `Fn<()>` closure, found `T` --> $DIR/issue-68644-codegen-selection.rs:15:5 | LL | type F<'a>: Fn() -> u32; @@ -19,8 +19,8 @@ LL | type F<'a> = Self; = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | -LL | impl> Fun for T { - | ^^^^^^^^^^^^^^^^^^ +LL | impl> Fun for T { + | ^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs index 423b80e847..676dcf9023 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs @@ -13,7 +13,7 @@ trait Fun { impl Fun for T { type F<'a> = Self; - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn<()>` closure, found `T` } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr index 0670625aa2..6c2d330a19 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` +error[E0277]: expected a `Fn<()>` closure, found `T` --> $DIR/issue-68645-codegen-fulfillment.rs:15:5 | LL | type F<'a>: Fn() -> u32; @@ -19,8 +19,8 @@ LL | type F<'a> = Self; = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | -LL | impl> Fun for T { - | ^^^^^^^^^^^^^^^^^^ +LL | impl> Fun for T { + | ^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs index 4ccd42ba64..f682bdd8ac 100644 --- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs @@ -14,7 +14,7 @@ trait UnsafeCopy { impl UnsafeCopy for T { type Item<'a> = T; - //~^ ERROR type mismatch resolving `::Target == T` + //~^ ERROR type mismatch resolving `::Target == T` } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr index e1ceeac319..a9336151b6 100644 --- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0271]: type mismatch resolving `::Target == T` +error[E0271]: type mismatch resolving `::Target == T` --> $DIR/issue-68656-unsized-values.rs:16:5 | LL | type Item<'a>: std::ops::Deref; @@ -19,11 +19,11 @@ LL | type Item<'a> = T; | ^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type | = note: expected type parameter `T` - found associated type `::Target` + found associated type `::Target` help: consider further restricting this bound | -LL | impl> UnsafeCopy for T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl> UnsafeCopy for T { + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed index 3ba7d043d0..54478d1628 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.fixed +++ b/src/test/ui/generic-associated-types/missing-bounds.fixed @@ -4,7 +4,7 @@ use std::ops::Add; struct A(B); -impl Add for A where B: Add + std::ops::Add { +impl Add for A where B: Add + Add { type Output = Self; fn add(self, rhs: Self) -> Self { @@ -14,7 +14,7 @@ impl Add for A where B: Add + std::ops::Add { struct C(B); -impl> Add for C { +impl> Add for C { type Output = Self; fn add(self, rhs: Self) -> Self { diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr index 630ceac093..4d4f7e5587 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.stderr +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -8,11 +8,11 @@ LL | A(self.0 + rhs.0) | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type | = note: expected type parameter `B` - found associated type `::Output` + found associated type `::Output` help: consider further restricting this bound | -LL | impl Add for A where B: Add + std::ops::Add { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Add for A where B: Add + Add { + | ^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/missing-bounds.rs:21:14 @@ -24,11 +24,11 @@ LL | Self(self.0 + rhs.0) | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type | = note: expected type parameter `B` - found associated type `::Output` + found associated type `::Output` help: consider further restricting this bound | -LL | impl> Add for C { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl> Add for C { + | ^^^^^^^^^^^^^^^^^ error[E0369]: cannot add `B` to `B` --> $DIR/missing-bounds.rs:31:21 diff --git a/src/test/ui/generic/generic-type-params-name-repr.rs b/src/test/ui/generic/generic-type-params-name-repr.rs index 45dc85a252..6e0beec663 100644 --- a/src/test/ui/generic/generic-type-params-name-repr.rs +++ b/src/test/ui/generic/generic-type-params-name-repr.rs @@ -27,12 +27,12 @@ fn main() { let _: HashMap = (); //~^ ERROR mismatched types //~| expected struct `HashMap`, found `()` - //~| expected struct `HashMap` + //~| expected struct `HashMap` //~| found unit type `()` let _: HashMap> = (); //~^ ERROR mismatched types //~| expected struct `HashMap`, found `()` - //~| expected struct `HashMap` + //~| expected struct `HashMap` //~| found unit type `()` // But not when there's a different type in between. diff --git a/src/test/ui/generic/generic-type-params-name-repr.stderr b/src/test/ui/generic/generic-type-params-name-repr.stderr index 1418076611..4c3c003965 100644 --- a/src/test/ui/generic/generic-type-params-name-repr.stderr +++ b/src/test/ui/generic/generic-type-params-name-repr.stderr @@ -28,7 +28,7 @@ LL | let _: HashMap = (); | | | expected due to this | - = note: expected struct `HashMap` + = note: expected struct `HashMap` found unit type `()` error[E0308]: mismatched types @@ -39,7 +39,7 @@ LL | let _: HashMap> = (); | | | expected due to this | - = note: expected struct `HashMap` + = note: expected struct `HashMap` found unit type `()` error[E0308]: mismatched types diff --git a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr index 7a6c07d4e0..2b88a6046f 100644 --- a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr +++ b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr @@ -7,7 +7,7 @@ LL | LL | impl Tsized for () {} | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[()]` + = help: the trait `Sized` is not implemented for `[()]` error: aborting due to previous error diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs index 7cddf5f652..b08732219d 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs @@ -2,7 +2,7 @@ #![feature(exclusive_range_pattern)] fn main() { - let "a".. = "a"; //~ ERROR only char and numeric types are allowed in range patterns - let .."a" = "a"; //~ ERROR only char and numeric types are allowed in range patterns - let ..="a" = "a"; //~ ERROR only char and numeric types are allowed in range patterns + let "a".. = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns + let .."a" = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns + let ..="a" = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns } diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr index 68ca363715..df0dae5696 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr @@ -1,16 +1,16 @@ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/half-open-range-pats-bad-types.rs:5:9 | LL | let "a".. = "a"; | ^^^ this is of type `&'static str` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/half-open-range-pats-bad-types.rs:6:11 | LL | let .."a" = "a"; | ^^^ this is of type `&'static str` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/half-open-range-pats-bad-types.rs:7:12 | LL | let ..="a" = "a"; diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr index 92a8582503..f6acb34982 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr @@ -8,8 +8,8 @@ LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u3 LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } | |_____________________________________________- in this macro invocation | - = note: expected enum `std::option::Option fn(&'a u32, &'b u32) -> &'a u32>` - found enum `std::option::Option fn(&'a u32, &'a u32) -> &'a u32>` + = note: expected enum `Option fn(&'a u32, &'b u32) -> &'a u32>` + found enum `Option fn(&'a u32, &'a u32) -> &'a u32>` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr index 98f5bff732..ebad4b93dc 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr @@ -8,8 +8,8 @@ LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), LL | | fn(&'x u32)) } | |______________- in this macro invocation | - = note: expected enum `std::option::Option fn(&'a u32)>` - found enum `std::option::Option` + = note: expected enum `Option fn(&'a u32)>` + found enum `Option` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr index 100ba6ac27..40a0ff97b6 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr @@ -8,8 +8,8 @@ LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } | |__________________________________- in this macro invocation | - = note: expected enum `std::option::Option fn(Inv<'a>, Inv<'b>)>` - found enum `std::option::Option fn(Inv<'a>, Inv<'a>)>` + = note: expected enum `Option fn(Inv<'a>, Inv<'b>)>` + found enum `Option fn(Inv<'a>, Inv<'a>)>` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr index 3c8af20e50..d2f40f7fb5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr @@ -8,8 +8,8 @@ LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), LL | | fn(Inv<'y>)) } | |______________- in this macro invocation | - = note: expected enum `std::option::Option)>` - found enum `std::option::Option)>` + = note: expected enum `Option)>` + found enum `Option)>` note: the lifetime `'x` as defined on the function body at 38:20... --> $DIR/hr-subtype.rs:38:20 | @@ -40,8 +40,8 @@ LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), LL | | fn(Inv<'y>)) } | |______________- in this macro invocation | - = note: expected enum `std::option::Option)>` - found enum `std::option::Option)>` + = note: expected enum `Option)>` + found enum `Option)>` note: the lifetime `'x` as defined on the function body at 44:22... --> $DIR/hr-subtype.rs:44:22 | diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr index 7b4cdd4a41..57610beb86 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr @@ -8,8 +8,8 @@ LL | / check! { free_x_vs_free_y: (fn(&'x u32), LL | | fn(&'y u32)) } | |______________- in this macro invocation | - = note: expected enum `std::option::Option` - found enum `std::option::Option` + = note: expected enum `Option` + found enum `Option` note: the lifetime `'x` as defined on the function body at 44:22... --> $DIR/hr-subtype.rs:44:22 | diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr index 720e2276d5..8bd23aa901 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -7,8 +7,8 @@ LL | trait Trait {} LL | foo::<()>(); | ^^^^^^^^^ implementation of `Trait` is not general enough | - = note: `()` must implement `Trait fn(std::cell::Cell<&'b u32>)>` - = note: ...but `()` actually implements `Trait)>`, for some specific lifetime `'0` + = note: `()` must implement `Trait fn(Cell<&'b u32>)>` + = note: ...but `()` actually implements `Trait)>`, for some specific lifetime `'0` error: aborting due to previous error diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr index 1c7bfa65d7..2342a4f6e1 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr @@ -9,7 +9,7 @@ LL | let v = Unit2.m( = help: consider constraining the associated type `<_ as Ty<'_>>::V` to `Unit4` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html -error[E0271]: type mismatch resolving `<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as std::ops::FnOnce<((&u8,),)>>::Output == Unit3` +error[E0271]: type mismatch resolving `<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as FnOnce<((&u8,),)>>::Output == Unit3` --> $DIR/issue-62203-hrtb-ice.rs:38:19 | LL | let v = Unit2.m( diff --git a/src/test/ui/huge-enum.stderr b/src/test/ui/huge-enum.stderr index 8398c511b9..a069c37b80 100644 --- a/src/test/ui/huge-enum.stderr +++ b/src/test/ui/huge-enum.stderr @@ -1,4 +1,4 @@ -error: the type `TYPE` is too big for the current architecture +error: the type `Option` is too big for the current architecture --> $DIR/huge-enum.rs:16:9 | LL | let big: BIG = None; diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs index 06d62656e9..571017df4d 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs @@ -9,7 +9,7 @@ macro a() { mod u { // Late resolution. fn f() { my_core::mem::drop(0); } - //~^ ERROR failed to resolve: use of undeclared type or module `my_core` + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` } } @@ -22,7 +22,7 @@ mod v { mod u { // Late resolution. fn f() { my_core::mem::drop(0); } - //~^ ERROR failed to resolve: use of undeclared type or module `my_core` + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` } fn main() {} diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr index b9e05c84a8..d3e6021a1e 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr @@ -18,22 +18,22 @@ LL | a!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `my_core` +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:11:18 | LL | fn f() { my_core::mem::drop(0); } - | ^^^^^^^ use of undeclared type or module `my_core` + | ^^^^^^^ use of undeclared crate or module `my_core` ... LL | a!(); | ----- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `my_core` +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:24:14 | LL | fn f() { my_core::mem::drop(0); } - | ^^^^^^^ use of undeclared type or module `my_core` + | ^^^^^^^ use of undeclared crate or module `my_core` error: aborting due to 4 previous errors diff --git a/src/test/ui/hygiene/fields.rs b/src/test/ui/hygiene/fields.rs index 597019cb1e..7a417b46fc 100644 --- a/src/test/ui/hygiene/fields.rs +++ b/src/test/ui/hygiene/fields.rs @@ -15,8 +15,8 @@ mod foo { let s = S { x: 0 }; //~ ERROR type `foo::S` is private let _ = s.x; //~ ERROR type `foo::S` is private - let t = T(0); //~ ERROR type `foo::T` is private - let _ = t.0; //~ ERROR type `foo::T` is private + let t = T(0); //~ ERROR type `T` is private + let _ = t.0; //~ ERROR type `T` is private let s = $S { $x: 0, x: 1 }; assert_eq!((s.$x, s.x), (0, 1)); diff --git a/src/test/ui/hygiene/fields.stderr b/src/test/ui/hygiene/fields.stderr index 6d78440801..3666aeabfa 100644 --- a/src/test/ui/hygiene/fields.stderr +++ b/src/test/ui/hygiene/fields.stderr @@ -20,7 +20,7 @@ LL | let s = foo::m!(S, x); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `foo::T` is private +error: type `T` is private --> $DIR/fields.rs:18:17 | LL | let t = T(0); @@ -31,7 +31,7 @@ LL | let s = foo::m!(S, x); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `foo::T` is private +error: type `T` is private --> $DIR/fields.rs:19:17 | LL | let _ = t.0; diff --git a/src/test/ui/hygiene/intercrate.rs b/src/test/ui/hygiene/intercrate.rs index 2acbc893cf..d9b5b789e4 100644 --- a/src/test/ui/hygiene/intercrate.rs +++ b/src/test/ui/hygiene/intercrate.rs @@ -8,5 +8,5 @@ extern crate intercrate; fn main() { assert_eq!(intercrate::foo::m!(), 1); - //~^ ERROR type `fn() -> u32 {intercrate::foo::bar::f}` is private + //~^ ERROR type `fn() -> u32 {foo::bar::f}` is private } diff --git a/src/test/ui/hygiene/intercrate.stderr b/src/test/ui/hygiene/intercrate.stderr index c27ba74a26..cd593abf53 100644 --- a/src/test/ui/hygiene/intercrate.stderr +++ b/src/test/ui/hygiene/intercrate.stderr @@ -1,4 +1,4 @@ -error: type `fn() -> u32 {intercrate::foo::bar::f}` is private +error: type `fn() -> u32 {foo::bar::f}` is private --> $DIR/intercrate.rs:10:16 | LL | assert_eq!(intercrate::foo::m!(), 1); diff --git a/src/test/ui/hygiene/nested_macro_privacy.rs b/src/test/ui/hygiene/nested_macro_privacy.rs index bee90e2bb8..dea9101ee0 100644 --- a/src/test/ui/hygiene/nested_macro_privacy.rs +++ b/src/test/ui/hygiene/nested_macro_privacy.rs @@ -12,6 +12,6 @@ n!(foo, S, i, m); fn main() { use foo::{S, m}; - S::default().i; //~ ERROR field `i` of struct `foo::S` is private + S::default().i; //~ ERROR field `i` of struct `S` is private m!(S::default()); // ok } diff --git a/src/test/ui/hygiene/nested_macro_privacy.stderr b/src/test/ui/hygiene/nested_macro_privacy.stderr index 482957a326..1d11cd0f57 100644 --- a/src/test/ui/hygiene/nested_macro_privacy.stderr +++ b/src/test/ui/hygiene/nested_macro_privacy.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `i` of struct `foo::S` is private +error[E0616]: field `i` of struct `S` is private --> $DIR/nested_macro_privacy.rs:15:18 | LL | S::default().i; diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index 990210ffb6..3c0c045077 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(0, 0); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `Vec` +error[E0433]: failed to resolve: use of undeclared type `Vec` --> $DIR/no_implicit_prelude.rs:11:9 | LL | fn f() { ::bar::m!(); } diff --git a/src/test/ui/if/ifmt-unimpl.rs b/src/test/ui/if/ifmt-unimpl.rs index 65daae4b25..258f4eea50 100644 --- a/src/test/ui/if/ifmt-unimpl.rs +++ b/src/test/ui/if/ifmt-unimpl.rs @@ -1,4 +1,4 @@ fn main() { format!("{:X}", "3"); - //~^ ERROR: `str: std::fmt::UpperHex` is not satisfied + //~^ ERROR: `str: UpperHex` is not satisfied } diff --git a/src/test/ui/if/ifmt-unimpl.stderr b/src/test/ui/if/ifmt-unimpl.stderr index a142896ada..65b0f4a09b 100644 --- a/src/test/ui/if/ifmt-unimpl.stderr +++ b/src/test/ui/if/ifmt-unimpl.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `str: std::fmt::UpperHex` is not satisfied +error[E0277]: the trait bound `str: UpperHex` is not satisfied --> $DIR/ifmt-unimpl.rs:2:21 | LL | format!("{:X}", "3"); - | ^^^ the trait `std::fmt::UpperHex` is not implemented for `str` + | ^^^ the trait `UpperHex` is not implemented for `str` | - = note: required because of the requirements on the impl of `std::fmt::UpperHex` for `&str` + = note: required because of the requirements on the impl of `UpperHex` for `&str` = note: required by `std::fmt::UpperHex::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/ifmt.rs b/src/test/ui/ifmt.rs deleted file mode 100644 index 27ab3d6b7a..0000000000 --- a/src/test/ui/ifmt.rs +++ /dev/null @@ -1,319 +0,0 @@ -// run-pass - -#![deny(warnings)] -#![allow(unused_must_use)] -#![allow(unused_features)] -#![feature(box_syntax)] - -use std::cell::RefCell; -use std::fmt::{self, Write}; -use std::usize; - -struct A; -struct B; -struct C; -struct D; - -impl fmt::LowerHex for A { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("aloha") - } -} -impl fmt::UpperHex for B { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("adios") - } -} -impl fmt::Display for C { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad_integral(true, "☃", "123") - } -} -impl fmt::Binary for D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("aa")?; - f.write_char('☃')?; - f.write_str("bb") - } -} - -macro_rules! t { - ($a:expr, $b:expr) => { assert_eq!($a, $b) } -} - -pub fn main() { - // Various edge cases without formats - t!(format!(""), ""); - t!(format!("hello"), "hello"); - t!(format!("hello {{"), "hello {"); - - // default formatters should work - t!(format!("{}", 1.0f32), "1"); - t!(format!("{}", 1.0f64), "1"); - t!(format!("{}", "a"), "a"); - t!(format!("{}", "a".to_string()), "a"); - t!(format!("{}", false), "false"); - t!(format!("{}", 'a'), "a"); - - // At least exercise all the formats - t!(format!("{}", true), "true"); - t!(format!("{}", '☃'), "☃"); - t!(format!("{}", 10), "10"); - t!(format!("{}", 10_usize), "10"); - t!(format!("{:?}", '☃'), "'☃'"); - t!(format!("{:?}", 10), "10"); - t!(format!("{:?}", 10_usize), "10"); - t!(format!("{:?}", "true"), "\"true\""); - t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); - t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), - r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#); - t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), - r#""foo\u{0}bar\u{1}baz\u{7f}qux""#); - t!(format!("{:o}", 10_usize), "12"); - t!(format!("{:x}", 10_usize), "a"); - t!(format!("{:X}", 10_usize), "A"); - t!(format!("{}", "foo"), "foo"); - t!(format!("{}", "foo".to_string()), "foo"); - if cfg!(target_pointer_width = "32") { - t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234"); - t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234"); - } else { - t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234"); - t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234"); - } - t!(format!("{:p}", 0x1234 as *const isize), "0x1234"); - t!(format!("{:p}", 0x1234 as *mut isize), "0x1234"); - t!(format!("{:x}", A), "aloha"); - t!(format!("{:X}", B), "adios"); - t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); - t!(format!("{1} {0}", 0, 1), "1 0"); - t!(format!("{foo} {bar}", foo=0, bar=1), "0 1"); - t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0"); - t!(format!("{} {0}", "a"), "a a"); - t!(format!("{_foo}", _foo = 6usize), "6"); - t!(format!("{foo_bar}", foo_bar=1), "1"); - t!(format!("{}", 5 + 5), "10"); - t!(format!("{:#4}", C), "☃123"); - t!(format!("{:b}", D), "aa☃bb"); - - let a: &dyn fmt::Debug = &1; - t!(format!("{:?}", a), "1"); - - // Formatting strings and their arguments - t!(format!("{}", "a"), "a"); - t!(format!("{:4}", "a"), "a "); - t!(format!("{:4}", "☃"), "☃ "); - t!(format!("{:>4}", "a"), " a"); - t!(format!("{:<4}", "a"), "a "); - t!(format!("{:^5}", "a"), " a "); - t!(format!("{:^5}", "aa"), " aa "); - t!(format!("{:^4}", "a"), " a "); - t!(format!("{:^4}", "aa"), " aa "); - t!(format!("{:.4}", "a"), "a"); - t!(format!("{:4.4}", "a"), "a "); - t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), " aaaa"); - t!(format!("{:2.4}", "aaaaa"), "aaaa"); - t!(format!("{:2.4}", "aaaa"), "aaaa"); - t!(format!("{:2.4}", "aaa"), "aaa"); - t!(format!("{:2.4}", "aa"), "aa"); - t!(format!("{:2.4}", "a"), "a "); - t!(format!("{:0>2}", "a"), "0a"); - t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); - t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa"); - t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a=4), "aaaa"); - t!(format!("{:1$}", "a", 4), "a "); - t!(format!("{1:0$}", 4, "a"), "a "); - t!(format!("{:a$}", "a", a=4), "a "); - t!(format!("{:-#}", "a"), "a"); - t!(format!("{:+#}", "a"), "a"); - t!(format!("{:/^10.8}", "1234567890"), "/12345678/"); - - // Some float stuff - t!(format!("{:}", 1.0f32), "1"); - t!(format!("{:}", 1.0f64), "1"); - t!(format!("{:.3}", 1.0f64), "1.000"); - t!(format!("{:10.3}", 1.0f64), " 1.000"); - t!(format!("{:+10.3}", 1.0f64), " +1.000"); - t!(format!("{:+10.3}", -1.0f64), " -1.000"); - - t!(format!("{:e}", 1.2345e6f32), "1.2345e6"); - t!(format!("{:e}", 1.2345e6f64), "1.2345e6"); - t!(format!("{:E}", 1.2345e6f64), "1.2345E6"); - t!(format!("{:.3e}", 1.2345e6f64), "1.234e6"); - t!(format!("{:10.3e}", 1.2345e6f64), " 1.234e6"); - t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6"); - t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); - - // Float edge cases - t!(format!("{}", -0.0), "0"); - t!(format!("{:?}", -0.0), "-0.0"); - t!(format!("{:?}", 0.0), "0.0"); - - // sign aware zero padding - t!(format!("{:<3}", 1), "1 "); - t!(format!("{:>3}", 1), " 1"); - t!(format!("{:^3}", 1), " 1 "); - t!(format!("{:03}", 1), "001"); - t!(format!("{:<03}", 1), "001"); - t!(format!("{:>03}", 1), "001"); - t!(format!("{:^03}", 1), "001"); - t!(format!("{:+03}", 1), "+01"); - t!(format!("{:<+03}", 1), "+01"); - t!(format!("{:>+03}", 1), "+01"); - t!(format!("{:^+03}", 1), "+01"); - t!(format!("{:#05x}", 1), "0x001"); - t!(format!("{:<#05x}", 1), "0x001"); - t!(format!("{:>#05x}", 1), "0x001"); - t!(format!("{:^#05x}", 1), "0x001"); - t!(format!("{:05}", 1.2), "001.2"); - t!(format!("{:<05}", 1.2), "001.2"); - t!(format!("{:>05}", 1.2), "001.2"); - t!(format!("{:^05}", 1.2), "001.2"); - t!(format!("{:05}", -1.2), "-01.2"); - t!(format!("{:<05}", -1.2), "-01.2"); - t!(format!("{:>05}", -1.2), "-01.2"); - t!(format!("{:^05}", -1.2), "-01.2"); - t!(format!("{:+05}", 1.2), "+01.2"); - t!(format!("{:<+05}", 1.2), "+01.2"); - t!(format!("{:>+05}", 1.2), "+01.2"); - t!(format!("{:^+05}", 1.2), "+01.2"); - - // Ergonomic format_args! - t!(format!("{0:x} {0:X}", 15), "f F"); - t!(format!("{0:x} {0:X} {}", 15), "f F 15"); - t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a=15), "dDfEeF"); - t!(format!("{a:x} {a:X}", a=15), "f F"); - - // And its edge cases - t!(format!("{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}", - 4, a="abcdefg", b="hijklmn", c=3), - "abcd hijk 4\nabc hij 3"); - t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a="abcdef"), "abcd 4 efg"); - t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a=2), "aa 2 0x2"); - - // Test that pointers don't get truncated. - { - let val = usize::MAX; - let exp = format!("{:#x}", val); - t!(format!("{:p}", val as *const isize), exp); - } - - // Escaping - t!(format!("{{"), "{"); - t!(format!("}}"), "}"); - - test_write(); - test_print(); - test_order(); - test_once(); - - // make sure that format! doesn't move out of local variables - let a: Box<_> = box 3; - format!("{}", a); - format!("{}", a); - - // make sure that format! doesn't cause spurious unused-unsafe warnings when - // it's inside of an outer unsafe block - unsafe { - let a: isize = ::std::mem::transmute(3_usize); - format!("{}", a); - } - - test_format_args(); - - // test that trailing commas are acceptable - format!("{}", "test",); - format!("{foo}", foo="test",); - - test_refcell(); -} - -// Basic test to make sure that we can invoke the `write!` macro with an -// fmt::Write instance. -fn test_write() { - let mut buf = String::new(); - write!(&mut buf, "{}", 3); - { - let w = &mut buf; - write!(w, "{foo}", foo=4); - write!(w, "{}", "hello"); - writeln!(w, "{}", "line"); - writeln!(w, "{foo}", foo="bar"); - w.write_char('☃'); - w.write_str("str"); - } - - t!(buf, "34helloline\nbar\n☃str"); -} - -// Just make sure that the macros are defined, there's not really a lot that we -// can do with them just yet (to test the output) -fn test_print() { - print!("hi"); - print!("{:?}", vec![0u8]); - println!("hello"); - println!("this is a {}", "test"); - println!("{foo}", foo="bar"); -} - -// Just make sure that the macros are defined, there's not really a lot that we -// can do with them just yet (to test the output) -fn test_format_args() { - let mut buf = String::new(); - { - let w = &mut buf; - write!(w, "{}", format_args!("{}", 1)); - write!(w, "{}", format_args!("test")); - write!(w, "{}", format_args!("{test}", test=3)); - } - let s = buf; - t!(s, "1test3"); - - let s = fmt::format(format_args!("hello {}", "world")); - t!(s, "hello world"); - let s = format!("{}: {}", "args were", format_args!("hello {}", "world")); - t!(s, "args were: hello world"); -} - -fn test_order() { - // Make sure format!() arguments are always evaluated in a left-to-right - // ordering - fn foo() -> isize { - static mut FOO: isize = 0; - unsafe { - FOO += 1; - FOO - } - } - assert_eq!(format!("{} {} {a} {b} {} {c}", - foo(), foo(), foo(), a=foo(), b=foo(), c=foo()), - "1 2 4 5 3 6".to_string()); -} - -fn test_once() { - // Make sure each argument are evaluated only once even though it may be - // formatted multiple times - fn foo() -> isize { - static mut FOO: isize = 0; - unsafe { - FOO += 1; - FOO - } - } - assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a=foo()), - "1 1 1 2 2 2".to_string()); -} - -fn test_refcell() { - let refcell = RefCell::new(5); - assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }"); - let borrow = refcell.borrow_mut(); - assert_eq!(format!("{:?}", refcell), "RefCell { value: }"); - drop(borrow); - assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }"); -} diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 679b26efe5..e578c4b4f8 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0` +error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` --> $DIR/auto-trait-leak.rs:12:16 | LL | fn cycle1() -> impl Clone { @@ -35,7 +35,7 @@ note: ...which requires type-checking `cycle1`... LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires computing type of `cycle2::{{opaque}}#0`... +note: ...which requires computing type of `cycle2::{opaque#0}`... --> $DIR/auto-trait-leak.rs:20:16 | LL | fn cycle2() -> impl Clone { @@ -71,7 +71,7 @@ note: ...which requires type-checking `cycle2`... LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... - = note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle + = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/auto-trait-leak.rs:1:1 | @@ -84,20 +84,20 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/auto-trait-leak.rs:14:5 | LL | fn send(_: T) {} | ---- required by this bound in `send` ... LL | send(cycle2().clone()); - | ^^^^ `std::rc::Rc` cannot be sent between threads safely + | ^^^^ `Rc` cannot be sent between threads safely ... LL | fn cycle2() -> impl Clone { - | ---------- within this `impl std::clone::Clone` + | ---------- within this `impl Clone` | - = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` - = note: required because it appears within the type `impl std::clone::Clone` + = help: within `impl Clone`, the trait `Send` is not implemented for `Rc` + = note: required because it appears within the type `impl Clone` error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/auto-trait-leak2.rs b/src/test/ui/impl-trait/auto-trait-leak2.rs index fb4b540512..a464f576dc 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.rs +++ b/src/test/ui/impl-trait/auto-trait-leak2.rs @@ -11,10 +11,10 @@ fn send(_: T) {} fn main() { send(before()); - //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely + //~^ ERROR `Rc>` cannot be sent between threads safely send(after()); - //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely + //~^ ERROR `Rc>` cannot be sent between threads safely } // Deferred path, main has to wait until typeck finishes, diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index b02ef7d4a5..6b2b8248a4 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -1,34 +1,34 @@ -error[E0277]: `std::rc::Rc>` cannot be sent between threads safely +error[E0277]: `Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:13:5 | LL | fn before() -> impl Fn(i32) { - | ------------ within this `impl std::ops::Fn<(i32,)>` + | ------------ within this `impl Fn<(i32,)>` ... LL | fn send(_: T) {} | ---- required by this bound in `send` ... LL | send(before()); - | ^^^^ `std::rc::Rc>` cannot be sent between threads safely + | ^^^^ `Rc>` cannot be sent between threads safely | - = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22 p:std::rc::Rc>]` - = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` + = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc>` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22]` + = note: required because it appears within the type `impl Fn<(i32,)>` -error[E0277]: `std::rc::Rc>` cannot be sent between threads safely +error[E0277]: `Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:16:5 | LL | fn send(_: T) {} | ---- required by this bound in `send` ... LL | send(after()); - | ^^^^ `std::rc::Rc>` cannot be sent between threads safely + | ^^^^ `Rc>` cannot be sent between threads safely ... LL | fn after() -> impl Fn(i32) { - | ------------ within this `impl std::ops::Fn<(i32,)>` + | ------------ within this `impl Fn<(i32,)>` | - = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:std::rc::Rc>]` - = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` + = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc>` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22]` + = note: required because it appears within the type `impl Fn<(i32,)>` error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/bindings-opaque.stderr b/src/test/ui/impl-trait/bindings-opaque.stderr index 6656968d79..170bd46123 100644 --- a/src/test/ui/impl-trait/bindings-opaque.stderr +++ b/src/test/ui/impl-trait/bindings-opaque.stderr @@ -7,23 +7,23 @@ LL | #![feature(impl_trait_in_bindings)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #63065 for more information -error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope +error[E0599]: no method named `count_ones` found for opaque type `impl Copy` in the current scope --> $DIR/bindings-opaque.rs:11:17 | LL | let _ = FOO.count_ones(); - | ^^^^^^^^^^ method not found in `impl std::marker::Copy` + | ^^^^^^^^^^ method not found in `impl Copy` -error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope +error[E0599]: no method named `count_ones` found for opaque type `impl Copy` in the current scope --> $DIR/bindings-opaque.rs:13:17 | LL | let _ = BAR.count_ones(); - | ^^^^^^^^^^ method not found in `impl std::marker::Copy` + | ^^^^^^^^^^ method not found in `impl Copy` -error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope +error[E0599]: no method named `count_ones` found for opaque type `impl Copy` in the current scope --> $DIR/bindings-opaque.rs:15:17 | LL | let _ = foo.count_ones(); - | ^^^^^^^^^^ method not found in `impl std::marker::Copy` + | ^^^^^^^^^^ method not found in `impl Copy` error: aborting due to 3 previous errors; 1 warning emitted diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr index 96f961a2aa..00145d10ed 100644 --- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr +++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -15,7 +15,7 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) } | | | doesn't have a size known at compile-time | - = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size @@ -36,7 +36,7 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } | | | doesn't have a size known at compile-time | - = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size @@ -137,15 +137,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:34:16 | LL | fn bam() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type LL | if true { LL | return Struct; | ^^^^^^ | | - | expected struct `std::boxed::Box`, found struct `Struct` + | expected struct `Box`, found struct `Struct` | help: store this in the heap by calling `Box::new`: `Box::new(Struct)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found struct `Struct` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html @@ -153,15 +153,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:36:5 | LL | fn bam() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type ... LL | 42 | ^^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(42)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html @@ -169,15 +169,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:40:16 | LL | fn baq() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type LL | if true { LL | return 0; | ^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(0)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html @@ -185,15 +185,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:42:5 | LL | fn baq() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type ... LL | 42 | ^^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(42)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html @@ -201,15 +201,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:46:9 | LL | fn baz() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type LL | if true { LL | Struct | ^^^^^^ | | - | expected struct `std::boxed::Box`, found struct `Struct` + | expected struct `Box`, found struct `Struct` | help: store this in the heap by calling `Box::new`: `Box::new(Struct)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found struct `Struct` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html @@ -217,15 +217,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:48:9 | LL | fn baz() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type ... LL | 42 | ^^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(42)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html @@ -233,15 +233,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:53:9 | LL | fn baw() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type LL | if true { LL | 0 | ^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(0)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html @@ -249,15 +249,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:55:9 | LL | fn baw() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type ... LL | 42 | ^^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(42)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index 628dfb13d4..cdaa61ac32 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -23,7 +23,7 @@ LL | 0_u32 = note: for information on `impl Trait`, see = help: if the trait `Foo` were object safe, you could return a boxed trait object = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type error[E0277]: cannot add `impl Foo` to `u32` --> $DIR/equality.rs:24:11 @@ -31,7 +31,7 @@ error[E0277]: cannot add `impl Foo` to `u32` LL | n + sum_to(n - 1) | ^ no implementation for `u32 + impl Foo` | - = help: the trait `std::ops::Add` is not implemented for `u32` + = help: the trait `Add` is not implemented for `u32` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr index 956ac1f1a1..7cea4fb93d 100644 --- a/src/test/ui/impl-trait/hidden-lifetimes.stderr +++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr @@ -16,7 +16,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { | ^^^^^^^^^^^^^^ | -note: hidden type `std::rc::Rc>` captures the lifetime `'b` as defined on the function body at 45:24 +note: hidden type `Rc>` captures the lifetime `'b` as defined on the function body at 45:24 --> $DIR/hidden-lifetimes.rs:45:24 | LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { diff --git a/src/test/ui/impl-trait/impl_trait_projections.stderr b/src/test/ui/impl-trait/impl_trait_projections.stderr index ff4382187a..e85ed0eda5 100644 --- a/src/test/ui/impl-trait/impl_trait_projections.stderr +++ b/src/test/ui/impl-trait/impl_trait_projections.stderr @@ -26,7 +26,7 @@ error[E0223]: ambiguous associated type --> $DIR/impl_trait_projections.rs:12:50 | LL | fn projection_is_disallowed(x: impl Iterator) -> ::Item { - | ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Item` + | ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Item` error: aborting due to 5 previous errors diff --git a/src/test/ui/impl-trait/issue-55872-1.rs b/src/test/ui/impl-trait/issue-55872-1.rs index f99096b4d5..a746ed09af 100644 --- a/src/test/ui/impl-trait/issue-55872-1.rs +++ b/src/test/ui/impl-trait/issue-55872-1.rs @@ -1,8 +1,7 @@ // ignore-tidy-linelength #![feature(type_alias_impl_trait)] -pub trait Bar -{ +pub trait Bar { type E: Copy; fn foo() -> Self::E; @@ -10,11 +9,12 @@ pub trait Bar impl Bar for S { type E = impl Copy; - //~^ ERROR the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` [E0277] - //~^^ ERROR the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)` [E0277] + //~^ ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277] + //~^^ ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277] fn foo() -> Self::E { - //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //~| ERROR impl has stricter requirements than trait (S::default(), T::default()) } } diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr index 5131509cdf..db49d988bb 100644 --- a/src/test/ui/impl-trait/issue-55872-1.stderr +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -1,39 +1,50 @@ -error[E0277]: the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:12:14 +error[E0276]: impl has stricter requirements than trait + --> $DIR/issue-55872-1.rs:15:5 + | +LL | fn foo() -> Self::E; + | ----------------------- definition of `foo` from trait +... +LL | fn foo() -> Self::E { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Default` + +error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)` + --> $DIR/issue-55872-1.rs:11:14 | LL | type E = impl Copy; - | ^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S` + | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` | = note: required because it appears within the type `(S, T)` = note: the return type of a function must have a statically known size help: consider further restricting this bound | -LL | impl Bar for S { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Bar for S { + | ^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:12:14 +error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)` + --> $DIR/issue-55872-1.rs:11:14 | LL | type E = impl Copy; - | ^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` | = note: required because it appears within the type `(S, T)` = note: the return type of a function must have a statically known size help: consider further restricting this bound | -LL | fn foo() -> Self::E { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo() -> Self::E { + | ^^^^^^ error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-1.rs:16:37 + --> $DIR/issue-55872-1.rs:15:37 | LL | fn foo() -> Self::E { | _____________________________________^ LL | | +LL | | LL | | (S::default(), T::default()) LL | | } | |_____^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs index 1ca2e3d906..7708576ae7 100644 --- a/src/test/ui/impl-trait/issue-55872-2.rs +++ b/src/test/ui/impl-trait/issue-55872-2.rs @@ -10,8 +10,8 @@ pub trait Bar { } impl Bar for S { - type E = impl Copy; - //~^ ERROR the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied [E0277] + type E = impl std::marker::Copy; + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied [E0277] fn foo() -> Self::E { //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias async {} diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr index 649109e4c9..6da3704184 100644 --- a/src/test/ui/impl-trait/issue-55872-2.stderr +++ b/src/test/ui/impl-trait/issue-55872-2.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `impl Future: Copy` is not satisfied --> $DIR/issue-55872-2.rs:13:14 | -LL | type E = impl Copy; - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `impl std::future::Future` +LL | type E = impl std::marker::Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/impl-trait/issue-56445.rs b/src/test/ui/impl-trait/issue-56445.rs index a34d7bae3a..6dd1648c9b 100644 --- a/src/test/ui/impl-trait/issue-56445.rs +++ b/src/test/ui/impl-trait/issue-56445.rs @@ -5,8 +5,7 @@ use std::marker::PhantomData; -pub struct S<'a> -{ +pub struct S<'a> { pub m1: PhantomData<&'a u8>, pub m2: [u8; S::size()], } diff --git a/src/test/ui/impl-trait/issue-72911.stderr b/src/test/ui/impl-trait/issue-72911.stderr index b28142b916..17748ae427 100644 --- a/src/test/ui/impl-trait/issue-72911.stderr +++ b/src/test/ui/impl-trait/issue-72911.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/issue-72911.rs:12:33 | LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator { - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/issue-72911.rs:17:41 | LL | fn lint_files() -> impl Iterator { - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error[E0720]: cannot resolve opaque type --> $DIR/issue-72911.rs:7:24 @@ -19,14 +19,14 @@ LL | LL | lint_files().flat_map(|f| gather_from_file(&f)) | ----------------------------------------------- | | - | returning here with type `std::iter::FlatMap` - | returning here with type `std::iter::FlatMap` + | returning here with type `FlatMap` + | returning here with type `FlatMap` ... LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator { - | -------------------------- returning this opaque type `std::iter::FlatMap` + | -------------------------- returning this opaque type `FlatMap` ... LL | fn lint_files() -> impl Iterator { - | -------------------------------------- returning this opaque type `std::iter::FlatMap` + | -------------------------------------- returning this opaque type `FlatMap` error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr index c538b77098..16a1262ec2 100644 --- a/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr +++ b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr @@ -5,22 +5,22 @@ LL | fn foo() -> impl Quux { | ^^^^^^^^^ recursive opaque type ... LL | Foo(bar()) - | ---------- returning here with type `foo::Foo` + | ---------- returning here with type `Foo` ... LL | fn bar() -> impl Quux { - | --------- returning this opaque type `foo::Foo` + | --------- returning this opaque type `Foo` error[E0720]: cannot resolve opaque type --> $DIR/infinite-impl-trait-issue-38064.rs:14:13 | LL | fn foo() -> impl Quux { - | --------- returning this opaque type `bar::Bar` + | --------- returning this opaque type `Bar` ... LL | fn bar() -> impl Quux { | ^^^^^^^^^ recursive opaque type ... LL | Bar(foo()) - | ---------- returning here with type `bar::Bar` + | ---------- returning here with type `Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr index 7f2eb0c21e..f6bb52bf63 100644 --- a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr +++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr @@ -9,7 +9,7 @@ LL | foo(|s| s.is_empty()); | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `is_empty`, perhaps you need to implement it: - candidate #1: `std::iter::ExactSizeIterator` + candidate #1: `ExactSizeIterator` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index 3cd4d0dd39..64ddcb81c0 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -16,11 +16,11 @@ LL | use no_method_suggested_traits::qux::PrivPub; LL | use no_method_suggested_traits::Reexported; | -error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&u32>>` in the current scope +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope --> $DIR/no-method-suggested-traits.rs:26:44 | LL | std::rc::Rc::new(&mut Box::new(&1u32)).method(); - | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u32>>` + | ^^^^^^ method not found in `Rc<&mut Box<&u32>>` | = help: items from traits can only be used if the trait is in scope help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: @@ -46,11 +46,11 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use foo::Bar; | -error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&char>>` in the current scope --> $DIR/no-method-suggested-traits.rs:32:43 | LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); - | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>` + | ^^^^^^ method not found in `Rc<&mut Box<&char>>` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: @@ -70,11 +70,11 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use no_method_suggested_traits::foo::PubPub; | -error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&i32>>` in the current scope +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&i32>>` in the current scope --> $DIR/no-method-suggested-traits.rs:37:44 | LL | std::rc::Rc::new(&mut Box::new(&1i32)).method(); - | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>` + | ^^^^^^ method not found in `Rc<&mut Box<&i32>>` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: @@ -94,22 +94,22 @@ LL | Foo.method(); = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `method`, perhaps you need to implement one of them: candidate #1: `foo::Bar` - candidate #2: `no_method_suggested_traits::foo::PubPub` + candidate #2: `PubPub` candidate #3: `no_method_suggested_traits::qux::PrivPub` - candidate #4: `no_method_suggested_traits::Reexported` + candidate #4: `Reexported` -error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:42:43 | LL | std::rc::Rc::new(&mut Box::new(&Foo)).method(); - | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&Foo>>` + | ^^^^^^ method not found in `Rc<&mut Box<&Foo>>` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `method`, perhaps you need to implement one of them: candidate #1: `foo::Bar` - candidate #2: `no_method_suggested_traits::foo::PubPub` + candidate #2: `PubPub` candidate #3: `no_method_suggested_traits::qux::PrivPub` - candidate #4: `no_method_suggested_traits::Reexported` + candidate #4: `Reexported` error[E0599]: no method named `method2` found for type `u64` in the current scope --> $DIR/no-method-suggested-traits.rs:45:10 @@ -124,11 +124,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it LL | pub trait Bar { | ^^^^^^^^^^^^^ -error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&u64>>` in the current scope +error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&u64>>` in the current scope --> $DIR/no-method-suggested-traits.rs:47:44 | LL | std::rc::Rc::new(&mut Box::new(&1u64)).method2(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u64>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&u64>>` | = help: items from traits can only be used if the trait is implemented and in scope note: `foo::Bar` defines an item `method2`, perhaps you need to implement it @@ -150,11 +150,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it LL | pub trait Bar { | ^^^^^^^^^^^^^ -error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope +error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:52:71 | LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>` | = help: items from traits can only be used if the trait is implemented and in scope note: `foo::Bar` defines an item `method2`, perhaps you need to implement it @@ -176,11 +176,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it LL | pub trait Bar { | ^^^^^^^^^^^^^ -error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope +error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope --> $DIR/no-method-suggested-traits.rs:56:74 | LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>` | = help: items from traits can only be used if the trait is implemented and in scope note: `foo::Bar` defines an item `method2`, perhaps you need to implement it @@ -200,17 +200,17 @@ LL | Foo.method3(); | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `method3`, perhaps you need to implement it: - candidate #1: `no_method_suggested_traits::foo::PubPub` + candidate #1: `PubPub` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:61:43 | LL | std::rc::Rc::new(&mut Box::new(&Foo)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&Foo>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `method3`, perhaps you need to implement it: - candidate #1: `no_method_suggested_traits::foo::PubPub` + candidate #1: `PubPub` error[E0599]: no method named `method3` found for enum `Bar` in the current scope --> $DIR/no-method-suggested-traits.rs:63:12 @@ -223,17 +223,17 @@ LL | Bar::X.method3(); | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `method3`, perhaps you need to implement it: - candidate #1: `no_method_suggested_traits::foo::PubPub` + candidate #1: `PubPub` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&Bar>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Bar>>` in the current scope --> $DIR/no-method-suggested-traits.rs:65:46 | LL | std::rc::Rc::new(&mut Box::new(&Bar::X)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&Bar>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `method3`, perhaps you need to implement it: - candidate #1: `no_method_suggested_traits::foo::PubPub` + candidate #1: `PubPub` error[E0599]: no method named `method3` found for type `usize` in the current scope --> $DIR/no-method-suggested-traits.rs:69:13 @@ -241,11 +241,11 @@ error[E0599]: no method named `method3` found for type `usize` in the current sc LL | 1_usize.method3(); | ^^^^^^^ method not found in `usize` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&usize>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&usize>>` in the current scope --> $DIR/no-method-suggested-traits.rs:70:47 | LL | std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&usize>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&usize>>` error[E0599]: no method named `method3` found for struct `no_method_suggested_traits::Foo` in the current scope --> $DIR/no-method-suggested-traits.rs:71:37 @@ -253,11 +253,11 @@ error[E0599]: no method named `method3` found for struct `no_method_suggested_tr LL | no_method_suggested_traits::Foo.method3(); | ^^^^^^^ method not found in `no_method_suggested_traits::Foo` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:72:71 | LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>` error[E0599]: no method named `method3` found for enum `no_method_suggested_traits::Bar` in the current scope --> $DIR/no-method-suggested-traits.rs:74:40 @@ -265,11 +265,11 @@ error[E0599]: no method named `method3` found for enum `no_method_suggested_trai LL | no_method_suggested_traits::Bar::X.method3(); | ^^^^^^^ method not found in `no_method_suggested_traits::Bar` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope --> $DIR/no-method-suggested-traits.rs:75:74 | LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>` error: aborting due to 24 previous errors diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr index dd4260fbe4..66043267f9 100644 --- a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr +++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr @@ -14,7 +14,7 @@ LL | B = note: for information on `impl Trait`, see = help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type error[E0308]: mismatched types --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5 @@ -30,9 +30,18 @@ LL | B | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn cat() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(A); +LL | } +LL | Box::new(B) + | error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index 75ff9e078c..0f89ec2475 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -5,9 +5,9 @@ LL | fn option(i: i32) -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | if i < 0 { None } else { Some((option(i - 1), i)) } - | ---- ------------------------ returning here with type `std::option::Option<(impl Sized, i32)>` + | ---- ------------------------ returning here with type `Option<(impl Sized, i32)>` | | - | returning here with type `std::option::Option<(impl Sized, i32)>` + | returning here with type `Option<(impl Sized, i32)>` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:12:15 @@ -54,7 +54,7 @@ LL | fn closure_capture() -> impl Sized { LL | / move || { LL | | x; LL | | } - | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]` + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:40:29 @@ -65,7 +65,7 @@ LL | fn closure_ref_capture() -> impl Sized { LL | / move || { LL | | &x; LL | | } - | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]` + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:48:21 @@ -95,7 +95,7 @@ LL | / move || { LL | | yield; LL | | x; LL | | } - | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]` + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 {()}]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 @@ -135,13 +135,13 @@ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 | LL | fn mutual_recursion() -> impl Sync { - | --------- returning this opaque type `impl std::marker::Sync` + | --------- returning this opaque type `impl Sync` ... LL | fn mutual_recursion_b() -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | mutual_recursion() - | ------------------ returning here with type `impl std::marker::Sync` + | ------------------ returning here with type `impl Sync` error: aborting due to 14 previous errors diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr index 894a65ff38..969ddc57af 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.stderr +++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr @@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> | ^^^^^^^^^^^^^^ | -note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime `'x` as defined on the function body at 17:7 +note: hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined on the function body at 17:7 --> $DIR/region-escape-via-bound.rs:17:7 | LL | where 'x: 'y diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index 748bc639a0..e94f2c7021 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -4,7 +4,7 @@ error[E0053]: method `fmt` has an incompatible type for trait LL | fn fmt(&self, x: &str) -> () { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | - = note: expected fn pointer `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + = note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` found fn pointer `fn(&MyType, &str)` error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2 @@ -13,7 +13,7 @@ error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fm LL | fn fmt(&self) -> () { } | ^^^^^ expected 2 parameters, found 1 | - = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + = note: `fmt` from trait: `fn(&Self, &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in the impl --> $DIR/trait_type.rs:17:4 @@ -21,7 +21,7 @@ error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in th LL | fn fmt() -> () { } | ^^^^^^^^^^^^^^ expected `&self` in impl | - = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + = note: `fmt` from trait: `fn(&Self, &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` error[E0046]: not all trait items implemented, missing: `fmt` --> $DIR/trait_type.rs:21:1 @@ -29,7 +29,7 @@ error[E0046]: not all trait items implemented, missing: `fmt` LL | impl std::fmt::Display for MyType4 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation | - = help: implement the missing item: `fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { todo!() }` + = help: implement the missing item: `fn fmt(&self, _: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { todo!() }` error: aborting due to 4 previous errors diff --git a/src/test/ui/impl-trait/universal-mismatched-type.stderr b/src/test/ui/impl-trait/universal-mismatched-type.stderr index a12b01b4d2..817c573c09 100644 --- a/src/test/ui/impl-trait/universal-mismatched-type.stderr +++ b/src/test/ui/impl-trait/universal-mismatched-type.stderr @@ -2,13 +2,13 @@ error[E0308]: mismatched types --> $DIR/universal-mismatched-type.rs:4:5 | LL | fn foo(x: impl Debug) -> String { - | ---------- ------ expected `std::string::String` because of return type + | ---------- ------ expected `String` because of return type | | | this type parameter LL | x - | ^ expected struct `std::string::String`, found type parameter `impl Debug` + | ^ expected struct `String`, found type parameter `impl Debug` | - = note: expected struct `std::string::String` + = note: expected struct `String` found type parameter `impl Debug` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs index 211a14ed4d..72b880fb92 100644 --- a/src/test/ui/impl-trait/where-allowed.rs +++ b/src/test/ui/impl-trait/where-allowed.rs @@ -56,10 +56,12 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types //~| ERROR nested `impl Trait` is not allowed +//~| ERROR cannot resolve opaque type // Disallowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +//~| ERROR cannot resolve opaque type // Disallowed fn in_Fn_parameter_in_generics (_: F) { panic!() } diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr index 7addc006e1..93f9724140 100644 --- a/src/test/ui/impl-trait/where-allowed.stderr +++ b/src/test/ui/impl-trait/where-allowed.stderr @@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | outer `impl Trait` error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:119:16 + --> $DIR/where-allowed.rs:121:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Out = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:155:23 + --> $DIR/where-allowed.rs:157:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type InTypeAlias = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:159:39 + --> $DIR/where-allowed.rs:161:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -110,139 +110,139 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:61:59 + --> $DIR/where-allowed.rs:62:59 | LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:65:38 + --> $DIR/where-allowed.rs:67:38 | LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:69:40 + --> $DIR/where-allowed.rs:71:40 | LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:82:32 + --> $DIR/where-allowed.rs:84:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:86:41 + --> $DIR/where-allowed.rs:88:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:90:27 + --> $DIR/where-allowed.rs:92:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:95:25 + --> $DIR/where-allowed.rs:97:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:97:20 + --> $DIR/where-allowed.rs:99:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:108:23 + --> $DIR/where-allowed.rs:110:23 | LL | fn in_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:126:34 + --> $DIR/where-allowed.rs:128:34 | LL | fn in_trait_impl_return() -> impl Debug { () } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:139:33 + --> $DIR/where-allowed.rs:141:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:142:31 + --> $DIR/where-allowed.rs:144:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:159:39 + --> $DIR/where-allowed.rs:161:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:164:16 + --> $DIR/where-allowed.rs:166:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:169:24 + --> $DIR/where-allowed.rs:171:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:174:6 + --> $DIR/where-allowed.rs:176:6 | LL | impl impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:180:24 + --> $DIR/where-allowed.rs:182:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:186:11 + --> $DIR/where-allowed.rs:188:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:193:15 + --> $DIR/where-allowed.rs:195:15 | LL | where Vec: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:200:24 + --> $DIR/where-allowed.rs:202:24 | LL | where T: PartialEq | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:207:17 + --> $DIR/where-allowed.rs:209:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:214:22 + --> $DIR/where-allowed.rs:216:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:220:29 + --> $DIR/where-allowed.rs:222:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ @@ -250,24 +250,44 @@ LL | let _in_local_variable: impl Fn() = || {}; = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:222:46 + --> $DIR/where-allowed.rs:224:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ +error[E0720]: cannot resolve opaque type + --> $DIR/where-allowed.rs:56:49 + | +LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } + | ^^^^^^^^^^^^^^^^^^^ -------- this returned value is of `!` type + | | + | cannot resolve opaque type + | + = help: this error will resolve once the item's body returns a concrete type + +error[E0720]: cannot resolve opaque type + --> $DIR/where-allowed.rs:62:46 + | +LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } + | ^^^^^^^^^^^^^^^^^^^^^^^ -------- this returned value is of `!` type + | | + | cannot resolve opaque type + | + = help: this error will resolve once the item's body returns a concrete type + error: could not find defining uses - --> $DIR/where-allowed.rs:119:16 + --> $DIR/where-allowed.rs:121:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/where-allowed.rs:155:23 + --> $DIR/where-allowed.rs:157:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ -error: aborting due to 42 previous errors +error: aborting due to 44 previous errors -Some errors have detailed explanations: E0562, E0658, E0666. +Some errors have detailed explanations: E0562, E0658, E0666, E0720. For more information about an error, try `rustc --explain E0562`. diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs index 6b70efe0c4..4a0c612020 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + // aux-build:two_macros.rs // compile-flags:--extern non_existent @@ -7,7 +9,7 @@ mod n { mod m { fn check() { - two_macros::m!(); //~ ERROR failed to resolve: use of undeclared type or module `two_macros` + two_macros::m!(); //~ ERROR failed to resolve: use of undeclared crate or module `two_macros` } } diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr index f7544306d3..2d7a1bf468 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr @@ -1,5 +1,5 @@ error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` - --> $DIR/extern-prelude-extern-crate-fail.rs:16:9 + --> $DIR/extern-prelude-extern-crate-fail.rs:18:9 | LL | extern crate std as non_existent; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,11 +9,11 @@ LL | define_std_as_non_existent!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `two_macros` - --> $DIR/extern-prelude-extern-crate-fail.rs:10:9 +error[E0433]: failed to resolve: use of undeclared crate or module `two_macros` + --> $DIR/extern-prelude-extern-crate-fail.rs:12:9 | LL | two_macros::m!(); - | ^^^^^^^^^^ use of undeclared type or module `two_macros` + | ^^^^^^^^^^ use of undeclared crate or module `two_macros` error: aborting due to 2 previous errors diff --git a/src/test/ui/imports/issue-62767.rs b/src/test/ui/imports/issue-62767.rs index 984d3f0ca9..0e0f915ea5 100644 --- a/src/test/ui/imports/issue-62767.rs +++ b/src/test/ui/imports/issue-62767.rs @@ -1,5 +1,4 @@ -// check-pass - +// Minimized case from #62767. mod m { pub enum Same { Same, @@ -8,8 +7,22 @@ mod m { use m::*; -// The variant `Same` introduced by this import is not considered when resolving the prefix -// `Same::` during import validation (issue #62767). -use Same::Same; +// The variant `Same` introduced by this import is also considered when resolving the prefix +// `Same::` during import validation to avoid effects similar to time travel (#74556). +use Same::Same; //~ ERROR unresolved import `Same` + +// Case from #74556. +mod foo { + pub mod bar { + pub mod bar { + pub fn foobar() {} + } + } +} + +use foo::*; +use bar::bar; //~ ERROR unresolved import `bar::bar` + //~| ERROR inconsistent resolution for an import +use bar::foobar; fn main() {} diff --git a/src/test/ui/imports/issue-62767.stderr b/src/test/ui/imports/issue-62767.stderr new file mode 100644 index 0000000000..a4334bda6d --- /dev/null +++ b/src/test/ui/imports/issue-62767.stderr @@ -0,0 +1,21 @@ +error: inconsistent resolution for an import + --> $DIR/issue-62767.rs:24:5 + | +LL | use bar::bar; + | ^^^^^^^^ + +error[E0432]: unresolved import `Same` + --> $DIR/issue-62767.rs:12:5 + | +LL | use Same::Same; + | ^^^^ `Same` is a variant, not a module + +error[E0432]: unresolved import `bar::bar` + --> $DIR/issue-62767.rs:24:5 + | +LL | use bar::bar; + | ^^^^^^^^ no `bar` in `foo::bar::bar` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/index-help.stderr b/src/test/ui/index-help.stderr index cd4d835674..78a8f439a7 100644 --- a/src/test/ui/index-help.stderr +++ b/src/test/ui/index-help.stderr @@ -4,8 +4,8 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `i32` LL | x[0i32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[{integer}]>` is not implemented for `i32` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec<{integer}>` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32` + = note: required because of the requirements on the impl of `Index` for `Vec<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr index 70614cbbf9..31fcd4b1c2 100644 --- a/src/test/ui/indexing-requires-a-uint.stderr +++ b/src/test/ui/indexing-requires-a-uint.stderr @@ -4,8 +4,8 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `u8` LL | [0][0u8]; | ^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[{integer}]>` is not implemented for `u8` - = note: required because of the requirements on the impl of `std::ops::Index` for `[{integer}]` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8` + = note: required because of the requirements on the impl of `Index` for `[{integer}]` error[E0308]: mismatched types --> $DIR/indexing-requires-a-uint.rs:12:18 diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr index 89a22f5e5d..b6e3bb190e 100644 --- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr +++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr @@ -7,11 +7,11 @@ LL | #![feature(impl_trait_in_bindings)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #63065 for more information -error[E0282]: type annotations needed for `impl std::future::Future` +error[E0282]: type annotations needed for `impl Future` --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:9 | LL | let fut = async { - | --- consider giving `fut` the explicit type `impl std::future::Future`, with the type parameters specified + | --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified LL | make_unit()?; | ^^^^^^^^^^^^ cannot infer type diff --git a/src/test/ui/inference/inference_unstable_featured.stderr b/src/test/ui/inference/inference_unstable_featured.stderr index e23b934ac1..0dd4baf80d 100644 --- a/src/test/ui/inference/inference_unstable_featured.stderr +++ b/src/test/ui/inference/inference_unstable_featured.stderr @@ -4,16 +4,16 @@ error[E0034]: multiple applicable items in scope LL | assert_eq!('x'.ipu_flatten(), 0); | ^^^^^^^^^^^ multiple `ipu_flatten` found | - = note: candidate #1 is defined in an impl of the trait `inference_unstable_iterator::IpuIterator` for the type `char` - = note: candidate #2 is defined in an impl of the trait `inference_unstable_itertools::IpuItertools` for the type `char` + = note: candidate #1 is defined in an impl of the trait `IpuIterator` for the type `char` + = note: candidate #2 is defined in an impl of the trait `IpuItertools` for the type `char` help: disambiguate the associated function for candidate #1 | -LL | assert_eq!(inference_unstable_iterator::IpuIterator::ipu_flatten(&'x'), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | assert_eq!(IpuIterator::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #2 | -LL | assert_eq!(inference_unstable_itertools::IpuItertools::ipu_flatten(&'x'), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | assert_eq!(IpuItertools::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/infinite/infinite-instantiation.rs b/src/test/ui/infinite/infinite-instantiation.rs index 9fee01c1ba..9b9f332ca8 100644 --- a/src/test/ui/infinite/infinite-instantiation.rs +++ b/src/test/ui/infinite/infinite-instantiation.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test: ".nll/" -> "/" trait ToOpt: Sized { fn to_option(&self) -> Option; @@ -19,7 +20,7 @@ impl ToOpt for Option { fn function(counter: usize, t: T) { if counter > 0 { function(counter - 1, t.to_option()); - //~^ ERROR reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/infinite-instantiation.rs:21:9 +error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + --> $DIR/infinite-instantiation.rs:22:9 | LL | function(counter - 1, t.to_option()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `function` defined here - --> $DIR/infinite-instantiation.rs:19:1 + --> $DIR/infinite-instantiation.rs:20:1 | LL | fn function(counter: usize, t: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/infinite/infinite-instantiation/infinite-instantiation.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.rs b/src/test/ui/infinite/infinite-recursion-const-fn.rs index 8289a3db6f..3458040792 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite/infinite-recursion-const-fn.rs @@ -1,7 +1,12 @@ //https://github.com/rust-lang/rust/issues/31364 -const fn a() -> usize { b() } //~ ERROR cycle detected when const-evaluating `a` [E0391] -const fn b() -> usize { a() } +const fn a() -> usize { + //~^ ERROR cycle detected when const-evaluating + checking `a` [E0391] + b() +} +const fn b() -> usize { + a() +} const ARR: [i32; a()] = [5; 6]; -fn main(){} +fn main() {} diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index de0c579f63..7ccc7cc987 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -1,17 +1,17 @@ -error[E0391]: cycle detected when const-evaluating `a` +error[E0391]: cycle detected when const-evaluating + checking `a` --> $DIR/infinite-recursion-const-fn.rs:3:1 | -LL | const fn a() -> usize { b() } +LL | const fn a() -> usize { | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `b`... - --> $DIR/infinite-recursion-const-fn.rs:4:1 +note: ...which requires const-evaluating + checking `b`... + --> $DIR/infinite-recursion-const-fn.rs:7:1 | -LL | const fn b() -> usize { a() } +LL | const fn b() -> usize { | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `a`, completing the cycle -note: cycle used when const-evaluating `ARR::{{constant}}#0` - --> $DIR/infinite-recursion-const-fn.rs:5:18 + = note: ...which again requires const-evaluating + checking `a`, completing the cycle +note: cycle used when const-evaluating + checking `ARR::{constant#0}` + --> $DIR/infinite-recursion-const-fn.rs:10:18 | LL | const ARR: [i32; a()] = [5; 6]; | ^^^ diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 6d1df4fda2..45322ea967 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -18,7 +18,7 @@ LL | enum MList { Cons(isize, MList), Nil } | ^^^^^^^^^^ | = note: ...which again requires computing drop-check constraints for `MList`, completing the cycle - = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: MList } }` + = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }` error: aborting due to 2 previous errors diff --git a/src/test/ui/inner-static-type-parameter.stderr b/src/test/ui/inner-static-type-parameter.stderr index 1e74445af5..990e4649a5 100644 --- a/src/test/ui/inner-static-type-parameter.stderr +++ b/src/test/ui/inner-static-type-parameter.stderr @@ -12,7 +12,7 @@ error[E0392]: parameter `T` is never used LL | enum Bar { What } | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/integral-indexing.stderr b/src/test/ui/integral-indexing.stderr index 28ef5937ea..fcd79d19aa 100644 --- a/src/test/ui/integral-indexing.stderr +++ b/src/test/ui/integral-indexing.stderr @@ -4,8 +4,8 @@ error[E0277]: the type `[isize]` cannot be indexed by `u8` LL | v[3u8]; | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `u8` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec` + = help: the trait `SliceIndex<[isize]>` is not implemented for `u8` + = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[isize]` cannot be indexed by `i8` --> $DIR/integral-indexing.rs:7:5 @@ -13,8 +13,8 @@ error[E0277]: the type `[isize]` cannot be indexed by `i8` LL | v[3i8]; | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `i8` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec` + = help: the trait `SliceIndex<[isize]>` is not implemented for `i8` + = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[isize]` cannot be indexed by `u32` --> $DIR/integral-indexing.rs:8:5 @@ -22,8 +22,8 @@ error[E0277]: the type `[isize]` cannot be indexed by `u32` LL | v[3u32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `u32` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec` + = help: the trait `SliceIndex<[isize]>` is not implemented for `u32` + = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[isize]` cannot be indexed by `i32` --> $DIR/integral-indexing.rs:9:5 @@ -31,8 +31,8 @@ error[E0277]: the type `[isize]` cannot be indexed by `i32` LL | v[3i32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `i32` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec` + = help: the trait `SliceIndex<[isize]>` is not implemented for `i32` + = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[u8]` cannot be indexed by `u8` --> $DIR/integral-indexing.rs:12:5 @@ -40,8 +40,8 @@ error[E0277]: the type `[u8]` cannot be indexed by `u8` LL | s.as_bytes()[3u8]; | ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `u8` - = note: required because of the requirements on the impl of `std::ops::Index` for `[u8]` + = help: the trait `SliceIndex<[u8]>` is not implemented for `u8` + = note: required because of the requirements on the impl of `Index` for `[u8]` error[E0277]: the type `[u8]` cannot be indexed by `i8` --> $DIR/integral-indexing.rs:13:5 @@ -49,8 +49,8 @@ error[E0277]: the type `[u8]` cannot be indexed by `i8` LL | s.as_bytes()[3i8]; | ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `i8` - = note: required because of the requirements on the impl of `std::ops::Index` for `[u8]` + = help: the trait `SliceIndex<[u8]>` is not implemented for `i8` + = note: required because of the requirements on the impl of `Index` for `[u8]` error[E0277]: the type `[u8]` cannot be indexed by `u32` --> $DIR/integral-indexing.rs:14:5 @@ -58,8 +58,8 @@ error[E0277]: the type `[u8]` cannot be indexed by `u32` LL | s.as_bytes()[3u32]; | ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `u32` - = note: required because of the requirements on the impl of `std::ops::Index` for `[u8]` + = help: the trait `SliceIndex<[u8]>` is not implemented for `u32` + = note: required because of the requirements on the impl of `Index` for `[u8]` error[E0277]: the type `[u8]` cannot be indexed by `i32` --> $DIR/integral-indexing.rs:15:5 @@ -67,8 +67,8 @@ error[E0277]: the type `[u8]` cannot be indexed by `i32` LL | s.as_bytes()[3i32]; | ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `i32` - = note: required because of the requirements on the impl of `std::ops::Index` for `[u8]` + = help: the trait `SliceIndex<[u8]>` is not implemented for `i32` + = note: required because of the requirements on the impl of `Index` for `[u8]` error: aborting due to 8 previous errors diff --git a/src/test/ui/interior-mutability/interior-mutability.rs b/src/test/ui/interior-mutability/interior-mutability.rs index ddc882cccf..c704acc22a 100644 --- a/src/test/ui/interior-mutability/interior-mutability.rs +++ b/src/test/ui/interior-mutability/interior-mutability.rs @@ -3,5 +3,5 @@ use std::panic::catch_unwind; fn main() { let mut x = Cell::new(22); catch_unwind(|| { x.set(23); }); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index a25acf10a1..dd43da1166 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,18 +1,18 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/interior-mutability.rs:5:5 | LL | catch_unwind(|| { x.set(23); }); - | ^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | ::: $SRC_DIR/std/src/panic.rs:LL:COL | LL | pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { - | ---------- required by this bound in `std::panic::catch_unwind` + | ---------- required by this bound in `catch_unwind` | - = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell` - = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:5:18: 5:35 x:&std::cell::Cell]` + = help: within `Cell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because of the requirements on the impl of `UnwindSafe` for `&Cell` + = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:5:18: 5:35]` error: aborting due to previous error diff --git a/src/test/ui/internal/auxiliary/internal_unstable.rs b/src/test/ui/internal/auxiliary/internal_unstable.rs index 148cbd1899..eb4d6cb380 100644 --- a/src/test/ui/internal/auxiliary/internal_unstable.rs +++ b/src/test/ui/internal/auxiliary/internal_unstable.rs @@ -52,6 +52,15 @@ macro_rules! access_field_allow { ($e: expr) => { $e.x } } +// regression test for #77088 +#[stable(feature = "stable", since = "1.0.0")] +#[allow_internal_unstable(struct_field)] +#[allow_internal_unstable(struct2_field)] +#[macro_export] +macro_rules! access_field_allow2 { + ($e: expr) => { $e.x } +} + #[stable(feature = "stable", since = "1.0.0")] #[allow_internal_unstable()] #[macro_export] diff --git a/src/test/ui/internal/internal-unstable-const.rs b/src/test/ui/internal/internal-unstable-const.rs index b923bc22f6..554c67be4e 100644 --- a/src/test/ui/internal/internal-unstable-const.rs +++ b/src/test/ui/internal/internal-unstable-const.rs @@ -8,7 +8,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn foo() -> i32 { - unsafe { std::mem::transmute(4u32) } //~ ERROR can only call `transmute` from const items + unsafe { std::mem::transmute(4u32) } //~ ERROR `transmute` } fn main() {} diff --git a/src/test/ui/internal/internal-unstable-const.stderr b/src/test/ui/internal/internal-unstable-const.stderr index 9626df23ec..adfb8dc369 100644 --- a/src/test/ui/internal/internal-unstable-const.stderr +++ b/src/test/ui/internal/internal-unstable-const.stderr @@ -1,12 +1,13 @@ -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/internal-unstable-const.rs:11:14 | LL | unsafe { std::mem::transmute(4u32) } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/internal/internal-unstable.rs b/src/test/ui/internal/internal-unstable.rs index e09a5d8917..94bd6aab23 100644 --- a/src/test/ui/internal/internal-unstable.rs +++ b/src/test/ui/internal/internal-unstable.rs @@ -28,6 +28,7 @@ fn main() { construct_unstable_allow!(0); |x: internal_unstable::Foo| { call_method_allow!(x) }; |x: internal_unstable::Bar| { access_field_allow!(x) }; + |x: internal_unstable::Bar| { access_field_allow2!(x) }; // regression test for #77088 // bad. pass_through_allow!(internal_unstable::unstable()); //~ ERROR use of unstable diff --git a/src/test/ui/internal/internal-unstable.stderr b/src/test/ui/internal/internal-unstable.stderr index 2c6bf42ae8..2e6360c75c 100644 --- a/src/test/ui/internal/internal-unstable.stderr +++ b/src/test/ui/internal/internal-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:33:25 + --> $DIR/internal-unstable.rs:34:25 | LL | pass_through_allow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | pass_through_allow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:35:27 + --> $DIR/internal-unstable.rs:36:27 | LL | pass_through_noallow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | pass_through_noallow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:39:22 + --> $DIR/internal-unstable.rs:40:22 | LL | println!("{:?}", internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | println!("{:?}", internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:41:10 + --> $DIR/internal-unstable.rs:42:10 | LL | bar!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 02f8ecaa4e..24474cabf1 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -3,7 +3,7 @@ // This test checks panic emitted from `mem::{uninitialized,zeroed}`. -#![feature(never_type)] +#![feature(never_type, arbitrary_enum_discriminant)] #![allow(deprecated, invalid_value)] use std::{ @@ -24,6 +24,20 @@ enum Bar {} #[allow(dead_code)] enum OneVariant { Variant(i32) } +#[allow(dead_code, non_camel_case_types)] +enum OneVariant_NonZero { + Variant(i32, i32, num::NonZeroI32), + DeadVariant(Bar), +} + +// An `Aggregate` abi enum where 0 is not a valid discriminant. +#[allow(dead_code)] +#[repr(i32)] +enum NoNullVariant { + Variant1(i32, i32) = 1, + Variant2(i32, i32) = 2, +} + // An enum with ScalarPair layout #[allow(dead_code)] enum LR { @@ -125,6 +139,7 @@ fn main() { "attempted to zero-initialize type `std::mem::ManuallyDrop`, \ which is invalid" ); + */ test_panic_msg( || mem::uninitialized::<(NonNull, u32, u32)>(), @@ -136,7 +151,28 @@ fn main() { "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ which is invalid" ); - */ + + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `OneVariant_NonZero` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `OneVariant_NonZero`, \ + 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`, \ + which is invalid" + ); // Types that can be zero, but not uninit. test_panic_msg( diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.rs b/src/test/ui/invalid-rustc_args_required_const-arguments.rs new file mode 100644 index 0000000000..76c01c2130 --- /dev/null +++ b/src/test/ui/invalid-rustc_args_required_const-arguments.rs @@ -0,0 +1,26 @@ +#![feature(rustc_attrs)] + +#[rustc_args_required_const(0)] //~ ERROR index exceeds number of arguments +fn foo1() {} + +#[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments +fn foo2(_: u8) {} + +#[rustc_args_required_const(a)] //~ ERROR arguments should be non-negative integers +fn foo4() {} + +#[rustc_args_required_const(1, a, 2, b)] //~ ERROR arguments should be non-negative integers +fn foo5(_: u8, _: u8, _: u8) {} + +#[rustc_args_required_const(0)] //~ ERROR attribute should be applied to a function +struct S; + +#[rustc_args_required_const(0usize)] //~ ERROR suffixed literals are not allowed in attributes +fn foo6(_: u8) {} + +extern { + #[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments + fn foo7(_: u8); +} + +fn main() {} diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.stderr b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr new file mode 100644 index 0000000000..39d0462616 --- /dev/null +++ b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr @@ -0,0 +1,48 @@ +error: suffixed literals are not allowed in attributes + --> $DIR/invalid-rustc_args_required_const-arguments.rs:18:29 + | +LL | #[rustc_args_required_const(0usize)] + | ^^^^^^ + | + = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_args_required_const-arguments.rs:3:29 + | +LL | #[rustc_args_required_const(0)] + | ^ there are only 0 arguments + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_args_required_const-arguments.rs:6:29 + | +LL | #[rustc_args_required_const(1)] + | ^ there is only 1 argument + +error: arguments should be non-negative integers + --> $DIR/invalid-rustc_args_required_const-arguments.rs:9:29 + | +LL | #[rustc_args_required_const(a)] + | ^ + +error: arguments should be non-negative integers + --> $DIR/invalid-rustc_args_required_const-arguments.rs:12:32 + | +LL | #[rustc_args_required_const(1, a, 2, b)] + | ^ ^ + +error: attribute should be applied to a function + --> $DIR/invalid-rustc_args_required_const-arguments.rs:15:1 + | +LL | #[rustc_args_required_const(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct S; + | --------- not a function + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_args_required_const-arguments.rs:22:33 + | +LL | #[rustc_args_required_const(1)] + | ^ there is only 1 argument + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/issue-74047.stderr b/src/test/ui/issue-74047.stderr index 6f477c77ce..8f7c91a78d 100644 --- a/src/test/ui/issue-74047.stderr +++ b/src/test/ui/issue-74047.stderr @@ -5,7 +5,7 @@ LL | impl TryFrom for MyStream {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Error`, `try_from` in implementation | = help: implement the missing item: `type Error = Type;` - = help: implement the missing item: `fn try_from(_: T) -> std::result::Result>::Error> { todo!() }` + = help: implement the missing item: `fn try_from(_: T) -> std::result::Result>::Error> { todo!() }` error: aborting due to previous error diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr index b3b29a7264..867f8f0496 100644 --- a/src/test/ui/issues-71798.stderr +++ b/src/test/ui/issues-71798.stderr @@ -12,7 +12,7 @@ LL | fn test_ref(x: &u32) -> impl std::future::Future + '_ { LL | *x | -- this returned value is of type `u32` | - = help: the trait `std::future::Future` is not implemented for `u32` + = help: the trait `Future` is not implemented for `u32` = note: the return type of a function must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/auxiliary/issue-75907.rs b/src/test/ui/issues/auxiliary/issue-75907.rs new file mode 100644 index 0000000000..0b70452a24 --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-75907.rs @@ -0,0 +1,5 @@ +pub struct Bar(pub u8, u8, u8); + +pub fn make_bar() -> Bar { + Bar(1, 12, 10) +} diff --git a/src/test/ui/issues/issue-10398.stderr b/src/test/ui/issues/issue-10398.stderr index f5f4974265..8d9faf324e 100644 --- a/src/test/ui/issues/issue-10398.stderr +++ b/src/test/ui/issues/issue-10398.stderr @@ -6,7 +6,7 @@ LL | let _a = x; LL | drop(x); | ^ value used here after move | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index d241e6406d..2a6e241459 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -55,7 +55,7 @@ LL | trait Serializable<'self, T> { LL | impl<'self> Serializable for &'self str { | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` help: consider relaxing the implicit `Sized` restriction | LL | trait Serializable<'self, T: ?Sized> { diff --git a/src/test/ui/issues/issue-10465.stderr b/src/test/ui/issues/issue-10465.stderr index 666fb6ab2b..eb32c8db3f 100644 --- a/src/test/ui/issues/issue-10465.stderr +++ b/src/test/ui/issues/issue-10465.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `foo` found for reference `&b::B` in the current scope +error[E0599]: no method named `foo` found for reference `&B` in the current scope --> $DIR/issue-10465.rs:17:15 | LL | b.foo(); - | ^^^ method not found in `&b::B` + | ^^^ method not found in `&B` | = help: items from traits can only be used if the trait is in scope = note: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-11374.stderr b/src/test/ui/issues/issue-11374.stderr index bc7d124750..d6a3e758de 100644 --- a/src/test/ui/issues/issue-11374.stderr +++ b/src/test/ui/issues/issue-11374.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | c.read_to(v); | ^ | | - | expected `&mut [u8]`, found struct `std::vec::Vec` + | expected `&mut [u8]`, found struct `Vec` | help: consider mutably borrowing here: `&mut v` | = note: expected mutable reference `&mut [u8]` - found struct `std::vec::Vec<_>` + found struct `Vec<_>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-11515.stderr b/src/test/ui/issues/issue-11515.stderr index b53563d7b6..7935615ad7 100644 --- a/src/test/ui/issues/issue-11515.stderr +++ b/src/test/ui/issues/issue-11515.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-11515.rs:9:33 | LL | let test = box Test { func: closure }; - | ^^^^^^^ expected trait `std::ops::FnMut`, found trait `std::ops::Fn` + | ^^^^^^^ expected trait `FnMut`, found trait `Fn` | - = note: expected struct `std::boxed::Box<(dyn std::ops::FnMut() + 'static)>` - found struct `std::boxed::Box<(dyn std::ops::Fn() + 'static)>` + = note: expected struct `Box<(dyn FnMut() + 'static)>` + found struct `Box<(dyn Fn() + 'static)>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-11771.stderr b/src/test/ui/issues/issue-11771.stderr index e78d8423e8..9f250925e5 100644 --- a/src/test/ui/issues/issue-11771.stderr +++ b/src/test/ui/issues/issue-11771.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot add `()` to `{integer}` LL | 1 + | ^ no implementation for `{integer} + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `{integer}` + = help: the trait `Add<()>` is not implemented for `{integer}` error[E0277]: cannot add `()` to `{integer}` --> $DIR/issue-11771.rs:8:7 @@ -12,7 +12,7 @@ error[E0277]: cannot add `()` to `{integer}` LL | 1 + | ^ no implementation for `{integer} + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `{integer}` + = help: the trait `Add<()>` is not implemented for `{integer}` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-11844.stderr b/src/test/ui/issues/issue-11844.stderr index 57533ba5e3..00eecbc9a9 100644 --- a/src/test/ui/issues/issue-11844.stderr +++ b/src/test/ui/issues/issue-11844.stderr @@ -2,11 +2,11 @@ error[E0308]: mismatched types --> $DIR/issue-11844.rs:6:9 | LL | match a { - | - this expression has type `std::option::Option>` + | - this expression has type `Option>` LL | Ok(a) => - | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option>` + = note: expected enum `Option>` found enum `std::result::Result<_, _>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12041.stderr b/src/test/ui/issues/issue-12041.stderr index d95cc89ce9..b9ffa499af 100644 --- a/src/test/ui/issues/issue-12041.stderr +++ b/src/test/ui/issues/issue-12041.stderr @@ -4,7 +4,7 @@ error[E0382]: use of moved value: `tx` LL | let tx = tx; | ^^ value moved here, in previous iteration of loop | - = note: move occurs because `tx` has type `std::sync::mpsc::Sender`, which does not implement the `Copy` trait + = note: move occurs because `tx` has type `Sender`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12127.stderr b/src/test/ui/issues/issue-12127.stderr index b759aa45e3..e1559ab2fe 100644 --- a/src/test/ui/issues/issue-12127.stderr +++ b/src/test/ui/issues/issue-12127.stderr @@ -11,7 +11,7 @@ note: this value implements `FnOnce`, which causes it to be moved when called | LL | f(); | ^ - = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41 x:std::boxed::Box]`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41]`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr index 45fede4410..1594c9f503 100644 --- a/src/test/ui/issues/issue-12552.stderr +++ b/src/test/ui/issues/issue-12552.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | match t { | - this expression has type `std::result::Result<_, {integer}>` LL | Some(k) => match k { - | ^^^^^^^ expected enum `std::result::Result`, found enum `std::option::Option` + | ^^^^^^^ expected enum `std::result::Result`, found enum `Option` | = note: expected enum `std::result::Result<_, {integer}>` - found enum `std::option::Option<_>` + found enum `Option<_>` error[E0308]: mismatched types --> $DIR/issue-12552.rs:9:5 @@ -16,10 +16,10 @@ LL | match t { | - this expression has type `std::result::Result<_, {integer}>` ... LL | None => () - | ^^^^ expected enum `std::result::Result`, found enum `std::option::Option` + | ^^^^ expected enum `std::result::Result`, found enum `Option` | = note: expected enum `std::result::Result<_, {integer}>` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-12997-2.stderr b/src/test/ui/issues/issue-12997-2.stderr index 04464896e9..895b415a7e 100644 --- a/src/test/ui/issues/issue-12997-2.stderr +++ b/src/test/ui/issues/issue-12997-2.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-12997-2.rs:8:1 | LL | fn bar(x: isize) { } - | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `&mut test::Bencher` + | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `&mut Bencher` | = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-13407.stderr b/src/test/ui/issues/issue-13407.stderr index f30b6cdeaf..4df1813a71 100644 --- a/src/test/ui/issues/issue-13407.stderr +++ b/src/test/ui/issues/issue-13407.stderr @@ -10,12 +10,6 @@ note: the unit struct `C` is defined here LL | struct C; | ^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/issue-13407.rs:6:12 - | -LL | A::C = 1; - | ^ expected struct `A::C`, found integer - error[E0070]: invalid left-hand side of assignment --> $DIR/issue-13407.rs:6:10 | @@ -24,6 +18,12 @@ LL | A::C = 1; | | | cannot assign to this expression +error[E0308]: mismatched types + --> $DIR/issue-13407.rs:6:12 + | +LL | A::C = 1; + | ^ expected struct `C`, found integer + error: aborting due to 3 previous errors Some errors have detailed explanations: E0070, E0308, E0603. diff --git a/src/test/ui/issues/issue-13446.stderr b/src/test/ui/issues/issue-13446.stderr index 71d3bfe339..962f8ee9dd 100644 --- a/src/test/ui/issues/issue-13446.stderr +++ b/src/test/ui/issues/issue-13446.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-13446.rs:3:26 | LL | static VEC: [u32; 256] = vec![]; - | ^^^^^^ expected array `[u32; 256]`, found struct `std::vec::Vec` + | ^^^^^^ expected array `[u32; 256]`, found struct `Vec` | = note: expected array `[u32; 256]` - found struct `std::vec::Vec<_>` + found struct `Vec<_>` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13466.rs b/src/test/ui/issues/issue-13466.rs index 411e7cbeeb..8048dae123 100644 --- a/src/test/ui/issues/issue-13466.rs +++ b/src/test/ui/issues/issue-13466.rs @@ -7,14 +7,14 @@ pub fn main() { let _x: usize = match Some(1) { Ok(u) => u, //~^ ERROR mismatched types - //~| expected enum `std::option::Option<{integer}>` + //~| expected enum `Option<{integer}>` //~| found enum `std::result::Result<_, _>` - //~| expected enum `std::option::Option`, found enum `std::result::Result` + //~| expected enum `Option`, found enum `std::result::Result` Err(e) => panic!(e) //~^ ERROR mismatched types - //~| expected enum `std::option::Option<{integer}>` + //~| expected enum `Option<{integer}>` //~| found enum `std::result::Result<_, _>` - //~| expected enum `std::option::Option`, found enum `std::result::Result` + //~| expected enum `Option`, found enum `std::result::Result` }; } diff --git a/src/test/ui/issues/issue-13466.stderr b/src/test/ui/issues/issue-13466.stderr index 52d9e2a91b..792cc398bb 100644 --- a/src/test/ui/issues/issue-13466.stderr +++ b/src/test/ui/issues/issue-13466.stderr @@ -2,23 +2,23 @@ error[E0308]: mismatched types --> $DIR/issue-13466.rs:8:9 | LL | let _x: usize = match Some(1) { - | ------- this expression has type `std::option::Option<{integer}>` + | ------- this expression has type `Option<{integer}>` LL | Ok(u) => u, - | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option<{integer}>` + = note: expected enum `Option<{integer}>` found enum `std::result::Result<_, _>` error[E0308]: mismatched types --> $DIR/issue-13466.rs:14:9 | LL | let _x: usize = match Some(1) { - | ------- this expression has type `std::option::Option<{integer}>` + | ------- this expression has type `Option<{integer}>` ... LL | Err(e) => panic!(e) - | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option<{integer}>` + = note: expected enum `Option<{integer}>` found enum `std::result::Result<_, _>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-13853-2.stderr b/src/test/ui/issues/issue-13853-2.stderr index 49b946b354..667ddbca97 100644 --- a/src/test/ui/issues/issue-13853-2.stderr +++ b/src/test/ui/issues/issue-13853-2.stderr @@ -1,4 +1,4 @@ -error[E0615]: attempted to take value of method `get` on type `std::boxed::Box<(dyn ResponseHook + 'static)>` +error[E0615]: attempted to take value of method `get` on type `Box<(dyn ResponseHook + 'static)>` --> $DIR/issue-13853-2.rs:5:43 | LL | fn foo(res : Box) { res.get } diff --git a/src/test/ui/issues/issue-13853.stderr b/src/test/ui/issues/issue-13853.stderr index 3f1b955ddd..527e0225eb 100644 --- a/src/test/ui/issues/issue-13853.stderr +++ b/src/test/ui/issues/issue-13853.stderr @@ -22,11 +22,11 @@ error[E0308]: mismatched types LL | iterate(graph); | ^^^^^ | | - | expected reference, found struct `std::vec::Vec` + | expected reference, found struct `Vec` | help: consider borrowing here: `&graph` | = note: expected reference `&_` - found struct `std::vec::Vec` + found struct `Vec` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-14366.stderr b/src/test/ui/issues/issue-14366.stderr index 4e41acf433..d5dab561dd 100644 --- a/src/test/ui/issues/issue-14366.stderr +++ b/src/test/ui/issues/issue-14366.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | let _x = "test" as &dyn (::std::any::Any); | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::any::Any` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn Any` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14915.rs b/src/test/ui/issues/issue-14915.rs index 4acb51a4e5..909540355e 100644 --- a/src/test/ui/issues/issue-14915.rs +++ b/src/test/ui/issues/issue-14915.rs @@ -4,5 +4,5 @@ fn main() { let x: Box = box 0; println!("{}", x + 1); - //~^ ERROR cannot add `{integer}` to `std::boxed::Box` + //~^ ERROR cannot add `{integer}` to `Box` } diff --git a/src/test/ui/issues/issue-14915.stderr b/src/test/ui/issues/issue-14915.stderr index 3c34a8a346..bd0b1d39a5 100644 --- a/src/test/ui/issues/issue-14915.stderr +++ b/src/test/ui/issues/issue-14915.stderr @@ -1,10 +1,10 @@ -error[E0369]: cannot add `{integer}` to `std::boxed::Box` +error[E0369]: cannot add `{integer}` to `Box` --> $DIR/issue-14915.rs:6:22 | LL | println!("{}", x + 1); | - ^ - {integer} | | - | std::boxed::Box + | Box error: aborting due to previous error diff --git a/src/test/ui/issues/issue-15756.stderr b/src/test/ui/issues/issue-15756.stderr index 68ceebc5b6..d9bdc69ad7 100644 --- a/src/test/ui/issues/issue-15756.stderr +++ b/src/test/ui/issues/issue-15756.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[T]` cannot be known at compilation t LL | &mut something | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[T]` + = help: the trait `Sized` is not implemented for `[T]` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-15783.rs b/src/test/ui/issues/issue-15783.rs index 0c1db02a8e..0b1f4545e8 100644 --- a/src/test/ui/issues/issue-15783.rs +++ b/src/test/ui/issues/issue-15783.rs @@ -7,8 +7,8 @@ fn main() { let x = Some(&[name]); let msg = foo(x); //~^ ERROR mismatched types - //~| expected enum `std::option::Option<&[&str]>` - //~| found enum `std::option::Option<&[&str; 1]>` + //~| expected enum `Option<&[&str]>` + //~| found enum `Option<&[&str; 1]>` //~| expected slice `[&str]`, found array `[&str; 1]` assert_eq!(msg, 3); } diff --git a/src/test/ui/issues/issue-15783.stderr b/src/test/ui/issues/issue-15783.stderr index 74a96df5b1..0b09751676 100644 --- a/src/test/ui/issues/issue-15783.stderr +++ b/src/test/ui/issues/issue-15783.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | let msg = foo(x); | ^ expected slice `[&str]`, found array `[&str; 1]` | - = note: expected enum `std::option::Option<&[&str]>` - found enum `std::option::Option<&[&str; 1]>` + = note: expected enum `Option<&[&str]>` + found enum `Option<&[&str; 1]>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-15896.rs b/src/test/ui/issues/issue-15896.rs index a11c9d07f6..d3153b516e 100644 --- a/src/test/ui/issues/issue-15896.rs +++ b/src/test/ui/issues/issue-15896.rs @@ -10,7 +10,6 @@ fn main() { E::B( Tau{t: x}, //~^ ERROR mismatched types - //~| expected enum `main::R`, found struct `main::Tau` _) => x, }; } diff --git a/src/test/ui/issues/issue-15896.stderr b/src/test/ui/issues/issue-15896.stderr index b3f0907b81..038337f5ac 100644 --- a/src/test/ui/issues/issue-15896.stderr +++ b/src/test/ui/issues/issue-15896.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-15896.rs:11:11 | LL | let u = match e { - | - this expression has type `main::E` + | - this expression has type `E` LL | E::B( LL | Tau{t: x}, - | ^^^^^^^^^ expected enum `main::R`, found struct `main::Tau` + | ^^^^^^^^^ expected enum `R`, found struct `Tau` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16538.stderr b/src/test/ui/issues/issue-16538.stderr index 5e1f95a989..81a91db371 100644 --- a/src/test/ui/issues/issue-16538.stderr +++ b/src/test/ui/issues/issue-16538.stderr @@ -10,7 +10,7 @@ error[E0277]: `*const usize` cannot be shared between threads safely LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `*const usize` + = help: the trait `Sync` is not implemented for `*const usize` = note: shared static variables must have a type that implements `Sync` error[E0133]: use of extern static is unsafe and requires unsafe function or block diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index ee621a8cb1..1148577016 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -1,22 +1,22 @@ error[E0391]: cycle detected when normalizing `FOO` | -note: ...which requires const-evaluating + checking `FOO`... +note: ...which requires simplifying constant for the type system `FOO`... --> $DIR/issue-17252.rs:1:1 | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `FOO`... +note: ...which requires simplifying constant for the type system `FOO`... --> $DIR/issue-17252.rs:1:1 | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `FOO`... +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/issue-17252.rs:1:1 | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires normalizing `FOO`, completing the cycle -note: cycle used when const-evaluating `main::{{constant}}#0` +note: cycle used when const-evaluating + checking `main::{constant#0}` --> $DIR/issue-17252.rs:4:18 | LL | let _x: [u8; FOO]; // caused stack overflow prior to fix diff --git a/src/test/ui/issues/issue-17441.rs b/src/test/ui/issues/issue-17441.rs index b9813ef1ee..e5f83c4eba 100644 --- a/src/test/ui/issues/issue-17441.rs +++ b/src/test/ui/issues/issue-17441.rs @@ -3,10 +3,10 @@ fn main() { //~^ ERROR cast to unsized type: `&[usize; 2]` as `[usize]` let _bar = Box::new(1_usize) as dyn std::fmt::Debug; - //~^ ERROR cast to unsized type: `std::boxed::Box` as `dyn std::fmt::Debug` + //~^ ERROR cast to unsized type: `Box` as `dyn Debug` let _baz = 1_usize as dyn std::fmt::Debug; - //~^ ERROR cast to unsized type: `usize` as `dyn std::fmt::Debug` + //~^ ERROR cast to unsized type: `usize` as `dyn Debug` let _quux = [1_usize, 2] as [usize]; //~^ ERROR cast to unsized type: `[usize; 2]` as `[usize]` diff --git a/src/test/ui/issues/issue-17441.stderr b/src/test/ui/issues/issue-17441.stderr index b63a3995d2..4dbe50178c 100644 --- a/src/test/ui/issues/issue-17441.stderr +++ b/src/test/ui/issues/issue-17441.stderr @@ -10,7 +10,7 @@ help: consider using an implicit coercion to `&[usize]` instead LL | let _foo = &[1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0620]: cast to unsized type: `std::boxed::Box` as `dyn std::fmt::Debug` +error[E0620]: cast to unsized type: `Box` as `dyn Debug` --> $DIR/issue-17441.rs:5:16 | LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; @@ -18,7 +18,7 @@ LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; | | | help: you can cast to a `Box` instead: `Box` -error[E0620]: cast to unsized type: `usize` as `dyn std::fmt::Debug` +error[E0620]: cast to unsized type: `usize` as `dyn Debug` --> $DIR/issue-17441.rs:8:16 | LL | let _baz = 1_usize as dyn std::fmt::Debug; diff --git a/src/test/ui/issues/issue-17651.stderr b/src/test/ui/issues/issue-17651.stderr index 812778911a..987f4e97f3 100644 --- a/src/test/ui/issues/issue-17651.stderr +++ b/src/test/ui/issues/issue-17651.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi LL | (|| Box::new(*(&[0][..])))(); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: required by `std::boxed::Box::::new` + = help: the trait `Sized` is not implemented for `[{integer}]` + = note: required by `Box::::new` error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time --> $DIR/issue-17651.rs:5:9 @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi LL | (|| Box::new(*(&[0][..])))(); | ^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` + = help: the trait `Sized` is not implemented for `[{integer}]` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-17718-static-sync.stderr b/src/test/ui/issues/issue-17718-static-sync.stderr index 7f162a9985..4cd85124c3 100644 --- a/src/test/ui/issues/issue-17718-static-sync.stderr +++ b/src/test/ui/issues/issue-17718-static-sync.stderr @@ -4,7 +4,7 @@ error[E0277]: `Foo` cannot be shared between threads safely LL | static BAR: Foo = Foo; | ^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `Foo` + = help: the trait `Sync` is not implemented for `Foo` = note: shared static variables must have a type that implements `Sync` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17728.nll.stderr b/src/test/ui/issues/issue-17728.nll.stderr index d515cf451c..a13d2dfa1f 100644 --- a/src/test/ui/issues/issue-17728.nll.stderr +++ b/src/test/ui/issues/issue-17728.nll.stderr @@ -9,12 +9,12 @@ LL | | "n" | "north" => RoomDirection::North, LL | | "down" => RoomDirection::Down, | | ------------------- this and all prior arms are found to be of type `RoomDirection` LL | | _ => None - | | ^^^^ expected enum `RoomDirection`, found enum `std::option::Option` + | | ^^^^ expected enum `RoomDirection`, found enum `Option` LL | | } | |_____- `match` arms have incompatible types | = note: expected enum `RoomDirection` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17728.stderr b/src/test/ui/issues/issue-17728.stderr index 2f9ae63aa4..50e3b853fc 100644 --- a/src/test/ui/issues/issue-17728.stderr +++ b/src/test/ui/issues/issue-17728.stderr @@ -20,12 +20,12 @@ LL | | "n" | "north" => RoomDirection::North, LL | | "down" => RoomDirection::Down, | | ------------------- this and all prior arms are found to be of type `RoomDirection` LL | | _ => None - | | ^^^^ expected enum `RoomDirection`, found enum `std::option::Option` + | | ^^^^ expected enum `RoomDirection`, found enum `Option` LL | | } | |_____- `match` arms have incompatible types | = note: expected enum `RoomDirection` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17904-2.stderr b/src/test/ui/issues/issue-17904-2.stderr index 25f32b6610..62b7b79538 100644 --- a/src/test/ui/issues/issue-17904-2.stderr +++ b/src/test/ui/issues/issue-17904-2.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `T` is never used LL | struct Foo where T: Copy; | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17959.rs b/src/test/ui/issues/issue-17959.rs index 01416a0d79..8bf9e62360 100644 --- a/src/test/ui/issues/issue-17959.rs +++ b/src/test/ui/issues/issue-17959.rs @@ -9,7 +9,7 @@ struct G { } impl Drop for G { -//~^ ERROR `Drop` impl requires `T: std::marker::Sized` +//~^ ERROR `Drop` impl requires `T: Sized` fn drop(&mut self) { if !self._ptr.is_null() { } diff --git a/src/test/ui/issues/issue-17959.stderr b/src/test/ui/issues/issue-17959.stderr index 29d32c1f3c..f00356f602 100644 --- a/src/test/ui/issues/issue-17959.stderr +++ b/src/test/ui/issues/issue-17959.stderr @@ -1,4 +1,4 @@ -error[E0367]: `Drop` impl requires `T: std::marker::Sized` but the struct it is implemented for does not +error[E0367]: `Drop` impl requires `T: Sized` but the struct it is implemented for does not --> $DIR/issue-17959.rs:11:6 | LL | impl Drop for G { diff --git a/src/test/ui/issues/issue-18400.stderr b/src/test/ui/issues/issue-18400.stderr index ed9137ce39..35fa5fde0a 100644 --- a/src/test/ui/issues/issue-18400.stderr +++ b/src/test/ui/issues/issue-18400.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `_: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `_: Sized` --> $DIR/issue-18400.rs:24:7 | LL | 0.contains(bits); diff --git a/src/test/ui/issues/issue-18783.stderr b/src/test/ui/issues/issue-18783.stderr index 047b42578a..cc223ac464 100644 --- a/src/test/ui/issues/issue-18783.stderr +++ b/src/test/ui/issues/issue-18783.stderr @@ -11,7 +11,7 @@ LL | c.push(Box::new(|| y = 0)); | second mutable borrow occurs here LL | LL | } - | - first borrow might be used here, when `c` is dropped and runs the destructor for type `std::cell::RefCell>>` + | - first borrow might be used here, when `c` is dropped and runs the destructor for type `RefCell>>` error[E0499]: cannot borrow `y` as mutable more than once at a time --> $DIR/issue-18783.rs:16:29 @@ -26,7 +26,7 @@ LL | Push::push(&c, Box::new(|| y = 0)); | second mutable borrow occurs here LL | LL | } - | - first borrow might be used here, when `c` is dropped and runs the destructor for type `std::cell::RefCell>>` + | - first borrow might be used here, when `c` is dropped and runs the destructor for type `RefCell>>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr index 3b5dfd1ad1..ece714c949 100644 --- a/src/test/ui/issues/issue-18919.stderr +++ b/src/test/ui/issues/issue-18919.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for values of type `dyn for<'r> std::ops::Fn(&'r isize) -> isize` cannot be known at compilation time +error[E0277]: the size for values of type `dyn for<'r> Fn(&'r isize) -> isize` cannot be known at compilation time --> $DIR/issue-18919.rs:3:15 | LL | fn ho_func(f: Option) { @@ -7,7 +7,7 @@ LL | fn ho_func(f: Option) { LL | enum Option { | - required by this bound in `Option` | - = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize` + = help: the trait `Sized` is not implemented for `dyn for<'r> Fn(&'r isize) -> isize` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-18919.rs:7:13 | diff --git a/src/test/ui/issues/issue-1920-1.rs b/src/test/ui/issues/issue-1920-1.rs index 996052d749..26553f56b8 100644 --- a/src/test/ui/issues/issue-1920-1.rs +++ b/src/test/ui/issues/issue-1920-1.rs @@ -10,5 +10,5 @@ fn assert_clone() where T : Clone { } fn main() { assert_clone::(); - //~^ ERROR `foo::issue_1920::S: std::clone::Clone` is not satisfied + //~^ ERROR `S: Clone` is not satisfied } diff --git a/src/test/ui/issues/issue-1920-1.stderr b/src/test/ui/issues/issue-1920-1.stderr index 3130434f6f..0a2459c3a5 100644 --- a/src/test/ui/issues/issue-1920-1.stderr +++ b/src/test/ui/issues/issue-1920-1.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `foo::issue_1920::S: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `S: Clone` is not satisfied --> $DIR/issue-1920-1.rs:12:20 | LL | fn assert_clone() where T : Clone { } | ----- required by this bound in `assert_clone` ... LL | assert_clone::(); - | ^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `foo::issue_1920::S` + | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `S` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-1920-2.rs b/src/test/ui/issues/issue-1920-2.rs index 56d842ec4a..8d4a5f6631 100644 --- a/src/test/ui/issues/issue-1920-2.rs +++ b/src/test/ui/issues/issue-1920-2.rs @@ -8,5 +8,5 @@ fn assert_clone() where T : Clone { } fn main() { assert_clone::(); - //~^ ERROR `bar::S: std::clone::Clone` is not satisfied + //~^ ERROR `S: Clone` is not satisfied } diff --git a/src/test/ui/issues/issue-1920-2.stderr b/src/test/ui/issues/issue-1920-2.stderr index 1084c47f00..06bc78a387 100644 --- a/src/test/ui/issues/issue-1920-2.stderr +++ b/src/test/ui/issues/issue-1920-2.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `bar::S: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `S: Clone` is not satisfied --> $DIR/issue-1920-2.rs:10:20 | LL | fn assert_clone() where T : Clone { } | ----- required by this bound in `assert_clone` ... LL | assert_clone::(); - | ^^^^^^ the trait `std::clone::Clone` is not implemented for `bar::S` + | ^^^^^^ the trait `Clone` is not implemented for `S` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-1920-3.rs b/src/test/ui/issues/issue-1920-3.rs index 83f3fdb9eb..520db50f94 100644 --- a/src/test/ui/issues/issue-1920-3.rs +++ b/src/test/ui/issues/issue-1920-3.rs @@ -12,5 +12,5 @@ fn assert_clone() where T : Clone { } fn main() { assert_clone::(); - //~^ ERROR `issue_1920::S: std::clone::Clone` is not satisfied + //~^ ERROR `S: Clone` is not satisfied } diff --git a/src/test/ui/issues/issue-1920-3.stderr b/src/test/ui/issues/issue-1920-3.stderr index 11740317e5..48d3105bf9 100644 --- a/src/test/ui/issues/issue-1920-3.stderr +++ b/src/test/ui/issues/issue-1920-3.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `issue_1920::S: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `S: Clone` is not satisfied --> $DIR/issue-1920-3.rs:14:20 | LL | fn assert_clone() where T : Clone { } | ----- required by this bound in `assert_clone` ... LL | assert_clone::(); - | ^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `issue_1920::S` + | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `S` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19538.stderr b/src/test/ui/issues/issue-19538.stderr index b6033e47b1..71a013248c 100644 --- a/src/test/ui/issues/issue-19538.stderr +++ b/src/test/ui/issues/issue-19538.stderr @@ -25,7 +25,7 @@ LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^ the trait `Bar` cannot be made into an object | = help: consider moving `foo` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&mut dyn Bar>` for `&mut Thing` + = note: required because of the requirements on the impl of `CoerceUnsized<&mut dyn Bar>` for `&mut Thing` = note: required by cast to type `&mut dyn Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr index cbaa750724..bc414044f7 100644 --- a/src/test/ui/issues/issue-20005.stderr +++ b/src/test/ui/issues/issue-20005.stderr @@ -9,8 +9,8 @@ LL | ) -> >::Result where Dst: From { | help: consider further restricting `Self` | -LL | ) -> >::Result where Dst: From, Self: std::marker::Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ) -> >::Result where Dst: From, Self: Sized { + | ^^^^^^^^^^^^^ help: consider relaxing the implicit `Sized` restriction | LL | trait From { diff --git a/src/test/ui/issues/issue-20162.rs b/src/test/ui/issues/issue-20162.rs index b7f9caee89..b491bc37f5 100644 --- a/src/test/ui/issues/issue-20162.rs +++ b/src/test/ui/issues/issue-20162.rs @@ -3,5 +3,5 @@ struct X { x: i32 } fn main() { let mut b: Vec = vec![]; b.sort(); - //~^ ERROR `X: std::cmp::Ord` is not satisfied + //~^ ERROR `X: Ord` is not satisfied } diff --git a/src/test/ui/issues/issue-20162.stderr b/src/test/ui/issues/issue-20162.stderr index 1d0d6d5c5d..ef1eb2ea6c 100644 --- a/src/test/ui/issues/issue-20162.stderr +++ b/src/test/ui/issues/issue-20162.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `X: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `X: Ord` is not satisfied --> $DIR/issue-20162.rs:5:7 | LL | b.sort(); - | ^^^^ the trait `std::cmp::Ord` is not implemented for `X` + | ^^^^ the trait `Ord` is not implemented for `X` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index a3eb4fec70..3f96f0bfcd 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `T` is never used LL | struct NoData; | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:36 diff --git a/src/test/ui/issues/issue-20433.stderr b/src/test/ui/issues/issue-20433.stderr index fda3f2f5db..3c14226b73 100644 --- a/src/test/ui/issues/issue-20433.stderr +++ b/src/test/ui/issues/issue-20433.stderr @@ -7,9 +7,9 @@ LL | fn iceman(c: Vec<[i32]>) {} ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | LL | pub struct Vec { - | - required by this bound in `std::vec::Vec` + | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `[i32]` + = help: the trait `Sized` is not implemented for `[i32]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index 5e06e3bc95..e8d16a55e9 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -1,11 +1,11 @@ -error[E0277]: the size for values of type `dyn std::iter::Iterator` cannot be known at compilation time +error[E0277]: the size for values of type `dyn Iterator` cannot be known at compilation time --> $DIR/issue-20605.rs:2:17 | LL | for item in *things { *item = 0 } | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Sized` is not implemented for `dyn Iterator` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr index ca2611e0f9..0badf66ba7 100644 --- a/src/test/ui/issues/issue-20692.stderr +++ b/src/test/ui/issues/issue-20692.stderr @@ -22,7 +22,7 @@ LL | trait Array: Sized + Copy {} LL | let _ = x | ^ the trait `Array` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Array>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Array>` for `&T` = note: required by cast to type `&dyn Array` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-2111.stderr b/src/test/ui/issues/issue-2111.stderr index aab2559a15..a39a479e07 100644 --- a/src/test/ui/issues/issue-2111.stderr +++ b/src/test/ui/issues/issue-2111.stderr @@ -5,7 +5,7 @@ LL | match (a,b) { | ^^^^^ pattern `(None, None)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(std::option::Option, std::option::Option)` + = note: the matched value is of type `(Option, Option)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21160.rs b/src/test/ui/issues/issue-21160.rs index 46733566cf..10136ba11a 100644 --- a/src/test/ui/issues/issue-21160.rs +++ b/src/test/ui/issues/issue-21160.rs @@ -6,6 +6,6 @@ impl Bar { #[derive(Hash)] struct Foo(Bar); -//~^ error: `Bar: std::hash::Hash` is not satisfied +//~^ error: `Bar: Hash` is not satisfied fn main() {} diff --git a/src/test/ui/issues/issue-21160.stderr b/src/test/ui/issues/issue-21160.stderr index aaba014fcb..b6ebfb3556 100644 --- a/src/test/ui/issues/issue-21160.stderr +++ b/src/test/ui/issues/issue-21160.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Bar: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Bar: Hash` is not satisfied --> $DIR/issue-21160.rs:8:12 | LL | struct Foo(Bar); - | ^^^ the trait `std::hash::Hash` is not implemented for `Bar` + | ^^^ the trait `Hash` is not implemented for `Bar` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/issues/issue-21332.rs b/src/test/ui/issues/issue-21332.rs index db157f095a..1b13f000b8 100644 --- a/src/test/ui/issues/issue-21332.rs +++ b/src/test/ui/issues/issue-21332.rs @@ -4,7 +4,7 @@ impl Iterator for S { type Item = i32; fn next(&mut self) -> Result { Ok(7) } //~^ ERROR method `next` has an incompatible type for trait - //~| expected enum `std::option::Option`, found enum `std::result::Result` + //~| expected enum `Option`, found enum `std::result::Result` } fn main() {} diff --git a/src/test/ui/issues/issue-21332.stderr b/src/test/ui/issues/issue-21332.stderr index ace3e01464..1d6ddd2660 100644 --- a/src/test/ui/issues/issue-21332.stderr +++ b/src/test/ui/issues/issue-21332.stderr @@ -2,9 +2,9 @@ error[E0053]: method `next` has an incompatible type for trait --> $DIR/issue-21332.rs:5:5 | LL | fn next(&mut self) -> Result { Ok(7) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected fn pointer `fn(&mut S) -> std::option::Option` + = note: expected fn pointer `fn(&mut S) -> Option` found fn pointer `fn(&mut S) -> std::result::Result` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr index 3e0a532b2b..70b975524e 100644 --- a/src/test/ui/issues/issue-21596.stderr +++ b/src/test/ui/issues/issue-21596.stderr @@ -8,7 +8,7 @@ LL | println!("{}", z.to_string()); = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior = note: the method `to_string` exists but the following trait bounds were not satisfied: `*const u8: std::fmt::Display` - which is required by `*const u8: std::string::ToString` + which is required by `*const u8: ToString` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21763.rs b/src/test/ui/issues/issue-21763.rs index 29ee5f9171..5beb1d8b8c 100644 --- a/src/test/ui/issues/issue-21763.rs +++ b/src/test/ui/issues/issue-21763.rs @@ -7,5 +7,5 @@ fn foo() {} fn main() { foo::, Rc<()>>>(); - //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely + //~^ ERROR `Rc<()>` cannot be sent between threads safely } diff --git a/src/test/ui/issues/issue-21763.stderr b/src/test/ui/issues/issue-21763.stderr index 3ec876f37d..4d27f507e2 100644 --- a/src/test/ui/issues/issue-21763.stderr +++ b/src/test/ui/issues/issue-21763.stderr @@ -1,17 +1,17 @@ -error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely +error[E0277]: `Rc<()>` cannot be sent between threads safely --> $DIR/issue-21763.rs:9:5 | LL | fn foo() {} | ---- required by this bound in `foo` ... LL | foo::, Rc<()>>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely | - = help: within `(std::rc::Rc<()>, std::rc::Rc<()>)`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` - = note: required because it appears within the type `(std::rc::Rc<()>, std::rc::Rc<()>)` - = note: required because of the requirements on the impl of `std::marker::Send` for `hashbrown::raw::RawTable<(std::rc::Rc<()>, std::rc::Rc<()>)>` - = note: required because it appears within the type `hashbrown::map::HashMap, std::rc::Rc<()>, std::collections::hash_map::RandomState>` - = note: required because it appears within the type `std::collections::HashMap, std::rc::Rc<()>>` + = help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>` + = note: required because it appears within the type `(Rc<()>, Rc<()>)` + = note: required because of the requirements on the impl of `Send` for `hashbrown::raw::RawTable<(Rc<()>, Rc<()>)>` + = note: required because it appears within the type `hashbrown::map::HashMap, Rc<()>, RandomState>` + = note: required because it appears within the type `HashMap, Rc<()>>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22034.rs b/src/test/ui/issues/issue-22034.rs index fab1cdadaf..405ffd089c 100644 --- a/src/test/ui/issues/issue-22034.rs +++ b/src/test/ui/issues/issue-22034.rs @@ -6,6 +6,6 @@ fn main() { let ptr: *mut () = core::ptr::null_mut(); let _: &mut dyn Fn() = unsafe { &mut *(ptr as *mut dyn Fn()) - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `()` + //~^ ERROR expected a `Fn<()>` closure, found `()` }; } diff --git a/src/test/ui/issues/issue-22034.stderr b/src/test/ui/issues/issue-22034.stderr index 132880aab1..edcd21ebd6 100644 --- a/src/test/ui/issues/issue-22034.stderr +++ b/src/test/ui/issues/issue-22034.stderr @@ -1,12 +1,12 @@ -error[E0277]: expected a `std::ops::Fn<()>` closure, found `()` +error[E0277]: expected a `Fn<()>` closure, found `()` --> $DIR/issue-22034.rs:8:16 | LL | &mut *(ptr as *mut dyn Fn()) | ^^^ expected an `Fn<()>` closure, found `()` | - = help: the trait `std::ops::Fn<()>` is not implemented for `()` + = help: the trait `Fn<()>` is not implemented for `()` = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` - = note: required for the cast to the object type `dyn std::ops::Fn()` + = note: required for the cast to the object type `dyn Fn()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2214.rs b/src/test/ui/issues/issue-2214.rs index c4c56cd109..9b7c448541 100644 --- a/src/test/ui/issues/issue-2214.rs +++ b/src/test/ui/issues/issue-2214.rs @@ -23,7 +23,6 @@ fn lgamma(n: c_double, value: &mut isize) -> c_double { mod m { use libc::{c_double, c_int}; - #[link_name = "m"] extern { #[cfg(any(all(unix, not(target_os = "vxworks")), target_os = "cloudabi"))] #[link_name="lgamma_r"] diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr index 4c35deb1fb..6002785360 100644 --- a/src/test/ui/issues/issue-22289.stderr +++ b/src/test/ui/issues/issue-22289.stderr @@ -1,4 +1,4 @@ -error[E0605]: non-primitive cast: `i32` as `&(dyn std::any::Any + 'static)` +error[E0605]: non-primitive cast: `i32` as `&(dyn Any + 'static)` --> $DIR/issue-22289.rs:2:5 | LL | 0 as &dyn std::any::Any; diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr index 28564b0746..823ffc6de6 100644 --- a/src/test/ui/issues/issue-22312.stderr +++ b/src/test/ui/issues/issue-22312.stderr @@ -1,4 +1,4 @@ -error[E0605]: non-primitive cast: `Self` as `&dyn std::ops::Index>::Output>` +error[E0605]: non-primitive cast: `Self` as `&dyn Index>::Output>` --> $DIR/issue-22312.rs:11:24 | LL | let indexer = &(*self as &dyn Index>::Output>); diff --git a/src/test/ui/issues/issue-22638.rs b/src/test/ui/issues/issue-22638.rs index 8913753842..198ceccc2c 100644 --- a/src/test/ui/issues/issue-22638.rs +++ b/src/test/ui/issues/issue-22638.rs @@ -1,5 +1,6 @@ // build-fail // normalize-stderr-test: "<\[closure@.+`" -> "$$CLOSURE`" +// normalize-stderr-test: ".nll/" -> "/" #![allow(unused)] diff --git a/src/test/ui/issues/issue-22638.stderr b/src/test/ui/issues/issue-22638.stderr index c4255b95b7..1354ec8e89 100644 --- a/src/test/ui/issues/issue-22638.stderr +++ b/src/test/ui/issues/issue-22638.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `A::matches::$CLOSURE` - --> $DIR/issue-22638.rs:55:9 + --> $DIR/issue-22638.rs:56:9 | LL | a.matches(f) | ^^^^^^^^^^^^ | note: `A::matches` defined here - --> $DIR/issue-22638.rs:14:5 + --> $DIR/issue-22638.rs:15:5 | LL | pub fn matches(&self, f: &F) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-22638/issue-22638.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr index 038490bbd7..c65a97d999 100644 --- a/src/test/ui/issues/issue-22872.stderr +++ b/src/test/ui/issues/issue-22872.stderr @@ -4,13 +4,13 @@ error[E0277]: `

    >::Item` is not an iterator LL | let _: Box Wrap<'b>> = Box::new(Wrapper(process)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `

    >::Item` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `

    >::Item` + = help: the trait `Iterator` is not implemented for `

    >::Item` = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper

    ` = note: required for the cast to the object type `dyn for<'b> Wrap<'b>` help: consider further restricting the associated type | -LL | fn push_process

    (process: P) where P: Process<'static>,

    >::Item: std::iter::Iterator { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn push_process

    (process: P) where P: Process<'static>,

    >::Item: Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22874.stderr b/src/test/ui/issues/issue-22874.stderr index 6f22fe6a99..d648990804 100644 --- a/src/test/ui/issues/issue-22874.stderr +++ b/src/test/ui/issues/issue-22874.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `[std::string::String]` cannot be known at compilation time +error[E0277]: the size for values of type `[String]` cannot be known at compilation time --> $DIR/issue-22874.rs:2:11 | LL | rows: [[String]], | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[std::string::String]` + = help: the trait `Sized` is not implemented for `[String]` = note: slice and array elements must have `Sized` type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23024.rs b/src/test/ui/issues/issue-23024.rs index 6367536816..ddeb516a4b 100644 --- a/src/test/ui/issues/issue-23024.rs +++ b/src/test/ui/issues/issue-23024.rs @@ -9,5 +9,5 @@ fn main() println!("{:?}",(vfnfer[0] as dyn Fn)(3)); //~^ ERROR the precise format of `Fn`-family traits' //~| ERROR wrong number of type arguments: expected 1, found 0 [E0107] - //~| ERROR the value of the associated type `Output` (from trait `std::ops::FnOnce`) + //~| ERROR the value of the associated type `Output` (from trait `FnOnce`) } diff --git a/src/test/ui/issues/issue-23024.stderr b/src/test/ui/issues/issue-23024.stderr index f9403cd077..fdb68ff712 100644 --- a/src/test/ui/issues/issue-23024.stderr +++ b/src/test/ui/issues/issue-23024.stderr @@ -13,7 +13,7 @@ error[E0107]: wrong number of type arguments: expected 1, found 0 LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); | ^^ expected 1 type argument -error[E0191]: the value of the associated type `Output` (from trait `std::ops::FnOnce`) must be specified +error[E0191]: the value of the associated type `Output` (from trait `FnOnce`) must be specified --> $DIR/issue-23024.rs:9:39 | LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index c4032b27ed..60dbb15d0f 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized` --> $DIR/issue-23122-2.rs:7:15 | LL | impl Next for GetNext { @@ -7,7 +7,7 @@ LL | impl Next for GetNext { = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized` --> $DIR/issue-23122-2.rs:9:5 | LL | type Next = as Next>::Next; diff --git a/src/test/ui/issues/issue-23281.stderr b/src/test/ui/issues/issue-23281.stderr index 46b4be6fd3..d8046497b9 100644 --- a/src/test/ui/issues/issue-23281.stderr +++ b/src/test/ui/issues/issue-23281.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for values of type `(dyn std::ops::Fn() + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time --> $DIR/issue-23281.rs:4:27 | LL | pub fn function(funs: Vec ()>) {} @@ -7,7 +7,7 @@ LL | pub fn function(funs: Vec ()>) {} LL | struct Vec { | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Fn() + 'static)` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-23281.rs:8:12 | diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index b6c85b9e22..d3a1993536 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -1,21 +1,21 @@ -error[E0391]: cycle detected when const-evaluating + checking `X::A::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `X::A::{constant#0}` --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `X::A::{constant#0}`... --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating `X::A::{{constant}}#0`... +note: ...which requires const-evaluating + checking `X::A::{constant#0}`... --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ = note: ...which requires normalizing `X::A as isize`... - = note: ...which again requires const-evaluating + checking `X::A::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `X::A::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23302-1.rs:3:1 | diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index d014922fe2..d3b78ea1af 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -1,21 +1,21 @@ -error[E0391]: cycle detected when const-evaluating + checking `Y::A::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{constant#0}` --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Y::A::{constant#0}`... --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Y::A::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Y::A::{constant#0}`... --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ = note: ...which requires normalizing `Y::B as isize`... - = note: ...which again requires const-evaluating + checking `Y::A::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Y::A::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23302-2.rs:3:1 | diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr index b30b121427..5233b832ec 100644 --- a/src/test/ui/issues/issue-23302-3.stderr +++ b/src/test/ui/issues/issue-23302-3.stderr @@ -1,37 +1,37 @@ -error[E0391]: cycle detected when const-evaluating + checking `A` +error[E0391]: cycle detected when simplifying constant for the type system `A` --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `A`... +note: ...which requires simplifying constant for the type system `A`... --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `A`... +note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `B`... -note: ...which requires const-evaluating + checking `B`... +note: ...which requires simplifying constant for the type system `B`... --> $DIR/issue-23302-3.rs:3:1 | LL | const B: i32 = A; | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `B`... +note: ...which requires simplifying constant for the type system `B`... --> $DIR/issue-23302-3.rs:3:1 | LL | const B: i32 = A; | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `B`... +note: ...which requires const-evaluating + checking `B`... --> $DIR/issue-23302-3.rs:3:1 | LL | const B: i32 = A; | ^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `A`... - = note: ...which again requires const-evaluating + checking `A`, completing the cycle + = note: ...which again requires simplifying constant for the type system `A`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23966.stderr b/src/test/ui/issues/issue-23966.stderr index c2fe6d92b9..fff9b3c303 100644 --- a/src/test/ui/issues/issue-23966.stderr +++ b/src/test/ui/issues/issue-23966.stderr @@ -1,10 +1,10 @@ -error[E0277]: expected a `std::ops::FnMut<(_, char)>` closure, found `()` +error[E0277]: expected a `FnMut<(_, char)>` closure, found `()` --> $DIR/issue-23966.rs:2:32 | LL | "".chars().fold(|_, _| (), ()); | ^^ expected an `FnMut<(_, char)>` closure, found `()` | - = help: the trait `std::ops::FnMut<(_, char)>` is not implemented for `()` + = help: the trait `FnMut<(_, char)>` is not implemented for `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24352.stderr b/src/test/ui/issues/issue-24352.stderr index a315ca8b08..69cd778906 100644 --- a/src/test/ui/issues/issue-24352.stderr +++ b/src/test/ui/issues/issue-24352.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot subtract `{integer}` from `f64` LL | 1.0f64 - 1 | ^ no implementation for `f64 - {integer}` | - = help: the trait `std::ops::Sub<{integer}>` is not implemented for `f64` + = help: the trait `Sub<{integer}>` is not implemented for `f64` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24446.stderr b/src/test/ui/issues/issue-24446.stderr index d2714408d8..1674fa8af2 100644 --- a/src/test/ui/issues/issue-24446.stderr +++ b/src/test/ui/issues/issue-24446.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `(dyn std::ops::Fn() -> u32 + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Fn() -> u32 + 'static)` cannot be known at compilation time --> $DIR/issue-24446.rs:2:17 | LL | static foo: dyn Fn() -> u32 = || -> u32 { | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() -> u32 + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24819.rs b/src/test/ui/issues/issue-24819.rs index 1155e8d5d5..59c3f2cd11 100644 --- a/src/test/ui/issues/issue-24819.rs +++ b/src/test/ui/issues/issue-24819.rs @@ -4,7 +4,7 @@ fn main() { let mut v = Vec::new(); foo(&mut v); //~^ ERROR mismatched types - //~| expected struct `std::collections::HashSet`, found struct `std::vec::Vec` + //~| expected struct `HashSet`, found struct `Vec` } fn foo(h: &mut HashSet) { diff --git a/src/test/ui/issues/issue-24819.stderr b/src/test/ui/issues/issue-24819.stderr index 1166a887f8..2f931e59d5 100644 --- a/src/test/ui/issues/issue-24819.stderr +++ b/src/test/ui/issues/issue-24819.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-24819.rs:5:9 | LL | foo(&mut v); - | ^^^^^^ expected struct `std::collections::HashSet`, found struct `std::vec::Vec` + | ^^^^^^ expected struct `HashSet`, found struct `Vec` | - = note: expected mutable reference `&mut std::collections::HashSet` - found mutable reference `&mut std::vec::Vec<_>` + = note: expected mutable reference `&mut HashSet` + found mutable reference `&mut Vec<_>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr index a09de86a70..6a970bc049 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed for `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)` +error[E0282]: type annotations needed for `(Sender>, std::sync::mpsc::Receiver>)` --> $DIR/issue-25368.rs:11:17 | LL | let (tx, rx) = channel(); - | -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)`, where the type parameter `T` is specified + | -------- consider giving this pattern the explicit type `(Sender>, std::sync::mpsc::Receiver>)`, where the type parameter `T` is specified ... LL | tx.send(Foo{ foo: PhantomData }); | ^^^ cannot infer type for type parameter `T` declared on the struct `Foo` diff --git a/src/test/ui/issues/issue-25386.rs b/src/test/ui/issues/issue-25386.rs index 45775e0e4a..a76d8a615f 100644 --- a/src/test/ui/issues/issue-25386.rs +++ b/src/test/ui/issues/issue-25386.rs @@ -17,12 +17,12 @@ mod stuff { macro_rules! check_ptr_exist { ($var:expr, $member:ident) => ( (*$var.c_object).$member.is_some() - //~^ ERROR field `c_object` of struct `stuff::Item` is private + //~^ ERROR field `c_object` of struct `Item` is private ); } fn main() { let item = stuff::Item::new(); println!("{}", check_ptr_exist!(item, name)); - //~^ ERROR field `name` of struct `stuff::CObj` is private + //~^ ERROR field `name` of struct `CObj` is private } diff --git a/src/test/ui/issues/issue-25386.stderr b/src/test/ui/issues/issue-25386.stderr index 6419e7a557..dcf2f5afa5 100644 --- a/src/test/ui/issues/issue-25386.stderr +++ b/src/test/ui/issues/issue-25386.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `c_object` of struct `stuff::Item` is private +error[E0616]: field `c_object` of struct `Item` is private --> $DIR/issue-25386.rs:19:16 | LL | (*$var.c_object).$member.is_some() @@ -9,7 +9,7 @@ LL | println!("{}", check_ptr_exist!(item, name)); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0616]: field `name` of struct `stuff::CObj` is private +error[E0616]: field `name` of struct `CObj` is private --> $DIR/issue-25386.rs:26:43 | LL | println!("{}", check_ptr_exist!(item, name)); diff --git a/src/test/ui/issues/issue-2590.stderr b/src/test/ui/issues/issue-2590.stderr index 3517d92403..6aacd563af 100644 --- a/src/test/ui/issues/issue-2590.stderr +++ b/src/test/ui/issues/issue-2590.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `self.tokens` which is behind a shared referenc --> $DIR/issue-2590.rs:11:9 | LL | self.tokens - | ^^^^^^^^^^^ move occurs because `self.tokens` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^^^^^^^^^ move occurs because `self.tokens` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26472.rs b/src/test/ui/issues/issue-26472.rs index 4eb38d10a7..b100c59ad0 100644 --- a/src/test/ui/issues/issue-26472.rs +++ b/src/test/ui/issues/issue-26472.rs @@ -8,6 +8,6 @@ mod sub { fn main() { let s = sub::S::new(); - let v = s.len; //~ ERROR field `len` of struct `sub::S` is private - s.len = v; //~ ERROR field `len` of struct `sub::S` is private + let v = s.len; //~ ERROR field `len` of struct `S` is private + s.len = v; //~ ERROR field `len` of struct `S` is private } diff --git a/src/test/ui/issues/issue-26472.stderr b/src/test/ui/issues/issue-26472.stderr index f7df5b6232..8e95b2ff68 100644 --- a/src/test/ui/issues/issue-26472.stderr +++ b/src/test/ui/issues/issue-26472.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `len` of struct `sub::S` is private +error[E0616]: field `len` of struct `S` is private --> $DIR/issue-26472.rs:11:15 | LL | let v = s.len; @@ -9,7 +9,7 @@ help: a method `len` also exists, call it with parentheses LL | let v = s.len(); | ^^ -error[E0616]: field `len` of struct `sub::S` is private +error[E0616]: field `len` of struct `S` is private --> $DIR/issue-26472.rs:12:7 | LL | s.len = v; diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr index 5dbcc96e87..c4faecbdf2 100644 --- a/src/test/ui/issues/issue-27060-2.stderr +++ b/src/test/ui/issues/issue-27060-2.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/issue-27060-2.rs:3:11 | LL | pub struct Bad { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | data: T, | ^ doesn't have a size known at compile-time | diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr index de1810e99a..006389f753 100644 --- a/src/test/ui/issues/issue-27078.stderr +++ b/src/test/ui/issues/issue-27078.stderr @@ -7,8 +7,8 @@ LL | fn foo(self) -> &'static i32 { = help: unsized locals are gated as an unstable feature help: consider further restricting `Self` | -LL | fn foo(self) -> &'static i32 where Self: std::marker::Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo(self) -> &'static i32 where Self: Sized { + | ^^^^^^^^^^^^^^^^^ help: function arguments must have a statically known size, borrowed types always have a known size | LL | fn foo(&self) -> &'static i32 { diff --git a/src/test/ui/issues/issue-2718-a.rs b/src/test/ui/issues/issue-2718-a.rs index 188168bb94..6c49158454 100644 --- a/src/test/ui/issues/issue-2718-a.rs +++ b/src/test/ui/issues/issue-2718-a.rs @@ -6,7 +6,7 @@ mod pingpong { use SendPacket; pub type Ping = SendPacket; pub struct Pong(SendPacket); - //~^ ERROR recursive type `pingpong::Pong` has infinite size + //~^ ERROR recursive type `Pong` has infinite size } fn main() {} diff --git a/src/test/ui/issues/issue-2718-a.stderr b/src/test/ui/issues/issue-2718-a.stderr index d152ffde4e..5c6c99a1ff 100644 --- a/src/test/ui/issues/issue-2718-a.stderr +++ b/src/test/ui/issues/issue-2718-a.stderr @@ -1,4 +1,4 @@ -error[E0072]: recursive type `pingpong::Pong` has infinite size +error[E0072]: recursive type `Pong` has infinite size --> $DIR/issue-2718-a.rs:8:5 | LL | pub struct Pong(SendPacket); @@ -7,7 +7,7 @@ LL | pub struct Pong(SendPacket); | | recursive without indirection | recursive type has infinite size | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `pingpong::Pong` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Pong` representable | LL | pub struct Pong(Box>); | ^^^^ ^ diff --git a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr index 30cf0d66af..7895cefb4c 100644 --- a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr +++ b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | if { (|| { let bar = foo; bar.take() })(); false } => {}, | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/issues/issue-28098.stderr b/src/test/ui/issues/issue-28098.stderr index 8b724b9331..df552fc2d0 100644 --- a/src/test/ui/issues/issue-28098.stderr +++ b/src/test/ui/issues/issue-28098.stderr @@ -4,7 +4,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: required by `std::iter::Iterator::next` error[E0277]: `bool` is not an iterator @@ -13,8 +13,8 @@ error[E0277]: `bool` is not an iterator LL | for _ in false {} | ^^^^^ `bool` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `bool` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `bool` + = note: required by `into_iter` error[E0277]: `()` is not an iterator --> $DIR/issue-28098.rs:9:28 @@ -22,7 +22,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: required by `std::iter::Iterator::next` error[E0277]: `()` is not an iterator @@ -31,7 +31,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` error[E0277]: `()` is not an iterator --> $DIR/issue-28098.rs:18:28 @@ -39,7 +39,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: required by `std::iter::Iterator::next` error[E0277]: `()` is not an iterator @@ -48,7 +48,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: required by `std::iter::Iterator::next` error[E0277]: `bool` is not an iterator @@ -57,8 +57,8 @@ error[E0277]: `bool` is not an iterator LL | for _ in false {} | ^^^^^ `bool` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `bool` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `bool` + = note: required by `into_iter` error[E0277]: `()` is not an iterator --> $DIR/issue-28098.rs:18:13 @@ -66,7 +66,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` error: aborting due to 8 previous errors diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr index fc38f4b61f..e044352e95 100644 --- a/src/test/ui/issues/issue-2823.stderr +++ b/src/test/ui/issues/issue-2823.stderr @@ -12,12 +12,12 @@ LL | let _d = c.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here + | the method is available for `Arc` here + | the method is available for `Rc` here | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28344.stderr b/src/test/ui/issues/issue-28344.stderr index e34ac45e69..4955dea564 100644 --- a/src/test/ui/issues/issue-28344.stderr +++ b/src/test/ui/issues/issue-28344.stderr @@ -1,31 +1,31 @@ -error[E0191]: the value of the associated type `Output` (from trait `std::ops::BitXor`) must be specified +error[E0191]: the value of the associated type `Output` (from trait `BitXor`) must be specified --> $DIR/issue-28344.rs:4:17 | LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); | ^^^^^^ help: specify the associated type: `BitXor` -error[E0599]: no function or associated item named `bitor` found for trait object `dyn std::ops::BitXor<_>` in the current scope +error[E0599]: no function or associated item named `bitor` found for trait object `dyn BitXor<_>` in the current scope --> $DIR/issue-28344.rs:4:25 | LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); | ^^^^^ | | - | function or associated item not found in `dyn std::ops::BitXor<_>` + | function or associated item not found in `dyn BitXor<_>` | help: there is an associated function with a similar name: `bitxor` -error[E0191]: the value of the associated type `Output` (from trait `std::ops::BitXor`) must be specified +error[E0191]: the value of the associated type `Output` (from trait `BitXor`) must be specified --> $DIR/issue-28344.rs:8:13 | LL | let g = BitXor::bitor; | ^^^^^^ help: specify the associated type: `BitXor` -error[E0599]: no function or associated item named `bitor` found for trait object `dyn std::ops::BitXor<_>` in the current scope +error[E0599]: no function or associated item named `bitor` found for trait object `dyn BitXor<_>` in the current scope --> $DIR/issue-28344.rs:8:21 | LL | let g = BitXor::bitor; | ^^^^^ | | - | function or associated item not found in `dyn std::ops::BitXor<_>` + | function or associated item not found in `dyn BitXor<_>` | help: there is an associated function with a similar name: `bitxor` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-29723.stderr b/src/test/ui/issues/issue-29723.stderr index 04915ab5f9..e39ddfc81c 100644 --- a/src/test/ui/issues/issue-29723.stderr +++ b/src/test/ui/issues/issue-29723.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `s` --> $DIR/issue-29723.rs:10:13 | LL | let s = String::new(); - | - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `s` has type `String`, which does not implement the `Copy` trait LL | let _s = match 0 { LL | 0 if { drop(s); false } => String::from("oops"), | - value moved here diff --git a/src/test/ui/issues/issue-30355.stderr b/src/test/ui/issues/issue-30355.stderr index 98de768a5a..db7a5a7f6d 100644 --- a/src/test/ui/issues/issue-30355.stderr +++ b/src/test/ui/issues/issue-30355.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | &X(*Y) | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 23a1a27675..818e004ffc 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]> as std::iter::Iterator>::Item == &_` +error[E0271]: type mismatch resolving `, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item == &_` --> $DIR/issue-31173.rs:10:10 | LL | .cloned() @@ -7,25 +7,25 @@ LL | .cloned() = note: expected type `u8` found reference `&_` -error[E0599]: no method named `collect` found for struct `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` in the current scope +error[E0599]: no method named `collect` found for struct `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` in the current scope --> $DIR/issue-31173.rs:14:10 | LL | .collect(); - | ^^^^^^^ method not found in `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` + | ^^^^^^^ method not found in `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` | ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL | LL | pub struct Cloned { - | -------------------- doesn't satisfy `_: std::iter::Iterator` + | -------------------- doesn't satisfy `_: Iterator` ... LL | pub struct TakeWhile { - | -------------------------- doesn't satisfy `<_ as std::iter::Iterator>::Item = &_` + | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_` | = note: the method `collect` exists but the following trait bounds were not satisfied: - `, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]> as std::iter::Iterator>::Item = &_` - which is required by `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>: std::iter::Iterator` - `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>: std::iter::Iterator` - which is required by `&mut std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>: std::iter::Iterator` + `, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item = &_` + which is required by `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator` + `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator` + which is required by `&mut Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index af272633f2..cc12c15362 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -4,10 +4,10 @@ error[E0277]: `?` couldn't convert the error to `()` LL | fn a() -> Result { | --------------- expected `()` because of this LL | Err(5)?; - | ^ the trait `std::convert::From<{integer}>` is not implemented for `()` + | ^ the trait `From<{integer}>` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `std::convert::From::from` + = note: required by `from` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-32963.rs b/src/test/ui/issues/issue-32963.rs index 3e6cf446da..58055cd545 100644 --- a/src/test/ui/issues/issue-32963.rs +++ b/src/test/ui/issues/issue-32963.rs @@ -8,5 +8,5 @@ fn main() { size_of_copy::(); //~^ ERROR only auto traits can be used as additional traits in a trait object //~| ERROR only auto traits can be used as additional traits in a trait object - //~| ERROR the trait bound `dyn Misc: std::marker::Copy` is not satisfied + //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied } diff --git a/src/test/ui/issues/issue-32963.stderr b/src/test/ui/issues/issue-32963.stderr index f9628f2c2e..76c62c1c6d 100644 --- a/src/test/ui/issues/issue-32963.stderr +++ b/src/test/ui/issues/issue-32963.stderr @@ -6,7 +6,7 @@ LL | size_of_copy::(); | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Misc + std::marker::Copy {}` + = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -17,17 +17,17 @@ LL | size_of_copy::(); | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Misc + std::marker::Copy {}` + = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0277]: the trait bound `dyn Misc: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied --> $DIR/issue-32963.rs:8:5 | LL | fn size_of_copy() -> usize { mem::size_of::() } | ---- required by this bound in `size_of_copy` ... LL | size_of_copy::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `dyn Misc` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-33293.rs b/src/test/ui/issues/issue-33293.rs index d367037428..a6ef007d51 100644 --- a/src/test/ui/issues/issue-33293.rs +++ b/src/test/ui/issues/issue-33293.rs @@ -1,6 +1,6 @@ fn main() { match 0 { aaa::bbb(_) => () - //~^ ERROR failed to resolve: use of undeclared type or module `aaa` + //~^ ERROR failed to resolve: use of undeclared crate or module `aaa` }; } diff --git a/src/test/ui/issues/issue-33293.stderr b/src/test/ui/issues/issue-33293.stderr index 6b7333f22f..c8450f4004 100644 --- a/src/test/ui/issues/issue-33293.stderr +++ b/src/test/ui/issues/issue-33293.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `aaa` +error[E0433]: failed to resolve: use of undeclared crate or module `aaa` --> $DIR/issue-33293.rs:3:9 | LL | aaa::bbb(_) => () - | ^^^ use of undeclared type or module `aaa` + | ^^^ use of undeclared crate or module `aaa` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3344.stderr b/src/test/ui/issues/issue-3344.stderr index 723e03d452..11d5999672 100644 --- a/src/test/ui/issues/issue-3344.stderr +++ b/src/test/ui/issues/issue-3344.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `partial_cmp` LL | impl PartialOrd for Thing { | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `partial_cmp` in implementation | - = help: implement the missing item: `fn partial_cmp(&self, _: &Rhs) -> std::option::Option { todo!() }` + = help: implement the missing item: `fn partial_cmp(&self, _: &Rhs) -> Option { todo!() }` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index 20335d2cdd..aeab923d2d 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` +error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` --> $DIR/issue-33941.rs:4:36 | LL | for _ in HashMap::new().iter().cloned() {} @@ -7,7 +7,7 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: expected tuple `(&_, &_)` found reference `&_` -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` +error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` --> $DIR/issue-33941.rs:4:14 | LL | for _ in HashMap::new().iter().cloned() {} @@ -15,9 +15,9 @@ LL | for _ in HashMap::new().iter().cloned() {} | = note: expected tuple `(&_, &_)` found reference `&_` - = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned>` + = note: required because of the requirements on the impl of `Iterator` for `Cloned>` -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` +error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` --> $DIR/issue-33941.rs:4:14 | LL | for _ in HashMap::new().iter().cloned() {} @@ -25,7 +25,7 @@ LL | for _ in HashMap::new().iter().cloned() {} | = note: expected tuple `(&_, &_)` found reference `&_` - = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned>` + = note: required because of the requirements on the impl of `Iterator` for `Cloned>` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-34229.stderr b/src/test/ui/issues/issue-34229.stderr index cd9be6ab72..d25189e783 100644 --- a/src/test/ui/issues/issue-34229.stderr +++ b/src/test/ui/issues/issue-34229.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs index 97905e2f8f..bf2d091a01 100644 --- a/src/test/ui/issues/issue-34334.rs +++ b/src/test/ui/issues/issue-34334.rs @@ -2,5 +2,5 @@ fn main () { let sr: Vec<(u32, _, _) = vec![]; //~^ ERROR expected one of `,` or `>`, found `=` let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); - //~^ ERROR a value of type `std::vec::Vec<(u32, _, _)>` cannot be built + //~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built } diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index 364f8264db..c10a414430 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -6,13 +6,13 @@ LL | let sr: Vec<(u32, _, _) = vec![]; | | | while parsing the type for `sr` -error[E0277]: a value of type `std::vec::Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()` +error[E0277]: a value of type `Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()` --> $DIR/issue-34334.rs:4:87 | LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); - | ^^^^^^^ value of type `std::vec::Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator` + | ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator<()>` is not implemented for `std::vec::Vec<(u32, _, _)>` + = help: the trait `FromIterator<()>` is not implemented for `Vec<(u32, _, _)>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-34784.rs b/src/test/ui/issues/issue-34784.rs index d3206e9943..98d943470a 100644 --- a/src/test/ui/issues/issue-34784.rs +++ b/src/test/ui/issues/issue-34784.rs @@ -1,4 +1,6 @@ // run-pass + +#![warn(pointer_structural_match)] #![allow(dead_code)] const C: *const u8 = &0; diff --git a/src/test/ui/issues/issue-35677.stderr b/src/test/ui/issues/issue-35677.stderr index 978221e502..afdc5d68ca 100644 --- a/src/test/ui/issues/issue-35677.stderr +++ b/src/test/ui/issues/issue-35677.stderr @@ -1,12 +1,12 @@ -error[E0599]: no method named `is_subset` found for reference `&std::collections::HashSet` in the current scope +error[E0599]: no method named `is_subset` found for reference `&HashSet` in the current scope --> $DIR/issue-35677.rs:4:10 | LL | this.is_subset(other) - | ^^^^^^^^^ method not found in `&std::collections::HashSet` + | ^^^^^^^^^ method not found in `&HashSet` | = note: the method `is_subset` exists but the following trait bounds were not satisfied: - `T: std::cmp::Eq` - `T: std::hash::Hash` + `T: Eq` + `T: Hash` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35869.stderr b/src/test/ui/issues/issue-35869.stderr index 66e89998e1..f80561bf6b 100644 --- a/src/test/ui/issues/issue-35869.stderr +++ b/src/test/ui/issues/issue-35869.stderr @@ -19,8 +19,8 @@ LL | fn bar(_: Option); LL | fn bar(_: Option) {} | ^^^^^^^^^^^ expected `u8`, found `u16` | - = note: expected fn pointer `fn(std::option::Option)` - found fn pointer `fn(std::option::Option)` + = note: expected fn pointer `fn(Option)` + found fn pointer `fn(Option)` error[E0053]: method `baz` has an incompatible type for trait --> $DIR/issue-35869.rs:15:15 diff --git a/src/test/ui/issues/issue-35988.stderr b/src/test/ui/issues/issue-35988.stderr index 0f0b80a9ff..2e03acc112 100644 --- a/src/test/ui/issues/issue-35988.stderr +++ b/src/test/ui/issues/issue-35988.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `[std::boxed::Box]` cannot be known at compilation time +error[E0277]: the size for values of type `[Box]` cannot be known at compilation time --> $DIR/issue-35988.rs:2:7 | LL | V([Box]), | ^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[std::boxed::Box]` + = help: the trait `Sized` is not implemented for `[Box]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size diff --git a/src/test/ui/issues/issue-3601.stderr b/src/test/ui/issues/issue-3601.stderr index 6b2a5d7624..adad480f92 100644 --- a/src/test/ui/issues/issue-3601.stderr +++ b/src/test/ui/issues/issue-3601.stderr @@ -5,7 +5,7 @@ LL | box NodeKind::Element(ed) => match ed.kind { | ^^^^^^^ pattern `Box(_)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `std::boxed::Box` + = note: the matched value is of type `Box` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/issues/issue-36163.stderr index 7c2da9dce6..113f86cf0f 100644 --- a/src/test/ui/issues/issue-36163.stderr +++ b/src/test/ui/issues/issue-36163.stderr @@ -1,37 +1,37 @@ -error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ | -note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Foo::B::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ -note: ...which requires const-evaluating `Foo::B::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ = note: ...which requires normalizing `A`... -note: ...which requires const-evaluating + checking `A`... +note: ...which requires simplifying constant for the type system `A`... --> $DIR/issue-36163.rs:1:1 | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `A`... +note: ...which requires simplifying constant for the type system `A`... --> $DIR/issue-36163.rs:1:1 | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `A`... +note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-36163.rs:1:1 | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `A`... - = note: ...which again requires const-evaluating + checking `Foo::B::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-36163.rs:1:1 | diff --git a/src/test/ui/issues/issue-36299.stderr b/src/test/ui/issues/issue-36299.stderr index a9516b8e5e..8e29a925d8 100644 --- a/src/test/ui/issues/issue-36299.stderr +++ b/src/test/ui/issues/issue-36299.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `'a` is never used LL | struct Foo<'a, A> {} | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `A` is never used --> $DIR/issue-36299.rs:1:16 @@ -12,7 +12,7 @@ error[E0392]: parameter `A` is never used LL | struct Foo<'a, A> {} | ^ unused parameter | - = help: consider removing `A`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-36617.stderr b/src/test/ui/issues/issue-36617.stderr index 98b41b07ea..586dcf2cea 100644 --- a/src/test/ui/issues/issue-36617.stderr +++ b/src/test/ui/issues/issue-36617.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-36617.rs:1:1 | LL | #![derive(Copy)] @@ -22,3 +22,4 @@ LL | #![derive(Copy)] error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-36638.stderr b/src/test/ui/issues/issue-36638.stderr index fe48ea158d..e5d6f8ec7a 100644 --- a/src/test/ui/issues/issue-36638.stderr +++ b/src/test/ui/issues/issue-36638.stderr @@ -16,7 +16,7 @@ error[E0392]: parameter `Self` is never used LL | struct Foo(Self); | ^^^^ unused parameter | - = help: consider removing `Self`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `Self`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-3680.rs b/src/test/ui/issues/issue-3680.rs index 64050c72f2..8912e7a18a 100644 --- a/src/test/ui/issues/issue-3680.rs +++ b/src/test/ui/issues/issue-3680.rs @@ -2,8 +2,8 @@ fn main() { match None { Err(_) => () //~^ ERROR mismatched types - //~| expected enum `std::option::Option<_>` + //~| expected enum `Option<_>` //~| found enum `std::result::Result<_, _>` - //~| expected enum `std::option::Option`, found enum `std::result::Result` + //~| expected enum `Option`, found enum `std::result::Result` } } diff --git a/src/test/ui/issues/issue-3680.stderr b/src/test/ui/issues/issue-3680.stderr index 713e4b5ccd..479942b8e2 100644 --- a/src/test/ui/issues/issue-3680.stderr +++ b/src/test/ui/issues/issue-3680.stderr @@ -2,11 +2,11 @@ error[E0308]: mismatched types --> $DIR/issue-3680.rs:3:9 | LL | match None { - | ---- this expression has type `std::option::Option<_>` + | ---- this expression has type `Option<_>` LL | Err(_) => () - | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option<_>` + = note: expected enum `Option<_>` found enum `std::result::Result<_, _>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37026.stderr b/src/test/ui/issues/issue-37026.stderr index f0285730c5..48a4a5bcad 100644 --- a/src/test/ui/issues/issue-37026.stderr +++ b/src/test/ui/issues/issue-37026.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let empty_struct::XEmpty2 = (); | ^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()` | | - | expected `()`, found struct `empty_struct::XEmpty2` + | expected `()`, found struct `XEmpty2` error[E0308]: mismatched types --> $DIR/issue-37026.rs:7:9 @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | let empty_struct::XEmpty6(..) = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()` | | - | expected `()`, found struct `empty_struct::XEmpty6` + | expected `()`, found struct `XEmpty6` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs index d3d5863ddb..50d1f166c9 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test: ".nll/" -> "/" trait Mirror { type Image; diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index a94f190d6b..93aeb89469 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(.....), ...), ...) as Foo>::recurse` - --> $DIR/issue-37311.rs:16:9 + --> $DIR/issue-37311.rs:17:9 | LL | (self, self).recurse(); | ^^^^^^^^^^^^^^^^^^^^^^ | note: `::recurse` defined here - --> $DIR/issue-37311.rs:15:5 + --> $DIR/issue-37311.rs:16:5 | LL | fn recurse(&self) { | ^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr index 5d008cf24d..895479986f 100644 --- a/src/test/ui/issues/issue-37534.stderr +++ b/src/test/ui/issues/issue-37534.stderr @@ -21,7 +21,7 @@ error[E0392]: parameter `T` is never used LL | struct Foo { } | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/issues/issue-37550.rs b/src/test/ui/issues/issue-37550.rs index 505c030b96..35b63bddca 100644 --- a/src/test/ui/issues/issue-37550.rs +++ b/src/test/ui/issues/issue-37550.rs @@ -1,6 +1,6 @@ const fn x() { let t = true; - let x = || t; //~ ERROR function pointers in const fn are unstable + let x = || t; //~ ERROR function pointer } fn main() {} diff --git a/src/test/ui/issues/issue-37550.stderr b/src/test/ui/issues/issue-37550.stderr index 35da625801..54b60df70f 100644 --- a/src/test/ui/issues/issue-37550.stderr +++ b/src/test/ui/issues/issue-37550.stderr @@ -1,12 +1,12 @@ -error[E0723]: function pointers in const fn are unstable +error[E0658]: function pointers cannot appear in constant functions --> $DIR/issue-37550.rs:3:9 | LL | let x = || t; | ^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-3763.rs b/src/test/ui/issues/issue-3763.rs index 451321c550..25ad6b319f 100644 --- a/src/test/ui/issues/issue-3763.rs +++ b/src/test/ui/issues/issue-3763.rs @@ -16,14 +16,14 @@ mod my_mod { fn main() { let my_struct = my_mod::MyStruct(); let _woohoo = (&my_struct).priv_field; - //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private + //~^ ERROR field `priv_field` of struct `MyStruct` is private let _woohoo = (Box::new(my_struct)).priv_field; - //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private + //~^ ERROR field `priv_field` of struct `MyStruct` is private (&my_struct).happyfun(); //~ ERROR associated function `happyfun` is private (Box::new(my_struct)).happyfun(); //~ ERROR associated function `happyfun` is private let nope = my_struct.priv_field; - //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private + //~^ ERROR field `priv_field` of struct `MyStruct` is private } diff --git a/src/test/ui/issues/issue-3763.stderr b/src/test/ui/issues/issue-3763.stderr index b63967bb9d..7f54c9f8a6 100644 --- a/src/test/ui/issues/issue-3763.stderr +++ b/src/test/ui/issues/issue-3763.stderr @@ -1,10 +1,10 @@ -error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private +error[E0616]: field `priv_field` of struct `MyStruct` is private --> $DIR/issue-3763.rs:18:32 | LL | let _woohoo = (&my_struct).priv_field; | ^^^^^^^^^^ private field -error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private +error[E0616]: field `priv_field` of struct `MyStruct` is private --> $DIR/issue-3763.rs:21:41 | LL | let _woohoo = (Box::new(my_struct)).priv_field; @@ -22,7 +22,7 @@ error[E0624]: associated function `happyfun` is private LL | (Box::new(my_struct)).happyfun(); | ^^^^^^^^ private associated function -error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private +error[E0616]: field `priv_field` of struct `MyStruct` is private --> $DIR/issue-3763.rs:27:26 | LL | let nope = my_struct.priv_field; diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr index 5baa245b3c..d741d42685 100644 --- a/src/test/ui/issues/issue-37884.stderr +++ b/src/test/ui/issues/issue-37884.stderr @@ -9,8 +9,8 @@ LL | | Some(&mut self.0) LL | | } | |_____^ lifetime mismatch | - = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> std::option::Option<_>` - found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> std::option::Option<_>` + = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>` + found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>` note: the anonymous lifetime #1 defined on the method body at 6:5... --> $DIR/issue-37884.rs:6:5 | diff --git a/src/test/ui/issues/issue-38604.stderr b/src/test/ui/issues/issue-38604.stderr index 2bba50e1f4..39a62b81c6 100644 --- a/src/test/ui/issues/issue-38604.stderr +++ b/src/test/ui/issues/issue-38604.stderr @@ -20,8 +20,8 @@ LL | trait Foo where u32: Q { LL | Box::new(()); | ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box<()>` - = note: required by cast to type `std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box<()>` + = note: required by cast to type `Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-38954.stderr b/src/test/ui/issues/issue-38954.stderr index e96bbe1a99..bc40fd07c5 100644 --- a/src/test/ui/issues/issue-38954.stderr +++ b/src/test/ui/issues/issue-38954.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | fn _test(ref _p: str) {} | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr index 2f6e676538..dbb334e7b9 100644 --- a/src/test/ui/issues/issue-39175.stderr +++ b/src/test/ui/issues/issue-39175.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `exec` found for mutable reference `&mut std::process::Command` in the current scope +error[E0599]: no method named `exec` found for mutable reference `&mut Command` in the current scope --> $DIR/issue-39175.rs:15:39 | LL | Command::new("echo").arg("hello").exec(); - | ^^^^ method not found in `&mut std::process::Command` + | ^^^^ method not found in `&mut Command` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr index 3eb3482ac9..00543c5fff 100644 --- a/src/test/ui/issues/issue-40000.stderr +++ b/src/test/ui/issues/issue-40000.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | foo(bar); | ^^^ one type is more general than the other | - = note: expected trait object `dyn for<'r> std::ops::Fn(&'r i32)` - found trait object `dyn std::ops::Fn(&i32)` + = note: expected trait object `dyn for<'r> Fn(&'r i32)` + found trait object `dyn Fn(&i32)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr index 8a9d9aab81..0a5a6b80e9 100644 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr +++ b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr @@ -1,10 +1,10 @@ -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/issue-40402-1.rs:9:13 | LL | let e = f.v[0]; | ^^^^^^ | | - | move occurs because value has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because value has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&f.v[0]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr index d0a4097de6..b6049f967f 100644 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr +++ b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr @@ -1,4 +1,4 @@ -error[E0507]: cannot move out of index of `std::vec::Vec<(std::string::String, std::string::String)>` +error[E0507]: cannot move out of index of `Vec<(String, String)>` --> $DIR/issue-40402-2.rs:5:18 | LL | let (a, b) = x[0]; diff --git a/src/test/ui/issues/issue-40749.rs b/src/test/ui/issues/issue-40749.rs index 87ff5a650f..0a847853b1 100644 --- a/src/test/ui/issues/issue-40749.rs +++ b/src/test/ui/issues/issue-40749.rs @@ -2,5 +2,5 @@ fn main() { [0; ..10]; //~^ ERROR mismatched types //~| expected type `usize` - //~| found struct `std::ops::RangeTo<{integer}>` + //~| found struct `RangeTo<{integer}>` } diff --git a/src/test/ui/issues/issue-40749.stderr b/src/test/ui/issues/issue-40749.stderr index 4170a96bdd..fa239f744f 100644 --- a/src/test/ui/issues/issue-40749.stderr +++ b/src/test/ui/issues/issue-40749.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-40749.rs:2:9 | LL | [0; ..10]; - | ^^^^ expected `usize`, found struct `std::ops::RangeTo` + | ^^^^ expected `usize`, found struct `RangeTo` | = note: expected type `usize` - found struct `std::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40827.stderr b/src/test/ui/issues/issue-40827.stderr index a10abb8902..5ea795d139 100644 --- a/src/test/ui/issues/issue-40827.stderr +++ b/src/test/ui/issues/issue-40827.stderr @@ -1,29 +1,29 @@ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/issue-40827.rs:14:5 | LL | fn f(_: T) {} | ---- required by this bound in `f` ... LL | f(Foo(Arc::new(Bar::B(None)))); - | ^ `std::rc::Rc` cannot be sent between threads safely + | ^ `Rc` cannot be sent between threads safely | - = help: within `Bar`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` + = help: within `Bar`, the trait `Send` is not implemented for `Rc` = note: required because it appears within the type `Bar` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc` + = note: required because of the requirements on the impl of `Send` for `Arc` = note: required because it appears within the type `Foo` -error[E0277]: `std::rc::Rc` cannot be shared between threads safely +error[E0277]: `Rc` cannot be shared between threads safely --> $DIR/issue-40827.rs:14:5 | LL | fn f(_: T) {} | ---- required by this bound in `f` ... LL | f(Foo(Arc::new(Bar::B(None)))); - | ^ `std::rc::Rc` cannot be shared between threads safely + | ^ `Rc` cannot be shared between threads safely | - = help: within `Bar`, the trait `std::marker::Sync` is not implemented for `std::rc::Rc` + = help: within `Bar`, the trait `Sync` is not implemented for `Rc` = note: required because it appears within the type `Bar` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc` + = note: required because of the requirements on the impl of `Send` for `Arc` = note: required because it appears within the type `Foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-41229-ref-str.stderr b/src/test/ui/issues/issue-41229-ref-str.stderr index 35aa1acdc1..c5c848e63e 100644 --- a/src/test/ui/issues/issue-41229-ref-str.stderr +++ b/src/test/ui/issues/issue-41229-ref-str.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | pub fn example(ref s: str) {} | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/issues/issue-41726.stderr b/src/test/ui/issues/issue-41726.stderr index aa7f23511d..b00a420bc3 100644 --- a/src/test/ui/issues/issue-41726.stderr +++ b/src/test/ui/issues/issue-41726.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow data in an index of `std::collections::HashMap>` as mutable +error[E0596]: cannot borrow data in an index of `HashMap>` as mutable --> $DIR/issue-41726.rs:5:9 | LL | things[src.as_str()].sort(); | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap>` + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr index d082e0a6b5..f1342181b3 100644 --- a/src/test/ui/issues/issue-41974.stderr +++ b/src/test/ui/issues/issue-41974.stderr @@ -5,7 +5,7 @@ LL | impl Drop for T where T: A { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `alloc`: - - impl std::ops::Drop for std::boxed::Box + - impl Drop for Box where T: ?Sized; = note: downstream crates may implement trait `A` for type `std::boxed::Box<_>` diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index fbe87aa2db..b55a724c0d 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -1,27 +1,27 @@ -error[E0277]: the size for values of type `::Target` cannot be known at compilation time +error[E0277]: the size for values of type `::Target` cannot be known at compilation time --> $DIR/issue-42312.rs:4:12 | LL | fn baz(_: Self::Target) where Self: Deref {} | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `::Target` + = help: the trait `Sized` is not implemented for `::Target` = help: unsized locals are gated as an unstable feature help: consider further restricting the associated type | -LL | fn baz(_: Self::Target) where Self: Deref, ::Target: std::marker::Sized {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn baz(_: Self::Target) where Self: Deref, ::Target: Sized {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: function arguments must have a statically known size, borrowed types always have a known size | LL | fn baz(_: &Self::Target) where Self: Deref {} | ^ -error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn ToString + 'static)` cannot be known at compilation time --> $DIR/issue-42312.rs:8:10 | LL | pub fn f(_: dyn ToString) {} | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)` + = help: the trait `Sized` is not implemented for `(dyn ToString + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/issues/issue-42796.stderr b/src/test/ui/issues/issue-42796.stderr index d9dfbc999f..61cf3f25d0 100644 --- a/src/test/ui/issues/issue-42796.stderr +++ b/src/test/ui/issues/issue-42796.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `s` --> $DIR/issue-42796.rs:18:20 | LL | let s = "Hello!".to_owned(); - | - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `s` has type `String`, which does not implement the `Copy` trait LL | let mut s_copy = s; | - value moved here ... diff --git a/src/test/ui/issues/issue-42880.stderr b/src/test/ui/issues/issue-42880.stderr index 82cdc20df2..bec14429d3 100644 --- a/src/test/ui/issues/issue-42880.stderr +++ b/src/test/ui/issues/issue-42880.stderr @@ -1,8 +1,8 @@ -error[E0599]: no associated item named `String` found for struct `std::string::String` in the current scope +error[E0599]: no associated item named `String` found for struct `String` in the current scope --> $DIR/issue-42880.rs:4:22 | LL | let f = |&Value::String(_)| (); - | ^^^^^^ associated item not found in `std::string::String` + | ^^^^^^ associated item not found in `String` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43023.stderr b/src/test/ui/issues/issue-43023.stderr index 206a51645f..f5f51cdcd4 100644 --- a/src/test/ui/issues/issue-43023.stderr +++ b/src/test/ui/issues/issue-43023.stderr @@ -1,16 +1,16 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:4:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:11:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:16:5 | LL | #[derive(Debug)] @@ -18,3 +18,4 @@ LL | #[derive(Debug)] error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-43420-no-over-suggest.stderr b/src/test/ui/issues/issue-43420-no-over-suggest.stderr index 27aebc548e..77d52f6eca 100644 --- a/src/test/ui/issues/issue-43420-no-over-suggest.stderr +++ b/src/test/ui/issues/issue-43420-no-over-suggest.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-43420-no-over-suggest.rs:8:9 | LL | foo(&a); - | ^^ expected slice `[u16]`, found struct `std::vec::Vec` + | ^^ expected slice `[u16]`, found struct `Vec` | = note: expected reference `&[u16]` - found reference `&std::vec::Vec` + found reference `&Vec` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43784-associated-type.rs b/src/test/ui/issues/issue-43784-associated-type.rs index 92083d88f1..78815d8d3f 100644 --- a/src/test/ui/issues/issue-43784-associated-type.rs +++ b/src/test/ui/issues/issue-43784-associated-type.rs @@ -11,7 +11,7 @@ impl Partial for T::Assoc where } impl Complete for T { - type Assoc = T; //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied + type Assoc = T; //~ ERROR the trait bound `T: Copy` is not satisfied } fn main() {} diff --git a/src/test/ui/issues/issue-43784-associated-type.stderr b/src/test/ui/issues/issue-43784-associated-type.stderr index d8e9110fbb..039852ad16 100644 --- a/src/test/ui/issues/issue-43784-associated-type.stderr +++ b/src/test/ui/issues/issue-43784-associated-type.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-43784-associated-type.rs:14:18 | LL | type Assoc = T; - | ^ the trait `std::marker::Copy` is not implemented for `T` + | ^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl Complete for T { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Complete for T { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43784-supertrait.rs b/src/test/ui/issues/issue-43784-supertrait.rs index 3c03433a26..55c26ccd2d 100644 --- a/src/test/ui/issues/issue-43784-supertrait.rs +++ b/src/test/ui/issues/issue-43784-supertrait.rs @@ -5,6 +5,6 @@ pub trait Complete: Partial { } impl Partial for T where T: Complete {} -impl Complete for T {} //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied +impl Complete for T {} //~ ERROR the trait bound `T: Copy` is not satisfied fn main() {} diff --git a/src/test/ui/issues/issue-43784-supertrait.stderr b/src/test/ui/issues/issue-43784-supertrait.stderr index 2fb0583ee7..d92e4fa9e4 100644 --- a/src/test/ui/issues/issue-43784-supertrait.stderr +++ b/src/test/ui/issues/issue-43784-supertrait.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-43784-supertrait.rs:8:9 | LL | impl Complete for T {} - | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl Complete for T {} - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Complete for T {} + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-44333.rs b/src/test/ui/issues/issue-44333.rs index fffef97504..96e8795e52 100644 --- a/src/test/ui/issues/issue-44333.rs +++ b/src/test/ui/issues/issue-44333.rs @@ -1,4 +1,7 @@ // run-pass + +#![warn(pointer_structural_match)] + type Func = fn(usize, usize) -> usize; fn foo(a: usize, b: usize) -> usize { a + b } @@ -13,8 +16,10 @@ const BAR: Func = bar; fn main() { match test(std::env::consts::ARCH.len()) { - FOO => println!("foo"), - BAR => println!("bar"), + FOO => println!("foo"), //~ WARN pointers in patterns behave unpredictably + //~^ WARN will become a hard error + BAR => println!("bar"), //~ WARN pointers in patterns behave unpredictably + //~^ WARN will become a hard error _ => unreachable!(), } } diff --git a/src/test/ui/issues/issue-44333.stderr b/src/test/ui/issues/issue-44333.stderr new file mode 100644 index 0000000000..8302b09e53 --- /dev/null +++ b/src/test/ui/issues/issue-44333.stderr @@ -0,0 +1,25 @@ +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:19:9 + | +LL | FOO => println!("foo"), + | ^^^ + | +note: the lint level is defined here + --> $DIR/issue-44333.rs:3:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 + +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:21:9 + | +LL | BAR => println!("bar"), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 + +warning: 2 warnings emitted + diff --git a/src/test/ui/issues/issue-46112.stderr b/src/test/ui/issues/issue-46112.stderr index a861c38b00..ec05fbe580 100644 --- a/src/test/ui/issues/issue-46112.stderr +++ b/src/test/ui/issues/issue-46112.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | fn main() { test(Ok(())); } | ^^ | | - | expected enum `std::option::Option`, found `()` + | expected enum `Option`, found `()` | help: try using a variant of the expected enum: `Some(())` | - = note: expected enum `std::option::Option<()>` + = note: expected enum `Option<()>` found unit type `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-46553.rs b/src/test/ui/issues/issue-46553.rs index e21a532eff..0a1e835672 100644 --- a/src/test/ui/issues/issue-46553.rs +++ b/src/test/ui/issues/issue-46553.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] #![deny(const_err)] pub struct Data { diff --git a/src/test/ui/issues/issue-46771.rs b/src/test/ui/issues/issue-46771.rs index 2b5241e5ff..22be8d6af8 100644 --- a/src/test/ui/issues/issue-46771.rs +++ b/src/test/ui/issues/issue-46771.rs @@ -1,4 +1,4 @@ fn main() { struct Foo; - (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `main::Foo` + (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `Foo` } diff --git a/src/test/ui/issues/issue-46771.stderr b/src/test/ui/issues/issue-46771.stderr index 76c86d7aa9..a37b564895 100644 --- a/src/test/ui/issues/issue-46771.stderr +++ b/src/test/ui/issues/issue-46771.stderr @@ -1,8 +1,8 @@ -error[E0618]: expected function, found `main::Foo` +error[E0618]: expected function, found `Foo` --> $DIR/issue-46771.rs:3:23 | LL | struct Foo; - | ----------- `main::Foo` defined here + | ----------- `Foo` defined here LL | (1 .. 2).find(|_| Foo(0) == 0); | ^^^--- | | diff --git a/src/test/ui/issues/issue-47646.stderr b/src/test/ui/issues/issue-47646.stderr index c0b8763684..b46c277d04 100644 --- a/src/test/ui/issues/issue-47646.stderr +++ b/src/test/ui/issues/issue-47646.stderr @@ -11,7 +11,7 @@ LL | println!("{:?}", heap); | ^^^^ immutable borrow occurs here ... LL | }; - | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(std::option::Option>, ())` + | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option>, ())` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-47725.rs b/src/test/ui/issues/issue-47725.rs new file mode 100644 index 0000000000..21108da500 --- /dev/null +++ b/src/test/ui/issues/issue-47725.rs @@ -0,0 +1,29 @@ +// ignore-tidy-linelength +#![warn(unused_attributes)] //~ NOTE lint level is defined here + +#[link_name = "foo"] +//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +struct Foo; //~ NOTE not a foreign function or static + +#[link_name = "foobar"] +//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~| HELP try `#[link(name = "foobar")]` instead +extern "C" { + fn foo() -> u32; +} +//~^^^ NOTE not a foreign function or static + +#[link_name] +//~^ ERROR malformed `link_name` attribute input +//~| HELP must be of the form +//~| WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~| HELP try `#[link(name = "...")]` instead +extern "C" { + fn bar() -> u32; +} +//~^^^ NOTE not a foreign function or static + +fn main() {} diff --git a/src/test/ui/issues/issue-47725.stderr b/src/test/ui/issues/issue-47725.stderr new file mode 100644 index 0000000000..b1e8d3292e --- /dev/null +++ b/src/test/ui/issues/issue-47725.stderr @@ -0,0 +1,60 @@ +error: malformed `link_name` attribute input + --> $DIR/issue-47725.rs:18:1 + | +LL | #[link_name] + | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:4:1 + | +LL | #[link_name = "foo"] + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | struct Foo; + | ----------- not a foreign function or static + | +note: the lint level is defined here + --> $DIR/issue-47725.rs:2:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:9:1 + | +LL | #[link_name = "foobar"] + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / extern "C" { +LL | | fn foo() -> u32; +LL | | } + | |_- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +help: try `#[link(name = "foobar")]` instead + --> $DIR/issue-47725.rs:9:1 + | +LL | #[link_name = "foobar"] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:18:1 + | +LL | #[link_name] + | ^^^^^^^^^^^^ +... +LL | / extern "C" { +LL | | fn bar() -> u32; +LL | | } + | |_- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +help: try `#[link(name = "...")]` instead + --> $DIR/issue-47725.rs:18:1 + | +LL | #[link_name] + | ^^^^^^^^^^^^ + +error: aborting due to previous error; 3 warnings emitted + diff --git a/src/test/ui/issues/issue-4972.stderr b/src/test/ui/issues/issue-4972.stderr index b1947e2a9d..40db50278c 100644 --- a/src/test/ui/issues/issue-4972.stderr +++ b/src/test/ui/issues/issue-4972.stderr @@ -1,8 +1,8 @@ -error[E0033]: type `std::boxed::Box<(dyn MyTrait + 'static)>` cannot be dereferenced +error[E0033]: type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced --> $DIR/issue-4972.rs:14:25 | LL | TraitWrapper::A(box ref map) => map, - | ^^^^^^^^^^^ type `std::boxed::Box<(dyn MyTrait + 'static)>` cannot be dereferenced + | ^^^^^^^^^^^ type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced error: aborting due to previous error diff --git a/src/test/ui/issues/issue-49934-errors.stderr b/src/test/ui/issues/issue-49934-errors.stderr index 8778d88d0e..3befb38a20 100644 --- a/src/test/ui/issues/issue-49934-errors.stderr +++ b/src/test/ui/issues/issue-49934-errors.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-49934-errors.rs:1:8 | LL | fn foo<#[derive(Debug)] T>() { @@ -10,7 +10,7 @@ error: expected an inert attribute, found a derive macro LL | fn foo<#[derive(Debug)] T>() { | ^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-49934-errors.rs:5:9 | LL | #[derive(Debug)] @@ -24,3 +24,4 @@ LL | #[derive(Debug)] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs index 5b6b8f8de1..153ca0843d 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs @@ -1,4 +1,4 @@ fn main() { let _result = &Some(42).as_deref(); -//~^ ERROR no method named `as_deref` found for enum `std::option::Option<{integer}>` +//~^ ERROR no method named `as_deref` found for enum `Option<{integer}>` } diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr index b97131a199..a8cd98b610 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr @@ -1,12 +1,12 @@ -error[E0599]: no method named `as_deref` found for enum `std::option::Option<{integer}>` in the current scope +error[E0599]: no method named `as_deref` found for enum `Option<{integer}>` in the current scope --> $DIR/option-as_deref.rs:2:29 | LL | let _result = &Some(42).as_deref(); | ^^^^^^^^ help: there is an associated function with a similar name: `as_ref` | = note: the method `as_deref` exists but the following trait bounds were not satisfied: - `{integer}: std::ops::Deref` - `<{integer} as std::ops::Deref>::Target = _` + `{integer}: Deref` + `<{integer} as Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs index c5fe6ea82c..11d5378fe3 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs @@ -1,4 +1,4 @@ fn main() { let _result = &mut Some(42).as_deref_mut(); -//~^ ERROR no method named `as_deref_mut` found for enum `std::option::Option<{integer}>` +//~^ ERROR no method named `as_deref_mut` found for enum `Option<{integer}>` } diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr index f2133c8c84..08399fcea7 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr @@ -1,12 +1,12 @@ -error[E0599]: no method named `as_deref_mut` found for enum `std::option::Option<{integer}>` in the current scope +error[E0599]: no method named `as_deref_mut` found for enum `Option<{integer}>` in the current scope --> $DIR/option-as_deref_mut.rs:2:33 | LL | let _result = &mut Some(42).as_deref_mut(); - | ^^^^^^^^^^^^ method not found in `std::option::Option<{integer}>` + | ^^^^^^^^^^^^ method not found in `Option<{integer}>` | = note: the method `as_deref_mut` exists but the following trait bounds were not satisfied: - `{integer}: std::ops::DerefMut` - `<{integer} as std::ops::Deref>::Target = _` + `{integer}: DerefMut` + `<{integer} as Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr index 96524c3095..933e8a0c44 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr @@ -5,8 +5,8 @@ LL | let _result = &Ok(42).as_deref(); | ^^^^^^^^ help: there is an associated function with a similar name: `as_ref` | = note: the method `as_deref` exists but the following trait bounds were not satisfied: - `{integer}: std::ops::Deref` - `<{integer} as std::ops::Deref>::Target = _` + `{integer}: Deref` + `<{integer} as Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr index 73266bc7f6..69d85126f1 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr @@ -5,8 +5,8 @@ LL | let _result = &mut Ok(42).as_deref_mut(); | ^^^^^^^^^^^^ method not found in `std::result::Result<{integer}, _>` | = note: the method `as_deref_mut` exists but the following trait bounds were not satisfied: - `{integer}: std::ops::DerefMut` - `<{integer} as std::ops::Deref>::Target = _` + `{integer}: DerefMut` + `<{integer} as Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50480.stderr b/src/test/ui/issues/issue-50480.stderr index dfcac12817..50691f1f57 100644 --- a/src/test/ui/issues/issue-50480.stderr +++ b/src/test/ui/issues/issue-50480.stderr @@ -16,7 +16,7 @@ error[E0277]: `i32` is not an iterator LL | struct Foo(NotDefined, ::Item, Vec, String); | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i32` + = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` error[E0204]: the trait `Copy` may not be implemented for this type diff --git a/src/test/ui/issues/issue-50582.stderr b/src/test/ui/issues/issue-50582.stderr index 13f6c4d763..4f531460e6 100644 --- a/src/test/ui/issues/issue-50582.stderr +++ b/src/test/ui/issues/issue-50582.stderr @@ -10,7 +10,7 @@ error[E0277]: cannot add `()` to `{integer}` LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); | ^ no implementation for `{integer} + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `{integer}` + = help: the trait `Add<()>` is not implemented for `{integer}` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-5100.rs b/src/test/ui/issues/issue-5100.rs index 71dd237cad..5e926fabe2 100644 --- a/src/test/ui/issues/issue-5100.rs +++ b/src/test/ui/issues/issue-5100.rs @@ -33,7 +33,7 @@ fn main() { box (true, false) => () //~^ ERROR mismatched types //~| expected tuple `(bool, bool)` -//~| found struct `std::boxed::Box<_>` +//~| found struct `Box<_>` } match (true, false) { diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr index a89980964c..de71e1d1a6 100644 --- a/src/test/ui/issues/issue-5100.stderr +++ b/src/test/ui/issues/issue-5100.stderr @@ -40,10 +40,10 @@ error[E0308]: mismatched types LL | match (true, false) { | ------------- this expression has type `(bool, bool)` LL | box (true, false) => () - | ^^^^^^^^^^^^^^^^^ expected tuple, found struct `std::boxed::Box` + | ^^^^^^^^^^^^^^^^^ expected tuple, found struct `Box` | = note: expected tuple `(bool, bool)` - found struct `std::boxed::Box<_>` + found struct `Box<_>` error[E0308]: mismatched types --> $DIR/issue-5100.rs:40:9 diff --git a/src/test/ui/issues/issue-51154.rs b/src/test/ui/issues/issue-51154.rs new file mode 100644 index 0000000000..12903f7901 --- /dev/null +++ b/src/test/ui/issues/issue-51154.rs @@ -0,0 +1,6 @@ +fn foo() { + let _: Box = Box::new(|| ()); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/issues/issue-51154.stderr b/src/test/ui/issues/issue-51154.stderr new file mode 100644 index 0000000000..3c3428f309 --- /dev/null +++ b/src/test/ui/issues/issue-51154.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-51154.rs:2:30 + | +LL | fn foo() { + | - this type parameter +LL | let _: Box = Box::new(|| ()); + | ^^^^^ expected type parameter `F`, found closure + | + = note: expected type parameter `F` + found closure `[closure@$DIR/issue-51154.rs:2:30: 2:35]` + = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-5216.stderr b/src/test/ui/issues/issue-5216.stderr index 21d9333735..7a1f42adf6 100644 --- a/src/test/ui/issues/issue-5216.stderr +++ b/src/test/ui/issues/issue-5216.stderr @@ -2,18 +2,18 @@ error[E0308]: mismatched types --> $DIR/issue-5216.rs:3:21 | LL | pub static C: S = S(f); - | ^ expected struct `std::boxed::Box`, found fn item + | ^ expected struct `Box`, found fn item | - = note: expected struct `std::boxed::Box<(dyn std::ops::FnMut() + 'static)>` + = note: expected struct `Box<(dyn FnMut() + 'static)>` found fn item `fn() {f}` error[E0308]: mismatched types --> $DIR/issue-5216.rs:8:19 | LL | pub static D: T = g; - | ^ expected struct `std::boxed::Box`, found fn item + | ^ expected struct `Box`, found fn item | - = note: expected struct `std::boxed::Box<(dyn std::ops::FnMut() + 'static)>` + = note: expected struct `Box<(dyn FnMut() + 'static)>` found fn item `fn() {g}` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-52262.stderr b/src/test/ui/issues/issue-52262.stderr index 7312976c80..c0bde4b232 100644 --- a/src/test/ui/issues/issue-52262.stderr +++ b/src/test/ui/issues/issue-52262.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `*key` which is behind a shared reference --> $DIR/issue-52262.rs:16:35 | LL | String::from_utf8(*key).unwrap() - | ^^^^ move occurs because `*key` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*key` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-53348.rs b/src/test/ui/issues/issue-53348.rs index bbfdd9c538..65f4656b02 100644 --- a/src/test/ui/issues/issue-53348.rs +++ b/src/test/ui/issues/issue-53348.rs @@ -9,7 +9,7 @@ fn main() { for i in v { a = *i.to_string(); //~^ ERROR mismatched types - //~| NOTE expected struct `std::string::String`, found `str` + //~| NOTE expected struct `String`, found `str` v2.push(a); } } diff --git a/src/test/ui/issues/issue-53348.stderr b/src/test/ui/issues/issue-53348.stderr index 433fe40ea0..8f50026124 100644 --- a/src/test/ui/issues/issue-53348.stderr +++ b/src/test/ui/issues/issue-53348.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-53348.rs:10:13 | LL | a = *i.to_string(); - | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found `str` + | ^^^^^^^^^^^^^^ expected struct `String`, found `str` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-53692.stderr b/src/test/ui/issues/issue-53692.stderr index b83fb346b1..09c78da54b 100644 --- a/src/test/ui/issues/issue-53692.stderr +++ b/src/test/ui/issues/issue-53692.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | let items_clone: Vec = ref_items.clone(); | -------- ^^^^^^^^^^^^^^^^^ | | | - | | expected struct `std::vec::Vec`, found `&[i32]` + | | expected struct `Vec`, found `&[i32]` | | help: try using a conversion method: `ref_items.to_vec()` | expected due to this | - = note: expected struct `std::vec::Vec` + = note: expected struct `Vec` found reference `&[i32]` error[E0308]: mismatched types @@ -17,7 +17,7 @@ error[E0308]: mismatched types LL | let string: String = s.clone(); | ------ ^^^^^^^^^ | | | - | | expected struct `std::string::String`, found `&str` + | | expected struct `String`, found `&str` | | help: try using a conversion method: `s.to_string()` | expected due to this diff --git a/src/test/ui/issues/issue-54044.rs b/src/test/ui/issues/issue-54044.rs new file mode 100644 index 0000000000..3f0b8bc5e3 --- /dev/null +++ b/src/test/ui/issues/issue-54044.rs @@ -0,0 +1,14 @@ +// ignore-tidy-linelength +#![deny(unused_attributes)] //~ NOTE lint level is defined here + +#[cold] +//~^ ERROR attribute should be applied to a function +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +struct Foo; //~ NOTE not a function + +fn main() { + #[cold] + //~^ ERROR attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + 5; //~ NOTE not a function +} diff --git a/src/test/ui/issues/issue-54044.stderr b/src/test/ui/issues/issue-54044.stderr new file mode 100644 index 0000000000..a13e84bbee --- /dev/null +++ b/src/test/ui/issues/issue-54044.stderr @@ -0,0 +1,29 @@ +error: attribute should be applied to a function + --> $DIR/issue-54044.rs:4:1 + | +LL | #[cold] + | ^^^^^^^ +... +LL | struct Foo; + | ----------- not a function + | +note: the lint level is defined here + --> $DIR/issue-54044.rs:2:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: attribute should be applied to a function + --> $DIR/issue-54044.rs:10:5 + | +LL | #[cold] + | ^^^^^^^ +... +LL | 5; + | - not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-54062.rs b/src/test/ui/issues/issue-54062.rs index 495b7343f2..093d6601d4 100644 --- a/src/test/ui/issues/issue-54062.rs +++ b/src/test/ui/issues/issue-54062.rs @@ -7,7 +7,6 @@ struct Test { fn main() {} fn testing(test: Test) { - let _ = test.comps.inner.lock().unwrap(); - //~^ ERROR: field `inner` of struct `std::sync::Mutex` is private - //~| ERROR: no method named `unwrap` found + let _ = test.comps.inner.try_lock(); + //~^ ERROR: field `inner` of struct `Mutex` is private } diff --git a/src/test/ui/issues/issue-54062.stderr b/src/test/ui/issues/issue-54062.stderr index f9aef08c35..5361ee1d34 100644 --- a/src/test/ui/issues/issue-54062.stderr +++ b/src/test/ui/issues/issue-54062.stderr @@ -1,16 +1,9 @@ -error[E0616]: field `inner` of struct `std::sync::Mutex` is private +error[E0616]: field `inner` of struct `Mutex` is private --> $DIR/issue-54062.rs:10:24 | -LL | let _ = test.comps.inner.lock().unwrap(); +LL | let _ = test.comps.inner.try_lock(); | ^^^^^ private field -error[E0599]: no method named `unwrap` found for struct `std::sys_common::mutex::MutexGuard<'_>` in the current scope - --> $DIR/issue-54062.rs:10:37 - | -LL | let _ = test.comps.inner.lock().unwrap(); - | ^^^^^^ method not found in `std::sys_common::mutex::MutexGuard<'_>` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0599, E0616. -For more information about an error, try `rustc --explain E0599`. +For more information about this error, try `rustc --explain E0616`. diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr index 6b67125e36..eb85f34984 100644 --- a/src/test/ui/issues/issue-54348.stderr +++ b/src/test/ui/issues/issue-54348.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/issue-54348.rs:5:5 | LL | [1][1.5 as usize]; - | ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default @@ -10,7 +10,7 @@ error: this operation will panic at runtime --> $DIR/issue-54348.rs:6:5 | LL | [1][1u64 as usize]; - | ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-54410.stderr b/src/test/ui/issues/issue-54410.stderr index 9205a518c8..516c59afb3 100644 --- a/src/test/ui/issues/issue-54410.stderr +++ b/src/test/ui/issues/issue-54410.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[i8]` cannot be known at compilation LL | pub static mut symbol: [i8]; | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[i8]` + = help: the trait `Sized` is not implemented for `[i8]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr index 6bfb7af544..1aa0050336 100644 --- a/src/test/ui/issues/issue-55796.stderr +++ b/src/test/ui/issues/issue-55796.stderr @@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the tra | LL | pub trait Graph<'a> { | ^^ -note: ...so that the type `std::iter::Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:16:40: 16:54]>` will meet its required lifetime bounds +note: ...so that the type `Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:16:40: 16:54]>` will meet its required lifetime bounds --> $DIR/issue-55796.rs:16:9 | LL | Box::new(self.out_edges(u).map(|e| e.target())) @@ -20,8 +20,8 @@ note: ...so that the expression is assignable | LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` - found `std::boxed::Box>::Node>>` + = note: expected `Box<(dyn Iterator>::Node> + 'static)>` + found `Box>::Node>>` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/issue-55796.rs:21:9 @@ -34,7 +34,7 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the tra | LL | pub trait Graph<'a> { | ^^ -note: ...so that the type `std::iter::Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:21:39: 21:53]>` will meet its required lifetime bounds +note: ...so that the type `Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:21:39: 21:53]>` will meet its required lifetime bounds --> $DIR/issue-55796.rs:21:9 | LL | Box::new(self.in_edges(u).map(|e| e.target())) @@ -45,8 +45,8 @@ note: ...so that the expression is assignable | LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` - found `std::boxed::Box>::Node>>` + = note: expected `Box<(dyn Iterator>::Node> + 'static)>` + found `Box>::Node>>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-56175.stderr b/src/test/ui/issues/issue-56175.stderr index c0799db7c1..ee3f609f47 100644 --- a/src/test/ui/issues/issue-56175.stderr +++ b/src/test/ui/issues/issue-56175.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `trait_method` found for struct `reexported_trait::FooStruct` in the current scope +error[E0599]: no method named `trait_method` found for struct `FooStruct` in the current scope --> $DIR/issue-56175.rs:5:33 | LL | reexported_trait::FooStruct.trait_method(); - | ^^^^^^^^^^^^ method not found in `reexported_trait::FooStruct` + | ^^^^^^^^^^^^ method not found in `FooStruct` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: @@ -10,11 +10,11 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use reexported_trait::Trait; | -error[E0599]: no method named `trait_method_b` found for struct `reexported_trait::FooStruct` in the current scope +error[E0599]: no method named `trait_method_b` found for struct `FooStruct` in the current scope --> $DIR/issue-56175.rs:7:33 | LL | reexported_trait::FooStruct.trait_method_b(); - | ^^^^^^^^^^^^^^ method not found in `reexported_trait::FooStruct` + | ^^^^^^^^^^^^^^ method not found in `FooStruct` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-56806.stderr b/src/test/ui/issues/issue-56806.stderr index a4f9aadcfe..f164fd0c5d 100644 --- a/src/test/ui/issues/issue-56806.stderr +++ b/src/test/ui/issues/issue-56806.stderr @@ -1,4 +1,4 @@ -error[E0307]: invalid `self` parameter type: std::boxed::Box<(dyn Trait + 'static)> +error[E0307]: invalid `self` parameter type: Box<(dyn Trait + 'static)> --> $DIR/issue-56806.rs:2:34 | LL | fn dyn_instead_of_self(self: Box); diff --git a/src/test/ui/issues/issue-56943.stderr b/src/test/ui/issues/issue-56943.stderr index 6caf974809..74ed5ec0fb 100644 --- a/src/test/ui/issues/issue-56943.stderr +++ b/src/test/ui/issues/issue-56943.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-56943.rs:6:29 | LL | let _: issue_56943::S = issue_56943::S2; - | -------------- ^^^^^^^^^^^^^^^ expected struct `issue_56943::S`, found struct `issue_56943::S2` + | -------------- ^^^^^^^^^^^^^^^ expected struct `S`, found struct `S2` | | | expected due to this diff --git a/src/test/ui/issues/issue-57741-1.stderr b/src/test/ui/issues/issue-57741-1.stderr index a4f1ac9482..789a1f44db 100644 --- a/src/test/ui/issues/issue-57741-1.stderr +++ b/src/test/ui/issues/issue-57741-1.stderr @@ -2,22 +2,22 @@ error[E0308]: mismatched types --> $DIR/issue-57741-1.rs:14:9 | LL | let y = match x { - | - this expression has type `std::boxed::Box` + | - this expression has type `Box` LL | S::A { a } | S::B { b: a } => a, - | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | ^^^^^^^^^^ expected struct `Box`, found enum `S` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `S` error[E0308]: mismatched types --> $DIR/issue-57741-1.rs:14:22 | LL | let y = match x { - | - this expression has type `std::boxed::Box` + | - this expression has type `Box` LL | S::A { a } | S::B { b: a } => a, - | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | ^^^^^^^^^^^^^ expected struct `Box`, found enum `S` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `S` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-57741.stderr b/src/test/ui/issues/issue-57741.stderr index 6f9e5b08a8..cd277f20ef 100644 --- a/src/test/ui/issues/issue-57741.stderr +++ b/src/test/ui/issues/issue-57741.stderr @@ -4,12 +4,12 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this expression has type `std::boxed::Box` + | this expression has type `Box` | help: consider dereferencing the boxed value: `*x` LL | T::A(a) | T::B(a) => a, - | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T` + | ^^^^^^^ expected struct `Box`, found enum `T` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `T` error[E0308]: mismatched types @@ -18,12 +18,12 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this expression has type `std::boxed::Box` + | this expression has type `Box` | help: consider dereferencing the boxed value: `*x` LL | T::A(a) | T::B(a) => a, - | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T` + | ^^^^^^^ expected struct `Box`, found enum `T` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `T` error[E0308]: mismatched types @@ -32,12 +32,12 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this expression has type `std::boxed::Box` + | this expression has type `Box` | help: consider dereferencing the boxed value: `*x` LL | S::A { a } | S::B { b: a } => a, - | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | ^^^^^^^^^^ expected struct `Box`, found enum `S` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `S` error[E0308]: mismatched types @@ -46,12 +46,12 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this expression has type `std::boxed::Box` + | this expression has type `Box` | help: consider dereferencing the boxed value: `*x` LL | S::A { a } | S::B { b: a } => a, - | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | ^^^^^^^^^^^^^ expected struct `Box`, found enum `S` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `S` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-57843.stderr b/src/test/ui/issues/issue-57843.stderr index 57b206d7bf..01edb9507a 100644 --- a/src/test/ui/issues/issue-57843.stderr +++ b/src/test/ui/issues/issue-57843.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | Foo(Box::new(|_| ())); | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(&'a bool,)>` - found type `std::ops::FnOnce<(&bool,)>` + = note: expected type `FnOnce<(&'a bool,)>` + found type `FnOnce<(&bool,)>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-58344.rs b/src/test/ui/issues/issue-58344.rs index 99b656d74f..9b184e296a 100644 --- a/src/test/ui/issues/issue-58344.rs +++ b/src/test/ui/issues/issue-58344.rs @@ -40,8 +40,8 @@ fn add_generic, B>(lhs: A, rhs: B) -> Either< fn add_one( value: u32, ) -> Either>::Output>, impl Trait<>::Output>> { - //~^ ERROR: the trait bound `impl Trait<::Output>: Trait` - //~| ERROR: the trait bound `impl Trait<::Output>: Trait` + //~^ ERROR: the trait bound `impl Trait<::Output>: Trait` + //~| ERROR: the trait bound `impl Trait<::Output>: Trait` add_generic(value, 1u32) } diff --git a/src/test/ui/issues/issue-58344.stderr b/src/test/ui/issues/issue-58344.stderr index e0c196e518..ade85d8b01 100644 --- a/src/test/ui/issues/issue-58344.stderr +++ b/src/test/ui/issues/issue-58344.stderr @@ -1,22 +1,22 @@ -error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied +error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied --> $DIR/issue-58344.rs:42:13 | LL | ) -> Either>::Output>, impl Trait<>::Output>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` ... LL | add_generic(value, 1u32) - | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` + | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` | = note: the return type of a function must have a statically known size -error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied +error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied --> $DIR/issue-58344.rs:42:52 | LL | ) -> Either>::Output>, impl Trait<>::Output>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` ... LL | add_generic(value, 1u32) - | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` + | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr index 897984d0ae..8d639304ab 100644 --- a/src/test/ui/issues/issue-5883.stderr +++ b/src/test/ui/issues/issue-5883.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at LL | fn new_struct(r: dyn A + 'static) | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` + = help: the trait `Sized` is not implemented for `(dyn A + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | @@ -20,7 +20,7 @@ LL | LL | Struct { r: r } | --------------- this returned value is of type `Struct` | - = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` + = help: within `Struct`, the trait `Sized` is not implemented for `(dyn A + 'static)` = note: required because it appears within the type `Struct` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/issues/issue-59488.rs b/src/test/ui/issues/issue-59488.rs index 6fa9961f26..384501e3e5 100644 --- a/src/test/ui/issues/issue-59488.rs +++ b/src/test/ui/issues/issue-59488.rs @@ -29,6 +29,6 @@ fn main() { let i = Foo::Bar; assert_eq!(Foo::Bar, i); //~^ ERROR binary operation `==` cannot be applied to type `fn(usize) -> Foo {Foo::Bar}` [E0369] - //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` [E0277] - //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` [E0277] + //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` [E0277] + //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` [E0277] } diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr index 58f1376b19..3b10491a8a 100644 --- a/src/test/ui/issues/issue-59488.stderr +++ b/src/test/ui/issues/issue-59488.stderr @@ -79,25 +79,25 @@ LL | assert_eq!(Foo::Bar, i); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` +error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` --> $DIR/issue-59488.rs:30:5 | LL | assert_eq!(Foo::Bar, i); - | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn(usize) -> Foo {Foo::Bar}` + = help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` + = note: required because of the requirements on the impl of `Debug` for `&fn(usize) -> Foo {Foo::Bar}` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` +error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` --> $DIR/issue-59488.rs:30:5 | LL | assert_eq!(Foo::Bar, i); - | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn(usize) -> Foo {Foo::Bar}` + = help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` + = note: required because of the requirements on the impl of `Debug` for `&fn(usize) -> Foo {Foo::Bar}` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-60218.stderr b/src/test/ui/issues/issue-60218.stderr index 77b9d9c4aa..a2b2fdd4fd 100644 --- a/src/test/ui/issues/issue-60218.stderr +++ b/src/test/ui/issues/issue-60218.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'t> ::IntoIter, _> as std::iter::Iterator>::Item: Foo` is not satisfied +error[E0277]: the trait bound `for<'t> ::IntoIter, _> as Iterator>::Item: Foo` is not satisfied --> $DIR/issue-60218.rs:18:5 | LL | pub fn trigger_error(iterable: I, functor: F) @@ -8,7 +8,7 @@ LL | for<'t> ::IntoIter, F> as Iterator>::Item: Foo, | --- required by this bound in `trigger_error` ... LL | trigger_error(vec![], |x: &u32| x) - | ^^^^^^^^^^^^^ the trait `for<'t> Foo` is not implemented for `::IntoIter, _> as std::iter::Iterator>::Item` + | ^^^^^^^^^^^^^ the trait `for<'t> Foo` is not implemented for `::IntoIter, _> as Iterator>::Item` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-61106.stderr b/src/test/ui/issues/issue-61106.stderr index 163aa816ab..2d841d28ee 100644 --- a/src/test/ui/issues/issue-61106.stderr +++ b/src/test/ui/issues/issue-61106.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo(x.clone()); | ^^^^^^^^^ | | - | expected `&str`, found struct `std::string::String` + | expected `&str`, found struct `String` | help: consider borrowing here: `&x` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index d7c2bbf917..d6c289cbd6 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `bad_letters` --> $DIR/issue-61108.rs:6:5 | LL | let mut bad_letters = vec!['e', 't', 'o', 'i']; - | --------------- move occurs because `bad_letters` has type `std::vec::Vec`, which does not implement the `Copy` trait + | --------------- move occurs because `bad_letters` has type `Vec`, which does not implement the `Copy` trait LL | for l in bad_letters { | ----------- | | diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr index e942a1aeba..5b97e21b88 100644 --- a/src/test/ui/issues/issue-64559.stderr +++ b/src/test/ui/issues/issue-64559.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `orig` --> $DIR/issue-64559.rs:4:20 | LL | let orig = vec![true]; - | ---- move occurs because `orig` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ---- move occurs because `orig` has type `Vec`, which does not implement the `Copy` trait LL | for _val in orig {} | ---- | | diff --git a/src/test/ui/issues/issue-6458-4.stderr b/src/test/ui/issues/issue-6458-4.stderr index 6537867bbf..00ebff9007 100644 --- a/src/test/ui/issues/issue-6458-4.stderr +++ b/src/test/ui/issues/issue-6458-4.stderr @@ -8,7 +8,7 @@ LL | fn foo(b: bool) -> Result { LL | Err("bar".to_string()); | - help: consider removing this semicolon | - = note: expected enum `std::result::Result` + = note: expected enum `std::result::Result` found unit type `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-65611.stderr b/src/test/ui/issues/issue-65611.stderr index 20e2ba144d..e3c005a059 100644 --- a/src/test/ui/issues/issue-65611.stderr +++ b/src/test/ui/issues/issue-65611.stderr @@ -5,7 +5,7 @@ LL | let x = buffer.last().unwrap().0.clone(); | -------^^^^-- | | | | | cannot infer type for type parameter `T` - | this method call resolves to `std::option::Option<&T>` + | this method call resolves to `Option<&T>` | = note: type must be known at this point diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr index 83d8770b2e..de0e78ac20 100644 --- a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr +++ b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr @@ -4,12 +4,12 @@ error[E0034]: multiple applicable items in scope LL | r#fn {}.r#struct(); | ^^^^^^^^ multiple `r#struct` found | -note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn` +note: candidate #1 is defined in an impl of the trait `async` for the type `fn` --> $DIR/issue-65634-raw-ident-suggestion.rs:4:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn` +note: candidate #2 is defined in an impl of the trait `await` for the type `fn` --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5 | LL | fn r#struct(&self) { diff --git a/src/test/ui/issues/issue-65673.stderr b/src/test/ui/issues/issue-65673.stderr index fef64ebf2d..aa43ac9414 100644 --- a/src/test/ui/issues/issue-65673.stderr +++ b/src/test/ui/issues/issue-65673.stderr @@ -9,7 +9,7 @@ LL | type Ctx; LL | type Ctx = dyn Alias; | ^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr index 8e7ee97e0b..a08531000b 100644 --- a/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr +++ b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr @@ -1,18 +1,18 @@ -error[E0277]: a value of type `std::vec::Vec` cannot be built from an iterator over elements of type `&f64` +error[E0277]: a value of type `Vec` cannot be built from an iterator over elements of type `&f64` --> $DIR/issue-66923-show-error-for-correct-call.rs:8:39 | LL | let x2: Vec = x1.into_iter().collect(); - | ^^^^^^^ value of type `std::vec::Vec` cannot be built from `std::iter::Iterator` + | ^^^^^^^ value of type `Vec` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec` + = help: the trait `FromIterator<&f64>` is not implemented for `Vec` -error[E0277]: a value of type `std::vec::Vec` cannot be built from an iterator over elements of type `&f64` +error[E0277]: a value of type `Vec` cannot be built from an iterator over elements of type `&f64` --> $DIR/issue-66923-show-error-for-correct-call.rs:12:29 | LL | let x3 = x1.into_iter().collect::>(); - | ^^^^^^^ value of type `std::vec::Vec` cannot be built from `std::iter::Iterator` + | ^^^^^^^ value of type `Vec` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec` + = help: the trait `FromIterator<&f64>` is not implemented for `Vec` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr index 3330d60242..036a9300a1 100644 --- a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr +++ b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr @@ -1,12 +1,12 @@ -error[E0271]: type mismatch resolving ` as std::ops::Deref>::Target == std::rc::Rc` +error[E0271]: type mismatch resolving ` as Deref>::Target == Rc` --> $DIR/issue-67039-unsound-pin-partialeq.rs:25:29 | LL | let _ = Pin::new(Apple) == Rc::pin(Apple); - | ^^ expected struct `Apple`, found struct `std::rc::Rc` + | ^^ expected struct `Apple`, found struct `Rc` | = note: expected type `Apple` - found struct `std::rc::Rc` - = note: required because of the requirements on the impl of `std::cmp::PartialEq>>` for `std::pin::Pin` + found struct `Rc` + = note: required because of the requirements on the impl of `PartialEq>>` for `Pin` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-67552.rs b/src/test/ui/issues/issue-67552.rs index b0fcb74764..98192dae20 100644 --- a/src/test/ui/issues/issue-67552.rs +++ b/src/test/ui/issues/issue-67552.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test: ".nll/" -> "/" fn main() { rec(Empty); diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr index f3e73399b5..cf05a72e92 100644 --- a/src/test/ui/issues/issue-67552.stderr +++ b/src/test/ui/issues/issue-67552.stderr @@ -1,16 +1,17 @@ error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &... &mut &mut &mut &mut &mut Empty>` - --> $DIR/issue-67552.rs:27:9 + --> $DIR/issue-67552.rs:28:9 | LL | rec(identity(&mut it)) | ^^^^^^^^^^^^^^^^^^^^^^ | note: `rec` defined here - --> $DIR/issue-67552.rs:20:1 + --> $DIR/issue-67552.rs:21:1 | LL | / fn rec(mut it: T) LL | | where LL | | T: Iterator, | |________________^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-67552/issue-67552.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-69725.stderr b/src/test/ui/issues/issue-69725.stderr index 20420d37b3..3f70dbcc2a 100644 --- a/src/test/ui/issues/issue-69725.stderr +++ b/src/test/ui/issues/issue-69725.stderr @@ -1,25 +1,25 @@ -error[E0599]: no method named `clone` found for struct `issue_69725::Struct` in the current scope +error[E0599]: no method named `clone` found for struct `Struct` in the current scope --> $DIR/issue-69725.rs:7:32 | LL | let _ = Struct::::new().clone(); - | ^^^^^ method not found in `issue_69725::Struct` + | ^^^^^ method not found in `Struct` | ::: $DIR/auxiliary/issue-69725.rs:2:1 | LL | pub struct Struct(A); - | ------------------------ doesn't satisfy `issue_69725::Struct: std::clone::Clone` + | ------------------------ doesn't satisfy `Struct: Clone` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `A: std::clone::Clone` - which is required by `issue_69725::Struct: std::clone::Clone` + `A: Clone` + which is required by `Struct: Clone` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-7013.rs b/src/test/ui/issues/issue-7013.rs index 3d72b67e39..c1f400b330 100644 --- a/src/test/ui/issues/issue-7013.rs +++ b/src/test/ui/issues/issue-7013.rs @@ -24,5 +24,5 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely + //~^ ERROR `Rc>` cannot be sent between threads safely } diff --git a/src/test/ui/issues/issue-7013.stderr b/src/test/ui/issues/issue-7013.stderr index f2668d3312..5f3156a540 100644 --- a/src/test/ui/issues/issue-7013.stderr +++ b/src/test/ui/issues/issue-7013.stderr @@ -1,13 +1,13 @@ -error[E0277]: `std::rc::Rc>` cannot be sent between threads safely +error[E0277]: `Rc>` cannot be sent between threads safely --> $DIR/issue-7013.rs:26:19 | LL | let a = A {v: box B{v: None} as Box}; - | ^^^^^^^^^^^^^^ `std::rc::Rc>` cannot be sent between threads safely + | ^^^^^^^^^^^^^^ `Rc>` cannot be sent between threads safely | - = help: within `B`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `std::option::Option>>` + = help: within `B`, the trait `Send` is not implemented for `Rc>` + = note: required because it appears within the type `Option>>` = note: required because it appears within the type `B` - = note: required for the cast to the object type `dyn Foo + std::marker::Send` + = note: required for the cast to the object type `dyn Foo + Send` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-70381.rs b/src/test/ui/issues/issue-70381.rs new file mode 100644 index 0000000000..3df8277b87 --- /dev/null +++ b/src/test/ui/issues/issue-70381.rs @@ -0,0 +1,6 @@ +// Test that multi-byte unicode characters with missing parameters do not ICE. + +fn main() { + println!("\r¡{}") + //~^ ERROR 1 positional argument in format string +} diff --git a/src/test/ui/issues/issue-70381.stderr b/src/test/ui/issues/issue-70381.stderr new file mode 100644 index 0000000000..96b8e65699 --- /dev/null +++ b/src/test/ui/issues/issue-70381.stderr @@ -0,0 +1,8 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/issue-70381.rs:4:16 + | +LL | println!("\r¡{}") + | ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-7061.rs b/src/test/ui/issues/issue-7061.rs index ef61eac7ba..8a6ee920a3 100644 --- a/src/test/ui/issues/issue-7061.rs +++ b/src/test/ui/issues/issue-7061.rs @@ -3,7 +3,7 @@ struct BarStruct; impl<'a> BarStruct { fn foo(&'a mut self) -> Box { self } //~^ ERROR mismatched types - //~| expected struct `std::boxed::Box` + //~| expected struct `Box` //~| found mutable reference `&'a mut BarStruct` } diff --git a/src/test/ui/issues/issue-7061.stderr b/src/test/ui/issues/issue-7061.stderr index bf1450ca76..27034378d3 100644 --- a/src/test/ui/issues/issue-7061.stderr +++ b/src/test/ui/issues/issue-7061.stderr @@ -2,11 +2,11 @@ error[E0308]: mismatched types --> $DIR/issue-7061.rs:4:46 | LL | fn foo(&'a mut self) -> Box { self } - | -------------- ^^^^ expected struct `std::boxed::Box`, found `&mut BarStruct` + | -------------- ^^^^ expected struct `Box`, found `&mut BarStruct` | | - | expected `std::boxed::Box` because of return type + | expected `Box` because of return type | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found mutable reference `&'a mut BarStruct` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr index 467c15cc52..f5a56d7553 100644 --- a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr +++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr @@ -20,18 +20,18 @@ LL | assert_eq!(a, 0); found type `i32` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `fn() -> i32 {a}` doesn't implement `std::fmt::Debug` +error[E0277]: `fn() -> i32 {a}` doesn't implement `Debug` --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5 | LL | fn a() -> i32 { | - consider calling this function ... LL | assert_eq!(a, 0); - | ^^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `fn() -> i32 {a}` + = help: the trait `Debug` is not implemented for `fn() -> i32 {a}` = help: use parentheses to call the function: `a()` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn() -> i32 {a}` + = note: required because of the requirements on the impl of `Debug` for `&fn() -> i32 {a}` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-7092.rs b/src/test/ui/issues/issue-7092.rs index 09fa6c5250..85bfbf90d9 100644 --- a/src/test/ui/issues/issue-7092.rs +++ b/src/test/ui/issues/issue-7092.rs @@ -5,9 +5,9 @@ fn foo(x: Whatever) { match x { Some(field) => //~^ ERROR mismatched types -//~| expected enum `Whatever`, found enum `std::option::Option` +//~| expected enum `Whatever`, found enum `Option` //~| expected enum `Whatever` -//~| found enum `std::option::Option<_>` +//~| found enum `Option<_>` field.access(), } } diff --git a/src/test/ui/issues/issue-7092.stderr b/src/test/ui/issues/issue-7092.stderr index 590dd40c65..59e8d75e23 100644 --- a/src/test/ui/issues/issue-7092.stderr +++ b/src/test/ui/issues/issue-7092.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | match x { | - this expression has type `Whatever` LL | Some(field) => - | ^^^^^^^^^^^ expected enum `Whatever`, found enum `std::option::Option` + | ^^^^^^^^^^^ expected enum `Whatever`, found enum `Option` | = note: expected enum `Whatever` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-71036.rs b/src/test/ui/issues/issue-71036.rs index 01d1cff42e..3d2df6fe99 100644 --- a/src/test/ui/issues/issue-71036.rs +++ b/src/test/ui/issues/issue-71036.rs @@ -9,8 +9,8 @@ struct Foo<'a, T: ?Sized> { } impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn> for Foo<'a, T> {} -//~^ ERROR the trait bound `&'a T: std::marker::Unsize<&'a U>` is not satisfied -//~| NOTE the trait `std::marker::Unsize<&'a U>` is not implemented for `&'a T` +//~^ ERROR the trait bound `&'a T: Unsize<&'a U>` is not satisfied +//~| NOTE the trait `Unsize<&'a U>` is not implemented for `&'a T` //~| NOTE all implementations of `Unsize` are provided automatically by the compiler //~| NOTE required because of the requirements on the impl diff --git a/src/test/ui/issues/issue-71036.stderr b/src/test/ui/issues/issue-71036.stderr index 57cf246894..db1f694666 100644 --- a/src/test/ui/issues/issue-71036.stderr +++ b/src/test/ui/issues/issue-71036.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `&'a T: std::marker::Unsize<&'a U>` is not satisfied +error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied --> $DIR/issue-71036.rs:11:1 | LL | impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn> for Foo<'a, T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unsize<&'a U>` is not implemented for `&'a T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T` | = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information - = note: required because of the requirements on the impl of `std::ops::DispatchFromDyn<&'a &'a U>` for `&'a &'a T` + = note: required because of the requirements on the impl of `DispatchFromDyn<&'a &'a U>` for `&'a &'a T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-71584.stderr b/src/test/ui/issues/issue-71584.stderr index c162d338a9..1c216e6498 100644 --- a/src/test/ui/issues/issue-71584.stderr +++ b/src/test/ui/issues/issue-71584.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `>::Output == u64` +error[E0284]: type annotations needed: cannot satisfy `>::Output == u64` --> $DIR/issue-71584.rs:4:11 | LL | d = d % n.into(); - | ^ cannot satisfy `>::Output == u64` + | ^ cannot satisfy `>::Output == u64` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-72690.stderr b/src/test/ui/issues/issue-72690.stderr index 64e78ddf60..feb1316357 100644 --- a/src/test/ui/issues/issue-72690.stderr +++ b/src/test/ui/issues/issue-72690.stderr @@ -2,10 +2,10 @@ error[E0283]: type annotations needed --> $DIR/issue-72690.rs:7:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` error[E0282]: type annotations needed --> $DIR/issue-72690.rs:11:6 @@ -19,68 +19,68 @@ error[E0283]: type annotations needed LL | let _ = "x".as_ref(); | ^^^^^^ cannot infer type for type `str` | - = note: cannot satisfy `str: std::convert::AsRef<_>` + = note: cannot satisfy `str: AsRef<_>` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:19:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:25:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:33:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` -error[E0283]: type annotations needed for `std::string::String` +error[E0283]: type annotations needed for `String` --> $DIR/issue-72690.rs:41:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` LL | let _ = String::from("x"); | - consider giving this pattern a type | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` -error[E0283]: type annotations needed for `std::string::String` +error[E0283]: type annotations needed for `String` --> $DIR/issue-72690.rs:47:5 | LL | let _ = String::from("x"); | - consider giving this pattern a type LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` -error[E0283]: type annotations needed for `std::string::String` +error[E0283]: type annotations needed for `String` --> $DIR/issue-72690.rs:55:5 | LL | let _ = String::from("x"); | - consider giving this pattern a type ... LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` error: aborting due to 9 previous errors diff --git a/src/test/ui/issues/issue-7364.rs b/src/test/ui/issues/issue-7364.rs index 52ec9e42be..29a1644673 100644 --- a/src/test/ui/issues/issue-7364.rs +++ b/src/test/ui/issues/issue-7364.rs @@ -5,7 +5,6 @@ use std::cell::RefCell; // Regression test for issue 7364 static boxed: Box> = box RefCell::new(0); //~^ ERROR allocations are not allowed in statics -//~| ERROR `std::cell::RefCell` cannot be shared between threads safely [E0277] -//~| ERROR static contains unimplemented expression type +//~| ERROR `RefCell` cannot be shared between threads safely [E0277] fn main() { } diff --git a/src/test/ui/issues/issue-7364.stderr b/src/test/ui/issues/issue-7364.stderr index efff2c2452..8ceb3be7ec 100644 --- a/src/test/ui/issues/issue-7364.stderr +++ b/src/test/ui/issues/issue-7364.stderr @@ -4,26 +4,18 @@ error[E0010]: allocations are not allowed in statics LL | static boxed: Box> = box RefCell::new(0); | ^^^^^^^^^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/issue-7364.rs:6:41 - | -LL | static boxed: Box> = box RefCell::new(0); - | ^^^^^^^^^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error[E0277]: `std::cell::RefCell` cannot be shared between threads safely +error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/issue-7364.rs:6:1 | LL | static boxed: Box> = box RefCell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique>` - = note: required because it appears within the type `std::boxed::Box>` + = help: the trait `Sync` is not implemented for `RefCell` + = note: required because of the requirements on the impl of `Sync` for `Unique>` + = note: required because it appears within the type `Box>` = note: shared static variables must have a type that implements `Sync` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0010, E0019, E0277. +Some errors have detailed explanations: E0010, E0277. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/issues/issue-73886.rs b/src/test/ui/issues/issue-73886.rs index 2f1ec8c6d6..9c0c87a5cf 100644 --- a/src/test/ui/issues/issue-73886.rs +++ b/src/test/ui/issues/issue-73886.rs @@ -2,5 +2,5 @@ fn main() { let _ = &&[0] as &[_]; //~^ ERROR non-primitive cast: `&&[i32; 1]` as `&[_]` let _ = 7u32 as Option<_>; - //~^ ERROR non-primitive cast: `u32` as `std::option::Option<_>` + //~^ ERROR non-primitive cast: `u32` as `Option<_>` } diff --git a/src/test/ui/issues/issue-73886.stderr b/src/test/ui/issues/issue-73886.stderr index e8ab7db6b8..31f642ea66 100644 --- a/src/test/ui/issues/issue-73886.stderr +++ b/src/test/ui/issues/issue-73886.stderr @@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]` LL | let _ = &&[0] as &[_]; | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object -error[E0605]: non-primitive cast: `u32` as `std::option::Option<_>` +error[E0605]: non-primitive cast: `u32` as `Option<_>` --> $DIR/issue-73886.rs:4:13 | LL | let _ = 7u32 as Option<_>; diff --git a/src/test/ui/issues/issue-74236/main.stderr b/src/test/ui/issues/issue-74236/main.stderr index 51d4833e01..55e94ae72c 100644 --- a/src/test/ui/issues/issue-74236/main.stderr +++ b/src/test/ui/issues/issue-74236/main.stderr @@ -2,9 +2,9 @@ error[E0308]: mismatched types --> $DIR/main.rs:7:9 | LL | let () = dep::Renamed; - | ^^ ------------ this expression has type `dep::Renamed` + | ^^ ------------ this expression has type `Renamed` | | - | expected struct `dep::Renamed`, found `()` + | expected struct `Renamed`, found `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-75907.rs b/src/test/ui/issues/issue-75907.rs new file mode 100644 index 0000000000..8c155d9be3 --- /dev/null +++ b/src/test/ui/issues/issue-75907.rs @@ -0,0 +1,18 @@ +// Test for for diagnostic improvement issue #75907 + +mod foo { + pub(crate) struct Foo(u8); + pub(crate) struct Bar(pub u8, u8, Foo); + + pub(crate) fn make_bar() -> Bar { + Bar(1, 12, Foo(10)) + } +} + +use foo::{make_bar, Bar, Foo}; + +fn main() { + let Bar(x, y, Foo(z)) = make_bar(); + //~^ ERROR expected tuple struct + //~| ERROR expected tuple struct +} diff --git a/src/test/ui/issues/issue-75907.stderr b/src/test/ui/issues/issue-75907.stderr new file mode 100644 index 0000000000..65b9a51e01 --- /dev/null +++ b/src/test/ui/issues/issue-75907.stderr @@ -0,0 +1,29 @@ +error[E0532]: expected tuple struct or tuple variant, found struct `Bar` + --> $DIR/issue-75907.rs:15:9 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75907.rs:15:16 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^ ^^^^^^ private field + | | + | private field + +error[E0532]: expected tuple struct or tuple variant, found struct `Foo` + --> $DIR/issue-75907.rs:15:19 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75907.rs:15:23 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^ private field + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/issues/issue-75907_b.rs b/src/test/ui/issues/issue-75907_b.rs new file mode 100644 index 0000000000..fdd3bc6d72 --- /dev/null +++ b/src/test/ui/issues/issue-75907_b.rs @@ -0,0 +1,11 @@ +// Test for for diagnostic improvement issue #75907, extern crate +// aux-build:issue-75907.rs + +extern crate issue_75907 as a; + +use a::{make_bar, Bar}; + +fn main() { + let Bar(x, y, z) = make_bar(); + //~^ ERROR expected tuple struct +} diff --git a/src/test/ui/issues/issue-75907_b.stderr b/src/test/ui/issues/issue-75907_b.stderr new file mode 100644 index 0000000000..cdd21de6c3 --- /dev/null +++ b/src/test/ui/issues/issue-75907_b.stderr @@ -0,0 +1,9 @@ +error[E0532]: expected tuple struct or tuple variant, found struct `Bar` + --> $DIR/issue-75907_b.rs:9:9 + | +LL | let Bar(x, y, z) = make_bar(); + | ^^^ constructor is not visible here due to private fields + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/issues/issue-76077-1.fixed b/src/test/ui/issues/issue-76077-1.fixed new file mode 100644 index 0000000000..8103a7ca47 --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.fixed @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { invisible: bool, } + + #[derive(Default)] + pub struct Bar { pub visible: bool, invisible: bool, } +} + +fn main() { + let foo::Foo { .. } = foo::Foo::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields + + let foo::Bar { visible, .. } = foo::Bar::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077-1.rs b/src/test/ui/issues/issue-76077-1.rs new file mode 100644 index 0000000000..730332853c --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.rs @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { invisible: bool, } + + #[derive(Default)] + pub struct Bar { pub visible: bool, invisible: bool, } +} + +fn main() { + let foo::Foo {} = foo::Foo::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields + + let foo::Bar { visible } = foo::Bar::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077-1.stderr b/src/test/ui/issues/issue-76077-1.stderr new file mode 100644 index 0000000000..4557595529 --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.stderr @@ -0,0 +1,24 @@ +error: pattern requires `..` due to inaccessible fields + --> $DIR/issue-76077-1.rs:13:9 + | +LL | let foo::Foo {} = foo::Foo::default(); + | ^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let foo::Foo { .. } = foo::Foo::default(); + | ^^^^^^ + +error: pattern requires `..` due to inaccessible fields + --> $DIR/issue-76077-1.rs:16:9 + | +LL | let foo::Bar { visible } = foo::Bar::default(); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let foo::Bar { visible, .. } = foo::Bar::default(); + | ^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-76077.rs b/src/test/ui/issues/issue-76077.rs new file mode 100644 index 0000000000..1ecd37de2e --- /dev/null +++ b/src/test/ui/issues/issue-76077.rs @@ -0,0 +1,10 @@ +pub mod foo { + pub struct Foo { + you_cant_use_this_field: bool, + } +} + +fn main() { + foo::Foo {}; + //~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077.stderr b/src/test/ui/issues/issue-76077.stderr new file mode 100644 index 0000000000..d834ec5e0e --- /dev/null +++ b/src/test/ui/issues/issue-76077.stderr @@ -0,0 +1,8 @@ +error: cannot construct `Foo` with struct literal syntax due to inaccessible fields + --> $DIR/issue-76077.rs:8:5 + | +LL | foo::Foo {}; + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-76191.rs b/src/test/ui/issues/issue-76191.rs new file mode 100644 index 0000000000..d9790d2b56 --- /dev/null +++ b/src/test/ui/issues/issue-76191.rs @@ -0,0 +1,19 @@ +// Regression test for diagnostic issue #76191 +#![allow(non_snake_case)] + +use std::ops::RangeInclusive; + +const RANGE: RangeInclusive = 0..=255; + +const RANGE2: RangeInclusive = panic!(); + +fn main() { + let n: i32 = 1; + match n { + RANGE => {} + //~^ ERROR mismatched types + RANGE2 => {} + //~^ ERROR mismatched types + _ => {} + } +} diff --git a/src/test/ui/issues/issue-76191.stderr b/src/test/ui/issues/issue-76191.stderr new file mode 100644 index 0000000000..bdcd2fe1ad --- /dev/null +++ b/src/test/ui/issues/issue-76191.stderr @@ -0,0 +1,43 @@ +error[E0308]: mismatched types + --> $DIR/issue-76191.rs:13:9 + | +LL | const RANGE: RangeInclusive = 0..=255; + | ------------------------------------------- constant defined here +... +LL | match n { + | - this expression has type `i32` +LL | RANGE => {} + | ^^^^^ + | | + | expected `i32`, found struct `RangeInclusive` + | `RANGE` is interpreted as a constant, not a new binding + | + = note: expected type `i32` + found struct `RangeInclusive` +help: you may want to move the range into the match block + | +LL | 0..=255 => {} + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-76191.rs:15:9 + | +LL | const RANGE2: RangeInclusive = panic!(); + | --------------------------------------------- constant defined here +... +LL | match n { + | - this expression has type `i32` +... +LL | RANGE2 => {} + | ^^^^^^ + | | + | expected `i32`, found struct `RangeInclusive` + | `RANGE2` is interpreted as a constant, not a new binding + | + = note: expected type `i32` + found struct `RangeInclusive` + = note: constants only support matching by type, if you meant to match against a range of values, consider using a range pattern like `min ..= max` in the match block + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-77002.rs b/src/test/ui/issues/issue-77002.rs new file mode 100644 index 0000000000..c7dd3cf810 --- /dev/null +++ b/src/test/ui/issues/issue-77002.rs @@ -0,0 +1,16 @@ +// compile-flags: -Zmir-opt-level=2 -Copt-level=0 +// run-pass + +type M = [i64; 2]; + +fn f(a: &M) -> M { + let mut b: M = M::default(); + b[0] = a[0] * a[0]; + b +} + +fn main() { + let mut a: M = [1, 1]; + a = f(&a); + assert_eq!(a[0], 1); +} diff --git a/src/test/ui/issues/issue-77218.rs b/src/test/ui/issues/issue-77218.rs new file mode 100644 index 0000000000..bc992c21dc --- /dev/null +++ b/src/test/ui/issues/issue-77218.rs @@ -0,0 +1,7 @@ +fn main() { + let value = [7u8]; + while Some(0) = value.get(0) { //~ ERROR mismatched types + //~^ NOTE expected `bool`, found `()` + //~| HELP you might have meant to use pattern matching + } +} diff --git a/src/test/ui/issues/issue-77218.stderr b/src/test/ui/issues/issue-77218.stderr new file mode 100644 index 0000000000..eca44725eb --- /dev/null +++ b/src/test/ui/issues/issue-77218.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-77218.rs:3:11 + | +LL | while Some(0) = value.get(0) { + | ^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | while let Some(0) = value.get(0) { + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs new file mode 100644 index 0000000000..9b04d5ee00 --- /dev/null +++ b/src/test/ui/issues/issue-77919.rs @@ -0,0 +1,13 @@ +fn main() { + [1; >::VAL]; //~ ERROR evaluation of constant value failed +} +trait TypeVal { + const VAL: T; //~ ERROR any use of this value will cause an error +} +struct Five; +struct Multiply { + _n: PhantomData, //~ ERROR cannot find type `PhantomData` in this scope +} +impl TypeVal for Multiply where N: TypeVal {} +//~^ ERROR cannot find type `VAL` in this scope +//~| ERROR not all trait items implemented, missing: `VAL` diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr new file mode 100644 index 0000000000..129af00644 --- /dev/null +++ b/src/test/ui/issues/issue-77919.stderr @@ -0,0 +1,46 @@ +error[E0412]: cannot find type `PhantomData` in this scope + --> $DIR/issue-77919.rs:9:9 + | +LL | _n: PhantomData, + | ^^^^^^^^^^^ not found in this scope + | +help: consider importing this struct + | +LL | use std::marker::PhantomData; + | + +error[E0412]: cannot find type `VAL` in this scope + --> $DIR/issue-77919.rs:11:63 + | +LL | impl TypeVal for Multiply where N: TypeVal {} + | - ^^^ not found in this scope + | | + | help: you might be missing a type parameter: `, VAL` + +error[E0046]: not all trait items implemented, missing: `VAL` + --> $DIR/issue-77919.rs:11:1 + | +LL | const VAL: T; + | ------------- `VAL` from trait +... +LL | impl TypeVal for Multiply where N: TypeVal {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation + +error: any use of this value will cause an error + --> $DIR/issue-77919.rs:5:5 + | +LL | const VAL: T; + | ^^^^^^^^^^^^^ no MIR body is available for DefId(0:7 ~ issue_77919[317d]::TypeVal::VAL) + | + = note: `#[deny(const_err)]` on by default + +error[E0080]: evaluation of constant value failed + --> $DIR/issue-77919.rs:2:9 + | +LL | [1; >::VAL]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0046, E0080, E0412. +For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/issues/issue-78372.rs b/src/test/ui/issues/issue-78372.rs new file mode 100644 index 0000000000..77a8c92c81 --- /dev/null +++ b/src/test/ui/issues/issue-78372.rs @@ -0,0 +1,14 @@ +use std::ops::DispatchFromDyn; //~ ERROR use of unstable library feature 'dispatch_from_dyn' +struct Smaht(PhantomData); //~ ERROR cannot find type `PhantomData` in this scope +impl DispatchFromDyn> for T {} //~ ERROR cannot find type `U` in this scope +//~^ ERROR cannot find type `MISC` in this scope +//~| ERROR use of unstable library feature 'dispatch_from_dyn' +//~| ERROR the trait `DispatchFromDyn` may only be implemented for a coercion between structures +//~| ERROR type parameter `T` must be covered by another type when it appears before the first +trait Foo: X {} +trait X { + fn foo(self: Smaht); +} +trait Marker {} +impl Marker for dyn Foo {} +fn main() {} diff --git a/src/test/ui/issues/issue-78372.stderr b/src/test/ui/issues/issue-78372.stderr new file mode 100644 index 0000000000..9cdec1a5df --- /dev/null +++ b/src/test/ui/issues/issue-78372.stderr @@ -0,0 +1,62 @@ +error[E0412]: cannot find type `PhantomData` in this scope + --> $DIR/issue-78372.rs:2:23 + | +LL | struct Smaht(PhantomData); + | ^^^^^^^^^^^ not found in this scope + | +help: consider importing this struct + | +LL | use std::marker::PhantomData; + | + +error[E0412]: cannot find type `U` in this scope + --> $DIR/issue-78372.rs:3:31 + | +LL | impl DispatchFromDyn> for T {} + | - ^ help: a type parameter with a similar name exists: `T` + | | + | similarly named type parameter `T` defined here + +error[E0412]: cannot find type `MISC` in this scope + --> $DIR/issue-78372.rs:3:34 + | +LL | impl DispatchFromDyn> for T {} + | - ^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `, MISC` + +error[E0658]: use of unstable library feature 'dispatch_from_dyn' + --> $DIR/issue-78372.rs:1:5 + | +LL | use std::ops::DispatchFromDyn; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(dispatch_from_dyn)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'dispatch_from_dyn' + --> $DIR/issue-78372.rs:3:9 + | +LL | impl DispatchFromDyn> for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(dispatch_from_dyn)]` to the crate attributes to enable + +error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures + --> $DIR/issue-78372.rs:3:1 + | +LL | impl DispatchFromDyn> for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Smaht<[type error], [type error]>`) + --> $DIR/issue-78372.rs:3:6 + | +LL | impl DispatchFromDyn> for T {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Smaht<[type error], [type error]>`) + | + = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0210, E0378, E0412, E0658. +For more information about an error, try `rustc --explain E0210`. diff --git a/src/test/ui/issues/issue-78622.rs b/src/test/ui/issues/issue-78622.rs new file mode 100644 index 0000000000..c00fd26606 --- /dev/null +++ b/src/test/ui/issues/issue-78622.rs @@ -0,0 +1,7 @@ +#![crate_type = "lib"] + +struct S; +fn f() { + S::A:: {} + //~^ ERROR ambiguous associated type +} diff --git a/src/test/ui/issues/issue-78622.stderr b/src/test/ui/issues/issue-78622.stderr new file mode 100644 index 0000000000..f13073da0a --- /dev/null +++ b/src/test/ui/issues/issue-78622.stderr @@ -0,0 +1,9 @@ +error[E0223]: ambiguous associated type + --> $DIR/issue-78622.rs:5:5 + | +LL | S::A:: {} + | ^^^^^^^^^ help: use fully-qualified syntax: `::A` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0223`. diff --git a/src/test/ui/issues/issue-8460-const.noopt.stderr b/src/test/ui/issues/issue-8460-const.noopt.stderr index eb8d66790c..739b546874 100644 --- a/src/test/ui/issues/issue-8460-const.noopt.stderr +++ b/src/test/ui/issues/issue-8460-const.noopt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:14:36 | LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:16:36 | LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:18:36 | LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:20:36 | LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:22:36 | LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:24:36 | LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:26:36 | LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to divide 1_isize by zero + | ^^^^^^^^^^ attempt to divide `1_isize` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -48,103 +48,103 @@ error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:28:36 | LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - | ^^^^^^^ attempt to divide 1_i8 by zero + | ^^^^^^^ attempt to divide `1_i8` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:30:36 | LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i16 by zero + | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:32:36 | LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:34:36 | LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i64 by zero + | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:36:36 | LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - | ^^^^^^^^^ attempt to divide 1_i128 by zero + | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:38:36 | LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:40:36 | LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:42:36 | LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:44:36 | LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:46:36 | LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:48:36 | LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:50:36 | LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero + | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:52:36 | LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - | ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero + | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:54:36 | LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:56:36 | LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:58:36 | LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:60:36 | LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - | ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero + | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: aborting due to 24 previous errors diff --git a/src/test/ui/issues/issue-8460-const.opt.stderr b/src/test/ui/issues/issue-8460-const.opt.stderr index eb8d66790c..739b546874 100644 --- a/src/test/ui/issues/issue-8460-const.opt.stderr +++ b/src/test/ui/issues/issue-8460-const.opt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:14:36 | LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:16:36 | LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:18:36 | LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:20:36 | LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:22:36 | LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:24:36 | LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:26:36 | LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to divide 1_isize by zero + | ^^^^^^^^^^ attempt to divide `1_isize` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -48,103 +48,103 @@ error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:28:36 | LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - | ^^^^^^^ attempt to divide 1_i8 by zero + | ^^^^^^^ attempt to divide `1_i8` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:30:36 | LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i16 by zero + | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:32:36 | LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:34:36 | LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i64 by zero + | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:36:36 | LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - | ^^^^^^^^^ attempt to divide 1_i128 by zero + | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:38:36 | LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:40:36 | LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:42:36 | LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:44:36 | LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:46:36 | LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:48:36 | LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:50:36 | LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero + | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:52:36 | LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - | ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero + | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:54:36 | LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:56:36 | LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:58:36 | LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:60:36 | LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - | ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero + | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: aborting due to 24 previous errors diff --git a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr index eb8d66790c..739b546874 100644 --- a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr +++ b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:14:36 | LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:16:36 | LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:18:36 | LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:20:36 | LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:22:36 | LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:24:36 | LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:26:36 | LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to divide 1_isize by zero + | ^^^^^^^^^^ attempt to divide `1_isize` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -48,103 +48,103 @@ error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:28:36 | LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - | ^^^^^^^ attempt to divide 1_i8 by zero + | ^^^^^^^ attempt to divide `1_i8` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:30:36 | LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i16 by zero + | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:32:36 | LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:34:36 | LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i64 by zero + | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:36:36 | LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - | ^^^^^^^^^ attempt to divide 1_i128 by zero + | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:38:36 | LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:40:36 | LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:42:36 | LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:44:36 | LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:46:36 | LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:48:36 | LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:50:36 | LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero + | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:52:36 | LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - | ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero + | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:54:36 | LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:56:36 | LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:58:36 | LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:60:36 | LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - | ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero + | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: aborting due to 24 previous errors diff --git a/src/test/ui/issues/issue-8727.rs b/src/test/ui/issues/issue-8727.rs index 14bdd85111..a9b8126618 100644 --- a/src/test/ui/issues/issue-8727.rs +++ b/src/test/ui/issues/issue-8727.rs @@ -2,11 +2,12 @@ // recursions. // build-fail +// normalize-stderr-test: ".nll/" -> "/" fn generic() { //~ WARN function cannot return without recursing generic::>(); } -//~^^ ERROR reached the recursion limit while instantiating `generic:: $DIR/issue-8727.rs:6:1 + --> $DIR/issue-8727.rs:7:1 | LL | fn generic() { | ^^^^^^^^^^^^^^^ cannot return without recursing @@ -9,17 +9,18 @@ LL | generic::>(); = note: `#[warn(unconditional_recursion)]` on by default = help: a `loop` may express intention better if this is on purpose -error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-8727.rs:7:5 +error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + --> $DIR/issue-8727.rs:8:5 | LL | generic::>(); | ^^^^^^^^^^^^^^^^^^^^^^ | note: `generic` defined here - --> $DIR/issue-8727.rs:6:1 + --> $DIR/issue-8727.rs:7:1 | LL | fn generic() { | ^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-8727/issue-8727.long-type.txt' error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/iterators/array-of-ranges.stderr b/src/test/ui/iterators/array-of-ranges.stderr index 3dbed9a106..6271d8107b 100644 --- a/src/test/ui/iterators/array-of-ranges.stderr +++ b/src/test/ui/iterators/array-of-ranges.stderr @@ -4,49 +4,49 @@ error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator LL | for _ in [0..1] {} | ^^^^^^ if you meant to iterate between two values, remove the square brackets | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` + = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeInclusive<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:4:14 | LL | for _ in [0..=1] {} - | ^^^^^^^ if you meant to iterate between two values, remove the square brackets + | ^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeInclusive<{integer}>; 1]` - = note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeFrom<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeFrom<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:6:14 | LL | for _ in [0..] {} - | ^^^^^ if you meant to iterate from a value onwards, remove the square brackets + | ^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeFrom<{integer}>; 1]` - = note: `[start..]` is an array of one `RangeFrom`; you might have meant to have a `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an unbounded iterator will run forever unless you `break` or `return` from within the loop - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeFrom<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeTo<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeTo<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:8:14 | LL | for _ in [..1] {} - | ^^^^^ if you meant to iterate until a value, remove the square brackets and add a starting value + | ^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeTo<{integer}>; 1]` - = note: `[..end]` is an array of one `RangeTo`; you might have meant to have a bounded `Range` without the brackets: `0..end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeTo<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeToInclusive<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeToInclusive<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:10:14 | LL | for _ in [..=1] {} - | ^^^^^^ if you meant to iterate until a value (including it), remove the square brackets and add a starting value + | ^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeToInclusive<{integer}>; 1]` - = note: `[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a bounded `RangeInclusive` without the brackets: `0..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeToInclusive<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:14:14 @@ -54,9 +54,9 @@ error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator LL | for _ in [start..end] {} | ^^^^^^^^^^^^ if you meant to iterate between two values, remove the square brackets | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` + = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:17:14 @@ -64,9 +64,9 @@ error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator LL | for _ in array_of_range {} | ^^^^^^^^^^^^^^ if you meant to iterate between two values, remove the square brackets | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` + = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `[std::ops::Range<{integer}>; 2]` is not an iterator --> $DIR/array-of-ranges.rs:19:14 @@ -74,19 +74,19 @@ error[E0277]: `[std::ops::Range<{integer}>; 2]` is not an iterator LL | for _ in [0..1, 2..3] {} | ^^^^^^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 2]` + = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 2]` = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeInclusive<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:21:14 | LL | for _ in [0..=1] {} - | ^^^^^^^ if you meant to iterate between two values, remove the square brackets + | ^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeInclusive<{integer}>; 1]` - = note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` error: aborting due to 9 previous errors diff --git a/src/test/ui/iterators/array.stderr b/src/test/ui/iterators/array.stderr index 94731f1c74..f86c82e491 100644 --- a/src/test/ui/iterators/array.stderr +++ b/src/test/ui/iterators/array.stderr @@ -4,9 +4,9 @@ error[E0277]: `[{integer}; 2]` is not an iterator LL | for _ in [1, 2] {} | ^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 2]` + = help: the trait `Iterator` is not implemented for `[{integer}; 2]` = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `[{integer}; 2]` is not an iterator --> $DIR/array.rs:5:14 @@ -14,9 +14,9 @@ error[E0277]: `[{integer}; 2]` is not an iterator LL | for _ in x {} | ^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 2]` + = help: the trait `Iterator` is not implemented for `[{integer}; 2]` = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `[{float}; 2]` is not an iterator --> $DIR/array.rs:7:14 @@ -24,9 +24,9 @@ error[E0277]: `[{float}; 2]` is not an iterator LL | for _ in [1.0, 2.0] {} | ^^^^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[{float}; 2]` + = help: the trait `Iterator` is not implemented for `[{float}; 2]` = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error: aborting due to 3 previous errors diff --git a/src/test/ui/iterators/bound.stderr b/src/test/ui/iterators/bound.stderr index 1a5aad6c36..eaf2e66d0f 100644 --- a/src/test/ui/iterators/bound.stderr +++ b/src/test/ui/iterators/bound.stderr @@ -6,7 +6,7 @@ LL | struct S(I); LL | struct T(S); | ^^^^^ `u8` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u8` + = help: the trait `Iterator` is not implemented for `u8` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` error: aborting due to previous error diff --git a/src/test/ui/iterators/integral.stderr b/src/test/ui/iterators/integral.stderr index 71e1e81e5a..c4c4641261 100644 --- a/src/test/ui/iterators/integral.stderr +++ b/src/test/ui/iterators/integral.stderr @@ -4,9 +4,9 @@ error[E0277]: `{integer}` is not an iterator LL | for _ in 42 {} | ^^ `{integer}` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `{integer}` + = help: the trait `Iterator` is not implemented for `{integer}` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `u8` is not an iterator --> $DIR/integral.rs:4:14 @@ -14,9 +14,9 @@ error[E0277]: `u8` is not an iterator LL | for _ in 42 as u8 {} | ^^^^^^^^ `u8` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u8` + = help: the trait `Iterator` is not implemented for `u8` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `i8` is not an iterator --> $DIR/integral.rs:6:14 @@ -24,9 +24,9 @@ error[E0277]: `i8` is not an iterator LL | for _ in 42 as i8 {} | ^^^^^^^^ `i8` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i8` + = help: the trait `Iterator` is not implemented for `i8` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `u16` is not an iterator --> $DIR/integral.rs:8:14 @@ -34,9 +34,9 @@ error[E0277]: `u16` is not an iterator LL | for _ in 42 as u16 {} | ^^^^^^^^^ `u16` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u16` + = help: the trait `Iterator` is not implemented for `u16` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `i16` is not an iterator --> $DIR/integral.rs:10:14 @@ -44,9 +44,9 @@ error[E0277]: `i16` is not an iterator LL | for _ in 42 as i16 {} | ^^^^^^^^^ `i16` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i16` + = help: the trait `Iterator` is not implemented for `i16` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `u32` is not an iterator --> $DIR/integral.rs:12:14 @@ -54,9 +54,9 @@ error[E0277]: `u32` is not an iterator LL | for _ in 42 as u32 {} | ^^^^^^^^^ `u32` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u32` + = help: the trait `Iterator` is not implemented for `u32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `i32` is not an iterator --> $DIR/integral.rs:14:14 @@ -64,9 +64,9 @@ error[E0277]: `i32` is not an iterator LL | for _ in 42 as i32 {} | ^^^^^^^^^ `i32` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i32` + = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `u64` is not an iterator --> $DIR/integral.rs:16:14 @@ -74,9 +74,9 @@ error[E0277]: `u64` is not an iterator LL | for _ in 42 as u64 {} | ^^^^^^^^^ `u64` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u64` + = help: the trait `Iterator` is not implemented for `u64` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `i64` is not an iterator --> $DIR/integral.rs:18:14 @@ -84,9 +84,9 @@ error[E0277]: `i64` is not an iterator LL | for _ in 42 as i64 {} | ^^^^^^^^^ `i64` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i64` + = help: the trait `Iterator` is not implemented for `i64` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `usize` is not an iterator --> $DIR/integral.rs:20:14 @@ -94,9 +94,9 @@ error[E0277]: `usize` is not an iterator LL | for _ in 42 as usize {} | ^^^^^^^^^^^ `usize` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `usize` + = help: the trait `Iterator` is not implemented for `usize` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `isize` is not an iterator --> $DIR/integral.rs:22:14 @@ -104,9 +104,9 @@ error[E0277]: `isize` is not an iterator LL | for _ in 42 as isize {} | ^^^^^^^^^^^ `isize` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `isize` + = help: the trait `Iterator` is not implemented for `isize` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `{float}` is not an iterator --> $DIR/integral.rs:24:14 @@ -114,8 +114,8 @@ error[E0277]: `{float}` is not an iterator LL | for _ in 42.0 {} | ^^^^ `{float}` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `{float}` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `{float}` + = note: required by `into_iter` error: aborting due to 12 previous errors diff --git a/src/test/ui/iterators/issue-58952-filter-type-length.rs b/src/test/ui/iterators/issue-58952-filter-type-length.rs index 046e378408..ffbe89a14e 100644 --- a/src/test/ui/iterators/issue-58952-filter-type-length.rs +++ b/src/test/ui/iterators/issue-58952-filter-type-length.rs @@ -3,6 +3,7 @@ //! so check that we don't accidentially exceed the type length limit. // FIXME: Once the size of iterator adaptors is further reduced, // increase the complexity of this test. +use std::collections::VecDeque; fn main() { let c = 2; @@ -27,5 +28,5 @@ fn main() { .filter(|a| b.clone().any(|b| *b == *a)) .filter(|a| b.clone().any(|b| *b == *a)) .filter(|a| b.clone().any(|b| *b == *a)) - .collect::>(); + .collect::>(); } diff --git a/src/test/ui/iterators/iter-zip.rs b/src/test/ui/iterators/iter-zip.rs deleted file mode 100644 index a76fa2408b..0000000000 --- a/src/test/ui/iterators/iter-zip.rs +++ /dev/null @@ -1,103 +0,0 @@ -// run-pass -// Test that .zip() specialization preserves side effects -// in sideeffectful iterator adaptors. - -use std::cell::Cell; - -#[derive(Debug)] -struct CountClone(Cell); - -fn count_clone() -> CountClone { CountClone(Cell::new(0)) } - -impl PartialEq for CountClone { - fn eq(&self, rhs: &i32) -> bool { - self.0.get() == *rhs - } -} - -impl Clone for CountClone { - fn clone(&self) -> Self { - let ret = CountClone(self.0.clone()); - let n = self.0.get(); - self.0.set(n + 1); - ret - } -} - -fn test_zip_cloned_sideffectful() { - let xs = [count_clone(), count_clone(), count_clone(), count_clone()]; - let ys = [count_clone(), count_clone()]; - - for _ in xs.iter().cloned().zip(ys.iter().cloned()) { } - - assert_eq!(&xs, &[1, 1, 1, 0][..]); - assert_eq!(&ys, &[1, 1][..]); - - let xs = [count_clone(), count_clone()]; - let ys = [count_clone(), count_clone(), count_clone(), count_clone()]; - - for _ in xs.iter().cloned().zip(ys.iter().cloned()) { } - - assert_eq!(&xs, &[1, 1][..]); - assert_eq!(&ys, &[1, 1, 0, 0][..]); -} - -fn test_zip_map_sideffectful() { - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { } - - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); - assert_eq!(&ys, &[1, 1, 1, 1]); - - let mut xs = [0; 4]; - let mut ys = [0; 6]; - - for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { } - - assert_eq!(&xs, &[1, 1, 1, 1]); - assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); -} - -fn test_zip_map_rev_sideffectful() { - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - { - let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - it.next_back(); - } - assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); - assert_eq!(&ys, &[0, 0, 0, 1]); - - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - { - let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - (&mut it).take(5).count(); - it.next_back(); - } - assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); - assert_eq!(&ys, &[1, 1, 1, 1]); -} - -fn test_zip_nested_sideffectful() { - let mut xs = [0; 6]; - let ys = [0; 4]; - - { - // test that it has the side effect nested inside enumerate - let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); - it.count(); - } - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); -} - -fn main() { - test_zip_cloned_sideffectful(); - test_zip_map_sideffectful(); - test_zip_map_rev_sideffectful(); - test_zip_nested_sideffectful(); -} diff --git a/src/test/ui/iterators/ranges.stderr b/src/test/ui/iterators/ranges.stderr index e5e2d87879..0324d5f1a9 100644 --- a/src/test/ui/iterators/ranges.stderr +++ b/src/test/ui/iterators/ranges.stderr @@ -1,22 +1,20 @@ -error[E0277]: `std::ops::RangeTo<{integer}>` is not an iterator +error[E0277]: `RangeTo<{integer}>` is not an iterator --> $DIR/ranges.rs:2:14 | LL | for _ in ..10 {} - | ^^^^ if you meant to iterate until a value, add a starting value + | ^^^^ `RangeTo<{integer}>` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `std::ops::RangeTo<{integer}>` - = note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>` + = note: required by `into_iter` -error[E0277]: `std::ops::RangeToInclusive<{integer}>` is not an iterator +error[E0277]: `RangeToInclusive<{integer}>` is not an iterator --> $DIR/ranges.rs:4:14 | LL | for _ in ..=10 {} - | ^^^^^ if you meant to iterate until a value (including it), add a starting value + | ^^^^^ `RangeToInclusive<{integer}>` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `std::ops::RangeToInclusive<{integer}>` - = note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>` + = note: required by `into_iter` error: aborting due to 2 previous errors diff --git a/src/test/ui/iterators/string.rs b/src/test/ui/iterators/string.rs index 4373dcaabe..ad58a463e9 100644 --- a/src/test/ui/iterators/string.rs +++ b/src/test/ui/iterators/string.rs @@ -1,6 +1,6 @@ fn main() { for _ in "".to_owned() {} - //~^ ERROR `std::string::String` is not an iterator + //~^ ERROR `String` is not an iterator for _ in "" {} //~^ ERROR `&str` is not an iterator } diff --git a/src/test/ui/iterators/string.stderr b/src/test/ui/iterators/string.stderr index 927de952cc..fecdbd1785 100644 --- a/src/test/ui/iterators/string.stderr +++ b/src/test/ui/iterators/string.stderr @@ -1,11 +1,11 @@ -error[E0277]: `std::string::String` is not an iterator +error[E0277]: `String` is not an iterator --> $DIR/string.rs:2:14 | LL | for _ in "".to_owned() {} - | ^^^^^^^^^^^^^ `std::string::String` is not an iterator; try calling `.chars()` or `.bytes()` + | ^^^^^^^^^^^^^ `String` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `std::string::String` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `String` + = note: required by `into_iter` error[E0277]: `&str` is not an iterator --> $DIR/string.rs:4:14 @@ -13,8 +13,8 @@ error[E0277]: `&str` is not an iterator LL | for _ in "" {} | ^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `std::iter::Iterator` is not implemented for `&str` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&str` + = note: required by `into_iter` error: aborting due to 2 previous errors diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json-bom-plus-crlf-multifile.stderr index 8d3c316e46..b222334eda 100644 --- a/src/test/ui/json-bom-plus-crlf-multifile.stderr +++ b/src/test/ui/json-bom-plus-crlf-multifile.stderr @@ -16,7 +16,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -36,7 +36,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -56,7 +56,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -76,7 +76,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors "} diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json-bom-plus-crlf.stderr index ed6b583f32..6041366dbd 100644 --- a/src/test/ui/json-bom-plus-crlf.stderr +++ b/src/test/ui/json-bom-plus-crlf.stderr @@ -16,7 +16,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -36,7 +36,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -56,7 +56,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -76,7 +76,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors "} diff --git a/src/test/ui/kindck/kindck-copy.rs b/src/test/ui/kindck/kindck-copy.rs index eb18613682..6df98c230e 100644 --- a/src/test/ui/kindck/kindck-copy.rs +++ b/src/test/ui/kindck/kindck-copy.rs @@ -24,14 +24,14 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::<&'a [isize]>(); // ...unless they are mutable - assert_copy::<&'static mut isize>(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::<&'a mut isize>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::<&'static mut isize>(); //~ ERROR : Copy` is not satisfied + assert_copy::<&'a mut isize>(); //~ ERROR : Copy` is not satisfied // boxes are not ok - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy:: >(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied + assert_copy::(); //~ ERROR : Copy` is not satisfied + assert_copy:: >(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied // borrowed object types are generally ok assert_copy::<&'a dyn Dummy>(); @@ -39,11 +39,11 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::<&'static (dyn Dummy + Send)>(); // owned object types are not ok - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied // mutable object types are not ok - assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : Copy` is not satisfied // unsafe ptrs are ok assert_copy::<*const isize>(); @@ -61,10 +61,10 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::(); // structs containing non-POD are not ok - assert_copy::(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::(); //~ ERROR : Copy` is not satisfied // ref counted types are not ok - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied } pub fn main() { diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr index 5a7cd458e5..1194304573 100644 --- a/src/test/ui/kindck/kindck-copy.stderr +++ b/src/test/ui/kindck/kindck-copy.stderr @@ -1,107 +1,107 @@ -error[E0277]: the trait bound `&'static mut isize: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied --> $DIR/kindck-copy.rs:27:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::<&'static mut isize>(); - | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'static mut isize` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize` | = help: the following implementations were found: - + -error[E0277]: the trait bound `&'a mut isize: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied --> $DIR/kindck-copy.rs:28:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::<&'a mut isize>(); - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'a mut isize` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize` | = help: the following implementations were found: - + -error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Box: Copy` is not satisfied --> $DIR/kindck-copy.rs:31:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` + | ^^^^^^^^^^ the trait `Copy` is not implemented for `Box` -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/kindck-copy.rs:32:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::(); - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^^^^^^ the trait `Copy` is not implemented for `String` -error[E0277]: the trait bound `std::vec::Vec: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Vec: Copy` is not satisfied --> $DIR/kindck-copy.rs:33:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy:: >(); - | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::vec::Vec` + | ^^^^^^^^^^ the trait `Copy` is not implemented for `Vec` -error[E0277]: the trait bound `std::boxed::Box<&'a mut isize>: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Box<&'a mut isize>: Copy` is not satisfied --> $DIR/kindck-copy.rs:34:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<&'a mut isize>` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<&'a mut isize>` -error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Box: Copy` is not satisfied --> $DIR/kindck-copy.rs:42:5 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` -error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Box: Copy` is not satisfied --> $DIR/kindck-copy.rs:43:5 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` -error[E0277]: the trait bound `&'a mut (dyn Dummy + std::marker::Send + 'a): std::marker::Copy` is not satisfied +error[E0277]: the trait bound `&'a mut (dyn Dummy + Send + 'a): Copy` is not satisfied --> $DIR/kindck-copy.rs:46:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::<&'a mut (dyn Dummy + Send)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'a mut (dyn Dummy + std::marker::Send + 'a)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut (dyn Dummy + Send + 'a)` -error[E0277]: the trait bound `MyNoncopyStruct: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `MyNoncopyStruct: Copy` is not satisfied --> $DIR/kindck-copy.rs:64:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::(); - | ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `MyNoncopyStruct` + | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `MyNoncopyStruct` -error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Rc: Copy` is not satisfied --> $DIR/kindck-copy.rs:67:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` + | ^^^^^^^^^ the trait `Copy` is not implemented for `Rc` error: aborting due to 11 previous errors diff --git a/src/test/ui/kindck/kindck-impl-type-params-2.rs b/src/test/ui/kindck/kindck-impl-type-params-2.rs index d5fcc68a75..c08f776dbf 100644 --- a/src/test/ui/kindck/kindck-impl-type-params-2.rs +++ b/src/test/ui/kindck/kindck-impl-type-params-2.rs @@ -11,5 +11,5 @@ fn take_param(foo: &T) { } fn main() { let x: Box<_> = box 3; take_param(&x); - //~^ ERROR the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied + //~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied } diff --git a/src/test/ui/kindck/kindck-impl-type-params-2.stderr b/src/test/ui/kindck/kindck-impl-type-params-2.stderr index 984960efae..7e0f6e0b2d 100644 --- a/src/test/ui/kindck/kindck-impl-type-params-2.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params-2.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied +error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied --> $DIR/kindck-impl-type-params-2.rs:13:16 | LL | fn take_param(foo: &T) { } | --- required by this bound in `take_param` ... LL | take_param(&x); - | ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` + | ^^ the trait `Copy` is not implemented for `Box<{integer}>` | - = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` + = note: required because of the requirements on the impl of `Foo` for `Box<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr index eb400cf061..b01b8258e7 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr @@ -8,21 +8,21 @@ LL | let a = &t as &dyn Gettable; = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn f(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn f(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; - | ^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn f(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn f(val: T) { + | ^^^^^^ error[E0277]: `T` cannot be sent between threads safely --> $DIR/kindck-impl-type-params.rs:25:31 @@ -34,39 +34,39 @@ LL | let a: &dyn Gettable = &t; = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn g(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; - | ^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn g(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:38:13 | LL | let a = t as Box>; - | ^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^ the trait `Copy` is not implemented for `String` | - = note: required because of the requirements on the impl of `Gettable` for `S` - = note: required for the cast to the object type `dyn Gettable` + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` -error[E0277]: the trait bound `foo3::Foo: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:46:37 | LL | let a: Box> = t; - | ^ the trait `std::marker::Copy` is not implemented for `foo3::Foo` + | ^ the trait `Copy` is not implemented for `Foo` | - = note: required because of the requirements on the impl of `Gettable` for `S` - = note: required for the cast to the object type `dyn Gettable` + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` error: aborting due to 6 previous errors diff --git a/src/test/ui/kindck/kindck-impl-type-params.rs b/src/test/ui/kindck/kindck-impl-type-params.rs index c4f90f36ac..4d4d191b6a 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.rs +++ b/src/test/ui/kindck/kindck-impl-type-params.rs @@ -17,14 +17,14 @@ fn f(val: T) { let t: S = S(marker::PhantomData); let a = &t as &dyn Gettable; //~^ ERROR `T` cannot be sent between threads safely - //~| ERROR : std::marker::Copy` is not satisfied + //~| ERROR : Copy` is not satisfied } fn g(val: T) { let t: S = S(marker::PhantomData); let a: &dyn Gettable = &t; //~^ ERROR `T` cannot be sent between threads safely - //~| ERROR : std::marker::Copy` is not satisfied + //~| ERROR : Copy` is not satisfied } fn foo<'a>() { @@ -36,7 +36,7 @@ fn foo<'a>() { fn foo2<'a>() { let t: Box> = box S(marker::PhantomData); let a = t as Box>; - //~^ ERROR : std::marker::Copy` is not satisfied + //~^ ERROR : Copy` is not satisfied } fn foo3<'a>() { @@ -44,7 +44,7 @@ fn foo3<'a>() { let t: Box> = box S(marker::PhantomData); let a: Box> = t; - //~^ ERROR : std::marker::Copy` is not satisfied + //~^ ERROR : Copy` is not satisfied } fn main() { } diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr index ab9dfc9b8a..ddf8adf363 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.stderr @@ -8,21 +8,21 @@ LL | let a = &t as &dyn Gettable; = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn f(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn f(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; - | ^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn f(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn f(val: T) { + | ^^^^^^ error[E0277]: `T` cannot be sent between threads safely --> $DIR/kindck-impl-type-params.rs:25:31 @@ -34,21 +34,21 @@ LL | let a: &dyn Gettable = &t; = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn g(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; - | ^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn g(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(val: T) { + | ^^^^^^ error[E0477]: the type `&'a isize` does not fulfill the required lifetime --> $DIR/kindck-impl-type-params.rs:32:13 @@ -58,23 +58,23 @@ LL | let a = &t as &dyn Gettable<&'a isize>; | = note: type must satisfy the static lifetime -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:38:13 | LL | let a = t as Box>; - | ^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^ the trait `Copy` is not implemented for `String` | - = note: required because of the requirements on the impl of `Gettable` for `S` - = note: required for the cast to the object type `dyn Gettable` + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` -error[E0277]: the trait bound `foo3::Foo: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:46:37 | LL | let a: Box> = t; - | ^ the trait `std::marker::Copy` is not implemented for `foo3::Foo` + | ^ the trait `Copy` is not implemented for `Foo` | - = note: required because of the requirements on the impl of `Gettable` for `S` - = note: required for the cast to the object type `dyn Gettable` + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` error: aborting due to 7 previous errors diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr index 7df98366ed..a6fd44d174 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied +error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | fn take_param(foo: &T) { } | --- required by this bound in `take_param` ... LL | take_param(&x); - | ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` + | ^^ the trait `Copy` is not implemented for `Box<{integer}>` | - = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` + = note: required because of the requirements on the impl of `Foo` for `Box<{integer}>` error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:19 @@ -31,7 +31,7 @@ LL | trait Foo : Copy { LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<{integer}>` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Foo>` for `&Box<{integer}>` = note: required by cast to type `&dyn Foo` error: aborting due to 3 previous errors diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr index 6b511e0a6e..bc7448a05e 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied +error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | fn take_param(foo: &T) { } | --- required by this bound in `take_param` ... LL | take_param(&x); - | ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` + | ^^ the trait `Copy` is not implemented for `Box<{integer}>` | - = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` + = note: required because of the requirements on the impl of `Foo` for `Box<{integer}>` error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:13 @@ -20,7 +20,7 @@ LL | trait Foo : Copy { LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Foo>` for `&Box` = note: required by cast to type `&dyn Foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-nonsendable-1.rs b/src/test/ui/kindck/kindck-nonsendable-1.rs index eaff5b1b99..b32fd78624 100644 --- a/src/test/ui/kindck/kindck-nonsendable-1.rs +++ b/src/test/ui/kindck/kindck-nonsendable-1.rs @@ -7,5 +7,5 @@ fn bar(_: F) { } fn main() { let x = Rc::new(3); bar(move|| foo(x)); - //~^ ERROR `std::rc::Rc` cannot be sent between threads safely + //~^ ERROR `Rc` cannot be sent between threads safely } diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr index c7f9058dd7..c7d67a991b 100644 --- a/src/test/ui/kindck/kindck-nonsendable-1.stderr +++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr @@ -1,16 +1,16 @@ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/kindck-nonsendable-1.rs:9:5 | LL | fn bar(_: F) { } | ---- required by this bound in `bar` ... LL | bar(move|| foo(x)); - | ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]` + | ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]` | | - | `std::rc::Rc` cannot be sent between threads safely + | `Rc` cannot be sent between threads safely | - = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` - = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]` + = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`, the trait `Send` is not implemented for `Rc` + = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]` error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-send-object.stderr b/src/test/ui/kindck/kindck-send-object.stderr index a59a375c6c..0df7df8537 100644 --- a/src/test/ui/kindck/kindck-send-object.stderr +++ b/src/test/ui/kindck/kindck-send-object.stderr @@ -7,8 +7,8 @@ LL | fn assert_send() { } LL | assert_send::<&'static (dyn Dummy + 'static)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'static)` - = note: required because of the requirements on the impl of `std::marker::Send` for `&'static (dyn Dummy + 'static)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = note: required because of the requirements on the impl of `Send` for `&'static (dyn Dummy + 'static)` error[E0277]: `dyn Dummy` cannot be sent between threads safely --> $DIR/kindck-send-object.rs:17:5 @@ -19,9 +19,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dyn Dummy` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` - = note: required because it appears within the type `std::boxed::Box` + = help: the trait `Send` is not implemented for `dyn Dummy` + = note: required because of the requirements on the impl of `Send` for `Unique` + = note: required because it appears within the type `Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-send-object1.nll.stderr b/src/test/ui/kindck/kindck-send-object1.nll.stderr index 14a6f554f6..4792914d95 100644 --- a/src/test/ui/kindck/kindck-send-object1.nll.stderr +++ b/src/test/ui/kindck/kindck-send-object1.nll.stderr @@ -7,8 +7,8 @@ LL | fn assert_send() { } LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'a)` - = note: required because of the requirements on the impl of `std::marker::Send` for `&'a (dyn Dummy + 'a)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `Send` for `&'a (dyn Dummy + 'a)` error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely --> $DIR/kindck-send-object1.rs:29:5 @@ -19,9 +19,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `(dyn Dummy + 'a)` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn Dummy + 'a)>` - = note: required because it appears within the type `std::boxed::Box<(dyn Dummy + 'a)>` + = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `Send` for `Unique<(dyn Dummy + 'a)>` + = note: required because it appears within the type `Box<(dyn Dummy + 'a)>` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-send-object1.stderr b/src/test/ui/kindck/kindck-send-object1.stderr index b6d82e3195..aa72fda367 100644 --- a/src/test/ui/kindck/kindck-send-object1.stderr +++ b/src/test/ui/kindck/kindck-send-object1.stderr @@ -7,10 +7,10 @@ LL | fn assert_send() { } LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'a)` - = note: required because of the requirements on the impl of `std::marker::Send` for `&'a (dyn Dummy + 'a)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `Send` for `&'a (dyn Dummy + 'a)` -error[E0477]: the type `&'a (dyn Dummy + std::marker::Sync + 'a)` does not fulfill the required lifetime +error[E0477]: the type `&'a (dyn Dummy + Sync + 'a)` does not fulfill the required lifetime --> $DIR/kindck-send-object1.rs:14:5 | LL | assert_send::<&'a (dyn Dummy + Sync)>(); @@ -27,9 +27,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `(dyn Dummy + 'a)` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn Dummy + 'a)>` - = note: required because it appears within the type `std::boxed::Box<(dyn Dummy + 'a)>` + = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `Send` for `Unique<(dyn Dummy + 'a)>` + = note: required because it appears within the type `Box<(dyn Dummy + 'a)>` error: aborting due to 3 previous errors diff --git a/src/test/ui/kindck/kindck-send-object2.stderr b/src/test/ui/kindck/kindck-send-object2.stderr index e6daf987c8..f7fb32ac04 100644 --- a/src/test/ui/kindck/kindck-send-object2.stderr +++ b/src/test/ui/kindck/kindck-send-object2.stderr @@ -7,8 +7,8 @@ LL | fn assert_send() { } LL | assert_send::<&'static dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'static)` - = note: required because of the requirements on the impl of `std::marker::Send` for `&'static (dyn Dummy + 'static)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = note: required because of the requirements on the impl of `Send` for `&'static (dyn Dummy + 'static)` error[E0277]: `dyn Dummy` cannot be sent between threads safely --> $DIR/kindck-send-object2.rs:12:5 @@ -19,9 +19,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dyn Dummy` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` - = note: required because it appears within the type `std::boxed::Box` + = help: the trait `Send` is not implemented for `dyn Dummy` + = note: required because of the requirements on the impl of `Send` for `Unique` + = note: required because it appears within the type `Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-send-owned.stderr b/src/test/ui/kindck/kindck-send-owned.stderr index 2c6c2c6267..d6664ec24f 100644 --- a/src/test/ui/kindck/kindck-send-owned.stderr +++ b/src/test/ui/kindck/kindck-send-owned.stderr @@ -7,9 +7,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `*mut u8` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<*mut u8>` - = note: required because it appears within the type `std::boxed::Box<*mut u8>` + = help: the trait `Send` is not implemented for `*mut u8` + = note: required because of the requirements on the impl of `Send` for `Unique<*mut u8>` + = note: required because it appears within the type `Box<*mut u8>` error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-send-unsafe.stderr b/src/test/ui/kindck/kindck-send-unsafe.stderr index 34f9821819..069e8dc67f 100644 --- a/src/test/ui/kindck/kindck-send-unsafe.stderr +++ b/src/test/ui/kindck/kindck-send-unsafe.stderr @@ -7,7 +7,7 @@ LL | fn assert_send() { } LL | assert_send::<*mut &'a isize>(); | ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `*mut &'a isize` + = help: the trait `Send` is not implemented for `*mut &'a isize` error: aborting due to previous error diff --git a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr index 98bf992382..5a6c86d133 100644 --- a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr +++ b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr @@ -5,7 +5,7 @@ LL | pub const fn sof() -> usize { | - required by this bound in `sof` ... LL | fn test() { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let _: [u8; sof::()]; | ^ doesn't have a size known at compile-time | diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.rs b/src/test/ui/lazy_normalization_consts/issue-73980.rs index 339b22c0b4..e10040652c 100644 --- a/src/test/ui/lazy_normalization_consts/issue-73980.rs +++ b/src/test/ui/lazy_normalization_consts/issue-73980.rs @@ -10,5 +10,7 @@ impl L { } impl X::S]> {} +//~^ WARN cannot use constants which depend on generic parameters +//~| WARN this was previously accepted by the compiler but is being phased out fn main() {} diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.stderr b/src/test/ui/lazy_normalization_consts/issue-73980.stderr new file mode 100644 index 0000000000..5ed1ca362f --- /dev/null +++ b/src/test/ui/lazy_normalization_consts/issue-73980.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/issue-73980.rs:12:9 + | +LL | impl X::S]> {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + +warning: 1 warning emitted + diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr index 93160a1c5e..91cdc0205d 100644 --- a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr +++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | ref_obj(x) | ^ lifetime mismatch | - = note: expected reference `&std::boxed::Box<(dyn std::ops::Fn() + 'static)>` - found reference `&std::boxed::Box<(dyn std::ops::Fn() + 'a)>` + = note: expected reference `&Box<(dyn Fn() + 'static)>` + found reference `&Box<(dyn Fn() + 'a)>` note: the lifetime `'a` as defined on the function body at 32:10... --> $DIR/lifetime-bound-will-change-warning.rs:32:10 | @@ -19,8 +19,8 @@ error[E0308]: mismatched types LL | lib::ref_obj(x) | ^ lifetime mismatch | - = note: expected reference `&std::boxed::Box<(dyn std::ops::Fn() + 'static)>` - found reference `&std::boxed::Box<(dyn std::ops::Fn() + 'a)>` + = note: expected reference `&Box<(dyn Fn() + 'static)>` + found reference `&Box<(dyn Fn() + 'a)>` note: the lifetime `'a` as defined on the function body at 37:12... --> $DIR/lifetime-bound-will-change-warning.rs:37:12 | diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr index 735f7a0dfc..1622ce4229 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn foo(x: &mut Vec>, y: Ref) { | - - has type `Ref<'1, i32>` | | - | has type `&mut std::vec::Vec>` + | has type `&mut Vec>` LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr index f9c33c2480..9630729d0e 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn foo(mut x: Vec, y: Ref) { | ----- - has type `Ref<'1>` | | - | has type `std::vec::Vec>` + | has type `Vec>` LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs index d6ac7ccccc..41f0baecf2 100644 --- a/src/test/ui/lint/clashing-extern-fn.rs +++ b/src/test/ui/lint/clashing-extern-fn.rs @@ -182,7 +182,9 @@ mod same_sized_members_clash { y: f32, z: f32, } - extern "C" { fn origin() -> Point3; } + extern "C" { + fn origin() -> Point3; + } } mod b { #[repr(C)] @@ -191,8 +193,9 @@ mod same_sized_members_clash { y: i32, z: i32, // NOTE: Incorrectly redeclared as i32 } - extern "C" { fn origin() -> Point3; } - //~^ WARN `origin` redeclared with a different signature + extern "C" { + fn origin() -> Point3; //~ WARN `origin` redeclared with a different signature + } } } @@ -258,6 +261,78 @@ mod non_zero_and_non_null { } } +// See #75739 +mod non_zero_transparent { + mod a1 { + use std::num::NonZeroUsize; + extern "C" { + fn f1() -> NonZeroUsize; + } + } + + mod b1 { + #[repr(transparent)] + struct X(NonZeroUsize); + use std::num::NonZeroUsize; + extern "C" { + fn f1() -> X; + } + } + + mod a2 { + use std::num::NonZeroUsize; + extern "C" { + fn f2() -> NonZeroUsize; + } + } + + mod b2 { + #[repr(transparent)] + struct X1(NonZeroUsize); + + #[repr(transparent)] + struct X(X1); + + use std::num::NonZeroUsize; + extern "C" { + // Same case as above, but with two layers of newtyping. + fn f2() -> X; + } + } + + mod a3 { + #[repr(transparent)] + struct X(core::ptr::NonNull); + + use std::num::NonZeroUsize; + extern "C" { + fn f3() -> X; + } + } + + mod b3 { + extern "C" { + fn f3() -> core::ptr::NonNull; + } + } + + mod a4 { + #[repr(transparent)] + enum E { + X(std::num::NonZeroUsize), + } + extern "C" { + fn f4() -> E; + } + } + + mod b4 { + extern "C" { + fn f4() -> std::num::NonZeroUsize; + } + } +} + mod null_optimised_enums { mod a { extern "C" { @@ -285,3 +360,26 @@ mod null_optimised_enums { } } } + +#[allow(improper_ctypes)] +mod unknown_layout { + mod a { + extern "C" { + pub fn generic(l: Link); + } + pub struct Link { + pub item: T, + pub next: *const Link, + } + } + + mod b { + extern "C" { + pub fn generic(l: Link); + } + pub struct Link { + pub item: T, + pub next: *const Link, + } + } +} diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr index cca0c4c59e..a48b0d008f 100644 --- a/src/test/ui/lint/clashing-extern-fn.stderr +++ b/src/test/ui/lint/clashing-extern-fn.stderr @@ -90,8 +90,8 @@ LL | fn weigh_banana(count: *const Banana) -> u64; LL | fn weigh_banana(count: *const Banana) -> u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn(*const banana::one::Banana) -> u64` - found `unsafe extern "C" fn(*const banana::three::Banana) -> u64` + = note: expected `unsafe extern "C" fn(*const one::Banana) -> u64` + found `unsafe extern "C" fn(*const three::Banana) -> u64` warning: `draw_point` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:171:13 @@ -106,19 +106,19 @@ LL | fn draw_point(p: Point); found `unsafe extern "C" fn(sameish_members::b::Point)` warning: `origin` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:194:22 + --> $DIR/clashing-extern-fn.rs:197:13 | -LL | extern "C" { fn origin() -> Point3; } - | ---------------------- `origin` previously declared here +LL | fn origin() -> Point3; + | ---------------------- `origin` previously declared here ... -LL | extern "C" { fn origin() -> Point3; } - | ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration +LL | fn origin() -> Point3; + | ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> same_sized_members_clash::a::Point3` found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` warning: `transparent_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:217:13 + --> $DIR/clashing-extern-fn.rs:220:13 | LL | fn transparent_incorrect() -> T; | -------------------------------- `transparent_incorrect` previously declared here @@ -126,11 +126,11 @@ LL | fn transparent_incorrect() -> T; LL | fn transparent_incorrect() -> isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn() -> transparent::T` + = note: expected `unsafe extern "C" fn() -> T` found `unsafe extern "C" fn() -> isize` warning: `missing_return_type` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:235:13 + --> $DIR/clashing-extern-fn.rs:238:13 | LL | fn missing_return_type() -> usize; | ---------------------------------- `missing_return_type` previously declared here @@ -142,7 +142,7 @@ LL | fn missing_return_type(); found `unsafe extern "C" fn()` warning: `non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:253:13 + --> $DIR/clashing-extern-fn.rs:256:13 | LL | fn non_zero_usize() -> core::num::NonZeroUsize; | ----------------------------------------------- `non_zero_usize` previously declared here @@ -150,11 +150,11 @@ LL | fn non_zero_usize() -> core::num::NonZeroUsize; LL | fn non_zero_usize() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn() -> std::num::NonZeroUsize` + = note: expected `unsafe extern "C" fn() -> NonZeroUsize` found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:255:13 + --> $DIR/clashing-extern-fn.rs:258:13 | LL | fn non_null_ptr() -> core::ptr::NonNull; | ----------------------------------------------- `non_null_ptr` previously declared here @@ -162,11 +162,11 @@ LL | fn non_null_ptr() -> core::ptr::NonNull; LL | fn non_null_ptr() -> *const usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn() -> std::ptr::NonNull` + = note: expected `unsafe extern "C" fn() -> NonNull` found `unsafe extern "C" fn() -> *const usize` warning: `option_non_zero_usize_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:281:13 + --> $DIR/clashing-extern-fn.rs:356:13 | LL | fn option_non_zero_usize_incorrect() -> usize; | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here @@ -178,7 +178,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `option_non_null_ptr_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:283:13 + --> $DIR/clashing-extern-fn.rs:358:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here diff --git a/src/test/ui/lint/dead-code/trait-impl.rs b/src/test/ui/lint/dead-code/trait-impl.rs new file mode 100644 index 0000000000..92e389a938 --- /dev/null +++ b/src/test/ui/lint/dead-code/trait-impl.rs @@ -0,0 +1,19 @@ +// check-pass +#![deny(dead_code)] + +enum Foo { + Bar, +} + +fn main() { + let p = [0; 0]; + p.bar(); +} + +trait Bar { + fn bar(&self) -> usize { + 3 + } +} + +impl Bar for [u32; Foo::Bar as usize] {} diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs new file mode 100644 index 0000000000..c49a13f106 --- /dev/null +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -0,0 +1,53 @@ +// check-pass + +struct MyStruct { + field: bool, + inner_array: [char; 1], + raw_ptr: *mut u8 +} +impl MyStruct { + fn use_mut(&mut self) {} +} + +struct Mutable { + msg: &'static str, +} +impl Drop for Mutable { + fn drop(&mut self) { + println!("{}", self.msg); + } +} + +struct Mutable2 { // this one has drop glue but not a Drop impl + msg: &'static str, + other: String, +} + +const ARRAY: [u8; 1] = [25]; +const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; +const RAW_PTR: *mut u8 = 1 as *mut u8; +const MUTABLE: Mutable = Mutable { msg: "" }; +const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; +const VEC: Vec = Vec::new(); + +fn main() { + ARRAY[0] = 5; //~ WARN attempting to modify + MY_STRUCT.field = false; //~ WARN attempting to modify + MY_STRUCT.inner_array[0] = 'b'; //~ WARN attempting to modify + MY_STRUCT.use_mut(); //~ WARN taking + &mut MY_STRUCT; //~ WARN taking + (&mut MY_STRUCT).use_mut(); //~ WARN taking + + // Test that we don't warn when writing through + // a raw pointer + // This is U.B., but this test is check-pass, + // so this never actually executes + unsafe { + *RAW_PTR = 0; + *MY_STRUCT.raw_ptr = 0; + } + + MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation + MUTABLE2.msg = "wow"; //~ WARN attempting to modify + VEC.push(0); //~ WARN taking a mutable reference to a `const` item +} diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr new file mode 100644 index 0000000000..11b5124b2d --- /dev/null +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -0,0 +1,127 @@ +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:34:5 + | +LL | ARRAY[0] = 5; + | ^^^^^^^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:26:1 + | +LL | const ARRAY: [u8; 1] = [25]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:35:5 + | +LL | MY_STRUCT.field = false; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:36:5 + | +LL | MY_STRUCT.inner_array[0] = 'b'; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:37:5 + | +LL | MY_STRUCT.use_mut(); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: mutable reference created due to call to this method + --> $DIR/lint-const-item-mutation.rs:9:5 + | +LL | fn use_mut(&mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^ +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:38:5 + | +LL | &mut MY_STRUCT; + | ^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:39:5 + | +LL | (&mut MY_STRUCT).use_mut(); + | ^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:51:5 + | +LL | MUTABLE2.msg = "wow"; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:30:1 + | +LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:52:5 + | +LL | VEC.push(0); + | ^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: mutable reference created due to call to this method + --> $SRC_DIR/alloc/src/vec.rs:LL:COL + | +LL | / pub fn push(&mut self, value: T) { +LL | | // This will panic or abort if we would allocate > isize::MAX bytes +LL | | // or if the length increment would overflow for zero-sized types. +LL | | if self.len == self.buf.capacity() { +... | +LL | | } +LL | | } + | |_____^ +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:31:1 + | +LL | const VEC: Vec = Vec::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 8 warnings emitted + diff --git a/src/test/ui/lint/lint-ctypes-enum.rs b/src/test/ui/lint/lint-ctypes-enum.rs index ccda005575..17cb705373 100644 --- a/src/test/ui/lint/lint-ctypes-enum.rs +++ b/src/test/ui/lint/lint-ctypes-enum.rs @@ -46,7 +46,7 @@ extern { fn option_fn(x: Option); fn nonnull(x: Option>); fn unique(x: Option>); - //~^ ERROR `extern` block uses type `std::option::Option>` + //~^ ERROR `extern` block uses type `Option>` fn nonzero_u8(x: Option); fn nonzero_u16(x: Option); fn nonzero_u32(x: Option); diff --git a/src/test/ui/lint/lint-ctypes-enum.stderr b/src/test/ui/lint/lint-ctypes-enum.stderr index 297ac2237a..3d02cda7d3 100644 --- a/src/test/ui/lint/lint-ctypes-enum.stderr +++ b/src/test/ui/lint/lint-ctypes-enum.stderr @@ -45,7 +45,7 @@ note: the type is defined here LL | enum T { E, F, G } | ^^^^^^^^^^^^^^^^^^ -error: `extern` block uses type `std::option::Option>`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:48:17 | LL | fn unique(x: Option>); @@ -70,7 +70,7 @@ LL | fn nonzero_i128(x: Option); | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `std::option::Option>`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:66:28 | LL | fn transparent_union(x: Option>); @@ -79,7 +79,7 @@ LL | fn transparent_union(x: Option>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `std::option::Option>`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:68:20 | LL | fn repr_rust(x: Option>); @@ -88,7 +88,7 @@ LL | fn repr_rust(x: Option>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>`, which is not FFI-safe +error: `extern` block uses type `std::result::Result<(), NonZeroI32>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:69:20 | LL | fn no_result(x: Result<(), num::NonZeroI32>); diff --git a/src/test/ui/lint/lint-ctypes-fn.rs b/src/test/ui/lint/lint-ctypes-fn.rs index aa02e57866..170a04efb0 100644 --- a/src/test/ui/lint/lint-ctypes-fn.rs +++ b/src/test/ui/lint/lint-ctypes-fn.rs @@ -96,7 +96,7 @@ pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { } //~^ ERROR uses type `ZeroSizeWithPhantomData` pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData { -//~^ ERROR uses type `std::marker::PhantomData` +//~^ ERROR uses type `PhantomData` Default::default() } @@ -158,7 +158,7 @@ pub extern "C" fn good2(size: *const libc::c_uint) { } pub extern "C" fn unused_generic1(size: *const Foo) { } pub extern "C" fn unused_generic2() -> PhantomData { -//~^ ERROR uses type `std::marker::PhantomData` +//~^ ERROR uses type `PhantomData` Default::default() } @@ -171,10 +171,10 @@ pub extern "C" fn used_generic3() -> T { } pub extern "C" fn used_generic4(x: Vec) { } -//~^ ERROR: uses type `std::vec::Vec` +//~^ ERROR: uses type `Vec` pub extern "C" fn used_generic5() -> Vec { -//~^ ERROR: uses type `std::vec::Vec` +//~^ ERROR: uses type `Vec` Default::default() } diff --git a/src/test/ui/lint/lint-ctypes-fn.stderr b/src/test/ui/lint/lint-ctypes-fn.stderr index d0a449514e..e6a0778ddb 100644 --- a/src/test/ui/lint/lint-ctypes-fn.stderr +++ b/src/test/ui/lint/lint-ctypes-fn.stderr @@ -91,7 +91,7 @@ note: the type is defined here LL | pub struct ZeroSizeWithPhantomData(PhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `extern` fn uses type `std::marker::PhantomData`, which is not FFI-safe +error: `extern` fn uses type `PhantomData`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:98:51 | LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData { @@ -134,7 +134,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { } = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent -error: `extern` fn uses type `std::marker::PhantomData`, which is not FFI-safe +error: `extern` fn uses type `PhantomData`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:160:43 | LL | pub extern "C" fn unused_generic2() -> PhantomData { @@ -142,7 +142,7 @@ LL | pub extern "C" fn unused_generic2() -> PhantomData { | = note: composed only of `PhantomData` -error: `extern` fn uses type `std::vec::Vec`, which is not FFI-safe +error: `extern` fn uses type `Vec`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:173:39 | LL | pub extern "C" fn used_generic4(x: Vec) { } @@ -151,7 +151,7 @@ LL | pub extern "C" fn used_generic4(x: Vec) { } = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout -error: `extern` fn uses type `std::vec::Vec`, which is not FFI-safe +error: `extern` fn uses type `Vec`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:176:41 | LL | pub extern "C" fn used_generic5() -> Vec { diff --git a/src/test/ui/lint/lint-ctypes.rs b/src/test/ui/lint/lint-ctypes.rs index f485766bcd..e8a90bca7d 100644 --- a/src/test/ui/lint/lint-ctypes.rs +++ b/src/test/ui/lint/lint-ctypes.rs @@ -48,9 +48,9 @@ extern { pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]` pub fn str_type(p: &str); //~ ERROR: uses type `str` - pub fn box_type(p: Box); //~ ERROR uses type `std::boxed::Box` + pub fn box_type(p: Box); //~ ERROR uses type `Box` pub fn opt_box_type(p: Option>); - //~^ ERROR uses type `std::option::Option>` + //~^ ERROR uses type `Option>` pub fn char_type(p: char); //~ ERROR uses type `char` pub fn i128_type(p: i128); //~ ERROR uses type `i128` pub fn u128_type(p: u128); //~ ERROR uses type `u128` @@ -61,13 +61,13 @@ extern { pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~^ ERROR uses type `ZeroSizeWithPhantomData` pub fn zero_size_phantom_toplevel() - -> ::std::marker::PhantomData; //~ ERROR uses type `std::marker::PhantomData` + -> ::std::marker::PhantomData; //~ ERROR uses type `PhantomData` pub fn fn_type(p: RustFn); //~ ERROR uses type `fn()` pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()` - pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box` + pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `Box` pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128` pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` - pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box` + pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box` pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]` pub static static_u128_type: u128; //~ ERROR: uses type `u128` diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr index a54226a7fc..6a968fca92 100644 --- a/src/test/ui/lint/lint-ctypes.stderr +++ b/src/test/ui/lint/lint-ctypes.stderr @@ -49,7 +49,7 @@ LL | pub fn str_type(p: &str); = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent -error: `extern` block uses type `std::boxed::Box`, which is not FFI-safe +error: `extern` block uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes.rs:51:24 | LL | pub fn box_type(p: Box); @@ -58,7 +58,7 @@ LL | pub fn box_type(p: Box); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout -error: `extern` block uses type `std::option::Option>`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes.rs:52:28 | LL | pub fn opt_box_type(p: Option>); @@ -145,7 +145,7 @@ note: the type is defined here LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `extern` block uses type `std::marker::PhantomData`, which is not FFI-safe +error: `extern` block uses type `PhantomData`, which is not FFI-safe --> $DIR/lint-ctypes.rs:64:12 | LL | -> ::std::marker::PhantomData; @@ -171,7 +171,7 @@ LL | pub fn fn_type2(p: fn()); = help: consider using an `extern fn(...) -> ...` function pointer instead = note: this function pointer has Rust-specific calling convention -error: `extern` block uses type `std::boxed::Box`, which is not FFI-safe +error: `extern` block uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes.rs:67:28 | LL | pub fn fn_contained(p: RustBadRet); @@ -197,7 +197,7 @@ LL | pub fn transparent_str(p: TransparentStr); = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent -error: `extern` block uses type `std::boxed::Box`, which is not FFI-safe +error: `extern` block uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes.rs:70:30 | LL | pub fn transparent_fn(p: TransparentBadFn); diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr index d33b99bdc4..d7fd514611 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:18:20 | LL | const N: i32 = T::N << 42; - | ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `42_i32`, which would overflow | note: the lint level is defined here --> $DIR/lint-exceeding-bitshifts.rs:10:9 @@ -14,139 +14,139 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:22:13 | LL | let _ = x << 42; - | ^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^ attempt to shift left by `42_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:27:15 | LL | let n = 1u8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:29:15 | LL | let n = 1u16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:31:15 | LL | let n = 1u32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:33:15 | LL | let n = 1u64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:35:15 | LL | let n = 1i8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:37:15 | LL | let n = 1i16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:39:15 | LL | let n = 1i32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:41:15 | LL | let n = 1i64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:44:15 | LL | let n = 1u8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:46:15 | LL | let n = 1u16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:48:15 | LL | let n = 1u32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:50:15 | LL | let n = 1u64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:52:15 | LL | let n = 1i8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:54:15 | LL | let n = 1i16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:56:15 | LL | let n = 1i32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:58:15 | LL | let n = 1i64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:62:15 | LL | let n = n << 8; - | ^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:64:15 | LL | let n = 1u8 << -8; - | ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow + | ^^^^^^^^^ attempt to shift left by `-8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:69:15 | LL | let n = 1u8 << (4+4); - | ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:71:15 | LL | let n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:77:15 | LL | let n = 1_isize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:78:15 | LL | let n = 1_usize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: 24 warnings emitted diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr index d33b99bdc4..d7fd514611 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:18:20 | LL | const N: i32 = T::N << 42; - | ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `42_i32`, which would overflow | note: the lint level is defined here --> $DIR/lint-exceeding-bitshifts.rs:10:9 @@ -14,139 +14,139 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:22:13 | LL | let _ = x << 42; - | ^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^ attempt to shift left by `42_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:27:15 | LL | let n = 1u8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:29:15 | LL | let n = 1u16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:31:15 | LL | let n = 1u32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:33:15 | LL | let n = 1u64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:35:15 | LL | let n = 1i8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:37:15 | LL | let n = 1i16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:39:15 | LL | let n = 1i32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:41:15 | LL | let n = 1i64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:44:15 | LL | let n = 1u8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:46:15 | LL | let n = 1u16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:48:15 | LL | let n = 1u32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:50:15 | LL | let n = 1u64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:52:15 | LL | let n = 1i8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:54:15 | LL | let n = 1i16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:56:15 | LL | let n = 1i32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:58:15 | LL | let n = 1i64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:62:15 | LL | let n = n << 8; - | ^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:64:15 | LL | let n = 1u8 << -8; - | ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow + | ^^^^^^^^^ attempt to shift left by `-8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:69:15 | LL | let n = 1u8 << (4+4); - | ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:71:15 | LL | let n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:77:15 | LL | let n = 1_isize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:78:15 | LL | let n = 1_usize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: 24 warnings emitted diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr index d33b99bdc4..d7fd514611 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:18:20 | LL | const N: i32 = T::N << 42; - | ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `42_i32`, which would overflow | note: the lint level is defined here --> $DIR/lint-exceeding-bitshifts.rs:10:9 @@ -14,139 +14,139 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:22:13 | LL | let _ = x << 42; - | ^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^ attempt to shift left by `42_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:27:15 | LL | let n = 1u8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:29:15 | LL | let n = 1u16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:31:15 | LL | let n = 1u32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:33:15 | LL | let n = 1u64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:35:15 | LL | let n = 1i8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:37:15 | LL | let n = 1i16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:39:15 | LL | let n = 1i32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:41:15 | LL | let n = 1i64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:44:15 | LL | let n = 1u8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:46:15 | LL | let n = 1u16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:48:15 | LL | let n = 1u32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:50:15 | LL | let n = 1u64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:52:15 | LL | let n = 1i8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:54:15 | LL | let n = 1i16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:56:15 | LL | let n = 1i32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:58:15 | LL | let n = 1i64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:62:15 | LL | let n = n << 8; - | ^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:64:15 | LL | let n = 1u8 << -8; - | ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow + | ^^^^^^^^^ attempt to shift left by `-8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:69:15 | LL | let n = 1u8 << (4+4); - | ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:71:15 | LL | let n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:77:15 | LL | let n = 1_isize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:78:15 | LL | let n = 1_usize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: 24 warnings emitted diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.rs b/src/test/ui/lint/lint-exceeding-bitshifts.rs index a76ca93f8e..d8774cb4df 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.rs +++ b/src/test/ui/lint/lint-exceeding-bitshifts.rs @@ -4,7 +4,7 @@ //[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O // build-pass // ignore-pass (test emits codegen-time warnings and verifies that they are not errors) -// normalize-stderr-test "shift left by (64|32)_usize which" -> "shift left by %BITS% which" +// normalize-stderr-test "shift left by `(64|32)_usize`, which" -> "shift left by `%BITS%`, which" #![crate_type="lib"] #![warn(arithmetic_overflow, const_err)] diff --git a/src/test/ui/lint/lint-missing-doc.rs b/src/test/ui/lint/lint-missing-doc.rs index bab6f4e9e5..2297257919 100644 --- a/src/test/ui/lint/lint-missing-doc.rs +++ b/src/test/ui/lint/lint-missing-doc.rs @@ -2,7 +2,7 @@ // injected intrinsics by the compiler. #![deny(missing_docs)] #![allow(dead_code)] -#![feature(associated_type_defaults)] +#![feature(associated_type_defaults, extern_types)] //! Some garbage docs for the crate here #![doc="More garbage"] @@ -183,4 +183,21 @@ pub mod public_interface { pub use internal_impl::globbed::*; } +extern "C" { + /// dox + pub fn extern_fn_documented(f: f32) -> f32; + pub fn extern_fn_undocumented(f: f32) -> f32; + //~^ ERROR: missing documentation for a function + + /// dox + pub static EXTERN_STATIC_DOCUMENTED: u8; + pub static EXTERN_STATIC_UNDOCUMENTED: u8; + //~^ ERROR: missing documentation for a static + + /// dox + pub type ExternTyDocumented; + pub type ExternTyUndocumented; + //~^ ERROR: missing documentation for a foreign type +} + fn main() {} diff --git a/src/test/ui/lint/lint-missing-doc.stderr b/src/test/ui/lint/lint-missing-doc.stderr index 21da4fae4c..56f8fc10e8 100644 --- a/src/test/ui/lint/lint-missing-doc.stderr +++ b/src/test/ui/lint/lint-missing-doc.stderr @@ -118,5 +118,23 @@ error: missing documentation for a function LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 19 previous errors +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:189:5 + | +LL | pub fn extern_fn_undocumented(f: f32) -> f32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a static + --> $DIR/lint-missing-doc.rs:194:5 + | +LL | pub static EXTERN_STATIC_UNDOCUMENTED: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a foreign type + --> $DIR/lint-missing-doc.rs:199:5 + | +LL | pub type ExternTyUndocumented; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 22 previous errors diff --git a/src/test/ui/lint/lint-owned-heap-memory.stderr b/src/test/ui/lint/lint-owned-heap-memory.stderr index 2c6b47e494..40310f9387 100644 --- a/src/test/ui/lint/lint-owned-heap-memory.stderr +++ b/src/test/ui/lint/lint-owned-heap-memory.stderr @@ -1,4 +1,4 @@ -error: type uses owned (Box type) pointers: std::boxed::Box +error: type uses owned (Box type) pointers: Box --> $DIR/lint-owned-heap-memory.rs:6:5 | LL | x: Box @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![forbid(box_pointers)] | ^^^^^^^^^^^^ -error: type uses owned (Box type) pointers: std::boxed::Box +error: type uses owned (Box type) pointers: Box --> $DIR/lint-owned-heap-memory.rs:10:29 | LL | let _x : Foo = Foo {x : box 10}; diff --git a/src/test/ui/lint/lint-unconditional-recursion.stderr b/src/test/ui/lint/lint-unconditional-recursion.stderr index 1770d71e2e..fb884e3129 100644 --- a/src/test/ui/lint/lint-unconditional-recursion.stderr +++ b/src/test/ui/lint/lint-unconditional-recursion.stderr @@ -149,7 +149,7 @@ error: function cannot return without recursing LL | fn deref(&self) -> &Baz { | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | self.as_ref() - | ---- recursive call site + | ------------- recursive call site | = help: a `loop` may express intention better if this is on purpose diff --git a/src/test/ui/lint/lint-uppercase-variables.rs b/src/test/ui/lint/lint-uppercase-variables.rs index a98b4f2fd4..b590fa697a 100644 --- a/src/test/ui/lint/lint-uppercase-variables.rs +++ b/src/test/ui/lint/lint-uppercase-variables.rs @@ -21,18 +21,18 @@ fn main() { match foo::Foo::Foo { Foo => {} //~^ ERROR variable `Foo` should have a snake case name -//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` +//~^^ WARN `Foo` is named the same as one of the variants of the type `Foo` //~^^^ WARN unused variable: `Foo` } let Foo = foo::Foo::Foo; //~^ ERROR variable `Foo` should have a snake case name - //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo` //~^^^ WARN unused variable: `Foo` fn in_param(Foo: foo::Foo) {} //~^ ERROR variable `Foo` should have a snake case name - //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo` //~^^^ WARN unused variable: `Foo` test(1); diff --git a/src/test/ui/lint/lint-uppercase-variables.stderr b/src/test/ui/lint/lint-uppercase-variables.stderr index d476d856e2..71b24a835b 100644 --- a/src/test/ui/lint/lint-uppercase-variables.stderr +++ b/src/test/ui/lint/lint-uppercase-variables.stderr @@ -1,22 +1,22 @@ -warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` +warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo` --> $DIR/lint-uppercase-variables.rs:22:9 | LL | Foo => {} - | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + | ^^^ help: to match on the variant, qualify the path: `Foo::Foo` | = note: `#[warn(bindings_with_variant_name)]` on by default -warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` +warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo` --> $DIR/lint-uppercase-variables.rs:28:9 | LL | let Foo = foo::Foo::Foo; - | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + | ^^^ help: to match on the variant, qualify the path: `Foo::Foo` -warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` +warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo` --> $DIR/lint-uppercase-variables.rs:33:17 | LL | fn in_param(Foo: foo::Foo) {} - | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + | ^^^ help: to match on the variant, qualify the path: `Foo::Foo` warning: unused variable: `Foo` --> $DIR/lint-uppercase-variables.rs:22:9 diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs index 3cbc084eca..4ceb0c3da0 100644 --- a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs @@ -9,7 +9,7 @@ pub fn ret_closure() -> A { extern "C" { pub fn a(_: A); -//~^ ERROR `extern` block uses type `impl std::ops::Fn<()>`, which is not FFI-safe +//~^ ERROR `extern` block uses type `impl Fn<()>`, which is not FFI-safe } fn main() {} diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr index 06dfb7b8fb..9d46f6d936 100644 --- a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr @@ -1,4 +1,4 @@ -error: `extern` block uses type `impl std::ops::Fn<()>`, which is not FFI-safe +error: `extern` block uses type `impl Fn<()>`, which is not FFI-safe --> $DIR/opaque-ty-ffi-unsafe.rs:11:17 | LL | pub fn a(_: A); diff --git a/src/test/ui/lint/uninitialized-zeroed.stderr b/src/test/ui/lint/uninitialized-zeroed.stderr index 3bf8a66ab0..de1b6c7617 100644 --- a/src/test/ui/lint/uninitialized-zeroed.stderr +++ b/src/test/ui/lint/uninitialized-zeroed.stderr @@ -285,7 +285,7 @@ note: references must be non-null (in this struct field) LL | struct RefPair((&'static i32, i32)); | ^^^^^^^^^^^^^^^^^^^ -error: the type `std::ptr::NonNull` does not permit zero-initialization +error: the type `NonNull` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:79:34 | LL | let _val: NonNull = mem::zeroed(); @@ -296,7 +296,7 @@ LL | let _val: NonNull = mem::zeroed(); | = note: `std::ptr::NonNull` must be non-null -error: the type `std::ptr::NonNull` does not permit being left uninitialized +error: the type `NonNull` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:80:34 | LL | let _val: NonNull = mem::uninitialized(); @@ -307,7 +307,7 @@ LL | let _val: NonNull = mem::uninitialized(); | = note: `std::ptr::NonNull` must be non-null -error: the type `*const dyn std::marker::Send` does not permit zero-initialization +error: the type `*const dyn Send` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:82:37 | LL | let _val: *const dyn Send = mem::zeroed(); @@ -318,7 +318,7 @@ LL | let _val: *const dyn Send = mem::zeroed(); | = note: the vtable of a wide raw pointer must be non-null -error: the type `*const dyn std::marker::Send` does not permit being left uninitialized +error: the type `*const dyn Send` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:83:37 | LL | let _val: *const dyn Send = mem::uninitialized(); @@ -406,7 +406,7 @@ LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); | = note: references must be non-null -error: the type `std::num::NonZeroU32` does not permit zero-initialization +error: the type `NonZeroU32` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:101:32 | LL | let _val: NonZeroU32 = mem::transmute(0); @@ -417,7 +417,7 @@ LL | let _val: NonZeroU32 = mem::transmute(0); | = note: `std::num::NonZeroU32` must be non-null -error: the type `std::ptr::NonNull` does not permit zero-initialization +error: the type `NonNull` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:104:34 | LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); @@ -428,7 +428,7 @@ LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); | = note: `std::ptr::NonNull` must be non-null -error: the type `std::ptr::NonNull` does not permit being left uninitialized +error: the type `NonNull` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:105:34 | LL | let _val: NonNull = MaybeUninit::uninit().assume_init(); diff --git a/src/test/ui/liveness/liveness-consts.rs b/src/test/ui/liveness/liveness-consts.rs new file mode 100644 index 0000000000..8fe2453ca2 --- /dev/null +++ b/src/test/ui/liveness/liveness-consts.rs @@ -0,0 +1,63 @@ +// check-pass +#![warn(unused)] +#![allow(unreachable_code)] + +pub static A: i32 = { + let mut i = 0; + let mut a = 0; //~ WARN variable `a` is assigned to, but never used + while i < 10 { + i += 1; + a += 1; + } + i +}; + +pub const B: u32 = { + let mut b = 1; + b += 1; //~ WARN value assigned to `b` is never read + b = 42; + b +}; + +pub enum E { + V1 = { + let e = 1; //~ WARN unused variable: `e` + 1 + }, + V2 = { + let _f = 10; + 2 + } +} + +pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { + //~^ WARN unused variable: `s` + //~| WARN unused variable: `z` + x +} + +pub trait T { + const T: usize = { + let mut t = 10; + t = t + t; //~ WARN value assigned to `t` is never read + 20 + }; +} + +impl T for String { + const T: usize = { + let w = 10; //~ WARN unused variable: `w` + loop { + break; + let _ = w; + } + 44 + }; +} + +fn main() { + let _ = [(); { + let z = 42; //~ WARN unused variable: `z` + 35 + }]; +} diff --git a/src/test/ui/liveness/liveness-consts.stderr b/src/test/ui/liveness/liveness-consts.stderr new file mode 100644 index 0000000000..fa8a590a81 --- /dev/null +++ b/src/test/ui/liveness/liveness-consts.stderr @@ -0,0 +1,68 @@ +warning: variable `a` is assigned to, but never used + --> $DIR/liveness-consts.rs:7:9 + | +LL | let mut a = 0; + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/liveness-consts.rs:2:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + = note: consider using `_a` instead + +warning: value assigned to `b` is never read + --> $DIR/liveness-consts.rs:17:5 + | +LL | b += 1; + | ^ + | +note: the lint level is defined here + --> $DIR/liveness-consts.rs:2:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]` + = help: maybe it is overwritten before being read? + +warning: unused variable: `e` + --> $DIR/liveness-consts.rs:24:13 + | +LL | let e = 1; + | ^ help: if this is intentional, prefix it with an underscore: `_e` + +warning: unused variable: `s` + --> $DIR/liveness-consts.rs:33:24 + | +LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { + | ^ help: if this is intentional, prefix it with an underscore: `_s` + +warning: unused variable: `z` + --> $DIR/liveness-consts.rs:33:55 + | +LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { + | ^ help: if this is intentional, prefix it with an underscore: `_z` + +warning: unused variable: `z` + --> $DIR/liveness-consts.rs:60:13 + | +LL | let z = 42; + | ^ help: if this is intentional, prefix it with an underscore: `_z` + +warning: value assigned to `t` is never read + --> $DIR/liveness-consts.rs:42:9 + | +LL | t = t + t; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `w` + --> $DIR/liveness-consts.rs:49:13 + | +LL | let w = 10; + | ^ help: if this is intentional, prefix it with an underscore: `_w` + +warning: 8 warnings emitted + diff --git a/src/test/ui/liveness/liveness-derive.rs b/src/test/ui/liveness/liveness-derive.rs new file mode 100644 index 0000000000..1921d0d72b --- /dev/null +++ b/src/test/ui/liveness/liveness-derive.rs @@ -0,0 +1,38 @@ +// Test for interaction between #[automatically_derived] attribute used by +// built-in derives and lints generated by liveness pass. +// +// edition:2018 +// check-pass +#![warn(unused)] + +pub trait T: Sized { + const N: usize; + fn t(&self) -> Self; +} + +impl T for u32 { + const N: usize = { + let a = 0; //~ WARN unused variable: `a` + 4 + }; + + fn t(&self) -> Self { + let b = 16; //~ WARN unused variable: `b` + 0 + } +} + +#[automatically_derived] +impl T for i32 { + const N: usize = { + let c = 0; + 4 + }; + + fn t(&self) -> Self { + let d = 17; + 0 + } +} + +fn main() {} diff --git a/src/test/ui/liveness/liveness-derive.stderr b/src/test/ui/liveness/liveness-derive.stderr new file mode 100644 index 0000000000..c03d909918 --- /dev/null +++ b/src/test/ui/liveness/liveness-derive.stderr @@ -0,0 +1,21 @@ +warning: unused variable: `a` + --> $DIR/liveness-derive.rs:15:13 + | +LL | let a = 0; + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/liveness-derive.rs:6:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: unused variable: `b` + --> $DIR/liveness-derive.rs:20:13 + | +LL | let b = 16; + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +warning: 2 warnings emitted + diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr index ab4460a326..5ea5c40f2a 100644 --- a/src/test/ui/liveness/liveness-move-call-arg.stderr +++ b/src/test/ui/liveness/liveness-move-call-arg.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/liveness-move-call-arg.rs:9:14 | LL | let x: Box = box 25; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | loop { LL | take(x); | ^ value moved here, in previous iteration of loop diff --git a/src/test/ui/liveness/liveness-move-in-loop.stderr b/src/test/ui/liveness/liveness-move-in-loop.stderr index 150c1ec82b..66b6373e45 100644 --- a/src/test/ui/liveness/liveness-move-in-loop.stderr +++ b/src/test/ui/liveness/liveness-move-in-loop.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `y` --> $DIR/liveness-move-in-loop.rs:11:25 | LL | let y: Box = box 42; - | - move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `y` has type `Box`, which does not implement the `Copy` trait ... LL | x = y; | ^ value moved here, in previous iteration of loop diff --git a/src/test/ui/liveness/liveness-move-in-while.stderr b/src/test/ui/liveness/liveness-move-in-while.stderr index 45c00e8d6d..92e0f37252 100644 --- a/src/test/ui/liveness/liveness-move-in-while.stderr +++ b/src/test/ui/liveness/liveness-move-in-while.stderr @@ -22,7 +22,7 @@ error[E0382]: borrow of moved value: `y` --> $DIR/liveness-move-in-while.rs:7:24 | LL | let y: Box = box 42; - | - move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `y` has type `Box`, which does not implement the `Copy` trait ... LL | println!("{}", y); | ^ value borrowed here after move diff --git a/src/test/ui/liveness/liveness-use-after-move.stderr b/src/test/ui/liveness/liveness-use-after-move.stderr index 383b89afaa..3977a3f413 100644 --- a/src/test/ui/liveness/liveness-use-after-move.stderr +++ b/src/test/ui/liveness/liveness-use-after-move.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/liveness-use-after-move.rs:6:20 | LL | let x: Box<_> = box 5; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | let y = x; | - value moved here LL | println!("{}", *x); diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr index ccf9499f64..50ae98ca9b 100644 --- a/src/test/ui/liveness/liveness-use-after-send.stderr +++ b/src/test/ui/liveness/liveness-use-after-send.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `message` --> $DIR/liveness-use-after-send.rs:16:20 | LL | fn test00_start(ch: Chan>, message: Box, _count: Box) { - | ------- move occurs because `message` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ------- move occurs because `message` has type `Box`, which does not implement the `Copy` trait LL | send(ch, message); | ------- value moved here LL | println!("{}", message); diff --git a/src/test/ui/macros/builtin-prelude-no-accidents.rs b/src/test/ui/macros/builtin-prelude-no-accidents.rs index ac82f343ac..01691a82dd 100644 --- a/src/test/ui/macros/builtin-prelude-no-accidents.rs +++ b/src/test/ui/macros/builtin-prelude-no-accidents.rs @@ -2,7 +2,7 @@ // because macros with the same names are in prelude. fn main() { - env::current_dir; //~ ERROR use of undeclared type or module `env` - type A = panic::PanicInfo; //~ ERROR use of undeclared type or module `panic` - type B = vec::Vec; //~ ERROR use of undeclared type or module `vec` + env::current_dir; //~ ERROR use of undeclared crate or module `env` + type A = panic::PanicInfo; //~ ERROR use of undeclared crate or module `panic` + type B = vec::Vec; //~ ERROR use of undeclared crate or module `vec` } diff --git a/src/test/ui/macros/builtin-prelude-no-accidents.stderr b/src/test/ui/macros/builtin-prelude-no-accidents.stderr index 914e906df5..56af618d48 100644 --- a/src/test/ui/macros/builtin-prelude-no-accidents.stderr +++ b/src/test/ui/macros/builtin-prelude-no-accidents.stderr @@ -1,20 +1,20 @@ -error[E0433]: failed to resolve: use of undeclared type or module `env` +error[E0433]: failed to resolve: use of undeclared crate or module `env` --> $DIR/builtin-prelude-no-accidents.rs:5:5 | LL | env::current_dir; - | ^^^ use of undeclared type or module `env` + | ^^^ use of undeclared crate or module `env` -error[E0433]: failed to resolve: use of undeclared type or module `panic` +error[E0433]: failed to resolve: use of undeclared crate or module `panic` --> $DIR/builtin-prelude-no-accidents.rs:6:14 | LL | type A = panic::PanicInfo; - | ^^^^^ use of undeclared type or module `panic` + | ^^^^^ use of undeclared crate or module `panic` -error[E0433]: failed to resolve: use of undeclared type or module `vec` +error[E0433]: failed to resolve: use of undeclared crate or module `vec` --> $DIR/builtin-prelude-no-accidents.rs:7:14 | LL | type B = vec::Vec; - | ^^^ use of undeclared type or module `vec` + | ^^^ use of undeclared crate or module `vec` error: aborting due to 3 previous errors diff --git a/src/test/ui/macros/duplicate-builtin.rs b/src/test/ui/macros/duplicate-builtin.rs new file mode 100644 index 0000000000..35f0f42905 --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.rs @@ -0,0 +1,17 @@ +// compile-flags:--crate-type lib +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { +//~^ NOTE previously defined + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + //~^ ERROR attempted to define built-in macro more than once [E0773] + /* compiler built-in */ + } +} diff --git a/src/test/ui/macros/duplicate-builtin.stderr b/src/test/ui/macros/duplicate-builtin.stderr new file mode 100644 index 0000000000..58accea27b --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.stderr @@ -0,0 +1,21 @@ +error[E0773]: attempted to define built-in macro more than once + --> $DIR/duplicate-builtin.rs:13:5 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_____^ + | +note: previously defined here + --> $DIR/duplicate-builtin.rs:6:1 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0773`. diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs index 8772e98b6e..f82eb338f4 100644 --- a/src/test/ui/macros/issue-68060.rs +++ b/src/test/ui/macros/issue-68060.rs @@ -2,11 +2,13 @@ fn main() { (0..) .map( #[target_feature(enable = "")] - //~^ ERROR: the feature named `` is not valid for this target - //~| ERROR: `#[target_feature(..)]` can only be applied to `unsafe` functions + //~^ ERROR: attribute should be applied to a function + //~| ERROR: the feature named `` is not valid for this target + //~| NOTE: `` is not valid for this target #[track_caller] - //~^ ERROR: `#[track_caller]` requires Rust ABI + //~^ ERROR: `#[track_caller]` requires Rust ABI [E0737] |_| (), + //~^ NOTE: not a function ) .next(); } diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr index b9b2f946c5..a01c3827bb 100644 --- a/src/test/ui/macros/issue-68060.stderr +++ b/src/test/ui/macros/issue-68060.stderr @@ -1,14 +1,11 @@ -error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions +error: attribute should be applied to a function --> $DIR/issue-68060.rs:4:13 | LL | #[target_feature(enable = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | |_| (), - | ------ not an `unsafe` function - | - = note: see issue #69098 for more information - = help: add `#![feature(target_feature_11)]` to the crate attributes to enable + | ------ not a function error: the feature named `` is not valid for this target --> $DIR/issue-68060.rs:4:30 @@ -17,12 +14,11 @@ LL | #[target_feature(enable = "")] | ^^^^^^^^^^^ `` is not valid for this target error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/issue-68060.rs:7:13 + --> $DIR/issue-68060.rs:8:13 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors -Some errors have detailed explanations: E0658, E0737. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0737`. diff --git a/src/test/ui/macros/macro-comma-behavior.core.stderr b/src/test/ui/macros/macro-comma-behavior.core.stderr index 83a88ab3bd..dd0cac659f 100644 --- a/src/test/ui/macros/macro-comma-behavior.core.stderr +++ b/src/test/ui/macros/macro-comma-behavior.core.stderr @@ -1,41 +1,41 @@ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:20:23 + --> $DIR/macro-comma-behavior.rs:21:23 | LL | assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:23:23 + --> $DIR/macro-comma-behavior.rs:24:23 | LL | assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:29:29 + --> $DIR/macro-comma-behavior.rs:30:29 | LL | debug_assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:32:29 + --> $DIR/macro-comma-behavior.rs:33:29 | LL | debug_assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:53:19 + --> $DIR/macro-comma-behavior.rs:54:19 | LL | format_args!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:71:21 + --> $DIR/macro-comma-behavior.rs:72:21 | LL | unimplemented!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:80:24 + --> $DIR/macro-comma-behavior.rs:81:24 | LL | write!(f, "{}",)?; | ^^ diff --git a/src/test/ui/macros/macro-comma-behavior.rs b/src/test/ui/macros/macro-comma-behavior.rs index 04714c65b5..0bfe068307 100644 --- a/src/test/ui/macros/macro-comma-behavior.rs +++ b/src/test/ui/macros/macro-comma-behavior.rs @@ -9,6 +9,7 @@ #[cfg(std)] use std::fmt; #[cfg(core)] use core::fmt; #[cfg(core)] #[lang = "eh_personality"] fn eh_personality() {} +#[cfg(core)] #[lang = "eh_catch_typeinfo"] static EH_CATCH_TYPEINFO: u8 = 0; #[cfg(core)] #[lang = "panic_impl"] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} } // (see documentation of the similarly-named test in run-pass) diff --git a/src/test/ui/macros/macro-comma-behavior.std.stderr b/src/test/ui/macros/macro-comma-behavior.std.stderr index 26445f2c5c..4372d89fbf 100644 --- a/src/test/ui/macros/macro-comma-behavior.std.stderr +++ b/src/test/ui/macros/macro-comma-behavior.std.stderr @@ -1,59 +1,59 @@ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:20:23 + --> $DIR/macro-comma-behavior.rs:21:23 | LL | assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:23:23 + --> $DIR/macro-comma-behavior.rs:24:23 | LL | assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:29:29 + --> $DIR/macro-comma-behavior.rs:30:29 | LL | debug_assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:32:29 + --> $DIR/macro-comma-behavior.rs:33:29 | LL | debug_assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:37:18 + --> $DIR/macro-comma-behavior.rs:38:18 | LL | eprint!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:49:18 + --> $DIR/macro-comma-behavior.rs:50:18 | LL | format!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:53:19 + --> $DIR/macro-comma-behavior.rs:54:19 | LL | format_args!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:60:17 + --> $DIR/macro-comma-behavior.rs:61:17 | LL | print!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:71:21 + --> $DIR/macro-comma-behavior.rs:72:21 | LL | unimplemented!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:80:24 + --> $DIR/macro-comma-behavior.rs:81:24 | LL | write!(f, "{}",)?; | ^^ diff --git a/src/test/ui/macros/macro-inner-attributes.rs b/src/test/ui/macros/macro-inner-attributes.rs index 56a9023156..a8cda23075 100644 --- a/src/test/ui/macros/macro-inner-attributes.rs +++ b/src/test/ui/macros/macro-inner-attributes.rs @@ -15,6 +15,6 @@ test!(b, #[rustc_dummy] fn main() { a::bar(); - //~^ ERROR failed to resolve: use of undeclared type or module `a` + //~^ ERROR failed to resolve: use of undeclared crate or module `a` b::bar(); } diff --git a/src/test/ui/macros/macro-inner-attributes.stderr b/src/test/ui/macros/macro-inner-attributes.stderr index 5e20f106a9..8223220d9a 100644 --- a/src/test/ui/macros/macro-inner-attributes.stderr +++ b/src/test/ui/macros/macro-inner-attributes.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `a` +error[E0433]: failed to resolve: use of undeclared crate or module `a` --> $DIR/macro-inner-attributes.rs:17:5 | LL | a::bar(); - | ^ use of undeclared type or module `a` + | ^ use of undeclared crate or module `a` error: aborting due to previous error diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr index 48c33575ad..00d954d24f 100644 --- a/src/test/ui/macros/macro_path_as_generic_bound.stderr +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `m` +error[E0433]: failed to resolve: use of undeclared crate or module `m` --> $DIR/macro_path_as_generic_bound.rs:7:6 | LL | foo!(m::m2::A); - | ^ use of undeclared type or module `m` + | ^ use of undeclared crate or module `m` error: aborting due to previous error diff --git a/src/test/ui/macros/missing-comma.rs b/src/test/ui/macros/missing-comma.rs index 2002fed6c9..92f8a77950 100644 --- a/src/test/ui/macros/missing-comma.rs +++ b/src/test/ui/macros/missing-comma.rs @@ -17,7 +17,7 @@ macro_rules! check { fn main() { println!("{}" a); - //~^ ERROR expected token: `,` + //~^ ERROR expected `,`, found `a` foo!(a b); //~^ ERROR no rules expected the token `b` foo!(a, b, c, d e); diff --git a/src/test/ui/macros/missing-comma.stderr b/src/test/ui/macros/missing-comma.stderr index f96848f823..6da92bdea1 100644 --- a/src/test/ui/macros/missing-comma.stderr +++ b/src/test/ui/macros/missing-comma.stderr @@ -1,4 +1,4 @@ -error: expected token: `,` +error: expected `,`, found `a` --> $DIR/missing-comma.rs:19:19 | LL | println!("{}" a); diff --git a/src/test/ui/macros/same-sequence-span.stderr b/src/test/ui/macros/same-sequence-span.stderr index 65b67a9423..63b8b29d6c 100644 --- a/src/test/ui/macros/same-sequence-span.stderr +++ b/src/test/ui/macros/same-sequence-span.stderr @@ -17,15 +17,11 @@ LL | $(= $z:tt)* error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments --> $DIR/same-sequence-span.rs:19:1 | -LL | proc_macro_sequence::make_foo!(); - | ^-------------------------------- - | | - | _in this macro invocation +LL | proc_macro_sequence::make_foo!(); + | ---------------------------------^^^^^^^^^^^^^ | | -LL | | -LL | | -LL | | fn main() {} -... | + | not allowed after `expr` fragments + | in this macro invocation | = note: allowed there are: `=>`, `,` or `;` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index aec9d1ab19..cecc942f47 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -60,7 +60,7 @@ LL | let a = pat_macro!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/trace_faulty_macros.rs:42:1 | LL | #[derive(Debug)] @@ -79,3 +79,4 @@ LL | let a = pat_macro!(); error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/macros/unknown-builtin.rs b/src/test/ui/macros/unknown-builtin.rs index a96b99ae4f..16f9139e64 100644 --- a/src/test/ui/macros/unknown-builtin.rs +++ b/src/test/ui/macros/unknown-builtin.rs @@ -1,4 +1,4 @@ -// error-pattern: cannot find a built-in macro with name `line` +// error-pattern: attempted to define built-in macro more than once #![feature(rustc_attrs)] @@ -6,7 +6,7 @@ macro_rules! unknown { () => () } //~ ERROR cannot find a built-in macro with name `unknown` #[rustc_builtin_macro] -macro_rules! line { () => () } +macro_rules! line { () => () } //~ NOTE previously defined here fn main() { line!(); diff --git a/src/test/ui/macros/unknown-builtin.stderr b/src/test/ui/macros/unknown-builtin.stderr index 4b650b2c47..7b04e05293 100644 --- a/src/test/ui/macros/unknown-builtin.stderr +++ b/src/test/ui/macros/unknown-builtin.stderr @@ -4,7 +4,7 @@ error: cannot find a built-in macro with name `unknown` LL | macro_rules! unknown { () => () } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot find a built-in macro with name `line` +error[E0773]: attempted to define built-in macro more than once --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | LL | / macro_rules! line { @@ -13,6 +13,13 @@ LL | | /* compiler built-in */ LL | | }; LL | | } | |_____^ + | +note: previously defined here + --> $DIR/unknown-builtin.rs:9:1 + | +LL | macro_rules! line { () => () } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0773`. diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr index e8f96178d1..c4532a375a 100644 --- a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr +++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr @@ -4,7 +4,7 @@ error: traits in `#[derive(...)]` don't accept arguments LL | #[derive(parse())] | ^^ help: remove the arguments -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-69341-malformed-derive-inert.rs:8:5 | LL | path: (), @@ -24,3 +24,4 @@ LL | #[derive(parse())] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr index 587fc5a5ae..63be8f9ca1 100644 --- a/src/test/ui/malformed/malformed-derive-entry.stderr +++ b/src/test/ui/malformed/malformed-derive-entry.stderr @@ -16,29 +16,29 @@ error: malformed `derive` attribute input LL | #[derive] | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]` -error[E0277]: the trait bound `Test1: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Test1: Clone` is not satisfied --> $DIR/malformed-derive-entry.rs:1:10 | LL | #[derive(Copy(Bad))] - | ^^^^ the trait `std::clone::Clone` is not implemented for `Test1` + | ^^^^ the trait `Clone` is not implemented for `Test1` | ::: $SRC_DIR/core/src/marker.rs:LL:COL | LL | pub trait Copy: Clone { - | ----- required by this bound in `std::marker::Copy` + | ----- required by this bound in `Copy` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Test2: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Test2: Clone` is not satisfied --> $DIR/malformed-derive-entry.rs:6:10 | LL | #[derive(Copy="bad")] - | ^^^^ the trait `std::clone::Clone` is not implemented for `Test2` + | ^^^^ the trait `Clone` is not implemented for `Test2` | ::: $SRC_DIR/core/src/marker.rs:LL:COL | LL | pub trait Copy: Clone { - | ----- required by this bound in `std::marker::Copy` + | ----- required by this bound in `Copy` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/map-types.rs b/src/test/ui/map-types.rs index c355a0e420..89b5708750 100644 --- a/src/test/ui/map-types.rs +++ b/src/test/ui/map-types.rs @@ -15,5 +15,5 @@ fn main() { let x: Box> = box HashMap::new(); let x: Box> = x; let y: Box> = Box::new(x); - //~^ ERROR `std::boxed::Box>: Map` is not satisfied + //~^ ERROR `Box>: Map` is not satisfied } diff --git a/src/test/ui/map-types.stderr b/src/test/ui/map-types.stderr index 21dac1ab1e..71006e1f4e 100644 --- a/src/test/ui/map-types.stderr +++ b/src/test/ui/map-types.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `std::boxed::Box>: Map` is not satisfied +error[E0277]: the trait bound `Box>: Map` is not satisfied --> $DIR/map-types.rs:17:41 | LL | let y: Box> = Box::new(x); - | ^^^^^^^^^^^ the trait `Map` is not implemented for `std::boxed::Box>` + | ^^^^^^^^^^^ the trait `Map` is not implemented for `Box>` | = note: required for the cast to the object type `dyn Map` diff --git a/src/test/ui/match/const_non_normal_zst_ref_pattern.rs b/src/test/ui/match/const_non_normal_zst_ref_pattern.rs new file mode 100644 index 0000000000..a114fafb64 --- /dev/null +++ b/src/test/ui/match/const_non_normal_zst_ref_pattern.rs @@ -0,0 +1,9 @@ +// check-pass + +const FOO: isize = 10; +const ZST: &() = unsafe { std::mem::transmute(FOO) }; +fn main() { + match &() { + ZST => 9, + }; +} diff --git a/src/test/ui/match/issue-70972-dyn-trait.rs b/src/test/ui/match/issue-70972-dyn-trait.rs index a9b2699caf..97d161c59e 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.rs +++ b/src/test/ui/match/issue-70972-dyn-trait.rs @@ -4,7 +4,7 @@ fn main() { let a: &dyn Send = &7u32; match a { F => panic!(), - //~^ ERROR trait objects cannot be used in patterns + //~^ ERROR `&dyn Send` cannot be used in patterns _ => {} } } diff --git a/src/test/ui/match/issue-70972-dyn-trait.stderr b/src/test/ui/match/issue-70972-dyn-trait.stderr index a4e827357d..7581070ebc 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.stderr +++ b/src/test/ui/match/issue-70972-dyn-trait.stderr @@ -1,4 +1,4 @@ -error: trait objects cannot be used in patterns +error: `&dyn Send` cannot be used in patterns --> $DIR/issue-70972-dyn-trait.rs:6:9 | LL | F => panic!(), diff --git a/src/test/ui/match/match-range-fail.rs b/src/test/ui/match/match-range-fail.rs index c0cdbe342a..e53c8463ef 100644 --- a/src/test/ui/match/match-range-fail.rs +++ b/src/test/ui/match/match-range-fail.rs @@ -2,17 +2,17 @@ fn main() { match "wow" { "bar" ..= "foo" => { } }; - //~^^ ERROR only char and numeric types are allowed in range + //~^^ ERROR only `char` and numeric types are allowed in range match "wow" { 10 ..= "what" => () }; - //~^^ ERROR only char and numeric types are allowed in range + //~^^ ERROR only `char` and numeric types are allowed in range match "wow" { true ..= "what" => {} }; - //~^^ ERROR only char and numeric types are allowed in range + //~^^ ERROR only `char` and numeric types are allowed in range match 5 { 'c' ..= 100 => { } diff --git a/src/test/ui/match/match-range-fail.stderr b/src/test/ui/match/match-range-fail.stderr index 64105dc73d..938c05ac73 100644 --- a/src/test/ui/match/match-range-fail.stderr +++ b/src/test/ui/match/match-range-fail.stderr @@ -1,4 +1,4 @@ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/match-range-fail.rs:3:9 | LL | "bar" ..= "foo" => { } @@ -7,7 +7,7 @@ LL | "bar" ..= "foo" => { } | | this is of type `&'static str` but it should be `char` or numeric | this is of type `&'static str` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/match-range-fail.rs:8:16 | LL | 10 ..= "what" => () @@ -15,7 +15,7 @@ LL | 10 ..= "what" => () | | | this is of type `{integer}` -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/match-range-fail.rs:13:9 | LL | true ..= "what" => {} diff --git a/src/test/ui/match/pattern-deref-miscompile.rs b/src/test/ui/match/pattern-deref-miscompile.rs new file mode 100644 index 0000000000..caa6d184a9 --- /dev/null +++ b/src/test/ui/match/pattern-deref-miscompile.rs @@ -0,0 +1,46 @@ +// run-pass + +fn main() { + match b"." as &[u8] { + b"." if true => {}, + b"." => panic!(), + b".." => panic!(), + b"" => panic!(), + _ => panic!(), + } + match b"." as &[u8] { + b"." if false => panic!(), + b"." => {}, + b".." => panic!(), + b"" => panic!(), + _ => panic!(), + } + match b".." as &[u8] { + b"." if true => panic!(), // the miscompile caused this arm to be reached + b"." => panic!(), + b".." => {}, + b"" => panic!(), + _ => panic!(), + } + match b".." as &[u8] { + b"." if false => panic!(), + b"." => panic!(), + b".." => {}, + b"" => panic!(), + _ => panic!(), + } + match b"" as &[u8] { + b"." if true => panic!(), + b"." => panic!(), + b".." => panic!(), + b"" => {}, + _ => panic!(), + } + match b"" as &[u8] { + b"." if false => panic!(), + b"." => panic!(), + b".." => panic!(), + b"" => {}, + _ => panic!(), + } +} diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index f3f3c47680..33e8282c9d 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed for `std::vec::Vec` +error[E0282]: type annotations needed for `Vec` --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17 | LL | let mut x = Vec::new(); | ----- ^^^^^^^^ cannot infer type for type parameter `T` | | - | consider giving `x` the explicit type `std::vec::Vec`, where the type parameter `T` is specified + | consider giving `x` the explicit type `Vec`, where the type parameter `T` is specified error[E0308]: mismatched types --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20 diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr index 1b354fc697..42802ba1d0 100644 --- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr @@ -9,15 +9,15 @@ note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize` | LL | impl Me2 for usize { fn me(&self) -> usize { *self } } | ^^^^^^^^^^^^^^^^^^^^^ - = note: candidate #2 is defined in an impl of the trait `ambig_impl_2_lib::Me` for the type `usize` + = note: candidate #2 is defined in an impl of the trait `Me` for the type `usize` help: disambiguate the associated function for candidate #1 | LL | fn main() { Me2::me(&1_usize); } | ^^^^^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #2 | -LL | fn main() { ambig_impl_2_lib::Me::me(&1_usize); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn main() { Me::me(&1_usize); } + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index 4678642dd6..b0d1bb9823 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -38,17 +38,17 @@ LL | pub struct Foo; | --------------- | | | method `take` not found for this - | doesn't satisfy `Foo: std::iter::Iterator` + | doesn't satisfy `Foo: Iterator` ... LL | .take() | ^^^^ method not found in `Foo` | = note: the method `take` exists but the following trait bounds were not satisfied: - `Foo: std::iter::Iterator` - which is required by `&mut Foo: std::iter::Iterator` + `Foo: Iterator` + which is required by `&mut Foo: Iterator` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `take`, perhaps you need to implement it: - candidate #1: `std::iter::Iterator` + candidate #1: `Iterator` error[E0061]: this function takes 3 arguments but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:21:7 diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index 1bc7f30d04..08be7ee155 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -20,12 +20,12 @@ error[E0034]: multiple applicable items in scope LL | let z = x.foo(); | ^^^ multiple `foo` found | -note: candidate #1 is defined in an impl of the trait `internal::X` for the type `T` +note: candidate #1 is defined in an impl of the trait `X` for the type `T` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:43:9 | LL | fn foo(self: Smaht) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `T` +note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9 | LL | fn foo(self) {} @@ -37,12 +37,12 @@ LL | fn foo(&self) -> u8; | ^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #1 | -LL | let z = internal::X::foo(x); - | ^^^^^^^^^^^^^^^^^^^ +LL | let z = X::foo(x); + | ^^^^^^^^^ help: disambiguate the associated function for candidate #2 | -LL | let z = nuisance_foo::NuisanceFoo::foo(x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let z = NuisanceFoo::foo(x); + | ^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #3 | LL | let z = FinalFoo::foo(x); diff --git a/src/test/ui/methods/method-missing-call.stderr b/src/test/ui/methods/method-missing-call.stderr index bc8a1c85e5..241c50d7ce 100644 --- a/src/test/ui/methods/method-missing-call.stderr +++ b/src/test/ui/methods/method-missing-call.stderr @@ -9,7 +9,7 @@ help: use parentheses to call the method LL | .get_x(); | ^^ -error[E0615]: attempted to take value of method `filter_map` on type `std::iter::Filter, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>` +error[E0615]: attempted to take value of method `filter_map` on type `Filter, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>` --> $DIR/method-missing-call.rs:29:16 | LL | .filter_map; diff --git a/src/test/ui/minus-string.rs b/src/test/ui/minus-string.rs index 946c587ce4..018f0ef9ac 100644 --- a/src/test/ui/minus-string.rs +++ b/src/test/ui/minus-string.rs @@ -1,3 +1,3 @@ -// error-pattern:cannot apply unary operator `-` to type `std::string::String` +// error-pattern:cannot apply unary operator `-` to type `String` fn main() { -"foo".to_string(); } diff --git a/src/test/ui/minus-string.stderr b/src/test/ui/minus-string.stderr index 3fbec7c89c..b429ad3046 100644 --- a/src/test/ui/minus-string.stderr +++ b/src/test/ui/minus-string.stderr @@ -1,4 +1,4 @@ -error[E0600]: cannot apply unary operator `-` to type `std::string::String` +error[E0600]: cannot apply unary operator `-` to type `String` --> $DIR/minus-string.rs:3:13 | LL | fn main() { -"foo".to_string(); } diff --git a/src/test/ui/mir/issue-71793-inline-args-storage.rs b/src/test/ui/mir/issue-71793-inline-args-storage.rs new file mode 100644 index 0000000000..87b2806d4e --- /dev/null +++ b/src/test/ui/mir/issue-71793-inline-args-storage.rs @@ -0,0 +1,16 @@ +// Verifies that inliner emits StorageLive & StorageDead when introducing +// temporaries for arguments, so that they don't become part of the generator. +// Regression test for #71793. +// +// check-pass +// edition:2018 +// compile-args: -Zmir-opt-level=2 + +#![crate_type = "lib"] + +pub async fn connect() {} + +pub async fn connect_many() { + Vec::::new().first().ok_or("").unwrap(); + connect().await; +} diff --git a/src/test/ui/mir/issue-76248.rs b/src/test/ui/mir/issue-76248.rs new file mode 100644 index 0000000000..b01a972785 --- /dev/null +++ b/src/test/ui/mir/issue-76248.rs @@ -0,0 +1,29 @@ +// This used to ICE during codegen after MIR inlining of g into f. +// The root cause was a missing fold of length constant in Rvalue::Repeat. +// Regression test for #76248. +// +// build-pass +// compile-flags: -Zmir-opt-level=2 + +const N: usize = 1; + +pub struct Elem { + pub x: [usize; N], + pub m: M, +} + +pub fn f() -> Elem<()> { + g(()) +} + +#[inline] +pub fn g(m: M) -> Elem { + Elem { + x: [0; N], + m, + } +} + +pub fn main() { + f(); +} diff --git a/src/test/ui/mir/issue-76740-copy-propagation.rs b/src/test/ui/mir/issue-76740-copy-propagation.rs new file mode 100644 index 0000000000..90999a3e55 --- /dev/null +++ b/src/test/ui/mir/issue-76740-copy-propagation.rs @@ -0,0 +1,30 @@ +// Regression test for issue #76740. +// run-pass +// compile-flags: -Zmir-opt-level=3 + +#[derive(Copy, Clone)] +pub struct V([usize; 4]); + +impl V { + fn new() -> Self { + V([0; 4]) + } + + #[inline(never)] + fn check(mut self) { + assert_eq!(self.0[0], 0); + self.0[0] = 1; + } +} + +fn main() { + let v = V::new(); + let mut i = 0; + while i != 10 { + // Copy propagation incorrectly assumed that Operand::Move does not + // mutate the local, and used the same v for each V::check call, + // rather than a copy. + v.check(); + i += 1; + } +} diff --git a/src/test/ui/mir/issue-77359-simplify-arm-identity-.rs b/src/test/ui/mir/issue-77359-simplify-arm-identity-.rs new file mode 100644 index 0000000000..e58ba50a9e --- /dev/null +++ b/src/test/ui/mir/issue-77359-simplify-arm-identity-.rs @@ -0,0 +1,35 @@ +// run-pass + +#![allow(dead_code)] + +#[derive(Debug)] +enum MyEnum { + Variant1(Vec), + Variant2, + Variant3, + Variant4, +} + +fn f(arg1: &bool, arg2: &bool, arg3: bool) -> MyStruct { + if *arg1 { + println!("{:?}", f(&arg2, arg2, arg3)); + MyStruct(None) + } else { + match if arg3 { Some(MyEnum::Variant3) } else { None } { + Some(t) => { + let ah = t; + return MyStruct(Some(ah)); + } + _ => MyStruct(None) + } + } +} + +#[derive(Debug)] +struct MyStruct(Option); + +fn main() { + let arg1 = true; + let arg2 = false; + f(&arg1, &arg2, true); +} diff --git a/src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs b/src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs new file mode 100644 index 0000000000..629b50dec6 --- /dev/null +++ b/src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs @@ -0,0 +1,27 @@ +// compile-flags: -Z mir-opt-level=2 +// build-pass +#![crate_type="lib"] + +// This used to ICE: const-prop did not account for field reordering of scalar pairs, +// and would generate a tuple like `(0x1337, VariantBar): (FooEnum, isize)`, +// causing assertion failures in codegen when trying to read 0x1337 at the wrong type. + +pub enum FooEnum { + VariantBar, + VariantBaz, + VariantBuz, +} + +pub fn wrong_index() -> isize { + let (_, b) = id((FooEnum::VariantBar, 0x1337)); + b +} + +pub fn wrong_index_two() -> isize { + let (_, (_, b)) = id(((), (FooEnum::VariantBar, 0x1338))); + b +} + +fn id(x: T) -> T { + x +} diff --git a/src/test/ui/mir/mir_detects_invalid_ops.stderr b/src/test/ui/mir/mir_detects_invalid_ops.stderr index b4f74a52a7..0fe56f4172 100644 --- a/src/test/ui/mir/mir_detects_invalid_ops.stderr +++ b/src/test/ui/mir/mir_detects_invalid_ops.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/mir_detects_invalid_ops.rs:11:14 | LL | let _z = 1 / y; - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -10,7 +10,7 @@ error: this operation will panic at runtime --> $DIR/mir_detects_invalid_ops.rs:16:14 | LL | let _z = 1 % y; - | ^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero + | ^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index c73130643d..b7564686cd 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | fn a() -> Foo { | --- expected `Foo` because of return type LL | Some(Foo { bar: 1 }) - | ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option` + | ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `Option` | = note: expected struct `Foo` - found enum `std::option::Option` + found enum `Option` error[E0308]: mismatched types --> $DIR/abridged.rs:20:5 @@ -24,14 +24,14 @@ error[E0308]: mismatched types --> $DIR/abridged.rs:24:5 | LL | fn b() -> Option { - | ----------- expected `std::option::Option` because of return type + | ----------- expected `Option` because of return type LL | Foo { bar: 1 } | ^^^^^^^^^^^^^^ | | - | expected enum `std::option::Option`, found struct `Foo` + | expected enum `Option`, found struct `Foo` | help: try using a variant of the expected enum: `Some(Foo { bar: 1 })` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found struct `Foo` error[E0308]: mismatched types @@ -52,46 +52,46 @@ error[E0308]: mismatched types --> $DIR/abridged.rs:39:5 | LL | fn d() -> X, String> { - | ---------------------------- expected `X, std::string::String>` because of return type + | ---------------------------- expected `X, String>` because of return type ... LL | x - | ^ expected struct `std::string::String`, found integer + | ^ expected struct `String`, found integer | - = note: expected struct `X, std::string::String>` + = note: expected struct `X, String>` found struct `X, {integer}>` error[E0308]: mismatched types --> $DIR/abridged.rs:50:5 | LL | fn e() -> X, String> { - | ---------------------------- expected `X, std::string::String>` because of return type + | ---------------------------- expected `X, String>` because of return type ... LL | x - | ^ expected struct `std::string::String`, found integer + | ^ expected struct `String`, found integer | - = note: expected struct `X, _>` + = note: expected struct `X, _>` found struct `X, _>` error[E0308]: mismatched types --> $DIR/abridged.rs:54:5 | LL | fn f() -> String { - | ------ expected `std::string::String` because of return type + | ------ expected `String` because of return type LL | 1+2 | ^^^ | | - | expected struct `std::string::String`, found integer + | expected struct `String`, found integer | help: try using a conversion method: `(1+2).to_string()` error[E0308]: mismatched types --> $DIR/abridged.rs:59:5 | LL | fn g() -> String { - | ------ expected `std::string::String` because of return type + | ------ expected `String` because of return type LL | -2 | ^^ | | - | expected struct `std::string::String`, found integer + | expected struct `String`, found integer | help: try using a conversion method: `(-2).to_string()` error: aborting due to 8 previous errors diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs index 621599ddb8..12d4826649 100644 --- a/src/test/ui/mismatched_types/binops.rs +++ b/src/test/ui/mismatched_types/binops.rs @@ -1,8 +1,8 @@ fn main() { - 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}` - 2 as usize - Some(1); //~ ERROR cannot subtract `std::option::Option<{integer}>` from `usize` + 1 + Some(1); //~ ERROR cannot add `Option<{integer}>` to `{integer}` + 2 as usize - Some(1); //~ ERROR cannot subtract `Option<{integer}>` from `usize` 3 * (); //~ ERROR cannot multiply `()` to `{integer}` 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` - 5 < String::new(); //~ ERROR can't compare `{integer}` with `std::string::String` + 5 < String::new(); //~ ERROR can't compare `{integer}` with `String` 6 == Ok(1); //~ ERROR can't compare `{integer}` with `std::result::Result<{integer}, _>` } diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 9dda44a856..227c7887fb 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -1,18 +1,18 @@ -error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}` +error[E0277]: cannot add `Option<{integer}>` to `{integer}` --> $DIR/binops.rs:2:7 | LL | 1 + Some(1); - | ^ no implementation for `{integer} + std::option::Option<{integer}>` + | ^ no implementation for `{integer} + Option<{integer}>` | - = help: the trait `std::ops::Add>` is not implemented for `{integer}` + = help: the trait `Add>` is not implemented for `{integer}` -error[E0277]: cannot subtract `std::option::Option<{integer}>` from `usize` +error[E0277]: cannot subtract `Option<{integer}>` from `usize` --> $DIR/binops.rs:3:16 | LL | 2 as usize - Some(1); - | ^ no implementation for `usize - std::option::Option<{integer}>` + | ^ no implementation for `usize - Option<{integer}>` | - = help: the trait `std::ops::Sub>` is not implemented for `usize` + = help: the trait `Sub>` is not implemented for `usize` error[E0277]: cannot multiply `()` to `{integer}` --> $DIR/binops.rs:4:7 @@ -20,7 +20,7 @@ error[E0277]: cannot multiply `()` to `{integer}` LL | 3 * (); | ^ no implementation for `{integer} * ()` | - = help: the trait `std::ops::Mul<()>` is not implemented for `{integer}` + = help: the trait `Mul<()>` is not implemented for `{integer}` error[E0277]: cannot divide `{integer}` by `&str` --> $DIR/binops.rs:5:7 @@ -28,15 +28,15 @@ error[E0277]: cannot divide `{integer}` by `&str` LL | 4 / ""; | ^ no implementation for `{integer} / &str` | - = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}` + = help: the trait `Div<&str>` is not implemented for `{integer}` -error[E0277]: can't compare `{integer}` with `std::string::String` +error[E0277]: can't compare `{integer}` with `String` --> $DIR/binops.rs:6:7 | LL | 5 < String::new(); - | ^ no implementation for `{integer} < std::string::String` and `{integer} > std::string::String` + | ^ no implementation for `{integer} < String` and `{integer} > String` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `{integer}` + = help: the trait `PartialOrd` is not implemented for `{integer}` error[E0277]: can't compare `{integer}` with `std::result::Result<{integer}, _>` --> $DIR/binops.rs:7:7 @@ -44,7 +44,7 @@ error[E0277]: can't compare `{integer}` with `std::result::Result<{integer}, _>` LL | 6 == Ok(1); | ^^ no implementation for `{integer} == std::result::Result<{integer}, _>` | - = help: the trait `std::cmp::PartialEq>` is not implemented for `{integer}` + = help: the trait `PartialEq>` is not implemented for `{integer}` error: aborting due to 6 previous errors diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 71abda5206..388c978d03 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -44,7 +44,7 @@ error[E0605]: non-primitive cast: `*const u8` as `(u32,)` LL | let _ = v as (u32,); | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object -error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8` +error[E0605]: non-primitive cast: `Option<&*const u8>` as `*const u8` --> $DIR/cast-rfc0401.rs:33:13 | LL | let _ = Some(&v) as *const u8; @@ -208,7 +208,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | let _ = fat_v as *const dyn Foo; | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -217,7 +217,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | let _ = a as *const dyn Foo; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn Foo` error[E0606]: casting `&{float}` as `f32` is invalid diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 664fa4bcaf..0af44d2119 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -28,8 +28,8 @@ error[E0308]: mismatched types LL | baz(f); | ^^^ one type is more general than the other | - = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` - found type `std::ops::Fn<(*mut &'a u32,)>` + = note: expected type `for<'r> Fn<(*mut &'r u32,)>` + found type `Fn<(*mut &'a u32,)>` error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 @@ -37,8 +37,8 @@ error[E0308]: mismatched types LL | baz(f); | ^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(*mut &u32,)>` - found type `std::ops::FnOnce<(*mut &'a u32,)>` + = note: expected type `FnOnce<(*mut &u32,)>` + found type `FnOnce<(*mut &'a u32,)>` error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 @@ -46,8 +46,8 @@ error[E0308]: mismatched types LL | baz(f); | ^^^ one type is more general than the other | - = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` - found type `std::ops::Fn<(*mut &'a u32,)>` + = note: expected type `for<'r> Fn<(*mut &'r u32,)>` + found type `Fn<(*mut &'a u32,)>` error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 @@ -55,8 +55,8 @@ error[E0308]: mismatched types LL | baz(f); | ^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(*mut &u32,)>` - found type `std::ops::FnOnce<(*mut &'a u32,)>` + = note: expected type `FnOnce<(*mut &u32,)>` + found type `FnOnce<(*mut &'a u32,)>` error: aborting due to 7 previous errors diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index d6c17d125c..149f505dc6 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | baz(|_| ()); | ^^^ one type is more general than the other | - = note: expected type `for<'r> std::ops::Fn<(&'r (),)>` - found type `std::ops::Fn<(&(),)>` + = note: expected type `for<'r> Fn<(&'r (),)>` + found type `Fn<(&(),)>` error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index 213b61bc6f..63c04bcd7b 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -1,24 +1,24 @@ -error[E0599]: no method named `count` found for struct `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope +error[E0599]: no method named `count` found for struct `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope --> $DIR/issue-36053-2.rs:7:55 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | -------------- ^^^^^ method not found in `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` + | -------------- ^^^^^ method not found in `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` | | - | doesn't satisfy `<_ as std::ops::FnOnce<(&&str,)>>::Output = bool` - | doesn't satisfy `_: std::ops::FnMut<(&&str,)>` + | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` + | doesn't satisfy `_: FnMut<(&&str,)>` | ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL | LL | pub struct Filter { - | ----------------------- doesn't satisfy `_: std::iter::Iterator` + | ----------------------- doesn't satisfy `_: Iterator` | = note: the method `count` exists but the following trait bounds were not satisfied: - `<[closure@$DIR/issue-36053-2.rs:7:39: 7:53] as std::ops::FnOnce<(&&str,)>>::Output = bool` - which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: std::iter::Iterator` - `[closure@$DIR/issue-36053-2.rs:7:39: 7:53]: std::ops::FnMut<(&&str,)>` - which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: std::iter::Iterator` - `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: std::iter::Iterator` - which is required by `&mut std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: std::iter::Iterator` + `<[closure@$DIR/issue-36053-2.rs:7:39: 7:53] as FnOnce<(&&str,)>>::Output = bool` + which is required by `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` + `[closure@$DIR/issue-36053-2.rs:7:39: 7:53]: FnMut<(&&str,)>` + which is required by `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` + `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` + which is required by `&mut Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` error[E0631]: type mismatch in closure arguments --> $DIR/issue-36053-2.rs:7:32 diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr index d260addef4..5df35fa571 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr @@ -13,15 +13,15 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/issue-74918-missing-lifetime.rs:11:5 | LL | fn next(&mut self) -> Option> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&mut ChunkingIterator) -> std::option::Option>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&mut ChunkingIterator) -> Option>` | ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | LL | fn next(&mut self) -> Option; - | ----------------------------------------- expected `fn(&mut ChunkingIterator) -> std::option::Option>` + | ----------------------------------------- expected `fn(&mut ChunkingIterator) -> Option>` | - = note: expected `fn(&mut ChunkingIterator) -> std::option::Option>` - found `fn(&mut ChunkingIterator) -> std::option::Option>` + = note: expected `fn(&mut ChunkingIterator) -> Option>` + found `fn(&mut ChunkingIterator) -> Option>` = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output diff --git a/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr index 5be7f5271d..4b86a1fede 100644 --- a/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr +++ b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr @@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/issue-75361-mismatched-impl.rs:18:3 | LL | fn adjacent_edges(&self) -> Box>; - | --------------------------------------------------------------------- expected `fn(&T) -> std::boxed::Box<(dyn MyTrait + 'static)>` + | --------------------------------------------------------------------- expected `fn(&T) -> Box<(dyn MyTrait + 'static)>` ... LL | fn adjacent_edges(&self) -> Box + '_> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&T) -> std::boxed::Box>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&T) -> Box>` | - = note: expected `fn(&T) -> std::boxed::Box<(dyn MyTrait + 'static)>` - found `fn(&T) -> std::boxed::Box>` + = note: expected `fn(&T) -> Box<(dyn MyTrait + 'static)>` + found `fn(&T) -> Box>` help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` --> $DIR/issue-75361-mismatched-impl.rs:12:55 | diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr index 5ab191b927..67f79a8147 100644 --- a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -2,13 +2,13 @@ error[E0599]: no method named `unwrap` found for enum `std::result::Result<(), F --> $DIR/method-help-unsatisfied-bound.rs:5:7 | LL | struct Foo; - | ----------- doesn't satisfy `Foo: std::fmt::Debug` + | ----------- doesn't satisfy `Foo: Debug` ... LL | a.unwrap(); | ^^^^^^ method not found in `std::result::Result<(), Foo>` | = note: the method `unwrap` exists but the following trait bounds were not satisfied: - `Foo: std::fmt::Debug` + `Foo: Debug` error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr index d9dd186624..485fae6d4d 100644 --- a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr +++ b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/trait-bounds-cant-coerce.rs:13:7 | LL | a(x); - | ^ expected trait `Foo + std::marker::Send`, found trait `Foo` + | ^ expected trait `Foo + Send`, found trait `Foo` | - = note: expected struct `std::boxed::Box<(dyn Foo + std::marker::Send + 'static)>` - found struct `std::boxed::Box<(dyn Foo + 'static)>` + = note: expected struct `Box<(dyn Foo + Send + 'static)>` + found struct `Box<(dyn Foo + 'static)>` error: aborting due to previous error diff --git a/src/test/ui/missing/missing-items/m2.stderr b/src/test/ui/missing/missing-items/m2.stderr index 64e9530e61..d18fb443aa 100644 --- a/src/test/ui/missing/missing-items/m2.stderr +++ b/src/test/ui/missing/missing-items/m2.stderr @@ -6,11 +6,11 @@ LL | impl m1::X for X { | = help: implement the missing item: `const CONSTANT: u32 = 42;` = help: implement the missing item: `type Type = Type;` - = help: implement the missing item: `fn method(&self, _: std::string::String) -> ::Type { todo!() }` - = help: implement the missing item: `fn method2(self: std::boxed::Box, _: std::string::String) -> ::Type { todo!() }` - = help: implement the missing item: `fn method3(_: &Self, _: std::string::String) -> ::Type { todo!() }` + = help: implement the missing item: `fn method(&self, _: String) -> ::Type { todo!() }` + = help: implement the missing item: `fn method2(self: Box, _: String) -> ::Type { todo!() }` + = help: implement the missing item: `fn method3(_: &Self, _: String) -> ::Type { todo!() }` = help: implement the missing item: `fn method4(&self, _: &Self) -> ::Type { todo!() }` - = help: implement the missing item: `fn method5(self: &std::boxed::Box) -> ::Type { todo!() }` + = help: implement the missing item: `fn method5(self: &Box) -> ::Type { todo!() }` error: aborting due to previous error diff --git a/src/test/ui/missing_debug_impls.rs b/src/test/ui/missing_debug_impls.rs index 72fcba5158..dc4dacfc46 100644 --- a/src/test/ui/missing_debug_impls.rs +++ b/src/test/ui/missing_debug_impls.rs @@ -4,7 +4,7 @@ use std::fmt; -pub enum A {} //~ ERROR type does not implement `std::fmt::Debug` +pub enum A {} //~ ERROR type does not implement `Debug` #[derive(Debug)] pub enum B {} @@ -17,7 +17,7 @@ impl fmt::Debug for C { } } -pub struct Foo; //~ ERROR type does not implement `std::fmt::Debug` +pub struct Foo; //~ ERROR type does not implement `Debug` #[derive(Debug)] pub struct Bar; diff --git a/src/test/ui/missing_debug_impls.stderr b/src/test/ui/missing_debug_impls.stderr index 51c65589b0..0538f207b4 100644 --- a/src/test/ui/missing_debug_impls.stderr +++ b/src/test/ui/missing_debug_impls.stderr @@ -1,4 +1,4 @@ -error: type does not implement `std::fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation +error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation --> $DIR/missing_debug_impls.rs:7:1 | LL | pub enum A {} @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(missing_debug_implementations)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: type does not implement `std::fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation +error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation --> $DIR/missing_debug_impls.rs:20:1 | LL | pub struct Foo; diff --git a/src/test/ui/mod/mod_file_disambig.rs b/src/test/ui/mod/mod_file_disambig.rs index 7b182421d3..e5958af173 100644 --- a/src/test/ui/mod/mod_file_disambig.rs +++ b/src/test/ui/mod/mod_file_disambig.rs @@ -2,5 +2,5 @@ mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` fou fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 2cb99b7514..3a3d2e2ddd 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -6,11 +6,11 @@ LL | mod mod_file_disambig_aux; | = help: delete or rename one of them to remove the ambiguity -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_disambig.rs:4:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/moves/issue-46099-move-in-macro.stderr b/src/test/ui/moves/issue-46099-move-in-macro.stderr index 83c99db870..db4c3979e3 100644 --- a/src/test/ui/moves/issue-46099-move-in-macro.stderr +++ b/src/test/ui/moves/issue-46099-move-in-macro.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `b` --> $DIR/issue-46099-move-in-macro.rs:14:12 | LL | let b = Box::new(true); - | - move occurs because `b` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `b` has type `Box`, which does not implement the `Copy` trait LL | test!({b}); | ^ | | diff --git a/src/test/ui/moves/issue-75904-move-closure-loop.rs b/src/test/ui/moves/issue-75904-move-closure-loop.rs new file mode 100644 index 0000000000..6641a0376c --- /dev/null +++ b/src/test/ui/moves/issue-75904-move-closure-loop.rs @@ -0,0 +1,15 @@ +// Regression test for issue #75904 +// Tests that we point at an expression +// that required the upvar to be moved, rather than just borrowed. + +struct NotCopy; + +fn main() { + let mut a = NotCopy; + loop { + || { //~ ERROR use of moved value + &mut a; + a; + }; + } +} diff --git a/src/test/ui/moves/issue-75904-move-closure-loop.stderr b/src/test/ui/moves/issue-75904-move-closure-loop.stderr new file mode 100644 index 0000000000..5e427a1fcd --- /dev/null +++ b/src/test/ui/moves/issue-75904-move-closure-loop.stderr @@ -0,0 +1,15 @@ +error[E0382]: use of moved value: `a` + --> $DIR/issue-75904-move-closure-loop.rs:10:9 + | +LL | let mut a = NotCopy; + | ----- move occurs because `a` has type `NotCopy`, which does not implement the `Copy` trait +LL | loop { +LL | || { + | ^^ value moved into closure here, in previous iteration of loop +LL | &mut a; +LL | a; + | - use occurs due to use in closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-deref-coercion.rs b/src/test/ui/moves/move-deref-coercion.rs new file mode 100644 index 0000000000..41154388f5 --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.rs @@ -0,0 +1,33 @@ +use std::ops::Deref; + +struct NotCopy { + inner: bool +} + +impl NotCopy { + fn inner_method(&self) {} +} + +struct Foo { + first: NotCopy, + second: NotCopy +} + +impl Deref for Foo { + type Target = NotCopy; + fn deref(&self) -> &NotCopy { + &self.second + } +} + +fn use_field(val: Foo) { + let _val = val.first; + val.inner; //~ ERROR borrow of +} + +fn use_method(val: Foo) { + let _val = val.first; + val.inner_method(); //~ ERROR borrow of +} + +fn main() {} diff --git a/src/test/ui/moves/move-deref-coercion.stderr b/src/test/ui/moves/move-deref-coercion.stderr new file mode 100644 index 0000000000..e3bdf6d783 --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.stderr @@ -0,0 +1,35 @@ +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:25:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner; + | ^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:30:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner_method(); + | ^^^^^^^^^^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr index 671d07a281..dd263c1e90 100644 --- a/src/test/ui/moves/move-fn-self-receiver.stderr +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -11,7 +11,7 @@ note: this function consumes the receiver `self` by taking ownership of it, whic | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ - = note: move occurs because `val.0` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because `val.0` has type `Vec`, which does not implement the `Copy` trait error[E0382]: use of moved value: `foo` --> $DIR/move-fn-self-receiver.rs:34:5 @@ -43,7 +43,7 @@ error[E0382]: use of moved value: `boxed_foo` --> $DIR/move-fn-self-receiver.rs:42:5 | LL | let boxed_foo = Box::new(Foo); - | --------- move occurs because `boxed_foo` has type `std::boxed::Box`, which does not implement the `Copy` trait + | --------- move occurs because `boxed_foo` has type `Box`, which does not implement the `Copy` trait LL | boxed_foo.use_box_self(); | -------------- `boxed_foo` moved due to this method call LL | boxed_foo; @@ -59,7 +59,7 @@ error[E0382]: use of moved value: `pin_box_foo` --> $DIR/move-fn-self-receiver.rs:46:5 | LL | let pin_box_foo = Box::pin(Foo); - | ----------- move occurs because `pin_box_foo` has type `std::pin::Pin>`, which does not implement the `Copy` trait + | ----------- move occurs because `pin_box_foo` has type `Pin>`, which does not implement the `Copy` trait LL | pin_box_foo.use_pin_box_self(); | ------------------ `pin_box_foo` moved due to this method call LL | pin_box_foo; @@ -85,7 +85,7 @@ error[E0382]: use of moved value: `rc_foo` --> $DIR/move-fn-self-receiver.rs:55:5 | LL | let rc_foo = Rc::new(Foo); - | ------ move occurs because `rc_foo` has type `std::rc::Rc`, which does not implement the `Copy` trait + | ------ move occurs because `rc_foo` has type `Rc`, which does not implement the `Copy` trait LL | rc_foo.use_rc_self(); | ------------- `rc_foo` moved due to this method call LL | rc_foo; @@ -117,7 +117,7 @@ error[E0382]: use of moved value: `implicit_into_iter` --> $DIR/move-fn-self-receiver.rs:63:5 | LL | let implicit_into_iter = vec![true]; - | ------------------ move occurs because `implicit_into_iter` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ------------------ move occurs because `implicit_into_iter` has type `Vec`, which does not implement the `Copy` trait LL | for _val in implicit_into_iter {} | ------------------ | | @@ -130,7 +130,7 @@ error[E0382]: use of moved value: `explicit_into_iter` --> $DIR/move-fn-self-receiver.rs:67:5 | LL | let explicit_into_iter = vec![true]; - | ------------------ move occurs because `explicit_into_iter` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ------------------ move occurs because `explicit_into_iter` has type `Vec`, which does not implement the `Copy` trait LL | for _val in explicit_into_iter.into_iter() {} | ----------- `explicit_into_iter` moved due to this method call LL | explicit_into_iter; diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr index 0945fbe68a..5fc8a54993 100644 --- a/src/test/ui/moves/move-guard-same-consts.stderr +++ b/src/test/ui/moves/move-guard-same-consts.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-guard-same-consts.rs:20:24 | LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (1, 2) if take(x) => (), | - value moved here diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr index 542fd16986..d894209f51 100644 --- a/src/test/ui/moves/move-in-guard-1.stderr +++ b/src/test/ui/moves/move-in-guard-1.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-in-guard-1.rs:10:24 | LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (1, _) if take(x) => (), | - value moved here diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr index 00d89f5507..a067d43389 100644 --- a/src/test/ui/moves/move-in-guard-2.stderr +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-in-guard-2.rs:10:24 | LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (_, 2) if take(x) => (), | ^ diff --git a/src/test/ui/moves/move-out-of-tuple-field.stderr b/src/test/ui/moves/move-out-of-tuple-field.stderr index 888ef3352e..bb4eb76772 100644 --- a/src/test/ui/moves/move-out-of-tuple-field.stderr +++ b/src/test/ui/moves/move-out-of-tuple-field.stderr @@ -6,7 +6,7 @@ LL | let y = x.0; LL | let z = x.0; | ^^^ value used here after move | - = note: move occurs because `x.0` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.0` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.0` --> $DIR/move-out-of-tuple-field.rs:12:13 @@ -16,7 +16,7 @@ LL | let y = x.0; LL | let z = x.0; | ^^^ value used here after move | - = note: move occurs because `x.0` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.0` has type `Box`, which does not implement the `Copy` trait error: aborting due to 2 previous errors diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr index aa0e9c7f68..11e9456958 100644 --- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-access-to-field.rs:11:12 | LL | let x = vec!["hi".to_string()]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | consume(x.into_iter().next().unwrap()); | ----------- `x` moved due to this method call LL | touch(&x[0]); diff --git a/src/test/ui/moves/moves-based-on-type-block-bad.stderr b/src/test/ui/moves/moves-based-on-type-block-bad.stderr index 12b87c54b9..a9ac9d63a9 100644 --- a/src/test/ui/moves/moves-based-on-type-block-bad.stderr +++ b/src/test/ui/moves/moves-based-on-type-block-bad.stderr @@ -8,7 +8,7 @@ LL | box E::Bar(x) => println!("{}", x.to_string()), | - | | | data moved here - | move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `x` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr index 3a05a1305b..acb0932f6d 100644 --- a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr +++ b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-capture-clause-bad.rs:8:20 | LL | let x = "Hello world!".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | thread::spawn(move|| { | ------ value moved into closure here LL | println!("{}", x); diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs index b070671cb2..4417fb926d 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs @@ -10,7 +10,7 @@ fn foo(node: Box) -> isize { Some(right) => consume(right), None => 0 }; - consume(node) + r //~ ERROR use of moved value: `node` + consume(node) + r //~ ERROR use of partially moved value: `node` } fn consume(v: Box) -> isize { diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr index 952985fcdd..f7e17815b6 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr @@ -1,13 +1,13 @@ -error[E0382]: use of moved value: `node` +error[E0382]: use of partially moved value: `node` --> $DIR/moves-based-on-type-cyclic-types-issue-4821.rs:13:13 | LL | Some(right) => consume(right), - | ----- value moved here + | ----- value partially moved here ... LL | consume(node) + r | ^^^^ value used here after partial move | - = note: move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `Box`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `node.next.0` | LL | Some(ref right) => consume(right), diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs index 0b44ca56ce..d256e18b6c 100644 --- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs +++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs @@ -6,7 +6,7 @@ fn touch(_a: &A) {} fn f00() { let x = "hi".to_string(); - //~^ NOTE move occurs because `x` has type `std::string::String` + //~^ NOTE move occurs because `x` has type `String` let _y = Foo { f:x }; //~^ NOTE value moved here touch(&x); //~ ERROR borrow of moved value: `x` @@ -15,7 +15,7 @@ fn f00() { fn f05() { let x = "hi".to_string(); - //~^ NOTE move occurs because `x` has type `std::string::String` + //~^ NOTE move occurs because `x` has type `String` let _y = Foo { f:(((x))) }; //~^ NOTE value moved here touch(&x); //~ ERROR borrow of moved value: `x` diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr index d7a7ceabf8..ee7971691a 100644 --- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr +++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:12:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | LL | let _y = Foo { f:x }; | - value moved here @@ -14,7 +14,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:21:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | LL | let _y = Foo { f:(((x))) }; | ------- value moved here diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index 95a591b225..46940cf493 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:12:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = Foo { f:x }; | - value moved here LL | touch(&x); @@ -12,7 +12,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:18:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = (x, 3); | - value moved here LL | touch(&x); @@ -22,7 +22,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:35:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | x | - value moved here @@ -34,7 +34,7 @@ error[E0382]: borrow of moved value: `y` --> $DIR/moves-based-on-type-exprs.rs:36:11 | LL | let y = "ho".to_string(); - | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `y` has type `String`, which does not implement the `Copy` trait ... LL | y | - value moved here @@ -46,7 +46,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:46:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | true => x, | - value moved here @@ -58,7 +58,7 @@ error[E0382]: borrow of moved value: `y` --> $DIR/moves-based-on-type-exprs.rs:47:11 | LL | let y = "ho".to_string(); - | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `y` has type `String`, which does not implement the `Copy` trait ... LL | false => y | - value moved here @@ -70,7 +70,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:58:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | _ if guard(x) => 10, | - value moved here @@ -82,7 +82,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:65:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = [x]; | - value moved here LL | touch(&x); @@ -92,7 +92,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:71:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = vec![x]; | - value moved here LL | touch(&x); @@ -102,7 +102,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:77:11 | LL | let x = vec!["hi".to_string()]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | let _y = x.into_iter().next().unwrap(); | ----------- `x` moved due to this method call LL | touch(&x); @@ -118,7 +118,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:83:11 | LL | let x = vec!["hi".to_string()]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | let _y = [x.into_iter().next().unwrap(); 1]; | ----------- `x` moved due to this method call LL | touch(&x); diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.rs b/src/test/ui/moves/moves-based-on-type-match-bindings.rs index 1290d4a25a..4fb9b40e87 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.rs +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.rs @@ -13,9 +13,9 @@ fn f10() { Foo {f} => {} }; - touch(&x); //~ ERROR borrow of moved value: `x` + touch(&x); //~ ERROR borrow of partially moved value: `x` //~^ value borrowed here after partial move - //~| move occurs because `x.f` has type `std::string::String` + //~| partial move occurs because `x.f` has type `String` } fn main() {} diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr index 322999a1f0..ad1a2db8b5 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr @@ -1,13 +1,13 @@ -error[E0382]: borrow of moved value: `x` +error[E0382]: borrow of partially moved value: `x` --> $DIR/moves-based-on-type-match-bindings.rs:16:11 | LL | Foo {f} => {} - | - value moved here + | - value partially moved here ... LL | touch(&x); | ^^ value borrowed here after partial move | - = note: move occurs because `x.f` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `x.f` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr index fafd377c12..462bbd7be5 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure LL | let i = box 3; | - captured outer variable LL | let _f = to_fn(|| test(i)); - | ^ move occurs because `i` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `i` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr index 2e1ddbdf57..a52c023e20 100644 --- a/src/test/ui/moves/moves-based-on-type-tuple.stderr +++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/moves-based-on-type-tuple.rs:4:13 | LL | fn dup(x: Box) -> Box<(Box,Box)> { - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | box (x, x) | - ^ value used here after move | | diff --git a/src/test/ui/moves/moves-sru-moved-field.stderr b/src/test/ui/moves/moves-sru-moved-field.stderr index a012c2d9b7..cf7213637c 100644 --- a/src/test/ui/moves/moves-sru-moved-field.stderr +++ b/src/test/ui/moves/moves-sru-moved-field.stderr @@ -6,7 +6,7 @@ LL | let _b = Foo {noncopyable: g, ..f}; LL | let _c = Foo {noncopyable: h, ..f}; | ^^^^^^^^^^^^^^^^^^^^^^^^^ value used here after move | - = note: move occurs because `f.moved` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `f.moved` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/mut/mut-cross-borrowing.stderr b/src/test/ui/mut/mut-cross-borrowing.stderr index c262d1336a..b77813f8af 100644 --- a/src/test/ui/mut/mut-cross-borrowing.stderr +++ b/src/test/ui/mut/mut-cross-borrowing.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | f(x) | ^ | | - | expected `&mut isize`, found struct `std::boxed::Box` + | expected `&mut isize`, found struct `Box` | help: consider mutably borrowing here: `&mut x` | = note: expected mutable reference `&mut isize` - found struct `std::boxed::Box<{integer}>` + found struct `Box<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/mut/mutable-enum-indirect.stderr b/src/test/ui/mut/mutable-enum-indirect.stderr index 9decba790d..3be6acb41a 100644 --- a/src/test/ui/mut/mutable-enum-indirect.stderr +++ b/src/test/ui/mut/mutable-enum-indirect.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(&x); | ^^^ `NoSync` cannot be shared between threads safely | - = help: within `&Foo`, the trait `std::marker::Sync` is not implemented for `NoSync` + = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync` = note: required because it appears within the type `Foo` = note: required because it appears within the type `&Foo` diff --git a/src/test/ui/mutexguard-sync.rs b/src/test/ui/mutexguard-sync.rs index 8e1370041d..b564183831 100644 --- a/src/test/ui/mutexguard-sync.rs +++ b/src/test/ui/mutexguard-sync.rs @@ -9,5 +9,5 @@ fn main() let m = Mutex::new(Cell::new(0i32)); let guard = m.lock().unwrap(); test_sync(guard); - //~^ ERROR `std::cell::Cell` cannot be shared between threads safely [E0277] + //~^ ERROR `Cell` cannot be shared between threads safely [E0277] } diff --git a/src/test/ui/mutexguard-sync.stderr b/src/test/ui/mutexguard-sync.stderr index 8b5362490b..588c32a755 100644 --- a/src/test/ui/mutexguard-sync.stderr +++ b/src/test/ui/mutexguard-sync.stderr @@ -1,14 +1,14 @@ -error[E0277]: `std::cell::Cell` cannot be shared between threads safely +error[E0277]: `Cell` cannot be shared between threads safely --> $DIR/mutexguard-sync.rs:11:15 | LL | fn test_sync(_t: T) {} | ---- required by this bound in `test_sync` ... LL | test_sync(guard); - | ^^^^^ `std::cell::Cell` cannot be shared between threads safely + | ^^^^^ `Cell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` - = note: required because of the requirements on the impl of `std::marker::Sync` for `std::sync::MutexGuard<'_, std::cell::Cell>` + = help: the trait `Sync` is not implemented for `Cell` + = note: required because of the requirements on the impl of `Sync` for `MutexGuard<'_, Cell>` error: aborting due to previous error diff --git a/src/test/ui/never_type/issue-13352.stderr b/src/test/ui/never_type/issue-13352.stderr index 58ac74be3e..93c792a72e 100644 --- a/src/test/ui/never_type/issue-13352.stderr +++ b/src/test/ui/never_type/issue-13352.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot add `()` to `usize` LL | 2_usize + (loop {}); | ^ no implementation for `usize + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `usize` + = help: the trait `Add<()>` is not implemented for `usize` error: aborting due to previous error diff --git a/src/test/ui/never_type/issue-2149.stderr b/src/test/ui/never_type/issue-2149.stderr index 3cdd6372ec..58fe2edb1e 100644 --- a/src/test/ui/never_type/issue-2149.stderr +++ b/src/test/ui/never_type/issue-2149.stderr @@ -1,10 +1,10 @@ -error[E0277]: cannot add `std::vec::Vec` to `()` +error[E0277]: cannot add `Vec` to `()` --> $DIR/issue-2149.rs:8:33 | LL | for elt in self { r = r + f(*elt); } - | ^ no implementation for `() + std::vec::Vec` + | ^ no implementation for `() + Vec` | - = help: the trait `std::ops::Add>` is not implemented for `()` + = help: the trait `Add>` is not implemented for `()` error[E0599]: no method named `bind` found for array `[&str; 1]` in the current scope --> $DIR/issue-2149.rs:13:12 diff --git a/src/test/ui/never_type/issue-51506.stderr b/src/test/ui/never_type/issue-51506.stderr index 73865a9b5a..c54cbe9b4d 100644 --- a/src/test/ui/never_type/issue-51506.stderr +++ b/src/test/ui/never_type/issue-51506.stderr @@ -7,7 +7,7 @@ LL | type Out: Iterator; LL | default type Out = !; | ^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `!` + = help: the trait `Iterator` is not implemented for `!` error: aborting due to previous error diff --git a/src/test/ui/nll/cannot-move-block-spans.stderr b/src/test/ui/nll/cannot-move-block-spans.stderr index 7db5d731ac..56a5cdff07 100644 --- a/src/test/ui/nll/cannot-move-block-spans.stderr +++ b/src/test/ui/nll/cannot-move-block-spans.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let x = { *r }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -13,7 +13,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let y = unsafe { *r }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -22,37 +22,37 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let z = loop { break *r; }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` -error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array +error[E0508]: cannot move out of type `[String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:11:15 | LL | let x = { arr[0] }; | ^^^^^^ | | | cannot move out of here - | move occurs because `arr[_]` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&arr[0]` -error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array +error[E0508]: cannot move out of type `[String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:12:22 | LL | let y = unsafe { arr[0] }; | ^^^^^^ | | | cannot move out of here - | move occurs because `arr[_]` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&arr[0]` -error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array +error[E0508]: cannot move out of type `[String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:13:26 | LL | let z = loop { break arr[0]; }; | ^^^^^^ | | | cannot move out of here - | move occurs because `arr[_]` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&arr[0]` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -61,7 +61,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let x = { let mut u = 0; u += 1; *r }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -70,7 +70,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let y = unsafe { let mut u = 0; u += 1; *r }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -79,7 +79,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error: aborting due to 9 previous errors diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr index 4a8086905b..ccc043a189 100644 --- a/src/test/ui/nll/closure-access-spans.stderr +++ b/src/test/ui/nll/closure-access-spans.stderr @@ -60,7 +60,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:35:5 | LL | fn closure_imm_capture_moved(mut x: String) { - | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here LL | || x.len(); @@ -72,7 +72,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:40:5 | LL | fn closure_mut_capture_moved(mut x: String) { - | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here LL | || x = String::new(); @@ -84,7 +84,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:45:5 | LL | fn closure_unique_capture_moved(x: &mut String) { - | - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `&mut String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here LL | || *x = String::new(); @@ -96,7 +96,7 @@ error[E0382]: use of moved value: `x` --> $DIR/closure-access-spans.rs:50:5 | LL | fn closure_move_capture_moved(x: &mut String) { - | - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `&mut String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here LL | || x; diff --git a/src/test/ui/nll/closure-move-spans.stderr b/src/test/ui/nll/closure-move-spans.stderr index 972dbc6a61..0446ef7b06 100644 --- a/src/test/ui/nll/closure-move-spans.stderr +++ b/src/test/ui/nll/closure-move-spans.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/closure-move-spans.rs:5:13 | LL | fn move_after_move(x: String) { - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | || x; | -- - variable moved due to use in closure | | @@ -14,7 +14,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-move-spans.rs:10:13 | LL | fn borrow_after_move(x: String) { - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | || x; | -- - variable moved due to use in closure | | @@ -26,7 +26,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-move-spans.rs:15:13 | LL | fn borrow_mut_after_move(mut x: String) { - | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | || x; | -- - variable moved due to use in closure | | diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index f0d169f419..799ed89dcc 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) i32)), (), diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index e251e69997..a094fc4517 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)), (), diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index 36257700be..1a82583761 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -4,7 +4,7 @@ note: external requirements LL | let mut closure1 = || p = &y; | ^^^^^^^^^ | - = note: defining type: test::{{closure}}#0::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0}::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), (&'_#1r i32, &'_#2r mut &'_#3r i32), @@ -22,7 +22,7 @@ LL | | closure1(); LL | | }; | |_________^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), (&'_#1r i32, &'_#2r mut &'_#3r i32), diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index d1c64fac3c..29fd796882 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -4,7 +4,7 @@ note: external requirements LL | let mut closure = || p = &y; | ^^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), (&'_#1r i32, &'_#2r mut &'_#3r i32), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 549ebb78d7..c4f4facae1 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -8,7 +8,7 @@ LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), @@ -21,9 +21,9 @@ error: lifetime may not live long enough --> $DIR/propagate-approximated-fail-no-postdom.rs:46:13 | LL | |_outlives1, _outlives2, _outlives3, x, y| { - | ---------- ---------- has type `std::cell::Cell<&'2 &'_#3r u32>` + | ---------- ---------- has type `Cell<&'2 &'_#3r u32>` | | - | has type `std::cell::Cell<&'_#1r &'1 u32>` + | has type `Cell<&'_#1r &'1 u32>` ... LL | demand_y(x, y, p) | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index 346b4af6ca..c1450564c4 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 3b1769ed3a..e7b8dff4e7 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -8,7 +8,7 @@ LL | | LL | | }) | |_____^ | - = note: defining type: case1::{{closure}}#0 with closure substs [ + = note: defining type: case1::{closure#0} with closure substs [ i32, for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), (), @@ -47,7 +47,7 @@ LL | | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static LL | | }) | |_____^ | - = note: defining type: case2::{{closure}}#0 with closure substs [ + = note: defining type: case2::{closure#0} with closure substs [ i32, for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index b167dafff0..c7e68d02dc 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -10,7 +10,7 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t2)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 91aacc3dff..abbc76eaf4 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -10,7 +10,7 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index ae44770862..c91b514a79 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index 256446a6e8..4ddf6f8323 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -8,7 +8,7 @@ LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 5c156d0d1e..6dc6f45680 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), @@ -21,9 +21,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | --------- - has type `&'_#7r std::cell::Cell<&'1 u32>` + | --------- - has type `&'_#7r Cell<&'1 u32>` | | - | has type `&'_#5r std::cell::Cell<&'2 &'_#1r u32>` + | has type `&'_#5r Cell<&'2 &'_#1r u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 46e3f2e75f..6bcada5c26 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), (), @@ -21,9 +21,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | ---------- ---------- has type `&'_#8r std::cell::Cell<&'2 &'_#2r u32>` + | ---------- ---------- has type `&'_#8r Cell<&'2 &'_#2r u32>` | | - | has type `&'_#6r std::cell::Cell<&'1 &'_#1r u32>` + | has type `&'_#6r Cell<&'1 &'_#1r u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index ef94147289..4b860a5505 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -11,7 +11,7 @@ LL | | require(value); LL | | }); | |_____^ | - = note: defining type: supply::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: supply::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((T,)), (), diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 2a382030f9..1da6c6d2c6 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | expect_sig(|a, b| b); // ought to return `a` | ^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, (), diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr index 0b15d9bcfe..37638a93d7 100644 --- a/src/test/ui/nll/closures-in-loops.stderr +++ b/src/test/ui/nll/closures-in-loops.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/closures-in-loops.rs:6:9 | LL | fn repreated_move(x: String) { - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | for i in 0..10 { LL | || x; | ^^ - use occurs due to use in closure diff --git a/src/test/ui/nll/guarantor-issue-46974.stderr b/src/test/ui/nll/guarantor-issue-46974.stderr index 80df393598..361466c4d5 100644 --- a/src/test/ui/nll/guarantor-issue-46974.stderr +++ b/src/test/ui/nll/guarantor-issue-46974.stderr @@ -13,7 +13,7 @@ error[E0621]: explicit lifetime required in the type of `s` --> $DIR/guarantor-issue-46974.rs:15:5 | LL | fn bar(s: &Box<(i32,)>) -> &'static i32 { - | ------------ help: add explicit lifetime `'static` to the type of `s`: `&'static std::boxed::Box<(i32,)>` + | ------------ help: add explicit lifetime `'static` to the type of `s`: `&'static Box<(i32,)>` LL | // FIXME(#46983): error message should be better LL | &s.0 | ^^^^ lifetime `'static` required diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr index 9e69262b38..77fa484c21 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr +++ b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr @@ -16,7 +16,7 @@ error[E0382]: assign to part of moved value: `s` LL | let mut s: S = S::new(); drop(s); | ----- - value moved here | | - | move occurs because `s` has type `S>`, which does not implement the `Copy` trait + | move occurs because `s` has type `S>`, which does not implement the `Copy` trait LL | s.x = 10; s.y = Box::new(20); | ^^^^^^^^ value partially assigned here after move @@ -26,7 +26,7 @@ error[E0382]: assign to part of moved value: `t` LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here | | - | move occurs because `t` has type `(u32, std::boxed::Box)`, which does not implement the `Copy` trait + | move occurs because `t` has type `(u32, Box)`, which does not implement the `Copy` trait LL | t.0 = 10; t.1 = Box::new(20); | ^^^^^^^^ value partially assigned here after move @@ -48,7 +48,7 @@ error[E0382]: assign to part of moved value: `s` LL | let mut s: S = S::new(); drop(s); | ----- - value moved here | | - | move occurs because `s` has type `S>`, which does not implement the `Copy` trait + | move occurs because `s` has type `S>`, which does not implement the `Copy` trait LL | s.x = 10; | ^^^^^^^^ value partially assigned here after move @@ -58,7 +58,7 @@ error[E0382]: assign to part of moved value: `t` LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here | | - | move occurs because `t` has type `(u32, std::boxed::Box)`, which does not implement the `Copy` trait + | move occurs because `t` has type `(u32, Box)`, which does not implement the `Copy` trait LL | t.0 = 10; | ^^^^^^^^ value partially assigned here after move @@ -94,7 +94,7 @@ LL | let mut q: Q> = Q::new(S::new()); drop(q.r); LL | q.r.f.x = 10; q.r.f.y = Box::new(20); | ^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait + = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` --> $DIR/issue-21232-partial-init-and-use.rs:197:5 @@ -104,7 +104,7 @@ LL | let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20); | ^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `q.r` has type `R<(u32, std::boxed::Box)>`, which does not implement the `Copy` trait + = note: move occurs because `q.r` has type `R<(u32, Box)>`, which does not implement the `Copy` trait error[E0381]: assign to part of possibly-uninitialized variable: `q` --> $DIR/issue-21232-partial-init-and-use.rs:204:5 @@ -126,7 +126,7 @@ LL | let mut q: Q> = Q::new(S::new()); drop(q.r); LL | q.r.f.x = 10; | ^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait + = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` --> $DIR/issue-21232-partial-init-and-use.rs:225:5 @@ -136,7 +136,7 @@ LL | let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); LL | q.r.f.0 = 10; | ^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `q.r` has type `R<(u32, std::boxed::Box)>`, which does not implement the `Copy` trait + = note: move occurs because `q.r` has type `R<(u32, Box)>`, which does not implement the `Copy` trait error[E0381]: assign to part of possibly-uninitialized variable: `q` --> $DIR/issue-21232-partial-init-and-use.rs:232:5 @@ -154,7 +154,7 @@ error[E0382]: assign to part of moved value: `c` --> $DIR/issue-21232-partial-init-and-use.rs:257:13 | LL | let mut c = (1, "".to_owned()); - | ----- move occurs because `c` has type `(i32, std::string::String)`, which does not implement the `Copy` trait + | ----- move occurs because `c` has type `(i32, String)`, which does not implement the `Copy` trait LL | match c { LL | c2 => { | -- value moved here @@ -165,7 +165,7 @@ error[E0382]: assign to part of moved value: `c` --> $DIR/issue-21232-partial-init-and-use.rs:267:13 | LL | let mut c = (1, (1, "".to_owned())); - | ----- move occurs because `c` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait + | ----- move occurs because `c` has type `(i32, (i32, String))`, which does not implement the `Copy` trait LL | match c { LL | c2 => { | -- value moved here @@ -180,7 +180,7 @@ LL | c2 => { LL | ((c.1).1).0 = 3; | ^^^^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `c.1` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait + = note: move occurs because `c.1` has type `(i32, (i32, String))`, which does not implement the `Copy` trait error: aborting due to 23 previous errors diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr index 74c33df37a..3dee3345db 100644 --- a/src/test/ui/nll/issue-50716.stderr +++ b/src/test/ui/nll/issue-50716.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | let _x = *s; | ^^ lifetime mismatch | - = note: expected type `std::marker::Sized` - found type `std::marker::Sized` + = note: expected type `Sized` + found type `Sized` note: the lifetime `'a` as defined on the function body at 9:8... --> $DIR/issue-50716.rs:9:8 | diff --git a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr index 1a1250ff93..c0a17a67ee 100644 --- a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr +++ b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr @@ -35,7 +35,7 @@ LL | let p = s.url; p | ^^^^^ | | | cannot move out of here - | move occurs because `s.url` has type `&mut std::string::String`, which does not implement the `Copy` trait + | move occurs because `s.url` has type `&mut String`, which does not implement the `Copy` trait | help: consider borrowing here: `&s.url` error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/issue-52086.stderr b/src/test/ui/nll/issue-52086.stderr index e9aa7939f7..3b2dae9b72 100644 --- a/src/test/ui/nll/issue-52086.stderr +++ b/src/test/ui/nll/issue-52086.stderr @@ -2,13 +2,13 @@ error[E0507]: cannot move out of an `Rc` --> $DIR/issue-52086.rs:8:10 | LL | drop(x.field); - | ^^^^^^^ move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait error[E0507]: cannot move out of an `Arc` --> $DIR/issue-52086.rs:12:10 | LL | drop(y.field); - | ^^^^^^^ move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr index 57b9dc1f0b..67115a5ccd 100644 --- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` LL | let x = (vec![22], vec![44]); | - captured outer variable LL | expect_fn(|| drop(x.0)); - | ^^^ move occurs because `x.0` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^ move occurs because `x.0` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/nll/issue-53807.stderr b/src/test/ui/nll/issue-53807.stderr index 4f36a4ccab..6767f7cd61 100644 --- a/src/test/ui/nll/issue-53807.stderr +++ b/src/test/ui/nll/issue-53807.stderr @@ -4,7 +4,7 @@ error[E0382]: use of moved value LL | if let Some(thing) = maybe { | ^^^^^ value moved here, in previous iteration of loop | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because value has type `Vec`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `maybe.0` | LL | if let Some(ref thing) = maybe { diff --git a/src/test/ui/nll/issue-54556-stephaneyfx.stderr b/src/test/ui/nll/issue-54556-stephaneyfx.stderr index 77065f0b8d..bfb0eb74a5 100644 --- a/src/test/ui/nll/issue-54556-stephaneyfx.stderr +++ b/src/test/ui/nll/issue-54556-stephaneyfx.stderr @@ -10,7 +10,7 @@ LL | } | - | | | `stmt` dropped here while still borrowed - | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::iter::Map, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:23]>` + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Map, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:23]>` | = note: the temporary is part of an expression at the end of a block; consider forcing this temporary to be dropped sooner, before the block's local variables are dropped diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr index 06fe564ac6..4b3817929f 100644 --- a/src/test/ui/nll/match-cfg-fake-edges.stderr +++ b/src/test/ui/nll/match-cfg-fake-edges.stderr @@ -8,7 +8,7 @@ error[E0382]: use of moved value: `x` --> $DIR/match-cfg-fake-edges.rs:35:13 | LL | let x = String::new(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | false if { drop(x); true } => 1, | - value moved here diff --git a/src/test/ui/nll/match-guards-always-borrow.stderr b/src/test/ui/nll/match-guards-always-borrow.stderr index 15f94043b4..df6d65056a 100644 --- a/src/test/ui/nll/match-guards-always-borrow.stderr +++ b/src/test/ui/nll/match-guards-always-borrow.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/nll/move-errors.stderr b/src/test/ui/nll/move-errors.stderr index d4a0e45648..0df326425a 100644 --- a/src/test/ui/nll/move-errors.stderr +++ b/src/test/ui/nll/move-errors.stderr @@ -52,7 +52,7 @@ LL | let A(s) = *a; | - ^^ help: consider borrowing here: `&*a` | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `D`, which implements the `Drop` trait --> $DIR/move-errors.rs:44:19 @@ -61,7 +61,7 @@ LL | let C(D(s)) = c; | - ^ cannot move out of here | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*a` which is behind a shared reference --> $DIR/move-errors.rs:51:9 @@ -95,7 +95,7 @@ LL | B::U(D(s)) => (), | - | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `D`, which implements the `Drop` trait --> $DIR/move-errors.rs:92:11 @@ -107,7 +107,7 @@ LL | (D(s), &t) => (), | - | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*x.1` which is behind a shared reference --> $DIR/move-errors.rs:92:11 @@ -119,7 +119,7 @@ LL | (D(s), &t) => (), | - | | | data moved here - | move occurs because `t` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `t` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `F`, which implements the `Drop` trait --> $DIR/move-errors.rs:102:11 @@ -144,7 +144,7 @@ LL | Ok(s) | Err(s) => (), | - | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error: aborting due to 14 previous errors diff --git a/src/test/ui/nll/move-subpaths-moves-root.rs b/src/test/ui/nll/move-subpaths-moves-root.rs index e7caf89e78..d266c6bb65 100644 --- a/src/test/ui/nll/move-subpaths-moves-root.rs +++ b/src/test/ui/nll/move-subpaths-moves-root.rs @@ -1,5 +1,5 @@ fn main() { let x = (vec![1, 2, 3], ); drop(x.0); - drop(x); //~ ERROR use of moved value + drop(x); //~ ERROR use of partially moved value } diff --git a/src/test/ui/nll/move-subpaths-moves-root.stderr b/src/test/ui/nll/move-subpaths-moves-root.stderr index 7030d5b330..ae9287f922 100644 --- a/src/test/ui/nll/move-subpaths-moves-root.stderr +++ b/src/test/ui/nll/move-subpaths-moves-root.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `x` +error[E0382]: use of partially moved value: `x` --> $DIR/move-subpaths-moves-root.rs:4:10 | LL | drop(x.0); - | --- value moved here + | --- value partially moved here LL | drop(x); | ^ value used here after partial move | - = note: move occurs because `x.0` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: partial move occurs because `x.0` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/nll/trait-associated-constant.stderr b/src/test/ui/nll/trait-associated-constant.stderr index 5158420c73..2af5b2a2e0 100644 --- a/src/test/ui/nll/trait-associated-constant.stderr +++ b/src/test/ui/nll/trait-associated-constant.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | const AC: Option<&'c str> = None; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected enum `std::option::Option<&'b str>` - found enum `std::option::Option<&'c str>` + = note: expected enum `Option<&'b str>` + found enum `Option<&'c str>` note: the lifetime `'c` as defined on the impl at 20:18... --> $DIR/trait-associated-constant.rs:20:18 | diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs index 20af0fbdc8..28010e198d 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs @@ -23,7 +23,7 @@ where T: Iterator, { with_signature(x, |mut y| Box::new(y.next())) - //~^ ERROR the associated type `::Item` may not live long enough + //~^ ERROR the associated type `::Item` may not live long enough } #[rustc_regions] @@ -40,7 +40,7 @@ where T: 'b + Iterator, { with_signature(x, |mut y| Box::new(y.next())) - //~^ ERROR the associated type `::Item` may not live long enough + //~^ ERROR the associated type `::Item` may not live long enough } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index 38e59ae3e2..983d6a06af 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, (), @@ -26,13 +26,13 @@ LL | | } | = note: defining type: no_region::<'_#1r, T> -error[E0309]: the associated type `::Item` may not live long enough +error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:25:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `::Item: 'a`... + = help: consider adding an explicit lifetime bound `::Item: 'a`... note: external requirements --> $DIR/projection-no-regions-closure.rs:34:23 @@ -40,7 +40,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, (), @@ -67,7 +67,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, (), @@ -89,13 +89,13 @@ LL | | } | = note: defining type: wrong_region::<'_#1r, '_#2r, T> -error[E0309]: the associated type `::Item` may not live long enough +error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:42:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `::Item: 'a`... + = help: consider adding an explicit lifetime bound `::Item: 'a`... note: external requirements --> $DIR/projection-no-regions-closure.rs:52:23 @@ -103,7 +103,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, (), diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs index 64073bec8a..c9989fb426 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs @@ -11,7 +11,7 @@ where T: Iterator, { Box::new(x.next()) - //~^ ERROR the associated type `::Item` may not live long enough + //~^ ERROR the associated type `::Item` may not live long enough } fn correct_region<'a, T>(mut x: T) -> Box @@ -26,7 +26,7 @@ where T: 'b + Iterator, { Box::new(x.next()) - //~^ ERROR the associated type `::Item` may not live long enough + //~^ ERROR the associated type `::Item` may not live long enough } fn outlives_region<'a, 'b, T>(mut x: T) -> Box diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr index b0338de933..c4df04b99b 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr @@ -1,18 +1,18 @@ -error[E0309]: the associated type `::Item` may not live long enough +error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-fn.rs:13:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `::Item: 'a`... + = help: consider adding an explicit lifetime bound `::Item: 'a`... -error[E0309]: the associated type `::Item` may not live long enough +error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-fn.rs:28:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `::Item: 'a`... + = help: consider adding an explicit lifetime bound `::Item: 'a`... error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index d551ccf9cf..2513b0bfcc 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -55,7 +55,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -105,7 +105,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -133,7 +133,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 3e17de1bf0..4eebe682d4 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -46,7 +46,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -87,7 +87,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -115,7 +115,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -143,7 +143,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index 3d9a01fec1..46a02598e1 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -30,7 +30,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -56,7 +56,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -82,7 +82,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -108,7 +108,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index e354f1b5f7..4e0155bdf2 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -41,7 +41,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -77,7 +77,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -105,7 +105,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -133,7 +133,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -161,7 +161,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: two_regions::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: two_regions::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -203,7 +203,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -231,7 +231,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 167ca740c6..7c0d63c368 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -4,7 +4,7 @@ note: external requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: generic::::{{closure}}#0 with closure substs [ + = note: defining type: generic::::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), (), @@ -29,7 +29,7 @@ note: external requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: generic_fail::::{{closure}}#0 with closure substs [ + = note: defining type: generic_fail::::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), (), diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 528da502b9..88d73e7a72 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(x, |y| y) | ^^^^^ | - = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>, (), diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index e341ee4829..5b175aac1e 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -11,7 +11,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: no_region::::{{closure}}#0 with closure substs [ + = note: defining type: no_region::::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)), (), @@ -62,7 +62,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -95,7 +95,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: wrong_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: wrong_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -141,7 +141,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), diff --git a/src/test/ui/nll/type-alias-free-regions.nll.stderr b/src/test/ui/nll/type-alias-free-regions.nll.stderr index 235bf4167d..bde73b0589 100644 --- a/src/test/ui/nll/type-alias-free-regions.nll.stderr +++ b/src/test/ui/nll/type-alias-free-regions.nll.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | impl<'a> FromBox<'a> for C<'a> { | -- lifetime `'a` defined here LL | fn from_box(b: Box) -> Self { - | - has type `std::boxed::Box>` + | - has type `Box>` LL | C { f: b } | ^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` @@ -14,7 +14,7 @@ error: lifetime may not live long enough LL | impl<'a> FromTuple<'a> for C<'a> { | -- lifetime `'a` defined here LL | fn from_tuple(b: (B,)) -> Self { - | - has type `(std::boxed::Box<&'1 isize>,)` + | - has type `(Box<&'1 isize>,)` LL | C { f: Box::new(b.0) } | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index 65ce058112..38e3e05d1c 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -14,8 +14,8 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^ - = note: expected `std::boxed::Box>` - found `std::boxed::Box>` + = note: expected `Box>` + found `Box>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6... --> $DIR/type-alias-free-regions.rs:15:6 | @@ -45,8 +45,8 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^ - = note: expected `std::boxed::Box<&isize>` - found `std::boxed::Box<&isize>` + = note: expected `Box<&isize>` + found `Box<&isize>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6... --> $DIR/type-alias-free-regions.rs:25:6 | diff --git a/src/test/ui/no-capture-arc.stderr b/src/test/ui/no-capture-arc.stderr index 476b6f75ab..37032e73f1 100644 --- a/src/test/ui/no-capture-arc.stderr +++ b/src/test/ui/no-capture-arc.stderr @@ -1,8 +1,8 @@ error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-capture-arc.rs:14:18 + --> $DIR/no-capture-arc.rs:14:16 | LL | let arc_v = Arc::new(v); - | ----- move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait + | ----- move occurs because `arc_v` has type `Arc>`, which does not implement the `Copy` trait LL | LL | thread::spawn(move|| { | ------ value moved into closure here @@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4); | ----- variable moved due to use in closure ... LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value borrowed here after move + | ^^^^^^^^ value borrowed here after move + | + = note: borrow occurs due to deref coercion to `Vec` +note: deref defined here + --> $SRC_DIR/alloc/src/sync.rs:LL:COL + | +LL | type Target = T; + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no-reuse-move-arc.stderr b/src/test/ui/no-reuse-move-arc.stderr index 3f7169e6fc..6f37d4c9d8 100644 --- a/src/test/ui/no-reuse-move-arc.stderr +++ b/src/test/ui/no-reuse-move-arc.stderr @@ -1,8 +1,8 @@ error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-reuse-move-arc.rs:12:18 + --> $DIR/no-reuse-move-arc.rs:12:16 | LL | let arc_v = Arc::new(v); - | ----- move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait + | ----- move occurs because `arc_v` has type `Arc>`, which does not implement the `Copy` trait LL | LL | thread::spawn(move|| { | ------ value moved into closure here @@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4); | ----- variable moved due to use in closure ... LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value borrowed here after move + | ^^^^^^^^ value borrowed here after move + | + = note: borrow occurs due to deref coercion to `Vec` +note: deref defined here + --> $SRC_DIR/alloc/src/sync.rs:LL:COL + | +LL | type Target = T; + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no-send-res-ports.rs b/src/test/ui/no-send-res-ports.rs index e10f447365..1bac5868e7 100644 --- a/src/test/ui/no-send-res-ports.rs +++ b/src/test/ui/no-send-res-ports.rs @@ -23,7 +23,7 @@ fn main() { let x = foo(Port(Rc::new(()))); thread::spawn(move|| { - //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely + //~^ ERROR `Rc<()>` cannot be sent between threads safely let y = x; println!("{:?}", y); }); diff --git a/src/test/ui/no-send-res-ports.stderr b/src/test/ui/no-send-res-ports.stderr index dbe1fde964..ef7fb4ad7b 100644 --- a/src/test/ui/no-send-res-ports.stderr +++ b/src/test/ui/no-send-res-ports.stderr @@ -1,25 +1,25 @@ -error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely +error[E0277]: `Rc<()>` cannot be sent between threads safely --> $DIR/no-send-res-ports.rs:25:5 | LL | thread::spawn(move|| { | _____^^^^^^^^^^^^^_- | | | - | | `std::rc::Rc<()>` cannot be sent between threads safely + | | `Rc<()>` cannot be sent between threads safely LL | | LL | | let y = x; LL | | println!("{:?}", y); LL | | }); - | |_____- within this `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6 x:main::Foo]` + | |_____- within this `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]` | ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL | LL | F: Send + 'static, - | ---- required by this bound in `std::thread::spawn` + | ---- required by this bound in `spawn` | - = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`, the trait `Send` is not implemented for `Rc<()>` = note: required because it appears within the type `Port<()>` - = note: required because it appears within the type `main::Foo` - = note: required because it appears within the type `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6 x:main::Foo]` + = note: required because it appears within the type `Foo` + = note: required because it appears within the type `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]` error: aborting due to previous error diff --git a/src/test/ui/no-stdio.rs b/src/test/ui/no-stdio.rs index e72b7b26e2..1b0ad930da 100644 --- a/src/test/ui/no-stdio.rs +++ b/src/test/ui/no-stdio.rs @@ -36,6 +36,16 @@ unsafe fn without_stdio R>(f: F) -> R { return r } +#[cfg(unix)] +fn assert_fd_is_valid(fd: libc::c_int) { + if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } { + panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error()); + } +} + +#[cfg(windows)] +fn assert_fd_is_valid(_fd: libc::c_int) {} + #[cfg(windows)] unsafe fn without_stdio R>(f: F) -> R { type DWORD = u32; @@ -77,10 +87,18 @@ unsafe fn without_stdio R>(f: F) -> R { fn main() { if env::args().len() > 1 { + // Writing to stdout & stderr should not panic. println!("test"); assert!(io::stdout().write(b"test\n").is_ok()); assert!(io::stderr().write(b"test\n").is_ok()); + + // Stdin should be at EOF. assert_eq!(io::stdin().read(&mut [0; 10]).unwrap(), 0); + + // Standard file descriptors should be valid on UNIX: + assert_fd_is_valid(0); + assert_fd_is_valid(1); + assert_fd_is_valid(2); return } @@ -109,12 +127,12 @@ fn main() { .stdout(Stdio::null()) .stderr(Stdio::null()) .status().unwrap(); - assert!(status.success(), "{:?} isn't a success", status); + assert!(status.success(), "{} isn't a success", status); // Finally, close everything then spawn a child to make sure everything is // *still* ok. let status = unsafe { without_stdio(|| Command::new(&me).arg("next").status()) }.unwrap(); - assert!(status.success(), "{:?} isn't a success", status); + assert!(status.success(), "{} isn't a success", status); } diff --git a/src/test/ui/no_owned_box_lang_item.rs b/src/test/ui/no_owned_box_lang_item.rs index 58e45ff73a..bef630d826 100644 --- a/src/test/ui/no_owned_box_lang_item.rs +++ b/src/test/ui/no_owned_box_lang_item.rs @@ -12,4 +12,5 @@ fn main() { } #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "eh_catch_typeinfo"] static EH_CATCH_TYPEINFO: u8 = 0; #[lang = "panic_impl"] fn panic_impl(panic: &PanicInfo) -> ! { loop {} } diff --git a/src/test/ui/no_send-enum.stderr b/src/test/ui/no_send-enum.stderr index 95a0d77676..b617fe410f 100644 --- a/src/test/ui/no_send-enum.stderr +++ b/src/test/ui/no_send-enum.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(x); | ^^^ `NoSend` cannot be sent between threads safely | - = help: within `Foo`, the trait `std::marker::Send` is not implemented for `NoSend` + = help: within `Foo`, the trait `Send` is not implemented for `NoSend` = note: required because it appears within the type `Foo` error: aborting due to previous error diff --git a/src/test/ui/no_send-rc.rs b/src/test/ui/no_send-rc.rs index 6ed0286ef1..f31db15ef2 100644 --- a/src/test/ui/no_send-rc.rs +++ b/src/test/ui/no_send-rc.rs @@ -5,5 +5,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(5); bar(x); - //~^ ERROR `std::rc::Rc<{integer}>` cannot be sent between threads safely + //~^ ERROR `Rc<{integer}>` cannot be sent between threads safely } diff --git a/src/test/ui/no_send-rc.stderr b/src/test/ui/no_send-rc.stderr index 1eb2edb14b..713dd75366 100644 --- a/src/test/ui/no_send-rc.stderr +++ b/src/test/ui/no_send-rc.stderr @@ -1,13 +1,13 @@ -error[E0277]: `std::rc::Rc<{integer}>` cannot be sent between threads safely +error[E0277]: `Rc<{integer}>` cannot be sent between threads safely --> $DIR/no_send-rc.rs:7:9 | LL | fn bar(_: T) {} | ---- required by this bound in `bar` ... LL | bar(x); - | ^ `std::rc::Rc<{integer}>` cannot be sent between threads safely + | ^ `Rc<{integer}>` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc<{integer}>` + = help: the trait `Send` is not implemented for `Rc<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/no_send-struct.stderr b/src/test/ui/no_send-struct.stderr index 4e8801a58b..a28a5e6d3d 100644 --- a/src/test/ui/no_send-struct.stderr +++ b/src/test/ui/no_send-struct.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(x); | ^ `Foo` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `Foo` + = help: the trait `Send` is not implemented for `Foo` error: aborting due to previous error diff --git a/src/test/ui/no_share-enum.stderr b/src/test/ui/no_share-enum.stderr index 40996aef70..4a93edc100 100644 --- a/src/test/ui/no_share-enum.stderr +++ b/src/test/ui/no_share-enum.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(x); | ^^^ `NoSync` cannot be shared between threads safely | - = help: within `Foo`, the trait `std::marker::Sync` is not implemented for `NoSync` + = help: within `Foo`, the trait `Sync` is not implemented for `NoSync` = note: required because it appears within the type `Foo` error: aborting due to previous error diff --git a/src/test/ui/no_share-struct.stderr b/src/test/ui/no_share-struct.stderr index f14b06835f..a35271a8b7 100644 --- a/src/test/ui/no_share-struct.stderr +++ b/src/test/ui/no_share-struct.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(x); | ^ `Foo` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `Foo` + = help: the trait `Sync` is not implemented for `Foo` error: aborting due to previous error diff --git a/src/test/ui/noexporttypeexe.rs b/src/test/ui/noexporttypeexe.rs index 0a8b40b08f..964ac9a300 100644 --- a/src/test/ui/noexporttypeexe.rs +++ b/src/test/ui/noexporttypeexe.rs @@ -10,6 +10,6 @@ fn main() { let x: isize = noexporttypelib::foo(); //~^ ERROR mismatched types //~| expected type `isize` - //~| found enum `std::option::Option` - //~| expected `isize`, found enum `std::option::Option` + //~| found enum `Option` + //~| expected `isize`, found enum `Option` } diff --git a/src/test/ui/noexporttypeexe.stderr b/src/test/ui/noexporttypeexe.stderr index e80fcd1368..7fc239613e 100644 --- a/src/test/ui/noexporttypeexe.stderr +++ b/src/test/ui/noexporttypeexe.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/noexporttypeexe.rs:10:18 | LL | let x: isize = noexporttypelib::foo(); - | ----- ^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found enum `std::option::Option` + | ----- ^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found enum `Option` | | | expected due to this | = note: expected type `isize` - found enum `std::option::Option` + found enum `Option` error: aborting due to previous error diff --git a/src/test/ui/non-copyable-void.stderr b/src/test/ui/non-copyable-void.stderr index 9b0277186c..8395a3a056 100644 --- a/src/test/ui/non-copyable-void.stderr +++ b/src/test/ui/non-copyable-void.stderr @@ -1,16 +1,16 @@ -error[E0599]: no method named `clone` found for enum `libc::c_void` in the current scope +error[E0599]: no method named `clone` found for enum `c_void` in the current scope --> $DIR/non-copyable-void.rs:11:23 | LL | let _z = (*y).clone(); - | ^^^^^ method not found in `libc::c_void` + | ^^^^^ method not found in `c_void` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here + | the method is available for `Arc` here + | the method is available for `Rc` here error: aborting due to previous error diff --git a/src/test/ui/non-integer-atomic.rs b/src/test/ui/non-integer-atomic.rs index 26d7e66ae3..00a7f368a0 100644 --- a/src/test/ui/non-integer-atomic.rs +++ b/src/test/ui/non-integer-atomic.rs @@ -53,22 +53,22 @@ pub unsafe fn test_Foo_cxchg(p: &mut Foo, v: Foo) { pub unsafe fn test_Bar_load(p: &mut Bar, v: Bar) { intrinsics::atomic_load(p); - //~^ ERROR expected basic integer type, found `&dyn std::ops::Fn()` + //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_store(p: &mut Bar, v: Bar) { intrinsics::atomic_store(p, v); - //~^ ERROR expected basic integer type, found `&dyn std::ops::Fn()` + //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_xchg(p: &mut Bar, v: Bar) { intrinsics::atomic_xchg(p, v); - //~^ ERROR expected basic integer type, found `&dyn std::ops::Fn()` + //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_cxchg(p: &mut Bar, v: Bar) { intrinsics::atomic_cxchg(p, v, v); - //~^ ERROR expected basic integer type, found `&dyn std::ops::Fn()` + //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Quux_load(p: &mut Quux, v: Quux) { diff --git a/src/test/ui/non-integer-atomic.stderr b/src/test/ui/non-integer-atomic.stderr index 468e76da66..ee485c21cd 100644 --- a/src/test/ui/non-integer-atomic.stderr +++ b/src/test/ui/non-integer-atomic.stderr @@ -46,25 +46,25 @@ error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected bas LL | intrinsics::atomic_cxchg(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` +error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:55:5 | LL | intrinsics::atomic_load(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:60:5 | LL | intrinsics::atomic_store(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:65:5 | LL | intrinsics::atomic_xchg(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:70:5 | LL | intrinsics::atomic_cxchg(p, v, v); diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr index 75009ec130..b8e467d840 100644 --- a/src/test/ui/noncopyable-class.stderr +++ b/src/test/ui/noncopyable-class.stderr @@ -12,12 +12,12 @@ LL | let _y = x.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here + | the method is available for `Arc` here + | the method is available for `Rc` here | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/not-clone-closure.rs b/src/test/ui/not-clone-closure.rs index 134d52c495..25635bc833 100644 --- a/src/test/ui/not-clone-closure.rs +++ b/src/test/ui/not-clone-closure.rs @@ -8,5 +8,5 @@ fn main() { println!("Hello {}", a.0); }; - let hello = hello.clone(); //~ ERROR the trait bound `S: std::clone::Clone` is not satisfied + let hello = hello.clone(); //~ ERROR the trait bound `S: Clone` is not satisfied } diff --git a/src/test/ui/not-clone-closure.stderr b/src/test/ui/not-clone-closure.stderr index 20c7f81cf5..a62c21f2ee 100644 --- a/src/test/ui/not-clone-closure.stderr +++ b/src/test/ui/not-clone-closure.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `S: std::clone::Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` +error[E0277]: the trait bound `S: Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]` --> $DIR/not-clone-closure.rs:11:23 | LL | let hello = move || { | _________________- LL | | println!("Hello {}", a.0); LL | | }; - | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` + | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]` LL | LL | let hello = hello.clone(); - | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S` + | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`, the trait `Clone` is not implemented for `S` | - = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` + = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]` error: aborting due to previous error diff --git a/src/test/ui/not-panic/not-panic-safe-2.rs b/src/test/ui/not-panic/not-panic-safe-2.rs index cd074281d0..f3faa70432 100644 --- a/src/test/ui/not-panic/not-panic-safe-2.rs +++ b/src/test/ui/not-panic/not-panic-safe-2.rs @@ -8,6 +8,6 @@ fn assert() {} fn main() { assert::>>(); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a + //~| ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/not-panic/not-panic-safe-2.stderr b/src/test/ui/not-panic/not-panic-safe-2.stderr index c52d5b9ade..6deb1e7d6f 100644 --- a/src/test/ui/not-panic/not-panic-safe-2.stderr +++ b/src/test/ui/not-panic/not-panic-safe-2.stderr @@ -1,29 +1,29 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-2.rs:10:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::rc::Rc>` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `Rc>` -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-2.rs:10:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::rc::Rc>` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `Rc>` error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe-3.rs b/src/test/ui/not-panic/not-panic-safe-3.rs index b0ba3781f3..21f0c09931 100644 --- a/src/test/ui/not-panic/not-panic-safe-3.rs +++ b/src/test/ui/not-panic/not-panic-safe-3.rs @@ -8,6 +8,6 @@ fn assert() {} fn main() { assert::>>(); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a + //~| ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/not-panic/not-panic-safe-3.stderr b/src/test/ui/not-panic/not-panic-safe-3.stderr index 711346b7b1..ef1cf548df 100644 --- a/src/test/ui/not-panic/not-panic-safe-3.stderr +++ b/src/test/ui/not-panic/not-panic-safe-3.stderr @@ -1,29 +1,29 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-3.rs:10:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::sync::Arc>` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `Arc>` -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-3.rs:10:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::sync::Arc>` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `Arc>` error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe-4.rs b/src/test/ui/not-panic/not-panic-safe-4.rs index ed2760576d..ba93af5c0a 100644 --- a/src/test/ui/not-panic/not-panic-safe-4.rs +++ b/src/test/ui/not-panic/not-panic-safe-4.rs @@ -7,6 +7,6 @@ fn assert() {} fn main() { assert::<&RefCell>(); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a + //~| ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/not-panic/not-panic-safe-4.stderr b/src/test/ui/not-panic/not-panic-safe-4.stderr index ada22fe9a7..2f86b96540 100644 --- a/src/test/ui/not-panic/not-panic-safe-4.stderr +++ b/src/test/ui/not-panic/not-panic-safe-4.stderr @@ -1,29 +1,29 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-4.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<&RefCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::RefCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `&RefCell` -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-4.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<&RefCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::RefCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `&RefCell` error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe-5.stderr b/src/test/ui/not-panic/not-panic-safe-5.stderr index c987ca7c08..c9f407a7f7 100644 --- a/src/test/ui/not-panic/not-panic-safe-5.stderr +++ b/src/test/ui/not-panic/not-panic-safe-5.stderr @@ -1,14 +1,14 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-5.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<*const UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `*const std::cell::UnsafeCell` + = help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `*const UnsafeCell` error: aborting due to previous error diff --git a/src/test/ui/not-panic/not-panic-safe-6.rs b/src/test/ui/not-panic/not-panic-safe-6.rs index a42e337ad9..4915096dc3 100644 --- a/src/test/ui/not-panic/not-panic-safe-6.rs +++ b/src/test/ui/not-panic/not-panic-safe-6.rs @@ -7,6 +7,6 @@ fn assert() {} fn main() { assert::<*mut RefCell>(); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a + //~| ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/not-panic/not-panic-safe-6.stderr b/src/test/ui/not-panic/not-panic-safe-6.stderr index f184a459b8..cf75c89f27 100644 --- a/src/test/ui/not-panic/not-panic-safe-6.stderr +++ b/src/test/ui/not-panic/not-panic-safe-6.stderr @@ -1,29 +1,29 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-6.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<*mut RefCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `*mut std::cell::RefCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `*mut RefCell` -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-6.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<*mut RefCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `*mut std::cell::RefCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `*mut RefCell` error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe.stderr b/src/test/ui/not-panic/not-panic-safe.stderr index b254a04166..1aaf17b1cd 100644 --- a/src/test/ui/not-panic/not-panic-safe.stderr +++ b/src/test/ui/not-panic/not-panic-safe.stderr @@ -7,8 +7,8 @@ LL | fn assert() {} LL | assert::<&mut i32>(); | ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary | - = help: the trait `std::panic::UnwindSafe` is not implemented for `&mut i32` - = note: `std::panic::UnwindSafe` is implemented for `&i32`, but not for `&mut i32` + = help: the trait `UnwindSafe` is not implemented for `&mut i32` + = note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32` error: aborting due to previous error diff --git a/src/test/ui/not-sync.rs b/src/test/ui/not-sync.rs index 70ba1fc580..f4648994fa 100644 --- a/src/test/ui/not-sync.rs +++ b/src/test/ui/not-sync.rs @@ -6,17 +6,17 @@ fn test() {} fn main() { test::>(); - //~^ ERROR `std::cell::Cell` cannot be shared between threads safely [E0277] + //~^ ERROR `Cell` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::cell::RefCell` cannot be shared between threads safely [E0277] + //~^ ERROR `RefCell` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::rc::Rc` cannot be shared between threads safely [E0277] + //~^ ERROR `Rc` cannot be shared between threads safely [E0277] test::>(); //~^ ERROR `std::rc::Weak` cannot be shared between threads safely [E0277] test::>(); //~^ ERROR `std::sync::mpsc::Receiver` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::sync::mpsc::Sender` cannot be shared between threads safely [E0277] + //~^ ERROR `Sender` cannot be shared between threads safely [E0277] } diff --git a/src/test/ui/not-sync.stderr b/src/test/ui/not-sync.stderr index 25f1a66062..85d3599da0 100644 --- a/src/test/ui/not-sync.stderr +++ b/src/test/ui/not-sync.stderr @@ -1,35 +1,35 @@ -error[E0277]: `std::cell::Cell` cannot be shared between threads safely +error[E0277]: `Cell` cannot be shared between threads safely --> $DIR/not-sync.rs:8:12 | LL | fn test() {} | ---- required by this bound in `test` ... LL | test::>(); - | ^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely + | ^^^^^^^^^ `Cell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` + = help: the trait `Sync` is not implemented for `Cell` -error[E0277]: `std::cell::RefCell` cannot be shared between threads safely +error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/not-sync.rs:10:12 | LL | fn test() {} | ---- required by this bound in `test` ... LL | test::>(); - | ^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = help: the trait `Sync` is not implemented for `RefCell` -error[E0277]: `std::rc::Rc` cannot be shared between threads safely +error[E0277]: `Rc` cannot be shared between threads safely --> $DIR/not-sync.rs:13:12 | LL | fn test() {} | ---- required by this bound in `test` ... LL | test::>(); - | ^^^^^^^ `std::rc::Rc` cannot be shared between threads safely + | ^^^^^^^ `Rc` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::rc::Rc` + = help: the trait `Sync` is not implemented for `Rc` error[E0277]: `std::rc::Weak` cannot be shared between threads safely --> $DIR/not-sync.rs:15:12 @@ -40,7 +40,7 @@ LL | fn test() {} LL | test::>(); | ^^^^^^^^^ `std::rc::Weak` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::rc::Weak` + = help: the trait `Sync` is not implemented for `std::rc::Weak` error[E0277]: `std::sync::mpsc::Receiver` cannot be shared between threads safely --> $DIR/not-sync.rs:18:12 @@ -51,18 +51,18 @@ LL | fn test() {} LL | test::>(); | ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver` + = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver` -error[E0277]: `std::sync::mpsc::Sender` cannot be shared between threads safely +error[E0277]: `Sender` cannot be shared between threads safely --> $DIR/not-sync.rs:20:12 | LL | fn test() {} | ---- required by this bound in `test` ... LL | test::>(); - | ^^^^^^^^^^^ `std::sync::mpsc::Sender` cannot be shared between threads safely + | ^^^^^^^^^^^ `Sender` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender` + = help: the trait `Sync` is not implemented for `Sender` error: aborting due to 6 previous errors diff --git a/src/test/ui/numbers-arithmetic/arith-0.rs b/src/test/ui/numbers-arithmetic/arith-0.rs deleted file mode 100644 index 7943cb908d..0000000000 --- a/src/test/ui/numbers-arithmetic/arith-0.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-pass - - -pub fn main() { - let a: isize = 10; - println!("{}", a); - assert_eq!(a * (a - 1), 90); -} diff --git a/src/test/ui/numbers-arithmetic/arith-1.rs b/src/test/ui/numbers-arithmetic/arith-1.rs deleted file mode 100644 index c13c8d8b76..0000000000 --- a/src/test/ui/numbers-arithmetic/arith-1.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass - - -pub fn main() { - let i32_a: isize = 10; - assert_eq!(i32_a, 10); - assert_eq!(i32_a - 10, 0); - assert_eq!(i32_a / 10, 1); - assert_eq!(i32_a - 20, -10); - assert_eq!(i32_a << 10, 10240); - assert_eq!(i32_a << 16, 655360); - assert_eq!(i32_a * 16, 160); - assert_eq!(i32_a * i32_a * i32_a, 1000); - assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); - assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); - assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); - let i32_b: isize = 0x10101010; - assert_eq!(i32_b + 1 - 1, i32_b); - assert_eq!(i32_b << 1, i32_b << 1); - assert_eq!(i32_b >> 1, i32_b >> 1); - assert_eq!(i32_b & i32_b << 1, 0); - println!("{}", i32_b | i32_b << 1); - assert_eq!(i32_b | i32_b << 1, 0x30303030); -} diff --git a/src/test/ui/numbers-arithmetic/arith-2.rs b/src/test/ui/numbers-arithmetic/arith-2.rs deleted file mode 100644 index 46c280677c..0000000000 --- a/src/test/ui/numbers-arithmetic/arith-2.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - - - -pub fn main() { - let i32_c: isize = 0x10101010; - assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), - i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)); -} diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr index 995afeeed8..1d029939c7 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-lsh-1.rs:7:14 | LL | let _x = 1_i32 << 32; - | ^^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-lsh-1.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr index e6f6b1ccd1..8598792e08 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-lsh-2.rs:7:14 | LL | let _x = 1 << -1; - | ^^^^^^^ attempt to shift left by -1_i32 which would overflow + | ^^^^^^^ attempt to shift left by `-1_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-lsh-2.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr index e57b892b80..9c6f806f1d 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-lsh-3.rs:7:14 | LL | let _x = 1_u64 << 64; - | ^^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-lsh-3.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr index f20b41c1ba..08081a0b78 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-lsh-4.rs:11:13 | LL | let x = 1_i8 << 17; - | ^^^^^^^^^^ attempt to shift left by 17_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `17_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-lsh-4.rs:7:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr index 18861a1b96..4d726fa7fe 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-1.rs:7:14 | LL | let _x = -1_i32 >> 32; - | ^^^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-1.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr index a2fb2b9053..9a8349d5dd 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-2.rs:7:14 | LL | let _x = -1_i32 >> -1; - | ^^^^^^^^^^^^ attempt to shift right by -1_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift right by `-1_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-2.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr index 24588b4a6b..f48b7ff6de 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-3.rs:7:14 | LL | let _x = -1_i64 >> 64; - | ^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-3.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr index 3f59653ea6..4816a38996 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-4.rs:11:13 | LL | let x = 2_i8 >> 17; - | ^^^^^^^^^^ attempt to shift right by 17_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `17_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-4.rs:7:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr index 8b0daf1551..cd36f543d6 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-5.rs:7:14 | LL | let _n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-5.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr index 53a1445b54..bec8b17df0 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-6.rs:7:14 | LL | let _n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-6.rs:4:9 diff --git a/src/test/ui/object-does-not-impl-trait.rs b/src/test/ui/object-does-not-impl-trait.rs index 104e7b2e21..b3b679813c 100644 --- a/src/test/ui/object-does-not-impl-trait.rs +++ b/src/test/ui/object-does-not-impl-trait.rs @@ -4,5 +4,5 @@ trait Foo {} fn take_foo(f: F) {} fn take_object(f: Box) { take_foo(f); } -//~^ ERROR `std::boxed::Box: Foo` is not satisfied +//~^ ERROR `Box: Foo` is not satisfied fn main() {} diff --git a/src/test/ui/object-does-not-impl-trait.stderr b/src/test/ui/object-does-not-impl-trait.stderr index 1d3675bf1c..44424bc4ae 100644 --- a/src/test/ui/object-does-not-impl-trait.stderr +++ b/src/test/ui/object-does-not-impl-trait.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `std::boxed::Box: Foo` is not satisfied +error[E0277]: the trait bound `Box: Foo` is not satisfied --> $DIR/object-does-not-impl-trait.rs:6:44 | LL | fn take_foo(f: F) {} | --- required by this bound in `take_foo` LL | fn take_object(f: Box) { take_foo(f); } - | ^ the trait `Foo` is not implemented for `std::boxed::Box` + | ^ the trait `Foo` is not implemented for `Box` error: aborting due to previous error diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr index 9563c0dff3..ae02c58d08 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr @@ -11,7 +11,7 @@ error[E0507]: cannot move out of `ss.r` which is behind a mutable reference --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | ss.r - | ^^^^ move occurs because `ss.r` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^^^^ move occurs because `ss.r` has type `Box`, which does not implement the `Copy` trait error[E0621]: explicit lifetime required in the type of `ss` --> $DIR/object-lifetime-default-from-box-error.rs:31:5 diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr index 86ec58d3f0..a789c4906e 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | ss.t = t; | ^ lifetime mismatch | - = note: expected reference `&'a std::boxed::Box<(dyn Test + 'static)>` - found reference `&'a std::boxed::Box<(dyn Test + 'a)>` + = note: expected reference `&'a Box<(dyn Test + 'static)>` + found reference `&'a Box<(dyn Test + 'a)>` note: the lifetime `'a` as defined on the function body at 14:6... --> $DIR/object-lifetime-default-from-rptr-box-error.rs:14:6 | diff --git a/src/test/ui/object-pointer-types.stderr b/src/test/ui/object-pointer-types.stderr index 021aa8670f..a477425edc 100644 --- a/src/test/ui/object-pointer-types.stderr +++ b/src/test/ui/object-pointer-types.stderr @@ -16,11 +16,11 @@ LL | fn owned(self: Box); LL | x.owned(); | ^^^^^ method not found in `&mut dyn Foo` -error[E0599]: no method named `managed` found for struct `std::boxed::Box<(dyn Foo + 'static)>` in the current scope +error[E0599]: no method named `managed` found for struct `Box<(dyn Foo + 'static)>` in the current scope --> $DIR/object-pointer-types.rs:23:7 | LL | x.managed(); - | ^^^^^^^ method not found in `std::boxed::Box<(dyn Foo + 'static)>` + | ^^^^^^^ method not found in `Box<(dyn Foo + 'static)>` error: aborting due to 3 previous errors diff --git a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr index e2a95d95a1..c32038b5a2 100644 --- a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr @@ -10,7 +10,7 @@ LL | t | ^ the trait `Bar` cannot be made into an object | = help: consider moving `X` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error: aborting due to previous error diff --git a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr index 7443d38470..7c104fa158 100644 --- a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr @@ -10,7 +10,7 @@ LL | t | ^ the trait `Bar` cannot be made into an object | = help: consider moving `bar` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error[E0038]: the trait `Bar` cannot be made into an object @@ -25,7 +25,7 @@ LL | t as &dyn Bar | ^ the trait `Bar` cannot be made into an object | = help: consider moving `bar` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr index 89b273fb8a..ced26889ba 100644 --- a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr @@ -10,7 +10,7 @@ LL | t | ^ the trait `Bar` cannot be made into an object | = help: consider moving `bar` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error[E0038]: the trait `Baz` cannot be made into an object @@ -25,7 +25,7 @@ LL | t | ^ the trait `Baz` cannot be made into an object | = help: consider moving `baz` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Baz>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Baz>` for `&T` = note: required by cast to type `&dyn Baz` error: aborting due to 2 previous errors diff --git a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr index de56843962..8e920697d8 100644 --- a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr @@ -9,8 +9,8 @@ LL | fn foo() {} LL | let b: Box = Box::new(Bar); | ^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` - = note: required by cast to type `std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box` + = note: required by cast to type `Box` help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects | LL | fn foo() where Self: Sized {} diff --git a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr index 2f1f06f4cf..cc0463f5d8 100644 --- a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr @@ -9,7 +9,7 @@ LL | where Self : Sized LL | t | ^ the trait `Bar` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error: aborting due to previous error diff --git a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr index 58c2b77214..aceacac2db 100644 --- a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr @@ -9,7 +9,7 @@ LL | trait Bar : Sized { LL | t | ^ the trait `Bar` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error: aborting due to previous error diff --git a/src/test/ui/on-unimplemented/no-debug.rs b/src/test/ui/on-unimplemented/no-debug.rs index 45c9ea46fa..bdc80c5b35 100644 --- a/src/test/ui/on-unimplemented/no-debug.rs +++ b/src/test/ui/on-unimplemented/no-debug.rs @@ -10,7 +10,7 @@ fn main() { println!("{:?} {:?}", Foo, Bar); println!("{} {}", Foo, Bar); } -//~^^^ ERROR `Foo` doesn't implement `std::fmt::Debug` -//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Debug` +//~^^^ ERROR `Foo` doesn't implement `Debug` +//~| ERROR `Bar` doesn't implement `Debug` //~^^^^ ERROR `Foo` doesn't implement `std::fmt::Display` -//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Display` +//~| ERROR `Bar` doesn't implement `std::fmt::Display` diff --git a/src/test/ui/on-unimplemented/no-debug.stderr b/src/test/ui/on-unimplemented/no-debug.stderr index 4f9d428546..2382fd8484 100644 --- a/src/test/ui/on-unimplemented/no-debug.stderr +++ b/src/test/ui/on-unimplemented/no-debug.stderr @@ -1,21 +1,21 @@ -error[E0277]: `Foo` doesn't implement `std::fmt::Debug` +error[E0277]: `Foo` doesn't implement `Debug` --> $DIR/no-debug.rs:10:27 | LL | println!("{:?} {:?}", Foo, Bar); | ^^^ `Foo` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Foo` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Foo` + = note: add `#[derive(Debug)]` or manually implement `Debug` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug` +error[E0277]: `Bar` doesn't implement `Debug` --> $DIR/no-debug.rs:10:32 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar` + = help: the trait `Debug` is not implemented for `Bar` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -30,13 +30,13 @@ LL | println!("{} {}", Foo, Bar); = note: required by `std::fmt::Display::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display` +error[E0277]: `Bar` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:11:28 | LL | println!("{} {}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted with the default formatter + | ^^^ `Bar` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar` + = help: the trait `std::fmt::Display` is not implemented for `Bar` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: required by `std::fmt::Display::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/on-unimplemented/on-trait.stderr b/src/test/ui/on-unimplemented/on-trait.stderr index be8efbf2ce..00c8492abc 100644 --- a/src/test/ui/on-unimplemented/on-trait.stderr +++ b/src/test/ui/on-unimplemented/on-trait.stderr @@ -1,24 +1,24 @@ -error[E0277]: the trait bound `std::option::Option>: MyFromIterator<&u8>` is not satisfied +error[E0277]: the trait bound `Option>: MyFromIterator<&u8>` is not satisfied --> $DIR/on-trait.rs:28:30 | LL | fn collect, B: MyFromIterator>(it: I) -> B { | ----------------- required by this bound in `collect` ... LL | let y: Option> = collect(x.iter()); // this should give approximately the same error for x.iter().collect() - | ^^^^^^^ a collection of type `std::option::Option>` cannot be built from an iterator over elements of type `&u8` + | ^^^^^^^ a collection of type `Option>` cannot be built from an iterator over elements of type `&u8` | - = help: the trait `MyFromIterator<&u8>` is not implemented for `std::option::Option>` + = help: the trait `MyFromIterator<&u8>` is not implemented for `Option>` -error[E0277]: the trait bound `std::string::String: Bar::Foo` is not satisfied +error[E0277]: the trait bound `String: Foo` is not satisfied --> $DIR/on-trait.rs:31:21 | LL | fn foobar>() -> T { | --------------- required by this bound in `foobar` ... LL | let x: String = foobar(); - | ^^^^^^ test error `std::string::String` with `u8` `_` `u32` in `Bar::Foo` + | ^^^^^^ test error `String` with `u8` `_` `u32` in `Foo` | - = help: the trait `Bar::Foo` is not implemented for `std::string::String` + = help: the trait `Foo` is not implemented for `String` error: aborting due to 2 previous errors diff --git a/src/test/ui/on-unimplemented/slice-index.stderr b/src/test/ui/on-unimplemented/slice-index.stderr index 25a6546007..44b8b0d8d8 100644 --- a/src/test/ui/on-unimplemented/slice-index.stderr +++ b/src/test/ui/on-unimplemented/slice-index.stderr @@ -4,17 +4,17 @@ error[E0277]: the type `[i32]` cannot be indexed by `i32` LL | x[1i32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32` - = note: required because of the requirements on the impl of `std::ops::Index` for `[i32]` + = help: the trait `SliceIndex<[i32]>` is not implemented for `i32` + = note: required because of the requirements on the impl of `Index` for `[i32]` -error[E0277]: the type `[i32]` cannot be indexed by `std::ops::RangeTo` +error[E0277]: the type `[i32]` cannot be indexed by `RangeTo` --> $DIR/slice-index.rs:9:5 | LL | x[..1i32]; | ^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo` - = note: required because of the requirements on the impl of `std::ops::Index>` for `[i32]` + = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo` + = note: required because of the requirements on the impl of `Index>` for `[i32]` error: aborting due to 2 previous errors diff --git a/src/test/ui/option-to-result.stderr b/src/test/ui/option-to-result.stderr index 5fa0677838..551b9f4650 100644 --- a/src/test/ui/option-to-result.stderr +++ b/src/test/ui/option-to-result.stderr @@ -5,26 +5,26 @@ LL | fn test_result() -> Result<(),()> { | ------------- expected `()` because of this LL | let a:Option<()> = Some(()); LL | a?; - | ^ the trait `std::convert::From` is not implemented for `()` + | ^ the trait `From` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `std::convert::From::from` + = note: required by `from` help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` | LL | a.ok_or_else(|| /* error value */)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `?` couldn't convert the error to `std::option::NoneError` +error[E0277]: `?` couldn't convert the error to `NoneError` --> $DIR/option-to-result.rs:11:6 | LL | fn test_option() -> Option{ - | ----------- expected `std::option::NoneError` because of this + | ----------- expected `NoneError` because of this LL | let a:Result = Ok(5); LL | a?; - | ^ the trait `std::convert::From` is not implemented for `std::option::NoneError` + | ^ the trait `From` is not implemented for `NoneError` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `std::convert::From::from` + = note: required by `from` help: consider converting the `Result` into an `Option` using `Result::ok` | LL | a.ok()?; diff --git a/src/test/ui/option-unwrap.rs b/src/test/ui/option-unwrap.rs deleted file mode 100644 index 173f803ee2..0000000000 --- a/src/test/ui/option-unwrap.rs +++ /dev/null @@ -1,32 +0,0 @@ -// run-pass - -#![allow(non_camel_case_types)] -use std::cell::Cell; - -struct dtor<'a> { - x: &'a Cell, -} - -impl<'a> Drop for dtor<'a> { - fn drop(&mut self) { - self.x.set(self.x.get() - 1); - } -} - -fn unwrap(o: Option) -> T { - match o { - Some(v) => v, - None => panic!() - } -} - -pub fn main() { - let x = &Cell::new(1); - - { - let b = Some(dtor { x:x }); - let _c = unwrap(b); - } - - assert_eq!(x.get(), 0); -} diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr index 7e8bb73190..d3ae798ead 100644 --- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr @@ -23,7 +23,7 @@ LL | match (Some(0u8),) { | ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(std::option::Option,)` + = note: the matched value is of type `(Option,)` error: aborting due to 3 previous errors diff --git a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr index 1dabb7c975..00dba053a5 100644 --- a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr +++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:13:39 | LL | match Blah::A(1, 1, 2) { - | ---------------- this expression has type `main::Blah` + | ---------------- this expression has type `Blah` LL | Blah::A(_, x, y) | Blah::B(x, y) => {} | - ^ expected `usize`, found `isize` | | @@ -14,7 +14,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:17:44 | LL | match Some(Blah::A(1, 1, 2)) { - | ---------------------- this expression has type `std::option::Option` + | ---------------------- this expression has type `Option` LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} | - ^ expected `usize`, found `isize` | | @@ -50,7 +50,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:41 | LL | match Some((0u8, Some((1u16, 2u32)))) { - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | - ^ expected `u16`, found `u8` | | @@ -62,7 +62,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:50 | LL | match Some((0u8, Some((1u16, 2u32)))) { - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | - ^ expected `u8`, found `u16` | | @@ -74,7 +74,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:59 | LL | match Some((0u8, Some((1u16, 2u32)))) { - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | - ^ expected `u32`, found `u16` | | @@ -86,7 +86,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:62 | LL | match Some((0u8, Some((1u16, 2u32)))) { - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | - first introduced with type `u8` here ^ expected `u8`, found `u32` | @@ -96,7 +96,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:34:42 | LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { - | - ^ ---------------- this expression has type `main::Blah` + | - ^ ---------------- this expression has type `Blah` | | | | | expected `usize`, found `isize` | first introduced with type `usize` here @@ -107,7 +107,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:38:47 | LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) { - | - ^ ---------------------- this expression has type `std::option::Option` + | - ^ ---------------------- this expression has type `Option` | | | | | expected `usize`, found `isize` | first introduced with type `usize` here @@ -145,7 +145,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | first introduced with type `u16` here ... LL | = Some((0u8, Some((1u16, 2u32)))) - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` | = note: a binding must have the same type in all alternatives @@ -158,7 +158,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | first introduced with type `u8` here ... LL | = Some((0u8, Some((1u16, 2u32)))) - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` | = note: a binding must have the same type in all alternatives @@ -171,7 +171,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | first introduced with type `u32` here ... LL | = Some((0u8, Some((1u16, 2u32)))) - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` | = note: a binding must have the same type in all alternatives @@ -182,7 +182,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | - first introduced with type `u8` here ^ expected `u8`, found `u32` ... LL | = Some((0u8, Some((1u16, 2u32)))) - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` | = note: a binding must have the same type in all alternatives @@ -190,7 +190,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:55:39 | LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2); - | - ^ ---------------- this expression has type `main::Blah` + | - ^ ---------------- this expression has type `Blah` | | | | | expected `usize`, found `isize` | first introduced with type `usize` here diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 6cbb59dc22..861d274ab5 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -112,7 +112,7 @@ error[E0308]: mismatched types LL | let recovery_witness: String = 0; | ------ ^ | | | - | | expected struct `std::string::String`, found integer + | | expected struct `String`, found integer | | help: try using a conversion method: `0.to_string()` | expected due to this diff --git a/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs b/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs index 3e5cdad7ab..b9ef2f3294 100644 --- a/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs +++ b/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs @@ -11,3 +11,5 @@ use core::panic::PanicInfo; fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} +#[lang = "eh_catch_typeinfo"] +static EH_CATCH_TYPEINFO: u8 = 0; diff --git a/src/test/ui/paren-span.rs b/src/test/ui/paren-span.rs index 24fadb24de..c8cb63d519 100644 --- a/src/test/ui/paren-span.rs +++ b/src/test/ui/paren-span.rs @@ -16,6 +16,6 @@ mod m { fn main() { let s = m::make(); - paren!(s.x); //~ ERROR field `x` of struct `m::S` is private + paren!(s.x); //~ ERROR field `x` of struct `S` is private // ^^^ highlight here } diff --git a/src/test/ui/paren-span.stderr b/src/test/ui/paren-span.stderr index ca22401f45..fc31371576 100644 --- a/src/test/ui/paren-span.stderr +++ b/src/test/ui/paren-span.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `x` of struct `m::S` is private +error[E0616]: field `x` of struct `S` is private --> $DIR/paren-span.rs:19:14 | LL | paren!(s.x); diff --git a/src/test/ui/parser/bind-struct-early-modifiers.stderr b/src/test/ui/parser/bind-struct-early-modifiers.stderr index 03482a41f5..b35762a887 100644 --- a/src/test/ui/parser/bind-struct-early-modifiers.stderr +++ b/src/test/ui/parser/bind-struct-early-modifiers.stderr @@ -1,8 +1,10 @@ error: expected `,` - --> $DIR/bind-struct-early-modifiers.rs:4:19 + --> $DIR/bind-struct-early-modifiers.rs:4:20 | LL | Foo { ref x: ref x } => {}, - | ^ + | --- ^ + | | + | while parsing the fields for this pattern error: aborting due to previous error diff --git a/src/test/ui/parser/float-field.stderr b/src/test/ui/parser/float-field.stderr index 62202b9996..7090efc501 100644 --- a/src/test/ui/parser/float-field.stderr +++ b/src/test/ui/parser/float-field.stderr @@ -271,10 +271,10 @@ LL | s.1e1; = note: available fields are: `0`, `1` error[E0609]: no field `1e1` on type `(u8, u8)` - --> $DIR/float-field.rs:9:7 + --> $DIR/float-field.rs:9:9 | LL | s.1.1e1; - | ^^^^^ + | ^^^ error[E0609]: no field `0x1e1` on type `S` --> $DIR/float-field.rs:24:7 @@ -288,7 +288,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:25:7 | LL | s.0x1.; - | ^^^^ unknown field + | ^^^ unknown field | = note: available fields are: `0`, `1` @@ -296,7 +296,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:28:7 | LL | s.0x1.1; - | ^^^^^ unknown field + | ^^^ unknown field | = note: available fields are: `0`, `1` @@ -304,7 +304,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:30:7 | LL | s.0x1.1e1; - | ^^^^^^^ unknown field + | ^^^ unknown field | = note: available fields are: `0`, `1` diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index d6b36fbb71..4193b3ee69 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -178,7 +178,7 @@ LL | async fn ft1() {} | expected `()`, found opaque type | = note: expected fn pointer `fn()` - found fn pointer `fn() -> impl std::future::Future` + found fn pointer `fn() -> impl Future` error[E0053]: method `ft5` has an incompatible type for trait --> $DIR/fn-header-semantic-fail.rs:34:48 @@ -193,7 +193,7 @@ LL | const async unsafe extern "C" fn ft5() {} | expected `()`, found opaque type | = note: expected fn pointer `unsafe extern "C" fn()` - found fn pointer `unsafe extern "C" fn() -> impl std::future::Future` + found fn pointer `unsafe extern "C" fn() -> impl Future` error: aborting due to 20 previous errors diff --git a/src/test/ui/parser/issue-10392.stderr b/src/test/ui/parser/issue-10392.stderr index 34991151c1..438ea67d33 100644 --- a/src/test/ui/parser/issue-10392.stderr +++ b/src/test/ui/parser/issue-10392.stderr @@ -2,7 +2,9 @@ error: expected identifier, found `,` --> $DIR/issue-10392.rs:6:13 | LL | let A { , } = a(); - | ^ expected identifier + | - ^ expected identifier + | | + | while parsing the fields for this pattern error: aborting due to previous error diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index 396aec8335..80e9ac5bed 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -35,7 +35,9 @@ error: expected one of `!` or `[`, found `}` --> $DIR/issue-63135.rs:3:16 | LL | fn i(n{...,f # - | ^ expected one of `!` or `[` + | - ^ expected one of `!` or `[` + | | + | while parsing the fields for this pattern error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.rs b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs new file mode 100644 index 0000000000..0b10a5f6f4 --- /dev/null +++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs @@ -0,0 +1,21 @@ +#![crate_type="lib"] +fn x<'a>(x: &mut 'a i32){} //~ ERROR lifetime must precede `mut` + +macro_rules! mac { + ($lt:lifetime) => { + fn w<$lt>(w: &mut $lt i32) {} + //~^ ERROR lifetime must precede `mut` + } +} + +mac!('a); + +// avoid false positives +fn y<'a>(y: &mut 'a + Send) { + //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a` + //~| WARNING trait objects without an explicit `dyn` are deprecated + //~| ERROR at least one trait is required for an object type + let z = y as &mut 'a + Send; + //~^ ERROR expected value, found trait `Send` + //~| WARNING trait objects without an explicit `dyn` are deprecated +} diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr new file mode 100644 index 0000000000..abb64f7e49 --- /dev/null +++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr @@ -0,0 +1,53 @@ +error: lifetime must precede `mut` + --> $DIR/issue-73568-lifetime-after-mut.rs:2:13 + | +LL | fn x<'a>(x: &mut 'a i32){} + | ^^^^^^^ help: place the lifetime before `mut`: `&'a mut` + +error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a` + --> $DIR/issue-73568-lifetime-after-mut.rs:14:13 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)` + +error: lifetime must precede `mut` + --> $DIR/issue-73568-lifetime-after-mut.rs:6:22 + | +LL | fn w<$lt>(w: &mut $lt i32) {} + | ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut` +... +LL | mac!('a); + | --------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0423]: expected value, found trait `Send` + --> $DIR/issue-73568-lifetime-after-mut.rs:18:28 + | +LL | let z = y as &mut 'a + Send; + | ^^^^ not a value + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-73568-lifetime-after-mut.rs:14:18 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^ help: use `dyn`: `dyn 'a` + | + = note: `#[warn(bare_trait_objects)]` on by default + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-73568-lifetime-after-mut.rs:18:23 + | +LL | let z = y as &mut 'a + Send; + | ^^ help: use `dyn`: `dyn 'a` + +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-73568-lifetime-after-mut.rs:14:18 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^ + +error: aborting due to 5 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0178, E0224, E0423. +For more information about an error, try `rustc --explain E0178`. diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/parser/lex-bad-char-literals-6.stderr index 82c46ad82c..48b8fc6a72 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -37,7 +37,7 @@ error[E0277]: can't compare `&str` with `char` LL | if x == y {} | ^^ no implementation for `&str == char` | - = help: the trait `std::cmp::PartialEq` is not implemented for `&str` + = help: the trait `PartialEq` is not implemented for `&str` error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:15:20 @@ -53,7 +53,7 @@ error[E0277]: can't compare `&str` with `char` LL | if x == z {} | ^^ no implementation for `&str == char` | - = help: the trait `std::cmp::PartialEq` is not implemented for `&str` + = help: the trait `PartialEq` is not implemented for `&str` error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/mod_file_not_exist.rs b/src/test/ui/parser/mod_file_not_exist.rs index f4a27b52ec..7b079eb02d 100644 --- a/src/test/ui/parser/mod_file_not_exist.rs +++ b/src/test/ui/parser/mod_file_not_exist.rs @@ -5,5 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index 087ae9fe3e..4e08125625 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -6,11 +6,11 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist.rs:7:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/mod_file_not_exist_windows.rs b/src/test/ui/parser/mod_file_not_exist_windows.rs index 4b7d7a02bb..5db21e2bbc 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.rs +++ b/src/test/ui/parser/mod_file_not_exist_windows.rs @@ -5,5 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist_windows.stderr b/src/test/ui/parser/mod_file_not_exist_windows.stderr index d67205cfdf..73cdf098b0 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.stderr +++ b/src/test/ui/parser/mod_file_not_exist_windows.stderr @@ -6,11 +6,11 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist_windows.rs:7:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/recover-range-pats.rs b/src/test/ui/parser/recover-range-pats.rs index e07ea6221d..7412b624b0 100644 --- a/src/test/ui/parser/recover-range-pats.rs +++ b/src/test/ui/parser/recover-range-pats.rs @@ -17,8 +17,8 @@ fn exclusive_from_to() { if let 0..Y = 0 {} // OK. if let X..3 = 0 {} // OK. if let X..Y = 0 {} // OK. - if let true..Y = 0 {} //~ ERROR only char and numeric types - if let X..true = 0 {} //~ ERROR only char and numeric types + if let true..Y = 0 {} //~ ERROR only `char` and numeric types + if let X..true = 0 {} //~ ERROR only `char` and numeric types if let .0..Y = 0 {} //~ ERROR mismatched types //~^ ERROR float literals must have an integer part if let X.. .0 = 0 {} //~ ERROR mismatched types @@ -30,8 +30,8 @@ fn inclusive_from_to() { if let 0..=Y = 0 {} // OK. if let X..=3 = 0 {} // OK. if let X..=Y = 0 {} // OK. - if let true..=Y = 0 {} //~ ERROR only char and numeric types - if let X..=true = 0 {} //~ ERROR only char and numeric types + if let true..=Y = 0 {} //~ ERROR only `char` and numeric types + if let X..=true = 0 {} //~ ERROR only `char` and numeric types if let .0..=Y = 0 {} //~ ERROR mismatched types //~^ ERROR float literals must have an integer part if let X..=.0 = 0 {} //~ ERROR mismatched types @@ -43,9 +43,9 @@ fn inclusive2_from_to() { if let 0...Y = 0 {} //~ ERROR `...` range patterns are deprecated if let X...3 = 0 {} //~ ERROR `...` range patterns are deprecated if let X...Y = 0 {} //~ ERROR `...` range patterns are deprecated - if let true...Y = 0 {} //~ ERROR only char and numeric types + if let true...Y = 0 {} //~ ERROR only `char` and numeric types //~^ ERROR `...` range patterns are deprecated - if let X...true = 0 {} //~ ERROR only char and numeric types + if let X...true = 0 {} //~ ERROR only `char` and numeric types //~^ ERROR `...` range patterns are deprecated if let .0...Y = 0 {} //~ ERROR mismatched types //~^ ERROR float literals must have an integer part @@ -59,7 +59,7 @@ fn exclusive_from() { if let 0.. = 0 {} if let X.. = 0 {} if let true.. = 0 {} - //~^ ERROR only char and numeric types + //~^ ERROR only `char` and numeric types if let .0.. = 0 {} //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -69,7 +69,7 @@ fn inclusive_from() { if let 0..= = 0 {} //~ ERROR inclusive range with no end if let X..= = 0 {} //~ ERROR inclusive range with no end if let true..= = 0 {} //~ ERROR inclusive range with no end - //~| ERROR only char and numeric types + //~| ERROR only `char` and numeric types if let .0..= = 0 {} //~ ERROR inclusive range with no end //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -79,7 +79,7 @@ fn inclusive2_from() { if let 0... = 0 {} //~ ERROR inclusive range with no end if let X... = 0 {} //~ ERROR inclusive range with no end if let true... = 0 {} //~ ERROR inclusive range with no end - //~| ERROR only char and numeric types + //~| ERROR only `char` and numeric types if let .0... = 0 {} //~ ERROR inclusive range with no end //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -89,7 +89,7 @@ fn exclusive_to() { if let ..0 = 0 {} if let ..Y = 0 {} if let ..true = 0 {} - //~^ ERROR only char and numeric types + //~^ ERROR only `char` and numeric types if let .. .0 = 0 {} //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -99,7 +99,7 @@ fn inclusive_to() { if let ..=3 = 0 {} if let ..=Y = 0 {} if let ..=true = 0 {} - //~^ ERROR only char and numeric types + //~^ ERROR only `char` and numeric types if let ..=.0 = 0 {} //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -112,7 +112,7 @@ fn inclusive2_to() { //~^ ERROR range-to patterns with `...` are not allowed if let ...true = 0 {} //~^ ERROR range-to patterns with `...` are not allowed - //~| ERROR only char and numeric types + //~| ERROR only `char` and numeric types if let ....3 = 0 {} //~^ ERROR float literals must have an integer part //~| ERROR range-to patterns with `...` are not allowed diff --git a/src/test/ui/parser/recover-range-pats.stderr b/src/test/ui/parser/recover-range-pats.stderr index 0d4db74f9f..e351a9783b 100644 --- a/src/test/ui/parser/recover-range-pats.stderr +++ b/src/test/ui/parser/recover-range-pats.stderr @@ -258,7 +258,7 @@ LL | mac2!(0, 1); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:20:12 | LL | if let true..Y = 0 {} @@ -266,7 +266,7 @@ LL | if let true..Y = 0 {} | | | this is of type `bool` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:21:15 | LL | if let X..true = 0 {} @@ -291,7 +291,7 @@ LL | if let X.. .0 = 0 {} | | expected integer, found floating-point number | this is of type `u8` -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:33:12 | LL | if let true..=Y = 0 {} @@ -299,7 +299,7 @@ LL | if let true..=Y = 0 {} | | | this is of type `bool` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:34:16 | LL | if let X..=true = 0 {} @@ -324,7 +324,7 @@ LL | if let X..=.0 = 0 {} | | expected integer, found floating-point number | this is of type `u8` -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:46:12 | LL | if let true...Y = 0 {} @@ -332,7 +332,7 @@ LL | if let true...Y = 0 {} | | | this is of type `bool` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:48:16 | LL | if let X...true = 0 {} @@ -357,7 +357,7 @@ LL | if let X... .0 = 0 {} | | expected integer, found floating-point number | this is of type `u8` -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:61:12 | LL | if let true.. = 0 {} @@ -369,7 +369,7 @@ error[E0308]: mismatched types LL | if let .0.. = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:71:12 | LL | if let true..= = 0 {} @@ -381,7 +381,7 @@ error[E0308]: mismatched types LL | if let .0..= = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:81:12 | LL | if let true... = 0 {} @@ -393,7 +393,7 @@ error[E0308]: mismatched types LL | if let .0... = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:91:14 | LL | if let ..true = 0 {} @@ -405,7 +405,7 @@ error[E0308]: mismatched types LL | if let .. .0 = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:101:15 | LL | if let ..=true = 0 {} @@ -417,7 +417,7 @@ error[E0308]: mismatched types LL | if let ..=.0 = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:113:15 | LL | if let ...true = 0 {} diff --git a/src/test/ui/parser/removed-syntax-with-2.rs b/src/test/ui/parser/removed-syntax-with-2.rs index f666da4969..8a489e7199 100644 --- a/src/test/ui/parser/removed-syntax-with-2.rs +++ b/src/test/ui/parser/removed-syntax-with-2.rs @@ -7,5 +7,5 @@ fn main() { let a = S { foo: (), bar: () }; let b = S { foo: (), with a }; //~^ ERROR expected one of `,` or `}`, found `a` - //~| ERROR missing field `bar` in initializer of `main::S` + //~| ERROR missing field `bar` in initializer of `S` } diff --git a/src/test/ui/parser/removed-syntax-with-2.stderr b/src/test/ui/parser/removed-syntax-with-2.stderr index 024c97cc9c..2c96dceb58 100644 --- a/src/test/ui/parser/removed-syntax-with-2.stderr +++ b/src/test/ui/parser/removed-syntax-with-2.stderr @@ -6,7 +6,7 @@ LL | let b = S { foo: (), with a }; | | | while parsing this struct -error[E0063]: missing field `bar` in initializer of `main::S` +error[E0063]: missing field `bar` in initializer of `S` --> $DIR/removed-syntax-with-2.rs:8:13 | LL | let b = S { foo: (), with a }; diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.rs b/src/test/ui/parser/shebang/shebang-doc-comment.rs index 7dbb9eebc7..72866753e0 100644 --- a/src/test/ui/parser/shebang/shebang-doc-comment.rs +++ b/src/test/ui/parser/shebang/shebang-doc-comment.rs @@ -1,6 +1,3 @@ #!///bin/bash [allow(unused_variables)] -//~^^ ERROR expected `[`, found doc comment - -// Doc comment is misinterpreted as a whitespace (regular comment) during shebang detection. -// Even if it wasn't, it would still result in an error, just a different one. +//~^ ERROR expected item, found `[` diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.stderr b/src/test/ui/parser/shebang/shebang-doc-comment.stderr index f524f55683..2227d45ec5 100644 --- a/src/test/ui/parser/shebang/shebang-doc-comment.stderr +++ b/src/test/ui/parser/shebang/shebang-doc-comment.stderr @@ -1,8 +1,8 @@ -error: expected `[`, found doc comment `///bin/bash` - --> $DIR/shebang-doc-comment.rs:1:3 +error: expected item, found `[` + --> $DIR/shebang-doc-comment.rs:2:1 | -LL | #!///bin/bash - | ^^^^^^^^^^^ expected `[` +LL | [allow(unused_variables)] + | ^ expected item error: aborting due to previous error diff --git a/src/test/ui/parser/struct-literal-in-for.stderr b/src/test/ui/parser/struct-literal-in-for.stderr index 2e59914864..42f5f1e7e7 100644 --- a/src/test/ui/parser/struct-literal-in-for.stderr +++ b/src/test/ui/parser/struct-literal-in-for.stderr @@ -23,8 +23,8 @@ LL | | x: 3 LL | | }.hi() { | |__________^ `bool` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `bool` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `bool` + = note: required by `into_iter` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr index a32a27bf98..d63a50034c 100644 --- a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr +++ b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr @@ -18,7 +18,7 @@ LL | let _: usize = unclosed_delim_mod::new(); | expected due to this | = note: expected type `usize` - found enum `std::result::Result` + found enum `std::result::Result` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/unicode-quote-chars.rs b/src/test/ui/parser/unicode-quote-chars.rs index 1812dad81a..eeaea3628b 100644 --- a/src/test/ui/parser/unicode-quote-chars.rs +++ b/src/test/ui/parser/unicode-quote-chars.rs @@ -6,5 +6,5 @@ fn main() { //~^^ HELP Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '"' (Quotation Mark), but are not //~^^^ ERROR unknown start of token: \u{201d} //~^^^^ HELP Unicode character '”' (Right Double Quotation Mark) looks like '"' (Quotation Mark), but it is not - //~^^^^^ ERROR expected token: `,` + //~^^^^^ ERROR expected `,`, found `world` } diff --git a/src/test/ui/parser/unicode-quote-chars.stderr b/src/test/ui/parser/unicode-quote-chars.stderr index 4b0cb96ed2..d9ec92b3f8 100644 --- a/src/test/ui/parser/unicode-quote-chars.stderr +++ b/src/test/ui/parser/unicode-quote-chars.stderr @@ -20,7 +20,7 @@ help: Unicode character '”' (Right Double Quotation Mark) looks like '"' (Quot LL | println!(“hello world"); | ^ -error: expected token: `,` +error: expected `,`, found `world` --> $DIR/unicode-quote-chars.rs:4:21 | LL | println!(“hello world”); diff --git a/src/test/ui/parser/unsafe-foreign-mod.rs b/src/test/ui/parser/unsafe-foreign-mod.rs new file mode 100644 index 0000000000..872af95bd2 --- /dev/null +++ b/src/test/ui/parser/unsafe-foreign-mod.rs @@ -0,0 +1,9 @@ +unsafe extern { + //~^ ERROR extern block cannot be declared unsafe +} + +unsafe extern "C" { + //~^ ERROR extern block cannot be declared unsafe +} + +fn main() {} diff --git a/src/test/ui/parser/unsafe-foreign-mod.stderr b/src/test/ui/parser/unsafe-foreign-mod.stderr new file mode 100644 index 0000000000..5e10988051 --- /dev/null +++ b/src/test/ui/parser/unsafe-foreign-mod.stderr @@ -0,0 +1,14 @@ +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod.rs:1:1 + | +LL | unsafe extern { + | ^^^^^^ + +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod.rs:5:1 + | +LL | unsafe extern "C" { + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/unsafe-mod.rs b/src/test/ui/parser/unsafe-mod.rs new file mode 100644 index 0000000000..7916d878ea --- /dev/null +++ b/src/test/ui/parser/unsafe-mod.rs @@ -0,0 +1,9 @@ +unsafe mod m { + //~^ ERROR module cannot be declared unsafe +} + +unsafe mod n; +//~^ ERROR module cannot be declared unsafe +//~^^ ERROR file not found for module `n` + +fn main() {} diff --git a/src/test/ui/parser/unsafe-mod.stderr b/src/test/ui/parser/unsafe-mod.stderr new file mode 100644 index 0000000000..259b2c1d61 --- /dev/null +++ b/src/test/ui/parser/unsafe-mod.stderr @@ -0,0 +1,23 @@ +error[E0583]: file not found for module `n` + --> $DIR/unsafe-mod.rs:5:1 + | +LL | unsafe mod n; + | ^^^^^^^^^^^^^ + | + = help: to create the module `n`, create file "$DIR/n.rs" + +error: module cannot be declared unsafe + --> $DIR/unsafe-mod.rs:1:1 + | +LL | unsafe mod m { + | ^^^^^^ + +error: module cannot be declared unsafe + --> $DIR/unsafe-mod.rs:5:1 + | +LL | unsafe mod n; + | ^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0583`. diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index 6acc09b62c..6decbef1af 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `&T` with `T` LL | a == b; | ^^ no implementation for `&T == T` | - = help: the trait `std::cmp::PartialEq` is not implemented for `&T` + = help: the trait `PartialEq` is not implemented for `&T` error: aborting due to previous error diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr index 56613ee761..d28edd11e1 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:14:13 | LL | let a @ b = U; - | ----^ - move occurs because value has type `main::U`, which does not implement the `Copy` trait + | ----^ - move occurs because value has type `U`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -11,7 +11,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:16:17 | LL | let a @ (b, c) = (U, U); - | --------^- ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | --------^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -20,7 +20,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:18:17 | LL | let a @ (b, c) = (u(), u()); - | --------^- ---------- move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | --------^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -29,7 +29,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:21:16 | LL | match Ok(U) { - | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait + | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait LL | a @ Ok(b) | a @ Err(b) => {} | -------^- | | | @@ -40,7 +40,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:21:29 | LL | match Ok(U) { - | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait + | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait LL | a @ Ok(b) | a @ Err(b) => {} | --------^- | | | @@ -51,7 +51,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:28:22 | LL | match [u(), u(), u(), u()] { - | -------------------- move occurs because value has type `[main::U; 4]`, which does not implement the `Copy` trait + | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait LL | xs @ [a, .., b] => {} | -------------^- | | | @@ -62,7 +62,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:32:18 | LL | match [u(), u(), u(), u()] { - | -------------------- move occurs because value has type `[main::U; 4]`, which does not implement the `Copy` trait + | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait LL | xs @ [_, ys @ .., _] => {} | ---------^^^^^^^---- | | | @@ -77,7 +77,7 @@ LL | fn fun(a @ b: U) {} | | | | | value used here after move | value moved here - | move occurs because value has type `main::U`, which does not implement the `Copy` trait + | move occurs because value has type `U`, which does not implement the `Copy` trait error: aborting due to 8 previous errors diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr index 5ce546f08b..44888369ab 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -74,7 +74,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-at-and-box.rs:21:18 | LL | let a @ box &b = Box::new(&C); - | ---------^ ------------ move occurs because value has type `std::boxed::Box<&C>`, which does not implement the `Copy` trait + | ---------^ ------------ move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -83,7 +83,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-at-and-box.rs:24:17 | LL | let a @ box b = Box::new(C); - | --------^ ----------- move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | --------^ ----------- move occurs because value has type `Box`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -92,7 +92,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-at-and-box.rs:34:17 | LL | match Box::new(C) { - | ----------- move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | ----------- move occurs because value has type `Box`, which does not implement the `Copy` trait LL | a @ box b => {} | --------^ | | | @@ -143,7 +143,7 @@ LL | fn f1(a @ box &b: Box<&C>) {} | | | | | value used here after move | value moved here - | move occurs because value has type `std::boxed::Box<&C>`, which does not implement the `Copy` trait + | move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait error[E0382]: use of moved value --> $DIR/borrowck-pat-at-and-box.rs:30:19 @@ -153,7 +153,7 @@ LL | fn f2(a @ box b: Box) {} | | | | | value used here after move | value moved here - | move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because value has type `Box`, which does not implement the `Copy` trait error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-at-and-box.rs:58:27 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr index 54900e958c..dacf23f9de 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr @@ -6,7 +6,7 @@ LL | let a @ ref b = U; | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `U` which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index 5058998f2a..86e09e5558 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -6,7 +6,7 @@ LL | let a @ ref b = U; | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9 @@ -17,7 +17,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:14 @@ -27,7 +27,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 @@ -37,7 +37,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9 @@ -48,7 +48,7 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `[main::U; 2]` which does not implement the `Copy` trait + | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:9 @@ -58,7 +58,7 @@ LL | let a @ ref b = u(); | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:9 @@ -69,7 +69,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:14 @@ -79,7 +79,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 @@ -89,7 +89,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:9 @@ -100,7 +100,7 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `[main::U; 2]` which does not implement the `Copy` trait + | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:56:9 @@ -110,7 +110,7 @@ LL | a @ Some(ref b) => {} | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option` which does not implement the `Copy` trait + | move occurs because `a` has type `Option` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 @@ -121,7 +121,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<(main::U, main::U)>` which does not implement the `Copy` trait + | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:19 @@ -131,7 +131,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 @@ -141,7 +141,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:9 @@ -152,7 +152,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<[main::U; 2]>` which does not implement the `Copy` trait + | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:9 @@ -162,7 +162,7 @@ LL | a @ Some(ref b) => {} | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option` which does not implement the `Copy` trait + | move occurs because `a` has type `Option` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:9 @@ -173,7 +173,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<(main::U, main::U)>` which does not implement the `Copy` trait + | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:19 @@ -183,7 +183,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 @@ -193,7 +193,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:9 @@ -204,7 +204,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<[main::U; 2]>` which does not implement the `Copy` trait + | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 @@ -214,7 +214,7 @@ LL | fn f1(a @ ref b: U) {} | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:11 @@ -225,7 +225,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:20 @@ -235,7 +235,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 @@ -245,7 +245,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:11 @@ -256,7 +256,7 @@ LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `[main::U; 2]` which does not implement the `Copy` trait + | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:22 @@ -267,13 +267,13 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); - | ------------------------^^^^^^^^^- ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | ------------------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -287,13 +287,13 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:25 | LL | let a @ [ref mut b, ref c] = [U, U]; - | ----------------^^^^^- ------ move occurs because value has type `[main::U; 2]`, which does not implement the `Copy` trait + | ----------------^^^^^- ------ move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -302,7 +302,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:13 | LL | let a @ ref b = u(); - | ----^^^^^ --- move occurs because value has type `main::U`, which does not implement the `Copy` trait + | ----^^^^^ --- move occurs because value has type `U`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -316,13 +316,13 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); - | ------------------------^^^^^^^^^- ---------- move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | ------------------------^^^^^^^^^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -336,13 +336,13 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:25 | LL | let a @ [ref mut b, ref c] = [u(), u()]; - | ----------------^^^^^- ---------- move occurs because value has type `[main::U; 2]`, which does not implement the `Copy` trait + | ----------------^^^^^- ---------- move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -356,7 +356,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving the value | LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} @@ -366,7 +366,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 | LL | match Some((U, U)) { - | ------------ move occurs because value has type `std::option::Option<(main::U, main::U)>`, which does not implement the `Copy` trait + | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----------------------------^^^^^^^^^-- | | | @@ -382,7 +382,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving the value | LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} @@ -392,7 +392,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30 | LL | match Some([U, U]) { - | ------------ move occurs because value has type `std::option::Option<[main::U; 2]>`, which does not implement the `Copy` trait + | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait LL | mut a @ Some([ref b, ref mut c]) => {} | ---------------------^^^^^^^^^-- | | | @@ -403,7 +403,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:18 | LL | match Some(u()) { - | --------- move occurs because value has type `std::option::Option`, which does not implement the `Copy` trait + | --------- move occurs because value has type `Option`, which does not implement the `Copy` trait LL | a @ Some(ref b) => {} | ---------^^^^^- | | | @@ -419,7 +419,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving the value | LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} @@ -429,7 +429,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 | LL | match Some((u(), u())) { - | ---------------- move occurs because value has type `std::option::Option<(main::U, main::U)>`, which does not implement the `Copy` trait + | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----------------------------^^^^^^^^^-- | | | @@ -445,7 +445,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving the value | LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} @@ -455,7 +455,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30 | LL | match Some([u(), u()]) { - | ---------------- move occurs because value has type `std::option::Option<[main::U; 2]>`, which does not implement the `Copy` trait + | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait LL | mut a @ Some([ref b, ref mut c]) => {} | ---------------------^^^^^^^^^-- | | | @@ -470,7 +470,7 @@ LL | fn f1(a @ ref b: U) {} | | | | | value borrowed here after move | value moved here - | move occurs because value has type `main::U`, which does not implement the `Copy` trait + | move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:24 @@ -481,7 +481,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 @@ -491,7 +491,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | | | value used here after move | value moved here - | move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | move occurs because value has type `(U, U)`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:39 @@ -502,7 +502,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:27 @@ -512,7 +512,7 @@ LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | | | | | value borrowed here after move | value moved here - | move occurs because value has type `[main::U; 2]`, which does not implement the `Copy` trait + | move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait error: aborting due to 48 previous errors diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index b161054414..695da9639a 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -374,7 +374,7 @@ error[E0507]: cannot move out of `b` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} - | ^ move occurs because `b` has type `&mut main::U`, which does not implement the `Copy` trait + | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard @@ -382,7 +382,7 @@ error[E0507]: cannot move out of `b` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} - | ^ move occurs because `b` has type `&mut main::U`, which does not implement the `Copy` trait + | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard @@ -390,7 +390,7 @@ error[E0507]: cannot move out of `a` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} - | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait + | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard @@ -398,7 +398,7 @@ error[E0507]: cannot move out of `a` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} - | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait + | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index ae7c8f38e1..1cd3e267b9 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -96,7 +96,7 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9 @@ -108,7 +108,7 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `&mut (main::U, [main::U; 2])` which does not implement the `Copy` trait + | move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9 @@ -118,7 +118,7 @@ LL | let a @ &mut ref mut b = &mut U; | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `&mut main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:77:9 @@ -129,7 +129,7 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `&mut (main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 @@ -286,7 +286,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:66:25 | LL | let a @ (ref mut b, ref mut c) = (U, U); - | ----------------^^^^^^^^^- ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | ----------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -295,7 +295,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:70:21 | LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- - | ------------^-- -------- move occurs because value has type `&mut (main::U, [main::U; 2])`, which does not implement the `Copy` trait + | ------------^-- -------- move occurs because value has type `&mut (U, [U; 2])`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -304,7 +304,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:74:18 | LL | let a @ &mut ref mut b = &mut U; - | ---------^^^^^^^^^ ------ move occurs because value has type `&mut main::U`, which does not implement the `Copy` trait + | ---------^^^^^^^^^ ------ move occurs because value has type `&mut U`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -313,7 +313,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:77:30 | LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); - | ---------------------^^^^^^^^^- ----------- move occurs because value has type `&mut (main::U, main::U)`, which does not implement the `Copy` trait + | ---------------------^^^^^^^^^- ----------- move occurs because value has type `&mut (U, U)`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index 141d667c74..a63a5a1e6c 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -33,7 +33,7 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::NotCopy` which does not implement the `Copy` trait + | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:44:9 diff --git a/src/test/ui/pattern/const-pat-ice.rs b/src/test/ui/pattern/const-pat-ice.rs index 0655876788..abfacf3936 100644 --- a/src/test/ui/pattern/const-pat-ice.rs +++ b/src/test/ui/pattern/const-pat-ice.rs @@ -1,10 +1,4 @@ -// failure-status: 101 -// rustc-env:RUST_BACKTRACE=0 -// normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET" -// normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS" -// normalize-stderr-test "/_match.rs:[0-9]+:[0-9]+" -> "/_match.rs:LL:CC" - -// This is a repro test for an ICE in our pattern handling of constants. +// check-pass const FOO: &&&u32 = &&&42; diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr deleted file mode 100644 index 2aa0824f30..0000000000 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ /dev/null @@ -1,13 +0,0 @@ -thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir_build/thir/pattern/_match.rs:LL:CC -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc VERSION running on TARGET - -note: compiler flags: FLAGS - diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs index c5e4a72fb9..65f27cf78f 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs @@ -4,6 +4,7 @@ fn main() { const C: impl Copy = 0; match C { - C | _ => {} //~ ERROR: opaque types cannot be used in patterns + C | //~ ERROR: `impl Copy` cannot be used in patterns + _ => {} } } diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr index 7695223f2c..62dc856be8 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr @@ -1,7 +1,7 @@ -error: opaque types cannot be used in patterns +error: `impl Copy` cannot be used in patterns --> $DIR/issue-71042-opaquely-typed-constant-used-in-pattern.rs:7:9 | -LL | C | _ => {} +LL | C | | ^ error: aborting due to previous error diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr index eb5391a95d..5335569a97 100644 --- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr +++ b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr @@ -49,7 +49,7 @@ LL | let (a, mut b) = &tup; | ----- ^^^^ | | | data moved here - | move occurs because `b` has type `main::X`, which does not implement the `Copy` trait + | move occurs because `b` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of a mutable reference --> $DIR/feature-gate-move_ref_pattern.rs:20:22 @@ -58,7 +58,7 @@ LL | let (mut a, b) = &mut tup; | ----- ^^^^^^^^ | | | data moved here - | move occurs because `a` has type `main::X`, which does not implement the `Copy` trait + | move occurs because `a` has type `X`, which does not implement the `Copy` trait error: aborting due to 6 previous errors diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr index 9159e3e221..9ad8487959 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `tup0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 | LL | let mut tup0 = (S, S); - | -------- move occurs because `tup0` has type `(main::S, main::S)`, which does not implement the `Copy` trait + | -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -17,7 +17,7 @@ error[E0382]: borrow of moved value: `tup1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 | LL | let mut tup1 = (S, S, S); - | -------- move occurs because `tup1` has type `(main::S, main::S, main::S)`, which does not implement the `Copy` trait + | -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -32,7 +32,7 @@ error[E0382]: borrow of moved value: `tup2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:35:10 | LL | let tup2 = (S, S); - | ---- move occurs because `tup2` has type `(main::S, main::S)`, which does not implement the `Copy` trait + | ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -47,7 +47,7 @@ error[E0382]: borrow of moved value: `tup3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:36:10 | LL | let tup3 = (S, S, S); - | ---- move occurs because `tup3` has type `(main::S, main::S, main::S)`, which does not implement the `Copy` trait + | ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -62,7 +62,7 @@ error[E0382]: borrow of moved value: `tup4` --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 | LL | let tup4 = (S, S); - | ---- move occurs because `tup4` has type `(main::S, main::S)`, which does not implement the `Copy` trait + | ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -77,7 +77,7 @@ error[E0382]: borrow of moved value: `arr0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 | LL | let mut arr0 = [S, S, S]; - | -------- move occurs because `arr0` has type `[main::S; 3]`, which does not implement the `Copy` trait + | -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -92,7 +92,7 @@ error[E0382]: borrow of moved value: `arr1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 | LL | let mut arr1 = [S, S, S, S, S]; - | -------- move occurs because `arr1` has type `[main::S; 5]`, which does not implement the `Copy` trait + | -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -107,7 +107,7 @@ error[E0382]: borrow of moved value: `arr2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:45:10 | LL | let arr2 = [S, S, S]; - | ---- move occurs because `arr2` has type `[main::S; 3]`, which does not implement the `Copy` trait + | ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -122,7 +122,7 @@ error[E0382]: borrow of moved value: `arr3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:46:36 | LL | let arr3 = [S, S, S, S, S]; - | ---- move occurs because `arr3` has type `[main::S; 5]`, which does not implement the `Copy` trait + | ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -137,7 +137,7 @@ error[E0382]: borrow of moved value: `tup0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 | LL | let mut tup0: Option<(S, S)> = None; - | -------- move occurs because `tup0` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -151,7 +151,7 @@ error[E0382]: borrow of moved value: `tup1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 | LL | let mut tup1: Option<(S, S, S)> = None; - | -------- move occurs because `tup1` has type `std::option::Option<(main::S, main::S, main::S)>`, which does not implement the `Copy` trait + | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -166,7 +166,7 @@ error[E0382]: borrow of moved value: `tup2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:10 | LL | let tup2: Option<(S, S)> = None; - | ---- move occurs because `tup2` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -181,7 +181,7 @@ error[E0382]: borrow of moved value: `tup3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 | LL | let tup3: Option<(S, S, S)> = None; - | ---- move occurs because `tup3` has type `std::option::Option<(main::S, main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -196,7 +196,7 @@ error[E0382]: borrow of moved value: `tup4` --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:21 | LL | let tup4: Option<(S, S)> = None; - | ---- move occurs because `tup4` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -211,7 +211,7 @@ error[E0382]: borrow of moved value: `arr0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 | LL | let mut arr0: Option<[S; 3]> = None; - | -------- move occurs because `arr0` has type `std::option::Option<[main::S; 3]>`, which does not implement the `Copy` trait + | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -226,7 +226,7 @@ error[E0382]: borrow of moved value: `arr1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 | LL | let mut arr1: Option<[S; 5]> = None; - | -------- move occurs because `arr1` has type `std::option::Option<[main::S; 5]>`, which does not implement the `Copy` trait + | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -241,7 +241,7 @@ error[E0382]: borrow of moved value: `arr2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:84:10 | LL | let arr2: Option<[S; 3]> = None; - | ---- move occurs because `arr2` has type `std::option::Option<[main::S; 3]>`, which does not implement the `Copy` trait + | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait LL | let arr3: Option<[S; 5]> = None; LL | let mut closure = || { | -- value moved into closure here @@ -256,7 +256,7 @@ error[E0382]: borrow of moved value: `arr3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:85:35 | LL | let arr3: Option<[S; 5]> = None; - | ---- move occurs because `arr3` has type `std::option::Option<[main::S; 5]>`, which does not implement the `Copy` trait + | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait LL | let mut closure = || { | -- value moved into closure here ... @@ -270,7 +270,7 @@ error[E0382]: borrow of moved value: `tup0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 | LL | let mut tup0: Option<(S, S)> = None; - | -------- move occurs because `tup0` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -284,7 +284,7 @@ error[E0382]: borrow of moved value: `tup1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 | LL | let mut tup1: Option<(S, S, S)> = None; - | -------- move occurs because `tup1` has type `std::option::Option<(main::S, main::S, main::S)>`, which does not implement the `Copy` trait + | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -299,7 +299,7 @@ error[E0382]: borrow of moved value: `tup2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:10 | LL | let tup2: Option<(S, S)> = None; - | ---- move occurs because `tup2` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -314,7 +314,7 @@ error[E0382]: borrow of moved value: `tup3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 | LL | let tup3: Option<(S, S, S)> = None; - | ---- move occurs because `tup3` has type `std::option::Option<(main::S, main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -329,7 +329,7 @@ error[E0382]: borrow of moved value: `tup4` --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:21 | LL | let tup4: Option<(S, S)> = None; - | ---- move occurs because `tup4` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -344,7 +344,7 @@ error[E0382]: borrow of moved value: `arr0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 | LL | let mut arr0: Option<[S; 3]> = None; - | -------- move occurs because `arr0` has type `std::option::Option<[main::S; 3]>`, which does not implement the `Copy` trait + | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -359,7 +359,7 @@ error[E0382]: borrow of moved value: `arr1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 | LL | let mut arr1: Option<[S; 5]> = None; - | -------- move occurs because `arr1` has type `std::option::Option<[main::S; 5]>`, which does not implement the `Copy` trait + | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -374,7 +374,7 @@ error[E0382]: borrow of moved value: `arr2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:120:10 | LL | let arr2: Option<[S; 3]> = None; - | ---- move occurs because `arr2` has type `std::option::Option<[main::S; 3]>`, which does not implement the `Copy` trait + | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait LL | let arr3: Option<[S; 5]> = None; LL | let mut closure = || { | -- value moved into closure here @@ -389,7 +389,7 @@ error[E0382]: borrow of moved value: `arr3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:121:35 | LL | let arr3: Option<[S; 5]> = None; - | ---- move occurs because `arr3` has type `std::option::Option<[main::S; 5]>`, which does not implement the `Copy` trait + | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait LL | let mut closure = || { | -- value moved into closure here ... diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr index fe7f71e6c4..f92699f5c3 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -5,7 +5,7 @@ LL | let (a, mut b) = &p; | ----- ^^ | | | data moved here - | move occurs because `b` has type `main::U`, which does not implement the `Copy` trait + | move occurs because `b` has type `U`, which does not implement the `Copy` trait error[E0507]: cannot move out of a mutable reference --> $DIR/move-ref-patterns-default-binding-modes.rs:14:22 @@ -14,7 +14,7 @@ LL | let (a, mut b) = &mut p; | ----- ^^^^^^ | | | data moved here - | move occurs because `b` has type `main::U`, which does not implement the `Copy` trait + | move occurs because `b` has type `U`, which does not implement the `Copy` trait error: aborting due to 2 previous errors diff --git a/src/test/ui/pattern/pat-type-err-formal-param.stderr b/src/test/ui/pattern/pat-type-err-formal-param.stderr index 2d7eb62fae..206713a4bf 100644 --- a/src/test/ui/pattern/pat-type-err-formal-param.stderr +++ b/src/test/ui/pattern/pat-type-err-formal-param.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn foo(Tuple(_): String) {} | ^^^^^^^^ ------ expected due to this | | - | expected struct `std::string::String`, found struct `Tuple` + | expected struct `String`, found struct `Tuple` error: aborting due to previous error diff --git a/src/test/ui/pattern/pat-type-err-let-stmt.stderr b/src/test/ui/pattern/pat-type-err-let-stmt.stderr index d75fa3f247..42258cfc1a 100644 --- a/src/test/ui/pattern/pat-type-err-let-stmt.stderr +++ b/src/test/ui/pattern/pat-type-err-let-stmt.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | let Ok(0): Option = 42u8; | ---------- ^^^^ | | | - | | expected enum `std::option::Option`, found `u8` + | | expected enum `Option`, found `u8` | | help: try using a variant of the expected enum: `Some(42u8)` | expected due to this | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found type `u8` error[E0308]: mismatched types @@ -17,9 +17,9 @@ error[E0308]: mismatched types LL | let Ok(0): Option = 42u8; | ^^^^^ ---------- expected due to this | | - | expected enum `std::option::Option`, found enum `std::result::Result` + | expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found enum `std::result::Result<_, _>` error[E0308]: mismatched types @@ -28,9 +28,9 @@ error[E0308]: mismatched types LL | let Ok(0): Option; | ^^^^^ ---------- expected due to this | | - | expected enum `std::option::Option`, found enum `std::result::Result` + | expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found enum `std::result::Result<_, _>` error[E0308]: mismatched types diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.rs b/src/test/ui/pattern/patkind-litrange-no-expr.rs index 5b3db2e57c..9464f277fb 100644 --- a/src/test/ui/pattern/patkind-litrange-no-expr.rs +++ b/src/test/ui/pattern/patkind-litrange-no-expr.rs @@ -19,7 +19,7 @@ enum_number!(Change { Neg = -1, Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns //~| ERROR arbitrary expressions aren't allowed in patterns - //~| ERROR only char and numeric types are allowed in range patterns + //~| ERROR only `char` and numeric types are allowed in range patterns }); fn main() {} diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.stderr b/src/test/ui/pattern/patkind-litrange-no-expr.stderr index 70dd1a9263..51af167a7c 100644 --- a/src/test/ui/pattern/patkind-litrange-no-expr.stderr +++ b/src/test/ui/pattern/patkind-litrange-no-expr.stderr @@ -10,7 +10,7 @@ error: arbitrary expressions aren't allowed in patterns LL | Arith = 1 + 1, | ^^^^^ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/patkind-litrange-no-expr.rs:20:13 | LL | $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range diff --git a/src/test/ui/pattern/pattern-error-continue.rs b/src/test/ui/pattern/pattern-error-continue.rs index 8635622ab3..0702a9986f 100644 --- a/src/test/ui/pattern/pattern-error-continue.rs +++ b/src/test/ui/pattern/pattern-error-continue.rs @@ -30,6 +30,6 @@ fn main() { //~| expected `char`, found `bool` match () { - E::V => {} //~ ERROR failed to resolve: use of undeclared type or module `E` + E::V => {} //~ ERROR failed to resolve: use of undeclared type `E` } } diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr index 60f76796c0..497c93b294 100644 --- a/src/test/ui/pattern/pattern-error-continue.stderr +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `E` +error[E0433]: failed to resolve: use of undeclared type `E` --> $DIR/pattern-error-continue.rs:33:9 | LL | E::V => {} - | ^ use of undeclared type or module `E` + | ^ use of undeclared type `E` error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D` --> $DIR/pattern-error-continue.rs:18:9 diff --git a/src/test/ui/pattern/pattern-ident-path-generics.stderr b/src/test/ui/pattern/pattern-ident-path-generics.stderr index 24b5cdf98d..01b082bd35 100644 --- a/src/test/ui/pattern/pattern-ident-path-generics.stderr +++ b/src/test/ui/pattern/pattern-ident-path-generics.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/pattern-ident-path-generics.rs:3:9 | LL | match Some("foo") { - | ----------- this expression has type `std::option::Option<&str>` + | ----------- this expression has type `Option<&str>` LL | None:: => {} | ^^^^^^^^^^^^^ expected `&str`, found `isize` | - = note: expected enum `std::option::Option<&str>` - found enum `std::option::Option` + = note: expected enum `Option<&str>` + found enum `Option` error: aborting due to previous error diff --git a/src/test/ui/pattern/pattern-tyvar-2.rs b/src/test/ui/pattern/pattern-tyvar-2.rs index 4c6d515b86..532df4fa0c 100644 --- a/src/test/ui/pattern/pattern-tyvar-2.rs +++ b/src/test/ui/pattern/pattern-tyvar-2.rs @@ -1,6 +1,6 @@ enum Bar { T1((), Option>), T2, } fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } } -//~^ ERROR cannot multiply `{integer}` to `std::vec::Vec` +//~^ ERROR cannot multiply `{integer}` to `Vec` fn main() { } diff --git a/src/test/ui/pattern/pattern-tyvar-2.stderr b/src/test/ui/pattern/pattern-tyvar-2.stderr index 9566244464..e205cd9015 100644 --- a/src/test/ui/pattern/pattern-tyvar-2.stderr +++ b/src/test/ui/pattern/pattern-tyvar-2.stderr @@ -1,10 +1,10 @@ -error[E0369]: cannot multiply `{integer}` to `std::vec::Vec` +error[E0369]: cannot multiply `{integer}` to `Vec` --> $DIR/pattern-tyvar-2.rs:3:71 | LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } } | - ^ - {integer} | | - | std::vec::Vec + | Vec error: aborting due to previous error diff --git a/src/test/ui/pattern/pattern-tyvar.stderr b/src/test/ui/pattern/pattern-tyvar.stderr index 15425da69b..f1e2a9d72c 100644 --- a/src/test/ui/pattern/pattern-tyvar.stderr +++ b/src/test/ui/pattern/pattern-tyvar.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | match t { | - this expression has type `Bar` LL | Bar::T1(_, Some::(x)) => { - | ^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found `isize` + | ^^^^^^^^^^^^^^^^ expected struct `Vec`, found `isize` | - = note: expected enum `std::option::Option>` - found enum `std::option::Option` + = note: expected enum `Option>` + found enum `Option` error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs index d379dc44bf..78cc0d28fb 100644 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs +++ b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs @@ -160,7 +160,7 @@ fn main() { match &0 { &42 => {} &FOO => {} //~ ERROR unreachable pattern - BAR => {} // Not detected as unreachable because `try_eval_bits` fails on `BAR`. + BAR => {} //~ ERROR unreachable pattern _ => {} } diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr index 161ac47718..9f076c50a8 100644 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr +++ b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr @@ -77,7 +77,7 @@ LL | match (0u8, Some(())) { | ^^^^^^^^^^^^^^^ patterns `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(u8, std::option::Option<()>)` + = note: the matched value is of type `(u8, Option<()>)` error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered --> $DIR/exhaustive_integer_patterns.rs:126:11 @@ -135,6 +135,12 @@ error: unreachable pattern LL | &FOO => {} | ^^^^ -error: aborting due to 15 previous errors +error: unreachable pattern + --> $DIR/exhaustive_integer_patterns.rs:163:9 + | +LL | BAR => {} + | ^^^ + +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-35609.stderr b/src/test/ui/pattern/usefulness/issue-35609.stderr index 66f904aced..0598c8d6f3 100644 --- a/src/test/ui/pattern/usefulness/issue-35609.stderr +++ b/src/test/ui/pattern/usefulness/issue-35609.stderr @@ -74,7 +74,7 @@ LL | match Some(A) { | ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `std::option::Option` + = note: the matched value is of type `Option` error: aborting due to 8 previous errors diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr index d541597508..f515525123 100644 --- a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr +++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr @@ -22,7 +22,7 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), | not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `std::option::Option>` + = note: the matched value is of type `Option>` error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered --> $DIR/match-arm-statics-2.rs:48:11 diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.stderr b/src/test/ui/pattern/usefulness/match-privately-empty.stderr index ca9006469e..cd157debcd 100644 --- a/src/test/ui/pattern/usefulness/match-privately-empty.stderr +++ b/src/test/ui/pattern/usefulness/match-privately-empty.stderr @@ -10,7 +10,7 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), | ---- not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `std::option::Option` + = note: the matched value is of type `Option` error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/match-slice-patterns.stderr b/src/test/ui/pattern/usefulness/match-slice-patterns.stderr index ba5312d213..88f27be041 100644 --- a/src/test/ui/pattern/usefulness/match-slice-patterns.stderr +++ b/src/test/ui/pattern/usefulness/match-slice-patterns.stderr @@ -5,7 +5,7 @@ LL | match list { | ^^^^ pattern `&[_, Some(_), .., None, _]` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `&[std::option::Option<()>]` + = note: the matched value is of type `&[Option<()>]` error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr index c9f26db6f1..d1cab75210 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr @@ -5,7 +5,7 @@ LL | match (l1, l2) { | ^^^^^^^^ pattern `(Some(&[]), Err(_))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(std::option::Option<&[T]>, std::result::Result<&[T], ()>)` + = note: the matched value is of type `(Option<&[T]>, std::result::Result<&[T], ()>)` error[E0004]: non-exhaustive patterns: `A(C)` not covered --> $DIR/non-exhaustive-match-nested.rs:15:11 diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index 5d29feb562..12412743b8 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -34,7 +34,7 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), | ---- not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `std::option::Option` + = note: the matched value is of type `Option` error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered --> $DIR/non-exhaustive-match.rs:14:11 @@ -76,7 +76,7 @@ LL | match *vec { | ^^^^ pattern `[]` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `[std::option::Option]` + = note: the matched value is of type `[Option]` error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered --> $DIR/non-exhaustive-match.rs:46:11 diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr index 8d0409a6af..99af71cadf 100644 --- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr @@ -4,7 +4,7 @@ error[E0005]: refutable pattern in function argument: `(_, _)` not covered LL | fn func((1, (Some(1), 2..=3)): (isize, (Option, isize))) { } | ^^^^^^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered | - = note: the matched value is of type `(isize, (std::option::Option, isize))` + = note: the matched value is of type `(isize, (Option, isize))` error[E0005]: refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered --> $DIR/refutable-pattern-errors.rs:7:9 @@ -14,7 +14,7 @@ LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)); | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html - = note: the matched value is of type `(i32, (std::option::Option, i32))` + = note: the matched value is of type `(i32, (Option, i32))` help: you might want to use `if let` to ignore the variant that isn't matched | LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { /* */ } diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs index a36c550f53..4bf8d0fd2d 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs @@ -6,19 +6,19 @@ fn main() { match s { MAGIC_TEST => (), [0x00, 0x00, 0x00, 0x00] => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), MAGIC_TEST => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), [4, 5, 6, 7] => (), - MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not + MAGIC_TEST => (), //~ ERROR unreachable pattern _ => (), } const FOO: [u32; 1] = [4]; diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr index cd0cb2e887..dcad11a38a 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:28:9 + --> $DIR/slice-pattern-const-2.rs:9:9 | -LL | FOO => (), - | ^^^ +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/slice-pattern-const-2.rs:1:9 @@ -10,5 +10,23 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:15:9 + | +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs index 8805c43ba0..2ca8323f00 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs @@ -6,19 +6,19 @@ fn main() { match s { MAGIC_TEST => (), ["0x00", "0x00", "0x00", "0x00"] => (), - ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern _ => (), } match s { ["0x00", "0x00", "0x00", "0x00"] => (), MAGIC_TEST => (), - ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern _ => (), } match s { ["0x00", "0x00", "0x00", "0x00"] => (), ["4", "5", "6", "7"] => (), - MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not + MAGIC_TEST => (), //~ ERROR unreachable pattern _ => (), } const FOO: [&str; 1] = ["boo"]; diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr index 3ba01b9eba..b90b3a88a1 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-3.rs:28:9 + --> $DIR/slice-pattern-const-3.rs:9:9 | -LL | FOO => (), - | ^^^ +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/slice-pattern-const-3.rs:1:9 @@ -10,5 +10,23 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:15:9 + | +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs index 52d1320dad..46e0da5be9 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs @@ -6,15 +6,15 @@ fn main() { let s10: &[bool; 10] = &[false; 10]; match s2 { - //~^ ERROR `&[false, _]` not covered + //~^ ERROR `&[false, _]` not covered [true, .., true] => {} } match s3 { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [true, .., true] => {} } match s10 { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [true, .., true] => {} } @@ -23,58 +23,58 @@ fn main() { [.., false] => {} } match s2 { - //~^ ERROR `&[false, true]` not covered + //~^ ERROR `&[false, true]` not covered [true, ..] => {} [.., false] => {} } match s3 { - //~^ ERROR `&[false, .., true]` not covered + //~^ ERROR `&[false, .., true]` not covered [true, ..] => {} [.., false] => {} } match s { - //~^ ERROR `&[false, .., true]` not covered + //~^ ERROR `&[false, .., true]` not covered [] => {} [true, ..] => {} [.., false] => {} } match s { - //~^ ERROR `&[_, ..]` not covered + //~^ ERROR `&[_, ..]` not covered [] => {} } match s { - //~^ ERROR `&[_, _, ..]` not covered + //~^ ERROR `&[_, _, ..]` not covered [] => {} [_] => {} } match s { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [] => {} [true, ..] => {} } match s { - //~^ ERROR `&[false, _, ..]` not covered + //~^ ERROR `&[false, _, ..]` not covered [] => {} [_] => {} [true, ..] => {} } match s { - //~^ ERROR `&[_, .., false]` not covered + //~^ ERROR `&[_, .., false]` not covered [] => {} [_] => {} [.., true] => {} } match s { - //~^ ERROR `&[_, _, .., true]` not covered + //~^ ERROR `&[_, _, .., true]` not covered [] => {} [_] => {} [_, _] => {} [.., false] => {} } match s { - //~^ ERROR `&[true, _, .., _]` not covered + //~^ ERROR `&[true, _, .., _]` not covered [] => {} [_] => {} [_, _] => {} @@ -83,19 +83,43 @@ fn main() { const CONST: &[bool] = &[true]; match s { - //~^ ERROR `&[..]` not covered + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[true] => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + CONST => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered CONST => {} + &[false] => {} } match s { - //~^ ERROR `&[true]` not covered - [] => {}, - [false] => {}, - CONST => {}, + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[false] => {} + CONST => {} + } + match s { + //~^ ERROR `&[_, _, ..]` not covered + &[] => {} + CONST => {} + } + match s { + //~^ ERROR `&[false]` not covered + &[] => {} + CONST => {} + &[_, _, ..] => {} + } + match s { + [] => {} + [false] => {} + CONST => {} [_, _, ..] => {} } const CONST1: &[bool; 1] = &[true]; match s1 { - //~^ ERROR `&[false]` not covered + //~^ ERROR `&[false]` not covered CONST1 => {} } match s1 { diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index 8b85eaeda0..e34770fb91 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -115,26 +115,62 @@ LL | match s { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool]` -error[E0004]: non-exhaustive patterns: `&[..]` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered --> $DIR/slice-patterns-exhaustiveness.rs:85:11 | LL | match s { - | ^ pattern `&[..]` not covered + | ^ patterns `&[]` and `&[_, _, ..]` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool]` -error[E0004]: non-exhaustive patterns: `&[true]` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered --> $DIR/slice-patterns-exhaustiveness.rs:89:11 | LL | match s { - | ^ pattern `&[true]` not covered + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:93:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:98:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:103:11 + | +LL | match s { + | ^ pattern `&[_, _, ..]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[false]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:108:11 + | +LL | match s { + | ^ pattern `&[false]` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool]` error[E0004]: non-exhaustive patterns: `&[false]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:97:11 + --> $DIR/slice-patterns-exhaustiveness.rs:121:11 | LL | match s1 { | ^^ pattern `&[false]` not covered @@ -142,6 +178,6 @@ LL | match s1 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool; 1]` -error: aborting due to 16 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-oibit.stderr index e143747d63..8a02f23da9 100644 --- a/src/test/ui/phantom-oibit.stderr +++ b/src/test/ui/phantom-oibit.stderr @@ -8,12 +8,12 @@ LL | is_zen(x) | ^ `T` cannot be shared between threads safely | = note: required because of the requirements on the impl of `Zen` for `&T` - = note: required because it appears within the type `std::marker::PhantomData<&T>` + = note: required because it appears within the type `PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` help: consider restricting type parameter `T` | -LL | fn not_sync(x: Guard) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn not_sync(x: Guard) { + | ^^^^^^ error[E0277]: `T` cannot be shared between threads safely --> $DIR/phantom-oibit.rs:26:12 @@ -25,13 +25,13 @@ LL | is_zen(x) | ^ `T` cannot be shared between threads safely | = note: required because of the requirements on the impl of `Zen` for `&T` - = note: required because it appears within the type `std::marker::PhantomData<&T>` + = note: required because it appears within the type `PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` = note: required because it appears within the type `Nested>` help: consider restricting type parameter `T` | -LL | fn nested_not_sync(x: Nested>) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn nested_not_sync(x: Nested>) { + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs index a80e5df1a2..fa7664a83e 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs @@ -2,16 +2,14 @@ fn foo() -> impl std::fmt::Display { if false { return 0i32; } - 1u32 - //~^ ERROR mismatched types + 1u32 //~ ERROR mismatched types } fn bar() -> impl std::fmt::Display { if false { return 0i32; } else { - return 1u32; - //~^ ERROR mismatched types + return 1u32; //~ ERROR mismatched types } } @@ -19,8 +17,7 @@ fn baz() -> impl std::fmt::Display { if false { return 0i32; } else { - 1u32 - //~^ ERROR mismatched types + 1u32 //~ ERROR mismatched types } } @@ -28,22 +25,19 @@ fn qux() -> impl std::fmt::Display { if false { 0i32 } else { - 1u32 - //~^ ERROR `if` and `else` have incompatible types + 1u32 //~ ERROR `if` and `else` have incompatible types } } fn bat() -> impl std::fmt::Display { match 13 { 0 => return 0i32, - _ => 1u32, - //~^ ERROR mismatched types + _ => 1u32, //~ ERROR mismatched types } } fn can() -> impl std::fmt::Display { - match 13 { - //~^ ERROR mismatched types + match 13 { //~ ERROR mismatched types 0 => return 0i32, 1 => 1u32, _ => 2u32, @@ -51,15 +45,57 @@ fn can() -> impl std::fmt::Display { } fn cat() -> impl std::fmt::Display { + match 13 { + 0 => { + return 0i32; + } + _ => { + 1u32 //~ ERROR mismatched types + } + } +} + +fn dog() -> impl std::fmt::Display { + match 13 { + 0 => 0i32, + 1 => 1u32, //~ ERROR `match` arms have incompatible types + _ => 2u32, + } +} + +fn hat() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object match 13 { 0 => { return 0i32; } _ => { 1u32 - //~^ ERROR mismatched types } } } +fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + match 13 { + 0 => 0i32, + 1 => 1u32, //~ ERROR `match` arms have incompatible types + _ => 2u32, + } +} + +fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + if false { + 0i32 + } else { + 1u32 //~ ERROR `if` and `else` have incompatible types + } +} + +fn apt() -> impl std::fmt::Display { + if let Some(42) = Some(42) { + 0i32 + } else { + 1u32 //~ ERROR `if` and `else` have incompatible types + } +} + fn main() {} diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr index b663cccbee..eb4dc45c8a 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr @@ -12,12 +12,21 @@ LL | 1u32 | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn foo() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } +LL | Box::new(1u32) + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16 | LL | fn bar() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -30,12 +39,21 @@ LL | return 1u32; | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn bar() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } else { +LL | return Box::new(1u32); + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9 | LL | fn baz() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -48,12 +66,21 @@ LL | 1u32 | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn baz() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } else { +LL | Box::new(1u32) + | error[E0308]: `if` and `else` have incompatible types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9 | LL | / if false { LL | | 0i32 @@ -61,12 +88,22 @@ LL | | 0i32 LL | | } else { LL | | 1u32 | | ^^^^ expected `i32`, found `u32` -LL | | LL | | } | |_____- `if` and `else` have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn qux() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | Box::new(0i32) +LL | } else { +LL | Box::new(1u32) + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:39:14 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14 | LL | fn bat() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -78,17 +115,24 @@ LL | _ => 1u32, | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn bat() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | 0 => return Box::new(0i32), +LL | _ => Box::new(1u32), + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5 | LL | fn can() -> impl std::fmt::Display { | ---------------------- expected because this return type... LL | / match 13 { -LL | | LL | | 0 => return 0i32, | | ---- ...is found to be `i32` here LL | | 1 => 1u32, @@ -98,12 +142,23 @@ LL | | } | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn can() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | Box::new(match 13 { +LL | 0 => return Box::new(0i32), +LL | 1 => 1u32, +LL | _ => 2u32, +LL | }) + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13 | LL | fn cat() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -116,10 +171,148 @@ LL | 1u32 | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn cat() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } +LL | _ => { +LL | Box::new(1u32) + | + +error[E0308]: `match` arms have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14 + | +LL | / match 13 { +LL | | 0 => 0i32, + | | ---- this is found to be of type `i32` +LL | | 1 => 1u32, + | | ^^^^ expected `i32`, found `u32` +LL | | _ => 2u32, +LL | | } + | |_____- `match` arms have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn dog() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | 0 => Box::new(0i32), +LL | 1 => Box::new(1u32), + | + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9 + | +LL | / if let Some(42) = Some(42) { +LL | | 0i32 + | | ---- expected because of this +LL | | } else { +LL | | 1u32 + | | ^^^^ expected `i32`, found `u32` +LL | | } + | |_____- `if` and `else` have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn apt() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | Box::new(0i32) +LL | } else { +LL | Box::new(1u32) + | + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13 + | +LL | fn hat() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn hat() -> Box { +LL | match 13 { +LL | 0 => { +LL | return Box::new(0i32); +LL | } +LL | _ => { + ... + +error[E0308]: `match` arms have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14 + | +LL | / match 13 { +LL | | 0 => 0i32, + | | ---- this is found to be of type `i32` +LL | | 1 => 1u32, + | | ^^^^ expected `i32`, found `u32` +LL | | _ => 2u32, +LL | | } + | |_____- `match` arms have incompatible types + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13 + | +LL | fn pug() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn pug() -> Box { +LL | match 13 { +LL | 0 => Box::new(0i32), +LL | 1 => Box::new(1u32), +LL | _ => Box::new(2u32), + | + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9 + | +LL | / if false { +LL | | 0i32 + | | ---- expected because of this +LL | | } else { +LL | | 1u32 + | | ^^^^ expected `i32`, found `u32` +LL | | } + | |_____- `if` and `else` have incompatible types + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13 + | +LL | fn man() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn man() -> Box { +LL | if false { +LL | Box::new(0i32) +LL | } else { +LL | Box::new(1u32) + | -error: aborting due to 7 previous errors +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0746. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/privacy/associated-item-privacy-trait.rs b/src/test/ui/privacy/associated-item-privacy-trait.rs index b1482bc040..b4e98debcf 100644 --- a/src/test/ui/privacy/associated-item-privacy-trait.rs +++ b/src/test/ui/privacy/associated-item-privacy-trait.rs @@ -15,21 +15,21 @@ mod priv_trait { pub macro mac() { let value = ::method; - //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private + //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private value; - //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private + //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private Pub.method(); - //~^ ERROR type `for<'r> fn(&'r Self) {::method}` is private + //~^ ERROR type `for<'r> fn(&'r Self) {::method}` is private ::CONST; //~^ ERROR associated constant `::CONST` is private let _: ::AssocTy; //~^ ERROR associated type `::AssocTy` is private pub type InSignatureTy = ::AssocTy; - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private pub trait InSignatureTr: PrivTr {} - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private impl PrivTr for u8 {} - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private } } fn priv_trait() { diff --git a/src/test/ui/privacy/associated-item-privacy-trait.stderr b/src/test/ui/privacy/associated-item-privacy-trait.stderr index b9f3e35d72..8e58a2fa08 100644 --- a/src/test/ui/privacy/associated-item-privacy-trait.stderr +++ b/src/test/ui/privacy/associated-item-privacy-trait.stderr @@ -1,4 +1,4 @@ -error: type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private +error: type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private --> $DIR/associated-item-privacy-trait.rs:17:21 | LL | let value = ::method; @@ -9,7 +9,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private +error: type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private --> $DIR/associated-item-privacy-trait.rs:19:9 | LL | value; @@ -20,7 +20,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `for<'r> fn(&'r Self) {::method}` is private +error: type `for<'r> fn(&'r Self) {::method}` is private --> $DIR/associated-item-privacy-trait.rs:21:13 | LL | Pub.method(); @@ -53,7 +53,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-trait.rs:27:34 | LL | pub type InSignatureTy = ::AssocTy; @@ -64,7 +64,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-trait.rs:29:34 | LL | pub trait InSignatureTr: PrivTr {} @@ -75,7 +75,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-trait.rs:31:14 | LL | impl PrivTr for u8 {} diff --git a/src/test/ui/privacy/associated-item-privacy-type-binding.rs b/src/test/ui/privacy/associated-item-privacy-type-binding.rs index b9c526f515..9826b83a35 100644 --- a/src/test/ui/privacy/associated-item-privacy-type-binding.rs +++ b/src/test/ui/privacy/associated-item-privacy-type-binding.rs @@ -9,21 +9,21 @@ mod priv_trait { pub macro mac1() { let _: Box>; - //~^ ERROR trait `priv_trait::PrivTr` is private - //~| ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private + //~| ERROR trait `PrivTr` is private type InSignatureTy2 = Box>; - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private trait InSignatureTr2: PubTr {} - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private } pub macro mac2() { let _: Box>; - //~^ ERROR trait `priv_trait::PrivTr` is private - //~| ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private + //~| ERROR trait `PrivTr` is private type InSignatureTy1 = Box>; - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private trait InSignatureTr1: PrivTr {} - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private } } fn priv_trait1() { @@ -42,19 +42,19 @@ mod priv_parent_substs { pub macro mac() { let _: Box>; - //~^ ERROR type `priv_parent_substs::Priv` is private - //~| ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private + //~| ERROR type `Priv` is private let _: Box>; - //~^ ERROR type `priv_parent_substs::Priv` is private - //~| ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private + //~| ERROR type `Priv` is private pub type InSignatureTy1 = Box>; - //~^ ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private pub type InSignatureTy2 = Box>; - //~^ ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private trait InSignatureTr1: PubTrWithParam {} - //~^ ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private trait InSignatureTr2: PubTr {} - //~^ ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private } } fn priv_parent_substs() { diff --git a/src/test/ui/privacy/associated-item-privacy-type-binding.stderr b/src/test/ui/privacy/associated-item-privacy-type-binding.stderr index d8515ccb66..5df2dfb871 100644 --- a/src/test/ui/privacy/associated-item-privacy-type-binding.stderr +++ b/src/test/ui/privacy/associated-item-privacy-type-binding.stderr @@ -1,4 +1,4 @@ -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:11:13 | LL | let _: Box>; @@ -9,7 +9,7 @@ LL | priv_trait::mac1!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:11:16 | LL | let _: Box>; @@ -20,7 +20,7 @@ LL | priv_trait::mac1!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:14:31 | LL | type InSignatureTy2 = Box>; @@ -31,7 +31,7 @@ LL | priv_trait::mac1!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:16:31 | LL | trait InSignatureTr2: PubTr {} @@ -42,7 +42,7 @@ LL | priv_trait::mac1!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:20:13 | LL | let _: Box>; @@ -53,7 +53,7 @@ LL | priv_trait::mac2!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:20:16 | LL | let _: Box>; @@ -64,7 +64,7 @@ LL | priv_trait::mac2!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:23:31 | LL | type InSignatureTy1 = Box>; @@ -75,7 +75,7 @@ LL | priv_trait::mac2!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:25:31 | LL | trait InSignatureTr1: PrivTr {} @@ -86,7 +86,7 @@ LL | priv_trait::mac2!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:44:13 | LL | let _: Box>; @@ -97,7 +97,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:44:16 | LL | let _: Box>; @@ -108,7 +108,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:47:13 | LL | let _: Box>; @@ -119,7 +119,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:47:16 | LL | let _: Box>; @@ -130,7 +130,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:50:35 | LL | pub type InSignatureTy1 = Box>; @@ -141,7 +141,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:52:35 | LL | pub type InSignatureTy2 = Box>; @@ -152,7 +152,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:54:31 | LL | trait InSignatureTr1: PubTrWithParam {} @@ -163,7 +163,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:56:31 | LL | trait InSignatureTr2: PubTr {} diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.rs b/src/test/ui/privacy/private-in-public-assoc-ty.rs index cd7c37cb04..5238894a97 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.rs +++ b/src/test/ui/privacy/private-in-public-assoc-ty.rs @@ -15,16 +15,16 @@ mod m { impl PubTrAux1 for u8 {} impl PubTrAux2 for u8 { type A = Priv; - //~^ ERROR private type `m::Priv` in public interface + //~^ ERROR private type `Priv` in public interface } // "Private-in-public in associated types is hard error" in RFC 2145 // applies only to the aliased types, not bounds. pub trait PubTr { - //~^ WARN private trait `m::PrivTr` in public interface + //~^ WARN private trait `PrivTr` in public interface //~| WARN this was previously accepted - //~| WARN private type `m::Priv` in public interface - //~| WARN private type `m::Priv` in public interface + //~| WARN private type `Priv` in public interface + //~| WARN private type `Priv` in public interface //~| WARN this was previously accepted //~| WARN this was previously accepted type Alias1: PrivTr; @@ -32,17 +32,17 @@ mod m { type Alias3: PubTrAux2 = u8; type Alias4 = Priv; - //~^ ERROR private type `m::Priv` in public interface + //~^ ERROR private type `Priv` in public interface type Exist; fn infer_exist() -> Self::Exist; } impl PubTr for u8 { type Alias1 = Priv; - //~^ ERROR private type `m::Priv` in public interface + //~^ ERROR private type `Priv` in public interface type Exist = impl PrivTr; - //~^ ERROR private trait `m::PrivTr` in public interface + //~^ ERROR private trait `PrivTr` in public interface fn infer_exist() -> Self::Exist { Priv } diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr index 1a3ca3f16e..acc6e20cf3 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr +++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr @@ -1,13 +1,13 @@ -error[E0446]: private type `m::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public-assoc-ty.rs:17:9 | LL | struct Priv; - | - `m::Priv` declared as private + | - `Priv` declared as private ... LL | type A = Priv; | ^^^^^^^^^^^^^^ can't leak private type -warning: private trait `m::PrivTr` in public interface (error E0445) +warning: private trait `PrivTr` in public interface (error E0445) --> $DIR/private-in-public-assoc-ty.rs:23:5 | LL | / pub trait PubTr { @@ -23,7 +23,7 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 -warning: private type `m::Priv` in public interface (error E0446) +warning: private type `Priv` in public interface (error E0446) --> $DIR/private-in-public-assoc-ty.rs:23:5 | LL | / pub trait PubTr { @@ -38,7 +38,7 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 -warning: private type `m::Priv` in public interface (error E0446) +warning: private type `Priv` in public interface (error E0446) --> $DIR/private-in-public-assoc-ty.rs:23:5 | LL | / pub trait PubTr { @@ -53,29 +53,29 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 -error[E0446]: private type `m::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public-assoc-ty.rs:34:9 | LL | struct Priv; - | - `m::Priv` declared as private + | - `Priv` declared as private ... LL | type Alias4 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `m::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public-assoc-ty.rs:41:9 | LL | struct Priv; - | - `m::Priv` declared as private + | - `Priv` declared as private ... LL | type Alias1 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0445]: private trait `m::PrivTr` in public interface +error[E0445]: private trait `PrivTr` in public interface --> $DIR/private-in-public-assoc-ty.rs:44:9 | LL | trait PrivTr {} - | - `m::PrivTr` declared as private + | - `PrivTr` declared as private ... LL | type Exist = impl PrivTr; | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait diff --git a/src/test/ui/privacy/private-in-public-ill-formed.rs b/src/test/ui/privacy/private-in-public-ill-formed.rs index 0ef5d89002..031e2874a2 100644 --- a/src/test/ui/privacy/private-in-public-ill-formed.rs +++ b/src/test/ui/privacy/private-in-public-ill-formed.rs @@ -11,7 +11,8 @@ mod aliases_pub { type AssocAlias = m::Pub3; } - impl ::AssocAlias { //~ ERROR no base type found for inherent implementation + impl ::AssocAlias { + //~^ ERROR no nominal type found for inherent implementation pub fn f(arg: Priv) {} // private type `aliases_pub::Priv` in public interface } } @@ -27,7 +28,8 @@ mod aliases_priv { type AssocAlias = Priv3; } - impl ::AssocAlias { //~ ERROR no base type found for inherent implementation + impl ::AssocAlias { + //~^ ERROR no nominal type found for inherent implementation pub fn f(arg: Priv) {} // OK } } diff --git a/src/test/ui/privacy/private-in-public-ill-formed.stderr b/src/test/ui/privacy/private-in-public-ill-formed.stderr index a1a326f287..e7c94bc301 100644 --- a/src/test/ui/privacy/private-in-public-ill-formed.stderr +++ b/src/test/ui/privacy/private-in-public-ill-formed.stderr @@ -1,16 +1,16 @@ -error[E0118]: no base type found for inherent implementation +error[E0118]: no nominal type found for inherent implementation --> $DIR/private-in-public-ill-formed.rs:14:10 | LL | impl ::AssocAlias { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a base type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead -error[E0118]: no base type found for inherent implementation - --> $DIR/private-in-public-ill-formed.rs:30:10 +error[E0118]: no nominal type found for inherent implementation + --> $DIR/private-in-public-ill-formed.rs:31:10 | LL | impl ::AssocAlias { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a base type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead diff --git a/src/test/ui/privacy/private-in-public-non-principal-2.rs b/src/test/ui/privacy/private-in-public-non-principal-2.rs index cd3d609ca3..effcb508e2 100644 --- a/src/test/ui/privacy/private-in-public-non-principal-2.rs +++ b/src/test/ui/privacy/private-in-public-non-principal-2.rs @@ -10,5 +10,5 @@ mod m { fn main() { m::leak_dyn_nonprincipal(); - //~^ ERROR trait `m::PrivNonPrincipal` is private + //~^ ERROR trait `PrivNonPrincipal` is private } diff --git a/src/test/ui/privacy/private-in-public-non-principal-2.stderr b/src/test/ui/privacy/private-in-public-non-principal-2.stderr index 7850694aab..7cc8bf0de2 100644 --- a/src/test/ui/privacy/private-in-public-non-principal-2.stderr +++ b/src/test/ui/privacy/private-in-public-non-principal-2.stderr @@ -1,4 +1,4 @@ -error: trait `m::PrivNonPrincipal` is private +error: trait `PrivNonPrincipal` is private --> $DIR/private-in-public-non-principal-2.rs:12:5 | LL | m::leak_dyn_nonprincipal(); diff --git a/src/test/ui/privacy/private-in-public-warn.rs b/src/test/ui/privacy/private-in-public-warn.rs index 467b837467..3022b470b7 100644 --- a/src/test/ui/privacy/private-in-public-warn.rs +++ b/src/test/ui/privacy/private-in-public-warn.rs @@ -247,12 +247,12 @@ mod aliases_priv { } pub trait Tr1: PrivUseAliasTr {} - //~^ ERROR private trait `aliases_priv::PrivTr1` in public interface + //~^ ERROR private trait `PrivTr1` in public interface //~| WARNING hard error pub trait Tr2: PrivUseAliasTr {} - //~^ ERROR private trait `aliases_priv::PrivTr1` in public interface + //~^ ERROR private trait `PrivTr1` in public interface //~| WARNING hard error - //~| ERROR private type `aliases_priv::Priv2` in public interface + //~| ERROR private type `Priv2` in public interface //~| WARNING hard error impl PrivUseAlias { diff --git a/src/test/ui/privacy/private-in-public-warn.stderr b/src/test/ui/privacy/private-in-public-warn.stderr index 4905e29519..36577a6010 100644 --- a/src/test/ui/privacy/private-in-public-warn.stderr +++ b/src/test/ui/privacy/private-in-public-warn.stderr @@ -306,7 +306,7 @@ LL | struct Priv; LL | type Check = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type -error: private trait `aliases_priv::PrivTr1` in public interface (error E0445) +error: private trait `PrivTr1` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:249:5 | LL | pub trait Tr1: PrivUseAliasTr {} @@ -315,7 +315,7 @@ LL | pub trait Tr1: PrivUseAliasTr {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 -error: private trait `aliases_priv::PrivTr1` in public interface (error E0445) +error: private trait `PrivTr1` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:252:5 | LL | pub trait Tr2: PrivUseAliasTr {} @@ -324,7 +324,7 @@ LL | pub trait Tr2: PrivUseAliasTr {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 -error: private type `aliases_priv::Priv2` in public interface (error E0446) +error: private type `Priv2` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:252:5 | LL | pub trait Tr2: PrivUseAliasTr {} diff --git a/src/test/ui/privacy/private-in-public.rs b/src/test/ui/privacy/private-in-public.rs index 08c00f44f2..dbd1c483f8 100644 --- a/src/test/ui/privacy/private-in-public.rs +++ b/src/test/ui/privacy/private-in-public.rs @@ -128,8 +128,8 @@ mod aliases_priv { } impl PrivTr for Priv {} - pub fn f1(arg: PrivUseAlias) {} //~ ERROR private type `aliases_priv::Priv1` in public interface - pub fn f2(arg: PrivAlias) {} //~ ERROR private type `aliases_priv::Priv2` in public interface + pub fn f1(arg: PrivUseAlias) {} //~ ERROR private type `Priv1` in public interface + pub fn f2(arg: PrivAlias) {} //~ ERROR private type `Priv2` in public interface pub fn f3(arg: ::Assoc) {} //~^ ERROR private trait `aliases_priv::PrivTr` in public interface //~| ERROR private type `aliases_priv::Priv` in public interface diff --git a/src/test/ui/privacy/private-in-public.stderr b/src/test/ui/privacy/private-in-public.stderr index 4750fe8687..2ec5b45d21 100644 --- a/src/test/ui/privacy/private-in-public.stderr +++ b/src/test/ui/privacy/private-in-public.stderr @@ -238,20 +238,20 @@ LL | struct Priv; LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `aliases_priv::Priv1` in public interface +error[E0446]: private type `Priv1` in public interface --> $DIR/private-in-public.rs:131:5 | LL | struct Priv1; - | - `aliases_priv::Priv1` declared as private + | - `Priv1` declared as private ... LL | pub fn f1(arg: PrivUseAlias) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `aliases_priv::Priv2` in public interface +error[E0446]: private type `Priv2` in public interface --> $DIR/private-in-public.rs:132:5 | LL | struct Priv2; - | - `aliases_priv::Priv2` declared as private + | - `Priv2` declared as private ... LL | pub fn f2(arg: PrivAlias) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/privacy/private-inferred-type-1.rs b/src/test/ui/privacy/private-inferred-type-1.rs index 69eeb2a26e..d633189e3f 100644 --- a/src/test/ui/privacy/private-inferred-type-1.rs +++ b/src/test/ui/privacy/private-inferred-type-1.rs @@ -13,6 +13,6 @@ mod m { } fn main() { - [].arr0_secret(); //~ ERROR type `m::Priv` is private - None.ty_param_secret(); //~ ERROR type `m::Priv` is private + [].arr0_secret(); //~ ERROR type `Priv` is private + None.ty_param_secret(); //~ ERROR type `Priv` is private } diff --git a/src/test/ui/privacy/private-inferred-type-1.stderr b/src/test/ui/privacy/private-inferred-type-1.stderr index 576498b2cf..245789f435 100644 --- a/src/test/ui/privacy/private-inferred-type-1.stderr +++ b/src/test/ui/privacy/private-inferred-type-1.stderr @@ -1,10 +1,10 @@ -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type-1.rs:16:5 | LL | [].arr0_secret(); | ^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type-1.rs:17:5 | LL | None.ty_param_secret(); diff --git a/src/test/ui/privacy/private-inferred-type-2.rs b/src/test/ui/privacy/private-inferred-type-2.rs index 28b47606d1..15b263b381 100644 --- a/src/test/ui/privacy/private-inferred-type-2.rs +++ b/src/test/ui/privacy/private-inferred-type-2.rs @@ -13,7 +13,7 @@ mod m { } fn main() { - m::Pub::get_priv; //~ ERROR type `m::Priv` is private - m::Pub::static_method; //~ ERROR type `m::Priv` is private + m::Pub::get_priv; //~ ERROR type `Priv` is private + m::Pub::static_method; //~ ERROR type `Priv` is private ext::Pub::static_method; //~ ERROR type `ext::Priv` is private } diff --git a/src/test/ui/privacy/private-inferred-type-2.stderr b/src/test/ui/privacy/private-inferred-type-2.stderr index f19e367ef1..3a0fc03b4d 100644 --- a/src/test/ui/privacy/private-inferred-type-2.stderr +++ b/src/test/ui/privacy/private-inferred-type-2.stderr @@ -1,10 +1,10 @@ -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type-2.rs:16:5 | LL | m::Pub::get_priv; | ^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type-2.rs:17:5 | LL | m::Pub::static_method; diff --git a/src/test/ui/privacy/private-inferred-type-3.rs b/src/test/ui/privacy/private-inferred-type-3.rs index 39f2e5d4af..00f0a715a8 100644 --- a/src/test/ui/privacy/private-inferred-type-3.rs +++ b/src/test/ui/privacy/private-inferred-type-3.rs @@ -5,8 +5,8 @@ // error-pattern:type `ext::PrivEnum` is private // error-pattern:type `fn() {::method}` is private // error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct}` is private -// error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct}` is private -// error-pattern:type `for<'r> fn(&'r ext::Pub) {ext::Pub::::priv_method}` is private +// error-pattern:type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private +// error-pattern:type `for<'r> fn(&'r Pub) {Pub::::priv_method}` is private #![feature(decl_macro)] diff --git a/src/test/ui/privacy/private-inferred-type-3.stderr b/src/test/ui/privacy/private-inferred-type-3.stderr index 39ef647252..165d932f08 100644 --- a/src/test/ui/privacy/private-inferred-type-3.stderr +++ b/src/test/ui/privacy/private-inferred-type-3.stderr @@ -38,7 +38,7 @@ LL | ext::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct}` is private +error: type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); @@ -46,7 +46,7 @@ LL | ext::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `for<'r> fn(&'r ext::Pub) {ext::Pub::::priv_method}` is private +error: type `for<'r> fn(&'r Pub) {Pub::::priv_method}` is private --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); diff --git a/src/test/ui/privacy/private-inferred-type.rs b/src/test/ui/privacy/private-inferred-type.rs index dab440b2d9..b083a3970d 100644 --- a/src/test/ui/privacy/private-inferred-type.rs +++ b/src/test/ui/privacy/private-inferred-type.rs @@ -36,18 +36,18 @@ mod m { impl TraitWithAssocTy for Priv { type AssocTy = u8; } pub macro m() { - priv_fn; //~ ERROR type `fn() {m::priv_fn}` is private + priv_fn; //~ ERROR type `fn() {priv_fn}` is private PRIV_STATIC; // OK, not cross-crate - PrivEnum::Variant; //~ ERROR type `m::PrivEnum` is private + PrivEnum::Variant; //~ ERROR type `PrivEnum` is private PubEnum::Variant; // OK - ::method; //~ ERROR type `fn() {::method}` is private + ::method; //~ ERROR type `fn() {::method}` is private ::method; // OK PrivTupleStruct; - //~^ ERROR type `fn(u8) -> m::PrivTupleStruct {m::PrivTupleStruct}` is private + //~^ ERROR type `fn(u8) -> PrivTupleStruct {PrivTupleStruct}` is private PubTupleStruct; - //~^ ERROR type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct}` is private + //~^ ERROR type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private Pub(0u8).priv_method(); - //~^ ERROR type `for<'r> fn(&'r m::Pub) {m::Pub::::priv_method}` is private + //~^ ERROR type `for<'r> fn(&'r Pub) {Pub::::priv_method}` is private } trait Trait {} @@ -59,7 +59,7 @@ mod m { impl TraitWithTyParam for u8 {} impl TraitWithTyParam2 for u8 {} impl TraitWithAssocTy for u8 { type AssocTy = Priv; } - //~^ ERROR private type `m::Priv` in public interface + //~^ ERROR private type `Priv` in public interface pub fn leak_anon1() -> impl Trait + 'static { 0 } pub fn leak_anon2() -> impl TraitWithTyParam { 0 } @@ -80,7 +80,7 @@ mod adjust { pub struct S3; impl Deref for S1 { - type Target = S2Alias; //~ ERROR private type `adjust::S2` in public interface + type Target = S2Alias; //~ ERROR private type `S2` in public interface fn deref(&self) -> &Self::Target { loop {} } } impl Deref for S2 { @@ -94,40 +94,40 @@ mod adjust { } fn main() { - let _: m::Alias; //~ ERROR type `m::Priv` is private - //~^ ERROR type `m::Priv` is private - let _: ::AssocTy; //~ ERROR type `m::Priv` is private - m::Alias {}; //~ ERROR type `m::Priv` is private - m::Pub { 0: m::Alias {} }; //~ ERROR type `m::Priv` is private + let _: m::Alias; //~ ERROR type `Priv` is private + //~^ ERROR type `Priv` is private + let _: ::AssocTy; //~ ERROR type `Priv` is private + m::Alias {}; //~ ERROR type `Priv` is private + m::Pub { 0: m::Alias {} }; //~ ERROR type `Priv` is private m::Pub { 0: loop {} }; // OK, `m::Pub` is in value context, so it means Pub<_>, not Pub - m::Pub::static_method; //~ ERROR type `m::Priv` is private - m::Pub::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private - m::Pub(0u8).method_with_substs::(); //~ ERROR type `m::Priv` is private - m::Pub(0u8).method_with_priv_params(loop{}); //~ ERROR type `m::Priv` is private - ::TRAIT_ASSOC_CONST; //~ ERROR type `m::Priv` is private - >::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private - >::INHERENT_ASSOC_CONST_GENERIC_SELF; //~ ERROR type `m::Priv` is private - >::static_method_generic_self; //~ ERROR type `m::Priv` is private + m::Pub::static_method; //~ ERROR type `Priv` is private + m::Pub::INHERENT_ASSOC_CONST; //~ ERROR type `Priv` is private + m::Pub(0u8).method_with_substs::(); //~ ERROR type `Priv` is private + m::Pub(0u8).method_with_priv_params(loop{}); //~ ERROR type `Priv` is private + ::TRAIT_ASSOC_CONST; //~ ERROR type `Priv` is private + >::INHERENT_ASSOC_CONST; //~ ERROR type `Priv` is private + >::INHERENT_ASSOC_CONST_GENERIC_SELF; //~ ERROR type `Priv` is private + >::static_method_generic_self; //~ ERROR type `Priv` is private use m::TraitWithTyParam2; - u8::pub_method; //~ ERROR type `m::Priv` is private + u8::pub_method; //~ ERROR type `Priv` is private - adjust::S1.method_s3(); //~ ERROR type `adjust::S2` is private + adjust::S1.method_s3(); //~ ERROR type `S2` is private m::m!(); - m::leak_anon1(); //~ ERROR trait `m::Trait` is private - m::leak_anon2(); //~ ERROR type `m::Priv` is private - m::leak_anon3(); //~ ERROR type `m::Priv` is private + m::leak_anon1(); //~ ERROR trait `Trait` is private + m::leak_anon2(); //~ ERROR type `Priv` is private + m::leak_anon3(); //~ ERROR type `Priv` is private - m::leak_dyn1(); //~ ERROR trait `m::Trait` is private - m::leak_dyn2(); //~ ERROR type `m::Priv` is private - m::leak_dyn3(); //~ ERROR type `m::Priv` is private + m::leak_dyn1(); //~ ERROR trait `Trait` is private + m::leak_dyn2(); //~ ERROR type `Priv` is private + m::leak_dyn3(); //~ ERROR type `Priv` is private // Check that messages are not duplicated for various kinds of assignments - let a = m::Alias {}; //~ ERROR type `m::Priv` is private - let mut b = a; //~ ERROR type `m::Priv` is private - b = a; //~ ERROR type `m::Priv` is private - match a { //~ ERROR type `m::Priv` is private + let a = m::Alias {}; //~ ERROR type `Priv` is private + let mut b = a; //~ ERROR type `Priv` is private + b = a; //~ ERROR type `Priv` is private + match a { //~ ERROR type `Priv` is private _ => {} } } diff --git a/src/test/ui/privacy/private-inferred-type.stderr b/src/test/ui/privacy/private-inferred-type.stderr index 7d1f794bfe..4a310f7009 100644 --- a/src/test/ui/privacy/private-inferred-type.stderr +++ b/src/test/ui/privacy/private-inferred-type.stderr @@ -1,112 +1,112 @@ -error[E0446]: private type `m::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-inferred-type.rs:61:36 | LL | struct Priv; - | - `m::Priv` declared as private + | - `Priv` declared as private ... LL | impl TraitWithAssocTy for u8 { type AssocTy = Priv; } | ^^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `adjust::S2` in public interface +error[E0446]: private type `S2` in public interface --> $DIR/private-inferred-type.rs:83:9 | LL | struct S2; - | - `adjust::S2` declared as private + | - `S2` declared as private ... LL | type Target = S2Alias; | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:97:9 | LL | let _: m::Alias; | ^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:97:12 | LL | let _: m::Alias; | ^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:99:13 | LL | let _: ::AssocTy; | ^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:100:5 | LL | m::Alias {}; | ^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:101:5 | LL | m::Pub { 0: m::Alias {} }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:103:5 | LL | m::Pub::static_method; | ^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:104:5 | LL | m::Pub::INHERENT_ASSOC_CONST; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:105:5 | LL | m::Pub(0u8).method_with_substs::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:106:17 | LL | m::Pub(0u8).method_with_priv_params(loop{}); | ^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:107:5 | LL | ::TRAIT_ASSOC_CONST; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:108:6 | LL | >::INHERENT_ASSOC_CONST; | ^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:109:5 | LL | >::INHERENT_ASSOC_CONST_GENERIC_SELF; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:110:5 | LL | >::static_method_generic_self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:112:5 | LL | u8::pub_method; | ^^^^^^^^^^^^^^ private type -error: type `adjust::S2` is private +error: type `S2` is private --> $DIR/private-inferred-type.rs:114:5 | LL | adjust::S1.method_s3(); | ^^^^^^^^^^ private type -error: type `fn() {m::priv_fn}` is private +error: type `fn() {priv_fn}` is private --> $DIR/private-inferred-type.rs:39:9 | LL | priv_fn; @@ -117,7 +117,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `m::PrivEnum` is private +error: type `PrivEnum` is private --> $DIR/private-inferred-type.rs:41:9 | LL | PrivEnum::Variant; @@ -128,7 +128,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `fn() {::method}` is private +error: type `fn() {::method}` is private --> $DIR/private-inferred-type.rs:43:9 | LL | ::method; @@ -139,7 +139,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `fn(u8) -> m::PrivTupleStruct {m::PrivTupleStruct}` is private +error: type `fn(u8) -> PrivTupleStruct {PrivTupleStruct}` is private --> $DIR/private-inferred-type.rs:45:9 | LL | PrivTupleStruct; @@ -150,7 +150,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct}` is private +error: type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private --> $DIR/private-inferred-type.rs:47:9 | LL | PubTupleStruct; @@ -161,7 +161,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `for<'r> fn(&'r m::Pub) {m::Pub::::priv_method}` is private +error: type `for<'r> fn(&'r Pub) {Pub::::priv_method}` is private --> $DIR/private-inferred-type.rs:49:18 | LL | Pub(0u8).priv_method(); @@ -172,61 +172,61 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `m::Trait` is private +error: trait `Trait` is private --> $DIR/private-inferred-type.rs:118:5 | LL | m::leak_anon1(); | ^^^^^^^^^^^^^^^ private trait -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:119:5 | LL | m::leak_anon2(); | ^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:120:5 | LL | m::leak_anon3(); | ^^^^^^^^^^^^^^^ private type -error: trait `m::Trait` is private +error: trait `Trait` is private --> $DIR/private-inferred-type.rs:122:5 | LL | m::leak_dyn1(); | ^^^^^^^^^^^^^^ private trait -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:123:5 | LL | m::leak_dyn2(); | ^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:124:5 | LL | m::leak_dyn3(); | ^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:127:13 | LL | let a = m::Alias {}; | ^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:128:17 | LL | let mut b = a; | ^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:129:9 | LL | b = a; | ^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:130:11 | LL | match a { diff --git a/src/test/ui/privacy/private-struct-field-cross-crate.rs b/src/test/ui/privacy/private-struct-field-cross-crate.rs index 2efcb7f1d8..301cd37b76 100644 --- a/src/test/ui/privacy/private-struct-field-cross-crate.rs +++ b/src/test/ui/privacy/private-struct-field-cross-crate.rs @@ -5,5 +5,5 @@ use cci_class::kitties::cat; fn main() { let nyan : cat = cat(52, 99); assert_eq!(nyan.meows, 52); - //~^ ERROR field `meows` of struct `cci_class::kitties::cat` is private + //~^ ERROR field `meows` of struct `cat` is private } diff --git a/src/test/ui/privacy/private-struct-field-cross-crate.stderr b/src/test/ui/privacy/private-struct-field-cross-crate.stderr index ac00d82ada..40cf3448d6 100644 --- a/src/test/ui/privacy/private-struct-field-cross-crate.stderr +++ b/src/test/ui/privacy/private-struct-field-cross-crate.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `meows` of struct `cci_class::kitties::cat` is private +error[E0616]: field `meows` of struct `cat` is private --> $DIR/private-struct-field-cross-crate.rs:7:19 | LL | assert_eq!(nyan.meows, 52); diff --git a/src/test/ui/privacy/private-struct-field-ctor.rs b/src/test/ui/privacy/private-struct-field-ctor.rs index 2c506f3479..56e84a7510 100644 --- a/src/test/ui/privacy/private-struct-field-ctor.rs +++ b/src/test/ui/privacy/private-struct-field-ctor.rs @@ -5,5 +5,5 @@ mod a { } fn main() { - let s = a::Foo { x: 1 }; //~ ERROR field `x` of struct `a::Foo` is private + let s = a::Foo { x: 1 }; //~ ERROR field `x` of struct `Foo` is private } diff --git a/src/test/ui/privacy/private-struct-field-ctor.stderr b/src/test/ui/privacy/private-struct-field-ctor.stderr index 7c32ebc2cf..9dc9db0eac 100644 --- a/src/test/ui/privacy/private-struct-field-ctor.stderr +++ b/src/test/ui/privacy/private-struct-field-ctor.stderr @@ -1,4 +1,4 @@ -error[E0451]: field `x` of struct `a::Foo` is private +error[E0451]: field `x` of struct `Foo` is private --> $DIR/private-struct-field-ctor.rs:8:22 | LL | let s = a::Foo { x: 1 }; diff --git a/src/test/ui/privacy/private-struct-field-pattern.rs b/src/test/ui/privacy/private-struct-field-pattern.rs index b3da6092ab..4a766500e1 100644 --- a/src/test/ui/privacy/private-struct-field-pattern.rs +++ b/src/test/ui/privacy/private-struct-field-pattern.rs @@ -12,6 +12,6 @@ mod a { fn main() { match a::make() { - Foo { x: _ } => {} //~ ERROR field `x` of struct `a::Foo` is private + Foo { x: _ } => {} //~ ERROR field `x` of struct `Foo` is private } } diff --git a/src/test/ui/privacy/private-struct-field-pattern.stderr b/src/test/ui/privacy/private-struct-field-pattern.stderr index 9190317403..6305530368 100644 --- a/src/test/ui/privacy/private-struct-field-pattern.stderr +++ b/src/test/ui/privacy/private-struct-field-pattern.stderr @@ -1,4 +1,4 @@ -error[E0451]: field `x` of struct `a::Foo` is private +error[E0451]: field `x` of struct `Foo` is private --> $DIR/private-struct-field-pattern.rs:15:15 | LL | Foo { x: _ } => {} diff --git a/src/test/ui/privacy/private-struct-field.rs b/src/test/ui/privacy/private-struct-field.rs index 216ae20e15..94cee4eff2 100644 --- a/src/test/ui/privacy/private-struct-field.rs +++ b/src/test/ui/privacy/private-struct-field.rs @@ -10,5 +10,5 @@ mod cat { fn main() { let nyan = cat::new_cat(); - assert_eq!(nyan.meows, 52); //~ ERROR field `meows` of struct `cat::Cat` is private + assert_eq!(nyan.meows, 52); //~ ERROR field `meows` of struct `Cat` is private } diff --git a/src/test/ui/privacy/private-struct-field.stderr b/src/test/ui/privacy/private-struct-field.stderr index c89ae507ab..facf4e82fd 100644 --- a/src/test/ui/privacy/private-struct-field.stderr +++ b/src/test/ui/privacy/private-struct-field.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `meows` of struct `cat::Cat` is private +error[E0616]: field `meows` of struct `Cat` is private --> $DIR/private-struct-field.rs:13:21 | LL | assert_eq!(nyan.meows, 52); diff --git a/src/test/ui/privacy/private-type-in-interface.rs b/src/test/ui/privacy/private-type-in-interface.rs index 359b6da1d7..7fbdbaf5f3 100644 --- a/src/test/ui/privacy/private-type-in-interface.rs +++ b/src/test/ui/privacy/private-type-in-interface.rs @@ -12,19 +12,19 @@ mod m { impl Trait for Priv { type X = u8; } } -fn f(_: m::Alias) {} //~ ERROR type `m::Priv` is private - //~^ ERROR type `m::Priv` is private +fn f(_: m::Alias) {} //~ ERROR type `Priv` is private + //~^ ERROR type `Priv` is private fn f_ext(_: ext::Alias) {} //~ ERROR type `ext::Priv` is private //~^ ERROR type `ext::Priv` is private trait Tr1 {} -impl m::Alias {} //~ ERROR type `m::Priv` is private +impl m::Alias {} //~ ERROR type `Priv` is private impl Tr1 for ext::Alias {} //~ ERROR type `ext::Priv` is private -type A = ::X; //~ ERROR type `m::Priv` is private +type A = ::X; //~ ERROR type `Priv` is private trait Tr2 {} impl Tr2 for u8 {} -fn g() -> impl Tr2 { 0 } //~ ERROR type `m::Priv` is private +fn g() -> impl Tr2 { 0 } //~ ERROR type `Priv` is private fn g_ext() -> impl Tr2 { 0 } //~ ERROR type `ext::Priv` is private fn main() {} diff --git a/src/test/ui/privacy/private-type-in-interface.stderr b/src/test/ui/privacy/private-type-in-interface.stderr index ea89035c3d..4e87caa341 100644 --- a/src/test/ui/privacy/private-type-in-interface.stderr +++ b/src/test/ui/privacy/private-type-in-interface.stderr @@ -1,10 +1,10 @@ -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:15:9 | LL | fn f(_: m::Alias) {} | ^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:15:6 | LL | fn f(_: m::Alias) {} @@ -22,7 +22,7 @@ error: type `ext::Priv` is private LL | fn f_ext(_: ext::Alias) {} | ^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:21:6 | LL | impl m::Alias {} @@ -34,13 +34,13 @@ error: type `ext::Priv` is private LL | impl Tr1 for ext::Alias {} | ^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:23:10 | LL | type A = ::X; | ^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:27:11 | LL | fn g() -> impl Tr2 { 0 } diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs index feab72b3ef..e485263aff 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -18,14 +18,14 @@ struct PrivateType { pub struct PublicType { pub field: OtherType, - //~^ ERROR type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface + //~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface priv_field: OtherType, // Private field - this is fine pub other_field: PubType // Type from public dependency - this is fine } impl PublicType { pub fn pub_fn(param: OtherType) {} - //~^ ERROR type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface + //~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface fn priv_fn(param: OtherType) {} } @@ -33,7 +33,7 @@ impl PublicType { pub trait MyPubTrait { type Foo: OtherTrait; } -//~^^^ ERROR trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface +//~^^^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface pub struct AllowedPrivType { #[allow(exported_private_dependencies)] diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr index 727134bd51..3b5b782344 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -1,4 +1,4 @@ -error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface +error: type `OtherType` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:20:5 | LL | pub field: OtherType, @@ -10,13 +10,13 @@ note: the lint level is defined here LL | #![deny(exported_private_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface +error: type `OtherType` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:27:5 | LL | pub fn pub_fn(param: OtherType) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface +error: trait `OtherTrait` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:33:1 | LL | / pub trait MyPubTrait { diff --git a/src/test/ui/privacy/restricted/private-in-public.stderr b/src/test/ui/privacy/restricted/private-in-public.stderr index c597935e7f..80995ab98e 100644 --- a/src/test/ui/privacy/restricted/private-in-public.stderr +++ b/src/test/ui/privacy/restricted/private-in-public.stderr @@ -1,17 +1,17 @@ -error[E0446]: private type `foo::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public.rs:8:9 | LL | struct Priv; - | - `foo::Priv` declared as private + | - `Priv` declared as private ... LL | pub(crate) fn g(_: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `foo::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public.rs:9:9 | LL | struct Priv; - | - `foo::Priv` declared as private + | - `Priv` declared as private ... LL | crate fn h(_: Priv) {} | ^^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/privacy/restricted/struct-literal-field.stderr b/src/test/ui/privacy/restricted/struct-literal-field.stderr index 591980dc34..eee964f022 100644 --- a/src/test/ui/privacy/restricted/struct-literal-field.stderr +++ b/src/test/ui/privacy/restricted/struct-literal-field.stderr @@ -1,4 +1,4 @@ -error[E0451]: field `x` of struct `foo::bar::S` is private +error[E0451]: field `x` of struct `S` is private --> $DIR/struct-literal-field.rs:18:9 | LL | S { x: 0 }; diff --git a/src/test/ui/privacy/restricted/test.stderr b/src/test/ui/privacy/restricted/test.stderr index 40512a34bd..61b9a43f89 100644 --- a/src/test/ui/privacy/restricted/test.stderr +++ b/src/test/ui/privacy/restricted/test.stderr @@ -46,7 +46,7 @@ note: the function `f` is defined here LL | pub(super) fn f() {} | ^^^^^^^^^^^^^^^^^ -error[E0616]: field `x` of struct `foo::bar::S` is private +error[E0616]: field `x` of struct `S` is private --> $DIR/test.rs:31:18 | LL | S::default().x; @@ -64,13 +64,13 @@ error[E0624]: associated function `g` is private LL | S::g(); | ^ private associated function -error[E0616]: field `y` of struct `pub_restricted::Universe` is private +error[E0616]: field `y` of struct `Universe` is private --> $DIR/test.rs:42:15 | LL | let _ = u.y; | ^ private field -error[E0616]: field `z` of struct `pub_restricted::Universe` is private +error[E0616]: field `z` of struct `Universe` is private --> $DIR/test.rs:43:15 | LL | let _ = u.z; diff --git a/src/test/ui/privacy/union-field-privacy-1.rs b/src/test/ui/privacy/union-field-privacy-1.rs index 1ff4d513fa..8a84bd86ae 100644 --- a/src/test/ui/privacy/union-field-privacy-1.rs +++ b/src/test/ui/privacy/union-field-privacy-1.rs @@ -9,9 +9,9 @@ mod m { fn main() { unsafe { let u = m::U { a: 0 }; // OK let u = m::U { b: 0 }; // OK - let u = m::U { c: 0 }; //~ ERROR field `c` of union `m::U` is private + let u = m::U { c: 0 }; //~ ERROR field `c` of union `U` is private let m::U { a } = u; // OK let m::U { b } = u; // OK - let m::U { c } = u; //~ ERROR field `c` of union `m::U` is private + let m::U { c } = u; //~ ERROR field `c` of union `U` is private }} diff --git a/src/test/ui/privacy/union-field-privacy-1.stderr b/src/test/ui/privacy/union-field-privacy-1.stderr index 15096eb113..b1f0b785ea 100644 --- a/src/test/ui/privacy/union-field-privacy-1.stderr +++ b/src/test/ui/privacy/union-field-privacy-1.stderr @@ -1,10 +1,10 @@ -error[E0451]: field `c` of union `m::U` is private +error[E0451]: field `c` of union `U` is private --> $DIR/union-field-privacy-1.rs:12:20 | LL | let u = m::U { c: 0 }; | ^^^^ private field -error[E0451]: field `c` of union `m::U` is private +error[E0451]: field `c` of union `U` is private --> $DIR/union-field-privacy-1.rs:16:16 | LL | let m::U { c } = u; diff --git a/src/test/ui/privacy/union-field-privacy-2.rs b/src/test/ui/privacy/union-field-privacy-2.rs index c2458f74bc..f02e0f8a9b 100644 --- a/src/test/ui/privacy/union-field-privacy-2.rs +++ b/src/test/ui/privacy/union-field-privacy-2.rs @@ -11,5 +11,5 @@ fn main() { let a = u.a; // OK let b = u.b; // OK - let c = u.c; //~ ERROR field `c` of union `m::U` is private + let c = u.c; //~ ERROR field `c` of union `U` is private } diff --git a/src/test/ui/privacy/union-field-privacy-2.stderr b/src/test/ui/privacy/union-field-privacy-2.stderr index a23cf90332..bf6a2b625d 100644 --- a/src/test/ui/privacy/union-field-privacy-2.stderr +++ b/src/test/ui/privacy/union-field-privacy-2.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `c` of union `m::U` is private +error[E0616]: field `c` of union `U` is private --> $DIR/union-field-privacy-2.rs:14:15 | LL | let c = u.c; diff --git a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr index 97b2f22e16..7141a1b50b 100644 --- a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr +++ b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/attributes-on-modules-fail.rs:16:1 | LL | #[derive(Copy)] @@ -64,5 +64,5 @@ LL | use m::X; error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0658. +Some errors have detailed explanations: E0412, E0658, E0774. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs new file mode 100644 index 0000000000..c72306c3d5 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs @@ -0,0 +1,89 @@ +// force-host +// no-prefer-dynamic + +// These are tests for syntax that is accepted by the Rust parser but +// unconditionally rejected semantically after macro expansion. Attribute macros +// are permitted to accept such syntax as long as they replace it with something +// that makes sense to Rust. +// +// We also inspect some of the spans to verify the syntax is not triggering the +// lossy string reparse hack (https://github.com/rust-lang/rust/issues/43081). + +#![crate_type = "proc-macro"] +#![feature(proc_macro_span)] + +extern crate proc_macro; +use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree}; +use std::path::Component; + +// unsafe mod m { +// pub unsafe mod inner; +// } +#[proc_macro_attribute] +pub fn expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "mod"); + expect(tokens, "m"); + let tokens = &mut expect_brace(tokens); + expect(tokens, "pub"); + expect(tokens, "unsafe"); + expect(tokens, "mod"); + let ident = expect(tokens, "inner"); + expect(tokens, ";"); + check_useful_span(ident, "unsafe-mod.rs"); + TokenStream::new() +} + +// unsafe extern { +// type T; +// } +#[proc_macro_attribute] +pub fn expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "extern"); + let tokens = &mut expect_brace(tokens); + expect(tokens, "type"); + let ident = expect(tokens, "T"); + expect(tokens, ";"); + check_useful_span(ident, "unsafe-foreign-mod.rs"); + TokenStream::new() +} + +// unsafe extern "C++" {} +#[proc_macro_attribute] +pub fn expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "extern"); + let abi = expect(tokens, "\"C++\""); + expect_brace(tokens); + check_useful_span(abi, "unsafe-foreign-mod.rs"); + TokenStream::new() +} + +fn expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree { + match tokens.next() { + Some(token) if token.to_string() == expected => token, + wrong => panic!("unexpected token: {:?}, expected `{}`", wrong, expected), + } +} + +fn expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter { + match tokens.next() { + Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => { + group.stream().into_iter() + } + wrong => panic!("unexpected token: {:?}, expected `{{`", wrong), + } +} + +fn check_useful_span(token: TokenTree, expected_filename: &str) { + let span = token.span(); + assert!(span.start().column < span.end().column); + + let source_path = span.source_file().path(); + let filename = source_path.components().last().unwrap(); + assert_eq!(filename, Component::Normal(expected_filename.as_ref())); +} diff --git a/src/test/ui/proc-macro/break-token-spans.stderr b/src/test/ui/proc-macro/break-token-spans.stderr index caca973f25..0a0322b8a3 100644 --- a/src/test/ui/proc-macro/break-token-spans.stderr +++ b/src/test/ui/proc-macro/break-token-spans.stderr @@ -8,11 +8,11 @@ error[E0308]: mismatched types --> $DIR/break-token-spans.rs:14:32 | LL | let a: Option>= true; - | ------------------ ^^^^ expected enum `std::option::Option`, found `bool` + | ------------------ ^^^^ expected enum `Option`, found `bool` | | | expected due to this | - = note: expected enum `std::option::Option>` + = note: expected enum `Option>` found type `bool` error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs index 2ff6ad6d68..de008a3708 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs @@ -1,10 +1,20 @@ // aux-build:test-macros.rs // check-pass // compile-flags: -Z span-debug -// normalize-stdout-test "#\d+" -> "#CTXT" + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; extern crate test_macros; -use test_macros::print_bang; +use test_macros::{print_bang, print_bang_consume}; + +macro_rules! test_matchers { + ($expr:expr, $block:block, $stmt:stmt, $ty:ty, $ident:ident, $lifetime:lifetime, + $meta:meta, $path:path, $vis:vis, $tt:tt, $lit:literal) => { + print_bang_consume!($expr, $block, $stmt, $ty, $ident, + $lifetime, $meta, $path, $vis, $tt, $lit) + } +} macro_rules! use_expr { ($expr:expr) => { @@ -24,10 +34,23 @@ impl Foo { #[allow(dead_code)] fn use_self(self) { drop(use_expr!(self)); + test_matchers!( + 1 + 1, + { "a" }, + let a = 1, + String, + my_name, + 'a, + my_val = 30, + std::option::Option, + pub(in some::path), + [ a b c ], + -30 + ); } fn with_pat(use_pat!((a, b)): (u32, u32)) { - println!("Args: {} {}", a, b); + let _ = (a, b); } } diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout index 28812e2054..0e7b429d62 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout @@ -5,10 +5,299 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "self", - span: $DIR/capture-macro-rules-invoke.rs:26:24: 26:28 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:36:24: 36:28 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:11:21: 11:26 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:21:21: 21:26 (#4), + }, +] +PRINT-BANG INPUT (DISPLAY): 1 + 1, { "a" }, let a = 1;, String, my_name, 'a, my_val = 30, +std::option::Option, pub(in some::path) , [a b c], -30 +PRINT-BANG RE-COLLECTED (DISPLAY): 1 + 1, { "a" }, let a = 1, String, my_name, 'a, my_val = 30, +std :: option :: Option, pub(in some :: path), [a b c], - 30 +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:38:13: 38:14 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:38:15: 38:16 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:38:17: 38:18 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:29: 14:34 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:34: 14:35 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: Brace, + stream: TokenStream [ + Literal { + kind: Str, + symbol: "a", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:39:15: 39:18 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:39:13: 39:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:36: 14:42 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:42: 14:43 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "let", + span: $DIR/capture-macro-rules-invoke.rs:40:13: 40:16 (#0), + }, + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:40:17: 40:18 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:40:19: 40:20 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:40:21: 40:22 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:44: 14:49 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:49: 14:50 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "String", + span: $DIR/capture-macro-rules-invoke.rs:41:13: 41:19 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:51: 14:54 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:54: 14:55 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "my_name", + span: $DIR/capture-macro-rules-invoke.rs:42:13: 42:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:56: 14:62 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:62: 14:63 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Punct { + ch: '\'', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:43:13: 43:15 (#0), + }, + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:43:13: 43:15 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:29: 15:38 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:38: 15:39 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "my_val", + span: $DIR/capture-macro-rules-invoke.rs:44:13: 44:19 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:44:20: 44:21 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:44:22: 44:24 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:40: 15:45 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:45: 15:46 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "std", + span: $DIR/capture-macro-rules-invoke.rs:45:13: 45:16 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:45:16: 45:18 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:45:16: 45:18 (#0), + }, + Ident { + ident: "option", + span: $DIR/capture-macro-rules-invoke.rs:45:18: 45:24 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:45:24: 45:26 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:45:24: 45:26 (#0), + }, + Ident { + ident: "Option", + span: $DIR/capture-macro-rules-invoke.rs:45:26: 45:32 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:47: 15:52 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:52: 15:53 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "pub", + span: $DIR/capture-macro-rules-invoke.rs:46:13: 46:16 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "in", + span: $DIR/capture-macro-rules-invoke.rs:46:17: 46:19 (#0), + }, + Ident { + ident: "some", + span: $DIR/capture-macro-rules-invoke.rs:46:20: 46:24 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:46:24: 46:26 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:46:24: 46:26 (#0), + }, + Ident { + ident: "path", + span: $DIR/capture-macro-rules-invoke.rs:46:26: 46:30 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:46:16: 46:31 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:54: 15:58 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:58: 15:59 (#8), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:47:15: 47:16 (#0), + }, + Ident { + ident: "b", + span: $DIR/capture-macro-rules-invoke.rs:47:17: 47:18 (#0), + }, + Ident { + ident: "c", + span: $DIR/capture-macro-rules-invoke.rs:47:19: 47:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:47:13: 47:22 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:63: 15:64 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Punct { + ch: '-', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:48:13: 48:14 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:48:14: 48:16 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:65: 15:69 (#8), }, ] PRINT-BANG INPUT (DISPLAY): (a, b) @@ -21,21 +310,21 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "a", - span: $DIR/capture-macro-rules-invoke.rs:29:27: 29:28 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:27: 52:28 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:29:28: 29:29 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:28: 52:29 (#0), }, Ident { ident: "b", - span: $DIR/capture-macro-rules-invoke.rs:29:30: 29:31 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:30: 52:31 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:29:26: 29:32 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:26: 52:32 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:17:21: 17:25 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:27:21: 27:25 (#12), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout index 9a5afbd604..c0c9ed72c5 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout @@ -2,79 +2,79 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate-issue-57089.rs:17:13: 17:19 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:13: 17:19 (#4), }, Ident { ident: "M", - span: $DIR/dollar-crate-issue-57089.rs:17:20: 17:21 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:20: 17:21 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate-issue-57089.rs:17:22: 17:28 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:22: 17:28 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate-issue-57089.rs:17:30: 17:31 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:30: 17:31 (#4), }, ], - span: $DIR/dollar-crate-issue-57089.rs:17:21: 17:32 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:21: 17:32 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:17:32: 17:33 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:32: 17:33 (#4), }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate-issue-57089.rs:21:9: 21:15 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:9: 21:15 (#4), }, Ident { ident: "A", - span: $DIR/dollar-crate-issue-57089.rs:21:16: 21:17 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:16: 21:17 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate-issue-57089.rs:21:18: 21:24 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:18: 21:24 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate-issue-57089.rs:21:26: 21:27 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:26: 21:27 (#4), }, ], - span: $DIR/dollar-crate-issue-57089.rs:21:17: 21:28 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:17: 21:28 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:21:28: 21:29 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:28: 21:29 (#4), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout index fc62eadd31..7f133fd05d 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout @@ -2,109 +2,109 @@ PRINT-ATTR INPUT (DISPLAY): struct A(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate-issue-62325.rs:19:5: 19:11 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:5: 19:11 (#4), }, Ident { ident: "A", - span: $DIR/dollar-crate-issue-62325.rs:19:12: 19:13 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:12: 19:13 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "identity", - span: $DIR/dollar-crate-issue-62325.rs:19:14: 19:22 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:14: 19:22 (#4), }, Punct { ch: '!', spacing: Alone, - span: $DIR/dollar-crate-issue-62325.rs:19:22: 19:23 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:22: 19:23 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate-issue-62325.rs:19:24: 19:30 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:24: 19:30 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate-issue-62325.rs:19:32: 19:33 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:32: 19:33 (#4), }, ], - span: $DIR/dollar-crate-issue-62325.rs:19:23: 19:34 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:23: 19:34 (#4), }, ], - span: $DIR/dollar-crate-issue-62325.rs:19:13: 19:35 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:13: 19:35 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate-issue-62325.rs:19:35: 19:36 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:35: 19:36 (#4), }, ] PRINT-ATTR INPUT (DISPLAY): struct B(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:21:5: 21:11 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:5: 21:11 (#12), }, Ident { ident: "B", - span: $DIR/auxiliary/dollar-crate-external.rs:21:12: 21:13 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:12: 21:13 (#12), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "identity", - span: $DIR/auxiliary/dollar-crate-external.rs:21:14: 21:22 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:14: 21:22 (#12), }, Punct { ch: '!', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:21:22: 21:23 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:22: 21:23 (#12), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:21:24: 21:30 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:24: 21:30 (#12), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#12), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#12), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:21:32: 21:33 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:32: 21:33 (#12), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:21:23: 21:34 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:23: 21:34 (#12), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:21:13: 21:35 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:13: 21:35 (#12), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:21:35: 21:36 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:35: 21:36 (#12), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout index 72fc658858..d01fcb9d0e 100644 --- a/src/test/ui/proc-macro/dollar-crate.stdout +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -2,239 +2,239 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate.rs:20:17: 20:23 (#3), + span: $DIR/dollar-crate.rs:20:17: 20:23 (#4), }, Ident { ident: "M", - span: $DIR/dollar-crate.rs:20:24: 20:25 (#3), + span: $DIR/dollar-crate.rs:20:24: 20:25 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate.rs:20:26: 20:32 (#3), + span: $DIR/dollar-crate.rs:20:26: 20:32 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate.rs:20:32: 20:34 (#3), + span: $DIR/dollar-crate.rs:20:32: 20:34 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate.rs:20:32: 20:34 (#3), + span: $DIR/dollar-crate.rs:20:32: 20:34 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate.rs:20:34: 20:35 (#3), + span: $DIR/dollar-crate.rs:20:34: 20:35 (#4), }, ], - span: $DIR/dollar-crate.rs:20:25: 20:36 (#3), + span: $DIR/dollar-crate.rs:20:25: 20:36 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate.rs:20:36: 20:37 (#3), + span: $DIR/dollar-crate.rs:20:36: 20:37 (#4), }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate.rs:24:13: 24:19 (#3), + span: $DIR/dollar-crate.rs:24:13: 24:19 (#4), }, Ident { ident: "A", - span: $DIR/dollar-crate.rs:24:20: 24:21 (#3), + span: $DIR/dollar-crate.rs:24:20: 24:21 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate.rs:24:22: 24:28 (#3), + span: $DIR/dollar-crate.rs:24:22: 24:28 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate.rs:24:28: 24:30 (#3), + span: $DIR/dollar-crate.rs:24:28: 24:30 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate.rs:24:28: 24:30 (#3), + span: $DIR/dollar-crate.rs:24:28: 24:30 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate.rs:24:30: 24:31 (#3), + span: $DIR/dollar-crate.rs:24:30: 24:31 (#4), }, ], - span: $DIR/dollar-crate.rs:24:21: 24:32 (#3), + span: $DIR/dollar-crate.rs:24:21: 24:32 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate.rs:24:32: 24:33 (#3), + span: $DIR/dollar-crate.rs:24:32: 24:33 (#4), }, ] PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate.rs:27:13: 27:19 (#3), + span: $DIR/dollar-crate.rs:27:13: 27:19 (#4), }, Ident { ident: "D", - span: $DIR/dollar-crate.rs:27:20: 27:21 (#3), + span: $DIR/dollar-crate.rs:27:20: 27:21 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate.rs:27:22: 27:28 (#3), + span: $DIR/dollar-crate.rs:27:22: 27:28 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate.rs:27:28: 27:30 (#3), + span: $DIR/dollar-crate.rs:27:28: 27:30 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate.rs:27:28: 27:30 (#3), + span: $DIR/dollar-crate.rs:27:28: 27:30 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate.rs:27:30: 27:31 (#3), + span: $DIR/dollar-crate.rs:27:30: 27:31 (#4), }, ], - span: $DIR/dollar-crate.rs:27:21: 27:32 (#3), + span: $DIR/dollar-crate.rs:27:21: 27:32 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate.rs:27:32: 27:33 (#3), + span: $DIR/dollar-crate.rs:27:32: 27:33 (#4), }, ] PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:7:13: 7:19 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:13: 7:19 (#15), }, Ident { ident: "M", - span: $DIR/auxiliary/dollar-crate-external.rs:7:20: 7:21 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:20: 7:21 (#15), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:7:22: 7:28 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:22: 7:28 (#15), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#15), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#15), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:7:30: 7:31 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:30: 7:31 (#15), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:7:21: 7:32 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:21: 7:32 (#15), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:7:32: 7:33 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:32: 7:33 (#15), }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:11:9: 11:15 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:9: 11:15 (#15), }, Ident { ident: "A", - span: $DIR/auxiliary/dollar-crate-external.rs:11:16: 11:17 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:16: 11:17 (#15), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:11:18: 11:24 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:18: 11:24 (#15), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#15), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#15), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:11:26: 11:27 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:26: 11:27 (#15), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:11:17: 11:28 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:17: 11:28 (#15), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:11:28: 11:29 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:28: 11:29 (#15), }, ] PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:14:9: 14:15 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:9: 14:15 (#15), }, Ident { ident: "D", - span: $DIR/auxiliary/dollar-crate-external.rs:14:16: 14:17 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:16: 14:17 (#15), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:14:18: 14:24 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:18: 14:24 (#15), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#15), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#15), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:14:26: 14:27 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:26: 14:27 (#15), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:14:17: 14:28 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:17: 14:28 (#15), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:14:28: 14:29 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:28: 14:29 (#15), }, ] diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout index e7645280a7..e83bc9f8fc 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout @@ -1,6 +1,6 @@ -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#5) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#5) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#5) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#9) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#9) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#9) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#9) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#13) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#13) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#13) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#13) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#13) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#19) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#19) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#19) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#19) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#23) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#23) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#23) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#23) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#27) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#27) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#27) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#27) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#27) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#14) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#14) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }] diff --git a/src/test/ui/proc-macro/input-interpolated.stdout b/src/test/ui/proc-macro/input-interpolated.stdout index a9636cfef8..866608e4d8 100644 --- a/src/test/ui/proc-macro/input-interpolated.stdout +++ b/src/test/ui/proc-macro/input-interpolated.stdout @@ -8,14 +8,14 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ], - span: #3 bytes(370..372), + span: #4 bytes(370..372), }, ] PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "const", - span: #3 bytes(416..421), + span: #4 bytes(416..421), }, Group { delimiter: None, @@ -25,39 +25,39 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ], - span: #3 bytes(422..424), + span: #4 bytes(422..424), }, Punct { ch: ':', spacing: Alone, - span: #3 bytes(424..425), + span: #4 bytes(424..425), }, Ident { ident: "u8", - span: #3 bytes(426..428), + span: #4 bytes(426..428), }, Punct { ch: '=', spacing: Alone, - span: #3 bytes(429..430), + span: #4 bytes(429..430), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: #3 bytes(431..432), + span: #4 bytes(431..432), }, Punct { ch: ';', spacing: Alone, - span: #3 bytes(432..433), + span: #4 bytes(432..433), }, ] PRINT-DERIVE INPUT (DISPLAY): struct A { } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #3 bytes(468..474), + span: #4 bytes(468..474), }, Group { delimiter: None, @@ -67,11 +67,11 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ], - span: #3 bytes(475..477), + span: #4 bytes(475..477), }, Group { delimiter: Brace, stream: TokenStream [], - span: #3 bytes(478..480), + span: #4 bytes(478..480), }, ] diff --git a/src/test/ui/proc-macro/issue-37788.stderr b/src/test/ui/proc-macro/issue-37788.stderr index f2c833e69f..0538701290 100644 --- a/src/test/ui/proc-macro/issue-37788.stderr +++ b/src/test/ui/proc-macro/issue-37788.stderr @@ -7,10 +7,10 @@ LL | // Test that constructing the `visible_parent_map` (in `cstore_impl.rs` LL | std::cell::Cell::new(0) | ^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` | | - | expected `()`, found struct `std::cell::Cell` + | expected `()`, found struct `Cell` | = note: expected unit type `()` - found struct `std::cell::Cell<{integer}>` + found struct `Cell<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.rs b/src/test/ui/proc-macro/issue-75930-derive-cfg.rs new file mode 100644 index 0000000000..a051d23bac --- /dev/null +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.rs @@ -0,0 +1,66 @@ +// check-pass +// compile-flags: -Z span-debug --error-format human +// aux-build:test-macros.rs + +// Regression test for issue #75930 +// Tests that we cfg-strip all targets before invoking +// a derive macro +// We need '--error-format human' to stop compiletest from +// trying to interpret proc-macro output as JSON messages +// (a pretty-printed struct may cause a line to start with '{' ) +// FIXME: We currently lose spans here (see issue #43081) + +#[macro_use] +extern crate test_macros; + +#[print_helper(a)] +#[cfg_attr(not(FALSE), allow(dead_code))] +#[print_attr] +#[derive(Print)] +#[print_helper(b)] +struct Foo<#[cfg(FALSE)] A, B> { + #[cfg(FALSE)] first: String, + #[cfg_attr(FALSE, deny(warnings))] second: bool, + third: [u8; { + #[cfg(FALSE)] struct Bar; + #[cfg(not(FALSE))] struct Inner; + #[cfg(FALSE)] let a = 25; + match true { + #[cfg(FALSE)] true => {}, + #[cfg_attr(not(FALSE), allow(warnings))] false => {}, + _ => {} + }; + + #[print_helper(should_be_removed)] + fn removed_fn() { + #![cfg(FALSE)] + } + + #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { + #![cfg(not(FALSE))] + let my_val = true; + } + + enum TupleEnum { + Foo( + #[cfg(FALSE)] u8, + #[cfg(FALSE)] bool, + #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] String, u8 + ) + } + + struct TupleStruct( + #[cfg(FALSE)] String, + #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] bool, + u8 + ); + + 0 + }], + #[print_helper(d)] + fourth: B +} + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout new file mode 100644 index 0000000000..f3daa56a49 --- /dev/null +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -0,0 +1,1831 @@ +PRINT-ATTR INPUT (DISPLAY): #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] #[print_helper(a)] +struct Foo < #[cfg(FALSE)] A, B > +{ + #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : + bool, third : + [u8 ; + { + #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ; + #[cfg(FALSE)] let a = 25 ; match true + { + #[cfg(FALSE)] true => { }, + #[cfg_attr(not(FALSE), allow(warnings))] false => { }, _ => { } + } ; #[print_helper(should_be_removed)] fn removed_fn() + { # ! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn + kept_fn() { # ! [cfg(not(FALSE))] let my_val = true ; } enum + TupleEnum + { + Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] String, u8) + } struct + TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] bool, u8) ; 0 + }], #[print_helper(d)] fourth : B +} +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:40 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/issue-75930-derive-cfg.rs:17:30: 17:39 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:17:29: 17:40 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:40 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:17 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "derive", + span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:9 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "Print", + span: $DIR/issue-75930-derive-cfg.rs:19:10: 19:15 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:19:9: 19:16 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:17 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:20:1: 20:19 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:20:3: 20:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "b", + span: $DIR/issue-75930-derive-cfg.rs:20:16: 20:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:20:15: 20:18 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:20:1: 20:19 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:16:1: 16:19 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:16:3: 16:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:16:16: 16:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:16:15: 16:18 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:16:1: 16:19 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:7 (#0), + }, + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:21:8: 21:11 (#0), + }, + Punct { + ch: '<', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:21:11: 21:12 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:21:12: 21:13 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:21:14: 21:17 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:21:18: 21:23 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:21:17: 21:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:21:13: 21:25 (#0), + }, + Ident { + ident: "A", + span: $DIR/issue-75930-derive-cfg.rs:21:26: 21:27 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:21:27: 21:28 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:30 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:31 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:22:5: 22:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:22:7: 22:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:22:11: 22:16 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:22:10: 22:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:22:6: 22:18 (#0), + }, + Ident { + ident: "first", + span: $DIR/issue-75930-derive-cfg.rs:22:19: 22:24 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:22:24: 22:25 (#0), + }, + Ident { + ident: "String", + span: $DIR/issue-75930-derive-cfg.rs:22:26: 22:32 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:22:32: 22:33 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:5: 23:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/issue-75930-derive-cfg.rs:23:7: 23:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:23:16: 23:21 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:21: 23:22 (#0), + }, + Ident { + ident: "deny", + span: $DIR/issue-75930-derive-cfg.rs:23:23: 23:27 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: $DIR/issue-75930-derive-cfg.rs:23:28: 23:36 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:23:27: 23:37 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:23:15: 23:38 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:23:6: 23:39 (#0), + }, + Ident { + ident: "second", + span: $DIR/issue-75930-derive-cfg.rs:23:40: 23:46 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:46: 23:47 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:23:48: 23:52 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:52: 23:53 (#0), + }, + Ident { + ident: "third", + span: $DIR/issue-75930-derive-cfg.rs:24:5: 24:10 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:24:10: 24:11 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:24:13: 24:15 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:16 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:25:9: 25:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:25:15: 25:20 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:25:14: 25:21 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:25:10: 25:22 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:25:23: 25:29 (#0), + }, + Ident { + ident: "Bar", + span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:33 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:25:33: 25:34 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:26:9: 26:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:26:11: 26:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:26:15: 26:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:26:19: 26:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:26:18: 26:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:26:14: 26:26 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:26:10: 26:27 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:26:28: 26:34 (#0), + }, + Ident { + ident: "Inner", + span: $DIR/issue-75930-derive-cfg.rs:26:35: 26:40 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:26:40: 26:41 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:27:9: 27:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:27:11: 27:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:27:15: 27:20 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:27:14: 27:21 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:27:10: 27:22 (#0), + }, + Ident { + ident: "let", + span: $DIR/issue-75930-derive-cfg.rs:27:23: 27:26 (#0), + }, + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:27:27: 27:28 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:27:29: 27:30 (#0), + }, + Literal { + kind: Integer, + symbol: "25", + suffix: None, + span: $DIR/issue-75930-derive-cfg.rs:27:31: 27:33 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:27:33: 27:34 (#0), + }, + Ident { + ident: "match", + span: $DIR/issue-75930-derive-cfg.rs:28:9: 28:14 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:19 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:29:13: 29:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:29:15: 29:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:29:19: 29:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:29:18: 29:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:29:14: 29:26 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:29:27: 29:31 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:29:32: 29:34 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:29:32: 29:34 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:29:35: 29:37 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:29:37: 29:38 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:13: 30:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:30:24: 30:27 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:33 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:27: 30:34 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:34: 30:35 (#0), + }, + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:30:36: 30:41 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: $DIR/issue-75930-derive-cfg.rs:30:42: 30:50 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:41: 30:51 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:23: 30:52 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:53 (#0), + }, + Ident { + ident: "false", + span: $DIR/issue-75930-derive-cfg.rs:30:54: 30:59 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:30:60: 30:62 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:60: 30:62 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:30:63: 30:65 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:65: 30:66 (#0), + }, + Ident { + ident: "_", + span: $DIR/issue-75930-derive-cfg.rs:31:13: 31:14 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:17 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:17 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:31:18: 31:20 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:28:20: 32:10 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:32:10: 32:11 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:34:9: 34:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:34:11: 34:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "should_be_removed", + span: $DIR/issue-75930-derive-cfg.rs:34:24: 34:41 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:34:23: 34:42 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:34:10: 34:43 (#0), + }, + Ident { + ident: "fn", + span: $DIR/issue-75930-derive-cfg.rs:35:9: 35:11 (#0), + }, + Ident { + ident: "removed_fn", + span: $DIR/issue-75930-derive-cfg.rs:35:12: 35:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:35:22: 35:24 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:36:13: 36:14 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:36:14: 36:15 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:36:16: 36:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:36:20: 36:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:36:19: 36:26 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:36:15: 36:27 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:35:25: 37:10 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:39:9: 39:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:39:11: 39:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "c", + span: $DIR/issue-75930-derive-cfg.rs:39:24: 39:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:23: 39:26 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:10: 39:27 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:39:28: 39:29 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:39:30: 39:33 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:39:34: 39:37 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:39:38: 39:43 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:37: 39:44 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:33: 39:45 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:29: 39:46 (#0), + }, + Ident { + ident: "fn", + span: $DIR/issue-75930-derive-cfg.rs:39:47: 39:49 (#0), + }, + Ident { + ident: "kept_fn", + span: $DIR/issue-75930-derive-cfg.rs:39:50: 39:57 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:39:57: 39:59 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:40:13: 40:14 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:40:14: 40:15 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:40:16: 40:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:40:20: 40:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:40:24: 40:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:40:23: 40:30 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:40:19: 40:31 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:40:15: 40:32 (#0), + }, + Ident { + ident: "let", + span: $DIR/issue-75930-derive-cfg.rs:41:13: 41:16 (#0), + }, + Ident { + ident: "my_val", + span: $DIR/issue-75930-derive-cfg.rs:41:17: 41:23 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:41:24: 41:25 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:41:26: 41:30 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:41:30: 41:31 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:60: 42:10 (#0), + }, + Ident { + ident: "enum", + span: $DIR/issue-75930-derive-cfg.rs:44:9: 44:13 (#0), + }, + Ident { + ident: "TupleEnum", + span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:23 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:46:17: 46:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:46:19: 46:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:46:23: 46:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:46:22: 46:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:46:18: 46:30 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:46:31: 46:33 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:46:33: 46:34 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:47:17: 47:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:47:19: 47:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:47:23: 47:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:47:22: 47:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:47:18: 47:30 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:47:31: 47:35 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:47:35: 47:36 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:48:17: 48:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:48:19: 48:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:48:23: 48:26 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:48:27: 48:32 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:48:26: 48:33 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:48:22: 48:34 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:48:18: 48:35 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:48:36: 48:39 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:48:39: 48:40 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:49:17: 49:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:49:19: 49:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:49:23: 49:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:49:22: 49:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:49:18: 49:30 (#0), + }, + Ident { + ident: "String", + span: $DIR/issue-75930-derive-cfg.rs:49:31: 49:37 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:49:37: 49:38 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:49:39: 49:41 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:45:16: 50:14 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:44:24: 51:10 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:53:9: 53:15 (#0), + }, + Ident { + ident: "TupleStruct", + span: $DIR/issue-75930-derive-cfg.rs:53:16: 53:27 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:54:13: 54:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:54:19: 54:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:54:18: 54:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:54:14: 54:26 (#0), + }, + Ident { + ident: "String", + span: $DIR/issue-75930-derive-cfg.rs:54:27: 54:33 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:54:33: 54:34 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:55:13: 55:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:55:15: 55:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:55:19: 55:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:55:23: 55:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:55:22: 55:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:55:18: 55:30 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:55:14: 55:31 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:55:32: 55:35 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:55:35: 55:36 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:56:13: 56:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:56:15: 56:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:56:19: 56:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:56:18: 56:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:56:14: 56:26 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:56:27: 56:31 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:56:31: 56:32 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:57:13: 57:15 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:53:27: 58:10 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:24:17: 61:6 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:24:12: 61:7 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:61:7: 61:8 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:62:5: 62:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:62:7: 62:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "d", + span: $DIR/issue-75930-derive-cfg.rs:62:20: 62:21 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:62:19: 62:22 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:62:6: 62:23 (#0), + }, + Ident { + ident: "fourth", + span: $DIR/issue-75930-derive-cfg.rs:63:5: 63:11 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:63:11: 63:12 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:63:13: 63:14 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:21:32: 64:2 (#0), + }, +] +PRINT-DERIVE INPUT (DISPLAY): #[allow(dead_code)] #[print_helper(b)] #[print_helper(a)] struct Foo < B > +{ + second : bool, third : + [u8 ; + { + #[cfg(not(FALSE))] struct Inner ; match true + { #[allow(warnings)] false => { } _ => { } } ; #[print_helper(c)] + #[cfg(not(FALSE))] fn kept_fn() + { # ! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum + { Foo(#[cfg(not(FALSE))] i32, u8), } struct + TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0 + }], #[print_helper(d)] fourth : B, +} +PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "b", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '<', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "second", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "third", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "Inner", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "match", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "false", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "_", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "c", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "fn", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "kept_fn", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "let", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "my_val", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "enum", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "TupleEnum", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "TupleStruct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "d", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "fourth", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, +] diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs new file mode 100644 index 0000000000..7d31de1d22 --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs @@ -0,0 +1,16 @@ +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// +// Regression test for issue #76182 +// Tests that we properly handle patterns with a leading vert + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate test_macros; + +#[test_macros::print_attr] +fn main() { + match () { | () => () } +} diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout new file mode 100644 index 0000000000..5493f9c7b6 --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout @@ -0,0 +1,62 @@ +PRINT-ATTR INPUT (DISPLAY): fn main() { match() { | () => () } } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/issue-76182-leading-vert-pat.rs:14:1: 14:3 (#0), + }, + Ident { + ident: "main", + span: $DIR/issue-76182-leading-vert-pat.rs:14:4: 14:8 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:14:8: 14:10 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "match", + span: $DIR/issue-76182-leading-vert-pat.rs:15:5: 15:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:11: 15:13 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '|', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:16: 15:17 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:18: 15:20 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:24: 15:26 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:15:14: 15:28 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:14:11: 16:2 (#0), + }, +] diff --git a/src/test/ui/proc-macro/load-panic-backtrace.rs b/src/test/ui/proc-macro/load-panic-backtrace.rs new file mode 100644 index 0000000000..90fe109abb --- /dev/null +++ b/src/test/ui/proc-macro/load-panic-backtrace.rs @@ -0,0 +1,21 @@ +// aux-build:test-macros.rs +// compile-flags: -Z proc-macro-backtrace +// rustc-env:RUST_BACKTRACE=0 + +// FIXME https://github.com/rust-lang/rust/issues/59998 +// normalize-stderr-test "thread '.*' panicked " -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" + +#[macro_use] +extern crate test_macros; + +#[derive(Panic)] +//~^ ERROR: proc-macro derive panicked +struct Foo; + +fn main() {} diff --git a/src/test/ui/proc-macro/load-panic-backtrace.stderr b/src/test/ui/proc-macro/load-panic-backtrace.stderr new file mode 100644 index 0000000000..63378b5735 --- /dev/null +++ b/src/test/ui/proc-macro/load-panic-backtrace.stderr @@ -0,0 +1,11 @@ +at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5 +error: proc-macro derive panicked + --> $DIR/load-panic-backtrace.rs:17:10 + | +LL | #[derive(Panic)] + | ^^^^^ + | + = help: message: panic-derive + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.stderr b/src/test/ui/proc-macro/macros-in-extern-derive.stderr index e2afb7d34c..6b73744920 100644 --- a/src/test/ui/proc-macro/macros-in-extern-derive.stderr +++ b/src/test/ui/proc-macro/macros-in-extern-derive.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/macros-in-extern-derive.rs:2:5 | LL | #[derive(Copy)] @@ -6,3 +6,4 @@ LL | #[derive(Copy)] error: aborting due to previous error +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.rs b/src/test/ui/proc-macro/meta-macro-hygiene.rs index c11cf42956..7e839f747f 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.rs +++ b/src/test/ui/proc-macro/meta-macro-hygiene.rs @@ -1,7 +1,8 @@ +// ignore-tidy-linelength // aux-build:make-macro.rs // aux-build:meta-macro.rs // edition:2018 -// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene +// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene -Z trim-diagnostic-paths=no // check-pass // normalize-stdout-test "\d+#" -> "0#" // diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout index dfd3e6a839..81cebae17a 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -1,11 +1,12 @@ -Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) -Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:23:37: 23:43 (#3) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#3) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#3) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:23:45: 23:50 (#3) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:50: 23:51 (#3) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:23:51: 23:53 (#3) }] -Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }] +Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) +Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:24:37: 24:43 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:24:45: 24:50 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:50: 24:51 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:24:51: 24:53 (#4) }] +Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }] #![feature /* 0#0 */(prelude_import)] +// ignore-tidy-linelength // aux-build:make-macro.rs // aux-build:meta-macro.rs // edition:2018 -// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene +// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene -Z trim-diagnostic-paths=no // check-pass // normalize-stdout-test "\d+#" -> "0#" // @@ -46,18 +47,20 @@ Expansions: 0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root 1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) 2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") -3: parent: ExpnId(2), call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") -4: parent: ExpnId(3), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) +4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") +5: parent: ExpnId(4), call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") SyntaxContexts: #0: parent: #0, outer_mark: (ExpnId(0), Opaque) #1: parent: #0, outer_mark: (ExpnId(1), Opaque) #2: parent: #0, outer_mark: (ExpnId(1), Transparent) -#3: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) -#4: parent: #0, outer_mark: (ExpnId(3), Opaque) -#5: parent: #3, outer_mark: (ExpnId(3), Transparent) -#6: parent: #0, outer_mark: (ExpnId(3), SemiTransparent) -#7: parent: #0, outer_mark: (ExpnId(4), Opaque) -#8: parent: #4, outer_mark: (ExpnId(4), Transparent) -#9: parent: #4, outer_mark: (ExpnId(4), SemiTransparent) +#3: parent: #0, outer_mark: (ExpnId(3), Opaque) +#4: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) +#5: parent: #0, outer_mark: (ExpnId(4), Opaque) +#6: parent: #4, outer_mark: (ExpnId(4), Transparent) +#7: parent: #0, outer_mark: (ExpnId(4), SemiTransparent) +#8: parent: #0, outer_mark: (ExpnId(5), Opaque) +#9: parent: #5, outer_mark: (ExpnId(5), Transparent) +#10: parent: #5, outer_mark: (ExpnId(5), SemiTransparent) */ diff --git a/src/test/ui/proc-macro/meta-macro.stdout b/src/test/ui/proc-macro/meta-macro.stdout index 71aa565f4d..662682d40b 100644 --- a/src/test/ui/proc-macro/meta-macro.stdout +++ b/src/test/ui/proc-macro/meta-macro.stdout @@ -1,3 +1,3 @@ -Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#3) +Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) Input: TokenStream [] Respanned: TokenStream [] diff --git a/src/test/ui/proc-macro/nested-macro-rules.stdout b/src/test/ui/proc-macro/nested-macro-rules.stdout index 7feea56c5d..dcafe3b4bd 100644 --- a/src/test/ui/proc-macro/nested-macro-rules.stdout +++ b/src/test/ui/proc-macro/nested-macro-rules.stdout @@ -5,10 +5,10 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "FirstStruct", - span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#5), + span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#7), }, ], - span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#4), + span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#6), }, ] PRINT-BANG INPUT (DISPLAY): SecondStruct @@ -18,9 +18,9 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "SecondStruct", - span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#11), + span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#13), }, ], - span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#10), + span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#12), }, ] diff --git a/src/test/ui/proc-macro/nested-nonterminal-tokens.rs b/src/test/ui/proc-macro/nested-nonterminal-tokens.rs new file mode 100644 index 0000000000..2f5af10a40 --- /dev/null +++ b/src/test/ui/proc-macro/nested-nonterminal-tokens.rs @@ -0,0 +1,26 @@ +// check-pass +// edition:2018 +// compile-flags: -Z span-debug +// aux-build:test-macros.rs + +// Tests that we properly pass tokens to proc-macro when nested +// nonterminals are involved. + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +#[macro_use] +extern crate test_macros; + + +macro_rules! wrap { + (first, $e:expr) => { wrap!(second, $e + 1) }; + (second, $e:expr) => { wrap!(third, $e + 2) }; + (third, $e:expr) => { + print_bang!($e + 3); + }; +} + +fn main() { + let _ = wrap!(first, 0); +} diff --git a/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout new file mode 100644 index 0000000000..a3d24dd26f --- /dev/null +++ b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout @@ -0,0 +1,60 @@ +PRINT-BANG INPUT (DISPLAY): 0 + 1 + 2 + 3 +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: $DIR/nested-nonterminal-tokens.rs:25:26: 25:27 (#0), + }, + ], + span: $DIR/nested-nonterminal-tokens.rs:17:41: 17:43 (#4), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nested-nonterminal-tokens.rs:17:44: 17:45 (#4), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/nested-nonterminal-tokens.rs:17:46: 17:47 (#4), + }, + ], + span: $DIR/nested-nonterminal-tokens.rs:18:41: 18:43 (#5), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nested-nonterminal-tokens.rs:18:44: 18:45 (#5), + }, + Literal { + kind: Integer, + symbol: "2", + suffix: None, + span: $DIR/nested-nonterminal-tokens.rs:18:46: 18:47 (#5), + }, + ], + span: $DIR/nested-nonterminal-tokens.rs:20:21: 20:23 (#6), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nested-nonterminal-tokens.rs:20:24: 20:25 (#6), + }, + Literal { + kind: Integer, + symbol: "3", + suffix: None, + span: $DIR/nested-nonterminal-tokens.rs:20:26: 20:27 (#6), + }, +] diff --git a/src/test/ui/proc-macro/nodelim-groups.stdout b/src/test/ui/proc-macro/nodelim-groups.stdout index cdf851b535..6b410f0bfb 100644 --- a/src/test/ui/proc-macro/nodelim-groups.stdout +++ b/src/test/ui/proc-macro/nodelim-groups.stdout @@ -4,7 +4,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Str, symbol: "hi", suffix: None, - span: $DIR/nodelim-groups.rs:16:42: 16:46 (#3), + span: $DIR/nodelim-groups.rs:16:42: 16:46 (#4), }, Group { delimiter: None, @@ -44,7 +44,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nodelim-groups.rs:20:27: 20:28 (#0), }, ], - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#3), + span: $DIR/nodelim-groups.rs:16:47: 16:51 (#4), }, Group { delimiter: Parenthesis, @@ -53,21 +53,21 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:53: 16:54 (#3), + span: $DIR/nodelim-groups.rs:16:53: 16:54 (#4), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:16:55: 16:56 (#3), + span: $DIR/nodelim-groups.rs:16:55: 16:56 (#4), }, Literal { kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:57: 16:58 (#3), + span: $DIR/nodelim-groups.rs:16:57: 16:58 (#4), }, ], - span: $DIR/nodelim-groups.rs:16:52: 16:59 (#3), + span: $DIR/nodelim-groups.rs:16:52: 16:59 (#4), }, ] PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1) @@ -76,7 +76,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Str, symbol: "hi", suffix: None, - span: $DIR/nodelim-groups.rs:16:42: 16:46 (#8), + span: $DIR/nodelim-groups.rs:16:42: 16:46 (#9), }, Group { delimiter: None, @@ -105,12 +105,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nodelim-groups.rs:21:28: 21:30 (#0), }, ], - span: $DIR/nodelim-groups.rs:15:49: 15:54 (#7), + span: $DIR/nodelim-groups.rs:15:49: 15:54 (#8), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:15:55: 15:56 (#7), + span: $DIR/nodelim-groups.rs:15:55: 15:56 (#8), }, Group { delimiter: None, @@ -136,10 +136,10 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nodelim-groups.rs:21:44: 21:46 (#0), }, ], - span: $DIR/nodelim-groups.rs:15:57: 15:62 (#7), + span: $DIR/nodelim-groups.rs:15:57: 15:62 (#8), }, ], - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), + span: $DIR/nodelim-groups.rs:16:47: 16:51 (#9), }, Group { delimiter: Parenthesis, @@ -148,20 +148,20 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:53: 16:54 (#8), + span: $DIR/nodelim-groups.rs:16:53: 16:54 (#9), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:16:55: 16:56 (#8), + span: $DIR/nodelim-groups.rs:16:55: 16:56 (#9), }, Literal { kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:57: 16:58 (#8), + span: $DIR/nodelim-groups.rs:16:57: 16:58 (#9), }, ], - span: $DIR/nodelim-groups.rs:16:52: 16:59 (#8), + span: $DIR/nodelim-groups.rs:16:52: 16:59 (#9), }, ] diff --git a/src/test/ui/proc-macro/resolved-located-at.stderr b/src/test/ui/proc-macro/resolved-located-at.stderr index e71e79514f..db1aa5d572 100644 --- a/src/test/ui/proc-macro/resolved-located-at.stderr +++ b/src/test/ui/proc-macro/resolved-located-at.stderr @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | fn main() { | - expected `()` because of default return type LL | resolve_located_at!(a b) - | ^ expected `()`, found struct `main::S` + | ^ expected `()`, found struct `S` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index a77e92022e..70e992a4f7 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -26,11 +26,11 @@ error[E0308]: mismatched types LL | let x = Foo { a: 10isize }; | ^^^^^^^ expected `usize`, found `isize` -error[E0560]: struct `c::Foo` has no field named `b` +error[E0560]: struct `Foo` has no field named `b` --> $DIR/span-preservation.rs:34:26 | LL | let y = Foo { a: 10, b: 10isize }; - | ^ `c::Foo` does not have this field + | ^ `Foo` does not have this field | = note: available fields are: `a` diff --git a/src/test/ui/proc-macro/trailing-plus.rs b/src/test/ui/proc-macro/trailing-plus.rs new file mode 100644 index 0000000000..4f61de47d8 --- /dev/null +++ b/src/test/ui/proc-macro/trailing-plus.rs @@ -0,0 +1,14 @@ +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate test_macros; + +#[test_macros::print_attr] +fn foo() where T: Copy + { +} + +fn main() {} diff --git a/src/test/ui/proc-macro/trailing-plus.stdout b/src/test/ui/proc-macro/trailing-plus.stdout new file mode 100644 index 0000000000..d60f400af2 --- /dev/null +++ b/src/test/ui/proc-macro/trailing-plus.stdout @@ -0,0 +1,57 @@ +PRINT-ATTR INPUT (DISPLAY): fn foo < T > () where T : Copy + { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/trailing-plus.rs:11:1: 11:3 (#0), + }, + Ident { + ident: "foo", + span: $DIR/trailing-plus.rs:11:4: 11:7 (#0), + }, + Punct { + ch: '<', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:7: 11:8 (#0), + }, + Ident { + ident: "T", + span: $DIR/trailing-plus.rs:11:8: 11:9 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:9: 11:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/trailing-plus.rs:11:10: 11:12 (#0), + }, + Ident { + ident: "where", + span: $DIR/trailing-plus.rs:11:13: 11:18 (#0), + }, + Ident { + ident: "T", + span: $DIR/trailing-plus.rs:11:19: 11:20 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:20: 11:21 (#0), + }, + Ident { + ident: "Copy", + span: $DIR/trailing-plus.rs:11:22: 11:26 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:27: 11:28 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/trailing-plus.rs:11:29: 12:2 (#0), + }, +] diff --git a/src/test/ui/proc-macro/unsafe-foreign-mod.rs b/src/test/ui/proc-macro/unsafe-foreign-mod.rs new file mode 100644 index 0000000000..7bdfa93c21 --- /dev/null +++ b/src/test/ui/proc-macro/unsafe-foreign-mod.rs @@ -0,0 +1,14 @@ +// run-pass +// aux-build:macro-only-syntax.rs + +extern crate macro_only_syntax; + +#[macro_only_syntax::expect_unsafe_foreign_mod] +unsafe extern { + type T; +} + +#[macro_only_syntax::expect_unsafe_extern_cpp_mod] +unsafe extern "C++" {} + +fn main() {} diff --git a/src/test/ui/proc-macro/unsafe-mod.rs b/src/test/ui/proc-macro/unsafe-mod.rs new file mode 100644 index 0000000000..8ff6e352c5 --- /dev/null +++ b/src/test/ui/proc-macro/unsafe-mod.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:macro-only-syntax.rs + +#![feature(proc_macro_hygiene)] + +extern crate macro_only_syntax; + +#[macro_only_syntax::expect_unsafe_mod] +unsafe mod m { + pub unsafe mod inner; +} + +fn main() {} diff --git a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs index 45dfb63992..d089359503 100644 --- a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs +++ b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs @@ -5,7 +5,7 @@ pub(crate) struct Snail; mod sea { pub(super) struct Turtle; - //~^ NOTE `sea::Turtle` declared as restricted + //~^ NOTE `Turtle` declared as restricted } struct Tortoise; @@ -19,7 +19,7 @@ pub type Helix_pomatia = Shell; //~^ ERROR crate-visible type `Snail` in public interface //~| NOTE can't leak crate-visible type pub type Dermochelys_coriacea = Shell; -//~^ ERROR restricted type `sea::Turtle` in public interface +//~^ ERROR restricted type `Turtle` in public interface //~| NOTE can't leak restricted type pub type Testudo_graeca = Shell; //~^ ERROR private type `Tortoise` in public interface diff --git a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr index ae9a33e944..41b6b09554 100644 --- a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr +++ b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr @@ -7,11 +7,11 @@ LL | pub(crate) struct Snail; LL | pub type Helix_pomatia = Shell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-visible type -error[E0446]: restricted type `sea::Turtle` in public interface +error[E0446]: restricted type `Turtle` in public interface --> $DIR/issue-33174-restricted-type-in-public-interface.rs:21:1 | LL | pub(super) struct Turtle; - | ---------- `sea::Turtle` declared as restricted + | ---------- `Turtle` declared as restricted ... LL | pub type Dermochelys_coriacea = Shell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak restricted type diff --git a/src/test/ui/qualified/qualified-path-params.rs b/src/test/ui/qualified/qualified-path-params.rs index 65549d909d..e8a95a4601 100644 --- a/src/test/ui/qualified/qualified-path-params.rs +++ b/src/test/ui/qualified/qualified-path-params.rs @@ -18,7 +18,8 @@ impl S { fn main() { match 10 { ::A::f:: => {} - //~^ ERROR expected unit struct, unit variant or constant, found associated function - 0 ..= ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range + //~^ ERROR expected unit struct, unit variant or constant, found associated function + 0 ..= ::A::f:: => {} + //~^ ERROR only `char` and numeric types are allowed in range } } diff --git a/src/test/ui/qualified/qualified-path-params.stderr b/src/test/ui/qualified/qualified-path-params.stderr index 4214e2503c..2be2deeb75 100644 --- a/src/test/ui/qualified/qualified-path-params.stderr +++ b/src/test/ui/qualified/qualified-path-params.stderr @@ -4,7 +4,7 @@ error[E0533]: expected unit struct, unit variant or constant, found associated f LL | ::A::f:: => {} | ^^^^^^^^^^^^^^^^^^^^^ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/qualified-path-params.rs:22:15 | LL | 0 ..= ::A::f:: => {} diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr index 64d8f68563..f530534ec8 100644 --- a/src/test/ui/question-mark-type-infer.stderr +++ b/src/test/ui/question-mark-type-infer.stderr @@ -4,7 +4,7 @@ error[E0284]: type annotations needed LL | l.iter().map(f).collect()? | ^^^^^^^ cannot infer type | - = note: cannot satisfy `<_ as std::ops::Try>::Ok == _` + = note: cannot satisfy `<_ as Try>::Ok == _` help: consider specifying the type argument in the method call | LL | l.iter().map(f).collect::()? diff --git a/src/test/ui/range/issue-54505-no-literals.stderr b/src/test/ui/range/issue-54505-no-literals.stderr index c49093343c..065e16a822 100644 --- a/src/test/ui/range/issue-54505-no-literals.stderr +++ b/src/test/ui/range/issue-54505-no-literals.stderr @@ -28,11 +28,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeFrom { start: 1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeFrom` + | expected reference, found struct `RangeFrom` | help: consider borrowing here: `&std::ops::RangeFrom { start: 1 }` | = note: expected reference `&_` - found struct `std::ops::RangeFrom<{integer}>` + found struct `RangeFrom<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:31:16 @@ -40,11 +40,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeFrom { start: 1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeFrom` + | expected reference, found struct `RangeFrom` | help: consider borrowing here: `&::std::ops::RangeFrom { start: 1 }` | = note: expected reference `&_` - found struct `std::ops::RangeFrom<{integer}>` + found struct `RangeFrom<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:36:16 @@ -52,11 +52,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeFull {}); | ^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeFull` + | expected reference, found struct `RangeFull` | help: consider borrowing here: `&std::ops::RangeFull {}` | = note: expected reference `&_` - found struct `std::ops::RangeFull` + found struct `RangeFull` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:41:16 @@ -64,11 +64,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeFull {}); | ^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeFull` + | expected reference, found struct `RangeFull` | help: consider borrowing here: `&::std::ops::RangeFull {}` | = note: expected reference `&_` - found struct `std::ops::RangeFull` + found struct `RangeFull` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:46:16 @@ -76,11 +76,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeInclusive::new(0, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeInclusive` + | expected reference, found struct `RangeInclusive` | help: consider borrowing here: `&std::ops::RangeInclusive::new(0, 1)` | = note: expected reference `&_` - found struct `std::ops::RangeInclusive<{integer}>` + found struct `RangeInclusive<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:51:16 @@ -88,11 +88,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeInclusive::new(0, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeInclusive` + | expected reference, found struct `RangeInclusive` | help: consider borrowing here: `&::std::ops::RangeInclusive::new(0, 1)` | = note: expected reference `&_` - found struct `std::ops::RangeInclusive<{integer}>` + found struct `RangeInclusive<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:56:16 @@ -100,11 +100,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeTo { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeTo` + | expected reference, found struct `RangeTo` | help: consider borrowing here: `&std::ops::RangeTo { end: 5 }` | = note: expected reference `&_` - found struct `std::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:61:16 @@ -112,11 +112,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeTo { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeTo` + | expected reference, found struct `RangeTo` | help: consider borrowing here: `&::std::ops::RangeTo { end: 5 }` | = note: expected reference `&_` - found struct `std::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:66:16 @@ -124,11 +124,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeToInclusive { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeToInclusive` + | expected reference, found struct `RangeToInclusive` | help: consider borrowing here: `&std::ops::RangeToInclusive { end: 5 }` | = note: expected reference `&_` - found struct `std::ops::RangeToInclusive<{integer}>` + found struct `RangeToInclusive<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:71:16 @@ -136,11 +136,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeToInclusive { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeToInclusive` + | expected reference, found struct `RangeToInclusive` | help: consider borrowing here: `&::std::ops::RangeToInclusive { end: 5 }` | = note: expected reference `&_` - found struct `std::ops::RangeToInclusive<{integer}>` + found struct `RangeToInclusive<{integer}>` error: aborting due to 12 previous errors diff --git a/src/test/ui/range/issue-54505-no-std.rs b/src/test/ui/range/issue-54505-no-std.rs index c6a3cc346f..f5d5823e46 100644 --- a/src/test/ui/range/issue-54505-no-std.rs +++ b/src/test/ui/range/issue-54505-no-std.rs @@ -14,6 +14,9 @@ use core::ops::RangeBounds; #[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] #[lang = "eh_personality"] extern fn eh_personality() {} +#[cfg(target_os = "emscripten")] +#[lang = "eh_catch_typeinfo"] +static EH_CATCH_TYPEINFO: u8 = 0; // take a reference to any built-in range diff --git a/src/test/ui/range/issue-54505-no-std.stderr b/src/test/ui/range/issue-54505-no-std.stderr index 9093406113..73507f4836 100644 --- a/src/test/ui/range/issue-54505-no-std.stderr +++ b/src/test/ui/range/issue-54505-no-std.stderr @@ -1,76 +1,76 @@ error: `#[panic_handler]` function required, but not found error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:24:16 + --> $DIR/issue-54505-no-std.rs:27:16 | LL | take_range(0..1); | ^^^^ | | - | expected reference, found struct `core::ops::Range` + | expected reference, found struct `Range` | help: consider borrowing here: `&(0..1)` | = note: expected reference `&_` - found struct `core::ops::Range<{integer}>` + found struct `Range<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:29:16 + --> $DIR/issue-54505-no-std.rs:32:16 | LL | take_range(1..); | ^^^ | | - | expected reference, found struct `core::ops::RangeFrom` + | expected reference, found struct `RangeFrom` | help: consider borrowing here: `&(1..)` | = note: expected reference `&_` - found struct `core::ops::RangeFrom<{integer}>` + found struct `RangeFrom<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:34:16 + --> $DIR/issue-54505-no-std.rs:37:16 | LL | take_range(..); | ^^ | | - | expected reference, found struct `core::ops::RangeFull` + | expected reference, found struct `RangeFull` | help: consider borrowing here: `&(..)` | = note: expected reference `&_` - found struct `core::ops::RangeFull` + found struct `RangeFull` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:39:16 + --> $DIR/issue-54505-no-std.rs:42:16 | LL | take_range(0..=1); | ^^^^^ | | - | expected reference, found struct `core::ops::RangeInclusive` + | expected reference, found struct `RangeInclusive` | help: consider borrowing here: `&(0..=1)` | = note: expected reference `&_` - found struct `core::ops::RangeInclusive<{integer}>` + found struct `RangeInclusive<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:44:16 + --> $DIR/issue-54505-no-std.rs:47:16 | LL | take_range(..5); | ^^^ | | - | expected reference, found struct `core::ops::RangeTo` + | expected reference, found struct `RangeTo` | help: consider borrowing here: `&(..5)` | = note: expected reference `&_` - found struct `core::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:49:16 + --> $DIR/issue-54505-no-std.rs:52:16 | LL | take_range(..=42); | ^^^^^ | | - | expected reference, found struct `core::ops::RangeToInclusive` + | expected reference, found struct `RangeToInclusive` | help: consider borrowing here: `&(..=42)` | = note: expected reference `&_` - found struct `core::ops::RangeToInclusive<{integer}>` + found struct `RangeToInclusive<{integer}>` error: aborting due to 7 previous errors diff --git a/src/test/ui/range/issue-54505.stderr b/src/test/ui/range/issue-54505.stderr index 9949ff8567..121af29834 100644 --- a/src/test/ui/range/issue-54505.stderr +++ b/src/test/ui/range/issue-54505.stderr @@ -16,11 +16,11 @@ error[E0308]: mismatched types LL | take_range(1..); | ^^^ | | - | expected reference, found struct `std::ops::RangeFrom` + | expected reference, found struct `RangeFrom` | help: consider borrowing here: `&(1..)` | = note: expected reference `&_` - found struct `std::ops::RangeFrom<{integer}>` + found struct `RangeFrom<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505.rs:24:16 @@ -28,11 +28,11 @@ error[E0308]: mismatched types LL | take_range(..); | ^^ | | - | expected reference, found struct `std::ops::RangeFull` + | expected reference, found struct `RangeFull` | help: consider borrowing here: `&(..)` | = note: expected reference `&_` - found struct `std::ops::RangeFull` + found struct `RangeFull` error[E0308]: mismatched types --> $DIR/issue-54505.rs:29:16 @@ -40,11 +40,11 @@ error[E0308]: mismatched types LL | take_range(0..=1); | ^^^^^ | | - | expected reference, found struct `std::ops::RangeInclusive` + | expected reference, found struct `RangeInclusive` | help: consider borrowing here: `&(0..=1)` | = note: expected reference `&_` - found struct `std::ops::RangeInclusive<{integer}>` + found struct `RangeInclusive<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505.rs:34:16 @@ -52,11 +52,11 @@ error[E0308]: mismatched types LL | take_range(..5); | ^^^ | | - | expected reference, found struct `std::ops::RangeTo` + | expected reference, found struct `RangeTo` | help: consider borrowing here: `&(..5)` | = note: expected reference `&_` - found struct `std::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505.rs:39:16 @@ -64,11 +64,11 @@ error[E0308]: mismatched types LL | take_range(..=42); | ^^^^^ | | - | expected reference, found struct `std::ops::RangeToInclusive` + | expected reference, found struct `RangeToInclusive` | help: consider borrowing here: `&(..=42)` | = note: expected reference `&_` - found struct `std::ops::RangeToInclusive<{integer}>` + found struct `RangeToInclusive<{integer}>` error: aborting due to 6 previous errors diff --git a/src/test/ui/range/range-1.rs b/src/test/ui/range/range-1.rs index f13787b1d6..192426fe22 100644 --- a/src/test/ui/range/range-1.rs +++ b/src/test/ui/range/range-1.rs @@ -7,7 +7,7 @@ pub fn main() { // Bool => does not implement iterator. for i in false..true {} - //~^ ERROR `bool: std::iter::Step` is not satisfied + //~^ ERROR `bool: Step` is not satisfied // Unsized type. let arr: &[_] = &[1, 2, 3]; diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr index 11cb72fa2b..a7557320fa 100644 --- a/src/test/ui/range/range-1.stderr +++ b/src/test/ui/range/range-1.stderr @@ -4,13 +4,13 @@ error[E0308]: mismatched types LL | let _ = 0u32..10i32; | ^^^^^ expected `u32`, found `i32` -error[E0277]: the trait bound `bool: std::iter::Step` is not satisfied +error[E0277]: the trait bound `bool: Step` is not satisfied --> $DIR/range-1.rs:9:14 | LL | for i in false..true {} - | ^^^^^^^^^^^ the trait `std::iter::Step` is not implemented for `bool` + | ^^^^^^^^^^^ the trait `Step` is not implemented for `bool` | - = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::ops::Range` + = note: required because of the requirements on the impl of `Iterator` for `std::ops::Range` error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time --> $DIR/range-1.rs:14:17 @@ -21,9 +21,9 @@ LL | let range = *arr..; ::: $SRC_DIR/core/src/ops/range.rs:LL:COL | LL | pub struct RangeFrom { - | --- required by this bound in `std::ops::RangeFrom` + | --- required by this bound in `RangeFrom` | - = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` + = help: the trait `Sized` is not implemented for `[{integer}]` error: aborting due to 3 previous errors diff --git a/src/test/ui/range/range_traits-1.stderr b/src/test/ui/range/range_traits-1.stderr index 0e1da3d3f7..165fcd415c 100644 --- a/src/test/ui/range/range_traits-1.stderr +++ b/src/test/ui/range/range_traits-1.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -54,7 +54,7 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -64,7 +64,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -74,7 +74,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -84,7 +84,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -94,7 +94,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -104,7 +104,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -114,7 +114,7 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -124,7 +124,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -134,7 +134,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -144,7 +144,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -154,7 +154,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -164,7 +164,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -174,7 +174,7 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -184,7 +184,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -194,7 +194,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -204,7 +204,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -214,7 +214,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -224,7 +224,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -234,7 +234,7 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -244,7 +244,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -254,7 +254,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -264,7 +264,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -274,7 +274,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -284,7 +284,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -294,60 +294,60 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::Range: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::Range: Ord` is not satisfied --> $DIR/range_traits-1.rs:5:5 | LL | a: Range, - | ^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::Range` + | ^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::Range` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeTo: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeTo: Ord` is not satisfied --> $DIR/range_traits-1.rs:12:5 | LL | b: RangeTo, - | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeTo` + | ^^^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeTo` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeFrom: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeFrom: Ord` is not satisfied --> $DIR/range_traits-1.rs:19:5 | LL | c: RangeFrom, - | ^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeFrom` + | ^^^^^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeFrom` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeFull: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeFull: Ord` is not satisfied --> $DIR/range_traits-1.rs:26:5 | LL | d: RangeFull, - | ^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeFull` + | ^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeFull` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeInclusive: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeInclusive: Ord` is not satisfied --> $DIR/range_traits-1.rs:33:5 | LL | e: RangeInclusive, - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeInclusive` + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeInclusive` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeToInclusive: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeToInclusive: Ord` is not satisfied --> $DIR/range_traits-1.rs:40:5 | LL | f: RangeToInclusive, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeToInclusive` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeToInclusive` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/realloc-16687.rs b/src/test/ui/realloc-16687.rs index bdcd47a726..2e07fdcbe8 100644 --- a/src/test/ui/realloc-16687.rs +++ b/src/test/ui/realloc-16687.rs @@ -48,7 +48,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?}) = {:?}", layout, ptr); } - ptr.as_non_null_ptr().as_ptr() + ptr.as_mut_ptr() } unsafe fn deallocate(ptr: *mut u8, layout: Layout) { @@ -65,23 +65,17 @@ unsafe fn test_triangle() -> bool { } let memory = if new.size() > old.size() { - Global.grow( - NonNull::new_unchecked(ptr), - old, - new.size(), - ) + Global.grow(NonNull::new_unchecked(ptr), old, new) } else { - Global.shrink(NonNull::new_unchecked(ptr), old, new.size()) + Global.shrink(NonNull::new_unchecked(ptr), old, new) }; - let ptr = memory.unwrap_or_else(|_| { - handle_alloc_error(Layout::from_size_align_unchecked(new.size(), old.align())) - }); + let ptr = memory.unwrap_or_else(|_| handle_alloc_error(new)); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, ptr); } - ptr.as_non_null_ptr().as_ptr() + ptr.as_mut_ptr() } fn idx_to_size(i: usize) -> usize { diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs index d9996b80ac..658def0ad5 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs @@ -2,7 +2,9 @@ // no free regions or type parameters. // Codegen however, has to error for the infinitely many `drop_in_place` // functions it has been asked to create. + // build-fail +// normalize-stderr-test: ".nll/" -> "/" struct S { t: T, diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index 72547fe79f..5bf381607c 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,26 +1,15 @@ -error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::...)))))))))))))))))))))))))))))>))` +error: reached the recursion limit while instantiating `drop_in_place::))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { -LL | | // Code here does not matter - this is replaced by the -LL | | // real drop glue by the compiler. -LL | | -LL | | // SAFETY: see comment above -LL | | unsafe { drop_in_place(to_drop) } -LL | | } - | |_^ +LL | pub unsafe fn drop_in_place(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: `std::intrinsics::drop_in_place` defined here +note: `drop_in_place` defined here --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { -LL | | // Code here does not matter - this is replaced by the -LL | | // real drop glue by the compiler. -LL | | -LL | | // SAFETY: see comment above -LL | | unsafe { drop_in_place(to_drop) } -LL | | } - | |_^ +LL | pub unsafe fn drop_in_place(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-38591-non-regular-dropck-recursion/issue-38591-non-regular-dropck-recursion.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/recursion/recursion.rs b/src/test/ui/recursion/recursion.rs index 373cc17d0e..b3ba0ec3a2 100644 --- a/src/test/ui/recursion/recursion.rs +++ b/src/test/ui/recursion/recursion.rs @@ -1,5 +1,6 @@ // build-fail // compile-flags:-C overflow-checks=off +// normalize-stderr-test: ".nll/" -> "/" enum Nil {NilValue} struct Cons {head:isize, tail:T} diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index 085bf82ef8..d2844d0e6d 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/recursion.rs:17:11 + --> $DIR/recursion.rs:18:11 | LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `test` defined here - --> $DIR/recursion.rs:15:1 + --> $DIR/recursion.rs:16:1 | LL | fn test (n:isize, i:isize, first:T, second:T) ->isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/recursion/recursion.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/recursion/recursive-requirements.stderr b/src/test/ui/recursion/recursive-requirements.stderr index 0237675aee..6c0be0f7f8 100644 --- a/src/test/ui/recursion/recursive-requirements.stderr +++ b/src/test/ui/recursion/recursive-requirements.stderr @@ -7,7 +7,7 @@ LL | struct AssertSync(PhantomData); LL | let _: AssertSync = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Bar` cannot be shared between threads safely | - = help: within `Foo`, the trait `std::marker::Sync` is not implemented for `*const Bar` + = help: within `Foo`, the trait `Sync` is not implemented for `*const Bar` = note: required because it appears within the type `Foo` error[E0277]: `*const Foo` cannot be shared between threads safely @@ -19,9 +19,9 @@ LL | struct AssertSync(PhantomData); LL | let _: AssertSync = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Foo` cannot be shared between threads safely | - = help: within `Foo`, the trait `std::marker::Sync` is not implemented for `*const Foo` + = help: within `Foo`, the trait `Sync` is not implemented for `*const Foo` = note: required because it appears within the type `Bar` - = note: required because it appears within the type `std::marker::PhantomData` + = note: required because it appears within the type `PhantomData` = note: required because it appears within the type `Foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/recursion/recursive-static-definition.rs b/src/test/ui/recursion/recursive-static-definition.rs index e816ce4e0c..f59ef7316d 100644 --- a/src/test/ui/recursion/recursive-static-definition.rs +++ b/src/test/ui/recursion/recursive-static-definition.rs @@ -1,4 +1,4 @@ pub static FOO: u32 = FOO; -//~^ ERROR cycle detected when const-evaluating `FOO` +//~^ ERROR cycle detected when const-evaluating + checking `FOO` fn main() {} diff --git a/src/test/ui/recursion/recursive-static-definition.stderr b/src/test/ui/recursion/recursive-static-definition.stderr index 093606e100..ee73b026a0 100644 --- a/src/test/ui/recursion/recursive-static-definition.stderr +++ b/src/test/ui/recursion/recursive-static-definition.stderr @@ -1,20 +1,16 @@ -error[E0391]: cycle detected when const-evaluating `FOO` +error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-static-definition.rs:1:1 | LL | pub static FOO: u32 = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `FOO`... - --> $DIR/recursive-static-definition.rs:1:1 - | -LL | pub static FOO: u32 = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `FOO` +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-static-definition.rs:1:1 | LL | pub static FOO: u32 = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/ref-suggestion.rs b/src/test/ui/ref-suggestion.rs index 49d199cd9e..346d118f0f 100644 --- a/src/test/ui/ref-suggestion.rs +++ b/src/test/ui/ref-suggestion.rs @@ -13,5 +13,5 @@ fn main() { (Some(y), ()) => {}, _ => {}, } - x; //~ ERROR use of moved value + x; //~ ERROR use of partially moved value } diff --git a/src/test/ui/ref-suggestion.stderr b/src/test/ui/ref-suggestion.stderr index 97d2c174d9..332dbb79cf 100644 --- a/src/test/ui/ref-suggestion.stderr +++ b/src/test/ui/ref-suggestion.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/ref-suggestion.rs:4:5 | LL | let x = vec![1]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | let y = x; | - value moved here LL | x; @@ -12,22 +12,22 @@ error[E0382]: use of moved value: `x` --> $DIR/ref-suggestion.rs:8:5 | LL | let x = vec![1]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | let mut y = x; | - value moved here LL | x; | ^ value used here after move -error[E0382]: use of moved value: `x` +error[E0382]: use of partially moved value: `x` --> $DIR/ref-suggestion.rs:16:5 | LL | (Some(y), ()) => {}, - | - value moved here + | - value partially moved here ... LL | x; | ^ value used here after partial move | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `Vec`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `x.0.0` | LL | (Some(ref y), ()) => {}, diff --git a/src/test/ui/regions/issue-78262.default.stderr b/src/test/ui/regions/issue-78262.default.stderr new file mode 100644 index 0000000000..e97b8eca94 --- /dev/null +++ b/src/test/ui/regions/issue-78262.default.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/issue-78262.rs:12:28 + | +LL | let f = |x: &dyn TT| x.func(); + | ^^^^ lifetime mismatch + | + = note: expected reference `&(dyn TT + 'static)` + found reference `&dyn TT` +note: the anonymous lifetime #1 defined on the body at 12:13... + --> $DIR/issue-78262.rs:12:13 + | +LL | let f = |x: &dyn TT| x.func(); + | ^^^^^^^^^^^^^^^^^^^^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/issue-78262.nll.stderr b/src/test/ui/regions/issue-78262.nll.stderr new file mode 100644 index 0000000000..4607dbad42 --- /dev/null +++ b/src/test/ui/regions/issue-78262.nll.stderr @@ -0,0 +1,10 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/issue-78262.rs:12:26 + | +LL | let f = |x: &dyn TT| x.func(); + | - ^^^^^^^^ `x` escapes the closure body here + | | + | `x` is a reference that is only valid in the closure body + +error: aborting due to previous error + diff --git a/src/test/ui/regions/issue-78262.rs b/src/test/ui/regions/issue-78262.rs new file mode 100644 index 0000000000..0bdb0abac3 --- /dev/null +++ b/src/test/ui/regions/issue-78262.rs @@ -0,0 +1,14 @@ +// revisions: nll default +// ignore-compare-mode-nll +//[nll]compile-flags: -Z borrowck=mir + +trait TT {} + +impl dyn TT { + fn func(&self) {} +} + +fn main() { + let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types + //[nll]~^ ERROR: borrowed data escapes outside of closure +} diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr index 22586b5de9..1fff85e766 100644 --- a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr +++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr @@ -27,7 +27,7 @@ error[E0392]: parameter `'c` is never used LL | struct Foo<'a,'b,'c> { | ^^ unused parameter | - = help: consider removing `'c`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'c`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 3 previous errors diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 63fea1f416..3607d6a722 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -74,8 +74,8 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn Foo + 'b)>` - found `std::boxed::Box` + = note: expected `Box<(dyn Foo + 'b)>` + found `Box` error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr index c72d6483c2..930bf608ac 100644 --- a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr +++ b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr @@ -22,7 +22,7 @@ LL | assert_send::<&'a [isize]>(); | = note: type must satisfy the static lifetime -error[E0477]: the type `std::boxed::Box<&'a isize>` does not fulfill the required lifetime +error[E0477]: the type `Box<&'a isize>` does not fulfill the required lifetime --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5 | LL | assert_send::>(); diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.stderr b/src/test/ui/regions/regions-close-associated-type-into-object.stderr index 9303e0f8e6..536a1b5e35 100644 --- a/src/test/ui/regions/regions-close-associated-type-into-object.stderr +++ b/src/test/ui/regions/regions-close-associated-type-into-object.stderr @@ -14,7 +14,7 @@ LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'static`... - = note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds + = note: ...so that the type `Box<::Item>` will meet its required lifetime bounds error[E0309]: the associated type `::Item` may not live long enough --> $DIR/regions-close-associated-type-into-object.rs:28:5 @@ -32,7 +32,7 @@ LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'a`... - = note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds + = note: ...so that the type `Box<::Item>` will meet its required lifetime bounds error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index aab7ce993a..da995a9631 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -12,8 +12,8 @@ LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ^^ help: alternatively, add an explicit `'static` bound to this reference | -LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A + 'static)>) -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn g<'a, T: 'static>(v: Box<(dyn A + 'static)>) -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 90f807a41c..7dc880849a 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -12,8 +12,8 @@ LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ^^ help: alternatively, add an explicit `'static` bound to this reference | -LL | fn i<'a, T, U>(v: std::boxed::Box<(dyn A + 'static)>) -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn i<'a, T, U>(v: Box<(dyn A + 'static)>) -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr index 2070ce257b..0cce89215d 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr @@ -24,8 +24,8 @@ note: ...so that the expression is assignable | LL | box v as Box | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>` - found `std::boxed::Box` + = note: expected `Box<(dyn SomeTrait + 'c)>` + found `Box` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-param-into-object.stderr b/src/test/ui/regions/regions-close-param-into-object.stderr index 705d21078e..5c355bbb73 100644 --- a/src/test/ui/regions/regions-close-param-into-object.stderr +++ b/src/test/ui/regions/regions-close-param-into-object.stderr @@ -14,7 +14,7 @@ LL | fn p2(v: Box) -> Box | - help: consider adding an explicit lifetime bound...: `T: 'static` ... LL | Box::new(v) - | ^^^^^^^^^^^ ...so that the type `std::boxed::Box` will meet its required lifetime bounds + | ^^^^^^^^^^^ ...so that the type `Box` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:18:5 @@ -32,7 +32,7 @@ LL | fn p4<'a,T>(v: Box) -> Box | - help: consider adding an explicit lifetime bound...: `T: 'a` ... LL | Box::new(v) - | ^^^^^^^^^^^ ...so that the type `std::boxed::Box` will meet its required lifetime bounds + | ^^^^^^^^^^^ ...so that the type `Box` will meet its required lifetime bounds error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr index a86e6ccdc5..afabdc1de1 100644 --- a/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr +++ b/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr @@ -5,7 +5,7 @@ LL | impl<'a> SetF<'a> for C<'a> { | -- lifetime `'a` defined here ... LL | fn set_f_bad(&mut self, b: Box) { - | - has type `std::boxed::Box>` + | - has type `Box>` LL | self.f = b; | ^^^^^^ assignment requires that `'1` must outlive `'a` diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.rs b/src/test/ui/regions/regions-infer-paramd-indirect.rs index beb88e81bc..3b18bbf1df 100644 --- a/src/test/ui/regions/regions-infer-paramd-indirect.rs +++ b/src/test/ui/regions/regions-infer-paramd-indirect.rs @@ -21,8 +21,8 @@ impl<'a> SetF<'a> for C<'a> { fn set_f_bad(&mut self, b: Box) { self.f = b; //~^ ERROR mismatched types - //~| expected struct `std::boxed::Box>` - //~| found struct `std::boxed::Box>` + //~| expected struct `Box>` + //~| found struct `Box>` //~| lifetime mismatch } } diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.stderr index 3e196cf8f1..620b25c9e0 100644 --- a/src/test/ui/regions/regions-infer-paramd-indirect.stderr +++ b/src/test/ui/regions/regions-infer-paramd-indirect.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | self.f = b; | ^ lifetime mismatch | - = note: expected struct `std::boxed::Box>` - found struct `std::boxed::Box>` + = note: expected struct `Box>` + found struct `Box>` note: the anonymous lifetime #2 defined on the method body at 21:5... --> $DIR/regions-infer-paramd-indirect.rs:21:5 | diff --git a/src/test/ui/reify-intrinsic.stderr b/src/test/ui/reify-intrinsic.stderr index c4eee0f466..675447f972 100644 --- a/src/test/ui/reify-intrinsic.stderr +++ b/src/test/ui/reify-intrinsic.stderr @@ -7,13 +7,13 @@ LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr | expected due to this | = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize` - found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` help: use parentheses to call this function | LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute(...); | ^^^^^ -error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid +error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid --> $DIR/reify-intrinsic.rs:11:13 | LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; diff --git a/src/test/ui/repeat-to-run-dtor-twice.rs b/src/test/ui/repeat-to-run-dtor-twice.rs index d857178166..0cd8eceefc 100644 --- a/src/test/ui/repeat-to-run-dtor-twice.rs +++ b/src/test/ui/repeat-to-run-dtor-twice.rs @@ -15,5 +15,5 @@ impl Drop for Foo { fn main() { let a = Foo { x: 3 }; let _ = [ a; 5 ]; - //~^ ERROR the trait bound `Foo: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Foo: Copy` is not satisfied [E0277] } diff --git a/src/test/ui/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-to-run-dtor-twice.stderr index 5434f6cef5..f07bbe3b9f 100644 --- a/src/test/ui/repeat-to-run-dtor-twice.stderr +++ b/src/test/ui/repeat-to-run-dtor-twice.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Foo: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/repeat-to-run-dtor-twice.rs:17:13 | LL | let _ = [ a; 5 ]; - | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Foo` + | ^^^^^^^^ the trait `Copy` is not implemented for `Foo` | = note: the `Copy` trait is required because the repeated element will be copied diff --git a/src/test/ui/repeat_count.rs b/src/test/ui/repeat_count.rs index 7e30491f0b..96abff4ab4 100644 --- a/src/test/ui/repeat_count.rs +++ b/src/test/ui/repeat_count.rs @@ -30,5 +30,5 @@ fn main() { } let g = [0; G { g: () }]; //~^ ERROR mismatched types - //~| expected `usize`, found struct `main::G` + //~| expected `usize`, found struct `G` } diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr index 2eab3ebc76..5fcda348ab 100644 --- a/src/test/ui/repeat_count.stderr +++ b/src/test/ui/repeat_count.stderr @@ -32,7 +32,7 @@ error[E0308]: mismatched types --> $DIR/repeat_count.rs:31:17 | LL | let g = [0; G { g: () }]; - | ^^^^^^^^^^^ expected `usize`, found struct `main::G` + | ^^^^^^^^^^^ expected `usize`, found struct `G` error[E0308]: mismatched types --> $DIR/repeat_count.rs:19:17 diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 4ed93ad327..5078ffbec7 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `(dyn I + 'static)` cannot be known at LL | fn foo(_x: K) {} | ^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn I + 'static)` + = help: the trait `Sized` is not implemented for `(dyn I + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/resolve/issue-54379.stderr b/src/test/ui/resolve/issue-54379.stderr index 2a6b54572d..750727273e 100644 --- a/src/test/ui/resolve/issue-54379.stderr +++ b/src/test/ui/resolve/issue-54379.stderr @@ -8,10 +8,12 @@ LL | MyStruct { .., Some(_) } => {}, | `..` must be at the end and cannot have a trailing comma error: expected `,` - --> $DIR/issue-54379.rs:9:24 + --> $DIR/issue-54379.rs:9:28 | LL | MyStruct { .., Some(_) } => {}, - | ^^^^ + | -------- ^ + | | + | while parsing the fields for this pattern error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr index a324d04d39..9b59e41501 100644 --- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr +++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr @@ -57,7 +57,7 @@ LL | async fn associated(); | expected `()`, found opaque type | = note: expected fn pointer `fn()` - found fn pointer `fn() -> impl std::future::Future` + found fn pointer `fn() -> impl Future` error: aborting due to 6 previous errors diff --git a/src/test/ui/resolve/name-clash-nullary.stderr b/src/test/ui/resolve/name-clash-nullary.stderr index 2de0b6a496..76c4b5914c 100644 --- a/src/test/ui/resolve/name-clash-nullary.stderr +++ b/src/test/ui/resolve/name-clash-nullary.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | let None: isize = 42; | ^^^^ ----- expected due to this | | - | expected `isize`, found enum `std::option::Option` + | expected `isize`, found enum `Option` | = note: expected type `isize` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to previous error diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index f1ed7aaa86..32eff15119 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -260,15 +260,15 @@ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:27:20 | LL | Fn(u8), - | ------ fn(u8) -> m::n::Z {m::n::Z::Fn} defined here + | ------ fn(u8) -> Z {Z::Fn} defined here ... LL | let _: Z = Z::Fn; - | - ^^^^^ expected enum `m::n::Z`, found fn item + | - ^^^^^ expected enum `Z`, found fn item | | | expected due to this | - = note: expected enum `m::n::Z` - found fn item `fn(u8) -> m::n::Z {m::n::Z::Fn}` + = note: expected enum `Z` + found fn item `fn(u8) -> Z {Z::Fn}` help: use parentheses to instantiate this tuple variant | LL | let _: Z = Z::Fn(_); @@ -294,15 +294,15 @@ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:43:16 | LL | Fn(u8), - | ------ fn(u8) -> m::E {m::E::Fn} defined here + | ------ fn(u8) -> E {E::Fn} defined here ... LL | let _: E = m::E::Fn; - | - ^^^^^^^^ expected enum `m::E`, found fn item + | - ^^^^^^^^ expected enum `E`, found fn item | | | expected due to this | - = note: expected enum `m::E` - found fn item `fn(u8) -> m::E {m::E::Fn}` + = note: expected enum `E` + found fn item `fn(u8) -> E {E::Fn}` help: use parentheses to instantiate this tuple variant | LL | let _: E = m::E::Fn(_); @@ -328,15 +328,15 @@ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:51:16 | LL | Fn(u8), - | ------ fn(u8) -> m::E {m::E::Fn} defined here + | ------ fn(u8) -> E {E::Fn} defined here ... LL | let _: E = E::Fn; - | - ^^^^^ expected enum `m::E`, found fn item + | - ^^^^^ expected enum `E`, found fn item | | | expected due to this | - = note: expected enum `m::E` - found fn item `fn(u8) -> m::E {m::E::Fn}` + = note: expected enum `E` + found fn item `fn(u8) -> E {E::Fn}` help: use parentheses to instantiate this tuple variant | LL | let _: E = E::Fn(_); diff --git a/src/test/ui/resolve/use_suggestion.stderr b/src/test/ui/resolve/use_suggestion.stderr index 72dda94072..4fff179b1f 100644 --- a/src/test/ui/resolve/use_suggestion.stderr +++ b/src/test/ui/resolve/use_suggestion.stderr @@ -1,10 +1,10 @@ -error[E0433]: failed to resolve: use of undeclared type or module `GooMap` +error[E0433]: failed to resolve: use of undeclared type `GooMap` --> $DIR/use_suggestion.rs:3:14 | LL | let x2 = GooMap::new(); - | ^^^^^^ use of undeclared type or module `GooMap` + | ^^^^^^ use of undeclared type `GooMap` -error[E0433]: failed to resolve: use of undeclared type or module `HashMap` +error[E0433]: failed to resolve: use of undeclared type `HashMap` --> $DIR/use_suggestion.rs:2:14 | LL | let x1 = HashMap::new(); diff --git a/src/test/ui/retslot-cast.stderr b/src/test/ui/retslot-cast.stderr index cdef304cdc..9b5f11ce66 100644 --- a/src/test/ui/retslot-cast.stderr +++ b/src/test/ui/retslot-cast.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/retslot-cast.rs:13:5 | LL | inner(x) - | ^^^^^^^^ expected trait `std::iter::Iterator`, found trait `std::iter::Iterator + std::marker::Send` + | ^^^^^^^^ expected trait `Iterator`, found trait `Iterator + Send` | - = note: expected enum `std::option::Option<&dyn std::iter::Iterator>` - found enum `std::option::Option<&dyn std::iter::Iterator + std::marker::Send>` + = note: expected enum `Option<&dyn Iterator>` + found enum `Option<&dyn Iterator + Send>` error: aborting due to previous error diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr index 7becd01324..6c3d1caf80 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `v` in pattern guard --> $DIR/rfc-reject-double-move-across-arms.rs:5:36 | LL | VecWrapper::A(v) if { drop(v); false } => 1, - | ^ move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^ move occurs because `v` has type `Vec`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr index b93e721906..d1204bc260 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `v` in pattern guard --> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30 | LL | A { a: v } if { drop(v); true } => v, - | ^ move occurs because `v` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `v` has type `Box`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs index 8f65144b14..3b60cbc578 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs @@ -1,3 +1,3 @@ // Tests that an `impl Trait` that is not `impl Termination` will not work. fn main() -> impl Copy { } -//~^ ERROR `main` has invalid return type `impl std::marker::Copy` +//~^ ERROR `main` has invalid return type `impl Copy` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr index 8a718183a8..5ee6d127e8 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr @@ -1,8 +1,8 @@ -error[E0277]: `main` has invalid return type `impl std::marker::Copy` +error[E0277]: `main` has invalid return type `impl Copy` --> $DIR/termination-trait-impl-trait.rs:2:14 | LL | fn main() -> impl Copy { } - | ^^^^^^^^^ `main` can only return types that implement `std::process::Termination` + | ^^^^^^^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.rs index 09bd1c8492..10f7d2215c 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -1,6 +1,6 @@ fn main() -> i32 { //~^ ERROR `main` has invalid return type `i32` -//~| NOTE `main` can only return types that implement `std::process::Termination` +//~| NOTE `main` can only return types that implement `Termination` //~| HELP consider using `()`, or a `Result` 0 } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.stderr index e88e3d884e..53779d365f 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.stderr @@ -2,7 +2,7 @@ error[E0277]: `main` has invalid return type `i32` --> $DIR/termination-trait-main-i32.rs:1:14 | LL | fn main() -> i32 { - | ^^^ `main` can only return types that implement `std::process::Termination` + | ^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr index 31b90340d7..bc8fd92ce5 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -2,7 +2,7 @@ error[E0277]: `main` has invalid return type `char` --> $DIR/termination-trait-main-wrong-type.rs:1:14 | LL | fn main() -> char { - | ^^^^ `main` can only return types that implement `std::process::Termination` + | ^^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr index 72a58a0417..cb329548d8 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr @@ -2,7 +2,7 @@ error[E0277]: `main` has invalid return type `ReturnType` --> $DIR/termination-trait-not-satisfied.rs:3:14 | LL | fn main() -> ReturnType { - | ^^^^^^^^^^ `main` can only return types that implement `std::process::Termination` + | ^^^^^^^^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr index d28232515f..d015b72c5c 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -1,17 +1,17 @@ -error[E0277]: `main` has invalid return type `std::result::Result` +error[E0277]: `main` has invalid return type `std::result::Result` --> $DIR/termination-trait-test-wrong-type.rs:6:1 | LL | / fn can_parse_zero_as_f32() -> Result { LL | | "0".parse() LL | | } - | |_^ `main` can only return types that implement `std::process::Termination` + | |_^ `main` can only return types that implement `Termination` | ::: $SRC_DIR/test/src/lib.rs:LL:COL | LL | pub fn assert_test_result(result: T) { - | ----------- required by this bound in `test::assert_test_result` + | ----------- required by this bound in `assert_test_result` | - = help: the trait `std::process::Termination` is not implemented for `std::result::Result` + = help: the trait `Termination` is not implemented for `std::result::Result` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs index 802f20b4be..73e0b98296 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs @@ -4,7 +4,7 @@ extern crate enums; use enums::{EmptyNonExhaustiveEnum, NonExhaustiveEnum}; fn empty(x: EmptyNonExhaustiveEnum) { - match x {} //~ ERROR type `enums::EmptyNonExhaustiveEnum` is non-empty + match x {} //~ ERROR type `EmptyNonExhaustiveEnum` is non-empty match x { _ => {}, // ok } diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr index 28e450336f..1d1c43c9e8 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr @@ -1,11 +1,11 @@ -error[E0004]: non-exhaustive patterns: type `enums::EmptyNonExhaustiveEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `EmptyNonExhaustiveEnum` is non-empty --> $DIR/enum.rs:7:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `enums::EmptyNonExhaustiveEnum` + = note: the matched value is of type `EmptyNonExhaustiveEnum` error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/enum.rs:16:11 @@ -14,7 +14,7 @@ LL | match enum_unit { | ^^^^^^^^^ pattern `_` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `enums::NonExhaustiveEnum` + = note: the matched value is of type `NonExhaustiveEnum` error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/enum.rs:23:11 @@ -23,7 +23,7 @@ LL | match enum_unit {}; | ^^^^^^^^^ pattern `_` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `enums::NonExhaustiveEnum` + = note: the matched value is of type `NonExhaustiveEnum` error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs index 900b9333f7..5feb9c98e9 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs @@ -10,15 +10,15 @@ use types::{NonExhaustiveEnum, NormalStruct, UnitStruct, TupleStruct, NonExhaust extern { pub fn non_exhaustive_enum(_: NonExhaustiveEnum); - //~^ ERROR `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe + //~^ ERROR `extern` block uses type `NonExhaustiveEnum`, which is not FFI-safe pub fn non_exhaustive_normal_struct(_: NormalStruct); - //~^ ERROR `extern` block uses type `types::NormalStruct`, which is not FFI-safe + //~^ ERROR `extern` block uses type `NormalStruct`, which is not FFI-safe pub fn non_exhaustive_unit_struct(_: UnitStruct); - //~^ ERROR `extern` block uses type `types::UnitStruct`, which is not FFI-safe + //~^ ERROR `extern` block uses type `UnitStruct`, which is not FFI-safe pub fn non_exhaustive_tuple_struct(_: TupleStruct); - //~^ ERROR `extern` block uses type `types::TupleStruct`, which is not FFI-safe + //~^ ERROR `extern` block uses type `TupleStruct`, which is not FFI-safe pub fn non_exhaustive_variant(_: NonExhaustiveVariants); - //~^ ERROR `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe + //~^ ERROR `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe } fn main() { } diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr index 4956226712..8a18ebc16f 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr @@ -1,4 +1,4 @@ -error: `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe +error: `extern` block uses type `NonExhaustiveEnum`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:12:35 | LL | pub fn non_exhaustive_enum(_: NonExhaustiveEnum); @@ -11,7 +11,7 @@ LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ = note: this enum is non-exhaustive -error: `extern` block uses type `types::NormalStruct`, which is not FFI-safe +error: `extern` block uses type `NormalStruct`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:14:44 | LL | pub fn non_exhaustive_normal_struct(_: NormalStruct); @@ -19,7 +19,7 @@ LL | pub fn non_exhaustive_normal_struct(_: NormalStruct); | = note: this struct is non-exhaustive -error: `extern` block uses type `types::UnitStruct`, which is not FFI-safe +error: `extern` block uses type `UnitStruct`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:16:42 | LL | pub fn non_exhaustive_unit_struct(_: UnitStruct); @@ -27,7 +27,7 @@ LL | pub fn non_exhaustive_unit_struct(_: UnitStruct); | = note: this struct is non-exhaustive -error: `extern` block uses type `types::TupleStruct`, which is not FFI-safe +error: `extern` block uses type `TupleStruct`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:18:43 | LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct); @@ -35,7 +35,7 @@ LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct); | = note: this struct is non-exhaustive -error: `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe +error: `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:20:38 | LL | pub fn non_exhaustive_variant(_: NonExhaustiveVariants); diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr index d2d319f50c..f8ed156b57 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { | - expected `A` because of return type LL | x - | ^ expected struct `A`, found enum `uninhabited::UninhabitedEnum` + | ^ expected struct `A`, found enum `UninhabitedEnum` error[E0308]: mismatched types --> $DIR/coercions.rs:27:5 @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { | - expected `A` because of return type LL | x - | ^ expected struct `A`, found struct `uninhabited::UninhabitedTupleStruct` + | ^ expected struct `A`, found struct `UninhabitedTupleStruct` error[E0308]: mismatched types --> $DIR/coercions.rs:31:5 @@ -20,7 +20,7 @@ error[E0308]: mismatched types LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { | - expected `A` because of return type LL | x - | ^ expected struct `A`, found struct `uninhabited::UninhabitedStruct` + | ^ expected struct `A`, found struct `UninhabitedStruct` error[E0308]: mismatched types --> $DIR/coercions.rs:35:5 @@ -28,7 +28,7 @@ error[E0308]: mismatched types LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { | - expected `A` because of return type LL | x - | ^ expected struct `A`, found enum `uninhabited::UninhabitedVariants` + | ^ expected struct `A`, found enum `UninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr index bd136333b7..c461302a36 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr @@ -1,38 +1,38 @@ -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty --> $DIR/indirect_match.rs:19:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedEnum` + = note: the matched value is of type `IndirectUninhabitedEnum` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty --> $DIR/indirect_match.rs:23:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedStruct` + = note: the matched value is of type `IndirectUninhabitedStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty --> $DIR/indirect_match.rs:27:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedTupleStruct` + = note: the matched value is of type `IndirectUninhabitedTupleStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty --> $DIR/indirect_match.rs:33:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedVariants` + = note: the matched value is of type `IndirectUninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr index 5211b57726..c397158c02 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr @@ -1,38 +1,38 @@ -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedEnum` + = note: the matched value is of type `IndirectUninhabitedEnum` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedStruct` + = note: the matched value is of type `IndirectUninhabitedStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedTupleStruct` + = note: the matched value is of type `IndirectUninhabitedTupleStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedVariants` + = note: the matched value is of type `IndirectUninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr index 961b3e5673..1f981ba82d 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -1,29 +1,29 @@ -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty --> $DIR/match.rs:19:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedEnum` + = note: the matched value is of type `UninhabitedEnum` -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty --> $DIR/match.rs:23:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedStruct` + = note: the matched value is of type `UninhabitedStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty --> $DIR/match.rs:27:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedTupleStruct` + = note: the matched value is of type `UninhabitedTupleStruct` error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered --> $DIR/match.rs:31:11 @@ -39,7 +39,7 @@ LL | #[non_exhaustive] Struct { x: ! } | ------ not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedVariants` + = note: the matched value is of type `UninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr index c489edeb69..0ff1c01cbd 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -1,29 +1,29 @@ -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty --> $DIR/match_with_exhaustive_patterns.rs:22:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedEnum` + = note: the matched value is of type `UninhabitedEnum` -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty --> $DIR/match_with_exhaustive_patterns.rs:26:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedStruct` + = note: the matched value is of type `UninhabitedStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty --> $DIR/match_with_exhaustive_patterns.rs:30:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedTupleStruct` + = note: the matched value is of type `UninhabitedTupleStruct` error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered --> $DIR/match_with_exhaustive_patterns.rs:34:11 @@ -39,7 +39,7 @@ LL | #[non_exhaustive] Struct { x: ! } | ------ not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedVariants` + = note: the matched value is of type `UninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr index cf8ca57714..0291a52633 100644 --- a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr +++ b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr @@ -1,10 +1,27 @@ warning: skipping const checks | +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:9 + | +LL | let ptr: fn() -> L = attributed; + | ^^^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5 + | +LL | ptr() + | ^^^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:26 + | +LL | let ptr: fn() -> L = attributed; + | ^^^^^^^^^^ help: skipping check that does not even have a feature gate --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5 | LL | ptr() | ^^^^^ -warning: 1 warning emitted +error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/rfc-2093-infer-outlives/projection.stderr b/src/test/ui/rfc-2093-infer-outlives/projection.stderr index 3746bab4d5..840676e796 100644 --- a/src/test/ui/rfc-2093-infer-outlives/projection.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/projection.stderr @@ -6,7 +6,7 @@ LL | | bar: &'a T::Item LL | | } | |_^ | - = note: ::Item: 'a + = note: ::Item: 'a error: aborting due to previous error diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr index 6efc1176d0..dfa44008ad 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr @@ -1,4 +1,4 @@ -error[E0491]: in type `&'a rev_variant_struct_region::Foo<'b>`, reference has a longer lifetime than the data it references +error[E0491]: in type `&'a Foo<'b>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-region-rev.rs:17:9 | LL | type Out = &'a Foo<'b>; diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr index 06e5f24dec..3561379138 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr @@ -1,4 +1,4 @@ -error[E0491]: in type `&'a variant_struct_region::Foo<'b>`, reference has a longer lifetime than the data it references +error[E0491]: in type `&'a Foo<'b>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-region.rs:17:9 | LL | type Out = &'a Foo<'b>; diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr index d02f7b7962..207686defa 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr @@ -1,4 +1,4 @@ -error[E0491]: in type `&'a variant_struct_type::Foo<&'b i32>`, reference has a longer lifetime than the data it references +error[E0491]: in type `&'a Foo<&'b i32>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-type-rev.rs:17:9 | LL | type Out = &'a Foo<&'b i32>; diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr index 40c70f5324..c1c4e78f78 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr @@ -1,4 +1,4 @@ -error[E0491]: in type `&'a variant_struct_type::Foo<&'b i32>`, reference has a longer lifetime than the data it references +error[E0491]: in type `&'a Foo<&'b i32>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-type.rs:17:9 | LL | type Out = &'a Foo<&'b i32>; diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr index 64b920e9aa..8189157217 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `xcrate` --> $DIR/non-existent-1.rs:3:5 | LL | use xcrate::S; - | ^^^^^^ use of undeclared type or module `xcrate` + | ^^^^^^ use of undeclared crate or module `xcrate` error: aborting due to previous error diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr index bfce180789..bd6778cf3d 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `ycrate` --> $DIR/non-existent-3.rs:3:5 | LL | use ycrate; - | ^^^^^^ no `ycrate` external crate + | ^^^^^^ no external crate `ycrate` error: aborting due to previous error diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr index 6d2b4508a0..a66330ccc4 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `alloc` --> $DIR/not-allowed.rs:5:5 | LL | use alloc; - | ^^^^^ no `alloc` external crate + | ^^^^^ no external crate `alloc` error: aborting due to previous error diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs index bdde484c25..f2fb62d76f 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs @@ -3,5 +3,5 @@ struct NotDebug; fn main() { - let _: NotDebug = dbg!(NotDebug); //~ ERROR `NotDebug` doesn't implement `std::fmt::Debug` + let _: NotDebug = dbg!(NotDebug); //~ ERROR `NotDebug` doesn't implement `Debug` } diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 799a05bf7e..6d150b84dd 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -1,12 +1,12 @@ -error[E0277]: `NotDebug` doesn't implement `std::fmt::Debug` +error[E0277]: `NotDebug` doesn't implement `Debug` --> $DIR/dbg-macro-requires-debug.rs:6:23 | LL | let _: NotDebug = dbg!(NotDebug); | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `NotDebug` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&NotDebug` + = help: the trait `Debug` is not implemented for `NotDebug` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&NotDebug` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs index 71af704c69..25c7fe760d 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs @@ -40,11 +40,11 @@ fn nested_within_if_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { if let 0 = 0? {} - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } if (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` //~| ERROR the `?` operator can only be used in a function that returns `Result` if true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here @@ -104,11 +104,11 @@ fn nested_within_while_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { while let 0 = 0? {} - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } while (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` //~| ERROR the `?` operator can only be used in a function that returns `Result` while true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here @@ -177,12 +177,12 @@ fn outside_if_and_while_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { let 0 = 0?; - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } (let 0 = 0)?; //~ ERROR `let` expressions are not supported here //~^ ERROR the `?` operator can only be used in a function that returns `Result` - //~| ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~| ERROR the `?` operator can only be applied to values that implement `Try` true || let 0 = 0; //~ ERROR `let` expressions are not supported here (true || let 0 = 0); //~ ERROR `let` expressions are not supported here diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 7f343d1a85..d38a3aba46 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -537,16 +537,16 @@ error[E0600]: cannot apply unary operator `-` to type `bool` LL | if -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:46:8 | LL | if (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | - = help: the trait `std::ops::Try` is not implemented for `bool` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `bool` + = note: required by `into_result` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/disallowed-positions.rs:46:8 | LL | / fn nested_within_if_expr() { @@ -561,17 +561,19 @@ LL | | if let true = let true = true {} LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:56:8 | LL | if x = let 0 = 0 {} - | ^^^^^^^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == let 0 = 0` + | ^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | if x == let 0 = 0 {} + | ^^ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:59:8 @@ -586,19 +588,19 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:61:8 | LL | if ..(let 0 = 0) {} - | ^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::RangeTo` + | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` | = note: expected type `bool` - found struct `std::ops::RangeTo` + found struct `RangeTo` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:63:8 | LL | if (let 0 = 0).. {} - | ^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::RangeFrom` + | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` | = note: expected type `bool` - found struct `std::ops::RangeFrom` + found struct `RangeFrom` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:67:12 @@ -693,14 +695,14 @@ LL | if let Range { start: true, end } = t..&&false {} = note: expected type `bool` found struct `std::ops::Range` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:42:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `into_result` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:96:11 @@ -723,16 +725,16 @@ error[E0600]: cannot apply unary operator `-` to type `bool` LL | while -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:110:11 | LL | while (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | - = help: the trait `std::ops::Try` is not implemented for `bool` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `bool` + = note: required by `into_result` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/disallowed-positions.rs:110:11 | LL | / fn nested_within_while_expr() { @@ -747,17 +749,19 @@ LL | | while let true = let true = true {} LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:120:11 | LL | while x = let 0 = 0 {} - | ^^^^^^^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == let 0 = 0` + | ^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | while x == let 0 = 0 {} + | ^^ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:123:11 @@ -772,19 +776,19 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:125:11 | LL | while ..(let 0 = 0) {} - | ^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::RangeTo` + | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` | = note: expected type `bool` - found struct `std::ops::RangeTo` + found struct `RangeTo` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:127:11 | LL | while (let 0 = 0).. {} - | ^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::RangeFrom` + | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` | = note: expected type `bool` - found struct `std::ops::RangeFrom` + found struct `RangeFrom` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:131:15 @@ -879,14 +883,14 @@ LL | while let Range { start: true, end } = t..&&false {} = note: expected type `bool` found struct `std::ops::Range` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:106:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `into_result` error[E0614]: type `bool` cannot be dereferenced --> $DIR/disallowed-positions.rs:173:5 @@ -900,16 +904,16 @@ error[E0600]: cannot apply unary operator `-` to type `bool` LL | -let 0 = 0; | ^^^^^^^^^^ cannot apply unary operator `-` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:183:5 | LL | (let 0 = 0)?; | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | - = help: the trait `std::ops::Try` is not implemented for `bool` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `bool` + = note: required by `into_result` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/disallowed-positions.rs:183:5 | LL | / fn outside_if_and_while_expr() { @@ -924,8 +928,8 @@ LL | | LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:198:10 @@ -947,14 +951,14 @@ LL | fn outside_if_and_while_expr() { LL | &let 0 = 0 | ^^^^^^^^^^ expected `()`, found `&bool` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:179:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `into_result` error: aborting due to 103 previous errors; 2 warnings emitted diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr index b57472d959..2b4fa66ecf 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr @@ -5,7 +5,7 @@ LL | impl const std::ops::Add for i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::ops::Add for i32; + - impl Add for i32; error[E0119]: conflicting implementations of trait `std::ops::Add` for type `Int`: --> $DIR/const-and-non-const-impl.rs:24:1 diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs index 3278f35bad..fc85e98ef5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs @@ -10,7 +10,7 @@ fn non_const() {} impl const T for S { fn foo() { non_const() } - //~^ ERROR can only call other `const fn` + //~^ ERROR calls in constant functions } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr index b50dd03a86..c6c78c7d1e 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -1,12 +1,9 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `non_const` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-check-fns-in-const-impl.rs:12:16 | LL | fn foo() { non_const() } | ^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr index 3994bd97c3..58041454d5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/feature-gate.rs:16:1 + --> $DIR/feature-gate.rs:17:1 | LL | fn main() {} | ^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs index d600b53e44..3506237d1f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs @@ -4,6 +4,7 @@ #![cfg_attr(gated, feature(const_trait_bound_opt_out))] #![allow(incomplete_features)] #![feature(rustc_attrs)] +#![feature(const_fn)] trait T { const CONST: i32; diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr index a1e1c3249a..8ae8b8868d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr @@ -1,5 +1,5 @@ error[E0658]: `?const` on trait bounds is experimental - --> $DIR/feature-gate.rs:12:29 + --> $DIR/feature-gate.rs:13:29 | LL | const fn get_assoc_const() -> i32 { ::CONST } | ^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.rs b/src/test/ui/rfc-2632-const-trait-impl/stability.rs index 03a6fb5150..454fde34a2 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.rs @@ -30,7 +30,7 @@ impl const std::ops::Add for Int { #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn foo() -> Int { Int(1i32) + Int(2i32) - //~^ ERROR can only call other `const fn` within a `const fn` + //~^ ERROR not yet stable as a const fn } // ok diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr index e7002a1a04..54d7cfd5d7 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr @@ -6,18 +6,14 @@ LL | | LL | | Int(self.0 - rhs.0) LL | | } | |_____^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `::add` is not stable as `const fn` +error: `::add` is not yet stable as a const fn --> $DIR/stability.rs:32:5 | LL | Int(1i32) + Int(2i32) | ^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs index b90a750cc1..c6d7166e74 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs index 1076b9f25d..cc7ea6cde8 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs index a4b832d377..86db09cc08 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs index 47b70e2e9c..99c574d078 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs index c663535e53..4a8a094937 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs @@ -21,7 +21,6 @@ fn main() { match WRAP_DIRECT_INLINE { WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { println!("WRAP_DIRECT_INLINE did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr index 9c7d1f3a18..c73a6cf132 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } | ^^^^^^^^^^^^^^^^^^ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9 - | -LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs index 872bf5a63f..93022a23db 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs @@ -21,7 +21,6 @@ fn main() { match WRAP_DIRECT_PARAM { WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { println!("WRAP_DIRECT_PARAM did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr index 6f49a8a0c9..6fdf9db89b 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } | ^^^^^^^^^^^^^^^^^ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cant-hide-behind-direct-struct-param.rs:22:9 - | -LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs index f694781969..fe62774d22 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_DOUBLY_INDIRECT_INLINE { WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_INLINE correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs index 1c29d67b65..c3a30674ea 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_DOUBLY_INDIRECT_PARAM { WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_PARAM correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs index 1a41dbb55c..4d0e80d5af 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_INDIRECT_INLINE { WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_INLINE did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs index 46032c4b0e..432f196ec8 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_INDIRECT_PARAM { WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_PARAM correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs index 6ebb948d73..46d8ee3b6b 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs @@ -10,7 +10,7 @@ // Issue 62307 pointed out a case where the structural-match checking // was too shallow. -#![warn(indirect_structural_match)] +#![warn(indirect_structural_match, nontrivial_structural_match)] // run-pass #[derive(Debug)] @@ -30,14 +30,14 @@ fn main() { match RR_B0 { RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { } } match RR_B1 { RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { } } } diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr index ae011dfcdb..a50093a5b1 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -7,7 +7,7 @@ LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); note: the lint level is defined here --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 | -LL | #![warn(indirect_structural_match)] +LL | #![warn(indirect_structural_match, nontrivial_structural_match)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #62411 diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs index b3c91cec58..567685950e 100644 --- a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs @@ -5,6 +5,8 @@ // cover the case this hit; I've since expanded it accordingly, but the // experience left me wary of leaving this regression test out.) +#![warn(pointer_structural_match)] + #[derive(Eq)] struct A { a: i64 @@ -31,6 +33,8 @@ fn main() { let s = B(my_fn); match s { B(TEST) => println!("matched"), + //~^ WARN pointers in patterns behave unpredictably + //~| WARN this was previously accepted by the compiler but is being phased out _ => panic!("didn't match") }; } diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr new file mode 100644 index 0000000000..8cf87cc85a --- /dev/null +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr @@ -0,0 +1,16 @@ +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-63479-match-fnptr.rs:35:7 + | +LL | B(TEST) => println!("matched"), + | ^^^^ + | +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 + +warning: 1 warning emitted + diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.rs b/src/test/ui/rfc1445/match-forbidden-without-eq.rs index 59141eac3e..1cca275206 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.rs @@ -12,7 +12,6 @@ fn main() { match y { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { } } diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr index 1f26f0f11d..02fa239818 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr @@ -5,7 +5,7 @@ LL | FOO => { } | ^^^ warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:21:9 + --> $DIR/match-forbidden-without-eq.rs:20:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ @@ -14,14 +14,8 @@ LL | f32::INFINITY => { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-forbidden-without-eq.rs:13:9 - | -LL | FOO => { } - | ^^^ - warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:21:9 + --> $DIR/match-forbidden-without-eq.rs:20:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ @@ -29,5 +23,5 @@ LL | f32::INFINITY => { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to previous error; 2 warnings emitted diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs index 4112e8f451..151a475c91 100644 --- a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs @@ -15,6 +15,5 @@ fn main() { match [B(1)] { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` } } diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr index 7e354bf9ad..371f8a0aa1 100644 --- a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `B` in a pattern, `B` must be annotated with `# LL | FOO => { } | ^^^ -error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-nonempty-array-forbidden-without-eq.rs:16:9 - | -LL | FOO => { } - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs index 9530a1ffec..6b7d94603b 100644 --- a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs +++ b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs @@ -16,7 +16,6 @@ fn main() { match y { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { } } } diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr index 7ef082852b..4157cf6528 100644 --- a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr +++ b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit LL | FOO => { } | ^^^ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9 - | -LL | FOO => { } - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr index 848d4fef1a..b5dd0c9d2a 100644 --- a/src/test/ui/rfc1623.nll.stderr +++ b/src/test/ui/rfc1623.nll.stderr @@ -1,4 +1,4 @@ -error[E0277]: `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely +error[E0277]: `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely --> $DIR/rfc1623.rs:21:1 | LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct { @@ -7,10 +7,10 @@ LL | | bar: &Bar { bools: &[true, true] }, LL | | f: &id, LL | | LL | | }; - | |__^ `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely + | |__^ `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely | - = help: within `&SomeStruct`, the trait `std::marker::Sync` is not implemented for `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` - = note: required because it appears within the type `&dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` + = help: within `&SomeStruct`, the trait `Sync` is not implemented for `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` + = note: required because it appears within the type `&dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` = note: required because it appears within the type `SomeStruct` = note: required because it appears within the type `&SomeStruct` = note: shared static variables must have a type that implements `Sync` diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 2efc58ac38..2835e47fa4 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(&'a Foo<'b>,)>` - found type `std::ops::FnOnce<(&Foo<'_>,)>` + = note: expected type `FnOnce<(&'a Foo<'b>,)>` + found type `FnOnce<(&Foo<'_>,)>` error: aborting due to previous error diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs index 5c838fd719..43bda49624 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs @@ -21,14 +21,14 @@ fn call_once(f: impl FnOnce()) { } fn main() { - call(foo); //~ ERROR expected a `std::ops::Fn<()>` closure, found `fn() {foo}` - call_mut(foo); //~ ERROR expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` - call_once(foo); //~ ERROR expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` + call(foo); //~ ERROR expected a `Fn<()>` closure, found `fn() {foo}` + call_mut(foo); //~ ERROR expected a `FnMut<()>` closure, found `fn() {foo}` + call_once(foo); //~ ERROR expected a `FnOnce<()>` closure, found `fn() {foo}` call(foo_unsafe); - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + //~^ ERROR expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` call_mut(foo_unsafe); - //~^ ERROR expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + //~^ ERROR expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` call_once(foo_unsafe); - //~^ ERROR expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` + //~^ ERROR expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` } diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index f9b4eed049..4ed86b34a3 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<()>` closure, found `fn() {foo}` +error[E0277]: expected a `Fn<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:24:10 | LL | fn call(f: impl Fn()) { @@ -7,11 +7,11 @@ LL | fn call(f: impl Fn()) { LL | call(foo); | ^^^ expected an `Fn<()>` closure, found `fn() {foo}` | - = help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}` + = help: the trait `Fn<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` +error[E0277]: expected a `FnMut<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:25:14 | LL | fn call_mut(f: impl FnMut()) { @@ -20,11 +20,11 @@ LL | fn call_mut(f: impl FnMut()) { LL | call_mut(foo); | ^^^ expected an `FnMut<()>` closure, found `fn() {foo}` | - = help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}` + = help: the trait `FnMut<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` +error[E0277]: expected a `FnOnce<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:26:15 | LL | fn call_once(f: impl FnOnce()) { @@ -33,11 +33,11 @@ LL | fn call_once(f: impl FnOnce()) { LL | call_once(foo); | ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}` | - = help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}` + = help: the trait `FnOnce<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}` +error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:28:10 | LL | fn call(f: impl Fn()) { @@ -46,11 +46,11 @@ LL | fn call(f: impl Fn()) { LL | call(foo_unsafe); | ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` | - = help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = help: the trait `Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` +error[E0277]: expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:30:14 | LL | fn call_mut(f: impl FnMut()) { @@ -59,11 +59,11 @@ LL | fn call_mut(f: impl FnMut()) { LL | call_mut(foo_unsafe); | ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` | - = help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = help: the trait `FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` +error[E0277]: expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:32:15 | LL | fn call_once(f: impl FnOnce()) { @@ -72,7 +72,7 @@ LL | fn call_once(f: impl FnOnce()) { LL | call_once(foo_unsafe); | ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` | - = help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = help: the trait `FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits diff --git a/src/test/ui/rmeta_meta_main.rs b/src/test/ui/rmeta_meta_main.rs index 52cd0c2f53..839f350d74 100644 --- a/src/test/ui/rmeta_meta_main.rs +++ b/src/test/ui/rmeta_meta_main.rs @@ -10,5 +10,5 @@ extern crate rmeta_meta; use rmeta_meta::Foo; fn main() { - let _ = Foo { field2: 42 }; //~ ERROR struct `rmeta_meta::Foo` has no field named `field2` + let _ = Foo { field2: 42 }; //~ ERROR struct `Foo` has no field named `field2` } diff --git a/src/test/ui/rmeta_meta_main.stderr b/src/test/ui/rmeta_meta_main.stderr index 347e5e97d7..0c6ed9afd3 100644 --- a/src/test/ui/rmeta_meta_main.stderr +++ b/src/test/ui/rmeta_meta_main.stderr @@ -1,4 +1,4 @@ -error[E0560]: struct `rmeta_meta::Foo` has no field named `field2` +error[E0560]: struct `Foo` has no field named `field2` --> $DIR/rmeta_meta_main.rs:13:19 | LL | let _ = Foo { field2: 42 }; diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr index 7948f7e9d6..85da2c6eeb 100644 --- a/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr @@ -26,8 +26,8 @@ LL | fn foo(self: &Rc) -> usize; LL | let x = Rc::new(5usize) as Rc; | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::rc::Rc` - = note: required by cast to type `std::rc::Rc` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Rc` + = note: required by cast to type `Rc` error: aborting due to 2 previous errors diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr index 74e76b8265..c4cde2c356 100644 --- a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr @@ -12,8 +12,8 @@ LL | fn foo(self: &Rc) -> usize; LL | let x = Rc::new(5usize) as Rc; | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::rc::Rc` - = note: required by cast to type `std::rc::Rc` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Rc` + = note: required by cast to type `Rc` error: aborting due to previous error diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr index 17099201d1..92241b2fb2 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr @@ -20,7 +20,7 @@ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58 | LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | -- ---- has type `std::pin::Pin<&'1 Foo>` ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` + | -- ---- has type `Pin<&'1 Foo>` ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` | | | lifetime `'a` defined here diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr index 96401cb71d..2954a499c1 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr @@ -5,7 +5,7 @@ LL | struct A; | --------- method `foo` not found for this ... LL | fn foo(self: Box) {} - | --- the method is available for `std::boxed::Box` here + | --- the method is available for `Box` here ... LL | A.foo(); | ^^^ method not found in `A` diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr index 37873031da..89fe84c0d2 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `foo` found for struct `A` in the current scope LL | trait B { fn foo(self: Box); } | --- --------- the method might not be found because of this arbitrary self type | | - | the method is available for `std::boxed::Box` here + | the method is available for `Box` here LL | struct A; | --------- method `foo` not found for this ... diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index 7997cdc295..47c04f1eb7 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -77,7 +77,7 @@ error[E0392]: parameter `'Self` is never used LL | struct Bar<'Self>; | ^^^^^ unused parameter | - = help: consider removing `'Self`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'Self`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 12 previous errors diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr index 91f8b0e630..c27bdf09a8 100644 --- a/src/test/ui/shift-various-bad-types.stderr +++ b/src/test/ui/shift-various-bad-types.stderr @@ -4,7 +4,7 @@ error[E0277]: no implementation for `{integer} >> char` LL | 22 >> p.char; | ^^ no implementation for `{integer} >> char` | - = help: the trait `std::ops::Shr` is not implemented for `{integer}` + = help: the trait `Shr` is not implemented for `{integer}` error[E0277]: no implementation for `{integer} >> &str` --> $DIR/shift-various-bad-types.rs:12:8 @@ -12,7 +12,7 @@ error[E0277]: no implementation for `{integer} >> &str` LL | 22 >> p.str; | ^^ no implementation for `{integer} >> &str` | - = help: the trait `std::ops::Shr<&str>` is not implemented for `{integer}` + = help: the trait `Shr<&str>` is not implemented for `{integer}` error[E0277]: no implementation for `{integer} >> &Panolpy` --> $DIR/shift-various-bad-types.rs:15:8 @@ -20,7 +20,7 @@ error[E0277]: no implementation for `{integer} >> &Panolpy` LL | 22 >> p; | ^^ no implementation for `{integer} >> &Panolpy` | - = help: the trait `std::ops::Shr<&Panolpy>` is not implemented for `{integer}` + = help: the trait `Shr<&Panolpy>` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/shift-various-bad-types.rs:25:18 diff --git a/src/test/ui/slice-to-vec-comparison.rs b/src/test/ui/slice-to-vec-comparison.rs new file mode 100644 index 0000000000..7026a49000 --- /dev/null +++ b/src/test/ui/slice-to-vec-comparison.rs @@ -0,0 +1,6 @@ +fn main() { + let a = &[]; + let b: &Vec = &vec![]; + a > b; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/slice-to-vec-comparison.stderr b/src/test/ui/slice-to-vec-comparison.stderr new file mode 100644 index 0000000000..e3b3b040f6 --- /dev/null +++ b/src/test/ui/slice-to-vec-comparison.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/slice-to-vec-comparison.rs:4:9 + | +LL | a > b; + | ^ expected array of 0 elements, found struct `Vec` + | + = note: expected reference `&[_; 0]` + found reference `&Vec` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 72f875bbd1..ab1fa2a4d8 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -33,7 +33,7 @@ LL | let mut f = move |g: Box, b: isize| { | ----- captured outer variable ... LL | foo(f); - | ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6 s:std::string::String]`, which does not implement the `Copy` trait + | ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait error[E0505]: cannot move out of `f` because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16 diff --git a/src/test/ui/span/borrowck-fn-in-const-b.stderr b/src/test/ui/span/borrowck-fn-in-const-b.stderr index 9133d482c2..8949a10481 100644 --- a/src/test/ui/span/borrowck-fn-in-const-b.stderr +++ b/src/test/ui/span/borrowck-fn-in-const-b.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-fn-in-const-b.rs:7:9 | LL | fn broken(x: &Vec) { - | ------------ help: consider changing this to be a mutable reference: `&mut std::vec::Vec` + | ------------ help: consider changing this to be a mutable reference: `&mut Vec` LL | x.push(format!("this is broken")); | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index d1960a8aab..857c3081c6 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:7:20 | LL | let x: usize = String::new(); - | ----- ^^^^^^^^^^^^^ expected `usize`, found struct `std::string::String` + | ----- ^^^^^^^^^^^^^ expected `usize`, found struct `String` | | | expected due to this @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | let x: &str = String::new(); | ---- ^^^^^^^^^^^^^ | | | - | | expected `&str`, found struct `std::string::String` + | | expected `&str`, found struct `String` | | help: consider borrowing here: `&String::new()` | expected due to this @@ -22,8 +22,8 @@ error[E0308]: mismatched types LL | test(&y); | ^^ types differ in mutability | - = note: expected mutable reference `&mut std::string::String` - found reference `&std::string::String` + = note: expected mutable reference `&mut String` + found reference `&String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:14:11 @@ -32,7 +32,7 @@ LL | test2(&y); | ^^ types differ in mutability | = note: expected mutable reference `&mut i32` - found reference `&std::string::String` + found reference `&String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:17:9 @@ -47,7 +47,7 @@ error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:21:9 | LL | s = format!("foo"); - | ^^^^^^^^^^^^^^ expected `&mut std::string::String`, found struct `std::string::String` + | ^^^^^^^^^^^^^^ expected `&mut String`, found struct `String` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/span/destructor-restrictions.stderr b/src/test/ui/span/destructor-restrictions.stderr index b5cd29f99c..f63d97780c 100644 --- a/src/test/ui/span/destructor-restrictions.stderr +++ b/src/test/ui/span/destructor-restrictions.stderr @@ -7,7 +7,7 @@ LL | *a.borrow() + 1 | borrowed value does not live long enough | a temporary with access to the borrow is created here ... LL | }; - | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, i32>` + | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, i32>` | | | `*a` dropped here while still borrowed | diff --git a/src/test/ui/span/dropck-object-cycle.stderr b/src/test/ui/span/dropck-object-cycle.stderr index cfaf470212..229d17e1cf 100644 --- a/src/test/ui/span/dropck-object-cycle.stderr +++ b/src/test/ui/span/dropck-object-cycle.stderr @@ -8,7 +8,7 @@ LL | } | - | | | `*m` dropped here while still borrowed - | borrow might be used here, when `m` is dropped and runs the destructor for type `std::boxed::Box>` + | borrow might be used here, when `m` is dropped and runs the destructor for type `Box>` error: aborting due to previous error diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index cda191522a..9b0aad28b0 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -64,7 +64,7 @@ error[E0046]: not all trait items implemented, missing: `fmt` LL | impl Debug for FooTypeForMethod { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation | - = help: implement the missing item: `fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { todo!() }` + = help: implement the missing item: `fn fmt(&self, _: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { todo!() }` error: aborting due to 8 previous errors diff --git a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr index 46702d364a..e04ca0f526 100644 --- a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr +++ b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr @@ -10,7 +10,7 @@ LL | } | - | | | `y` dropped here while still borrowed - | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::string::String>` + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, String>` | = note: the temporary is part of an expression at the end of a block; consider forcing this temporary to be dropped sooner, before the block's local variables are dropped @@ -28,7 +28,7 @@ LL | y.borrow().clone() | borrowed value does not live long enough | a temporary with access to the borrow is created here ... LL | }; - | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::string::String>` + | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, String>` | | | `y` dropped here while still borrowed | diff --git a/src/test/ui/span/issue-29106.stderr b/src/test/ui/span/issue-29106.stderr index 3b403de12d..71fbd60ee7 100644 --- a/src/test/ui/span/issue-29106.stderr +++ b/src/test/ui/span/issue-29106.stderr @@ -7,7 +7,7 @@ LL | } | - | | | `x` dropped here while still borrowed - | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `std::sync::Arc` + | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `Arc` | = note: values in a scope are dropped in the opposite order they are defined @@ -20,7 +20,7 @@ LL | } | - | | | `x` dropped here while still borrowed - | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `std::rc::Rc` + | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `Rc` | = note: values in a scope are dropped in the opposite order they are defined diff --git a/src/test/ui/span/issue-33884.stderr b/src/test/ui/span/issue-33884.stderr index 184d9644c8..46f36679b8 100644 --- a/src/test/ui/span/issue-33884.stderr +++ b/src/test/ui/span/issue-33884.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-33884.rs:8:22 | LL | stream.write_fmt(format!("message received")) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::fmt::Arguments`, found struct `std::string::String` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Arguments`, found struct `String` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index 8caa5bea4a..a7131ab8af 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -22,11 +22,11 @@ LL | let y = World::Hello + World::Goodbye; | = note: an implementation of `std::ops::Add` might be missing for `World` -error[E0369]: cannot add `std::string::String` to `&str` +error[E0369]: cannot add `String` to `&str` --> $DIR/issue-39018.rs:11:22 | LL | let x = "Hello " + "World!".to_owned(); - | -------- ^ ------------------- std::string::String + | -------- ^ ------------------- String | | | | | `+` cannot be used to concatenate a `&str` with a `String` | &str @@ -36,28 +36,28 @@ help: `to_owned()` can be used to create an owned `String` from a string referen LL | let x = "Hello ".to_owned() + &"World!".to_owned(); | ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ -error[E0369]: cannot add `&std::string::String` to `&std::string::String` +error[E0369]: cannot add `&String` to `&String` --> $DIR/issue-39018.rs:26:16 | LL | let _ = &a + &b; - | -- ^ -- &std::string::String + | -- ^ -- &String | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = a + &b; | ^ -error[E0369]: cannot add `std::string::String` to `&std::string::String` +error[E0369]: cannot add `String` to `&String` --> $DIR/issue-39018.rs:27:16 | LL | let _ = &a + b; - | -- ^ - std::string::String + | -- ^ - String | | | | | `+` cannot be used to concatenate a `&str` with a `String` - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -70,59 +70,59 @@ error[E0308]: mismatched types LL | let _ = a + b; | ^ | | - | expected `&str`, found struct `std::string::String` + | expected `&str`, found struct `String` | help: consider borrowing here: `&b` -error[E0369]: cannot add `std::string::String` to `&std::string::String` +error[E0369]: cannot add `String` to `&String` --> $DIR/issue-39018.rs:30:15 | LL | let _ = e + b; - | - ^ - std::string::String + | - ^ - String | | | | | `+` cannot be used to concatenate a `&str` with a `String` - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = e.to_owned() + &b; | ^^^^^^^^^^^^ ^^ -error[E0369]: cannot add `&std::string::String` to `&std::string::String` +error[E0369]: cannot add `&String` to `&String` --> $DIR/issue-39018.rs:31:15 | LL | let _ = e + &b; - | - ^ -- &std::string::String + | - ^ -- &String | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = e.to_owned() + &b; | ^^^^^^^^^^^^ -error[E0369]: cannot add `&str` to `&std::string::String` +error[E0369]: cannot add `&str` to `&String` --> $DIR/issue-39018.rs:32:15 | LL | let _ = e + d; | - ^ - &str | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = e.to_owned() + d; | ^^^^^^^^^^^^ -error[E0369]: cannot add `&&str` to `&std::string::String` +error[E0369]: cannot add `&&str` to `&String` --> $DIR/issue-39018.rs:33:15 | LL | let _ = e + &d; | - ^ -- &&str | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr index 9824d879db..c64c5b1c28 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed for `std::option::Option<_>` +error[E0282]: type annotations needed for `Option<_>` --> $DIR/issue-42234-unknown-receiver-type.rs:7:7 | LL | let x: Option<_> = None; - | - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified + | - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified LL | x.unwrap().method_that_could_exist_on_some_type(); | ^^^^^^ cannot infer type for type parameter `T` | diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.stderr b/src/test/ui/span/issue-43927-non-ADT-derive.stderr index b68681c529..b160a4e587 100644 --- a/src/test/ui/span/issue-43927-non-ADT-derive.stderr +++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43927-non-ADT-derive.rs:3:1 | LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! @@ -54,3 +54,4 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 6495d9bc73..13ef0d1820 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot add `()` to `u32` LL | foo(1 as u32 + | ^ no implementation for `u32 + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `u32` + = help: the trait `Add<()>` is not implemented for `u32` error: aborting due to previous error diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr index 8027cf69cf..e04e4cbdab 100644 --- a/src/test/ui/span/mut-arg-hint.stderr +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:3:9 | LL | fn foo(mut a: &String) { - | ------- help: consider changing this to be a mutable reference: `&mut std::string::String` + | ------- help: consider changing this to be a mutable reference: `&mut String` LL | a.push_str("bar"); | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -18,7 +18,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:15:9 | LL | pub fn foo(mut a: &String) { - | ------- help: consider changing this to be a mutable reference: `&mut std::string::String` + | ------- help: consider changing this to be a mutable reference: `&mut String` LL | a.push_str("foo"); | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr index 2be2d0ff7b..ba0c45acf2 100644 --- a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr @@ -7,7 +7,7 @@ LL | let ss: &isize = &id(1); LL | } | - temporary value is freed at the end of this statement LL | } - | - borrow might be used here, when `blah` is dropped and runs the destructor for type `std::boxed::Box` + | - borrow might be used here, when `blah` is dropped and runs the destructor for type `Box` | = note: consider using a `let` binding to create a longer lived value diff --git a/src/test/ui/span/send-is-not-static-std-sync.stderr b/src/test/ui/span/send-is-not-static-std-sync.stderr index d00b157d38..81de8c2990 100644 --- a/src/test/ui/span/send-is-not-static-std-sync.stderr +++ b/src/test/ui/span/send-is-not-static-std-sync.stderr @@ -62,7 +62,7 @@ LL | } | - `z` dropped here while still borrowed ... LL | } - | - borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `std::sync::mpsc::Sender` + | - borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `Sender` | = note: values in a scope are dropped in the opposite order they are defined diff --git a/src/test/ui/span/type-binding.stderr b/src/test/ui/span/type-binding.stderr index f698993355..cb0aefe060 100644 --- a/src/test/ui/span/type-binding.stderr +++ b/src/test/ui/span/type-binding.stderr @@ -1,4 +1,4 @@ -error[E0220]: associated type `Trget` not found for `std::ops::Deref` +error[E0220]: associated type `Trget` not found for `Deref` --> $DIR/type-binding.rs:6:20 | LL | fn homura>(_: T) {} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/deafult-associated-type-bound-1.rs index 272a5e3fe1..c043114b56 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.rs +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.rs @@ -16,7 +16,7 @@ trait X { // normalization. impl X for T { default type U = str; - //~^ ERROR the trait bound `str: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `str: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr index 90ad5d4c15..612e22c204 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr @@ -7,14 +7,14 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 for more information -error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/deafult-associated-type-bound-1.rs:18:5 | LL | type U: Clone; | -------------- required by `X::U` ... LL | default type U = str; - | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr index ea40f846e3..a14024c160 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -16,7 +16,7 @@ LL | type U: PartialEq; LL | default type U = &'static B; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B` | - = help: the trait `std::cmp::PartialEq` is not implemented for `&'static B` + = help: the trait `PartialEq` is not implemented for `&'static B` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr index 3da8725d88..556feda642 100644 --- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -24,11 +24,11 @@ LL | type U<'a>: PartialEq<&'a Self>; LL | default type U<'a> = &'a T; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T` | - = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T` + = note: required because of the requirements on the impl of `PartialEq` for `&'a T` help: consider further restricting this bound | -LL | impl X for T { - | ^^^^^^^^^^^^^^^^^^^^^ +LL | impl X for T { + | ^^^^^^^^^^^ error: aborting due to previous error; 2 warnings emitted diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs index afd634725e..eb18d6eaac 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs +++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs @@ -5,6 +5,6 @@ trait Foo<'a, T: Eq + 'a> { } default impl Foo<'static, U> for () {} -//~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied +//~^ ERROR the trait bound `U: Eq` is not satisfied fn main(){} diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr index d45825651a..dcac310ed0 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr @@ -7,19 +7,19 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 for more information -error[E0277]: the trait bound `U: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `U: Eq` is not satisfied --> $DIR/specialization-wfcheck.rs:7:17 | LL | trait Foo<'a, T: Eq + 'a> { } | -- required by this bound in `Foo` LL | LL | default impl Foo<'static, U> for () {} - | ^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `U` + | ^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `U` | help: consider restricting type parameter `U` | -LL | default impl Foo<'static, U> for () {} - | ^^^^^^^^^^^^^^ +LL | default impl Foo<'static, U> for () {} + | ^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/specialization/issue-44861.rs b/src/test/ui/specialization/issue-44861.rs index c37a6273de..79d9b9490d 100644 --- a/src/test/ui/specialization/issue-44861.rs +++ b/src/test/ui/specialization/issue-44861.rs @@ -19,7 +19,7 @@ impl MaybeObjectSafe for () {} impl Smartass for T { type Data = ::Data2; default type Data2 = (); - //~^ ERROR: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied + //~^ ERROR: the trait bound `(): CoerceUnsized<*const [u8]>` is not satisfied } impl Smartass for () { diff --git a/src/test/ui/specialization/issue-44861.stderr b/src/test/ui/specialization/issue-44861.stderr index b41b17e76a..be7196a63c 100644 --- a/src/test/ui/specialization/issue-44861.stderr +++ b/src/test/ui/specialization/issue-44861.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied +error[E0277]: the trait bound `(): CoerceUnsized<*const [u8]>` is not satisfied --> $DIR/issue-44861.rs:21:5 | LL | type Data2: CoerceUnsized<*const [u8]>; | --------------------------------------- required by `Smartass::Data2` ... LL | default type Data2 = (); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::CoerceUnsized<*const [u8]>` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `CoerceUnsized<*const [u8]>` is not implemented for `()` error: aborting due to previous error diff --git a/src/test/ui/specialization/issue-59435.rs b/src/test/ui/specialization/issue-59435.rs index 47323d3096..3239002566 100644 --- a/src/test/ui/specialization/issue-59435.rs +++ b/src/test/ui/specialization/issue-59435.rs @@ -9,7 +9,7 @@ trait MyTrait { impl MyTrait for i32 { default type MyType = MyStruct; - //~^ ERROR: the trait bound `MyStruct: std::default::Default` is not satisfied + //~^ ERROR: the trait bound `MyStruct: Default` is not satisfied } fn main() { diff --git a/src/test/ui/specialization/issue-59435.stderr b/src/test/ui/specialization/issue-59435.stderr index fd512a539a..ee5c061592 100644 --- a/src/test/ui/specialization/issue-59435.stderr +++ b/src/test/ui/specialization/issue-59435.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `MyStruct: std::default::Default` is not satisfied +error[E0277]: the trait bound `MyStruct: Default` is not satisfied --> $DIR/issue-59435.rs:11:5 | LL | type MyType: Default; | --------------------- required by `MyTrait::MyType` ... LL | default type MyType = MyStruct; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `MyStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `MyStruct` error: aborting due to previous error diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr index 1361117f6c..fee8b06e94 100644 --- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr @@ -1,4 +1,4 @@ -error: cannot specialize on `ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id[0]::This[0]) }, (I,))` +error: cannot specialize on `ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,))` --> $DIR/repeated_projection_type.rs:19:1 | LL | / impl> X for V { diff --git a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr index 154c839c6d..5782ad01b3 100644 --- a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr +++ b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr @@ -1,4 +1,4 @@ -error: cannot specialize on trait `std::default::Default` +error: cannot specialize on trait `Default` --> $DIR/specialization_super_trait.rs:13:1 | LL | / impl SpecMarker for T { diff --git a/src/test/ui/specialization/min_specialization/specialization_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_trait.stderr index 4357d2318f..8a70d6cc1b 100644 --- a/src/test/ui/specialization/min_specialization/specialization_trait.stderr +++ b/src/test/ui/specialization/min_specialization/specialization_trait.stderr @@ -16,7 +16,7 @@ LL | | fn f() {} LL | | } | |_^ -error: cannot specialize on trait `std::clone::Clone` +error: cannot specialize on trait `Clone` --> $DIR/specialization_trait.rs:21:1 | LL | / impl SpecMarker for [T] { diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr index 5e0221f078..5acfb53e20 100644 --- a/src/test/ui/specialization/specialization-default-types.stderr +++ b/src/test/ui/specialization/specialization-default-types.stderr @@ -15,22 +15,22 @@ LL | default type Output = Box; LL | default fn generate(self) -> Self::Output { | ------------ expected `::Output` because of return type LL | Box::new(self) - | ^^^^^^^^^^^^^^ expected associated type, found struct `std::boxed::Box` + | ^^^^^^^^^^^^^^ expected associated type, found struct `Box` | = note: expected associated type `::Output` - found struct `std::boxed::Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:25:5 | LL | fn trouble(t: T) -> Box { - | ------ expected `std::boxed::Box` because of return type + | ------ expected `Box` because of return type LL | Example::generate(t) - | ^^^^^^^^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found associated type + | ^^^^^^^^^^^^^^^^^^^^ expected struct `Box`, found associated type | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found associated type `::Output` - = help: consider constraining the associated type `::Output` to `std::boxed::Box` + = help: consider constraining the associated type `::Output` to `Box` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs new file mode 100644 index 0000000000..231ab96655 --- /dev/null +++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs @@ -0,0 +1,229 @@ +#![crate_type = "lib"] +#![feature(staged_api)] +#![stable(feature = "stable_test_feature", since = "1.0.0")] + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Trait1<#[unstable(feature = "unstable_default", issue = "none")] T = ()> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + fn foo() -> T; +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Trait2<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + fn foo() -> T; +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Trait3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + fn foo() -> T; +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: T, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct2 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: T, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field1: A, + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field2: B, +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct4 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: A, +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct5<#[unstable(feature = "unstable_default", issue = "none")] A = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: A, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct6<#[unstable(feature = "unstable_default6", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: T, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT1: Struct1 = Struct1 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT2: Struct2 = Struct2 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT3: Struct3 = Struct3 { field1: 1, field2: 2 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT4: Struct4 = Struct4 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT5: Struct5 = Struct5 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum2 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Ok(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Err(#[stable(feature = "stable_test_feature", since = "1.0.0")] E), +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum4 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum6<#[unstable(feature = "unstable_default6", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM1: Enum1 = Enum1::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM2: Enum2 = Enum2::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM3: Enum3 = Enum3::Ok(1); +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM3B: Enum3 = Enum3::Err(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM4: Enum4 = Enum4::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM5: Enum5 = Enum5::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias2 = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias3 = + Result; + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias4 = Option; + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias6<#[unstable(feature = "unstable_default6", issue = "none")] T = usize> = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS1: Alias1 = Alias1::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS2: Alias2 = Alias2::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS3: Alias3 = Alias3::Ok(1); +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS3B: Alias3 = Alias3::Err(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS4: Alias4 = Alias4::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS5: Alias5 = Alias5::Some(1); + + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Alloc {} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct System {} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +impl Alloc for System {} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Box1 { + ptr: *mut T, + alloc: A, +} + +impl Box1 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new(mut t: T) -> Self { + unsafe { Self { ptr: &mut t, alloc: System {} } } + } +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Box2 { + ptr: *mut T, + alloc: A, +} + +impl Box2 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new(mut t: T) -> Self { + Self { ptr: &mut t, alloc: System {} } + } +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Box3 { + ptr: *mut T, +} + +impl Box3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new(mut t: T) -> Self { + Self { ptr: &mut t } + } +} diff --git a/src/test/ui/stability-attribute/generics-default-stability-where.rs b/src/test/ui/stability-attribute/generics-default-stability-where.rs new file mode 100644 index 0000000000..3fd14e25d0 --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability-where.rs @@ -0,0 +1,12 @@ +// ignore-tidy-linelength +// aux-build:unstable_generic_param.rs + +extern crate unstable_generic_param; + +use unstable_generic_param::*; + +impl Trait3 for T where T: Trait2 { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> usize { T::foo() } +} + +fn main() {} diff --git a/src/test/ui/stability-attribute/generics-default-stability-where.stderr b/src/test/ui/stability-attribute/generics-default-stability-where.stderr new file mode 100644 index 0000000000..19fa09f311 --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability-where.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability-where.rs:8:45 + | +LL | impl Trait3 for T where T: Trait2 { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs new file mode 100644 index 0000000000..d6f28e3e44 --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -0,0 +1,264 @@ +// ignore-tidy-linelength +// aux-build:unstable_generic_param.rs +#![feature(unstable_default6)] + +extern crate unstable_generic_param; + +use unstable_generic_param::*; + +struct R; + +impl Trait1 for S { + fn foo() -> () { () } // ok +} + +struct S; + +impl Trait1 for S { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> usize { 0 } +} + +impl Trait1 for S { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> isize { 0 } +} + +impl Trait2 for S { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> usize { 0 } +} + +impl Trait3 for S { + fn foo() -> usize { 0 } // ok +} + +fn main() { + let _ = S; + + let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + + let _ = STRUCT1; // ok + let _: Struct1 = STRUCT1; // ok + let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct1 = Struct1 { field: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + + // Instability is not enforced for generic type parameters used in public fields. + // Note how the unstable type default `usize` leaks, + // and can be used without the 'unstable_default' feature. + let _ = STRUCT1.field; + let _ = Struct1 { field: 1 }; + let _ = Struct1 { field: () }; + let _ = Struct1 { field: 1isize }; + let _: Struct1 = Struct1 { field: 1 }; + let _: usize = STRUCT1.field; + let _ = STRUCT1.field + 1; + let _ = STRUCT1.field + 1usize; + + let _ = Struct2 { field: 1 }; // ok + let _: Struct2 = Struct2 { field: 1 }; // ok + let _: Struct2 = Struct2 { field: 1 }; // ok + + let _ = STRUCT2; + let _: Struct2 = STRUCT2; // ok + let _: Struct2 = STRUCT2; // ok + let _: Struct2 = Struct2 { field: 0 }; // ok + let _ = STRUCT2.field; // ok + let _: usize = STRUCT2.field; // ok + let _ = STRUCT2.field + 1; // ok + let _ = STRUCT2.field + 1usize; // ok + + let _ = STRUCT3; + let _: Struct3 = STRUCT3; // ok + let _: Struct3 = STRUCT3; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct3 = STRUCT3; // ok + let _: Struct3 = Struct3 { field1: 0, field2: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct3 = Struct3 { field1: 0, field2: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + let _ = STRUCT3.field1; // ok + let _: isize = STRUCT3.field1; // ok + let _ = STRUCT3.field1 + 1; // ok + // Note the aforementioned leak. + let _: usize = STRUCT3.field2; // ok + let _: Struct3 = Struct3 { field1: 0, field2: 0 }; // ok + let _ = STRUCT3.field2 + 1; // ok + let _ = STRUCT3.field2 + 1usize; // ok + + let _ = STRUCT4; + let _: Struct4 = Struct4 { field: 1 }; + //~^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] + let _ = STRUCT4; + let _: Struct4 = STRUCT4; //~ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + let _: Struct4 = STRUCT4; //~ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + let _: Struct4 = Struct4 { field: 0 }; + //~^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] + + let _ = STRUCT5; + let _: Struct5 = Struct5 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] + let _ = STRUCT5; + let _: Struct5 = STRUCT5; //~ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + let _: Struct5 = STRUCT5; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + let _: Struct5 = Struct5 { field: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] + + let _: Struct6 = Struct6 { field: 1 }; // ok + let _: Struct6 = Struct6 { field: 0 }; // ok + + let _: Alias1 = Alias1::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + + let _ = ALIAS1; // ok + let _: Alias1 = ALIAS1; // ok + let _: Alias1 = ALIAS1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Alias1 = Alias1::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + + // Instability is not enforced for generic type parameters used in public fields. + // Note how the unstable type default `usize` leaks, + // and can be used without the 'unstable_default' feature. + let _ = Alias1::Some(1); + let _ = Alias1::Some(()); + let _ = Alias1::Some(1isize); + let _: Alias1 = Alias1::Some(1); + let _: usize = ALIAS1.unwrap(); + let _ = ALIAS1.unwrap() + 1; + let _ = ALIAS1.unwrap() + 1usize; + + let _ = Alias2::Some(1); // ok + let _: Alias2 = Alias2::Some(1); // ok + let _: Alias2 = Alias2::Some(1); // ok + + let _ = ALIAS2; + let _: Alias2 = ALIAS2; // ok + let _: Alias2 = ALIAS2; // ok + let _: Alias2 = Alias2::Some(0); // ok + let _ = ALIAS2.unwrap(); // ok + let _: usize = ALIAS2.unwrap(); // ok + let _ = ALIAS2.unwrap() + 1; // ok + let _ = ALIAS2.unwrap() + 1usize; // ok + + let _ = ALIAS3; + let _: Alias3 = ALIAS3; // ok + let _: Alias3 = ALIAS3; //~ ERROR use of unstable library feature 'unstable_default' + let _: Alias3 = ALIAS3; // ok + let _: Alias3 = Alias3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + let _: Alias3 = Alias3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + let _ = ALIAS3.unwrap(); // ok + let _: isize = ALIAS3.unwrap(); // ok + let _ = ALIAS3.unwrap() + 1; // ok + // Note the aforementioned leak. + let _: usize = ALIAS3B.unwrap_err(); // ok + let _: Alias3 = Alias3::Err(0); // ok + let _ = ALIAS3B.unwrap_err() + 1; // ok + let _ = ALIAS3B.unwrap_err() + 1usize; // ok + + let _ = ALIAS4; + let _: Alias4 = Alias4::Some(1); + //~^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _ = ALIAS4; + let _: Alias4 = ALIAS4; //~ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _: Alias4 = ALIAS4; //~ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _: Alias4 = Alias4::Some(0); + //~^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + + let _ = ALIAS5; + let _: Alias5 = Alias5::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _ = ALIAS5; + let _: Alias5 = ALIAS5; //~ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _: Alias5 = ALIAS5; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _: Alias5 = Alias5::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + + let _: Alias6 = Alias6::Some(1); // ok + let _: Alias6 = Alias6::Some(0); // ok + + let _: Enum1 = Enum1::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + + let _ = ENUM1; // ok + let _: Enum1 = ENUM1; // ok + let _: Enum1 = ENUM1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Enum1 = Enum1::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + + // Instability is not enforced for generic type parameters used in public fields. + // Note how the unstable type default `usize` leaks, + // and can be used without the 'unstable_default' feature. + let _ = Enum1::Some(1); + let _ = Enum1::Some(()); + let _ = Enum1::Some(1isize); + let _: Enum1 = Enum1::Some(1); + if let Enum1::Some(x) = ENUM1 {let _: usize = x;} + if let Enum1::Some(x) = ENUM1 {let _ = x + 1;} + if let Enum1::Some(x) = ENUM1 {let _ = x + 1usize;} + + let _ = Enum2::Some(1); // ok + let _: Enum2 = Enum2::Some(1); // ok + let _: Enum2 = Enum2::Some(1); // ok + + let _ = ENUM2; + let _: Enum2 = ENUM2; // ok + let _: Enum2 = ENUM2; // ok + let _: Enum2 = Enum2::Some(0); // ok + if let Enum2::Some(x) = ENUM2 {let _ = x;} // ok + if let Enum2::Some(x) = ENUM2 {let _: usize = x;} // ok + if let Enum2::Some(x) = ENUM2 {let _ = x + 1;} // ok + if let Enum2::Some(x) = ENUM2 {let _ = x + 1usize;} // ok + + let _ = ENUM3; + let _: Enum3 = ENUM3; // ok + let _: Enum3 = ENUM3; //~ ERROR use of unstable library feature 'unstable_default' + let _: Enum3 = ENUM3; // ok + let _: Enum3 = Enum3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + let _: Enum3 = Enum3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + if let Enum3::Ok(x) = ENUM3 {let _ = x;} // ok + if let Enum3::Ok(x) = ENUM3 {let _: isize = x;} // ok + if let Enum3::Ok(x) = ENUM3 {let _ = x + 1;} // ok + // Note the aforementioned leak. + if let Enum3::Err(x) = ENUM3B {let _: usize = x;} // ok + let _: Enum3 = Enum3::Err(0); // ok + if let Enum3::Err(x) = ENUM3B {let _ = x + 1;} // ok + if let Enum3::Err(x) = ENUM3B {let _ = x + 1usize;} // ok + + let _ = ENUM4; + let _: Enum4 = Enum4::Some(1); + //~^ use of deprecated variant `unstable_generic_param::Enum4::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _ = ENUM4; + let _: Enum4 = ENUM4; //~ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _: Enum4 = ENUM4; //~ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _: Enum4 = Enum4::Some(0); + //~^ use of deprecated variant `unstable_generic_param::Enum4::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + + let _ = ENUM5; + let _: Enum5 = Enum5::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated variant `unstable_generic_param::Enum5::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _ = ENUM5; + let _: Enum5 = ENUM5; //~ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _: Enum5 = ENUM5; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _: Enum5 = Enum5::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated variant `unstable_generic_param::Enum5::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + + let _: Enum6 = Enum6::Some(1); // ok + let _: Enum6 = Enum6::Some(0); // ok + + let _: Box1 = Box1::new(1); //~ ERROR use of unstable library feature 'box_alloc_param' + let _: Box1 = Box1::new(1); // ok + + let _: Box2 = Box2::new(1); // ok + let _: Box2 = Box2::new(1); // ok + + let _: Box3 = Box3::new(1); // ok +} diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr new file mode 100644 index 0000000000..a5df70bb8b --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -0,0 +1,493 @@ +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:17:13 + | +LL | impl Trait1 for S { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:21:13 + | +LL | impl Trait1 for S { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:25:13 + | +LL | impl Trait2 for S { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:84:29 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:84:12 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:89:12 + | +LL | let _: Struct4 = STRUCT4; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:90:12 + | +LL | let _: Struct4 = STRUCT4; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:91:29 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:91:12 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:97:29 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:97:12 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:102:12 + | +LL | let _: Struct5 = STRUCT5; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:103:12 + | +LL | let _: Struct5 = STRUCT5; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:105:29 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:105:12 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:160:28 + | +LL | let _: Alias4 = Alias4::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:160:12 + | +LL | let _: Alias4 = Alias4::Some(1); + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:164:12 + | +LL | let _: Alias4 = ALIAS4; + | ^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:165:12 + | +LL | let _: Alias4 = ALIAS4; + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:166:28 + | +LL | let _: Alias4 = Alias4::Some(0); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:166:12 + | +LL | let _: Alias4 = Alias4::Some(0); + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:171:28 + | +LL | let _: Alias5 = Alias5::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:171:12 + | +LL | let _: Alias5 = Alias5::Some(1); + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:175:12 + | +LL | let _: Alias5 = ALIAS5; + | ^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:176:12 + | +LL | let _: Alias5 = ALIAS5; + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:178:28 + | +LL | let _: Alias5 = Alias5::Some(0); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:178:12 + | +LL | let _: Alias5 = Alias5::Some(0); + | ^^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test + --> $DIR/generics-default-stability.rs:232:27 + | +LL | let _: Enum4 = Enum4::Some(1); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:232:12 + | +LL | let _: Enum4 = Enum4::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:236:12 + | +LL | let _: Enum4 = ENUM4; + | ^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:237:12 + | +LL | let _: Enum4 = ENUM4; + | ^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test + --> $DIR/generics-default-stability.rs:238:27 + | +LL | let _: Enum4 = Enum4::Some(0); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:238:12 + | +LL | let _: Enum4 = Enum4::Some(0); + | ^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test + --> $DIR/generics-default-stability.rs:243:27 + | +LL | let _: Enum5 = Enum5::Some(1); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:243:12 + | +LL | let _: Enum5 = Enum5::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:247:12 + | +LL | let _: Enum5 = ENUM5; + | ^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:248:12 + | +LL | let _: Enum5 = ENUM5; + | ^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test + --> $DIR/generics-default-stability.rs:250:27 + | +LL | let _: Enum5 = Enum5::Some(0); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:250:12 + | +LL | let _: Enum5 = Enum5::Some(0); + | ^^^^^^^^^^^^ + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:36:20 + | +LL | let _: Struct1 = Struct1 { field: 1 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:40:20 + | +LL | let _: Struct1 = STRUCT1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:41:20 + | +LL | let _: Struct1 = Struct1 { field: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:70:27 + | +LL | let _: Struct3 = STRUCT3; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:72:27 + | +LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:73:27 + | +LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:97:20 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:103:20 + | +LL | let _: Struct5 = STRUCT5; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:105:20 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:113:19 + | +LL | let _: Alias1 = Alias1::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:117:19 + | +LL | let _: Alias1 = ALIAS1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:118:19 + | +LL | let _: Alias1 = Alias1::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:146:26 + | +LL | let _: Alias3 = ALIAS3; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:148:26 + | +LL | let _: Alias3 = Alias3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:149:26 + | +LL | let _: Alias3 = Alias3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:171:19 + | +LL | let _: Alias5 = Alias5::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:176:19 + | +LL | let _: Alias5 = ALIAS5; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:178:19 + | +LL | let _: Alias5 = Alias5::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:185:18 + | +LL | let _: Enum1 = Enum1::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:189:18 + | +LL | let _: Enum1 = ENUM1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:190:18 + | +LL | let _: Enum1 = Enum1::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:218:25 + | +LL | let _: Enum3 = ENUM3; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:220:25 + | +LL | let _: Enum3 = Enum3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:221:25 + | +LL | let _: Enum3 = Enum3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:243:18 + | +LL | let _: Enum5 = Enum5::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:248:18 + | +LL | let _: Enum5 = ENUM5; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:250:18 + | +LL | let _: Enum5 = Enum5::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'box_alloc_param' + --> $DIR/generics-default-stability.rs:257:24 + | +LL | let _: Box1 = Box1::new(1); + | ^^^^^^ + | + = help: add `#![feature(box_alloc_param)]` to the crate attributes to enable + +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test + --> $DIR/generics-default-stability.rs:84:39 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^^ + +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test + --> $DIR/generics-default-stability.rs:91:39 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^^ + +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test + --> $DIR/generics-default-stability.rs:97:39 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^^ + +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test + --> $DIR/generics-default-stability.rs:105:39 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^^ + +error: aborting due to 31 previous errors; 40 warnings emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/missing-const-stability.rs b/src/test/ui/stability-attribute/missing-const-stability.rs new file mode 100644 index 0000000000..7d499c611a --- /dev/null +++ b/src/test/ui/stability-attribute/missing-const-stability.rs @@ -0,0 +1,12 @@ +#![feature(staged_api)] + +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "foo", since = "1.0.0")] +pub const fn foo() {} +//~^ ERROR rustc_const_stable + +#[unstable(feature = "bar", issue = "none")] +pub const fn bar() {} // ok + +fn main() {} diff --git a/src/test/ui/stability-attribute/missing-const-stability.stderr b/src/test/ui/stability-attribute/missing-const-stability.stderr new file mode 100644 index 0000000000..450a5303fd --- /dev/null +++ b/src/test/ui/stability-attribute/missing-const-stability.stderr @@ -0,0 +1,8 @@ +error: `#[stable]` const functions must also be either `#[rustc_const_stable]` or `#[rustc_const_unstable]` + --> $DIR/missing-const-stability.rs:6:1 + | +LL | pub const fn foo() {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs new file mode 100644 index 0000000000..cc57071b87 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs @@ -0,0 +1,28 @@ +#![feature(staged_api)] + +#[stable(feature = "x", since = "1")] +struct StableType; + +#[unstable(feature = "x", issue = "none")] +struct UnstableType; + +#[stable(feature = "x", since = "1")] +trait StableTrait {} + +#[unstable(feature = "x", issue = "none")] +trait UnstableTrait {} + +#[unstable(feature = "x", issue = "none")] +impl UnstableTrait for UnstableType {} + +#[unstable(feature = "x", issue = "none")] +impl StableTrait for UnstableType {} + +#[unstable(feature = "x", issue = "none")] +impl UnstableTrait for StableType {} + +#[unstable(feature = "x", issue = "none")] +//~^ ERROR an `#[unstable]` annotation here has no effect [rustc::ineffective_unstable_trait_impl] +impl StableTrait for StableType {} + +fn main() {} diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr new file mode 100644 index 0000000000..1915d03fb0 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr @@ -0,0 +1,11 @@ +error: an `#[unstable]` annotation here has no effect + --> $DIR/stability-attribute-trait-impl.rs:24:1 + | +LL | #[unstable(feature = "x", issue = "none")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(rustc::ineffective_unstable_trait_impl)]` on by default + = note: see issue #55436 for more information + +error: aborting due to previous error + diff --git a/src/test/ui/static/static-mut-not-constant.rs b/src/test/ui/static/static-mut-not-constant.rs index 84d401c9fa..2091fffd41 100644 --- a/src/test/ui/static/static-mut-not-constant.rs +++ b/src/test/ui/static/static-mut-not-constant.rs @@ -2,6 +2,5 @@ static mut a: Box = box 3; //~^ ERROR allocations are not allowed in statics -//~| ERROR static contains unimplemented expression type fn main() {} diff --git a/src/test/ui/static/static-mut-not-constant.stderr b/src/test/ui/static/static-mut-not-constant.stderr index a618b49d10..a0fa245156 100644 --- a/src/test/ui/static/static-mut-not-constant.stderr +++ b/src/test/ui/static/static-mut-not-constant.stderr @@ -4,15 +4,6 @@ error[E0010]: allocations are not allowed in statics LL | static mut a: Box = box 3; | ^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/static-mut-not-constant.rs:3:32 - | -LL | static mut a: Box = box 3; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0010, E0019. -For more information about an error, try `rustc --explain E0010`. +For more information about this error, try `rustc --explain E0010`. diff --git a/src/test/ui/static/static-reference-to-fn-1.stderr b/src/test/ui/static/static-reference-to-fn-1.stderr index 77ab62c321..67b478bdb7 100644 --- a/src/test/ui/static/static-reference-to-fn-1.stderr +++ b/src/test/ui/static/static-reference-to-fn-1.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | func: &foo, | ^^^^ expected fn pointer, found fn item | - = note: expected reference `&fn() -> std::option::Option` - found reference `&fn() -> std::option::Option {foo}` + = note: expected reference `&fn() -> Option` + found reference `&fn() -> Option {foo}` error: aborting due to previous error diff --git a/src/test/ui/statics/static-promotion.rs b/src/test/ui/statics/static-promotion.rs index bd8910bdb3..b9eff46917 100644 --- a/src/test/ui/statics/static-promotion.rs +++ b/src/test/ui/statics/static-promotion.rs @@ -1,4 +1,4 @@ -// check-pass +// run-pass // Use of global static variables in literal values should be allowed for // promotion. diff --git a/src/test/ui/stdout-during-shutdown.rs b/src/test/ui/stdout-during-shutdown.rs new file mode 100644 index 0000000000..a6cf812ca6 --- /dev/null +++ b/src/test/ui/stdout-during-shutdown.rs @@ -0,0 +1,19 @@ +// run-pass +// check-run-results +// ignore-emscripten + +// Emscripten doesn't flush its own stdout buffers on exit, which would fail +// this test. So this test is disabled on this platform. +// See https://emscripten.org/docs/getting_started/FAQ.html#what-does-exiting-the-runtime-mean-why-don-t-atexit-s-run + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + extern "C" fn bye() { + print!(", world!"); + } + unsafe { libc::atexit(bye) }; + print!("hello"); +} diff --git a/src/test/ui/stdout-during-shutdown.run.stdout b/src/test/ui/stdout-during-shutdown.run.stdout new file mode 100644 index 0000000000..30f51a3fba --- /dev/null +++ b/src/test/ui/stdout-during-shutdown.run.stdout @@ -0,0 +1 @@ +hello, world! \ No newline at end of file diff --git a/src/test/ui/str-concat.rs b/src/test/ui/str-concat.rs deleted file mode 100644 index fa2fc97d7b..0000000000 --- a/src/test/ui/str-concat.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - -pub fn main() { - let a: String = "hello".to_string(); - let b: String = "world".to_string(); - let s: String = format!("{}{}", a, b); - println!("{}", s.clone()); - assert_eq!(s.as_bytes()[9], 'd' as u8); -} diff --git a/src/test/ui/str-multiline.rs b/src/test/ui/str-multiline.rs deleted file mode 100644 index 2b2e001d8b..0000000000 --- a/src/test/ui/str-multiline.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass - -pub fn main() { - let a: String = "this \ -is a test".to_string(); - let b: String = - "this \ - is \ - another \ - test".to_string(); - assert_eq!(a, "this is a test".to_string()); - assert_eq!(b, "this is another test".to_string()); -} diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr index 52d3aefe12..73c03f09f2 100644 --- a/src/test/ui/str/str-array-assignment.stderr +++ b/src/test/ui/str/str-array-assignment.stderr @@ -21,7 +21,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | let v = s[..2]; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature help: consider borrowing here diff --git a/src/test/ui/str/str-concat-on-double-ref.rs b/src/test/ui/str/str-concat-on-double-ref.rs index 23e5f89206..e68210d53b 100644 --- a/src/test/ui/str/str-concat-on-double-ref.rs +++ b/src/test/ui/str/str-concat-on-double-ref.rs @@ -2,6 +2,6 @@ fn main() { let a: &String = &"1".to_owned(); let b: &str = &"2"; let c = a + b; - //~^ ERROR cannot add `&str` to `&std::string::String` + //~^ ERROR cannot add `&str` to `&String` println!("{:?}", c); } diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr index d77e0d8f24..ac87d6ecca 100644 --- a/src/test/ui/str/str-concat-on-double-ref.stderr +++ b/src/test/ui/str/str-concat-on-double-ref.stderr @@ -1,11 +1,11 @@ -error[E0369]: cannot add `&str` to `&std::string::String` +error[E0369]: cannot add `&str` to `&String` --> $DIR/str-concat-on-double-ref.rs:4:15 | LL | let c = a + b; | - ^ - &str | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | diff --git a/src/test/ui/str/str-idx.stderr b/src/test/ui/str/str-idx.stderr index 9f21aaaeba..f323ba03c0 100644 --- a/src/test/ui/str/str-idx.stderr +++ b/src/test/ui/str/str-idx.stderr @@ -4,10 +4,10 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | let _: u8 = s[4]; | ^^^^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book - = note: required because of the requirements on the impl of `std::ops::Index<{integer}>` for `str` + for more information, see chapter 8 in The Book: + = note: required because of the requirements on the impl of `Index<{integer}>` for `str` error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-idx.rs:4:19 @@ -15,9 +15,9 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | let _ = s.get(4); | ^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-idx.rs:5:29 @@ -25,9 +25,9 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | let _ = s.get_unchecked(4); | ^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `char` --> $DIR/str-idx.rs:6:17 @@ -35,8 +35,8 @@ error[E0277]: the type `str` cannot be indexed by `char` LL | let _: u8 = s['c']; | ^^^^^^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `char` - = note: required because of the requirements on the impl of `std::ops::Index` for `str` + = help: the trait `SliceIndex` is not implemented for `char` + = note: required because of the requirements on the impl of `Index` for `str` error: aborting due to 4 previous errors diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr index 7c834165e7..405542820a 100644 --- a/src/test/ui/str/str-mut-idx.stderr +++ b/src/test/ui/str/str-mut-idx.stderr @@ -7,7 +7,7 @@ LL | fn bot() -> T { loop {} } LL | s[1..2] = bot(); | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` help: consider relaxing the implicit `Sized` restriction | LL | fn bot() -> T { loop {} } @@ -19,7 +19,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | s[1..2] = bot(); | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: the left-hand-side of an assignment must have a statically known size error[E0277]: the type `str` cannot be indexed by `usize` @@ -28,8 +28,8 @@ error[E0277]: the type `str` cannot be indexed by `usize` LL | s[1usize] = bot(); | ^^^^^^^^^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `usize` - = note: required because of the requirements on the impl of `std::ops::Index` for `str` + = help: the trait `SliceIndex` is not implemented for `usize` + = note: required because of the requirements on the impl of `Index` for `str` error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-mut-idx.rs:9:15 @@ -37,9 +37,9 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | s.get_mut(1); | ^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-mut-idx.rs:11:25 @@ -47,9 +47,9 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | s.get_unchecked_mut(1); | ^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `char` --> $DIR/str-mut-idx.rs:13:5 @@ -57,8 +57,8 @@ error[E0277]: the type `str` cannot be indexed by `char` LL | s['c']; | ^^^^^^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `char` - = note: required because of the requirements on the impl of `std::ops::Index` for `str` + = help: the trait `SliceIndex` is not implemented for `char` + = note: required because of the requirements on the impl of `Index` for `str` error: aborting due to 6 previous errors diff --git a/src/test/ui/string-escapes.rs b/src/test/ui/string-escapes.rs deleted file mode 100644 index cee5e27786..0000000000 --- a/src/test/ui/string-escapes.rs +++ /dev/null @@ -1,7 +0,0 @@ -// run-pass - -fn main() { - let x = "\\\\\ - "; - assert_eq!(x, r"\\"); // extraneous whitespace stripped -} diff --git a/src/test/ui/structs/struct-field-cfg.stderr b/src/test/ui/structs/struct-field-cfg.stderr index 29bad31ef9..b913b92907 100644 --- a/src/test/ui/structs/struct-field-cfg.stderr +++ b/src/test/ui/structs/struct-field-cfg.stderr @@ -17,6 +17,15 @@ error[E0027]: pattern does not mention field `present` | LL | let Foo { #[cfg(any())] present: () } = foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present` + | +help: include the missing field in the pattern + | +LL | let Foo { present } = foo; + | ^^^^^^^^^^^ +help: if you don't care about this missing field, you can explicitely ignore it + | +LL | let Foo { .. } = foo; + | ^^^^^^ error[E0026]: struct `Foo` does not have a field named `absent` --> $DIR/struct-field-cfg.rs:16:42 diff --git a/src/test/ui/structs/struct-field-privacy.rs b/src/test/ui/structs/struct-field-privacy.rs index 5c35c04a69..898ca475cb 100644 --- a/src/test/ui/structs/struct-field-privacy.rs +++ b/src/test/ui/structs/struct-field-privacy.rs @@ -32,7 +32,7 @@ fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B, z: inner::Z) { e.b; //~ ERROR: field `b` of struct `xc::B` is private z.0; - z.1; //~ ERROR: field `1` of struct `inner::Z` is private + z.1; //~ ERROR: field `1` of struct `Z` is private } fn main() {} diff --git a/src/test/ui/structs/struct-field-privacy.stderr b/src/test/ui/structs/struct-field-privacy.stderr index f8b16ec0d0..ee83e0d6c2 100644 --- a/src/test/ui/structs/struct-field-privacy.stderr +++ b/src/test/ui/structs/struct-field-privacy.stderr @@ -22,7 +22,7 @@ error[E0616]: field `b` of struct `xc::B` is private LL | e.b; | ^ private field -error[E0616]: field `1` of struct `inner::Z` is private +error[E0616]: field `1` of struct `Z` is private --> $DIR/struct-field-privacy.rs:35:7 | LL | z.1; diff --git a/src/test/ui/structs/struct-pat-derived-error.stderr b/src/test/ui/structs/struct-pat-derived-error.stderr index 6526ef58a4..f3e9ce76f1 100644 --- a/src/test/ui/structs/struct-pat-derived-error.stderr +++ b/src/test/ui/structs/struct-pat-derived-error.stderr @@ -15,6 +15,15 @@ error[E0027]: pattern does not mention fields `b`, `c` | LL | let A { x, y } = self.d; | ^^^^^^^^^^ missing fields `b`, `c` + | +help: include the missing fields in the pattern + | +LL | let A { x, y, b, c } = self.d; + | ^^^^^^ +help: if you don't care about these missing fields, you can explicitely ignore them + | +LL | let A { x, y, .. } = self.d; + | ^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/structs/struct-path-alias-bounds.rs b/src/test/ui/structs/struct-path-alias-bounds.rs index ae6ca80826..1e2c4b836a 100644 --- a/src/test/ui/structs/struct-path-alias-bounds.rs +++ b/src/test/ui/structs/struct-path-alias-bounds.rs @@ -7,5 +7,5 @@ type A = S; fn main() { let s = A { a: NoClone }; - //~^ ERROR the trait bound `NoClone: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `NoClone: Clone` is not satisfied } diff --git a/src/test/ui/structs/struct-path-alias-bounds.stderr b/src/test/ui/structs/struct-path-alias-bounds.stderr index 1c2c205e01..cea3d5d4df 100644 --- a/src/test/ui/structs/struct-path-alias-bounds.stderr +++ b/src/test/ui/structs/struct-path-alias-bounds.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `NoClone: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NoClone: Clone` is not satisfied --> $DIR/struct-path-alias-bounds.rs:9:13 | LL | struct S { a: T } | ------------------ required by `S` ... LL | let s = A { a: NoClone }; - | ^ the trait `std::clone::Clone` is not implemented for `NoClone` + | ^ the trait `Clone` is not implemented for `NoClone` error: aborting due to previous error diff --git a/src/test/ui/substs-ppaux.normal.stderr b/src/test/ui/substs-ppaux.normal.stderr index 8dab8add80..89be3d29e0 100644 --- a/src/test/ui/substs-ppaux.normal.stderr +++ b/src/test/ui/substs-ppaux.normal.stderr @@ -79,7 +79,7 @@ LL | fn bar<'a, T>() where T: 'a {} LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: required because of the requirements on the impl of `Foo<'_, '_, u8>` for `str` error: aborting due to 5 previous errors diff --git a/src/test/ui/substs-ppaux.verbose.stderr b/src/test/ui/substs-ppaux.verbose.stderr index a40d5e4bf7..e37d087fcc 100644 --- a/src/test/ui/substs-ppaux.verbose.stderr +++ b/src/test/ui/substs-ppaux.verbose.stderr @@ -79,7 +79,7 @@ LL | fn bar<'a, T>() where T: 'a {} LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: required because of the requirements on the impl of `Foo<'_#0r, '_#1r, u8>` for `str` error: aborting due to 5 previous errors diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr index f4c0d0f96c..9450612332 100644 --- a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr +++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr @@ -5,7 +5,7 @@ LL | struct X(T); | - required by this bound in `X` ... LL | struct Struct5{ - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | _t: X, | ^^^^ doesn't have a size known at compile-time | @@ -28,8 +28,8 @@ LL | struct Struct1{ | help: consider further restricting `Self` | -LL | fn func1() -> Struct1 where Self: std::marker::Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn func1() -> Struct1 where Self: Sized; + | ^^^^^^^^^^^^^^^^^ help: consider relaxing the implicit `Sized` restriction | LL | struct Struct1{ @@ -46,8 +46,8 @@ LL | struct Struct2<'a, T>{ | help: consider further restricting `Self` | -LL | fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn func2<'a>() -> Struct2<'a, Self> where Self: Sized; + | ^^^^^^^^^^^^^^^^^ help: consider relaxing the implicit `Sized` restriction | LL | struct Struct2<'a, T: ?Sized>{ @@ -71,8 +71,8 @@ LL | _t: T, | - ...if indirection was used here: `Box` help: consider further restricting `Self` | -LL | fn func3() -> Struct3 where Self: std::marker::Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn func3() -> Struct3 where Self: Sized; + | ^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `Self` cannot be known at compilation time --> $DIR/adt-param-with-implicit-sized-bound.rs:5:19 @@ -85,8 +85,8 @@ LL | struct Struct4{ | help: consider further restricting `Self` | -LL | fn func4() -> Struct4 where Self: std::marker::Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn func4() -> Struct4 where Self: Sized; + | ^^^^^^^^^^^^^^^^^ help: consider relaxing the implicit `Sized` restriction | LL | struct Struct4{ diff --git a/src/test/ui/suggestions/as-ref.stderr b/src/test/ui/suggestions/as-ref.stderr index 8445a706f4..4b5a9be7e5 100644 --- a/src/test/ui/suggestions/as-ref.stderr +++ b/src/test/ui/suggestions/as-ref.stderr @@ -36,12 +36,12 @@ error[E0308]: mismatched types LL | let y: Option<&usize> = x; | -------------- ^ | | | - | | expected enum `std::option::Option`, found reference + | | expected enum `Option`, found `&Option` | | help: you can convert from `&Option` to `Option<&T>` using `.as_ref()`: `x.as_ref()` | expected due to this | - = note: expected enum `std::option::Option<&usize>` - found reference `&std::option::Option` + = note: expected enum `Option<&usize>` + found reference `&Option` error[E0308]: mismatched types --> $DIR/as-ref.rs:19:35 diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 1137249477..cb4acc4c39 100644 --- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -1,4 +1,4 @@ -error[E0277]: `fn() -> impl std::future::Future {foo}` is not a future +error[E0277]: `fn() -> impl Future {foo}` is not a future --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9 | LL | async fn foo() {} @@ -8,9 +8,9 @@ LL | fn bar(f: impl Future) {} | ----------------- required by this bound in `bar` ... LL | bar(foo); - | ^^^ `fn() -> impl std::future::Future {foo}` is not a future + | ^^^ `fn() -> impl Future {foo}` is not a future | - = help: the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}` + = help: the trait `Future` is not implemented for `fn() -> impl Future {foo}` help: use parentheses to call the function | LL | bar(foo()); @@ -27,7 +27,7 @@ LL | let async_closure = async || (); LL | bar(async_closure); | ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future | - = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` + = help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` help: use parentheses to call the closure | LL | bar(async_closure()); diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr index 36bced9e43..de342a969f 100644 --- a/src/test/ui/suggestions/borrow-for-loop-head.stderr +++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr @@ -10,7 +10,7 @@ error[E0382]: use of moved value: `a` --> $DIR/borrow-for-loop-head.rs:4:18 | LL | let a = vec![1, 2, 3]; - | - move occurs because `a` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `a` has type `Vec`, which does not implement the `Copy` trait LL | for i in &a { LL | for j in a { | ^ diff --git a/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr b/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr index 63e3bb7895..965dbb9679 100644 --- a/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr +++ b/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr @@ -2,9 +2,9 @@ error[E0308]: mismatched types --> $DIR/chain-method-call-mutation-in-place.rs:3:5 | LL | fn foo(mut s: String) -> String { - | ------ expected `std::string::String` because of return type + | ------ expected `String` because of return type LL | s.push_str("asdf") - | ^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found `()` + | ^^^^^^^^^^^^^^^^^^ expected struct `String`, found `()` | note: method `push_str` modifies its receiver in-place --> $DIR/chain-method-call-mutation-in-place.rs:3:7 diff --git a/src/test/ui/suggestions/const-in-struct-pat.stderr b/src/test/ui/suggestions/const-in-struct-pat.stderr index ab336b14d2..df9c230eef 100644 --- a/src/test/ui/suggestions/const-in-struct-pat.stderr +++ b/src/test/ui/suggestions/const-in-struct-pat.stderr @@ -7,7 +7,7 @@ LL | struct foo; LL | let Thing { foo } = t; | ^^^ - this expression has type `Thing` | | - | expected struct `std::string::String`, found struct `foo` + | expected struct `String`, found struct `foo` | `foo` is interpreted as a unit struct, not a new binding | help: bind the struct field to a different name instead diff --git a/src/test/ui/suggestions/const-no-type.rs b/src/test/ui/suggestions/const-no-type.rs index b931a04c28..2ffb24c6e6 100644 --- a/src/test/ui/suggestions/const-no-type.rs +++ b/src/test/ui/suggestions/const-no-type.rs @@ -43,7 +43,7 @@ const D = &&42; static S = Vec::::new(); //~^ ERROR missing type for `static` item //~| HELP provide a type for the item -//~| SUGGESTION S: std::vec::Vec +//~| SUGGESTION S: Vec static mut SM = "abc"; //~^ ERROR missing type for `static mut` item diff --git a/src/test/ui/suggestions/const-no-type.stderr b/src/test/ui/suggestions/const-no-type.stderr index 874c1bac10..b180a6a9a9 100644 --- a/src/test/ui/suggestions/const-no-type.stderr +++ b/src/test/ui/suggestions/const-no-type.stderr @@ -14,7 +14,7 @@ error: missing type for `static` item --> $DIR/const-no-type.rs:43:8 | LL | static S = Vec::::new(); - | ^ help: provide a type for the item: `S: std::vec::Vec` + | ^ help: provide a type for the item: `S: Vec` error: missing type for `static mut` item --> $DIR/const-no-type.rs:48:12 diff --git a/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr index b0cef952b2..0123e617c4 100644 --- a/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr +++ b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | / intrinsic_match! { LL | | "abc" LL | | }; - | |______^ expected `&str`, found struct `std::string::String` + | |______^ expected `&str`, found struct `String` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr index 5550e097cf..f7528b5ccd 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr @@ -112,7 +112,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:102:17 | LL | let X(_t) = vs[0]; @@ -121,7 +121,7 @@ LL | let X(_t) = vs[0]; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:106:30 | LL | if let Either::One(_t) = vr[0] { } @@ -130,7 +130,7 @@ LL | if let Either::One(_t) = vr[0] { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:110:33 | LL | while let Either::One(_t) = vr[0] { } @@ -139,7 +139,7 @@ LL | while let Either::One(_t) = vr[0] { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:114:11 | LL | match vr[0] { @@ -151,7 +151,7 @@ LL | Either::One(_t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:121:11 | LL | match vr[0] { @@ -163,7 +163,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:130:17 | LL | let X(_t) = vsm[0]; @@ -172,7 +172,7 @@ LL | let X(_t) = vsm[0]; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:134:30 | LL | if let Either::One(_t) = vrm[0] { } @@ -181,7 +181,7 @@ LL | if let Either::One(_t) = vrm[0] { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:138:33 | LL | while let Either::One(_t) = vrm[0] { } @@ -190,7 +190,7 @@ LL | while let Either::One(_t) = vrm[0] { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:142:11 | LL | match vrm[0] { @@ -202,7 +202,7 @@ LL | Either::One(_t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:149:11 | LL | match vrm[0] { @@ -214,7 +214,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:157:11 | LL | match vrm[0] { diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index baa84115e2..32961b7f87 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -2,27 +2,27 @@ error[E0308]: mismatched types --> $DIR/expected-boxed-future-isnt-pinned.rs:11:5 | LL | fn foo + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - | - this type parameter ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type + | - this type parameter ----------------------- expected `Pin + Send + 'static)>>` because of return type LL | // We could instead use an `async` block, but this way we have no std spans. LL | x | ^ | | - | expected struct `std::pin::Pin`, found type parameter `F` + | expected struct `Pin`, found type parameter `F` | help: you need to pin and box this expression: `Box::pin(x)` | - = note: expected struct `std::pin::Pin + std::marker::Send + 'static)>>` + = note: expected struct `Pin + Send + 'static)>>` found type parameter `F` error[E0308]: mismatched types --> $DIR/expected-boxed-future-isnt-pinned.rs:18:5 | LL | fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - | ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type + | ----------------------- expected `Pin + Send + 'static)>>` because of return type LL | Box::new(x) - | ^^^^^^^^^^^ expected struct `std::pin::Pin`, found struct `std::boxed::Box` + | ^^^^^^^^^^^ expected struct `Pin`, found struct `Box` | - = note: expected struct `std::pin::Pin + std::marker::Send + 'static)>>` - found struct `std::boxed::Box` + = note: expected struct `Pin + Send + 'static)>>` + found struct `Box` = help: use `Box::pin` error[E0308]: mismatched types @@ -33,48 +33,46 @@ LL | fn baz + Send + 'static>(x: F) -> BoxFuture<'static, LL | Pin::new(x) | ^ | | - | expected struct `std::boxed::Box`, found type parameter `F` + | expected struct `Box`, found type parameter `F` | help: store this in the heap by calling `Box::new`: `Box::new(x)` | - = note: expected struct `std::boxed::Box + std::marker::Send>` + = note: expected struct `Box + Send>` found type parameter `F` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html -error[E0277]: `dyn std::future::Future + std::marker::Send` cannot be unpinned +error[E0277]: `dyn Future + Send` cannot be unpinned --> $DIR/expected-boxed-future-isnt-pinned.rs:22:5 | LL | Pin::new(x) - | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` + | ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future + Send` | - = note: consider using `Box::pin` - = note: required by `std::pin::Pin::

    ::new` + = note: required by `Pin::

    ::new` -error[E0277]: `dyn std::future::Future + std::marker::Send` cannot be unpinned +error[E0277]: `dyn Future + Send` cannot be unpinned --> $DIR/expected-boxed-future-isnt-pinned.rs:27:5 | LL | Pin::new(Box::new(x)) - | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` + | ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future + Send` | - = note: consider using `Box::pin` - = note: required by `std::pin::Pin::

    ::new` + = note: required by `Pin::

    ::new` error[E0308]: mismatched types --> $DIR/expected-boxed-future-isnt-pinned.rs:31:5 | LL | fn zap() -> BoxFuture<'static, i32> { - | ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type + | ----------------------- expected `Pin + Send + 'static)>>` because of return type LL | / async { LL | | 42 LL | | } - | |_____^ expected struct `std::pin::Pin`, found opaque type + | |_____^ expected struct `Pin`, found opaque type | ::: $SRC_DIR/core/src/future/mod.rs:LL:COL | LL | pub const fn from_generator(gen: T) -> impl Future | ------------------------------- the found opaque type | - = note: expected struct `std::pin::Pin + std::marker::Send + 'static)>>` - found opaque type `impl std::future::Future` + = note: expected struct `Pin + Send + 'static)>>` + found opaque type `impl Future` help: you need to pin and box this expression | LL | Box::pin(async { diff --git a/src/test/ui/suggestions/for-i-in-vec.stderr b/src/test/ui/suggestions/for-i-in-vec.stderr index 576a7cc2f6..48f3f423ac 100644 --- a/src/test/ui/suggestions/for-i-in-vec.stderr +++ b/src/test/ui/suggestions/for-i-in-vec.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `self.v` which is behind a shared reference LL | for _ in self.v { | ^^^^^^ | | - | move occurs because `self.v` has type `std::vec::Vec`, which does not implement the `Copy` trait + | move occurs because `self.v` has type `Vec`, which does not implement the `Copy` trait | help: consider iterating over a slice of the `Vec<_>`'s content: `&self.v` error: aborting due to previous error diff --git a/src/test/ui/suggestions/format-borrow.stderr b/src/test/ui/suggestions/format-borrow.stderr index 44fac16260..05d8fcd3ed 100644 --- a/src/test/ui/suggestions/format-borrow.stderr +++ b/src/test/ui/suggestions/format-borrow.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let a: String = &String::from("a"); | ------ ^^^^^^^^^^^^^^^^^^ | | | - | | expected struct `std::string::String`, found `&std::string::String` + | | expected struct `String`, found `&String` | | help: consider removing the borrow: `String::from("a")` | expected due to this @@ -14,7 +14,7 @@ error[E0308]: mismatched types LL | let b: String = &format!("b"); | ------ ^^^^^^^^^^^^^ | | | - | | expected struct `std::string::String`, found `&std::string::String` + | | expected struct `String`, found `&String` | | help: consider removing the borrow: `format!("b")` | expected due to this diff --git a/src/test/ui/suggestions/if-let-typo.rs b/src/test/ui/suggestions/if-let-typo.rs new file mode 100644 index 0000000000..87def13c47 --- /dev/null +++ b/src/test/ui/suggestions/if-let-typo.rs @@ -0,0 +1,8 @@ +fn main() { + let foo = Some(0); + let bar = None; + if Some(x) = foo {} //~ ERROR cannot find value `x` in this scope + if Some(foo) = bar {} //~ ERROR mismatched types + if 3 = foo {} //~ ERROR mismatched types + if Some(3) = foo {} //~ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/if-let-typo.stderr b/src/test/ui/suggestions/if-let-typo.stderr new file mode 100644 index 0000000000..d8e50cae55 --- /dev/null +++ b/src/test/ui/suggestions/if-let-typo.stderr @@ -0,0 +1,56 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/if-let-typo.rs:4:13 + | +LL | if Some(x) = foo {} + | ^ not found in this scope + | +help: you might have meant to use pattern matching + | +LL | if let Some(x) = foo {} + | ^^^ + +error[E0308]: mismatched types + --> $DIR/if-let-typo.rs:5:8 + | +LL | if Some(foo) = bar {} + | ^^^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let Some(foo) = bar {} + | ^^^ +help: you might have meant to compare for equality + | +LL | if Some(foo) == bar {} + | ^^ + +error[E0308]: mismatched types + --> $DIR/if-let-typo.rs:6:8 + | +LL | if 3 = foo {} + | ^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let 3 = foo {} + | ^^^ + +error[E0308]: mismatched types + --> $DIR/if-let-typo.rs:7:8 + | +LL | if Some(3) = foo {} + | ^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let Some(3) = foo {} + | ^^^ +help: you might have meant to compare for equality + | +LL | if Some(3) == foo {} + | ^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0425. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/imm-ref-trait-object.stderr b/src/test/ui/suggestions/imm-ref-trait-object.stderr index cbaed41cf9..9f89dcd912 100644 --- a/src/test/ui/suggestions/imm-ref-trait-object.stderr +++ b/src/test/ui/suggestions/imm-ref-trait-object.stderr @@ -9,7 +9,7 @@ LL | t.min().unwrap() LL | Self: Sized, | ----- this has a `Sized` requirement | - = note: you need `&mut dyn std::iter::Iterator` instead of `&dyn std::iter::Iterator` + = note: you need `&mut dyn Iterator` instead of `&dyn Iterator` error: aborting due to previous error diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs index 6e9e8821cf..d401328077 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs @@ -4,7 +4,7 @@ fn foo(constraints: impl Iterator) { for constraint in constraints { qux(constraint); -//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` +//~^ ERROR `::Item` doesn't implement `Debug` } } @@ -12,7 +12,7 @@ fn bar(t: T, constraints: impl Iterator) where T: std::fmt::Debug { for constraint in constraints { qux(t); qux(constraint); -//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` +//~^ ERROR `::Item` doesn't implement `Debug` } } @@ -20,7 +20,7 @@ fn baz(t: impl std::fmt::Debug, constraints: impl Iterator) { for constraint in constraints { qux(t); qux(constraint); -//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` +//~^ ERROR `::Item` doesn't implement `Debug` } } @@ -28,14 +28,14 @@ fn bat(t: T, constraints: impl Iterator, _: I) { for constraint in constraints { qux(t); qux(constraint); -//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` +//~^ ERROR `::Item` doesn't implement `Debug` } } fn bak(constraints: impl Iterator + std::fmt::Debug) { for constraint in constraints { qux(constraint); -//~^ ERROR `::Item` doesn't implement +//~^ ERROR `::Item` doesn't implement } } diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr index fb0914a874..099eb1c9d0 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -1,77 +1,77 @@ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:6:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn foo(constraints: I) where ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo(constraints: I) where ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:14:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn bar(t: T, constraints: I) where T: std::fmt::Debug, ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(t: T, constraints: I) where T: std::fmt::Debug, ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:22:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn baz(t: impl std::fmt::Debug, constraints: I) where ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn baz(t: impl std::fmt::Debug, constraints: I) where ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:30:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn bat(t: T, constraints: U, _: I) where ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bat(t: T, constraints: U, _: I) where ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:37:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn bak(constraints: I) where ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bak(constraints: I) where ::Item: Debug { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/suggestions/into-str.rs b/src/test/ui/suggestions/into-str.rs index 9793ee801d..606e44b2eb 100644 --- a/src/test/ui/suggestions/into-str.rs +++ b/src/test/ui/suggestions/into-str.rs @@ -2,5 +2,5 @@ fn foo<'a, T>(_t: T) where T: Into<&'a str> {} fn main() { foo(String::new()); - //~^ ERROR the trait bound `&str: std::convert::From` is not satisfied + //~^ ERROR the trait bound `&str: From` is not satisfied } diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr index f7affdbf1b..2854b830ba 100644 --- a/src/test/ui/suggestions/into-str.stderr +++ b/src/test/ui/suggestions/into-str.stderr @@ -1,14 +1,13 @@ -error[E0277]: the trait bound `&str: std::convert::From` is not satisfied +error[E0277]: the trait bound `&str: From` is not satisfied --> $DIR/into-str.rs:4:5 | LL | fn foo<'a, T>(_t: T) where T: Into<&'a str> {} | ------------- required by this bound in `foo` ... LL | foo(String::new()); - | ^^^ the trait `std::convert::From` is not implemented for `&str` + | ^^^ the trait `From` is not implemented for `&str` | - = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix - = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String` + = note: required because of the requirements on the impl of `Into<&str>` for `String` error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-52820.stderr b/src/test/ui/suggestions/issue-52820.stderr index 5ad6597b82..ece784de3e 100644 --- a/src/test/ui/suggestions/issue-52820.stderr +++ b/src/test/ui/suggestions/issue-52820.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | guts, | ^^^^ | | - | expected struct `std::string::String`, found `&str` + | expected struct `String`, found `&str` | help: try using a conversion method: `guts: guts.to_string()` error[E0308]: mismatched types @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | brains: guts.clone(), | ^^^^^^^^^^^^ | | - | expected struct `std::string::String`, found `&str` + | expected struct `String`, found `&str` | help: try using a conversion method: `guts.to_string()` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-59819.stderr b/src/test/ui/suggestions/issue-59819.stderr index b20327a9ff..43e0016ee2 100644 --- a/src/test/ui/suggestions/issue-59819.stderr +++ b/src/test/ui/suggestions/issue-59819.stderr @@ -24,7 +24,7 @@ error[E0308]: mismatched types LL | let g: String = f; | ------ ^ | | | - | | expected struct `std::string::String`, found struct `Bar` + | | expected struct `String`, found struct `Bar` | | help: try using a conversion method: `f.to_string()` | expected due to this diff --git a/src/test/ui/suggestions/issue-62843.stderr b/src/test/ui/suggestions/issue-62843.stderr index 3b7f85c566..b2be09a4c7 100644 --- a/src/test/ui/suggestions/issue-62843.stderr +++ b/src/test/ui/suggestions/issue-62843.stderr @@ -1,14 +1,14 @@ -error[E0277]: expected a `std::ops::FnMut<(char,)>` closure, found `std::string::String` +error[E0277]: expected a `FnMut<(char,)>` closure, found `String` --> $DIR/issue-62843.rs:4:32 | LL | println!("{:?}", line.find(pattern)); | ^^^^^^^ | | - | expected an implementor of trait `std::str::pattern::Pattern<'_>` + | expected an implementor of trait `Pattern<'_>` | help: consider borrowing here: `&pattern` | - = note: the trait bound `std::string::String: std::str::pattern::Pattern<'_>` is not satisfied - = note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `std::string::String` + = note: the trait bound `String: Pattern<'_>` is not satisfied + = note: required because of the requirements on the impl of `Pattern<'_>` for `String` error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.rs b/src/test/ui/suggestions/issue-71394-no-from-impl.rs index 9ffcc3f7bc..0c35deb51e 100644 --- a/src/test/ui/suggestions/issue-71394-no-from-impl.rs +++ b/src/test/ui/suggestions/issue-71394-no-from-impl.rs @@ -1,5 +1,5 @@ fn main() { let data: &[u8] = &[0; 10]; let _: &[i8] = data.into(); - //~^ ERROR the trait bound `&[i8]: std::convert::From<&[u8]>` is not satisfied + //~^ ERROR the trait bound `&[i8]: From<&[u8]>` is not satisfied } diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr index 84c73c2f67..355f2038df 100644 --- a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `&[i8]: std::convert::From<&[u8]>` is not satisfied +error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied --> $DIR/issue-71394-no-from-impl.rs:3:25 | LL | let _: &[i8] = data.into(); - | ^^^^ the trait `std::convert::From<&[u8]>` is not implemented for `&[i8]` + | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]` | - = note: required because of the requirements on the impl of `std::convert::Into<&[i8]>` for `&[u8]` + = note: required because of the requirements on the impl of `Into<&[i8]>` for `&[u8]` error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-72766.stderr b/src/test/ui/suggestions/issue-72766.stderr index 4290f3b4bf..a1a5949b19 100644 --- a/src/test/ui/suggestions/issue-72766.stderr +++ b/src/test/ui/suggestions/issue-72766.stderr @@ -1,14 +1,14 @@ -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/issue-72766.rs:14:5 | LL | SadGirl {}.call()?; | ^^^^^^^^^^^^^^^^^^ | | - | the `?` operator cannot be applied to type `impl std::future::Future` + | the `?` operator cannot be applied to type `impl Future` | help: consider using `.await` here: `SadGirl {}.call().await?` | - = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `impl Future` + = note: required by `into_result` error: aborting due to previous error diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index cec01fefca..69e95efa72 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -41,7 +41,7 @@ LL | | LL | | where LL | | G: Get | |_____________^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6 g:G, dest:&mut T]` will meet its required lifetime bounds +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6]` will meet its required lifetime bounds --> $DIR/missing-lifetimes-in-signature.rs:25:37 | LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ @@ -65,7 +65,7 @@ LL | | LL | | where LL | | G: Get | |_____________^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6 g:G, dest:&mut T]` will meet its required lifetime bounds +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6]` will meet its required lifetime bounds --> $DIR/missing-lifetimes-in-signature.rs:47:45 | LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ @@ -86,7 +86,7 @@ note: the parameter type `G` must be valid for the anonymous lifetime #1 defined | LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10 g:G, dest:&mut T]` will meet its required lifetime bounds +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10]` will meet its required lifetime bounds --> $DIR/missing-lifetimes-in-signature.rs:59:58 | LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { @@ -108,7 +108,7 @@ error[E0309]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:79:44 | LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6 g:G, dest:&mut T]` will meet its required lifetime bounds + | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6]` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `G: 'a` diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index 559a2d2955..ca7562beb1 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -12,17 +12,17 @@ LL | [&v] => {}, = note: expected type `i32` found reference `&_` -error[E0529]: expected an array or slice, found `std::vec::Vec` +error[E0529]: expected an array or slice, found `Vec` --> $DIR/match-ergonomics.rs:8:9 | LL | [&v] => {}, - | ^^^^ pattern cannot match with input type `std::vec::Vec` + | ^^^^ pattern cannot match with input type `Vec` -error[E0529]: expected an array or slice, found `std::vec::Vec` +error[E0529]: expected an array or slice, found `Vec` --> $DIR/match-ergonomics.rs:20:9 | LL | [v] => {}, - | ^^^ pattern cannot match with input type `std::vec::Vec` + | ^^^ pattern cannot match with input type `Vec` error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:29:9 diff --git a/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed index 64a1aeae3e..a0cb39a3f8 100644 --- a/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed +++ b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed @@ -13,7 +13,7 @@ struct S; struct Type; impl TraitA<()> for S { //~ ERROR not all trait items implemented -fn baz(_: T) -> Self where T: TraitB, ::Item: std::marker::Copy { todo!() } +fn baz(_: T) -> Self where T: TraitB, ::Item: Copy { todo!() } fn bar(_: T) -> Self { todo!() } type Type = Type; } diff --git a/src/test/ui/suggestions/missing-assoc-fn.stderr b/src/test/ui/suggestions/missing-assoc-fn.stderr index 4f75e2b838..136ec2152e 100644 --- a/src/test/ui/suggestions/missing-assoc-fn.stderr +++ b/src/test/ui/suggestions/missing-assoc-fn.stderr @@ -28,7 +28,7 @@ error[E0046]: not all trait items implemented, missing: `from_iter` LL | impl FromIterator<()> for X { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_iter` in implementation | - = help: implement the missing item: `fn from_iter(_: T) -> Self where T: std::iter::IntoIterator, std::iter::IntoIterator::Item = A { todo!() }` + = help: implement the missing item: `fn from_iter(_: T) -> Self where T: IntoIterator, std::iter::IntoIterator::Item = A { todo!() }` error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr index c6d94826c0..eb695379b5 100644 --- a/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr +++ b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr @@ -10,12 +10,12 @@ LL | self.foo(); = note: the method `foo` exists but the following trait bounds were not satisfied: `T: Bar` which is required by `Foo: Bar` - `T: std::default::Default` + `T: Default` which is required by `Foo: Bar` help: consider restricting the type parameters to satisfy the trait bounds | -LL | struct Foo where T: Bar, T: std::default::Default { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct Foo where T: Bar, T: Default { + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: no method named `foo` found for reference `&Fin` in the current scope --> $DIR/missing-trait-bounds-for-method-call.rs:27:14 @@ -27,12 +27,12 @@ LL | self.foo(); | ^^^ method not found in `&Fin` | = note: the method `foo` exists but the following trait bounds were not satisfied: - `T: std::default::Default` + `T: Default` which is required by `Fin: Bar` help: consider restricting the type parameter to satisfy the trait bound | -LL | struct Fin where T: Bar, T: std::default::Default { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct Fin where T: Bar, T: Default { + | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index c3bb37cf83..c1eea56f70 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -5,7 +5,7 @@ LL | let fp = BufWriter::new(fp); | ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` - = note: required by `std::io::BufWriter::::new` + = note: required by `BufWriter::::new` error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied --> $DIR/mut-borrow-needed-by-trait.rs:17:14 @@ -16,7 +16,7 @@ LL | let fp = BufWriter::new(fp); ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL | LL | pub struct BufWriter { - | ----- required by this bound in `std::io::BufWriter` + | ----- required by this bound in `BufWriter` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` @@ -29,24 +29,24 @@ LL | let fp = BufWriter::new(fp); ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL | LL | pub struct BufWriter { - | ----- required by this bound in `std::io::BufWriter` + | ----- required by this bound in `BufWriter` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` -error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<&dyn std::io::Write>` in the current scope +error[E0599]: no method named `write_fmt` found for struct `BufWriter<&dyn std::io::Write>` in the current scope --> $DIR/mut-borrow-needed-by-trait.rs:22:5 | LL | writeln!(fp, "hello world").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `BufWriter<&dyn std::io::Write>` | ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL | LL | pub struct BufWriter { - | ------------------------------ doesn't satisfy `_: std::io::Write` + | ------------------------------ doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write` | = note: the method `write_fmt` exists but the following trait bounds were not satisfied: `&dyn std::io::Write: std::io::Write` - which is required by `std::io::BufWriter<&dyn std::io::Write>: std::io::Write` + which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/mut-ref-reassignment.stderr b/src/test/ui/suggestions/mut-ref-reassignment.stderr index e774800849..e31c4dc66c 100644 --- a/src/test/ui/suggestions/mut-ref-reassignment.stderr +++ b/src/test/ui/suggestions/mut-ref-reassignment.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/mut-ref-reassignment.rs:2:11 | LL | opt = None; - | ^^^^ expected mutable reference, found enum `std::option::Option` + | ^^^^ expected mutable reference, found enum `Option` | - = note: expected mutable reference `&mut std::option::Option` - found enum `std::option::Option<_>` + = note: expected mutable reference `&mut Option` + found enum `Option<_>` help: consider dereferencing here to assign to the mutable borrowed piece of memory | LL | *opt = None; @@ -15,19 +15,19 @@ error[E0308]: mismatched types --> $DIR/mut-ref-reassignment.rs:6:11 | LL | opt = None - | ^^^^ expected mutable reference, found enum `std::option::Option` + | ^^^^ expected mutable reference, found enum `Option` | - = note: expected mutable reference `&mut std::result::Result` - found enum `std::option::Option<_>` + = note: expected mutable reference `&mut std::result::Result` + found enum `Option<_>` error[E0308]: mismatched types --> $DIR/mut-ref-reassignment.rs:10:11 | LL | opt = Some(String::new()) - | ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `std::option::Option` + | ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `Option` | - = note: expected mutable reference `&mut std::option::Option` - found enum `std::option::Option` + = note: expected mutable reference `&mut Option` + found enum `Option` help: consider dereferencing here to assign to the mutable borrowed piece of memory | LL | *opt = Some(String::new()) @@ -37,10 +37,10 @@ error[E0308]: mismatched types --> $DIR/mut-ref-reassignment.rs:14:11 | LL | opt = Some(42) - | ^^^^^^^^ expected mutable reference, found enum `std::option::Option` + | ^^^^^^^^ expected mutable reference, found enum `Option` | - = note: expected mutable reference `&mut std::option::Option` - found enum `std::option::Option<{integer}>` + = note: expected mutable reference `&mut Option` + found enum `Option<{integer}>` error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/opaque-type-error.stderr b/src/test/ui/suggestions/opaque-type-error.stderr index 167d61bdf7..a7c2b82942 100644 --- a/src/test/ui/suggestions/opaque-type-error.stderr +++ b/src/test/ui/suggestions/opaque-type-error.stderr @@ -13,10 +13,9 @@ LL | | thing_two() LL | | }.await | |_____- `if` and `else` have incompatible types | - = note: expected type `impl std::future::Future` (opaque type at <$DIR/opaque-type-error.rs:8:19>) - found opaque type `impl std::future::Future` (opaque type at <$DIR/opaque-type-error.rs:12:19>) + = note: expected type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:8:19>) + found opaque type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:12:19>) = note: distinct uses of `impl Trait` result in different opaque types - = help: if both `Future`s have the same `Output` type, consider `.await`ing on both of them error: aborting due to previous error diff --git a/src/test/ui/suggestions/option-content-move.stderr b/src/test/ui/suggestions/option-content-move.stderr index c842e7b293..0f3dd346e8 100644 --- a/src/test/ui/suggestions/option-content-move.stderr +++ b/src/test/ui/suggestions/option-content-move.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared referenc LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ | | - | move occurs because `selection.1` has type `std::option::Option`, which does not implement the `Copy` trait + | move occurs because `selection.1` has type `Option`, which does not implement the `Copy` trait | help: consider borrowing the `Option`'s content: `selection.1.as_ref()` error[E0507]: cannot move out of `selection.1` which is behind a shared reference @@ -13,7 +13,7 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared referenc LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ | | - | move occurs because `selection.1` has type `std::result::Result`, which does not implement the `Copy` trait + | move occurs because `selection.1` has type `std::result::Result`, which does not implement the `Copy` trait | help: consider borrowing the `Result`'s content: `selection.1.as_ref()` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr index 71f745374e..cfbee1518c 100644 --- a/src/test/ui/suggestions/option-content-move2.stderr +++ b/src/test/ui/suggestions/option-content-move2.stderr @@ -10,7 +10,7 @@ LL | LL | var = Some(NotCopyable); | --- | | - | move occurs because `var` has type `std::option::Option`, which does not implement the `Copy` trait + | move occurs because `var` has type `Option`, which does not implement the `Copy` trait | move occurs due to use in closure error: aborting due to previous error diff --git a/src/test/ui/suggestions/path-by-value.stderr b/src/test/ui/suggestions/path-by-value.stderr index 2b7c29e20c..ea0c63ac25 100644 --- a/src/test/ui/suggestions/path-by-value.stderr +++ b/src/test/ui/suggestions/path-by-value.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn f(p: Path) { } | ^ doesn't have a size known at compile-time | - = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: required because it appears within the type `std::path::Path` + = help: within `Path`, the trait `Sized` is not implemented for `[u8]` + = note: required because it appears within the type `Path` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/suggestions/path-display.stderr b/src/test/ui/suggestions/path-display.stderr index 13546cddbd..b08e22eaab 100644 --- a/src/test/ui/suggestions/path-display.stderr +++ b/src/test/ui/suggestions/path-display.stderr @@ -1,12 +1,12 @@ -error[E0277]: `std::path::Path` doesn't implement `std::fmt::Display` +error[E0277]: `Path` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:5:20 | LL | println!("{}", path); - | ^^^^ `std::path::Path` cannot be formatted with the default formatter; call `.display()` on it + | ^^^^ `Path` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `std::path::Path` - = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data - = note: required because of the requirements on the impl of `std::fmt::Display` for `&std::path::Path` + = help: the trait `std::fmt::Display` is not implemented for `Path` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: required because of the requirements on the impl of `std::fmt::Display` for `&Path` = note: required by `std::fmt::Display::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr b/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr index 163be4cfce..aa621111c0 100644 --- a/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr +++ b/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr @@ -30,7 +30,7 @@ error[E0308]: mismatched types --> $DIR/recover-from-semicolon-trailing-item.rs:12:20 | LL | let _: usize = X {}; - | ----- ^^^^ expected `usize`, found struct `main::X` + | ----- ^^^^ expected `usize`, found struct `X` | | | expected due to this diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr index 33af13d943..7a7242a636 100644 --- a/src/test/ui/suggestions/restrict-type-argument.stderr +++ b/src/test/ui/suggestions/restrict-type-argument.stderr @@ -9,8 +9,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | fn use_impl_sync(val: impl Sync + std::marker::Send) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_impl_sync(val: impl Sync + Send) { + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:8:13 @@ -23,8 +23,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | fn use_where(val: S) where S: Sync + std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_where(val: S) where S: Sync + Send { + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:12:13 @@ -37,8 +37,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | fn use_bound(val: S) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_bound(val: S) { + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:20:13 @@ -51,8 +51,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | Sync + std::marker::Send - | ^^^^^^^^^^^^^^^^^^^ +LL | Sync + Send + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:24:13 @@ -65,8 +65,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | fn use_bound_and_where(val: S) where S: std::fmt::Debug + std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_bound_and_where(val: S) where S: std::fmt::Debug + Send { + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:28:13 @@ -79,8 +79,8 @@ LL | is_send(val); | help: consider restricting type parameter `S` | -LL | fn use_unbound(val: S) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_unbound(val: S) { + | ^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr index 507f822e7b..996d577311 100644 --- a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `hello` found for struct `std::cell::RefMut<'_, HasAssocMethod>` in the current scope +error[E0599]: no method named `hello` found for struct `RefMut<'_, HasAssocMethod>` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11 | LL | state.hello(); diff --git a/src/test/ui/suggestions/suggest-box.stderr b/src/test/ui/suggestions/suggest-box.stderr index 19786bee9c..57c83baf4f 100644 --- a/src/test/ui/suggestions/suggest-box.stderr +++ b/src/test/ui/suggestions/suggest-box.stderr @@ -8,9 +8,9 @@ LL | let _x: Box Result<(), ()>> = || { LL | | Err(())?; LL | | Ok(()) LL | | }; - | |_____^ expected struct `std::boxed::Box`, found closure + | |_____^ expected struct `Box`, found closure | - = note: expected struct `std::boxed::Box std::result::Result<(), ()>>` + = note: expected struct `Box std::result::Result<(), ()>>` found closure `[closure@$DIR/suggest-box.rs:4:47: 7:6]` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html help: store this in the heap by calling `Box::new` diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggestions/suggest-methods.stderr index c343071ac3..535841e535 100644 --- a/src/test/ui/suggestions/suggest-methods.stderr +++ b/src/test/ui/suggestions/suggest-methods.stderr @@ -7,7 +7,7 @@ LL | struct Foo; LL | f.bat(1.0); | ^^^ help: there is an associated function with a similar name: `bar` -error[E0599]: no method named `is_emtpy` found for struct `std::string::String` in the current scope +error[E0599]: no method named `is_emtpy` found for struct `String` in the current scope --> $DIR/suggest-methods.rs:21:15 | LL | let _ = s.is_emtpy(); diff --git a/src/test/ui/suggestions/suggest-private-fields.rs b/src/test/ui/suggestions/suggest-private-fields.rs index 347c8aeed6..8267a82fe2 100644 --- a/src/test/ui/suggestions/suggest-private-fields.rs +++ b/src/test/ui/suggestions/suggest-private-fields.rs @@ -13,9 +13,9 @@ fn main () { // external crate struct let k = B { aa: 20, - //~^ ERROR struct `xc::B` has no field named `aa` + //~^ ERROR struct `B` has no field named `aa` bb: 20, - //~^ ERROR struct `xc::B` has no field named `bb` + //~^ ERROR struct `B` has no field named `bb` }; // local crate struct let l = A { diff --git a/src/test/ui/suggestions/suggest-private-fields.stderr b/src/test/ui/suggestions/suggest-private-fields.stderr index 524558e0ec..d628bd1620 100644 --- a/src/test/ui/suggestions/suggest-private-fields.stderr +++ b/src/test/ui/suggestions/suggest-private-fields.stderr @@ -1,14 +1,14 @@ -error[E0560]: struct `xc::B` has no field named `aa` +error[E0560]: struct `B` has no field named `aa` --> $DIR/suggest-private-fields.rs:15:9 | LL | aa: 20, | ^^ help: a field with a similar name exists: `a` -error[E0560]: struct `xc::B` has no field named `bb` +error[E0560]: struct `B` has no field named `bb` --> $DIR/suggest-private-fields.rs:17:9 | LL | bb: 20, - | ^^ `xc::B` does not have this field + | ^^ `B` does not have this field | = note: available fields are: `a` diff --git a/src/test/ui/suggestions/suggest-remove-refs-1.fixed b/src/test/ui/suggestions/suggest-remove-refs-1.fixed index 042e85b10a..a39e0fbd11 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-1.fixed +++ b/src/test/ui/suggestions/suggest-remove-refs-1.fixed @@ -4,7 +4,7 @@ fn main() { let v = vec![0, 1, 2, 3]; for (i, _) in v.iter().enumerate() { - //~^ ERROR `&std::iter::Enumerate>` is not an iterator + //~^ ERROR `&Enumerate>` is not an iterator println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-1.rs b/src/test/ui/suggestions/suggest-remove-refs-1.rs index 7bdf5dbf35..6f767f2c17 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-1.rs +++ b/src/test/ui/suggestions/suggest-remove-refs-1.rs @@ -4,7 +4,7 @@ fn main() { let v = vec![0, 1, 2, 3]; for (i, _) in &v.iter().enumerate() { - //~^ ERROR `&std::iter::Enumerate>` is not an iterator + //~^ ERROR `&Enumerate>` is not an iterator println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-1.stderr b/src/test/ui/suggestions/suggest-remove-refs-1.stderr index 5be0072fa3..0dd1b2a59e 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-1.stderr +++ b/src/test/ui/suggestions/suggest-remove-refs-1.stderr @@ -1,14 +1,14 @@ -error[E0277]: `&std::iter::Enumerate>` is not an iterator +error[E0277]: `&Enumerate>` is not an iterator --> $DIR/suggest-remove-refs-1.rs:6:19 | LL | for (i, _) in &v.iter().enumerate() { | -^^^^^^^^^^^^^^^^^^^^ | | - | `&std::iter::Enumerate>` is not an iterator + | `&Enumerate>` is not an iterator | help: consider removing the leading `&`-reference | - = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Enumerate>` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&Enumerate>` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-remove-refs-2.fixed b/src/test/ui/suggestions/suggest-remove-refs-2.fixed index bdf47b0e87..0f9c3abfe8 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-2.fixed +++ b/src/test/ui/suggestions/suggest-remove-refs-2.fixed @@ -4,7 +4,7 @@ fn main() { let v = vec![0, 1, 2, 3]; for (i, _) in v.iter().enumerate() { - //~^ ERROR `&&&&&std::iter::Enumerate>` is not an iterator + //~^ ERROR `&&&&&Enumerate>` is not an iterator println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-2.rs b/src/test/ui/suggestions/suggest-remove-refs-2.rs index 3ed56377e1..6c94b12d20 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-2.rs +++ b/src/test/ui/suggestions/suggest-remove-refs-2.rs @@ -4,7 +4,7 @@ fn main() { let v = vec![0, 1, 2, 3]; for (i, _) in & & & & &v.iter().enumerate() { - //~^ ERROR `&&&&&std::iter::Enumerate>` is not an iterator + //~^ ERROR `&&&&&Enumerate>` is not an iterator println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-2.stderr b/src/test/ui/suggestions/suggest-remove-refs-2.stderr index ff84a2ce37..5c2efdb197 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-2.stderr +++ b/src/test/ui/suggestions/suggest-remove-refs-2.stderr @@ -1,14 +1,14 @@ -error[E0277]: `&&&&&std::iter::Enumerate>` is not an iterator +error[E0277]: `&&&&&Enumerate>` is not an iterator --> $DIR/suggest-remove-refs-2.rs:6:19 | LL | for (i, _) in & & & & &v.iter().enumerate() { | ---------^^^^^^^^^^^^^^^^^^^^ | | - | `&&&&&std::iter::Enumerate>` is not an iterator + | `&&&&&Enumerate>` is not an iterator | help: consider removing 5 leading `&`-references | - = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate>` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-remove-refs-3.fixed b/src/test/ui/suggestions/suggest-remove-refs-3.fixed index e0ecafabf3..3148fcbe5d 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-3.fixed +++ b/src/test/ui/suggestions/suggest-remove-refs-3.fixed @@ -6,7 +6,7 @@ fn main() { for (i, _) in v .iter() .enumerate() { - //~^^^^ ERROR `&&&&&std::iter::Enumerate>` is not an + //~^^^^ ERROR `&&&&&Enumerate>` is not an println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-3.rs b/src/test/ui/suggestions/suggest-remove-refs-3.rs index e13099e8c3..0622adada0 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-3.rs +++ b/src/test/ui/suggestions/suggest-remove-refs-3.rs @@ -7,7 +7,7 @@ fn main() { & &v .iter() .enumerate() { - //~^^^^ ERROR `&&&&&std::iter::Enumerate>` is not an + //~^^^^ ERROR `&&&&&Enumerate>` is not an println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-3.stderr b/src/test/ui/suggestions/suggest-remove-refs-3.stderr index d2f7c72b0e..c7fbd3d9bd 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-3.stderr +++ b/src/test/ui/suggestions/suggest-remove-refs-3.stderr @@ -1,4 +1,4 @@ -error[E0277]: `&&&&&std::iter::Enumerate>` is not an iterator +error[E0277]: `&&&&&Enumerate>` is not an iterator --> $DIR/suggest-remove-refs-3.rs:6:19 | LL | for (i, _) in & & & @@ -9,10 +9,10 @@ LL | || & &v | ||___________- help: consider removing 5 leading `&`-references LL | | .iter() LL | | .enumerate() { - | |_____________________^ `&&&&&std::iter::Enumerate>` is not an iterator + | |_____________________^ `&&&&&Enumerate>` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate>` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.rs b/src/test/ui/suggestions/type-ascription-instead-of-path.rs index e92087e294..ce40b55f1e 100644 --- a/src/test/ui/suggestions/type-ascription-instead-of-path.rs +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.rs @@ -1,5 +1,5 @@ fn main() { std:io::stdin(); - //~^ ERROR failed to resolve: use of undeclared type or module `io` + //~^ ERROR failed to resolve: use of undeclared crate or module `io` //~| ERROR expected value, found crate } diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr index fd2fedc764..518660cfa1 100644 --- a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `io` +error[E0433]: failed to resolve: use of undeclared crate or module `io` --> $DIR/type-ascription-instead-of-path.rs:2:9 | LL | std:io::stdin(); - | ^^ use of undeclared type or module `io` + | ^^ use of undeclared crate or module `io` error[E0423]: expected value, found crate `std` --> $DIR/type-ascription-instead-of-path.rs:2:5 diff --git a/src/test/ui/switched-expectations.stderr b/src/test/ui/switched-expectations.stderr index dca9c6ce4d..82fea0f14b 100644 --- a/src/test/ui/switched-expectations.stderr +++ b/src/test/ui/switched-expectations.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/switched-expectations.rs:3:30 | LL | let ref string: String = var; - | ^^^ expected struct `std::string::String`, found `i32` + | ^^^ expected struct `String`, found `i32` error: aborting due to previous error diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr index 52ee3452a4..e4c20cd882 100644 --- a/src/test/ui/symbol-names/impl1.legacy.stderr +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -64,7 +64,7 @@ error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::A LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method) +error: def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method) --> $DIR/impl1.rs:71:13 | LL | #[rustc_def_path] diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 380d20d0b1..1d86abd002 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -69,8 +69,8 @@ fn main() { //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo extern "C" fn(&'a u8, ...)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method) //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method) #[rustc_def_path] - //[legacy]~^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method) - //[v0]~^^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method) + //[legacy]~^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method) + //[v0]~^^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method) fn method(&self) {} } }; diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr index b6a35d9746..01d047d34a 100644 --- a/src/test/ui/symbol-names/impl1.v0.stderr +++ b/src/test/ui/symbol-names/impl1.v0.stderr @@ -64,7 +64,7 @@ error: demangling-alt(<[&dyn impl1::Foo extern "C" fn(&'a u8, .. LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method) +error: def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method) --> $DIR/impl1.rs:71:13 | LL | #[rustc_def_path] diff --git a/src/test/ui/symbol-names/issue-76365.rs b/src/test/ui/symbol-names/issue-76365.rs new file mode 100644 index 0000000000..61ba255dac --- /dev/null +++ b/src/test/ui/symbol-names/issue-76365.rs @@ -0,0 +1,18 @@ +// check-pass +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib + //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib + +#![feature(min_const_generics)] + +pub struct Bar; + +impl Bar { + pub fn foo() {} +} + +impl Bar { + pub fn bar() {} +} + +fn main() {} diff --git a/src/test/ui/tag-that-dare-not-speak-its-name.rs b/src/test/ui/tag-that-dare-not-speak-its-name.rs index 4d9a98827d..36e22f0b5f 100644 --- a/src/test/ui/tag-that-dare-not-speak-its-name.rs +++ b/src/test/ui/tag-that-dare-not-speak-its-name.rs @@ -11,6 +11,6 @@ fn main() { let x : char = last(y); //~^ ERROR mismatched types //~| expected type `char` - //~| found enum `std::option::Option<_>` - //~| expected `char`, found enum `std::option::Option` + //~| found enum `Option<_>` + //~| expected `char`, found enum `Option` } diff --git a/src/test/ui/tag-that-dare-not-speak-its-name.stderr b/src/test/ui/tag-that-dare-not-speak-its-name.stderr index cafb6d2d28..96bab15261 100644 --- a/src/test/ui/tag-that-dare-not-speak-its-name.stderr +++ b/src/test/ui/tag-that-dare-not-speak-its-name.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/tag-that-dare-not-speak-its-name.rs:11:20 | LL | let x : char = last(y); - | ---- ^^^^^^^ expected `char`, found enum `std::option::Option` + | ---- ^^^^^^^ expected `char`, found enum `Option` | | | expected due to this | = note: expected type `char` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to previous error diff --git a/src/test/ui/target-feature/gate.rs b/src/test/ui/target-feature/gate.rs index 10fbba36d3..e4b78c76e1 100644 --- a/src/test/ui/target-feature/gate.rs +++ b/src/test/ui/target-feature/gate.rs @@ -19,7 +19,6 @@ // gate-test-aarch64_target_feature // gate-test-hexagon_target_feature // gate-test-mips_target_feature -// gate-test-mmx_target_feature // gate-test-wasm_target_feature // gate-test-adx_target_feature // gate-test-cmpxchg16b_target_feature @@ -30,7 +29,6 @@ #[target_feature(enable = "avx512bw")] //~^ ERROR: currently unstable -unsafe fn foo() { -} +unsafe fn foo() {} fn main() {} diff --git a/src/test/ui/target-feature/gate.stderr b/src/test/ui/target-feature/gate.stderr index 2d6abcc0a0..2384a00aa4 100644 --- a/src/test/ui/target-feature/gate.stderr +++ b/src/test/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:31:18 + --> $DIR/gate.rs:30:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/target-feature/invalid-attribute.rs b/src/test/ui/target-feature/invalid-attribute.rs index 98afded671..5ea7821554 100644 --- a/src/test/ui/target-feature/invalid-attribute.rs +++ b/src/test/ui/target-feature/invalid-attribute.rs @@ -13,6 +13,7 @@ // ignore-sparc64 #![feature(target_feature)] +#![warn(unused_attributes)] #[target_feature = "+sse2"] //~^ ERROR malformed `target_feature` attribute @@ -48,17 +49,20 @@ struct Foo; #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function -enum Bar { } +enum Bar {} //~^ NOTE not a function #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function -union Qux { f1: u16, f2: u16 } +union Qux { //~^ NOTE not a function + f1: u16, + f2: u16, +} #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function -trait Baz { } +trait Baz {} //~^ NOTE not a function #[inline(always)] @@ -79,13 +83,16 @@ impl Quux for Foo { } fn main() { + #[target_feature(enable = "sse2")] + //~^ ERROR attribute should be applied to a function unsafe { foo(); bar(); } + //~^^^^ NOTE not a function + #[target_feature(enable = "sse2")] - //~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions - //~| NOTE see issue #69098 + //~^ ERROR attribute should be applied to a function || {}; - //~^ NOTE not an `unsafe` function + //~^ NOTE not a function } diff --git a/src/test/ui/target-feature/invalid-attribute.stderr b/src/test/ui/target-feature/invalid-attribute.stderr index 3d629afb9a..8c8e24ccc5 100644 --- a/src/test/ui/target-feature/invalid-attribute.stderr +++ b/src/test/ui/target-feature/invalid-attribute.stderr @@ -1,29 +1,29 @@ error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:17:1 + --> $DIR/invalid-attribute.rs:18:1 | LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]` error: the feature named `foo` is not valid for this target - --> $DIR/invalid-attribute.rs:19:18 + --> $DIR/invalid-attribute.rs:20:18 | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ `foo` is not valid for this target error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:22:18 + --> $DIR/invalid-attribute.rs:23:18 | LL | #[target_feature(bar)] | ^^^ help: must be of the form: `enable = ".."` error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:24:18 + --> $DIR/invalid-attribute.rs:25:18 | LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."` error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:28:1 + --> $DIR/invalid-attribute.rs:29:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | fn bar() {} = help: add `#![feature(target_feature_11)]` to the crate attributes to enable error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:34:1 + --> $DIR/invalid-attribute.rs:35:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | mod another {} | -------------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:39:1 + --> $DIR/invalid-attribute.rs:40:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | const FOO: usize = 7; | --------------------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:44:1 + --> $DIR/invalid-attribute.rs:45:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,52 +62,65 @@ LL | struct Foo; | ----------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:49:1 + --> $DIR/invalid-attribute.rs:50:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | enum Bar { } - | ------------ not a function +LL | enum Bar {} + | ----------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:54:1 + --> $DIR/invalid-attribute.rs:55:1 | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | union Qux { f1: u16, f2: u16 } - | ------------------------------ not a function +LL | / union Qux { +LL | | +LL | | f1: u16, +LL | | f2: u16, +LL | | } + | |_- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:59:1 + --> $DIR/invalid-attribute.rs:63:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | trait Baz { } - | ------------- not a function +LL | trait Baz {} + | ------------ not a function error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/invalid-attribute.rs:64:1 + --> $DIR/invalid-attribute.rs:68:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ -error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions +error: attribute should be applied to a function --> $DIR/invalid-attribute.rs:86:5 | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / unsafe { +LL | | foo(); +LL | | bar(); +LL | | } + | |_____- not a function + +error: attribute should be applied to a function + --> $DIR/invalid-attribute.rs:94:5 + | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | || {}; - | ----- not an `unsafe` function - | - = note: see issue #69098 for more information - = help: add `#![feature(target_feature_11)]` to the crate attributes to enable + | ----- not a function error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:74:5 + --> $DIR/invalid-attribute.rs:78:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,6 +131,6 @@ LL | fn foo() {} = note: see issue #69098 for more information = help: add `#![feature(target_feature_11)]` to the crate attributes to enable -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/terr-sorts.rs b/src/test/ui/terr-sorts.rs index f91185fd7c..c1e2f7daee 100644 --- a/src/test/ui/terr-sorts.rs +++ b/src/test/ui/terr-sorts.rs @@ -9,7 +9,7 @@ fn want_foo(f: Foo) {} fn have_bar(b: Bar) { want_foo(b); //~ ERROR mismatched types //~| expected struct `Foo` - //~| found struct `std::boxed::Box` + //~| found struct `Box` } fn main() {} diff --git a/src/test/ui/terr-sorts.stderr b/src/test/ui/terr-sorts.stderr index 2f7cc66f10..869b372965 100644 --- a/src/test/ui/terr-sorts.stderr +++ b/src/test/ui/terr-sorts.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/terr-sorts.rs:10:14 | LL | want_foo(b); - | ^ expected struct `Foo`, found struct `std::boxed::Box` + | ^ expected struct `Foo`, found struct `Box` | = note: expected struct `Foo` - found struct `std::boxed::Box` + found struct `Box` error: aborting due to previous error diff --git a/src/test/ui/trait-impl-bound-suggestions.fixed b/src/test/ui/trait-impl-bound-suggestions.fixed new file mode 100644 index 0000000000..db3a95f5c4 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.fixed @@ -0,0 +1,20 @@ +// run-rustfix + +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + +#[allow(dead_code)] +struct ConstrainedStruct { + x: X +} + +#[allow(dead_code)] +trait InsufficientlyConstrainedGeneric where X: Copy { + fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + //~^ ERROR the trait bound `X: Copy` is not satisfied + ConstrainedStruct { x } + } +} + +pub fn main() { } diff --git a/src/test/ui/trait-impl-bound-suggestions.rs b/src/test/ui/trait-impl-bound-suggestions.rs new file mode 100644 index 0000000000..bf75175179 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.rs @@ -0,0 +1,20 @@ +// run-rustfix + +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + +#[allow(dead_code)] +struct ConstrainedStruct { + x: X +} + +#[allow(dead_code)] +trait InsufficientlyConstrainedGeneric { + fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + //~^ ERROR the trait bound `X: Copy` is not satisfied + ConstrainedStruct { x } + } +} + +pub fn main() { } diff --git a/src/test/ui/trait-impl-bound-suggestions.stderr b/src/test/ui/trait-impl-bound-suggestions.stderr new file mode 100644 index 0000000000..3a21e9c6b2 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `X: Copy` is not satisfied + --> $DIR/trait-impl-bound-suggestions.rs:14:52 + | +LL | struct ConstrainedStruct { + | ---- required by this bound in `ConstrainedStruct` +... +LL | fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `X` + | +help: consider further restricting type parameter `X` + | +LL | trait InsufficientlyConstrainedGeneric where X: Copy { + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr index 324316ceaf..25b1f427f3 100644 --- a/src/test/ui/traits/cycle-cache-err-60010.stderr +++ b/src/test/ui/traits/cycle-cache-err-60010.stderr @@ -6,7 +6,7 @@ LL | _parse: >::Data, | = note: required because of the requirements on the impl of `Query` for `ParseQuery` -error[E0275]: overflow evaluating the requirement `Runtime: std::panic::RefUnwindSafe` +error[E0275]: overflow evaluating the requirement `Runtime: RefUnwindSafe` --> $DIR/cycle-cache-err-60010.rs:31:20 | LL | trait Database { diff --git a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr index 446b8dbf11..83b1b83d19 100644 --- a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -7,7 +7,7 @@ LL | struct Outer(T); LL | Outer(TestType); | ^^^^^^^^ `dummy::TestType` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dummy::TestType` + = help: the trait `Send` is not implemented for `dummy::TestType` error[E0277]: `dummy::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:23:5 @@ -18,7 +18,7 @@ LL | struct Outer(T); LL | Outer(TestType); | ^^^^^^^^^^^^^^^ `dummy::TestType` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dummy::TestType` + = help: the trait `Send` is not implemented for `dummy::TestType` error[E0277]: `dummy1b::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:32:13 @@ -29,7 +29,7 @@ LL | fn is_send(_: T) {} LL | is_send(TestType); | ^^^^^^^^ `dummy1b::TestType` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dummy1b::TestType` + = help: the trait `Send` is not implemented for `dummy1b::TestType` error[E0277]: `dummy1c::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:40:13 @@ -40,7 +40,7 @@ LL | fn is_send(_: T) {} LL | is_send((8, TestType)); | ^^^^^^^^^^^^^ `dummy1c::TestType` cannot be sent between threads safely | - = help: within `({integer}, dummy1c::TestType)`, the trait `std::marker::Send` is not implemented for `dummy1c::TestType` + = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType` = note: required because it appears within the type `({integer}, dummy1c::TestType)` error[E0277]: `dummy2::TestType` cannot be sent between threads safely @@ -52,12 +52,12 @@ LL | fn is_send(_: T) {} LL | is_send(Box::new(TestType)); | ^^^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::marker::Send` + | expected an implementor of trait `Send` | help: consider borrowing here: `&Box::new(TestType)` | - = note: the trait bound `dummy2::TestType: std::marker::Send` is not satisfied - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` - = note: required because it appears within the type `std::boxed::Box` + = note: the trait bound `dummy2::TestType: Send` is not satisfied + = note: required because of the requirements on the impl of `Send` for `Unique` + = note: required because it appears within the type `Box` error[E0277]: `dummy3::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:56:13 @@ -68,10 +68,10 @@ LL | fn is_send(_: T) {} LL | is_send(Box::new(Outer2(TestType))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `dummy3::TestType` cannot be sent between threads safely | - = help: within `Outer2`, the trait `std::marker::Send` is not implemented for `dummy3::TestType` + = help: within `Outer2`, the trait `Send` is not implemented for `dummy3::TestType` = note: required because it appears within the type `Outer2` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique>` - = note: required because it appears within the type `std::boxed::Box>` + = note: required because of the requirements on the impl of `Send` for `Unique>` + = note: required because it appears within the type `Box>` error[E0277]: `main::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:66:13 @@ -82,11 +82,11 @@ LL | fn is_sync(_: T) {} LL | is_sync(Outer2(TestType)); | ^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::marker::Sync` + | expected an implementor of trait `Sync` | help: consider borrowing here: `&Outer2(TestType)` | - = note: the trait bound `main::TestType: std::marker::Sync` is not satisfied - = note: required because of the requirements on the impl of `std::marker::Sync` for `Outer2` + = note: the trait bound `main::TestType: Sync` is not satisfied + = note: required because of the requirements on the impl of `Sync` for `Outer2` error: aborting due to 7 previous errors diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr index 7c00bb5207..f692e92d86 100644 --- a/src/test/ui/traits/trait-alias-ambiguous.stderr +++ b/src/test/ui/traits/trait-alias-ambiguous.stderr @@ -4,24 +4,24 @@ error[E0034]: multiple applicable items in scope LL | t.foo(); | ^^^ multiple `foo` found | -note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u8` +note: candidate #1 is defined in an impl of the trait `A` for the type `u8` --> $DIR/trait-alias-ambiguous.rs:8:9 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8` +note: candidate #2 is defined in an impl of the trait `B` for the type `u8` --> $DIR/trait-alias-ambiguous.rs:11:9 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #1 | -LL | inner::A::foo(&t); - | ^^^^^^^^^^^^^^^^^ +LL | A::foo(&t); + | ^^^^^^^^^^ help: disambiguate the associated function for candidate #2 | -LL | inner::B::foo(&t); - | ^^^^^^^^^^^^^^^^^ +LL | B::foo(&t); + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs index 259fc4fa5d..14edfdd7a3 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs +++ b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs @@ -12,6 +12,6 @@ fn use_alias() {} fn main() { use_alias::(); use_alias::>(); - //~^ ERROR `std::rc::Rc` cannot be sent between threads safely [E0277] - //~^^ ERROR `std::rc::Rc` cannot be shared between threads safely [E0277] + //~^ ERROR `Rc` cannot be sent between threads safely [E0277] + //~^^ ERROR `Rc` cannot be shared between threads safely [E0277] } diff --git a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr index 04c86cb240..60a4a46a05 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr @@ -1,24 +1,24 @@ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/trait-alias-cross-crate.rs:14:17 | LL | fn use_alias() {} | -------- required by this bound in `use_alias` ... LL | use_alias::>(); - | ^^^^^^^ `std::rc::Rc` cannot be sent between threads safely + | ^^^^^^^ `Rc` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc` + = help: the trait `Send` is not implemented for `Rc` -error[E0277]: `std::rc::Rc` cannot be shared between threads safely +error[E0277]: `Rc` cannot be shared between threads safely --> $DIR/trait-alias-cross-crate.rs:14:17 | LL | fn use_alias() {} | -------- required by this bound in `use_alias` ... LL | use_alias::>(); - | ^^^^^^^ `std::rc::Rc` cannot be shared between threads safely + | ^^^^^^^ `Rc` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::rc::Rc` + = help: the trait `Sync` is not implemented for `Rc` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs b/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs index d62fd7e59c..5c753ff207 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs +++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs @@ -5,7 +5,7 @@ trait IteratorAlias = Iterator; fn main() { let _: &dyn EqAlias = &123; - //~^ ERROR the trait `std::cmp::Eq` cannot be made into an object [E0038] + //~^ ERROR the trait `Eq` cannot be made into an object [E0038] let _: &dyn IteratorAlias = &vec![123].into_iter(); //~^ ERROR must be specified } diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr index 4cad710789..1f54e03ee6 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr @@ -1,15 +1,15 @@ -error[E0038]: the trait `std::cmp::Eq` cannot be made into an object +error[E0038]: the trait `Eq` cannot be made into an object --> $DIR/trait-alias-object-fail.rs:7:13 | LL | let _: &dyn EqAlias = &123; - | ^^^^^^^^^^^ the trait `std::cmp::Eq` cannot be made into an object + | ^^^^^^^^^^^ the trait `Eq` cannot be made into an object | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub trait Eq: PartialEq { | --------------- the trait cannot be made into an object because it uses `Self` as a type parameter in this -error[E0191]: the value of the associated type `Item` (from trait `std::iter::Iterator`) must be specified +error[E0191]: the value of the associated type `Item` (from trait `Iterator`) must be specified --> $DIR/trait-alias-object-fail.rs:9:17 | LL | let _: &dyn IteratorAlias = &vec![123].into_iter(); diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr index daca91abff..b403fb4184 100644 --- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr +++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr @@ -6,13 +6,13 @@ LL | fn foo(_x: Foo + Send) { | = note: `#[warn(bare_trait_objects)]` on by default -error[E0277]: the size for values of type `(dyn Foo + std::marker::Send + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time --> $DIR/trait-bounds-not-on-bare-trait.rs:7:8 | LL | fn foo(_x: Foo + Send) { | ^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + std::marker::Send + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc.stderr index d2fa211b48..3e8c727dda 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc.stderr @@ -1,24 +1,24 @@ -error[E0277]: the trait bound `usize: trait_bounds_on_structs_and_enums_xc::Trait` is not satisfied +error[E0277]: the trait bound `usize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-xc.rs:7:15 | LL | fn explode(x: Foo) {} - | ^^^^^^^^^^ the trait `trait_bounds_on_structs_and_enums_xc::Trait` is not implemented for `usize` + | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` | ::: $DIR/auxiliary/trait_bounds_on_structs_and_enums_xc.rs:5:18 | LL | pub struct Foo { - | ----- required by this bound in `trait_bounds_on_structs_and_enums_xc::Foo` + | ----- required by this bound in `Foo` -error[E0277]: the trait bound `f32: trait_bounds_on_structs_and_enums_xc::Trait` is not satisfied +error[E0277]: the trait bound `f32: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-xc.rs:10:14 | LL | fn kaboom(y: Bar) {} - | ^^^^^^^^ the trait `trait_bounds_on_structs_and_enums_xc::Trait` is not implemented for `f32` + | ^^^^^^^^ the trait `Trait` is not implemented for `f32` | ::: $DIR/auxiliary/trait_bounds_on_structs_and_enums_xc.rs:9:16 | LL | pub enum Bar { - | ----- required by this bound in `trait_bounds_on_structs_and_enums_xc::Bar` + | ----- required by this bound in `Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc1.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc1.stderr index ee3e755c95..899e994199 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc1.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc1.stderr @@ -1,21 +1,21 @@ -error[E0277]: the trait bound `f64: trait_bounds_on_structs_and_enums_xc::Trait` is not satisfied +error[E0277]: the trait bound `f64: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-xc1.rs:12:14 | LL | let bar: Bar = return; - | ^^^^^^^^ the trait `trait_bounds_on_structs_and_enums_xc::Trait` is not implemented for `f64` + | ^^^^^^^^ the trait `Trait` is not implemented for `f64` | ::: $DIR/auxiliary/trait_bounds_on_structs_and_enums_xc.rs:9:16 | LL | pub enum Bar { - | ----- required by this bound in `trait_bounds_on_structs_and_enums_xc::Bar` + | ----- required by this bound in `Bar` -error[E0277]: the trait bound `{integer}: trait_bounds_on_structs_and_enums_xc::Trait` is not satisfied +error[E0277]: the trait bound `{integer}: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-xc1.rs:8:15 | LL | let foo = Foo { - | ^^^ the trait `trait_bounds_on_structs_and_enums_xc::Trait` is not implemented for `{integer}` + | ^^^ the trait `Trait` is not implemented for `{integer}` | - = note: required by `trait_bounds_on_structs_and_enums_xc::Foo` + = note: required by `Foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-bounds-same-crate-name.stderr b/src/test/ui/traits/trait-bounds-same-crate-name.stderr index 8a6e059604..af5ba8808f 100644 --- a/src/test/ui/traits/trait-bounds-same-crate-name.stderr +++ b/src/test/ui/traits/trait-bounds-same-crate-name.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `main::a::Foo: main::a::Bar` is not satisfied +error[E0277]: the trait bound `Foo: main::a::Bar` is not satisfied --> $DIR/trait-bounds-same-crate-name.rs:31:20 | LL | a::try_foo(foo); - | ^^^ the trait `main::a::Bar` is not implemented for `main::a::Foo` + | ^^^ the trait `main::a::Bar` is not implemented for `Foo` | ::: $DIR/auxiliary/crate_a1.rs:3:24 | LL | pub fn try_foo(x: impl Bar) {} - | --- required by this bound in `main::a::try_foo` + | --- required by this bound in `try_foo` | help: trait impl with same name found --> $DIR/auxiliary/crate_a2.rs:5:1 @@ -16,27 +16,27 @@ LL | impl Bar for Foo {} | ^^^^^^^^^^^^^^^^^^^ = note: perhaps two different versions of crate `crate_a2` are being used? -error[E0277]: the trait bound `main::a::DoesNotImplementTrait: main::a::Bar` is not satisfied +error[E0277]: the trait bound `DoesNotImplementTrait: main::a::Bar` is not satisfied --> $DIR/trait-bounds-same-crate-name.rs:38:20 | LL | a::try_foo(implements_no_traits); - | ^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `main::a::DoesNotImplementTrait` + | ^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `DoesNotImplementTrait` | ::: $DIR/auxiliary/crate_a1.rs:3:24 | LL | pub fn try_foo(x: impl Bar) {} - | --- required by this bound in `main::a::try_foo` + | --- required by this bound in `try_foo` -error[E0277]: the trait bound `main::a::ImplementsWrongTraitConditionally: main::a::Bar` is not satisfied +error[E0277]: the trait bound `ImplementsWrongTraitConditionally: main::a::Bar` is not satisfied --> $DIR/trait-bounds-same-crate-name.rs:45:20 | LL | a::try_foo(other_variant_implements_mismatched_trait); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `main::a::ImplementsWrongTraitConditionally` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsWrongTraitConditionally` | ::: $DIR/auxiliary/crate_a1.rs:3:24 | LL | pub fn try_foo(x: impl Bar) {} - | --- required by this bound in `main::a::try_foo` + | --- required by this bound in `try_foo` | help: trait impl with same name found --> $DIR/auxiliary/crate_a2.rs:13:1 @@ -45,19 +45,19 @@ LL | impl Bar for ImplementsWrongTraitConditionally {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: perhaps two different versions of crate `crate_a2` are being used? -error[E0277]: the trait bound `main::a::ImplementsTraitForUsize: main::a::Bar` is not satisfied +error[E0277]: the trait bound `ImplementsTraitForUsize: main::a::Bar` is not satisfied --> $DIR/trait-bounds-same-crate-name.rs:51:20 | LL | a::try_foo(other_variant_implements_correct_trait); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `main::a::ImplementsTraitForUsize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsTraitForUsize` | ::: $DIR/auxiliary/crate_a1.rs:3:24 | LL | pub fn try_foo(x: impl Bar) {} - | --- required by this bound in `main::a::try_foo` + | --- required by this bound in `try_foo` | = help: the following implementations were found: - as main::a::Bar> + as main::a::Bar> error: aborting due to 4 previous errors diff --git a/src/test/ui/traits/trait-bounds-sugar.stderr b/src/test/ui/traits/trait-bounds-sugar.stderr index 5ee8be51dd..6bd335fe47 100644 --- a/src/test/ui/traits/trait-bounds-sugar.stderr +++ b/src/test/ui/traits/trait-bounds-sugar.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/trait-bounds-sugar.rs:12:7 | LL | a(x); - | ^ expected trait `Foo + std::marker::Send`, found trait `Foo + std::marker::Sync` + | ^ expected trait `Foo + Send`, found trait `Foo + Sync` | - = note: expected struct `std::boxed::Box<(dyn Foo + std::marker::Send + 'static)>` - found struct `std::boxed::Box<(dyn Foo + std::marker::Sync + 'static)>` + = note: expected struct `Box<(dyn Foo + Send + 'static)>` + found struct `Box<(dyn Foo + Sync + 'static)>` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-object-macro-matcher.rs b/src/test/ui/traits/trait-object-macro-matcher.rs index a6852569f3..9109787499 100644 --- a/src/test/ui/traits/trait-object-macro-matcher.rs +++ b/src/test/ui/traits/trait-object-macro-matcher.rs @@ -6,7 +6,7 @@ macro_rules! m { fn main() { m!(dyn Copy + Send + 'static); - //~^ ERROR the trait `std::marker::Copy` cannot be made into an object + //~^ ERROR the trait `Copy` cannot be made into an object m!(dyn 'static + Send); m!(dyn 'static +); //~ ERROR at least one trait is required for an object type } diff --git a/src/test/ui/traits/trait-object-macro-matcher.stderr b/src/test/ui/traits/trait-object-macro-matcher.stderr index cb48bd1258..bc56736073 100644 --- a/src/test/ui/traits/trait-object-macro-matcher.stderr +++ b/src/test/ui/traits/trait-object-macro-matcher.stderr @@ -4,11 +4,11 @@ error[E0224]: at least one trait is required for an object type LL | m!(dyn 'static +); | ^^^^^^^^^^^^^ -error[E0038]: the trait `std::marker::Copy` cannot be made into an object +error[E0038]: the trait `Copy` cannot be made into an object --> $DIR/trait-object-macro-matcher.rs:8:8 | LL | m!(dyn Copy + Send + 'static); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` diff --git a/src/test/ui/traits/trait-object-safety.stderr b/src/test/ui/traits/trait-object-safety.stderr index 162e9249b8..3fa7c0c484 100644 --- a/src/test/ui/traits/trait-object-safety.stderr +++ b/src/test/ui/traits/trait-object-safety.stderr @@ -9,7 +9,7 @@ LL | fn foo(); LL | let _: &dyn Tr = &St; | ^^^ the trait `Tr` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Tr>` for `&St` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Tr>` for `&St` = note: required by cast to type `&dyn Tr` help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects | diff --git a/src/test/ui/traits/trait-safety-trait-impl-cc.stderr b/src/test/ui/traits/trait-safety-trait-impl-cc.stderr index 5234e205a8..2fcedc5cc5 100644 --- a/src/test/ui/traits/trait-safety-trait-impl-cc.stderr +++ b/src/test/ui/traits/trait-safety-trait-impl-cc.stderr @@ -1,4 +1,4 @@ -error[E0200]: the trait `lib::Foo` requires an `unsafe impl` declaration +error[E0200]: the trait `Foo` requires an `unsafe impl` declaration --> $DIR/trait-safety-trait-impl-cc.rs:9:1 | LL | / impl lib::Foo for Bar { diff --git a/src/test/ui/traits/trait-static-method-generic-inference.stderr b/src/test/ui/traits/trait-static-method-generic-inference.stderr index 8f20cc5093..6a7e8f59d8 100644 --- a/src/test/ui/traits/trait-static-method-generic-inference.stderr +++ b/src/test/ui/traits/trait-static-method-generic-inference.stderr @@ -2,12 +2,12 @@ error[E0283]: type annotations needed --> $DIR/trait-static-method-generic-inference.rs:24:25 | LL | fn new() -> T; - | -------------- required by `base::HasNew::new` + | -------------- required by `HasNew::new` ... LL | let _f: base::Foo = base::HasNew::new(); | ^^^^^^^^^^^^^^^^^ cannot infer type | - = note: cannot satisfy `_: base::HasNew` + = note: cannot satisfy `_: HasNew` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed index 2bb34b0ebe..a1abf668b8 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed @@ -14,5 +14,5 @@ fn main() { let _works = TcpListener::bind("some string"); let bad = NoToSocketAddrs("bad".to_owned()); let _errors = TcpListener::bind(&*bad); - //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied + //~^ ERROR the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied } diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs index 33d524608a..90d097105e 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs @@ -14,5 +14,5 @@ fn main() { let _works = TcpListener::bind("some string"); let bad = NoToSocketAddrs("bad".to_owned()); let _errors = TcpListener::bind(&bad); - //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied + //~^ ERROR the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied } diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr index 6dff2e418c..4273b8e3f3 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr @@ -1,18 +1,18 @@ -error[E0277]: the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied +error[E0277]: the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied --> $DIR/trait-suggest-deferences-issue-39029.rs:16:37 | LL | let _errors = TcpListener::bind(&bad); | ^^^^ | | - | the trait `std::net::ToSocketAddrs` is not implemented for `NoToSocketAddrs` + | the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs` | help: consider adding dereference here: `&*bad` | ::: $SRC_DIR/std/src/net/tcp.rs:LL:COL | LL | pub fn bind(addr: A) -> io::Result { - | ------------- required by this bound in `std::net::TcpListener::bind` + | ------------- required by this bound in `TcpListener::bind` | - = note: required because of the requirements on the impl of `std::net::ToSocketAddrs` for `&NoToSocketAddrs` + = note: required because of the requirements on the impl of `ToSocketAddrs` for `&NoToSocketAddrs` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed index fa7b9167d8..406caaa007 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed @@ -11,5 +11,5 @@ fn main() { let string = String::new(); takes_str(&string); // Ok takes_type_parameter(&*string); // Error - //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied + //~^ ERROR the trait bound `&String: SomeTrait` is not satisfied } diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs index e785f01217..53846be730 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs @@ -11,5 +11,5 @@ fn main() { let string = String::new(); takes_str(&string); // Ok takes_type_parameter(&string); // Error - //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied + //~^ ERROR the trait bound `&String: SomeTrait` is not satisfied } diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr index 9c2a582638..eaec87d01d 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `&std::string::String: SomeTrait` is not satisfied +error[E0277]: the trait bound `&String: SomeTrait` is not satisfied --> $DIR/trait-suggest-deferences-issue-62530.rs:13:26 | LL | fn takes_type_parameter(_x: T) where T: SomeTrait {} @@ -7,7 +7,7 @@ LL | fn takes_type_parameter(_x: T) where T: SomeTrait {} LL | takes_type_parameter(&string); // Error | ^^^^^^^ | | - | the trait `SomeTrait` is not implemented for `&std::string::String` + | the trait `SomeTrait` is not implemented for `&String` | help: consider adding dereference here: `&*string` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-suggest-where-clause.rs b/src/test/ui/traits/trait-suggest-where-clause.rs index 8405e5ff62..46d047a2de 100644 --- a/src/test/ui/traits/trait-suggest-where-clause.rs +++ b/src/test/ui/traits/trait-suggest-where-clause.rs @@ -13,15 +13,15 @@ fn check() { // ... even if T occurs as a type parameter >::from; - //~^ ERROR `u64: std::convert::From` is not satisfied + //~^ ERROR `u64: From` is not satisfied ::Item>>::from; - //~^ ERROR `u64: std::convert::From<::Item>` is not satisfied + //~^ ERROR `u64: From<::Item>` is not satisfied // ... but not if there are inference variables as From>::from; - //~^ ERROR `Misc<_>: std::convert::From` is not satisfied + //~^ ERROR `Misc<_>: From` is not satisfied // ... and also not if the error is not related to the type diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr index 73da2a6eb4..0f6f8d75c5 100644 --- a/src/test/ui/traits/trait-suggest-where-clause.stderr +++ b/src/test/ui/traits/trait-suggest-where-clause.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `U` cannot be known at compilation tim --> $DIR/trait-suggest-where-clause.rs:7:20 | LL | fn check() { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | // suggest a where-clause, if needed LL | mem::size_of::(); | ^ doesn't have a size known at compile-time @@ -16,7 +16,7 @@ error[E0277]: the size for values of type `U` cannot be known at compilation tim --> $DIR/trait-suggest-where-clause.rs:10:5 | LL | fn check() { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | mem::size_of::>(); | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -28,29 +28,29 @@ LL | pub const fn size_of() -> usize { | = note: required because it appears within the type `Misc` -error[E0277]: the trait bound `u64: std::convert::From` is not satisfied +error[E0277]: the trait bound `u64: From` is not satisfied --> $DIR/trait-suggest-where-clause.rs:15:5 | LL | >::from; - | ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From` is not implemented for `u64` + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `From` is not implemented for `u64` | - = note: required by `std::convert::From::from` + = note: required by `from` -error[E0277]: the trait bound `u64: std::convert::From<::Item>` is not satisfied +error[E0277]: the trait bound `u64: From<::Item>` is not satisfied --> $DIR/trait-suggest-where-clause.rs:18:5 | LL | ::Item>>::from; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<::Item>` is not implemented for `u64` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<::Item>` is not implemented for `u64` | - = note: required by `std::convert::From::from` + = note: required by `from` -error[E0277]: the trait bound `Misc<_>: std::convert::From` is not satisfied +error[E0277]: the trait bound `Misc<_>: From` is not satisfied --> $DIR/trait-suggest-where-clause.rs:23:5 | LL | as From>::from; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From` is not implemented for `Misc<_>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From` is not implemented for `Misc<_>` | - = note: required by `std::convert::From::from` + = note: required by `from` error[E0277]: the size for values of type `[T]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:28:20 @@ -63,7 +63,7 @@ LL | mem::size_of::<[T]>(); LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | - = help: the trait `std::marker::Sized` is not implemented for `[T]` + = help: the trait `Sized` is not implemented for `[T]` error[E0277]: the size for values of type `[&U]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:31:5 @@ -76,7 +76,7 @@ LL | mem::size_of::<[&U]>(); LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | - = help: the trait `std::marker::Sized` is not implemented for `[&U]` + = help: the trait `Sized` is not implemented for `[&U]` error: aborting due to 7 previous errors diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr index 9d1eef5475..0a62f1aeb2 100644 --- a/src/test/ui/traits/trait-test-2.stderr +++ b/src/test/ui/traits/trait-test-2.stderr @@ -39,8 +39,8 @@ LL | (box 10 as Box).dup(); | = help: consider moving `dup` to another trait = help: consider moving `blah` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box<{integer}>` - = note: required by cast to type `std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box<{integer}>` + = note: required by cast to type `Box` error: aborting due to 4 previous errors diff --git a/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr b/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr index 604763f8e3..5ac7b08e52 100644 --- a/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr +++ b/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == u32` +error[E0271]: type mismatch resolving ` as Iterator>::Item == u32` --> $DIR/traits-assoc-type-in-supertrait-bad.rs:12:16 | LL | type Key = u32; diff --git a/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr b/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr index 9a227229ea..b904826081 100644 --- a/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `std::boxed::Box>>: NotAuto` +error[E0275]: overflow evaluating the requirement `Box>>: NotAuto` --> $DIR/traits-inductive-overflow-lifetime.rs:27:5 | LL | fn is_send() {} diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr index b97197285e..c11234ee48 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr @@ -6,14 +6,14 @@ LL | auto trait Magic: Copy {} | | | auto trait cannot have super traits -error[E0277]: the trait bound `NoClone: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `NoClone: Copy` is not satisfied --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:16:23 | LL | fn copy(x: T) -> (T, T) { (x, x) } | ----- required by this bound in `copy` ... LL | let (a, b) = copy(NoClone); - | ^^^^^^^ the trait `std::marker::Copy` is not implemented for `NoClone` + | ^^^^^^^ the trait `Copy` is not implemented for `NoClone` | = note: required because of the requirements on the impl of `Magic` for `NoClone` diff --git a/src/test/ui/traits/traits-issue-71136.stderr b/src/test/ui/traits/traits-issue-71136.stderr index 4c0a43062f..23a8040f6f 100644 --- a/src/test/ui/traits/traits-issue-71136.stderr +++ b/src/test/ui/traits/traits-issue-71136.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `Foo: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Foo: Clone` is not satisfied --> $DIR/traits-issue-71136.rs:5:5 | LL | the_foos: Vec, - | ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `std::clone::Clone` + | ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec` - = note: required by `std::clone::Clone::clone` + = note: required because of the requirements on the impl of `Clone` for `Vec` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr b/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr index 1a6093343a..aefe3fb8e2 100644 --- a/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr +++ b/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr @@ -13,7 +13,7 @@ error[E0591]: can't transmute zero-sized type LL | let p = mem::transmute(foo); | ^^^^^^^^^^^^^^ | - = note: source type: unsafe fn() -> (i8, *const (), std::option::Option) {foo} + = note: source type: unsafe fn() -> (i8, *const (), Option) {foo} = note: target type: *const () = help: cast with `as` to a pointer instead @@ -24,7 +24,7 @@ LL | let of = mem::transmute(main); | ^^^^^^^^^^^^^^ | = note: source type: fn() {main} - = note: target type: std::option::Option + = note: target type: Option = help: cast with `as` to a pointer instead error[E0512]: cannot transmute between types of different sizes, or dependently-sized types @@ -42,7 +42,7 @@ error[E0591]: can't transmute zero-sized type LL | mem::transmute::<_, *mut ()>(foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: source type: unsafe fn() -> (i8, *const (), std::option::Option) {foo} + = note: source type: unsafe fn() -> (i8, *const (), Option) {foo} = note: target type: *mut () = help: cast with `as` to a pointer instead @@ -62,7 +62,7 @@ error[E0591]: can't transmute zero-sized type LL | mem::transmute::<_, *mut ()>(Some(foo)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: source type: unsafe fn() -> (i8, *const (), std::option::Option) {foo} + = note: source type: unsafe fn() -> (i8, *const (), Option) {foo} = note: target type: *mut () = help: cast with `as` to a pointer instead @@ -83,7 +83,7 @@ LL | mem::transmute::<_, Option>(Some(baz)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: unsafe fn() {baz} - = note: target type: std::option::Option + = note: target type: Option = help: cast with `as` to a pointer instead error: aborting due to 9 previous errors diff --git a/src/test/ui/transmute/transmute-type-parameters.stderr b/src/test/ui/transmute/transmute-type-parameters.stderr index a355a1bf31..220b929d4f 100644 --- a/src/test/ui/transmute/transmute-type-parameters.stderr +++ b/src/test/ui/transmute/transmute-type-parameters.stderr @@ -49,7 +49,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | let _: i32 = transmute(x); | ^^^^^^^^^ | - = note: source type: `std::option::Option` (size can vary because of T) + = note: source type: `Option` (size can vary because of T) = note: target type: `i32` (32 bits) error: aborting due to 6 previous errors diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr index 39f7fb148f..7bd951febf 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr @@ -1,4 +1,4 @@ -warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters +warning: Trait bound String: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:5:51 | LL | fn copy_string(t: String) -> String where String: Copy { @@ -6,19 +6,19 @@ LL | fn copy_string(t: String) -> String where String: Copy { | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters +warning: Trait bound String: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:12:56 | LL | fn copy_out_string(t: &String) -> String where String: Copy { | ^^^^ -warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters +warning: Trait bound String: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:16:55 | LL | fn copy_string_with_param(x: String) where String: Copy { | ^^^^ -warning: Trait bound for<'b> &'b mut i32: std::marker::Copy does not depend on any type or lifetime parameters +warning: Trait bound for<'b> &'b mut i32: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:22:76 | LL | fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr index aa5d4fcc72..ff254edbd7 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr @@ -1,4 +1,4 @@ -warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters +warning: Trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:14:31 | LL | struct S(str, str) where str: Sized; @@ -6,13 +6,13 @@ LL | struct S(str, str) where str: Sized; | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound for<'a> T<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters +warning: Trait bound for<'a> T<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:17:49 | LL | fn unsized_local() where for<'a> T: Sized { | ^^^^^ -warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters +warning: Trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:22:35 | LL | fn return_str() -> str where str: Sized { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr index ffcfbdf54a..a9905052ff 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr @@ -1,4 +1,4 @@ -warning: Trait bound std::vec::Vec: std::fmt::Debug does not depend on any type or lifetime parameters +warning: Trait bound Vec: Debug does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-well-formed.rs:7:30 | LL | pub fn foo() where Vec: Debug, str: Copy { @@ -6,7 +6,7 @@ LL | pub fn foo() where Vec: Debug, str: Copy { | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound str: std::marker::Copy does not depend on any type or lifetime parameters +warning: Trait bound str: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-well-formed.rs:7:42 | LL | pub fn foo() where Vec: Debug, str: Copy { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr index d863cf6249..38245010c7 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr @@ -60,31 +60,31 @@ warning: Trait bound &'static str: Foo does not depend on any type or lifetime p LL | fn g() where &'static str: Foo { | ^^^ -warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters +warning: Trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:55:37 | LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^ -warning: Trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters +warning: Trait bound for<'a> Dst<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:57:51 | LL | fn unsized_local() where for<'a> Dst: Sized { | ^^^^^ -warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters +warning: Trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:61:35 | LL | fn return_str() -> str where str: Sized { | ^^^^^ -warning: Trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters +warning: Trait bound String: Neg does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:65:46 | LL | fn use_op(s: String) -> String where String: ::std::ops::Neg { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: Trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters +warning: Trait bound i32: Iterator does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:70:25 | LL | fn use_for() where i32: Iterator { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr index e96a241968..b3ec3cd8d9 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `*t` which is behind a shared reference --> $DIR/trivial-bounds-leak-copy.rs:9:5 | LL | *t - | ^^ move occurs because `*t` has type `std::string::String`, which does not implement the `Copy` trait + | ^^ move occurs because `*t` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr index 4f4695612d..de7a431d6f 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | fn cant_return_str() -> str { | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: the return type of a function must have a statically known size error[E0599]: no method named `test` found for type `i32` in the current scope diff --git a/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr b/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr index 3f2162365d..c685d9e740 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr @@ -1,4 +1,4 @@ -error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters +error: Trait bound i32: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:5:21 | LL | struct A where i32: Copy; @@ -40,7 +40,7 @@ error: Lifetime bound 'static: 'static does not depend on any type or lifetime p LL | fn global_outlives() where 'static: 'static {} | ^^^^^^^ -error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters +error: Trait bound i32: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:38:46 | LL | fn mixed_bounds() where i32: X + Copy {} diff --git a/src/test/ui/trivial_casts.rs b/src/test/ui/trivial_casts.rs index dd578e074f..0a8b9de1de 100644 --- a/src/test/ui/trivial_casts.rs +++ b/src/test/ui/trivial_casts.rs @@ -43,7 +43,7 @@ pub fn main() { let x: Box<[u32; 3]> = Box::new([42, 43, 44]); let _ = x as Box<[u32]>; - //~^ ERROR trivial cast: `std::boxed::Box<[u32; 3]>` as `std::boxed::Box<[u32]>` + //~^ ERROR trivial cast: `Box<[u32; 3]>` as `Box<[u32]>` let x: Box<[u32; 3]> = Box::new([42, 43, 44]); let _: Box<[u32]> = x; @@ -61,13 +61,13 @@ pub fn main() { let _: *mut dyn Foo = x; let x: Box = Box::new(Bar); - let _ = x as Box; //~ERROR `std::boxed::Box` as `std::boxed::Box` + let _ = x as Box; //~ERROR `Box` as `Box` let x: Box = Box::new(Bar); let _: Box = x; // functions fn baz(_x: i32) {} - let _ = &baz as &dyn Fn(i32); //~ERROR `&fn(i32) {main::baz}` as `&dyn std::ops::Fn(i32)` + let _ = &baz as &dyn Fn(i32); //~ERROR `&fn(i32) {baz}` as `&dyn Fn(i32)` let _: &dyn Fn(i32) = &baz; let x = |_x: i32| {}; let _ = &x as &dyn Fn(i32); //~ERROR trivial cast diff --git a/src/test/ui/trivial_casts.stderr b/src/test/ui/trivial_casts.stderr index 70954f00ba..141703460b 100644 --- a/src/test/ui/trivial_casts.stderr +++ b/src/test/ui/trivial_casts.stderr @@ -72,7 +72,7 @@ LL | let _ = x as *mut [u32]; | = help: cast can be replaced by coercion; this might require a temporary variable -error: trivial cast: `std::boxed::Box<[u32; 3]>` as `std::boxed::Box<[u32]>` +error: trivial cast: `Box<[u32; 3]>` as `Box<[u32]>` --> $DIR/trivial_casts.rs:45:13 | LL | let _ = x as Box<[u32]>; @@ -112,7 +112,7 @@ LL | let _ = x as *mut dyn Foo; | = help: cast can be replaced by coercion; this might require a temporary variable -error: trivial cast: `std::boxed::Box` as `std::boxed::Box` +error: trivial cast: `Box` as `Box` --> $DIR/trivial_casts.rs:64:13 | LL | let _ = x as Box; @@ -120,7 +120,7 @@ LL | let _ = x as Box; | = help: cast can be replaced by coercion; this might require a temporary variable -error: trivial cast: `&fn(i32) {main::baz}` as `&dyn std::ops::Fn(i32)` +error: trivial cast: `&fn(i32) {baz}` as `&dyn Fn(i32)` --> $DIR/trivial_casts.rs:70:13 | LL | let _ = &baz as &dyn Fn(i32); @@ -128,7 +128,7 @@ LL | let _ = &baz as &dyn Fn(i32); | = help: cast can be replaced by coercion; this might require a temporary variable -error: trivial cast: `&[closure@$DIR/trivial_casts.rs:72:13: 72:25]` as `&dyn std::ops::Fn(i32)` +error: trivial cast: `&[closure@$DIR/trivial_casts.rs:72:13: 72:25]` as `&dyn Fn(i32)` --> $DIR/trivial_casts.rs:73:13 | LL | let _ = &x as &dyn Fn(i32); diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs index 4dfc8e6a2f..c338294913 100644 --- a/src/test/ui/try-block/try-block-bad-type.rs +++ b/src/test/ui/try-block/try-block-bad-type.rs @@ -14,7 +14,7 @@ pub fn main() { let res: Result = try { }; //~ ERROR type mismatch - let res: () = try { }; //~ the trait bound `(): std::ops::Try` is not satisfied + let res: () = try { }; //~ the trait bound `(): Try` is not satisfied - let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied + let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: Try` is not satisfied } diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index 414c3f24d3..03d5d3661d 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -2,44 +2,44 @@ error[E0277]: `?` couldn't convert the error to `i32` --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; - | ^ the trait `std::convert::From<&str>` is not implemented for `i32` + | ^ the trait `From<&str>` is not implemented for `i32` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following implementations were found: - > - > - > - > + > + > + > + > and 2 others - = note: required by `std::convert::From::from` + = note: required by `from` -error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == &str` +error[E0271]: type mismatch resolving ` as Try>::Ok == &str` --> $DIR/try-block-bad-type.rs:12:9 | LL | "" | ^^ expected `i32`, found `&str` -error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == ()` +error[E0271]: type mismatch resolving ` as Try>::Ok == ()` --> $DIR/try-block-bad-type.rs:15:39 | LL | let res: Result = try { }; | ^ expected `i32`, found `()` -error[E0277]: the trait bound `(): std::ops::Try` is not satisfied +error[E0277]: the trait bound `(): Try` is not satisfied --> $DIR/try-block-bad-type.rs:17:23 | LL | let res: () = try { }; - | ^^^ the trait `std::ops::Try` is not implemented for `()` + | ^^^ the trait `Try` is not implemented for `()` | - = note: required by `std::ops::Try::from_ok` + = note: required by `from_ok` -error[E0277]: the trait bound `i32: std::ops::Try` is not satisfied +error[E0277]: the trait bound `i32: Try` is not satisfied --> $DIR/try-block-bad-type.rs:19:24 | LL | let res: i32 = try { 5 }; - | ^^^^^ the trait `std::ops::Try` is not implemented for `i32` + | ^^^^^ the trait `Try` is not implemented for `i32` | - = note: required by `std::ops::Try::from_ok` + = note: required by `from_ok` error: aborting due to 5 previous errors diff --git a/src/test/ui/try-block/try-block-in-return.rs b/src/test/ui/try-block/try-block-in-return.rs new file mode 100644 index 0000000000..a15bfeef1c --- /dev/null +++ b/src/test/ui/try-block/try-block-in-return.rs @@ -0,0 +1,12 @@ +// run-pass +// compile-flags: --edition 2018 + +#![feature(try_blocks)] + +fn issue_76271() -> Option { + return try { 4 } +} + +fn main() { + assert_eq!(issue_76271(), Some(4)); +} diff --git a/src/test/ui/try-block/try-block-in-while.rs b/src/test/ui/try-block/try-block-in-while.rs index 33d2723651..5d8748f1dd 100644 --- a/src/test/ui/try-block/try-block-in-while.rs +++ b/src/test/ui/try-block/try-block-in-while.rs @@ -4,5 +4,5 @@ fn main() { while try { false } {} - //~^ ERROR the trait bound `bool: std::ops::Try` is not satisfied + //~^ ERROR the trait bound `bool: Try` is not satisfied } diff --git a/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr index ac41ddfd8c..bc0f5bb650 100644 --- a/src/test/ui/try-block/try-block-in-while.stderr +++ b/src/test/ui/try-block/try-block-in-while.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `bool: std::ops::Try` is not satisfied +error[E0277]: the trait bound `bool: Try` is not satisfied --> $DIR/try-block-in-while.rs:6:15 | LL | while try { false } {} - | ^^^^^^^^^ the trait `std::ops::Try` is not implemented for `bool` + | ^^^^^^^^^ the trait `Try` is not implemented for `bool` | - = note: required by `std::ops::Try::from_ok` + = note: required by `from_ok` error: aborting due to previous error diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr index 1f0e09277b..c092aa2694 100644 --- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr +++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr @@ -14,7 +14,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/try-block-maybe-bad-lifetime.rs:28:24 | LL | let x = String::new(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | ::std::mem::drop(x); | - value moved here diff --git a/src/test/ui/try-block/try-block-type-error.stderr b/src/test/ui/try-block/try-block-type-error.stderr index f779121bbc..df1441c83d 100644 --- a/src/test/ui/try-block/try-block-type-error.stderr +++ b/src/test/ui/try-block/try-block-type-error.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == {integer}` +error[E0271]: type mismatch resolving ` as Try>::Ok == {integer}` --> $DIR/try-block-type-error.rs:10:9 | LL | 42 @@ -7,7 +7,7 @@ LL | 42 | expected `f32`, found integer | help: use a float literal: `42.0` -error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == ()` +error[E0271]: type mismatch resolving ` as Try>::Ok == ()` --> $DIR/try-block-type-error.rs:16:5 | LL | }; diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-on-option-diagnostics.stderr index c9dc3f1b87..a71ee20aac 100644 --- a/src/test/ui/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-on-option-diagnostics.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-diagnostics.rs:7:5 | LL | / fn a_function() -> u32 { @@ -9,10 +9,10 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `u32` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `u32` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-diagnostics.rs:14:9 | LL | let a_closure = || { @@ -24,10 +24,10 @@ LL | | 22 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-diagnostics.rs:26:13 | LL | / fn a_method() { @@ -37,10 +37,10 @@ LL | | x?; LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-diagnostics.rs:39:13 | LL | / fn a_trait_method() { @@ -50,8 +50,8 @@ LL | | x?; LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` error: aborting due to 4 previous errors diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index 33ca58bf7f..ecd12c430f 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -5,16 +5,16 @@ LL | fn foo() -> Result { | --------------- expected `()` because of this LL | let x: Option = None; LL | x?; - | ^ the trait `std::convert::From` is not implemented for `()` + | ^ the trait `From` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `std::convert::From::from` + = note: required by `from` help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` | LL | x.ok_or_else(|| /* error value */)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option.rs:13:5 | LL | / fn bar() -> u32 { @@ -25,8 +25,8 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `u32` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `u32` + = note: required by `from_error` error: aborting due to 2 previous errors diff --git a/src/test/ui/try-operator-on-main.rs b/src/test/ui/try-operator-on-main.rs index 602c3c5c35..a8a99a150c 100644 --- a/src/test/ui/try-operator-on-main.rs +++ b/src/test/ui/try-operator-on-main.rs @@ -19,7 +19,7 @@ fn main() { fn try_trait_generic() -> T { // and a non-`Try` object on a `Try` fn. - ()?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + ()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` loop {} } diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-operator-on-main.stderr index ecad5a7d11..f2e17812ae 100644 --- a/src/test/ui/try-operator-on-main.stderr +++ b/src/test/ui/try-operator-on-main.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-operator-on-main.rs:9:5 | LL | / fn main() { @@ -11,35 +11,35 @@ LL | | try_trait_generic::<()>(); LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/try-operator-on-main.rs:12:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `()` + = note: required by `into_result` -error[E0277]: the trait bound `(): std::ops::Try` is not satisfied +error[E0277]: the trait bound `(): Try` is not satisfied --> $DIR/try-operator-on-main.rs:15:25 | LL | try_trait_generic::<()>(); - | ^^ the trait `std::ops::Try` is not implemented for `()` + | ^^ the trait `Try` is not implemented for `()` ... LL | fn try_trait_generic() -> T { | --- required by this bound in `try_trait_generic` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/try-operator-on-main.rs:22:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `()` + = note: required by `into_result` error: aborting due to 4 previous errors diff --git a/src/test/ui/tuple/index-invalid.stderr b/src/test/ui/tuple/index-invalid.stderr index 800b5a31d9..8d22f458a6 100644 --- a/src/test/ui/tuple/index-invalid.stderr +++ b/src/test/ui/tuple/index-invalid.stderr @@ -2,19 +2,19 @@ error[E0609]: no field `1` on type `(((),),)` --> $DIR/index-invalid.rs:2:22 | LL | let _ = (((),),).1.0; - | ^^^ + | ^ error[E0609]: no field `1` on type `((),)` - --> $DIR/index-invalid.rs:4:22 + --> $DIR/index-invalid.rs:4:24 | LL | let _ = (((),),).0.1; - | ^^^ + | ^ error[E0609]: no field `000` on type `(((),),)` --> $DIR/index-invalid.rs:6:22 | LL | let _ = (((),),).000.000; - | ^^^^^^^ + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs index 63b21faa62..8dadd77fc1 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs @@ -1,8 +1,8 @@ #[repr(u8)] enum Alpha { V1 = 41, - V2 = Self::V1 as u8 + 1, // OK; See #50072. - V3 = Self::V1 {} as u8 + 2, //~ ERROR cycle detected when const-evaluating + V2 = Self::V1 as u8 + 1, // OK; See #50072. + V3 = Self::V1 {} as u8 + 2, //~ ERROR cycle detected when simplifying constant } fn main() {} diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr index db535b53fc..277f4e8424 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr @@ -1,28 +1,28 @@ -error[E0391]: cycle detected when const-evaluating + checking `Alpha::V3::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Alpha::V3::{constant#0}` --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ | -note: ...which requires const-evaluating + checking `Alpha::V3::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`... --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ -note: ...which requires const-evaluating `Alpha::V3::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`... --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ = note: ...which requires computing layout of `Alpha`... - = note: ...which again requires const-evaluating + checking `Alpha::V3::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Alpha::V3::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/self-in-enum-definition.rs:1:1 | LL | / #[repr(u8)] LL | | enum Alpha { LL | | V1 = 41, -LL | | V2 = Self::V1 as u8 + 1, // OK; See #50072. +LL | | V2 = Self::V1 as u8 + 1, // OK; See #50072. ... | LL | | LL | | fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs index 0a4cc9b7fe..a15074c359 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs @@ -1,19 +1,18 @@ #![feature(type_alias_impl_trait)] -fn main() { -} +fn main() {} trait TraitWithAssoc { type Assoc; } type Foo = impl Trait; -//~^ ERROR the trait bound `T: TraitWithAssoc` is not satisfied trait Trait {} impl Trait for () {} fn foo_desugared(_: T) -> Foo { + //~^ ERROR non-defining opaque type use in defining scope () } diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr index 9ebf63468e..c9d6a43b90 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,14 +1,14 @@ -error[E0277]: the trait bound `T: TraitWithAssoc` is not satisfied - --> $DIR/bound_reduction2.rs:10:15 +error: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:15:46 | -LL | type Foo = impl Trait; - | ^^^^^^^^^^^^^ the trait `TraitWithAssoc` is not implemented for `T` +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^ | -help: consider further restricting this bound +note: used non-generic type `::Assoc` for generic parameter + --> $DIR/bound_reduction2.rs:9:10 | -LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^^^^ +LL | type Foo = impl Trait; + | ^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs index 09873a8c8c..7ea517eb73 100644 --- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs +++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs @@ -9,4 +9,5 @@ mod boo { fn bomp() -> boo::Boo { "" + //~^ mismatched types } diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr index c0cb94b15d..0b4c262bbb 100644 --- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr +++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr @@ -4,5 +4,20 @@ error: could not find defining uses LL | pub type Boo = impl ::std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/declared_but_not_defined_in_scope.rs:11:5 + | +LL | pub type Boo = impl ::std::fmt::Debug; + | ---------------------- the expected opaque type +... +LL | fn bomp() -> boo::Boo { + | -------- expected `impl Debug` because of return type +LL | "" + | ^^ expected opaque type, found `&str` + | + = note: expected opaque type `impl Debug` + found reference `&'static str` + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs index 2b98d8fc63..a74731df69 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs @@ -8,10 +8,10 @@ fn main() {} type Two = impl Debug; fn one(t: T) -> Two { + //~^ ERROR non-defining opaque type use in defining scope t } fn two(t: T, _: U) -> Two { -//~^ ERROR concrete type differs from previous defining opaque type use t } diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr index 7900da47ca..d87e8c5783 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr @@ -1,14 +1,14 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/generic_duplicate_param_use2.rs:14:1 +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_param_use2.rs:10:27 | -LL | fn two(t: T, _: U) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T` +LL | fn one(t: T) -> Two { + | ^^^^^^^^^ | -note: previous use here - --> $DIR/generic_duplicate_param_use2.rs:10:1 +note: type used multiple times + --> $DIR/generic_duplicate_param_use2.rs:8:10 | -LL | fn one(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type Two = impl Debug; + | ^ ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs index d9133fd11f..0597b8385d 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs @@ -8,11 +8,11 @@ fn main() {} type Two = impl Debug; fn one(t: T) -> Two { + //~^ ERROR non-defining opaque type use in defining scope t } fn two(t: T, _: U) -> Two { -//~^ ERROR concrete type differs from previous defining opaque type use t } diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr index ac5f7947d5..711de855f0 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr @@ -1,14 +1,14 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/generic_duplicate_param_use3.rs:14:1 +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_param_use3.rs:10:27 | -LL | fn two(t: T, _: U) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T` +LL | fn one(t: T) -> Two { + | ^^^^^^^^^ | -note: previous use here - --> $DIR/generic_duplicate_param_use3.rs:10:1 +note: type used multiple times + --> $DIR/generic_duplicate_param_use3.rs:8:10 | -LL | fn one(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type Two = impl Debug; + | ^ ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs index 589612d5ed..766ee36c02 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs @@ -3,10 +3,11 @@ fn main() {} trait Trait {} -type Underconstrained = impl 'static; //~ ERROR the trait bound `T: Trait` +type Underconstrained = impl 'static; //~^ ERROR: at least one trait must be specified // no `Trait` bound fn underconstrain(_: T) -> Underconstrained { + //~^ ERROR the trait bound `T: Trait` unimplemented!() } diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr index 911f592f73..cefc5d99b3 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -5,12 +5,14 @@ LL | type Underconstrained = impl 'static; | ^^^^^^^^^^^^ error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/generic_underconstrained.rs:6:35 + --> $DIR/generic_underconstrained.rs:10:31 | LL | type Underconstrained = impl 'static; - | ^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | ----- required by this bound in `Underconstrained` +... +LL | fn underconstrain(_: T) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | - = note: the return type of a function must have a statically known size help: consider restricting type parameter `T` | LL | fn underconstrain(_: T) -> Underconstrained { diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs index 87b8aaad95..cd7c962e2d 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs @@ -3,19 +3,19 @@ fn main() {} type Underconstrained = impl 'static; -//~^ ERROR `U` doesn't implement `std::fmt::Debug` -//~^^ ERROR: at least one trait must be specified +//~^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained(_: U) -> Underconstrained { + //~^ ERROR `U` doesn't implement `Debug` 5u32 } type Underconstrained2 = impl 'static; -//~^ ERROR `V` doesn't implement `std::fmt::Debug` -//~^^ ERROR: at least one trait must be specified +//~^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained2(_: U, _: V) -> Underconstrained2 { + //~^ ERROR `V` doesn't implement `Debug` 5u32 } diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 28e30cbdd9..669546aef8 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -10,35 +10,33 @@ error: at least one trait must be specified LL | type Underconstrained2 = impl 'static; | ^^^^^^^^^^^^ -error[E0277]: `U` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:5:45 +error[E0277]: `U` doesn't implement `Debug` + --> $DIR/generic_underconstrained2.rs:9:33 | LL | type Underconstrained = impl 'static; - | ^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | --------------- required by this bound in `Underconstrained` ... -LL | 5u32 - | ---- this returned value is of type `u32` +LL | fn underconstrained(_: U) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: the return type of a function must have a statically known size help: consider restricting type parameter `U` | -LL | fn underconstrained(_: U) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^ +LL | fn underconstrained(_: U) -> Underconstrained { + | ^^^^^^^ -error[E0277]: `V` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:14:46 +error[E0277]: `V` doesn't implement `Debug` + --> $DIR/generic_underconstrained2.rs:18:43 | LL | type Underconstrained2 = impl 'static; - | ^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | --------------- required by this bound in `Underconstrained2` ... -LL | 5u32 - | ---- this returned value is of type `u32` +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: the return type of a function must have a statically known size help: consider restricting type parameter `V` | -LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ^^^^^^^^^^^^^^^^^ +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | ^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs index bc6543a922..851c2f66c4 100644 --- a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs +++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs @@ -9,10 +9,9 @@ trait X { } impl X for () { + //~^ ERROR the type parameter `T` is not constrained type I = impl Sized; - //~^ ERROR could not find defining uses fn f() -> Self::I {} - //~^ ERROR type annotations needed } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr index e8b677113d..8cf8fb1d16 100644 --- a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr +++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr @@ -1,15 +1,9 @@ -error[E0282]: type annotations needed - --> $DIR/impl-with-unconstrained-param.rs:14:23 +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/impl-with-unconstrained-param.rs:11:6 | -LL | fn f() -> Self::I {} - | ^^ cannot infer type for type parameter `T` +LL | impl X for () { + | ^ unconstrained type parameter -error: could not find defining uses - --> $DIR/impl-with-unconstrained-param.rs:12:14 - | -LL | type I = impl Sized; - | ^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr index f8e1e55f23..cb893c40c3 100644 --- a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr +++ b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr @@ -5,8 +5,8 @@ LL | impl FnOnce<()> for &F { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::ops::FnOnce for &F - where F: std::ops::Fn, F: ?Sized; + - impl FnOnce for &F + where F: Fn, F: ?Sized; error[E0210]: type parameter `F` must be used as the type parameter for some local type (e.g., `MyStruct`) --> $DIR/incoherent-assoc-imp-trait.rs:10:6 diff --git a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr index 13069126ba..d82050e263 100644 --- a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr @@ -2,7 +2,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/issue-52843-closure-constrain.rs:10:16 | LL | let null = || -> Opaque { 0 }; - | ^^^^^^^^^^^^^^^^^^ expected `std::string::String`, got `i32` + | ^^^^^^^^^^^^^^^^^^ expected `String`, got `i32` | note: previous use here --> $DIR/issue-52843-closure-constrain.rs:9:5 diff --git a/src/test/ui/type-alias-impl-trait/issue-53096.rs b/src/test/ui/type-alias-impl-trait/issue-53096.rs index 564c5c3d33..bdf426bbd3 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53096.rs +++ b/src/test/ui/type-alias-impl-trait/issue-53096.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(const_fn)] +#![feature(const_fn, const_fn_fn_ptr_basics)] #![feature(type_alias_impl_trait)] type Foo = impl Fn() -> usize; diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index 41e019247c..782eb0fb3d 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -22,6 +22,6 @@ impl Foo for X { } } -trait Baz = Fn(&A) -> &B; +trait Baz = Fn(&A) -> &B; fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index cd637056c9..a8706aa9a2 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | type Bar = impl Baz; | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(&X,)>` - found type `std::ops::FnOnce<(&X,)>` + = note: expected type `FnOnce<(&X,)>` + found type `FnOnce<(&X,)>` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr index d07f64c331..9ad181b368 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr @@ -1,10 +1,10 @@ -error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:8:5: 8:28] as std::ops::FnOnce<()>>::Output == ()` +error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:8:5: 8:28] as FnOnce<()>>::Output == ()` --> $DIR/issue-63279.rs:5:16 | LL | type Closure = impl FnOnce(); | ^^^^^^^^^^^^^ expected opaque type, found `()` | - = note: expected opaque type `impl std::ops::FnOnce<()>` + = note: expected opaque type `impl FnOnce<()>` found unit type `()` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.rs b/src/test/ui/type-alias-impl-trait/issue-74761.rs new file mode 100644 index 0000000000..4345b5d886 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74761.rs @@ -0,0 +1,16 @@ +#![feature(member_constraints)] +#![feature(type_alias_impl_trait)] + +pub trait A { + type B; + fn f(&self) -> Self::B; +} +impl<'a, 'b> A for () { + //~^ ERROR the lifetime parameter `'a` is not constrained + //~| ERROR the lifetime parameter `'b` is not constrained + type B = impl core::fmt::Debug; + + fn f(&self) -> Self::B {} +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.stderr b/src/test/ui/type-alias-impl-trait/issue-74761.stderr new file mode 100644 index 0000000000..3f38fa4de0 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74761.stderr @@ -0,0 +1,15 @@ +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-74761.rs:8:6 + | +LL | impl<'a, 'b> A for () { + | ^^ unconstrained lifetime parameter + +error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-74761.rs:8:10 + | +LL | impl<'a, 'b> A for () { + | ^^ unconstrained lifetime parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs new file mode 100644 index 0000000000..9ce19536e7 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs @@ -0,0 +1,23 @@ +// Regression test for issue #76202 +// Tests that we don't ICE when we have a trait impl on a TAIT. + +#![feature(type_alias_impl_trait)] + +trait Dummy {} +impl Dummy for () {} + +type F = impl Dummy; +fn f() -> F {} + +trait Test { + fn test(self); +} + +impl Test for F { //~ ERROR cannot implement trait + fn test(self) {} +} + +fn main() { + let x: F = f(); + x.test(); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr new file mode 100644 index 0000000000..8689ee5366 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr @@ -0,0 +1,14 @@ +error: cannot implement trait on type alias impl trait + --> $DIR/issue-76202-trait-impl-for-tait.rs:16:1 + | +LL | impl Test for F { + | ^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/issue-76202-trait-impl-for-tait.rs:9:10 + | +LL | type F = impl Dummy; + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr index a6b7e35b48..b438f84451 100644 --- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr @@ -10,9 +10,9 @@ LL | let _: &'static str = x; | expected due to this | = note: expected reference `&'static str` - found opaque type `impl std::fmt::Debug` + found opaque type `impl Debug` -error[E0605]: non-primitive cast: `impl std::fmt::Debug` as `&'static str` +error[E0605]: non-primitive cast: `impl Debug` as `&'static str` --> $DIR/never_reveal_concrete_type.rs:14:13 | LL | let _ = x as &'static str; diff --git a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr index d237cc6238..67752acb8c 100644 --- a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr +++ b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr @@ -10,7 +10,7 @@ LL | let _: &str = bomp(); | expected due to this | = note: expected reference `&str` - found opaque type `impl std::fmt::Debug` + found opaque type `impl Debug` error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:19:5 @@ -19,11 +19,11 @@ LL | pub type Boo = impl ::std::fmt::Debug; | ---------------------- the expected opaque type ... LL | fn bomp() -> boo::Boo { - | -------- expected `impl std::fmt::Debug` because of return type + | -------- expected `impl Debug` because of return type LL | "" | ^^ expected opaque type, found `&str` | - = note: expected opaque type `impl std::fmt::Debug` + = note: expected opaque type `impl Debug` found reference `&'static str` error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs index 02485b24e7..f29b980dfd 100644 --- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs +++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs @@ -7,6 +7,7 @@ fn main() {} type Two = impl Debug; fn two(t: T) -> Two { + //~^ ERROR non-defining opaque type use in defining scope (t, 4i8) } @@ -24,9 +25,7 @@ impl Bar for u32 { const FOO: i32 = 42; } -// this should work! But it requires `two` and `three` not to be defining uses, -// just restricting uses -fn four(t: T) -> Two { //~ concrete type differs from previous +fn four(t: T) -> Two { (t, ::FOO) } diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr index 9ce07a879f..2fa236b373 100644 --- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr +++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr @@ -1,14 +1,14 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/not_a_defining_use.rs:29:1 +error: non-defining opaque type use in defining scope + --> $DIR/not_a_defining_use.rs:9:27 | -LL | fn four(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, ::Blub)` +LL | fn two(t: T) -> Two { + | ^^^^^^^^^^^ | -note: previous use here - --> $DIR/not_a_defining_use.rs:9:1 +note: used non-generic type `u32` for generic parameter + --> $DIR/not_a_defining_use.rs:7:13 | -LL | fn two(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type Two = impl Debug; + | ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs index 479d6cd9af..d50835608f 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs @@ -12,9 +12,9 @@ const LEAK_FREE: Bar = leak_free(); fn leak_free_test() { match todo!() { LEAK_FREE => (), - //~^ opaque types cannot be used in patterns + //~^ `impl Send` cannot be used in patterns _ => (), } } -fn main() { } +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr index ae0d8e8d42..889c4fd4b0 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr @@ -1,4 +1,4 @@ -error: opaque types cannot be used in patterns +error: `impl Send` cannot be used in patterns --> $DIR/structural-match-no-leak.rs:14:9 | LL | LEAK_FREE => (), diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs index 481448d64b..a3ff4ad1d4 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match.rs @@ -13,9 +13,9 @@ const VALUE: Foo = value(); fn test() { match todo!() { VALUE => (), - //~^ opaque types cannot be used in patterns + //~^ `impl Send` cannot be used in patterns _ => (), } } -fn main() { } +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/structural-match.stderr b/src/test/ui/type-alias-impl-trait/structural-match.stderr index ad9036a87d..262fd07261 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match.stderr @@ -1,4 +1,4 @@ -error: opaque types cannot be used in patterns +error: `impl Send` cannot be used in patterns --> $DIR/structural-match.rs:15:9 | LL | VALUE => (), diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs index bc2bf9eca9..01769f7115 100644 --- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs @@ -4,7 +4,7 @@ // Currently, the `type_alias_impl_trait` feature implicitly // depends on `impl_trait_in_bindings` in order to work properly. // Specifically, this line requires `impl_trait_in_bindings` to be enabled: -// https://github.com/rust-lang/rust/blob/481068a707679257e2a738b40987246e0420e787/src/librustc_typeck/check/mod.rs#L856 +// https://github.com/rust-lang/rust/blob/481068a707679257e2a738b40987246e0420e787/compiler/rustc_typeck/check/mod.rs#L856 #![feature(impl_trait_in_bindings)] //~^ WARN the feature `impl_trait_in_bindings` is incomplete diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs new file mode 100644 index 0000000000..efbf4f1e35 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs @@ -0,0 +1,18 @@ +// regression test for #74018 + +#![feature(type_alias_impl_trait)] + +trait Trait { + type Associated; + fn into(self) -> Self::Associated; +} + +impl<'a, I: Iterator> Trait for (i32, I) { + //~^ ERROR the lifetime parameter `'a` is not constrained + type Associated = (i32, impl Iterator); + fn into(self) -> Self::Associated { + (0_i32, [0_i32].iter().copied()) + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr new file mode 100644 index 0000000000..8cdce2f8e8 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr @@ -0,0 +1,9 @@ +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/type-alias-impl-trait-unconstrained-lifetime.rs:10:6 + | +LL | impl<'a, I: Iterator> Trait for (i32, I) { + | ^^ unconstrained lifetime parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.rs b/src/test/ui/type-alias/issue-62263-self-in-atb.rs index 5e812db4d2..1f64b4cfe5 100644 --- a/src/test/ui/type-alias/issue-62263-self-in-atb.rs +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.rs @@ -3,6 +3,6 @@ pub trait Trait { } pub type Alias = dyn Trait; -//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] +//~^ ERROR failed to resolve: use of undeclared type `Self` [E0433] fn main() {} diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.stderr b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr index a642d029f9..d34b6ed503 100644 --- a/src/test/ui/type-alias/issue-62263-self-in-atb.stderr +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/issue-62263-self-in-atb.rs:5:32 | LL | pub type Alias = dyn Trait; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to previous error diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs index 0b95ddeb19..999902fb18 100644 --- a/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs @@ -1,4 +1,4 @@ type Alias = Self::Target; -//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] +//~^ ERROR failed to resolve: use of undeclared type `Self` [E0433] fn main() {} diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr index 6eb445e9db..823a5fa50f 100644 --- a/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/issue-62305-self-assoc-ty.rs:1:14 | LL | type Alias = Self::Target; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to previous error diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index 927cc50726..97817a1f9f 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -7,7 +7,7 @@ LL | fn foo>(x: i32) {} LL | foo(42); | ^^^ cannot infer type for type parameter `T` declared on the function `foo` | - = note: cannot satisfy `_: std::convert::Into` + = note: cannot satisfy `_: Into` help: consider specifying the type argument in the function call | LL | foo::(42); diff --git a/src/test/ui/type/type-check-defaults.rs b/src/test/ui/type/type-check-defaults.rs index 5380fae541..6a0a7ed338 100644 --- a/src/test/ui/type/type-check-defaults.rs +++ b/src/test/ui/type/type-check-defaults.rs @@ -9,17 +9,17 @@ struct WellFormedNoBounds>(Z); //~^ ERROR a value of type `i32` cannot be built from an iterator over elements of type `i32` struct Bounds(T); -//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `String: Copy` is not satisfied [E0277] struct WhereClause(T) where T: Copy; -//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `String: Copy` is not satisfied [E0277] trait TraitBound {} -//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `String: Copy` is not satisfied [E0277] trait Super { } trait Base: Super { } -//~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `T: Copy` is not satisfied [E0277] trait ProjectionPred> where T::Item : Add {} //~^ ERROR cannot add `u8` to `i32` [E0277] diff --git a/src/test/ui/type/type-check-defaults.stderr b/src/test/ui/type/type-check-defaults.stderr index e2729c65e0..d8c7f595e6 100644 --- a/src/test/ui/type/type-check-defaults.stderr +++ b/src/test/ui/type/type-check-defaults.stderr @@ -6,7 +6,7 @@ LL | struct Foo>(T, U); LL | struct WellFormed>(Z); | ^ value of type `i32` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator` is not implemented for `i32` + = help: the trait `FromIterator` is not implemented for `i32` error[E0277]: a value of type `i32` cannot be built from an iterator over elements of type `i32` --> $DIR/type-check-defaults.rs:8:27 @@ -17,47 +17,47 @@ LL | struct Foo>(T, U); LL | struct WellFormedNoBounds>(Z); | ^ value of type `i32` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator` is not implemented for `i32` + = help: the trait `FromIterator` is not implemented for `i32` -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/type-check-defaults.rs:11:17 | LL | struct Bounds(T); | ----------------^^^^------------ | | | - | | the trait `std::marker::Copy` is not implemented for `std::string::String` + | | the trait `Copy` is not implemented for `String` | required by `Bounds` -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/type-check-defaults.rs:14:42 | LL | struct WhereClause(T) where T: Copy; | -----------------------------------------^^^^- | | | - | | the trait `std::marker::Copy` is not implemented for `std::string::String` + | | the trait `Copy` is not implemented for `String` | required by `WhereClause` -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/type-check-defaults.rs:17:20 | LL | trait TraitBound {} | -------------------^^^^-------- | | | - | | the trait `std::marker::Copy` is not implemented for `std::string::String` + | | the trait `Copy` is not implemented for `String` | required by `TraitBound` -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/type-check-defaults.rs:21:25 | LL | trait Super { } | ---- required by this bound in `Super` LL | trait Base: Super { } - | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider further restricting type parameter `T` | -LL | trait Base: Super, T: std::marker::Copy { } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Base: Super where T: Copy { } + | ^^^^^^^^^^^^^ error[E0277]: cannot add `u8` to `i32` --> $DIR/type-check-defaults.rs:24:66 @@ -68,7 +68,7 @@ LL | trait ProjectionPred> where T::Item : Add {} | | no implementation for `i32 + u8` | required by `ProjectionPred` | - = help: the trait `std::ops::Add` is not implemented for `i32` + = help: the trait `Add` is not implemented for `i32` error: aborting due to 7 previous errors diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr index 3f1caddf72..d1c13a33f7 100644 --- a/src/test/ui/type/type-check/assignment-expected-bool.stderr +++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr @@ -2,100 +2,126 @@ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:6:19 | LL | let _: bool = 0 = 0; - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | let _: bool = 0 == 0; + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:9:14 | LL | 0 => 0 = 0, - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | 0 => 0 == 0, + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:10:14 | LL | _ => 0 = 0, - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | _ => 0 == 0, + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:14:17 | LL | true => 0 = 0, - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | true => 0 == 0, + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:18:8 | LL | if 0 = 0 {} - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let 0 = 0 {} + | ^^^ +help: you might have meant to compare for equality + | +LL | if 0 == 0 {} + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:20:24 | LL | let _: bool = if { 0 = 0 } { - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | let _: bool = if { 0 == 0 } { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:21:9 | LL | 0 = 0 - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | 0 == 0 + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:23:9 | LL | 0 = 0 - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | 0 == 0 + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:26:13 | LL | let _ = (0 = 0) - | ^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | let _ = (0 == 0) + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:27:14 | LL | && { 0 = 0 } - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | && { 0 == 0 } + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:28:12 | LL | || (0 = 0); - | ^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | || (0 == 0); + | ^^ error[E0070]: invalid left-hand side of assignment --> $DIR/assignment-expected-bool.rs:31:22 diff --git a/src/test/ui/type/type-check/assignment-in-if.stderr b/src/test/ui/type/type-check/assignment-in-if.stderr index 0957dcb986..f5306a1226 100644 --- a/src/test/ui/type/type-check/assignment-in-if.stderr +++ b/src/test/ui/type/type-check/assignment-in-if.stderr @@ -2,55 +2,71 @@ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:15:8 | LL | if x = x { - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == x` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | if x == x { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:20:8 | LL | if (x = x) { - | ^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == x` + | ^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | if (x == x) { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:25:8 | LL | if y = (Foo { foo: x }) { - | ^^^^^^^^^^^^^^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `y == (Foo { foo: x })` + | ^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | if y == (Foo { foo: x }) { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:30:8 | LL | if 3 = x { - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `3 == x` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let 3 = x { + | ^^^ +help: you might have meant to compare for equality + | +LL | if 3 == x { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:36:13 | LL | x = 4 - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == 4` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | x == 4 + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:38:13 | LL | x = 5 - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == 5` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | x == 5 + | ^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr index 8162fed2cd..729a8c63b6 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed for `std::vec::Vec` +error[E0282]: type annotations needed for `Vec` --> $DIR/cannot_infer_local_or_vec.rs:2:13 | LL | let x = vec![]; | - ^^^^^^ cannot infer type for type parameter `T` | | - | consider giving `x` the explicit type `std::vec::Vec`, where the type parameter `T` is specified + | consider giving `x` the explicit type `Vec`, where the type parameter `T` is specified | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr index e62565c8f9..e24593a89b 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed for `(std::vec::Vec,)` +error[E0282]: type annotations needed for `(Vec,)` --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18 | LL | let (x, ) = (vec![], ); | ----- ^^^^^^ cannot infer type for type parameter `T` | | - | consider giving this pattern the explicit type `(std::vec::Vec,)`, where the type parameter `T` is specified + | consider giving this pattern the explicit type `(Vec,)`, where the type parameter `T` is specified | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/type/type-mismatch-same-crate-name.rs b/src/test/ui/type/type-mismatch-same-crate-name.rs index eeda5460ac..c9cdc874c0 100644 --- a/src/test/ui/type/type-mismatch-same-crate-name.rs +++ b/src/test/ui/type/type-mismatch-same-crate-name.rs @@ -21,7 +21,7 @@ fn main() { //~^ ERROR mismatched types //~| perhaps two different versions of crate `crate_a1` //~| expected trait `main::a::Bar` - //~| expected struct `std::boxed::Box<(dyn main::a::Bar + 'static)>` - //~| found struct `std::boxed::Box` + //~| expected struct `Box<(dyn main::a::Bar + 'static)>` + //~| found struct `Box` } } diff --git a/src/test/ui/type/type-mismatch-same-crate-name.stderr b/src/test/ui/type/type-mismatch-same-crate-name.stderr index be5406696b..49d40ebed1 100644 --- a/src/test/ui/type/type-mismatch-same-crate-name.stderr +++ b/src/test/ui/type/type-mismatch-same-crate-name.stderr @@ -12,8 +12,8 @@ error[E0308]: mismatched types LL | a::try_bar(bar2); | ^^^^ expected trait `main::a::Bar`, found a different trait `main::a::Bar` | - = note: expected struct `std::boxed::Box<(dyn main::a::Bar + 'static)>` - found struct `std::boxed::Box` + = note: expected struct `Box<(dyn main::a::Bar + 'static)>` + found struct `Box` = note: perhaps two different versions of crate `crate_a1` are being used? error: aborting due to 2 previous errors diff --git a/src/test/ui/type/type-path-err-node-types.rs b/src/test/ui/type/type-path-err-node-types.rs index 15adfebb33..b3795772e6 100644 --- a/src/test/ui/type/type-path-err-node-types.rs +++ b/src/test/ui/type/type-path-err-node-types.rs @@ -12,7 +12,7 @@ fn ufcs_trait() { } fn ufcs_item() { - NonExistent::Assoc::; //~ ERROR undeclared type or module `NonExistent` + NonExistent::Assoc::; //~ ERROR undeclared type `NonExistent` } fn method() { diff --git a/src/test/ui/type/type-path-err-node-types.stderr b/src/test/ui/type/type-path-err-node-types.stderr index ea9cca2bfa..baf218243c 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `NonExistent` +error[E0433]: failed to resolve: use of undeclared type `NonExistent` --> $DIR/type-path-err-node-types.rs:15:5 | LL | NonExistent::Assoc::; - | ^^^^^^^^^^^ use of undeclared type or module `NonExistent` + | ^^^^^^^^^^^ use of undeclared type `NonExistent` error[E0412]: cannot find type `Nonexistent` in this scope --> $DIR/type-path-err-node-types.rs:7:12 diff --git a/src/test/ui/type_length_limit.rs b/src/test/ui/type_length_limit.rs index 921cded503..c1f3acbecf 100644 --- a/src/test/ui/type_length_limit.rs +++ b/src/test/ui/type_length_limit.rs @@ -1,5 +1,6 @@ // build-fail // error-pattern: reached the type-length limit while instantiating +// normalize-stderr-test: ".nll/" -> "/" // Test that the type length limit can be changed. diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr index 83da193eb0..a2ddffff99 100644 --- a/src/test/ui/type_length_limit.stderr +++ b/src/test/ui/type_length_limit.stderr @@ -1,10 +1,11 @@ -error: reached the type-length limit while instantiating `std::mem::drop::>` +error: reached the type-length limit while instantiating `std::mem::drop::>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | LL | pub fn drop(_x: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: consider adding a `#![type_length_limit="8"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt' + = help: consider adding a `#![type_length_limit="8"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr index a656b20c23..b4d7dfe06b 100644 --- a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr +++ b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | fn ice(x: Box>) { | - possibly return type missing here? LL | *x - | ^^ expected `()`, found trait object `dyn std::iter::Iterator` + | ^^ expected `()`, found trait object `dyn Iterator` | = note: expected unit type `()` - found trait object `(dyn std::iter::Iterator + 'static)` + found trait object `(dyn Iterator + 'static)` error: aborting due to previous error diff --git a/src/test/ui/typeck/issue-67971.stderr b/src/test/ui/typeck/issue-67971.stderr index 36ad3fcb34..5d07f9cc74 100644 --- a/src/test/ui/typeck/issue-67971.stderr +++ b/src/test/ui/typeck/issue-67971.stderr @@ -8,7 +8,7 @@ error[E0308]: mismatched types --> $DIR/issue-67971.rs:3:24 | LL | fn foo(ctx: &mut S) -> String { - | --- ^^^^^^ expected struct `std::string::String`, found `()` + | --- ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed index dd1195b99f..a9107f9987 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed @@ -7,7 +7,7 @@ trait Trait { type AssocType; fn dummy(&self) { } } -fn bar() where ::AssocType: std::marker::Send { +fn bar() where ::AssocType: Send { is_send::(); //~ ERROR E0277 } diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr index f97d41637b..17ad017294 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr @@ -7,11 +7,11 @@ LL | is_send::(); LL | fn is_send() { | ---- required by this bound in `is_send` | - = help: the trait `std::marker::Send` is not implemented for `::AssocType` + = help: the trait `Send` is not implemented for `::AssocType` help: consider further restricting the associated type | -LL | fn bar() where ::AssocType: std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar() where ::AssocType: Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr index a54826787d..90ab5be016 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr @@ -20,7 +20,7 @@ LL | impl !DefaultedTrait for (B,) { } | = note: define and implement a trait or new type instead -error[E0321]: cross-crate traits with a default impl, like `lib::DefaultedTrait`, can only be implemented for a struct/enum type defined in the current crate +error[E0321]: cross-crate traits with a default impl, like `DefaultedTrait`, can only be implemented for a struct/enum type defined in the current crate --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:20:1 | LL | impl DefaultedTrait for Box { } @@ -32,7 +32,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl DefaultedTrait for lib::Something { } | ^^^^^^^^^^^^^^^^^^^^^^^^----------------- | | | - | | `lib::Something` is not defined in the current crate + | | `Something` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr b/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr index b6ab36f515..e164bb01f7 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr @@ -7,7 +7,7 @@ LL | fn is_send() {} LL | is_send::(); | ^^^^^^^^^^^^^ `MyNotSendable` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `MyNotSendable` + = help: the trait `Send` is not implemented for `MyNotSendable` error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs index 2734b761e6..b9042188ad 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs @@ -34,7 +34,7 @@ fn main() { //~^ ERROR `MyNotSync` cannot be shared between threads safely [E0277] is_sync::(); - //~^ ERROR `std::cell::UnsafeCell` cannot be shared between threads safely [E0277] + //~^ ERROR `UnsafeCell` cannot be shared between threads safely [E0277] is_sync::(); //~^ ERROR `Managed` cannot be shared between threads safely [E0277] diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr index d671b8eb75..1f21e12597 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr @@ -7,18 +7,18 @@ LL | fn is_sync() {} LL | is_sync::(); | ^^^^^^^^^ `MyNotSync` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `MyNotSync` + = help: the trait `Sync` is not implemented for `MyNotSync` -error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely +error[E0277]: `UnsafeCell` cannot be shared between threads safely --> $DIR/typeck-default-trait-impl-negation-sync.rs:36:5 | LL | fn is_sync() {} | ---- required by this bound in `is_sync` ... LL | is_sync::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` cannot be shared between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` cannot be shared between threads safely | - = help: within `MyTypeWUnsafe`, the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` + = help: within `MyTypeWUnsafe`, the trait `Sync` is not implemented for `UnsafeCell` = note: required because it appears within the type `MyTypeWUnsafe` error[E0277]: `Managed` cannot be shared between threads safely @@ -30,7 +30,7 @@ LL | fn is_sync() {} LL | is_sync::(); | ^^^^^^^^^^^^^^^^^^^^^^^^ `Managed` cannot be shared between threads safely | - = help: within `MyTypeManaged`, the trait `std::marker::Sync` is not implemented for `Managed` + = help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed` = note: required because it appears within the type `MyTypeManaged` error: aborting due to 3 previous errors diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr index 7398b48a23..4fb423b9a2 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr @@ -9,8 +9,8 @@ LL | fn is_send() { | help: consider restricting type parameter `T` | -LL | fn foo() { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo() { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-unsafe-always-share.rs b/src/test/ui/typeck/typeck-unsafe-always-share.rs index dc5ddf5156..be87ab1726 100644 --- a/src/test/ui/typeck/typeck-unsafe-always-share.rs +++ b/src/test/ui/typeck/typeck-unsafe-always-share.rs @@ -17,15 +17,15 @@ fn test(s: T) {} fn main() { let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0)}); test(us); - //~^ ERROR `std::cell::UnsafeCell>` cannot be shared between threads safely + //~^ ERROR `UnsafeCell>` cannot be shared between threads safely let uns = UnsafeCell::new(NoSync); test(uns); - //~^ ERROR `std::cell::UnsafeCell` cannot be shared between threads safely [E0277] + //~^ ERROR `UnsafeCell` cannot be shared between threads safely [E0277] let ms = MySync{u: uns}; test(ms); - //~^ ERROR `std::cell::UnsafeCell` cannot be shared between threads safely [E0277] + //~^ ERROR `UnsafeCell` cannot be shared between threads safely [E0277] test(NoSync); //~^ ERROR `NoSync` cannot be shared between threads safely [E0277] diff --git a/src/test/ui/typeck/typeck-unsafe-always-share.stderr b/src/test/ui/typeck/typeck-unsafe-always-share.stderr index 61585fcc1c..2a6ae736d7 100644 --- a/src/test/ui/typeck/typeck-unsafe-always-share.stderr +++ b/src/test/ui/typeck/typeck-unsafe-always-share.stderr @@ -1,35 +1,35 @@ -error[E0277]: `std::cell::UnsafeCell>` cannot be shared between threads safely +error[E0277]: `UnsafeCell>` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:19:10 | LL | fn test(s: T) {} | ---- required by this bound in `test` ... LL | test(us); - | ^^ `std::cell::UnsafeCell>` cannot be shared between threads safely + | ^^ `UnsafeCell>` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell>` + = help: the trait `Sync` is not implemented for `UnsafeCell>` -error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely +error[E0277]: `UnsafeCell` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:23:10 | LL | fn test(s: T) {} | ---- required by this bound in `test` ... LL | test(uns); - | ^^^ `std::cell::UnsafeCell` cannot be shared between threads safely + | ^^^ `UnsafeCell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` + = help: the trait `Sync` is not implemented for `UnsafeCell` -error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely +error[E0277]: `UnsafeCell` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:27:5 | LL | fn test(s: T) {} | ---- required by this bound in `test` ... LL | test(ms); - | ^^^^ `std::cell::UnsafeCell` cannot be shared between threads safely + | ^^^^ `UnsafeCell` cannot be shared between threads safely | - = help: within `MySync`, the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` + = help: within `MySync`, the trait `Sync` is not implemented for `UnsafeCell` = note: required because it appears within the type `MySync` error[E0277]: `NoSync` cannot be shared between threads safely @@ -41,7 +41,7 @@ LL | fn test(s: T) {} LL | test(NoSync); | ^^^^^^ `NoSync` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `NoSync` + = help: the trait `Sync` is not implemented for `NoSync` error: aborting due to 4 previous errors diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index 782ff4948c..684f451b7c 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -405,15 +405,10 @@ LL | type X = Box<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:43:27 - | -LL | fn test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead + --> $DIR/typeck_type_placeholder_item.rs:182:21 | -LL | fn test10(&self, _x : T) { } - | ^^^ ^ +LL | type Y = impl Trait<_>; + | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:140:31 @@ -485,45 +480,6 @@ help: use type parameters instead LL | fn assoc_fn_test3() -> T; | ^^^ ^ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:61:37 - | -LL | fn clone_from(&mut self, other: _) { *self = Test9; } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn clone_from(&mut self, other: T) { *self = Test9; } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:110:34 - | -LL | fn fn_test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn fn_test10(&self, _x : T) { } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:118:41 - | -LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:182:21 - | -LL | type Y = impl Trait<_>; - | ^ not allowed in type signatures - error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:190:14 | @@ -560,6 +516,17 @@ LL | fn test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:43:27 + | +LL | fn test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn test10(&self, _x : T) { } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:58:24 | @@ -569,6 +536,17 @@ LL | fn clone(&self) -> _ { Test9 } | not allowed in type signatures | help: replace with the correct return type: `Test9` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:61:37 + | +LL | fn clone_from(&mut self, other: _) { *self = Test9; } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn clone_from(&mut self, other: T) { *self = Test9; } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:107:31 | @@ -578,6 +556,17 @@ LL | fn fn_test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:110:34 + | +LL | fn fn_test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn fn_test10(&self, _x : T) { } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:115:28 | @@ -585,7 +574,18 @@ LL | fn clone(&self) -> _ { FnTest9 } | ^ | | | not allowed in type signatures - | help: replace with the correct return type: `main::FnTest9` + | help: replace with the correct return type: `FnTest9` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:118:41 + | +LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } + | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:201:14 diff --git a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr index e3bc059d1f..88133814d2 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr @@ -5,7 +5,7 @@ LL | fn test1() -> _ { Some(42) } | ^ | | | not allowed in type signatures - | help: replace with the correct return type: `std::option::Option` + | help: replace with the correct return type: `Option` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item_help.rs:7:14 @@ -23,7 +23,7 @@ LL | const TEST3: _ = Some(42); | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `std::option::Option` + | help: replace `_` with the correct type: `Option` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item_help.rs:14:18 diff --git a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr index 59f699b702..9e710c15fd 100644 --- a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot add `u32` to `i32` LL | >::add(1, 2); | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32` | - = help: the trait `std::ops::Add` is not implemented for `i32` + = help: the trait `Add` is not implemented for `i32` error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:6:28 diff --git a/src/test/ui/unboxed-closures/issue-30906.stderr b/src/test/ui/unboxed-closures/issue-30906.stderr index 5c3a1154e7..5f343ff74a 100644 --- a/src/test/ui/unboxed-closures/issue-30906.stderr +++ b/src/test/ui/unboxed-closures/issue-30906.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | test(Compose(f, |_| {})); | ^^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(&'x str,)>` - found type `std::ops::FnOnce<(&str,)>` + = note: expected type `FnOnce<(&'x str,)>` + found type `FnOnce<(&str,)>` error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr index 58062872aa..f8c90176ff 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(|| drop(x)); - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:19:35 @@ -12,7 +12,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(|| drop(x)); - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure --> $DIR/unboxed-closure-illegal-move.rs:28:36 @@ -20,7 +20,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(move || drop(x)); - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:32:40 @@ -28,7 +28,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(move || drop(x)); - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error: aborting due to 4 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr index 0466887e37..94de194705 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr @@ -10,7 +10,7 @@ LL | } | - | | | `factorial` dropped here while still borrowed - | borrow might be used here, when `factorial` is dropped and runs the destructor for type `std::option::Option u32>>` + | borrow might be used here, when `factorial` is dropped and runs the destructor for type `Option u32>>` error[E0506]: cannot assign to `factorial` because it is borrowed --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:20:5 diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr index 18af3dc640..de20a38c44 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed for `std::option::Option` +error[E0282]: type annotations needed for `Option` --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32 | LL | let mut closure0 = None; - | ------------ consider giving `closure0` the explicit type `std::option::Option`, with the type parameters specified + | ------------ consider giving `closure0` the explicit type `Option`, with the type parameters specified ... LL | return c(); | ^^^ cannot infer type diff --git a/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr index d427873ebc..df3563455b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<(isize,)>` closure, found `S` +error[E0277]: expected a `Fn<(isize,)>` closure, found `S` --> $DIR/unboxed-closures-fnmut-as-fn.rs:28:21 | LL | fn call_itisize>(f: &F, x: isize) -> isize { @@ -7,7 +7,7 @@ LL | fn call_itisize>(f: &F, x: isize) -> isize { LL | let x = call_it(&S, 22); | ^^ expected an `Fn<(isize,)>` closure, found `S` | - = help: the trait `std::ops::Fn<(isize,)>` is not implemented for `S` + = help: the trait `Fn<(isize,)>` is not implemented for `S` error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr index ead42c1488..e97157b839 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | doit(0, &|x, y| { | - - has type `&'1 i32` | | - | has type `&std::cell::Cell<&'2 i32>` + | has type `&Cell<&'2 i32>` LL | x.set(y); | ^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr index b06f745e7c..d1f433e92d 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` +error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21 | LL | fn call_it isize>(_: &F, _: isize) -> isize { @@ -7,9 +7,9 @@ LL | fn call_it isize>(_: &F, _: isize) -> isize { LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` +error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25 | LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { @@ -18,9 +18,9 @@ LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` +error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26 | LL | fn call_it_once isize>(_: F, _: isize) -> isize { @@ -29,7 +29,7 @@ LL | fn call_it_once isize>(_: F, _: isize) -> isize { LL | let z = call_it_once(square, 22); | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` error: aborting due to 3 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr index 8f6945cda8..05b532e983 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` +error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:20:21 | LL | fn call_it isize>(_: &F, _: isize) -> isize { @@ -7,9 +7,9 @@ LL | fn call_it isize>(_: &F, _: isize) -> isize { LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` +error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:25:25 | LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { @@ -18,9 +18,9 @@ LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` +error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:30:26 | LL | fn call_it_once isize>(_: F, _: isize) -> isize { @@ -29,7 +29,7 @@ LL | fn call_it_once isize>(_: F, _: isize) -> isize { LL | let z = call_it_once(square, 22); | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` error: aborting due to 3 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr index 93a645b485..3b88b35d4b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` +error[E0277]: expected a `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21 | LL | fn call_it isize>(_: &F, _: isize) -> isize { @@ -7,9 +7,9 @@ LL | fn call_it isize>(_: &F, _: isize) -> isize { LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` +error[E0277]: expected a `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25 | LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { @@ -18,9 +18,9 @@ LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` +error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26 | LL | fn call_it_once isize>(_: F, _: isize) -> isize { @@ -29,7 +29,7 @@ LL | fn call_it_once isize>(_: F, _: isize) -> isize { LL | let z = call_it_once(square, 22); | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-const-pat.rs b/src/test/ui/union/union-const-pat.rs index cb2248cc6d..e7cb248a20 100644 --- a/src/test/ui/union/union-const-pat.rs +++ b/src/test/ui/union/union-const-pat.rs @@ -8,7 +8,6 @@ const C: U = U { a: 10 }; fn main() { match C { C => {} //~ ERROR cannot use unions in constant patterns - //~| ERROR cannot use unions in constant patterns _ => {} } } diff --git a/src/test/ui/union/union-const-pat.stderr b/src/test/ui/union/union-const-pat.stderr index bec720401b..dc87f4de52 100644 --- a/src/test/ui/union/union-const-pat.stderr +++ b/src/test/ui/union/union-const-pat.stderr @@ -4,11 +4,5 @@ error: cannot use unions in constant patterns LL | C => {} | ^ -error: cannot use unions in constant patterns - --> $DIR/union-const-pat.rs:10:9 - | -LL | C => {} - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/union/union-deref.rs b/src/test/ui/union/union-deref.rs new file mode 100644 index 0000000000..df598eea9e --- /dev/null +++ b/src/test/ui/union/union-deref.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength +//! Test the part of RFC 2514 that is about not applying `DerefMut` coercions +//! of union fields. +#![feature(untagged_unions)] + +use std::mem::ManuallyDrop; + +union U1 { x:(), f: ManuallyDrop<(T,)> } + +union U2 { x:(), f: (ManuallyDrop<(T,)>,) } + +fn main() { + let mut u : U1> = U1 { x: () }; + unsafe { (*u.f).0 = Vec::new() }; // explicit deref, this compiles + unsafe { u.f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { &mut (*u.f).0 }; // explicit deref, this compiles + unsafe { &mut u.f.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { (*u.f).0.push(0) }; // explicit deref, this compiles + unsafe { u.f.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + + let mut u : U2> = U2 { x: () }; + unsafe { (*u.f.0).0 = Vec::new() }; // explicit deref, this compiles + unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { &mut (*u.f.0).0 }; // explicit deref, this compiles + unsafe { &mut u.f.0.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { (*u.f.0).0.push(0) }; // explicit deref, this compiles + unsafe { u.f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field +} diff --git a/src/test/ui/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr new file mode 100644 index 0000000000..f7722764cd --- /dev/null +++ b/src/test/ui/union/union-deref.stderr @@ -0,0 +1,56 @@ +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:15:14 + | +LL | unsafe { u.f.0 = Vec::new() }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:17:19 + | +LL | unsafe { &mut u.f.0 }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:19:14 + | +LL | unsafe { u.f.0.push(0) }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:23:14 + | +LL | unsafe { u.f.0.0 = Vec::new() }; + | ^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:25:19 + | +LL | unsafe { &mut u.f.0.0 }; + | ^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:27:14 + | +LL | unsafe { u.f.0.0.push(0) }; + | ^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/union/union-derive-clone.rs b/src/test/ui/union/union-derive-clone.rs index 4a106cc940..8126980604 100644 --- a/src/test/ui/union/union-derive-clone.rs +++ b/src/test/ui/union/union-derive-clone.rs @@ -2,7 +2,7 @@ use std::mem::ManuallyDrop; -#[derive(Clone)] //~ ERROR the trait bound `U1: std::marker::Copy` is not satisfied +#[derive(Clone)] //~ ERROR the trait bound `U1: Copy` is not satisfied union U1 { a: u8, } diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index f02b7605a3..7a59f539c3 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `U1: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U1: Copy` is not satisfied --> $DIR/union-derive-clone.rs:5:10 | LL | #[derive(Clone)] - | ^^^^^ the trait `std::marker::Copy` is not implemented for `U1` + | ^^^^^ the trait `Copy` is not implemented for `U1` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | pub struct AssertParamIsCopy { - | ---- required by this bound in `std::clone::AssertParamIsCopy` + | ---- required by this bound in `AssertParamIsCopy` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -18,10 +18,10 @@ LL | union U5 { | ----------- | | | method `clone` not found for this - | doesn't satisfy `U5: std::clone::Clone` + | doesn't satisfy `U5: Clone` ... LL | struct CloneNoCopy; - | ------------------- doesn't satisfy `CloneNoCopy: std::marker::Copy` + | ------------------- doesn't satisfy `CloneNoCopy: Copy` ... LL | let w = u.clone(); | ^^^^^ method not found in `U5` @@ -31,12 +31,12 @@ LL | let w = u.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `CloneNoCopy: std::marker::Copy` - which is required by `U5: std::clone::Clone` + `CloneNoCopy: Copy` + which is required by `U5: Clone` error: aborting due to 2 previous errors diff --git a/src/test/ui/union/union-derive-eq.rs b/src/test/ui/union/union-derive-eq.rs index 698c38fac7..ac5808e436 100644 --- a/src/test/ui/union/union-derive-eq.rs +++ b/src/test/ui/union/union-derive-eq.rs @@ -12,7 +12,7 @@ struct PartialEqNotEq; #[derive(Eq)] union U2 { - a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: std::cmp::Eq` is not satisfied + a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: Eq` is not satisfied } impl PartialEq for U2 { fn eq(&self, rhs: &Self) -> bool { true } } diff --git a/src/test/ui/union/union-derive-eq.stderr b/src/test/ui/union/union-derive-eq.stderr index 4a9b689b44..c4d437c6cd 100644 --- a/src/test/ui/union/union-derive-eq.stderr +++ b/src/test/ui/union/union-derive-eq.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `PartialEqNotEq: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied --> $DIR/union-derive-eq.rs:15:5 | LL | a: PartialEqNotEq, - | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `PartialEqNotEq` + | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs index daa03ce6b6..4df3ed5028 100644 --- a/src/test/ui/union/union-drop.rs +++ b/src/test/ui/union/union-drop.rs @@ -48,6 +48,11 @@ fn main() { { let y = Y { a: S }; } - assert_eq!(CHECK, 2); // 2, dtor of Y is called + assert_eq!(CHECK, 2); // 2, Y has no dtor + { + let u2 = U { a: 1 }; + std::mem::forget(u2); + } + assert_eq!(CHECK, 2); // 2, dtor of U *not* called for u2 } } diff --git a/src/test/ui/union/union-generic.rs b/src/test/ui/union/union-generic.rs index 4b2ccbdb7b..ff87789257 100644 --- a/src/test/ui/union/union-generic.rs +++ b/src/test/ui/union/union-generic.rs @@ -6,7 +6,7 @@ union U { fn main() { let u = U { a: Rc::new(0u32) }; - //~^ ERROR the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Rc: Copy` is not satisfied let u = U::> { a: Default::default() }; - //~^ ERROR the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Rc: Copy` is not satisfied } diff --git a/src/test/ui/union/union-generic.stderr b/src/test/ui/union/union-generic.stderr index f13b2def6d..c418b27ce6 100644 --- a/src/test/ui/union/union-generic.stderr +++ b/src/test/ui/union/union-generic.stderr @@ -1,20 +1,20 @@ -error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Rc: Copy` is not satisfied --> $DIR/union-generic.rs:8:13 | LL | union U { | ---------------- required by `U` ... LL | let u = U { a: Rc::new(0u32) }; - | ^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` + | ^ the trait `Copy` is not implemented for `Rc` -error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Rc: Copy` is not satisfied --> $DIR/union-generic.rs:10:13 | LL | union U { | ---------------- required by `U` ... LL | let u = U::> { a: Default::default() }; - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `Rc` error: aborting due to 2 previous errors diff --git a/src/test/ui/union/union-move.rs b/src/test/ui/union/union-move.rs new file mode 100644 index 0000000000..a0a2d0d659 --- /dev/null +++ b/src/test/ui/union/union-move.rs @@ -0,0 +1,53 @@ +//! Test the behavior of moving out of non-`Copy` union fields. +//! Avoid types that `Drop`, we want to focus on moving. +#![feature(untagged_unions)] + +use std::cell::RefCell; + +fn move_out(x: T) {} + +union U1 { + f1_nocopy: RefCell, + f2_nocopy: RefCell, + f3_copy: i32, +} + +union U2 { + f1_nocopy: RefCell, +} +impl Drop for U2 { + fn drop(&mut self) {} +} + +fn test1(x: U1) { + // Moving out of a nocopy field prevents accessing other nocopy field. + unsafe { + move_out(x.f1_nocopy); + move_out(x.f2_nocopy); //~ ERROR use of moved value: `x` + } +} + +fn test2(x: U1) { + // "Moving" out of copy field doesn't prevent later field accesses. + unsafe { + move_out(x.f3_copy); + move_out(x.f2_nocopy); // no error + } +} + +fn test3(x: U1) { + // Moving out of a nocopy field prevents accessing other copy field. + unsafe { + move_out(x.f2_nocopy); + move_out(x.f3_copy); //~ ERROR use of moved value: `x` + } +} + +fn test4(x: U2) { + // Cannot move out of union that implements `Drop`. + unsafe { + move_out(x.f1_nocopy); //~ ERROR cannot move out of type `U2`, which implements the `Drop` + } +} + +fn main() {} diff --git a/src/test/ui/union/union-move.stderr b/src/test/ui/union/union-move.stderr new file mode 100644 index 0000000000..5679192b64 --- /dev/null +++ b/src/test/ui/union/union-move.stderr @@ -0,0 +1,35 @@ +error[E0382]: use of moved value: `x` + --> $DIR/union-move.rs:26:18 + | +LL | fn test1(x: U1) { + | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait +... +LL | move_out(x.f1_nocopy); + | ----------- value moved here +LL | move_out(x.f2_nocopy); + | ^^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `x` + --> $DIR/union-move.rs:42:18 + | +LL | fn test3(x: U1) { + | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait +... +LL | move_out(x.f2_nocopy); + | ----------- value moved here +LL | move_out(x.f3_copy); + | ^^^^^^^^^ value used here after move + +error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait + --> $DIR/union-move.rs:49:18 + | +LL | move_out(x.f1_nocopy); + | ^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `x.f1_nocopy` has type `RefCell`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0382, E0509. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index b916bbe8ad..cebeeb59a7 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/union-sized-field.rs:4:12 | LL | union Foo { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | value: T, | ^ doesn't have a size known at compile-time | @@ -21,7 +21,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/union-sized-field.rs:9:12 | LL | struct Foo2 { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | value: T, | ^ doesn't have a size known at compile-time | @@ -40,7 +40,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/union-sized-field.rs:15:11 | LL | enum Foo3 { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | Value(T), | ^ doesn't have a size known at compile-time | diff --git a/src/test/ui/union/union-unsized.stderr b/src/test/ui/union/union-unsized.stderr index f62a3b4d14..454580dcba 100644 --- a/src/test/ui/union/union-unsized.stderr +++ b/src/test/ui/union/union-unsized.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | a: str, | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -22,7 +22,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | b: str, | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 5b4c892299..423350cd93 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -1,33 +1,33 @@ -error[E0599]: no method named `clone` found for struct `std::boxed::Box` in the current scope +error[E0599]: no method named `clone` found for struct `Box` in the current scope --> $DIR/unique-object-noncopyable.rs:24:16 | LL | trait Foo { | --------- | | - | doesn't satisfy `dyn Foo: std::clone::Clone` - | doesn't satisfy `dyn Foo: std::marker::Sized` + | doesn't satisfy `dyn Foo: Clone` + | doesn't satisfy `dyn Foo: Sized` ... LL | let _z = y.clone(); - | ^^^^^ method not found in `std::boxed::Box` + | ^^^^^ method not found in `Box` | ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL | LL | pub struct Box(Unique); - | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` + | ------------------------------------- doesn't satisfy `Box: Clone` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `dyn Foo: std::marker::Sized` - which is required by `std::boxed::Box: std::clone::Clone` - `dyn Foo: std::clone::Clone` - which is required by `std::boxed::Box: std::clone::Clone` + `dyn Foo: Sized` + which is required by `Box: Clone` + `dyn Foo: Clone` + which is required by `Box: Clone` error: aborting due to previous error diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index ef3dcb478c..d39db22504 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -1,31 +1,31 @@ -error[E0599]: no method named `clone` found for struct `std::boxed::Box` in the current scope +error[E0599]: no method named `clone` found for struct `Box` in the current scope --> $DIR/unique-pinned-nocopy.rs:12:16 | LL | struct R { - | -------- doesn't satisfy `R: std::clone::Clone` + | -------- doesn't satisfy `R: Clone` ... LL | let _j = i.clone(); - | ^^^^^ method not found in `std::boxed::Box` + | ^^^^^ method not found in `Box` | ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL | LL | pub struct Box(Unique); - | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` + | ------------------------------------- doesn't satisfy `Box: Clone` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `R: std::clone::Clone` - which is required by `std::boxed::Box: std::clone::Clone` + `R: Clone` + which is required by `Box: Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/unknown-tool-name.rs b/src/test/ui/unknown-tool-name.rs index 05f99ced68..73fca61c65 100644 --- a/src/test/ui/unknown-tool-name.rs +++ b/src/test/ui/unknown-tool-name.rs @@ -1,2 +1,2 @@ -#[foo::bar] //~ ERROR failed to resolve: use of undeclared type or module `foo` +#[foo::bar] //~ ERROR failed to resolve: use of undeclared crate or module `foo` fn main() {} diff --git a/src/test/ui/unknown-tool-name.stderr b/src/test/ui/unknown-tool-name.stderr index 7a6ed57bda..4a1370ba80 100644 --- a/src/test/ui/unknown-tool-name.stderr +++ b/src/test/ui/unknown-tool-name.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/unknown-tool-name.rs:1:3 | LL | #[foo::bar] - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to previous error diff --git a/src/test/ui/unsafe/ranged_ints2_const.rs b/src/test/ui/unsafe/ranged_ints2_const.rs index 788f49f743..65e0d79308 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.rs +++ b/src/test/ui/unsafe/ranged_ints2_const.rs @@ -8,13 +8,13 @@ fn main() { const fn foo() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = &mut x.0; //~ ERROR references in const fn are unstable + let y = &mut x.0; //~ ERROR mutable references //~^ ERROR mutation of layout constrained field is unsafe unsafe { NonZero(1) } } const fn bar() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = unsafe { &mut x.0 }; //~ ERROR mutable references in const fn are unstable + let y = unsafe { &mut x.0 }; //~ ERROR mutable references unsafe { NonZero(1) } } diff --git a/src/test/ui/unsafe/ranged_ints2_const.stderr b/src/test/ui/unsafe/ranged_ints2_const.stderr index d508d07791..5ce4296458 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.stderr +++ b/src/test/ui/unsafe/ranged_ints2_const.stderr @@ -1,20 +1,20 @@ -error[E0723]: mutable references in const fn are unstable - --> $DIR/ranged_ints2_const.rs:11:9 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/ranged_ints2_const.rs:11:13 | LL | let y = &mut x.0; - | ^ + | ^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable - --> $DIR/ranged_ints2_const.rs:18:9 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/ranged_ints2_const.rs:18:22 | LL | let y = unsafe { &mut x.0 }; - | ^ + | ^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints2_const.rs:11:13 @@ -26,5 +26,5 @@ LL | let y = &mut x.0; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0133, E0723. +Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/unsafe-subtyping.stderr b/src/test/ui/unsafe/unsafe-subtyping.stderr index 19f5ef463c..2db7cc3128 100644 --- a/src/test/ui/unsafe/unsafe-subtyping.stderr +++ b/src/test/ui/unsafe/unsafe-subtyping.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/unsafe-subtyping.rs:4:5 | LL | fn foo(x: Option) -> Option { - | ---------------------- expected `std::option::Option` because of return type + | ---------------------- expected `Option` because of return type LL | x | ^ expected unsafe fn, found normal fn | - = note: expected enum `std::option::Option` - found enum `std::option::Option` + = note: expected enum `Option` + found enum `Option` error: aborting due to previous error diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index 906b543e42..b49c32f5f8 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -5,7 +5,7 @@ LL | let y = *x; | -- value moved here LL | drop_unsized(y); LL | println!("{}", &x); - | ^^ value borrowed here after partial move + | ^^ value borrowed here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -27,7 +27,7 @@ LL | let y = *x; | -- value moved here LL | y.foo(); LL | println!("{}", &x); - | ^^ value borrowed here after partial move + | ^^ value borrowed here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -52,7 +52,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 | LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | x.foo(); | - value moved here LL | println!("{}", &x); diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index 49b2031c6b..36fb32ae09 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -14,7 +14,7 @@ error[E0382]: use of moved value: `x` LL | let _y = *x; | -- value moved here LL | drop_unsized(x); - | ^ value used here after partial move + | ^ value used here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -22,7 +22,7 @@ error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:32:18 | LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | drop_unsized(x); | - value moved here LL | let _y = *x; @@ -50,7 +50,7 @@ error[E0382]: use of moved value: `x` LL | let _y = *x; | -- value moved here LL | x.foo(); - | ^ value used here after partial move + | ^ value used here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -58,7 +58,7 @@ error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | x.foo(); | - value moved here LL | let _y = *x; diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr index 2ed35dc0e2..46e381611a 100644 --- a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time | - = help: within `Test`, the trait `std::marker::Sized` is not implemented for `[i32]` + = help: within `Test`, the trait `Sized` is not implemented for `[i32]` = note: required because it appears within the type `Test` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/issue-30276.stderr b/src/test/ui/unsized-locals/issue-30276.stderr index 461efcf3db..e9258a61c3 100644 --- a/src/test/ui/unsized-locals/issue-30276.stderr +++ b/src/test/ui/unsized-locals/issue-30276.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[i32]` + = help: the trait `Sized` is not implemented for `[i32]` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr index 04a8de1b5d..dc20b92b42 100644 --- a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time | - = help: within `main::A`, the trait `std::marker::Sized` is not implemented for `str` - = note: required because it appears within the type `main::A` + = help: within `A`, the trait `Sized` is not implemented for `str` + = note: required because it appears within the type `A` = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/unsized-locals/issue-50940.stderr b/src/test/ui/unsized-locals/issue-50940.stderr index 8e5f753082..c602fae883 100644 --- a/src/test/ui/unsized-locals/issue-50940.stderr +++ b/src/test/ui/unsized-locals/issue-50940.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr index 0a9b43dac3..9fb401aec2 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::<(i32, [u8])>((42, *foo())); | ^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `({integer}, [u8])`, the trait `std::marker::Sized` is not implemented for `[u8]` + = help: within `({integer}, [u8])`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `({integer}, [u8])` = note: tuples must have a statically known size to be initialized @@ -14,7 +14,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::>(A { 0: *foo() }); | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` + = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `A<[u8]>` = note: structs must have a statically known size to be initialized @@ -24,7 +24,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::>(A(*foo())); | ^ doesn't have a size known at compile-time | - = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` + = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `A<[u8]>` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/unsized-exprs3.stderr b/src/test/ui/unsized-locals/unsized-exprs3.stderr index 11435ec035..426262e82b 100644 --- a/src/test/ui/unsized-locals/unsized-exprs3.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs3.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop as fn([u8]); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr index 19978ae24c..b2ff3159c9 100644 --- a/src/test/ui/unsized/unsized-bare-typaram.stderr +++ b/src/test/ui/unsized/unsized-bare-typaram.stderr @@ -6,7 +6,7 @@ LL | fn bar() { } LL | fn foo() { bar::() } | - ^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr index fdfdb9b4e2..795c7beab0 100644 --- a/src/test/ui/unsized/unsized-enum.stderr +++ b/src/test/ui/unsized/unsized-enum.stderr @@ -7,7 +7,7 @@ LL | fn foo1() { not_sized::>() } // Hunky dory. LL | fn foo2() { not_sized::>() } | - ^^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box` --> $DIR/unsized-enum.rs:4:10 diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr index 988c310167..0a0896638e 100644 --- a/src/test/ui/unsized/unsized-enum2.stderr +++ b/src/test/ui/unsized/unsized-enum2.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `W` cannot be known at compilation tim --> $DIR/unsized-enum2.rs:23:8 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | // parameter LL | VA(W), | ^ doesn't have a size known at compile-time @@ -22,7 +22,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized-enum2.rs:25:11 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | VB{x: X}, | ^ doesn't have a size known at compile-time @@ -42,7 +42,7 @@ error[E0277]: the size for values of type `Y` cannot be known at compilation tim --> $DIR/unsized-enum2.rs:27:15 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | VC(isize, Y), | ^ doesn't have a size known at compile-time @@ -62,7 +62,7 @@ error[E0277]: the size for values of type `Z` cannot be known at compilation tim --> $DIR/unsized-enum2.rs:29:21 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | VD{u: isize, x: Z}, | ^ doesn't have a size known at compile-time @@ -84,7 +84,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | VE([u8]), | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -102,7 +102,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | VF{x: str}, | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -120,7 +120,7 @@ error[E0277]: the size for values of type `[f32]` cannot be known at compilation LL | VG(isize, [f32]), | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[f32]` + = help: the trait `Sized` is not implemented for `[f32]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -138,7 +138,7 @@ error[E0277]: the size for values of type `[u32]` cannot be known at compilation LL | VH{u: isize, x: [u32]}, | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u32]` + = help: the trait `Sized` is not implemented for `[u32]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -156,7 +156,7 @@ error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known LL | VM(dyn Foo), | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -174,7 +174,7 @@ error[E0277]: the size for values of type `(dyn Bar + 'static)` cannot be known LL | VN{x: dyn Bar}, | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn Bar + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Bar + 'static)` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -192,7 +192,7 @@ error[E0277]: the size for values of type `(dyn FooBar + 'static)` cannot be kno LL | VO(isize, dyn FooBar), | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn FooBar + 'static)` + = help: the trait `Sized` is not implemented for `(dyn FooBar + 'static)` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -210,7 +210,7 @@ error[E0277]: the size for values of type `(dyn BarFoo + 'static)` cannot be kno LL | VP{u: isize, x: dyn BarFoo}, | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn BarFoo + 'static)` + = help: the trait `Sized` is not implemented for `(dyn BarFoo + 'static)` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -228,7 +228,7 @@ error[E0277]: the size for values of type `[i8]` cannot be known at compilation LL | VQ(<&'static [i8] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[i8]` + = help: the trait `Sized` is not implemented for `[i8]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -246,7 +246,7 @@ error[E0277]: the size for values of type `[char]` cannot be known at compilatio LL | VR{x: <&'static [char] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[char]` + = help: the trait `Sized` is not implemented for `[char]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -264,7 +264,7 @@ error[E0277]: the size for values of type `[f64]` cannot be known at compilation LL | VS(isize, <&'static [f64] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[f64]` + = help: the trait `Sized` is not implemented for `[f64]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -282,7 +282,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[i32]` + = help: the trait `Sized` is not implemented for `[i32]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -300,7 +300,7 @@ error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot b LL | VI(Path1), | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper1 + 'static)` + = help: within `Path1`, the trait `Sized` is not implemented for `(dyn PathHelper1 + 'static)` = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size @@ -319,7 +319,7 @@ error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot b LL | VJ{x: Path2}, | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper2 + 'static)` + = help: within `Path2`, the trait `Sized` is not implemented for `(dyn PathHelper2 + 'static)` = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size @@ -338,7 +338,7 @@ error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot b LL | VK(isize, Path3), | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper3 + 'static)` + = help: within `Path3`, the trait `Sized` is not implemented for `(dyn PathHelper3 + 'static)` = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size @@ -357,7 +357,7 @@ error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot b LL | VL{u: isize, x: Path4}, | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper4 + 'static)` + = help: within `Path4`, the trait `Sized` is not implemented for `(dyn PathHelper4 + 'static)` = note: required because it appears within the type `Path4` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr index 6b54db7148..b498259efe 100644 --- a/src/test/ui/unsized/unsized-fn-param.stderr +++ b/src/test/ui/unsized/unsized-fn-param.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo11("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::convert::AsRef` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-fn-param.rs:13:19 @@ -13,8 +13,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo12(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::convert::AsRef` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-fn-param.rs:16:11 @@ -22,8 +22,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo21("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::convert::AsRef` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-fn-param.rs:18:19 @@ -31,8 +31,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo22(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::convert::AsRef` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn AsRef` error: aborting due to 4 previous errors diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr index 50b54593f3..9efebe3aef 100644 --- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr @@ -7,7 +7,7 @@ LL | LL | impl S5 { | - ^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-inherent-impl-self-type.rs:5:11 diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr index 0c8529bf1a..e013b8fc69 100644 --- a/src/test/ui/unsized/unsized-struct.stderr +++ b/src/test/ui/unsized/unsized-struct.stderr @@ -7,7 +7,7 @@ LL | fn foo1() { not_sized::>() } // Hunky dory. LL | fn foo2() { not_sized::>() } | - ^^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/unsized-struct.rs:4:12 @@ -26,7 +26,7 @@ LL | fn is_sized() { } LL | fn bar2() { is_sized::>() } | - ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | = note: required because it appears within the type `Bar` diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr index 071547c945..516c750cb3 100644 --- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr @@ -7,7 +7,7 @@ LL | LL | impl T3 for S5 { | - ^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-trait-impl-self-type.rs:8:11 diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr index f48d4ef9f1..17fe16ed4f 100644 --- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr @@ -7,7 +7,7 @@ LL | trait T2 { LL | impl T2 for S4 { | - ^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: consider relaxing the implicit `Sized` restriction | diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr index ddddae4eab..7ed43c38f1 100644 --- a/src/test/ui/unsized3.stderr +++ b/src/test/ui/unsized3.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized3.rs:7:13 | LL | fn f1(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f2::(x); | ^ doesn't have a size known at compile-time ... @@ -18,7 +18,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized3.rs:18:13 | LL | fn f3(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f4::(x); | ^ doesn't have a size known at compile-time ... @@ -37,7 +37,7 @@ LL | fn f5(x: &Y) {} | - required by this bound in `f5` ... LL | fn f8(x1: &S, x2: &S) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f5(x1); | ^^ doesn't have a size known at compile-time | @@ -51,7 +51,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized3.rs:40:8 | LL | fn f9(x1: Box>) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f5(&(*x1, 34)); | ^^^^^^^^^^ doesn't have a size known at compile-time | @@ -62,7 +62,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized3.rs:45:9 | LL | fn f10(x1: Box>) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f5(&(32, *x1)); | ^^^^^^^^^ doesn't have a size known at compile-time | @@ -77,7 +77,7 @@ LL | fn f5(x: &Y) {} | - required by this bound in `f5` ... LL | fn f10(x1: Box>) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f5(&(32, *x1)); | ^^^^^^^^^^ doesn't have a size known at compile-time | diff --git a/src/test/ui/unsized5.stderr b/src/test/ui/unsized5.stderr index 3fd0b429be..a7539b0672 100644 --- a/src/test/ui/unsized5.stderr +++ b/src/test/ui/unsized5.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized5.rs:4:9 | LL | struct S1 { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f1: X, | ^ doesn't have a size known at compile-time | @@ -21,7 +21,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized5.rs:10:8 | LL | struct S2 { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f: isize, LL | g: X, | ^ doesn't have a size known at compile-time @@ -43,7 +43,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | f: str, | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: only the last field of a struct may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -61,7 +61,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | f: [u8], | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: only the last field of a struct may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -77,7 +77,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized5.rs:25:8 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | V1(X, isize), | ^ doesn't have a size known at compile-time | @@ -96,7 +96,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized5.rs:29:12 | LL | enum F { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | V2{f1: X, f: isize}, | ^ doesn't have a size known at compile-time | diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr index f045bfe244..e85b73355e 100644 --- a/src/test/ui/unsized6.stderr +++ b/src/test/ui/unsized6.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `Y` cannot be known at compilation tim --> $DIR/unsized6.rs:9:9 | LL | fn f1(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y: Y; | ^ doesn't have a size known at compile-time @@ -14,7 +14,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:7:12 | LL | fn f1(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let _: W; // <-- this is OK, no bindings created, no initializer. LL | let _: (isize, (X, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -25,7 +25,7 @@ error[E0277]: the size for values of type `Z` cannot be known at compilation tim --> $DIR/unsized6.rs:11:12 | LL | fn f1(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y: (isize, (Z, usize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -36,7 +36,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:15:9 | LL | fn f2(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let y: X; | ^ doesn't have a size known at compile-time | @@ -47,7 +47,7 @@ error[E0277]: the size for values of type `Y` cannot be known at compilation tim --> $DIR/unsized6.rs:17:12 | LL | fn f2(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y: (isize, (Y, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -58,7 +58,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:22:9 | LL | fn f3(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | @@ -69,7 +69,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:24:9 | LL | fn f3(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y = *x2; | ^ doesn't have a size known at compile-time @@ -81,7 +81,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:26:10 | LL | fn f3(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time @@ -93,7 +93,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:30:9 | LL | fn f4(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | @@ -104,7 +104,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:32:9 | LL | fn f4(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y = *x2; | ^ doesn't have a size known at compile-time @@ -116,7 +116,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:34:10 | LL | fn f4(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time @@ -130,7 +130,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim LL | fn g1(x: X) {} | - ^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size @@ -144,7 +144,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim LL | fn g2(x: X) {} | - ^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr index 7dbddd4ed2..5f9a2604ed 100644 --- a/src/test/ui/unsized7.stderr +++ b/src/test/ui/unsized7.stderr @@ -7,7 +7,7 @@ LL | trait T1 { LL | impl T1 for S3 { | - ^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: consider relaxing the implicit `Sized` restriction | diff --git a/src/test/ui/unused/unused-closure.rs b/src/test/ui/unused/unused-closure.rs index 637d8bb43a..5100636842 100644 --- a/src/test/ui/unused/unused-closure.rs +++ b/src/test/ui/unused/unused-closure.rs @@ -11,7 +11,7 @@ fn unused() { println!("Hello!"); }; - async {}; //~ ERROR unused implementer of `std::future::Future` that must be used + async {}; //~ ERROR unused implementer of `Future` that must be used || async {}; //~ ERROR unused closure that must be used async || {}; //~ ERROR unused closure that must be used diff --git a/src/test/ui/unused/unused-closure.stderr b/src/test/ui/unused/unused-closure.stderr index 9dc73fb7ab..f8b4cbb02c 100644 --- a/src/test/ui/unused/unused-closure.stderr +++ b/src/test/ui/unused/unused-closure.stderr @@ -13,7 +13,7 @@ LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ = note: closures are lazy and do nothing unless called -error: unused implementer of `std::future::Future` that must be used +error: unused implementer of `Future` that must be used --> $DIR/unused-closure.rs:14:5 | LL | async {}; diff --git a/src/test/ui/use/use-after-move-based-on-type.stderr b/src/test/ui/use/use-after-move-based-on-type.stderr index 520f88f55d..11ce005bb4 100644 --- a/src/test/ui/use/use-after-move-based-on-type.stderr +++ b/src/test/ui/use/use-after-move-based-on-type.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/use-after-move-based-on-type.rs:4:20 | LL | let x = "Hello!".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = x; | - value moved here LL | println!("{}", x); diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr index e16bca3806..b3266562d1 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `n` --> $DIR/use-after-move-implicity-coerced-object.rs:28:13 | LL | let n: Box<_> = box Number { n: 42 }; - | - move occurs because `n` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `n` has type `Box`, which does not implement the `Copy` trait LL | let mut l: Box<_> = box List { list: Vec::new() }; LL | l.push(n); | - value moved here diff --git a/src/test/ui/use/use-self-type.rs b/src/test/ui/use/use-self-type.rs index 3e5c7bf3cc..370593b2eb 100644 --- a/src/test/ui/use/use-self-type.rs +++ b/src/test/ui/use/use-self-type.rs @@ -4,7 +4,7 @@ impl S { fn f() {} fn g() { use Self::f; //~ ERROR unresolved import - pub(in Self::f) struct Z; //~ ERROR use of undeclared type or module `Self` + pub(in Self::f) struct Z; //~ ERROR use of undeclared type `Self` } } diff --git a/src/test/ui/use/use-self-type.stderr b/src/test/ui/use/use-self-type.stderr index 0dd0e04267..d1469fb349 100644 --- a/src/test/ui/use/use-self-type.stderr +++ b/src/test/ui/use/use-self-type.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/use-self-type.rs:7:16 | LL | pub(in Self::f) struct Z; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 | LL | use Self::f; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-regions-unused-direct.stderr b/src/test/ui/variance/variance-regions-unused-direct.stderr index cf375ccae8..1a600f5b05 100644 --- a/src/test/ui/variance/variance-regions-unused-direct.stderr +++ b/src/test/ui/variance/variance-regions-unused-direct.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `'a` is never used LL | struct Bivariant<'a>; | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `'d` is never used --> $DIR/variance-regions-unused-direct.rs:7:19 @@ -12,7 +12,7 @@ error[E0392]: parameter `'d` is never used LL | struct Struct<'a, 'd> { | ^^ unused parameter | - = help: consider removing `'d`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'d`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-regions-unused-indirect.stderr b/src/test/ui/variance/variance-regions-unused-indirect.stderr index 7c7ba69db2..93710cc133 100644 --- a/src/test/ui/variance/variance-regions-unused-indirect.stderr +++ b/src/test/ui/variance/variance-regions-unused-indirect.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `'a` is never used LL | enum Foo<'a> { | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `'a` is never used --> $DIR/variance-regions-unused-indirect.rs:7:10 @@ -12,7 +12,7 @@ error[E0392]: parameter `'a` is never used LL | enum Bar<'a> { | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-unused-region-param.stderr b/src/test/ui/variance/variance-unused-region-param.stderr index 4cd3135803..7c7ec40ba3 100644 --- a/src/test/ui/variance/variance-unused-region-param.stderr +++ b/src/test/ui/variance/variance-unused-region-param.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `'a` is never used LL | struct SomeStruct<'a> { x: u32 } | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `'a` is never used --> $DIR/variance-unused-region-param.rs:4:15 @@ -12,7 +12,7 @@ error[E0392]: parameter `'a` is never used LL | enum SomeEnum<'a> { Nothing } | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-unused-type-param.stderr b/src/test/ui/variance/variance-unused-type-param.stderr index b648e3c1d5..a4d636bc03 100644 --- a/src/test/ui/variance/variance-unused-type-param.stderr +++ b/src/test/ui/variance/variance-unused-type-param.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `A` is never used LL | struct SomeStruct { x: u32 } | ^ unused parameter | - = help: consider removing `A`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `A` is never used --> $DIR/variance-unused-type-param.rs:9:15 @@ -12,7 +12,7 @@ error[E0392]: parameter `A` is never used LL | enum SomeEnum { Nothing } | ^ unused parameter | - = help: consider removing `A`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `T` is never used --> $DIR/variance-unused-type-param.rs:13:15 @@ -20,7 +20,7 @@ error[E0392]: parameter `T` is never used LL | enum ListCell { | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 3 previous errors diff --git a/src/test/ui/vec/vec-res-add.rs b/src/test/ui/vec/vec-res-add.rs index 4785178fb2..57b552ee55 100644 --- a/src/test/ui/vec/vec-res-add.rs +++ b/src/test/ui/vec/vec-res-add.rs @@ -14,6 +14,6 @@ fn main() { let i = vec![r(0)]; let j = vec![r(1)]; let k = i + j; - //~^ ERROR cannot add `std::vec::Vec` to `std::vec::Vec` + //~^ ERROR cannot add `Vec` to `Vec` println!("{:?}", j); } diff --git a/src/test/ui/vec/vec-res-add.stderr b/src/test/ui/vec/vec-res-add.stderr index 2d41583268..7511271361 100644 --- a/src/test/ui/vec/vec-res-add.stderr +++ b/src/test/ui/vec/vec-res-add.stderr @@ -1,10 +1,10 @@ -error[E0369]: cannot add `std::vec::Vec` to `std::vec::Vec` +error[E0369]: cannot add `Vec` to `Vec` --> $DIR/vec-res-add.rs:16:15 | LL | let k = i + j; - | - ^ - std::vec::Vec + | - ^ - Vec | | - | std::vec::Vec + | Vec error: aborting due to previous error diff --git a/src/test/ui/vector-no-ann.stderr b/src/test/ui/vector-no-ann.stderr index 62fc42fbae..8a7b8d2276 100644 --- a/src/test/ui/vector-no-ann.stderr +++ b/src/test/ui/vector-no-ann.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed for `std::vec::Vec` +error[E0282]: type annotations needed for `Vec` --> $DIR/vector-no-ann.rs:2:16 | LL | let _foo = Vec::new(); | ---- ^^^^^^^^ cannot infer type for type parameter `T` | | - | consider giving `_foo` the explicit type `std::vec::Vec`, where the type parameter `T` is specified + | consider giving `_foo` the explicit type `Vec`, where the type parameter `T` is specified error: aborting due to previous error diff --git a/src/test/ui/wf/wf-array-elem-sized.stderr b/src/test/ui/wf/wf-array-elem-sized.stderr index fedec1909f..7f3c58d6bb 100644 --- a/src/test/ui/wf/wf-array-elem-sized.stderr +++ b/src/test/ui/wf/wf-array-elem-sized.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | foo: [[u8]], | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: slice and array elements must have `Sized` type error: aborting due to previous error diff --git a/src/test/ui/wf/wf-const-type.stderr b/src/test/ui/wf/wf-const-type.stderr index 1b7f8b6fca..d2e6854880 100644 --- a/src/test/ui/wf/wf-const-type.stderr +++ b/src/test/ui/wf/wf-const-type.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `NotCopy: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-const-type.rs:10:12 | LL | struct IsCopy { t: T } | ---- required by this bound in `IsCopy` ... LL | const FOO: IsCopy> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `NotCopy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `std::option::Option` + = note: required because of the requirements on the impl of `Copy` for `Option` error: aborting due to previous error diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr index eefb450155..e707839a97 100644 --- a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr @@ -9,8 +9,8 @@ LL | trait Trait: Sized {} LL | let t_box: Box = Box::new(S); | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` - = note: required by cast to type `std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box` + = note: required by cast to type `Box` error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-convert-unsafe-trait-obj-box.rs:17:15 @@ -23,8 +23,8 @@ LL | trait Trait: Sized {} LL | takes_box(Box::new(S)); | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` - = note: required by cast to type `std::boxed::Box<(dyn Trait + 'static)>` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box` + = note: required by cast to type `Box<(dyn Trait + 'static)>` error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-convert-unsafe-trait-obj-box.rs:15:5 @@ -37,8 +37,8 @@ LL | trait Trait: Sized {} LL | Box::new(S) as Box; | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` - = note: required by cast to type `std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box` + = note: required by cast to type `Box` error: aborting due to 3 previous errors diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr index 5e645382d1..08d4808b77 100644 --- a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr @@ -9,7 +9,7 @@ LL | trait Trait: Sized {} LL | let t: &dyn Trait = &S; | ^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object @@ -23,7 +23,7 @@ LL | trait Trait: Sized {} LL | takes_trait(&S); | ^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object @@ -37,7 +37,7 @@ LL | trait Trait: Sized {} LL | &S as &dyn Trait; | ^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` error: aborting due to 3 previous errors diff --git a/src/test/ui/wf/wf-enum-bound.stderr b/src/test/ui/wf/wf-enum-bound.stderr index 962a1b839a..e7bc858225 100644 --- a/src/test/ui/wf/wf-enum-bound.stderr +++ b/src/test/ui/wf/wf-enum-bound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-enum-bound.rs:10:14 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | where T: ExtraCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr index 1eb7010c77..c97ce53885 100644 --- a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr +++ b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `A: Copy` is not satisfied --> $DIR/wf-enum-fields-struct-variant.rs:13:12 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | f: IsCopy - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `Copy` is not implemented for `A` | help: consider restricting type parameter `A` | -LL | enum AnotherEnum { - | ^^^^^^^^^^^^^^^^^^^ +LL | enum AnotherEnum { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields.stderr b/src/test/ui/wf/wf-enum-fields.stderr index a833eeacbd..85da1bf583 100644 --- a/src/test/ui/wf/wf-enum-fields.stderr +++ b/src/test/ui/wf/wf-enum-fields.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `A: Copy` is not satisfied --> $DIR/wf-enum-fields.rs:12:17 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | SomeVariant(IsCopy) - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `Copy` is not implemented for `A` | help: consider restricting type parameter `A` | -LL | enum SomeEnum { - | ^^^^^^^^^^^^^^^^^^^ +LL | enum SomeEnum { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr index 938336d3ac..e7921f3496 100644 --- a/src/test/ui/wf/wf-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-fn-where-clause.stderr @@ -1,18 +1,18 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-fn-where-clause.rs:8:24 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` LL | LL | fn foo() where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | fn foo() where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo() where T: ExtraCopy, U: Copy + | ^^^^^^^^^ -error[E0277]: the size for values of type `(dyn std::marker::Copy + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time --> $DIR/wf-fn-where-clause.rs:12:16 | LL | fn bar() where Vec:, {} @@ -21,7 +21,7 @@ LL | fn bar() where Vec:, {} LL | struct Vec { | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Copy + 'static)` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/wf-fn-where-clause.rs:16:12 | @@ -30,11 +30,11 @@ LL | struct Vec { LL | t: T, | - ...if indirection was used here: `Box` -error[E0038]: the trait `std::marker::Copy` cannot be made into an object +error[E0038]: the trait `Copy` cannot be made into an object --> $DIR/wf-fn-where-clause.rs:12:16 | LL | fn bar() where Vec:, {} - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` cannot be made into an object + | ^^^^^^^^^^^^^ the trait `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` diff --git a/src/test/ui/wf/wf-impl-self-type.stderr b/src/test/ui/wf/wf-impl-self-type.stderr index 0c24cafb24..bc30fc90f3 100644 --- a/src/test/ui/wf/wf-impl-self-type.stderr +++ b/src/test/ui/wf/wf-impl-self-type.stderr @@ -7,9 +7,9 @@ LL | impl Foo for Option<[u8]> {} ::: $SRC_DIR/core/src/option.rs:LL:COL | LL | pub enum Option { - | - required by this bound in `std::option::Option` + | - required by this bound in `Option` | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-arg.stderr b/src/test/ui/wf/wf-in-fn-arg.stderr index 84adf04a68..d6010d1d79 100644 --- a/src/test/ui/wf/wf-in-fn-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-arg.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-fn-arg.rs:10:14 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | fn bar(_: &MustBeCopy) - | ^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | fn bar(_: &MustBeCopy) - | ^^^^^^^^^^^^^^^^^^^ +LL | fn bar(_: &MustBeCopy) + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-ret.stderr b/src/test/ui/wf/wf-in-fn-ret.stderr index 68ef734be5..c22252657f 100644 --- a/src/test/ui/wf/wf-in-fn-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-ret.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-fn-ret.rs:10:16 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | fn bar() -> MustBeCopy - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | fn bar() -> MustBeCopy - | ^^^^^^^^^^^^^^^^^^^ +LL | fn bar() -> MustBeCopy + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-arg.stderr b/src/test/ui/wf/wf-in-fn-type-arg.stderr index 212c61e1e5..6d249f5f91 100644 --- a/src/test/ui/wf/wf-in-fn-type-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-type-arg.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-fn-type-arg.rs:9:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: fn(MustBeCopy) - | ^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | struct Bar { - | ^^^^^^^^^^^^^^^^^^^ +LL | struct Bar { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-ret.stderr b/src/test/ui/wf/wf-in-fn-type-ret.stderr index 3fb05fe817..30ff365b11 100644 --- a/src/test/ui/wf/wf-in-fn-type-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-type-ret.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-fn-type-ret.rs:9:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: fn() -> MustBeCopy - | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ +LL | struct Foo { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-where-clause.stderr b/src/test/ui/wf/wf-in-fn-where-clause.stderr index 41cfb18631..64e9694c0e 100644 --- a/src/test/ui/wf/wf-in-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-in-fn-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-in-fn-where-clause.rs:10:14 | LL | trait MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | where T: MustBeCopy - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | where T: MustBeCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | where T: MustBeCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-obj-type-trait.stderr b/src/test/ui/wf/wf-in-obj-type-trait.stderr index 129f9484df..55ea08ccbe 100644 --- a/src/test/ui/wf/wf-in-obj-type-trait.stderr +++ b/src/test/ui/wf/wf-in-obj-type-trait.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-obj-type-trait.rs:11:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: dyn Object> - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | struct Bar { - | ^^^^^^^^^^^^^^^^^^^ +LL | struct Bar { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr index 1a2a20ec68..7bbdd4bcf2 100644 --- a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-inherent-impl-method-where-clause.rs:12:27 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | fn foo(self) where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider restricting type parameter `U` | -LL | impl Foo { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr index ba1d4a036c..2a44e1cdc7 100644 --- a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-inherent-impl-where-clause.rs:11:29 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | impl Foo where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | impl Foo where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Foo where T: ExtraCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-static-type.stderr b/src/test/ui/wf/wf-static-type.stderr index 4e78090f99..a98184633b 100644 --- a/src/test/ui/wf/wf-static-type.stderr +++ b/src/test/ui/wf/wf-static-type.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `NotCopy: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-static-type.rs:10:13 | LL | struct IsCopy { t: T } | ---- required by this bound in `IsCopy` ... LL | static FOO: IsCopy> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `NotCopy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `std::option::Option` + = note: required because of the requirements on the impl of `Copy` for `Option` error: aborting due to previous error diff --git a/src/test/ui/wf/wf-struct-bound.stderr b/src/test/ui/wf/wf-struct-bound.stderr index d9d193aa79..948693ac6f 100644 --- a/src/test/ui/wf/wf-struct-bound.stderr +++ b/src/test/ui/wf/wf-struct-bound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-struct-bound.rs:10:14 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | where T: ExtraCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-struct-field.stderr b/src/test/ui/wf/wf-struct-field.stderr index d7d0b7a082..04e62a7fcb 100644 --- a/src/test/ui/wf/wf-struct-field.stderr +++ b/src/test/ui/wf/wf-struct-field.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `A: Copy` is not satisfied --> $DIR/wf-struct-field.rs:12:11 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | data: IsCopy - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `Copy` is not implemented for `A` | help: consider restricting type parameter `A` | -LL | struct SomeStruct { - | ^^^^^^^^^^^^^^^^^^^ +LL | struct SomeStruct { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-associated-type-bound.stderr b/src/test/ui/wf/wf-trait-associated-type-bound.stderr index a4ceb41ffa..166e3626f0 100644 --- a/src/test/ui/wf/wf-trait-associated-type-bound.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-bound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-trait-associated-type-bound.rs:10:17 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | type Type1: ExtraCopy; - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | trait SomeTrait { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait SomeTrait { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-associated-type-trait.stderr b/src/test/ui/wf/wf-trait-associated-type-trait.stderr index e2892e3d24..a139186ebb 100644 --- a/src/test/ui/wf/wf-trait-associated-type-trait.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-trait.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `::Type1: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `::Type1: Copy` is not satisfied --> $DIR/wf-trait-associated-type-trait.rs:11:5 | LL | struct IsCopy { x: T } | ---- required by this bound in `IsCopy` ... LL | type Type2 = IsCopy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `::Type1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `::Type1` | help: consider further restricting the associated type | -LL | trait SomeTrait where ::Type1: std::marker::Copy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait SomeTrait where ::Type1: Copy { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-bound.stderr b/src/test/ui/wf/wf-trait-bound.stderr index 384d668d80..abb97adcfd 100644 --- a/src/test/ui/wf/wf-trait-bound.stderr +++ b/src/test/ui/wf/wf-trait-bound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-trait-bound.rs:10:14 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | where T: ExtraCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr index 23d886e25f..c3d5d2b966 100644 --- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-default-fn-arg.rs:11:22 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar) { - | ^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self, x: &Bar) where Self: std::cmp::Eq { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self, x: &Bar) where Self: Eq { + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-ret.stderr b/src/test/ui/wf/wf-trait-default-fn-ret.stderr index 0214064017..4382a8fe81 100644 --- a/src/test/ui/wf/wf-trait-default-fn-ret.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-ret.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-default-fn-ret.rs:11:22 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self) -> Bar { - | ^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self) -> Bar where Self: std::cmp::Eq { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self) -> Bar where Self: Eq { + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr index 3664c8b25a..16c0424915 100644 --- a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-default-fn-where-clause.rs:11:31 | LL | trait Bar { } | -- required by this bound in `Bar` ... LL | fn bar(&self) where A: Bar { - | ^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self) where A: Bar, Self: std::cmp::Eq { - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self) where A: Bar, Self: Eq { + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-arg.stderr b/src/test/ui/wf/wf-trait-fn-arg.stderr index b5f5f70ce8..4510f50fee 100644 --- a/src/test/ui/wf/wf-trait-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-fn-arg.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-fn-arg.rs:10:22 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar); - | ^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self, x: &Bar) where Self: std::cmp::Eq; - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self, x: &Bar) where Self: Eq; + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-ret.stderr b/src/test/ui/wf/wf-trait-fn-ret.stderr index 5e7d8cbfea..bd0bbc09a8 100644 --- a/src/test/ui/wf/wf-trait-fn-ret.stderr +++ b/src/test/ui/wf/wf-trait-fn-ret.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-fn-ret.rs:10:22 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self) -> &Bar; - | ^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self) -> &Bar where Self: std::cmp::Eq; - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self) -> &Bar where Self: Eq; + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-fn-where-clause.stderr index 2d9ba56c58..62e5318802 100644 --- a/src/test/ui/wf/wf-trait-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-trait-fn-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-fn-where-clause.rs:10:49 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self) where Self: Sized, Bar: Copy; - | ^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self) where Self: Sized, Bar: Copy, Self: std::cmp::Eq; - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self) where Self: Sized, Bar: Copy, Self: Eq; + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-superbound.stderr b/src/test/ui/wf/wf-trait-superbound.stderr index 7d99b8f5a2..db337a7c6d 100644 --- a/src/test/ui/wf/wf-trait-superbound.stderr +++ b/src/test/ui/wf/wf-trait-superbound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-trait-superbound.rs:9:21 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` LL | LL | trait SomeTrait: ExtraCopy { - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | trait SomeTrait: ExtraCopy { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait SomeTrait: ExtraCopy { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr index 9319e3382c..d0f43f800f 100644 --- a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -23,7 +23,7 @@ LL | trait Trait: Sized {} LL | Some(()) => &S, | ^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object @@ -37,7 +37,7 @@ LL | trait Trait: Sized {} LL | let t: &dyn Trait = match opt() { | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&R` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&R` = note: required by cast to type `&dyn Trait` error: aborting due to 3 previous errors diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs index e55316bb92..0e8bb61a79 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs @@ -11,7 +11,7 @@ impl Foo { fn fails_copy(self) { require_copy(self.x); - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } } diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr index 7e88107470..916c6dc6d5 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/where-clause-constraints-are-local-for-inherent-impl.rs:13:22 | LL | fn require_copy(x: T) {} | ---- required by this bound in `require_copy` ... LL | require_copy(self.x); - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl Foo { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs index b628a2ae14..25c46330e4 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs @@ -16,7 +16,7 @@ impl Foo for Bar { fn fails_copy(self) { require_copy(self.x); - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } } diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr index 3558d779d9..8814018964 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/where-clause-constraints-are-local-for-trait-impl.rs:18:22 | LL | fn require_copy(x: T) {} | ---- required by this bound in `require_copy` ... LL | require_copy(self.x); - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl Foo for Bar { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for Bar { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs index d63f37a722..a8ae029640 100644 --- a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs +++ b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs @@ -16,5 +16,5 @@ impl Foo { fn main() { let x = Foo { value: Bar }; x.equals(&x); - //~^ ERROR `Bar: std::cmp::Eq` is not satisfied + //~^ ERROR `Bar: Eq` is not satisfied } diff --git a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr index 6fd3872877..d7de83104c 100644 --- a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr +++ b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Bar: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Bar: Eq` is not satisfied --> $DIR/where-clauses-method-unsatisfied.rs:18:14 | LL | x.equals(&x); - | ^^ the trait `std::cmp::Eq` is not implemented for `Bar` + | ^^ the trait `Eq` is not implemented for `Bar` error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clauses-unsatisfied.rs b/src/test/ui/where-clauses/where-clauses-unsatisfied.rs index 83620e5cf3..8b067d30a2 100644 --- a/src/test/ui/where-clauses/where-clauses-unsatisfied.rs +++ b/src/test/ui/where-clauses/where-clauses-unsatisfied.rs @@ -4,5 +4,5 @@ struct Struct; fn main() { drop(equal(&Struct, &Struct)) - //~^ ERROR the trait bound `Struct: std::cmp::Eq` is not satisfied + //~^ ERROR the trait bound `Struct: Eq` is not satisfied } diff --git a/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr b/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr index e92a8fc83d..9e19b9a3b1 100644 --- a/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr +++ b/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `Struct: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Struct: Eq` is not satisfied --> $DIR/where-clauses-unsatisfied.rs:6:10 | LL | fn equal(a: &T, b: &T) -> bool where T : Eq { a == b } | -- required by this bound in `equal` ... LL | drop(equal(&Struct, &Struct)) - | ^^^^^ the trait `std::cmp::Eq` is not implemented for `Struct` + | ^^^^^ the trait `Eq` is not implemented for `Struct` error: aborting due to previous error diff --git a/src/test/ui/wrapping-int-combinations.rs b/src/test/ui/wrapping-int-combinations.rs deleted file mode 100644 index f0bc479ee0..0000000000 --- a/src/test/ui/wrapping-int-combinations.rs +++ /dev/null @@ -1,77 +0,0 @@ -// run-pass - -use std::num::Wrapping; - -macro_rules! wrapping_operation { - ($result:expr, $lhs:ident $op:tt $rhs:expr) => { - assert_eq!($result, $lhs $op $rhs); - assert_eq!($result, &$lhs $op $rhs); - assert_eq!($result, $lhs $op &$rhs); - assert_eq!($result, &$lhs $op &$rhs); - }; - ($result:expr, $op:tt $expr:expr) => { - assert_eq!($result, $op $expr); - assert_eq!($result, $op &$expr); - }; -} - -macro_rules! wrapping_assignment { - ($result:expr, $lhs:ident $op:tt $rhs:expr) => { - let mut lhs1 = $lhs; - lhs1 $op $rhs; - assert_eq!($result, lhs1); - - let mut lhs2 = $lhs; - lhs2 $op &$rhs; - assert_eq!($result, lhs2); - }; -} - -macro_rules! wrapping_test { - ($type:ty, $min:expr, $max:expr) => { - let zero: Wrapping<$type> = Wrapping(0); - let one: Wrapping<$type> = Wrapping(1); - let min: Wrapping<$type> = Wrapping($min); - let max: Wrapping<$type> = Wrapping($max); - - wrapping_operation!(min, max + one); - wrapping_assignment!(min, max += one); - wrapping_operation!(max, min - one); - wrapping_assignment!(max, min -= one); - wrapping_operation!(max, max * one); - wrapping_assignment!(max, max *= one); - wrapping_operation!(max, max / one); - wrapping_assignment!(max, max /= one); - wrapping_operation!(zero, max % one); - wrapping_assignment!(zero, max %= one); - wrapping_operation!(zero, zero & max); - wrapping_assignment!(zero, zero &= max); - wrapping_operation!(max, zero | max); - wrapping_assignment!(max, zero |= max); - wrapping_operation!(zero, max ^ max); - wrapping_assignment!(zero, max ^= max); - wrapping_operation!(zero, zero << 1usize); - wrapping_assignment!(zero, zero <<= 1usize); - wrapping_operation!(zero, zero >> 1usize); - wrapping_assignment!(zero, zero >>= 1usize); - wrapping_operation!(zero, -zero); - wrapping_operation!(max, !min); - }; -} - -fn main() { - wrapping_test!(i8, std::i8::MIN, std::i8::MAX); - wrapping_test!(i16, std::i16::MIN, std::i16::MAX); - wrapping_test!(i32, std::i32::MIN, std::i32::MAX); - wrapping_test!(i64, std::i64::MIN, std::i64::MAX); - #[cfg(not(target_os = "emscripten"))] - wrapping_test!(i128, std::i128::MIN, std::i128::MAX); - wrapping_test!(isize, std::isize::MIN, std::isize::MAX); - wrapping_test!(u8, std::u8::MIN, std::u8::MAX); - wrapping_test!(u16, std::u16::MIN, std::u16::MAX); - wrapping_test!(u32, std::u32::MIN, std::u32::MAX); - wrapping_test!(u64, std::u64::MIN, std::u64::MAX); - #[cfg(not(target_os = "emscripten"))] - wrapping_test!(u128, std::u128::MIN, std::u128::MAX); - wrapping_test!(usize, std::usize::MIN, std::usize::MAX); -} diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr index 50dfce3448..789919bd16 100644 --- a/src/test/ui/write-to-static-mut-in-static.stderr +++ b/src/test/ui/write-to-static-mut-in-static.stderr @@ -4,23 +4,19 @@ error[E0080]: could not evaluate static initializer LL | pub static mut B: () = unsafe { A = 1; }; | ^^^^^ modifying a static's initial value from another static's initializer -error[E0391]: cycle detected when const-evaluating `C` +error[E0391]: cycle detected when const-evaluating + checking `C` --> $DIR/write-to-static-mut-in-static.rs:5:1 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `C`... - --> $DIR/write-to-static-mut-in-static.rs:5:1 - | -LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `C`, completing the cycle -note: cycle used when const-evaluating + checking `C` +note: ...which requires const-evaluating + checking `C`... --> $DIR/write-to-static-mut-in-static.rs:5:1 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating + checking `C`, completing the cycle + = note: cycle used when running analysis passes on this crate error: aborting due to 2 previous errors diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 0bbbabd299..4a2c710811 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -8,3 +8,10 @@ edition = "2018" toml = "0.5" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +anyhow = "1.0.32" +flate2 = "1.0.16" +tar = "0.4.29" +sha2 = "0.9.1" +rayon = "1.3.1" +hex = "0.4.2" +num_cpus = "1.13.0" diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md index a80f36d496..b77c5a907c 100644 --- a/src/tools/build-manifest/README.md +++ b/src/tools/build-manifest/README.md @@ -20,11 +20,9 @@ Then, you can generate the manifest and all the packages from `path/to/dist` to `path/to/output` with: ``` -$ BUILD_MANIFEST_DISABLE_SIGNING=1 cargo +nightly run \ - path/to/dist path/to/output 1970-01-01 \ - nightly nightly nightly nightly nightly nightly nightly nightly \ - http://example.com +$ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com \ + CHANNEL VERSION ``` -In the future, if the tool complains about missing arguments just add more -`nightly`s in the middle. +Remember to replace `CHANNEL` with the channel you produced dist artifacts of +and `VERSION` with the current Rust version. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 58022484fa..cb04900c73 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -4,18 +4,26 @@ //! via `x.py dist hash-and-sign`; the cmdline arguments are set up //! by rustbuild (in `src/bootstrap/dist.rs`). -use serde::Serialize; - -use std::collections::BTreeMap; -use std::collections::HashMap; +mod manifest; +mod versions; + +use crate::manifest::{Component, FileHash, Manifest, Package, Rename, Target}; +use crate::versions::{PkgType, Versions}; +use rayon::prelude::*; +use sha2::Digest; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::env; +use std::error::Error; use std::fs::{self, File}; -use std::io::{self, Read, Write}; +use std::io::{self, BufReader, Read, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +use std::sync::Mutex; +use std::time::Instant; static HOSTS: &[&str] = &[ "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", "arm-unknown-linux-gnueabi", "arm-unknown-linux-gnueabihf", "armv7-unknown-linux-gnueabihf", @@ -110,6 +118,7 @@ static TARGETS: &[&str] = &[ "riscv32i-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", + "riscv32gc-unknown-linux-gnu", "riscv64imac-unknown-none-elf", "riscv64gc-unknown-none-elf", "riscv64gc-unknown-linux-gnu", @@ -163,57 +172,6 @@ static MINGW: &[&str] = &["i686-pc-windows-gnu", "x86_64-pc-windows-gnu"]; static NIGHTLY_ONLY_COMPONENTS: &[&str] = &["miri-preview", "rust-analyzer-preview"]; -#[derive(Serialize)] -#[serde(rename_all = "kebab-case")] -struct Manifest { - manifest_version: String, - date: String, - pkg: BTreeMap, - renames: BTreeMap, - profiles: BTreeMap>, -} - -#[derive(Serialize)] -struct Package { - version: String, - git_commit_hash: Option, - target: BTreeMap, -} - -#[derive(Serialize)] -struct Rename { - to: String, -} - -#[derive(Serialize, Default)] -struct Target { - available: bool, - url: Option, - hash: Option, - xz_url: Option, - xz_hash: Option, - components: Option>, - extensions: Option>, -} - -impl Target { - fn unavailable() -> Self { - Self::default() - } -} - -#[derive(Serialize)] -struct Component { - pkg: String, - target: String, -} - -impl Component { - fn from_str(pkg: &str, target: &str) -> Self { - Self { pkg: pkg.to_string(), target: target.to_string() } - } -} - macro_rules! t { ($e:expr) => { match $e { @@ -224,175 +182,89 @@ macro_rules! t { } struct Builder { - rust_release: String, - cargo_release: String, - rls_release: String, - rust_analyzer_release: String, - clippy_release: String, - rustfmt_release: String, - llvm_tools_release: String, - miri_release: String, + versions: Versions, input: PathBuf, output: PathBuf, - gpg_passphrase: String, - digests: BTreeMap, s3_address: String, date: String, - rust_version: Option, - cargo_version: Option, - rls_version: Option, - rust_analyzer_version: Option, - clippy_version: Option, - rustfmt_version: Option, - llvm_tools_version: Option, - miri_version: Option, - - rust_git_commit_hash: Option, - cargo_git_commit_hash: Option, - rls_git_commit_hash: Option, - rust_analyzer_git_commit_hash: Option, - clippy_git_commit_hash: Option, - rustfmt_git_commit_hash: Option, - llvm_tools_git_commit_hash: Option, - miri_git_commit_hash: Option, - - should_sign: bool, + legacy: bool, + legacy_gpg_passphrase: String, } fn main() { - // Avoid signing packages while manually testing - // Do NOT set this envvar in CI - let should_sign = env::var("BUILD_MANIFEST_DISABLE_SIGNING").is_err(); - - // Safety check to ensure signing is always enabled on CI - // The CI environment variable is set by both Travis and AppVeyor - if !should_sign && env::var("CI").is_ok() { - println!("The 'BUILD_MANIFEST_DISABLE_SIGNING' env var can't be enabled on CI."); - println!("If you're not running this on CI, unset the 'CI' env var."); - panic!(); - } + // Up until Rust 1.48 the release process relied on build-manifest to create the SHA256 + // checksums of released files and to sign the tarballs. That was moved over to promote-release + // in time for the branching of Rust 1.48, but the old release process still had to work the + // old way. + // + // When running build-manifest through the old ./x.py dist hash-and-sign the environment + // variable will be set, enabling the legacy behavior of generating the .sha256 files and + // signing the tarballs. + // + // Once the old release process is fully decommissioned, the environment variable, all the + // related code in this tool and ./x.py dist hash-and-sign can be removed. + let legacy = env::var_os("BUILD_MANIFEST_LEGACY").is_some(); + + let num_threads = if legacy { + // Avoid overloading the old server in legacy mode. + 1 + } else if let Some(num) = env::var_os("BUILD_MANIFEST_NUM_THREADS") { + num.to_str().unwrap().parse().expect("invalid number for BUILD_MANIFEST_NUM_THREADS") + } else { + num_cpus::get() + }; + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build_global() + .expect("failed to initialize Rayon"); let mut args = env::args().skip(1); let input = PathBuf::from(args.next().unwrap()); let output = PathBuf::from(args.next().unwrap()); let date = args.next().unwrap(); - let rust_release = args.next().unwrap(); let s3_address = args.next().unwrap(); - let cargo_release = args.next().unwrap(); - let rls_release = args.next().unwrap(); - let rust_analyzer_release = args.next().unwrap(); - let clippy_release = args.next().unwrap(); - let miri_release = args.next().unwrap(); - let rustfmt_release = args.next().unwrap(); - let llvm_tools_release = args.next().unwrap(); + let channel = args.next().unwrap(); // Do not ask for a passphrase while manually testing let mut passphrase = String::new(); - if should_sign { + if legacy { // `x.py` passes the passphrase via stdin. t!(io::stdin().read_to_string(&mut passphrase)); } Builder { - rust_release, - cargo_release, - rls_release, - rust_analyzer_release, - clippy_release, - rustfmt_release, - llvm_tools_release, - miri_release, + versions: Versions::new(&channel, &input).unwrap(), input, output, - gpg_passphrase: passphrase, - digests: BTreeMap::new(), s3_address, date, - rust_version: None, - cargo_version: None, - rls_version: None, - rust_analyzer_version: None, - clippy_version: None, - rustfmt_version: None, - llvm_tools_version: None, - miri_version: None, - - rust_git_commit_hash: None, - cargo_git_commit_hash: None, - rls_git_commit_hash: None, - rust_analyzer_git_commit_hash: None, - clippy_git_commit_hash: None, - rustfmt_git_commit_hash: None, - llvm_tools_git_commit_hash: None, - miri_git_commit_hash: None, - - should_sign, + legacy, + legacy_gpg_passphrase: passphrase, } .build(); } -enum PkgType { - RustSrc, - Cargo, - Rls, - RustAnalyzer, - Clippy, - Rustfmt, - LlvmTools, - Miri, - Other, -} - -impl PkgType { - fn from_component(component: &str) -> Self { - use PkgType::*; - match component { - "rust-src" => RustSrc, - "cargo" => Cargo, - "rls" | "rls-preview" => Rls, - "rust-analyzer" | "rust-analyzer-preview" => RustAnalyzer, - "clippy" | "clippy-preview" => Clippy, - "rustfmt" | "rustfmt-preview" => Rustfmt, - "llvm-tools" | "llvm-tools-preview" => LlvmTools, - "miri" | "miri-preview" => Miri, - _ => Other, - } - } -} - impl Builder { fn build(&mut self) { - self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu"); - self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu"); - self.rls_version = self.version("rls", "x86_64-unknown-linux-gnu"); - self.rust_analyzer_version = self.version("rust-analyzer", "x86_64-unknown-linux-gnu"); - self.clippy_version = self.version("clippy", "x86_64-unknown-linux-gnu"); - self.rustfmt_version = self.version("rustfmt", "x86_64-unknown-linux-gnu"); - self.llvm_tools_version = self.version("llvm-tools", "x86_64-unknown-linux-gnu"); - self.miri_version = self.version("miri", "x86_64-unknown-linux-gnu"); - - self.rust_git_commit_hash = self.git_commit_hash("rust", "x86_64-unknown-linux-gnu"); - self.cargo_git_commit_hash = self.git_commit_hash("cargo", "x86_64-unknown-linux-gnu"); - self.rls_git_commit_hash = self.git_commit_hash("rls", "x86_64-unknown-linux-gnu"); - self.rust_analyzer_git_commit_hash = - self.git_commit_hash("rust-analyzer", "x86_64-unknown-linux-gnu"); - self.clippy_git_commit_hash = self.git_commit_hash("clippy", "x86_64-unknown-linux-gnu"); - self.rustfmt_git_commit_hash = self.git_commit_hash("rustfmt", "x86_64-unknown-linux-gnu"); - self.llvm_tools_git_commit_hash = - self.git_commit_hash("llvm-tools", "x86_64-unknown-linux-gnu"); - self.miri_git_commit_hash = self.git_commit_hash("miri", "x86_64-unknown-linux-gnu"); - self.check_toolstate(); - self.digest_and_sign(); + if self.legacy { + self.digest_and_sign(); + } let manifest = self.build_manifest(); - self.write_channel_files(&self.rust_release, &manifest); - if self.rust_release != "beta" && self.rust_release != "nightly" { - self.write_channel_files("stable", &manifest); + self.write_channel_files(self.versions.channel(), &manifest); + if self.versions.channel() == "stable" { + // channel-rust-1.XX.YY.toml + let rust_version = self.versions.rustc_version(); + self.write_channel_files(rust_version, &manifest); + + // channel-rust-1.XX.toml + let major_minor = rust_version.split('.').take(2).collect::>().join("."); + self.write_channel_files(&major_minor, &manifest); } } @@ -413,18 +285,16 @@ impl Builder { // Mark some tools as missing based on toolstate. if toolstates.get("miri").map(|s| &*s as &str) != Some("test-pass") { println!("Miri tests are not passing, removing component"); - self.miri_version = None; - self.miri_git_commit_hash = None; + self.versions.disable_version(&PkgType::Miri); } } /// Hash all files, compute their signatures, and collect the hashes in `self.digests`. fn digest_and_sign(&mut self) { for file in t!(self.input.read_dir()).map(|e| t!(e).path()) { - let filename = file.file_name().unwrap().to_str().unwrap(); - let digest = self.hash(&file); + file.file_name().unwrap().to_str().unwrap(); + self.hash(&file); self.sign(&file); - assert!(self.digests.insert(filename.to_string(), digest).is_none()); } } @@ -440,6 +310,9 @@ impl Builder { self.add_profiles_to(&mut manifest); self.add_renames_to(&mut manifest); manifest.pkg.insert("rust".to_string(), self.rust_package(&manifest)); + + self.fill_missing_hashes(&mut manifest); + manifest } @@ -499,7 +372,7 @@ impl Builder { // The compiler libraries are not stable for end users, and they're also huge, so we only // `rustc-dev` for nightly users, and only in the "complete" profile. It's still possible // for users to install the additional component manually, if needed. - if self.rust_release == "nightly" { + if self.versions.channel() == "nightly" { self.extend_profile("complete", &mut manifest.profiles, &["rustc-dev"]); self.extend_profile("complete", &mut manifest.profiles, &["rustc-docs"]); } @@ -516,13 +389,10 @@ impl Builder { } fn rust_package(&mut self, manifest: &Manifest) -> Package { + let version_info = self.versions.version(&PkgType::Rust).expect("missing Rust tarball"); let mut pkg = Package { - version: self - .cached_version("rust") - .as_ref() - .expect("Couldn't find Rust version") - .clone(), - git_commit_hash: self.cached_git_commit_hash("rust").clone(), + version: version_info.version.expect("missing Rust version"), + git_commit_hash: version_info.git_commit, target: BTreeMap::new(), }; for host in HOSTS { @@ -537,10 +407,13 @@ impl Builder { } fn target_host_combination(&mut self, host: &str, manifest: &Manifest) -> Option { - let filename = self.filename("rust", host); - let digest = self.digests.remove(&filename)?; - let xz_filename = filename.replace(".tar.gz", ".tar.xz"); - let xz_digest = self.digests.remove(&xz_filename); + let filename = self.versions.tarball_name(&PkgType::Rust, host).unwrap(); + + let mut target = Target::from_compressed_tar(self, &filename); + if !target.available { + return None; + } + let mut components = Vec::new(); let mut extensions = Vec::new(); @@ -596,15 +469,9 @@ impl Builder { extensions.retain(&has_component); components.retain(&has_component); - Some(Target { - available: true, - url: Some(self.url(&filename)), - hash: Some(digest), - xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)), - xz_hash: xz_digest, - components: Some(components), - extensions: Some(extensions), - }) + target.components = Some(components); + target.extensions = Some(extensions); + Some(target) } fn profile( @@ -628,135 +495,49 @@ impl Builder { } fn package(&mut self, pkgname: &str, dst: &mut BTreeMap, targets: &[&str]) { - let (version, mut is_present) = self - .cached_version(pkgname) - .as_ref() - .cloned() - .map(|version| (version, true)) - .unwrap_or_default(); // `is_present` defaults to `false` here. + let version_info = self + .versions + .version(&PkgType::from_component(pkgname)) + .expect("failed to load package version"); + let mut is_present = version_info.present; // Never ship nightly-only components for other trains. - if self.rust_release != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkgname) { + if self.versions.channel() != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkgname) { is_present = false; // Pretend the component is entirely missing. } let targets = targets .iter() .map(|name| { - if is_present { - // The component generally exists, but it might still be missing for this target. - let filename = self.filename(pkgname, name); - let digest = match self.digests.remove(&filename) { - Some(digest) => digest, - // This component does not exist for this target -- skip it. - None => return (name.to_string(), Target::unavailable()), - }; - let xz_filename = filename.replace(".tar.gz", ".tar.xz"); - let xz_digest = self.digests.remove(&xz_filename); - - ( - name.to_string(), - Target { - available: true, - url: Some(self.url(&filename)), - hash: Some(digest), - xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)), - xz_hash: xz_digest, - components: None, - extensions: None, - }, - ) + let target = if is_present { + let filename = self + .versions + .tarball_name(&PkgType::from_component(pkgname), name) + .unwrap(); + + Target::from_compressed_tar(self, &filename) } else { // If the component is not present for this build add it anyway but mark it as // unavailable -- this way rustup won't allow upgrades without --force - (name.to_string(), Target::unavailable()) - } + Target::unavailable() + }; + (name.to_string(), target) }) .collect(); dst.insert( pkgname.to_string(), Package { - version, - git_commit_hash: self.cached_git_commit_hash(pkgname).clone(), + version: version_info.version.unwrap_or_default(), + git_commit_hash: version_info.git_commit, target: targets, }, ); } - fn url(&self, filename: &str) -> String { - format!("{}/{}/{}", self.s3_address, self.date, filename) - } - - fn filename(&self, component: &str, target: &str) -> String { - use PkgType::*; - match PkgType::from_component(component) { - RustSrc => format!("rust-src-{}.tar.gz", self.rust_release), - Cargo => format!("cargo-{}-{}.tar.gz", self.cargo_release, target), - Rls => format!("rls-{}-{}.tar.gz", self.rls_release, target), - RustAnalyzer => { - format!("rust-analyzer-{}-{}.tar.gz", self.rust_analyzer_release, target) - } - Clippy => format!("clippy-{}-{}.tar.gz", self.clippy_release, target), - Rustfmt => format!("rustfmt-{}-{}.tar.gz", self.rustfmt_release, target), - LlvmTools => format!("llvm-tools-{}-{}.tar.gz", self.llvm_tools_release, target), - Miri => format!("miri-{}-{}.tar.gz", self.miri_release, target), - Other => format!("{}-{}-{}.tar.gz", component, self.rust_release, target), - } - } - - fn cached_version(&self, component: &str) -> &Option { - use PkgType::*; - match PkgType::from_component(component) { - Cargo => &self.cargo_version, - Rls => &self.rls_version, - RustAnalyzer => &self.rust_analyzer_version, - Clippy => &self.clippy_version, - Rustfmt => &self.rustfmt_version, - LlvmTools => &self.llvm_tools_version, - Miri => &self.miri_version, - _ => &self.rust_version, - } - } - - fn cached_git_commit_hash(&self, component: &str) -> &Option { - use PkgType::*; - match PkgType::from_component(component) { - Cargo => &self.cargo_git_commit_hash, - Rls => &self.rls_git_commit_hash, - RustAnalyzer => &self.rust_analyzer_git_commit_hash, - Clippy => &self.clippy_git_commit_hash, - Rustfmt => &self.rustfmt_git_commit_hash, - LlvmTools => &self.llvm_tools_git_commit_hash, - Miri => &self.miri_git_commit_hash, - _ => &self.rust_git_commit_hash, - } - } - - fn version(&self, component: &str, target: &str) -> Option { - self.untar(component, target, |filename| format!("{}/version", filename)) - } - - fn git_commit_hash(&self, component: &str, target: &str) -> Option { - self.untar(component, target, |filename| format!("{}/git-commit-hash", filename)) - } - - fn untar(&self, component: &str, target: &str, dir: F) -> Option - where - F: FnOnce(String) -> String, - { - let mut cmd = Command::new("tar"); - let filename = self.filename(component, target); - cmd.arg("xf") - .arg(self.input.join(&filename)) - .arg(dir(filename.replace(".tar.gz", ""))) - .arg("-O"); - let output = t!(cmd.output()); - if output.status.success() { - Some(String::from_utf8_lossy(&output.stdout).trim().to_string()) - } else { - None - } + fn url(&self, path: &Path) -> String { + let file_name = path.file_name().unwrap().to_str().unwrap(); + format!("{}/{}/{}", self.s3_address, self.date, file_name) } fn hash(&self, path: &Path) -> String { @@ -777,7 +558,7 @@ impl Builder { } fn sign(&self, path: &Path) { - if !self.should_sign { + if !self.legacy { return; } @@ -800,10 +581,45 @@ impl Builder { .arg(path) .stdin(Stdio::piped()); let mut child = t!(cmd.spawn()); - t!(child.stdin.take().unwrap().write_all(self.gpg_passphrase.as_bytes())); + t!(child.stdin.take().unwrap().write_all(self.legacy_gpg_passphrase.as_bytes())); assert!(t!(child.wait()).success()); } + fn fill_missing_hashes(&self, manifest: &mut Manifest) { + // First collect all files that need hashes + let mut need_hashes = HashSet::new(); + crate::manifest::visit_file_hashes(manifest, |file_hash| { + if let FileHash::Missing(path) = file_hash { + need_hashes.insert(path.clone()); + } + }); + + let collected = Mutex::new(HashMap::new()); + let collection_start = Instant::now(); + println!( + "collecting hashes for {} tarballs across {} threads", + need_hashes.len(), + rayon::current_num_threads().min(need_hashes.len()), + ); + need_hashes.par_iter().for_each(|path| match fetch_hash(path) { + Ok(hash) => { + collected.lock().unwrap().insert(path, hash); + } + Err(err) => eprintln!("error while fetching the hash for {}: {}", path.display(), err), + }); + let collected = collected.into_inner().unwrap(); + println!("collected {} hashes in {:.2?}", collected.len(), collection_start.elapsed()); + + crate::manifest::visit_file_hashes(manifest, |file_hash| { + if let FileHash::Missing(path) = file_hash { + match collected.get(path) { + Some(hash) => *file_hash = FileHash::Present(hash.clone()), + None => panic!("missing hash for file {}", path.display()), + } + } + }) + } + fn write_channel_files(&self, channel_name: &str, manifest: &Manifest) { self.write(&toml::to_string(&manifest).unwrap(), channel_name, ".toml"); self.write(&manifest.date, channel_name, "-date.txt"); @@ -817,7 +633,16 @@ impl Builder { fn write(&self, contents: &str, channel_name: &str, suffix: &str) { let dst = self.output.join(format!("channel-rust-{}{}", channel_name, suffix)); t!(fs::write(&dst, contents)); - self.hash(&dst); - self.sign(&dst); + if self.legacy { + self.hash(&dst); + self.sign(&dst); + } } } + +fn fetch_hash(path: &Path) -> Result> { + let mut file = BufReader::new(File::open(path)?); + let mut sha256 = sha2::Sha256::default(); + std::io::copy(&mut file, &mut sha256)?; + Ok(hex::encode(sha256.finalize())) +} diff --git a/src/tools/build-manifest/src/manifest.rs b/src/tools/build-manifest/src/manifest.rs new file mode 100644 index 0000000000..20e62abb54 --- /dev/null +++ b/src/tools/build-manifest/src/manifest.rs @@ -0,0 +1,114 @@ +use crate::Builder; +use serde::{Serialize, Serializer}; +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; + +#[derive(Serialize)] +#[serde(rename_all = "kebab-case")] +pub(crate) struct Manifest { + pub(crate) manifest_version: String, + pub(crate) date: String, + pub(crate) pkg: BTreeMap, + pub(crate) renames: BTreeMap, + pub(crate) profiles: BTreeMap>, +} + +#[derive(Serialize)] +pub(crate) struct Package { + pub(crate) version: String, + pub(crate) git_commit_hash: Option, + pub(crate) target: BTreeMap, +} + +#[derive(Serialize)] +pub(crate) struct Rename { + pub(crate) to: String, +} + +#[derive(Serialize, Default)] +pub(crate) struct Target { + pub(crate) available: bool, + pub(crate) url: Option, + pub(crate) hash: Option, + pub(crate) xz_url: Option, + pub(crate) xz_hash: Option, + pub(crate) components: Option>, + pub(crate) extensions: Option>, +} + +impl Target { + pub(crate) fn from_compressed_tar(builder: &Builder, base_path: &str) -> Self { + let base_path = builder.input.join(base_path); + let gz = Self::tarball_variant(&base_path, "gz"); + let xz = Self::tarball_variant(&base_path, "xz"); + + if gz.is_none() { + return Self::unavailable(); + } + + Self { + available: true, + components: None, + extensions: None, + // .gz + url: gz.as_ref().map(|path| builder.url(path)), + hash: gz.map(FileHash::Missing), + // .xz + xz_url: xz.as_ref().map(|path| builder.url(path)), + xz_hash: xz.map(FileHash::Missing), + } + } + + fn tarball_variant(base: &Path, ext: &str) -> Option { + let mut path = base.to_path_buf(); + path.set_extension(ext); + if path.is_file() { Some(path) } else { None } + } + + pub(crate) fn unavailable() -> Self { + Self::default() + } +} + +#[derive(Serialize)] +pub(crate) struct Component { + pub(crate) pkg: String, + pub(crate) target: String, +} + +impl Component { + pub(crate) fn from_str(pkg: &str, target: &str) -> Self { + Self { pkg: pkg.to_string(), target: target.to_string() } + } +} + +#[allow(unused)] +pub(crate) enum FileHash { + Missing(PathBuf), + Present(String), +} + +impl Serialize for FileHash { + fn serialize(&self, serializer: S) -> Result { + match self { + FileHash::Missing(path) => Err(serde::ser::Error::custom(format!( + "can't serialize a missing hash for file {}", + path.display() + ))), + FileHash::Present(inner) => inner.serialize(serializer), + } + } +} + +pub(crate) fn visit_file_hashes(manifest: &mut Manifest, mut f: impl FnMut(&mut FileHash)) { + for pkg in manifest.pkg.values_mut() { + for target in pkg.target.values_mut() { + if let Some(hash) = &mut target.hash { + f(hash); + } + if let Some(hash) = &mut target.xz_hash { + f(hash); + } + } + } +} diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs new file mode 100644 index 0000000000..79f2ef8dfc --- /dev/null +++ b/src/tools/build-manifest/src/versions.rs @@ -0,0 +1,191 @@ +use anyhow::Error; +use flate2::read::GzDecoder; +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; +use std::path::{Path, PathBuf}; +use tar::Archive; + +const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu"; +const RUSTC_VERSION: &str = include_str!("../../../version"); + +#[derive(Debug, Hash, Eq, PartialEq, Clone)] +pub(crate) enum PkgType { + Rust, + RustSrc, + Cargo, + Rls, + RustAnalyzer, + Clippy, + Rustfmt, + LlvmTools, + Miri, + Other(String), +} + +impl PkgType { + pub(crate) fn from_component(component: &str) -> Self { + match component { + "rust" => PkgType::Rust, + "rust-src" => PkgType::RustSrc, + "cargo" => PkgType::Cargo, + "rls" | "rls-preview" => PkgType::Rls, + "rust-analyzer" | "rust-analyzer-preview" => PkgType::RustAnalyzer, + "clippy" | "clippy-preview" => PkgType::Clippy, + "rustfmt" | "rustfmt-preview" => PkgType::Rustfmt, + "llvm-tools" | "llvm-tools-preview" => PkgType::LlvmTools, + "miri" | "miri-preview" => PkgType::Miri, + other => PkgType::Other(other.into()), + } + } + + /// First part of the tarball name. + fn tarball_component_name(&self) -> &str { + match self { + PkgType::Rust => "rust", + PkgType::RustSrc => "rust-src", + PkgType::Cargo => "cargo", + PkgType::Rls => "rls", + PkgType::RustAnalyzer => "rust-analyzer", + PkgType::Clippy => "clippy", + PkgType::Rustfmt => "rustfmt", + PkgType::LlvmTools => "llvm-tools", + PkgType::Miri => "miri", + PkgType::Other(component) => component, + } + } + + /// Whether this package has the same version as Rust itself, or has its own `version` and + /// `git-commit-hash` files inside the tarball. + fn should_use_rust_version(&self) -> bool { + match self { + PkgType::Cargo => false, + PkgType::Rls => false, + PkgType::RustAnalyzer => false, + PkgType::Clippy => false, + PkgType::Rustfmt => false, + PkgType::LlvmTools => false, + PkgType::Miri => false, + + PkgType::Rust => true, + PkgType::RustSrc => true, + PkgType::Other(_) => true, + } + } + + /// Whether this package is target-independent or not. + fn target_independent(&self) -> bool { + *self == PkgType::RustSrc + } +} + +#[derive(Debug, Default, Clone)] +pub(crate) struct VersionInfo { + pub(crate) version: Option, + pub(crate) git_commit: Option, + pub(crate) present: bool, +} + +pub(crate) struct Versions { + channel: String, + dist_path: PathBuf, + versions: HashMap, +} + +impl Versions { + pub(crate) fn new(channel: &str, dist_path: &Path) -> Result { + Ok(Self { channel: channel.into(), dist_path: dist_path.into(), versions: HashMap::new() }) + } + + pub(crate) fn channel(&self) -> &str { + &self.channel + } + + pub(crate) fn version(&mut self, mut package: &PkgType) -> Result { + if package.should_use_rust_version() { + package = &PkgType::Rust; + } + + match self.versions.get(package) { + Some(version) => Ok(version.clone()), + None => { + let version_info = self.load_version_from_tarball(package)?; + self.versions.insert(package.clone(), version_info.clone()); + Ok(version_info) + } + } + } + + fn load_version_from_tarball(&mut self, package: &PkgType) -> Result { + let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?; + let tarball = self.dist_path.join(tarball_name); + + let file = match File::open(&tarball) { + Ok(file) => file, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + // Missing tarballs do not return an error, but return empty data. + return Ok(VersionInfo::default()); + } + Err(err) => return Err(err.into()), + }; + let mut tar = Archive::new(GzDecoder::new(file)); + + let mut version = None; + let mut git_commit = None; + for entry in tar.entries()? { + let mut entry = entry?; + + let dest; + match entry.path()?.components().nth(1).and_then(|c| c.as_os_str().to_str()) { + Some("version") => dest = &mut version, + Some("git-commit-hash") => dest = &mut git_commit, + _ => continue, + } + let mut buf = String::new(); + entry.read_to_string(&mut buf)?; + *dest = Some(buf); + + // Short circuit to avoid reading the whole tar file if not necessary. + if version.is_some() && git_commit.is_some() { + break; + } + } + + Ok(VersionInfo { version, git_commit, present: true }) + } + + pub(crate) fn disable_version(&mut self, package: &PkgType) { + match self.versions.get_mut(package) { + Some(version) => { + *version = VersionInfo::default(); + } + None => { + self.versions.insert(package.clone(), VersionInfo::default()); + } + } + } + + pub(crate) fn tarball_name( + &mut self, + package: &PkgType, + target: &str, + ) -> Result { + let component_name = package.tarball_component_name(); + let version = match self.channel.as_str() { + "stable" => RUSTC_VERSION.into(), + "beta" => "beta".into(), + "nightly" => "nightly".into(), + _ => format!("{}-dev", RUSTC_VERSION), + }; + + if package.target_independent() { + Ok(format!("{}-{}.tar.gz", component_name, version)) + } else { + Ok(format!("{}-{}-{}.tar.gz", component_name, version, target)) + } + } + + pub(crate) fn rustc_version(&self) -> &str { + RUSTC_VERSION + } +} diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 0f56dbba1d..8aabe077cf 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -22,21 +22,14 @@ const TEST_REPOS: &[Test] = &[ Test { name: "ripgrep", repo: "https://github.com/BurntSushi/ripgrep", - sha: "ad9befbc1d3b5c695e7f6b6734ee1b8e683edd41", + sha: "3de31f752729525d85a3d1575ac1978733b3f7e7", lock: None, packages: &[], }, Test { name: "tokei", repo: "https://github.com/XAMPPRocky/tokei", - sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928", - lock: None, - packages: &[], - }, - Test { - name: "treeify", - repo: "https://github.com/dzamlo/treeify", - sha: "999001b223152441198f117a68fb81f57bc086dd", + sha: "fdf3f8cb279a7aeac0696c87e5d8b0cd946e4f9e", lock: None, packages: &[], }, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 848bd3a43e..2f832b53a9 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -261,6 +261,9 @@ pub struct Config { /// Path to / name of the Microsoft Console Debugger (CDB) executable pub cdb: Option, + /// Version of CDB + pub cdb_version: Option<[u16; 4]>, + /// Path to / name of the GDB executable pub gdb: Option, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 0efa668ecc..59f64e7df0 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -8,8 +8,8 @@ use std::path::{Path, PathBuf}; use tracing::*; use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode}; -use crate::extract_gdb_version; use crate::util; +use crate::{extract_cdb_version, extract_gdb_version}; #[cfg(test)] mod tests; @@ -105,6 +105,10 @@ impl EarlyProps { props.ignore = true; } + if config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln) { + props.ignore = true; + } + if config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln) { props.ignore = true; } @@ -131,6 +135,21 @@ impl EarlyProps { return props; + fn ignore_cdb(config: &Config, line: &str) -> bool { + if let Some(actual_version) = config.cdb_version { + if let Some(min_version) = line.strip_prefix("min-cdb-version:").map(str::trim) { + let min_version = extract_cdb_version(min_version).unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", min_version); + }); + + // Ignore if actual version is smaller than the minimum + // required version + return actual_version < min_version; + } + } + false + } + fn ignore_gdb(config: &Config, line: &str) -> bool { if let Some(actual_version) = config.gdb_version { if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { @@ -142,8 +161,8 @@ impl EarlyProps { if start_ver != end_ver { panic!("Expected single GDB version") } - // Ignore if actual version is smaller the minimum required - // version + // Ignore if actual version is smaller than the minimum + // required version return actual_version < start_ver; } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { let (min_version, max_version) = @@ -189,10 +208,13 @@ impl EarlyProps { config.parse_name_value_directive(line, "needs-llvm-components") { let components: HashSet<_> = config.llvm_components.split_whitespace().collect(); - if !needed_components + if let Some(missing_component) = needed_components .split_whitespace() - .all(|needed_component| components.contains(needed_component)) + .find(|needed_component| !components.contains(needed_component)) { + if env::var_os("COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS").is_some() { + panic!("missing LLVM component: {}", missing_component); + } return true; } } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index adf2fa7fd8..190a9c6221 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -163,7 +163,7 @@ pub fn parse_config(args: Vec) -> Config { let target = opt_str2(matches.opt_str("target")); let android_cross_path = opt_path(matches, "android-cross-path"); - let cdb = analyze_cdb(matches.opt_str("cdb"), &target); + let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); let (lldb_version, lldb_native_rust) = matches @@ -216,6 +216,7 @@ pub fn parse_config(args: Vec) -> Config { target, host: opt_str2(matches.opt_str("host")), cdb, + cdb_version, gdb, gdb_version, gdb_native_rust, @@ -773,8 +774,30 @@ fn find_cdb(target: &str) -> Option { } /// Returns Path to CDB -fn analyze_cdb(cdb: Option, target: &str) -> Option { - cdb.map(OsString::from).or_else(|| find_cdb(target)) +fn analyze_cdb(cdb: Option, target: &str) -> (Option, Option<[u16; 4]>) { + let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); + + let mut version = None; + if let Some(cdb) = cdb.as_ref() { + if let Ok(output) = Command::new(cdb).arg("/version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version = extract_cdb_version(&first_line); + } + } + } + + (cdb, version) +} + +fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { + // Example full_version_line: "cdb version 10.0.18362.1" + let version = full_version_line.rsplit(' ').next()?; + let mut components = version.split('.'); + let major: u16 = components.next().unwrap().parse().unwrap(); + let minor: u16 = components.next().unwrap().parse().unwrap(); + let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); + let build: u16 = components.next().unwrap_or("0").parse().unwrap(); + Some([major, minor, patch, build]) } /// Returns (Path to GDB, GDB Version, GDB has Rust Support) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 124a9adcab..acad316d80 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2782,6 +2782,18 @@ impl<'test> TestCx<'test> { cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static").env("IS_MUSL_HOST", "1"); } + if self.config.bless { + cmd.env("RUSTC_BLESS_TEST", "--bless"); + // Assume this option is active if the environment variable is "defined", with _any_ value. + // As an example, a `Makefile` can use this option by: + // + // ifdef RUSTC_BLESS_TEST + // cp "$(TMPDIR)"/actual_something.ext expected_something.ext + // else + // $(DIFF) expected_something.ext "$(TMPDIR)"/actual_something.ext + // endif + } + if self.config.target.contains("msvc") && self.config.cc != "" { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. @@ -3144,12 +3156,12 @@ impl<'test> TestCx<'test> { if self.config.bless { for e in - glob(&format!("{}/{}.*.mir{}", test_dir.display(), test_crate, bit_width)).unwrap() + glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, bit_width)).unwrap() { std::fs::remove_file(e.unwrap()).unwrap(); } for e in - glob(&format!("{}/{}.*.diff{}", test_dir.display(), test_crate, bit_width)).unwrap() + glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, bit_width)).unwrap() { std::fs::remove_file(e.unwrap()).unwrap(); } @@ -3169,7 +3181,7 @@ impl<'test> TestCx<'test> { let trimmed = test_name.trim_end_matches(".diff"); let test_against = format!("{}.after.mir", trimmed); from_file = format!("{}.before.mir", trimmed); - expected_file = format!("{}{}", test_name, bit_width); + expected_file = format!("{}{}.diff", trimmed, bit_width); assert!( test_names.next().is_none(), "two mir pass names specified for MIR diff" @@ -3187,7 +3199,8 @@ impl<'test> TestCx<'test> { from_file = format!("{}.{}.mir", test_name, first_pass); to_file = Some(second_file); } else { - expected_file = format!("{}{}", test_name, bit_width); + expected_file = + format!("{}{}.mir", test_name.trim_end_matches(".mir"), bit_width); from_file = test_name.to_string(); assert!( test_names.next().is_none(), diff --git a/src/tools/error_index_generator/build.rs b/src/tools/error_index_generator/build.rs index efa4177d1d..caae8c6117 100644 --- a/src/tools/error_index_generator/build.rs +++ b/src/tools/error_index_generator/build.rs @@ -9,7 +9,7 @@ fn main() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let dest = out_dir.join("error_codes.rs"); - let error_codes_path = "../../../src/librustc_error_codes/error_codes.rs"; + let error_codes_path = "../../../compiler/rustc_error_codes/src/error_codes.rs"; println!("cargo:rerun-if-changed={}", error_codes_path); let file = fs::read_to_string(error_codes_path) @@ -19,7 +19,7 @@ fn main() { fs::write(&out_dir.join("all_error_codes.rs"), &contents).unwrap(); // We copy the md files as well to the target directory. - for entry in WalkDir::new("../../../src/librustc_error_codes/error_codes") { + for entry in WalkDir::new("../../../compiler/rustc_error_codes/src/error_codes") { let entry = entry.unwrap(); match entry.path().extension() { Some(s) if s == "md" => {} diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index d83fd7b292..4fe493a850 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -39,6 +39,7 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ "#method.sort_by_key", "#method.make_ascii_uppercase", "#method.make_ascii_lowercase", + "#method.get_unchecked_mut", ], ), // These try to link to std::collections, but are defined in alloc diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml new file mode 100644 index 0000000000..657b115671 --- /dev/null +++ b/src/tools/lint-docs/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "lint-docs" +version = "0.1.0" +authors = ["The Rust Project Developers"] +edition = "2018" +description = "A script to extract the lint documentation for the rustc book." + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde_json = "1.0.57" +tempfile = "3.1.0" +walkdir = "2.3.1" diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs new file mode 100644 index 0000000000..6b32ebdc28 --- /dev/null +++ b/src/tools/lint-docs/src/groups.rs @@ -0,0 +1,114 @@ +use crate::Lint; +use std::collections::{BTreeMap, BTreeSet}; +use std::error::Error; +use std::fmt::Write; +use std::fs; +use std::path::Path; +use std::process::Command; + +static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ + ("unused", "Lints that detect things being declared but not used, or excess syntax"), + ("rustdoc", "Rustdoc-specific lints"), + ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"), + ("nonstandard-style", "Violation of standard naming conventions"), + ("future-incompatible", "Lints that detect code that has future-compatibility problems"), + ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), +]; + +/// Updates the documentation of lint groups. +pub(crate) fn generate_group_docs( + lints: &[Lint], + rustc: crate::Rustc<'_>, + out_path: &Path, +) -> Result<(), Box> { + let groups = collect_groups(rustc)?; + let groups_path = out_path.join("groups.md"); + let contents = fs::read_to_string(&groups_path) + .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; + let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?); + // Delete the output because rustbuild uses hard links in its copies. + let _ = fs::remove_file(&groups_path); + fs::write(&groups_path, new_contents) + .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?; + Ok(()) +} + +type LintGroups = BTreeMap>; + +/// Collects the group names from rustc. +fn collect_groups(rustc: crate::Rustc<'_>) -> Result> { + let mut result = BTreeMap::new(); + let mut cmd = Command::new(rustc.path); + cmd.arg("-Whelp"); + let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; + if !output.status.success() { + return Err(format!( + "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n", + output.status, + std::str::from_utf8(&output.stderr).unwrap(), + std::str::from_utf8(&output.stdout).unwrap(), + ) + .into()); + } + let stdout = std::str::from_utf8(&output.stdout).unwrap(); + let lines = stdout.lines(); + let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1); + let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1); + for line in table_start { + if line.is_empty() { + break; + } + let mut parts = line.trim().splitn(2, ' '); + let name = parts.next().expect("name in group"); + if name == "warnings" { + // This is special. + continue; + } + let lints = + parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?; + let lints = lints.split(',').map(|l| l.trim().to_string()).collect(); + assert!(result.insert(name.to_string(), lints).is_none()); + } + if result.is_empty() { + return Err( + format!("expected at least one group in -Whelp output, got:\n{}", stdout).into() + ); + } + Ok(result) +} + +fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result> { + let mut result = String::new(); + let mut to_link = Vec::new(); + result.push_str("| Group | Description | Lints |\n"); + result.push_str("|-------|-------------|-------|\n"); + result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n"); + for (group_name, group_lints) in groups { + let description = GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) + .ok_or_else(|| format!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))? + .1; + to_link.extend(group_lints); + let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect(); + write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap(); + } + result.push('\n'); + result.push_str("[warn-by-default]: listing/warn-by-default.md\n"); + for lint_name in to_link { + let lint_def = + lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| { + format!( + "`rustc -W help` defined lint `{}` but that lint does not appear to exist", + lint_name + ) + })?; + write!( + result, + "[{}]: listing/{}#{}\n", + lint_name, + lint_def.level.doc_filename(), + lint_name + ) + .unwrap(); + } + Ok(result) +} diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs new file mode 100644 index 0000000000..6ca71dcaf3 --- /dev/null +++ b/src/tools/lint-docs/src/lib.rs @@ -0,0 +1,482 @@ +use std::error::Error; +use std::fmt::Write; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; +use walkdir::WalkDir; + +mod groups; + +struct Lint { + name: String, + doc: Vec, + level: Level, + path: PathBuf, + lineno: usize, +} + +impl Lint { + fn doc_contains(&self, text: &str) -> bool { + self.doc.iter().any(|line| line.contains(text)) + } + + fn is_ignored(&self) -> bool { + self.doc + .iter() + .filter(|line| line.starts_with("```rust")) + .all(|line| line.contains(",ignore")) + } +} + +#[derive(Clone, Copy, PartialEq)] +enum Level { + Allow, + Warn, + Deny, +} + +impl Level { + fn doc_filename(&self) -> &str { + match self { + Level::Allow => "allowed-by-default.md", + Level::Warn => "warn-by-default.md", + Level::Deny => "deny-by-default.md", + } + } +} + +#[derive(Copy, Clone)] +pub struct Rustc<'a> { + pub path: &'a Path, + pub target: &'a str, +} + +/// Collects all lints, and writes the markdown documentation at the given directory. +pub fn extract_lint_docs( + src_path: &Path, + out_path: &Path, + rustc: Rustc<'_>, + verbose: bool, +) -> Result<(), Box> { + let mut lints = gather_lints(src_path)?; + for lint in &mut lints { + generate_output_example(lint, rustc, verbose).map_err(|e| { + format!( + "failed to test example in lint docs for `{}` in {}:{}: {}", + lint.name, + lint.path.display(), + lint.lineno, + e + ) + })?; + } + save_lints_markdown(&lints, &out_path.join("listing"))?; + groups::generate_group_docs(&lints, rustc, out_path)?; + Ok(()) +} + +/// Collects all lints from all files in the given directory. +fn gather_lints(src_path: &Path) -> Result, Box> { + let mut lints = Vec::new(); + for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) { + if !entry.path().extension().map_or(false, |ext| ext == "rs") { + continue; + } + lints.extend(lints_from_file(entry.path())?); + } + if lints.is_empty() { + return Err("no lints were found!".into()); + } + Ok(lints) +} + +/// Collects all lints from the given file. +fn lints_from_file(path: &Path) -> Result, Box> { + let mut lints = Vec::new(); + let contents = fs::read_to_string(path) + .map_err(|e| format!("could not read {}: {}", path.display(), e))?; + let mut lines = contents.lines().enumerate(); + loop { + // Find a lint declaration. + let lint_start = loop { + match lines.next() { + Some((lineno, line)) => { + if line.trim().starts_with("declare_lint!") { + break lineno + 1; + } + } + None => return Ok(lints), + } + }; + // Read the lint. + let mut doc_lines = Vec::new(); + let (doc, name) = loop { + match lines.next() { + Some((lineno, line)) => { + let line = line.trim(); + if line.starts_with("/// ") { + doc_lines.push(line.trim()[4..].to_string()); + } else if line.starts_with("///") { + doc_lines.push("".to_string()); + } else if line.starts_with("// ") { + // Ignore comments. + continue; + } else { + let name = lint_name(line).map_err(|e| { + format!( + "could not determine lint name in {}:{}: {}, line was `{}`", + path.display(), + lineno, + e, + line + ) + })?; + if doc_lines.is_empty() { + return Err(format!( + "did not find doc lines for lint `{}` in {}", + name, + path.display() + ) + .into()); + } + break (doc_lines, name); + } + } + None => { + return Err(format!( + "unexpected EOF for lint definition at {}:{}", + path.display(), + lint_start + ) + .into()); + } + } + }; + // These lints are specifically undocumented. This should be reserved + // for internal rustc-lints only. + if name == "deprecated_in_future" { + continue; + } + // Read the level. + let level = loop { + match lines.next() { + // Ignore comments. + Some((_, line)) if line.trim().starts_with("// ") => {} + Some((lineno, line)) => match line.trim() { + "Allow," => break Level::Allow, + "Warn," => break Level::Warn, + "Deny," => break Level::Deny, + _ => { + return Err(format!( + "unexpected lint level `{}` in {}:{}", + line, + path.display(), + lineno + ) + .into()); + } + }, + None => { + return Err(format!( + "expected lint level in {}:{}, got EOF", + path.display(), + lint_start + ) + .into()); + } + } + }; + // The rest of the lint definition is ignored. + assert!(!doc.is_empty()); + lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start }); + } +} + +/// Extracts the lint name (removing the visibility modifier, and checking validity). +fn lint_name(line: &str) -> Result { + // Skip over any potential `pub` visibility. + match line.trim().split(' ').next_back() { + Some(name) => { + if !name.ends_with(',') { + return Err("lint name should end with comma"); + } + let name = &name[..name.len() - 1]; + if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() { + return Err("lint name did not have expected format"); + } + Ok(name.to_lowercase().to_string()) + } + None => Err("could not find lint name"), + } +} + +/// Mutates the lint definition to replace the `{{produces}}` marker with the +/// actual output from the compiler. +fn generate_output_example( + lint: &mut Lint, + rustc: Rustc<'_>, + verbose: bool, +) -> Result<(), Box> { + // Explicit list of lints that are allowed to not have an example. Please + // try to avoid adding to this list. + if matches!( + lint.name.as_str(), + "unused_features" // broken lint + | "unstable_features" // deprecated + ) { + return Ok(()); + } + if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") { + // Rustdoc lints are documented in the rustdoc book, don't check these. + return Ok(()); + } + check_style(lint)?; + // Unfortunately some lints have extra requirements that this simple test + // setup can't handle (like extern crates). An alternative is to use a + // separate test suite, and use an include mechanism such as mdbook's + // `{{#rustdoc_include}}`. + if !lint.is_ignored() { + replace_produces(lint, rustc, verbose)?; + } + Ok(()) +} + +/// Checks the doc style of the lint. +fn check_style(lint: &Lint) -> Result<(), Box> { + for &expected in &["### Example", "### Explanation", "{{produces}}"] { + if expected == "{{produces}}" && lint.is_ignored() { + continue; + } + if !lint.doc_contains(expected) { + return Err(format!("lint docs should contain the line `{}`", expected).into()); + } + } + if let Some(first) = lint.doc.first() { + if !first.starts_with(&format!("The `{}` lint", lint.name)) { + return Err(format!( + "lint docs should start with the text \"The `{}` lint\" to introduce the lint", + lint.name + ) + .into()); + } + } + Ok(()) +} + +/// Mutates the lint docs to replace the `{{produces}}` marker with the actual +/// output from the compiler. +fn replace_produces( + lint: &mut Lint, + rustc: Rustc<'_>, + verbose: bool, +) -> Result<(), Box> { + let mut lines = lint.doc.iter_mut(); + loop { + // Find start of example. + let options = loop { + match lines.next() { + Some(line) if line.starts_with("```rust") => { + break line[7..].split(',').collect::>(); + } + Some(line) if line.contains("{{produces}}") => { + return Err("lint marker {{{{produces}}}} found, \ + but expected to immediately follow a rust code block" + .into()); + } + Some(_) => {} + None => return Ok(()), + } + }; + // Find the end of example. + let mut example = Vec::new(); + loop { + match lines.next() { + Some(line) if line == "```" => break, + Some(line) => example.push(line), + None => { + return Err(format!( + "did not find end of example triple ticks ```, docs were:\n{:?}", + lint.doc + ) + .into()); + } + } + } + // Find the {{produces}} line. + loop { + match lines.next() { + Some(line) if line.is_empty() => {} + Some(line) if line == "{{produces}}" => { + let output = + generate_lint_output(&lint.name, &example, &options, rustc, verbose)?; + line.replace_range( + .., + &format!( + "This will produce:\n\ + \n\ + ```text\n\ + {}\ + ```", + output + ), + ); + break; + } + // No {{produces}} after example, find next example. + Some(_line) => break, + None => return Ok(()), + } + } + } +} + +/// Runs the compiler against the example, and extracts the output. +fn generate_lint_output( + name: &str, + example: &[&mut String], + options: &[&str], + rustc: Rustc<'_>, + verbose: bool, +) -> Result> { + if verbose { + eprintln!("compiling lint {}", name); + } + let tempdir = tempfile::TempDir::new()?; + let tempfile = tempdir.path().join("lint_example.rs"); + let mut source = String::new(); + let needs_main = !example.iter().any(|line| line.contains("fn main")); + // Remove `# ` prefix for hidden lines. + let unhidden = + example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line }); + let mut lines = unhidden.peekable(); + while let Some(line) = lines.peek() { + if line.starts_with("#!") { + source.push_str(line); + source.push('\n'); + lines.next(); + } else { + break; + } + } + if needs_main { + source.push_str("fn main() {\n"); + } + for line in lines { + source.push_str(line); + source.push('\n') + } + if needs_main { + source.push_str("}\n"); + } + fs::write(&tempfile, source) + .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; + let mut cmd = Command::new(rustc.path); + if options.contains(&"edition2015") { + cmd.arg("--edition=2015"); + } else { + cmd.arg("--edition=2018"); + } + cmd.arg("--error-format=json"); + cmd.arg("--target").arg(rustc.target); + if options.contains(&"test") { + cmd.arg("--test"); + } + cmd.arg("lint_example.rs"); + cmd.current_dir(tempdir.path()); + let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; + let stderr = std::str::from_utf8(&output.stderr).unwrap(); + let msgs = stderr + .lines() + .filter(|line| line.starts_with('{')) + .map(serde_json::from_str) + .collect::, _>>()?; + match msgs + .iter() + .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) + { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + match msgs.iter().find( + |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), + ) { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + let rendered: Vec<&str> = + msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + let non_json: Vec<&str> = + stderr.lines().filter(|line| !line.starts_with('{')).collect(); + Err(format!( + "did not find lint `{}` in output of example, got:\n{}\n{}", + name, + non_json.join("\n"), + rendered.join("\n") + ) + .into()) + } + } + } + } +} + +static ALLOWED_MD: &str = r#"# Allowed-by-default lints + +These lints are all set to the 'allow' level by default. As such, they won't show up +unless you set them to a higher lint level with a flag or attribute. + +"#; + +static WARN_MD: &str = r#"# Warn-by-default lints + +These lints are all set to the 'warn' level by default. + +"#; + +static DENY_MD: &str = r#"# Deny-by-default lints + +These lints are all set to the 'deny' level by default. + +"#; + +/// Saves the mdbook lint chapters at the given path. +fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box> { + save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?; + save_level(lints, Level::Warn, out_dir, WARN_MD)?; + save_level(lints, Level::Deny, out_dir, DENY_MD)?; + Ok(()) +} + +fn save_level( + lints: &[Lint], + level: Level, + out_dir: &Path, + header: &str, +) -> Result<(), Box> { + let mut result = String::new(); + result.push_str(header); + let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect(); + these_lints.sort_unstable_by_key(|lint| &lint.name); + for lint in &these_lints { + write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap(); + } + result.push('\n'); + for lint in &these_lints { + write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap(); + for line in &lint.doc { + result.push_str(line); + result.push('\n'); + } + result.push('\n'); + } + let out_path = out_dir.join(level.doc_filename()); + // Delete the output because rustbuild uses hard links in its copies. + let _ = fs::remove_file(&out_path); + fs::write(&out_path, result) + .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?; + Ok(()) +} diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs new file mode 100644 index 0000000000..5db49007d3 --- /dev/null +++ b/src/tools/lint-docs/src/main.rs @@ -0,0 +1,69 @@ +use std::error::Error; +use std::path::PathBuf; + +fn main() { + if let Err(e) = doit() { + println!("error: {}", e); + std::process::exit(1); + } +} + +fn doit() -> Result<(), Box> { + let mut args = std::env::args().skip(1); + let mut src_path = None; + let mut out_path = None; + let mut rustc_path = None; + let mut rustc_target = None; + let mut verbose = false; + while let Some(arg) = args.next() { + match arg.as_str() { + "--src" => { + src_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--src requires a value".into()), + }; + } + "--out" => { + out_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--out requires a value".into()), + }; + } + "--rustc" => { + rustc_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--rustc requires a value".into()), + }; + } + "--rustc-target" => { + rustc_target = match args.next() { + Some(s) => Some(s), + None => return Err("--rustc-target requires a value".into()), + }; + } + "-v" | "--verbose" => verbose = true, + s => return Err(format!("unexpected argument `{}`", s).into()), + } + } + if src_path.is_none() { + return Err("--src must be specified to the directory with the compiler source".into()); + } + if out_path.is_none() { + return Err("--out must be specified to the directory with the lint listing docs".into()); + } + if rustc_path.is_none() { + return Err("--rustc must be specified to the path of rustc".into()); + } + if rustc_target.is_none() { + return Err("--rustc-target must be specified to the rustc target".into()); + } + lint_docs::extract_lint_docs( + &src_path.unwrap(), + &out_path.unwrap(), + lint_docs::Rustc { + path: rustc_path.as_deref().unwrap(), + target: rustc_target.as_deref().unwrap(), + }, + verbose, + ) +} diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 51416c8ce6..7586f5aa3b 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -33,7 +33,7 @@ MAINTAINERS = { 'rust-by-example': {'steveklabnik', 'marioidival'}, 'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'}, 'edition-guide': {'ehuss', 'steveklabnik'}, - 'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'}, + 'rustc-dev-guide': {'spastorino', 'amanjeev', 'JohnTitor'}, } LABELS = { @@ -157,9 +157,6 @@ def issue( cc @{}, do you think you would have time to do the follow-up work? If so, that would be great! - - And nominating for compiler team prioritization. - ''').format( relevant_pr_number, tool, status_description, REPOS.get(tool), relevant_pr_user @@ -275,7 +272,12 @@ def update_latest( return message -def main(): +# Warning: Do not try to add a function containing the body of this try block. +# There are variables declared within that are implicitly global; it is unknown +# which ones precisely but at least this is true for `github_token`. +try: + if __name__ != '__main__': + exit(0) repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO') if repo: github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN') @@ -342,11 +344,6 @@ def main(): } )) response.read() - - -if __name__ == '__main__': - try: - main() - except urllib2.HTTPError as e: - print("HTTPError: %s\n%s" % (e, e.read())) - raise +except urllib2.HTTPError as e: + print("HTTPError: %s\n%s" % (e, e.read())) + raise diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index f0a6ce2fa0..f5e5c0867b 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -9,6 +9,6 @@ edition = "2018" clap = "2.25.0" [dependencies.mdbook] -version = "0.4.0" +version = "0.4.3" default-features = false features = ["search"] diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 351e2d4481..11d61606ff 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -69,7 +69,7 @@ serde = { version = "1.0.82", features = ['derive'] } serde_json = { version = "1.0.31", features = ["raw_value"] } smallvec-0_6 = { package = "smallvec", version = "0.6", features = ['union', 'may_dangle'] } smallvec = { version = "1.0", features = ['union', 'may_dangle'] } -syn = { version = "1", features = ['fold', 'full', 'extra-traits', 'visit'] } +syn = { version = "1", features = ['fold', 'full', 'extra-traits', 'visit', 'visit-mut'] } url = { version = "2.0", features = ['serde'] } [target.'cfg(not(windows))'.dependencies] diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs index 408be83b92..ab87230f88 100644 --- a/src/tools/tidy/src/debug_artifacts.rs +++ b/src/tools/tidy/src/debug_artifacts.rs @@ -1,4 +1,4 @@ -//! Tidy check to prevent creation of unnecessary debug artifacts. +//! Tidy check to prevent creation of unnecessary debug artifacts while running tests. use std::path::{Path, PathBuf}; diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index af3fb40370..356705305d 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -42,6 +42,7 @@ const EXCEPTIONS: &[(&str, &str)] = &[ ("crossbeam-queue", "MIT/Apache-2.0 AND BSD-2-Clause"), // rls via rayon ("arrayref", "BSD-2-Clause"), // cargo-miri/directories/.../rust-argon2 (redox) ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot + ("snap", "BSD-3-Clause"), // rustc // FIXME: this dependency violates the documentation comment above: ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target ]; @@ -161,6 +162,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "serde_derive", "sha-1", "smallvec", + "snap", "stable_deref_trait", "stacker", "syn", diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs index 4a2e49fd1c..7761ae64ee 100644 --- a/src/tools/tidy/src/edition.rs +++ b/src/tools/tidy/src/edition.rs @@ -1,5 +1,4 @@ //! Tidy check to ensure that crate `edition` is '2018' -//! use std::path::Path; diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 678e346bd4..d8029ea04f 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -71,8 +71,14 @@ pub fn collect_lib_features(base_src_path: &Path) -> Features { lib_features } -pub fn check(src_path: &Path, lib_path: &Path, bad: &mut bool, verbose: bool) -> CollectedFeatures { - let mut features = collect_lang_features(src_path, bad); +pub fn check( + src_path: &Path, + compiler_path: &Path, + lib_path: &Path, + bad: &mut bool, + verbose: bool, +) -> CollectedFeatures { + let mut features = collect_lang_features(compiler_path, bad); assert!(!features.is_empty()); let lib_features = get_and_check_lib_features(lib_path, bad, &features); @@ -225,15 +231,15 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool { false } -pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { - let mut all = collect_lang_features_in(base_src_path, "active.rs", bad); - all.extend(collect_lang_features_in(base_src_path, "accepted.rs", bad)); - all.extend(collect_lang_features_in(base_src_path, "removed.rs", bad)); +pub fn collect_lang_features(base_compiler_path: &Path, bad: &mut bool) -> Features { + let mut all = collect_lang_features_in(base_compiler_path, "active.rs", bad); + all.extend(collect_lang_features_in(base_compiler_path, "accepted.rs", bad)); + all.extend(collect_lang_features_in(base_compiler_path, "removed.rs", bad)); all } fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features { - let path = base.join("librustc_feature").join(file); + let path = base.join("rustc_feature").join("src").join(file); let contents = t!(fs::read_to_string(&path)); // We allow rustc-internal features to omit a tracking issue. diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 43105188ec..36c9e58eb9 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -11,44 +11,53 @@ use std::path::PathBuf; use std::process; fn main() { - let path: PathBuf = env::args_os().nth(1).expect("need path to src").into(); + let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into(); let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into(); - let library_path: PathBuf = path - .join("..") - .join("library") - .canonicalize() - .expect("unable to canonicalize path to library/"); + let src_path = root_path.join("src"); + let library_path = root_path.join("library"); + let compiler_path = root_path.join("compiler"); let args: Vec = env::args().skip(1).collect(); let mut bad = false; let verbose = args.iter().any(|s| *s == "--verbose"); + // Checks over tests. + debug_artifacts::check(&src_path, &mut bad); + ui_tests::check(&src_path, &mut bad); + // Checks that only make sense for the compiler. - debug_artifacts::check(&path, &mut bad); - errors::check(&path, &mut bad); - ui_tests::check(&path, &mut bad); - error_codes_check::check(&path, &mut bad); + errors::check(&compiler_path, &mut bad); + error_codes_check::check(&src_path, &mut bad); // Checks that only make sense for the std libs. pal::check(&library_path, &mut bad); unit_tests::check(&library_path, &mut bad); - // Check that need to be done for both the compiler and std libraries. - bins::check(&path, &mut bad); + // Checks that need to be done for both the compiler and std libraries. + bins::check(&src_path, &mut bad); + bins::check(&compiler_path, &mut bad); bins::check(&library_path, &mut bad); - style::check(&path, &mut bad); + + style::check(&src_path, &mut bad); + style::check(&compiler_path, &mut bad); style::check(&library_path, &mut bad); - cargo::check(&path, &mut bad); + + cargo::check(&src_path, &mut bad); + cargo::check(&compiler_path, &mut bad); cargo::check(&library_path, &mut bad); - edition::check(&path, &mut bad); + + edition::check(&src_path, &mut bad); + edition::check(&compiler_path, &mut bad); edition::check(&library_path, &mut bad); - let collected = features::check(&path, &library_path, &mut bad, verbose); - unstable_book::check(&path, collected, &mut bad); - deps::check(&path.parent().unwrap(), &cargo, &mut bad); - extdeps::check(&path.parent().unwrap(), &mut bad); + let collected = features::check(&src_path, &compiler_path, &library_path, &mut bad, verbose); + unstable_book::check(&src_path, collected, &mut bad); + + // Checks that are done on the cargo workspace. + deps::check(&root_path, &cargo, &mut bad); + extdeps::check(&root_path, &mut bad); if bad { eprintln!("some tidy checks failed"); diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 8f9d691579..1dba6b73b9 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -56,9 +56,14 @@ const EXCEPTION_PATHS: &[&str] = &[ // Integration test for platform-specific run-time feature detection: "library/std/tests/run-time-detect.rs", "library/std/src/net/test.rs", + "library/std/src/net/addr", + "library/std/src/net/udp", "library/std/src/sys_common/mod.rs", "library/std/src/sys_common/net.rs", "library/std/src/sys_common/backtrace.rs", + "library/std/src/sys_common/remutex.rs", + "library/std/src/sync/mutex.rs", + "library/std/src/sync/rwlock.rs", // panic_unwind shims "library/std/src/panicking.rs", "library/term", // Not sure how to make this crate portable, but test crate needs it. diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs index c6d67844a2..04f2bbaa0d 100644 --- a/src/tools/tidy/src/unit_tests.rs +++ b/src/tools/tidy/src/unit_tests.rs @@ -20,15 +20,19 @@ pub fn check(root_path: &Path, bad: &mut bool) { let mut skip = |path: &Path| { let file_name = path.file_name().unwrap_or_default(); if path.is_dir() { - super::filter_dirs(path) || - path.ends_with("src/test") || - path.ends_with("src/doc") || - path.ends_with("library/std") || // FIXME? - (file_name == "tests" || file_name == "benches") && !is_core(path) + super::filter_dirs(path) + || path.ends_with("src/test") + || path.ends_with("src/doc") + || (file_name == "tests" || file_name == "benches") && !is_core(path) } else { let extension = path.extension().unwrap_or_default(); extension != "rs" || (file_name == "tests.rs" || file_name == "benches.rs") && !is_core(path) + // UI tests with different names + || path.ends_with("src/thread/local/dynamic_tests.rs") + || path.ends_with("src/sync/mpsc/sync_tests.rs") + // Has copyright banner + || path.ends_with("src/sys/cloudabi/abi/cloudabi.rs") } }; diff --git a/src/tools/tier-check/src/main.rs b/src/tools/tier-check/src/main.rs index b8d60a5e2f..6a492bbff4 100644 --- a/src/tools/tier-check/src/main.rs +++ b/src/tools/tier-check/src/main.rs @@ -25,8 +25,6 @@ fn main() { let doc_targets: HashSet<_> = doc_targets_md .lines() .filter(|line| line.starts_with('`') && line.contains('|')) - // These platforms only exist on macos. - .filter(|line| !line.contains("[^apple]") || cfg!(target_os = "macos")) .map(|line| line.split('`').skip(1).next().expect("expected target code span")) .collect(); diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index 5d277e1c41..e10f72a47b 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -27,12 +27,12 @@ macro_rules! t { fn generate_stub_issue(path: &Path, name: &str, issue: u32) { let mut file = t!(File::create(path)); - t!(file.write_fmt(format_args!(include_str!("stub-issue.md"), name = name, issue = issue))); + t!(write!(file, include_str!("stub-issue.md"), name = name, issue = issue)); } fn generate_stub_no_issue(path: &Path, name: &str) { let mut file = t!(File::create(path)); - t!(file.write_fmt(format_args!(include_str!("stub-no-issue.md"), name = name))); + t!(write!(file, include_str!("stub-no-issue.md"), name = name)); } fn set_to_summary_str(set: &BTreeSet, dir: &str) -> String { @@ -94,14 +94,16 @@ fn copy_recursive(from: &Path, to: &Path) { } fn main() { - let library_path_str = env::args_os().nth(1).expect("library path required"); - let src_path_str = env::args_os().nth(2).expect("source path required"); - let dest_path_str = env::args_os().nth(3).expect("destination path required"); + let library_path_str = env::args_os().nth(1).expect("library/ path required"); + let compiler_path_str = env::args_os().nth(2).expect("compiler/ path required"); + let src_path_str = env::args_os().nth(3).expect("src/ path required"); + let dest_path_str = env::args_os().nth(4).expect("destination path required"); let library_path = Path::new(&library_path_str); + let compiler_path = Path::new(&compiler_path_str); let src_path = Path::new(&src_path_str); let dest_path = Path::new(&dest_path_str); - let lang_features = collect_lang_features(src_path, &mut false); + let lang_features = collect_lang_features(compiler_path, &mut false); let lib_features = collect_lib_features(library_path) .into_iter() .filter(|&(ref name, _)| !lang_features.contains_key(name)) diff --git a/src/version b/src/version new file mode 100644 index 0000000000..9db5ea12f5 --- /dev/null +++ b/src/version @@ -0,0 +1 @@ +1.48.0 diff --git a/vendor/block-buffer-0.7.3/.cargo-checksum.json b/vendor/block-buffer-0.7.3/.cargo-checksum.json new file mode 100644 index 0000000000..779d602b1b --- /dev/null +++ b/vendor/block-buffer-0.7.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"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 new file mode 100644 index 0000000000..6b10954cbb --- /dev/null +++ b/vendor/block-buffer-0.7.3/Cargo.toml @@ -0,0 +1,36 @@ +# 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 new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/block-buffer-0.7.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 new file mode 100644 index 0000000000..502cee6e85 --- /dev/null +++ b/vendor/block-buffer-0.7.3/LICENSE-MIT @@ -0,0 +1,25 @@ +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 new file mode 100644 index 0000000000..d3b6916554 --- /dev/null +++ b/vendor/block-buffer-0.7.3/src/lib.rs @@ -0,0 +1,210 @@ +#![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-buffer/.cargo-checksum.json b/vendor/block-buffer/.cargo-checksum.json index 779d602b1b..ad6294a06e 100644 --- a/vendor/block-buffer/.cargo-checksum.json +++ b/vendor/block-buffer/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"e4e9e182794c2185438af0c505714df9e051d1d1b17aec7a42265be672b1d027","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"59dd4084e456153bee968153ee45e34c8e853abfb756a53571c5844ccaf18c23"},"package":"c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"} \ No newline at end of file +{"files":{"Cargo.toml":"34462967bea652daffb9de37578231a0c8318b5b9ed0f7682c8ab5d00820cb82","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"39a549b74d83a11887e1f257d3273d7c1b82052b671e6e5ac1938f87a9ee4717"},"package":"4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"} \ No newline at end of file diff --git a/vendor/block-buffer/Cargo.toml b/vendor/block-buffer/Cargo.toml index 6b10954cbb..99c0f39af5 100644 --- a/vendor/block-buffer/Cargo.toml +++ b/vendor/block-buffer/Cargo.toml @@ -11,8 +11,9 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "block-buffer" -version = "0.7.3" +version = "0.9.0" authors = ["RustCrypto Developers"] description = "Fixed size buffer for block processing of data" documentation = "https://docs.rs/block-buffer" @@ -21,16 +22,8 @@ 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 +version = "0.2.0" +optional = true [dependencies.generic-array] -version = "0.12" -[badges.travis-ci] -repository = "RustCrypto/utils" +version = "0.14" diff --git a/vendor/block-buffer/src/lib.rs b/vendor/block-buffer/src/lib.rs index d3b6916554..49b8b3dcdb 100644 --- a/vendor/block-buffer/src/lib.rs +++ b/vendor/block-buffer/src/lib.rs @@ -1,14 +1,12 @@ #![no_std] -pub extern crate byteorder; -pub extern crate block_padding; -pub extern crate generic_array; -extern crate byte_tools; +pub use generic_array; +#[cfg(feature = "block-padding")] +pub use block_padding; -use byteorder::{ByteOrder, BE}; -use byte_tools::zero; -use block_padding::{Padding, PadError}; +use core::{slice, convert::TryInto}; use generic_array::{GenericArray, ArrayLength}; -use core::slice; +#[cfg(feature = "block-padding")] +use block_padding::{Padding, PadError}; /// Buffer for block processing of data #[derive(Clone, Default)] @@ -17,56 +15,52 @@ pub struct BlockBuffer> { 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); + pub fn input_block( + &mut self, mut input: &[u8], mut f: impl FnMut(&GenericArray), + ) { + let r = self.remaining(); + if input.len() < r { + let n = input.len(); + self.buffer[self.pos..self.pos + n].copy_from_slice(input); + self.pos += n; + return; + } + if self.pos != 0 && input.len() >= r { + let (l, r) = input.split_at(r); 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) }); + let mut chunks_iter = input.chunks_exact(self.size()); + for chunk in &mut chunks_iter { + f(chunk.try_into().unwrap()); } + let rem = chunks_iter.remainder(); // Copy any remaining data into the buffer. - self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); - self.pos += input.len(); + self.buffer[..rem.len()].copy_from_slice(rem); + self.pos = rem.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); + pub fn input_blocks( + &mut self, mut input: &[u8], mut f: impl FnMut(&[GenericArray]), + ) { + let r = self.remaining(); + if input.len() < r { + let n = input.len(); + self.buffer[self.pos..self.pos + n].copy_from_slice(input); + self.pos += n; + return; + } + if self.pos != 0 && input.len() >= r { + let (l, r) = input.split_at(r); input = r; self.buffer[self.pos..].copy_from_slice(l); self.pos = 0; @@ -74,10 +68,10 @@ impl> BlockBuffer { } // While we have at least a full buffer size chunks's worth of data, - // process it data without copying into the buffer + // process its 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` + // SAFETY: we guarantee that `blocks` does not point outside of `input` let blocks = unsafe { slice::from_raw_parts( left.as_ptr() as *const GenericArray, @@ -87,45 +81,50 @@ impl> BlockBuffer { f(blocks); // Copy remaining data into the buffer. - self.buffer[self.pos..self.pos+right.len()].copy_from_slice(right); - self.pos += right.len(); + let n = right.len(); + self.buffer[..n].copy_from_slice(right); + self.pos = n; } - */ /// 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); + pub fn input_lazy( + &mut self, mut input: &[u8], mut f: impl FnMut(&GenericArray), + ) { + let r = self.remaining(); + if input.len() <= r { + let n = input.len(); + self.buffer[self.pos..self.pos + n].copy_from_slice(input); + self.pos += n; + return; + } + if self.pos != 0 && input.len() > r { + let (l, r) = input.split_at(r); 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) }); + f(block.try_into().unwrap()); } - self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); - self.pos += input.len(); + self.buffer[..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) - { + fn digest_pad( + &mut self, up_to: usize, mut f: impl FnMut(&GenericArray), + ) { if self.pos == self.size() { f(&self.buffer); self.pos = 0; @@ -133,40 +132,52 @@ impl> BlockBuffer { self.buffer[self.pos] = 0x80; self.pos += 1; - zero(&mut self.buffer[self.pos..]); + set_zero(&mut self.buffer[self.pos..]); if self.remaining() < up_to { f(&self.buffer); - zero(&mut self.buffer[..self.pos]); + set_zero(&mut self.buffer[..self.pos]); } } /// Pad message with 0x80, zeros and 64-bit message length - /// in a byte order specified by `B` + /// using big-endian byte order #[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 + pub fn len64_padding_be( + &mut self, data_len: u64, mut f: impl FnMut(&GenericArray), + ) { self.digest_pad(8, &mut f); - let s = self.size(); - B::write_u64(&mut self.buffer[s-8..], data_len); + let b = data_len.to_be_bytes(); + let n = self.buffer.len() - b.len(); + self.buffer[n..].copy_from_slice(&b); f(&self.buffer); self.pos = 0; } + /// Pad message with 0x80, zeros and 64-bit message length + /// using little-endian byte order + #[inline] + pub fn len64_padding_le( + &mut self, data_len: u64, mut f: impl FnMut(&GenericArray), + ) { + self.digest_pad(8, &mut f); + let b = data_len.to_le_bytes(); + let n = self.buffer.len() - b.len(); + self.buffer[n..].copy_from_slice(&b); + f(&self.buffer); + self.pos = 0; + } /// Pad message with 0x80, zeros and 128-bit message length - /// in the big-endian byte order + /// using 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` + pub fn len128_padding_be( + &mut self, data_len: u128, mut f: impl FnMut(&GenericArray), + ) { 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); + let b = data_len.to_be_bytes(); + let n = self.buffer.len() - b.len(); + self.buffer[n..].copy_from_slice(&b); f(&self.buffer); self.pos = 0; } @@ -175,6 +186,7 @@ impl> BlockBuffer { /// /// Returns `PadError` if internall buffer is full, which can only happen if /// `input_lazy` was used. + #[cfg(feature = "block-padding")] #[inline] pub fn pad_with(&mut self) -> Result<&mut GenericArray, PadError> @@ -208,3 +220,14 @@ impl> BlockBuffer { self.pos = 0 } } + +/// Sets all bytes in `dst` to zero +#[inline(always)] +fn set_zero(dst: &mut [u8]) { + // SAFETY: we overwrite valid memory behind `dst` + // note: loop is not used here because it produces + // unnecessary branch which tests for zero-length slices + unsafe { + core::ptr::write_bytes(dst.as_mut_ptr(), 0, dst.len()); + } +} diff --git a/vendor/cargo_metadata/.cargo-checksum.json b/vendor/cargo_metadata/.cargo-checksum.json index 3de50a81f7..1cbbe337d4 100644 --- a/vendor/cargo_metadata/.cargo-checksum.json +++ b/vendor/cargo_metadata/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"be8b1e989478350479ab1d521682ddf562f767023121a6d0ae603af545a23462","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"b1816348f92faff49f0b8caacb9b31f38333381ff7bb4abbd11ac5bcd92e45a1","src/dependency.rs":"c85c395f4cbd4fee0a7268c614dd69437b916339bca0f94b7a14917cd8b33aff","src/diagnostic.rs":"3d497083d3704289fa003a8ba06df41db929e067e36a90ebfcd51b411721debc","src/errors.rs":"b7d396821f3c031510e18b434011a351166448889bcbdffa3c4e96e593fff474","src/lib.rs":"8823b593ced1d95d10e83ac0341c34ad4336eddbb4d618e5baae317a4ecbdcae","src/messages.rs":"6183e5ca4e49d42118f43a7cb0293c6f6281ae6d8d7135dbaa94e5869f868c2d","tests/selftest.rs":"257436f1e219aadf9343d1cd2db7cc0748c7b89340ff43ae8b5c83fceb0a8b7f","tests/test_samples.rs":"7c4ad89485e470b0271c81763bddc4f533c821b2ab600b162433a7b95a22366c"},"package":"89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35"} \ No newline at end of file +{"files":{"Cargo.toml":"f0e34187daaec536ba3bbfc307d951e213b2f60e7e522bbb7d86918dd90c919c","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"b1816348f92faff49f0b8caacb9b31f38333381ff7bb4abbd11ac5bcd92e45a1","src/dependency.rs":"c85c395f4cbd4fee0a7268c614dd69437b916339bca0f94b7a14917cd8b33aff","src/diagnostic.rs":"3d497083d3704289fa003a8ba06df41db929e067e36a90ebfcd51b411721debc","src/errors.rs":"b7d396821f3c031510e18b434011a351166448889bcbdffa3c4e96e593fff474","src/lib.rs":"69ef2145b406ded504821438da5f78ba87ccf9bd7e239af30d57665f01fb81cd","src/messages.rs":"6183e5ca4e49d42118f43a7cb0293c6f6281ae6d8d7135dbaa94e5869f868c2d","tests/selftest.rs":"257436f1e219aadf9343d1cd2db7cc0748c7b89340ff43ae8b5c83fceb0a8b7f","tests/test_samples.rs":"c52641f82f279157cf08eb8394bd53f8bd74493d27967db0d80eabd6069518d5"},"package":"c990b1694d29f8e477f456db1b2fcd5dd1cd6e29d5be082df45213e8834eb39a"} \ No newline at end of file diff --git a/vendor/cargo_metadata/Cargo.toml b/vendor/cargo_metadata/Cargo.toml index df37960a64..2ea3317f8f 100644 --- a/vendor/cargo_metadata/Cargo.toml +++ b/vendor/cargo_metadata/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "cargo_metadata" -version = "0.11.1" +version = "0.11.2" authors = ["Oliver Schneider "] description = "structured access to the output of `cargo metadata`" readme = "README.md" @@ -27,7 +27,7 @@ version = "0.10" features = ["serde"] [dependencies.serde] -version = "1.0.79" +version = "1.0.107" features = ["derive"] [dependencies.serde_json] diff --git a/vendor/cargo_metadata/src/lib.rs b/vendor/cargo_metadata/src/lib.rs index a06479db43..afb2599baa 100644 --- a/vendor/cargo_metadata/src/lib.rs +++ b/vendor/cargo_metadata/src/lib.rs @@ -380,6 +380,11 @@ pub struct Target { /// This is always `true` if running with a version of Cargo older than 1.37. #[serde(default = "default_true")] pub doctest: bool, + /// Whether or not this target is tested by default by `cargo test`. + /// + /// This is always `true` if running with a version of Cargo older than 1.47. + #[serde(default = "default_true")] + pub test: bool, #[doc(hidden)] #[serde(skip)] __do_not_match_exhaustively: (), diff --git a/vendor/cargo_metadata/tests/test_samples.rs b/vendor/cargo_metadata/tests/test_samples.rs index 58f30f5e5e..2a8f74bc0f 100644 --- a/vendor/cargo_metadata/tests/test_samples.rs +++ b/vendor/cargo_metadata/tests/test_samples.rs @@ -94,6 +94,7 @@ fn old_minimal() { assert_eq!(target.src_path, PathBuf::from("/foo/src/main.rs")); assert_eq!(target.edition, "2015"); assert_eq!(target.doctest, true); + assert_eq!(target.test, true); assert_eq!(pkg.features.len(), 0); assert_eq!(pkg.manifest_path, PathBuf::from("/foo/Cargo.toml")); assert_eq!(pkg.categories.len(), 0); @@ -141,10 +142,10 @@ fn cargo_version() -> semver::Version { #[test] fn all_the_fields() { - // All the fields currently generated as of 1.41. This tries to exercise as + // All the fields currently generated as of 1.47. This tries to exercise as // much as possible. let ver = cargo_version(); - let minimum = semver::Version::parse("1.41.0").unwrap(); + let minimum = semver::Version::parse("1.47.0").unwrap(); if ver < minimum { // edition added in 1.30 // rename added in 1.31 @@ -152,6 +153,7 @@ fn all_the_fields() { // doctest added in 1.37 // publish added in 1.39 // dep_kinds added in 1.41 + // test added in 1.47 eprintln!("Skipping all_the_fields test, cargo {} is too old.", ver); return; } @@ -262,11 +264,13 @@ fn all_the_fields() { assert_eq!(lib.required_features.len(), 0); assert_eq!(lib.edition, "2018"); assert_eq!(lib.doctest, true); + assert_eq!(lib.test, true); let main = get_file_name!("main.rs"); assert_eq!(main.crate_types, vec!["bin"]); assert_eq!(main.kind, vec!["bin"]); assert_eq!(main.doctest, false); + assert_eq!(main.test, true); let otherbin = get_file_name!("otherbin.rs"); assert_eq!(otherbin.edition, "2015"); @@ -276,6 +280,7 @@ fn all_the_fields() { let ex1 = get_file_name!("ex1.rs"); assert_eq!(ex1.kind, vec!["example"]); + assert_eq!(ex1.test, false); let t1 = get_file_name!("t1.rs"); assert_eq!(t1.kind, vec!["test"]); diff --git a/vendor/cc-1.0.59/.cargo-checksum.json b/vendor/cc-1.0.59/.cargo-checksum.json new file mode 100644 index 0000000000..a9252fa545 --- /dev/null +++ b/vendor/cc-1.0.59/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"bd34a585a35969291c78b96b1f239fa09f1f9dbeee48474989695def1ed64052","Cargo.toml":"cb73923110f764c2a6da0fde98db8f5f7c7194bd56e96e2f302da9ba29cba0a8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"68fe1bc9f8aab4d8d195e8bc39fe76562742dc392f5c490e5404e01463100277","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"96f4782c70e0bd8d9ab7ce3efcc2091d2591c3276c0ed672e2379748bb3930aa","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"52afe8554f577c87841c48ddee3ba7ffe70a00129e1d6eeb2ec0efb3d2b9aa11","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"} \ No newline at end of file diff --git a/vendor/cc-1.0.59/Cargo.lock b/vendor/cc-1.0.59/Cargo.lock new file mode 100644 index 0000000000..a624f35455 --- /dev/null +++ b/vendor/cc-1.0.59/Cargo.lock @@ -0,0 +1,145 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "cc" +version = "1.0.59" +dependencies = [ + "jobserver", + "tempfile", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "jobserver" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" + +[[package]] +name = "ppv-lite86" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[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", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[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/cc-1.0.59/Cargo.toml b/vendor/cc-1.0.59/Cargo.toml new file mode 100644 index 0000000000..2b3aac577f --- /dev/null +++ b/vendor/cc-1.0.59/Cargo.toml @@ -0,0 +1,34 @@ +# 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 = "cc" +version = "1.0.59" +authors = ["Alex Crichton "] +exclude = ["/.travis.yml", "/appveyor.yml"] +description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n" +homepage = "https://github.com/alexcrichton/cc-rs" +documentation = "https://docs.rs/cc" +readme = "README.md" +keywords = ["build-dependencies"] +categories = ["development-tools::build-utils"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/cc-rs" +[dependencies.jobserver] +version = "0.1.16" +optional = true +[dev-dependencies.tempfile] +version = "3" + +[features] +parallel = ["jobserver"] diff --git a/vendor/crossbeam-queue/LICENSE-APACHE b/vendor/cc-1.0.59/LICENSE-APACHE similarity index 100% rename from vendor/crossbeam-queue/LICENSE-APACHE rename to vendor/cc-1.0.59/LICENSE-APACHE diff --git a/vendor/parking_lot-0.10.2/LICENSE-MIT b/vendor/cc-1.0.59/LICENSE-MIT similarity index 95% rename from vendor/parking_lot-0.10.2/LICENSE-MIT rename to vendor/cc-1.0.59/LICENSE-MIT index 40b8817a47..39e0ed6602 100644 --- a/vendor/parking_lot-0.10.2/LICENSE-MIT +++ b/vendor/cc-1.0.59/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2016 The Rust Project Developers +Copyright (c) 2014 Alex Crichton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/vendor/cc-1.0.59/README.md b/vendor/cc-1.0.59/README.md new file mode 100644 index 0000000000..e147d7e177 --- /dev/null +++ b/vendor/cc-1.0.59/README.md @@ -0,0 +1,195 @@ +# cc-rs + +A library to compile C/C++/assembly into a Rust library/application. + +[Documentation](https://docs.rs/cc) + +A simple library meant to be used as a build dependency with Cargo packages in +order to build a set of C/C++ files into a static archive. This crate calls out +to the most relevant compiler for a platform, for example using `cl` on MSVC. + +> **Note**: this crate was recently renamed from the `gcc` crate, so if you're +> looking for the `gcc` crate you're in the right spot! + +## Using cc-rs + +First, you'll want to both add a build script for your crate (`build.rs`) and +also add this crate to your `Cargo.toml` via: + +```toml +[build-dependencies] +cc = "1.0" +``` + +Next up, you'll want to write a build script like so: + +```rust,no_run +// build.rs + +fn main() { + cc::Build::new() + .file("foo.c") + .file("bar.c") + .compile("foo"); +} +``` + +And that's it! Running `cargo build` should take care of the rest and your Rust +application will now have the C files `foo.c` and `bar.c` compiled into a file +named libfoo.a. You can call the functions in Rust by declaring functions in +your Rust code like so: + +```rust,no_run +extern { + fn foo_function(); + fn bar_function(); +} + +pub fn call() { + unsafe { + foo_function(); + bar_function(); + } +} + +fn main() { + // ... +} +``` + +## External configuration via environment variables + +To control the programs and flags used for building, the builder can set a +number of different environment variables. + +* `CFLAGS` - a series of space separated flags passed to compilers. Note that + individual flags cannot currently contain spaces, so doing + something like: "-L=foo\ bar" is not possible. +* `CC` - the actual C compiler used. Note that this is used as an exact + executable name, so (for example) no extra flags can be passed inside + this variable, and the builder must ensure that there aren't any + trailing spaces. This compiler must understand the `-c` flag. For + certain `TARGET`s, it also is assumed to know about other flags (most + common is `-fPIC`). +* `AR` - the `ar` (archiver) executable to use to build the static library. +* `CRATE_CC_NO_DEFAULTS` - the default compiler flags may cause conflicts in some cross compiling scenarios. Setting this variable will disable the generation of default compiler flags. + +Each of these variables can also be supplied with certain prefixes and suffixes, +in the following prioritized order: + +1. `_` - for example, `CC_x86_64-unknown-linux-gnu` +2. `_` - for example, `CC_x86_64_unknown_linux_gnu` +3. `_` - for example, `HOST_CC` or `TARGET_CFLAGS` +4. `` - a plain `CC`, `AR` as above. + +If none of these variables exist, cc-rs uses built-in defaults + +In addition to the above optional environment variables, `cc-rs` has some +functions with hard requirements on some variables supplied by [cargo's +build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`, +and `HOST` variables. + +[cargo]: http://doc.crates.io/build-script.html#inputs-to-the-build-script + +## Optional features + +### Parallel + +Currently cc-rs supports parallel compilation (think `make -jN`) but this +feature is turned off by default. To enable cc-rs to compile C/C++ in parallel, +you can change your dependency to: + +```toml +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } +``` + +By default cc-rs will limit parallelism to `$NUM_JOBS`, or if not present it +will limit it to the number of cpus on the machine. If you are using cargo, +use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS` +is supplied by cargo. + +## Compile-time Requirements + +To work properly this crate needs access to a C compiler when the build script +is being run. This crate does not ship a C compiler with it. The compiler +required varies per platform, but there are three broad categories: + +* Unix platforms require `cc` to be the C compiler. This can be found by + installing cc/clang on Linux distributions and Xcode on OSX, for example. +* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`) + require `cl.exe` to be available and in `PATH`. This is typically found in + standard Visual Studio installations and the `PATH` can be set up by running + the appropriate developer tools shell. +* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`) + require `cc` to be available in `PATH`. We recommend the + [MinGW-w64](http://mingw-w64.org) distribution, which is using the + [Win-builds](http://win-builds.org) installation system. + You may also acquire it via + [MSYS2](http://msys2.github.io), as explained [here][msys2-help]. Make sure + to install the appropriate architecture corresponding to your installation of + rustc. GCC from older [MinGW](http://www.mingw.org) project is compatible + only with 32-bit rust compiler. + +[msys2-help]: http://github.com/rust-lang/rust#building-on-windows + +## C++ support + +`cc-rs` supports C++ libraries compilation by using the `cpp` method on +`Build`: + +```rust,no_run +fn main() { + cc::Build::new() + .cpp(true) // Switch to C++ library compilation. + .file("foo.cpp") + .compile("libfoo.a"); +} +``` + +When using C++ library compilation switch, the `CXX` and `CXXFLAGS` env +variables are used instead of `CC` and `CFLAGS` and the C++ standard library is +linked to the crate target. +Remember that C++ does name mangling so `extern "C"` might be required to enable rust linker to find your functions. + +## CUDA C++ support + +`cc-rs` also supports compiling CUDA C++ libraries by using the `cuda` method +on `Build` (currently for GNU/Clang toolchains only): + +```rust,no_run +fn main() { + cc::Build::new() + // Switch to CUDA C++ library compilation using NVCC. + .cuda(true) + // Generate code for Maxwell (GTX 970, 980, 980 Ti, Titan X). + .flag("-gencode").flag("arch=compute_52,code=sm_52") + // Generate code for Maxwell (Jetson TX1). + .flag("-gencode").flag("arch=compute_53,code=sm_53") + // Generate code for Pascal (GTX 1070, 1080, 1080 Ti, Titan Xp). + .flag("-gencode").flag("arch=compute_61,code=sm_61") + // Generate code for Pascal (Tesla P100). + .flag("-gencode").flag("arch=compute_60,code=sm_60") + // Generate code for Pascal (Jetson TX2). + .flag("-gencode").flag("arch=compute_62,code=sm_62") + .file("bar.cu") + .compile("libbar.a"); +} +``` + +## License + +This project is 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 cc-rs 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/cc-1.0.59/src/bin/gcc-shim.rs b/vendor/cc-1.0.59/src/bin/gcc-shim.rs new file mode 100644 index 0000000000..1731df82ea --- /dev/null +++ b/vendor/cc-1.0.59/src/bin/gcc-shim.rs @@ -0,0 +1,48 @@ +#![cfg_attr(test, allow(dead_code))] + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; + +fn main() { + let mut args = env::args(); + let program = args.next().expect("Unexpected empty args"); + + let out_dir = PathBuf::from( + env::var_os("GCCTEST_OUT_DIR").expect(&format!("{}: GCCTEST_OUT_DIR not found", program)), + ); + + // Find the first nonexistent candidate file to which the program's args can be written. + for i in 0.. { + let candidate = &out_dir.join(format!("out{}", i)); + + // If the file exists, commands have already run. Try again. + if candidate.exists() { + continue; + } + + // Create a file and record the args passed to the command. + let mut f = File::create(candidate).expect(&format!( + "{}: can't create candidate: {}", + program, + candidate.to_string_lossy() + )); + for arg in args { + writeln!(f, "{}", arg).expect(&format!( + "{}: can't write to candidate: {}", + program, + candidate.to_string_lossy() + )); + } + break; + } + + // Create a file used by some tests. + let path = &out_dir.join("libfoo.a"); + File::create(path).expect(&format!( + "{}: can't create libfoo.a: {}", + program, + path.to_string_lossy() + )); +} diff --git a/vendor/cc-1.0.59/src/com.rs b/vendor/cc-1.0.59/src/com.rs new file mode 100644 index 0000000000..a5f2afedf4 --- /dev/null +++ b/vendor/cc-1.0.59/src/com.rs @@ -0,0 +1,155 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] + +use crate::winapi::CoInitializeEx; +use crate::winapi::IUnknown; +use crate::winapi::Interface; +use crate::winapi::BSTR; +use crate::winapi::COINIT_MULTITHREADED; +use crate::winapi::{SysFreeString, SysStringLen}; +use crate::winapi::{HRESULT, S_FALSE, S_OK}; +use std::ffi::{OsStr, OsString}; +use std::mem::forget; +use std::ops::Deref; +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::ptr::null_mut; +use std::slice::from_raw_parts; + +pub fn initialize() -> Result<(), HRESULT> { + let err = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) }; + if err != S_OK && err != S_FALSE { + // S_FALSE just means COM is already initialized + return Err(err); + } + Ok(()) +} + +pub struct ComPtr(*mut T) +where + T: Interface; +impl ComPtr +where + T: Interface, +{ + /// Creates a `ComPtr` to wrap a raw pointer. + /// It takes ownership over the pointer which means it does __not__ call `AddRef`. + /// `T` __must__ be a COM interface that inherits from `IUnknown`. + pub unsafe fn from_raw(ptr: *mut T) -> ComPtr { + assert!(!ptr.is_null()); + ComPtr(ptr) + } + /// Casts up the inheritance chain + pub fn up(self) -> ComPtr + where + T: Deref, + U: Interface, + { + ComPtr(self.into_raw() as *mut U) + } + /// Extracts the raw pointer. + /// You are now responsible for releasing it yourself. + pub fn into_raw(self) -> *mut T { + let p = self.0; + forget(self); + p + } + /// For internal use only. + fn as_unknown(&self) -> &IUnknown { + unsafe { &*(self.0 as *mut IUnknown) } + } + /// Performs QueryInterface fun. + pub fn cast(&self) -> Result, i32> + where + U: Interface, + { + let mut obj = null_mut(); + let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { ComPtr::from_raw(obj as *mut U) }) + } +} +impl Deref for ComPtr +where + T: Interface, +{ + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.0 } + } +} +impl Clone for ComPtr +where + T: Interface, +{ + fn clone(&self) -> Self { + unsafe { + self.as_unknown().AddRef(); + ComPtr::from_raw(self.0) + } + } +} +impl Drop for ComPtr +where + T: Interface, +{ + fn drop(&mut self) { + unsafe { + self.as_unknown().Release(); + } + } +} +pub struct BStr(BSTR); +impl BStr { + pub unsafe fn from_raw(s: BSTR) -> BStr { + BStr(s) + } + pub fn to_osstring(&self) -> OsString { + let len = unsafe { SysStringLen(self.0) }; + let slice = unsafe { from_raw_parts(self.0, len as usize) }; + OsStringExt::from_wide(slice) + } +} +impl Drop for BStr { + fn drop(&mut self) { + unsafe { SysFreeString(self.0) }; + } +} + +pub trait ToWide { + fn to_wide(&self) -> Vec; + fn to_wide_null(&self) -> Vec; +} +impl ToWide for T +where + T: AsRef, +{ + fn to_wide(&self) -> Vec { + self.as_ref().encode_wide().collect() + } + fn to_wide_null(&self) -> Vec { + self.as_ref().encode_wide().chain(Some(0)).collect() + } +} +pub trait FromWide +where + Self: Sized, +{ + fn from_wide(wide: &[u16]) -> Self; + fn from_wide_null(wide: &[u16]) -> Self { + let len = wide.iter().take_while(|&&c| c != 0).count(); + Self::from_wide(&wide[..len]) + } +} +impl FromWide for OsString { + fn from_wide(wide: &[u16]) -> OsString { + OsStringExt::from_wide(wide) + } +} diff --git a/vendor/cc-1.0.59/src/lib.rs b/vendor/cc-1.0.59/src/lib.rs new file mode 100644 index 0000000000..fecc073056 --- /dev/null +++ b/vendor/cc-1.0.59/src/lib.rs @@ -0,0 +1,2960 @@ +//! A library for build scripts to compile custom C code +//! +//! This library is intended to be used as a `build-dependencies` entry in +//! `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! cc = "1.0" +//! ``` +//! +//! The purpose of this crate is to provide the utility functions necessary to +//! compile C code into a static archive which is then linked into a Rust crate. +//! Configuration is available through the `Build` struct. +//! +//! This crate will automatically detect situations such as cross compilation or +//! other environment variables set by Cargo and will build code appropriately. +//! +//! The crate is not limited to C code, it can accept any source code that can +//! be passed to a C or C++ compiler. As such, assembly files with extensions +//! `.s` (gcc/clang) and `.asm` (MSVC) can also be compiled. +//! +//! [`Build`]: struct.Build.html +//! +//! # Parallelism +//! +//! To parallelize computation, enable the `parallel` feature for the crate. +//! +//! ```toml +//! [build-dependencies] +//! cc = { version = "1.0", features = ["parallel"] } +//! ``` +//! To specify the max number of concurrent compilation jobs, set the `NUM_JOBS` +//! environment variable to the desired amount. +//! +//! Cargo will also set this environment variable when executed with the `-jN` flag. +//! +//! If `NUM_JOBS` is not set, the `RAYON_NUM_THREADS` environment variable can +//! also specify the build parallelism. +//! +//! # Examples +//! +//! Use the `Build` struct to compile `src/foo.c`: +//! +//! ```no_run +//! fn main() { +//! cc::Build::new() +//! .file("src/foo.c") +//! .define("FOO", Some("bar")) +//! .include("src") +//! .compile("foo"); +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/cc/1.0")] +#![cfg_attr(test, deny(warnings))] +#![allow(deprecated)] +#![deny(missing_docs)] + +use std::collections::HashMap; +use std::env; +use std::ffi::{OsStr, OsString}; +use std::fmt::{self, Display}; +use std::fs; +use std::io::{self, BufRead, BufReader, Read, Write}; +use std::path::{Path, PathBuf}; +use std::process::{Child, Command, Stdio}; +use std::sync::{Arc, Mutex}; +use std::thread::{self, JoinHandle}; + +// These modules are all glue to support reading the MSVC version from +// the registry and from COM interfaces +#[cfg(windows)] +mod registry; +#[cfg(windows)] +#[macro_use] +mod winapi; +#[cfg(windows)] +mod com; +#[cfg(windows)] +mod setup_config; + +pub mod windows_registry; + +/// A builder for compilation of a native static library. +/// +/// A `Build` is the main type of the `cc` crate and is used to control all the +/// various configuration options and such of a compile. You'll find more +/// documentation on each method itself. +#[derive(Clone, Debug)] +pub struct Build { + include_directories: Vec, + definitions: Vec<(String, Option)>, + objects: Vec, + flags: Vec, + flags_supported: Vec, + known_flag_support_status: Arc>>, + ar_flags: Vec, + no_default_flags: bool, + files: Vec, + cpp: bool, + cpp_link_stdlib: Option>, + cpp_set_stdlib: Option, + cuda: bool, + target: Option, + host: Option, + out_dir: Option, + opt_level: Option, + debug: Option, + force_frame_pointer: Option, + env: Vec<(OsString, OsString)>, + compiler: Option, + archiver: Option, + cargo_metadata: bool, + pic: Option, + use_plt: Option, + static_crt: Option, + shared_flag: Option, + static_flag: Option, + warnings_into_errors: bool, + warnings: Option, + extra_warnings: Option, + env_cache: Arc>>>, + apple_sdk_root_cache: Arc>>, +} + +/// Represents the types of errors that may occur while using cc-rs. +#[derive(Clone, Debug)] +enum ErrorKind { + /// Error occurred while performing I/O. + IOError, + /// Invalid architecture supplied. + ArchitectureInvalid, + /// Environment variable not found, with the var in question as extra info. + EnvVarNotFound, + /// Error occurred while using external tools (ie: invocation of compiler). + ToolExecError, + /// Error occurred due to missing external tools. + ToolNotFound, +} + +/// Represents an internal error that occurred, with an explanation. +#[derive(Clone, Debug)] +pub struct Error { + /// Describes the kind of error that occurred. + kind: ErrorKind, + /// More explanation of error that occurred. + message: String, +} + +impl Error { + fn new(kind: ErrorKind, message: &str) -> Error { + Error { + kind: kind, + message: message.to_owned(), + } + } +} + +impl From for Error { + fn from(e: io::Error) -> Error { + Error::new(ErrorKind::IOError, &format!("{}", e)) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}: {}", self.kind, self.message) + } +} + +impl std::error::Error for Error {} + +/// Configuration used to represent an invocation of a C compiler. +/// +/// This can be used to figure out what compiler is in use, what the arguments +/// to it are, and what the environment variables look like for the compiler. +/// This can be used to further configure other build systems (e.g. forward +/// along CC and/or CFLAGS) or the `to_command` method can be used to run the +/// compiler itself. +#[derive(Clone, Debug)] +pub struct Tool { + path: PathBuf, + cc_wrapper_path: Option, + cc_wrapper_args: Vec, + args: Vec, + env: Vec<(OsString, OsString)>, + family: ToolFamily, + cuda: bool, + removed_args: Vec, +} + +/// Represents the family of tools this tool belongs to. +/// +/// Each family of tools differs in how and what arguments they accept. +/// +/// Detection of a family is done on best-effort basis and may not accurately reflect the tool. +#[derive(Copy, Clone, Debug, PartialEq)] +enum ToolFamily { + /// Tool is GNU Compiler Collection-like. + Gnu, + /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags + /// and its cross-compilation approach is different. + Clang, + /// Tool is the MSVC cl.exe. + Msvc { clang_cl: bool }, +} + +impl ToolFamily { + /// What the flag to request debug info for this family of tools look like + fn add_debug_flags(&self, cmd: &mut Tool) { + match *self { + ToolFamily::Msvc { .. } => { + cmd.push_cc_arg("-Z7".into()); + } + ToolFamily::Gnu | ToolFamily::Clang => { + cmd.push_cc_arg("-g".into()); + } + } + } + + /// What the flag to force frame pointers. + fn add_force_frame_pointer(&self, cmd: &mut Tool) { + match *self { + ToolFamily::Gnu | ToolFamily::Clang => { + cmd.push_cc_arg("-fno-omit-frame-pointer".into()); + } + _ => (), + } + } + + /// What the flags to enable all warnings + fn warnings_flags(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "-W4", + ToolFamily::Gnu | ToolFamily::Clang => "-Wall", + } + } + + /// What the flags to enable extra warnings + fn extra_warnings_flags(&self) -> Option<&'static str> { + match *self { + ToolFamily::Msvc { .. } => None, + ToolFamily::Gnu | ToolFamily::Clang => Some("-Wextra"), + } + } + + /// What the flag to turn warning into errors + fn warnings_to_errors_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "-WX", + ToolFamily::Gnu | ToolFamily::Clang => "-Werror", + } + } + + fn verbose_stderr(&self) -> bool { + *self == ToolFamily::Clang + } +} + +/// Represents an object. +/// +/// This is a source file -> object file pair. +#[derive(Clone, Debug)] +struct Object { + src: PathBuf, + dst: PathBuf, +} + +impl Object { + /// Create a new source file -> object file pair. + fn new(src: PathBuf, dst: PathBuf) -> Object { + Object { src: src, dst: dst } + } +} + +impl Build { + /// Construct a new instance of a blank set of configuration. + /// + /// This builder is finished with the [`compile`] function. + /// + /// [`compile`]: struct.Build.html#method.compile + pub fn new() -> Build { + Build { + include_directories: Vec::new(), + definitions: Vec::new(), + objects: Vec::new(), + flags: Vec::new(), + flags_supported: Vec::new(), + known_flag_support_status: Arc::new(Mutex::new(HashMap::new())), + ar_flags: Vec::new(), + no_default_flags: false, + files: Vec::new(), + shared_flag: None, + static_flag: None, + cpp: false, + cpp_link_stdlib: None, + cpp_set_stdlib: None, + cuda: false, + target: None, + host: None, + out_dir: None, + opt_level: None, + debug: None, + force_frame_pointer: None, + env: Vec::new(), + compiler: None, + archiver: None, + cargo_metadata: true, + pic: None, + use_plt: None, + static_crt: None, + warnings: None, + extra_warnings: None, + warnings_into_errors: false, + env_cache: Arc::new(Mutex::new(HashMap::new())), + apple_sdk_root_cache: Arc::new(Mutex::new(HashMap::new())), + } + } + + /// Add a directory to the `-I` or include path for headers + /// + /// # Example + /// + /// ```no_run + /// use std::path::Path; + /// + /// let library_path = Path::new("/path/to/library"); + /// + /// cc::Build::new() + /// .file("src/foo.c") + /// .include(library_path) + /// .include("src") + /// .compile("foo"); + /// ``` + pub fn include>(&mut self, dir: P) -> &mut Build { + self.include_directories.push(dir.as_ref().to_path_buf()); + self + } + + /// Specify a `-D` variable with an optional value. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .define("FOO", "BAR") + /// .define("BAZ", None) + /// .compile("foo"); + /// ``` + pub fn define<'a, V: Into>>(&mut self, var: &str, val: V) -> &mut Build { + self.definitions + .push((var.to_string(), val.into().map(|s| s.to_string()))); + self + } + + /// Add an arbitrary object file to link in + pub fn object>(&mut self, obj: P) -> &mut Build { + self.objects.push(obj.as_ref().to_path_buf()); + self + } + + /// Add an arbitrary flag to the invocation of the compiler + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag("-ffunction-sections") + /// .compile("foo"); + /// ``` + pub fn flag(&mut self, flag: &str) -> &mut Build { + self.flags.push(flag.to_string()); + self + } + + /// Add an arbitrary flag to the invocation of the compiler + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .file("src/bar.c") + /// .ar_flag("/NODEFAULTLIB:libc.dll") + /// .compile("foo"); + /// ``` + + pub fn ar_flag(&mut self, flag: &str) -> &mut Build { + self.ar_flags.push(flag.to_string()); + self + } + + fn ensure_check_file(&self) -> Result { + let out_dir = self.get_out_dir()?; + let src = if self.cuda { + assert!(self.cpp); + out_dir.join("flag_check.cu") + } else if self.cpp { + out_dir.join("flag_check.cpp") + } else { + out_dir.join("flag_check.c") + }; + + if !src.exists() { + let mut f = fs::File::create(&src)?; + write!(f, "int main(void) {{ return 0; }}")?; + } + + Ok(src) + } + + /// Run the compiler to test if it accepts the given flag. + /// + /// For a convenience method for setting flags conditionally, + /// see `flag_if_supported()`. + /// + /// It may return error if it's unable to run the compiler with a test file + /// (e.g. the compiler is missing or a write to the `out_dir` failed). + /// + /// Note: Once computed, the result of this call is stored in the + /// `known_flag_support` field. If `is_flag_supported(flag)` + /// is called again, the result will be read from the hash table. + pub fn is_flag_supported(&self, flag: &str) -> Result { + let mut known_status = self.known_flag_support_status.lock().unwrap(); + if let Some(is_supported) = known_status.get(flag).cloned() { + return Ok(is_supported); + } + + let out_dir = self.get_out_dir()?; + let src = self.ensure_check_file()?; + let obj = out_dir.join("flag_check"); + let target = self.get_target()?; + let host = self.get_host()?; + let mut cfg = Build::new(); + cfg.flag(flag) + .target(&target) + .opt_level(0) + .host(&host) + .debug(false) + .cpp(self.cpp) + .cuda(self.cuda); + let mut compiler = cfg.try_get_compiler()?; + + // Clang uses stderr for verbose output, which yields a false positive + // result if the CFLAGS/CXXFLAGS include -v to aid in debugging. + if compiler.family.verbose_stderr() { + compiler.remove_arg("-v".into()); + } + + let mut cmd = compiler.to_command(); + let is_arm = target.contains("aarch64") || target.contains("arm"); + let clang = compiler.family == ToolFamily::Clang; + command_add_output_file( + &mut cmd, + &obj, + self.cuda, + target.contains("msvc"), + clang, + false, + is_arm, + ); + + // We need to explicitly tell msvc not to link and create an exe + // in the root directory of the crate + if target.contains("msvc") && !self.cuda { + cmd.arg("-c"); + } + + cmd.arg(&src); + + let output = cmd.output()?; + let is_supported = output.stderr.is_empty(); + + known_status.insert(flag.to_owned(), is_supported); + Ok(is_supported) + } + + /// Add an arbitrary flag to the invocation of the compiler if it supports it + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag_if_supported("-Wlogical-op") // only supported by GCC + /// .flag_if_supported("-Wunreachable-code") // only supported by clang + /// .compile("foo"); + /// ``` + pub fn flag_if_supported(&mut self, flag: &str) -> &mut Build { + self.flags_supported.push(flag.to_string()); + self + } + + /// Set the `-shared` flag. + /// + /// When enabled, the compiler will produce a shared object which can + /// then be linked with other objects to form an executable. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .compile("libfoo.so"); + /// ``` + pub fn shared_flag(&mut self, shared_flag: bool) -> &mut Build { + self.shared_flag = Some(shared_flag); + self + } + + /// Set the `-static` flag. + /// + /// When enabled on systems that support dynamic linking, this prevents + /// linking with the shared libraries. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .static_flag(true) + /// .compile("foo"); + /// ``` + pub fn static_flag(&mut self, static_flag: bool) -> &mut Build { + self.static_flag = Some(static_flag); + self + } + + /// Disables the generation of default compiler flags. The default compiler + /// flags may cause conflicts in some cross compiling scenarios. + /// + /// Setting the `CRATE_CC_NO_DEFAULTS` environment variable has the same + /// effect as setting this to `true`. The presence of the environment + /// variable and the value of `no_default_flags` will be OR'd together. + pub fn no_default_flags(&mut self, no_default_flags: bool) -> &mut Build { + self.no_default_flags = no_default_flags; + self + } + + /// Add a file which will be compiled + pub fn file>(&mut self, p: P) -> &mut Build { + self.files.push(p.as_ref().to_path_buf()); + self + } + + /// Add files which will be compiled + pub fn files

    (&mut self, p: P) -> &mut Build + where + P: IntoIterator, + P::Item: AsRef, + { + for file in p.into_iter() { + self.file(file); + } + self + } + + /// Set C++ support. + /// + /// The other `cpp_*` options will only become active if this is set to + /// `true`. + pub fn cpp(&mut self, cpp: bool) -> &mut Build { + self.cpp = cpp; + self + } + + /// Set CUDA C++ support. + /// + /// Enabling CUDA will pass the detected C/C++ toolchain as an argument to + /// the CUDA compiler, NVCC. NVCC itself accepts some limited GNU-like args; + /// any other arguments for the C/C++ toolchain will be redirected using + /// "-Xcompiler" flags. + /// + /// If enabled, this also implicitly enables C++ support. + pub fn cuda(&mut self, cuda: bool) -> &mut Build { + self.cuda = cuda; + if cuda { + self.cpp = true; + } + self + } + + /// Set warnings into errors flag. + /// + /// Disabled by default. + /// + /// Warning: turning warnings into errors only make sense + /// if you are a developer of the crate using cc-rs. + /// Some warnings only appear on some architecture or + /// specific version of the compiler. Any user of this crate, + /// or any other crate depending on it, could fail during + /// compile time. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings_into_errors(true) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings_into_errors(&mut self, warnings_into_errors: bool) -> &mut Build { + self.warnings_into_errors = warnings_into_errors; + self + } + + /// Set warnings flags. + /// + /// Adds some flags: + /// - "-Wall" for MSVC. + /// - "-Wall", "-Wextra" for GNU and Clang. + /// + /// Enabled by default. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings(false) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings(&mut self, warnings: bool) -> &mut Build { + self.warnings = Some(warnings); + self.extra_warnings = Some(warnings); + self + } + + /// Set extra warnings flags. + /// + /// Adds some flags: + /// - nothing for MSVC. + /// - "-Wextra" for GNU and Clang. + /// + /// Enabled by default. + /// + /// # Example + /// + /// ```no_run + /// // Disables -Wextra, -Wall remains enabled: + /// cc::Build::new() + /// .file("src/foo.c") + /// .extra_warnings(false) + /// .compile("libfoo.a"); + /// ``` + pub fn extra_warnings(&mut self, warnings: bool) -> &mut Build { + self.extra_warnings = Some(warnings); + self + } + + /// Set the standard library to link against when compiling with C++ + /// support. + /// + /// The default value of this property depends on the current target: On + /// OS X `Some("c++")` is used, when compiling for a Visual Studio based + /// target `None` is used and for other targets `Some("stdc++")` is used. + /// If the `CXXSTDLIB` environment variable is set, its value will + /// override the default value. + /// + /// A value of `None` indicates that no automatic linking should happen, + /// otherwise cargo will link against the specified library. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .cpp_link_stdlib("stdc++") + /// .compile("libfoo.so"); + /// ``` + pub fn cpp_link_stdlib<'a, V: Into>>( + &mut self, + cpp_link_stdlib: V, + ) -> &mut Build { + self.cpp_link_stdlib = Some(cpp_link_stdlib.into().map(|s| s.into())); + self + } + + /// Force the C++ compiler to use the specified standard library. + /// + /// Setting this option will automatically set `cpp_link_stdlib` to the same + /// value. + /// + /// The default value of this option is always `None`. + /// + /// This option has no effect when compiling for a Visual Studio based + /// target. + /// + /// This option sets the `-stdlib` flag, which is only supported by some + /// compilers (clang, icc) but not by others (gcc). The library will not + /// detect which compiler is used, as such it is the responsibility of the + /// caller to ensure that this option is only used in conjuction with a + /// compiler which supports the `-stdlib` flag. + /// + /// A value of `None` indicates that no specific C++ standard library should + /// be used, otherwise `-stdlib` is added to the compile invocation. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .cpp_set_stdlib("c++") + /// .compile("libfoo.a"); + /// ``` + pub fn cpp_set_stdlib<'a, V: Into>>( + &mut self, + cpp_set_stdlib: V, + ) -> &mut Build { + let cpp_set_stdlib = cpp_set_stdlib.into(); + self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into()); + self.cpp_link_stdlib(cpp_set_stdlib); + self + } + + /// Configures the target this configuration will be compiling for. + /// + /// This option is automatically scraped from the `TARGET` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .target("aarch64-linux-android") + /// .compile("foo"); + /// ``` + pub fn target(&mut self, target: &str) -> &mut Build { + self.target = Some(target.to_string()); + self + } + + /// Configures the host assumed by this configuration. + /// + /// This option is automatically scraped from the `HOST` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .host("arm-linux-gnueabihf") + /// .compile("foo"); + /// ``` + pub fn host(&mut self, host: &str) -> &mut Build { + self.host = Some(host.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level(&mut self, opt_level: u32) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level_str(&mut self, opt_level: &str) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures whether the compiler will emit debug information when + /// generating object files. + /// + /// This option is automatically scraped from the `DEBUG` environment + /// variable by build scripts, so it's not required to call this function. + pub fn debug(&mut self, debug: bool) -> &mut Build { + self.debug = Some(debug); + self + } + + /// Configures whether the compiler will emit instructions to store + /// frame pointers during codegen. + /// + /// This option is automatically enabled when debug information is emitted. + /// Otherwise the target platform compiler's default will be used. + /// You can use this option to force a specific setting. + pub fn force_frame_pointer(&mut self, force: bool) -> &mut Build { + self.force_frame_pointer = Some(force); + self + } + + /// Configures the output directory where all object files and static + /// libraries will be located. + /// + /// This option is automatically scraped from the `OUT_DIR` environment + /// variable by build scripts, so it's not required to call this function. + pub fn out_dir>(&mut self, out_dir: P) -> &mut Build { + self.out_dir = Some(out_dir.as_ref().to_owned()); + self + } + + /// Configures the compiler to be used to produce output. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn compiler>(&mut self, compiler: P) -> &mut Build { + self.compiler = Some(compiler.as_ref().to_owned()); + self + } + + /// Configures the tool used to assemble archives. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn archiver>(&mut self, archiver: P) -> &mut Build { + self.archiver = Some(archiver.as_ref().to_owned()); + self + } + /// Define whether metadata should be emitted for cargo allowing it to + /// automatically link the binary. Defaults to `true`. + /// + /// The emitted metadata is: + /// + /// - `rustc-link-lib=static=`*compiled lib* + /// - `rustc-link-search=native=`*target folder* + /// - When target is MSVC, the ATL-MFC libs are added via `rustc-link-search=native=` + /// - When C++ is enabled, the C++ stdlib is added via `rustc-link-lib` + /// + pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Build { + self.cargo_metadata = cargo_metadata; + self + } + + /// Configures whether the compiler will emit position independent code. + /// + /// This option defaults to `false` for `windows-gnu` and bare metal targets and + /// to `true` for all other targets. + pub fn pic(&mut self, pic: bool) -> &mut Build { + self.pic = Some(pic); + self + } + + /// Configures whether the Procedure Linkage Table is used for indirect + /// calls into shared libraries. + /// + /// The PLT is used to provide features like lazy binding, but introduces + /// a small performance loss due to extra pointer indirection. Setting + /// `use_plt` to `false` can provide a small performance increase. + /// + /// Note that skipping the PLT requires a recent version of GCC/Clang. + /// + /// This only applies to ELF targets. It has no effect on other platforms. + pub fn use_plt(&mut self, use_plt: bool) -> &mut Build { + self.use_plt = Some(use_plt); + self + } + + /// Configures whether the /MT flag or the /MD flag will be passed to msvc build tools. + /// + /// This option defaults to `false`, and affect only msvc targets. + pub fn static_crt(&mut self, static_crt: bool) -> &mut Build { + self.static_crt = Some(static_crt); + self + } + + #[doc(hidden)] + pub fn __set_env(&mut self, a: A, b: B) -> &mut Build + where + A: AsRef, + B: AsRef, + { + self.env + .push((a.as_ref().to_owned(), b.as_ref().to_owned())); + self + } + + /// Run the compiler, generating the file `output` + /// + /// This will return a result instead of panicing; see compile() for the complete description. + pub fn try_compile(&self, output: &str) -> Result<(), Error> { + let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") { + (&output[3..output.len() - 2], output.to_owned()) + } else { + let mut gnu = String::with_capacity(5 + output.len()); + gnu.push_str("lib"); + gnu.push_str(&output); + gnu.push_str(".a"); + (output, gnu) + }; + let dst = self.get_out_dir()?; + + let mut objects = Vec::new(); + for file in self.files.iter() { + let obj = dst.join(file).with_extension("o"); + let obj = if !obj.starts_with(&dst) { + dst.join(obj.file_name().ok_or_else(|| { + Error::new(ErrorKind::IOError, "Getting object file details failed.") + })?) + } else { + obj + }; + + match obj.parent() { + Some(s) => fs::create_dir_all(s)?, + None => { + return Err(Error::new( + ErrorKind::IOError, + "Getting object file details failed.", + )); + } + }; + + objects.push(Object::new(file.to_path_buf(), obj)); + } + self.compile_objects(&objects)?; + self.assemble(lib_name, &dst.join(gnu_lib_name), &objects)?; + + if self.get_target()?.contains("msvc") { + let compiler = self.get_base_compiler()?; + let atlmfc_lib = compiler + .env() + .iter() + .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB")) + .and_then(|&(_, ref lib_paths)| { + env::split_paths(lib_paths).find(|path| { + let sub = Path::new("atlmfc/lib"); + path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub)) + }) + }); + + if let Some(atlmfc_lib) = atlmfc_lib { + self.print(&format!( + "cargo:rustc-link-search=native={}", + atlmfc_lib.display() + )); + } + } + + self.print(&format!("cargo:rustc-link-lib=static={}", lib_name)); + self.print(&format!("cargo:rustc-link-search=native={}", dst.display())); + + // Add specific C++ libraries, if enabled. + if self.cpp { + if let Some(stdlib) = self.get_cpp_link_stdlib()? { + self.print(&format!("cargo:rustc-link-lib={}", stdlib)); + } + } + + Ok(()) + } + + /// Run the compiler, generating the file `output` + /// + /// The name `output` should be the name of the library. For backwards compatibility, + /// the `output` may start with `lib` and end with `.a`. The Rust compiler will create + /// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix, + /// ending with `.lib`. + /// + /// # Panics + /// + /// Panics if `output` is not formatted correctly or if one of the underlying + /// compiler commands fails. It can also panic if it fails reading file names + /// or creating directories. + pub fn compile(&self, output: &str) { + if let Err(e) = self.try_compile(output) { + fail(&e.message); + } + } + + #[cfg(feature = "parallel")] + fn compile_objects<'me>(&'me self, objs: &[Object]) -> Result<(), Error> { + use std::sync::atomic::{AtomicBool, Ordering::SeqCst}; + use std::sync::Once; + + // Limit our parallelism globally with a jobserver. Start off by + // releasing our own token for this process so we can have a bit of an + // easier to write loop below. If this fails, though, then we're likely + // on Windows with the main implicit token, so we just have a bit extra + // parallelism for a bit and don't reacquire later. + let server = jobserver(); + let reacquire = server.release_raw().is_ok(); + + // When compiling objects in parallel we do a few dirty tricks to speed + // things up: + // + // * First is that we use the `jobserver` crate to limit the parallelism + // of this build script. The `jobserver` crate will use a jobserver + // configured by Cargo for build scripts to ensure that parallelism is + // coordinated across C compilations and Rust compilations. Before we + // compile anything we make sure to wait until we acquire a token. + // + // Note that this jobserver is cached globally so we only used one per + // process and only worry about creating it once. + // + // * Next we use a raw `thread::spawn` per thread to actually compile + // objects in parallel. We only actually spawn a thread after we've + // acquired a token to perform some work + // + // * Finally though we want to keep the dependencies of this crate + // pretty light, so we avoid using a safe abstraction like `rayon` and + // instead rely on some bits of `unsafe` code. We know that this stack + // frame persists while everything is compiling so we use all the + // stack-allocated objects without cloning/reallocating. We use a + // transmute to `State` with a `'static` lifetime to persist + // everything we need across the boundary, and the join-on-drop + // semantics of `JoinOnDrop` should ensure that our stack frame is + // alive while threads are alive. + // + // With all that in mind we compile all objects in a loop here, after we + // acquire the appropriate tokens, Once all objects have been compiled + // we join on all the threads and propagate the results of compilation. + // + // Note that as a slight optimization we try to break out as soon as + // possible as soon as any compilation fails to ensure that errors get + // out to the user as fast as possible. + let error = AtomicBool::new(false); + let mut threads = Vec::new(); + for obj in objs { + if error.load(SeqCst) { + break; + } + let token = server.acquire()?; + let state = State { + build: self, + obj, + error: &error, + }; + let state = unsafe { std::mem::transmute::>(state) }; + let thread = thread::spawn(|| { + let state: State<'me> = state; // erase the `'static` lifetime + let result = state.build.compile_object(state.obj); + if result.is_err() { + state.error.store(true, SeqCst); + } + drop(token); // make sure our jobserver token is released after the compile + return result; + }); + threads.push(JoinOnDrop(Some(thread))); + } + + for mut thread in threads { + if let Some(thread) = thread.0.take() { + thread.join().expect("thread should not panic")?; + } + } + + // Reacquire our process's token before we proceed, which we released + // before entering the loop above. + if reacquire { + server.acquire_raw()?; + } + + return Ok(()); + + /// Shared state from the parent thread to the child thread. This + /// package of pointers is temporarily transmuted to a `'static` + /// lifetime to cross the thread boundary and then once the thread is + /// running we erase the `'static` to go back to an anonymous lifetime. + struct State<'a> { + build: &'a Build, + obj: &'a Object, + error: &'a AtomicBool, + } + + /// Returns a suitable `jobserver::Client` used to coordinate + /// parallelism between build scripts. + fn jobserver() -> &'static jobserver::Client { + static INIT: Once = Once::new(); + static mut JOBSERVER: Option = None; + + fn _assert_sync() {} + _assert_sync::(); + + unsafe { + INIT.call_once(|| { + let server = default_jobserver(); + JOBSERVER = Some(server); + }); + JOBSERVER.as_ref().unwrap() + } + } + + unsafe fn default_jobserver() -> jobserver::Client { + // Try to use the environmental jobserver which Cargo typically + // initializes for us... + if let Some(client) = jobserver::Client::from_env() { + return client; + } + + // ... but if that fails for whatever reason select something + // reasonable and crate a new jobserver. Use `NUM_JOBS` if set (it's + // configured by Cargo) and otherwise just fall back to a + // semi-reasonable number. Note that we could use `num_cpus` here + // but it's an extra dependency that will almost never be used, so + // it's generally not too worth it. + let mut parallelism = 4; + if let Ok(amt) = env::var("NUM_JOBS") { + if let Ok(amt) = amt.parse() { + parallelism = amt; + } + } + + // If we create our own jobserver then be sure to reserve one token + // for ourselves. + let client = jobserver::Client::new(parallelism).expect("failed to create jobserver"); + client.acquire_raw().expect("failed to acquire initial"); + return client; + } + + struct JoinOnDrop(Option>>); + + impl Drop for JoinOnDrop { + fn drop(&mut self) { + if let Some(thread) = self.0.take() { + drop(thread.join()); + } + } + } + } + + #[cfg(not(feature = "parallel"))] + fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { + for obj in objs { + self.compile_object(obj)?; + } + Ok(()) + } + + fn compile_object(&self, obj: &Object) -> Result<(), Error> { + let is_asm = obj.src.extension().and_then(|s| s.to_str()) == Some("asm"); + let target = self.get_target()?; + let msvc = target.contains("msvc"); + let compiler = self.try_get_compiler()?; + let clang = compiler.family == ToolFamily::Clang; + let (mut cmd, name) = if msvc && is_asm { + self.msvc_macro_assembler()? + } else { + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + ( + cmd, + compiler + .path + .file_name() + .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? + .to_string_lossy() + .into_owned(), + ) + }; + let is_arm = target.contains("aarch64") || target.contains("arm"); + command_add_output_file(&mut cmd, &obj.dst, self.cuda, msvc, clang, is_asm, is_arm); + // armasm and armasm64 don't requrie -c option + if !msvc || !is_asm || !is_arm { + cmd.arg("-c"); + } + cmd.arg(&obj.src); + if cfg!(target_os = "macos") { + self.fix_env_for_apple_os(&mut cmd)?; + } + + run(&mut cmd, &name)?; + Ok(()) + } + + /// This will return a result instead of panicing; see expand() for the complete description. + pub fn try_expand(&self) -> Result, Error> { + let compiler = self.try_get_compiler()?; + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd.arg("-E"); + + assert!( + self.files.len() <= 1, + "Expand may only be called for a single file" + ); + + for file in self.files.iter() { + cmd.arg(file); + } + + let name = compiler + .path + .file_name() + .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? + .to_string_lossy() + .into_owned(); + + Ok(run_output(&mut cmd, &name)?) + } + + /// Run the compiler, returning the macro-expanded version of the input files. + /// + /// This is only relevant for C and C++ files. + /// + /// # Panics + /// Panics if more than one file is present in the config, or if compiler + /// path has an invalid file name. + /// + /// # Example + /// ```no_run + /// let out = cc::Build::new().file("src/foo.c").expand(); + /// ``` + pub fn expand(&self) -> Vec { + match self.try_expand() { + Err(e) => fail(&e.message), + Ok(v) => v, + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This function will return a `Tool` which represents the culmination + /// of this configuration at a snapshot in time. The returned compiler can + /// be inspected (e.g. the path, arguments, environment) to forward along to + /// other tools, or the `to_command` method can be used to invoke the + /// compiler itself. + /// + /// This method will take into account all configuration such as debug + /// information, optimization level, include directories, defines, etc. + /// Additionally, the compiler binary in use follows the standard + /// conventions for this path, e.g. looking at the explicitly set compiler, + /// environment variables (a number of which are inspected here), and then + /// falling back to the default configuration. + /// + /// # Panics + /// + /// Panics if an error occurred while determining the architecture. + pub fn get_compiler(&self) -> Tool { + match self.try_get_compiler() { + Ok(tool) => tool, + Err(e) => fail(&e.message), + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This will return a result instead of panicing; see get_compiler() for the complete description. + pub fn try_get_compiler(&self) -> Result { + let opt_level = self.get_opt_level()?; + let target = self.get_target()?; + + let mut cmd = self.get_base_compiler()?; + let envflags = self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" }); + + // Disable default flag generation via `no_default_flags` or environment variable + let no_defaults = self.no_default_flags || self.getenv("CRATE_CC_NO_DEFAULTS").is_some(); + + if !no_defaults { + self.add_default_flags(&mut cmd, &target, &opt_level)?; + } else { + println!("Info: default compiler flags are disabled"); + } + + for arg in envflags { + cmd.push_cc_arg(arg.into()); + } + + for directory in self.include_directories.iter() { + cmd.args.push("-I".into()); + cmd.args.push(directory.into()); + } + + // If warnings and/or extra_warnings haven't been explicitly set, + // then we set them only if the environment doesn't already have + // CFLAGS/CXXFLAGS, since those variables presumably already contain + // the desired set of warnings flags. + + if self + .warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + let wflags = cmd.family.warnings_flags().into(); + cmd.push_cc_arg(wflags); + } + + if self + .extra_warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + if let Some(wflags) = cmd.family.extra_warnings_flags() { + cmd.push_cc_arg(wflags.into()); + } + } + + for flag in self.flags.iter() { + cmd.args.push(flag.into()); + } + + for flag in self.flags_supported.iter() { + if self.is_flag_supported(flag).unwrap_or(false) { + cmd.push_cc_arg(flag.into()); + } + } + + for &(ref key, ref value) in self.definitions.iter() { + if let Some(ref value) = *value { + cmd.args.push(format!("-D{}={}", key, value).into()); + } else { + cmd.args.push(format!("-D{}", key).into()); + } + } + + if self.warnings_into_errors { + let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into(); + cmd.push_cc_arg(warnings_to_errors_flag); + } + + Ok(cmd) + } + + fn add_default_flags( + &self, + cmd: &mut Tool, + target: &str, + opt_level: &str, + ) -> Result<(), Error> { + // Non-target flags + // If the flag is not conditioned on target variable, it belongs here :) + match cmd.family { + ToolFamily::Msvc { .. } => { + cmd.push_cc_arg("-nologo".into()); + + let crt_flag = match self.static_crt { + Some(true) => "-MT", + Some(false) => "-MD", + None => { + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); + if features.contains("crt-static") { + "-MT" + } else { + "-MD" + } + } + }; + cmd.push_cc_arg(crt_flag.into()); + + match &opt_level[..] { + // Msvc uses /O1 to enable all optimizations that minimize code size. + "z" | "s" | "1" => cmd.push_opt_unless_duplicate("-O1".into()), + // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2. + "2" | "3" => cmd.push_opt_unless_duplicate("-O2".into()), + _ => {} + } + } + ToolFamily::Gnu | ToolFamily::Clang => { + // arm-linux-androideabi-gcc 4.8 shipped with Android NDK does + // not support '-Oz' + if opt_level == "z" && cmd.family != ToolFamily::Clang { + cmd.push_opt_unless_duplicate("-Os".into()); + } else { + cmd.push_opt_unless_duplicate(format!("-O{}", opt_level).into()); + } + + if cmd.family == ToolFamily::Clang && target.contains("android") { + // For compatibility with code that doesn't use pre-defined `__ANDROID__` macro. + // If compiler used via ndk-build or cmake (officially supported build methods) + // this macros is defined. + // See https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/cmake/android.toolchain.cmake#456 + // https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/core/build-binary.mk#141 + cmd.push_opt_unless_duplicate("-DANDROID".into()); + } + + if !target.contains("-ios") { + cmd.push_cc_arg("-ffunction-sections".into()); + cmd.push_cc_arg("-fdata-sections".into()); + } + // Disable generation of PIC on bare-metal for now: rust-lld doesn't support this yet + if self + .pic + .unwrap_or(!target.contains("windows") && !target.contains("-none-")) + { + cmd.push_cc_arg("-fPIC".into()); + // PLT only applies if code is compiled with PIC support, + // and only for ELF targets. + if target.contains("linux") && !self.use_plt.unwrap_or(true) { + cmd.push_cc_arg("-fno-plt".into()); + } + } + } + } + + if self.get_debug() { + if self.cuda { + // NVCC debug flag + cmd.args.push("-G".into()); + } + let family = cmd.family; + family.add_debug_flags(cmd); + } + + if self.get_force_frame_pointer() { + let family = cmd.family; + family.add_force_frame_pointer(cmd); + } + + // Target flags + match cmd.family { + ToolFamily::Clang => { + if !(target.contains("android") + && android_clang_compiler_uses_target_arg_internally(&cmd.path)) + { + cmd.args.push(format!("--target={}", target).into()); + } + } + ToolFamily::Msvc { clang_cl } => { + // This is an undocumented flag from MSVC but helps with making + // builds more reproducible by avoiding putting timestamps into + // files. + cmd.push_cc_arg("-Brepro".into()); + + if clang_cl { + if target.contains("x86_64") { + cmd.push_cc_arg("-m64".into()); + } else if target.contains("86") { + cmd.push_cc_arg("-m32".into()); + cmd.push_cc_arg("-arch:IA32".into()); + } else { + cmd.push_cc_arg(format!("--target={}", target).into()); + } + } else { + if target.contains("i586") { + cmd.push_cc_arg("-arch:IA32".into()); + } + } + + // There is a check in corecrt.h that will generate a + // compilation error if + // _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE is + // not defined to 1. The check was added in Windows + // 8 days because only store apps were allowed on ARM. + // This changed with the release of Windows 10 IoT Core. + // The check will be going away in future versions of + // the SDK, but for all released versions of the + // Windows SDK it is required. + if target.contains("arm") || target.contains("thumb") { + cmd.args + .push("-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1".into()); + } + } + ToolFamily::Gnu => { + if target.contains("i686") || target.contains("i586") { + cmd.args.push("-m32".into()); + } else if target == "x86_64-unknown-linux-gnux32" { + cmd.args.push("-mx32".into()); + } else if target.contains("x86_64") || target.contains("powerpc64") { + cmd.args.push("-m64".into()); + } + + if target.contains("darwin") { + if target.contains("x86_64") { + cmd.args.push("-arch".into()); + cmd.args.push("x86_64".into()); + } else if target.contains("arm64e") { + cmd.args.push("-arch".into()); + cmd.args.push("arm64e".into()); + } else if target.contains("aarch64") { + cmd.args.push("-arch".into()); + cmd.args.push("arm64".into()); + } + } + + if self.static_flag.is_none() { + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); + if features.contains("crt-static") { + cmd.args.push("-static".into()); + } + } + + // armv7 targets get to use armv7 instructions + if (target.starts_with("armv7") || target.starts_with("thumbv7")) + && target.contains("-linux-") + { + cmd.args.push("-march=armv7-a".into()); + } + + // (x86 Android doesn't say "eabi") + if target.contains("-androideabi") && target.contains("v7") { + // -march=armv7-a handled above + cmd.args.push("-mthumb".into()); + if !target.contains("neon") { + // On android we can guarantee some extra float instructions + // (specified in the android spec online) + // NEON guarantees even more; see below. + cmd.args.push("-mfpu=vfpv3-d16".into()); + } + cmd.args.push("-mfloat-abi=softfp".into()); + } + + if target.contains("neon") { + cmd.args.push("-mfpu=neon-vfpv4".into()); + } + + if target.starts_with("armv4t-unknown-linux-") { + cmd.args.push("-march=armv4t".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + if target.starts_with("armv5te-unknown-linux-") { + cmd.args.push("-march=armv5te".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + // For us arm == armv6 by default + if target.starts_with("arm-unknown-linux-") { + cmd.args.push("-march=armv6".into()); + cmd.args.push("-marm".into()); + if target.ends_with("hf") { + cmd.args.push("-mfpu=vfp".into()); + } else { + cmd.args.push("-mfloat-abi=soft".into()); + } + } + + // We can guarantee some settings for FRC + if target.starts_with("arm-frc-") { + cmd.args.push("-march=armv7-a".into()); + cmd.args.push("-mcpu=cortex-a9".into()); + cmd.args.push("-mfpu=vfpv3".into()); + cmd.args.push("-mfloat-abi=softfp".into()); + cmd.args.push("-marm".into()); + } + + // Turn codegen down on i586 to avoid some instructions. + if target.starts_with("i586-unknown-linux-") { + cmd.args.push("-march=pentium".into()); + } + + // Set codegen level for i686 correctly + if target.starts_with("i686-unknown-linux-") { + cmd.args.push("-march=i686".into()); + } + + // Looks like `musl-gcc` makes is hard for `-m32` to make its way + // all the way to the linker, so we need to actually instruct the + // linker that we're generating 32-bit executables as well. This'll + // typically only be used for build scripts which transitively use + // these flags that try to compile executables. + if target == "i686-unknown-linux-musl" || target == "i586-unknown-linux-musl" { + cmd.args.push("-Wl,-melf_i386".into()); + } + + if target.starts_with("thumb") { + cmd.args.push("-mthumb".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfloat-abi=hard".into()) + } + } + if target.starts_with("thumbv6m") { + cmd.args.push("-march=armv6s-m".into()); + } + if target.starts_with("thumbv7em") { + cmd.args.push("-march=armv7e-m".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfpu=fpv4-sp-d16".into()) + } + } + if target.starts_with("thumbv7m") { + cmd.args.push("-march=armv7-m".into()); + } + if target.starts_with("thumbv8m.base") { + cmd.args.push("-march=armv8-m.base".into()); + } + if target.starts_with("thumbv8m.main") { + cmd.args.push("-march=armv8-m.main".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfpu=fpv5-sp-d16".into()) + } + } + if target.starts_with("armebv7r") | target.starts_with("armv7r") { + if target.starts_with("armeb") { + cmd.args.push("-mbig-endian".into()); + } else { + cmd.args.push("-mlittle-endian".into()); + } + + // ARM mode + cmd.args.push("-marm".into()); + + // R Profile + cmd.args.push("-march=armv7-r".into()); + + if target.ends_with("eabihf") { + // Calling convention + cmd.args.push("-mfloat-abi=hard".into()); + + // lowest common denominator FPU + // (see Cortex-R4 technical reference manual) + cmd.args.push("-mfpu=vfpv3-d16".into()) + } else { + // Calling convention + cmd.args.push("-mfloat-abi=soft".into()); + } + } + if target.starts_with("armv7a") { + cmd.args.push("-march=armv7-a".into()); + + if target.ends_with("eabihf") { + // lowest common denominator FPU + cmd.args.push("-mfpu=vfpv3-d16".into()); + } + } + if target.starts_with("riscv32") || target.starts_with("riscv64") { + // get the 32i/32imac/32imc/64gc/64imac/... part + let mut parts = target.split('-'); + if let Some(arch) = parts.next() { + let arch = &arch[5..]; + cmd.args.push(("-march=rv".to_owned() + arch).into()); + if target.contains("linux") && arch.starts_with("64") { + cmd.args.push("-mabi=lp64d".into()); + } else if target.contains("linux") && arch.starts_with("32") { + cmd.args.push("-mabi=ilp32d".into()); + } else if arch.starts_with("64") { + cmd.args.push("-mabi=lp64".into()); + } else { + cmd.args.push("-mabi=ilp32".into()); + } + cmd.args.push("-mcmodel=medany".into()); + } + } + } + } + + if target.contains("-ios") { + // FIXME: potential bug. iOS is always compiled with Clang, but Gcc compiler may be + // detected instead. + self.ios_flags(cmd)?; + } + + if self.static_flag.unwrap_or(false) { + cmd.args.push("-static".into()); + } + if self.shared_flag.unwrap_or(false) { + cmd.args.push("-shared".into()); + } + + if self.cpp { + match (self.cpp_set_stdlib.as_ref(), cmd.family) { + (None, _) => {} + (Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang) => { + cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); + } + _ => { + println!( + "cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \ + does not support this option, ignored", + cmd.family + ); + } + } + } + + Ok(()) + } + + fn has_flags(&self) -> bool { + let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" }; + let flags_env_var_value = self.get_var(flags_env_var_name); + if let Ok(_) = flags_env_var_value { + true + } else { + false + } + } + + fn msvc_macro_assembler(&self) -> Result<(Command, String), Error> { + let target = self.get_target()?; + let tool = if target.contains("x86_64") { + "ml64.exe" + } else if target.contains("arm") { + "armasm.exe" + } else if target.contains("aarch64") { + "armasm64.exe" + } else { + "ml.exe" + }; + let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool)); + cmd.arg("-nologo"); // undocumented, yet working with armasm[64] + for directory in self.include_directories.iter() { + cmd.arg("-I").arg(directory); + } + if target.contains("aarch64") || target.contains("arm") { + println!("cargo:warning=The MSVC ARM assemblers do not support -D flags"); + } else { + for &(ref key, ref value) in self.definitions.iter() { + if let Some(ref value) = *value { + cmd.arg(&format!("-D{}={}", key, value)); + } else { + cmd.arg(&format!("-D{}", key)); + } + } + } + + if target.contains("i686") || target.contains("i586") { + cmd.arg("-safeseh"); + } + for flag in self.flags.iter() { + cmd.arg(flag); + } + + Ok((cmd, tool.to_string())) + } + + fn assemble(&self, lib_name: &str, dst: &Path, objs: &[Object]) -> Result<(), Error> { + // Delete the destination if it exists as the `ar` tool at least on Unix + // appends to it, which we don't want. + let _ = fs::remove_file(&dst); + + let objects: Vec<_> = objs.iter().map(|obj| obj.dst.clone()).collect(); + let target = self.get_target()?; + if target.contains("msvc") { + let (mut cmd, program) = self.get_ar()?; + let mut out = OsString::from("-out:"); + out.push(dst); + cmd.arg(out).arg("-nologo"); + for flag in self.ar_flags.iter() { + cmd.arg(flag); + } + + // Similar to https://github.com/rust-lang/rust/pull/47507 + // and https://github.com/rust-lang/rust/pull/48548 + let estimated_command_line_len = objects + .iter() + .chain(&self.objects) + .map(|a| a.as_os_str().len()) + .sum::(); + if estimated_command_line_len > 1024 * 6 { + let mut args = String::from("\u{FEFF}"); // BOM + for arg in objects.iter().chain(&self.objects) { + args.push('"'); + for c in arg.to_str().unwrap().chars() { + if c == '"' { + args.push('\\') + } + args.push(c) + } + args.push('"'); + args.push('\n'); + } + + let mut utf16le = Vec::new(); + for code_unit in args.encode_utf16() { + utf16le.push(code_unit as u8); + utf16le.push((code_unit >> 8) as u8); + } + + let mut args_file = OsString::from(dst); + args_file.push(".args"); + fs::File::create(&args_file) + .unwrap() + .write_all(&utf16le) + .unwrap(); + + let mut args_file_arg = OsString::from("@"); + args_file_arg.push(args_file); + cmd.arg(args_file_arg); + } else { + cmd.args(&objects).args(&self.objects); + } + run(&mut cmd, &program)?; + + // The Rust compiler will look for libfoo.a and foo.lib, but the + // MSVC linker will also be passed foo.lib, so be sure that both + // exist for now. + let lib_dst = dst.with_file_name(format!("{}.lib", lib_name)); + let _ = fs::remove_file(&lib_dst); + match fs::hard_link(&dst, &lib_dst).or_else(|_| { + // if hard-link fails, just copy (ignoring the number of bytes written) + fs::copy(&dst, &lib_dst).map(|_| ()) + }) { + Ok(_) => (), + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Could not copy or create a hard-link to the generated lib file.", + )); + } + }; + } else { + let (mut ar, cmd) = self.get_ar()?; + + // Set an environment variable to tell the OSX archiver to ensure + // that all dates listed in the archive are zero, improving + // determinism of builds. AFAIK there's not really official + // documentation of this but there's a lot of references to it if + // you search google. + // + // You can reproduce this locally on a mac with: + // + // $ touch foo.c + // $ cc -c foo.c -o foo.o + // + // # Notice that these two checksums are different + // $ ar crus libfoo1.a foo.o && sleep 2 && ar crus libfoo2.a foo.o + // $ md5sum libfoo*.a + // + // # Notice that these two checksums are the same + // $ export ZERO_AR_DATE=1 + // $ ar crus libfoo1.a foo.o && sleep 2 && touch foo.o && ar crus libfoo2.a foo.o + // $ md5sum libfoo*.a + // + // In any case if this doesn't end up getting read, it shouldn't + // cause that many issues! + ar.env("ZERO_AR_DATE", "1"); + for flag in self.ar_flags.iter() { + ar.arg(flag); + } + run( + ar.arg("crs").arg(dst).args(&objects).args(&self.objects), + &cmd, + )?; + } + + Ok(()) + } + + fn ios_flags(&self, cmd: &mut Tool) -> Result<(), Error> { + enum ArchSpec { + Device(&'static str), + Simulator(&'static str), + } + + let target = self.get_target()?; + let arch = target.split('-').nth(0).ok_or_else(|| { + Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + ) + })?; + let arch = match arch { + "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), + "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), + "arm64e" => ArchSpec::Device("arm64e"), + "arm64" | "aarch64" => ArchSpec::Device("arm64"), + "i386" | "i686" => ArchSpec::Simulator("-m32"), + "x86_64" => ArchSpec::Simulator("-m64"), + _ => { + return Err(Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + )); + } + }; + + let min_version = + std::env::var("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "7.0".into()); + + let sdk = match arch { + ArchSpec::Device(arch) => { + cmd.args.push("-arch".into()); + cmd.args.push(arch.into()); + cmd.args + .push(format!("-miphoneos-version-min={}", min_version).into()); + "iphoneos" + } + ArchSpec::Simulator(arch) => { + cmd.args.push(arch.into()); + cmd.args + .push(format!("-mios-simulator-version-min={}", min_version).into()); + "iphonesimulator" + } + }; + + self.print(&format!("Detecting iOS SDK path for {}", sdk)); + let sdk_path = self.apple_sdk_root(sdk)?; + cmd.args.push("-isysroot".into()); + cmd.args.push(sdk_path); + cmd.args.push("-fembed-bitcode".into()); + /* + * TODO we probably ultimately want the -fembed-bitcode-marker flag + * but can't have it now because of an issue in LLVM: + * https://github.com/alexcrichton/cc-rs/issues/301 + * https://github.com/rust-lang/rust/pull/48896#comment-372192660 + */ + /* + if self.get_opt_level()? == "0" { + cmd.args.push("-fembed-bitcode-marker".into()); + } + */ + + Ok(()) + } + + fn cmd>(&self, prog: P) -> Command { + let mut cmd = Command::new(prog); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd + } + + fn get_base_compiler(&self) -> Result { + if let Some(ref c) = self.compiler { + return Ok(Tool::new(c.clone())); + } + let host = self.get_host()?; + let target = self.get_target()?; + let (env, msvc, gnu, traditional, clang) = if self.cpp { + ("CXX", "cl.exe", "g++", "c++", "clang++") + } else { + ("CC", "cl.exe", "gcc", "cc", "clang") + }; + + // On historical Solaris systems, "cc" may have been Sun Studio, which + // is not flag-compatible with "gcc". This history casts a long shadow, + // and many modern illumos distributions today ship GCC as "gcc" without + // also making it available as "cc". + let default = if host.contains("solaris") || host.contains("illumos") { + gnu + } else { + traditional + }; + + let cl_exe = windows_registry::find_tool(&target, "cl.exe"); + + let tool_opt: Option = self + .env_tool(env) + .map(|(tool, wrapper, args)| { + // find the driver mode, if any + const DRIVER_MODE: &str = "--driver-mode="; + let driver_mode = args + .iter() + .find(|a| a.starts_with(DRIVER_MODE)) + .map(|a| &a[DRIVER_MODE.len()..]); + // Chop off leading/trailing whitespace to work around + // semi-buggy build scripts which are shared in + // makefiles/configure scripts (where spaces are far more + // lenient) + let mut t = Tool::with_clang_driver(PathBuf::from(tool.trim()), driver_mode); + if let Some(cc_wrapper) = wrapper { + t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); + } + for arg in args { + t.cc_wrapper_args.push(arg.into()); + } + t + }) + .or_else(|| { + if target.contains("emscripten") { + let tool = if self.cpp { "em++" } else { "emcc" }; + // Windows uses bat file so we have to be a bit more specific + if cfg!(windows) { + let mut t = Tool::new(PathBuf::from("cmd")); + t.args.push("/c".into()); + t.args.push(format!("{}.bat", tool).into()); + Some(t) + } else { + Some(Tool::new(PathBuf::from(tool))) + } + } else { + None + } + }) + .or_else(|| cl_exe.clone()); + + let tool = match tool_opt { + Some(t) => t, + None => { + let compiler = if host.contains("windows") && target.contains("windows") { + if target.contains("msvc") { + msvc.to_string() + } else { + format!("{}.exe", gnu) + } + } else if target.contains("android") { + autodetect_android_compiler(&target, &host, gnu, clang) + } else if target.contains("cloudabi") { + format!("{}-{}", target, traditional) + } else if target == "wasm32-wasi" + || target == "wasm32-unknown-wasi" + || target == "wasm32-unknown-unknown" + { + "clang".to_string() + } else if target.contains("vxworks") { + "wr-c++".to_string() + } else if self.get_host()? != target { + let prefix = self.prefix_for_target(&target); + match prefix { + Some(prefix) => format!("{}-{}", prefix, gnu), + None => default.to_string(), + } + } else { + default.to_string() + }; + + let mut t = Tool::new(PathBuf::from(compiler)); + if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() { + t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); + } + t + } + }; + + let mut tool = if self.cuda { + assert!( + tool.args.is_empty(), + "CUDA compilation currently assumes empty pre-existing args" + ); + let nvcc = match self.get_var("NVCC") { + Err(_) => "nvcc".into(), + Ok(nvcc) => nvcc, + }; + let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), None, self.cuda); + nvcc_tool + .args + .push(format!("-ccbin={}", tool.path.display()).into()); + nvcc_tool.family = tool.family; + nvcc_tool + } else { + tool + }; + + // If we found `cl.exe` in our environment, the tool we're returning is + // an MSVC-like tool, *and* no env vars were set then set env vars for + // the tool that we're returning. + // + // Env vars are needed for things like `link.exe` being put into PATH as + // well as header include paths sometimes. These paths are automatically + // included by default but if the `CC` or `CXX` env vars are set these + // won't be used. This'll ensure that when the env vars are used to + // configure for invocations like `clang-cl` we still get a "works out + // of the box" experience. + if let Some(cl_exe) = cl_exe { + if tool.family == (ToolFamily::Msvc { clang_cl: true }) + && tool.env.len() == 0 + && target.contains("msvc") + { + for &(ref k, ref v) in cl_exe.env.iter() { + tool.env.push((k.to_owned(), v.to_owned())); + } + } + } + + Ok(tool) + } + + fn get_var(&self, var_base: &str) -> Result { + let target = self.get_target()?; + let host = self.get_host()?; + let kind = if host == target { "HOST" } else { "TARGET" }; + let target_u = target.replace("-", "_"); + let res = self + .getenv(&format!("{}_{}", var_base, target)) + .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u))) + .or_else(|| self.getenv(&format!("{}_{}", kind, var_base))) + .or_else(|| self.getenv(var_base)); + + match res { + Some(res) => Ok(res), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!("Could not find environment variable {}.", var_base), + )), + } + } + + fn envflags(&self, name: &str) -> Vec { + self.get_var(name) + .unwrap_or(String::new()) + .split(|c: char| c.is_whitespace()) + .filter(|s| !s.is_empty()) + .map(|s| s.to_string()) + .collect() + } + + /// Returns a fallback `cc_compiler_wrapper` by introspecting `RUSTC_WRAPPER` + fn rustc_wrapper_fallback() -> Option { + // No explicit CC wrapper was detected, but check if RUSTC_WRAPPER + // is defined and is a build accelerator that is compatible with + // C/C++ compilers (e.g. sccache) + let valid_wrappers = ["sccache"]; + + let rustc_wrapper = std::env::var_os("RUSTC_WRAPPER")?; + let wrapper_path = Path::new(&rustc_wrapper); + let wrapper_stem = wrapper_path.file_stem()?; + + if valid_wrappers.contains(&wrapper_stem.to_str()?) { + Some(rustc_wrapper.to_str()?.to_owned()) + } else { + None + } + } + + /// Returns compiler path, optional modifier name from whitelist, and arguments vec + fn env_tool(&self, name: &str) -> Option<(String, Option, Vec)> { + let tool = match self.get_var(name) { + Ok(tool) => tool, + Err(_) => return None, + }; + + // If this is an exact path on the filesystem we don't want to do any + // interpretation at all, just pass it on through. This'll hopefully get + // us to support spaces-in-paths. + if Path::new(&tool).exists() { + return Some((tool, None, Vec::new())); + } + + // Ok now we want to handle a couple of scenarios. We'll assume from + // here on out that spaces are splitting separate arguments. Two major + // features we want to support are: + // + // CC='sccache cc' + // + // aka using `sccache` or any other wrapper/caching-like-thing for + // compilations. We want to know what the actual compiler is still, + // though, because our `Tool` API support introspection of it to see + // what compiler is in use. + // + // additionally we want to support + // + // CC='cc -flag' + // + // where the CC env var is used to also pass default flags to the C + // compiler. + // + // It's true that everything here is a bit of a pain, but apparently if + // you're not literally make or bash then you get a lot of bug reports. + let known_wrappers = ["ccache", "distcc", "sccache", "icecc"]; + + let mut parts = tool.split_whitespace(); + let maybe_wrapper = match parts.next() { + Some(s) => s, + None => return None, + }; + + let file_stem = Path::new(maybe_wrapper) + .file_stem() + .unwrap() + .to_str() + .unwrap(); + if known_wrappers.contains(&file_stem) { + if let Some(compiler) = parts.next() { + return Some(( + compiler.to_string(), + Some(maybe_wrapper.to_string()), + parts.map(|s| s.to_string()).collect(), + )); + } + } + + Some(( + maybe_wrapper.to_string(), + Self::rustc_wrapper_fallback(), + parts.map(|s| s.to_string()).collect(), + )) + } + + /// Returns the default C++ standard library for the current target: `libc++` + /// for OS X and `libstdc++` for anything else. + fn get_cpp_link_stdlib(&self) -> Result, Error> { + match self.cpp_link_stdlib.clone() { + Some(s) => Ok(s), + None => { + if let Ok(stdlib) = self.get_var("CXXSTDLIB") { + if stdlib.is_empty() { + Ok(None) + } else { + Ok(Some(stdlib)) + } + } else { + let target = self.get_target()?; + if target.contains("msvc") { + Ok(None) + } else if target.contains("apple") { + Ok(Some("c++".to_string())) + } else if target.contains("freebsd") { + Ok(Some("c++".to_string())) + } else if target.contains("openbsd") { + Ok(Some("c++".to_string())) + } else { + Ok(Some("stdc++".to_string())) + } + } + } + } + } + + fn get_ar(&self) -> Result<(Command, String), Error> { + if let Some(ref p) = self.archiver { + let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("ar"); + return Ok((self.cmd(p), name.to_string())); + } + if let Ok(p) = self.get_var("AR") { + return Ok((self.cmd(&p), p)); + } + let target = self.get_target()?; + let default_ar = "ar".to_string(); + let program = if target.contains("android") { + format!("{}-ar", target.replace("armv7", "arm")) + } else if target.contains("emscripten") { + // Windows use bat files so we have to be a bit more specific + if cfg!(windows) { + let mut cmd = self.cmd("cmd"); + cmd.arg("/c").arg("emar.bat"); + return Ok((cmd, "emar.bat".to_string())); + } + + "emar".to_string() + } else if target.contains("msvc") { + match windows_registry::find(&target, "lib.exe") { + Some(t) => return Ok((t, "lib.exe".to_string())), + None => "lib.exe".to_string(), + } + } else if self.get_host()? != target { + match self.prefix_for_target(&target) { + Some(p) => { + let target_ar = format!("{}-ar", p); + if Command::new(&target_ar).output().is_ok() { + target_ar + } else { + default_ar + } + } + None => default_ar, + } + } else { + default_ar + }; + Ok((self.cmd(&program), program)) + } + + fn prefix_for_target(&self, target: &str) -> Option { + // CROSS_COMPILE is of the form: "arm-linux-gnueabi-" + let cc_env = self.getenv("CROSS_COMPILE"); + let cross_compile = cc_env + .as_ref() + .map(|s| s.trim_right_matches('-').to_owned()); + cross_compile.or(match &target[..] { + "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"), + "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"), + "aarch64-unknown-netbsd" => Some("aarch64--netbsd"), + "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-musleabi" => Some("arm-linux-gnueabi"), + "arm-frc-linux-gnueabi" => Some("arm-frc-linux-gnueabi"), + "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"), + "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "arm-unknown-netbsd-eabi" => Some("arm--netbsdelf-eabi"), + "armv6-unknown-netbsd-eabihf" => Some("armv6--netbsdelf-eabihf"), + "armv7-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7-unknown-netbsd-eabihf" => Some("armv7--netbsdelf-eabihf"), + "hexagon-unknown-linux-musl" => Some("hexagon-linux-musl"), + "i586-unknown-linux-musl" => Some("musl"), + "i686-pc-windows-gnu" => Some("i686-w64-mingw32"), + "i686-uwp-windows-gnu" => Some("i686-w64-mingw32"), + "i686-unknown-linux-musl" => Some("musl"), + "i686-unknown-netbsd" => Some("i486--netbsdelf"), + "mips-unknown-linux-gnu" => Some("mips-linux-gnu"), + "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), + "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), + "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), + "mipsisa32r6-unknown-linux-gnu" => Some("mipsisa32r6-linux-gnu"), + "mipsisa32r6el-unknown-linux-gnu" => Some("mipsisa32r6el-linux-gnu"), + "mipsisa64r6-unknown-linux-gnuabi64" => Some("mipsisa64r6-linux-gnuabi64"), + "mipsisa64r6el-unknown-linux-gnuabi64" => Some("mipsisa64r6el-linux-gnuabi64"), + "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc-unknown-linux-gnuspe" => Some("powerpc-linux-gnuspe"), + "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), + "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), + "riscv32i-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv32imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv32imc-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv64gc-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv64-unknown-elf", + "riscv32-unknown-elf", + "riscv-none-embed", + ]), + "riscv64imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv64-unknown-elf", + "riscv32-unknown-elf", + "riscv-none-embed", + ]), + "riscv64gc-unknown-linux-gnu" => Some("riscv64-linux-gnu"), + "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), + "sparc-unknown-linux-gnu" => Some("sparc-linux-gnu"), + "sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"), + "sparc64-unknown-netbsd" => Some("sparc64--netbsd"), + "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"), + "armv7a-none-eabi" => Some("arm-none-eabi"), + "armv7a-none-eabihf" => Some("arm-none-eabi"), + "armebv7r-none-eabi" => Some("arm-none-eabi"), + "armebv7r-none-eabihf" => Some("arm-none-eabi"), + "armv7r-none-eabi" => Some("arm-none-eabi"), + "armv7r-none-eabihf" => Some("arm-none-eabi"), + "thumbv6m-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabihf" => Some("arm-none-eabi"), + "thumbv7m-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.base-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabihf" => Some("arm-none-eabi"), + "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-uwp-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"), + "x86_64-unknown-linux-musl" => Some("musl"), + "x86_64-unknown-netbsd" => Some("x86_64--netbsd"), + _ => None, + } + .map(|x| x.to_owned())) + } + + /// Some platforms have multiple, compatible, canonical prefixes. Look through + /// each possible prefix for a compiler that exists and return it. The prefixes + /// should be ordered from most-likely to least-likely. + fn find_working_gnu_prefix(&self, prefixes: &[&'static str]) -> Option<&'static str> { + let suffix = if self.cpp { "-g++" } else { "-gcc" }; + let extension = std::env::consts::EXE_SUFFIX; + + // Loop through PATH entries searching for each toolchain. This ensures that we + // are more likely to discover the toolchain early on, because chances are good + // that the desired toolchain is in one of the higher-priority paths. + env::var_os("PATH") + .as_ref() + .and_then(|path_entries| { + env::split_paths(path_entries).find_map(|path_entry| { + for prefix in prefixes { + let target_compiler = format!("{}{}{}", prefix, suffix, extension); + if path_entry.join(&target_compiler).exists() { + return Some(prefix); + } + } + None + }) + }) + .map(|prefix| *prefix) + .or_else(|| + // If no toolchain was found, provide the first toolchain that was passed in. + // This toolchain has been shown not to exist, however it will appear in the + // error that is shown to the user which should make it easier to search for + // where it should be obtained. + prefixes.first().map(|prefix| *prefix)) + } + + fn get_target(&self) -> Result { + match self.target.clone() { + Some(t) => Ok(t), + None => Ok(self.getenv_unwrap("TARGET")?), + } + } + + fn get_host(&self) -> Result { + match self.host.clone() { + Some(h) => Ok(h), + None => Ok(self.getenv_unwrap("HOST")?), + } + } + + fn get_opt_level(&self) -> Result { + match self.opt_level.as_ref().cloned() { + Some(ol) => Ok(ol), + None => Ok(self.getenv_unwrap("OPT_LEVEL")?), + } + } + + fn get_debug(&self) -> bool { + self.debug.unwrap_or_else(|| match self.getenv("DEBUG") { + Some(s) => s != "false", + None => false, + }) + } + + fn get_force_frame_pointer(&self) -> bool { + self.force_frame_pointer.unwrap_or_else(|| self.get_debug()) + } + + fn get_out_dir(&self) -> Result { + match self.out_dir.clone() { + Some(p) => Ok(p), + None => Ok(env::var_os("OUT_DIR").map(PathBuf::from).ok_or_else(|| { + Error::new( + ErrorKind::EnvVarNotFound, + "Environment variable OUT_DIR not defined.", + ) + })?), + } + } + + fn getenv(&self, v: &str) -> Option { + let mut cache = self.env_cache.lock().unwrap(); + if let Some(val) = cache.get(v) { + return val.clone(); + } + let r = env::var(v).ok(); + self.print(&format!("{} = {:?}", v, r)); + cache.insert(v.to_string(), r.clone()); + r + } + + fn getenv_unwrap(&self, v: &str) -> Result { + match self.getenv(v) { + Some(s) => Ok(s), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!("Environment variable {} not defined.", v.to_string()), + )), + } + } + + fn print(&self, s: &str) { + if self.cargo_metadata { + println!("{}", s); + } + } + + fn fix_env_for_apple_os(&self, cmd: &mut Command) -> Result<(), Error> { + let target = self.get_target()?; + let host = self.get_host()?; + if host.contains("apple-darwin") && target.contains("apple-darwin") { + // If, for example, `cargo` runs during the build of an XCode project, then `SDKROOT` environment variable + // would represent the current target, and this is the problem for us, if we want to compile something + // for the host, when host != target. + // We can not just remove `SDKROOT`, because, again, for example, XCode add to PATH + // /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin + // and `cc` from this path can not find system include files, like `pthread.h`, if `SDKROOT` + // is not set + if let Ok(sdkroot) = env::var("SDKROOT") { + if !sdkroot.contains("MacOSX") { + let macos_sdk = self.apple_sdk_root("macosx")?; + cmd.env("SDKROOT", macos_sdk); + } + } + // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at + // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld", + // although this is apparently ignored when using the linker at "/usr/bin/ld". + cmd.env_remove("IPHONEOS_DEPLOYMENT_TARGET"); + } + Ok(()) + } + + fn apple_sdk_root(&self, sdk: &str) -> Result { + let mut cache = self + .apple_sdk_root_cache + .lock() + .expect("apple_sdk_root_cache lock failed"); + if let Some(ret) = cache.get(sdk) { + return Ok(ret.clone()); + } + + let sdk_path = self + .cmd("xcrun") + .arg("--show-sdk-path") + .arg("--sdk") + .arg(sdk) + .stderr(Stdio::inherit()) + .output()? + .stdout; + + let sdk_path = match String::from_utf8(sdk_path) { + Ok(p) => p, + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Unable to determine iOS SDK path.", + )); + } + }; + let ret: OsString = sdk_path.trim().into(); + cache.insert(sdk.into(), ret.clone()); + Ok(ret) + } +} + +impl Default for Build { + fn default() -> Build { + Build::new() + } +} + +impl Tool { + fn new(path: PathBuf) -> Self { + Tool::with_features(path, None, false) + } + + fn with_clang_driver(path: PathBuf, clang_driver: Option<&str>) -> Self { + Self::with_features(path, clang_driver, false) + } + + #[cfg(windows)] + /// Explictly set the `ToolFamily`, skipping name-based detection. + fn with_family(path: PathBuf, family: ToolFamily) -> Self { + Self { + path: path, + cc_wrapper_path: None, + cc_wrapper_args: Vec::new(), + args: Vec::new(), + env: Vec::new(), + family: family, + cuda: false, + removed_args: Vec::new(), + } + } + + fn with_features(path: PathBuf, clang_driver: Option<&str>, cuda: bool) -> Self { + // Try to detect family of the tool from its name, falling back to Gnu. + let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { + if fname.contains("clang-cl") { + ToolFamily::Msvc { clang_cl: true } + } else if fname.contains("cl") + && !fname.contains("cloudabi") + && !fname.contains("uclibc") + && !fname.contains("clang") + { + ToolFamily::Msvc { clang_cl: false } + } else if fname.contains("clang") { + match clang_driver { + Some("cl") => ToolFamily::Msvc { clang_cl: true }, + _ => ToolFamily::Clang, + } + } else { + ToolFamily::Gnu + } + } else { + ToolFamily::Gnu + }; + + Tool { + path: path, + cc_wrapper_path: None, + cc_wrapper_args: Vec::new(), + args: Vec::new(), + env: Vec::new(), + family: family, + cuda: cuda, + removed_args: Vec::new(), + } + } + + /// Add an argument to be stripped from the final command arguments. + fn remove_arg(&mut self, flag: OsString) { + self.removed_args.push(flag); + } + + /// Add a flag, and optionally prepend the NVCC wrapper flag "-Xcompiler". + /// + /// Currently this is only used for compiling CUDA sources, since NVCC only + /// accepts a limited set of GNU-like flags, and the rest must be prefixed + /// with a "-Xcompiler" flag to get passed to the underlying C++ compiler. + fn push_cc_arg(&mut self, flag: OsString) { + if self.cuda { + self.args.push("-Xcompiler".into()); + } + self.args.push(flag); + } + + fn is_duplicate_opt_arg(&self, flag: &OsString) -> bool { + let flag = flag.to_str().unwrap(); + let mut chars = flag.chars(); + + // Only duplicate check compiler flags + if self.is_like_msvc() { + if chars.next() != Some('/') { + return false; + } + } else if self.is_like_gnu() || self.is_like_clang() { + if chars.next() != Some('-') { + return false; + } + } + + // Check for existing optimization flags (-O, /O) + if chars.next() == Some('O') { + return self + .args() + .iter() + .any(|ref a| a.to_str().unwrap_or("").chars().nth(1) == Some('O')); + } + + // TODO Check for existing -m..., -m...=..., /arch:... flags + return false; + } + + /// Don't push optimization arg if it conflicts with existing args + fn push_opt_unless_duplicate(&mut self, flag: OsString) { + if self.is_duplicate_opt_arg(&flag) { + println!("Info: Ignoring duplicate arg {:?}", &flag); + } else { + self.push_cc_arg(flag); + } + } + + /// Converts this compiler into a `Command` that's ready to be run. + /// + /// This is useful for when the compiler needs to be executed and the + /// command returned will already have the initial arguments and environment + /// variables configured. + pub fn to_command(&self) -> Command { + let mut cmd = match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cmd = Command::new(&cc_wrapper_path); + cmd.arg(&self.path); + cmd + } + None => Command::new(&self.path), + }; + cmd.args(&self.cc_wrapper_args); + + let value = self + .args + .iter() + .filter(|a| !self.removed_args.contains(a)) + .collect::>(); + cmd.args(&value); + + for &(ref k, ref v) in self.env.iter() { + cmd.env(k, v); + } + cmd + } + + /// Returns the path for this compiler. + /// + /// Note that this may not be a path to a file on the filesystem, e.g. "cc", + /// but rather something which will be resolved when a process is spawned. + pub fn path(&self) -> &Path { + &self.path + } + + /// Returns the default set of arguments to the compiler needed to produce + /// executables for the target this compiler generates. + pub fn args(&self) -> &[OsString] { + &self.args + } + + /// Returns the set of environment variables needed for this compiler to + /// operate. + /// + /// This is typically only used for MSVC compilers currently. + pub fn env(&self) -> &[(OsString, OsString)] { + &self.env + } + + /// Returns the compiler command in format of CC environment variable. + /// Or empty string if CC env was not present + /// + /// This is typically used by configure script + pub fn cc_env(&self) -> OsString { + match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cc_env = cc_wrapper_path.as_os_str().to_owned(); + cc_env.push(" "); + cc_env.push(self.path.to_path_buf().into_os_string()); + for arg in self.cc_wrapper_args.iter() { + cc_env.push(" "); + cc_env.push(arg); + } + cc_env + } + None => OsString::from(""), + } + } + + /// Returns the compiler flags in format of CFLAGS environment variable. + /// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS + /// This is typically used by configure script + pub fn cflags_env(&self) -> OsString { + let mut flags = OsString::new(); + for (i, arg) in self.args.iter().enumerate() { + if i > 0 { + flags.push(" "); + } + flags.push(arg); + } + flags + } + + /// Whether the tool is GNU Compiler Collection-like. + pub fn is_like_gnu(&self) -> bool { + self.family == ToolFamily::Gnu + } + + /// Whether the tool is Clang-like. + pub fn is_like_clang(&self) -> bool { + self.family == ToolFamily::Clang + } + + /// Whether the tool is MSVC-like. + pub fn is_like_msvc(&self) -> bool { + match self.family { + ToolFamily::Msvc { .. } => true, + _ => false, + } + } +} + +fn run(cmd: &mut Command, program: &str) -> Result<(), Error> { + let (mut child, print) = spawn(cmd, program)?; + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, program + ), + )); + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(()) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, program, status + ), + )) + } +} + +fn run_output(cmd: &mut Command, program: &str) -> Result, Error> { + cmd.stdout(Stdio::piped()); + let (mut child, print) = spawn(cmd, program)?; + let mut stdout = vec![]; + child + .stdout + .take() + .unwrap() + .read_to_end(&mut stdout) + .unwrap(); + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, program + ), + )); + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(stdout) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, program, status + ), + )) + } +} + +fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Error> { + println!("running: {:?}", cmd); + + // Capture the standard error coming from these programs, and write it out + // with cargo:warning= prefixes. Note that this is a bit wonky to avoid + // requiring the output to be UTF-8, we instead just ship bytes from one + // location to another. + match cmd.stderr(Stdio::piped()).spawn() { + Ok(mut child) => { + let stderr = BufReader::new(child.stderr.take().unwrap()); + let print = thread::spawn(move || { + for line in stderr.split(b'\n').filter_map(|l| l.ok()) { + print!("cargo:warning="); + std::io::stdout().write_all(&line).unwrap(); + println!(""); + } + }); + Ok((child, print)) + } + Err(ref e) if e.kind() == io::ErrorKind::NotFound => { + let extra = if cfg!(windows) { + " (see https://github.com/alexcrichton/cc-rs#compile-time-requirements \ + for help)" + } else { + "" + }; + Err(Error::new( + ErrorKind::ToolNotFound, + &format!("Failed to find tool. Is `{}` installed?{}", program, extra), + )) + } + Err(_) => Err(Error::new( + ErrorKind::ToolExecError, + &format!("Command {:?} with args {:?} failed to start.", cmd, program), + )), + } +} + +fn fail(s: &str) -> ! { + let _ = writeln!(io::stderr(), "\n\nerror occurred: {}\n\n", s); + std::process::exit(1); +} + +fn command_add_output_file( + cmd: &mut Command, + dst: &Path, + cuda: bool, + msvc: bool, + clang: bool, + is_asm: bool, + is_arm: bool, +) { + if msvc && !clang && !cuda && !(is_asm && is_arm) { + let mut s = OsString::from("-Fo"); + s.push(&dst); + cmd.arg(s); + } else { + cmd.arg("-o").arg(&dst); + } +} + +// Use by default minimum available API level +// See note about naming here +// https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/docs/BuildSystemMaintainers.md#Clang +static NEW_STANDALONE_ANDROID_COMPILERS: [&str; 4] = [ + "aarch64-linux-android21-clang", + "armv7a-linux-androideabi16-clang", + "i686-linux-android16-clang", + "x86_64-linux-android21-clang", +]; + +// New "standalone" C/C++ cross-compiler executables from recent Android NDK +// are just shell scripts that call main clang binary (from Android NDK) with +// proper `--target` argument. +// +// For example, armv7a-linux-androideabi16-clang passes +// `--target=armv7a-linux-androideabi16` to clang. +// So to construct proper command line check if +// `--target` argument would be passed or not to clang +fn android_clang_compiler_uses_target_arg_internally(clang_path: &Path) -> bool { + if let Some(filename) = clang_path.file_name() { + if let Some(filename_str) = filename.to_str() { + filename_str.contains("android") + } else { + false + } + } else { + false + } +} + +#[test] +fn test_android_clang_compiler_uses_target_arg_internally() { + for version in 16..21 { + assert!(android_clang_compiler_uses_target_arg_internally( + &PathBuf::from(format!("armv7a-linux-androideabi{}-clang", version)) + )); + assert!(android_clang_compiler_uses_target_arg_internally( + &PathBuf::from(format!("armv7a-linux-androideabi{}-clang++", version)) + )); + } + assert!(!android_clang_compiler_uses_target_arg_internally( + &PathBuf::from("clang") + )); + assert!(!android_clang_compiler_uses_target_arg_internally( + &PathBuf::from("clang++") + )); +} + +fn autodetect_android_compiler(target: &str, host: &str, gnu: &str, clang: &str) -> String { + let new_clang_key = match target { + "aarch64-linux-android" => Some("aarch64"), + "armv7-linux-androideabi" => Some("armv7a"), + "i686-linux-android" => Some("i686"), + "x86_64-linux-android" => Some("x86_64"), + _ => None, + }; + + let new_clang = new_clang_key + .map(|key| { + NEW_STANDALONE_ANDROID_COMPILERS + .iter() + .find(|x| x.starts_with(key)) + }) + .unwrap_or(None); + + if let Some(new_clang) = new_clang { + if Command::new(new_clang).output().is_ok() { + return (*new_clang).into(); + } + } + + let target = target + .replace("armv7neon", "arm") + .replace("armv7", "arm") + .replace("thumbv7neon", "arm") + .replace("thumbv7", "arm"); + let gnu_compiler = format!("{}-{}", target, gnu); + let clang_compiler = format!("{}-{}", target, clang); + + // On Windows, the Android clang compiler is provided as a `.cmd` file instead + // of a `.exe` file. `std::process::Command` won't run `.cmd` files unless the + // `.cmd` is explicitly appended to the command name, so we do that here. + let clang_compiler_cmd = format!("{}-{}.cmd", target, clang); + + // Check if gnu compiler is present + // if not, use clang + if Command::new(&gnu_compiler).output().is_ok() { + gnu_compiler + } else if host.contains("windows") && Command::new(&clang_compiler_cmd).output().is_ok() { + clang_compiler_cmd + } else { + clang_compiler + } +} diff --git a/vendor/cc-1.0.59/src/registry.rs b/vendor/cc-1.0.59/src/registry.rs new file mode 100644 index 0000000000..2ac2fa63ba --- /dev/null +++ b/vendor/cc-1.0.59/src/registry.rs @@ -0,0 +1,204 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ffi::{OsStr, OsString}; +use std::io; +use std::ops::RangeFrom; +use std::os::raw; +use std::os::windows::prelude::*; + +pub struct RegistryKey(Repr); + +type HKEY = *mut u8; +type DWORD = u32; +type LPDWORD = *mut DWORD; +type LPCWSTR = *const u16; +type LPWSTR = *mut u16; +type LONG = raw::c_long; +type PHKEY = *mut HKEY; +type PFILETIME = *mut u8; +type LPBYTE = *mut u8; +type REGSAM = u32; + +const ERROR_SUCCESS: DWORD = 0; +const ERROR_NO_MORE_ITEMS: DWORD = 259; +const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY; +const REG_SZ: DWORD = 1; +const KEY_READ: DWORD = 0x20019; +const KEY_WOW64_32KEY: DWORD = 0x200; + +#[link(name = "advapi32")] +extern "system" { + fn RegOpenKeyExW( + key: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY, + ) -> LONG; + fn RegEnumKeyExW( + key: HKEY, + dwIndex: DWORD, + lpName: LPWSTR, + lpcName: LPDWORD, + lpReserved: LPDWORD, + lpClass: LPWSTR, + lpcClass: LPDWORD, + lpftLastWriteTime: PFILETIME, + ) -> LONG; + fn RegQueryValueExW( + hKey: HKEY, + lpValueName: LPCWSTR, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LONG; + fn RegCloseKey(hKey: HKEY) -> LONG; +} + +struct OwnedKey(HKEY); + +enum Repr { + Const(HKEY), + Owned(OwnedKey), +} + +pub struct Iter<'a> { + idx: RangeFrom, + key: &'a RegistryKey, +} + +unsafe impl Sync for Repr {} +unsafe impl Send for Repr {} + +pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE)); + +impl RegistryKey { + fn raw(&self) -> HKEY { + match self.0 { + Repr::Const(val) => val, + Repr::Owned(ref val) => val.0, + } + } + + pub fn open(&self, key: &OsStr) -> io::Result { + let key = key.encode_wide().chain(Some(0)).collect::>(); + let mut ret = 0 as *mut _; + let err = unsafe { + RegOpenKeyExW( + self.raw(), + key.as_ptr(), + 0, + KEY_READ | KEY_WOW64_32KEY, + &mut ret, + ) + }; + if err == ERROR_SUCCESS as LONG { + Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) + } else { + Err(io::Error::from_raw_os_error(err as i32)) + } + } + + pub fn iter(&self) -> Iter { + Iter { + idx: 0.., + key: self, + } + } + + pub fn query_str(&self, name: &str) -> io::Result { + let name: &OsStr = name.as_ref(); + let name = name.encode_wide().chain(Some(0)).collect::>(); + let mut len = 0; + let mut kind = 0; + unsafe { + let err = RegQueryValueExW( + self.raw(), + name.as_ptr(), + 0 as *mut _, + &mut kind, + 0 as *mut _, + &mut len, + ); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)); + } + if kind != REG_SZ { + return Err(io::Error::new( + io::ErrorKind::Other, + "registry key wasn't a string", + )); + } + + // The length here is the length in bytes, but we're using wide + // characters so we need to be sure to halve it for the capacity + // passed in. + let mut v = Vec::with_capacity(len as usize / 2); + let err = RegQueryValueExW( + self.raw(), + name.as_ptr(), + 0 as *mut _, + 0 as *mut _, + v.as_mut_ptr() as *mut _, + &mut len, + ); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)); + } + v.set_len(len as usize / 2); + + // Some registry keys may have a terminating nul character, but + // we're not interested in that, so chop it off if it's there. + if v[v.len() - 1] == 0 { + v.pop(); + } + Ok(OsString::from_wide(&v)) + } + } +} + +impl Drop for OwnedKey { + fn drop(&mut self) { + unsafe { + RegCloseKey(self.0); + } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.idx.next().and_then(|i| unsafe { + let mut v = Vec::with_capacity(256); + let mut len = v.capacity() as DWORD; + let ret = RegEnumKeyExW( + self.key.raw(), + i, + v.as_mut_ptr(), + &mut len, + 0 as *mut _, + 0 as *mut _, + 0 as *mut _, + 0 as *mut _, + ); + if ret == ERROR_NO_MORE_ITEMS as LONG { + None + } else if ret != ERROR_SUCCESS as LONG { + Some(Err(io::Error::from_raw_os_error(ret as i32))) + } else { + v.set_len(len as usize); + Some(Ok(OsString::from_wide(&v))) + } + }) + } +} diff --git a/vendor/cc-1.0.59/src/setup_config.rs b/vendor/cc-1.0.59/src/setup_config.rs new file mode 100644 index 0000000000..bc2b1c2d30 --- /dev/null +++ b/vendor/cc-1.0.59/src/setup_config.rs @@ -0,0 +1,283 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] +#![allow(unused)] + +use crate::winapi::Interface; +use crate::winapi::BSTR; +use crate::winapi::LPCOLESTR; +use crate::winapi::LPSAFEARRAY; +use crate::winapi::S_FALSE; +use crate::winapi::{CoCreateInstance, CLSCTX_ALL}; +use crate::winapi::{IUnknown, IUnknownVtbl}; +use crate::winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG}; +use crate::winapi::{LPFILETIME, ULONG}; +use std::ffi::OsString; +use std::ptr::null_mut; + +use crate::com::{BStr, ComPtr}; + +// Bindings to the Setup.Configuration stuff +pub type InstanceState = u32; + +pub const eNone: InstanceState = 0; +pub const eLocal: InstanceState = 1; +pub const eRegistered: InstanceState = 2; +pub const eNoRebootRequired: InstanceState = 4; +pub const eComplete: InstanceState = -1i32 as u32; + +RIDL! {#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)] +interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) { + fn GetInstanceId( + pbstrInstanceId: *mut BSTR, + ) -> HRESULT, + fn GetInstallDate( + pInstallDate: LPFILETIME, + ) -> HRESULT, + fn GetInstallationName( + pbstrInstallationName: *mut BSTR, + ) -> HRESULT, + fn GetInstallationPath( + pbstrInstallationPath: *mut BSTR, + ) -> HRESULT, + fn GetInstallationVersion( + pbstrInstallationVersion: *mut BSTR, + ) -> HRESULT, + fn GetDisplayName( + lcid: LCID, + pbstrDisplayName: *mut BSTR, + ) -> HRESULT, + fn GetDescription( + lcid: LCID, + pbstrDescription: *mut BSTR, + ) -> HRESULT, + fn ResolvePath( + pwszRelativePath: LPCOLESTR, + pbstrAbsolutePath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)] +interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) { + fn GetState( + pState: *mut InstanceState, + ) -> HRESULT, + fn GetPackages( + ppsaPackages: *mut LPSAFEARRAY, + ) -> HRESULT, + fn GetProduct( + ppPackage: *mut *mut ISetupPackageReference, + ) -> HRESULT, + fn GetProductPath( + pbstrProductPath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)] +interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut ISetupInstance, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)] +interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) { + fn EnumInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, + fn GetInstanceForCurrentProcess( + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, + fn GetInstanceForPath( + wzPath: LPCWSTR, + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)] +interface ISetupConfiguration2(ISetupConfiguration2Vtbl): + ISetupConfiguration(ISetupConfigurationVtbl) { + fn EnumAllInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)] +interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) { + fn GetId( + pbstrId: *mut BSTR, + ) -> HRESULT, + fn GetVersion( + pbstrVersion: *mut BSTR, + ) -> HRESULT, + fn GetChip( + pbstrChip: *mut BSTR, + ) -> HRESULT, + fn GetLanguage( + pbstrLanguage: *mut BSTR, + ) -> HRESULT, + fn GetBranch( + pbstrBranch: *mut BSTR, + ) -> HRESULT, + fn GetType( + pbstrType: *mut BSTR, + ) -> HRESULT, + fn GetUniqueId( + pbstrUniqueId: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)] +interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) { + fn ParseVersion( + pwszVersion: LPCOLESTR, + pullVersion: PULONGLONG, + ) -> HRESULT, + fn ParseVersionRange( + pwszVersionRange: LPCOLESTR, + pullMinVersion: PULONGLONG, + pullMaxVersion: PULONGLONG, + ) -> HRESULT, +}} + +DEFINE_GUID! {CLSID_SetupConfiguration, +0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d} + +// Safe wrapper around the COM interfaces +pub struct SetupConfiguration(ComPtr); + +impl SetupConfiguration { + pub fn new() -> Result { + let mut obj = null_mut(); + let err = unsafe { + CoCreateInstance( + &CLSID_SetupConfiguration, + null_mut(), + CLSCTX_ALL, + &ISetupConfiguration::uuidof(), + &mut obj, + ) + }; + if err < 0 { + return Err(err); + } + let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) }; + Ok(SetupConfiguration(obj)) + } + pub fn get_instance_for_current_process(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { SetupInstance::from_raw(obj) }) + } + pub fn enum_instances(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.EnumInstances(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } + pub fn enum_all_instances(&self) -> Result { + let mut obj = null_mut(); + let this = self.0.cast::()?; + let err = unsafe { this.EnumAllInstances(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } +} + +pub struct SetupInstance(ComPtr); + +impl SetupInstance { + pub unsafe fn from_raw(obj: *mut ISetupInstance) -> SetupInstance { + SetupInstance(ComPtr::from_raw(obj)) + } + pub fn instance_id(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstanceId(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_name(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationName(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_path(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_version(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationVersion(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn product_path(&self) -> Result { + let mut s = null_mut(); + let this = self.0.cast::()?; + let err = unsafe { this.GetProductPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } +} + +pub struct EnumSetupInstances(ComPtr); + +impl EnumSetupInstances { + pub unsafe fn from_raw(obj: *mut IEnumSetupInstances) -> EnumSetupInstances { + EnumSetupInstances(ComPtr::from_raw(obj)) + } +} + +impl Iterator for EnumSetupInstances { + type Item = Result; + fn next(&mut self) -> Option> { + let mut obj = null_mut(); + let err = unsafe { self.0.Next(1, &mut obj, null_mut()) }; + if err < 0 { + return Some(Err(err)); + } + if err == S_FALSE { + return None; + } + Some(Ok(unsafe { SetupInstance::from_raw(obj) })) + } +} diff --git a/vendor/cc-1.0.59/src/winapi.rs b/vendor/cc-1.0.59/src/winapi.rs new file mode 100644 index 0000000000..c416325b52 --- /dev/null +++ b/vendor/cc-1.0.59/src/winapi.rs @@ -0,0 +1,218 @@ +// Copyright © 2015-2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::os::raw; + +pub type wchar_t = u16; + +pub type UINT = raw::c_uint; +pub type LPUNKNOWN = *mut IUnknown; +pub type REFIID = *const IID; +pub type IID = GUID; +pub type REFCLSID = *const IID; +pub type PVOID = *mut raw::c_void; +pub type USHORT = raw::c_ushort; +pub type ULONG = raw::c_ulong; +pub type LONG = raw::c_long; +pub type DWORD = u32; +pub type LPVOID = *mut raw::c_void; +pub type HRESULT = raw::c_long; +pub type LPFILETIME = *mut FILETIME; +pub type BSTR = *mut OLECHAR; +pub type OLECHAR = WCHAR; +pub type WCHAR = wchar_t; +pub type LPCOLESTR = *const OLECHAR; +pub type LCID = DWORD; +pub type LPCWSTR = *const WCHAR; +pub type PULONGLONG = *mut ULONGLONG; +pub type ULONGLONG = u64; + +pub const S_OK: HRESULT = 0; +pub const S_FALSE: HRESULT = 1; +pub const COINIT_MULTITHREADED: u32 = 0x0; + +pub type CLSCTX = u32; + +pub const CLSCTX_INPROC_SERVER: CLSCTX = 0x1; +pub const CLSCTX_INPROC_HANDLER: CLSCTX = 0x2; +pub const CLSCTX_LOCAL_SERVER: CLSCTX = 0x4; +pub const CLSCTX_REMOTE_SERVER: CLSCTX = 0x10; + +pub const CLSCTX_ALL: CLSCTX = + CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct GUID { + pub Data1: raw::c_ulong, + pub Data2: raw::c_ushort, + pub Data3: raw::c_ushort, + pub Data4: [raw::c_uchar; 8], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct FILETIME { + pub dwLowDateTime: DWORD, + pub dwHighDateTime: DWORD, +} + +pub trait Interface { + fn uuidof() -> GUID; +} + +#[link(name = "ole32")] +#[link(name = "oleaut32")] +extern "C" {} + +extern "system" { + pub fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) -> HRESULT; + pub fn CoCreateInstance( + rclsid: REFCLSID, + pUnkOuter: LPUNKNOWN, + dwClsContext: DWORD, + riid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT; + pub fn SysFreeString(bstrString: BSTR); + pub fn SysStringLen(pbstr: BSTR) -> UINT; +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SAFEARRAYBOUND { + pub cElements: ULONG, + pub lLbound: LONG, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SAFEARRAY { + pub cDims: USHORT, + pub fFeatures: USHORT, + pub cbElements: ULONG, + pub cLocks: ULONG, + pub pvData: PVOID, + pub rgsabound: [SAFEARRAYBOUND; 1], +} + +pub type LPSAFEARRAY = *mut SAFEARRAY; + +macro_rules! DEFINE_GUID { + ( + $name:ident, $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => { + pub const $name: $crate::winapi::GUID = $crate::winapi::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + }; + }; +} + +macro_rules! RIDL { + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t),* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) { + }) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t,)* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (@deref $interface:ident $pinterface:ident) => ( + impl ::std::ops::Deref for $interface { + type Target = $pinterface; + #[inline] + fn deref(&self) -> &$pinterface { + unsafe { &*(self as *const $interface as *const $pinterface) } + } + } + ); + (@impl $interface:ident {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + impl $interface { + $(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr { + ((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*) + })+ + } + ); + (@uuid $interface:ident + $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => ( + impl $crate::winapi::Interface for $interface { + #[inline] + fn uuidof() -> $crate::winapi::GUID { + $crate::winapi::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + } + } + } + ); +} + +RIDL! {#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IUnknown(IUnknownVtbl) { + fn QueryInterface( + riid: REFIID, + ppvObject: *mut *mut raw::c_void, + ) -> HRESULT, + fn AddRef() -> ULONG, + fn Release() -> ULONG, +}} diff --git a/vendor/cc-1.0.59/src/windows_registry.rs b/vendor/cc-1.0.59/src/windows_registry.rs new file mode 100644 index 0000000000..81725026b3 --- /dev/null +++ b/vendor/cc-1.0.59/src/windows_registry.rs @@ -0,0 +1,794 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A helper module to probe the Windows Registry when looking for +//! windows-specific tools. + +use std::process::Command; + +use crate::Tool; +#[cfg(windows)] +use crate::ToolFamily; + +#[cfg(windows)] +const MSVC_FAMILY: ToolFamily = ToolFamily::Msvc { clang_cl: false }; + +/// Attempts to find a tool within an MSVC installation using the Windows +/// registry as a point to search from. +/// +/// The `target` argument is the target that the tool should work for (e.g. +/// compile or link for) and the `tool` argument is the tool to find (e.g. +/// `cl.exe` or `link.exe`). +/// +/// This function will return `None` if the tool could not be found, or it will +/// return `Some(cmd)` which represents a command that's ready to execute the +/// tool with the appropriate environment variables set. +/// +/// Note that this function always returns `None` for non-MSVC targets. +pub fn find(target: &str, tool: &str) -> Option { + find_tool(target, tool).map(|c| c.to_command()) +} + +/// Similar to the `find` function above, this function will attempt the same +/// operation (finding a MSVC tool in a local install) but instead returns a +/// `Tool` which may be introspected. +#[cfg(not(windows))] +pub fn find_tool(_target: &str, _tool: &str) -> Option { + None +} + +/// Documented above. +#[cfg(windows)] +pub fn find_tool(target: &str, tool: &str) -> Option { + use std::env; + + // This logic is all tailored for MSVC, if we're not that then bail out + // early. + if !target.contains("msvc") { + return None; + } + + // Looks like msbuild isn't located in the same location as other tools like + // cl.exe and lib.exe. To handle this we probe for it manually with + // dedicated registry keys. + if tool.contains("msbuild") { + return impl_::find_msbuild(target); + } + + if tool.contains("devenv") { + return impl_::find_devenv(target); + } + + // If VCINSTALLDIR is set, then someone's probably already run vcvars and we + // should just find whatever that indicates. + if env::var_os("VCINSTALLDIR").is_some() { + return env::var_os("PATH") + .and_then(|path| { + env::split_paths(&path) + .map(|p| p.join(tool)) + .find(|p| p.exists()) + }) + .map(|path| Tool::with_family(path.into(), MSVC_FAMILY)); + } + + // Ok, if we're here, now comes the fun part of the probing. Default shells + // or shells like MSYS aren't really configured to execute `cl.exe` and the + // various compiler tools shipped as part of Visual Studio. Here we try to + // first find the relevant tool, then we also have to be sure to fill in + // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that + // the tool is actually usable. + + return impl_::find_msvc_15plus(tool, target) + .or_else(|| impl_::find_msvc_14(tool, target)) + .or_else(|| impl_::find_msvc_12(tool, target)) + .or_else(|| impl_::find_msvc_11(tool, target)); +} + +/// A version of Visual Studio +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum VsVers { + /// Visual Studio 12 (2013) + Vs12, + /// Visual Studio 14 (2015) + Vs14, + /// Visual Studio 15 (2017) + Vs15, + /// Visual Studio 16 (2019) + Vs16, + + /// Hidden variant that should not be matched on. Callers that want to + /// handle an enumeration of `VsVers` instances should always have a default + /// case meaning that it's a VS version they don't understand. + #[doc(hidden)] + #[allow(bad_style)] + __Nonexhaustive_do_not_match_this_or_your_code_will_break, +} + +/// Find the most recent installed version of Visual Studio +/// +/// This is used by the cmake crate to figure out the correct +/// generator. +#[cfg(not(windows))] +pub fn find_vs_version() -> Result { + Err(format!("not windows")) +} + +/// Documented above +#[cfg(windows)] +pub fn find_vs_version() -> Result { + use std::env; + + match env::var("VisualStudioVersion") { + Ok(version) => match &version[..] { + "16.0" => Ok(VsVers::Vs16), + "15.0" => Ok(VsVers::Vs15), + "14.0" => Ok(VsVers::Vs14), + "12.0" => Ok(VsVers::Vs12), + vers => Err(format!( + "\n\n\ + unsupported or unknown VisualStudio version: {}\n\ + if another version is installed consider running \ + the appropriate vcvars script before building this \ + crate\n\ + ", + vers + )), + }, + _ => { + // Check for the presense of a specific registry key + // that indicates visual studio is installed. + if impl_::has_msbuild_version("16.0") { + Ok(VsVers::Vs16) + } else if impl_::has_msbuild_version("15.0") { + Ok(VsVers::Vs15) + } else if impl_::has_msbuild_version("14.0") { + Ok(VsVers::Vs14) + } else if impl_::has_msbuild_version("12.0") { + Ok(VsVers::Vs12) + } else { + Err(format!( + "\n\n\ + couldn't determine visual studio generator\n\ + if VisualStudio is installed, however, consider \ + running the appropriate vcvars script before building \ + this crate\n\ + " + )) + } + } + } +} + +#[cfg(windows)] +mod impl_ { + use crate::com; + use crate::registry::{RegistryKey, LOCAL_MACHINE}; + use crate::setup_config::{EnumSetupInstances, SetupConfiguration, SetupInstance}; + use std::env; + use std::ffi::OsString; + use std::fs::File; + use std::io::Read; + use std::iter; + use std::mem; + use std::path::{Path, PathBuf}; + use std::str::FromStr; + + use super::MSVC_FAMILY; + use crate::Tool; + + struct MsvcTool { + tool: PathBuf, + libs: Vec, + path: Vec, + include: Vec, + } + + impl MsvcTool { + fn new(tool: PathBuf) -> MsvcTool { + MsvcTool { + tool: tool, + libs: Vec::new(), + path: Vec::new(), + include: Vec::new(), + } + } + + fn into_tool(self) -> Tool { + let MsvcTool { + tool, + libs, + path, + include, + } = self; + let mut tool = Tool::with_family(tool.into(), MSVC_FAMILY); + add_env(&mut tool, "LIB", libs); + add_env(&mut tool, "PATH", path); + add_env(&mut tool, "INCLUDE", include); + tool + } + } + + #[allow(bare_trait_objects)] + fn vs16_instances() -> Box> { + let instances = if let Some(instances) = vs15plus_instances() { + instances + } else { + return Box::new(iter::empty()); + }; + Box::new(instances.filter_map(|instance| { + let instance = instance.ok()?; + let installation_name = instance.installation_name().ok()?; + if installation_name.to_str()?.starts_with("VisualStudio/16.") { + Some(PathBuf::from(instance.installation_path().ok()?)) + } else if installation_name + .to_str()? + .starts_with("VisualStudioPreview/16.") + { + Some(PathBuf::from(instance.installation_path().ok()?)) + } else { + None + } + })) + } + + fn find_tool_in_vs16_path(tool: &str, target: &str) -> Option { + vs16_instances() + .filter_map(|path| { + let path = path.join(tool); + if !path.is_file() { + return None; + } + let mut tool = Tool::with_family(path, MSVC_FAMILY); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + Some(tool) + }) + .next() + } + + fn find_msbuild_vs16(target: &str) -> Option { + find_tool_in_vs16_path(r"MSBuild\Current\Bin\MSBuild.exe", target) + } + + // In MSVC 15 (2017) MS once again changed the scheme for locating + // the tooling. Now we must go through some COM interfaces, which + // is super fun for Rust. + // + // Note that much of this logic can be found [online] wrt paths, COM, etc. + // + // [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/ + // + // Returns MSVC 15+ instances (15, 16 right now), the order should be consider undefined. + fn vs15plus_instances() -> Option { + com::initialize().ok()?; + + let config = SetupConfiguration::new().ok()?; + config.enum_all_instances().ok() + } + + // Inspired from official microsoft/vswhere ParseVersionString + // i.e. at most four u16 numbers separated by '.' + fn parse_version(version: &str) -> Option> { + version + .split('.') + .map(|chunk| u16::from_str(chunk).ok()) + .collect() + } + + pub fn find_msvc_15plus(tool: &str, target: &str) -> Option { + let iter = vs15plus_instances()?; + iter.filter_map(|instance| { + let instance = instance.ok()?; + let version = parse_version(instance.installation_version().ok()?.to_str()?)?; + let tool = tool_from_vs15plus_instance(tool, target, &instance)?; + Some((version, tool)) + }) + .max_by(|(a_version, _), (b_version, _)| a_version.cmp(b_version)) + .map(|(_version, tool)| tool) + } + + // While the paths to Visual Studio 2017's devenv and MSBuild could + // potentially be retrieved from the registry, finding them via + // SetupConfiguration has shown to be [more reliable], and is preferred + // according to Microsoft. To help head off potential regressions though, + // we keep the registry method as a fallback option. + // + // [more reliable]: https://github.com/alexcrichton/cc-rs/pull/331 + fn find_tool_in_vs15_path(tool: &str, target: &str) -> Option { + let mut path = match vs15plus_instances() { + Some(instances) => instances + .filter_map(|instance| { + instance + .ok() + .and_then(|instance| instance.installation_path().ok()) + }) + .map(|path| PathBuf::from(path).join(tool)) + .find(|ref path| path.is_file()), + None => None, + }; + + if path.is_none() { + let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7"; + path = LOCAL_MACHINE + .open(key.as_ref()) + .ok() + .and_then(|key| key.query_str("15.0").ok()) + .map(|path| PathBuf::from(path).join(tool)) + .and_then(|path| if path.is_file() { Some(path) } else { None }); + } + + path.map(|path| { + let mut tool = Tool::with_family(path, MSVC_FAMILY); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } + + fn tool_from_vs15plus_instance( + tool: &str, + target: &str, + instance: &SetupInstance, + ) -> Option { + let (bin_path, host_dylib_path, lib_path, include_path) = + vs15plus_vc_paths(target, instance)?; + let tool_path = bin_path.join(tool); + if !tool_path.exists() { + return None; + }; + + let mut tool = MsvcTool::new(tool_path); + tool.path.push(bin_path.clone()); + tool.path.push(host_dylib_path); + tool.libs.push(lib_path); + tool.include.push(include_path); + + if let Some((atl_lib_path, atl_include_path)) = atl_paths(target, &bin_path) { + tool.libs.push(atl_lib_path); + tool.include.push(atl_include_path); + } + + add_sdks(&mut tool, target)?; + + Some(tool.into_tool()) + } + + fn vs15plus_vc_paths( + target: &str, + instance: &SetupInstance, + ) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf)> { + let instance_path: PathBuf = instance.installation_path().ok()?.into(); + let version_path = + instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt"); + let mut version_file = File::open(version_path).ok()?; + let mut version = String::new(); + version_file.read_to_string(&mut version).ok()?; + let version = version.trim(); + let host = match host_arch() { + X86 => "X86", + X86_64 => "X64", + // There is no natively hosted compiler on ARM64. + // Instead, use the x86 toolchain under emulation (there is no x64 emulation). + AARCH64 => "X86", + _ => return None, + }; + let target = lib_subdir(target)?; + // The directory layout here is MSVC/bin/Host$host/$target/ + let path = instance_path.join(r"VC\Tools\MSVC").join(version); + // This is the path to the toolchain for a particular target, running + // on a given host + let bin_path = path + .join("bin") + .join(&format!("Host{}", host)) + .join(&target); + // But! we also need PATH to contain the target directory for the host + // architecture, because it contains dlls like mspdb140.dll compiled for + // the host architecture. + let host_dylib_path = path + .join("bin") + .join(&format!("Host{}", host)) + .join(&host.to_lowercase()); + let lib_path = path.join("lib").join(&target); + let include_path = path.join("include"); + Some((bin_path, host_dylib_path, lib_path, include_path)) + } + + fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> { + let atl_path = path.join("atlfmc"); + let sub = lib_subdir(target)?; + if atl_path.exists() { + Some((atl_path.join("lib").join(sub), atl_path.join("include"))) + } else { + None + } + } + + // For MSVC 14 we need to find the Universal CRT as well as either + // the Windows 10 SDK or Windows 8.1 SDK. + pub fn find_msvc_14(tool: &str, target: &str) -> Option { + let vcdir = get_vc_dir("14.0")?; + let mut tool = get_tool(tool, &vcdir, target)?; + add_sdks(&mut tool, target)?; + Some(tool.into_tool()) + } + + fn add_sdks(tool: &mut MsvcTool, target: &str) -> Option<()> { + let sub = lib_subdir(target)?; + let (ucrt, ucrt_version) = get_ucrt_dir()?; + + let host = match host_arch() { + X86 => "x86", + X86_64 => "x64", + AARCH64 => "arm64", + _ => return None, + }; + + tool.path + .push(ucrt.join("bin").join(&ucrt_version).join(host)); + + let ucrt_include = ucrt.join("include").join(&ucrt_version); + tool.include.push(ucrt_include.join("ucrt")); + + let ucrt_lib = ucrt.join("lib").join(&ucrt_version); + tool.libs.push(ucrt_lib.join("ucrt").join(sub)); + + if let Some((sdk, version)) = get_sdk10_dir() { + tool.path.push(sdk.join("bin").join(host)); + let sdk_lib = sdk.join("lib").join(&version); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include").join(&version); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("cppwinrt")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } else if let Some(sdk) = get_sdk81_dir() { + tool.path.push(sdk.join("bin").join(host)); + let sdk_lib = sdk.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include"); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } + + Some(()) + } + + // For MSVC 12 we need to find the Windows 8.1 SDK. + pub fn find_msvc_12(tool: &str, target: &str) -> Option { + let vcdir = get_vc_dir("12.0")?; + let mut tool = get_tool(tool, &vcdir, target)?; + let sub = lib_subdir(target)?; + let sdk81 = get_sdk81_dir()?; + tool.path.push(sdk81.join("bin").join(sub)); + let sdk_lib = sdk81.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk81.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + // For MSVC 11 we need to find the Windows 8 SDK. + pub fn find_msvc_11(tool: &str, target: &str) -> Option { + let vcdir = get_vc_dir("11.0")?; + let mut tool = get_tool(tool, &vcdir, target)?; + let sub = lib_subdir(target)?; + let sdk8 = get_sdk8_dir()?; + tool.path.push(sdk8.join("bin").join(sub)); + let sdk_lib = sdk8.join("lib").join("win8"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk8.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + fn add_env(tool: &mut Tool, env: &str, paths: Vec) { + let prev = env::var_os(env).unwrap_or(OsString::new()); + let prev = env::split_paths(&prev); + let new = paths.into_iter().chain(prev); + tool.env + .push((env.to_string().into(), env::join_paths(new).unwrap())); + } + + // Given a possible MSVC installation directory, we look for the linker and + // then add the MSVC library path. + fn get_tool(tool: &str, path: &Path, target: &str) -> Option { + bin_subdir(target) + .into_iter() + .map(|(sub, host)| { + ( + path.join("bin").join(sub).join(tool), + path.join("bin").join(host), + ) + }) + .filter(|&(ref path, _)| path.is_file()) + .map(|(path, host)| { + let mut tool = MsvcTool::new(path); + tool.path.push(host); + tool + }) + .filter_map(|mut tool| { + let sub = vc_lib_subdir(target)?; + tool.libs.push(path.join("lib").join(sub)); + tool.include.push(path.join("include")); + let atlmfc_path = path.join("atlmfc"); + if atlmfc_path.exists() { + tool.libs.push(atlmfc_path.join("lib").join(sub)); + tool.include.push(atlmfc_path.join("include")); + } + Some(tool) + }) + .next() + } + + // To find MSVC we look in a specific registry key for the version we are + // trying to find. + fn get_vc_dir(ver: &str) -> Option { + let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let path = key.query_str(ver).ok()?; + Some(path.into()) + } + + // To find the Universal CRT we look in a specific registry key for where + // all the Universal CRTs are located and then sort them asciibetically to + // find the newest version. While this sort of sorting isn't ideal, it is + // what vcvars does so that's good enough for us. + // + // Returns a pair of (root, version) for the ucrt dir if found + fn get_ucrt_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("KitsRoot10").ok()?; + let readdir = Path::new(&root).join("lib").read_dir().ok()?; + let max_libdir = readdir + .filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .filter(|dir| { + dir.components() + .last() + .and_then(|c| c.as_os_str().to_str()) + .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir()) + .unwrap_or(false) + }) + .max()?; + let version = max_libdir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Vcvars finds the correct version of the Windows 10 SDK by looking + // for the include `um\Windows.h` because sometimes a given version will + // only have UCRT bits without the rest of the SDK. Since we only care about + // libraries and not includes, we instead look for `um\x64\kernel32.lib`. + // Since the 32-bit and 64-bit libraries are always installed together we + // only need to bother checking x64, making this code a tiny bit simpler. + // Like we do for the Universal CRT, we sort the possibilities + // asciibetically to find the newest one as that is what vcvars does. + fn get_sdk10_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("InstallationFolder").ok()?; + let readdir = Path::new(&root).join("lib").read_dir().ok()?; + let mut dirs = readdir + .filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .collect::>(); + dirs.sort(); + let dir = dirs + .into_iter() + .rev() + .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file()) + .next()?; + let version = dir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Interestingly there are several subdirectories, `win7` `win8` and + // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same + // applies to us. Note that if we were targetting kernel mode drivers + // instead of user mode applications, we would care. + fn get_sdk81_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("InstallationFolder").ok()?; + Some(root.into()) + } + + fn get_sdk8_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("InstallationFolder").ok()?; + Some(root.into()) + } + + const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0; + const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9; + const PROCESSOR_ARCHITECTURE_ARM64: u16 = 12; + const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL; + const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64; + const AARCH64: u16 = PROCESSOR_ARCHITECTURE_ARM64; + + // When choosing the tool to use, we have to choose the one which matches + // the target architecture. Otherwise we end up in situations where someone + // on 32-bit Windows is trying to cross compile to 64-bit and it tries to + // invoke the native 64-bit compiler which won't work. + // + // For the return value of this function, the first member of the tuple is + // the folder of the tool we will be invoking, while the second member is + // the folder of the host toolchain for that tool which is essential when + // using a cross linker. We return a Vec since on x64 there are often two + // linkers that can target the architecture we desire. The 64-bit host + // linker is preferred, and hence first, due to 64-bit allowing it more + // address space to work with and potentially being faster. + fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> { + let arch = target.split('-').next().unwrap(); + match (arch, host_arch()) { + ("i586", X86) | ("i686", X86) => vec![("", "")], + ("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")], + ("x86_64", X86) => vec![("x86_amd64", "")], + ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")], + ("arm", X86) | ("thumbv7a", X86) => vec![("x86_arm", "")], + ("arm", X86_64) | ("thumbv7a", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")], + _ => vec![], + } + } + + fn lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some("x86"), + "x86_64" => Some("x64"), + "arm" | "thumbv7a" => Some("arm"), + "aarch64" => Some("arm64"), + _ => None, + } + } + + // MSVC's x86 libraries are not in a subfolder + fn vc_lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some(""), + "x86_64" => Some("amd64"), + "arm" | "thumbv7a" => Some("arm"), + "aarch64" => Some("arm64"), + _ => None, + } + } + + #[allow(bad_style)] + fn host_arch() -> u16 { + type DWORD = u32; + type WORD = u16; + type LPVOID = *mut u8; + type DWORD_PTR = usize; + + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: WORD, + _wReserved: WORD, + _dwPageSize: DWORD, + _lpMinimumApplicationAddress: LPVOID, + _lpMaximumApplicationAddress: LPVOID, + _dwActiveProcessorMask: DWORD_PTR, + _dwNumberOfProcessors: DWORD, + _dwProcessorType: DWORD, + _dwAllocationGranularity: DWORD, + _wProcessorLevel: WORD, + _wProcessorRevision: WORD, + } + + extern "system" { + fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO); + } + + unsafe { + let mut info = mem::zeroed(); + GetNativeSystemInfo(&mut info); + info.wProcessorArchitecture + } + } + + // Given a registry key, look at all the sub keys and find the one which has + // the maximal numeric value. + // + // Returns the name of the maximal key as well as the opened maximal key. + fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> { + let mut max_vers = 0; + let mut max_key = None; + for subkey in key.iter().filter_map(|k| k.ok()) { + let val = subkey + .to_str() + .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok()); + let val = match val { + Some(s) => s, + None => continue, + }; + if val > max_vers { + if let Ok(k) = key.open(&subkey) { + max_vers = val; + max_key = Some((subkey, k)); + } + } + } + max_key + } + + pub fn has_msbuild_version(version: &str) -> bool { + match version { + "16.0" => { + find_msbuild_vs16("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs16("i686-pc-windows-msvc").is_some() + } + "15.0" => { + find_msbuild_vs15("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs15("i686-pc-windows-msvc").is_some() + } + "12.0" | "14.0" => LOCAL_MACHINE + .open(&OsString::from(format!( + "SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}", + version + ))) + .is_ok(), + _ => false, + } + } + + pub fn find_devenv(target: &str) -> Option { + find_devenv_vs15(&target) + } + + fn find_devenv_vs15(target: &str) -> Option { + find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target) + } + + // see http://stackoverflow.com/questions/328017/path-to-msbuild + pub fn find_msbuild(target: &str) -> Option { + // VS 15 (2017) changed how to locate msbuild + if let Some(r) = find_msbuild_vs16(target) { + return Some(r); + } else if let Some(r) = find_msbuild_vs15(target) { + return Some(r); + } else { + find_old_msbuild(target) + } + } + + fn find_msbuild_vs15(target: &str) -> Option { + find_tool_in_vs15_path(r"MSBuild\15.0\Bin\MSBuild.exe", target) + } + + fn find_old_msbuild(target: &str) -> Option { + let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions"; + LOCAL_MACHINE + .open(key.as_ref()) + .ok() + .and_then(|key| { + max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok()) + }) + .map(|path| { + let mut path = PathBuf::from(path); + path.push("MSBuild.exe"); + let mut tool = Tool::with_family(path, MSVC_FAMILY); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } +} diff --git a/vendor/cc-1.0.59/tests/cc_env.rs b/vendor/cc-1.0.59/tests/cc_env.rs new file mode 100644 index 0000000000..43eb689f0f --- /dev/null +++ b/vendor/cc-1.0.59/tests/cc_env.rs @@ -0,0 +1,118 @@ +use std::env; +use std::ffi::OsString; +use std::path::Path; + +mod support; +use crate::support::Test; + +#[test] +fn main() { + ccache(); + distcc(); + ccache_spaces(); + ccache_env_flags(); + leading_spaces(); + extra_flags(); + path_to_ccache(); + more_spaces(); +} + +fn ccache() { + let test = Test::gnu(); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn distcc() { + let test = Test::gnu(); + test.shim("distcc"); + + env::set_var("CC", "distcc cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_env_flags() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache lol-this-is-not-a-compiler"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("lol-this-is-not-a-compiler")); + assert_eq!( + compiler.cc_env(), + OsString::from("ccache lol-this-is-not-a-compiler") + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains("ccache") + == false + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains(" lol-this-is-not-a-compiler") + == false + ); + + env::set_var("CC", ""); +} + +fn leading_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", " test "); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("test")); + + env::set_var("CC", ""); +} + +fn extra_flags() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn path_to_ccache() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "/path/to/ccache.exe cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); + assert_eq!( + compiler.cc_env(), + OsString::from("/path/to/ccache.exe cc -m32"), + ); +} + +fn more_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} diff --git a/vendor/cc-1.0.59/tests/cflags.rs b/vendor/cc-1.0.59/tests/cflags.rs new file mode 100644 index 0000000000..caec6ea4ed --- /dev/null +++ b/vendor/cc-1.0.59/tests/cflags.rs @@ -0,0 +1,15 @@ +mod support; + +use crate::support::Test; +use std::env; + +/// This test is in its own module because it modifies the environment and would affect other tests +/// when run in parallel with them. +#[test] +fn gnu_no_warnings_if_cflags() { + env::set_var("CFLAGS", "-arbitrary"); + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra"); +} diff --git a/vendor/cc-1.0.59/tests/cxxflags.rs b/vendor/cc-1.0.59/tests/cxxflags.rs new file mode 100644 index 0000000000..c524c7da4e --- /dev/null +++ b/vendor/cc-1.0.59/tests/cxxflags.rs @@ -0,0 +1,15 @@ +mod support; + +use crate::support::Test; +use std::env; + +/// This test is in its own module because it modifies the environment and would affect other tests +/// when run in parallel with them. +#[test] +fn gnu_no_warnings_if_cxxflags() { + env::set_var("CXXFLAGS", "-arbitrary"); + let test = Test::gnu(); + test.gcc().file("foo.cpp").cpp(true).compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra"); +} diff --git a/vendor/cc-1.0.59/tests/support/mod.rs b/vendor/cc-1.0.59/tests/support/mod.rs new file mode 100644 index 0000000000..cde930e90b --- /dev/null +++ b/vendor/cc-1.0.59/tests/support/mod.rs @@ -0,0 +1,173 @@ +#![allow(dead_code)] + +use std::env; +use std::ffi::{OsStr, OsString}; +use std::fs::{self, File}; +use std::io; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; + +use cc; +use tempfile::{Builder, TempDir}; + +pub struct Test { + pub td: TempDir, + pub gcc: PathBuf, + pub msvc: bool, +} + +pub struct Execution { + args: Vec, +} + +impl Test { + pub fn new() -> Test { + // This is ugly: `sccache` needs to introspect the compiler it is + // executing, as it adjusts its behavior depending on the + // language/compiler. This crate's test driver uses mock compilers that + // are obviously not supported by sccache, so the tests fail if + // RUSTC_WRAPPER is set. rust doesn't build test dependencies with + // the `test` feature enabled, so we can't conditionally disable the + // usage of `sccache` if running in a test environment, at least not + // without setting an environment variable here and testing for it + // there. Explicitly deasserting RUSTC_WRAPPER here seems to be the + // lesser of the two evils. + env::remove_var("RUSTC_WRAPPER"); + + let mut gcc = PathBuf::from(env::current_exe().unwrap()); + gcc.pop(); + if gcc.ends_with("deps") { + gcc.pop(); + } + let td = Builder::new().prefix("gcc-test").tempdir_in(&gcc).unwrap(); + gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX)); + Test { + td: td, + gcc: gcc, + msvc: false, + } + } + + pub fn gnu() -> Test { + let t = Test::new(); + t.shim("cc").shim("c++").shim("ar"); + t + } + + pub fn msvc() -> Test { + let mut t = Test::new(); + t.shim("cl").shim("lib.exe"); + t.msvc = true; + t + } + + pub fn shim(&self, name: &str) -> &Test { + link_or_copy( + &self.gcc, + self.td + .path() + .join(&format!("{}{}", name, env::consts::EXE_SUFFIX)), + ) + .unwrap(); + self + } + + pub fn gcc(&self) -> cc::Build { + let mut cfg = cc::Build::new(); + let target = if self.msvc { + "x86_64-pc-windows-msvc" + } else { + "x86_64-unknown-linux-gnu" + }; + + cfg.target(target) + .host(target) + .opt_level(2) + .debug(false) + .out_dir(self.td.path()) + .__set_env("PATH", self.path()) + .__set_env("GCCTEST_OUT_DIR", self.td.path()); + if self.msvc { + cfg.compiler(self.td.path().join("cl")); + cfg.archiver(self.td.path().join("lib.exe")); + } + cfg + } + + fn path(&self) -> OsString { + let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::>(); + path.insert(0, self.td.path().to_owned()); + env::join_paths(path).unwrap() + } + + pub fn cmd(&self, i: u32) -> Execution { + let mut s = String::new(); + File::open(self.td.path().join(format!("out{}", i))) + .unwrap() + .read_to_string(&mut s) + .unwrap(); + Execution { + args: s.lines().map(|s| s.to_string()).collect(), + } + } +} + +impl Execution { + pub fn must_have>(&self, p: P) -> &Execution { + if !self.has(p.as_ref()) { + panic!("didn't find {:?} in {:?}", p.as_ref(), self.args); + } else { + self + } + } + + pub fn must_not_have>(&self, p: P) -> &Execution { + if self.has(p.as_ref()) { + panic!("found {:?}", p.as_ref()); + } else { + self + } + } + + pub fn has(&self, p: &OsStr) -> bool { + self.args.iter().any(|arg| OsStr::new(arg) == p) + } + + pub fn must_have_in_order(&self, before: &str, after: &str) -> &Execution { + let before_position = self + .args + .iter() + .rposition(|x| OsStr::new(x) == OsStr::new(before)); + let after_position = self + .args + .iter() + .rposition(|x| OsStr::new(x) == OsStr::new(after)); + match (before_position, after_position) { + (Some(b), Some(a)) if b < a => {} + (b, a) => panic!( + "{:?} (last position: {:?}) did not appear before {:?} (last position: {:?})", + before, b, after, a + ), + }; + self + } +} + +/// Hard link an executable or copy it if that fails. +/// +/// We first try to hard link an executable to save space. If that fails (as on Windows with +/// different mount points, issue #60), we copy. +#[cfg(not(target_os = "macos"))] +fn link_or_copy, Q: AsRef>(from: P, to: Q) -> io::Result<()> { + let from = from.as_ref(); + let to = to.as_ref(); + fs::hard_link(from, to).or_else(|_| fs::copy(from, to).map(|_| ())) +} + +/// Copy an executable. +/// +/// On macOS, hard linking the executable leads to strange failures (issue #419), so we just copy. +#[cfg(target_os = "macos")] +fn link_or_copy, Q: AsRef>(from: P, to: Q) -> io::Result<()> { + fs::copy(from, to).map(|_| ()) +} diff --git a/vendor/cc-1.0.59/tests/test.rs b/vendor/cc-1.0.59/tests/test.rs new file mode 100644 index 0000000000..3c9b4dc498 --- /dev/null +++ b/vendor/cc-1.0.59/tests/test.rs @@ -0,0 +1,413 @@ +use crate::support::Test; + +mod support; + +// Some tests check that a flag is *not* present. These tests might fail if the flag is set in the +// CFLAGS or CXXFLAGS environment variables. This function clears the CFLAGS and CXXFLAGS +// variables to make sure that the tests can run correctly. +fn reset_env() { + std::env::set_var("CFLAGS", ""); + std::env::set_var("CXXFLAGS", ""); +} + +#[test] +fn gnu_smoke() { + reset_env(); + + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-O2") + .must_have("foo.c") + .must_not_have("-g") + .must_have("-c") + .must_have("-ffunction-sections") + .must_have("-fdata-sections"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn gnu_opt_level_1() { + reset_env(); + + let test = Test::gnu(); + test.gcc().opt_level(1).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-O1").must_not_have("-O2"); +} + +#[test] +fn gnu_opt_level_s() { + reset_env(); + + let test = Test::gnu(); + test.gcc().opt_level_str("s").file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-Os") + .must_not_have("-O1") + .must_not_have("-O2") + .must_not_have("-O3") + .must_not_have("-Oz"); +} + +#[test] +fn gnu_debug_fp_auto() { + let test = Test::gnu(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-g"); + test.cmd(0).must_have("-fno-omit-frame-pointer"); +} + +#[test] +fn gnu_debug_fp() { + let test = Test::gnu(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-g"); + test.cmd(0).must_have("-fno-omit-frame-pointer"); +} + +#[test] +fn gnu_debug_nofp() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .debug(true) + .force_frame_pointer(false) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-g"); + test.cmd(0).must_not_have("-fno-omit-frame-pointer"); + + let test = Test::gnu(); + test.gcc() + .force_frame_pointer(false) + .debug(true) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-g"); + test.cmd(0).must_not_have("-fno-omit-frame-pointer"); +} + +#[test] +fn gnu_warnings_into_errors() { + let test = Test::gnu(); + test.gcc() + .warnings_into_errors(true) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Werror"); +} + +#[test] +fn gnu_warnings() { + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Wall").must_have("-Wextra"); +} + +#[test] +fn gnu_extra_warnings0() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .warnings(true) + .extra_warnings(false) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Wall").must_not_have("-Wextra"); +} + +#[test] +fn gnu_extra_warnings1() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .warnings(false) + .extra_warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_have("-Wextra"); +} + +#[test] +fn gnu_warnings_overridable() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have_in_order("-Wall", "-Wno-missing-field-initializers"); +} + +#[test] +fn gnu_x86_64() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-fPIC").must_have("-m64"); + } +} + +#[test] +fn gnu_x86_64_no_pic() { + reset_env(); + + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(false) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-fPIC"); + } +} + +#[test] +fn gnu_i686() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-m32"); + } +} + +#[test] +fn gnu_i686_pic() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(true) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-fPIC"); + } +} + +#[test] +fn gnu_x86_64_no_plt() { + let target = "x86_64-unknown-linux-gnu"; + let test = Test::gnu(); + test.gcc() + .pic(true) + .use_plt(false) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-fno-plt"); +} + +#[test] +fn gnu_set_stdlib() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .cpp_set_stdlib(Some("foo")) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-stdlib=foo"); +} + +#[test] +fn gnu_include() { + let test = Test::gnu(); + test.gcc().include("foo/bar").file("foo.c").compile("foo"); + + test.cmd(0).must_have("-I").must_have("foo/bar"); +} + +#[test] +fn gnu_define() { + let test = Test::gnu(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); +} + +#[test] +fn gnu_compile_assembly() { + let test = Test::gnu(); + test.gcc().file("foo.S").compile("foo"); + test.cmd(0).must_have("foo.S"); +} + +#[test] +fn gnu_shared() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(true) + .static_flag(false) + .compile("foo"); + + test.cmd(0).must_have("-shared").must_not_have("-static"); +} + +#[test] +fn gnu_flag_if_supported() { + reset_env(); + + if cfg!(windows) { + return; + } + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .flag("-v") + .flag_if_supported("-Wall") + .flag_if_supported("-Wflag-does-not-exist") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0) + .must_have("-v") + .must_have("-Wall") + .must_not_have("-Wflag-does-not-exist") + .must_not_have("-std=c++11"); +} + +#[test] +fn gnu_flag_if_supported_cpp() { + if cfg!(windows) { + return; + } + let test = Test::gnu(); + test.gcc() + .cpp(true) + .file("foo.cpp") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0).must_have("-std=c++11"); +} + +#[test] +fn gnu_static() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(false) + .static_flag(true) + .compile("foo"); + + test.cmd(0).must_have("-static").must_not_have("-shared"); +} + +#[test] +fn msvc_smoke() { + reset_env(); + + let test = Test::msvc(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-O2") + .must_have("foo.c") + .must_not_have("-Z7") + .must_have("-c") + .must_have("-MD"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn msvc_opt_level_0() { + reset_env(); + + let test = Test::msvc(); + test.gcc().opt_level(0).file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("-O2"); +} + +#[test] +fn msvc_debug() { + let test = Test::msvc(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-Z7"); +} + +#[test] +fn msvc_include() { + let test = Test::msvc(); + test.gcc().include("foo/bar").file("foo.c").compile("foo"); + + test.cmd(0).must_have("-I").must_have("foo/bar"); +} + +#[test] +fn msvc_define() { + let test = Test::msvc(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); +} + +#[test] +fn msvc_static_crt() { + let test = Test::msvc(); + test.gcc().static_crt(true).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-MT"); +} + +#[test] +fn msvc_no_static_crt() { + let test = Test::msvc(); + test.gcc().static_crt(false).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-MD"); +} diff --git a/vendor/cc/.cargo-checksum.json b/vendor/cc/.cargo-checksum.json index a9252fa545..6b12277a4b 100644 --- a/vendor/cc/.cargo-checksum.json +++ b/vendor/cc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"bd34a585a35969291c78b96b1f239fa09f1f9dbeee48474989695def1ed64052","Cargo.toml":"cb73923110f764c2a6da0fde98db8f5f7c7194bd56e96e2f302da9ba29cba0a8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"68fe1bc9f8aab4d8d195e8bc39fe76562742dc392f5c490e5404e01463100277","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"96f4782c70e0bd8d9ab7ce3efcc2091d2591c3276c0ed672e2379748bb3930aa","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"52afe8554f577c87841c48ddee3ba7ffe70a00129e1d6eeb2ec0efb3d2b9aa11","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"} \ No newline at end of file +{"files":{"Cargo.lock":"30b9e23f97015aea3eed3e17c6d76d565c2924efec8bdae64c899080847afe89","Cargo.toml":"f6f22b69df3df57c58373cdee72b22218ffa030bc375b36632660037dd72c866","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"51405d284d2e0620db62c655c652fc0ec84f20c1cb30529227355c9575a9e6dd","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"903c5f2f5dd0cc7d04f99f605a95e6abde8b38156fd4e73eefc58493f55a4e5a","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"52afe8554f577c87841c48ddee3ba7ffe70a00129e1d6eeb2ec0efb3d2b9aa11","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"} \ No newline at end of file diff --git a/vendor/cc/Cargo.lock b/vendor/cc/Cargo.lock index a624f35455..f48ad9b92f 100644 --- a/vendor/cc/Cargo.lock +++ b/vendor/cc/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "cc" -version = "1.0.59" +version = "1.0.60" dependencies = [ "jobserver", "tempfile", @@ -16,9 +16,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", @@ -36,15 +36,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "rand" diff --git a/vendor/cc/Cargo.toml b/vendor/cc/Cargo.toml index 2b3aac577f..a198b2fdee 100644 --- a/vendor/cc/Cargo.toml +++ b/vendor/cc/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "cc" -version = "1.0.59" +version = "1.0.60" authors = ["Alex Crichton "] exclude = ["/.travis.yml", "/appveyor.yml"] description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n" diff --git a/vendor/cc/README.md b/vendor/cc/README.md index e147d7e177..c792132af0 100644 --- a/vendor/cc/README.md +++ b/vendor/cc/README.md @@ -8,9 +8,6 @@ A simple library meant to be used as a build dependency with Cargo packages in order to build a set of C/C++ files into a static archive. This crate calls out to the most relevant compiler for a platform, for example using `cl` on MSVC. -> **Note**: this crate was recently renamed from the `gcc` crate, so if you're -> looking for the `gcc` crate you're in the right spot! - ## Using cc-rs First, you'll want to both add a build script for your crate (`build.rs`) and diff --git a/vendor/cc/src/lib.rs b/vendor/cc/src/lib.rs index fecc073056..aff6be86a9 100644 --- a/vendor/cc/src/lib.rs +++ b/vendor/cc/src/lib.rs @@ -1423,7 +1423,16 @@ impl Build { if !(target.contains("android") && android_clang_compiler_uses_target_arg_internally(&cmd.path)) { - cmd.args.push(format!("--target={}", target).into()); + if target.contains("darwin") { + if let Some(arch) = + map_darwin_target_from_rust_to_compiler_architecture(target) + { + cmd.args + .push(format!("--target={}-apple-darwin", arch).into()); + } + } else { + cmd.args.push(format!("--target={}", target).into()); + } } } ToolFamily::Msvc { clang_cl } => { @@ -1471,15 +1480,10 @@ impl Build { } if target.contains("darwin") { - if target.contains("x86_64") { - cmd.args.push("-arch".into()); - cmd.args.push("x86_64".into()); - } else if target.contains("arm64e") { - cmd.args.push("-arch".into()); - cmd.args.push("arm64e".into()); - } else if target.contains("aarch64") { + if let Some(arch) = map_darwin_target_from_rust_to_compiler_architecture(target) + { cmd.args.push("-arch".into()); - cmd.args.push("arm64".into()); + cmd.args.push(arch.into()); } } @@ -2002,7 +2006,11 @@ impl Build { { "clang".to_string() } else if target.contains("vxworks") { - "wr-c++".to_string() + if self.cpp { + "wr-c++".to_string() + } else { + "wr-cc".to_string() + } } else if self.get_host()? != target { let prefix = self.prefix_for_target(&target); match prefix { @@ -2958,3 +2966,16 @@ fn autodetect_android_compiler(target: &str, host: &str, gnu: &str, clang: &str) clang_compiler } } + +// Rust and clang/cc don't agree on how to name the target. +fn map_darwin_target_from_rust_to_compiler_architecture(target: &str) -> Option<&'static str> { + if target.contains("x86_64") { + Some("x86_64") + } else if target.contains("arm64e") { + Some("arm64e") + } else if target.contains("aarch64") { + Some("arm64") + } else { + None + } +} diff --git a/vendor/chalk-derive-0.14.0/.cargo-checksum.json b/vendor/chalk-derive-0.14.0/.cargo-checksum.json deleted file mode 100644 index fa6df7fe6b..0000000000 --- a/vendor/chalk-derive-0.14.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"5afc28841a188f45dab6b221c873c9e32f6292cb68b84585a2552c83761c1542","README.md":"41a362e6750d37202fcf0a87a0b48ae41552715d97d740ee9883424ebae78564","src/lib.rs":"fea6545836f3b1c61cea44bba2b9c85c81fc85e310615d4f148466a12197e68c"},"package":"d463e01905d607e181de72e8608721d3269f29176c9a14ce037011316ae7131d"} \ No newline at end of file diff --git a/vendor/chalk-derive-0.25.0/.cargo-checksum.json b/vendor/chalk-derive-0.25.0/.cargo-checksum.json new file mode 100644 index 0000000000..105ed5c0da --- /dev/null +++ b/vendor/chalk-derive-0.25.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"b9d70df3e3d8b2b593772a42e2997e2e8e4a04ecdb87ae6f6bce09246cc89497","README.md":"41a362e6750d37202fcf0a87a0b48ae41552715d97d740ee9883424ebae78564","src/lib.rs":"fea6545836f3b1c61cea44bba2b9c85c81fc85e310615d4f148466a12197e68c"},"package":"624e14d3f029186e6ffd97081ffa082f98ddd5df20655b6f0e8efb83dd8ac8b4"} \ No newline at end of file diff --git a/vendor/chalk-derive-0.14.0/Cargo.toml b/vendor/chalk-derive-0.25.0/Cargo.toml similarity index 98% rename from vendor/chalk-derive-0.14.0/Cargo.toml rename to vendor/chalk-derive-0.25.0/Cargo.toml index 2ca4f319d7..af9654d259 100644 --- a/vendor/chalk-derive-0.14.0/Cargo.toml +++ b/vendor/chalk-derive-0.25.0/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-derive" -version = "0.14.0" +version = "0.25.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "A helper crate for use by chalk crates for `derive` macros." readme = "README.md" diff --git a/vendor/chalk-derive-0.14.0/README.md b/vendor/chalk-derive-0.25.0/README.md similarity index 100% rename from vendor/chalk-derive-0.14.0/README.md rename to vendor/chalk-derive-0.25.0/README.md diff --git a/vendor/chalk-derive-0.14.0/src/lib.rs b/vendor/chalk-derive-0.25.0/src/lib.rs similarity index 100% rename from vendor/chalk-derive-0.14.0/src/lib.rs rename to vendor/chalk-derive-0.25.0/src/lib.rs diff --git a/vendor/chalk-derive/.cargo-checksum.json b/vendor/chalk-derive/.cargo-checksum.json index 6657399932..0a2e24c003 100644 --- a/vendor/chalk-derive/.cargo-checksum.json +++ b/vendor/chalk-derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"89cff317fa4dbf470456d226db4e76a146490cf0bcdbb250d62f7cad58561710","README.md":"41a362e6750d37202fcf0a87a0b48ae41552715d97d740ee9883424ebae78564","src/lib.rs":"fea6545836f3b1c61cea44bba2b9c85c81fc85e310615d4f148466a12197e68c"},"package":"c3cb438e961fd7f1183dc5e0bdcfd09253bf9b90592cf665d1ce6787d8a4908f"} \ No newline at end of file +{"files":{"Cargo.toml":"00ef8d136fcbf3b4a9ff2348994d1bf5fb991067ef00fe447b8dc17ba71b13ec","README.md":"41a362e6750d37202fcf0a87a0b48ae41552715d97d740ee9883424ebae78564","src/lib.rs":"fea6545836f3b1c61cea44bba2b9c85c81fc85e310615d4f148466a12197e68c"},"package":"3a7f257e3bcdc56d8877ae31c012bd69fba0be66929d588e603905f2632c0c59"} \ No newline at end of file diff --git a/vendor/chalk-derive/Cargo.toml b/vendor/chalk-derive/Cargo.toml index 90ab38b870..6f6b1902c7 100644 --- a/vendor/chalk-derive/Cargo.toml +++ b/vendor/chalk-derive/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-derive" -version = "0.23.0" +version = "0.29.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "A helper crate for use by chalk crates for `derive` macros." readme = "README.md" diff --git a/vendor/chalk-engine/.cargo-checksum.json b/vendor/chalk-engine/.cargo-checksum.json index ce5202e5d6..71a6151fe6 100644 --- a/vendor/chalk-engine/.cargo-checksum.json +++ b/vendor/chalk-engine/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"0b93b1a262052bb3da1c77b89966bed3a6d67f62ce694e9a0c991ca2ac2cc757","README.md":"d8d9a21a6700b554e110030288fb94ca98fa6c6398fa6a5a1dafa52b3f7dd545","src/README.md":"6606b446db6a271e99f1019cd6e59a44af50e7b1ee995718d30fde11c09bbc80","src/context.rs":"e9c9485eacd80f44a16e9d23c8290b09e8a35ca20ff15d97786b7d853ed98693","src/derived.rs":"a59fe981325e664865bf21407e4a24e317b00cc2545b380d1140b4fddc86ede3","src/forest.rs":"a3fd27964be8465932ec4de4bb4cf991faf0df927fe0c960941eaeff1434deb3","src/lib.rs":"15367f2f3e0af018fb6aa8fab3715aea599a0f340aa98dd638f8e9f04b249140","src/logic.rs":"68ac57c93b163d86d7d27f45fdadc155effe512155c489dd60c97d4ed5d37e15","src/simplify.rs":"9e595790550c6e8d26dcfdfe3a041908cb8c059c28f51c0aeb5e672071151e6b","src/stack.rs":"aff571cc6e7383dd4d7365d9fb19b5f9c1e91106de74f47fbaf6fd07af03b466","src/strand.rs":"03f70b15c17452dab3604819edf6ebae94d373ab47e2bfa32d8bbff706a70101","src/table.rs":"fd6751107314b836dc8738df025fb7a6f40d93fd18effc9fdf61dd055194c01c","src/tables.rs":"8c0e31d1d16120580e214a84c3d1a841462a50903a0da509a9c68c35b00cd642"},"package":"efaf428f5398d36284f79690cf988762b7c091249f50a6c11db613a46c057000"} \ No newline at end of file +{"files":{"Cargo.toml":"db8f2d350c608a2a4f781754d506f040a884240b6f506051f4a446dbc33b7ea4","README.md":"d8d9a21a6700b554e110030288fb94ca98fa6c6398fa6a5a1dafa52b3f7dd545","src/README.md":"6606b446db6a271e99f1019cd6e59a44af50e7b1ee995718d30fde11c09bbc80","src/context.rs":"e9c9485eacd80f44a16e9d23c8290b09e8a35ca20ff15d97786b7d853ed98693","src/derived.rs":"a59fe981325e664865bf21407e4a24e317b00cc2545b380d1140b4fddc86ede3","src/forest.rs":"af603f739e0921dc5520f2ddaa0606c5e7901f918826cfecbb34b9d5fe90d090","src/lib.rs":"a23eb51a4a9854f550700e66e1c8035fec59cbedd2a15a7e35a5e8e60a99f369","src/logic.rs":"96b55c0b85b4568fa1211047187bae7ac33e448e6375cc4c340493288ca81435","src/normalize_deep.rs":"c95cdd01aba4a0dd000b7cb765f1668bcc874199342274a3fb12f65e3dbb827c","src/simplify.rs":"8d1d0691897f9823c61037aadfaaf39538d770c410470bb11402fca33b0303d9","src/slg.rs":"5d162d8934b512a336fe7fc4f6f9927cfb6caba74e473395a667d7131741845d","src/slg/aggregate.rs":"cc11aa6a0ef4dc1f3894fafb3f0d8cb157f168c0d0d811e10e9b3d6cb6afc9ff","src/slg/resolvent.rs":"3132d66fd6a7139f7e1ffa276626fde1f6010c7e00fb0bc1b978dca3feb2cc78","src/solve.rs":"7ab67699c8d70ca60aded258c37b98f06004b2ad63a702af8af6114a46d578d5","src/stack.rs":"3c872d5ccc5f86184b936b1faff927c8cfe57ea068a1d8d9e9946bb6a0c5fa26","src/strand.rs":"03f70b15c17452dab3604819edf6ebae94d373ab47e2bfa32d8bbff706a70101","src/table.rs":"57debdcd6ec49a68122fdcb2ba6f704e82307074bda9ac82a509892b6d778927","src/tables.rs":"c140ea3b7ada35c097f578dc81873164c2c36f41adfb5f7d0d71cd9978974a23"},"package":"c43fcc7edf4d51b42f44ed50e2337bd90ddc8e088d0cd78a71db92a6f780f782"} \ No newline at end of file diff --git a/vendor/chalk-engine/Cargo.toml b/vendor/chalk-engine/Cargo.toml index 792947dfcf..dce8801d95 100644 --- a/vendor/chalk-engine/Cargo.toml +++ b/vendor/chalk-engine/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-engine" -version = "0.14.0" +version = "0.29.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Core trait engine from Chalk project" readme = "README.md" @@ -21,10 +21,13 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.14.0" +version = "=0.29.0" [dependencies.chalk-ir] -version = "=0.14.0" +version = "=0.29.0" + +[dependencies.chalk-solve] +version = "=0.29.0" [dependencies.rustc-hash] version = "1.1.0" @@ -32,5 +35,7 @@ version = "1.1.0" [dependencies.tracing] version = "0.1" +[dev-dependencies] + [features] default = [] diff --git a/vendor/chalk-engine/src/forest.rs b/vendor/chalk-engine/src/forest.rs index 2a45067957..2a6a309393 100644 --- a/vendor/chalk-engine/src/forest.rs +++ b/vendor/chalk-engine/src/forest.rs @@ -8,7 +8,7 @@ use chalk_ir::interner::Interner; use chalk_ir::{Goal, InEnvironment, Substitution, UCanonical}; use tracing::debug; -pub struct Forest> { +pub(crate) struct Forest> { pub(crate) tables: Tables, /// This is a clock which always increases. It is @@ -76,7 +76,7 @@ impl<'me, I: Interner, C: Context, CO: ContextOps> AnswerStream .root_answer(self.context, self.table, self.answer) { Ok(answer) => { - debug!("Answer: {:?}", &answer); + debug!(answer = ?(&answer)); return AnswerResult::Answer(answer); } diff --git a/vendor/chalk-engine/src/lib.rs b/vendor/chalk-engine/src/lib.rs index 0a958a3933..369de54fe9 100644 --- a/vendor/chalk-engine/src/lib.rs +++ b/vendor/chalk-engine/src/lib.rs @@ -68,7 +68,10 @@ pub mod context; mod derived; pub mod forest; mod logic; +mod normalize_deep; mod simplify; +pub mod slg; +pub mod solve; mod stack; mod strand; mod table; diff --git a/vendor/chalk-engine/src/logic.rs b/vendor/chalk-engine/src/logic.rs index 931b642c71..de17def483 100644 --- a/vendor/chalk-engine/src/logic.rs +++ b/vendor/chalk-engine/src/logic.rs @@ -12,8 +12,8 @@ use crate::{ use chalk_ir::interner::Interner; use chalk_ir::{ - Canonical, ConstrainedSubst, DomainGoal, Floundered, Goal, GoalData, InEnvironment, NoSolution, - Substitution, UCanonical, UniverseMap, WhereClause, + Canonical, ConstrainedSubst, Floundered, Goal, GoalData, InEnvironment, NoSolution, + Substitution, UCanonical, UniverseMap, }; use tracing::{debug, debug_span, info, instrument}; @@ -196,8 +196,7 @@ impl> Forest { } }; - debug!("ucanonical_subgoal={:?}", ucanonical_subgoal); - debug!("universe_map={:?}", universe_map); + debug!(?ucanonical_subgoal, ?universe_map); let table = self.get_or_create_table_for_ucanonical_goal(context, ucanonical_subgoal); @@ -218,14 +217,14 @@ impl> Forest { goal: UCanonical>>, ) -> TableIndex { if let Some(table) = self.tables.index_of(&goal) { - debug!("found existing table {:?}", table); + debug!(?table, "found existing table"); return table; } info!( - "creating new table {:?} and goal {:#?}", - self.tables.next_index(), - goal + table = ?self.tables.next_index(), + "creating new table with goal = {:#?}", + goal, ); let table = Self::build_table(context, self.tables.next_index(), goal); self.tables.insert(table) @@ -251,16 +250,8 @@ impl> Forest { let (mut infer, subst, environment, goal) = context.instantiate_ucanonical_goal(&goal); let goal_data = goal.data(context.interner()); - let is_outlives_goal = |dg: &DomainGoal| { - if let DomainGoal::Holds(WhereClause::LifetimeOutlives(_)) = dg { - true - } else { - false - } - }; - match goal_data { - GoalData::DomainGoal(domain_goal) if !is_outlives_goal(domain_goal) => { + GoalData::DomainGoal(domain_goal) => { match context.program_clauses(&environment, &domain_goal, &mut infer) { Ok(clauses) => { for clause in clauses { @@ -287,6 +278,7 @@ impl> Forest { } Err(Floundered) => { debug!( + table = ?table_idx, "Marking table {:?} as floundered! (failed to create program clauses)", table_idx ); @@ -308,8 +300,8 @@ impl> Forest { Self::simplify_goal(context, &mut infer, subst, environment, goal) { info!( - "pushing initial strand with ex-clause: {:#?}", - infer.debug_ex_clause(context.interner(), &ex_clause), + ex_clause = ?infer.debug_ex_clause(context.interner(), &ex_clause), + "pushing initial strand" ); let strand = Strand { infer, @@ -464,8 +456,6 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore self.stack .push(initial_table, Minimums::MAX, self.forest.increment_clock()); loop { - // FIXME: use depth for debug/info printing - let clock = self.stack.top().clock; // If we had an active strand, continue to pursue it let table = self.stack.top().table; @@ -500,18 +490,17 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore } = canonical_strand; let (infer, ex_clause) = context.instantiate_ex_clause(num_universes, &canonical_ex_clause); - let strand = Strand { + Strand { infer, ex_clause, - selected_subgoal: selected_subgoal.clone(), + selected_subgoal, last_pursued_time, - }; - strand + } }) }); match next_strand { Some(mut strand) => { - debug!("next strand: {:#?}", strand); + debug!("starting next strand = {:#?}", strand); strand.last_pursued_time = clock; match self.select_subgoal(&mut strand) { @@ -606,7 +595,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore infer: strand.infer.clone(), ex_clause: strand.ex_clause.clone(), selected_subgoal: Some(next_subgoal), - last_pursued_time: strand.last_pursued_time.clone(), + last_pursued_time: strand.last_pursued_time, }; let table = self.stack.top().table; let canonical_next_strand = Forest::canonicalize_strand(self.context, next_strand); @@ -723,7 +712,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // We want to disproval the subgoal, but we // have an unconditional answer for the subgoal, // therefore we have failed to disprove it. - debug!("Marking Strand as ambiguous because answer to (negative) subgoal was ambiguous"); + debug!(?strand, "Marking Strand as ambiguous because answer to (negative) subgoal was ambiguous"); strand.ex_clause.ambiguous = true; // Strand is ambigious. @@ -757,7 +746,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // and maybe come back to it. self.flounder_subgoal(&mut strand.ex_clause, selected_subgoal.subgoal_index); - return false; + false } Literal::Negative(_) => { // Floundering on a negative literal isn't like a @@ -779,7 +768,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // This strand has no solution. It is no longer active, // so it dropped at the end of this scope. - return true; + true } } } @@ -811,7 +800,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore strand.ex_clause.delayed_subgoals.push(subgoal); self.stack.top().active_strand = Some(strand); - return Ok(()); + Ok(()) } Literal::Negative(_) => { // We don't allow coinduction for negative literals @@ -887,7 +876,9 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore } = *strand.selected_subgoal.as_ref().unwrap(); debug!( - "table selection {:?} with goal: {:#?}", + ?subgoal_table, + goal = ?self.forest.tables[subgoal_table].table_goal, + "table selection {:?} with goal: {:?}", subgoal_table, self.forest.tables[subgoal_table].table_goal ); @@ -902,12 +893,12 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // We need to check if we can merge it into the current `Strand`. match self.merge_answer_into_strand(&mut strand) { Err(e) => { - debug!("could not merge into current strand"); + debug!(?strand, "could not merge into current strand"); drop(strand); return Err(e); } Ok(_) => { - debug!("merged answer into current strand"); + debug!(?strand, "merged answer into current strand"); self.stack.top().active_strand = Some(strand); return Ok(()); } @@ -967,7 +958,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore return NoRemainingSubgoalsResult::RootSearchFail(RootSearchFail::QuantumExceeded); } } - let floundered = strand.ex_clause.floundered_subgoals.len() > 0; + let floundered = !strand.ex_clause.floundered_subgoals.is_empty(); if floundered { debug!("all remaining subgoals floundered for the table"); } else { @@ -984,7 +975,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore match self.stack.pop_and_take_caller_strand() { Some(caller_strand) => { self.stack.top().active_strand = Some(caller_strand); - return NoRemainingSubgoalsResult::Success; + NoRemainingSubgoalsResult::Success } None => { // That was the root table, so we are done -- @@ -1003,9 +994,9 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore self.forest.tables[table].enqueue_strand(strand); } - return NoRemainingSubgoalsResult::RootAnswerAvailable; + NoRemainingSubgoalsResult::RootAnswerAvailable } - }; + } } None => { debug!("answer is not available (or not new)"); @@ -1016,9 +1007,9 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // Now we yield with `QuantumExceeded` self.unwind_stack(); - return NoRemainingSubgoalsResult::RootSearchFail(RootSearchFail::QuantumExceeded); + NoRemainingSubgoalsResult::RootSearchFail(RootSearchFail::QuantumExceeded) } - }; + } } /// A "refinement" strand is used in coinduction. When the root @@ -1074,13 +1065,13 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore } fn on_no_strands_left(&mut self) -> Result<(), RootSearchFail> { - debug!("no more strands available (or all cycles)"); + let table = self.stack.top().table; + debug!("no more strands available (or all cycles) for {:?}", table); // No more strands left to try! This is either because all // strands have failed, because all strands encountered a // cycle, or all strands have would give ambiguous answers. - let table = self.stack.top().table; if self.forest.tables[table].strands_mut().count() == 0 { // All strands for the table T on the top of the stack // have **failed**. Hence we can pop it off the stack and @@ -1127,36 +1118,12 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore }; } - let num_universes = self.forest.tables[table].table_goal.universes; - let table_answer_mode = self.forest.tables[table].answer_mode; - let forest = &mut self.forest; - let context = &self.context; - let strand_is_participating = |strand: &CanonicalStrand| { - let (_, ex_clause) = - context.instantiate_ex_clause(num_universes, &strand.canonical_ex_clause); - match (table_answer_mode, ex_clause.ambiguous) { - (AnswerMode::Complete, true) => false, - (AnswerMode::Complete, false) => true, - (AnswerMode::Ambiguous, _) => true, - } - }; - if forest.tables[table] - .strands_mut() - .all(|s| !strand_is_participating(s)) - { - // If no strands are participating, then that means they are all - // ambiguous and we are in complete mode. - debug!("All strands would return ambiguous answers."); - match self.forest.tables[table].answer_mode { - AnswerMode::Complete => { - debug!("Allowing ambiguous answers."); - self.forest.tables[table].answer_mode = AnswerMode::Ambiguous; - return Err(RootSearchFail::QuantumExceeded); - } - AnswerMode::Ambiguous => { - unreachable!(); - } - } + // We can't consider this table as part of a cycle unless we've handled + // all strands, not just non-ambiguous ones. See chalk#571. + if let AnswerMode::Complete = self.forest.tables[table].answer_mode { + debug!("Allowing ambiguous answers."); + self.forest.tables[table].answer_mode = AnswerMode::Ambiguous; + return Err(RootSearchFail::QuantumExceeded); } let clock = self.stack.top().clock; @@ -1175,9 +1142,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // then no more answers are forthcoming. We can clear all // the strands for those things recursively. let table = self.stack.top().table; - // N.B. If we try to pursue a strand and it's found to be ambiguous, - // we know that isn't part of a cycle. - let cyclic_strands = self.forest.tables[table].drain_strands(strand_is_participating); + let cyclic_strands = self.forest.tables[table].take_strands(); self.clear_strands_after_cycle(cyclic_strands); // Now we yield with `QuantumExceeded` @@ -1418,10 +1383,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore constraints, filtered_delayed_subgoals, ); - debug!( - "answer: table={:?}, subst={:?}, floundered={:?}", - table, subst, floundered - ); + debug!(?table, ?subst, ?floundered, "found answer"); let answer = Answer { subst, ambiguous }; @@ -1486,7 +1448,11 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore let is_trivial_answer = { self.context .is_trivial_substitution(&self.forest.tables[table].table_goal, &answer.subst) - && answer.subst.value.constraints.is_empty() + && answer + .subst + .value + .constraints + .is_empty(self.context.interner()) }; if let Some(answer_index) = self.forest.tables[table].push_answer(answer) { @@ -1536,7 +1502,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore floundered_literal, floundered_time, }); - debug!("flounder_subgoal: ex_clause={:#?}", ex_clause); + debug!(?ex_clause); } /// True if all the tables on the stack starting from `depth` and diff --git a/vendor/chalk-solve-0.14.0/src/infer/normalize_deep.rs b/vendor/chalk-engine/src/normalize_deep.rs similarity index 66% rename from vendor/chalk-solve-0.14.0/src/infer/normalize_deep.rs rename to vendor/chalk-engine/src/normalize_deep.rs index 4491929057..6e37d6f7b7 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/normalize_deep.rs +++ b/vendor/chalk-engine/src/normalize_deep.rs @@ -2,10 +2,14 @@ use chalk_ir::fold::shift::Shift; use chalk_ir::fold::{Fold, Folder}; use chalk_ir::interner::Interner; use chalk_ir::*; +use chalk_solve::infer::InferenceTable; -use super::InferenceTable; +pub(crate) struct DeepNormalizer<'table, 'i, I: Interner> { + table: &'table mut InferenceTable, + interner: &'i I, +} -impl InferenceTable { +impl DeepNormalizer<'_, '_, I> { /// Given a value `value` with variables in it, replaces those variables /// with their instantiated values (if any). Uninstantiated variables are /// left as-is. @@ -17,24 +21,20 @@ impl InferenceTable { /// See also `InferenceTable::canonicalize`, which -- during real /// processing -- is often used to capture the "current state" of /// variables. - pub(crate) fn normalize_deep>(&mut self, interner: &I, value: &T) -> T::Result { + pub fn normalize_deep>( + table: &mut InferenceTable, + interner: &I, + value: &T, + ) -> T::Result { value .fold_with( - &mut DeepNormalizer { - interner, - table: self, - }, + &mut DeepNormalizer { interner, table }, DebruijnIndex::INNERMOST, ) .unwrap() } } -struct DeepNormalizer<'table, 'i, I: Interner> { - table: &'table mut InferenceTable, - interner: &'i I, -} - impl<'i, I: Interner> Folder<'i, I> for DeepNormalizer<'_, 'i, I> where I: 'i, @@ -102,3 +102,35 @@ where self.interner() } } + +#[cfg(test)] +mod test { + use super::*; + use chalk_integration::interner::ChalkIr; + use chalk_integration::{arg, ty, ty_name}; + + const U0: UniverseIndex = UniverseIndex { counter: 0 }; + + #[test] + fn infer() { + let interner = &ChalkIr; + let mut table: InferenceTable = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + let b = table.new_variable(U0).to_ty(interner); + table + .unify(interner, &environment0, &a, &ty!(apply (item 0) (expr b))) + .unwrap(); + assert_eq!( + DeepNormalizer::normalize_deep(&mut table, interner, &a), + ty!(apply (item 0) (expr b)) + ); + table + .unify(interner, &environment0, &b, &ty!(apply (item 1))) + .unwrap(); + assert_eq!( + DeepNormalizer::normalize_deep(&mut table, interner, &a), + ty!(apply (item 0) (apply (item 1))) + ); + } +} diff --git a/vendor/chalk-engine/src/simplify.rs b/vendor/chalk-engine/src/simplify.rs index 9e9c6ed600..a1087eea82 100644 --- a/vendor/chalk-engine/src/simplify.rs +++ b/vendor/chalk-engine/src/simplify.rs @@ -4,8 +4,7 @@ use crate::{ExClause, Literal, TimeStamp}; use chalk_ir::interner::Interner; use chalk_ir::{ - Constraint, DomainGoal, Environment, Fallible, Goal, GoalData, InEnvironment, LifetimeOutlives, - QuantifierKind, Substitution, WhereClause, + Environment, Fallible, Goal, GoalData, InEnvironment, QuantifierKind, Substitution, }; use tracing::debug; @@ -69,23 +68,15 @@ impl> Forest { &goal.b, &mut ex_clause, )?, - GoalData::DomainGoal(domain_goal) => match domain_goal { - DomainGoal::Holds(WhereClause::LifetimeOutlives(LifetimeOutlives { a, b })) => { - ex_clause.constraints.push(InEnvironment::new( + GoalData::DomainGoal(domain_goal) => { + ex_clause + .subgoals + .push(Literal::Positive(InEnvironment::new( &environment, - Constraint::Outlives(a.clone(), b.clone()), - )); - } - _ => { - ex_clause - .subgoals - .push(Literal::Positive(InEnvironment::new( - &environment, - context.into_goal(domain_goal.clone()), - ))); - } - }, - GoalData::CannotProve(()) => { + context.into_goal(domain_goal.clone()), + ))); + } + GoalData::CannotProve => { debug!("Marking Strand as ambiguous because of a `CannotProve` subgoal"); ex_clause.ambiguous = true; } diff --git a/vendor/chalk-solve-0.14.0/src/solve/slg.rs b/vendor/chalk-engine/src/slg.rs similarity index 88% rename from vendor/chalk-solve-0.14.0/src/solve/slg.rs rename to vendor/chalk-engine/src/slg.rs index fbf880ed3a..640f12cc3a 100644 --- a/vendor/chalk-solve-0.14.0/src/solve/slg.rs +++ b/vendor/chalk-engine/src/slg.rs @@ -1,58 +1,26 @@ -use crate::clauses::program_clauses_for_goal; -use crate::coinductive_goal::IsCoinductive; -use crate::infer::ucanonicalize::UCanonicalized; -use crate::infer::unify::UnificationResult; -use crate::infer::InferenceTable; -use crate::solve::truncate; -use crate::RustIrDatabase; +use crate::context; +use crate::normalize_deep::DeepNormalizer; +use crate::{ExClause, Literal}; + use chalk_derive::HasInterner; -use chalk_engine::context; -use chalk_engine::{ExClause, Literal}; use chalk_ir::cast::Cast; use chalk_ir::cast::Caster; use chalk_ir::interner::Interner; use chalk_ir::*; - -use std::fmt::{Debug, Display}; +use chalk_solve::clauses::program_clauses_for_goal; +use chalk_solve::coinductive_goal::IsCoinductive; +use chalk_solve::infer::ucanonicalize::UCanonicalized; +use chalk_solve::infer::unify::UnificationResult; +use chalk_solve::infer::InferenceTable; +use chalk_solve::solve::truncate; +use chalk_solve::RustIrDatabase; + +use std::fmt::Debug; use std::marker::PhantomData; pub(crate) mod aggregate; mod resolvent; -#[derive(Debug)] -pub enum SubstitutionResult { - Definite(S), - Ambiguous(S), - Floundered, -} - -impl SubstitutionResult { - pub fn as_ref(&self) -> SubstitutionResult<&S> { - match self { - SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(subst), - SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(subst), - SubstitutionResult::Floundered => SubstitutionResult::Floundered, - } - } - pub fn map U>(self, f: F) -> SubstitutionResult { - match self { - SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(f(subst)), - SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(f(subst)), - SubstitutionResult::Floundered => SubstitutionResult::Floundered, - } - } -} - -impl Display for SubstitutionResult { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - SubstitutionResult::Definite(subst) => write!(fmt, "{}", subst), - SubstitutionResult::Ambiguous(subst) => write!(fmt, "Ambiguous({})", subst), - SubstitutionResult::Floundered => write!(fmt, "Floundered"), - } - } -} - #[derive(Clone, Debug, HasInterner)] pub(crate) struct SlgContext { phantom: PhantomData, @@ -66,11 +34,11 @@ pub(crate) struct SlgContextOps<'me, I: Interner> { } impl SlgContextOps<'_, I> { - pub(crate) fn new<'p>( - program: &'p dyn RustIrDatabase, + pub(crate) fn new( + program: &dyn RustIrDatabase, max_size: usize, expected_answers: Option, - ) -> SlgContextOps<'p, I> { + ) -> SlgContextOps<'_, I> { SlgContextOps { program, max_size, @@ -111,7 +79,7 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' map: &UniverseMap, value: &Canonical>>, ) -> Canonical>> { - use crate::infer::ucanonicalize::UniverseMapExt; + use chalk_solve::infer::ucanonicalize::UniverseMapExt; map.map_from_canonical(self.program.interner(), value) } @@ -120,7 +88,7 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' map: &UniverseMap, value: &Canonical>, ) -> Canonical> { - use crate::infer::ucanonicalize::UniverseMapExt; + use chalk_solve::infer::ucanonicalize::UniverseMapExt; map.map_from_canonical(self.program.interner(), value) } @@ -130,7 +98,12 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' goal: &DomainGoal, _infer: &mut TruncatingInferenceTable, ) -> Result>, Floundered> { - let clauses: Vec<_> = program_clauses_for_goal(self.program, environment, goal)?; + let clauses: Vec<_> = program_clauses_for_goal( + self.program, + environment, + goal, + &CanonicalVarKinds::empty(self.program.interner()), + )?; Ok(clauses) } @@ -190,7 +163,12 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' }, ) = InferenceTable::from_canonical(self.program.interner(), num_universes, answer); let infer_table = TruncatingInferenceTable::new(self.max_size, infer); - (infer_table, subst, constraints, delayed_subgoals) + ( + infer_table, + subst, + constraints.as_slice(self.interner()).to_vec(), + delayed_subgoals, + ) } fn identity_constrained_subst( @@ -207,7 +185,7 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' self.program.interner(), &ConstrainedSubst { subst, - constraints: vec![], + constraints: Constraints::empty(self.program.interner()), }, ) .quantified @@ -271,7 +249,11 @@ impl context::UnificationOps> for TruncatingInfere } fn debug_ex_clause<'v>(&mut self, interner: &I, value: &'v ExClause) -> Box { - Box::new(self.infer.normalize_deep(interner, value)) + Box::new(DeepNormalizer::normalize_deep( + &mut self.infer, + interner, + value, + )) } fn fully_canonicalize_goal( @@ -302,7 +284,13 @@ impl context::UnificationOps> for TruncatingInfere constraints: Vec>>, ) -> Canonical> { self.infer - .canonicalize(interner, &ConstrainedSubst { subst, constraints }) + .canonicalize( + interner, + &ConstrainedSubst { + subst, + constraints: Constraints::from_iter(interner, constraints), + }, + ) .quantified } @@ -318,7 +306,7 @@ impl context::UnificationOps> for TruncatingInfere interner, &AnswerSubst { subst, - constraints, + constraints: Constraints::from_iter(interner, constraints), delayed_subgoals, }, ) @@ -359,7 +347,6 @@ fn into_ex_clause( .casted(interner) .map(Literal::Positive), ); - ex_clause.constraints.extend(result.constraints); } trait SubstitutionExt { diff --git a/vendor/chalk-solve-0.14.0/src/solve/slg/aggregate.rs b/vendor/chalk-engine/src/slg/aggregate.rs similarity index 86% rename from vendor/chalk-solve-0.14.0/src/solve/slg/aggregate.rs rename to vendor/chalk-engine/src/slg/aggregate.rs index 2018229e12..d2387538cc 100644 --- a/vendor/chalk-solve-0.14.0/src/solve/slg/aggregate.rs +++ b/vendor/chalk-engine/src/slg/aggregate.rs @@ -1,14 +1,14 @@ -use crate::ext::*; -use crate::infer::InferenceTable; -use crate::solve::slg::SlgContextOps; -use crate::solve::slg::SubstitutionExt; -use crate::solve::{Guidance, Solution}; +use crate::context::{self, AnswerResult, ContextOps}; +use crate::slg::SlgContextOps; +use crate::slg::SubstitutionExt; +use crate::CompleteAnswer; use chalk_ir::cast::Cast; use chalk_ir::interner::Interner; use chalk_ir::*; +use chalk_solve::ext::*; +use chalk_solve::infer::InferenceTable; +use chalk_solve::solve::{Guidance, Solution}; -use chalk_engine::context::{self, AnswerResult, ContextOps}; -use chalk_engine::CompleteAnswer; use std::fmt::Debug; /// Methods for combining solutions to yield an aggregate solution. @@ -179,7 +179,7 @@ fn merge_into_guidance( }) .collect(); - let aggr_subst = Substitution::from(interner, aggr_generic_args); + let aggr_subst = Substitution::from_iter(interner, aggr_generic_args); infer.canonicalize(interner, &aggr_subst).quantified } @@ -307,7 +307,7 @@ impl AntiUnifier<'_, '_, I> { if index1 != index2 { self.new_ty_variable() } else { - TyData::Placeholder(index1.clone()).intern(interner) + TyData::Placeholder(*index1).intern(interner) } } @@ -388,7 +388,7 @@ impl AntiUnifier<'_, '_, I> { substitution2.len(interner) ); - let substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, substitution1 .iter(interner) @@ -465,7 +465,7 @@ impl AntiUnifier<'_, '_, I> { } (ConstValue::BoundVar(_), _) | (_, ConstValue::BoundVar(_)) => { - self.new_const_variable(ty.clone()) + self.new_const_variable(ty) } (ConstValue::Placeholder(_), ConstValue::Placeholder(_)) => { @@ -507,63 +507,71 @@ impl AntiUnifier<'_, '_, I> { } } -/// Test the equivalent of `Vec` vs `Vec` -#[test] -fn vec_i32_vs_vec_u32() { - use chalk_integration::interner::ChalkIr; - let mut infer: InferenceTable = InferenceTable::new(); - let mut anti_unifier = AntiUnifier { - infer: &mut infer, - universe: UniverseIndex::root(), - interner: &ChalkIr, - }; - - let ty = anti_unifier.aggregate_tys( - &ty!(apply (item 0) (apply (item 1))), - &ty!(apply (item 0) (apply (item 2))), - ); - assert_eq!(ty!(apply (item 0) (infer 0)), ty); -} +#[cfg(test)] +mod test { + use crate::slg::aggregate::AntiUnifier; + use chalk_integration::{arg, ty, ty_name}; + use chalk_ir::UniverseIndex; + use chalk_solve::infer::InferenceTable; + + /// Test the equivalent of `Vec` vs `Vec` + #[test] + fn vec_i32_vs_vec_u32() { + use chalk_integration::interner::ChalkIr; + let mut infer: InferenceTable = InferenceTable::new(); + let mut anti_unifier = AntiUnifier { + infer: &mut infer, + universe: UniverseIndex::root(), + interner: &ChalkIr, + }; -/// Test the equivalent of `Vec` vs `Vec` -#[test] -fn vec_i32_vs_vec_i32() { - use chalk_integration::interner::ChalkIr; - let interner = &ChalkIr; - let mut infer: InferenceTable = InferenceTable::new(); - let mut anti_unifier = AntiUnifier { - interner, - infer: &mut infer, - universe: UniverseIndex::root(), - }; - - let ty = anti_unifier.aggregate_tys( - &ty!(apply (item 0) (apply (item 1))), - &ty!(apply (item 0) (apply (item 1))), - ); - assert_eq!(ty!(apply (item 0) (apply (item 1))), ty); -} + let ty = anti_unifier.aggregate_tys( + &ty!(apply (item 0) (apply (item 1))), + &ty!(apply (item 0) (apply (item 2))), + ); + assert_eq!(ty!(apply (item 0) (infer 0)), ty); + } + + /// Test the equivalent of `Vec` vs `Vec` + #[test] + fn vec_i32_vs_vec_i32() { + use chalk_integration::interner::ChalkIr; + let interner = &ChalkIr; + let mut infer: InferenceTable = InferenceTable::new(); + let mut anti_unifier = AntiUnifier { + interner, + infer: &mut infer, + universe: UniverseIndex::root(), + }; -/// Test the equivalent of `Vec` vs `Vec` -#[test] -fn vec_x_vs_vec_y() { - use chalk_integration::interner::ChalkIr; - let interner = &ChalkIr; - let mut infer: InferenceTable = InferenceTable::new(); - let mut anti_unifier = AntiUnifier { - interner, - infer: &mut infer, - universe: UniverseIndex::root(), - }; - - // Note that the `var 0` and `var 1` in these types would be - // referring to canonicalized free variables, not variables in - // `infer`. - let ty = anti_unifier.aggregate_tys( - &ty!(apply (item 0) (infer 0)), - &ty!(apply (item 0) (infer 1)), - ); - - // But this `var 0` is from `infer. - assert_eq!(ty!(apply (item 0) (infer 0)), ty); + let ty = anti_unifier.aggregate_tys( + &ty!(apply (item 0) (apply (item 1))), + &ty!(apply (item 0) (apply (item 1))), + ); + assert_eq!(ty!(apply (item 0) (apply (item 1))), ty); + } + + /// Test the equivalent of `Vec` vs `Vec` + #[test] + fn vec_x_vs_vec_y() { + use chalk_integration::interner::ChalkIr; + let interner = &ChalkIr; + let mut infer: InferenceTable = InferenceTable::new(); + let mut anti_unifier = AntiUnifier { + interner, + infer: &mut infer, + universe: UniverseIndex::root(), + }; + + // Note that the `var 0` and `var 1` in these types would be + // referring to canonicalized free variables, not variables in + // `infer`. + let ty = anti_unifier.aggregate_tys( + &ty!(apply (item 0) (infer 0)), + &ty!(apply (item 0) (infer 1)), + ); + + // But this `var 0` is from `infer. + assert_eq!(ty!(apply (item 0) (infer 0)), ty); + } } diff --git a/vendor/chalk-solve-0.14.0/src/solve/slg/resolvent.rs b/vendor/chalk-engine/src/slg/resolvent.rs similarity index 97% rename from vendor/chalk-solve-0.14.0/src/solve/slg/resolvent.rs rename to vendor/chalk-engine/src/slg/resolvent.rs index b47ecac575..7cbdd697dd 100644 --- a/vendor/chalk-solve-0.14.0/src/solve/slg/resolvent.rs +++ b/vendor/chalk-engine/src/slg/resolvent.rs @@ -1,15 +1,15 @@ -use crate::infer::InferenceTable; -use crate::solve::slg::{self, SlgContext, TruncatingInferenceTable}; +use crate::context; +use crate::normalize_deep::DeepNormalizer; +use crate::slg::{self, SlgContext, TruncatingInferenceTable}; +use crate::{ExClause, Literal, TimeStamp}; use chalk_ir::fold::shift::Shift; use chalk_ir::fold::Fold; use chalk_ir::interner::{HasInterner, Interner}; use chalk_ir::zip::{Zip, Zipper}; use chalk_ir::*; +use chalk_solve::infer::InferenceTable; use tracing::{debug, instrument}; -use chalk_engine::context; -use chalk_engine::{ExClause, Literal, TimeStamp}; - /////////////////////////////////////////////////////////////////////////// // SLG RESOLVENTS // @@ -76,6 +76,7 @@ impl context::ResolventOps> for TruncatingInferenc let ProgramClauseImplication { consequence, conditions, + constraints, priority: _, } = { let ProgramClauseData(implication) = clause.data(interner); @@ -83,8 +84,7 @@ impl context::ResolventOps> for TruncatingInferenc self.infer .instantiate_binders_existentially(interner, implication) }; - debug!("consequence = {:?}", consequence); - debug!("conditions = {:?}", conditions); + debug!(?consequence, ?conditions, ?constraints); // Unify the selected literal Li with C'. let unification_result = self @@ -105,6 +105,10 @@ impl context::ResolventOps> for TruncatingInferenc // Add the subgoals/region-constraints that unification gave us. slg::into_ex_clause(interner, unification_result, &mut ex_clause); + ex_clause + .constraints + .extend(constraints.as_slice(interner).to_owned()); + // Add the `conditions` from the program clause into the result too. ex_clause .subgoals @@ -205,10 +209,7 @@ impl context::ResolventOps> for TruncatingInferenc answer_table_goal: &Canonical>>, canonical_answer_subst: &Canonical>, ) -> Fallible<()> { - debug!( - "selected_goal={:?}", - self.infer.normalize_deep(interner, selected_goal) - ); + debug!(selected_goal = ?DeepNormalizer::normalize_deep(&mut self.infer, interner, selected_goal)); // C' is now `answer`. No variables in common with G. let AnswerSubst { @@ -235,7 +236,9 @@ impl context::ResolventOps> for TruncatingInferenc &answer_table_goal.value, selected_goal, )?; - ex_clause.constraints.extend(answer_constraints); + ex_clause + .constraints + .extend(answer_constraints.as_slice(interner).to_vec()); // at that point we should only have goals that stemmed // from non trivial self cycles ex_clause.delayed_subgoals.extend(delayed_subgoals); diff --git a/vendor/chalk-engine/src/solve.rs b/vendor/chalk-engine/src/solve.rs new file mode 100644 index 0000000000..6c3b0c321d --- /dev/null +++ b/vendor/chalk-engine/src/solve.rs @@ -0,0 +1,84 @@ +use crate::context::{AnswerResult, AnswerStream, ContextOps}; +use crate::forest::Forest; +use crate::slg::aggregate::AggregateOps; +use crate::slg::{SlgContext, SlgContextOps}; +use chalk_ir::interner::Interner; +use chalk_ir::{Canonical, ConstrainedSubst, Goal, InEnvironment, UCanonical}; +use chalk_solve::{RustIrDatabase, Solution, Solver, SubstitutionResult}; + +use std::fmt; + +pub struct SLGSolver { + pub(crate) forest: Forest>, + pub(crate) max_size: usize, + pub(crate) expected_answers: Option, +} + +impl SLGSolver { + pub fn new(max_size: usize, expected_answers: Option) -> Self { + Self { + forest: Forest::new(), + max_size, + expected_answers, + } + } +} + +impl fmt::Debug for SLGSolver { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "SLGSolver") + } +} + +impl Solver for SLGSolver { + fn solve( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + ) -> Option> { + let ops = SlgContextOps::new(program, self.max_size, self.expected_answers); + ops.make_solution(goal, self.forest.iter_answers(&ops, goal), || true) + } + + fn solve_limited( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + should_continue: &dyn std::ops::Fn() -> bool, + ) -> Option> { + let ops = SlgContextOps::new(program, self.max_size, self.expected_answers); + ops.make_solution(goal, self.forest.iter_answers(&ops, goal), should_continue) + } + + fn solve_multiple( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + f: &mut dyn FnMut(SubstitutionResult>>, bool) -> bool, + ) -> bool { + let ops = SlgContextOps::new(program, self.max_size, self.expected_answers); + let mut answers = self.forest.iter_answers(&ops, goal); + loop { + let subst = match answers.next_answer(|| true) { + AnswerResult::Answer(answer) => { + if !answer.ambiguous { + SubstitutionResult::Definite(answer.subst) + } else if ops.is_trivial_constrained_substitution(&answer.subst) { + SubstitutionResult::Floundered + } else { + SubstitutionResult::Ambiguous(answer.subst) + } + } + AnswerResult::Floundered => SubstitutionResult::Floundered, + AnswerResult::NoMoreSolutions => { + return true; + } + AnswerResult::QuantumExceeded => continue, + }; + + if !f(subst, !answers.peek_answer(|| true).is_no_more_solutions()) { + return false; + } + } + } +} diff --git a/vendor/chalk-engine/src/stack.rs b/vendor/chalk-engine/src/stack.rs index f200c70c13..4b2ea059d7 100644 --- a/vendor/chalk-engine/src/stack.rs +++ b/vendor/chalk-engine/src/stack.rs @@ -1,7 +1,9 @@ use crate::context::Context; use crate::index_struct; use crate::strand::Strand; +use crate::tables::Tables; use crate::{Minimums, TableIndex, TimeStamp}; +use std::fmt; use std::ops::{Index, IndexMut, Range}; use chalk_ir::interner::Interner; @@ -13,6 +15,44 @@ pub(crate) struct Stack> { stack: Vec>, } +impl> Stack { + // This isn't actually used, but it can be helpful when debugging stack issues + #[allow(dead_code)] + pub(crate) fn debug_with<'a>(&'a self, tables: &'a Tables) -> StackDebug<'_, I, C> { + StackDebug { + stack: self, + tables, + } + } +} + +pub(crate) struct StackDebug<'a, I: Interner, C: Context> { + stack: &'a Stack, + tables: &'a Tables, +} + +impl> fmt::Debug for StackDebug<'_, I, C> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "---- Stack ----")?; + for entry in self.stack.stack.iter() { + writeln!(f, " --- StackEntry ---")?; + writeln!( + f, + " Table {:?} with goal {:?}", + entry.table, self.tables[entry.table].table_goal + )?; + writeln!(f, " Active strand: {:#?}", entry.active_strand)?; + writeln!( + f, + " Additional strands: {:#?}", + self.tables[entry.table].strands().collect::>() + )?; + } + write!(f, "---- End Stack ----")?; + Ok(()) + } +} + impl> Default for Stack { fn default() -> Self { Stack { stack: vec![] } diff --git a/vendor/chalk-engine/src/table.rs b/vendor/chalk-engine/src/table.rs index ff68b018d5..bb0de48bb9 100644 --- a/vendor/chalk-engine/src/table.rs +++ b/vendor/chalk-engine/src/table.rs @@ -10,6 +10,7 @@ use chalk_ir::interner::Interner; use chalk_ir::{AnswerSubst, Canonical, Goal, InEnvironment, UCanonical}; use tracing::{debug, info, instrument}; +#[derive(Debug)] pub(crate) struct Table { /// The goal this table is trying to solve (also the key to look /// it up). @@ -85,17 +86,6 @@ impl Table { mem::replace(&mut self.strands, VecDeque::new()) } - pub(crate) fn drain_strands( - &mut self, - test: impl Fn(&CanonicalStrand) -> bool, - ) -> VecDeque> { - let old = mem::replace(&mut self.strands, VecDeque::new()); - let (test_in, test_out): (VecDeque>, VecDeque>) = - old.into_iter().partition(test); - let _ = mem::replace(&mut self.strands, test_out); - test_in - } - /// Remove the next strand from the queue that meets the given criteria pub(crate) fn dequeue_next_strand_that( &mut self, @@ -157,8 +147,8 @@ impl Table { }; info!( - "new answer to table with goal {:?}: answer={:?}", - self.table_goal, answer, + goal = ?self.table_goal, ?answer, + "new answer to table", ); if !added { return None; diff --git a/vendor/chalk-engine/src/tables.rs b/vendor/chalk-engine/src/tables.rs index e1e020f057..76508eaa8d 100644 --- a/vendor/chalk-engine/src/tables.rs +++ b/vendor/chalk-engine/src/tables.rs @@ -7,6 +7,7 @@ use chalk_ir::interner::Interner; use chalk_ir::{Goal, InEnvironment, UCanonical}; /// See `Forest`. +#[derive(Debug)] pub(crate) struct Tables { /// Maps from a canonical goal to the index of its table. table_indices: FxHashMap>>, TableIndex>, diff --git a/vendor/chalk-ir-0.14.0/.cargo-checksum.json b/vendor/chalk-ir-0.14.0/.cargo-checksum.json deleted file mode 100644 index c0008e7e36..0000000000 --- a/vendor/chalk-ir-0.14.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"349a9d115dc2b195d3b67519c7074a5298cb735f667e42d8dd51b05ebf4fc7e1","README.md":"64cba0ddf3e9b5c168fbe069f1a84c401ce0b33e765ea49acb1345d0923afe8d","src/cast.rs":"23f99f9cb896c3c54c07a6f1bd242f40c3ba4102441c65344f58209bd8b8a4fe","src/could_match.rs":"329f99b596d7548e2502956905d2788d289e2c695d5573969d37bf2d8d5938f5","src/debug.rs":"579f88d223fd3382264dd7519857582269dd72334f6842b9cecf647543bac75b","src/fold.rs":"2060ea5b4647aa80a9ca171e8c446cb1f77b30f2d299a62e6c9b62a714f81fdb","src/fold/binder_impls.rs":"000af61a46ffc0ed9d01fbd6764402157969af6b4a501ad1027593ef15ca20ec","src/fold/boring_impls.rs":"38c7167a8b6e351a47b060f89017794ef6406d5462544bd93c0d3d1241fe2df1","src/fold/shift.rs":"5ae3b2efd6275411bba822459e0a9377594c9116c2bdc3b86fde90efa6dab020","src/fold/subst.rs":"59db128e9bc82cf0f7dd49c9057bde85d31e2c51832736a359ca726639a69d15","src/interner.rs":"25735e216d5ba9efeee1c7d829bcf72d7599e976f6a02487dc343cec4cda2e1b","src/lib.rs":"8c305524ed505ea87035b23a1c1fe3c480933c0b4710339e64e0a8ebaab2e426","src/visit.rs":"e78a78472c1ef7fbd33a158b146471b2177d184e1de0839f1e789f5e4b309cf7","src/visit/binder_impls.rs":"8e02aadf0551a66ce0748c6c890d8a85543c0d72d4d22990ed2eccad29813afb","src/visit/boring_impls.rs":"5423adb7cac7dde0a614405575c4c612efebc1802d639871a87a31e6e1151cad","src/visit/visitors.rs":"abda40eb51d97a68af62148e906dd2957b34617059d8b8c0fbe01eac6653196c","src/zip.rs":"8f49ef5dda9d98c9f74977502197d9bb7927b30754afe8abaf790163170e1f16"},"package":"fd3fdc1e9f68498ffe80f4a23b0b95f1ca6fb21d5a4c9b0c085fab3ca712bdbe"} \ No newline at end of file diff --git a/vendor/chalk-ir-0.25.0/.cargo-checksum.json b/vendor/chalk-ir-0.25.0/.cargo-checksum.json new file mode 100644 index 0000000000..131ca2f0c0 --- /dev/null +++ b/vendor/chalk-ir-0.25.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"40254e614cf85d16362f59878865e03647a7645cfcc2b24cd4879163ad91c362","README.md":"64cba0ddf3e9b5c168fbe069f1a84c401ce0b33e765ea49acb1345d0923afe8d","src/cast.rs":"6e8bc7ebd3d94a27c561499a15de2cc5d9501e6bf387b62e76772d7cb7ecd0a2","src/could_match.rs":"46507c372868dcd51c4a04dcd4bcc4e6e61f0fa537d980b3dc615be52c98171b","src/debug.rs":"e130908297f47a08ec7ed0d36131e5bd8534434fb9d30881da4fcbd714d2d95a","src/fold.rs":"2d1f8fd0f8603dad54428ba9d93f281d478c380dfca9d755e96a362d3be9d470","src/fold/binder_impls.rs":"0cb4f2b40b34e5f80e5a5946289959431ac5c22f6ec87d30e9b2f7d4122d0fd0","src/fold/boring_impls.rs":"f83bddd6061e0d035fb37a250013c2ce55fb624d0a3ee63d5e1840bb8ebd8227","src/fold/shift.rs":"134caa51a84399e7bd31471e3a31f7ca05b91c99cb1f06132f1d42151328e5d3","src/fold/subst.rs":"4db018d2b5d447420ae4b9269de36f3ce816de201b4eeaf30d54ae5c3b5db7cd","src/interner.rs":"993b347617e2a6dc8f34d966e4f140a082dfadc946d52e1e4064311db07f4b65","src/lib.rs":"808cf7a58fc04b89fd10eac36125dd9356a00bc33cc6570d81d63796a1572497","src/visit.rs":"22e5230a397b3d5ec1c2002cdd03dc6c8adb3d5497e83534d93b9ff72875896c","src/visit/binder_impls.rs":"4e544fc24158c8a1c84237ed21b83673225f87876ee78eeda83b41bc2b65f408","src/visit/boring_impls.rs":"f9904bf7200af8dc55e01ff24c238406596b7e7353ad7361d074ec5af4a4d013","src/visit/visitors.rs":"5f429cc2f9a94f918258c8df776a0fec15cffaff4dd7b20019a2ad6c091a1ddd","src/zip.rs":"f2b25e7221e32b5176adc95220b338d079555fae2949e12bf197e28dd8b24c2f"},"package":"118c68eccdda5604af50bbef84c94550f3854f76989cb03c36ffd36cc2ffe958"} \ No newline at end of file diff --git a/vendor/chalk-ir-0.14.0/Cargo.toml b/vendor/chalk-ir-0.25.0/Cargo.toml similarity index 95% rename from vendor/chalk-ir-0.14.0/Cargo.toml rename to vendor/chalk-ir-0.25.0/Cargo.toml index 451b3b83ad..940c51750e 100644 --- a/vendor/chalk-ir-0.14.0/Cargo.toml +++ b/vendor/chalk-ir-0.25.0/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-ir" -version = "0.14.0" +version = "0.25.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Chalk's internal representation of types, goals, and clauses" readme = "README.md" @@ -21,7 +21,7 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.14.0" +version = "=0.25.0" [dependencies.lazy_static] version = "1.4.0" diff --git a/vendor/chalk-ir-0.14.0/README.md b/vendor/chalk-ir-0.25.0/README.md similarity index 100% rename from vendor/chalk-ir-0.14.0/README.md rename to vendor/chalk-ir-0.25.0/README.md diff --git a/vendor/chalk-ir-0.14.0/src/cast.rs b/vendor/chalk-ir-0.25.0/src/cast.rs similarity index 94% rename from vendor/chalk-ir-0.14.0/src/cast.rs rename to vendor/chalk-ir-0.25.0/src/cast.rs index 310ef3b467..c363d3800b 100644 --- a/vendor/chalk-ir-0.14.0/src/cast.rs +++ b/vendor/chalk-ir-0.25.0/src/cast.rs @@ -1,3 +1,5 @@ +//! Upcasts, to avoid writing out wrapper types. + use crate::*; use std::marker::PhantomData; @@ -38,6 +40,7 @@ use std::marker::PhantomData; /// This split setup allows us to write `foo.cast::()` to mean /// "cast to T". pub trait Cast: Sized { + /// Cast a value to type `U` using `CastTo`. fn cast(self, interner: &U::Interner) -> U where Self: CastTo, @@ -54,6 +57,7 @@ impl Cast for T {} /// functions that take (e.g.) an `impl CastTo>` or something /// like that. pub trait CastTo: Sized { + /// Cast a value to type `T`. fn cast_to(self, interner: &T::Interner) -> T; } @@ -83,8 +87,11 @@ reflexive_impl!(for(I: Interner) Goal); reflexive_impl!(for(I: Interner) WhereClause); reflexive_impl!(for(I: Interner) ProgramClause); reflexive_impl!(for(I: Interner) QuantifiedWhereClause); +reflexive_impl!(for(I: Interner) VariableKind); reflexive_impl!(for(I: Interner) VariableKinds); +reflexive_impl!(for(I: Interner) CanonicalVarKind); reflexive_impl!(for(I: Interner) CanonicalVarKinds); +reflexive_impl!(for(I: Interner) Constraint); impl CastTo> for TraitRef { fn cast_to(self, _interner: &I) -> WhereClause { @@ -201,7 +208,8 @@ where fn cast_to(self, interner: &I) -> ProgramClause { let implication = ProgramClauseImplication { consequence: self.cast(interner), - conditions: Goals::new(interner), + conditions: Goals::empty(interner), + constraints: Constraints::empty(interner), priority: ClausePriority::High, }; @@ -218,7 +226,8 @@ where fn cast_to(self, interner: &I) -> ProgramClause { ProgramClauseData(self.map(|bound| ProgramClauseImplication { consequence: bound.cast(interner), - conditions: Goals::new(interner), + conditions: Goals::empty(interner), + constraints: Constraints::empty(interner), priority: ClausePriority::High, })) .intern(interner) @@ -333,6 +342,7 @@ where } } +/// An iterator that casts each element to some other type. pub struct Casted<'i, IT, U: HasInterner> { interner: &'i U::Interner, iterator: IT, @@ -358,6 +368,7 @@ where /// An iterator adapter that casts each element we are iterating over /// to some other type. pub trait Caster: Iterator + Sized { + /// Cast each element in this iterator. fn casted(self, interner: &U::Interner) -> Casted<'_, Self, U> where Self::Item: CastTo, diff --git a/vendor/chalk-ir-0.14.0/src/could_match.rs b/vendor/chalk-ir-0.25.0/src/could_match.rs similarity index 95% rename from vendor/chalk-ir-0.14.0/src/could_match.rs rename to vendor/chalk-ir-0.25.0/src/could_match.rs index c070d32a44..a8446c621d 100644 --- a/vendor/chalk-ir-0.14.0/src/could_match.rs +++ b/vendor/chalk-ir-0.25.0/src/could_match.rs @@ -1,9 +1,12 @@ +//! Fast matching check for zippable values. + use crate::interner::HasInterner; use crate::zip::{Zip, Zipper}; use crate::*; /// A fast check to see whether two things could ever possibly match. pub trait CouldMatch { + /// Checks whether `self` and `other` could possibly match. fn could_match(&self, interner: &T::Interner, other: &T) -> bool; } diff --git a/vendor/chalk-ir-0.14.0/src/debug.rs b/vendor/chalk-ir-0.25.0/src/debug.rs similarity index 91% rename from vendor/chalk-ir-0.14.0/src/debug.rs rename to vendor/chalk-ir-0.25.0/src/debug.rs index 485471f9f9..7c2f21853c 100644 --- a/vendor/chalk-ir-0.14.0/src/debug.rs +++ b/vendor/chalk-ir-0.25.0/src/debug.rs @@ -1,3 +1,5 @@ +//! Debug impls for types. + use std::fmt::{Debug, Display, Error, Formatter}; use super::*; @@ -94,6 +96,12 @@ impl Debug for ProgramClauses { } } +impl Debug for Constraints { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { + I::debug_constraints(self, fmt).unwrap_or_else(|| write!(fmt, "{:?}", self.interned)) + } +} + impl Debug for ApplicationTy { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { I::debug_application_ty(self, fmt).unwrap_or_else(|| write!(fmt, "ApplicationTy(?)")) @@ -224,14 +232,21 @@ impl Debug for InferenceVar { } } -impl Debug for Fn { +impl Debug for FnPointer { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { // FIXME -- we should introduce some names or something here - let Fn { + let FnPointer { num_binders, substitution, + abi, + safety, + variadic: _, } = self; - write!(fmt, "for<{}> {:?}", num_binders, substitution) + write!( + fmt, + "for<{}> {:?} {:?} {:?}", + num_binders, safety, abi, substitution + ) } } @@ -251,6 +266,7 @@ impl VariableKinds { VariableKindsDebug(self) } + /// Helper method for debugging variable kinds. pub fn inner_debug<'a>(&'a self, interner: &'a I) -> VariableKindsInnerDebug<'a, I> { VariableKindsInnerDebug { variable_kinds: self, @@ -268,6 +284,7 @@ impl<'a, I: Interner> Debug for VariableKindsDebug<'a, I> { } } +/// Helper struct for showing debug output for `VariableKinds`. pub struct VariableKindsInnerDebug<'a, I: Interner> { variable_kinds: &'a VariableKinds, interner: &'a I, @@ -322,11 +339,12 @@ impl Debug for GoalData { GoalData::Not(ref g) => write!(fmt, "not {{ {:?} }}", g), GoalData::EqGoal(ref wc) => write!(fmt, "{:?}", wc), GoalData::DomainGoal(ref wc) => write!(fmt, "{:?}", wc), - GoalData::CannotProve(()) => write!(fmt, r"¯\_(ツ)_/¯"), + GoalData::CannotProve => write!(fmt, r"¯\_(ツ)_/¯"), } } } +/// Helper struct for showing debug output for `Goals`. pub struct GoalsDebug<'a, I: Interner> { goals: &'a Goals, interner: &'a I, @@ -347,6 +365,7 @@ impl<'a, I: Interner> Debug for GoalsDebug<'a, I> { } impl Goals { + /// Show debug output for `Goals`. pub fn debug<'a>(&'a self, interner: &'a I) -> GoalsDebug<'a, I> { GoalsDebug { goals: self, @@ -355,6 +374,7 @@ impl Goals { } } +/// Helper struct for showing debug output for `GenericArgData`. pub struct GenericArgDataInnerDebug<'a, I: Interner>(&'a GenericArgData); impl<'a, I: Interner> Debug for GenericArgDataInnerDebug<'a, I> { @@ -368,11 +388,13 @@ impl<'a, I: Interner> Debug for GenericArgDataInnerDebug<'a, I> { } impl GenericArgData { + /// Helper method for debugging `GenericArgData`. pub fn inner_debug(&self) -> GenericArgDataInnerDebug<'_, I> { GenericArgDataInnerDebug(self) } } +/// Helper struct for showing debug output for program clause implications. pub struct ProgramClauseImplicationDebug<'a, I: Interner> { pci: &'a ProgramClauseImplication, interner: &'a I, @@ -399,6 +421,7 @@ impl<'a, I: Interner> Debug for ProgramClauseImplicationDebug<'a, I> { } impl ProgramClauseImplication { + /// Show debug output for the program clause implication. pub fn debug<'a>(&'a self, interner: &'a I) -> ProgramClauseImplicationDebug<'a, I> { ProgramClauseImplicationDebug { pci: self, @@ -407,6 +430,7 @@ impl ProgramClauseImplication { } } +/// Helper struct for showing debug output for application types. pub struct ApplicationTyDebug<'a, I: Interner> { application_ty: &'a ApplicationTy, interner: &'a I, @@ -424,6 +448,7 @@ impl<'a, I: Interner> Debug for ApplicationTyDebug<'a, I> { } impl ApplicationTy { + /// Show debug output for the application type. pub fn debug<'a>(&'a self, interner: &'a I) -> ApplicationTyDebug<'a, I> { ApplicationTyDebug { application_ty: self, @@ -432,6 +457,7 @@ impl ApplicationTy { } } +/// Helper struct for showing debug output for substitutions. pub struct SubstitutionDebug<'a, I: Interner> { substitution: &'a Substitution, interner: &'a I, @@ -464,6 +490,7 @@ impl<'a, I: Interner> Debug for SubstitutionDebug<'a, I> { } impl Substitution { + /// Show debug output for the substitution. pub fn debug<'a>(&'a self, interner: &'a I) -> SubstitutionDebug<'a, I> { SubstitutionDebug { substitution: self, @@ -480,7 +507,7 @@ impl Debug for PlaceholderIndex { } impl TraitRef { - /// Returns a "Debuggable" type that prints like `P0 as Trait` + /// Returns a "Debuggable" type that prints like `P0 as Trait`. pub fn with_as(&self) -> impl std::fmt::Debug + '_ { SeparatorTraitRef { trait_ref: self, @@ -488,7 +515,7 @@ impl TraitRef { } } - /// Returns a "Debuggable" type that prints like `P0: Trait` + /// Returns a "Debuggable" type that prints like `P0: Trait`. pub fn with_colon(&self) -> impl std::fmt::Debug + '_ { SeparatorTraitRef { trait_ref: self, @@ -503,11 +530,16 @@ impl Debug for TraitRef { } } +/// Trait ref with associated separator used for debug output. pub struct SeparatorTraitRef<'me, I: Interner> { + /// The `TraitRef` itself. pub trait_ref: &'me TraitRef, + + /// The separator used for displaying the `TraitRef`. pub separator: &'me str, } +/// Helper struct for showing debug output for the `SeperatorTraitRef`. pub struct SeparatorTraitRefDebug<'a, 'me, I: Interner> { separator_trait_ref: &'a SeparatorTraitRef<'me, I>, interner: &'a I, @@ -522,7 +554,7 @@ impl<'a, 'me, I: Interner> Debug for SeparatorTraitRefDebug<'a, 'me, I> { let parameters = separator_trait_ref .trait_ref .substitution - .parameters(interner); + .as_slice(interner); write!( fmt, "{:?}{}{:?}{:?}", @@ -535,6 +567,7 @@ impl<'a, 'me, I: Interner> Debug for SeparatorTraitRefDebug<'a, 'me, I> { } impl<'me, I: Interner> SeparatorTraitRef<'me, I> { + /// Show debug output for the `SeperatorTraitRef`. pub fn debug<'a>(&'a self, interner: &'a I) -> SeparatorTraitRefDebug<'a, 'me, I> { SeparatorTraitRefDebug { separator_trait_ref: self, @@ -549,6 +582,13 @@ impl Debug for LifetimeOutlives { } } +impl Debug for TypeOutlives { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { + write!(fmt, "{:?}: {:?}", self.ty, self.lifetime) + } +} + +/// Helper struct for showing debug output for projection types. pub struct ProjectionTyDebug<'a, I: Interner> { projection_ty: &'a ProjectionTy, interner: &'a I, @@ -570,6 +610,7 @@ impl<'a, I: Interner> Debug for ProjectionTyDebug<'a, I> { } impl ProjectionTy { + /// Show debug output for the projection type. pub fn debug<'a>(&'a self, interner: &'a I) -> ProjectionTyDebug<'a, I> { ProjectionTyDebug { projection_ty: self, @@ -578,6 +619,7 @@ impl ProjectionTy { } } +/// Helper struct for showing debug output for opaque types. pub struct OpaqueTyDebug<'a, I: Interner> { opaque_ty: &'a OpaqueTy, interner: &'a I, @@ -599,6 +641,7 @@ impl<'a, I: Interner> Debug for OpaqueTyDebug<'a, I> { } impl OpaqueTy { + /// Show debug output for the opaque type. pub fn debug<'a>(&'a self, interner: &'a I) -> OpaqueTyDebug<'a, I> { OpaqueTyDebug { opaque_ty: self, @@ -607,11 +650,12 @@ impl OpaqueTy { } } +/// Wraps debug output in angle brackets (`<>`). pub struct Angle<'a, T>(pub &'a [T]); impl<'a, T: Debug> Debug for Angle<'a, T> { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { - if self.0.len() > 0 { + if !self.0.is_empty() { write!(fmt, "<")?; for (index, elem) in self.0.iter().enumerate() { if index > 0 { @@ -644,6 +688,7 @@ impl Debug for WhereClause { WhereClause::Implemented(tr) => write!(fmt, "Implemented({:?})", tr.with_colon()), WhereClause::AliasEq(a) => write!(fmt, "{:?}", a), WhereClause::LifetimeOutlives(l_o) => write!(fmt, "{:?}", l_o), + WhereClause::TypeOutlives(t_o) => write!(fmt, "{:?}", t_o), } } } @@ -679,9 +724,9 @@ impl Debug for DomainGoal { DomainGoal::LocalImplAllowed(tr) => { write!(fmt, "LocalImplAllowed({:?})", tr.with_colon(),) } - DomainGoal::Compatible(_) => write!(fmt, "Compatible"), + DomainGoal::Compatible => write!(fmt, "Compatible"), DomainGoal::DownstreamType(n) => write!(fmt, "DownstreamType({:?})", n), - DomainGoal::Reveal(_) => write!(fmt, "Reveal"), + DomainGoal::Reveal => write!(fmt, "Reveal"), DomainGoal::ObjectSafe(n) => write!(fmt, "ObjectSafe({:?})", n), } } @@ -724,6 +769,7 @@ impl Debug for CanonicalVarKinds { } impl Canonical { + /// Display the canonicalized item. pub fn display<'a>(&'a self, interner: &'a T::Interner) -> CanonicalDisplay<'a, T> { CanonicalDisplay { canonical: self, @@ -732,6 +778,7 @@ impl Canonical { } } +/// Helper struct for displaying canonicalized items. pub struct CanonicalDisplay<'a, T: HasInterner> { canonical: &'a Canonical, interner: &'a T::Interner, @@ -805,7 +852,8 @@ impl Debug for WithKind { impl Debug for Constraint { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { match self { - Constraint::Outlives(a, b) => write!(fmt, "{:?}: {:?}", a, b), + Constraint::LifetimeOutlives(a, b) => write!(fmt, "{:?}: {:?}", a, b), + Constraint::TypeOutlives(ty, lifetime) => write!(fmt, "{:?}: {:?}", ty, lifetime), } } } @@ -826,7 +874,7 @@ impl Substitution { /// Displays the substitution in the form `< P0, .. Pn >`, or (if /// the substitution is empty) as an empty string. pub fn with_angle(&self, interner: &I) -> Angle<'_, GenericArg> { - Angle(self.parameters(interner)) + Angle(self.as_slice(interner)) } } diff --git a/vendor/chalk-ir-0.14.0/src/fold.rs b/vendor/chalk-ir-0.25.0/src/fold.rs similarity index 98% rename from vendor/chalk-ir-0.14.0/src/fold.rs rename to vendor/chalk-ir-0.25.0/src/fold.rs index 5cec1558fa..40f5f276da 100644 --- a/vendor/chalk-ir-0.14.0/src/fold.rs +++ b/vendor/chalk-ir-0.25.0/src/fold.rs @@ -172,6 +172,7 @@ where } } + /// As `fold_free_var_ty`, but for constants. fn fold_free_var_const( &mut self, ty: &Ty, @@ -233,6 +234,7 @@ where } } + /// As with `fold_free_placeholder_ty`, but for constants. #[allow(unused_variables)] fn fold_free_placeholder_const( &mut self, @@ -278,7 +280,7 @@ where } } - /// As with `fold_free_inference_ty`, but for lifetimes. + /// As with `fold_inference_ty`, but for lifetimes. #[allow(unused_variables)] fn fold_inference_lifetime( &mut self, @@ -292,6 +294,7 @@ where } } + /// As with `fold_inference_ty`, but for constants. #[allow(unused_variables)] fn fold_inference_const( &mut self, @@ -309,8 +312,10 @@ where } } + /// Gets the interner that is being folded from. fn interner(&self) -> &'i I; + /// Gets the interner that is being folded to. fn target_interner(&self) -> &'i TI; } @@ -356,6 +361,7 @@ pub trait Fold = I>: Debug { /// `SuperFold` trait captures the recursive behavior that folds all /// the contents of the type. pub trait SuperFold = I>: Fold { + /// Recursively folds the value. fn super_fold_with<'i>( &self, folder: &mut dyn Folder<'i, I, TI>, diff --git a/vendor/chalk-ir-0.14.0/src/fold/binder_impls.rs b/vendor/chalk-ir-0.25.0/src/fold/binder_impls.rs similarity index 86% rename from vendor/chalk-ir-0.14.0/src/fold/binder_impls.rs rename to vendor/chalk-ir-0.25.0/src/fold/binder_impls.rs index b514d8f189..1f751f16ca 100644 --- a/vendor/chalk-ir-0.14.0/src/fold/binder_impls.rs +++ b/vendor/chalk-ir-0.25.0/src/fold/binder_impls.rs @@ -6,8 +6,8 @@ use crate::interner::TargetInterner; use crate::*; -impl> Fold for Fn { - type Result = Fn; +impl> Fold for FnPointer { + type Result = FnPointer; fn fold_with<'i>( &self, folder: &mut dyn Folder<'i, I, TI>, @@ -17,13 +17,19 @@ impl> Fold for Fn { I: 'i, TI: 'i, { - let Fn { + let FnPointer { num_binders, substitution, + abi, + safety, + variadic, } = self; - Ok(Fn { + Ok(FnPointer { num_binders: *num_binders, substitution: substitution.fold_with(folder, outer_binder.shifted_in())?, + abi: TI::transfer_abi(*abi), + safety: *safety, + variadic: *variadic, }) } } @@ -81,9 +87,6 @@ where let binders = CanonicalVarKinds { interned: TI::transfer_canonical_var_kinds(self_binders.interned().clone()), }; - Ok(Canonical { - binders: binders, - value: value, - }) + Ok(Canonical { binders, value }) } } diff --git a/vendor/chalk-ir-0.14.0/src/fold/boring_impls.rs b/vendor/chalk-ir-0.25.0/src/fold/boring_impls.rs similarity index 93% rename from vendor/chalk-ir-0.14.0/src/fold/boring_impls.rs rename to vendor/chalk-ir-0.25.0/src/fold/boring_impls.rs index 7d14b02349..9922315a39 100644 --- a/vendor/chalk-ir-0.14.0/src/fold/boring_impls.rs +++ b/vendor/chalk-ir-0.25.0/src/fold/boring_impls.rs @@ -213,6 +213,27 @@ impl> Fold for QuantifiedWhereClauses< } } +impl> Fold for Constraints { + type Result = Constraints; + fn fold_with<'i>( + &self, + folder: &mut dyn Folder<'i, I, TI>, + outer_binder: DebruijnIndex, + ) -> Fallible + where + I: 'i, + TI: 'i, + { + let interner = folder.interner(); + let target_interner = folder.target_interner(); + let folded = self + .iter(interner) + .map(|p| p.fold_with(folder, outer_binder)); + Ok(Constraints::from_fallible(target_interner, folded)?) + } +} + +#[doc(hidden)] #[macro_export] macro_rules! copy_fold { ($t:ty) => { @@ -246,7 +267,9 @@ copy_fold!(FloatTy); copy_fold!(Scalar); copy_fold!(ClausePriority); copy_fold!(Mutability); +copy_fold!(Safety); +#[doc(hidden)] #[macro_export] macro_rules! id_fold { ($t:ident) => { diff --git a/vendor/chalk-ir-0.14.0/src/fold/shift.rs b/vendor/chalk-ir-0.25.0/src/fold/shift.rs similarity index 99% rename from vendor/chalk-ir-0.14.0/src/fold/shift.rs rename to vendor/chalk-ir-0.25.0/src/fold/shift.rs index 1c34f59fe4..2a144ae2d2 100644 --- a/vendor/chalk-ir-0.14.0/src/fold/shift.rs +++ b/vendor/chalk-ir-0.25.0/src/fold/shift.rs @@ -1,3 +1,5 @@ +//! Shifting of debruijn indices + use super::Fold; use crate::*; diff --git a/vendor/chalk-ir-0.14.0/src/fold/subst.rs b/vendor/chalk-ir-0.25.0/src/fold/subst.rs similarity index 97% rename from vendor/chalk-ir-0.14.0/src/fold/subst.rs rename to vendor/chalk-ir-0.25.0/src/fold/subst.rs index ffee986bec..6c6cb2c7a1 100644 --- a/vendor/chalk-ir-0.14.0/src/fold/subst.rs +++ b/vendor/chalk-ir-0.25.0/src/fold/subst.rs @@ -1,6 +1,7 @@ use super::*; use crate::fold::shift::Shift; +/// Substitution used during folding pub struct Subst<'s, 'i, I: Interner> { /// Values to substitute. A reference to a free variable with /// index `i` will be mapped to `parameters[i]` -- if `i > @@ -10,6 +11,7 @@ pub struct Subst<'s, 'i, I: Interner> { } impl Subst<'_, '_, I> { + /// Applies the substitution by folding pub fn apply>( interner: &I, parameters: &[GenericArg], diff --git a/vendor/chalk-ir-0.14.0/src/interner.rs b/vendor/chalk-ir-0.25.0/src/interner.rs similarity index 72% rename from vendor/chalk-ir-0.14.0/src/interner.rs rename to vendor/chalk-ir-0.25.0/src/interner.rs index eae60aef2c..c996059d97 100644 --- a/vendor/chalk-ir-0.14.0/src/interner.rs +++ b/vendor/chalk-ir-0.25.0/src/interner.rs @@ -1,3 +1,4 @@ +//! Encapsulates the concrete representation of core types such as types and goals. use crate::AdtId; use crate::AliasTy; use crate::ApplicationTy; @@ -5,12 +6,15 @@ use crate::AssocTypeId; use crate::CanonicalVarKind; use crate::CanonicalVarKinds; use crate::ClosureId; +use crate::Constraint; +use crate::Constraints; use crate::FnDefId; use crate::GenericArg; use crate::GenericArgData; use crate::Goal; use crate::GoalData; use crate::Goals; +use crate::InEnvironment; use crate::Lifetime; use crate::LifetimeData; use crate::OpaqueTy; @@ -163,33 +167,34 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// to its underlying data via `canonical_var_kinds_data`. type InternedCanonicalVarKinds: Debug + Clone + Eq + Hash; + /// "Interned" representation of a list of region constraints. + /// In normal user code, `Self::InternedConstraints` is not referenced. + /// Instead, we refer to `Constraints`, which wraps this type. + /// + /// An `InternedConstraints` is created by `intern_constraints` + /// and can be converted back to its underlying data via `constraints_data`. + type InternedConstraints: Debug + Clone + Eq + Hash; + /// The core "id" type used for trait-ids and the like. type DefId: Debug + Copy + Eq + Ord + Hash; /// The ID type for ADTs type InternedAdtId: Debug + Copy + Eq + Ord + Hash; + /// Representation of identifiers. type Identifier: Debug + Clone + Eq + Hash; + /// Representation of function ABI (e.g. calling convention). type FnAbi: Debug + Copy + Eq + Hash; - /// Prints the debug representation of a type-kind-id. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a type-kind-id. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_adt_id(adt_id: AdtId, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a type-kind-id. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// + /// Prints the debug representation of a type-kind-id. /// Returns `None` to fallback to the default debug output (e.g., /// if no info about current program is available from TLS). #[allow(unused_variables)] @@ -200,10 +205,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a type-kind-id. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). + /// Prints the debug representation of a type-kind-id. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_assoc_type_id( type_id: AssocTypeId, @@ -212,13 +215,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an opaque type. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific type-family (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an opaque type. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_opaque_ty_id( opaque_ty_id: OpaqueTyId, @@ -227,6 +225,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + /// Prints the debug representation of a function-def-id. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_fn_def_id( fn_def_id: FnDefId, @@ -235,6 +235,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + /// Prints the debug representation of a closure id. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_closure_id( fn_def_id: ClosureId, @@ -243,25 +245,15 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an alias. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an alias. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_alias(alias: &AliasTy, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a ProjectionTy. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a ProjectionTy. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_projection_ty( projection_ty: &ProjectionTy, @@ -270,13 +262,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an OpaqueTy. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an OpaqueTy. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_opaque_ty( opaque_ty: &OpaqueTy, @@ -285,25 +272,15 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a type. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a type. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_ty(ty: &Ty, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a lifetime. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a lifetime. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_lifetime( lifetime: &Lifetime, @@ -312,25 +289,15 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a const. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a const. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_const(constant: &Const, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of an parameter. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an parameter. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_generic_arg( generic_arg: &GenericArg, @@ -339,13 +306,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a parameter kinds list. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a parameter kinds list. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_variable_kinds( variable_kinds: &VariableKinds, @@ -355,12 +317,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { } /// Prints the debug representation of a parameter kinds list, with angle brackets. - /// To get good results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_variable_kinds_with_angles( variable_kinds: &VariableKinds, @@ -370,12 +327,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { } /// Prints the debug representation of an parameter kinds list with universe index. - /// To get good results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_canonical_var_kinds( canonical_var_kinds: &CanonicalVarKinds, @@ -384,37 +336,22 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an goal. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an goal. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a list of goals. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a list of goals. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_goals(goals: &Goals, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a ProgramClauseImplication. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a ProgramClauseImplication. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_program_clause_implication( pci: &ProgramClauseImplication, @@ -423,13 +360,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a ProgramClause. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a ProgramClause. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_program_clause( clause: &ProgramClause, @@ -438,13 +370,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a ProgramClauses. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a ProgramClauses. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_program_clauses( clauses: &ProgramClauses, @@ -453,13 +380,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an ApplicationTy. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an ApplicationTy. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_application_ty( application_ty: &ApplicationTy, @@ -468,13 +390,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a Substitution. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a Substitution. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_substitution( substitution: &Substitution, @@ -483,13 +400,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a SeparatorTraitRef. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a SeparatorTraitRef. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_separator_trait_ref( separator_trait_ref: &SeparatorTraitRef<'_, Self>, @@ -498,13 +410,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a QuantifiedWhereClauses. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a QuantifiedWhereClauses. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_quantified_where_clauses( clauses: &QuantifiedWhereClauses, @@ -513,6 +420,16 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + /// Prints the debug representation of a Constraints. + /// Returns `None` to fallback to the default debug output. + #[allow(unused_variables)] + fn debug_constraints( + clauses: &Constraints, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + /// Create an "interned" type from `ty`. This is not normally /// invoked directly; instead, you invoke `TyData::intern` (which /// will ultimately call this method). @@ -539,6 +456,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Lookup the `ConstData` that was interned to create a `InternedConst`. fn const_data<'a>(&self, constant: &'a Self::InternedConst) -> &'a ConstData; + /// Deterermine whether two concrete const values are equal. fn const_eq( &self, ty: &Self::InternedType, @@ -608,7 +526,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Create an "interned" program clauses from `data`. This is not /// normally invoked directly; instead, you invoke - /// `ProgramClauses::from` (which will ultimately call this + /// `ProgramClauses::from_iter` (which will ultimately call this /// method). fn intern_program_clauses( &self, @@ -623,7 +541,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Create an "interned" quantified where clauses from `data`. This is not /// normally invoked directly; instead, you invoke - /// `QuantifiedWhereClauses::from` (which will ultimately call this + /// `QuantifiedWhereClauses::from_iter` (which will ultimately call this /// method). fn intern_quantified_where_clauses( &self, @@ -639,7 +557,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Create an "interned" parameter kinds from `data`. This is not /// normally invoked directly; instead, you invoke - /// `VariableKinds::from` (which will ultimately call this + /// `VariableKinds::from_iter` (which will ultimately call this /// method). fn intern_generic_arg_kinds( &self, @@ -655,7 +573,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Create "interned" variable kinds with universe index from `data`. This is not /// normally invoked directly; instead, you invoke - /// `CanonicalVarKinds::from` (which will ultimately call this + /// `CanonicalVarKinds::from_iter` (which will ultimately call this /// method). fn intern_canonical_var_kinds( &self, @@ -668,25 +586,56 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { &self, canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, ) -> &'a [CanonicalVarKind]; + + /// Create "interned" constraints from `data`. This is not + /// normally invoked dirctly; instead, you invoke + /// `Constraints::from_iter` (which will ultimately call this + /// method). + fn intern_constraints( + &self, + data: impl IntoIterator>, E>>, + ) -> Result; + + /// Lookup the slice of `Constraint` that was interned to + /// create a `Constraints`. + fn constraints_data<'a>( + &self, + constraints: &'a Self::InternedConstraints, + ) -> &'a [InEnvironment>]; } +/// "Target" interner, used to specify the interner of the folded value. +/// In most cases, both interners are the same, but in some cases you want +/// to change a value to a different internal representation, and as such +/// a different target interner. +/// +/// Contains several methods to transfer types from another interner to +/// the `TargetInterner`. pub trait TargetInterner: Interner { + /// Transfer a `DefId` to the target interner. fn transfer_def_id(def_id: I::DefId) -> Self::DefId; + /// Transfer an AdtId to the target interner. fn transfer_adt_id(adt_id: I::InternedAdtId) -> Self::InternedAdtId; + /// Transfer variable kinds to the target interner. fn transfer_variable_kinds( variable_kinds: I::InternedVariableKinds, ) -> Self::InternedVariableKinds; + /// Transfer canonical var kinds to the target interner. fn transfer_canonical_var_kinds( variable_kinds: I::InternedCanonicalVarKinds, ) -> Self::InternedCanonicalVarKinds; + /// Transfer constant values to the target interner. fn transfer_const( &self, const_evaluated: &I::InternedConcreteConst, ) -> Self::InternedConcreteConst; + + /// Transfer function ABI to the target interner. + fn transfer_abi(abi: I::FnAbi) -> Self::FnAbi; } impl TargetInterner for I { @@ -716,6 +665,10 @@ impl TargetInterner for I { ) -> Self::InternedConcreteConst { const_evaluated.clone() } + + fn transfer_abi(abi: I::FnAbi) -> Self::FnAbi { + abi + } } /// Implemented by types that have an associated interner (which @@ -725,6 +678,7 @@ impl TargetInterner for I { /// It's particularly useful for writing `Fold` impls for generic types like /// `Binder`, since it allows us to figure out the interner of `T`. pub trait HasInterner { + /// The interner associated with the type. type Interner: Interner; } diff --git a/vendor/chalk-ir-0.14.0/src/lib.rs b/vendor/chalk-ir-0.25.0/src/lib.rs similarity index 74% rename from vendor/chalk-ir-0.14.0/src/lib.rs rename to vendor/chalk-ir-0.25.0/src/lib.rs index e650f5dc00..3a1cad53f3 100644 --- a/vendor/chalk-ir-0.14.0/src/lib.rs +++ b/vendor/chalk-ir-0.25.0/src/lib.rs @@ -1,18 +1,21 @@ +//! Defines the IR for types and logical predicates. + #![deny(rust_2018_idioms)] +#![warn(missing_docs)] // Allows macros to refer to this crate as `::chalk_ir` extern crate self as chalk_ir; -use crate::cast::{Cast, CastTo}; +use crate::cast::{Cast, CastTo, Caster}; use crate::fold::shift::Shift; use crate::fold::{Fold, Folder, Subst, SuperFold}; use crate::visit::{SuperVisit, Visit, VisitExt, VisitResult, Visitor}; use chalk_derive::{Fold, HasInterner, SuperVisit, Visit, Zip}; -use std::iter; use std::marker::PhantomData; pub use crate::debug::SeparatorTraitRef; +/// Uninhabited (empty) type, used in combination with `PhantomData`. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Void {} @@ -63,34 +66,66 @@ pub mod debug; /// The set of assumptions we've made so far, and the current number of /// universal (forall) quantifiers we're within. pub struct Environment { + /// The clauses in the environment. pub clauses: ProgramClauses, } +impl Copy for Environment where I::InternedProgramClauses: Copy {} + impl Environment { + /// Creates a new environment. pub fn new(interner: &I) -> Self { Environment { - clauses: ProgramClauses::new(interner), + clauses: ProgramClauses::empty(interner), } } + /// Adds (an iterator of) clauses to the environment. pub fn add_clauses(&self, interner: &I, clauses: II) -> Self where II: IntoIterator>, { let mut env = self.clone(); env.clauses = - ProgramClauses::from(interner, env.clauses.iter(interner).cloned().chain(clauses)); + ProgramClauses::from_iter(interner, env.clauses.iter(interner).cloned().chain(clauses)); env } + + /// True if any of the clauses in the environment have a consequence of `Compatible`. + /// Panics if the conditions or constraints of that clause are not empty. + pub fn has_compatible_clause(&self, interner: &I) -> bool { + self.clauses.as_slice(interner).iter().any(|c| { + let ProgramClauseData(implication) = c.data(interner); + match implication.skip_binders().consequence { + DomainGoal::Compatible => { + // We currently don't generate `Compatible` with any conditions or constraints + // If this was needed, for whatever reason, then a third "yes, but must evaluate" + // return value would have to be added. + assert!(implication.skip_binders().conditions.is_empty(interner)); + assert!(implication.skip_binders().constraints.is_empty(interner)); + true + } + _ => false, + } + }) + } } +/// A goal with an environment to solve it in. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit)] +#[allow(missing_docs)] pub struct InEnvironment { pub environment: Environment, pub goal: G, } +impl + Copy, I: Interner> Copy for InEnvironment where + I::InternedProgramClauses: Copy +{ +} + impl InEnvironment { + /// Creates a new environment/goal pair. pub fn new(environment: &Environment, goal: G) -> Self { InEnvironment { environment: environment.clone(), @@ -98,6 +133,7 @@ impl InEnvironment { } } + /// Maps the goal without touching the environment. pub fn map(self, op: OP) -> InEnvironment where OP: FnOnce(G) -> H, @@ -114,7 +150,9 @@ impl HasInterner for InEnvironment { type Interner = G::Interner; } +/// Different signed int types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(missing_docs)] pub enum IntTy { Isize, I8, @@ -124,7 +162,9 @@ pub enum IntTy { I128, } +/// Different unsigned int types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(missing_docs)] pub enum UintTy { Usize, U8, @@ -134,13 +174,17 @@ pub enum UintTy { U128, } +/// Different kinds of float types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(missing_docs)] pub enum FloatTy { F32, F64, } +/// Types of scalar values. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(missing_docs)] pub enum Scalar { Bool, Char, @@ -149,12 +193,25 @@ pub enum Scalar { Float(FloatTy), } +/// Whether a function is safe or not. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Safety { + /// Safe + Safe, + /// Unsafe + Unsafe, +} + +/// Whether a type is mutable or not. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Mutability { + /// Mutable Mut, + /// Immutable Not, } +/// Different kinds of Rust types. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Fold, Visit)] pub enum TypeName { /// Abstract data types, i.e., structs, unions, or enumerations. @@ -215,20 +272,25 @@ impl HasInterner for TypeName { /// See https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference.html#placeholders-and-universes for more. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct UniverseIndex { + /// The counter for the universe index, starts with 0. pub counter: usize, } impl UniverseIndex { + /// Root universe index (0). pub const ROOT: UniverseIndex = UniverseIndex { counter: 0 }; + /// Root universe index (0). pub fn root() -> UniverseIndex { Self::ROOT } + /// Whether one universe can "see" another. pub fn can_see(self, ui: UniverseIndex) -> bool { self.counter >= ui.counter } + /// Increases the index counter. pub fn next(self) -> UniverseIndex { UniverseIndex { counter: self.counter + 1, @@ -250,6 +312,7 @@ pub struct UniverseMap { } impl UniverseMap { + /// Creates a new universe map. pub fn new() -> Self { UniverseMap { universes: vec![UniverseIndex::root()], @@ -261,6 +324,8 @@ impl UniverseMap { self.universes.len() } } + +/// The id for an Abstract Data Type (i.e. structs, unions and enums). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AdtId(pub I::InternedAdtId); @@ -271,9 +336,11 @@ pub struct AdtId(pub I::InternedAdtId); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TraitId(pub I::DefId); +/// The id for an impl. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ImplId(pub I::DefId); +/// Id for a specific clause. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ClauseId(pub I::DefId); @@ -284,41 +351,50 @@ pub struct ClauseId(pub I::DefId); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AssocTypeId(pub I::DefId); +/// Id for an opaque type. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct OpaqueTyId(pub I::DefId); +/// Function definition id. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FnDefId(pub I::DefId); +/// Id for Rust closures. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ClosureId(pub I::DefId); impl_debugs!(ImplId, ClauseId); +/// A Rust type. The actual type data is stored in `TyData`. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct Ty { interned: I::InternedType, } impl Ty { + /// Creates a type from `TyData`. pub fn new(interner: &I, data: impl CastTo>) -> Self { Ty { interned: I::intern_ty(interner, data.cast(interner)), } } + /// Gets the interned type. pub fn interned(&self) -> &I::InternedType { &self.interned } + /// Gets the underlying type data. pub fn data(&self, interner: &I) -> &TyData { I::ty_data(interner, &self.interned) } + /// Creates a `FromEnv` constraint using this type. pub fn from_env(&self) -> FromEnv { FromEnv::Ty(self.clone()) } + /// Creates a WF-constraint for this type. pub fn well_formed(&self) -> WellFormed { WellFormed::Ty(self.clone()) } @@ -346,14 +422,21 @@ impl Ty { } } - /// Returns true if this is a `BoundVar` or `InferenceVar`. - pub fn is_var(&self, interner: &I) -> bool { + /// Returns true if this is a `BoundVar` or an `InferenceVar` of `TyKind::General`. + pub fn is_general_var(&self, interner: &I, binders: &CanonicalVarKinds) -> bool { match self.data(interner) { - TyData::BoundVar(_) | TyData::InferenceVar(_, _) => true, + TyData::BoundVar(bv) + if bv.debruijn == DebruijnIndex::INNERMOST + && binders.at(interner, bv.index).kind == VariableKind::Ty(TyKind::General) => + { + true + } + TyData::InferenceVar(_, TyKind::General) => true, _ => false, } } + /// Returns true if this is an `Alias`. pub fn is_alias(&self, interner: &I) -> bool { match self.data(interner) { TyData::Alias(..) => true, @@ -361,7 +444,7 @@ impl Ty { } } - /// Returns true if this is an `IntTy` or `UintTy` + /// Returns true if this is an `IntTy` or `UintTy`. pub fn is_integer(&self, interner: &I) -> bool { match self.data(interner) { TyData::Apply(ApplicationTy { @@ -376,7 +459,7 @@ impl Ty { } } - /// Returns true if this is a `FloatTy` + /// Returns true if this is a `FloatTy`. pub fn is_float(&self, interner: &I) -> bool { match self.data(interner) { TyData::Apply(ApplicationTy { @@ -395,6 +478,7 @@ impl Ty { } } +/// Type data, which holds the actual type information. #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub enum TyData { /// An "application" type is one that applies the set of type @@ -404,7 +488,7 @@ pub enum TyData { /// an empty list). Apply(ApplicationTy), - /// instantiated form a universally quantified type, e.g., from + /// instantiated from a universally quantified type, e.g., from /// `forall { .. }`. Stands in as a representative of "some /// unknown type". Placeholder(PlaceholderIndex), @@ -428,7 +512,7 @@ pub enum TyData { /// Note that "higher-ranked" types (starting with `for<>`) are either /// function types or dyn types, and do not appear otherwise in Rust /// surface syntax. - Function(Fn), + Function(FnPointer), /// References the binding at the given depth. The index is a [de /// Bruijn index], so it counts back through the in-scope binders. @@ -438,7 +522,17 @@ pub enum TyData { InferenceVar(InferenceVar, TyKind), } +impl Copy for TyData +where + I::InternedLifetime: Copy, + I::InternedSubstitution: Copy, + I::InternedVariableKinds: Copy, + I::InternedQuantifiedWhereClauses: Copy, +{ +} + impl TyData { + /// Casts the type data to a type. pub fn intern(self, interner: &I) -> Ty { Ty::new(interner, self) } @@ -470,23 +564,29 @@ impl TyData { /// indices identify the location *within* that binder. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct BoundVar { + /// Debruijn index, which identifies the binder. pub debruijn: DebruijnIndex, + /// Index within the binder. pub index: usize, } impl BoundVar { + /// Creates a new bound variable. pub fn new(debruijn: DebruijnIndex, index: usize) -> Self { Self { debruijn, index } } + /// Casts the bound variable to a type. pub fn to_ty(self, interner: &I) -> Ty { TyData::::BoundVar(self).intern(interner) } + /// Wrap the bound variable in a lifetime. pub fn to_lifetime(self, interner: &I) -> Lifetime { LifetimeData::::BoundVar(self).intern(interner) } + /// Wraps the bound variable in a constant. pub fn to_const(self, interner: &I, ty: Ty) -> Const { ConstData { ty, @@ -559,13 +659,18 @@ pub struct DebruijnIndex { } impl DebruijnIndex { + /// Innermost index. pub const INNERMOST: DebruijnIndex = DebruijnIndex { depth: 0 }; + /// One level higher than the innermost index. pub const ONE: DebruijnIndex = DebruijnIndex { depth: 1 }; + /// Creates a new de Bruijn index with a given depth. pub fn new(depth: u32) -> Self { DebruijnIndex { depth } } + /// Depth of the De Bruijn index, counting from 0 starting with + /// the innermost binder. pub fn depth(self) -> u32 { self.depth } @@ -685,10 +790,10 @@ impl DebruijnIndex { /// A "DynTy" represents a trait object (`dyn Trait`). Trait objects /// are conceptually very related to an "existential type" of the form -/// `exists { T: Trait }` (another exaple of such type is `impl Trait`). +/// `exists { T: Trait }` (another example of such type is `impl Trait`). /// `DynTy` represents the bounds on that type. /// -/// The "binder" here represents the unknown self type. So, a type like +/// The "bounds" here represents the unknown self type. So, a type like /// `dyn for<'a> Fn(&'a u32)` would be represented with two-levels of /// binder, as "depicted" here: /// @@ -708,10 +813,21 @@ impl DebruijnIndex { /// level of binder). #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct DynTy { + /// The unknown self type. pub bounds: Binders>, + /// Lifetime of the `DynTy`. pub lifetime: Lifetime, } +impl Copy for DynTy +where + I::InternedLifetime: Copy, + I::InternedQuantifiedWhereClauses: Copy, + I::InternedVariableKinds: Copy, +{ +} + +/// A type, lifetime or constant whose value is being inferred. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct InferenceVar { index: u32, @@ -724,18 +840,22 @@ impl From for InferenceVar { } impl InferenceVar { + /// Gets the underlying index value. pub fn index(self) -> u32 { self.index } + /// Wraps the inference variable in a type. pub fn to_ty(self, interner: &I, kind: TyKind) -> Ty { TyData::::InferenceVar(self, kind).intern(interner) } + /// Wraps the inference variable in a lifetime. pub fn to_lifetime(self, interner: &I) -> Lifetime { LifetimeData::::InferenceVar(self).intern(interner) } + /// Wraps the inference variable in a constant. pub fn to_const(self, interner: &I, ty: Ty) -> Const { ConstData { ty, @@ -748,27 +868,37 @@ impl InferenceVar { /// for<'a...'z> X -- all binders are instantiated at once, /// and we use deBruijn indices within `self.ty` #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] -pub struct Fn { +#[allow(missing_docs)] +pub struct FnPointer { pub num_binders: usize, + pub abi: I::FnAbi, + pub safety: Safety, + pub variadic: bool, pub substitution: Substitution, } -#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] +impl Copy for FnPointer where I::InternedSubstitution: Copy {} + +/// Constants. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct Const { interned: I::InternedConst, } impl Const { + /// Create a `Const` using something that can be cast to const data. pub fn new(interner: &I, data: impl CastTo>) -> Self { Const { interned: I::intern_const(interner, data.cast(interner)), } } + /// Gets the interned constant. pub fn interned(&self) -> &I::InternedConst { &self.interned } + /// Gets the constant data from the interner. pub fn data(&self, interner: &I) -> &ConstData { I::const_data(interner, &self.interned) } @@ -803,53 +933,73 @@ impl Const { } } +/// Constant data, containing the constant's type and value. #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub struct ConstData { + /// Type that holds the constant. pub ty: Ty, + /// The value of the constant. pub value: ConstValue, } +/// A constant value, not necessarily concrete. #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub enum ConstValue { + /// Bound var (e.g. a parameter). BoundVar(BoundVar), + /// Constant whose value is being inferred. InferenceVar(InferenceVar), + /// Lifetime on some yet-unknown placeholder. Placeholder(PlaceholderIndex), + /// Concrete constant value. Concrete(ConcreteConst), } +impl Copy for ConstValue where I::InternedConcreteConst: Copy {} + impl ConstData { + /// Wraps the constant data in a `Const`. pub fn intern(self, interner: &I) -> Const { Const::new(interner, self) } } -#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] +/// Concrete constant, whose value is known (as opposed to +/// inferred constants and placeholders). +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct ConcreteConst { + /// The interned constant. pub interned: I::InternedConcreteConst, } impl ConcreteConst { + /// Checks whether two concrete constants are equal. pub fn const_eq(&self, ty: &Ty, other: &ConcreteConst, interner: &I) -> bool { interner.const_eq(&ty.interned, &self.interned, &other.interned) } } +/// A Rust lifetime. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct Lifetime { interned: I::InternedLifetime, } impl Lifetime { + /// Create a lifetime from lifetime data + /// (or something that can be cast to lifetime data). pub fn new(interner: &I, data: impl CastTo>) -> Self { Lifetime { interned: I::intern_lifetime(interner, data.cast(interner)), } } + /// Gets the interned value. pub fn interned(&self) -> &I::InternedLifetime { &self.interned } + /// Gets the lifetime data. pub fn data(&self, interner: &I) -> &LifetimeData { I::lifetime_data(interner, &self.interned) } @@ -884,16 +1034,21 @@ impl Lifetime { } } +/// Lifetime data, including what kind of lifetime it is and what it points to. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub enum LifetimeData { - /// See TyData::Var(_). + /// See TyData::BoundVar. BoundVar(BoundVar), + /// Lifetime whose value is being inferred. InferenceVar(InferenceVar), + /// Lifetime on some yet-unknown placeholder. Placeholder(PlaceholderIndex), + /// Lifetime on phantom data. Phantom(Void, PhantomData), } impl LifetimeData { + /// Wrap the lifetime data in a lifetime. pub fn intern(self, interner: &I) -> Lifetime { Lifetime::new(interner, self) } @@ -911,14 +1066,17 @@ pub struct PlaceholderIndex { } impl PlaceholderIndex { + /// Wrap the placeholder instance in a lifetime. pub fn to_lifetime(self, interner: &I) -> Lifetime { LifetimeData::::Placeholder(self).intern(interner) } + /// Create an interned type. pub fn to_ty(self, interner: &I) -> Ty { TyData::Placeholder(self).intern(interner) } + /// Wrap the placeholder index in a constant. pub fn to_const(self, interner: &I, ty: Ty) -> Const { ConstData { ty, @@ -928,18 +1086,25 @@ impl PlaceholderIndex { } } -// Fold derive intentionally omitted, folded through Ty +/// Normal Rust types, containing the type name and zero or more generic arguments. +/// For example, in `Vec` those would be `Vec` and `[u32]` respectively. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct ApplicationTy { + /// The type name. pub name: TypeName, + /// The substitution containing the generic arguments. pub substitution: Substitution, } +impl Copy for ApplicationTy where I::InternedSubstitution: Copy {} + impl ApplicationTy { + /// Create an interned type from this application type. pub fn intern(self, interner: &I) -> Ty { Ty::new(interner, self) } + /// Gets an iterator of all type parameters. pub fn type_parameters<'a>(&'a self, interner: &'a I) -> impl Iterator> + 'a { self.substitution .iter(interner) @@ -947,10 +1112,12 @@ impl ApplicationTy { .cloned() } + /// Gets the first type parameter. pub fn first_type_parameter(&self, interner: &I) -> Option> { self.type_parameters(interner).next() } + /// Gets the number of type parameters. pub fn len_type_parameters(&self, interner: &I) -> usize { self.type_parameters(interner).count() } @@ -967,19 +1134,28 @@ impl ApplicationTy { /// `Index` impl for. `i` would have a `TyKind` of `Integer` to guide the /// inference process. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] pub enum TyKind { General, Integer, Float, } +/// The "kind" of variable. Type, lifetime or constant. #[derive(Clone, PartialEq, Eq, Hash)] +#[allow(missing_docs)] pub enum VariableKind { Ty(TyKind), Lifetime, Const(Ty), } +impl interner::HasInterner for VariableKind { + type Interner = I; +} + +impl Copy for VariableKind where I::InternedType: Copy {} + impl VariableKind { fn to_bound_variable(&self, interner: &I, bound_var: BoundVar) -> GenericArg { match self { @@ -1002,37 +1178,45 @@ impl VariableKind { } } +/// A generic argument, see `GenericArgData` for more information. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct GenericArg { interned: I::InternedGenericArg, } impl GenericArg { + /// Constructs a generic argument using `GenericArgData`. pub fn new(interner: &I, data: GenericArgData) -> Self { let interned = I::intern_generic_arg(interner, data); GenericArg { interned } } + /// Gets the interned value. pub fn interned(&self) -> &I::InternedGenericArg { &self.interned } + /// Gets the underlying data. pub fn data(&self, interner: &I) -> &GenericArgData { I::generic_arg_data(interner, &self.interned) } + /// Asserts that this is a type argument. pub fn assert_ty_ref(&self, interner: &I) -> &Ty { self.ty(interner).unwrap() } + /// Asserts that this is a lifetime argument. pub fn assert_lifetime_ref(&self, interner: &I) -> &Lifetime { self.lifetime(interner).unwrap() } + /// Asserts that this is a constant argument. pub fn assert_const_ref(&self, interner: &I) -> &Const { self.constant(interner).unwrap() } + /// Checks whether the generic argument is a type. pub fn is_ty(&self, interner: &I) -> bool { match self.data(interner) { GenericArgData::Ty(_) => true, @@ -1041,6 +1225,7 @@ impl GenericArg { } } + /// Returns the type if it is one, `None` otherwise. pub fn ty(&self, interner: &I) -> Option<&Ty> { match self.data(interner) { GenericArgData::Ty(t) => Some(t), @@ -1048,6 +1233,7 @@ impl GenericArg { } } + /// Returns the lifetime if it is one, `None` otherwise. pub fn lifetime(&self, interner: &I) -> Option<&Lifetime> { match self.data(interner) { GenericArgData::Lifetime(t) => Some(t), @@ -1055,6 +1241,7 @@ impl GenericArg { } } + /// Returns the constant if it is one, `None` otherwise. pub fn constant(&self, interner: &I) -> Option<&Const> { match self.data(interner) { GenericArgData::Const(c) => Some(c), @@ -1063,25 +1250,43 @@ impl GenericArg { } } +/// Generic arguments data. #[derive(Clone, PartialEq, Eq, Hash, Visit, Fold, Zip)] pub enum GenericArgData { + /// Type argument Ty(Ty), + /// Lifetime argument Lifetime(Lifetime), + /// Constant argument Const(Const), } +impl Copy for GenericArgData +where + I::InternedType: Copy, + I::InternedLifetime: Copy, + I::InternedConst: Copy, +{ +} + impl GenericArgData { + /// Create an interned type. pub fn intern(self, interner: &I) -> GenericArg { GenericArg::new(interner, self) } } +/// A value with an associated variable kind. #[derive(Clone, PartialEq, Eq, Hash)] pub struct WithKind { + /// The associated variable kind. pub kind: VariableKind, + /// The wrapped value. value: T, } +impl Copy for WithKind where I::InternedType: Copy {} + impl HasInterner for WithKind { type Interner = I; } @@ -1093,10 +1298,12 @@ impl From> for (VariableKind, T) { } impl WithKind { + /// Creates a `WithKind` from a variable kind and a value. pub fn new(kind: VariableKind, value: T) -> Self { Self { kind, value } } + /// Maps the value in `WithKind`. pub fn map(self, op: OP) -> WithKind where OP: FnOnce(T) -> U, @@ -1107,6 +1314,7 @@ impl WithKind { } } + /// Maps a function taking `WithKind` over `&WithKind`. pub fn map_ref(&self, op: OP) -> WithKind where OP: FnOnce(&T) -> U, @@ -1117,25 +1325,34 @@ impl WithKind { } } + /// Extract the value, ignoring the variable kind. pub fn skip_kind(&self) -> &T { &self.value } } +/// A variable kind with universe index. #[allow(type_alias_bounds)] pub type CanonicalVarKind = WithKind; +/// An alias, which is a trait indirection such as a projection or opaque type. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub enum AliasTy { + /// An associated type projection. Projection(ProjectionTy), + /// An opaque type. Opaque(OpaqueTy), } +impl Copy for AliasTy where I::InternedSubstitution: Copy {} + impl AliasTy { + /// Create an interned type for this alias. pub fn intern(self, interner: &I) -> Ty { Ty::new(interner, self) } + /// Gets the type parameters of the `Self` type in this alias type. pub fn self_type_parameter(&self, interner: &I) -> Ty { match self { AliasTy::Projection(projection_ty) => projection_ty @@ -1149,25 +1366,46 @@ impl AliasTy { } } +/// A projection `>::AssocItem`. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct ProjectionTy { + /// The id for the associated type member. pub associated_ty_id: AssocTypeId, + /// The substitution for the projection. pub substitution: Substitution, } +impl Copy for ProjectionTy where I::InternedSubstitution: Copy {} + +/// An opaque type `opaque type T<..>: Trait = HiddenTy`. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct OpaqueTy { + /// The id for the opaque type. pub opaque_ty_id: OpaqueTyId, + /// The substitution for the opaque type. pub substitution: Substitution, } +impl Copy for OpaqueTy where I::InternedSubstitution: Copy {} + +/// A trait reference describes the relationship between a type and a trait. +/// This can be used in two forms: +/// - `P0: Trait` (e.g. `i32: Copy`), which mentions that the type +/// implements the trait. +/// - `>` (e.g. `i32 as Copy`), which casts the type to +/// that specific trait. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct TraitRef { + /// The trait id. pub trait_id: TraitId, + /// The substitution, containing both the `Self` type and the parameters. pub substitution: Substitution, } +impl Copy for TraitRef where I::InternedSubstitution: Copy {} + impl TraitRef { + /// Gets all type parameters in this trait ref, including `Self`. pub fn type_parameters<'a>(&'a self, interner: &'a I) -> impl Iterator> + 'a { self.substitution .iter(interner) @@ -1175,32 +1413,72 @@ impl TraitRef { .cloned() } + /// Gets the type parameters of the `Self` type in this trait ref. pub fn self_type_parameter(&self, interner: &I) -> Ty { self.type_parameters(interner).next().unwrap() } + /// Construct a `FromEnv` using this trait ref. pub fn from_env(self) -> FromEnv { FromEnv::Trait(self) } + /// Construct a `WellFormed` using this trait ref. pub fn well_formed(self) -> WellFormed { WellFormed::Trait(self) } } +/// Lifetime outlives, which for `'a: 'b`` checks that the lifetime `'a` +/// is a superset of the value of `'b`. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] +#[allow(missing_docs)] pub struct LifetimeOutlives { pub a: Lifetime, pub b: Lifetime, } + +impl Copy for LifetimeOutlives where I::InternedLifetime: Copy {} + +/// Type outlives, which for `T: 'a` checks that the type `T` +/// lives at least as long as the lifetime `'a` +#[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] +pub struct TypeOutlives { + /// The type which must outlive the given lifetime. + pub ty: Ty, + /// The lifetime which the type must outlive. + pub lifetime: Lifetime, +} + +impl Copy for TypeOutlives +where + I::InternedLifetime: Copy, + I::InternedType: Copy, +{ +} + /// Where clauses that can be written by a Rust programmer. #[derive(Clone, PartialEq, Eq, Hash, Fold, SuperVisit, HasInterner, Zip)] pub enum WhereClause { + /// Type implements a trait. Implemented(TraitRef), + /// Type is equal to an alias. AliasEq(AliasEq), + /// One lifetime outlives another. LifetimeOutlives(LifetimeOutlives), + /// Type outlives a lifetime. + TypeOutlives(TypeOutlives), } +impl Copy for WhereClause +where + I::InternedSubstitution: Copy, + I::InternedLifetime: Copy, + I::InternedType: Copy, +{ +} + +/// Checks whether a type or trait ref is well-formed. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub enum WellFormed { /// A predicate which is true when some trait ref is well-formed. @@ -1231,6 +1509,14 @@ pub enum WellFormed { Ty(Ty), } +impl Copy for WellFormed +where + I::InternedType: Copy, + I::InternedSubstitution: Copy, +{ +} + +/// Checks whether a type or trait ref can be derived from the contents of the environment. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub enum FromEnv { /// A predicate which enables deriving everything which should be true if we *know* that @@ -1260,17 +1546,28 @@ pub enum FromEnv { Ty(Ty), } +impl Copy for FromEnv +where + I::InternedType: Copy, + I::InternedSubstitution: Copy, +{ +} + /// A "domain goal" is a goal that is directly about Rust, rather than a pure /// logical statement. As much as possible, the Chalk solver should avoid /// decomposing this enum, and instead treat its values opaquely. #[derive(Clone, PartialEq, Eq, Hash, Fold, SuperVisit, HasInterner, Zip)] pub enum DomainGoal { + /// Simple goal that is true if the where clause is true. Holds(WhereClause), + /// True if the type or trait ref is well-formed. WellFormed(WellFormed), + /// True if the trait ref can be derived from in-scope where clauses. FromEnv(FromEnv), + /// True if the alias type can be normalized to some other type Normalize(Normalize), /// True if a type is considered to have been "defined" by the current crate. This is true for @@ -1310,9 +1607,7 @@ pub enum DomainGoal { /// Used to activate the "compatible modality" rules. Rules that introduce predicates that have /// to do with "all compatible universes" should depend on this clause so that they only apply /// if this is present. - /// - /// (HACK: Having `()` makes some of our macros work better.) - Compatible(()), + Compatible, /// Used to indicate that a given type is in a downstream crate. Downstream crates contain the /// current crate at some level of their dependencies. @@ -1327,12 +1622,21 @@ pub enum DomainGoal { /// Used to activate the "reveal mode", in which opaque (`impl Trait`) types can be equated /// to their actual type. - Reveal(()), + Reveal, /// Used to indicate that a trait is object safe. ObjectSafe(TraitId), } +impl Copy for DomainGoal +where + I::InternedSubstitution: Copy, + I::InternedLifetime: Copy, + I::InternedType: Copy, +{ +} + +/// A where clause that can contain `forall<>` or `exists<>` quantifiers. pub type QuantifiedWhereClause = Binders>; impl WhereClause { @@ -1355,12 +1659,13 @@ impl WhereClause { } } - /// If where clause is a `TraitRef`, returns its trait id + /// If where clause is a `TraitRef`, returns its trait id. pub fn trait_id(&self) -> Option> { match self { WhereClause::Implemented(trait_ref) => Some(trait_ref.trait_id), WhereClause::AliasEq(_) => None, WhereClause::LifetimeOutlives(_) => None, + WhereClause::TypeOutlives(_) => None, } } } @@ -1382,69 +1687,12 @@ impl QuantifiedWhereClause { self.map(|wc| wc.into_from_env_goal(interner)) } - /// If the underlying where clause is a `TraitRef`, returns its trait id + /// If the underlying where clause is a `TraitRef`, returns its trait id. pub fn trait_id(&self) -> Option> { self.skip_binders().trait_id() } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] -pub struct QuantifiedWhereClauses { - interned: I::InternedQuantifiedWhereClauses, -} - -impl QuantifiedWhereClauses { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedQuantifiedWhereClauses { - &self.interned - } - - pub fn from( - interner: &I, - clauses: impl IntoIterator>>, - ) -> Self { - Self::from_fallible( - interner, - clauses - .into_iter() - .map(|p| -> Result, ()> { Ok(p.cast(interner)) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - clauses: impl IntoIterator>, E>>, - ) -> Result { - use crate::cast::Caster; - Ok(QuantifiedWhereClauses { - interned: I::intern_quantified_where_clauses( - interner, - clauses.into_iter().casted(interner), - )?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, QuantifiedWhereClause> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[QuantifiedWhereClause] { - interner.quantified_where_clauses_data(&self.interned) - } -} - impl DomainGoal { /// Convert `Implemented(...)` into `FromEnv(...)`, but leave other /// goals unchanged. @@ -1455,6 +1703,7 @@ impl DomainGoal { } } + /// Lists generic arguments that are inputs to this domain goal. pub fn inputs(&self, interner: &I) -> Vec> { match self { DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => { @@ -1465,29 +1714,49 @@ impl DomainGoal { } } +/// Equality goal: tries to prove that two values are equal. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, Zip)] +#[allow(missing_docs)] pub struct EqGoal { pub a: GenericArg, pub b: GenericArg, } +impl Copy for EqGoal where I::InternedGenericArg: Copy {} + /// Proves that the given type alias **normalizes** to the given /// type. A projection `T::Foo` normalizes to the type `U` if we can /// **match it to an impl** and that impl has a `type Foo = V` where /// `U = V`. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, Zip)] +#[allow(missing_docs)] pub struct Normalize { pub alias: AliasTy, pub ty: Ty, } +impl Copy for Normalize +where + I::InternedSubstitution: Copy, + I::InternedType: Copy, +{ +} + /// Proves **equality** between an alias and a type. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, Zip)] +#[allow(missing_docs)] pub struct AliasEq { pub alias: AliasTy, pub ty: Ty, } +impl Copy for AliasEq +where + I::InternedSubstitution: Copy, + I::InternedType: Copy, +{ +} + impl HasInterner for AliasEq { type Interner = I; } @@ -1501,15 +1770,24 @@ impl HasInterner for AliasEq { /// of `self.binders`.) #[derive(Clone, PartialEq, Eq, Hash)] pub struct Binders { + /// The binders that quantify over the value. pub binders: VariableKinds, + + /// The value being quantified over. value: T, } +impl Copy for Binders where + ::InternedVariableKinds: Copy +{ +} + impl HasInterner for Binders { type Interner = T::Interner; } impl Binders { + /// Create new binders. pub fn new(binders: VariableKinds, value: T) -> Self { Self { binders, value } } @@ -1518,7 +1796,7 @@ impl Binders { /// (value)`. Since our deBruijn indices count binders, not variables, this /// is sometimes useful. pub fn empty(interner: &T::Interner, value: T) -> Self { - let binders = VariableKinds::new(interner); + let binders = VariableKinds::empty(interner); Self { binders, value } } @@ -1547,6 +1825,7 @@ impl Binders { } } + /// Maps the binders by applying a function. pub fn map(self, op: OP) -> Binders where OP: FnOnce(T) -> U, @@ -1573,6 +1852,7 @@ impl Binders { }) } + /// Maps a function taking `Binders<&T>` over `&Binders`. pub fn map_ref<'a, U, OP>(&'a self, op: OP) -> Binders where OP: FnOnce(&'a T) -> U, @@ -1585,12 +1865,12 @@ impl Binders { /// substitution will not change the value, i.e. `^0.0, ^0.1, ^0.2` and so /// on. pub fn identity_substitution(&self, interner: &T::Interner) -> Substitution { - Substitution::from( + Substitution::from_iter( interner, self.binders .iter(interner) .enumerate() - .map(|(i, pk)| (pk, i).to_generic_arg(interner)), + .map(|p| p.to_generic_arg(interner)), ) } @@ -1607,10 +1887,11 @@ impl Binders { // The new variable is at the front and everything afterwards is shifted up by 1 let new_var = TyData::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(interner); let value = op(new_var); - let binders = VariableKinds::from(interner, iter::once(VariableKind::Ty(TyKind::General))); + let binders = VariableKinds::from1(interner, VariableKind::Ty(TyKind::General)); Binders { binders, value } } + /// Returns the number of binders. pub fn len(&self, interner: &T::Interner) -> usize { self.binders.len(interner) } @@ -1626,16 +1907,16 @@ where pub fn fuse_binders(self, interner: &T::Interner) -> Binders { let num_binders = self.len(interner); // generate a substitution to shift the indexes of the inner binder: - let subst = Substitution::from( + let subst = Substitution::from_iter( interner, self.value .binders .iter(interner) .enumerate() - .map(|(i, pk)| (pk, i + num_binders).to_generic_arg(interner)), + .map(|(i, pk)| (i + num_binders, pk).to_generic_arg(interner)), ); let value = self.value.substitute(interner, &subst); - let binders = VariableKinds::from( + let binders = VariableKinds::from_iter( interner, self.binders .iter(interner) @@ -1690,6 +1971,7 @@ where } } +/// `IntoIterator` for binders. pub struct BindersIntoIterator { iter: ::IntoIter, binders: VariableKinds, @@ -1713,14 +1995,26 @@ where /// conditions. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct ProgramClauseImplication { + /// The consequence of the clause, which holds if the conditions holds. pub consequence: DomainGoal, + + /// The condition goals that should hold. pub conditions: Goals, + + /// The lifetime constraints that should be proven. + pub constraints: Constraints, + + /// The relative priority of the implication. pub priority: ClausePriority, } +/// Specifies how important an implication is. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum ClausePriority { + /// High priority, the solver should prioritize this. High, + + /// Low priority, this implication has lower chance to be relevant to the goal. Low, } @@ -1734,15 +2028,18 @@ impl std::ops::BitAnd for ClausePriority { } } +/// Contains the data for a program clause. #[derive(Clone, PartialEq, Eq, Hash, Fold, HasInterner, Zip)] pub struct ProgramClauseData(pub Binders>); impl ProgramClauseImplication { + /// Change the implication into an application holding a `FromEnv` goal. pub fn into_from_env_clause(self, interner: &I) -> ProgramClauseImplication { if self.conditions.is_empty(interner) { ProgramClauseImplication { consequence: self.consequence.into_from_env_goal(interner), conditions: self.conditions.clone(), + constraints: self.constraints.clone(), priority: self.priority, } } else { @@ -1752,10 +2049,12 @@ impl ProgramClauseImplication { } impl ProgramClauseData { + /// Change the program clause data into a `FromEnv` program clause. pub fn into_from_env_clause(self, interner: &I) -> ProgramClauseData { ProgramClauseData(self.0.map(|i| i.into_from_env_clause(interner))) } + /// Intern the program clause data. pub fn intern(self, interner: &I) -> ProgramClause { ProgramClause { interned: interner.intern_program_clause(self), @@ -1763,189 +2062,37 @@ impl ProgramClauseData { } } +/// A program clause is a logic expression used to describe a part of the program. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct ProgramClause { interned: I::InternedProgramClause, } impl ProgramClause { + /// Create a new program clause using `ProgramClauseData`. pub fn new(interner: &I, clause: ProgramClauseData) -> Self { let interned = interner.intern_program_clause(clause); Self { interned } } + /// Change the clause into a `FromEnv` clause. pub fn into_from_env_clause(self, interner: &I) -> ProgramClause { let program_clause_data = self.data(interner); let new_clause = program_clause_data.clone().into_from_env_clause(interner); Self::new(interner, new_clause) } + /// Get the interned program clause. pub fn interned(&self) -> &I::InternedProgramClause { &self.interned } + /// Get the program clause data. pub fn data(&self, interner: &I) -> &ProgramClauseData { interner.program_clause_data(&self.interned) } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] -pub struct ProgramClauses { - interned: I::InternedProgramClauses, -} - -impl ProgramClauses { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedProgramClauses { - &self.interned - } - - pub fn from( - interner: &I, - clauses: impl IntoIterator>>, - ) -> Self { - Self::from_fallible( - interner, - clauses - .into_iter() - .map(|p| -> Result, ()> { Ok(p.cast(interner)) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - clauses: impl IntoIterator>, E>>, - ) -> Result { - use crate::cast::Caster; - Ok(ProgramClauses { - interned: I::intern_program_clauses(interner, clauses.into_iter().casted(interner))?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, ProgramClause> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[ProgramClause] { - interner.program_clauses_data(&self.interned) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] -pub struct VariableKinds { - interned: I::InternedVariableKinds, -} - -impl VariableKinds { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedVariableKinds { - &self.interned - } - - pub fn from(interner: &I, variable_kinds: impl IntoIterator>) -> Self { - Self::from_fallible( - interner, - variable_kinds - .into_iter() - .map(|p| -> Result, ()> { Ok(p) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - variable_kinds: impl IntoIterator, E>>, - ) -> Result { - Ok(VariableKinds { - interned: I::intern_generic_arg_kinds(interner, variable_kinds.into_iter())?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, VariableKind> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[VariableKind] { - interner.variable_kinds_data(&self.interned) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] -pub struct CanonicalVarKinds { - interned: I::InternedCanonicalVarKinds, -} - -impl CanonicalVarKinds { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedCanonicalVarKinds { - &self.interned - } - - pub fn from( - interner: &I, - variable_kinds: impl IntoIterator>, - ) -> Self { - Self::from_fallible( - interner, - variable_kinds - .into_iter() - .map(|p| -> Result, ()> { Ok(p) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - variable_kinds: impl IntoIterator, E>>, - ) -> Result { - Ok(CanonicalVarKinds { - interned: I::intern_canonical_var_kinds(interner, variable_kinds.into_iter())?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, CanonicalVarKind> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[CanonicalVarKind] { - interner.canonical_var_kinds_data(&self.interned) - } -} - /// Wraps a "canonicalized item". Items are canonicalized as follows: /// /// All unresolved existential variables are "renumbered" according to their @@ -1953,7 +2100,10 @@ impl CanonicalVarKinds { /// `binders` field. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Canonical { + /// The item that is canonicalized. pub value: T, + + /// The kind/universe of the variable. pub binders: CanonicalVarKinds, } @@ -1969,11 +2119,16 @@ impl HasInterner for Canonical { /// To produce one of these values, use the `u_canonicalize` method. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct UCanonical { + /// The wrapped `Canonical`. pub canonical: Canonical, + + /// The number of universes that have been collapsed. pub universes: usize, } impl UCanonical { + /// Checks whether the universe canonical value is a trivial + /// substitution (e.g. an identity substitution). pub fn is_trivial_substitution( &self, interner: &T::Interner, @@ -1982,14 +2137,15 @@ impl UCanonical { let subst = &canonical_subst.value.subst; assert_eq!( self.canonical.binders.len(interner), - subst.parameters(interner).len() + subst.as_slice(interner).len() ); subst.is_identity_subst(interner) } + /// Creates an identity substitution. pub fn trivial_substitution(&self, interner: &T::Interner) -> Substitution { let binders = &self.canonical.binders; - Substitution::from( + Substitution::from_iter( interner, binders .iter(interner) @@ -2020,58 +2176,6 @@ impl UCanonical { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, HasInterner)] -/// A list of goals. -pub struct Goals { - interned: I::InternedGoals, -} - -impl Goals { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedGoals { - &self.interned - } - - pub fn from(interner: &I, goals: impl IntoIterator>>) -> Self { - Self::from_fallible( - interner, - goals - .into_iter() - .map(|p| -> Result, ()> { Ok(p.cast(interner)) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - goals: impl IntoIterator>, E>>, - ) -> Result { - use crate::cast::Caster; - Ok(Goals { - interned: I::intern_goals(interner, goals.into_iter().casted(interner))?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, Goal> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[Goal] { - interner.goals_data(&self.interned) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] /// A general goal; this is the full range of questions you can pose to Chalk. pub struct Goal { @@ -2079,19 +2183,23 @@ pub struct Goal { } impl Goal { + /// Create a new goal using `GoalData`. pub fn new(interner: &I, interned: GoalData) -> Self { let interned = I::intern_goal(interner, interned); Self { interned } } + /// Gets the interned goal. pub fn interned(&self) -> &I::InternedGoal { &self.interned } + /// Gets the interned goal data. pub fn data(&self, interner: &I) -> &GoalData { interner.goal_data(&self.interned) } + /// Create a goal using a `forall` or `exists` quantifier. pub fn quantify( self, interner: &I, @@ -2101,7 +2209,7 @@ impl Goal { GoalData::Quantified(kind, Binders::new(binders, self)).intern(interner) } - /// Takes a goal `G` and turns it into `not { G }` + /// Takes a goal `G` and turns it into `not { G }`. pub fn negate(self, interner: &I) -> Self { GoalData::Not(self).intern(interner) } @@ -2114,9 +2222,9 @@ impl Goal { QuantifierKind::ForAll, Binders::with_fresh_type_var(interner, |ty| { GoalData::Implies( - ProgramClauses::from( + ProgramClauses::from_iter( interner, - vec![DomainGoal::Compatible(()), DomainGoal::DownstreamType(ty)], + vec![DomainGoal::Compatible, DomainGoal::DownstreamType(ty)], ), self.shifted_in(interner), ) @@ -2126,6 +2234,7 @@ impl Goal { .intern(interner) } + /// Create an implication goal that holds if the predicates are true. pub fn implied_by(self, interner: &I, predicates: ProgramClauses) -> Goal { GoalData::Implies(predicates, self).intern(interner) } @@ -2144,6 +2253,7 @@ impl Goal where I: Interner, { + /// Creates a single goal that only holds if a list of goals holds. pub fn all(interner: &I, iter: II) -> Self where II: IntoIterator>, @@ -2152,7 +2262,7 @@ where if let Some(goal0) = iter.next() { if let Some(goal1) = iter.next() { // More than one goal to prove - let goals = Goals::from( + let goals = Goals::from_iter( interner, Some(goal0).into_iter().chain(Some(goal1)).chain(iter), ); @@ -2163,7 +2273,7 @@ where } } else { // No goals to prove, always true - GoalData::All(Goals::new(interner)).intern(interner) + GoalData::All(Goals::empty(interner)).intern(interner) } } } @@ -2174,8 +2284,14 @@ pub enum GoalData { /// Introduces a binding at depth 0, shifting other bindings up /// (deBruijn index). Quantified(QuantifierKind, Binders>), + + /// A goal that holds given some clauses (like an if-statement). Implies(ProgramClauses, Goal), + + /// List of goals that all should hold. All(Goals), + + /// Negation: the inner goal should not hold. Not(Goal), /// Make two things equal; the rules for doing so are well known to the logic @@ -2192,20 +2308,47 @@ pub enum GoalData { /// X, Y where `X = Y` is not true. But we treat it as "cannot /// prove" so that `forall { not { X = Y } }` also winds up /// as cannot prove. - /// - /// (TOTAL HACK: Having a unit result makes some of our macros work better.) - CannotProve(()), + CannotProve, +} + +impl Copy for GoalData +where + I::InternedType: Copy, + I::InternedLifetime: Copy, + I::InternedGenericArg: Copy, + I::InternedSubstitution: Copy, + I::InternedGoal: Copy, + I::InternedGoals: Copy, + I::InternedProgramClauses: Copy, + I::InternedVariableKinds: Copy, +{ } impl GoalData { + /// Create an interned goal. pub fn intern(self, interner: &I) -> Goal { Goal::new(interner, self) } } +/// Kinds of quantifiers in the logic, such as `forall` and `exists`. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum QuantifierKind { + /// Universal quantifier `ForAll`. + /// + /// A formula with the universal quantifier `forall(x). P(x)` is satisfiable + /// if and only if the subformula `P(x)` is true for all possible values for x. ForAll, + + /// Existential quantifier `Exists`. + /// + /// A formula with the existential quantifier `exists(x). P(x)` is satisfiable + /// if and only if there exists at least one value for all possible values of x + /// which satisfies the subformula `P(x)`. + + /// In the context of chalk, the existential quantifier usually demands the + /// existence of exactly one instance (i.e. type) that satisfies the formula + /// (i.e. type constraints). More than one instance means that the result is ambiguous. Exists, } @@ -2215,77 +2358,25 @@ pub enum QuantifierKind { /// lifetime constraints, instead gathering them up to return with our solution /// for later checking. This allows for decoupling between type and region /// checking in the compiler. -#[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] +#[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub enum Constraint { - Outlives(Lifetime, Lifetime), + /// Outlives constraint `'a: 'b`, indicating that the value of `'a` must be + /// a superset of the value of `'b`. + LifetimeOutlives(Lifetime, Lifetime), + + /// Type outlives constraint `T: 'a`, indicating that the type `T` must live + /// at least as long as the value of `'a`. + TypeOutlives(Ty, Lifetime), } -/// A mapping of inference variables to instantiations thereof. -#[derive(Copy, Clone, PartialEq, Eq, Hash, HasInterner)] -pub struct Substitution { - /// Map free variable with given index to the value with the same - /// index. Naturally, the kind of the variable must agree with - /// the kind of the value. - interned: I::InternedSubstitution, +impl Copy for Constraint +where + I::InternedLifetime: Copy, + I::InternedType: Copy, +{ } impl Substitution { - pub fn from( - interner: &I, - parameters: impl IntoIterator>>, - ) -> Self { - Self::from_fallible( - interner, - parameters - .into_iter() - .map(|p| -> Result, ()> { Ok(p.cast(interner)) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - parameters: impl IntoIterator>, E>>, - ) -> Result { - use crate::cast::Caster; - Ok(Substitution { - interned: I::intern_substitution(interner, parameters.into_iter().casted(interner))?, - }) - } - - pub fn interned(&self) -> &I::InternedSubstitution { - &self.interned - } - - /// Index into the list of parameters - pub fn at(&self, interner: &I, index: usize) -> &GenericArg { - &self.parameters(interner)[index] - } - - pub fn from1(interner: &I, parameter: impl CastTo>) -> Self { - Self::from(interner, Some(parameter)) - } - - pub fn empty(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.parameters(interner).is_empty() - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, GenericArg> { - self.parameters(interner).iter() - } - - pub fn parameters(&self, interner: &I) -> &[GenericArg] { - interner.substitution_data(&self.interned) - } - - pub fn len(&self, interner: &I) -> usize { - self.parameters(interner).len() - } - /// A substitution is an **identity substitution** if it looks /// like this /// @@ -2318,6 +2409,7 @@ impl Substitution { }) } + /// Apply the substitution to a value. pub fn apply(&self, value: &T, interner: &I) -> T::Result where T: Fold, @@ -2340,21 +2432,23 @@ struct SubstFolder<'i, I: Interner> { } impl SubstFolder<'_, I> { - /// Index into the list of parameters + /// Index into the list of parameters. pub fn at(&self, index: usize) -> &GenericArg { let interner = self.interner; - &self.subst.parameters(interner)[index] + &self.subst.as_slice(interner)[index] } } +/// Convert a value to a list of parameters. pub trait AsParameters { + /// Convert the current value to parameters. fn as_parameters(&self, interner: &I) -> &[GenericArg]; } impl AsParameters for Substitution { #[allow(unreachable_code, unused_variables)] fn as_parameters(&self, interner: &I) -> &[GenericArg] { - self.parameters(interner) + self.as_slice(interner) } } @@ -2385,22 +2479,24 @@ where } } +/// Utility for converting a list of all the binders into scope +/// into references to those binders. Simply pair the binders with +/// the indices, and invoke `to_generic_arg()` on the `(binder, +/// index)` pair. The result will be a reference to a bound +/// variable of appropriate kind at the corresponding index. pub trait ToGenericArg { - /// Utility for converting a list of all the binders into scope - /// into references to those binders. Simply pair the binders with - /// the indices, and invoke `to_generic_arg()` on the `(binder, - /// index)` pair. The result will be a reference to a bound - /// variable of appropriate kind at the corresponding index. + /// Converts the binders in scope to references to those binders. fn to_generic_arg(&self, interner: &I) -> GenericArg { self.to_generic_arg_at_depth(interner, DebruijnIndex::INNERMOST) } + /// Converts the binders at the specified depth to references to those binders. fn to_generic_arg_at_depth(&self, interner: &I, debruijn: DebruijnIndex) -> GenericArg; } -impl<'a, I: Interner> ToGenericArg for (&'a VariableKind, usize) { +impl<'a, I: Interner> ToGenericArg for (usize, &'a VariableKind) { fn to_generic_arg_at_depth(&self, interner: &I, debruijn: DebruijnIndex) -> GenericArg { - let &(binder, index) = self; + let &(index, binder) = self; let bound_var = BoundVar::new(debruijn, index); binder.to_bound_variable(interner, bound_var) } @@ -2454,6 +2550,122 @@ impl<'i, I: Interner> Folder<'i, I> for &SubstFolder<'i, I> { } } +macro_rules! interned_slice { + ($seq:ident, $data:ident => $elem:ty, $intern:ident => $interned:ident) => { + /// List of interned elements. + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] + pub struct $seq { + interned: I::$interned, + } + + impl $seq { + /// Get the interned elements. + pub fn interned(&self) -> &I::$interned { + &self.interned + } + } + + impl $seq { + /// Tries to create a sequence using an iterator of element-like things. + pub fn from_fallible( + interner: &I, + elements: impl IntoIterator, E>>, + ) -> Result { + Ok(Self { + interned: I::$intern(interner, elements.into_iter().casted(interner))?, + }) + } + + /// Returns a slice containing the elements. + pub fn as_slice(&self, interner: &I) -> &[$elem] { + Interner::$data(interner, &self.interned) + } + + /// Create a sequence from elements + pub fn from_iter( + interner: &I, + elements: impl IntoIterator>, + ) -> Self { + Self::from_fallible( + interner, + elements + .into_iter() + .map(|el| -> Result<$elem, ()> { Ok(el.cast(interner)) }), + ) + .unwrap() + } + + /// Index into the sequence. + pub fn at(&self, interner: &I, index: usize) -> &$elem { + &self.as_slice(interner)[index] + } + + /// Create a sequence from a single element. + pub fn from1(interner: &I, element: impl CastTo<$elem>) -> Self { + Self::from_iter(interner, Some(element)) + } + + /// Create an empty sequence. + pub fn empty(interner: &I) -> Self { + Self::from_iter(interner, None::<$elem>) + } + + /// Check whether this is an empty sequence. + pub fn is_empty(&self, interner: &I) -> bool { + self.as_slice(interner).is_empty() + } + + /// Get an iterator over the elements of the sequence. + pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, $elem> { + self.as_slice(interner).iter() + } + + /// Get the length of the sequence. + pub fn len(&self, interner: &I) -> usize { + self.as_slice(interner).len() + } + } + }; +} + +interned_slice!( + QuantifiedWhereClauses, + quantified_where_clauses_data => QuantifiedWhereClause, + intern_quantified_where_clauses => InternedQuantifiedWhereClauses +); + +interned_slice!( + ProgramClauses, + program_clauses_data => ProgramClause, + intern_program_clauses => InternedProgramClauses +); + +interned_slice!( + VariableKinds, + variable_kinds_data => VariableKind, + intern_generic_arg_kinds => InternedVariableKinds +); + +interned_slice!( + CanonicalVarKinds, + canonical_var_kinds_data => CanonicalVarKind, + intern_canonical_var_kinds => InternedCanonicalVarKinds +); + +interned_slice!(Goals, goals_data => Goal, intern_goals => InternedGoals); + +interned_slice!( + Constraints, + constraints_data => InEnvironment>, + intern_constraints => InternedConstraints +); + +interned_slice!( + Substitution, + substitution_data => GenericArg, + intern_substitution => InternedSubstitution +); + /// Combines a substitution (`subst`) with a set of region constraints /// (`constraints`). This represents the result of a query; the /// substitution stores the values for the query's unknown variables, @@ -2461,13 +2673,26 @@ impl<'i, I: Interner> Folder<'i, I> for &SubstFolder<'i, I> { /// additionally be solved. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] pub struct ConstrainedSubst { - pub subst: Substitution, /* NB: The `is_trivial` routine relies on the fact that `subst` is folded first. */ - pub constraints: Vec>>, + /// The substitution that is being constrained. + /// + /// NB: The `is_trivial` routine relies on the fact that `subst` is folded first. + pub subst: Substitution, + + /// Region constraints that constrain the substitution. + pub constraints: Constraints, } +/// The resulting substitution after solving a goal. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] pub struct AnswerSubst { - pub subst: Substitution, /* NB: The `is_trivial` routine relies on the fact that `subst` is folded first. */ - pub constraints: Vec>>, + /// The substitution result. + /// + /// NB: The `is_trivial` routine relies on the fact that `subst` is folded first. + pub subst: Substitution, + + /// List of constraints that are part of the answer. + pub constraints: Constraints, + + /// Delayed subgoals, used when the solver answered with an (incomplete) `Answer` (instead of a `CompleteAnswer`). pub delayed_subgoals: Vec>>, } diff --git a/vendor/chalk-ir-0.14.0/src/visit.rs b/vendor/chalk-ir-0.25.0/src/visit.rs similarity index 97% rename from vendor/chalk-ir-0.14.0/src/visit.rs rename to vendor/chalk-ir-0.25.0/src/visit.rs index 0568f3db8f..7612807dd6 100644 --- a/vendor/chalk-ir-0.14.0/src/visit.rs +++ b/vendor/chalk-ir-0.25.0/src/visit.rs @@ -17,12 +17,15 @@ pub use visitors::VisitExt; /// are doing. A common choice is `FindAny`, which indicates that the visitor /// is searching for something and that the visitor should stop once it is found. pub trait VisitResult: Sized { + /// Creates a new visitor result. fn new() -> Self; /// Returns true if this result is "complete" and we can stop visiting any /// further parts of the term. This is used by `FindAny`, for example, to /// stop the search after a match has been found. fn return_early(&self) -> bool; + + /// Combines two visitor results. fn combine(self, other: Self) -> Self; /// Convenience helper for use in writing `Visitor` impls. Returns `self` @@ -50,7 +53,7 @@ pub trait VisitResult: Sized { /// Unit type for a visitor indicates a "side-effecting" visitor that /// should visit an entire term. impl VisitResult for () { - fn new() -> () {} + fn new() -> Self {} fn return_early(&self) -> bool { false @@ -71,6 +74,7 @@ pub trait Visitor<'i, I: Interner> where I: 'i, { + /// The type of result that this visitor produces. type Result: VisitResult; /// Creates a `dyn` value from this visitor. Unfortunately, this @@ -124,6 +128,7 @@ where goal.super_visit_with(self.as_dyn(), outer_binder) } + /// Invoked for each domain goal. fn visit_domain_goal( &mut self, domain_goal: &DomainGoal, @@ -172,6 +177,7 @@ where } } + /// Invoked for each where clause. fn visit_where_clause( &mut self, where_clause: &WhereClause, @@ -201,6 +207,7 @@ where } } + /// Gets the visitor's interner. fn interner(&self) -> &'i I; } @@ -225,6 +232,7 @@ pub trait Visit: Debug { /// `SuperVisit` trait captures the recursive behavior that visits all /// the contents of the type. pub trait SuperVisit: Visit { + /// Recursively visits the type contents. fn super_visit_with<'i, R: VisitResult>( &self, visitor: &mut dyn Visitor<'i, I, Result = R>, diff --git a/vendor/chalk-ir-0.14.0/src/visit/binder_impls.rs b/vendor/chalk-ir-0.25.0/src/visit/binder_impls.rs similarity index 87% rename from vendor/chalk-ir-0.14.0/src/visit/binder_impls.rs rename to vendor/chalk-ir-0.25.0/src/visit/binder_impls.rs index 58ab0871db..ab0bf559d7 100644 --- a/vendor/chalk-ir-0.14.0/src/visit/binder_impls.rs +++ b/vendor/chalk-ir-0.25.0/src/visit/binder_impls.rs @@ -4,9 +4,9 @@ //! The more interesting impls of `Visit` remain in the `visit` module. use crate::interner::HasInterner; -use crate::{Binders, Canonical, DebruijnIndex, Fn, Interner, Visit, VisitResult, Visitor}; +use crate::{Binders, Canonical, DebruijnIndex, FnPointer, Interner, Visit, VisitResult, Visitor}; -impl Visit for Fn { +impl Visit for FnPointer { fn visit_with<'i, R: VisitResult>( &self, visitor: &mut dyn Visitor<'i, I, Result = R>, @@ -17,7 +17,7 @@ impl Visit for Fn { { let interner = visitor.interner(); self.substitution - .parameters(interner) + .as_slice(interner) .visit_with(visitor, outer_binder.shifted_in()) } } diff --git a/vendor/chalk-ir-0.14.0/src/visit/boring_impls.rs b/vendor/chalk-ir-0.25.0/src/visit/boring_impls.rs similarity index 90% rename from vendor/chalk-ir-0.14.0/src/visit/boring_impls.rs rename to vendor/chalk-ir-0.25.0/src/visit/boring_impls.rs index 34f10c79af..242844fc40 100644 --- a/vendor/chalk-ir-0.14.0/src/visit/boring_impls.rs +++ b/vendor/chalk-ir-0.25.0/src/visit/boring_impls.rs @@ -5,10 +5,10 @@ //! The more interesting impls of `Visit` remain in the `visit` module. use crate::{ - AdtId, AssocTypeId, ClausePriority, ClosureId, DebruijnIndex, FloatTy, FnDefId, GenericArg, - Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex, ProgramClause, - ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Scalar, Substitution, SuperVisit, - TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor, + AdtId, AssocTypeId, ClausePriority, ClosureId, Constraints, DebruijnIndex, FloatTy, FnDefId, + GenericArg, Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex, + ProgramClause, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Safety, Scalar, + Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor, }; use std::{marker::PhantomData, sync::Arc}; @@ -179,6 +179,7 @@ impl Visit for Goals { } } +#[doc(hidden)] #[macro_export] macro_rules! const_visit { ($t:ty) => { @@ -210,7 +211,9 @@ const_visit!(UintTy); const_visit!(IntTy); const_visit!(FloatTy); const_visit!(Mutability); +const_visit!(Safety); +#[doc(hidden)] #[macro_export] macro_rules! id_visit { ($t:ident) => { @@ -267,6 +270,21 @@ impl Visit for ProgramClauses { } } +impl Visit for Constraints { + fn visit_with<'i, R: VisitResult>( + &self, + visitor: &mut dyn Visitor<'i, I, Result = R>, + outer_binder: DebruijnIndex, + ) -> R + where + I: 'i, + { + let interner = visitor.interner(); + + visit_iter(self.iter(interner), visitor, outer_binder) + } +} + impl Visit for QuantifiedWhereClauses { fn visit_with<'i, R: VisitResult>( &self, diff --git a/vendor/chalk-ir-0.14.0/src/visit/visitors.rs b/vendor/chalk-ir-0.25.0/src/visit/visitors.rs similarity index 84% rename from vendor/chalk-ir-0.14.0/src/visit/visitors.rs rename to vendor/chalk-ir-0.25.0/src/visit/visitors.rs index 8eb37b920b..892280eb1a 100644 --- a/vendor/chalk-ir-0.14.0/src/visit/visitors.rs +++ b/vendor/chalk-ir-0.25.0/src/visit/visitors.rs @@ -1,6 +1,10 @@ +//! Visitor helpers + use crate::{BoundVar, DebruijnIndex, Interner, Visit, VisitResult, Visitor}; +/// Visitor extensions. pub trait VisitExt: Visit { + /// Check whether there are free (non-bound) variables. fn has_free_vars(&self, interner: &I) -> bool { self.visit_with( &mut FindFreeVarsVisitor { interner }, @@ -12,14 +16,18 @@ pub trait VisitExt: Visit { impl VisitExt for T where T: Visit {} +/// Helper visitor for finding a specific value. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[allow(missing_docs)] pub struct FindAny { pub found: bool, } impl FindAny { + /// Visitor has found the value. pub const FOUND: FindAny = FindAny { found: true }; + /// Checks whether the value has been found. pub fn to_bool(&self) -> bool { self.found } diff --git a/vendor/chalk-ir-0.14.0/src/zip.rs b/vendor/chalk-ir-0.25.0/src/zip.rs similarity index 94% rename from vendor/chalk-ir-0.14.0/src/zip.rs rename to vendor/chalk-ir-0.25.0/src/zip.rs index e7dc072800..ad439058a6 100644 --- a/vendor/chalk-ir-0.14.0/src/zip.rs +++ b/vendor/chalk-ir-0.25.0/src/zip.rs @@ -1,3 +1,5 @@ +//! Traits for "zipping" types, walking through two structures and checking that they match. + use crate::fold::Fold; use crate::*; use std::fmt::Debug; @@ -78,6 +80,7 @@ pub trait Zip: Debug where I: Interner, { + /// Uses the zipper to walk through two values, ensuring that they match. fn zip_with<'i, Z: Zipper<'i, I>>(zipper: &mut Z, a: &Self, b: &Self) -> Fallible<()> where I: 'i; @@ -267,6 +270,17 @@ impl Zip for ProgramClauses { } } +impl Zip for Constraints { + fn zip_with<'i, Z: Zipper<'i, I>>(zipper: &mut Z, a: &Self, b: &Self) -> Fallible<()> + where + I: 'i, + { + let interner = zipper.interner(); + Zip::zip_with(zipper, a.as_slice(interner), b.as_slice(interner))?; + Ok(()) + } +} + impl Zip for QuantifiedWhereClauses { fn zip_with<'i, Z: Zipper<'i, I>>(zipper: &mut Z, a: &Self, b: &Self) -> Fallible<()> where @@ -284,7 +298,7 @@ impl Zip for Substitution { I: 'i, { let interner = zipper.interner(); - Zip::zip_with(zipper, a.parameters(interner), b.parameters(interner)) + Zip::zip_with(zipper, a.as_slice(interner), b.as_slice(interner)) } } diff --git a/vendor/chalk-ir/.cargo-checksum.json b/vendor/chalk-ir/.cargo-checksum.json index 59db159d38..ef105669ae 100644 --- a/vendor/chalk-ir/.cargo-checksum.json +++ b/vendor/chalk-ir/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"051d24338c250ec6f390e5990e2691e110faa9484cc4957cb4229c9b522668e5","README.md":"64cba0ddf3e9b5c168fbe069f1a84c401ce0b33e765ea49acb1345d0923afe8d","src/cast.rs":"6e8bc7ebd3d94a27c561499a15de2cc5d9501e6bf387b62e76772d7cb7ecd0a2","src/could_match.rs":"46507c372868dcd51c4a04dcd4bcc4e6e61f0fa537d980b3dc615be52c98171b","src/debug.rs":"e130908297f47a08ec7ed0d36131e5bd8534434fb9d30881da4fcbd714d2d95a","src/fold.rs":"2d1f8fd0f8603dad54428ba9d93f281d478c380dfca9d755e96a362d3be9d470","src/fold/binder_impls.rs":"0cb4f2b40b34e5f80e5a5946289959431ac5c22f6ec87d30e9b2f7d4122d0fd0","src/fold/boring_impls.rs":"f83bddd6061e0d035fb37a250013c2ce55fb624d0a3ee63d5e1840bb8ebd8227","src/fold/shift.rs":"134caa51a84399e7bd31471e3a31f7ca05b91c99cb1f06132f1d42151328e5d3","src/fold/subst.rs":"4db018d2b5d447420ae4b9269de36f3ce816de201b4eeaf30d54ae5c3b5db7cd","src/interner.rs":"993b347617e2a6dc8f34d966e4f140a082dfadc946d52e1e4064311db07f4b65","src/lib.rs":"808cf7a58fc04b89fd10eac36125dd9356a00bc33cc6570d81d63796a1572497","src/visit.rs":"22e5230a397b3d5ec1c2002cdd03dc6c8adb3d5497e83534d93b9ff72875896c","src/visit/binder_impls.rs":"4e544fc24158c8a1c84237ed21b83673225f87876ee78eeda83b41bc2b65f408","src/visit/boring_impls.rs":"f9904bf7200af8dc55e01ff24c238406596b7e7353ad7361d074ec5af4a4d013","src/visit/visitors.rs":"5f429cc2f9a94f918258c8df776a0fec15cffaff4dd7b20019a2ad6c091a1ddd","src/zip.rs":"f2b25e7221e32b5176adc95220b338d079555fae2949e12bf197e28dd8b24c2f"},"package":"bb332abfcb015b148c6fbab39b1d13282745b0f7f312019dd8e138f5f3f0855d"} \ No newline at end of file +{"files":{"Cargo.toml":"0e7c7b33a3d6e048149a5d007a9e4dad3ab002b69a024e8cef30dae69d5df697","README.md":"64cba0ddf3e9b5c168fbe069f1a84c401ce0b33e765ea49acb1345d0923afe8d","src/cast.rs":"6e8bc7ebd3d94a27c561499a15de2cc5d9501e6bf387b62e76772d7cb7ecd0a2","src/could_match.rs":"46507c372868dcd51c4a04dcd4bcc4e6e61f0fa537d980b3dc615be52c98171b","src/debug.rs":"9f2107f33d1fb6b8e941d01445829d09882bd06512bd3f48a24aae6b8d3c3fa7","src/fold.rs":"2d1f8fd0f8603dad54428ba9d93f281d478c380dfca9d755e96a362d3be9d470","src/fold/binder_impls.rs":"31c5fe338fb31fdee44730902f6dc3ce7f091d57bddd24c13e14bea14443a167","src/fold/boring_impls.rs":"3acd9e4c79d57864113d8f87c93e80c4ea734c1679443699c7f5a873980469ac","src/fold/shift.rs":"134caa51a84399e7bd31471e3a31f7ca05b91c99cb1f06132f1d42151328e5d3","src/fold/subst.rs":"4db018d2b5d447420ae4b9269de36f3ce816de201b4eeaf30d54ae5c3b5db7cd","src/interner.rs":"235f430a7b7a1885a073d154ecae18fa9b1b41543df24a89781ba6d0d4d3436b","src/lib.rs":"cac3d9e4931702212aa2b6d99cdfd26ab696fd8ef7a5264ba5e9819303652c62","src/visit.rs":"22e5230a397b3d5ec1c2002cdd03dc6c8adb3d5497e83534d93b9ff72875896c","src/visit/binder_impls.rs":"4e544fc24158c8a1c84237ed21b83673225f87876ee78eeda83b41bc2b65f408","src/visit/boring_impls.rs":"6e8974e191211a16ec4d7f38a4cba4db7e27aaec30ce4979fa55406e1d5214d4","src/visit/visitors.rs":"5f429cc2f9a94f918258c8df776a0fec15cffaff4dd7b20019a2ad6c091a1ddd","src/zip.rs":"f2b25e7221e32b5176adc95220b338d079555fae2949e12bf197e28dd8b24c2f"},"package":"03a4050029ecb2b5a1ff3bfc64c39279179b294821ec2e8891a4a5c6e3a08db0"} \ No newline at end of file diff --git a/vendor/chalk-ir/Cargo.toml b/vendor/chalk-ir/Cargo.toml index 8ea73ccf66..5b37c9c64d 100644 --- a/vendor/chalk-ir/Cargo.toml +++ b/vendor/chalk-ir/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-ir" -version = "0.23.0" +version = "0.29.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Chalk's internal representation of types, goals, and clauses" readme = "README.md" @@ -21,7 +21,7 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.23.0" +version = "=0.29.0" [dependencies.lazy_static] version = "1.4.0" diff --git a/vendor/chalk-ir/src/debug.rs b/vendor/chalk-ir/src/debug.rs index 7c2f21853c..4d77dea862 100644 --- a/vendor/chalk-ir/src/debug.rs +++ b/vendor/chalk-ir/src/debug.rs @@ -35,6 +35,13 @@ impl Debug for ClosureId { } } +impl Debug for ForeignDefId { + fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result { + I::debug_foreign_def_id(*self, fmt) + .unwrap_or_else(|| write!(fmt, "ForeignDefId({:?})", self.0)) + } +} + impl Debug for Ty { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { I::debug_ty(self, fmt).unwrap_or_else(|| write!(fmt, "{:?}", self.interned)) @@ -179,11 +186,26 @@ impl Debug for TypeName { TypeName::OpaqueType(opaque_ty) => write!(fmt, "!{:?}", opaque_ty), TypeName::Slice => write!(fmt, "{{slice}}"), TypeName::FnDef(fn_def) => write!(fmt, "{:?}", fn_def), - TypeName::Raw(mutability) => write!(fmt, "{:?}", mutability), - TypeName::Ref(mutability) => write!(fmt, "{:?}", mutability), + TypeName::Ref(mutability) => write!( + fmt, + "{}", + match mutability { + Mutability::Mut => "{{&mut}}", + Mutability::Not => "{{&}}", + } + ), + TypeName::Raw(mutability) => write!( + fmt, + "{}", + match mutability { + Mutability::Mut => "{{*mut}}", + Mutability::Not => "{{*const}}", + } + ), TypeName::Never => write!(fmt, "Never"), TypeName::Array => write!(fmt, "{{array}}"), TypeName::Closure(id) => write!(fmt, "{{closure:{:?}}}", id), + TypeName::Foreign(foreign_ty) => write!(fmt, "{:?}", foreign_ty), TypeName::Error => write!(fmt, "{{error}}"), } } @@ -238,14 +260,12 @@ impl Debug for FnPointer { let FnPointer { num_binders, substitution, - abi, - safety, - variadic: _, + sig, } = self; write!( fmt, "for<{}> {:?} {:?} {:?}", - num_binders, safety, abi, substitution + num_binders, sig.safety, sig.abi, substitution ) } } diff --git a/vendor/chalk-ir/src/fold/binder_impls.rs b/vendor/chalk-ir/src/fold/binder_impls.rs index 1f751f16ca..dc290e9224 100644 --- a/vendor/chalk-ir/src/fold/binder_impls.rs +++ b/vendor/chalk-ir/src/fold/binder_impls.rs @@ -20,16 +20,16 @@ impl> Fold for FnPointer { let FnPointer { num_binders, substitution, - abi, - safety, - variadic, + sig, } = self; Ok(FnPointer { num_binders: *num_binders, substitution: substitution.fold_with(folder, outer_binder.shifted_in())?, - abi: TI::transfer_abi(*abi), - safety: *safety, - variadic: *variadic, + sig: FnSig { + abi: TI::transfer_abi(sig.abi), + safety: sig.safety, + variadic: sig.variadic, + }, }) } } diff --git a/vendor/chalk-ir/src/fold/boring_impls.rs b/vendor/chalk-ir/src/fold/boring_impls.rs index 9922315a39..9d6f835e1d 100644 --- a/vendor/chalk-ir/src/fold/boring_impls.rs +++ b/vendor/chalk-ir/src/fold/boring_impls.rs @@ -303,6 +303,7 @@ id_fold!(AssocTypeId); id_fold!(OpaqueTyId); id_fold!(FnDefId); id_fold!(ClosureId); +id_fold!(ForeignDefId); impl> SuperFold for ProgramClauseData { fn super_fold_with<'i>( diff --git a/vendor/chalk-ir/src/interner.rs b/vendor/chalk-ir/src/interner.rs index c996059d97..b4da73c53d 100644 --- a/vendor/chalk-ir/src/interner.rs +++ b/vendor/chalk-ir/src/interner.rs @@ -9,6 +9,7 @@ use crate::ClosureId; use crate::Constraint; use crate::Constraints; use crate::FnDefId; +use crate::ForeignDefId; use crate::GenericArg; use crate::GenericArgData; use crate::Goal; @@ -245,6 +246,16 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + /// Prints the debug representation of a foreign-def-id. + /// Returns `None` to fallback to the default debug output. + #[allow(unused_variables)] + fn debug_foreign_def_id( + foreign_def_id: ForeignDefId, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + /// Prints the debug representation of an alias. /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] @@ -715,6 +726,16 @@ where type Interner = I; } +impl HasInterner for (A, B, C) +where + A: HasInterner, + B: HasInterner, + C: HasInterner, + I: Interner, +{ + type Interner = I; +} + impl<'a, T: HasInterner> HasInterner for std::slice::Iter<'a, T> { type Interner = T::Interner; } diff --git a/vendor/chalk-ir/src/lib.rs b/vendor/chalk-ir/src/lib.rs index 3a1cad53f3..2464b1dc24 100644 --- a/vendor/chalk-ir/src/lib.rs +++ b/vendor/chalk-ir/src/lib.rs @@ -254,6 +254,9 @@ pub enum TypeName { /// A closure. Closure(ClosureId), + /// foreign types + Foreign(ForeignDefId), + /// This can be used to represent an error, e.g. during name resolution of a type. /// Chalk itself will not produce this, just pass it through when given. Error, @@ -363,6 +366,10 @@ pub struct FnDefId(pub I::DefId); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ClosureId(pub I::DefId); +/// Id for foreign types. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ForeignDefId(pub I::DefId); + impl_debugs!(ImplId, ClauseId); /// A Rust type. The actual type data is stored in `TyData`. @@ -470,6 +477,17 @@ impl Ty { } } + /// Returns `Some(adt_id)` if this is an ADT, `None` otherwise + pub fn adt_id(&self, interner: &I) -> Option> { + match self.data(interner) { + TyData::Apply(ApplicationTy { + name: TypeName::Adt(adt_id), + .. + }) => Some(*adt_id), + _ => None, + } + } + /// True if this type contains "bound" types/lifetimes, and hence /// needs to be shifted across binders. This is a very inefficient /// check, intended only for debug assertions, because I am lazy. @@ -865,15 +883,22 @@ impl InferenceVar { } } +/// A function signature. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HasInterner, Debug)] +#[allow(missing_docs)] +pub struct FnSig { + pub abi: I::FnAbi, + pub safety: Safety, + pub variadic: bool, +} + /// for<'a...'z> X -- all binders are instantiated at once, /// and we use deBruijn indices within `self.ty` #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] #[allow(missing_docs)] pub struct FnPointer { pub num_binders: usize, - pub abi: I::FnAbi, - pub safety: Safety, - pub variadic: bool, + pub sig: FnSig, pub substitution: Substitution, } diff --git a/vendor/chalk-ir/src/visit/boring_impls.rs b/vendor/chalk-ir/src/visit/boring_impls.rs index 242844fc40..43e4cf1652 100644 --- a/vendor/chalk-ir/src/visit/boring_impls.rs +++ b/vendor/chalk-ir/src/visit/boring_impls.rs @@ -6,9 +6,10 @@ use crate::{ AdtId, AssocTypeId, ClausePriority, ClosureId, Constraints, DebruijnIndex, FloatTy, FnDefId, - GenericArg, Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex, - ProgramClause, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Safety, Scalar, - Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor, + ForeignDefId, GenericArg, Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, + PlaceholderIndex, ProgramClause, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, + Safety, Scalar, Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, + Visitor, }; use std::{marker::PhantomData, sync::Arc}; @@ -239,6 +240,7 @@ id_visit!(OpaqueTyId); id_visit!(AssocTypeId); id_visit!(FnDefId); id_visit!(ClosureId); +id_visit!(ForeignDefId); impl SuperVisit for ProgramClause { fn super_visit_with<'i, R: VisitResult>( diff --git a/vendor/chalk-recursive/.cargo-checksum.json b/vendor/chalk-recursive/.cargo-checksum.json index 05c3993daa..fb0363492e 100644 --- a/vendor/chalk-recursive/.cargo-checksum.json +++ b/vendor/chalk-recursive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"d36cc5e58b884205292bce50b222d520a4ed021e71cdc794dce26731f1553e5a","README.md":"2742a242541363c8a1ee50ef908c63d9b940d8c75c77f941a74afb51654c22c0","src/combine.rs":"b8addb86955f08265dc9d3664b51b8acd80b45c48456a8e99aa18dc2495576f8","src/fulfill.rs":"7f7555597cb76523e115415f3f9c3d144284ba826faaee4ac90cb76463cf2c92","src/lib.rs":"30c9772443b0c98a0292e4b9e1f3675d5bd6b459f6f150a9f2614e950cb559b0","src/recursive.rs":"5d3e77da4131ccd853c2587f82557ce48700085853b5c041f4b157b2dce5d969","src/search_graph.rs":"d123fc1fbb06c20284fa9bd1ee57f32dc33de5a8adebc21bf515e13736a44402","src/solve.rs":"bfbbe4cddce519ac7848f431ccb37dbc3add9f6d2b90c309c0b778097c5d61e3","src/stack.rs":"babcaae992f46febbb86997627f17f620cd926d244b7d48b0e7a53856e9fd73f"},"package":"e7c7673f10c5fa1acf7fa07d4f4c5917cbcf161ed3a952d14530c79950de32d2"} \ No newline at end of file +{"files":{"Cargo.toml":"9559d15a01a6154cf689e58c2e3d489fca15daf5218a2b40140968be80880e56","README.md":"2742a242541363c8a1ee50ef908c63d9b940d8c75c77f941a74afb51654c22c0","src/combine.rs":"b8addb86955f08265dc9d3664b51b8acd80b45c48456a8e99aa18dc2495576f8","src/fulfill.rs":"69d0ac7b256f85a3a8db7f170f7a075f02c486dc713a93973ee535b72f035896","src/lib.rs":"cd7ed2dda48bbeb1a4d6ce97ec8c2d2b0b3b393f5dced9110ab89c37ed06d735","src/recursive.rs":"5d3e77da4131ccd853c2587f82557ce48700085853b5c041f4b157b2dce5d969","src/search_graph.rs":"d123fc1fbb06c20284fa9bd1ee57f32dc33de5a8adebc21bf515e13736a44402","src/solve.rs":"bfbbe4cddce519ac7848f431ccb37dbc3add9f6d2b90c309c0b778097c5d61e3","src/stack.rs":"babcaae992f46febbb86997627f17f620cd926d244b7d48b0e7a53856e9fd73f"},"package":"5130de3065e3cdfd2ab6d7d70b02b917bafbc096f270c9a643c23da249053606"} \ No newline at end of file diff --git a/vendor/chalk-recursive/Cargo.toml b/vendor/chalk-recursive/Cargo.toml index 68704e64c6..f2cf6f8ee8 100644 --- a/vendor/chalk-recursive/Cargo.toml +++ b/vendor/chalk-recursive/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-recursive" -version = "0.23.0" +version = "0.25.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Recursive solver for the Chalk project" readme = "README.md" @@ -21,13 +21,13 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.23.0" +version = "=0.25.0" [dependencies.chalk-ir] -version = "=0.23.0" +version = "=0.25.0" [dependencies.chalk-solve] -version = "=0.23.0" +version = "=0.25.0" [dependencies.rustc-hash] version = "1.1.0" diff --git a/vendor/chalk-recursive/src/fulfill.rs b/vendor/chalk-recursive/src/fulfill.rs index 63d597923f..b2cf64cf1c 100644 --- a/vendor/chalk-recursive/src/fulfill.rs +++ b/vendor/chalk-recursive/src/fulfill.rs @@ -447,9 +447,17 @@ impl<'s, I: Interner, Solver: SolveDatabase, Infer: RecursiveInferenceTable Solution { } /// Determine whether this solution contains type information that *must* - /// hold. - pub(crate) fn has_definite(&self) -> bool { - match *self { - Solution::Unique(_) => true, - Solution::Ambig(Guidance::Definite(_)) => true, - _ => false, + /// hold, and returns the subst in that case. + pub(crate) fn definite_subst(&self, interner: &I) -> Option>> { + match self { + Solution::Unique(constrained) => Some(constrained.clone()), + Solution::Ambig(Guidance::Definite(canonical)) => { + let value = ConstrainedSubst { + subst: canonical.value.clone(), + constraints: Constraints::empty(interner), + }; + Some(Canonical { + value, + binders: canonical.binders.clone(), + }) + } + _ => None, } } diff --git a/vendor/chalk-solve-0.14.0/.cargo-checksum.json b/vendor/chalk-solve-0.14.0/.cargo-checksum.json deleted file mode 100644 index 95b7eac8c0..0000000000 --- a/vendor/chalk-solve-0.14.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"aab8c2b4711cf8d263ee626158e7ce046ead9fc940ddafd61cb3edea9312704c","README.md":"2de2da988dbbaa8feb78b0a771b7bee942f34705ab057c824b1183300c535c74","src/clauses.rs":"68b7e9aa192744f9907bca52da3282ef7ef321c6674cf9627f1ab457b34eb0af","src/clauses/builder.rs":"0807ccb0313729ebaa16b8ed65e6853ac121c0a1eff338ccdef8d8945daa6aad","src/clauses/builtin_traits.rs":"2001fee54cc892b72745d7a51d08a0bc243d0ab14306d7458ef797e60f7844cd","src/clauses/builtin_traits/clone.rs":"e07279b49184e6e3636e3d124cb0470270c96d9e7305a2b560f8206feabf3c02","src/clauses/builtin_traits/copy.rs":"7ad5332f0891ec0b5c89c67006085955bdbb67098d26076ee47f2aa70999804c","src/clauses/builtin_traits/fn_family.rs":"c9bcf132f5509c52695639263384d94470e24554b766850b61b02597fa45a4f7","src/clauses/builtin_traits/sized.rs":"2d83af31a481e97c62ef22008319de7110cb6c1e4f3c5c71f515890018638e84","src/clauses/builtin_traits/unsize.rs":"95d7f75d25148f918dafd418384ef9df2b52f10bf76f0307b85ed31fc52acce7","src/clauses/dyn_ty.rs":"4359c991e85a622f713defa3a21b31f2df94d0fab9b3f35a4fcd406ad1fc63d6","src/clauses/env_elaborator.rs":"b5c54aa5747602deaf524d88c3323d1ab470f939baca0622188ad9edd025f2a9","src/clauses/generalize.rs":"1bea574a507b7499f8a5dae20746ca46cb7c38554edff215273575dd19410a96","src/clauses/program_clauses.rs":"ff77edf1f793a4139399a486f0191cf28b983bff9fe4c3b866d40abc4189fc3a","src/coherence.rs":"7ed42d105871abe22562955e8fcb788738bc378fdf20f705e6d15bff581d1119","src/coherence/orphan.rs":"ad607bd620a883c135092e75636545738da21c0526dcb72a1a8bc9474828a715","src/coherence/solve.rs":"bf4ddefb0ebb79ac13d6d319ae5a981c057a2687a75f19a68fc6fdf582e1e33f","src/coinductive_goal.rs":"bbef8deeb1c423b0d2215ecb287c96fceb22f6d11da31502b995e4a6aa9391f4","src/ext.rs":"b71de835698b02434ffb67000d33bd82be53c3dadd41aee0056f0e4b31e102cd","src/goal_builder.rs":"f5a2f0883165faf173a031f8576196abe88316596196a6b1bcf928dfe0c66089","src/infer.rs":"12143d3ed9324ccdb86acc5edaa897c2a7226396b291a77dec168a7a4856d327","src/infer/canonicalize.rs":"e09c7e82741fe988cec330ffbc75dcf8877e8f766bffd8e0b2d62ba61ae15632","src/infer/instantiate.rs":"b2b25da7840dc3a1cb6505f6523d392c430ba00feed331f774ad8d57959e90a3","src/infer/invert.rs":"c155fc04db1206a8212a9a55f68a1b33f5210c9c5d3523784c91e055a1b62e91","src/infer/normalize_deep.rs":"d70f351944c7d0982e5a0be4ef62085a5944f45be806cc71abff97c9fb56fa9f","src/infer/test.rs":"30cc313ab07250c3ffe1fcaa72ece6b61b4c7eeffb24d62ef6b4254eb12e65bb","src/infer/ucanonicalize.rs":"e9390b67b0cb3684a330d14cc8820edddd5cb6b57e301d9f1c52d97dc9fd5a02","src/infer/unify.rs":"3c54b32b0dd59340556f3e52417b95d30a93bf3f1fea3043a326150015960902","src/infer/var.rs":"4653b7ff3022e689c147c546c36b6f112e2b5bbc9b6dd266d2931fc0b985b813","src/lib.rs":"873280d9858e824f73c4fcb58ac2ddac066032615518802433c3b8f4a663fe80","src/recursive.rs":"b905871086c2e1969f5ad27a1a1fc7229c81e826841a62eb8ceb3436c7a7cc10","src/recursive/combine.rs":"c40b4e26adb6f3edbdcf129c8b2843a7342c47d6a84bdfcb866ca90e037bfc48","src/recursive/fulfill.rs":"0205074c731d1c0ea9e6fa6a63516429557edf2ed2a1a2924181f8b2230bed9d","src/recursive/lib.rs":"862e086f9e1815fa2b56583ac3c659752cf5b57515f1d35d2e5a276a5bc25457","src/recursive/search_graph.rs":"817b4b56c75e4202e1868891aa36504c8d9d67b7e176c1a681370d9af5037e95","src/recursive/solve.rs":"9856cbde2805c73fdf31c5f7838bafc40b3e6079a73d689f06b524e56daaacaf","src/recursive/stack.rs":"babcaae992f46febbb86997627f17f620cd926d244b7d48b0e7a53856e9fd73f","src/rust_ir.rs":"97bbf72539d0985c2de5f0e2efe01cfa8b42c12ce8a847437fdf790e2f9d0d53","src/solve.rs":"74249d77c50336ca7cfd9b3777b52ecb5adc52f819ca60f63a4868ade0d6ebf2","src/solve/slg.rs":"973e3111db82f35efcede1b53d1428dfaa0621e1ce2a2e0adcfd95e51daf9776","src/solve/slg/aggregate.rs":"f4d29294bd9bf66f7e6cdd6ec96979e741464ac44acad06c717c1d3547b520e4","src/solve/slg/resolvent.rs":"0c10b7babe7367bd5ced2c3c7e3a7c8ebd0c186103439773ae6a2b3edb5eed01","src/solve/test/bench.rs":"8da8bb948bdf598ed7f225fd695b12c9e8626cd7a14d4b7d8650de0fae73d655","src/solve/truncate.rs":"4762189065a55fc58434e2adde2f2a510ff2275f273b8a9ba7f7b7d69a79ef4f","src/split.rs":"7df598067f5ff2b1f1aa42e154533471554041d5933ccac0c38d485365960665","src/test_macros.rs":"f43f44c44c68b7192bdf72a70de55e26e2ee608b7477a7c0ee6920641eab3810","src/wf.rs":"28ff03c9b3fd0a1ff13dc894f348db8acd99377238017fc866e9ffaba8dae6aa"},"package":"5b9fd4102807b7ebe8fb034fa0f488c5656e1966d3261b558b81a08d519cdb29"} \ No newline at end of file diff --git a/vendor/chalk-solve-0.14.0/src/recursive.rs b/vendor/chalk-solve-0.14.0/src/recursive.rs deleted file mode 100644 index 46848edba8..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive.rs +++ /dev/null @@ -1,279 +0,0 @@ -mod combine; -mod fulfill; -pub mod lib; -mod search_graph; -mod solve; -mod stack; - -use self::lib::{Minimums, Solution, UCanonicalGoal}; -use self::search_graph::{DepthFirstNumber, SearchGraph}; -use self::solve::{SolveDatabase, SolveIteration}; -use self::stack::{Stack, StackDepth}; -use crate::{coinductive_goal::IsCoinductive, RustIrDatabase}; -use chalk_ir::interner::Interner; -use chalk_ir::{Canonical, ConstrainedSubst, Fallible}; -use rustc_hash::FxHashMap; -use tracing::{debug, info, instrument}; - -pub(crate) struct RecursiveContext { - stack: Stack, - - /// The "search graph" stores "in-progress results" that are still being - /// solved. - search_graph: SearchGraph, - - /// The "cache" stores results for goals that we have completely solved. - /// Things are added to the cache when we have completely processed their - /// result. - cache: FxHashMap, Fallible>>, - - caching_enabled: bool, -} - -/// A Solver is the basic context in which you can propose goals for a given -/// program. **All questions posed to the solver are in canonical, closed form, -/// so that each question is answered with effectively a "clean slate"**. This -/// allows for better caching, and simplifies management of the inference -/// context. -pub(crate) struct Solver<'me, I: Interner> { - program: &'me dyn RustIrDatabase, - context: &'me mut RecursiveContext, -} - -/// An extension trait for merging `Result`s -trait MergeWith { - fn merge_with(self, other: Self, f: F) -> Self - where - F: FnOnce(T, T) -> T; -} - -impl MergeWith for Fallible { - fn merge_with(self: Fallible, other: Fallible, f: F) -> Fallible - where - F: FnOnce(T, T) -> T, - { - match (self, other) { - (Err(_), Ok(v)) | (Ok(v), Err(_)) => Ok(v), - (Ok(v1), Ok(v2)) => Ok(f(v1, v2)), - (Err(_), Err(e)) => Err(e), - } - } -} - -impl RecursiveContext { - pub(crate) fn new(overflow_depth: usize, caching_enabled: bool) -> Self { - RecursiveContext { - stack: Stack::new(overflow_depth), - search_graph: SearchGraph::new(), - cache: FxHashMap::default(), - caching_enabled, - } - } - - pub(crate) fn solver<'me>( - &'me mut self, - program: &'me dyn RustIrDatabase, - ) -> Solver<'me, I> { - Solver { - program, - context: self, - } - } -} - -impl<'me, I: Interner> Solver<'me, I> { - /// Solves a canonical goal. The substitution returned in the - /// solution will be for the fully decomposed goal. For example, given the - /// program - /// - /// ```ignore - /// struct u8 { } - /// struct SomeType { } - /// trait Foo { } - /// impl Foo for SomeType { } - /// ``` - /// - /// and the goal `exists { forall { SomeType: Foo } - /// }`, `into_peeled_goal` can be used to create a canonical goal - /// `SomeType: Foo`. This function will then return a - /// solution with the substitution `?0 := u8`. - pub(crate) fn solve_root_goal( - &mut self, - canonical_goal: &UCanonicalGoal, - ) -> Fallible> { - debug!("solve_root_goal(canonical_goal={:?})", canonical_goal); - assert!(self.context.stack.is_empty()); - let minimums = &mut Minimums::new(); - self.solve_goal(canonical_goal.clone(), minimums) - } - - #[instrument(level = "debug", skip(self))] - fn solve_new_subgoal( - &mut self, - canonical_goal: UCanonicalGoal, - depth: StackDepth, - dfn: DepthFirstNumber, - ) -> Minimums { - // We start with `answer = None` and try to solve the goal. At the end of the iteration, - // `answer` will be updated with the result of the solving process. If we detect a cycle - // during the solving process, we cache `answer` and try to solve the goal again. We repeat - // until we reach a fixed point for `answer`. - // Considering the partial order: - // - None < Some(Unique) < Some(Ambiguous) - // - None < Some(CannotProve) - // the function which maps the loop iteration to `answer` is a nondecreasing function - // so this function will eventually be constant and the loop terminates. - loop { - let minimums = &mut Minimums::new(); - let (current_answer, current_prio) = self.solve_iteration(&canonical_goal, minimums); - - debug!( - "solve_new_subgoal: loop iteration result = {:?} with minimums {:?}", - current_answer, minimums - ); - - if !self.context.stack[depth].read_and_reset_cycle_flag() { - // None of our subgoals depended on us directly. - // We can return. - self.context.search_graph[dfn].solution = current_answer; - self.context.search_graph[dfn].solution_priority = current_prio; - return *minimums; - } - - let old_answer = &self.context.search_graph[dfn].solution; - let old_prio = self.context.search_graph[dfn].solution_priority; - - let (current_answer, current_prio) = combine::with_priorities_for_goal( - self.program.interner(), - &canonical_goal.canonical.value.goal, - old_answer.clone(), - old_prio, - current_answer, - current_prio, - ); - - // Some of our subgoals depended on us. We need to re-run - // with the current answer. - if self.context.search_graph[dfn].solution == current_answer { - // Reached a fixed point. - return *minimums; - } - - let current_answer_is_ambig = match ¤t_answer { - Ok(s) => s.is_ambig(), - Err(_) => false, - }; - - self.context.search_graph[dfn].solution = current_answer; - self.context.search_graph[dfn].solution_priority = current_prio; - - // Subtle: if our current answer is ambiguous, we can just stop, and - // in fact we *must* -- otherwise, we sometimes fail to reach a - // fixed point. See `multiple_ambiguous_cycles` for more. - if current_answer_is_ambig { - return *minimums; - } - - // Otherwise: rollback the search tree and try again. - self.context.search_graph.rollback_to(dfn + 1); - } - } -} - -impl<'me, I: Interner> SolveDatabase for Solver<'me, I> { - /// Attempt to solve a goal that has been fully broken down into leaf form - /// and canonicalized. This is where the action really happens, and is the - /// place where we would perform caching in rustc (and may eventually do in Chalk). - #[instrument(level = "info", skip(self, minimums))] - fn solve_goal( - &mut self, - goal: UCanonicalGoal, - minimums: &mut Minimums, - ) -> Fallible> { - // First check the cache. - if let Some(value) = self.context.cache.get(&goal) { - debug!("solve_reduced_goal: cache hit, value={:?}", value); - return value.clone(); - } - - // Next, check if the goal is in the search tree already. - if let Some(dfn) = self.context.search_graph.lookup(&goal) { - // Check if this table is still on the stack. - if let Some(depth) = self.context.search_graph[dfn].stack_depth { - // Is this a coinductive goal? If so, that is success, - // so we can return normally. Note that this return is - // not tabled. - // - // XXX how does caching with coinduction work? - if self.context.stack.coinductive_cycle_from(depth) { - let value = ConstrainedSubst { - subst: goal.trivial_substitution(self.program.interner()), - constraints: vec![], - }; - debug!("applying coinductive semantics"); - return Ok(Solution::Unique(Canonical { - value, - binders: goal.canonical.binders, - })); - } - - self.context.stack[depth].flag_cycle(); - } - - minimums.update_from(self.context.search_graph[dfn].links); - - // Return the solution from the table. - let previous_solution = self.context.search_graph[dfn].solution.clone(); - let previous_solution_priority = self.context.search_graph[dfn].solution_priority; - info!( - "solve_goal: cycle detected, previous solution {:?} with prio {:?}", - previous_solution, previous_solution_priority - ); - previous_solution - } else { - // Otherwise, push the goal onto the stack and create a table. - // The initial result for this table is error. - let coinductive_goal = goal.is_coinductive(self.program); - let depth = self.context.stack.push(coinductive_goal); - let dfn = self.context.search_graph.insert(&goal, depth); - let subgoal_minimums = self.solve_new_subgoal(goal, depth, dfn); - self.context.search_graph[dfn].links = subgoal_minimums; - self.context.search_graph[dfn].stack_depth = None; - self.context.stack.pop(depth); - minimums.update_from(subgoal_minimums); - - // Read final result from table. - let result = self.context.search_graph[dfn].solution.clone(); - let priority = self.context.search_graph[dfn].solution_priority; - - // If processing this subgoal did not involve anything - // outside of its subtree, then we can promote it to the - // cache now. This is a sort of hack to alleviate the - // worst of the repeated work that we do during tabling. - if subgoal_minimums.positive >= dfn { - if self.context.caching_enabled { - self.context - .search_graph - .move_to_cache(dfn, &mut self.context.cache); - debug!("solve_reduced_goal: SCC head encountered, moving to cache"); - } else { - debug!( - "solve_reduced_goal: SCC head encountered, rolling back as caching disabled" - ); - self.context.search_graph.rollback_to(dfn); - } - } - - info!("solve_goal: solution = {:?} prio {:?}", result, priority); - result - } - } - - fn interner(&self) -> &I { - &self.program.interner() - } - - fn db(&self) -> &dyn RustIrDatabase { - self.program - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/combine.rs b/vendor/chalk-solve-0.14.0/src/recursive/combine.rs deleted file mode 100644 index e42c282c6a..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/combine.rs +++ /dev/null @@ -1,77 +0,0 @@ -use super::lib::Solution; -use tracing::debug; - -use chalk_ir::interner::Interner; -use chalk_ir::{ClausePriority, DomainGoal, Fallible, GenericArg, Goal, GoalData}; - -pub(super) fn with_priorities_for_goal( - interner: &I, - goal: &Goal, - a: Fallible>, - prio_a: ClausePriority, - b: Fallible>, - prio_b: ClausePriority, -) -> (Fallible>, ClausePriority) { - let domain_goal = match goal.data(interner) { - GoalData::DomainGoal(domain_goal) => domain_goal, - _ => { - // non-domain goals currently have no priorities, so we always take the new solution here - return (b, prio_b); - } - }; - match (a, b) { - (Ok(a), Ok(b)) => { - let (solution, prio) = with_priorities(interner, domain_goal, a, prio_a, b, prio_b); - (Ok(solution), prio) - } - (Ok(solution), Err(_)) => (Ok(solution), prio_a), - (Err(_), Ok(solution)) => (Ok(solution), prio_b), - (Err(_), Err(e)) => (Err(e), prio_b), - } -} - -pub(super) fn with_priorities( - interner: &I, - domain_goal: &DomainGoal, - a: Solution, - prio_a: ClausePriority, - b: Solution, - prio_b: ClausePriority, -) -> (Solution, ClausePriority) { - match (prio_a, prio_b, a, b) { - (ClausePriority::High, ClausePriority::Low, higher, lower) - | (ClausePriority::Low, ClausePriority::High, lower, higher) => { - // if we have a high-priority solution and a low-priority solution, - // the high-priority solution overrides *if* they are both for the - // same inputs -- we don't want a more specific high-priority - // solution overriding a general low-priority one. Currently inputs - // only matter for projections; in a goal like `AliasEq(::Type = ?1)`, ?0 is the input. - let inputs_higher = calculate_inputs(interner, domain_goal, &higher); - let inputs_lower = calculate_inputs(interner, domain_goal, &lower); - if inputs_higher == inputs_lower { - debug!( - "preferring solution: {:?} over {:?} because of higher prio", - higher, lower - ); - (higher, ClausePriority::High) - } else { - (higher.combine(lower, interner), ClausePriority::High) - } - } - (_, _, a, b) => (a.combine(b, interner), prio_a), - } -} - -fn calculate_inputs( - interner: &I, - domain_goal: &DomainGoal, - solution: &Solution, -) -> Vec> { - if let Some(subst) = solution.constrained_subst() { - let subst_goal = subst.value.subst.apply(&domain_goal, interner); - subst_goal.inputs(interner) - } else { - domain_goal.inputs(interner) - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/fulfill.rs b/vendor/chalk-solve-0.14.0/src/recursive/fulfill.rs deleted file mode 100644 index 773ed575a7..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/fulfill.rs +++ /dev/null @@ -1,577 +0,0 @@ -use super::lib::{Guidance, Minimums, Solution}; -use super::solve::SolveDatabase; -use crate::debug_span; -use chalk_ir::cast::Cast; -use chalk_ir::fold::Fold; -use chalk_ir::interner::{HasInterner, Interner}; -use chalk_ir::visit::Visit; -use chalk_ir::zip::Zip; -use chalk_ir::{ - Binders, Canonical, ConstrainedSubst, Constraint, DomainGoal, Environment, EqGoal, Fallible, - GenericArg, Goal, GoalData, InEnvironment, LifetimeOutlives, NoSolution, - ProgramClauseImplication, QuantifierKind, Substitution, UCanonical, UniverseMap, WhereClause, -}; -use rustc_hash::FxHashSet; -use std::fmt::Debug; -use tracing::debug; - -enum Outcome { - Complete, - Incomplete, -} - -impl Outcome { - fn is_complete(&self) -> bool { - match *self { - Outcome::Complete => true, - _ => false, - } - } -} - -/// A goal that must be resolved -#[derive(Clone, Debug, PartialEq, Eq)] -enum Obligation { - /// For "positive" goals, we flatten all the way out to leafs within the - /// current `Fulfill` - Prove(InEnvironment>), - - /// For "negative" goals, we don't flatten in *this* `Fulfill`, which would - /// require having a logical "or" operator. Instead, we recursively solve in - /// a fresh `Fulfill`. - Refute(InEnvironment>), -} - -/// When proving a leaf goal, we record the free variables that appear within it -/// so that we can update inference state accordingly. -#[derive(Clone, Debug)] -struct PositiveSolution { - free_vars: Vec>, - universes: UniverseMap, - solution: Solution, -} - -/// When refuting a goal, there's no impact on inference state. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum NegativeSolution { - Refuted, - Ambiguous, -} - -pub(super) trait RecursiveInferenceTable { - fn instantiate_binders_universally<'a, T>( - &mut self, - interner: &'a I, - arg: &'a Binders, - ) -> T::Result - where - T: Fold + HasInterner; - - fn instantiate_binders_existentially<'a, T>( - &mut self, - interner: &'a I, - arg: &'a Binders, - ) -> T::Result - where - T: Fold + HasInterner; - - fn canonicalize( - &mut self, - interner: &I, - value: &T, - ) -> (Canonical, Vec>) - where - T: Fold, - T::Result: HasInterner; - - fn u_canonicalize( - &mut self, - interner: &I, - value0: &Canonical, - ) -> (UCanonical, UniverseMap) - where - T: HasInterner + Fold + Visit, - T::Result: HasInterner; - - fn unify( - &mut self, - interner: &I, - environment: &Environment, - a: &T, - b: &T, - ) -> Fallible<( - Vec>>, - Vec>>, - )> - where - T: ?Sized + Zip; - - fn instantiate_canonical(&mut self, interner: &I, bound: &Canonical) -> T::Result - where - T: HasInterner + Fold + Debug; - - fn invert_then_canonicalize( - &mut self, - interner: &I, - value: &T, - ) -> Option> - where - T: Fold + HasInterner; - - fn needs_truncation(&mut self, interner: &I, max_size: usize, value: impl Visit) -> bool; -} - -/// A `Fulfill` is where we actually break down complex goals, instantiate -/// variables, and perform inference. It's highly stateful. It's generally used -/// in Chalk to try to solve a goal, and then package up what was learned in a -/// stateless, canonical way. -/// -/// In rustc, you can think of there being an outermost `Fulfill` that's used when -/// type checking each function body, etc. There, the state reflects the state -/// of type inference in general. But when solving trait constraints, *fresh* -/// `Fulfill` instances will be created to solve canonicalized, free-standing -/// goals, and transport what was learned back to the outer context. -pub(super) struct Fulfill< - 's, - I: Interner, - Solver: SolveDatabase, - Infer: RecursiveInferenceTable, -> { - solver: &'s mut Solver, - subst: Substitution, - infer: Infer, - - /// The remaining goals to prove or refute - obligations: Vec>, - - /// Lifetime constraints that must be fulfilled for a solution to be fully - /// validated. - constraints: FxHashSet>>, - - /// Record that a goal has been processed that can neither be proved nor - /// refuted. In such a case the solution will be either `CannotProve`, or `Err` - /// in the case where some other goal leads to an error. - cannot_prove: bool, -} - -impl<'s, I: Interner, Solver: SolveDatabase, Infer: RecursiveInferenceTable> - Fulfill<'s, I, Solver, Infer> -{ - pub(super) fn new_with_clause( - solver: &'s mut Solver, - infer: Infer, - subst: Substitution, - canonical_goal: InEnvironment>, - clause: &Binders>, - ) -> Fallible { - let mut fulfill = Fulfill { - solver, - infer, - subst, - obligations: vec![], - constraints: FxHashSet::default(), - cannot_prove: false, - }; - - let ProgramClauseImplication { - consequence, - conditions, - priority: _, - } = fulfill - .infer - .instantiate_binders_existentially(fulfill.solver.interner(), clause); - - debug!("the subst is {:?}", fulfill.subst); - - if let Err(e) = fulfill.unify( - &canonical_goal.environment, - &canonical_goal.goal, - &consequence, - ) { - return Err(e); - } - - // if so, toss in all of its premises - for condition in conditions.as_slice(fulfill.solver.interner()) { - if let Err(e) = fulfill.push_goal(&canonical_goal.environment, condition.clone()) { - return Err(e); - } - } - - Ok(fulfill) - } - - pub(super) fn new_with_simplification( - solver: &'s mut Solver, - infer: Infer, - subst: Substitution, - canonical_goal: InEnvironment>, - ) -> Fallible { - let mut fulfill = Fulfill { - solver, - infer, - subst, - obligations: vec![], - constraints: FxHashSet::default(), - cannot_prove: false, - }; - - if let Err(e) = fulfill.push_goal(&canonical_goal.environment, canonical_goal.goal.clone()) - { - return Err(e); - } - - Ok(fulfill) - } - - fn push_obligation(&mut self, obligation: Obligation) { - // truncate to avoid overflows - match &obligation { - Obligation::Prove(goal) => { - if self - .infer - .needs_truncation(self.solver.interner(), 30, goal) - { - // the goal is too big. Record that we should return Ambiguous - self.cannot_prove = true; - return; - } - } - Obligation::Refute(goal) => { - if self - .infer - .needs_truncation(self.solver.interner(), 30, goal) - { - // the goal is too big. Record that we should return Ambiguous - self.cannot_prove = true; - return; - } - } - }; - self.obligations.push(obligation); - } - - /// Unifies `a` and `b` in the given environment. - /// - /// Wraps `InferenceTable::unify`; any resulting normalizations are added - /// into our list of pending obligations with the given environment. - pub(super) fn unify(&mut self, environment: &Environment, a: &T, b: &T) -> Fallible<()> - where - T: ?Sized + Zip + Debug, - { - let (goals, constraints) = self - .infer - .unify(self.solver.interner(), environment, a, b)?; - debug!("unify({:?}, {:?}) succeeded", a, b); - debug!("unify: goals={:?}", goals); - debug!("unify: constraints={:?}", constraints); - self.constraints.extend(constraints); - for goal in goals { - let goal = goal.cast(self.solver.interner()); - self.push_obligation(Obligation::Prove(goal)); - } - Ok(()) - } - - /// Create obligations for the given goal in the given environment. This may - /// ultimately create any number of obligations. - pub(super) fn push_goal( - &mut self, - environment: &Environment, - goal: Goal, - ) -> Fallible<()> { - debug!("push_goal({:?}, {:?})", goal, environment); - let interner = self.interner(); - match goal.data(interner) { - GoalData::Quantified(QuantifierKind::ForAll, subgoal) => { - let subgoal = self - .infer - .instantiate_binders_universally(self.solver.interner(), subgoal); - self.push_goal(environment, subgoal)?; - } - GoalData::Quantified(QuantifierKind::Exists, subgoal) => { - let subgoal = self - .infer - .instantiate_binders_existentially(self.solver.interner(), subgoal); - self.push_goal(environment, subgoal)?; - } - GoalData::Implies(wc, subgoal) => { - let new_environment = - &environment.add_clauses(interner, wc.iter(interner).cloned()); - self.push_goal(new_environment, subgoal.clone())?; - } - GoalData::All(goals) => { - for subgoal in goals.as_slice(interner) { - self.push_goal(environment, subgoal.clone())?; - } - } - GoalData::Not(subgoal) => { - let in_env = InEnvironment::new(environment, subgoal.clone()); - self.push_obligation(Obligation::Refute(in_env)); - } - GoalData::DomainGoal(domain_goal) => match domain_goal { - DomainGoal::Holds(WhereClause::LifetimeOutlives(LifetimeOutlives { a, b })) => { - self.constraints.insert(InEnvironment::new( - &environment, - Constraint::Outlives(a.clone(), b.clone()), - )); - } - _ => { - let in_env = InEnvironment::new(environment, goal); - self.push_obligation(Obligation::Prove(in_env)); - } - }, - GoalData::EqGoal(EqGoal { a, b }) => { - self.unify(&environment, &a, &b)?; - } - GoalData::CannotProve(()) => { - self.cannot_prove = true; - } - } - Ok(()) - } - - fn prove( - &mut self, - wc: &InEnvironment>, - minimums: &mut Minimums, - ) -> Fallible> { - let interner = self.solver.interner(); - let (quantified, free_vars) = self.infer.canonicalize(interner, &wc); - let (quantified, universes) = self.infer.u_canonicalize(interner, &quantified); - let result = self.solver.solve_goal(quantified, minimums); - Ok(PositiveSolution { - free_vars, - universes, - solution: result?, - }) - } - - fn refute(&mut self, goal: &InEnvironment>) -> Fallible { - let canonicalized = match self - .infer - .invert_then_canonicalize(self.solver.interner(), goal) - { - Some(v) => v, - None => { - // Treat non-ground negatives as ambiguous. Note that, as inference - // proceeds, we may wind up with more information here. - return Ok(NegativeSolution::Ambiguous); - } - }; - - // Negate the result - let (quantified, _) = self - .infer - .u_canonicalize(self.solver.interner(), &canonicalized); - let mut minimums = Minimums::new(); // FIXME -- minimums here seems wrong - if let Ok(solution) = self.solver.solve_goal(quantified, &mut minimums) { - if solution.is_unique() { - Err(NoSolution) - } else { - Ok(NegativeSolution::Ambiguous) - } - } else { - Ok(NegativeSolution::Refuted) - } - } - - /// Trying to prove some goal led to a the substitution `subst`; we - /// wish to apply that substitution to our own inference variables - /// (and incorporate any region constraints). This substitution - /// requires some mapping to get it into our namespace -- first, - /// the universes it refers to have been canonicalized, and - /// `universes` stores the mapping back into our - /// universes. Second, the free variables that appear within can - /// be mapped into our variables with `free_vars`. - fn apply_solution( - &mut self, - free_vars: Vec>, - universes: UniverseMap, - subst: Canonical>, - ) { - use crate::infer::ucanonicalize::UniverseMapExt; - let subst = universes.map_from_canonical(self.interner(), &subst); - let ConstrainedSubst { subst, constraints } = self - .infer - .instantiate_canonical(self.solver.interner(), &subst); - - debug!( - "fulfill::apply_solution: adding constraints {:?}", - constraints - ); - self.constraints.extend(constraints); - - // We use the empty environment for unification here because we're - // really just doing a substitution on unconstrained variables, which is - // guaranteed to succeed without generating any new constraints. - let empty_env = &Environment::new(self.solver.interner()); - - for (i, free_var) in free_vars.into_iter().enumerate() { - let subst_value = subst.at(self.interner(), i); - self.unify(empty_env, &free_var, subst_value) - .unwrap_or_else(|err| { - panic!( - "apply_solution failed with free_var={:?}, subst_value={:?}: {:?}", - free_var, subst_value, err - ); - }); - } - } - - fn fulfill(&mut self, minimums: &mut Minimums) -> Fallible { - debug_span!("fulfill", obligations=?self.obligations); - - // Try to solve all the obligations. We do this via a fixed-point - // iteration. We try to solve each obligation in turn. Anything which is - // successful, we drop; anything ambiguous, we retain in the - // `obligations` array. This process is repeated so long as we are - // learning new things about our inference state. - let mut obligations = Vec::with_capacity(self.obligations.len()); - let mut progress = true; - - while progress { - progress = false; - debug!("start of round, {} obligations", self.obligations.len()); - - // Take the list of `obligations` to solve this round and replace it - // with an empty vector. Iterate through each obligation to solve - // and solve it if we can. If not (because of ambiguity), then push - // it back onto `self.to_prove` for next round. Note that - // `solve_one` may also push onto the `self.to_prove` list - // directly. - assert!(obligations.is_empty()); - while let Some(obligation) = self.obligations.pop() { - let ambiguous = match obligation { - Obligation::Prove(ref wc) => { - let PositiveSolution { - free_vars, - universes, - solution, - } = self.prove(wc, minimums)?; - - if solution.has_definite() { - if let Some(constrained_subst) = solution.constrained_subst() { - self.apply_solution(free_vars, universes, constrained_subst); - progress = true; - } - } - - solution.is_ambig() - } - Obligation::Refute(ref goal) => { - let answer = self.refute(goal)?; - answer == NegativeSolution::Ambiguous - } - }; - - if ambiguous { - debug!("ambiguous result: {:?}", obligation); - obligations.push(obligation); - } - } - - self.obligations.extend(obligations.drain(..)); - debug!("end of round, {} obligations left", self.obligations.len()); - } - - // At the end of this process, `self.obligations` should have - // all of the ambiguous obligations, and `obligations` should - // be empty. - assert!(obligations.is_empty()); - - if self.obligations.is_empty() { - Ok(Outcome::Complete) - } else { - Ok(Outcome::Incomplete) - } - } - - /// Try to fulfill all pending obligations and build the resulting - /// solution. The returned solution will transform `subst` substitution with - /// the outcome of type inference by updating the replacements it provides. - pub(super) fn solve(mut self, minimums: &mut Minimums) -> Fallible> { - let outcome = match self.fulfill(minimums) { - Ok(o) => o, - Err(e) => return Err(e), - }; - - if self.cannot_prove { - return Ok(Solution::Ambig(Guidance::Unknown)); - } - - if outcome.is_complete() { - // No obligations remain, so we have definitively solved our goals, - // and the current inference state is the unique way to solve them. - - let constraints = self.constraints.into_iter().collect(); - let constrained = self.infer.canonicalize( - self.solver.interner(), - &ConstrainedSubst { - subst: self.subst, - constraints, - }, - ); - return Ok(Solution::Unique(constrained.0)); - } - - // Otherwise, we have (positive or negative) obligations remaining, but - // haven't proved that it's *impossible* to satisfy out obligations. we - // need to determine how to package up what we learned about type - // inference as an ambiguous solution. - - let interner = self.solver.interner(); - let canonical_subst = self.infer.canonicalize(interner, &self.subst); - - if canonical_subst.0.value.is_identity_subst(interner) { - // In this case, we didn't learn *anything* definitively. So now, we - // go one last time through the positive obligations, this time - // applying even *tentative* inference suggestions, so that we can - // yield these upwards as our own suggestions. There are no - // particular guarantees about *which* obligaiton we derive - // suggestions from. - - while let Some(obligation) = self.obligations.pop() { - if let Obligation::Prove(goal) = obligation { - let PositiveSolution { - free_vars, - universes, - solution, - } = self.prove(&goal, minimums).unwrap(); - if let Some(constrained_subst) = solution.constrained_subst() { - self.apply_solution(free_vars, universes, constrained_subst); - return Ok(Solution::Ambig(Guidance::Suggested(canonical_subst.0))); - } - } - } - - Ok(Solution::Ambig(Guidance::Unknown)) - } else { - // While we failed to prove the goal, we still learned that - // something had to hold. Here's an example where this happens: - // - // ```rust - // trait Display {} - // trait Debug {} - // struct Foo {} - // struct Bar {} - // struct Baz {} - // - // impl Display for Bar {} - // impl Display for Baz {} - // - // impl Debug for Foo where T: Display {} - // ``` - // - // If we pose the goal `exists { T: Debug }`, we can't say - // for sure what `T` must be (it could be either `Foo` or - // `Foo`, but we *can* say for sure that it must be of the - // form `Foo`. - Ok(Solution::Ambig(Guidance::Definite(canonical_subst.0))) - } - } - - fn interner(&self) -> &I { - self.solver.interner() - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/search_graph.rs b/vendor/chalk-solve-0.14.0/src/recursive/search_graph.rs deleted file mode 100644 index 77b3078f87..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/search_graph.rs +++ /dev/null @@ -1,131 +0,0 @@ -use std::ops::Add; -use std::ops::Index; -use std::ops::IndexMut; -use std::usize; - -use super::lib::{Minimums, Solution, UCanonicalGoal}; -use super::stack::StackDepth; -use chalk_ir::{interner::Interner, ClausePriority, Fallible, NoSolution}; -use rustc_hash::FxHashMap; -use tracing::debug; - -/// The "search graph" stores in-progress goals that are still -/// being solved. -pub(super) struct SearchGraph { - indices: FxHashMap, DepthFirstNumber>, - nodes: Vec>, -} - -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub(super) struct DepthFirstNumber { - index: usize, -} - -pub(super) struct Node { - pub(crate) goal: UCanonicalGoal, - - pub(crate) solution: Fallible>, - pub(crate) solution_priority: ClausePriority, - - /// This is `Some(X)` if we are actively exploring this node, or - /// `None` otherwise. - pub(crate) stack_depth: Option, - - /// While this node is on the stack, this field will be set to - /// contain our own depth-first number. Once the node is popped - /// from the stack, it contains the DFN of the minimal ancestor - /// that the table reached (or MAX if no cycle was encountered). - pub(crate) links: Minimums, -} - -impl SearchGraph { - pub(crate) fn new() -> Self { - SearchGraph { - indices: FxHashMap::default(), - nodes: vec![], - } - } - - pub(crate) fn lookup(&self, goal: &UCanonicalGoal) -> Option { - self.indices.get(goal).cloned() - } - - /// Insert a new search node in the tree. The node will be in the initial - /// state for a search node: - /// - /// - stack depth as given - /// - links set to its own DFN - /// - solution is initially `NoSolution` - pub(crate) fn insert( - &mut self, - goal: &UCanonicalGoal, - stack_depth: StackDepth, - ) -> DepthFirstNumber { - let dfn = DepthFirstNumber { - index: self.nodes.len(), - }; - let node = Node { - goal: goal.clone(), - solution: Err(NoSolution), - solution_priority: ClausePriority::High, - stack_depth: Some(stack_depth), - links: Minimums { positive: dfn }, - }; - self.nodes.push(node); - let previous_index = self.indices.insert(goal.clone(), dfn); - assert!(previous_index.is_none()); - dfn - } - - /// Clears all nodes with a depth-first number greater than or equal `dfn`. - pub(crate) fn rollback_to(&mut self, dfn: DepthFirstNumber) { - debug!("rollback_to(dfn={:?})", dfn); - self.indices.retain(|_key, value| *value < dfn); - self.nodes.truncate(dfn.index); - } - - /// Removes all nodes with a depth-first-number greater than or - /// equal to `dfn`, adding their final solutions into the cache. - pub(crate) fn move_to_cache( - &mut self, - dfn: DepthFirstNumber, - cache: &mut FxHashMap, Fallible>>, - ) { - debug!("move_to_cache(dfn={:?})", dfn); - self.indices.retain(|_key, value| *value < dfn); - for node in self.nodes.drain(dfn.index..) { - assert!(node.stack_depth.is_none()); - assert!(node.links.positive >= dfn); - debug!("caching solution {:?} for {:?}", node.solution, node.goal); - cache.insert(node.goal, node.solution); - } - } -} - -impl Index for SearchGraph { - type Output = Node; - - fn index(&self, table_index: DepthFirstNumber) -> &Node { - &self.nodes[table_index.index] - } -} - -impl IndexMut for SearchGraph { - fn index_mut(&mut self, table_index: DepthFirstNumber) -> &mut Node { - &mut self.nodes[table_index.index] - } -} - -impl DepthFirstNumber { - pub(crate) const MAX: DepthFirstNumber = DepthFirstNumber { index: usize::MAX }; -} - -impl Add for DepthFirstNumber { - type Output = DepthFirstNumber; - - fn add(self, v: usize) -> DepthFirstNumber { - DepthFirstNumber { - index: self.index + v, - } - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/solve.rs b/vendor/chalk-solve-0.14.0/src/recursive/solve.rs deleted file mode 100644 index ab6b7acbbb..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/solve.rs +++ /dev/null @@ -1,314 +0,0 @@ -use super::combine; -use super::fulfill::{Fulfill, RecursiveInferenceTable}; -use super::lib::{Guidance, Minimums, Solution, UCanonicalGoal}; -use crate::clauses::program_clauses_for_goal; -use crate::debug_span; -use crate::infer::{InferenceTable, ParameterEnaVariableExt}; -use crate::{solve::truncate, RustIrDatabase}; -use chalk_ir::fold::Fold; -use chalk_ir::interner::{HasInterner, Interner}; -use chalk_ir::visit::Visit; -use chalk_ir::zip::Zip; -use chalk_ir::{ - Binders, Canonical, ClausePriority, Constraint, DomainGoal, Environment, Fallible, Floundered, - GenericArg, Goal, GoalData, InEnvironment, NoSolution, ProgramClause, ProgramClauseData, - ProgramClauseImplication, Substitution, UCanonical, UniverseMap, -}; -use std::fmt::Debug; -use tracing::{debug, instrument}; - -pub(super) trait SolveDatabase: Sized { - fn solve_goal( - &mut self, - goal: UCanonical>>, - minimums: &mut Minimums, - ) -> Fallible>; - - fn interner(&self) -> &I; - - fn db(&self) -> &dyn RustIrDatabase; -} - -/// The `solve_iteration` method -- implemented for any type that implements -/// `SolveDb`. -pub(super) trait SolveIteration: SolveDatabase { - /// Executes one iteration of the recursive solver, computing the current - /// solution to the given canonical goal. This is used as part of a loop in - /// the case of cyclic goals. - fn solve_iteration( - &mut self, - canonical_goal: &UCanonicalGoal, - minimums: &mut Minimums, - ) -> (Fallible>, ClausePriority) { - let UCanonical { - universes, - canonical: - Canonical { - binders, - value: InEnvironment { environment, goal }, - }, - } = canonical_goal.clone(); - - match goal.data(self.interner()) { - GoalData::DomainGoal(domain_goal) => { - let canonical_goal = UCanonical { - universes, - canonical: Canonical { - binders, - value: InEnvironment { - environment, - goal: domain_goal.clone(), - }, - }, - }; - - // "Domain" goals (i.e., leaf goals that are Rust-specific) are - // always solved via some form of implication. We can either - // apply assumptions from our environment (i.e. where clauses), - // or from the lowered program, which includes fallback - // clauses. We try each approach in turn: - - let InEnvironment { environment, goal } = &canonical_goal.canonical.value; - - let (prog_solution, prog_prio) = { - debug_span!("prog_clauses"); - - let prog_clauses = self.program_clauses_for_goal(environment, &goal); - match prog_clauses { - Ok(clauses) => self.solve_from_clauses(&canonical_goal, clauses, minimums), - Err(Floundered) => { - (Ok(Solution::Ambig(Guidance::Unknown)), ClausePriority::High) - } - } - }; - debug!("prog_solution={:?}", prog_solution); - - (prog_solution, prog_prio) - } - - _ => { - let canonical_goal = UCanonical { - universes, - canonical: Canonical { - binders, - value: InEnvironment { environment, goal }, - }, - }; - - self.solve_via_simplification(&canonical_goal, minimums) - } - } - } -} - -impl SolveIteration for S -where - S: SolveDatabase, - I: Interner, -{ -} - -/// Helper methods for `solve_iteration`, private to this module. -trait SolveIterationHelpers: SolveDatabase { - #[instrument(level = "debug", skip(self, minimums))] - fn solve_via_simplification( - &mut self, - canonical_goal: &UCanonicalGoal, - minimums: &mut Minimums, - ) -> (Fallible>, ClausePriority) { - let (infer, subst, goal) = self.new_inference_table(canonical_goal); - match Fulfill::new_with_simplification(self, infer, subst, goal) { - Ok(fulfill) => (fulfill.solve(minimums), ClausePriority::High), - Err(e) => (Err(e), ClausePriority::High), - } - } - - /// See whether we can solve a goal by implication on any of the given - /// clauses. If multiple such solutions are possible, we attempt to combine - /// them. - fn solve_from_clauses( - &mut self, - canonical_goal: &UCanonical>>, - clauses: C, - minimums: &mut Minimums, - ) -> (Fallible>, ClausePriority) - where - C: IntoIterator>, - { - let mut cur_solution = None; - for program_clause in clauses { - debug_span!("solve_from_clauses", clause = ?program_clause); - - // If we have a completely ambiguous answer, it's not going to get better, so stop - if cur_solution == Some((Solution::Ambig(Guidance::Unknown), ClausePriority::High)) { - return (Ok(Solution::Ambig(Guidance::Unknown)), ClausePriority::High); - } - - let ProgramClauseData(implication) = program_clause.data(self.interner()); - let res = self.solve_via_implication(canonical_goal, implication, minimums); - - if let (Ok(solution), priority) = res { - debug!("ok: solution={:?} prio={:?}", solution, priority); - cur_solution = Some(match cur_solution { - None => (solution, priority), - Some((cur, cur_priority)) => combine::with_priorities( - self.interner(), - &canonical_goal.canonical.value.goal, - cur, - cur_priority, - solution, - priority, - ), - }); - } else { - debug!("error"); - } - } - cur_solution.map_or((Err(NoSolution), ClausePriority::High), |(s, p)| (Ok(s), p)) - } - - /// Modus ponens! That is: try to apply an implication by proving its premises. - #[instrument(level = "info", skip(self, minimums))] - fn solve_via_implication( - &mut self, - canonical_goal: &UCanonical>>, - clause: &Binders>, - minimums: &mut Minimums, - ) -> (Fallible>, ClausePriority) { - let (infer, subst, goal) = self.new_inference_table(canonical_goal); - match Fulfill::new_with_clause(self, infer, subst, goal, clause) { - Ok(fulfill) => (fulfill.solve(minimums), clause.skip_binders().priority), - Err(e) => (Err(e), ClausePriority::High), - } - } - - fn new_inference_table + HasInterner + Clone>( - &self, - ucanonical_goal: &UCanonical>, - ) -> ( - RecursiveInferenceTableImpl, - Substitution, - InEnvironment, - ) { - let (infer, subst, canonical_goal) = InferenceTable::from_canonical( - self.interner(), - ucanonical_goal.universes, - &ucanonical_goal.canonical, - ); - let infer = RecursiveInferenceTableImpl { infer }; - (infer, subst, canonical_goal) - } - - fn program_clauses_for_goal( - &self, - environment: &Environment, - goal: &DomainGoal, - ) -> Result>, Floundered> { - program_clauses_for_goal(self.db(), environment, goal) - } -} - -impl SolveIterationHelpers for S -where - S: SolveDatabase, - I: Interner, -{ -} - -struct RecursiveInferenceTableImpl { - infer: InferenceTable, -} - -impl RecursiveInferenceTable for RecursiveInferenceTableImpl { - fn instantiate_binders_universally<'a, T>( - &mut self, - interner: &'a I, - arg: &'a Binders, - ) -> T::Result - where - T: Fold + HasInterner, - { - self.infer.instantiate_binders_universally(interner, arg) - } - - fn instantiate_binders_existentially<'a, T>( - &mut self, - interner: &'a I, - arg: &'a Binders, - ) -> T::Result - where - T: Fold + HasInterner, - { - self.infer.instantiate_binders_existentially(interner, arg) - } - - fn canonicalize( - &mut self, - interner: &I, - value: &T, - ) -> (Canonical, Vec>) - where - T: Fold, - T::Result: HasInterner, - { - let res = self.infer.canonicalize(interner, value); - let free_vars = res - .free_vars - .into_iter() - .map(|free_var| free_var.to_generic_arg(interner)) - .collect(); - (res.quantified, free_vars) - } - - fn u_canonicalize( - &mut self, - interner: &I, - value0: &Canonical, - ) -> (UCanonical, UniverseMap) - where - T: HasInterner + Fold + Visit, - T::Result: HasInterner, - { - let res = self.infer.u_canonicalize(interner, value0); - (res.quantified, res.universes) - } - - fn unify( - &mut self, - interner: &I, - environment: &Environment, - a: &T, - b: &T, - ) -> Fallible<( - Vec>>, - Vec>>, - )> - where - T: ?Sized + Zip, - { - let res = self.infer.unify(interner, environment, a, b)?; - Ok((res.goals, res.constraints)) - } - - fn instantiate_canonical(&mut self, interner: &I, bound: &Canonical) -> T::Result - where - T: HasInterner + Fold + Debug, - { - self.infer.instantiate_canonical(interner, bound) - } - - fn invert_then_canonicalize( - &mut self, - interner: &I, - value: &T, - ) -> Option> - where - T: Fold + HasInterner, - { - self.infer.invert_then_canonicalize(interner, value) - } - - fn needs_truncation(&mut self, interner: &I, max_size: usize, value: impl Visit) -> bool { - truncate::needs_truncation(interner, &mut self.infer, max_size, value) - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/stack.rs b/vendor/chalk-solve-0.14.0/src/recursive/stack.rs deleted file mode 100644 index 917d39c764..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/stack.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::mem; -use std::ops::Index; -use std::ops::IndexMut; -use std::usize; - -pub(crate) struct Stack { - // program: Arc, - entries: Vec, - overflow_depth: usize, -} - -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub(crate) struct StackDepth { - depth: usize, -} - -/// The data we actively keep for each goal on the stack. -pub(crate) struct StackEntry { - /// Was this a coinductive goal? - coinductive_goal: bool, - - /// Initially false, set to true when some subgoal depends on us. - cycle: bool, -} - -impl Stack { - pub(crate) fn new( - // program: &Arc, - overflow_depth: usize, - ) -> Self { - Stack { - // program: program.clone(), - entries: vec![], - overflow_depth, - } - } - - pub(crate) fn is_empty(&self) -> bool { - self.entries.is_empty() - } - - pub(crate) fn push(&mut self, coinductive_goal: bool) -> StackDepth { - let depth = StackDepth { - depth: self.entries.len(), - }; - - if depth.depth >= self.overflow_depth { - // This shoudl perhaps be a result or something, though - // really I'd prefer to move to subgoal abstraction for - // guaranteeing termination. -nmatsakis - panic!("overflow depth reached") - } - - self.entries.push(StackEntry { - coinductive_goal, - cycle: false, - }); - depth - } - - pub(crate) fn pop(&mut self, depth: StackDepth) { - assert_eq!( - depth.depth + 1, - self.entries.len(), - "mismatched stack push/pop" - ); - self.entries.pop(); - } - - /// True if all the goals from the top of the stack down to (and - /// including) the given depth are coinductive. - pub(crate) fn coinductive_cycle_from(&self, depth: StackDepth) -> bool { - self.entries[depth.depth..] - .iter() - .all(|entry| entry.coinductive_goal) - } -} - -impl StackEntry { - pub(crate) fn flag_cycle(&mut self) { - self.cycle = true; - } - - pub(crate) fn read_and_reset_cycle_flag(&mut self) -> bool { - mem::replace(&mut self.cycle, false) - } -} - -impl Index for Stack { - type Output = StackEntry; - - fn index(&self, depth: StackDepth) -> &StackEntry { - &self.entries[depth.depth] - } -} - -impl IndexMut for Stack { - fn index_mut(&mut self, depth: StackDepth) -> &mut StackEntry { - &mut self.entries[depth.depth] - } -} diff --git a/vendor/chalk-solve-0.14.0/src/solve.rs b/vendor/chalk-solve-0.14.0/src/solve.rs deleted file mode 100644 index 342bb77119..0000000000 --- a/vendor/chalk-solve-0.14.0/src/solve.rs +++ /dev/null @@ -1,395 +0,0 @@ -use crate::RustIrDatabase; -use chalk_ir::interner::Interner; -use chalk_ir::*; -use std::fmt; - -#[cfg(feature = "slg-solver")] -pub use crate::solve::slg::SubstitutionResult; -#[cfg(feature = "slg-solver")] -use { - crate::solve::slg::{aggregate::AggregateOps, SlgContext, SlgContextOps}, - chalk_engine::context::{AnswerResult, AnswerStream, ContextOps}, - chalk_engine::forest::Forest, -}; - -#[cfg(feature = "recursive-solver")] -use crate::recursive::RecursiveContext; - -#[cfg(feature = "slg-solver")] -mod slg; -pub(crate) mod truncate; - -/// A (possible) solution for a proposed goal. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Solution { - /// The goal indeed holds, and there is a unique value for all existential - /// variables. In this case, we also record a set of lifetime constraints - /// which must also hold for the goal to be valid. - Unique(Canonical>), - - /// The goal may be provable in multiple ways, but regardless we may have some guidance - /// for type inference. In this case, we don't return any lifetime - /// constraints, since we have not "committed" to any particular solution - /// yet. - Ambig(Guidance), -} - -/// When a goal holds ambiguously (e.g., because there are multiple possible -/// solutions), we issue a set of *guidance* back to type inference. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Guidance { - /// The existential variables *must* have the given values if the goal is - /// ever to hold, but that alone isn't enough to guarantee the goal will - /// actually hold. - Definite(Canonical>), - - /// There are multiple plausible values for the existentials, but the ones - /// here are suggested as the preferred choice heuristically. These should - /// be used for inference fallback only. - Suggested(Canonical>), - - /// There's no useful information to feed back to type inference - Unknown, -} - -impl Solution { - pub fn is_unique(&self) -> bool { - match *self { - Solution::Unique(..) => true, - _ => false, - } - } - - pub fn display<'a>(&'a self, interner: &'a I) -> SolutionDisplay<'a, I> { - SolutionDisplay { - solution: self, - interner, - } - } -} - -pub struct SolutionDisplay<'a, I: Interner> { - solution: &'a Solution, - interner: &'a I, -} - -impl<'a, I: Interner> fmt::Display for SolutionDisplay<'a, I> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - let SolutionDisplay { solution, interner } = self; - match solution { - Solution::Unique(constrained) => write!(f, "Unique; {}", constrained.display(interner)), - Solution::Ambig(Guidance::Definite(subst)) => write!( - f, - "Ambiguous; definite substitution {}", - subst.display(interner) - ), - Solution::Ambig(Guidance::Suggested(subst)) => write!( - f, - "Ambiguous; suggested substitution {}", - subst.display(interner) - ), - Solution::Ambig(Guidance::Unknown) => write!(f, "Ambiguous; no inference guidance"), - } - } -} - -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub enum SolverChoice { - /// Run the SLG solver, producing a Solution. - #[cfg(feature = "slg-solver")] - SLG { - max_size: usize, - expected_answers: Option, - }, - /// Run the recursive solver. - #[cfg(feature = "recursive-solver")] - Recursive { - overflow_depth: usize, - caching_enabled: bool, - }, -} - -impl SolverChoice { - /// Returns specific SLG parameters. - #[cfg(feature = "slg-solver")] - pub fn slg(max_size: usize, expected_answers: Option) -> Self { - SolverChoice::SLG { - max_size, - expected_answers, - } - } - - /// Returns the default SLG parameters. - #[cfg(feature = "slg-solver")] - pub fn slg_default() -> Self { - SolverChoice::slg(10, None) - } - - /// Returns the default recursive solver setup. - #[cfg(feature = "recursive-solver")] - pub fn recursive() -> Self { - SolverChoice::Recursive { - overflow_depth: 100, - caching_enabled: true, - } - } - - /// Creates a solver state. - pub fn into_solver(self) -> Solver { - match self { - #[cfg(feature = "slg-solver")] - SolverChoice::SLG { - max_size, - expected_answers, - } => Solver(SolverImpl::Slg { - forest: Box::new(Forest::new()), - max_size, - expected_answers, - }), - #[cfg(feature = "recursive-solver")] - SolverChoice::Recursive { - overflow_depth, - caching_enabled, - } => Solver(SolverImpl::Recursive(Box::new(RecursiveContext::new( - overflow_depth, - caching_enabled, - )))), - } - } -} - -#[cfg(feature = "slg-solver")] -impl Default for SolverChoice { - fn default() -> Self { - SolverChoice::slg_default() - } -} - -#[cfg(all(not(feature = "slg-solver"), feature = "recursive-solver"))] -impl Default for SolverChoice { - fn default() -> Self { - SolverChoice::recursive() - } -} - -/// Finds the solution to "goals", or trait queries -- i.e., figures -/// out what sets of types implement which traits. Also, between -/// queries, this struct stores the cached state from previous solver -/// attempts, which can then be re-used later. -pub struct Solver(SolverImpl); - -enum SolverImpl { - #[cfg(feature = "slg-solver")] - Slg { - forest: Box>>, - max_size: usize, - /// The expected number of answers for a solution. - /// Only really useful for tests, since `make_solution` - /// will panic if the number of cached answers does not - /// equal this when a solution is made. - expected_answers: Option, - }, - #[cfg(feature = "recursive-solver")] - Recursive(Box>), -} - -impl Solver { - /// Attempts to solve the given goal, which must be in canonical - /// form. Returns a unique solution (if one exists). This will do - /// only as much work towards `goal` as it has to (and that work - /// is cached for future attempts). - /// - /// # Parameters - /// - /// - `program` -- defines the program clauses in scope. - /// - **Important:** You must supply the same set of program clauses - /// each time you invoke `solve`, as otherwise the cached data may be - /// invalid. - /// - `goal` the goal to solve - /// - /// # Returns - /// - /// - `None` is the goal cannot be proven. - /// - `Some(solution)` if we succeeded in finding *some* answers, - /// although `solution` may reflect ambiguity and unknowns. - pub fn solve( - &mut self, - program: &dyn RustIrDatabase, - goal: &UCanonical>>, - ) -> Option> { - match &mut self.0 { - #[cfg(feature = "slg-solver")] - SolverImpl::Slg { - forest, - max_size, - expected_answers, - } => { - let ops = SlgContextOps::new(program, *max_size, *expected_answers); - ops.make_solution(goal, forest.iter_answers(&ops, goal), || true) - } - #[cfg(feature = "recursive-solver")] - SolverImpl::Recursive(ctx) => { - ctx.solver(program) - .solve_root_goal(goal) - .ok() - .map(|s| match s { - crate::recursive::lib::Solution::Unique(c) => { - crate::solve::Solution::Unique(c) - } - crate::recursive::lib::Solution::Ambig(g) => { - crate::solve::Solution::Ambig(match g { - crate::recursive::lib::Guidance::Definite(g) => { - crate::solve::Guidance::Definite(g) - } - crate::recursive::lib::Guidance::Suggested(g) => { - crate::solve::Guidance::Suggested(g) - } - crate::recursive::lib::Guidance::Unknown => { - crate::solve::Guidance::Unknown - } - }) - } - }) - } - } - } - - /// Attempts to solve the given goal, which must be in canonical - /// form. Returns a unique solution (if one exists). This will do - /// only as much work towards `goal` as it has to (and that work - /// is cached for future attempts). In addition, the solving of the - /// goal can be limited by returning `false` from `should_continue`. - /// - /// # Parameters - /// - /// - `program` -- defines the program clauses in scope. - /// - **Important:** You must supply the same set of program clauses - /// each time you invoke `solve`, as otherwise the cached data may be - /// invalid. - /// - `goal` the goal to solve - /// - `should_continue` if `false` is returned, the no further solving - /// will be done. A `Guidance(Suggested(...))` will be returned a - /// `Solution`, using any answers that were generated up to that point. - /// - /// # Returns - /// - /// - `None` is the goal cannot be proven. - /// - `Some(solution)` if we succeeded in finding *some* answers, - /// although `solution` may reflect ambiguity and unknowns. - pub fn solve_limited( - &mut self, - program: &dyn RustIrDatabase, - goal: &UCanonical>>, - should_continue: impl std::ops::Fn() -> bool, - ) -> Option> { - match &mut self.0 { - #[cfg(feature = "slg-solver")] - SolverImpl::Slg { - forest, - max_size, - expected_answers, - } => { - let ops = SlgContextOps::new(program, *max_size, *expected_answers); - ops.make_solution(goal, forest.iter_answers(&ops, goal), should_continue) - } - #[cfg(feature = "recursive-solver")] - SolverImpl::Recursive(ctx) => { - // TODO support should_continue in recursive solver - ctx.solver(program) - .solve_root_goal(goal) - .ok() - .map(|s| match s { - crate::recursive::lib::Solution::Unique(c) => { - crate::solve::Solution::Unique(c) - } - crate::recursive::lib::Solution::Ambig(g) => { - crate::solve::Solution::Ambig(match g { - crate::recursive::lib::Guidance::Definite(g) => { - crate::solve::Guidance::Definite(g) - } - crate::recursive::lib::Guidance::Suggested(g) => { - crate::solve::Guidance::Suggested(g) - } - crate::recursive::lib::Guidance::Unknown => { - crate::solve::Guidance::Unknown - } - }) - } - }) - } - } - } - - /// Attempts to solve the given goal, which must be in canonical - /// form. Provides multiple solutions to function `f`. This will do - /// only as much work towards `goal` as it has to (and that work - /// is cached for future attempts). - /// - /// # Parameters - /// - /// - `program` -- defines the program clauses in scope. - /// - **Important:** You must supply the same set of program clauses - /// each time you invoke `solve`, as otherwise the cached data may be - /// invalid. - /// - `goal` the goal to solve - /// - `f` -- function to proceed solution. New solutions will be generated - /// while function returns `true`. - /// - first argument is solution found - /// - second argument is ther next solution present - /// - returns true if next solution should be handled - /// - /// # Returns - /// - /// - `true` all solutions were processed with the function. - /// - `false` the function returned `false` and solutions were interrupted. - #[cfg(feature = "slg-solver")] - pub fn solve_multiple( - &mut self, - program: &dyn RustIrDatabase, - goal: &UCanonical>>, - mut f: impl FnMut(SubstitutionResult>>, bool) -> bool, - ) -> bool { - match &mut self.0 { - SolverImpl::Slg { - forest, - max_size, - expected_answers, - } => { - let ops = SlgContextOps::new(program, *max_size, *expected_answers); - let mut answers = forest.iter_answers(&ops, goal); - loop { - let subst = match answers.next_answer(|| true) { - AnswerResult::Answer(answer) => { - if !answer.ambiguous { - SubstitutionResult::Definite(answer.subst) - } else { - if ops.is_trivial_constrained_substitution(&answer.subst) { - SubstitutionResult::Floundered - } else { - SubstitutionResult::Ambiguous(answer.subst) - } - } - } - AnswerResult::Floundered => SubstitutionResult::Floundered, - AnswerResult::NoMoreSolutions => { - return true; - } - AnswerResult::QuantumExceeded => continue, - }; - - if !f(subst, !answers.peek_answer(|| true).is_no_more_solutions()) { - return false; - } - } - } - #[cfg(feature = "recursive-solver")] - SolverImpl::Recursive(_ctx) => unimplemented!(), - } - } -} - -impl std::fmt::Debug for Solver { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "Solver {{ .. }}") - } -} diff --git a/vendor/chalk-solve-0.14.0/src/test_macros.rs b/vendor/chalk-solve-0.14.0/src/test_macros.rs deleted file mode 100644 index 20f39e3fdb..0000000000 --- a/vendor/chalk-solve-0.14.0/src/test_macros.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! Useful macros for writing unit tests. They let you gin up dummy types and things. - -macro_rules! ty { - (apply $n:tt $($arg:tt)*) => { - chalk_ir::TyData::Apply(ApplicationTy { - name: ty_name!($n), - substitution: chalk_ir::Substitution::from( - &chalk_integration::interner::ChalkIr, - vec![$(arg!($arg)),*] as Vec> - ), - }).intern(&chalk_integration::interner::ChalkIr) - }; - - (function $n:tt $($arg:tt)*) => { - chalk_ir::TyData::Function(Fn { - num_binders: $n, - substitution: chalk_ir::Substitution::from( - &chalk_integration::interner::ChalkIr, - vec![$(arg!($arg)),*] as Vec> - ), - }).intern(&chalk_integration::interner::ChalkIr) - }; - - (placeholder $n:expr) => { - chalk_ir::TyData::Placeholder(PlaceholderIndex { - ui: UniverseIndex { counter: $n }, - idx: 0, - }).intern(&chalk_integration::interner::ChalkIr) - }; - - (projection (item $n:tt) $($arg:tt)*) => { - chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id: AssocTypeId(chalk_integration::interner::RawId { index: $n }), - substitution: chalk_ir::Substitution::from( - &chalk_integration::interner::ChalkIr, - vec![$(arg!($arg)),*] as Vec> - ), - }).intern(&chalk_integration::interner::ChalkIr) - }; - - (infer $b:expr) => { - chalk_ir::TyData::InferenceVar(chalk_ir::InferenceVar::from($b), chalk_ir::TyKind::General) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (bound $d:tt $b:tt) => { - chalk_ir::TyData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::new($d), $b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (bound $b:expr) => { - chalk_ir::TyData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::INNERMOST, $b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (expr $b:expr) => { - $b.clone() - }; - - (($($b:tt)*)) => { - ty!($($b)*) - }; -} - -macro_rules! arg { - ((lifetime $b:tt)) => { - chalk_ir::GenericArg::new( - &chalk_integration::interner::ChalkIr, - chalk_ir::GenericArgData::Lifetime(lifetime!($b)), - ) - }; - - ($arg:tt) => { - chalk_ir::GenericArg::new( - &chalk_integration::interner::ChalkIr, - chalk_ir::GenericArgData::Ty(ty!($arg)), - ) - }; -} - -macro_rules! lifetime { - (infer $b:expr) => { - chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from($b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (bound $d:tt $b:tt) => { - chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::new($d), $b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (bound $b:expr) => { - chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::INNERMOST, $b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (placeholder $b:expr) => { - chalk_ir::LifetimeData::Placeholder(PlaceholderIndex { ui: UniverseIndex { counter: $b }, idx: 0}) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (expr $b:expr) => { - $b.clone() - }; - - (($($b:tt)*)) => { - lifetime!($($b)*) - }; -} - -macro_rules! ty_name { - ((item $n:expr)) => { - chalk_ir::TypeName::Adt(AdtId(chalk_integration::interner::RawId { index: $n })) - }; -} diff --git a/vendor/chalk-solve-0.25.0/.cargo-checksum.json b/vendor/chalk-solve-0.25.0/.cargo-checksum.json new file mode 100644 index 0000000000..8b5dbeb285 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"b5c6f88446f266ca3638fb46bd55caac0d836b5452ca46033ca13a39c1c1d9f8","README.md":"2de2da988dbbaa8feb78b0a771b7bee942f34705ab057c824b1183300c535c74","src/clauses.rs":"b4e8d03cf1137b3512b3dee245d05471396069131e2391ca667d3b192c942425","src/clauses/builder.rs":"ea0e37237addb834d3b274d316fae270dcbd418fc89d3c6cebf09e31fe346634","src/clauses/builtin_traits.rs":"0d8280fa4b261154a101698d2dbb63e5ff14c314fd7801732055c2f9d1ab66d0","src/clauses/builtin_traits/clone.rs":"963a3a192aa8283733d3bc2c0a5e7cf0debcf47986df85a25eef3e3c647de257","src/clauses/builtin_traits/copy.rs":"e5e2e9d8355fb2aaf36ab6d9ab89cf28d6a0984eb621773cb8a4d82a6302e25c","src/clauses/builtin_traits/fn_family.rs":"b81715f2521a1ee9aafd429931c2a250675898f0ee121c374298cb4af20aff58","src/clauses/builtin_traits/sized.rs":"7147c0bdc117fb7e768430ad963ce5c627bfe3641c04e3269f8a08a215c93dab","src/clauses/builtin_traits/unsize.rs":"9ac311cc905d068f5626204cdacadfe8b3e9c126fb821c8cbd054f7fd21165d2","src/clauses/dyn_ty.rs":"7c32ccd5a3bc7479b0e34ca2d3da254edcc7f73e38ace9f1860c5f64bb8def8a","src/clauses/env_elaborator.rs":"bd598d47075b7c5366c9db55d99b1426c7ea646bd2508c7674bcc52d918bdf76","src/clauses/generalize.rs":"c44f8e559a12f67ad55cff2dd3ffb39d9333cf39a7c8b78c6a8fe87e764c2f98","src/clauses/program_clauses.rs":"4ff101e17087299b3e431796dbb2fe8950b2bb3f2f4b2e7b4464bd3698656d41","src/coherence.rs":"665658b1dda7d5a37e9183a6ff176048c5b1001d23766b3b97288cdf8f3a94cc","src/coherence/orphan.rs":"621a839058309f1977e9eea972afa1622a372e06889d8d20aff64788cfba1829","src/coherence/solve.rs":"34746fd1a3e5984b8b3163bf89a906f5e2f99f17f57b1364ec688c3754d5272e","src/coinductive_goal.rs":"7a2179fb2d61435cf55c5c87301db6c15edb3cb46750bea381451649b2f1051d","src/display.rs":"c5c0a796b6037dea1cf18dcb063f0ccd3bd82012b480231f4e15d2186bb9a9f8","src/display/bounds.rs":"47b402d34c9a0cb7d4f4f35b40d86f983b6a335c9dfae95645eaa472404b6098","src/display/identifiers.rs":"22937fc099812dd9282c20c77ad3797cfa13a8838a0c68638bc4fc32178afbc8","src/display/items.rs":"0e24b30a35c079b8661c2fb5f957b0fc5932b5aef995495fa0c96b3a045f3650","src/display/render_trait.rs":"ccdcbe8e5a1771630dd61eb24b8e384fc30147c285bd40865f9ccc87ab4931b7","src/display/state.rs":"598f115023570bb6659a043d2410aef538364473031e53018bd78c247658d51b","src/display/stub.rs":"28e1ee74aefd8e491956f30e7c703778b68b62288e4763bb429313c5cbe5738e","src/display/ty.rs":"6673ac4c5e767b2afb35d133ff607cfba7f9bc9514ed6888b678ded09891d50c","src/display/utils.rs":"929d68b566265674e31a3fce6ffa0123fd6fc7b7c7323baf62aefd56ce67e085","src/ext.rs":"b71de835698b02434ffb67000d33bd82be53c3dadd41aee0056f0e4b31e102cd","src/goal_builder.rs":"1acef3990ec74d515200c2f42045028496f1799352d945481505ca00698d9838","src/infer.rs":"b5a533153d2a3ae342892b250d0eac0dcd87a26a38626a3753f326d3ce93966e","src/infer/canonicalize.rs":"85de8d18c62b151587a8df45af65b105faa20a14c033ca38d5b20965614ac515","src/infer/instantiate.rs":"0b43c5b86afae964298cc33b11d89b81feb8094074aa71ebcbbfa218c6a11a86","src/infer/invert.rs":"18ff374ff9ac9735ecedd66b3afa8dfa3531867d2b578eb011fdd97d56e150c1","src/infer/test.rs":"b3e69f1110aca3e6d261e01d2da7b7159b08e3e6345375f55bedaf3ae4c995aa","src/infer/ucanonicalize.rs":"f53f9b113921e122646d90075c0c518c48b3e6483b2bce72e3edc22083fcf957","src/infer/unify.rs":"fb17f98014d56618d5ea3ff0b491387c986266a1b80fe3bf906135f1b859a6a3","src/infer/var.rs":"35f88c269fbe1c7da572d9b21a64a1bed80036c563d91f7c71a639c51cac9801","src/lib.rs":"35517aa1e7b3ddaad9d52babedb497f5d068c48ce44ee768d2db171a7f3ed08e","src/logging.rs":"a3e3fa6bb03f29db9f87aedfa6051d4ad649c2aa2be292d03260d64c9bb8c5e2","src/logging_db.rs":"6d153fcf823a19680ab015286ad3d6e2ab47e1f6b39262f77271e664f8acef27","src/logging_db/id_collector.rs":"1f793e32ddb4b4562f139a63e9888a3320291209e91370ec7475b37a6dd396e2","src/recursive/lib.rs":"24f1dd3310eae203607835f063de7b8ed0fc75dee934428ad08abedb6c3e8704","src/rust_ir.rs":"f122a9c96aaa17f02739fb7443b3ffc38fcdd2c1b2a08b39cf3184011d43a403","src/solve.rs":"aa4d20a73dce06a0a5bb0459f4b2bdd80fd842d7a193f65ca48878ed915c6dd3","src/solve/test/bench.rs":"8da8bb948bdf598ed7f225fd695b12c9e8626cd7a14d4b7d8650de0fae73d655","src/solve/truncate.rs":"f77bacc0545b4f6af841fd4707185bb79bac768eabb44a9bdc9514b9f19800d0","src/split.rs":"f01ead861bc2abf79b08a67c7d620e8794f73db833ec516b5115602aa9d07d1c","src/wf.rs":"546fa2af849cd8afa480896c6e52816e96e2705b3d10628388eedfded1a6ddd0"},"package":"45b235a1f568b28707f117b2d30eabbee9cbcfccaa0d6e9697300400c8ca0996"} \ No newline at end of file diff --git a/vendor/chalk-solve-0.14.0/Cargo.toml b/vendor/chalk-solve-0.25.0/Cargo.toml similarity index 79% rename from vendor/chalk-solve-0.14.0/Cargo.toml rename to vendor/chalk-solve-0.25.0/Cargo.toml index a330a1dd0f..0267d04875 100644 --- a/vendor/chalk-solve-0.14.0/Cargo.toml +++ b/vendor/chalk-solve-0.25.0/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-solve" -version = "0.14.0" +version = "0.25.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Combines the chalk-engine with chalk-ir" readme = "README.md" @@ -21,14 +21,10 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.14.0" - -[dependencies.chalk-engine] -version = "=0.14.0" -optional = true +version = "=0.25.0" [dependencies.chalk-ir] -version = "=0.14.0" +version = "=0.25.0" [dependencies.ena] version = "0.14.0" @@ -37,17 +33,24 @@ version = "0.14.0" version = "0.9.0" [dependencies.petgraph] -version = "0.5.0" +version = "0.5.1" [dependencies.rustc-hash] -version = "1.0.0" +version = "1.1.0" [dependencies.tracing] version = "0.1" +[dependencies.tracing-subscriber] +version = "0.2" +optional = true + +[dependencies.tracing-tree] +version = "0.1.4" +optional = true + [dev-dependencies] [features] -default = ["slg-solver", "recursive-solver"] -recursive-solver = [] -slg-solver = ["chalk-engine"] +default = ["tracing-full"] +tracing-full = ["tracing-subscriber", "tracing-tree"] diff --git a/vendor/chalk-solve-0.14.0/README.md b/vendor/chalk-solve-0.25.0/README.md similarity index 100% rename from vendor/chalk-solve-0.14.0/README.md rename to vendor/chalk-solve-0.25.0/README.md diff --git a/vendor/chalk-solve-0.14.0/src/clauses.rs b/vendor/chalk-solve-0.25.0/src/clauses.rs similarity index 66% rename from vendor/chalk-solve-0.14.0/src/clauses.rs rename to vendor/chalk-solve-0.25.0/src/clauses.rs index 7fc248363f..db54807664 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses.rs @@ -3,11 +3,12 @@ use self::env_elaborator::elaborate_env_clauses; use self::program_clauses::ToProgramClauses; use crate::split::Split; use crate::RustIrDatabase; -use chalk_ir::cast::Cast; +use chalk_ir::cast::{Cast, Caster}; use chalk_ir::could_match::CouldMatch; use chalk_ir::interner::Interner; use chalk_ir::*; use rustc_hash::FxHashSet; +use std::iter; use tracing::{debug, instrument}; pub mod builder; @@ -17,6 +18,7 @@ mod env_elaborator; mod generalize; pub mod program_clauses; +/// FIXME(#505) update comments for ADTs /// For auto-traits, we generate a default rule for every struct, /// unless there is a manual impl for that struct given explicitly. /// @@ -73,8 +75,8 @@ pub fn push_auto_trait_impls( return; } - let binders = adt_datum.binders.map_ref(|b| &b.fields); - builder.push_binders(&binders, |builder, fields| { + let binders = adt_datum.binders.map_ref(|b| &b.variants); + builder.push_binders(&binders, |builder, variants| { let self_ty: Ty<_> = ApplicationTy { name: adt_id.cast(interner), substitution: builder.substitution_in_scope(), @@ -95,9 +97,11 @@ pub fn push_auto_trait_impls( // } builder.push_clause( auto_trait_ref, - fields.iter().map(|field_ty| TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, field_ty.clone()), + variants.iter().flat_map(|variant| { + variant.fields.iter().map(|field_ty| TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, field_ty.clone()), + }) }), ); }); @@ -168,16 +172,17 @@ pub fn push_auto_trait_impls_opaque( /// is `Implemented(T: Clone)`, then this function might return clauses /// derived from the trait `Clone` and its impls. #[instrument(level = "debug", skip(db))] -pub(crate) fn program_clauses_for_goal<'db, I: Interner>( +pub fn program_clauses_for_goal<'db, I: Interner>( db: &'db dyn RustIrDatabase, environment: &Environment, goal: &DomainGoal, + binders: &CanonicalVarKinds, ) -> Result>, Floundered> { let interner = db.interner(); let custom_clauses = db.custom_clauses().into_iter(); - let clauses_that_could_match = - program_clauses_that_could_match(db, environment, goal).map(|cl| cl.into_iter())?; + let clauses_that_could_match = program_clauses_that_could_match(db, environment, goal, binders) + .map(|cl| cl.into_iter())?; let clauses: Vec> = custom_clauses .chain(clauses_that_could_match) @@ -189,7 +194,7 @@ pub(crate) fn program_clauses_for_goal<'db, I: Interner>( .filter(|c| c.could_match(interner, goal)) .collect(); - debug!("vec = {:#?}", clauses); + debug!(?clauses); Ok(clauses) } @@ -203,6 +208,11 @@ fn program_clauses_that_could_match( db: &dyn RustIrDatabase, environment: &Environment, goal: &DomainGoal, + // FIXME: These are the binders for `goal`. We're passing them separately + // because `goal` is not necessarily canonicalized: The recursive solver + // passes the canonical goal; the SLG solver instantiates the goal first. + // (See #568.) + binders: &CanonicalVarKinds, ) -> Result>, Floundered> { let interner = db.interner(); let mut clauses: Vec> = vec![]; @@ -221,22 +231,22 @@ fn program_clauses_that_could_match( if trait_datum.is_auto_trait() { push_auto_trait_impls_opaque(builder, trait_id, opaque_ty.opaque_ty_id) } - } else if self_ty.bound_var(interner).is_some() - || self_ty.inference_var(interner).is_some() - { + } else if self_ty.is_general_var(interner, binders) { return Err(Floundered); } } // This is needed for the coherence related impls, as well // as for the `Implemented(Foo) :- FromEnv(Foo)` rule. - trait_datum.to_program_clauses(builder); + trait_datum.to_program_clauses(builder, environment); for impl_id in db.impls_for_trait( trait_ref.trait_id, - trait_ref.substitution.parameters(interner), + trait_ref.substitution.as_slice(interner), + binders, ) { - db.impl_datum(impl_id).to_program_clauses(builder); + db.impl_datum(impl_id) + .to_program_clauses(builder, environment); } // If this is a `Foo: Send` (or any auto-trait), then add @@ -279,13 +289,33 @@ fn program_clauses_that_could_match( .. }) | TyData::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, .. })) => { - db.opaque_ty_data(*opaque_ty_id).to_program_clauses(builder); + db.opaque_ty_data(*opaque_ty_id) + .to_program_clauses(builder, environment); + } + _ => {} + } + + // We don't actually do anything here, but we need to record the types it when logging + match self_ty.data(interner) { + TyData::Apply(ApplicationTy { + name: TypeName::Adt(adt_id), + .. + }) => { + let _ = db.adt_datum(*adt_id); + } + TyData::Apply(ApplicationTy { + name: TypeName::FnDef(fn_def_id), + .. + }) => { + let _ = db.fn_def_datum(*fn_def_id); } _ => {} } if let Some(well_known) = trait_datum.well_known { - builtin_traits::add_builtin_program_clauses(db, builder, well_known, trait_ref)?; + builtin_traits::add_builtin_program_clauses( + db, builder, well_known, trait_ref, binders, + )?; } } DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => match &alias_eq.alias { @@ -300,23 +330,62 @@ fn program_clauses_that_could_match( .. }) | TyData::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, .. })) => { - db.opaque_ty_data(*opaque_ty_id).to_program_clauses(builder); + db.opaque_ty_data(*opaque_ty_id) + .to_program_clauses(builder, environment); } _ => {} } + // If the self type is a `dyn trait` type, generate program-clauses + // for any associated type bindings it contains. + // FIXME: see the fixme for the analogous code for Implemented goals. + if let TyData::Dyn(_) = trait_self_ty.data(interner) { + dyn_ty::build_dyn_self_ty_clauses(db, builder, trait_self_ty.clone()) + } + db.associated_ty_data(proj.associated_ty_id) - .to_program_clauses(builder) + .to_program_clauses(builder, environment) } AliasTy::Opaque(opaque_ty) => db .opaque_ty_data(opaque_ty.opaque_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), }, - DomainGoal::Holds(WhereClause::LifetimeOutlives(_)) => {} + DomainGoal::Holds(WhereClause::LifetimeOutlives(..)) => { + builder.push_bound_lifetime(|builder, a| { + builder.push_bound_lifetime(|builder, b| { + builder.push_fact_with_constraints( + DomainGoal::Holds(WhereClause::LifetimeOutlives(LifetimeOutlives { + a: a.clone(), + b: b.clone(), + })), + Some(InEnvironment::new( + environment, + Constraint::LifetimeOutlives(a, b), + )), + ); + }) + }); + } + DomainGoal::Holds(WhereClause::TypeOutlives(..)) => { + builder.push_bound_ty(|builder, ty| { + builder.push_bound_lifetime(|builder, lifetime| { + builder.push_fact_with_constraints( + DomainGoal::Holds(WhereClause::TypeOutlives(TypeOutlives { + ty: ty.clone(), + lifetime: lifetime.clone(), + })), + Some(InEnvironment::new( + environment, + Constraint::TypeOutlives(ty, lifetime), + )), + ) + }) + }); + } DomainGoal::WellFormed(WellFormed::Trait(trait_ref)) | DomainGoal::LocalImplAllowed(trait_ref) => { db.trait_datum(trait_ref.trait_id) - .to_program_clauses(builder); + .to_program_clauses(builder, environment); } DomainGoal::ObjectSafe(trait_id) => { if builder.db.is_object_safe(*trait_id) { @@ -353,7 +422,9 @@ fn program_clauses_that_could_match( // Flounder if the self-type is unknown and the trait is non-enumerable. // // e.g., Normalize(::Item = u32) - if (self_ty.is_var(interner)) && trait_datum.is_non_enumerable_trait() { + if (self_ty.is_general_var(interner, binders)) + && trait_datum.is_non_enumerable_trait() + { return Err(Floundered); } @@ -365,18 +436,87 @@ fn program_clauses_that_could_match( push_program_clauses_for_associated_type_values_in_impls_of( builder, + environment, trait_id, trait_parameters, + binders, ); + + if environment.has_compatible_clause(interner) { + push_clauses_for_compatible_normalize( + db, + builder, + interner, + trait_id, + proj.associated_ty_id, + ); + } } AliasTy::Opaque(_) => (), }, - DomainGoal::Compatible(()) | DomainGoal::Reveal(()) => (), + DomainGoal::Compatible | DomainGoal::Reveal => (), }; Ok(clauses) } +/// Adds clauses to allow normalizing possible downstream associated type +/// implementations when in the "compatible" mode. Example clauses: +/// +/// ```notrust +/// for Normalize(<^0.0 as Trait<^0.1>>::Item -> ^0.2) +/// :- Compatible, Implemented(^0.0: Trait<^0.1>), DownstreamType(^0.1), CannotProve +/// for Normalize(<^0.0 as Trait<^0.1>>::Item -> ^0.2) +/// :- Compatible, Implemented(^0.0: Trait<^0.1>), IsFullyVisible(^0.0), DownstreamType(^0.1), CannotProve +/// ``` +fn push_clauses_for_compatible_normalize( + db: &dyn RustIrDatabase, + builder: &mut ClauseBuilder<'_, I>, + interner: &I, + trait_id: TraitId, + associated_ty_id: AssocTypeId, +) { + let trait_datum = db.trait_datum(trait_id); + let trait_binders = trait_datum.binders.map_ref(|b| &b.where_clauses); + builder.push_binders(&trait_binders, |builder, where_clauses| { + let projection = ProjectionTy { + associated_ty_id, + substitution: builder.substitution_in_scope(), + }; + let trait_ref = TraitRef { + trait_id, + substitution: builder.substitution_in_scope(), + }; + let type_parameters: Vec<_> = trait_ref.type_parameters(interner).collect(); + + builder.push_bound_ty(|builder, target_ty| { + for i in 0..type_parameters.len() { + builder.push_clause( + DomainGoal::Normalize(Normalize { + ty: target_ty.clone(), + alias: AliasTy::Projection(projection.clone()), + }), + where_clauses + .iter() + .cloned() + .casted(interner) + .chain(iter::once(DomainGoal::Compatible.cast(interner))) + .chain(iter::once( + WhereClause::Implemented(trait_ref.clone()).cast(interner), + )) + .chain((0..i).map(|j| { + DomainGoal::IsFullyVisible(type_parameters[j].clone()).cast(interner) + })) + .chain(iter::once( + DomainGoal::DownstreamType(type_parameters[i].clone()).cast(interner), + )) + .chain(iter::once(GoalData::CannotProve.intern(interner))), + ); + } + }); + }); +} + /// Generate program clauses from the associated-type values /// found in impls of the given trait. i.e., if `trait_id` = Iterator, /// then we would generate program clauses from each `type Item = ...` @@ -394,21 +534,26 @@ fn program_clauses_that_could_match( #[instrument(level = "debug", skip(builder))] fn push_program_clauses_for_associated_type_values_in_impls_of( builder: &mut ClauseBuilder<'_, I>, + environment: &Environment, trait_id: TraitId, trait_parameters: &[GenericArg], + binders: &CanonicalVarKinds, ) { - for impl_id in builder.db.impls_for_trait(trait_id, trait_parameters) { + for impl_id in builder + .db + .impls_for_trait(trait_id, trait_parameters, binders) + { let impl_datum = builder.db.impl_datum(impl_id); if !impl_datum.is_positive() { continue; } - debug!("impl_id = {:?}", impl_id); + debug!(?impl_id); for &atv_id in &impl_datum.associated_ty_value_ids { let atv = builder.db.associated_ty_value(atv_id); - debug!("atv_id = {:?} atv = {:#?}", atv_id, atv); - atv.to_program_clauses(builder); + debug!(?atv_id, ?atv); + atv.to_program_clauses(builder, environment); } } } @@ -431,18 +576,18 @@ fn match_ty( ) -> Result<(), Floundered> { let interner = builder.interner(); Ok(match ty.data(interner) { - TyData::Apply(application_ty) => match_type_name(builder, interner, application_ty), + TyData::Apply(application_ty) => match_type_name(builder, environment, application_ty), TyData::Placeholder(_) => { builder.push_clause(WellFormed::Ty(ty.clone()), Some(FromEnv::Ty(ty.clone()))); } TyData::Alias(AliasTy::Projection(proj)) => builder .db .associated_ty_data(proj.associated_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TyData::Alias(AliasTy::Opaque(opaque_ty)) => builder .db .opaque_ty_data(opaque_ty.opaque_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TyData::Function(quantified_ty) => { builder.push_fact(WellFormed::Ty(ty.clone())); quantified_ty @@ -460,24 +605,28 @@ fn match_ty( /// Lower a Rust IR application type to logic fn match_type_name( builder: &mut ClauseBuilder<'_, I>, - interner: &I, + environment: &Environment, application: &ApplicationTy, ) { + let interner = builder.interner(); match application.name { - TypeName::Adt(adt_id) => match_adt(builder, adt_id), + TypeName::Adt(adt_id) => builder + .db + .adt_datum(adt_id) + .to_program_clauses(builder, environment), TypeName::OpaqueType(opaque_ty_id) => builder .db .opaque_ty_data(opaque_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TypeName::Error => {} TypeName::AssociatedType(type_id) => builder .db .associated_ty_data(type_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TypeName::FnDef(fn_def_id) => builder .db .fn_def_datum(fn_def_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TypeName::Tuple(_) | TypeName::Scalar(_) | TypeName::Str @@ -492,20 +641,20 @@ fn match_type_name( } } -fn match_alias_ty(builder: &mut ClauseBuilder<'_, I>, alias: &AliasTy) { +fn match_alias_ty( + builder: &mut ClauseBuilder<'_, I>, + environment: &Environment, + alias: &AliasTy, +) { match alias { AliasTy::Projection(projection_ty) => builder .db .associated_ty_data(projection_ty.associated_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), _ => (), } } -fn match_adt(builder: &mut ClauseBuilder<'_, I>, adt_id: AdtId) { - builder.db.adt_datum(adt_id).to_program_clauses(builder) -} - pub fn program_clauses_for_env<'db, I: Interner>( db: &'db dyn RustIrDatabase, environment: &Environment, @@ -519,7 +668,12 @@ pub fn program_clauses_for_env<'db, I: Interner>( let mut closure = last_round.clone(); let mut next_round = FxHashSet::default(); while !last_round.is_empty() { - elaborate_env_clauses(db, &last_round.drain().collect::>(), &mut next_round); + elaborate_env_clauses( + db, + &last_round.drain().collect::>(), + &mut next_round, + environment, + ); last_round.extend( next_round .drain() @@ -527,5 +681,5 @@ pub fn program_clauses_for_env<'db, I: Interner>( ); } - ProgramClauses::from(db.interner(), closure) + ProgramClauses::from_iter(db.interner(), closure) } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builder.rs b/vendor/chalk-solve-0.25.0/src/clauses/builder.rs similarity index 74% rename from vendor/chalk-solve-0.14.0/src/clauses/builder.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builder.rs index 7bd4085617..2359358d4a 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builder.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builder.rs @@ -1,4 +1,3 @@ -use std::iter; use std::marker::PhantomData; use crate::cast::{Cast, CastTo}; @@ -44,9 +43,10 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { pub fn push_fact_with_priority( &mut self, consequence: impl CastTo>, + constraints: impl IntoIterator>>, priority: ClausePriority, ) { - self.push_clause_with_priority(consequence, None::>, priority); + self.push_clause_with_priority(consequence, None::>, constraints, priority); } /// Pushes a clause `forall<..> { consequence :- conditions }` @@ -58,23 +58,34 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { consequence: impl CastTo>, conditions: impl IntoIterator>>, ) { - self.push_clause_with_priority(consequence, conditions, ClausePriority::High) + self.push_clause_with_priority(consequence, conditions, None, ClausePriority::High) } - /// Pushes a clause `forall<..> { consequence :- conditions }` + pub fn push_fact_with_constraints( + &mut self, + consequence: impl CastTo>, + constraints: impl IntoIterator>>, + ) { + self.push_fact_with_priority(consequence, constraints, ClausePriority::High) + } + + /// Pushes a clause `forall<..> { consequence :- conditions ; constraints }` /// into the set of program clauses, meaning that `consequence` - /// can be proven if `conditions` are all true. The `forall<..>` - /// binders will be whichever binders have been pushed (see `push_binders`). + /// can be proven if `conditions` are all true and `constraints` + /// are proven to hold. The `forall<..>` binders will be whichever binders + /// have been pushed (see `push_binders`). pub fn push_clause_with_priority( &mut self, consequence: impl CastTo>, conditions: impl IntoIterator>>, + constraints: impl IntoIterator>>, priority: ClausePriority, ) { let interner = self.db.interner(); let clause = ProgramClauseImplication { consequence: consequence.cast(interner), - conditions: Goals::from(interner, conditions), + conditions: Goals::from_iter(interner, conditions), + constraints: Constraints::from_iter(interner, constraints), priority, }; @@ -87,7 +98,7 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { self.clauses.push( ProgramClauseData(Binders::new( - VariableKinds::from(interner, self.binders.clone()), + VariableKinds::from_iter(interner, self.binders.clone()), clause, )) .intern(interner), @@ -104,7 +115,7 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { /// Accesses the placeholders for the current list of parameters in scope, /// in the form of a `Substitution`. pub fn substitution_in_scope(&self) -> Substitution { - Substitution::from( + Substitution::from_iter( self.db.interner(), self.placeholders_in_scope().iter().cloned(), ) @@ -135,11 +146,11 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { .binders .iter(interner) .zip(old_len..) - .map(|p| p.to_generic_arg(interner)), + .map(|(pk, i)| (i, pk).to_generic_arg(interner)), ); let value = binders.substitute(self.interner(), &self.parameters[old_len..]); - debug!("push_binders: value={:?}", value); + debug!(?value); let res = op(self, value); self.binders.truncate(old_len); @@ -152,11 +163,10 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { /// unaffected and hence the context remains usable. Invokes `op`, /// passing a type representing this new type variable in as an /// argument. - #[allow(dead_code)] pub fn push_bound_ty(&mut self, op: impl FnOnce(&mut Self, Ty)) { let interner = self.interner(); let binders = Binders::new( - VariableKinds::from(interner, iter::once(VariableKind::Ty(TyKind::General))), + VariableKinds::from1(interner, VariableKind::Ty(TyKind::General)), PhantomData::, ); self.push_binders(&binders, |this, PhantomData| { @@ -170,6 +180,28 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { }); } + /// Push a single binder, for a lifetime, at the end of the binder + /// list. The indices of previously bound variables are + /// unaffected and hence the context remains usable. Invokes `op`, + /// passing a lifetime representing this new lifetime variable in as an + /// argument. + pub fn push_bound_lifetime(&mut self, op: impl FnOnce(&mut Self, Lifetime)) { + let interner = self.interner(); + let binders = Binders::new( + VariableKinds::from1(interner, VariableKind::Lifetime), + PhantomData::, + ); + self.push_binders(&binders, |this, PhantomData| { + let lifetime = this + .placeholders_in_scope() + .last() + .unwrap() + .assert_lifetime_ref(interner) + .clone(); + op(this, lifetime) + }); + } + pub fn interner(&self) -> &'me I { self.db.interner() } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits.rs similarity index 72% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits.rs index d88cd6591b..d21a4b602b 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits.rs @@ -1,5 +1,5 @@ use super::{builder::ClauseBuilder, generalize}; -use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait}; +use crate::{CanonicalVarKinds, Interner, RustIrDatabase, TraitRef, WellKnownTrait}; use chalk_ir::{Floundered, Substitution, Ty}; mod clone; @@ -15,6 +15,7 @@ pub fn add_builtin_program_clauses( builder: &mut ClauseBuilder<'_, I>, well_known: WellKnownTrait, trait_ref: &TraitRef, + binders: &CanonicalVarKinds, ) -> Result<(), Floundered> { // If `trait_ref` contains bound vars, we want to universally quantify them. // `Generalize` collects them for us. @@ -23,17 +24,17 @@ pub fn add_builtin_program_clauses( builder.push_binders(&generalized, |builder, trait_ref| { let self_ty = trait_ref.self_type_parameter(db.interner()); let ty = self_ty.data(db.interner()); - if let Some(force_impl) = db.force_impl_for(well_known, ty) { - if force_impl { - builder.push_fact(trait_ref.clone()); - } - return Ok(()); - } match well_known { - WellKnownTrait::Sized => sized::add_sized_program_clauses(db, builder, &trait_ref, ty), - WellKnownTrait::Copy => copy::add_copy_program_clauses(db, builder, &trait_ref, ty), - WellKnownTrait::Clone => clone::add_clone_program_clauses(db, builder, &trait_ref, ty), + WellKnownTrait::Sized => { + sized::add_sized_program_clauses(db, builder, &trait_ref, ty, binders) + } + WellKnownTrait::Copy => { + copy::add_copy_program_clauses(db, builder, &trait_ref, ty, binders) + } + WellKnownTrait::Clone => { + clone::add_clone_program_clauses(db, builder, &trait_ref, ty, binders) + } WellKnownTrait::FnOnce | WellKnownTrait::FnMut | WellKnownTrait::Fn => { fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)? } @@ -57,11 +58,17 @@ pub fn add_builtin_assoc_program_clauses( ) -> Result<(), Floundered> { match well_known { WellKnownTrait::FnOnce => { - fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)?; + // If `self_ty` contains bound vars, we want to universally quantify them. + // `Generalize` collects them for us. + let generalized = generalize::Generalize::apply(db.interner(), &self_ty); + + builder.push_binders(&generalized, |builder, self_ty| { + fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)?; + Ok(()) + }) } - _ => {} + _ => Ok(()), } - Ok(()) } /// Given a trait ref `T0: Trait` and a list of types `U0..Un`, pushes a clause of the form diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/clone.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/clone.rs similarity index 71% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/clone.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/clone.rs index 7fb62fbd0a..69943be85d 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/clone.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/clone.rs @@ -1,6 +1,6 @@ use crate::clauses::ClauseBuilder; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::TyData; +use chalk_ir::{CanonicalVarKinds, TyData}; use super::copy::add_copy_program_clauses; @@ -9,9 +9,8 @@ pub fn add_clone_program_clauses( builder: &mut ClauseBuilder<'_, I>, trait_ref: &TraitRef, ty: &TyData, + binders: &CanonicalVarKinds, ) { - let _interner = db.interner(); - // Implement Clone for types that automaticly implement Copy - add_copy_program_clauses(db, builder, trait_ref, ty); + add_copy_program_clauses(db, builder, trait_ref, ty, binders); } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/copy.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/copy.rs similarity index 61% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/copy.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/copy.rs index 7642ef1578..5fd9c1a17a 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/copy.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/copy.rs @@ -1,8 +1,11 @@ use crate::clauses::builtin_traits::needs_impl_for_tys; use crate::clauses::ClauseBuilder; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::{ApplicationTy, Substitution, TyData, TypeName}; +use chalk_ir::{ + ApplicationTy, CanonicalVarKinds, Substitution, TyData, TyKind, TypeName, VariableKind, +}; use std::iter; +use tracing::instrument; fn push_tuple_copy_conditions( db: &dyn RustIrDatabase, @@ -29,11 +32,13 @@ fn push_tuple_copy_conditions( ); } +#[instrument(skip(db, builder))] pub fn add_copy_program_clauses( db: &dyn RustIrDatabase, builder: &mut ClauseBuilder<'_, I>, trait_ref: &TraitRef, ty: &TyData, + binders: &CanonicalVarKinds, ) { match ty { TyData::Apply(ApplicationTy { name, substitution }) => match name { @@ -58,11 +63,38 @@ pub fn add_copy_program_clauses( let upvars = upvars.substitute(db.interner(), &closure_fn_substitution); needs_impl_for_tys(db, builder, trait_ref, Some(upvars).into_iter()); } - _ => return, + + // these impls are in libcore + TypeName::Ref(_) + | TypeName::Raw(_) + | TypeName::Scalar(_) + | TypeName::Never + | TypeName::Str => {} + + TypeName::Adt(_) + | TypeName::AssociatedType(_) + | TypeName::Slice + | TypeName::OpaqueType(_) + | TypeName::Error => {} }, + TyData::Function(_) => builder.push_fact(trait_ref.clone()), - // TODO(areredify) - // when #368 lands, extend this to handle everything accordingly - _ => return, + + TyData::InferenceVar(_, kind) => match kind { + TyKind::Integer | TyKind::Float => builder.push_fact(trait_ref.clone()), + TyKind::General => {} + }, + + TyData::BoundVar(bound_var) => { + let var_kind = &binders.at(db.interner(), bound_var.index).kind; + match var_kind { + VariableKind::Ty(TyKind::Integer) | VariableKind::Ty(TyKind::Float) => { + builder.push_fact(trait_ref.clone()) + } + VariableKind::Ty(_) | VariableKind::Const(_) | VariableKind::Lifetime => {} + } + } + + TyData::Alias(_) | TyData::Dyn(_) | TyData::Placeholder(_) => {} }; } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/fn_family.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/fn_family.rs similarity index 83% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/fn_family.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/fn_family.rs index ca878026b9..2012367b68 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/fn_family.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/fn_family.rs @@ -4,8 +4,8 @@ use crate::rust_ir::{ClosureKind, FnDefInputsAndOutputDatum, WellKnownTrait}; use crate::{Interner, RustIrDatabase, TraitRef}; use chalk_ir::cast::Cast; use chalk_ir::{ - AliasTy, ApplicationTy, Binders, Floundered, Normalize, ProjectionTy, Substitution, TraitId, - Ty, TyData, TypeName, VariableKinds, + AliasTy, ApplicationTy, Binders, Floundered, Normalize, ProjectionTy, Safety, Substitution, + TraitId, Ty, TyData, TypeName, VariableKinds, }; fn push_clauses( @@ -24,7 +24,7 @@ fn push_clauses( }) .intern(interner); let substitution = - Substitution::from(interner, &[self_ty.cast(interner), tupled.cast(interner)]); + Substitution::from_iter(interner, &[self_ty.cast(interner), tupled.cast(interner)]); builder.push_fact(TraitRef { trait_id, substitution: substitution.clone(), @@ -68,7 +68,7 @@ fn push_clauses_for_apply( .iter() .cloned() .map(|ty| ty.cast(interner)); - let arg_sub = Substitution::from(interner, arg_sub); + let arg_sub = Substitution::from_iter(interner, arg_sub); let output_ty = inputs_and_output.return_type; push_clauses( @@ -99,22 +99,19 @@ pub fn add_fn_trait_program_clauses( TyData::Apply(apply) => match apply.name { TypeName::FnDef(fn_def_id) => { let fn_def_datum = builder.db.fn_def_datum(fn_def_id); - let bound = fn_def_datum - .binders - .substitute(builder.interner(), &apply.substitution); - let self_ty = ApplicationTy { - name: apply.name, - substitution: builder.substitution_in_scope(), + if fn_def_datum.safety == Safety::Safe && !fn_def_datum.variadic { + let bound = fn_def_datum + .binders + .substitute(builder.interner(), &apply.substitution); + push_clauses_for_apply( + db, + builder, + well_known, + trait_id, + self_ty, + &bound.inputs_and_output, + ); } - .intern(interner); - push_clauses_for_apply( - db, - builder, - well_known, - trait_id, - self_ty, - &bound.inputs_and_output, - ); Ok(()) } TypeName::Closure(closure_id) => { @@ -143,15 +140,15 @@ pub fn add_fn_trait_program_clauses( } _ => Ok(()), }, - TyData::Function(fn_val) => { + TyData::Function(fn_val) if fn_val.safety == Safety::Safe && !fn_val.variadic => { let (binders, orig_sub) = fn_val.into_binders_and_value(interner); - let bound_ref = Binders::new(VariableKinds::from(interner, binders), orig_sub); + let bound_ref = Binders::new(VariableKinds::from_iter(interner, binders), orig_sub); builder.push_binders(&bound_ref, |builder, orig_sub| { // The last parameter represents the function return type let (arg_sub, fn_output_ty) = orig_sub - .parameters(interner) + .as_slice(interner) .split_at(orig_sub.len(interner) - 1); - let arg_sub = Substitution::from(interner, arg_sub); + let arg_sub = Substitution::from_iter(interner, arg_sub); let output_ty = fn_output_ty[0].assert_ty_ref(interner).clone(); push_clauses( diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/sized.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/sized.rs similarity index 58% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/sized.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/sized.rs index fc5a525bc7..786c705a29 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/sized.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/sized.rs @@ -2,8 +2,11 @@ use std::iter; use crate::clauses::builtin_traits::needs_impl_for_tys; use crate::clauses::ClauseBuilder; +use crate::rust_ir::AdtKind; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::{AdtId, ApplicationTy, Substitution, TyData, TypeName}; +use chalk_ir::{ + AdtId, ApplicationTy, CanonicalVarKinds, Substitution, TyData, TyKind, TypeName, VariableKind, +}; fn push_adt_sized_conditions( db: &dyn RustIrDatabase, @@ -14,22 +17,25 @@ fn push_adt_sized_conditions( ) { let adt_datum = db.adt_datum(adt_id); - // ADTs with no fields are always Sized - if adt_datum.binders.skip_binders().fields.is_empty() { + // WF ensures that all enums are Sized, so we only have to consider structs. + if adt_datum.kind != AdtKind::Struct { builder.push_fact(trait_ref.clone()); return; } let interner = db.interner(); - // To check if an ADT type S<..> is Sized, we only have to look at its last field. + // To check if a struct S<..> is Sized, we only have to look at its last field. // This is because the WF checks for ADTs require that all the other fields must be Sized. let last_field_ty = adt_datum .binders - .map_ref(|b| b.fields.last().unwrap()) - .substitute(interner, substitution); + .map_ref(|b| &b.variants) + .substitute(interner, substitution) + .into_iter() + .take(1) // We have a struct so we're guaranteed one variant + .flat_map(|mut v| v.fields.pop()); - needs_impl_for_tys(db, builder, trait_ref, iter::once(last_field_ty)); + needs_impl_for_tys(db, builder, trait_ref, last_field_ty); } fn push_tuple_sized_conditions( @@ -65,6 +71,7 @@ pub fn add_sized_program_clauses( builder: &mut ClauseBuilder<'_, I>, trait_ref: &TraitRef, ty: &TyData, + binders: &CanonicalVarKinds, ) { match ty { TyData::Apply(ApplicationTy { name, substitution }) => match name { @@ -81,11 +88,31 @@ pub fn add_sized_program_clauses( | TypeName::Scalar(_) | TypeName::Raw(_) | TypeName::Ref(_) => builder.push_fact(trait_ref.clone()), - _ => return, + + TypeName::AssociatedType(_) + | TypeName::Slice + | TypeName::OpaqueType(_) + | TypeName::Str + | TypeName::Error => {} }, - TyData::Function(_) => builder.push_fact(trait_ref.clone()), - // TODO(areredify) - // when #368 lands, extend this to handle everything accordingly - _ => return, + + TyData::Function(_) + | TyData::InferenceVar(_, TyKind::Float) + | TyData::InferenceVar(_, TyKind::Integer) => builder.push_fact(trait_ref.clone()), + + TyData::BoundVar(bound_var) => { + let var_kind = &binders.at(db.interner(), bound_var.index).kind; + match var_kind { + VariableKind::Ty(TyKind::Integer) | VariableKind::Ty(TyKind::Float) => { + builder.push_fact(trait_ref.clone()) + } + VariableKind::Ty(_) | VariableKind::Const(_) | VariableKind::Lifetime => {} + } + } + + TyData::InferenceVar(_, TyKind::General) + | TyData::Placeholder(_) + | TyData::Dyn(_) + | TyData::Alias(_) => {} } } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/unsize.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/unsize.rs similarity index 87% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/unsize.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/unsize.rs index df1fd09941..e2bd3f7f1e 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/unsize.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/unsize.rs @@ -2,6 +2,7 @@ use std::collections::HashSet; use std::iter; use crate::clauses::ClauseBuilder; +use crate::rust_ir::AdtKind; use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait}; use chalk_ir::{ cast::Cast, @@ -9,7 +10,7 @@ use chalk_ir::{ visit::{visitors::FindAny, SuperVisit, Visit, VisitResult, Visitor}, ApplicationTy, Binders, Const, ConstValue, DebruijnIndex, DomainGoal, DynTy, EqGoal, Goal, LifetimeOutlives, QuantifiedWhereClauses, Substitution, TraitId, Ty, TyData, TypeName, - WhereClause, + TypeOutlives, WhereClause, }; struct UnsizeParameterCollector<'a, I: Interner> { @@ -42,14 +43,11 @@ impl<'a, I: Interner> Visitor<'a, I> for UnsizeParameterCollector<'a, I> { fn visit_const(&mut self, constant: &Const, outer_binder: DebruijnIndex) -> Self::Result { let interner = self.interner; - match constant.data(interner).value { - ConstValue::BoundVar(bound_var) => { - // check if bound var refers to the outermost binder - if bound_var.debruijn.shifted_in() == outer_binder { - self.parameters.insert(bound_var.index); - } + if let ConstValue::BoundVar(bound_var) = constant.data(interner).value { + // check if bound var refers to the outermost binder + if bound_var.debruijn.shifted_in() == outer_binder { + self.parameters.insert(bound_var.index); } - _ => (), } } @@ -140,12 +138,11 @@ fn principal_id<'a, I: Interner>( ) -> Option> { let interner = db.interner(); - return bounds + bounds .skip_binders() .iter(interner) .filter_map(|b| b.trait_id()) - .filter(|&id| !db.trait_datum(id).is_auto_trait()) - .next(); + .find(|&id| !db.trait_datum(id).is_auto_trait()) } fn auto_trait_ids<'a, I: Interner>( @@ -239,7 +236,7 @@ pub fn add_unsize_program_clauses( // should be equal to target type. let new_source_ty = TyData::Dyn(DynTy { bounds: bounds_a.map_ref(|bounds| { - QuantifiedWhereClauses::from( + QuantifiedWhereClauses::from_iter( interner, bounds.iter(interner).filter(|bound| { let trait_id = match bound.trait_id() { @@ -276,13 +273,7 @@ pub fn add_unsize_program_clauses( } // T -> dyn Trait + 'a - ( - _, - TyData::Dyn(DynTy { - bounds, - lifetime: _, - }), - ) => { + (_, TyData::Dyn(DynTy { bounds, lifetime })) => { // Check if all traits in trait object are object safe let object_safe_goals = bounds .skip_binders() @@ -304,7 +295,12 @@ pub fn add_unsize_program_clauses( } .cast(interner); - // FIXME(areredify) we need a `source_ty: 'lifetime` goal here + // Check that `source_ty` outlives `'a` + let source_ty_outlives: Goal<_> = WhereClause::TypeOutlives(TypeOutlives { + ty: source_ty, + lifetime: lifetime.clone(), + }) + .cast(interner); builder.push_clause( trait_ref.clone(), @@ -312,7 +308,8 @@ pub fn add_unsize_program_clauses( .iter(interner) .map(|bound| bound.clone().cast::>(interner)) .chain(object_safe_goals) - .chain(iter::once(self_sized_goal.cast(interner))), + .chain(iter::once(self_sized_goal.cast(interner))) + .chain(iter::once(source_ty_outlives)), ); } @@ -337,40 +334,53 @@ pub fn add_unsize_program_clauses( builder.push_clause(trait_ref.clone(), iter::once(eq_goal)); } - // Struct -> Struct - // Unsizing of enums is not allowed + // Adt -> Adt ( TyData::Apply(ApplicationTy { - name: TypeName::Adt(struct_id_a), + name: TypeName::Adt(adt_id_a), substitution: substitution_a, }), TyData::Apply(ApplicationTy { - name: TypeName::Adt(struct_id_b), + name: TypeName::Adt(adt_id_b), substitution: substitution_b, }), ) => { - if struct_id_a != struct_id_b { + if adt_id_a != adt_id_b { + return; + } + + let adt_id = *adt_id_a; + let adt_datum = db.adt_datum(adt_id); + + // Unsizing of enums is not allowed + if adt_datum.kind == AdtKind::Enum { return; } - let struct_id = *struct_id_a; - let struct_datum = db.adt_datum(struct_id); - let fields_len = struct_datum.binders.skip_binders().fields.len(); + // We have a `struct` so we're guaranteed a single variant + let fields_len = adt_datum + .binders + .skip_binders() + .variants + .last() + .unwrap() + .fields + .len(); if fields_len == 0 { return; } - let adt_tail_field = struct_datum + let adt_tail_field = adt_datum .binders - .map_ref(|bound| bound.fields.last().unwrap()); + .map_ref(|bound| bound.variants.last().unwrap().fields.last().unwrap()); // Collect unsize parameters that last field contains and // ensure there at least one of them. let unsize_parameter_candidates = outer_binder_parameters_used(interner, &adt_tail_field); - if unsize_parameter_candidates.len() == 0 { + if unsize_parameter_candidates.is_empty() { return; } // Ensure none of the other fields mention the parameters used @@ -379,16 +389,16 @@ pub fn add_unsize_program_clauses( // i.e. the struct generic arguments binder. if uses_outer_binder_params( interner, - &struct_datum + &adt_datum .binders - .map_ref(|bound| &bound.fields[..fields_len - 1]), + .map_ref(|bound| &bound.variants.last().unwrap().fields[..fields_len - 1]), &unsize_parameter_candidates, ) { return; } - let parameters_a = substitution_a.parameters(interner); - let parameters_b = substitution_b.parameters(interner); + let parameters_a = substitution_a.as_slice(interner); + let parameters_b = substitution_b.as_slice(interner); // Check that the source adt with the target's // unsizing parameters is equal to the target. // We construct a new substitution where if a parameter is used in the @@ -398,7 +408,7 @@ pub fn add_unsize_program_clauses( // // In order for the coercion to be valid, target struct and // struct with this newly constructed substitution applied to it should be equal. - let substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, parameters_a.iter().enumerate().map(|(i, p)| { if unsize_parameter_candidates.contains(&i) { @@ -411,7 +421,7 @@ pub fn add_unsize_program_clauses( let eq_goal = EqGoal { a: TyData::Apply(ApplicationTy { - name: TypeName::Adt(struct_id), + name: TypeName::Adt(adt_id), substitution, }) .intern(interner) @@ -427,7 +437,7 @@ pub fn add_unsize_program_clauses( // Check that `TailField: Unsize>` let last_field_unsizing_goal: Goal = TraitRef { trait_id: unsize_trait_id, - substitution: Substitution::from( + substitution: Substitution::from_iter( interner, [source_tail_field, target_tail_field].iter().cloned(), ), @@ -463,7 +473,7 @@ pub fn add_unsize_program_clauses( // last element is equal to the target. let new_tuple = ApplicationTy { name: TypeName::Tuple(*arity), - substitution: Substitution::from( + substitution: Substitution::from_iter( interner, substitution_a .iter(interner) @@ -483,7 +493,10 @@ pub fn add_unsize_program_clauses( // Check that `T: Unsize` let last_field_unsizing_goal: Goal = TraitRef { trait_id: unsize_trait_id, - substitution: Substitution::from(interner, [tail_ty_a, tail_ty_b].iter().cloned()), + substitution: Substitution::from_iter( + interner, + [tail_ty_a, tail_ty_b].iter().cloned(), + ), } .cast(interner); diff --git a/vendor/chalk-solve-0.14.0/src/clauses/dyn_ty.rs b/vendor/chalk-solve-0.25.0/src/clauses/dyn_ty.rs similarity index 98% rename from vendor/chalk-solve-0.14.0/src/clauses/dyn_ty.rs rename to vendor/chalk-solve-0.25.0/src/clauses/dyn_ty.rs index ad54a39719..6859437e1d 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/dyn_ty.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/dyn_ty.rs @@ -73,6 +73,7 @@ pub(super) fn build_dyn_self_ty_clauses( // Associated item bindings are just taken as facts (?) WhereClause::AliasEq(_) => builder.push_fact(wc), WhereClause::LifetimeOutlives(..) => {} + WhereClause::TypeOutlives(..) => {} }); } }); @@ -162,6 +163,7 @@ pub fn super_traits( } WhereClause::AliasEq(_) => None, WhereClause::LifetimeOutlives(..) => None, + WhereClause::TypeOutlives(..) => None, }) }) .collect::>() diff --git a/vendor/chalk-solve-0.14.0/src/clauses/env_elaborator.rs b/vendor/chalk-solve-0.25.0/src/clauses/env_elaborator.rs similarity index 77% rename from vendor/chalk-solve-0.14.0/src/clauses/env_elaborator.rs rename to vendor/chalk-solve-0.25.0/src/clauses/env_elaborator.rs index 5b239a129c..ddce951277 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/env_elaborator.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/env_elaborator.rs @@ -6,12 +6,12 @@ use crate::FromEnv; use crate::ProgramClause; use crate::RustIrDatabase; use crate::Ty; -use crate::TyData; +use crate::{debug_span, TyData}; use chalk_ir::interner::Interner; use chalk_ir::visit::{Visit, Visitor}; -use chalk_ir::DebruijnIndex; +use chalk_ir::{DebruijnIndex, Environment}; use rustc_hash::FxHashSet; -use tracing::debug; +use tracing::instrument; /// When proving a `FromEnv` goal, we elaborate all `FromEnv` goals /// found in the environment. @@ -23,10 +23,11 @@ pub(super) fn elaborate_env_clauses( db: &dyn RustIrDatabase, in_clauses: &[ProgramClause], out: &mut FxHashSet>, + environment: &Environment, ) { let mut this_round = vec![]; in_clauses.visit_with( - &mut EnvElaborator::new(db, &mut this_round), + &mut EnvElaborator::new(db, &mut this_round, environment), DebruijnIndex::INNERMOST, ); out.extend(this_round); @@ -35,13 +36,19 @@ pub(super) fn elaborate_env_clauses( struct EnvElaborator<'me, I: Interner> { db: &'me dyn RustIrDatabase, builder: ClauseBuilder<'me, I>, + environment: &'me Environment, } impl<'me, I: Interner> EnvElaborator<'me, I> { - fn new(db: &'me dyn RustIrDatabase, out: &'me mut Vec>) -> Self { + fn new( + db: &'me dyn RustIrDatabase, + out: &'me mut Vec>, + environment: &'me Environment, + ) -> Self { EnvElaborator { db, builder: ClauseBuilder::new(db, out), + environment, } } } @@ -56,15 +63,15 @@ impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { fn interner(&self) -> &'me I { self.db.interner() } - + #[instrument(level = "debug", skip(self, _outer_binder))] fn visit_ty(&mut self, ty: &Ty, _outer_binder: DebruijnIndex) { - debug!("EnvElaborator::visit_ty(ty={:?})", ty); - let interner = self.db.interner(); - match ty.data(interner) { + match ty.data(self.interner()) { TyData::Apply(application_ty) => { - match_type_name(&mut self.builder, interner, application_ty) + match_type_name(&mut self.builder, self.environment, application_ty) + } + TyData::Alias(alias_ty) => { + match_alias_ty(&mut self.builder, self.environment, alias_ty) } - TyData::Alias(alias_ty) => match_alias_ty(&mut self.builder, alias_ty), TyData::Placeholder(_) => {} // FIXME(#203) -- We haven't fully figured out the implied @@ -77,12 +84,12 @@ impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { fn visit_domain_goal(&mut self, domain_goal: &DomainGoal, outer_binder: DebruijnIndex) { if let DomainGoal::FromEnv(from_env) = domain_goal { - debug!("EnvElaborator::visit_domain_goal(from_env={:?})", from_env); + debug_span!("visit_domain_goal", ?from_env); match from_env { FromEnv::Trait(trait_ref) => { let trait_datum = self.db.trait_datum(trait_ref.trait_id); - trait_datum.to_program_clauses(&mut self.builder); + trait_datum.to_program_clauses(&mut self.builder, self.environment); // If we know that `T: Iterator`, then we also know // things about `::Item`, so push those @@ -90,7 +97,7 @@ impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { for &associated_ty_id in &trait_datum.associated_ty_ids { self.db .associated_ty_data(associated_ty_id) - .to_program_clauses(&mut self.builder); + .to_program_clauses(&mut self.builder, self.environment); } } FromEnv::Ty(ty) => ty.visit_with(self, outer_binder), diff --git a/vendor/chalk-solve-0.14.0/src/clauses/generalize.rs b/vendor/chalk-solve-0.25.0/src/clauses/generalize.rs similarity index 95% rename from vendor/chalk-solve-0.14.0/src/clauses/generalize.rs rename to vendor/chalk-solve-0.25.0/src/clauses/generalize.rs index fc5e5a7c3a..42f80ac9ec 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/generalize.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/generalize.rs @@ -34,7 +34,10 @@ impl Generalize<'_, I> { let value = value .fold_with(&mut generalize, DebruijnIndex::INNERMOST) .unwrap(); - Binders::new(VariableKinds::from(interner, generalize.binders), value) + Binders::new( + VariableKinds::from_iter(interner, generalize.binders), + value, + ) } } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/program_clauses.rs b/vendor/chalk-solve-0.25.0/src/clauses/program_clauses.rs similarity index 87% rename from vendor/chalk-solve-0.14.0/src/clauses/program_clauses.rs rename to vendor/chalk-solve-0.25.0/src/clauses/program_clauses.rs index 81610cba97..2f9ed502c4 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/program_clauses.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/program_clauses.rs @@ -11,7 +11,7 @@ use tracing::instrument; /// or struct definition) into its associated "program clauses" -- /// that is, into the lowered, logical rules that it defines. pub trait ToProgramClauses { - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>); + fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>, environment: &Environment); } impl ToProgramClauses for ImplDatum { @@ -28,7 +28,11 @@ impl ToProgramClauses for ImplDatum { /// generate nothing -- this is just a way to *opt out* from the /// default auto trait impls, it doesn't have any positive effect /// on its own. - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { if self.is_positive() { let binders = self.binders.map_ref(|b| (&b.trait_ref, &b.where_clauses)); builder.push_binders(&binders, |builder, (trait_ref, where_clauses)| { @@ -64,7 +68,11 @@ impl ToProgramClauses for AssociatedTyValue { /// Implemented(Iter<'a, T>: 'a). // (2) /// } /// ``` - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { let impl_datum = builder.db.impl_datum(self.impl_id); let associated_ty = builder.db.associated_ty_data(self.associated_ty_id); @@ -120,17 +128,22 @@ impl ToProgramClauses for AssociatedTyValue { } impl ToProgramClauses for OpaqueTyDatum { - /// Given `opaque type T<..>: A + B = HiddenTy;`, we generate: + /// Given `opaque type T: A + B = HiddenTy where U: C;`, we generate: /// /// ```notrust - /// AliasEq(T<..> = HiddenTy) :- Reveal. - /// AliasEq(T<..> = !T<..>). - /// Implemented(!T<..>: A). - /// Implemented(!T<..>: B). + /// AliasEq(T = HiddenTy) :- Reveal. + /// AliasEq(T = !T). + /// WF(T) :- WF(U: C). + /// Implemented(!T: A). + /// Implemented(!T: B). /// ``` /// where `!T<..>` is the placeholder for the unnormalized type `T<..>`. #[instrument(level = "debug", skip(builder))] - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { builder.push_binders(&self.bound, |builder, opaque_ty_bound| { let interner = builder.interner(); let substitution = builder.substitution_in_scope(); @@ -156,19 +169,29 @@ impl ToProgramClauses for OpaqueTyDatum { } .cast(interner), ), - iter::once(DomainGoal::Reveal(())), + iter::once(DomainGoal::Reveal), ); // AliasEq(T<..> = !T<..>). builder.push_fact(DomainGoal::Holds( AliasEq { - alias: alias.clone(), + alias, ty: alias_placeholder_ty.clone(), } .cast(interner), )); - let substitution = Substitution::from1(interner, alias_placeholder_ty.clone()); + // WF(!T<..>) :- WF(WC). + builder.push_binders(&opaque_ty_bound.where_clauses, |builder, where_clauses| { + builder.push_clause( + WellFormed::Ty(alias_placeholder_ty.clone()), + where_clauses + .into_iter() + .map(|wc| wc.into_well_formed_goal(interner)), + ); + }); + + let substitution = Substitution::from1(interner, alias_placeholder_ty); for bound in opaque_ty_bound.bounds { // Implemented(!T<..>: Bound). let bound_with_placeholder_ty = bound.substitute(interner, &substitution); @@ -220,9 +243,9 @@ fn well_formed_program_clauses<'a, I, Wc>( { let interner = builder.interner(); let appl_ty = application_ty(builder, type_name); - let ty = appl_ty.clone().intern(interner); + let ty = appl_ty.intern(interner); builder.push_clause( - WellFormed::Ty(ty.clone()), + WellFormed::Ty(ty), where_clauses .cloned() .map(|qwc| qwc.into_well_formed_goal(interner)), @@ -248,8 +271,8 @@ fn well_formed_program_clauses<'a, I, Wc>( /// /// - builder -- the clause builder. We assume all the generic types from `Foo` are in scope /// - type_name -- in our example above, the name `Foo` -fn fully_visible_program_clauses<'a, I>( - builder: &'a mut ClauseBuilder<'_, I>, +fn fully_visible_program_clauses( + builder: &mut ClauseBuilder<'_, I>, type_name: impl CastTo>, ) where I: Interner, @@ -258,7 +281,7 @@ fn fully_visible_program_clauses<'a, I>( let appl_ty = application_ty(builder, type_name); let ty = appl_ty.clone().intern(interner); builder.push_clause( - DomainGoal::IsFullyVisible(ty.clone()), + DomainGoal::IsFullyVisible(ty), appl_ty .type_parameters(interner) .map(|typ| DomainGoal::IsFullyVisible(typ).cast::>(interner)), @@ -294,7 +317,7 @@ fn implied_bounds_program_clauses<'a, I, Wc>( { let interner = builder.interner(); let appl_ty = application_ty(builder, type_name); - let ty = appl_ty.clone().intern(interner); + let ty = appl_ty.intern(interner); for qwc in where_clauses { builder.push_binders(&qwc, |builder, wc| { @@ -353,7 +376,11 @@ impl ToProgramClauses for AdtDatum { /// ``` /// #[instrument(level = "debug", skip(builder))] - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { let interner = builder.interner(); let binders = self.binders.map_ref(|b| &b.where_clauses); let id = self.id; @@ -442,7 +469,11 @@ impl ToProgramClauses for FnDefDatum { /// } /// ``` #[instrument(level = "debug", skip(builder))] - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { let binders = self.binders.map_ref(|b| &b.where_clauses); let id = self.id; @@ -570,7 +601,7 @@ impl ToProgramClauses for TraitDatum { /// To implement fundamental traits, we simply just do not add the rule above that allows /// upstream types to implement upstream traits. Fundamental traits are not allowed to /// compatibly do that. - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>, environment: &Environment) { let interner = builder.interner(); let binders = self.binders.map_ref(|b| &b.where_clauses); builder.push_binders(&binders, |builder, where_clauses| { @@ -596,30 +627,56 @@ impl ToProgramClauses for TraitDatum { // conditions. let type_parameters: Vec<_> = trait_ref.type_parameters(interner).collect(); - // Drop trait can't have downstream implementation because it can only - // be implemented with the same genericity as the struct definition, - // i.e. Drop implementation for `struct S {}` is forced to be - // `impl Drop for S { ... }`. That means that orphan rules - // prevent Drop from being implemented in downstream crates. - if self.well_known != Some(WellKnownTrait::Drop) { - // Add all cases for potential downstream impls that could exist - for i in 0..type_parameters.len() { + if environment.has_compatible_clause(interner) { + // Note: even though we do check for a `Compatible` clause here, + // we also keep it as a condition for the clauses below, purely + // for logical consistency. But really, it's not needed and could be + // removed. + + // Drop trait can't have downstream implementation because it can only + // be implemented with the same genericity as the struct definition, + // i.e. Drop implementation for `struct S {}` is forced to be + // `impl Drop for S { ... }`. That means that orphan rules + // prevent Drop from being implemented in downstream crates. + if self.well_known != Some(WellKnownTrait::Drop) { + // Add all cases for potential downstream impls that could exist + for i in 0..type_parameters.len() { + builder.push_clause( + trait_ref.clone(), + where_clauses + .iter() + .cloned() + .casted(interner) + .chain(iter::once(DomainGoal::Compatible.cast(interner))) + .chain((0..i).map(|j| { + DomainGoal::IsFullyVisible(type_parameters[j].clone()) + .cast(interner) + })) + .chain(iter::once( + DomainGoal::DownstreamType(type_parameters[i].clone()) + .cast(interner), + )) + .chain(iter::once(GoalData::CannotProve.intern(interner))), + ); + } + } + + // Fundamental traits can be reasoned about negatively without any ambiguity, so no + // need for this rule if the trait is fundamental. + if !self.flags.fundamental { builder.push_clause( trait_ref.clone(), where_clauses .iter() .cloned() .casted(interner) - .chain(iter::once(DomainGoal::Compatible(()).cast(interner))) - .chain((0..i).map(|j| { - DomainGoal::IsFullyVisible(type_parameters[j].clone()) - .cast(interner) - })) - .chain(iter::once( - DomainGoal::DownstreamType(type_parameters[i].clone()) - .cast(interner), - )) - .chain(iter::once(GoalData::CannotProve(()).intern(interner))), + .chain(iter::once(DomainGoal::Compatible.cast(interner))) + .chain( + trait_ref + .type_parameters(interner) + .map(|ty| DomainGoal::IsUpstream(ty).cast(interner)), + ) + .chain(iter::once(GoalData::CannotProve.intern(interner))), ); } } @@ -640,25 +697,6 @@ impl ToProgramClauses for TraitDatum { } } - // Fundamental traits can be reasoned about negatively without any ambiguity, so no - // need for this rule if the trait is fundamental. - if !self.flags.fundamental { - builder.push_clause( - trait_ref.clone(), - where_clauses - .iter() - .cloned() - .casted(interner) - .chain(iter::once(DomainGoal::Compatible(()).cast(interner))) - .chain( - trait_ref - .type_parameters(interner) - .map(|ty| DomainGoal::IsUpstream(ty).cast(interner)), - ) - .chain(iter::once(GoalData::CannotProve(()).intern(interner))), - ); - } - // Reverse implied bound rules: given (e.g.) `trait Foo: Bar + Baz`, // we create rules like: // @@ -685,7 +723,7 @@ impl ToProgramClauses for TraitDatum { // ``` // Implemented(T: Foo) :- FromEnv(T: Foo) // ``` - builder.push_clause(trait_ref.clone(), Some(trait_ref.clone().from_env())); + builder.push_clause(trait_ref.clone(), Some(trait_ref.from_env())); }); } } @@ -759,7 +797,11 @@ impl ToProgramClauses for AssociatedTyDatum { /// FromEnv(Self: Foo) :- FromEnv((Foo::Assoc)). /// } /// ``` - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { let interner = builder.interner(); let binders = self.binders.map_ref(|b| (&b.where_clauses, &b.bounds)); builder.push_binders(&binders, |builder, (where_clauses, bounds)| { @@ -793,7 +835,7 @@ impl ToProgramClauses for AssociatedTyDatum { // forall { // AliasEq(::Assoc = (Foo::Assoc)). // } - builder.push_fact_with_priority(projection_eq, ClausePriority::Low); + builder.push_fact_with_priority(projection_eq, None, ClausePriority::Low); // Well-formedness of projection type. // diff --git a/vendor/chalk-solve-0.14.0/src/coherence.rs b/vendor/chalk-solve-0.25.0/src/coherence.rs similarity index 93% rename from vendor/chalk-solve-0.14.0/src/coherence.rs rename to vendor/chalk-solve-0.25.0/src/coherence.rs index 060ab6d223..31384c0d82 100644 --- a/vendor/chalk-solve-0.14.0/src/coherence.rs +++ b/vendor/chalk-solve-0.25.0/src/coherence.rs @@ -1,6 +1,6 @@ use petgraph::prelude::*; -use crate::solve::SolverChoice; +use crate::solve::Solver; use crate::RustIrDatabase; use chalk_ir::interner::Interner; use chalk_ir::{self, ImplId, TraitId}; @@ -11,9 +11,9 @@ use std::sync::Arc; pub mod orphan; mod solve; -pub struct CoherenceSolver<'db, I: Interner> { - db: &'db dyn RustIrDatabase, - solver_choice: SolverChoice, +pub struct CoherenceSolver<'a, I: Interner> { + db: &'a dyn RustIrDatabase, + solver_builder: &'a dyn Fn() -> Box>, trait_id: TraitId, } @@ -71,19 +71,19 @@ impl SpecializationPriorities { #[derive(Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug)] pub struct SpecializationPriority(usize); -impl<'db, I> CoherenceSolver<'db, I> +impl<'a, I> CoherenceSolver<'a, I> where I: Interner, { /// Constructs a new `CoherenceSolver`. pub fn new( - db: &'db dyn RustIrDatabase, - solver_choice: SolverChoice, + db: &'a dyn RustIrDatabase, + solver_builder: &'a dyn Fn() -> Box>, trait_id: TraitId, ) -> Self { Self { db, - solver_choice, + solver_builder, trait_id, } } diff --git a/vendor/chalk-solve-0.14.0/src/coherence/orphan.rs b/vendor/chalk-solve-0.25.0/src/coherence/orphan.rs similarity index 76% rename from vendor/chalk-solve-0.14.0/src/coherence/orphan.rs rename to vendor/chalk-solve-0.25.0/src/coherence/orphan.rs index b339def322..f8e06b901e 100644 --- a/vendor/chalk-solve-0.14.0/src/coherence/orphan.rs +++ b/vendor/chalk-solve-0.25.0/src/coherence/orphan.rs @@ -1,6 +1,6 @@ use crate::coherence::CoherenceError; use crate::ext::GoalExt; -use crate::solve::SolverChoice; +use crate::solve::Solver; use crate::RustIrDatabase; use chalk_ir::cast::*; use chalk_ir::interner::Interner; @@ -14,14 +14,14 @@ use tracing::{debug, instrument}; // forall { LocalImplAllowed(MyType: Trait) } // // This must be provable in order to pass the orphan check. -#[instrument(level = "debug", skip(db, solver_choice))] +#[instrument(level = "debug", skip(db, solver))] pub fn perform_orphan_check( db: &dyn RustIrDatabase, - solver_choice: SolverChoice, + solver: &mut dyn Solver, impl_id: ImplId, ) -> Result<(), CoherenceError> { let impl_datum = db.impl_datum(impl_id); - debug!("impl_datum={:#?}", impl_datum); + debug!(?impl_datum); let impl_allowed: Goal = impl_datum .binders @@ -32,15 +32,12 @@ pub fn perform_orphan_check( .cast(db.interner()); let canonical_goal = &impl_allowed.into_closed_goal(db.interner()); - let is_allowed = solver_choice - .into_solver() - .solve(db, canonical_goal) - .is_some(); + let is_allowed = solver.solve(db, canonical_goal).is_some(); debug!("overlaps = {:?}", is_allowed); if !is_allowed { let trait_id = impl_datum.trait_id(); - Err(CoherenceError::FailedOrphanCheck(trait_id))?; + return Err(CoherenceError::FailedOrphanCheck(trait_id)); } Ok(()) diff --git a/vendor/chalk-solve-0.14.0/src/coherence/solve.rs b/vendor/chalk-solve-0.25.0/src/coherence/solve.rs similarity index 94% rename from vendor/chalk-solve-0.14.0/src/coherence/solve.rs rename to vendor/chalk-solve-0.25.0/src/coherence/solve.rs index 35cd035201..98081ce9b8 100644 --- a/vendor/chalk-solve-0.14.0/src/coherence/solve.rs +++ b/vendor/chalk-solve-0.25.0/src/coherence/solve.rs @@ -40,7 +40,7 @@ impl CoherenceSolver<'_, I> { (true, false) => record_specialization(l_id, r_id), (false, true) => record_specialization(r_id, l_id), (_, _) => { - Err(CoherenceError::OverlappingImpls(self.trait_id))?; + return Err(CoherenceError::OverlappingImpls(self.trait_id)); } } } @@ -93,13 +93,13 @@ impl CoherenceSolver<'_, I> { let lhs_params = lhs_bound .trait_ref .substitution - .parameters(interner) + .as_slice(interner) .iter() .cloned(); let rhs_params = rhs_bound .trait_ref .substitution - .parameters(interner) + .as_slice(interner) .iter() .map(|param| param.shifted_in(interner)); @@ -130,10 +130,8 @@ impl CoherenceSolver<'_, I> { .negate(interner); let canonical_goal = &goal.into_closed_goal(interner); - let solution = self - .solver_choice - .into_solver() - .solve(self.db, canonical_goal); + let mut fresh_solver = (self.solver_builder)(); + let solution = fresh_solver.solve(self.db, canonical_goal); let result = match solution { // Goal was proven with a unique solution, so no impl was found that causes these two // to overlap @@ -223,14 +221,14 @@ impl CoherenceSolver<'_, I> { // T0 = U0, ..., Tm = Um let params_goals = more_special_trait_ref .substitution - .parameters(interner) + .as_slice(interner) .iter() .cloned() .zip( less_special_impl .trait_ref .substitution - .parameters(interner) + .as_slice(interner) .iter() .cloned(), ) @@ -252,11 +250,8 @@ impl CoherenceSolver<'_, I> { ); let canonical_goal = &goal.into_closed_goal(interner); - let result = match self - .solver_choice - .into_solver() - .solve(self.db, canonical_goal) - { + let mut fresh_solver = (self.solver_builder)(); + let result = match fresh_solver.solve(self.db, canonical_goal) { Some(sol) => sol.is_unique(), None => false, }; diff --git a/vendor/chalk-solve-0.14.0/src/coinductive_goal.rs b/vendor/chalk-solve-0.25.0/src/coinductive_goal.rs similarity index 96% rename from vendor/chalk-solve-0.14.0/src/coinductive_goal.rs rename to vendor/chalk-solve-0.25.0/src/coinductive_goal.rs index 3c06933bce..cdb5cca108 100644 --- a/vendor/chalk-solve-0.14.0/src/coinductive_goal.rs +++ b/vendor/chalk-solve-0.25.0/src/coinductive_goal.rs @@ -25,6 +25,7 @@ impl IsCoinductive for Goal { } WhereClause::AliasEq(..) => false, WhereClause::LifetimeOutlives(..) => false, + WhereClause::TypeOutlives(..) => false, }, GoalData::DomainGoal(DomainGoal::WellFormed(WellFormed::Trait(..))) => true, GoalData::Quantified(QuantifierKind::ForAll, goal) => { diff --git a/vendor/chalk-solve-0.25.0/src/display.rs b/vendor/chalk-solve-0.25.0/src/display.rs new file mode 100644 index 0000000000..677332ace3 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display.rs @@ -0,0 +1,219 @@ +use std::{ + borrow::Borrow, + fmt::{Display, Result}, + sync::Arc, +}; + +use crate::rust_ir::*; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +use crate::{logging_db::RecordedItemId, split::Split, RustIrDatabase}; + +#[macro_use] +mod utils; + +mod bounds; +mod identifiers; +mod items; +mod render_trait; +mod state; +mod stub; +mod ty; + +use self::render_trait::*; +pub use self::state::*; +pub use self::utils::sanitize_debug_name; + +use self::utils::as_display; + +fn write_item(f: &mut F, ws: &InternalWriterState<'_, I>, v: &T) -> Result +where + F: std::fmt::Write + ?Sized, + I: Interner, + T: RenderAsRust, +{ + writeln!(f, "{}", v.display(ws)) +} + +/// Writes stubs for items which were referenced by name, but for which we +/// didn't directly access. For instance, traits mentioned in where bounds which +/// are only usually checked during well-formedness, when we weren't recording +/// well-formedness. +/// +/// The "stub" nature of this means it writes output with the right names and +/// the right number of generics, but nothing else. Where clauses, bounds, and +/// fields are skipped. Associated types are ???? skipped. +/// +/// `RecordedItemId::Impl` is not supported. +pub fn write_stub_items(f: &mut F, ws: &WriterState, ids: T) -> Result +where + F: std::fmt::Write + ?Sized, + I: Interner, + DB: RustIrDatabase, + P: Borrow, + T: IntoIterator>, +{ + let wrapped_db = &ws.wrap_db_ref(|db| stub::StubWrapper::new(db.borrow())); + + write_items(f, wrapped_db, ids) +} + +/// Writes out each item recorded by a [`LoggingRustIrDatabase`]. +/// +/// [`LoggingRustIrDatabase`]: crate::logging_db::LoggingRustIrDatabase +pub fn write_items(f: &mut F, ws: &WriterState, ids: T) -> Result +where + F: std::fmt::Write + ?Sized, + I: Interner, + DB: RustIrDatabase, + P: Borrow, + T: IntoIterator>, +{ + for id in ids { + match id { + RecordedItemId::Impl(id) => { + let v = ws.db().impl_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::Adt(id) => { + let v = ws.db().adt_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::Trait(id) => { + let v = ws.db().trait_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::OpaqueTy(id) => { + let v = ws.db().opaque_ty_data(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::FnDef(id) => { + let v = ws.db().fn_def_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + } + } + Ok(()) +} + +/// Displays a set of bounds, all targeting `Self`, as just the trait names, +/// separated by `+`. +/// +/// For example, a list of quantified where clauses which would normally be +/// displayed as: +/// +/// ```notrust +/// Self: A, Self: B, Self: C +/// ``` +/// +/// Is instead displayed by this function as: +/// +/// ```notrust +/// A + B + C +/// ``` +/// +/// Shared between the `Trait` in `dyn Trait` and [`OpaqueTyDatum`] bounds. +fn display_self_where_clauses_as_bounds<'a, I: Interner>( + s: &'a InternalWriterState<'a, I>, + bounds: &'a [QuantifiedWhereClause], +) -> impl Display + 'a { + as_display(move |f| { + let interner = s.db().interner(); + write!( + f, + "{}", + bounds + .iter() + .map(|bound| { + as_display(|f| { + // each individual trait can have a forall + let s = &s.add_debrujin_index(None); + if !bound.binders.is_empty(interner) { + write!( + f, + "forall<{}> ", + s.binder_var_display(&bound.binders) + .collect::>() + .join(", ") + )?; + } + match &bound.skip_binders() { + WhereClause::Implemented(trait_ref) => display_type_with_generics( + s, + trait_ref.trait_id, + &trait_ref.substitution.as_slice(interner)[1..], + ) + .fmt(f), + WhereClause::AliasEq(alias_eq) => match &alias_eq.alias { + AliasTy::Projection(projection_ty) => { + let (assoc_ty_datum, trait_params, assoc_type_params) = + s.db().split_projection(&projection_ty); + display_trait_with_assoc_ty_value( + s, + assoc_ty_datum, + &trait_params[1..], + assoc_type_params, + &alias_eq.ty, + ) + .fmt(f) + } + AliasTy::Opaque(_opaque) => todo!("opaque type AliasTy"), + }, + WhereClause::LifetimeOutlives(lifetime) => lifetime.display(s).fmt(f), + WhereClause::TypeOutlives(ty) => ty.display(s).fmt(f), + } + }) + .to_string() + }) + .format(" + ") + ) + }) +} + +/// Displays a type with its parameters - something like `AsRef`, +/// OpaqueTyName, or `AdtName`. +/// +/// This is shared between where bounds, OpaqueTy, & dyn Trait. +fn display_type_with_generics<'a, I: Interner>( + s: &'a InternalWriterState<'a, I>, + trait_name: impl RenderAsRust + 'a, + trait_params: impl IntoIterator> + 'a, +) -> impl Display + 'a { + use std::fmt::Write; + let trait_params = trait_params.into_iter().map(|param| param.display(s)); + let mut trait_params_str = String::new(); + write_joined_non_empty_list!(trait_params_str, "<{}>", trait_params, ", ").unwrap(); + as_display(move |f| write!(f, "{}{}", trait_name.display(s), trait_params_str)) +} + +/// Displays a trait with its parameters and a single associated type - +/// something like `IntoIterator`. +/// +/// This is shared between where bounds & dyn Trait. +fn display_trait_with_assoc_ty_value<'a, I: Interner>( + s: &'a InternalWriterState<'a, I>, + assoc_ty_datum: Arc>, + trait_params: &'a [GenericArg], + assoc_ty_params: &'a [GenericArg], + assoc_ty_value: &'a Ty, +) -> impl Display + 'a { + as_display(move |f| { + write!(f, "{}<", assoc_ty_datum.trait_id.display(s))?; + write_joined_non_empty_list!( + f, + "{}, ", + trait_params.iter().map(|param| param.display(s)), + ", " + )?; + write!(f, "{}", assoc_ty_datum.id.display(s))?; + write_joined_non_empty_list!( + f, + "<{}>", + assoc_ty_params.iter().map(|param| param.display(s)), + ", " + )?; + write!(f, "={}>", assoc_ty_value.display(s))?; + Ok(()) + }) +} diff --git a/vendor/chalk-solve-0.25.0/src/display/bounds.rs b/vendor/chalk-solve-0.25.0/src/display/bounds.rs new file mode 100644 index 0000000000..627b0bb8d2 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/bounds.rs @@ -0,0 +1,168 @@ +//! Writer logic for `where` clauses and other bounds. +//! +//! Contains logic for writing the various forms of `Foo: Bar`. +use std::fmt::{Display, Formatter, Result}; + +use crate::rust_ir::*; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +use super::{ + display_trait_with_assoc_ty_value, display_type_with_generics, render_trait::RenderAsRust, + state::InternalWriterState, +}; +use crate::split::Split; + +impl RenderAsRust for InlineBound { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + // Foo: Vec + InlineBound::TraitBound(trait_bound) => trait_bound.fmt(s, f), + // Foo: Iterator + InlineBound::AliasEqBound(eq_bound) => eq_bound.fmt(s, f), + } + } +} + +impl RenderAsRust for TraitBound { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + display_type_with_generics(s, self.trait_id, &self.args_no_self).fmt(f) + } +} + +impl RenderAsRust for AliasEqBound { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + display_trait_with_assoc_ty_value( + s, + s.db().associated_ty_data(self.associated_ty_id), + &self.trait_bound.args_no_self, + &self.parameters, + &self.value, + ) + .fmt(f) + } +} + +impl RenderAsRust for QuantifiedWhereClause { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + let s = &s.add_debrujin_index(None); + if !self.binders.is_empty(interner) { + write!( + f, + "forall<{}> ", + s.binder_var_display(&self.binders).format(", ") + )?; + } + self.skip_binders().fmt(s, f) + } +} + +impl RenderAsRust for QuantifiedInlineBound { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + let s = &s.add_debrujin_index(None); + if !self.binders.is_empty(&interner) { + write!( + f, + "forall<{}> ", + s.binder_var_display(&self.binders).format(", ") + )?; + } + self.skip_binders().fmt(s, f) + } +} + +impl RenderAsRust for Vec> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + write!( + f, + "{}", + self.iter() + .map(|where_clause| { format!("{}{}", s.indent(), where_clause.display(s)) }) + .format(",\n") + )?; + Ok(()) + } +} + +impl RenderAsRust for WhereClause { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + WhereClause::Implemented(trait_ref) => trait_ref.fmt(s, f), + WhereClause::AliasEq(alias_eq) => alias_eq.fmt(s, f), + WhereClause::LifetimeOutlives(lifetime) => lifetime.display(s).fmt(f), + WhereClause::TypeOutlives(ty) => ty.display(s).fmt(f), + } + } +} + +/// This renders `TraitRef` as a clause in a where clause, as opposed to its +/// usage in other places. +impl RenderAsRust for TraitRef { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + write!( + f, + "{}: {}", + self.self_type_parameter(interner).display(s), + display_type_with_generics( + s, + self.trait_id, + &self.substitution.as_slice(interner)[1..] + ) + ) + } +} + +/// This renders `AliasEq` as a clause in a where clause, as opposed to its +/// usage in other places. +impl RenderAsRust for AliasEq { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // we have: X: Y=D> + // B1, B2, B3, X, A1, A2, A3 are put into alias_eq.alias.substitution + // D is alias_eq.ty + // Z is alias_eq.alias.associated_ty_id + // Y is also packed into alias_eq.alias.associated_ty_id + // Now, we split out A*, Y/Z and B*: + // trait_params is X, A1, A2, A3, + // assoc_type_params is B1, B2, B3, + // assoc_ty_datum stores info about Y and Z. + match &self.alias { + AliasTy::Projection(projection_ty) => { + let (assoc_ty_datum, trait_params, assoc_type_params) = + s.db().split_projection(&projection_ty); + // An alternate form might be `<{} as {}<{}>>::{}<{}> = {}` (with same + // parameter ordering). This alternate form would require type equality + // constraints (https://github.com/rust-lang/rust/issues/20041). + write!( + f, + "{}: {}", + trait_params[0].display(s), + display_trait_with_assoc_ty_value( + s, + assoc_ty_datum, + &trait_params[1..], + assoc_type_params, + &self.ty + ), + ) + } + AliasTy::Opaque(_) => todo!("opaque types"), + } + } +} + +impl RenderAsRust for LifetimeOutlives { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + // a': 'b + write!(f, "{}: {}", self.a.display(s), self.b.display(s)) + } +} + +impl RenderAsRust for TypeOutlives { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + // T: 'a + write!(f, "{}: {}", self.ty.display(s), self.lifetime.display(s)) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/identifiers.rs b/vendor/chalk-solve-0.25.0/src/display/identifiers.rs new file mode 100644 index 0000000000..81a08d71b3 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/identifiers.rs @@ -0,0 +1,54 @@ +//! Writer logic for simple IDs +//! +//! `RenderAsRust` impls for identifiers which are either too small or too +//! shared to belong anywhere else belong here. +use std::fmt::{Formatter, Result}; + +use chalk_ir::interner::Interner; +use chalk_ir::*; + +use super::{render_trait::RenderAsRust, state::InternalWriterState}; + +impl RenderAsRust for AdtId { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_adt_id_name(self.0, s.db().adt_name(*self)) + ) + } +} + +impl RenderAsRust for TraitId { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_id_name(self.0, s.db().trait_name(*self)) + ) + } +} + +impl RenderAsRust for AssocTypeId { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_id_name(self.0, s.db().assoc_type_name(*self)) + ) + } +} + +impl RenderAsRust for OpaqueTyId { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_id_name(self.0, s.db().opaque_type_name(*self)) + ) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/items.rs b/vendor/chalk-solve-0.25.0/src/display/items.rs new file mode 100644 index 0000000000..13da1a01b2 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/items.rs @@ -0,0 +1,490 @@ +//! Writer logic for top level items. +//! +//! Contains code specific to top-level items and other structures specific to a +//! single top-level item. + +use std::fmt::{Formatter, Result}; + +use crate::rust_ir::*; +use crate::split::Split; +use chalk_ir::interner::Interner; +use itertools::Itertools; + +use super::{ + display_self_where_clauses_as_bounds, display_type_with_generics, render_trait::RenderAsRust, + state::InternalWriterState, +}; + +/// Used in `AdtDatum` and `TraitDatum` to write n flags from a flags struct +/// to a writer. Each flag field turns into an if expression + write!, so we can +/// just list the names and not repeat this pattern over and over. +/// +/// This macro will error if unknown flags are specified. This will also error +/// if any flags are missing. +/// +/// # Usage +/// +/// ```rust,ignore +/// write_flags!(f, self.flags, XFlags { red, green }) +/// ``` +/// +/// Turns into +/// +/// ```rust,ignore +/// match self.flags { +/// XFlags { red, green } => { +/// if red { +/// write!(f, "#[red]")?; +/// } +/// if green { +/// write!(f, "#[green]")?; +/// } +/// } +/// } +/// ``` +macro_rules! write_flags { + ($writer:ident, $val:expr, $struct_name:ident { $($n:ident $(: $extra_arg:tt)?),* }) => { + match $val { + // if any fields are missing, the destructuring will error + $struct_name { + $($n,)* + } => { + $(if $n { + write!($writer, "#[{}]\n", write_flags!(@default $n $(: $extra_arg)*))?; + })* + } + } + }; + (@default $n:ident : $name:literal) => { + $name + }; + (@default $n:ident ) => { + stringify!($n) + }; +} + +impl RenderAsRust for AdtDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // When support for Self in structs is added, self_binding should be + // changed to Some(0) + let s = &s.add_debrujin_index(None); + let value = self.binders.skip_binders(); + + // flags + write_flags!( + f, + self.flags, + AdtFlags { + // Ordering matters + upstream, + fundamental, + phantom_data + } + ); + + // repr + let repr = s.db().adt_repr(self.id); + + write_flags!( + f, + repr, + AdtRepr { + repr_c: "repr(C)", + repr_packed: "repr(packed)" + } + ); + + // name + match self.kind { + AdtKind::Struct => write!(f, "struct {}", self.id.display(s),)?, + AdtKind::Enum => write!(f, "enum {}", self.id.display(s),)?, + AdtKind::Union => write!(f, "union {}", self.id.display(s),)?, + } + write_joined_non_empty_list!(f, "<{}>", s.binder_var_display(&self.binders.binders), ", ")?; + + // where clauses + if !value.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; + } else { + write!(f, " ")?; + } + + // body + write!(f, "{{")?; + let s = &s.add_indent(); + match self.kind { + AdtKind::Struct | AdtKind::Union => { + write_joined_non_empty_list!( + f, + "\n{}\n", + value.variants[0] + .fields + .iter() + .enumerate() + .map(|(idx, field)| { + format!("{}field_{}: {}", s.indent(), idx, field.display(s)) + }), + ",\n" + )?; + } + AdtKind::Enum => { + for (variant_idx, variant) in value.variants.iter().enumerate() { + write!(f, "\n{}variant_{} {{", s.indent(), variant_idx)?; + let s = &s.add_indent(); + write_joined_non_empty_list!( + f, + "\n{}\n", + variant.fields.iter().enumerate().map(|(idx, field)| { + format!("{}field_{}: {}", s.indent(), idx, field.display(s)) + }), + ",\n" + )?; + write!(f, "{}}},", s.indent())?; + } + } + } + write!(f, "}}")?; + Ok(()) + } +} + +impl RenderAsRust for Polarity { + fn fmt(&self, _s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + if !self.is_positive() { + write!(f, "!")?; + } + Ok(()) + } +} + +impl RenderAsRust for TraitDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let s = &s.add_debrujin_index(Some(0)); + let value = self.binders.skip_binders(); + + // flags + write_flags!( + f, + self.flags, + TraitFlags { + auto, + marker, + upstream, + fundamental, + non_enumerable, + coinductive + } + ); + + // object safe + if s.db().is_object_safe(self.id) { + writeln!(f, "#[object_safe]")?; + } + + // well-known + if let Some(well_known) = self.well_known { + let name = match well_known { + WellKnownTrait::Sized => "sized", + WellKnownTrait::Copy => "copy", + WellKnownTrait::Clone => "clone", + WellKnownTrait::Drop => "drop", + WellKnownTrait::FnOnce => "fn_once", + WellKnownTrait::FnMut => "fn_mut", + WellKnownTrait::Fn => "fn", + WellKnownTrait::Unsize => "unsize", + }; + writeln!(f, "#[lang({})]", name)?; + } + + // trait declaration + let binders = s.binder_var_display(&self.binders.binders).skip(1); + write!(f, "trait {}", self.id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; + + // where clauses + if !value.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; + } else { + write!(f, " ")?; + } + + // body + write!(f, "{{")?; + let s = &s.add_indent(); + write_joined_non_empty_list!( + f, + "\n{}\n", + self.associated_ty_ids.iter().map(|assoc_ty_id| { + let assoc_ty_data = s.db().associated_ty_data(*assoc_ty_id); + format!("{}{}", s.indent(), (*assoc_ty_data).display(s)) + }), + "\n" + )?; + write!(f, "}}")?; + Ok(()) + } +} + +impl RenderAsRust for ImplDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + + let s = &s.add_debrujin_index(None); + let binders = s.binder_var_display(&self.binders.binders); + let value = self.binders.skip_binders(); + + // annotations + // #[upstream] + // ^^^^^^^^^^^ + // impl Foo for Bar where T: Baz { } + if self.impl_type == ImplType::External { + writeln!(f, "#[upstream]")?; + } + + // impl keyword + // impl Foo for Bar where T: Baz { } + // ^^^^ + write!(f, "impl")?; + let trait_ref = &value.trait_ref; + + // generic binders + // impl Foo for Bar where T: Baz + // ^^^ + write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; + + // trait, type and parameters + // impl Foo for Bar where T: Baz { } + // ^^^^^^^^^^^^^^^^^ + let full_trait_name = display_type_with_generics( + s, + trait_ref.trait_id, + // Ignore automatically added Self parameter by skipping first parameter + &trait_ref.substitution.as_slice(interner)[1..], + ); + write!( + f, + " {}{} for {}", + self.polarity.display(s), + full_trait_name, + trait_ref.self_type_parameter(interner).display(s) + )?; + + // where clauses + // impl Foo for Bar where T: Baz { } + // ^^^^^^^^^^^^ + if !value.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; + } else { + write!(f, " ")?; + } + + // body + // impl Foo for Bar where T: Baz { } + // ^^^ + write!(f, "{{")?; + { + let s = &s.add_indent(); + let assoc_ty_values = self.associated_ty_value_ids.iter().map(|assoc_ty_value| { + s.db() + .associated_ty_value(*assoc_ty_value) + .display(s) + .to_string() + }); + write_joined_non_empty_list!(f, "\n{}\n", assoc_ty_values, "\n")?; + } + write!(f, "}}")?; + Ok(()) + } +} + +impl RenderAsRust for OpaqueTyDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + let s = &s.add_debrujin_index(None); + let bounds = self.bound.skip_binders(); + write!(f, "opaque type {}", self.opaque_ty_id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", s.binder_var_display(&self.bound.binders), ", ")?; + { + let s = &s.add_debrujin_index(Some(0)); + let clauses = bounds.bounds.skip_binders(); + write!( + f, + ": {} = ", + display_self_where_clauses_as_bounds(s, clauses) + )?; + } + write!( + f, + "{};", + s.db().hidden_opaque_type(self.opaque_ty_id).display(s) + )?; + Ok(()) + } +} + +impl RenderAsRust for AssociatedTyDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // In lowering, a completely new empty environment is created for each + // AssociatedTyDatum, and it's given generic parameters for each generic + // parameter that its trait had. We want to map the new binders for + // those generic parameters back into their original names. To do that, + // first find their original names (trait_binder_names), then the names + // they have inside the AssociatedTyDatum (assoc_ty_names_for_trait_params), + // and then add that mapping to the WriterState when writing bounds and + // where clauses. + let trait_datum = s.db().trait_datum(self.trait_id); + // inverted Debrujin indices for the trait's parameters in the trait + // environment + let trait_param_names_in_trait_env = s.binder_var_indices(&trait_datum.binders.binders); + let s = &s.add_debrujin_index(None); + // inverted Debrujin indices for the trait's parameters in the + // associated type environment + let param_names_in_assoc_ty_env = s + .binder_var_indices(&self.binders.binders) + .collect::>(); + // inverted Debrujin indices to render the trait's parameters in the + // associated type environment + let (trait_param_names_in_assoc_ty_env, _) = s + .db() + .split_associated_ty_parameters(¶m_names_in_assoc_ty_env, self); + + let s = &s.add_parameter_mapping( + trait_param_names_in_assoc_ty_env.iter().copied(), + trait_param_names_in_trait_env, + ); + + // rendered names for the associated type's generics in the associated + // type environment + let binder_display_in_assoc_ty = s + .binder_var_display(&self.binders.binders) + .collect::>(); + + let (_, assoc_ty_params) = s + .db() + .split_associated_ty_parameters(&binder_display_in_assoc_ty, self); + write!(f, "type {}", self.id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", assoc_ty_params, ", ")?; + + let datum_bounds = &self.binders.skip_binders(); + + if !datum_bounds.bounds.is_empty() { + write!(f, ": ")?; + } + + // bounds is `A: V, B: D, C = E`? + // type Foo: X + Y + Z; + let bounds = datum_bounds + .bounds + .iter() + .map(|bound| bound.display(s).to_string()) + .format(" + "); + write!(f, "{}", bounds)?; + + // where_clause is 'X: Y, Z: D' + // type Foo<...>: ... where X: Y, Z: D; + + // note: it's a quantified clause b/c we could have `for<'a> T: Foo<'a>` + // within 'where' + if !datum_bounds.where_clauses.is_empty() { + let where_s = &s.add_indent(); + let where_clauses = datum_bounds.where_clauses.display(where_s); + write!(f, "\n{}where\n{}", s.indent(), where_clauses)?; + } + write!(f, ";")?; + Ok(()) + } +} + +impl RenderAsRust for AssociatedTyValue { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // see comments for a similar empty env operation in AssociatedTyDatum's + // impl of RenderAsRust. + let assoc_ty_data = s.db().associated_ty_data(self.associated_ty_id); + let impl_datum = s.db().impl_datum(self.impl_id); + + let impl_param_names_in_impl_env = s.binder_var_indices(&impl_datum.binders.binders); + + let s = &s.add_debrujin_index(None); + let value = self.value.skip_binders(); + + let param_names_in_assoc_ty_value_env = s + .binder_var_indices(&self.value.binders) + .collect::>(); + + let (impl_params_in_assoc_ty_value_env, _assoc_ty_value_params) = s + .db() + .split_associated_ty_value_parameters(¶m_names_in_assoc_ty_value_env, self); + + let s = &s.add_parameter_mapping( + impl_params_in_assoc_ty_value_env.iter().cloned(), + impl_param_names_in_impl_env, + ); + + let display_params = s + .binder_var_display(&self.value.binders) + .collect::>(); + + let (_impl_display, assoc_ty_value_display) = s + .db() + .split_associated_ty_value_parameters(&display_params, self); + + write!(f, "{}type {}", s.indent(), assoc_ty_data.id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", &assoc_ty_value_display, ", ")?; + write!(f, " = {};", value.ty.display(s))?; + Ok(()) + } +} + +impl RenderAsRust for FnDefDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + let s = &s.add_debrujin_index(None); + let bound_datum = self.binders.skip_binders(); + + // declaration + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^^^^ + write!(f, "fn {}", s.db().fn_def_name(self.id))?; + + // binders + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^ + let binders = s.binder_var_display(&self.binders.binders); + write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; + + { + let s = &s.add_debrujin_index(None); + let inputs_and_output = bound_datum.inputs_and_output.skip_binders(); + + // arguments + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^^^^^^^^^^^^^^^^^ + let arguments = inputs_and_output + .argument_types + .iter() + .enumerate() + .map(|(idx, arg)| format!("arg_{}: {}", idx, arg.display(s))) + .format(", "); + + write!(f, "({})", arguments)?; + + // return Type + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^^^^^^^^^^^ + write!(f, " -> {}", inputs_and_output.return_type.display(s))?; + } + + // where clause + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^^^^^^^^^^ + if !bound_datum.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}", bound_datum.where_clauses.display(s))?; + } + + write!(f, ";")?; + + Ok(()) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/render_trait.rs b/vendor/chalk-solve-0.25.0/src/display/render_trait.rs new file mode 100644 index 0000000000..a565f076c7 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/render_trait.rs @@ -0,0 +1,30 @@ +//! `RenderAsRust` trait and related utils. +use std::fmt::{Display, Formatter, Result}; + +use chalk_ir::interner::Interner; + +use super::state::InternalWriterState; + +/// Displays `RenderAsRust` data. +/// +/// This is a utility struct for making `RenderAsRust` nice to use with rust format macros. +pub(in crate::display) struct DisplayRenderAsRust<'a, I: Interner, T> { + s: &'a InternalWriterState<'a, I>, + rar: &'a T, +} + +impl> Display for DisplayRenderAsRust<'_, I, T> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + self.rar.fmt(self.s, f) + } +} + +pub(in crate::display) trait RenderAsRust { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result; + fn display<'a>(&'a self, s: &'a InternalWriterState<'a, I>) -> DisplayRenderAsRust<'a, I, Self> + where + Self: Sized, + { + DisplayRenderAsRust { s, rar: self } + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/state.rs b/vendor/chalk-solve-0.25.0/src/display/state.rs new file mode 100644 index 0000000000..3501d5916d --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/state.rs @@ -0,0 +1,350 @@ +//! Persistent state passed down between writers. +//! +//! This is essentially `InternalWriterState` and other things supporting that. +use std::{ + borrow::Borrow, + collections::BTreeMap, + fmt::{Debug, Display, Formatter, Result}, + marker::PhantomData, + rc::Rc, + sync::{Arc, Mutex}, +}; + +use crate::RustIrDatabase; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +/// Like a BoundVar, but with the debrujin index inverted so as to create a +/// canonical name we can use anywhere for each bound variable. +/// +/// In BoundVar, the innermost bound variables have debrujin index `0`, and +/// each further out BoundVar has a debrujin index `1` higher. +/// +/// In InvertedBoundVar, the outermost variables have inverted_debrujin_idx `0`, +/// and the innermost have their depth, not the other way around. +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] +pub struct InvertedBoundVar { + /// The inverted debrujin index. Corresponds roughly to an inverted `DebrujinIndex::depth`. + inverted_debrujin_idx: i64, + /// The index within the debrujin index. Corresponds to `BoundVar::index`. + within_idx: IndexWithinBinding, +} + +impl Display for InvertedBoundVar { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "_{}_{}", self.inverted_debrujin_idx, self.within_idx) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +enum UnifiedId { + AdtId(I::InternedAdtId), + DefId(I::DefId), +} + +#[derive(Debug)] +pub struct IdAliasStore { + /// Map from the DefIds we've encountered to a u32 alias id unique to all ids + /// the same name. + aliases: BTreeMap, + /// Map from each name to the next unused u32 alias id. + next_unused_for_name: BTreeMap, +} + +impl Default for IdAliasStore { + fn default() -> Self { + IdAliasStore { + aliases: BTreeMap::default(), + next_unused_for_name: BTreeMap::default(), + } + } +} + +impl IdAliasStore { + fn alias_for_id_name(&mut self, id: T, name: String) -> String { + let next_unused_for_name = &mut self.next_unused_for_name; + let alias = *self.aliases.entry(id).or_insert_with(|| { + let next_unused: &mut u32 = next_unused_for_name.entry(name.clone()).or_default(); + let id = *next_unused; + *next_unused += 1; + id + }); + // If there are no conflicts, keep the name the same so that we don't + // need name-agnostic equality in display tests. + if alias == 0 { + name + } else { + format!("{}_{}", name, alias) + } + } +} + +#[derive(Debug)] +struct IdAliases { + id_aliases: IdAliasStore>, +} + +impl Default for IdAliases { + fn default() -> Self { + IdAliases { + id_aliases: IdAliasStore::default(), + } + } +} + +/// Writer state which persists across multiple writes. +/// +/// Currently, this means keeping track of what IDs have been given what names, +/// including deduplication information. +/// +/// This data is stored using interior mutability - clones will point to the same underlying +/// data. +/// +/// Uses a separate type, `P`, for the database stored inside to account for +/// `Arc` or wrapping other storage mediums. +#[derive(Debug)] +pub struct WriterState +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + pub(super) db: P, + id_aliases: Arc>>, + _phantom: PhantomData, +} + +impl Clone for WriterState +where + DB: RustIrDatabase, + P: Borrow + Clone, + I: Interner, +{ + fn clone(&self) -> Self { + WriterState { + db: self.db.clone(), + id_aliases: self.id_aliases.clone(), + _phantom: PhantomData, + } + } +} + +impl WriterState +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + pub fn new(db: P) -> Self { + WriterState { + db, + id_aliases: Arc::new(Mutex::new(IdAliases::default())), + _phantom: PhantomData, + } + } + + /// Returns a new version of self containing a wrapped database which + /// references the outer data. + /// + /// `f` will be run on the internal database, and the returned result will + /// wrap the result from `f`. For consistency, `f` should always contain the + /// given database, and must keep the same ID<->item relationships. + pub(super) fn wrap_db_ref<'a, DB2: ?Sized, P2, F>(&'a self, f: F) -> WriterState + where + DB2: RustIrDatabase, + P2: Borrow, + // We need to pass in `&'a P` specifically to guarantee that the `&P` + // can outlive the function body, and thus that it's safe to store `&P` + // in `P2`. + F: FnOnce(&'a P) -> P2, + { + WriterState { + db: f(&self.db), + id_aliases: self.id_aliases.clone(), + _phantom: PhantomData, + } + } + + pub(crate) fn db(&self) -> &DB { + self.db.borrow() + } +} + +/// Writer state for a single write call, persistent only as long as necessary +/// to write a single item. +/// +/// Stores things necessary for . +#[derive(Clone, Debug)] +pub(super) struct InternalWriterState<'a, I: Interner> { + persistent_state: WriterState + 'a, &'a dyn RustIrDatabase>, + indent_level: usize, + debrujin_indices_deep: u32, + // lowered_(inverted_debrujin_idx, index) -> src_correct_(inverted_debrujin_idx, index) + remapping: Rc>, + // the inverted_bound_var which maps to "Self" + self_mapping: Option, +} + +type IndexWithinBinding = usize; + +impl<'a, I: Interner> InternalWriterState<'a, I> { + pub fn new(persistent_state: &'a WriterState) -> Self + where + DB: RustIrDatabase, + P: Borrow, + { + InternalWriterState { + persistent_state: persistent_state + .wrap_db_ref(|db| db.borrow() as &dyn RustIrDatabase), + indent_level: 0, + debrujin_indices_deep: 0, + remapping: Rc::new(BTreeMap::new()), + self_mapping: None, + } + } + + pub(super) fn db(&self) -> &dyn RustIrDatabase { + self.persistent_state.db + } + + pub(super) fn add_indent(&self) -> Self { + InternalWriterState { + indent_level: self.indent_level + 1, + ..self.clone() + } + } + + pub(super) fn indent(&self) -> impl Display { + std::iter::repeat(" ").take(self.indent_level).format("") + } + + pub(super) fn alias_for_adt_id_name(&self, id: I::InternedAdtId, name: String) -> impl Display { + self.persistent_state + .id_aliases + .lock() + .unwrap() + .id_aliases + .alias_for_id_name(UnifiedId::AdtId(id), name) + } + + pub(super) fn alias_for_id_name(&self, id: I::DefId, name: String) -> impl Display { + self.persistent_state + .id_aliases + .lock() + .unwrap() + .id_aliases + .alias_for_id_name(UnifiedId::DefId(id), name) + } + + /// Adds a level of debrujin index, and possibly a "Self" parameter. + /// + /// This should be called whenever recursing into the value within a + /// [`Binders`]. + /// + /// If `self_binding` is `Some`, then it will introduce a new variable named + /// `Self` with the within-debrujin index given within and the innermost + /// debrujian index after increasing debrujin index. + #[must_use = "this returns a new `InternalWriterState`, and does not modify the existing one"] + pub(super) fn add_debrujin_index(&self, self_binding: Option) -> Self { + let mut new_state = self.clone(); + new_state.debrujin_indices_deep += 1; + new_state.self_mapping = self_binding + .map(|idx| new_state.indices_for_introduced_bound_var(idx)) + .or(self.self_mapping); + new_state + } + + /// Adds parameter remapping. + /// + /// Each of the parameters in `lowered_vars` will be mapped to its + /// corresponding variable in `original_vars` when printed through the + /// `InternalWriterState` returned from this method. + /// + /// `lowered_vars` and `original_vars` must have the same length. + pub(super) fn add_parameter_mapping( + &self, + lowered_vars: impl Iterator, + original_vars: impl Iterator, + ) -> Self { + let remapping = self + .remapping + .iter() + .map(|(a, b)| (*a, *b)) + .chain(lowered_vars.zip(original_vars)) + .collect::>(); + + InternalWriterState { + remapping: Rc::new(remapping), + ..self.clone() + } + } + + /// Inverts the debrujin index so as to create a canonical name we can + /// anywhere for each bound variable. + /// + /// See [`InvertedBoundVar`][InvertedBoundVar]. + pub(super) fn invert_debrujin_idx( + &self, + debrujin_idx: u32, + index: IndexWithinBinding, + ) -> InvertedBoundVar { + InvertedBoundVar { + inverted_debrujin_idx: (self.debrujin_indices_deep as i64) - (debrujin_idx as i64), + within_idx: index, + } + } + + pub(super) fn apply_mappings(&self, b: InvertedBoundVar) -> impl Display { + let remapped = self.remapping.get(&b).copied().unwrap_or(b); + if self.self_mapping == Some(remapped) { + "Self".to_owned() + } else { + remapped.to_string() + } + } + + pub(super) fn indices_for_bound_var(&self, b: &BoundVar) -> InvertedBoundVar { + self.invert_debrujin_idx(b.debruijn.depth(), b.index) + } + + pub(super) fn indices_for_introduced_bound_var( + &self, + idx: IndexWithinBinding, + ) -> InvertedBoundVar { + // freshly introduced bound vars will always have debrujin index of 0, + // they're always "innermost". + self.invert_debrujin_idx(0, idx) + } + + pub(super) fn display_bound_var(&self, b: &BoundVar) -> impl Display { + self.apply_mappings(self.indices_for_bound_var(b)) + } + + pub(super) fn name_for_introduced_bound_var(&self, idx: IndexWithinBinding) -> impl Display { + self.apply_mappings(self.indices_for_introduced_bound_var(idx)) + } + + pub(super) fn binder_var_indices<'b>( + &'b self, + binders: &'b VariableKinds, + ) -> impl Iterator + 'b { + binders + .iter(self.db().interner()) + .enumerate() + .map(move |(idx, _param)| self.indices_for_introduced_bound_var(idx)) + } + + pub(super) fn binder_var_display<'b>( + &'b self, + binders: &'b VariableKinds, + ) -> impl Iterator + 'b { + binders + .iter(self.db().interner()) + .zip(self.binder_var_indices(binders)) + .map(move |(parameter, var)| match parameter { + VariableKind::Ty(_) => format!("{}", self.apply_mappings(var)), + VariableKind::Lifetime => format!("'{}", self.apply_mappings(var)), + VariableKind::Const(_ty) => format!("const {}", self.apply_mappings(var)), + }) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/stub.rs b/vendor/chalk-solve-0.25.0/src/display/stub.rs new file mode 100644 index 0000000000..2c433578c2 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/stub.rs @@ -0,0 +1,239 @@ +//! Contains a `LoggingIrDatabase` which returns stub versions of everything +//! queried. +use std::sync::Arc; + +use crate::{ + rust_ir::{ + AdtDatumBound, AdtKind, AdtVariantDatum, AssociatedTyDatumBound, FnDefDatumBound, + OpaqueTyDatumBound, TraitDatumBound, + }, + RustIrDatabase, +}; +use chalk_ir::{ + interner::Interner, ApplicationTy, Binders, CanonicalVarKinds, TypeName, VariableKinds, +}; + +#[derive(Debug)] +pub struct StubWrapper<'a, DB> { + db: &'a DB, +} + +impl<'a, DB> StubWrapper<'a, DB> { + pub fn new(db: &'a DB) -> Self { + StubWrapper { db } + } +} + +impl> RustIrDatabase for StubWrapper<'_, DB> { + fn custom_clauses(&self) -> Vec> { + self.db.custom_clauses() + } + + fn associated_ty_data( + &self, + ty: chalk_ir::AssocTypeId, + ) -> std::sync::Arc> { + let mut v = (*self.db.associated_ty_data(ty)).clone(); + v.binders = Binders::new( + v.binders.binders.clone(), + AssociatedTyDatumBound { + where_clauses: Vec::new(), + bounds: Vec::new(), + }, + ); + Arc::new(v) + } + + fn trait_datum( + &self, + trait_id: chalk_ir::TraitId, + ) -> std::sync::Arc> { + let mut v = (*self.db.trait_datum(trait_id)).clone(); + v.binders = Binders::new( + v.binders.binders.clone(), + TraitDatumBound { + where_clauses: Vec::new(), + }, + ); + Arc::new(v) + } + + fn adt_datum(&self, adt_id: chalk_ir::AdtId) -> std::sync::Arc> { + let mut v = (*self.db.adt_datum(adt_id)).clone(); + let variants = match v.kind { + AdtKind::Struct | AdtKind::Union => vec![AdtVariantDatum { fields: vec![] }], + AdtKind::Enum => vec![], + }; + v.binders = Binders::new( + v.binders.binders.clone(), + AdtDatumBound { + variants, + where_clauses: Vec::new(), + }, + ); + Arc::new(v) + } + + fn adt_repr(&self, id: chalk_ir::AdtId) -> crate::rust_ir::AdtRepr { + self.db.adt_repr(id) + } + + fn fn_def_datum( + &self, + fn_def_id: chalk_ir::FnDefId, + ) -> std::sync::Arc> { + let mut v = (*self.db.fn_def_datum(fn_def_id)).clone(); + v.binders = Binders::new( + v.binders.binders.clone(), + FnDefDatumBound { + inputs_and_output: v.binders.skip_binders().inputs_and_output.clone(), + where_clauses: Vec::new(), + }, + ); + Arc::new(v) + } + + fn impl_datum( + &self, + _impl_id: chalk_ir::ImplId, + ) -> std::sync::Arc> { + unreachable!("impl items should never be stubbed") + } + + fn associated_ty_value( + &self, + _id: crate::rust_ir::AssociatedTyValueId, + ) -> std::sync::Arc> { + unreachable!("associated type values should never be stubbed") + } + + fn opaque_ty_data( + &self, + id: chalk_ir::OpaqueTyId, + ) -> std::sync::Arc> { + let mut v = (*self.db.opaque_ty_data(id)).clone(); + v.bound = Binders::new( + v.bound.binders, + OpaqueTyDatumBound { + bounds: Binders::new(VariableKinds::empty(self.db.interner()), Vec::new()), + where_clauses: Binders::new(VariableKinds::empty(self.db.interner()), Vec::new()), + }, + ); + Arc::new(v) + } + + fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId) -> chalk_ir::Ty { + // Return a unit since the particular hidden type doesn't matter (If it + // did matter, it would have been recorded) + chalk_ir::TyData::Apply(ApplicationTy { + name: TypeName::Tuple(0), + substitution: chalk_ir::Substitution::from_iter( + self.db.interner(), + Vec::>::new(), + ), + }) + .intern(self.db.interner()) + } + + fn impls_for_trait( + &self, + _trait_id: chalk_ir::TraitId, + _parameters: &[chalk_ir::GenericArg], + _binders: &CanonicalVarKinds, + ) -> Vec> { + // We panic here because the returned ids may not be collected, + // resulting in unresolvable names. + unimplemented!("stub display code should call this") + } + + fn local_impls_to_coherence_check( + &self, + trait_id: chalk_ir::TraitId, + ) -> Vec> { + self.db.local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for( + &self, + _auto_trait_id: chalk_ir::TraitId, + _adt_id: chalk_ir::AdtId, + ) -> bool { + // We panic here because the returned ids may not be collected, + // resulting in unresolvable names. + unimplemented!("stub display code should call this") + } + + fn well_known_trait_id( + &self, + well_known_trait: crate::rust_ir::WellKnownTrait, + ) -> Option> { + self.db.well_known_trait_id(well_known_trait) + } + + fn program_clauses_for_env( + &self, + environment: &chalk_ir::Environment, + ) -> chalk_ir::ProgramClauses { + self.db.program_clauses_for_env(environment) + } + + fn interner(&self) -> &I { + self.db.interner() + } + + fn is_object_safe(&self, trait_id: chalk_ir::TraitId) -> bool { + self.db.is_object_safe(trait_id) + } + + fn closure_kind( + &self, + _closure_id: chalk_ir::ClosureId, + _substs: &chalk_ir::Substitution, + ) -> crate::rust_ir::ClosureKind { + unimplemented!("cannot stub closures") + } + + fn closure_inputs_and_output( + &self, + _closure_id: chalk_ir::ClosureId, + _substs: &chalk_ir::Substitution, + ) -> chalk_ir::Binders> { + unimplemented!("cannot stub closures") + } + + fn closure_upvars( + &self, + _closure_id: chalk_ir::ClosureId, + _substs: &chalk_ir::Substitution, + ) -> chalk_ir::Binders> { + unimplemented!("cannot stub closures") + } + + fn closure_fn_substitution( + &self, + _closure_id: chalk_ir::ClosureId, + _substs: &chalk_ir::Substitution, + ) -> chalk_ir::Substitution { + unimplemented!("cannot stub closures") + } + + fn trait_name(&self, trait_id: chalk_ir::TraitId) -> String { + self.db.trait_name(trait_id) + } + + fn adt_name(&self, struct_id: chalk_ir::AdtId) -> String { + self.db.adt_name(struct_id) + } + + fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId) -> String { + self.db.assoc_type_name(assoc_ty_id) + } + + fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId) -> String { + self.db.opaque_type_name(opaque_ty_id) + } + + fn fn_def_name(&self, fn_def_id: chalk_ir::FnDefId) -> String { + self.db.fn_def_name(fn_def_id) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/ty.rs b/vendor/chalk-solve-0.25.0/src/display/ty.rs new file mode 100644 index 0000000000..6792703096 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/ty.rs @@ -0,0 +1,333 @@ +//! Writer logic for types. +//! +//! Contains the highly-recursive logic for writing `TyData` and its variants. +use std::fmt::{Formatter, Result}; + +use crate::split::Split; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +use super::{ + display_self_where_clauses_as_bounds, display_type_with_generics, render_trait::RenderAsRust, + state::InternalWriterState, +}; + +impl RenderAsRust for TyData { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + match self { + TyData::Dyn(dyn_ty) => { + // the lifetime needs to be outside of the bounds, so we + // introduce a new scope for the bounds + { + let s = &s.add_debrujin_index(None); + // dyn_ty.bounds.binders creates a Self binding for the trait + let bounds = dyn_ty.bounds.skip_binders(); + + write!( + f, + "dyn {}", + display_self_where_clauses_as_bounds(s, bounds.as_slice(interner)), + )?; + } + + write!(f, " + {}", dyn_ty.lifetime.display(s))?; + Ok(()) + } + TyData::BoundVar(bound_var) => write!(f, "{}", s.display_bound_var(bound_var)), + TyData::InferenceVar(_, _) => write!(f, "_"), + TyData::Alias(alias_ty) => alias_ty.fmt(s, f), + TyData::Apply(apply_ty) => apply_ty.fmt(s, f), + TyData::Function(func) => func.fmt(s, f), + TyData::Placeholder(_) => write!(f, ""), + } + } +} + +impl RenderAsRust for AliasTy { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + AliasTy::Projection(projection_ty) => projection_ty.fmt(s, f), + AliasTy::Opaque(opaque_ty) => opaque_ty.fmt(s, f), + } + } +} + +impl RenderAsRust for ProjectionTy { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // >::Z + + // Now, we split out A*, Y/Z and B*: + // trait_params is X, A1, A2, A3, + // assoc_type_params is B1, B2, B3, + // assoc_ty_datum stores info about Y and Z. + let (assoc_ty_datum, trait_params, assoc_type_params) = s.db().split_projection(&self); + write!( + f, + "<{} as {}>::{}", + trait_params[0].display(s), + display_type_with_generics(s, assoc_ty_datum.trait_id, &trait_params[1..]), + assoc_ty_datum.id.display(s), + )?; + write_joined_non_empty_list!( + f, + "<{}>", + assoc_type_params.iter().map(|param| param.display(s)), + ", " + )?; + Ok(()) + } +} + +impl RenderAsRust for OpaqueTy { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + write!( + f, + "{}", + display_type_with_generics(s, self.opaque_ty_id, self.substitution.as_slice(interner),) + ) + } +} + +impl RenderAsRust for FnPointer { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + let s = &s.add_debrujin_index(None); + if self.num_binders > 0 { + write!( + f, + "for<{}> ", + (0..self.num_binders) + .map(|n| format!("'{}", s.name_for_introduced_bound_var(n))) + .format(", ") + )?; + } + let parameters = self.substitution.as_slice(interner); + write!( + f, + "fn({}) -> {}", + parameters[..parameters.len() - 1] + .iter() + .map(|param| param.display(s)) + .format(", "), + parameters[parameters.len() - 1].display(s), + ) + } +} + +impl RenderAsRust for ApplicationTy { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + match self.name { + TypeName::Adt(sid) => { + write!(f, "{}", sid.display(s))?; + let parameters = self.substitution.as_slice(interner); + let parameters = parameters.iter().map(|param| param.display(s)); + write_joined_non_empty_list!(f, "<{}>", parameters, ", ")?; + } + TypeName::AssociatedType(assoc_type_id) => { + // (Iterator::Item)(x) + // should be written in Rust as ::Item + let datum = s.db().associated_ty_data(assoc_type_id); + assert!( + self.len_type_parameters(interner) >= 1, + "AssociatedType should have at least 1 parameter" + ); + write!( + f, + "<{} as {}>::{}", + self.first_type_parameter(interner).unwrap().display(s), + datum.trait_id.display(s), + datum.id.display(s), + )?; + let params = self.substitution.as_slice(interner); + write_joined_non_empty_list!( + f, + "<{}>", + params[1..].iter().map(|ty| ty.display(s)), + "," + )?; + } + TypeName::Scalar(scalar) => write!(f, "{}", scalar.display(s))?, + TypeName::Tuple(arity) => { + write!( + f, + "({}{})", + self.substitution + .as_slice(interner) + .iter() + .map(|p| p.display(s)) + .format(", "), + if arity == 1 { + // need trailing single comma + "," + } else { + "" + } + )? + } + TypeName::OpaqueType(opaque_ty_id) => { + write!( + f, + "{}", + display_type_with_generics( + s, + opaque_ty_id, + self.substitution.as_slice(interner) + ) + )?; + } + TypeName::Raw(raw) => { + let mutability = match raw { + Mutability::Mut => "*mut ", + Mutability::Not => "*const ", + }; + write!( + f, + "{}{}", + mutability, + self.first_type_parameter(interner).unwrap().display(s) + )? + } + TypeName::Ref(mutability) => { + let mutability = match mutability { + Mutability::Mut => "mut ", + Mutability::Not => "", + }; + write!( + f, + "&{} {}{}", + self.substitution.at(interner, 0).display(s), + mutability, + self.substitution.at(interner, 1).display(s) + )?; + } + TypeName::Str => write!(f, "str")?, + TypeName::Slice => { + write!( + f, + "[{}]", + self.first_type_parameter(interner).unwrap().display(s) + )?; + } + TypeName::Error => write!(f, "{{error}}")?, + TypeName::Never => write!(f, "!")?, + + // FIXME: write out valid types for these variants + TypeName::FnDef(_) => write!(f, "")?, + TypeName::Closure(..) => write!(f, "")?, + + TypeName::Array => write!( + f, + "[{}; {}]", + self.first_type_parameter(interner).unwrap().display(s), + self.substitution.at(interner, 1).display(s) + )?, + } + Ok(()) + } +} + +impl RenderAsRust for Scalar { + fn fmt(&self, _s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + use chalk_ir::{FloatTy::*, IntTy::*, UintTy::*}; + write!( + f, + "{}", + match self { + Scalar::Bool => "bool", + Scalar::Char => "char", + Scalar::Int(int) => match int { + Isize => "isize", + I8 => "i8", + I16 => "i16", + I32 => "i32", + I64 => "i64", + I128 => "i128", + }, + Scalar::Uint(uint) => match uint { + Usize => "usize", + U8 => "u8", + U16 => "u16", + U32 => "u32", + U64 => "u64", + U128 => "u128", + }, + Scalar::Float(float) => match float { + F32 => "f32", + F64 => "f64", + }, + } + ) + } +} + +impl RenderAsRust for LifetimeData { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + LifetimeData::BoundVar(v) => write!(f, "'{}", s.display_bound_var(v)), + LifetimeData::InferenceVar(_) => write!(f, "'_"), + LifetimeData::Placeholder(ix) => { + write!(f, "'_placeholder_{}_{}", ix.ui.counter, ix.idx) + } + // Matching the void ensures at compile time that this code is + // unreachable + LifetimeData::Phantom(void, _) => match *void {}, + } + } +} + +impl RenderAsRust for ConstData { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + write!(f, "{}", self.value.display(s)) + } +} + +impl RenderAsRust for ConstValue { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + match self { + ConstValue::BoundVar(v) => write!(f, "{}", s.display_bound_var(v)), + ConstValue::InferenceVar(_) => write!(f, "_"), + ConstValue::Placeholder(_) => write!(f, ""), + ConstValue::Concrete(_value) => unimplemented!("const values"), + } + } +} + +impl RenderAsRust for GenericArgData { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + GenericArgData::Ty(ty) => write!(f, "{}", ty.display(s)), + GenericArgData::Lifetime(lt) => write!(f, "{}", lt.display(s)), + GenericArgData::Const(const_ty) => write!(f, "{}", const_ty.display(s)), + } + } +} + +impl RenderAsRust for Ty { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // delegate to TyData + self.data(s.db().interner()).fmt(s, f) + } +} + +impl RenderAsRust for Lifetime { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // delegate to LifetimeData + self.data(s.db().interner()).fmt(s, f) + } +} + +impl RenderAsRust for Const { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + self.data(s.db().interner()).fmt(s, f) + } +} + +impl RenderAsRust for GenericArg { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // delegate to GenericArgData + self.data(s.db().interner()).fmt(s, f) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/utils.rs b/vendor/chalk-solve-0.25.0/src/display/utils.rs new file mode 100644 index 0000000000..31a8a9357d --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/utils.rs @@ -0,0 +1,51 @@ +//! Render utilities which don't belong anywhere else. +use std::fmt::{Display, Formatter, Result}; + +pub fn as_display) -> Result>(f: F) -> impl Display { + struct ClosureDisplay) -> Result>(F); + + impl) -> Result> Display for ClosureDisplay { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + self.0(f) + } + } + + ClosureDisplay(f) +} + +macro_rules! write_joined_non_empty_list { + ($f:expr,$template:tt,$list:expr,$sep:expr) => {{ + let mut x = $list.into_iter().peekable(); + if x.peek().is_some() { + write!($f, $template, x.format($sep)) + } else { + Ok(()) + } + }}; +} + +/// Processes a name given by an [`Interner`][chalk_ir::Interner] debug +/// method into something usable by the `display` module. +/// +/// This is specifically useful when implementing +/// [`RustIrDatabase`][crate::RustIrDatabase] `name_*` methods. +pub fn sanitize_debug_name(func: impl Fn(&mut Formatter<'_>) -> Option) -> String { + use std::fmt::Write; + + // First, write the debug method contents to a String. + let mut debug_out = String::new(); + // ignore if the result is `None`, as we can just as easily tell by looking + // to see if anything was written to `debug_out`. + write!( + debug_out, + "{}", + as_display(|fmt| { func(fmt).unwrap_or(Ok(())) }) + ) + .expect("expected writing to a String to succeed"); + if debug_out.is_empty() { + return "Unknown".to_owned(); + } + + // now the actual sanitization + debug_out.replace(|c: char| !c.is_ascii_alphanumeric(), "_") +} diff --git a/vendor/chalk-solve-0.14.0/src/ext.rs b/vendor/chalk-solve-0.25.0/src/ext.rs similarity index 100% rename from vendor/chalk-solve-0.14.0/src/ext.rs rename to vendor/chalk-solve-0.25.0/src/ext.rs diff --git a/vendor/chalk-solve-0.14.0/src/goal_builder.rs b/vendor/chalk-solve-0.25.0/src/goal_builder.rs similarity index 97% rename from vendor/chalk-solve-0.14.0/src/goal_builder.rs rename to vendor/chalk-solve-0.25.0/src/goal_builder.rs index a5bf84d163..e78b3c31dc 100644 --- a/vendor/chalk-solve-0.14.0/src/goal_builder.rs +++ b/vendor/chalk-solve-0.25.0/src/goal_builder.rs @@ -45,7 +45,7 @@ impl<'i, I: Interner> GoalBuilder<'i, I> { G: CastTo>, { GoalData::Implies( - ProgramClauses::from(self.interner(), clauses), + ProgramClauses::from_iter(self.interner(), clauses), goal(self).cast(self.interner()), ) .intern(self.interner()) @@ -132,12 +132,12 @@ impl<'i, I: Interner> GoalBuilder<'i, I> { // actually an identity mapping, since this `forall` will be the innermost // debruijn binder and so forth, so there's no actual reason to // *do* the substitution, since it would effectively just be a clone. - let substitution: Substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, binders .binders .iter(interner) - .zip(0..) + .enumerate() .map(|p| p.to_generic_arg(interner)), ); diff --git a/vendor/chalk-solve-0.14.0/src/infer.rs b/vendor/chalk-solve-0.25.0/src/infer.rs similarity index 87% rename from vendor/chalk-solve-0.14.0/src/infer.rs rename to vendor/chalk-solve-0.25.0/src/infer.rs index c9fcaa51ba..df7fec405a 100644 --- a/vendor/chalk-solve-0.14.0/src/infer.rs +++ b/vendor/chalk-solve-0.25.0/src/infer.rs @@ -3,19 +3,18 @@ use chalk_ir::*; use chalk_ir::{cast::Cast, fold::Fold}; use tracing::{debug, instrument}; -pub(crate) mod canonicalize; +mod canonicalize; pub(crate) mod instantiate; mod invert; -mod normalize_deep; mod test; -pub(crate) mod ucanonicalize; -pub(crate) mod unify; -pub(crate) mod var; +pub mod ucanonicalize; +pub mod unify; +mod var; use self::var::*; #[derive(Clone)] -pub(crate) struct InferenceTable { +pub struct InferenceTable { unify: ena::unify::InPlaceUnificationTable>, vars: Vec>, max_universe: UniverseIndex, @@ -32,7 +31,7 @@ pub(crate) type ParameterEnaVariable = WithKind>; impl InferenceTable { /// Create an empty inference table with no variables. - pub(crate) fn new() -> Self { + pub fn new() -> Self { InferenceTable { unify: ena::unify::UnificationTable::new(), vars: vec![], @@ -47,7 +46,7 @@ impl InferenceTable { /// the substitution mapping from each canonical binder to its /// corresponding existential variable, along with the /// instantiated result. - pub(crate) fn from_canonical( + pub fn from_canonical( interner: &I, num_universes: usize, canonical: &Canonical, @@ -76,17 +75,17 @@ impl InferenceTable { pub(crate) fn new_universe(&mut self) -> UniverseIndex { let u = self.max_universe.next(); self.max_universe = u; - debug!("new_universe: {:?}", u); + debug!("created new universe: {:?}", u); u } /// Creates a new inference variable and returns its index. The /// kind of the variable should be known by the caller, but is not /// tracked directly by the inference table. - pub(crate) fn new_variable(&mut self, ui: UniverseIndex) -> EnaVariable { + pub fn new_variable(&mut self, ui: UniverseIndex) -> EnaVariable { let var = self.unify.new_key(InferenceValue::Unbound(ui)); self.vars.push(var); - debug!("new_variable: var={:?} ui={:?}", var, ui); + debug!(?var, ?ui, "created new variable"); var } @@ -119,12 +118,12 @@ impl InferenceTable { self.unify.commit(snapshot.unify_snapshot); } - pub(crate) fn normalize_ty_shallow(&mut self, interner: &I, leaf: &Ty) -> Option> { + pub fn normalize_ty_shallow(&mut self, interner: &I, leaf: &Ty) -> Option> { self.probe_var(leaf.inference_var(interner)?) .map(|p| p.assert_ty_ref(interner).clone()) } - pub(crate) fn normalize_lifetime_shallow( + pub fn normalize_lifetime_shallow( &mut self, interner: &I, leaf: &Lifetime, @@ -133,18 +132,14 @@ impl InferenceTable { .map(|p| p.assert_lifetime_ref(interner).clone()) } - pub(crate) fn normalize_const_shallow( - &mut self, - interner: &I, - leaf: &Const, - ) -> Option> { + pub fn normalize_const_shallow(&mut self, interner: &I, leaf: &Const) -> Option> { self.probe_var(leaf.inference_var(interner)?) .map(|p| p.assert_const_ref(interner).clone()) } /// If type `leaf` is a free inference variable, and that variable has been /// bound, returns `Some(P)` where `P` is the parameter to which it has been bound. - pub(crate) fn probe_var(&mut self, leaf: InferenceVar) -> Option> { + pub fn probe_var(&mut self, leaf: InferenceVar) -> Option> { match self.unify.probe_value(EnaVariable::from(leaf)) { InferenceValue::Unbound(_) => None, InferenceValue::Bound(val) => Some(val), @@ -164,7 +159,7 @@ impl InferenceTable { } } -pub(crate) trait ParameterEnaVariableExt { +pub trait ParameterEnaVariableExt { fn to_generic_arg(&self, interner: &I) -> GenericArg; } diff --git a/vendor/chalk-solve-0.14.0/src/infer/canonicalize.rs b/vendor/chalk-solve-0.25.0/src/infer/canonicalize.rs similarity index 93% rename from vendor/chalk-solve-0.14.0/src/infer/canonicalize.rs rename to vendor/chalk-solve-0.25.0/src/infer/canonicalize.rs index bb0c086a82..d821460681 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/canonicalize.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/canonicalize.rs @@ -1,3 +1,4 @@ +use crate::debug_span; use chalk_ir::fold::shift::Shift; use chalk_ir::fold::{Fold, Folder}; use chalk_ir::interner::{HasInterner, Interner}; @@ -26,12 +27,12 @@ impl InferenceTable { /// /// A substitution mapping from the free variables to their re-bound form is /// also returned. - pub(crate) fn canonicalize(&mut self, interner: &I, value: &T) -> Canonicalized + pub fn canonicalize(&mut self, interner: &I, value: &T) -> Canonicalized where T: Fold, T::Result: HasInterner, { - debug!("canonicalize({:#?})", value); + debug_span!("canonicalize", "{:#?}", value); let mut q = Canonicalizer { table: self, free_vars: Vec::new(), @@ -54,12 +55,12 @@ impl InferenceTable { } #[derive(Debug)] -pub(crate) struct Canonicalized { +pub struct Canonicalized { /// The canonicalized result. - pub(crate) quantified: Canonical, + pub quantified: Canonical, /// The free existential variables, along with the universes they inhabit. - pub(crate) free_vars: Vec>, + pub free_vars: Vec>, /// The maximum universe of any universally quantified variables /// encountered. @@ -81,7 +82,7 @@ impl<'q, I: Interner> Canonicalizer<'q, I> { interner, .. } = self; - CanonicalVarKinds::from( + CanonicalVarKinds::from_iter( interner, free_vars .into_iter() @@ -174,7 +175,7 @@ where ParameterEnaVariable::new(VariableKind::Ty(kind), self.table.unify.find(var)); let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); - debug!("not yet unified: position={:?}", bound_var); + debug!(position=?bound_var, "not yet unified"); Ok(TyData::BoundVar(bound_var.shifted_in_from(outer_binder)).intern(interner)) } } @@ -198,7 +199,7 @@ where let free_var = ParameterEnaVariable::new(VariableKind::Lifetime, self.table.unify.find(var)); let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); - debug!("not yet unified: position={:?}", bound_var); + debug!(position=?bound_var, "not yet unified"); Ok( LifetimeData::BoundVar(bound_var.shifted_in_from(outer_binder)) .intern(interner), @@ -228,7 +229,7 @@ where self.table.unify.find(var), ); let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); - debug!("not yet unified: position={:?}", bound_var); + debug!(position = ?bound_var, "not yet unified"); Ok(bound_var .shifted_in_from(outer_binder) .to_const(interner, ty.clone())) diff --git a/vendor/chalk-solve-0.14.0/src/infer/instantiate.rs b/vendor/chalk-solve-0.25.0/src/infer/instantiate.rs similarity index 92% rename from vendor/chalk-solve-0.14.0/src/infer/instantiate.rs rename to vendor/chalk-solve-0.25.0/src/infer/instantiate.rs index 9269b3b635..8250be649e 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/instantiate.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/instantiate.rs @@ -15,7 +15,7 @@ impl InferenceTable { interner: &I, binders: &[CanonicalVarKind], ) -> Substitution { - Substitution::from( + Substitution::from_iter( interner, binders.iter().map(|kind| { let param_infer_var = kind.map_ref(|&ui| self.new_variable(ui)); @@ -25,11 +25,7 @@ impl InferenceTable { } /// Variant on `instantiate` that takes a `Canonical`. - pub(crate) fn instantiate_canonical( - &mut self, - interner: &I, - bound: &Canonical, - ) -> T::Result + pub fn instantiate_canonical(&mut self, interner: &I, bound: &Canonical) -> T::Result where T: HasInterner + Fold + Debug, { @@ -62,7 +58,7 @@ impl InferenceTable { } /// Variant on `instantiate_in` that takes a `Binders`. - pub(crate) fn instantiate_binders_existentially<'a, T>( + pub fn instantiate_binders_existentially<'a, T>( &mut self, interner: &'a I, arg: impl IntoBindersAndValue<'a, I, Value = T>, @@ -75,7 +71,7 @@ impl InferenceTable { self.instantiate_in(interner, max_universe, binders, &value) } - pub(crate) fn instantiate_binders_universally<'a, T>( + pub fn instantiate_binders_universally<'a, T>( &mut self, interner: &'a I, arg: impl IntoBindersAndValue<'a, I, Value = T>, @@ -106,7 +102,7 @@ impl InferenceTable { } } -pub(crate) trait IntoBindersAndValue<'a, I: Interner> { +pub trait IntoBindersAndValue<'a, I: Interner> { type Binders: IntoIterator>; type Value; @@ -127,7 +123,7 @@ where } } -impl<'a, I> IntoBindersAndValue<'a, I> for &'a Fn +impl<'a, I> IntoBindersAndValue<'a, I> for &'a FnPointer where I: Interner, { diff --git a/vendor/chalk-solve-0.14.0/src/infer/invert.rs b/vendor/chalk-solve-0.25.0/src/infer/invert.rs similarity index 98% rename from vendor/chalk-solve-0.14.0/src/infer/invert.rs rename to vendor/chalk-solve-0.25.0/src/infer/invert.rs index ff1f59322f..5569b5a521 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/invert.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/invert.rs @@ -71,7 +71,7 @@ impl InferenceTable { /// `?T: Clone` in the case where `?T = Vec`. The current /// version would delay processing the negative goal (i.e., return /// `None`) until the second unification has occurred.) - pub(crate) fn invert(&mut self, interner: &I, value: &T) -> Option + pub fn invert(&mut self, interner: &I, value: &T) -> Option where T: Fold + HasInterner, { @@ -97,7 +97,7 @@ impl InferenceTable { /// As `negated_instantiated`, but canonicalizes before /// returning. Just a convenience function. - pub(crate) fn invert_then_canonicalize( + pub fn invert_then_canonicalize( &mut self, interner: &I, value: &T, diff --git a/vendor/chalk-solve-0.14.0/src/infer/test.rs b/vendor/chalk-solve-0.25.0/src/infer/test.rs similarity index 87% rename from vendor/chalk-solve-0.14.0/src/infer/test.rs rename to vendor/chalk-solve-0.25.0/src/infer/test.rs index eac42c1a9f..7f8486720a 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/test.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/test.rs @@ -3,29 +3,7 @@ use super::unify::UnificationResult; use super::*; use chalk_integration::interner::ChalkIr; - -#[test] -fn infer() { - let interner = &ChalkIr; - let mut table: InferenceTable = InferenceTable::new(); - let environment0 = Environment::new(interner); - let a = table.new_variable(U0).to_ty(interner); - let b = table.new_variable(U0).to_ty(interner); - table - .unify(interner, &environment0, &a, &ty!(apply (item 0) (expr b))) - .unwrap(); - assert_eq!( - table.normalize_deep(interner, &a), - ty!(apply (item 0) (expr b)) - ); - table - .unify(interner, &environment0, &b, &ty!(apply (item 1))) - .unwrap(); - assert_eq!( - table.normalize_deep(interner, &a), - ty!(apply (item 0) (apply (item 1))) - ); -} +use chalk_integration::{arg, lifetime, ty, ty_name}; #[test] fn universe_error() { @@ -181,7 +159,7 @@ fn quantify_simple() { .quantified, Canonical { value: ty!(apply (item 0) (bound 0) (bound 1) (bound 2)), - binders: CanonicalVarKinds::from( + binders: CanonicalVarKinds::from_iter( interner, vec![ CanonicalVarKind::new(VariableKind::Ty(TyKind::General), U2), @@ -222,7 +200,7 @@ fn quantify_bound() { .quantified, Canonical { value: ty!(apply (item 0) (apply (item 1) (bound 0) (bound 1)) (bound 2) (bound 0) (bound 1)), - binders: CanonicalVarKinds::from( + binders: CanonicalVarKinds::from_iter( interner, vec![ CanonicalVarKind::new(VariableKind::Ty(TyKind::General), U1), @@ -266,7 +244,7 @@ fn quantify_ty_under_binder() { .quantified, Canonical { value: ty!(function 3 (apply (item 0) (bound 1) (bound 1 0) (bound 1 0) (lifetime (bound 1 1)))), - binders: CanonicalVarKinds::from( + binders: CanonicalVarKinds::from_iter( interner, vec![ CanonicalVarKind::new(VariableKind::Ty(TyKind::General), U0), @@ -292,10 +270,8 @@ fn lifetime_constraint_indirect() { // '!1. let t_a = ty!(apply (item 0) (lifetime (placeholder 1))); let t_b = ty!(apply (item 0) (lifetime (infer 1))); - let UnificationResult { goals, constraints } = - table.unify(interner, &environment0, &t_a, &t_b).unwrap(); + let UnificationResult { goals } = table.unify(interner, &environment0, &t_a, &t_b).unwrap(); assert!(goals.is_empty()); - assert!(constraints.is_empty()); // Here, we try to unify `?0` (the type variable in universe 0) // with something that involves `'?1`. Since `'?1` has been @@ -303,16 +279,14 @@ fn lifetime_constraint_indirect() { // we will replace `'!1` with a new variable `'?2` and introduce a // (likely unsatisfiable) constraint relating them. let t_c = ty!(infer 0); - let UnificationResult { goals, constraints } = - table.unify(interner, &environment0, &t_c, &t_b).unwrap(); - assert!(goals.is_empty()); - assert_eq!(constraints.len(), 2); + let UnificationResult { goals } = table.unify(interner, &environment0, &t_c, &t_b).unwrap(); + assert_eq!(goals.len(), 2); assert_eq!( - format!("{:?}", constraints[0]), + format!("{:?}", goals[0]), "InEnvironment { environment: Env([]), goal: \'?2: \'!1_0 }", ); assert_eq!( - format!("{:?}", constraints[1]), + format!("{:?}", goals[1]), "InEnvironment { environment: Env([]), goal: \'!1_0: \'?2 }", ); } diff --git a/vendor/chalk-solve-0.14.0/src/infer/ucanonicalize.rs b/vendor/chalk-solve-0.25.0/src/infer/ucanonicalize.rs similarity index 95% rename from vendor/chalk-solve-0.14.0/src/infer/ucanonicalize.rs rename to vendor/chalk-solve-0.25.0/src/infer/ucanonicalize.rs index 507981d384..7dedc2842f 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/ucanonicalize.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/ucanonicalize.rs @@ -1,13 +1,13 @@ +use crate::debug_span; use chalk_ir::fold::{Fold, Folder}; use chalk_ir::interner::{HasInterner, Interner}; use chalk_ir::visit::{Visit, Visitor}; use chalk_ir::*; -use tracing::debug; use super::InferenceTable; impl InferenceTable { - pub(crate) fn u_canonicalize( + pub fn u_canonicalize( &mut self, interner: &I, value0: &Canonical, @@ -16,7 +16,7 @@ impl InferenceTable { T: HasInterner + Fold + Visit, T::Result: HasInterner, { - debug!("u_canonicalize({:#?})", value0); + debug_span!("u_canonicalize", "{:#?}", value0); // First, find all the universes that appear in `value`. let mut universes = UniverseMap::new(); @@ -46,7 +46,7 @@ impl InferenceTable { DebruijnIndex::INNERMOST, ) .unwrap(); - let binders = CanonicalVarKinds::from( + let binders = CanonicalVarKinds::from_iter( interner, value0 .binders @@ -68,15 +68,15 @@ impl InferenceTable { } #[derive(Debug)] -pub(crate) struct UCanonicalized { +pub struct UCanonicalized { /// The canonicalized result. - pub(crate) quantified: UCanonical, + pub quantified: UCanonical, /// A map between the universes in `quantified` and the original universes - pub(crate) universes: UniverseMap, + pub universes: UniverseMap, } -pub(crate) trait UniverseMapExt { +pub trait UniverseMapExt { fn add(&mut self, universe: UniverseIndex); fn map_universe_to_canonical(&self, universe: UniverseIndex) -> Option; fn map_universe_from_canonical(&self, universe: UniverseIndex) -> UniverseIndex; @@ -169,8 +169,7 @@ impl UniverseMapExt for UniverseMap { T::Result: HasInterner, I: Interner, { - debug!("map_from_canonical(value={:?})", canonical_value); - debug!("map_from_canonical: universes = {:?}", self.universes); + debug_span!("map_from_canonical", ?canonical_value, universes = ?self.universes); let binders = canonical_value .binders @@ -189,7 +188,7 @@ impl UniverseMapExt for UniverseMap { .unwrap(); Canonical { - binders: CanonicalVarKinds::from(interner, binders), + binders: CanonicalVarKinds::from_iter(interner, binders), value, } } diff --git a/vendor/chalk-solve-0.14.0/src/infer/unify.rs b/vendor/chalk-solve-0.25.0/src/infer/unify.rs similarity index 91% rename from vendor/chalk-solve-0.14.0/src/infer/unify.rs rename to vendor/chalk-solve-0.25.0/src/infer/unify.rs index 55229091e7..57b76d5b55 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/unify.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/unify.rs @@ -10,7 +10,7 @@ use std::fmt::Debug; impl InferenceTable { #[instrument(level = "debug", skip(self, interner, environment))] - pub(crate) fn unify( + pub fn unify( &mut self, interner: &I, environment: &Environment, @@ -37,15 +37,13 @@ impl InferenceTable { struct Unifier<'t, I: Interner> { table: &'t mut InferenceTable, environment: &'t Environment, - goals: Vec>>, - constraints: Vec>>, + goals: Vec>>, interner: &'t I, } #[derive(Debug)] -pub(crate) struct UnificationResult { - pub(crate) goals: Vec>>, - pub(crate) constraints: Vec>>, +pub struct UnificationResult { + pub goals: Vec>>, } impl<'t, I: Interner> Unifier<'t, I> { @@ -55,10 +53,9 @@ impl<'t, I: Interner> Unifier<'t, I> { environment: &'t Environment, ) -> Self { Unifier { - environment: environment, - table: table, + environment, + table, goals: vec![], - constraints: vec![], interner, } } @@ -71,10 +68,7 @@ impl<'t, I: Interner> Unifier<'t, I> { T: ?Sized + Zip, { Zip::zip_with(&mut self, a, b)?; - Ok(UnificationResult { - goals: self.goals, - constraints: self.constraints, - }) + Ok(UnificationResult { goals: self.goals }) } fn unify_ty_ty(&mut self, a: &Ty, b: &Ty) -> Fallible<()> { @@ -86,7 +80,6 @@ impl<'t, I: Interner> Unifier<'t, I> { let b = n_b.as_ref().unwrap_or(b); debug_span!("unify_ty_ty", ?a, ?b); - // let _s = span.enter(); match (a.data(interner), b.data(interner)) { // Unifying two inference variables: unify them in the underlying @@ -136,7 +129,11 @@ impl<'t, I: Interner> Unifier<'t, I> { // Unifying `forall { T }` with some other forall type `forall { U }` (&TyData::Function(ref fn1), &TyData::Function(ref fn2)) => { - self.unify_binders(fn1, fn2) + if fn1.abi == fn2.abi && fn1.safety == fn2.safety && fn1.variadic == fn2.variadic { + self.unify_binders(fn1, fn2) + } else { + Err(NoSolution) + } } // This would correspond to unifying a `fn` type with a non-fn @@ -191,8 +188,8 @@ impl<'t, I: Interner> Unifier<'t, I> { } /// Unify two inference variables + #[instrument(level = "debug", skip(self))] fn unify_var_var(&mut self, a: InferenceVar, b: InferenceVar) -> Fallible<()> { - debug!("unify_var_var({:?}, {:?})", a, b); let var1 = EnaVariable::from(a); let var2 = EnaVariable::from(b); Ok(self @@ -206,16 +203,13 @@ impl<'t, I: Interner> Unifier<'t, I> { /// (type kind is not `General`). For example, unify a `TyKind::General` /// inference variable with a `TyKind::Integer` variable, resulting in the /// general inference variable narrowing to an integer variable. + + #[instrument(level = "debug", skip(self))] fn unify_general_var_specific_ty( &mut self, general_var: InferenceVar, specific_ty: Ty, ) -> Fallible<()> { - debug!( - "unify_general_var_specific_var({:?}, {:?})", - general_var, specific_ty - ); - self.table .unify .unify_var_value( @@ -227,6 +221,7 @@ impl<'t, I: Interner> Unifier<'t, I> { Ok(()) } + #[instrument(level = "debug", skip(self))] fn unify_binders<'a, T, R>( &mut self, a: impl IntoBindersAndValue<'a, I, Value = T> + Copy + Debug, @@ -244,7 +239,6 @@ impl<'t, I: Interner> Unifier<'t, I> { // for<'a...> exists<'b...> T == U && // for<'b...> exists<'a...> T == U - debug!("unify_binders({:?}, {:?})", a, b); let interner = self.interner; { @@ -307,7 +301,7 @@ impl<'t, I: Interner> Unifier<'t, I> { .unify .unify_var_value(var, InferenceValue::from_ty(interner, ty1.clone())) .unwrap(); - debug!("unify_var_ty: var {:?} set to {:?}", var, ty1); + debug!("var {:?} set to {:?}", var, ty1); Ok(()) } @@ -326,10 +320,7 @@ impl<'t, I: Interner> Unifier<'t, I> { (&LifetimeData::InferenceVar(var_a), &LifetimeData::InferenceVar(var_b)) => { let var_a = EnaVariable::from(var_a); let var_b = EnaVariable::from(var_b); - debug!( - "unify_lifetime_lifetime: var_a={:?} var_b={:?}", - var_a, var_b - ); + debug!(?var_a, ?var_b); self.table.unify.unify_var_var(var_a, var_b).unwrap(); Ok(()) } @@ -344,7 +335,7 @@ impl<'t, I: Interner> Unifier<'t, I> { (&LifetimeData::Placeholder(_), &LifetimeData::Placeholder(_)) => { if a != b { - Ok(self.push_lifetime_eq_constraint(a.clone(), b.clone())) + Ok(self.push_lifetime_eq_goals(a.clone(), b.clone())) } else { Ok(()) } @@ -371,10 +362,7 @@ impl<'t, I: Interner> Unifier<'t, I> { let var = EnaVariable::from(var); let var_ui = self.table.universe_of_unbound_var(var); if var_ui.can_see(value_ui) { - debug!( - "unify_lifetime_var: {:?} in {:?} can see {:?}; unifying", - var, var_ui, value_ui - ); + debug!("{:?} in {:?} can see {:?}; unifying", var, var_ui, value_ui); self.table .unify .unify_var_value( @@ -385,10 +373,10 @@ impl<'t, I: Interner> Unifier<'t, I> { Ok(()) } else { debug!( - "unify_lifetime_var: {:?} in {:?} cannot see {:?}; pushing constraint", + "{:?} in {:?} cannot see {:?}; pushing constraint", var, var_ui, value_ui ); - Ok(self.push_lifetime_eq_constraint(a.clone(), b.clone())) + Ok(self.push_lifetime_eq_goals(a.clone(), b.clone())) } } @@ -417,7 +405,7 @@ impl<'t, I: Interner> Unifier<'t, I> { // Unifying two inference variables: unify them in the underlying // ena table. (&ConstValue::InferenceVar(var1), &ConstValue::InferenceVar(var2)) => { - // debug!("unify_ty_ty: unify_var_var({:?}, {:?})", var1, var2); + debug!(?var1, ?var2, "unify_ty_ty"); let var1 = EnaVariable::from(var1); let var2 = EnaVariable::from(var2); Ok(self @@ -430,14 +418,13 @@ impl<'t, I: Interner> Unifier<'t, I> { // Unifying an inference variables with a non-inference variable. (&ConstValue::InferenceVar(var), &ConstValue::Concrete(_)) | (&ConstValue::InferenceVar(var), &ConstValue::Placeholder(_)) => { - debug!("unify_var_ty(var={:?}, ty={:?})", var, b); + debug!(?var, ty=?b, "unify_var_ty"); self.unify_var_const(var, b) } (&ConstValue::Concrete(_), &ConstValue::InferenceVar(var)) | (&ConstValue::Placeholder(_), &ConstValue::InferenceVar(var)) => { - debug!("unify_var_ty(var={:?}, ty={:?})", var, a); - + debug!(?var, ty=?a, "unify_var_ty"); self.unify_var_const(var, a) } @@ -463,9 +450,8 @@ impl<'t, I: Interner> Unifier<'t, I> { } } + #[instrument(level = "debug", skip(self))] fn unify_var_const(&mut self, var: InferenceVar, c: &Const) -> Fallible<()> { - debug!("unify_var_const(var={:?}, c={:?})", var, c); - let interner = self.interner; let var = EnaVariable::from(var); @@ -478,14 +464,18 @@ impl<'t, I: Interner> Unifier<'t, I> { Ok(()) } - fn push_lifetime_eq_constraint(&mut self, a: Lifetime, b: Lifetime) { - self.constraints.push(InEnvironment::new( + fn push_lifetime_eq_goals(&mut self, a: Lifetime, b: Lifetime) { + self.goals.push(InEnvironment::new( self.environment, - Constraint::Outlives(a.clone(), b.clone()), + WhereClause::LifetimeOutlives(LifetimeOutlives { + a: a.clone(), + b: b.clone(), + }) + .cast(self.interner), )); - self.constraints.push(InEnvironment::new( + self.goals.push(InEnvironment::new( self.environment, - Constraint::Outlives(b, a), + WhereClause::LifetimeOutlives(LifetimeOutlives { a: b, b: a }).cast(self.interner), )); } } @@ -567,6 +557,7 @@ where } } + #[instrument(level = "debug", skip(self))] fn fold_free_placeholder_lifetime( &mut self, ui: PlaceholderIndex, @@ -588,10 +579,8 @@ where // exists<'x> forall<'b> ?T = Foo<'x>, where 'x = 'b let tick_x = self.unifier.table.new_variable(self.universe_index); - self.unifier.push_lifetime_eq_constraint( - tick_x.to_lifetime(interner), - ui.to_lifetime(interner), - ); + self.unifier + .push_lifetime_eq_goals(tick_x.to_lifetime(interner), ui.to_lifetime(interner)); Ok(tick_x.to_lifetime(interner)) } else { // If the `ui` is higher than `self.universe_index`, then we can name diff --git a/vendor/chalk-solve-0.14.0/src/infer/var.rs b/vendor/chalk-solve-0.25.0/src/infer/var.rs similarity index 93% rename from vendor/chalk-solve-0.14.0/src/infer/var.rs rename to vendor/chalk-solve-0.25.0/src/infer/var.rs index eacd086171..e272f27102 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/var.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/var.rs @@ -36,7 +36,7 @@ use std::u32; /// "downcast" the resulting variable using /// e.g. `value.ty().unwrap()`. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct EnaVariable { +pub struct EnaVariable { var: InferenceVar, phantom: PhantomData, } @@ -54,28 +54,28 @@ impl EnaVariable { /// Convert this inference variable into a type. When using this /// method, naturally you should know from context that the kind /// of this inference variable is a type (we can't check it). - pub(crate) fn to_ty_with_kind(self, interner: &I, kind: TyKind) -> Ty { + pub fn to_ty_with_kind(self, interner: &I, kind: TyKind) -> Ty { self.var.to_ty(interner, kind) } /// Same as `to_ty_with_kind`, but the kind is set to `TyKind::General`. /// This should be used instead of `to_ty_with_kind` when creating a new /// inference variable (when the kind is not known). - pub(crate) fn to_ty(self, interner: &I) -> Ty { + pub fn to_ty(self, interner: &I) -> Ty { self.var.to_ty(interner, TyKind::General) } /// Convert this inference variable into a lifetime. When using this /// method, naturally you should know from context that the kind /// of this inference variable is a lifetime (we can't check it). - pub(crate) fn to_lifetime(self, interner: &I) -> Lifetime { + pub fn to_lifetime(self, interner: &I) -> Lifetime { self.var.to_lifetime(interner) } /// Convert this inference variable into a const. When using this /// method, naturally you should know from context that the kind /// of this inference variable is a const (we can't check it). - pub(crate) fn to_const(self, interner: &I, ty: Ty) -> Const { + pub fn to_const(self, interner: &I, ty: Ty) -> Const { self.var.to_const(interner, ty) } } @@ -100,7 +100,7 @@ impl UnifyKey for EnaVariable { /// universe index; when the inference variable is assigned a value, it becomes /// bound and records that value. See `EnaVariable` for more details. #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum InferenceValue { +pub enum InferenceValue { Unbound(UniverseIndex), Bound(GenericArg), } diff --git a/vendor/chalk-solve-0.14.0/src/lib.rs b/vendor/chalk-solve-0.25.0/src/lib.rs similarity index 64% rename from vendor/chalk-solve-0.14.0/src/lib.rs rename to vendor/chalk-solve-0.25.0/src/lib.rs index 616d656d7d..0c6d300959 100644 --- a/vendor/chalk-solve-0.14.0/src/lib.rs +++ b/vendor/chalk-solve-0.25.0/src/lib.rs @@ -1,5 +1,6 @@ #![deny(rust_2018_idioms)] +use crate::display::sanitize_debug_name; use crate::rust_ir::*; use chalk_ir::interner::Interner; @@ -7,23 +8,39 @@ use chalk_ir::*; use std::fmt::Debug; use std::sync::Arc; -#[cfg(test)] -#[macro_use] -mod test_macros; - pub mod clauses; pub mod coherence; -mod coinductive_goal; +pub mod coinductive_goal; +pub mod display; pub mod ext; pub mod goal_builder; -mod infer; -#[cfg(feature = "recursive-solver")] -pub mod recursive; +pub mod infer; +pub mod logging; +pub mod logging_db; pub mod rust_ir; -mod solve; +pub mod solve; pub mod split; pub mod wf; +/// Trait representing access to a database of rust types. +/// +/// # `*_name` methods +/// +/// This trait has a number of `*_name` methods with default implementations. +/// These are used in the implementation for [`LoggingRustIrDatabase`], so that +/// when printing `.chalk` files equivalent to the data used, we can use real +/// names. +/// +/// The default implementations simply fall back to calling [`Interner`] debug +/// methods, and printing `"UnknownN"` (where `N` is the demultiplexing integer) +/// if those methods return `None`. +/// +/// The [`display::sanitize_debug_name`] utility is used in the default +/// implementations, and might be useful when providing custom implementations. +/// +/// [`LoggingRustIrDatabase`]: crate::logging_db::LoggingRustIrDatabase +/// [`display::sanitize_debug_name`]: crate::display::sanitize_debug_name +/// [`Interner`]: Interner pub trait RustIrDatabase: Debug { /// Returns any "custom program clauses" that do not derive from /// Rust IR. Used only in testing the underlying solver. @@ -35,9 +52,13 @@ pub trait RustIrDatabase: Debug { /// Returns the datum for the definition with the given id. fn trait_datum(&self, trait_id: TraitId) -> Arc>; - /// Returns the datum for the impl with the given id. + /// Returns the datum for the ADT with the given id. fn adt_datum(&self, adt_id: AdtId) -> Arc>; + /// Returns the representation for the ADT definition with the given id. + fn adt_repr(&self, id: AdtId) -> AdtRepr; + + /// Returns the datum for the fn definition with the given id. fn fn_def_datum(&self, fn_def_id: FnDefId) -> Arc>; /// Returns the datum for the impl with the given id. @@ -61,8 +82,15 @@ pub trait RustIrDatabase: Debug { /// apply. The parameters are provided as a "hint" to help the /// implementor do less work, but can be completely ignored if /// desired. - fn impls_for_trait(&self, trait_id: TraitId, parameters: &[GenericArg]) - -> Vec>; + /// + /// The `binders` are for the `parameters`; if the recursive solver is used, + /// the parameters can contain bound variables referring to these binders. + fn impls_for_trait( + &self, + trait_id: TraitId, + parameters: &[GenericArg], + binders: &CanonicalVarKinds, + ) -> Vec>; /// Returns the impls that require coherence checking. This is not the /// full set of impls that exist: @@ -80,17 +108,6 @@ pub trait RustIrDatabase: Debug { /// user gave). fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool; - /// A stop-gap solution to force an impl for a given well-known trait. - /// Useful when the logic for a given trait is absent or incomplete. - /// A value of `Some(true)` means that the the clause for the impl will be - /// added. A value of `Some(false)` means that the clause for the impl will - /// not be added, and fallback logic will not be checked. A value of `None` - /// means that the clause will not be added, but fallback logic may add logic. - #[allow(unused_variables)] - fn force_impl_for(&self, well_known: WellKnownTrait, ty: &TyData) -> Option { - None - } - /// Returns id of a trait lang item, if found fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option>; @@ -135,6 +152,36 @@ pub trait RustIrDatabase: Debug { closure_id: ClosureId, substs: &Substitution, ) -> Substitution; + + /// Retrieves a trait's original name. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn trait_name(&self, trait_id: TraitId) -> String { + sanitize_debug_name(|f| I::debug_trait_id(trait_id, f)) + } + + /// Retrieves a struct's original name. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn adt_name(&self, adt_id: AdtId) -> String { + sanitize_debug_name(|f| I::debug_adt_id(adt_id, f)) + } + + /// Retrieves the name of an associated type. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn assoc_type_name(&self, assoc_ty_id: AssocTypeId) -> String { + sanitize_debug_name(|f| I::debug_assoc_type_id(assoc_ty_id, f)) + } + + /// Retrieves the name of an opaque type. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId) -> String { + sanitize_debug_name(|f| I::debug_opaque_ty_id(opaque_ty_id, f)) + } + + /// Retrieves the name of a function definition. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn fn_def_name(&self, fn_def_id: FnDefId) -> String { + sanitize_debug_name(|f| I::debug_fn_def_id(fn_def_id, f)) + } } pub use clauses::program_clauses_for_env; @@ -142,7 +189,6 @@ pub use clauses::program_clauses_for_env; pub use solve::Guidance; pub use solve::Solution; pub use solve::Solver; -pub use solve::SolverChoice; pub use solve::SubstitutionResult; #[macro_use] diff --git a/vendor/chalk-solve-0.25.0/src/logging.rs b/vendor/chalk-solve-0.25.0/src/logging.rs new file mode 100644 index 0000000000..ac7305c480 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/logging.rs @@ -0,0 +1,19 @@ +/// Run an action with a tracing log subscriber. The logging level is loaded +/// from `CHALK_DEBUG`. +#[cfg(feature = "tracing-full")] +pub fn with_tracing_logs(action: impl FnOnce() -> T) -> T { + use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; + use tracing_tree::HierarchicalLayer; + let filter = EnvFilter::from_env("CHALK_DEBUG"); + let subscriber = Registry::default() + .with(filter) + .with(HierarchicalLayer::new(2)); + tracing::subscriber::with_default(subscriber, action) +} + +/// Run an action with a tracing log subscriber. The logging level is loaded +/// from `CHALK_DEBUG`. +#[cfg(not(feature = "tracing-full"))] +pub fn with_tracing_logs(action: impl FnOnce() -> T) -> T { + action() +} diff --git a/vendor/chalk-solve-0.25.0/src/logging_db.rs b/vendor/chalk-solve-0.25.0/src/logging_db.rs new file mode 100644 index 0000000000..52279110db --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/logging_db.rs @@ -0,0 +1,529 @@ +//! Provides wrappers over `RustIrDatabase` which record used definitions and write +//! `.chalk` files containing those definitions. +use std::{ + borrow::Borrow, + cmp::{Ord, Ordering}, + collections::BTreeSet, + fmt::{self, Debug, Display}, + io::Write, + marker::PhantomData, + sync::Arc, + sync::Mutex, +}; + +use crate::rust_ir::*; +use crate::{ + display::{self, WriterState}, + RustIrDatabase, +}; +use chalk_ir::{interner::Interner, *}; + +mod id_collector; + +/// Wraps another `RustIrDatabase` (`DB`) and records which definitions are +/// used. +/// +/// A full .chalk file containing all used definitions can be recovered through +/// `LoggingRustIrDatabase`'s `Display` implementation. +/// +/// Uses a separate type, `P`, for the database stored inside to account for +/// `Arc` or wrapping other storage mediums. +#[derive(Debug)] +pub struct LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + ws: WriterState, + def_ids: Mutex>>, + _phantom: PhantomData, +} + +impl LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + pub fn new(db: P) -> Self { + LoggingRustIrDatabase { + ws: WriterState::new(db), + def_ids: Default::default(), + _phantom: PhantomData, + } + } +} + +impl Display for LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let def_ids = self.def_ids.lock().unwrap(); + let stub_ids = id_collector::collect_unrecorded_ids(self.ws.db(), &def_ids); + display::write_stub_items(f, &self.ws, stub_ids)?; + display::write_items(f, &self.ws, def_ids.iter().copied()) + } +} + +impl LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + fn record(&self, id: impl Into>) { + self.def_ids.lock().unwrap().insert(id.into()); + } + + fn record_all(&self, ids: T) + where + T: IntoIterator, + U: Into>, + { + self.def_ids + .lock() + .unwrap() + .extend(ids.into_iter().map(Into::into)); + } +} + +impl RustIrDatabase for LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow + Debug, + I: Interner, +{ + fn custom_clauses(&self) -> Vec> { + self.ws.db().custom_clauses() + } + + fn associated_ty_data( + &self, + ty: chalk_ir::AssocTypeId, + ) -> Arc> { + let ty_datum = self.ws.db().associated_ty_data(ty); + self.record(ty_datum.trait_id); + ty_datum + } + + fn trait_datum(&self, trait_id: TraitId) -> Arc> { + self.record(trait_id); + self.ws.db().trait_datum(trait_id) + } + + fn adt_datum(&self, adt_id: AdtId) -> Arc> { + self.record(adt_id); + self.ws.db().adt_datum(adt_id) + } + + fn adt_repr(&self, id: AdtId) -> AdtRepr { + self.record(id); + self.ws.db().adt_repr(id) + } + + fn impl_datum(&self, impl_id: ImplId) -> Arc> { + self.record(impl_id); + self.ws.db().impl_datum(impl_id) + } + + fn hidden_opaque_type(&self, id: OpaqueTyId) -> Ty { + self.record(id); + self.ws.db().hidden_opaque_type(id) + } + + fn associated_ty_value( + &self, + id: crate::rust_ir::AssociatedTyValueId, + ) -> Arc> { + let value = self.ws.db().associated_ty_value(id); + self.record(value.impl_id); + value + } + + fn opaque_ty_data(&self, id: OpaqueTyId) -> Arc> { + self.record(id); + self.ws.db().opaque_ty_data(id) + } + + fn impls_for_trait( + &self, + trait_id: TraitId, + parameters: &[chalk_ir::GenericArg], + binders: &CanonicalVarKinds, + ) -> Vec> { + self.record(trait_id); + let impl_ids = self.ws.db().impls_for_trait(trait_id, parameters, binders); + self.record_all(impl_ids.iter().copied()); + impl_ids + } + + fn local_impls_to_coherence_check(&self, trait_id: TraitId) -> Vec> { + self.record(trait_id); + self.ws.db().local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { + self.record(auto_trait_id); + self.record(adt_id); + self.ws.db().impl_provided_for(auto_trait_id, adt_id) + } + + fn well_known_trait_id( + &self, + well_known_trait: crate::rust_ir::WellKnownTrait, + ) -> Option> { + let trait_id = self.ws.db().well_known_trait_id(well_known_trait); + trait_id.map(|id| self.record(id)); + trait_id + } + + fn program_clauses_for_env( + &self, + environment: &chalk_ir::Environment, + ) -> chalk_ir::ProgramClauses { + self.ws.db().program_clauses_for_env(environment) + } + + fn interner(&self) -> &I { + self.ws.db().interner() + } + + fn trait_name(&self, trait_id: TraitId) -> String { + self.ws.db().trait_name(trait_id) + } + + fn adt_name(&self, adt_id: AdtId) -> String { + self.ws.db().adt_name(adt_id) + } + + fn assoc_type_name(&self, assoc_ty_id: AssocTypeId) -> String { + self.ws.db().assoc_type_name(assoc_ty_id) + } + + fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId) -> String { + self.ws.db().opaque_type_name(opaque_ty_id) + } + + fn is_object_safe(&self, trait_id: TraitId) -> bool { + self.record(trait_id); + self.ws.db().is_object_safe(trait_id) + } + + fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId) -> Arc> { + self.record(fn_def_id); + self.ws.db().fn_def_datum(fn_def_id) + } + + fn fn_def_name(&self, fn_def_id: FnDefId) -> String { + self.ws.db().fn_def_name(fn_def_id) + } + + fn closure_kind(&self, closure_id: ClosureId, substs: &Substitution) -> ClosureKind { + // TODO: record closure IDs + self.ws.db().closure_kind(closure_id, substs) + } + + fn closure_inputs_and_output( + &self, + closure_id: ClosureId, + substs: &Substitution, + ) -> Binders> { + // TODO: record closure IDs + self.ws.db().closure_inputs_and_output(closure_id, substs) + } + + fn closure_upvars(&self, closure_id: ClosureId, substs: &Substitution) -> Binders> { + // TODO: record closure IDs + self.ws.db().closure_upvars(closure_id, substs) + } + + fn closure_fn_substitution( + &self, + closure_id: ClosureId, + substs: &Substitution, + ) -> Substitution { + // TODO: record closure IDs + self.ws.db().closure_fn_substitution(closure_id, substs) + } +} + +/// Wraps a [`RustIrDatabase`], and, when dropped, writes out all used +/// definition to the given file. +/// +/// Uses [`LoggingRustIrDatabase`] internally. +/// +/// Uses a separate type, `P`, for the database stored inside to account for +/// `Arc` or wrapping other storage mediums. +pub struct WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow, +{ + db: LoggingRustIrDatabase, + write: W, +} + +impl fmt::Debug for WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("WriteOnDropRustIrDatabase") + .field("db", &self.db) + .field("write", &"") + .finish() + } +} + +impl WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow, +{ + pub fn new(db: P, write: W) -> Self { + WriteOnDropRustIrDatabase { + db: LoggingRustIrDatabase::new(db), + write, + } + } + + pub fn from_logging_db(db: LoggingRustIrDatabase, write: W) -> Self { + WriteOnDropRustIrDatabase { db, write } + } +} + +impl Drop for WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow, +{ + fn drop(&mut self) { + write!(self.write, "{}", self.db) + .and_then(|_| self.write.flush()) + .expect("expected to be able to write rust ir database"); + } +} + +impl RustIrDatabase for WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow + Debug, +{ + fn custom_clauses(&self) -> Vec> { + self.db.custom_clauses() + } + + fn associated_ty_data( + &self, + ty: chalk_ir::AssocTypeId, + ) -> Arc> { + self.db.associated_ty_data(ty) + } + + fn trait_datum(&self, trait_id: TraitId) -> Arc> { + self.db.trait_datum(trait_id) + } + + fn adt_datum(&self, adt_id: AdtId) -> Arc> { + self.db.adt_datum(adt_id) + } + + fn adt_repr(&self, id: AdtId) -> AdtRepr { + self.db.adt_repr(id) + } + + fn impl_datum(&self, impl_id: ImplId) -> Arc> { + self.db.impl_datum(impl_id) + } + + fn associated_ty_value( + &self, + id: crate::rust_ir::AssociatedTyValueId, + ) -> Arc> { + self.db.associated_ty_value(id) + } + + fn opaque_ty_data(&self, id: OpaqueTyId) -> Arc> { + self.db.opaque_ty_data(id) + } + + fn hidden_opaque_type(&self, id: OpaqueTyId) -> Ty { + self.db.hidden_opaque_type(id) + } + + fn impls_for_trait( + &self, + trait_id: TraitId, + parameters: &[chalk_ir::GenericArg], + binders: &CanonicalVarKinds, + ) -> Vec> { + self.db.impls_for_trait(trait_id, parameters, binders) + } + + fn local_impls_to_coherence_check(&self, trait_id: TraitId) -> Vec> { + self.db.local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { + self.db.impl_provided_for(auto_trait_id, adt_id) + } + + fn well_known_trait_id( + &self, + well_known_trait: crate::rust_ir::WellKnownTrait, + ) -> Option> { + self.db.well_known_trait_id(well_known_trait) + } + + fn program_clauses_for_env( + &self, + environment: &chalk_ir::Environment, + ) -> chalk_ir::ProgramClauses { + self.db.program_clauses_for_env(environment) + } + + fn interner(&self) -> &I { + self.db.interner() + } + + fn is_object_safe(&self, trait_id: TraitId) -> bool { + self.db.is_object_safe(trait_id) + } + + fn trait_name(&self, trait_id: TraitId) -> String { + self.db.trait_name(trait_id) + } + + fn adt_name(&self, adt_id: AdtId) -> String { + self.db.adt_name(adt_id) + } + + fn assoc_type_name(&self, assoc_ty_id: AssocTypeId) -> String { + self.db.assoc_type_name(assoc_ty_id) + } + + fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId) -> String { + self.db.opaque_type_name(opaque_ty_id) + } + + fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId) -> Arc> { + self.db.fn_def_datum(fn_def_id) + } + + fn fn_def_name(&self, fn_def_id: FnDefId) -> String { + self.db.fn_def_name(fn_def_id) + } + + fn closure_kind(&self, closure_id: ClosureId, substs: &Substitution) -> ClosureKind { + // TODO: record closure IDs + self.db.closure_kind(closure_id, substs) + } + + fn closure_inputs_and_output( + &self, + closure_id: ClosureId, + substs: &Substitution, + ) -> Binders> { + self.db.closure_inputs_and_output(closure_id, substs) + } + + fn closure_upvars(&self, closure_id: ClosureId, substs: &Substitution) -> Binders> { + self.db.closure_upvars(closure_id, substs) + } + + fn closure_fn_substitution( + &self, + closure_id: ClosureId, + substs: &Substitution, + ) -> Substitution { + self.db.closure_fn_substitution(closure_id, substs) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum RecordedItemId { + Adt(AdtId), + Trait(TraitId), + Impl(ImplId), + OpaqueTy(OpaqueTyId), + FnDef(FnDefId), +} + +impl From> for RecordedItemId { + fn from(v: AdtId) -> Self { + RecordedItemId::Adt(v) + } +} + +impl From> for RecordedItemId { + fn from(v: TraitId) -> Self { + RecordedItemId::Trait(v) + } +} + +impl From> for RecordedItemId { + fn from(v: ImplId) -> Self { + RecordedItemId::Impl(v) + } +} + +impl From> for RecordedItemId { + fn from(v: OpaqueTyId) -> Self { + RecordedItemId::OpaqueTy(v) + } +} + +impl From> for RecordedItemId { + fn from(v: FnDefId) -> Self { + RecordedItemId::FnDef(v) + } +} + +/// Utility for implementing Ord for RecordedItemId. +#[derive(PartialEq, Eq, PartialOrd, Ord)] +enum OrderedItemId<'a, DefId, AdtId> { + DefId(&'a DefId), + AdtId(&'a AdtId), +} + +impl RecordedItemId { + /// Extract internal identifier. Allows for absolute ordering matching the + /// order in which chalk saw things (and thus reproducing that order in + /// printed programs) + fn ordered_item_id(&self) -> OrderedItemId<'_, I::DefId, I::InternedAdtId> { + match self { + RecordedItemId::Trait(TraitId(x)) + | RecordedItemId::Impl(ImplId(x)) + | RecordedItemId::OpaqueTy(OpaqueTyId(x)) + | RecordedItemId::FnDef(FnDefId(x)) => OrderedItemId::DefId(x), + RecordedItemId::Adt(AdtId(x)) => OrderedItemId::AdtId(x), + } + } +} + +impl PartialOrd for RecordedItemId { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for RecordedItemId { + fn cmp(&self, other: &Self) -> Ordering { + self.ordered_item_id().cmp(&other.ordered_item_id()) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/logging_db/id_collector.rs b/vendor/chalk-solve-0.25.0/src/logging_db/id_collector.rs new file mode 100644 index 0000000000..9c3dd8d866 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/logging_db/id_collector.rs @@ -0,0 +1,170 @@ +use super::RecordedItemId; +use crate::RustIrDatabase; +use chalk_ir::{ + interner::Interner, + visit::Visitor, + visit::{SuperVisit, Visit}, + AliasTy, DebruijnIndex, TyData, TypeName, WhereClause, +}; +use std::collections::BTreeSet; + +/// Collects the identifiers needed to resolve all the names for a given +/// set of identifers, excluding identifiers we already have. +/// +/// When recording identifiers to print, the `LoggingRustIrDatabase` only +/// records identifiers the solver uses. But the solver assumes well-formedness, +/// and thus skips over many names referenced in the definitions. +/// +/// For instance, if we have: +/// +/// ```rust,ignore +/// struct S {} +/// +/// trait Parent {} +/// trait Child where Self: Parent {} +/// impl Parent for S {} +/// impl Child for S {} +/// ``` +/// +/// And our goal is `S: Child`, we will only render `S`, `impl Child for S`, and +/// `trait Child`. This will not parse because the `Child` trait's definition +/// references parent. IdCollector solves this by collecting all of the directly +/// related identifiers, allowing those to be rendered as well, ensuring name +/// resolution is successful. +pub fn collect_unrecorded_ids<'i, I: Interner, DB: RustIrDatabase>( + db: &'i DB, + identifiers: &'_ BTreeSet>, +) -> BTreeSet> { + let mut collector = IdCollector { + db, + found_identifiers: BTreeSet::new(), + }; + for id in identifiers { + match *id { + RecordedItemId::Adt(adt_id) => { + collector + .db + .adt_datum(adt_id) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + RecordedItemId::FnDef(fn_def) => { + collector + .db + .fn_def_datum(fn_def) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + RecordedItemId::Trait(trait_id) => { + let trait_datum = collector.db.trait_datum(trait_id); + + trait_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST); + for assoc_ty_id in &trait_datum.associated_ty_ids { + let assoc_ty_datum = collector.db.associated_ty_data(*assoc_ty_id); + assoc_ty_datum + .bounds_on_self(collector.db.interner()) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + assoc_ty_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST) + } + } + RecordedItemId::OpaqueTy(opaque_id) => { + collector + .db + .opaque_ty_data(opaque_id) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + collector + .db + .hidden_opaque_type(opaque_id) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + RecordedItemId::Impl(impl_id) => { + let impl_datum = collector.db.impl_datum(impl_id); + for id in &impl_datum.associated_ty_value_ids { + let assoc_ty_value = collector.db.associated_ty_value(*id); + assoc_ty_value.visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + impl_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + } + } + collector + .found_identifiers + .difference(identifiers) + .copied() + .collect() +} + +struct IdCollector<'i, I: Interner, DB: RustIrDatabase> { + db: &'i DB, + found_identifiers: BTreeSet>, +} + +impl<'i, I: Interner, DB: RustIrDatabase> IdCollector<'i, I, DB> { + fn record(&mut self, id: impl Into>) { + self.found_identifiers.insert(id.into()); + } +} + +impl<'i, I: Interner, DB: RustIrDatabase> Visitor<'i, I> for IdCollector<'i, I, DB> +where + I: 'i, +{ + type Result = (); + fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = Self::Result> { + self + } + fn interner(&self) -> &'i I { + self.db.interner() + } + + fn visit_ty( + &mut self, + ty: &chalk_ir::Ty, + outer_binder: chalk_ir::DebruijnIndex, + ) -> Self::Result { + let ty_data = ty.data(self.db.interner()); + match ty_data { + TyData::Apply(apply_ty) => match apply_ty.name { + TypeName::Adt(adt) => self.record(adt), + TypeName::FnDef(fn_def) => self.record(fn_def), + TypeName::OpaqueType(opaque) => self.record(opaque), + _ => {} + }, + TyData::Alias(alias) => match alias { + AliasTy::Projection(projection_ty) => { + let assoc_ty_datum = self.db.associated_ty_data(projection_ty.associated_ty_id); + self.record(assoc_ty_datum.trait_id) + } + AliasTy::Opaque(opaque_ty) => { + self.record(opaque_ty.opaque_ty_id); + } + }, + TyData::BoundVar(..) => (), + TyData::Dyn(..) => (), + TyData::Function(..) => (), + TyData::InferenceVar(..) => (), + TyData::Placeholder(..) => (), + } + ty.super_visit_with(self, outer_binder) + } + + fn visit_where_clause( + &mut self, + where_clause: &WhereClause, + outer_binder: DebruijnIndex, + ) -> Self::Result { + match where_clause { + WhereClause::Implemented(trait_ref) => self.record(trait_ref.trait_id), + WhereClause::AliasEq(alias_eq) => match &alias_eq.alias { + AliasTy::Projection(projection_ty) => { + let assoc_ty_datum = self.db.associated_ty_data(projection_ty.associated_ty_id); + self.record(assoc_ty_datum.trait_id) + } + AliasTy::Opaque(opaque_ty) => { + self.record(opaque_ty.opaque_ty_id); + } + }, + WhereClause::LifetimeOutlives(_lifetime_outlives) => (), + WhereClause::TypeOutlives(_type_outlives) => (), + } + where_clause.super_visit_with(self.as_dyn(), outer_binder) + } +} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/lib.rs b/vendor/chalk-solve-0.25.0/src/recursive/lib.rs similarity index 96% rename from vendor/chalk-solve-0.14.0/src/recursive/lib.rs rename to vendor/chalk-solve-0.25.0/src/recursive/lib.rs index b81a41fb55..8c30267eef 100644 --- a/vendor/chalk-solve-0.14.0/src/recursive/lib.rs +++ b/vendor/chalk-solve-0.25.0/src/recursive/lib.rs @@ -1,6 +1,8 @@ use super::search_graph::DepthFirstNumber; use chalk_ir::interner::Interner; -use chalk_ir::{Canonical, ConstrainedSubst, Goal, InEnvironment, Substitution, UCanonical}; +use chalk_ir::{ + Canonical, ConstrainedSubst, Constraints, Goal, InEnvironment, Substitution, UCanonical, +}; use std::fmt; use tracing::debug; @@ -118,14 +120,14 @@ impl Solution { } /// Extract a constrained substitution from this solution, even if ambiguous. - pub(crate) fn constrained_subst(&self) -> Option>> { + pub(crate) fn constrained_subst(&self, interner: &I) -> Option>> { match *self { Solution::Unique(ref constrained) => Some(constrained.clone()), Solution::Ambig(Guidance::Definite(ref canonical)) | Solution::Ambig(Guidance::Suggested(ref canonical)) => { let value = ConstrainedSubst { subst: canonical.value.clone(), - constraints: vec![], + constraints: Constraints::empty(interner), }; Some(Canonical { value, diff --git a/vendor/chalk-solve-0.14.0/src/rust_ir.rs b/vendor/chalk-solve-0.25.0/src/rust_ir.rs similarity index 84% rename from vendor/chalk-solve-0.14.0/src/rust_ir.rs rename to vendor/chalk-solve-0.25.0/src/rust_ir.rs index 7b576539dd..74fdd85b4d 100644 --- a/vendor/chalk-solve-0.14.0/src/rust_ir.rs +++ b/vendor/chalk-solve-0.25.0/src/rust_ir.rs @@ -1,5 +1,3 @@ -#![deny(rust_2018_idioms)] - //! Contains the definition for the "Rust IR" -- this is basically a "lowered" //! version of the AST, roughly corresponding to [the HIR] in the Rust //! compiler. @@ -9,9 +7,10 @@ use chalk_ir::cast::Cast; use chalk_ir::fold::shift::Shift; use chalk_ir::interner::{Interner, TargetInterner}; use chalk_ir::{ + visit::{Visit, VisitResult}, AdtId, AliasEq, AliasTy, AssocTypeId, Binders, DebruijnIndex, FnDefId, GenericArg, ImplId, - OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Substitution, ToGenericArg, TraitId, TraitRef, - Ty, TyData, TypeName, VariableKind, WhereClause, WithKind, + OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Safety, Substitution, ToGenericArg, TraitId, + TraitRef, Ty, TyData, TypeName, VariableKind, WhereClause, WithKind, }; use std::iter; @@ -19,9 +18,10 @@ use std::iter; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AssociatedTyValueId(pub I::DefId); +chalk_ir::id_visit!(AssociatedTyValueId); chalk_ir::id_fold!(AssociatedTyValueId); -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Visit)] pub struct ImplDatum { pub polarity: Polarity, pub binders: Binders>, @@ -55,7 +55,7 @@ impl ImplDatum { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, Fold)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, Fold, Visit)] pub struct ImplDatumBound { pub trait_ref: TraitRef, pub where_clauses: Vec>, @@ -67,6 +67,8 @@ pub enum ImplType { External, } +chalk_ir::const_visit!(ImplType); + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct DefaultImplDatum { pub binders: Binders>, @@ -78,25 +80,40 @@ pub struct DefaultImplDatumBound { pub accessible_tys: Vec>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Visit)] pub struct AdtDatum { pub binders: Binders>, pub id: AdtId, pub flags: AdtFlags, + pub kind: AdtKind, } +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub enum AdtKind { + Struct, + Enum, + Union, +} + +chalk_ir::const_visit!(AdtKind); + impl AdtDatum { pub fn name(&self, interner: &I) -> TypeName { self.id.cast(interner) } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct AdtDatumBound { - pub fields: Vec>, + pub variants: Vec>, pub where_clauses: Vec>, } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] +pub struct AdtVariantDatum { + pub fields: Vec>, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct AdtFlags { pub upstream: bool, @@ -104,6 +121,14 @@ pub struct AdtFlags { pub phantom_data: bool, } +chalk_ir::const_visit!(AdtFlags); + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct AdtRepr { + pub repr_c: bool, + pub repr_packed: bool, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] /// A rust intermediate represention (rust_ir) of a function definition/declaration. /// For example, in the following rust code: @@ -120,12 +145,32 @@ pub struct AdtFlags { pub struct FnDefDatum { pub id: FnDefId, pub abi: I::FnAbi, + pub safety: Safety, + pub variadic: bool, pub binders: Binders>, } +/// Avoids visiting `I::FnAbi` +impl Visit for FnDefDatum { + fn visit_with<'i, R: VisitResult>( + &self, + visitor: &mut dyn chalk_ir::visit::Visitor<'i, I, Result = R>, + outer_binder: DebruijnIndex, + ) -> R + where + I: 'i, + { + let result = R::new().combine(self.id.visit_with(visitor, outer_binder)); + if result.return_early() { + return result; + } + result.combine(self.binders.visit_with(visitor, outer_binder)) + } +} + /// Represents the inputs and outputs on a `FnDefDatum`. This is split /// from the where clauses, since these can contain bound lifetimes. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct FnDefInputsAndOutputDatum { /// Types of the function's arguments /// ```ignore @@ -142,7 +187,7 @@ pub struct FnDefInputsAndOutputDatum { pub return_type: Ty, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] /// Represents the bounds on a `FnDefDatum`, including /// the function definition's type signature and where clauses. pub struct FnDefDatumBound { @@ -193,6 +238,7 @@ pub struct FnDefDatumBound { /// /// [`ImplDatum`]: struct.ImplDatum.html /// [`AssociatedTyDatum`]: struct.AssociatedTyDatum.html +#[derive(Visit)] pub struct TraitDatum { pub id: TraitId, @@ -227,6 +273,8 @@ pub enum WellKnownTrait { Unsize, } +chalk_ir::const_visit!(WellKnownTrait); + impl TraitDatum { pub fn is_auto_trait(&self) -> bool { self.flags.auto @@ -251,7 +299,7 @@ impl TraitDatum { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, Visit)] pub struct TraitDatumBound { /// Where clauses defined on the trait: /// @@ -295,6 +343,8 @@ pub struct TraitFlags { pub coinductive: bool, } +chalk_ir::const_visit!(TraitFlags); + /// An inline bound, e.g. `: Foo` in `impl> SomeType`. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] pub enum InlineBound { @@ -355,7 +405,7 @@ impl TraitBound { pub fn as_trait_ref(&self, interner: &I, self_ty: Ty) -> TraitRef { TraitRef { trait_id: self.trait_id, - substitution: Substitution::from( + substitution: Substitution::from_iter( interner, iter::once(self_ty.cast(interner)).chain(self.args_no_self.iter().cloned()), ), @@ -378,7 +428,7 @@ impl AliasEqBound { fn into_where_clauses(&self, interner: &I, self_ty: Ty) -> Vec> { let trait_ref = self.trait_bound.as_trait_ref(interner, self_ty); - let substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, self.parameters .iter() @@ -448,6 +498,28 @@ pub struct AssociatedTyDatum { pub binders: Binders>, } +// Manual implementation to avoid I::Identifier type. +impl Visit for AssociatedTyDatum { + fn visit_with<'i, R: VisitResult>( + &self, + visitor: &mut dyn chalk_ir::visit::Visitor<'i, I, Result = R>, + outer_binder: DebruijnIndex, + ) -> R + where + I: 'i, + { + let result = R::new().combine(self.trait_id.visit_with(visitor, outer_binder)); + if result.return_early() { + return result; + } + let result = result.combine(self.id.visit_with(visitor, outer_binder)); + if result.return_early() { + return result; + } + result.combine(self.binders.visit_with(visitor, outer_binder)) + } +} + /// Encodes the parts of `AssociatedTyDatum` where the parameters /// `P0..Pm` are in scope (`bounds` and `where_clauses`). #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] @@ -475,11 +547,11 @@ impl AssociatedTyDatum { let (binders, assoc_ty_datum) = self.binders.as_ref().into(); // Create a list `P0...Pn` of references to the binders in // scope for this associated type: - let substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, binders .iter(interner) - .zip(0..) + .enumerate() .map(|p| p.to_generic_arg(interner)), ); @@ -562,7 +634,7 @@ pub struct AssociatedTyValueBound { /// ```ignore /// opaque type T: A + B = HiddenTy; /// ``` -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit)] pub struct OpaqueTyDatum { /// The placeholder `!T` that corresponds to the opaque type `T`. pub opaque_ty_id: OpaqueTyId, @@ -571,10 +643,14 @@ pub struct OpaqueTyDatum { pub bound: Binders>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct OpaqueTyDatumBound { - /// Trait bounds for the opaque type. + /// Trait bounds for the opaque type. These are bounds that the hidden type must meet. pub bounds: Binders>>, + /// Where clauses that inform well-formedness conditions for the opaque type. + /// These are conditions on the generic parameters of the opaque type which must be true + /// for a reference to the opaque type to be well-formed. + pub where_clauses: Binders>>, } #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] @@ -583,6 +659,8 @@ pub enum Polarity { Negative, } +chalk_ir::const_visit!(Polarity); + impl Polarity { pub fn is_positive(&self) -> bool { match *self { diff --git a/vendor/chalk-solve-0.25.0/src/solve.rs b/vendor/chalk-solve-0.25.0/src/solve.rs new file mode 100644 index 0000000000..dc74045acd --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/solve.rs @@ -0,0 +1,206 @@ +use crate::RustIrDatabase; +use chalk_derive::HasInterner; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use std::fmt; + +pub mod truncate; + +/// A (possible) solution for a proposed goal. +#[derive(Clone, Debug, PartialEq, Eq, HasInterner)] +pub enum Solution { + /// The goal indeed holds, and there is a unique value for all existential + /// variables. In this case, we also record a set of lifetime constraints + /// which must also hold for the goal to be valid. + Unique(Canonical>), + + /// The goal may be provable in multiple ways, but regardless we may have some guidance + /// for type inference. In this case, we don't return any lifetime + /// constraints, since we have not "committed" to any particular solution + /// yet. + Ambig(Guidance), +} + +/// When a goal holds ambiguously (e.g., because there are multiple possible +/// solutions), we issue a set of *guidance* back to type inference. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Guidance { + /// The existential variables *must* have the given values if the goal is + /// ever to hold, but that alone isn't enough to guarantee the goal will + /// actually hold. + Definite(Canonical>), + + /// There are multiple plausible values for the existentials, but the ones + /// here are suggested as the preferred choice heuristically. These should + /// be used for inference fallback only. + Suggested(Canonical>), + + /// There's no useful information to feed back to type inference + Unknown, +} + +impl Solution { + pub fn is_unique(&self) -> bool { + match *self { + Solution::Unique(..) => true, + _ => false, + } + } + + pub fn display<'a>(&'a self, interner: &'a I) -> SolutionDisplay<'a, I> { + SolutionDisplay { + solution: self, + interner, + } + } +} + +pub struct SolutionDisplay<'a, I: Interner> { + solution: &'a Solution, + interner: &'a I, +} + +impl<'a, I: Interner> fmt::Display for SolutionDisplay<'a, I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + let SolutionDisplay { solution, interner } = self; + match solution { + Solution::Unique(constrained) => write!(f, "Unique; {}", constrained.display(interner)), + Solution::Ambig(Guidance::Definite(subst)) => write!( + f, + "Ambiguous; definite substitution {}", + subst.display(interner) + ), + Solution::Ambig(Guidance::Suggested(subst)) => write!( + f, + "Ambiguous; suggested substitution {}", + subst.display(interner) + ), + Solution::Ambig(Guidance::Unknown) => write!(f, "Ambiguous; no inference guidance"), + } + } +} + +#[derive(Debug)] +pub enum SubstitutionResult { + Definite(S), + Ambiguous(S), + Floundered, +} + +impl SubstitutionResult { + pub fn as_ref(&self) -> SubstitutionResult<&S> { + match self { + SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(subst), + SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(subst), + SubstitutionResult::Floundered => SubstitutionResult::Floundered, + } + } + pub fn map U>(self, f: F) -> SubstitutionResult { + match self { + SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(f(subst)), + SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(f(subst)), + SubstitutionResult::Floundered => SubstitutionResult::Floundered, + } + } +} + +impl fmt::Display for SubstitutionResult { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SubstitutionResult::Definite(subst) => write!(fmt, "{}", subst), + SubstitutionResult::Ambiguous(subst) => write!(fmt, "Ambiguous({})", subst), + SubstitutionResult::Floundered => write!(fmt, "Floundered"), + } + } +} + +/// Finds the solution to "goals", or trait queries -- i.e., figures +/// out what sets of types implement which traits. Also, between +/// queries, this struct stores the cached state from previous solver +/// attempts, which can then be re-used later. +pub trait Solver +where + Self: fmt::Debug, +{ + /// Attempts to solve the given goal, which must be in canonical + /// form. Returns a unique solution (if one exists). This will do + /// only as much work towards `goal` as it has to (and that work + /// is cached for future attempts). + /// + /// # Parameters + /// + /// - `program` -- defines the program clauses in scope. + /// - **Important:** You must supply the same set of program clauses + /// each time you invoke `solve`, as otherwise the cached data may be + /// invalid. + /// - `goal` the goal to solve + /// + /// # Returns + /// + /// - `None` is the goal cannot be proven. + /// - `Some(solution)` if we succeeded in finding *some* answers, + /// although `solution` may reflect ambiguity and unknowns. + fn solve( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + ) -> Option>; + + /// Attempts to solve the given goal, which must be in canonical + /// form. Returns a unique solution (if one exists). This will do + /// only as much work towards `goal` as it has to (and that work + /// is cached for future attempts). In addition, the solving of the + /// goal can be limited by returning `false` from `should_continue`. + /// + /// # Parameters + /// + /// - `program` -- defines the program clauses in scope. + /// - **Important:** You must supply the same set of program clauses + /// each time you invoke `solve`, as otherwise the cached data may be + /// invalid. + /// - `goal` the goal to solve + /// - `should_continue` if `false` is returned, the no further solving + /// will be done. A `Guidance(Suggested(...))` will be returned a + /// `Solution`, using any answers that were generated up to that point. + /// + /// # Returns + /// + /// - `None` is the goal cannot be proven. + /// - `Some(solution)` if we succeeded in finding *some* answers, + /// although `solution` may reflect ambiguity and unknowns. + fn solve_limited( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + should_continue: &dyn std::ops::Fn() -> bool, + ) -> Option>; + + /// Attempts to solve the given goal, which must be in canonical + /// form. Provides multiple solutions to function `f`. This will do + /// only as much work towards `goal` as it has to (and that work + /// is cached for future attempts). + /// + /// # Parameters + /// + /// - `program` -- defines the program clauses in scope. + /// - **Important:** You must supply the same set of program clauses + /// each time you invoke `solve`, as otherwise the cached data may be + /// invalid. + /// - `goal` the goal to solve + /// - `f` -- function to proceed solution. New solutions will be generated + /// while function returns `true`. + /// - first argument is solution found + /// - second argument is ther next solution present + /// - returns true if next solution should be handled + /// + /// # Returns + /// + /// - `true` all solutions were processed with the function. + /// - `false` the function returned `false` and solutions were interrupted. + fn solve_multiple( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + f: &mut dyn FnMut(SubstitutionResult>>, bool) -> bool, + ) -> bool; +} diff --git a/vendor/chalk-solve-0.14.0/src/solve/test/bench.rs b/vendor/chalk-solve-0.25.0/src/solve/test/bench.rs similarity index 100% rename from vendor/chalk-solve-0.14.0/src/solve/test/bench.rs rename to vendor/chalk-solve-0.25.0/src/solve/test/bench.rs diff --git a/vendor/chalk-solve-0.14.0/src/solve/truncate.rs b/vendor/chalk-solve-0.25.0/src/solve/truncate.rs similarity index 97% rename from vendor/chalk-solve-0.14.0/src/solve/truncate.rs rename to vendor/chalk-solve-0.25.0/src/solve/truncate.rs index a56528ba12..44c5ea81ea 100644 --- a/vendor/chalk-solve-0.14.0/src/solve/truncate.rs +++ b/vendor/chalk-solve-0.25.0/src/solve/truncate.rs @@ -6,7 +6,7 @@ use chalk_ir::visit::{SuperVisit, Visit, Visitor}; use chalk_ir::*; use std::cmp::max; -pub(crate) fn needs_truncation( +pub fn needs_truncation( interner: &I, infer: &mut InferenceTable, max_size: usize, @@ -73,6 +73,8 @@ impl<'infer, 'i, I: Interner> Visitor<'i, I> for TySizeVisitor<'infer, 'i, I> { #[cfg(test)] mod tests { use super::*; + use chalk_integration::{arg, ty, ty_name}; + #[test] fn one_type() { use chalk_integration::interner::ChalkIr; diff --git a/vendor/chalk-solve-0.14.0/src/split.rs b/vendor/chalk-solve-0.25.0/src/split.rs similarity index 79% rename from vendor/chalk-solve-0.14.0/src/split.rs rename to vendor/chalk-solve-0.25.0/src/split.rs index 616958d006..b94adc195d 100644 --- a/vendor/chalk-solve-0.14.0/src/split.rs +++ b/vendor/chalk-solve-0.25.0/src/split.rs @@ -27,12 +27,10 @@ pub trait Split: RustIrDatabase { associated_ty_id, ref substitution, } = *projection; - let parameters = substitution.parameters(interner); + let parameters = substitution.as_slice(interner); let associated_ty_data = &self.associated_ty_data(associated_ty_id); - let trait_datum = &self.trait_datum(associated_ty_data.trait_id); - let trait_num_params = trait_datum.binders.len(interner); - let split_point = parameters.len() - trait_num_params; - let (other_params, trait_params) = parameters.split_at(split_point); + let (trait_params, other_params) = + self.split_associated_ty_parameters(parameters, &**associated_ty_data); (associated_ty_data.clone(), trait_params, other_params) } @@ -55,7 +53,7 @@ pub trait Split: RustIrDatabase { let (associated_ty_data, trait_params, _) = self.split_projection(&projection); TraitRef { trait_id: associated_ty_data.trait_id, - substitution: Substitution::from(interner, trait_params), + substitution: Substitution::from_iter(interner, trait_params), } } @@ -137,14 +135,14 @@ pub trait Split: RustIrDatabase { self.split_associated_ty_value_parameters(¶meters, associated_ty_value); let trait_ref = { let opaque_ty_ref = impl_datum.binders.map_ref(|b| &b.trait_ref); - debug!("opaque_ty_ref: {:?}", opaque_ty_ref); + debug!(?opaque_ty_ref); opaque_ty_ref.substitute(interner, impl_parameters) }; // Create the parameters for the projection -- in our example // above, this would be `['!a, Box]`, corresponding to // ` as Foo>::Item<'!a>` - let projection_substitution = Substitution::from( + let projection_substitution = Substitution::from_iter( interner, atv_parameters .iter() @@ -157,12 +155,45 @@ pub trait Split: RustIrDatabase { substitution: projection_substitution, }; - debug!("impl_parameters: {:?}", impl_parameters); - debug!("trait_ref: {:?}", trait_ref); - debug!("projection: {:?}", projection); + debug!(?impl_parameters, ?trait_ref, ?projection); (impl_parameters, projection) } + + /// Given the full set of parameters (or binders) for an + /// associated type datum (the one appearing in a trait), splits + /// them into the parameters for the *trait* and those for the + /// *associated type*. + /// + /// # Example + /// + /// ```ignore (example) + /// trait Foo { + /// type Assoc<'a>; + /// } + /// ``` + /// + /// in this example, the full set of parameters would be `['x, + /// Y]`, where `'x` is the value for `'a` and `Y` is the value for + /// `T`. + /// + /// # Returns + /// + /// Returns the tuple of: + /// + /// * the parameters for the impl (`[Y]`, in our example) + /// * the parameters for the associated type value (`['a]`, in our example) + fn split_associated_ty_parameters<'p, P>( + &self, + parameters: &'p [P], + associated_ty_datum: &AssociatedTyDatum, + ) -> (&'p [P], &'p [P]) { + let trait_datum = &self.trait_datum(associated_ty_datum.trait_id); + let trait_num_params = trait_datum.binders.len(self.interner()); + let split_point = parameters.len() - trait_num_params; + let (other_params, trait_params) = parameters.split_at(split_point); + (trait_params, other_params) + } } impl + ?Sized, I: Interner> Split for DB {} diff --git a/vendor/chalk-solve-0.14.0/src/wf.rs b/vendor/chalk-solve-0.25.0/src/wf.rs similarity index 85% rename from vendor/chalk-solve-0.14.0/src/wf.rs rename to vendor/chalk-solve-0.25.0/src/wf.rs index d5892c76f6..03c60e66da 100644 --- a/vendor/chalk-solve-0.14.0/src/wf.rs +++ b/vendor/chalk-solve-0.25.0/src/wf.rs @@ -3,7 +3,7 @@ use std::{fmt, iter}; use crate::ext::*; use crate::goal_builder::GoalBuilder; use crate::rust_ir::*; -use crate::solve::SolverChoice; +use crate::solve::Solver; use crate::split::Split; use crate::RustIrDatabase; use chalk_ir::cast::*; @@ -38,9 +38,9 @@ impl fmt::Display for WfError { impl std::error::Error for WfError {} -pub struct WfSolver<'db, I: Interner> { - db: &'db dyn RustIrDatabase, - solver_choice: SolverChoice, +pub struct WfSolver<'a, I: Interner> { + db: &'a dyn RustIrDatabase, + solver_builder: &'a dyn Fn() -> Box>, } struct InputTypeCollector<'i, I: Interner> { @@ -84,6 +84,7 @@ impl<'i, I: Interner> Visitor<'i, I> for InputTypeCollector<'i, I> { WhereClause::Implemented(trait_ref) => { trait_ref.visit_with(self, outer_binder); } + WhereClause::TypeOutlives(TypeOutlives { ty, .. }) => ty.visit_with(self, outer_binder), WhereClause::LifetimeOutlives(..) => {} } } @@ -137,16 +138,18 @@ impl<'i, I: Interner> Visitor<'i, I> for InputTypeCollector<'i, I> { } } -impl<'db, I> WfSolver<'db, I> +impl<'a, I> WfSolver<'a, I> where I: Interner, { /// Constructs a new `WfSolver`. - pub fn new(db: &'db dyn RustIrDatabase, solver_choice: SolverChoice) -> Self { - Self { db, solver_choice } + pub fn new( + db: &'a dyn RustIrDatabase, + solver_builder: &'a dyn Fn() -> Box>, + ) -> Self { + Self { db, solver_builder } } - /// TODO: Currently only handles structs, may need more work for enums & unions pub fn verify_adt_decl(&self, adt_id: AdtId) -> Result<(), WfError> { let interner = self.db.interner(); @@ -157,46 +160,67 @@ where // data: Vec // } // ``` - let struct_datum = self.db.adt_datum(adt_id); + let adt_datum = self.db.adt_datum(adt_id); + let is_enum = adt_datum.kind == AdtKind::Enum; let mut gb = GoalBuilder::new(self.db); - let struct_data = struct_datum + let adt_data = adt_datum .binders - .map_ref(|b| (&b.fields, &b.where_clauses)); + .map_ref(|b| (&b.variants, &b.where_clauses)); // We make a goal like... // // forall { ... } - let wg_goal = gb.forall(&struct_data, (), |gb, _, (fields, where_clauses), ()| { - let interner = gb.interner(); - - // struct is well-formed in terms of Sized - let sized_constraint_goal = WfWellKnownGoals::struct_sized_constraint(gb.db(), fields); + let wg_goal = gb.forall( + &adt_data, + is_enum, + |gb, _, (variants, where_clauses), is_enum| { + let interner = gb.interner(); - // (FromEnv(T: Eq) => ...) - gb.implies( - where_clauses - .iter() - .cloned() - .map(|wc| wc.into_from_env_goal(interner)), - |gb| { - // WellFormed(Vec), for each field type `Vec` or type that appears in the where clauses - let types = - InputTypeCollector::types_in(gb.interner(), (&fields, &where_clauses)); - - gb.all( - types - .into_iter() - .map(|ty| ty.well_formed().cast(interner)) - .chain(sized_constraint_goal.into_iter()), - ) - }, - ) - }); + // (FromEnv(T: Eq) => ...) + gb.implies( + where_clauses + .iter() + .cloned() + .map(|wc| wc.into_from_env_goal(interner)), + |gb| { + let sub_goals: Vec<_> = variants + .iter() + .flat_map(|variant| { + let fields = &variant.fields; + + // When checking if Enum is well-formed, we require that all fields of + // each variant are sized. For `structs`, we relax this requirement to + // all but the last field. + let sized_constraint_goal = + WfWellKnownGoals::struct_sized_constraint( + gb.db(), + fields, + is_enum, + ); + + // WellFormed(Vec), for each field type `Vec` or type that appears in the where clauses + let types = InputTypeCollector::types_in( + gb.interner(), + (&fields, &where_clauses), + ); + + types + .into_iter() + .map(|ty| ty.well_formed().cast(interner)) + .chain(sized_constraint_goal.into_iter()) + }) + .collect(); + + gb.all(sub_goals) + }, + ) + }, + ); let wg_goal = wg_goal.into_closed_goal(interner); - - let is_legal = match self.solver_choice.into_solver().solve(self.db, &wg_goal) { + let mut fresh_solver = (self.solver_builder)(); + let is_legal = match fresh_solver.solve(self.db, &wg_goal) { Some(sol) => sol.is_unique(), None => false, }; @@ -226,11 +250,8 @@ where debug!("WF trait goal: {:?}", impl_goal); - let is_legal = match self - .solver_choice - .into_solver() - .solve(self.db, &impl_goal.into_closed_goal(interner)) - { + let mut fresh_solver = (self.solver_builder)(); + let is_legal = match fresh_solver.solve(self.db, &impl_goal.into_closed_goal(interner)) { Some(sol) => sol.is_unique(), None => false, }; @@ -280,7 +301,7 @@ fn impl_header_wf_goal( // Things to prove well-formed: input types of the where-clauses, projection types // appearing in the header, associated type values, and of course the trait ref. - debug!("verify_trait_impl: input_types={:?}", types); + debug!(input_types=?types); let goals = types .into_iter() .map(|ty| ty.well_formed().cast(interner)) @@ -386,7 +407,7 @@ fn compute_assoc_ty_goal( let (impl_parameters, projection) = db .impl_parameters_and_projection_from_associated_ty_value( - &assoc_ty_substitution.parameters(interner), + &assoc_ty_substitution.as_slice(interner), assoc_ty, ); @@ -499,7 +520,7 @@ impl WfWellKnownGoals { | WellKnownTrait::FnOnce | WellKnownTrait::FnMut | WellKnownTrait::Fn - | WellKnownTrait::Unsize => Some(GoalData::CannotProve(()).intern(interner)), + | WellKnownTrait::Unsize => Some(GoalData::CannotProve.intern(interner)), } } @@ -509,8 +530,11 @@ impl WfWellKnownGoals { pub fn struct_sized_constraint( db: &dyn RustIrDatabase, fields: &[Ty], + size_all: bool, ) -> Option> { - if fields.len() <= 1 { + let excluded = if size_all { 0 } else { 1 }; + + if fields.len() <= excluded { return None; } @@ -520,7 +544,7 @@ impl WfWellKnownGoals { Some(Goal::all( interner, - fields[..fields.len() - 1].iter().map(|ty| { + fields[..fields.len() - excluded].iter().map(|ty| { TraitRef { trait_id: sized_trait, substitution: Substitution::from1(interner, ty.clone()), @@ -533,7 +557,7 @@ impl WfWellKnownGoals { /// Computes a goal to prove constraints on a Copy implementation. /// Copy impl is considered well-formed for /// a) certain builtin types (scalar values, shared ref, etc..) - /// b) structs which + /// b) adts which /// 1) have all Copy fields /// 2) don't have a Drop impl fn copy_impl_constraint( @@ -554,10 +578,10 @@ impl WfWellKnownGoals { | TypeName::Ref(Mutability::Not) | TypeName::Never => return None, TypeName::Adt(adt_id) => (*adt_id, substitution), - _ => return Some(GoalData::CannotProve(()).intern(interner)), + _ => return Some(GoalData::CannotProve.intern(interner)), }, - _ => return Some(GoalData::CannotProve(()).intern(interner)), + _ => return Some(GoalData::CannotProve.intern(interner)), }; // not { Implemented(ImplSelfTy: Drop) } @@ -576,16 +600,18 @@ impl WfWellKnownGoals { let goals = adt_datum .binders - .map_ref(|b| &b.fields) + .map_ref(|b| &b.variants) .substitute(interner, substitution) .into_iter() - .map(|f| { - // Implemented(FieldTy: Copy) - TraitRef { - trait_id: trait_ref.trait_id, - substitution: Substitution::from1(interner, f), - } - .cast(interner) + .flat_map(|v| { + v.fields.into_iter().map(|f| { + // Implemented(FieldTy: Copy) + TraitRef { + trait_id: trait_ref.trait_id, + substitution: Substitution::from1(interner, f), + } + .cast(interner) + }) }) .chain(neg_drop_goal.into_iter()); @@ -635,7 +661,7 @@ impl WfWellKnownGoals { let adt_id = match impl_datum.self_type_adt_id(interner) { Some(id) => id, // Drop can only be implemented on a nominal type - None => return Some(GoalData::CannotProve(()).intern(interner)), + None => return Some(GoalData::CannotProve.intern(interner)), }; let mut gb = GoalBuilder::new(db); diff --git a/vendor/chalk-solve/.cargo-checksum.json b/vendor/chalk-solve/.cargo-checksum.json index f2e511090b..7b027f6d9e 100644 --- a/vendor/chalk-solve/.cargo-checksum.json +++ b/vendor/chalk-solve/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"cd30176dbc4a3acb159f54698bf07d567cc0d6edc373ff74b79b14b014d456aa","README.md":"2de2da988dbbaa8feb78b0a771b7bee942f34705ab057c824b1183300c535c74","src/clauses.rs":"b4e8d03cf1137b3512b3dee245d05471396069131e2391ca667d3b192c942425","src/clauses/builder.rs":"ea0e37237addb834d3b274d316fae270dcbd418fc89d3c6cebf09e31fe346634","src/clauses/builtin_traits.rs":"0d8280fa4b261154a101698d2dbb63e5ff14c314fd7801732055c2f9d1ab66d0","src/clauses/builtin_traits/clone.rs":"963a3a192aa8283733d3bc2c0a5e7cf0debcf47986df85a25eef3e3c647de257","src/clauses/builtin_traits/copy.rs":"e5e2e9d8355fb2aaf36ab6d9ab89cf28d6a0984eb621773cb8a4d82a6302e25c","src/clauses/builtin_traits/fn_family.rs":"b81715f2521a1ee9aafd429931c2a250675898f0ee121c374298cb4af20aff58","src/clauses/builtin_traits/sized.rs":"7147c0bdc117fb7e768430ad963ce5c627bfe3641c04e3269f8a08a215c93dab","src/clauses/builtin_traits/unsize.rs":"9ac311cc905d068f5626204cdacadfe8b3e9c126fb821c8cbd054f7fd21165d2","src/clauses/dyn_ty.rs":"7c32ccd5a3bc7479b0e34ca2d3da254edcc7f73e38ace9f1860c5f64bb8def8a","src/clauses/env_elaborator.rs":"bd598d47075b7c5366c9db55d99b1426c7ea646bd2508c7674bcc52d918bdf76","src/clauses/generalize.rs":"c44f8e559a12f67ad55cff2dd3ffb39d9333cf39a7c8b78c6a8fe87e764c2f98","src/clauses/program_clauses.rs":"4ff101e17087299b3e431796dbb2fe8950b2bb3f2f4b2e7b4464bd3698656d41","src/coherence.rs":"665658b1dda7d5a37e9183a6ff176048c5b1001d23766b3b97288cdf8f3a94cc","src/coherence/orphan.rs":"621a839058309f1977e9eea972afa1622a372e06889d8d20aff64788cfba1829","src/coherence/solve.rs":"34746fd1a3e5984b8b3163bf89a906f5e2f99f17f57b1364ec688c3754d5272e","src/coinductive_goal.rs":"7a2179fb2d61435cf55c5c87301db6c15edb3cb46750bea381451649b2f1051d","src/display.rs":"c5c0a796b6037dea1cf18dcb063f0ccd3bd82012b480231f4e15d2186bb9a9f8","src/display/bounds.rs":"47b402d34c9a0cb7d4f4f35b40d86f983b6a335c9dfae95645eaa472404b6098","src/display/identifiers.rs":"22937fc099812dd9282c20c77ad3797cfa13a8838a0c68638bc4fc32178afbc8","src/display/items.rs":"0e24b30a35c079b8661c2fb5f957b0fc5932b5aef995495fa0c96b3a045f3650","src/display/render_trait.rs":"ccdcbe8e5a1771630dd61eb24b8e384fc30147c285bd40865f9ccc87ab4931b7","src/display/state.rs":"598f115023570bb6659a043d2410aef538364473031e53018bd78c247658d51b","src/display/stub.rs":"28e1ee74aefd8e491956f30e7c703778b68b62288e4763bb429313c5cbe5738e","src/display/ty.rs":"6673ac4c5e767b2afb35d133ff607cfba7f9bc9514ed6888b678ded09891d50c","src/display/utils.rs":"929d68b566265674e31a3fce6ffa0123fd6fc7b7c7323baf62aefd56ce67e085","src/ext.rs":"b71de835698b02434ffb67000d33bd82be53c3dadd41aee0056f0e4b31e102cd","src/goal_builder.rs":"1acef3990ec74d515200c2f42045028496f1799352d945481505ca00698d9838","src/infer.rs":"b5a533153d2a3ae342892b250d0eac0dcd87a26a38626a3753f326d3ce93966e","src/infer/canonicalize.rs":"85de8d18c62b151587a8df45af65b105faa20a14c033ca38d5b20965614ac515","src/infer/instantiate.rs":"0b43c5b86afae964298cc33b11d89b81feb8094074aa71ebcbbfa218c6a11a86","src/infer/invert.rs":"18ff374ff9ac9735ecedd66b3afa8dfa3531867d2b578eb011fdd97d56e150c1","src/infer/test.rs":"b3e69f1110aca3e6d261e01d2da7b7159b08e3e6345375f55bedaf3ae4c995aa","src/infer/ucanonicalize.rs":"f53f9b113921e122646d90075c0c518c48b3e6483b2bce72e3edc22083fcf957","src/infer/unify.rs":"fb17f98014d56618d5ea3ff0b491387c986266a1b80fe3bf906135f1b859a6a3","src/infer/var.rs":"35f88c269fbe1c7da572d9b21a64a1bed80036c563d91f7c71a639c51cac9801","src/lib.rs":"35517aa1e7b3ddaad9d52babedb497f5d068c48ce44ee768d2db171a7f3ed08e","src/logging.rs":"a3e3fa6bb03f29db9f87aedfa6051d4ad649c2aa2be292d03260d64c9bb8c5e2","src/logging_db.rs":"6d153fcf823a19680ab015286ad3d6e2ab47e1f6b39262f77271e664f8acef27","src/logging_db/id_collector.rs":"1f793e32ddb4b4562f139a63e9888a3320291209e91370ec7475b37a6dd396e2","src/recursive/lib.rs":"24f1dd3310eae203607835f063de7b8ed0fc75dee934428ad08abedb6c3e8704","src/rust_ir.rs":"f122a9c96aaa17f02739fb7443b3ffc38fcdd2c1b2a08b39cf3184011d43a403","src/solve.rs":"aa4d20a73dce06a0a5bb0459f4b2bdd80fd842d7a193f65ca48878ed915c6dd3","src/solve/test/bench.rs":"8da8bb948bdf598ed7f225fd695b12c9e8626cd7a14d4b7d8650de0fae73d655","src/solve/truncate.rs":"f77bacc0545b4f6af841fd4707185bb79bac768eabb44a9bdc9514b9f19800d0","src/split.rs":"f01ead861bc2abf79b08a67c7d620e8794f73db833ec516b5115602aa9d07d1c","src/wf.rs":"546fa2af849cd8afa480896c6e52816e96e2705b3d10628388eedfded1a6ddd0"},"package":"802de4eff72e5a5d2828e6c07224c74d66949dc6308aff025d0ae2871a11b4eb"} \ No newline at end of file +{"files":{"Cargo.toml":"57a5e65f384e3d148e718d77af88bab9e1d3a9f4f3b86cef7df6c43cf6234ea9","README.md":"2de2da988dbbaa8feb78b0a771b7bee942f34705ab057c824b1183300c535c74","src/clauses.rs":"b621b0b8f9f7411519fa9c8107af3d27c59d4042015259e6190d71259d6589f0","src/clauses/builder.rs":"ea0e37237addb834d3b274d316fae270dcbd418fc89d3c6cebf09e31fe346634","src/clauses/builtin_traits.rs":"0b401afe5f1a90d08d7decf4d1a5ae63caa279c2a5c91af2c8c6446cfb137ade","src/clauses/builtin_traits/clone.rs":"963a3a192aa8283733d3bc2c0a5e7cf0debcf47986df85a25eef3e3c647de257","src/clauses/builtin_traits/copy.rs":"edeb7565820075cb03ca452b41e6bce61ed6cd0f290ed92953f863435ce19afb","src/clauses/builtin_traits/fn_family.rs":"b96a30c3245228c20a1ceca237b3d1b3fb18a6eee0338876a6e488b06d186f19","src/clauses/builtin_traits/sized.rs":"837c85f520aa51b712b07c14f5f5d31929e76e347de54d9d2b8d27f7186cc92b","src/clauses/builtin_traits/unsize.rs":"9ac311cc905d068f5626204cdacadfe8b3e9c126fb821c8cbd054f7fd21165d2","src/clauses/dyn_ty.rs":"7c32ccd5a3bc7479b0e34ca2d3da254edcc7f73e38ace9f1860c5f64bb8def8a","src/clauses/env_elaborator.rs":"bd598d47075b7c5366c9db55d99b1426c7ea646bd2508c7674bcc52d918bdf76","src/clauses/generalize.rs":"c44f8e559a12f67ad55cff2dd3ffb39d9333cf39a7c8b78c6a8fe87e764c2f98","src/clauses/program_clauses.rs":"4ff101e17087299b3e431796dbb2fe8950b2bb3f2f4b2e7b4464bd3698656d41","src/coherence.rs":"665658b1dda7d5a37e9183a6ff176048c5b1001d23766b3b97288cdf8f3a94cc","src/coherence/orphan.rs":"621a839058309f1977e9eea972afa1622a372e06889d8d20aff64788cfba1829","src/coherence/solve.rs":"76c8ab111b8946aeb014563e13bf6f30a3bdf15c1fda63276f1711becbcf187b","src/coinductive_goal.rs":"7a2179fb2d61435cf55c5c87301db6c15edb3cb46750bea381451649b2f1051d","src/display.rs":"c5c0a796b6037dea1cf18dcb063f0ccd3bd82012b480231f4e15d2186bb9a9f8","src/display/bounds.rs":"47b402d34c9a0cb7d4f4f35b40d86f983b6a335c9dfae95645eaa472404b6098","src/display/identifiers.rs":"22937fc099812dd9282c20c77ad3797cfa13a8838a0c68638bc4fc32178afbc8","src/display/items.rs":"8aeb2923137d3bc1efe2cee0b93f2a97fa112d43438fa261963f8760f8ca4cfc","src/display/render_trait.rs":"ccdcbe8e5a1771630dd61eb24b8e384fc30147c285bd40865f9ccc87ab4931b7","src/display/state.rs":"598f115023570bb6659a043d2410aef538364473031e53018bd78c247658d51b","src/display/stub.rs":"d95da21650ace65b11f4ceb4583364d3114a39657ba37c97e5b93c4ed5a2913b","src/display/ty.rs":"26e23e3876d91554b6672f8b779b0342e2b221ba195c6a65d2a87f2aa061f504","src/display/utils.rs":"929d68b566265674e31a3fce6ffa0123fd6fc7b7c7323baf62aefd56ce67e085","src/ext.rs":"b71de835698b02434ffb67000d33bd82be53c3dadd41aee0056f0e4b31e102cd","src/goal_builder.rs":"1acef3990ec74d515200c2f42045028496f1799352d945481505ca00698d9838","src/infer.rs":"b5a533153d2a3ae342892b250d0eac0dcd87a26a38626a3753f326d3ce93966e","src/infer/canonicalize.rs":"85de8d18c62b151587a8df45af65b105faa20a14c033ca38d5b20965614ac515","src/infer/instantiate.rs":"0b43c5b86afae964298cc33b11d89b81feb8094074aa71ebcbbfa218c6a11a86","src/infer/invert.rs":"18ff374ff9ac9735ecedd66b3afa8dfa3531867d2b578eb011fdd97d56e150c1","src/infer/test.rs":"b3e69f1110aca3e6d261e01d2da7b7159b08e3e6345375f55bedaf3ae4c995aa","src/infer/ucanonicalize.rs":"f53f9b113921e122646d90075c0c518c48b3e6483b2bce72e3edc22083fcf957","src/infer/unify.rs":"fa64bc2a04978c0598d1fae74a77ed11325904e69b0785cb38d7acce47d7a794","src/infer/var.rs":"35f88c269fbe1c7da572d9b21a64a1bed80036c563d91f7c71a639c51cac9801","src/lib.rs":"9c70de2446236e71269cfca5b0cbf26e28765ceede71e460a56b2f891865c039","src/logging.rs":"a3e3fa6bb03f29db9f87aedfa6051d4ad649c2aa2be292d03260d64c9bb8c5e2","src/logging_db.rs":"a5c4bc36b4d242871ff6cd9b1550eadd627e29af7364d50f45892301d8d4f4cb","src/logging_db/id_collector.rs":"1f793e32ddb4b4562f139a63e9888a3320291209e91370ec7475b37a6dd396e2","src/recursive/lib.rs":"24f1dd3310eae203607835f063de7b8ed0fc75dee934428ad08abedb6c3e8704","src/rust_ir.rs":"5a1d30410997f6514af21e0311c4ad0d55e15f073aa75b25811ae9ebe6cd29b2","src/solve.rs":"487802e88356bae4f2b334dc9e4347f2f7574b0f888ea3524554998d9c956e96","src/solve/test/bench.rs":"8da8bb948bdf598ed7f225fd695b12c9e8626cd7a14d4b7d8650de0fae73d655","src/solve/truncate.rs":"f77bacc0545b4f6af841fd4707185bb79bac768eabb44a9bdc9514b9f19800d0","src/split.rs":"f01ead861bc2abf79b08a67c7d620e8794f73db833ec516b5115602aa9d07d1c","src/wf.rs":"77f688b8812e04bf90484fd9f7bd318611a0d7f4eb0c6016c78946c9e3b0b69e"},"package":"828c1f80d4eaf681027cce02050c54a3c97370f81988d31bf2a56df54048746c"} \ No newline at end of file diff --git a/vendor/chalk-solve/Cargo.toml b/vendor/chalk-solve/Cargo.toml index de0d4f5146..ef19ea8b01 100644 --- a/vendor/chalk-solve/Cargo.toml +++ b/vendor/chalk-solve/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-solve" -version = "0.23.0" +version = "0.29.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Combines the chalk-engine with chalk-ir" readme = "README.md" @@ -21,10 +21,10 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.23.0" +version = "=0.29.0" [dependencies.chalk-ir] -version = "=0.23.0" +version = "=0.29.0" [dependencies.ena] version = "0.14.0" diff --git a/vendor/chalk-solve/src/clauses.rs b/vendor/chalk-solve/src/clauses.rs index db54807664..ebea5efaf1 100644 --- a/vendor/chalk-solve/src/clauses.rs +++ b/vendor/chalk-solve/src/clauses.rs @@ -18,6 +18,49 @@ mod env_elaborator; mod generalize; pub mod program_clauses; +// yields the types "contained" in `app_ty` +fn constituent_types( + db: &dyn RustIrDatabase, + app_ty: &ApplicationTy, +) -> Vec> { + let interner = db.interner(); + + match app_ty.name { + // For non-phantom_data adts we collect its variants/fields + TypeName::Adt(adt_id) if !db.adt_datum(adt_id).flags.phantom_data => { + let adt_datum = &db.adt_datum(adt_id); + let adt_datum_bound = adt_datum.binders.substitute(interner, &app_ty.substitution); + adt_datum_bound + .variants + .into_iter() + .flat_map(|variant| variant.fields.into_iter()) + .collect() + } + // And for `PhantomData`, we pass `T`. + TypeName::Adt(_) + | TypeName::Array + | TypeName::Tuple(_) + | TypeName::Slice + | TypeName::Raw(_) + | TypeName::Ref(_) + | TypeName::Scalar(_) + | TypeName::Str + | TypeName::Never + | TypeName::FnDef(_) => app_ty + .substitution + .iter(interner) + .filter_map(|x| x.ty(interner)) + .cloned() + .collect(), + + TypeName::Closure(_) => panic!("this function should not be called for closures"), + TypeName::Foreign(_) => panic!("constituent_types of foreign types are unknown!"), + TypeName::Error => Vec::new(), + TypeName::OpaqueType(_) => unimplemented!(), + TypeName::AssociatedType(_) => unimplemented!(), + } +} + /// FIXME(#505) update comments for ADTs /// For auto-traits, we generate a default rule for every struct, /// unless there is a manual impl for that struct given explicitly. @@ -53,9 +96,8 @@ pub mod program_clauses; pub fn push_auto_trait_impls( builder: &mut ClauseBuilder<'_, I>, auto_trait_id: TraitId, - adt_id: AdtId, + app_ty: &ApplicationTy, ) { - let adt_datum = &builder.db.adt_datum(adt_id); let interner = builder.interner(); // Must be an auto trait. @@ -67,44 +109,48 @@ pub fn push_auto_trait_impls( 1 ); + // we assume that the builder has no binders so far. + assert!(builder.placeholders_in_scope().is_empty()); + // If there is a `impl AutoTrait for Foo<..>` or `impl !AutoTrait // for Foo<..>`, where `Foo` is the adt we're looking at, then // we don't generate our own rules. - if builder.db.impl_provided_for(auto_trait_id, adt_id) { + if builder.db.impl_provided_for(auto_trait_id, app_ty) { debug!("impl provided"); return; } - let binders = adt_datum.binders.map_ref(|b| &b.variants); - builder.push_binders(&binders, |builder, variants| { - let self_ty: Ty<_> = ApplicationTy { - name: adt_id.cast(interner), - substitution: builder.substitution_in_scope(), + let mk_ref = |ty: Ty| TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, ty.cast(interner)), + }; + + let consequence = mk_ref(app_ty.clone().intern(interner)); + + match app_ty.name { + // auto traits are not implemented for foreign types + TypeName::Foreign(_) => return, + + // closures require binders, while the other types do not + TypeName::Closure(closure_id) => { + let binders = builder + .db + .closure_upvars(closure_id, &Substitution::empty(interner)); + builder.push_binders(&binders, |builder, upvar_ty| { + let conditions = iter::once(mk_ref(upvar_ty)); + builder.push_clause(consequence, conditions); + }); } - .intern(interner); - // trait_ref = `MyStruct<...>: MyAutoTrait` - let auto_trait_ref = TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, self_ty), - }; + // app_ty implements AutoTrait if all constituents of app_ty implement AutoTrait + _ => { + let conditions = constituent_types(builder.db, app_ty) + .into_iter() + .map(mk_ref); - // forall { // generic parameters from struct - // MyStruct<...>: MyAutoTrait :- - // Field0: MyAutoTrait, - // ... - // FieldN: MyAutoTrait - // } - builder.push_clause( - auto_trait_ref, - variants.iter().flat_map(|variant| { - variant.fields.iter().map(|field_ty| TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, field_ty.clone()), - }) - }), - ); - }); + builder.push_clause(consequence, conditions); + } + } } /// Leak auto traits for opaque types, just like `push_auto_trait_impls` does for structs. @@ -253,13 +299,20 @@ fn program_clauses_that_could_match( // the automatic impls for `Foo`. let trait_datum = db.trait_datum(trait_id); if trait_datum.is_auto_trait() { - match trait_ref.self_type_parameter(interner).data(interner) { - TyData::Apply(apply) => match &apply.name { - TypeName::Adt(adt_id) => { - push_auto_trait_impls(builder, trait_id, *adt_id); - } - _ => {} - }, + let ty = trait_ref.self_type_parameter(interner); + match ty.data(interner) { + TyData::Apply(apply) => { + push_auto_trait_impls(builder, trait_id, apply); + } + // function-types implement auto traits unconditionally + TyData::Function(_) => { + let auto_trait_ref = TraitRef { + trait_id, + substitution: Substitution::from1(interner, ty.cast(interner)), + }; + + builder.push_fact(auto_trait_ref); + } TyData::InferenceVar(_, _) | TyData::BoundVar(_) => { return Err(Floundered); } @@ -635,7 +688,8 @@ fn match_type_name( | TypeName::Ref(_) | TypeName::Array | TypeName::Never - | TypeName::Closure(_) => { + | TypeName::Closure(_) + | TypeName::Foreign(_) => { builder.push_fact(WellFormed::Ty(application.clone().intern(interner))) } } diff --git a/vendor/chalk-solve/src/clauses/builtin_traits.rs b/vendor/chalk-solve/src/clauses/builtin_traits.rs index d21a4b602b..6a4eed3759 100644 --- a/vendor/chalk-solve/src/clauses/builtin_traits.rs +++ b/vendor/chalk-solve/src/clauses/builtin_traits.rs @@ -41,8 +41,8 @@ pub fn add_builtin_program_clauses( WellKnownTrait::Unsize => { unsize::add_unsize_program_clauses(db, builder, &trait_ref, ty) } - // Drop impls are provided explicitly - WellKnownTrait::Drop => (), + // There are no builtin impls provided for the following traits: + WellKnownTrait::Unpin | WellKnownTrait::Drop | WellKnownTrait::CoerceUnsized => (), } Ok(()) }) diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs b/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs index 5fd9c1a17a..d8528da8f2 100644 --- a/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs +++ b/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs @@ -75,6 +75,7 @@ pub fn add_copy_program_clauses( | TypeName::AssociatedType(_) | TypeName::Slice | TypeName::OpaqueType(_) + | TypeName::Foreign(_) | TypeName::Error => {} }, diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs b/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs index 2012367b68..9178f80a6a 100644 --- a/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs +++ b/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs @@ -99,7 +99,7 @@ pub fn add_fn_trait_program_clauses( TyData::Apply(apply) => match apply.name { TypeName::FnDef(fn_def_id) => { let fn_def_datum = builder.db.fn_def_datum(fn_def_id); - if fn_def_datum.safety == Safety::Safe && !fn_def_datum.variadic { + if fn_def_datum.sig.safety == Safety::Safe && !fn_def_datum.sig.variadic { let bound = fn_def_datum .binders .substitute(builder.interner(), &apply.substitution); @@ -140,7 +140,7 @@ pub fn add_fn_trait_program_clauses( } _ => Ok(()), }, - TyData::Function(fn_val) if fn_val.safety == Safety::Safe && !fn_val.variadic => { + TyData::Function(fn_val) if fn_val.sig.safety == Safety::Safe && !fn_val.sig.variadic => { let (binders, orig_sub) = fn_val.into_binders_and_value(interner); let bound_ref = Binders::new(VariableKinds::from_iter(interner, binders), orig_sub); builder.push_binders(&bound_ref, |builder, orig_sub| { diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs b/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs index 786c705a29..b256a4bf82 100644 --- a/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs +++ b/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs @@ -93,6 +93,7 @@ pub fn add_sized_program_clauses( | TypeName::Slice | TypeName::OpaqueType(_) | TypeName::Str + | TypeName::Foreign(_) | TypeName::Error => {} }, diff --git a/vendor/chalk-solve/src/coherence/solve.rs b/vendor/chalk-solve/src/coherence/solve.rs index 98081ce9b8..25fb25344d 100644 --- a/vendor/chalk-solve/src/coherence/solve.rs +++ b/vendor/chalk-solve/src/coherence/solve.rs @@ -251,10 +251,7 @@ impl CoherenceSolver<'_, I> { let canonical_goal = &goal.into_closed_goal(interner); let mut fresh_solver = (self.solver_builder)(); - let result = match fresh_solver.solve(self.db, canonical_goal) { - Some(sol) => sol.is_unique(), - None => false, - }; + let result = fresh_solver.has_unique_solution(self.db, canonical_goal); debug!("specializes: result = {:?}", result); diff --git a/vendor/chalk-solve/src/display/items.rs b/vendor/chalk-solve/src/display/items.rs index 13da1a01b2..62a2154d65 100644 --- a/vendor/chalk-solve/src/display/items.rs +++ b/vendor/chalk-solve/src/display/items.rs @@ -193,6 +193,8 @@ impl RenderAsRust for TraitDatum { WellKnownTrait::FnMut => "fn_mut", WellKnownTrait::Fn => "fn", WellKnownTrait::Unsize => "unsize", + WellKnownTrait::Unpin => "unpin", + WellKnownTrait::CoerceUnsized => "coerce_unsized", }; writeln!(f, "#[lang({})]", name)?; } diff --git a/vendor/chalk-solve/src/display/stub.rs b/vendor/chalk-solve/src/display/stub.rs index 2c433578c2..2ad5791d49 100644 --- a/vendor/chalk-solve/src/display/stub.rs +++ b/vendor/chalk-solve/src/display/stub.rs @@ -156,7 +156,7 @@ impl> RustIrDatabase for StubWrapper<'_, D fn impl_provided_for( &self, _auto_trait_id: chalk_ir::TraitId, - _adt_id: chalk_ir::AdtId, + _app_ty: &chalk_ir::ApplicationTy, ) -> bool { // We panic here because the returned ids may not be collected, // resulting in unresolvable names. diff --git a/vendor/chalk-solve/src/display/ty.rs b/vendor/chalk-solve/src/display/ty.rs index 6792703096..8454cd15b6 100644 --- a/vendor/chalk-solve/src/display/ty.rs +++ b/vendor/chalk-solve/src/display/ty.rs @@ -217,6 +217,7 @@ impl RenderAsRust for ApplicationTy { // FIXME: write out valid types for these variants TypeName::FnDef(_) => write!(f, "")?, TypeName::Closure(..) => write!(f, "")?, + TypeName::Foreign(_) => write!(f, "")?, TypeName::Array => write!( f, diff --git a/vendor/chalk-solve/src/infer/unify.rs b/vendor/chalk-solve/src/infer/unify.rs index 57b76d5b55..46648c5ac8 100644 --- a/vendor/chalk-solve/src/infer/unify.rs +++ b/vendor/chalk-solve/src/infer/unify.rs @@ -129,7 +129,7 @@ impl<'t, I: Interner> Unifier<'t, I> { // Unifying `forall { T }` with some other forall type `forall { U }` (&TyData::Function(ref fn1), &TyData::Function(ref fn2)) => { - if fn1.abi == fn2.abi && fn1.safety == fn2.safety && fn1.variadic == fn2.variadic { + if fn1.sig == fn2.sig { self.unify_binders(fn1, fn2) } else { Err(NoSolution) @@ -455,11 +455,23 @@ impl<'t, I: Interner> Unifier<'t, I> { let interner = self.interner; let var = EnaVariable::from(var); + // Determine the universe index associated with this + // variable. This is basically a count of the number of + // `forall` binders that had been introduced at the point + // this variable was created -- though it may change over time + // as the variable is unified. + let universe_index = self.table.universe_of_unbound_var(var); + + let c1 = c.fold_with( + &mut OccursCheck::new(self, var, universe_index), + DebruijnIndex::INNERMOST, + )?; + + debug!("unify_var_const: var {:?} set to {:?}", var, c1); self.table .unify - .unify_var_value(var, InferenceValue::from_const(interner, c.clone())) + .unify_var_value(var, InferenceValue::from_const(interner, c1)) .unwrap(); - debug!("unify_var_const: var {:?} set to {:?}", var, c); Ok(()) } @@ -557,6 +569,20 @@ where } } + fn fold_free_placeholder_const( + &mut self, + ty: &Ty, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Fallible> { + let interner = self.interner(); + if self.universe_index < universe.ui { + Err(NoSolution) + } else { + Ok(universe.to_const(interner, ty.clone())) // no need to shift, not relative to depth + } + } + #[instrument(level = "debug", skip(self))] fn fold_free_placeholder_lifetime( &mut self, @@ -633,6 +659,51 @@ where } } + fn fold_inference_const( + &mut self, + ty: &Ty, + var: InferenceVar, + _outer_binder: DebruijnIndex, + ) -> Fallible> { + let interner = self.interner(); + let var = EnaVariable::from(var); + match self.unifier.table.unify.probe_value(var) { + // If this variable already has a value, fold over that value instead. + InferenceValue::Bound(normalized_const) => { + let normalized_const = normalized_const.assert_const_ref(interner); + let normalized_const = + normalized_const.fold_with(self, DebruijnIndex::INNERMOST)?; + assert!(!normalized_const.needs_shift(interner)); + Ok(normalized_const) + } + + // Otherwise, check the universe of the variable, and also + // check for cycles with `self.var` (which this will soon + // become the value of). + InferenceValue::Unbound(ui) => { + if self.unifier.table.unify.unioned(var, self.var) { + return Err(NoSolution); + } + + if self.universe_index < ui { + // Scenario is like: + // + // forall exists ?C = Foo + // + // where A is in universe 0 and B is in universe 1. + // This is OK, if B is promoted to universe 0. + self.unifier + .table + .unify + .unify_var_value(var, InferenceValue::Unbound(self.universe_index)) + .unwrap(); + } + + Ok(var.to_const(interner, ty.clone())) + } + } + } + fn fold_inference_lifetime( &mut self, var: InferenceVar, diff --git a/vendor/chalk-solve/src/lib.rs b/vendor/chalk-solve/src/lib.rs index 0c6d300959..583595e11c 100644 --- a/vendor/chalk-solve/src/lib.rs +++ b/vendor/chalk-solve/src/lib.rs @@ -101,12 +101,11 @@ pub trait RustIrDatabase: Debug { fn local_impls_to_coherence_check(&self, trait_id: TraitId) -> Vec>; /// Returns true if there is an explicit impl of the auto trait - /// `auto_trait_id` for the ADT `adt_id`. This is part of + /// `auto_trait_id` for the type `app_ty`. This is part of /// the auto trait handling -- if there is no explicit impl given - /// by the user for the struct, then we provide default impls - /// based on the field types (otherwise, we rely on the impls the - /// user gave). - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool; + /// by the user for `app_ty`, then we provide default impls + /// (otherwise, we rely on the impls the user gave). + fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool; /// Returns id of a trait lang item, if found fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option>; diff --git a/vendor/chalk-solve/src/logging_db.rs b/vendor/chalk-solve/src/logging_db.rs index 52279110db..3681e8c280 100644 --- a/vendor/chalk-solve/src/logging_db.rs +++ b/vendor/chalk-solve/src/logging_db.rs @@ -166,10 +166,12 @@ where self.ws.db().local_impls_to_coherence_check(trait_id) } - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { + fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool { self.record(auto_trait_id); - self.record(adt_id); - self.ws.db().impl_provided_for(auto_trait_id, adt_id) + if let TypeName::Adt(adt_id) = app_ty.name { + self.record(adt_id); + } + self.ws.db().impl_provided_for(auto_trait_id, app_ty) } fn well_known_trait_id( @@ -379,8 +381,8 @@ where self.db.local_impls_to_coherence_check(trait_id) } - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { - self.db.impl_provided_for(auto_trait_id, adt_id) + fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool { + self.db.impl_provided_for(auto_trait_id, app_ty) } fn well_known_trait_id( diff --git a/vendor/chalk-solve/src/rust_ir.rs b/vendor/chalk-solve/src/rust_ir.rs index 74fdd85b4d..3dabc05f2f 100644 --- a/vendor/chalk-solve/src/rust_ir.rs +++ b/vendor/chalk-solve/src/rust_ir.rs @@ -9,8 +9,8 @@ use chalk_ir::interner::{Interner, TargetInterner}; use chalk_ir::{ visit::{Visit, VisitResult}, AdtId, AliasEq, AliasTy, AssocTypeId, Binders, DebruijnIndex, FnDefId, GenericArg, ImplId, - OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Safety, Substitution, ToGenericArg, TraitId, - TraitRef, Ty, TyData, TypeName, VariableKind, WhereClause, WithKind, + OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Substitution, ToGenericArg, TraitId, TraitRef, + Ty, TyData, TypeName, VariableKind, WhereClause, WithKind, }; use std::iter; @@ -144,9 +144,7 @@ pub struct AdtRepr { /// a specific function definition. pub struct FnDefDatum { pub id: FnDefId, - pub abi: I::FnAbi, - pub safety: Safety, - pub variadic: bool, + pub sig: chalk_ir::FnSig, pub binders: Binders>, } @@ -271,6 +269,8 @@ pub enum WellKnownTrait { FnMut, Fn, Unsize, + Unpin, + CoerceUnsized, } chalk_ir::const_visit!(WellKnownTrait); diff --git a/vendor/chalk-solve/src/solve.rs b/vendor/chalk-solve/src/solve.rs index dc74045acd..8d0315219d 100644 --- a/vendor/chalk-solve/src/solve.rs +++ b/vendor/chalk-solve/src/solve.rs @@ -203,4 +203,17 @@ where goal: &UCanonical>>, f: &mut dyn FnMut(SubstitutionResult>>, bool) -> bool, ) -> bool; + + /// A convenience method for when one doesn't need the actual solution, + /// only whether or not one exists. + fn has_unique_solution( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + ) -> bool { + match self.solve(program, goal) { + Some(sol) => sol.is_unique(), + None => false, + } + } } diff --git a/vendor/chalk-solve/src/wf.rs b/vendor/chalk-solve/src/wf.rs index 03c60e66da..be09a9050f 100644 --- a/vendor/chalk-solve/src/wf.rs +++ b/vendor/chalk-solve/src/wf.rs @@ -1,21 +1,21 @@ use std::{fmt, iter}; -use crate::ext::*; -use crate::goal_builder::GoalBuilder; -use crate::rust_ir::*; -use crate::solve::Solver; -use crate::split::Split; -use crate::RustIrDatabase; -use chalk_ir::cast::*; -use chalk_ir::fold::shift::Shift; -use chalk_ir::interner::Interner; -use chalk_ir::visit::{Visit, Visitor}; -use chalk_ir::*; +use crate::{ + ext::*, goal_builder::GoalBuilder, rust_ir::*, solve::Solver, split::Split, RustIrDatabase, +}; +use chalk_ir::{ + cast::*, + fold::shift::Shift, + interner::Interner, + visit::{Visit, Visitor}, + *, +}; use tracing::debug; #[derive(Debug)] pub enum WfError { IllFormedTypeDecl(chalk_ir::AdtId), + IllFormedOpaqueTypeDecl(chalk_ir::OpaqueTyId), IllFormedTraitImpl(chalk_ir::TraitId), } @@ -27,6 +27,11 @@ impl fmt::Display for WfError { "type declaration `{:?}` does not meet well-formedness requirements", id ), + WfError::IllFormedOpaqueTypeDecl(id) => write!( + f, + "opaque type declaration `{:?}` does not meet well-formedness requirements", + id + ), WfError::IllFormedTraitImpl(id) => write!( f, "trait impl for `{:?}` does not meet well-formedness requirements", @@ -193,7 +198,7 @@ where // each variant are sized. For `structs`, we relax this requirement to // all but the last field. let sized_constraint_goal = - WfWellKnownGoals::struct_sized_constraint( + WfWellKnownConstraints::struct_sized_constraint( gb.db(), fields, is_enum, @@ -220,10 +225,7 @@ where let wg_goal = wg_goal.into_closed_goal(interner); let mut fresh_solver = (self.solver_builder)(); - let is_legal = match fresh_solver.solve(self.db, &wg_goal) { - Some(sol) => sol.is_unique(), - None => false, - }; + let is_legal = fresh_solver.has_unique_solution(self.db, &wg_goal); if !is_legal { Err(WfError::IllFormedTypeDecl(adt_id)) @@ -248,13 +250,15 @@ where ), ); + if let Some(well_known) = self.db.trait_datum(trait_id).well_known { + self.verify_well_known_impl(impl_id, well_known)? + } + debug!("WF trait goal: {:?}", impl_goal); let mut fresh_solver = (self.solver_builder)(); - let is_legal = match fresh_solver.solve(self.db, &impl_goal.into_closed_goal(interner)) { - Some(sol) => sol.is_unique(), - None => false, - }; + let is_legal = + fresh_solver.has_unique_solution(self.db, &impl_goal.into_closed_goal(interner)); if is_legal { Ok(()) @@ -262,6 +266,99 @@ where Err(WfError::IllFormedTraitImpl(trait_id)) } } + + pub fn verify_opaque_ty_decl(&self, opaque_ty_id: OpaqueTyId) -> Result<(), WfError> { + // Given an opaque type like + // ```notrust + // opaque type Foo: Clone where T: Bar = Baz; + // ``` + let interner = self.db.interner(); + + let mut gb = GoalBuilder::new(self.db); + + let datum = self.db.opaque_ty_data(opaque_ty_id); + let bound = &datum.bound; + + // We make a goal like + // + // forall + let goal = gb.forall(&bound, opaque_ty_id, |gb, _, bound, opaque_ty_id| { + let interner = gb.interner(); + + let subst = Substitution::from1(interner, gb.db().hidden_opaque_type(opaque_ty_id)); + + let bounds = bound.bounds.substitute(interner, &subst); + let where_clauses = bound.where_clauses.substitute(interner, &subst); + + let clauses = where_clauses + .iter() + .cloned() + .map(|wc| wc.into_from_env_goal(interner)); + + // if (WellFormed(T: Bar)) + gb.implies(clauses, |gb| { + let interner = gb.interner(); + + // all(WellFormed(Baz: Clone)) + gb.all( + bounds + .iter() + .cloned() + .map(|b| b.into_well_formed_goal(interner)), + ) + }) + }); + + debug!("WF opaque type goal: {:#?}", goal); + + let mut new_solver = (self.solver_builder)(); + let is_legal = new_solver.has_unique_solution(self.db, &goal.into_closed_goal(interner)); + + if is_legal { + Ok(()) + } else { + Err(WfError::IllFormedOpaqueTypeDecl(opaque_ty_id)) + } + } + + /// Verify builtin rules for well-known traits + pub fn verify_well_known_impl( + &self, + impl_id: ImplId, + well_known: WellKnownTrait, + ) -> Result<(), WfError> { + let mut solver = (self.solver_builder)(); + let impl_datum = self.db.impl_datum(impl_id); + + let is_legal = match well_known { + WellKnownTrait::Copy => { + WfWellKnownConstraints::copy_impl_constraint(&mut *solver, self.db, &impl_datum) + } + WellKnownTrait::Drop => { + WfWellKnownConstraints::drop_impl_constraint(&mut *solver, self.db, &impl_datum) + } + WellKnownTrait::CoerceUnsized => { + WfWellKnownConstraints::coerce_unsized_impl_constraint( + &mut *solver, + self.db, + &impl_datum, + ) + } + WellKnownTrait::Clone | WellKnownTrait::Unpin => true, + // You can't add a manual implementation for the following traits: + WellKnownTrait::Fn + | WellKnownTrait::FnOnce + | WellKnownTrait::FnMut + | WellKnownTrait::Unsize + | WellKnownTrait::Sized => false, + }; + + if is_legal { + Ok(()) + } else { + Err(WfError::IllFormedTraitImpl(impl_datum.trait_id())) + } + } } fn impl_header_wf_goal( @@ -283,8 +380,6 @@ fn impl_header_wf_goal( let well_formed_goal = gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| { let interner = gb.interner(); - let trait_constraint_goal = WfWellKnownGoals::inside_impl(gb.db(), &trait_ref); - // if (WC && input types are well formed) { ... } gb.implies( impl_wf_environment(interner, &where_clauses, &trait_ref), @@ -305,20 +400,14 @@ fn impl_header_wf_goal( let goals = types .into_iter() .map(|ty| ty.well_formed().cast(interner)) - .chain(Some((*trait_ref).clone().well_formed().cast(interner))) - .chain(trait_constraint_goal.into_iter()); + .chain(Some((*trait_ref).clone().well_formed().cast(interner))); gb.all::<_, Goal>(goals) }, ) }); - Some( - gb.all( - iter::once(well_formed_goal) - .chain(WfWellKnownGoals::outside_impl(db, &impl_datum).into_iter()), - ), - ) + Some(well_formed_goal) } /// Creates the conditions that an impl (and its contents of an impl) @@ -482,48 +571,9 @@ fn compute_assoc_ty_goal( /// Defines methods to compute well-formedness goals for well-known /// traits (e.g. a goal for all fields of struct in a Copy impl to be Copy) -struct WfWellKnownGoals {} - -impl WfWellKnownGoals { - /// A convenience method to compute the goal assuming `trait_ref` - /// well-formedness requirements are in the environment. - pub fn inside_impl( - db: &dyn RustIrDatabase, - trait_ref: &TraitRef, - ) -> Option> { - match db.trait_datum(trait_ref.trait_id).well_known? { - WellKnownTrait::Copy => Self::copy_impl_constraint(db, trait_ref), - WellKnownTrait::Drop - | WellKnownTrait::Clone - | WellKnownTrait::Sized - | WellKnownTrait::FnOnce - | WellKnownTrait::FnMut - | WellKnownTrait::Fn - | WellKnownTrait::Unsize => None, - } - } - - /// Computes well-formedness goals without any assumptions about the environment. - /// Note that `outside_impl` does not call `inside_impl`, one needs to call both - /// in order to get the full set of goals to be proven. - pub fn outside_impl( - db: &dyn RustIrDatabase, - impl_datum: &ImplDatum, - ) -> Option> { - let interner = db.interner(); - - match db.trait_datum(impl_datum.trait_id()).well_known? { - WellKnownTrait::Drop => Self::drop_impl_constraint(db, impl_datum), - WellKnownTrait::Copy | WellKnownTrait::Clone => None, - // You can't add a manual implementation for following traits: - WellKnownTrait::Sized - | WellKnownTrait::FnOnce - | WellKnownTrait::FnMut - | WellKnownTrait::Fn - | WellKnownTrait::Unsize => Some(GoalData::CannotProve.intern(interner)), - } - } +struct WfWellKnownConstraints; +impl WfWellKnownConstraints { /// Computes a goal to prove Sized constraints on a struct definition. /// Struct is considered well-formed (in terms of Sized) when it either /// has no fields or all of it's fields except the last are proven to be Sized. @@ -554,71 +604,108 @@ impl WfWellKnownGoals { )) } - /// Computes a goal to prove constraints on a Copy implementation. + /// Verify constraints on a Copy implementation. /// Copy impl is considered well-formed for /// a) certain builtin types (scalar values, shared ref, etc..) /// b) adts which /// 1) have all Copy fields /// 2) don't have a Drop impl fn copy_impl_constraint( + solver: &mut dyn Solver, db: &dyn RustIrDatabase, - trait_ref: &TraitRef, - ) -> Option> { + impl_datum: &ImplDatum, + ) -> bool { let interner = db.interner(); - let ty = trait_ref.self_type_parameter(interner); - let ty_data = ty.data(interner); + let mut gb = GoalBuilder::new(db); + + let impl_fields = impl_datum + .binders + .map_ref(|v| (&v.trait_ref, &v.where_clauses)); // Implementations for scalars, pointer types and never type are provided by libcore. // User implementations on types other than ADTs are forbidden. - let (adt_id, substitution) = match ty_data { - TyData::Apply(ApplicationTy { name, substitution }) => match name { + match impl_datum + .binders + .skip_binders() + .trait_ref + .self_type_parameter(interner) + .data(interner) + { + TyData::Apply(ApplicationTy { name, .. }) => match name { TypeName::Scalar(_) | TypeName::Raw(_) | TypeName::Ref(Mutability::Not) - | TypeName::Never => return None, - TypeName::Adt(adt_id) => (*adt_id, substitution), - _ => return Some(GoalData::CannotProve.intern(interner)), + | TypeName::Never => return true, + TypeName::Adt(_) => (), + _ => return false, }, - _ => return Some(GoalData::CannotProve.intern(interner)), + _ => return false, }; - // not { Implemented(ImplSelfTy: Drop) } - let neg_drop_goal = db - .well_known_trait_id(WellKnownTrait::Drop) - .map(|drop_trait_id| { - TraitRef { - trait_id: drop_trait_id, - substitution: Substitution::from1(interner, ty.clone()), - } - .cast::>(interner) - .negate(interner) - }); + // Well fomedness goal for ADTs + let well_formed_goal = + gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| { + let interner = gb.interner(); - let adt_datum = db.adt_datum(adt_id); + let ty = trait_ref.self_type_parameter(interner); + let ty_data = ty.data(interner); - let goals = adt_datum - .binders - .map_ref(|b| &b.variants) - .substitute(interner, substitution) - .into_iter() - .flat_map(|v| { - v.fields.into_iter().map(|f| { - // Implemented(FieldTy: Copy) - TraitRef { - trait_id: trait_ref.trait_id, - substitution: Substitution::from1(interner, f), - } - .cast(interner) - }) - }) - .chain(neg_drop_goal.into_iter()); + let (adt_id, substitution) = match ty_data { + TyData::Apply(ApplicationTy { name, substitution }) => match name { + TypeName::Adt(adt_id) => (*adt_id, substitution), + _ => unreachable!(), + }, + + _ => unreachable!(), + }; + + // if (WC) { ... } + gb.implies( + impl_wf_environment(interner, &where_clauses, &trait_ref), + |gb| -> Goal { + let db = gb.db(); + + // not { Implemented(ImplSelfTy: Drop) } + let neg_drop_goal = + db.well_known_trait_id(WellKnownTrait::Drop) + .map(|drop_trait_id| { + TraitRef { + trait_id: drop_trait_id, + substitution: Substitution::from1(interner, ty.clone()), + } + .cast::>(interner) + .negate(interner) + }); + + let adt_datum = db.adt_datum(adt_id); + + let goals = adt_datum + .binders + .map_ref(|b| &b.variants) + .substitute(interner, substitution) + .into_iter() + .flat_map(|v| { + v.fields.into_iter().map(|f| { + // Implemented(FieldTy: Copy) + TraitRef { + trait_id: trait_ref.trait_id, + substitution: Substitution::from1(interner, f), + } + .cast(interner) + }) + }) + .chain(neg_drop_goal.into_iter()); + gb.all(goals) + }, + ) + }); - Some(Goal::all(interner, goals)) + solver.has_unique_solution(db, &well_formed_goal.into_closed_goal(interner)) } - /// Computes goal to prove constraints on a Drop implementation + /// Verifies constraints on a Drop implementation /// Drop implementation is considered well-formed if: /// a) it's implemented on an ADT /// b) The generic parameters of the impl's type must all be parameters @@ -653,15 +740,16 @@ impl WfWellKnownGoals { /// } /// ``` fn drop_impl_constraint( + solver: &mut dyn Solver, db: &dyn RustIrDatabase, impl_datum: &ImplDatum, - ) -> Option> { + ) -> bool { let interner = db.interner(); let adt_id = match impl_datum.self_type_adt_id(interner) { Some(id) => id, // Drop can only be implemented on a nominal type - None => return Some(GoalData::CannotProve.intern(interner)), + None => return false, }; let mut gb = GoalBuilder::new(db); @@ -727,6 +815,189 @@ impl WfWellKnownGoals { }, ); - Some(gb.all([implied_by_adt_def_goal, eq_goal].iter())) + let well_formed_goal = gb.all([implied_by_adt_def_goal, eq_goal].iter()); + + solver.has_unique_solution(db, &well_formed_goal.into_closed_goal(interner)) + } + + /// Verify constraints a CoerceUnsized impl. + /// Rules for CoerceUnsized impl to be considered well-formed: + /// a) pointer conversions: &[mut] T -> &[mut] U, &[mut] T -> *[mut] U, + /// *[mut] T -> *[mut] U are considered valid if + /// 1) T: Unsize + /// 2) mutability is respected, i.e. immutable -> immutable, mutable -> immutable, + /// mutable -> mutable conversions are allowed, immutable -> mutable is not. + /// b) struct conversions of structures with the same definition, `S` -> `S`. + /// To check if this impl is legal, we would walk down the fields of `S` + /// and consider their types with both substitutes. We are looking to find + /// exactly one (non-phantom) field that has changed its type (from T to U), and + /// expect T to be unsizeable to U, i.e. T: CoerceUnsized. + /// + /// As an example, consider a struct + /// ```rust + /// struct Foo { + /// extra: T, + /// ptr: *mut U, + /// } + /// ``` + /// + /// We might have an impl that allows (e.g.) `Foo` to be unsized + /// to `Foo`. That impl would look like: + /// ```rust,ignore + /// impl, V> CoerceUnsized> for Foo {} + /// ``` + /// In this case: + /// + /// - `extra` has type `T` before and type `T` after + /// - `ptr` has type `*mut U` before and type `*mut V` after + /// + /// Since just one field changed, we would then check that `*mut U: CoerceUnsized<*mut V>` + /// is implemented. This will work out because `U: Unsize`, and we have a libcore rule + /// that `*mut U` can be coerced to `*mut V` if `U: Unsize`. + fn coerce_unsized_impl_constraint( + solver: &mut dyn Solver, + db: &dyn RustIrDatabase, + impl_datum: &ImplDatum, + ) -> bool { + let interner = db.interner(); + let mut gb = GoalBuilder::new(db); + + let (binders, impl_datum) = impl_datum.binders.as_ref().into(); + + let trait_ref: &TraitRef = &impl_datum.trait_ref; + + let source = trait_ref.self_type_parameter(interner); + let target = trait_ref + .substitution + .at(interner, 1) + .assert_ty_ref(interner) + .clone(); + + let mut place_in_environment = |goal| -> Goal { + gb.forall( + &Binders::new( + binders.clone(), + (goal, trait_ref, &impl_datum.where_clauses), + ), + (), + |gb, _, (goal, trait_ref, where_clauses), ()| { + let interner = gb.interner(); + gb.implies( + impl_wf_environment(interner, &where_clauses, &trait_ref), + |_| goal, + ) + }, + ) + }; + + match (source.data(interner), target.data(interner)) { + (TyData::Apply(source_app), TyData::Apply(target_app)) => { + match (&source_app.name, &target_app.name) { + (TypeName::Ref(s_m), TypeName::Ref(t_m)) + | (TypeName::Ref(s_m), TypeName::Raw(t_m)) + | (TypeName::Raw(s_m), TypeName::Raw(t_m)) => { + if (*s_m, *t_m) == (Mutability::Not, Mutability::Mut) { + return false; + } + + let source = source_app.first_type_parameter(interner).unwrap(); + let target = target_app.first_type_parameter(interner).unwrap(); + + let unsize_trait_id = + if let Some(id) = db.well_known_trait_id(WellKnownTrait::Unsize) { + id + } else { + return false; + }; + + // Source: Unsize + let unsize_goal: Goal = TraitRef { + trait_id: unsize_trait_id, + substitution: Substitution::from_iter( + interner, + [source, target].iter().cloned(), + ), + } + .cast(interner); + + // ImplEnv -> Source: Unsize + let unsize_goal = place_in_environment(unsize_goal); + + solver.has_unique_solution(db, &unsize_goal.into_closed_goal(interner)) + } + (TypeName::Adt(source_id), TypeName::Adt(target_id)) => { + let adt_datum = db.adt_datum(*source_id); + + if source_id != target_id || adt_datum.kind != AdtKind::Struct { + return false; + } + + let fields = adt_datum + .binders + .map_ref(|bound| &bound.variants.last().unwrap().fields); + + let (source_fields, target_fields) = ( + fields.substitute(interner, &source_app.substitution), + fields.substitute(interner, &target_app.substitution), + ); + + // collect fields with unequal ids + let uneq_field_ids: Vec = (0..source_fields.len()) + .filter(|&i| { + // ignore phantom data fields + if let Some(adt_id) = source_fields[i].adt_id(interner) { + if db.adt_datum(adt_id).flags.phantom_data { + return false; + } + } + + let eq_goal: Goal = EqGoal { + a: source_fields[i].clone().cast(interner), + b: target_fields[i].clone().cast(interner), + } + .cast(interner); + + // ImplEnv -> Source.fields[i] = Target.fields[i] + let eq_goal = place_in_environment(eq_goal); + + // We are interested in !UNEQUAL! fields + !solver.has_unique_solution(db, &eq_goal.into_closed_goal(interner)) + }) + .collect(); + + if uneq_field_ids.len() != 1 { + return false; + } + + let field_id = uneq_field_ids[0]; + + // Source.fields[i]: CoerceUnsized + let coerce_unsized_goal: Goal = TraitRef { + trait_id: trait_ref.trait_id, + substitution: Substitution::from_iter( + interner, + [ + source_fields[field_id].clone(), + target_fields[field_id].clone(), + ] + .iter() + .cloned(), + ), + } + .cast(interner); + + // ImplEnv -> Source.fields[i]: CoerceUnsized + let coerce_unsized_goal = place_in_environment(coerce_unsized_goal); + + solver.has_unique_solution( + db, + &coerce_unsized_goal.into_closed_goal(interner), + ) + } + _ => false, + } + } + _ => false, + } } } diff --git a/vendor/compiler_builtins/.cargo-checksum.json b/vendor/compiler_builtins/.cargo-checksum.json index b14e1309a8..838b788c8c 100644 --- a/vendor/compiler_builtins/.cargo-checksum.json +++ b/vendor/compiler_builtins/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"1dfa9c1f68c8e0f1d1fc90ed0712a3eeb2ea68478064c19d601249f60acde4a1","Cargo.toml":"d12e720542879582d4a8b9d6582a367d2962def71cd58cddfccf4e5d8df8b0cd","README.md":"2dd28b207028773ffee09ed0db563ac71b255b6b67256289d67a13cb19d15f94","build.rs":"bb626c4ce8b3b4c7e61548a1a56684997a58fc9d5f052df690031901321a43e6","examples/intrinsics.rs":"5bc2a8e39a541a6b55567f36ff9de17afad3cb620702a9e7c5b069a237f1197b","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":"0e6caff1597818471c28b7c3226dbfe9976fdb38ace5246172ac030754be6b79","libm/src/math/ceilf.rs":"f942bcea617de7da880b68bdfe676837a7984e2a887eaafe181be24c6bc13cc2","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":"dc85b66e4ef662721276ae3a301af22795524e4367ee8dd40f0c24c439773c6d","libm/src/math/fdim.rs":"8ec091996005207297c2389ae563e1b18dbc6a9eac951de29a976c5cd7bc32a7","libm/src/math/fdimf.rs":"c7f3f2269834d55be26b6580ddc07c42531577955fa4de35bad1e2a361085614","libm/src/math/fenv.rs":"8730d45aa4c591f91dccdcc1ce533fa23e9c6df0c38defb9c57f749cb25e1cd0","libm/src/math/floor.rs":"be15e687a6798defc6f2c6b43028481f8104fb93d2b3f359d3d5d16b78e79d4f","libm/src/math/floorf.rs":"4ec41aa64cfafd23b8cfc043eacea5e9125cca5dcb3f5e655cc3d3458c6ba2c5","libm/src/math/fma.rs":"6872e79787e9270520189b53608f602b8ad5a099f3cef10ad5b9e0c06ef01fe0","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":"1d504d7750c0481273baad88196d3644f258af9ad10f8b5b16341c0aab8b9125","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":"ffa73c08f4c0a4dc6c9d1cb9d62fe97f3a5046edede128c9441cc3adc9170dd3","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":"64fba587143fa88cdfa5c9d30b658ab03e3a19e3ea3759394836add4068983c6","libm/src/math/powf.rs":"2c423a0ea57fdc4e20f3533f744c6e6288c998b4de8f2914fafaa0e78be81b04","libm/src/math/rem_pio2.rs":"9be99c44493b2b7088578c0fa2872630725b2da544c751516df0c6c686112a43","libm/src/math/rem_pio2_large.rs":"21762d08d72dc6f2e313123a7311683000974a09b8fcae50994d9c39239721b1","libm/src/math/rem_pio2f.rs":"377349d1308bda8cd2f776e4856fe090baa78fa3db816b680780ddf31b80d446","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":"955649c893fa3151b4a81c8e550fbc03f01bb99b40d60986e5f153ee71043f69","libm/src/math/roundf.rs":"8ae8f1f71eedd158566771cfe80b352d2f13c170a0ce8dc2691a14e8a791cfbb","libm/src/math/scalbn.rs":"b5c9d6d4177fe393cbfe1c634d75ce14b754f6cbce87c5bf979a9661491748a2","libm/src/math/scalbnf.rs":"4f198d06db1896386256fb9a5ac5b805b16b836226c18780a475cf18d7c1449c","libm/src/math/sin.rs":"0e014e6377c9673a73395ab2ffcf5962e512392afddf8a4e731fb694098faf34","libm/src/math/sincos.rs":"59e9f196140681fa817652134b8d1bdd2d6dd47bb8557b0346c77b176389f883","libm/src/math/sincosf.rs":"d37d71c7204c7892fe24c956df0fb95e7a014a808f5cbd5e125aee48c3c449b5","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":"d9e12ac55c5471c18175efdfb15c092ba71a2eb914d2e1ee3b3310a22202042e","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":"619b675b6a9bb81eccddb1fa8214cff63e1f62136629b645c87f036672311732","src/arm.rs":"2035935972d728031d31d35067f0ec474f1c3b1ab86e166130d29df266b09b90","src/arm_linux.rs":"80d18ce84bdfa841fa133f5ee9e9fd50167344436d2d398f74347a90f27606c6","src/float/add.rs":"1a230ed4e17148cfffb7c880929c9c0d5d48d85581d75164c5031b8f05a5d567","src/float/cmp.rs":"a86ccbc0e56f07ba439dc6a4fd835184645178c0a6da625bd4ae24ecf9a790f8","src/float/conv.rs":"0af148b6c717d124e870e5d1926eaa562de37e374c605ea81c1f7eea994146f4","src/float/div.rs":"58bdcd73c5ffafde9cca8a0e7986de0660fb8b5b4d4132e7a63dd21f93f4fe0e","src/float/extend.rs":"180b2e791c58e0526de0a798845c580ce3222c8a15c8665e6e6a4bf5cf1a34aa","src/float/mod.rs":"d15b78070d824f5523f12d55fc084879b638241324451dbcd0ac291589c53125","src/float/mul.rs":"9465960b326897a04543789aa44640aefeb4cc63311e58ae8213f664dd4ac21e","src/float/pow.rs":"64f4935f4bed46d3b9cde4d16f59cca76a110d36d02d76f4b909157349edf5e3","src/float/sub.rs":"c2a87f4628f51d5d908d0f25b5d51ce0599dc559d5a72b20e131261f484d5848","src/int/addsub.rs":"9e7a393c76958fe9e8fb7de9bfe1304766c276bfdaa25761913357e0f6172369","src/int/mod.rs":"d15781df9dc054aa11e23f4825152ae9c609aab15bf43599ff07ff683f513643","src/int/mul.rs":"3142da8783cfac3ef704efcae19838bfda4916965fb852294685cf7664976e8a","src/int/sdiv.rs":"ca47f2a41fe0aad1e37f4e56ab1e0959c5b10c32c3593596c8cef2ff17694389","src/int/shift.rs":"0427e05a39cf6a0abab0b6525e8567afcf336f49fbb0ed0977b480e16a878bd8","src/int/udiv.rs":"9a222e79c0bf74ab77728cfa2026508508b33e7f2ac6cafc1fa34040e5538ba0","src/lib.rs":"da4433593615a60f05aff9f5252f15350e537d97dfa96e6536619545dd173851","src/macros.rs":"9f3aa9b66195b258ff29209c6b1e7962d6f82d31579d669dd74c9fdeee134170","src/math.rs":"a2e45a208bcdd742d32639591c91525a44f891db6057ce066052d67c4d4ae809","src/mem.rs":"4ece60ca07aaff3611a716a80f55668a785ad8399b65fc36cc9ab4b481fa639c","src/probestack.rs":"c1ad1e4a9550a3507bcbec00c8917530a954ba971c02506aeec949381443674a","src/riscv32.rs":"b9b433d248fce35e43a7df430697545f39898fad46be7d0197284764e44993b2","src/x86.rs":"068e456417d4740f048800da1d18eb49dd85f85604e5e383446331925e1effc3","src/x86_64.rs":"3ffbefe3bdc75cd4674ba1bbab9029bc4d6d8635f5e0b1fe30329ec6209bfd8a"},"package":"7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c"} \ No newline at end of file +{"files":{"Cargo.lock":"4772ce261c2f483910066a5cc1617e71a977b5c29f8a482be4ca4296f0154016","Cargo.toml":"465bc9f84288f6569851041d8a1ae04f7cda2eb1f1a4e9e06a71b2eb4262ae6a","README.md":"2dd28b207028773ffee09ed0db563ac71b255b6b67256289d67a13cb19d15f94","build.rs":"8140e3dce70516bbf8d151565f8f50a31bbfab60e749becd649f4c11ee350282","examples/intrinsics.rs":"5bc2a8e39a541a6b55567f36ff9de17afad3cb620702a9e7c5b069a237f1197b","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":"0e6caff1597818471c28b7c3226dbfe9976fdb38ace5246172ac030754be6b79","libm/src/math/ceilf.rs":"f942bcea617de7da880b68bdfe676837a7984e2a887eaafe181be24c6bc13cc2","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":"dc85b66e4ef662721276ae3a301af22795524e4367ee8dd40f0c24c439773c6d","libm/src/math/fdim.rs":"8ec091996005207297c2389ae563e1b18dbc6a9eac951de29a976c5cd7bc32a7","libm/src/math/fdimf.rs":"c7f3f2269834d55be26b6580ddc07c42531577955fa4de35bad1e2a361085614","libm/src/math/fenv.rs":"8730d45aa4c591f91dccdcc1ce533fa23e9c6df0c38defb9c57f749cb25e1cd0","libm/src/math/floor.rs":"be15e687a6798defc6f2c6b43028481f8104fb93d2b3f359d3d5d16b78e79d4f","libm/src/math/floorf.rs":"4ec41aa64cfafd23b8cfc043eacea5e9125cca5dcb3f5e655cc3d3458c6ba2c5","libm/src/math/fma.rs":"6872e79787e9270520189b53608f602b8ad5a099f3cef10ad5b9e0c06ef01fe0","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":"1d504d7750c0481273baad88196d3644f258af9ad10f8b5b16341c0aab8b9125","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":"ffa73c08f4c0a4dc6c9d1cb9d62fe97f3a5046edede128c9441cc3adc9170dd3","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":"64fba587143fa88cdfa5c9d30b658ab03e3a19e3ea3759394836add4068983c6","libm/src/math/powf.rs":"2c423a0ea57fdc4e20f3533f744c6e6288c998b4de8f2914fafaa0e78be81b04","libm/src/math/rem_pio2.rs":"9be99c44493b2b7088578c0fa2872630725b2da544c751516df0c6c686112a43","libm/src/math/rem_pio2_large.rs":"21762d08d72dc6f2e313123a7311683000974a09b8fcae50994d9c39239721b1","libm/src/math/rem_pio2f.rs":"377349d1308bda8cd2f776e4856fe090baa78fa3db816b680780ddf31b80d446","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":"955649c893fa3151b4a81c8e550fbc03f01bb99b40d60986e5f153ee71043f69","libm/src/math/roundf.rs":"8ae8f1f71eedd158566771cfe80b352d2f13c170a0ce8dc2691a14e8a791cfbb","libm/src/math/scalbn.rs":"b5c9d6d4177fe393cbfe1c634d75ce14b754f6cbce87c5bf979a9661491748a2","libm/src/math/scalbnf.rs":"4f198d06db1896386256fb9a5ac5b805b16b836226c18780a475cf18d7c1449c","libm/src/math/sin.rs":"0e014e6377c9673a73395ab2ffcf5962e512392afddf8a4e731fb694098faf34","libm/src/math/sincos.rs":"59e9f196140681fa817652134b8d1bdd2d6dd47bb8557b0346c77b176389f883","libm/src/math/sincosf.rs":"d37d71c7204c7892fe24c956df0fb95e7a014a808f5cbd5e125aee48c3c449b5","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":"d9e12ac55c5471c18175efdfb15c092ba71a2eb914d2e1ee3b3310a22202042e","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":"619b675b6a9bb81eccddb1fa8214cff63e1f62136629b645c87f036672311732","src/arm.rs":"2035935972d728031d31d35067f0ec474f1c3b1ab86e166130d29df266b09b90","src/arm_linux.rs":"80d18ce84bdfa841fa133f5ee9e9fd50167344436d2d398f74347a90f27606c6","src/float/add.rs":"1a230ed4e17148cfffb7c880929c9c0d5d48d85581d75164c5031b8f05a5d567","src/float/cmp.rs":"a86ccbc0e56f07ba439dc6a4fd835184645178c0a6da625bd4ae24ecf9a790f8","src/float/conv.rs":"0af148b6c717d124e870e5d1926eaa562de37e374c605ea81c1f7eea994146f4","src/float/div.rs":"58bdcd73c5ffafde9cca8a0e7986de0660fb8b5b4d4132e7a63dd21f93f4fe0e","src/float/extend.rs":"180b2e791c58e0526de0a798845c580ce3222c8a15c8665e6e6a4bf5cf1a34aa","src/float/mod.rs":"d15b78070d824f5523f12d55fc084879b638241324451dbcd0ac291589c53125","src/float/mul.rs":"9465960b326897a04543789aa44640aefeb4cc63311e58ae8213f664dd4ac21e","src/float/pow.rs":"64f4935f4bed46d3b9cde4d16f59cca76a110d36d02d76f4b909157349edf5e3","src/float/sub.rs":"c2a87f4628f51d5d908d0f25b5d51ce0599dc559d5a72b20e131261f484d5848","src/int/addsub.rs":"9e7a393c76958fe9e8fb7de9bfe1304766c276bfdaa25761913357e0f6172369","src/int/leading_zeros.rs":"b2c8763857b0687c45e540c585d5884eaf4f3badf5a0827350cff5b1c324beed","src/int/mod.rs":"0ae6151f3bc73783405507ab9c108eb006cc3a437ca4a215c9c4ef50b5081d00","src/int/mul.rs":"3142da8783cfac3ef704efcae19838bfda4916965fb852294685cf7664976e8a","src/int/sdiv.rs":"ca47f2a41fe0aad1e37f4e56ab1e0959c5b10c32c3593596c8cef2ff17694389","src/int/shift.rs":"0427e05a39cf6a0abab0b6525e8567afcf336f49fbb0ed0977b480e16a878bd8","src/int/udiv.rs":"9a222e79c0bf74ab77728cfa2026508508b33e7f2ac6cafc1fa34040e5538ba0","src/lib.rs":"f6ffd1dac18ea01184379e447a29bc4fb446fc15da15227fde82aa5fa0369bdf","src/macros.rs":"9f3aa9b66195b258ff29209c6b1e7962d6f82d31579d669dd74c9fdeee134170","src/math.rs":"a2e45a208bcdd742d32639591c91525a44f891db6057ce066052d67c4d4ae809","src/mem.rs":"4ece60ca07aaff3611a716a80f55668a785ad8399b65fc36cc9ab4b481fa639c","src/probestack.rs":"c1ad1e4a9550a3507bcbec00c8917530a954ba971c02506aeec949381443674a","src/riscv32.rs":"b9b433d248fce35e43a7df430697545f39898fad46be7d0197284764e44993b2","src/x86.rs":"068e456417d4740f048800da1d18eb49dd85f85604e5e383446331925e1effc3","src/x86_64.rs":"3ffbefe3bdc75cd4674ba1bbab9029bc4d6d8635f5e0b1fe30329ec6209bfd8a"},"package":"e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455"} \ No newline at end of file diff --git a/vendor/compiler_builtins/Cargo.lock b/vendor/compiler_builtins/Cargo.lock index 04152f7db4..caead05b05 100644 --- a/vendor/compiler_builtins/Cargo.lock +++ b/vendor/compiler_builtins/Cargo.lock @@ -2,13 +2,13 @@ # It is not intended for manual editing. [[package]] name = "cc" -version = "1.0.52" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d" +checksum = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1" [[package]] name = "compiler_builtins" -version = "0.1.32" +version = "0.1.35" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/vendor/compiler_builtins/Cargo.toml b/vendor/compiler_builtins/Cargo.toml index aafd5b9eac..fb3000592c 100644 --- a/vendor/compiler_builtins/Cargo.toml +++ b/vendor/compiler_builtins/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "compiler_builtins" -version = "0.1.32" +version = "0.1.35" authors = ["Jorge Aparicio "] links = "compiler-rt" include = ["/Cargo.toml", "/build.rs", "/src/*", "/examples/*", "/LICENSE.txt", "/README.md", "/compiler-rt/*", "/libm/src/math/*"] diff --git a/vendor/compiler_builtins/build.rs b/vendor/compiler_builtins/build.rs index abeac9bf1e..f948edba9e 100644 --- a/vendor/compiler_builtins/build.rs +++ b/vendor/compiler_builtins/build.rs @@ -419,6 +419,37 @@ mod c { if target_os != "windows" { sources.extend(&[("__multc3", "multc3.c")]); } + + if target_env == "musl" { + sources.extend(&[ + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__divtf3", "divtf3.c"), + ("__powitf2", "powitf2.c"), + ("__fe_getround", "fp_mode.c"), + ("__fe_raise_inexact", "fp_mode.c"), + ]); + } + } + + if target_arch == "mips" { + sources.extend(&[("__bswapsi2", "bswapsi2.c")]); + } + + if target_arch == "mips64" { + sources.extend(&[ + ("__extenddftf2", "extenddftf2.c"), + ("__netf2", "comparetf2.c"), + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__fixtfsi", "fixtfsi.c"), + ("__floatsitf", "floatsitf.c"), + ("__fixunstfsi", "fixunstfsi.c"), + ("__floatunsitf", "floatunsitf.c"), + ("__fe_getround", "fp_mode.c"), + ]); } // Remove the assembly implementations that won't compile for the target diff --git a/vendor/compiler_builtins/src/int/leading_zeros.rs b/vendor/compiler_builtins/src/int/leading_zeros.rs new file mode 100644 index 0000000000..78556f0bcf --- /dev/null +++ b/vendor/compiler_builtins/src/int/leading_zeros.rs @@ -0,0 +1,143 @@ +// Note: these functions happen to produce the correct `usize::leading_zeros(0)` value +// without a explicit zero check. Zero is probably common enough that it could warrant +// adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. +// Compilers will insert the check for zero in cases where it is needed. + +/// Returns the number of leading binary zeros in `x`. +pub fn usize_leading_zeros_default(x: usize) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = usize::MAX.count_ones() as usize; + // a temporary + let mut t: usize; + #[cfg(target_pointer_width = "64")] + { + t = x >> 32; + if t != 0 { + z -= 32; + x = t; + } + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + t = x >> 16; + if t != 0 { + z -= 16; + x = t; + } + } + t = x >> 8; + if t != 0 { + z -= 8; + x = t; + } + t = x >> 4; + if t != 0 { + z -= 4; + x = t; + } + t = x >> 2; + if t != 0 { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != 0 { + z - 2 + } else { + z - x + } + + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/ + // fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. +} + +// The above method does not compile well on RISC-V (because of the lack of predicated +// instructions), producing code with many branches or using an excessively long +// branchless solution. This method takes advantage of the set-if-less-than instruction on +// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + +/// Returns the number of leading binary zeros in `x`. +pub fn usize_leading_zeros_riscv(x: usize) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = usize::MAX.count_ones() as usize; + // a temporary + let mut t: usize; + + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + #[cfg(target_pointer_width = "64")] + { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (1 << 32)) as usize) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + t = ((x >= (1 << 16)) as usize) << 4; + x >>= t; + z -= t; + } + t = ((x >= (1 << 8)) as usize) << 3; + x >>= t; + z -= t; + t = ((x >= (1 << 4)) as usize) << 2; + x >>= t; + z -= t; + t = ((x >= (1 << 2)) as usize) << 1; + x >>= t; + z -= t; + t = (x >= (1 << 1)) as usize; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z - x +} + +intrinsics! { + #[maybe_use_optimized_c_shim] + #[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" + ))] + /// Returns the number of leading binary zeros in `x`. + pub extern "C" fn __clzsi2(x: usize) -> usize { + if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + usize_leading_zeros_riscv(x) + } else { + usize_leading_zeros_default(x) + } + } +} diff --git a/vendor/compiler_builtins/src/int/mod.rs b/vendor/compiler_builtins/src/int/mod.rs index d73bf6db99..8a469d9014 100644 --- a/vendor/compiler_builtins/src/int/mod.rs +++ b/vendor/compiler_builtins/src/int/mod.rs @@ -13,11 +13,14 @@ macro_rules! os_ty { } pub mod addsub; +pub mod leading_zeros; pub mod mul; pub mod sdiv; pub mod shift; pub mod udiv; +pub use self::leading_zeros::__clzsi2; + /// Trait for some basic operations on integers pub(crate) trait Int: Copy @@ -300,69 +303,3 @@ macro_rules! impl_wide_int { impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); - -intrinsics! { - #[maybe_use_optimized_c_shim] - #[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" - ))] - pub extern "C" fn __clzsi2(x: usize) -> usize { - // TODO: const this? Would require const-if - // Note(Lokathor): the `intrinsics!` macro can't process mut inputs - let mut x = x; - let mut y: usize; - let mut n: usize = { - #[cfg(target_pointer_width = "64")] - { - 64 - } - #[cfg(target_pointer_width = "32")] - { - 32 - } - #[cfg(target_pointer_width = "16")] - { - 16 - } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; - if y != 0 { - n -= 32; - x = y; - } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; - if y != 0 { - n -= 16; - x = y; - } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x - } - } -} diff --git a/vendor/compiler_builtins/src/lib.rs b/vendor/compiler_builtins/src/lib.rs index db05af5de3..34397e0d25 100644 --- a/vendor/compiler_builtins/src/lib.rs +++ b/vendor/compiler_builtins/src/lib.rs @@ -15,7 +15,7 @@ // We use `u128` in a whole bunch of places which we currently agree with the // compiler on ABIs and such, so we should be "good enough" for now and changes // to the `u128` ABI will be reflected here. -#![allow(improper_ctypes)] +#![allow(improper_ctypes, improper_ctypes_definitions)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/vendor/cpuid-bool/.cargo-checksum.json b/vendor/cpuid-bool/.cargo-checksum.json new file mode 100644 index 0000000000..1903d4c1e5 --- /dev/null +++ b/vendor/cpuid-bool/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"e0cd09e38fffd25bdf238995b8a1855e3162b6a6609decfd07e18a7ac9f18ec0","Cargo.toml":"081493bc0588bd6edc77176138e21039312aae65dcd2a700f8d8b4368d6ae3ad","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"904801faf3f1850328af8e1aa1047b9190cc22ed40df5c87f2d93d17f847ef67","src/lib.rs":"e724effc564546e40616f5a64e722a3c81a5b4837f178b7a0e656c4b39e816c9"},"package":"8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"} \ No newline at end of file diff --git a/vendor/cpuid-bool/CHANGELOG.md b/vendor/cpuid-bool/CHANGELOG.md new file mode 100644 index 0000000000..961ba48c89 --- /dev/null +++ b/vendor/cpuid-bool/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +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). + +## 0.1.2 (2020-07-20) +### Added +- LICENSE files ([#70]) + +[#70]: https://github.com/RustCrypto/utils/pull/70 + +## 0.1.1 (2020-07-14) +### Fixed +- SGX target support ([#68]) + +[#68]: https://github.com/RustCrypto/utils/pull/68 + +## 0.1.0 (2020-06-11) +- Initial release \ No newline at end of file diff --git a/vendor/cpuid-bool/Cargo.toml b/vendor/cpuid-bool/Cargo.toml new file mode 100644 index 0000000000..b7b7e07d48 --- /dev/null +++ b/vendor/cpuid-bool/Cargo.toml @@ -0,0 +1,23 @@ +# 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 = "cpuid-bool" +version = "0.1.2" +authors = ["RustCrypto Developers"] +description = "A lightweight no-std compatible alternative to is_x86_feature_detected" +documentation = "https://docs.rs/cpuid-bool" +keywords = ["cpuid", "target-feature"] +categories = ["no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/utils" diff --git a/vendor/cpuid-bool/LICENSE-APACHE b/vendor/cpuid-bool/LICENSE-APACHE new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/cpuid-bool/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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/cpuid-bool/LICENSE-MIT b/vendor/cpuid-bool/LICENSE-MIT new file mode 100644 index 0000000000..2726e14a40 --- /dev/null +++ b/vendor/cpuid-bool/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020 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/cpuid-bool/src/lib.rs b/vendor/cpuid-bool/src/lib.rs new file mode 100644 index 0000000000..557539a75b --- /dev/null +++ b/vendor/cpuid-bool/src/lib.rs @@ -0,0 +1,121 @@ +//! Macro for checking CPU capabilities at runtime. +//! +//! # Usage example +//! ``` +//! if cpuid_bool::cpuid_bool!("sha", "aes") { +//! println!("CPU supports both SHA and AES extensions"); +//! } else { +//! println!("SHA and AES extensions are not supported"); +//! } +//! ``` +//! Note that if all tested target features are enabled via compiler options +//! (e.g. by using `RUSTFLAGS`), `cpuid_bool!` macro immideatly will expand +//! to `true` and will not use CPUID instruction. Such behavior allows +//! compiler to eliminate fallback code. +//! +//! After first call macro caches result and returns it in subsequent +//! calls, thus runtime overhead for them is minimal. +#![no_std] +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +compile_error!("This crate works only on x86 and x86-64 targets."); + +use core::sync::atomic::{AtomicU8, Ordering::Relaxed}; + +/// This structure represents a lazily initialized static boolean value. +/// +/// Useful when it is preferable to just rerun initialization instead of +/// locking. Used internally by the `cpuid_bool` macro. +pub struct LazyBool(AtomicU8); + +impl LazyBool { + const UNINIT: u8 = u8::max_value(); + + pub const fn new() -> Self { + Self(AtomicU8::new(Self::UNINIT)) + } + + // Runs the init() function at least once, returning the value of some run + // of init(). Multiple callers can run their init() functions in parallel. + // init() should always return the same value, if it succeeds. + pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { + // Relaxed ordering is fine, as we only have a single atomic variable. + let mut val = self.0.load(Relaxed); + if val == Self::UNINIT { + val = init() as u8; + self.0.store(val as u8, Relaxed); + } + val != 0 + } +} + +// TODO: find how to define private macro usable inside a public one +macro_rules! expand_check_macro { + ($(($name:tt, $i:expr, $reg:ident, $offset:expr)),* $(,)?) => { + #[macro_export] + #[doc(hidden)] + macro_rules! check { + $( + ($cr:expr, $name) => { ($cr[$i].$reg & (1 << $offset) != 0) }; + )* + } + }; +} + +expand_check_macro! { + ("mmx", 0, edx, 23), + ("sse", 0, edx, 25), + ("sse2", 0, edx, 26), + ("sse3", 0, ecx, 0), + ("pclmulqdq", 0, ecx, 1), + ("ssse3", 0, ecx, 9), + ("fma", 0, ecx, 12), + ("sse4.1", 0, ecx, 19), + ("sse4.2", 0, ecx, 20), + ("popcnt", 0, ecx, 23), + ("aes", 0, ecx, 25), + ("avx", 0, ecx, 28), + ("rdrand", 0, ecx, 30), + ("sgx", 1, ebx, 2), + ("bmi1", 1, ebx, 3), + ("avx2", 1, ebx, 5), + ("bmi2", 1, ebx, 8), + ("rdseed", 1, ebx, 18), + ("adx", 1, ebx, 19), + ("sha", 1, ebx, 29), +} + +/// Check at runtime if CPU supports sequence of target features. +/// +/// During first execution this macro will use CPUID to check requested +/// target features, results will be cached and further calls will return +/// it instead. +#[macro_export] +macro_rules! cpuid_bool { + ($($tf:tt),+ $(,)? ) => {{ + // CPUID is not available on SGX targets + #[cfg(all(not(target_env = "sgx"), not(all($(target_feature=$tf, )*))))] + let res = { + #[cfg(target_arch = "x86")] + use core::arch::x86::{__cpuid, __cpuid_count}; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::{__cpuid, __cpuid_count}; + + static CPUID_BOOL: cpuid_bool::LazyBool = cpuid_bool::LazyBool::new(); + CPUID_BOOL.unsync_init(|| { + #[allow(unused_variables)] + let cr = unsafe { + [__cpuid(1), __cpuid_count(7, 0)] + }; + // TODO: find how to remove `true` + $(cpuid_bool::check!(cr, $tf) & )+ true + }) + }; + + #[cfg(all(target_env = "sgx", not(all($(target_feature=$tf, )*))))] + let res = false; + #[cfg(all($(target_feature=$tf, )*))] + let res = true; + + res + }}; +} diff --git a/vendor/crossbeam-channel/.cargo-checksum.json b/vendor/crossbeam-channel/.cargo-checksum.json new file mode 100644 index 0000000000..61a680a18a --- /dev/null +++ b/vendor/crossbeam-channel/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"d55a5f1a75b60fbbd53a5b1432f19b8fa7e2bb822e1cc93ec956e542e7e8b3cd","Cargo.lock":"dcb3de08ddba81cf97f49253b63b8eb4f386338c0db8d4b77ae943fc138bfe69","Cargo.toml":"c20147fdaf2d6e99fe30c9f639fc0339f6af18994c2756cba1c869cd8e198bc0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"924a49392dc8304def57586be4ebd69aaf51e16fd245b55b4b69ad2cce6b715a","README.md":"7967172d90f7ebc20531d76c5a2bad7be8d81670fbc64abc33be4315d1430757","benches/crossbeam.rs":"baef02dffd58ee4d84d33a4e999254e81fcf45241623cfa6c4b1ef73dbd7479d","examples/fibonacci.rs":"8755bcb9cf05e391d8679fbb51db40ed9692703c3b66341cd1c1e4cca2068874","examples/matching.rs":"a1bdd7d211cf8612d649de3de3e24f56e911bc8d5e95b86b06f412314f9edd6c","examples/stopwatch.rs":"4e90ce134475859a421da0a095baea52a575b03e41fb8fb50cf47446f422ee6e","src/channel.rs":"4483ddf38c4b9b308b81dd156653ccb590524aae1e5ff8efcab6b8f44a8d3dfc","src/context.rs":"48eb848538482aeadd5bafb8fd24695dcf5635243d6f9d3b059a22538ce67014","src/counter.rs":"8b6d4d69db59bc992ddc7ed33f709788c3fab482521bb1adf985f77499506c09","src/err.rs":"80c47848fbfeeabaa83ea49c0928274cd4ae0ced7ebf214a075322fe301f3fa6","src/flavors/after.rs":"4f761618efe21036145e44f01506bdfbc2524879368ac138600e0feed921a6a7","src/flavors/array.rs":"606e27d3376c3cee128656b3690bd429964a22e3078886b6b7bf10cfa072fabb","src/flavors/list.rs":"0e2bf126b07ba8c2ef5db881043a3987b5f91013d47ae2da147a1c61a033c320","src/flavors/mod.rs":"a5af9b6105207e293c0d64928b4486fb1da9bfe0318354c66c8b5069e41ec31f","src/flavors/never.rs":"86e21b4d8b154e5d795cf72c7203a1d16a846c4d670095c8b592c12569f35a98","src/flavors/tick.rs":"d80858e0d5d1d7ec3886fb607e49bbc9577d64dc7c7304c5d3e6c8629a065476","src/flavors/zero.rs":"a24c2fb547586ab4bf2a09efb8af5264274f7b373749cd259a7dd3c843c8aac5","src/lib.rs":"1f0e6c4fb470dfe2fbdda90b7ac17f72c32fd62d41bccb4db9a756a88481fb44","src/select.rs":"f917459c033f8edbb45f377d6a4af24ffb583583d039182e72252d4af64a8807","src/select_macro.rs":"b1a3d2b9d4c64b48f6b176d2ff8b44c3d754f157ddbe830e8a1e86e4c100e0e9","src/utils.rs":"8b1184222df9047355e6044ad7e3fefd6065a5dda98b968cae45cca5f4b2fb5d","src/waker.rs":"345b551d467389a3a18dc22b351674dfbf288945b984450f607e644faa8a9731","tests/after.rs":"effb341c02f03a45ce09ab7862bc5b191191e0175997c494f988e6daca1ef8af","tests/array.rs":"35cd46fc7310f4206e3bbd81f900c18053a3a22943e221fbb81f9b89505fee46","tests/golang.rs":"9cb210ef2668428f7efb542ff4a8ab4e61f77dd4ff7e39720d63ad0797ff4ec1","tests/iter.rs":"b6df3f21273bb21dfecda47ffc0c296541214cde6bed876a31db5f2410839e83","tests/list.rs":"eb6cfc9a0f02c77df6d6d608fbbe1f82e09901e167b4b86993c49f9d6052a8ee","tests/mpsc.rs":"965e18abbfcdebec09380f8ec9bb62e5556ad2aa0176ed088ce091994c1d2500","tests/never.rs":"cd455a4c78403d9a96fe0f3a4e968164cca533cc85c96aaa4558987f9b088fcc","tests/ready.rs":"b91cebde45a6c46bd2cf16b1fc58b2ec258dcc960cb9f8eb5b4c39b1a144cadc","tests/same_channel.rs":"bd93f72e982f9881235848a4a2da67276feca810ed1e4d22e0e2bda8675cae4a","tests/select.rs":"57558f93834dc1ae1a56fe8d1211536e16015a74c8c7458c653852472c21ddcd","tests/select_macro.rs":"1cd5250d46d6d2e8c0a87ee9b1c0a5d80aac193c3eb0a86877249684e7aabd39","tests/thread_locals.rs":"845f8c8f1a37a14e4235fc9fc20d8b7288fd9fda307c075c0e61e6ab79b33921","tests/tick.rs":"dd4257f1f8de01477d542e20a816eede3b4e2e4dc6fcdf07d554220f0ef8a86f","tests/zero.rs":"088804df377904eca4a985d8f1703f98550e51304d6849bfce143fcd0b69c349"},"package":"b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"} \ No newline at end of file diff --git a/vendor/crossbeam-channel/CHANGELOG.md b/vendor/crossbeam-channel/CHANGELOG.md new file mode 100644 index 0000000000..8c1c7fc42f --- /dev/null +++ b/vendor/crossbeam-channel/CHANGELOG.md @@ -0,0 +1,167 @@ +# Version 0.4.4 + +- Fix bug in release (yanking 0.4.3) +- Fix UB and breaking change introduced in 0.4.3 + +# Version 0.4.3 + +- Change license to "MIT OR Apache-2.0". + +# Version 0.4.2 + +- Fix bug in release (yanking 0.4.1) + +# Version 0.4.1 + +- Avoid time drift in `channel::tick`. (#456) +- Fix unsoundness issues by adopting `MaybeUninit`. (#458) + +# Version 0.4.0 + +- Bump the minimum required version to 1.28. +- Bump `crossbeam-utils` to `0.7`. + +# Version 0.3.9 + +- Fix a bug in reference counting. +- Optimize `recv_timeout()`. +- Add `Select::remove()`. +- Various small improvements, code cleanup, more tests. + +# Version 0.3.8 + +- Bump the minimum required version of `crossbeam-utils`. + +# Version 0.3.7 + +- Remove `parking_lot` and `rand` dependencies. +- Expand documentation. +- Implement `Default` for `Select`. +- Make `size_of::>()` smaller. +- Several minor optimizations. +- Add more tests. + +# Version 0.3.6 + +- Fix a bug in initialization of unbounded channels. + +# Version 0.3.5 + +- New implementation for unbounded channels. +- A number of small performance improvements. +- Remove `crossbeam-epoch` dependency. + +# Version 0.3.4 + +- Bump `crossbeam-epoch` to `0.7`. +- Improve documentation. + +# Version 0.3.3 + +- Relax the lifetime in `SelectedOperation<'_>`. +- Add `Select::try_ready()`, `Select::ready()`, and `Select::ready_timeout()`. +- Update licensing notices. +- Improve documentation. +- Add methods `is_disconnected()`, `is_timeout()`, `is_empty()`, and `is_full()` on error types. + +# Version 0.3.2 + +- More elaborate licensing notices. + +# Version 0.3.1 + +- Update `crossbeam-utils` to `0.6`. + +# Version 0.3.0 + +- Add a special `never` channel type. +- Dropping all receivers now closes the channel. +- The interface of sending and receiving methods is now very similar to those in v0.1. +- The syntax for `send` in `select!` is now `send(sender, msg) -> res => body`. +- The syntax for `recv` in `select!` is now `recv(receiver) -> res => body`. +- New, more efficient interface for `Select` without callbacks. +- Timeouts can be specified in `select!`. + +# Version 0.2.6 + +- `Select` struct that can add cases dynamically. +- More documentation (in particular, the FAQ section). +- Optimize contended sends/receives in unbounded channels. + +# Version 0.2.5 + +- Use `LocalKey::try_with` instead of `LocalKey::with`. +- Remove helper macros `__crossbeam_channel*`. + +# Version 0.2.4 + +- Make `select!` linearizable with other channel operations. +- Update `crossbeam-utils` to `0.5.0`. +- Update `parking_lot` to `0.6.3`. +- Remove Mac OS X tests. + +# Version 0.2.3 + +- Add Mac OS X tests. +- Lower some memory orderings. +- Eliminate calls to `mem::unitialized`, which caused bugs with ZST. + +# Version 0.2.2 + +- Add more tests. +- Update `crossbeam-epoch` to 0.5.0 +- Initialize the RNG seed to a random value. +- Replace `libc::abort` with `std::process::abort`. +- Ignore clippy warnings in `select!`. +- Better interaction of `select!` with the NLL borrow checker. + +# Version 0.2.1 + +- Fix compilation errors when using `select!` with `#[deny(unsafe_code)]`. + +# Version 0.2.0 + +- Implement `IntoIterator` for `Receiver`. +- Add a new `select!` macro. +- Add special channels `after` and `tick`. +- Dropping receivers doesn't close the channel anymore. +- Change the signature of `recv`, `send`, and `try_recv`. +- Remove `Sender::is_closed` and `Receiver::is_closed`. +- Remove `Sender::close` and `Receiver::close`. +- Remove `Sender::send_timeout` and `Receiver::recv_timeout`. +- Remove `Sender::try_send`. +- Remove `Select` and `select_loop!`. +- Remove all error types. +- Remove `Iter`, `TryIter`, and `IntoIter`. +- Remove the `nightly` feature. +- Remove ordering operators for `Sender` and `Receiver`. + +# Version 0.1.3 + +- Add `Sender::disconnect` and `Receiver::disconnect`. +- Implement comparison operators for `Sender` and `Receiver`. +- Allow arbitrary patterns in place of `msg` in `recv(r, msg)`. +- Add a few conversion impls between error types. +- Add benchmarks for `atomicring` and `mpmc`. +- Add benchmarks for different message sizes. +- Documentation improvements. +- Update `crossbeam-epoch` to 0.4.0 +- Update `crossbeam-utils` to 0.3.0 +- Update `parking_lot` to 0.5 +- Update `rand` to 0.4 + +# Version 0.1.2 + +- Allow conditional cases in `select_loop!` macro. +- Fix typos in documentation. +- Fix deadlock in selection when all channels are disconnected and a timeout is specified. + +# Version 0.1.1 + +- Implement `Debug` for `Sender`, `Receiver`, `Iter`, `TryIter`, `IntoIter`, and `Select`. +- Implement `Default` for `Select`. + +# Version 0.1.0 + +- First implementation of the channels. +- Add `select_loop!` macro by @TimNN. diff --git a/vendor/crossbeam-channel/Cargo.lock b/vendor/crossbeam-channel/Cargo.lock new file mode 100644 index 0000000000..fe038cc011 --- /dev/null +++ b/vendor/crossbeam-channel/Cargo.lock @@ -0,0 +1,262 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arc-swap" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.4" +dependencies = [ + "crossbeam-utils", + "maybe-uninit", + "num_cpus", + "rand", + "signal-hook", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg 1.0.1", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "hermit-abi" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "signal-hook" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" +dependencies = [ + "arc-swap", + "libc", +] + +[[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/crossbeam-queue/Cargo.toml b/vendor/crossbeam-channel/Cargo.toml similarity index 65% rename from vendor/crossbeam-queue/Cargo.toml rename to vendor/crossbeam-channel/Cargo.toml index c03e35b1dc..86f264b99b 100644 --- a/vendor/crossbeam-queue/Cargo.toml +++ b/vendor/crossbeam-channel/Cargo.toml @@ -11,30 +11,27 @@ # will likely look very different (and much more reasonable) [package] -name = "crossbeam-queue" -version = "0.2.3" +name = "crossbeam-channel" +version = "0.4.4" authors = ["The Crossbeam Project Developers"] -description = "Concurrent queues" -homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" -documentation = "https://docs.rs/crossbeam-queue" +description = "Multi-producer multi-consumer channels for message passing" +homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel" +documentation = "https://docs.rs/crossbeam-channel" readme = "README.md" -keywords = ["queue", "mpmc", "lock-free", "producer", "consumer"] -categories = ["concurrency", "data-structures"] -license = "MIT/Apache-2.0 AND BSD-2-Clause" +keywords = ["channel", "mpmc", "select", "golang", "message"] +categories = ["algorithms", "concurrency", "data-structures"] +license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" -[dependencies.cfg-if] -version = "0.1.2" - [dependencies.crossbeam-utils] version = "0.7" -default-features = false [dependencies.maybe-uninit] version = "2.0.0" +[dev-dependencies.num_cpus] +version = "1.10.0" + [dev-dependencies.rand] version = "0.6" -[features] -alloc = ["crossbeam-utils/alloc"] -default = ["std"] -std = ["crossbeam-utils/std"] +[dev-dependencies.signal-hook] +version = "0.1.5" diff --git a/vendor/itertools-0.8.2/LICENSE-APACHE b/vendor/crossbeam-channel/LICENSE-APACHE similarity index 100% rename from vendor/itertools-0.8.2/LICENSE-APACHE rename to vendor/crossbeam-channel/LICENSE-APACHE diff --git a/vendor/crossbeam-queue/LICENSE-MIT b/vendor/crossbeam-channel/LICENSE-MIT similarity index 100% rename from vendor/crossbeam-queue/LICENSE-MIT rename to vendor/crossbeam-channel/LICENSE-MIT diff --git a/vendor/crossbeam-channel/LICENSE-THIRD-PARTY b/vendor/crossbeam-channel/LICENSE-THIRD-PARTY new file mode 100644 index 0000000000..d15e32bc71 --- /dev/null +++ b/vendor/crossbeam-channel/LICENSE-THIRD-PARTY @@ -0,0 +1,625 @@ +=============================================================================== + +Bounded MPMC queue +http://www.1024cores.net/home/code-license + +Copyright (c) 2010-2011 Dmitry Vyukov. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of Dmitry Vyukov. + +=============================================================================== + +matching.go +https://creativecommons.org/licenses/by/3.0/legalcode + +Creative Commons Legal Code + +Attribution 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4 (b) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. + + Creative Commons may be contacted at https://creativecommons.org/. + +=============================================================================== + +The Go Programming Language +https://golang.org/LICENSE + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================== + +The Rust Programming Language +https://github.com/rust-lang/rust/blob/master/LICENSE-MIT + +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. + +=============================================================================== + +The Rust Programming Language +https://github.com/rust-lang/rust/blob/master/LICENSE-APACHE + + 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-channel/README.md b/vendor/crossbeam-channel/README.md new file mode 100644 index 0000000000..be2e0b8f32 --- /dev/null +++ b/vendor/crossbeam-channel/README.md @@ -0,0 +1,93 @@ +# Crossbeam Channel + +[![Build Status](https://travis-ci.org/crossbeam-rs/crossbeam.svg?branch=master)]( +https://travis-ci.org/crossbeam-rs/crossbeam) +[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)]( +https://github.com/crossbeam-rs/crossbeam-channel) +[![Cargo](https://img.shields.io/crates/v/crossbeam-channel.svg)]( +https://crates.io/crates/crossbeam-channel) +[![Documentation](https://docs.rs/crossbeam-channel/badge.svg)]( +https://docs.rs/crossbeam-channel) +[![Rust 1.28+](https://img.shields.io/badge/rust-1.28+-lightgray.svg)]( +https://www.rust-lang.org) +[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) + +This crate provides multi-producer multi-consumer channels for message passing. +It is an alternative to [`std::sync::mpsc`] with more features and better performance. + +Some highlights: + +* [`Sender`]s and [`Receiver`]s can be cloned and shared among threads. +* Two main kinds of channels are [`bounded`] and [`unbounded`]. +* Convenient extra channels like [`after`], [`never`], and [`tick`]. +* The [`select!`] macro can block on multiple channel operations. +* [`Select`] can select over a dynamically built list of channel operations. +* Channels use locks very sparingly for maximum [performance](benchmarks). + +[`std::sync::mpsc`]: https://doc.rust-lang.org/std/sync/mpsc/index.html +[`Sender`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/struct.Sender.html +[`Receiver`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/struct.Receiver.html +[`bounded`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.bounded.html +[`unbounded`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.unbounded.html +[`after`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.after.html +[`never`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.never.html +[`tick`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.tick.html +[`select!`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/macro.select.html +[`Select`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/struct.Select.html + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +crossbeam-channel = "0.4" +``` + +Next, add this to your crate: + +```rust +#[macro_use] +extern crate crossbeam_channel; +``` + +## Compatibility + +The minimum supported Rust version is 1.28. Any change to this is considered a breaking change. + +## 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. + +#### Third party software + +This product includes copies and modifications of software developed by third parties: + +* [examples/matching.rs](examples/matching.rs) includes + [matching.go](http://www.nada.kth.se/~snilsson/concurrency/src/matching.go) by Stefan Nilsson, + licensed under Creative Commons Attribution 3.0 Unported License. + +* [src/flavors/array.rs](src/flavors/array.rs) is based on + [Bounded MPMC queue](http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue) + by Dmitry Vyukov, licensed under the Simplified BSD License and the Apache License, Version 2.0. + +* [tests/mpsc.rs](tests/mpsc.rs) includes modifications of code from The Rust Programming Language, + licensed under the MIT License and the Apache License, Version 2.0. + +* [tests/golang.rs](tests/golang.rs) is based on code from The Go Programming Language, licensed + under the 3-Clause BSD License. + +See the source code files for more details. + +Copies of third party licenses can be found in [LICENSE-THIRD-PARTY](LICENSE-THIRD-PARTY). diff --git a/vendor/crossbeam-channel/benches/crossbeam.rs b/vendor/crossbeam-channel/benches/crossbeam.rs new file mode 100644 index 0000000000..4dd956b12c --- /dev/null +++ b/vendor/crossbeam-channel/benches/crossbeam.rs @@ -0,0 +1,715 @@ +#![feature(test)] + +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate num_cpus; +extern crate test; + +use crossbeam_channel::{bounded, unbounded}; +use crossbeam_utils::thread::scope; +use test::Bencher; + +const TOTAL_STEPS: usize = 40_000; + +mod unbounded { + use super::*; + + #[bench] + fn create(b: &mut Bencher) { + b.iter(|| unbounded::()); + } + + #[bench] + fn oneshot(b: &mut Bencher) { + b.iter(|| { + let (s, r) = unbounded::(); + s.send(0).unwrap(); + r.recv().unwrap(); + }); + } + + #[bench] + fn inout(b: &mut Bencher) { + let (s, r) = unbounded::(); + b.iter(|| { + s.send(0).unwrap(); + r.recv().unwrap(); + }); + } + + #[bench] + fn par_inout(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} + +mod bounded_n { + use super::*; + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = bounded::(steps); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(steps * threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(steps * threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn par_inout(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + assert_eq!(threads % 2, 0); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(steps * threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} + +mod bounded_1 { + use super::*; + + #[bench] + fn create(b: &mut Bencher) { + b.iter(|| bounded::(1)); + } + + #[bench] + fn oneshot(b: &mut Bencher) { + b.iter(|| { + let (s, r) = bounded::(1); + s.send(0).unwrap(); + r.recv().unwrap(); + }); + } + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} + +mod bounded_0 { + use super::*; + + #[bench] + fn create(b: &mut Bencher) { + b.iter(|| bounded::(0)); + } + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} diff --git a/vendor/crossbeam-channel/examples/fibonacci.rs b/vendor/crossbeam-channel/examples/fibonacci.rs new file mode 100644 index 0000000000..499887a052 --- /dev/null +++ b/vendor/crossbeam-channel/examples/fibonacci.rs @@ -0,0 +1,27 @@ +//! An asynchronous fibonacci sequence generator. + +extern crate crossbeam_channel; + +use std::thread; + +use crossbeam_channel::{bounded, Sender}; + +// Sends the Fibonacci sequence into the channel until it becomes disconnected. +fn fibonacci(sender: Sender) { + let (mut x, mut y) = (0, 1); + while sender.send(x).is_ok() { + let tmp = x; + x = y; + y = tmp + y; + } +} + +fn main() { + let (s, r) = bounded(0); + thread::spawn(|| fibonacci(s)); + + // Print the first 20 Fibonacci numbers. + for num in r.iter().take(20) { + println!("{}", num); + } +} diff --git a/vendor/crossbeam-channel/examples/matching.rs b/vendor/crossbeam-channel/examples/matching.rs new file mode 100644 index 0000000000..4b157ff56c --- /dev/null +++ b/vendor/crossbeam-channel/examples/matching.rs @@ -0,0 +1,76 @@ +//! Using `select!` to send and receive on the same channel at the same time. +//! +//! This example is based on the following program in Go. +//! +//! Source: +//! - https://web.archive.org/web/20171209034309/https://www.nada.kth.se/~snilsson/concurrency +//! - http://www.nada.kth.se/~snilsson/concurrency/src/matching.go +//! +//! Copyright & License: +//! - Stefan Nilsson +//! - Creative Commons Attribution 3.0 Unported License +//! - https://creativecommons.org/licenses/by/3.0/ +//! +//! ```go +//! func main() { +//! people := []string{"Anna", "Bob", "Cody", "Dave", "Eva"} +//! match := make(chan string, 1) // Make room for one unmatched send. +//! wg := new(sync.WaitGroup) +//! for _, name := range people { +//! wg.Add(1) +//! go Seek(name, match, wg) +//! } +//! wg.Wait() +//! select { +//! case name := <-match: +//! fmt.Printf("No one received %s’s message.\n", name) +//! default: +//! // There was no pending send operation. +//! } +//! } +//! +//! // Seek either sends or receives, whichever possible, a name on the match +//! // channel and notifies the wait group when done. +//! func Seek(name string, match chan string, wg *sync.WaitGroup) { +//! select { +//! case peer := <-match: +//! fmt.Printf("%s received a message from %s.\n", name, peer) +//! case match <- name: +//! // Wait for someone to receive my message. +//! } +//! wg.Done() +//! } +//! ``` + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use crossbeam_channel::bounded; +use crossbeam_utils::thread; + +fn main() { + let people = vec!["Anna", "Bob", "Cody", "Dave", "Eva"]; + let (s, r) = bounded(1); // Make room for one unmatched send. + + // Either send my name into the channel or receive someone else's, whatever happens first. + let seek = |name, s, r| { + select! { + recv(r) -> peer => println!("{} received a message from {}.", name, peer.unwrap()), + send(s, name) -> _ => {}, // Wait for someone to receive my message. + } + }; + + thread::scope(|scope| { + for name in people { + let (s, r) = (s.clone(), r.clone()); + scope.spawn(move |_| seek(name, s, r)); + } + }) + .unwrap(); + + // Check if there is a pending send operation. + if let Ok(name) = r.try_recv() { + println!("No one received {}’s message.", name); + } +} diff --git a/vendor/crossbeam-channel/examples/stopwatch.rs b/vendor/crossbeam-channel/examples/stopwatch.rs new file mode 100644 index 0000000000..137ea210e6 --- /dev/null +++ b/vendor/crossbeam-channel/examples/stopwatch.rs @@ -0,0 +1,58 @@ +//! Prints the elapsed time every 1 second and quits on Ctrl+C. + +#[macro_use] +extern crate crossbeam_channel; +extern crate signal_hook; + +use std::io; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{bounded, tick, Receiver}; +use signal_hook::iterator::Signals; +use signal_hook::SIGINT; + +// Creates a channel that gets a message every time `SIGINT` is signalled. +fn sigint_notifier() -> io::Result> { + let (s, r) = bounded(100); + let signals = Signals::new(&[SIGINT])?; + + thread::spawn(move || { + for _ in signals.forever() { + if s.send(()).is_err() { + break; + } + } + }); + + Ok(r) +} + +// Prints the elapsed time. +fn show(dur: Duration) { + println!( + "Elapsed: {}.{:03} sec", + dur.as_secs(), + dur.subsec_nanos() / 1_000_000 + ); +} + +fn main() { + let start = Instant::now(); + let update = tick(Duration::from_secs(1)); + let ctrl_c = sigint_notifier().unwrap(); + + loop { + select! { + recv(update) -> _ => { + show(start.elapsed()); + } + recv(ctrl_c) -> _ => { + println!(); + println!("Goodbye!"); + show(start.elapsed()); + break; + } + } + } +} diff --git a/vendor/crossbeam-channel/src/channel.rs b/vendor/crossbeam-channel/src/channel.rs new file mode 100644 index 0000000000..bc7908f0f4 --- /dev/null +++ b/vendor/crossbeam-channel/src/channel.rs @@ -0,0 +1,1389 @@ +//! The channel interface. + +use std::fmt; +use std::iter::FusedIterator; +use std::mem; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +use context::Context; +use counter; +use err::{RecvError, RecvTimeoutError, SendError, SendTimeoutError, TryRecvError, TrySendError}; +use flavors; +use select::{Operation, SelectHandle, Token}; + +/// Creates a channel of unbounded capacity. +/// +/// This channel has a growable buffer that can hold any number of messages at a time. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// // Computes the n-th Fibonacci number. +/// fn fib(n: i32) -> i32 { +/// if n <= 1 { +/// n +/// } else { +/// fib(n - 1) + fib(n - 2) +/// } +/// } +/// +/// // Spawn an asynchronous computation. +/// thread::spawn(move || s.send(fib(20)).unwrap()); +/// +/// // Print the result of the computation. +/// println!("{}", r.recv().unwrap()); +/// ``` +pub fn unbounded() -> (Sender, Receiver) { + let (s, r) = counter::new(flavors::list::Channel::new()); + let s = Sender { + flavor: SenderFlavor::List(s), + }; + let r = Receiver { + flavor: ReceiverFlavor::List(r), + }; + (s, r) +} + +/// Creates a channel of bounded capacity. +/// +/// This channel has a buffer that can hold at most `cap` messages at a time. +/// +/// A special case is zero-capacity channel, which cannot hold any messages. Instead, send and +/// receive operations must appear at the same time in order to pair up and pass the message over. +/// +/// # Examples +/// +/// A channel of capacity 1: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::bounded; +/// +/// let (s, r) = bounded(1); +/// +/// // This call returns immediately because there is enough space in the channel. +/// s.send(1).unwrap(); +/// +/// thread::spawn(move || { +/// // This call blocks the current thread because the channel is full. +/// // It will be able to complete only after the first message is received. +/// s.send(2).unwrap(); +/// }); +/// +/// thread::sleep(Duration::from_secs(1)); +/// assert_eq!(r.recv(), Ok(1)); +/// assert_eq!(r.recv(), Ok(2)); +/// ``` +/// +/// A zero-capacity channel: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::bounded; +/// +/// let (s, r) = bounded(0); +/// +/// thread::spawn(move || { +/// // This call blocks the current thread until a receive operation appears +/// // on the other side of the channel. +/// s.send(1).unwrap(); +/// }); +/// +/// thread::sleep(Duration::from_secs(1)); +/// assert_eq!(r.recv(), Ok(1)); +/// ``` +pub fn bounded(cap: usize) -> (Sender, Receiver) { + if cap == 0 { + let (s, r) = counter::new(flavors::zero::Channel::new()); + let s = Sender { + flavor: SenderFlavor::Zero(s), + }; + let r = Receiver { + flavor: ReceiverFlavor::Zero(r), + }; + (s, r) + } else { + let (s, r) = counter::new(flavors::array::Channel::with_capacity(cap)); + let s = Sender { + flavor: SenderFlavor::Array(s), + }; + let r = Receiver { + flavor: ReceiverFlavor::Array(r), + }; + (s, r) + } +} + +/// Creates a receiver that delivers a message after a certain duration of time. +/// +/// The channel is bounded with capacity of 1 and never gets disconnected. Exactly one message will +/// be sent into the channel after `duration` elapses. The message is the instant at which it is +/// sent. +/// +/// # Examples +/// +/// Using an `after` channel for timeouts: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::time::Duration; +/// use crossbeam_channel::{after, unbounded}; +/// +/// let (s, r) = unbounded::(); +/// let timeout = Duration::from_millis(100); +/// +/// select! { +/// recv(r) -> msg => println!("received {:?}", msg), +/// recv(after(timeout)) -> _ => println!("timed out"), +/// } +/// # } +/// ``` +/// +/// When the message gets sent: +/// +/// ``` +/// use std::thread; +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::after; +/// +/// // Converts a number of milliseconds into a `Duration`. +/// let ms = |ms| Duration::from_millis(ms); +/// +/// // Returns `true` if `a` and `b` are very close `Instant`s. +/// let eq = |a, b| a + ms(50) > b && b + ms(50) > a; +/// +/// let start = Instant::now(); +/// let r = after(ms(100)); +/// +/// thread::sleep(ms(500)); +/// +/// // This message was sent 100 ms from the start and received 500 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(100))); +/// assert!(eq(Instant::now(), start + ms(500))); +/// ``` +pub fn after(duration: Duration) -> Receiver { + Receiver { + flavor: ReceiverFlavor::After(Arc::new(flavors::after::Channel::new(duration))), + } +} + +/// Creates a receiver that never delivers messages. +/// +/// The channel is bounded with capacity of 0 and never gets disconnected. +/// +/// # Examples +/// +/// Using a `never` channel to optionally add a timeout to [`select!`]: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::{after, never, unbounded}; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s.send(1).unwrap(); +/// }); +/// +/// // Suppose this duration can be a `Some` or a `None`. +/// let duration = Some(Duration::from_millis(100)); +/// +/// // Create a channel that times out after the specified duration. +/// let timeout = duration +/// .map(|d| after(d)) +/// .unwrap_or(never()); +/// +/// select! { +/// recv(r) -> msg => assert_eq!(msg, Ok(1)), +/// recv(timeout) -> _ => println!("timed out"), +/// } +/// # } +/// ``` +/// +/// [`select!`]: macro.select.html +pub fn never() -> Receiver { + Receiver { + flavor: ReceiverFlavor::Never(flavors::never::Channel::new()), + } +} + +/// Creates a receiver that delivers messages periodically. +/// +/// The channel is bounded with capacity of 1 and never gets disconnected. Messages will be +/// sent into the channel in intervals of `duration`. Each message is the instant at which it is +/// sent. +/// +/// # Examples +/// +/// Using a `tick` channel to periodically print elapsed time: +/// +/// ``` +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::tick; +/// +/// let start = Instant::now(); +/// let ticker = tick(Duration::from_millis(100)); +/// +/// for _ in 0..5 { +/// ticker.recv().unwrap(); +/// println!("elapsed: {:?}", start.elapsed()); +/// } +/// ``` +/// +/// When messages get sent: +/// +/// ``` +/// use std::thread; +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::tick; +/// +/// // Converts a number of milliseconds into a `Duration`. +/// let ms = |ms| Duration::from_millis(ms); +/// +/// // Returns `true` if `a` and `b` are very close `Instant`s. +/// let eq = |a, b| a + ms(50) > b && b + ms(50) > a; +/// +/// let start = Instant::now(); +/// let r = tick(ms(100)); +/// +/// // This message was sent 100 ms from the start and received 100 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(100))); +/// assert!(eq(Instant::now(), start + ms(100))); +/// +/// thread::sleep(ms(500)); +/// +/// // This message was sent 200 ms from the start and received 600 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(200))); +/// assert!(eq(Instant::now(), start + ms(600))); +/// +/// // This message was sent 700 ms from the start and received 700 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(700))); +/// assert!(eq(Instant::now(), start + ms(700))); +/// ``` +pub fn tick(duration: Duration) -> Receiver { + Receiver { + flavor: ReceiverFlavor::Tick(Arc::new(flavors::tick::Channel::new(duration))), + } +} + +/// The sending side of a channel. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s1, r) = unbounded(); +/// let s2 = s1.clone(); +/// +/// thread::spawn(move || s1.send(1).unwrap()); +/// thread::spawn(move || s2.send(2).unwrap()); +/// +/// let msg1 = r.recv().unwrap(); +/// let msg2 = r.recv().unwrap(); +/// +/// assert_eq!(msg1 + msg2, 3); +/// ``` +pub struct Sender { + flavor: SenderFlavor, +} + +/// Sender flavors. +enum SenderFlavor { + /// Bounded channel based on a preallocated array. + Array(counter::Sender>), + + /// Unbounded channel implemented as a linked list. + List(counter::Sender>), + + /// Zero-capacity channel. + Zero(counter::Sender>), +} + +unsafe impl Send for Sender {} +unsafe impl Sync for Sender {} + +impl UnwindSafe for Sender {} +impl RefUnwindSafe for Sender {} + +impl Sender { + /// Attempts to send a message into the channel without blocking. + /// + /// This method will either send a message into the channel immediately or return an error if + /// the channel is full or disconnected. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will send the message only if there + /// happens to be a receive operation on the other side of the channel at the same time. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, TrySendError}; + /// + /// let (s, r) = bounded(1); + /// + /// assert_eq!(s.try_send(1), Ok(())); + /// assert_eq!(s.try_send(2), Err(TrySendError::Full(2))); + /// + /// drop(r); + /// assert_eq!(s.try_send(3), Err(TrySendError::Disconnected(3))); + /// ``` + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + match &self.flavor { + SenderFlavor::Array(chan) => chan.try_send(msg), + SenderFlavor::List(chan) => chan.try_send(msg), + SenderFlavor::Zero(chan) => chan.try_send(msg), + } + } + + /// Blocks the current thread until a message is sent or the channel is disconnected. + /// + /// If the channel is full and not disconnected, this call will block until the send operation + /// can proceed. If the channel becomes disconnected, this call will wake up and return an + /// error. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will wait for a receive operation to + /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{bounded, SendError}; + /// + /// let (s, r) = bounded(1); + /// assert_eq!(s.send(1), Ok(())); + /// + /// thread::spawn(move || { + /// assert_eq!(r.recv(), Ok(1)); + /// thread::sleep(Duration::from_secs(1)); + /// drop(r); + /// }); + /// + /// assert_eq!(s.send(2), Ok(())); + /// assert_eq!(s.send(3), Err(SendError(3))); + /// ``` + pub fn send(&self, msg: T) -> Result<(), SendError> { + match &self.flavor { + SenderFlavor::Array(chan) => chan.send(msg, None), + SenderFlavor::List(chan) => chan.send(msg, None), + SenderFlavor::Zero(chan) => chan.send(msg, None), + } + .map_err(|err| match err { + SendTimeoutError::Disconnected(msg) => SendError(msg), + SendTimeoutError::Timeout(_) => unreachable!(), + }) + } + + /// Waits for a message to be sent into the channel, but only for a limited time. + /// + /// If the channel is full and not disconnected, this call will block until the send operation + /// can proceed or the operation times out. If the channel becomes disconnected, this call will + /// wake up and return an error. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will wait for a receive operation to + /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{bounded, SendTimeoutError}; + /// + /// let (s, r) = bounded(0); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// assert_eq!(r.recv(), Ok(2)); + /// drop(r); + /// }); + /// + /// assert_eq!( + /// s.send_timeout(1, Duration::from_millis(500)), + /// Err(SendTimeoutError::Timeout(1)), + /// ); + /// assert_eq!( + /// s.send_timeout(2, Duration::from_secs(1)), + /// Ok(()), + /// ); + /// assert_eq!( + /// s.send_timeout(3, Duration::from_millis(500)), + /// Err(SendTimeoutError::Disconnected(3)), + /// ); + /// ``` + pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError> { + let deadline = Instant::now() + timeout; + + match &self.flavor { + SenderFlavor::Array(chan) => chan.send(msg, Some(deadline)), + SenderFlavor::List(chan) => chan.send(msg, Some(deadline)), + SenderFlavor::Zero(chan) => chan.send(msg, Some(deadline)), + } + } + + /// Returns `true` if the channel is empty. + /// + /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// assert!(s.is_empty()); + /// + /// s.send(0).unwrap(); + /// assert!(!s.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.is_empty(), + SenderFlavor::List(chan) => chan.is_empty(), + SenderFlavor::Zero(chan) => chan.is_empty(), + } + } + + /// Returns `true` if the channel is full. + /// + /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::bounded; + /// + /// let (s, r) = bounded(1); + /// + /// assert!(!s.is_full()); + /// s.send(0).unwrap(); + /// assert!(s.is_full()); + /// ``` + pub fn is_full(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.is_full(), + SenderFlavor::List(chan) => chan.is_full(), + SenderFlavor::Zero(chan) => chan.is_full(), + } + } + + /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// assert_eq!(s.len(), 0); + /// + /// s.send(1).unwrap(); + /// s.send(2).unwrap(); + /// assert_eq!(s.len(), 2); + /// ``` + pub fn len(&self) -> usize { + match &self.flavor { + SenderFlavor::Array(chan) => chan.len(), + SenderFlavor::List(chan) => chan.len(), + SenderFlavor::Zero(chan) => chan.len(), + } + } + + /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, unbounded}; + /// + /// let (s, _) = unbounded::(); + /// assert_eq!(s.capacity(), None); + /// + /// let (s, _) = bounded::(5); + /// assert_eq!(s.capacity(), Some(5)); + /// + /// let (s, _) = bounded::(0); + /// assert_eq!(s.capacity(), Some(0)); + /// ``` + pub fn capacity(&self) -> Option { + match &self.flavor { + SenderFlavor::Array(chan) => chan.capacity(), + SenderFlavor::List(chan) => chan.capacity(), + SenderFlavor::Zero(chan) => chan.capacity(), + } + } + + /// Returns `true` if senders belong to the same channel. + /// + /// # Examples + /// + /// ```rust + /// use crossbeam_channel::unbounded; + /// + /// let (s, _) = unbounded::(); + /// + /// let s2 = s.clone(); + /// assert!(s.same_channel(&s2)); + /// + /// let (s3, _) = unbounded(); + /// assert!(!s.same_channel(&s3)); + /// ``` + pub fn same_channel(&self, other: &Sender) -> bool { + match (&self.flavor, &other.flavor) { + (SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b, + (SenderFlavor::List(ref a), SenderFlavor::List(ref b)) => a == b, + (SenderFlavor::Zero(ref a), SenderFlavor::Zero(ref b)) => a == b, + _ => false, + } + } +} + +impl Drop for Sender { + fn drop(&mut self) { + unsafe { + match &self.flavor { + SenderFlavor::Array(chan) => chan.release(|c| c.disconnect()), + SenderFlavor::List(chan) => chan.release(|c| c.disconnect()), + SenderFlavor::Zero(chan) => chan.release(|c| c.disconnect()), + } + } + } +} + +impl Clone for Sender { + fn clone(&self) -> Self { + let flavor = match &self.flavor { + SenderFlavor::Array(chan) => SenderFlavor::Array(chan.acquire()), + SenderFlavor::List(chan) => SenderFlavor::List(chan.acquire()), + SenderFlavor::Zero(chan) => SenderFlavor::Zero(chan.acquire()), + }; + + Sender { flavor } + } +} + +impl fmt::Debug for Sender { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Sender { .. }") + } +} + +/// The receiving side of a channel. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// s.send(1); +/// thread::sleep(Duration::from_secs(1)); +/// s.send(2); +/// }); +/// +/// assert_eq!(r.recv(), Ok(1)); // Received immediately. +/// assert_eq!(r.recv(), Ok(2)); // Received after 1 second. +/// ``` +pub struct Receiver { + flavor: ReceiverFlavor, +} + +/// Receiver flavors. +enum ReceiverFlavor { + /// Bounded channel based on a preallocated array. + Array(counter::Receiver>), + + /// Unbounded channel implemented as a linked list. + List(counter::Receiver>), + + /// Zero-capacity channel. + Zero(counter::Receiver>), + + /// The after flavor. + After(Arc), + + /// The tick flavor. + Tick(Arc), + + /// The never flavor. + Never(flavors::never::Channel), +} + +unsafe impl Send for Receiver {} +unsafe impl Sync for Receiver {} + +impl UnwindSafe for Receiver {} +impl RefUnwindSafe for Receiver {} + +impl Receiver { + /// Attempts to receive a message from the channel without blocking. + /// + /// This method will either receive a message from the channel immediately or return an error + /// if the channel is empty. + /// + /// If called on a zero-capacity channel, this method will receive a message only if there + /// happens to be a send operation on the other side of the channel at the same time. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{unbounded, TryRecvError}; + /// + /// let (s, r) = unbounded(); + /// assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + /// + /// s.send(5).unwrap(); + /// drop(s); + /// + /// assert_eq!(r.try_recv(), Ok(5)); + /// assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + /// ``` + pub fn try_recv(&self) -> Result { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.try_recv(), + ReceiverFlavor::List(chan) => chan.try_recv(), + ReceiverFlavor::Zero(chan) => chan.try_recv(), + ReceiverFlavor::After(chan) => { + let msg = chan.try_recv(); + unsafe { + mem::transmute_copy::, Result>( + &msg, + ) + } + } + ReceiverFlavor::Tick(chan) => { + let msg = chan.try_recv(); + unsafe { + mem::transmute_copy::, Result>( + &msg, + ) + } + } + ReceiverFlavor::Never(chan) => chan.try_recv(), + } + } + + /// Blocks the current thread until a message is received or the channel is empty and + /// disconnected. + /// + /// If the channel is empty and not disconnected, this call will block until the receive + /// operation can proceed. If the channel is empty and becomes disconnected, this call will + /// wake up and return an error. + /// + /// If called on a zero-capacity channel, this method will wait for a send operation to appear + /// on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, RecvError}; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s.send(5).unwrap(); + /// drop(s); + /// }); + /// + /// assert_eq!(r.recv(), Ok(5)); + /// assert_eq!(r.recv(), Err(RecvError)); + /// ``` + pub fn recv(&self) -> Result { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.recv(None), + ReceiverFlavor::List(chan) => chan.recv(None), + ReceiverFlavor::Zero(chan) => chan.recv(None), + ReceiverFlavor::After(chan) => { + let msg = chan.recv(None); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Tick(chan) => { + let msg = chan.recv(None); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Never(chan) => chan.recv(None), + } + .map_err(|_| RecvError) + } + + /// Waits for a message to be received from the channel, but only for a limited time. + /// + /// If the channel is empty and not disconnected, this call will block until the receive + /// operation can proceed or the operation times out. If the channel is empty and becomes + /// disconnected, this call will wake up and return an error. + /// + /// If called on a zero-capacity channel, this method will wait for a send operation to appear + /// on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, RecvTimeoutError}; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s.send(5).unwrap(); + /// drop(s); + /// }); + /// + /// assert_eq!( + /// r.recv_timeout(Duration::from_millis(500)), + /// Err(RecvTimeoutError::Timeout), + /// ); + /// assert_eq!( + /// r.recv_timeout(Duration::from_secs(1)), + /// Ok(5), + /// ); + /// assert_eq!( + /// r.recv_timeout(Duration::from_secs(1)), + /// Err(RecvTimeoutError::Disconnected), + /// ); + /// ``` + pub fn recv_timeout(&self, timeout: Duration) -> Result { + let deadline = Instant::now() + timeout; + + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::List(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::Zero(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::After(chan) => { + let msg = chan.recv(Some(deadline)); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Tick(chan) => { + let msg = chan.recv(Some(deadline)); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Never(chan) => chan.recv(Some(deadline)), + } + } + + /// Returns `true` if the channel is empty. + /// + /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// + /// assert!(r.is_empty()); + /// s.send(0).unwrap(); + /// assert!(!r.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.is_empty(), + ReceiverFlavor::List(chan) => chan.is_empty(), + ReceiverFlavor::Zero(chan) => chan.is_empty(), + ReceiverFlavor::After(chan) => chan.is_empty(), + ReceiverFlavor::Tick(chan) => chan.is_empty(), + ReceiverFlavor::Never(chan) => chan.is_empty(), + } + } + + /// Returns `true` if the channel is full. + /// + /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::bounded; + /// + /// let (s, r) = bounded(1); + /// + /// assert!(!r.is_full()); + /// s.send(0).unwrap(); + /// assert!(r.is_full()); + /// ``` + pub fn is_full(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.is_full(), + ReceiverFlavor::List(chan) => chan.is_full(), + ReceiverFlavor::Zero(chan) => chan.is_full(), + ReceiverFlavor::After(chan) => chan.is_full(), + ReceiverFlavor::Tick(chan) => chan.is_full(), + ReceiverFlavor::Never(chan) => chan.is_full(), + } + } + + /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// assert_eq!(r.len(), 0); + /// + /// s.send(1).unwrap(); + /// s.send(2).unwrap(); + /// assert_eq!(r.len(), 2); + /// ``` + pub fn len(&self) -> usize { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.len(), + ReceiverFlavor::List(chan) => chan.len(), + ReceiverFlavor::Zero(chan) => chan.len(), + ReceiverFlavor::After(chan) => chan.len(), + ReceiverFlavor::Tick(chan) => chan.len(), + ReceiverFlavor::Never(chan) => chan.len(), + } + } + + /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, unbounded}; + /// + /// let (_, r) = unbounded::(); + /// assert_eq!(r.capacity(), None); + /// + /// let (_, r) = bounded::(5); + /// assert_eq!(r.capacity(), Some(5)); + /// + /// let (_, r) = bounded::(0); + /// assert_eq!(r.capacity(), Some(0)); + /// ``` + pub fn capacity(&self) -> Option { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.capacity(), + ReceiverFlavor::List(chan) => chan.capacity(), + ReceiverFlavor::Zero(chan) => chan.capacity(), + ReceiverFlavor::After(chan) => chan.capacity(), + ReceiverFlavor::Tick(chan) => chan.capacity(), + ReceiverFlavor::Never(chan) => chan.capacity(), + } + } + + /// A blocking iterator over messages in the channel. + /// + /// Each call to [`next`] blocks waiting for the next message and then returns it. However, if + /// the channel becomes empty and disconnected, it returns [`None`] without blocking. + /// + /// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next + /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// s.send(1).unwrap(); + /// s.send(2).unwrap(); + /// s.send(3).unwrap(); + /// drop(s); // Disconnect the channel. + /// }); + /// + /// // Collect all messages from the channel. + /// // Note that the call to `collect` blocks until the sender is dropped. + /// let v: Vec<_> = r.iter().collect(); + /// + /// assert_eq!(v, [1, 2, 3]); + /// ``` + pub fn iter(&self) -> Iter { + Iter { receiver: self } + } + + /// A non-blocking iterator over messages in the channel. + /// + /// Each call to [`next`] returns a message if there is one ready to be received. The iterator + /// never blocks waiting for the next message. + /// + /// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded::(); + /// + /// thread::spawn(move || { + /// s.send(1).unwrap(); + /// thread::sleep(Duration::from_secs(1)); + /// s.send(2).unwrap(); + /// thread::sleep(Duration::from_secs(2)); + /// s.send(3).unwrap(); + /// }); + /// + /// thread::sleep(Duration::from_secs(2)); + /// + /// // Collect all messages from the channel without blocking. + /// // The third message hasn't been sent yet so we'll collect only the first two. + /// let v: Vec<_> = r.try_iter().collect(); + /// + /// assert_eq!(v, [1, 2]); + /// ``` + pub fn try_iter(&self) -> TryIter { + TryIter { receiver: self } + } + + /// Returns `true` if receivers belong to the same channel. + /// + /// # Examples + /// + /// ```rust + /// use crossbeam_channel::unbounded; + /// + /// let (_, r) = unbounded::(); + /// + /// let r2 = r.clone(); + /// assert!(r.same_channel(&r2)); + /// + /// let (_, r3) = unbounded(); + /// assert!(!r.same_channel(&r3)); + /// ``` + pub fn same_channel(&self, other: &Receiver) -> bool { + match (&self.flavor, &other.flavor) { + (ReceiverFlavor::Array(a), ReceiverFlavor::Array(b)) => a == b, + (ReceiverFlavor::List(a), ReceiverFlavor::List(b)) => a == b, + (ReceiverFlavor::Zero(a), ReceiverFlavor::Zero(b)) => a == b, + (ReceiverFlavor::After(a), ReceiverFlavor::After(b)) => Arc::ptr_eq(a, b), + (ReceiverFlavor::Tick(a), ReceiverFlavor::Tick(b)) => Arc::ptr_eq(a, b), + (ReceiverFlavor::Never(_), ReceiverFlavor::Never(_)) => true, + _ => false, + } + } +} + +impl Drop for Receiver { + fn drop(&mut self) { + unsafe { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::List(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::Zero(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::After(_) => {} + ReceiverFlavor::Tick(_) => {} + ReceiverFlavor::Never(_) => {} + } + } + } +} + +impl Clone for Receiver { + fn clone(&self) -> Self { + let flavor = match &self.flavor { + ReceiverFlavor::Array(chan) => ReceiverFlavor::Array(chan.acquire()), + ReceiverFlavor::List(chan) => ReceiverFlavor::List(chan.acquire()), + ReceiverFlavor::Zero(chan) => ReceiverFlavor::Zero(chan.acquire()), + ReceiverFlavor::After(chan) => ReceiverFlavor::After(chan.clone()), + ReceiverFlavor::Tick(chan) => ReceiverFlavor::Tick(chan.clone()), + ReceiverFlavor::Never(_) => ReceiverFlavor::Never(flavors::never::Channel::new()), + }; + + Receiver { flavor } + } +} + +impl fmt::Debug for Receiver { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Receiver { .. }") + } +} + +impl<'a, T> IntoIterator for &'a Receiver { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for Receiver { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { receiver: self } + } +} + +/// A blocking iterator over messages in a channel. +/// +/// Each call to [`next`] blocks waiting for the next message and then returns it. However, if the +/// channel becomes empty and disconnected, it returns [`None`] without blocking. +/// +/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next +/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// s.send(1).unwrap(); +/// s.send(2).unwrap(); +/// s.send(3).unwrap(); +/// drop(s); // Disconnect the channel. +/// }); +/// +/// // Collect all messages from the channel. +/// // Note that the call to `collect` blocks until the sender is dropped. +/// let v: Vec<_> = r.iter().collect(); +/// +/// assert_eq!(v, [1, 2, 3]); +/// ``` +pub struct Iter<'a, T: 'a> { + receiver: &'a Receiver, +} + +impl<'a, T> FusedIterator for Iter<'a, T> {} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.receiver.recv().ok() + } +} + +impl<'a, T> fmt::Debug for Iter<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Iter { .. }") + } +} + +/// A non-blocking iterator over messages in a channel. +/// +/// Each call to [`next`] returns a message if there is one ready to be received. The iterator +/// never blocks waiting for the next message. +/// +/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded::(); +/// +/// thread::spawn(move || { +/// s.send(1).unwrap(); +/// thread::sleep(Duration::from_secs(1)); +/// s.send(2).unwrap(); +/// thread::sleep(Duration::from_secs(2)); +/// s.send(3).unwrap(); +/// }); +/// +/// thread::sleep(Duration::from_secs(2)); +/// +/// // Collect all messages from the channel without blocking. +/// // The third message hasn't been sent yet so we'll collect only the first two. +/// let v: Vec<_> = r.try_iter().collect(); +/// +/// assert_eq!(v, [1, 2]); +/// ``` +pub struct TryIter<'a, T: 'a> { + receiver: &'a Receiver, +} + +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.receiver.try_recv().ok() + } +} + +impl<'a, T> fmt::Debug for TryIter<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("TryIter { .. }") + } +} + +/// A blocking iterator over messages in a channel. +/// +/// Each call to [`next`] blocks waiting for the next message and then returns it. However, if the +/// channel becomes empty and disconnected, it returns [`None`] without blocking. +/// +/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next +/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// s.send(1).unwrap(); +/// s.send(2).unwrap(); +/// s.send(3).unwrap(); +/// drop(s); // Disconnect the channel. +/// }); +/// +/// // Collect all messages from the channel. +/// // Note that the call to `collect` blocks until the sender is dropped. +/// let v: Vec<_> = r.into_iter().collect(); +/// +/// assert_eq!(v, [1, 2, 3]); +/// ``` +pub struct IntoIter { + receiver: Receiver, +} + +impl FusedIterator for IntoIter {} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + self.receiver.recv().ok() + } +} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("IntoIter { .. }") + } +} + +impl SelectHandle for Sender { + fn try_select(&self, token: &mut Token) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().try_select(token), + SenderFlavor::List(chan) => chan.sender().try_select(token), + SenderFlavor::Zero(chan) => chan.sender().try_select(token), + } + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().register(oper, cx), + SenderFlavor::List(chan) => chan.sender().register(oper, cx), + SenderFlavor::Zero(chan) => chan.sender().register(oper, cx), + } + } + + fn unregister(&self, oper: Operation) { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().unregister(oper), + SenderFlavor::List(chan) => chan.sender().unregister(oper), + SenderFlavor::Zero(chan) => chan.sender().unregister(oper), + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().accept(token, cx), + SenderFlavor::List(chan) => chan.sender().accept(token, cx), + SenderFlavor::Zero(chan) => chan.sender().accept(token, cx), + } + } + + fn is_ready(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().is_ready(), + SenderFlavor::List(chan) => chan.sender().is_ready(), + SenderFlavor::Zero(chan) => chan.sender().is_ready(), + } + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().watch(oper, cx), + SenderFlavor::List(chan) => chan.sender().watch(oper, cx), + SenderFlavor::Zero(chan) => chan.sender().watch(oper, cx), + } + } + + fn unwatch(&self, oper: Operation) { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().unwatch(oper), + SenderFlavor::List(chan) => chan.sender().unwatch(oper), + SenderFlavor::Zero(chan) => chan.sender().unwatch(oper), + } + } +} + +impl SelectHandle for Receiver { + fn try_select(&self, token: &mut Token) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().try_select(token), + ReceiverFlavor::List(chan) => chan.receiver().try_select(token), + ReceiverFlavor::Zero(chan) => chan.receiver().try_select(token), + ReceiverFlavor::After(chan) => chan.try_select(token), + ReceiverFlavor::Tick(chan) => chan.try_select(token), + ReceiverFlavor::Never(chan) => chan.try_select(token), + } + } + + fn deadline(&self) -> Option { + match &self.flavor { + ReceiverFlavor::Array(_) => None, + ReceiverFlavor::List(_) => None, + ReceiverFlavor::Zero(_) => None, + ReceiverFlavor::After(chan) => chan.deadline(), + ReceiverFlavor::Tick(chan) => chan.deadline(), + ReceiverFlavor::Never(chan) => chan.deadline(), + } + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().register(oper, cx), + ReceiverFlavor::List(chan) => chan.receiver().register(oper, cx), + ReceiverFlavor::Zero(chan) => chan.receiver().register(oper, cx), + ReceiverFlavor::After(chan) => chan.register(oper, cx), + ReceiverFlavor::Tick(chan) => chan.register(oper, cx), + ReceiverFlavor::Never(chan) => chan.register(oper, cx), + } + } + + fn unregister(&self, oper: Operation) { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().unregister(oper), + ReceiverFlavor::List(chan) => chan.receiver().unregister(oper), + ReceiverFlavor::Zero(chan) => chan.receiver().unregister(oper), + ReceiverFlavor::After(chan) => chan.unregister(oper), + ReceiverFlavor::Tick(chan) => chan.unregister(oper), + ReceiverFlavor::Never(chan) => chan.unregister(oper), + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().accept(token, cx), + ReceiverFlavor::List(chan) => chan.receiver().accept(token, cx), + ReceiverFlavor::Zero(chan) => chan.receiver().accept(token, cx), + ReceiverFlavor::After(chan) => chan.accept(token, cx), + ReceiverFlavor::Tick(chan) => chan.accept(token, cx), + ReceiverFlavor::Never(chan) => chan.accept(token, cx), + } + } + + fn is_ready(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().is_ready(), + ReceiverFlavor::List(chan) => chan.receiver().is_ready(), + ReceiverFlavor::Zero(chan) => chan.receiver().is_ready(), + ReceiverFlavor::After(chan) => chan.is_ready(), + ReceiverFlavor::Tick(chan) => chan.is_ready(), + ReceiverFlavor::Never(chan) => chan.is_ready(), + } + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().watch(oper, cx), + ReceiverFlavor::List(chan) => chan.receiver().watch(oper, cx), + ReceiverFlavor::Zero(chan) => chan.receiver().watch(oper, cx), + ReceiverFlavor::After(chan) => chan.watch(oper, cx), + ReceiverFlavor::Tick(chan) => chan.watch(oper, cx), + ReceiverFlavor::Never(chan) => chan.watch(oper, cx), + } + } + + fn unwatch(&self, oper: Operation) { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().unwatch(oper), + ReceiverFlavor::List(chan) => chan.receiver().unwatch(oper), + ReceiverFlavor::Zero(chan) => chan.receiver().unwatch(oper), + ReceiverFlavor::After(chan) => chan.unwatch(oper), + ReceiverFlavor::Tick(chan) => chan.unwatch(oper), + ReceiverFlavor::Never(chan) => chan.unwatch(oper), + } + } +} + +/// Writes a message into the channel. +pub unsafe fn write(s: &Sender, token: &mut Token, msg: T) -> Result<(), T> { + match &s.flavor { + SenderFlavor::Array(chan) => chan.write(token, msg), + SenderFlavor::List(chan) => chan.write(token, msg), + SenderFlavor::Zero(chan) => chan.write(token, msg), + } +} + +/// Reads a message from the channel. +pub unsafe fn read(r: &Receiver, token: &mut Token) -> Result { + match &r.flavor { + ReceiverFlavor::Array(chan) => chan.read(token), + ReceiverFlavor::List(chan) => chan.read(token), + ReceiverFlavor::Zero(chan) => chan.read(token), + ReceiverFlavor::After(chan) => { + mem::transmute_copy::, Result>(&chan.read(token)) + } + ReceiverFlavor::Tick(chan) => { + mem::transmute_copy::, Result>(&chan.read(token)) + } + ReceiverFlavor::Never(chan) => chan.read(token), + } +} diff --git a/vendor/crossbeam-channel/src/context.rs b/vendor/crossbeam-channel/src/context.rs new file mode 100644 index 0000000000..c6e5c15db3 --- /dev/null +++ b/vendor/crossbeam-channel/src/context.rs @@ -0,0 +1,191 @@ +//! Thread-local context used in select. + +use std::cell::Cell; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::thread::{self, Thread, ThreadId}; +use std::time::Instant; + +use crossbeam_utils::Backoff; + +use select::Selected; + +/// Thread-local context used in select. +#[derive(Debug, Clone)] +pub struct Context { + inner: Arc, +} + +/// Inner representation of `Context`. +#[derive(Debug)] +struct Inner { + /// Selected operation. + select: AtomicUsize, + + /// A slot into which another thread may store a pointer to its `Packet`. + packet: AtomicUsize, + + /// Thread handle. + thread: Thread, + + /// Thread id. + thread_id: ThreadId, +} + +impl Context { + /// Creates a new context for the duration of the closure. + #[inline] + pub fn with(f: F) -> R + where + F: FnOnce(&Context) -> R, + { + thread_local! { + /// Cached thread-local context. + static CONTEXT: Cell> = Cell::new(Some(Context::new())); + } + + let mut f = Some(f); + let mut f = move |cx: &Context| -> R { + let f = f.take().unwrap(); + f(cx) + }; + + CONTEXT + .try_with(|cell| match cell.take() { + None => f(&Context::new()), + Some(cx) => { + cx.reset(); + let res = f(&cx); + cell.set(Some(cx)); + res + } + }) + .unwrap_or_else(|_| f(&Context::new())) + } + + /// Creates a new `Context`. + #[cold] + fn new() -> Context { + Context { + inner: Arc::new(Inner { + select: AtomicUsize::new(Selected::Waiting.into()), + packet: AtomicUsize::new(0), + thread: thread::current(), + thread_id: thread::current().id(), + }), + } + } + + /// Resets `select` and `packet`. + #[inline] + fn reset(&self) { + self.inner + .select + .store(Selected::Waiting.into(), Ordering::Release); + self.inner.packet.store(0, Ordering::Release); + } + + /// Attempts to select an operation. + /// + /// On failure, the previously selected operation is returned. + #[inline] + pub fn try_select(&self, select: Selected) -> Result<(), Selected> { + self.inner + .select + .compare_exchange( + Selected::Waiting.into(), + select.into(), + Ordering::AcqRel, + Ordering::Acquire, + ) + .map(|_| ()) + .map_err(|e| e.into()) + } + + /// Returns the selected operation. + #[inline] + pub fn selected(&self) -> Selected { + Selected::from(self.inner.select.load(Ordering::Acquire)) + } + + /// Stores a packet. + /// + /// This method must be called after `try_select` succeeds and there is a packet to provide. + #[inline] + pub fn store_packet(&self, packet: usize) { + if packet != 0 { + self.inner.packet.store(packet, Ordering::Release); + } + } + + /// Waits until a packet is provided and returns it. + #[inline] + pub fn wait_packet(&self) -> usize { + let backoff = Backoff::new(); + loop { + let packet = self.inner.packet.load(Ordering::Acquire); + if packet != 0 { + return packet; + } + backoff.snooze(); + } + } + + /// Waits until an operation is selected and returns it. + /// + /// If the deadline is reached, `Selected::Aborted` will be selected. + #[inline] + pub fn wait_until(&self, deadline: Option) -> Selected { + // Spin for a short time, waiting until an operation is selected. + let backoff = Backoff::new(); + loop { + let sel = Selected::from(self.inner.select.load(Ordering::Acquire)); + if sel != Selected::Waiting { + return sel; + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + loop { + // Check whether an operation has been selected. + let sel = Selected::from(self.inner.select.load(Ordering::Acquire)); + if sel != Selected::Waiting { + return sel; + } + + // If there's a deadline, park the current thread until the deadline is reached. + if let Some(end) = deadline { + let now = Instant::now(); + + if now < end { + thread::park_timeout(end - now); + } else { + // The deadline has been reached. Try aborting select. + return match self.try_select(Selected::Aborted) { + Ok(()) => Selected::Aborted, + Err(s) => s, + }; + } + } else { + thread::park(); + } + } + } + + /// Unparks the thread this context belongs to. + #[inline] + pub fn unpark(&self) { + self.inner.thread.unpark(); + } + + /// Returns the id of the thread this context belongs to. + #[inline] + pub fn thread_id(&self) -> ThreadId { + self.inner.thread_id + } +} diff --git a/vendor/crossbeam-channel/src/counter.rs b/vendor/crossbeam-channel/src/counter.rs new file mode 100644 index 0000000000..2eaf067820 --- /dev/null +++ b/vendor/crossbeam-channel/src/counter.rs @@ -0,0 +1,144 @@ +//! Reference counter for channels. + +use std::isize; +use std::ops; +use std::process; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; + +/// Reference counter internals. +struct Counter { + /// The number of senders associated with the channel. + senders: AtomicUsize, + + /// The number of receivers associated with the channel. + receivers: AtomicUsize, + + /// Set to `true` if the last sender or the last receiver reference deallocates the channel. + destroy: AtomicBool, + + /// The internal channel. + chan: C, +} + +/// Wraps a channel into the reference counter. +pub fn new(chan: C) -> (Sender, Receiver) { + let counter = Box::into_raw(Box::new(Counter { + senders: AtomicUsize::new(1), + receivers: AtomicUsize::new(1), + destroy: AtomicBool::new(false), + chan, + })); + let s = Sender { counter }; + let r = Receiver { counter }; + (s, r) +} + +/// The sending side. +pub struct Sender { + counter: *mut Counter, +} + +impl Sender { + /// Returns the internal `Counter`. + fn counter(&self) -> &Counter { + unsafe { &*self.counter } + } + + /// Acquires another sender reference. + pub fn acquire(&self) -> Sender { + let count = self.counter().senders.fetch_add(1, Ordering::Relaxed); + + // Cloning senders and calling `mem::forget` on the clones could potentially overflow the + // counter. It's very difficult to recover sensibly from such degenerate scenarios so we + // just abort when the count becomes very large. + if count > isize::MAX as usize { + process::abort(); + } + + Sender { + counter: self.counter, + } + } + + /// Releases the sender reference. + /// + /// Function `disconnect` will be called if this is the last sender reference. + pub unsafe fn release bool>(&self, disconnect: F) { + if self.counter().senders.fetch_sub(1, Ordering::AcqRel) == 1 { + disconnect(&self.counter().chan); + + if self.counter().destroy.swap(true, Ordering::AcqRel) { + drop(Box::from_raw(self.counter)); + } + } + } +} + +impl ops::Deref for Sender { + type Target = C; + + fn deref(&self) -> &C { + &self.counter().chan + } +} + +impl PartialEq for Sender { + fn eq(&self, other: &Sender) -> bool { + self.counter == other.counter + } +} + +/// The receiving side. +pub struct Receiver { + counter: *mut Counter, +} + +impl Receiver { + /// Returns the internal `Counter`. + fn counter(&self) -> &Counter { + unsafe { &*self.counter } + } + + /// Acquires another receiver reference. + pub fn acquire(&self) -> Receiver { + let count = self.counter().receivers.fetch_add(1, Ordering::Relaxed); + + // Cloning receivers and calling `mem::forget` on the clones could potentially overflow the + // counter. It's very difficult to recover sensibly from such degenerate scenarios so we + // just abort when the count becomes very large. + if count > isize::MAX as usize { + process::abort(); + } + + Receiver { + counter: self.counter, + } + } + + /// Releases the receiver reference. + /// + /// Function `disconnect` will be called if this is the last receiver reference. + pub unsafe fn release bool>(&self, disconnect: F) { + if self.counter().receivers.fetch_sub(1, Ordering::AcqRel) == 1 { + disconnect(&self.counter().chan); + + if self.counter().destroy.swap(true, Ordering::AcqRel) { + drop(Box::from_raw(self.counter)); + } + } + } +} + +impl ops::Deref for Receiver { + type Target = C; + + fn deref(&self) -> &C { + &self.counter().chan + } +} + +impl PartialEq for Receiver { + fn eq(&self, other: &Receiver) -> bool { + self.counter == other.counter + } +} diff --git a/vendor/crossbeam-channel/src/err.rs b/vendor/crossbeam-channel/src/err.rs new file mode 100644 index 0000000000..468ce5cd89 --- /dev/null +++ b/vendor/crossbeam-channel/src/err.rs @@ -0,0 +1,451 @@ +use std::error; +use std::fmt; + +/// An error returned from the [`send`] method. +/// +/// The message could not be sent because the channel is disconnected. +/// +/// The error contains the message so it can be recovered. +/// +/// [`send`]: struct.Sender.html#method.send +#[derive(PartialEq, Eq, Clone, Copy)] +pub struct SendError(pub T); + +/// An error returned from the [`try_send`] method. +/// +/// The error contains the message being sent so it can be recovered. +/// +/// [`try_send`]: struct.Sender.html#method.try_send +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum TrySendError { + /// The message could not be sent because the channel is full. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no receiver + /// available to receive the message at the time. + Full(T), + + /// The message could not be sent because the channel is disconnected. + Disconnected(T), +} + +/// An error returned from the [`send_timeout`] method. +/// +/// The error contains the message being sent so it can be recovered. +/// +/// [`send_timeout`]: struct.Sender.html#method.send_timeout +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum SendTimeoutError { + /// The message could not be sent because the channel is full and the operation timed out. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no receiver + /// available to receive the message and the operation timed out. + Timeout(T), + + /// The message could not be sent because the channel is disconnected. + Disconnected(T), +} + +/// An error returned from the [`recv`] method. +/// +/// A message could not be received because the channel is empty and disconnected. +/// +/// [`recv`]: struct.Receiver.html#method.recv +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct RecvError; + +/// An error returned from the [`try_recv`] method. +/// +/// [`try_recv`]: struct.Receiver.html#method.recv +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum TryRecvError { + /// A message could not be received because the channel is empty. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no sender + /// available to send a message at the time. + Empty, + + /// The message could not be received because the channel is empty and disconnected. + Disconnected, +} + +/// An error returned from the [`recv_timeout`] method. +/// +/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum RecvTimeoutError { + /// A message could not be received because the channel is empty and the operation timed out. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no sender + /// available to send a message and the operation timed out. + Timeout, + + /// The message could not be received because the channel is empty and disconnected. + Disconnected, +} + +/// An error returned from the [`try_select`] method. +/// +/// Failed because none of the channel operations were ready. +/// +/// [`try_select`]: struct.Select.html#method.try_select +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct TrySelectError; + +/// An error returned from the [`select_timeout`] method. +/// +/// Failed because none of the channel operations became ready before the timeout. +/// +/// [`select_timeout`]: struct.Select.html#method.select_timeout +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct SelectTimeoutError; + +/// An error returned from the [`try_ready`] method. +/// +/// Failed because none of the channel operations were ready. +/// +/// [`try_ready`]: struct.Select.html#method.try_ready +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct TryReadyError; + +/// An error returned from the [`ready_timeout`] method. +/// +/// Failed because none of the channel operations became ready before the timeout. +/// +/// [`ready_timeout`]: struct.Select.html#method.ready_timeout +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ReadyTimeoutError; + +impl fmt::Debug for SendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "SendError(..)".fmt(f) + } +} + +impl fmt::Display for SendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "sending on a disconnected channel".fmt(f) + } +} + +impl error::Error for SendError { + fn description(&self) -> &str { + "sending on a disconnected channel" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl SendError { + /// Unwraps the message. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// drop(r); + /// + /// if let Err(err) = s.send("foo") { + /// assert_eq!(err.into_inner(), "foo"); + /// } + /// ``` + pub fn into_inner(self) -> T { + self.0 + } +} + +impl fmt::Debug for TrySendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TrySendError::Full(..) => "Full(..)".fmt(f), + TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), + } + } +} + +impl fmt::Display for TrySendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TrySendError::Full(..) => "sending on a full channel".fmt(f), + TrySendError::Disconnected(..) => "sending on a disconnected channel".fmt(f), + } + } +} + +impl error::Error for TrySendError { + fn description(&self) -> &str { + match *self { + TrySendError::Full(..) => "sending on a full channel", + TrySendError::Disconnected(..) => "sending on a disconnected channel", + } + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl From> for TrySendError { + fn from(err: SendError) -> TrySendError { + match err { + SendError(t) => TrySendError::Disconnected(t), + } + } +} + +impl TrySendError { + /// Unwraps the message. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::bounded; + /// + /// let (s, r) = bounded(0); + /// + /// if let Err(err) = s.try_send("foo") { + /// assert_eq!(err.into_inner(), "foo"); + /// } + /// ``` + pub fn into_inner(self) -> T { + match self { + TrySendError::Full(v) => v, + TrySendError::Disconnected(v) => v, + } + } + + /// Returns `true` if the send operation failed because the channel is full. + pub fn is_full(&self) -> bool { + match self { + TrySendError::Full(_) => true, + _ => false, + } + } + + /// Returns `true` if the send operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + TrySendError::Disconnected(_) => true, + _ => false, + } + } +} + +impl fmt::Debug for SendTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "SendTimeoutError(..)".fmt(f) + } +} + +impl fmt::Display for SendTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + SendTimeoutError::Timeout(..) => "timed out waiting on send operation".fmt(f), + SendTimeoutError::Disconnected(..) => "sending on a disconnected channel".fmt(f), + } + } +} + +impl error::Error for SendTimeoutError { + fn description(&self) -> &str { + "sending on an empty and disconnected channel" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl From> for SendTimeoutError { + fn from(err: SendError) -> SendTimeoutError { + match err { + SendError(e) => SendTimeoutError::Disconnected(e), + } + } +} + +impl SendTimeoutError { + /// Unwraps the message. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// + /// if let Err(err) = s.send_timeout("foo", Duration::from_secs(1)) { + /// assert_eq!(err.into_inner(), "foo"); + /// } + /// ``` + pub fn into_inner(self) -> T { + match self { + SendTimeoutError::Timeout(v) => v, + SendTimeoutError::Disconnected(v) => v, + } + } + + /// Returns `true` if the send operation timed out. + pub fn is_timeout(&self) -> bool { + match self { + SendTimeoutError::Timeout(_) => true, + _ => false, + } + } + + /// Returns `true` if the send operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + SendTimeoutError::Disconnected(_) => true, + _ => false, + } + } +} + +impl fmt::Display for RecvError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "receiving on an empty and disconnected channel".fmt(f) + } +} + +impl error::Error for RecvError { + fn description(&self) -> &str { + "receiving on an empty and disconnected channel" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl fmt::Display for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TryRecvError::Empty => "receiving on an empty channel".fmt(f), + TryRecvError::Disconnected => "receiving on an empty and disconnected channel".fmt(f), + } + } +} + +impl error::Error for TryRecvError { + fn description(&self) -> &str { + match *self { + TryRecvError::Empty => "receiving on an empty channel", + TryRecvError::Disconnected => "receiving on an empty and disconnected channel", + } + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl From for TryRecvError { + fn from(err: RecvError) -> TryRecvError { + match err { + RecvError => TryRecvError::Disconnected, + } + } +} + +impl TryRecvError { + /// Returns `true` if the receive operation failed because the channel is empty. + pub fn is_empty(&self) -> bool { + match self { + TryRecvError::Empty => true, + _ => false, + } + } + + /// Returns `true` if the receive operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + TryRecvError::Disconnected => true, + _ => false, + } + } +} + +impl fmt::Display for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + RecvTimeoutError::Timeout => "timed out waiting on receive operation".fmt(f), + RecvTimeoutError::Disconnected => "channel is empty and disconnected".fmt(f), + } + } +} + +impl error::Error for RecvTimeoutError { + fn description(&self) -> &str { + match *self { + RecvTimeoutError::Timeout => "timed out waiting on receive operation", + RecvTimeoutError::Disconnected => "channel is empty and disconnected", + } + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl From for RecvTimeoutError { + fn from(err: RecvError) -> RecvTimeoutError { + match err { + RecvError => RecvTimeoutError::Disconnected, + } + } +} + +impl RecvTimeoutError { + /// Returns `true` if the receive operation timed out. + pub fn is_timeout(&self) -> bool { + match self { + RecvTimeoutError::Timeout => true, + _ => false, + } + } + + /// Returns `true` if the receive operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + RecvTimeoutError::Disconnected => true, + _ => false, + } + } +} + +impl fmt::Display for TrySelectError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "all operations in select would block".fmt(f) + } +} + +impl error::Error for TrySelectError { + fn description(&self) -> &str { + "all operations in select would block" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl fmt::Display for SelectTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "timed out waiting on select".fmt(f) + } +} + +impl error::Error for SelectTimeoutError { + fn description(&self) -> &str { + "timed out waiting on select" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} diff --git a/vendor/crossbeam-channel/src/flavors/after.rs b/vendor/crossbeam-channel/src/flavors/after.rs new file mode 100644 index 0000000000..b57f8a7879 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/after.rs @@ -0,0 +1,200 @@ +//! Channel that delivers a message after a certain amount of time. +//! +//! Messages cannot be sent into this kind of channel; they are materialized on demand. + +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::{Duration, Instant}; + +use context::Context; +use err::{RecvTimeoutError, TryRecvError}; +use select::{Operation, SelectHandle, Token}; +use utils; + +/// Result of a receive operation. +pub type AfterToken = Option; + +/// Channel that delivers a message after a certain amount of time. +pub struct Channel { + /// The instant at which the message will be delivered. + delivery_time: Instant, + + /// `true` if the message has been received. + received: AtomicBool, +} + +impl Channel { + /// Creates a channel that delivers a message after a certain duration of time. + #[inline] + pub fn new(dur: Duration) -> Self { + Channel { + delivery_time: Instant::now() + dur, + received: AtomicBool::new(false), + } + } + + /// Attempts to receive a message without blocking. + #[inline] + pub fn try_recv(&self) -> Result { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + // The message has already been received. + return Err(TryRecvError::Empty); + } + + if Instant::now() < self.delivery_time { + // The message was not delivered yet. + return Err(TryRecvError::Empty); + } + + // Try receiving the message if it is still available. + if !self.received.swap(true, Ordering::SeqCst) { + // Success! Return delivery time as the message. + Ok(self.delivery_time) + } else { + // The message was already received. + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + #[inline] + pub fn recv(&self, deadline: Option) -> Result { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + // The message has already been received. + utils::sleep_until(deadline); + return Err(RecvTimeoutError::Timeout); + } + + // Wait until the message is received or the deadline is reached. + loop { + let now = Instant::now(); + + // Check if we can receive the next message. + if now >= self.delivery_time { + break; + } + + // Check if the deadline has been reached. + if let Some(d) = deadline { + if now >= d { + return Err(RecvTimeoutError::Timeout); + } + + thread::sleep(self.delivery_time.min(d) - now); + } else { + thread::sleep(self.delivery_time - now); + } + } + + // Try receiving the message if it is still available. + if !self.received.swap(true, Ordering::SeqCst) { + // Success! Return the message, which is the instant at which it was delivered. + Ok(self.delivery_time) + } else { + // The message was already received. Block forever. + utils::sleep_until(None); + unreachable!() + } + } + + /// Reads a message from the channel. + #[inline] + pub unsafe fn read(&self, token: &mut Token) -> Result { + token.after.ok_or(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub fn is_empty(&self) -> bool { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + return true; + } + + // If the delivery time hasn't been reached yet, the channel is empty. + if Instant::now() < self.delivery_time { + return true; + } + + // The delivery time has been reached. The channel is empty only if the message has already + // been received. + self.received.load(Ordering::SeqCst) + } + + /// Returns `true` if the channel is full. + #[inline] + pub fn is_full(&self) -> bool { + !self.is_empty() + } + + /// Returns the number of messages in the channel. + #[inline] + pub fn len(&self) -> usize { + if self.is_empty() { + 0 + } else { + 1 + } + } + + /// Returns the capacity of the channel. + #[inline] + pub fn capacity(&self) -> Option { + Some(1) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, token: &mut Token) -> bool { + match self.try_recv() { + Ok(msg) => { + token.after = Some(msg); + true + } + Err(TryRecvError::Disconnected) => { + token.after = None; + true + } + Err(TryRecvError::Empty) => false, + } + } + + #[inline] + fn deadline(&self) -> Option { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + None + } else { + Some(self.delivery_time) + } + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + !self.is_empty() + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/vendor/crossbeam-channel/src/flavors/array.rs b/vendor/crossbeam-channel/src/flavors/array.rs new file mode 100644 index 0000000000..659fce69a1 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/array.rs @@ -0,0 +1,639 @@ +//! Bounded channel based on a preallocated array. +//! +//! This flavor has a fixed, positive capacity. +//! +//! The implementation is based on Dmitry Vyukov's bounded MPMC queue. +//! +//! Source: +//! - http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue +//! - https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub +//! +//! Copyright & License: +//! - Copyright (c) 2010-2011 Dmitry Vyukov +//! - Simplified BSD License and Apache License, Version 2.0 +//! - http://www.1024cores.net/home/code-license + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::mem; +use std::ptr; +use std::sync::atomic::{self, AtomicUsize, Ordering}; +use std::time::Instant; + +use crossbeam_utils::{Backoff, CachePadded}; + +use maybe_uninit::MaybeUninit; + +use context::Context; +use err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; +use select::{Operation, SelectHandle, Selected, Token}; +use waker::SyncWaker; + +/// A slot in a channel. +struct Slot { + /// The current stamp. + stamp: AtomicUsize, + + /// The message in this slot. + msg: UnsafeCell>, +} + +/// The token type for the array flavor. +#[derive(Debug)] +pub struct ArrayToken { + /// Slot to read from or write to. + slot: *const u8, + + /// Stamp to store into the slot after reading or writing. + stamp: usize, +} + +impl Default for ArrayToken { + #[inline] + fn default() -> Self { + ArrayToken { + slot: ptr::null(), + stamp: 0, + } + } +} + +/// Bounded channel based on a preallocated array. +pub struct Channel { + /// The head of the channel. + /// + /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but + /// packed into a single `usize`. The lower bits represent the index, while the upper bits + /// represent the lap. The mark bit in the head is always zero. + /// + /// Messages are popped from the head of the channel. + head: CachePadded, + + /// The tail of the channel. + /// + /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but + /// packed into a single `usize`. The lower bits represent the index, while the upper bits + /// represent the lap. The mark bit indicates that the channel is disconnected. + /// + /// Messages are pushed into the tail of the channel. + tail: CachePadded, + + /// The buffer holding slots. + buffer: *mut Slot, + + /// The channel capacity. + cap: usize, + + /// A stamp with the value of `{ lap: 1, mark: 0, index: 0 }`. + one_lap: usize, + + /// If this bit is set in the tail, that means the channel is disconnected. + mark_bit: usize, + + /// Senders waiting while the channel is full. + senders: SyncWaker, + + /// Receivers waiting while the channel is empty and not disconnected. + receivers: SyncWaker, + + /// Indicates that dropping a `Channel` may drop values of type `T`. + _marker: PhantomData, +} + +impl Channel { + /// Creates a bounded channel of capacity `cap`. + pub fn with_capacity(cap: usize) -> Self { + assert!(cap > 0, "capacity must be positive"); + + // Compute constants `mark_bit` and `one_lap`. + let mark_bit = (cap + 1).next_power_of_two(); + let one_lap = mark_bit * 2; + + // Head is initialized to `{ lap: 0, mark: 0, index: 0 }`. + let head = 0; + // Tail is initialized to `{ lap: 0, mark: 0, index: 0 }`. + let tail = 0; + + // Allocate a buffer of `cap` slots. + let buffer = { + let mut v = Vec::>::with_capacity(cap); + let ptr = v.as_mut_ptr(); + mem::forget(v); + ptr + }; + + // Initialize stamps in the slots. + for i in 0..cap { + unsafe { + // Set the stamp to `{ lap: 0, mark: 0, index: i }`. + let slot = buffer.add(i); + ptr::write(&mut (*slot).stamp, AtomicUsize::new(i)); + } + } + + Channel { + buffer, + cap, + one_lap, + mark_bit, + head: CachePadded::new(AtomicUsize::new(head)), + tail: CachePadded::new(AtomicUsize::new(tail)), + senders: SyncWaker::new(), + receivers: SyncWaker::new(), + _marker: PhantomData, + } + } + + /// Returns a receiver handle to the channel. + pub fn receiver(&self) -> Receiver { + Receiver(self) + } + + /// Returns a sender handle to the channel. + pub fn sender(&self) -> Sender { + Sender(self) + } + + /// Attempts to reserve a slot for sending a message. + fn start_send(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut tail = self.tail.load(Ordering::Relaxed); + + loop { + // Check if the channel is disconnected. + if tail & self.mark_bit != 0 { + token.array.slot = ptr::null(); + token.array.stamp = 0; + return true; + } + + // Deconstruct the tail. + let index = tail & (self.mark_bit - 1); + let lap = tail & !(self.one_lap - 1); + + // Inspect the corresponding slot. + let slot = unsafe { &*self.buffer.add(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the tail and the stamp match, we may attempt to push. + if tail == stamp { + let new_tail = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. + tail + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. + lap.wrapping_add(self.one_lap) + }; + + // Try moving the tail. + match self.tail.compare_exchange_weak( + tail, + new_tail, + Ordering::SeqCst, + Ordering::Relaxed, + ) { + Ok(_) => { + // Prepare the token for the follow-up call to `write`. + token.array.slot = slot as *const Slot as *const u8; + token.array.stamp = tail + 1; + return true; + } + Err(t) => { + tail = t; + backoff.spin(); + } + } + } else if stamp.wrapping_add(self.one_lap) == tail + 1 { + atomic::fence(Ordering::SeqCst); + let head = self.head.load(Ordering::Relaxed); + + // If the head lags one lap behind the tail as well... + if head.wrapping_add(self.one_lap) == tail { + // ...then the channel is full. + return false; + } + + backoff.spin(); + tail = self.tail.load(Ordering::Relaxed); + } else { + // Snooze because we need to wait for the stamp to get updated. + backoff.snooze(); + tail = self.tail.load(Ordering::Relaxed); + } + } + } + + /// Writes a message into the channel. + pub unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> { + // If there is no slot, the channel is disconnected. + if token.array.slot.is_null() { + return Err(msg); + } + + let slot: &Slot = &*(token.array.slot as *const Slot); + + // Write the message into the slot and update the stamp. + slot.msg.get().write(MaybeUninit::new(msg)); + slot.stamp.store(token.array.stamp, Ordering::Release); + + // Wake a sleeping receiver. + self.receivers.notify(); + Ok(()) + } + + /// Attempts to reserve a slot for receiving a message. + fn start_recv(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut head = self.head.load(Ordering::Relaxed); + + loop { + // Deconstruct the head. + let index = head & (self.mark_bit - 1); + let lap = head & !(self.one_lap - 1); + + // Inspect the corresponding slot. + let slot = unsafe { &*self.buffer.add(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the the stamp is ahead of the head by 1, we may attempt to pop. + if head + 1 == stamp { + let new = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. + head + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. + lap.wrapping_add(self.one_lap) + }; + + // Try moving the head. + match self.head.compare_exchange_weak( + head, + new, + Ordering::SeqCst, + Ordering::Relaxed, + ) { + Ok(_) => { + // Prepare the token for the follow-up call to `read`. + token.array.slot = slot as *const Slot as *const u8; + token.array.stamp = head.wrapping_add(self.one_lap); + return true; + } + 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 & !self.mark_bit) == head { + // If the channel is disconnected... + if tail & self.mark_bit != 0 { + // ...then receive an error. + token.array.slot = ptr::null(); + token.array.stamp = 0; + return true; + } else { + // Otherwise, the receive operation is not ready. + return false; + } + } + + backoff.spin(); + head = self.head.load(Ordering::Relaxed); + } else { + // Snooze because we need to wait for the stamp to get updated. + backoff.snooze(); + head = self.head.load(Ordering::Relaxed); + } + } + } + + /// Reads a message from the channel. + pub unsafe fn read(&self, token: &mut Token) -> Result { + if token.array.slot.is_null() { + // The channel is disconnected. + return Err(()); + } + + let slot: &Slot = &*(token.array.slot as *const Slot); + + // Read the message from the slot and update the stamp. + let msg = slot.msg.get().read().assume_init(); + slot.stamp.store(token.array.stamp, Ordering::Release); + + // Wake a sleeping sender. + self.senders.notify(); + Ok(msg) + } + + /// Attempts to send a message into the channel. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + let token = &mut Token::default(); + if self.start_send(token) { + unsafe { self.write(token, msg).map_err(TrySendError::Disconnected) } + } else { + Err(TrySendError::Full(msg)) + } + } + + /// Sends a message into the channel. + pub fn send(&self, msg: T, deadline: Option) -> Result<(), SendTimeoutError> { + let token = &mut Token::default(); + loop { + // Try sending a message several times. + let backoff = Backoff::new(); + loop { + if self.start_send(token) { + let res = unsafe { self.write(token, msg) }; + return res.map_err(SendTimeoutError::Disconnected); + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + if let Some(d) = deadline { + if Instant::now() >= d { + return Err(SendTimeoutError::Timeout(msg)); + } + } + + Context::with(|cx| { + // Prepare for blocking until a receiver wakes us up. + let oper = Operation::hook(token); + self.senders.register(oper, cx); + + // Has the channel become ready just now? + if !self.is_full() || self.is_disconnected() { + let _ = cx.try_select(Selected::Aborted); + } + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted | Selected::Disconnected => { + self.senders.unregister(oper).unwrap(); + } + Selected::Operation(_) => {} + } + }); + } + } + + /// Attempts to receive a message without blocking. + pub fn try_recv(&self) -> Result { + let token = &mut Token::default(); + + if self.start_recv(token) { + unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) } + } else { + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + pub fn recv(&self, deadline: Option) -> Result { + let token = &mut Token::default(); + loop { + // Try receiving a message several times. + let backoff = Backoff::new(); + loop { + if self.start_recv(token) { + let res = unsafe { self.read(token) }; + return res.map_err(|_| RecvTimeoutError::Disconnected); + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + if let Some(d) = deadline { + if Instant::now() >= d { + return Err(RecvTimeoutError::Timeout); + } + } + + Context::with(|cx| { + // Prepare for blocking until a sender wakes us up. + let oper = Operation::hook(token); + self.receivers.register(oper, cx); + + // Has the channel become ready just now? + if !self.is_empty() || self.is_disconnected() { + let _ = cx.try_select(Selected::Aborted); + } + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted | Selected::Disconnected => { + self.receivers.unregister(oper).unwrap(); + // If the channel was disconnected, we still have to check for remaining + // messages. + } + Selected::Operation(_) => {} + } + }); + } + } + + /// Returns the current number of messages inside the channel. + pub fn len(&self) -> usize { + loop { + // Load the tail, then load the head. + let tail = self.tail.load(Ordering::SeqCst); + let head = self.head.load(Ordering::SeqCst); + + // If the tail didn't change, we've got consistent values to work with. + if self.tail.load(Ordering::SeqCst) == tail { + let hix = head & (self.mark_bit - 1); + let tix = tail & (self.mark_bit - 1); + + return if hix < tix { + tix - hix + } else if hix > tix { + self.cap - hix + tix + } else if (tail & !self.mark_bit) == head { + 0 + } else { + self.cap + }; + } + } + } + + /// Returns the capacity of the channel. + pub fn capacity(&self) -> Option { + Some(self.cap) + } + + /// Disconnects the channel and wakes up all blocked senders and receivers. + /// + /// Returns `true` if this call disconnected the channel. + pub fn disconnect(&self) -> bool { + let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst); + + if tail & self.mark_bit == 0 { + self.senders.disconnect(); + self.receivers.disconnect(); + true + } else { + false + } + } + + /// Returns `true` if the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + self.tail.load(Ordering::SeqCst) & self.mark_bit != 0 + } + + /// Returns `true` if the channel 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 equal to the head? + // + // Note: If the head changes just before we load the tail, that means there was a moment + // when the channel was not empty, so it is safe to just return `false`. + (tail & !self.mark_bit) == head + } + + /// Returns `true` if the channel is full. + pub fn is_full(&self) -> bool { + let tail = self.tail.load(Ordering::SeqCst); + let head = self.head.load(Ordering::SeqCst); + + // Is the head lagging one lap behind tail? + // + // Note: If the tail changes just before we load the head, that means there was a moment + // when the channel was not full, so it is safe to just return `false`. + head.wrapping_add(self.one_lap) == tail & !self.mark_bit + } +} + +impl Drop for Channel { + fn drop(&mut self) { + // Get the index of the head. + let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1); + + // Loop over all slots that hold a message and drop them. + for i in 0..self.len() { + // Compute the index of the next slot holding a message. + let index = if hix + i < self.cap { + hix + i + } else { + hix + i - self.cap + }; + + unsafe { + let p = { + let slot = &mut *self.buffer.add(index); + let msg = &mut *slot.msg.get(); + msg.as_mut_ptr() + }; + p.drop_in_place(); + } + } + + // Finally, deallocate the buffer, but don't run any destructors. + unsafe { + Vec::from_raw_parts(self.buffer, 0, self.cap); + } + } +} + +/// Receiver handle to a channel. +pub struct Receiver<'a, T: 'a>(&'a Channel); + +/// Sender handle to a channel. +pub struct Sender<'a, T: 'a>(&'a Channel); + +impl<'a, T> SelectHandle for Receiver<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_recv(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.register(oper, cx); + self.is_ready() + } + + fn unregister(&self, oper: Operation) { + self.0.receivers.unregister(oper); + } + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + !self.0.is_empty() || self.0.is_disconnected() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.watch(oper, cx); + self.is_ready() + } + + fn unwatch(&self, oper: Operation) { + self.0.receivers.unwatch(oper); + } +} + +impl<'a, T> SelectHandle for Sender<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_send(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + self.0.senders.register(oper, cx); + self.is_ready() + } + + fn unregister(&self, oper: Operation) { + self.0.senders.unregister(oper); + } + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + !self.0.is_full() || self.0.is_disconnected() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + self.0.senders.watch(oper, cx); + self.is_ready() + } + + fn unwatch(&self, oper: Operation) { + self.0.senders.unwatch(oper); + } +} diff --git a/vendor/crossbeam-channel/src/flavors/list.rs b/vendor/crossbeam-channel/src/flavors/list.rs new file mode 100644 index 0000000000..dd9e6e9dee --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/list.rs @@ -0,0 +1,671 @@ +//! Unbounded channel implemented as a linked list. + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::ptr; +use std::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; +use std::time::Instant; + +use crossbeam_utils::{Backoff, CachePadded}; + +use maybe_uninit::MaybeUninit; + +use context::Context; +use err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; +use select::{Operation, SelectHandle, Selected, Token}; +use waker::SyncWaker; + +// TODO(stjepang): Once we bump the minimum required Rust version to 1.28 or newer, re-apply the +// following changes by @kleimkuhler: +// +// 1. https://github.com/crossbeam-rs/crossbeam-channel/pull/100 +// 2. https://github.com/crossbeam-rs/crossbeam-channel/pull/101 + +// Bits indicating the state of a slot: +// * If a message has been written into the slot, `WRITE` is set. +// * If a message has been read from the slot, `READ` is set. +// * If the block is being destroyed, `DESTROY` is set. +const WRITE: usize = 1; +const READ: usize = 2; +const DESTROY: usize = 4; + +// Each block covers one "lap" of indices. +const LAP: usize = 32; +// The maximum number of messages a block can hold. +const BLOCK_CAP: usize = LAP - 1; +// How many lower bits are reserved for metadata. +const SHIFT: usize = 1; +// Has two different purposes: +// * If set in head, indicates that the block is not the last one. +// * If set in tail, indicates that the channel is disconnected. +const MARK_BIT: usize = 1; + +/// A slot in a block. +struct Slot { + /// The message. + msg: UnsafeCell>, + + /// The state of the slot. + state: AtomicUsize, +} + +impl Slot { + /// Waits until a message is written into the slot. + fn wait_write(&self) { + let backoff = Backoff::new(); + while self.state.load(Ordering::Acquire) & WRITE == 0 { + backoff.snooze(); + } + } +} + +/// A block in a linked list. +/// +/// Each block in the list can hold up to `BLOCK_CAP` messages. +struct Block { + /// The next block in the linked list. + next: AtomicPtr>, + + /// Slots for messages. + slots: [Slot; BLOCK_CAP], +} + +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() } + } + + /// 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 channel. +#[derive(Debug)] +struct Position { + /// The index in the channel. + index: AtomicUsize, + + /// The block in the linked list. + block: AtomicPtr>, +} + +/// The token type for the list flavor. +#[derive(Debug)] +pub struct ListToken { + /// The block of slots. + block: *const u8, + + /// The offset into the block. + offset: usize, +} + +impl Default for ListToken { + #[inline] + fn default() -> Self { + ListToken { + block: ptr::null(), + offset: 0, + } + } +} + +/// Unbounded channel implemented as a linked list. +/// +/// Each message sent into the channel is assigned a sequence number, i.e. an index. Indices are +/// represented as numbers of type `usize` and wrap on overflow. +/// +/// Consecutive messages are grouped into blocks in order to put less pressure on the allocator and +/// improve cache efficiency. +pub struct Channel { + /// The head of the channel. + head: CachePadded>, + + /// The tail of the channel. + tail: CachePadded>, + + /// Receivers waiting while the channel is empty and not disconnected. + receivers: SyncWaker, + + /// Indicates that dropping a `Channel` may drop messages of type `T`. + _marker: PhantomData, +} + +impl Channel { + /// Creates a new unbounded channel. + pub fn new() -> Self { + Channel { + head: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + tail: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + receivers: SyncWaker::new(), + _marker: PhantomData, + } + } + + /// Returns a receiver handle to the channel. + pub fn receiver(&self) -> Receiver { + Receiver(self) + } + + /// Returns a sender handle to the channel. + pub fn sender(&self) -> Sender { + Sender(self) + } + + /// Attempts to reserve a slot for sending a message. + fn start_send(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut tail = self.tail.index.load(Ordering::Acquire); + let mut block = self.tail.block.load(Ordering::Acquire); + let mut next_block = None; + + loop { + // Check if the channel is disconnected. + if tail & MARK_BIT != 0 { + token.list.block = ptr::null(); + return true; + } + + // Calculate the offset of the index into the block. + let offset = (tail >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + tail = self.tail.index.load(Ordering::Acquire); + block = self.tail.block.load(Ordering::Acquire); + continue; + } + + // If we're going to have to install the next block, allocate it in advance in order to + // make the wait for other threads as short as possible. + if offset + 1 == BLOCK_CAP && next_block.is_none() { + next_block = Some(Box::new(Block::::new())); + } + + // If this is the first message to be sent into the channel, we need to allocate the + // first block and install it. + if block.is_null() { + let new = Box::into_raw(Box::new(Block::::new())); + + if self + .tail + .block + .compare_and_swap(block, new, Ordering::Release) + == block + { + self.head.block.store(new, Ordering::Release); + block = new; + } else { + next_block = unsafe { Some(Box::from_raw(new)) }; + tail = self.tail.index.load(Ordering::Acquire); + block = self.tail.block.load(Ordering::Acquire); + continue; + } + } + + let new_tail = tail + (1 << SHIFT); + + // Try advancing the tail forward. + match self.tail.index.compare_exchange_weak( + tail, + new_tail, + Ordering::SeqCst, + Ordering::Acquire, + ) { + Ok(_) => unsafe { + // If we've reached the end of the block, install the next one. + if offset + 1 == BLOCK_CAP { + let next_block = Box::into_raw(next_block.unwrap()); + self.tail.block.store(next_block, Ordering::Release); + self.tail.index.fetch_add(1 << SHIFT, Ordering::Release); + (*block).next.store(next_block, Ordering::Release); + } + + token.list.block = block as *const u8; + token.list.offset = offset; + return true; + }, + Err(t) => { + tail = t; + block = self.tail.block.load(Ordering::Acquire); + backoff.spin(); + } + } + } + } + + /// Writes a message into the channel. + pub unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> { + // If there is no slot, the channel is disconnected. + if token.list.block.is_null() { + return Err(msg); + } + + // Write the message into the slot. + let block = token.list.block as *mut Block; + let offset = token.list.offset; + let slot = (*block).slots.get_unchecked(offset); + slot.msg.get().write(MaybeUninit::new(msg)); + slot.state.fetch_or(WRITE, Ordering::Release); + + // Wake a sleeping receiver. + self.receivers.notify(); + Ok(()) + } + + /// Attempts to reserve a slot for receiving a message. + fn start_recv(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut head = self.head.index.load(Ordering::Acquire); + let mut block = self.head.block.load(Ordering::Acquire); + + loop { + // Calculate the offset of the index into the block. + let offset = (head >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + continue; + } + + let mut new_head = head + (1 << SHIFT); + + if new_head & MARK_BIT == 0 { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::Relaxed); + + // If the tail equals the head, that means the channel is empty. + if head >> SHIFT == tail >> SHIFT { + // If the channel is disconnected... + if tail & MARK_BIT != 0 { + // ...then receive an error. + token.list.block = ptr::null(); + return true; + } else { + // Otherwise, the receive operation is not ready. + return false; + } + } + + // If head and tail are not in the same block, set `MARK_BIT` in head. + if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { + new_head |= MARK_BIT; + } + } + + // The block can be null here only if the first message is being sent into the channel. + // In that case, just wait until it gets initialized. + if block.is_null() { + backoff.snooze(); + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + continue; + } + + // Try moving the head index forward. + match self.head.index.compare_exchange_weak( + head, + new_head, + Ordering::SeqCst, + Ordering::Acquire, + ) { + Ok(_) => unsafe { + // If we've reached the end of the block, move to the next one. + if offset + 1 == BLOCK_CAP { + let next = (*block).wait_next(); + let mut next_index = (new_head & !MARK_BIT).wrapping_add(1 << SHIFT); + if !(*next).next.load(Ordering::Relaxed).is_null() { + next_index |= MARK_BIT; + } + + self.head.block.store(next, Ordering::Release); + self.head.index.store(next_index, Ordering::Release); + } + + token.list.block = block as *const u8; + token.list.offset = offset; + return true; + }, + Err(h) => { + head = h; + block = self.head.block.load(Ordering::Acquire); + backoff.spin(); + } + } + } + } + + /// Reads a message from the channel. + pub unsafe fn read(&self, token: &mut Token) -> Result { + if token.list.block.is_null() { + // The channel is disconnected. + return Err(()); + } + + // Read the message. + let block = token.list.block as *mut Block; + let offset = token.list.offset; + let slot = (*block).slots.get_unchecked(offset); + slot.wait_write(); + let msg = slot.msg.get().read().assume_init(); + + // Destroy the block if we've reached the end, or if another thread wanted to destroy but + // couldn't because we were busy reading from the slot. + if offset + 1 == BLOCK_CAP { + Block::destroy(block, 0); + } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { + Block::destroy(block, offset + 1); + } + + Ok(msg) + } + + /// Attempts to send a message into the channel. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + self.send(msg, None).map_err(|err| match err { + SendTimeoutError::Disconnected(msg) => TrySendError::Disconnected(msg), + SendTimeoutError::Timeout(_) => unreachable!(), + }) + } + + /// Sends a message into the channel. + pub fn send(&self, msg: T, _deadline: Option) -> Result<(), SendTimeoutError> { + let token = &mut Token::default(); + assert!(self.start_send(token)); + unsafe { + self.write(token, msg) + .map_err(SendTimeoutError::Disconnected) + } + } + + /// Attempts to receive a message without blocking. + pub fn try_recv(&self) -> Result { + let token = &mut Token::default(); + + if self.start_recv(token) { + unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) } + } else { + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + pub fn recv(&self, deadline: Option) -> Result { + let token = &mut Token::default(); + loop { + // Try receiving a message several times. + let backoff = Backoff::new(); + loop { + if self.start_recv(token) { + unsafe { + return self.read(token).map_err(|_| RecvTimeoutError::Disconnected); + } + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + if let Some(d) = deadline { + if Instant::now() >= d { + return Err(RecvTimeoutError::Timeout); + } + } + + // Prepare for blocking until a sender wakes us up. + Context::with(|cx| { + let oper = Operation::hook(token); + self.receivers.register(oper, cx); + + // Has the channel become ready just now? + if !self.is_empty() || self.is_disconnected() { + let _ = cx.try_select(Selected::Aborted); + } + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted | Selected::Disconnected => { + self.receivers.unregister(oper).unwrap(); + // If the channel was disconnected, we still have to check for remaining + // messages. + } + Selected::Operation(_) => {} + } + }); + } + } + + /// Returns the current number of messages inside the channel. + pub 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); + + // 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; + + // Fix up indices if they fall onto block ends. + if head == BLOCK_CAP { + head = 0; + tail -= LAP; + } + if tail == BLOCK_CAP { + tail += 1; + } + + // Return the difference minus the number of blocks between tail and head. + return tail - head - tail / LAP; + } + } + } + + /// Returns the capacity of the channel. + pub fn capacity(&self) -> Option { + None + } + + /// Disconnects the channel and wakes up all blocked receivers. + /// + /// Returns `true` if this call disconnected the channel. + pub fn disconnect(&self) -> bool { + let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst); + + if tail & MARK_BIT == 0 { + self.receivers.disconnect(); + true + } else { + false + } + } + + /// Returns `true` if the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + self.tail.index.load(Ordering::SeqCst) & MARK_BIT != 0 + } + + /// Returns `true` if the channel 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 `true` if the channel is full. + pub fn is_full(&self) -> bool { + false + } +} + +impl Drop for Channel { + fn drop(&mut self) { + let mut head = self.head.index.load(Ordering::Relaxed); + let mut tail = self.tail.index.load(Ordering::Relaxed); + let mut block = self.head.block.load(Ordering::Relaxed); + + // Erase the lower bits. + head &= !((1 << SHIFT) - 1); + tail &= !((1 << SHIFT) - 1); + + unsafe { + // Drop all messages between head and tail and deallocate the heap-allocated blocks. + while head != tail { + let offset = (head >> SHIFT) % LAP; + + if offset < BLOCK_CAP { + // Drop the message in the slot. + let slot = (*block).slots.get_unchecked(offset); + let p = &mut *slot.msg.get(); + p.as_mut_ptr().drop_in_place(); + } else { + // Deallocate the block and move to the next one. + let next = (*block).next.load(Ordering::Relaxed); + drop(Box::from_raw(block)); + block = next; + } + + head = head.wrapping_add(1 << SHIFT); + } + + // Deallocate the last remaining block. + if !block.is_null() { + drop(Box::from_raw(block)); + } + } + } +} + +/// Receiver handle to a channel. +pub struct Receiver<'a, T: 'a>(&'a Channel); + +/// Sender handle to a channel. +pub struct Sender<'a, T: 'a>(&'a Channel); + +impl<'a, T> SelectHandle for Receiver<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_recv(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.register(oper, cx); + self.is_ready() + } + + fn unregister(&self, oper: Operation) { + self.0.receivers.unregister(oper); + } + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + !self.0.is_empty() || self.0.is_disconnected() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.watch(oper, cx); + self.is_ready() + } + + fn unwatch(&self, oper: Operation) { + self.0.receivers.unwatch(oper); + } +} + +impl<'a, T> SelectHandle for Sender<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_send(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + fn unregister(&self, _oper: Operation) {} + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + true + } + + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + fn unwatch(&self, _oper: Operation) {} +} diff --git a/vendor/crossbeam-channel/src/flavors/mod.rs b/vendor/crossbeam-channel/src/flavors/mod.rs new file mode 100644 index 0000000000..ebd0cfa540 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/mod.rs @@ -0,0 +1,17 @@ +//! Channel flavors. +//! +//! There are six flavors: +//! +//! 1. `after` - Channel that delivers a message after a certain amount of time. +//! 2. `array` - Bounded channel based on a preallocated array. +//! 3. `list` - Unbounded channel implemented as a linked list. +//! 4. `never` - Channel that never delivers messages. +//! 5. `tick` - Channel that delivers messages periodically. +//! 6. `zero` - Zero-capacity channel. + +pub mod after; +pub mod array; +pub mod list; +pub mod never; +pub mod tick; +pub mod zero; diff --git a/vendor/crossbeam-channel/src/flavors/never.rs b/vendor/crossbeam-channel/src/flavors/never.rs new file mode 100644 index 0000000000..5fb12e67ed --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/never.rs @@ -0,0 +1,110 @@ +//! Channel that never delivers messages. +//! +//! Messages cannot be sent into this kind of channel. + +use std::marker::PhantomData; +use std::time::Instant; + +use context::Context; +use err::{RecvTimeoutError, TryRecvError}; +use select::{Operation, SelectHandle, Token}; +use utils; + +/// This flavor doesn't need a token. +pub type NeverToken = (); + +/// Channel that never delivers messages. +pub struct Channel { + _marker: PhantomData, +} + +impl Channel { + /// Creates a channel that never delivers messages. + #[inline] + pub fn new() -> Self { + Channel { + _marker: PhantomData, + } + } + + /// Attempts to receive a message without blocking. + #[inline] + pub fn try_recv(&self) -> Result { + Err(TryRecvError::Empty) + } + + /// Receives a message from the channel. + #[inline] + pub fn recv(&self, deadline: Option) -> Result { + utils::sleep_until(deadline); + Err(RecvTimeoutError::Timeout) + } + + /// Reads a message from the channel. + #[inline] + pub unsafe fn read(&self, _token: &mut Token) -> Result { + Err(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub fn is_empty(&self) -> bool { + true + } + + /// Returns `true` if the channel is full. + #[inline] + pub fn is_full(&self) -> bool { + true + } + + /// Returns the number of messages in the channel. + #[inline] + pub fn len(&self) -> usize { + 0 + } + + /// Returns the capacity of the channel. + #[inline] + pub fn capacity(&self) -> Option { + Some(0) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, _token: &mut Token) -> bool { + false + } + + #[inline] + fn deadline(&self) -> Option { + None + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + false + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/vendor/crossbeam-channel/src/flavors/tick.rs b/vendor/crossbeam-channel/src/flavors/tick.rs new file mode 100644 index 0000000000..2941117614 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/tick.rs @@ -0,0 +1,167 @@ +//! Channel that delivers messages periodically. +//! +//! Messages cannot be sent into this kind of channel; they are materialized on demand. + +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_utils::atomic::AtomicCell; + +use context::Context; +use err::{RecvTimeoutError, TryRecvError}; +use select::{Operation, SelectHandle, Token}; + +/// Result of a receive operation. +pub type TickToken = Option; + +/// Channel that delivers messages periodically. +pub struct Channel { + /// The instant at which the next message will be delivered. + delivery_time: AtomicCell, + + /// The time interval in which messages get delivered. + duration: Duration, +} + +impl Channel { + /// Creates a channel that delivers messages periodically. + #[inline] + pub fn new(dur: Duration) -> Self { + Channel { + delivery_time: AtomicCell::new(Instant::now() + dur), + duration: dur, + } + } + + /// Attempts to receive a message without blocking. + #[inline] + pub fn try_recv(&self) -> Result { + loop { + let now = Instant::now(); + let delivery_time = self.delivery_time.load(); + + if now < delivery_time { + return Err(TryRecvError::Empty); + } + + if self + .delivery_time + .compare_exchange(delivery_time, now + self.duration) + .is_ok() + { + return Ok(delivery_time); + } + } + } + + /// Receives a message from the channel. + #[inline] + pub fn recv(&self, deadline: Option) -> Result { + loop { + let delivery_time = self.delivery_time.load(); + let now = Instant::now(); + + if let Some(d) = deadline { + if d < delivery_time { + if now < d { + thread::sleep(d - now); + } + return Err(RecvTimeoutError::Timeout); + } + } + + if self + .delivery_time + .compare_exchange(delivery_time, delivery_time.max(now) + self.duration) + .is_ok() + { + if now < delivery_time { + thread::sleep(delivery_time - now); + } + return Ok(delivery_time); + } + } + } + + /// Reads a message from the channel. + #[inline] + pub unsafe fn read(&self, token: &mut Token) -> Result { + token.tick.ok_or(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub fn is_empty(&self) -> bool { + Instant::now() < self.delivery_time.load() + } + + /// Returns `true` if the channel is full. + #[inline] + pub fn is_full(&self) -> bool { + !self.is_empty() + } + + /// Returns the number of messages in the channel. + #[inline] + pub fn len(&self) -> usize { + if self.is_empty() { + 0 + } else { + 1 + } + } + + /// Returns the capacity of the channel. + #[inline] + pub fn capacity(&self) -> Option { + Some(1) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, token: &mut Token) -> bool { + match self.try_recv() { + Ok(msg) => { + token.tick = Some(msg); + true + } + Err(TryRecvError::Disconnected) => { + token.tick = None; + true + } + Err(TryRecvError::Empty) => false, + } + } + + #[inline] + fn deadline(&self) -> Option { + Some(self.delivery_time.load()) + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + !self.is_empty() + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/vendor/crossbeam-channel/src/flavors/zero.rs b/vendor/crossbeam-channel/src/flavors/zero.rs new file mode 100644 index 0000000000..ee1bfc5344 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/zero.rs @@ -0,0 +1,466 @@ +//! Zero-capacity channel. +//! +//! This kind of channel is also known as *rendezvous* channel. + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::Instant; + +use crossbeam_utils::Backoff; + +use context::Context; +use err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; +use select::{Operation, SelectHandle, Selected, Token}; +use utils::Spinlock; +use waker::Waker; + +/// A pointer to a packet. +pub type ZeroToken = usize; + +/// A slot for passing one message from a sender to a receiver. +struct Packet { + /// Equals `true` if the packet is allocated on the stack. + on_stack: bool, + + /// Equals `true` once the packet is ready for reading or writing. + ready: AtomicBool, + + /// The message. + msg: UnsafeCell>, +} + +impl Packet { + /// Creates an empty packet on the stack. + fn empty_on_stack() -> Packet { + Packet { + on_stack: true, + ready: AtomicBool::new(false), + msg: UnsafeCell::new(None), + } + } + + /// Creates an empty packet on the heap. + fn empty_on_heap() -> Box> { + Box::new(Packet { + on_stack: false, + ready: AtomicBool::new(false), + msg: UnsafeCell::new(None), + }) + } + + /// Creates a packet on the stack, containing a message. + fn message_on_stack(msg: T) -> Packet { + Packet { + on_stack: true, + ready: AtomicBool::new(false), + msg: UnsafeCell::new(Some(msg)), + } + } + + /// Waits until the packet becomes ready for reading or writing. + fn wait_ready(&self) { + let backoff = Backoff::new(); + while !self.ready.load(Ordering::Acquire) { + backoff.snooze(); + } + } +} + +/// Inner representation of a zero-capacity channel. +struct Inner { + /// Senders waiting to pair up with a receive operation. + senders: Waker, + + /// Receivers waiting to pair up with a send operation. + receivers: Waker, + + /// Equals `true` when the channel is disconnected. + is_disconnected: bool, +} + +/// Zero-capacity channel. +pub struct Channel { + /// Inner representation of the channel. + inner: Spinlock, + + /// Indicates that dropping a `Channel` may drop values of type `T`. + _marker: PhantomData, +} + +impl Channel { + /// Constructs a new zero-capacity channel. + pub fn new() -> Self { + Channel { + inner: Spinlock::new(Inner { + senders: Waker::new(), + receivers: Waker::new(), + is_disconnected: false, + }), + _marker: PhantomData, + } + } + + /// Returns a receiver handle to the channel. + pub fn receiver(&self) -> Receiver { + Receiver(self) + } + + /// Returns a sender handle to the channel. + pub fn sender(&self) -> Sender { + Sender(self) + } + + /// Attempts to reserve a slot for sending a message. + fn start_send(&self, token: &mut Token) -> bool { + let mut inner = self.inner.lock(); + + // If there's a waiting receiver, pair up with it. + if let Some(operation) = inner.receivers.try_select() { + token.zero = operation.packet; + true + } else if inner.is_disconnected { + token.zero = 0; + true + } else { + false + } + } + + /// Writes a message into the packet. + pub unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> { + // If there is no packet, the channel is disconnected. + if token.zero == 0 { + return Err(msg); + } + + let packet = &*(token.zero as *const Packet); + packet.msg.get().write(Some(msg)); + packet.ready.store(true, Ordering::Release); + Ok(()) + } + + /// Attempts to pair up with a sender. + fn start_recv(&self, token: &mut Token) -> bool { + let mut inner = self.inner.lock(); + + // If there's a waiting sender, pair up with it. + if let Some(operation) = inner.senders.try_select() { + token.zero = operation.packet; + true + } else if inner.is_disconnected { + token.zero = 0; + true + } else { + false + } + } + + /// Reads a message from the packet. + pub unsafe fn read(&self, token: &mut Token) -> Result { + // If there is no packet, the channel is disconnected. + if token.zero == 0 { + return Err(()); + } + + let packet = &*(token.zero as *const Packet); + + if packet.on_stack { + // The message has been in the packet from the beginning, so there is no need to wait + // for it. However, after reading the message, we need to set `ready` to `true` in + // order to signal that the packet can be destroyed. + let msg = packet.msg.get().replace(None).unwrap(); + packet.ready.store(true, Ordering::Release); + Ok(msg) + } else { + // Wait until the message becomes available, then read it and destroy the + // heap-allocated packet. + packet.wait_ready(); + let msg = packet.msg.get().replace(None).unwrap(); + drop(Box::from_raw(packet as *const Packet as *mut Packet)); + Ok(msg) + } + } + + /// Attempts to send a message into the channel. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting receiver, pair up with it. + if let Some(operation) = inner.receivers.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { + self.write(token, msg).ok().unwrap(); + } + Ok(()) + } else if inner.is_disconnected { + Err(TrySendError::Disconnected(msg)) + } else { + Err(TrySendError::Full(msg)) + } + } + + /// Sends a message into the channel. + pub fn send(&self, msg: T, deadline: Option) -> Result<(), SendTimeoutError> { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting receiver, pair up with it. + if let Some(operation) = inner.receivers.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { + self.write(token, msg).ok().unwrap(); + } + return Ok(()); + } + + if inner.is_disconnected { + return Err(SendTimeoutError::Disconnected(msg)); + } + + Context::with(|cx| { + // Prepare for blocking until a receiver wakes us up. + let oper = Operation::hook(token); + let packet = Packet::::message_on_stack(msg); + inner + .senders + .register_with_packet(oper, &packet as *const Packet as usize, cx); + inner.receivers.notify(); + drop(inner); + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => { + self.inner.lock().senders.unregister(oper).unwrap(); + let msg = unsafe { packet.msg.get().replace(None).unwrap() }; + Err(SendTimeoutError::Timeout(msg)) + } + Selected::Disconnected => { + self.inner.lock().senders.unregister(oper).unwrap(); + let msg = unsafe { packet.msg.get().replace(None).unwrap() }; + Err(SendTimeoutError::Disconnected(msg)) + } + Selected::Operation(_) => { + // Wait until the message is read, then drop the packet. + packet.wait_ready(); + Ok(()) + } + } + }) + } + + /// Attempts to receive a message without blocking. + pub fn try_recv(&self) -> Result { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting sender, pair up with it. + if let Some(operation) = inner.senders.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) } + } else if inner.is_disconnected { + Err(TryRecvError::Disconnected) + } else { + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + pub fn recv(&self, deadline: Option) -> Result { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting sender, pair up with it. + if let Some(operation) = inner.senders.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { + return self.read(token).map_err(|_| RecvTimeoutError::Disconnected); + } + } + + if inner.is_disconnected { + return Err(RecvTimeoutError::Disconnected); + } + + Context::with(|cx| { + // Prepare for blocking until a sender wakes us up. + let oper = Operation::hook(token); + let packet = Packet::::empty_on_stack(); + inner + .receivers + .register_with_packet(oper, &packet as *const Packet as usize, cx); + inner.senders.notify(); + drop(inner); + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => { + self.inner.lock().receivers.unregister(oper).unwrap(); + Err(RecvTimeoutError::Timeout) + } + Selected::Disconnected => { + self.inner.lock().receivers.unregister(oper).unwrap(); + Err(RecvTimeoutError::Disconnected) + } + Selected::Operation(_) => { + // Wait until the message is provided, then read it. + packet.wait_ready(); + unsafe { Ok(packet.msg.get().replace(None).unwrap()) } + } + } + }) + } + + /// Disconnects the channel and wakes up all blocked senders and receivers. + /// + /// Returns `true` if this call disconnected the channel. + pub fn disconnect(&self) -> bool { + let mut inner = self.inner.lock(); + + if !inner.is_disconnected { + inner.is_disconnected = true; + inner.senders.disconnect(); + inner.receivers.disconnect(); + true + } else { + false + } + } + + /// Returns the current number of messages inside the channel. + pub fn len(&self) -> usize { + 0 + } + + /// Returns the capacity of the channel. + pub fn capacity(&self) -> Option { + Some(0) + } + + /// Returns `true` if the channel is empty. + pub fn is_empty(&self) -> bool { + true + } + + /// Returns `true` if the channel is full. + pub fn is_full(&self) -> bool { + true + } +} + +/// Receiver handle to a channel. +pub struct Receiver<'a, T: 'a>(&'a Channel); + +/// Sender handle to a channel. +pub struct Sender<'a, T: 'a>(&'a Channel); + +impl<'a, T> SelectHandle for Receiver<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_recv(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + let packet = Box::into_raw(Packet::::empty_on_heap()); + + let mut inner = self.0.inner.lock(); + inner + .receivers + .register_with_packet(oper, packet as usize, cx); + inner.senders.notify(); + inner.senders.can_select() || inner.is_disconnected + } + + fn unregister(&self, oper: Operation) { + if let Some(operation) = self.0.inner.lock().receivers.unregister(oper) { + unsafe { + drop(Box::from_raw(operation.packet as *mut Packet)); + } + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + token.zero = cx.wait_packet(); + true + } + + fn is_ready(&self) -> bool { + let inner = self.0.inner.lock(); + inner.senders.can_select() || inner.is_disconnected + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + let mut inner = self.0.inner.lock(); + inner.receivers.watch(oper, cx); + inner.senders.can_select() || inner.is_disconnected + } + + fn unwatch(&self, oper: Operation) { + let mut inner = self.0.inner.lock(); + inner.receivers.unwatch(oper); + } +} + +impl<'a, T> SelectHandle for Sender<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_send(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + let packet = Box::into_raw(Packet::::empty_on_heap()); + + let mut inner = self.0.inner.lock(); + inner + .senders + .register_with_packet(oper, packet as usize, cx); + inner.receivers.notify(); + inner.receivers.can_select() || inner.is_disconnected + } + + fn unregister(&self, oper: Operation) { + if let Some(operation) = self.0.inner.lock().senders.unregister(oper) { + unsafe { + drop(Box::from_raw(operation.packet as *mut Packet)); + } + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + token.zero = cx.wait_packet(); + true + } + + fn is_ready(&self) -> bool { + let inner = self.0.inner.lock(); + inner.receivers.can_select() || inner.is_disconnected + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + let mut inner = self.0.inner.lock(); + inner.senders.watch(oper, cx); + inner.receivers.can_select() || inner.is_disconnected + } + + fn unwatch(&self, oper: Operation) { + let mut inner = self.0.inner.lock(); + inner.senders.unwatch(oper); + } +} diff --git a/vendor/crossbeam-channel/src/lib.rs b/vendor/crossbeam-channel/src/lib.rs new file mode 100644 index 0000000000..898239632f --- /dev/null +++ b/vendor/crossbeam-channel/src/lib.rs @@ -0,0 +1,379 @@ +//! Multi-producer multi-consumer channels for message passing. +//! +//! This crate is an alternative to [`std::sync::mpsc`] with more features and better performance. +//! +//! # Hello, world! +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! // Create a channel of unbounded capacity. +//! let (s, r) = unbounded(); +//! +//! // Send a message into the channel. +//! s.send("Hello, world!").unwrap(); +//! +//! // Receive the message from the channel. +//! assert_eq!(r.recv(), Ok("Hello, world!")); +//! ``` +//! +//! # Channel types +//! +//! Channels can be created using two functions: +//! +//! * [`bounded`] creates a channel of bounded capacity, i.e. there is a limit to how many messages +//! it can hold at a time. +//! +//! * [`unbounded`] creates a channel of unbounded capacity, i.e. it can hold any number of +//! messages at a time. +//! +//! Both functions return a [`Sender`] and a [`Receiver`], which represent the two opposite sides +//! of a channel. +//! +//! Creating a bounded channel: +//! +//! ``` +//! use crossbeam_channel::bounded; +//! +//! // Create a channel that can hold at most 5 messages at a time. +//! let (s, r) = bounded(5); +//! +//! // Can send only 5 messages without blocking. +//! for i in 0..5 { +//! s.send(i).unwrap(); +//! } +//! +//! // Another call to `send` would block because the channel is full. +//! // s.send(5).unwrap(); +//! ``` +//! +//! Creating an unbounded channel: +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! // Create an unbounded channel. +//! let (s, r) = unbounded(); +//! +//! // Can send any number of messages into the channel without blocking. +//! for i in 0..1000 { +//! s.send(i).unwrap(); +//! } +//! ``` +//! +//! A special case is zero-capacity channel, which cannot hold any messages. Instead, send and +//! receive operations must appear at the same time in order to pair up and pass the message over: +//! +//! ``` +//! use std::thread; +//! use crossbeam_channel::bounded; +//! +//! // Create a zero-capacity channel. +//! let (s, r) = bounded(0); +//! +//! // Sending blocks until a receive operation appears on the other side. +//! thread::spawn(move || s.send("Hi!").unwrap()); +//! +//! // Receiving blocks until a send operation appears on the other side. +//! assert_eq!(r.recv(), Ok("Hi!")); +//! ``` +//! +//! # Sharing channels +//! +//! Senders and receivers can be cloned and sent to other threads: +//! +//! ``` +//! use std::thread; +//! use crossbeam_channel::bounded; +//! +//! let (s1, r1) = bounded(0); +//! let (s2, r2) = (s1.clone(), r1.clone()); +//! +//! // Spawn a thread that receives a message and then sends one. +//! thread::spawn(move || { +//! r2.recv().unwrap(); +//! s2.send(2).unwrap(); +//! }); +//! +//! // Send a message and then receive one. +//! s1.send(1).unwrap(); +//! r1.recv().unwrap(); +//! ``` +//! +//! Note that cloning only creates a new handle to the same sending or receiving side. It does not +//! create a separate stream of messages in any way: +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! let (s1, r1) = unbounded(); +//! let (s2, r2) = (s1.clone(), r1.clone()); +//! let (s3, r3) = (s2.clone(), r2.clone()); +//! +//! s1.send(10).unwrap(); +//! s2.send(20).unwrap(); +//! s3.send(30).unwrap(); +//! +//! assert_eq!(r3.recv(), Ok(10)); +//! assert_eq!(r1.recv(), Ok(20)); +//! assert_eq!(r2.recv(), Ok(30)); +//! ``` +//! +//! It's also possible to share senders and receivers by reference: +//! +//! ``` +//! # extern crate crossbeam_channel; +//! # extern crate crossbeam_utils; +//! # fn main() { +//! use std::thread; +//! use crossbeam_channel::bounded; +//! use crossbeam_utils::thread::scope; +//! +//! let (s, r) = bounded(0); +//! +//! scope(|scope| { +//! // Spawn a thread that receives a message and then sends one. +//! scope.spawn(|_| { +//! r.recv().unwrap(); +//! s.send(2).unwrap(); +//! }); +//! +//! // Send a message and then receive one. +//! s.send(1).unwrap(); +//! r.recv().unwrap(); +//! }).unwrap(); +//! # } +//! ``` +//! +//! # Disconnection +//! +//! When all senders or all receivers associated with a channel get dropped, the channel becomes +//! disconnected. No more messages can be sent, but any remaining messages can still be received. +//! Send and receive operations on a disconnected channel never block. +//! +//! ``` +//! use crossbeam_channel::{unbounded, RecvError}; +//! +//! let (s, r) = unbounded(); +//! s.send(1).unwrap(); +//! s.send(2).unwrap(); +//! s.send(3).unwrap(); +//! +//! // The only sender is dropped, disconnecting the channel. +//! drop(s); +//! +//! // The remaining messages can be received. +//! assert_eq!(r.recv(), Ok(1)); +//! assert_eq!(r.recv(), Ok(2)); +//! assert_eq!(r.recv(), Ok(3)); +//! +//! // There are no more messages in the channel. +//! assert!(r.is_empty()); +//! +//! // Note that calling `r.recv()` does not block. +//! // Instead, `Err(RecvError)` is returned immediately. +//! assert_eq!(r.recv(), Err(RecvError)); +//! ``` +//! +//! # Blocking operations +//! +//! Send and receive operations come in three flavors: +//! +//! * Non-blocking (returns immediately with success or failure). +//! * Blocking (waits until the operation succeeds or the channel becomes disconnected). +//! * Blocking with a timeout (blocks only for a certain duration of time). +//! +//! A simple example showing the difference between non-blocking and blocking operations: +//! +//! ``` +//! use crossbeam_channel::{bounded, RecvError, TryRecvError}; +//! +//! let (s, r) = bounded(1); +//! +//! // Send a message into the channel. +//! s.send("foo").unwrap(); +//! +//! // This call would block because the channel is full. +//! // s.send("bar").unwrap(); +//! +//! // Receive the message. +//! assert_eq!(r.recv(), Ok("foo")); +//! +//! // This call would block because the channel is empty. +//! // r.recv(); +//! +//! // Try receiving a message without blocking. +//! assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +//! +//! // Disconnect the channel. +//! drop(s); +//! +//! // This call doesn't block because the channel is now disconnected. +//! assert_eq!(r.recv(), Err(RecvError)); +//! ``` +//! +//! # Iteration +//! +//! Receivers can be used as iterators. For example, method [`iter`] creates an iterator that +//! receives messages until the channel becomes empty and disconnected. Note that iteration may +//! block waiting for next message to arrive. +//! +//! ``` +//! use std::thread; +//! use crossbeam_channel::unbounded; +//! +//! let (s, r) = unbounded(); +//! +//! thread::spawn(move || { +//! s.send(1).unwrap(); +//! s.send(2).unwrap(); +//! s.send(3).unwrap(); +//! drop(s); // Disconnect the channel. +//! }); +//! +//! // Collect all messages from the channel. +//! // Note that the call to `collect` blocks until the sender is dropped. +//! let v: Vec<_> = r.iter().collect(); +//! +//! assert_eq!(v, [1, 2, 3]); +//! ``` +//! +//! A non-blocking iterator can be created using [`try_iter`], which receives all available +//! messages without blocking: +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! let (s, r) = unbounded(); +//! s.send(1).unwrap(); +//! s.send(2).unwrap(); +//! s.send(3).unwrap(); +//! // No need to drop the sender. +//! +//! // Receive all messages currently in the channel. +//! let v: Vec<_> = r.try_iter().collect(); +//! +//! assert_eq!(v, [1, 2, 3]); +//! ``` +//! +//! # Selection +//! +//! The [`select!`] macro allows you to define a set of channel operations, wait until any one of +//! them becomes ready, and finally execute it. If multiple operations are ready at the same time, +//! a random one among them is selected. +//! +//! It is also possible to define a `default` case that gets executed if none of the operations are +//! ready, either right away or for a certain duration of time. +//! +//! An operation is considered to be ready if it doesn't have to block. Note that it is ready even +//! when it will simply return an error because the channel is disconnected. +//! +//! An example of receiving a message from two channels: +//! +//! ``` +//! # #[macro_use] +//! # extern crate crossbeam_channel; +//! # fn main() { +//! use std::thread; +//! use std::time::Duration; +//! use crossbeam_channel::unbounded; +//! +//! let (s1, r1) = unbounded(); +//! let (s2, r2) = unbounded(); +//! +//! thread::spawn(move || s1.send(10).unwrap()); +//! thread::spawn(move || s2.send(20).unwrap()); +//! +//! // At most one of these two receive operations will be executed. +//! select! { +//! recv(r1) -> msg => assert_eq!(msg, Ok(10)), +//! recv(r2) -> msg => assert_eq!(msg, Ok(20)), +//! default(Duration::from_secs(1)) => println!("timed out"), +//! } +//! # } +//! ``` +//! +//! If you need to select over a dynamically created list of channel operations, use [`Select`] +//! instead. The [`select!`] macro is just a convenience wrapper around [`Select`]. +//! +//! # Extra channels +//! +//! Three functions can create special kinds of channels, all of which return just a [`Receiver`] +//! handle: +//! +//! * [`after`] creates a channel that delivers a single message after a certain duration of time. +//! * [`tick`] creates a channel that delivers messages periodically. +//! * [`never`] creates a channel that never delivers messages. +//! +//! These channels are very efficient because messages get lazily generated on receive operations. +//! +//! An example that prints elapsed time every 50 milliseconds for the duration of 1 second: +//! +//! ``` +//! # #[macro_use] +//! # extern crate crossbeam_channel; +//! # fn main() { +//! use std::time::{Duration, Instant}; +//! use crossbeam_channel::{after, tick}; +//! +//! let start = Instant::now(); +//! let ticker = tick(Duration::from_millis(50)); +//! let timeout = after(Duration::from_secs(1)); +//! +//! loop { +//! select! { +//! recv(ticker) -> _ => println!("elapsed: {:?}", start.elapsed()), +//! recv(timeout) -> _ => break, +//! } +//! } +//! # } +//! ``` +//! +//! [`std::sync::mpsc`]: https://doc.rust-lang.org/std/sync/mpsc/index.html +//! [`unbounded`]: fn.unbounded.html +//! [`bounded`]: fn.bounded.html +//! [`after`]: fn.after.html +//! [`tick`]: fn.tick.html +//! [`never`]: fn.never.html +//! [`send`]: struct.Sender.html#method.send +//! [`recv`]: struct.Receiver.html#method.recv +//! [`iter`]: struct.Receiver.html#method.iter +//! [`try_iter`]: struct.Receiver.html#method.try_iter +//! [`select!`]: macro.select.html +//! [`Select`]: struct.Select.html +//! [`Sender`]: struct.Sender.html +//! [`Receiver`]: struct.Receiver.html + +#![warn(missing_docs)] +#![warn(missing_debug_implementations)] + +extern crate crossbeam_utils; +extern crate maybe_uninit; + +mod channel; +mod context; +mod counter; +mod err; +mod flavors; +mod select; +mod select_macro; +mod utils; +mod waker; + +/// Crate internals used by the `select!` macro. +#[doc(hidden)] +pub mod internal { + pub use select::SelectHandle; + pub use select::{select, select_timeout, try_select}; +} + +pub use channel::{after, never, tick}; +pub use channel::{bounded, unbounded}; +pub use channel::{IntoIter, Iter, TryIter}; +pub use channel::{Receiver, Sender}; + +pub use select::{Select, SelectedOperation}; + +pub use err::{ReadyTimeoutError, SelectTimeoutError, TryReadyError, TrySelectError}; +pub use err::{RecvError, RecvTimeoutError, TryRecvError}; +pub use err::{SendError, SendTimeoutError, TrySendError}; diff --git a/vendor/crossbeam-channel/src/select.rs b/vendor/crossbeam-channel/src/select.rs new file mode 100644 index 0000000000..60c6a45dcb --- /dev/null +++ b/vendor/crossbeam-channel/src/select.rs @@ -0,0 +1,1166 @@ +//! Interface to the select mechanism. + +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use std::time::{Duration, Instant}; + +use crossbeam_utils::Backoff; + +use channel::{self, Receiver, Sender}; +use context::Context; +use err::{ReadyTimeoutError, TryReadyError}; +use err::{RecvError, SendError}; +use err::{SelectTimeoutError, TrySelectError}; +use flavors; +use utils; + +/// Temporary data that gets initialized during select or a blocking operation, and is consumed by +/// `read` or `write`. +/// +/// Each field contains data associated with a specific channel flavor. +#[derive(Debug, Default)] +pub struct Token { + pub after: flavors::after::AfterToken, + pub array: flavors::array::ArrayToken, + pub list: flavors::list::ListToken, + pub never: flavors::never::NeverToken, + pub tick: flavors::tick::TickToken, + pub zero: flavors::zero::ZeroToken, +} + +/// Identifier associated with an operation by a specific thread on a specific channel. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Operation(usize); + +impl Operation { + /// Creates an operation identifier from a mutable reference. + /// + /// This function essentially just turns the address of the reference into a number. The + /// reference should point to a variable that is specific to the thread and the operation, + /// and is alive for the entire duration of select or blocking operation. + #[inline] + pub fn hook(r: &mut T) -> Operation { + let val = r as *mut T as usize; + // Make sure that the pointer address doesn't equal the numerical representation of + // `Selected::{Waiting, Aborted, Disconnected}`. + assert!(val > 2); + Operation(val) + } +} + +/// Current state of a select or a blocking operation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Selected { + /// Still waiting for an operation. + Waiting, + + /// The attempt to block the current thread has been aborted. + Aborted, + + /// An operation became ready because a channel is disconnected. + Disconnected, + + /// An operation became ready because a message can be sent or received. + Operation(Operation), +} + +impl From for Selected { + #[inline] + fn from(val: usize) -> Selected { + match val { + 0 => Selected::Waiting, + 1 => Selected::Aborted, + 2 => Selected::Disconnected, + oper => Selected::Operation(Operation(oper)), + } + } +} + +impl Into for Selected { + #[inline] + fn into(self) -> usize { + match self { + Selected::Waiting => 0, + Selected::Aborted => 1, + Selected::Disconnected => 2, + Selected::Operation(Operation(val)) => val, + } + } +} + +/// A receiver or a sender that can participate in select. +/// +/// This is a handle that assists select in executing an operation, registration, deciding on the +/// appropriate deadline for blocking, etc. +pub trait SelectHandle { + /// Attempts to select an operation and returns `true` on success. + fn try_select(&self, token: &mut Token) -> bool; + + /// Returns a deadline for an operation, if there is one. + fn deadline(&self) -> Option; + + /// Registers an operation for execution and returns `true` if it is now ready. + fn register(&self, oper: Operation, cx: &Context) -> bool; + + /// Unregisters an operation for execution. + fn unregister(&self, oper: Operation); + + /// Attempts to select an operation the thread got woken up for and returns `true` on success. + fn accept(&self, token: &mut Token, cx: &Context) -> bool; + + /// Returns `true` if an operation can be executed without blocking. + fn is_ready(&self) -> bool; + + /// Registers an operation for readiness notification and returns `true` if it is now ready. + fn watch(&self, oper: Operation, cx: &Context) -> bool; + + /// Unregisters an operation for readiness notification. + fn unwatch(&self, oper: Operation); +} + +impl<'a, T: SelectHandle> SelectHandle for &'a T { + fn try_select(&self, token: &mut Token) -> bool { + (**self).try_select(token) + } + + fn deadline(&self) -> Option { + (**self).deadline() + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + (**self).register(oper, cx) + } + + fn unregister(&self, oper: Operation) { + (**self).unregister(oper); + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + (**self).accept(token, cx) + } + + fn is_ready(&self) -> bool { + (**self).is_ready() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + (**self).watch(oper, cx) + } + + fn unwatch(&self, oper: Operation) { + (**self).unwatch(oper) + } +} + +/// Determines when a select operation should time out. +#[derive(Clone, Copy, Eq, PartialEq)] +enum Timeout { + /// No blocking. + Now, + + /// Block forever. + Never, + + /// Time out after the time instant. + At(Instant), +} + +/// Runs until one of the operations is selected, potentially blocking the current thread. +/// +/// Successful receive operations will have to be followed up by `channel::read()` and successful +/// send operations by `channel::write()`. +fn run_select( + handles: &mut [(&dyn SelectHandle, usize, *const u8)], + timeout: Timeout, +) -> Option<(Token, usize, *const u8)> { + if handles.is_empty() { + // Wait until the timeout and return. + match timeout { + Timeout::Now => return None, + Timeout::Never => { + utils::sleep_until(None); + unreachable!(); + } + Timeout::At(when) => { + utils::sleep_until(Some(when)); + return None; + } + } + } + + // Shuffle the operations for fairness. + utils::shuffle(handles); + + // Create a token, which serves as a temporary variable that gets initialized in this function + // and is later used by a call to `channel::read()` or `channel::write()` that completes the + // selected operation. + let mut token = Token::default(); + + // Try selecting one of the operations without blocking. + for &(handle, i, ptr) in handles.iter() { + if handle.try_select(&mut token) { + return Some((token, i, ptr)); + } + } + + loop { + // Prepare for blocking. + let res = Context::with(|cx| { + let mut sel = Selected::Waiting; + let mut registered_count = 0; + let mut index_ready = None; + + if let Timeout::Now = timeout { + cx.try_select(Selected::Aborted).unwrap(); + } + + // Register all operations. + for (handle, i, _) in handles.iter_mut() { + registered_count += 1; + + // If registration returns `false`, that means the operation has just become ready. + if handle.register(Operation::hook::<&dyn SelectHandle>(handle), cx) { + // Try aborting select. + sel = match cx.try_select(Selected::Aborted) { + Ok(()) => { + index_ready = Some(*i); + Selected::Aborted + } + Err(s) => s, + }; + break; + } + + // If another thread has already selected one of the operations, stop registration. + sel = cx.selected(); + if sel != Selected::Waiting { + break; + } + } + + if sel == Selected::Waiting { + // Check with each operation for how long we're allowed to block, and compute the + // earliest deadline. + let mut deadline: Option = match timeout { + Timeout::Now => return None, + Timeout::Never => None, + Timeout::At(when) => Some(when), + }; + for &(handle, _, _) in handles.iter() { + if let Some(x) = handle.deadline() { + deadline = deadline.map(|y| x.min(y)).or(Some(x)); + } + } + + // Block the current thread. + sel = cx.wait_until(deadline); + } + + // Unregister all registered operations. + for (handle, _, _) in handles.iter_mut().take(registered_count) { + handle.unregister(Operation::hook::<&dyn SelectHandle>(handle)); + } + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => { + // If an operation became ready during registration, try selecting it. + if let Some(index_ready) = index_ready { + for &(handle, i, ptr) in handles.iter() { + if i == index_ready && handle.try_select(&mut token) { + return Some((i, ptr)); + } + } + } + } + Selected::Disconnected => {} + Selected::Operation(_) => { + // Find the selected operation. + for (handle, i, ptr) in handles.iter_mut() { + // Is this the selected operation? + if sel == Selected::Operation(Operation::hook::<&dyn SelectHandle>(handle)) + { + // Try selecting this operation. + if handle.accept(&mut token, cx) { + return Some((*i, *ptr)); + } + } + } + } + } + + None + }); + + // Return if an operation was selected. + if let Some((i, ptr)) = res { + return Some((token, i, ptr)); + } + + // Try selecting one of the operations without blocking. + for &(handle, i, ptr) in handles.iter() { + if handle.try_select(&mut token) { + return Some((token, i, ptr)); + } + } + + match timeout { + Timeout::Now => return None, + Timeout::Never => {} + Timeout::At(when) => { + if Instant::now() >= when { + return None; + } + } + } + } +} + +/// Runs until one of the operations becomes ready, potentially blocking the current thread. +fn run_ready( + handles: &mut [(&dyn SelectHandle, usize, *const u8)], + timeout: Timeout, +) -> Option { + if handles.is_empty() { + // Wait until the timeout and return. + match timeout { + Timeout::Now => return None, + Timeout::Never => { + utils::sleep_until(None); + unreachable!(); + } + Timeout::At(when) => { + utils::sleep_until(Some(when)); + return None; + } + } + } + + // Shuffle the operations for fairness. + utils::shuffle(handles); + + loop { + let backoff = Backoff::new(); + loop { + // Check operations for readiness. + for &(handle, i, _) in handles.iter() { + if handle.is_ready() { + return Some(i); + } + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + // Check for timeout. + match timeout { + Timeout::Now => return None, + Timeout::Never => {} + Timeout::At(when) => { + if Instant::now() >= when { + return None; + } + } + } + + // Prepare for blocking. + let res = Context::with(|cx| { + let mut sel = Selected::Waiting; + let mut registered_count = 0; + + // Begin watching all operations. + for (handle, _, _) in handles.iter_mut() { + registered_count += 1; + let oper = Operation::hook::<&dyn SelectHandle>(handle); + + // If registration returns `false`, that means the operation has just become ready. + if handle.watch(oper, cx) { + sel = match cx.try_select(Selected::Operation(oper)) { + Ok(()) => Selected::Operation(oper), + Err(s) => s, + }; + break; + } + + // If another thread has already chosen one of the operations, stop registration. + sel = cx.selected(); + if sel != Selected::Waiting { + break; + } + } + + if sel == Selected::Waiting { + // Check with each operation for how long we're allowed to block, and compute the + // earliest deadline. + let mut deadline: Option = match timeout { + Timeout::Now => unreachable!(), + Timeout::Never => None, + Timeout::At(when) => Some(when), + }; + for &(handle, _, _) in handles.iter() { + if let Some(x) = handle.deadline() { + deadline = deadline.map(|y| x.min(y)).or(Some(x)); + } + } + + // Block the current thread. + sel = cx.wait_until(deadline); + } + + // Unwatch all operations. + for (handle, _, _) in handles.iter_mut().take(registered_count) { + handle.unwatch(Operation::hook::<&dyn SelectHandle>(handle)); + } + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => {} + Selected::Disconnected => {} + Selected::Operation(_) => { + for (handle, i, _) in handles.iter_mut() { + let oper = Operation::hook::<&dyn SelectHandle>(handle); + if sel == Selected::Operation(oper) { + return Some(*i); + } + } + } + } + + None + }); + + // Return if an operation became ready. + if res.is_some() { + return res; + } + } +} + +/// Attempts to select one of the operations without blocking. +#[inline] +pub fn try_select<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], +) -> Result, TrySelectError> { + match run_select(handles, Timeout::Now) { + None => Err(TrySelectError), + Some((token, index, ptr)) => Ok(SelectedOperation { + token, + index, + ptr, + _marker: PhantomData, + }), + } +} + +/// Blocks until one of the operations becomes ready and selects it. +#[inline] +pub fn select<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], +) -> SelectedOperation<'a> { + if handles.is_empty() { + panic!("no operations have been added to `Select`"); + } + + let (token, index, ptr) = run_select(handles, Timeout::Never).unwrap(); + SelectedOperation { + token, + index, + ptr, + _marker: PhantomData, + } +} + +/// Blocks for a limited time until one of the operations becomes ready and selects it. +#[inline] +pub fn select_timeout<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], + timeout: Duration, +) -> Result, SelectTimeoutError> { + let timeout = Timeout::At(Instant::now() + timeout); + + match run_select(handles, timeout) { + None => Err(SelectTimeoutError), + Some((token, index, ptr)) => Ok(SelectedOperation { + token, + index, + ptr, + _marker: PhantomData, + }), + } +} + +/// Selects from a set of channel operations. +/// +/// `Select` allows you to define a set of channel operations, wait until any one of them becomes +/// ready, and finally execute it. If multiple operations are ready at the same time, a random one +/// among them is selected. +/// +/// An operation is considered to be ready if it doesn't have to block. Note that it is ready even +/// when it will simply return an error because the channel is disconnected. +/// +/// The [`select!`] macro is a convenience wrapper around `Select`. However, it cannot select over a +/// dynamically created list of channel operations. +/// +/// Once a list of operations has been built with `Select`, there are two different ways of +/// proceeding: +/// +/// * Select an operation with [`try_select`], [`select`], or [`select_timeout`]. If successful, +/// the returned selected operation has already begun and **must** be completed. If we don't +/// complete it, a panic will occur. +/// +/// * Wait for an operation to become ready with [`try_ready`], [`ready`], or [`ready_timeout`]. If +/// successful, we may attempt to execute the operation, but are not obliged to. In fact, it's +/// possible for another thread to make the operation not ready just before we try executing it, +/// so it's wise to use a retry loop. However, note that these methods might return with success +/// spuriously, so it's a good idea to always double check if the operation is really ready. +/// +/// # Examples +/// +/// Use [`select`] to receive a message from a list of receivers: +/// +/// ``` +/// use crossbeam_channel::{Receiver, RecvError, Select}; +/// +/// fn recv_multiple(rs: &[Receiver]) -> Result { +/// // Build a list of operations. +/// let mut sel = Select::new(); +/// for r in rs { +/// sel.recv(r); +/// } +/// +/// // Complete the selected operation. +/// let oper = sel.select(); +/// let index = oper.index(); +/// oper.recv(&rs[index]) +/// } +/// ``` +/// +/// Use [`ready`] to receive a message from a list of receivers: +/// +/// ``` +/// use crossbeam_channel::{Receiver, RecvError, Select}; +/// +/// fn recv_multiple(rs: &[Receiver]) -> Result { +/// // Build a list of operations. +/// let mut sel = Select::new(); +/// for r in rs { +/// sel.recv(r); +/// } +/// +/// loop { +/// // Wait until a receive operation becomes ready and try executing it. +/// let index = sel.ready(); +/// let res = rs[index].try_recv(); +/// +/// // If the operation turns out not to be ready, retry. +/// if let Err(e) = res { +/// if e.is_empty() { +/// continue; +/// } +/// } +/// +/// // Success! +/// return res.map_err(|_| RecvError); +/// } +/// } +/// ``` +/// +/// [`select!`]: macro.select.html +/// [`try_select`]: struct.Select.html#method.try_select +/// [`select`]: struct.Select.html#method.select +/// [`select_timeout`]: struct.Select.html#method.select_timeout +/// [`try_ready`]: struct.Select.html#method.try_ready +/// [`ready`]: struct.Select.html#method.ready +/// [`ready_timeout`]: struct.Select.html#method.ready_timeout +pub struct Select<'a> { + /// A list of senders and receivers participating in selection. + handles: Vec<(&'a dyn SelectHandle, usize, *const u8)>, + + /// The next index to assign to an operation. + next_index: usize, +} + +unsafe impl<'a> Send for Select<'a> {} +unsafe impl<'a> Sync for Select<'a> {} + +impl<'a> Select<'a> { + /// Creates an empty list of channel operations for selection. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::Select; + /// + /// let mut sel = Select::new(); + /// + /// // The list of operations is empty, which means no operation can be selected. + /// assert!(sel.try_select().is_err()); + /// ``` + pub fn new() -> Select<'a> { + Select { + handles: Vec::with_capacity(4), + next_index: 0, + } + } + + /// Adds a send operation. + /// + /// Returns the index of the added operation. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s, r) = unbounded::(); + /// + /// let mut sel = Select::new(); + /// let index = sel.send(&s); + /// ``` + pub fn send(&mut self, s: &'a Sender) -> usize { + let i = self.next_index; + let ptr = s as *const Sender<_> as *const u8; + self.handles.push((s, i, ptr)); + self.next_index += 1; + i + } + + /// Adds a receive operation. + /// + /// Returns the index of the added operation. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s, r) = unbounded::(); + /// + /// let mut sel = Select::new(); + /// let index = sel.recv(&r); + /// ``` + pub fn recv(&mut self, r: &'a Receiver) -> usize { + let i = self.next_index; + let ptr = r as *const Receiver<_> as *const u8; + self.handles.push((r, i, ptr)); + self.next_index += 1; + i + } + + /// Removes a previously added operation. + /// + /// This is useful when an operation is selected because the channel got disconnected and we + /// want to try again to select a different operation instead. + /// + /// If new operations are added after removing some, the indices of removed operations will not + /// be reused. + /// + /// # Panics + /// + /// An attempt to remove a non-existing or already removed operation will panic. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded::(); + /// let (_, r2) = unbounded::(); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // Both operations are initially ready, so a random one will be executed. + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper2); + /// assert!(oper.recv(&r2).is_err()); + /// sel.remove(oper2); + /// + /// s1.send(10).unwrap(); + /// + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper1); + /// assert_eq!(oper.recv(&r1), Ok(10)); + /// ``` + pub fn remove(&mut self, index: usize) { + assert!( + index < self.next_index, + "index out of bounds; {} >= {}", + index, + self.next_index, + ); + + let i = self + .handles + .iter() + .enumerate() + .find(|(_, (_, i, _))| *i == index) + .expect("no operation with this index") + .0; + + self.handles.swap_remove(i); + } + + /// Attempts to select one of the operations without blocking. + /// + /// If an operation is ready, it is selected and returned. If multiple operations are ready at + /// the same time, a random one among them is selected. If none of the operations are ready, an + /// error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// [`SelectedOperation::send`]: struct.SelectedOperation.html#method.send + /// [`SelectedOperation::recv`]: struct.SelectedOperation.html#method.recv + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// s1.send(10).unwrap(); + /// s2.send(20).unwrap(); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // Both operations are initially ready, so a random one will be executed. + /// let oper = sel.try_select(); + /// match oper { + /// Err(_) => panic!("both operations should be ready"), + /// Ok(oper) => match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// } + /// ``` + pub fn try_select(&mut self) -> Result, TrySelectError> { + try_select(&mut self.handles) + } + + /// Blocks until one of the operations becomes ready and selects it. + /// + /// Once an operation becomes ready, it is selected and returned. If multiple operations are + /// ready at the same time, a random one among them is selected. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// [`SelectedOperation::send`]: struct.SelectedOperation.html#method.send + /// [`SelectedOperation::recv`]: struct.SelectedOperation.html#method.recv + /// + /// # Panics + /// + /// Panics if no operations have been added to `Select`. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// let oper = sel.select(); + /// match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// ``` + pub fn select(&mut self) -> SelectedOperation<'a> { + select(&mut self.handles) + } + + /// Blocks for a limited time until one of the operations becomes ready and selects it. + /// + /// If an operation becomes ready, it is selected and returned. If multiple operations are + /// ready at the same time, a random one among them is selected. If none of the operations + /// become ready for the specified duration, an error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// [`SelectedOperation::send`]: struct.SelectedOperation.html#method.send + /// [`SelectedOperation::recv`]: struct.SelectedOperation.html#method.recv + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// let oper = sel.select_timeout(Duration::from_millis(500)); + /// match oper { + /// Err(_) => panic!("should not have timed out"), + /// Ok(oper) => match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// } + /// ``` + pub fn select_timeout( + &mut self, + timeout: Duration, + ) -> Result, SelectTimeoutError> { + select_timeout(&mut self.handles, timeout) + } + + /// Attempts to find a ready operation without blocking. + /// + /// If an operation is ready, its index is returned. If multiple operations are ready at the + /// same time, a random one among them is chosen. If none of the operations are ready, an error + /// is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to always + /// double check if the operation is really ready. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// s1.send(10).unwrap(); + /// s2.send(20).unwrap(); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // Both operations are initially ready, so a random one will be chosen. + /// match sel.try_ready() { + /// Err(_) => panic!("both operations should be ready"), + /// Ok(i) if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// Ok(_) => unreachable!(), + /// } + /// ``` + pub fn try_ready(&mut self) -> Result { + match run_ready(&mut self.handles, Timeout::Now) { + None => Err(TryReadyError), + Some(index) => Ok(index), + } + } + + /// Blocks until one of the operations becomes ready. + /// + /// Once an operation becomes ready, its index is returned. If multiple operations are ready at + /// the same time, a random one among them is chosen. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to always + /// double check if the operation is really ready. + /// + /// # Panics + /// + /// Panics if no operations have been added to `Select`. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// match sel.ready() { + /// i if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// i if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// _ => unreachable!(), + /// } + /// ``` + pub fn ready(&mut self) -> usize { + if self.handles.is_empty() { + panic!("no operations have been added to `Select`"); + } + + run_ready(&mut self.handles, Timeout::Never).unwrap() + } + + /// Blocks for a limited time until one of the operations becomes ready. + /// + /// If an operation becomes ready, its index is returned. If multiple operations are ready at + /// the same time, a random one among them is chosen. If none of the operations become ready + /// for the specified duration, an error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to double + /// check if the operation is really ready. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// match sel.ready_timeout(Duration::from_millis(500)) { + /// Err(_) => panic!("should not have timed out"), + /// Ok(i) if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// Ok(_) => unreachable!(), + /// } + /// ``` + pub fn ready_timeout(&mut self, timeout: Duration) -> Result { + let timeout = Timeout::At(Instant::now() + timeout); + + match run_ready(&mut self.handles, timeout) { + None => Err(ReadyTimeoutError), + Some(index) => Ok(index), + } + } +} + +impl<'a> Clone for Select<'a> { + fn clone(&self) -> Select<'a> { + Select { + handles: self.handles.clone(), + next_index: self.next_index, + } + } +} + +impl<'a> Default for Select<'a> { + fn default() -> Select<'a> { + Select::new() + } +} + +impl<'a> fmt::Debug for Select<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Select { .. }") + } +} + +/// A selected operation that needs to be completed. +/// +/// To complete the operation, call [`send`] or [`recv`]. +/// +/// # Panics +/// +/// Forgetting to complete the operation is an error and might lead to deadlocks. If a +/// `SelectedOperation` is dropped without completion, a panic occurs. +/// +/// [`send`]: struct.SelectedOperation.html#method.send +/// [`recv`]: struct.SelectedOperation.html#method.recv +#[must_use] +pub struct SelectedOperation<'a> { + /// Token needed to complete the operation. + token: Token, + + /// The index of the selected operation. + index: usize, + + /// The address of the selected `Sender` or `Receiver`. + ptr: *const u8, + + /// Indicates that `Sender`s and `Receiver`s are borrowed. + _marker: PhantomData<&'a ()>, +} + +impl<'a> SelectedOperation<'a> { + /// Returns the index of the selected operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, Select}; + /// + /// let (s1, r1) = bounded::<()>(0); + /// let (s2, r2) = bounded::<()>(0); + /// let (s3, r3) = bounded::<()>(1); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.send(&s1); + /// let oper2 = sel.recv(&r2); + /// let oper3 = sel.send(&s3); + /// + /// // Only the last operation is ready. + /// let oper = sel.select(); + /// assert_eq!(oper.index(), 2); + /// assert_eq!(oper.index(), oper3); + /// + /// // Complete the operation. + /// oper.send(&s3, ()).unwrap(); + /// ``` + pub fn index(&self) -> usize { + self.index + } + + /// Completes the send operation. + /// + /// The passed [`Sender`] reference must be the same one that was used in [`Select::send`] + /// when the operation was added. + /// + /// # Panics + /// + /// Panics if an incorrect [`Sender`] reference is passed. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, Select, SendError}; + /// + /// let (s, r) = bounded::(0); + /// drop(r); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.send(&s); + /// + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper1); + /// assert_eq!(oper.send(&s, 10), Err(SendError(10))); + /// ``` + /// + /// [`Sender`]: struct.Sender.html + /// [`Select::send`]: struct.Select.html#method.send + pub fn send(mut self, s: &Sender, msg: T) -> Result<(), SendError> { + assert!( + s as *const Sender as *const u8 == self.ptr, + "passed a sender that wasn't selected", + ); + let res = unsafe { channel::write(s, &mut self.token, msg) }; + mem::forget(self); + res.map_err(SendError) + } + + /// Completes the receive operation. + /// + /// The passed [`Receiver`] reference must be the same one that was used in [`Select::recv`] + /// when the operation was added. + /// + /// # Panics + /// + /// Panics if an incorrect [`Receiver`] reference is passed. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, Select, RecvError}; + /// + /// let (s, r) = bounded::(0); + /// drop(s); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r); + /// + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper1); + /// assert_eq!(oper.recv(&r), Err(RecvError)); + /// ``` + /// + /// [`Receiver`]: struct.Receiver.html + /// [`Select::recv`]: struct.Select.html#method.recv + pub fn recv(mut self, r: &Receiver) -> Result { + assert!( + r as *const Receiver as *const u8 == self.ptr, + "passed a receiver that wasn't selected", + ); + let res = unsafe { channel::read(r, &mut self.token) }; + mem::forget(self); + res.map_err(|_| RecvError) + } +} + +impl<'a> fmt::Debug for SelectedOperation<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("SelectedOperation { .. }") + } +} + +impl<'a> Drop for SelectedOperation<'a> { + fn drop(&mut self) { + panic!("dropped `SelectedOperation` without completing the operation"); + } +} diff --git a/vendor/crossbeam-channel/src/select_macro.rs b/vendor/crossbeam-channel/src/select_macro.rs new file mode 100644 index 0000000000..9aaaa9e935 --- /dev/null +++ b/vendor/crossbeam-channel/src/select_macro.rs @@ -0,0 +1,1214 @@ +//! The `select!` macro. + +/// A simple wrapper around the standard macros. +/// +/// This is just an ugly workaround until it becomes possible to import macros with `use` +/// statements. +/// +/// TODO(stjepang): Once we bump the minimum required Rust version to 1.30 or newer, we should: +/// +/// 1. Remove all `#[macro_export(local_inner_macros)]` lines. +/// 2. Replace `crossbeam_channel_delegate` with direct macro invocations. +#[doc(hidden)] +#[macro_export] +macro_rules! crossbeam_channel_delegate { + (concat($($args:tt)*)) => { + concat!($($args)*) + }; + (stringify($($args:tt)*)) => { + stringify!($($args)*) + }; + (unreachable($($args:tt)*)) => { + unreachable!($($args)*) + }; + (compile_error($($args:tt)*)) => { + compile_error!($($args)*) + }; +} + +/// A helper macro for `select!` to hide the long list of macro patterns from the documentation. +/// +/// The macro consists of two stages: +/// 1. Parsing +/// 2. Code generation +/// +/// The parsing stage consists of these subparts: +/// 1. `@list`: Turns a list of tokens into a list of cases. +/// 2. `@list_errorN`: Diagnoses the syntax error. +/// 3. `@case`: Parses a single case and verifies its argument list. +/// +/// The codegen stage consists of these subparts: +/// 1. `@init`: Attempts to optimize `select!` away and initializes the list of handles. +/// 1. `@count`: Counts the listed cases. +/// 3. `@add`: Adds send/receive operations to the list of handles and starts selection. +/// 4. `@complete`: Completes the selected send/receive operation. +/// +/// If the parsing stage encounters a syntax error or the codegen stage ends up with too many +/// cases to process, the macro fails with a compile-time error. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! crossbeam_channel_internal { + // The list is empty. Now check the arguments of each processed case. + (@list + () + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @case + ($($head)*) + () + () + ) + }; + // If necessary, insert an empty argument list after `default`. + (@list + (default => $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + (default() => $($tail)*) + ($($head)*) + ) + }; + // But print an error if `default` is followed by a `->`. + (@list + (default -> $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "expected `=>` after `default` case, found `->`" + )) + }; + // Print an error if there's an `->` after the argument list in the default case. + (@list + (default $args:tt -> $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "expected `=>` after `default` case, found `->`" + )) + }; + // Print an error if there is a missing result in a recv case. + (@list + (recv($($args:tt)*) => $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "expected `->` after `recv` case, found `=>`" + )) + }; + // Print an error if there is a missing result in a send case. + (@list + (send($($args:tt)*) => $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "expected `->` after `send` operation, found `=>`" + )) + }; + // Make sure the arrow and the result are not repeated. + (@list + ($case:ident $args:tt -> $res:tt -> $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error("expected `=>`, found `->`")) + }; + // Print an error if there is a semicolon after the block. + (@list + ($case:ident $args:tt $(-> $res:pat)* => $body:block; $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "did you mean to put a comma instead of the semicolon after `}`?" + )) + }; + // The first case is separated by a comma. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr, $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + ($($tail)*) + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Don't require a comma after the case if it has a proper block. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:block $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + ($($tail)*) + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Only one case remains. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + () + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Accept a trailing comma at the end of the list. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr,) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + () + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Diagnose and print an error. + (@list + ($($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!(@list_error1 $($tail)*) + }; + // Stage 1: check the case type. + (@list_error1 recv $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error2 recv $($tail)*) + }; + (@list_error1 send $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error2 send $($tail)*) + }; + (@list_error1 default $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error2 default $($tail)*) + }; + (@list_error1 $t:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected one of `recv`, `send`, or `default`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error1 $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error2 $($tail)*); + }; + // Stage 2: check the argument list. + (@list_error2 $case:ident) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "missing argument list after `", + crossbeam_channel_delegate!(stringify($case)), + "`", + )) + )) + }; + (@list_error2 $case:ident => $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "missing argument list after `", + crossbeam_channel_delegate!(stringify($case)), + "`", + )) + )) + }; + (@list_error2 $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error3 $($tail)*) + }; + // Stage 3: check the `=>` and what comes after it. + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "missing `=>` after `", + crossbeam_channel_delegate!(stringify($case)), + "` case", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* =>) => { + crossbeam_channel_delegate!(compile_error( + "expected expression after `=>`" + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:expr; $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma instead of the semicolon after `", + crossbeam_channel_delegate!(stringify($body)), + "`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => recv($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + "expected an expression after `=>`" + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => send($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + "expected an expression after `=>`" + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => default($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + "expected an expression after `=>`" + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($f)), + "(", + crossbeam_channel_delegate!(stringify($($a)*)), + ")`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($f)), + "!(", + crossbeam_channel_delegate!(stringify($($a)*)), + ")`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident![$($a:tt)*] $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($f)), + "![", + crossbeam_channel_delegate!(stringify($($a)*)), + "]`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!{$($a:tt)*} $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($f)), + "!{", + crossbeam_channel_delegate!(stringify($($a)*)), + "}`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($body)), + "`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) -> => $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error("missing pattern after `->`")) + }; + (@list_error3 $case:ident($($args:tt)*) $t:tt $(-> $r:pat)* => $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected `->`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) -> $t:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected a pattern, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error3 recv($($args:tt)*) $t:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected `->`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error3 send($($args:tt)*) $t:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected `->`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error3 recv $args:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list after `recv`, found `", + crossbeam_channel_delegate!(stringify($args)), + "`", + )) + )) + }; + (@list_error3 send $args:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list after `send`, found `", + crossbeam_channel_delegate!(stringify($args)), + "`", + )) + )) + }; + (@list_error3 default $args:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list or `=>` after `default`, found `", + crossbeam_channel_delegate!(stringify($args)), + "`", + )) + )) + }; + (@list_error3 $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error4 $($tail)*) + }; + // Stage 4: fail with a generic error message. + (@list_error4 $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error("invalid syntax")) + }; + + // Success! All cases were parsed. + (@case + () + $cases:tt + $default:tt + ) => { + crossbeam_channel_internal!( + @init + $cases + $default + ) + }; + + // Check the format of a recv case. + (@case + (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* recv($r) -> $res => $body,) + $default + ) + }; + // Allow trailing comma... + (@case + (recv($r:expr,) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* recv($r) -> $res => $body,) + $default + ) + }; + // Print an error if the argument list is invalid. + (@case + (recv($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "invalid argument list in `recv(", + crossbeam_channel_delegate!(stringify($($args)*)), + ")`", + )) + )) + }; + // Print an error if there is no argument list. + (@case + (recv $t:tt $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list after `recv`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + + // Check the format of a send case. + (@case + (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* send($s, $m) -> $res => $body,) + $default + ) + }; + // Allow trailing comma... + (@case + (send($s:expr, $m:expr,) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* send($s, $m) -> $res => $body,) + $default + ) + }; + // Print an error if the argument list is invalid. + (@case + (send($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "invalid argument list in `send(", + crossbeam_channel_delegate!(stringify($($args)*)), + ")`", + )) + )) + }; + // Print an error if there is no argument list. + (@case + (send $t:tt $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list after `send`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + + // Check the format of a default case. + (@case + (default() => $body:tt, $($tail:tt)*) + $cases:tt + () + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + $cases + (default() => $body,) + ) + }; + // Check the format of a default case with timeout. + (@case + (default($timeout:expr) => $body:tt, $($tail:tt)*) + $cases:tt + () + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + $cases + (default($timeout) => $body,) + ) + }; + // Allow trailing comma... + (@case + (default($timeout:expr,) => $body:tt, $($tail:tt)*) + $cases:tt + () + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + $cases + (default($timeout) => $body,) + ) + }; + // Check for duplicate default cases... + (@case + (default $($tail:tt)*) + $cases:tt + ($($def:tt)+) + ) => { + crossbeam_channel_delegate!(compile_error( + "there can be only one `default` case in a `select!` block" + )) + }; + // Print an error if the argument list is invalid. + (@case + (default($($args:tt)*) => $body:tt, $($tail:tt)*) + $cases:tt + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "invalid argument list in `default(", + crossbeam_channel_delegate!(stringify($($args)*)), + ")`", + )) + )) + }; + // Print an error if there is an unexpected token after `default`. + (@case + (default $t:tt $($tail:tt)*) + $cases:tt + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list or `=>` after `default`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + + // The case was not consumed, therefore it must be invalid. + (@case + ($case:ident $($tail:tt)*) + $cases:tt + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected one of `recv`, `send`, or `default`, found `", + crossbeam_channel_delegate!(stringify($case)), + "`", + )) + )) + }; + + // Optimize `select!` into `try_recv()`. + (@init + (recv($r:expr) -> $res:pat => $recv_body:tt,) + (default() => $default_body:tt,) + ) => {{ + match $r { + ref _r => { + let _r: &$crate::Receiver<_> = _r; + match _r.try_recv() { + ::std::result::Result::Err($crate::TryRecvError::Empty) => { + $default_body + } + _res => { + let _res = _res.map_err(|_| $crate::RecvError); + let $res = _res; + $recv_body + } + } + } + } + }}; + // Optimize `select!` into `recv()`. + (@init + (recv($r:expr) -> $res:pat => $body:tt,) + () + ) => {{ + match $r { + ref _r => { + let _r: &$crate::Receiver<_> = _r; + let _res = _r.recv(); + let $res = _res; + $body + } + } + }}; + // Optimize `select!` into `recv_timeout()`. + (@init + (recv($r:expr) -> $res:pat => $recv_body:tt,) + (default($timeout:expr) => $default_body:tt,) + ) => {{ + match $r { + ref _r => { + let _r: &$crate::Receiver<_> = _r; + match _r.recv_timeout($timeout) { + ::std::result::Result::Err($crate::RecvTimeoutError::Timeout) => { + $default_body + } + _res => { + let _res = _res.map_err(|_| $crate::RecvError); + let $res = _res; + $recv_body + } + } + } + } + }}; + + // // Optimize the non-blocking case with two receive operations. + // (@init + // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,) + // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,) + // (default() => $default_body:tt,) + // ) => {{ + // match $r1 { + // ref _r1 => { + // let _r1: &$crate::Receiver<_> = _r1; + // + // match $r2 { + // ref _r2 => { + // let _r2: &$crate::Receiver<_> = _r2; + // + // // TODO(stjepang): Implement this optimization. + // } + // } + // } + // } + // }}; + // // Optimize the blocking case with two receive operations. + // (@init + // (recv($r1:expr) -> $res1:pat => $body1:tt,) + // (recv($r2:expr) -> $res2:pat => $body2:tt,) + // () + // ) => {{ + // match $r1 { + // ref _r1 => { + // let _r1: &$crate::Receiver<_> = _r1; + // + // match $r2 { + // ref _r2 => { + // let _r2: &$crate::Receiver<_> = _r2; + // + // // TODO(stjepang): Implement this optimization. + // } + // } + // } + // } + // }}; + // // Optimize the case with two receive operations and a timeout. + // (@init + // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,) + // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,) + // (default($timeout:expr) => $default_body:tt,) + // ) => {{ + // match $r1 { + // ref _r1 => { + // let _r1: &$crate::Receiver<_> = _r1; + // + // match $r2 { + // ref _r2 => { + // let _r2: &$crate::Receiver<_> = _r2; + // + // // TODO(stjepang): Implement this optimization. + // } + // } + // } + // } + // }}; + + // // Optimize `select!` into `try_send()`. + // (@init + // (send($s:expr, $m:expr) -> $res:pat => $send_body:tt,) + // (default() => $default_body:tt,) + // ) => {{ + // match $s { + // ref _s => { + // let _s: &$crate::Sender<_> = _s; + // // TODO(stjepang): Implement this optimization. + // } + // } + // }}; + // // Optimize `select!` into `send()`. + // (@init + // (send($s:expr, $m:expr) -> $res:pat => $body:tt,) + // () + // ) => {{ + // match $s { + // ref _s => { + // let _s: &$crate::Sender<_> = _s; + // // TODO(stjepang): Implement this optimization. + // } + // } + // }}; + // // Optimize `select!` into `send_timeout()`. + // (@init + // (send($s:expr, $m:expr) -> $res:pat => $body:tt,) + // (default($timeout:expr) => $body:tt,) + // ) => {{ + // match $s { + // ref _s => { + // let _s: &$crate::Sender<_> = _s; + // // TODO(stjepang): Implement this optimization. + // } + // } + // }}; + + // Create the list of handles and add operations to it. + (@init + ($($cases:tt)*) + $default:tt + ) => {{ + const _LEN: usize = crossbeam_channel_internal!(@count ($($cases)*)); + let _handle: &$crate::internal::SelectHandle = &$crate::never::<()>(); + + #[allow(unused_mut)] + let mut _sel = [(_handle, 0, ::std::ptr::null()); _LEN]; + + crossbeam_channel_internal!( + @add + _sel + ($($cases)*) + $default + ( + (0usize _oper0) + (1usize _oper1) + (2usize _oper2) + (3usize _oper3) + (4usize _oper4) + (5usize _oper5) + (6usize _oper6) + (7usize _oper7) + (8usize _oper8) + (9usize _oper9) + (10usize _oper10) + (11usize _oper11) + (12usize _oper12) + (13usize _oper13) + (14usize _oper14) + (15usize _oper15) + (16usize _oper16) + (17usize _oper17) + (18usize _oper18) + (19usize _oper19) + (20usize _oper20) + (21usize _oper21) + (22usize _oper22) + (23usize _oper23) + (24usize _oper24) + (25usize _oper25) + (26usize _oper26) + (27usize _oper27) + (28usize _oper28) + (29usize _oper29) + (30usize _oper30) + (31usize _oper31) + ) + () + ) + }}; + + // Count the listed cases. + (@count ()) => { + 0 + }; + (@count ($oper:ident $args:tt -> $res:pat => $body:tt, $($cases:tt)*)) => { + 1 + crossbeam_channel_internal!(@count ($($cases)*)) + }; + + // Run blocking selection. + (@add + $sel:ident + () + () + $labels:tt + $cases:tt + ) => {{ + let _oper: $crate::SelectedOperation<'_> = { + let _oper = $crate::internal::select(&mut $sel); + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + #[allow(unsafe_code)] + unsafe { ::std::mem::transmute(_oper) } + }; + + crossbeam_channel_internal! { + @complete + $sel + _oper + $cases + } + }}; + // Run non-blocking selection. + (@add + $sel:ident + () + (default() => $body:tt,) + $labels:tt + $cases:tt + ) => {{ + let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = { + let _oper = $crate::internal::try_select(&mut $sel); + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + #[allow(unsafe_code)] + unsafe { ::std::mem::transmute(_oper) } + }; + + match _oper { + None => { + { $sel }; + $body + } + Some(_oper) => { + crossbeam_channel_internal! { + @complete + $sel + _oper + $cases + } + } + } + }}; + // Run selection with a timeout. + (@add + $sel:ident + () + (default($timeout:expr) => $body:tt,) + $labels:tt + $cases:tt + ) => {{ + let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = { + let _oper = $crate::internal::select_timeout(&mut $sel, $timeout); + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + #[allow(unsafe_code)] + unsafe { ::std::mem::transmute(_oper) } + }; + + match _oper { + ::std::option::Option::None => { + { $sel }; + $body + } + ::std::option::Option::Some(_oper) => { + crossbeam_channel_internal! { + @complete + $sel + _oper + $cases + } + } + } + }}; + // Have we used up all labels? + (@add + $sel:ident + $input:tt + $default:tt + () + $cases:tt + ) => { + crossbeam_channel_delegate!(compile_error("too many operations in a `select!` block")) + }; + // Add a receive operation to `sel`. + (@add + $sel:ident + (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*) + $default:tt + (($i:tt $var:ident) $($labels:tt)*) + ($($cases:tt)*) + ) => {{ + match $r { + ref _r => { + #[allow(unsafe_code)] + let $var: &$crate::Receiver<_> = unsafe { + let _r: &$crate::Receiver<_> = _r; + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + unsafe fn unbind<'a, T>(x: &T) -> &'a T { + ::std::mem::transmute(x) + } + unbind(_r) + }; + $sel[$i] = ($var, $i, $var as *const $crate::Receiver<_> as *const u8); + + crossbeam_channel_internal!( + @add + $sel + ($($tail)*) + $default + ($($labels)*) + ($($cases)* [$i] recv($var) -> $res => $body,) + ) + } + } + }}; + // Add a send operation to `sel`. + (@add + $sel:ident + (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) + $default:tt + (($i:tt $var:ident) $($labels:tt)*) + ($($cases:tt)*) + ) => {{ + match $s { + ref _s => { + #[allow(unsafe_code)] + let $var: &$crate::Sender<_> = unsafe { + let _s: &$crate::Sender<_> = _s; + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + unsafe fn unbind<'a, T>(x: &T) -> &'a T { + ::std::mem::transmute(x) + } + unbind(_s) + }; + $sel[$i] = ($var, $i, $var as *const $crate::Sender<_> as *const u8); + + crossbeam_channel_internal!( + @add + $sel + ($($tail)*) + $default + ($($labels)*) + ($($cases)* [$i] send($var, $m) -> $res => $body,) + ) + } + } + }}; + + // Complete a receive operation. + (@complete + $sel:ident + $oper:ident + ([$i:tt] recv($r:ident) -> $res:pat => $body:tt, $($tail:tt)*) + ) => {{ + if $oper.index() == $i { + let _res = $oper.recv($r); + { $sel }; + + let $res = _res; + $body + } else { + crossbeam_channel_internal! { + @complete + $sel + $oper + ($($tail)*) + } + } + }}; + // Complete a send operation. + (@complete + $sel:ident + $oper:ident + ([$i:tt] send($s:ident, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) + ) => {{ + if $oper.index() == $i { + let _res = $oper.send($s, $m); + { $sel }; + + let $res = _res; + $body + } else { + crossbeam_channel_internal! { + @complete + $sel + $oper + ($($tail)*) + } + } + }}; + // Panic if we don't identify the selected case, but this should never happen. + (@complete + $sel:ident + $oper:ident + () + ) => {{ + crossbeam_channel_delegate!(unreachable( + "internal error in crossbeam-channel: invalid case" + )) + }}; + + // Catches a bug within this macro (should not happen). + (@$($tokens:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "internal error in crossbeam-channel: ", + crossbeam_channel_delegate!(stringify(@$($tokens)*)), + )) + )) + }; + + // The entry points. + () => { + crossbeam_channel_delegate!(compile_error("empty `select!` block")) + }; + ($($case:ident $(($($args:tt)*))* => $body:expr $(,)*)*) => { + crossbeam_channel_internal!( + @list + ($($case $(($($args)*))* => { $body },)*) + () + ) + }; + ($($tokens:tt)*) => { + crossbeam_channel_internal!( + @list + ($($tokens)*) + () + ) + }; +} + +/// Selects from a set of channel operations. +/// +/// This macro allows you to define a set of channel operations, wait until any one of them becomes +/// ready, and finally execute it. If multiple operations are ready at the same time, a random one +/// among them is selected. +/// +/// It is also possible to define a `default` case that gets executed if none of the operations are +/// ready, either right away or for a certain duration of time. +/// +/// An operation is considered to be ready if it doesn't have to block. Note that it is ready even +/// when it will simply return an error because the channel is disconnected. +/// +/// The `select` macro is a convenience wrapper around [`Select`]. However, it cannot select over a +/// dynamically created list of channel operations. +/// +/// [`Select`]: struct.Select.html +/// +/// # Examples +/// +/// Block until a send or a receive operation is selected: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// s1.send(10).unwrap(); +/// +/// // Since both operations are initially ready, a random one will be executed. +/// select! { +/// recv(r1) -> msg => assert_eq!(msg, Ok(10)), +/// send(s2, 20) -> res => { +/// assert_eq!(res, Ok(())); +/// assert_eq!(r2.recv(), Ok(20)); +/// } +/// } +/// # } +/// ``` +/// +/// Select from a set of operations without blocking: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s1.send(10).unwrap(); +/// }); +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// s2.send(20).unwrap(); +/// }); +/// +/// // None of the operations are initially ready. +/// select! { +/// recv(r1) -> msg => panic!(), +/// recv(r2) -> msg => panic!(), +/// default => println!("not ready"), +/// } +/// # } +/// ``` +/// +/// Select over a set of operations with a timeout: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s1.send(10).unwrap(); +/// }); +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// s2.send(20).unwrap(); +/// }); +/// +/// // None of the two operations will become ready within 100 milliseconds. +/// select! { +/// recv(r1) -> msg => panic!(), +/// recv(r2) -> msg => panic!(), +/// default(Duration::from_millis(100)) => println!("timed out"), +/// } +/// # } +/// ``` +/// +/// Optionally add a receive operation to `select!` using [`never`]: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::{never, unbounded}; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s1.send(10).unwrap(); +/// }); +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// s2.send(20).unwrap(); +/// }); +/// +/// // This receiver can be a `Some` or a `None`. +/// let r2 = Some(&r2); +/// +/// // None of the two operations will become ready within 100 milliseconds. +/// select! { +/// recv(r1) -> msg => panic!(), +/// recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)), +/// } +/// # } +/// ``` +/// +/// To optionally add a timeout to `select!`, see the [example] for [`never`]. +/// +/// [`never`]: fn.never.html +/// [example]: fn.never.html#examples +#[macro_export(local_inner_macros)] +macro_rules! select { + ($($tokens:tt)*) => { + crossbeam_channel_internal!( + $($tokens)* + ) + }; +} diff --git a/vendor/crossbeam-channel/src/utils.rs b/vendor/crossbeam-channel/src/utils.rs new file mode 100644 index 0000000000..c6513bc3f8 --- /dev/null +++ b/vendor/crossbeam-channel/src/utils.rs @@ -0,0 +1,112 @@ +//! Miscellaneous utilities. + +use std::cell::{Cell, UnsafeCell}; +use std::num::Wrapping; +use std::ops::{Deref, DerefMut}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_utils::Backoff; + +/// Randomly shuffles a slice. +pub fn shuffle(v: &mut [T]) { + let len = v.len(); + if len <= 1 { + return; + } + + thread_local! { + static RNG: Cell> = Cell::new(Wrapping(1406868647)); + } + + let _ = RNG.try_with(|rng| { + for i in 1..len { + // This is the 32-bit variant of Xorshift. + // + // Source: https://en.wikipedia.org/wiki/Xorshift + let mut x = rng.get(); + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + rng.set(x); + + let x = x.0; + let n = i + 1; + + // This is a fast alternative to `let j = x % n`. + // + // Author: Daniel Lemire + // Source: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ + let j = ((x as u64).wrapping_mul(n as u64) >> 32) as u32 as usize; + + v.swap(i, j); + } + }); +} + +/// Sleeps until the deadline, or forever if the deadline isn't specified. +pub fn sleep_until(deadline: Option) { + loop { + match deadline { + None => thread::sleep(Duration::from_secs(1000)), + Some(d) => { + let now = Instant::now(); + if now >= d { + break; + } + thread::sleep(d - now); + } + } + } +} + +/// A simple spinlock. +pub struct Spinlock { + flag: AtomicBool, + value: UnsafeCell, +} + +impl Spinlock { + /// Returns a new spinlock initialized with `value`. + pub fn new(value: T) -> Spinlock { + Spinlock { + flag: AtomicBool::new(false), + value: UnsafeCell::new(value), + } + } + + /// Locks the spinlock. + pub fn lock(&self) -> SpinlockGuard<'_, T> { + let backoff = Backoff::new(); + while self.flag.swap(true, Ordering::Acquire) { + backoff.snooze(); + } + SpinlockGuard { parent: self } + } +} + +/// A guard holding a spinlock locked. +pub struct SpinlockGuard<'a, T: 'a> { + parent: &'a Spinlock, +} + +impl<'a, T> Drop for SpinlockGuard<'a, T> { + fn drop(&mut self) { + self.parent.flag.store(false, Ordering::Release); + } +} + +impl<'a, T> Deref for SpinlockGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.parent.value.get() } + } +} + +impl<'a, T> DerefMut for SpinlockGuard<'a, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.parent.value.get() } + } +} diff --git a/vendor/crossbeam-channel/src/waker.rs b/vendor/crossbeam-channel/src/waker.rs new file mode 100644 index 0000000000..7f3428b7eb --- /dev/null +++ b/vendor/crossbeam-channel/src/waker.rs @@ -0,0 +1,285 @@ +//! Waking mechanism for threads blocked on channel operations. + +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread::{self, ThreadId}; + +use context::Context; +use select::{Operation, Selected}; +use utils::Spinlock; + +/// Represents a thread blocked on a specific channel operation. +pub struct Entry { + /// The operation. + pub oper: Operation, + + /// Optional packet. + pub packet: usize, + + /// Context associated with the thread owning this operation. + pub cx: Context, +} + +/// A queue of threads blocked on channel operations. +/// +/// This data structure is used by threads to register blocking operations and get woken up once +/// an operation becomes ready. +pub struct Waker { + /// A list of select operations. + selectors: Vec, + + /// A list of operations waiting to be ready. + observers: Vec, +} + +impl Waker { + /// Creates a new `Waker`. + #[inline] + pub fn new() -> Self { + Waker { + selectors: Vec::new(), + observers: Vec::new(), + } + } + + /// Registers a select operation. + #[inline] + pub fn register(&mut self, oper: Operation, cx: &Context) { + self.register_with_packet(oper, 0, cx); + } + + /// Registers a select operation and a packet. + #[inline] + pub fn register_with_packet(&mut self, oper: Operation, packet: usize, cx: &Context) { + self.selectors.push(Entry { + oper, + packet, + cx: cx.clone(), + }); + } + + /// Unregisters a select operation. + #[inline] + pub fn unregister(&mut self, oper: Operation) -> Option { + if let Some((i, _)) = self + .selectors + .iter() + .enumerate() + .find(|&(_, entry)| entry.oper == oper) + { + let entry = self.selectors.remove(i); + Some(entry) + } else { + None + } + } + + /// Attempts to find another thread's entry, select the operation, and wake it up. + #[inline] + pub fn try_select(&mut self) -> Option { + let mut entry = None; + + if !self.selectors.is_empty() { + let thread_id = current_thread_id(); + + for i in 0..self.selectors.len() { + // Does the entry belong to a different thread? + if self.selectors[i].cx.thread_id() != thread_id { + // Try selecting this operation. + let sel = Selected::Operation(self.selectors[i].oper); + let res = self.selectors[i].cx.try_select(sel); + + if res.is_ok() { + // Provide the packet. + self.selectors[i].cx.store_packet(self.selectors[i].packet); + // Wake the thread up. + self.selectors[i].cx.unpark(); + + // Remove the entry from the queue to keep it clean and improve + // performance. + entry = Some(self.selectors.remove(i)); + break; + } + } + } + } + + entry + } + + /// Returns `true` if there is an entry which can be selected by the current thread. + #[inline] + pub fn can_select(&self) -> bool { + if self.selectors.is_empty() { + false + } else { + let thread_id = current_thread_id(); + + self.selectors.iter().any(|entry| { + entry.cx.thread_id() != thread_id && entry.cx.selected() == Selected::Waiting + }) + } + } + + /// Registers an operation waiting to be ready. + #[inline] + pub fn watch(&mut self, oper: Operation, cx: &Context) { + self.observers.push(Entry { + oper, + packet: 0, + cx: cx.clone(), + }); + } + + /// Unregisters an operation waiting to be ready. + #[inline] + pub fn unwatch(&mut self, oper: Operation) { + self.observers.retain(|e| e.oper != oper); + } + + /// Notifies all operations waiting to be ready. + #[inline] + pub fn notify(&mut self) { + for entry in self.observers.drain(..) { + if entry.cx.try_select(Selected::Operation(entry.oper)).is_ok() { + entry.cx.unpark(); + } + } + } + + /// Notifies all registered operations that the channel is disconnected. + #[inline] + pub fn disconnect(&mut self) { + for entry in self.selectors.iter() { + if entry.cx.try_select(Selected::Disconnected).is_ok() { + // Wake the thread up. + // + // Here we don't remove the entry from the queue. Registered threads must + // unregister from the waker by themselves. They might also want to recover the + // packet value and destroy it, if necessary. + entry.cx.unpark(); + } + } + + self.notify(); + } +} + +impl Drop for Waker { + #[inline] + fn drop(&mut self) { + debug_assert_eq!(self.selectors.len(), 0); + debug_assert_eq!(self.observers.len(), 0); + } +} + +/// A waker that can be shared among threads without locking. +/// +/// This is a simple wrapper around `Waker` that internally uses a mutex for synchronization. +pub struct SyncWaker { + /// The inner `Waker`. + inner: Spinlock, + + /// `true` if the waker is empty. + is_empty: AtomicBool, +} + +impl SyncWaker { + /// Creates a new `SyncWaker`. + #[inline] + pub fn new() -> Self { + SyncWaker { + inner: Spinlock::new(Waker::new()), + is_empty: AtomicBool::new(true), + } + } + + /// Registers the current thread with an operation. + #[inline] + pub fn register(&self, oper: Operation, cx: &Context) { + let mut inner = self.inner.lock(); + inner.register(oper, cx); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + + /// Unregisters an operation previously registered by the current thread. + #[inline] + pub fn unregister(&self, oper: Operation) -> Option { + let mut inner = self.inner.lock(); + let entry = inner.unregister(oper); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + entry + } + + /// Attempts to find one thread (not the current one), select its operation, and wake it up. + #[inline] + pub fn notify(&self) { + if !self.is_empty.load(Ordering::SeqCst) { + let mut inner = self.inner.lock(); + inner.try_select(); + inner.notify(); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + } + + /// Registers an operation waiting to be ready. + #[inline] + pub fn watch(&self, oper: Operation, cx: &Context) { + let mut inner = self.inner.lock(); + inner.watch(oper, cx); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + + /// Unregisters an operation waiting to be ready. + #[inline] + pub fn unwatch(&self, oper: Operation) { + let mut inner = self.inner.lock(); + inner.unwatch(oper); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + + /// Notifies all threads that the channel is disconnected. + #[inline] + pub fn disconnect(&self) { + let mut inner = self.inner.lock(); + inner.disconnect(); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } +} + +impl Drop for SyncWaker { + #[inline] + fn drop(&mut self) { + debug_assert_eq!(self.is_empty.load(Ordering::SeqCst), true); + } +} + +/// Returns the id of the current thread. +#[inline] +fn current_thread_id() -> ThreadId { + thread_local! { + /// Cached thread-local id. + static THREAD_ID: ThreadId = thread::current().id(); + } + + THREAD_ID + .try_with(|id| *id) + .unwrap_or_else(|_| thread::current().id()) +} diff --git a/vendor/crossbeam-channel/tests/after.rs b/vendor/crossbeam-channel/tests/after.rs new file mode 100644 index 0000000000..1137bb1b77 --- /dev/null +++ b/vendor/crossbeam-channel/tests/after.rs @@ -0,0 +1,339 @@ +//! Tests for the after channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, Select, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn fire() { + let start = Instant::now(); + let r = after(ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(100)); + + let fired = r.try_recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired >= ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + + select! { + recv(r) -> _ => panic!(), + default => {} + } + + select! { + recv(r) -> _ => panic!(), + recv(after(ms(200))) -> _ => {} + } +} + +#[test] +fn capacity() { + const COUNT: usize = 10; + + for i in 0..COUNT { + let r = after(ms(i as u64)); + assert_eq!(r.capacity(), Some(1)); + } +} + +#[test] +fn len_empty_full() { + let r = after(ms(50)); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + thread::sleep(ms(100)); + + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), true); + + r.try_recv().unwrap(); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let r = after(ms(200)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(100)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_ok()); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_err()); +} + +#[test] +fn recv() { + let start = Instant::now(); + let r = after(ms(50)); + + let fired = r.recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired < fired - start); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn recv_timeout() { + let start = Instant::now(); + let r = after(ms(200)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(100)); + assert!(now - start <= ms(150)); + + let fired = r.recv_timeout(ms(200)).unwrap(); + assert!(fired - start >= ms(200)); + assert!(fired - start <= ms(250)); + + assert!(r.recv_timeout(ms(200)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(400)); + assert!(now - start <= ms(450)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn recv_two() { + let r1 = after(ms(50)); + let r2 = after(ms(50)); + + scope(|scope| { + scope.spawn(|_| { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + }); + scope.spawn(|_| { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + }); + }) + .unwrap(); +} + +#[test] +fn recv_race() { + select! { + recv(after(ms(50))) -> _ => {} + recv(after(ms(100))) -> _ => panic!(), + } + + select! { + recv(after(ms(100))) -> _ => panic!(), + recv(after(ms(50))) -> _ => {} + } +} + +#[test] +fn stress_default() { + const COUNT: usize = 10; + + for _ in 0..COUNT { + select! { + recv(after(ms(0))) -> _ => {} + default => panic!(), + } + } + + for _ in 0..COUNT { + select! { + recv(after(ms(100))) -> _ => panic!(), + default => {} + } + } +} + +#[test] +fn select() { + const THREADS: usize = 4; + const COUNT: usize = 1000; + const TIMEOUT_MS: u64 = 100; + + let v = (0..COUNT) + .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2))) + .collect::>(); + let hits = AtomicUsize::new(0); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let v: Vec<&_> = v.iter().collect(); + + loop { + let timeout = after(ms(TIMEOUT_MS)); + let mut sel = Select::new(); + for r in &v { + sel.recv(r); + } + let oper_timeout = sel.recv(&timeout); + + let oper = sel.select(); + match oper.index() { + i if i == oper_timeout => { + oper.recv(&timeout).unwrap(); + break; + } + i => { + oper.recv(&v[i]).unwrap(); + hits.fetch_add(1, Ordering::SeqCst); + } + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), COUNT); +} + +#[test] +fn ready() { + const THREADS: usize = 4; + const COUNT: usize = 1000; + const TIMEOUT_MS: u64 = 100; + + let v = (0..COUNT) + .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2))) + .collect::>(); + let hits = AtomicUsize::new(0); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let v: Vec<&_> = v.iter().collect(); + + loop { + let timeout = after(ms(TIMEOUT_MS)); + let mut sel = Select::new(); + for r in &v { + sel.recv(r); + } + let oper_timeout = sel.recv(&timeout); + + loop { + let i = sel.ready(); + if i == oper_timeout { + timeout.try_recv().unwrap(); + return; + } else if v[i].try_recv().is_ok() { + hits.fetch_add(1, Ordering::SeqCst); + break; + } + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), COUNT); +} + +#[test] +fn stress_clone() { + const RUNS: usize = 1000; + const THREADS: usize = 10; + const COUNT: usize = 50; + + for i in 0..RUNS { + let r = after(ms(i as u64)); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let r = r.clone(); + let _ = r.try_recv(); + + for _ in 0..COUNT { + drop(r.clone()); + thread::yield_now(); + } + }); + } + }) + .unwrap(); + } +} + +#[test] +fn fairness() { + const COUNT: usize = 1000; + + for &dur in &[0, 1] { + let mut hits = [0usize; 2]; + + for _ in 0..COUNT { + select! { + recv(after(ms(dur))) -> _ => hits[0] += 1, + recv(after(ms(dur))) -> _ => hits[1] += 1, + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 1000; + + for &dur in &[0, 1] { + let mut hits = [0usize; 5]; + + for _ in 0..COUNT { + let r = after(ms(dur)); + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} diff --git a/vendor/crossbeam-channel/tests/array.rs b/vendor/crossbeam-channel/tests/array.rs new file mode 100644 index 0000000000..a6fc8451b1 --- /dev/null +++ b/vendor/crossbeam-channel/tests/array.rs @@ -0,0 +1,659 @@ +//! Tests for the array channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{bounded, Receiver}; +use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; +use crossbeam_channel::{SendError, SendTimeoutError, TrySendError}; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + let (s, r) = bounded(1); + s.send(7).unwrap(); + assert_eq!(r.try_recv(), Ok(7)); + + s.send(8).unwrap(); + assert_eq!(r.recv(), Ok(8)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); +} + +#[test] +fn capacity() { + for i in 1..10 { + let (s, r) = bounded::<()>(i); + assert_eq!(s.capacity(), Some(i)); + assert_eq!(r.capacity(), Some(i)); + } +} + +#[test] +fn len_empty_full() { + let (s, r) = bounded(2); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + s.send(()).unwrap(); + + assert_eq!(s.len(), 1); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), false); + + s.send(()).unwrap(); + + assert_eq!(s.len(), 2); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), true); + assert_eq!(r.len(), 2); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), true); + + r.recv().unwrap(); + + assert_eq!(s.len(), 1); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let (s, r) = bounded(100); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(1500)); + assert_eq!(r.try_recv(), Ok(7)); + thread::sleep(ms(500)); + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = bounded(100); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Ok(7)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(9)); + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + s.send(8).unwrap(); + s.send(9).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = bounded::(100); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); + assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); + assert_eq!( + r.recv_timeout(ms(1000)), + Err(RecvTimeoutError::Disconnected) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.try_send(1), Ok(())); + assert_eq!(s.try_send(2), Err(TrySendError::Full(2))); + thread::sleep(ms(1500)); + assert_eq!(s.try_send(3), Ok(())); + thread::sleep(ms(500)); + assert_eq!(s.try_send(4), Err(TrySendError::Disconnected(4))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + assert_eq!(r.try_recv(), Ok(1)); + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(r.recv(), Ok(3)); + }); + }) + .unwrap(); +} + +#[test] +fn send() { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(|_| { + s.send(7).unwrap(); + thread::sleep(ms(1000)); + s.send(8).unwrap(); + thread::sleep(ms(1000)); + s.send(9).unwrap(); + thread::sleep(ms(1000)); + s.send(10).unwrap(); + }); + scope.spawn(|_| { + thread::sleep(ms(1500)); + assert_eq!(r.recv(), Ok(7)); + assert_eq!(r.recv(), Ok(8)); + assert_eq!(r.recv(), Ok(9)); + }); + }) + .unwrap(); +} + +#[test] +fn send_timeout() { + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.send_timeout(1, ms(1000)), Ok(())); + assert_eq!(s.send_timeout(2, ms(1000)), Ok(())); + assert_eq!( + s.send_timeout(3, ms(500)), + Err(SendTimeoutError::Timeout(3)) + ); + thread::sleep(ms(1000)); + assert_eq!(s.send_timeout(4, ms(1000)), Ok(())); + thread::sleep(ms(1000)); + assert_eq!(s.send(5), Err(SendError(5))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(1)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(2)); + assert_eq!(r.recv(), Ok(4)); + }); + }) + .unwrap(); +} + +#[test] +fn send_after_disconnect() { + let (s, r) = bounded(100); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(r); + + assert_eq!(s.send(4), Err(SendError(4))); + assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5))); + assert_eq!( + s.send_timeout(6, ms(500)), + Err(SendTimeoutError::Disconnected(6)) + ); +} + +#[test] +fn recv_after_disconnect() { + let (s, r) = bounded(100); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(s); + + assert_eq!(r.recv(), Ok(1)); + assert_eq!(r.recv(), Ok(2)); + assert_eq!(r.recv(), Ok(3)); + assert_eq!(r.recv(), Err(RecvError)); +} + +#[test] +fn len() { + const COUNT: usize = 25_000; + const CAP: usize = 1000; + + let (s, r) = bounded(CAP); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + for _ in 0..CAP / 10 { + for i in 0..50 { + s.send(i).unwrap(); + assert_eq!(s.len(), i + 1); + } + + for i in 0..50 { + r.recv().unwrap(); + assert_eq!(r.len(), 50 - i - 1); + } + } + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + for i in 0..CAP { + s.send(i).unwrap(); + assert_eq!(s.len(), i + 1); + } + + for _ in 0..CAP { + r.recv().unwrap(); + } + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + let len = r.len(); + assert!(len <= CAP); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + let len = s.len(); + assert!(len <= CAP); + } + }); + }) + .unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); +} + +#[test] +fn disconnect_wakes_sender() { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.send(()), Ok(())); + assert_eq!(s.send(()), Err(SendError(()))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(r); + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = bounded::<()>(1); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let (s, r) = bounded(3); + + scope(|scope| { + scope.spawn(move |_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + } + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = bounded::(3); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = r.recv().unwrap(); + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + } + }) + .unwrap(); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn stress_oneshot() { + const COUNT: usize = 10_000; + + for _ in 0..COUNT { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(|_| r.recv().unwrap()); + scope.spawn(|_| s.send(0).unwrap()); + }) + .unwrap(); + } +} + +#[test] +fn stress_iter() { + const COUNT: usize = 100_000; + + let (request_s, request_r) = bounded(1); + let (response_s, response_r) = bounded(1); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == COUNT { + return; + } + } + request_s.send(()).unwrap(); + } + }); + + for _ in request_r.iter() { + if response_s.send(1).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 100; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(()) = s.send_timeout(i, ms(10)) { + break; + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(x) = r.recv_timeout(ms(10)) { + assert_eq!(x, i); + break; + } + } + } + }); + }) + .unwrap(); +} + +#[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 (s, r) = bounded::(50); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + r.recv().unwrap(); + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + s.send(DropCounter).unwrap(); + } + }); + }) + .unwrap(); + + for _ in 0..additional { + s.send(DropCounter).unwrap(); + } + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(s); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); + } +} + +#[test] +fn linearizable() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = bounded(THREADS); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + s.send(0).unwrap(); + r.try_recv().unwrap(); + } + }); + } + }) + .unwrap(); +} + +#[test] +fn fairness() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = bounded::<()>(COUNT); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 10_000; + + let (s, r) = bounded::<()>(COUNT); + + for _ in 0..COUNT { + s.send(()).unwrap(); + } + + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn recv_in_send() { + let (s, _r) = bounded(1); + s.send(()).unwrap(); + + #[allow(unreachable_code)] + { + select! { + send(s, panic!()) -> _ => panic!(), + default => {} + } + } + + let (s, r) = bounded(2); + s.send(()).unwrap(); + + select! { + send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {} + } +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + let (s, r) = bounded::(1); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(1); + let new_r: T = Box::new(Some(new_r)); + + s.send(new_r).unwrap(); + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = r + .recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/golang.rs b/vendor/crossbeam-channel/tests/golang.rs new file mode 100644 index 0000000000..be015b28fc --- /dev/null +++ b/vendor/crossbeam-channel/tests/golang.rs @@ -0,0 +1,1448 @@ +//! Tests copied from Go and manually rewritten in Rust. +//! +//! Source: +//! - https://github.com/golang/go +//! +//! Copyright & License: +//! - Copyright (c) 2009 The Go Authors +//! - https://golang.org/AUTHORS +//! - https://golang.org/LICENSE +//! - https://golang.org/PATENTS + +#[macro_use] +extern crate crossbeam_channel; + +use std::any::Any; +use std::cell::Cell; +use std::collections::HashMap; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{bounded, tick, Receiver, Select, Sender}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +struct Chan { + inner: Arc>>, +} + +struct ChanInner { + s: Option>, + r: Receiver, +} + +impl Clone for Chan { + fn clone(&self) -> Chan { + Chan { + inner: self.inner.clone(), + } + } +} + +impl Chan { + fn send(&self, msg: T) { + let s = self + .inner + .lock() + .unwrap() + .s + .as_ref() + .expect("sending into closed channel") + .clone(); + let _ = s.send(msg); + } + + fn try_recv(&self) -> Option { + let r = self.inner.lock().unwrap().r.clone(); + r.try_recv().ok() + } + + fn recv(&self) -> Option { + let r = self.inner.lock().unwrap().r.clone(); + r.recv().ok() + } + + fn close(&self) { + self.inner + .lock() + .unwrap() + .s + .take() + .expect("channel already closed"); + } + + fn rx(&self) -> Receiver { + self.inner.lock().unwrap().r.clone() + } + + fn tx(&self) -> Sender { + match self.inner.lock().unwrap().s.as_ref() { + None => { + let (s, r) = bounded(0); + std::mem::forget(r); + s + } + Some(s) => s.clone(), + } + } +} + +impl Iterator for Chan { + type Item = T; + + fn next(&mut self) -> Option { + self.recv() + } +} + +impl<'a, T> IntoIterator for &'a Chan { + type Item = T; + type IntoIter = Chan; + + fn into_iter(self) -> Self::IntoIter { + self.clone() + } +} + +fn make(cap: usize) -> Chan { + let (s, r) = bounded(cap); + Chan { + inner: Arc::new(Mutex::new(ChanInner { s: Some(s), r })), + } +} + +#[derive(Clone)] +struct WaitGroup(Arc); + +struct WaitGroupInner { + cond: Condvar, + count: Mutex, +} + +impl WaitGroup { + fn new() -> WaitGroup { + WaitGroup(Arc::new(WaitGroupInner { + cond: Condvar::new(), + count: Mutex::new(0), + })) + } + + fn add(&self, delta: i32) { + let mut count = self.0.count.lock().unwrap(); + *count += delta; + assert!(*count >= 0); + self.0.cond.notify_all(); + } + + fn done(&self) { + self.add(-1); + } + + fn wait(&self) { + let mut count = self.0.count.lock().unwrap(); + while *count > 0 { + count = self.0.cond.wait(count).unwrap(); + } + } +} + +struct Defer { + f: Option>, +} + +impl Drop for Defer { + fn drop(&mut self) { + let f = self.f.take().unwrap(); + let mut f = Some(f); + let mut f = move || f.take().unwrap()(); + f(); + } +} + +macro_rules! defer { + ($body:expr) => { + let _defer = Defer { + f: Some(Box::new(|| $body)), + }; + }; +} + +macro_rules! go { + (@parse ref $v:ident, $($tail:tt)*) => {{ + let ref $v = $v; + go!(@parse $($tail)*) + }}; + (@parse move $v:ident, $($tail:tt)*) => {{ + let $v = $v; + go!(@parse $($tail)*) + }}; + (@parse $v:ident, $($tail:tt)*) => {{ + let $v = $v.clone(); + go!(@parse $($tail)*) + }}; + (@parse $body:expr) => { + ::std::thread::spawn(move || { + let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| { + $body + })); + if res.is_err() { + eprintln!("goroutine panicked: {:?}", res); + ::std::process::abort(); + } + }) + }; + (@parse $($tail:tt)*) => { + compile_error!("invalid `go!` syntax") + }; + ($($tail:tt)*) => {{ + go!(@parse $($tail)*) + }}; +} + +// https://github.com/golang/go/blob/master/test/chan/doubleselect.go +mod doubleselect { + use super::*; + + const ITERATIONS: i32 = 10_000; + + fn sender(n: i32, c1: Chan, c2: Chan, c3: Chan, c4: Chan) { + defer! { c1.close() } + defer! { c2.close() } + defer! { c3.close() } + defer! { c4.close() } + + for i in 0..n { + select! { + send(c1.tx(), i) -> _ => {} + send(c2.tx(), i) -> _ => {} + send(c3.tx(), i) -> _ => {} + send(c4.tx(), i) -> _ => {} + } + } + } + + fn mux(out: Chan, inp: Chan, done: Chan) { + for v in inp { + out.send(v); + } + done.send(true); + } + + fn recver(inp: Chan) { + let mut seen = HashMap::new(); + + for v in &inp { + if seen.contains_key(&v) { + panic!("got duplicate value for {}", v); + } + seen.insert(v, true); + } + } + + #[test] + fn main() { + let c1 = make::(0); + let c2 = make::(0); + let c3 = make::(0); + let c4 = make::(0); + let done = make::(0); + let cmux = make::(0); + + go!(c1, c2, c3, c4, sender(ITERATIONS, c1, c2, c3, c4)); + go!(cmux, c1, done, mux(cmux, c1, done)); + go!(cmux, c2, done, mux(cmux, c2, done)); + go!(cmux, c3, done, mux(cmux, c3, done)); + go!(cmux, c4, done, mux(cmux, c4, done)); + go!(done, cmux, { + done.recv(); + done.recv(); + done.recv(); + done.recv(); + cmux.close(); + }); + recver(cmux); + } +} + +// https://github.com/golang/go/blob/master/test/chan/fifo.go +mod fifo { + use super::*; + + const N: i32 = 10; + + #[test] + fn asynch_fifo() { + let ch = make::(N as usize); + for i in 0..N { + ch.send(i); + } + for i in 0..N { + if ch.recv() != Some(i) { + panic!("bad receive"); + } + } + } + + fn chain(ch: Chan, val: i32, inp: Chan, out: Chan) { + inp.recv(); + if ch.recv() != Some(val) { + panic!(val); + } + out.send(1); + } + + #[test] + fn synch_fifo() { + let ch = make::(0); + let mut inp = make::(0); + let start = inp.clone(); + + for i in 0..N { + let out = make::(0); + go!(ch, i, inp, out, chain(ch, i, inp, out)); + inp = out; + } + + start.send(0); + for i in 0..N { + ch.send(i); + } + inp.recv(); + } +} + +// https://github.com/golang/go/blob/master/test/chan/goroutines.go +mod goroutines { + use super::*; + + fn f(left: Chan, right: Chan) { + left.send(right.recv().unwrap()); + } + + #[test] + fn main() { + let n = 100i32; + + let leftmost = make::(0); + let mut right = leftmost.clone(); + let mut left = leftmost.clone(); + + for _ in 0..n { + right = make::(0); + go!(left, right, f(left, right)); + left = right.clone(); + } + + go!(right, right.send(1)); + leftmost.recv().unwrap(); + } +} + +// https://github.com/golang/go/blob/master/test/chan/nonblock.go +mod nonblock { + use super::*; + + fn i32receiver(c: Chan, strobe: Chan) { + if c.recv().unwrap() != 123 { + panic!("i32 value"); + } + strobe.send(true); + } + + fn i32sender(c: Chan, strobe: Chan) { + c.send(234); + strobe.send(true); + } + + fn i64receiver(c: Chan, strobe: Chan) { + if c.recv().unwrap() != 123456 { + panic!("i64 value"); + } + strobe.send(true); + } + + fn i64sender(c: Chan, strobe: Chan) { + c.send(234567); + strobe.send(true); + } + + fn breceiver(c: Chan, strobe: Chan) { + if !c.recv().unwrap() { + panic!("b value"); + } + strobe.send(true); + } + + fn bsender(c: Chan, strobe: Chan) { + c.send(true); + strobe.send(true); + } + + fn sreceiver(c: Chan, strobe: Chan) { + if c.recv().unwrap() != "hello" { + panic!("x value"); + } + strobe.send(true); + } + + fn ssender(c: Chan, strobe: Chan) { + c.send("hello again".to_string()); + strobe.send(true); + } + + const MAX_TRIES: usize = 10000; // Up to 100ms per test. + + #[test] + fn main() { + let ticker = tick(Duration::new(0, 10_000)); // 10 us + let sleep = || { + ticker.recv().unwrap(); + ticker.recv().unwrap(); + thread::yield_now(); + thread::yield_now(); + thread::yield_now(); + }; + + let sync = make::(0); + + for buffer in 0..2 { + let c32 = make::(buffer); + let c64 = make::(buffer); + let cb = make::(buffer); + let cs = make::(buffer); + + select! { + recv(c32.rx()) -> _ => panic!("blocked i32sender"), + default => {} + } + + select! { + recv(c64.rx()) -> _ => panic!("blocked i64sender"), + default => {} + } + + select! { + recv(cb.rx()) -> _ => panic!("blocked bsender"), + default => {} + } + + select! { + recv(cs.rx()) -> _ => panic!("blocked ssender"), + default => {} + } + + go!(c32, sync, i32receiver(c32, sync)); + let mut try = 0; + loop { + select! { + send(c32.tx(), 123) -> _ => break, + default => { + try += 1; + if try > MAX_TRIES { + println!("i32receiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(c32, sync, i32sender(c32, sync)); + if buffer > 0 { + sync.recv(); + } + let mut try = 0; + loop { + select! { + recv(c32.rx()) -> v => { + if v != Ok(234) { + panic!("i32sender value"); + } + break; + } + default => { + try += 1; + if try > MAX_TRIES { + println!("i32sender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + + go!(c64, sync, i64receiver(c64, sync)); + let mut try = 0; + loop { + select! { + send(c64.tx(), 123456) -> _ => break, + default => { + try += 1; + if try > MAX_TRIES { + println!("i64receiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(c64, sync, i64sender(c64, sync)); + if buffer > 0 { + sync.recv(); + } + let mut try = 0; + loop { + select! { + recv(c64.rx()) -> v => { + if v != Ok(234567) { + panic!("i64sender value"); + } + break; + } + default => { + try += 1; + if try > MAX_TRIES { + println!("i64sender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + + go!(cb, sync, breceiver(cb, sync)); + let mut try = 0; + loop { + select! { + send(cb.tx(), true) -> _ => break, + default => { + try += 1; + if try > MAX_TRIES { + println!("breceiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(cb, sync, bsender(cb, sync)); + if buffer > 0 { + sync.recv(); + } + let mut try = 0; + loop { + select! { + recv(cb.rx()) -> v => { + if v != Ok(true) { + panic!("bsender value"); + } + break; + } + default => { + try += 1; + if try > MAX_TRIES { + println!("bsender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + + go!(cs, sync, sreceiver(cs, sync)); + let mut try = 0; + loop { + select! { + send(cs.tx(), "hello".to_string()) -> _ => break, + default => { + try += 1; + if try > MAX_TRIES { + println!("sreceiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(cs, sync, ssender(cs, sync)); + if buffer > 0 { + sync.recv(); + } + let mut try = 0; + loop { + select! { + recv(cs.rx()) -> v => { + if v != Ok("hello again".to_string()) { + panic!("ssender value"); + } + break; + } + default => { + try += 1; + if try > MAX_TRIES { + println!("ssender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + } + } +} + +// https://github.com/golang/go/blob/master/test/chan/select.go +mod select { + use super::*; + + #[test] + fn main() { + let shift = Cell::new(0); + let counter = Cell::new(0); + + let get_value = || { + counter.set(counter.get() + 1); + 1 << shift.get() + }; + + let send = |mut a: Option<&Chan>, mut b: Option<&Chan>| { + let mut i = 0; + let never = make::(0); + loop { + let nil1 = never.tx(); + let nil2 = never.tx(); + let v1 = get_value(); + let v2 = get_value(); + select! { + send(a.map(|c| c.tx()).unwrap_or(nil1), v1) -> _ => { + i += 1; + a = None; + } + send(b.map(|c| c.tx()).unwrap_or(nil2), v2) -> _ => { + i += 1; + b = None; + } + default => break, + } + shift.set(shift.get() + 1); + } + i + }; + + let a = make::(1); + let b = make::(1); + + assert_eq!(send(Some(&a), Some(&b)), 2); + + let av = a.recv().unwrap(); + let bv = b.recv().unwrap(); + assert_eq!(av | bv, 3); + + assert_eq!(send(Some(&a), None), 1); + assert_eq!(counter.get(), 10); + } +} + +// https://github.com/golang/go/blob/master/test/chan/select2.go +mod select2 { + // TODO +} + +// https://github.com/golang/go/blob/master/test/chan/select3.go +mod select3 { + // TODO +} + +// https://github.com/golang/go/blob/master/test/chan/select4.go +mod select4 { + use super::*; + + #[test] + fn main() { + let c = make::(1); + let c1 = make::(0); + c.send(42); + select! { + recv(c1.rx()) -> _ => panic!("BUG"), + recv(c.rx()) -> v => assert_eq!(v, Ok(42)), + } + } +} + +// https://github.com/golang/go/blob/master/test/chan/select6.go +mod select6 { + use super::*; + + #[test] + fn main() { + let c1 = make::(0); + let c2 = make::(0); + let c3 = make::(0); + + go!(c1, c1.recv()); + go!(c1, c2, c3, { + select! { + recv(c1.rx()) -> _ => panic!("dummy"), + recv(c2.rx()) -> _ => c3.send(true), + } + c1.recv(); + }); + go!(c2, c2.send(true)); + + c3.recv(); + c1.send(true); + c1.send(true); + } +} + +// https://github.com/golang/go/blob/master/test/chan/select7.go +mod select7 { + use super::*; + + fn recv1(c: Chan) { + c.recv().unwrap(); + } + + fn recv2(c: Chan) { + select! { + recv(c.rx()) -> _ => () + } + } + + fn recv3(c: Chan) { + let c2 = make::(1); + select! { + recv(c.rx()) -> _ => (), + recv(c2.rx()) -> _ => () + } + } + + fn send1(recv: fn(Chan)) { + let c = make::(1); + go!(c, recv(c)); + thread::yield_now(); + c.send(1); + } + + fn send2(recv: fn(Chan)) { + let c = make::(1); + go!(c, recv(c)); + thread::yield_now(); + select! { + send(c.tx(), 1) -> _ => () + } + } + + fn send3(recv: fn(Chan)) { + let c = make::(1); + go!(c, recv(c)); + thread::yield_now(); + let c2 = make::(1); + select! { + send(c.tx(), 1) -> _ => (), + send(c2.tx(), 1) -> _ => () + } + } + + #[test] + fn main() { + send1(recv1); + send2(recv1); + send3(recv1); + send1(recv2); + send2(recv2); + send3(recv2); + send1(recv3); + send2(recv3); + send3(recv3); + } +} + +// https://github.com/golang/go/blob/master/test/chan/sieve1.go +mod sieve1 { + use super::*; + + fn generate(ch: Chan) { + let mut i = 2; + loop { + ch.send(i); + i += 1; + } + } + + fn filter(in_ch: Chan, out_ch: Chan, prime: i32) { + for i in in_ch { + if i % prime != 0 { + out_ch.send(i); + } + } + } + + fn sieve(primes: Chan) { + let mut ch = make::(1); + go!(ch, generate(ch)); + loop { + let prime = ch.recv().unwrap(); + primes.send(prime); + + let ch1 = make::(1); + go!(ch, ch1, prime, filter(ch, ch1, prime)); + ch = ch1; + } + } + + #[test] + fn main() { + let primes = make::(1); + go!(primes, sieve(primes)); + + let a = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, + ]; + for item in a.iter() { + let x = primes.recv().unwrap(); + if x != *item { + println!("{} != {}", x, item); + panic!("fail"); + } + } + } +} + +// https://github.com/golang/go/blob/master/test/chan/zerosize.go +mod zerosize { + use super::*; + + #[test] + fn zero_size_struct() { + struct ZeroSize; + let _ = make::(0); + } + + #[test] + fn zero_size_array() { + let _ = make::<[u8; 0]>(0); + } +} + +// https://github.com/golang/go/blob/master/src/runtime/chan_test.go +mod chan_test { + use super::*; + + #[test] + fn test_chan() { + const N: i32 = 200; + + for cap in 0..N { + { + // Ensure that receive from empty chan blocks. + let c = make::(cap as usize); + + let recv1 = Arc::new(Mutex::new(false)); + go!(c, recv1, { + c.recv(); + *recv1.lock().unwrap() = true; + }); + + let recv2 = Arc::new(Mutex::new(false)); + go!(c, recv2, { + c.recv(); + *recv2.lock().unwrap() = true; + }); + + thread::sleep(ms(1)); + + if *recv1.lock().unwrap() || *recv2.lock().unwrap() { + panic!(); + } + + // Ensure that non-blocking receive does not block. + select! { + recv(c.rx()) -> _ => panic!(), + default => {} + } + select! { + recv(c.rx()) -> _ => panic!(), + default => {} + } + + c.send(0); + c.send(0); + } + + { + // Ensure that send to full chan blocks. + let c = make::(cap as usize); + for i in 0..cap { + c.send(i); + } + + let sent = Arc::new(Mutex::new(0)); + go!(sent, c, { + c.send(0); + *sent.lock().unwrap() = 1; + }); + + thread::sleep(ms(1)); + + if *sent.lock().unwrap() != 0 { + panic!(); + } + + // Ensure that non-blocking send does not block. + select! { + send(c.tx(), 0) -> _ => panic!(), + default => {} + } + c.recv(); + } + + { + // Ensure that we receive 0 from closed chan. + let c = make::(cap as usize); + for i in 0..cap { + c.send(i); + } + c.close(); + + for i in 0..cap { + let v = c.recv(); + if v != Some(i) { + panic!(); + } + } + + if c.recv() != None { + panic!(); + } + if c.try_recv() != None { + panic!(); + } + } + + { + // Ensure that close unblocks receive. + let c = make::(cap as usize); + let done = make::(0); + + go!(c, done, { + let v = c.try_recv(); + done.send(v.is_some()); + }); + + thread::sleep(ms(1)); + c.close(); + + if !done.recv().unwrap() { + // panic!(); + } + } + + { + // Send 100 integers, + // ensure that we receive them non-corrupted in FIFO order. + let c = make::(cap as usize); + go!(c, { + for i in 0..100 { + c.send(i); + } + }); + for i in 0..100 { + if c.recv() != Some(i) { + panic!(); + } + } + + // Same, but using recv2. + go!(c, { + for i in 0..100 { + c.send(i); + } + }); + for i in 0..100 { + if c.recv() != Some(i) { + panic!(); + } + } + } + } + } + + #[test] + fn test_nonblock_recv_race() { + const N: usize = 1000; + + for _ in 0..N { + let c = make::(1); + c.send(1); + + let t = go!(c, { + select! { + recv(c.rx()) -> _ => {} + default => panic!("chan is not ready"), + } + }); + + c.close(); + c.recv(); + t.join().unwrap(); + } + } + + #[test] + fn test_nonblock_select_race() { + const N: usize = 1000; + + let done = make::(1); + for _ in 0..N { + let c1 = make::(1); + let c2 = make::(1); + c1.send(1); + + go!(c1, c2, done, { + select! { + recv(c1.rx()) -> _ => {} + recv(c2.rx()) -> _ => {} + default => { + done.send(false); + return; + } + } + done.send(true); + }); + + c2.send(1); + select! { + recv(c1.rx()) -> _ => {} + default => {} + } + if !done.recv().unwrap() { + panic!("no chan is ready"); + } + } + } + + #[test] + fn test_nonblock_select_race2() { + const N: usize = 1000; + + let done = make::(1); + for _ in 0..N { + let c1 = make::(1); + let c2 = make::(0); + c1.send(1); + + go!(c1, c2, done, { + select! { + recv(c1.rx()) -> _ => {} + recv(c2.rx()) -> _ => {} + default => { + done.send(false); + return; + } + } + done.send(true); + }); + + c2.close(); + select! { + recv(c1.rx()) -> _ => {} + default => {} + } + if !done.recv().unwrap() { + panic!("no chan is ready"); + } + } + } + + #[test] + fn test_self_select() { + // Ensure that send/recv on the same chan in select + // does not crash nor deadlock. + + for &cap in &[0, 10] { + let wg = WaitGroup::new(); + wg.add(2); + let c = make::(cap); + + for p in 0..2 { + let p = p; + go!(wg, p, c, { + defer! { wg.done() } + for i in 0..1000 { + if p == 0 || i % 2 == 0 { + select! { + send(c.tx(), p) -> _ => {} + recv(c.rx()) -> v => { + if cap == 0 && v.ok() == Some(p) { + panic!("self receive"); + } + } + } + } else { + select! { + recv(c.rx()) -> v => { + if cap == 0 && v.ok() == Some(p) { + panic!("self receive"); + } + } + send(c.tx(), p) -> _ => {} + } + } + } + }); + } + wg.wait(); + } + } + + #[test] + fn test_select_stress() { + let c = vec![ + make::(0), + make::(0), + make::(2), + make::(3), + ]; + + const N: usize = 10000; + + // There are 4 goroutines that send N values on each of the chans, + // + 4 goroutines that receive N values on each of the chans, + // + 1 goroutine that sends N values on each of the chans in a single select, + // + 1 goroutine that receives N values on each of the chans in a single select. + // All these sends, receives and selects interact chaotically at runtime, + // but we are careful that this whole construct does not deadlock. + let wg = WaitGroup::new(); + wg.add(10); + + for k in 0..4 { + go!(k, c, wg, { + for _ in 0..N { + c[k].send(0); + } + wg.done(); + }); + go!(k, c, wg, { + for _ in 0..N { + c[k].recv(); + } + wg.done(); + }); + } + + go!(c, wg, { + let mut n = [0; 4]; + let mut c1 = c.iter().map(|c| Some(c.rx().clone())).collect::>(); + + for _ in 0..4 * N { + let index = { + let mut sel = Select::new(); + let mut opers = [!0; 4]; + for &i in &[3, 2, 0, 1] { + if let Some(c) = &c1[i] { + opers[i] = sel.recv(c); + } + } + + let oper = sel.select(); + let mut index = !0; + for i in 0..4 { + if opers[i] == oper.index() { + index = i; + let _ = oper.recv(c1[i].as_ref().unwrap()); + break; + } + } + index + }; + + n[index] += 1; + if n[index] == N { + c1[index] = None; + } + } + wg.done(); + }); + + go!(c, wg, { + let mut n = [0; 4]; + let mut c1 = c.iter().map(|c| Some(c.tx().clone())).collect::>(); + + for _ in 0..4 * N { + let index = { + let mut sel = Select::new(); + let mut opers = [!0; 4]; + for &i in &[0, 1, 2, 3] { + if let Some(c) = &c1[i] { + opers[i] = sel.send(c); + } + } + + let oper = sel.select(); + let mut index = !0; + for i in 0..4 { + if opers[i] == oper.index() { + index = i; + let _ = oper.send(c1[i].as_ref().unwrap(), 0); + break; + } + } + index + }; + + n[index] += 1; + if n[index] == N { + c1[index] = None; + } + } + wg.done(); + }); + + wg.wait(); + } + + #[test] + fn test_select_fairness() { + const TRIALS: usize = 10000; + + let c1 = make::(TRIALS + 1); + let c2 = make::(TRIALS + 1); + + for _ in 0..TRIALS + 1 { + c1.send(1); + c2.send(2); + } + + let c3 = make::(0); + let c4 = make::(0); + let out = make::(0); + let done = make::(0); + let wg = WaitGroup::new(); + + wg.add(1); + go!(wg, c1, c2, c3, c4, out, done, { + defer! { wg.done() }; + loop { + let b; + select! { + recv(c3.rx()) -> m => b = m.unwrap(), + recv(c4.rx()) -> m => b = m.unwrap(), + recv(c1.rx()) -> m => b = m.unwrap(), + recv(c2.rx()) -> m => b = m.unwrap(), + } + select! { + send(out.tx(), b) -> _ => {} + recv(done.rx()) -> _ => return, + } + } + }); + + let (mut cnt1, mut cnt2) = (0, 0); + for _ in 0..TRIALS { + match out.recv() { + Some(1) => cnt1 += 1, + Some(2) => cnt2 += 1, + b => panic!("unexpected value {:?} on channel", b), + } + } + + // If the select in the goroutine is fair, + // cnt1 and cnt2 should be about the same value. + // With 10,000 trials, the expected margin of error at + // a confidence level of five nines is 4.4172 / (2 * Sqrt(10000)). + + let r = cnt1 as f64 / TRIALS as f64; + let e = (r - 0.5).abs(); + + if e > 4.4172 / (2.0 * (TRIALS as f64).sqrt()) { + panic!( + "unfair select: in {} trials, results were {}, {}", + TRIALS, cnt1, cnt2, + ); + } + + done.close(); + wg.wait(); + } + + #[test] + fn test_chan_send_interface() { + struct Mt; + + let c = make::>(1); + c.send(Box::new(Mt)); + + select! { + send(c.tx(), Box::new(Mt)) -> _ => {} + default => {} + } + + select! { + send(c.tx(), Box::new(Mt)) -> _ => {} + send(c.tx(), Box::new(Mt)) -> _ => {} + default => {} + } + } + + #[test] + fn test_pseudo_random_send() { + const N: usize = 100; + + for cap in 0..N { + let c = make::(cap); + let l = Arc::new(Mutex::new(vec![0i32; N])); + let done = make::(0); + + go!(c, done, l, { + let mut l = l.lock().unwrap(); + for i in 0..N { + thread::yield_now(); + l[i] = c.recv().unwrap(); + } + done.send(true); + }); + + for _ in 0..N { + select! { + send(c.tx(), 1) -> _ => {} + send(c.tx(), 0) -> _ => {} + } + } + done.recv(); + + let mut n0 = 0; + let mut n1 = 0; + for &i in l.lock().unwrap().iter() { + n0 += (i + 1) % 2; + n1 += i; + } + + if n0 <= N as i32 / 10 || n1 <= N as i32 / 10 { + panic!( + "Want pseudorandom, got {} zeros and {} ones (chan cap {})", + n0, n1, cap, + ); + } + } + } + + #[test] + fn test_multi_consumer() { + const NWORK: usize = 23; + const NITER: usize = 271828; + + let pn = [2, 3, 7, 11, 13, 17, 19, 23, 27, 31]; + + let q = make::(NWORK * 3); + let r = make::(NWORK * 3); + + let wg = WaitGroup::new(); + for i in 0..NWORK { + wg.add(1); + let w = i; + go!(q, r, wg, pn, { + for v in &q { + if pn[w % pn.len()] == v { + thread::yield_now(); + } + r.send(v); + } + wg.done(); + }); + } + + let expect = Arc::new(Mutex::new(0)); + go!(q, r, expect, wg, pn, { + for i in 0..NITER { + let v = pn[i % pn.len()]; + *expect.lock().unwrap() += v; + q.send(v); + } + q.close(); + wg.wait(); + r.close(); + }); + + let mut n = 0; + let mut s = 0; + for v in &r { + n += 1; + s += v; + } + + if n != NITER || s != *expect.lock().unwrap() { + panic!(); + } + } + + #[test] + fn test_select_duplicate_channel() { + // This test makes sure we can queue a G on + // the same channel multiple times. + let c = make::(0); + let d = make::(0); + let e = make::(0); + + go!(c, d, e, { + select! { + recv(c.rx()) -> _ => {} + recv(d.rx()) -> _ => {} + recv(e.rx()) -> _ => {} + } + e.send(9); + }); + thread::sleep(ms(1)); + + go!(c, c.recv()); + thread::sleep(ms(1)); + + d.send(7); + e.recv(); + c.send(8); + } +} + +// https://github.com/golang/go/blob/master/test/closedchan.go +mod closedchan { + // TODO +} + +// https://github.com/golang/go/blob/master/src/runtime/chanbarrier_test.go +mod chanbarrier_test { + // TODO +} + +// https://github.com/golang/go/blob/master/src/runtime/race/testdata/chan_test.go +mod race_chan_test { + // TODO +} + +// https://github.com/golang/go/blob/master/test/ken/chan.go +mod chan { + // TODO +} + +// https://github.com/golang/go/blob/master/test/ken/chan1.go +mod chan1 { + // TODO +} diff --git a/vendor/crossbeam-channel/tests/iter.rs b/vendor/crossbeam-channel/tests/iter.rs new file mode 100644 index 0000000000..6acec59c28 --- /dev/null +++ b/vendor/crossbeam-channel/tests/iter.rs @@ -0,0 +1,113 @@ +//! Tests for iteration over receivers. + +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use crossbeam_channel::unbounded; +use crossbeam_utils::thread::scope; + +#[test] +fn nested_recv_iter() { + let (s, r) = unbounded::(); + let (total_s, total_r) = unbounded::(); + + scope(|scope| { + scope.spawn(move |_| { + let mut acc = 0; + for x in r.iter() { + acc += x; + } + total_s.send(acc).unwrap(); + }); + + s.send(3).unwrap(); + s.send(1).unwrap(); + s.send(2).unwrap(); + drop(s); + assert_eq!(total_r.recv().unwrap(), 6); + }) + .unwrap(); +} + +#[test] +fn recv_iter_break() { + let (s, r) = unbounded::(); + let (count_s, count_r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + for x in r.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_s.send(count).unwrap(); + }); + + s.send(2).unwrap(); + s.send(2).unwrap(); + s.send(2).unwrap(); + let _ = s.send(2); + drop(s); + assert_eq!(count_r.recv().unwrap(), 4); + }) + .unwrap(); +} + +#[test] +fn recv_try_iter() { + let (request_s, request_r) = unbounded(); + let (response_s, response_r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == 6 { + return; + } + } + request_s.send(()).unwrap(); + } + }); + + for _ in request_r.iter() { + if response_s.send(2).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn recv_into_iter_owned() { + let mut iter = { + let (s, r) = unbounded::(); + s.send(1).unwrap(); + s.send(2).unwrap(); + r.into_iter() + }; + + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn recv_into_iter_borrowed() { + let (s, r) = unbounded::(); + s.send(1).unwrap(); + s.send(2).unwrap(); + drop(s); + + let mut iter = (&r).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} diff --git a/vendor/crossbeam-channel/tests/list.rs b/vendor/crossbeam-channel/tests/list.rs new file mode 100644 index 0000000000..ed1d4c4209 --- /dev/null +++ b/vendor/crossbeam-channel/tests/list.rs @@ -0,0 +1,538 @@ +//! Tests for the list channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{unbounded, Receiver}; +use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; +use crossbeam_channel::{SendError, SendTimeoutError, TrySendError}; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + let (s, r) = unbounded(); + s.try_send(7).unwrap(); + assert_eq!(r.try_recv(), Ok(7)); + + s.send(8).unwrap(); + assert_eq!(r.recv(), Ok(8)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); +} + +#[test] +fn capacity() { + let (s, r) = unbounded::<()>(); + assert_eq!(s.capacity(), None); + assert_eq!(r.capacity(), None); +} + +#[test] +fn len_empty_full() { + let (s, r) = unbounded(); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + s.send(()).unwrap(); + + assert_eq!(s.len(), 1); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), false); + + r.recv().unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(1500)); + assert_eq!(r.try_recv(), Ok(7)); + thread::sleep(ms(500)); + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Ok(7)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(9)); + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + s.send(8).unwrap(); + s.send(9).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = unbounded::(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); + assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); + assert_eq!( + r.recv_timeout(ms(1000)), + Err(RecvTimeoutError::Disconnected) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = unbounded(); + for i in 0..1000 { + assert_eq!(s.try_send(i), Ok(())); + } + + drop(r); + assert_eq!(s.try_send(777), Err(TrySendError::Disconnected(777))); +} + +#[test] +fn send() { + let (s, r) = unbounded(); + for i in 0..1000 { + assert_eq!(s.send(i), Ok(())); + } + + drop(r); + assert_eq!(s.send(777), Err(SendError(777))); +} + +#[test] +fn send_timeout() { + let (s, r) = unbounded(); + for i in 0..1000 { + assert_eq!(s.send_timeout(i, ms(i as u64)), Ok(())); + } + + drop(r); + assert_eq!( + s.send_timeout(777, ms(0)), + Err(SendTimeoutError::Disconnected(777)) + ); +} + +#[test] +fn send_after_disconnect() { + let (s, r) = unbounded(); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(r); + + assert_eq!(s.send(4), Err(SendError(4))); + assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5))); + assert_eq!( + s.send_timeout(6, ms(0)), + Err(SendTimeoutError::Disconnected(6)) + ); +} + +#[test] +fn recv_after_disconnect() { + let (s, r) = unbounded(); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(s); + + assert_eq!(r.recv(), Ok(1)); + assert_eq!(r.recv(), Ok(2)); + assert_eq!(r.recv(), Ok(3)); + assert_eq!(r.recv(), Err(RecvError)); +} + +#[test] +fn len() { + let (s, r) = unbounded(); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + for i in 0..50 { + s.send(i).unwrap(); + assert_eq!(s.len(), i + 1); + } + + for i in 0..50 { + r.recv().unwrap(); + assert_eq!(r.len(), 50 - i - 1); + } + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + } + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = unbounded::(); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = r.recv().unwrap(); + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn stress_oneshot() { + const COUNT: usize = 10_000; + + for _ in 0..COUNT { + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(|_| r.recv().unwrap()); + scope.spawn(|_| s.send(0).unwrap()); + }) + .unwrap(); + } +} + +#[test] +fn stress_iter() { + const COUNT: usize = 100_000; + + let (request_s, request_r) = unbounded(); + let (response_s, response_r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == COUNT { + return; + } + } + request_s.send(()).unwrap(); + } + }); + + for _ in request_r.iter() { + if response_s.send(1).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 100; + + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + s.send(i).unwrap(); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(x) = r.recv_timeout(ms(10)) { + assert_eq!(x, i); + break; + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn drops() { + 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..100 { + let steps = rng.gen_range(0, 10_000); + let additional = rng.gen_range(0, 1000); + + DROPS.store(0, Ordering::SeqCst); + let (s, r) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + r.recv().unwrap(); + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + s.send(DropCounter).unwrap(); + } + }); + }) + .unwrap(); + + for _ in 0..additional { + s.try_send(DropCounter).unwrap(); + } + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(s); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); + } +} + +#[test] +fn linearizable() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = unbounded(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + s.send(0).unwrap(); + r.try_recv().unwrap(); + } + }); + } + }) + .unwrap(); +} + +#[test] +fn fairness() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 10_000; + + let (s, r) = unbounded(); + + for _ in 0..COUNT { + s.send(()).unwrap(); + } + + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn recv_in_send() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + select! { + send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {} + } +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + let (s, r) = unbounded::(); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = unbounded(); + let new_r: T = Box::new(Some(new_r)); + + s.send(new_r).unwrap(); + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = r + .recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/mpsc.rs b/vendor/crossbeam-channel/tests/mpsc.rs new file mode 100644 index 0000000000..213b9d8b7d --- /dev/null +++ b/vendor/crossbeam-channel/tests/mpsc.rs @@ -0,0 +1,2095 @@ +//! Tests copied from `std::sync::mpsc`. +//! +//! This is a copy of tests for the `std::sync::mpsc` channels from the standard library, but +//! modified to work with `crossbeam-channel` instead. +//! +//! Minor tweaks were needed to make the tests compile: +//! +//! - Replace `box` syntax with `Box::new`. +//! - Replace all uses of `Select` with `select!`. +//! - Change the imports. +//! - Join all spawned threads. +//! - Removed assertion from oneshot_multi_thread_send_close_stress tests. +//! +//! Source: +//! - https://github.com/rust-lang/rust/tree/master/src/libstd/sync/mpsc +//! +//! Copyright & License: +//! - Copyright 2013-2014 The Rust Project Developers +//! - Apache License, Version 2.0 or MIT license, at your option +//! - https://github.com/rust-lang/rust/blob/master/COPYRIGHT +//! - https://www.rust-lang.org/en-US/legal.html + +#[macro_use] +extern crate crossbeam_channel as cc; + +use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError}; +use std::sync::mpsc::{SendError, TrySendError}; +use std::thread::JoinHandle; +use std::time::Duration; + +pub struct Sender { + pub inner: cc::Sender, +} + +impl Sender { + pub fn send(&self, t: T) -> Result<(), SendError> { + self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) + } +} + +impl Clone for Sender { + fn clone(&self) -> Sender { + Sender { + inner: self.inner.clone(), + } + } +} + +pub struct SyncSender { + pub inner: cc::Sender, +} + +impl SyncSender { + pub fn send(&self, t: T) -> Result<(), SendError> { + self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) + } + + pub fn try_send(&self, t: T) -> Result<(), TrySendError> { + self.inner.try_send(t).map_err(|err| match err { + cc::TrySendError::Full(m) => TrySendError::Full(m), + cc::TrySendError::Disconnected(m) => TrySendError::Disconnected(m), + }) + } +} + +impl Clone for SyncSender { + fn clone(&self) -> SyncSender { + SyncSender { + inner: self.inner.clone(), + } + } +} + +pub struct Receiver { + pub inner: cc::Receiver, +} + +impl Receiver { + pub fn try_recv(&self) -> Result { + self.inner.try_recv().map_err(|err| match err { + cc::TryRecvError::Empty => TryRecvError::Empty, + cc::TryRecvError::Disconnected => TryRecvError::Disconnected, + }) + } + + pub fn recv(&self) -> Result { + self.inner.recv().map_err(|_| RecvError) + } + + pub fn recv_timeout(&self, timeout: Duration) -> Result { + self.inner.recv_timeout(timeout).map_err(|err| match err { + cc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout, + cc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + }) + } + + pub fn iter(&self) -> Iter { + Iter { inner: self } + } + + pub fn try_iter(&self) -> TryIter { + TryIter { inner: self } + } +} + +impl<'a, T> IntoIterator for &'a Receiver { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl IntoIterator for Receiver { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { inner: self } + } +} + +pub struct TryIter<'a, T: 'a> { + inner: &'a Receiver, +} + +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.try_recv().ok() + } +} + +pub struct Iter<'a, T: 'a> { + inner: &'a Receiver, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.recv().ok() + } +} + +pub struct IntoIter { + inner: Receiver, +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.recv().ok() + } +} + +pub fn channel() -> (Sender, Receiver) { + let (s, r) = cc::unbounded(); + let s = Sender { inner: s }; + let r = Receiver { inner: r }; + (s, r) +} + +pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { + let (s, r) = cc::bounded(bound); + let s = SyncSender { inner: s }; + let r = Receiver { inner: r }; + (s, r) +} + +macro_rules! select { + ( + $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ + ) => ({ + crossbeam_channel_internal! { + $( + recv(($rx).inner) -> res => { + let $name = res.map_err(|_| ::std::sync::mpsc::RecvError); + $code + } + )+ + } + }) +} + +// Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/mod.rs +mod channel_tests { + use super::*; + + use std::env; + use std::thread; + use std::time::{Duration, Instant}; + + pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } + } + + #[test] + fn smoke() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn drop_full() { + let (tx, _rx) = channel::>(); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn drop_full_shared() { + let (tx, _rx) = channel::>(); + drop(tx.clone()); + drop(tx.clone()); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn smoke_shared() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn smoke_threads() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); + t.join().unwrap(); + } + + #[test] + fn smoke_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()); + } + + #[test] + fn smoke_shared_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()) + } + + #[test] + fn smoke_shared_port_gone2() { + let (tx, rx) = channel::(); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); + } + + #[test] + fn port_gone_concurrent() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn port_gone_concurrent_shared() { + let (tx, rx) = channel::(); + let tx2 = tx.clone(); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn smoke_chan_gone() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn smoke_chan_gone_shared() { + let (tx, rx) = channel::<()>(); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); + } + + #[test] + fn chan_gone_concurrent() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} + t.join().unwrap(); + } + + #[test] + fn stress() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().ok().unwrap(); + } + + #[test] + fn stress_shared() { + const AMT: u32 = 10000; + const NTHREADS: u32 = 8; + let (tx, rx) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + }); + + 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 { + tx.send(1).unwrap(); + } + }); + ts.push(t); + } + drop(tx); + t.join().ok().unwrap(); + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn send_from_outside_runtime() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + tx1.send(()).unwrap(); + for _ in 0..40 { + assert_eq!(rx2.recv().unwrap(), 1); + } + }); + rx1.recv().unwrap(); + let t2 = thread::spawn(move || { + for _ in 0..40 { + tx2.send(1).unwrap(); + } + }); + t1.join().ok().unwrap(); + t2.join().ok().unwrap(); + } + + #[test] + fn recv_from_outside_runtime() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..40 { + assert_eq!(rx.recv().unwrap(), 1); + } + }); + for _ in 0..40 { + tx.send(1).unwrap(); + } + t.join().ok().unwrap(); + } + + #[test] + fn no_runtime() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + assert_eq!(rx1.recv().unwrap(), 1); + tx2.send(2).unwrap(); + }); + let t2 = thread::spawn(move || { + tx1.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 2); + }); + t1.join().ok().unwrap(); + t2.join().ok().unwrap(); + } + + #[test] + fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = channel::(); + drop(rx); + } + + #[test] + fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = channel::(); + drop(tx); + } + + #[test] + fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = channel::>(); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); + } + + #[test] + fn oneshot_single_thread_recv_chan_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.recv(), Err(RecvError)); + } + + #[test] + fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = channel::>(); + tx.send(Box::new(10)).unwrap(); + assert!(*rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_open() { + let (tx, rx) = channel::(); + assert!(tx.send(10).is_ok()); + assert!(rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(10).is_err()); + } + + #[test] + fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = channel::(); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } + + #[test] + fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn oneshot_single_thread_peek_data() { + let (tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); + } + + #[test] + fn oneshot_single_thread_peek_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } + + #[test] + fn oneshot_single_thread_peek_open() { + let (_tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } + + #[test] + fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = channel::>(); + let t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(Box::new(10)).unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = channel::>(); + let t = thread::spawn(move || { + drop(tx); + }); + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_thread_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + drop(tx); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + thread::spawn(move || { + let _ = tx.send(1); + }) + .join() + .unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_recv_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + }); + ts.push(t); + let t2 = thread::spawn(move || { + let t = thread::spawn(move || { + drop(tx); + }); + t.join().unwrap(); + }); + ts.push(t2); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::>(); + let t = thread::spawn(move || { + tx.send(Box::new(10)).unwrap(); + }); + ts.push(t); + assert!(*rx.recv().unwrap() == 10); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn stream_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel(); + + if let Some(t) = send(tx, 0) { + ts.push(t); + } + if let Some(t2) = recv(rx, 0) { + ts.push(t2); + } + + fn send(tx: Sender>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + })) + } + + fn recv(rx: Receiver>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + })) + } + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_single_thread_recv_timeout() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + assert_eq!( + rx.recv_timeout(Duration::from_millis(1)), + Err(RecvTimeoutError::Timeout) + ); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + } + + #[test] + fn stress_recv_timeout_two_threads() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + let timeout = Duration::from_millis(100); + + let t = thread::spawn(move || { + for i in 0..stress { + if i % 2 == 0 { + thread::sleep(timeout * 2); + } + tx.send(1usize).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(timeout) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); + t.join().unwrap() + } + + #[test] + fn recv_timeout_upgrade() { + let (tx, rx) = channel::<()>(); + let timeout = Duration::from_millis(1); + let _tx_clone = tx.clone(); + + let start = Instant::now(); + assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); + assert!(Instant::now() >= start + timeout); + } + + #[test] + fn stress_recv_timeout_shared() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + + let mut ts = Vec::with_capacity(stress); + for i in 0..stress { + let tx = tx.clone(); + let t = thread::spawn(move || { + thread::sleep(Duration::from_millis(i as u64 * 10)); + tx.send(1usize).unwrap(); + }); + ts.push(t); + } + + drop(tx); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = channel(); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } + } + + #[test] + fn shared_recv_timeout() { + let (tx, rx) = channel(); + let total = 5; + let mut ts = Vec::with_capacity(total); + for _ in 0..total { + let tx = tx.clone(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + }); + ts.push(t); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + + assert_eq!( + rx.recv_timeout(Duration::from_millis(1)), + Err(RecvTimeoutError::Timeout) + ); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn shared_chan_stress() { + let (tx, rx) = channel(); + let total = stress_factor() + 100; + let mut ts = Vec::with_capacity(total); + for _ in 0..total { + let tx = tx.clone(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + }); + ts.push(t); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn test_nested_recv_iter() { + let (tx, rx) = channel::(); + let (total_tx, total_rx) = channel::(); + + let t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); + t.join().unwrap(); + } + + #[test] + fn test_recv_iter_break() { + let (tx, rx) = channel::(); + let (count_tx, count_rx) = channel(); + + let t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); + t.join().unwrap(); + } + + #[test] + fn test_recv_try_iter() { + let (request_tx, request_rx) = channel(); + let (response_tx, response_rx) = channel(); + + // Request `x`s until we have `6`. + let t = thread::spawn(move || { + let mut count = 0; + loop { + for x in response_rx.try_iter() { + count += x; + if count == 6 { + return count; + } + } + request_tx.send(()).unwrap(); + } + }); + + for _ in request_rx.iter() { + if response_tx.send(2).is_err() { + break; + } + } + + assert_eq!(t.join().unwrap(), 6); + } + + #[test] + fn test_recv_into_iter_owned() { + let mut iter = { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + rx.into_iter() + }; + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); + } + + #[test] + fn test_recv_into_iter_borrowed() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + let mut iter = (&rx).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); + } + + #[test] + fn try_recv_states() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); + t.join().unwrap(); + } + + // This bug used to end up in a livelock inside of the Receiver destructor + // because the internal state of the Shared packet was corrupted + #[test] + fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = channel(); + let (tx2, rx2) = channel(); + let t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let tx2 = tx.clone(); + drop(tx); + tx2.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn issue_32114() { + let (tx, _) = channel(); + let _ = tx.send(123); + assert_eq!(tx.send(123), Err(SendError(123))); + } +} + +// Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/mod.rs +mod sync_channel_tests { + use super::*; + + use std::env; + use std::thread; + use std::time::Duration; + + pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } + } + + #[test] + fn smoke() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn drop_full() { + let (tx, _rx) = sync_channel::>(1); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn smoke_shared() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn recv_timeout() { + let (tx, rx) = sync_channel::(1); + assert_eq!( + rx.recv_timeout(Duration::from_millis(1)), + Err(RecvTimeoutError::Timeout) + ); + tx.send(1).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); + } + + #[test] + fn smoke_threads() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); + t.join().unwrap(); + } + + #[test] + fn smoke_port_gone() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert!(tx.send(1).is_err()); + } + + #[test] + fn smoke_shared_port_gone2() { + let (tx, rx) = sync_channel::(0); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); + } + + #[test] + fn port_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn port_gone_concurrent_shared() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn smoke_chan_gone() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn smoke_chan_gone_shared() { + let (tx, rx) = sync_channel::<()>(0); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); + } + + #[test] + fn chan_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} + t.join().unwrap(); + } + + #[test] + fn stress() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().unwrap(); + } + + #[test] + fn stress_recv_timeout_two_threads() { + let (tx, rx) = sync_channel::(0); + + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(1)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, 10000); + t.join().unwrap(); + } + + #[test] + fn stress_recv_timeout_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + let t = thread::spawn(move || { + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, AMT * NTHREADS); + assert!(rx.try_recv().is_err()); + + dtx.send(()).unwrap(); + }); + + 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 { + tx.send(1).unwrap(); + } + }); + ts.push(t); + } + + drop(tx); + + drx.recv().unwrap(); + for t in ts { + t.join().unwrap(); + } + t.join().unwrap(); + } + + #[test] + fn stress_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + dtx.send(()).unwrap(); + }); + + 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 { + tx.send(1).unwrap(); + } + }); + ts.push(t); + } + drop(tx); + drx.recv().unwrap(); + for t in ts { + t.join().unwrap(); + } + t.join().unwrap(); + } + + #[test] + fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = sync_channel::(0); + drop(rx); + } + + #[test] + fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = sync_channel::(0); + drop(tx); + } + + #[test] + fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = sync_channel::>(0); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); + } + + #[test] + fn oneshot_single_thread_recv_chan_close() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert_eq!(rx.recv(), Err(RecvError)); + } + + #[test] + fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = sync_channel::>(1); + tx.send(Box::new(10)).unwrap(); + assert!(*rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_open() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(10), Ok(())); + assert!(rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); + } + + #[test] + fn oneshot_single_thread_try_send_closed2() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); + } + + #[test] + fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } + + #[test] + fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn oneshot_single_thread_try_recv_closed_with_data() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + drop(tx); + assert_eq!(rx.try_recv(), Ok(10)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } + + #[test] + fn oneshot_single_thread_peek_data() { + let (tx, rx) = sync_channel::(1); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); + } + + #[test] + fn oneshot_single_thread_peek_close() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } + + #[test] + fn oneshot_single_thread_peek_open() { + let (_tx, rx) = sync_channel::(0); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } + + #[test] + fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = sync_channel::>(0); + let t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(Box::new(10)).unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = sync_channel::>(0); + let t = thread::spawn(move || { + drop(tx); + }); + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_thread_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + drop(tx); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + thread::spawn(move || { + let _ = tx.send(1); + }) + .join() + .unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_recv_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + }); + ts.push(t); + let t2 = thread::spawn(move || { + thread::spawn(move || { + drop(tx); + }); + }); + ts.push(t2); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::>(0); + let t = thread::spawn(move || { + tx.send(Box::new(10)).unwrap(); + }); + ts.push(t); + assert!(*rx.recv().unwrap() == 10); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn stream_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::>(0); + + if let Some(t) = send(tx, 0) { + ts.push(t); + } + if let Some(t) = recv(rx, 0) { + ts.push(t); + } + + fn send(tx: SyncSender>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + })) + } + + fn recv(rx: Receiver>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + })) + } + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = sync_channel(10000); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } + } + + #[test] + fn shared_chan_stress() { + let (tx, rx) = sync_channel(0); + let total = stress_factor() + 100; + let mut ts = Vec::with_capacity(total); + for _ in 0..total { + let tx = tx.clone(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + }); + ts.push(t); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn test_nested_recv_iter() { + let (tx, rx) = sync_channel::(0); + let (total_tx, total_rx) = sync_channel::(0); + + let t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); + t.join().unwrap(); + } + + #[test] + fn test_recv_iter_break() { + let (tx, rx) = sync_channel::(0); + let (count_tx, count_rx) = sync_channel(0); + + let t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.try_send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); + t.join().unwrap(); + } + + #[test] + fn try_recv_states() { + let (tx1, rx1) = sync_channel::(1); + let (tx2, rx2) = sync_channel::<()>(1); + let (tx3, rx3) = sync_channel::<()>(1); + let t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); + t.join().unwrap(); + } + + // This bug used to end up in a livelock inside of the Receiver destructor + // because the internal state of the Shared packet was corrupted + #[test] + fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = sync_channel::<()>(0); + let (tx2, rx2) = sync_channel::<()>(0); + let t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let tx2 = tx.clone(); + drop(tx); + tx2.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn send1() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + assert_eq!(tx.send(1), Ok(())); + t.join().unwrap(); + } + + #[test] + fn send2() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); + t.join().unwrap(); + } + + #[test] + fn send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.send(1), Ok(())); + let t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); + t.join().unwrap(); + } + + #[test] + fn send4() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let (done, donerx) = channel(); + let done2 = done.clone(); + let t = thread::spawn(move || { + assert!(tx.send(1).is_err()); + done.send(()).unwrap(); + }); + let t2 = thread::spawn(move || { + assert!(tx2.send(2).is_err()); + done2.send(()).unwrap(); + }); + drop(rx); + donerx.recv().unwrap(); + donerx.recv().unwrap(); + t.join().unwrap(); + t2.join().unwrap(); + } + + #[test] + fn try_send1() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); + } + + #[test] + fn try_send2() { + let (tx, _rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); + } + + #[test] + fn try_send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + drop(rx); + assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); + } + + #[test] + fn issue_15761() { + fn repro() { + let (tx1, rx1) = sync_channel::<()>(3); + let (tx2, rx2) = sync_channel::<()>(3); + + let _t = thread::spawn(move || { + rx1.recv().unwrap(); + tx2.try_send(()).unwrap(); + }); + + tx1.try_send(()).unwrap(); + rx2.recv().unwrap(); + } + + for _ in 0..100 { + repro() + } + } +} + +// Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/select.rs +mod select_tests { + use super::*; + + use std::thread; + + #[test] + fn smoke() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + tx1.send(1).unwrap(); + select! { + foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); }, + _bar = rx2.recv() => { panic!() } + } + tx2.send(2).unwrap(); + select! { + _foo = rx1.recv() => { panic!() }, + bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) } + } + drop(tx1); + select! { + foo = rx1.recv() => { assert!(foo.is_err()); }, + _bar = rx2.recv() => { panic!() } + } + drop(tx2); + select! { + bar = rx2.recv() => { assert!(bar.is_err()); } + } + } + + #[test] + fn smoke2() { + let (_tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (_tx3, rx3) = channel::(); + let (_tx4, rx4) = channel::(); + let (tx5, rx5) = channel::(); + tx5.send(4).unwrap(); + select! { + _foo = rx1.recv() => { panic!("1") }, + _foo = rx2.recv() => { panic!("2") }, + _foo = rx3.recv() => { panic!("3") }, + _foo = rx4.recv() => { panic!("4") }, + foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); } + } + } + + #[test] + fn closed() { + let (_tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + drop(tx2); + + select! { + _a1 = rx1.recv() => { panic!() }, + a2 = rx2.recv() => { assert!(a2.is_err()); } + } + } + + #[test] + fn unblocks() { + let (tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (tx3, rx3) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..20 { + thread::yield_now(); + } + tx1.send(1).unwrap(); + rx3.recv().unwrap(); + for _ in 0..20 { + thread::yield_now(); + } + }); + + select! { + a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, + _b = rx2.recv() => { panic!() } + } + tx3.send(1).unwrap(); + select! { + a = rx1.recv() => { assert!(a.is_err()) }, + _b = rx2.recv() => { panic!() } + } + t.join().unwrap(); + } + + #[test] + fn both_ready() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + for _ in 0..20 { + thread::yield_now(); + } + tx1.send(1).unwrap(); + tx2.send(2).unwrap(); + rx3.recv().unwrap(); + }); + + select! { + a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, + a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } + } + select! { + a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, + a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } + } + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty)); + tx3.send(()).unwrap(); + t.join().unwrap(); + } + + #[test] + fn stress() { + const AMT: i32 = 10000; + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + for i in 0..AMT { + if i % 2 == 0 { + tx1.send(i).unwrap(); + } else { + tx2.send(i).unwrap(); + } + rx3.recv().unwrap(); + } + }); + + for i in 0..AMT { + select! { + i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); }, + i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); } + } + tx3.send(()).unwrap(); + } + t.join().unwrap(); + } + + #[allow(unused_must_use)] + #[test] + fn cloning() { + let (tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + rx3.recv().unwrap(); + tx1.clone(); + assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); + tx1.send(2).unwrap(); + rx3.recv().unwrap(); + }); + + tx3.send(()).unwrap(); + select! { + _i1 = rx1.recv() => {}, + _i2 = rx2.recv() => panic!() + } + tx3.send(()).unwrap(); + t.join().unwrap(); + } + + #[allow(unused_must_use)] + #[test] + fn cloning2() { + let (tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + rx3.recv().unwrap(); + tx1.clone(); + assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); + tx1.send(2).unwrap(); + rx3.recv().unwrap(); + }); + + tx3.send(()).unwrap(); + select! { + _i1 = rx1.recv() => {}, + _i2 = rx2.recv() => panic!() + } + tx3.send(()).unwrap(); + t.join().unwrap(); + } + + #[test] + fn cloning3() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let t = thread::spawn(move || { + select! { + _ = rx1.recv() => panic!(), + _ = rx2.recv() => {} + } + tx3.send(()).unwrap(); + }); + + for _ in 0..1000 { + thread::yield_now(); + } + drop(tx1.clone()); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn preflight1() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + select! { + _n = rx.recv() => {} + } + } + + #[test] + fn preflight2() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + tx.send(()).unwrap(); + select! { + _n = rx.recv() => {} + } + } + + #[test] + fn preflight3() { + let (tx, rx) = channel(); + drop(tx.clone()); + tx.send(()).unwrap(); + select! { + _n = rx.recv() => {} + } + } + + #[test] + fn preflight4() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight5() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + tx.send(()).unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight6() { + let (tx, rx) = channel(); + drop(tx.clone()); + tx.send(()).unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight7() { + let (tx, rx) = channel::<()>(); + drop(tx); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight8() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + drop(tx); + rx.recv().unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight9() { + let (tx, rx) = channel(); + drop(tx.clone()); + tx.send(()).unwrap(); + drop(tx); + rx.recv().unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn oneshot_data_waiting() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let t = thread::spawn(move || { + select! { + _n = rx1.recv() => {} + } + tx2.send(()).unwrap(); + }); + + for _ in 0..100 { + thread::yield_now() + } + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn stream_data_waiting() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + tx1.send(()).unwrap(); + tx1.send(()).unwrap(); + rx1.recv().unwrap(); + rx1.recv().unwrap(); + let t = thread::spawn(move || { + select! { + _n = rx1.recv() => {} + } + tx2.send(()).unwrap(); + }); + + for _ in 0..100 { + thread::yield_now() + } + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn shared_data_waiting() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + drop(tx1.clone()); + tx1.send(()).unwrap(); + rx1.recv().unwrap(); + let t = thread::spawn(move || { + select! { + _n = rx1.recv() => {} + } + tx2.send(()).unwrap(); + }); + + for _ in 0..100 { + thread::yield_now() + } + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn sync1() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + select! { + n = rx.recv() => { assert_eq!(n.unwrap(), 1); } + } + } + + #[test] + fn sync2() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + for _ in 0..100 { + thread::yield_now() + } + tx.send(1).unwrap(); + }); + select! { + n = rx.recv() => { assert_eq!(n.unwrap(), 1); } + } + t.join().unwrap(); + } + + #[test] + fn sync3() { + let (tx1, rx1) = sync_channel::(0); + let (tx2, rx2): (Sender, Receiver) = channel(); + let t = thread::spawn(move || { + tx1.send(1).unwrap(); + }); + let t2 = thread::spawn(move || { + tx2.send(2).unwrap(); + }); + select! { + n = rx1.recv() => { + let n = n.unwrap(); + assert_eq!(n, 1); + assert_eq!(rx2.recv().unwrap(), 2); + }, + n = rx2.recv() => { + let n = n.unwrap(); + assert_eq!(n, 2); + assert_eq!(rx1.recv().unwrap(), 1); + } + } + t.join().unwrap(); + t2.join().unwrap(); + } +} diff --git a/vendor/crossbeam-channel/tests/never.rs b/vendor/crossbeam-channel/tests/never.rs new file mode 100644 index 0000000000..35b6f74dda --- /dev/null +++ b/vendor/crossbeam-channel/tests/never.rs @@ -0,0 +1,99 @@ +//! Tests for the never channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate rand; + +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{never, tick, unbounded}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + select! { + recv(never::()) -> _ => panic!(), + default => {} + } +} + +#[test] +fn optional() { + let (s, r) = unbounded::(); + s.send(1).unwrap(); + s.send(2).unwrap(); + + let mut r = Some(&r); + select! { + recv(r.unwrap_or(&never())) -> _ => {} + default => panic!(), + } + + r = None; + select! { + recv(r.unwrap_or(&never())) -> _ => panic!(), + default => {} + } +} + +#[test] +fn tick_n() { + let mut r = tick(ms(100)); + let mut step = 0; + + loop { + select! { + recv(r) -> _ => step += 1, + default(ms(500)) => break, + } + + if step == 10 { + r = never(); + } + } + + assert_eq!(step, 10); +} + +#[test] +fn capacity() { + let r = never::(); + assert_eq!(r.capacity(), Some(0)); +} + +#[test] +fn len_empty_full() { + let r = never::(); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), true); +} + +#[test] +fn try_recv() { + let r = never::(); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(100)); + assert!(r.try_recv().is_err()); +} + +#[test] +fn recv_timeout() { + let start = Instant::now(); + let r = never::(); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(100)); + assert!(now - start <= ms(150)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(200)); + assert!(now - start <= ms(250)); +} diff --git a/vendor/crossbeam-channel/tests/ready.rs b/vendor/crossbeam-channel/tests/ready.rs new file mode 100644 index 0000000000..23769b7bd7 --- /dev/null +++ b/vendor/crossbeam-channel/tests/ready.rs @@ -0,0 +1,837 @@ +//! Tests for channel readiness using the `Select` struct. + +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use std::any::Any; +use std::cell::Cell; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, bounded, tick, unbounded}; +use crossbeam_channel::{Receiver, Select, TryRecvError, TrySendError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke1() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert_eq!(sel.ready(), 0); + assert_eq!(r1.try_recv(), Ok(1)); + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert_eq!(sel.ready(), 1); + assert_eq!(r2.try_recv(), Ok(2)); +} + +#[test] +fn smoke2() { + let (_s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (_s3, r3) = unbounded::(); + let (_s4, r4) = unbounded::(); + let (s5, r5) = unbounded::(); + + s5.send(5).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&r3); + sel.recv(&r4); + sel.recv(&r5); + assert_eq!(sel.ready(), 4); + assert_eq!(r5.try_recv(), Ok(5)); +} + +#[test] +fn disconnected() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + drop(s1); + thread::sleep(ms(500)); + s2.send(5).unwrap(); + }); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + r2.recv().unwrap(); + }) + .unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + drop(s2); + }); + + let mut sel = Select::new(); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r2.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn default() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert!(sel.try_ready().is_err()); + + drop(s1); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.try_ready() { + Ok(0) => assert!(r1.try_recv().is_err()), + _ => panic!(), + } + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r2); + match sel.try_ready() { + Ok(0) => assert_eq!(r2.try_recv(), Ok(2)), + _ => panic!(), + } + + let mut sel = Select::new(); + sel.recv(&r2); + assert!(sel.try_ready().is_err()); + + let mut sel = Select::new(); + assert!(sel.try_ready().is_err()); +} + +#[test] +fn timeout() { + let (_s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(1500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert!(sel.ready_timeout(ms(1000)).is_err()); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(1) => assert_eq!(r2.try_recv(), Ok(2)), + _ => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + let (s, r) = unbounded::(); + + scope.spawn(move |_| { + thread::sleep(ms(500)); + drop(s); + }); + + let mut sel = Select::new(); + assert!(sel.ready_timeout(ms(1000)).is_err()); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.try_ready() { + Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn default_when_disconnected() { + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.try_ready() { + Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + sel.send(&s); + match sel.try_ready() { + Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))), + _ => panic!(), + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + sel.send(&s); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))), + _ => panic!(), + } +} + +#[test] +fn default_only() { + let start = Instant::now(); + + let mut sel = Select::new(); + assert!(sel.try_ready().is_err()); + let now = Instant::now(); + assert!(now - start <= ms(50)); + + let start = Instant::now(); + let mut sel = Select::new(); + assert!(sel.ready_timeout(ms(500)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(450)); + assert!(now - start <= ms(550)); +} + +#[test] +fn unblocks() { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(1) => assert_eq!(r2.try_recv(), Ok(2)), + _ => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + assert_eq!(r1.recv().unwrap(), 1); + }); + + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper2 = sel.send(&s2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => oper.send(&s1, 1).unwrap(), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + }) + .unwrap(); +} + +#[test] +fn both_ready() { + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s1.send(1).unwrap(); + assert_eq!(r2.recv().unwrap(), 2); + }); + + for _ in 0..2 { + let mut sel = Select::new(); + sel.recv(&r1); + sel.send(&s2); + match sel.ready() { + 0 => assert_eq!(r1.try_recv(), Ok(1)), + 1 => s2.try_send(2).unwrap(), + _ => panic!(), + } + } + }) + .unwrap(); +} + +#[test] +fn cloning1() { + scope(|scope| { + let (s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (s3, r3) = unbounded::<()>(); + + scope.spawn(move |_| { + r3.recv().unwrap(); + drop(s1.clone()); + assert!(r3.try_recv().is_err()); + s1.send(1).unwrap(); + r3.recv().unwrap(); + }); + + s3.send(()).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready() { + 0 => drop(r1.try_recv()), + 1 => drop(r2.try_recv()), + _ => panic!(), + } + + s3.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn cloning2() { + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + let (_s3, _r3) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready() { + 0 => panic!(), + 1 => drop(r2.try_recv()), + _ => panic!(), + } + }); + + thread::sleep(ms(500)); + drop(s1.clone()); + s2.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn preflight1() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => drop(r.try_recv()), + _ => panic!(), + } +} + +#[test] +fn preflight2() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => assert_eq!(r.try_recv(), Ok(())), + _ => panic!(), + } + + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn preflight3() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + r.recv().unwrap(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } +} + +#[test] +fn duplicate_operations() { + let (s, r) = unbounded::(); + let hit = vec![Cell::new(false); 4]; + + while hit.iter().map(|h| h.get()).any(|hit| !hit) { + let mut sel = Select::new(); + sel.recv(&r); + sel.recv(&r); + sel.send(&s); + sel.send(&s); + match sel.ready() { + 0 => { + assert!(r.try_recv().is_ok()); + hit[0].set(true); + } + 1 => { + assert!(r.try_recv().is_ok()); + hit[1].set(true); + } + 2 => { + assert!(s.try_send(0).is_ok()); + hit[2].set(true); + } + 3 => { + assert!(s.try_send(0).is_ok()); + hit[3].set(true); + } + _ => panic!(), + } + } +} + +#[test] +fn nesting() { + let (s, r) = unbounded::(); + + let mut sel = Select::new(); + sel.send(&s); + match sel.ready() { + 0 => { + assert!(s.try_send(0).is_ok()); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => { + assert_eq!(r.try_recv(), Ok(0)); + + let mut sel = Select::new(); + sel.send(&s); + match sel.ready() { + 0 => { + assert!(s.try_send(1).is_ok()); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => { + assert_eq!(r.try_recv(), Ok(1)); + } + _ => panic!(), + } + } + _ => panic!(), + } + } + _ => panic!(), + } + } + _ => panic!(), + } +} + +#[test] +fn stress_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded(); + let (s2, r2) = bounded(5); + let (s3, r3) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + r3.recv().unwrap(); + + s2.send(i).unwrap(); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready() { + 0 => assert_eq!(r1.try_recv(), Ok(i)), + 1 => assert_eq!(r2.try_recv(), Ok(i)), + _ => panic!(), + } + + s3.send(()).unwrap(); + } + } + }) + .unwrap(); +} + +#[test] +fn stress_send() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r1.recv().unwrap(), i); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + sel.send(&s1); + sel.send(&s2); + match sel.ready() { + 0 => assert!(s1.try_send(i).is_ok()), + 1 => assert!(s2.try_send(i).is_ok()), + _ => panic!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_mixed() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + sel.recv(&r1); + sel.send(&s2); + match sel.ready() { + 0 => assert_eq!(r1.try_recv(), Ok(i)), + 1 => assert!(s2.try_send(i).is_ok()), + _ => panic!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 20; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let done = false; + while !done { + let mut sel = Select::new(); + sel.send(&s); + match sel.ready_timeout(ms(100)) { + Err(_) => {} + Ok(0) => { + assert!(s.try_send(i).is_ok()); + break; + } + Ok(_) => panic!(), + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let mut done = false; + while !done { + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready_timeout(ms(100)) { + Err(_) => {} + Ok(0) => { + assert_eq!(r.try_recv(), Ok(i)); + done = true; + } + Ok(_) => panic!(), + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn send_recv_same_channel() { + let (s, r) = bounded::(0); + let mut sel = Select::new(); + sel.send(&s); + sel.recv(&r); + assert!(sel.ready_timeout(ms(100)).is_err()); + + let (s, r) = unbounded::(); + let mut sel = Select::new(); + sel.send(&s); + sel.recv(&r); + match sel.ready_timeout(ms(100)) { + Err(_) => panic!(), + Ok(0) => assert!(s.try_send(0).is_ok()), + Ok(_) => panic!(), + } +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + for cap in 1..4 { + let (s, r) = bounded::(cap); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(cap); + let new_r: T = Box::new(Some(new_r)); + + { + let mut sel = Select::new(); + sel.send(&s); + match sel.ready() { + 0 => assert!(s.try_send(new_r).is_ok()), + _ => panic!(), + } + } + + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + let new = { + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => r + .try_recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap(), + _ => panic!(), + } + }; + r = new; + } + }); + }) + .unwrap(); + } +} + +#[test] +fn fairness1() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let hits = vec![Cell::new(0usize); 4]; + for _ in 0..COUNT { + let after = after(ms(0)); + let tick = tick(ms(0)); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&after); + sel.recv(&tick); + match sel.ready() { + 0 => { + r1.try_recv().unwrap(); + hits[0].set(hits[0].get() + 1); + } + 1 => { + r2.try_recv().unwrap(); + hits[1].set(hits[1].get() + 1); + } + 2 => { + after.try_recv().unwrap(); + hits[2].set(hits[2].get() + 1); + } + 3 => { + tick.try_recv().unwrap(); + hits[3].set(hits[3].get() + 1); + } + _ => panic!(), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness2() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = bounded::<()>(1); + let (s3, r3) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + let mut sel = Select::new(); + let mut oper1 = None; + let mut oper2 = None; + if s1.is_empty() { + oper1 = Some(sel.send(&s1)); + } + if s2.is_empty() { + oper2 = Some(sel.send(&s2)); + } + let oper3 = sel.send(&s3); + let oper = sel.select(); + match oper.index() { + i if Some(i) == oper1 => assert!(oper.send(&s1, ()).is_ok()), + i if Some(i) == oper2 => assert!(oper.send(&s2, ()).is_ok()), + i if i == oper3 => assert!(oper.send(&s3, ()).is_ok()), + _ => unreachable!(), + } + } + }); + + let hits = vec![Cell::new(0usize); 3]; + for _ in 0..COUNT { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&r3); + loop { + match sel.ready() { + 0 => { + if r1.try_recv().is_ok() { + hits[0].set(hits[0].get() + 1); + break; + } + } + 1 => { + if r2.try_recv().is_ok() { + hits[1].set(hits[1].get() + 1); + break; + } + } + 2 => { + if r3.try_recv().is_ok() { + hits[2].set(hits[2].get() + 1); + break; + } + } + _ => unreachable!(), + } + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 10)); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/same_channel.rs b/vendor/crossbeam-channel/tests/same_channel.rs new file mode 100644 index 0000000000..8e34faf448 --- /dev/null +++ b/vendor/crossbeam-channel/tests/same_channel.rs @@ -0,0 +1,114 @@ +extern crate crossbeam_channel; + +use std::time::Duration; + +use crossbeam_channel::{after, bounded, never, tick, unbounded}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn after_same_channel() { + let r = after(ms(50)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let r3 = after(ms(50)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); + + let r4 = after(ms(100)); + assert!(!r.same_channel(&r4)); + assert!(!r2.same_channel(&r4)); +} + +#[test] +fn array_same_channel() { + let (s, r) = bounded::(1); + + let s2 = s.clone(); + assert!(s.same_channel(&s2)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let (s3, r3) = bounded::(1); + assert!(!s.same_channel(&s3)); + assert!(!s2.same_channel(&s3)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); +} + +#[test] +fn list_same_channel() { + let (s, r) = unbounded::(); + + let s2 = s.clone(); + assert!(s.same_channel(&s2)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let (s3, r3) = unbounded::(); + assert!(!s.same_channel(&s3)); + assert!(!s2.same_channel(&s3)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); +} + +#[test] +fn never_same_channel() { + let r = never::(); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + // Never channel are always equal to one another. + let r3 = never::(); + assert!(r.same_channel(&r3)); + assert!(r2.same_channel(&r3)); +} + +#[test] +fn tick_same_channel() { + let r = tick(ms(50)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let r3 = tick(ms(50)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); + + let r4 = tick(ms(100)); + assert!(!r.same_channel(&r4)); + assert!(!r2.same_channel(&r4)); +} + +#[test] +fn zero_same_channel() { + let (s, r) = bounded::(0); + + let s2 = s.clone(); + assert!(s.same_channel(&s2)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let (s3, r3) = bounded::(0); + assert!(!s.same_channel(&s3)); + assert!(!s2.same_channel(&s3)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); +} + +#[test] +fn different_flavors_same_channel() { + let (s1, r1) = bounded::(0); + let (s2, r2) = unbounded::(); + + assert!(!s1.same_channel(&s2)); + assert!(!r1.same_channel(&r2)); +} diff --git a/vendor/crossbeam-channel/tests/select.rs b/vendor/crossbeam-channel/tests/select.rs new file mode 100644 index 0000000000..b18d66d7cd --- /dev/null +++ b/vendor/crossbeam-channel/tests/select.rs @@ -0,0 +1,1304 @@ +//! Tests for channel selection using the `Select` struct. + +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use std::any::Any; +use std::cell::Cell; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, bounded, tick, unbounded, Receiver, Select, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke1() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), + i if i == oper2 => panic!(), + _ => unreachable!(), + } + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + } +} + +#[test] +fn smoke2() { + let (_s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (_s3, r3) = unbounded::(); + let (_s4, r4) = unbounded::(); + let (s5, r5) = unbounded::(); + + s5.send(5).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&r3); + let oper4 = sel.recv(&r4); + let oper5 = sel.recv(&r5); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => panic!(), + i if i == oper3 => panic!(), + i if i == oper4 => panic!(), + i if i == oper5 => assert_eq!(oper.recv(&r5), Ok(5)), + _ => unreachable!(), + } +} + +#[test] +fn disconnected() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + drop(s1); + thread::sleep(ms(500)); + s2.send(5).unwrap(); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r1).is_err()), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + r2.recv().unwrap(); + }) + .unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r1).is_err()), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + drop(s2); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r2).is_err()), + _ => unreachable!(), + }, + } + }) + .unwrap(); +} + +#[test] +fn default() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + let mut sel = Select::new(); + let _oper1 = sel.recv(&r1); + let _oper2 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(_) => panic!(), + } + + drop(s1); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r1).is_err()), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + }, + } + + let mut sel = Select::new(); + let _oper1 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(_) => panic!(), + } + + let mut sel = Select::new(); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(_) => panic!(), + } +} + +#[test] +fn timeout() { + let (_s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(1500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + }, + } + }) + .unwrap(); + + scope(|scope| { + let (s, r) = unbounded::(); + + scope.spawn(move |_| { + thread::sleep(ms(500)); + drop(s); + }); + + let mut sel = Select::new(); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + }, + } + } + Ok(_) => unreachable!(), + } + }) + .unwrap(); +} + +#[test] +fn default_when_disconnected() { + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + }, + } + + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + }, + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.send(&s, 0).is_err()), + _ => unreachable!(), + }, + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.send(&s, 0).is_err()), + _ => unreachable!(), + }, + } +} + +#[test] +fn default_only() { + let start = Instant::now(); + + let mut sel = Select::new(); + let oper = sel.try_select(); + assert!(oper.is_err()); + let now = Instant::now(); + assert!(now - start <= ms(50)); + + let start = Instant::now(); + let mut sel = Select::new(); + let oper = sel.select_timeout(ms(500)); + assert!(oper.is_err()); + let now = Instant::now(); + assert!(now - start >= ms(450)); + assert!(now - start <= ms(550)); +} + +#[test] +fn unblocks() { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + }, + } + }) + .unwrap(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + assert_eq!(r1.recv().unwrap(), 1); + }); + + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper2 = sel.send(&s2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => oper.send(&s1, 1).unwrap(), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + }) + .unwrap(); +} + +#[test] +fn both_ready() { + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s1.send(1).unwrap(); + assert_eq!(r2.recv().unwrap(), 2); + }); + + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), + i if i == oper2 => oper.send(&s2, 2).unwrap(), + _ => unreachable!(), + } + } + }) + .unwrap(); +} + +#[test] +fn loop_try() { + const RUNS: usize = 20; + + for _ in 0..RUNS { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + let (s_end, r_end) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| loop { + let mut done = false; + + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => { + let _ = oper.send(&s1, 1); + done = true; + } + _ => unreachable!(), + }, + } + if done { + break; + } + + let mut sel = Select::new(); + let oper1 = sel.recv(&r_end); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => { + let _ = oper.recv(&r_end); + done = true; + } + _ => unreachable!(), + }, + } + if done { + break; + } + }); + + scope.spawn(|_| loop { + if let Ok(x) = r2.try_recv() { + assert_eq!(x, 2); + break; + } + + let mut done = false; + let mut sel = Select::new(); + let oper1 = sel.recv(&r_end); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => { + let _ = oper.recv(&r_end); + done = true; + } + _ => unreachable!(), + }, + } + if done { + break; + } + }); + + scope.spawn(|_| { + thread::sleep(ms(500)); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), + i if i == oper2 => assert!(oper.send(&s2, 2).is_ok()), + _ => unreachable!(), + }, + } + + drop(s_end); + }); + }) + .unwrap(); + } +} + +#[test] +fn cloning1() { + scope(|scope| { + let (s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (s3, r3) = unbounded::<()>(); + + scope.spawn(move |_| { + r3.recv().unwrap(); + drop(s1.clone()); + assert!(r3.try_recv().is_err()); + s1.send(1).unwrap(); + r3.recv().unwrap(); + }); + + s3.send(()).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => drop(oper.recv(&r1)), + i if i == oper2 => drop(oper.recv(&r2)), + _ => unreachable!(), + } + + s3.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn cloning2() { + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + let (_s3, _r3) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => drop(oper.recv(&r2)), + _ => unreachable!(), + } + }); + + thread::sleep(ms(500)); + drop(s1.clone()); + s2.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn preflight1() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => drop(oper.recv(&r)), + _ => unreachable!(), + } +} + +#[test] +fn preflight2() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r), Ok(())), + _ => unreachable!(), + } + + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn preflight3() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + r.recv().unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + } +} + +#[test] +fn duplicate_operations() { + let (s, r) = unbounded::(); + let hit = vec![Cell::new(false); 4]; + + while hit.iter().map(|h| h.get()).any(|hit| !hit) { + let mut sel = Select::new(); + let oper0 = sel.recv(&r); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let oper3 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + i if i == oper0 => { + assert!(oper.recv(&r).is_ok()); + hit[0].set(true); + } + i if i == oper1 => { + assert!(oper.recv(&r).is_ok()); + hit[1].set(true); + } + i if i == oper2 => { + assert!(oper.send(&s, 0).is_ok()); + hit[2].set(true); + } + i if i == oper3 => { + assert!(oper.send(&s, 0).is_ok()); + hit[3].set(true); + } + _ => unreachable!(), + } + } +} + +#[test] +fn nesting() { + let (s, r) = unbounded::(); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert!(oper.send(&s, 0).is_ok()); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert_eq!(oper.recv(&r), Ok(0)); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert!(oper.send(&s, 1).is_ok()); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert_eq!(oper.recv(&r), Ok(1)); + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } +} + +#[test] +fn stress_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded(); + let (s2, r2) = bounded(5); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + r3.recv().unwrap(); + + s2.send(i).unwrap(); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), + ix if ix == oper2 => assert_eq!(oper.recv(&r2), Ok(i)), + _ => unreachable!(), + } + + s3.send(()).unwrap(); + } + } + }) + .unwrap(); +} + +#[test] +fn stress_send() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r1.recv().unwrap(), i); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper2 = sel.send(&s2); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert!(oper.send(&s1, i).is_ok()), + ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), + _ => unreachable!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_mixed() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), + _ => unreachable!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 20; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let done = false; + while !done { + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + ix if ix == oper1 => { + assert!(oper.send(&s, i).is_ok()); + break; + } + _ => unreachable!(), + }, + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let mut done = false; + while !done { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + ix if ix == oper1 => { + assert_eq!(oper.recv(&r), Ok(i)); + done = true; + } + _ => unreachable!(), + }, + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn send_recv_same_channel() { + let (s, r) = bounded::(0); + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper2 = sel.recv(&r); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + ix if ix == oper1 => panic!(), + ix if ix == oper2 => panic!(), + _ => unreachable!(), + }, + } + + let (s, r) = unbounded::(); + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper2 = sel.recv(&r); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + ix if ix == oper1 => assert!(oper.send(&s, 0).is_ok()), + ix if ix == oper2 => panic!(), + _ => unreachable!(), + }, + } +} + +#[test] +fn matching() { + const THREADS: usize = 44; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn matching_with_leftover() { + const THREADS: usize = 55; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + s.send(!0).unwrap(); + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + for cap in 0..3 { + let (s, r) = bounded::(cap); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(cap); + let new_r: T = Box::new(Some(new_r)); + + { + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert!(oper.send(&s, new_r).is_ok()), + _ => unreachable!(), + } + } + + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + let new = { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => oper + .recv(&r) + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap(), + _ => unreachable!(), + } + }; + r = new; + } + }); + }) + .unwrap(); + } +} + +#[test] +fn linearizable_try() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => unreachable!(), + Ok(oper) => match oper.index() { + ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), + ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), + _ => unreachable!(), + }, + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn linearizable_timeout() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(0)); + match oper { + Err(_) => unreachable!(), + Ok(oper) => match oper.index() { + ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), + ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), + _ => unreachable!(), + }, + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn fairness1() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let hits = vec![Cell::new(0usize); 4]; + for _ in 0..COUNT { + let after = after(ms(0)); + let tick = tick(ms(0)); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&after); + let oper4 = sel.recv(&tick); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + oper.recv(&r1).unwrap(); + hits[0].set(hits[0].get() + 1); + } + i if i == oper2 => { + oper.recv(&r2).unwrap(); + hits[1].set(hits[1].get() + 1); + } + i if i == oper3 => { + oper.recv(&after).unwrap(); + hits[2].set(hits[2].get() + 1); + } + i if i == oper4 => { + oper.recv(&tick).unwrap(); + hits[3].set(hits[3].get() + 1); + } + _ => unreachable!(), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness2() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = bounded::<()>(1); + let (s3, r3) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + let mut sel = Select::new(); + let mut oper1 = None; + let mut oper2 = None; + if s1.is_empty() { + oper1 = Some(sel.send(&s1)); + } + if s2.is_empty() { + oper2 = Some(sel.send(&s2)); + } + let oper3 = sel.send(&s3); + let oper = sel.select(); + match oper.index() { + i if Some(i) == oper1 => assert!(oper.send(&s1, ()).is_ok()), + i if Some(i) == oper2 => assert!(oper.send(&s2, ()).is_ok()), + i if i == oper3 => assert!(oper.send(&s3, ()).is_ok()), + _ => unreachable!(), + } + } + }); + + let hits = vec![Cell::new(0usize); 3]; + for _ in 0..COUNT { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&r3); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + oper.recv(&r1).unwrap(); + hits[0].set(hits[0].get() + 1); + } + i if i == oper2 => { + oper.recv(&r2).unwrap(); + hits[1].set(hits[1].get() + 1); + } + i if i == oper3 => { + oper.recv(&r3).unwrap(); + hits[2].set(hits[2].get() + 1); + } + _ => unreachable!(), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50)); + }) + .unwrap(); +} + +#[test] +fn sync_and_clone() { + const THREADS: usize = 20; + + let (s, r) = &bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let sel = &sel; + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + let mut sel = sel.clone(); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn send_and_clone() { + const THREADS: usize = 20; + + let (s, r) = &bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + + scope(|scope| { + for i in 0..THREADS { + let mut sel = sel.clone(); + scope.spawn(move |_| { + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn reuse() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + + for i in 0..COUNT { + for _ in 0..2 { + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), + _ => unreachable!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/select_macro.rs b/vendor/crossbeam-channel/tests/select_macro.rs new file mode 100644 index 0000000000..a9cc7fac79 --- /dev/null +++ b/vendor/crossbeam-channel/tests/select_macro.rs @@ -0,0 +1,1440 @@ +//! Tests for the `select!` macro. + +#![deny(unsafe_code)] + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use std::any::Any; +use std::cell::Cell; +use std::ops::Deref; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, bounded, never, tick, unbounded}; +use crossbeam_channel::{Receiver, RecvError, SendError, Sender, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke1() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + s1.send(1).unwrap(); + + select! { + recv(r1) -> v => assert_eq!(v, Ok(1)), + recv(r2) -> _ => panic!(), + } + + s2.send(2).unwrap(); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> v => assert_eq!(v, Ok(2)), + } +} + +#[test] +fn smoke2() { + let (_s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (_s3, r3) = unbounded::(); + let (_s4, r4) = unbounded::(); + let (s5, r5) = unbounded::(); + + s5.send(5).unwrap(); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => panic!(), + recv(r3) -> _ => panic!(), + recv(r4) -> _ => panic!(), + recv(r5) -> v => assert_eq!(v, Ok(5)), + } +} + +#[test] +fn disconnected() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + drop(s1); + thread::sleep(ms(500)); + s2.send(5).unwrap(); + }); + + select! { + recv(r1) -> v => assert!(v.is_err()), + recv(r2) -> _ => panic!(), + default(ms(1000)) => panic!(), + } + + r2.recv().unwrap(); + }) + .unwrap(); + + select! { + recv(r1) -> v => assert!(v.is_err()), + recv(r2) -> _ => panic!(), + default(ms(1000)) => panic!(), + } + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + drop(s2); + }); + + select! { + recv(r2) -> v => assert!(v.is_err()), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn default() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => panic!(), + default => {} + } + + drop(s1); + + select! { + recv(r1) -> v => assert!(v.is_err()), + recv(r2) -> _ => panic!(), + default => panic!(), + } + + s2.send(2).unwrap(); + + select! { + recv(r2) -> v => assert_eq!(v, Ok(2)), + default => panic!(), + } + + select! { + recv(r2) -> _ => panic!(), + default => {}, + } + + select! { + default => {}, + } +} + +#[test] +fn timeout() { + let (_s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(1500)); + s2.send(2).unwrap(); + }); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => panic!(), + default(ms(1000)) => {}, + } + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> v => assert_eq!(v, Ok(2)), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + let (s, r) = unbounded::(); + + scope.spawn(move |_| { + thread::sleep(ms(500)); + drop(s); + }); + + select! { + default(ms(1000)) => { + select! { + recv(r) -> v => assert!(v.is_err()), + default => panic!(), + } + } + } + }) + .unwrap(); +} + +#[test] +fn default_when_disconnected() { + let (_, r) = unbounded::(); + + select! { + recv(r) -> res => assert!(res.is_err()), + default => panic!(), + } + + let (_, r) = unbounded::(); + + select! { + recv(r) -> res => assert!(res.is_err()), + default(ms(1000)) => panic!(), + } + + let (s, _) = bounded::(0); + + select! { + send(s, 0) -> res => assert!(res.is_err()), + default => panic!(), + } + + let (s, _) = bounded::(0); + + select! { + send(s, 0) -> res => assert!(res.is_err()), + default(ms(1000)) => panic!(), + } +} + +#[test] +fn default_only() { + let start = Instant::now(); + select! { + default => {} + } + let now = Instant::now(); + assert!(now - start <= ms(50)); + + let start = Instant::now(); + select! { + default(ms(500)) => {} + } + let now = Instant::now(); + assert!(now - start >= ms(450)); + assert!(now - start <= ms(550)); +} + +#[test] +fn unblocks() { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s2.send(2).unwrap(); + }); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> v => assert_eq!(v, Ok(2)), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + assert_eq!(r1.recv().unwrap(), 1); + }); + + select! { + send(s1, 1) -> _ => {}, + send(s2, 2) -> _ => panic!(), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn both_ready() { + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s1.send(1).unwrap(); + assert_eq!(r2.recv().unwrap(), 2); + }); + + for _ in 0..2 { + select! { + recv(r1) -> v => assert_eq!(v, Ok(1)), + send(s2, 2) -> _ => {}, + } + } + }) + .unwrap(); +} + +#[test] +fn loop_try() { + const RUNS: usize = 20; + + for _ in 0..RUNS { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + let (s_end, r_end) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| loop { + select! { + send(s1, 1) -> _ => break, + default => {} + } + + select! { + recv(r_end) -> _ => break, + default => {} + } + }); + + scope.spawn(|_| loop { + if let Ok(x) = r2.try_recv() { + assert_eq!(x, 2); + break; + } + + select! { + recv(r_end) -> _ => break, + default => {} + } + }); + + scope.spawn(|_| { + thread::sleep(ms(500)); + + select! { + recv(r1) -> v => assert_eq!(v, Ok(1)), + send(s2, 2) -> _ => {}, + default(ms(500)) => panic!(), + } + + drop(s_end); + }); + }) + .unwrap(); + } +} + +#[test] +fn cloning1() { + scope(|scope| { + let (s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (s3, r3) = unbounded::<()>(); + + scope.spawn(move |_| { + r3.recv().unwrap(); + drop(s1.clone()); + assert_eq!(r3.try_recv(), Err(TryRecvError::Empty)); + s1.send(1).unwrap(); + r3.recv().unwrap(); + }); + + s3.send(()).unwrap(); + + select! { + recv(r1) -> _ => {}, + recv(r2) -> _ => {}, + } + + s3.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn cloning2() { + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + let (_s3, _r3) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => {}, + } + }); + + thread::sleep(ms(500)); + drop(s1.clone()); + s2.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn preflight1() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + select! { + recv(r) -> _ => {} + } +} + +#[test] +fn preflight2() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + + select! { + recv(r) -> v => assert!(v.is_ok()), + } + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn preflight3() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + r.recv().unwrap(); + + select! { + recv(r) -> v => assert!(v.is_err()) + } +} + +#[test] +fn duplicate_operations() { + let (s, r) = unbounded::(); + let mut hit = [false; 4]; + + while hit.iter().any(|hit| !hit) { + select! { + recv(r) -> _ => hit[0] = true, + recv(r) -> _ => hit[1] = true, + send(s, 0) -> _ => hit[2] = true, + send(s, 0) -> _ => hit[3] = true, + } + } +} + +#[test] +fn nesting() { + let (s, r) = unbounded::(); + + select! { + send(s, 0) -> _ => { + select! { + recv(r) -> v => { + assert_eq!(v, Ok(0)); + select! { + send(s, 1) -> _ => { + select! { + recv(r) -> v => { + assert_eq!(v, Ok(1)); + } + } + } + } + } + } + } + } +} + +#[test] +#[should_panic(expected = "send panicked")] +fn panic_sender() { + fn get() -> Sender { + panic!("send panicked") + } + + #[allow(unreachable_code)] + { + select! { + send(get(), panic!()) -> _ => {} + } + } +} + +#[test] +#[should_panic(expected = "recv panicked")] +fn panic_receiver() { + fn get() -> Receiver { + panic!("recv panicked") + } + + select! { + recv(get()) -> _ => {} + } +} + +#[test] +fn stress_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded(); + let (s2, r2) = bounded(5); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + r3.recv().unwrap(); + + s2.send(i).unwrap(); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + select! { + recv(r1) -> v => assert_eq!(v, Ok(i)), + recv(r2) -> v => assert_eq!(v, Ok(i)), + } + + s3.send(()).unwrap(); + } + } + }) + .unwrap(); +} + +#[test] +fn stress_send() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r1.recv().unwrap(), i); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + select! { + send(s1, i) -> _ => {}, + send(s2, i) -> _ => {}, + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_mixed() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + select! { + recv(r1) -> v => assert_eq!(v, Ok(i)), + send(s2, i) -> _ => {}, + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 20; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + loop { + select! { + send(s, i) -> _ => break, + default(ms(100)) => {} + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + loop { + select! { + recv(r) -> v => { + assert_eq!(v, Ok(i)); + break; + } + default(ms(100)) => {} + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn send_recv_same_channel() { + let (s, r) = bounded::(0); + select! { + send(s, 0) -> _ => panic!(), + recv(r) -> _ => panic!(), + default(ms(500)) => {} + } + + let (s, r) = unbounded::(); + select! { + send(s, 0) -> _ => {}, + recv(r) -> _ => panic!(), + default(ms(500)) => panic!(), + } +} + +#[test] +fn matching() { + const THREADS: usize = 44; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + select! { + recv(r) -> v => assert_ne!(v.unwrap(), i), + send(s, i) -> _ => {}, + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn matching_with_leftover() { + const THREADS: usize = 55; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + select! { + recv(r) -> v => assert_ne!(v.unwrap(), i), + send(s, i) -> _ => {}, + } + }); + } + s.send(!0).unwrap(); + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + for cap in 0..3 { + let (s, r) = bounded::(cap); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(cap); + let new_r: T = Box::new(Some(new_r)); + + select! { + send(s, new_r) -> _ => {} + } + + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = select! { + recv(r) -> msg => { + msg.unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + } + } + }); + }) + .unwrap(); + } +} + +#[test] +fn linearizable_default() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + default => unreachable!() + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn linearizable_timeout() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + default(ms(0)) => unreachable!() + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn fairness1() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 4]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + recv(after(ms(0))) -> _ => hits[2] += 1, + recv(tick(ms(0))) -> _ => hits[3] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness2() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = bounded::<()>(1); + let (s3, r3) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + let (hole, _r) = bounded(0); + + for _ in 0..COUNT { + let s1 = if s1.is_empty() { &s1 } else { &hole }; + let s2 = if s2.is_empty() { &s2 } else { &hole }; + + select! { + send(s1, ()) -> res => assert!(res.is_ok()), + send(s2, ()) -> res => assert!(res.is_ok()), + send(s3, ()) -> res => assert!(res.is_ok()), + } + } + }); + + let hits = vec![Cell::new(0usize); 3]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0].set(hits[0].get() + 1), + recv(r2) -> _ => hits[1].set(hits[1].get() + 1), + recv(r3) -> _ => hits[2].set(hits[2].get() + 1), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50)); + }) + .unwrap(); +} + +#[test] +fn fairness_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 2]; + while hits[0] + hits[1] < COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / 4)); +} + +#[test] +fn fairness_send() { + const COUNT: usize = 10_000; + + let (s1, _r1) = bounded::<()>(COUNT); + let (s2, _r2) = unbounded::<()>(); + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + send(s1, ()) -> _ => hits[0] += 1, + send(s2, ()) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / 4)); +} + +#[test] +fn references() { + let (s, r) = unbounded::(); + select! { + send(s, 0) -> _ => {} + recv(r) -> _ => {} + } + select! { + send(&&&&s, 0) -> _ => {} + recv(&&&&r) -> _ => {} + } + select! { + recv(Some(&r).unwrap_or(&never())) -> _ => {}, + default => {} + } + select! { + recv(Some(r).unwrap_or(never())) -> _ => {}, + default => {} + } +} + +#[test] +fn case_blocks() { + let (s, r) = unbounded::(); + + select! { + recv(r) -> _ => 3.0, + recv(r) -> _ => loop { + unreachable!() + }, + recv(r) -> _ => match 7 + 3 { + _ => unreachable!() + }, + default => 7. + }; + + select! { + recv(r) -> msg => if msg.is_ok() { + unreachable!() + }, + default => () + } + + drop(s); +} + +#[test] +fn move_handles() { + let (s, r) = unbounded::(); + select! { + recv((move || r)()) -> _ => {} + send((move || s)(), 0) -> _ => {} + } +} + +#[test] +fn infer_types() { + let (s, r) = unbounded(); + select! { + recv(r) -> _ => {} + default => {} + } + s.send(()).unwrap(); + + let (s, r) = unbounded(); + select! { + send(s, ()) -> _ => {} + } + r.recv().unwrap(); +} + +#[test] +fn default_syntax() { + let (s, r) = bounded::(0); + + select! { + recv(r) -> _ => panic!(), + default => {} + } + select! { + send(s, 0) -> _ => panic!(), + default() => {} + } + select! { + default => {} + } + select! { + default() => {} + } +} + +#[test] +fn same_variable_name() { + let (_, r) = unbounded::(); + select! { + recv(r) -> r => assert!(r.is_err()), + } +} + +#[test] +fn handles_on_heap() { + let (s, r) = unbounded::(); + let (s, r) = (Box::new(s), Box::new(r)); + + select! { + send(*s, 0) -> _ => {} + recv(*r) -> _ => {} + default => {} + } + + drop(s); + drop(r); +} + +#[test] +fn once_blocks() { + let (s, r) = unbounded::(); + + let once = Box::new(()); + select! { + send(s, 0) -> _ => drop(once), + } + + let once = Box::new(()); + select! { + recv(r) -> _ => drop(once), + } + + let once1 = Box::new(()); + let once2 = Box::new(()); + select! { + send(s, 0) -> _ => drop(once1), + default => drop(once2), + } + + let once1 = Box::new(()); + let once2 = Box::new(()); + select! { + recv(r) -> _ => drop(once1), + default => drop(once2), + } + + let once1 = Box::new(()); + let once2 = Box::new(()); + select! { + recv(r) -> _ => drop(once1), + send(s, 0) -> _ => drop(once2), + } +} + +#[test] +fn once_receiver() { + let (_, r) = unbounded::(); + + let once = Box::new(()); + let get = move || { + drop(once); + r + }; + + select! { + recv(get()) -> _ => {} + } +} + +#[test] +fn once_sender() { + let (s, _) = unbounded::(); + + let once = Box::new(()); + let get = move || { + drop(once); + s + }; + + select! { + send(get(), 5) -> _ => {} + } +} + +#[test] +fn parse_nesting() { + let (_, r) = unbounded::(); + + select! { + recv(r) -> _ => {} + recv(r) -> _ => { + select! { + recv(r) -> _ => {} + recv(r) -> _ => { + select! { + recv(r) -> _ => {} + recv(r) -> _ => { + select! { + default => {} + } + } + } + } + } + } + } +} + +#[test] +fn evaluate() { + let (s, r) = unbounded::(); + + let v = select! { + recv(r) -> _ => "foo".into(), + send(s, 0) -> _ => "bar".to_owned(), + default => "baz".to_string(), + }; + assert_eq!(v, "bar"); + + let v = select! { + recv(r) -> _ => "foo".into(), + default => "baz".to_string(), + }; + assert_eq!(v, "foo"); + + let v = select! { + recv(r) -> _ => "foo".into(), + default => "baz".to_string(), + }; + assert_eq!(v, "baz"); +} + +#[test] +fn deref() { + use crossbeam_channel as cc; + + struct Sender(cc::Sender); + struct Receiver(cc::Receiver); + + impl Deref for Receiver { + type Target = cc::Receiver; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl Deref for Sender { + type Target = cc::Sender; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + let (s, r) = bounded::(0); + let (s, r) = (Sender(s), Receiver(r)); + + select! { + send(s, 0) -> _ => panic!(), + recv(r) -> _ => panic!(), + default => {} + } +} + +#[test] +fn result_types() { + let (s, _) = bounded::(0); + let (_, r) = bounded::(0); + + select! { + recv(r) -> res => drop::>(res), + } + select! { + recv(r) -> res => drop::>(res), + default => {} + } + select! { + recv(r) -> res => drop::>(res), + default(ms(0)) => {} + } + + select! { + send(s, 0) -> res => drop::>>(res), + } + select! { + send(s, 0) -> res => drop::>>(res), + default => {} + } + select! { + send(s, 0) -> res => drop::>>(res), + default(ms(0)) => {} + } + + select! { + send(s, 0) -> res => drop::>>(res), + recv(r) -> res => drop::>(res), + } +} + +#[test] +fn try_recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> _ => panic!(), + default => {} + } + thread::sleep(ms(1500)); + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + default => panic!(), + } + thread::sleep(ms(500)); + select! { + recv(r) -> v => assert_eq!(v, Err(RecvError)), + default => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + select! { + send(s, 7) -> res => res.unwrap(), + } + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + } + thread::sleep(ms(1000)); + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + thread::sleep(ms(1000)); + select! { + recv(r) -> v => assert_eq!(v, Ok(9)), + } + select! { + recv(r) -> v => assert_eq!(v, Err(RecvError)), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + send(s, 7) -> res => res.unwrap(), + } + select! { + send(s, 8) -> res => res.unwrap(), + } + select! { + send(s, 9) -> res => res.unwrap(), + } + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> _ => panic!(), + default(ms(1000)) => {} + } + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + default(ms(1000)) => panic!(), + } + select! { + recv(r) -> v => assert_eq!(v, Err(RecvError)), + default(ms(1000)) => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + send(s, 7) -> res => res.unwrap(), + } + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, 7) -> _ => panic!(), + default => {} + } + thread::sleep(ms(1500)); + select! { + send(s, 8) -> res => res.unwrap(), + default => panic!(), + } + thread::sleep(ms(500)); + select! { + send(s, 8) -> res => assert_eq!(res, Err(SendError(8))), + default => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + }); + }) + .unwrap(); +} + +#[test] +fn send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, 7) -> res => res.unwrap(), + } + thread::sleep(ms(1000)); + select! { + send(s, 8) -> res => res.unwrap(), + } + thread::sleep(ms(1000)); + select! { + send(s, 9) -> res => res.unwrap(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + } + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + select! { + recv(r) -> v => assert_eq!(v, Ok(9)), + } + }); + }) + .unwrap(); +} + +#[test] +fn send_timeout() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, 7) -> _ => panic!(), + default(ms(1000)) => {} + } + select! { + send(s, 8) -> res => res.unwrap(), + default(ms(1000)) => panic!(), + } + select! { + send(s, 9) -> res => assert_eq!(res, Err(SendError(9))), + default(ms(1000)) => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_sender() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, ()) -> res => assert_eq!(res, Err(SendError(()))), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(r); + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> res => assert_eq!(res, Err(RecvError)), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/thread_locals.rs b/vendor/crossbeam-channel/tests/thread_locals.rs new file mode 100644 index 0000000000..fd319c7284 --- /dev/null +++ b/vendor/crossbeam-channel/tests/thread_locals.rs @@ -0,0 +1,55 @@ +//! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use std::thread; +use std::time::Duration; + +use crossbeam_channel::unbounded; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +#[cfg_attr(target_os = "macos", ignore = "TLS is destroyed too early on macOS")] +fn use_while_exiting() { + struct Foo; + + impl Drop for Foo { + fn drop(&mut self) { + // A blocking operation after the thread-locals have been dropped. This will attempt to + // use the thread-locals and must not panic. + let (_s, r) = unbounded::<()>(); + select! { + recv(r) -> _ => {} + default(ms(100)) => {} + } + } + } + + thread_local! { + static FOO: Foo = Foo; + } + + let (s, r) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(|_| { + // First initialize `FOO`, then the thread-locals related to crossbeam-channel. + FOO.with(|_| ()); + r.recv().unwrap(); + // At thread exit, thread-locals related to crossbeam-channel get dropped first and + // `FOO` is dropped last. + }); + + scope.spawn(|_| { + thread::sleep(ms(100)); + s.send(()).unwrap(); + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/tick.rs b/vendor/crossbeam-channel/tests/tick.rs new file mode 100644 index 0000000000..34e55b31bf --- /dev/null +++ b/vendor/crossbeam-channel/tests/tick.rs @@ -0,0 +1,353 @@ +//! Tests for the tick channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, tick, Select, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn fire() { + let start = Instant::now(); + let r = tick(ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(100)); + + let fired = r.try_recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired >= ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + + select! { + recv(r) -> _ => panic!(), + default => {} + } + + select! { + recv(r) -> _ => {} + recv(tick(ms(200))) -> _ => panic!(), + } +} + +#[test] +fn intervals() { + let start = Instant::now(); + let r = tick(ms(50)); + + let t1 = r.recv().unwrap(); + assert!(start + ms(50) <= t1); + assert!(start + ms(100) > t1); + + thread::sleep(ms(300)); + let t2 = r.try_recv().unwrap(); + assert!(start + ms(100) <= t2); + assert!(start + ms(150) > t2); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + let t3 = r.recv().unwrap(); + assert!(start + ms(400) <= t3); + assert!(start + ms(450) > t3); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn capacity() { + const COUNT: usize = 10; + + for i in 0..COUNT { + let r = tick(ms(i as u64)); + assert_eq!(r.capacity(), Some(1)); + } +} + +#[test] +fn len_empty_full() { + let r = tick(ms(50)); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + thread::sleep(ms(100)); + + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), true); + + r.try_recv().unwrap(); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let r = tick(ms(200)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(100)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_ok()); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_ok()); + assert!(r.try_recv().is_err()); +} + +#[test] +fn recv() { + let start = Instant::now(); + let r = tick(ms(50)); + + let fired = r.recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired < fired - start); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn recv_timeout() { + let start = Instant::now(); + let r = tick(ms(200)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(100)); + assert!(now - start <= ms(150)); + + let fired = r.recv_timeout(ms(200)).unwrap(); + assert!(fired - start >= ms(200)); + assert!(fired - start <= ms(250)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(300)); + assert!(now - start <= ms(350)); + + let fired = r.recv_timeout(ms(200)).unwrap(); + assert!(fired - start >= ms(400)); + assert!(fired - start <= ms(450)); +} + +#[test] +fn recv_two() { + let r1 = tick(ms(50)); + let r2 = tick(ms(50)); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..10 { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + } + }); + scope.spawn(|_| { + for _ in 0..10 { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + } + }); + }) + .unwrap(); +} + +#[test] +fn recv_race() { + select! { + recv(tick(ms(50))) -> _ => {} + recv(tick(ms(100))) -> _ => panic!(), + } + + select! { + recv(tick(ms(100))) -> _ => panic!(), + recv(tick(ms(50))) -> _ => {} + } +} + +#[test] +fn stress_default() { + const COUNT: usize = 10; + + for _ in 0..COUNT { + select! { + recv(tick(ms(0))) -> _ => {} + default => panic!(), + } + } + + for _ in 0..COUNT { + select! { + recv(tick(ms(100))) -> _ => panic!(), + default => {} + } + } +} + +#[test] +fn select() { + const THREADS: usize = 4; + + let hits = AtomicUsize::new(0); + let r1 = tick(ms(200)); + let r2 = tick(ms(300)); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let timeout = after(ms(1100)); + loop { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&timeout); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + oper.recv(&r1).unwrap(); + hits.fetch_add(1, Ordering::SeqCst); + } + i if i == oper2 => { + oper.recv(&r2).unwrap(); + hits.fetch_add(1, Ordering::SeqCst); + } + i if i == oper3 => { + oper.recv(&timeout).unwrap(); + break; + } + _ => unreachable!(), + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), 8); +} + +#[test] +fn ready() { + const THREADS: usize = 4; + + let hits = AtomicUsize::new(0); + let r1 = tick(ms(200)); + let r2 = tick(ms(300)); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let timeout = after(ms(1100)); + 'outer: loop { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&timeout); + loop { + match sel.ready() { + 0 => { + if r1.try_recv().is_ok() { + hits.fetch_add(1, Ordering::SeqCst); + break; + } + } + 1 => { + if r2.try_recv().is_ok() { + hits.fetch_add(1, Ordering::SeqCst); + break; + } + } + 2 => { + if timeout.try_recv().is_ok() { + break 'outer; + } + } + _ => unreachable!(), + } + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), 8); +} + +#[test] +fn fairness() { + const COUNT: usize = 30; + + for &dur in &[0, 1] { + let mut hits = [0usize; 2]; + + for _ in 0..COUNT { + let r1 = tick(ms(dur)); + let r2 = tick(ms(dur)); + + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 30; + + for &dur in &[0, 1] { + let mut hits = [0usize; 5]; + + for _ in 0..COUNT { + let r = tick(ms(dur)); + + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} diff --git a/vendor/crossbeam-channel/tests/zero.rs b/vendor/crossbeam-channel/tests/zero.rs new file mode 100644 index 0000000000..bd336ee157 --- /dev/null +++ b/vendor/crossbeam-channel/tests/zero.rs @@ -0,0 +1,559 @@ +//! Tests for the zero channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{bounded, Receiver}; +use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; +use crossbeam_channel::{SendError, SendTimeoutError, TrySendError}; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + let (s, r) = bounded(0); + assert_eq!(s.try_send(7), Err(TrySendError::Full(7))); + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn capacity() { + let (s, r) = bounded::<()>(0); + assert_eq!(s.capacity(), Some(0)); + assert_eq!(r.capacity(), Some(0)); +} + +#[test] +fn len_empty_full() { + let (s, r) = bounded(0); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), true); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), true); + + scope(|scope| { + scope.spawn(|_| s.send(0).unwrap()); + scope.spawn(|_| r.recv().unwrap()); + }) + .unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), true); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), true); +} + +#[test] +fn try_recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(1500)); + assert_eq!(r.try_recv(), Ok(7)); + thread::sleep(ms(500)); + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Ok(7)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(9)); + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + s.send(8).unwrap(); + s.send(9).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); + assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); + assert_eq!( + r.recv_timeout(ms(1000)), + Err(RecvTimeoutError::Disconnected) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.try_send(7), Err(TrySendError::Full(7))); + thread::sleep(ms(1500)); + assert_eq!(s.try_send(8), Ok(())); + thread::sleep(ms(500)); + assert_eq!(s.try_send(9), Err(TrySendError::Disconnected(9))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + }); + }) + .unwrap(); +} + +#[test] +fn send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + s.send(7).unwrap(); + thread::sleep(ms(1000)); + s.send(8).unwrap(); + thread::sleep(ms(1000)); + s.send(9).unwrap(); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + assert_eq!(r.recv(), Ok(7)); + assert_eq!(r.recv(), Ok(8)); + assert_eq!(r.recv(), Ok(9)); + }); + }) + .unwrap(); +} + +#[test] +fn send_timeout() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!( + s.send_timeout(7, ms(1000)), + Err(SendTimeoutError::Timeout(7)) + ); + assert_eq!(s.send_timeout(8, ms(1000)), Ok(())); + assert_eq!( + s.send_timeout(9, ms(1000)), + Err(SendTimeoutError::Disconnected(9)) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + assert_eq!(r.recv(), Ok(8)); + }); + }) + .unwrap(); +} + +#[test] +fn len() { + const COUNT: usize = 25_000; + + let (s, r) = bounded(0); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + assert_eq!(r.len(), 0); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + assert_eq!(s.len(), 0); + } + }); + }) + .unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); +} + +#[test] +fn disconnect_wakes_sender() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.send(()), Err(SendError(()))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(r); + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + } + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = bounded::(0); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = r.recv().unwrap(); + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + } + }) + .unwrap(); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn stress_oneshot() { + const COUNT: usize = 10_000; + + for _ in 0..COUNT { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(|_| r.recv().unwrap()); + scope.spawn(|_| s.send(0).unwrap()); + }) + .unwrap(); + } +} + +#[test] +fn stress_iter() { + const COUNT: usize = 1000; + + let (request_s, request_r) = bounded(0); + let (response_s, response_r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == COUNT { + return; + } + } + let _ = request_s.try_send(()); + } + }); + + for _ in request_r.iter() { + if response_s.send(1).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 100; + + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(()) = s.send_timeout(i, ms(10)) { + break; + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(x) = r.recv_timeout(ms(10)) { + assert_eq!(x, i); + break; + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn drops() { + 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..100 { + let steps = rng.gen_range(0, 3_000); + + DROPS.store(0, Ordering::SeqCst); + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + r.recv().unwrap(); + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + s.send(DropCounter).unwrap(); + } + }); + }) + .unwrap(); + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(s); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + } +} + +#[test] +fn fairness() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(0); + let (s2, r2) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }); + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + send(s1, ()) -> _ => hits[0] += 1, + send(s2, ()) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }) + .unwrap(); +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 10_000; + + let (s, r) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }); + + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + send(s, ()) -> _ => hits[0] += 1, + send(s, ()) -> _ => hits[1] += 1, + send(s, ()) -> _ => hits[2] += 1, + send(s, ()) -> _ => hits[3] += 1, + send(s, ()) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }) + .unwrap(); +} + +#[test] +fn recv_in_send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(100)); + r.recv() + }); + + scope.spawn(|_| { + thread::sleep(ms(500)); + s.send(()).unwrap(); + }); + + select! { + send(s, r.recv().unwrap()) -> _ => {} + } + }) + .unwrap(); +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(0); + let new_r: T = Box::new(Some(new_r)); + + s.send(new_r).unwrap(); + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = r + .recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-queue/.cargo-checksum.json b/vendor/crossbeam-queue/.cargo-checksum.json deleted file mode 100644 index b0d2114fcc..0000000000 --- a/vendor/crossbeam-queue/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"fd132a0c0418817ad83e67f46762a13e8c210ce6e94293abfa902361d99b953d","Cargo.toml":"49f1e746f6258de6e2b2127cd974a54735b08d565068b4079378a68eb73a5946","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"abb1905b1c2b7db73902e6c328d332d82f3797d7fab61e6fc1c2fc366b132014","README.md":"b487d2d9d9cf9726fbf3b5cf736ddc363f8d1e1410a0a4020dda27c4df72c627","src/array_queue.rs":"02d3deea53652d6fadba3bb4236324262776242176f487688dcf624b379ad500","src/err.rs":"cde063a29dc8887d4c3bd0994f7aab08879841d94c61ecf104a8a85f2c436302","src/lib.rs":"a1331aa4f2d67b4e634667f225c63d55b234802bd1ff72a485d2d56a08eab521","src/seg_queue.rs":"732b5b032313329e39d9c08cf6e63d2926950d645467983fc62e7cabb3cbe330","tests/array_queue.rs":"3faa35bbe2acb3dabdfab5e81860a19e0237c57513420bbb9afe0cb89ac25909","tests/seg_queue.rs":"885ea52ce2c5d1fa9b4265250957d51ffa3f0781d57b01d28cb871371e32ac92"},"package":"774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"} \ 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 e44d1f9a40..0000000000 --- a/vendor/crossbeam-queue/CHANGELOG.md +++ /dev/null @@ -1,28 +0,0 @@ -# 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/LICENSE-THIRD-PARTY b/vendor/crossbeam-queue/LICENSE-THIRD-PARTY deleted file mode 100644 index 8914949a8e..0000000000 --- a/vendor/crossbeam-queue/LICENSE-THIRD-PARTY +++ /dev/null @@ -1,31 +0,0 @@ -=============================================================================== - -Bounded MPMC queue -http://www.1024cores.net/home/code-license - -Copyright (c) 2010-2011 Dmitry Vyukov. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of Dmitry Vyukov. diff --git a/vendor/crossbeam-queue/README.md b/vendor/crossbeam-queue/README.md deleted file mode 100644 index 646f9cfaad..0000000000 --- a/vendor/crossbeam-queue/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Crossbeam Queue - -[![Build Status](https://travis-ci.org/crossbeam-rs/crossbeam.svg?branch=master)]( -https://travis-ci.org/crossbeam-rs/crossbeam) -[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam-queue/tree/master/src) -[![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.28+](https://img.shields.io/badge/rust-1.28+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) - -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. - -[`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.2" -``` - -Next, add this to your crate: - -```rust -extern crate crossbeam_queue; -``` - -## Compatibility - -The minimum supported Rust version is 1.28. Any change to this is considered a breaking change. - -## 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. - -#### Third party software - -This product includes copies and modifications of software developed by third parties: - -* [src/array_queue.rs](src/array_queue.rs) is based on - [Bounded MPMC queue](http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue) - by Dmitry Vyukov, licensed under the Simplified BSD License and the Apache License, Version 2.0. - -See the source code files for more details. - -Copies of third party licenses can be found in [LICENSE-THIRD-PARTY](LICENSE-THIRD-PARTY). diff --git a/vendor/crossbeam-queue/src/array_queue.rs b/vendor/crossbeam-queue/src/array_queue.rs deleted file mode 100644 index 45b055abde..0000000000 --- a/vendor/crossbeam-queue/src/array_queue.rs +++ /dev/null @@ -1,440 +0,0 @@ -//! The implementation is based on Dmitry Vyukov's bounded MPMC queue. -//! -//! Source: -//! - http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue -//! -//! Copyright & License: -//! - Copyright (c) 2010-2011 Dmitry Vyukov -//! - Simplified BSD License and Apache License, Version 2.0 -//! - http://www.1024cores.net/home/code-license - -use alloc::vec::Vec; -use core::cell::UnsafeCell; -use core::fmt; -use core::marker::PhantomData; -use core::mem; -use core::ptr; -use core::sync::atomic::{self, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -use maybe_uninit::MaybeUninit; - -use err::{PopError, PushError}; - -/// 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. Having a buffer allocated upfront makes this queue a bit -/// faster than [`SegQueue`]. -/// -/// [`SegQueue`]: struct.SegQueue.html -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::{ArrayQueue, PushError}; -/// -/// let q = ArrayQueue::new(2); -/// -/// assert_eq!(q.push('a'), Ok(())); -/// assert_eq!(q.push('b'), Ok(())); -/// assert_eq!(q.push('c'), Err(PushError('c'))); -/// assert_eq!(q.pop(), Ok('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: *mut Slot, - - /// The queue capacity. - cap: usize, - - /// A stamp with the value of `{ lap: 1, index: 0 }`. - one_lap: usize, - - /// Indicates that dropping an `ArrayQueue` may drop elements of type `T`. - _marker: PhantomData, -} - -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. - let buffer = { - let mut v = Vec::>::with_capacity(cap); - let ptr = v.as_mut_ptr(); - mem::forget(v); - ptr - }; - - // Initialize stamps in the slots. - for i in 0..cap { - unsafe { - // Set the stamp to `{ lap: 0, index: i }`. - let slot = buffer.add(i); - ptr::write(&mut (*slot).stamp, AtomicUsize::new(i)); - } - } - - // 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)), - _marker: PhantomData, - } - } - - /// 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, PushError}; - /// - /// let q = ArrayQueue::new(1); - /// - /// assert_eq!(q.push(10), Ok(())); - /// assert_eq!(q.push(20), Err(PushError(20))); - /// ``` - pub fn push(&self, value: T) -> Result<(), PushError> { - 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); - - // Inspect the corresponding slot. - let slot = unsafe { &*self.buffer.add(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); - - // If the tail and the stamp match, we may attempt to push. - if tail == stamp { - let new_tail = if index + 1 < self.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, 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) - }; - - // 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); - 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. - return Err(PushError(value)); - } - - 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 pop an element from the queue. - /// - /// If the queue is empty, an error is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{ArrayQueue, PopError}; - /// - /// let q = ArrayQueue::new(1); - /// assert_eq!(q.push(10), Ok(())); - /// - /// assert_eq!(q.pop(), Ok(10)); - /// assert_eq!(q.pop(), Err(PopError)); - /// ``` - pub fn pop(&self) -> Result { - 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. - let slot = unsafe { &*self.buffer.add(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 Ok(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 Err(PopError); - } - - 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, PopError}; - /// - /// 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, PopError}; - /// - /// 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, PopError}; - /// - /// 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, PopError}; - /// - /// 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 { - let p = { - let slot = &mut *self.buffer.add(index); - let value = &mut *slot.value.get(); - value.as_mut_ptr() - }; - p.drop_in_place(); - } - } - - // Finally, deallocate the buffer, but don't run any destructors. - unsafe { - Vec::from_raw_parts(self.buffer, 0, self.cap); - } - } -} - -impl fmt::Debug for ArrayQueue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("ArrayQueue { .. }") - } -} diff --git a/vendor/crossbeam-queue/src/err.rs b/vendor/crossbeam-queue/src/err.rs deleted file mode 100644 index 42880e89ec..0000000000 --- a/vendor/crossbeam-queue/src/err.rs +++ /dev/null @@ -1,47 +0,0 @@ -use core::fmt; - -/// Error which occurs when popping from an empty queue. -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct PopError; - -impl fmt::Debug for PopError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "PopError".fmt(f) - } -} - -impl fmt::Display for PopError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "popping from an empty queue".fmt(f) - } -} - -#[cfg(features = "std")] -impl std::error::Error for PopError { - fn description(&self) -> &str { - "popping from an empty queue" - } -} - -/// Error which occurs when pushing into a full queue. -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct PushError(pub T); - -impl fmt::Debug for PushError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "PushError(..)".fmt(f) - } -} - -impl fmt::Display for PushError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "pushing into a full queue".fmt(f) - } -} - -#[cfg(features = "std")] -impl std::error::Error for PushError { - fn description(&self) -> &str { - "pushing into a full queue" - } -} diff --git a/vendor/crossbeam-queue/src/lib.rs b/vendor/crossbeam-queue/src/lib.rs deleted file mode 100644 index fd99392070..0000000000 --- a/vendor/crossbeam-queue/src/lib.rs +++ /dev/null @@ -1,42 +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. -//! -//! [`ArrayQueue`]: struct.ArrayQueue.html -//! [`SegQueue`]: struct.SegQueue.html - -#![warn(missing_docs)] -#![warn(missing_debug_implementations)] -#![cfg_attr(not(feature = "std"), no_std)] - -#[macro_use] -extern crate cfg_if; -#[cfg(feature = "std")] -extern crate core; - -extern crate maybe_uninit; - -cfg_if! { - if #[cfg(feature = "alloc")] { - extern crate alloc; - } else if #[cfg(feature = "std")] { - extern crate std as alloc; - } -} - -extern crate crossbeam_utils; - -cfg_if! { - if #[cfg(any(feature = "alloc", feature = "std"))] { - mod array_queue; - mod err; - mod seg_queue; - - pub use self::array_queue::ArrayQueue; - pub use self::err::{PopError, PushError}; - 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 b52da4f5c0..0000000000 --- a/vendor/crossbeam-queue/src/seg_queue.rs +++ /dev/null @@ -1,490 +0,0 @@ -use alloc::boxed::Box; -use core::cell::UnsafeCell; -use core::fmt; -use core::marker::PhantomData; -use core::ptr; -use core::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -use maybe_uninit::MaybeUninit; - -use err::PopError; - -// 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`]: struct.ArrayQueue.html -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::{PopError, SegQueue}; -/// -/// let q = SegQueue::new(); -/// -/// q.push('a'); -/// q.push('b'); -/// -/// assert_eq!(q.pop(), Ok('a')); -/// assert_eq!(q.pop(), Ok('b')); -/// assert_eq!(q.pop(), Err(PopError)); -/// ``` -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 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_and_swap(block, new, Ordering::Release) - == block - { - 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, an error is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{PopError, SegQueue}; - /// - /// let q = SegQueue::new(); - /// - /// q.push(10); - /// assert_eq!(q.pop(), Ok(10)); - /// assert_eq!(q.pop(), Err(PopError)); - /// ``` - pub fn pop(&self) -> Result { - 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 Err(PopError); - } - - // 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 Ok(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, PopError}; - /// - /// 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); - - // 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; - - // Fix up indices if they fall onto block ends. - if head == BLOCK_CAP { - head = 0; - tail -= LAP; - } - if tail == BLOCK_CAP { - tail += 1; - } - - // 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() - } -} diff --git a/vendor/crossbeam-queue/tests/array_queue.rs b/vendor/crossbeam-queue/tests/array_queue.rs deleted file mode 100644 index a4f64f3432..0000000000 --- a/vendor/crossbeam-queue/tests/array_queue.rs +++ /dev/null @@ -1,254 +0,0 @@ -extern crate crossbeam_queue; -extern crate crossbeam_utils; -extern crate rand; - -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(), Ok(7)); - - q.push(8).unwrap(); - assert_eq!(q.pop(), Ok(8)); - assert!(q.pop().is_err()); -} - -#[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_eq!(q.is_empty(), true); - assert_eq!(q.is_full(), false); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 1); - assert_eq!(q.is_empty(), false); - assert_eq!(q.is_full(), false); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 2); - assert_eq!(q.is_empty(), false); - assert_eq!(q.is_full(), true); - - q.pop().unwrap(); - - assert_eq!(q.len(), 1); - assert_eq!(q.is_empty(), false); - assert_eq!(q.is_full(), false); -} - -#[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 Ok(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); -} - -#[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 Ok(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_err()); - }); - - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - } - }); - }) - .unwrap(); -} - -#[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 Ok(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); - } -} - -#[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_err() {} - } - }); - - 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() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = ArrayQueue::new(THREADS); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - while q.push(0).is_err() {} - q.pop().unwrap(); - } - }); - } - }) - .unwrap(); -} diff --git a/vendor/crossbeam-queue/tests/seg_queue.rs b/vendor/crossbeam-queue/tests/seg_queue.rs deleted file mode 100644 index ec32e1f642..0000000000 --- a/vendor/crossbeam-queue/tests/seg_queue.rs +++ /dev/null @@ -1,167 +0,0 @@ -extern crate crossbeam_queue; -extern crate crossbeam_utils; -extern crate rand; - -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(), Ok(7)); - - q.push(8); - assert_eq!(q.pop(), Ok(8)); - assert!(q.pop().is_err()); -} - -#[test] -fn len_empty_full() { - let q = SegQueue::new(); - - assert_eq!(q.len(), 0); - assert_eq!(q.is_empty(), true); - - q.push(()); - - assert_eq!(q.len(), 1); - assert_eq!(q.is_empty(), false); - - q.pop().unwrap(); - - assert_eq!(q.len(), 0); - assert_eq!(q.is_empty(), true); -} - -#[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); -} - -#[test] -fn spsc() { - const COUNT: usize = 100_000; - - let q = SegQueue::new(); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Ok(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_err()); - }); - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - }) - .unwrap(); -} - -#[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 Ok(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); - } -} - -#[test] -fn drops() { - 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..100 { - 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_err() {} - } - }); - - 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); - } -} diff --git a/vendor/digest-0.8.1/.cargo-checksum.json b/vendor/digest-0.8.1/.cargo-checksum.json new file mode 100644 index 0000000000..ed59510b23 --- /dev/null +++ b/vendor/digest-0.8.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"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 new file mode 100644 index 0000000000..d363007695 --- /dev/null +++ b/vendor/digest-0.8.1/Cargo.toml @@ -0,0 +1,36 @@ +# 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 new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/digest-0.8.1/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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/parking_lot_core-0.7.2/LICENSE-MIT b/vendor/digest-0.8.1/LICENSE-MIT similarity index 95% rename from vendor/parking_lot_core-0.7.2/LICENSE-MIT rename to vendor/digest-0.8.1/LICENSE-MIT index 40b8817a47..8dcb85b302 100644 --- a/vendor/parking_lot_core-0.7.2/LICENSE-MIT +++ b/vendor/digest-0.8.1/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2016 The Rust Project Developers +Copyright (c) 2017 Artyom Pavlov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/vendor/digest-0.8.1/src/dev.rs b/vendor/digest-0.8.1/src/dev.rs new file mode 100644 index 0000000000..e9950ee799 --- /dev/null +++ b/vendor/digest-0.8.1/src/dev.rs @@ -0,0 +1,218 @@ +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 new file mode 100644 index 0000000000..50128e13ec --- /dev/null +++ b/vendor/digest-0.8.1/src/digest.rs @@ -0,0 +1,86 @@ +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 new file mode 100644 index 0000000000..2af43a8e3d --- /dev/null +++ b/vendor/digest-0.8.1/src/dyn_digest.rs @@ -0,0 +1,63 @@ +#![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 new file mode 100644 index 0000000000..aa026a21a1 --- /dev/null +++ b/vendor/digest-0.8.1/src/errors.rs @@ -0,0 +1,20 @@ +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 new file mode 100644 index 0000000000..f03c501076 --- /dev/null +++ b/vendor/digest-0.8.1/src/lib.rs @@ -0,0 +1,141 @@ +//! 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/digest/.cargo-checksum.json b/vendor/digest/.cargo-checksum.json index ed59510b23..00bfd169d8 100644 --- a/vendor/digest/.cargo-checksum.json +++ b/vendor/digest/.cargo-checksum.json @@ -1 +1 @@ -{"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 +{"files":{"CHANGELOG.md":"dc6fb3107d31625c783c08064beae3169506996d4a8680543d220f63b235dfed","Cargo.toml":"10e467adec4f2b31ef4d9b65aaf16e4724ccafcc9631660406e4ab225c15014d","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","README.md":"b09a5f742c7bbba7fa2ce9d38a4584ad88e9ff835b18563d27daedb234142667","src/dev.rs":"1a57f754b3fdaaef5f2f6f8b89cc4c426b16830d57398d4b2e170094304424a6","src/digest.rs":"3155f2b42578b759da226efb51c92acec99eeee4b293c33e83c63c4b62492f7c","src/dyn_digest.rs":"ce6100ee4af7c785dc257c86fd1c2f08a8d096d520164ee5a993500fc19dd211","src/errors.rs":"b8412605e73c8d75e128ced82bbd2b02691d40d93c5436271307a2e74c5cbf66","src/fixed.rs":"06d144dec57157ad89e7c36fbf9494d9a597eadcf98006cfbf4599ddd3ab9b08","src/lib.rs":"dc5fdf8ea8a5cfcb2c2fdbc412cd8bf9aec58af4f274e3788f86eea5f755688f","src/variable.rs":"6aaa3fd4409ca9aeada08246d0bb535c66d26bc09ce2ca6b7eddf460456e9157","src/xof.rs":"53032d946352b74b74e6a8f7b11df3e45985438701e7e7621fe563008eb3c627"},"package":"d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"} \ No newline at end of file diff --git a/vendor/digest/CHANGELOG.md b/vendor/digest/CHANGELOG.md new file mode 100644 index 0000000000..03f0ad387c --- /dev/null +++ b/vendor/digest/CHANGELOG.md @@ -0,0 +1,78 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +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). + +## 0.9.0 (2020-06-09) +### Added +- `ExtendableOutputDirty` and `VariableOutputDirty` traits ([#183]) +- `FixedOutputDirty` trait + `finalize_into*` ([#180]) +- `XofReader::read_boxed` method ([#178], [#181], [#182]) +- `alloc` feature ([#163]) +- Re-export `typenum::consts` as `consts` ([#123]) +- `Output` type alias ([#115]) + +### Changed +- Rename `*result*` methods to `finalize` ala IUF ([#161]) +- Use `impl AsRef<[u8]>` instead of generic params on methods ([#112]) +- Rename `Input::input` to `Update::update` ala IUF ([#111]) +- Upgrade to Rust 2018 edition ([#109]) +- Bump `generic-array` to v0.14 ([#95]) + +[#183]: https://github.com/RustCrypto/traits/pull/183 +[#181]: https://github.com/RustCrypto/traits/pull/181 +[#182]: https://github.com/RustCrypto/traits/pull/182 +[#180]: https://github.com/RustCrypto/traits/pull/180 +[#178]: https://github.com/RustCrypto/traits/pull/178 +[#163]: https://github.com/RustCrypto/traits/pull/163 +[#161]: https://github.com/RustCrypto/traits/pull/161 +[#123]: https://github.com/RustCrypto/traits/pull/123 +[#115]: https://github.com/RustCrypto/traits/pull/115 +[#111]: https://github.com/RustCrypto/traits/pull/111 +[#112]: https://github.com/RustCrypto/traits/pull/112 +[#109]: https://github.com/RustCrypto/traits/pull/109 +[#95]: https://github.com/RustCrypto/traits/pull/95 + +## 0.8.1 (2019-06-30) + +## 0.8.0 (2018-10-01) + +## 0.7.6 (2018-09-21) + +## 0.7.5 (2018-07-13) + +## 0.7.4 (2018-06-21) + +## 0.7.3 (2018-06-20) + +## 0.7.2 (2017-11-17) + +## 0.7.1 (2017-11-15) + +## 0.7.0 (2017-11-14) + +## 0.6.2 (2017-07-24) + +## 0.6.1 (2017-06-18) + +## 0.6.0 (2017-06-12) + +## 0.5.2 (2017-05-02) + +## 0.5.1 (2017-05-02) + +## 0.5.0 (2017-04-06) + +## 0.4.0 (2016-12-24) + +## 0.3.1 (2016-12-16) + +## 0.3.0 (2016-11-17) + +## 0.2.1 (2016-10-14) + +## 0.2.0 (2016-10-14) + +## 0.1.0 (2016-10-06) diff --git a/vendor/digest/Cargo.toml b/vendor/digest/Cargo.toml index d363007695..83c818ce6c 100644 --- a/vendor/digest/Cargo.toml +++ b/vendor/digest/Cargo.toml @@ -11,26 +11,28 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "digest" -version = "0.8.1" +version = "0.9.0" authors = ["RustCrypto Developers"] description = "Traits for cryptographic hash functions" documentation = "https://docs.rs/digest" +readme = "README.md" 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"] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] [dependencies.blobby] version = "0.1" optional = true [dependencies.generic-array] -version = "0.12" +version = "0.14" [features] +alloc = [] dev = ["blobby"] -std = [] -[badges.travis-ci] -repository = "RustCrypto/traits" +std = ["alloc"] diff --git a/vendor/digest/README.md b/vendor/digest/README.md new file mode 100644 index 0000000000..e68638771e --- /dev/null +++ b/vendor/digest/README.md @@ -0,0 +1,161 @@ +# RustCrypto: Digest Algorithm Traits + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Build Status][build-image]][build-link] + +Traits which describe functionality of [cryptographic hash functions][0], a.k.a. +digest algorithms. + +See [RustCrypto/hashes][1] for implementations which use this trait. + +[Documentation][docs-link] + +## Minimum Supported Rust Version + +Rust **1.41** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## Usage + +Let us demonstrate how to use crates in this repository using BLAKE2b as an +example. + +First add `blake2` crate to your `Cargo.toml`: + +```toml +[dependencies] +blake2 = "0.8" +``` + +`blake2` and other crates re-export `digest` crate and `Digest` trait for +convenience, so you don't have to add `digest` crate as an explicit dependency. + +Now you can write the following code: + +```rust +use blake2::{Blake2b, Digest}; + +let mut hasher = Blake2b::new(); +let data = b"Hello world!"; +hasher.input(data); +// `input` can be called repeatedly and is generic over `AsRef<[u8]>` +hasher.input("String data"); +// Note that calling `finalize()` consumes hasher +let hash = hasher.finalize(); +println!("Result: {:x}", hash); +``` + +In this example `hash` has type [`GenericArray`][2], which is a generic +alternative to `[u8; 64]`. + +Alternatively you can use chained approach, which is equivalent to the previous +example: + +```rust +let hash = Blake2b::new() + .chain(b"Hello world!") + .chain("String data") + .finalize(); + +println!("Result: {:x}", hash); +``` + +If the whole message is available you also can use convinience `digest` method: + +```rust +let hash = Blake2b::digest(b"my message"); +println!("Result: {:x}", hash); +``` + +### Hashing `Read`-able objects + +If you want to hash data from [`Read`][3] trait (e.g. from file) you can rely on +implementation of [`Write`][4] trait (requires enabled-by-default `std` feature): + +```rust +use blake2::{Blake2b, Digest}; +use std::{fs, io}; + +let mut file = fs::File::open(&path)?; +let mut hasher = Blake2b::new(); +let n = io::copy(&mut file, &mut hasher)?; +let hash = hasher.finalize(); + +println!("Path: {}", path); +println!("Bytes processed: {}", n); +println!("Hash value: {:x}", hash); +``` + +### Generic code + +You can write generic code over `Digest` (or other traits from `digest` crate) +trait which will work over different hash functions: + +```rust +use digest::Digest; + +// Toy example, do not use it in practice! +// Instead use crates from: https://github.com/RustCrypto/password-hashing +fn hash_password(password: &str, salt: &str, output: &mut [u8]) { + let mut hasher = D::new(); + hasher.input(password.as_bytes()); + hasher.input(b"$"); + hasher.input(salt.as_bytes()); + output.copy_from_slice(hasher.finalize().as_slice()) +} + +use blake2::Blake2b; +use sha2::Sha256; + +hash_password::("my_password", "abcd", &mut buf); +hash_password::("my_password", "abcd", &mut buf); +``` + +If you want to use hash functions with trait objects, use `digest::DynDigest` +trait. + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/digest.svg +[crate-link]: https://crates.io/crates/digest +[docs-image]: https://docs.rs/digest/badge.svg +[docs-link]: https://docs.rs/digest/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[build-image]: https://github.com/RustCrypto/traits/workflows/digest/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/traits/actions?query=workflow%3Adigest + +[//]: # (general links) + +[0]: https://en.wikipedia.org/wiki/Cryptographic_hash_function +[1]: https://github.com/RustCrypto/hashes +[2]: https://docs.rs/generic-array +[3]: https://doc.rust-lang.org/std/io/trait.Read.html +[4]: https://doc.rust-lang.org/std/io/trait.Write.html +[5]: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code +[6]: https://github.com/RustCrypto/MACs diff --git a/vendor/digest/src/dev.rs b/vendor/digest/src/dev.rs index e9950ee799..c205cab439 100644 --- a/vendor/digest/src/dev.rs +++ b/vendor/digest/src/dev.rs @@ -1,50 +1,59 @@ -use super::{Input, VariableOutput, ExtendableOutput, Reset, XofReader}; +//! Development-related functionality + +pub use blobby; + +use super::{ExtendableOutput, Reset, Update, VariableOutput, XofReader}; use core::fmt::Debug; +/// Define test #[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! new_test { ($name:ident, $test_name:expr, $hasher:ty, $test_func:ident) => { #[test] fn $name() { - use digest::blobby::Blob2Iterator; + use digest::dev::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", + panic!( + "\n\ + Failed test №{}: {}\n\ + input:\t{:?}\n\ + output:\t{:?}\n", i, desc, input, output, ); } } } - } + }; } -// module to separate Digest from other traits +/// Module to separate Digest from other traits mod foo { use super::super::Digest; use core::fmt::Debug; + /// Digest test pub fn digest_test(input: &[u8], output: &[u8]) -> Option<&'static str> - where D: Digest + Debug + Clone + where + D: Digest + Debug + Clone, { let mut hasher = D::new(); // Test that it works when accepting the message all at once - hasher.input(input); + hasher.update(input); let mut hasher2 = hasher.clone(); - if hasher.result().as_slice() != output { + if hasher.finalize().as_slice() != output { return Some("whole message"); } // Test if reset works correctly hasher2.reset(); - hasher2.input(input); - if hasher2.result().as_slice() != output { + hasher2.update(input); + if hasher2.finalize().as_slice() != output { return Some("whole message after reset"); } @@ -54,66 +63,72 @@ mod foo { let mut left = len; while left > 0 { let take = (left + 1) / 2; - hasher.input(&input[len - left..take + len - left]); - left = left - take; + hasher.update(&input[len - left..take + len - left]); + left -= take; } - if hasher.result().as_slice() != output { + if hasher.finalize().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) + hasher.update(chunk) } - if hasher.result().as_slice() != output { + if hasher.finalize().as_slice() != output { return Some("message byte-by-byte"); } None } - + /// Compute digest of one million `a` bytes pub fn one_million_a(expected: &[u8]) - where D: Digest + Debug + Clone + where + D: Digest + Debug + Clone, { let mut sh = D::new(); for _ in 0..50_000 { - sh.input(&[b'a'; 10]); + sh.update(&[b'a'; 10]); } - sh.input(&[b'a'; 500_000][..]); - let out = sh.result(); + sh.update(&[b'a'; 500_000][..]); + let out = sh.finalize(); 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 +/// XOF test +pub fn xof_test(input: &[u8], output: &[u8]) -> Option<&'static str> +where + D: Update + 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); + hasher.update(input); let mut hasher2 = hasher.clone(); { let out = &mut buf[..output.len()]; - hasher.xof_result().read(out); + hasher.finalize_xof().read(out); - if out != output { return Some("whole message"); } + if out != output { + return Some("whole message"); + } } // Test if hasher resets correctly hasher2.reset(); - hasher2.input(input); + hasher2.update(input); { let out = &mut buf[..output.len()]; - hasher2.xof_result().read(out); + hasher2.finalize_xof().read(out); - if out != output { return Some("whole message after reset"); } + if out != output { + return Some("whole message after reset"); + } } // Test if hasher accepts message in pieces correctly @@ -122,48 +137,57 @@ pub fn xof_test(input: &[u8], output: &[u8]) let mut left = len; while left > 0 { let take = (left + 1) / 2; - hasher.input(&input[len - left..take + len - left]); - left = left - take; + hasher.update(&input[len - left..take + len - left]); + left -= take; } { let out = &mut buf[..output.len()]; - hasher.xof_result().read(out); - if out != output { return Some("message in pieces"); } + hasher.finalize_xof().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); + hasher.update(input); - let mut reader = hasher.xof_result(); + let mut reader = hasher.finalize_xof(); let out = &mut buf[..output.len()]; for chunk in out.chunks_mut(1) { reader.read(chunk); } - if out != output { return Some("message in pieces"); } + 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 +/// Variable-output digest test +pub fn variable_test(input: &[u8], output: &[u8]) -> Option<&'static str> +where + D: Update + 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); + hasher.update(input); let mut hasher2 = hasher.clone(); - hasher.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("whole message"); } + hasher.finalize_variable(|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"); } + hasher2.update(input); + hasher2.finalize_variable(|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(); @@ -171,24 +195,29 @@ pub fn variable_test(input: &[u8], output: &[u8]) let mut left = len; while left > 0 { let take = (left + 1) / 2; - hasher.input(&input[len - left..take + len - left]); - left = left - take; + hasher.update(&input[len - left..take + len - left]); + left -= take; + } + hasher.finalize_variable(|res| buf.copy_from_slice(res)); + if buf != output { + return Some("message in pieces"); } - 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.update(chunk) + } + hasher.finalize_variable(|res| buf.copy_from_slice(res)); + if buf != output { + return Some("message byte-by-byte"); } - hasher.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("message byte-by-byte"); } None } - +/// Define benchmark #[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! bench { ($name:ident, $engine:path, $bs:expr) => { #[bench] @@ -197,7 +226,7 @@ macro_rules! bench { let data = [0; $bs]; b.iter(|| { - d.input(&data[..]); + d.update(&data[..]); }); b.bytes = $bs; @@ -207,12 +236,12 @@ macro_rules! bench { ($engine:path) => { extern crate test; - use test::Bencher; use digest::Digest; + use test::Bencher; - bench!(bench1_10, $engine, 10); - bench!(bench2_100, $engine, 100); - bench!(bench3_1000, $engine, 1000); - bench!(bench4_10000, $engine, 10000); - } + $crate::bench!(bench1_10, $engine, 10); + $crate::bench!(bench2_100, $engine, 100); + $crate::bench!(bench3_1000, $engine, 1000); + $crate::bench!(bench4_10000, $engine, 10000); + }; } diff --git a/vendor/digest/src/digest.rs b/vendor/digest/src/digest.rs index 50128e13ec..ef72951d8b 100644 --- a/vendor/digest/src/digest.rs +++ b/vendor/digest/src/digest.rs @@ -1,32 +1,36 @@ -use super::{Input, FixedOutput, Reset}; -use generic_array::{GenericArray, ArrayLength}; +use super::{FixedOutput, Reset, Update}; use generic_array::typenum::Unsigned; +use generic_array::{ArrayLength, GenericArray}; /// 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. +/// It's a convenience wrapper around [`Update`], [`FixedOutput`], [`Reset`], +/// [`Clone`], and [`Default`] traits. It also provides additional convenience methods. pub trait Digest { + /// Output size for `Digest` type OutputSize: ArrayLength; + /// Create new hasher instance fn new() -> Self; - /// Digest input data. + /// Digest data, updating the internal state. /// /// This method can be called repeatedly for use with streaming messages. - fn input>(&mut self, data: B); + fn update(&mut self, data: impl AsRef<[u8]>); /// Digest input data in a chained manner. - fn chain>(self, data: B) -> Self where Self: Sized; + fn chain(self, data: impl AsRef<[u8]>) -> Self + where + Self: Sized; /// Retrieve result and consume hasher instance. - fn result(self) -> GenericArray; + fn finalize(self) -> Output; /// Retrieve result and reset hasher instance. /// /// This method sometimes can be more efficient compared to hasher /// re-creation. - fn result_reset(&mut self) -> GenericArray; + fn finalize_reset(&mut self) -> Output; /// Reset hasher instance to its initial state. fn reset(&mut self); @@ -42,30 +46,33 @@ pub trait Digest { /// ```rust,ignore /// println!("{:x}", sha2::Sha256::digest(b"Hello world")); /// ``` - fn digest(data: &[u8]) -> GenericArray; + fn digest(data: &[u8]) -> Output; } -impl Digest for D { +impl Digest for D { type OutputSize = ::OutputSize; fn new() -> Self { Self::default() } - fn input>(&mut self, data: B) { - Input::input(self, data); + fn update(&mut self, data: impl AsRef<[u8]>) { + Update::update(self, data); } - fn chain>(self, data: B) -> Self where Self: Sized { - Input::chain(self, data) + fn chain(self, data: impl AsRef<[u8]>) -> Self + where + Self: Sized, + { + Update::chain(self, data) } - fn result(self) -> GenericArray { - self.fixed_result() + fn finalize(self) -> Output { + self.finalize_fixed() } - fn result_reset(&mut self) -> GenericArray { - let res = self.clone().fixed_result(); + fn finalize_reset(&mut self) -> Output { + let res = self.clone().finalize_fixed(); self.reset(); res } @@ -78,9 +85,12 @@ impl Digest for D { Self::OutputSize::to_usize() } - fn digest(data: &[u8]) -> GenericArray { + fn digest(data: &[u8]) -> Output { let mut hasher = Self::default(); - Input::input(&mut hasher, data); - hasher.fixed_result() + Update::update(&mut hasher, data); + hasher.finalize_fixed() } } + +/// Output of a [`Digest`] function +pub type Output = GenericArray::OutputSize>; diff --git a/vendor/digest/src/dyn_digest.rs b/vendor/digest/src/dyn_digest.rs index 2af43a8e3d..156f9bdbff 100644 --- a/vendor/digest/src/dyn_digest.rs +++ b/vendor/digest/src/dyn_digest.rs @@ -1,22 +1,23 @@ -#![cfg(feature = "std")] -use std::boxed::Box; +#![cfg(feature = "alloc")] +use alloc::boxed::Box; -use super::{Input, FixedOutput, Reset}; +use super::{FixedOutput, Reset, Update}; use generic_array::typenum::Unsigned; /// The `DynDigest` trait is a modification of `Digest` trait suitable /// for trait objects. +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub trait DynDigest { /// Digest input data. /// /// This method can be called repeatedly for use with streaming messages. - fn input(&mut self, data: &[u8]); + fn update(&mut self, data: &[u8]); /// Retrieve result and reset hasher instance - fn result_reset(&mut self) -> Box<[u8]>; + fn finalize_reset(&mut self) -> Box<[u8]>; /// Retrieve result and consume boxed hasher instance - fn result(self: Box) -> Box<[u8]>; + fn finalize(self: Box) -> Box<[u8]>; /// Reset hasher instance to its initial state. fn reset(&mut self); @@ -25,22 +26,22 @@ pub trait DynDigest { fn output_size(&self) -> usize; /// Clone hasher state into a boxed trait object - fn box_clone(&self) -> Box; + fn box_clone(&self) -> Box; } -impl DynDigest for D { - fn input(&mut self, data: &[u8]) { - Input::input(self, data); +impl DynDigest for D { + fn update(&mut self, data: &[u8]) { + Update::update(self, data); } - fn result_reset(&mut self) -> Box<[u8]> { - let res = self.clone().fixed_result().to_vec().into_boxed_slice(); + fn finalize_reset(&mut self) -> Box<[u8]> { + let res = self.finalize_fixed_reset().to_vec().into_boxed_slice(); Reset::reset(self); res } - fn result(self: Box) -> Box<[u8]> { - self.fixed_result().to_vec().into_boxed_slice() + fn finalize(self: Box) -> Box<[u8]> { + self.finalize_fixed().to_vec().into_boxed_slice() } fn reset(&mut self) { @@ -51,12 +52,12 @@ impl DynDigest for D { ::OutputSize::to_usize() } - fn box_clone(&self) -> Box { + fn box_clone(&self) -> Box { Box::new(self.clone()) } } -impl Clone for Box { +impl Clone for Box { fn clone(&self) -> Self { self.box_clone() } diff --git a/vendor/digest/src/errors.rs b/vendor/digest/src/errors.rs index aa026a21a1..6071e456b0 100644 --- a/vendor/digest/src/errors.rs +++ b/vendor/digest/src/errors.rs @@ -1,20 +1,14 @@ 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 { + 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" - } -} +impl std::error::Error for InvalidOutputSize {} diff --git a/vendor/digest/src/fixed.rs b/vendor/digest/src/fixed.rs new file mode 100644 index 0000000000..432a6c42cf --- /dev/null +++ b/vendor/digest/src/fixed.rs @@ -0,0 +1,71 @@ +//! Fixed-size output digest support + +use crate::Reset; +use generic_array::{ArrayLength, GenericArray}; + +/// Trait for returning digest result with the fixed size +pub trait FixedOutput { + /// Output size for fixed output digest + type OutputSize: ArrayLength; + + /// Write result into provided array and consume the hasher instance. + fn finalize_into(self, out: &mut GenericArray); + + /// Write result into provided array and reset the hasher instance. + fn finalize_into_reset(&mut self, out: &mut GenericArray); + + /// Retrieve result and consume the hasher instance. + #[inline] + fn finalize_fixed(self) -> GenericArray + where + Self: Sized, + { + let mut out = Default::default(); + self.finalize_into(&mut out); + out + } + + /// Retrieve result and reset the hasher instance. + #[inline] + fn finalize_fixed_reset(&mut self) -> GenericArray { + let mut out = Default::default(); + self.finalize_into_reset(&mut out); + out + } +} + +/// Trait for fixed-output digest implementations to use to retrieve the +/// hash output. +/// +/// Usage of this trait in user code is discouraged. Instead use the +/// [`FixedOutput::finalize_fixed`] or [`FixedOutput::finalize_fixed_reset`] +/// methods. +/// +/// Types which impl this trait along with [`Reset`] will receive a blanket +/// impl of [`FixedOutput`]. +pub trait FixedOutputDirty { + /// Output size for fixed output digest + type OutputSize: ArrayLength; + + /// Retrieve result into provided buffer and leave hasher in a dirty state. + /// + /// This method is expected to only be called once unless + /// [`Reset::reset`] is called, after which point it can be + /// called again and reset again (and so on). + fn finalize_into_dirty(&mut self, out: &mut GenericArray); +} + +impl FixedOutput for D { + type OutputSize = D::OutputSize; + + #[inline] + fn finalize_into(mut self, out: &mut GenericArray) { + self.finalize_into_dirty(out); + } + + #[inline] + fn finalize_into_reset(&mut self, out: &mut GenericArray) { + self.finalize_into_dirty(out); + self.reset(); + } +} diff --git a/vendor/digest/src/lib.rs b/vendor/digest/src/lib.rs index f03c501076..b049a694d8 100644 --- a/vendor/digest/src/lib.rs +++ b/vendor/digest/src/lib.rs @@ -1,51 +1,77 @@ //! 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. +//! Traits in this repository are organized into high-level convenience traits, +//! mid-level traits which expose more fine-grained functionality, and +//! low-level traits intended to only be used by algorithm implementations: //! -//! Additionally hash functions implement traits from `std`: `Default`, `Clone`, -//! `Write`. (the latter depends on enabled-by-default `std` crate feature) +//! - **High-level convenience traits**: [`Digest`], [`DynDigest`]. They are wrappers +//! around lower-level traits for most common hash-function use-cases. +//! - **Mid-level traits**: [`Update`], [`BlockInput`], [`Reset`], [`FixedOutput`], +//! [`VariableOutput`], [`ExtendableOutput`]. These traits atomically describe +//! available functionality of hash function implementations. +//! - **Low-level traits**: [`FixedOutputDirty`], [`VariableOutputDirty`], +//! [`ExtendableOutputDirty`]. These traits are intended to be implemented by +//! low-level algorithm providers only and simplify the amount of work +//! implementers need to do and therefore shouldn't be used in +//! application-level code. //! -//! The `Digest` trait is the most commonly used trait. +//! Additionally hash functions implement traits from the standard library: +//! `Default`, `Clone`, `Write`. The latter is feature-gated behind `std` feature, +//! which is usually enabled by default by hash implementation crates. +//! +//! 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_attr(docsrs, feature(doc_cfg))] +#![forbid(unsafe_code)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] +#![warn(missing_docs, rust_2018_idioms)] + +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; + #[cfg(feature = "std")] -#[macro_use] extern crate std; +extern crate std; + #[cfg(feature = "dev")] -pub extern crate blobby; -use generic_array::{GenericArray, ArrayLength}; -#[cfg(feature = "std")] -use std::vec::Vec; +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +pub mod dev; mod digest; mod dyn_digest; mod errors; -#[cfg(feature = "dev")] -pub mod dev; - -pub use errors::InvalidOutputSize; -pub use digest::Digest; -#[cfg(feature = "std")] +mod fixed; +mod variable; +mod xof; + +pub use crate::digest::{Digest, Output}; +pub use crate::errors::InvalidOutputSize; +pub use crate::fixed::{FixedOutput, FixedOutputDirty}; +pub use crate::variable::{VariableOutput, VariableOutputDirty}; +pub use crate::xof::{ExtendableOutput, ExtendableOutputDirty, XofReader}; +pub use generic_array::{self, typenum::consts}; + +#[cfg(feature = "alloc")] pub use dyn_digest::DynDigest; -/// Trait for processing input data -pub trait Input { +use generic_array::ArrayLength; + +/// Trait for updating digest state with input data. +pub trait Update { /// Digest input data. /// /// This method can be called repeatedly, e.g. for processing streaming /// messages. - fn input>(&mut self, data: B); + fn update(&mut self, data: impl AsRef<[u8]>); /// Digest input data in a chained manner. - fn chain>(mut self, data: B) -> Self where Self: Sized { - self.input(data); + fn chain(mut self, data: impl AsRef<[u8]>) -> Self + where + Self: Sized, + { + self.update(data); self } } @@ -55,67 +81,10 @@ pub trait Input { /// /// The main usage of this trait is for implementing HMAC generically. pub trait BlockInput { + /// Block size 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. @@ -123,19 +92,19 @@ pub trait Reset { } #[macro_export] -/// Implements `std::io::Write` trait for implementer of `Input` +/// Implements `std::io::Write` trait for implementer of [`Update`] 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); + impl std::io::Write for $hasher { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + Update::update(self, buf); Ok(buf.len()) } - fn flush(&mut self) -> ::std::io::Result<()> { + fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } - } + }; } diff --git a/vendor/digest/src/variable.rs b/vendor/digest/src/variable.rs new file mode 100644 index 0000000000..7f444931ff --- /dev/null +++ b/vendor/digest/src/variable.rs @@ -0,0 +1,106 @@ +//! Variable-sized output digest support + +use crate::{InvalidOutputSize, Reset}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// Trait for returning digest result with the variable size +pub trait VariableOutput: 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 finalize_variable(self, f: impl FnOnce(&[u8])); + + /// Retrieve result via closure and reset the hasher state. + /// + /// Closure is guaranteed to be called, length of the buffer passed to it + /// will be equal to `output_size`. + fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8])); + + /// Retrieve result into a boxed slice and consume hasher. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed(self) -> Box<[u8]> { + let n = self.output_size(); + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_variable(|res| buf.copy_from_slice(res)); + buf + } + + /// Retrieve result into a boxed slice and reset hasher state. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed_reset(&mut self) -> Box<[u8]> { + let n = self.output_size(); + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_variable_reset(|res| buf.copy_from_slice(res)); + buf + } +} + +/// Trait for variable-sized output digest implementations to use to retrieve +/// the hash output. +/// +/// Usage of this trait in user code is discouraged. Instead use the +/// [`VariableOutput::finalize_variable`] or +/// [`VariableOutput::finalize_variable_reset`] methods. +/// +/// Types which impl this trait along with [`Reset`] will receive a blanket +/// impl of [`VariableOutput`]. +pub trait VariableOutputDirty: 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 into provided buffer and leave hasher in a dirty state. + /// + /// This method is expected to only be called once unless + /// [`Reset::reset`] is called, after which point it can be + /// called again and reset again (and so on). + fn finalize_variable_dirty(&mut self, f: impl FnOnce(&[u8])); +} + +impl VariableOutput for D { + fn new(output_size: usize) -> Result { + ::new(output_size) + } + + fn output_size(&self) -> usize { + ::output_size(self) + } + + #[inline] + fn finalize_variable(mut self, f: impl FnOnce(&[u8])) { + self.finalize_variable_dirty(f); + } + + #[inline] + fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8])) { + self.finalize_variable_dirty(f); + self.reset(); + } +} diff --git a/vendor/digest/src/xof.rs b/vendor/digest/src/xof.rs new file mode 100644 index 0000000000..0a41833b0c --- /dev/null +++ b/vendor/digest/src/xof.rs @@ -0,0 +1,102 @@ +//! Extendable-Output Function (XOF) support + +use crate::Reset; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// 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 an unlimited number of times. + fn read(&mut self, buffer: &mut [u8]); + + /// Read output into a boxed slice of the specified size. + /// + /// Can be called an unlimited number of times in combination with `read`. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn read_boxed(&mut self, n: usize) -> Box<[u8]> { + let mut buf = vec![0u8; n].into_boxed_slice(); + self.read(&mut buf); + buf + } +} + +/// Trait which describes extendable-output functions (XOF). +pub trait ExtendableOutput: Sized { + /// Reader + type Reader: XofReader; + + /// Retrieve XOF reader and consume hasher instance. + fn finalize_xof(self) -> Self::Reader; + + /// Retrieve XOF reader and reset hasher instance state. + fn finalize_xof_reset(&mut self) -> Self::Reader; + + /// Retrieve result into a boxed slice of the specified size and consume + /// the hasher. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed(self, n: usize) -> Box<[u8]> { + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_xof().read(&mut buf); + buf + } + + /// Retrieve result into a boxed slice of the specified size and reset + /// the hasher's state. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed_reset(&mut self, n: usize) -> Box<[u8]> { + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_xof_reset().read(&mut buf); + buf + } +} + +/// Trait for extendable-output function (XOF) implementations to use to +/// retrieve the hash output. +/// +/// Usage of this trait in user code is discouraged. Instead use the +/// [`ExtendableOutput::finalize_xof`] or +/// [`ExtendableOutput::finalize_xof_reset`] methods. +/// +/// Types which impl this trait along with [`Reset`] will receive a blanket +/// impl of [`ExtendableOutput`]. +pub trait ExtendableOutputDirty: Sized { + /// Reader + type Reader: XofReader; + + /// Retrieve XOF reader. + /// + /// This method is expected to only be called once unless + /// [`Reset::reset`] is called, after which point it can be + /// called again and reset again (and so on). + fn finalize_xof_dirty(&mut self) -> Self::Reader; +} + +impl ExtendableOutput for X { + type Reader = X::Reader; + + #[inline] + fn finalize_xof(mut self) -> Self::Reader { + self.finalize_xof_dirty() + } + + #[inline] + fn finalize_xof_reset(&mut self) -> Self::Reader { + let reader = self.finalize_xof_dirty(); + self.reset(); + reader + } +} diff --git a/vendor/expect-test/.cargo-checksum.json b/vendor/expect-test/.cargo-checksum.json index 94abf0aaa0..a647d9b4be 100644 --- a/vendor/expect-test/.cargo-checksum.json +++ b/vendor/expect-test/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"2d0741c78cbf44d9df22433e83b0b4202edddb70bc0ad36da295e474817ff242","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"1c299480321bd07dcae24086bd1a5ff1a13ed6d0f855a0d962bf362ecb532b79","src/lib.rs":"35e6a84e7b8e911dbb2b5febfda296524d8227cf7159c53b772714557fbfbaaa"},"package":"a3e383741ea1982866572109d1a8c807bd36aad91fca701489fdca56ef92b3b8"} \ No newline at end of file +{"files":{"Cargo.toml":"5c0bf7c6a2323d45f0557fb2bd81a11426e8be3b570a7ad076a5c6f76a1af09e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5a67ee6ca778c7280704bf08cbdd197edb798ab69ee79841037fde2248400814","src/lib.rs":"0802f71f4439ba9ce1b472e6053691350457f26dbf30d21d1749deb64ffdadd4"},"package":"ceb96f3eaa0d4e8769c52dacfd4eb60183b817ed2f176171b3c691d5022b0f2e"} \ No newline at end of file diff --git a/vendor/expect-test/Cargo.toml b/vendor/expect-test/Cargo.toml index 3c0b6cc6cc..f73029d7bc 100644 --- a/vendor/expect-test/Cargo.toml +++ b/vendor/expect-test/Cargo.toml @@ -13,12 +13,14 @@ [package] edition = "2018" name = "expect-test" -version = "0.1.0" +version = "1.0.1" authors = ["rust-analyzer developers"] -exclude = [".github/", "bors.toml"] -description = "A minimal snapshot testing library" +exclude = [".github/", "bors.toml", "rustfmt.toml"] +description = "Minimalistic snapshot testing library" +keywords = ["snapshot", "testing", "expect"] +categories = ["development-tools::testing"] license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-analyzer/rust-analyzer" +repository = "https://github.com/rust-analyzer/expect-test" [dependencies.difference] version = "2" diff --git a/vendor/expect-test/README.md b/vendor/expect-test/README.md index 734f57f7b3..90a4bc9d1a 100644 --- a/vendor/expect-test/README.md +++ b/vendor/expect-test/README.md @@ -1,3 +1,3 @@ -# expect_test +# expect-test Minimalistic snapshot testing for Rust. diff --git a/vendor/expect-test/src/lib.rs b/vendor/expect-test/src/lib.rs index d58f2ae11f..07f9dd6704 100644 --- a/vendor/expect-test/src/lib.rs +++ b/vendor/expect-test/src/lib.rs @@ -13,8 +13,8 @@ //! ```no_run //! use expect_test::expect; //! -//! let expected = expect![["5"]]; //! let actual = 2 + 2; +//! let expected = expect![["5"]]; //! expected.assert_eq(&actual.to_string()) //! ``` //! @@ -72,11 +72,11 @@ //! use expect_test::expect_file; //! //! let actual = 42; -//! let expected = expect_file!["the-answer.txt"]; +//! let expected = expect_file!["./the-answer.txt"]; //! expected.assert_eq(&actual.to_string()); //! ``` //! -//! File path is relative to the root of the Cargo workspace. +//! File path is relative to the current file. //! //! # Suggested Workflows //! @@ -105,7 +105,7 @@ //! Each test's body is a single call to `check`. All the variation in tests //! comes from the input data. //! -//! When writing new test, I usually copy-paste and old one, leave the `expect` +//! When writing a new test, I usually copy-paste an old one, leave the `expect` //! blank and use `UPDATE_EXPECT` to fill the value for me: //! //! ``` @@ -120,6 +120,21 @@ //! See //! https://blog.janestreet.com/using-ascii-waveforms-to-test-hardware-designs/ //! for a cool example of snapshot testing in the wild! +//! +//! # Alternatives +//! +//! * [insta](https://crates.io/crates/insta) -- a more feature full snapshot +//! testing library. +//! * [k9](https://crates.io/crates/k9) -- testing library which includes +//! support for snapshot testing among other things. +//! +//! # Maintenance status +//! +//! The main customer of this library is rust-analyzer. The library is expected +//! to be relatively stable, but, if the need arises, it could be significantly +//! reworked to fit rust-analyzer better. +//! +//! MSRV: latest stable. use std::{ collections::HashMap, env, fmt, fs, mem, @@ -167,16 +182,17 @@ macro_rules! expect { [[]] => { $crate::expect![[""]] }; } -/// Creates an instance of `ExpectFile` from workspace-relative path: +/// Creates an instance of `ExpectFile` from relative or absolute path: /// /// ``` /// # use expect_test::expect_file; -/// expect_file!["/crates/foo/test_data/bar.html"]; +/// expect_file!["./test_data/bar.html"]; /// ``` #[macro_export] macro_rules! expect_file { [$path:expr] => {$crate::ExpectFile { - path: std::path::PathBuf::from($path) + path: std::path::PathBuf::from($path), + position: file!(), }}; } @@ -194,6 +210,8 @@ pub struct Expect { pub struct ExpectFile { #[doc(hidden)] pub path: PathBuf, + #[doc(hidden)] + pub position: &'static str, } /// Position of original `expect!` in the source file. @@ -278,7 +296,8 @@ impl ExpectFile { fs::write(self.abs_path(), contents).unwrap() } fn abs_path(&self) -> PathBuf { - WORKSPACE_ROOT.join(&self.path) + let dir = Path::new(self.position).parent().unwrap(); + WORKSPACE_ROOT.join(dir).join(&self.path) } } @@ -302,7 +321,6 @@ impl Runtime { } rt.panic(expect.position.to_string(), expected, actual); } - fn fail_file(expect: &ExpectFile, expected: &str, actual: &str) { let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); if update_expect() { @@ -312,7 +330,6 @@ impl Runtime { } rt.panic(expect.path.display().to_string(), expected, actual); } - fn panic(&mut self, position: String, expected: &str, actual: &str) { let print_help = !mem::replace(&mut self.help_printed, true); let help = if print_help { HELP } else { "" }; @@ -543,4 +560,9 @@ mod tests { "#]] .assert_debug_eq(&patchwork); } + + #[test] + fn test_expect_file() { + expect_file!["./lib.rs"].assert_eq(include_str!("./lib.rs")) + } } diff --git a/vendor/fs-err/.cargo-checksum.json b/vendor/fs-err/.cargo-checksum.json new file mode 100644 index 0000000000..7975f71f1f --- /dev/null +++ b/vendor/fs-err/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"4309b9e2bad51a76be93951a205a9410a641488a2094b7e0d081a8c854d40814","Cargo.toml":"cc8b8da949a2ff953b49c8d9a6c5fe63d51f290c9138ab6f3cb50846c612675e","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"e5c3355cb080a50bade0664df1f853e3f041121a9aa5bda2074ce6e01e210437","README.tpl":"de2f4fa16d473b928004aed4e11bd70522690961c6e34094a07fc68e9a092426","src/dir.rs":"1fbc8a3ada7e5e8a8c15dc0bf0e3c94cbeeea26e4a5f2b411c62d93adc023ebb","src/errors.rs":"a6a381326d6c0406409d6dc2dafa5f7c0e7f84e0ec304d234ad90c313c74d798","src/file.rs":"13463b9da1cd61dc4bee7a7a5d0e8e020b6d562a72395d66354b4ce956cfd17b","src/lib.rs":"38ff1b0362e9c2fcd741245126b08588183e5f98afd79ff6220bcc2b5eecf00b","tests/version-numbers.rs":"370467b40ce930d655389ba82015ae2842b3361bf24280c3dc7214d3ac163a2d"},"package":"c1a51f8b7158efbe531f7baa74e38e49fbc41239e5d66720bb37ed39c27c241a"} \ No newline at end of file diff --git a/vendor/fs-err/CHANGELOG.md b/vendor/fs-err/CHANGELOG.md new file mode 100644 index 0000000000..39743116a8 --- /dev/null +++ b/vendor/fs-err/CHANGELOG.md @@ -0,0 +1,33 @@ +# fs-err Changelog + +## 2.3.0 +* Added `create_dir` and `create_dir_all`. ([#19](https://github.com/andrewhickman/fs-err/pull/19)) +* Added `remove_file`, `remove_dir`, and `remove_dir_all`. ([#16](https://github.com/andrewhickman/fs-err/pull/16)) + +## 2.2.0 +* Added `metadata`. ([#15](https://github.com/andrewhickman/fs-err/pull/15)) + +## 2.1.0 +* Updated crate-level documentation. ([#8](https://github.com/andrewhickman/fs-err/pull/8)) +* Added `read_dir`, `ReadDir`, and `DirEntry`. ([#9](https://github.com/andrewhickman/fs-err/pull/9)) + +## 2.0.1 (2020-02-22) +* Added `copy`. ([#7](https://github.com/andrewhickman/fs-err/pull/7)) + +## 2.0.0 (2020-02-19) +* Removed custom error type in favor of `std::io::Error`. ([#2](https://github.com/andrewhickman/fs-err/pull/2)) + +## 1.0.1 (2020-02-15) +* Fixed bad documentation link in `Cargo.toml`. + +## 1.0.0 (2020-02-15) +* No changes from 0.1.2. + +## 0.1.2 (2020-02-10) +* Added `Error::cause` implementation for `fs_err::Error`. + +## 0.1.1 (2020-02-05) +* Added wrappers for `std::fs::*` functions. + +## 0.1.0 (2020-02-02) +* Initial release, containing a wrapper around `std::fs::File`. diff --git a/vendor/fs-err/Cargo.toml b/vendor/fs-err/Cargo.toml new file mode 100644 index 0000000000..c911b14e97 --- /dev/null +++ b/vendor/fs-err/Cargo.toml @@ -0,0 +1,30 @@ +# 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 = "fs-err" +version = "2.3.0" +authors = ["Andrew Hickman "] +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"] +license = "MIT/Apache-2.0" +repository = "https://github.com/andrewhickman/fs-err" + +[dependencies] +[dev-dependencies.serde_json] +version = "1.0.48" + +[dev-dependencies.version-sync] +version = "0.8.1" diff --git a/vendor/fs-err/LICENSE-APACHE b/vendor/fs-err/LICENSE-APACHE new file mode 100644 index 0000000000..f47c941141 --- /dev/null +++ b/vendor/fs-err/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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/fs-err/LICENSE-MIT b/vendor/fs-err/LICENSE-MIT new file mode 100644 index 0000000000..458723b374 --- /dev/null +++ b/vendor/fs-err/LICENSE-MIT @@ -0,0 +1,23 @@ +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/fs-err/README.md b/vendor/fs-err/README.md new file mode 100644 index 0000000000..70bf1fa440 --- /dev/null +++ b/vendor/fs-err/README.md @@ -0,0 +1,88 @@ + + +# fs-err + +[![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) + +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. + +## Error Messages + +Using [`std::fs`][std::fs], if this code fails: + +```rust +let file = File::open("does not exist.txt")?; +``` + +The error message that Rust gives you isn't very useful: + +```txt +The system cannot find the file specified. (os error 2) +``` + +...but if we use fs-err instead, our error contains more actionable information: + +```txt +failed to open file `does not exist.txt` + caused by: The system cannot find the file specified. (os error 2) +``` + +## Usage + +fs-err's API is the same as [`std::fs`][std::fs], so migrating code to use it is easy. + +```rust +// use std::fs; +use fs_err as fs; + +let contents = fs::read_to_string("foo.txt")?; + +println!("Read foo.txt: {}", contents); + +``` + +fs-err uses [`std::io::Error`][std::io::Error] for all errors. This helps fs-err +compose well with traits from the standard library like +[`std::io::Read`][std::io::Read] and crates that use them like +[`serde_json`][serde_json]: + +```rust +use fs_err::File; + +let file = File::open("my-config.json")?; + +// If an I/O error occurs inside serde_json, the error will include a file path +// as well as what operation was being performed. +let decoded: Vec = serde_json::from_reader(file)?; + +println!("Program config: {:?}", decoded); + +``` + +[std::fs]: https://doc.rust-lang.org/stable/std/fs/ +[std::io::Error]: https://doc.rust-lang.org/stable/std/io/struct.Error.html +[std::io::Read]: https://doc.rust-lang.org/stable/std/io/trait.Read.html +[serde_json]: https://crates.io/crates/serde_json + +## 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. diff --git a/vendor/fs-err/README.tpl b/vendor/fs-err/README.tpl new file mode 100644 index 0000000000..35ac8052d8 --- /dev/null +++ b/vendor/fs-err/README.tpl @@ -0,0 +1,28 @@ + + +# {{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 new file mode 100644 index 0000000000..adba643b9c --- /dev/null +++ b/vendor/fs-err/src/dir.rs @@ -0,0 +1,85 @@ +use std::ffi::OsString; +use std::fs; +use std::io; +use std::path::PathBuf; + +use crate::errors::{Error, ErrorKind}; + +/// Wrapper for [`fs::read_dir`](https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html). +pub fn read_dir>(path: P) -> io::Result { + let path = path.into(); + + match fs::read_dir(&path) { + Ok(inner) => Ok(ReadDir { inner, path }), + Err(source) => Err(Error::new(source, ErrorKind::ReadDir, path)), + } +} + +/// Wrapper around [`std::fs::ReadDir`][std::fs::ReadDir] which adds more +/// helpful information to all errors. +/// +/// This struct is created via [`fs_err::read_dir`][fs_err::read_dir]. +/// +/// [std::fs::ReadDir]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html +/// [fs_err::read_dir]: fn.read_dir.html +#[derive(Debug)] +pub struct ReadDir { + inner: fs::ReadDir, + path: PathBuf, +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option { + Some(self.inner.next()?.map(|inner| DirEntry { inner })) + } +} + +/// Wrapper around [`std::fs::DirEntry`][std::fs::DirEntry] which adds more +/// helpful information to all errors. +/// +/// [std::fs::DirEntry]: https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html +#[derive(Debug)] +pub struct DirEntry { + inner: fs::DirEntry, +} + +impl DirEntry { + /// Wrapper for [`DirEntry::path`](https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html#method.path). + pub fn path(&self) -> PathBuf { + self.inner.path() + } + + /// Wrapper for [`DirEntry::metadata`](https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html#method.metadata). + pub fn metadata(&self) -> io::Result { + self.inner + .metadata() + .map_err(|source| Error::new(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())) + } + + /// Wrapper for [`DirEntry::file_name`](https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html#method.file_name). + pub fn file_name(&self) -> OsString { + self.inner.file_name() + } +} + +#[cfg(unix)] +mod unix { + use std::os::unix::fs::DirEntryExt; + + use super::*; + + impl DirEntryExt for DirEntry { + fn ino(&self) -> u64 { + self.inner.ino() + } + } +} diff --git a/vendor/fs-err/src/errors.rs b/vendor/fs-err/src/errors.rs new file mode 100644 index 0000000000..37e0f80366 --- /dev/null +++ b/vendor/fs-err/src/errors.rs @@ -0,0 +1,125 @@ +use std::error::Error as StdError; +use std::fmt; +use std::io; +use std::path::PathBuf; + +#[derive(Debug, Clone, Copy)] +pub(crate) enum ErrorKind { + OpenFile, + CreateFile, + CreateDir, + SyncFile, + SetLen, + Metadata, + Clone, + SetPermissions, + Read, + Seek, + Write, + Flush, + ReadDir, + RemoveFile, + RemoveDir, +} + +/// Contains an IO error that has a file path attached. +/// +/// This type is never returned directly, but is instead wrapped inside yet +/// another IO error. +#[derive(Debug)] +pub(crate) struct Error { + kind: ErrorKind, + source: io::Error, + path: PathBuf, +} + +impl Error { + pub fn new>(source: io::Error, kind: ErrorKind, path: P) -> io::Error { + io::Error::new( + source.kind(), + Self { + kind, + source, + path: path.into(), + }, + ) + } +} + +impl fmt::Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + use ErrorKind::*; + + let path = self.path.display(); + + match self.kind { + OpenFile => write!(formatter, "failed to open file `{}`", path), + CreateFile => write!(formatter, "failed to create file `{}`", path), + CreateDir => write!(formatter, "failed to create directory `{}`", path), + SyncFile => write!(formatter, "failed to sync file `{}`", path), + SetLen => write!(formatter, "failed to set length of file `{}`", path), + Metadata => write!(formatter, "failed to query metadata of file `{}`", path), + Clone => write!(formatter, "failed to clone handle for file `{}`", path), + SetPermissions => write!(formatter, "failed to set permissions for file `{}`", path), + Read => write!(formatter, "failed to read from file `{}`", path), + Seek => write!(formatter, "failed to seek in file `{}`", path), + Write => write!(formatter, "failed to write to file `{}`", path), + Flush => write!(formatter, "failed to flush file `{}`", path), + ReadDir => write!(formatter, "failed to read directory `{}`", path), + RemoveFile => write!(formatter, "failed to remove file `{}`", path), + RemoveDir => write!(formatter, "failed to remove directory `{}`", path), + } + } +} + +impl StdError for Error { + fn cause(&self) -> Option<&dyn StdError> { + self.source() + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(&self.source) + } +} + +/// Error type used by `fs::copy` that holds two paths. +#[derive(Debug)] +pub(crate) struct CopyError { + source: io::Error, + from_path: PathBuf, + to_path: PathBuf, +} + +impl CopyError { + pub fn new, Q: Into>(source: io::Error, from: P, to: Q) -> io::Error { + io::Error::new( + source.kind(), + Self { + source, + from_path: from.into(), + to_path: to.into(), + }, + ) + } +} + +impl fmt::Display for CopyError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "failed to copy file from {} to {}", + self.from_path.display(), + self.to_path.display() + ) + } +} + +impl StdError for CopyError { + fn cause(&self) -> Option<&dyn StdError> { + self.source() + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(&self.source) + } +} diff --git a/vendor/fs-err/src/file.rs b/vendor/fs-err/src/file.rs new file mode 100644 index 0000000000..3a839ab7c7 --- /dev/null +++ b/vendor/fs-err/src/file.rs @@ -0,0 +1,217 @@ +use std::fs; +use std::io::{self, Read, Seek, Write}; +use std::path::{Path, PathBuf}; + +use crate::errors::{Error, ErrorKind}; + +/// Wrapper around [`std::fs::File`][std::fs::File] which adds more helpful +/// information to all errors. +/// +/// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html +#[derive(Debug)] +pub struct File { + file: fs::File, + path: PathBuf, +} + +/// Wrappers for methods from [`std::fs::File`][std::fs::File]. +/// +/// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html +impl File { + /// Wrapper for [`File::open`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.open). + pub fn open

    (path: P) -> Result + where + P: AsRef + Into, + { + match fs::File::open(path.as_ref()) { + Ok(file) => Ok(File::from_parts(file, path.into())), + Err(source) => Err(Error::new(source, ErrorKind::OpenFile, path)), + } + } + + /// Wrapper for [`File::create`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.create). + pub fn create

    (path: P) -> Result + where + P: AsRef + Into, + { + match fs::File::create(path.as_ref()) { + Ok(file) => Ok(File::from_parts(file, path.into())), + Err(source) => Err(Error::new(source, ErrorKind::CreateFile, path)), + } + } + + /// Wrapper for [`OpenOptions::open`](https://doc.rust-lang.org/stable/std/fs/struct.OpenOptions.html#method.open). + pub fn from_options

    (path: P, options: &fs::OpenOptions) -> Result + where + P: AsRef + Into, + { + match options.open(path.as_ref()) { + Ok(file) => Ok(File::from_parts(file, path.into())), + Err(source) => Err(Error::new(source, ErrorKind::OpenFile, path)), + } + } + + /// Wrapper for [`File::sync_all`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.sync_all). + pub fn sync_all(&self) -> Result<(), io::Error> { + self.file + .sync_all() + .map_err(|source| self.error(source, ErrorKind::SyncFile)) + } + + /// Wrapper for [`File::sync_data`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.sync_data). + pub fn sync_data(&self) -> Result<(), io::Error> { + self.file + .sync_data() + .map_err(|source| self.error(source, ErrorKind::SyncFile)) + } + + /// Wrapper for [`File::set_len`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.set_len). + pub fn set_len(&self, size: u64) -> Result<(), io::Error> { + self.file + .set_len(size) + .map_err(|source| self.error(source, ErrorKind::SetLen)) + } + + /// Wrapper for [`File::metadata`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.metadata). + pub fn metadata(&self) -> Result { + self.file + .metadata() + .map_err(|source| self.error(source, ErrorKind::Metadata)) + } + + /// Wrapper for [`File::try_clone`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.try_clone). + pub fn try_clone(&self) -> Result { + self.file + .try_clone() + .map(|file| File { + file, + path: self.path.clone(), + }) + .map_err(|source| self.error(source, ErrorKind::Clone)) + } + + /// Wrapper for [`File::set_permissions`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.set_permissions). + pub fn set_permissions(&self, perm: fs::Permissions) -> Result<(), io::Error> { + self.file + .set_permissions(perm) + .map_err(|source| self.error(source, ErrorKind::SetPermissions)) + } + + /// Creates a [`File`](struct.File.html) from a raw file and its path. + pub fn from_parts

    (file: fs::File, path: P) -> Self + where + P: Into, + { + File { + 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 { + /// 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 + pub fn file(&self) -> &fs::File { + &self.file + } + + /// Returns a reference to the path that this file was created with. + pub fn path(&self) -> &Path { + &self.path + } + + /// 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) + } +} + +impl Read for File { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.file + .read(buf) + .map_err(|source| self.error(source, ErrorKind::Read)) + } + + fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result { + self.file + .read_vectored(bufs) + .map_err(|source| self.error(source, ErrorKind::Read)) + } +} + +impl<'a> Read for &'a File { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + (&(**self).file) + .read(buf) + .map_err(|source| self.error(source, ErrorKind::Read)) + } + + fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result { + (&(**self).file) + .read_vectored(bufs) + .map_err(|source| self.error(source, ErrorKind::Read)) + } +} + +impl Seek for File { + fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { + self.file + .seek(pos) + .map_err(|source| self.error(source, ErrorKind::Seek)) + } +} + +impl<'a> Seek for &'a File { + fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { + (&(**self).file) + .seek(pos) + .map_err(|source| self.error(source, ErrorKind::Seek)) + } +} + +impl Write for File { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.file + .write(buf) + .map_err(|source| self.error(source, ErrorKind::Write)) + } + + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { + self.file + .write_vectored(bufs) + .map_err(|source| self.error(source, ErrorKind::Write)) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.file + .flush() + .map_err(|source| self.error(source, ErrorKind::Flush)) + } +} + +impl<'a> Write for &'a File { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + (&(**self).file) + .write(buf) + .map_err(|source| self.error(source, ErrorKind::Write)) + } + + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { + (&(**self).file) + .write_vectored(bufs) + .map_err(|source| self.error(source, ErrorKind::Write)) + } + + fn flush(&mut self) -> std::io::Result<()> { + (&(**self).file) + .flush() + .map_err(|source| self.error(source, ErrorKind::Flush)) + } +} diff --git a/vendor/fs-err/src/lib.rs b/vendor/fs-err/src/lib.rs new file mode 100644 index 0000000000..96cba8c768 --- /dev/null +++ b/vendor/fs-err/src/lib.rs @@ -0,0 +1,170 @@ +/*! +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. + +# Error Messages + +Using [`std::fs`][std::fs], if this code fails: + +```no_run +# use std::fs::File; +let file = File::open("does not exist.txt")?; +# Ok::<(), std::io::Error>(()) +``` + +The error message that Rust gives you isn't very useful: + +```txt +The system cannot find the file specified. (os error 2) +``` + +...but if we use fs-err instead, our error contains more actionable information: + +```txt +failed to open file `does not exist.txt` + caused by: The system cannot find the file specified. (os error 2) +``` + +# Usage + +fs-err's API is the same as [`std::fs`][std::fs], so migrating code to use it is easy. + +```no_run +// use std::fs; +use fs_err as fs; + +let contents = fs::read_to_string("foo.txt")?; + +println!("Read foo.txt: {}", contents); + +# Ok::<(), std::io::Error>(()) +``` + +fs-err uses [`std::io::Error`][std::io::Error] for all errors. This helps fs-err +compose well with traits from the standard library like +[`std::io::Read`][std::io::Read] and crates that use them like +[`serde_json`][serde_json]: + +```no_run +use fs_err::File; + +let file = File::open("my-config.json")?; + +// If an I/O error occurs inside serde_json, the error will include a file path +// as well as what operation was being performed. +let decoded: Vec = serde_json::from_reader(file)?; + +println!("Program config: {:?}", decoded); + +# Ok::<(), Box>(()) +``` + +[std::fs]: https://doc.rust-lang.org/stable/std/fs/ +[std::io::Error]: https://doc.rust-lang.org/stable/std/io/struct.Error.html +[std::io::Read]: https://doc.rust-lang.org/stable/std/io/trait.Read.html +[serde_json]: https://crates.io/crates/serde_json +*/ + +#![doc(html_root_url = "https://docs.rs/fs-err/2.3.0")] +#![deny(missing_debug_implementations, missing_docs)] + +mod dir; +mod errors; +mod file; + +use std::fs; +use std::io::{self, Read, Write}; +use std::path::{Path, PathBuf}; + +use errors::{CopyError, Error, ErrorKind}; + +pub use dir::*; +pub use file::*; + +/// Wrapper for [`fs::read`](https://doc.rust-lang.org/stable/std/fs/fn.read.html). +pub fn read + Into>(path: P) -> io::Result> { + let mut file = File::open(path)?; + let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); + file.read_to_end(&mut bytes)?; + 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 + Into>(path: P) -> io::Result { + let mut file = File::open(path)?; + let mut string = String::with_capacity(initial_buffer_size(&file)); + file.read_to_string(&mut string)?; + Ok(string) +} + +/// Wrapper for [`fs::write`](https://doc.rust-lang.org/stable/std/fs/fn.write.html). +pub fn write + Into, C: AsRef<[u8]>>( + path: P, + contents: C, +) -> io::Result<()> { + File::create(path)?.write_all(contents.as_ref()) +} + +/// Wrapper for [`fs::copy`](https://doc.rust-lang.org/stable/std/fs/fn.copy.html). +pub fn copy(from: P, to: Q) -> io::Result +where + P: AsRef + Into, + Q: AsRef + Into, +{ + fs::copy(from.as_ref(), to.as_ref()).map_err(|source| CopyError::new(source, from, to)) +} + +/// Wrapper for [`fs::create_dir`](https://doc.rust-lang.org/stable/std/fs/fn.create_dir.html). +pub fn create_dir

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::create_dir(path.as_ref()).map_err(|source| Error::new(source, ErrorKind::CreateDir, path)) +} + +/// Wrapper for [`fs::create_dir_all`](https://doc.rust-lang.org/stable/std/fs/fn.create_dir_all.html). +pub fn create_dir_all

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::create_dir_all(path.as_ref()) + .map_err(|source| Error::new(source, ErrorKind::CreateDir, path)) +} + +/// Wrapper for [`fs::remove_dir`](https://doc.rust-lang.org/stable/std/fs/fn.remove_dir.html). +pub fn remove_dir

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::remove_dir(path.as_ref()).map_err(|source| Error::new(source, ErrorKind::RemoveDir, path)) +} + +/// Wrapper for [`fs::remove_dir_all`](https://doc.rust-lang.org/stable/std/fs/fn.remove_dir_all.html). +pub fn remove_dir_all

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::remove_dir_all(path.as_ref()) + .map_err(|source| Error::new(source, ErrorKind::RemoveDir, path)) +} + +/// Wrapper for [`fs::remove_file`](https://doc.rust-lang.org/stable/std/fs/fn.remove_file.html). +pub fn remove_file

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::remove_file(path.as_ref()).map_err(|source| Error::new(source, ErrorKind::RemoveFile, path)) +} + +/// Wrapper for [`fs::metadata`](https://doc.rust-lang.org/stable/std/fs/fn.metadata.html). +pub fn metadata + Into>(path: P) -> io::Result { + fs::metadata(path.as_ref()).map_err(|source| Error::new(source, ErrorKind::Metadata, path)) +} + +fn initial_buffer_size(file: &File) -> usize { + file.file() + .metadata() + .map(|m| m.len() as usize + 1) + .unwrap_or(0) +} diff --git a/vendor/fs-err/tests/version-numbers.rs b/vendor/fs-err/tests/version-numbers.rs new file mode 100644 index 0000000000..41a5ea4802 --- /dev/null +++ b/vendor/fs-err/tests/version-numbers.rs @@ -0,0 +1,9 @@ +#[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.3/.cargo-checksum.json b/vendor/generic-array-0.12.3/.cargo-checksum.json new file mode 100644 index 0000000000..66e17ddfc4 --- /dev/null +++ b/vendor/generic-array-0.12.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"aa938a1a7581e59cbb554b44cc2dcf628cc1af9ddee6dccd53f557ed8d62775e","Cargo.toml":"6f83fe34b8c252299c537c8f5cdb22bffb583c5676d5353ad73bef7f4d6958fc","LICENSE":"c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583","README.md":"aad2a8508f8ae6b009d04d388bffb751875d4cfdcc6f3398212c65cc3c390d03","rustfmt.toml":"13d771354ddee15d5aa5a168fd6965c3c0ee7aa7ce75cdd5e3b82852cdac5123","src/arr.rs":"5fee5550800b890383c1dd80e00a0a568475a8599e7678e143740c941e98099d","src/functional.rs":"2437c360c645d8a9816a3b13531f23b005d1aed3ef7b1d9bcc9b2859b1d56826","src/hex.rs":"438288cf41fad3fd40ce60eb893cd038e9a88e450bab0189fe4dba8ce833a686","src/impl_serde.rs":"2cab2f808ba000c214a3ded9f43b4d5363114fe57c2c7abf545345b8b749f0db","src/impls.rs":"0472fc62d69e3e78b3f31e340cfc038bf12c3d7c4bdcd5fee064e7113d2f171d","src/iter.rs":"156f798c82bc0d5e2c9a0a7777acc156bfdda793b64295ad7495cc5daa5ecb97","src/lib.rs":"d2f4b74c7ac8f9a9d7a782089b95315ec6b1f1571d79a2b16bd76bcff2004bd4","src/sequence.rs":"63813c9e305b6642ac29f0ba3dd70d7db86e27fc58b31e7508c68ea52c060e82","tests/arr.rs":"22d332fcb5e0314980ddc952af0265125cf53bb9cb8b546a9dcaec2e29bfc3b0","tests/generics.rs":"491c9351fd973ff2b7bc72e78d3069cf3ed3fcd2f9180558ab027099605fa147","tests/hex.rs":"fd428c2558da2f1e2cf229af2e40e5b35a2094b3306312ac41943d25a85b7de1","tests/import_name.rs":"c9439c7d7531ce79419b0d413d729ea4321887c091bd9be8b18e6c2413021ed0","tests/iter.rs":"edf27c43ed13bf8cba2cd01de2fd7b6451c1226c8ad8331880996248e7f14d12","tests/mod.rs":"fca2966183ccd1d1681f91a845773911ab61f618bd412470612fac240ecfe0db"},"package":"c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"} \ No newline at end of file diff --git a/vendor/generic-array-0.12.3/CHANGELOG.md b/vendor/generic-array-0.12.3/CHANGELOG.md new file mode 100644 index 0000000000..f8ee86b8e6 --- /dev/null +++ b/vendor/generic-array-0.12.3/CHANGELOG.md @@ -0,0 +1,48 @@ +* **`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.3/Cargo.toml b/vendor/generic-array-0.12.3/Cargo.toml new file mode 100644 index 0000000000..14b070c0b6 --- /dev/null +++ b/vendor/generic-array-0.12.3/Cargo.toml @@ -0,0 +1,40 @@ +# 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.3" +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.3/LICENSE b/vendor/generic-array-0.12.3/LICENSE new file mode 100644 index 0000000000..6d318946df --- /dev/null +++ b/vendor/generic-array-0.12.3/LICENSE @@ -0,0 +1,21 @@ +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.3/README.md b/vendor/generic-array-0.12.3/README.md new file mode 100644 index 0000000000..64dd84faaf --- /dev/null +++ b/vendor/generic-array-0.12.3/README.md @@ -0,0 +1,34 @@ +[![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.3/rustfmt.toml b/vendor/generic-array-0.12.3/rustfmt.toml new file mode 100644 index 0000000000..a46e4b2bdb --- /dev/null +++ b/vendor/generic-array-0.12.3/rustfmt.toml @@ -0,0 +1,3 @@ +reorder_imports = true +reorder_imported_names = true +use_try_shorthand = true diff --git a/vendor/generic-array-0.12.3/src/arr.rs b/vendor/generic-array-0.12.3/src/arr.rs new file mode 100644 index 0000000000..a07d129ad3 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/arr.rs @@ -0,0 +1,57 @@ +//! 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 { + ($T:ty; $N:ty, [$($x:expr),*], []) => ({ + unsafe { $crate::transmute::<_, $crate::GenericArray<$T, $N>>([$($x),*]) } + }); + ($T:ty; $N:ty, [], [$x1:expr]) => ( + arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], []) + ); + ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => ( + arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),+]) + ); + ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => ( + arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], []) + ); + ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => ( + arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [$($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];`") +} diff --git a/vendor/generic-array-0.12.3/src/functional.rs b/vendor/generic-array-0.12.3/src/functional.rs new file mode 100644 index 0000000000..d161a83cac --- /dev/null +++ b/vendor/generic-array-0.12.3/src/functional.rs @@ -0,0 +1,94 @@ +//! 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.3/src/hex.rs b/vendor/generic-array-0.12.3/src/hex.rs new file mode 100644 index 0000000000..09a6608e37 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/hex.rs @@ -0,0 +1,102 @@ +//! 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.3/src/impl_serde.rs b/vendor/generic-array-0.12.3/src/impl_serde.rs new file mode 100644 index 0000000000..7bf20ba013 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/impl_serde.rs @@ -0,0 +1,108 @@ +//! 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.3/src/impls.rs b/vendor/generic-array-0.12.3/src/impls.rs new file mode 100644 index 0000000000..52896dfba3 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/impls.rs @@ -0,0 +1,182 @@ +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.3/src/iter.rs b/vendor/generic-array-0.12.3/src/iter.rs new file mode 100644 index 0000000000..46f3e768d7 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/iter.rs @@ -0,0 +1,190 @@ +//! `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.3/src/lib.rs b/vendor/generic-array-0.12.3/src/lib.rs new file mode 100644 index 0000000000..5b95805375 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/lib.rs @@ -0,0 +1,632 @@ +//! 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.3/src/sequence.rs b/vendor/generic-array-0.12.3/src/sequence.rs new file mode 100644 index 0000000000..cec6601ba3 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/sequence.rs @@ -0,0 +1,320 @@ +//! 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.3/tests/arr.rs b/vendor/generic-array-0.12.3/tests/arr.rs new file mode 100644 index 0000000000..461805a501 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/arr.rs @@ -0,0 +1,27 @@ +#[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.3/tests/generics.rs b/vendor/generic-array-0.12.3/tests/generics.rs new file mode 100644 index 0000000000..952867b386 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/generics.rs @@ -0,0 +1,98 @@ +#![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.3/tests/hex.rs b/vendor/generic-array-0.12.3/tests/hex.rs new file mode 100644 index 0000000000..0c63391a64 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/hex.rs @@ -0,0 +1,61 @@ +#[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.3/tests/import_name.rs b/vendor/generic-array-0.12.3/tests/import_name.rs new file mode 100644 index 0000000000..f59f1b6c56 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/import_name.rs @@ -0,0 +1,10 @@ +#[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.3/tests/iter.rs b/vendor/generic-array-0.12.3/tests/iter.rs new file mode 100644 index 0000000000..19d198cb58 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/iter.rs @@ -0,0 +1,164 @@ +#[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.3/tests/mod.rs b/vendor/generic-array-0.12.3/tests/mod.rs new file mode 100644 index 0000000000..c103f417ab --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/mod.rs @@ -0,0 +1,287 @@ +#![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/generic-array/.cargo-checksum.json b/vendor/generic-array/.cargo-checksum.json index 66e17ddfc4..9996cc4538 100644 --- a/vendor/generic-array/.cargo-checksum.json +++ b/vendor/generic-array/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"aa938a1a7581e59cbb554b44cc2dcf628cc1af9ddee6dccd53f557ed8d62775e","Cargo.toml":"6f83fe34b8c252299c537c8f5cdb22bffb583c5676d5353ad73bef7f4d6958fc","LICENSE":"c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583","README.md":"aad2a8508f8ae6b009d04d388bffb751875d4cfdcc6f3398212c65cc3c390d03","rustfmt.toml":"13d771354ddee15d5aa5a168fd6965c3c0ee7aa7ce75cdd5e3b82852cdac5123","src/arr.rs":"5fee5550800b890383c1dd80e00a0a568475a8599e7678e143740c941e98099d","src/functional.rs":"2437c360c645d8a9816a3b13531f23b005d1aed3ef7b1d9bcc9b2859b1d56826","src/hex.rs":"438288cf41fad3fd40ce60eb893cd038e9a88e450bab0189fe4dba8ce833a686","src/impl_serde.rs":"2cab2f808ba000c214a3ded9f43b4d5363114fe57c2c7abf545345b8b749f0db","src/impls.rs":"0472fc62d69e3e78b3f31e340cfc038bf12c3d7c4bdcd5fee064e7113d2f171d","src/iter.rs":"156f798c82bc0d5e2c9a0a7777acc156bfdda793b64295ad7495cc5daa5ecb97","src/lib.rs":"d2f4b74c7ac8f9a9d7a782089b95315ec6b1f1571d79a2b16bd76bcff2004bd4","src/sequence.rs":"63813c9e305b6642ac29f0ba3dd70d7db86e27fc58b31e7508c68ea52c060e82","tests/arr.rs":"22d332fcb5e0314980ddc952af0265125cf53bb9cb8b546a9dcaec2e29bfc3b0","tests/generics.rs":"491c9351fd973ff2b7bc72e78d3069cf3ed3fcd2f9180558ab027099605fa147","tests/hex.rs":"fd428c2558da2f1e2cf229af2e40e5b35a2094b3306312ac41943d25a85b7de1","tests/import_name.rs":"c9439c7d7531ce79419b0d413d729ea4321887c091bd9be8b18e6c2413021ed0","tests/iter.rs":"edf27c43ed13bf8cba2cd01de2fd7b6451c1226c8ad8331880996248e7f14d12","tests/mod.rs":"fca2966183ccd1d1681f91a845773911ab61f618bd412470612fac240ecfe0db"},"package":"c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"} \ No newline at end of file +{"files":{"CHANGELOG.md":"6fd290755dcbb7da68223425151b556fd76ab9998fe9cee81042acf1a47164e5","Cargo.toml":"a14186cc9cbb4d0446fcb8898439c24b5dd8acccc05dd27e3d829c069da97fa4","DESIGN.md":"8b745d89e634c48646202edfaa2151ee08a04a9c32271f4c2cc4afb63b4e952c","LICENSE":"c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583","README.md":"9e86d03b400dc818f44df68b76dafd1d89e42a51221bcb0de4259a6529ab6d84","build.rs":"08fa30c4a2c1ad24fe5f987e721dfb20131f45ea5b5dc3e836dcf88a8e33248c","rustfmt.toml":"13d771354ddee15d5aa5a168fd6965c3c0ee7aa7ce75cdd5e3b82852cdac5123","src/arr.rs":"a898e3a37910bfc59d9caf71bf22eda02d3a4ad96c75f8a6d49ed1309531aa4e","src/functional.rs":"7dd6ddd5db3000054cbbd76959f745c7de73c8493cbfb745be80509b306e4a83","src/hex.rs":"091fb78f6d373a6ef1c467d85c461472fcdb1e91efc294039f4c870151c3ee9f","src/impl_serde.rs":"f046daba067522b4c3e79437d04f43a001e83353c81e6b2188c37a2e63dba7a3","src/impls.rs":"18b285821421eea0cdbbcfcc896eef67bd55d72f8d85b5827cca6687e9c0fc27","src/iter.rs":"5e5e92e86a18e747f6687f4b3853aa2eaaa1121af43f3833b940f074baa32302","src/lib.rs":"22af14d446ec5f67a99e350d4a0c95e070f4ff9537ac9e84ec1172f654f8b95a","src/sequence.rs":"26679cfec035bae7298f067f37e8d42a1eda8fe241e9cf2c2977ba4bddddab1d","tests/arr.rs":"22d332fcb5e0314980ddc952af0265125cf53bb9cb8b546a9dcaec2e29bfc3b0","tests/generics.rs":"491c9351fd973ff2b7bc72e78d3069cf3ed3fcd2f9180558ab027099605fa147","tests/hex.rs":"fd428c2558da2f1e2cf229af2e40e5b35a2094b3306312ac41943d25a85b7de1","tests/import_name.rs":"c9439c7d7531ce79419b0d413d729ea4321887c091bd9be8b18e6c2413021ed0","tests/iter.rs":"d9f18c7a280a938a63d382086450146206c5805804d4b62c7e55cd60ea0e2d0d","tests/mod.rs":"556a9cb6f6699c523ebfb1b167a18b30d909604339e929e9c874da92aae60bd3"},"package":"501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"} \ No newline at end of file diff --git a/vendor/generic-array/CHANGELOG.md b/vendor/generic-array/CHANGELOG.md index f8ee86b8e6..da20e891aa 100644 --- a/vendor/generic-array/CHANGELOG.md +++ b/vendor/generic-array/CHANGELOG.md @@ -1,3 +1,45 @@ +* **`0.14.4`** + * Update `typenum` to `1.12.0` + * Make `Drop` a no-op when the inner type does not require `Drop` (using `core::mem::needs_drop`) + +* **`0.14.3`** + * Improve behavior of `GenericArray::from_exact_iter` to assume `ExactIterator`s can lie. + * Fix alignment of zero-length `GenericArray`s + * Implement `From<&[T; N]> for &GenericArray` and its mutable variant + +* **`0.14.2`** + * Lower MSRV to `1.36.0` without `From<[T; N]>` implementations. + +* **`0.14.1`** + * Fix element conversions in `arr!` macro. + +* **`0.14.0`** + * Replace `Into` implementations with the more general `From`. + * Requires minumum Rust version of 1.41.0 + * Fix unsoundness in `arr!` macro. + * Fix meta variable misuse + * Fix Undefined Behavior across the crate by switching to `MaybeUninit` + * Improve some documentation and doctests + * Add `AsRef<[T; N]>` and `AsMut<[T; N]>` impls to `GenericArray` + * Add `Split` impl for `&GenericArray` and `&mut GenericArray` + +* **`0.13.2`** + * Add feature `more_lengths`, which adds more `From`/`Into` implementations for arrays of various lengths. + +* **`0.13.1`** + * Mark `GenericArray` as `#[repr(transparent)]` + * Implement `Into<[T; N]>` for `GenericArray` up to N=32 + +* **`0.13.0`** + * Allow `arr!` to be imported with use syntax. + * Requires minumum Rust version of 1.30.1 + +* **`0.12.2`** + * Implement `FusedIterator` for `GenericArrayIter` + +* **`0.12.1`** + * Use internal iteration where possible and provide more efficient internal iteration methods. + * **`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. diff --git a/vendor/generic-array/Cargo.toml b/vendor/generic-array/Cargo.toml index 14b070c0b6..e802b576da 100644 --- a/vendor/generic-array/Cargo.toml +++ b/vendor/generic-array/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "generic-array" -version = "0.12.3" +version = "0.14.4" authors = ["Bartłomiej Kamiński ", "Aaron Trent "] description = "Generic types implementing functionality of arrays" documentation = "http://fizyk20.github.io/generic-array/generic_array/" @@ -30,11 +30,16 @@ optional = true default-features = false [dependencies.typenum] -version = "1.10" +version = "1.12" [dev-dependencies.bincode] version = "1.0" [dev-dependencies.serde_json] version = "1.0" +[build-dependencies.version_check] +version = "0.9" + +[features] +more_lengths = [] [badges.travis-ci] repository = "fizyk20/generic-array" diff --git a/vendor/generic-array/DESIGN.md b/vendor/generic-array/DESIGN.md new file mode 100644 index 0000000000..547bc7bd25 --- /dev/null +++ b/vendor/generic-array/DESIGN.md @@ -0,0 +1,585 @@ +Design and Usage Notes +====================== + +## Sections + +1. [How it Works](#how-it-works) +2. [Initialization](#initialization) +3. [Functional Programming](#functional-programming) +4. [Miscellaneous Utilities](#miscellaneous-utilities) +5. [Safety](#safety) +6. [Optimization](#optimization) +7. [The Future](#the-future) + +**NOTE**: This document uses `

    ` sections, so look out for collapsible parts with an arrow on the left. + +# How it works + +`generic-array` is a method of achieving fixed-length fixed-size stack-allocated generic arrays without needing const generics in stable Rust. + +That is to say this: + +```rust +struct Foo { + data: [i32; N], +} +``` + +or anything similar is not currently supported. + +However, Rust's type system is sufficiently advanced, and a "hack" for solving this was created in the form of the `typenum` crate, which recursively defines integer values in binary as nested types, and operations which can be applied to those type-numbers, such as `Add`, `Sub`, etc. + +e.g. `6` would be `UInt, B1>, B0>` + +Over time, I've come to see `typenum` as less of a hack and more as an elegant solution. + +The recursive binary nature of `typenum` is what makes `generic-array` possible, so: + +```rust +struct Foo> { + data: GenericArray, +} +``` + +is supported. + +I often see questions about why `ArrayLength` requires the element type `T` in it's signature, even though it's not used in the inner `ArrayType`. + +This is because `GenericArray` itself does not define the actual array. Rather, it is defined as: + +```rust +pub struct GenericArray> { + data: N::ArrayType, +} +``` + +The trait `ArrayLength` does all the real heavy lifting for defining the data, with implementations on `UInt`, `UInt` and `UTerm`, which correspond to even, odd and zero numeric values, respectively. + +`ArrayLength`'s implementations use type-level recursion to peel away each least significant bit and form sort of an opaque binary tree of contiguous data the correct physical size to store `N` elements of `T`. The tree, or block of data, is then stored inside of `GenericArray` to be reinterpreted as the array. + +For example, `GenericArray` more or less expands to (at compile time): + +
    +Expand for code + +```rust +GenericArray { + // UInt, B1>, B0> + data: EvenData { + // UInt, B1> + left: OddData { + // UInt + left: OddData { + left: (), // UTerm + right: (), // UTerm + data: T, // Element 0 + }, + // UInt + right: OddData { + left: (), // UTerm + right: (), // UTerm + data: T, // Element 1 + }, + data: T // Element 2 + }, + // UInt, B1> + right: OddData { + // UInt + left: OddData { + left: (), // UTerm + right: (), // UTerm + data: T, // Element 3 + }, + // UInt + right: OddData { + left: (), // UTerm + right: (), // UTerm + data: T, // Element 4 + }, + data: T // Element 5 + } + } +} +``` + +
    + +This has the added benefit of only being `log2(N)` deep, which is important for things like `Drop`, which we'll go into later. + +Then, we take `data` and cast it to `*const T` or `*mut T` and use it as a slice like: + +```rust +unsafe { + slice::from_raw_parts( + self as *const Self as *const T, + N::to_usize() + ) +} +``` + +It is useful to note that because `typenum` is compile-time with nested generics, `to_usize`, even if it isn't a `const fn`, *does* expand to effectively `1 + 2 + 4 + 8 + ...` and so forth, which LLVM is smart enough to reduce to a single compile-time constant. This helps hint to the optimizers about things such as bounds checks. + +So, to reiterate, we're working with a raw block of contiguous memory the correct physical size to store `N` elements of `T`. It's really no different from how normal arrays are stored. + +## Pointer Safety + +Of course, casting pointers around and constructing blocks of data out of thin air is normal for C, but here in Rust we try to be a bit less prone to segfaults. Therefore, great care is taken to minimize casual `unsafe` usage and restrict `unsafe` to specific parts of the API, making heavy use those exposed safe APIs internally. + +For example, the above `slice::from_raw_parts` is only used twice in the entire library, once for `&[T]` and `slice::from_raw_parts_mut` once for `&mut [T]`. Everything else goes through those slices. + +# Initialization + +## Constant + +"Constant" initialization, that is to say - without dynamic values, can be done via the `arr![]` macro, which works almost exactly like `vec![]`, but with an additional type parameter. + +Example: + +```rust +let my_arr = arr![i32; 1, 2, 3, 4, 5, 6, 7, 8]; +``` + +## Dynamic + +Although some users have opted to use their own initializers, as of version `0.9` and beyond `generic-array` includes safe methods for initializing elements in the array. + +The `GenericSequence` trait defines a `generate` method which can be used like so: + +```rust +use generic_array::{GenericArray, sequence::GenericSequence}; + +let squares: GenericArray = + GenericArray::generate(|i: usize| i as i32 * 2); +``` + +and `GenericArray` additionally implements `FromIterator`, although `from_iter` ***will*** panic if the number of elements is not *at least* `N`. It will ignore extra items. + +The safety of these operations is described later. + +# Functional Programming + +In addition to `GenericSequence`, this crate provides a `FunctionalSequence`, which allows extremely efficient `map`, `zip` and `fold` operations on `GenericArray`s. + +As described at the end of the [Optimization](#optimization) section, `FunctionalSequence` uses clever specialization tactics to provide optimized methods wherever possible, while remaining perfectly safe. + +Some examples, taken from `tests/generic.rs`: + +
    + +and if you really want to go off the deep end and support any arbitrary *`GenericSequence`*: + +
    +Expand for code + +```rust +/// 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) +} +``` + +of course, as I stated before, that's almost never necessary, especially when you know the concrete types of all the components. + +
    + +The [`numeric-array`](https://crates.io/crates/numeric-array) crate uses these to apply numeric operations across all elements in a `GenericArray`, making full use of all the optimizations described in the last section here. + +# Miscellaneous Utilities + +Although not usually advertised, `generic-array` contains traits for lengthening, shortening, splitting and concatenating arrays. + +For example, these snippets are taken from `tests/mod.rs`: + +
    +Expand for code + +Appending and prepending elements: + +```rust +use generic_array::sequence::Lengthen; + +#[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]); +} +``` + +Popping elements from the front of back of the array: + +```rust +use generic_array::sequence::Shorten; + +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]); +``` + +and of course concatenating and splitting: + +```rust +use generic_array::sequence::{Concat, Split}; + +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]); +``` +
    + +`Split` and `Concat` in these examples use type-inference to determine the lengths of the resulting arrays. + +# Safety + +As stated earlier, for raw reinterpretations such as this, safety is a must even while working with unsafe code. Great care is taken to reduce or eliminate undefined behavior. + +For most of the above code examples, the biggest potential undefined behavior hasn't even been applicable for one simple reason: they were all primitive values. + +The simplest way to lead into this is to post these questions: + +1. What if the element type of the array implements `Drop`? +2. What if `GenericArray::generate` opens a bunch of files? +3. What if halfway through opening each of the files, one is not found? +4. What if the resulting error is unwrapped, causing the generation function to panic? + +For a fully initialized `GenericArray`, the expanded structure as described in the [How It Works](#how-it-works) can implement `Drop` naturally, recursively dropping elements. As it is only `log2(N)` deep, the recursion is very small overall. + +In fact, I tested it while writing this, the size of the array itself overflows the stack before any recursive calls to `drop` can. + +However, ***partially*** initialized arrays, such as described in the above hypothetical, pose an issue where `drop` could be called on uninitialized data, which is undefined behavior. + +To solve this, `GenericArray` implements two components named `ArrayBuilder` and `ArrayConsumer`, which work very similarly. + +`ArrayBuilder` creates a block of wholly uninitialized memory via `mem::unintialized()`, and stores that in a `ManuallyDrop` wrapper. `ManuallyDrop` does exactly what it says on the tin, and simply doesn't drop the value unless manually requested to. + +So, as we're initializing our array, `ArrayBuilder` keeps track of the current position through it, and if something happens, `ArrayBuilder` itself will iteratively and manually `drop` all currently initialized elements, ignoring any uninitialized ones, because those are just raw memory and should be ignored. + +`ArrayConsumer` does almost the same, "moving" values out of the array and into something else, like user code. It uses `ptr::read` to "move" the value out, and increments a counter saying that value is no longer valid in the array. + +If a panic occurs in the user code with that element, it's dropped naturally as it was moved into that scope. `ArrayConsumer` then proceeds to iteratively and manually `drop` all *remaining* elements. + +Combined, these two systems provide a safe system for building and consuming `GenericArray`s. In fact, they are used extensively inside the library itself for `FromIterator`, `GenericSequence` and `FunctionalSequence`, among others. + +Even `GenericArray`s implementation of `Clone` makes use of this via: + +```rust +impl Clone for GenericArray +where + N: ArrayLength, +{ + fn clone(&self) -> GenericArray { + self.map(|x| x.clone()) + } +} +``` + +where `.map` is from the `FunctionalSequence`, and uses those builder and consumer structures to safely move and initialize values. Although, in this particular case, a consumer is not necessary as we're using references. More on how that is automatically deduced is described in the next section. + +# Optimization + +Rust and LLVM is smart. Crazy smart. However, it's not magic. + +In my experience, most of Rust's "zero-cost" abstractions stem more from the type system, rather than explicit optimizations. Most Rust code is very easily optimizable and inlinable by design, so it can be simplified and compacted rather well, as opposed to the spaghetti code of some other languages. + +Unfortunately, unless `rustc` or LLVM can "prove" things about code to simplify it, it must still be run, and can prevent further optimization. + +A great example of this, and why I created the `GenericSequence` and `FunctionalSequence` traits, are iterators. + +Custom iterators are slow. Not terribly slow, but slow enough to prevent some rather important optimizations. + +Take `GenericArrayIter` for example: + +
    +Expand for code + +```rust +pub struct GenericArrayIter> { + array: ManuallyDrop>, + index: usize, + index_back: usize, +} + +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 + } + } + + //and more +} +``` +
    + +Seems simple enough, right? Move an element out of the array with `ptr::read` and increment the index. If the iterator is dropped, the remaining elements are dropped exactly as they would with `ArrayConsumer`. `index_back` is provided for `DoubleEndedIterator`. + +Unfortunately, that single `if` statement is terrible. In my mind, this is one of the biggest flaws of the iterator design. A conditional jump on a mutable variable unrelated to the data we are accessing on each call foils the optimizer and generates suboptimal code for the above iterator, even when we use `get_unchecked`. + +The optimizer is unable to see that we are simply accessing memory sequentially. In fact, almost all iterators are like this. Granted, this is usually fine and, especially if they have to handle errors, it's perfectly acceptable. + +However, there is one iterator in the standard library that is optimized perfectly: the slice iterator. So perfectly in fact that it allows the optimizer to do something even more special: **auto-vectorization**! We'll get to that later. + +It's a bit frustrating as to *why* slice iterators can be so perfectly optimized, and it basically boils down to that the iterator itself does not own the data the slice refers to, so it uses raw pointers to the array/sequence/etc. rather than having to use an index on a stack allocated and always moving array. It can check for if the iterator is empty by comparing some `front` and `back` pointers for equality, and because those directly correspond to the position in memory of the next element, LLVM can see that and make optimizations. + +So, the gist of that is: always use slice iterators where possible. + +Here comes the most important part of all of this: `ArrayBuilder` and `ArrayConsumer` don't iterate the arrays themselves. Instead, we use slice iterators (immutable and mutable), with `zip` or `enumerate`, to apply operations to the entire array, incrementing the position in both `ArrayBuilder` or `ArrayConsumer` to keep track. + +For example, `GenericSequence::generate` for `GenericArray` is: + +
    +Expand for code + +```rust +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() + } +} +``` + +where `ArrayBuilder::iter_position` is just an internal convenience function: + +```rust +pub unsafe fn iter_position(&mut self) -> (slice::IterMut, &mut usize) { + (self.array.iter_mut(), &mut self.position) +} +``` +
    + +Of course, this may appear to be redundant, if we're using an iterator that keeps track of the position itself, and the builder is also keeping track of the position. However, the two are decoupled. + +If the generation function doesn't have a chance at panicking, and/or the array element type doesn't implement `Drop`, the optimizer deems the `Drop` implementation on `ArrayBuilder` (and `ArrayConsumer`) dead code, and therefore `position` is never actually read from, so it becomes dead code as well, and is removed. + +So for simple non-`Drop`/non-panicking elements and generation functions, `generate` becomes a very simple loop that uses a slice iterator to write values to the array. + +Next, let's take a look at a more complex example where this *really* shines: `.zip` + +To cut down on excessively verbose code, `.zip` uses `FromIterator` for building the array, which has almost identical code to `generate`, so it will be omitted. + +The first implementation of `.zip` is defined as: + +
    +Expand for code + +```rust +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) + })) + } +} +``` +
    + +The gist of this is that we have two `GenericArray` instances that need to be zipped together and mapped to a new sequence. This employs two `ArrayConsumer`s, and more or less use the same pattern as the previous example. + +Again, the position values can be optimized out, and so can the slice iterator adapters. + +We can go a step further with this, however. + +Consider this: + +```rust +let a = arr![i32; 1, 3, 5, 7]; +let b = arr![i32; 2, 4, 6, 8]; + +let c = a.zip(b, |l, r| l + r); + +assert_eq!(c, arr![i32; 3, 7, 11, 15]); +``` + +when compiled with: + +``` +cargo rustc --lib --profile test --release -- -C target-cpu=native -C opt-level=3 --emit asm +``` + +will produce assembly with the following relevant instructions taken from the entire program: + +```asm +; Copy constant to register +vmovaps __xmm@00000007000000050000000300000001(%rip), %xmm0 + +; Copy constant to register +vmovaps __xmm@00000008000000060000000400000002(%rip), %xmm0 + +; Add the two values together +vpaddd 192(%rsp), %xmm0, %xmm1 + +; Copy constant to register +vmovaps __xmm@0000000f0000000b0000000700000003(%rip), %xmm0 + +; Compare result of the addition with the last constant +vpcmpeqb 128(%rsp), %xmm0, %xmm0 +``` + +so, aside from a bunch of obvious hygiene instructions around those selected instructions, +it seriously boils down that `.zip` call to a ***SINGLE*** SIMD instruction. In fact, it continues to do this for even larger arrays. Although it does fall back to individual additions for fewer than four elements, as it can't fit those into an SSE register evenly. + +Using this property of auto-vectorization without sacrificing safety, I created the [`numeric-array`](https://crates.io/crates/numeric-array) crate which makes use of this to wrap `GenericArray` and implement numeric traits so that almost *all* operations can be auto-vectorized, even complex ones like fused multiple-add. + +It doesn't end there, though. You may have noticed that the function name for zip above wasn't `zip`, but `inverted_zip`. + +This is because `generic-array` employs a clever specialization tactic to ensure `.zip` works corrects with: + +1. `a.zip(b, ...)` +2. `(&a).zip(b, ...)` +3. `(&a).zip(&b, ...)` +4. `a.zip(&b, ...)` + +wherein `GenericSequence` and `FunctionalSequence` have default implementations of `zip` variants, with concrete implementations for `GenericArray`. As `GenericSequence` is implemented for `&GenericArray`, where calling `into_iter` on produces a slice iterator, it can use "naive" iterator adapters to the same effect, while the specialized implementations use `ArrayConsumer`. + +The result is that any combination of move or reference calls to `.zip`, `.map` and `.fold` produce code that can be optimized, none of them falling back to slow non-slice iterators. All perfectly safe with the `ArrayBuilder` and `ArrayConsumer` systems. + +Honestly, `GenericArray` is better than standard arrays at this point. + +# The Future + +If/when const generics land in stable Rust, my intention is to reorient this crate or create a new crate to provide traits and wrappers for standard arrays to provide the same safety and performance discussed above. \ No newline at end of file diff --git a/vendor/generic-array/README.md b/vendor/generic-array/README.md index 64dd84faaf..cf54f40550 100644 --- a/vendor/generic-array/README.md +++ b/vendor/generic-array/README.md @@ -4,6 +4,8 @@ This crate implements generic array types for Rust. +**Requires minumum Rust version of 1.36.0, or 1.41.0 for `From<[T; N]>` implementations** + [Documentation](http://fizyk20.github.io/generic-array/generic_array/) ## Usage @@ -24,7 +26,33 @@ struct Foo> { } ``` -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]` :) +The `ArrayLength` trait is implemented by default for [unsigned integer types](http://fizyk20.github.io/generic-array/typenum/uint/index.html) from [typenum](http://fizyk20.github.io/generic-array/typenum/index.html) crate: + +```rust +use generic_array::typenum::U5; + +struct Foo> { + data: GenericArray +} + +fn main() { + let foo = Foo::{data: GenericArray::default()}; +} +``` + +For example, `GenericArray` would work almost like `[T; 5]`: + +```rust +use generic_array::typenum::U5; + +struct Foo> { + data: GenericArray +} + +fn main() { + let foo = Foo::{data: GenericArray::default()}; +} +``` In version 0.1.1 an `arr!` macro was introduced, allowing for creation of arrays as shown below: diff --git a/vendor/generic-array/build.rs b/vendor/generic-array/build.rs new file mode 100644 index 0000000000..c27c7e3fa9 --- /dev/null +++ b/vendor/generic-array/build.rs @@ -0,0 +1,5 @@ +fn main() { + if version_check::is_min_version("1.41.0").unwrap_or(false) { + println!("cargo:rustc-cfg=relaxed_coherence"); + } +} diff --git a/vendor/generic-array/src/arr.rs b/vendor/generic-array/src/arr.rs index a07d129ad3..aed4999205 100644 --- a/vendor/generic-array/src/arr.rs +++ b/vendor/generic-array/src/arr.rs @@ -1,57 +1,125 @@ -//! 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 { - ($T:ty; $N:ty, [$($x:expr),*], []) => ({ - unsafe { $crate::transmute::<_, $crate::GenericArray<$T, $N>>([$($x),*]) } - }); - ($T:ty; $N:ty, [], [$x1:expr]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], []) - ); - ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),+]) - ); - ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], []) - ); - ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [$($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];`") -} +//! 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) )*; + + #[inline(always)] + fn __do_transmute>(arr: [T; __ARR_LENGTH]) -> $crate::GenericArray { + unsafe { $crate::transmute(arr) } + } + + let _: [(); <$N as $crate::typenum::Unsigned>::USIZE] = [(); __ARR_LENGTH]; + + __do_transmute::<$T, $N>([$($x as $T),*]) + }); + ($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),* $(,)*) => ( + $crate::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/src/functional.rs b/vendor/generic-array/src/functional.rs index d161a83cac..2ddcc5c4c4 100644 --- a/vendor/generic-array/src/functional.rs +++ b/vendor/generic-array/src/functional.rs @@ -4,7 +4,8 @@ use super::ArrayLength; use core::iter::FromIterator; -use sequence::*; + +use crate::sequence::*; /// Defines the relationship between one generic sequence and another, /// for operations such as `map` and `zip`. diff --git a/vendor/generic-array/src/hex.rs b/vendor/generic-array/src/hex.rs index 09a6608e37..33c796f3c9 100644 --- a/vendor/generic-array/src/hex.rs +++ b/vendor/generic-array/src/hex.rs @@ -15,13 +15,12 @@ //! ``` //! -use {ArrayLength, GenericArray}; -use core::cmp::min; -use core::fmt; -use core::ops::Add; -use core::str; +use core::{fmt, str, ops::Add, cmp::min}; + use typenum::*; +use crate::{ArrayLength, GenericArray}; + static LOWER_CHARS: &'static [u8] = b"0123456789abcdef"; static UPPER_CHARS: &'static [u8] = b"0123456789ABCDEF"; @@ -30,19 +29,20 @@ where T: Add, >::Output: ArrayLength, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + 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 { + if T::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() { + self.iter().take(max_hex).enumerate().for_each(|(i, c)| { 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) @@ -50,10 +50,11 @@ where let mut digits_left = max_digits; for chunk in self[..max_hex].chunks(1024) { - for (i, c) in chunk.iter().enumerate() { + chunk.iter().enumerate().for_each(|(i, c)| { 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; @@ -68,19 +69,20 @@ where T: Add, >::Output: ArrayLength, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + 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 { + if T::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() { + self.iter().take(max_hex).enumerate().for_each(|(i, c)| { 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) @@ -88,10 +90,11 @@ where let mut digits_left = max_digits; for chunk in self[..max_hex].chunks(1024) { - for (i, c) in chunk.iter().enumerate() { + chunk.iter().enumerate().for_each(|(i, c)| { 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; diff --git a/vendor/generic-array/src/impl_serde.rs b/vendor/generic-array/src/impl_serde.rs index 7bf20ba013..49c095a5de 100644 --- a/vendor/generic-array/src/impl_serde.rs +++ b/vendor/generic-array/src/impl_serde.rs @@ -16,7 +16,7 @@ where where S: Serializer, { - let mut tup = serializer.serialize_tuple(N::to_usize())?; + let mut tup = serializer.serialize_tuple(N::USIZE)?; for el in self { tup.serialize_element(el)?; } @@ -46,7 +46,7 @@ where A: SeqAccess<'de>, { let mut result = GenericArray::default(); - for i in 0..N::to_usize() { + for i in 0..N::USIZE { result[i] = seq .next_element()? .ok_or_else(|| de::Error::invalid_length(i, &self))?; @@ -68,7 +68,7 @@ where _t: PhantomData, _n: PhantomData, }; - deserializer.deserialize_tuple(N::to_usize(), visitor) + deserializer.deserialize_tuple(N::USIZE, visitor) } } @@ -91,7 +91,7 @@ mod tests { array[0] = 1; array[1] = 2; let serialized = bincode::serialize(&array).unwrap(); - let deserialized = bincode::deserialize::>(&array); + let deserialized = bincode::deserialize::>(&serialized); assert!(deserialized.is_ok()); let array = deserialized.unwrap(); assert_eq!(array[0], 1); diff --git a/vendor/generic-array/src/impls.rs b/vendor/generic-array/src/impls.rs index 52896dfba3..47ecc1d31d 100644 --- a/vendor/generic-array/src/impls.rs +++ b/vendor/generic-array/src/impls.rs @@ -1,16 +1,18 @@ -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::*; + +use super::{ArrayLength, GenericArray}; + +use crate::functional::*; +use crate::sequence::*; impl Default for GenericArray where N: ArrayLength, { - #[inline] + #[inline(always)] fn default() -> Self { Self::generate(|_| T::default()) } @@ -40,11 +42,7 @@ where **self == **other } } -impl Eq for GenericArray -where - N: ArrayLength, -{ -} +impl Eq for GenericArray where N: ArrayLength {} impl PartialOrd for GenericArray where @@ -135,14 +133,50 @@ macro_rules! impl_from { } } + #[cfg(relaxed_coherence)] + impl From> for [T; $n] { + #[inline(always)] + fn from(sel: GenericArray) -> [T; $n] { + unsafe { $crate::transmute(sel) } + } + } + + impl<'a, T> From<&'a [T; $n]> for &'a GenericArray { + #[inline] + fn from(slice: &[T; $n]) -> &GenericArray { + unsafe { &*(slice.as_ptr() as *const GenericArray) } + } + } + + impl<'a, T> From<&'a mut [T; $n]> for &'a mut GenericArray { + #[inline] + fn from(slice: &mut [T; $n]) -> &mut GenericArray { + unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray) } + } + } + + #[cfg(not(relaxed_coherence))] impl Into<[T; $n]> for GenericArray { #[inline(always)] fn into(self) -> [T; $n] { unsafe { $crate::transmute(self) } } } - )* + impl AsRef<[T; $n]> for GenericArray { + #[inline] + fn as_ref(&self) -> &[T; $n] { + unsafe { $crate::transmute(self) } + } + } + + impl AsMut<[T; $n]> for GenericArray { + #[inline] + fn as_mut(&mut self) -> &mut [T; $n] { + unsafe { $crate::transmute(self) } + } + } + )* } } @@ -180,3 +214,56 @@ impl_from! { 31 => ::typenum::U31, 32 => ::typenum::U32 } + +#[cfg(feature = "more_lengths")] +impl_from! { + 33 => ::typenum::U33, + 34 => ::typenum::U34, + 35 => ::typenum::U35, + 36 => ::typenum::U36, + 37 => ::typenum::U37, + 38 => ::typenum::U38, + 39 => ::typenum::U39, + 40 => ::typenum::U40, + 41 => ::typenum::U41, + 42 => ::typenum::U42, + 43 => ::typenum::U43, + 44 => ::typenum::U44, + 45 => ::typenum::U45, + 46 => ::typenum::U46, + 47 => ::typenum::U47, + 48 => ::typenum::U48, + 49 => ::typenum::U49, + 50 => ::typenum::U50, + 51 => ::typenum::U51, + 52 => ::typenum::U52, + 53 => ::typenum::U53, + 54 => ::typenum::U54, + 55 => ::typenum::U55, + 56 => ::typenum::U56, + 57 => ::typenum::U57, + 58 => ::typenum::U58, + 59 => ::typenum::U59, + 60 => ::typenum::U60, + 61 => ::typenum::U61, + 62 => ::typenum::U62, + 63 => ::typenum::U63, + 64 => ::typenum::U64, + + 70 => ::typenum::U70, + 80 => ::typenum::U80, + 90 => ::typenum::U90, + + 100 => ::typenum::U100, + 200 => ::typenum::U200, + 300 => ::typenum::U300, + 400 => ::typenum::U400, + 500 => ::typenum::U500, + + 128 => ::typenum::U128, + 256 => ::typenum::U256, + 512 => ::typenum::U512, + + 1000 => ::typenum::U1000, + 1024 => ::typenum::U1024 +} diff --git a/vendor/generic-array/src/iter.rs b/vendor/generic-array/src/iter.rs index 46f3e768d7..90e94fc6c1 100644 --- a/vendor/generic-array/src/iter.rs +++ b/vendor/generic-array/src/iter.rs @@ -1,8 +1,9 @@ //! `GenericArray` iterator implementation. use super::{ArrayLength, GenericArray}; -use core::{cmp, ptr, fmt, mem}; -use core::mem::ManuallyDrop; +use core::iter::FusedIterator; +use core::mem::{MaybeUninit, ManuallyDrop}; +use core::{cmp, fmt, ptr, mem}; /// An iterator that moves out of a `GenericArray` pub struct GenericArrayIter> { @@ -54,7 +55,7 @@ where GenericArrayIter { array: ManuallyDrop::new(self), index: 0, - index_back: N::to_usize(), + index_back: N::USIZE, } } } @@ -77,10 +78,12 @@ where { #[inline] fn drop(&mut self) { - // Drop values that are still alive. - for p in self.as_mut_slice() { - unsafe { - ptr::drop_in_place(p); + if mem::needs_drop::() { + // Drop values that are still alive. + for p in self.as_mut_slice() { + unsafe { + ptr::drop_in_place(p); + } } } } @@ -95,19 +98,20 @@ where // 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, - }; + let mut array: MaybeUninit> = MaybeUninit::uninit(); + let mut index_back = 0; - for (dst, src) in iter.array.iter_mut().zip(self.as_slice()) { + for (dst, src) in (&mut *array.as_mut_ptr()).iter_mut().zip(self.as_slice()) { ptr::write(dst, src.clone()); - iter.index_back += 1; + index_back += 1; } - iter + GenericArrayIter { + array: ManuallyDrop::new(array.assume_init()), + index: 0, + index_back + } } } } @@ -131,6 +135,34 @@ where } } + fn fold(mut self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + let ret = unsafe { + let GenericArrayIter { + ref array, + ref mut index, + index_back, + } = self; + + let remaining = &array[*index..index_back]; + + remaining.iter().fold(init, |acc, src| { + let value = ptr::read(src); + + *index += 1; + + f(acc, value) + }) + }; + + // ensure the drop happens here after iteration + drop(self); + + ret + } + #[inline] fn size_hint(&self) -> (usize, Option) { let len = self.len(); @@ -157,6 +189,7 @@ where self.next() } + #[inline] fn last(mut self) -> Option { // Note, everything else will correctly drop first as `self` leaves scope. self.next_back() @@ -176,6 +209,34 @@ where None } } + + fn rfold(mut self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + let ret = unsafe { + let GenericArrayIter { + ref array, + index, + ref mut index_back, + } = self; + + let remaining = &array[index..*index_back]; + + remaining.iter().rfold(init, |acc, src| { + let value = ptr::read(src); + + *index_back -= 1; + + f(acc, value) + }) + }; + + // ensure the drop happens here after iteration + drop(self); + + ret + } } impl ExactSizeIterator for GenericArrayIter @@ -187,4 +248,10 @@ where } } -// TODO: Implement `FusedIterator` and `TrustedLen` when stabilized \ No newline at end of file +impl FusedIterator for GenericArrayIter +where + N: ArrayLength, +{ +} + +// TODO: Implement `TrustedLen` when stabilized diff --git a/vendor/generic-array/src/lib.rs b/vendor/generic-array/src/lib.rs index 5b95805375..4e634448a4 100644 --- a/vendor/generic-array/src/lib.rs +++ b/vendor/generic-array/src/lib.rs @@ -1,8 +1,8 @@ -//! This crate implements a structure that can be used as a generic array type.use +//! This crate implements a structure that can be used as a generic array type. //! Core Rust array types `[T; N]` can't be used generically with //! respect to `N`, so for example this: //! -//! ```{should_fail} +//! ```rust{compile_fail} //! struct Foo { //! data: [T; N] //! } @@ -13,8 +13,9 @@ //! **generic-array** exports a `GenericArray` type, which lets //! the above be implemented as: //! -//! ``` -//! # use generic_array::{ArrayLength, GenericArray}; +//! ```rust +//! use generic_array::{ArrayLength, GenericArray}; +//! //! struct Foo> { //! data: GenericArray //! } @@ -22,7 +23,35 @@ //! //! The `ArrayLength` trait is implemented by default for //! [unsigned integer types](../typenum/uint/index.html) from -//! [typenum](../typenum/index.html). +//! [typenum](../typenum/index.html): +//! +//! ```rust +//! # use generic_array::{ArrayLength, GenericArray}; +//! use generic_array::typenum::U5; +//! +//! struct Foo> { +//! data: GenericArray +//! } +//! +//! # fn main() { +//! let foo = Foo::{data: GenericArray::default()}; +//! # } +//! ``` +//! +//! For example, `GenericArray` would work almost like `[T; 5]`: +//! +//! ```rust +//! # use generic_array::{ArrayLength, GenericArray}; +//! use generic_array::typenum::U5; +//! +//! struct Foo> { +//! data: GenericArray +//! } +//! +//! # fn main() { +//! let foo = Foo::{data: GenericArray::default()}; +//! # } +//! ``` //! //! For ease of use, an `arr!` macro is provided - example below: //! @@ -37,6 +66,7 @@ //! ``` #![deny(missing_docs)] +#![deny(meta_variable_misuse)] #![no_std] #[cfg(feature = "serde")] @@ -51,11 +81,11 @@ mod hex; mod impls; #[cfg(feature = "serde")] -pub mod impl_serde; +mod impl_serde; use core::iter::FromIterator; use core::marker::PhantomData; -use core::mem::ManuallyDrop; +use core::mem::{MaybeUninit, ManuallyDrop}; use core::ops::{Deref, DerefMut}; use core::{mem, ptr, slice}; use typenum::bit::{B0, B1}; @@ -67,9 +97,9 @@ pub mod functional; pub mod iter; pub mod sequence; -use functional::*; -pub use iter::GenericArrayIter; -use sequence::*; +use self::functional::*; +pub use self::iter::GenericArrayIter; +use self::sequence::*; /// Trait making `GenericArray` work, marking types to be used as length of an array pub unsafe trait ArrayLength: Unsigned { @@ -79,7 +109,7 @@ pub unsafe trait ArrayLength: Unsigned { unsafe impl ArrayLength for UTerm { #[doc(hidden)] - type ArrayType = (); + type ArrayType = [T; 0]; } /// Internal type used to generate a struct of appropriate size @@ -138,6 +168,7 @@ unsafe impl> ArrayLength for UInt { /// Struct representing a generic array - `GenericArray` works like [T; N] #[allow(dead_code)] +#[repr(transparent)] pub struct GenericArray> { data: U::ArrayType, } @@ -153,7 +184,7 @@ where #[inline(always)] fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self as *const Self as *const T, N::to_usize()) } + unsafe { slice::from_raw_parts(self as *const Self as *const T, N::USIZE) } } } @@ -163,7 +194,7 @@ where { #[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()) } + unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut T, N::USIZE) } } } @@ -174,7 +205,7 @@ where /// which will be dropped if `into_inner` is not called. #[doc(hidden)] pub struct ArrayBuilder> { - array: ManuallyDrop>, + array: MaybeUninit>, position: usize, } @@ -183,7 +214,7 @@ impl> ArrayBuilder { #[inline] pub unsafe fn new() -> ArrayBuilder { ArrayBuilder { - array: ManuallyDrop::new(mem::uninitialized()), + array: MaybeUninit::uninit(), position: 0, } } @@ -195,7 +226,7 @@ impl> ArrayBuilder { #[doc(hidden)] #[inline] pub unsafe fn iter_position(&mut self) -> (slice::IterMut, &mut usize) { - (self.array.iter_mut(), &mut self.position) + ((&mut *self.array.as_mut_ptr()).iter_mut(), &mut self.position) } /// When done writing (assuming all elements have been written to), @@ -207,15 +238,17 @@ impl> ArrayBuilder { mem::forget(self); - ManuallyDrop::into_inner(array) + array.assume_init() } } impl> Drop for ArrayBuilder { fn drop(&mut self) { - for value in &mut self.array[..self.position] { + if mem::needs_drop::() { unsafe { - ptr::drop_in_place(value); + for value in &mut (&mut *self.array.as_mut_ptr())[..self.position] { + ptr::drop_in_place(value); + } } } } @@ -254,9 +287,11 @@ impl> ArrayConsumer { 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); + if mem::needs_drop::() { + for value in &mut self.array[self.position..N::USIZE] { + unsafe { + ptr::drop_in_place(value); + } } } } @@ -300,15 +335,17 @@ where { let (destination_iter, position) = destination.iter_position(); - for (src, dst) in iter.into_iter().zip(destination_iter) { - ptr::write(dst, src); + iter.into_iter() + .zip(destination_iter) + .for_each(|(src, dst)| { + ptr::write(dst, src); - *position += 1; - } + *position += 1; + }); } - if destination.position < N::to_usize() { - from_iter_length_fail(destination.position, N::to_usize()); + if destination.position < N::USIZE { + from_iter_length_fail(destination.position, N::USIZE); } destination.into_inner() @@ -343,11 +380,11 @@ where { let (destination_iter, position) = destination.iter_position(); - for (i, dst) in destination_iter.enumerate() { + destination_iter.enumerate().for_each(|(i, dst)| { ptr::write(dst, f(i)); *position += 1; - } + }); } destination.into_inner() @@ -519,7 +556,7 @@ impl<'a, T, N: ArrayLength> From<&'a [T]> for &'a GenericArray { /// 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()); + assert_eq!(slice.len(), N::USIZE); unsafe { &*(slice.as_ptr() as *const GenericArray) } } @@ -531,7 +568,7 @@ impl<'a, T, N: ArrayLength> From<&'a mut [T]> for &'a mut GenericArray /// 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()); + assert_eq!(slice.len(), N::USIZE); unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray) } } @@ -555,34 +592,39 @@ impl GenericArray where N: ArrayLength, { - /// Creates a new `GenericArray` instance from an iterator with a known exact size. + /// Creates a new `GenericArray` instance from an iterator with a specific 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(); + let mut iter = iter.into_iter(); - if iter.len() == N::to_usize() { - unsafe { - let mut destination = ArrayBuilder::new(); + unsafe { + let mut destination = ArrayBuilder::new(); - { - let (destination_iter, position) = destination.iter_position(); + { + let (destination_iter, position) = destination.iter_position(); - for (dst, src) in destination_iter.zip(iter.into_iter()) { - ptr::write(dst, src); + destination_iter.zip(&mut iter).for_each(|(dst, src)| { + ptr::write(dst, src); - *position += 1; - } + *position += 1; + }); + + // The iterator produced fewer than `N` elements. + if *position != N::USIZE { + return None; } - Some(destination.into_inner()) + // The iterator produced more than `N` elements. + if iter.next().is_some() { + return None; + } } - } else { - None + + Some(destination.into_inner()) } } } @@ -592,9 +634,8 @@ where #[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 + let a = ManuallyDrop::new(a); + ::core::ptr::read(&*a as *const A as *const B) } #[cfg(test)] @@ -616,7 +657,7 @@ mod test { #[test] fn test_assembly() { - use functional::*; + use crate::functional::*; let a = black_box(arr![i32; 1, 3, 5, 7]); let b = black_box(arr![i32; 2, 4, 6, 8]); diff --git a/vendor/generic-array/src/sequence.rs b/vendor/generic-array/src/sequence.rs index cec6601ba3..0119d3db67 100644 --- a/vendor/generic-array/src/sequence.rs +++ b/vendor/generic-array/src/sequence.rs @@ -1,8 +1,9 @@ //! Useful traits for manipulating sequences of data stored in `GenericArray`s use super::*; -use core::{mem, ptr}; use core::ops::{Add, Sub}; +use core::mem::MaybeUninit; +use core::ptr; use typenum::operator_aliases::*; /// Defines some sequence with an associated length and iteration capabilities. @@ -41,17 +42,15 @@ pub unsafe trait GenericSequence: Sized + IntoIterator { let (left_array_iter, left_position) = left.iter_position(); - FromIterator::from_iter( - left_array_iter - .zip(self.into_iter()) - .map(|(l, right_value)| { + 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) - }) - ) + }, + )) } } @@ -117,12 +116,15 @@ pub unsafe trait Lengthen: Sized + GenericSequence { /// /// Example: /// - /// ```ignore + /// ```rust + /// # use generic_array::{arr, sequence::Lengthen}; + /// # fn main() { /// 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; @@ -130,12 +132,15 @@ pub unsafe trait Lengthen: Sized + GenericSequence { /// /// Example: /// - /// ```ignore + /// ```rust + /// # use generic_array::{arr, sequence::Lengthen}; + /// # fn main() { /// 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; } @@ -152,26 +157,32 @@ pub unsafe trait Shorten: Sized + GenericSequence { /// /// Example: /// - /// ```ignore + /// ```rust + /// # use generic_array::{arr, sequence::Shorten}; + /// # fn main() { /// 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 + /// ```rust + /// # use generic_array::{arr, sequence::Shorten}; + /// # fn main() { /// 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); } @@ -186,27 +197,35 @@ where type Longer = GenericArray>; fn append(self, last: T) -> Self::Longer { - let mut longer: Self::Longer = unsafe { mem::uninitialized() }; + let mut longer: MaybeUninit = MaybeUninit::uninit(); + + // Note this is *mut Self, so add(1) increments by the whole array + let out_ptr = longer.as_mut_ptr() as *mut Self; unsafe { - ptr::write(longer.as_mut_ptr() as *mut _, self); - ptr::write(&mut longer[N::to_usize()], last); - } + // write self first + ptr::write(out_ptr, self); + // increment past self, then write the last + ptr::write(out_ptr.add(1) as *mut T, last); - longer + longer.assume_init() + } } fn prepend(self, first: T) -> Self::Longer { - let mut longer: Self::Longer = unsafe { mem::uninitialized() }; + let mut longer: MaybeUninit = MaybeUninit::uninit(); - let longer_ptr = longer.as_mut_ptr(); + // Note this is *mut T, so add(1) increments by a single T + let out_ptr = longer.as_mut_ptr() as *mut T; unsafe { - ptr::write(longer_ptr as *mut _, first); - ptr::write(longer_ptr.offset(1) as *mut _, self); - } + // write the first at the start + ptr::write(out_ptr, first); + // increment past the first, then write self + ptr::write(out_ptr.add(1) as *mut Self, self); - longer + longer.assume_init() + } } } @@ -220,27 +239,26 @@ where 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 whole = ManuallyDrop::new(self); - let init = unsafe { ptr::read(init_ptr as _) }; - let last = unsafe { ptr::read(last_ptr as _) }; - - mem::forget(self); + unsafe { + let init = ptr::read(whole.as_ptr() as _); + let last = ptr::read(whole.as_ptr().add(Sub1::::USIZE) as _); - (init, last) + (init, last) + } } fn pop_front(self) -> (T, Self::Shorter) { - let head_ptr = self.as_ptr(); - let tail_ptr = unsafe { head_ptr.offset(1) }; + // ensure this doesn't get dropped + let whole = ManuallyDrop::new(self); - let head = unsafe { ptr::read(head_ptr as _) }; - let tail = unsafe { ptr::read(tail_ptr as _) }; - - mem::forget(self); + unsafe { + let head = ptr::read(whole.as_ptr() as _); + let tail = ptr::read(whole.as_ptr().offset(1) as _); - (head, tail) + (head, tail) + } } } @@ -269,15 +287,55 @@ where 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) }; + unsafe { + // ensure this doesn't get dropped + let whole = ManuallyDrop::new(self); + + let head = ptr::read(whole.as_ptr() as *const _); + let tail = ptr::read(whole.as_ptr().add(K::USIZE) as *const _); + + (head, tail) + } + } +} + +unsafe impl<'a, T, N, K> Split for &'a GenericArray +where + N: ArrayLength, + K: ArrayLength + 'static, + N: Sub, + Diff: ArrayLength, +{ + type First = &'a GenericArray; + type Second = &'a GenericArray>; - let head = unsafe { ptr::read(head_ptr as _) }; - let tail = unsafe { ptr::read(tail_ptr as _) }; + fn split(self) -> (Self::First, Self::Second) { + unsafe { + let ptr_to_first: *const T = self.as_ptr(); + let head = &*(ptr_to_first as *const _); + let tail = &*(ptr_to_first.add(K::USIZE) as *const _); + (head, tail) + } + } +} - mem::forget(self); +unsafe impl<'a, T, N, K> Split for &'a mut GenericArray +where + N: ArrayLength, + K: ArrayLength + 'static, + N: Sub, + Diff: ArrayLength, +{ + type First = &'a mut GenericArray; + type Second = &'a mut GenericArray>; - (head, tail) + fn split(self) -> (Self::First, Self::Second) { + unsafe { + let ptr_to_first: *mut T = self.as_mut_ptr(); + let head = &mut *(ptr_to_first as *mut _); + let tail = &mut *(ptr_to_first.add(K::USIZE) as *mut _); + (head, tail) + } } } @@ -306,15 +364,17 @@ where type Output = GenericArray>; fn concat(self, rest: Self::Rest) -> Self::Output { - let mut output: Self::Output = unsafe { mem::uninitialized() }; + let mut output: MaybeUninit = MaybeUninit::uninit(); - let output_ptr = output.as_mut_ptr(); + let out_ptr = output.as_mut_ptr() as *mut Self; unsafe { - ptr::write(output_ptr as *mut _, self); - ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest); - } + // write all of self to the pointer + ptr::write(out_ptr, self); + // increment past self, then write the rest + ptr::write(out_ptr.add(1) as *mut _, rest); - output + output.assume_init() + } } } diff --git a/vendor/generic-array/tests/iter.rs b/vendor/generic-array/tests/iter.rs index 19d198cb58..d96f984147 100644 --- a/vendor/generic-array/tests/iter.rs +++ b/vendor/generic-array/tests/iter.rs @@ -4,8 +4,28 @@ extern crate generic_array; use std::cell::Cell; use std::ops::Drop; -use generic_array::GenericArray; use generic_array::typenum::consts::U5; +use generic_array::GenericArray; + +#[test] +fn test_from_iterator() { + struct BadExact(usize); + + impl Iterator for BadExact { + type Item = usize; + fn next(&mut self) -> Option { + if self.0 == 1 { + return None; + } + self.0 -= 1; + Some(self.0) + } + } + impl ExactSizeIterator for BadExact { + fn len(&self) -> usize { self.0 } + } + assert!(GenericArray::::from_exact_iter(BadExact(5)).is_none()); +} #[test] fn test_into_iter_as_slice() { @@ -92,22 +112,37 @@ 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_fold() { + assert_eq!( + arr![i32; 1, 2, 3, 4].into_iter().fold(0, |sum, x| sum + x), + 10 + ); + + let mut iter = arr![i32; 0, 1, 2, 3, 4, 5].into_iter(); + + iter.next(); + iter.next_back(); + + assert_eq!(iter.clone().fold(0, |sum, x| sum + x), 10); + + assert_eq!(iter.rfold(0, |sum, x| sum + x), 10); +} + #[test] fn test_into_iter_drops() { struct R<'a> { - i: &'a Cell, + i: &'a Cell, } impl<'a> Drop for R<'a> { - fn drop(&mut self) { + fn drop(&mut self) { self.i.set(self.i.get() + 1); } } fn r(i: &Cell) -> R { - R { - i: i - } + R { i: i } } fn v(i: &Cell) -> GenericArray { @@ -161,4 +196,4 @@ fn assert_covariance() { i } } -*/ \ No newline at end of file +*/ diff --git a/vendor/generic-array/tests/mod.rs b/vendor/generic-array/tests/mod.rs index c103f417ab..fb1a35f2ca 100644 --- a/vendor/generic-array/tests/mod.rs +++ b/vendor/generic-array/tests/mod.rs @@ -4,10 +4,10 @@ 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}; +use generic_array::typenum::{U0, U3, U4, U97}; +use generic_array::GenericArray; #[test] fn test() { @@ -88,8 +88,8 @@ fn test_from_mut_slice() { #[test] fn test_default() { - let arr = GenericArray::::default(); - assert_eq!(arr[0], 0); + let arr = GenericArray::::default(); + assert_eq!(arr.as_slice(), &[0, 0, 0, 0]); } #[test] @@ -112,7 +112,7 @@ fn test_empty_macro() { #[test] fn test_cmp() { - arr![u8; 0x00].cmp(&arr![u8; 0x00]); + let _ = arr![u8; 0x00].cmp(&arr![u8; 0x00]); } /// This test should cause a helpful compile error if uncommented. @@ -124,8 +124,8 @@ fn test_cmp() { mod impl_serde { extern crate serde_json; - use generic_array::GenericArray; use generic_array::typenum::U6; + use generic_array::GenericArray; #[test] fn test_serde_implementation() { @@ -175,23 +175,40 @@ fn test_from_iter() { assert_eq!(a, arr![i32; 11, 11, 11, 0]); } +#[allow(unused)] +#[derive(Debug, Copy, Clone)] +enum E { + V, + V2(i32), + V3 { h: bool, i: i32 }, +} + +#[allow(unused)] +#[derive(Debug, Copy, Clone)] +#[repr(C)] +#[repr(packed)] +struct Test { + t: u16, + s: u32, + mm: bool, + r: u16, + f: u16, + p: (), + o: u32, + ff: *const extern "C" fn(*const char) -> *const core::ffi::c_void, + l: *const core::ffi::c_void, + w: bool, + q: bool, + v: E, +} + #[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::(), 8); - assert_eq!(size_of::(), 14); + assert_eq!(size_of::(), 25 + size_of::() * 2); assert_eq!(size_of_val(&arr![u8; 1, 2, 3]), size_of::() * 3); assert_eq!(size_of_val(&arr![u32; 1]), size_of::() * 1); @@ -200,6 +217,15 @@ fn test_sizes() { assert_eq!(size_of::>(), size_of::() * 97); } +#[test] +fn test_alignment() { + use core::mem::align_of; + + assert_eq!(align_of::>(), align_of::<[u32; 0]>()); + assert_eq!(align_of::>(), align_of::<[u32; 3]>()); + assert_eq!(align_of::>(), align_of::<[Test; 3]>()); +} + #[test] fn test_append() { let a = arr![i32; 1, 2, 3]; @@ -248,19 +274,51 @@ fn test_split() { assert_eq!(f, arr![i32; 3, 4]); } +#[test] +fn test_split_ref() { + let a = arr![i32; 1, 2, 3, 4]; + let a_ref = &a; + + let (b_ref, c_ref) = a_ref.split(); + + assert_eq!(b_ref, &arr![i32; 1]); + assert_eq!(c_ref, &arr![i32; 2, 3, 4]); + + let (e_ref, f_ref) = a_ref.split(); + + assert_eq!(e_ref, &arr![i32; 1, 2]); + assert_eq!(f_ref, &arr![i32; 3, 4]); +} + +#[test] +fn test_split_mut() { + let mut a = arr![i32; 1, 2, 3, 4]; + let a_ref = &mut a; + + let (b_ref, c_ref) = a_ref.split(); + + assert_eq!(b_ref, &mut arr![i32; 1]); + assert_eq!(c_ref, &mut arr![i32; 2, 3, 4]); + + let (e_ref, f_ref) = a_ref.split(); + + assert_eq!(e_ref, &mut arr![i32; 1, 2]); + assert_eq!(f_ref, &mut arr![i32; 3, 4]); +} + #[test] fn test_concat() { let a = arr![i32; 1, 2]; - let b = arr![i32; 3, 4]; + let b = arr![i32; 3, 4, 5]; let c = a.concat(b); - assert_eq!(c, arr![i32; 1, 2, 3, 4]); + assert_eq!(c, arr![i32; 1, 2, 3, 4, 5]); let (d, e) = c.split(); - assert_eq!(d, arr![i32; 1]); - assert_eq!(e, arr![i32; 2, 3, 4]); + assert_eq!(d, arr![i32; 1, 2]); + assert_eq!(e, arr![i32; 3, 4, 5]); } #[test] @@ -285,3 +343,37 @@ fn test_sum() { assert_eq!(a, 10); } + +#[test] +fn test_as_ref() { + let a = arr![i32; 1, 2, 3, 4]; + let a_ref: &[i32; 4] = a.as_ref(); + assert_eq!(a_ref, &[1, 2, 3, 4]); +} + +#[test] +fn test_as_mut() { + let mut a = arr![i32; 1, 2, 3, 4]; + let a_mut: &mut [i32; 4] = a.as_mut(); + assert_eq!(a_mut, &mut [1, 2, 3, 4]); + a_mut[2] = 0; + assert_eq!(a_mut, &mut [1, 2, 0, 4]); + assert_eq!(a, arr![i32; 1, 2, 0, 4]); +} + +#[test] +fn test_from_array_ref() { + let a = arr![i32; 1, 2, 3, 4]; + let a_ref: &[i32; 4] = a.as_ref(); + let a_from: &GenericArray = a_ref.into(); + assert_eq!(&a, a_from); +} + +#[test] +fn test_from_array_mut() { + let mut a = arr![i32; 1, 2, 3, 4]; + let mut a_copy = a; + let a_mut: &mut [i32; 4] = a.as_mut(); + let a_from: &mut GenericArray = a_mut.into(); + assert_eq!(&mut a_copy, a_from); +} diff --git a/vendor/getrandom/.cargo-checksum.json b/vendor/getrandom-0.1.14/.cargo-checksum.json similarity index 100% rename from vendor/getrandom/.cargo-checksum.json rename to vendor/getrandom-0.1.14/.cargo-checksum.json diff --git a/vendor/getrandom/CHANGELOG.md b/vendor/getrandom-0.1.14/CHANGELOG.md similarity index 100% rename from vendor/getrandom/CHANGELOG.md rename to vendor/getrandom-0.1.14/CHANGELOG.md diff --git a/vendor/getrandom/Cargo.toml b/vendor/getrandom-0.1.14/Cargo.toml similarity index 100% rename from vendor/getrandom/Cargo.toml rename to vendor/getrandom-0.1.14/Cargo.toml diff --git a/vendor/getrandom/LICENSE-APACHE b/vendor/getrandom-0.1.14/LICENSE-APACHE similarity index 100% rename from vendor/getrandom/LICENSE-APACHE rename to vendor/getrandom-0.1.14/LICENSE-APACHE diff --git a/vendor/getrandom/LICENSE-MIT b/vendor/getrandom-0.1.14/LICENSE-MIT similarity index 100% rename from vendor/getrandom/LICENSE-MIT rename to vendor/getrandom-0.1.14/LICENSE-MIT diff --git a/vendor/getrandom/README.md b/vendor/getrandom-0.1.14/README.md similarity index 100% rename from vendor/getrandom/README.md rename to vendor/getrandom-0.1.14/README.md diff --git a/vendor/getrandom/benches/mod.rs b/vendor/getrandom-0.1.14/benches/mod.rs similarity index 100% rename from vendor/getrandom/benches/mod.rs rename to vendor/getrandom-0.1.14/benches/mod.rs diff --git a/vendor/getrandom/build.rs b/vendor/getrandom-0.1.14/build.rs similarity index 100% rename from vendor/getrandom/build.rs rename to vendor/getrandom-0.1.14/build.rs diff --git a/vendor/getrandom/src/bsd_arandom.rs b/vendor/getrandom-0.1.14/src/bsd_arandom.rs similarity index 100% rename from vendor/getrandom/src/bsd_arandom.rs rename to vendor/getrandom-0.1.14/src/bsd_arandom.rs diff --git a/vendor/getrandom/src/cloudabi.rs b/vendor/getrandom-0.1.14/src/cloudabi.rs similarity index 100% rename from vendor/getrandom/src/cloudabi.rs rename to vendor/getrandom-0.1.14/src/cloudabi.rs diff --git a/vendor/getrandom/src/dummy.rs b/vendor/getrandom-0.1.14/src/dummy.rs similarity index 100% rename from vendor/getrandom/src/dummy.rs rename to vendor/getrandom-0.1.14/src/dummy.rs diff --git a/vendor/getrandom/src/error.rs b/vendor/getrandom-0.1.14/src/error.rs similarity index 100% rename from vendor/getrandom/src/error.rs rename to vendor/getrandom-0.1.14/src/error.rs diff --git a/vendor/getrandom/src/error_impls.rs b/vendor/getrandom-0.1.14/src/error_impls.rs similarity index 100% rename from vendor/getrandom/src/error_impls.rs rename to vendor/getrandom-0.1.14/src/error_impls.rs diff --git a/vendor/getrandom/src/fuchsia.rs b/vendor/getrandom-0.1.14/src/fuchsia.rs similarity index 100% rename from vendor/getrandom/src/fuchsia.rs rename to vendor/getrandom-0.1.14/src/fuchsia.rs diff --git a/vendor/getrandom/src/ios.rs b/vendor/getrandom-0.1.14/src/ios.rs similarity index 100% rename from vendor/getrandom/src/ios.rs rename to vendor/getrandom-0.1.14/src/ios.rs diff --git a/vendor/getrandom/src/lib.rs b/vendor/getrandom-0.1.14/src/lib.rs similarity index 100% rename from vendor/getrandom/src/lib.rs rename to vendor/getrandom-0.1.14/src/lib.rs diff --git a/vendor/getrandom/src/linux_android.rs b/vendor/getrandom-0.1.14/src/linux_android.rs similarity index 100% rename from vendor/getrandom/src/linux_android.rs rename to vendor/getrandom-0.1.14/src/linux_android.rs diff --git a/vendor/getrandom/src/macos.rs b/vendor/getrandom-0.1.14/src/macos.rs similarity index 100% rename from vendor/getrandom/src/macos.rs rename to vendor/getrandom-0.1.14/src/macos.rs diff --git a/vendor/getrandom/src/openbsd.rs b/vendor/getrandom-0.1.14/src/openbsd.rs similarity index 100% rename from vendor/getrandom/src/openbsd.rs rename to vendor/getrandom-0.1.14/src/openbsd.rs diff --git a/vendor/getrandom/src/rdrand.rs b/vendor/getrandom-0.1.14/src/rdrand.rs similarity index 100% rename from vendor/getrandom/src/rdrand.rs rename to vendor/getrandom-0.1.14/src/rdrand.rs diff --git a/vendor/getrandom/src/solaris_illumos.rs b/vendor/getrandom-0.1.14/src/solaris_illumos.rs similarity index 100% rename from vendor/getrandom/src/solaris_illumos.rs rename to vendor/getrandom-0.1.14/src/solaris_illumos.rs diff --git a/vendor/getrandom/src/use_file.rs b/vendor/getrandom-0.1.14/src/use_file.rs similarity index 100% rename from vendor/getrandom/src/use_file.rs rename to vendor/getrandom-0.1.14/src/use_file.rs diff --git a/vendor/getrandom/src/util.rs b/vendor/getrandom-0.1.14/src/util.rs similarity index 100% rename from vendor/getrandom/src/util.rs rename to vendor/getrandom-0.1.14/src/util.rs diff --git a/vendor/getrandom/src/util_libc.rs b/vendor/getrandom-0.1.14/src/util_libc.rs similarity index 100% rename from vendor/getrandom/src/util_libc.rs rename to vendor/getrandom-0.1.14/src/util_libc.rs diff --git a/vendor/getrandom/src/vxworks.rs b/vendor/getrandom-0.1.14/src/vxworks.rs similarity index 100% rename from vendor/getrandom/src/vxworks.rs rename to vendor/getrandom-0.1.14/src/vxworks.rs diff --git a/vendor/getrandom/src/wasi.rs b/vendor/getrandom-0.1.14/src/wasi.rs similarity index 100% rename from vendor/getrandom/src/wasi.rs rename to vendor/getrandom-0.1.14/src/wasi.rs diff --git a/vendor/getrandom/src/wasm32_bindgen.rs b/vendor/getrandom-0.1.14/src/wasm32_bindgen.rs similarity index 100% rename from vendor/getrandom/src/wasm32_bindgen.rs rename to vendor/getrandom-0.1.14/src/wasm32_bindgen.rs diff --git a/vendor/getrandom/src/wasm32_stdweb.rs b/vendor/getrandom-0.1.14/src/wasm32_stdweb.rs similarity index 100% rename from vendor/getrandom/src/wasm32_stdweb.rs rename to vendor/getrandom-0.1.14/src/wasm32_stdweb.rs diff --git a/vendor/getrandom/src/windows.rs b/vendor/getrandom-0.1.14/src/windows.rs similarity index 100% rename from vendor/getrandom/src/windows.rs rename to vendor/getrandom-0.1.14/src/windows.rs diff --git a/vendor/getrandom/src/windows_uwp.rs b/vendor/getrandom-0.1.14/src/windows_uwp.rs similarity index 100% rename from vendor/getrandom/src/windows_uwp.rs rename to vendor/getrandom-0.1.14/src/windows_uwp.rs diff --git a/vendor/getrandom/tests/common.rs b/vendor/getrandom-0.1.14/tests/common.rs similarity index 100% rename from vendor/getrandom/tests/common.rs rename to vendor/getrandom-0.1.14/tests/common.rs diff --git a/vendor/hashbrown/.cargo-checksum.json b/vendor/hashbrown/.cargo-checksum.json index 53ccb357be..4811ac7d60 100644 --- a/vendor/hashbrown/.cargo-checksum.json +++ b/vendor/hashbrown/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"41956c7543a3c6688ef073100128201fb25b105c244c955f61a5970f82410e89","Cargo.toml":"b6a0baee0e7d34a00841ab3716bae87d723ede5cfe3f1f353474748e17100147","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"66f79e21927df369fccac1cfff147c6fe66e15b4fc003851a008b9cbac831ea9","benches/bench.rs":"a3f8426559ebf68d93e37edee0bf83c28f18572b394b22e47dbff33e25cac403","build.rs":"85096ca579db79e502f0af4521b62820b2b0efcfe0f3d4de2f8ec4965f13b61f","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"d69528827794524cfd9acbeacc1ac4f6131e3c7574311e6d919f818f65fbff07","src/external_trait_impls/rayon/helpers.rs":"d4fbca4db924925548f8dab8eb94cf4a3955a53c5e1ff15f59c460546c394034","src/external_trait_impls/rayon/map.rs":"eee0d42bd8cd347d49cfb1332f15297ca63b864c3690299a3ccd6d52c22c67de","src/external_trait_impls/rayon/mod.rs":"156de9c1ad0123334ea3b7e5a17444faf1b8bf971aa88a1f23e2f2d1c3021141","src/external_trait_impls/rayon/raw.rs":"d1b2415a4c3c42279f99a23bcf45c80ddb9a641c7f7974d42ed4d55f57bf6854","src/external_trait_impls/rayon/set.rs":"59afc7b1cdc985a85952d456e34eada4ca2fedf90d2a14dccf98a69f8f496137","src/external_trait_impls/serde.rs":"9306fb6e0e339398dc23ba9e7400a9a28d713df248e8b260e3d4dc44f799e101","src/lib.rs":"d8d7f9de34b79cb3c8187ff74a4c91d99386da1c40486b0d3c762b70dc5626d9","src/macros.rs":"0b1e9a55e8f5232b82f7e56f352a98904b35ddfca015377cf71daa31939baabf","src/map.rs":"57a1da730c123fdd9dae08a90ca14c3c979627d0a92d102b6f3e970a0fdbbbd0","src/raw/bitmask.rs":"05e72c64957af7383001ca43a827cc5b3a8a39d00fac332ecea2fd7d2704099c","src/raw/generic.rs":"03d4d5cf5241dd32cfee55986381048bf5432957cdb7c48efd85538c0cf0523d","src/raw/mod.rs":"f3b5bc990cf032717e7308f509a9f93e97f8aba055279cef84281337f91b37f8","src/raw/sse2.rs":"963b7be51552eb18ea24eec8b8d8882d98ba0e798eef46f1813eb42311422ce3","src/rustc_entry.rs":"64e47870015a9f152340017b79e2262e5c70d0f42b4fc2dfa48dd25ca70465f7","src/scopeguard.rs":"337cde60c9e1109cd19d4fa53529014cef1e3d5900dffde82f647881df1505f7","src/set.rs":"e27abbe3863362c3d63899176a54443fb7df9598ebd250d73c6d80aec811e994","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/rayon.rs":"2286707a87b139f41902c82488c355b9fb402a3e734f392f3a73e87b9b932795","tests/serde.rs":"eed27382c0e43f67e402cd9eed20dea23ef5582e1a26a183e708ca9217a559e0","tests/set.rs":"374bd312c01a01cf8953bbbc9494f431b260c2657d7c79cc250e977b869a76ad"},"package":"e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"} \ No newline at end of file +{"files":{"CHANGELOG.md":"32cf1068a2d6d82879e998892e4f474812bba744101404c4c70e1f9768f589de","Cargo.toml":"52c7504a9ff4eac66a7a8a20e7853d0316f73df711a559eb390477a6d05d8eac","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"66f79e21927df369fccac1cfff147c6fe66e15b4fc003851a008b9cbac831ea9","benches/bench.rs":"a3f8426559ebf68d93e37edee0bf83c28f18572b394b22e47dbff33e25cac403","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"d69528827794524cfd9acbeacc1ac4f6131e3c7574311e6d919f818f65fbff07","src/external_trait_impls/rayon/helpers.rs":"d4fbca4db924925548f8dab8eb94cf4a3955a53c5e1ff15f59c460546c394034","src/external_trait_impls/rayon/map.rs":"eee0d42bd8cd347d49cfb1332f15297ca63b864c3690299a3ccd6d52c22c67de","src/external_trait_impls/rayon/mod.rs":"156de9c1ad0123334ea3b7e5a17444faf1b8bf971aa88a1f23e2f2d1c3021141","src/external_trait_impls/rayon/raw.rs":"d1b2415a4c3c42279f99a23bcf45c80ddb9a641c7f7974d42ed4d55f57bf6854","src/external_trait_impls/rayon/set.rs":"59afc7b1cdc985a85952d456e34eada4ca2fedf90d2a14dccf98a69f8f496137","src/external_trait_impls/serde.rs":"9306fb6e0e339398dc23ba9e7400a9a28d713df248e8b260e3d4dc44f799e101","src/lib.rs":"a455a0387b0133114247380659c2825713a4b91ef38a45f737007b47a2c30ee4","src/macros.rs":"0b1e9a55e8f5232b82f7e56f352a98904b35ddfca015377cf71daa31939baabf","src/map.rs":"51ec9f24aef15b80ee26a9f50c954ea5863aefda60ce75ae3646f378ab03163f","src/raw/bitmask.rs":"05e72c64957af7383001ca43a827cc5b3a8a39d00fac332ecea2fd7d2704099c","src/raw/generic.rs":"28da6bb3a722dcaa26cb5aba9e028111f32212dc9ce0c323e8f39ff5f367385e","src/raw/mod.rs":"723a66ce495d3a60b0039d32adf31ecf2626d6768d5ed61423fa40b3423df219","src/raw/sse2.rs":"ff332a9104558fe6a86b85ab975b6f43d4a042c634d5dc6cf70cf1d71d97ad7d","src/rustc_entry.rs":"64e47870015a9f152340017b79e2262e5c70d0f42b4fc2dfa48dd25ca70465f7","src/scopeguard.rs":"337cde60c9e1109cd19d4fa53529014cef1e3d5900dffde82f647881df1505f7","src/set.rs":"4ec68cf40a41bbc50da754047893640c62c55f612e03c43e3e3e837a23defc6d","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/rayon.rs":"2286707a87b139f41902c82488c355b9fb402a3e734f392f3a73e87b9b932795","tests/serde.rs":"eed27382c0e43f67e402cd9eed20dea23ef5582e1a26a183e708ca9217a559e0","tests/set.rs":"374bd312c01a01cf8953bbbc9494f431b260c2657d7c79cc250e977b869a76ad"},"package":"00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7"} \ No newline at end of file diff --git a/vendor/hashbrown/CHANGELOG.md b/vendor/hashbrown/CHANGELOG.md index f95632d23b..e349925555 100644 --- a/vendor/hashbrown/CHANGELOG.md +++ b/vendor/hashbrown/CHANGELOG.md @@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.9.0] - 2020-09-03 + +### Fixed +- `drain_filter` now removes and yields items that do match the predicate, + rather than items that don't. This is a **breaking change** to match the + behavior of the `drain_filter` methods in `std`. (#187) + +### Added +- Added `replace_entry_with` to `OccupiedEntry`, and `and_replace_entry_with` to `Entry`. (#190) +- Implemented `FusedIterator` and `size_hint` for `DrainFilter`. (#188) + +### Changed +- The minimum Rust version has been bumped to 1.36 (due to `crossbeam` dependency). (#193) +- Updated `ahash` dependency to 0.4. (#198) +- `HashMap::with_hasher` and `HashSet::with_hasher` are now `const fn`. (#195) +- Removed `T: Hash + Eq` and `S: BuildHasher` bounds on `HashSet::new`, + `with_capacity`, `with_hasher`, and `with_capacity_and_hasher`. (#185) + ## [v0.8.2] - 2020-08-08 ### Changed @@ -231,7 +249,8 @@ This release was _yanked_ due to a breaking change for users of `no-default-feat - Initial release -[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...HEAD +[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.9.0...HEAD +[v0.9.0]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...v0.9.0 [v0.8.2]: https://github.com/rust-lang/hashbrown/compare/v0.8.1...v0.8.2 [v0.8.1]: https://github.com/rust-lang/hashbrown/compare/v0.8.0...v0.8.1 [v0.8.0]: https://github.com/rust-lang/hashbrown/compare/v0.7.2...v0.8.0 diff --git a/vendor/hashbrown/Cargo.toml b/vendor/hashbrown/Cargo.toml index 0a09938108..2367e873ad 100644 --- a/vendor/hashbrown/Cargo.toml +++ b/vendor/hashbrown/Cargo.toml @@ -13,9 +13,8 @@ [package] edition = "2018" name = "hashbrown" -version = "0.8.2" +version = "0.9.0" authors = ["Amanieu d'Antras "] -build = "build.rs" exclude = [".travis.yml", "bors.toml", "/ci/*"] description = "A Rust port of Google's SwissTable hash map" readme = "README.md" @@ -26,7 +25,7 @@ repository = "https://github.com/rust-lang/hashbrown" [package.metadata.docs.rs] features = ["nightly", "rayon", "serde", "raw"] [dependencies.ahash] -version = "0.3.2" +version = "0.4.4" optional = true default-features = false @@ -70,8 +69,6 @@ version = "=1.0" [dev-dependencies.serde_test] version = "1.0" -[build-dependencies.autocfg] -version = "1" [features] ahash-compile-time-rng = ["ahash/compile-time-rng"] diff --git a/vendor/hashbrown/build.rs b/vendor/hashbrown/build.rs deleted file mode 100644 index 818b20182f..0000000000 --- a/vendor/hashbrown/build.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - let nightly = std::env::var_os("CARGO_FEATURE_NIGHTLY").is_some(); - let has_stable_alloc = || autocfg::new().probe_rustc_version(1, 36); - - if nightly || has_stable_alloc() { - autocfg::emit("has_extern_crate_alloc") - } -} diff --git a/vendor/hashbrown/src/lib.rs b/vendor/hashbrown/src/lib.rs index 34b01d5d1d..3aff40a4ff 100644 --- a/vendor/hashbrown/src/lib.rs +++ b/vendor/hashbrown/src/lib.rs @@ -12,16 +12,7 @@ #![no_std] #![cfg_attr( feature = "nightly", - feature( - alloc_layout_extra, - allocator_api, - ptr_offset_from, - test, - core_intrinsics, - dropck_eyepatch, - min_specialization, - extend_one, - ) + feature(test, core_intrinsics, dropck_eyepatch, min_specialization, extend_one) )] #![allow( clippy::doc_markdown, @@ -36,11 +27,8 @@ #[macro_use] extern crate std; -#[cfg(has_extern_crate_alloc)] #[cfg_attr(test, macro_use)] extern crate alloc; -#[cfg(not(has_extern_crate_alloc))] -extern crate std as alloc; #[cfg(feature = "nightly")] #[cfg(doctest)] diff --git a/vendor/hashbrown/src/map.rs b/vendor/hashbrown/src/map.rs index 5ac8528c72..380d71a1d9 100644 --- a/vendor/hashbrown/src/map.rs +++ b/vendor/hashbrown/src/map.rs @@ -275,7 +275,7 @@ impl HashMap { /// /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[cfg_attr(feature = "inline-more", inline)] - pub fn with_hasher(hash_builder: S) -> Self { + pub const fn with_hasher(hash_builder: S) -> Self { Self { hash_builder, table: RawTable::new(), @@ -584,13 +584,13 @@ impl HashMap { } } - /// Drains elements which are false under the given predicate, + /// Drains elements which are true under the given predicate, /// and returns an iterator over the removed items. /// - /// In other words, move all pairs `(k, v)` such that `f(&k,&mut v)` returns `false` out + /// In other words, move all pairs `(k, v)` such that `f(&k,&mut v)` returns `true` out /// into another iterator. /// - /// When the returned DrainedFilter is dropped, the elements that don't satisfy + /// When the returned DrainedFilter is dropped, any remaining elements that satisfy /// the predicate are dropped from the table. /// /// # Examples @@ -598,10 +598,16 @@ impl HashMap { /// ``` /// use hashbrown::HashMap; /// - /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); - /// let drained = map.drain_filter(|&k, _| k % 2 == 0); - /// assert_eq!(drained.count(), 4); - /// assert_eq!(map.len(), 4); + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// let drained: HashMap = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().cloned().collect::>(); + /// let mut odds = map.keys().cloned().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn drain_filter(&mut self, f: F) -> DrainFilter<'_, K, V, F> @@ -764,6 +770,7 @@ where let hash = make_hash(&self.hash_builder, &key); if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { Entry::Occupied(OccupiedEntry { + hash, key: Some(key), elem, table: self, @@ -840,7 +847,7 @@ where Some(item) => unsafe { let &(ref key, ref value) = item.as_ref(); Some((key, value)) - } + }, None => None, } } @@ -880,7 +887,7 @@ where Some(item) => unsafe { let &mut (ref key, ref mut value) = item.as_mut(); Some((key, value)) - } + }, None => None, } } @@ -1384,8 +1391,15 @@ where fn next(&mut self) -> Option { self.inner.next(&mut self.f) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } } +impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + /// Portions of `DrainFilter` shared with `set::DrainFilter` pub(super) struct DrainFilterInner<'a, K, V> { pub iter: RawIter<(K, V)>, @@ -1401,7 +1415,7 @@ impl DrainFilterInner<'_, K, V> { unsafe { while let Some(item) = self.iter.next() { let &mut (ref key, ref mut value) = item.as_mut(); - if !f(key, value) { + if f(key, value) { return Some(self.table.remove(item)); } } @@ -1443,7 +1457,7 @@ pub struct RawEntryBuilderMut<'a, K, V, S> { /// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html pub enum RawEntryMut<'a, K, V, S> { /// An occupied entry. - Occupied(RawOccupiedEntryMut<'a, K, V>), + Occupied(RawOccupiedEntryMut<'a, K, V, S>), /// A vacant entry. Vacant(RawVacantEntryMut<'a, K, V, S>), } @@ -1452,21 +1466,24 @@ pub enum RawEntryMut<'a, K, V, S> { /// It is part of the [`RawEntryMut`] enum. /// /// [`RawEntryMut`]: enum.RawEntryMut.html -pub struct RawOccupiedEntryMut<'a, K, V> { +pub struct RawOccupiedEntryMut<'a, K, V, S> { elem: Bucket<(K, V)>, table: &'a mut RawTable<(K, V)>, + hash_builder: &'a S, } -unsafe impl Send for RawOccupiedEntryMut<'_, K, V> +unsafe impl Send for RawOccupiedEntryMut<'_, K, V, S> where K: Send, V: Send, + S: Sync, { } -unsafe impl Sync for RawOccupiedEntryMut<'_, K, V> +unsafe impl Sync for RawOccupiedEntryMut<'_, K, V, S> where K: Sync, V: Sync, + S: Sync, { } @@ -1535,6 +1552,7 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> { Some(elem) => RawEntryMut::Occupied(RawOccupiedEntryMut { elem, table: &mut self.map.table, + hash_builder: &self.map.hash_builder, }), None => RawEntryMut::Vacant(RawVacantEntryMut { table: &mut self.map.table, @@ -1579,7 +1597,7 @@ impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> { Some(item) => unsafe { let &(ref key, ref value) = item.as_ref(); Some((key, value)) - } + }, None => None, } } @@ -1609,7 +1627,7 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { /// assert_eq!(entry.remove_entry(), ("horseyland", 37)); /// ``` #[cfg_attr(feature = "inline-more", inline)] - pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V> + pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S> where K: Hash, S: BuildHasher, @@ -1721,9 +1739,75 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), } } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RawEntryMut; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// RawEntryMut::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// }, + /// RawEntryMut::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + RawEntryMut::Occupied(entry) => entry.replace_entry_with(f), + RawEntryMut::Vacant(_) => self, + } + } } -impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> { +impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// Gets a reference to the key in the entry. #[cfg_attr(feature = "inline-more", inline)] pub fn key(&self) -> &K { @@ -1813,6 +1897,32 @@ impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> { pub fn remove_entry(self) -> (K, V) { unsafe { self.table.remove(self.elem) } } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> RawEntryMut<'a, K, V, S> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let still_occupied = self + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + f(&key, value).map(|new_value| (key, new_value)) + }); + + if still_occupied { + RawEntryMut::Occupied(self) + } else { + RawEntryMut::Vacant(RawVacantEntryMut { + table: self.table, + hash_builder: self.hash_builder, + }) + } + } + } } impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { @@ -1862,7 +1972,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { } #[cfg_attr(feature = "inline-more", inline)] - fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V> + fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S> where K: Hash, S: BuildHasher, @@ -1877,6 +1987,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { RawOccupiedEntryMut { elem, table: self.table, + hash_builder: self.hash_builder, } } } @@ -1896,7 +2007,7 @@ impl Debug for RawEntryMut<'_, K, V, S> { } } -impl Debug for RawOccupiedEntryMut<'_, K, V> { +impl Debug for RawOccupiedEntryMut<'_, K, V, S> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawOccupiedEntryMut") .field("key", self.key()) @@ -1945,6 +2056,7 @@ impl Debug for Entry<'_, K, V, S> { /// /// [`Entry`]: enum.Entry.html pub struct OccupiedEntry<'a, K, V, S> { + hash: u64, key: Option, elem: Bucket<(K, V)>, table: &'a mut HashMap, @@ -2049,7 +2161,7 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { Some(x) => unsafe { let r = x.as_ref(); Some((&r.0, &r.1)) - } + }, None => None, } } @@ -2077,7 +2189,7 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { Some(x) => unsafe { let r = x.as_mut(); Some((&r.0, &mut r.1)) - } + }, None => None, } } @@ -2406,6 +2518,71 @@ impl<'a, K, V, S> Entry<'a, K, V, S> { Entry::Vacant(entry) => Entry::Vacant(entry), } } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// Entry::Vacant(e) => assert_eq!(e.key(), &"poneyland"), + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + Entry::Occupied(entry) => entry.replace_entry_with(f), + Entry::Vacant(_) => self, + } + } } impl<'a, K, V: Default, S> Entry<'a, K, V, S> { @@ -2660,6 +2837,85 @@ impl<'a, K, V, S> OccupiedEntry<'a, K, V, S> { let entry = unsafe { self.elem.as_mut() }; mem::replace(&mut entry.0, self.key.unwrap()) } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.insert("poneyland", 42); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => { + /// e.replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }) + /// } + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => e.replace_entry_with(|_k, _v| None), + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> Entry<'a, K, V, S> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let mut spare_key = None; + + self.table + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) + } else { + spare_key = Some(key); + None + } + }); + + if let Some(key) = spare_key { + Entry::Vacant(VacantEntry { + hash: self.hash, + key, + table: self.table, + }) + } else { + Entry::Occupied(self) + } + } + } } impl<'a, K, V, S> VacantEntry<'a, K, V, S> { @@ -2738,6 +2994,7 @@ impl<'a, K, V, S> VacantEntry<'a, K, V, S> { make_hash(hash_builder, &x.0) }); OccupiedEntry { + hash: self.hash, key: None, elem, table: self.table, @@ -3745,6 +4002,233 @@ mod test_map { assert_eq!(a[key], value); } + #[test] + fn test_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).insert(value).replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.entry(key) { + Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + Vacant(_) => panic!(), + }; + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).and_replace_entry_with(|_, _| panic!()); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .insert(key, value) + .replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.raw_entry_mut().from_key(&key) { + RawEntryMut::Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + RawEntryMut::Vacant(_) => panic!(), + }; + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|_, _| panic!()); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_replace_entry_with_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + SmallRng::from_seed(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10, 10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10, 10); + m.entry(x).and_replace_entry_with(|_, _| None); + check(&m); + } + } + #[test] fn test_retain() { let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); @@ -3763,7 +4247,7 @@ mod test_map { let drained = map.drain_filter(|&k, _| k % 2 == 0); let mut out = drained.collect::>(); out.sort_unstable(); - assert_eq!(vec![(1, 10), (3, 30), (5, 50), (7, 70)], out); + assert_eq!(vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); assert_eq!(map.len(), 4); } { @@ -4016,4 +4500,28 @@ mod test_map { assert_eq!(m.table.len(), left); } } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::borrow::ToOwned; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_MAP: HashMap = + HashMap::with_hasher(MyHasher); + + let mut map = EMPTY_MAP.clone(); + map.insert(17, "seventeen".to_owned()); + assert_eq!("seventeen", map[&17]); + } } diff --git a/vendor/hashbrown/src/raw/generic.rs b/vendor/hashbrown/src/raw/generic.rs index 6f71900cee..26f8c58969 100644 --- a/vendor/hashbrown/src/raw/generic.rs +++ b/vendor/hashbrown/src/raw/generic.rs @@ -47,20 +47,20 @@ impl Group { pub const WIDTH: usize = mem::size_of::(); /// Returns a full group of empty bytes, suitable for use as the initial - /// value for an empty hash table. This value is explicitly declared as - /// a static variable to ensure the address is consistent across dylibs. + /// value for an empty hash table. /// /// This is guaranteed to be aligned to the group size. - #[inline] - pub fn static_empty() -> &'static [u8] { - union AlignedBytes { - _align: Group, + pub const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], bytes: [u8; Group::WIDTH], }; - static ALIGNED_BYTES: AlignedBytes = AlignedBytes { + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], bytes: [EMPTY; Group::WIDTH], }; - unsafe { &ALIGNED_BYTES.bytes } + &ALIGNED_BYTES.bytes } /// Loads a group of bytes starting at the given address. diff --git a/vendor/hashbrown/src/raw/mod.rs b/vendor/hashbrown/src/raw/mod.rs index 1ff0135382..fe95932f3d 100644 --- a/vendor/hashbrown/src/raw/mod.rs +++ b/vendor/hashbrown/src/raw/mod.rs @@ -382,10 +382,10 @@ impl RawTable { /// leave the data pointer dangling since that bucket is never written to /// due to our load factor forcing us to always have at least 1 free bucket. #[cfg_attr(feature = "inline-more", inline)] - pub fn new() -> Self { + pub const fn new() -> Self { Self { // Be careful to cast the entire slice to a raw pointer. - ctrl: unsafe { NonNull::new_unchecked(Group::static_empty().as_ptr() as *mut u8) }, + ctrl: unsafe { NonNull::new_unchecked(Group::static_empty() as *const _ as *mut u8) }, bucket_mask: 0, items: 0, growth_left: 0, @@ -406,7 +406,7 @@ impl RawTable { // Avoid `Option::ok_or_else` because it bloats LLVM IR. let (layout, ctrl_offset) = match calculate_layout::(buckets) { Some(lco) => lco, - None => return Err(fallability.capacity_overflow()) + None => return Err(fallability.capacity_overflow()), }; let ptr = match NonNull::new(alloc(layout)) { Some(ptr) => ptr, @@ -688,7 +688,10 @@ impl RawTable { *self = Self::with_capacity(min_size) } else { // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. - if self.resize(min_size, hasher, Fallibility::Infallible).is_err() { + if self + .resize(min_size, hasher, Fallibility::Infallible) + .is_err() + { unsafe { hint::unreachable_unchecked() } } } @@ -701,7 +704,10 @@ impl RawTable { pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { if additional > self.growth_left { // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. - if self.reserve_rehash(additional, hasher, Fallibility::Infallible).is_err() { + if self + .reserve_rehash(additional, hasher, Fallibility::Infallible) + .is_err() + { unsafe { hint::unreachable_unchecked() } } } @@ -954,6 +960,33 @@ impl RawTable { } } + /// Temporary removes a bucket, applying the given function to the removed + /// element and optionally put back the returned value in the same bucket. + /// + /// Returns `true` if the bucket still contains an element + /// + /// This does not check if the given bucket is actually occupied. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn replace_bucket_with(&mut self, bucket: Bucket, f: F) -> bool + where + F: FnOnce(T) -> Option, + { + let index = self.bucket_index(&bucket); + let old_ctrl = *self.ctrl(index); + debug_assert!(is_full(old_ctrl)); + let old_growth_left = self.growth_left; + let item = self.remove(bucket); + if let Some(new_item) = f(item) { + self.growth_left = old_growth_left; + self.set_ctrl(index, old_ctrl); + self.items += 1; + self.bucket(index).write(new_item); + true + } else { + false + } + } + /// Searches for an element in the table. #[inline] pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option> { @@ -1114,7 +1147,7 @@ impl Clone for RawTable { match Self::new_uninitialized(self.buckets(), Fallibility::Infallible) { Ok(table) => table, Err(_) => hint::unreachable_unchecked(), - } + }, ); new_table.clone_from_spec(self, |new_table| { @@ -1151,7 +1184,7 @@ impl Clone for RawTable { match Self::new_uninitialized(source.buckets(), Fallibility::Infallible) { Ok(table) => table, Err(_) => hint::unreachable_unchecked(), - } + }, ); } diff --git a/vendor/hashbrown/src/raw/sse2.rs b/vendor/hashbrown/src/raw/sse2.rs index 79b0aad42d..a27bc0910f 100644 --- a/vendor/hashbrown/src/raw/sse2.rs +++ b/vendor/hashbrown/src/raw/sse2.rs @@ -25,19 +25,20 @@ impl Group { pub const WIDTH: usize = mem::size_of::(); /// Returns a full group of empty bytes, suitable for use as the initial - /// value for an empty hash table. This value is explicitly declared as - /// a static variable to ensure the address is consistent across dylibs. + /// value for an empty hash table. /// /// This is guaranteed to be aligned to the group size. - pub fn static_empty() -> &'static [u8] { - union AlignedBytes { - _align: Group, + pub const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], bytes: [u8; Group::WIDTH], }; - static ALIGNED_BYTES: AlignedBytes = AlignedBytes { + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], bytes: [EMPTY; Group::WIDTH], }; - unsafe { &ALIGNED_BYTES.bytes } + &ALIGNED_BYTES.bytes } /// Loads a group of bytes starting at the given address. diff --git a/vendor/hashbrown/src/set.rs b/vendor/hashbrown/src/set.rs index eaae82ce7d..b8460fd3b6 100644 --- a/vendor/hashbrown/src/set.rs +++ b/vendor/hashbrown/src/set.rs @@ -100,11 +100,9 @@ use super::map::{self, ConsumeAllOnDrop, DefaultHashBuilder, DrainFilterInner, H /// ``` /// use hashbrown::HashSet; /// -/// fn main() { /// let viking_names: HashSet<&'static str> = /// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); /// // use the values stored in the set -/// } /// ``` /// /// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html @@ -130,7 +128,7 @@ impl Clone for HashSet { } #[cfg(feature = "ahash")] -impl HashSet { +impl HashSet { /// Creates an empty `HashSet`. /// /// The hash set is initially created with a capacity of 0, so it will not allocate until it @@ -170,6 +168,72 @@ impl HashSet { } impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher(hasher: S) -> Self { + Self { + map: HashMap::with_hasher(hasher), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { + Self { + map: HashMap::with_capacity_and_hasher(capacity, hasher), + } + } + /// Returns the number of elements the set can hold without reallocating. /// /// # Examples @@ -286,13 +350,13 @@ impl HashSet { self.map.retain(|k, _| f(k)); } - /// Drains elements which are false under the given predicate, + /// Drains elements which are true under the given predicate, /// and returns an iterator over the removed items. /// - /// In other words, move all elements `e` such that `f(&e)` returns `false` out + /// In other words, move all elements `e` such that `f(&e)` returns `true` out /// into another iterator. /// - /// When the returned DrainedFilter is dropped, the elements that don't satisfy + /// When the returned DrainedFilter is dropped, any remaining elements that satisfy /// the predicate are dropped from the set. /// /// # Examples @@ -301,9 +365,15 @@ impl HashSet { /// use hashbrown::HashSet; /// /// let mut set: HashSet = (0..8).collect(); - /// let drained = set.drain_filter(|&k| k % 2 == 0); - /// assert_eq!(drained.count(), 4); - /// assert_eq!(set.len(), 4); + /// let drained: HashSet = set.drain_filter(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn drain_filter(&mut self, f: F) -> DrainFilter<'_, T, F> @@ -335,78 +405,6 @@ impl HashSet { pub fn clear(&mut self) { self.map.clear() } -} - -impl HashSet -where - T: Eq + Hash, - S: BuildHasher, -{ - /// Creates a new empty hash set which will use the given hasher to hash - /// keys. - /// - /// The hash set is also created with the default initial capacity. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. - /// - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// use hashbrown::hash_map::DefaultHashBuilder; - /// - /// let s = DefaultHashBuilder::default(); - /// let mut set = HashSet::with_hasher(s); - /// set.insert(2); - /// ``` - /// - /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html - #[cfg_attr(feature = "inline-more", inline)] - pub fn with_hasher(hasher: S) -> Self { - Self { - map: HashMap::with_hasher(hasher), - } - } - - /// Creates an empty `HashSet` with the specified capacity, using - /// `hasher` to hash the keys. - /// - /// The hash set will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash set will not allocate. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// use hashbrown::hash_map::DefaultHashBuilder; - /// - /// let s = DefaultHashBuilder::default(); - /// let mut set = HashSet::with_capacity_and_hasher(10, s); - /// set.insert(1); - /// ``` - /// - /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html - #[cfg_attr(feature = "inline-more", inline)] - pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { - Self { - map: HashMap::with_capacity_and_hasher(capacity, hasher), - } - } /// Returns a reference to the set's [`BuildHasher`]. /// @@ -426,7 +424,13 @@ where pub fn hasher(&self) -> &S { self.map.hasher() } +} +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, +{ /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashSet`. The collection may reserve more space to avoid /// frequent reallocations. @@ -1456,8 +1460,15 @@ where let (k, _) = self.inner.next(&mut |k, _| f(k))?; Some(k) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } } +impl FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {} + impl Clone for Intersection<'_, T, S> { #[cfg_attr(feature = "inline-more", inline)] fn clone(&self) -> Self { @@ -2074,7 +2085,7 @@ mod test_set { let drained = set.drain_filter(|&k| k % 2 == 0); let mut out = drained.collect::>(); out.sort_unstable(); - assert_eq!(vec![1, 3, 5, 7], out); + assert_eq!(vec![0, 2, 4, 6], out); assert_eq!(set.len(), 4); } { @@ -2083,4 +2094,26 @@ mod test_set { assert_eq!(set.len(), 4, "Removes non-matching items on drop"); } } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_SET: HashSet = HashSet::with_hasher(MyHasher); + + let mut set = EMPTY_SET.clone(); + set.insert(19); + assert!(set.contains(&19)); + } } diff --git a/vendor/hex/.cargo-checksum.json b/vendor/hex/.cargo-checksum.json new file mode 100644 index 0000000000..2c9c1d0803 --- /dev/null +++ b/vendor/hex/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"3b509da1763642f9bd85382ae9d83a5f4355cf201b0fab9de719aa635ea0ff70","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"f7bdb3426d045cd50efd4953026e3eb5a83d0199f458a075602611b9344da5b9","README.md":"4bbf89813cd9d2a04707299f34e1c906ed9e8247b910043f38d47b18a0d0641b","benches/hex.rs":"f1301fdaaf5f31cdd16e6988673201c9ce5b7dc65ae7cb7c69559b7adabf38bc","src/error.rs":"7c8af5efa9135fa24fc37dfcd973112c0766ccc7a4826078edb045df9a8efd79","src/lib.rs":"734506f5d604c7d7575d2c6bc31c75a10f628c7b41daa6be11656bd6f7117191","src/serde.rs":"8fb25650a850ae258ff9178bb8818145101dd3df40aa2725fc11b81bdd5d4567","tests/serde.rs":"28dca8a567daf9861413d1b1b5c2da13472f1c1b9c69db02598674cdbd633be2","tests/version-number.rs":"73301b7bfe500eada5ede66f0dce89bd3e354af50a8e7a123b02931cd5eb8e16"},"package":"644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"} \ No newline at end of file diff --git a/vendor/hex/Cargo.toml b/vendor/hex/Cargo.toml new file mode 100644 index 0000000000..6dd9a31a71 --- /dev/null +++ b/vendor/hex/Cargo.toml @@ -0,0 +1,62 @@ +# 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 = "hex" +version = "0.4.2" +authors = ["KokaKiwi "] +description = "Encoding and decoding data into/from hexadecimal representation." +documentation = "https://docs.rs/hex/" +readme = "README.md" +keywords = ["no_std", "hex"] +categories = ["encoding", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/KokaKiwi/rust-hex" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[[bench]] +name = "hex" +harness = false +[dependencies.serde] +version = "1.0" +optional = true +[dev-dependencies.criterion] +version = "0.3" + +[dev-dependencies.faster-hex] +version = "0.4" + +[dev-dependencies.pretty_assertions] +version = "0.6" + +[dev-dependencies.rustc-hex] +version = "2.0" + +[dev-dependencies.serde] +version = "1.0" +features = ["derive"] + +[dev-dependencies.serde_json] +version = "1.0" + +[dev-dependencies.version-sync] +version = "0.8" + +[features] +default = ["std"] +std = [] +[badges.travis-ci] +branch = "master" +repository = "KokaKiwi/rust-hex" diff --git a/vendor/hex/LICENSE-APACHE b/vendor/hex/LICENSE-APACHE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/vendor/hex/LICENSE-APACHE @@ -0,0 +1,202 @@ + 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/hex/LICENSE-MIT b/vendor/hex/LICENSE-MIT new file mode 100644 index 0000000000..a7b461f97c --- /dev/null +++ b/vendor/hex/LICENSE-MIT @@ -0,0 +1,20 @@ +Copyright (c) 2013-2014 The Rust Project Developers. +Copyright (c) 2015-2020 The rust-hex 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/hex/README.md b/vendor/hex/README.md new file mode 100644 index 0000000000..9453cfa23b --- /dev/null +++ b/vendor/hex/README.md @@ -0,0 +1,67 @@ +hex +=== +[![Crates.io: hex](https://img.shields.io/crates/v/hex.svg)](https://crates.io/crates/hex) +[![Documentation](https://docs.rs/hex/badge.svg)](https://docs.rs/hex) +[![Build Status (Travis)](https://travis-ci.org/KokaKiwi/rust-hex.svg?branch=master)](https://travis-ci.org/KokaKiwi/rust-hex) +[![Build Status (Github Actions)](https://github.com/KokaKiwi/rust-hex/workflows/Test%20hex/badge.svg?master)](https://github.com/KokaKiwi/rust-hex/actions) + +Encoding and decoding data into/from hexadecimal representation. + +## Examples + +Encoding a `String` +```rust +let hex_string = hex::encode("Hello world!"); + +println!("{}", hex_string); // Prints "48656c6c6f20776f726c6421" +``` + +Decoding a `String` +```rust +let decoded_string = hex::decode("48656c6c6f20776f726c6421"); + +println!("{}", decoded_string); // Prints "Hello world!" +``` + +You can find the [documentation](https://docs.rs/hex) here. + +## Installation + +In order to use this crate, you have to add it under `[dependencies]` to your `Cargo.toml` +```toml +[dependencies] +hex = "0.4" +``` + +By default this will import `std`, if you are working in a +[`no_std`](https://rust-embedded.github.io/book/intro/no-std.html) +environment you can turn this off by adding the following + +```toml +[dependencies] +hex = { version = "0.4", default-features = false } +``` + +## Features + +- `std`: + Enabled by default. Add support for Rust's libstd types. +- `serde`: + Disabled by default. Add support for `serde` de/serializing library. + See the `serde` module documentation for usage. + +## 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/hex/benches/hex.rs b/vendor/hex/benches/hex.rs new file mode 100644 index 0000000000..56b121f3c1 --- /dev/null +++ b/vendor/hex/benches/hex.rs @@ -0,0 +1,70 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use rustc_hex::{FromHex, ToHex}; + +const DATA: &[u8] = include_bytes!("../src/lib.rs"); + +fn bench_encode(c: &mut Criterion) { + c.bench_function("hex_encode", |b| b.iter(|| hex::encode(DATA))); + + c.bench_function("rustc_hex_encode", |b| b.iter(|| DATA.to_hex::())); + + c.bench_function("faster_hex_encode", |b| { + b.iter(|| faster_hex::hex_string(DATA).unwrap()) + }); + + c.bench_function("faster_hex_encode_fallback", |b| { + b.iter(|| { + let mut dst = vec![0; DATA.len() * 2]; + faster_hex::hex_encode_fallback(DATA, &mut dst); + dst + }) + }); +} + +fn bench_decode(c: &mut Criterion) { + c.bench_function("hex_decode", |b| { + let hex = hex::encode(DATA); + b.iter(|| hex::decode(&hex).unwrap()) + }); + + c.bench_function("rustc_hex_decode", |b| { + let hex = DATA.to_hex::(); + b.iter(|| hex.from_hex::>().unwrap()) + }); + + c.bench_function("faster_hex_decode", move |b| { + let hex = faster_hex::hex_string(DATA).unwrap(); + let len = DATA.len(); + b.iter(|| { + let mut dst = Vec::with_capacity(len); + dst.resize(len, 0); + faster_hex::hex_decode(hex.as_bytes(), &mut dst).unwrap(); + dst + }) + }); + + c.bench_function("faster_hex_decode_unchecked", |b| { + let hex = faster_hex::hex_string(DATA).unwrap(); + let len = DATA.len(); + b.iter(|| { + let mut dst = Vec::with_capacity(len); + dst.resize(len, 0); + faster_hex::hex_decode_unchecked(hex.as_bytes(), &mut dst); + dst + }) + }); + + c.bench_function("faster_hex_decode_fallback", |b| { + let hex = faster_hex::hex_string(DATA).unwrap(); + let len = DATA.len(); + b.iter(|| { + let mut dst = Vec::with_capacity(len); + dst.resize(len, 0); + faster_hex::hex_decode_fallback(hex.as_bytes(), &mut dst); + dst + }) + }); +} + +criterion_group!(benches, bench_encode, bench_decode); +criterion_main!(benches); diff --git a/vendor/hex/src/error.rs b/vendor/hex/src/error.rs new file mode 100644 index 0000000000..b9f2acf650 --- /dev/null +++ b/vendor/hex/src/error.rs @@ -0,0 +1,55 @@ +use core::fmt; + +/// The error type for decoding a hex string into `Vec` or `[u8; N]`. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum FromHexError { + /// An invalid character was found. Valid ones are: `0...9`, `a...f` + /// or `A...F`. + InvalidHexCharacter { c: char, index: usize }, + + /// A hex string's length needs to be even, as two digits correspond to + /// one byte. + OddLength, + + /// If the hex string is decoded into a fixed sized container, such as an + /// array, the hex string's length * 2 has to match the container's + /// length. + InvalidStringLength, +} + +#[cfg(feature = "std")] +impl std::error::Error for FromHexError {} + +impl fmt::Display for FromHexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + FromHexError::InvalidHexCharacter { c, index } => { + write!(f, "Invalid character {:?} at position {}", c, index) + } + FromHexError::OddLength => write!(f, "Odd number of digits"), + FromHexError::InvalidStringLength => write!(f, "Invalid string length"), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[cfg(not(feature = "std"))] + use alloc::string::ToString; + use pretty_assertions::assert_eq; + + #[test] + fn test_display() { + assert_eq!( + FromHexError::InvalidHexCharacter { c: '\n', index: 5 }.to_string(), + "Invalid character '\\n' at position 5" + ); + + assert_eq!(FromHexError::OddLength.to_string(), "Odd number of digits"); + assert_eq!( + FromHexError::InvalidStringLength.to_string(), + "Invalid string length" + ); + } +} diff --git a/vendor/hex/src/lib.rs b/vendor/hex/src/lib.rs new file mode 100644 index 0000000000..19ee759c65 --- /dev/null +++ b/vendor/hex/src/lib.rs @@ -0,0 +1,485 @@ +// Copyright (c) 2013-2014 The Rust Project Developers. +// Copyright (c) 2015-2020 The rust-hex Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Encoding and decoding hex strings. +//! +//! For most cases, you can simply use the [`decode`], [`encode`] and +//! [`encode_upper`] functions. If you need a bit more control, use the traits +//! [`ToHex`] and [`FromHex`] instead. +//! +//! # Example +//! +//! ``` +//! let hex_string = hex::encode("Hello world!"); +//! +//! println!("{}", hex_string); // Prints "48656c6c6f20776f726c6421" +//! +//! # assert_eq!(hex_string, "48656c6c6f20776f726c6421"); +//! ``` + +#![doc(html_root_url = "https://docs.rs/hex/0.4.2")] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![allow(clippy::unreadable_literal)] + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{string::String, vec::Vec}; + +use core::iter; + +mod error; +pub use crate::error::FromHexError; + +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +pub mod serde; +#[cfg(feature = "serde")] +pub use crate::serde::{deserialize, serialize, serialize_upper}; + +/// Encoding values as hex string. +/// +/// This trait is implemented for all `T` which implement `AsRef<[u8]>`. This +/// includes `String`, `str`, `Vec` and `[u8]`. +/// +/// # Example +/// +/// ``` +/// use hex::ToHex; +/// +/// println!("{}", "Hello world!".encode_hex::()); +/// # assert_eq!("Hello world!".encode_hex::(), "48656c6c6f20776f726c6421".to_string()); +/// ``` +/// +/// *Note*: instead of using this trait, you might want to use [`encode()`]. +pub trait ToHex { + /// Encode the hex strict representing `self` into the result.. Lower case + /// letters are used (e.g. `f9b4ca`) + fn encode_hex>(&self) -> T; + + /// Encode the hex strict representing `self` into the result.. Lower case + /// letters are used (e.g. `F9B4CA`) + fn encode_hex_upper>(&self) -> T; +} + +const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef"; +const HEX_CHARS_UPPER: &[u8; 16] = b"0123456789ABCDEF"; + +struct BytesToHexChars<'a> { + inner: ::core::slice::Iter<'a, u8>, + table: &'static [u8; 16], + next: Option, +} + +impl<'a> BytesToHexChars<'a> { + fn new(inner: &'a [u8], table: &'static [u8; 16]) -> BytesToHexChars<'a> { + BytesToHexChars { + inner: inner.iter(), + table, + next: None, + } + } +} + +impl<'a> Iterator for BytesToHexChars<'a> { + type Item = char; + + fn next(&mut self) -> Option { + match self.next.take() { + Some(current) => Some(current), + None => self.inner.next().map(|byte| { + let current = self.table[(byte >> 4) as usize] as char; + self.next = Some(self.table[(byte & 0xf) as usize] as char); + current + }), + } + } + + fn size_hint(&self) -> (usize, Option) { + let length = self.len(); + (length, Some(length)) + } +} + +impl<'a> iter::ExactSizeIterator for BytesToHexChars<'a> { + fn len(&self) -> usize { + let mut length = self.inner.len() * 2; + if self.next.is_some() { + length += 1; + } + length + } +} + +fn encode_to_iter>(table: &'static [u8; 16], source: &[u8]) -> T { + BytesToHexChars::new(source, table).collect() +} + +impl> ToHex for T { + fn encode_hex>(&self) -> U { + encode_to_iter(HEX_CHARS_LOWER, self.as_ref()) + } + + fn encode_hex_upper>(&self) -> U { + encode_to_iter(HEX_CHARS_UPPER, self.as_ref()) + } +} + +/// Types that can be decoded from a hex string. +/// +/// This trait is implemented for `Vec` and small `u8`-arrays. +/// +/// # Example +/// +/// ``` +/// use hex::FromHex; +/// +/// match Vec::from_hex("48656c6c6f20776f726c6421") { +/// Ok(vec) => { +/// for b in vec { +/// println!("{}", b as char); +/// } +/// } +/// Err(e) => { +/// // Deal with the error ... +/// } +/// } +/// ``` +pub trait FromHex: Sized { + type Error; + + /// Creates an instance of type `Self` from the given hex string, or fails + /// with a custom error type. + /// + /// Both, upper and lower case characters are valid and can even be + /// mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). + fn from_hex>(hex: T) -> Result; +} + +fn val(c: u8, idx: usize) -> Result { + match c { + b'A'..=b'F' => Ok(c - b'A' + 10), + b'a'..=b'f' => Ok(c - b'a' + 10), + b'0'..=b'9' => Ok(c - b'0'), + _ => Err(FromHexError::InvalidHexCharacter { + c: c as char, + index: idx, + }), + } +} + +impl FromHex for Vec { + type Error = FromHexError; + + fn from_hex>(hex: T) -> Result { + let hex = hex.as_ref(); + if hex.len() % 2 != 0 { + return Err(FromHexError::OddLength); + } + + hex.chunks(2) + .enumerate() + .map(|(i, pair)| Ok(val(pair[0], 2 * i)? << 4 | val(pair[1], 2 * i + 1)?)) + .collect() + } +} + +// Helper macro to implement the trait for a few fixed sized arrays. Once Rust +// has type level integers, this should be removed. +macro_rules! from_hex_array_impl { + ($($len:expr)+) => {$( + impl FromHex for [u8; $len] { + type Error = FromHexError; + + fn from_hex>(hex: T) -> Result { + let mut out = [0u8; $len]; + decode_to_slice(hex, &mut out as &mut [u8])?; + Ok(out) + } + } + )+} +} + +from_hex_array_impl! { + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 + 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 + 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 + 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 + 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 + 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 + 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 + 160 192 200 224 256 384 512 768 1024 2048 4096 8192 16384 32768 +} + +#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] +from_hex_array_impl! { + 65536 131072 262144 524288 1048576 2097152 4194304 8388608 + 16777216 33554432 67108864 134217728 268435456 536870912 + 1073741824 2147483648 +} + +#[cfg(target_pointer_width = "64")] +from_hex_array_impl! { + 4294967296 +} + +/// Encodes `data` as hex string using lowercase characters. +/// +/// Lowercase characters are used (e.g. `f9b4ca`). The resulting string's +/// length is always even, each byte in `data` is always encoded using two hex +/// digits. Thus, the resulting string contains exactly twice as many bytes as +/// the input data. +/// +/// # Example +/// +/// ``` +/// assert_eq!(hex::encode("Hello world!"), "48656c6c6f20776f726c6421"); +/// assert_eq!(hex::encode(vec![1, 2, 3, 15, 16]), "0102030f10"); +/// ``` +pub fn encode>(data: T) -> String { + data.encode_hex() +} + +/// Encodes `data` as hex string using uppercase characters. +/// +/// Apart from the characters' casing, this works exactly like `encode()`. +/// +/// # Example +/// +/// ``` +/// assert_eq!(hex::encode_upper("Hello world!"), "48656C6C6F20776F726C6421"); +/// assert_eq!(hex::encode_upper(vec![1, 2, 3, 15, 16]), "0102030F10"); +/// ``` +pub fn encode_upper>(data: T) -> String { + data.encode_hex_upper() +} + +/// Decodes a hex string into raw bytes. +/// +/// Both, upper and lower case characters are valid in the input string and can +/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). +/// +/// # Example +/// +/// ``` +/// assert_eq!( +/// hex::decode("48656c6c6f20776f726c6421"), +/// Ok("Hello world!".to_owned().into_bytes()) +/// ); +/// +/// assert_eq!(hex::decode("123"), Err(hex::FromHexError::OddLength)); +/// assert!(hex::decode("foo").is_err()); +/// ``` +pub fn decode>(data: T) -> Result, FromHexError> { + FromHex::from_hex(data) +} + +/// Decode a hex string into a mutable bytes slice. +/// +/// Both, upper and lower case characters are valid in the input string and can +/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). +/// +/// # Example +/// +/// ``` +/// let mut bytes = [0u8; 4]; +/// assert_eq!(hex::decode_to_slice("6b697769", &mut bytes as &mut [u8]), Ok(())); +/// assert_eq!(&bytes, b"kiwi"); +/// ``` +pub fn decode_to_slice>(data: T, out: &mut [u8]) -> Result<(), FromHexError> { + let data = data.as_ref(); + + if data.len() % 2 != 0 { + return Err(FromHexError::OddLength); + } + if data.len() / 2 != out.len() { + return Err(FromHexError::InvalidStringLength); + } + + for (i, byte) in out.iter_mut().enumerate() { + *byte = val(data[2 * i], 2 * i)? << 4 | val(data[2 * i + 1], 2 * i + 1)?; + } + + Ok(()) +} + +// generates an iterator like this +// (0, 1) +// (2, 3) +// (4, 5) +// (6, 7) +// ... +fn generate_iter(len: usize) -> impl Iterator { + (0..len).step_by(2).zip((0..len).skip(1).step_by(2)) +} + +// the inverse of `val`. +fn byte2hex(byte: u8, table: &[u8; 16]) -> (u8, u8) { + let high = table[((byte & 0xf0) >> 4) as usize]; + let low = table[(byte & 0x0f) as usize]; + + (high, low) +} + +/// Encodes some bytes into a mutable slice of bytes. +/// +/// The output buffer, has to be able to hold at least `input.len() * 2` bytes, +/// otherwise this function will return an error. +/// +/// # Example +/// +/// ``` +/// # use hex::FromHexError; +/// # fn main() -> Result<(), FromHexError> { +/// let mut bytes = [0u8; 4 * 2]; +/// +/// hex::encode_to_slice(b"kiwi", &mut bytes)?; +/// assert_eq!(&bytes, b"6b697769"); +/// # Ok(()) +/// # } +/// ``` +pub fn encode_to_slice>(input: T, output: &mut [u8]) -> Result<(), FromHexError> { + if input.as_ref().len() * 2 != output.len() { + return Err(FromHexError::InvalidStringLength); + } + + for (byte, (i, j)) in input.as_ref().iter().zip(generate_iter(input.as_ref().len() * 2)) { + let (high, low) = byte2hex(*byte, HEX_CHARS_LOWER); + output[i] = high; + output[j] = low; + } + + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + #[cfg(not(feature = "std"))] + use alloc::string::ToString; + use pretty_assertions::assert_eq; + + #[test] + fn test_gen_iter() { + let mut result = Vec::new(); + result.push((0, 1)); + result.push((2, 3)); + + assert_eq!(generate_iter(5).collect::>(), result); + } + + #[test] + fn test_encode_to_slice() { + let mut output_1 = [0; 4 * 2]; + encode_to_slice(b"kiwi", &mut output_1).unwrap(); + assert_eq!(&output_1, b"6b697769"); + + let mut output_2 = [0; 5 * 2]; + encode_to_slice(b"kiwis", &mut output_2).unwrap(); + assert_eq!(&output_2, b"6b69776973"); + + let mut output_3 = [0; 100]; + + assert_eq!( + encode_to_slice(b"kiwis", &mut output_3), + Err(FromHexError::InvalidStringLength) + ); + } + + #[test] + fn test_decode_to_slice() { + let mut output_1 = [0; 4]; + decode_to_slice(b"6b697769", &mut output_1).unwrap(); + assert_eq!(&output_1, b"kiwi"); + + let mut output_2 = [0; 5]; + decode_to_slice(b"6b69776973", &mut output_2).unwrap(); + assert_eq!(&output_2, b"kiwis"); + + let mut output_3 = [0; 4]; + + assert_eq!(decode_to_slice(b"6", &mut output_3), Err(FromHexError::OddLength)); + } + + #[test] + fn test_encode() { + assert_eq!(encode("foobar"), "666f6f626172"); + } + + #[test] + fn test_decode() { + assert_eq!(decode("666f6f626172"), Ok(String::from("foobar").into_bytes())); + } + + #[test] + pub fn test_from_hex_okay_str() { + assert_eq!(Vec::from_hex("666f6f626172").unwrap(), b"foobar"); + assert_eq!(Vec::from_hex("666F6F626172").unwrap(), b"foobar"); + } + + #[test] + pub fn test_from_hex_okay_bytes() { + assert_eq!(Vec::from_hex(b"666f6f626172").unwrap(), b"foobar"); + assert_eq!(Vec::from_hex(b"666F6F626172").unwrap(), b"foobar"); + } + + #[test] + pub fn test_invalid_length() { + assert_eq!(Vec::from_hex("1").unwrap_err(), FromHexError::OddLength); + assert_eq!(Vec::from_hex("666f6f6261721").unwrap_err(), FromHexError::OddLength); + } + + #[test] + pub fn test_invalid_char() { + assert_eq!( + Vec::from_hex("66ag").unwrap_err(), + FromHexError::InvalidHexCharacter { c: 'g', index: 3 } + ); + } + + #[test] + pub fn test_empty() { + assert_eq!(Vec::from_hex("").unwrap(), b""); + } + + #[test] + pub fn test_from_hex_whitespace() { + assert_eq!( + Vec::from_hex("666f 6f62617").unwrap_err(), + FromHexError::InvalidHexCharacter { c: ' ', index: 4 } + ); + } + + #[test] + pub fn test_from_hex_array() { + assert_eq!( + <[u8; 6] as FromHex>::from_hex("666f6f626172"), + Ok([0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]) + ); + + assert_eq!( + <[u8; 5] as FromHex>::from_hex("666f6f626172"), + Err(FromHexError::InvalidStringLength) + ); + } + + #[test] + fn test_to_hex() { + assert_eq!( + [0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72].encode_hex::(), + "666f6f626172".to_string(), + ); + + assert_eq!( + [0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72].encode_hex_upper::(), + "666F6F626172".to_string(), + ); + } +} diff --git a/vendor/hex/src/serde.rs b/vendor/hex/src/serde.rs new file mode 100644 index 0000000000..a90e36095b --- /dev/null +++ b/vendor/hex/src/serde.rs @@ -0,0 +1,88 @@ +//! Hex encoding with `serde`. +//! +//! # Example +//! +//! ``` +//! use serde::{Serialize, Deserialize}; +//! +//! #[derive(Serialize, Deserialize)] +//! struct Foo { +//! #[serde(with = "hex")] +//! bar: Vec, +//! } +//! ``` +//! +use serde::de::{Error, Visitor}; +use serde::{Deserializer, Serializer}; + +use std::fmt; +use std::marker::PhantomData; + +use crate::{FromHex, ToHex}; + +/// Serializes `data` as hex string using uppercase characters. +/// +/// Apart from the characters' casing, this works exactly like `serialize()`. +pub fn serialize_upper(data: T, serializer: S) -> Result +where + S: Serializer, + T: ToHex, +{ + let s = data.encode_hex_upper::(); + serializer.serialize_str(&s) +} + +/// Serializes `data` as hex string using lowercase characters. +/// +/// Lowercase characters are used (e.g. `f9b4ca`). The resulting string's length +/// is always even, each byte in data is always encoded using two hex digits. +/// Thus, the resulting string contains exactly twice as many bytes as the input data. +pub fn serialize(data: T, serializer: S) -> Result +where + S: Serializer, + T: ToHex, +{ + let s = data.encode_hex::(); + serializer.serialize_str(&s) +} + +/// Deserializes a hex string into raw bytes. +/// +/// Both, upper and lower case characters are valid in the input string and can +/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). +pub fn deserialize<'de, D, T>(deserializer: D) -> Result +where + D: Deserializer<'de>, + T: FromHex, + ::Error: fmt::Display, +{ + struct HexStrVisitor(PhantomData); + + impl<'de, T> Visitor<'de> for HexStrVisitor + where + T: FromHex, + ::Error: fmt::Display, + { + type Value = T; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "a hex encoded string") + } + + fn visit_str(self, data: &str) -> Result + where + E: Error, + { + FromHex::from_hex(data).map_err(|e| Error::custom(e)) + } + + fn visit_borrowed_str(self, data: &'de str) -> Result + where + E: Error, + { + FromHex::from_hex(data).map_err(|e| Error::custom(e)) + } + } + + deserializer.deserialize_str(HexStrVisitor(PhantomData)) +} diff --git a/vendor/hex/tests/serde.rs b/vendor/hex/tests/serde.rs new file mode 100644 index 0000000000..aedf8c77c1 --- /dev/null +++ b/vendor/hex/tests/serde.rs @@ -0,0 +1,58 @@ +#![cfg(feature = "serde")] + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +struct Foo { + #[serde(with = "hex")] + bar: Vec, +} + +#[test] +fn serialize() { + let foo = Foo { + bar: vec![1, 10, 100], + }; + + let ser = serde_json::to_string(&foo).expect("serialization failed"); + assert_eq!(ser, r#"{"bar":"010a64"}"#); +} + +#[test] +fn deserialize() { + let foo = Foo { + bar: vec![1, 10, 100], + }; + + let de: Foo = serde_json::from_str(r#"{"bar":"010a64"}"#).expect("deserialization failed"); + assert_eq!(de, foo); +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +struct Bar { + #[serde( + serialize_with = "hex::serialize_upper", + deserialize_with = "hex::deserialize" + )] + foo: Vec, +} + +#[test] +fn serialize_upper() { + let bar = Bar { + foo: vec![1, 10, 100], + }; + + let ser = serde_json::to_string(&bar).expect("serialization failed"); + assert_eq!(ser, r#"{"foo":"010A64"}"#); +} + +#[test] +fn deserialize_upper() { + let bar = Bar { + foo: vec![1, 10, 100], + }; + + let de: Bar = serde_json::from_str(r#"{"foo":"010A64"}"#).expect("deserialization failed"); + assert_eq!(de, bar); +} diff --git a/vendor/hex/tests/version-number.rs b/vendor/hex/tests/version-number.rs new file mode 100644 index 0000000000..288592d02f --- /dev/null +++ b/vendor/hex/tests/version-number.rs @@ -0,0 +1,9 @@ +#[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/indexmap/.cargo-checksum.json b/vendor/indexmap/.cargo-checksum.json index 0a17817b83..7cf443999b 100644 --- a/vendor/indexmap/.cargo-checksum.json +++ b/vendor/indexmap/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"fcdee9f8eacd948e4ffc43c51e7b4e01cc44ab94076c59531ea0c85507fe7b11","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.rst":"1f0456806c90e69e673676e5444f3d1d588e63ab932663ad5c209346dcf300de","benches/bench.rs":"dda3c7e3cd68b8f5c74dbd60189e89f0e43339cdc25dae7b1e5a9d25b1fb80a9","benches/faststring.rs":"2472b9d0d52031988cd31401357908fd850d15f1efa9f9761aa6b6779aad1889","build.rs":"14e5731ffc7eb135b295312b87730554521b0621fe61b2a19c71dc8f98dfc6ff","src/equivalent.rs":"2e6ae24ef09a09b917f4e2b0f6288f901878e42f5080f61b1bd1afdcc90aba87","src/lib.rs":"4c4fa0d4882387d2c1681fa29a333354230de157101783bea2af6af04951d973","src/macros.rs":"cb2e9742b7e2bcadc4eb356a4ca4eb3317d1a80e293f37a3cd5a0155c5347c50","src/map.rs":"21c0c04acfb25d526da41b447b2e572d14e52778b84910514869d1cd2dce267c","src/map/core.rs":"9d9df231fbc02e3539429451c6f8cfd142c97d6e47b0c1f58672f75e3806d578","src/map/core/raw.rs":"9842320404357ec15e536240a9ab32d969e61f31508d3c485c0c76077618ef63","src/mutable_keys.rs":"99fdec7c0182902ba19524f342c220b51475bcd41c44c2cb2c3f62eacb029335","src/rayon/map.rs":"cdbe6cad8e5753aca3f07b621d2bb3b480f1ae3e10697568b8c16aeb865de65b","src/rayon/mod.rs":"bf2b0fc074f20135a6734db600b04828e88dd263b3e361606be4efe8e916eafc","src/rayon/set.rs":"789efd10d41f03fa73268bae8afdc3b6582767420218a4b28f3c83c528ef726c","src/serde.rs":"2f7ce29e63e92ddbe14d3ad0b7e83bdc9662b226565ec0aa707d5cd92cb1e263","src/set.rs":"a88c5e902e8c67d014c7c1680a7e4b9156af67d2ac58e7dcf96698b742abc88b","src/util.rs":"c415261cff9f610d7331192feba0839cb05e04d3d375a5fa2f8190a29661994e","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"6efe8c6dfa5bdd466b3f5c491d9dfbf57fd730301849a710abff9358968218c5","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"} \ No newline at end of file +{"files":{"Cargo.toml":"b2e03e7a524d10bb253021375ccc06a3d2a060d2c7c045a1a60d8bb3739b46a9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.rst":"6751ed067142c9445ffb9c201457a40bb73af76aa3c7e525fb415508abec74b1","benches/bench.rs":"dda3c7e3cd68b8f5c74dbd60189e89f0e43339cdc25dae7b1e5a9d25b1fb80a9","benches/faststring.rs":"2472b9d0d52031988cd31401357908fd850d15f1efa9f9761aa6b6779aad1889","build.rs":"558b4d0b9e9b3a44f7e1a2b69f7a7567ea721cd45cb54f4e458e850bf702f35c","src/equivalent.rs":"2e6ae24ef09a09b917f4e2b0f6288f901878e42f5080f61b1bd1afdcc90aba87","src/lib.rs":"4c4fa0d4882387d2c1681fa29a333354230de157101783bea2af6af04951d973","src/macros.rs":"cb2e9742b7e2bcadc4eb356a4ca4eb3317d1a80e293f37a3cd5a0155c5347c50","src/map.rs":"21c0c04acfb25d526da41b447b2e572d14e52778b84910514869d1cd2dce267c","src/map/core.rs":"9d9df231fbc02e3539429451c6f8cfd142c97d6e47b0c1f58672f75e3806d578","src/map/core/raw.rs":"9842320404357ec15e536240a9ab32d969e61f31508d3c485c0c76077618ef63","src/mutable_keys.rs":"99fdec7c0182902ba19524f342c220b51475bcd41c44c2cb2c3f62eacb029335","src/rayon/map.rs":"cdbe6cad8e5753aca3f07b621d2bb3b480f1ae3e10697568b8c16aeb865de65b","src/rayon/mod.rs":"bf2b0fc074f20135a6734db600b04828e88dd263b3e361606be4efe8e916eafc","src/rayon/set.rs":"789efd10d41f03fa73268bae8afdc3b6582767420218a4b28f3c83c528ef726c","src/serde.rs":"2f7ce29e63e92ddbe14d3ad0b7e83bdc9662b226565ec0aa707d5cd92cb1e263","src/set.rs":"a88c5e902e8c67d014c7c1680a7e4b9156af67d2ac58e7dcf96698b742abc88b","src/util.rs":"c415261cff9f610d7331192feba0839cb05e04d3d375a5fa2f8190a29661994e","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"6efe8c6dfa5bdd466b3f5c491d9dfbf57fd730301849a710abff9358968218c5","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"} \ No newline at end of file diff --git a/vendor/indexmap/Cargo.toml b/vendor/indexmap/Cargo.toml index 0e42aa2659..96876f030e 100644 --- a/vendor/indexmap/Cargo.toml +++ b/vendor/indexmap/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "indexmap" -version = "1.5.1" +version = "1.6.0" authors = ["bluss", "Josh Stone "] build = "build.rs" description = "A hash table with consistent order and fast iteration.\n\nThe indexmap is a hash table where the iteration order of the key-value\npairs is independent of the hash values of the keys. It has the usual\nhash table functionality, it preserves insertion order except after\nremovals, and it allows lookup of its elements by either hash table key\nor numerical index. A corresponding hash set type is also provided.\n\nThis crate was initially published under the name ordermap, but it was renamed to\nindexmap.\n" @@ -34,7 +34,7 @@ debug = true [lib] bench = false [dependencies.hashbrown] -version = "0.8.1" +version = "0.9.0" features = ["raw"] default-features = false @@ -70,5 +70,6 @@ version = "1" [features] serde-1 = ["serde"] +std = [] test_debug = [] test_low_transition_point = [] diff --git a/vendor/indexmap/README.rst b/vendor/indexmap/README.rst index 5fbab927d7..2c489850df 100644 --- a/vendor/indexmap/README.rst +++ b/vendor/indexmap/README.rst @@ -66,6 +66,20 @@ which is roughly: Recent Changes ============== +- 1.6.0 + + - **MSRV**: Rust 1.36 or later is now required. + + - The ``hashbrown`` dependency has been updated to version 0.9. + +- 1.5.2 + + - The new "std" feature will force the use of ``std`` for users that explicitly + want the default ``S = RandomState``, bypassing the autodetection added in 1.3.0, + by @cuviper in PR 145_. + +.. _145: https://github.com/bluss/indexmap/pull/145 + - 1.5.1 - Values can now be indexed by their ``usize`` position by @cuviper in PR 132_. diff --git a/vendor/indexmap/build.rs b/vendor/indexmap/build.rs index 645c0f1c82..9f9fa054f8 100644 --- a/vendor/indexmap/build.rs +++ b/vendor/indexmap/build.rs @@ -1,5 +1,8 @@ fn main() { - let ac = autocfg::new(); - ac.emit_sysroot_crate("std"); + // If "std" is explicitly requested, don't bother probing the target for it. + match std::env::var_os("CARGO_FEATURE_STD") { + Some(_) => autocfg::emit("has_std"), + None => autocfg::new().emit_sysroot_crate("std"), + } autocfg::rerun_path("build.rs"); } diff --git a/vendor/itertools-0.8.2/.cargo-checksum.json b/vendor/itertools-0.8.2/.cargo-checksum.json deleted file mode 100644 index 4df07cd850..0000000000 --- a/vendor/itertools-0.8.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.lock":"bb03f756d39151fea8de875ac282889d4370443e6fee0c4edf5b33e53f983246","Cargo.toml":"e0c22789bdbb1efe1c80b861e7c00da2015b4d7eacb00fcf827ba28d82e36a2e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.rst":"86c2f8499d778ff74de701ca291420c244bf4c7be94fb73bed32fcafc4cf467a","benches/bench1.rs":"126211884ea482d5176535ca0b35bfa4d28c62c3377db77aaf7b7c12f712577c","benches/combinations_with_replacement.rs":"b15e1694991a35936b5b4eb8525fbc2bfa3720ecebffb01684e7b4b72541c328","benches/extra/mod.rs":"4c5b03e74fc5b02383500c9da9fd6550262706ee569d70d085700f6d0b5749ba","benches/extra/zipslices.rs":"108dd488de366b2d83fb6bcc603ecbf9a017e165ac19d03440074fa244af3fb2","benches/fold_specialization.rs":"1b9753d6adaf6d1e979d9d2af535255e23a94bb0d4f27b57bb9005a944aaec81","benches/tree_fold1.rs":"84cddbabb1a681f3196430a8e27b060103366143a3ee4c42c3b0628fc00a7543","benches/tuple_combinations.rs":"6a4b89eb2e45fa0c99e5e5942b3196b76998213c66c44b3765b869be42016a82","benches/tuples.rs":"412a952f08bb03695952d5cfd57949dcf28be8b99e3c6653994bdb8af9654653","examples/iris.data":"596ffd580471ca4d4880f8e439c7281f3b50d8249a5960353cb200b1490f63a0","examples/iris.rs":"3996ca0a62762aec2b102f0f4244fe90d4b4354286d68d80cdc40e35f4352ba3","src/adaptors/mod.rs":"d4be18d69488b2c5dc6679f554c0a3eacc079bb9b55996505e56491be13d22cb","src/adaptors/multi_product.rs":"bb239555be38cde1f419bacfd09728f6ccaf51b6b4811c266b5677705175e685","src/combinations.rs":"bfbb4cb3975128b1a4daa96350be6b2f3de1d1a937d8351034a72f9f051cdd73","src/combinations_with_replacement.rs":"dc05611ab3f86a9ffe96dcb10c16d65c7619343d323f20e7142d094abe539bc2","src/concat_impl.rs":"276339b00588f54c25f8ffbe0ae3c0031f7e52fb53c6578554a0bde1681b58a5","src/cons_tuples_impl.rs":"87c620d2ffdd3475218f5f493dbef601491be9f6cdfe57c44929449b32e6709f","src/diff.rs":"921e2b867d7b32ffedc72a5eb780811322d14d1e0883a608b9028a2afcad0df2","src/either_or_both.rs":"b7bf810817795465d9e6e43fd0ba02eebbb58d19b62b2eaaebef10dc2a51e769","src/exactly_one_err.rs":"94aa8d7495dd138720863cfddd6da07ec6f85ea74d9af88d3f08805e7cae2310","src/format.rs":"412fbe02f12311c6fbcec1044f57ad6991783f5a3f323b9c391accfe4915106f","src/free.rs":"473d19906720eb2a1309c0505497658b1426f3ea0c845b40f41f3154194fff18","src/group_map.rs":"872d6e243e649ad30c94973c034596cc3377b10018e361bca07e11c612006de6","src/groupbylazy.rs":"a067a12671be9ae05a9152518103f39f7286fde09f758de8af75a1064a3b5567","src/impl_macros.rs":"eb0bb3f70ec1bcaffa6110ae4134c777951ed1e5f48d8c811dbf0a597dc48faa","src/intersperse.rs":"5ea6966e91b26d3e883a3a68b74c107c7ec47da8ccb5b3b95acd9cbb0bc66e2a","src/kmerge_impl.rs":"44c3645d864a00ae1ae6aa2f09ff8be704e7e2452da02e95d02cd3f588caa3ac","src/lazy_buffer.rs":"ed60449deb6d775b054f6165718ae1b70ee84d69ffc015df5b769b73c3133054","src/lib.rs":"359c00d77510384e3ed18647ecd8e2f618758ab7944ca31eb960dabcfa25fc2a","src/merge_join.rs":"98e6fcc761a558ad21789efe041c3f90e62f6c75e05840670df45ad4f9b07e1f","src/minmax.rs":"4668a7f824fbc133599f43ffb6f7283e5bd603e07df2d8176abc6f25d6af9db0","src/multipeek_impl.rs":"ebe9544d94d0bf7200f7625241a3b5a291b7b564091a08cad40ff08b51f1b1bf","src/pad_tail.rs":"078615a2892f8c6db665074cf6f1be1bef4cf5ee418bc174edcfd4dc703e163f","src/peeking_take_while.rs":"6aea3bb40fb480e9f3695ce2a7a3a2e2346d437ca846d20e6bb3c09beb0934f4","src/permutations.rs":"862a53d18e8f5d600da1c60befcda98978617ab01c744bd9baf1ed3dd74f1261","src/process_results_impl.rs":"5f454cf62ceb82cab7c08c0c190de3ae083e219a8acc7a1a22f17eec9cfcd65c","src/put_back_n_impl.rs":"d35858184c525372b22d14d42cdf63726cf0fd50f5bd42ec7a82d55a8e180e9f","src/rciter_impl.rs":"8f51abc7e1ae3320cc5d56fadd66f880a7a06773be656bd8c4712357f01ae1d9","src/repeatn.rs":"4bd1782364b16105fbef3f3de7bf62780710e5c996db44a00e4b5f16c2625d86","src/size_hint.rs":"c1d35b422a696cf3d63e7c90d8f9fdf01a304cf8156e914287c4ef48fea62dd3","src/sources.rs":"cb6ebe06b05f7da0ac1073ba486c45afaeebf8b558c0f5499f0eacd2cd1785da","src/tee.rs":"59cf9ef0b41882307ea1e3503a2ff351f401f4c43d95acf423a990b0bf0e29ae","src/tuple_impl.rs":"0c7f907e85d2ef0661583b36c7b8a7341b8feadafe28d10539a211dff5c028ea","src/unique_impl.rs":"63db2d720ff5e3d9c0d6c2b245ffff25d4040e4fcbcb2a6524b0f912826f86af","src/with_position.rs":"d922f045f6fa090a431be928f3221c6dc37ac6f9bb54461b3b84f99a7e91244a","src/zip_eq_impl.rs":"f857c69120255db16ad6ddec628c79cb573b1d5179fcebab1906bf5b762c02e3","src/zip_longest.rs":"375325ef069970e6fb83c6097c2824877bb0f06e4f1e664e4fe681804abe003c","src/ziptuple.rs":"d7ae7d3c33185ad74ab2bba750ac337b5c236750cc8341dd9883faf6465712a1","tests/adaptors_no_collect.rs":"2572c5555cc2e494a44714710dbaf5d62965d847f4e620ea09e52a7158371364","tests/fold_specialization.rs":"de403af575c6c77234bff2a5e56581159c5ceeff30eadaac14bfd8d405c16bec","tests/merge_join.rs":"546eaffae40010f15a7bcf95bc53f5e9b67424c5b93df6ffb0aaa1e48e8b90c0","tests/peeking_take_while.rs":"a2ae6474e09620a47bb8a6e3c62929261e72c52881370adb2d22e89aa9e9aec8","tests/quick.rs":"b0d36a7ab4aa8b7283c9440b8a4f4867acab951da9aaec59a7314e1b39782be8","tests/test_core.rs":"8d73cb165698dbfaf0d14e278fbd02bda4b92c2a552912ce1a67388a9fe54bcf","tests/test_std.rs":"40a7a001afbf79e08ec970e091799d7e35ee72fdad8baf16a850a1abecf4e921","tests/tuples.rs":"5323d15a7abf6545b2655167d3206b6cf6a947e9409a244ea6a8cf4ad8ceac64","tests/zip.rs":"fe213d70c4fa114cb4d1930a6b971f4af617a239041ddb87e6b5a9bbe62261b8"},"package":"f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"} \ No newline at end of file diff --git a/vendor/itertools-0.8.2/Cargo.lock b/vendor/itertools-0.8.2/Cargo.lock deleted file mode 100644 index a34644cf2c..0000000000 --- a/vendor/itertools-0.8.2/Cargo.lock +++ /dev/null @@ -1,227 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "either" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "itertools" -version = "0.8.2" -dependencies = [ - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.65" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "permutohedron" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quickcheck" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" -"checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" -"checksum quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4537d3e4edf73a15dd059b75bed1c292d17d3ea7517f583cebe716794fcf816" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/itertools-0.8.2/Cargo.toml b/vendor/itertools-0.8.2/Cargo.toml deleted file mode 100644 index db22e36866..0000000000 --- a/vendor/itertools-0.8.2/Cargo.toml +++ /dev/null @@ -1,47 +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 = "itertools" -version = "0.8.2" -authors = ["bluss"] -exclude = ["/bors.toml"] -description = "Extra iterator adaptors, iterator methods, free functions, and macros." -documentation = "https://docs.rs/itertools/" -keywords = ["iterator", "data-structure", "zip", "product", "group-by"] -categories = ["algorithms", "rust-patterns"] -license = "MIT/Apache-2.0" -repository = "https://github.com/bluss/rust-itertools" -[package.metadata.release] -no-dev-version = true -[profile.bench] -debug = true - -[lib] -test = false -bench = false -[dependencies.either] -version = "1.0" -default-features = false -[dev-dependencies.permutohedron] -version = "0.2" - -[dev-dependencies.quickcheck] -version = "0.7" -default-features = false - -[dev-dependencies.rand] -version = "0.6" - -[features] -default = ["use_std"] -use_std = [] diff --git a/vendor/itertools-0.8.2/README.rst b/vendor/itertools-0.8.2/README.rst deleted file mode 100644 index b06751afef..0000000000 --- a/vendor/itertools-0.8.2/README.rst +++ /dev/null @@ -1,620 +0,0 @@ - -Itertools -========= - -Extra iterator adaptors, functions and macros. - -Please read the `API documentation here`__ - -__ https://docs.rs/itertools/ - -|build_status|_ |crates|_ - -.. |build_status| image:: https://travis-ci.org/rust-itertools/itertools.svg?branch=master -.. _build_status: https://travis-ci.org/rust-itertools/itertools - -.. |crates| image:: http://meritbadge.herokuapp.com/itertools -.. _crates: https://crates.io/crates/itertools - -How to use with cargo: - -.. code:: toml - - [dependencies] - itertools = "0.8" - -How to use in your crate: - -.. code:: rust - - #[macro_use] extern crate itertools; - - use itertools::Itertools; - -How to contribute ------------------ - -- Fix a bug or implement a new thing -- Include tests for your new feature, preferably a quickcheck test -- Make a Pull Request - -For new features, please first consider filing a PR to `rust-lang/rust `_, -adding your new feature to the `Iterator` trait of the standard library, if you believe it is reasonable. -If it isn't accepted there, proposing it for inclusion in ``itertools`` is a good idea. -The reason for doing is this is so that we avoid future breakage as with ``.flatten()``. -However, if your feature involves heap allocation, such as storing elements in a ``Vec``, -then it can't be accepted into ``libcore``, and you should propose it for ``itertools`` directly instead. - -Recent Changes --------------- -- 0.8.2 - - - Use :code:`slice::iter` instead of :code:`into_iter` to avoid future breakage (`#378 `_, by `@LukasKalbertodt `_) - -- 0.8.1 - - - Added a `.exactly_one() `_ - iterator method that, on success, extracts the single value of an - iterator - ; by `@Xaeroxe `_ - - - Added combinatory iterator adaptors: - - - `.permutations(k) `_: - - ``[0, 1, 2].iter().permutations(2)`` yields - - .. code:: rust - - [ - vec![0, 1], - vec![0, 2], - vec![1, 0], - vec![1, 2], - vec![2, 0], - vec![2, 1], - ] - - ; by `@tobz1000 `_ - - - `.combinations_with_replacement(k) `_: - - ``[0, 1, 2].iter().combinations_with_replacement(2)`` yields - - .. code:: rust - - [ - vec![0, 0], - vec![0, 1], - vec![0, 2], - vec![1, 1], - vec![1, 2], - vec![2, 2], - ] - - ; by `@tommilligan `_ - - - For reference, these methods join the already existing - `.combinations(k) `_: - - ``[0, 1, 2].iter().combinations(2)`` yields - - .. code:: rust - - [ - vec![0, 1], - vec![0, 2], - vec![1, 2], - ] - - - Improved the performance of `.fold() `_-based internal iteration for the - `.intersperse() `_ iterator - ; by `@jswrenn `_ - - - Added - `.dedup_by() `_, - `.merge_by() `_ - and `.kmerge_by() `_ - adaptors that work like - `.dedup() `_, - `.merge() `_ and - `.kmerge() `_, - but taking an additional custom comparison closure parameter. - ; by `@phimuemue `_ - - - Improved the performance of `.all_equal() `_ - ; by `@fyrchik `_ - - - Loosened the bounds on `.partition_map() `_ - to take just a ``FnMut`` closure rather than a ``Fn`` closure, and made its - implementation use internal iteration for better performance - ; by `@danielhenrymantilla `_ - - - Added convenience methods to - `EitherOrBoth `_ elements yielded from the - `.zip_longest() `_ iterator adaptor - ; by `@Avi-D-coder `_ - - - Added `.sum1() `_ - and `.product1() `_ - iterator methods that respectively try to return the sum and the product of - the elements of an iterator **when it is not empty**, otherwise they return - ``None`` - ; by `@Emerentius `_ - -- 0.8.0 - - - Added new adaptor ``.map_into()`` for conversions using ``Into`` by @vorner - - Improved ``Itertools`` docs by @JohnHeitmann - - The return type of ``.sorted/_by/_by_key()`` is now an iterator, not a Vec. - - The return type of the ``izip!(x, y)`` macro with exactly two arguments - is now the usual ``Iterator::zip``. - - Remove ``.flatten()`` in favour of std's ``.flatten()`` - - Deprecate ``.foreach()`` in favour of std's ``.for_each()`` - - Deprecate ``.step()`` in favour of std's ``.step_by()`` - - Deprecate ``repeat_call`` in favour of std's ``repeat_with`` - - Deprecate ``.fold_while()`` in favour of std's ``.try_fold()`` - - Require Rust 1.24 as minimal version. - -- 0.7.11 - - - Add convenience methods to ``EitherOrBoth``, making it more similar to ``Option`` - and ``Either`` by @jethrogb - -- 0.7.10 - - - No changes. - -- 0.7.9 - - - New inclusion policy: See the readme about suggesting features for std before - accepting them in itertools. - - The ``FoldWhile`` type now implements ``Eq`` and ``PartialEq`` by @jturner314 - -- 0.7.8 - - - Add new iterator method ``.tree_fold1()`` which is like ``.fold1()`` - except items are combined in a tree structure (see its docs). - By @scottmcm - - Add more ``Debug`` impls by @phimuemue: KMerge, KMergeBy, MergeJoinBy, - ConsTuples, Intersperse, ProcessResults, RcIter, Tee, TupleWindows, Tee, - ZipLongest, ZipEq, Zip. - -- 0.7.7 - - - Add new iterator method ``.into_group_map() -> HashMap>`` - which turns an iterator of ``(K, V)`` elements into such a hash table, - where values are grouped by key. By @tobz1000 - - Add new free function ``flatten`` for the ``.flatten()`` adaptor. - **NOTE:** recent Rust nightlies have ``Iterator::flatten`` and thus a clash - with our flatten adaptor. One workaround is to use the itertools ``flatten`` - free function. - -- 0.7.6 - - - Add new adaptor ``.multi_cartesian_product()`` which is an n-ary product - iterator by @tobz1000 - - Add new method ``.sorted_by_key()`` by @Xion - - Provide simpler and faster ``.count()`` for ``.unique()`` and ``.unique_by()`` - -- 0.7.5 - - - ``.multipeek()`` now implements ``PeekingNext``, by @nicopap. - -- 0.7.4 - - - Add new adaptor ``.update()`` by @lucasem; this adaptor is used - to modify an element before passing it on in an iterator chain. - -- 0.7.3 - - - Add new method ``.collect_tuple()`` by @matklad; it makes a tuple out of - the iterator's elements if the number of them matches **exactly**. - - Implement ``fold`` and ``collect`` for ``.map_results()`` which means - it reuses the code of the standard ``.map()`` for these methods. - -- 0.7.2 - - - Add new adaptor ``.merge_join_by`` by @srijs; a heterogeneous merge join - for two ordered sequences. - -- 0.7.1 - - - Iterator adaptors and iterators in itertools now use the same ``must_use`` - reminder that the standard library adaptors do, by @matematikaedit and @bluss - *“iterator adaptors are lazy and do nothing unless consumed”*. - -- 0.7.0 - - - Faster ``izip!()`` by @krdln - - - ``izip!()`` is now a wrapper for repeated regular ``.zip()`` and - a single ``.map()``. This means it optimizes as well as the standard - library ``.zip()`` it uses. - **Note:** ``multizip`` and ``izip!()`` are now different! The former - has a named type but the latter optimizes better. - - - Faster ``.unique()`` - - - ``no_std`` support, which is opt-in! - - - Many lovable features are still there without std, like ``izip!()`` - or ``.format()`` or ``.merge()``, but not those that use collections. - - - Trait bounds were required up front instead of just on the type: - ``group_by``'s ``PartialEq`` by @Phlosioneer and ``repeat_call``'s - ``FnMut``. - - Removed deprecated constructor ``Zip::new`` — use ``izip!()`` or ``multizip()`` - -- 0.6.5 - - - Fix bug in ``.cartesian_product()``'s fold (which only was visible for - unfused iterators). - -- 0.6.4 - - - Add specific ``fold`` implementations for ``.cartesian_product()`` and - ``cons_tuples()``, which improves their performance in fold, foreach, and - iterator consumers derived from them. - -- 0.6.3 - - - Add iterator adaptor ``.positions(predicate)`` by @tmccombs - -- 0.6.2 - - - Add function ``process_results`` which can “lift” a function of the regular - values of an iterator so that it can process the ``Ok`` values from an - iterator of ``Results`` instead, by @shepmaster - - Add iterator method ``.concat()`` which combines all iterator elements - into a single collection using the ``Extend`` trait, by @srijs - -- 0.6.1 - - - Better size hint testing and subsequent size hint bugfixes by @rkarp. - Fixes bugs in product, interleave_shortest size hints. - - New iterator method ``.all_equal()`` by @phimuemue - -- 0.6.0 - - - Deprecated names were removed in favour of their replacements - - ``.flatten()`` does not implement double ended iteration anymore - - ``.fold_while()`` uses ``&mut self`` and returns ``FoldWhile``, for - composability (#168) - - ``.foreach()`` and ``.fold1()`` use ``self``, like ``.fold()`` does. - - ``.combinations(0)`` now produces a single empty vector. (#174) - -- 0.5.10 - - - Add itertools method ``.kmerge_by()`` (and corresponding free function) - - Relaxed trait requirement of ``.kmerge()`` and ``.minmax()`` to PartialOrd. - -- 0.5.9 - - - Add multipeek method ``.reset_peek()`` - - Add categories - -- 0.5.8 - - - Add iterator adaptor ``.peeking_take_while()`` and its trait ``PeekingNext``. - -- 0.5.7 - - - Add iterator adaptor ``.with_position()`` - - Fix multipeek's performance for long peeks by using ``VecDeque``. - -- 0.5.6 - - - Add ``.map_results()`` - -- 0.5.5 - - - Many more adaptors now implement ``Debug`` - - Add free function constructor ``repeat_n``. ``RepeatN::new`` is now - deprecated. - -- 0.5.4 - - - Add infinite generator function ``iterate``, that takes a seed and a - closure. - -- 0.5.3 - - - Special-cased ``.fold()`` for flatten and put back. ``.foreach()`` - now uses fold on the iterator, to pick up any iterator specific loop - implementation. - - ``.combinations(n)`` asserts up front that ``n != 0``, instead of - running into an error on the second iterator element. - -- 0.5.2 - - - Add ``.tuples::()`` that iterates by two, three or four elements at - a time (where ``T`` is a tuple type). - - Add ``.tuple_windows::()`` that iterates using a window of the - two, three or four most recent elements. - - Add ``.next_tuple::()`` method, that picks the next two, three or four - elements in one go. - - ``.interleave()`` now has an accurate size hint. - -- 0.5.1 - - - Workaround module/function name clash that made racer crash on completing - itertools. Only internal changes needed. - -- 0.5.0 - - - `Release announcement `_ - - Renamed: - - - combinations is now tuple_combinations - - combinations_n to combinations - - group_by_lazy, chunks_lazy to group_by, chunks - - Unfold::new to unfold() - - RepeatCall::new to repeat_call() - - Zip::new to multizip - - PutBack::new, PutBackN::new to put_back, put_back_n - - PutBack::with_value is now a builder setter, not a constructor - - MultiPeek::new, .multipeek() to multipeek() - - format to format_with and format_default to format - - .into_rc() to rciter - - ``Partition`` enum is now ``Either`` - - - Module reorganization: - - - All iterator structs are under ``itertools::structs`` but also - reexported to the top level, for backwards compatibility - - All free functions are reexported at the root, ``itertools::free`` will - be removed in the next version - - - Removed: - - - ZipSlices, use .zip() instead - - .enumerate_from(), ZipTrusted, due to being unstable - - .mend_slices(), moved to crate odds - - Stride, StrideMut, moved to crate odds - - linspace(), moved to crate itertools-num - - .sort_by(), use .sorted_by() - - .is_empty_hint(), use .size_hint() - - .dropn(), use .dropping() - - .map_fn(), use .map() - - .slice(), use .take() / .skip() - - helper traits in misc - - ``new`` constructors on iterator structs, use Itertools trait or free - functions instead - - ``itertools::size_hint`` is now private - - - Behaviour changes: - - - format and format_with helpers now panic if you try to format them more - than once. - - ``repeat_call`` is not double ended anymore - - - New features: - - - tuple flattening iterator is constructible with ``cons_tuples`` - - itertools reexports ``Either`` from the ``either`` crate. ``Either`` - is an iterator when ``L, R`` are. - - ``MinMaxResult`` now implements Copy and Clone - - tuple_combinations supports 1-4 tuples of combinations (previously just 2) - -- 0.4.19 - - - Add ``.minmax_by()`` - - Add ``itertools::free::cloned`` - - Add ``itertools::free::rciter`` - - Improve ``.step(n)`` slightly to take advantage of specialized Fuse better. - -- 0.4.18 - - - Only changes related to the "unstable" crate feature. This feature is more - or less deprecated. - - - Use deprecated warnings when unstable is enabled. .enumerate_from() will - be removed imminently since it's using a deprecated libstd trait. - -- 0.4.17 - - - Fix bug in .kmerge() that caused it to often produce the wrong order (#134) - -- 0.4.16 - - - Improve precision of the interleave_shortest adaptor's size hint (it is - now computed exactly when possible). - -- 0.4.15 - - - Fixup on top of the workaround in 0.4.14. A function in itertools::free was - removed by mistake and now it is added back again. - -- 0.4.14 - - - Workaround an upstream regression in a rust nightly build that broke - compilation of of itertools::free::{interleave, merge} - -- 0.4.13 - - - Add .minmax() and .minmax_by_key(), iterator methods for finding both minimum - and maximum in one scan. - - Add .format_default(), a simpler version of .format() (lazy formatting - for iterators). - -- 0.4.12 - - - Add .zip_eq(), an adaptor like .zip() except it ensures iterators - of inequal length don't pass silently (instead it panics). - - Add .fold_while(), an iterator method that is a fold that - can short-circuit. - - Add .partition_map(), an iterator method that can separate elements - into two collections. - -- 0.4.11 - - - Add .get() for Stride{,Mut} and .get_mut() for StrideMut - -- 0.4.10 - - - Improve performance of .kmerge() - -- 0.4.9 - - - Add k-ary merge adaptor .kmerge() - - Fix a bug in .islice() with ranges a..b where a > b. - -- 0.4.8 - - - Implement Clone, Debug for Linspace - -- 0.4.7 - - - Add function diff_with() that compares two iterators - - Add .combinations_n(), an n-ary combinations iterator - - Add methods PutBack::with_value and PutBack::into_parts. - -- 0.4.6 - - - Add method .sorted() - - Add module ``itertools::free`` with free function variants of common - iterator adaptors and methods. - For example ``enumerate(iterable)``, ``rev(iterable)``, and so on. - -- 0.4.5 - - - Add .flatten() - -- 0.4.4 - - - Allow composing ZipSlices with itself - -- 0.4.3 - - - Write iproduct!() as a single expression; this allows temporary values - in its arguments. - -- 0.4.2 - - - Add .fold_options() - - Require Rust 1.1 or later - -- 0.4.1 - - - Update .dropping() to take advantage of .nth() - -- 0.4.0 - - - .merge(), .unique() and .dedup() now perform better due to not using - function pointers - - Add free functions enumerate() and rev() - - Breaking changes: - - - Return types of .merge() and .merge_by() renamed and changed - - Method Merge::new removed - - .merge_by() now takes a closure that returns bool. - - Return type of .dedup() changed - - Return type of .mend_slices() changed - - Return type of .unique() changed - - Removed function times(), struct Times: use a range instead - - Removed deprecated macro icompr!() - - Removed deprecated FnMap and method .fn_map(): use .map_fn() - - .interleave_shortest() is no longer guaranteed to act like fused - -- 0.3.25 - - - Rename .sort_by() to .sorted_by(). Old name is deprecated. - - Fix well-formedness warnings from RFC 1214, no user visible impact - -- 0.3.24 - - - Improve performance of .merge()'s ordering function slightly - -- 0.3.23 - - - Added .chunks(), similar to (and based on) .group_by_lazy(). - - Tweak linspace to match numpy.linspace and make it double ended. - -- 0.3.22 - - - Added ZipSlices, a fast zip for slices - -- 0.3.21 - - - Remove `Debug` impl for `Format`, it will have different use later - -- 0.3.20 - - - Optimize .group_by_lazy() - -- 0.3.19 - - - Added .group_by_lazy(), a possibly nonallocating group by - - Added .format(), a nonallocating formatting helper for iterators - - Remove uses of RandomAccessIterator since it has been deprecated in rust. - -- 0.3.17 - - - Added (adopted) Unfold from rust - -- 0.3.16 - - - Added adaptors .unique(), .unique_by() - -- 0.3.15 - - - Added method .sort_by() - -- 0.3.14 - - - Added adaptor .while_some() - -- 0.3.13 - - - Added adaptor .interleave_shortest() - - Added adaptor .pad_using() - -- 0.3.11 - - - Added assert_equal function - -- 0.3.10 - - - Bugfix .combinations() size_hint. - -- 0.3.8 - - - Added source RepeatCall - -- 0.3.7 - - - Added adaptor PutBackN - - Added adaptor .combinations() - -- 0.3.6 - - - Added itertools::partition, partition a sequence in place based on a predicate. - - Deprecate icompr!() with no replacement. - -- 0.3.5 - - - .map_fn() replaces deprecated .fn_map(). - -- 0.3.4 - - - .take_while_ref() *by-ref adaptor* - - .coalesce() *adaptor* - - .mend_slices() *adaptor* - -- 0.3.3 - - - .dropping_back() *method* - - .fold1() *method* - - .is_empty_hint() *method* - -License -------- - -Dual-licensed to be compatible with the Rust project. - -Licensed under the Apache License, Version 2.0 -http://www.apache.org/licenses/LICENSE-2.0 or the MIT license -http://opensource.org/licenses/MIT, at your -option. This file may not be copied, modified, or distributed -except according to those terms. diff --git a/vendor/itertools-0.8.2/benches/bench1.rs b/vendor/itertools-0.8.2/benches/bench1.rs deleted file mode 100644 index 5d2adcad40..0000000000 --- a/vendor/itertools-0.8.2/benches/bench1.rs +++ /dev/null @@ -1,806 +0,0 @@ -#![feature(test)] - -extern crate test; -#[macro_use] extern crate itertools; - -use test::{black_box}; -use itertools::Itertools; - -use itertools::free::cloned; -use itertools::Permutations; - -use std::iter::repeat; -use std::cmp; -use std::ops::{Add, Range}; - -mod extra; - -use extra::ZipSlices; - -#[bench] -fn slice_iter(b: &mut test::Bencher) -{ - let xs: Vec<_> = repeat(1i32).take(20).collect(); - b.iter(|| for elt in xs.iter() { - test::black_box(elt); - }) -} - -#[bench] -fn slice_iter_rev(b: &mut test::Bencher) -{ - let xs: Vec<_> = repeat(1i32).take(20).collect(); - b.iter(|| for elt in xs.iter().rev() { - test::black_box(elt); - }) -} - -#[bench] -fn zip_default_zip(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - for (&x, &y) in xs.iter().zip(&ys) { - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipdot_i32_default_zip(b: &mut test::Bencher) -{ - let xs = vec![2; 1024]; - let ys = vec![2; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let mut s = 0; - for (&x, &y) in xs.iter().zip(&ys) { - s += x * y; - } - s - }) -} - -#[bench] -fn zipdot_f32_default_zip(b: &mut test::Bencher) -{ - let xs = vec![2f32; 1024]; - let ys = vec![2f32; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let mut s = 0.; - for (&x, &y) in xs.iter().zip(&ys) { - s += x * y; - } - s - }) -} - -#[bench] -fn zip_default_zip3(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let zs = vec![0; 766]; - let xs = black_box(xs); - let ys = black_box(ys); - let zs = black_box(zs); - - b.iter(|| { - for ((&x, &y), &z) in xs.iter().zip(&ys).zip(&zs) { - test::black_box(x); - test::black_box(y); - test::black_box(z); - } - }) -} - -#[bench] -fn zip_slices_ziptuple(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - - b.iter(|| { - let xs = black_box(&xs); - let ys = black_box(&ys); - for (&x, &y) in itertools::multizip((xs, ys)) { - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipslices(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - for (&x, &y) in ZipSlices::new(&xs, &ys) { - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipslices_mut(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let mut ys = black_box(ys); - - b.iter(|| { - for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) { - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipdot_i32_zipslices(b: &mut test::Bencher) -{ - let xs = vec![2; 1024]; - let ys = vec![2; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let mut s = 0i32; - for (&x, &y) in ZipSlices::new(&xs, &ys) { - s += x * y; - } - s - }) -} - -#[bench] -fn zipdot_f32_zipslices(b: &mut test::Bencher) -{ - let xs = vec![2f32; 1024]; - let ys = vec![2f32; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let mut s = 0.; - for (&x, &y) in ZipSlices::new(&xs, &ys) { - s += x * y; - } - s - }) -} - - -#[bench] -fn zip_checked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - // Must slice to equal lengths, and then bounds checks are eliminated! - let len = cmp::min(xs.len(), ys.len()); - let xs = &xs[..len]; - let ys = &ys[..len]; - - for i in 0..len { - let x = xs[i]; - let y = ys[i]; - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipdot_i32_checked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![2; 1024]; - let ys = vec![2; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - // Must slice to equal lengths, and then bounds checks are eliminated! - let len = cmp::min(xs.len(), ys.len()); - let xs = &xs[..len]; - let ys = &ys[..len]; - - let mut s = 0i32; - - for i in 0..len { - s += xs[i] * ys[i]; - } - s - }) -} - -#[bench] -fn zipdot_f32_checked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![2f32; 1024]; - let ys = vec![2f32; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - // Must slice to equal lengths, and then bounds checks are eliminated! - let len = cmp::min(xs.len(), ys.len()); - let xs = &xs[..len]; - let ys = &ys[..len]; - - let mut s = 0.; - - for i in 0..len { - s += xs[i] * ys[i]; - } - s - }) -} - -#[bench] -fn zipdot_f32_checked_counted_unrolled_loop(b: &mut test::Bencher) -{ - let xs = vec![2f32; 1024]; - let ys = vec![2f32; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - // Must slice to equal lengths, and then bounds checks are eliminated! - let len = cmp::min(xs.len(), ys.len()); - let mut xs = &xs[..len]; - let mut ys = &ys[..len]; - - let mut s = 0.; - let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) = - (0., 0., 0., 0., 0., 0., 0., 0.); - - // how to unroll and have bounds checks eliminated (by cristicbz) - // split sum into eight parts to enable vectorization (by bluss) - while xs.len() >= 8 { - p0 += xs[0] * ys[0]; - p1 += xs[1] * ys[1]; - p2 += xs[2] * ys[2]; - p3 += xs[3] * ys[3]; - p4 += xs[4] * ys[4]; - p5 += xs[5] * ys[5]; - p6 += xs[6] * ys[6]; - p7 += xs[7] * ys[7]; - - xs = &xs[8..]; - ys = &ys[8..]; - } - s += p0 + p4; - s += p1 + p5; - s += p2 + p6; - s += p3 + p7; - - for i in 0..xs.len() { - s += xs[i] * ys[i]; - } - s - }) -} - -#[bench] -fn zip_unchecked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let len = cmp::min(xs.len(), ys.len()); - for i in 0..len { - unsafe { - let x = *xs.get_unchecked(i); - let y = *ys.get_unchecked(i); - test::black_box(x); - test::black_box(y); - } - } - }) -} - -#[bench] -fn zipdot_i32_unchecked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![2; 1024]; - let ys = vec![2; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let len = cmp::min(xs.len(), ys.len()); - let mut s = 0i32; - for i in 0..len { - unsafe { - let x = *xs.get_unchecked(i); - let y = *ys.get_unchecked(i); - s += x * y; - } - } - s - }) -} - -#[bench] -fn zipdot_f32_unchecked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![2.; 1024]; - let ys = vec![2.; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let len = cmp::min(xs.len(), ys.len()); - let mut s = 0f32; - for i in 0..len { - unsafe { - let x = *xs.get_unchecked(i); - let y = *ys.get_unchecked(i); - s += x * y; - } - } - s - }) -} - -#[bench] -fn zip_unchecked_counted_loop3(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let zs = vec![0; 766]; - let xs = black_box(xs); - let ys = black_box(ys); - let zs = black_box(zs); - - b.iter(|| { - let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len())); - for i in 0..len { - unsafe { - let x = *xs.get_unchecked(i); - let y = *ys.get_unchecked(i); - let z = *zs.get_unchecked(i); - test::black_box(x); - test::black_box(y); - test::black_box(z); - } - } - }) -} - -#[bench] -fn group_by_lazy_1(b: &mut test::Bencher) { - let mut data = vec![0; 1024]; - for (index, elt) in data.iter_mut().enumerate() { - *elt = index / 10; - } - - let data = test::black_box(data); - - b.iter(|| { - for (_key, group) in &data.iter().group_by(|elt| **elt) { - for elt in group { - test::black_box(elt); - } - } - }) -} - -#[bench] -fn group_by_lazy_2(b: &mut test::Bencher) { - let mut data = vec![0; 1024]; - for (index, elt) in data.iter_mut().enumerate() { - *elt = index / 2; - } - - let data = test::black_box(data); - - b.iter(|| { - for (_key, group) in &data.iter().group_by(|elt| **elt) { - for elt in group { - test::black_box(elt); - } - } - }) -} - -#[bench] -fn slice_chunks(b: &mut test::Bencher) { - let data = vec![0; 1024]; - - let data = test::black_box(data); - let sz = test::black_box(10); - - b.iter(|| { - for group in data.chunks(sz) { - for elt in group { - test::black_box(elt); - } - } - }) -} - -#[bench] -fn chunks_lazy_1(b: &mut test::Bencher) { - let data = vec![0; 1024]; - - let data = test::black_box(data); - let sz = test::black_box(10); - - b.iter(|| { - for group in &data.iter().chunks(sz) { - for elt in group { - test::black_box(elt); - } - } - }) -} - -#[bench] -fn equal(b: &mut test::Bencher) { - let data = vec![7; 1024]; - let l = data.len(); - let alpha = test::black_box(&data[1..]); - let beta = test::black_box(&data[..l - 1]); - b.iter(|| { - itertools::equal(alpha, beta) - }) -} - -#[bench] -fn merge_default(b: &mut test::Bencher) { - let mut data1 = vec![0; 1024]; - let mut data2 = vec![0; 800]; - let mut x = 0; - for (_, elt) in data1.iter_mut().enumerate() { - *elt = x; - x += 1; - } - - let mut y = 0; - for (i, elt) in data2.iter_mut().enumerate() { - *elt += y; - if i % 3 == 0 { - y += 3; - } else { - y += 0; - } - } - let data1 = test::black_box(data1); - let data2 = test::black_box(data2); - b.iter(|| { - data1.iter().merge(&data2).count() - }) -} - -#[bench] -fn merge_by_cmp(b: &mut test::Bencher) { - let mut data1 = vec![0; 1024]; - let mut data2 = vec![0; 800]; - let mut x = 0; - for (_, elt) in data1.iter_mut().enumerate() { - *elt = x; - x += 1; - } - - let mut y = 0; - for (i, elt) in data2.iter_mut().enumerate() { - *elt += y; - if i % 3 == 0 { - y += 3; - } else { - y += 0; - } - } - let data1 = test::black_box(data1); - let data2 = test::black_box(data2); - b.iter(|| { - data1.iter().merge_by(&data2, PartialOrd::le).count() - }) -} - -#[bench] -fn merge_by_lt(b: &mut test::Bencher) { - let mut data1 = vec![0; 1024]; - let mut data2 = vec![0; 800]; - let mut x = 0; - for (_, elt) in data1.iter_mut().enumerate() { - *elt = x; - x += 1; - } - - let mut y = 0; - for (i, elt) in data2.iter_mut().enumerate() { - *elt += y; - if i % 3 == 0 { - y += 3; - } else { - y += 0; - } - } - let data1 = test::black_box(data1); - let data2 = test::black_box(data2); - b.iter(|| { - data1.iter().merge_by(&data2, |a, b| a <= b).count() - }) -} - -#[bench] -fn kmerge_default(b: &mut test::Bencher) { - let mut data1 = vec![0; 1024]; - let mut data2 = vec![0; 800]; - let mut x = 0; - for (_, elt) in data1.iter_mut().enumerate() { - *elt = x; - x += 1; - } - - let mut y = 0; - for (i, elt) in data2.iter_mut().enumerate() { - *elt += y; - if i % 3 == 0 { - y += 3; - } else { - y += 0; - } - } - let data1 = test::black_box(data1); - let data2 = test::black_box(data2); - let its = &[data1.iter(), data2.iter()]; - b.iter(|| { - its.iter().cloned().kmerge().count() - }) -} - -#[bench] -fn kmerge_tenway(b: &mut test::Bencher) { - let mut data = vec![0; 10240]; - - let mut state = 1729u16; - fn rng(state: &mut u16) -> u16 { - let new = state.wrapping_mul(31421) + 6927; - *state = new; - new - } - - for elt in &mut data { - *elt = rng(&mut state); - } - - let mut chunks = Vec::new(); - let mut rest = &mut data[..]; - while rest.len() > 0 { - let chunk_len = 1 + rng(&mut state) % 512; - let chunk_len = cmp::min(rest.len(), chunk_len as usize); - let (fst, tail) = {rest}.split_at_mut(chunk_len); - fst.sort(); - chunks.push(fst.iter().cloned()); - rest = tail; - } - - // println!("Chunk lengths: {}", chunks.iter().format_with(", ", |elt, f| f(&elt.len()))); - - b.iter(|| { - chunks.iter().cloned().kmerge().count() - }) -} - - -fn fast_integer_sum(iter: I) -> I::Item - where I: IntoIterator, - I::Item: Default + Add -{ - iter.into_iter().fold(<_>::default(), |x, y| x + y) -} - - -#[bench] -fn step_vec_2(b: &mut test::Bencher) { - let v = vec![0; 1024]; - b.iter(|| { - fast_integer_sum(cloned(v.iter().step(2))) - }); -} - -#[bench] -fn step_vec_10(b: &mut test::Bencher) { - let v = vec![0; 1024]; - b.iter(|| { - fast_integer_sum(cloned(v.iter().step(10))) - }); -} - -#[bench] -fn step_range_2(b: &mut test::Bencher) { - let v = black_box(0..1024); - b.iter(|| { - fast_integer_sum(v.clone().step(2)) - }); -} - -#[bench] -fn step_range_10(b: &mut test::Bencher) { - let v = black_box(0..1024); - b.iter(|| { - fast_integer_sum(v.clone().step(10)) - }); -} - -#[bench] -fn cartesian_product_iterator(b: &mut test::Bencher) -{ - let xs = vec![0; 16]; - - b.iter(|| { - let mut sum = 0; - for (&x, &y, &z) in iproduct!(&xs, &xs, &xs) { - sum += x; - sum += y; - sum += z; - } - sum - }) -} - -#[bench] -fn cartesian_product_fold(b: &mut test::Bencher) -{ - let xs = vec![0; 16]; - - b.iter(|| { - let mut sum = 0; - iproduct!(&xs, &xs, &xs).fold((), |(), (&x, &y, &z)| { - sum += x; - sum += y; - sum += z; - }); - sum - }) -} - -#[bench] -fn multi_cartesian_product_iterator(b: &mut test::Bencher) -{ - let xs = [vec![0; 16], vec![0; 16], vec![0; 16]]; - - b.iter(|| { - let mut sum = 0; - for x in xs.iter().multi_cartesian_product() { - sum += x[0]; - sum += x[1]; - sum += x[2]; - } - sum - }) -} - -#[bench] -fn multi_cartesian_product_fold(b: &mut test::Bencher) -{ - let xs = [vec![0; 16], vec![0; 16], vec![0; 16]]; - - b.iter(|| { - let mut sum = 0; - xs.iter().multi_cartesian_product().fold((), |(), x| { - sum += x[0]; - sum += x[1]; - sum += x[2]; - }); - sum - }) -} - -#[bench] -fn cartesian_product_nested_for(b: &mut test::Bencher) -{ - let xs = vec![0; 16]; - - b.iter(|| { - let mut sum = 0; - for &x in &xs { - for &y in &xs { - for &z in &xs { - sum += x; - sum += y; - sum += z; - } - } - } - sum - }) -} - -#[bench] -fn all_equal(b: &mut test::Bencher) { - let mut xs = vec![0; 5_000_000]; - xs.extend(vec![1; 5_000_000]); - - b.iter(|| xs.iter().all_equal()) -} - -#[bench] -fn all_equal_for(b: &mut test::Bencher) { - let mut xs = vec![0; 5_000_000]; - xs.extend(vec![1; 5_000_000]); - - b.iter(|| { - for &x in &xs { - if x != xs[0] { - return false; - } - } - true - }) -} - -#[bench] -fn all_equal_default(b: &mut test::Bencher) { - let mut xs = vec![0; 5_000_000]; - xs.extend(vec![1; 5_000_000]); - - b.iter(|| xs.iter().dedup().nth(1).is_none()) -} - -const PERM_COUNT: usize = 6; - -#[bench] -fn permutations_iter(b: &mut test::Bencher) { - struct NewIterator(Range); - - impl Iterator for NewIterator { - type Item = usize; - - fn next(&mut self) -> Option { - self.0.next() - } - } - - b.iter(|| { - for _ in NewIterator(0..PERM_COUNT).permutations(PERM_COUNT) { - - } - }) -} - -#[bench] -fn permutations_range(b: &mut test::Bencher) { - b.iter(|| { - for _ in (0..PERM_COUNT).permutations(PERM_COUNT) { - - } - }) -} - -#[bench] -fn permutations_slice(b: &mut test::Bencher) { - let v = (0..PERM_COUNT).collect_vec(); - - b.iter(|| { - for _ in v.as_slice().iter().permutations(PERM_COUNT) { - - } - }) -} diff --git a/vendor/itertools-0.8.2/benches/combinations_with_replacement.rs b/vendor/itertools-0.8.2/benches/combinations_with_replacement.rs deleted file mode 100644 index 0652e49e79..0000000000 --- a/vendor/itertools-0.8.2/benches/combinations_with_replacement.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![feature(test)] - -extern crate itertools; -extern crate test; - -use itertools::Itertools; -use test::{black_box, Bencher}; - -#[bench] -fn comb_replacement_n10_k5(b: &mut Bencher) { - b.iter(|| { - for i in (0..10).combinations_with_replacement(5) { - black_box(i); - } - }); -} - -#[bench] -fn comb_replacement_n5_k10(b: &mut Bencher) { - b.iter(|| { - for i in (0..5).combinations_with_replacement(10) { - black_box(i); - } - }); -} - -#[bench] -fn comb_replacement_n10_k10(b: &mut Bencher) { - b.iter(|| { - for i in (0..10).combinations_with_replacement(10) { - black_box(i); - } - }); -} diff --git a/vendor/itertools-0.8.2/benches/extra/mod.rs b/vendor/itertools-0.8.2/benches/extra/mod.rs deleted file mode 100644 index 5ddb5772f4..0000000000 --- a/vendor/itertools-0.8.2/benches/extra/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ - - -pub use self::zipslices::ZipSlices; -mod zipslices; diff --git a/vendor/itertools-0.8.2/benches/extra/zipslices.rs b/vendor/itertools-0.8.2/benches/extra/zipslices.rs deleted file mode 100644 index 493a539fd6..0000000000 --- a/vendor/itertools-0.8.2/benches/extra/zipslices.rs +++ /dev/null @@ -1,189 +0,0 @@ -use std::cmp; - -// Note: There are different ways to implement ZipSlices. -// This version performed the best in benchmarks. -// -// I also implemented a version with three pointes (tptr, tend, uptr), -// that mimiced slice::Iter and only checked bounds by using tptr == tend, -// but that was inferior to this solution. - -/// An iterator which iterates two slices simultaneously. -/// -/// `ZipSlices` acts like a double-ended `.zip()` iterator. -/// -/// It was intended to be more efficient than `.zip()`, and it was, then -/// rustc changed how it optimizes so it can not promise improved performance -/// at this time. -/// -/// Note that elements past the end of the shortest of the two slices are ignored. -/// -/// Iterator element type for `ZipSlices` is `(T::Item, U::Item)`. For example, -/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`. -#[derive(Clone)] -pub struct ZipSlices { - t: T, - u: U, - len: usize, - index: usize, -} - -impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]> { - /// Create a new `ZipSlices` from slices `a` and `b`. - /// - /// Act like a double-ended `.zip()` iterator, but more efficiently. - /// - /// Note that elements past the end of the shortest of the two slices are ignored. - #[inline(always)] - pub fn new(a: &'a [A], b: &'b [B]) -> Self { - let minl = cmp::min(a.len(), b.len()); - ZipSlices { - t: a, - u: b, - len: minl, - index: 0, - } - } -} - -impl ZipSlices - where T: Slice, - U: Slice -{ - /// Create a new `ZipSlices` from slices `a` and `b`. - /// - /// Act like a double-ended `.zip()` iterator, but more efficiently. - /// - /// Note that elements past the end of the shortest of the two slices are ignored. - #[inline(always)] - pub fn from_slices(a: T, b: U) -> Self { - let minl = cmp::min(a.len(), b.len()); - ZipSlices { - t: a, - u: b, - len: minl, - index: 0, - } - } -} - -impl Iterator for ZipSlices - where T: Slice, - U: Slice -{ - type Item = (T::Item, U::Item); - - #[inline(always)] - fn next(&mut self) -> Option { - unsafe { - if self.index >= self.len { - None - } else { - let i = self.index; - self.index += 1; - Some(( - self.t.get_unchecked(i), - self.u.get_unchecked(i))) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.len - self.index; - (len, Some(len)) - } -} - -impl DoubleEndedIterator for ZipSlices - where T: Slice, - U: Slice -{ - #[inline(always)] - fn next_back(&mut self) -> Option { - unsafe { - if self.index >= self.len { - None - } else { - self.len -= 1; - let i = self.len; - Some(( - self.t.get_unchecked(i), - self.u.get_unchecked(i))) - } - } - } -} - -impl ExactSizeIterator for ZipSlices - where T: Slice, - U: Slice -{} - -unsafe impl Slice for ZipSlices - where T: Slice, - U: Slice -{ - type Item = (T::Item, U::Item); - - fn len(&self) -> usize { - self.len - self.index - } - - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - (self.t.get_unchecked(i), - self.u.get_unchecked(i)) - } -} - -/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`. -/// -/// Unsafe trait because: -/// -/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`. -pub unsafe trait Slice { - /// The type of a reference to the slice's elements - type Item; - #[doc(hidden)] - fn len(&self) -> usize; - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item; -} - -unsafe impl<'a, T> Slice for &'a [T] { - type Item = &'a T; - #[inline(always)] - fn len(&self) -> usize { (**self).len() } - #[inline(always)] - unsafe fn get_unchecked(&mut self, i: usize) -> &'a T { - debug_assert!(i < self.len()); - (**self).get_unchecked(i) - } -} - -unsafe impl<'a, T> Slice for &'a mut [T] { - type Item = &'a mut T; - #[inline(always)] - fn len(&self) -> usize { (**self).len() } - #[inline(always)] - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T { - debug_assert!(i < self.len()); - // override the lifetime constraints of &mut &'a mut [T] - (*(*self as *mut [T])).get_unchecked_mut(i) - } -} - -#[test] -fn zipslices() { - - let xs = [1, 2, 3, 4, 5, 6]; - let ys = [1, 2, 3, 7]; - ::itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys)); - - let xs = [1, 2, 3, 4, 5, 6]; - let mut ys = [0; 6]; - for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) { - *y = *x; - } - ::itertools::assert_equal(&xs, &ys); -} - diff --git a/vendor/itertools-0.8.2/benches/fold_specialization.rs b/vendor/itertools-0.8.2/benches/fold_specialization.rs deleted file mode 100644 index db3c995876..0000000000 --- a/vendor/itertools-0.8.2/benches/fold_specialization.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate itertools; - -use itertools::Itertools; - -struct Unspecialized(I); - -impl Iterator for Unspecialized -where I: Iterator -{ - type Item = I::Item; - - #[inline(always)] - fn next(&mut self) -> Option { - self.0.next() - } - - #[inline(always)] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} - -mod specialization { - use super::*; - - mod intersperse { - use super::*; - - #[bench] - fn external(b: &mut test::Bencher) - { - let arr = [1; 1024]; - - b.iter(|| { - let mut sum = 0; - for &x in arr.into_iter().intersperse(&0) { - sum += x; - } - sum - }) - } - - #[bench] - fn internal_specialized(b: &mut test::Bencher) - { - let arr = [1; 1024]; - - b.iter(|| { - arr.into_iter().intersperse(&0).fold(0, |acc, x| acc + x) - }) - } - - #[bench] - fn internal_unspecialized(b: &mut test::Bencher) - { - let arr = [1; 1024]; - - b.iter(|| { - Unspecialized(arr.into_iter().intersperse(&0)).fold(0, |acc, x| acc + x) - }) - } - } -} diff --git a/vendor/itertools-0.8.2/benches/tree_fold1.rs b/vendor/itertools-0.8.2/benches/tree_fold1.rs deleted file mode 100644 index b71589f3fe..0000000000 --- a/vendor/itertools-0.8.2/benches/tree_fold1.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate itertools; - -use itertools::Itertools; -use itertools::cloned; -use test::Bencher; - -trait IterEx : Iterator { - // Another efficient implementation against which to compare, - // but needs `std` so is less desirable. - fn tree_fold1_vec(self, mut f: F) -> Option - where F: FnMut(Self::Item, Self::Item) -> Self::Item, - Self: Sized, - { - let hint = self.size_hint().0; - let cap = std::mem::size_of::() * 8 - hint.leading_zeros() as usize; - let mut stack = Vec::with_capacity(cap); - self.enumerate().foreach(|(mut i, mut x)| { - while (i & 1) != 0 { - x = f(stack.pop().unwrap(), x); - i >>= 1; - } - stack.push(x); - }); - stack.into_iter().fold1(f) - } -} -impl IterEx for T {} - -macro_rules! def_benchs { - ($N:expr, - $FUN:ident, - $BENCH_NAME:ident, - ) => ( - mod $BENCH_NAME { - use super::*; - - #[bench] - fn sum(b: &mut Bencher) { - let v: Vec = (0.. $N).collect(); - b.iter(|| { - cloned(&v).$FUN(|x, y| x + y) - }); - } - - #[bench] - fn complex_iter(b: &mut Bencher) { - let u = (3..).take($N / 2); - let v = (5..).take($N / 2); - let it = u.chain(v); - - b.iter(|| { - it.clone().map(|x| x as f32).$FUN(f32::atan2) - }); - } - - #[bench] - fn string_format(b: &mut Bencher) { - // This goes quadratic with linear `fold1`, so use a smaller - // size to not waste too much time in travis. The allocations - // in here are so expensive anyway that it'll still take - // way longer per iteration than the other two benchmarks. - let v: Vec = (0.. ($N/4)).collect(); - b.iter(|| { - cloned(&v).map(|x| x.to_string()).$FUN(|x, y| format!("{} + {}", x, y)) - }); - } - } - ) -} - -def_benchs!{ - 10_000, - fold1, - fold1_10k, -} - -def_benchs!{ - 10_000, - tree_fold1, - tree_fold1_stack_10k, -} - -def_benchs!{ - 10_000, - tree_fold1_vec, - tree_fold1_vec_10k, -} - -def_benchs!{ - 100, - fold1, - fold1_100, -} - -def_benchs!{ - 100, - tree_fold1, - tree_fold1_stack_100, -} - -def_benchs!{ - 100, - tree_fold1_vec, - tree_fold1_vec_100, -} - -def_benchs!{ - 8, - fold1, - fold1_08, -} - -def_benchs!{ - 8, - tree_fold1, - tree_fold1_stack_08, -} - -def_benchs!{ - 8, - tree_fold1_vec, - tree_fold1_vec_08, -} diff --git a/vendor/itertools-0.8.2/benches/tuple_combinations.rs b/vendor/itertools-0.8.2/benches/tuple_combinations.rs deleted file mode 100644 index 4a14b1d0bd..0000000000 --- a/vendor/itertools-0.8.2/benches/tuple_combinations.rs +++ /dev/null @@ -1,97 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate itertools; - -use test::{black_box, Bencher}; -use itertools::Itertools; - -// approximate 100_000 iterations for each combination -const N1: usize = 100_000; -const N2: usize = 448; -const N3: usize = 86; -const N4: usize = 41; - -#[bench] -fn comb_for1(b: &mut Bencher) { - b.iter(|| { - for i in 0..N1 { - black_box(i); - } - }); -} - -#[bench] -fn comb_for2(b: &mut Bencher) { - b.iter(|| { - for i in 0..N2 { - for j in (i + 1)..N2 { - black_box(i + j); - } - } - }); -} - -#[bench] -fn comb_for3(b: &mut Bencher) { - b.iter(|| { - for i in 0..N3 { - for j in (i + 1)..N3 { - for k in (j + 1)..N3 { - black_box(i + j + k); - } - } - } - }); -} - -#[bench] -fn comb_for4(b: &mut Bencher) { - b.iter(|| { - for i in 0..N4 { - for j in (i + 1)..N4 { - for k in (j + 1)..N4 { - for l in (k + 1)..N4 { - black_box(i + j + k + l); - } - } - } - } - }); -} - -#[bench] -fn comb_c1(b: &mut Bencher) { - b.iter(|| { - for (i,) in (0..N1).tuple_combinations() { - black_box(i); - } - }); -} - -#[bench] -fn comb_c2(b: &mut Bencher) { - b.iter(|| { - for (i, j) in (0..N2).tuple_combinations() { - black_box(i + j); - } - }); -} - -#[bench] -fn comb_c3(b: &mut Bencher) { - b.iter(|| { - for (i, j, k) in (0..N3).tuple_combinations() { - black_box(i + j + k); - } - }); -} - -#[bench] -fn comb_c4(b: &mut Bencher) { - b.iter(|| { - for (i, j, k, l) in (0..N4).tuple_combinations() { - black_box(i + j + k + l); - } - }); -} diff --git a/vendor/itertools-0.8.2/benches/tuples.rs b/vendor/itertools-0.8.2/benches/tuples.rs deleted file mode 100644 index b0f2990fdf..0000000000 --- a/vendor/itertools-0.8.2/benches/tuples.rs +++ /dev/null @@ -1,190 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate itertools; - -use test::Bencher; -use itertools::Itertools; - -fn s1(a: u32) -> u32 { - a -} - -fn s2(a: u32, b: u32) -> u32 { - a + b -} - -fn s3(a: u32, b: u32, c: u32) -> u32 { - a + b + c -} - -fn s4(a: u32, b: u32, c: u32, d: u32) -> u32 { - a + b + c + d -} - -fn sum_s1(s: &[u32]) -> u32 { - s1(s[0]) -} - -fn sum_s2(s: &[u32]) -> u32 { - s2(s[0], s[1]) -} - -fn sum_s3(s: &[u32]) -> u32 { - s3(s[0], s[1], s[2]) -} - -fn sum_s4(s: &[u32]) -> u32 { - s4(s[0], s[1], s[2], s[3]) -} - -fn sum_t1(s: &(&u32, )) -> u32 { - s1(*s.0) -} - -fn sum_t2(s: &(&u32, &u32)) -> u32 { - s2(*s.0, *s.1) -} - -fn sum_t3(s: &(&u32, &u32, &u32)) -> u32 { - s3(*s.0, *s.1, *s.2) -} - -fn sum_t4(s: &(&u32, &u32, &u32, &u32)) -> u32 { - s4(*s.0, *s.1, *s.2, *s.3) -} - -macro_rules! def_benchs { - ($N:expr; - $TUPLE_FUN:ident, - $TUPLES:ident, - $TUPLE_WINDOWS:ident; - $SLICE_FUN:ident, - $CHUNKS:ident, - $WINDOWS:ident; - $FOR_CHUNKS:ident, - $FOR_WINDOWS:ident - ) => ( - #[bench] - fn $FOR_CHUNKS(b: &mut Bencher) { - let v: Vec = (0.. $N * 1_000).collect(); - let mut s = 0; - b.iter(|| { - let mut j = 0; - for _ in 0..1_000 { - s += $SLICE_FUN(&v[j..(j + $N)]); - j += $N; - } - s - }); - } - - #[bench] - fn $FOR_WINDOWS(b: &mut Bencher) { - let v: Vec = (0..1_000).collect(); - let mut s = 0; - b.iter(|| { - for i in 0..(1_000 - $N) { - s += $SLICE_FUN(&v[i..(i + $N)]); - } - s - }); - } - - #[bench] - fn $TUPLES(b: &mut Bencher) { - let v: Vec = (0.. $N * 1_000).collect(); - let mut s = 0; - b.iter(|| { - for x in v.iter().tuples() { - s += $TUPLE_FUN(&x); - } - s - }); - } - - #[bench] - fn $CHUNKS(b: &mut Bencher) { - let v: Vec = (0.. $N * 1_000).collect(); - let mut s = 0; - b.iter(|| { - for x in v.chunks($N) { - s += $SLICE_FUN(x); - } - s - }); - } - - #[bench] - fn $TUPLE_WINDOWS(b: &mut Bencher) { - let v: Vec = (0..1_000).collect(); - let mut s = 0; - b.iter(|| { - for x in v.iter().tuple_windows() { - s += $TUPLE_FUN(&x); - } - s - }); - } - - #[bench] - fn $WINDOWS(b: &mut Bencher) { - let v: Vec = (0..1_000).collect(); - let mut s = 0; - b.iter(|| { - for x in v.windows($N) { - s += $SLICE_FUN(x); - } - s - }); - } - ) -} - -def_benchs!{ - 1; - sum_t1, - tuple_chunks_1, - tuple_windows_1; - sum_s1, - slice_chunks_1, - slice_windows_1; - for_chunks_1, - for_windows_1 -} - -def_benchs!{ - 2; - sum_t2, - tuple_chunks_2, - tuple_windows_2; - sum_s2, - slice_chunks_2, - slice_windows_2; - for_chunks_2, - for_windows_2 -} - -def_benchs!{ - 3; - sum_t3, - tuple_chunks_3, - tuple_windows_3; - sum_s3, - slice_chunks_3, - slice_windows_3; - for_chunks_3, - for_windows_3 -} - -def_benchs!{ - 4; - sum_t4, - tuple_chunks_4, - tuple_windows_4; - sum_s4, - slice_chunks_4, - slice_windows_4; - for_chunks_4, - for_windows_4 -} diff --git a/vendor/itertools-0.8.2/examples/iris.data b/vendor/itertools-0.8.2/examples/iris.data deleted file mode 100644 index a3490e0e07..0000000000 --- a/vendor/itertools-0.8.2/examples/iris.data +++ /dev/null @@ -1,150 +0,0 @@ -5.1,3.5,1.4,0.2,Iris-setosa -4.9,3.0,1.4,0.2,Iris-setosa -4.7,3.2,1.3,0.2,Iris-setosa -4.6,3.1,1.5,0.2,Iris-setosa -5.0,3.6,1.4,0.2,Iris-setosa -5.4,3.9,1.7,0.4,Iris-setosa -4.6,3.4,1.4,0.3,Iris-setosa -5.0,3.4,1.5,0.2,Iris-setosa -4.4,2.9,1.4,0.2,Iris-setosa -4.9,3.1,1.5,0.1,Iris-setosa -5.4,3.7,1.5,0.2,Iris-setosa -4.8,3.4,1.6,0.2,Iris-setosa -4.8,3.0,1.4,0.1,Iris-setosa -4.3,3.0,1.1,0.1,Iris-setosa -5.8,4.0,1.2,0.2,Iris-setosa -5.7,4.4,1.5,0.4,Iris-setosa -5.4,3.9,1.3,0.4,Iris-setosa -5.1,3.5,1.4,0.3,Iris-setosa -5.7,3.8,1.7,0.3,Iris-setosa -5.1,3.8,1.5,0.3,Iris-setosa -5.4,3.4,1.7,0.2,Iris-setosa -5.1,3.7,1.5,0.4,Iris-setosa -4.6,3.6,1.0,0.2,Iris-setosa -5.1,3.3,1.7,0.5,Iris-setosa -4.8,3.4,1.9,0.2,Iris-setosa -5.0,3.0,1.6,0.2,Iris-setosa -5.0,3.4,1.6,0.4,Iris-setosa -5.2,3.5,1.5,0.2,Iris-setosa -5.2,3.4,1.4,0.2,Iris-setosa -4.7,3.2,1.6,0.2,Iris-setosa -4.8,3.1,1.6,0.2,Iris-setosa -5.4,3.4,1.5,0.4,Iris-setosa -5.2,4.1,1.5,0.1,Iris-setosa -5.5,4.2,1.4,0.2,Iris-setosa -4.9,3.1,1.5,0.1,Iris-setosa -5.0,3.2,1.2,0.2,Iris-setosa -5.5,3.5,1.3,0.2,Iris-setosa -4.9,3.1,1.5,0.1,Iris-setosa -4.4,3.0,1.3,0.2,Iris-setosa -5.1,3.4,1.5,0.2,Iris-setosa -5.0,3.5,1.3,0.3,Iris-setosa -4.5,2.3,1.3,0.3,Iris-setosa -4.4,3.2,1.3,0.2,Iris-setosa -5.0,3.5,1.6,0.6,Iris-setosa -5.1,3.8,1.9,0.4,Iris-setosa -4.8,3.0,1.4,0.3,Iris-setosa -5.1,3.8,1.6,0.2,Iris-setosa -4.6,3.2,1.4,0.2,Iris-setosa -5.3,3.7,1.5,0.2,Iris-setosa -5.0,3.3,1.4,0.2,Iris-setosa -7.0,3.2,4.7,1.4,Iris-versicolor -6.4,3.2,4.5,1.5,Iris-versicolor -6.9,3.1,4.9,1.5,Iris-versicolor -5.5,2.3,4.0,1.3,Iris-versicolor -6.5,2.8,4.6,1.5,Iris-versicolor -5.7,2.8,4.5,1.3,Iris-versicolor -6.3,3.3,4.7,1.6,Iris-versicolor -4.9,2.4,3.3,1.0,Iris-versicolor -6.6,2.9,4.6,1.3,Iris-versicolor -5.2,2.7,3.9,1.4,Iris-versicolor -5.0,2.0,3.5,1.0,Iris-versicolor -5.9,3.0,4.2,1.5,Iris-versicolor -6.0,2.2,4.0,1.0,Iris-versicolor -6.1,2.9,4.7,1.4,Iris-versicolor -5.6,2.9,3.6,1.3,Iris-versicolor -6.7,3.1,4.4,1.4,Iris-versicolor -5.6,3.0,4.5,1.5,Iris-versicolor -5.8,2.7,4.1,1.0,Iris-versicolor -6.2,2.2,4.5,1.5,Iris-versicolor -5.6,2.5,3.9,1.1,Iris-versicolor -5.9,3.2,4.8,1.8,Iris-versicolor -6.1,2.8,4.0,1.3,Iris-versicolor -6.3,2.5,4.9,1.5,Iris-versicolor -6.1,2.8,4.7,1.2,Iris-versicolor -6.4,2.9,4.3,1.3,Iris-versicolor -6.6,3.0,4.4,1.4,Iris-versicolor -6.8,2.8,4.8,1.4,Iris-versicolor -6.7,3.0,5.0,1.7,Iris-versicolor -6.0,2.9,4.5,1.5,Iris-versicolor -5.7,2.6,3.5,1.0,Iris-versicolor -5.5,2.4,3.8,1.1,Iris-versicolor -5.5,2.4,3.7,1.0,Iris-versicolor -5.8,2.7,3.9,1.2,Iris-versicolor -6.0,2.7,5.1,1.6,Iris-versicolor -5.4,3.0,4.5,1.5,Iris-versicolor -6.0,3.4,4.5,1.6,Iris-versicolor -6.7,3.1,4.7,1.5,Iris-versicolor -6.3,2.3,4.4,1.3,Iris-versicolor -5.6,3.0,4.1,1.3,Iris-versicolor -5.5,2.5,4.0,1.3,Iris-versicolor -5.5,2.6,4.4,1.2,Iris-versicolor -6.1,3.0,4.6,1.4,Iris-versicolor -5.8,2.6,4.0,1.2,Iris-versicolor -5.0,2.3,3.3,1.0,Iris-versicolor -5.6,2.7,4.2,1.3,Iris-versicolor -5.7,3.0,4.2,1.2,Iris-versicolor -5.7,2.9,4.2,1.3,Iris-versicolor -6.2,2.9,4.3,1.3,Iris-versicolor -5.1,2.5,3.0,1.1,Iris-versicolor -5.7,2.8,4.1,1.3,Iris-versicolor -6.3,3.3,6.0,2.5,Iris-virginica -5.8,2.7,5.1,1.9,Iris-virginica -7.1,3.0,5.9,2.1,Iris-virginica -6.3,2.9,5.6,1.8,Iris-virginica -6.5,3.0,5.8,2.2,Iris-virginica -7.6,3.0,6.6,2.1,Iris-virginica -4.9,2.5,4.5,1.7,Iris-virginica -7.3,2.9,6.3,1.8,Iris-virginica -6.7,2.5,5.8,1.8,Iris-virginica -7.2,3.6,6.1,2.5,Iris-virginica -6.5,3.2,5.1,2.0,Iris-virginica -6.4,2.7,5.3,1.9,Iris-virginica -6.8,3.0,5.5,2.1,Iris-virginica -5.7,2.5,5.0,2.0,Iris-virginica -5.8,2.8,5.1,2.4,Iris-virginica -6.4,3.2,5.3,2.3,Iris-virginica -6.5,3.0,5.5,1.8,Iris-virginica -7.7,3.8,6.7,2.2,Iris-virginica -7.7,2.6,6.9,2.3,Iris-virginica -6.0,2.2,5.0,1.5,Iris-virginica -6.9,3.2,5.7,2.3,Iris-virginica -5.6,2.8,4.9,2.0,Iris-virginica -7.7,2.8,6.7,2.0,Iris-virginica -6.3,2.7,4.9,1.8,Iris-virginica -6.7,3.3,5.7,2.1,Iris-virginica -7.2,3.2,6.0,1.8,Iris-virginica -6.2,2.8,4.8,1.8,Iris-virginica -6.1,3.0,4.9,1.8,Iris-virginica -6.4,2.8,5.6,2.1,Iris-virginica -7.2,3.0,5.8,1.6,Iris-virginica -7.4,2.8,6.1,1.9,Iris-virginica -7.9,3.8,6.4,2.0,Iris-virginica -6.4,2.8,5.6,2.2,Iris-virginica -6.3,2.8,5.1,1.5,Iris-virginica -6.1,2.6,5.6,1.4,Iris-virginica -7.7,3.0,6.1,2.3,Iris-virginica -6.3,3.4,5.6,2.4,Iris-virginica -6.4,3.1,5.5,1.8,Iris-virginica -6.0,3.0,4.8,1.8,Iris-virginica -6.9,3.1,5.4,2.1,Iris-virginica -6.7,3.1,5.6,2.4,Iris-virginica -6.9,3.1,5.1,2.3,Iris-virginica -5.8,2.7,5.1,1.9,Iris-virginica -6.8,3.2,5.9,2.3,Iris-virginica -6.7,3.3,5.7,2.5,Iris-virginica -6.7,3.0,5.2,2.3,Iris-virginica -6.3,2.5,5.0,1.9,Iris-virginica -6.5,3.0,5.2,2.0,Iris-virginica -6.2,3.4,5.4,2.3,Iris-virginica -5.9,3.0,5.1,1.8,Iris-virginica diff --git a/vendor/itertools-0.8.2/examples/iris.rs b/vendor/itertools-0.8.2/examples/iris.rs deleted file mode 100644 index c09afbea0d..0000000000 --- a/vendor/itertools-0.8.2/examples/iris.rs +++ /dev/null @@ -1,141 +0,0 @@ -/// -/// This example parses, sorts and groups the iris dataset -/// and does some simple manipulations. -/// -/// Iterators and itertools functionality are used throughout. -/// -/// - -extern crate itertools; - -use itertools::Itertools; -use std::collections::HashMap; -use std::iter::repeat; -use std::num::ParseFloatError; -use std::str::FromStr; - -static DATA: &'static str = include_str!("iris.data"); - -#[derive(Clone, Debug)] -struct Iris { - name: String, - data: [f32; 4], -} - -#[derive(Clone, Debug)] -enum ParseError { - Numeric(ParseFloatError), - Other(&'static str), -} - -impl From for ParseError { - fn from(err: ParseFloatError) -> Self { - ParseError::Numeric(err) - } -} - -/// Parse an Iris from a comma-separated line -impl FromStr for Iris { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - let mut iris = Iris { name: "".into(), data: [0.; 4] }; - let mut parts = s.split(",").map(str::trim); - - // using Iterator::by_ref() - for (index, part) in parts.by_ref().take(4).enumerate() { - iris.data[index] = try!(part.parse::()); - } - if let Some(name) = parts.next() { - iris.name = name.into(); - } else { - return Err(ParseError::Other("Missing name")) - } - Ok(iris) - } -} - -fn main() { - // using Itertools::fold_results to create the result of parsing - let irises = DATA.lines() - .map(str::parse) - .fold_results(Vec::new(), |mut v, iris: Iris| { - v.push(iris); - v - }); - let mut irises = match irises { - Err(e) => { - println!("Error parsing: {:?}", e); - std::process::exit(1); - } - Ok(data) => data, - }; - - // Sort them and group them - irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name)); - - // using Iterator::cycle() - let mut plot_symbols = "+ox".chars().cycle(); - let mut symbolmap = HashMap::new(); - - // using Itertools::group_by - for (species, species_group) in &irises.iter().group_by(|iris| &iris.name) { - // assign a plot symbol - symbolmap.entry(species).or_insert_with(|| { - plot_symbols.next().unwrap() - }); - println!("{} (symbol={})", species, symbolmap[species]); - - for iris in species_group { - // using Itertools::format for lazy formatting - println!("{:>3.1}", iris.data.iter().format(", ")); - } - - } - - // Look at all combinations of the four columns - // - // See https://en.wikipedia.org/wiki/Iris_flower_data_set - // - let n = 30; // plot size - let mut plot = vec![' '; n * n]; - - // using Itertools::tuple_combinations - for (a, b) in (0..4).tuple_combinations() { - println!("Column {} vs {}:", a, b); - - // Clear plot - // - // using std::iter::repeat; - // using Itertools::set_from - plot.iter_mut().set_from(repeat(' ')); - - // using Itertools::minmax - let min_max = |data: &[Iris], col| { - data.iter() - .map(|iris| iris.data[col]) - .minmax() - .into_option() - .expect("Can't find min/max of empty iterator") - }; - let (min_x, max_x) = min_max(&irises, a); - let (min_y, max_y) = min_max(&irises, b); - - // Plot the data points - let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n - 1) as f32)) as usize; - let flip = |ix| n - 1 - ix; // reverse axis direction - - for iris in &irises { - let ix = round_to_grid(iris.data[a], min_x, max_x); - let iy = flip(round_to_grid(iris.data[b], min_y, max_y)); - plot[n * iy + ix] = symbolmap[&iris.name]; - } - - // render plot - // - // using Itertools::join - for line in plot.chunks(n) { - println!("{}", line.iter().join(" ")) - } - } -} diff --git a/vendor/itertools-0.8.2/src/adaptors/mod.rs b/vendor/itertools-0.8.2/src/adaptors/mod.rs deleted file mode 100644 index 4d0f5e1291..0000000000 --- a/vendor/itertools-0.8.2/src/adaptors/mod.rs +++ /dev/null @@ -1,1251 +0,0 @@ -//! Licensed under the Apache License, Version 2.0 -//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license -//! http://opensource.org/licenses/MIT, at your -//! option. This file may not be copied, modified, or distributed -//! except according to those terms. - -mod multi_product; -#[cfg(feature = "use_std")] -pub use self::multi_product::*; - -use std::fmt; -use std::mem::replace; -use std::iter::{Fuse, Peekable, FromIterator}; -use std::marker::PhantomData; -use size_hint; - -macro_rules! clone_fields { - ($name:ident, $base:expr, $($field:ident),+) => ( - $name { - $( - $field : $base . $field .clone() - ),* - } - ); -} - -/// An iterator adaptor that alternates elements from two iterators until both -/// run out. -/// -/// This iterator is *fused*. -/// -/// See [`.interleave()`](../trait.Itertools.html#method.interleave) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Interleave { - a: Fuse, - b: Fuse, - flag: bool, -} - -/// Create an iterator that interleaves elements in `i` and `j`. -/// -/// `IntoIterator` enabled version of `i.interleave(j)`. -/// -/// ``` -/// use itertools::interleave; -/// -/// for elt in interleave(&[1, 2, 3], &[2, 3, 4]) { -/// /* loop body */ -/// } -/// ``` -pub fn interleave(i: I, j: J) -> Interleave<::IntoIter, ::IntoIter> - where I: IntoIterator, - J: IntoIterator -{ - Interleave { - a: i.into_iter().fuse(), - b: j.into_iter().fuse(), - flag: false, - } -} - -impl Iterator for Interleave - where I: Iterator, - J: Iterator -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - self.flag = !self.flag; - if self.flag { - match self.a.next() { - None => self.b.next(), - r => r, - } - } else { - match self.b.next() { - None => self.a.next(), - r => r, - } - } - } - - fn size_hint(&self) -> (usize, Option) { - size_hint::add(self.a.size_hint(), self.b.size_hint()) - } -} - -/// An iterator adaptor that alternates elements from the two iterators until -/// one of them runs out. -/// -/// This iterator is *fused*. -/// -/// See [`.interleave_shortest()`](../trait.Itertools.html#method.interleave_shortest) -/// for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct InterleaveShortest - where I: Iterator, - J: Iterator -{ - it0: I, - it1: J, - phase: bool, // false ==> it0, true ==> it1 -} - -/// Create a new `InterleaveShortest` iterator. -pub fn interleave_shortest(a: I, b: J) -> InterleaveShortest - where I: Iterator, - J: Iterator -{ - InterleaveShortest { - it0: a, - it1: b, - phase: false, - } -} - -impl Iterator for InterleaveShortest - where I: Iterator, - J: Iterator -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - match self.phase { - false => match self.it0.next() { - None => None, - e => { - self.phase = true; - e - } - }, - true => match self.it1.next() { - None => None, - e => { - self.phase = false; - e - } - }, - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (curr_hint, next_hint) = { - let it0_hint = self.it0.size_hint(); - let it1_hint = self.it1.size_hint(); - if self.phase { - (it1_hint, it0_hint) - } else { - (it0_hint, it1_hint) - } - }; - let (curr_lower, curr_upper) = curr_hint; - let (next_lower, next_upper) = next_hint; - let (combined_lower, combined_upper) = - size_hint::mul_scalar(size_hint::min(curr_hint, next_hint), 2); - let lower = - if curr_lower > next_lower { - combined_lower + 1 - } else { - combined_lower - }; - let upper = { - let extra_elem = match (curr_upper, next_upper) { - (_, None) => false, - (None, Some(_)) => true, - (Some(curr_max), Some(next_max)) => curr_max > next_max, - }; - if extra_elem { - combined_upper.and_then(|x| x.checked_add(1)) - } else { - combined_upper - } - }; - (lower, upper) - } -} - -#[derive(Clone, Debug)] -/// An iterator adaptor that allows putting back a single -/// item to the front of the iterator. -/// -/// Iterator element type is `I::Item`. -pub struct PutBack - where I: Iterator -{ - top: Option, - iter: I, -} - -/// Create an iterator where you can put back a single item -pub fn put_back(iterable: I) -> PutBack - where I: IntoIterator -{ - PutBack { - top: None, - iter: iterable.into_iter(), - } -} - -impl PutBack - where I: Iterator -{ - /// put back value `value` (builder method) - pub fn with_value(mut self, value: I::Item) -> Self { - self.put_back(value); - self - } - - /// Split the `PutBack` into its parts. - #[inline] - pub fn into_parts(self) -> (Option, I) { - let PutBack{top, iter} = self; - (top, iter) - } - - /// Put back a single value to the front of the iterator. - /// - /// If a value is already in the put back slot, it is overwritten. - #[inline] - pub fn put_back(&mut self, x: I::Item) { - self.top = Some(x) - } -} - -impl Iterator for PutBack - where I: Iterator -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - match self.top { - None => self.iter.next(), - ref mut some => some.take(), - } - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - // Not ExactSizeIterator because size may be larger than usize - size_hint::add_scalar(self.iter.size_hint(), self.top.is_some() as usize) - } - - fn all(&mut self, mut f: G) -> bool - where G: FnMut(Self::Item) -> bool - { - if let Some(elt) = self.top.take() { - if !f(elt) { - return false; - } - } - self.iter.all(f) - } - - fn fold(mut self, init: Acc, mut f: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - let mut accum = init; - if let Some(elt) = self.top.take() { - accum = f(accum, elt); - } - self.iter.fold(accum, f) - } -} - -#[derive(Debug, Clone)] -/// An iterator adaptor that iterates over the cartesian product of -/// the element sets of two iterators `I` and `J`. -/// -/// Iterator element type is `(I::Item, J::Item)`. -/// -/// See [`.cartesian_product()`](../trait.Itertools.html#method.cartesian_product) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Product - where I: Iterator -{ - a: I, - a_cur: Option, - b: J, - b_orig: J, -} - -/// Create a new cartesian product iterator -/// -/// Iterator element type is `(I::Item, J::Item)`. -pub fn cartesian_product(mut i: I, j: J) -> Product - where I: Iterator, - J: Clone + Iterator, - I::Item: Clone -{ - Product { - a_cur: i.next(), - a: i, - b: j.clone(), - b_orig: j, - } -} - - -impl Iterator for Product - where I: Iterator, - J: Clone + Iterator, - I::Item: Clone -{ - type Item = (I::Item, J::Item); - fn next(&mut self) -> Option<(I::Item, J::Item)> { - let elt_b = match self.b.next() { - None => { - self.b = self.b_orig.clone(); - match self.b.next() { - None => return None, - Some(x) => { - self.a_cur = self.a.next(); - x - } - } - } - Some(x) => x - }; - match self.a_cur { - None => None, - Some(ref a) => { - Some((a.clone(), elt_b)) - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let has_cur = self.a_cur.is_some() as usize; - // Not ExactSizeIterator because size may be larger than usize - let (b_min, b_max) = self.b.size_hint(); - - // Compute a * b_orig + b for both lower and upper bound - size_hint::add( - size_hint::mul(self.a.size_hint(), self.b_orig.size_hint()), - (b_min * has_cur, b_max.map(move |x| x * has_cur))) - } - - fn fold(mut self, mut accum: Acc, mut f: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - // use a split loop to handle the loose a_cur as well as avoiding to - // clone b_orig at the end. - if let Some(mut a) = self.a_cur.take() { - let mut b = self.b; - loop { - accum = b.fold(accum, |acc, elt| f(acc, (a.clone(), elt))); - - // we can only continue iterating a if we had a first element; - if let Some(next_a) = self.a.next() { - b = self.b_orig.clone(); - a = next_a; - } else { - break; - } - } - } - accum - } -} - -/// A “meta iterator adaptor”. Its closure receives a reference to the iterator -/// and may pick off as many elements as it likes, to produce the next iterator element. -/// -/// Iterator element type is *X*, if the return type of `F` is *Option\*. -/// -/// See [`.batching()`](../trait.Itertools.html#method.batching) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Batching { - f: F, - iter: I, -} - -impl fmt::Debug for Batching where I: fmt::Debug { - debug_fmt_fields!(Batching, iter); -} - -/// Create a new Batching iterator. -pub fn batching(iter: I, f: F) -> Batching { - Batching { f: f, iter: iter } -} - -impl Iterator for Batching - where I: Iterator, - F: FnMut(&mut I) -> Option -{ - type Item = B; - #[inline] - fn next(&mut self) -> Option { - (self.f)(&mut self.iter) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - // No information about closue behavior - (0, None) - } -} - -/// An iterator adaptor that steps a number elements in the base iterator -/// for each iteration. -/// -/// The iterator steps by yielding the next element from the base iterator, -/// then skipping forward *n-1* elements. -/// -/// See [`.step()`](../trait.Itertools.html#method.step) for more information. -#[deprecated(note="Use std .step_by() instead", since="0.8")] -#[allow(deprecated)] -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Step { - iter: Fuse, - skip: usize, -} - -/// Create a `Step` iterator. -/// -/// **Panics** if the step is 0. -#[allow(deprecated)] -pub fn step(iter: I, step: usize) -> Step - where I: Iterator -{ - assert!(step != 0); - Step { - iter: iter.fuse(), - skip: step - 1, - } -} - -#[allow(deprecated)] -impl Iterator for Step - where I: Iterator -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - let elt = self.iter.next(); - if self.skip > 0 { - self.iter.nth(self.skip - 1); - } - elt - } - - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.iter.size_hint(); - let div = |x: usize| { - if x == 0 { - 0 - } else { - 1 + (x - 1) / (self.skip + 1) - } - }; - (div(low), high.map(div)) - } -} - -// known size -#[allow(deprecated)] -impl ExactSizeIterator for Step - where I: ExactSizeIterator -{} - -pub trait MergePredicate { - fn merge_pred(&mut self, a: &T, b: &T) -> bool; -} - -#[derive(Clone)] -pub struct MergeLte; - -impl MergePredicate for MergeLte { - fn merge_pred(&mut self, a: &T, b: &T) -> bool { - a <= b - } -} - -/// An iterator adaptor that merges the two base iterators in ascending order. -/// If both base iterators are sorted (ascending), the result is sorted. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.merge()`](../trait.Itertools.html#method.merge_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub type Merge = MergeBy; - -/// Create an iterator that merges elements in `i` and `j`. -/// -/// `IntoIterator` enabled version of `i.merge(j)`. -/// -/// ``` -/// use itertools::merge; -/// -/// for elt in merge(&[1, 2, 3], &[2, 3, 4]) { -/// /* loop body */ -/// } -/// ``` -pub fn merge(i: I, j: J) -> Merge<::IntoIter, ::IntoIter> - where I: IntoIterator, - J: IntoIterator, - I::Item: PartialOrd -{ - merge_by_new(i, j, MergeLte) -} - -/// An iterator adaptor that merges the two base iterators in ascending order. -/// If both base iterators are sorted (ascending), the result is sorted. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.merge_by()`](../trait.Itertools.html#method.merge_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MergeBy - where I: Iterator, - J: Iterator -{ - a: Peekable, - b: Peekable, - fused: Option, - cmp: F, -} - -impl fmt::Debug for MergeBy - where I: Iterator + fmt::Debug, J: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(MergeBy, a, b); -} - -implbool> MergePredicate for F { - fn merge_pred(&mut self, a: &T, b: &T) -> bool { - self(a, b) - } -} - -/// Create a `MergeBy` iterator. -pub fn merge_by_new(a: I, b: J, cmp: F) -> MergeBy - where I: IntoIterator, - J: IntoIterator, - F: MergePredicate, -{ - MergeBy { - a: a.into_iter().peekable(), - b: b.into_iter().peekable(), - fused: None, - cmp: cmp, - } -} - -impl Clone for MergeBy - where I: Iterator, - J: Iterator, - Peekable: Clone, - Peekable: Clone, - F: Clone -{ - fn clone(&self) -> Self { - clone_fields!(MergeBy, self, a, b, fused, cmp) - } -} - -impl Iterator for MergeBy - where I: Iterator, - J: Iterator, - F: MergePredicate -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - let less_than = match self.fused { - Some(lt) => lt, - None => match (self.a.peek(), self.b.peek()) { - (Some(a), Some(b)) => self.cmp.merge_pred(a, b), - (Some(_), None) => { - self.fused = Some(true); - true - } - (None, Some(_)) => { - self.fused = Some(false); - false - } - (None, None) => return None, - } - }; - if less_than { - self.a.next() - } else { - self.b.next() - } - } - - fn size_hint(&self) -> (usize, Option) { - // Not ExactSizeIterator because size may be larger than usize - size_hint::add(self.a.size_hint(), self.b.size_hint()) - } -} - -#[derive(Clone, Debug)] -pub struct CoalesceCore - where I: Iterator -{ - iter: I, - last: Option, -} - -impl CoalesceCore - where I: Iterator -{ - fn next_with(&mut self, mut f: F) -> Option - where F: FnMut(I::Item, I::Item) -> Result - { - // this fuses the iterator - let mut last = match self.last.take() { - None => return None, - Some(x) => x, - }; - for next in &mut self.iter { - match f(last, next) { - Ok(joined) => last = joined, - Err((last_, next_)) => { - self.last = Some(next_); - return Some(last_); - } - } - } - - Some(last) - } - - fn size_hint(&self) -> (usize, Option) { - let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), - self.last.is_some() as usize); - ((low > 0) as usize, hi) - } -} - -/// An iterator adaptor that may join together adjacent elements. -/// -/// See [`.coalesce()`](../trait.Itertools.html#method.coalesce) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Coalesce - where I: Iterator -{ - iter: CoalesceCore, - f: F, -} - -impl Clone for Coalesce - where I: Iterator, - I::Item: Clone -{ - fn clone(&self) -> Self { - clone_fields!(Coalesce, self, iter, f) - } -} - -impl fmt::Debug for Coalesce - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Coalesce, iter); -} - -/// Create a new `Coalesce`. -pub fn coalesce(mut iter: I, f: F) -> Coalesce - where I: Iterator -{ - Coalesce { - iter: CoalesceCore { - last: iter.next(), - iter: iter, - }, - f: f, - } -} - -impl Iterator for Coalesce - where I: Iterator, - F: FnMut(I::Item, I::Item) -> Result -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - self.iter.next_with(&mut self.f) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function. -/// -/// See [`.dedup_by()`](../trait.Itertools.html#method.dedup_by) or [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct DedupBy - where I: Iterator -{ - iter: CoalesceCore, - dedup_pred: Pred, -} - -pub trait DedupPredicate { // TODO replace by Fn(&T, &T)->bool once Rust supports it - fn dedup_pair(&mut self, a: &T, b: &T) -> bool; -} - -#[derive(Clone)] -pub struct DedupEq; - -impl DedupPredicate for DedupEq { - fn dedup_pair(&mut self, a: &T, b: &T) -> bool { - a==b - } -} - -implbool> DedupPredicate for F { - fn dedup_pair(&mut self, a: &T, b: &T) -> bool { - self(a, b) - } -} - -/// An iterator adaptor that removes repeated duplicates. -/// -/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. -pub type Dedup=DedupBy; - -impl Clone for DedupBy - where I: Iterator, - I::Item: Clone, -{ - fn clone(&self) -> Self { - clone_fields!(DedupBy, self, iter, dedup_pred) - } -} - -/// Create a new `DedupBy`. -pub fn dedup_by(mut iter: I, dedup_pred: Pred) -> DedupBy - where I: Iterator, -{ - DedupBy { - iter: CoalesceCore { - last: iter.next(), - iter: iter, - }, - dedup_pred, - } -} - -/// Create a new `Dedup`. -pub fn dedup(iter: I) -> Dedup - where I: Iterator -{ - dedup_by(iter, DedupEq) -} - -impl fmt::Debug for DedupBy - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Dedup, iter); -} - -impl Iterator for DedupBy - where I: Iterator, - I::Item: PartialEq, - Pred: DedupPredicate, -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - let ref mut dedup_pred = self.dedup_pred; - self.iter.next_with(|x, y| { - if dedup_pred.dedup_pair(&x, &y) { Ok(x) } else { Err((x, y)) } - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, mut accum: Acc, mut f: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - if let Some(mut last) = self.iter.last { - let mut dedup_pred = self.dedup_pred; - accum = self.iter.iter.fold(accum, |acc, elt| { - if dedup_pred.dedup_pair(&elt, &last) { - acc - } else { - f(acc, replace(&mut last, elt)) - } - }); - f(accum, last) - } else { - accum - } - } -} - -/// An iterator adaptor that borrows from a `Clone`-able iterator -/// to only pick off elements while the predicate returns `true`. -/// -/// See [`.take_while_ref()`](../trait.Itertools.html#method.take_while_ref) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct TakeWhileRef<'a, I: 'a, F> { - iter: &'a mut I, - f: F, -} - -impl<'a, I, F> fmt::Debug for TakeWhileRef<'a, I, F> - where I: Iterator + fmt::Debug, -{ - debug_fmt_fields!(TakeWhileRef, iter); -} - -/// Create a new `TakeWhileRef` from a reference to clonable iterator. -pub fn take_while_ref(iter: &mut I, f: F) -> TakeWhileRef - where I: Iterator + Clone -{ - TakeWhileRef { iter: iter, f: f } -} - -impl<'a, I, F> Iterator for TakeWhileRef<'a, I, F> - where I: Iterator + Clone, - F: FnMut(&I::Item) -> bool -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - let old = self.iter.clone(); - match self.iter.next() { - None => None, - Some(elt) => { - if (self.f)(&elt) { - Some(elt) - } else { - *self.iter = old; - None - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let (_, hi) = self.iter.size_hint(); - (0, hi) - } -} - -/// An iterator adaptor that filters `Option
    ` iterator elements -/// and produces `A`. Stops on the first `None` encountered. -/// -/// See [`.while_some()`](../trait.Itertools.html#method.while_some) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct WhileSome { - iter: I, -} - -/// Create a new `WhileSome`. -pub fn while_some(iter: I) -> WhileSome { - WhileSome { iter: iter } -} - -impl Iterator for WhileSome - where I: Iterator> -{ - type Item = A; - - fn next(&mut self) -> Option { - match self.iter.next() { - None | Some(None) => None, - Some(elt) => elt, - } - } - - fn size_hint(&self) -> (usize, Option) { - let sh = self.iter.size_hint(); - (0, sh.1) - } -} - -/// An iterator to iterate through all combinations in a `Clone`-able iterator that produces tuples -/// of a specific size. -/// -/// See [`.tuple_combinations()`](../trait.Itertools.html#method.tuple_combinations) for more -/// information. -#[derive(Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct TupleCombinations - where I: Iterator, - T: HasCombination -{ - iter: T::Combination, - _mi: PhantomData, - _mt: PhantomData -} - -pub trait HasCombination: Sized { - type Combination: From + Iterator; -} - -/// Create a new `TupleCombinations` from a clonable iterator. -pub fn tuple_combinations(iter: I) -> TupleCombinations - where I: Iterator + Clone, - I::Item: Clone, - T: HasCombination, -{ - TupleCombinations { - iter: T::Combination::from(iter), - _mi: PhantomData, - _mt: PhantomData, - } -} - -impl Iterator for TupleCombinations - where I: Iterator, - T: HasCombination, -{ - type Item = T; - - fn next(&mut self) -> Option { - self.iter.next() - } -} - -#[derive(Debug)] -pub struct Tuple1Combination { - iter: I, -} - -impl From for Tuple1Combination { - fn from(iter: I) -> Self { - Tuple1Combination { iter: iter } - } -} - -impl Iterator for Tuple1Combination { - type Item = (I::Item,); - - fn next(&mut self) -> Option { - self.iter.next().map(|x| (x,)) - } -} - -impl HasCombination for (I::Item,) { - type Combination = Tuple1Combination; -} - -macro_rules! impl_tuple_combination { - ($C:ident $P:ident ; $A:ident, $($I:ident),* ; $($X:ident)*) => ( - #[derive(Debug)] - pub struct $C { - item: Option, - iter: I, - c: $P, - } - - impl From for $C { - fn from(mut iter: I) -> Self { - $C { - item: iter.next(), - iter: iter.clone(), - c: $P::from(iter), - } - } - } - - impl From for $C> { - fn from(iter: I) -> Self { - let mut iter = iter.fuse(); - $C { - item: iter.next(), - iter: iter.clone(), - c: $P::from(iter), - } - } - } - - impl Iterator for $C - where I: Iterator + Clone, - I::Item: Clone - { - type Item = ($($I),*); - - fn next(&mut self) -> Option { - if let Some(($($X),*,)) = self.c.next() { - let z = self.item.clone().unwrap(); - Some((z, $($X),*)) - } else { - self.item = self.iter.next(); - self.item.clone().and_then(|z| { - self.c = $P::from(self.iter.clone()); - self.c.next().map(|($($X),*,)| (z, $($X),*)) - }) - } - } - } - - impl HasCombination for ($($I),*) - where I: Iterator + Clone, - I::Item: Clone - { - type Combination = $C>; - } - ) -} - -impl_tuple_combination!(Tuple2Combination Tuple1Combination ; A, A, A ; a); -impl_tuple_combination!(Tuple3Combination Tuple2Combination ; A, A, A, A ; a b); -impl_tuple_combination!(Tuple4Combination Tuple3Combination ; A, A, A, A, A; a b c); - -/// An iterator adapter to apply `Into` conversion to each element. -/// -/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MapInto { - iter: I, - _res: PhantomData R>, -} - -/// Create a new [`MapInto`](struct.MapInto.html) iterator. -pub fn map_into(iter: I) -> MapInto { - MapInto { - iter: iter, - _res: PhantomData, - } -} - -impl Iterator for MapInto - where I: Iterator, - I::Item: Into, -{ - type Item = R; - - fn next(&mut self) -> Option { - self.iter - .next() - .map(|i| i.into()) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: Acc, mut fold_f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, move |acc, v| fold_f(acc, v.into())) - } -} - -impl DoubleEndedIterator for MapInto - where I: DoubleEndedIterator, - I::Item: Into, -{ - fn next_back(&mut self) -> Option { - self.iter - .next_back() - .map(|i| i.into()) - } -} - -impl ExactSizeIterator for MapInto -where - I: ExactSizeIterator, - I::Item: Into, -{} - -/// An iterator adapter to apply a transformation within a nested `Result`. -/// -/// See [`.map_results()`](../trait.Itertools.html#method.map_results) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MapResults { - iter: I, - f: F -} - -/// Create a new `MapResults` iterator. -pub fn map_results(iter: I, f: F) -> MapResults - where I: Iterator>, - F: FnMut(T) -> U, -{ - MapResults { - iter: iter, - f: f, - } -} - -impl Iterator for MapResults - where I: Iterator>, - F: FnMut(T) -> U, -{ - type Item = Result; - - fn next(&mut self) -> Option { - self.iter.next().map(|v| v.map(&mut self.f)) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: Acc, mut fold_f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.fold(init, move |acc, v| fold_f(acc, v.map(&mut f))) - } - - fn collect(self) -> C - where C: FromIterator - { - let mut f = self.f; - self.iter.map(move |v| v.map(&mut f)).collect() - } -} - -/// An iterator adapter to get the positions of each element that matches a predicate. -/// -/// See [`.positions()`](../trait.Itertools.html#method.positions) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Positions { - iter: I, - f: F, - count: usize, -} - -/// Create a new `Positions` iterator. -pub fn positions(iter: I, f: F) -> Positions - where I: Iterator, - F: FnMut(I::Item) -> bool, -{ - Positions { - iter: iter, - f: f, - count: 0 - } -} - -impl Iterator for Positions - where I: Iterator, - F: FnMut(I::Item) -> bool, -{ - type Item = usize; - - fn next(&mut self) -> Option { - while let Some(v) = self.iter.next() { - let i = self.count; - self.count = i + 1; - if (self.f)(v) { - return Some(i); - } - } - None - } - - fn size_hint(&self) -> (usize, Option) { - (0, self.iter.size_hint().1) - } -} - -impl DoubleEndedIterator for Positions - where I: DoubleEndedIterator + ExactSizeIterator, - F: FnMut(I::Item) -> bool, -{ - fn next_back(&mut self) -> Option { - while let Some(v) = self.iter.next_back() { - if (self.f)(v) { - return Some(self.count + self.iter.len()) - } - } - None - } -} - -/// An iterator adapter to apply a mutating function to each element before yielding it. -/// -/// See [`.update()`](../trait.Itertools.html#method.update) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Update { - iter: I, - f: F, -} - -/// Create a new `Update` iterator. -pub fn update(iter: I, f: F) -> Update -where - I: Iterator, - F: FnMut(&mut I::Item), -{ - Update { iter: iter, f: f } -} - -impl Iterator for Update -where - I: Iterator, - F: FnMut(&mut I::Item), -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - if let Some(mut v) = self.iter.next() { - (self.f)(&mut v); - Some(v) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: Acc, mut g: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.fold(init, move |acc, mut v| { f(&mut v); g(acc, v) }) - } - - // if possible, re-use inner iterator specializations in collect - fn collect(self) -> C - where C: FromIterator - { - let mut f = self.f; - self.iter.map(move |mut v| { f(&mut v); v }).collect() - } -} - -impl ExactSizeIterator for Update -where - I: ExactSizeIterator, - F: FnMut(&mut I::Item), -{} - -impl DoubleEndedIterator for Update -where - I: DoubleEndedIterator, - F: FnMut(&mut I::Item), -{ - fn next_back(&mut self) -> Option { - if let Some(mut v) = self.iter.next_back() { - (self.f)(&mut v); - Some(v) - } else { - None - } - } -} diff --git a/vendor/itertools-0.8.2/src/adaptors/multi_product.rs b/vendor/itertools-0.8.2/src/adaptors/multi_product.rs deleted file mode 100644 index a6796386ed..0000000000 --- a/vendor/itertools-0.8.2/src/adaptors/multi_product.rs +++ /dev/null @@ -1,220 +0,0 @@ -#![cfg(feature = "use_std")] - -use size_hint; -use Itertools; - -#[derive(Clone)] -/// An iterator adaptor that iterates over the cartesian product of -/// multiple iterators of type `I`. -/// -/// An iterator element type is `Vec`. -/// -/// See [`.multi_cartesian_product()`](../trait.Itertools.html#method.multi_cartesian_product) -/// for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MultiProduct(Vec>) - where I: Iterator + Clone, - I::Item: Clone; - -/// Create a new cartesian product iterator over an arbitrary number -/// of iterators of the same type. -/// -/// Iterator element is of type `Vec`. -pub fn multi_cartesian_product(iters: H) -> MultiProduct<::IntoIter> - where H: Iterator, - H::Item: IntoIterator, - ::IntoIter: Clone, - ::Item: Clone -{ - MultiProduct(iters.map(|i| MultiProductIter::new(i.into_iter())).collect()) -} - -#[derive(Clone, Debug)] -/// Holds the state of a single iterator within a MultiProduct. -struct MultiProductIter - where I: Iterator + Clone, - I::Item: Clone -{ - cur: Option, - iter: I, - iter_orig: I, -} - -/// Holds the current state during an iteration of a MultiProduct. -#[derive(Debug)] -enum MultiProductIterState { - StartOfIter, - MidIter { on_first_iter: bool }, -} - -impl MultiProduct - where I: Iterator + Clone, - I::Item: Clone -{ - /// Iterates the rightmost iterator, then recursively iterates iterators - /// to the left if necessary. - /// - /// Returns true if the iteration succeeded, else false. - fn iterate_last( - multi_iters: &mut [MultiProductIter], - mut state: MultiProductIterState - ) -> bool { - use self::MultiProductIterState::*; - - if let Some((last, rest)) = multi_iters.split_last_mut() { - let on_first_iter = match state { - StartOfIter => { - let on_first_iter = !last.in_progress(); - state = MidIter { on_first_iter: on_first_iter }; - on_first_iter - }, - MidIter { on_first_iter } => on_first_iter - }; - - if !on_first_iter { - last.iterate(); - } - - if last.in_progress() { - true - } else if MultiProduct::iterate_last(rest, state) { - last.reset(); - last.iterate(); - // If iterator is None twice consecutively, then iterator is - // empty; whole product is empty. - last.in_progress() - } else { - false - } - } else { - // Reached end of iterator list. On initialisation, return true. - // At end of iteration (final iterator finishes), finish. - match state { - StartOfIter => false, - MidIter { on_first_iter } => on_first_iter - } - } - } - - /// Returns the unwrapped value of the next iteration. - fn curr_iterator(&self) -> Vec { - self.0.iter().map(|multi_iter| { - multi_iter.cur.clone().unwrap() - }).collect() - } - - /// Returns true if iteration has started and has not yet finished; false - /// otherwise. - fn in_progress(&self) -> bool { - if let Some(last) = self.0.last() { - last.in_progress() - } else { - false - } - } -} - -impl MultiProductIter - where I: Iterator + Clone, - I::Item: Clone -{ - fn new(iter: I) -> Self { - MultiProductIter { - cur: None, - iter: iter.clone(), - iter_orig: iter - } - } - - /// Iterate the managed iterator. - fn iterate(&mut self) { - self.cur = self.iter.next(); - } - - /// Reset the managed iterator. - fn reset(&mut self) { - self.iter = self.iter_orig.clone(); - } - - /// Returns true if the current iterator has been started and has not yet - /// finished; false otherwise. - fn in_progress(&self) -> bool { - self.cur.is_some() - } -} - -impl Iterator for MultiProduct - where I: Iterator + Clone, - I::Item: Clone -{ - type Item = Vec; - - fn next(&mut self) -> Option { - if MultiProduct::iterate_last( - &mut self.0, - MultiProductIterState::StartOfIter - ) { - Some(self.curr_iterator()) - } else { - None - } - } - - fn count(self) -> usize { - if self.0.len() == 0 { - return 0; - } - - if !self.in_progress() { - return self.0.into_iter().fold(1, |acc, multi_iter| { - acc * multi_iter.iter.count() - }); - } - - self.0.into_iter().fold( - 0, - |acc, MultiProductIter { iter, iter_orig, cur: _ }| { - let total_count = iter_orig.count(); - let cur_count = iter.count(); - acc * total_count + cur_count - } - ) - } - - fn size_hint(&self) -> (usize, Option) { - // Not ExactSizeIterator because size may be larger than usize - if self.0.len() == 0 { - return (0, Some(0)); - } - - if !self.in_progress() { - return self.0.iter().fold((1, Some(1)), |acc, multi_iter| { - size_hint::mul(acc, multi_iter.iter.size_hint()) - }); - } - - self.0.iter().fold( - (0, Some(0)), - |acc, &MultiProductIter { ref iter, ref iter_orig, cur: _ }| { - let cur_size = iter.size_hint(); - let total_size = iter_orig.size_hint(); - size_hint::add(size_hint::mul(acc, total_size), cur_size) - } - ) - } - - fn last(self) -> Option { - let iter_count = self.0.len(); - - let lasts: Self::Item = self.0.into_iter() - .map(|multi_iter| multi_iter.iter.last()) - .while_some() - .collect(); - - if lasts.len() == iter_count { - Some(lasts) - } else { - None - } - } -} diff --git a/vendor/itertools-0.8.2/src/combinations.rs b/vendor/itertools-0.8.2/src/combinations.rs deleted file mode 100644 index 61833cecd3..0000000000 --- a/vendor/itertools-0.8.2/src/combinations.rs +++ /dev/null @@ -1,100 +0,0 @@ -use std::fmt; - -use super::lazy_buffer::LazyBuffer; - -/// An iterator to iterate through all the `k`-length combinations in an iterator. -/// -/// See [`.combinations()`](../trait.Itertools.html#method.combinations) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Combinations { - k: usize, - indices: Vec, - pool: LazyBuffer, - first: bool, -} - -impl fmt::Debug for Combinations - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Combinations, k, indices, pool, first); -} - -/// Create a new `Combinations` from a clonable iterator. -pub fn combinations(iter: I, k: usize) -> Combinations - where I: Iterator -{ - let mut indices: Vec = Vec::with_capacity(k); - for i in 0..k { - indices.push(i); - } - let mut pool: LazyBuffer = LazyBuffer::new(iter); - - for _ in 0..k { - if !pool.get_next() { - break; - } - } - - Combinations { - k: k, - indices: indices, - pool: pool, - first: true, - } -} - -impl Iterator for Combinations - where I: Iterator, - I::Item: Clone -{ - type Item = Vec; - fn next(&mut self) -> Option { - let mut pool_len = self.pool.len(); - if self.pool.is_done() { - if pool_len == 0 || self.k > pool_len { - return None; - } - } - - if self.first { - self.first = false; - } else if self.k == 0 { - return None; - } else { - // Scan from the end, looking for an index to increment - let mut i: usize = self.k - 1; - - // Check if we need to consume more from the iterator - if self.indices[i] == pool_len - 1 && !self.pool.is_done() { - if self.pool.get_next() { - pool_len += 1; - } - } - - while self.indices[i] == i + pool_len - self.k { - if i > 0 { - i -= 1; - } else { - // Reached the last combination - return None; - } - } - - // Increment index, and reset the ones to its right - self.indices[i] += 1; - let mut j = i + 1; - while j < self.k { - self.indices[j] = self.indices[j - 1] + 1; - j += 1; - } - } - - // Create result vector based on the indices - let mut result = Vec::with_capacity(self.k); - for i in self.indices.iter() { - result.push(self.pool[*i].clone()); - } - Some(result) - } -} diff --git a/vendor/itertools-0.8.2/src/combinations_with_replacement.rs b/vendor/itertools-0.8.2/src/combinations_with_replacement.rs deleted file mode 100644 index 499ccf70d1..0000000000 --- a/vendor/itertools-0.8.2/src/combinations_with_replacement.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::fmt; - -use super::lazy_buffer::LazyBuffer; - -/// An iterator to iterate through all the `n`-length combinations in an iterator, with replacement. -/// -/// See [`.combinations_with_replacement()`](../trait.Itertools.html#method.combinations_with_replacement) for more information. -#[derive(Clone)] -pub struct CombinationsWithReplacement -where - I: Iterator, - I::Item: Clone, -{ - k: usize, - indices: Vec, - // The current known max index value. This increases as pool grows. - max_index: usize, - pool: LazyBuffer, - first: bool, -} - -impl fmt::Debug for CombinationsWithReplacement -where - I: Iterator + fmt::Debug, - I::Item: fmt::Debug + Clone, -{ - debug_fmt_fields!(Combinations, k, indices, max_index, pool, first); -} - -impl CombinationsWithReplacement -where - I: Iterator, - I::Item: Clone, -{ - /// Map the current mask over the pool to get an output combination - fn current(&self) -> Vec { - self.indices.iter().map(|i| self.pool[*i].clone()).collect() - } -} - -/// Create a new `CombinationsWithReplacement` from a clonable iterator. -pub fn combinations_with_replacement(iter: I, k: usize) -> CombinationsWithReplacement -where - I: Iterator, - I::Item: Clone, -{ - let indices: Vec = vec![0; k]; - let pool: LazyBuffer = LazyBuffer::new(iter); - - CombinationsWithReplacement { - k, - indices, - max_index: 0, - pool: pool, - first: true, - } -} - -impl Iterator for CombinationsWithReplacement -where - I: Iterator, - I::Item: Clone, -{ - type Item = Vec; - fn next(&mut self) -> Option { - // If this is the first iteration, return early - if self.first { - // In empty edge cases, stop iterating immediately - return if self.k == 0 || self.pool.is_done() { - None - // Otherwise, yield the initial state - } else { - self.first = false; - Some(self.current()) - }; - } - - // Check if we need to consume more from the iterator - // This will run while we increment our first index digit - if !self.pool.is_done() { - self.pool.get_next(); - self.max_index = self.pool.len() - 1; - } - - // Work out where we need to update our indices - let mut increment: Option<(usize, usize)> = None; - for (i, indices_int) in self.indices.iter().enumerate().rev() { - if indices_int < &self.max_index { - increment = Some((i, indices_int + 1)); - break; - } - } - - match increment { - // If we can update the indices further - Some((increment_from, increment_value)) => { - // We need to update the rightmost non-max value - // and all those to the right - for indices_index in increment_from..self.indices.len() { - self.indices[indices_index] = increment_value - } - Some(self.current()) - } - // Otherwise, we're done - None => None, - } - } -} diff --git a/vendor/itertools-0.8.2/src/concat_impl.rs b/vendor/itertools-0.8.2/src/concat_impl.rs deleted file mode 100644 index 05b370e1c6..0000000000 --- a/vendor/itertools-0.8.2/src/concat_impl.rs +++ /dev/null @@ -1,22 +0,0 @@ -use Itertools; - -/// Combine all an iterator's elements into one element by using `Extend`. -/// -/// `IntoIterator`-enabled version of `.concat()` -/// -/// This combinator will extend the first item with each of the rest of the -/// items of the iterator. If the iterator is empty, the default value of -/// `I::Item` is returned. -/// -/// ```rust -/// use itertools::concat; -/// -/// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]]; -/// assert_eq!(concat(input), vec![1, 2, 3, 4, 5, 6]); -/// ``` -pub fn concat(iterable: I) -> I::Item - where I: IntoIterator, - I::Item: Extend<<::Item as IntoIterator>::Item> + IntoIterator + Default -{ - iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_else(|| <_>::default()) -} diff --git a/vendor/itertools-0.8.2/src/cons_tuples_impl.rs b/vendor/itertools-0.8.2/src/cons_tuples_impl.rs deleted file mode 100644 index 9b27e7580f..0000000000 --- a/vendor/itertools-0.8.2/src/cons_tuples_impl.rs +++ /dev/null @@ -1,68 +0,0 @@ - -macro_rules! impl_cons_iter( - ($_A:ident, $_B:ident, ) => (); // stop - - ($A:ident, $($B:ident,)*) => ( - impl_cons_iter!($($B,)*); - #[allow(non_snake_case)] - impl Iterator for ConsTuples - where Iter: Iterator, - { - type Item = ($($B,)* X, ); - fn next(&mut self) -> Option { - self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, )) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - fn fold(self, accum: Acc, mut f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(accum, move |acc, (($($B,)*), x)| f(acc, ($($B,)* x, ))) - } - } - - #[allow(non_snake_case)] - impl DoubleEndedIterator for ConsTuples - where Iter: DoubleEndedIterator, - { - fn next_back(&mut self) -> Option { - self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, )) - } - } - - ); -); - -impl_cons_iter!(A, B, C, D, E, F, G, H,); - -/// An iterator that maps an iterator of tuples like -/// `((A, B), C)` to an iterator of `(A, B, C)`. -/// -/// Used by the `iproduct!()` macro. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct ConsTuples - where I: Iterator, -{ - iter: I, -} - -impl Clone for ConsTuples - where I: Clone + Iterator, -{ - fn clone(&self) -> Self { - ConsTuples { - iter: self.iter.clone(), - } - } -} - -/// Create an iterator that maps for example iterators of -/// `((A, B), C)` to `(A, B, C)`. -pub fn cons_tuples(iterable: I) -> ConsTuples - where I: Iterator -{ - ConsTuples { iter: iterable.into_iter() } -} diff --git a/vendor/itertools-0.8.2/src/diff.rs b/vendor/itertools-0.8.2/src/diff.rs deleted file mode 100644 index 2951bc422e..0000000000 --- a/vendor/itertools-0.8.2/src/diff.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! "Diff"ing iterators for caching elements to sequential collections without requiring the new -//! elements' iterator to be `Clone`. -//! -//! - [**Diff**](./enum.Diff.html) (produced by the [**diff_with**](./fn.diff_with.html) function) -//! describes the difference between two non-`Clone` iterators `I` and `J` after breaking ASAP from -//! a lock-step comparison. - -use free::put_back; -use structs::PutBack; - -/// A type returned by the [`diff_with`](./fn.diff_with.html) function. -/// -/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some -/// iterator `J`. -pub enum Diff - where I: Iterator, - J: Iterator -{ - /// The index of the first non-matching element along with both iterator's remaining elements - /// starting with the first mis-match. - FirstMismatch(usize, PutBack, PutBack), - /// The total number of elements that were in `J` along with the remaining elements of `I`. - Shorter(usize, PutBack), - /// The total number of elements that were in `I` along with the remaining elements of `J`. - Longer(usize, PutBack), -} - -/// Compares every element yielded by both `i` and `j` with the given function in lock-step and -/// returns a `Diff` which describes how `j` differs from `i`. -/// -/// If the number of elements yielded by `j` is less than the number of elements yielded by `i`, -/// the number of `j` elements yielded will be returned along with `i`'s remaining elements as -/// `Diff::Shorter`. -/// -/// If the two elements of a step differ, the index of those elements along with the remaining -/// elements of both `i` and `j` are returned as `Diff::FirstMismatch`. -/// -/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with -/// the remaining `j` elements will be returned as `Diff::Longer`. -pub fn diff_with(i: I, j: J, is_equal: F) - -> Option> - where I: IntoIterator, - J: IntoIterator, - F: Fn(&I::Item, &J::Item) -> bool -{ - let mut i = i.into_iter(); - let mut j = j.into_iter(); - let mut idx = 0; - while let Some(i_elem) = i.next() { - match j.next() { - None => return Some(Diff::Shorter(idx, put_back(i).with_value(i_elem))), - Some(j_elem) => if !is_equal(&i_elem, &j_elem) { - let remaining_i = put_back(i).with_value(i_elem); - let remaining_j = put_back(j).with_value(j_elem); - return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j)); - }, - } - idx += 1; - } - j.next().map(|j_elem| Diff::Longer(idx, put_back(j).with_value(j_elem))) -} diff --git a/vendor/itertools-0.8.2/src/either_or_both.rs b/vendor/itertools-0.8.2/src/either_or_both.rs deleted file mode 100644 index 03130b128c..0000000000 --- a/vendor/itertools-0.8.2/src/either_or_both.rs +++ /dev/null @@ -1,190 +0,0 @@ -use EitherOrBoth::*; - -use either::Either; - -/// Value that either holds a single A or B, or both. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum EitherOrBoth { - /// Both values are present. - Both(A, B), - /// Only the left value of type `A` is present. - Left(A), - /// Only the right value of type `B` is present. - Right(B), -} - -impl EitherOrBoth { - /// If `Left`, or `Both`, return true, otherwise, return false. - pub fn has_left(&self) -> bool { - self.as_ref().left().is_some() - } - - /// If `Right`, or `Both`, return true, otherwise, return false. - pub fn has_right(&self) -> bool { - self.as_ref().right().is_some() - } - - /// If Left, return true otherwise, return false. - /// Exclusive version of [`has_left`]. - pub fn is_left(&self) -> bool { - match *self { - Left(_) => true, - _ => false, - } - } - - /// If Right, return true otherwise, return false. - /// Exclusive version of [`has_right`]. - pub fn is_right(&self) -> bool { - match *self { - Right(_) => true, - _ => false, - } - } - - /// If Right, return true otherwise, return false. - /// Equivalent to `self.as_ref().both().is_some()`. - pub fn is_both(&self) -> bool { - self.as_ref().both().is_some() - } - - /// If `Left`, or `Both`, return `Some` with the left value, otherwise, return `None`. - pub fn left(self) -> Option { - match self { - Left(left) | Both(left, _) => Some(left), - _ => None, - } - } - - /// If `Right`, or `Both`, return `Some` with the right value, otherwise, return `None`. - pub fn right(self) -> Option { - match self { - Right(right) | Both(_, right) => Some(right), - _ => None, - } - } - - /// If Both, return `Some` tuple containing left and right. - pub fn both(self) -> Option<(A, B)> { - match self { - Both(a, b) => Some((a, b)), - _ => None, - } - } - - /// Converts from `&EitherOrBoth` to `EitherOrBoth<&A, &B>`. - pub fn as_ref(&self) -> EitherOrBoth<&A, &B> { - match *self { - Left(ref left) => Left(left), - Right(ref right) => Right(right), - Both(ref left, ref right) => Both(left, right), - } - } - - /// Converts from `&mut EitherOrBoth` to `EitherOrBoth<&mut A, &mut B>`. - pub fn as_mut(&mut self) -> EitherOrBoth<&mut A, &mut B> { - match *self { - Left(ref mut left) => Left(left), - Right(ref mut right) => Right(right), - Both(ref mut left, ref mut right) => Both(left, right), - } - } - - /// Convert `EitherOrBoth` to `EitherOrBoth`. - pub fn flip(self) -> EitherOrBoth { - match self { - Left(a) => Right(a), - Right(b) => Left(b), - Both(a, b) => Both(b, a), - } - } - - /// Apply the function `f` on the value `a` in `Left(a)` or `Both(a, b)` variants. If it is - /// present rewrapping the result in `self`'s original variant. - pub fn map_left(self, f: F) -> EitherOrBoth - where - F: FnOnce(A) -> M, - { - match self { - Both(a, b) => Both(f(a), b), - Left(a) => Left(f(a)), - Right(b) => Right(b), - } - } - - /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, b)` variants. - /// If it is present rewrapping the result in `self`'s original variant. - pub fn map_right(self, f: F) -> EitherOrBoth - where - F: FnOnce(B) -> M, - { - match self { - Left(a) => Left(a), - Right(b) => Right(f(b)), - Both(a, b) => Both(a, f(b)), - } - } - - /// Apply the functions `f` and `g` on the value `a` and `b` respectively; - /// found in `Left(a)`, `Right(b)`, or `Both(a, b)` variants. - /// The Result is rewrapped `self`'s original variant. - pub fn map_any(self, f: F, g: G) -> EitherOrBoth - where - F: FnOnce(A) -> L, - G: FnOnce(B) -> R, - { - match self { - Left(a) => Left(f(a)), - Right(b) => Right(g(b)), - Both(a, b) => Both(f(a), g(b)), - } - } - - /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, _)` variants if it is - /// present. - pub fn left_and_then(self, f: F) -> EitherOrBoth - where - F: FnOnce(A) -> EitherOrBoth, - { - match self { - Left(a) | Both(a, _) => f(a), - Right(b) => Right(b), - } - } - - /// Apply the function `f` on the value `a` - /// in `Left(a)` or `Both(a, _)` variants if it is present. - pub fn right_and_then(self, f: F) -> EitherOrBoth - where - F: FnOnce(B) -> EitherOrBoth, - { - match self { - Left(a) => Left(a), - Right(b) | Both(_, b) => f(b), - } - } -} - -impl EitherOrBoth { - /// Return either value of left, right, or the product of `f` applied where `Both` are present. - pub fn reduce(self, f: F) -> T - where - F: FnOnce(T, T) -> T, - { - match self { - Left(a) => a, - Right(b) => b, - Both(a, b) => f(a, b), - } - } -} - -impl Into>> for EitherOrBoth { - fn into(self) -> Option> { - match self { - EitherOrBoth::Left(l) => Some(Either::Left(l)), - EitherOrBoth::Right(r) => Some(Either::Right(r)), - _ => None, - } - } -} diff --git a/vendor/itertools-0.8.2/src/exactly_one_err.rs b/vendor/itertools-0.8.2/src/exactly_one_err.rs deleted file mode 100644 index 6b7bad56d2..0000000000 --- a/vendor/itertools-0.8.2/src/exactly_one_err.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::iter::ExactSizeIterator; - -use size_hint; - -/// Iterator returned for the error case of `IterTools::exactly_one()` -/// This iterator yields exactly the same elements as the input iterator. -/// -/// During the execution of exactly_one the iterator must be mutated. This wrapper -/// effectively "restores" the state of the input iterator when it's handed back. -/// -/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not -/// use a `Vec`. -#[derive(Debug, Clone)] -pub struct ExactlyOneError -where - I: Iterator, -{ - first_two: (Option, Option), - inner: I, -} - -impl ExactlyOneError -where - I: Iterator, -{ - /// Creates a new `ExactlyOneErr` iterator. - pub(crate) fn new(first_two: (Option, Option), inner: I) -> Self { - Self { first_two, inner } - } -} - -impl Iterator for ExactlyOneError -where - I: Iterator, -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - self.first_two - .0 - .take() - .or_else(|| self.first_two.1.take()) - .or_else(|| self.inner.next()) - } - - fn size_hint(&self) -> (usize, Option) { - let mut additional_len = 0; - if self.first_two.0.is_some() { - additional_len += 1; - } - if self.first_two.1.is_some() { - additional_len += 1; - } - size_hint::add_scalar(self.inner.size_hint(), additional_len) - } -} - -impl ExactSizeIterator for ExactlyOneError where I: ExactSizeIterator {} diff --git a/vendor/itertools-0.8.2/src/format.rs b/vendor/itertools-0.8.2/src/format.rs deleted file mode 100644 index c42806b01c..0000000000 --- a/vendor/itertools-0.8.2/src/format.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::fmt; -use std::cell::RefCell; - -/// Format all iterator elements lazily, separated by `sep`. -/// -/// The format value can only be formatted once, after that the iterator is -/// exhausted. -/// -/// See [`.format_with()`](../trait.Itertools.html#method.format_with) for more information. -pub struct FormatWith<'a, I, F> { - sep: &'a str, - /// FormatWith uses interior mutability because Display::fmt takes &self. - inner: RefCell>, -} - -/// Format all iterator elements lazily, separated by `sep`. -/// -/// The format value can only be formatted once, after that the iterator is -/// exhausted. -/// -/// See [`.format()`](../trait.Itertools.html#method.format) -/// for more information. -#[derive(Clone)] -pub struct Format<'a, I> { - sep: &'a str, - /// Format uses interior mutability because Display::fmt takes &self. - inner: RefCell>, -} - -pub fn new_format<'a, I, F>(iter: I, separator: &'a str, f: F) -> FormatWith<'a, I, F> - where I: Iterator, - F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result -{ - FormatWith { - sep: separator, - inner: RefCell::new(Some((iter, f))), - } -} - -pub fn new_format_default<'a, I>(iter: I, separator: &'a str) -> Format<'a, I> - where I: Iterator, -{ - Format { - sep: separator, - inner: RefCell::new(Some(iter)), - } -} - -impl<'a, I, F> fmt::Display for FormatWith<'a, I, F> - where I: Iterator, - F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (mut iter, mut format) = match self.inner.borrow_mut().take() { - Some(t) => t, - None => panic!("FormatWith: was already formatted once"), - }; - - if let Some(fst) = iter.next() { - try!(format(fst, &mut |disp: &fmt::Display| disp.fmt(f))); - for elt in iter { - if self.sep.len() > 0 { - - try!(f.write_str(self.sep)); - } - try!(format(elt, &mut |disp: &fmt::Display| disp.fmt(f))); - } - } - Ok(()) - } -} - -impl<'a, I> Format<'a, I> - where I: Iterator, -{ - fn format(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result - where F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result, - { - let mut iter = match self.inner.borrow_mut().take() { - Some(t) => t, - None => panic!("Format: was already formatted once"), - }; - - if let Some(fst) = iter.next() { - try!(cb(&fst, f)); - for elt in iter { - if self.sep.len() > 0 { - try!(f.write_str(self.sep)); - } - try!(cb(&elt, f)); - } - } - Ok(()) - } -} - -macro_rules! impl_format { - ($($fmt_trait:ident)*) => { - $( - impl<'a, I> fmt::$fmt_trait for Format<'a, I> - where I: Iterator, - I::Item: fmt::$fmt_trait, - { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.format(f, fmt::$fmt_trait::fmt) - } - } - )* - } -} - -impl_format!{Display Debug - UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer} diff --git a/vendor/itertools-0.8.2/src/free.rs b/vendor/itertools-0.8.2/src/free.rs deleted file mode 100644 index 2bc72a9aa1..0000000000 --- a/vendor/itertools-0.8.2/src/free.rs +++ /dev/null @@ -1,236 +0,0 @@ -//! Free functions that create iterator adaptors or call iterator methods. -//! -//! The benefit of free functions is that they accept any `IntoIterator` as -//! argument, so the resulting code may be easier to read. - -#[cfg(feature = "use_std")] -use std::fmt::Display; -use std::iter::{self, Zip}; -#[cfg(feature = "use_std")] -type VecIntoIter = ::std::vec::IntoIter; - -#[cfg(feature = "use_std")] -use Itertools; - -pub use adaptors::{ - interleave, - merge, - put_back, -}; -#[cfg(feature = "use_std")] -pub use put_back_n_impl::put_back_n; -#[cfg(feature = "use_std")] -pub use multipeek_impl::multipeek; -#[cfg(feature = "use_std")] -pub use kmerge_impl::kmerge; -pub use zip_eq_impl::zip_eq; -pub use merge_join::merge_join_by; -#[cfg(feature = "use_std")] -pub use rciter_impl::rciter; - -/// Iterate `iterable` with a running index. -/// -/// `IntoIterator` enabled version of `.enumerate()`. -/// -/// ``` -/// use itertools::enumerate; -/// -/// for (i, elt) in enumerate(&[1, 2, 3]) { -/// /* loop body */ -/// } -/// ``` -pub fn enumerate(iterable: I) -> iter::Enumerate - where I: IntoIterator -{ - iterable.into_iter().enumerate() -} - -/// Iterate `iterable` in reverse. -/// -/// `IntoIterator` enabled version of `.rev()`. -/// -/// ``` -/// use itertools::rev; -/// -/// for elt in rev(&[1, 2, 3]) { -/// /* loop body */ -/// } -/// ``` -pub fn rev(iterable: I) -> iter::Rev - where I: IntoIterator, - I::IntoIter: DoubleEndedIterator -{ - iterable.into_iter().rev() -} - -/// Iterate `i` and `j` in lock step. -/// -/// `IntoIterator` enabled version of `i.zip(j)`. -/// -/// ``` -/// use itertools::zip; -/// -/// let data = [1, 2, 3, 4, 5]; -/// for (a, b) in zip(&data, &data[1..]) { -/// /* loop body */ -/// } -/// ``` -pub fn zip(i: I, j: J) -> Zip - where I: IntoIterator, - J: IntoIterator -{ - i.into_iter().zip(j) -} - -/// Create an iterator that first iterates `i` and then `j`. -/// -/// `IntoIterator` enabled version of `i.chain(j)`. -/// -/// ``` -/// use itertools::chain; -/// -/// for elt in chain(&[1, 2, 3], &[4]) { -/// /* loop body */ -/// } -/// ``` -pub fn chain(i: I, j: J) -> iter::Chain<::IntoIter, ::IntoIter> - where I: IntoIterator, - J: IntoIterator -{ - i.into_iter().chain(j) -} - -/// Create an iterator that clones each element from &T to T -/// -/// `IntoIterator` enabled version of `i.cloned()`. -/// -/// ``` -/// use itertools::cloned; -/// -/// assert_eq!(cloned(b"abc").next(), Some(b'a')); -/// ``` -pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned - where I: IntoIterator, - T: Clone, -{ - iterable.into_iter().cloned() -} - -/// Perform a fold operation over the iterable. -/// -/// `IntoIterator` enabled version of `i.fold(init, f)` -/// -/// ``` -/// use itertools::fold; -/// -/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.); -/// ``` -pub fn fold(iterable: I, init: B, f: F) -> B - where I: IntoIterator, - F: FnMut(B, I::Item) -> B -{ - iterable.into_iter().fold(init, f) -} - -/// Test whether the predicate holds for all elements in the iterable. -/// -/// `IntoIterator` enabled version of `i.all(f)` -/// -/// ``` -/// use itertools::all; -/// -/// assert!(all(&[1, 2, 3], |elt| *elt > 0)); -/// ``` -pub fn all(iterable: I, f: F) -> bool - where I: IntoIterator, - F: FnMut(I::Item) -> bool -{ - iterable.into_iter().all(f) -} - -/// Test whether the predicate holds for any elements in the iterable. -/// -/// `IntoIterator` enabled version of `i.any(f)` -/// -/// ``` -/// use itertools::any; -/// -/// assert!(any(&[0, -1, 2], |elt| *elt > 0)); -/// ``` -pub fn any(iterable: I, f: F) -> bool - where I: IntoIterator, - F: FnMut(I::Item) -> bool -{ - iterable.into_iter().any(f) -} - -/// Return the maximum value of the iterable. -/// -/// `IntoIterator` enabled version of `i.max()`. -/// -/// ``` -/// use itertools::max; -/// -/// assert_eq!(max(0..10), Some(9)); -/// ``` -pub fn max(iterable: I) -> Option - where I: IntoIterator, - I::Item: Ord -{ - iterable.into_iter().max() -} - -/// Return the minimum value of the iterable. -/// -/// `IntoIterator` enabled version of `i.min()`. -/// -/// ``` -/// use itertools::min; -/// -/// assert_eq!(min(0..10), Some(0)); -/// ``` -pub fn min(iterable: I) -> Option - where I: IntoIterator, - I::Item: Ord -{ - iterable.into_iter().min() -} - - -/// Combine all iterator elements into one String, seperated by `sep`. -/// -/// `IntoIterator` enabled version of `iterable.join(sep)`. -/// -/// ``` -/// use itertools::join; -/// -/// assert_eq!(join(&[1, 2, 3], ", "), "1, 2, 3"); -/// ``` -#[cfg(feature = "use_std")] -pub fn join(iterable: I, sep: &str) -> String - where I: IntoIterator, - I::Item: Display -{ - iterable.into_iter().join(sep) -} - -/// Sort all iterator elements into a new iterator in ascending order. -/// -/// `IntoIterator` enabled version of [`iterable.sorted()`][1]. -/// -/// [1]: trait.Itertools.html#method.sorted -/// -/// ``` -/// use itertools::sorted; -/// use itertools::assert_equal; -/// -/// assert_equal(sorted("rust".chars()), "rstu".chars()); -/// ``` -#[cfg(feature = "use_std")] -pub fn sorted(iterable: I) -> VecIntoIter - where I: IntoIterator, - I::Item: Ord -{ - iterable.into_iter().sorted() -} - diff --git a/vendor/itertools-0.8.2/src/group_map.rs b/vendor/itertools-0.8.2/src/group_map.rs deleted file mode 100644 index be9f8420d8..0000000000 --- a/vendor/itertools-0.8.2/src/group_map.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![cfg(feature = "use_std")] - -use std::collections::HashMap; -use std::hash::Hash; -use std::iter::Iterator; - -/// Return a `HashMap` of keys mapped to a list of their corresponding values. -/// -/// See [`.into_group_map()`](../trait.Itertools.html#method.into_group_map) -/// for more information. -pub fn into_group_map(iter: I) -> HashMap> - where I: Iterator, - K: Hash + Eq, -{ - let mut lookup = HashMap::new(); - - for (key, val) in iter { - lookup.entry(key).or_insert(Vec::new()).push(val); - } - - lookup -} \ No newline at end of file diff --git a/vendor/itertools-0.8.2/src/groupbylazy.rs b/vendor/itertools-0.8.2/src/groupbylazy.rs deleted file mode 100644 index ff253e845d..0000000000 --- a/vendor/itertools-0.8.2/src/groupbylazy.rs +++ /dev/null @@ -1,571 +0,0 @@ -use std::cell::{Cell, RefCell}; -use std::vec; - -/// A trait to unify FnMut for GroupBy with the chunk key in IntoChunks -trait KeyFunction { - type Key; - fn call_mut(&mut self, arg: A) -> Self::Key; -} - -impl<'a, A, K, F: ?Sized> KeyFunction for F - where F: FnMut(A) -> K -{ - type Key = K; - #[inline] - fn call_mut(&mut self, arg: A) -> Self::Key { - (*self)(arg) - } -} - - -/// ChunkIndex acts like the grouping key function for IntoChunks -#[derive(Debug)] -struct ChunkIndex { - size: usize, - index: usize, - key: usize, -} - -impl ChunkIndex { - #[inline(always)] - fn new(size: usize) -> Self { - ChunkIndex { - size: size, - index: 0, - key: 0, - } - } -} - -impl<'a, A> KeyFunction for ChunkIndex { - type Key = usize; - #[inline(always)] - fn call_mut(&mut self, _arg: A) -> Self::Key { - if self.index == self.size { - self.key += 1; - self.index = 0; - } - self.index += 1; - self.key - } -} - - -struct GroupInner - where I: Iterator -{ - key: F, - iter: I, - current_key: Option, - current_elt: Option, - /// flag set if iterator is exhausted - done: bool, - /// Index of group we are currently buffering or visiting - top_group: usize, - /// Least index for which we still have elements buffered - oldest_buffered_group: usize, - /// Group index for `buffer[0]` -- the slots - /// bottom_group..oldest_buffered_group are unused and will be erased when - /// that range is large enough. - bottom_group: usize, - /// Buffered groups, from `bottom_group` (index 0) to `top_group`. - buffer: Vec>, - /// index of last group iter that was dropped, usize::MAX == none - dropped_group: usize, -} - -impl GroupInner - where I: Iterator, - F: for<'a> KeyFunction<&'a I::Item, Key=K>, - K: PartialEq, -{ - /// `client`: Index of group that requests next element - #[inline(always)] - fn step(&mut self, client: usize) -> Option { - /* - println!("client={}, bottom_group={}, oldest_buffered_group={}, top_group={}, buffers=[{}]", - client, self.bottom_group, self.oldest_buffered_group, - self.top_group, - self.buffer.iter().map(|elt| elt.len()).format(", ")); - */ - if client < self.oldest_buffered_group { - None - } else if client < self.top_group || - (client == self.top_group && - self.buffer.len() > self.top_group - self.bottom_group) - { - self.lookup_buffer(client) - } else if self.done { - None - } else if self.top_group == client { - self.step_current() - } else { - self.step_buffering(client) - } - } - - #[inline(never)] - fn lookup_buffer(&mut self, client: usize) -> Option { - // if `bufidx` doesn't exist in self.buffer, it might be empty - let bufidx = client - self.bottom_group; - if client < self.oldest_buffered_group { - return None; - } - let elt = self.buffer.get_mut(bufidx).and_then(|queue| queue.next()); - if elt.is_none() && client == self.oldest_buffered_group { - // FIXME: VecDeque is unfortunately not zero allocation when empty, - // so we do this job manually. - // `bottom_group..oldest_buffered_group` is unused, and if it's large enough, erase it. - self.oldest_buffered_group += 1; - // skip forward further empty queues too - while self.buffer.get(self.oldest_buffered_group - self.bottom_group) - .map_or(false, |buf| buf.len() == 0) - { - self.oldest_buffered_group += 1; - } - - let nclear = self.oldest_buffered_group - self.bottom_group; - if nclear > 0 && nclear >= self.buffer.len() / 2 { - let mut i = 0; - self.buffer.retain(|buf| { - i += 1; - debug_assert!(buf.len() == 0 || i > nclear); - i > nclear - }); - self.bottom_group = self.oldest_buffered_group; - } - } - elt - } - - /// Take the next element from the iterator, and set the done - /// flag if exhausted. Must not be called after done. - #[inline(always)] - fn next_element(&mut self) -> Option { - debug_assert!(!self.done); - match self.iter.next() { - None => { self.done = true; None } - otherwise => otherwise, - } - } - - - #[inline(never)] - fn step_buffering(&mut self, client: usize) -> Option { - // requested a later group -- walk through the current group up to - // the requested group index, and buffer the elements (unless - // the group is marked as dropped). - // Because the `Groups` iterator is always the first to request - // each group index, client is the next index efter top_group. - debug_assert!(self.top_group + 1 == client); - let mut group = Vec::new(); - - if let Some(elt) = self.current_elt.take() { - if self.top_group != self.dropped_group { - group.push(elt); - } - } - let mut first_elt = None; // first element of the next group - - while let Some(elt) = self.next_element() { - let key = self.key.call_mut(&elt); - match self.current_key.take() { - None => {} - Some(old_key) => if old_key != key { - self.current_key = Some(key); - first_elt = Some(elt); - break; - }, - } - self.current_key = Some(key); - if self.top_group != self.dropped_group { - group.push(elt); - } - } - - if self.top_group != self.dropped_group { - self.push_next_group(group); - } - if first_elt.is_some() { - self.top_group += 1; - debug_assert!(self.top_group == client); - } - first_elt - } - - fn push_next_group(&mut self, group: Vec) { - // When we add a new buffered group, fill up slots between oldest_buffered_group and top_group - while self.top_group - self.bottom_group > self.buffer.len() { - if self.buffer.is_empty() { - self.bottom_group += 1; - self.oldest_buffered_group += 1; - } else { - self.buffer.push(Vec::new().into_iter()); - } - } - self.buffer.push(group.into_iter()); - debug_assert!(self.top_group + 1 - self.bottom_group == self.buffer.len()); - } - - /// This is the immediate case, where we use no buffering - #[inline] - fn step_current(&mut self) -> Option { - debug_assert!(!self.done); - if let elt @ Some(..) = self.current_elt.take() { - return elt; - } - match self.next_element() { - None => None, - Some(elt) => { - let key = self.key.call_mut(&elt); - match self.current_key.take() { - None => {} - Some(old_key) => if old_key != key { - self.current_key = Some(key); - self.current_elt = Some(elt); - self.top_group += 1; - return None; - }, - } - self.current_key = Some(key); - Some(elt) - } - } - } - - /// Request the just started groups' key. - /// - /// `client`: Index of group - /// - /// **Panics** if no group key is available. - fn group_key(&mut self, client: usize) -> K { - // This can only be called after we have just returned the first - // element of a group. - // Perform this by simply buffering one more element, grabbing the - // next key. - debug_assert!(!self.done); - debug_assert!(client == self.top_group); - debug_assert!(self.current_key.is_some()); - debug_assert!(self.current_elt.is_none()); - let old_key = self.current_key.take().unwrap(); - if let Some(elt) = self.next_element() { - let key = self.key.call_mut(&elt); - if old_key != key { - self.top_group += 1; - } - self.current_key = Some(key); - self.current_elt = Some(elt); - } - old_key - } -} - -impl GroupInner - where I: Iterator, -{ - /// Called when a group is dropped - fn drop_group(&mut self, client: usize) { - // It's only useful to track the maximal index - if self.dropped_group == !0 || client > self.dropped_group { - self.dropped_group = client; - } - } -} - -/// `GroupBy` is the storage for the lazy grouping operation. -/// -/// If the groups are consumed in their original order, or if each -/// group is dropped without keeping it around, then `GroupBy` uses -/// no allocations. It needs allocations only if several group iterators -/// are alive at the same time. -/// -/// This type implements `IntoIterator` (it is **not** an iterator -/// itself), because the group iterators need to borrow from this -/// value. It should be stored in a local variable or temporary and -/// iterated. -/// -/// See [`.group_by()`](../trait.Itertools.html#method.group_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct GroupBy - where I: Iterator, -{ - inner: RefCell>, - // the group iterator's current index. Keep this in the main value - // so that simultaneous iterators all use the same state. - index: Cell, -} - -/// Create a new -pub fn new(iter: J, f: F) -> GroupBy - where J: IntoIterator, - F: FnMut(&J::Item) -> K, -{ - GroupBy { - inner: RefCell::new(GroupInner { - key: f, - iter: iter.into_iter(), - current_key: None, - current_elt: None, - done: false, - top_group: 0, - oldest_buffered_group: 0, - bottom_group: 0, - buffer: Vec::new(), - dropped_group: !0, - }), - index: Cell::new(0), - } -} - -impl GroupBy - where I: Iterator, -{ - /// `client`: Index of group that requests next element - fn step(&self, client: usize) -> Option - where F: FnMut(&I::Item) -> K, - K: PartialEq, - { - self.inner.borrow_mut().step(client) - } - - /// `client`: Index of group - fn drop_group(&self, client: usize) { - self.inner.borrow_mut().drop_group(client) - } -} - -impl<'a, K, I, F> IntoIterator for &'a GroupBy - where I: Iterator, - I::Item: 'a, - F: FnMut(&I::Item) -> K, - K: PartialEq -{ - type Item = (K, Group<'a, K, I, F>); - type IntoIter = Groups<'a, K, I, F>; - - fn into_iter(self) -> Self::IntoIter { - Groups { parent: self } - } -} - - -/// An iterator that yields the Group iterators. -/// -/// Iterator element type is `(K, Group)`: -/// the group's key `K` and the group's iterator. -/// -/// See [`.group_by()`](../trait.Itertools.html#method.group_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Groups<'a, K: 'a, I: 'a, F: 'a> - where I: Iterator, - I::Item: 'a -{ - parent: &'a GroupBy, -} - -impl<'a, K, I, F> Iterator for Groups<'a, K, I, F> - where I: Iterator, - I::Item: 'a, - F: FnMut(&I::Item) -> K, - K: PartialEq -{ - type Item = (K, Group<'a, K, I, F>); - - #[inline] - fn next(&mut self) -> Option { - let index = self.parent.index.get(); - self.parent.index.set(index + 1); - let inner = &mut *self.parent.inner.borrow_mut(); - inner.step(index).map(|elt| { - let key = inner.group_key(index); - (key, Group { - parent: self.parent, - index: index, - first: Some(elt), - }) - }) - } -} - -/// An iterator for the elements in a single group. -/// -/// Iterator element type is `I::Item`. -pub struct Group<'a, K: 'a, I: 'a, F: 'a> - where I: Iterator, - I::Item: 'a, -{ - parent: &'a GroupBy, - index: usize, - first: Option, -} - -impl<'a, K, I, F> Drop for Group<'a, K, I, F> - where I: Iterator, - I::Item: 'a, -{ - fn drop(&mut self) { - self.parent.drop_group(self.index); - } -} - -impl<'a, K, I, F> Iterator for Group<'a, K, I, F> - where I: Iterator, - I::Item: 'a, - F: FnMut(&I::Item) -> K, - K: PartialEq, -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - if let elt @ Some(..) = self.first.take() { - return elt; - } - self.parent.step(self.index) - } -} - -///// IntoChunks ///// - -/// Create a new -pub fn new_chunks(iter: J, size: usize) -> IntoChunks - where J: IntoIterator, -{ - IntoChunks { - inner: RefCell::new(GroupInner { - key: ChunkIndex::new(size), - iter: iter.into_iter(), - current_key: None, - current_elt: None, - done: false, - top_group: 0, - oldest_buffered_group: 0, - bottom_group: 0, - buffer: Vec::new(), - dropped_group: !0, - }), - index: Cell::new(0), - } -} - - -/// `ChunkLazy` is the storage for a lazy chunking operation. -/// -/// `IntoChunks` behaves just like `GroupBy`: it is iterable, and -/// it only buffers if several chunk iterators are alive at the same time. -/// -/// This type implements `IntoIterator` (it is **not** an iterator -/// itself), because the chunk iterators need to borrow from this -/// value. It should be stored in a local variable or temporary and -/// iterated. -/// -/// Iterator element type is `Chunk`, each chunk's iterator. -/// -/// See [`.chunks()`](../trait.Itertools.html#method.chunks) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct IntoChunks - where I: Iterator, -{ - inner: RefCell>, - // the chunk iterator's current index. Keep this in the main value - // so that simultaneous iterators all use the same state. - index: Cell, -} - - -impl IntoChunks - where I: Iterator, -{ - /// `client`: Index of chunk that requests next element - fn step(&self, client: usize) -> Option { - self.inner.borrow_mut().step(client) - } - - /// `client`: Index of chunk - fn drop_group(&self, client: usize) { - self.inner.borrow_mut().drop_group(client) - } -} - -impl<'a, I> IntoIterator for &'a IntoChunks - where I: Iterator, - I::Item: 'a, -{ - type Item = Chunk<'a, I>; - type IntoIter = Chunks<'a, I>; - - fn into_iter(self) -> Self::IntoIter { - Chunks { - parent: self, - } - } -} - - -/// An iterator that yields the Chunk iterators. -/// -/// Iterator element type is `Chunk`. -/// -/// See [`.chunks()`](../trait.Itertools.html#method.chunks) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Chunks<'a, I: 'a> - where I: Iterator, - I::Item: 'a, -{ - parent: &'a IntoChunks, -} - -impl<'a, I> Iterator for Chunks<'a, I> - where I: Iterator, - I::Item: 'a, -{ - type Item = Chunk<'a, I>; - - #[inline] - fn next(&mut self) -> Option { - let index = self.parent.index.get(); - self.parent.index.set(index + 1); - let inner = &mut *self.parent.inner.borrow_mut(); - inner.step(index).map(|elt| { - Chunk { - parent: self.parent, - index: index, - first: Some(elt), - } - }) - } -} - -/// An iterator for the elements in a single chunk. -/// -/// Iterator element type is `I::Item`. -pub struct Chunk<'a, I: 'a> - where I: Iterator, - I::Item: 'a, -{ - parent: &'a IntoChunks, - index: usize, - first: Option, -} - -impl<'a, I> Drop for Chunk<'a, I> - where I: Iterator, - I::Item: 'a, -{ - fn drop(&mut self) { - self.parent.drop_group(self.index); - } -} - -impl<'a, I> Iterator for Chunk<'a, I> - where I: Iterator, - I::Item: 'a, -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - if let elt @ Some(..) = self.first.take() { - return elt; - } - self.parent.step(self.index) - } -} diff --git a/vendor/itertools-0.8.2/src/impl_macros.rs b/vendor/itertools-0.8.2/src/impl_macros.rs deleted file mode 100644 index b41760aee8..0000000000 --- a/vendor/itertools-0.8.2/src/impl_macros.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! -//! Implementation's internal macros - -macro_rules! debug_fmt_fields { - ($tyname:ident, $($($field:ident).+),*) => { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - f.debug_struct(stringify!($tyname)) - $( - .field(stringify!($($field).+), &self.$($field).+) - )* - .finish() - } - } -} diff --git a/vendor/itertools-0.8.2/src/intersperse.rs b/vendor/itertools-0.8.2/src/intersperse.rs deleted file mode 100644 index f82544229c..0000000000 --- a/vendor/itertools-0.8.2/src/intersperse.rs +++ /dev/null @@ -1,79 +0,0 @@ -use std::iter::Fuse; -use super::size_hint; - -#[derive(Clone)] -/// An iterator adaptor to insert a particular value -/// between each element of the adapted iterator. -/// -/// Iterator element type is `I::Item` -/// -/// This iterator is *fused*. -/// -/// See [`.intersperse()`](../trait.Itertools.html#method.intersperse) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct Intersperse - where I: Iterator -{ - element: I::Item, - iter: Fuse, - peek: Option, -} - -/// Create a new Intersperse iterator -pub fn intersperse(iter: I, elt: I::Item) -> Intersperse - where I: Iterator -{ - let mut iter = iter.fuse(); - Intersperse { - peek: iter.next(), - iter: iter, - element: elt, - } -} - -impl Iterator for Intersperse - where I: Iterator, - I::Item: Clone -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - if self.peek.is_some() { - self.peek.take() - } else { - self.peek = self.iter.next(); - if self.peek.is_some() { - Some(self.element.clone()) - } else { - None - } - } - } - - fn size_hint(&self) -> (usize, Option) { - // 2 * SH + { 1 or 0 } - let has_peek = self.peek.is_some() as usize; - let sh = self.iter.size_hint(); - size_hint::add_scalar(size_hint::add(sh, sh), has_peek) - } - - fn fold(mut self, init: B, mut f: F) -> B where - Self: Sized, F: FnMut(B, Self::Item) -> B, - { - let mut accum = init; - - if let Some(x) = self.peek.take() { - accum = f(accum, x); - } - - let element = &self.element; - - self.iter.fold(accum, - |accum, x| { - let accum = f(accum, element.clone()); - let accum = f(accum, x); - accum - }) - } -} diff --git a/vendor/itertools-0.8.2/src/kmerge_impl.rs b/vendor/itertools-0.8.2/src/kmerge_impl.rs deleted file mode 100644 index a79b7bdace..0000000000 --- a/vendor/itertools-0.8.2/src/kmerge_impl.rs +++ /dev/null @@ -1,231 +0,0 @@ - -use size_hint; -use Itertools; - -use std::mem::replace; -use std::fmt; - -macro_rules! clone_fields { - ($name:ident, $base:expr, $($field:ident),+) => ( - $name { - $( - $field : $base . $field .clone() - ),* - } - ); -} - -/// Head element and Tail iterator pair -/// -/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on -/// first items (which are guaranteed to exist). -/// -/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in -/// `KMerge` into a min-heap. -#[derive(Debug)] -struct HeadTail - where I: Iterator -{ - head: I::Item, - tail: I, -} - -impl HeadTail - where I: Iterator -{ - /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty. - fn new(mut it: I) -> Option> { - let head = it.next(); - head.map(|h| { - HeadTail { - head: h, - tail: it, - } - }) - } - - /// Get the next element and update `head`, returning the old head in `Some`. - /// - /// Returns `None` when the tail is exhausted (only `head` then remains). - fn next(&mut self) -> Option { - if let Some(next) = self.tail.next() { - Some(replace(&mut self.head, next)) - } else { - None - } - } - - /// Hints at the size of the sequence, same as the `Iterator` method. - fn size_hint(&self) -> (usize, Option) { - size_hint::add_scalar(self.tail.size_hint(), 1) - } -} - -impl Clone for HeadTail - where I: Iterator + Clone, - I::Item: Clone -{ - fn clone(&self) -> Self { - clone_fields!(HeadTail, self, head, tail) - } -} - -/// Make `data` a heap (min-heap w.r.t the sorting). -fn heapify(data: &mut [T], mut less_than: S) - where S: FnMut(&T, &T) -> bool -{ - for i in (0..data.len() / 2).rev() { - sift_down(data, i, &mut less_than); - } -} - -/// Sift down element at `index` (`heap` is a min-heap wrt the ordering) -fn sift_down(heap: &mut [T], index: usize, mut less_than: S) - where S: FnMut(&T, &T) -> bool -{ - debug_assert!(index <= heap.len()); - let mut pos = index; - let mut child = 2 * pos + 1; - // the `pos` conditional is to avoid a bounds check - while pos < heap.len() && child < heap.len() { - let right = child + 1; - - // pick the smaller of the two children - if right < heap.len() && less_than(&heap[right], &heap[child]) { - child = right; - } - - // sift down is done if we are already in order - if !less_than(&heap[child], &heap[pos]) { - return; - } - heap.swap(pos, child); - pos = child; - child = 2 * pos + 1; - } -} - -/// An iterator adaptor that merges an abitrary number of base iterators in ascending order. -/// If all base iterators are sorted (ascending), the result is sorted. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.kmerge()`](../trait.Itertools.html#method.kmerge) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub type KMerge = KMergeBy; - -pub trait KMergePredicate { - fn kmerge_pred(&mut self, a: &T, b: &T) -> bool; -} - -#[derive(Clone)] -pub struct KMergeByLt; - -impl KMergePredicate for KMergeByLt { - fn kmerge_pred(&mut self, a: &T, b: &T) -> bool { - a < b - } -} - -implbool> KMergePredicate for F { - fn kmerge_pred(&mut self, a: &T, b: &T) -> bool { - self(a, b) - } -} - -/// Create an iterator that merges elements of the contained iterators using -/// the ordering function. -/// -/// Equivalent to `iterable.into_iter().kmerge()`. -/// -/// ``` -/// use itertools::kmerge; -/// -/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) { -/// /* loop body */ -/// } -/// ``` -pub fn kmerge(iterable: I) -> KMerge<::IntoIter> - where I: IntoIterator, - I::Item: IntoIterator, - <::Item as IntoIterator>::Item: PartialOrd -{ - kmerge_by(iterable, KMergeByLt) -} - -/// An iterator adaptor that merges an abitrary number of base iterators -/// according to an ordering function. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.kmerge_by()`](../trait.Itertools.html#method.kmerge_by) for more -/// information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct KMergeBy - where I: Iterator, -{ - heap: Vec>, - less_than: F, -} - -impl fmt::Debug for KMergeBy - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(KMergeBy, heap); -} - -/// Create an iterator that merges elements of the contained iterators. -/// -/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`. -pub fn kmerge_by(iterable: I, mut less_than: F) - -> KMergeBy<::IntoIter, F> - where I: IntoIterator, - I::Item: IntoIterator, - F: KMergePredicate<<::Item as IntoIterator>::Item>, -{ - let iter = iterable.into_iter(); - let (lower, _) = iter.size_hint(); - let mut heap: Vec<_> = Vec::with_capacity(lower); - heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter()))); - heapify(&mut heap, |a, b| less_than.kmerge_pred(&a.head, &b.head)); - KMergeBy { heap: heap, less_than: less_than } -} - -impl Clone for KMergeBy - where I: Iterator + Clone, - I::Item: Clone, - F: Clone, -{ - fn clone(&self) -> KMergeBy { - clone_fields!(KMergeBy, self, heap, less_than) - } -} - -impl Iterator for KMergeBy - where I: Iterator, - F: KMergePredicate -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - if self.heap.is_empty() { - return None; - } - let result = if let Some(next) = self.heap[0].next() { - next - } else { - self.heap.swap_remove(0).head - }; - let less_than = &mut self.less_than; - sift_down(&mut self.heap, 0, |a, b| less_than.kmerge_pred(&a.head, &b.head)); - Some(result) - } - - fn size_hint(&self) -> (usize, Option) { - self.heap.iter() - .map(|i| i.size_hint()) - .fold1(size_hint::add) - .unwrap_or((0, Some(0))) - } -} diff --git a/vendor/itertools-0.8.2/src/lazy_buffer.rs b/vendor/itertools-0.8.2/src/lazy_buffer.rs deleted file mode 100644 index 09a8cd9569..0000000000 --- a/vendor/itertools-0.8.2/src/lazy_buffer.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::ops::Index; - -#[derive(Debug, Clone)] -pub struct LazyBuffer { - pub it: I, - done: bool, - buffer: Vec, -} - -impl LazyBuffer -where - I: Iterator, -{ - pub fn new(it: I) -> LazyBuffer { - let mut it = it; - let mut buffer = Vec::new(); - let done; - if let Some(first) = it.next() { - buffer.push(first); - done = false; - } else { - done = true; - } - LazyBuffer { - it: it, - done: done, - buffer: buffer, - } - } - - pub fn len(&self) -> usize { - self.buffer.len() - } - - pub fn is_done(&self) -> bool { - self.done - } - - pub fn get_next(&mut self) -> bool { - if self.done { - return false; - } - let next_item = self.it.next(); - match next_item { - Some(x) => { - self.buffer.push(x); - true - } - None => { - self.done = true; - false - } - } - } -} - -impl Index for LazyBuffer -where - I: Iterator, - I::Item: Sized, - Vec: Index -{ - type Output = as Index>::Output; - - fn index(&self, _index: J) -> &Self::Output { - self.buffer.index(_index) - } -} diff --git a/vendor/itertools-0.8.2/src/lib.rs b/vendor/itertools-0.8.2/src/lib.rs deleted file mode 100644 index d7c7960bb7..0000000000 --- a/vendor/itertools-0.8.2/src/lib.rs +++ /dev/null @@ -1,2391 +0,0 @@ -#![warn(missing_docs)] -#![crate_name="itertools"] -#![cfg_attr(not(feature = "use_std"), no_std)] - -//! Extra iterator adaptors, functions and macros. -//! -//! To extend [`Iterator`] with methods in this crate, import -//! the [`Itertools` trait](./trait.Itertools.html): -//! -//! ``` -//! use itertools::Itertools; -//! ``` -//! -//! Now, new methods like [`interleave`](./trait.Itertools.html#method.interleave) -//! are available on all iterators: -//! -//! ``` -//! use itertools::Itertools; -//! -//! let it = (1..3).interleave(vec![-1, -2]); -//! itertools::assert_equal(it, vec![1, -1, 2, -2]); -//! ``` -//! -//! Most iterator methods are also provided as functions (with the benefit -//! that they convert parameters using [`IntoIterator`]): -//! -//! ``` -//! use itertools::interleave; -//! -//! for elt in interleave(&[1, 2, 3], &[2, 3, 4]) { -//! /* loop body */ -//! } -//! ``` -//! -//! ## Crate Features -//! -//! - `use_std` -//! - Enabled by default. -//! - Disable to compile itertools using `#![no_std]`. This disables -//! any items that depend on collections (like `group_by`, `unique`, -//! `kmerge`, `join` and many more). -//! -//! ## Rust Version -//! -//! This version of itertools requires Rust 1.24 or later. -//! -//! [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html -#![doc(html_root_url="https://docs.rs/itertools/0.8/")] - -extern crate either; - -#[cfg(not(feature = "use_std"))] -extern crate core as std; - -pub use either::Either; - -#[cfg(feature = "use_std")] -use std::collections::HashMap; -use std::iter::{IntoIterator, once}; -use std::cmp::Ordering; -use std::fmt; -#[cfg(feature = "use_std")] -use std::hash::Hash; -#[cfg(feature = "use_std")] -use std::fmt::Write; -#[cfg(feature = "use_std")] -type VecIntoIter = ::std::vec::IntoIter; -#[cfg(feature = "use_std")] -use std::iter::FromIterator; - -#[macro_use] -mod impl_macros; - -// for compatibility with no std and macros -#[doc(hidden)] -pub use std::iter as __std_iter; - -/// The concrete iterator types. -pub mod structs { - pub use adaptors::{ - Dedup, - DedupBy, - Interleave, - InterleaveShortest, - Product, - PutBack, - Batching, - MapInto, - MapResults, - Merge, - MergeBy, - TakeWhileRef, - WhileSome, - Coalesce, - TupleCombinations, - Positions, - Update, - }; - #[allow(deprecated)] - pub use adaptors::Step; - #[cfg(feature = "use_std")] - pub use adaptors::MultiProduct; - #[cfg(feature = "use_std")] - pub use combinations::Combinations; - #[cfg(feature = "use_std")] - pub use combinations_with_replacement::CombinationsWithReplacement; - pub use cons_tuples_impl::ConsTuples; - pub use exactly_one_err::ExactlyOneError; - pub use format::{Format, FormatWith}; - #[cfg(feature = "use_std")] - pub use groupbylazy::{IntoChunks, Chunk, Chunks, GroupBy, Group, Groups}; - pub use intersperse::Intersperse; - #[cfg(feature = "use_std")] - pub use kmerge_impl::{KMerge, KMergeBy}; - pub use merge_join::MergeJoinBy; - #[cfg(feature = "use_std")] - pub use multipeek_impl::MultiPeek; - pub use pad_tail::PadUsing; - pub use peeking_take_while::PeekingTakeWhile; - #[cfg(feature = "use_std")] - pub use permutations::Permutations; - pub use process_results_impl::ProcessResults; - #[cfg(feature = "use_std")] - pub use put_back_n_impl::PutBackN; - #[cfg(feature = "use_std")] - pub use rciter_impl::RcIter; - pub use repeatn::RepeatN; - #[allow(deprecated)] - pub use sources::{RepeatCall, Unfold, Iterate}; - #[cfg(feature = "use_std")] - pub use tee::Tee; - pub use tuple_impl::{TupleBuffer, TupleWindows, Tuples}; - #[cfg(feature = "use_std")] - pub use unique_impl::{Unique, UniqueBy}; - pub use with_position::WithPosition; - pub use zip_eq_impl::ZipEq; - pub use zip_longest::ZipLongest; - pub use ziptuple::Zip; -} -#[allow(deprecated)] -pub use structs::*; -pub use concat_impl::concat; -pub use cons_tuples_impl::cons_tuples; -pub use diff::diff_with; -pub use diff::Diff; -#[cfg(feature = "use_std")] -pub use kmerge_impl::{kmerge_by}; -pub use minmax::MinMaxResult; -pub use peeking_take_while::PeekingNext; -pub use process_results_impl::process_results; -pub use repeatn::repeat_n; -#[allow(deprecated)] -pub use sources::{repeat_call, unfold, iterate}; -pub use with_position::Position; -pub use ziptuple::multizip; -mod adaptors; -mod either_or_both; -pub use either_or_both::EitherOrBoth; -#[doc(hidden)] -pub mod free; -#[doc(inline)] -pub use free::*; -mod concat_impl; -mod cons_tuples_impl; -#[cfg(feature = "use_std")] -mod combinations; -#[cfg(feature = "use_std")] -mod combinations_with_replacement; -mod exactly_one_err; -mod diff; -mod format; -#[cfg(feature = "use_std")] -mod group_map; -#[cfg(feature = "use_std")] -mod groupbylazy; -mod intersperse; -#[cfg(feature = "use_std")] -mod kmerge_impl; -#[cfg(feature = "use_std")] -mod lazy_buffer; -mod merge_join; -mod minmax; -#[cfg(feature = "use_std")] -mod multipeek_impl; -mod pad_tail; -mod peeking_take_while; -#[cfg(feature = "use_std")] -mod permutations; -mod process_results_impl; -#[cfg(feature = "use_std")] -mod put_back_n_impl; -#[cfg(feature = "use_std")] -mod rciter_impl; -mod repeatn; -mod size_hint; -mod sources; -#[cfg(feature = "use_std")] -mod tee; -mod tuple_impl; -#[cfg(feature = "use_std")] -mod unique_impl; -mod with_position; -mod zip_eq_impl; -mod zip_longest; -mod ziptuple; - -#[macro_export] -/// Create an iterator over the “cartesian product” of iterators. -/// -/// Iterator element type is like `(A, B, ..., E)` if formed -/// from iterators `(I, J, ..., M)` with element types `I::Item = A`, `J::Item = B`, etc. -/// -/// ``` -/// #[macro_use] extern crate itertools; -/// # fn main() { -/// // Iterate over the coordinates of a 4 x 4 x 4 grid -/// // from (0, 0, 0), (0, 0, 1), .., (0, 1, 0), (0, 1, 1), .. etc until (3, 3, 3) -/// for (i, j, k) in iproduct!(0..4, 0..4, 0..4) { -/// // .. -/// } -/// # } -/// ``` -/// -/// **Note:** To enable the macros in this crate, use the `#[macro_use]` -/// attribute when importing the crate: -/// -/// ``` -/// #[macro_use] extern crate itertools; -/// # fn main() { } -/// ``` -macro_rules! iproduct { - (@flatten $I:expr,) => ( - $I - ); - (@flatten $I:expr, $J:expr, $($K:expr,)*) => ( - iproduct!(@flatten $crate::cons_tuples(iproduct!($I, $J)), $($K,)*) - ); - ($I:expr) => ( - $crate::__std_iter::IntoIterator::into_iter($I) - ); - ($I:expr, $J:expr) => ( - $crate::Itertools::cartesian_product(iproduct!($I), iproduct!($J)) - ); - ($I:expr, $J:expr, $($K:expr),+) => ( - iproduct!(@flatten iproduct!($I, $J), $($K,)+) - ); -} - -#[macro_export] -/// Create an iterator running multiple iterators in lockstep. -/// -/// The `izip!` iterator yields elements until any subiterator -/// returns `None`. -/// -/// This is a version of the standard ``.zip()`` that's supporting more than -/// two iterators. The iterator element type is a tuple with one element -/// from each of the input iterators. Just like ``.zip()``, the iteration stops -/// when the shortest of the inputs reaches its end. -/// -/// **Note:** The result of this macro is in the general case an iterator -/// composed of repeated `.zip()` and a `.map()`; it has an anonymous type. -/// The special cases of one and two arguments produce the equivalent of -/// `$a.into_iter()` and `$a.into_iter().zip($b)` respectively. -/// -/// Prefer this macro `izip!()` over [`multizip`] for the performance benefits -/// of using the standard library `.zip()`. -/// -/// [`multizip`]: fn.multizip.html -/// -/// ``` -/// #[macro_use] extern crate itertools; -/// # fn main() { -/// -/// // iterate over three sequences side-by-side -/// let mut results = [0, 0, 0, 0]; -/// let inputs = [3, 7, 9, 6]; -/// -/// for (r, index, input) in izip!(&mut results, 0..10, &inputs) { -/// *r = index * 10 + input; -/// } -/// -/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); -/// # } -/// ``` -/// -/// **Note:** To enable the macros in this crate, use the `#[macro_use]` -/// attribute when importing the crate: -/// -/// ``` -/// #[macro_use] extern crate itertools; -/// # fn main() { } -/// ``` -macro_rules! izip { - // @closure creates a tuple-flattening closure for .map() call. usage: - // @closure partial_pattern => partial_tuple , rest , of , iterators - // eg. izip!( @closure ((a, b), c) => (a, b, c) , dd , ee ) - ( @closure $p:pat => $tup:expr ) => { - |$p| $tup - }; - - // The "b" identifier is a different identifier on each recursion level thanks to hygiene. - ( @closure $p:pat => ( $($tup:tt)* ) , $_iter:expr $( , $tail:expr )* ) => { - izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*) - }; - - // unary - ($first:expr $(,)*) => { - $crate::__std_iter::IntoIterator::into_iter($first) - }; - - // binary - ($first:expr, $second:expr $(,)*) => { - izip!($first) - .zip($second) - }; - - // n-ary where n > 2 - ( $first:expr $( , $rest:expr )* $(,)* ) => { - izip!($first) - $( - .zip($rest) - )* - .map( - izip!(@closure a => (a) $( , $rest )*) - ) - }; -} - -/// An [`Iterator`] blanket implementation that provides extra adaptors and -/// methods. -/// -/// This trait defines a number of methods. They are divided into two groups: -/// -/// * *Adaptors* take an iterator and parameter as input, and return -/// a new iterator value. These are listed first in the trait. An example -/// of an adaptor is [`.interleave()`](#method.interleave) -/// -/// * *Regular methods* are those that don't return iterators and instead -/// return a regular value of some other kind. -/// [`.next_tuple()`](#method.next_tuple) is an example and the first regular -/// method in the list. -/// -/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html -pub trait Itertools : Iterator { - // adaptors - - /// Alternate elements from two iterators until both have run out. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (1..7).interleave(vec![-1, -2]); - /// itertools::assert_equal(it, vec![1, -1, 2, -2, 3, 4, 5, 6]); - /// ``` - fn interleave(self, other: J) -> Interleave - where J: IntoIterator, - Self: Sized - { - interleave(self, other) - } - - /// Alternate elements from two iterators until at least one of them has run - /// out. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (1..7).interleave_shortest(vec![-1, -2]); - /// itertools::assert_equal(it, vec![1, -1, 2, -2, 3]); - /// ``` - fn interleave_shortest(self, other: J) -> InterleaveShortest - where J: IntoIterator, - Self: Sized - { - adaptors::interleave_shortest(self, other.into_iter()) - } - - /// An iterator adaptor to insert a particular value - /// between each element of the adapted iterator. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// itertools::assert_equal((0..3).intersperse(8), vec![0, 8, 1, 8, 2]); - /// ``` - fn intersperse(self, element: Self::Item) -> Intersperse - where Self: Sized, - Self::Item: Clone - { - intersperse::intersperse(self, element) - } - - /// Create an iterator which iterates over both this and the specified - /// iterator simultaneously, yielding pairs of two optional elements. - /// - /// This iterator is *fused*. - /// - /// As long as neither input iterator is exhausted yet, it yields two values - /// via `EitherOrBoth::Both`. - /// - /// When the parameter iterator is exhausted, it only yields a value from the - /// `self` iterator via `EitherOrBoth::Left`. - /// - /// When the `self` iterator is exhausted, it only yields a value from the - /// parameter iterator via `EitherOrBoth::Right`. - /// - /// When both iterators return `None`, all further invocations of `.next()` - /// will return `None`. - /// - /// Iterator element type is - /// [`EitherOrBoth`](enum.EitherOrBoth.html). - /// - /// ```rust - /// use itertools::EitherOrBoth::{Both, Right}; - /// use itertools::Itertools; - /// let it = (0..1).zip_longest(1..3); - /// itertools::assert_equal(it, vec![Both(0, 1), Right(2)]); - /// ``` - #[inline] - fn zip_longest(self, other: J) -> ZipLongest - where J: IntoIterator, - Self: Sized - { - zip_longest::zip_longest(self, other.into_iter()) - } - - /// Create an iterator which iterates over both this and the specified - /// iterator simultaneously, yielding pairs of elements. - /// - /// **Panics** if the iterators reach an end and they are not of equal - /// lengths. - #[inline] - fn zip_eq(self, other: J) -> ZipEq - where J: IntoIterator, - Self: Sized - { - zip_eq(self, other) - } - - /// A “meta iterator adaptor”. Its closure receives a reference to the - /// iterator and may pick off as many elements as it likes, to produce the - /// next iterator element. - /// - /// Iterator element type is `B`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // An adaptor that gathers elements in pairs - /// let pit = (0..4).batching(|it| { - /// match it.next() { - /// None => None, - /// Some(x) => match it.next() { - /// None => None, - /// Some(y) => Some((x, y)), - /// } - /// } - /// }); - /// - /// itertools::assert_equal(pit, vec![(0, 1), (2, 3)]); - /// ``` - /// - fn batching(self, f: F) -> Batching - where F: FnMut(&mut Self) -> Option, - Self: Sized - { - adaptors::batching(self, f) - } - - /// Return an *iterable* that can group iterator elements. - /// Consecutive elements that map to the same key (“runs”), are assigned - /// to the same group. - /// - /// `GroupBy` is the storage for the lazy grouping operation. - /// - /// If the groups are consumed in order, or if each group's iterator is - /// dropped without keeping it around, then `GroupBy` uses no - /// allocations. It needs allocations only if several group iterators - /// are alive at the same time. - /// - /// This type implements `IntoIterator` (it is **not** an iterator - /// itself), because the group iterators need to borrow from this - /// value. It should be stored in a local variable or temporary and - /// iterated. - /// - /// Iterator element type is `(K, Group)`: the group's key and the - /// group iterator. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // group data into runs of larger than zero or not. - /// let data = vec![1, 3, -2, -2, 1, 0, 1, 2]; - /// // groups: |---->|------>|--------->| - /// - /// // Note: The `&` is significant here, `GroupBy` is iterable - /// // only by reference. You can also call `.into_iter()` explicitly. - /// for (key, group) in &data.into_iter().group_by(|elt| *elt >= 0) { - /// // Check that the sum of each group is +/- 4. - /// assert_eq!(4, group.sum::().abs()); - /// } - /// ``` - #[cfg(feature = "use_std")] - fn group_by(self, key: F) -> GroupBy - where Self: Sized, - F: FnMut(&Self::Item) -> K, - K: PartialEq, - { - groupbylazy::new(self, key) - } - - /// Return an *iterable* that can chunk the iterator. - /// - /// Yield subiterators (chunks) that each yield a fixed number elements, - /// determined by `size`. The last chunk will be shorter if there aren't - /// enough elements. - /// - /// `IntoChunks` is based on `GroupBy`: it is iterable (implements - /// `IntoIterator`, **not** `Iterator`), and it only buffers if several - /// chunk iterators are alive at the same time. - /// - /// Iterator element type is `Chunk`, each chunk's iterator. - /// - /// **Panics** if `size` is 0. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![1, 1, 2, -2, 6, 0, 3, 1]; - /// //chunk size=3 |------->|-------->|--->| - /// - /// // Note: The `&` is significant here, `IntoChunks` is iterable - /// // only by reference. You can also call `.into_iter()` explicitly. - /// for chunk in &data.into_iter().chunks(3) { - /// // Check that the sum of each chunk is 4. - /// assert_eq!(4, chunk.sum()); - /// } - /// ``` - #[cfg(feature = "use_std")] - fn chunks(self, size: usize) -> IntoChunks - where Self: Sized, - { - assert!(size != 0); - groupbylazy::new_chunks(self, size) - } - - /// Return an iterator over all contiguous windows producing tuples of - /// a specific size (up to 4). - /// - /// `tuple_windows` clones the iterator elements so that they can be - /// part of successive windows, this makes it most suited for iterators - /// of references and other values that are cheap to copy. - /// - /// ``` - /// use itertools::Itertools; - /// let mut v = Vec::new(); - /// for (a, b) in (1..5).tuple_windows() { - /// v.push((a, b)); - /// } - /// assert_eq!(v, vec![(1, 2), (2, 3), (3, 4)]); - /// - /// let mut it = (1..5).tuple_windows(); - /// assert_eq!(Some((1, 2, 3)), it.next()); - /// assert_eq!(Some((2, 3, 4)), it.next()); - /// assert_eq!(None, it.next()); - /// - /// // this requires a type hint - /// let it = (1..5).tuple_windows::<(_, _, _)>(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (2, 3, 4)]); - /// - /// // you can also specify the complete type - /// use itertools::TupleWindows; - /// use std::ops::Range; - /// - /// let it: TupleWindows, (u32, u32, u32)> = (1..5).tuple_windows(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (2, 3, 4)]); - /// ``` - fn tuple_windows(self) -> TupleWindows - where Self: Sized + Iterator, - T: tuple_impl::TupleCollect, - T::Item: Clone - { - tuple_impl::tuple_windows(self) - } - - /// Return an iterator that groups the items in tuples of a specific size - /// (up to 4). - /// - /// See also the method [`.next_tuple()`](#method.next_tuple). - /// - /// ``` - /// use itertools::Itertools; - /// let mut v = Vec::new(); - /// for (a, b) in (1..5).tuples() { - /// v.push((a, b)); - /// } - /// assert_eq!(v, vec![(1, 2), (3, 4)]); - /// - /// let mut it = (1..7).tuples(); - /// assert_eq!(Some((1, 2, 3)), it.next()); - /// assert_eq!(Some((4, 5, 6)), it.next()); - /// assert_eq!(None, it.next()); - /// - /// // this requires a type hint - /// let it = (1..7).tuples::<(_, _, _)>(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (4, 5, 6)]); - /// - /// // you can also specify the complete type - /// use itertools::Tuples; - /// use std::ops::Range; - /// - /// let it: Tuples, (u32, u32, u32)> = (1..7).tuples(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (4, 5, 6)]); - /// ``` - /// - /// See also [`Tuples::into_buffer`](structs/struct.Tuples.html#method.into_buffer). - fn tuples(self) -> Tuples - where Self: Sized + Iterator, - T: tuple_impl::TupleCollect - { - tuple_impl::tuples(self) - } - - /// Split into an iterator pair that both yield all elements from - /// the original iterator. - /// - /// **Note:** If the iterator is clonable, prefer using that instead - /// of using this method. It is likely to be more efficient. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// let xs = vec![0, 1, 2, 3]; - /// - /// let (mut t1, t2) = xs.into_iter().tee(); - /// itertools::assert_equal(t1.next(), Some(0)); - /// itertools::assert_equal(t2, 0..4); - /// itertools::assert_equal(t1, 1..4); - /// ``` - #[cfg(feature = "use_std")] - fn tee(self) -> (Tee, Tee) - where Self: Sized, - Self::Item: Clone - { - tee::new(self) - } - - /// Return an iterator adaptor that steps `n` elements in the base iterator - /// for each iteration. - /// - /// The iterator steps by yielding the next element from the base iterator, - /// then skipping forward `n - 1` elements. - /// - /// Iterator element type is `Self::Item`. - /// - /// **Panics** if the step is 0. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (0..8).step(3); - /// itertools::assert_equal(it, vec![0, 3, 6]); - /// ``` - #[deprecated(note="Use std .step_by() instead", since="0.8")] - #[allow(deprecated)] - fn step(self, n: usize) -> Step - where Self: Sized - { - adaptors::step(self, n) - } - - /// Convert each item of the iterator using the `Into` trait. - /// - /// ```rust - /// use itertools::Itertools; - /// - /// (1i32..42i32).map_into::().collect_vec(); - /// ``` - fn map_into(self) -> MapInto - where Self: Sized, - Self::Item: Into, - { - adaptors::map_into(self) - } - - /// Return an iterator adaptor that applies the provided closure - /// to every `Result::Ok` value. `Result::Err` values are - /// unchanged. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let input = vec![Ok(41), Err(false), Ok(11)]; - /// let it = input.into_iter().map_results(|i| i + 1); - /// itertools::assert_equal(it, vec![Ok(42), Err(false), Ok(12)]); - /// ``` - fn map_results(self, f: F) -> MapResults - where Self: Iterator> + Sized, - F: FnMut(T) -> U, - { - adaptors::map_results(self, f) - } - - /// Return an iterator adaptor that merges the two base iterators in - /// ascending order. If both base iterators are sorted (ascending), the - /// result is sorted. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let a = (0..11).step(3); - /// let b = (0..11).step(5); - /// let it = a.merge(b); - /// itertools::assert_equal(it, vec![0, 0, 3, 5, 6, 9, 10]); - /// ``` - fn merge(self, other: J) -> Merge - where Self: Sized, - Self::Item: PartialOrd, - J: IntoIterator - { - merge(self, other) - } - - /// Return an iterator adaptor that merges the two base iterators in order. - /// This is much like `.merge()` but allows for a custom ordering. - /// - /// This can be especially useful for sequences of tuples. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let a = (0..).zip("bc".chars()); - /// let b = (0..).zip("ad".chars()); - /// let it = a.merge_by(b, |x, y| x.1 <= y.1); - /// itertools::assert_equal(it, vec![(0, 'a'), (0, 'b'), (1, 'c'), (1, 'd')]); - /// ``` - - fn merge_by(self, other: J, is_first: F) -> MergeBy - where Self: Sized, - J: IntoIterator, - F: FnMut(&Self::Item, &Self::Item) -> bool - { - adaptors::merge_by_new(self, other.into_iter(), is_first) - } - - /// Create an iterator that merges items from both this and the specified - /// iterator in ascending order. - /// - /// It chooses whether to pair elements based on the `Ordering` returned by the - /// specified compare function. At any point, inspecting the tip of the - /// iterators `I` and `J` as items `i` of type `I::Item` and `j` of type - /// `J::Item` respectively, the resulting iterator will: - /// - /// - Emit `EitherOrBoth::Left(i)` when `i < j`, - /// and remove `i` from its source iterator - /// - Emit `EitherOrBoth::Right(j)` when `i > j`, - /// and remove `j` from its source iterator - /// - Emit `EitherOrBoth::Both(i, j)` when `i == j`, - /// and remove both `i` and `j` from their respective source iterators - /// - /// ``` - /// use itertools::Itertools; - /// use itertools::EitherOrBoth::{Left, Right, Both}; - /// - /// let ki = (0..10).step(3); - /// let ku = (0..10).step(5); - /// let ki_ku = ki.merge_join_by(ku, |i, j| i.cmp(j)).map(|either| { - /// match either { - /// Left(_) => "Ki", - /// Right(_) => "Ku", - /// Both(_, _) => "KiKu" - /// } - /// }); - /// - /// itertools::assert_equal(ki_ku, vec!["KiKu", "Ki", "Ku", "Ki", "Ki"]); - /// ``` - #[inline] - fn merge_join_by(self, other: J, cmp_fn: F) -> MergeJoinBy - where J: IntoIterator, - F: FnMut(&Self::Item, &J::Item) -> std::cmp::Ordering, - Self: Sized - { - merge_join_by(self, other, cmp_fn) - } - - - /// Return an iterator adaptor that flattens an iterator of iterators by - /// merging them in ascending order. - /// - /// If all base iterators are sorted (ascending), the result is sorted. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let a = (0..6).step(3); - /// let b = (1..6).step(3); - /// let c = (2..6).step(3); - /// let it = vec![a, b, c].into_iter().kmerge(); - /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5]); - /// ``` - #[cfg(feature = "use_std")] - fn kmerge(self) -> KMerge<::IntoIter> - where Self: Sized, - Self::Item: IntoIterator, - ::Item: PartialOrd, - { - kmerge(self) - } - - /// Return an iterator adaptor that flattens an iterator of iterators by - /// merging them according to the given closure. - /// - /// The closure `first` is called with two elements *a*, *b* and should - /// return `true` if *a* is ordered before *b*. - /// - /// If all base iterators are sorted according to `first`, the result is - /// sorted. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let a = vec![-1f64, 2., 3., -5., 6., -7.]; - /// let b = vec![0., 2., -4.]; - /// let mut it = vec![a, b].into_iter().kmerge_by(|a, b| a.abs() < b.abs()); - /// assert_eq!(it.next(), Some(0.)); - /// assert_eq!(it.last(), Some(-7.)); - /// ``` - #[cfg(feature = "use_std")] - fn kmerge_by(self, first: F) - -> KMergeBy<::IntoIter, F> - where Self: Sized, - Self::Item: IntoIterator, - F: FnMut(&::Item, - &::Item) -> bool - { - kmerge_by(self, first) - } - - /// Return an iterator adaptor that iterates over the cartesian product of - /// the element sets of two iterators `self` and `J`. - /// - /// Iterator element type is `(Self::Item, J::Item)`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (0..2).cartesian_product("αβ".chars()); - /// itertools::assert_equal(it, vec![(0, 'α'), (0, 'β'), (1, 'α'), (1, 'β')]); - /// ``` - fn cartesian_product(self, other: J) -> Product - where Self: Sized, - Self::Item: Clone, - J: IntoIterator, - J::IntoIter: Clone - { - adaptors::cartesian_product(self, other.into_iter()) - } - - /// Return an iterator adaptor that iterates over the cartesian product of - /// all subiterators returned by meta-iterator `self`. - /// - /// All provided iterators must yield the same `Item` type. To generate - /// the product of iterators yielding multiple types, use the - /// [`iproduct`](macro.iproduct.html) macro instead. - /// - /// - /// The iterator element type is `Vec`, where `T` is the iterator element - /// of the subiterators. - /// - /// ``` - /// use itertools::Itertools; - /// let mut multi_prod = (0..3).map(|i| (i * 2)..(i * 2 + 2)) - /// .multi_cartesian_product(); - /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 4])); - /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 5])); - /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 4])); - /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 5])); - /// assert_eq!(multi_prod.next(), Some(vec![1, 2, 4])); - /// assert_eq!(multi_prod.next(), Some(vec![1, 2, 5])); - /// assert_eq!(multi_prod.next(), Some(vec![1, 3, 4])); - /// assert_eq!(multi_prod.next(), Some(vec![1, 3, 5])); - /// assert_eq!(multi_prod.next(), None); - /// ``` - #[cfg(feature = "use_std")] - fn multi_cartesian_product(self) -> MultiProduct<::IntoIter> - where Self: Iterator + Sized, - Self::Item: IntoIterator, - ::IntoIter: Clone, - ::Item: Clone - { - adaptors::multi_cartesian_product(self) - } - - /// Return an iterator adaptor that uses the passed-in closure to - /// optionally merge together consecutive elements. - /// - /// The closure `f` is passed two elements, `previous` and `current` and may - /// return either (1) `Ok(combined)` to merge the two values or - /// (2) `Err((previous', current'))` to indicate they can't be merged. - /// In (2), the value `previous'` is emitted by the iterator. - /// Either (1) `combined` or (2) `current'` becomes the previous value - /// when coalesce continues with the next pair of elements to merge. The - /// value that remains at the end is also emitted by the iterator. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // sum same-sign runs together - /// let data = vec![-1., -2., -3., 3., 1., 0., -1.]; - /// itertools::assert_equal(data.into_iter().coalesce(|x, y| - /// if (x >= 0.) == (y >= 0.) { - /// Ok(x + y) - /// } else { - /// Err((x, y)) - /// }), - /// vec![-6., 4., -1.]); - /// ``` - fn coalesce(self, f: F) -> Coalesce - where Self: Sized, - F: FnMut(Self::Item, Self::Item) - -> Result - { - adaptors::coalesce(self, f) - } - - /// Remove duplicates from sections of consecutive identical elements. - /// If the iterator is sorted, all elements will be unique. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![1., 1., 2., 3., 3., 2., 2.]; - /// itertools::assert_equal(data.into_iter().dedup(), - /// vec![1., 2., 3., 2.]); - /// ``` - fn dedup(self) -> Dedup - where Self: Sized, - Self::Item: PartialEq, - { - adaptors::dedup(self) - } - - /// Remove duplicates from sections of consecutive identical elements, - /// determining equality using a comparison function. - /// If the iterator is sorted, all elements will be unique. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![(0, 1.), (1, 1.), (0, 2.), (0, 3.), (1, 3.), (1, 2.), (2, 2.)]; - /// itertools::assert_equal(data.into_iter().dedup_by(|x, y| x.1==y.1), - /// vec![(0, 1.), (0, 2.), (0, 3.), (1, 2.)]); - /// ``` - fn dedup_by(self, cmp: Cmp) -> DedupBy - where Self: Sized, - Cmp: FnMut(&Self::Item, &Self::Item)->bool, - { - adaptors::dedup_by(self, cmp) - } - - /// Return an iterator adaptor that filters out elements that have - /// already been produced once during the iteration. Duplicates - /// are detected using hash and equality. - /// - /// Clones of visited elements are stored in a hash set in the - /// iterator. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![10, 20, 30, 20, 40, 10, 50]; - /// itertools::assert_equal(data.into_iter().unique(), - /// vec![10, 20, 30, 40, 50]); - /// ``` - #[cfg(feature = "use_std")] - fn unique(self) -> Unique - where Self: Sized, - Self::Item: Clone + Eq + Hash - { - unique_impl::unique(self) - } - - /// Return an iterator adaptor that filters out elements that have - /// already been produced once during the iteration. - /// - /// Duplicates are detected by comparing the key they map to - /// with the keying function `f` by hash and equality. - /// The keys are stored in a hash set in the iterator. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec!["a", "bb", "aa", "c", "ccc"]; - /// itertools::assert_equal(data.into_iter().unique_by(|s| s.len()), - /// vec!["a", "bb", "ccc"]); - /// ``` - #[cfg(feature = "use_std")] - fn unique_by(self, f: F) -> UniqueBy - where Self: Sized, - V: Eq + Hash, - F: FnMut(&Self::Item) -> V - { - unique_impl::unique_by(self, f) - } - - /// Return an iterator adaptor that borrows from this iterator and - /// takes items while the closure `accept` returns `true`. - /// - /// This adaptor can only be used on iterators that implement `PeekingNext` - /// like `.peekable()`, `put_back` and a few other collection iterators. - /// - /// The last and rejected element (first `false`) is still available when - /// `peeking_take_while` is done. - /// - /// - /// See also [`.take_while_ref()`](#method.take_while_ref) - /// which is a similar adaptor. - fn peeking_take_while(&mut self, accept: F) -> PeekingTakeWhile - where Self: Sized + PeekingNext, - F: FnMut(&Self::Item) -> bool, - { - peeking_take_while::peeking_take_while(self, accept) - } - - /// Return an iterator adaptor that borrows from a `Clone`-able iterator - /// to only pick off elements while the predicate `accept` returns `true`. - /// - /// It uses the `Clone` trait to restore the original iterator so that the - /// last and rejected element (first `false`) is still available when - /// `take_while_ref` is done. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut hexadecimals = "0123456789abcdef".chars(); - /// - /// let decimals = hexadecimals.take_while_ref(|c| c.is_numeric()) - /// .collect::(); - /// assert_eq!(decimals, "0123456789"); - /// assert_eq!(hexadecimals.next(), Some('a')); - /// - /// ``` - fn take_while_ref(&mut self, accept: F) -> TakeWhileRef - where Self: Clone, - F: FnMut(&Self::Item) -> bool - { - adaptors::take_while_ref(self, accept) - } - - /// Return an iterator adaptor that filters `Option` iterator elements - /// and produces `A`. Stops on the first `None` encountered. - /// - /// Iterator element type is `A`, the unwrapped element. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // List all hexadecimal digits - /// itertools::assert_equal( - /// (0..).map(|i| std::char::from_digit(i, 16)).while_some(), - /// "0123456789abcdef".chars()); - /// - /// ``` - fn while_some(self) -> WhileSome - where Self: Sized + Iterator> - { - adaptors::while_some(self) - } - - /// Return an iterator adaptor that iterates over the combinations of the - /// elements from an iterator. - /// - /// Iterator element can be any homogeneous tuple of type `Self::Item` with - /// size up to 4. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut v = Vec::new(); - /// for (a, b) in (1..5).tuple_combinations() { - /// v.push((a, b)); - /// } - /// assert_eq!(v, vec![(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]); - /// - /// let mut it = (1..5).tuple_combinations(); - /// assert_eq!(Some((1, 2, 3)), it.next()); - /// assert_eq!(Some((1, 2, 4)), it.next()); - /// assert_eq!(Some((1, 3, 4)), it.next()); - /// assert_eq!(Some((2, 3, 4)), it.next()); - /// assert_eq!(None, it.next()); - /// - /// // this requires a type hint - /// let it = (1..5).tuple_combinations::<(_, _, _)>(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]); - /// - /// // you can also specify the complete type - /// use itertools::TupleCombinations; - /// use std::ops::Range; - /// - /// let it: TupleCombinations, (u32, u32, u32)> = (1..5).tuple_combinations(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]); - /// ``` - fn tuple_combinations(self) -> TupleCombinations - where Self: Sized + Clone, - Self::Item: Clone, - T: adaptors::HasCombination, - { - adaptors::tuple_combinations(self) - } - - /// Return an iterator adaptor that iterates over the `k`-length combinations of - /// the elements from an iterator. - /// - /// Iterator element type is `Vec`. The iterator produces a new Vec per iteration, - /// and clones the iterator elements. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (1..5).combinations(3); - /// itertools::assert_equal(it, vec![ - /// vec![1, 2, 3], - /// vec![1, 2, 4], - /// vec![1, 3, 4], - /// vec![2, 3, 4], - /// ]); - /// ``` - /// - /// Note: Combinations does not take into account the equality of the iterated values. - /// ``` - /// use itertools::Itertools; - /// - /// let it = vec![1, 2, 2].into_iter().combinations(2); - /// itertools::assert_equal(it, vec![ - /// vec![1, 2], // Note: these are the same - /// vec![1, 2], // Note: these are the same - /// vec![2, 2], - /// ]); - /// ``` - #[cfg(feature = "use_std")] - fn combinations(self, k: usize) -> Combinations - where Self: Sized, - Self::Item: Clone - { - combinations::combinations(self, k) - } - - /// Return an iterator that iterates over the `k`-length combinations of - /// the elements from an iterator, with replacement. - /// - /// Iterator element type is `Vec`. The iterator produces a new Vec per iteration, - /// and clones the iterator elements. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (1..4).combinations_with_replacement(2); - /// itertools::assert_equal(it, vec![ - /// vec![1, 1], - /// vec![1, 2], - /// vec![1, 3], - /// vec![2, 2], - /// vec![2, 3], - /// vec![3, 3], - /// ]); - /// ``` - #[cfg(feature = "use_std")] - fn combinations_with_replacement(self, k: usize) -> CombinationsWithReplacement - where - Self: Sized, - Self::Item: Clone, - { - combinations_with_replacement::combinations_with_replacement(self, k) - } - - /// Return an iterator adaptor that iterates over all k-permutations of the - /// elements from an iterator. - /// - /// Iterator element type is `Vec` with length `k`. The iterator - /// produces a new Vec per iteration, and clones the iterator elements. - /// - /// If `k` is greater than the length of the input iterator, the resultant - /// iterator adaptor will be empty. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let perms = (5..8).permutations(2); - /// itertools::assert_equal(perms, vec![ - /// vec![5, 6], - /// vec![5, 7], - /// vec![6, 5], - /// vec![6, 7], - /// vec![7, 5], - /// vec![7, 6], - /// ]); - /// ``` - /// - /// Note: Permutations does not take into account the equality of the iterated values. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = vec![2, 2].into_iter().permutations(2); - /// itertools::assert_equal(it, vec![ - /// vec![2, 2], // Note: these are the same - /// vec![2, 2], // Note: these are the same - /// ]); - /// ``` - /// - /// Note: The source iterator is collected lazily, and will not be - /// re-iterated if the permutations adaptor is completed and re-iterated. - #[cfg(feature = "use_std")] - fn permutations(self, k: usize) -> Permutations - where Self: Sized, - Self::Item: Clone - { - permutations::permutations(self, k) - } - - /// Return an iterator adaptor that pads the sequence to a minimum length of - /// `min` by filling missing elements using a closure `f`. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (0..5).pad_using(10, |i| 2*i); - /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 10, 12, 14, 16, 18]); - /// - /// let it = (0..10).pad_using(5, |i| 2*i); - /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - /// - /// let it = (0..5).pad_using(10, |i| 2*i).rev(); - /// itertools::assert_equal(it, vec![18, 16, 14, 12, 10, 4, 3, 2, 1, 0]); - /// ``` - fn pad_using(self, min: usize, f: F) -> PadUsing - where Self: Sized, - F: FnMut(usize) -> Self::Item - { - pad_tail::pad_using(self, min, f) - } - - /// Return an iterator adaptor that wraps each element in a `Position` to - /// ease special-case handling of the first or last elements. - /// - /// Iterator element type is - /// [`Position`](enum.Position.html) - /// - /// ``` - /// use itertools::{Itertools, Position}; - /// - /// let it = (0..4).with_position(); - /// itertools::assert_equal(it, - /// vec![Position::First(0), - /// Position::Middle(1), - /// Position::Middle(2), - /// Position::Last(3)]); - /// - /// let it = (0..1).with_position(); - /// itertools::assert_equal(it, vec![Position::Only(0)]); - /// ``` - fn with_position(self) -> WithPosition - where Self: Sized, - { - with_position::with_position(self) - } - - /// Return an iterator adaptor that yields the indices of all elements - /// satisfying a predicate, counted from the start of the iterator. - /// - /// Equivalent to `iter.enumerate().filter(|(_, v)| predicate(v)).map(|(i, _)| i)`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![1, 2, 3, 3, 4, 6, 7, 9]; - /// itertools::assert_equal(data.iter().positions(|v| v % 2 == 0), vec![1, 4, 5]); - /// - /// itertools::assert_equal(data.iter().positions(|v| v % 2 == 1).rev(), vec![7, 6, 3, 2, 0]); - /// ``` - fn positions

    (self, predicate: P) -> Positions - where Self: Sized, - P: FnMut(Self::Item) -> bool, - { - adaptors::positions(self, predicate) - } - - /// Return an iterator adaptor that applies a mutating function - /// to each element before yielding it. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let input = vec![vec![1], vec![3, 2, 1]]; - /// let it = input.into_iter().update(|mut v| v.push(0)); - /// itertools::assert_equal(it, vec![vec![1, 0], vec![3, 2, 1, 0]]); - /// ``` - fn update(self, updater: F) -> Update - where Self: Sized, - F: FnMut(&mut Self::Item), - { - adaptors::update(self, updater) - } - - // non-adaptor methods - /// Advances the iterator and returns the next items grouped in a tuple of - /// a specific size (up to 4). - /// - /// If there are enough elements to be grouped in a tuple, then the tuple is - /// returned inside `Some`, otherwise `None` is returned. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut iter = 1..5; - /// - /// assert_eq!(Some((1, 2)), iter.next_tuple()); - /// ``` - fn next_tuple(&mut self) -> Option - where Self: Sized + Iterator, - T: tuple_impl::TupleCollect - { - T::collect_from_iter_no_buf(self) - } - - /// Collects all items from the iterator into a tuple of a specific size - /// (up to 4). - /// - /// If the number of elements inside the iterator is **exactly** equal to - /// the tuple size, then the tuple is returned inside `Some`, otherwise - /// `None` is returned. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let iter = 1..3; - /// - /// if let Some((x, y)) = iter.collect_tuple() { - /// assert_eq!((x, y), (1, 2)) - /// } else { - /// panic!("Expected two elements") - /// } - /// ``` - fn collect_tuple(mut self) -> Option - where Self: Sized + Iterator, - T: tuple_impl::TupleCollect - { - match self.next_tuple() { - elt @ Some(_) => match self.next() { - Some(_) => None, - None => elt, - }, - _ => None - } - } - - - /// Find the position and value of the first element satisfying a predicate. - /// - /// The iterator is not advanced past the first element found. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let text = "Hα"; - /// assert_eq!(text.chars().find_position(|ch| ch.is_lowercase()), Some((1, 'α'))); - /// ``` - fn find_position

    (&mut self, mut pred: P) -> Option<(usize, Self::Item)> - where P: FnMut(&Self::Item) -> bool - { - let mut index = 0usize; - for elt in self { - if pred(&elt) { - return Some((index, elt)); - } - index += 1; - } - None - } - - /// Check whether all elements compare equal. - /// - /// Empty iterators are considered to have equal elements: - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5]; - /// assert!(!data.iter().all_equal()); - /// assert!(data[0..3].iter().all_equal()); - /// assert!(data[3..5].iter().all_equal()); - /// assert!(data[5..8].iter().all_equal()); - /// - /// let data : Option = None; - /// assert!(data.into_iter().all_equal()); - /// ``` - fn all_equal(&mut self) -> bool - where Self: Sized, - Self::Item: PartialEq, - { - match self.next() { - None => true, - Some(a) => self.all(|x| a == x), - } - } - - /// Consume the first `n` elements from the iterator eagerly, - /// and return the same iterator again. - /// - /// It works similarly to *.skip(* `n` *)* except it is eager and - /// preserves the iterator type. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut iter = "αβγ".chars().dropping(2); - /// itertools::assert_equal(iter, "γ".chars()); - /// ``` - /// - /// *Fusing notes: if the iterator is exhausted by dropping, - /// the result of calling `.next()` again depends on the iterator implementation.* - fn dropping(mut self, n: usize) -> Self - where Self: Sized - { - if n > 0 { - self.nth(n - 1); - } - self - } - - /// Consume the last `n` elements from the iterator eagerly, - /// and return the same iterator again. - /// - /// This is only possible on double ended iterators. `n` may be - /// larger than the number of elements. - /// - /// Note: This method is eager, dropping the back elements immediately and - /// preserves the iterator type. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let init = vec![0, 3, 6, 9].into_iter().dropping_back(1); - /// itertools::assert_equal(init, vec![0, 3, 6]); - /// ``` - fn dropping_back(mut self, n: usize) -> Self - where Self: Sized, - Self: DoubleEndedIterator - { - if n > 0 { - (&mut self).rev().nth(n - 1); - } - self - } - - /// Run the closure `f` eagerly on each element of the iterator. - /// - /// Consumes the iterator until its end. - /// - /// ``` - /// use std::sync::mpsc::channel; - /// use itertools::Itertools; - /// - /// let (tx, rx) = channel(); - /// - /// // use .foreach() to apply a function to each value -- sending it - /// (0..5).map(|x| x * 2 + 1).foreach(|x| { tx.send(x).unwrap(); } ); - /// - /// drop(tx); - /// - /// itertools::assert_equal(rx.iter(), vec![1, 3, 5, 7, 9]); - /// ``` - #[deprecated(note="Use .for_each() instead", since="0.8")] - fn foreach(self, f: F) - where F: FnMut(Self::Item), - Self: Sized, - { - self.for_each(f) - } - - /// Combine all an iterator's elements into one element by using `Extend`. - /// - /// This combinator will extend the first item with each of the rest of the - /// items of the iterator. If the iterator is empty, the default value of - /// `I::Item` is returned. - /// - /// ```rust - /// use itertools::Itertools; - /// - /// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]]; - /// assert_eq!(input.into_iter().concat(), - /// vec![1, 2, 3, 4, 5, 6]); - /// ``` - fn concat(self) -> Self::Item - where Self: Sized, - Self::Item: Extend<<::Item as IntoIterator>::Item> + IntoIterator + Default - { - concat(self) - } - - /// `.collect_vec()` is simply a type specialization of `.collect()`, - /// for convenience. - #[cfg(feature = "use_std")] - fn collect_vec(self) -> Vec - where Self: Sized - { - self.collect() - } - - /// Assign to each reference in `self` from the `from` iterator, - /// stopping at the shortest of the two iterators. - /// - /// The `from` iterator is queried for its next element before the `self` - /// iterator, and if either is exhausted the method is done. - /// - /// Return the number of elements written. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut xs = [0; 4]; - /// xs.iter_mut().set_from(1..); - /// assert_eq!(xs, [1, 2, 3, 4]); - /// ``` - #[inline] - fn set_from<'a, A: 'a, J>(&mut self, from: J) -> usize - where Self: Iterator, - J: IntoIterator - { - let mut count = 0; - for elt in from { - match self.next() { - None => break, - Some(ptr) => *ptr = elt, - } - count += 1; - } - count - } - - /// Combine all iterator elements into one String, separated by `sep`. - /// - /// Use the `Display` implementation of each element. - /// - /// ``` - /// use itertools::Itertools; - /// - /// assert_eq!(["a", "b", "c"].iter().join(", "), "a, b, c"); - /// assert_eq!([1, 2, 3].iter().join(", "), "1, 2, 3"); - /// ``` - #[cfg(feature = "use_std")] - fn join(&mut self, sep: &str) -> String - where Self::Item: std::fmt::Display - { - match self.next() { - None => String::new(), - Some(first_elt) => { - // estimate lower bound of capacity needed - let (lower, _) = self.size_hint(); - let mut result = String::with_capacity(sep.len() * lower); - write!(&mut result, "{}", first_elt).unwrap(); - for elt in self { - result.push_str(sep); - write!(&mut result, "{}", elt).unwrap(); - } - result - } - } - } - - /// Format all iterator elements, separated by `sep`. - /// - /// All elements are formatted (any formatting trait) - /// with `sep` inserted between each element. - /// - /// **Panics** if the formatter helper is formatted more than once. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = [1.1, 2.71828, -3.]; - /// assert_eq!( - /// format!("{:.2}", data.iter().format(", ")), - /// "1.10, 2.72, -3.00"); - /// ``` - fn format(self, sep: &str) -> Format - where Self: Sized, - { - format::new_format_default(self, sep) - } - - /// Format all iterator elements, separated by `sep`. - /// - /// This is a customizable version of `.format()`. - /// - /// The supplied closure `format` is called once per iterator element, - /// with two arguments: the element and a callback that takes a - /// `&Display` value, i.e. any reference to type that implements `Display`. - /// - /// Using `&format_args!(...)` is the most versatile way to apply custom - /// element formatting. The callback can be called multiple times if needed. - /// - /// **Panics** if the formatter helper is formatted more than once. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = [1.1, 2.71828, -3.]; - /// let data_formatter = data.iter().format_with(", ", |elt, f| f(&format_args!("{:.2}", elt))); - /// assert_eq!(format!("{}", data_formatter), - /// "1.10, 2.72, -3.00"); - /// - /// // .format_with() is recursively composable - /// let matrix = [[1., 2., 3.], - /// [4., 5., 6.]]; - /// let matrix_formatter = matrix.iter().format_with("\n", |row, f| { - /// f(&row.iter().format_with(", ", |elt, g| g(&elt))) - /// }); - /// assert_eq!(format!("{}", matrix_formatter), - /// "1, 2, 3\n4, 5, 6"); - /// - /// - /// ``` - fn format_with(self, sep: &str, format: F) -> FormatWith - where Self: Sized, - F: FnMut(Self::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result, - { - format::new_format(self, sep, format) - } - - /// Fold `Result` values from an iterator. - /// - /// Only `Ok` values are folded. If no error is encountered, the folded - /// value is returned inside `Ok`. Otherwise, the operation terminates - /// and returns the first `Err` value it encounters. No iterator elements are - /// consumed after the first error. - /// - /// The first accumulator value is the `start` parameter. - /// Each iteration passes the accumulator value and the next value inside `Ok` - /// to the fold function `f` and its return value becomes the new accumulator value. - /// - /// For example the sequence *Ok(1), Ok(2), Ok(3)* will result in a - /// computation like this: - /// - /// ```ignore - /// let mut accum = start; - /// accum = f(accum, 1); - /// accum = f(accum, 2); - /// accum = f(accum, 3); - /// ``` - /// - /// With a `start` value of 0 and an addition as folding function, - /// this effectively results in *((0 + 1) + 2) + 3* - /// - /// ``` - /// use std::ops::Add; - /// use itertools::Itertools; - /// - /// let values = [1, 2, -2, -1, 2, 1]; - /// assert_eq!( - /// values.iter() - /// .map(Ok::<_, ()>) - /// .fold_results(0, Add::add), - /// Ok(3) - /// ); - /// assert!( - /// values.iter() - /// .map(|&x| if x >= 0 { Ok(x) } else { Err("Negative number") }) - /// .fold_results(0, Add::add) - /// .is_err() - /// ); - /// ``` - fn fold_results(&mut self, mut start: B, mut f: F) -> Result - where Self: Iterator>, - F: FnMut(B, A) -> B - { - for elt in self { - match elt { - Ok(v) => start = f(start, v), - Err(u) => return Err(u), - } - } - Ok(start) - } - - /// Fold `Option` values from an iterator. - /// - /// Only `Some` values are folded. If no `None` is encountered, the folded - /// value is returned inside `Some`. Otherwise, the operation terminates - /// and returns `None`. No iterator elements are consumed after the `None`. - /// - /// This is the `Option` equivalent to `fold_results`. - /// - /// ``` - /// use std::ops::Add; - /// use itertools::Itertools; - /// - /// let mut values = vec![Some(1), Some(2), Some(-2)].into_iter(); - /// assert_eq!(values.fold_options(5, Add::add), Some(5 + 1 + 2 - 2)); - /// - /// let mut more_values = vec![Some(2), None, Some(0)].into_iter(); - /// assert!(more_values.fold_options(0, Add::add).is_none()); - /// assert_eq!(more_values.next().unwrap(), Some(0)); - /// ``` - fn fold_options(&mut self, mut start: B, mut f: F) -> Option - where Self: Iterator>, - F: FnMut(B, A) -> B - { - for elt in self { - match elt { - Some(v) => start = f(start, v), - None => return None, - } - } - Some(start) - } - - /// Accumulator of the elements in the iterator. - /// - /// Like `.fold()`, without a base case. If the iterator is - /// empty, return `None`. With just one element, return it. - /// Otherwise elements are accumulated in sequence using the closure `f`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// assert_eq!((0..10).fold1(|x, y| x + y).unwrap_or(0), 45); - /// assert_eq!((0..0).fold1(|x, y| x * y), None); - /// ``` - fn fold1(mut self, f: F) -> Option - where F: FnMut(Self::Item, Self::Item) -> Self::Item, - Self: Sized, - { - self.next().map(move |x| self.fold(x, f)) - } - - /// Accumulate the elements in the iterator in a tree-like manner. - /// - /// You can think of it as, while there's more than one item, repeatedly - /// combining adjacent items. It does so in bottom-up-merge-sort order, - /// however, so that it needs only logarithmic stack space. - /// - /// This produces a call tree like the following (where the calls under - /// an item are done after reading that item): - /// - /// ```text - /// 1 2 3 4 5 6 7 - /// │ │ │ │ │ │ │ - /// └─f └─f └─f │ - /// │ │ │ │ - /// └───f └─f - /// │ │ - /// └─────f - /// ``` - /// - /// Which, for non-associative functions, will typically produce a different - /// result than the linear call tree used by `fold1`: - /// - /// ```text - /// 1 2 3 4 5 6 7 - /// │ │ │ │ │ │ │ - /// └─f─f─f─f─f─f - /// ``` - /// - /// If `f` is associative, prefer the normal `fold1` instead. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // The same tree as above - /// let num_strings = (1..8).map(|x| x.to_string()); - /// assert_eq!(num_strings.tree_fold1(|x, y| format!("f({}, {})", x, y)), - /// Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))"))); - /// - /// // Like fold1, an empty iterator produces None - /// assert_eq!((0..0).tree_fold1(|x, y| x * y), None); - /// - /// // tree_fold1 matches fold1 for associative operations... - /// assert_eq!((0..10).tree_fold1(|x, y| x + y), - /// (0..10).fold1(|x, y| x + y)); - /// // ...but not for non-associative ones - /// assert_ne!((0..10).tree_fold1(|x, y| x - y), - /// (0..10).fold1(|x, y| x - y)); - /// ``` - fn tree_fold1(mut self, mut f: F) -> Option - where F: FnMut(Self::Item, Self::Item) -> Self::Item, - Self: Sized, - { - type State = Result>; - - fn inner0(it: &mut II, f: &mut FF) -> State - where - II: Iterator, - FF: FnMut(T, T) -> T - { - // This function could be replaced with `it.next().ok_or(None)`, - // but half the useful tree_fold1 work is combining adjacent items, - // so put that in a form that LLVM is more likely to optimize well. - - let a = - if let Some(v) = it.next() { v } - else { return Err(None) }; - let b = - if let Some(v) = it.next() { v } - else { return Err(Some(a)) }; - Ok(f(a, b)) - } - - fn inner(stop: usize, it: &mut II, f: &mut FF) -> State - where - II: Iterator, - FF: FnMut(T, T) -> T - { - let mut x = try!(inner0(it, f)); - for height in 0..stop { - // Try to get another tree the same size with which to combine it, - // creating a new tree that's twice as big for next time around. - let next = - if height == 0 { - inner0(it, f) - } else { - inner(height, it, f) - }; - match next { - Ok(y) => x = f(x, y), - - // If we ran out of items, combine whatever we did manage - // to get. It's better combined with the current value - // than something in a parent frame, because the tree in - // the parent is always as least as big as this one. - Err(None) => return Err(Some(x)), - Err(Some(y)) => return Err(Some(f(x, y))), - } - } - Ok(x) - } - - match inner(usize::max_value(), &mut self, &mut f) { - Err(x) => x, - _ => unreachable!(), - } - } - - /// An iterator method that applies a function, producing a single, final value. - /// - /// `fold_while()` is basically equivalent to `fold()` but with additional support for - /// early exit via short-circuiting. - /// - /// ``` - /// use itertools::Itertools; - /// use itertools::FoldWhile::{Continue, Done}; - /// - /// let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - /// - /// let mut result = 0; - /// - /// // for loop: - /// for i in &numbers { - /// if *i > 5 { - /// break; - /// } - /// result = result + i; - /// } - /// - /// // fold: - /// let result2 = numbers.iter().fold(0, |acc, x| { - /// if *x > 5 { acc } else { acc + x } - /// }); - /// - /// // fold_while: - /// let result3 = numbers.iter().fold_while(0, |acc, x| { - /// if *x > 5 { Done(acc) } else { Continue(acc + x) } - /// }).into_inner(); - /// - /// // they're the same - /// assert_eq!(result, result2); - /// assert_eq!(result2, result3); - /// ``` - /// - /// The big difference between the computations of `result2` and `result3` is that while - /// `fold()` called the provided closure for every item of the callee iterator, - /// `fold_while()` actually stopped iterating as soon as it encountered `Fold::Done(_)`. - #[deprecated(note="Use .try_fold() instead", since="0.8")] - fn fold_while(&mut self, init: B, mut f: F) -> FoldWhile - where Self: Sized, - F: FnMut(B, Self::Item) -> FoldWhile - { - let mut acc = init; - while let Some(item) = self.next() { - match f(acc, item) { - FoldWhile::Continue(res) => acc = res, - res @ FoldWhile::Done(_) => return res, - } - } - FoldWhile::Continue(acc) - } - - /// Iterate over the entire iterator and add all the elements. - /// - /// An empty iterator returns `None`, otherwise `Some(sum)`. - /// - /// # Panics - /// - /// When calling `sum1()` and a primitive integer type is being returned, this - /// method will panic if the computation overflows and debug assertions are - /// enabled. - /// - /// # Examples - /// - /// ``` - /// use itertools::Itertools; - /// - /// let empty_sum = (1..1).sum1::(); - /// assert_eq!(empty_sum, None); - /// - /// let nonempty_sum = (1..11).sum1::(); - /// assert_eq!(nonempty_sum, Some(55)); - /// ``` - fn sum1(mut self) -> Option - where Self: Sized, - S: std::iter::Sum, - { - self.next() - .map(|first| once(first).chain(self).sum()) - } - - /// Iterate over the entire iterator and multiply all the elements. - /// - /// An empty iterator returns `None`, otherwise `Some(product)`. - /// - /// # Panics - /// - /// When calling `product1()` and a primitive integer type is being returned, - /// method will panic if the computation overflows and debug assertions are - /// enabled. - /// - /// # Examples - /// ``` - /// use itertools::Itertools; - /// - /// let empty_product = (1..1).product1::(); - /// assert_eq!(empty_product, None); - /// - /// let nonempty_product = (1..11).product1::(); - /// assert_eq!(nonempty_product, Some(3628800)); - /// ``` - fn product1

    (mut self) -> Option

    - where Self: Sized, - P: std::iter::Product, - { - self.next() - .map(|first| once(first).chain(self).product()) - } - - - /// Sort all iterator elements into a new iterator in ascending order. - /// - /// **Note:** This consumes the entire iterator, uses the - /// `slice::sort()` method and returns the result as a new - /// iterator that owns its elements. - /// - /// The sorted iterator, if directly collected to a `Vec`, is converted - /// without any extra copying or allocation cost. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // sort the letters of the text in ascending order - /// let text = "bdacfe"; - /// itertools::assert_equal(text.chars().sorted(), - /// "abcdef".chars()); - /// ``` - #[cfg(feature = "use_std")] - fn sorted(self) -> VecIntoIter - where Self: Sized, - Self::Item: Ord - { - // Use .sort() directly since it is not quite identical with - // .sort_by(Ord::cmp) - let mut v = Vec::from_iter(self); - v.sort(); - v.into_iter() - } - - /// Sort all iterator elements into a new iterator in ascending order. - /// - /// **Note:** This consumes the entire iterator, uses the - /// `slice::sort_by()` method and returns the result as a new - /// iterator that owns its elements. - /// - /// The sorted iterator, if directly collected to a `Vec`, is converted - /// without any extra copying or allocation cost. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // sort people in descending order by age - /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; - /// - /// let oldest_people_first = people - /// .into_iter() - /// .sorted_by(|a, b| Ord::cmp(&b.1, &a.1)) - /// .map(|(person, _age)| person); - /// - /// itertools::assert_equal(oldest_people_first, - /// vec!["Jill", "Jack", "Jane", "John"]); - /// ``` - #[cfg(feature = "use_std")] - fn sorted_by(self, cmp: F) -> VecIntoIter - where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - let mut v = Vec::from_iter(self); - v.sort_by(cmp); - v.into_iter() - } - - /// Sort all iterator elements into a new iterator in ascending order. - /// - /// **Note:** This consumes the entire iterator, uses the - /// `slice::sort_by_key()` method and returns the result as a new - /// iterator that owns its elements. - /// - /// The sorted iterator, if directly collected to a `Vec`, is converted - /// without any extra copying or allocation cost. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // sort people in descending order by age - /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; - /// - /// let oldest_people_first = people - /// .into_iter() - /// .sorted_by_key(|x| -x.1) - /// .map(|(person, _age)| person); - /// - /// itertools::assert_equal(oldest_people_first, - /// vec!["Jill", "Jack", "Jane", "John"]); - /// ``` - #[cfg(feature = "use_std")] - fn sorted_by_key(self, f: F) -> VecIntoIter - where Self: Sized, - K: Ord, - F: FnMut(&Self::Item) -> K, - { - let mut v = Vec::from_iter(self); - v.sort_by_key(f); - v.into_iter() - } - - /// Collect all iterator elements into one of two - /// partitions. Unlike `Iterator::partition`, each partition may - /// have a distinct type. - /// - /// ``` - /// use itertools::{Itertools, Either}; - /// - /// let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)]; - /// - /// let (successes, failures): (Vec<_>, Vec<_>) = successes_and_failures - /// .into_iter() - /// .partition_map(|r| { - /// match r { - /// Ok(v) => Either::Left(v), - /// Err(v) => Either::Right(v), - /// } - /// }); - /// - /// assert_eq!(successes, [1, 2]); - /// assert_eq!(failures, [false, true]); - /// ``` - fn partition_map(self, mut predicate: F) -> (A, B) - where Self: Sized, - F: FnMut(Self::Item) -> Either, - A: Default + Extend, - B: Default + Extend, - { - let mut left = A::default(); - let mut right = B::default(); - - self.for_each(|val| match predicate(val) { - Either::Left(v) => left.extend(Some(v)), - Either::Right(v) => right.extend(Some(v)), - }); - - (left, right) - } - - /// Return a `HashMap` of keys mapped to `Vec`s of values. Keys and values - /// are taken from `(Key, Value)` tuple pairs yielded by the input iterator. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)]; - /// let lookup = data.into_iter().into_group_map(); - /// - /// assert_eq!(lookup[&0], vec![10, 20]); - /// assert_eq!(lookup.get(&1), None); - /// assert_eq!(lookup[&2], vec![12, 42]); - /// assert_eq!(lookup[&3], vec![13, 33]); - /// ``` - #[cfg(feature = "use_std")] - fn into_group_map(self) -> HashMap> - where Self: Iterator + Sized, - K: Hash + Eq, - { - group_map::into_group_map(self) - } - - /// Return the minimum and maximum elements in the iterator. - /// - /// The return type `MinMaxResult` is an enum of three variants: - /// - /// - `NoElements` if the iterator is empty. - /// - `OneElement(x)` if the iterator has exactly one element. - /// - `MinMax(x, y)` is returned otherwise, where `x <= y`. Two - /// values are equal if and only if there is more than one - /// element in the iterator and all elements are equal. - /// - /// On an iterator of length `n`, `minmax` does `1.5 * n` comparisons, - /// and so is faster than calling `min` and `max` separately which does - /// `2 * n` comparisons. - /// - /// # Examples - /// - /// ``` - /// use itertools::Itertools; - /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; - /// - /// let a: [i32; 0] = []; - /// assert_eq!(a.iter().minmax(), NoElements); - /// - /// let a = [1]; - /// assert_eq!(a.iter().minmax(), OneElement(&1)); - /// - /// let a = [1, 2, 3, 4, 5]; - /// assert_eq!(a.iter().minmax(), MinMax(&1, &5)); - /// - /// let a = [1, 1, 1, 1]; - /// assert_eq!(a.iter().minmax(), MinMax(&1, &1)); - /// ``` - /// - /// The elements can be floats but no particular result is guaranteed - /// if an element is NaN. - fn minmax(self) -> MinMaxResult - where Self: Sized, Self::Item: PartialOrd - { - minmax::minmax_impl(self, |_| (), |x, y, _, _| x < y) - } - - /// Return the minimum and maximum element of an iterator, as determined by - /// the specified function. - /// - /// The return value is a variant of `MinMaxResult` like for `minmax()`. - /// - /// For the minimum, the first minimal element is returned. For the maximum, - /// the last maximal element wins. This matches the behavior of the standard - /// `Iterator::min()` and `Iterator::max()` methods. - /// - /// The keys can be floats but no particular result is guaranteed - /// if a key is NaN. - fn minmax_by_key(self, key: F) -> MinMaxResult - where Self: Sized, K: PartialOrd, F: FnMut(&Self::Item) -> K - { - minmax::minmax_impl(self, key, |_, _, xk, yk| xk < yk) - } - - /// Return the minimum and maximum element of an iterator, as determined by - /// the specified comparison function. - /// - /// The return value is a variant of `MinMaxResult` like for `minmax()`. - /// - /// For the minimum, the first minimal element is returned. For the maximum, - /// the last maximal element wins. This matches the behavior of the standard - /// `Iterator::min()` and `Iterator::max()` methods. - fn minmax_by(self, mut compare: F) -> MinMaxResult - where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering - { - minmax::minmax_impl( - self, - |_| (), - |x, y, _, _| Ordering::Less == compare(x, y) - ) - } - - /// If the iterator yields exactly one element, that element will be returned, otherwise - /// an error will be returned containing an iterator that has the same output as the input - /// iterator. - /// - /// This provides an additional layer of validation over just calling `Iterator::next()`. - /// If your assumption that there should only be one element yielded is false this provides - /// the opportunity to detect and handle that, preventing errors at a distance. - /// - /// # Examples - /// ``` - /// use itertools::Itertools; - /// - /// assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2); - /// assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4)); - /// assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5)); - /// assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0)); - /// ``` - fn exactly_one(mut self) -> Result> - where - Self: Sized, - { - match self.next() { - Some(first) => { - match self.next() { - Some(second) => { - Err(ExactlyOneError::new((Some(first), Some(second)), self)) - } - None => { - Ok(first) - } - } - } - None => Err(ExactlyOneError::new((None, None), self)), - } - } -} - -impl Itertools for T where T: Iterator { } - -/// Return `true` if both iterables produce equal sequences -/// (elements pairwise equal and sequences of the same length), -/// `false` otherwise. -/// -/// This is an `IntoIterator` enabled function that is similar to the standard -/// library method `Iterator::eq`. -/// -/// ``` -/// assert!(itertools::equal(vec![1, 2, 3], 1..4)); -/// assert!(!itertools::equal(&[0, 0], &[0, 0, 0])); -/// ``` -pub fn equal(a: I, b: J) -> bool - where I: IntoIterator, - J: IntoIterator, - I::Item: PartialEq -{ - let mut ia = a.into_iter(); - let mut ib = b.into_iter(); - loop { - match ia.next() { - Some(x) => match ib.next() { - Some(y) => if x != y { return false; }, - None => return false, - }, - None => return ib.next().is_none() - } - } -} - -/// Assert that two iterables produce equal sequences, with the same -/// semantics as *equal(a, b)*. -/// -/// **Panics** on assertion failure with a message that shows the -/// two iteration elements. -/// -/// ```ignore -/// assert_equal("exceed".split('c'), "excess".split('c')); -/// // ^PANIC: panicked at 'Failed assertion Some("eed") == Some("ess") for iteration 1', -/// ``` -pub fn assert_equal(a: I, b: J) - where I: IntoIterator, - J: IntoIterator, - I::Item: fmt::Debug + PartialEq, - J::Item: fmt::Debug, -{ - let mut ia = a.into_iter(); - let mut ib = b.into_iter(); - let mut i = 0; - loop { - match (ia.next(), ib.next()) { - (None, None) => return, - (a, b) => { - let equal = match (&a, &b) { - (&Some(ref a), &Some(ref b)) => a == b, - _ => false, - }; - assert!(equal, "Failed assertion {a:?} == {b:?} for iteration {i}", - i=i, a=a, b=b); - i += 1; - } - } - } -} - -/// Partition a sequence using predicate `pred` so that elements -/// that map to `true` are placed before elements which map to `false`. -/// -/// The order within the partitions is arbitrary. -/// -/// Return the index of the split point. -/// -/// ``` -/// use itertools::partition; -/// -/// # // use repeated numbers to not promise any ordering -/// let mut data = [7, 1, 1, 7, 1, 1, 7]; -/// let split_index = partition(&mut data, |elt| *elt >= 3); -/// -/// assert_eq!(data, [7, 7, 7, 1, 1, 1, 1]); -/// assert_eq!(split_index, 3); -/// ``` -pub fn partition<'a, A: 'a, I, F>(iter: I, mut pred: F) -> usize - where I: IntoIterator, - I::IntoIter: DoubleEndedIterator, - F: FnMut(&A) -> bool -{ - let mut split_index = 0; - let mut iter = iter.into_iter(); - 'main: while let Some(front) = iter.next() { - if !pred(front) { - loop { - match iter.next_back() { - Some(back) => if pred(back) { - std::mem::swap(front, back); - break; - }, - None => break 'main, - } - } - } - split_index += 1; - } - split_index -} - -/// An enum used for controlling the execution of `.fold_while()`. -/// -/// See [`.fold_while()`](trait.Itertools.html#method.fold_while) for more information. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum FoldWhile { - /// Continue folding with this value - Continue(T), - /// Fold is complete and will return this value - Done(T), -} - -impl FoldWhile { - /// Return the value in the continue or done. - pub fn into_inner(self) -> T { - match self { - FoldWhile::Continue(x) | FoldWhile::Done(x) => x, - } - } - - /// Return true if `self` is `Done`, false if it is `Continue`. - pub fn is_done(&self) -> bool { - match *self { - FoldWhile::Continue(_) => false, - FoldWhile::Done(_) => true, - } - } -} diff --git a/vendor/itertools-0.8.2/src/merge_join.rs b/vendor/itertools-0.8.2/src/merge_join.rs deleted file mode 100644 index 5f9a0f4013..0000000000 --- a/vendor/itertools-0.8.2/src/merge_join.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::cmp::Ordering; -use std::iter::Fuse; -use std::fmt; - -use super::adaptors::{PutBack, put_back}; -use either_or_both::EitherOrBoth; - -/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order. -/// -/// See [`.merge_join_by()`](trait.Itertools.html#method.merge_join_by) for more information. -pub fn merge_join_by(left: I, right: J, cmp_fn: F) - -> MergeJoinBy - where I: IntoIterator, - J: IntoIterator, - F: FnMut(&I::Item, &J::Item) -> Ordering -{ - MergeJoinBy { - left: put_back(left.into_iter().fuse()), - right: put_back(right.into_iter().fuse()), - cmp_fn: cmp_fn - } -} - -/// An iterator adaptor that merge-joins items from the two base iterators in ascending order. -/// -/// See [`.merge_join_by()`](../trait.Itertools.html#method.merge_join_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MergeJoinBy { - left: PutBack>, - right: PutBack>, - cmp_fn: F -} - -impl fmt::Debug for MergeJoinBy - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, - J: Iterator + fmt::Debug, - J::Item: fmt::Debug, -{ - debug_fmt_fields!(MergeJoinBy, left, right); -} - -impl Iterator for MergeJoinBy - where I: Iterator, - J: Iterator, - F: FnMut(&I::Item, &J::Item) -> Ordering -{ - type Item = EitherOrBoth; - - fn next(&mut self) -> Option { - match (self.left.next(), self.right.next()) { - (None, None) => None, - (Some(left), None) => - Some(EitherOrBoth::Left(left)), - (None, Some(right)) => - Some(EitherOrBoth::Right(right)), - (Some(left), Some(right)) => { - match (self.cmp_fn)(&left, &right) { - Ordering::Equal => - Some(EitherOrBoth::Both(left, right)), - Ordering::Less => { - self.right.put_back(right); - Some(EitherOrBoth::Left(left)) - }, - Ordering::Greater => { - self.left.put_back(left); - Some(EitherOrBoth::Right(right)) - } - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let (a_lower, a_upper) = self.left.size_hint(); - let (b_lower, b_upper) = self.right.size_hint(); - - let lower = ::std::cmp::max(a_lower, b_lower); - - let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) => Some(x + y), - _ => None, - }; - - (lower, upper) - } -} diff --git a/vendor/itertools-0.8.2/src/minmax.rs b/vendor/itertools-0.8.2/src/minmax.rs deleted file mode 100644 index 38180ef6d0..0000000000 --- a/vendor/itertools-0.8.2/src/minmax.rs +++ /dev/null @@ -1,114 +0,0 @@ - -/// `MinMaxResult` is an enum returned by `minmax`. See `Itertools::minmax()` for -/// more detail. -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum MinMaxResult { - /// Empty iterator - NoElements, - - /// Iterator with one element, so the minimum and maximum are the same - OneElement(T), - - /// More than one element in the iterator, the first element is not larger - /// than the second - MinMax(T, T) -} - -impl MinMaxResult { - /// `into_option` creates an `Option` of type `(T, T)`. The returned `Option` - /// has variant `None` if and only if the `MinMaxResult` has variant - /// `NoElements`. Otherwise `Some((x, y))` is returned where `x <= y`. - /// If the `MinMaxResult` has variant `OneElement(x)`, performing this - /// operation will make one clone of `x`. - /// - /// # Examples - /// - /// ``` - /// use itertools::MinMaxResult::{self, NoElements, OneElement, MinMax}; - /// - /// let r: MinMaxResult = NoElements; - /// assert_eq!(r.into_option(), None); - /// - /// let r = OneElement(1); - /// assert_eq!(r.into_option(), Some((1, 1))); - /// - /// let r = MinMax(1, 2); - /// assert_eq!(r.into_option(), Some((1, 2))); - /// ``` - pub fn into_option(self) -> Option<(T,T)> { - match self { - MinMaxResult::NoElements => None, - MinMaxResult::OneElement(x) => Some((x.clone(), x)), - MinMaxResult::MinMax(x, y) => Some((x, y)) - } - } -} - -/// Implementation guts for `minmax` and `minmax_by_key`. -pub fn minmax_impl(mut it: I, mut key_for: F, - mut lt: L) -> MinMaxResult - where I: Iterator, - F: FnMut(&I::Item) -> K, - L: FnMut(&I::Item, &I::Item, &K, &K) -> bool, -{ - let (mut min, mut max, mut min_key, mut max_key) = match it.next() { - None => return MinMaxResult::NoElements, - Some(x) => { - match it.next() { - None => return MinMaxResult::OneElement(x), - Some(y) => { - let xk = key_for(&x); - let yk = key_for(&y); - if !lt(&y, &x, &yk, &xk) {(x, y, xk, yk)} else {(y, x, yk, xk)} - } - } - } - }; - - loop { - // `first` and `second` are the two next elements we want to look - // at. We first compare `first` and `second` (#1). The smaller one - // is then compared to current minimum (#2). The larger one is - // compared to current maximum (#3). This way we do 3 comparisons - // for 2 elements. - let first = match it.next() { - None => break, - Some(x) => x - }; - let second = match it.next() { - None => { - let first_key = key_for(&first); - if lt(&first, &min, &first_key, &min_key) { - min = first; - } else if !lt(&first, &max, &first_key, &max_key) { - max = first; - } - break; - } - Some(x) => x - }; - let first_key = key_for(&first); - let second_key = key_for(&second); - if !lt(&second, &first, &second_key, &first_key) { - if lt(&first, &min, &first_key, &min_key) { - min = first; - min_key = first_key; - } - if !lt(&second, &max, &second_key, &max_key) { - max = second; - max_key = second_key; - } - } else { - if lt(&second, &min, &second_key, &min_key) { - min = second; - min_key = second_key; - } - if !lt(&first, &max, &first_key, &max_key) { - max = first; - max_key = first_key; - } - } - } - - MinMaxResult::MinMax(min, max) -} diff --git a/vendor/itertools-0.8.2/src/multipeek_impl.rs b/vendor/itertools-0.8.2/src/multipeek_impl.rs deleted file mode 100644 index a6a2fb33eb..0000000000 --- a/vendor/itertools-0.8.2/src/multipeek_impl.rs +++ /dev/null @@ -1,104 +0,0 @@ - - -use std::iter::Fuse; -use std::collections::VecDeque; -use size_hint; -use PeekingNext; - -/// See [`multipeek()`](../fn.multipeek.html) for more information. -#[derive(Clone, Debug)] -pub struct MultiPeek - where I: Iterator -{ - iter: Fuse, - buf: VecDeque, - index: usize, -} - -/// An iterator adaptor that allows the user to peek at multiple `.next()` -/// values without advancing the base iterator. -pub fn multipeek(iterable: I) -> MultiPeek - where I: IntoIterator -{ - MultiPeek { - iter: iterable.into_iter().fuse(), - buf: VecDeque::new(), - index: 0, - } -} - -impl MultiPeek - where I: Iterator -{ - /// Reset the peeking “cursor” - pub fn reset_peek(&mut self) { - self.index = 0; - } -} - -impl MultiPeek { - /// Works exactly like `.next()` with the only difference that it doesn't - /// advance itself. `.peek()` can be called multiple times, to peek - /// further ahead. - pub fn peek(&mut self) -> Option<&I::Item> { - let ret = if self.index < self.buf.len() { - Some(&self.buf[self.index]) - } else { - match self.iter.next() { - Some(x) => { - self.buf.push_back(x); - Some(&self.buf[self.index]) - } - None => return None, - } - }; - - self.index += 1; - ret - } -} - -impl PeekingNext for MultiPeek - where I: Iterator, -{ - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - if self.buf.is_empty() { - if let Some(r) = self.peek() { - if !accept(r) { return None } - } - } else { - if let Some(r) = self.buf.get(0) { - if !accept(r) { return None } - } - } - self.next() - } -} - -impl Iterator for MultiPeek - where I: Iterator -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - self.index = 0; - if self.buf.is_empty() { - self.iter.next() - } else { - self.buf.pop_front() - } - } - - fn size_hint(&self) -> (usize, Option) { - size_hint::add_scalar(self.iter.size_hint(), self.buf.len()) - } -} - -// Same size -impl ExactSizeIterator for MultiPeek - where I: ExactSizeIterator -{} - - diff --git a/vendor/itertools-0.8.2/src/pad_tail.rs b/vendor/itertools-0.8.2/src/pad_tail.rs deleted file mode 100644 index c9cfe6af30..0000000000 --- a/vendor/itertools-0.8.2/src/pad_tail.rs +++ /dev/null @@ -1,83 +0,0 @@ -use std::iter::Fuse; -use size_hint; - -/// An iterator adaptor that pads a sequence to a minimum length by filling -/// missing elements using a closure. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.pad_using()`](../trait.Itertools.html#method.pad_using) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct PadUsing { - iter: Fuse, - min: usize, - pos: usize, - filler: F, -} - -/// Create a new **PadUsing** iterator. -pub fn pad_using(iter: I, min: usize, filler: F) -> PadUsing - where I: Iterator, - F: FnMut(usize) -> I::Item -{ - PadUsing { - iter: iter.fuse(), - min: min, - pos: 0, - filler: filler, - } -} - -impl Iterator for PadUsing - where I: Iterator, - F: FnMut(usize) -> I::Item -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - match self.iter.next() { - None => { - if self.pos < self.min { - let e = Some((self.filler)(self.pos)); - self.pos += 1; - e - } else { - None - } - }, - e => { - self.pos += 1; - e - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let tail = self.min.saturating_sub(self.pos); - size_hint::max(self.iter.size_hint(), (tail, Some(tail))) - } -} - -impl DoubleEndedIterator for PadUsing - where I: DoubleEndedIterator + ExactSizeIterator, - F: FnMut(usize) -> I::Item -{ - fn next_back(&mut self) -> Option { - if self.min == 0 { - self.iter.next_back() - } else if self.iter.len() >= self.min { - self.min -= 1; - self.iter.next_back() - } else { - self.min -= 1; - Some((self.filler)(self.min)) - } - } -} - -impl ExactSizeIterator for PadUsing - where I: ExactSizeIterator, - F: FnMut(usize) -> I::Item -{} diff --git a/vendor/itertools-0.8.2/src/peeking_take_while.rs b/vendor/itertools-0.8.2/src/peeking_take_while.rs deleted file mode 100644 index 0b2291dfdd..0000000000 --- a/vendor/itertools-0.8.2/src/peeking_take_while.rs +++ /dev/null @@ -1,149 +0,0 @@ - -use std::iter::Peekable; -use PutBack; -#[cfg(feature = "use_std")] -use PutBackN; - -/// An iterator that allows peeking at an element before deciding to accept it. -/// -/// See [`.peeking_take_while()`](trait.Itertools.html#method.peeking_take_while) -/// for more information. -/// -/// This is implemented by peeking adaptors like peekable and put back, -/// but also by a few iterators that can be peeked natively, like the slice’s -/// by reference iterator (`std::slice::Iter`). -pub trait PeekingNext : Iterator { - /// Pass a reference to the next iterator element to the closure `accept`; - /// if `accept` returns true, return it as the next element, - /// else None. - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool; -} - -impl PeekingNext for Peekable - where I: Iterator, -{ - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - if let Some(r) = self.peek() { - if !accept(r) { - return None; - } - } - self.next() - } -} - -impl PeekingNext for PutBack - where I: Iterator, -{ - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - if let Some(r) = self.next() { - if !accept(&r) { - self.put_back(r); - return None; - } - Some(r) - } else { - None - } - } -} - -#[cfg(feature = "use_std")] -impl PeekingNext for PutBackN - where I: Iterator, -{ - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - if let Some(r) = self.next() { - if !accept(&r) { - self.put_back(r); - return None; - } - Some(r) - } else { - None - } - } -} - -/// An iterator adaptor that takes items while a closure returns `true`. -/// -/// See [`.peeking_take_while()`](../trait.Itertools.html#method.peeking_take_while) -/// for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct PeekingTakeWhile<'a, I: 'a, F> - where I: Iterator, -{ - iter: &'a mut I, - f: F, -} - -/// Create a PeekingTakeWhile -pub fn peeking_take_while(iter: &mut I, f: F) -> PeekingTakeWhile - where I: Iterator, -{ - PeekingTakeWhile { - iter: iter, - f: f, - } -} - -impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F> - where I: PeekingNext, - F: FnMut(&I::Item) -> bool, - -{ - type Item = I::Item; - fn next(&mut self) -> Option { - self.iter.peeking_next(&mut self.f) - } - - fn size_hint(&self) -> (usize, Option) { - let (_, hi) = self.iter.size_hint(); - (0, hi) - } -} - -// Some iterators are so lightweight we can simply clone them to save their -// state and use that for peeking. -macro_rules! peeking_next_by_clone { - ([$($typarm:tt)*] $type_:ty) => { - impl<$($typarm)*> PeekingNext for $type_ { - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - let saved_state = self.clone(); - if let Some(r) = self.next() { - if !accept(&r) { - *self = saved_state; - } else { - return Some(r) - } - } - None - } - } - } -} - -peeking_next_by_clone! { ['a, T] ::std::slice::Iter<'a, T> } -peeking_next_by_clone! { ['a] ::std::str::Chars<'a> } -peeking_next_by_clone! { ['a] ::std::str::CharIndices<'a> } -peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> } -peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> } -peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> } -peeking_next_by_clone! { [T] ::std::iter::Empty } -#[cfg(feature = "use_std")] -peeking_next_by_clone! { ['a, T] ::std::collections::linked_list::Iter<'a, T> } -#[cfg(feature = "use_std")] -peeking_next_by_clone! { ['a, T] ::std::collections::vec_deque::Iter<'a, T> } - -// cloning a Rev has no extra overhead; peekable and put backs are never DEI. -peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator] - ::std::iter::Rev } diff --git a/vendor/itertools-0.8.2/src/permutations.rs b/vendor/itertools-0.8.2/src/permutations.rs deleted file mode 100644 index a9423375fd..0000000000 --- a/vendor/itertools-0.8.2/src/permutations.rs +++ /dev/null @@ -1,272 +0,0 @@ -use std::fmt; -use std::iter::once; - -use super::lazy_buffer::LazyBuffer; - -/// An iterator adaptor that iterates through all the `k`-permutations of the -/// elements from an iterator. -/// -/// See [`.permutations()`](../trait.Itertools.html#method.permutations) for -/// more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Permutations { - vals: LazyBuffer, - state: PermutationState, -} - -#[derive(Debug)] -enum PermutationState { - StartUnknownLen { - k: usize, - }, - OngoingUnknownLen { - k: usize, - min_n: usize, - }, - Complete(CompleteState), - Empty, -} - -#[derive(Debug)] -enum CompleteState { - Start { - n: usize, - k: usize, - }, - Ongoing { - indices: Vec, - cycles: Vec, - } -} - -enum CompleteStateRemaining { - Known(usize), - Overflow, -} - -impl fmt::Debug for Permutations - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Permutations, vals, state); -} - -pub fn permutations(iter: I, k: usize) -> Permutations { - let mut vals = LazyBuffer::new(iter); - - if k == 0 { - // Special case, yields single empty vec; `n` is irrelevant - let state = PermutationState::Complete(CompleteState::Start { n: 0, k: 0 }); - - return Permutations { - vals, - state - }; - } - - let mut enough_vals = true; - - while vals.len() < k { - if !vals.get_next() { - enough_vals = false; - break; - } - } - - let state = if enough_vals { - PermutationState::StartUnknownLen { k } - } else { - PermutationState::Empty - }; - - Permutations { - vals, - state - } -} - -impl Iterator for Permutations -where - I: Iterator, - I::Item: Clone -{ - type Item = Vec; - - fn next(&mut self) -> Option { - self.advance(); - - let &mut Permutations { ref vals, ref state } = self; - - match state { - &PermutationState::StartUnknownLen { .. } => panic!("unexpected iterator state"), - &PermutationState::OngoingUnknownLen { k, min_n } => { - let latest_idx = min_n - 1; - let indices = (0..(k - 1)).chain(once(latest_idx)); - - Some(indices.map(|i| vals[i].clone()).collect()) - } - &PermutationState::Complete(CompleteState::Start { .. }) => None, - &PermutationState::Complete(CompleteState::Ongoing { ref indices, ref cycles }) => { - let k = cycles.len(); - - Some(indices[0..k].iter().map(|&i| vals[i].clone()).collect()) - }, - &PermutationState::Empty => None - } - } - - fn count(self) -> usize { - let Permutations { vals, state } = self; - - fn from_complete(complete_state: CompleteState) -> usize { - match complete_state.remaining() { - CompleteStateRemaining::Known(count) => count, - CompleteStateRemaining::Overflow => { - panic!("Iterator count greater than usize::MAX"); - } - } - } - - match state { - PermutationState::StartUnknownLen { k } => { - let n = vals.len() + vals.it.count(); - let complete_state = CompleteState::Start { n, k }; - - from_complete(complete_state) - } - PermutationState::OngoingUnknownLen { k, min_n } => { - let prev_iteration_count = min_n - k + 1; - let n = vals.len() + vals.it.count(); - let complete_state = CompleteState::Start { n, k }; - - from_complete(complete_state) - prev_iteration_count - }, - PermutationState::Complete(state) => from_complete(state), - PermutationState::Empty => 0 - } - } - - fn size_hint(&self) -> (usize, Option) { - match self.state { - PermutationState::StartUnknownLen { .. } | - PermutationState::OngoingUnknownLen { .. } => (0, None), // TODO can we improve this lower bound? - PermutationState::Complete(ref state) => match state.remaining() { - CompleteStateRemaining::Known(count) => (count, Some(count)), - CompleteStateRemaining::Overflow => (::std::usize::MAX, None) - } - PermutationState::Empty => (0, Some(0)) - } - } -} - -impl Permutations -where - I: Iterator, - I::Item: Clone -{ - fn advance(&mut self) { - let &mut Permutations { ref mut vals, ref mut state } = self; - - *state = match state { - &mut PermutationState::StartUnknownLen { k } => { - PermutationState::OngoingUnknownLen { k, min_n: k } - } - &mut PermutationState::OngoingUnknownLen { k, min_n } => { - if vals.get_next() { - PermutationState::OngoingUnknownLen { k, min_n: min_n + 1 } - } else { - let n = min_n; - let prev_iteration_count = n - k + 1; - let mut complete_state = CompleteState::Start { n, k }; - - // Advance the complete-state iterator to the correct point - for _ in 0..(prev_iteration_count + 1) { - complete_state.advance(); - } - - PermutationState::Complete(complete_state) - } - } - &mut PermutationState::Complete(ref mut state) => { - state.advance(); - - return; - } - &mut PermutationState::Empty => { return; } - }; - } -} - -impl CompleteState { - fn advance(&mut self) { - *self = match self { - &mut CompleteState::Start { n, k } => { - let indices = (0..n).collect(); - let cycles = ((n - k)..n).rev().collect(); - - CompleteState::Ongoing { - cycles, - indices - } - }, - &mut CompleteState::Ongoing { ref mut indices, ref mut cycles } => { - let n = indices.len(); - let k = cycles.len(); - - for i in (0..k).rev() { - if cycles[i] == 0 { - cycles[i] = n - i - 1; - - let to_push = indices.remove(i); - indices.push(to_push); - } else { - let swap_index = n - cycles[i]; - indices.swap(i, swap_index); - - cycles[i] -= 1; - return; - } - } - - CompleteState::Start { n, k } - } - } - } - - fn remaining(&self) -> CompleteStateRemaining { - use self::CompleteStateRemaining::{Known, Overflow}; - - match self { - &CompleteState::Start { n, k } => { - if n < k { - return Known(0); - } - - let count: Option = (n - k + 1..n + 1).fold(Some(1), |acc, i| { - acc.and_then(|acc| acc.checked_mul(i)) - }); - - match count { - Some(count) => Known(count), - None => Overflow - } - } - &CompleteState::Ongoing { ref indices, ref cycles } => { - let mut count: usize = 0; - - for (i, &c) in cycles.iter().enumerate() { - let radix = indices.len() - i; - let next_count = count.checked_mul(radix) - .and_then(|count| count.checked_add(c)); - - count = match next_count { - Some(count) => count, - None => { return Overflow; } - }; - } - - Known(count) - } - } - } -} \ No newline at end of file diff --git a/vendor/itertools-0.8.2/src/process_results_impl.rs b/vendor/itertools-0.8.2/src/process_results_impl.rs deleted file mode 100644 index f78515d77f..0000000000 --- a/vendor/itertools-0.8.2/src/process_results_impl.rs +++ /dev/null @@ -1,81 +0,0 @@ - -/// An iterator that produces only the `T` values as long as the -/// inner iterator produces `Ok(T)`. -/// -/// Used by [`process_results`](../fn.process_results.html), see its docs -/// for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct ProcessResults<'a, I, E: 'a> { - error: &'a mut Result<(), E>, - iter: I, -} - -impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E> - where I: Iterator> -{ - type Item = T; - - fn next(&mut self) -> Option { - match self.iter.next() { - Some(Ok(x)) => Some(x), - Some(Err(e)) => { - *self.error = Err(e); - None - } - None => None, - } - } - - fn size_hint(&self) -> (usize, Option) { - let (_, hi) = self.iter.size_hint(); - (0, hi) - } -} - -/// “Lift” a function of the values of an iterator so that it can process -/// an iterator of `Result` values instead. -/// -/// `iterable` is an iterator or iterable with `Result` elements, where -/// `T` is the value type and `E` the error type. -/// -/// `processor` is a closure that receives an adapted version of the iterable -/// as the only argument — the adapted iterator produces elements of type `T`, -/// as long as the original iterator produces `Ok` values. -/// -/// If the original iterable produces an error at any point, the adapted -/// iterator ends and the `process_results` function will return the -/// error iself. -/// -/// Otherwise, the return value from the closure is returned wrapped -/// inside `Ok`. -/// -/// # Example -/// -/// ``` -/// use itertools::process_results; -/// -/// type R = Result; -/// -/// let first_values: Vec = vec![Ok(1), Ok(0), Ok(3)]; -/// let second_values: Vec = vec![Ok(2), Ok(1), Err("overflow")]; -/// -/// // “Lift” the iterator .max() method to work on the values in Results using process_results -/// -/// let first_max = process_results(first_values, |iter| iter.max().unwrap_or(0)); -/// let second_max = process_results(second_values, |iter| iter.max().unwrap_or(0)); -/// -/// assert_eq!(first_max, Ok(3)); -/// assert!(second_max.is_err()); -/// ``` -pub fn process_results(iterable: I, processor: F) -> Result - where I: IntoIterator>, - F: FnOnce(ProcessResults) -> R -{ - let iter = iterable.into_iter(); - let mut error = Ok(()); - - let result = processor(ProcessResults { error: &mut error, iter: iter }); - - error.map(|_| result) -} diff --git a/vendor/itertools-0.8.2/src/put_back_n_impl.rs b/vendor/itertools-0.8.2/src/put_back_n_impl.rs deleted file mode 100644 index cc08320714..0000000000 --- a/vendor/itertools-0.8.2/src/put_back_n_impl.rs +++ /dev/null @@ -1,63 +0,0 @@ -use size_hint; - -/// An iterator adaptor that allows putting multiple -/// items in front of the iterator. -/// -/// Iterator element type is `I::Item`. -#[derive(Debug, Clone)] -pub struct PutBackN { - top: Vec, - iter: I, -} - -/// Create an iterator where you can put back multiple values to the front -/// of the iteration. -/// -/// Iterator element type is `I::Item`. -pub fn put_back_n(iterable: I) -> PutBackN - where I: IntoIterator -{ - PutBackN { - top: Vec::new(), - iter: iterable.into_iter(), - } -} - -impl PutBackN { - /// Puts x in front of the iterator. - /// The values are yielded in order of the most recently put back - /// values first. - /// - /// ```rust - /// use itertools::put_back_n; - /// - /// let mut it = put_back_n(1..5); - /// it.next(); - /// it.put_back(1); - /// it.put_back(0); - /// - /// assert!(itertools::equal(it, 0..5)); - /// ``` - #[inline] - pub fn put_back(&mut self, x: I::Item) { - self.top.push(x); - } -} - -impl Iterator for PutBackN { - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - if self.top.is_empty() { - self.iter.next() - } else { - self.top.pop() - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - size_hint::add_scalar(self.iter.size_hint(), self.top.len()) - } -} - diff --git a/vendor/itertools-0.8.2/src/rciter_impl.rs b/vendor/itertools-0.8.2/src/rciter_impl.rs deleted file mode 100644 index 1c3b03b5bc..0000000000 --- a/vendor/itertools-0.8.2/src/rciter_impl.rs +++ /dev/null @@ -1,98 +0,0 @@ - -use std::iter::IntoIterator; -use std::rc::Rc; -use std::cell::RefCell; - -/// A wrapper for `Rc>`, that implements the `Iterator` trait. -#[derive(Debug)] -pub struct RcIter { - /// The boxed iterator. - pub rciter: Rc>, -} - -/// Return an iterator inside a `Rc>` wrapper. -/// -/// The returned `RcIter` can be cloned, and each clone will refer back to the -/// same original iterator. -/// -/// `RcIter` allows doing interesting things like using `.zip()` on an iterator with -/// itself, at the cost of runtime borrow checking which may have a performance -/// penalty. -/// -/// Iterator element type is `Self::Item`. -/// -/// ``` -/// use itertools::rciter; -/// use itertools::zip; -/// -/// // In this example a range iterator is created and we iterate it using -/// // three separate handles (two of them given to zip). -/// // We also use the IntoIterator implementation for `&RcIter`. -/// -/// let mut iter = rciter(0..9); -/// let mut z = zip(&iter, &iter); -/// -/// assert_eq!(z.next(), Some((0, 1))); -/// assert_eq!(z.next(), Some((2, 3))); -/// assert_eq!(z.next(), Some((4, 5))); -/// assert_eq!(iter.next(), Some(6)); -/// assert_eq!(z.next(), Some((7, 8))); -/// assert_eq!(z.next(), None); -/// ``` -/// -/// **Panics** in iterator methods if a borrow error is encountered in the -/// iterator methods. It can only happen if the `RcIter` is reentered in -/// `.next()`, i.e. if it somehow participates in an “iterator knot” -/// where it is an adaptor of itself. -pub fn rciter(iterable: I) -> RcIter - where I: IntoIterator -{ - RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) } -} - -impl Clone for RcIter { - #[inline] - fn clone(&self) -> RcIter { - RcIter { rciter: self.rciter.clone() } - } -} - -impl Iterator for RcIter - where I: Iterator -{ - type Item = A; - #[inline] - fn next(&mut self) -> Option { - self.rciter.borrow_mut().next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - // To work sanely with other API that assume they own an iterator, - // so it can't change in other places, we can't guarantee as much - // in our size_hint. Other clones may drain values under our feet. - let (_, hi) = self.rciter.borrow().size_hint(); - (0, hi) - } -} - -impl DoubleEndedIterator for RcIter - where I: DoubleEndedIterator -{ - #[inline] - fn next_back(&mut self) -> Option { - self.rciter.borrow_mut().next_back() - } -} - -/// Return an iterator from `&RcIter` (by simply cloning it). -impl<'a, I> IntoIterator for &'a RcIter - where I: Iterator -{ - type Item = I::Item; - type IntoIter = RcIter; - - fn into_iter(self) -> RcIter { - self.clone() - } -} diff --git a/vendor/itertools-0.8.2/src/repeatn.rs b/vendor/itertools-0.8.2/src/repeatn.rs deleted file mode 100644 index 1c7c310014..0000000000 --- a/vendor/itertools-0.8.2/src/repeatn.rs +++ /dev/null @@ -1,54 +0,0 @@ - -/// An iterator that produces *n* repetitions of an element. -/// -/// See [`repeat_n()`](../fn.repeat_n.html) for more information. -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct RepeatN { - elt: Option, - n: usize, -} - -/// Create an iterator that produces `n` repetitions of `element`. -pub fn repeat_n(element: A, n: usize) -> RepeatN - where A: Clone, -{ - if n == 0 { - RepeatN { elt: None, n: n, } - } else { - RepeatN { elt: Some(element), n: n, } - } -} - -impl Iterator for RepeatN - where A: Clone -{ - type Item = A; - - fn next(&mut self) -> Option { - if self.n > 1 { - self.n -= 1; - self.elt.as_ref().cloned() - } else { - self.n = 0; - self.elt.take() - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.n, Some(self.n)) - } -} - -impl DoubleEndedIterator for RepeatN - where A: Clone -{ - #[inline] - fn next_back(&mut self) -> Option { - self.next() - } -} - -impl ExactSizeIterator for RepeatN - where A: Clone -{} diff --git a/vendor/itertools-0.8.2/src/size_hint.rs b/vendor/itertools-0.8.2/src/size_hint.rs deleted file mode 100644 index be54443f29..0000000000 --- a/vendor/itertools-0.8.2/src/size_hint.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! Arithmetic on **Iterator** *.size_hint()* values. -//! - -use std::usize; -use std::cmp; - -/// **SizeHint** is the return type of **Iterator::size_hint()**. -pub type SizeHint = (usize, Option); - -/// Add **SizeHint** correctly. -#[inline] -pub fn add(a: SizeHint, b: SizeHint) -> SizeHint { - let min = a.0.checked_add(b.0).unwrap_or(usize::MAX); - let max = match (a.1, b.1) { - (Some(x), Some(y)) => x.checked_add(y), - _ => None, - }; - - (min, max) -} - -/// Add **x** correctly to a **SizeHint**. -#[inline] -pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint { - let (mut low, mut hi) = sh; - low = low.saturating_add(x); - hi = hi.and_then(|elt| elt.checked_add(x)); - (low, hi) -} - -/// Sbb **x** correctly to a **SizeHint**. -#[inline] -#[allow(dead_code)] -pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint { - let (mut low, mut hi) = sh; - low = low.saturating_sub(x); - hi = hi.map(|elt| elt.saturating_sub(x)); - (low, hi) -} - - -/// Multiply **SizeHint** correctly -/// -/// ```ignore -/// use std::usize; -/// use itertools::size_hint; -/// -/// assert_eq!(size_hint::mul((3, Some(4)), (3, Some(4))), -/// (9, Some(16))); -/// -/// assert_eq!(size_hint::mul((3, Some(4)), (usize::MAX, None)), -/// (usize::MAX, None)); -/// -/// assert_eq!(size_hint::mul((3, None), (0, Some(0))), -/// (0, Some(0))); -/// ``` -#[inline] -pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint { - let low = a.0.checked_mul(b.0).unwrap_or(usize::MAX); - let hi = match (a.1, b.1) { - (Some(x), Some(y)) => x.checked_mul(y), - (Some(0), None) | (None, Some(0)) => Some(0), - _ => None, - }; - (low, hi) -} - -/// Multiply **x** correctly with a **SizeHint**. -#[inline] -pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint { - let (mut low, mut hi) = sh; - low = low.saturating_mul(x); - hi = hi.and_then(|elt| elt.checked_mul(x)); - (low, hi) -} - -/// Return the maximum -#[inline] -pub fn max(a: SizeHint, b: SizeHint) -> SizeHint { - let (a_lower, a_upper) = a; - let (b_lower, b_upper) = b; - - let lower = cmp::max(a_lower, b_lower); - - let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) => Some(cmp::max(x, y)), - _ => None, - }; - - (lower, upper) -} - -/// Return the minimum -#[inline] -pub fn min(a: SizeHint, b: SizeHint) -> SizeHint { - let (a_lower, a_upper) = a; - let (b_lower, b_upper) = b; - let lower = cmp::min(a_lower, b_lower); - let upper = match (a_upper, b_upper) { - (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)), - _ => a_upper.or(b_upper), - }; - (lower, upper) -} diff --git a/vendor/itertools-0.8.2/src/sources.rs b/vendor/itertools-0.8.2/src/sources.rs deleted file mode 100644 index a579f3d9c2..0000000000 --- a/vendor/itertools-0.8.2/src/sources.rs +++ /dev/null @@ -1,190 +0,0 @@ -//! Iterators that are sources (produce elements from parameters, -//! not from another iterator). -#![allow(deprecated)] - -use std::fmt; -use std::mem; - -/// See [`repeat_call`](../fn.repeat_call.html) for more information. -#[deprecated(note="Use std repeat_with() instead", since="0.8")] -pub struct RepeatCall { - f: F, -} - -impl fmt::Debug for RepeatCall -{ - debug_fmt_fields!(RepeatCall, ); -} - -/// An iterator source that produces elements indefinitely by calling -/// a given closure. -/// -/// Iterator element type is the return type of the closure. -/// -/// ``` -/// use itertools::repeat_call; -/// use itertools::Itertools; -/// use std::collections::BinaryHeap; -/// -/// let mut heap = BinaryHeap::from(vec![2, 5, 3, 7, 8]); -/// -/// // extract each element in sorted order -/// for element in repeat_call(|| heap.pop()).while_some() { -/// print!("{}", element); -/// } -/// -/// itertools::assert_equal( -/// repeat_call(|| 1).take(5), -/// vec![1, 1, 1, 1, 1] -/// ); -/// ``` -#[deprecated(note="Use std repeat_with() instead", since="0.8")] -pub fn repeat_call(function: F) -> RepeatCall - where F: FnMut() -> A -{ - RepeatCall { f: function } -} - -impl Iterator for RepeatCall - where F: FnMut() -> A -{ - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - Some((self.f)()) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::max_value(), None) - } -} - -/// Creates a new unfold source with the specified closure as the "iterator -/// function" and an initial state to eventually pass to the closure -/// -/// `unfold` is a general iterator builder: it has a mutable state value, -/// and a closure with access to the state that produces the next value. -/// -/// This more or less equivalent to a regular struct with an `Iterator` -/// implementation, and is useful for one-off iterators. -/// -/// ``` -/// // an iterator that yields sequential Fibonacci numbers, -/// // and stops at the maximum representable value. -/// -/// use itertools::unfold; -/// -/// let (mut x1, mut x2) = (1u32, 1u32); -/// let mut fibonacci = unfold((), move |_| { -/// // Attempt to get the next Fibonacci number -/// let next = x1.saturating_add(x2); -/// -/// // Shift left: ret <- x1 <- x2 <- next -/// let ret = x1; -/// x1 = x2; -/// x2 = next; -/// -/// // If addition has saturated at the maximum, we are finished -/// if ret == x1 && ret > 1 { -/// return None; -/// } -/// -/// Some(ret) -/// }); -/// -/// itertools::assert_equal(fibonacci.by_ref().take(8), -/// vec![1, 1, 2, 3, 5, 8, 13, 21]); -/// assert_eq!(fibonacci.last(), Some(2_971_215_073)) -/// ``` -pub fn unfold(initial_state: St, f: F) -> Unfold - where F: FnMut(&mut St) -> Option -{ - Unfold { - f: f, - state: initial_state, - } -} - -impl fmt::Debug for Unfold - where St: fmt::Debug, -{ - debug_fmt_fields!(Unfold, state); -} - -/// See [`unfold`](../fn.unfold.html) for more information. -#[derive(Clone)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct Unfold { - f: F, - /// Internal state that will be passed to the closure on the next iteration - pub state: St, -} - -impl Iterator for Unfold - where F: FnMut(&mut St) -> Option -{ - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - (self.f)(&mut self.state) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - // no possible known bounds at this point - (0, None) - } -} - -/// An iterator that infinitely applies function to value and yields results. -/// -/// This `struct` is created by the [`iterate()`] function. See its documentation for more. -/// -/// [`iterate()`]: ../fn.iterate.html -#[derive(Clone)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct Iterate { - state: St, - f: F, -} - -impl fmt::Debug for Iterate - where St: fmt::Debug, -{ - debug_fmt_fields!(Iterate, state); -} - -impl Iterator for Iterate - where F: FnMut(&St) -> St -{ - type Item = St; - - #[inline] - fn next(&mut self) -> Option { - let next_state = (self.f)(&self.state); - Some(mem::replace(&mut self.state, next_state)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (usize::max_value(), None) - } -} - -/// Creates a new iterator that infinitely applies function to value and yields results. -/// -/// ``` -/// use itertools::iterate; -/// -/// itertools::assert_equal(iterate(1, |&i| i * 3).take(5), vec![1, 3, 9, 27, 81]); -/// ``` -pub fn iterate(initial_value: St, f: F) -> Iterate - where F: FnMut(&St) -> St -{ - Iterate { - state: initial_value, - f: f, - } -} diff --git a/vendor/itertools-0.8.2/src/tee.rs b/vendor/itertools-0.8.2/src/tee.rs deleted file mode 100644 index 77d261759d..0000000000 --- a/vendor/itertools-0.8.2/src/tee.rs +++ /dev/null @@ -1,78 +0,0 @@ -use super::size_hint; - -use std::cell::RefCell; -use std::collections::VecDeque; -use std::rc::Rc; - -/// Common buffer object for the two tee halves -#[derive(Debug)] -struct TeeBuffer { - backlog: VecDeque, - iter: I, - /// The owner field indicates which id should read from the backlog - owner: bool, -} - -/// One half of an iterator pair where both return the same elements. -/// -/// See [`.tee()`](../trait.Itertools.html#method.tee) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct Tee - where I: Iterator -{ - rcbuffer: Rc>>, - id: bool, -} - -pub fn new(iter: I) -> (Tee, Tee) - where I: Iterator -{ - let buffer = TeeBuffer{backlog: VecDeque::new(), iter: iter, owner: false}; - let t1 = Tee{rcbuffer: Rc::new(RefCell::new(buffer)), id: true}; - let t2 = Tee{rcbuffer: t1.rcbuffer.clone(), id: false}; - (t1, t2) -} - -impl Iterator for Tee - where I: Iterator, - I::Item: Clone -{ - type Item = I::Item; - fn next(&mut self) -> Option { - // .borrow_mut may fail here -- but only if the user has tied some kind of weird - // knot where the iterator refers back to itself. - let mut buffer = self.rcbuffer.borrow_mut(); - if buffer.owner == self.id { - match buffer.backlog.pop_front() { - None => {} - some_elt => return some_elt, - } - } - match buffer.iter.next() { - None => None, - Some(elt) => { - buffer.backlog.push_back(elt.clone()); - buffer.owner = !self.id; - Some(elt) - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let buffer = self.rcbuffer.borrow(); - let sh = buffer.iter.size_hint(); - - if buffer.owner == self.id { - let log_len = buffer.backlog.len(); - size_hint::add_scalar(sh, log_len) - } else { - sh - } - } -} - -impl ExactSizeIterator for Tee - where I: ExactSizeIterator, - I::Item: Clone -{} diff --git a/vendor/itertools-0.8.2/src/tuple_impl.rs b/vendor/itertools-0.8.2/src/tuple_impl.rs deleted file mode 100644 index 0daa7800c1..0000000000 --- a/vendor/itertools-0.8.2/src/tuple_impl.rs +++ /dev/null @@ -1,266 +0,0 @@ -//! Some iterator that produces tuples - -use std::iter::Fuse; - -/// An iterator over a incomplete tuple. -/// -/// See [`.tuples()`](../trait.Itertools.html#method.tuples) and -/// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer). -#[derive(Debug)] -pub struct TupleBuffer - where T: TupleCollect -{ - cur: usize, - buf: T::Buffer, -} - -impl TupleBuffer - where T: TupleCollect -{ - fn new(buf: T::Buffer) -> Self { - TupleBuffer { - cur: 0, - buf: buf, - } - } -} - -impl Iterator for TupleBuffer - where T: TupleCollect -{ - type Item = T::Item; - - fn next(&mut self) -> Option { - let s = self.buf.as_mut(); - if let Some(ref mut item) = s.get_mut(self.cur) { - self.cur += 1; - item.take() - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - let buffer = &self.buf.as_ref()[self.cur..]; - let len = if buffer.len() == 0 { - 0 - } else { - buffer.iter() - .position(|x| x.is_none()) - .unwrap_or(buffer.len()) - }; - (len, Some(len)) - } -} - -impl ExactSizeIterator for TupleBuffer - where T: TupleCollect -{ -} - -/// An iterator that groups the items in tuples of a specific size. -/// -/// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Tuples - where I: Iterator, - T: TupleCollect -{ - iter: Fuse, - buf: T::Buffer, -} - -/// Create a new tuples iterator. -pub fn tuples(iter: I) -> Tuples - where I: Iterator, - T: TupleCollect -{ - Tuples { - iter: iter.fuse(), - buf: Default::default(), - } -} - -impl Iterator for Tuples - where I: Iterator, - T: TupleCollect -{ - type Item = T; - - fn next(&mut self) -> Option { - T::collect_from_iter(&mut self.iter, &mut self.buf) - } -} - -impl Tuples - where I: Iterator, - T: TupleCollect -{ - /// Return a buffer with the produced items that was not enough to be grouped in a tuple. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut iter = (0..5).tuples(); - /// assert_eq!(Some((0, 1, 2)), iter.next()); - /// assert_eq!(None, iter.next()); - /// itertools::assert_equal(vec![3, 4], iter.into_buffer()); - /// ``` - pub fn into_buffer(self) -> TupleBuffer { - TupleBuffer::new(self.buf) - } -} - - -/// An iterator over all contiguous windows that produces tuples of a specific size. -/// -/// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more -/// information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct TupleWindows - where I: Iterator, - T: TupleCollect -{ - iter: I, - last: Option, -} - -/// Create a new tuple windows iterator. -pub fn tuple_windows(mut iter: I) -> TupleWindows - where I: Iterator, - T: TupleCollect, - T::Item: Clone -{ - use std::iter::once; - - let mut last = None; - if T::num_items() != 1 { - // put in a duplicate item in front of the tuple; this simplifies - // .next() function. - if let Some(item) = iter.next() { - let iter = once(item.clone()).chain(once(item)).chain(&mut iter); - last = T::collect_from_iter_no_buf(iter); - } - } - - TupleWindows { - last: last, - iter: iter, - } -} - -impl Iterator for TupleWindows - where I: Iterator, - T: TupleCollect + Clone, - T::Item: Clone -{ - type Item = T; - - fn next(&mut self) -> Option { - if T::num_items() == 1 { - return T::collect_from_iter_no_buf(&mut self.iter) - } - if let Some(ref mut last) = self.last { - if let Some(new) = self.iter.next() { - last.left_shift_push(new); - return Some(last.clone()); - } - } - None - } -} - -pub trait TupleCollect: Sized { - type Item; - type Buffer: Default + AsRef<[Option]> + AsMut<[Option]>; - - fn collect_from_iter(iter: I, buf: &mut Self::Buffer) -> Option - where I: IntoIterator; - - fn collect_from_iter_no_buf(iter: I) -> Option - where I: IntoIterator; - - fn num_items() -> usize; - - fn left_shift_push(&mut self, item: Self::Item); -} - -macro_rules! impl_tuple_collect { - () => (); - ($N:expr; $A:ident ; $($X:ident),* ; $($Y:ident),* ; $($Y_rev:ident),*) => ( - impl<$A> TupleCollect for ($($X),*,) { - type Item = $A; - type Buffer = [Option<$A>; $N - 1]; - - #[allow(unused_assignments, unused_mut)] - fn collect_from_iter(iter: I, buf: &mut Self::Buffer) -> Option - where I: IntoIterator - { - let mut iter = iter.into_iter(); - $( - let mut $Y = None; - )* - - loop { - $( - $Y = iter.next(); - if $Y.is_none() { - break - } - )* - return Some(($($Y.unwrap()),*,)) - } - - let mut i = 0; - let mut s = buf.as_mut(); - $( - if i < s.len() { - s[i] = $Y; - i += 1; - } - )* - return None; - } - - #[allow(unused_assignments)] - fn collect_from_iter_no_buf(iter: I) -> Option - where I: IntoIterator - { - let mut iter = iter.into_iter(); - loop { - $( - let $Y = if let Some($Y) = iter.next() { - $Y - } else { - break; - }; - )* - return Some(($($Y),*,)) - } - - return None; - } - - fn num_items() -> usize { - $N - } - - fn left_shift_push(&mut self, item: $A) { - use std::mem::replace; - - let &mut ($(ref mut $Y),*,) = self; - let tmp = item; - $( - let tmp = replace($Y_rev, tmp); - )* - drop(tmp); - } - } - ) -} - -impl_tuple_collect!(1; A; A; a; a); -impl_tuple_collect!(2; A; A, A; a, b; b, a); -impl_tuple_collect!(3; A; A, A, A; a, b, c; c, b, a); -impl_tuple_collect!(4; A; A, A, A, A; a, b, c, d; d, c, b, a); diff --git a/vendor/itertools-0.8.2/src/unique_impl.rs b/vendor/itertools-0.8.2/src/unique_impl.rs deleted file mode 100644 index d9e7fd3dc8..0000000000 --- a/vendor/itertools-0.8.2/src/unique_impl.rs +++ /dev/null @@ -1,134 +0,0 @@ - -use std::collections::HashMap; -use std::collections::hash_map::{Entry}; -use std::hash::Hash; -use std::fmt; - -/// An iterator adapter to filter out duplicate elements. -/// -/// See [`.unique_by()`](../trait.Itertools.html#method.unique) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct UniqueBy { - iter: I, - // Use a hashmap for the entry API - used: HashMap, - f: F, -} - -impl fmt::Debug for UniqueBy - where I: Iterator + fmt::Debug, - V: fmt::Debug + Hash + Eq, -{ - debug_fmt_fields!(UniqueBy, iter, used); -} - -/// Create a new `UniqueBy` iterator. -pub fn unique_by(iter: I, f: F) -> UniqueBy - where V: Eq + Hash, - F: FnMut(&I::Item) -> V, - I: Iterator, -{ - UniqueBy { - iter: iter, - used: HashMap::new(), - f: f, - } -} - -// count the number of new unique keys in iterable (`used` is the set already seen) -fn count_new_keys(mut used: HashMap, iterable: I) -> usize - where I: IntoIterator, - K: Hash + Eq, -{ - let iter = iterable.into_iter(); - let current_used = used.len(); - used.extend(iter.map(|key| (key, ()))); - used.len() - current_used -} - -impl Iterator for UniqueBy - where I: Iterator, - V: Eq + Hash, - F: FnMut(&I::Item) -> V -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - while let Some(v) = self.iter.next() { - let key = (self.f)(&v); - if self.used.insert(key, ()).is_none() { - return Some(v); - } - } - None - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, hi) = self.iter.size_hint(); - ((low > 0 && self.used.is_empty()) as usize, hi) - } - - fn count(self) -> usize { - let mut key_f = self.f; - count_new_keys(self.used, self.iter.map(move |elt| key_f(&elt))) - } -} - -impl Iterator for Unique - where I: Iterator, - I::Item: Eq + Hash + Clone -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - while let Some(v) = self.iter.iter.next() { - if let Entry::Vacant(entry) = self.iter.used.entry(v) { - let elt = entry.key().clone(); - entry.insert(()); - return Some(elt); - } - } - None - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, hi) = self.iter.iter.size_hint(); - ((low > 0 && self.iter.used.is_empty()) as usize, hi) - } - - fn count(self) -> usize { - count_new_keys(self.iter.used, self.iter.iter) - } -} - -/// An iterator adapter to filter out duplicate elements. -/// -/// See [`.unique()`](../trait.Itertools.html#method.unique) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Unique { - iter: UniqueBy, -} - -impl fmt::Debug for Unique - where I: Iterator + fmt::Debug, - I::Item: Hash + Eq + fmt::Debug, -{ - debug_fmt_fields!(Unique, iter); -} - -pub fn unique(iter: I) -> Unique - where I: Iterator, - I::Item: Eq + Hash, -{ - Unique { - iter: UniqueBy { - iter: iter, - used: HashMap::new(), - f: (), - } - } -} diff --git a/vendor/itertools-0.8.2/src/with_position.rs b/vendor/itertools-0.8.2/src/with_position.rs deleted file mode 100644 index 2a7c2b8ad6..0000000000 --- a/vendor/itertools-0.8.2/src/with_position.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::iter::{Fuse,Peekable}; - -/// An iterator adaptor that wraps each element in an [`Position`](../enum.Position.html). -/// -/// Iterator element type is `Position`. -/// -/// See [`.with_position()`](../trait.Itertools.html#method.with_position) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct WithPosition - where I: Iterator, -{ - handled_first: bool, - peekable: Peekable>, -} - -/// Create a new `WithPosition` iterator. -pub fn with_position(iter: I) -> WithPosition - where I: Iterator, -{ - WithPosition { - handled_first: false, - peekable: iter.fuse().peekable(), - } -} - -/// A value yielded by `WithPosition`. -/// Indicates the position of this element in the iterator results. -/// -/// See [`.with_position()`](trait.Itertools.html#method.with_position) for more information. -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum Position { - /// This is the first element. - First(T), - /// This is neither the first nor the last element. - Middle(T), - /// This is the last element. - Last(T), - /// This is the only element. - Only(T), -} - -impl Position { - /// Return the inner value. - pub fn into_inner(self) -> T { - match self { - Position::First(x) | - Position::Middle(x) | - Position::Last(x) | - Position::Only(x) => x, - } - } -} - -impl Iterator for WithPosition { - type Item = Position; - - fn next(&mut self) -> Option { - match self.peekable.next() { - Some(item) => { - if !self.handled_first { - // Haven't seen the first item yet, and there is one to give. - self.handled_first = true; - // Peek to see if this is also the last item, - // in which case tag it as `Only`. - match self.peekable.peek() { - Some(_) => Some(Position::First(item)), - None => Some(Position::Only(item)), - } - } else { - // Have seen the first item, and there's something left. - // Peek to see if this is the last item. - match self.peekable.peek() { - Some(_) => Some(Position::Middle(item)), - None => Some(Position::Last(item)), - } - } - } - // Iterator is finished. - None => None, - } - } - - fn size_hint(&self) -> (usize, Option) { - self.peekable.size_hint() - } -} - -impl ExactSizeIterator for WithPosition - where I: ExactSizeIterator, -{ } diff --git a/vendor/itertools-0.8.2/src/zip_eq_impl.rs b/vendor/itertools-0.8.2/src/zip_eq_impl.rs deleted file mode 100644 index 857465da41..0000000000 --- a/vendor/itertools-0.8.2/src/zip_eq_impl.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::size_hint; - -/// An iterator which iterates two other iterators simultaneously -/// -/// See [`.zip_eq()`](../trait.Itertools.html#method.zip_eq) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct ZipEq { - a: I, - b: J, -} - -/// Iterate `i` and `j` in lock step. -/// -/// **Panics** if the iterators are not of the same length. -/// -/// `IntoIterator` enabled version of `i.zip_eq(j)`. -/// -/// ``` -/// use itertools::zip_eq; -/// -/// let data = [1, 2, 3, 4, 5]; -/// for (a, b) in zip_eq(&data[..data.len() - 1], &data[1..]) { -/// /* loop body */ -/// } -/// ``` -pub fn zip_eq(i: I, j: J) -> ZipEq - where I: IntoIterator, - J: IntoIterator -{ - ZipEq { - a: i.into_iter(), - b: j.into_iter(), - } -} - -impl Iterator for ZipEq - where I: Iterator, - J: Iterator -{ - type Item = (I::Item, J::Item); - - fn next(&mut self) -> Option { - match (self.a.next(), self.b.next()) { - (None, None) => None, - (Some(a), Some(b)) => Some((a, b)), - (None, Some(_)) | (Some(_), None) => - panic!("itertools: .zip_eq() reached end of one iterator before the other") - } - } - - fn size_hint(&self) -> (usize, Option) { - size_hint::min(self.a.size_hint(), self.b.size_hint()) - } -} - -impl ExactSizeIterator for ZipEq - where I: ExactSizeIterator, - J: ExactSizeIterator -{} diff --git a/vendor/itertools-0.8.2/src/zip_longest.rs b/vendor/itertools-0.8.2/src/zip_longest.rs deleted file mode 100644 index 68a381acee..0000000000 --- a/vendor/itertools-0.8.2/src/zip_longest.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::cmp::Ordering::{Equal, Greater, Less}; -use super::size_hint; -use std::iter::Fuse; - -use either_or_both::EitherOrBoth; - -// ZipLongest originally written by SimonSapin, -// and dedicated to itertools https://github.com/rust-lang/rust/pull/19283 - -/// An iterator which iterates two other iterators simultaneously -/// -/// This iterator is *fused*. -/// -/// See [`.zip_longest()`](../trait.Itertools.html#method.zip_longest) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct ZipLongest { - a: Fuse, - b: Fuse, -} - -/// Create a new `ZipLongest` iterator. -pub fn zip_longest(a: T, b: U) -> ZipLongest - where T: Iterator, - U: Iterator -{ - ZipLongest { - a: a.fuse(), - b: b.fuse(), - } -} - -impl Iterator for ZipLongest - where T: Iterator, - U: Iterator -{ - type Item = EitherOrBoth; - - #[inline] - fn next(&mut self) -> Option { - match (self.a.next(), self.b.next()) { - (None, None) => None, - (Some(a), None) => Some(EitherOrBoth::Left(a)), - (None, Some(b)) => Some(EitherOrBoth::Right(b)), - (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)), - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - size_hint::max(self.a.size_hint(), self.b.size_hint()) - } -} - -impl DoubleEndedIterator for ZipLongest - where T: DoubleEndedIterator + ExactSizeIterator, - U: DoubleEndedIterator + ExactSizeIterator -{ - #[inline] - fn next_back(&mut self) -> Option { - match self.a.len().cmp(&self.b.len()) { - Equal => match (self.a.next_back(), self.b.next_back()) { - (None, None) => None, - (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)), - // These can only happen if .len() is inconsistent with .next_back() - (Some(a), None) => Some(EitherOrBoth::Left(a)), - (None, Some(b)) => Some(EitherOrBoth::Right(b)), - }, - Greater => self.a.next_back().map(EitherOrBoth::Left), - Less => self.b.next_back().map(EitherOrBoth::Right), - } - } -} - -impl ExactSizeIterator for ZipLongest - where T: ExactSizeIterator, - U: ExactSizeIterator -{} diff --git a/vendor/itertools-0.8.2/src/ziptuple.rs b/vendor/itertools-0.8.2/src/ziptuple.rs deleted file mode 100644 index 2dc3ea5e0b..0000000000 --- a/vendor/itertools-0.8.2/src/ziptuple.rs +++ /dev/null @@ -1,111 +0,0 @@ -use super::size_hint; - -/// See [`multizip`](../fn.multizip.html) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Zip { - t: T, -} - -/// An iterator that generalizes *.zip()* and allows running multiple iterators in lockstep. -/// -/// The iterator `Zip<(I, J, ..., M)>` is formed from a tuple of iterators (or values that -/// implement `IntoIterator`) and yields elements -/// until any of the subiterators yields `None`. -/// -/// The iterator element type is a tuple like like `(A, B, ..., E)` where `A` to `E` are the -/// element types of the subiterator. -/// -/// **Note:** The result of this macro is a value of a named type (`Zip<(I, J, -/// ..)>` of each component iterator `I, J, ...`) if each component iterator is -/// nameable. -/// -/// Prefer [`izip!()`] over `multizip` for the performance benefits of using the -/// standard library `.zip()`. Prefer `multizip` if a nameable type is needed. -/// -/// [`izip!()`]: macro.izip.html -/// -/// ``` -/// use itertools::multizip; -/// -/// // iterate over three sequences side-by-side -/// let mut results = [0, 0, 0, 0]; -/// let inputs = [3, 7, 9, 6]; -/// -/// for (r, index, input) in multizip((&mut results, 0..10, &inputs)) { -/// *r = index * 10 + input; -/// } -/// -/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); -/// ``` -pub fn multizip(t: U) -> Zip - where Zip: From, - Zip: Iterator, -{ - Zip::from(t) -} - -macro_rules! impl_zip_iter { - ($($B:ident),*) => ( - #[allow(non_snake_case)] - impl<$($B: IntoIterator),*> From<($($B,)*)> for Zip<($($B::IntoIter,)*)> { - fn from(t: ($($B,)*)) -> Self { - let ($($B,)*) = t; - Zip { t: ($($B.into_iter(),)*) } - } - } - - #[allow(non_snake_case)] - #[allow(unused_assignments)] - impl<$($B),*> Iterator for Zip<($($B,)*)> - where - $( - $B: Iterator, - )* - { - type Item = ($($B::Item,)*); - - fn next(&mut self) -> Option - { - let ($(ref mut $B,)*) = self.t; - - // NOTE: Just like iter::Zip, we check the iterators - // for None in order. We may finish unevenly (some - // iterators gave n + 1 elements, some only n). - $( - let $B = match $B.next() { - None => return None, - Some(elt) => elt - }; - )* - Some(($($B,)*)) - } - - fn size_hint(&self) -> (usize, Option) - { - let sh = (::std::usize::MAX, None); - let ($(ref $B,)*) = self.t; - $( - let sh = size_hint::min($B.size_hint(), sh); - )* - sh - } - } - - #[allow(non_snake_case)] - impl<$($B),*> ExactSizeIterator for Zip<($($B,)*)> where - $( - $B: ExactSizeIterator, - )* - { } - ); -} - -impl_zip_iter!(A); -impl_zip_iter!(A, B); -impl_zip_iter!(A, B, C); -impl_zip_iter!(A, B, C, D); -impl_zip_iter!(A, B, C, D, E); -impl_zip_iter!(A, B, C, D, E, F); -impl_zip_iter!(A, B, C, D, E, F, G); -impl_zip_iter!(A, B, C, D, E, F, G, H); diff --git a/vendor/itertools-0.8.2/tests/adaptors_no_collect.rs b/vendor/itertools-0.8.2/tests/adaptors_no_collect.rs deleted file mode 100644 index 4da6fcf4e9..0000000000 --- a/vendor/itertools-0.8.2/tests/adaptors_no_collect.rs +++ /dev/null @@ -1,49 +0,0 @@ -extern crate itertools; - -use itertools::Itertools; - -struct PanickingCounter { - curr: usize, - max: usize, -} - -impl Iterator for PanickingCounter { - type Item = (); - - fn next(&mut self) -> Option { - self.curr += 1; - - if self.curr == self.max { - panic!( - "Input iterator reached maximum of {} suggesting collection by adaptor", - self.max - ); - } - - Some(()) - } -} - -fn no_collect_test(to_adaptor: T) - where A: Iterator, T: Fn(PanickingCounter) -> A -{ - let counter = PanickingCounter { curr: 0, max: 10_000 }; - let adaptor = to_adaptor(counter); - - for _ in adaptor.take(5) {} -} - -#[test] -fn permutations_no_collect() { - no_collect_test(|iter| iter.permutations(5)) -} - -#[test] -fn combinations_no_collect() { - no_collect_test(|iter| iter.combinations(5)) -} - -#[test] -fn combinations_with_replacement_no_collect() { - no_collect_test(|iter| iter.combinations_with_replacement(5)) -} \ No newline at end of file diff --git a/vendor/itertools-0.8.2/tests/fold_specialization.rs b/vendor/itertools-0.8.2/tests/fold_specialization.rs deleted file mode 100644 index ac5d6a25dc..0000000000 --- a/vendor/itertools-0.8.2/tests/fold_specialization.rs +++ /dev/null @@ -1,15 +0,0 @@ -extern crate itertools; - -use itertools::Itertools; - -#[test] -fn specialization_intersperse() { - let mut iter = (1..2).intersperse(0); - iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); - - let mut iter = (1..3).intersperse(0); - iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); - - let mut iter = (1..4).intersperse(0); - iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); -} diff --git a/vendor/itertools-0.8.2/tests/merge_join.rs b/vendor/itertools-0.8.2/tests/merge_join.rs deleted file mode 100644 index 41829202b8..0000000000 --- a/vendor/itertools-0.8.2/tests/merge_join.rs +++ /dev/null @@ -1,110 +0,0 @@ -extern crate itertools; - -use itertools::EitherOrBoth; -use itertools::free::merge_join_by; - -#[test] -fn empty() { - let left: Vec = vec![]; - let right: Vec = vec![]; - let expected_result: Vec> = vec![]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn left_only() { - let left: Vec = vec![1,2,3]; - let right: Vec = vec![]; - let expected_result: Vec> = vec![ - EitherOrBoth::Left(1), - EitherOrBoth::Left(2), - EitherOrBoth::Left(3) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn right_only() { - let left: Vec = vec![]; - let right: Vec = vec![1,2,3]; - let expected_result: Vec> = vec![ - EitherOrBoth::Right(1), - EitherOrBoth::Right(2), - EitherOrBoth::Right(3) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn first_left_then_right() { - let left: Vec = vec![1,2,3]; - let right: Vec = vec![4,5,6]; - let expected_result: Vec> = vec![ - EitherOrBoth::Left(1), - EitherOrBoth::Left(2), - EitherOrBoth::Left(3), - EitherOrBoth::Right(4), - EitherOrBoth::Right(5), - EitherOrBoth::Right(6) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn first_right_then_left() { - let left: Vec = vec![4,5,6]; - let right: Vec = vec![1,2,3]; - let expected_result: Vec> = vec![ - EitherOrBoth::Right(1), - EitherOrBoth::Right(2), - EitherOrBoth::Right(3), - EitherOrBoth::Left(4), - EitherOrBoth::Left(5), - EitherOrBoth::Left(6) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn interspersed_left_and_right() { - let left: Vec = vec![1,3,5]; - let right: Vec = vec![2,4,6]; - let expected_result: Vec> = vec![ - EitherOrBoth::Left(1), - EitherOrBoth::Right(2), - EitherOrBoth::Left(3), - EitherOrBoth::Right(4), - EitherOrBoth::Left(5), - EitherOrBoth::Right(6) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn overlapping_left_and_right() { - let left: Vec = vec![1,3,4,6]; - let right: Vec = vec![2,3,4,5]; - let expected_result: Vec> = vec![ - EitherOrBoth::Left(1), - EitherOrBoth::Right(2), - EitherOrBoth::Both(3, 3), - EitherOrBoth::Both(4, 4), - EitherOrBoth::Right(5), - EitherOrBoth::Left(6) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} diff --git a/vendor/itertools-0.8.2/tests/peeking_take_while.rs b/vendor/itertools-0.8.2/tests/peeking_take_while.rs deleted file mode 100644 index 45c76c2d5c..0000000000 --- a/vendor/itertools-0.8.2/tests/peeking_take_while.rs +++ /dev/null @@ -1,53 +0,0 @@ - -extern crate itertools; - -use itertools::Itertools; -use itertools::{put_back, put_back_n}; - -#[test] -fn peeking_take_while_peekable() { - let mut r = (0..10).peekable(); - r.peeking_take_while(|x| *x <= 3).count(); - assert_eq!(r.next(), Some(4)); -} - -#[test] -fn peeking_take_while_put_back() { - let mut r = put_back(0..10); - r.peeking_take_while(|x| *x <= 3).count(); - assert_eq!(r.next(), Some(4)); - r.peeking_take_while(|_| true).count(); - assert_eq!(r.next(), None); -} - -#[test] -fn peeking_take_while_put_back_n() { - let mut r = put_back_n(6..10); - for elt in (0..6).rev() { - r.put_back(elt); - } - r.peeking_take_while(|x| *x <= 3).count(); - assert_eq!(r.next(), Some(4)); - r.peeking_take_while(|_| true).count(); - assert_eq!(r.next(), None); -} - -#[test] -fn peeking_take_while_slice_iter() { - let v = [1, 2, 3, 4, 5, 6]; - let mut r = v.iter(); - r.peeking_take_while(|x| **x <= 3).count(); - assert_eq!(r.next(), Some(&4)); - r.peeking_take_while(|_| true).count(); - assert_eq!(r.next(), None); -} - -#[test] -fn peeking_take_while_slice_iter_rev() { - let v = [1, 2, 3, 4, 5, 6]; - let mut r = v.iter().rev(); - r.peeking_take_while(|x| **x >= 3).count(); - assert_eq!(r.next(), Some(&2)); - r.peeking_take_while(|_| true).count(); - assert_eq!(r.next(), None); -} diff --git a/vendor/itertools-0.8.2/tests/quick.rs b/vendor/itertools-0.8.2/tests/quick.rs deleted file mode 100644 index 7767447268..0000000000 --- a/vendor/itertools-0.8.2/tests/quick.rs +++ /dev/null @@ -1,1161 +0,0 @@ -//! The purpose of these tests is to cover corner cases of iterators -//! and adaptors. -//! -//! In particular we test the tedious size_hint and exact size correctness. - -#[macro_use] extern crate itertools; - -extern crate quickcheck; -extern crate rand; - -use std::default::Default; - -use quickcheck as qc; -use std::ops::Range; -use std::cmp::{max, min, Ordering}; -use std::collections::HashSet; -use itertools::Itertools; -use itertools::{ - multizip, - EitherOrBoth, -}; -use itertools::free::{ - cloned, - enumerate, - multipeek, - put_back, - put_back_n, - rciter, - zip, - zip_eq, -}; - -use rand::Rng; -use rand::seq::SliceRandom; -use quickcheck::TestResult; - -/// Trait for size hint modifier types -trait HintKind: Copy + Send + qc::Arbitrary { - fn loosen_bounds(&self, org_hint: (usize, Option)) -> (usize, Option); -} - -/// Exact size hint variant that leaves hints unchanged -#[derive(Clone, Copy, Debug)] -struct Exact {} - -impl HintKind for Exact { - fn loosen_bounds(&self, org_hint: (usize, Option)) -> (usize, Option) { - org_hint - } -} - -impl qc::Arbitrary for Exact { - fn arbitrary(_: &mut G) -> Self { - Exact {} - } -} - -/// Inexact size hint variant to simulate imprecise (but valid) size hints -/// -/// Will always decrease the lower bound and increase the upper bound -/// of the size hint by set amounts. -#[derive(Clone, Copy, Debug)] -struct Inexact { - underestimate: usize, - overestimate: usize, -} - -impl HintKind for Inexact { - fn loosen_bounds(&self, org_hint: (usize, Option)) -> (usize, Option) { - let (org_lower, org_upper) = org_hint; - (org_lower.saturating_sub(self.underestimate), - org_upper.and_then(move |x| x.checked_add(self.overestimate))) - } -} - -impl qc::Arbitrary for Inexact { - fn arbitrary(g: &mut G) -> Self { - let ue_value = usize::arbitrary(g); - let oe_value = usize::arbitrary(g); - // Compensate for quickcheck using extreme values too rarely - let ue_choices = &[0, ue_value, usize::max_value()]; - let oe_choices = &[0, oe_value, usize::max_value()]; - Inexact { - underestimate: *ue_choices.choose(g).unwrap(), - overestimate: *oe_choices.choose(g).unwrap(), - } - } - - fn shrink(&self) -> Box> { - let underestimate_value = self.underestimate; - let overestimate_value = self.overestimate; - Box::new( - underestimate_value.shrink().flat_map(move |ue_value| - overestimate_value.shrink().map(move |oe_value| - Inexact { - underestimate: ue_value, - overestimate: oe_value, - } - ) - ) - ) - } -} - -/// Our base iterator that we can impl Arbitrary for -/// -/// By default we'll return inexact bounds estimates for size_hint -/// to make tests harder to pass. -/// -/// NOTE: Iter is tricky and is not fused, to help catch bugs. -/// At the end it will return None once, then return Some(0), -/// then return None again. -#[derive(Clone, Debug)] -struct Iter { - iterator: Range, - // fuse/done flag - fuse_flag: i32, - hint_kind: SK, -} - -impl Iter where HK: HintKind -{ - fn new(it: Range, hint_kind: HK) -> Self { - Iter { - iterator: it, - fuse_flag: 0, - hint_kind: hint_kind - } - } -} - -impl Iterator for Iter - where Range: Iterator, - as Iterator>::Item: Default, - HK: HintKind, -{ - type Item = as Iterator>::Item; - - fn next(&mut self) -> Option - { - let elt = self.iterator.next(); - if elt.is_none() { - self.fuse_flag += 1; - // check fuse flag - if self.fuse_flag == 2 { - return Some(Default::default()) - } - } - elt - } - - fn size_hint(&self) -> (usize, Option) - { - let org_hint = self.iterator.size_hint(); - self.hint_kind.loosen_bounds(org_hint) - } -} - -impl DoubleEndedIterator for Iter - where Range: DoubleEndedIterator, - as Iterator>::Item: Default, - HK: HintKind -{ - fn next_back(&mut self) -> Option { self.iterator.next_back() } -} - -impl ExactSizeIterator for Iter where Range: ExactSizeIterator, - as Iterator>::Item: Default, -{ } - -impl qc::Arbitrary for Iter - where T: qc::Arbitrary, - HK: HintKind, -{ - fn arbitrary(g: &mut G) -> Self - { - Iter::new(T::arbitrary(g)..T::arbitrary(g), HK::arbitrary(g)) - } - - fn shrink(&self) -> Box>> - { - let r = self.iterator.clone(); - let hint_kind = self.hint_kind; - Box::new( - r.start.shrink().flat_map(move |a| - r.end.shrink().map(move |b| - Iter::new(a.clone()..b, hint_kind) - ) - ) - ) - } -} - -/// A meta-iterator which yields `Iter`s whose start/endpoints are -/// increased or decreased linearly on each iteration. -#[derive(Clone, Debug)] -struct ShiftRange { - range_start: i32, - range_end: i32, - start_step: i32, - end_step: i32, - iter_count: u32, - hint_kind: HK, -} - -impl Iterator for ShiftRange where HK: HintKind { - type Item = Iter; - - fn next(&mut self) -> Option { - if self.iter_count == 0 { - return None; - } - - let iter = Iter::new(self.range_start..self.range_end, self.hint_kind); - - self.range_start += self.start_step; - self.range_end += self.end_step; - self.iter_count -= 1; - - Some(iter) - } -} - -impl ExactSizeIterator for ShiftRange { } - -impl qc::Arbitrary for ShiftRange - where HK: HintKind -{ - fn arbitrary(g: &mut G) -> Self { - const MAX_STARTING_RANGE_DIFF: i32 = 32; - const MAX_STEP_MODULO: i32 = 8; - const MAX_ITER_COUNT: u32 = 3; - - let range_start = qc::Arbitrary::arbitrary(g); - let range_end = range_start + g.gen_range(0, MAX_STARTING_RANGE_DIFF + 1); - let start_step = g.gen_range(-MAX_STEP_MODULO, MAX_STEP_MODULO + 1); - let end_step = g.gen_range(-MAX_STEP_MODULO, MAX_STEP_MODULO + 1); - let iter_count = g.gen_range(0, MAX_ITER_COUNT + 1); - let hint_kind = qc::Arbitrary::arbitrary(g); - - ShiftRange { - range_start: range_start, - range_end: range_end, - start_step: start_step, - end_step: end_step, - iter_count: iter_count, - hint_kind: hint_kind - } - } -} - -fn correct_count(get_it: F) -> bool -where - I: Iterator, - F: Fn() -> I -{ - let mut counts = vec![get_it().count()]; - - 'outer: loop { - let mut it = get_it(); - - for _ in 0..(counts.len() - 1) { - if let None = it.next() { - panic!("Iterator shouldn't be finished, may not be deterministic"); - } - } - - if let None = it.next() { - break 'outer; - } - - counts.push(it.count()); - } - - let total_actual_count = counts.len() - 1; - - for (i, returned_count) in counts.into_iter().enumerate() { - let actual_count = total_actual_count - i; - if actual_count != returned_count { - println!("Total iterations: {} True count: {} returned count: {}", i, actual_count, returned_count); - - return false; - } - } - - true -} - -fn correct_size_hint(mut it: I) -> bool { - // record size hint at each iteration - let initial_hint = it.size_hint(); - let mut hints = Vec::with_capacity(initial_hint.0 + 1); - hints.push(initial_hint); - while let Some(_) = it.next() { - hints.push(it.size_hint()) - } - - let mut true_count = hints.len(); // start off +1 too much - - // check all the size hints - for &(low, hi) in &hints { - true_count -= 1; - if low > true_count || - (hi.is_some() && hi.unwrap() < true_count) - { - println!("True size: {:?}, size hint: {:?}", true_count, (low, hi)); - //println!("All hints: {:?}", hints); - return false - } - } - true -} - -fn exact_size(mut it: I) -> bool { - // check every iteration - let (mut low, mut hi) = it.size_hint(); - if Some(low) != hi { return false; } - while let Some(_) = it.next() { - let (xlow, xhi) = it.size_hint(); - if low != xlow + 1 { return false; } - low = xlow; - hi = xhi; - if Some(low) != hi { return false; } - } - let (low, hi) = it.size_hint(); - low == 0 && hi == Some(0) -} - -// Exact size for this case, without ExactSizeIterator -fn exact_size_for_this(mut it: I) -> bool { - // check every iteration - let (mut low, mut hi) = it.size_hint(); - if Some(low) != hi { return false; } - while let Some(_) = it.next() { - let (xlow, xhi) = it.size_hint(); - if low != xlow + 1 { return false; } - low = xlow; - hi = xhi; - if Some(low) != hi { return false; } - } - let (low, hi) = it.size_hint(); - low == 0 && hi == Some(0) -} - -/* - * NOTE: Range is broken! - * (all signed ranges are) -#[quickcheck] -fn size_range_i8(a: Iter) -> bool { - exact_size(a) -} - -#[quickcheck] -fn size_range_i16(a: Iter) -> bool { - exact_size(a) -} - -#[quickcheck] -fn size_range_u8(a: Iter) -> bool { - exact_size(a) -} - */ - -macro_rules! quickcheck { - // accept several property function definitions - // The property functions can use pattern matching and `mut` as usual - // in the function arguments, but the functions can not be generic. - {$($(#$attr:tt)* fn $fn_name:ident($($arg:tt)*) -> $ret:ty { $($code:tt)* })*} => ( - $( - #[test] - $(#$attr)* - fn $fn_name() { - fn prop($($arg)*) -> $ret { - $($code)* - } - ::quickcheck::quickcheck(quickcheck!(@fn prop [] $($arg)*)); - } - )* - ); - // parse argument list (with patterns allowed) into prop as fn(_, _) -> _ - (@fn $f:ident [$($t:tt)*]) => { - $f as fn($($t),*) -> _ - }; - (@fn $f:ident [$($p:tt)*] : $($tail:tt)*) => { - quickcheck!(@fn $f [$($p)* _] $($tail)*) - }; - (@fn $f:ident [$($p:tt)*] $t:tt $($tail:tt)*) => { - quickcheck!(@fn $f [$($p)*] $($tail)*) - }; -} - -quickcheck! { - - fn size_product(a: Iter, b: Iter) -> bool { - correct_size_hint(a.cartesian_product(b)) - } - fn size_product3(a: Iter, b: Iter, c: Iter) -> bool { - correct_size_hint(iproduct!(a, b, c)) - } - - fn correct_cartesian_product3(a: Iter, b: Iter, c: Iter, - take_manual: usize) -> () - { - // test correctness of iproduct through regular iteration (take) - // and through fold. - let ac = a.clone(); - let br = &b.clone(); - let cr = &c.clone(); - let answer: Vec<_> = ac.flat_map(move |ea| br.clone().flat_map(move |eb| cr.clone().map(move |ec| (ea, eb, ec)))).collect(); - let mut product_iter = iproduct!(a, b, c); - let mut actual = Vec::new(); - - actual.extend((&mut product_iter).take(take_manual)); - if actual.len() == take_manual { - product_iter.fold((), |(), elt| actual.push(elt)); - } - assert_eq!(answer, actual); - } - - fn size_multi_product(a: ShiftRange) -> bool { - correct_size_hint(a.multi_cartesian_product()) - } - fn correct_multi_product3(a: ShiftRange, take_manual: usize) -> () { - // Fix no. of iterators at 3 - let a = ShiftRange { iter_count: 3, ..a }; - - // test correctness of MultiProduct through regular iteration (take) - // and through fold. - let mut iters = a.clone(); - let i0 = iters.next().unwrap(); - let i1r = &iters.next().unwrap(); - let i2r = &iters.next().unwrap(); - let answer: Vec<_> = i0.flat_map(move |ei0| i1r.clone().flat_map(move |ei1| i2r.clone().map(move |ei2| vec![ei0, ei1, ei2]))).collect(); - let mut multi_product = a.clone().multi_cartesian_product(); - let mut actual = Vec::new(); - - actual.extend((&mut multi_product).take(take_manual)); - if actual.len() == take_manual { - multi_product.fold((), |(), elt| actual.push(elt)); - } - assert_eq!(answer, actual); - - assert_eq!(answer.into_iter().last(), a.clone().multi_cartesian_product().last()); - } - - #[allow(deprecated)] - fn size_step(a: Iter, s: usize) -> bool { - let mut s = s; - if s == 0 { - s += 1; // never zero - } - let filt = a.clone().dedup(); - correct_size_hint(filt.step(s)) && - exact_size(a.step(s)) - } - - #[allow(deprecated)] - fn equal_step(a: Iter, s: usize) -> bool { - let mut s = s; - if s == 0 { - s += 1; // never zero - } - let mut i = 0; - itertools::equal(a.clone().step(s), a.filter(|_| { - let keep = i % s == 0; - i += 1; - keep - })) - } - - #[allow(deprecated)] - fn equal_step_vec(a: Vec, s: usize) -> bool { - let mut s = s; - if s == 0 { - s += 1; // never zero - } - let mut i = 0; - itertools::equal(a.iter().step(s), a.iter().filter(|_| { - let keep = i % s == 0; - i += 1; - keep - })) - } - - fn size_multipeek(a: Iter, s: u8) -> bool { - let mut it = multipeek(a); - // peek a few times - for _ in 0..s { - it.peek(); - } - exact_size(it) - } - - fn equal_merge(a: Vec, b: Vec) -> bool { - let mut sa = a.clone(); - let mut sb = b.clone(); - sa.sort(); - sb.sort(); - let mut merged = sa.clone(); - merged.extend(sb.iter().cloned()); - merged.sort(); - itertools::equal(&merged, sa.iter().merge(&sb)) - } - fn size_merge(a: Iter, b: Iter) -> bool { - correct_size_hint(a.merge(b)) - } - fn size_zip(a: Iter, b: Iter, c: Iter) -> bool { - let filt = a.clone().dedup(); - correct_size_hint(multizip((filt, b.clone(), c.clone()))) && - exact_size(multizip((a, b, c))) - } - fn size_zip_rc(a: Iter, b: Iter) -> bool { - let rc = rciter(a.clone()); - correct_size_hint(multizip((&rc, &rc, b))) - } - - fn size_zip_macro(a: Iter, b: Iter, c: Iter) -> bool { - let filt = a.clone().dedup(); - correct_size_hint(izip!(filt, b.clone(), c.clone())) && - exact_size(izip!(a, b, c)) - } - fn equal_kmerge(a: Vec, b: Vec, c: Vec) -> bool { - use itertools::free::kmerge; - let mut sa = a.clone(); - let mut sb = b.clone(); - let mut sc = c.clone(); - sa.sort(); - sb.sort(); - sc.sort(); - let mut merged = sa.clone(); - merged.extend(sb.iter().cloned()); - merged.extend(sc.iter().cloned()); - merged.sort(); - itertools::equal(merged.into_iter(), kmerge(vec![sa, sb, sc])) - } - - // Any number of input iterators - fn equal_kmerge_2(mut inputs: Vec>) -> bool { - use itertools::free::kmerge; - // sort the inputs - for input in &mut inputs { - input.sort(); - } - let mut merged = inputs.concat(); - merged.sort(); - itertools::equal(merged.into_iter(), kmerge(inputs)) - } - - // Any number of input iterators - fn equal_kmerge_by_ge(mut inputs: Vec>) -> bool { - // sort the inputs - for input in &mut inputs { - input.sort(); - input.reverse(); - } - let mut merged = inputs.concat(); - merged.sort(); - merged.reverse(); - itertools::equal(merged.into_iter(), - inputs.into_iter().kmerge_by(|x, y| x >= y)) - } - - // Any number of input iterators - fn equal_kmerge_by_lt(mut inputs: Vec>) -> bool { - // sort the inputs - for input in &mut inputs { - input.sort(); - } - let mut merged = inputs.concat(); - merged.sort(); - itertools::equal(merged.into_iter(), - inputs.into_iter().kmerge_by(|x, y| x < y)) - } - - // Any number of input iterators - fn equal_kmerge_by_le(mut inputs: Vec>) -> bool { - // sort the inputs - for input in &mut inputs { - input.sort(); - } - let mut merged = inputs.concat(); - merged.sort(); - itertools::equal(merged.into_iter(), - inputs.into_iter().kmerge_by(|x, y| x <= y)) - } - fn size_kmerge(a: Iter, b: Iter, c: Iter) -> bool { - use itertools::free::kmerge; - correct_size_hint(kmerge(vec![a, b, c])) - } - fn equal_zip_eq(a: Vec, b: Vec) -> bool { - let len = std::cmp::min(a.len(), b.len()); - let a = &a[..len]; - let b = &b[..len]; - itertools::equal(zip_eq(a, b), zip(a, b)) - } - fn size_zip_longest(a: Iter, b: Iter) -> bool { - let filt = a.clone().dedup(); - let filt2 = b.clone().dedup(); - correct_size_hint(filt.zip_longest(b.clone())) && - correct_size_hint(a.clone().zip_longest(filt2)) && - exact_size(a.zip_longest(b)) - } - fn size_2_zip_longest(a: Iter, b: Iter) -> bool { - let it = a.clone().zip_longest(b.clone()); - let jt = a.clone().zip_longest(b.clone()); - itertools::equal(a.clone(), - it.filter_map(|elt| match elt { - EitherOrBoth::Both(x, _) => Some(x), - EitherOrBoth::Left(x) => Some(x), - _ => None, - } - )) - && - itertools::equal(b.clone(), - jt.filter_map(|elt| match elt { - EitherOrBoth::Both(_, y) => Some(y), - EitherOrBoth::Right(y) => Some(y), - _ => None, - } - )) - } - fn size_interleave(a: Iter, b: Iter) -> bool { - correct_size_hint(a.interleave(b)) - } - fn exact_interleave(a: Iter, b: Iter) -> bool { - exact_size_for_this(a.interleave(b)) - } - fn size_interleave_shortest(a: Iter, b: Iter) -> bool { - correct_size_hint(a.interleave_shortest(b)) - } - fn exact_interleave_shortest(a: Vec<()>, b: Vec<()>) -> bool { - exact_size_for_this(a.iter().interleave_shortest(&b)) - } - fn size_intersperse(a: Iter, x: i16) -> bool { - correct_size_hint(a.intersperse(x)) - } - fn equal_intersperse(a: Vec, x: i32) -> bool { - let mut inter = false; - let mut i = 0; - for elt in a.iter().cloned().intersperse(x) { - if inter { - if elt != x { return false } - } else { - if elt != a[i] { return false } - i += 1; - } - inter = !inter; - } - true - } - - fn equal_combinations_2(a: Vec) -> bool { - let mut v = Vec::new(); - for (i, x) in enumerate(&a) { - for y in &a[i + 1..] { - v.push((x, y)); - } - } - itertools::equal(a.iter().tuple_combinations::<(_, _)>(), v) - } - - fn collect_tuple_matches_size(a: Iter) -> bool { - let size = a.clone().count(); - a.collect_tuple::<(_, _, _)>().is_some() == (size == 3) - } - - fn correct_permutations(vals: HashSet, k: usize) -> () { - // Test permutations only on iterators of distinct integers, to prevent - // false positives. - - const MAX_N: usize = 5; - - let n = min(vals.len(), MAX_N); - let vals: HashSet = vals.into_iter().take(n).collect(); - - let perms = vals.iter().permutations(k); - - let mut actual = HashSet::new(); - - for perm in perms { - assert_eq!(perm.len(), k); - - let all_items_valid = perm.iter().all(|p| vals.contains(p)); - assert!(all_items_valid, "perm contains value not from input: {:?}", perm); - - // Check that all perm items are distinct - let distinct_len = { - let perm_set: HashSet<_> = perm.iter().collect(); - perm_set.len() - }; - assert_eq!(perm.len(), distinct_len); - - // Check that the perm is new - assert!(actual.insert(perm.clone()), "perm already encountered: {:?}", perm); - } - } - - fn permutations_lexic_order(a: usize, b: usize) -> () { - let a = a % 6; - let b = b % 6; - - let n = max(a, b); - let k = min (a, b); - - let expected_first: Vec = (0..k).collect(); - let expected_last: Vec = ((n - k)..n).rev().collect(); - - let mut perms = (0..n).permutations(k); - - let mut curr_perm = match perms.next() { - Some(p) => p, - None => { return; } - }; - - assert_eq!(expected_first, curr_perm); - - while let Some(next_perm) = perms.next() { - assert!( - next_perm > curr_perm, - "next perm isn't greater-than current; next_perm={:?} curr_perm={:?} n={}", - next_perm, curr_perm, n - ); - - curr_perm = next_perm; - } - - assert_eq!(expected_last, curr_perm); - - } - - fn permutations_count(n: usize, k: usize) -> bool { - let n = n % 6; - - correct_count(|| (0..n).permutations(k)) - } - - fn permutations_size(a: Iter, k: usize) -> bool { - correct_size_hint(a.take(5).permutations(k)) - } - - fn permutations_k0_yields_once(n: usize) -> () { - let k = 0; - let expected: Vec> = vec![vec![]]; - let actual = (0..n).permutations(k).collect_vec(); - - assert_eq!(expected, actual); - } -} - -quickcheck! { - fn equal_dedup(a: Vec) -> bool { - let mut b = a.clone(); - b.dedup(); - itertools::equal(&b, a.iter().dedup()) - } -} - -quickcheck! { - fn equal_dedup_by(a: Vec<(i32, i32)>) -> bool { - let mut b = a.clone(); - b.dedup_by(|x, y| x.0==y.0); - itertools::equal(&b, a.iter().dedup_by(|x, y| x.0==y.0)) - } -} - -quickcheck! { - fn size_dedup(a: Vec) -> bool { - correct_size_hint(a.iter().dedup()) - } -} - -quickcheck! { - fn size_dedup_by(a: Vec<(i32, i32)>) -> bool { - correct_size_hint(a.iter().dedup_by(|x, y| x.0==y.0)) - } -} - -quickcheck! { - fn exact_repeatn((n, x): (usize, i32)) -> bool { - let it = itertools::repeat_n(x, n); - exact_size(it) - } -} - -quickcheck! { - fn size_put_back(a: Vec, x: Option) -> bool { - let mut it = put_back(a.into_iter()); - match x { - Some(t) => it.put_back(t), - None => {} - } - correct_size_hint(it) - } -} - -quickcheck! { - fn size_put_backn(a: Vec, b: Vec) -> bool { - let mut it = put_back_n(a.into_iter()); - for elt in b { - it.put_back(elt) - } - correct_size_hint(it) - } -} - -quickcheck! { - fn size_tee(a: Vec) -> bool { - let (mut t1, mut t2) = a.iter().tee(); - t1.next(); - t1.next(); - t2.next(); - exact_size(t1) && exact_size(t2) - } -} - -quickcheck! { - fn size_tee_2(a: Vec) -> bool { - let (mut t1, mut t2) = a.iter().dedup().tee(); - t1.next(); - t1.next(); - t2.next(); - correct_size_hint(t1) && correct_size_hint(t2) - } -} - -quickcheck! { - fn size_take_while_ref(a: Vec, stop: u8) -> bool { - correct_size_hint(a.iter().take_while_ref(|x| **x != stop)) - } -} - -quickcheck! { - fn equal_partition(a: Vec) -> bool { - let mut a = a; - let mut ap = a.clone(); - let split_index = itertools::partition(&mut ap, |x| *x >= 0); - let parted = (0..split_index).all(|i| ap[i] >= 0) && - (split_index..a.len()).all(|i| ap[i] < 0); - - a.sort(); - ap.sort(); - parted && (a == ap) - } -} - -quickcheck! { - fn size_combinations(it: Iter) -> bool { - correct_size_hint(it.tuple_combinations::<(_, _)>()) - } -} - -quickcheck! { - fn equal_combinations(it: Iter) -> bool { - let values = it.clone().collect_vec(); - let mut cmb = it.tuple_combinations(); - for i in 0..values.len() { - for j in i+1..values.len() { - let pair = (values[i], values[j]); - if pair != cmb.next().unwrap() { - return false; - } - } - } - cmb.next() == None - } -} - -quickcheck! { - fn size_pad_tail(it: Iter, pad: u8) -> bool { - correct_size_hint(it.clone().pad_using(pad as usize, |_| 0)) && - correct_size_hint(it.dropping(1).rev().pad_using(pad as usize, |_| 0)) - } -} - -quickcheck! { - fn size_pad_tail2(it: Iter, pad: u8) -> bool { - exact_size(it.pad_using(pad as usize, |_| 0)) - } -} - -quickcheck! { - fn size_unique(it: Iter) -> bool { - correct_size_hint(it.unique()) - } - - fn count_unique(it: Vec, take_first: u8) -> () { - let answer = { - let mut v = it.clone(); - v.sort(); v.dedup(); - v.len() - }; - let mut iter = cloned(&it).unique(); - let first_count = (&mut iter).take(take_first as usize).count(); - let rest_count = iter.count(); - assert_eq!(answer, first_count + rest_count); - } -} - -quickcheck! { - fn fuzz_group_by_lazy_1(it: Iter) -> bool { - let jt = it.clone(); - let groups = it.group_by(|k| *k); - let res = itertools::equal(jt, groups.into_iter().flat_map(|(_, x)| x)); - res - } -} - -quickcheck! { - fn fuzz_group_by_lazy_2(data: Vec) -> bool { - let groups = data.iter().group_by(|k| *k / 10); - let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x)); - res - } -} - -quickcheck! { - fn fuzz_group_by_lazy_3(data: Vec) -> bool { - let grouper = data.iter().group_by(|k| *k / 10); - let groups = grouper.into_iter().collect_vec(); - let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x)); - res - } -} - -quickcheck! { - fn fuzz_group_by_lazy_duo(data: Vec, order: Vec<(bool, bool)>) -> bool { - let grouper = data.iter().group_by(|k| *k / 3); - let mut groups1 = grouper.into_iter(); - let mut groups2 = grouper.into_iter(); - let mut elts = Vec::<&u8>::new(); - let mut old_groups = Vec::new(); - - let tup1 = |(_, b)| b; - for &(ord, consume_now) in &order { - let iter = &mut [&mut groups1, &mut groups2][ord as usize]; - match iter.next() { - Some((_, gr)) => if consume_now { - for og in old_groups.drain(..) { - elts.extend(og); - } - elts.extend(gr); - } else { - old_groups.push(gr); - }, - None => break, - } - } - for og in old_groups.drain(..) { - elts.extend(og); - } - for gr in groups1.map(&tup1) { elts.extend(gr); } - for gr in groups2.map(&tup1) { elts.extend(gr); } - itertools::assert_equal(&data, elts); - true - } -} - -quickcheck! { - fn equal_chunks_lazy(a: Vec, size: u8) -> bool { - let mut size = size; - if size == 0 { - size += 1; - } - let chunks = a.iter().chunks(size as usize); - let it = a.chunks(size as usize); - for (a, b) in chunks.into_iter().zip(it) { - if !itertools::equal(a, b) { - return false; - } - } - true - } -} - -quickcheck! { - fn equal_tuple_windows_1(a: Vec) -> bool { - let x = a.windows(1).map(|s| (&s[0], )); - let y = a.iter().tuple_windows::<(_,)>(); - itertools::equal(x, y) - } - - fn equal_tuple_windows_2(a: Vec) -> bool { - let x = a.windows(2).map(|s| (&s[0], &s[1])); - let y = a.iter().tuple_windows::<(_, _)>(); - itertools::equal(x, y) - } - - fn equal_tuple_windows_3(a: Vec) -> bool { - let x = a.windows(3).map(|s| (&s[0], &s[1], &s[2])); - let y = a.iter().tuple_windows::<(_, _, _)>(); - itertools::equal(x, y) - } - - fn equal_tuple_windows_4(a: Vec) -> bool { - let x = a.windows(4).map(|s| (&s[0], &s[1], &s[2], &s[3])); - let y = a.iter().tuple_windows::<(_, _, _, _)>(); - itertools::equal(x, y) - } - - fn equal_tuples_1(a: Vec) -> bool { - let x = a.chunks(1).map(|s| (&s[0], )); - let y = a.iter().tuples::<(_,)>(); - itertools::equal(x, y) - } - - fn equal_tuples_2(a: Vec) -> bool { - let x = a.chunks(2).filter(|s| s.len() == 2).map(|s| (&s[0], &s[1])); - let y = a.iter().tuples::<(_, _)>(); - itertools::equal(x, y) - } - - fn equal_tuples_3(a: Vec) -> bool { - let x = a.chunks(3).filter(|s| s.len() == 3).map(|s| (&s[0], &s[1], &s[2])); - let y = a.iter().tuples::<(_, _, _)>(); - itertools::equal(x, y) - } - - fn equal_tuples_4(a: Vec) -> bool { - let x = a.chunks(4).filter(|s| s.len() == 4).map(|s| (&s[0], &s[1], &s[2], &s[3])); - let y = a.iter().tuples::<(_, _, _, _)>(); - itertools::equal(x, y) - } - - fn exact_tuple_buffer(a: Vec) -> bool { - let mut iter = a.iter().tuples::<(_, _, _, _)>(); - (&mut iter).last(); - let buffer = iter.into_buffer(); - assert_eq!(buffer.len(), a.len() % 4); - exact_size(buffer) - } -} - -// with_position -quickcheck! { - fn with_position_exact_size_1(a: Vec) -> bool { - exact_size_for_this(a.iter().with_position()) - } - fn with_position_exact_size_2(a: Iter) -> bool { - exact_size_for_this(a.with_position()) - } -} - -quickcheck! { - fn correct_group_map_modulo_key(a: Vec, modulo: u8) -> () { - let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0` - let count = a.len(); - let lookup = a.into_iter().map(|i| (i % modulo, i)).into_group_map(); - - assert_eq!(lookup.values().flat_map(|vals| vals.iter()).count(), count); - - for (&key, vals) in lookup.iter() { - assert!(vals.iter().all(|&val| val % modulo == key)); - } - } -} - -/// A peculiar type: Equality compares both tuple items, but ordering only the -/// first item. This is so we can check the stability property easily. -#[derive(Clone, Debug, PartialEq, Eq)] -struct Val(u32, u32); - -impl PartialOrd for Val { - fn partial_cmp(&self, other: &Val) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for Val { - fn cmp(&self, other: &Val) -> Ordering { - self.0.cmp(&other.0) - } -} - -impl qc::Arbitrary for Val { - fn arbitrary(g: &mut G) -> Self { - let (x, y) = <(u32, u32)>::arbitrary(g); - Val(x, y) - } - fn shrink(&self) -> Box> { - Box::new((self.0, self.1).shrink().map(|(x, y)| Val(x, y))) - } -} - -quickcheck! { - fn minmax(a: Vec) -> bool { - use itertools::MinMaxResult; - - - let minmax = a.iter().minmax(); - let expected = match a.len() { - 0 => MinMaxResult::NoElements, - 1 => MinMaxResult::OneElement(&a[0]), - _ => MinMaxResult::MinMax(a.iter().min().unwrap(), - a.iter().max().unwrap()), - }; - minmax == expected - } -} - -quickcheck! { - fn minmax_f64(a: Vec) -> TestResult { - use itertools::MinMaxResult; - - if a.iter().any(|x| x.is_nan()) { - return TestResult::discard(); - } - - let min = cloned(&a).fold1(f64::min); - let max = cloned(&a).fold1(f64::max); - - let minmax = cloned(&a).minmax(); - let expected = match a.len() { - 0 => MinMaxResult::NoElements, - 1 => MinMaxResult::OneElement(min.unwrap()), - _ => MinMaxResult::MinMax(min.unwrap(), max.unwrap()), - }; - TestResult::from_bool(minmax == expected) - } -} - -quickcheck! { - #[allow(deprecated)] - fn tree_fold1_f64(mut a: Vec) -> TestResult { - fn collapse_adjacent(x: Vec, mut f: F) -> Vec - where F: FnMut(f64, f64) -> f64 - { - let mut out = Vec::new(); - for i in (0..x.len()).step(2) { - if i == x.len()-1 { - out.push(x[i]) - } else { - out.push(f(x[i], x[i+1])); - } - } - out - } - - if a.iter().any(|x| x.is_nan()) { - return TestResult::discard(); - } - - let actual = a.iter().cloned().tree_fold1(f64::atan2); - - while a.len() > 1 { - a = collapse_adjacent(a, f64::atan2); - } - let expected = a.pop(); - - TestResult::from_bool(actual == expected) - } -} - -quickcheck! { - fn exactly_one_i32(a: Vec) -> TestResult { - let ret = a.iter().cloned().exactly_one(); - match a.len() { - 1 => TestResult::from_bool(ret.unwrap() == a[0]), - _ => TestResult::from_bool(ret.unwrap_err().eq(a.iter().cloned())), - } - } -} diff --git a/vendor/itertools-0.8.2/tests/test_core.rs b/vendor/itertools-0.8.2/tests/test_core.rs deleted file mode 100644 index b1e03cf672..0000000000 --- a/vendor/itertools-0.8.2/tests/test_core.rs +++ /dev/null @@ -1,272 +0,0 @@ -//! Licensed under the Apache License, Version 2.0 -//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license -//! http://opensource.org/licenses/MIT, at your -//! option. This file may not be copied, modified, or distributed -//! except according to those terms. -#![no_std] - -#[macro_use] extern crate itertools as it; - -use core::iter; - -use it::Itertools; -use it::interleave; -use it::multizip; -use it::free::put_back; - -#[test] -fn product2() { - let s = "αβ"; - - let mut prod = iproduct!(s.chars(), 0..2); - assert!(prod.next() == Some(('α', 0))); - assert!(prod.next() == Some(('α', 1))); - assert!(prod.next() == Some(('β', 0))); - assert!(prod.next() == Some(('β', 1))); - assert!(prod.next() == None); -} - -#[test] -fn product_temporary() { - for (_x, _y, _z) in iproduct!( - [0, 1, 2].iter().cloned(), - [0, 1, 2].iter().cloned(), - [0, 1, 2].iter().cloned()) - { - // ok - } -} - - -#[test] -fn izip_macro() { - let mut zip = izip!(2..3); - assert!(zip.next() == Some(2)); - assert!(zip.next().is_none()); - - let mut zip = izip!(0..3, 0..2, 0..2i8); - for i in 0..2 { - assert!((i as usize, i, i as i8) == zip.next().unwrap()); - } - assert!(zip.next().is_none()); - - let xs: [isize; 0] = []; - let mut zip = izip!(0..3, 0..2, 0..2i8, &xs); - assert!(zip.next().is_none()); -} - -#[test] -fn izip2() { - let _zip1: iter::Zip<_, _> = izip!(1.., 2..); - let _zip2: iter::Zip<_, _> = izip!(1.., 2.., ); -} - -#[test] -fn izip3() { - let mut zip: iter::Map, _> = izip!(0..3, 0..2, 0..2i8); - for i in 0..2 { - assert!((i as usize, i, i as i8) == zip.next().unwrap()); - } - assert!(zip.next().is_none()); -} - -#[test] -fn multizip3() { - let mut zip = multizip((0..3, 0..2, 0..2i8)); - for i in 0..2 { - assert!((i as usize, i, i as i8) == zip.next().unwrap()); - } - assert!(zip.next().is_none()); - - let xs: [isize; 0] = []; - let mut zip = multizip((0..3, 0..2, 0..2i8, xs.iter())); - assert!(zip.next().is_none()); - - for (_, _, _, _, _) in multizip((0..3, 0..2, xs.iter(), &xs, xs.to_vec())) { - /* test compiles */ - } -} - -#[test] -fn write_to() { - let xs = [7, 9, 8]; - let mut ys = [0; 5]; - let cnt = ys.iter_mut().set_from(xs.iter().map(|x| *x)); - assert!(cnt == xs.len()); - assert!(ys == [7, 9, 8, 0, 0]); - - let cnt = ys.iter_mut().set_from(0..10); - assert!(cnt == ys.len()); - assert!(ys == [0, 1, 2, 3, 4]); -} - -#[test] -fn test_interleave() { - let xs: [u8; 0] = []; - let ys = [7u8, 9, 8, 10]; - let zs = [2u8, 77]; - let it = interleave(xs.iter(), ys.iter()); - it::assert_equal(it, ys.iter()); - - let rs = [7u8, 2, 9, 77, 8, 10]; - let it = interleave(ys.iter(), zs.iter()); - it::assert_equal(it, rs.iter()); -} - -#[allow(deprecated)] -#[test] -fn foreach() { - let xs = [1i32, 2, 3]; - let mut sum = 0; - xs.iter().foreach(|elt| sum += *elt); - assert!(sum == 6); -} - -#[test] -fn dropping() { - let xs = [1, 2, 3]; - let mut it = xs.iter().dropping(2); - assert_eq!(it.next(), Some(&3)); - assert!(it.next().is_none()); - let mut it = xs.iter().dropping(5); - assert!(it.next().is_none()); -} - -#[test] -fn batching() { - let xs = [0, 1, 2, 1, 3]; - let ys = [(0, 1), (2, 1)]; - - // An iterator that gathers elements up in pairs - let pit = xs.iter().cloned().batching(|it| { - match it.next() { - None => None, - Some(x) => match it.next() { - None => None, - Some(y) => Some((x, y)), - } - } - }); - it::assert_equal(pit, ys.iter().cloned()); -} - -#[test] -fn test_put_back() { - let xs = [0, 1, 1, 1, 2, 1, 3, 3]; - let mut pb = put_back(xs.iter().cloned()); - pb.next(); - pb.put_back(1); - pb.put_back(0); - it::assert_equal(pb, xs.iter().cloned()); -} - -#[allow(deprecated)] -#[test] -fn step() { - it::assert_equal((0..10).step(1), 0..10); - it::assert_equal((0..10).step(2), (0..10).filter(|x: &i32| *x % 2 == 0)); - it::assert_equal((0..10).step(10), 0..1); -} - -#[allow(deprecated)] -#[test] -fn merge() { - it::assert_equal((0..10).step(2).merge((1..10).step(2)), 0..10); -} - - -#[test] -fn repeatn() { - let s = "α"; - let mut it = it::repeat_n(s, 3); - assert_eq!(it.len(), 3); - assert_eq!(it.next(), Some(s)); - assert_eq!(it.next(), Some(s)); - assert_eq!(it.next(), Some(s)); - assert_eq!(it.next(), None); - assert_eq!(it.next(), None); -} - -#[test] -fn count_clones() { - // Check that RepeatN only clones N - 1 times. - - use core::cell::Cell; - #[derive(PartialEq, Debug)] - struct Foo { - n: Cell - } - - impl Clone for Foo - { - fn clone(&self) -> Self - { - let n = self.n.get(); - self.n.set(n + 1); - Foo { n: Cell::new(n + 1) } - } - } - - - for n in 0..10 { - let f = Foo{n: Cell::new(0)}; - let it = it::repeat_n(f, n); - // drain it - let last = it.last(); - if n == 0 { - assert_eq!(last, None); - } else { - assert_eq!(last, Some(Foo{n: Cell::new(n - 1)})); - } - } -} - -#[test] -fn part() { - let mut data = [7, 1, 1, 9, 1, 1, 3]; - let i = it::partition(&mut data, |elt| *elt >= 3); - assert_eq!(i, 3); - assert_eq!(data, [7, 3, 9, 1, 1, 1, 1]); - - let i = it::partition(&mut data, |elt| *elt == 1); - assert_eq!(i, 4); - assert_eq!(data, [1, 1, 1, 1, 9, 3, 7]); - - let mut data = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let i = it::partition(&mut data, |elt| *elt % 3 == 0); - assert_eq!(i, 3); - assert_eq!(data, [9, 6, 3, 4, 5, 2, 7, 8, 1]); -} - -#[test] -fn tree_fold1() { - for i in 0..100 { - assert_eq!((0..i).tree_fold1(|x, y| x + y), (0..i).fold1(|x, y| x + y)); - } -} - -#[test] -fn exactly_one() { - assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2); - assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4)); - assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5)); - assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0)); -} - -#[test] -fn sum1() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..0].iter().cloned().sum1::(), None); - assert_eq!(v[1..2].iter().cloned().sum1::(), Some(1)); - assert_eq!(v[1..3].iter().cloned().sum1::(), Some(3)); - assert_eq!(v.iter().cloned().sum1::(), Some(55)); -} - -#[test] -fn product1() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..0].iter().cloned().product1::(), None); - assert_eq!(v[..1].iter().cloned().product1::(), Some(0)); - assert_eq!(v[1..3].iter().cloned().product1::(), Some(2)); - assert_eq!(v[1..5].iter().cloned().product1::(), Some(24)); -} diff --git a/vendor/itertools-0.8.2/tests/test_std.rs b/vendor/itertools-0.8.2/tests/test_std.rs deleted file mode 100644 index 4f48c55cf3..0000000000 --- a/vendor/itertools-0.8.2/tests/test_std.rs +++ /dev/null @@ -1,781 +0,0 @@ - -#[macro_use] extern crate itertools as it; -extern crate permutohedron; - -use it::Itertools; -use it::multizip; -use it::multipeek; -use it::free::rciter; -use it::free::put_back_n; -use it::FoldWhile; -use it::cloned; - -#[test] -fn product3() { - let prod = iproduct!(0..3, 0..2, 0..2); - assert_eq!(prod.size_hint(), (12, Some(12))); - let v = prod.collect_vec(); - for i in 0..3 { - for j in 0..2 { - for k in 0..2 { - assert!((i, j, k) == v[(i * 2 * 2 + j * 2 + k) as usize]); - } - } - } - for (_, _, _, _) in iproduct!(0..3, 0..2, 0..2, 0..3) { - /* test compiles */ - } -} - -#[test] -fn interleave_shortest() { - let v0: Vec = vec![0, 2, 4]; - let v1: Vec = vec![1, 3, 5, 7]; - let it = v0.into_iter().interleave_shortest(v1.into_iter()); - assert_eq!(it.size_hint(), (6, Some(6))); - assert_eq!(it.collect_vec(), vec![0, 1, 2, 3, 4, 5]); - - let v0: Vec = vec![0, 2, 4, 6, 8]; - let v1: Vec = vec![1, 3, 5]; - let it = v0.into_iter().interleave_shortest(v1.into_iter()); - assert_eq!(it.size_hint(), (7, Some(7))); - assert_eq!(it.collect_vec(), vec![0, 1, 2, 3, 4, 5, 6]); - - let i0 = ::std::iter::repeat(0); - let v1: Vec<_> = vec![1, 3, 5]; - let it = i0.interleave_shortest(v1.into_iter()); - assert_eq!(it.size_hint(), (7, Some(7))); - - let v0: Vec<_> = vec![0, 2, 4]; - let i1 = ::std::iter::repeat(1); - let it = v0.into_iter().interleave_shortest(i1); - assert_eq!(it.size_hint(), (6, Some(6))); -} - - -#[test] -fn unique_by() { - let xs = ["aaa", "bbbbb", "aa", "ccc", "bbbb", "aaaaa", "cccc"]; - let ys = ["aaa", "bbbbb", "ccc"]; - it::assert_equal(ys.iter(), xs.iter().unique_by(|x| x[..2].to_string())); -} - -#[test] -fn unique() { - let xs = [0, 1, 2, 3, 2, 1, 3]; - let ys = [0, 1, 2, 3]; - it::assert_equal(ys.iter(), xs.iter().unique()); - let xs = [0, 1]; - let ys = [0, 1]; - it::assert_equal(ys.iter(), xs.iter().unique()); -} - -#[test] -fn intersperse() { - let xs = ["a", "", "b", "c"]; - let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); - let text: String = v.concat(); - assert_eq!(text, "a, , b, c".to_string()); - - let ys = [0, 1, 2, 3]; - let mut it = ys[..0].iter().map(|x| *x).intersperse(1); - assert!(it.next() == None); -} - -#[test] -fn dedup() { - let xs = [0, 1, 1, 1, 2, 1, 3, 3]; - let ys = [0, 1, 2, 1, 3]; - it::assert_equal(ys.iter(), xs.iter().dedup()); - let xs = [0, 0, 0, 0, 0]; - let ys = [0]; - it::assert_equal(ys.iter(), xs.iter().dedup()); - - let xs = [0, 1, 1, 1, 2, 1, 3, 3]; - let ys = [0, 1, 2, 1, 3]; - let mut xs_d = Vec::new(); - xs.iter().dedup().fold((), |(), &elt| xs_d.push(elt)); - assert_eq!(&xs_d, &ys); -} - -#[test] -fn dedup_by() { - let xs = [(0, 0), (0, 1), (1, 1), (2, 1), (0, 2), (3, 1), (0, 3), (1, 3)]; - let ys = [(0, 0), (0, 1), (0, 2), (3, 1), (0, 3)]; - it::assert_equal(ys.iter(), xs.iter().dedup_by(|x, y| x.1==y.1)); - let xs = [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)]; - let ys = [(0, 1)]; - it::assert_equal(ys.iter(), xs.iter().dedup_by(|x, y| x.0==y.0)); - - let xs = [(0, 0), (0, 1), (1, 1), (2, 1), (0, 2), (3, 1), (0, 3), (1, 3)]; - let ys = [(0, 0), (0, 1), (0, 2), (3, 1), (0, 3)]; - let mut xs_d = Vec::new(); - xs.iter().dedup_by(|x, y| x.1==y.1).fold((), |(), &elt| xs_d.push(elt)); - assert_eq!(&xs_d, &ys); -} - -#[test] -fn all_equal() { - assert!("".chars().all_equal()); - assert!("A".chars().all_equal()); - assert!(!"AABBCCC".chars().all_equal()); - assert!("AAAAAAA".chars().all_equal()); - for (_key, mut sub) in &"AABBCCC".chars().group_by(|&x| x) { - assert!(sub.all_equal()); - } -} - -#[test] -fn test_put_back_n() { - let xs = [0, 1, 1, 1, 2, 1, 3, 3]; - let mut pb = put_back_n(xs.iter().cloned()); - pb.next(); - pb.next(); - pb.put_back(1); - pb.put_back(0); - it::assert_equal(pb, xs.iter().cloned()); -} - -#[test] -fn tee() { - let xs = [0, 1, 2, 3]; - let (mut t1, mut t2) = xs.iter().cloned().tee(); - assert_eq!(t1.next(), Some(0)); - assert_eq!(t2.next(), Some(0)); - assert_eq!(t1.next(), Some(1)); - assert_eq!(t1.next(), Some(2)); - assert_eq!(t1.next(), Some(3)); - assert_eq!(t1.next(), None); - assert_eq!(t2.next(), Some(1)); - assert_eq!(t2.next(), Some(2)); - assert_eq!(t1.next(), None); - assert_eq!(t2.next(), Some(3)); - assert_eq!(t2.next(), None); - assert_eq!(t1.next(), None); - assert_eq!(t2.next(), None); - - let (t1, t2) = xs.iter().cloned().tee(); - it::assert_equal(t1, xs.iter().cloned()); - it::assert_equal(t2, xs.iter().cloned()); - - let (t1, t2) = xs.iter().cloned().tee(); - it::assert_equal(t1.zip(t2), xs.iter().cloned().zip(xs.iter().cloned())); -} - - -#[test] -fn test_rciter() { - let xs = [0, 1, 1, 1, 2, 1, 3, 5, 6]; - - let mut r1 = rciter(xs.iter().cloned()); - let mut r2 = r1.clone(); - assert_eq!(r1.next(), Some(0)); - assert_eq!(r2.next(), Some(1)); - let mut z = r1.zip(r2); - assert_eq!(z.next(), Some((1, 1))); - assert_eq!(z.next(), Some((2, 1))); - assert_eq!(z.next(), Some((3, 5))); - assert_eq!(z.next(), None); - - // test intoiterator - let r1 = rciter(0..5); - let mut z = izip!(&r1, r1); - assert_eq!(z.next(), Some((0, 1))); -} - -#[allow(deprecated)] -#[test] -fn trait_pointers() { - struct ByRef<'r, I: ?Sized>(&'r mut I) where I: 'r; - - impl<'r, X, I: ?Sized> Iterator for ByRef<'r, I> where - I: 'r + Iterator - { - type Item = X; - fn next(&mut self) -> Option - { - self.0.next() - } - } - - let mut it = Box::new(0..10) as Box>; - assert_eq!(it.next(), Some(0)); - - { - /* make sure foreach works on non-Sized */ - let jt: &mut Iterator = &mut *it; - assert_eq!(jt.next(), Some(1)); - - { - let mut r = ByRef(jt); - assert_eq!(r.next(), Some(2)); - } - - assert_eq!(jt.find_position(|x| *x == 4), Some((1, 4))); - jt.foreach(|_| ()); - } -} - -#[test] -fn merge_by() { - let odd : Vec<(u32, &str)> = vec![(1, "hello"), (3, "world"), (5, "!")]; - let even = vec![(2, "foo"), (4, "bar"), (6, "baz")]; - let expected = vec![(1, "hello"), (2, "foo"), (3, "world"), (4, "bar"), (5, "!"), (6, "baz")]; - let results = odd.iter().merge_by(even.iter(), |a, b| a.0 <= b.0); - it::assert_equal(results, expected.iter()); -} - -#[test] -fn merge_by_btree() { - use std::collections::BTreeMap; - let mut bt1 = BTreeMap::new(); - bt1.insert("hello", 1); - bt1.insert("world", 3); - let mut bt2 = BTreeMap::new(); - bt2.insert("foo", 2); - bt2.insert("bar", 4); - let results = bt1.into_iter().merge_by(bt2.into_iter(), |a, b| a.0 <= b.0 ); - let expected = vec![("bar", 4), ("foo", 2), ("hello", 1), ("world", 3)]; - it::assert_equal(results, expected.into_iter()); -} - -#[allow(deprecated)] -#[test] -fn kmerge() { - let its = (0..4).map(|s| (s..10).step(4)); - - it::assert_equal(its.kmerge(), 0..10); -} - -#[allow(deprecated)] -#[test] -fn kmerge_2() { - let its = vec![3, 2, 1, 0].into_iter().map(|s| (s..10).step(4)); - - it::assert_equal(its.kmerge(), 0..10); -} - -#[test] -fn kmerge_empty() { - let its = (0..4).map(|_| 0..0); - assert_eq!(its.kmerge().next(), None); -} - -#[test] -fn kmerge_size_hint() { - let its = (0..5).map(|_| (0..10)); - assert_eq!(its.kmerge().size_hint(), (50, Some(50))); -} - -#[test] -fn kmerge_empty_size_hint() { - let its = (0..5).map(|_| (0..0)); - assert_eq!(its.kmerge().size_hint(), (0, Some(0))); -} - -#[test] -fn join() { - let many = [1, 2, 3]; - let one = [1]; - let none: Vec = vec![]; - - assert_eq!(many.iter().join(", "), "1, 2, 3"); - assert_eq!( one.iter().join(", "), "1"); - assert_eq!(none.iter().join(", "), ""); -} - -#[test] -fn sorted_by() { - let sc = [3, 4, 1, 2].iter().cloned().sorted_by(|&a, &b| { - a.cmp(&b) - }); - it::assert_equal(sc, vec![1, 2, 3, 4]); - - let v = (0..5).sorted_by(|&a, &b| a.cmp(&b).reverse()); - it::assert_equal(v, vec![4, 3, 2, 1, 0]); -} - -#[test] -fn sorted_by_key() { - let sc = [3, 4, 1, 2].iter().cloned().sorted_by_key(|&x| x); - it::assert_equal(sc, vec![1, 2, 3, 4]); - - let v = (0..5).sorted_by_key(|&x| -x); - it::assert_equal(v, vec![4, 3, 2, 1, 0]); -} - -#[test] -fn test_multipeek() { - let nums = vec![1u8,2,3,4,5]; - - let mp = multipeek(nums.iter().map(|&x| x)); - assert_eq!(nums, mp.collect::>()); - - let mut mp = multipeek(nums.iter().map(|&x| x)); - assert_eq!(mp.peek(), Some(&1)); - assert_eq!(mp.next(), Some(1)); - assert_eq!(mp.peek(), Some(&2)); - assert_eq!(mp.peek(), Some(&3)); - assert_eq!(mp.next(), Some(2)); - assert_eq!(mp.peek(), Some(&3)); - assert_eq!(mp.peek(), Some(&4)); - assert_eq!(mp.peek(), Some(&5)); - assert_eq!(mp.peek(), None); - assert_eq!(mp.next(), Some(3)); - assert_eq!(mp.next(), Some(4)); - assert_eq!(mp.peek(), Some(&5)); - assert_eq!(mp.peek(), None); - assert_eq!(mp.next(), Some(5)); - assert_eq!(mp.next(), None); - assert_eq!(mp.peek(), None); - -} - -#[test] -fn test_multipeek_reset() { - let data = [1, 2, 3, 4]; - - let mut mp = multipeek(cloned(&data)); - assert_eq!(mp.peek(), Some(&1)); - assert_eq!(mp.next(), Some(1)); - assert_eq!(mp.peek(), Some(&2)); - assert_eq!(mp.peek(), Some(&3)); - mp.reset_peek(); - assert_eq!(mp.peek(), Some(&2)); - assert_eq!(mp.next(), Some(2)); -} - -#[test] -fn test_multipeek_peeking_next() { - use it::PeekingNext; - let nums = vec![1u8,2,3,4,5,6,7]; - - let mut mp = multipeek(nums.iter().map(|&x| x)); - assert_eq!(mp.peeking_next(|&x| x != 0), Some(1)); - assert_eq!(mp.next(), Some(2)); - assert_eq!(mp.peek(), Some(&3)); - assert_eq!(mp.peek(), Some(&4)); - assert_eq!(mp.peeking_next(|&x| x == 3), Some(3)); - assert_eq!(mp.peek(), Some(&4)); - assert_eq!(mp.peeking_next(|&x| x != 4), None); - assert_eq!(mp.peeking_next(|&x| x == 4), Some(4)); - assert_eq!(mp.peek(), Some(&5)); - assert_eq!(mp.peek(), Some(&6)); - assert_eq!(mp.peeking_next(|&x| x != 5), None); - assert_eq!(mp.peek(), Some(&7)); - assert_eq!(mp.peeking_next(|&x| x == 5), Some(5)); - assert_eq!(mp.peeking_next(|&x| x == 6), Some(6)); - assert_eq!(mp.peek(), Some(&7)); - assert_eq!(mp.peek(), None); - assert_eq!(mp.next(), Some(7)); - assert_eq!(mp.peek(), None); -} - -#[test] -fn pad_using() { - it::assert_equal((0..0).pad_using(1, |_| 1), 1..2); - - let v: Vec = vec![0, 1, 2]; - let r = v.into_iter().pad_using(5, |n| n); - it::assert_equal(r, vec![0, 1, 2, 3, 4]); - - let v: Vec = vec![0, 1, 2]; - let r = v.into_iter().pad_using(1, |_| panic!()); - it::assert_equal(r, vec![0, 1, 2]); -} - -#[test] -fn group_by() { - for (ch1, sub) in &"AABBCCC".chars().group_by(|&x| x) { - for ch2 in sub { - assert_eq!(ch1, ch2); - } - } - - for (ch1, sub) in &"AAABBBCCCCDDDD".chars().group_by(|&x| x) { - for ch2 in sub { - assert_eq!(ch1, ch2); - if ch1 == 'C' { - break; - } - } - } - - let toupper = |ch: &char| ch.to_uppercase().nth(0).unwrap(); - - // try all possible orderings - for indices in permutohedron::Heap::new(&mut [0, 1, 2, 3]) { - let groups = "AaaBbbccCcDDDD".chars().group_by(&toupper); - let mut subs = groups.into_iter().collect_vec(); - - for &idx in &indices[..] { - let (key, text) = match idx { - 0 => ('A', "Aaa".chars()), - 1 => ('B', "Bbb".chars()), - 2 => ('C', "ccCc".chars()), - 3 => ('D', "DDDD".chars()), - _ => unreachable!(), - }; - assert_eq!(key, subs[idx].0); - it::assert_equal(&mut subs[idx].1, text); - } - } - - let groups = "AAABBBCCCCDDDD".chars().group_by(|&x| x); - let mut subs = groups.into_iter().map(|(_, g)| g).collect_vec(); - - let sd = subs.pop().unwrap(); - let sc = subs.pop().unwrap(); - let sb = subs.pop().unwrap(); - let sa = subs.pop().unwrap(); - for (a, b, c, d) in multizip((sa, sb, sc, sd)) { - assert_eq!(a, 'A'); - assert_eq!(b, 'B'); - assert_eq!(c, 'C'); - assert_eq!(d, 'D'); - } - - // check that the key closure is called exactly n times - { - let mut ntimes = 0; - let text = "AABCCC"; - for (_, sub) in &text.chars().group_by(|&x| { ntimes += 1; x}) { - for _ in sub { - } - } - assert_eq!(ntimes, text.len()); - } - - { - let mut ntimes = 0; - let text = "AABCCC"; - for _ in &text.chars().group_by(|&x| { ntimes += 1; x}) { - } - assert_eq!(ntimes, text.len()); - } - - { - let text = "ABCCCDEEFGHIJJKK"; - let gr = text.chars().group_by(|&x| x); - it::assert_equal(gr.into_iter().flat_map(|(_, sub)| sub), text.chars()); - } -} - -#[test] -fn group_by_lazy_2() { - let data = vec![0, 1]; - let groups = data.iter().group_by(|k| *k); - let gs = groups.into_iter().collect_vec(); - it::assert_equal(data.iter(), gs.into_iter().flat_map(|(_k, g)| g)); - - let data = vec![0, 1, 1, 0, 0]; - let groups = data.iter().group_by(|k| *k); - let mut gs = groups.into_iter().collect_vec(); - gs[1..].reverse(); - it::assert_equal(&[0, 0, 0, 1, 1], gs.into_iter().flat_map(|(_, g)| g)); - - let grouper = data.iter().group_by(|k| *k); - let mut groups = Vec::new(); - for (k, group) in &grouper { - if *k == 1 { - groups.push(group); - } - } - it::assert_equal(&mut groups[0], &[1, 1]); - - let data = vec![0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3]; - let grouper = data.iter().group_by(|k| *k); - let mut groups = Vec::new(); - for (i, (_, group)) in grouper.into_iter().enumerate() { - if i < 2 { - groups.push(group); - } else if i < 4 { - for _ in group { - } - } else { - groups.push(group); - } - } - it::assert_equal(&mut groups[0], &[0, 0, 0]); - it::assert_equal(&mut groups[1], &[1, 1]); - it::assert_equal(&mut groups[2], &[3, 3]); - - // use groups as chunks - let data = vec![0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3]; - let mut i = 0; - let grouper = data.iter().group_by(move |_| { let k = i / 3; i += 1; k }); - for (i, group) in &grouper { - match i { - 0 => it::assert_equal(group, &[0, 0, 0]), - 1 => it::assert_equal(group, &[1, 1, 0]), - 2 => it::assert_equal(group, &[0, 2, 2]), - 3 => it::assert_equal(group, &[3, 3]), - _ => unreachable!(), - } - } -} - -#[test] -fn group_by_lazy_3() { - // test consuming each group on the lap after it was produced - let data = vec![0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2]; - let grouper = data.iter().group_by(|elt| *elt); - let mut last = None; - for (key, group) in &grouper { - if let Some(gr) = last.take() { - for elt in gr { - assert!(elt != key && i32::abs(elt - key) == 1); - } - } - last = Some(group); - } -} - -#[test] -fn chunks() { - let data = vec![0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3]; - let grouper = data.iter().chunks(3); - for (i, chunk) in grouper.into_iter().enumerate() { - match i { - 0 => it::assert_equal(chunk, &[0, 0, 0]), - 1 => it::assert_equal(chunk, &[1, 1, 0]), - 2 => it::assert_equal(chunk, &[0, 2, 2]), - 3 => it::assert_equal(chunk, &[3, 3]), - _ => unreachable!(), - } - } -} - -#[test] -fn concat_empty() { - let data: Vec> = Vec::new(); - assert_eq!(data.into_iter().concat(), Vec::new()) -} - -#[test] -fn concat_non_empty() { - let data = vec![vec![1,2,3], vec![4,5,6], vec![7,8,9]]; - assert_eq!(data.into_iter().concat(), vec![1,2,3,4,5,6,7,8,9]) -} - -#[test] -fn combinations() { - assert!((1..3).combinations(5).next().is_none()); - - let it = (1..3).combinations(2); - it::assert_equal(it, vec![ - vec![1, 2], - ]); - - let it = (1..5).combinations(2); - it::assert_equal(it, vec![ - vec![1, 2], - vec![1, 3], - vec![1, 4], - vec![2, 3], - vec![2, 4], - vec![3, 4], - ]); - - it::assert_equal((0..0).tuple_combinations::<(_, _)>(), >::new()); - it::assert_equal((0..1).tuple_combinations::<(_, _)>(), >::new()); - it::assert_equal((0..2).tuple_combinations::<(_, _)>(), vec![(0, 1)]); - - it::assert_equal((0..0).combinations(2), >>::new()); - it::assert_equal((0..1).combinations(1), vec![vec![0]]); - it::assert_equal((0..2).combinations(1), vec![vec![0], vec![1]]); - it::assert_equal((0..2).combinations(2), vec![vec![0, 1]]); -} - -#[test] -fn combinations_of_too_short() { - for i in 1..10 { - assert!((0..0).combinations(i).next().is_none()); - assert!((0..i - 1).combinations(i).next().is_none()); - } -} - - -#[test] -fn combinations_zero() { - it::assert_equal((1..3).combinations(0), vec![vec![]]); -} - -#[test] -fn combinations_with_replacement() { - // Pool smaller than n - it::assert_equal((0..1).combinations_with_replacement(2), vec![vec![0, 0]]); - // Pool larger than n - it::assert_equal( - (0..3).combinations_with_replacement(2), - vec![ - vec![0, 0], - vec![0, 1], - vec![0, 2], - vec![1, 1], - vec![1, 2], - vec![2, 2], - ], - ); - // Zero size - it::assert_equal( - (0..3).combinations_with_replacement(0), - >>::new(), - ); - // Empty pool - it::assert_equal( - (0..0).combinations_with_replacement(2), - >>::new(), - ); -} - -#[test] -fn diff_mismatch() { - let a = vec![1, 2, 3, 4]; - let b = vec![1.0, 5.0, 3.0, 4.0]; - let b_map = b.into_iter().map(|f| f as i32); - let diff = it::diff_with(a.iter(), b_map, |a, b| *a == b); - - assert!(match diff { - Some(it::Diff::FirstMismatch(1, _, from_diff)) => - from_diff.collect::>() == vec![5, 3, 4], - _ => false, - }); -} - -#[test] -fn diff_longer() { - let a = vec![1, 2, 3, 4]; - let b = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; - let b_map = b.into_iter().map(|f| f as i32); - let diff = it::diff_with(a.iter(), b_map, |a, b| *a == b); - - assert!(match diff { - Some(it::Diff::Longer(_, remaining)) => - remaining.collect::>() == vec![5, 6], - _ => false, - }); -} - -#[test] -fn diff_shorter() { - let a = vec![1, 2, 3, 4]; - let b = vec![1.0, 2.0]; - let b_map = b.into_iter().map(|f| f as i32); - let diff = it::diff_with(a.iter(), b_map, |a, b| *a == b); - - assert!(match diff { - Some(it::Diff::Shorter(len, _)) => len == 2, - _ => false, - }); -} - -#[test] -fn minmax() { - use std::cmp::Ordering; - use it::MinMaxResult; - - // A peculiar type: Equality compares both tuple items, but ordering only the - // first item. This is so we can check the stability property easily. - #[derive(Clone, Debug, PartialEq, Eq)] - struct Val(u32, u32); - - impl PartialOrd for Val { - fn partial_cmp(&self, other: &Val) -> Option { - self.0.partial_cmp(&other.0) - } - } - - impl Ord for Val { - fn cmp(&self, other: &Val) -> Ordering { - self.0.cmp(&other.0) - } - } - - assert_eq!(None::>.iter().minmax(), MinMaxResult::NoElements); - - assert_eq!(Some(1u32).iter().minmax(), MinMaxResult::OneElement(&1)); - - let data = vec![Val(0, 1), Val(2, 0), Val(0, 2), Val(1, 0), Val(2, 1)]; - - let minmax = data.iter().minmax(); - assert_eq!(minmax, MinMaxResult::MinMax(&Val(0, 1), &Val(2, 1))); - - let (min, max) = data.iter().minmax_by_key(|v| v.1).into_option().unwrap(); - assert_eq!(min, &Val(2, 0)); - assert_eq!(max, &Val(0, 2)); - - let (min, max) = data.iter().minmax_by(|x, y| x.1.cmp(&y.1)).into_option().unwrap(); - assert_eq!(min, &Val(2, 0)); - assert_eq!(max, &Val(0, 2)); -} - -#[test] -fn format() { - let data = [0, 1, 2, 3]; - let ans1 = "0, 1, 2, 3"; - let ans2 = "0--1--2--3"; - - let t1 = format!("{}", data.iter().format(", ")); - assert_eq!(t1, ans1); - let t2 = format!("{:?}", data.iter().format("--")); - assert_eq!(t2, ans2); - - let dataf = [1.1, 2.71828, -22.]; - let t3 = format!("{:.2e}", dataf.iter().format(", ")); - assert_eq!(t3, "1.10e0, 2.72e0, -2.20e1"); -} - -#[test] -fn while_some() { - let ns = (1..10).map(|x| if x % 5 != 0 { Some(x) } else { None }) - .while_some(); - it::assert_equal(ns, vec![1, 2, 3, 4]); -} - -#[allow(deprecated)] -#[test] -fn fold_while() { - let mut iterations = 0; - let vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let sum = vec.into_iter().fold_while(0, |acc, item| { - iterations += 1; - let new_sum = acc.clone() + item; - if new_sum <= 20 { - FoldWhile::Continue(new_sum) - } else { - FoldWhile::Done(acc) - } - }).into_inner(); - assert_eq!(iterations, 6); - assert_eq!(sum, 15); -} - -#[test] -fn tree_fold1() { - let x = [ - "", - "0", - "0 1 x", - "0 1 x 2 x", - "0 1 x 2 3 x x", - "0 1 x 2 3 x x 4 x", - "0 1 x 2 3 x x 4 5 x x", - "0 1 x 2 3 x x 4 5 x 6 x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x 14 x x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x 14 15 x x x x", - ]; - for (i, &s) in x.iter().enumerate() { - let expected = if s == "" { None } else { Some(s.to_string()) }; - let num_strings = (0..i).map(|x| x.to_string()); - let actual = num_strings.tree_fold1(|a, b| format!("{} {} x", a, b)); - assert_eq!(actual, expected); - } -} diff --git a/vendor/itertools-0.8.2/tests/tuples.rs b/vendor/itertools-0.8.2/tests/tuples.rs deleted file mode 100644 index 07dba57fe6..0000000000 --- a/vendor/itertools-0.8.2/tests/tuples.rs +++ /dev/null @@ -1,88 +0,0 @@ -extern crate itertools; - -use itertools::Itertools; - -#[test] -fn tuples() { - let v = [1, 2, 3, 4, 5]; - let mut iter = v.iter().cloned().tuples(); - assert_eq!(Some((1,)), iter.next()); - assert_eq!(Some((2,)), iter.next()); - assert_eq!(Some((3,)), iter.next()); - assert_eq!(Some((4,)), iter.next()); - assert_eq!(Some((5,)), iter.next()); - assert_eq!(None, iter.next()); - assert_eq!(None, iter.into_buffer().next()); - - let mut iter = v.iter().cloned().tuples(); - assert_eq!(Some((1, 2)), iter.next()); - assert_eq!(Some((3, 4)), iter.next()); - assert_eq!(None, iter.next()); - itertools::assert_equal(vec![5], iter.into_buffer()); - - let mut iter = v.iter().cloned().tuples(); - assert_eq!(Some((1, 2, 3)), iter.next()); - assert_eq!(None, iter.next()); - itertools::assert_equal(vec![4, 5], iter.into_buffer()); - - let mut iter = v.iter().cloned().tuples(); - assert_eq!(Some((1, 2, 3, 4)), iter.next()); - assert_eq!(None, iter.next()); - itertools::assert_equal(vec![5], iter.into_buffer()); -} - -#[test] -fn tuple_windows() { - let v = [1, 2, 3, 4, 5]; - - let mut iter = v.iter().cloned().tuple_windows(); - assert_eq!(Some((1,)), iter.next()); - assert_eq!(Some((2,)), iter.next()); - assert_eq!(Some((3,)), iter.next()); - - let mut iter = v.iter().cloned().tuple_windows(); - assert_eq!(Some((1, 2)), iter.next()); - assert_eq!(Some((2, 3)), iter.next()); - assert_eq!(Some((3, 4)), iter.next()); - assert_eq!(Some((4, 5)), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = v.iter().cloned().tuple_windows(); - assert_eq!(Some((1, 2, 3)), iter.next()); - assert_eq!(Some((2, 3, 4)), iter.next()); - assert_eq!(Some((3, 4, 5)), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = v.iter().cloned().tuple_windows(); - assert_eq!(Some((1, 2, 3, 4)), iter.next()); - assert_eq!(Some((2, 3, 4, 5)), iter.next()); - assert_eq!(None, iter.next()); - - let v = [1, 2, 3]; - let mut iter = v.iter().cloned().tuple_windows::<(_, _, _, _)>(); - assert_eq!(None, iter.next()); -} - -#[test] -fn next_tuple() { - let v = [1, 2, 3, 4, 5]; - let mut iter = v.iter(); - assert_eq!(iter.next_tuple().map(|(&x, &y)| (x, y)), Some((1, 2))); - assert_eq!(iter.next_tuple().map(|(&x, &y)| (x, y)), Some((3, 4))); - assert_eq!(iter.next_tuple::<(_, _)>(), None); -} - -#[test] -fn collect_tuple() { - let v = [1, 2]; - let iter = v.iter().cloned(); - assert_eq!(iter.collect_tuple(), Some((1, 2))); - - let v = [1]; - let iter = v.iter().cloned(); - assert_eq!(iter.collect_tuple::<(_, _)>(), None); - - let v = [1, 2, 3]; - let iter = v.iter().cloned(); - assert_eq!(iter.collect_tuple::<(_, _)>(), None); -} diff --git a/vendor/itertools-0.8.2/tests/zip.rs b/vendor/itertools-0.8.2/tests/zip.rs deleted file mode 100644 index c5c51899b8..0000000000 --- a/vendor/itertools-0.8.2/tests/zip.rs +++ /dev/null @@ -1,65 +0,0 @@ -extern crate itertools; - -use itertools::Itertools; -use itertools::EitherOrBoth::{Both, Left, Right}; -use itertools::free::zip_eq; - -#[test] -fn zip_longest_fused() { - let a = [Some(1), None, Some(3), Some(4)]; - let b = [1, 2, 3]; - - let unfused = a.iter().batching(|it| *it.next().unwrap()) - .zip_longest(b.iter().cloned()); - itertools::assert_equal(unfused, - vec![Both(1, 1), Right(2), Right(3)]); -} - -#[test] -fn test_zip_longest_size_hint() { - let c = (1..10).cycle(); - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let v2 = &[10, 11, 12]; - - assert_eq!(c.zip_longest(v.iter()).size_hint(), (std::usize::MAX, None)); - - assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10))); -} - -#[test] -fn test_double_ended_zip_longest() { - let xs = [1, 2, 3, 4, 5, 6]; - let ys = [1, 2, 3, 7]; - let a = xs.iter().map(|&x| x); - let b = ys.iter().map(|&x| x); - let mut it = a.zip_longest(b); - assert_eq!(it.next(), Some(Both(1, 1))); - assert_eq!(it.next(), Some(Both(2, 2))); - assert_eq!(it.next_back(), Some(Left(6))); - assert_eq!(it.next_back(), Some(Left(5))); - assert_eq!(it.next_back(), Some(Both(4, 7))); - assert_eq!(it.next(), Some(Both(3, 3))); - assert_eq!(it.next(), None); -} - - -#[should_panic] -#[test] -fn zip_eq_panic1() -{ - let a = [1, 2]; - let b = [1, 2, 3]; - - zip_eq(&a, &b).count(); -} - -#[should_panic] -#[test] -fn zip_eq_panic2() -{ - let a: [i32; 0] = []; - let b = [1, 2, 3]; - - zip_eq(&a, &b).count(); -} - diff --git a/vendor/libc/.cargo-checksum.json b/vendor/libc/.cargo-checksum.json index 2233783fde..e2af23d0fa 100644 --- a/vendor/libc/.cargo-checksum.json +++ b/vendor/libc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CONTRIBUTING.md":"3a9f0037ad5f1198eada74a9d0363925ef09db664380b0e5a2840f03da260476","Cargo.toml":"f21c12e9feff009e1694d41296471ff3d06a392ecc6088bd86e283e6432396ea","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a8d47ff51ca256f56a8932dba07660672dbfe3004257ca8de708aac1415937a1","README.md":"8d633db1fa838f24fb7ae854b31f37fc238b833d6f4044a1c3c077fe88a59e1f","build.rs":"e487789ca77b0015d75cecb253286d4a1406f11b1ae538929414fc0506842bef","rustfmt.toml":"8a654d5787585ca8f2c20580737336fc327f411a07b0dbd4870adf6e9bdf624f","src/cloudabi/aarch64.rs":"b8550bf1fd7344972aa4db29441486f39f31482d0327534981dbb75959c29114","src/cloudabi/arm.rs":"c197e2781c2839808bd6fcef219a29705b27b992d3ef920e9cf6ac96e2022bbf","src/cloudabi/mod.rs":"d5d4488e8c0b8227f516fe13810f550a2a72af3bdfe769200ad8687c8755bdf6","src/cloudabi/x86.rs":"33eb97f272d2201f3838ae74d444583c7de8f67856852ca375293b20bbd05636","src/cloudabi/x86_64.rs":"400d85d4fe39e26cf2e6ece9ee31c75fe9e88c4bcf4d836ca9f765c05c9c5be3","src/fixed_width_ints.rs":"34c60f12ec5eeb90f13ec3b954427532111c2446e69617616a97aefc1086a9f1","src/fuchsia/aarch64.rs":"378776a9e40766154a54c94c2a7b4675b5c302a38e6e42da99e67bfbaee60e56","src/fuchsia/align.rs":"ae1cf8f011a99737eabeb14ffff768e60f13b13363d7646744dbb0f443dab3d6","src/fuchsia/mod.rs":"61502b3d124759c7c1bae294c1662036a96718fb3bd329cfa2f12e1c61ac10ad","src/fuchsia/no_align.rs":"303f3f1b255e0088b5715094353cf00476131d8e94e6aebb3f469557771c8b8a","src/fuchsia/x86_64.rs":"93a3632b5cf67d2a6bcb7dc0a558605252d5fe689e0f38d8aa2ec5852255ac87","src/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/hermit/mod.rs":"d3bfce41e4463d4be8020a2d063c9bfa8b665f45f1cc6cbf3163f5d01e7cb21f","src/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/lib.rs":"d80f0a2f77d485601a218e0707474245636d8b23fb3d6c65c9dbd4302ea6674b","src/macros.rs":"83aed048c5053300345fca843b148928b91ed444188c479315ff6bcabaa0c4e9","src/psp.rs":"a621e34d2d31d9b29c725897b846122acce4763ac2017a1fe2200b133e5ad064","src/sgx.rs":"16a95cdefc81c5ee00d8353a60db363c4cc3e0f75abcd5d0144723f2a306ed1b","src/switch.rs":"9da3dd39b3de45a7928789926e8572d00e1e11a39e6f7289a1349aadce90edba","src/unix/align.rs":"2cdc7c826ef7ae61f5171c5ae8c445a743d86f1a7f2d9d7e4ceeec56d6874f65","src/unix/bsd/apple/b32/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b32/mod.rs":"6a4ce300da0d2b0db04b18548286603ffe4b47d679a41cf60f1902895894aa1f","src/unix/bsd/apple/b64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/mod.rs":"81254d89be1febc5bb20e787d014a624950d56e2e14973df5bbebfdabc95ae20","src/unix/bsd/apple/mod.rs":"5b9136a239e9893aaaa604b4499e5bb3e9899fd9ef76c0ed616a4d6b0fa4c3ba","src/unix/bsd/freebsdlike/dragonfly/errno.rs":"ae5e8e6b0f610ec015dfcc2928609037d7ea7b94570c72bcc5bdd588424c6259","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"0e41b6202c7670ce27201095fc1a2826c9e9ccbbc751e97ae1568871ea481a62","src/unix/bsd/freebsdlike/freebsd/aarch64.rs":"14f0bd6693967d4fedec904f7042bd51f2138cb843ec4df18c911b357417cdd2","src/unix/bsd/freebsdlike/freebsd/arm.rs":"59d6a670eea562fb87686e243e0a84603d29a2028a3d4b3f99ccc01bd04d2f47","src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs":"9808d152c1196aa647f1b0f0cf84dac8c930da7d7f897a44975545e3d9d17681","src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs":"16dd3e1a09f123d0aa544b3fd7c123654b4906cac94838fbed7f34a64413c930","src/unix/bsd/freebsdlike/freebsd/freebsd12/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs":"c6152ce3db241d99e350d34352f3f3d167953ef0ee08bfbe2685cb9ebde2e83b","src/unix/bsd/freebsdlike/freebsd/mod.rs":"1ed8971b7de3b0435341a9af1366493d0458e4a00507dd824c4c11f4ce2006af","src/unix/bsd/freebsdlike/freebsd/powerpc64.rs":"2dae3ecc87eac3b11657aa98915def55fc4b5c0de11fe26aae23329a54628a9a","src/unix/bsd/freebsdlike/freebsd/x86.rs":"c5005e3249eb7c93cfbac72a9e9272320d80ce7983da990ceb05a447f59a02c5","src/unix/bsd/freebsdlike/freebsd/x86_64/align.rs":"0e1f69a88fca1c32874b1daf5db3d446fefbe518dca497f096cc9168c39dde70","src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs":"6132aa0973454379674ea6cbc77e6eace1e1032dd9f38182071388a036f1bc08","src/unix/bsd/freebsdlike/mod.rs":"8ab67353a9bd2c5490a0bd734de3a70c90fa6b3c3160dccf18c690e70a44e1b8","src/unix/bsd/mod.rs":"4acdbc0148b672fe015ddd7cae952e5d77691df6941a20f8ca40fd996e6a37dd","src/unix/bsd/netbsdlike/mod.rs":"48dd60524119c1e09b255d5472d091e7e7b2b29eab04be51b4b1e740bd022859","src/unix/bsd/netbsdlike/netbsd/aarch64.rs":"b38fc046f9a40fea28bd26328b96629f4d5d63d7524936bd6af1865d401a8716","src/unix/bsd/netbsdlike/netbsd/arm.rs":"58cdbb70b0d6f536551f0f3bb3725d2d75c4690db12c26c034e7d6ec4a924452","src/unix/bsd/netbsdlike/netbsd/mod.rs":"16a9036b6a8b373cdf0576ae99c95430f3f111b6be906a1e1ecff8047e178a86","src/unix/bsd/netbsdlike/netbsd/powerpc.rs":"ee7ff5d89d0ed22f531237b5059aa669df93a3b5c489fa641465ace8d405bf41","src/unix/bsd/netbsdlike/netbsd/sparc64.rs":"9489f4b3e4566f43bb12dfb92238960613dac7f6a45cc13068a8d152b902d7d9","src/unix/bsd/netbsdlike/netbsd/x86.rs":"20692320e36bfe028d1a34d16fe12ca77aa909cb02bda167376f98f1a09aefe7","src/unix/bsd/netbsdlike/netbsd/x86_64.rs":"135509edeaf3fb3f102d89d51ff1a8f82323497336a8dc7e1f0f23b5c2434b73","src/unix/bsd/netbsdlike/openbsd/aarch64.rs":"1dd5449dd1fd3d51e30ffdeeaece91d0aaf05c710e0ac699fecc5461cfa2c28e","src/unix/bsd/netbsdlike/openbsd/mod.rs":"a2938e72d1c6e3f32fb51e896b63abd0d79e1e360dc53f9254fdac82b21206b9","src/unix/bsd/netbsdlike/openbsd/sparc64.rs":"d04fd287afbaa2c5df9d48c94e8374a532a3ba491b424ddf018270c7312f4085","src/unix/bsd/netbsdlike/openbsd/x86.rs":"6f7f5c4fde2a2259eb547890cbd86570cea04ef85347d7569e94e679448bec87","src/unix/bsd/netbsdlike/openbsd/x86_64.rs":"e59b7fd65f68f8e857eec39e0c03bac1d3af6ddc26c9ba58494336b83659bb9b","src/unix/haiku/b32.rs":"69ae47fc52c6880e85416b4744500d5655c9ec6131cb737f3b649fceaadce15a","src/unix/haiku/b64.rs":"73e64db09275a8da8d50a13cce2cfa2b136036ddf3a930d2939f337fc995900b","src/unix/haiku/mod.rs":"4ff3c94cf2e046609c95822e99b2a72663ba72056aa3519c0189cc6197b23751","src/unix/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/unix/hermit/mod.rs":"fb7e14d0f46ffaa989b5ab68c85184efe6aa04b5381e46866299b1f3258ddce3","src/unix/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/unix/linux_like/android/b32/arm.rs":"155994121906903a2e0afad895f0b3b7546f6e54d6305a3336ce2c4dfafbfdfa","src/unix/linux_like/android/b32/mod.rs":"0325adf3364fed7157fff5b24fabe1b36d806c39ee04ec82dd29a606d28f91f6","src/unix/linux_like/android/b32/x86/align.rs":"812914e4241df82e32b12375ca3374615dc3a4bdd4cf31f0423c5815320c0dab","src/unix/linux_like/android/b32/x86/mod.rs":"5b1e9fcd77ca5f939acb7fb5f5da12f305b0377698d8b8989feb236e26360aa0","src/unix/linux_like/android/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/android/b64/aarch64/mod.rs":"655116966eb7846b933e5e28b073c329668588cd3c2120cc9ce60c697bd19978","src/unix/linux_like/android/b64/mod.rs":"6a71abfcbbcdae60c916de41cd4688d5f25bdbca83d1d9df49decd56ad726a06","src/unix/linux_like/android/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/android/b64/x86_64/mod.rs":"e84176d838e663d351450bad218715db1fafbb531e47ea0e262cbb45829dae89","src/unix/linux_like/android/mod.rs":"a30a8bd58d6e9e330ed42af86db84a7dde7225262bc1197066cdb776cc1936a4","src/unix/linux_like/emscripten/align.rs":"86c95cbed7a7161b1f23ee06843e7b0e2340ad92b2cb86fe2a8ef3e0e8c36216","src/unix/linux_like/emscripten/mod.rs":"55fb89f5a965a4ad81ee4d02498c32aaed69e6047ce708c2329a602171862a76","src/unix/linux_like/emscripten/no_align.rs":"0128e4aa721a9902754828b61b5ec7d8a86619983ed1e0544a85d35b1051fad6","src/unix/linux_like/linux/align.rs":"dde648468764a5deef5566b8016290150acf50ee6a0f8c0678cb2078658bc2fa","src/unix/linux_like/linux/gnu/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/gnu/b32/arm/align.rs":"3fed009dc9af3cc81be7087da9d2d7d1f39845e4497e290259c5cdbae25f039d","src/unix/linux_like/linux/gnu/b32/arm/mod.rs":"6d9ba242111c7be8173b7a7b8cf8c863ba23d839edc9d026c0fd37a4b64460b4","src/unix/linux_like/linux/gnu/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/gnu/b32/mips/mod.rs":"e2d2e51fea73210d9705b7eaa37de8baa7152b71ae3a10a316c277345c529b5c","src/unix/linux_like/linux/gnu/b32/mod.rs":"e224551fa50be726bc8a559da32a96294b18743fb5a5b67cdbee4bb6a9eeb796","src/unix/linux_like/linux/gnu/b32/powerpc.rs":"39aae80d2c4ffa845592e16c0a6c910017de19e2b15c1e507c4df10e79ce3e38","src/unix/linux_like/linux/gnu/b32/sparc/align.rs":"21adbed27df73e2d1ed934aaf733a643003d7baf2bde9c48ea440895bcca6d41","src/unix/linux_like/linux/gnu/b32/sparc/mod.rs":"3b4dd40b288788740d2b030171b21f9d0b076ce26d88e0ff62f5d87f09e7c787","src/unix/linux_like/linux/gnu/b32/x86/align.rs":"e4bafdc4a519a7922a81b37a62bbfd1177a2f620890eef8f1fbc47162e9eb413","src/unix/linux_like/linux/gnu/b32/x86/mod.rs":"927d1bd8cb2f053549fc5acfeb1315b7f80b35d7a1904cd76e99651ff32b141e","src/unix/linux_like/linux/gnu/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs":"17e9cd23a14bd19700c05a154568fff5897788c0ae151c21dd3bba67aac829d9","src/unix/linux_like/linux/gnu/b64/mips64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/mips64/mod.rs":"0b5d94f3a2361742b6dd9eb3f543ddf675d3f70dab3402ad179faa6ddaae2218","src/unix/linux_like/linux/gnu/b64/mod.rs":"b90d87f76bff37707a1725551fe45d70d0c106e01b1dbbcd5f60460e0a19b4c3","src/unix/linux_like/linux/gnu/b64/powerpc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs":"2f279eb268c0aca9a6bd9b4c84139799cd039a64ca1cd2ded68b04c63397be1b","src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs":"bb01828300f02c11c27689522454439d0d02f22d738df88a97367dc87eecf868","src/unix/linux_like/linux/gnu/b64/s390x.rs":"9c449b64b11cbf55d453b324cf9475acb3253f85cb9692f9873b777ed8978ff4","src/unix/linux_like/linux/gnu/b64/sparc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs":"a2667a09e526878683fafa02474f81fbc212d861ceeabade17b0ff4d6d49ff9d","src/unix/linux_like/linux/gnu/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs":"e6197537739cb8628cad25827081c8bf6b371c02ad4b2132b30b9ae74143b1ef","src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs":"c1862036556262f076eda2008470b8a351b9c371d70664f54387c46890e8cd18","src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs":"30f88d0fa9e7807ee4cbe89fd274061f810099567d5e68fa829277d7d27ba708","src/unix/linux_like/linux/gnu/mod.rs":"747a07b094dff07bbf77049ce1117098255de9be403a6f703219c1c6a174898c","src/unix/linux_like/linux/gnu/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/mod.rs":"3dc8b1980062117edd7bdfdf2279065737f8cdcdcb883f57f23f27a1d0bbb8b2","src/unix/linux_like/linux/musl/b32/arm/align.rs":"3e8ac052c1043764776b54c93ba4260e061df998631737a897d9d47d54f7b80c","src/unix/linux_like/linux/musl/b32/arm/mod.rs":"45062a178b382ab17341a69d027b5c83325c4e79fecf45729ba9c47b1bcdc3da","src/unix/linux_like/linux/musl/b32/hexagon.rs":"7c6c481f70da1fe6ca759f363784e130041f3d87906c45910fc1142b5ef17970","src/unix/linux_like/linux/musl/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/musl/b32/mips/mod.rs":"9eb0e4953be5afaa0b9e3ac54c85ed40583cfb8cc0b03264b9bc8f763a8f3254","src/unix/linux_like/linux/musl/b32/mod.rs":"8ede3985e6243882814ce91e8ce543e7edbafc0cee5932816072b6f14207a671","src/unix/linux_like/linux/musl/b32/powerpc.rs":"cf286cbf4d2076aaa82662ace2b5c333480410fa59af5cb4542d59f04da84b31","src/unix/linux_like/linux/musl/b32/x86/align.rs":"08e77fbd7435d7dec2ff56932433bece3f02e47ce810f89004a275a86d39cbe1","src/unix/linux_like/linux/musl/b32/x86/mod.rs":"9c3b6e98e7710d6c877a4e31726d36416115a58f53fc469bb173b7fe660b39e5","src/unix/linux_like/linux/musl/b64/aarch64/align.rs":"22da1c030c254c511bc335c824d40b693904975a4633f8243a8777ca68ef1c65","src/unix/linux_like/linux/musl/b64/aarch64/mod.rs":"7b3fb85a869e00aae3f6af9c36f82f9c70bf8c2b9cccbd931b923602846ea42c","src/unix/linux_like/linux/musl/b64/mips64.rs":"9d0158ac7a913222d0a62239ec043aa1aee73522a7a1e0e191d0642dde35c083","src/unix/linux_like/linux/musl/b64/mod.rs":"8b76e92a1505ad785d4aa0b7739e0b93647a1e81910949b49cedb6c88468be9c","src/unix/linux_like/linux/musl/b64/powerpc64.rs":"ed9b879bb9cdc526ad83815875edeb4cad4e8829086dfba2578277c265336229","src/unix/linux_like/linux/musl/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/musl/b64/x86_64/mod.rs":"cfeb109c732ac6bc7d2be44069d3652e917a0509b8b545270b756ff2d52e27e8","src/unix/linux_like/linux/musl/mod.rs":"243e32b93641df7a77f970a32c0fb8e4fd4a13720e54e0e42a9da321fd169798","src/unix/linux_like/linux/no_align.rs":"c81ccd1942295d423b43a55b4aa19633c2096fb93bb381a6a29acb93e85aab07","src/unix/linux_like/mod.rs":"7fa57fd43b7429c29a34867a85b34f185ed8a05c4511749177c870d8cfafa0dd","src/unix/mod.rs":"48268482b43ab4bf82d6a6e67f64043279c7266032826ff25d3ccc14ac0ae1ed","src/unix/newlib/aarch64/mod.rs":"bb269c1468a9676442554600e87417079a787fe6220dfc23b3109639259e8710","src/unix/newlib/align.rs":"28aaf87fafbc6b312622719d472d8cf65f9e5467d15339df5f73e66d8502b28a","src/unix/newlib/arm/mod.rs":"c71be856bfd7f576b2db28af9f680211cbe6c1cac7d537bbc8020b39591af07c","src/unix/newlib/mod.rs":"2f771ab23df36ab0c7a117e854483a917aaf9c5cbb9eded1bdda35827cdaf734","src/unix/newlib/no_align.rs":"7123dcec13604a11b7765c380ff3a4d0da19c39f4b03919de7857723c0cf1502","src/unix/newlib/powerpc/mod.rs":"2d0f7af28b47f7a2a6c210ebd1c1f33ed8eac62e56b5af2b856de2ad3fdc5187","src/unix/newlib/xtensa/mod.rs":"4c72003c5e692e648c7e798358c49af6901e68850dbba0624af84c40baf208f5","src/unix/no_align.rs":"c06e95373b9088266e0b14bba0954eef95f93fb2b01d951855e382d22de78e53","src/unix/redox/mod.rs":"89c31827cf348e9a7af387f9e708fc834d04da36cad415d3957d2faa70f2fcbe","src/unix/solarish/compat.rs":"3f13657fc072462b85b5f937f0db1427c41acb2a714cc4f78fefba1ea8036846","src/unix/solarish/illumos.rs":"1088c45b238e7d398dbb140d238257d5b5f93aeded98652c3f6747f0c07b4fa7","src/unix/solarish/mod.rs":"9f96e346d87296e2b0b87b9fe375d67fb66cd88ce61ea2905466c8c5891d3108","src/unix/solarish/solaris.rs":"6000d322ee9f691f38a2cd89b2b8838e51f64c01584143924962b0c598e0985c","src/unix/uclibc/align.rs":"a8540e1cce5913a45bc8d7422b79e86c0b12740e8a679478e0e4d863a31f8cc1","src/unix/uclibc/arm/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/arm/mod.rs":"d67dd46bc6f417169fc6a23832bde7ccdafc5d1bcb08b10debdd82edaf75d529","src/unix/uclibc/arm/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips32/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/mips/mips32/mod.rs":"a045ebc6619f540adf670b88a987abd2d6e42e440a552e8cfe9f8c77f397e873","src/unix/uclibc/mips/mips32/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips64/align.rs":"a7bdcb18a37a2d91e64d5fad83ea3edc78f5412adb28f77ab077dbb26dd08b2d","src/unix/uclibc/mips/mips64/mod.rs":"e3085ba56cfbc528d7c3c55065880603238c333b6047ef51c58177508a487fcd","src/unix/uclibc/mips/mips64/no_align.rs":"4a18e3875698c85229599225ac3401a2a40da87e77b2ad4ef47c6fcd5a24ed30","src/unix/uclibc/mips/mod.rs":"1054d0bfeb506b3346b9a4148564beced8a22da0d9c9a612101f6237756795fb","src/unix/uclibc/mod.rs":"18d6c2628ca458ba75e743bce75bda6614de99606af4e2e62daf2440d2878f18","src/unix/uclibc/no_align.rs":"3f28637046524618adaa1012e26cb7ffe94b9396e6b518cccdc69d59f274d709","src/unix/uclibc/x86_64/align.rs":"4e34cebb7955e9c98ae2f310be6f8ed16a861fc3817c08543867554aeec9524e","src/unix/uclibc/x86_64/l4re.rs":"bb31053d6403091e11f95ac2203982f279f8b984a19adf30796878c45fdd8c25","src/unix/uclibc/x86_64/mod.rs":"188fbaf06a8e23cac72718b1ef7eb4bd98bdfd946aa708151f3f7e3553b65876","src/unix/uclibc/x86_64/no_align.rs":"2ccc0107a6007c70dc49e656095b64a352ca5d8f9f3e65c1dba634effbc15636","src/unix/uclibc/x86_64/other.rs":"42c3f71e58cabba373f6a55a623f3c31b85049eb64824c09c2b082b3b2d6a0a8","src/vxworks/aarch64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/arm.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/mod.rs":"e78d05ff53cc6af0ae41ca0af8d7ee2b3ca1b1b05216a9e39db19d67e9f8f8c6","src/vxworks/powerpc.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/powerpc64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/x86.rs":"552f007f38317620b23889cb7c49d1d115841252439060122f52f434fbc6e5ba","src/vxworks/x86_64.rs":"018d92be3ad628a129eff9f2f5dfbc0883d8b8e5f2fa917b900a7f98ed6b514a","src/wasi.rs":"486a00bafb5b6bf0538c4d984dab021835295c431cb2ceb7a9a74b499f78ade6","src/windows/gnu/align.rs":"b2c13ec1b9f3b39a75c452c80c951dff9d0215e31d77e883b4502afb31794647","src/windows/gnu/mod.rs":"c7ab9793baaa3b6854d25fdf44266b7953533009e4fa722ca717b71d3e5d2c9d","src/windows/mod.rs":"7b74bf885712d16a3557df33ef02799dc03d4a1af953c7e6b4648954ce7a20fc","src/windows/msvc.rs":"2c2bfce66027d88021e7289139ebf5b0db258a7b6443f18872c84dbd4ef57131","tests/const_fn.rs":"cb75a1f0864f926aebe79118fc34d51a0d1ade2c20a394e7774c7e545f21f1f4","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"} \ No newline at end of file +{"files":{"CONTRIBUTING.md":"3a9f0037ad5f1198eada74a9d0363925ef09db664380b0e5a2840f03da260476","Cargo.toml":"d372dc49f9d6323c13f9aa079f463e435562b4ea1c73cc7de0bdd0134cdf0a15","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a8d47ff51ca256f56a8932dba07660672dbfe3004257ca8de708aac1415937a1","README.md":"8d633db1fa838f24fb7ae854b31f37fc238b833d6f4044a1c3c077fe88a59e1f","build.rs":"e487789ca77b0015d75cecb253286d4a1406f11b1ae538929414fc0506842bef","rustfmt.toml":"8a654d5787585ca8f2c20580737336fc327f411a07b0dbd4870adf6e9bdf624f","src/cloudabi/aarch64.rs":"b8550bf1fd7344972aa4db29441486f39f31482d0327534981dbb75959c29114","src/cloudabi/arm.rs":"c197e2781c2839808bd6fcef219a29705b27b992d3ef920e9cf6ac96e2022bbf","src/cloudabi/mod.rs":"d5d4488e8c0b8227f516fe13810f550a2a72af3bdfe769200ad8687c8755bdf6","src/cloudabi/x86.rs":"33eb97f272d2201f3838ae74d444583c7de8f67856852ca375293b20bbd05636","src/cloudabi/x86_64.rs":"400d85d4fe39e26cf2e6ece9ee31c75fe9e88c4bcf4d836ca9f765c05c9c5be3","src/fixed_width_ints.rs":"34c60f12ec5eeb90f13ec3b954427532111c2446e69617616a97aefc1086a9f1","src/fuchsia/aarch64.rs":"378776a9e40766154a54c94c2a7b4675b5c302a38e6e42da99e67bfbaee60e56","src/fuchsia/align.rs":"ae1cf8f011a99737eabeb14ffff768e60f13b13363d7646744dbb0f443dab3d6","src/fuchsia/mod.rs":"61502b3d124759c7c1bae294c1662036a96718fb3bd329cfa2f12e1c61ac10ad","src/fuchsia/no_align.rs":"303f3f1b255e0088b5715094353cf00476131d8e94e6aebb3f469557771c8b8a","src/fuchsia/x86_64.rs":"93a3632b5cf67d2a6bcb7dc0a558605252d5fe689e0f38d8aa2ec5852255ac87","src/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/hermit/mod.rs":"d3bfce41e4463d4be8020a2d063c9bfa8b665f45f1cc6cbf3163f5d01e7cb21f","src/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/lib.rs":"d80f0a2f77d485601a218e0707474245636d8b23fb3d6c65c9dbd4302ea6674b","src/macros.rs":"f024ec4ccd3762d4da198f14718d15a3ef70207f63aa3dceabf0de480fe780e9","src/psp.rs":"a621e34d2d31d9b29c725897b846122acce4763ac2017a1fe2200b133e5ad064","src/sgx.rs":"16a95cdefc81c5ee00d8353a60db363c4cc3e0f75abcd5d0144723f2a306ed1b","src/switch.rs":"9da3dd39b3de45a7928789926e8572d00e1e11a39e6f7289a1349aadce90edba","src/unix/align.rs":"2cdc7c826ef7ae61f5171c5ae8c445a743d86f1a7f2d9d7e4ceeec56d6874f65","src/unix/bsd/apple/b32/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b32/mod.rs":"6a4ce300da0d2b0db04b18548286603ffe4b47d679a41cf60f1902895894aa1f","src/unix/bsd/apple/b64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/mod.rs":"81254d89be1febc5bb20e787d014a624950d56e2e14973df5bbebfdabc95ae20","src/unix/bsd/apple/mod.rs":"41a54fb1f44b3d5bd79be9ecbb227c67c33caed5dcd80f9a8daf845222bee883","src/unix/bsd/freebsdlike/dragonfly/errno.rs":"63f22519f7f4b18152f912c03b860532114b8726832c40b5590def6f02eeb13a","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"1f361fc8c73eef537b274ab126d641614f076a488acfbdb19dcc053c50bc5308","src/unix/bsd/freebsdlike/freebsd/aarch64.rs":"14f0bd6693967d4fedec904f7042bd51f2138cb843ec4df18c911b357417cdd2","src/unix/bsd/freebsdlike/freebsd/arm.rs":"59d6a670eea562fb87686e243e0a84603d29a2028a3d4b3f99ccc01bd04d2f47","src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs":"9808d152c1196aa647f1b0f0cf84dac8c930da7d7f897a44975545e3d9d17681","src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs":"16dd3e1a09f123d0aa544b3fd7c123654b4906cac94838fbed7f34a64413c930","src/unix/bsd/freebsdlike/freebsd/freebsd12/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs":"c6152ce3db241d99e350d34352f3f3d167953ef0ee08bfbe2685cb9ebde2e83b","src/unix/bsd/freebsdlike/freebsd/mod.rs":"1d0e3411a757a6f3f533177dbd4058a2ce8fd062130734cea6a225210a8664ae","src/unix/bsd/freebsdlike/freebsd/powerpc64.rs":"2dae3ecc87eac3b11657aa98915def55fc4b5c0de11fe26aae23329a54628a9a","src/unix/bsd/freebsdlike/freebsd/x86.rs":"c5005e3249eb7c93cfbac72a9e9272320d80ce7983da990ceb05a447f59a02c5","src/unix/bsd/freebsdlike/freebsd/x86_64/align.rs":"0e1f69a88fca1c32874b1daf5db3d446fefbe518dca497f096cc9168c39dde70","src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs":"6132aa0973454379674ea6cbc77e6eace1e1032dd9f38182071388a036f1bc08","src/unix/bsd/freebsdlike/mod.rs":"9f123d0fbc452013ddc233e61f988ca22483beb21b01983b4754b9a1515205b4","src/unix/bsd/mod.rs":"92fb2e6f86189b7d56d9d02c44cdf35b964b982e439b806901de1637272d9df3","src/unix/bsd/netbsdlike/mod.rs":"48dd60524119c1e09b255d5472d091e7e7b2b29eab04be51b4b1e740bd022859","src/unix/bsd/netbsdlike/netbsd/aarch64.rs":"b38fc046f9a40fea28bd26328b96629f4d5d63d7524936bd6af1865d401a8716","src/unix/bsd/netbsdlike/netbsd/arm.rs":"58cdbb70b0d6f536551f0f3bb3725d2d75c4690db12c26c034e7d6ec4a924452","src/unix/bsd/netbsdlike/netbsd/mod.rs":"16a9036b6a8b373cdf0576ae99c95430f3f111b6be906a1e1ecff8047e178a86","src/unix/bsd/netbsdlike/netbsd/powerpc.rs":"ee7ff5d89d0ed22f531237b5059aa669df93a3b5c489fa641465ace8d405bf41","src/unix/bsd/netbsdlike/netbsd/sparc64.rs":"9489f4b3e4566f43bb12dfb92238960613dac7f6a45cc13068a8d152b902d7d9","src/unix/bsd/netbsdlike/netbsd/x86.rs":"20692320e36bfe028d1a34d16fe12ca77aa909cb02bda167376f98f1a09aefe7","src/unix/bsd/netbsdlike/netbsd/x86_64.rs":"135509edeaf3fb3f102d89d51ff1a8f82323497336a8dc7e1f0f23b5c2434b73","src/unix/bsd/netbsdlike/openbsd/aarch64.rs":"1dd5449dd1fd3d51e30ffdeeaece91d0aaf05c710e0ac699fecc5461cfa2c28e","src/unix/bsd/netbsdlike/openbsd/mod.rs":"a2938e72d1c6e3f32fb51e896b63abd0d79e1e360dc53f9254fdac82b21206b9","src/unix/bsd/netbsdlike/openbsd/sparc64.rs":"d04fd287afbaa2c5df9d48c94e8374a532a3ba491b424ddf018270c7312f4085","src/unix/bsd/netbsdlike/openbsd/x86.rs":"6f7f5c4fde2a2259eb547890cbd86570cea04ef85347d7569e94e679448bec87","src/unix/bsd/netbsdlike/openbsd/x86_64.rs":"e59b7fd65f68f8e857eec39e0c03bac1d3af6ddc26c9ba58494336b83659bb9b","src/unix/haiku/b32.rs":"69ae47fc52c6880e85416b4744500d5655c9ec6131cb737f3b649fceaadce15a","src/unix/haiku/b64.rs":"73e64db09275a8da8d50a13cce2cfa2b136036ddf3a930d2939f337fc995900b","src/unix/haiku/mod.rs":"449eabbfc0390282a3b7da5c1d22f5df88145a49f879e55ba99fda1092fb8312","src/unix/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/unix/hermit/mod.rs":"fb7e14d0f46ffaa989b5ab68c85184efe6aa04b5381e46866299b1f3258ddce3","src/unix/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/unix/linux_like/android/b32/arm.rs":"155994121906903a2e0afad895f0b3b7546f6e54d6305a3336ce2c4dfafbfdfa","src/unix/linux_like/android/b32/mod.rs":"0325adf3364fed7157fff5b24fabe1b36d806c39ee04ec82dd29a606d28f91f6","src/unix/linux_like/android/b32/x86/align.rs":"812914e4241df82e32b12375ca3374615dc3a4bdd4cf31f0423c5815320c0dab","src/unix/linux_like/android/b32/x86/mod.rs":"5b1e9fcd77ca5f939acb7fb5f5da12f305b0377698d8b8989feb236e26360aa0","src/unix/linux_like/android/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/android/b64/aarch64/mod.rs":"655116966eb7846b933e5e28b073c329668588cd3c2120cc9ce60c697bd19978","src/unix/linux_like/android/b64/mod.rs":"6a71abfcbbcdae60c916de41cd4688d5f25bdbca83d1d9df49decd56ad726a06","src/unix/linux_like/android/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/android/b64/x86_64/mod.rs":"e84176d838e663d351450bad218715db1fafbb531e47ea0e262cbb45829dae89","src/unix/linux_like/android/mod.rs":"a30a8bd58d6e9e330ed42af86db84a7dde7225262bc1197066cdb776cc1936a4","src/unix/linux_like/emscripten/align.rs":"86c95cbed7a7161b1f23ee06843e7b0e2340ad92b2cb86fe2a8ef3e0e8c36216","src/unix/linux_like/emscripten/mod.rs":"55fb89f5a965a4ad81ee4d02498c32aaed69e6047ce708c2329a602171862a76","src/unix/linux_like/emscripten/no_align.rs":"0128e4aa721a9902754828b61b5ec7d8a86619983ed1e0544a85d35b1051fad6","src/unix/linux_like/linux/align.rs":"dde648468764a5deef5566b8016290150acf50ee6a0f8c0678cb2078658bc2fa","src/unix/linux_like/linux/gnu/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/gnu/b32/arm/align.rs":"3fed009dc9af3cc81be7087da9d2d7d1f39845e4497e290259c5cdbae25f039d","src/unix/linux_like/linux/gnu/b32/arm/mod.rs":"6d9ba242111c7be8173b7a7b8cf8c863ba23d839edc9d026c0fd37a4b64460b4","src/unix/linux_like/linux/gnu/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/gnu/b32/mips/mod.rs":"e2d2e51fea73210d9705b7eaa37de8baa7152b71ae3a10a316c277345c529b5c","src/unix/linux_like/linux/gnu/b32/mod.rs":"e224551fa50be726bc8a559da32a96294b18743fb5a5b67cdbee4bb6a9eeb796","src/unix/linux_like/linux/gnu/b32/powerpc.rs":"39aae80d2c4ffa845592e16c0a6c910017de19e2b15c1e507c4df10e79ce3e38","src/unix/linux_like/linux/gnu/b32/sparc/align.rs":"21adbed27df73e2d1ed934aaf733a643003d7baf2bde9c48ea440895bcca6d41","src/unix/linux_like/linux/gnu/b32/sparc/mod.rs":"3b4dd40b288788740d2b030171b21f9d0b076ce26d88e0ff62f5d87f09e7c787","src/unix/linux_like/linux/gnu/b32/x86/align.rs":"e4bafdc4a519a7922a81b37a62bbfd1177a2f620890eef8f1fbc47162e9eb413","src/unix/linux_like/linux/gnu/b32/x86/mod.rs":"927d1bd8cb2f053549fc5acfeb1315b7f80b35d7a1904cd76e99651ff32b141e","src/unix/linux_like/linux/gnu/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs":"17e9cd23a14bd19700c05a154568fff5897788c0ae151c21dd3bba67aac829d9","src/unix/linux_like/linux/gnu/b64/mips64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/mips64/mod.rs":"0b5d94f3a2361742b6dd9eb3f543ddf675d3f70dab3402ad179faa6ddaae2218","src/unix/linux_like/linux/gnu/b64/mod.rs":"b90d87f76bff37707a1725551fe45d70d0c106e01b1dbbcd5f60460e0a19b4c3","src/unix/linux_like/linux/gnu/b64/powerpc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs":"2f279eb268c0aca9a6bd9b4c84139799cd039a64ca1cd2ded68b04c63397be1b","src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs":"bb01828300f02c11c27689522454439d0d02f22d738df88a97367dc87eecf868","src/unix/linux_like/linux/gnu/b64/s390x.rs":"9c449b64b11cbf55d453b324cf9475acb3253f85cb9692f9873b777ed8978ff4","src/unix/linux_like/linux/gnu/b64/sparc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs":"a2667a09e526878683fafa02474f81fbc212d861ceeabade17b0ff4d6d49ff9d","src/unix/linux_like/linux/gnu/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs":"e6197537739cb8628cad25827081c8bf6b371c02ad4b2132b30b9ae74143b1ef","src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs":"c1862036556262f076eda2008470b8a351b9c371d70664f54387c46890e8cd18","src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs":"30f88d0fa9e7807ee4cbe89fd274061f810099567d5e68fa829277d7d27ba708","src/unix/linux_like/linux/gnu/mod.rs":"747a07b094dff07bbf77049ce1117098255de9be403a6f703219c1c6a174898c","src/unix/linux_like/linux/gnu/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/mod.rs":"34c5f6451bed8875b1db90b49260c0eba55aa67eadc77b82d2ba818750569602","src/unix/linux_like/linux/musl/b32/arm/align.rs":"3e8ac052c1043764776b54c93ba4260e061df998631737a897d9d47d54f7b80c","src/unix/linux_like/linux/musl/b32/arm/mod.rs":"45062a178b382ab17341a69d027b5c83325c4e79fecf45729ba9c47b1bcdc3da","src/unix/linux_like/linux/musl/b32/hexagon.rs":"7c6c481f70da1fe6ca759f363784e130041f3d87906c45910fc1142b5ef17970","src/unix/linux_like/linux/musl/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/musl/b32/mips/mod.rs":"9eb0e4953be5afaa0b9e3ac54c85ed40583cfb8cc0b03264b9bc8f763a8f3254","src/unix/linux_like/linux/musl/b32/mod.rs":"8ede3985e6243882814ce91e8ce543e7edbafc0cee5932816072b6f14207a671","src/unix/linux_like/linux/musl/b32/powerpc.rs":"cf286cbf4d2076aaa82662ace2b5c333480410fa59af5cb4542d59f04da84b31","src/unix/linux_like/linux/musl/b32/x86/align.rs":"08e77fbd7435d7dec2ff56932433bece3f02e47ce810f89004a275a86d39cbe1","src/unix/linux_like/linux/musl/b32/x86/mod.rs":"9c3b6e98e7710d6c877a4e31726d36416115a58f53fc469bb173b7fe660b39e5","src/unix/linux_like/linux/musl/b64/aarch64/align.rs":"22da1c030c254c511bc335c824d40b693904975a4633f8243a8777ca68ef1c65","src/unix/linux_like/linux/musl/b64/aarch64/mod.rs":"9870fd9a953c98b775c9e17a29a66bbe8019a6236eb69a0272f42232a226521d","src/unix/linux_like/linux/musl/b64/mips64.rs":"9d0158ac7a913222d0a62239ec043aa1aee73522a7a1e0e191d0642dde35c083","src/unix/linux_like/linux/musl/b64/mod.rs":"8b76e92a1505ad785d4aa0b7739e0b93647a1e81910949b49cedb6c88468be9c","src/unix/linux_like/linux/musl/b64/powerpc64.rs":"ed9b879bb9cdc526ad83815875edeb4cad4e8829086dfba2578277c265336229","src/unix/linux_like/linux/musl/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/musl/b64/x86_64/mod.rs":"cfeb109c732ac6bc7d2be44069d3652e917a0509b8b545270b756ff2d52e27e8","src/unix/linux_like/linux/musl/mod.rs":"243e32b93641df7a77f970a32c0fb8e4fd4a13720e54e0e42a9da321fd169798","src/unix/linux_like/linux/no_align.rs":"c81ccd1942295d423b43a55b4aa19633c2096fb93bb381a6a29acb93e85aab07","src/unix/linux_like/mod.rs":"9db5a512b824c5ec124951ccefd1f78285d1549adce7798645b5fdef1643000b","src/unix/mod.rs":"48268482b43ab4bf82d6a6e67f64043279c7266032826ff25d3ccc14ac0ae1ed","src/unix/newlib/aarch64/mod.rs":"bb269c1468a9676442554600e87417079a787fe6220dfc23b3109639259e8710","src/unix/newlib/align.rs":"28aaf87fafbc6b312622719d472d8cf65f9e5467d15339df5f73e66d8502b28a","src/unix/newlib/arm/mod.rs":"c71be856bfd7f576b2db28af9f680211cbe6c1cac7d537bbc8020b39591af07c","src/unix/newlib/mod.rs":"2f771ab23df36ab0c7a117e854483a917aaf9c5cbb9eded1bdda35827cdaf734","src/unix/newlib/no_align.rs":"7123dcec13604a11b7765c380ff3a4d0da19c39f4b03919de7857723c0cf1502","src/unix/newlib/powerpc/mod.rs":"2d0f7af28b47f7a2a6c210ebd1c1f33ed8eac62e56b5af2b856de2ad3fdc5187","src/unix/newlib/xtensa/mod.rs":"4c72003c5e692e648c7e798358c49af6901e68850dbba0624af84c40baf208f5","src/unix/no_align.rs":"c06e95373b9088266e0b14bba0954eef95f93fb2b01d951855e382d22de78e53","src/unix/redox/mod.rs":"89c31827cf348e9a7af387f9e708fc834d04da36cad415d3957d2faa70f2fcbe","src/unix/solarish/compat.rs":"3f13657fc072462b85b5f937f0db1427c41acb2a714cc4f78fefba1ea8036846","src/unix/solarish/illumos.rs":"1088c45b238e7d398dbb140d238257d5b5f93aeded98652c3f6747f0c07b4fa7","src/unix/solarish/mod.rs":"a9e46c0eee970cb5b4bd910924141d223fad4aa45380d3df1ce4b25992a13037","src/unix/solarish/solaris.rs":"6000d322ee9f691f38a2cd89b2b8838e51f64c01584143924962b0c598e0985c","src/unix/uclibc/align.rs":"a8540e1cce5913a45bc8d7422b79e86c0b12740e8a679478e0e4d863a31f8cc1","src/unix/uclibc/arm/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/arm/mod.rs":"d67dd46bc6f417169fc6a23832bde7ccdafc5d1bcb08b10debdd82edaf75d529","src/unix/uclibc/arm/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips32/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/mips/mips32/mod.rs":"a045ebc6619f540adf670b88a987abd2d6e42e440a552e8cfe9f8c77f397e873","src/unix/uclibc/mips/mips32/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips64/align.rs":"a7bdcb18a37a2d91e64d5fad83ea3edc78f5412adb28f77ab077dbb26dd08b2d","src/unix/uclibc/mips/mips64/mod.rs":"e3085ba56cfbc528d7c3c55065880603238c333b6047ef51c58177508a487fcd","src/unix/uclibc/mips/mips64/no_align.rs":"4a18e3875698c85229599225ac3401a2a40da87e77b2ad4ef47c6fcd5a24ed30","src/unix/uclibc/mips/mod.rs":"1054d0bfeb506b3346b9a4148564beced8a22da0d9c9a612101f6237756795fb","src/unix/uclibc/mod.rs":"18d6c2628ca458ba75e743bce75bda6614de99606af4e2e62daf2440d2878f18","src/unix/uclibc/no_align.rs":"3f28637046524618adaa1012e26cb7ffe94b9396e6b518cccdc69d59f274d709","src/unix/uclibc/x86_64/align.rs":"4e34cebb7955e9c98ae2f310be6f8ed16a861fc3817c08543867554aeec9524e","src/unix/uclibc/x86_64/l4re.rs":"bb31053d6403091e11f95ac2203982f279f8b984a19adf30796878c45fdd8c25","src/unix/uclibc/x86_64/mod.rs":"188fbaf06a8e23cac72718b1ef7eb4bd98bdfd946aa708151f3f7e3553b65876","src/unix/uclibc/x86_64/no_align.rs":"2ccc0107a6007c70dc49e656095b64a352ca5d8f9f3e65c1dba634effbc15636","src/unix/uclibc/x86_64/other.rs":"42c3f71e58cabba373f6a55a623f3c31b85049eb64824c09c2b082b3b2d6a0a8","src/vxworks/aarch64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/arm.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/mod.rs":"e78d05ff53cc6af0ae41ca0af8d7ee2b3ca1b1b05216a9e39db19d67e9f8f8c6","src/vxworks/powerpc.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/powerpc64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/x86.rs":"552f007f38317620b23889cb7c49d1d115841252439060122f52f434fbc6e5ba","src/vxworks/x86_64.rs":"018d92be3ad628a129eff9f2f5dfbc0883d8b8e5f2fa917b900a7f98ed6b514a","src/wasi.rs":"91950f1e7a7bea35e715d4ae6fc851717ae84dbfbb7902c9724fe0e71045c63c","src/windows/gnu/align.rs":"b2c13ec1b9f3b39a75c452c80c951dff9d0215e31d77e883b4502afb31794647","src/windows/gnu/mod.rs":"c7ab9793baaa3b6854d25fdf44266b7953533009e4fa722ca717b71d3e5d2c9d","src/windows/mod.rs":"7b74bf885712d16a3557df33ef02799dc03d4a1af953c7e6b4648954ce7a20fc","src/windows/msvc.rs":"2c2bfce66027d88021e7289139ebf5b0db258a7b6443f18872c84dbd4ef57131","tests/const_fn.rs":"cb75a1f0864f926aebe79118fc34d51a0d1ade2c20a394e7774c7e545f21f1f4","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"} \ No newline at end of file diff --git a/vendor/libc/Cargo.toml b/vendor/libc/Cargo.toml index b7cb5eccb1..7ab5a99706 100644 --- a/vendor/libc/Cargo.toml +++ b/vendor/libc/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "libc" -version = "0.2.76" +version = "0.2.77" authors = ["The Rust Project Developers"] build = "build.rs" exclude = ["/ci/*", "/azure-pipelines.yml"] diff --git a/vendor/libc/src/macros.rs b/vendor/libc/src/macros.rs index 378da7ccfb..b314f60ff2 100644 --- a/vendor/libc/src/macros.rs +++ b/vendor/libc/src/macros.rs @@ -195,6 +195,21 @@ cfg_if! { )*) } + #[allow(unused_macros)] + macro_rules! safe_f { + ($(pub $({$constness:ident})* fn $i:ident( + $($arg:ident: $argty:ty),* + ) -> $ret:ty { + $($body:stmt);* + })*) => ($( + #[inline] + pub $($constness)* extern fn $i($($arg: $argty),* + ) -> $ret { + $($body);* + } + )*) + } + #[allow(unused_macros)] macro_rules! const_fn { ($($({$constness:ident})* fn $i:ident( @@ -226,6 +241,21 @@ cfg_if! { )*) } + #[allow(unused_macros)] + macro_rules! safe_f { + ($(pub $({$constness:ident})* fn $i:ident( + $($arg:ident: $argty:ty),* + ) -> $ret:ty { + $($body:stmt);* + })*) => ($( + #[inline] + pub extern fn $i($($arg: $argty),* + ) -> $ret { + $($body);* + } + )*) + } + #[allow(unused_macros)] macro_rules! const_fn { ($($({$constness:ident})* fn $i:ident( diff --git a/vendor/libc/src/unix/bsd/apple/mod.rs b/vendor/libc/src/unix/bsd/apple/mod.rs index 857a2badee..b6984ecd4c 100644 --- a/vendor/libc/src/unix/bsd/apple/mod.rs +++ b/vendor/libc/src/unix/bsd/apple/mod.rs @@ -1406,6 +1406,7 @@ pub const O_DSYNC: ::c_int = 0x400000; pub const O_NOCTTY: ::c_int = 0x20000; pub const O_CLOEXEC: ::c_int = 0x1000000; pub const O_DIRECTORY: ::c_int = 0x100000; +pub const O_SYMLINK: ::c_int = 0x200000; pub const S_IFIFO: mode_t = 4096; pub const S_IFCHR: mode_t = 8192; pub const S_IFBLK: mode_t = 24576; diff --git a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs index e9ad63b86b..434ac63a3c 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs @@ -1,6 +1,7 @@ // DragonFlyBSD's __error function is declared with "static inline", so it must // be implemented in the libc crate, as a pointer to a static thread_local. f! { + #[deprecated(since = "0.2.77", "Use `__errno_location()` instead")] pub fn __error() -> *mut ::c_int { &mut errno } diff --git a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs index 5841947f33..47e3b7c152 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs @@ -460,21 +460,6 @@ pub const RLIM_NLIMITS: ::rlim_t = 12; pub const Q_GETQUOTA: ::c_int = 0x300; pub const Q_SETQUOTA: ::c_int = 0x400; -pub const CLOCK_REALTIME: ::clockid_t = 0; -pub const CLOCK_VIRTUAL: ::clockid_t = 1; -pub const CLOCK_PROF: ::clockid_t = 2; -pub const CLOCK_MONOTONIC: ::clockid_t = 4; -pub const CLOCK_UPTIME: ::clockid_t = 5; -pub const CLOCK_UPTIME_PRECISE: ::clockid_t = 7; -pub const CLOCK_UPTIME_FAST: ::clockid_t = 8; -pub const CLOCK_REALTIME_PRECISE: ::clockid_t = 9; -pub const CLOCK_REALTIME_FAST: ::clockid_t = 10; -pub const CLOCK_MONOTONIC_PRECISE: ::clockid_t = 11; -pub const CLOCK_MONOTONIC_FAST: ::clockid_t = 12; -pub const CLOCK_SECOND: ::clockid_t = 13; -pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 14; -pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 15; - pub const CTL_UNSPEC: ::c_int = 0; pub const CTL_KERN: ::c_int = 1; pub const CTL_VM: ::c_int = 2; @@ -1059,18 +1044,13 @@ f! { } extern "C" { + pub fn __errno_location() -> *mut ::c_int; pub fn setgrent(); pub fn mprotect( addr: *mut ::c_void, len: ::size_t, prot: ::c_int, ) -> ::c_int; - pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; - pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; - pub fn clock_settime( - clk_id: ::clockid_t, - tp: *const ::timespec, - ) -> ::c_int; pub fn setutxdb(_type: ::c_uint, file: *mut ::c_char) -> ::c_int; diff --git a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs index 1ca003959c..6359196138 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -447,21 +447,6 @@ pub const NOTE_NSECONDS: u32 = 0x00000008; pub const MADV_PROTECT: ::c_int = 10; pub const RUSAGE_THREAD: ::c_int = 1; -pub const CLOCK_REALTIME: ::clockid_t = 0; -pub const CLOCK_VIRTUAL: ::clockid_t = 1; -pub const CLOCK_PROF: ::clockid_t = 2; -pub const CLOCK_MONOTONIC: ::clockid_t = 4; -pub const CLOCK_UPTIME: ::clockid_t = 5; -pub const CLOCK_UPTIME_PRECISE: ::clockid_t = 7; -pub const CLOCK_UPTIME_FAST: ::clockid_t = 8; -pub const CLOCK_REALTIME_PRECISE: ::clockid_t = 9; -pub const CLOCK_REALTIME_FAST: ::clockid_t = 10; -pub const CLOCK_MONOTONIC_PRECISE: ::clockid_t = 11; -pub const CLOCK_MONOTONIC_FAST: ::clockid_t = 12; -pub const CLOCK_SECOND: ::clockid_t = 13; -pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 14; -pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 15; - #[doc(hidden)] #[deprecated( since = "0.2.72", @@ -1222,13 +1207,6 @@ f! { extern "C" { pub fn __error() -> *mut ::c_int; - pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; - pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; - pub fn clock_settime( - clk_id: ::clockid_t, - tp: *const ::timespec, - ) -> ::c_int; - pub fn extattr_delete_fd( fd: ::c_int, attrnamespace: ::c_int, diff --git a/vendor/libc/src/unix/bsd/freebsdlike/mod.rs b/vendor/libc/src/unix/bsd/freebsdlike/mod.rs index e9f70579ea..f70b8a5e6e 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/mod.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/mod.rs @@ -638,6 +638,21 @@ pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff; pub const RUSAGE_SELF: ::c_int = 0; pub const RUSAGE_CHILDREN: ::c_int = -1; +pub const CLOCK_REALTIME: ::clockid_t = 0; +pub const CLOCK_VIRTUAL: ::clockid_t = 1; +pub const CLOCK_PROF: ::clockid_t = 2; +pub const CLOCK_MONOTONIC: ::clockid_t = 4; +pub const CLOCK_UPTIME: ::clockid_t = 5; +pub const CLOCK_UPTIME_PRECISE: ::clockid_t = 7; +pub const CLOCK_UPTIME_FAST: ::clockid_t = 8; +pub const CLOCK_REALTIME_PRECISE: ::clockid_t = 9; +pub const CLOCK_REALTIME_FAST: ::clockid_t = 10; +pub const CLOCK_MONOTONIC_PRECISE: ::clockid_t = 11; +pub const CLOCK_MONOTONIC_FAST: ::clockid_t = 12; +pub const CLOCK_SECOND: ::clockid_t = 13; +pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 14; +pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 15; + pub const MADV_NORMAL: ::c_int = 0; pub const MADV_RANDOM: ::c_int = 1; pub const MADV_SEQUENTIAL: ::c_int = 2; @@ -1242,6 +1257,18 @@ extern "C" { flags: ::c_ulong, atflag: ::c_int, ) -> ::c_int; + + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_settime( + clk_id: ::clockid_t, + tp: *const ::timespec, + ) -> ::c_int; + pub fn clock_getcpuclockid( + pid: ::pid_t, + clk_id: *mut ::clockid_t, + ) -> ::c_int; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; pub fn duplocale(base: ::locale_t) -> ::locale_t; pub fn endutxent(); diff --git a/vendor/libc/src/unix/bsd/mod.rs b/vendor/libc/src/unix/bsd/mod.rs index 1b55078d5a..e49703e0da 100644 --- a/vendor/libc/src/unix/bsd/mod.rs +++ b/vendor/libc/src/unix/bsd/mod.rs @@ -254,6 +254,8 @@ pub const FIOGETOWN: ::c_ulong = 0x4004667b; pub const PATH_MAX: ::c_int = 1024; +pub const IOV_MAX: ::c_int = 1024; + pub const SA_ONSTACK: ::c_int = 0x0001; pub const SA_SIGINFO: ::c_int = 0x0040; pub const SA_RESTART: ::c_int = 0x0002; @@ -504,6 +506,10 @@ pub const PRIO_PROCESS: ::c_int = 0; pub const PRIO_PGRP: ::c_int = 1; pub const PRIO_USER: ::c_int = 2; +pub const ITIMER_REAL: ::c_int = 0; +pub const ITIMER_VIRTUAL: ::c_int = 1; +pub const ITIMER_PROF: ::c_int = 2; + f! { pub fn CMSG_FIRSTHDR(mhdr: *const ::msghdr) -> *mut ::cmsghdr { if (*mhdr).msg_controllen as usize >= ::mem::size_of::<::cmsghdr>() { @@ -847,6 +853,23 @@ extern "C" { options: ::c_int, rusage: *mut ::rusage, ) -> ::pid_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "getitimer$UNIX2003" + )] + pub fn getitimer( + which: ::c_int, + curr_value: *mut ::itimerval + ) -> ::c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "setitimer$UNIX2003" + )] + pub fn setitimer( + which: ::c_int, + new_value: *const ::itimerval, + old_value: *mut ::itimerval, + ) -> ::c_int; pub fn regcomp( preg: *mut regex_t, diff --git a/vendor/libc/src/unix/haiku/mod.rs b/vendor/libc/src/unix/haiku/mod.rs index adcac2e5ae..ccd11380e7 100644 --- a/vendor/libc/src/unix/haiku/mod.rs +++ b/vendor/libc/src/unix/haiku/mod.rs @@ -1292,6 +1292,9 @@ f! { extern "C" { pub fn getrlimit(resource: ::c_int, rlim: *mut ::rlimit) -> ::c_int; pub fn setrlimit(resource: ::c_int, rlim: *const ::rlimit) -> ::c_int; + pub fn getpriority(which: ::c_int, who: id_t) -> ::c_int; + pub fn setpriority(which: ::c_int, who: id_t, priority: ::c_int) -> ::c_int; + pub fn utimensat( fd: ::c_int, path: *const ::c_char, diff --git a/vendor/libc/src/unix/linux_like/linux/mod.rs b/vendor/libc/src/unix/linux_like/linux/mod.rs index dc6512df1f..421e131ba4 100644 --- a/vendor/libc/src/unix/linux_like/linux/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/mod.rs @@ -2761,11 +2761,6 @@ extern "C" { sevp: *mut ::sigevent, ) -> ::c_int; - pub fn clock_getcpuclockid( - pid: ::pid_t, - clk_id: *mut ::clockid_t, - ) -> ::c_int; - pub fn lutimes(file: *const ::c_char, times: *const ::timeval) -> ::c_int; pub fn setpwent(); diff --git a/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs b/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs index d7e06cd21c..88c252ea6c 100644 --- a/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs @@ -170,7 +170,7 @@ pub const MAP_POPULATE: ::c_int = 0x08000; pub const MAP_NONBLOCK: ::c_int = 0x010000; pub const MAP_STACK: ::c_int = 0x020000; pub const MAP_HUGETLB: ::c_int = 0x040000; -pub const MAP_SYNC : ::c_int = 0x080000; +pub const MAP_SYNC: ::c_int = 0x080000; pub const SOCK_STREAM: ::c_int = 1; pub const SOCK_DGRAM: ::c_int = 2; @@ -284,6 +284,10 @@ pub const SYS_umount2: ::c_long = 39; pub const SYS_mount: ::c_long = 40; pub const SYS_pivot_root: ::c_long = 41; pub const SYS_nfsservctl: ::c_long = 42; +pub const SYS_statfs: ::c_long = 43; +pub const SYS_fstatfs: ::c_long = 44; +pub const SYS_truncate: ::c_long = 45; +pub const SYS_ftruncate: ::c_long = 46; pub const SYS_fallocate: ::c_long = 47; pub const SYS_faccessat: ::c_long = 48; pub const SYS_chdir: ::c_long = 49; diff --git a/vendor/libc/src/unix/linux_like/mod.rs b/vendor/libc/src/unix/linux_like/mod.rs index a48c3aaaad..2fc872b565 100644 --- a/vendor/libc/src/unix/linux_like/mod.rs +++ b/vendor/libc/src/unix/linux_like/mod.rs @@ -847,6 +847,8 @@ pub const SS_DISABLE: ::c_int = 2; pub const PATH_MAX: ::c_int = 4096; +pub const UIO_MAXIOV: ::c_int = 1024; + pub const FD_SETSIZE: usize = 1024; pub const EPOLLIN: ::c_int = 0x1; @@ -1233,64 +1235,66 @@ f! { *slot = 0; } } +} - pub fn WIFSTOPPED(status: ::c_int) -> bool { +safe_f! { + pub {const} fn WIFSTOPPED(status: ::c_int) -> bool { (status & 0xff) == 0x7f } - pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + pub {const} fn WSTOPSIG(status: ::c_int) -> ::c_int { (status >> 8) & 0xff } - pub fn WIFCONTINUED(status: ::c_int) -> bool { + pub {const} fn WIFCONTINUED(status: ::c_int) -> bool { status == 0xffff } - pub fn WIFSIGNALED(status: ::c_int) -> bool { + pub {const} fn WIFSIGNALED(status: ::c_int) -> bool { ((status & 0x7f) + 1) as i8 >= 2 } - pub fn WTERMSIG(status: ::c_int) -> ::c_int { + pub {const} fn WTERMSIG(status: ::c_int) -> ::c_int { status & 0x7f } - pub fn WIFEXITED(status: ::c_int) -> bool { + pub {const} fn WIFEXITED(status: ::c_int) -> bool { (status & 0x7f) == 0 } - pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + pub {const} fn WEXITSTATUS(status: ::c_int) -> ::c_int { (status >> 8) & 0xff } - pub fn WCOREDUMP(status: ::c_int) -> bool { + pub {const} fn WCOREDUMP(status: ::c_int) -> bool { (status & 0x80) != 0 } - pub fn W_EXITCODE(ret: ::c_int, sig: ::c_int) -> ::c_int { + pub {const} fn W_EXITCODE(ret: ::c_int, sig: ::c_int) -> ::c_int { (ret << 8) | sig } - pub fn W_STOPCODE(sig: ::c_int) -> ::c_int { + pub {const} fn W_STOPCODE(sig: ::c_int) -> ::c_int { (sig << 8) | 0x7f } - pub fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int { + pub {const} fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int { (cmd << 8) | (type_ & 0x00ff) } - pub fn IPOPT_COPIED(o: u8) -> u8 { + pub {const} fn IPOPT_COPIED(o: u8) -> u8 { o & IPOPT_COPY } - pub fn IPOPT_CLASS(o: u8) -> u8 { + pub {const} fn IPOPT_CLASS(o: u8) -> u8 { o & IPOPT_CLASS_MASK } - pub fn IPOPT_NUMBER(o: u8) -> u8 { + pub {const} fn IPOPT_NUMBER(o: u8) -> u8 { o & IPOPT_NUMBER_MASK } - pub fn IPTOS_ECN(x: u8) -> u8 { + pub {const} fn IPTOS_ECN(x: u8) -> u8 { x & ::IPTOS_ECN_MASK } } @@ -1308,12 +1312,18 @@ extern "C" { len: ::size_t, vec: *mut ::c_uchar, ) -> ::c_int; + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; pub fn clock_settime( clk_id: ::clockid_t, tp: *const ::timespec, ) -> ::c_int; + pub fn clock_getcpuclockid( + pid: ::pid_t, + clk_id: *mut ::clockid_t, + ) -> ::c_int; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; pub fn pthread_getattr_np( diff --git a/vendor/libc/src/unix/solarish/mod.rs b/vendor/libc/src/unix/solarish/mod.rs index 532e5aa6cf..9b1daeb659 100644 --- a/vendor/libc/src/unix/solarish/mod.rs +++ b/vendor/libc/src/unix/solarish/mod.rs @@ -2266,6 +2266,15 @@ extern "C" { f: extern "C" fn(*mut ::c_void) -> *mut ::c_void, value: *mut ::c_void, ) -> ::c_int; + pub fn pthread_getattr_np( + thread: ::pthread_t, + attr: *mut ::pthread_attr_t, + ) -> ::c_int; + pub fn pthread_attr_getstack( + attr: *const ::pthread_attr_t, + stackaddr: *mut *mut ::c_void, + stacksize: *mut ::size_t, + ) -> ::c_int; pub fn pthread_condattr_getclock( attr: *const pthread_condattr_t, clock_id: *mut clockid_t, diff --git a/vendor/libc/src/wasi.rs b/vendor/libc/src/wasi.rs index 6a26858694..12db506417 100644 --- a/vendor/libc/src/wasi.rs +++ b/vendor/libc/src/wasi.rs @@ -202,6 +202,7 @@ pub const O_SEARCH: c_int = 0x08000000; pub const O_WRONLY: c_int = 0x10000000; pub const O_RDWR: c_int = O_WRONLY | O_RDONLY; pub const O_ACCMODE: c_int = O_EXEC | O_RDWR | O_SEARCH; +pub const O_NOCTTY: c_int = 0x0; pub const POSIX_FADV_DONTNEED: c_int = 4; pub const POSIX_FADV_NOREUSE: c_int = 5; pub const POSIX_FADV_NORMAL: c_int = 0; @@ -230,6 +231,17 @@ pub const DT_REG: u8 = 4; pub const DT_LNK: u8 = 7; pub const FIONREAD: c_int = 1; pub const FIONBIO: c_int = 2; +pub const F_OK: ::c_int = 0; +pub const R_OK: ::c_int = 4; +pub const W_OK: ::c_int = 2; +pub const X_OK: ::c_int = 1; +pub const POLLIN: ::c_short = 0x1; +pub const POLLOUT: ::c_short = 0x2; +pub const POLLERR: ::c_short = 0x1000; +pub const POLLHUP: ::c_short = 0x2000; +pub const POLLNVAL: ::c_short = 0x4000; +pub const POLLRDNORM: ::c_short = 0x1; +pub const POLLWRNORM: ::c_short = 0x2; pub const E2BIG: c_int = 1; pub const EACCES: c_int = 2; diff --git a/vendor/libloading/.cargo-checksum.json b/vendor/libloading/.cargo-checksum.json index 2685cdd749..b13fbd8317 100644 --- a/vendor/libloading/.cargo-checksum.json +++ b/vendor/libloading/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f6ff11a653f961e5ece86a28ad80d498a974cac8200d3a2d9c88abf9438070b4","LICENSE":"b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f","README.mkd":"1be1c69361f15ea2a555dfd9abb05fcef1b692019e4911cbfdaa4e734baa89e3","build.rs":"836e601b6f981ded849d531053a017fc9fa1fffbe7162f124fab0ca161142ab3","src/changelog.rs":"ad8371639d99571911f6e35142905ebd5eb9b520000e7f02989bdbebf5571eef","src/error.rs":"13c880ebc44626cd69f8a6c287ce81dd5ba2947ffa7913da727b8c2ad9910a3a","src/lib.rs":"55d9d61c6403b8634e128f0d0f64f5376b89b7bd75f459592660a471c88e9576","src/os/mod.rs":"51d733e5522dacd6069642ad66aa6d7acf6c82950c934eb040e8dfd112e6d610","src/os/unix/mod.rs":"ac04bbae9d42e74c128c4afd3581cc427b7109a16b968de3899522a4ce2e366f","src/os/windows/mod.rs":"4d0dd74b217a13efa99105c647de4fa807781343e15a3bc2554a1b3df7738d2e","src/test_helpers.rs":"3a55052e8cd5231e97d9282b43398c2f144c57ced2d2df64bde7f482f5c778e7","src/util.rs":"ce5da7b01f15c1d8d99a435079884d86abac861a0f2a1593df44fcb6478ad735","tests/functions.rs":"35132cb8057acb0abe73527872aa7f8d6b3b43773dd5c4d076dddf9d0d2d51a1","tests/markers.rs":"8e9c1b883404d9190e4f23ed39b3d6cbbccb3a07883f733b04aed4357b9c6aca","tests/nagisa32.dll":"5c69b2bd9c8a6ad04165c221075fc9fade1dd66ca697399ace528a5a62328e36","tests/nagisa64.dll":"e20b95e3036f3289421abd100760874d4f455afd33c3b5b64fec56b191f7d477","tests/windows.rs":"7711dfe19062d91356cd127546542b1b6e13aeef76ad3098f32c8a6ae319b66a"},"package":"2cadb8e769f070c45df05c78c7520eb4cd17061d4ab262e43cfc68b4d00ac71c"} \ No newline at end of file +{"files":{"Cargo.toml":"cbed52e85049d7bdb634eda426ab4219bc7cca2ebb8ad538c62367f9c02e4ea8","LICENSE":"b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f","README.mkd":"a393e1f356cb808332ce9259dba73214b00595198bb8b6274e12f86c79ecfa5d","build.rs":"50f772ce98b73be6000de5477020bd84c1e99e6acbf66877876a4b3a4fb0d169","src/changelog.rs":"0b44d40939f95afa33118e41ae2d11762f089b55d29c9157b20bcd6ea7d485c7","src/error.rs":"42fba08d5af2a1d4822e933fb9158d21761bbbfa8b83b1a09389158544b63925","src/lib.rs":"93e856cc28233c187b8dc2e39fdf33291f0323e1716a94e0500f2508ddfac71d","src/os/mod.rs":"88ff3de01a3a2e2ddd45d11de37f765fde2f2afc043e79fa78271c3a266815d4","src/os/unix/consts.rs":"027cd1c54eadb7ae87d8451181c16d6560b68d20ef684c6e15daa4ce56417840","src/os/unix/mod.rs":"227d331c0fc7e8ae9ef1a80f80539b3795a80d7b17ff7ab04b18239be15a0914","src/os/windows/mod.rs":"cadf5983848565ad6581a3edc068f3a1047d871dfaf8c3bef5275413eb2f13f1","src/test_helpers.rs":"201403e143e5b3204864124cd38067cf8813d5273dc1a9099288a9dc4bdd15b6","src/util.rs":"571ce54e82c48bb4d678240da1f61c2c935248b4e5b3010b49174b32224b9542","tests/constants.rs":"f958b26be93bd26d37b25963f019b7856151cb18dd98d34923ddf968121f7f0a","tests/functions.rs":"7f488a5009d94be9f96d18c54af5b7f5bfd52535fb898fda1c74bc00b14b284c","tests/library_filename.rs":"b1481f0bb374687c5f24e25113426d2a95f08a45fb8bc41a41e8702bd5a7b4bf","tests/markers.rs":"0ebc8f807b92e39452d35732988012cdca7ce96231c57eaac9c3f4217225ad39","tests/nagisa32.dll":"5c69b2bd9c8a6ad04165c221075fc9fade1dd66ca697399ace528a5a62328e36","tests/nagisa64.dll":"e20b95e3036f3289421abd100760874d4f455afd33c3b5b64fec56b191f7d477","tests/windows.rs":"7711dfe19062d91356cd127546542b1b6e13aeef76ad3098f32c8a6ae319b66a"},"package":"2443d8f0478b16759158b2f66d525991a05491138bc05814ef52a250148ef4f9"} \ No newline at end of file diff --git a/vendor/libloading/Cargo.toml b/vendor/libloading/Cargo.toml index 630f1e7044..41ad4e7656 100644 --- a/vendor/libloading/Cargo.toml +++ b/vendor/libloading/Cargo.toml @@ -12,14 +12,26 @@ [package] name = "libloading" -version = "0.6.2" +version = "0.6.3" authors = ["Simonas Kazlauskas "] build = "build.rs" description = "A safer binding to platform’s dynamic library loading utilities" documentation = "https://docs.rs/libloading/" +readme = "README.mkd" keywords = ["dlopen", "load", "shared", "dylib"] +categories = ["api-bindings"] license = "ISC" repository = "https://github.com/nagisa/rust_libloading/" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +[dev-dependencies.libc] +version = "0.2" + +[dev-dependencies.static_assertions] +version = "1.1" +[target."cfg(unix)".dependencies.cfg-if] +version = "0.1" [target."cfg(windows)".dependencies.winapi] version = "0.3" features = ["winerror", "errhandlingapi", "libloaderapi"] diff --git a/vendor/libloading/README.mkd b/vendor/libloading/README.mkd index 006f172340..8f7d3427ce 100644 --- a/vendor/libloading/README.mkd +++ b/vendor/libloading/README.mkd @@ -1,6 +1,6 @@ # libloading -A memory-safer wrapper around system dynamic library loading primitives. The most important safety +Safer bindings around system dynamic library loading primitives. The most important safety guarantee by this library is prevention of dangling-`Symbol`s that may occur after a `Library` is unloaded. @@ -13,4 +13,4 @@ functions and static variables these libraries contain. [docs]: https://docs.rs/libloading/ [changelog]: https://docs.rs/libloading/*/libloading/changelog/index.html -libloading is distributed under ISC (MIT-like) license. +libloading is available to use under ISC (MIT-like) license. diff --git a/vendor/libloading/build.rs b/vendor/libloading/build.rs index fdc446d34b..e217f80128 100644 --- a/vendor/libloading/build.rs +++ b/vendor/libloading/build.rs @@ -61,4 +61,10 @@ fn main() { ::std::process::exit(0xfd); } } + + // For tests + println!( + "cargo:rustc-env=LIBLOADING_TEST_TARGET={}", + std::env::var("TARGET").expect("$TARGET is not set") + ); } diff --git a/vendor/libloading/src/changelog.rs b/vendor/libloading/src/changelog.rs index 952eb5ec2d..01c25ec483 100644 --- a/vendor/libloading/src/changelog.rs +++ b/vendor/libloading/src/changelog.rs @@ -1,6 +1,18 @@ //! Project changelog // TODO: for the next breaking release rename `Error::LoadLibraryW` to `Error::LoadLibraryExW`. +// TODO: for the next breaking release use `RTLD_LAZY | RTLD_LOCAL` by default on unix. + +/// Release 0.6.3 (2020-08-22) +/// +/// * Improve documentation, allowing to view all of the os-specific functionality from +/// documentation generated for any target; +/// * Add [`os::windows::Library::this`]; +/// * Added constants to use with OS-specific `Library::open`; +/// * Add [`library_filename`]. +/// +/// [`os::windows::Library::this`]: crate::os::windows::Library::this +/// [`library_filename`]: crate::library_filename /// Release 0.6.2 (2020-05-06) /// @@ -12,7 +24,7 @@ pub mod r0_6_2 {} /// * Introduced a new method [`os::windows::Library::load_with_flags`]; /// * Added support for the Illumos triple. /// -/// [`os::windows::Library::load_with_flags`]: ../../os/windows/struct.Library.html#method.load_with_flags +/// [`os::windows::Library::load_with_flags`]: crate::os::windows::Library::load_with_flags pub mod r0_6_1 {} /// Release 0.6.0 (2020-04-05) @@ -39,9 +51,9 @@ pub mod r0_6_1 {} /// `dlsym` returns a null pointer. For the use-cases where loading null pointers is necessary /// consider using [`os::unix::Library::get_singlethreaded`] instead. /// -/// [`Library::get`]: ../../struct.Library.html#method.get -/// [`os::unix::Library::get_singlethreaded`]: ../../os/unix/struct.Library.html#method.get_singlethreaded -/// [`Error`]: ../../enum.Error.html +/// [`Library::get`]: crate::Library::get +/// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded +/// [`Error`]: crate::Error pub mod r0_6_0 {} diff --git a/vendor/libloading/src/error.rs b/vendor/libloading/src/error.rs index dcbe2b1143..6ba536709d 100644 --- a/vendor/libloading/src/error.rs +++ b/vendor/libloading/src/error.rs @@ -1,5 +1,6 @@ use std::ffi::CString; +/// A `dlerror` error. pub struct DlDescription(pub(crate) CString); impl std::fmt::Debug for DlDescription { @@ -8,6 +9,7 @@ impl std::fmt::Debug for DlDescription { } } +/// A Windows API error. pub struct WindowsError(pub(crate) std::io::Error); impl std::fmt::Debug for WindowsError { @@ -16,39 +18,71 @@ impl std::fmt::Debug for WindowsError { } } +/// Errors. #[derive(Debug)] #[non_exhaustive] pub enum Error { /// The `dlopen` call failed. - DlOpen { desc: DlDescription }, + DlOpen { + /// The source error. + desc: DlDescription + }, /// The `dlopen` call failed and system did not report an error. DlOpenUnknown, /// The `dlsym` call failed. - DlSym { desc: DlDescription }, + DlSym { + /// The source error. + desc: DlDescription + }, /// The `dlsym` call failed and system did not report an error. DlSymUnknown, /// The `dlclose` call failed. - DlClose { desc: DlDescription }, + DlClose { + /// The source error. + desc: DlDescription + }, /// The `dlclose` call failed and system did not report an error. DlCloseUnknown, /// The `LoadLibraryW` call failed. - LoadLibraryW { source: WindowsError }, + LoadLibraryW { + /// The source error. + source: WindowsError + }, /// The `LoadLibraryW` call failed and system did not report an error. LoadLibraryWUnknown, + /// The `GetModuleHandleExW` call failed. + GetModuleHandleExW { + /// The source error. + source: WindowsError + }, + /// The `LoadLibraryW` call failed and system did not report an error. + GetModuleHandleExWUnknown, /// The `GetProcAddress` call failed. - GetProcAddress { source: WindowsError }, + GetProcAddress { + /// The source error. + source: WindowsError + }, /// The `GetProcAddressUnknown` call failed and system did not report an error. GetProcAddressUnknown, /// The `FreeLibrary` call failed. - FreeLibrary { source: WindowsError }, + FreeLibrary { + /// The source error. + source: WindowsError + }, /// The `FreeLibrary` call failed and system did not report an error. FreeLibraryUnknown, /// The requested type cannot possibly work. IncompatibleSize, /// Could not create a new CString. - CreateCString { source: std::ffi::NulError }, + CreateCString { + /// The source error. + source: std::ffi::NulError + }, /// Could not create a new CString from bytes with trailing null. - CreateCStringWithTrailing { source: std::ffi::FromBytesWithNulError }, + CreateCStringWithTrailing { + /// The source error. + source: std::ffi::FromBytesWithNulError + }, } impl std::error::Error for Error { @@ -75,9 +109,12 @@ impl std::fmt::Display for Error { DlSymUnknown => write!(f, "dlsym failed, but system did not report the error"), DlClose { ref desc } => write!(f, "{}", desc.0.to_string_lossy()), DlCloseUnknown => write!(f, "dlclose failed, but system did not report the error"), - LoadLibraryW { .. } => write!(f, "LoadLibraryW failed"), + LoadLibraryW { .. } => write!(f, "LoadLibraryExW failed"), LoadLibraryWUnknown => - write!(f, "LoadLibraryW failed, but system did not report the error"), + write!(f, "LoadLibraryExW failed, but system did not report the error"), + GetModuleHandleExW { .. } => write!(f, "GetModuleHandleExW failed"), + GetModuleHandleExWUnknown => + write!(f, "GetModuleHandleExWUnknown failed, but system did not report the error"), GetProcAddress { .. } => write!(f, "GetProcAddress failed"), GetProcAddressUnknown => write!(f, "GetProcAddress failed, but system did not report the error"), @@ -91,24 +128,3 @@ impl std::fmt::Display for Error { } } } - -#[cfg(test)] -mod tests { - #[test] - fn error_send() { - fn assert_send() {} - assert_send::(); - } - - #[test] - fn error_sync() { - fn assert_sync() {} - assert_sync::(); - } - - #[test] - fn error_display() { - fn assert_display() {} - assert_display::(); - } -} diff --git a/vendor/libloading/src/lib.rs b/vendor/libloading/src/lib.rs index fad7d63396..f6fc58d1ae 100644 --- a/vendor/libloading/src/lib.rs +++ b/vendor/libloading/src/lib.rs @@ -17,7 +17,7 @@ //! //! ```toml //! [dependencies] -//! libloading = "0.5" +//! libloading = "0.6" //! ``` //! //! Then inside your project @@ -36,7 +36,17 @@ //! //! The compiler will ensure that the loaded `function` will not outlive the `Library` it comes //! from, preventing a common cause of undefined behaviour and memory safety problems. -use std::ffi::OsStr; +#![deny( + missing_docs, + clippy::all, + unreachable_pub, + unused, +)] +#![cfg_attr(docsrs, deny(broken_intra_doc_links))] +#![cfg_attr(docsrs, feature(doc_cfg))] + +use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; +use std::ffi::{OsStr, OsString}; use std::fmt; use std::ops; use std::marker; @@ -64,7 +74,7 @@ impl Library { /// * Absolute path to the library; /// * Relative (to the current working directory) path to the library. /// - /// ## Thread-safety + /// # Thread-safety /// /// The implementation strives to be as MT-safe as sanely possible, however due to certain /// error-handling related resources not always being safe, this library is not MT-safe either. @@ -77,15 +87,17 @@ impl Library { /// [`SetErrorMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx /// /// Calling this function from multiple threads is not safe if used in conjunction with - /// path-less filename and library search path is modified (`SetDllDirectory` function on + /// relative filenames and the library search path is modified (`SetDllDirectory` function on /// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX). /// - /// ## Platform-specific behaviour + /// # Platform-specific behaviour /// /// When a plain library filename is supplied, locations where library is searched for is - /// platform specific and cannot be adjusted in a portable manner. + /// platform specific and cannot be adjusted in a portable manner. See documentation for + /// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods + /// for further information on library lookup behaviour. /// - /// ### Windows + /// ## Windows /// /// If the `filename` specifies a library filename without path and with extension omitted, /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a @@ -95,17 +107,18 @@ impl Library { /// `#[thread_local]` attributes), loading the library will fail on versions prior to Windows /// Vista. /// - /// ## Tips + /// # Tips /// /// Distributing your dynamic libraries under a filename common to all platforms (e.g. /// `awesome.module`) allows to avoid code which has to account for platform’s conventional /// library filenames. /// - /// Strive to specify absolute or relative path to your library, unless system-wide libraries - /// are being loaded. Platform-dependent library search locations combined with various quirks - /// related to path-less filenames may cause flaky code. + /// Strive to specify an absolute or at least a relative path to your library, unless + /// system-wide libraries are being loaded. Platform-dependent library search locations + /// combined with various quirks related to path-less filenames may cause flakiness in + /// programs. /// - /// ## Examples + /// # Examples /// /// ```no_run /// # use ::libloading::Library; @@ -126,16 +139,16 @@ impl Library { /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are /// most likely invalid. /// - /// ## Unsafety + /// # Safety /// /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is /// undefined. /// - /// ## Platform-specific behaviour + /// # Platform-specific behaviour /// - /// On Linux and Windows, a TLS variable acts just like any regular global variable. OS X uses - /// some sort of lazy initialization scheme, which makes loading TLS variables this way - /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour. + /// Implementation of thread local variables is extremely platform specific and uses of these + /// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems or + /// Windows. /// /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such /// as FreeBSD), this function will unconditionally return an error the underlying `dlsym` call @@ -143,7 +156,7 @@ impl Library { /// pointer without it being an error. If loading a null pointer is something you care about, /// consider using the [`os::unix::Library::get_singlethreaded`] call. /// - /// ## Examples + /// # Examples /// /// Given a loaded library: /// @@ -232,12 +245,13 @@ pub struct Symbol<'lib, T: 'lib> { impl<'lib, T> Symbol<'lib, T> { /// Extract the wrapped `os::platform::Symbol`. /// - /// ## Unsafety + /// # Safety + /// /// Using this function relinquishes all the lifetime guarantees. It is up to programmer to /// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol /// was loaded from. /// - /// ## Examples + /// # Examples /// /// ```no_run /// # use ::libloading::{Library, Symbol}; @@ -256,12 +270,12 @@ impl<'lib, T> Symbol<'lib, T> { /// Note that, in order to create association between the symbol and the library this symbol /// came from, this function requires reference to the library provided. /// - /// ## Unsafety + /// # Safety /// /// It is invalid to provide a reference to any other value other than the library the `sym` /// was loaded from. Doing so invalidates any lifetime guarantees. /// - /// ## Examples + /// # Examples /// /// ```no_run /// # use ::libloading::{Library, Symbol}; @@ -283,7 +297,7 @@ impl<'lib, T> Symbol<'lib, T> { impl<'lib, T> Symbol<'lib, Option> { /// Lift Option out of the symbol. /// - /// ## Examples + /// # Examples /// /// ```no_run /// # use ::libloading::{Library, Symbol}; @@ -326,3 +340,27 @@ impl<'lib, T> fmt::Debug for Symbol<'lib, T> { unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {} unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {} + +/// Converts a library name to a filename generally appropriate for use on the system. +/// +/// The function will prepend prefixes (such as `lib`) and suffixes (such as `.so`) to the library +/// `name` to construct the filename. +/// +/// # Examples +/// +/// It can be used to load global libraries in a platform independent manner: +/// +/// ``` +/// use libloading::{Library, library_filename}; +/// // Will attempt to load `libLLVM.so` on Linux, `libLLVM.dylib` on macOS and `LLVM.dll` on +/// // Windows. +/// let library = Library::new(library_filename("LLVM")); +/// ``` +pub fn library_filename>(name: S) -> OsString { + let name = name.as_ref(); + let mut string = OsString::with_capacity(name.len() + DLL_PREFIX.len() + DLL_SUFFIX.len()); + string.push(DLL_PREFIX); + string.push(name); + string.push(DLL_SUFFIX); + string +} diff --git a/vendor/libloading/src/os/mod.rs b/vendor/libloading/src/os/mod.rs index ccbc8e9778..40361c5f30 100644 --- a/vendor/libloading/src/os/mod.rs +++ b/vendor/libloading/src/os/mod.rs @@ -16,30 +16,12 @@ //! use libloading::os::windows::*; //! ``` -macro_rules! unix { - ($item: item) => { - /// UNIX implementation of dynamic library loading. - /// - /// This module should be expanded with more UNIX-specific functionality in the future. - $item - } -} +/// UNIX implementation of dynamic library loading. +#[cfg(any(unix, docsrs))] +#[cfg_attr(docsrs, doc(cfg(unix)))] +pub mod unix; -macro_rules! windows { - ($item: item) => { - /// Windows implementation of dynamic library loading. - /// - /// This module should be expanded with more Windows-specific functionality in the future. - $item - } -} - -#[cfg(unix)] -unix!(pub mod unix;); -#[cfg(unix)] -windows!(pub mod windows {}); - -#[cfg(windows)] -windows!(pub mod windows;); -#[cfg(windows)] -unix!(pub mod unix {}); +/// Windows implementation of dynamic library loading. +#[cfg(any(windows, docsrs))] +#[cfg_attr(docsrs, doc(cfg(windows)))] +pub mod windows; diff --git a/vendor/libloading/src/os/unix/consts.rs b/vendor/libloading/src/os/unix/consts.rs new file mode 100644 index 0000000000..823155e75f --- /dev/null +++ b/vendor/libloading/src/os/unix/consts.rs @@ -0,0 +1,230 @@ +use std::os::raw::c_int; + +/// Perform lazy binding. +/// +/// Relocations shall be performed at an implementation-defined time, ranging from the time +/// of the [`Library::open`] call until the first reference to a given symbol occurs. +/// Specifying `RTLD_LAZY` should improve performance on implementations supporting dynamic +/// symbol binding since a process might not reference all of the symbols in an executable +/// object file. And, for systems supporting dynamic symbol resolution for normal process +/// execution, this behavior mimics the normal handling of process execution. +/// +/// Conflicts with [`RTLD_NOW`]. +/// +/// [`Library::open`]: crate::os::unix::Library::open +pub const RTLD_LAZY: c_int = posix::RTLD_LAZY; + +/// Perform eager binding. +/// +/// All necessary relocations shall be performed when the executable object file is first +/// loaded. This may waste some processing if relocations are performed for symbols +/// that are never referenced. This behavior may be useful for applications that need to +/// know that all symbols referenced during execution will be available before +/// [`Library::open`] returns. +/// +/// Conflicts with [`RTLD_LAZY`]. +/// +/// [`Library::open`]: crate::os::unix::Library::open +pub const RTLD_NOW: c_int = posix::RTLD_NOW; + +/// Make loaded symbols available for resolution globally. +/// +/// The executable object file's symbols shall be made available for relocation processing of any +/// other executable object file. In addition, calls to [`Library::get`] on `Library` obtained from +/// [`Library::this`] allows executable object files loaded with this mode to be searched. +/// +/// [`Library::this`]: crate::os::unix::Library::this +/// [`Library::get`]: crate::os::unix::Library::get +pub const RTLD_GLOBAL: c_int = posix::RTLD_GLOBAL; + +/// Load symbols into an isolated namespace. +/// +/// The executable object file's symbols shall not be made available for relocation processing of +/// any other executable object file. This mode of operation is most appropriate for e.g. plugins. +pub const RTLD_LOCAL: c_int = posix::RTLD_LOCAL; + +#[cfg(docsrs)] +mod posix { + use super::c_int; + pub(super) const RTLD_LAZY: c_int = !0; + pub(super) const RTLD_NOW: c_int = !0; + pub(super) const RTLD_GLOBAL: c_int = !0; + pub(super) const RTLD_LOCAL: c_int = !0; +} + +#[cfg(not(docsrs))] +mod posix { + extern crate cfg_if; + use self::cfg_if::cfg_if; + use super::c_int; + cfg_if! { + if #[cfg(target_os = "haiku")] { + pub(super) const RTLD_LAZY: c_int = 0; + } else if #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + + target_os = "solaris", + target_os = "illumos", + + target_env = "uclibc", + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_LAZY: c_int = 1; + } else { + compile_error!( + "Target has no known `RTLD_LAZY` value. Please submit an issue or PR adding it." + ); + } + } + + cfg_if! { + if #[cfg(target_os = "haiku")] { + pub(super) const RTLD_NOW: c_int = 1; + } else if #[cfg(any( + target_os = "linux", + all(target_os = "android", target_pointer_width = "64"), + target_os = "emscripten", + + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + + target_os = "solaris", + target_os = "illumos", + + target_env = "uclibc", + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_NOW: c_int = 2; + } else if #[cfg(all(target_os = "android",target_pointer_width = "32"))] { + pub(super) const RTLD_NOW: c_int = 0; + } else { + compile_error!( + "Target has no known `RTLD_NOW` value. Please submit an issue or PR adding it." + ); + } + } + + cfg_if! { + if #[cfg(any( + target_os = "haiku", + all(target_os = "android",target_pointer_width = "32"), + ))] { + pub(super) const RTLD_GLOBAL: c_int = 2; + } else if #[cfg(any( + target_env = "uclibc", + all(target_os = "linux", target_arch = "mips"), + all(target_os = "linux", target_arch = "mips64"), + ))] { + pub(super) const RTLD_GLOBAL: c_int = 4; + } else if #[cfg(any( + target_os = "macos", + target_os = "ios", + ))] { + pub(super) const RTLD_GLOBAL: c_int = 8; + } else if #[cfg(any( + target_os = "linux", + all(target_os = "android", target_pointer_width = "64"), + target_os = "emscripten", + + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + + target_os = "solaris", + target_os = "illumos", + + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_GLOBAL: c_int = 0x100; + } else { + compile_error!( + "Target has no known `RTLD_GLOBAL` value. Please submit an issue or PR adding it." + ); + } + } + + cfg_if! { + if #[cfg(target_os = "netbsd")] { + pub(super) const RTLD_LOCAL: c_int = 0x200; + } else if #[cfg(any( + target_os = "macos", + target_os = "ios", + ))] { + pub(super) const RTLD_LOCAL: c_int = 4; + } else if #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + + target_os = "haiku", + + target_os = "solaris", + target_os = "illumos", + + target_env = "uclibc", + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_LOCAL: c_int = 0; + } else { + compile_error!( + "Target has no known `RTLD_LOCAL` value. Please submit an issue or PR adding it." + ); + } + } +} + +// Other constants that exist but are not bound because they are platform-specific (non-posix) +// extensions. Some of these constants are only relevant to `dlsym` or `dlmopen` calls. +// +// RTLD_CONFGEN +// RTLD_DEFAULT +// RTLD_DI_CONFIGADDR +// RTLD_DI_LINKMAP +// RTLD_DI_LMID +// RTLD_DI_ORIGIN +// RTLD_DI_PROFILENAME +// RTLD_DI_PROFILEOUT +// RTLD_DI_SERINFO +// RTLD_DI_SERINFOSIZE +// RTLD_DI_TLS_DATA +// RTLD_DI_TLS_MODID +// RTLD_FIRST +// RTLD_GROUP +// RTLD_NEXT +// RTLD_PARENT +// RTLD_PROBE +// RTLD_SELF +// RTLD_WORLD +// RTLD_NODELETE +// RTLD_NOLOAD +// RTLD_DEEPBIND diff --git a/vendor/libloading/src/os/unix/mod.rs b/vendor/libloading/src/os/unix/mod.rs index 29d2003659..785c58f264 100644 --- a/vendor/libloading/src/os/unix/mod.rs +++ b/vendor/libloading/src/os/unix/mod.rs @@ -1,9 +1,21 @@ -use util::{ensure_compatible_types, cstr_cow_from_bytes}; +// A hack for docs.rs to build documentation that has both windows and linux documentation in the +// same rustdoc build visible. +#[cfg(all(docsrs, not(unix)))] +mod unix_imports { +} +#[cfg(any(not(docsrs), unix))] +mod unix_imports { + pub(super) use std::os::unix::ffi::OsStrExt; +} +use self::unix_imports::*; +use util::{ensure_compatible_types, cstr_cow_from_bytes}; use std::ffi::{CStr, OsStr}; use std::{fmt, marker, mem, ptr}; use std::os::raw; -use std::os::unix::ffi::OsStrExt; +pub use self::consts::*; + +mod consts; // dl* family of functions did not have enough thought put into it. // @@ -61,7 +73,7 @@ where F: FnOnce() -> Option { }) } -/// A platform-specific equivalent of the cross-platform `Library`. +/// A platform-specific counterpart of the cross-platform [`Library`](crate::Library). pub struct Library { handle: *mut raw::c_void } @@ -85,34 +97,45 @@ unsafe impl Send for Library {} unsafe impl Sync for Library {} impl Library { - /// Find and load a shared library (module). + /// Find and eagerly load a shared library (module). /// - /// Locations where library is searched for is platform specific and can’t be adjusted - /// portably. + /// If the `filename` contains a [path separator], the `filename` is interpreted as a `path` to + /// a file. Otherwise, platform-specific algorithms are employed to find a library with a + /// matching file name. /// - /// Corresponds to `dlopen(filename, RTLD_NOW)`. + /// This is equivalent to [`Library::open`]`(filename, RTLD_NOW)`. + /// + /// [path separator]: std::path::MAIN_SEPARATOR #[inline] pub fn new>(filename: P) -> Result { Library::open(Some(filename), RTLD_NOW) } - /// Load the dynamic libraries linked into main program. + /// Eagerly load the `Library` representing the current executable. + /// + /// [`Library::get`] calls of the returned `Library` will look for symbols in following + /// locations in order: + /// + /// 1. Original program image; + /// 2. Any executable object files (e.g. shared libraries) loaded at program startup; + /// 3. Executable object files loaded at runtime (e.g. via other `Library::new` calls or via + /// calls to the `dlopen` function) /// - /// This allows retrieving symbols from any **dynamic** library linked into the program, - /// without specifying the exact library. + /// Note that behaviour of `Library` loaded with this method is different from + /// Libraries loaded with [`os::windows::Library::this`]. /// - /// Corresponds to `dlopen(NULL, RTLD_NOW)`. + /// This is equivalent to [`Library::open`]`(None, RTLD_NOW)`. + /// + /// [`os::windows::Library::this`]: crate::os::windows::Library::this #[inline] pub fn this() -> Library { Library::open(None::<&OsStr>, RTLD_NOW).expect("this should never fail") } - /// Find and load a shared library (module). - /// - /// Locations where library is searched for is platform specific and can’t be adjusted - /// portably. + /// Find and load an executable object file (shared library). /// - /// If the `filename` is None, null pointer is passed to `dlopen`. + /// See documentation for [`Library::this`] for further description of behaviour + /// when the `filename` is `None`. Otherwise see [`Library::new`]. /// /// Corresponds to `dlopen(filename, flags)`. pub fn open

    (filename: Option

    , flags: raw::c_int) -> Result @@ -174,37 +197,33 @@ impl Library { /// Get a pointer to function or static variable by symbol name. /// /// The `symbol` may not contain any null bytes, with an exception of last byte. A null - /// terminated `symbol` may avoid a string allocation in some cases. + /// terminated `symbol` may avoid an allocation in some cases. /// /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are /// most likely invalid. /// - /// ## Unsafety + /// # Safety /// /// This function does not validate the type `T`. It is up to the user of this function to /// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no - /// definied behaviour. - /// - /// + /// defined behaviour. /// - /// ## Platform-specific behaviour + /// # Platform-specific behaviour /// - /// OS X uses some sort of lazy initialization scheme, which makes loading TLS variables - /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour. + /// Implementation of thread local variables is extremely platform specific and uses of these + /// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems. /// /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such - /// as FreeBSD), this function will unconditionally return an error the underlying `dlsym` call - /// returns a null pointer. There are rare situations where `dlsym` returns a genuine null - /// pointer without it being an error. If loading a null pointer is something you care about, - /// consider using the [`Library::get_singlethreaded`] call. + /// as FreeBSD), this function will unconditionally return an error when the underlying `dlsym` + /// call returns a null pointer. There are rare situations where `dlsym` returns a genuine null + /// pointer without it being an error. If loading a symbol at null address is something you + /// care about, consider using the [`Library::get_singlethreaded`] call. #[inline(always)] pub unsafe fn get(&self, symbol: &[u8]) -> Result, crate::Error> { #[cfg(mtsafe_dlerror)] - { return self.get_singlethreaded(symbol); } + { self.get_singlethreaded(symbol) } #[cfg(not(mtsafe_dlerror))] - { - return self.get_impl(symbol, || Err(crate::Error::DlSymUnknown)); - } + { self.get_impl(symbol, || Err(crate::Error::DlSymUnknown)) } } /// Get a pointer to function or static variable by symbol name. @@ -215,20 +234,20 @@ impl Library { /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are /// most likely invalid. /// - /// ## Unsafety + /// # Safety /// /// This function does not validate the type `T`. It is up to the user of this function to /// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no - /// definied behaviour. + /// defined behaviour. /// /// It is up to the user of this library to ensure that no other calls to an MT-unsafe - /// implementation of `dlerror` occur while this function is executing. Failing that the - /// results of this function are not defined. + /// implementation of `dlerror` occur during execution of this function. Failing that, the + /// behaviour of this function is not defined. /// - /// ## Platform-specific behaviour + /// # Platform-specific behaviour /// - /// OS X uses some sort of lazy initialization scheme, which makes loading TLS variables - /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour. + /// Implementation of thread local variables is extremely platform specific and uses of these + /// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems. #[inline(always)] pub unsafe fn get_singlethreaded(&self, symbol: &[u8]) -> Result, crate::Error> { self.get_impl(symbol, || Ok(Symbol { @@ -249,14 +268,14 @@ impl Library { /// Convert a raw handle returned by `dlopen`-family of calls to a `Library`. /// - /// ## Unsafety + /// # Safety /// /// The pointer shall be a result of a successful call of the `dlopen`-family of functions or a /// pointer previously returned by `Library::into_raw` call. It must be valid to call `dlclose` /// with this pointer as an argument. pub unsafe fn from_raw(handle: *mut raw::c_void) -> Library { Library { - handle: handle + handle } } @@ -266,8 +285,7 @@ impl Library { /// what library was opened or other platform specifics. /// /// You only need to call this if you are interested in handling any errors that may arise when - /// library is unloaded. Otherwise the implementation of `Drop` for `Library` will close the - /// library and ignore the errors were they arise. + /// library is unloaded. Otherwise this will be done when `Library` is dropped. pub fn close(self) -> Result<(), crate::Error> { let result = with_dlerror(|desc| crate::Error::DlClose { desc }, || { if unsafe { dlclose(self.handle) } == 0 { @@ -341,7 +359,7 @@ impl ::std::ops::Deref for Symbol { fn deref(&self) -> &T { unsafe { // Additional reference level for a dereference on `deref` return value. - mem::transmute(&self.pointer) + &*(&self.pointer as *const *mut _ as *const T) } } } @@ -369,7 +387,6 @@ impl fmt::Debug for Symbol { } // Platform specific things - extern { fn dlopen(filename: *const raw::c_char, flags: raw::c_int) -> *mut raw::c_void; fn dlclose(handle: *mut raw::c_void) -> raw::c_int; @@ -378,11 +395,6 @@ extern { fn dladdr(addr: *mut raw::c_void, info: *mut DlInfo) -> raw::c_int; } -#[cfg(not(target_os="android"))] -const RTLD_NOW: raw::c_int = 2; -#[cfg(target_os="android")] -const RTLD_NOW: raw::c_int = 0; - #[repr(C)] struct DlInfo { dli_fname: *const raw::c_char, @@ -390,11 +402,3 @@ struct DlInfo { dli_sname: *const raw::c_char, dli_saddr: *mut raw::c_void } - -#[cfg(test)] -mod tests { - #[test] - fn this() { - super::Library::this(); - } -} diff --git a/vendor/libloading/src/os/windows/mod.rs b/vendor/libloading/src/os/windows/mod.rs index 3620b3e383..a106234aff 100644 --- a/vendor/libloading/src/os/windows/mod.rs +++ b/vendor/libloading/src/os/windows/mod.rs @@ -1,17 +1,63 @@ -extern crate winapi; -use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC}; -use self::winapi::shared::ntdef::WCHAR; -use self::winapi::shared::winerror; -use self::winapi::um::{errhandlingapi, libloaderapi}; +// A hack for docs.rs to build documentation that has both windows and linux documentation in the +// same rustdoc build visible. +#[cfg(all(docsrs, not(windows)))] +mod windows_imports { + pub(super) enum WORD {} + pub(super) struct DWORD; + pub(super) enum HMODULE {} + pub(super) enum FARPROC {} -use util::{ensure_compatible_types, cstr_cow_from_bytes}; + pub(super) mod consts { + use super::DWORD; + pub(crate) const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_AS_DATAFILE: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = DWORD; + pub(crate) const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = DWORD; + } +} +#[cfg(any(not(docsrs), windows))] +mod windows_imports { + extern crate winapi; + pub(super) use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC}; + pub(super) use self::winapi::shared::ntdef::WCHAR; + pub(super) use self::winapi::shared::winerror; + pub(super) use self::winapi::um::{errhandlingapi, libloaderapi}; + pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt}; + pub(super) const SEM_FAILCE: DWORD = 1; + pub(super) mod consts { + pub(crate) use super::winapi::um::libloaderapi::{ + LOAD_IGNORE_CODE_AUTHZ_LEVEL, + LOAD_LIBRARY_AS_DATAFILE, + LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE, + LOAD_LIBRARY_AS_IMAGE_RESOURCE, + LOAD_LIBRARY_SEARCH_APPLICATION_DIR, + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, + LOAD_LIBRARY_SEARCH_SYSTEM32, + LOAD_LIBRARY_SEARCH_USER_DIRS, + LOAD_WITH_ALTERED_SEARCH_PATH, + LOAD_LIBRARY_REQUIRE_SIGNED_TARGET, + LOAD_LIBRARY_SAFE_CURRENT_DIRS, + }; + } +} + +use self::windows_imports::*; +use util::{ensure_compatible_types, cstr_cow_from_bytes}; use std::ffi::{OsStr, OsString}; use std::{fmt, io, marker, mem, ptr}; -use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::sync::atomic::{AtomicBool, Ordering}; -/// A platform-specific equivalent of the cross-platform `Library`. +/// A platform-specific counterpart of the cross-platform [`Library`](crate::Library). pub struct Library(HMODULE); unsafe impl Send for Library {} @@ -31,20 +77,56 @@ unsafe impl Send for Library {} unsafe impl Sync for Library {} impl Library { - /// Find and load a shared library (module). + /// Find and load a module. + /// + /// If the `filename` specifies a full path, the function only searches that path for the + /// module. Otherwise, if the `filename` specifies a relative path or a module name without a + /// path, the function uses a windows-specific search strategy to find the module; for more + /// information, see the [Remarks on MSDN][msdn]. /// - /// Corresponds to `LoadLibraryW(filename, reserved: NULL, flags: 0)` which is equivalent to `LoadLibraryW(filename)` + /// If the `filename` specifies a library filename without path and with extension omitted, + /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a + /// trailing `.` to the `filename`. + /// + /// This is equivalent to [`Library::load_with_flags`]`(filename, 0)`. + /// + /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw#remarks #[inline] pub fn new>(filename: P) -> Result { Library::load_with_flags(filename, 0) } - /// Find and load a shared library (module). + /// Load the `Library` representing the original program executable. + /// + /// Note that behaviour of `Library` loaded with this method is different from + /// Libraries loaded with [`os::unix::Library::this`]. For more information refer to [MSDN]. + /// + /// Corresponds to `GetModuleHandleExW(0, NULL, _)`. + /// + /// [`os::unix::Library::this`]: crate::os::unix::Library::this + /// [MSDN]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw + pub fn this() -> Result { + unsafe { + let mut handle: HMODULE = std::ptr::null_mut(); + with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || { + let result = libloaderapi::GetModuleHandleExW(0, std::ptr::null_mut(), &mut handle); + if result == 0 { + None + } else { + Some(Library(handle)) + } + }).map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown)) + } + } + + /// Find and load a module, additionally adjusting behaviour with flags. + /// + /// See [`Library::new`] for documentation on handling of the `filename` argument. See the + /// [flag table on MSDN][flags] for information on applicable values for the `flags` argument. /// - /// Locations where library is searched for is platform specific and can’t be adjusted - /// portably. + /// Corresponds to `LoadLibraryExW(filename, reserved: NULL, flags)`. /// - /// Corresponds to `LoadLibraryW(filename, reserved: NULL, flags)`. + /// [flags]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters pub fn load_with_flags>(filename: P, flags: DWORD) -> Result { let wide_filename: Vec = filename.as_ref().encode_wide().chain(Some(0)).collect(); let _guard = ErrorModeGuard::new(); @@ -52,7 +134,9 @@ impl Library { let ret = with_get_last_error(|source| crate::Error::LoadLibraryW { source }, || { // Make sure no winapi calls as a result of drop happen inside this closure, because // otherwise that might change the return value of the GetLastError. - let handle = unsafe { libloaderapi::LoadLibraryExW(wide_filename.as_ptr(), std::ptr::null_mut(), flags) }; + let handle = unsafe { + libloaderapi::LoadLibraryExW(wide_filename.as_ptr(), std::ptr::null_mut(), flags) + }; if handle.is_null() { None } else { @@ -72,7 +156,7 @@ impl Library { /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are /// most likely invalid. /// - /// ## Unsafety + /// # Safety /// /// This function does not validate the type `T`. It is up to the user of this function to /// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no @@ -95,7 +179,7 @@ impl Library { /// Get a pointer to function or static variable by ordinal number. /// - /// ## Unsafety + /// # Safety /// /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is /// undefined. @@ -124,7 +208,7 @@ impl Library { /// Convert a raw handle to a `Library`. /// - /// ## Unsafety + /// # Safety /// /// The handle shall be a result of a successful call of `LoadLibraryW` or a /// handle previously returned by the `Library::into_raw` call. @@ -217,7 +301,7 @@ impl ::std::ops::Deref for Symbol { fn deref(&self) -> &T { unsafe { // Additional reference level for a dereference on `deref` return value. - mem::transmute(&self.pointer) + &*(&self.pointer as *const *mut _ as *const T) } } } @@ -228,13 +312,12 @@ impl fmt::Debug for Symbol { } } - static USE_ERRORMODE: AtomicBool = AtomicBool::new(false); struct ErrorModeGuard(DWORD); impl ErrorModeGuard { + #[allow(clippy::if_same_then_else)] fn new() -> Option { - const SEM_FAILCE: DWORD = 1; unsafe { if !USE_ERRORMODE.load(Ordering::Acquire) { let mut previous_mode = 0; @@ -302,31 +385,114 @@ where F: FnOnce() -> Option { }) } -#[cfg(test)] -mod tests { - use super::*; +/// Do not check AppLocker rules or apply Software Restriction Policies for the DLL. +/// +/// This action applies only to the DLL being loaded and not to its dependencies. This value is +/// recommended for use in setup programs that must run extracted DLLs during installation. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = consts::LOAD_IGNORE_CODE_AUTHZ_LEVEL; - #[test] - fn works_getlasterror() { - let lib = Library::new("kernel32.dll").unwrap(); - let gle: Symbol DWORD> = unsafe { - lib.get(b"GetLastError").unwrap() - }; - unsafe { - errhandlingapi::SetLastError(42); - assert_eq!(errhandlingapi::GetLastError(), gle()) - } - } +/// Map the file into the calling process’ virtual address space as if it were a data file. +/// +/// Nothing is done to execute or prepare to execute the mapped file. Therefore, you cannot call +/// functions like [`Library::get`] with this DLL. Using this value causes writes to read-only +/// memory to raise an access violation. Use this flag when you want to load a DLL only to extract +/// messages or resources from it. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_AS_DATAFILE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE; - #[test] - fn works_getlasterror0() { - let lib = Library::new("kernel32.dll").unwrap(); - let gle: Symbol DWORD> = unsafe { - lib.get(b"GetLastError\0").unwrap() - }; - unsafe { - errhandlingapi::SetLastError(42); - assert_eq!(errhandlingapi::GetLastError(), gle()) - } - } -} +/// Map the file into the calling process’ virtual address space as if it were a data file. +/// +/// Similar to [`LOAD_LIBRARY_AS_DATAFILE`], except that the DLL file is opened with exclusive +/// write access for the calling process. Other processes cannot open the DLL file for write access +/// while it is in use. However, the DLL can still be opened by other processes. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE; + +/// Map the file into the process’ virtual address space as an image file. +/// +/// The loader does not load the static imports or perform the other usual initialization steps. +/// Use this flag when you want to load a DLL only to extract messages or resources from it. +/// +/// Unless the application depends on the file having the in-memory layout of an image, this value +/// should be used with either [`LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE`] or +/// [`LOAD_LIBRARY_AS_DATAFILE`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE; + +/// Search application's installation directory for the DLL and its dependencies. +/// +/// Directories in the standard search path are not searched. This value cannot be combined with +/// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_APPLICATION_DIR; + +/// Search default directories when looking for the DLL and its dependencies. +/// +/// This value is a combination of [`LOAD_LIBRARY_SEARCH_APPLICATION_DIR`], +/// [`LOAD_LIBRARY_SEARCH_SYSTEM32`], and [`LOAD_LIBRARY_SEARCH_USER_DIRS`]. Directories in the +/// standard search path are not searched. This value cannot be combined with +/// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; + +/// Directory that contains the DLL is temporarily added to the beginning of the list of +/// directories that are searched for the DLL’s dependencies. +/// +/// Directories in the standard search path are not searched. +/// +/// The `filename` parameter must specify a fully qualified path. This value cannot be combined +/// with [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR; + +/// Search `%windows%\system32` for the DLL and its dependencies. +/// +/// Directories in the standard search path are not searched. This value cannot be combined with +/// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = consts::LOAD_LIBRARY_SEARCH_SYSTEM32; + +/// Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched +/// for the DLL and its dependencies. +/// +/// If more than one directory has been added, the order in which the directories are searched is +/// unspecified. Directories in the standard search path are not searched. This value cannot be +/// combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_USER_DIRS; + +/// If `filename specifies an absolute path, the system uses the alternate file search strategy +/// discussed in the [Remarks section] to find associated executable modules that the specified +/// module causes to be loaded. +/// +/// If this value is used and `filename` specifies a relative path, the behavior is undefined. +/// +/// If this value is not used, or if `filename` does not specify a path, the system uses the +/// standard search strategy discussed in the [Remarks section] to find associated executable +/// modules that the specified module causes to be loaded. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +/// +/// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks +pub const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = consts::LOAD_WITH_ALTERED_SEARCH_PATH; + +/// Specifies that the digital signature of the binary image must be checked at load time. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = consts::LOAD_LIBRARY_REQUIRE_SIGNED_TARGET; + +/// Allow loading a DLL for execution from the current directory only if it is under a directory in +/// the Safe load list. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS; diff --git a/vendor/libloading/src/test_helpers.rs b/vendor/libloading/src/test_helpers.rs index 32f7023188..9e3e9924ff 100644 --- a/vendor/libloading/src/test_helpers.rs +++ b/vendor/libloading/src/test_helpers.rs @@ -1,7 +1,6 @@ //! This is a separate file containing helpers for tests of this library. It is built into a //! dynamic library by the build.rs script. -#![crate_type="dylib"] // FIXME: should become a cdylib in due time -#![cfg_attr(test_nightly, feature(thread_local))] +#![crate_type="cdylib"] #[no_mangle] pub static mut TEST_STATIC_U32: u32 = 0; @@ -9,11 +8,6 @@ pub static mut TEST_STATIC_U32: u32 = 0; #[no_mangle] pub static mut TEST_STATIC_PTR: *mut () = 0 as *mut _; -#[cfg(test_nightly)] -#[thread_local] -#[no_mangle] -pub static mut TEST_THREAD_LOCAL: u32 = 0; - #[no_mangle] pub extern "C" fn test_identity_u32(x: u32) -> u32 { x @@ -41,9 +35,3 @@ pub unsafe extern "C" fn test_get_static_u32() -> u32 { pub unsafe extern "C" fn test_check_static_ptr() -> bool { TEST_STATIC_PTR == (&mut TEST_STATIC_PTR as *mut *mut _ as *mut _) } - -#[cfg(test_nightly)] -#[no_mangle] -pub unsafe extern "C" fn test_get_thread_local() -> u32 { - TEST_THREAD_LOCAL -} diff --git a/vendor/libloading/src/util.rs b/vendor/libloading/src/util.rs index e5108c2d14..880b68927d 100644 --- a/vendor/libloading/src/util.rs +++ b/vendor/libloading/src/util.rs @@ -7,7 +7,7 @@ use crate::Error; /// Checks for last byte and avoids allocating if it is zero. /// /// Non-last null bytes still result in an error. -pub(crate) fn cstr_cow_from_bytes<'a>(slice: &'a [u8]) -> Result, Error> { +pub(crate) fn cstr_cow_from_bytes(slice: &[u8]) -> Result, Error> { static ZERO: raw::c_char = 0; Ok(match slice.last() { // Slice out of 0 elements diff --git a/vendor/libloading/tests/constants.rs b/vendor/libloading/tests/constants.rs new file mode 100644 index 0000000000..ad910c405e --- /dev/null +++ b/vendor/libloading/tests/constants.rs @@ -0,0 +1,13 @@ +extern crate libloading; +extern crate libc; +extern crate static_assertions; + +#[cfg(all(test, unix))] +mod unix { + use super::static_assertions::const_assert_eq; + + const_assert_eq!(libloading::os::unix::RTLD_LOCAL, libc::RTLD_LOCAL); + const_assert_eq!(libloading::os::unix::RTLD_GLOBAL, libc::RTLD_GLOBAL); + const_assert_eq!(libloading::os::unix::RTLD_NOW, libc::RTLD_NOW); + const_assert_eq!(libloading::os::unix::RTLD_LAZY, libc::RTLD_LAZY); +} diff --git a/vendor/libloading/tests/functions.rs b/vendor/libloading/tests/functions.rs index dece58c585..b642478244 100644 --- a/vendor/libloading/tests/functions.rs +++ b/vendor/libloading/tests/functions.rs @@ -1,19 +1,25 @@ +#[cfg(windows)] +extern crate winapi; + extern crate libloading; use libloading::{Symbol, Library}; -const LIBPATH: &'static str = concat!(env!("OUT_DIR"), "/libtest_helpers.dll"); +const LIBPATH: &'static str = concat!(env!("OUT_DIR"), "/libtest_helpers.module"); fn make_helpers() { static ONCE: ::std::sync::Once = ::std::sync::Once::new(); ONCE.call_once(|| { - let mut outpath = String::from(if let Some(od) = option_env!("OUT_DIR") { od } else { return }); let rustc = option_env!("RUSTC").unwrap_or_else(|| { "rustc".into() }); - outpath.push_str(&"/libtest_helpers.dll"); // extension for windows required, POSIX does not care. - let _ = ::std::process::Command::new(rustc) + let mut cmd = ::std::process::Command::new(rustc); + cmd .arg("src/test_helpers.rs") .arg("-o") - .arg(outpath) - .arg("-O") + .arg(LIBPATH) + .arg("--target") + .arg(env!("LIBLOADING_TEST_TARGET")) + .arg("-O"); + + cmd .output() .expect("could not compile the test helpers!"); }); @@ -136,20 +142,69 @@ fn test_static_ptr() { } } -#[cfg(any(windows, target_os="linux"))] -#[cfg(test_nightly)] +#[cfg(unix)] #[test] -fn test_tls_static() { +fn library_this_get() { + use libloading::os::unix::Library; make_helpers(); - let lib = Library::new(LIBPATH).unwrap(); + let _lib = Library::new(LIBPATH).unwrap(); + let this = Library::this(); + // SAFE: functions are never called + unsafe { + // Library we loaded in `_lib` (should be RTLD_LOCAL). + // FIXME: inconsistent behaviour between macos and other posix systems + // assert!(this.get::(b"test_identity_u32").is_err()); + // Something obscure from libc... + assert!(this.get::(b"freopen").is_ok()); + } +} + +#[cfg(windows)] +#[test] +fn library_this() { + use libloading::os::windows::Library; + make_helpers(); + let _lib = Library::new(LIBPATH).unwrap(); + let this = Library::this().expect("this library"); + // SAFE: functions are never called + unsafe { + // Library we loaded in `_lib`. + assert!(this.get::(b"test_identity_u32").is_err()); + // Something "obscure" from kernel32... + assert!(this.get::(b"GetLastError").is_err()); + } +} + +#[cfg(windows)] +#[test] +fn works_getlasterror() { + use winapi::um::errhandlingapi; + use winapi::shared::minwindef::DWORD; + use libloading::os::windows::{Library, Symbol}; + + let lib = Library::new("kernel32.dll").unwrap(); + let gle: Symbol DWORD> = unsafe { + lib.get(b"GetLastError").unwrap() + }; + unsafe { + errhandlingapi::SetLastError(42); + assert_eq!(errhandlingapi::GetLastError(), gle()) + } +} + +#[cfg(windows)] +#[test] +fn works_getlasterror0() { + use winapi::um::errhandlingapi; + use winapi::shared::minwindef::DWORD; + use libloading::os::windows::{Library, Symbol}; + + let lib = Library::new("kernel32.dll").unwrap(); + let gle: Symbol DWORD> = unsafe { + lib.get(b"GetLastError\0").unwrap() + }; unsafe { - let var: Symbol<*mut u32> = lib.get(b"TEST_THREAD_LOCAL\0").unwrap(); - **var = 84; - let help: Symbol u32> = lib.get(b"test_get_thread_local\0").unwrap(); - assert_eq!(84, help()); + errhandlingapi::SetLastError(42); + assert_eq!(errhandlingapi::GetLastError(), gle()) } - ::std::thread::spawn(move || unsafe { - let help: Symbol u32> = lib.get(b"test_get_thread_local\0").unwrap(); - assert_eq!(0, help()); - }).join().unwrap(); } diff --git a/vendor/libloading/tests/library_filename.rs b/vendor/libloading/tests/library_filename.rs new file mode 100644 index 0000000000..efe51b8656 --- /dev/null +++ b/vendor/libloading/tests/library_filename.rs @@ -0,0 +1,17 @@ +extern crate libloading; +use libloading::library_filename; +use std::path::Path; + +#[cfg(target_os = "windows")] +const EXPECTED: &str = "audioengine.dll"; +#[cfg(target_os = "linux")] +const EXPECTED: &str = "libaudioengine.so"; +#[cfg(target_os = "macos")] +const EXPECTED: &str = "libaudioengine.dylib"; + +#[test] +fn test_library_filename() { + let name = "audioengine"; + let resolved = library_filename(name); + assert!(Path::new(&resolved).ends_with(EXPECTED)); +} diff --git a/vendor/libloading/tests/markers.rs b/vendor/libloading/tests/markers.rs index 01da108c68..330c034ad5 100644 --- a/vendor/libloading/tests/markers.rs +++ b/vendor/libloading/tests/markers.rs @@ -4,6 +4,23 @@ extern crate libloading; fn assert_send() {} #[cfg(test)] fn assert_sync() {} +#[cfg(test)] +fn assert_display() {} + +#[test] +fn check_error_send() { + assert_send::(); +} + +#[test] +fn check_error_sync() { + assert_sync::(); +} + +#[test] +fn check_error_display() { + assert_display::(); +} #[test] fn check_library_send() { diff --git a/vendor/lsp-types/.cargo-checksum.json b/vendor/lsp-types/.cargo-checksum.json index 913e249cfa..adc51096b7 100644 --- a/vendor/lsp-types/.cargo-checksum.json +++ b/vendor/lsp-types/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"54cfa4a7a811c1d2275bf24f7fd1a119d934dd64c9ea4c8ca156b88ed8924122","Cargo.toml":"7ed745e1c0ba57f7bcf0d2cba289b562af677343e2883c98a0c7062dc11cdf39","LICENSE":"a11232911aa0d746688b560af367728021184084eeb6328a1922d60925c5eda0","README.md":"77acfc82fff7852e9608da342ddc033a52b980cc0edb618b3c642a12ece017f0","release.sh":"013c6c56e2f36d7c3ff9703ef0de3bd58e2cefa5d1e203a298c27a29df7076f1","release.toml":"11ae2978b700cff4279d509b896a09570654ce19de88cec6b6eb6c521f8b141a","src/lib.rs":"84b4198bfa0696f4bce9f740867e6f7581dedf7cd36a18df28af1a2e16d647f3","src/notification.rs":"d20bd5b9ff32935063d2020843ee7b376e66412cb8dca2ee89e220ac5e3d636f","src/request.rs":"47398a878833e5f4fce1b3a43afd125912affa214e97d0d1343374240f714bf0"},"package":"7f1f86677fdbe8df5f88b99131b1424e50aad27bbe3e5900d221bc414bd72e9b"} \ No newline at end of file +{"files":{"CHANGELOG.md":"75e3fa387ef6fce999638dc98ee790d7ea1f7a54c6de83840ef95ebcff4ea75d","Cargo.toml":"f6b7c905407aa0dbad06ba06d5da525405d60991b61d75d502450b59fd21e89d","LICENSE":"005b90a7238f92fd39eaef0b4329a47e1cab351958d9e9bbed9b9c60b76bb2bb","README.md":"0011ea934f9c4a40409204b440517023b53bd7325b4e6d56a3da0dec252ff07f","release.sh":"0fc7c0f74e261a3faf5f0dea05f7098110d41b249511a9f2a573657f787fac9a","release.toml":"d06137fb8b6e1048cf42f39c2f6925f2a806c5b782b46e20a990bb4a3449bb8d","src/lib.rs":"c10021aad2f090d847e86004ddf76ae12075aca27939963d991d1687626078ef","src/notification.rs":"0d6296c66eb4551ffcf31aedc01d5dae9db3b71d2a4b1e39ad9287b2b0967cd4","src/request.rs":"3f02c22951b113c05a746bf08846c40a5ad63c6206c24e93685f286525b595fa"},"package":"f4265e2715bdacbb4dad029fce525e420cd66dc0af24ff9cb996a8ab48ac92ef"} \ No newline at end of file diff --git a/vendor/lsp-types/CHANGELOG.md b/vendor/lsp-types/CHANGELOG.md index c35ac1e3e8..8c12067d85 100644 --- a/vendor/lsp-types/CHANGELOG.md +++ b/vendor/lsp-types/CHANGELOG.md @@ -1,92 +1,98 @@ - -## v0.79.0 (2020-07-26) - - - - - -## v0.77.0 (2020-07-15) - - - - - -### v0.76.1 (2020-07-14) - - - - - -### v0.74.2 (2020-05-30) - - - - - -### v0.74.1 (2020-05-01) - - - - - -## v0.74.0 (2020-04-26) - - - - - -## v0.74.0 (2020-04-26) - - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - + +## v0.80.0 (2020-09-02) + + + + + +## v0.79.0 (2020-07-26) + + + + + +## v0.77.0 (2020-07-15) + + + + + +### v0.76.1 (2020-07-14) + + + + + +### v0.74.2 (2020-05-30) + + + + + +### v0.74.1 (2020-05-01) + + + + + +## v0.74.0 (2020-04-26) + + + + + +## v0.74.0 (2020-04-26) + + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + diff --git a/vendor/lsp-types/Cargo.toml b/vendor/lsp-types/Cargo.toml index 4980f1da74..8a5cb6027a 100644 --- a/vendor/lsp-types/Cargo.toml +++ b/vendor/lsp-types/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "lsp-types" -version = "0.79.0" +version = "0.80.0" authors = ["Markus Westerlind ", "Bruno Medeiros "] description = "Types for interaction with a language server, using VSCode's Language Server Protocol" documentation = "https://docs.rs/lsp-types" diff --git a/vendor/lsp-types/LICENSE b/vendor/lsp-types/LICENSE index 32781d976c..968950bbb5 100644 --- a/vendor/lsp-types/LICENSE +++ b/vendor/lsp-types/LICENSE @@ -1,22 +1,22 @@ -The MIT License (MIT) - -Copyright (c) 2016 Markus Westerlind - -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. - +The MIT License (MIT) + +Copyright (c) 2016 Markus Westerlind + +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/lsp-types/README.md b/vendor/lsp-types/README.md index 2c29a1f63f..b6972e9759 100644 --- a/vendor/lsp-types/README.md +++ b/vendor/lsp-types/README.md @@ -1,9 +1,9 @@ -# lsp-types [![Build Status](https://travis-ci.org/gluon-lang/lsp-types.svg?branch=master)](https://travis-ci.org/gluon-lang/lsp-types) [![Documentation](https://docs.rs/lsp-types/badge.svg)](https://docs.rs/crate/lsp-types) - -Types useful for interacting with a [language server](https://code.visualstudio.com/blogs/2016/06/27/common-language-protocol). - -Supports Language Server Protocol (LSP) version 3.15.0. - -## Links - -[Protocol reference](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-15.md) +# lsp-types [![Build Status](https://travis-ci.org/gluon-lang/lsp-types.svg?branch=master)](https://travis-ci.org/gluon-lang/lsp-types) [![Documentation](https://docs.rs/lsp-types/badge.svg)](https://docs.rs/crate/lsp-types) + +Types useful for interacting with a [language server](https://code.visualstudio.com/blogs/2016/06/27/common-language-protocol). + +Supports Language Server Protocol (LSP) version 3.15.0. + +## Links + +[Protocol reference](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-15.md) diff --git a/vendor/lsp-types/release.sh b/vendor/lsp-types/release.sh old mode 100755 new mode 100644 index db6a709c1e..cede6f575e --- a/vendor/lsp-types/release.sh +++ b/vendor/lsp-types/release.sh @@ -1,15 +1,15 @@ -#!/bin/sh -set -ex - -LEVEL=$1 -if [ -z "$LEVEL" ]; then - echo "Expected patch, minor or major" - exit 1 -fi - -clog --$LEVEL - -git add CHANGELOG.md -git commit -m "Update changelog" - -cargo release $LEVEL +#!/bin/sh +set -ex + +LEVEL=$1 +if [ -z "$LEVEL" ]; then + echo "Expected patch, minor or major" + exit 1 +fi + +clog --$LEVEL + +git add CHANGELOG.md +git commit -m "Update changelog" + +cargo release $LEVEL diff --git a/vendor/lsp-types/release.toml b/vendor/lsp-types/release.toml index 5e7e4943cd..0e10206ed6 100644 --- a/vendor/lsp-types/release.toml +++ b/vendor/lsp-types/release.toml @@ -1,2 +1,2 @@ -no-dev-version = true -tag-message = "Version {{version}}" +no-dev-version = true +tag-message = "Version {{version}}" diff --git a/vendor/lsp-types/src/lib.rs b/vendor/lsp-types/src/lib.rs index c93ac7b7e5..ca1bd3b8c1 100644 --- a/vendor/lsp-types/src/lib.rs +++ b/vendor/lsp-types/src/lib.rs @@ -1,4856 +1,4888 @@ -/*! - -Language Server Protocol types for Rust. - -Based on: - -This library uses the URL crate for parsing URIs. Note that there is -some confusion on the meaning of URLs vs URIs: -. According to that -information, on the classical sense of "URLs", "URLs" are a subset of -URIs, But on the modern/new meaning of URLs, they are the same as -URIs. The important take-away aspect is that the URL crate should be -able to parse any URI, such as `urn:isbn:0451450523`. - - -*/ -#![allow(non_upper_case_globals)] -#![forbid(unsafe_code)] - -#[macro_use] -extern crate bitflags; - -use serde::{Deserialize, Serialize}; -use serde_json; -use serde_repr::{Deserialize_repr, Serialize_repr}; - -pub use url::Url; - -use std::borrow::Cow; - -#[cfg(feature = "proposed")] -use std::convert::TryFrom; - -use std::collections::HashMap; - -#[cfg(feature = "proposed")] -use base64; -use serde::de; -use serde::de::Error as Error_; -use serde_json::Value; - -#[cfg(feature = "proposed")] -use serde::ser::SerializeSeq; - -pub mod notification; -pub mod request; - -/* ----------------- Auxiliary types ----------------- */ - -#[derive(Debug, Eq, Hash, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum NumberOrString { - Number(u64), - String(String), -} - -/* ----------------- Cancel support ----------------- */ - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct CancelParams { - /// The request id to cancel. - pub id: NumberOrString, -} - -/* ----------------- Basic JSON Structures ----------------- */ - -/// Position in a text document expressed as zero-based line and character offset. -/// A position is between two characters like an 'insert' cursor in a editor. -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Default, Deserialize, Serialize)] -pub struct Position { - /// Line position in a document (zero-based). - pub line: u64, - /// Character offset on a line in a document (zero-based). - pub character: u64, -} - -impl Position { - pub fn new(line: u64, character: u64) -> Position { - Position { line, character } - } -} - -/// A range in a text document expressed as (zero-based) start and end positions. -/// A range is comparable to a selection in an editor. Therefore the end position is exclusive. -#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Deserialize, Serialize)] -pub struct Range { - /// The range's start position. - pub start: Position, - /// The range's end position. - pub end: Position, -} - -impl Range { - pub fn new(start: Position, end: Position) -> Range { - Range { start, end } - } -} - -/// Represents a location inside a resource, such as a line inside a text file. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct Location { - pub uri: Url, - pub range: Range, -} - -impl Location { - pub fn new(uri: Url, range: Range) -> Location { - Location { uri, range } - } -} - -/// Represents a link between a source and a target location. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct LocationLink { - /// Span of the origin of this link. - /// - /// Used as the underlined span for mouse interaction. Defaults to the word range at - /// the mouse position. - #[serde(skip_serializing_if = "Option::is_none")] - pub origin_selection_range: Option, - - /// The target resource identifier of this link. - pub target_uri: Url, - - /// The full target range of this link. - pub target_range: Range, - - /// The span of this link. - pub target_selection_range: Range, -} - -/// Represents a diagnostic, such as a compiler error or warning. -/// Diagnostic objects are only valid in the scope of a resource. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Diagnostic { - /// The range at which the message applies. - pub range: Range, - - /// The diagnostic's severity. Can be omitted. If omitted it is up to the - /// client to interpret diagnostics as error, warning, info or hint. - #[serde(skip_serializing_if = "Option::is_none")] - pub severity: Option, - - /// The diagnostic's code. Can be omitted. - #[serde(skip_serializing_if = "Option::is_none")] - pub code: Option, - // code?: number | string; - /// A human-readable string describing the source of this - /// diagnostic, e.g. 'typescript' or 'super lint'. - #[serde(skip_serializing_if = "Option::is_none")] - pub source: Option, - - /// The diagnostic's message. - pub message: String, - - /// An array of related diagnostic information, e.g. when symbol-names within - /// a scope collide all definitions can be marked via this property. - #[serde(skip_serializing_if = "Option::is_none")] - pub related_information: Option>, - - /// Additional metadata about the diagnostic. - #[serde(skip_serializing_if = "Option::is_none")] - pub tags: Option>, -} - -impl Diagnostic { - pub fn new( - range: Range, - severity: Option, - code: Option, - source: Option, - message: String, - related_information: Option>, - tags: Option>, - ) -> Diagnostic { - Diagnostic { - range, - severity, - code, - source, - message, - related_information, - tags, - } - } - - pub fn new_simple(range: Range, message: String) -> Diagnostic { - Self::new(range, None, None, None, message, None, None) - } - - pub fn new_with_code_number( - range: Range, - severity: DiagnosticSeverity, - code_number: u64, - source: Option, - message: String, - ) -> Diagnostic { - let code = Some(NumberOrString::Number(code_number)); - Self::new(range, Some(severity), code, source, message, None, None) - } -} - -/// The protocol currently supports the following diagnostic severities: -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum DiagnosticSeverity { - /// Reports an error. - Error = 1, - /// Reports a warning. - Warning = 2, - /// Reports an information. - Information = 3, - /// Reports a hint. - Hint = 4, -} - -/// Represents a related message and source code location for a diagnostic. This -/// should be used to point to code locations that cause or related to a -/// diagnostics, e.g when duplicating a symbol in a scope. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DiagnosticRelatedInformation { - /// The location of this related diagnostic information. - pub location: Location, - - /// The message of this related diagnostic information. - pub message: String, -} - -/// The diagnostic tags. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum DiagnosticTag { - /// Unused or unnecessary code. - /// Clients are allowed to render diagnostics with this tag faded out instead of having - /// an error squiggle. - Unnecessary = 1, - - /// Deprecated or obsolete code. - /// Clients are allowed to rendered diagnostics with this tag strike through. - Deprecated = 2, -} - -/// Represents a reference to a command. Provides a title which will be used to represent a command in the UI. -/// Commands are identitifed using a string identifier and the protocol currently doesn't specify a set of -/// well known commands. So executing a command requires some tool extension code. -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct Command { - /// Title of the command, like `save`. - pub title: String, - /// The identifier of the actual command handler. - pub command: String, - /// Arguments that the command handler should be - /// invoked with. - #[serde(skip_serializing_if = "Option::is_none")] - pub arguments: Option>, -} - -impl Command { - pub fn new(title: String, command: String, arguments: Option>) -> Command { - Command { - title, - command, - arguments, - } - } -} - -/// A textual edit applicable to a text document. -/// -/// If n `TextEdit`s are applied to a text document all text edits describe changes to the initial document version. -/// Execution wise text edits should applied from the bottom to the top of the text document. Overlapping text edits -/// are not supported. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextEdit { - /// The range of the text document to be manipulated. To insert - /// text into a document create a range where start === end. - pub range: Range, - /// The string to be inserted. For delete operations use an - /// empty string. - pub new_text: String, -} - -impl TextEdit { - pub fn new(range: Range, new_text: String) -> TextEdit { - TextEdit { range, new_text } - } -} - -/// Describes textual changes on a single text document. The text document is referred to as a -/// `VersionedTextDocumentIdentifier` to allow clients to check the text document version before an -/// edit is applied. A `TextDocumentEdit` describes all changes on a version Si and after they are -/// applied move the document to version Si+1. So the creator of a `TextDocumentEdit` doesn't need to -/// sort the array or do any kind of ordering. However the edits must be non overlapping. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentEdit { - /// The text document to change. - pub text_document: VersionedTextDocumentIdentifier, - - /// The edits to be applied. - pub edits: Vec, -} - -/// A special text edit to provide an insert and a replace operation. -/// -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct InsertReplaceEdit { - /// The string to be inserted. - pub new_text: String, - - /// The range if the insert is requested - pub insert: Range, - - /// The range if the replace is requested. - pub replace: Range, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum CompletionTextEdit { - Edit(TextEdit), - #[cfg(feature = "proposed")] - InsertAndReplace(InsertReplaceEdit), -} - -impl From for CompletionTextEdit { - fn from(edit: TextEdit) -> Self { - CompletionTextEdit::Edit(edit) - } -} - -#[cfg(feature = "proposed")] -impl From for CompletionTextEdit { - fn from(edit: InsertReplaceEdit) -> Self { - CompletionTextEdit::InsertAndReplace(edit) - } -} - -/// Options to create a file. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateFileOptions { - /// Overwrite existing file. Overwrite wins over `ignoreIfExists` - #[serde(skip_serializing_if = "Option::is_none")] - pub overwrite: Option, - /// Ignore if exists. - #[serde(skip_serializing_if = "Option::is_none")] - pub ignore_if_exists: Option, -} - -/// Create file operation -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateFile { - /// The resource to create. - pub uri: Url, - /// Additional options - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option, -} - -/// Rename file options -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameFileOptions { - /// Overwrite target if existing. Overwrite wins over `ignoreIfExists` - #[serde(skip_serializing_if = "Option::is_none")] - pub overwrite: Option, - /// Ignores if target exists. - #[serde(skip_serializing_if = "Option::is_none")] - pub ignore_if_exists: Option, -} - -/// Rename file operation -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameFile { - /// The old (existing) location. - pub old_uri: Url, - /// The new location. - pub new_uri: Url, - /// Rename options. - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option, -} - -/// Delete file options -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DeleteFileOptions { - /// Delete the content recursively if a folder is denoted. - #[serde(skip_serializing_if = "Option::is_none")] - pub recursive: Option, - /// Ignore the operation if the file doesn't exist. - #[serde(skip_serializing_if = "Option::is_none")] - pub ignore_if_not_exists: Option, -} - -/// Delete file operation -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DeleteFile { - /// The file to delete. - pub uri: Url, - /// Delete options. - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option, -} - -/// A workspace edit represents changes to many resources managed in the workspace. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceEdit { - /// Holds changes to existing resources. - #[serde(with = "url_map")] - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(default)] - pub changes: Option>>, // changes?: { [uri: string]: TextEdit[]; }; - - /// Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes - /// are either an array of `TextDocumentEdit`s to express changes to n different text documents - /// where each text document edit addresses a specific version of a text document. Or it can contain - /// above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. - /// - /// Whether a client supports versioned document edits is expressed via - /// `workspace.workspaceEdit.documentChanges` client capability. - /// - /// If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then - /// only plain `TextEdit`s using the `changes` property are supported. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_changes: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum DocumentChanges { - Edits(Vec), - Operations(Vec), -} - -// TODO: Once https://github.com/serde-rs/serde/issues/912 is solved -// we can remove ResourceOp and switch to the following implementation -// of DocumentChangeOperation: -// -// #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -// #[serde(tag = "kind", rename_all="lowercase" )] -// pub enum DocumentChangeOperation { -// Create(CreateFile), -// Rename(RenameFile), -// Delete(DeleteFile), -// -// #[serde(other)] -// Edit(TextDocumentEdit), -// } - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged, rename_all = "lowercase")] -pub enum DocumentChangeOperation { - Op(ResourceOp), - Edit(TextDocumentEdit), -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum ResourceOp { - Create(CreateFile), - Rename(RenameFile), - Delete(DeleteFile), -} - -#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ConfigurationParams { - pub items: Vec, -} - -#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ConfigurationItem { - /// The scope to get the configuration section for. - #[serde(skip_serializing_if = "Option::is_none")] - pub scope_uri: Option, - - ///The configuration section asked for. - #[serde(skip_serializing_if = "Option::is_none")] - pub section: Option, -} - -mod url_map { - use super::*; - - use std::fmt; - - pub fn deserialize<'de, D>( - deserializer: D, - ) -> Result>>, D::Error> - where - D: serde::Deserializer<'de>, - { - struct UrlMapVisitor; - impl<'de> de::Visitor<'de> for UrlMapVisitor { - type Value = HashMap>; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("map") - } - - fn visit_map(self, mut visitor: M) -> Result - where - M: de::MapAccess<'de>, - { - let mut values = HashMap::with_capacity(visitor.size_hint().unwrap_or(0)); - - // While there are entries remaining in the input, add them - // into our map. - while let Some((key, value)) = visitor.next_entry::()? { - values.insert(key, value); - } - - Ok(values) - } - } - - struct OptionUrlMapVisitor; - impl<'de> de::Visitor<'de> for OptionUrlMapVisitor { - type Value = Option>>; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("option") - } - - #[inline] - fn visit_unit(self) -> Result - where - E: serde::de::Error, - { - Ok(None) - } - - #[inline] - fn visit_none(self) -> Result - where - E: serde::de::Error, - { - Ok(None) - } - - #[inline] - fn visit_some(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_map(UrlMapVisitor).map(Some) - } - } - - // Instantiate our Visitor and ask the Deserializer to drive - // it over the input data, resulting in an instance of MyMap. - deserializer.deserialize_option(OptionUrlMapVisitor) - } - - pub fn serialize( - changes: &Option>>, - serializer: S, - ) -> Result - where - S: serde::Serializer, - { - use serde::ser::SerializeMap; - - match *changes { - Some(ref changes) => { - let mut map = serializer.serialize_map(Some(changes.len()))?; - for (k, v) in changes { - map.serialize_entry(k.as_str(), v)?; - } - map.end() - } - None => serializer.serialize_none(), - } - } -} - -impl WorkspaceEdit { - pub fn new(changes: HashMap>) -> WorkspaceEdit { - WorkspaceEdit { - changes: Some(changes), - document_changes: None, - } - } -} - -/// Text documents are identified using a URI. On the protocol level, URIs are passed as strings. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct TextDocumentIdentifier { - // !!!!!! Note: - // In the spec VersionedTextDocumentIdentifier extends TextDocumentIdentifier - // This modelled by "mixing-in" TextDocumentIdentifier in VersionedTextDocumentIdentifier, - // so any changes to this type must be effected in the sub-type as well. - /// The text document's URI. - pub uri: Url, -} - -impl TextDocumentIdentifier { - pub fn new(uri: Url) -> TextDocumentIdentifier { - TextDocumentIdentifier { uri } - } -} - -/// An item to transfer a text document from the client to the server. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentItem { - /// The text document's URI. - pub uri: Url, - - /// The text document's language identifier. - pub language_id: String, - - /// The version number of this document (it will strictly increase after each - /// change, including undo/redo). - pub version: i64, - - /// The content of the opened text document. - pub text: String, -} - -impl TextDocumentItem { - pub fn new(uri: Url, language_id: String, version: i64, text: String) -> TextDocumentItem { - TextDocumentItem { - uri, - language_id, - version, - text, - } - } -} - -/// An identifier to denote a specific version of a text document. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct VersionedTextDocumentIdentifier { - // This field was "mixed-in" from TextDocumentIdentifier - /// The text document's URI. - pub uri: Url, - - /// The version number of this document. - pub version: Option, -} - -impl VersionedTextDocumentIdentifier { - pub fn new(uri: Url, version: i64) -> VersionedTextDocumentIdentifier { - VersionedTextDocumentIdentifier { - uri, - version: Some(version), - } - } -} - -/// A parameter literal used in requests to pass a text document and a position inside that document. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentPositionParams { - // !!!!!! Note: - // In the spec ReferenceParams extends TextDocumentPositionParams - // This modelled by "mixing-in" TextDocumentPositionParams in ReferenceParams, - // so any changes to this type must be effected in sub-type as well. - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The position inside the text document. - pub position: Position, -} - -impl TextDocumentPositionParams { - pub fn new( - text_document: TextDocumentIdentifier, - position: Position, - ) -> TextDocumentPositionParams { - TextDocumentPositionParams { - text_document, - position, - } - } -} - -/// A document filter denotes a document through properties like language, schema or pattern. -/// Examples are a filter that applies to TypeScript files on disk or a filter the applies to JSON -/// files with name package.json: -/// -/// { language: 'typescript', scheme: 'file' } -/// { language: 'json', pattern: '**/package.json' } -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DocumentFilter { - /// A language id, like `typescript`. - #[serde(skip_serializing_if = "Option::is_none")] - pub language: Option, - - /// A Uri [scheme](#Uri.scheme), like `file` or `untitled`. - #[serde(skip_serializing_if = "Option::is_none")] - pub scheme: Option, - - /// A glob pattern, like `*.{ts,js}`. - #[serde(skip_serializing_if = "Option::is_none")] - pub pattern: Option, -} - -/// A document selector is the combination of one or many document filters. -pub type DocumentSelector = Vec; - -// ========================= Actual Protocol ========================= - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct InitializeParams { - /// The process Id of the parent process that started - /// the server. Is null if the process has not been started by another process. - /// If the parent process is not alive then the server should exit (see exit notification) its process. - pub process_id: Option, - - /// The rootPath of the workspace. Is null - /// if no folder is open. - #[serde(skip_serializing_if = "Option::is_none")] - #[deprecated(note = "Use `root_uri` instead when possible")] - pub root_path: Option, - - /// The rootUri of the workspace. Is null if no - /// folder is open. If both `rootPath` and `rootUri` are set - /// `rootUri` wins. - #[serde(default)] - pub root_uri: Option, - - /// User provided initialization options. - #[serde(skip_serializing_if = "Option::is_none")] - pub initialization_options: Option, - - /// The capabilities provided by the client (editor) - pub capabilities: ClientCapabilities, - - /// The initial trace setting. If omitted trace is disabled ('off'). - #[serde(default)] - #[serde(skip_serializing_if = "Option::is_none")] - pub trace: Option, - - /// The workspace folders configured in the client when the server starts. - /// This property is only available if the client supports workspace folders. - /// It can be `null` if the client supports workspace folders but none are - /// configured. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_folders: Option>, - - /// Information about the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub client_info: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -pub struct ClientInfo { - /// The name of the client as defined by the client. - pub name: String, - /// The client's version as defined by the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub version: Option, -} - -#[derive(Debug, PartialEq, Clone, Copy, Deserialize, Serialize)] -pub struct InitializedParams {} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] -pub enum TraceOption { - #[serde(rename = "off")] - Off, - #[serde(rename = "messages")] - Messages, - #[serde(rename = "verbose")] - Verbose, -} - -impl Default for TraceOption { - fn default() -> TraceOption { - TraceOption::Off - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct GenericRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, - - #[serde(flatten)] - pub options: GenericOptions, - - #[serde(flatten)] - pub static_registration_options: StaticRegistrationOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct GenericOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct GenericParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GenericCapability { - /// This capability supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GotoCapability { - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client supports additional metadata in the form of definition links. - pub link_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceEditCapability { - /// The client supports versioned document changes in `WorkspaceEdit`s - #[serde(skip_serializing_if = "Option::is_none")] - pub document_changes: Option, - - /// The resource operations the client supports. Clients should at least - /// support 'create', 'rename' and 'delete' files and folders. - #[serde(skip_serializing_if = "Option::is_none")] - pub resource_operations: Option>, - - /// The failure handling strategy of a client if applying the workspace edit - /// failes. - #[serde(skip_serializing_if = "Option::is_none")] - pub failure_handling: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceCapability { - /// The server supports workspace folder. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_folders: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceFolderCapability { - #[serde(skip_serializing_if = "Option::is_none")] - pub supported: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub change_notifications: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum WorkspaceFolderCapabilityChangeNotifications { - Bool(bool), - Id(String), -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceFolder { - /// The associated URI for this workspace folder. - pub uri: Url, - /// The name of the workspace folder. Defaults to the uri's basename. - pub name: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidChangeWorkspaceFoldersParams { - /// The actual workspace folder change event. - pub event: WorkspaceFoldersChangeEvent, -} - -/// The workspace folder change event. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceFoldersChangeEvent { - /// The array of added workspace folders - pub added: Vec, - - /// The array of the removed workspace folders - pub removed: Vec, -} - -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] -#[serde(rename_all = "lowercase")] -pub enum ResourceOperationKind { - Create, - Rename, - Delete, -} - -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] -#[serde(rename_all = "camelCase")] -pub enum FailureHandlingKind { - Abort, - Transactional, - TextOnlyTransactional, - Undo, -} - -/// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SymbolKindCapability { - /// The symbol kind values the client supports. When this - /// property exists the client also guarantees that it will - /// handle values outside its set gracefully and falls back - /// to a default value when unknown. - /// - /// If this property is not present the client only supports - /// the symbol kinds from `File` to `Array` as defined in - /// the initial version of the protocol. - pub value_set: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceSymbolClientCapabilities { - /// This capability supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub symbol_kind: Option, - - /// The client supports tags on `SymbolInformation`. - /// Clients supporting tags have to handle unknown tags gracefully. - /// - /// @since 3.16.0 - /// - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "TagSupport::deserialize_compat" - )] - #[cfg(feature = "proposed")] - pub tag_support: Option>, -} - -/// Workspace specific client capabilities. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceClientCapabilities { - /// The client supports applying batch edits to the workspace by supporting - /// the request 'workspace/applyEdit' - #[serde(skip_serializing_if = "Option::is_none")] - pub apply_edit: Option, - - /// Capabilities specific to `WorkspaceEdit`s - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_edit: Option, - - /// Capabilities specific to the `workspace/didChangeConfiguration` notification. - #[serde(skip_serializing_if = "Option::is_none")] - pub did_change_configuration: Option, - - /// Capabilities specific to the `workspace/didChangeWatchedFiles` notification. - #[serde(skip_serializing_if = "Option::is_none")] - pub did_change_watched_files: Option, - - /// Capabilities specific to the `workspace/symbol` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub symbol: Option, - - /// Capabilities specific to the `workspace/executeCommand` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub execute_command: Option, - - /// The client has support for workspace folders. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_folders: Option, - - /// The client supports `workspace/configuration` requests. - #[serde(skip_serializing_if = "Option::is_none")] - pub configuration: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SynchronizationCapability { - /// Whether text document synchronization supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client supports sending will save notifications. - #[serde(skip_serializing_if = "Option::is_none")] - pub will_save: Option, - - /// The client supports sending a will save request and - /// waits for a response providing text edits which will - /// be applied to the document before it is saved. - #[serde(skip_serializing_if = "Option::is_none")] - pub will_save_wait_until: Option, - - /// The client supports did save notifications. - #[serde(skip_serializing_if = "Option::is_none")] - pub did_save: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionItemCapability { - /// Client supports snippets as insert text. - /// - /// A snippet can define tab stops and placeholders with `$1`, `$2` - /// and `${3:foo}`. `$0` defines the final tab stop, it defaults to - /// the end of the snippet. Placeholders with equal identifiers are linked, - /// that is typing in one will update others too. - #[serde(skip_serializing_if = "Option::is_none")] - pub snippet_support: Option, - - /// Client supports commit characters on a completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub commit_characters_support: Option, - - /// Client supports the follow content formats for the documentation - /// property. The order describes the preferred format of the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation_format: Option>, - - /// Client supports the deprecated property on a completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub deprecated_support: Option, - - /// Client supports the preselect property on a completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub preselect_support: Option, - - /// Client supports the tag property on a completion item. Clients supporting - /// tags have to handle unknown tags gracefully. Clients especially need to - /// preserve unknown tags when sending a completion item back to the server in - /// a resolve call. - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "TagSupport::deserialize_compat" - )] - pub tag_support: Option>, - - /// Client support insert replace edit to control different behavior if a - /// completion item is inserted in the text or should replace text. - /// - /// @since 3.16.0 - Proposed state - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub insert_replace_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum CompletionItemTag { - Deprecated = 1, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionItemKindCapability { - /// The completion item kind values the client supports. When this - /// property exists the client also guarantees that it will - /// handle values outside its set gracefully and falls back - /// to a default value when unknown. - /// - /// If this property is not present the client only supports - /// the completion items kinds from `Text` to `Reference` as defined in - /// the initial version of the protocol. - #[serde(skip_serializing_if = "Option::is_none")] - pub value_set: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct HoverCapability { - /// Whether completion supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Client supports the follow content formats for the content - /// property. The order describes the preferred format of the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub content_format: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionCapability { - /// Whether completion supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client supports the following `CompletionItem` specific - /// capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub completion_item: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub completion_item_kind: Option, - - /// The client supports to send additional context information for a - /// `textDocument/completion` requestion. - #[serde(skip_serializing_if = "Option::is_none")] - pub context_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureInformationSettings { - /// Client supports the follow content formats for the documentation - /// property. The order describes the preferred format of the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation_format: Option>, - - #[serde(skip_serializing_if = "Option::is_none")] - pub parameter_information: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ParameterInformationSettings { - /// The client supports processing label offsets instead of a - /// simple label string. - #[serde(skip_serializing_if = "Option::is_none")] - pub label_offset_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelpCapability { - /// Whether completion supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client supports the following `SignatureInformation` - /// specific properties. - #[serde(skip_serializing_if = "Option::is_none")] - pub signature_information: Option, - - /// The client supports to send additional context information for a - /// `textDocument/signatureHelp` request. A client that opts into - /// contextSupport will also support the `retriggerCharacters` on - /// `SignatureHelpOptions`. - #[serde(skip_serializing_if = "Option::is_none")] - pub context_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct PublishDiagnosticsCapability { - /// Whether the clients accepts diagnostics with related information. - #[serde(skip_serializing_if = "Option::is_none")] - pub related_information: Option, - - /// Client supports the tag property to provide meta data about a diagnostic. - /// Clients supporting tags have to handle unknown tags gracefully. - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "TagSupport::deserialize_compat" - )] - pub tag_support: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TagSupport { - /// The tags supported by the client. - pub value_set: Vec, -} - -impl TagSupport { - /// Support for deserializing a boolean tag Support, in case it's present. - /// - /// This is currently the case for vscode 1.41.1 - fn deserialize_compat<'de, S>(serializer: S) -> Result>, S::Error> - where - S: serde::Deserializer<'de>, - T: serde::Deserialize<'de>, - { - Ok( - match Option::::deserialize(serializer).map_err(serde::de::Error::custom)? { - Some(Value::Bool(false)) => None, - Some(Value::Bool(true)) => Some(TagSupport { value_set: vec![] }), - Some(other) => { - Some(TagSupport::::deserialize(other).map_err(serde::de::Error::custom)?) - } - None => None, - }, - ) - } -} - -/// Text document specific client capabilities. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentClientCapabilities { - #[serde(skip_serializing_if = "Option::is_none")] - pub synchronization: Option, - /// Capabilities specific to the `textDocument/completion` - #[serde(skip_serializing_if = "Option::is_none")] - pub completion: Option, - - /// Capabilities specific to the `textDocument/hover` - #[serde(skip_serializing_if = "Option::is_none")] - pub hover: Option, - - /// Capabilities specific to the `textDocument/signatureHelp` - #[serde(skip_serializing_if = "Option::is_none")] - pub signature_help: Option, - - /// Capabilities specific to the `textDocument/references` - #[serde(skip_serializing_if = "Option::is_none")] - pub references: Option, - - /// Capabilities specific to the `textDocument/documentHighlight` - #[serde(skip_serializing_if = "Option::is_none")] - pub document_highlight: Option, - - /// Capabilities specific to the `textDocument/documentSymbol` - #[serde(skip_serializing_if = "Option::is_none")] - pub document_symbol: Option, - /// Capabilities specific to the `textDocument/formatting` - #[serde(skip_serializing_if = "Option::is_none")] - pub formatting: Option, - - /// Capabilities specific to the `textDocument/rangeFormatting` - #[serde(skip_serializing_if = "Option::is_none")] - pub range_formatting: Option, - - /// Capabilities specific to the `textDocument/onTypeFormatting` - #[serde(skip_serializing_if = "Option::is_none")] - pub on_type_formatting: Option, - - /// Capabilities specific to the `textDocument/declaration` - #[serde(skip_serializing_if = "Option::is_none")] - pub declaration: Option, - - /// Capabilities specific to the `textDocument/definition` - #[serde(skip_serializing_if = "Option::is_none")] - pub definition: Option, - - /// Capabilities specific to the `textDocument/typeDefinition` - #[serde(skip_serializing_if = "Option::is_none")] - pub type_definition: Option, - - /// Capabilities specific to the `textDocument/implementation` - #[serde(skip_serializing_if = "Option::is_none")] - pub implementation: Option, - - /// Capabilities specific to the `textDocument/codeAction` - #[serde(skip_serializing_if = "Option::is_none")] - pub code_action: Option, - - /// Capabilities specific to the `textDocument/codeLens` - #[serde(skip_serializing_if = "Option::is_none")] - pub code_lens: Option, - - /// Capabilities specific to the `textDocument/documentLink` - #[serde(skip_serializing_if = "Option::is_none")] - pub document_link: Option, - - /// Capabilities specific to the `textDocument/documentColor` and the - /// `textDocument/colorPresentation` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub color_provider: Option, - - /// Capabilities specific to the `textDocument/rename` - #[serde(skip_serializing_if = "Option::is_none")] - pub rename: Option, - - /// Capabilities specific to `textDocument/publishDiagnostics`. - #[serde(skip_serializing_if = "Option::is_none")] - pub publish_diagnostics: Option, - - /// Capabilities specific to `textDocument/foldingRange` requests. - #[serde(skip_serializing_if = "Option::is_none")] - pub folding_range: Option, - - /// The client's semantic highlighting capability. - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub semantic_highlighting_capabilities: Option, - - /// Capabilities specific to the `textDocument/semanticTokens` - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub semantic_tokens: Option, -} - -/// Window specific client capabilities. -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WindowClientCapabilities { - /// Whether client supports create a work done progress UI from the server side. - #[serde(skip_serializing_if = "Option::is_none")] - pub work_done_progress: Option, -} - -/// Where ClientCapabilities are currently empty: -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ClientCapabilities { - /// Workspace specific client capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace: Option, - - /// Text document specific client capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub text_document: Option, - - /// Window specific client capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub window: Option, - - /// Experimental client capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub experimental: Option, -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct InitializeResult { - /// The capabilities the language server provides. - pub capabilities: ServerCapabilities, - - /// The capabilities the language server provides. - #[serde(skip_serializing_if = "Option::is_none")] - pub server_info: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct ServerInfo { - /// The name of the server as defined by the server. - pub name: String, - /// The servers's version as defined by the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub version: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct InitializeError { - /// Indicates whether the client should retry to send the - /// initilize request after showing the message provided - /// in the ResponseError. - pub retry: bool, -} - -// The server can signal the following capabilities: - -/// Defines how the host (editor) should sync document changes to the language server. -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum TextDocumentSyncKind { - /// Documents should not be synced at all. - None = 0, - - /// Documents are synced by always sending the full content of the document. - Full = 1, - - /// Documents are synced by sending the full content on open. After that only - /// incremental updates to the document are sent. - Incremental = 2, -} - -/// Completion options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionOptions { - /// The server provides support to resolve additional information for a completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub resolve_provider: Option, - - /// The characters that trigger completion automatically. - #[serde(skip_serializing_if = "Option::is_none")] - pub trigger_characters: Option>, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -/// Hover options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct HoverOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct HoverRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, - - #[serde(flatten)] - pub hover_options: HoverOptions, -} - -/// Signature help options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelpOptions { - /// The characters that trigger signature help automatically. - #[serde(skip_serializing_if = "Option::is_none")] - pub trigger_characters: Option>, - - /// List of characters that re-trigger signature help. - /// These trigger characters are only active when signature help is already showing. All trigger characters - /// are also counted as re-trigger characters. - #[serde(skip_serializing_if = "Option::is_none")] - pub retrigger_characters: Option>, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -/// Signature help options. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct SignatureHelpRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, -} -/// Signature help options. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum SignatureHelpTriggerKind { - /// Signature help was invoked manually by the user or by a command. - Invoked = 1, - /// Signature help was triggered by a trigger character. - TriggerCharacter = 2, - /// Signature help was triggered by the cursor moving or by the document content changing. - ContentChange = 3, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelpParams { - /// The signature help context. This is only available if the client specifies - /// to send this using the client capability `textDocument.signatureHelp.contextSupport === true` - #[serde(skip_serializing_if = "Option::is_none")] - pub context: Option, - - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelpContext { - /// Action that caused signature help to be triggered. - pub trigger_kind: SignatureHelpTriggerKind, - - /// Character that caused signature help to be triggered. - /// This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter` - #[serde(skip_serializing_if = "Option::is_none")] - pub trigger_character: Option, - - /// `true` if signature help was already showing when it was triggered. - /// Retriggers occur when the signature help is already active and can be caused by actions such as - /// typing a trigger character, a cursor move, or document content changes. - pub is_retrigger: bool, - - /// The currently active `SignatureHelp`. - /// The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on - /// the user navigating through available signatures. - #[serde(skip_serializing_if = "Option::is_none")] - pub active_signature_help: Option, -} - -/// Code Lens options. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeLensOptions { - /// Code lens has a resolve provider as well. - #[serde(skip_serializing_if = "Option::is_none")] - pub resolve_provider: Option, -} - -/// Format document on type options -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentOnTypeFormattingOptions { - /// A character on which formatting should be triggered, like `}`. - pub first_trigger_character: String, - - /// More trigger characters. - #[serde(skip_serializing_if = "Option::is_none")] - pub more_trigger_character: Option>, -} - -/// Execute command options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct ExecuteCommandOptions { - /// The commands to be executed on the server - pub commands: Vec, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -/// Save options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SaveOptions { - /// The client is supposed to include the content on save. - #[serde(skip_serializing_if = "Option::is_none")] - pub include_text: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum TextDocumentSyncSaveOptions { - Supported(bool), - SaveOptions(SaveOptions), -} - -impl From for TextDocumentSyncSaveOptions { - fn from(from: SaveOptions) -> Self { - Self::SaveOptions(from) - } -} - -impl From for TextDocumentSyncSaveOptions { - fn from(from: bool) -> Self { - Self::Supported(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentSyncOptions { - /// Open and close notifications are sent to the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub open_close: Option, - - /// Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full - /// and TextDocumentSyncKindIncremental. - #[serde(skip_serializing_if = "Option::is_none")] - pub change: Option, - - /// Will save notifications are sent to the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub will_save: Option, - - /// Will save wait until requests are sent to the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub will_save_wait_until: Option, - - /// Save notifications are sent to the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub save: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum TextDocumentSyncCapability { - Kind(TextDocumentSyncKind), - Options(TextDocumentSyncOptions), -} - -impl From for TextDocumentSyncCapability { - fn from(from: TextDocumentSyncOptions) -> Self { - Self::Options(from) - } -} - -impl From for TextDocumentSyncCapability { - fn from(from: TextDocumentSyncKind) -> Self { - Self::Kind(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum ImplementationProviderCapability { - Simple(bool), - Options(StaticTextDocumentRegistrationOptions), -} - -impl From for ImplementationProviderCapability { - fn from(from: StaticTextDocumentRegistrationOptions) -> Self { - Self::Options(from) - } -} - -impl From for ImplementationProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum TypeDefinitionProviderCapability { - Simple(bool), - Options(StaticTextDocumentRegistrationOptions), -} - -impl From for TypeDefinitionProviderCapability { - fn from(from: StaticTextDocumentRegistrationOptions) -> Self { - Self::Options(from) - } -} - -impl From for TypeDefinitionProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum HoverProviderCapability { - Simple(bool), - Options(HoverOptions), -} - -impl From for HoverProviderCapability { - fn from(from: HoverOptions) -> Self { - Self::Options(from) - } -} - -impl From for HoverProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum ColorProviderCapability { - Simple(bool), - ColorProvider(ColorProviderOptions), - Options(StaticTextDocumentColorProviderOptions), -} - -impl From for ColorProviderCapability { - fn from(from: ColorProviderOptions) -> Self { - Self::ColorProvider(from) - } -} - -impl From for ColorProviderCapability { - fn from(from: StaticTextDocumentColorProviderOptions) -> Self { - Self::Options(from) - } -} - -impl From for ColorProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum CodeActionProviderCapability { - Simple(bool), - Options(CodeActionOptions), -} - -impl From for CodeActionProviderCapability { - fn from(from: CodeActionOptions) -> Self { - Self::Options(from) - } -} - -impl From for CodeActionProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionCapability { - /// - /// This capability supports dynamic registration. - /// - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client support code action literals as a valid - /// response of the `textDocument/codeAction` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub code_action_literal_support: Option, - - /// Whether code action supports the `isPreferred` property. - #[serde(skip_serializing_if = "Option::is_none")] - pub is_preferred_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionLiteralSupport { - /// The code action kind is support with the following value set. - pub code_action_kind: CodeActionKindLiteralSupport, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionKindLiteralSupport { - /// The code action kind values the client supports. When this - /// property exists the client also guarantees that it will - /// handle values outside its set gracefully and falls back - /// to a default value when unknown. - pub value_set: Vec, -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ServerCapabilities { - /// Defines how text documents are synced. - #[serde(skip_serializing_if = "Option::is_none")] - pub text_document_sync: Option, - - /// Capabilities specific to `textDocument/selectionRange` requests. - #[serde(skip_serializing_if = "Option::is_none")] - pub selection_range_provider: Option, - - /// The server provides hover support. - #[serde(skip_serializing_if = "Option::is_none")] - pub hover_provider: Option, - - /// The server provides completion support. - #[serde(skip_serializing_if = "Option::is_none")] - pub completion_provider: Option, - - /// The server provides signature help support. - #[serde(skip_serializing_if = "Option::is_none")] - pub signature_help_provider: Option, - - /// The server provides goto definition support. - #[serde(skip_serializing_if = "Option::is_none")] - pub definition_provider: Option, - - /// The server provides goto type definition support. - #[serde(skip_serializing_if = "Option::is_none")] - pub type_definition_provider: Option, - - /// the server provides goto implementation support. - #[serde(skip_serializing_if = "Option::is_none")] - pub implementation_provider: Option, - - /// The server provides find references support. - #[serde(skip_serializing_if = "Option::is_none")] - pub references_provider: Option, - - /// The server provides document highlight support. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_highlight_provider: Option, - - /// The server provides document symbol support. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_symbol_provider: Option, - - /// The server provides workspace symbol support. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_symbol_provider: Option, - - /// The server provides code actions. - #[serde(skip_serializing_if = "Option::is_none")] - pub code_action_provider: Option, - - /// The server provides code lens. - #[serde(skip_serializing_if = "Option::is_none")] - pub code_lens_provider: Option, - - /// The server provides document formatting. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_formatting_provider: Option, - - /// The server provides document range formatting. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_range_formatting_provider: Option, - - /// The server provides document formatting on typing. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_on_type_formatting_provider: Option, - - /// The server provides rename support. - #[serde(skip_serializing_if = "Option::is_none")] - pub rename_provider: Option, - - /// The server provides document link support. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_link_provider: Option, - - /// The server provides color provider support. - #[serde(skip_serializing_if = "Option::is_none")] - pub color_provider: Option, - - /// The server provides folding provider support. - #[serde(skip_serializing_if = "Option::is_none")] - pub folding_range_provider: Option, - - /// The server provides go to declaration support. - #[serde(skip_serializing_if = "Option::is_none")] - pub declaration_provider: Option, - - /// The server provides execute command support. - #[serde(skip_serializing_if = "Option::is_none")] - pub execute_command_provider: Option, - - /// Workspace specific server capabilities - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace: Option, - - /// Semantic highlighting server capabilities. - #[cfg(feature = "proposed")] - #[serde(skip_serializing_if = "Option::is_none")] - pub semantic_highlighting: Option, - - /// Call hierarchy provider capabilities. - #[cfg(feature = "proposed")] - #[serde(skip_serializing_if = "Option::is_none")] - pub call_hierarchy_provider: Option, - - /// Semantic tokens server capabilities. - #[cfg(feature = "proposed")] - #[serde(skip_serializing_if = "Option::is_none")] - pub semantic_tokens_provider: Option, - - /// Experimental server capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub experimental: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentLinkCapabilities { - /// Whether document link supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Whether the client support the `tooltip` property on `DocumentLink`. - #[serde(skip_serializing_if = "Option::is_none")] - pub tooltip_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ShowMessageParams { - /// The message type. See {@link MessageType}. - #[serde(rename = "type")] - pub typ: MessageType, - - /// The actual message. - pub message: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum MessageType { - /// An error message. - Error = 1, - /// A warning message. - Warning = 2, - /// An information message. - Info = 3, - /// A log message. - Log = 4, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ShowMessageRequestParams { - /// The message type. See {@link MessageType} - #[serde(rename = "type")] - pub typ: MessageType, - - /// The actual message - pub message: String, - - /// The message action items to present. - #[serde(skip_serializing_if = "Option::is_none")] - pub actions: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct MessageActionItem { - /// A short title like 'Retry', 'Open Log' etc. - pub title: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct LogMessageParams { - /// The message type. See {@link MessageType} - #[serde(rename = "type")] - pub typ: MessageType, - - /// The actual message - pub message: String, -} - -/// General parameters to to register for a capability. -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Registration { - /// The id used to register the request. The id can be used to deregister - /// the request again. - pub id: String, - - /// The method / capability to register for. - pub method: String, - - /// Options necessary for the registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub register_options: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -pub struct RegistrationParams { - pub registrations: Vec, -} - -/// Since most of the registration options require to specify a document selector there is a base -/// interface that can be used. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentRegistrationOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct StaticRegistrationOptions { - #[serde(skip_serializing_if = "Option::is_none")] - pub id: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct StaticTextDocumentRegistrationOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub id: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ColorProviderOptions {} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct StaticTextDocumentColorProviderOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub id: Option, -} - -/// General parameters to unregister a capability. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct Unregistration { - /// The id used to unregister the request or notification. Usually an id - /// provided during the register request. - pub id: String, - - /// The method / capability to unregister for. - pub method: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct UnregistrationParams { - pub unregisterations: Vec, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -pub struct DidChangeConfigurationParams { - /// The actual changed settings - pub settings: Value, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidOpenTextDocumentParams { - /// The document that was opened. - pub text_document: TextDocumentItem, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidChangeTextDocumentParams { - /// The document that did change. The version number points - /// to the version after all provided content changes have - /// been applied. - pub text_document: VersionedTextDocumentIdentifier, - /// The actual content changes. - pub content_changes: Vec, -} - -/// An event describing a change to a text document. If range and rangeLength are omitted -/// the new text is considered to be the full content of the document. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentContentChangeEvent { - /// The range of the document that changed. - #[serde(skip_serializing_if = "Option::is_none")] - pub range: Option, - - /// The length of the range that got replaced. - /// NOTE: seems redundant, see: - #[serde(skip_serializing_if = "Option::is_none")] - pub range_length: Option, - - /// The new text of the document. - pub text: String, -} - -/// Descibe options to be used when registered for text document change events. -/// -/// Extends TextDocumentRegistrationOptions -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentChangeRegistrationOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, - - /// How documents are synced to the server. See TextDocumentSyncKind.Full - /// and TextDocumentSyncKindIncremental. - pub sync_kind: i32, -} - -/// The parameters send in a will save text document notification. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WillSaveTextDocumentParams { - /// The document that will be saved. - pub text_document: TextDocumentIdentifier, - - /// The 'TextDocumentSaveReason'. - pub reason: TextDocumentSaveReason, -} - -/// Represents reasons why a text document is saved. -#[derive(Copy, Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum TextDocumentSaveReason { - /// Manually triggered, e.g. by the user pressing save, by starting debugging, - /// or by an API call. - Manual = 1, - - /// Automatic after a delay. - AfterDelay = 2, - - /// When the editor lost focus. - FocusOut = 3, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidCloseTextDocumentParams { - /// The document that was closed. - pub text_document: TextDocumentIdentifier, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidSaveTextDocumentParams { - /// The document that was saved. - pub text_document: TextDocumentIdentifier, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentSaveRegistrationOptions { - /// The client is supposed to include the content on save. - #[serde(skip_serializing_if = "Option::is_none")] - pub include_text: Option, - - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DidChangeWatchedFilesParams { - /// The actual file events. - pub changes: Vec, -} - -/// The file event type. -#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum FileChangeType { - /// The file got created. - Created = 1, - - /// The file got changed. - Changed = 2, - - /// The file got deleted. - Deleted = 3, -} - -/// An event describing a file change. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct FileEvent { - /// The file's URI. - pub uri: Url, - - /// The change type. - #[serde(rename = "type")] - pub typ: FileChangeType, -} - -impl FileEvent { - pub fn new(uri: Url, typ: FileChangeType) -> FileEvent { - FileEvent { uri, typ } - } -} - -/// Describe options to be used when registered for text document change events. -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] -pub struct DidChangeWatchedFilesRegistrationOptions { - /// The watchers to register. - pub watchers: Vec, -} - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct FileSystemWatcher { - /// The glob pattern to watch - pub glob_pattern: String, - - /// The kind of events of interest. If omitted it defaults to WatchKind.Create | - /// WatchKind.Change | WatchKind.Delete which is 7. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, -} - -bitflags! { -pub struct WatchKind: u8 { - /// Interested in create events. - const Create = 1; - /// Interested in change events - const Change = 2; - /// Interested in delete events - const Delete = 4; -} -} - -impl<'de> serde::Deserialize<'de> for WatchKind { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let i = u8::deserialize(deserializer)?; - WatchKind::from_bits(i).ok_or_else(|| { - D::Error::invalid_value(de::Unexpected::Unsigned(u64::from(i)), &"Unknown flag") - }) - } -} - -impl serde::Serialize for WatchKind { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_u8(self.bits()) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct PublishDiagnosticsParams { - /// The URI for which diagnostic information is reported. - pub uri: Url, - - /// An array of diagnostic information items. - pub diagnostics: Vec, - - /// Optional the version number of the document the diagnostics are published for. - #[serde(skip_serializing_if = "Option::is_none")] - pub version: Option, -} - -impl PublishDiagnosticsParams { - pub fn new( - uri: Url, - diagnostics: Vec, - version: Option, - ) -> PublishDiagnosticsParams { - PublishDiagnosticsParams { - uri, - diagnostics, - version, - } - } -} - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -pub struct CompletionRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, - - #[serde(flatten)] - pub completion_options: CompletionOptions, -} - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum CompletionResponse { - Array(Vec), - List(CompletionList), -} - -impl From> for CompletionResponse { - fn from(items: Vec) -> Self { - CompletionResponse::Array(items) - } -} - -impl From for CompletionResponse { - fn from(list: CompletionList) -> Self { - CompletionResponse::List(list) - } -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionParams { - // This field was "mixed-in" from TextDocumentPositionParams - #[serde(flatten)] - pub text_document_position: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - // CompletionParams properties: - #[serde(skip_serializing_if = "Option::is_none")] - pub context: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionContext { - /// How the completion was triggered. - pub trigger_kind: CompletionTriggerKind, - - /// The trigger character (a single character) that has trigger code complete. - /// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` - #[serde(skip_serializing_if = "Option::is_none")] - pub trigger_character: Option, -} - -/// How a completion was triggered. -#[derive(Debug, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum CompletionTriggerKind { - Invoked = 1, - TriggerCharacter = 2, - TriggerForIncompleteCompletions = 3, -} - -/// Represents a collection of [completion items](#CompletionItem) to be presented -/// in the editor. -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionList { - /// This list it not complete. Further typing should result in recomputing - /// this list. - pub is_incomplete: bool, - - /// The completion items. - pub items: Vec, -} - -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] -#[serde(untagged)] -pub enum Documentation { - String(String), - MarkupContent(MarkupContent), -} - -#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct CompletionItem { - /// The label of this completion item. By default - /// also the text that is inserted when selecting - /// this completion. - pub label: String, - - /// The kind of this completion item. Based of the kind - /// an icon is chosen by the editor. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, - - /// A human-readable string with additional information - /// about this item, like type or symbol information. - #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - - /// A human-readable string that represents a doc-comment. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation: Option, - - /// Indicates if this item is deprecated. - #[serde(skip_serializing_if = "Option::is_none")] - pub deprecated: Option, - - /// Select this item when showing. - #[serde(skip_serializing_if = "Option::is_none")] - pub preselect: Option, - - /// A string that shoud be used when comparing this item - /// with other items. When `falsy` the label is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub sort_text: Option, - - /// A string that should be used when filtering a set of - /// completion items. When `falsy` the label is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub filter_text: Option, - - /// A string that should be inserted a document when selecting - /// this completion. When `falsy` the label is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub insert_text: Option, - - /// The format of the insert text. The format applies to both the `insertText` property - /// and the `newText` property of a provided `textEdit`. - #[serde(skip_serializing_if = "Option::is_none")] - pub insert_text_format: Option, - - /// An edit which is applied to a document when selecting - /// this completion. When an edit is provided the value of - /// insertText is ignored. - /// - /// Most editors support two different operation when accepting a completion item. One is to insert a - /// completion text and the other is to replace an existing text with a competion text. Since this can - /// usually not predetermend by a server it can report both ranges. Clients need to signal support for - /// `InsertReplaceEdits` via the `textDocument.completion.insertReplaceSupport` client capability - /// property. - /// - /// *Note 1:* The text edit's range as well as both ranges from a insert replace edit must be a - /// [single line] and they must contain the position at which completion has been requested. - /// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range must be a prefix of - /// the edit's replace range, that means it must be contained and starting at the same position. - /// - /// @since 3.16.0 additional type `InsertReplaceEdit` - Proposed state - #[serde(skip_serializing_if = "Option::is_none")] - pub text_edit: Option, - - /// An optional array of additional text edits that are applied when - /// selecting this completion. Edits must not overlap with the main edit - /// nor with themselves. - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_text_edits: Option>, - - /// An optional command that is executed *after* inserting this completion. *Note* that - /// additional modifications to the current document should be described with the - /// additionalTextEdits-property. - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - - /// An data entry field that is preserved on a completion item between - /// a completion and a completion resolve request. - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, - - /// Tags for this completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub tags: Option>, -} - -impl CompletionItem { - /// Create a CompletionItem with the minimum possible info (label and detail). - pub fn new_simple(label: String, detail: String) -> CompletionItem { - CompletionItem { - label, - detail: Some(detail), - ..Self::default() - } - } -} - -/// The kind of a completion entry. -#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr)] -#[repr(u8)] -pub enum CompletionItemKind { - Text = 1, - Method = 2, - Function = 3, - Constructor = 4, - Field = 5, - Variable = 6, - Class = 7, - Interface = 8, - Module = 9, - Property = 10, - Unit = 11, - Value = 12, - Enum = 13, - Keyword = 14, - Snippet = 15, - Color = 16, - File = 17, - Reference = 18, - Folder = 19, - EnumMember = 20, - Constant = 21, - Struct = 22, - Event = 23, - Operator = 24, - TypeParameter = 25, -} - -/// Defines how to interpret the insert text in a completion item -#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr)] -#[repr(u8)] -pub enum InsertTextFormat { - PlainText = 1, - Snippet = 2, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct HoverParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -/// The result of a hover request. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct Hover { - /// The hover's content - pub contents: HoverContents, - /// An optional range is a range inside a text document - /// that is used to visualize a hover, e.g. by changing the background color. - #[serde(skip_serializing_if = "Option::is_none")] - pub range: Option, -} - -/// Hover contents could be single entry or multiple entries. -#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum HoverContents { - Scalar(MarkedString), - Array(Vec), - Markup(MarkupContent), -} - -/// The marked string is rendered: -/// - as markdown if it is represented as a string -/// - as code block of the given langauge if it is represented as a pair of a language and a value -/// -/// The pair of a language and a value is an equivalent to markdown: -/// ```${language} -/// ${value} -/// ``` -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum MarkedString { - String(String), - LanguageString(LanguageString), -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct LanguageString { - pub language: String, - pub value: String, -} - -impl MarkedString { - pub fn from_markdown(markdown: String) -> MarkedString { - MarkedString::String(markdown) - } - - pub fn from_language_code(language: String, code_block: String) -> MarkedString { - MarkedString::LanguageString(LanguageString { - language, - value: code_block, - }) - } -} - -/// Signature help represents the signature of something -/// callable. There can be multiple signature but only one -/// active and only one active parameter. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelp { - /// One or more signatures. - pub signatures: Vec, - - /// The active signature. - #[serde(skip_serializing_if = "Option::is_none")] - pub active_signature: Option, - - /// The active parameter of the active signature. - #[serde(skip_serializing_if = "Option::is_none")] - pub active_parameter: Option, -} - -/// Represents the signature of something callable. A signature -/// can have a label, like a function-name, a doc-comment, and -/// a set of parameters. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct SignatureInformation { - /// The label of this signature. Will be shown in - /// the UI. - pub label: String, - - /// The human-readable doc-comment of this signature. Will be shown - /// in the UI but can be omitted. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation: Option, - - /// The parameters of this signature. - #[serde(skip_serializing_if = "Option::is_none")] - pub parameters: Option>, -} - -/// Represents a parameter of a callable-signature. A parameter can -/// have a label and a doc-comment. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ParameterInformation { - /// The label of this parameter information. - /// - /// Either a string or an inclusive start and exclusive end offsets within its containing - /// signature label. (see SignatureInformation.label). *Note*: A label of type string must be - /// a substring of its containing signature label. - pub label: ParameterLabel, - - /// The human-readable doc-comment of this parameter. Will be shown - /// in the UI but can be omitted. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum ParameterLabel { - Simple(String), - LabelOffsets([u64; 2]), -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GotoDefinitionParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// GotoDefinition response can be single location, or multiple Locations or a link. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] -pub enum GotoDefinitionResponse { - Scalar(Location), - Array(Vec), - Link(Vec), -} - -impl From for GotoDefinitionResponse { - fn from(location: Location) -> Self { - GotoDefinitionResponse::Scalar(location) - } -} - -impl From> for GotoDefinitionResponse { - fn from(locations: Vec) -> Self { - GotoDefinitionResponse::Array(locations) - } -} - -impl From> for GotoDefinitionResponse { - fn from(locations: Vec) -> Self { - GotoDefinitionResponse::Link(locations) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ReferenceParams { - // Text Document and Position fields - #[serde(flatten)] - pub text_document_position: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - // ReferenceParams properties: - pub context: ReferenceContext, -} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ReferenceContext { - /// Include the declaration of the current symbol. - pub include_declaration: bool, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentHighlightParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// A document highlight is a range inside a text document which deserves -/// special attention. Usually a document highlight is visualized by changing -/// the background color of its range. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DocumentHighlight { - /// The range this highlight applies to. - pub range: Range, - - /// The highlight kind, default is DocumentHighlightKind.Text. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, -} - -/// A document highlight kind. -#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum DocumentHighlightKind { - /// A textual occurrance. - Text = 1, - - /// Read-access of a symbol, like reading a variable. - Read = 2, - - /// Write-access of a symbol, like writing to a variable. - Write = 3, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentSymbolClientCapabilities { - /// This capability supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Specific capabilities for the `SymbolKind`. - #[serde(skip_serializing_if = "Option::is_none")] - pub symbol_kind: Option, - - /// The client support hierarchical document symbols. - #[serde(skip_serializing_if = "Option::is_none")] - pub hierarchical_document_symbol_support: Option, - - /// The client supports tags on `SymbolInformation`. Tags are supported on - /// `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. - /// Clients supporting tags have to handle unknown tags gracefully. - /// - /// @since 3.16.0 - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "TagSupport::deserialize_compat" - )] - #[cfg(feature = "proposed")] - pub tag_support: Option>, -} - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum DocumentSymbolResponse { - Flat(Vec), - Nested(Vec), -} - -impl From> for DocumentSymbolResponse { - fn from(info: Vec) -> Self { - DocumentSymbolResponse::Flat(info) - } -} - -impl From> for DocumentSymbolResponse { - fn from(symbols: Vec) -> Self { - DocumentSymbolResponse::Nested(symbols) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentSymbolParams { - /// The text document. - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// Represents programming constructs like variables, classes, interfaces etc. -/// that appear in a document. Document symbols can be hierarchical and they have two ranges: -/// one that encloses its definition and one that points to its most interesting range, -/// e.g. the range of an identifier. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentSymbol { - /// The name of this symbol. - pub name: String, - /// More detail for this symbol, e.g the signature of a function. If not provided the - /// name is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - /// The kind of this symbol. - pub kind: SymbolKind, - /// Tags for this completion item. - /// since 3.16.0 - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub tags: Option>, - /// Indicates if this symbol is deprecated. - #[serde(skip_serializing_if = "Option::is_none")] - #[deprecated(note = "Use tags instead")] - pub deprecated: Option, - /// The range enclosing this symbol not including leading/trailing whitespace but everything else - /// like comments. This information is typically used to determine if the the clients cursor is - /// inside the symbol to reveal in the symbol in the UI. - pub range: Range, - /// The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. - /// Must be contained by the the `range`. - pub selection_range: Range, - /// Children of this symbol, e.g. properties of a class. - #[serde(skip_serializing_if = "Option::is_none")] - pub children: Option>, -} - -/// Represents information about programming constructs like variables, classes, -/// interfaces etc. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SymbolInformation { - /// The name of this symbol. - pub name: String, - - /// The kind of this symbol. - pub kind: SymbolKind, - - /// Tags for this completion item. - /// since 3.16.0 - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub tags: Option>, - - /// Indicates if this symbol is deprecated. - #[serde(skip_serializing_if = "Option::is_none")] - #[deprecated(note = "Use tags instead")] - pub deprecated: Option, - - /// The location of this symbol. - pub location: Location, - - /// The name of the symbol containing this symbol. - #[serde(skip_serializing_if = "Option::is_none")] - pub container_name: Option, -} - -/// A symbol kind. -#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize_repr, Deserialize_repr)] -#[repr(u8)] -pub enum SymbolKind { - File = 1, - Module = 2, - Namespace = 3, - Package = 4, - Class = 5, - Method = 6, - Property = 7, - Field = 8, - Constructor = 9, - Enum = 10, - Interface = 11, - Function = 12, - Variable = 13, - Constant = 14, - String = 15, - Number = 16, - Boolean = 17, - Array = 18, - Object = 19, - Key = 20, - Null = 21, - EnumMember = 22, - Struct = 23, - Event = 24, - Operator = 25, - TypeParameter = 26, - - // Capturing all unknown enums by this lib. - Unknown = 255, -} - -/// The parameters of a Workspace Symbol Request. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct WorkspaceSymbolParams { - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - /// A non-empty query string - pub query: String, -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct ExecuteCommandParams { - /// The identifier of the actual command handler. - pub command: String, - /// Arguments that the command should be invoked with. - #[serde(default)] - pub arguments: Vec, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -/// Execute command registration options. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ExecuteCommandRegistrationOptions { - /// The commands to be executed on the server - pub commands: Vec, - - #[serde(flatten)] - pub execute_command_options: ExecuteCommandOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ApplyWorkspaceEditParams { - /// The edits to apply. - pub edit: WorkspaceEdit, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ApplyWorkspaceEditResponse { - /// Indicates whether the edit was applied or not. - pub applied: bool, -} - -/// Params for the CodeActionRequest -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionParams { - /// The document in which the command was invoked. - pub text_document: TextDocumentIdentifier, - - /// The range for which the command was invoked. - pub range: Range, - - /// Context carrying additional information. - pub context: CodeActionContext, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// response for CodeActionRequest -pub type CodeActionResponse = Vec; - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -#[serde(untagged)] -pub enum CodeActionOrCommand { - Command(Command), - CodeAction(CodeAction), -} - -impl From for CodeActionOrCommand { - fn from(comand: Command) -> Self { - CodeActionOrCommand::Command(comand) - } -} - -impl From for CodeActionOrCommand { - fn from(action: CodeAction) -> Self { - CodeActionOrCommand::CodeAction(action) - } -} - -#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] -pub struct CodeActionKind(Cow<'static, str>); - -impl CodeActionKind { - /// Empty kind. - pub const EMPTY: CodeActionKind = CodeActionKind::new(""); - - /// Base kind for quickfix actions: 'quickfix' - pub const QUICKFIX: CodeActionKind = CodeActionKind::new("quickfix"); - - /// Base kind for refactoring actions: 'refactor' - pub const REFACTOR: CodeActionKind = CodeActionKind::new("refactor"); - - /// Base kind for refactoring extraction actions: 'refactor.extract' - /// - /// Example extract actions: - /// - /// - Extract method - /// - Extract function - /// - Extract variable - /// - Extract interface from class - /// - ... - pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract"); - - /// Base kind for refactoring inline actions: 'refactor.inline' - /// - /// Example inline actions: - /// - /// - Inline function - /// - Inline variable - /// - Inline constant - /// - ... - pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline"); - - /// Base kind for refactoring rewrite actions: 'refactor.rewrite' - /// - /// Example rewrite actions: - /// - /// - Convert JavaScript function to class - /// - Add or remove parameter - /// - Encapsulate field - /// - Make method static - /// - Move method to base class - /// - ... - pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite"); - - /// Base kind for source actions: `source` - /// - /// Source code actions apply to the entire file. - pub const SOURCE: CodeActionKind = CodeActionKind::new("source"); - - /// Base kind for an organize imports source action: `source.organizeImports` - pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind = - CodeActionKind::new("source.organizeImports"); - - pub const fn new(tag: &'static str) -> Self { - CodeActionKind(Cow::Borrowed(tag)) - } - - pub fn as_str(&self) -> &str { - &self.0 - } -} - -impl From for CodeActionKind { - fn from(from: String) -> Self { - CodeActionKind(Cow::from(from)) - } -} - -impl From<&'static str> for CodeActionKind { - fn from(from: &'static str) -> Self { - CodeActionKind::new(from) - } -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeAction { - /// A short, human-readable, title for this code action. - pub title: String, - - /// The kind of the code action. - /// Used to filter code actions. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, - - /// The diagnostics that this code action resolves. - #[serde(skip_serializing_if = "Option::is_none")] - pub diagnostics: Option>, - - /// The workspace edit this code action performs. - #[serde(skip_serializing_if = "Option::is_none")] - pub edit: Option, - - /// A command this code action executes. If a code action - /// provides an edit and a command, first the edit is - /// executed and then the command. - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - - /// Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted - /// by keybindings. - /// A quick fix should be marked preferred if it properly addresses the underlying error. - /// A refactoring should be marked preferred if it is the most reasonable choice of actions to take. - #[serde(skip_serializing_if = "Option::is_none")] - pub is_preferred: Option, -} - -/// Contains additional diagnostic information about the context in which -/// a code action is run. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct CodeActionContext { - /// An array of diagnostics. - pub diagnostics: Vec, - - /// Requested kind of actions to return. - /// - /// Actions not of this kind are filtered out by the client before being shown. So servers - /// can omit computing them. - #[serde(skip_serializing_if = "Option::is_none")] - pub only: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionOptions { - /// CodeActionKinds that this server may return. - /// - /// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server - /// may list out every specific kind they provide. - #[serde(skip_serializing_if = "Option::is_none")] - pub code_action_kinds: Option>, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeLensParams { - /// The document to request code lens for. - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// A code lens represents a command that should be shown along with -/// source text, like the number of references, a way to run tests, etc. -/// -/// A code lens is _unresolved_ when no command is associated to it. For performance -/// reasons the creation of a code lens and resolving should be done in two stages. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub struct CodeLens { - /// The range in which this code lens is valid. Should only span a single line. - pub range: Range, - - /// The command this code lens represents. - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - - /// A data entry field that is preserved on a code lens item between - /// a code lens and a code lens resolve request. - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentLinkParams { - /// The document to provide document links for. - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// A document link is a range in a text document that links to an internal or external resource, like another -/// text document or a web site. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DocumentLink { - /// The range this link applies to. - pub range: Range, - /// The uri this link points to. - #[serde(skip_serializing_if = "Option::is_none")] - pub target: Option, - - /// The tooltip text when you hover over this link. - /// - /// If a tooltip is provided, is will be displayed in a string that includes instructions on how to - /// trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, - /// user settings, and localization. - #[serde(skip_serializing_if = "Option::is_none")] - pub tooltip: Option, - - /// A data entry field that is preserved on a document link between a DocumentLinkRequest - /// and a DocumentLinkResolveRequest. - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentFormattingParams { - /// The document to format. - pub text_document: TextDocumentIdentifier, - - /// The format options. - pub options: FormattingOptions, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -/// Value-object describing what options formatting should use. -#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct FormattingOptions { - /// Size of a tab in spaces. - pub tab_size: u64, - - /// Prefer spaces over tabs. - pub insert_spaces: bool, - - /// Signature for further properties. - #[serde(flatten)] - pub properties: HashMap, - - /// Trim trailing whitespaces on a line. - #[serde(skip_serializing_if = "Option::is_none")] - pub trim_trailing_whitespace: Option, - - /// Insert a newline character at the end of the file if one does not exist. - #[serde(skip_serializing_if = "Option::is_none")] - pub insert_final_newline: Option, - - /// Trim all newlines after the final newline at the end of the file. - #[serde(skip_serializing_if = "Option::is_none")] - pub trim_final_newlines: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum FormattingProperty { - Bool(bool), - Number(f64), - String(String), -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentRangeFormattingParams { - /// The document to format. - pub text_document: TextDocumentIdentifier, - - /// The range to format - pub range: Range, - - /// The format options - pub options: FormattingOptions, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentOnTypeFormattingParams { - /// Text Document and Position fields. - #[serde(flatten)] - pub text_document_position: TextDocumentPositionParams, - - /// The character that has been typed. - pub ch: String, - - /// The format options. - pub options: FormattingOptions, -} - -/// Extends TextDocumentRegistrationOptions -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentOnTypeFormattingRegistrationOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, - - /// A character on which formatting should be triggered, like `}`. - pub first_trigger_character: String, - - /// More trigger characters. - #[serde(skip_serializing_if = "Option::is_none")] - pub more_trigger_character: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameParams { - /// Text Document and Position fields - #[serde(flatten)] - pub text_document_position: TextDocumentPositionParams, - - /// The new name of the symbol. If the given name is not valid the - /// request must return a [ResponseError](#ResponseError) with an - /// appropriate message set. - pub new_name: String, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum RenameProviderCapability { - Simple(bool), - Options(RenameOptions), -} - -impl From for RenameProviderCapability { - fn from(from: RenameOptions) -> Self { - Self::Options(from) - } -} - -impl From for RenameProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameOptions { - /// Renames should be checked and tested before being executed. - #[serde(skip_serializing_if = "Option::is_none")] - pub prepare_provider: Option, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameCapability { - /// Whether rename supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Client supports testing for validity of rename operations before execution. - #[serde(skip_serializing_if = "Option::is_none")] - pub prepare_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum PrepareRenameResponse { - Range(Range), - RangeWithPlaceholder { range: Range, placeholder: String }, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentLinkOptions { - /// Document links have a resolve provider as well. - #[serde(skip_serializing_if = "Option::is_none")] - pub resolve_provider: Option, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentColorParams { - /// The text document - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ColorInformation { - /// The range in the document where this color appears. - pub range: Range, - /// The actual color value for this color range. - pub color: Color, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Color { - /// The red component of this color in the range [0-1]. - pub red: f64, - /// The green component of this color in the range [0-1]. - pub green: f64, - /// The blue component of this color in the range [0-1]. - pub blue: f64, - /// The alpha component of this color in the range [0-1]. - pub alpha: f64, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ColorPresentationParams { - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The color information to request presentations for. - pub color: Color, - - /// The range where the color would be inserted. Serves as a context. - pub range: Range, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Default, Clone)] -#[serde(rename_all = "camelCase")] -pub struct ColorPresentation { - /// The label of this color presentation. It will be shown on the color - /// picker header. By default this is also the text that is inserted when selecting - /// this color presentation. - pub label: String, - - /// An [edit](#TextEdit) which is applied to a document when selecting - /// this presentation for the color. When `falsy` the [label](#ColorPresentation.label) - /// is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub text_edit: Option, - - /// An optional array of additional [text edits](#TextEdit) that are applied when - /// selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_text_edits: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct FoldingRangeParams { - /// The text document. - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum FoldingRangeProviderCapability { - Simple(bool), - FoldingProvider(FoldingProviderOptions), - Options(StaticTextDocumentColorProviderOptions), -} - -impl From for FoldingRangeProviderCapability { - fn from(from: StaticTextDocumentColorProviderOptions) -> Self { - Self::Options(from) - } -} - -impl From for FoldingRangeProviderCapability { - fn from(from: FoldingProviderOptions) -> Self { - Self::FoldingProvider(from) - } -} - -impl From for FoldingRangeProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct FoldingProviderOptions {} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct FoldingRangeCapability { - /// Whether implementation supports dynamic registration for folding range providers. If this is set to `true` - /// the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` - /// return value for the corresponding server capability as well. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The maximum number of folding ranges that the client prefers to receive per document. The value serves as a - /// hint, servers are free to follow the limit. - #[serde(skip_serializing_if = "Option::is_none")] - pub range_limit: Option, - /// If set, the client signals that it only supports folding complete lines. If set, client will - /// ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. - #[serde(skip_serializing_if = "Option::is_none")] - pub line_folding_only: Option, -} - -/// Represents a folding range. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct FoldingRange { - /// The zero-based line number from where the folded range starts. - pub start_line: u64, - - /// The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. - #[serde(skip_serializing_if = "Option::is_none")] - pub start_character: Option, - - /// The zero-based line number where the folded range ends. - pub end_line: u64, - - /// The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. - #[serde(skip_serializing_if = "Option::is_none")] - pub end_character: Option, - - /// Describes the kind of the folding range such as `comment' or 'region'. The kind - /// is used to categorize folding ranges and used by commands like 'Fold all comments'. See - /// [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct SelectionRangeOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct SelectionRangeRegistrationOptions { - #[serde(flatten)] - pub selection_range_options: SelectionRangeOptions, - - #[serde(flatten)] - pub registration_options: StaticTextDocumentRegistrationOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum SelectionRangeProviderCapability { - Simple(bool), - Options(SelectionRangeOptions), - RegistrationOptions(SelectionRangeRegistrationOptions), -} - -impl From for SelectionRangeProviderCapability { - fn from(from: SelectionRangeRegistrationOptions) -> Self { - Self::RegistrationOptions(from) - } -} - -impl From for SelectionRangeProviderCapability { - fn from(from: SelectionRangeOptions) -> Self { - Self::Options(from) - } -} - -impl From for SelectionRangeProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -/// A parameter literal used in selection range requests. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SelectionRangeParams { - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The positions inside the text document. - pub positions: Vec, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// Represents a selection range. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SelectionRange { - /// Range of the selection. - pub range: Range, - - /// The parent selection range containing this range. - #[serde(skip_serializing_if = "Option::is_none")] - pub parent: Option>, -} - -/// Enum of known range kinds -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "lowercase")] -pub enum FoldingRangeKind { - /// Folding range for a comment - Comment, - /// Folding range for a imports or includes - Imports, - /// Folding range for a region (e.g. `#region`) - Region, -} - -/// Describes the content type that a client supports in various -/// result literals like `Hover`, `ParameterInfo` or `CompletionItem`. -/// -/// Please note that `MarkupKinds` must not start with a `$`. This kinds -/// are reserved for internal usage. -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "lowercase")] -pub enum MarkupKind { - /// Plain text is supported as a content format - PlainText, - /// Markdown is supported as a content format - Markdown, -} - -/// A `MarkupContent` literal represents a string value which content is interpreted base on its -/// kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. -/// -/// If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. -/// See -/// -/// Here is an example how such a string can be constructed using JavaScript / TypeScript: -/// ```ignore -/// let markdown: MarkupContent = { -/// kind: MarkupKind::Markdown, -/// value: [ -/// "# Header", -/// "Some text", -/// "```typescript", -/// "someCode();", -/// "```" -/// ] -/// .join("\n"), -/// }; -/// ``` -/// -/// Please Note* that clients might sanitize the return markdown. A client could decide to -/// remove HTML from the markdown to avoid script execution. -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] -pub struct MarkupContent { - pub kind: MarkupKind, - pub value: String, -} - -pub type ProgressToken = NumberOrString; - -/// The progress notification is sent from the server to the client to ask -/// the client to indicate progress. -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct ProgressParams { - /// The progress token provided by the client. - pub token: ProgressToken, - - /// The progress data. - pub value: ProgressParamsValue, -} - -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(untagged)] -pub enum ProgressParamsValue { - WorkDone(WorkDoneProgress), -} - -/// The `window/workDoneProgress/create` request is sent from the server -/// to the clientto ask the client to create a work done progress. -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressCreateParams { - /// The token to be used to report progress. - pub token: ProgressToken, -} - -/// The `window/workDoneProgress/cancel` notification is sent from the client -/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressCancelParams { - /// The token to be used to report progress. - pub token: ProgressToken, -} - -/// Options to signal work done progress support in server capabilities. -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressOptions { - #[serde(skip_serializing_if = "Option::is_none")] - pub work_done_progress: Option, -} - -/// An optional token that a server can use to report work done progress -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressParams { - #[serde(skip_serializing_if = "Option::is_none")] - pub work_done_token: Option, -} - -#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressBegin { - /// Mandatory title of the progress operation. Used to briefly inform - /// about the kind of operation being performed. - /// Examples: "Indexing" or "Linking dependencies". - pub title: String, - - /// Controls if a cancel button should show to allow the user to cancel the - /// long running operation. Clients that don't support cancellation are allowed - /// to ignore the setting. - #[serde(skip_serializing_if = "Option::is_none")] - pub cancellable: Option, - - /// Optional, more detailed associated progress message. Contains - /// complementary information to the `title`. - /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". - /// If unset, the previous progress message (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, - - /// Optional progress percentage to display (value 100 is considered 100%). - /// If unset, the previous progress percentage (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub percentage: Option, -} - -#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressReport { - /// Controls if a cancel button should show to allow the user to cancel the - /// long running operation. Clients that don't support cancellation are allowed - /// to ignore the setting. - #[serde(skip_serializing_if = "Option::is_none")] - pub cancellable: Option, - - /// Optional, more detailed associated progress message. Contains - /// complementary information to the `title`. - /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". - /// If unset, the previous progress message (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, - - /// Optional progress percentage to display (value 100 is considered 100%). - /// If unset, the previous progress percentage (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub percentage: Option, -} - -#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressEnd { - /// Optional, more detailed associated progress message. Contains - /// complementary information to the `title`. - /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". - /// If unset, the previous progress message (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, -} - -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum WorkDoneProgress { - Begin(WorkDoneProgressBegin), - Report(WorkDoneProgressReport), - End(WorkDoneProgressEnd), -} - -/// A parameter literal used to pass a partial result token. -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct PartialResultParams { - #[serde(skip_serializing_if = "Option::is_none")] - pub partial_result_token: Option, -} - -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingClientCapability { - /// `true` if the client supports semantic highlighting support text documents. Otherwise, `false`. It is `false` by default. - pub semantic_highlighting: bool, -} - -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingServerCapability { - /// A "lookup table" of semantic highlighting [TextMate scopes](https://manual.macromates.com/en/language_grammars) - /// supported by the language server. If not defined or empty, then the server does not support the semantic highlighting - /// feature. Otherwise, clients should reuse this "lookup table" when receiving semantic highlighting notifications from - /// the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub scopes: Option>>, -} - -#[derive(Debug, Eq, PartialEq, Clone)] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingToken { - pub character: u32, - pub length: u16, - pub scope: u16, -} - -#[cfg(feature = "proposed")] -impl SemanticHighlightingToken { - /// Deserializes the tokens from a base64 encoded string - fn deserialize_tokens<'de, D>( - deserializer: D, - ) -> Result>, D::Error> - where - D: serde::Deserializer<'de>, - { - let opt_s = Option::::deserialize(deserializer)?; - - if let Some(s) = opt_s { - let bytes = base64::decode_config(s.as_str(), base64::STANDARD) - .map_err(|_| serde::de::Error::custom("Error parsing base64 string"))?; - let mut res = Vec::new(); - for chunk in bytes.chunks_exact(8) { - res.push(SemanticHighlightingToken { - character: u32::from_be_bytes(<[u8; 4]>::try_from(&chunk[0..4]).unwrap()), - length: u16::from_be_bytes(<[u8; 2]>::try_from(&chunk[4..6]).unwrap()), - scope: u16::from_be_bytes(<[u8; 2]>::try_from(&chunk[6..8]).unwrap()), - }); - } - Result::Ok(Some(res)) - } else { - Result::Ok(None) - } - } - - /// Serialize the tokens to a base64 encoded string - fn serialize_tokens( - tokens: &Option>, - serializer: S, - ) -> Result - where - S: serde::Serializer, - { - if let Some(tokens) = tokens { - let mut bytes = vec![]; - for token in tokens { - bytes.extend_from_slice(&token.character.to_be_bytes()); - bytes.extend_from_slice(&token.length.to_be_bytes()); - bytes.extend_from_slice(&token.scope.to_be_bytes()); - } - serializer.collect_str(&base64::display::Base64Display::with_config( - &bytes, - base64::STANDARD, - )) - } else { - serializer.serialize_none() - } - } -} - -/// Represents a semantic highlighting information that has to be applied on a specific line of the text document. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingInformation { - /// The zero-based line position in the text document. - pub line: i32, - - /// A base64 encoded string representing every single highlighted characters with its start position, length and the "lookup table" index of - /// of the semantic highlighting [TextMate scopes](https://manual.macromates.com/en/language_grammars). - /// If the `tokens` is empty or not defined, then no highlighted positions are available for the line. - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "SemanticHighlightingToken::deserialize_tokens", - serialize_with = "SemanticHighlightingToken::serialize_tokens" - )] - pub tokens: Option>, -} - -/// Parameters for the semantic highlighting (server-side) push notification. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingParams { - /// The text document that has to be decorated with the semantic highlighting information. - pub text_document: VersionedTextDocumentIdentifier, - - /// An array of semantic highlighting information. - pub lines: Vec, -} - -/// A set of predefined token types. This set is not fixed -/// and clients can specify additional token types via the -/// corresponding client capabilities. -/// -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] -#[cfg(feature = "proposed")] -pub struct SemanticTokenType(Cow<'static, str>); - -#[cfg(feature = "proposed")] -impl SemanticTokenType { - pub const COMMENT: SemanticTokenType = SemanticTokenType::new("comment"); - pub const KEYWORD: SemanticTokenType = SemanticTokenType::new("keyword"); - pub const STRING: SemanticTokenType = SemanticTokenType::new("string"); - pub const NUMBER: SemanticTokenType = SemanticTokenType::new("number"); - pub const REGEXP: SemanticTokenType = SemanticTokenType::new("regexp"); - pub const OPERATOR: SemanticTokenType = SemanticTokenType::new("operator"); - pub const NAMESPACE: SemanticTokenType = SemanticTokenType::new("namespace"); - pub const TYPE: SemanticTokenType = SemanticTokenType::new("type"); - pub const STRUCT: SemanticTokenType = SemanticTokenType::new("struct"); - pub const CLASS: SemanticTokenType = SemanticTokenType::new("class"); - pub const INTERFACE: SemanticTokenType = SemanticTokenType::new("interface"); - pub const ENUM: SemanticTokenType = SemanticTokenType::new("enum"); - pub const TYPE_PARAMETER: SemanticTokenType = SemanticTokenType::new("typeParameter"); - pub const FUNCTION: SemanticTokenType = SemanticTokenType::new("function"); - pub const MEMBER: SemanticTokenType = SemanticTokenType::new("member"); - pub const PROPERTY: SemanticTokenType = SemanticTokenType::new("property"); - pub const MACRO: SemanticTokenType = SemanticTokenType::new("macro"); - pub const VARIABLE: SemanticTokenType = SemanticTokenType::new("variable"); - pub const PARAMETER: SemanticTokenType = SemanticTokenType::new("parameter"); - pub const LABEL: SemanticTokenType = SemanticTokenType::new("label"); - - pub const fn new(tag: &'static str) -> Self { - SemanticTokenType(Cow::Borrowed(tag)) - } - - pub fn as_str(&self) -> &str { - &self.0 - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokenType { - fn from(from: String) -> Self { - SemanticTokenType(Cow::from(from)) - } -} -#[cfg(feature = "proposed")] -impl From<&'static str> for SemanticTokenType { - fn from(from: &'static str) -> Self { - SemanticTokenType::new(from) - } -} - -/// A set of predefined token modifiers. This set is not fixed -/// and clients can specify additional token types via the -/// corresponding client capabilities. -/// -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] -#[cfg(feature = "proposed")] -pub struct SemanticTokenModifier(Cow<'static, str>); - -#[cfg(feature = "proposed")] -impl SemanticTokenModifier { - pub const DOCUMENTATION: SemanticTokenModifier = SemanticTokenModifier::new("documentation"); - pub const DECLARATION: SemanticTokenModifier = SemanticTokenModifier::new("declaration"); - pub const DEFINITION: SemanticTokenModifier = SemanticTokenModifier::new("definition"); - pub const STATIC: SemanticTokenModifier = SemanticTokenModifier::new("static"); - pub const ABSTRACT: SemanticTokenModifier = SemanticTokenModifier::new("abstract"); - pub const DEPRECATED: SemanticTokenModifier = SemanticTokenModifier::new("deprecated"); - pub const READONLY: SemanticTokenModifier = SemanticTokenModifier::new("readonly"); - - pub const fn new(tag: &'static str) -> Self { - SemanticTokenModifier(Cow::Borrowed(tag)) - } - - pub fn as_str(&self) -> &str { - &self.0 - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokenModifier { - fn from(from: String) -> Self { - SemanticTokenModifier(Cow::from(from)) - } -} -#[cfg(feature = "proposed")] -impl From<&'static str> for SemanticTokenModifier { - fn from(from: &'static str) -> Self { - SemanticTokenModifier::new(from) - } -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensLegend { - /// The token types a server uses. - pub token_types: Vec, - - /// The token modifiers a server uses. - pub token_modifiers: Vec, -} - -/// The actual tokens. For a detailed description about how the data is -/// structured please see -/// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 -#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] -#[cfg(feature = "proposed")] -pub struct SemanticToken { - pub delta_line: u32, - pub delta_start: u32, - pub length: u32, - pub token_type: u32, - pub token_modifiers_bitset: u32, -} - -#[cfg(feature = "proposed")] -impl SemanticToken { - fn deserialize_tokens<'de, D>(deserializer: D) -> Result, D::Error> - where - D: serde::Deserializer<'de>, - { - let data = Vec::::deserialize(deserializer)?; - let chunks = data.chunks_exact(5); - - if !chunks.remainder().is_empty() { - return Result::Err(serde::de::Error::custom("Length is not divisible by 5")); - } - - Result::Ok( - chunks - .map(|chunk| SemanticToken { - delta_line: chunk[0], - delta_start: chunk[1], - length: chunk[2], - token_type: chunk[3], - token_modifiers_bitset: chunk[4], - }) - .collect(), - ) - } - - fn serialize_tokens(tokens: &[SemanticToken], serializer: S) -> Result - where - S: serde::Serializer, - { - let mut seq = serializer.serialize_seq(Some(tokens.len() * 5))?; - for token in tokens.iter() { - seq.serialize_element(&token.delta_line)?; - seq.serialize_element(&token.delta_start)?; - seq.serialize_element(&token.length)?; - seq.serialize_element(&token.token_type)?; - seq.serialize_element(&token.token_modifiers_bitset)?; - } - seq.end() - } - - fn deserialize_tokens_opt<'de, D>( - deserializer: D, - ) -> Result>, D::Error> - where - D: serde::Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(transparent)] - struct Wrapper { - #[serde(deserialize_with = "SemanticToken::deserialize_tokens")] - tokens: Vec, - } - - Ok(Option::::deserialize(deserializer)?.map(|wrapper| wrapper.tokens)) - } - - fn serialize_tokens_opt( - data: &Option>, - serializer: S, - ) -> Result - where - S: serde::Serializer, - { - #[derive(Serialize)] - #[serde(transparent)] - struct Wrapper { - #[serde(serialize_with = "SemanticToken::serialize_tokens")] - tokens: Vec, - } - - let opt = data.as_ref().map(|t| Wrapper { tokens: t.to_vec() }); - - opt.serialize(serializer) - } -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokens { - /// An optional result id. If provided and clients support delta updating - /// the client will include the result id in the next semantic token request. - /// A server can then instead of computing all sematic tokens again simply - /// send a delta. - #[serde(skip_serializing_if = "Option::is_none")] - pub result_id: Option, - - /// The actual tokens. For a detailed description about how the data is - /// structured please see - /// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 - #[serde( - deserialize_with = "SemanticToken::deserialize_tokens", - serialize_with = "SemanticToken::serialize_tokens" - )] - pub data: Vec, -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensPartialResult { - #[serde( - deserialize_with = "SemanticToken::deserialize_tokens", - serialize_with = "SemanticToken::serialize_tokens" - )] - pub data: Vec, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensResult { - Tokens(SemanticTokens), - Partial(SemanticTokensPartialResult), -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensResult { - fn from(from: SemanticTokens) -> Self { - SemanticTokensResult::Tokens(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensResult { - fn from(from: SemanticTokensPartialResult) -> Self { - SemanticTokensResult::Partial(from) - } -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensEdit { - pub start: u32, - pub delete_count: u32, - - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "SemanticToken::deserialize_tokens_opt", - serialize_with = "SemanticToken::serialize_tokens_opt" - )] - pub data: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensEditResult { - Tokens(SemanticTokens), - TokensEdits(SemanticTokensEdits), - PartialTokens(SemanticTokensPartialResult), - PartialTokensEdit(SemanticTokensEditsPartialResult), -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensEditResult { - fn from(from: SemanticTokens) -> Self { - SemanticTokensEditResult::Tokens(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensEditResult { - fn from(from: SemanticTokensEdits) -> Self { - SemanticTokensEditResult::TokensEdits(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensEditResult { - fn from(from: SemanticTokensPartialResult) -> Self { - SemanticTokensEditResult::PartialTokens(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensEditResult { - fn from(from: SemanticTokensEditsPartialResult) -> Self { - SemanticTokensEditResult::PartialTokensEdit(from) - } -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensEdits { - #[serde(skip_serializing_if = "Option::is_none")] - pub result_id: Option, - /// For a detailed description how these edits are structured pls see - /// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L131 - pub edits: Vec, -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensEditsPartialResult { - pub edits: Vec, -} - -/// Capabilities specific to the `textDocument/semanticTokens` -/// -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensClientCapabilities { - /// Whether implementation supports dynamic registration. If this is set to `true` - /// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - /// return value for the corresponding server capability as well. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The token types known by the client. - pub token_types: Vec, - - /// The token modifiers known by the client. - pub token_modifiers: Vec, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensDocumentProvider { - Bool(bool), - - /// The server supports deltas for full documents. - Edits { - #[serde(skip_serializing_if = "Option::is_none")] - edits: Option, - }, -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, - - /// The legend used by the server - pub legend: SemanticTokensLegend, - - /// Server supports providing semantic tokens for a sepcific range - /// of a document. - #[serde(skip_serializing_if = "Option::is_none")] - pub range_provider: Option, - - /// Server supports providing semantic tokens for a full document. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_provider: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, - - #[serde(flatten)] - pub semantic_tokens_options: SemanticTokensOptions, - - #[serde(flatten)] - pub static_registration_options: StaticRegistrationOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensServerCapabilities { - SemanticTokensOptions(SemanticTokensOptions), - SemanticTokensRegistrationOptions(SemanticTokensRegistrationOptions), -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensServerCapabilities { - fn from(from: SemanticTokensOptions) -> Self { - SemanticTokensServerCapabilities::SemanticTokensOptions(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensServerCapabilities { - fn from(from: SemanticTokensRegistrationOptions) -> Self { - SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensParams { - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - /// The text document. - pub text_document: TextDocumentIdentifier, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensEditsParams { - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The previous result id. - pub previous_result_id: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensRangeParams { - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The range the semantic tokens are requested for. - pub range: Range, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensRangeResult { - Tokens(SemanticTokens), - Partial(SemanticTokensPartialResult), -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensRangeResult { - fn from(tokens: SemanticTokens) -> Self { - SemanticTokensRangeResult::Tokens(tokens) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensRangeResult { - fn from(partial: SemanticTokensPartialResult) -> Self { - SemanticTokensRangeResult::Partial(partial) - } -} - -/// Symbol tags are extra annotations that tweak the rendering of a symbol. -/// Since 3.15 -#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -#[cfg(feature = "proposed")] -pub enum SymbolTag { - /// Render a symbol as obsolete, usually using a strike-out. - Deprecated = 1, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum CallHierarchyServerCapability { - Simple(bool), - Options(CallHierarchyOptions), -} - -#[cfg(feature = "proposed")] -impl From for CallHierarchyServerCapability { - fn from(from: CallHierarchyOptions) -> Self { - Self::Options(from) - } -} - -#[cfg(feature = "proposed")] -impl From for CallHierarchyServerCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyPrepareParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyItem { - /// The name of this item. - pub name: String, - - /// The kind of this item. - pub kind: SymbolKind, - - /// Tags for this item. - #[serde(skip_serializing_if = "Option::is_none")] - pub tags: Option>, - - /// More detail for this item, e.g. the signature of a function. - #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - - /// The resource identifier of this item. - pub uri: Url, - - /// The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. - pub range: Range, - - /// The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. - /// Must be contained by the [`range`](#CallHierarchyItem.range). - pub selection_range: Range, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyIncomingCallsParams { - pub item: CallHierarchyItem, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// Represents an incoming call, e.g. a caller of a method or constructor. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyIncomingCall { - /// The item that makes the call. - pub from: CallHierarchyItem, - - /// The range at which at which the calls appears. This is relative to the caller - /// denoted by [`this.from`](#CallHierarchyIncomingCall.from). - pub from_ranges: Vec, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyOutgoingCallsParams { - pub item: CallHierarchyItem, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyOutgoingCall { - /// The item that is called. - pub to: CallHierarchyItem, - - /// The range at which this item is called. This is the range relative to the caller, e.g the item - /// passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls) - /// and not [`this.to`](#CallHierarchyOutgoingCall.to). - pub from_ranges: Vec, -} - -#[cfg(test)] -mod tests { - use super::*; - use serde::{Deserialize, Serialize}; - - fn test_serialization(ms: &SER, expected: &str) - where - SER: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, - { - let json_str = serde_json::to_string(ms).unwrap(); - assert_eq!(&json_str, expected); - let deserialized: SER = serde_json::from_str(&json_str).unwrap(); - assert_eq!(&deserialized, ms); - } - - fn test_deserialization(json: &str, expected: &T) - where - T: for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, - { - let value = serde_json::from_str::(json).unwrap(); - assert_eq!(&value, expected); - } - - #[test] - fn number_or_string() { - test_serialization(&NumberOrString::Number(123), r#"123"#); - - test_serialization(&NumberOrString::String("abcd".into()), r#""abcd""#); - } - - #[test] - fn marked_string() { - test_serialization(&MarkedString::from_markdown("xxx".into()), r#""xxx""#); - - test_serialization( - &MarkedString::from_language_code("lang".into(), "code".into()), - r#"{"language":"lang","value":"code"}"#, - ); - } - - #[test] - fn language_string() { - test_serialization( - &LanguageString { - language: "LL".into(), - value: "VV".into(), - }, - r#"{"language":"LL","value":"VV"}"#, - ); - } - - #[test] - fn workspace_edit() { - test_serialization( - &WorkspaceEdit { - changes: Some(vec![].into_iter().collect()), - document_changes: None, - }, - r#"{"changes":{}}"#, - ); - - test_serialization( - &WorkspaceEdit { - changes: None, - document_changes: None, - }, - r#"{}"#, - ); - - test_serialization( - &WorkspaceEdit { - changes: Some( - vec![(Url::parse("file://test").unwrap(), vec![])] - .into_iter() - .collect(), - ), - document_changes: None, - }, - r#"{"changes":{"file://test/":[]}}"#, - ); - } - - #[test] - fn formatting_options() { - test_serialization( - &FormattingOptions { - tab_size: 123, - insert_spaces: true, - properties: HashMap::new(), - trim_trailing_whitespace: None, - insert_final_newline: None, - trim_final_newlines: None, - }, - r#"{"tabSize":123,"insertSpaces":true}"#, - ); - - test_serialization( - &FormattingOptions { - tab_size: 123, - insert_spaces: true, - properties: vec![("prop".to_string(), FormattingProperty::Number(1.0))] - .into_iter() - .collect(), - trim_trailing_whitespace: None, - insert_final_newline: None, - trim_final_newlines: None, - }, - r#"{"tabSize":123,"insertSpaces":true,"prop":1.0}"#, - ); - } - - #[test] - fn root_uri_can_be_missing() { - serde_json::from_str::(r#"{ "capabilities": {} }"#).unwrap(); - } - - #[test] - fn test_watch_kind() { - test_serialization(&WatchKind::Create, "1"); - test_serialization(&(WatchKind::Create | WatchKind::Change), "3"); - test_serialization( - &(WatchKind::Create | WatchKind::Change | WatchKind::Delete), - "7", - ); - } - - #[test] - fn test_resource_operation_kind() { - test_serialization( - &vec![ - ResourceOperationKind::Create, - ResourceOperationKind::Rename, - ResourceOperationKind::Delete, - ], - r#"["create","rename","delete"]"#, - ); - } - - #[test] - fn test_code_action_response() { - test_serialization( - &vec![ - CodeActionOrCommand::Command(Command { - title: "title".to_string(), - command: "command".to_string(), - arguments: None, - }), - CodeActionOrCommand::CodeAction(CodeAction { - title: "title".to_string(), - kind: Some(CodeActionKind::QUICKFIX), - command: None, - diagnostics: None, - edit: None, - is_preferred: None, - }), - ], - r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#, - ) - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_highlighting_information_serialization() { - test_serialization( - &SemanticHighlightingInformation { - line: 10, - tokens: Some(vec![ - SemanticHighlightingToken { - character: 0x00000001, - length: 0x0002, - scope: 0x0003, - }, - SemanticHighlightingToken { - character: 0x00112222, - length: 0x0FF0, - scope: 0x0202, - }, - ]), - }, - r#"{"line":10,"tokens":"AAAAAQACAAMAESIiD/ACAg=="}"#, - ); - - test_serialization( - &SemanticHighlightingInformation { - line: 22, - tokens: None, - }, - r#"{"line":22}"#, - ); - } - - #[test] - fn test_tag_support_deserialization() { - let mut empty = CompletionItemCapability::default(); - empty.tag_support = None; - - test_deserialization(r#"{}"#, &empty); - test_deserialization(r#"{"tagSupport": false}"#, &empty); - - let mut t = CompletionItemCapability::default(); - t.tag_support = Some(TagSupport { value_set: vec![] }); - test_deserialization(r#"{"tagSupport": true}"#, &t); - - let mut t = CompletionItemCapability::default(); - t.tag_support = Some(TagSupport { - value_set: vec![CompletionItemTag::Deprecated], - }); - test_deserialization(r#"{"tagSupport": {"valueSet": [1]}}"#, &t); - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_tokens_support_serialization() { - test_serialization( - &SemanticTokens { - result_id: None, - data: vec![], - }, - r#"{"data":[]}"#, - ); - - test_serialization( - &SemanticTokens { - result_id: None, - data: vec![SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }], - }, - r#"{"data":[2,5,3,0,3]}"#, - ); - - test_serialization( - &SemanticTokens { - result_id: None, - data: vec![ - SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }, - SemanticToken { - delta_line: 0, - delta_start: 5, - length: 4, - token_type: 1, - token_modifiers_bitset: 0, - }, - ], - }, - r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, - ); - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_tokens_support_deserialization() { - test_deserialization( - r#"{"data":[]}"#, - &SemanticTokens { - result_id: None, - data: vec![], - }, - ); - - test_deserialization( - r#"{"data":[2,5,3,0,3]}"#, - &SemanticTokens { - result_id: None, - data: vec![SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }], - }, - ); - - test_deserialization( - r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, - &SemanticTokens { - result_id: None, - data: vec![ - SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }, - SemanticToken { - delta_line: 0, - delta_start: 5, - length: 4, - token_type: 1, - token_modifiers_bitset: 0, - }, - ], - }, - ); - } - - #[cfg(feature = "proposed")] - #[test] - #[should_panic] - fn test_semantic_tokens_support_deserialization_err() { - test_deserialization( - r#"{"data":[1]}"#, - &SemanticTokens { - result_id: None, - data: vec![], - }, - ); - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_tokens_edit_support_deserialization() { - test_deserialization( - r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, - &SemanticTokensEdit { - start: 0, - delete_count: 1, - data: Some(vec![ - SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }, - SemanticToken { - delta_line: 0, - delta_start: 5, - length: 4, - token_type: 1, - token_modifiers_bitset: 0, - }, - ]), - }, - ); - - test_deserialization( - r#"{"start":0,"deleteCount":1}"#, - &SemanticTokensEdit { - start: 0, - delete_count: 1, - data: None, - }, - ); - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_tokens_edit_support_serialization() { - test_serialization( - &SemanticTokensEdit { - start: 0, - delete_count: 1, - data: Some(vec![ - SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }, - SemanticToken { - delta_line: 0, - delta_start: 5, - length: 4, - token_type: 1, - token_modifiers_bitset: 0, - }, - ]), - }, - r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, - ); - - test_serialization( - &SemanticTokensEdit { - start: 0, - delete_count: 1, - data: None, - }, - r#"{"start":0,"deleteCount":1}"#, - ); - } -} +/*! + +Language Server Protocol types for Rust. + +Based on: + +This library uses the URL crate for parsing URIs. Note that there is +some confusion on the meaning of URLs vs URIs: +. According to that +information, on the classical sense of "URLs", "URLs" are a subset of +URIs, But on the modern/new meaning of URLs, they are the same as +URIs. The important take-away aspect is that the URL crate should be +able to parse any URI, such as `urn:isbn:0451450523`. + + +*/ +#![allow(non_upper_case_globals)] +#![forbid(unsafe_code)] + +#[macro_use] +extern crate bitflags; + +use serde::{Deserialize, Serialize}; +use serde_json; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +pub use url::Url; + +use std::borrow::Cow; + +#[cfg(feature = "proposed")] +use std::convert::TryFrom; + +use std::collections::HashMap; + +#[cfg(feature = "proposed")] +use base64; +use serde::de; +use serde::de::Error as Error_; +use serde_json::Value; + +#[cfg(feature = "proposed")] +use serde::ser::SerializeSeq; + +pub mod notification; +pub mod request; + +/* ----------------- Auxiliary types ----------------- */ + +#[derive(Debug, Eq, Hash, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum NumberOrString { + Number(u64), + String(String), +} + +/* ----------------- Cancel support ----------------- */ + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct CancelParams { + /// The request id to cancel. + pub id: NumberOrString, +} + +/* ----------------- Basic JSON Structures ----------------- */ + +/// Position in a text document expressed as zero-based line and character offset. +/// A position is between two characters like an 'insert' cursor in a editor. +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Default, Deserialize, Serialize)] +pub struct Position { + /// Line position in a document (zero-based). + pub line: u64, + /// Character offset on a line in a document (zero-based). + pub character: u64, +} + +impl Position { + pub fn new(line: u64, character: u64) -> Position { + Position { line, character } + } +} + +/// A range in a text document expressed as (zero-based) start and end positions. +/// A range is comparable to a selection in an editor. Therefore the end position is exclusive. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Deserialize, Serialize)] +pub struct Range { + /// The range's start position. + pub start: Position, + /// The range's end position. + pub end: Position, +} + +impl Range { + pub fn new(start: Position, end: Position) -> Range { + Range { start, end } + } +} + +/// Represents a location inside a resource, such as a line inside a text file. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct Location { + pub uri: Url, + pub range: Range, +} + +impl Location { + pub fn new(uri: Url, range: Range) -> Location { + Location { uri, range } + } +} + +/// Represents a link between a source and a target location. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LocationLink { + /// Span of the origin of this link. + /// + /// Used as the underlined span for mouse interaction. Defaults to the word range at + /// the mouse position. + #[serde(skip_serializing_if = "Option::is_none")] + pub origin_selection_range: Option, + + /// The target resource identifier of this link. + pub target_uri: Url, + + /// The full target range of this link. + pub target_range: Range, + + /// The span of this link. + pub target_selection_range: Range, +} + +/// Represents a diagnostic, such as a compiler error or warning. +/// Diagnostic objects are only valid in the scope of a resource. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Diagnostic { + /// The range at which the message applies. + pub range: Range, + + /// The diagnostic's severity. Can be omitted. If omitted it is up to the + /// client to interpret diagnostics as error, warning, info or hint. + #[serde(skip_serializing_if = "Option::is_none")] + pub severity: Option, + + /// The diagnostic's code. Can be omitted. + #[serde(skip_serializing_if = "Option::is_none")] + pub code: Option, + // code?: number | string; + /// A human-readable string describing the source of this + /// diagnostic, e.g. 'typescript' or 'super lint'. + #[serde(skip_serializing_if = "Option::is_none")] + pub source: Option, + + /// The diagnostic's message. + pub message: String, + + /// An array of related diagnostic information, e.g. when symbol-names within + /// a scope collide all definitions can be marked via this property. + #[serde(skip_serializing_if = "Option::is_none")] + pub related_information: Option>, + + /// Additional metadata about the diagnostic. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, +} + +impl Diagnostic { + pub fn new( + range: Range, + severity: Option, + code: Option, + source: Option, + message: String, + related_information: Option>, + tags: Option>, + ) -> Diagnostic { + Diagnostic { + range, + severity, + code, + source, + message, + related_information, + tags, + } + } + + pub fn new_simple(range: Range, message: String) -> Diagnostic { + Self::new(range, None, None, None, message, None, None) + } + + pub fn new_with_code_number( + range: Range, + severity: DiagnosticSeverity, + code_number: u64, + source: Option, + message: String, + ) -> Diagnostic { + let code = Some(NumberOrString::Number(code_number)); + Self::new(range, Some(severity), code, source, message, None, None) + } +} + +/// The protocol currently supports the following diagnostic severities: +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum DiagnosticSeverity { + /// Reports an error. + Error = 1, + /// Reports a warning. + Warning = 2, + /// Reports an information. + Information = 3, + /// Reports a hint. + Hint = 4, +} + +/// Represents a related message and source code location for a diagnostic. This +/// should be used to point to code locations that cause or related to a +/// diagnostics, e.g when duplicating a symbol in a scope. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DiagnosticRelatedInformation { + /// The location of this related diagnostic information. + pub location: Location, + + /// The message of this related diagnostic information. + pub message: String, +} + +/// The diagnostic tags. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum DiagnosticTag { + /// Unused or unnecessary code. + /// Clients are allowed to render diagnostics with this tag faded out instead of having + /// an error squiggle. + Unnecessary = 1, + + /// Deprecated or obsolete code. + /// Clients are allowed to rendered diagnostics with this tag strike through. + Deprecated = 2, +} + +/// Represents a reference to a command. Provides a title which will be used to represent a command in the UI. +/// Commands are identitifed using a string identifier and the protocol currently doesn't specify a set of +/// well known commands. So executing a command requires some tool extension code. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct Command { + /// Title of the command, like `save`. + pub title: String, + /// The identifier of the actual command handler. + pub command: String, + /// Arguments that the command handler should be + /// invoked with. + #[serde(skip_serializing_if = "Option::is_none")] + pub arguments: Option>, +} + +impl Command { + pub fn new(title: String, command: String, arguments: Option>) -> Command { + Command { + title, + command, + arguments, + } + } +} + +/// A textual edit applicable to a text document. +/// +/// If n `TextEdit`s are applied to a text document all text edits describe changes to the initial document version. +/// Execution wise text edits should applied from the bottom to the top of the text document. Overlapping text edits +/// are not supported. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextEdit { + /// The range of the text document to be manipulated. To insert + /// text into a document create a range where start === end. + pub range: Range, + /// The string to be inserted. For delete operations use an + /// empty string. + pub new_text: String, +} + +impl TextEdit { + pub fn new(range: Range, new_text: String) -> TextEdit { + TextEdit { range, new_text } + } +} + +/// Describes textual changes on a single text document. The text document is referred to as a +/// `VersionedTextDocumentIdentifier` to allow clients to check the text document version before an +/// edit is applied. A `TextDocumentEdit` describes all changes on a version Si and after they are +/// applied move the document to version Si+1. So the creator of a `TextDocumentEdit` doesn't need to +/// sort the array or do any kind of ordering. However the edits must be non overlapping. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentEdit { + /// The text document to change. + pub text_document: VersionedTextDocumentIdentifier, + + /// The edits to be applied. + pub edits: Vec, +} + +/// A special text edit to provide an insert and a replace operation. +/// +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct InsertReplaceEdit { + /// The string to be inserted. + pub new_text: String, + + /// The range if the insert is requested + pub insert: Range, + + /// The range if the replace is requested. + pub replace: Range, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum CompletionTextEdit { + Edit(TextEdit), + #[cfg(feature = "proposed")] + InsertAndReplace(InsertReplaceEdit), +} + +impl From for CompletionTextEdit { + fn from(edit: TextEdit) -> Self { + CompletionTextEdit::Edit(edit) + } +} + +#[cfg(feature = "proposed")] +impl From for CompletionTextEdit { + fn from(edit: InsertReplaceEdit) -> Self { + CompletionTextEdit::InsertAndReplace(edit) + } +} + +/// Options to create a file. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateFileOptions { + /// Overwrite existing file. Overwrite wins over `ignoreIfExists` + #[serde(skip_serializing_if = "Option::is_none")] + pub overwrite: Option, + /// Ignore if exists. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_if_exists: Option, +} + +/// Create file operation +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateFile { + /// The resource to create. + pub uri: Url, + /// Additional options + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, +} + +/// Rename file options +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameFileOptions { + /// Overwrite target if existing. Overwrite wins over `ignoreIfExists` + #[serde(skip_serializing_if = "Option::is_none")] + pub overwrite: Option, + /// Ignores if target exists. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_if_exists: Option, +} + +/// Rename file operation +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameFile { + /// The old (existing) location. + pub old_uri: Url, + /// The new location. + pub new_uri: Url, + /// Rename options. + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, +} + +/// Delete file options +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DeleteFileOptions { + /// Delete the content recursively if a folder is denoted. + #[serde(skip_serializing_if = "Option::is_none")] + pub recursive: Option, + /// Ignore the operation if the file doesn't exist. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_if_not_exists: Option, +} + +/// Delete file operation +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DeleteFile { + /// The file to delete. + pub uri: Url, + /// Delete options. + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, +} + +/// A workspace edit represents changes to many resources managed in the workspace. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceEdit { + /// Holds changes to existing resources. + #[serde(with = "url_map")] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub changes: Option>>, // changes?: { [uri: string]: TextEdit[]; }; + + /// Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes + /// are either an array of `TextDocumentEdit`s to express changes to n different text documents + /// where each text document edit addresses a specific version of a text document. Or it can contain + /// above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. + /// + /// Whether a client supports versioned document edits is expressed via + /// `workspace.workspaceEdit.documentChanges` client capability. + /// + /// If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then + /// only plain `TextEdit`s using the `changes` property are supported. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_changes: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum DocumentChanges { + Edits(Vec), + Operations(Vec), +} + +// TODO: Once https://github.com/serde-rs/serde/issues/912 is solved +// we can remove ResourceOp and switch to the following implementation +// of DocumentChangeOperation: +// +// #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +// #[serde(tag = "kind", rename_all="lowercase" )] +// pub enum DocumentChangeOperation { +// Create(CreateFile), +// Rename(RenameFile), +// Delete(DeleteFile), +// +// #[serde(other)] +// Edit(TextDocumentEdit), +// } + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged, rename_all = "lowercase")] +pub enum DocumentChangeOperation { + Op(ResourceOp), + Edit(TextDocumentEdit), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum ResourceOp { + Create(CreateFile), + Rename(RenameFile), + Delete(DeleteFile), +} + +#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ConfigurationParams { + pub items: Vec, +} + +#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ConfigurationItem { + /// The scope to get the configuration section for. + #[serde(skip_serializing_if = "Option::is_none")] + pub scope_uri: Option, + + ///The configuration section asked for. + #[serde(skip_serializing_if = "Option::is_none")] + pub section: Option, +} + +mod url_map { + use super::*; + + use std::fmt; + + pub fn deserialize<'de, D>( + deserializer: D, + ) -> Result>>, D::Error> + where + D: serde::Deserializer<'de>, + { + struct UrlMapVisitor; + impl<'de> de::Visitor<'de> for UrlMapVisitor { + type Value = HashMap>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("map") + } + + fn visit_map(self, mut visitor: M) -> Result + where + M: de::MapAccess<'de>, + { + let mut values = HashMap::with_capacity(visitor.size_hint().unwrap_or(0)); + + // While there are entries remaining in the input, add them + // into our map. + while let Some((key, value)) = visitor.next_entry::()? { + values.insert(key, value); + } + + Ok(values) + } + } + + struct OptionUrlMapVisitor; + impl<'de> de::Visitor<'de> for OptionUrlMapVisitor { + type Value = Option>>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("option") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: serde::de::Error, + { + Ok(None) + } + + #[inline] + fn visit_none(self) -> Result + where + E: serde::de::Error, + { + Ok(None) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_map(UrlMapVisitor).map(Some) + } + } + + // Instantiate our Visitor and ask the Deserializer to drive + // it over the input data, resulting in an instance of MyMap. + deserializer.deserialize_option(OptionUrlMapVisitor) + } + + pub fn serialize( + changes: &Option>>, + serializer: S, + ) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeMap; + + match *changes { + Some(ref changes) => { + let mut map = serializer.serialize_map(Some(changes.len()))?; + for (k, v) in changes { + map.serialize_entry(k.as_str(), v)?; + } + map.end() + } + None => serializer.serialize_none(), + } + } +} + +impl WorkspaceEdit { + pub fn new(changes: HashMap>) -> WorkspaceEdit { + WorkspaceEdit { + changes: Some(changes), + document_changes: None, + } + } +} + +/// Text documents are identified using a URI. On the protocol level, URIs are passed as strings. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct TextDocumentIdentifier { + // !!!!!! Note: + // In the spec VersionedTextDocumentIdentifier extends TextDocumentIdentifier + // This modelled by "mixing-in" TextDocumentIdentifier in VersionedTextDocumentIdentifier, + // so any changes to this type must be effected in the sub-type as well. + /// The text document's URI. + pub uri: Url, +} + +impl TextDocumentIdentifier { + pub fn new(uri: Url) -> TextDocumentIdentifier { + TextDocumentIdentifier { uri } + } +} + +/// An item to transfer a text document from the client to the server. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentItem { + /// The text document's URI. + pub uri: Url, + + /// The text document's language identifier. + pub language_id: String, + + /// The version number of this document (it will strictly increase after each + /// change, including undo/redo). + pub version: i64, + + /// The content of the opened text document. + pub text: String, +} + +impl TextDocumentItem { + pub fn new(uri: Url, language_id: String, version: i64, text: String) -> TextDocumentItem { + TextDocumentItem { + uri, + language_id, + version, + text, + } + } +} + +/// An identifier to denote a specific version of a text document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct VersionedTextDocumentIdentifier { + // This field was "mixed-in" from TextDocumentIdentifier + /// The text document's URI. + pub uri: Url, + + /// The version number of this document. + pub version: Option, +} + +impl VersionedTextDocumentIdentifier { + pub fn new(uri: Url, version: i64) -> VersionedTextDocumentIdentifier { + VersionedTextDocumentIdentifier { + uri, + version: Some(version), + } + } +} + +/// A parameter literal used in requests to pass a text document and a position inside that document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentPositionParams { + // !!!!!! Note: + // In the spec ReferenceParams extends TextDocumentPositionParams + // This modelled by "mixing-in" TextDocumentPositionParams in ReferenceParams, + // so any changes to this type must be effected in sub-type as well. + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The position inside the text document. + pub position: Position, +} + +impl TextDocumentPositionParams { + pub fn new( + text_document: TextDocumentIdentifier, + position: Position, + ) -> TextDocumentPositionParams { + TextDocumentPositionParams { + text_document, + position, + } + } +} + +/// A document filter denotes a document through properties like language, schema or pattern. +/// Examples are a filter that applies to TypeScript files on disk or a filter the applies to JSON +/// files with name package.json: +/// +/// { language: 'typescript', scheme: 'file' } +/// { language: 'json', pattern: '**/package.json' } +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DocumentFilter { + /// A language id, like `typescript`. + #[serde(skip_serializing_if = "Option::is_none")] + pub language: Option, + + /// A Uri [scheme](#Uri.scheme), like `file` or `untitled`. + #[serde(skip_serializing_if = "Option::is_none")] + pub scheme: Option, + + /// A glob pattern, like `*.{ts,js}`. + #[serde(skip_serializing_if = "Option::is_none")] + pub pattern: Option, +} + +/// A document selector is the combination of one or many document filters. +pub type DocumentSelector = Vec; + +// ========================= Actual Protocol ========================= + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InitializeParams { + /// The process Id of the parent process that started + /// the server. Is null if the process has not been started by another process. + /// If the parent process is not alive then the server should exit (see exit notification) its process. + pub process_id: Option, + + /// The rootPath of the workspace. Is null + /// if no folder is open. + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use `root_uri` instead when possible")] + pub root_path: Option, + + /// The rootUri of the workspace. Is null if no + /// folder is open. If both `rootPath` and `rootUri` are set + /// `rootUri` wins. + #[serde(default)] + pub root_uri: Option, + + /// User provided initialization options. + #[serde(skip_serializing_if = "Option::is_none")] + pub initialization_options: Option, + + /// The capabilities provided by the client (editor) + pub capabilities: ClientCapabilities, + + /// The initial trace setting. If omitted trace is disabled ('off'). + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub trace: Option, + + /// The workspace folders configured in the client when the server starts. + /// This property is only available if the client supports workspace folders. + /// It can be `null` if the client supports workspace folders but none are + /// configured. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_folders: Option>, + + /// Information about the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub client_info: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct ClientInfo { + /// The name of the client as defined by the client. + pub name: String, + /// The client's version as defined by the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +#[derive(Debug, PartialEq, Clone, Copy, Deserialize, Serialize)] +pub struct InitializedParams {} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +pub enum TraceOption { + #[serde(rename = "off")] + Off, + #[serde(rename = "messages")] + Messages, + #[serde(rename = "verbose")] + Verbose, +} + +impl Default for TraceOption { + fn default() -> TraceOption { + TraceOption::Off + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct GenericRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub options: GenericOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct GenericOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct GenericParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GenericCapability { + /// This capability supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GotoCapability { + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports additional metadata in the form of definition links. + pub link_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceEditCapability { + /// The client supports versioned document changes in `WorkspaceEdit`s + #[serde(skip_serializing_if = "Option::is_none")] + pub document_changes: Option, + + /// The resource operations the client supports. Clients should at least + /// support 'create', 'rename' and 'delete' files and folders. + #[serde(skip_serializing_if = "Option::is_none")] + pub resource_operations: Option>, + + /// The failure handling strategy of a client if applying the workspace edit + /// failes. + #[serde(skip_serializing_if = "Option::is_none")] + pub failure_handling: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceCapability { + /// The server supports workspace folder. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_folders: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFolderCapability { + #[serde(skip_serializing_if = "Option::is_none")] + pub supported: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub change_notifications: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum WorkspaceFolderCapabilityChangeNotifications { + Bool(bool), + Id(String), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFolder { + /// The associated URI for this workspace folder. + pub uri: Url, + /// The name of the workspace folder. Defaults to the uri's basename. + pub name: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidChangeWorkspaceFoldersParams { + /// The actual workspace folder change event. + pub event: WorkspaceFoldersChangeEvent, +} + +/// The workspace folder change event. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFoldersChangeEvent { + /// The array of added workspace folders + pub added: Vec, + + /// The array of the removed workspace folders + pub removed: Vec, +} + +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] +#[serde(rename_all = "lowercase")] +pub enum ResourceOperationKind { + Create, + Rename, + Delete, +} + +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] +#[serde(rename_all = "camelCase")] +pub enum FailureHandlingKind { + Abort, + Transactional, + TextOnlyTransactional, + Undo, +} + +/// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SymbolKindCapability { + /// The symbol kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + /// + /// If this property is not present the client only supports + /// the symbol kinds from `File` to `Array` as defined in + /// the initial version of the protocol. + pub value_set: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceSymbolClientCapabilities { + /// This capability supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol_kind: Option, + + /// The client supports tags on `SymbolInformation`. + /// Clients supporting tags have to handle unknown tags gracefully. + /// + /// @since 3.16.0 + /// + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + #[cfg(feature = "proposed")] + pub tag_support: Option>, +} + +/// Workspace specific client capabilities. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceClientCapabilities { + /// The client supports applying batch edits to the workspace by supporting + /// the request 'workspace/applyEdit' + #[serde(skip_serializing_if = "Option::is_none")] + pub apply_edit: Option, + + /// Capabilities specific to `WorkspaceEdit`s + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_edit: Option, + + /// Capabilities specific to the `workspace/didChangeConfiguration` notification. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_change_configuration: Option, + + /// Capabilities specific to the `workspace/didChangeWatchedFiles` notification. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_change_watched_files: Option, + + /// Capabilities specific to the `workspace/symbol` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol: Option, + + /// Capabilities specific to the `workspace/executeCommand` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub execute_command: Option, + + /// The client has support for workspace folders. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_folders: Option, + + /// The client supports `workspace/configuration` requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub configuration: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SynchronizationCapability { + /// Whether text document synchronization supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports sending will save notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save: Option, + + /// The client supports sending a will save request and + /// waits for a response providing text edits which will + /// be applied to the document before it is saved. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save_wait_until: Option, + + /// The client supports did save notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_save: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItemCapability { + /// Client supports snippets as insert text. + /// + /// A snippet can define tab stops and placeholders with `$1`, `$2` + /// and `${3:foo}`. `$0` defines the final tab stop, it defaults to + /// the end of the snippet. Placeholders with equal identifiers are linked, + /// that is typing in one will update others too. + #[serde(skip_serializing_if = "Option::is_none")] + pub snippet_support: Option, + + /// Client supports commit characters on a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub commit_characters_support: Option, + + /// Client supports the follow content formats for the documentation + /// property. The order describes the preferred format of the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation_format: Option>, + + /// Client supports the deprecated property on a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated_support: Option, + + /// Client supports the preselect property on a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub preselect_support: Option, + + /// Client supports the tag property on a completion item. Clients supporting + /// tags have to handle unknown tags gracefully. Clients especially need to + /// preserve unknown tags when sending a completion item back to the server in + /// a resolve call. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + pub tag_support: Option>, + + /// Client support insert replace edit to control different behavior if a + /// completion item is inserted in the text or should replace text. + /// + /// @since 3.16.0 - Proposed state + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub insert_replace_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum CompletionItemTag { + Deprecated = 1, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItemKindCapability { + /// The completion item kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + /// + /// If this property is not present the client only supports + /// the completion items kinds from `Text` to `Reference` as defined in + /// the initial version of the protocol. + #[serde(skip_serializing_if = "Option::is_none")] + pub value_set: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverCapability { + /// Whether completion supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Client supports the follow content formats for the content + /// property. The order describes the preferred format of the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub content_format: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionCapability { + /// Whether completion supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports the following `CompletionItem` specific + /// capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_item: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_item_kind: Option, + + /// The client supports to send additional context information for a + /// `textDocument/completion` requestion. + #[serde(skip_serializing_if = "Option::is_none")] + pub context_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureInformationSettings { + /// Client supports the follow content formats for the documentation + /// property. The order describes the preferred format of the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation_format: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub parameter_information: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ParameterInformationSettings { + /// The client supports processing label offsets instead of a + /// simple label string. + #[serde(skip_serializing_if = "Option::is_none")] + pub label_offset_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpCapability { + /// Whether completion supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports the following `SignatureInformation` + /// specific properties. + #[serde(skip_serializing_if = "Option::is_none")] + pub signature_information: Option, + + /// The client supports to send additional context information for a + /// `textDocument/signatureHelp` request. A client that opts into + /// contextSupport will also support the `retriggerCharacters` on + /// `SignatureHelpOptions`. + #[serde(skip_serializing_if = "Option::is_none")] + pub context_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PublishDiagnosticsCapability { + /// Whether the clients accepts diagnostics with related information. + #[serde(skip_serializing_if = "Option::is_none")] + pub related_information: Option, + + /// Client supports the tag property to provide meta data about a diagnostic. + /// Clients supporting tags have to handle unknown tags gracefully. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + pub tag_support: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TagSupport { + /// The tags supported by the client. + pub value_set: Vec, +} + +impl TagSupport { + /// Support for deserializing a boolean tag Support, in case it's present. + /// + /// This is currently the case for vscode 1.41.1 + fn deserialize_compat<'de, S>(serializer: S) -> Result>, S::Error> + where + S: serde::Deserializer<'de>, + T: serde::Deserialize<'de>, + { + Ok( + match Option::::deserialize(serializer).map_err(serde::de::Error::custom)? { + Some(Value::Bool(false)) => None, + Some(Value::Bool(true)) => Some(TagSupport { value_set: vec![] }), + Some(other) => { + Some(TagSupport::::deserialize(other).map_err(serde::de::Error::custom)?) + } + None => None, + }, + ) + } +} + +/// Text document specific client capabilities. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentClientCapabilities { + #[serde(skip_serializing_if = "Option::is_none")] + pub synchronization: Option, + /// Capabilities specific to the `textDocument/completion` + #[serde(skip_serializing_if = "Option::is_none")] + pub completion: Option, + + /// Capabilities specific to the `textDocument/hover` + #[serde(skip_serializing_if = "Option::is_none")] + pub hover: Option, + + /// Capabilities specific to the `textDocument/signatureHelp` + #[serde(skip_serializing_if = "Option::is_none")] + pub signature_help: Option, + + /// Capabilities specific to the `textDocument/references` + #[serde(skip_serializing_if = "Option::is_none")] + pub references: Option, + + /// Capabilities specific to the `textDocument/documentHighlight` + #[serde(skip_serializing_if = "Option::is_none")] + pub document_highlight: Option, + + /// Capabilities specific to the `textDocument/documentSymbol` + #[serde(skip_serializing_if = "Option::is_none")] + pub document_symbol: Option, + /// Capabilities specific to the `textDocument/formatting` + #[serde(skip_serializing_if = "Option::is_none")] + pub formatting: Option, + + /// Capabilities specific to the `textDocument/rangeFormatting` + #[serde(skip_serializing_if = "Option::is_none")] + pub range_formatting: Option, + + /// Capabilities specific to the `textDocument/onTypeFormatting` + #[serde(skip_serializing_if = "Option::is_none")] + pub on_type_formatting: Option, + + /// Capabilities specific to the `textDocument/declaration` + #[serde(skip_serializing_if = "Option::is_none")] + pub declaration: Option, + + /// Capabilities specific to the `textDocument/definition` + #[serde(skip_serializing_if = "Option::is_none")] + pub definition: Option, + + /// Capabilities specific to the `textDocument/typeDefinition` + #[serde(skip_serializing_if = "Option::is_none")] + pub type_definition: Option, + + /// Capabilities specific to the `textDocument/implementation` + #[serde(skip_serializing_if = "Option::is_none")] + pub implementation: Option, + + /// Capabilities specific to the `textDocument/codeAction` + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action: Option, + + /// Capabilities specific to the `textDocument/codeLens` + #[serde(skip_serializing_if = "Option::is_none")] + pub code_lens: Option, + + /// Capabilities specific to the `textDocument/documentLink` + #[serde(skip_serializing_if = "Option::is_none")] + pub document_link: Option, + + /// Capabilities specific to the `textDocument/documentColor` and the + /// `textDocument/colorPresentation` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub color_provider: Option, + + /// Capabilities specific to the `textDocument/rename` + #[serde(skip_serializing_if = "Option::is_none")] + pub rename: Option, + + /// Capabilities specific to `textDocument/publishDiagnostics`. + #[serde(skip_serializing_if = "Option::is_none")] + pub publish_diagnostics: Option, + + /// Capabilities specific to `textDocument/foldingRange` requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub folding_range: Option, + + /// The client's semantic highlighting capability. + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub semantic_highlighting_capabilities: Option, + + /// Capabilities specific to the `textDocument/semanticTokens/*` requests. + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub semantic_tokens: Option, +} + +/// Window specific client capabilities. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WindowClientCapabilities { + /// Whether client supports create a work done progress UI from the server side. + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_progress: Option, +} + +/// Where ClientCapabilities are currently empty: +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ClientCapabilities { + /// Workspace specific client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace: Option, + + /// Text document specific client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_document: Option, + + /// Window specific client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub window: Option, + + /// Experimental client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub experimental: Option, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InitializeResult { + /// The capabilities the language server provides. + pub capabilities: ServerCapabilities, + + /// The capabilities the language server provides. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_info: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct ServerInfo { + /// The name of the server as defined by the server. + pub name: String, + /// The servers's version as defined by the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct InitializeError { + /// Indicates whether the client should retry to send the + /// initilize request after showing the message provided + /// in the ResponseError. + pub retry: bool, +} + +// The server can signal the following capabilities: + +/// Defines how the host (editor) should sync document changes to the language server. +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum TextDocumentSyncKind { + /// Documents should not be synced at all. + None = 0, + + /// Documents are synced by always sending the full content of the document. + Full = 1, + + /// Documents are synced by sending the full content on open. After that only + /// incremental updates to the document are sent. + Incremental = 2, +} + +/// Completion options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionOptions { + /// The server provides support to resolve additional information for a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, + + /// The characters that trigger completion automatically. + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_characters: Option>, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Hover options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub hover_options: HoverOptions, +} + +/// Signature help options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpOptions { + /// The characters that trigger signature help automatically. + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_characters: Option>, + + /// List of characters that re-trigger signature help. + /// These trigger characters are only active when signature help is already showing. All trigger characters + /// are also counted as re-trigger characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub retrigger_characters: Option>, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Signature help options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SignatureHelpRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, +} +/// Signature help options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum SignatureHelpTriggerKind { + /// Signature help was invoked manually by the user or by a command. + Invoked = 1, + /// Signature help was triggered by a trigger character. + TriggerCharacter = 2, + /// Signature help was triggered by the cursor moving or by the document content changing. + ContentChange = 3, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpParams { + /// The signature help context. This is only available if the client specifies + /// to send this using the client capability `textDocument.signatureHelp.contextSupport === true` + #[serde(skip_serializing_if = "Option::is_none")] + pub context: Option, + + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpContext { + /// Action that caused signature help to be triggered. + pub trigger_kind: SignatureHelpTriggerKind, + + /// Character that caused signature help to be triggered. + /// This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter` + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_character: Option, + + /// `true` if signature help was already showing when it was triggered. + /// Retriggers occur when the signature help is already active and can be caused by actions such as + /// typing a trigger character, a cursor move, or document content changes. + pub is_retrigger: bool, + + /// The currently active `SignatureHelp`. + /// The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on + /// the user navigating through available signatures. + #[serde(skip_serializing_if = "Option::is_none")] + pub active_signature_help: Option, +} + +/// Code Lens options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeLensOptions { + /// Code lens has a resolve provider as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, +} + +/// Format document on type options +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentOnTypeFormattingOptions { + /// A character on which formatting should be triggered, like `}`. + pub first_trigger_character: String, + + /// More trigger characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub more_trigger_character: Option>, +} + +/// Execute command options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct ExecuteCommandOptions { + /// The commands to be executed on the server + pub commands: Vec, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Save options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SaveOptions { + /// The client is supposed to include the content on save. + #[serde(skip_serializing_if = "Option::is_none")] + pub include_text: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TextDocumentSyncSaveOptions { + Supported(bool), + SaveOptions(SaveOptions), +} + +impl From for TextDocumentSyncSaveOptions { + fn from(from: SaveOptions) -> Self { + Self::SaveOptions(from) + } +} + +impl From for TextDocumentSyncSaveOptions { + fn from(from: bool) -> Self { + Self::Supported(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentSyncOptions { + /// Open and close notifications are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub open_close: Option, + + /// Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full + /// and TextDocumentSyncKindIncremental. + #[serde(skip_serializing_if = "Option::is_none")] + pub change: Option, + + /// Will save notifications are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save: Option, + + /// Will save wait until requests are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save_wait_until: Option, + + /// Save notifications are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub save: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TextDocumentSyncCapability { + Kind(TextDocumentSyncKind), + Options(TextDocumentSyncOptions), +} + +impl From for TextDocumentSyncCapability { + fn from(from: TextDocumentSyncOptions) -> Self { + Self::Options(from) + } +} + +impl From for TextDocumentSyncCapability { + fn from(from: TextDocumentSyncKind) -> Self { + Self::Kind(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ImplementationProviderCapability { + Simple(bool), + Options(StaticTextDocumentRegistrationOptions), +} + +impl From for ImplementationProviderCapability { + fn from(from: StaticTextDocumentRegistrationOptions) -> Self { + Self::Options(from) + } +} + +impl From for ImplementationProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TypeDefinitionProviderCapability { + Simple(bool), + Options(StaticTextDocumentRegistrationOptions), +} + +impl From for TypeDefinitionProviderCapability { + fn from(from: StaticTextDocumentRegistrationOptions) -> Self { + Self::Options(from) + } +} + +impl From for TypeDefinitionProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum HoverProviderCapability { + Simple(bool), + Options(HoverOptions), +} + +impl From for HoverProviderCapability { + fn from(from: HoverOptions) -> Self { + Self::Options(from) + } +} + +impl From for HoverProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ColorProviderCapability { + Simple(bool), + ColorProvider(ColorProviderOptions), + Options(StaticTextDocumentColorProviderOptions), +} + +impl From for ColorProviderCapability { + fn from(from: ColorProviderOptions) -> Self { + Self::ColorProvider(from) + } +} + +impl From for ColorProviderCapability { + fn from(from: StaticTextDocumentColorProviderOptions) -> Self { + Self::Options(from) + } +} + +impl From for ColorProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum CodeActionProviderCapability { + Simple(bool), + Options(CodeActionOptions), +} + +impl From for CodeActionProviderCapability { + fn from(from: CodeActionOptions) -> Self { + Self::Options(from) + } +} + +impl From for CodeActionProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionCapability { + /// + /// This capability supports dynamic registration. + /// + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client support code action literals as a valid + /// response of the `textDocument/codeAction` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action_literal_support: Option, + + /// Whether code action supports the `isPreferred` property. + #[serde(skip_serializing_if = "Option::is_none")] + pub is_preferred_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionLiteralSupport { + /// The code action kind is support with the following value set. + pub code_action_kind: CodeActionKindLiteralSupport, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionKindLiteralSupport { + /// The code action kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + pub value_set: Vec, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ServerCapabilities { + /// Defines how text documents are synced. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_document_sync: Option, + + /// Capabilities specific to `textDocument/selectionRange` requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub selection_range_provider: Option, + + /// The server provides hover support. + #[serde(skip_serializing_if = "Option::is_none")] + pub hover_provider: Option, + + /// The server provides completion support. + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_provider: Option, + + /// The server provides signature help support. + #[serde(skip_serializing_if = "Option::is_none")] + pub signature_help_provider: Option, + + /// The server provides goto definition support. + #[serde(skip_serializing_if = "Option::is_none")] + pub definition_provider: Option, + + /// The server provides goto type definition support. + #[serde(skip_serializing_if = "Option::is_none")] + pub type_definition_provider: Option, + + /// the server provides goto implementation support. + #[serde(skip_serializing_if = "Option::is_none")] + pub implementation_provider: Option, + + /// The server provides find references support. + #[serde(skip_serializing_if = "Option::is_none")] + pub references_provider: Option, + + /// The server provides document highlight support. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_highlight_provider: Option, + + /// The server provides document symbol support. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_symbol_provider: Option, + + /// The server provides workspace symbol support. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_symbol_provider: Option, + + /// The server provides code actions. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action_provider: Option, + + /// The server provides code lens. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_lens_provider: Option, + + /// The server provides document formatting. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_formatting_provider: Option, + + /// The server provides document range formatting. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_range_formatting_provider: Option, + + /// The server provides document formatting on typing. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_on_type_formatting_provider: Option, + + /// The server provides rename support. + #[serde(skip_serializing_if = "Option::is_none")] + pub rename_provider: Option, + + /// The server provides document link support. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_link_provider: Option, + + /// The server provides color provider support. + #[serde(skip_serializing_if = "Option::is_none")] + pub color_provider: Option, + + /// The server provides folding provider support. + #[serde(skip_serializing_if = "Option::is_none")] + pub folding_range_provider: Option, + + /// The server provides go to declaration support. + #[serde(skip_serializing_if = "Option::is_none")] + pub declaration_provider: Option, + + /// The server provides execute command support. + #[serde(skip_serializing_if = "Option::is_none")] + pub execute_command_provider: Option, + + /// Workspace specific server capabilities + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace: Option, + + /// Semantic highlighting server capabilities. + #[cfg(feature = "proposed")] + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_highlighting: Option, + + /// Call hierarchy provider capabilities. + #[cfg(feature = "proposed")] + #[serde(skip_serializing_if = "Option::is_none")] + pub call_hierarchy_provider: Option, + + /// Semantic tokens server capabilities. + #[cfg(feature = "proposed")] + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_tokens_provider: Option, + + /// Experimental server capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub experimental: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentLinkCapabilities { + /// Whether document link supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Whether the client support the `tooltip` property on `DocumentLink`. + #[serde(skip_serializing_if = "Option::is_none")] + pub tooltip_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ShowMessageParams { + /// The message type. See {@link MessageType}. + #[serde(rename = "type")] + pub typ: MessageType, + + /// The actual message. + pub message: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum MessageType { + /// An error message. + Error = 1, + /// A warning message. + Warning = 2, + /// An information message. + Info = 3, + /// A log message. + Log = 4, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ShowMessageRequestParams { + /// The message type. See {@link MessageType} + #[serde(rename = "type")] + pub typ: MessageType, + + /// The actual message + pub message: String, + + /// The message action items to present. + #[serde(skip_serializing_if = "Option::is_none")] + pub actions: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct MessageActionItem { + /// A short title like 'Retry', 'Open Log' etc. + pub title: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct LogMessageParams { + /// The message type. See {@link MessageType} + #[serde(rename = "type")] + pub typ: MessageType, + + /// The actual message + pub message: String, +} + +/// General parameters to to register for a capability. +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Registration { + /// The id used to register the request. The id can be used to deregister + /// the request again. + pub id: String, + + /// The method / capability to register for. + pub method: String, + + /// Options necessary for the registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub register_options: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct RegistrationParams { + pub registrations: Vec, +} + +/// Since most of the registration options require to specify a document selector there is a base +/// interface that can be used. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaticRegistrationOptions { + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaticTextDocumentRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ColorProviderOptions {} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaticTextDocumentColorProviderOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +/// General parameters to unregister a capability. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct Unregistration { + /// The id used to unregister the request or notification. Usually an id + /// provided during the register request. + pub id: String, + + /// The method / capability to unregister for. + pub method: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct UnregistrationParams { + pub unregisterations: Vec, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct DidChangeConfigurationParams { + /// The actual changed settings + pub settings: Value, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidOpenTextDocumentParams { + /// The document that was opened. + pub text_document: TextDocumentItem, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidChangeTextDocumentParams { + /// The document that did change. The version number points + /// to the version after all provided content changes have + /// been applied. + pub text_document: VersionedTextDocumentIdentifier, + /// The actual content changes. + pub content_changes: Vec, +} + +/// An event describing a change to a text document. If range and rangeLength are omitted +/// the new text is considered to be the full content of the document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentContentChangeEvent { + /// The range of the document that changed. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + + /// The length of the range that got replaced. + /// NOTE: seems redundant, see: + #[serde(skip_serializing_if = "Option::is_none")] + pub range_length: Option, + + /// The new text of the document. + pub text: String, +} + +/// Descibe options to be used when registered for text document change events. +/// +/// Extends TextDocumentRegistrationOptions +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentChangeRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + /// How documents are synced to the server. See TextDocumentSyncKind.Full + /// and TextDocumentSyncKindIncremental. + pub sync_kind: i32, +} + +/// The parameters send in a will save text document notification. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WillSaveTextDocumentParams { + /// The document that will be saved. + pub text_document: TextDocumentIdentifier, + + /// The 'TextDocumentSaveReason'. + pub reason: TextDocumentSaveReason, +} + +/// Represents reasons why a text document is saved. +#[derive(Copy, Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum TextDocumentSaveReason { + /// Manually triggered, e.g. by the user pressing save, by starting debugging, + /// or by an API call. + Manual = 1, + + /// Automatic after a delay. + AfterDelay = 2, + + /// When the editor lost focus. + FocusOut = 3, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidCloseTextDocumentParams { + /// The document that was closed. + pub text_document: TextDocumentIdentifier, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidSaveTextDocumentParams { + /// The document that was saved. + pub text_document: TextDocumentIdentifier, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentSaveRegistrationOptions { + /// The client is supposed to include the content on save. + #[serde(skip_serializing_if = "Option::is_none")] + pub include_text: Option, + + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DidChangeWatchedFilesParams { + /// The actual file events. + pub changes: Vec, +} + +/// The file event type. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum FileChangeType { + /// The file got created. + Created = 1, + + /// The file got changed. + Changed = 2, + + /// The file got deleted. + Deleted = 3, +} + +/// An event describing a file change. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct FileEvent { + /// The file's URI. + pub uri: Url, + + /// The change type. + #[serde(rename = "type")] + pub typ: FileChangeType, +} + +impl FileEvent { + pub fn new(uri: Url, typ: FileChangeType) -> FileEvent { + FileEvent { uri, typ } + } +} + +/// Describe options to be used when registered for text document change events. +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] +pub struct DidChangeWatchedFilesRegistrationOptions { + /// The watchers to register. + pub watchers: Vec, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileSystemWatcher { + /// The glob pattern to watch + pub glob_pattern: String, + + /// The kind of events of interest. If omitted it defaults to WatchKind.Create | + /// WatchKind.Change | WatchKind.Delete which is 7. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, +} + +bitflags! { +pub struct WatchKind: u8 { + /// Interested in create events. + const Create = 1; + /// Interested in change events + const Change = 2; + /// Interested in delete events + const Delete = 4; +} +} + +impl<'de> serde::Deserialize<'de> for WatchKind { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let i = u8::deserialize(deserializer)?; + WatchKind::from_bits(i).ok_or_else(|| { + D::Error::invalid_value(de::Unexpected::Unsigned(u64::from(i)), &"Unknown flag") + }) + } +} + +impl serde::Serialize for WatchKind { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_u8(self.bits()) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct PublishDiagnosticsParams { + /// The URI for which diagnostic information is reported. + pub uri: Url, + + /// An array of diagnostic information items. + pub diagnostics: Vec, + + /// Optional the version number of the document the diagnostics are published for. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +impl PublishDiagnosticsParams { + pub fn new( + uri: Url, + diagnostics: Vec, + version: Option, + ) -> PublishDiagnosticsParams { + PublishDiagnosticsParams { + uri, + diagnostics, + version, + } + } +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +pub struct CompletionRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub completion_options: CompletionOptions, +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CompletionResponse { + Array(Vec), + List(CompletionList), +} + +impl From> for CompletionResponse { + fn from(items: Vec) -> Self { + CompletionResponse::Array(items) + } +} + +impl From for CompletionResponse { + fn from(list: CompletionList) -> Self { + CompletionResponse::List(list) + } +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionParams { + // This field was "mixed-in" from TextDocumentPositionParams + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + // CompletionParams properties: + #[serde(skip_serializing_if = "Option::is_none")] + pub context: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionContext { + /// How the completion was triggered. + pub trigger_kind: CompletionTriggerKind, + + /// The trigger character (a single character) that has trigger code complete. + /// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_character: Option, +} + +/// How a completion was triggered. +#[derive(Debug, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum CompletionTriggerKind { + Invoked = 1, + TriggerCharacter = 2, + TriggerForIncompleteCompletions = 3, +} + +/// Represents a collection of [completion items](#CompletionItem) to be presented +/// in the editor. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionList { + /// This list it not complete. Further typing should result in recomputing + /// this list. + pub is_incomplete: bool, + + /// The completion items. + pub items: Vec, +} + +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum Documentation { + String(String), + MarkupContent(MarkupContent), +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItem { + /// The label of this completion item. By default + /// also the text that is inserted when selecting + /// this completion. + pub label: String, + + /// The kind of this completion item. Based of the kind + /// an icon is chosen by the editor. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + /// A human-readable string with additional information + /// about this item, like type or symbol information. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + + /// A human-readable string that represents a doc-comment. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation: Option, + + /// Indicates if this item is deprecated. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated: Option, + + /// Select this item when showing. + #[serde(skip_serializing_if = "Option::is_none")] + pub preselect: Option, + + /// A string that shoud be used when comparing this item + /// with other items. When `falsy` the label is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub sort_text: Option, + + /// A string that should be used when filtering a set of + /// completion items. When `falsy` the label is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub filter_text: Option, + + /// A string that should be inserted a document when selecting + /// this completion. When `falsy` the label is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text: Option, + + /// The format of the insert text. The format applies to both the `insertText` property + /// and the `newText` property of a provided `textEdit`. + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text_format: Option, + + /// An edit which is applied to a document when selecting + /// this completion. When an edit is provided the value of + /// insertText is ignored. + /// + /// Most editors support two different operation when accepting a completion item. One is to insert a + /// completion text and the other is to replace an existing text with a competion text. Since this can + /// usually not predetermend by a server it can report both ranges. Clients need to signal support for + /// `InsertReplaceEdits` via the `textDocument.completion.insertReplaceSupport` client capability + /// property. + /// + /// *Note 1:* The text edit's range as well as both ranges from a insert replace edit must be a + /// [single line] and they must contain the position at which completion has been requested. + /// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range must be a prefix of + /// the edit's replace range, that means it must be contained and starting at the same position. + /// + /// @since 3.16.0 additional type `InsertReplaceEdit` - Proposed state + #[serde(skip_serializing_if = "Option::is_none")] + pub text_edit: Option, + + /// An optional array of additional text edits that are applied when + /// selecting this completion. Edits must not overlap with the main edit + /// nor with themselves. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_text_edits: Option>, + + /// An optional command that is executed *after* inserting this completion. *Note* that + /// additional modifications to the current document should be described with the + /// additionalTextEdits-property. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + + /// An data entry field that is preserved on a completion item between + /// a completion and a completion resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, + + /// Tags for this completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, +} + +impl CompletionItem { + /// Create a CompletionItem with the minimum possible info (label and detail). + pub fn new_simple(label: String, detail: String) -> CompletionItem { + CompletionItem { + label, + detail: Some(detail), + ..Self::default() + } + } +} + +/// The kind of a completion entry. +#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum CompletionItemKind { + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25, +} + +/// Defines how to interpret the insert text in a completion item +#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum InsertTextFormat { + PlainText = 1, + Snippet = 2, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +/// The result of a hover request. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct Hover { + /// The hover's content + pub contents: HoverContents, + /// An optional range is a range inside a text document + /// that is used to visualize a hover, e.g. by changing the background color. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, +} + +/// Hover contents could be single entry or multiple entries. +#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum HoverContents { + Scalar(MarkedString), + Array(Vec), + Markup(MarkupContent), +} + +/// The marked string is rendered: +/// - as markdown if it is represented as a string +/// - as code block of the given langauge if it is represented as a pair of a language and a value +/// +/// The pair of a language and a value is an equivalent to markdown: +/// ```${language} +/// ${value} +/// ``` +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum MarkedString { + String(String), + LanguageString(LanguageString), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct LanguageString { + pub language: String, + pub value: String, +} + +impl MarkedString { + pub fn from_markdown(markdown: String) -> MarkedString { + MarkedString::String(markdown) + } + + pub fn from_language_code(language: String, code_block: String) -> MarkedString { + MarkedString::LanguageString(LanguageString { + language, + value: code_block, + }) + } +} + +/// Signature help represents the signature of something +/// callable. There can be multiple signature but only one +/// active and only one active parameter. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelp { + /// One or more signatures. + pub signatures: Vec, + + /// The active signature. + #[serde(skip_serializing_if = "Option::is_none")] + pub active_signature: Option, + + /// The active parameter of the active signature. + #[serde(skip_serializing_if = "Option::is_none")] + pub active_parameter: Option, +} + +/// Represents the signature of something callable. A signature +/// can have a label, like a function-name, a doc-comment, and +/// a set of parameters. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SignatureInformation { + /// The label of this signature. Will be shown in + /// the UI. + pub label: String, + + /// The human-readable doc-comment of this signature. Will be shown + /// in the UI but can be omitted. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation: Option, + + /// The parameters of this signature. + #[serde(skip_serializing_if = "Option::is_none")] + pub parameters: Option>, +} + +/// Represents a parameter of a callable-signature. A parameter can +/// have a label and a doc-comment. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ParameterInformation { + /// The label of this parameter information. + /// + /// Either a string or an inclusive start and exclusive end offsets within its containing + /// signature label. (see SignatureInformation.label). *Note*: A label of type string must be + /// a substring of its containing signature label. + pub label: ParameterLabel, + + /// The human-readable doc-comment of this parameter. Will be shown + /// in the UI but can be omitted. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ParameterLabel { + Simple(String), + LabelOffsets([u64; 2]), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GotoDefinitionParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// GotoDefinition response can be single location, or multiple Locations or a link. +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GotoDefinitionResponse { + Scalar(Location), + Array(Vec), + Link(Vec), +} + +impl From for GotoDefinitionResponse { + fn from(location: Location) -> Self { + GotoDefinitionResponse::Scalar(location) + } +} + +impl From> for GotoDefinitionResponse { + fn from(locations: Vec) -> Self { + GotoDefinitionResponse::Array(locations) + } +} + +impl From> for GotoDefinitionResponse { + fn from(locations: Vec) -> Self { + GotoDefinitionResponse::Link(locations) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReferenceParams { + // Text Document and Position fields + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + // ReferenceParams properties: + pub context: ReferenceContext, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReferenceContext { + /// Include the declaration of the current symbol. + pub include_declaration: bool, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentHighlightParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A document highlight is a range inside a text document which deserves +/// special attention. Usually a document highlight is visualized by changing +/// the background color of its range. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DocumentHighlight { + /// The range this highlight applies to. + pub range: Range, + + /// The highlight kind, default is DocumentHighlightKind.Text. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, +} + +/// A document highlight kind. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum DocumentHighlightKind { + /// A textual occurrance. + Text = 1, + + /// Read-access of a symbol, like reading a variable. + Read = 2, + + /// Write-access of a symbol, like writing to a variable. + Write = 3, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbolClientCapabilities { + /// This capability supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Specific capabilities for the `SymbolKind`. + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol_kind: Option, + + /// The client support hierarchical document symbols. + #[serde(skip_serializing_if = "Option::is_none")] + pub hierarchical_document_symbol_support: Option, + + /// The client supports tags on `SymbolInformation`. Tags are supported on + /// `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. + /// Clients supporting tags have to handle unknown tags gracefully. + /// + /// @since 3.16.0 + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + #[cfg(feature = "proposed")] + pub tag_support: Option>, +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum DocumentSymbolResponse { + Flat(Vec), + Nested(Vec), +} + +impl From> for DocumentSymbolResponse { + fn from(info: Vec) -> Self { + DocumentSymbolResponse::Flat(info) + } +} + +impl From> for DocumentSymbolResponse { + fn from(symbols: Vec) -> Self { + DocumentSymbolResponse::Nested(symbols) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbolParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents programming constructs like variables, classes, interfaces etc. +/// that appear in a document. Document symbols can be hierarchical and they have two ranges: +/// one that encloses its definition and one that points to its most interesting range, +/// e.g. the range of an identifier. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbol { + /// The name of this symbol. + pub name: String, + /// More detail for this symbol, e.g the signature of a function. If not provided the + /// name is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + /// The kind of this symbol. + pub kind: SymbolKind, + /// Tags for this completion item. + /// since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub tags: Option>, + /// Indicates if this symbol is deprecated. + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use tags instead")] + pub deprecated: Option, + /// The range enclosing this symbol not including leading/trailing whitespace but everything else + /// like comments. This information is typically used to determine if the the clients cursor is + /// inside the symbol to reveal in the symbol in the UI. + pub range: Range, + /// The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. + /// Must be contained by the the `range`. + pub selection_range: Range, + /// Children of this symbol, e.g. properties of a class. + #[serde(skip_serializing_if = "Option::is_none")] + pub children: Option>, +} + +/// Represents information about programming constructs like variables, classes, +/// interfaces etc. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SymbolInformation { + /// The name of this symbol. + pub name: String, + + /// The kind of this symbol. + pub kind: SymbolKind, + + /// Tags for this completion item. + /// since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub tags: Option>, + + /// Indicates if this symbol is deprecated. + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use tags instead")] + pub deprecated: Option, + + /// The location of this symbol. + pub location: Location, + + /// The name of the symbol containing this symbol. + #[serde(skip_serializing_if = "Option::is_none")] + pub container_name: Option, +} + +/// A symbol kind. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum SymbolKind { + File = 1, + Module = 2, + Namespace = 3, + Package = 4, + Class = 5, + Method = 6, + Property = 7, + Field = 8, + Constructor = 9, + Enum = 10, + Interface = 11, + Function = 12, + Variable = 13, + Constant = 14, + String = 15, + Number = 16, + Boolean = 17, + Array = 18, + Object = 19, + Key = 20, + Null = 21, + EnumMember = 22, + Struct = 23, + Event = 24, + Operator = 25, + TypeParameter = 26, + + // Capturing all unknown enums by this lib. + Unknown = 255, +} + +/// The parameters of a Workspace Symbol Request. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct WorkspaceSymbolParams { + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + /// A non-empty query string + pub query: String, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct ExecuteCommandParams { + /// The identifier of the actual command handler. + pub command: String, + /// Arguments that the command should be invoked with. + #[serde(default)] + pub arguments: Vec, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +/// Execute command registration options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ExecuteCommandRegistrationOptions { + /// The commands to be executed on the server + pub commands: Vec, + + #[serde(flatten)] + pub execute_command_options: ExecuteCommandOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ApplyWorkspaceEditParams { + /// The edits to apply. + pub edit: WorkspaceEdit, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ApplyWorkspaceEditResponse { + /// Indicates whether the edit was applied or not. + pub applied: bool, +} + +/// Params for the CodeActionRequest +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionParams { + /// The document in which the command was invoked. + pub text_document: TextDocumentIdentifier, + + /// The range for which the command was invoked. + pub range: Range, + + /// Context carrying additional information. + pub context: CodeActionContext, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// response for CodeActionRequest +pub type CodeActionResponse = Vec; + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(untagged)] +pub enum CodeActionOrCommand { + Command(Command), + CodeAction(CodeAction), +} + +impl From for CodeActionOrCommand { + fn from(comand: Command) -> Self { + CodeActionOrCommand::Command(comand) + } +} + +impl From for CodeActionOrCommand { + fn from(action: CodeAction) -> Self { + CodeActionOrCommand::CodeAction(action) + } +} + +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +pub struct CodeActionKind(Cow<'static, str>); + +impl CodeActionKind { + /// Empty kind. + pub const EMPTY: CodeActionKind = CodeActionKind::new(""); + + /// Base kind for quickfix actions: 'quickfix' + pub const QUICKFIX: CodeActionKind = CodeActionKind::new("quickfix"); + + /// Base kind for refactoring actions: 'refactor' + pub const REFACTOR: CodeActionKind = CodeActionKind::new("refactor"); + + /// Base kind for refactoring extraction actions: 'refactor.extract' + /// + /// Example extract actions: + /// + /// - Extract method + /// - Extract function + /// - Extract variable + /// - Extract interface from class + /// - ... + pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract"); + + /// Base kind for refactoring inline actions: 'refactor.inline' + /// + /// Example inline actions: + /// + /// - Inline function + /// - Inline variable + /// - Inline constant + /// - ... + pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline"); + + /// Base kind for refactoring rewrite actions: 'refactor.rewrite' + /// + /// Example rewrite actions: + /// + /// - Convert JavaScript function to class + /// - Add or remove parameter + /// - Encapsulate field + /// - Make method static + /// - Move method to base class + /// - ... + pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite"); + + /// Base kind for source actions: `source` + /// + /// Source code actions apply to the entire file. + pub const SOURCE: CodeActionKind = CodeActionKind::new("source"); + + /// Base kind for an organize imports source action: `source.organizeImports` + pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind = + CodeActionKind::new("source.organizeImports"); + + pub const fn new(tag: &'static str) -> Self { + CodeActionKind(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl From for CodeActionKind { + fn from(from: String) -> Self { + CodeActionKind(Cow::from(from)) + } +} + +impl From<&'static str> for CodeActionKind { + fn from(from: &'static str) -> Self { + CodeActionKind::new(from) + } +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeAction { + /// A short, human-readable, title for this code action. + pub title: String, + + /// The kind of the code action. + /// Used to filter code actions. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + /// The diagnostics that this code action resolves. + #[serde(skip_serializing_if = "Option::is_none")] + pub diagnostics: Option>, + + /// The workspace edit this code action performs. + #[serde(skip_serializing_if = "Option::is_none")] + pub edit: Option, + + /// A command this code action executes. If a code action + /// provides an edit and a command, first the edit is + /// executed and then the command. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + + /// Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted + /// by keybindings. + /// A quick fix should be marked preferred if it properly addresses the underlying error. + /// A refactoring should be marked preferred if it is the most reasonable choice of actions to take. + #[serde(skip_serializing_if = "Option::is_none")] + pub is_preferred: Option, +} + +/// Contains additional diagnostic information about the context in which +/// a code action is run. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct CodeActionContext { + /// An array of diagnostics. + pub diagnostics: Vec, + + /// Requested kind of actions to return. + /// + /// Actions not of this kind are filtered out by the client before being shown. So servers + /// can omit computing them. + #[serde(skip_serializing_if = "Option::is_none")] + pub only: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionOptions { + /// CodeActionKinds that this server may return. + /// + /// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server + /// may list out every specific kind they provide. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action_kinds: Option>, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeLensParams { + /// The document to request code lens for. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A code lens represents a command that should be shown along with +/// source text, like the number of references, a way to run tests, etc. +/// +/// A code lens is _unresolved_ when no command is associated to it. For performance +/// reasons the creation of a code lens and resolving should be done in two stages. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct CodeLens { + /// The range in which this code lens is valid. Should only span a single line. + pub range: Range, + + /// The command this code lens represents. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + + /// A data entry field that is preserved on a code lens item between + /// a code lens and a code lens resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentLinkParams { + /// The document to provide document links for. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A document link is a range in a text document that links to an internal or external resource, like another +/// text document or a web site. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DocumentLink { + /// The range this link applies to. + pub range: Range, + /// The uri this link points to. + #[serde(skip_serializing_if = "Option::is_none")] + pub target: Option, + + /// The tooltip text when you hover over this link. + /// + /// If a tooltip is provided, is will be displayed in a string that includes instructions on how to + /// trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, + /// user settings, and localization. + #[serde(skip_serializing_if = "Option::is_none")] + pub tooltip: Option, + + /// A data entry field that is preserved on a document link between a DocumentLinkRequest + /// and a DocumentLinkResolveRequest. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentFormattingParams { + /// The document to format. + pub text_document: TextDocumentIdentifier, + + /// The format options. + pub options: FormattingOptions, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +/// Value-object describing what options formatting should use. +#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct FormattingOptions { + /// Size of a tab in spaces. + pub tab_size: u64, + + /// Prefer spaces over tabs. + pub insert_spaces: bool, + + /// Signature for further properties. + #[serde(flatten)] + pub properties: HashMap, + + /// Trim trailing whitespaces on a line. + #[serde(skip_serializing_if = "Option::is_none")] + pub trim_trailing_whitespace: Option, + + /// Insert a newline character at the end of the file if one does not exist. + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_final_newline: Option, + + /// Trim all newlines after the final newline at the end of the file. + #[serde(skip_serializing_if = "Option::is_none")] + pub trim_final_newlines: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum FormattingProperty { + Bool(bool), + Number(f64), + String(String), +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentRangeFormattingParams { + /// The document to format. + pub text_document: TextDocumentIdentifier, + + /// The range to format + pub range: Range, + + /// The format options + pub options: FormattingOptions, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentOnTypeFormattingParams { + /// Text Document and Position fields. + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + /// The character that has been typed. + pub ch: String, + + /// The format options. + pub options: FormattingOptions, +} + +/// Extends TextDocumentRegistrationOptions +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentOnTypeFormattingRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + /// A character on which formatting should be triggered, like `}`. + pub first_trigger_character: String, + + /// More trigger characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub more_trigger_character: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameParams { + /// Text Document and Position fields + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + /// The new name of the symbol. If the given name is not valid the + /// request must return a [ResponseError](#ResponseError) with an + /// appropriate message set. + pub new_name: String, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum RenameProviderCapability { + Simple(bool), + Options(RenameOptions), +} + +impl From for RenameProviderCapability { + fn from(from: RenameOptions) -> Self { + Self::Options(from) + } +} + +impl From for RenameProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameOptions { + /// Renames should be checked and tested before being executed. + #[serde(skip_serializing_if = "Option::is_none")] + pub prepare_provider: Option, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameCapability { + /// Whether rename supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Client supports testing for validity of rename operations before execution. + #[serde(skip_serializing_if = "Option::is_none")] + pub prepare_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum PrepareRenameResponse { + Range(Range), + RangeWithPlaceholder { range: Range, placeholder: String }, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentLinkOptions { + /// Document links have a resolve provider as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentColorParams { + /// The text document + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ColorInformation { + /// The range in the document where this color appears. + pub range: Range, + /// The actual color value for this color range. + pub color: Color, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Color { + /// The red component of this color in the range [0-1]. + pub red: f64, + /// The green component of this color in the range [0-1]. + pub green: f64, + /// The blue component of this color in the range [0-1]. + pub blue: f64, + /// The alpha component of this color in the range [0-1]. + pub alpha: f64, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ColorPresentationParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The color information to request presentations for. + pub color: Color, + + /// The range where the color would be inserted. Serves as a context. + pub range: Range, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Default, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ColorPresentation { + /// The label of this color presentation. It will be shown on the color + /// picker header. By default this is also the text that is inserted when selecting + /// this color presentation. + pub label: String, + + /// An [edit](#TextEdit) which is applied to a document when selecting + /// this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + /// is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_edit: Option, + + /// An optional array of additional [text edits](#TextEdit) that are applied when + /// selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_text_edits: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRangeParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum FoldingRangeProviderCapability { + Simple(bool), + FoldingProvider(FoldingProviderOptions), + Options(StaticTextDocumentColorProviderOptions), +} + +impl From for FoldingRangeProviderCapability { + fn from(from: StaticTextDocumentColorProviderOptions) -> Self { + Self::Options(from) + } +} + +impl From for FoldingRangeProviderCapability { + fn from(from: FoldingProviderOptions) -> Self { + Self::FoldingProvider(from) + } +} + +impl From for FoldingRangeProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct FoldingProviderOptions {} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRangeCapability { + /// Whether implementation supports dynamic registration for folding range providers. If this is set to `true` + /// the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` + /// return value for the corresponding server capability as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The maximum number of folding ranges that the client prefers to receive per document. The value serves as a + /// hint, servers are free to follow the limit. + #[serde(skip_serializing_if = "Option::is_none")] + pub range_limit: Option, + /// If set, the client signals that it only supports folding complete lines. If set, client will + /// ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. + #[serde(skip_serializing_if = "Option::is_none")] + pub line_folding_only: Option, +} + +/// Represents a folding range. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRange { + /// The zero-based line number from where the folded range starts. + pub start_line: u64, + + /// The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. + #[serde(skip_serializing_if = "Option::is_none")] + pub start_character: Option, + + /// The zero-based line number where the folded range ends. + pub end_line: u64, + + /// The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. + #[serde(skip_serializing_if = "Option::is_none")] + pub end_character: Option, + + /// Describes the kind of the folding range such as `comment' or 'region'. The kind + /// is used to categorize folding ranges and used by commands like 'Fold all comments'. See + /// [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct SelectionRangeOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SelectionRangeRegistrationOptions { + #[serde(flatten)] + pub selection_range_options: SelectionRangeOptions, + + #[serde(flatten)] + pub registration_options: StaticTextDocumentRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum SelectionRangeProviderCapability { + Simple(bool), + Options(SelectionRangeOptions), + RegistrationOptions(SelectionRangeRegistrationOptions), +} + +impl From for SelectionRangeProviderCapability { + fn from(from: SelectionRangeRegistrationOptions) -> Self { + Self::RegistrationOptions(from) + } +} + +impl From for SelectionRangeProviderCapability { + fn from(from: SelectionRangeOptions) -> Self { + Self::Options(from) + } +} + +impl From for SelectionRangeProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +/// A parameter literal used in selection range requests. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SelectionRangeParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The positions inside the text document. + pub positions: Vec, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents a selection range. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SelectionRange { + /// Range of the selection. + pub range: Range, + + /// The parent selection range containing this range. + #[serde(skip_serializing_if = "Option::is_none")] + pub parent: Option>, +} + +/// Enum of known range kinds +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "lowercase")] +pub enum FoldingRangeKind { + /// Folding range for a comment + Comment, + /// Folding range for a imports or includes + Imports, + /// Folding range for a region (e.g. `#region`) + Region, +} + +/// Describes the content type that a client supports in various +/// result literals like `Hover`, `ParameterInfo` or `CompletionItem`. +/// +/// Please note that `MarkupKinds` must not start with a `$`. This kinds +/// are reserved for internal usage. +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "lowercase")] +pub enum MarkupKind { + /// Plain text is supported as a content format + PlainText, + /// Markdown is supported as a content format + Markdown, +} + +/// A `MarkupContent` literal represents a string value which content is interpreted base on its +/// kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. +/// +/// If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. +/// See +/// +/// Here is an example how such a string can be constructed using JavaScript / TypeScript: +/// ```ignore +/// let markdown: MarkupContent = { +/// kind: MarkupKind::Markdown, +/// value: [ +/// "# Header", +/// "Some text", +/// "```typescript", +/// "someCode();", +/// "```" +/// ] +/// .join("\n"), +/// }; +/// ``` +/// +/// Please Note* that clients might sanitize the return markdown. A client could decide to +/// remove HTML from the markdown to avoid script execution. +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +pub struct MarkupContent { + pub kind: MarkupKind, + pub value: String, +} + +pub type ProgressToken = NumberOrString; + +/// The progress notification is sent from the server to the client to ask +/// the client to indicate progress. +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ProgressParams { + /// The progress token provided by the client. + pub token: ProgressToken, + + /// The progress data. + pub value: ProgressParamsValue, +} + +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum ProgressParamsValue { + WorkDone(WorkDoneProgress), +} + +/// The `window/workDoneProgress/create` request is sent from the server +/// to the clientto ask the client to create a work done progress. +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressCreateParams { + /// The token to be used to report progress. + pub token: ProgressToken, +} + +/// The `window/workDoneProgress/cancel` notification is sent from the client +/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressCancelParams { + /// The token to be used to report progress. + pub token: ProgressToken, +} + +/// Options to signal work done progress support in server capabilities. +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressOptions { + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_progress: Option, +} + +/// An optional token that a server can use to report work done progress +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressParams { + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_token: Option, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressBegin { + /// Mandatory title of the progress operation. Used to briefly inform + /// about the kind of operation being performed. + /// Examples: "Indexing" or "Linking dependencies". + pub title: String, + + /// Controls if a cancel button should show to allow the user to cancel the + /// long running operation. Clients that don't support cancellation are allowed + /// to ignore the setting. + #[serde(skip_serializing_if = "Option::is_none")] + pub cancellable: Option, + + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// If unset, the previous progress message (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + + /// Optional progress percentage to display (value 100 is considered 100%). + /// If unset, the previous progress percentage (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub percentage: Option, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressReport { + /// Controls if a cancel button should show to allow the user to cancel the + /// long running operation. Clients that don't support cancellation are allowed + /// to ignore the setting. + #[serde(skip_serializing_if = "Option::is_none")] + pub cancellable: Option, + + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// If unset, the previous progress message (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + + /// Optional progress percentage to display (value 100 is considered 100%). + /// If unset, the previous progress percentage (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub percentage: Option, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressEnd { + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// If unset, the previous progress message (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} + +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum WorkDoneProgress { + Begin(WorkDoneProgressBegin), + Report(WorkDoneProgressReport), + End(WorkDoneProgressEnd), +} + +/// A parameter literal used to pass a partial result token. +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PartialResultParams { + #[serde(skip_serializing_if = "Option::is_none")] + pub partial_result_token: Option, +} + +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingClientCapability { + /// `true` if the client supports semantic highlighting support text documents. Otherwise, `false`. It is `false` by default. + pub semantic_highlighting: bool, +} + +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingServerCapability { + /// A "lookup table" of semantic highlighting [TextMate scopes](https://manual.macromates.com/en/language_grammars) + /// supported by the language server. If not defined or empty, then the server does not support the semantic highlighting + /// feature. Otherwise, clients should reuse this "lookup table" when receiving semantic highlighting notifications from + /// the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub scopes: Option>>, +} + +#[derive(Debug, Eq, PartialEq, Clone)] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingToken { + pub character: u32, + pub length: u16, + pub scope: u16, +} + +#[cfg(feature = "proposed")] +impl SemanticHighlightingToken { + /// Deserializes the tokens from a base64 encoded string + fn deserialize_tokens<'de, D>( + deserializer: D, + ) -> Result>, D::Error> + where + D: serde::Deserializer<'de>, + { + let opt_s = Option::::deserialize(deserializer)?; + + if let Some(s) = opt_s { + let bytes = base64::decode_config(s.as_str(), base64::STANDARD) + .map_err(|_| serde::de::Error::custom("Error parsing base64 string"))?; + let mut res = Vec::new(); + for chunk in bytes.chunks_exact(8) { + res.push(SemanticHighlightingToken { + character: u32::from_be_bytes(<[u8; 4]>::try_from(&chunk[0..4]).unwrap()), + length: u16::from_be_bytes(<[u8; 2]>::try_from(&chunk[4..6]).unwrap()), + scope: u16::from_be_bytes(<[u8; 2]>::try_from(&chunk[6..8]).unwrap()), + }); + } + Result::Ok(Some(res)) + } else { + Result::Ok(None) + } + } + + /// Serialize the tokens to a base64 encoded string + fn serialize_tokens( + tokens: &Option>, + serializer: S, + ) -> Result + where + S: serde::Serializer, + { + if let Some(tokens) = tokens { + let mut bytes = vec![]; + for token in tokens { + bytes.extend_from_slice(&token.character.to_be_bytes()); + bytes.extend_from_slice(&token.length.to_be_bytes()); + bytes.extend_from_slice(&token.scope.to_be_bytes()); + } + serializer.collect_str(&base64::display::Base64Display::with_config( + &bytes, + base64::STANDARD, + )) + } else { + serializer.serialize_none() + } + } +} + +/// Represents a semantic highlighting information that has to be applied on a specific line of the text document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingInformation { + /// The zero-based line position in the text document. + pub line: i32, + + /// A base64 encoded string representing every single highlighted characters with its start position, length and the "lookup table" index of + /// of the semantic highlighting [TextMate scopes](https://manual.macromates.com/en/language_grammars). + /// If the `tokens` is empty or not defined, then no highlighted positions are available for the line. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "SemanticHighlightingToken::deserialize_tokens", + serialize_with = "SemanticHighlightingToken::serialize_tokens" + )] + pub tokens: Option>, +} + +/// Parameters for the semantic highlighting (server-side) push notification. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingParams { + /// The text document that has to be decorated with the semantic highlighting information. + pub text_document: VersionedTextDocumentIdentifier, + + /// An array of semantic highlighting information. + pub lines: Vec, +} + +/// A set of predefined token types. This set is not fixed +/// and clients can specify additional token types via the +/// corresponding client capabilities. +/// +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +#[cfg(feature = "proposed")] +pub struct SemanticTokenType(Cow<'static, str>); + +#[cfg(feature = "proposed")] +impl SemanticTokenType { + pub const NAMESPACE: SemanticTokenType = SemanticTokenType::new("namespace"); + pub const TYPE: SemanticTokenType = SemanticTokenType::new("type"); + pub const CLASS: SemanticTokenType = SemanticTokenType::new("class"); + pub const ENUM: SemanticTokenType = SemanticTokenType::new("enum"); + pub const INTERFACE: SemanticTokenType = SemanticTokenType::new("interface"); + pub const STRUCT: SemanticTokenType = SemanticTokenType::new("struct"); + pub const TYPE_PARAMETER: SemanticTokenType = SemanticTokenType::new("typeParameter"); + pub const PARAMETER: SemanticTokenType = SemanticTokenType::new("parameter"); + pub const VARIABLE: SemanticTokenType = SemanticTokenType::new("variable"); + pub const PROPERTY: SemanticTokenType = SemanticTokenType::new("property"); + pub const ENUM_MEMBER: SemanticTokenType = SemanticTokenType::new("enumMember"); + pub const EVENT: SemanticTokenType = SemanticTokenType::new("event"); + pub const FUNCTION: SemanticTokenType = SemanticTokenType::new("function"); + pub const MEMBER: SemanticTokenType = SemanticTokenType::new("member"); + pub const MACRO: SemanticTokenType = SemanticTokenType::new("macro"); + pub const KEYWORD: SemanticTokenType = SemanticTokenType::new("keyword"); + pub const MODIFIER: SemanticTokenType = SemanticTokenType::new("modifier"); + pub const COMMENT: SemanticTokenType = SemanticTokenType::new("comment"); + pub const STRING: SemanticTokenType = SemanticTokenType::new("string"); + pub const NUMBER: SemanticTokenType = SemanticTokenType::new("number"); + pub const REGEXP: SemanticTokenType = SemanticTokenType::new("regexp"); + pub const OPERATOR: SemanticTokenType = SemanticTokenType::new("operator"); + + pub const fn new(tag: &'static str) -> Self { + SemanticTokenType(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokenType { + fn from(from: String) -> Self { + SemanticTokenType(Cow::from(from)) + } +} +#[cfg(feature = "proposed")] +impl From<&'static str> for SemanticTokenType { + fn from(from: &'static str) -> Self { + SemanticTokenType::new(from) + } +} + +/// A set of predefined token modifiers. This set is not fixed +/// and clients can specify additional token types via the +/// corresponding client capabilities. +/// +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +#[cfg(feature = "proposed")] +pub struct SemanticTokenModifier(Cow<'static, str>); + +#[cfg(feature = "proposed")] +impl SemanticTokenModifier { + pub const DECLARATION: SemanticTokenModifier = SemanticTokenModifier::new("declaration"); + pub const DEFINITION: SemanticTokenModifier = SemanticTokenModifier::new("definition"); + pub const READONLY: SemanticTokenModifier = SemanticTokenModifier::new("readonly"); + pub const STATIC: SemanticTokenModifier = SemanticTokenModifier::new("static"); + pub const DEPRECATED: SemanticTokenModifier = SemanticTokenModifier::new("deprecated"); + pub const ABSTRACT: SemanticTokenModifier = SemanticTokenModifier::new("abstract"); + pub const ASYNC: SemanticTokenModifier = SemanticTokenModifier::new("async"); + pub const MODIFICATION: SemanticTokenModifier = SemanticTokenModifier::new("modification"); + pub const DOCUMENTATION: SemanticTokenModifier = SemanticTokenModifier::new("documentation"); + pub const DEFAULT_LIBRARY: SemanticTokenModifier = SemanticTokenModifier::new("defaultLibrary"); + + pub const fn new(tag: &'static str) -> Self { + SemanticTokenModifier(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokenModifier { + fn from(from: String) -> Self { + SemanticTokenModifier(Cow::from(from)) + } +} +#[cfg(feature = "proposed")] +impl From<&'static str> for SemanticTokenModifier { + fn from(from: &'static str) -> Self { + SemanticTokenModifier::new(from) + } +} + +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +#[cfg(feature = "proposed")] +pub struct TokenFormat(Cow<'static, str>); + +#[cfg(feature = "proposed")] +impl TokenFormat { + pub const RELATIVE: TokenFormat = TokenFormat::new("relative"); + + pub const fn new(tag: &'static str) -> Self { + TokenFormat(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[cfg(feature = "proposed")] +impl From for TokenFormat { + fn from(from: String) -> Self { + TokenFormat(Cow::from(from)) + } +} +#[cfg(feature = "proposed")] +impl From<&'static str> for TokenFormat { + fn from(from: &'static str) -> Self { + TokenFormat::new(from) + } +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensLegend { + /// The token types a server uses. + pub token_types: Vec, + + /// The token modifiers a server uses. + pub token_modifiers: Vec, +} + +/// The actual tokens. For a detailed description about how the data is +/// structured please see +/// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 +#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] +#[cfg(feature = "proposed")] +pub struct SemanticToken { + pub delta_line: u32, + pub delta_start: u32, + pub length: u32, + pub token_type: u32, + pub token_modifiers_bitset: u32, +} + +#[cfg(feature = "proposed")] +impl SemanticToken { + fn deserialize_tokens<'de, D>(deserializer: D) -> Result, D::Error> + where + D: serde::Deserializer<'de>, + { + let data = Vec::::deserialize(deserializer)?; + let chunks = data.chunks_exact(5); + + if !chunks.remainder().is_empty() { + return Result::Err(serde::de::Error::custom("Length is not divisible by 5")); + } + + Result::Ok( + chunks + .map(|chunk| SemanticToken { + delta_line: chunk[0], + delta_start: chunk[1], + length: chunk[2], + token_type: chunk[3], + token_modifiers_bitset: chunk[4], + }) + .collect(), + ) + } + + fn serialize_tokens(tokens: &[SemanticToken], serializer: S) -> Result + where + S: serde::Serializer, + { + let mut seq = serializer.serialize_seq(Some(tokens.len() * 5))?; + for token in tokens.iter() { + seq.serialize_element(&token.delta_line)?; + seq.serialize_element(&token.delta_start)?; + seq.serialize_element(&token.length)?; + seq.serialize_element(&token.token_type)?; + seq.serialize_element(&token.token_modifiers_bitset)?; + } + seq.end() + } + + fn deserialize_tokens_opt<'de, D>( + deserializer: D, + ) -> Result>, D::Error> + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(transparent)] + struct Wrapper { + #[serde(deserialize_with = "SemanticToken::deserialize_tokens")] + tokens: Vec, + } + + Ok(Option::::deserialize(deserializer)?.map(|wrapper| wrapper.tokens)) + } + + fn serialize_tokens_opt( + data: &Option>, + serializer: S, + ) -> Result + where + S: serde::Serializer, + { + #[derive(Serialize)] + #[serde(transparent)] + struct Wrapper { + #[serde(serialize_with = "SemanticToken::serialize_tokens")] + tokens: Vec, + } + + let opt = data.as_ref().map(|t| Wrapper { tokens: t.to_vec() }); + + opt.serialize(serializer) + } +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokens { + /// An optional result id. If provided and clients support delta updating + /// the client will include the result id in the next semantic token request. + /// A server can then instead of computing all semantic tokens again simply + /// send a delta. + #[serde(skip_serializing_if = "Option::is_none")] + pub result_id: Option, + + /// The actual tokens. For a detailed description about how the data is + /// structured please see + /// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 + #[serde( + deserialize_with = "SemanticToken::deserialize_tokens", + serialize_with = "SemanticToken::serialize_tokens" + )] + pub data: Vec, +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensPartialResult { + #[serde( + deserialize_with = "SemanticToken::deserialize_tokens", + serialize_with = "SemanticToken::serialize_tokens" + )] + pub data: Vec, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensResult { + Tokens(SemanticTokens), + Partial(SemanticTokensPartialResult), +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensResult { + fn from(from: SemanticTokens) -> Self { + SemanticTokensResult::Tokens(from) + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensResult { + fn from(from: SemanticTokensPartialResult) -> Self { + SemanticTokensResult::Partial(from) + } +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensEdit { + pub start: u32, + pub delete_count: u32, + + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "SemanticToken::deserialize_tokens_opt", + serialize_with = "SemanticToken::serialize_tokens_opt" + )] + pub data: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensFullDeltaResult { + Tokens(SemanticTokens), + TokensDelta(SemanticTokensDelta), + PartialTokensDelta { edits: Vec }, +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensFullDeltaResult { + fn from(from: SemanticTokens) -> Self { + SemanticTokensFullDeltaResult::Tokens(from) + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensFullDeltaResult { + fn from(from: SemanticTokensDelta) -> Self { + SemanticTokensFullDeltaResult::TokensDelta(from) + } +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensDelta { + #[serde(skip_serializing_if = "Option::is_none")] + pub result_id: Option, + /// For a detailed description how these edits are structured pls see + /// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L131 + pub edits: Vec, +} + +/// Capabilities specific to the `textDocument/semanticTokens/*` requests. +/// +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensClientCapabilities { + /// Whether implementation supports dynamic registration. If this is set to `true` + /// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` + /// return value for the corresponding server capability as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Which requests the client supports and might send to the server. + pub requests: SemanticTokensClientCapabilitiesRequests, + + /// The token types that the client supports. + pub token_types: Vec, + + /// The token modifiers that the client supports. + pub token_modifiers: Vec, + + /// The formats the clients supports. + pub formats: Vec, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensClientCapabilitiesRequests { + /// The client will send the `textDocument/semanticTokens/range` request if the server provides a corresponding handler. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + + /// The client will send the `textDocument/semanticTokens/full` request if the server provides a corresponding handler. + #[serde(skip_serializing_if = "Option::is_none")] + pub full: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensFullOptions { + Bool(bool), + Delta { + /// The client will send the `textDocument/semanticTokens/full/delta` request if the server provides a corresponding handler. + /// The server supports deltas for full documents. + #[serde(skip_serializing_if = "Option::is_none")] + delta: Option, + }, +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, + + /// The legend used by the server + pub legend: SemanticTokensLegend, + + /// Server supports providing semantic tokens for a sepcific range + /// of a document. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + + /// Server supports providing semantic tokens for a full document. + #[serde(skip_serializing_if = "Option::is_none")] + pub full: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub semantic_tokens_options: SemanticTokensOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensServerCapabilities { + SemanticTokensOptions(SemanticTokensOptions), + SemanticTokensRegistrationOptions(SemanticTokensRegistrationOptions), +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensServerCapabilities { + fn from(from: SemanticTokensOptions) -> Self { + SemanticTokensServerCapabilities::SemanticTokensOptions(from) + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensServerCapabilities { + fn from(from: SemanticTokensRegistrationOptions) -> Self { + SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensDeltaParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The result id of a previous response. The result Id can either point to a full response + /// or a delta response depending on what was recevied last. + pub previous_result_id: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensRangeParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The range the semantic tokens are requested for. + pub range: Range, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensRangeResult { + Tokens(SemanticTokens), + Partial(SemanticTokensPartialResult), +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensRangeResult { + fn from(tokens: SemanticTokens) -> Self { + SemanticTokensRangeResult::Tokens(tokens) + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensRangeResult { + fn from(partial: SemanticTokensPartialResult) -> Self { + SemanticTokensRangeResult::Partial(partial) + } +} + +/// Symbol tags are extra annotations that tweak the rendering of a symbol. +/// Since 3.15 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +#[cfg(feature = "proposed")] +pub enum SymbolTag { + /// Render a symbol as obsolete, usually using a strike-out. + Deprecated = 1, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum CallHierarchyServerCapability { + Simple(bool), + Options(CallHierarchyOptions), +} + +#[cfg(feature = "proposed")] +impl From for CallHierarchyServerCapability { + fn from(from: CallHierarchyOptions) -> Self { + Self::Options(from) + } +} + +#[cfg(feature = "proposed")] +impl From for CallHierarchyServerCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyPrepareParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyItem { + /// The name of this item. + pub name: String, + + /// The kind of this item. + pub kind: SymbolKind, + + /// Tags for this item. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, + + /// More detail for this item, e.g. the signature of a function. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + + /// The resource identifier of this item. + pub uri: Url, + + /// The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + pub range: Range, + + /// The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. + /// Must be contained by the [`range`](#CallHierarchyItem.range). + pub selection_range: Range, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyIncomingCallsParams { + pub item: CallHierarchyItem, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents an incoming call, e.g. a caller of a method or constructor. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyIncomingCall { + /// The item that makes the call. + pub from: CallHierarchyItem, + + /// The range at which at which the calls appears. This is relative to the caller + /// denoted by [`this.from`](#CallHierarchyIncomingCall.from). + pub from_ranges: Vec, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyOutgoingCallsParams { + pub item: CallHierarchyItem, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyOutgoingCall { + /// The item that is called. + pub to: CallHierarchyItem, + + /// The range at which this item is called. This is the range relative to the caller, e.g the item + /// passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls) + /// and not [`this.to`](#CallHierarchyOutgoingCall.to). + pub from_ranges: Vec, +} + +#[cfg(test)] +mod tests { + use super::*; + use serde::{Deserialize, Serialize}; + + fn test_serialization(ms: &SER, expected: &str) + where + SER: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, + { + let json_str = serde_json::to_string(ms).unwrap(); + assert_eq!(&json_str, expected); + let deserialized: SER = serde_json::from_str(&json_str).unwrap(); + assert_eq!(&deserialized, ms); + } + + fn test_deserialization(json: &str, expected: &T) + where + T: for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, + { + let value = serde_json::from_str::(json).unwrap(); + assert_eq!(&value, expected); + } + + #[test] + fn number_or_string() { + test_serialization(&NumberOrString::Number(123), r#"123"#); + + test_serialization(&NumberOrString::String("abcd".into()), r#""abcd""#); + } + + #[test] + fn marked_string() { + test_serialization(&MarkedString::from_markdown("xxx".into()), r#""xxx""#); + + test_serialization( + &MarkedString::from_language_code("lang".into(), "code".into()), + r#"{"language":"lang","value":"code"}"#, + ); + } + + #[test] + fn language_string() { + test_serialization( + &LanguageString { + language: "LL".into(), + value: "VV".into(), + }, + r#"{"language":"LL","value":"VV"}"#, + ); + } + + #[test] + fn workspace_edit() { + test_serialization( + &WorkspaceEdit { + changes: Some(vec![].into_iter().collect()), + document_changes: None, + }, + r#"{"changes":{}}"#, + ); + + test_serialization( + &WorkspaceEdit { + changes: None, + document_changes: None, + }, + r#"{}"#, + ); + + test_serialization( + &WorkspaceEdit { + changes: Some( + vec![(Url::parse("file://test").unwrap(), vec![])] + .into_iter() + .collect(), + ), + document_changes: None, + }, + r#"{"changes":{"file://test/":[]}}"#, + ); + } + + #[test] + fn formatting_options() { + test_serialization( + &FormattingOptions { + tab_size: 123, + insert_spaces: true, + properties: HashMap::new(), + trim_trailing_whitespace: None, + insert_final_newline: None, + trim_final_newlines: None, + }, + r#"{"tabSize":123,"insertSpaces":true}"#, + ); + + test_serialization( + &FormattingOptions { + tab_size: 123, + insert_spaces: true, + properties: vec![("prop".to_string(), FormattingProperty::Number(1.0))] + .into_iter() + .collect(), + trim_trailing_whitespace: None, + insert_final_newline: None, + trim_final_newlines: None, + }, + r#"{"tabSize":123,"insertSpaces":true,"prop":1.0}"#, + ); + } + + #[test] + fn root_uri_can_be_missing() { + serde_json::from_str::(r#"{ "capabilities": {} }"#).unwrap(); + } + + #[test] + fn test_watch_kind() { + test_serialization(&WatchKind::Create, "1"); + test_serialization(&(WatchKind::Create | WatchKind::Change), "3"); + test_serialization( + &(WatchKind::Create | WatchKind::Change | WatchKind::Delete), + "7", + ); + } + + #[test] + fn test_resource_operation_kind() { + test_serialization( + &vec![ + ResourceOperationKind::Create, + ResourceOperationKind::Rename, + ResourceOperationKind::Delete, + ], + r#"["create","rename","delete"]"#, + ); + } + + #[test] + fn test_code_action_response() { + test_serialization( + &vec![ + CodeActionOrCommand::Command(Command { + title: "title".to_string(), + command: "command".to_string(), + arguments: None, + }), + CodeActionOrCommand::CodeAction(CodeAction { + title: "title".to_string(), + kind: Some(CodeActionKind::QUICKFIX), + command: None, + diagnostics: None, + edit: None, + is_preferred: None, + }), + ], + r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#, + ) + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_highlighting_information_serialization() { + test_serialization( + &SemanticHighlightingInformation { + line: 10, + tokens: Some(vec![ + SemanticHighlightingToken { + character: 0x00000001, + length: 0x0002, + scope: 0x0003, + }, + SemanticHighlightingToken { + character: 0x00112222, + length: 0x0FF0, + scope: 0x0202, + }, + ]), + }, + r#"{"line":10,"tokens":"AAAAAQACAAMAESIiD/ACAg=="}"#, + ); + + test_serialization( + &SemanticHighlightingInformation { + line: 22, + tokens: None, + }, + r#"{"line":22}"#, + ); + } + + #[test] + fn test_tag_support_deserialization() { + let mut empty = CompletionItemCapability::default(); + empty.tag_support = None; + + test_deserialization(r#"{}"#, &empty); + test_deserialization(r#"{"tagSupport": false}"#, &empty); + + let mut t = CompletionItemCapability::default(); + t.tag_support = Some(TagSupport { value_set: vec![] }); + test_deserialization(r#"{"tagSupport": true}"#, &t); + + let mut t = CompletionItemCapability::default(); + t.tag_support = Some(TagSupport { + value_set: vec![CompletionItemTag::Deprecated], + }); + test_deserialization(r#"{"tagSupport": {"valueSet": [1]}}"#, &t); + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_tokens_support_serialization() { + test_serialization( + &SemanticTokens { + result_id: None, + data: vec![], + }, + r#"{"data":[]}"#, + ); + + test_serialization( + &SemanticTokens { + result_id: None, + data: vec![SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }], + }, + r#"{"data":[2,5,3,0,3]}"#, + ); + + test_serialization( + &SemanticTokens { + result_id: None, + data: vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ], + }, + r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, + ); + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_tokens_support_deserialization() { + test_deserialization( + r#"{"data":[]}"#, + &SemanticTokens { + result_id: None, + data: vec![], + }, + ); + + test_deserialization( + r#"{"data":[2,5,3,0,3]}"#, + &SemanticTokens { + result_id: None, + data: vec![SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }], + }, + ); + + test_deserialization( + r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, + &SemanticTokens { + result_id: None, + data: vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ], + }, + ); + } + + #[cfg(feature = "proposed")] + #[test] + #[should_panic] + fn test_semantic_tokens_support_deserialization_err() { + test_deserialization( + r#"{"data":[1]}"#, + &SemanticTokens { + result_id: None, + data: vec![], + }, + ); + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_tokens_edit_support_deserialization() { + test_deserialization( + r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: Some(vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ]), + }, + ); + + test_deserialization( + r#"{"start":0,"deleteCount":1}"#, + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: None, + }, + ); + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_tokens_edit_support_serialization() { + test_serialization( + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: Some(vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ]), + }, + r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, + ); + + test_serialization( + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: None, + }, + r#"{"start":0,"deleteCount":1}"#, + ); + } +} diff --git a/vendor/lsp-types/src/notification.rs b/vendor/lsp-types/src/notification.rs index 272eb27c7f..3468cf1ed3 100644 --- a/vendor/lsp-types/src/notification.rs +++ b/vendor/lsp-types/src/notification.rs @@ -1,304 +1,304 @@ -use super::*; - -use serde::{de::DeserializeOwned, Serialize}; - -pub trait Notification { - type Params: DeserializeOwned + Serialize; - const METHOD: &'static str; -} - -#[macro_export] -macro_rules! lsp_notification { - ("$/cancelRequest") => { - $crate::notification::Cancel - }; - ("initialized") => { - $crate::notification::Initialized - }; - ("exit") => { - $crate::notification::Exit - }; - - ("window/showMessage") => { - $crate::notification::ShowMessage - }; - ("window/logMessage") => { - $crate::notification::LogMessage - }; - ("window/workDoneProgress/cancel") => { - $crate::notification::WorkDoneProgressCancel - }; - - ("telemetry/event") => { - $crate::notification::TelemetryEvent - }; - - ("textDocument/didOpen") => { - $crate::notification::DidOpenTextDocument - }; - ("textDocument/didChange") => { - $crate::notification::DidChangeTextDocument - }; - ("textDocument/willSave") => { - $crate::notification::WillSaveTextDocument - }; - ("textDocument/didSave") => { - $crate::notification::DidSaveTextDocument - }; - ("textDocument/didClose") => { - $crate::notification::DidCloseTextDocument - }; - ("textDocument/publishDiagnostics") => { - $crate::notification::PublishDiagnostics - }; - - ("workspace/didChangeConfiguration") => { - $crate::notification::DidChangeConfiguration - }; - ("workspace/didChangeWatchedFiles") => { - $crate::notification::DidChangeWatchedFiles - }; - ("workspace/didChangeWorkspaceFolders") => { - $crate::notification::DidChangeWorkspaceFolders - }; - ("$/progress") => { - $crate::notification::Progress - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/semanticHighlighting") => { - $crate::notification::SemanticHighlighting - }; -} - -/// The base protocol now offers support for request cancellation. To cancel a request, -/// a notification message with the following properties is sent: -/// -/// A request that got canceled still needs to return from the server and send a response back. -/// It can not be left open / hanging. This is in line with the JSON RPC protocol that requires -/// that every request sends a response back. In addition it allows for returning partial results on cancel. -#[derive(Debug)] -pub enum Cancel {} - -impl Notification for Cancel { - type Params = CancelParams; - const METHOD: &'static str = "$/cancelRequest"; -} - -/// The initialized notification is sent from the client to the server after the client received -/// the result of the initialize request but before the client is sending any other request or -/// notification to the server. The server can use the initialized notification for example to -/// dynamically register capabilities. -#[derive(Debug)] -pub enum Initialized {} - -impl Notification for Initialized { - type Params = InitializedParams; - const METHOD: &'static str = "initialized"; -} - -/// A notification to ask the server to exit its process. -/// The server should exit with success code 0 if the shutdown request has been received before; -/// otherwise with error code 1. -#[derive(Debug)] -pub enum Exit {} - -impl Notification for Exit { - type Params = (); - const METHOD: &'static str = "exit"; -} - -/// The show message notification is sent from a server to a client to ask the client to display a particular message -/// in the user interface. -#[derive(Debug)] -pub enum ShowMessage {} - -impl Notification for ShowMessage { - type Params = ShowMessageParams; - const METHOD: &'static str = "window/showMessage"; -} - -/// The log message notification is sent from the server to the client to ask the client to log a particular message. -#[derive(Debug)] -pub enum LogMessage {} - -impl Notification for LogMessage { - type Params = LogMessageParams; - const METHOD: &'static str = "window/logMessage"; -} - -/// The telemetry notification is sent from the server to the client to ask the client to log a telemetry event. -#[derive(Debug)] -pub enum TelemetryEvent {} - -impl Notification for TelemetryEvent { - type Params = serde_json::Value; - const METHOD: &'static str = "telemetry/event"; -} - -/// A notification sent from the client to the server to signal the change of configuration settings. -#[derive(Debug)] -pub enum DidChangeConfiguration {} - -impl Notification for DidChangeConfiguration { - type Params = DidChangeConfigurationParams; - const METHOD: &'static str = "workspace/didChangeConfiguration"; -} - -/// The document open notification is sent from the client to the server to signal newly opened text documents. -/// The document's truth is now managed by the client and the server must not try to read the document's truth -/// using the document's uri. -#[derive(Debug)] -pub enum DidOpenTextDocument {} - -impl Notification for DidOpenTextDocument { - type Params = DidOpenTextDocumentParams; - const METHOD: &'static str = "textDocument/didOpen"; -} - -/// The document change notification is sent from the client to the server to signal changes to a text document. -/// In 2.0 the shape of the params has changed to include proper version numbers and language ids. -#[derive(Debug)] -pub enum DidChangeTextDocument {} - -impl Notification for DidChangeTextDocument { - type Params = DidChangeTextDocumentParams; - const METHOD: &'static str = "textDocument/didChange"; -} - -/// The document will save notification is sent from the client to the server before the document -/// is actually saved. -#[derive(Debug)] -pub enum WillSaveTextDocument {} - -impl Notification for WillSaveTextDocument { - type Params = WillSaveTextDocumentParams; - const METHOD: &'static str = "textDocument/willSave"; -} - -/// The document close notification is sent from the client to the server when the document got closed in the client. -/// The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri -/// the truth now exists on disk). -#[derive(Debug)] -pub enum DidCloseTextDocument {} - -impl Notification for DidCloseTextDocument { - type Params = DidCloseTextDocumentParams; - const METHOD: &'static str = "textDocument/didClose"; -} - -/// The document save notification is sent from the client to the server when the document was saved in the client. -#[derive(Debug)] -pub enum DidSaveTextDocument {} - -impl Notification for DidSaveTextDocument { - type Params = DidSaveTextDocumentParams; - const METHOD: &'static str = "textDocument/didSave"; -} - -/// The watched files notification is sent from the client to the server when the client detects changes to files -/// watched by the language client. -#[derive(Debug)] -pub enum DidChangeWatchedFiles {} - -impl Notification for DidChangeWatchedFiles { - type Params = DidChangeWatchedFilesParams; - const METHOD: &'static str = "workspace/didChangeWatchedFiles"; -} - -/// The workspace/didChangeWorkspaceFolders notification is sent from the client to the server to inform the server -/// about workspace folder configuration changes -#[derive(Debug)] -pub enum DidChangeWorkspaceFolders {} - -impl Notification for DidChangeWorkspaceFolders { - type Params = DidChangeWorkspaceFoldersParams; - const METHOD: &'static str = "workspace/didChangeWorkspaceFolders"; -} - -/// Diagnostics notification are sent from the server to the client to signal results of validation runs. -#[derive(Debug)] -pub enum PublishDiagnostics {} - -impl Notification for PublishDiagnostics { - type Params = PublishDiagnosticsParams; - const METHOD: &'static str = "textDocument/publishDiagnostics"; -} - -/// The progress notification is sent from the server to the client to ask -/// the client to indicate progress. -#[derive(Debug)] -pub enum Progress {} - -impl Notification for Progress { - type Params = ProgressParams; - const METHOD: &'static str = "$/progress"; -} - -/// The `window/workDoneProgress/cancel` notification is sent from the client -/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. -#[derive(Debug)] -pub enum WorkDoneProgressCancel {} - -impl Notification for WorkDoneProgressCancel { - type Params = WorkDoneProgressCancelParams; - const METHOD: &'static str = "window/workDoneProgress/cancel"; -} - -#[cfg(feature = "proposed")] -/// Diagnostics notification are sent from the server to the client to signal results of validation runs. -#[derive(Debug)] -pub enum SemanticHighlighting {} - -#[cfg(feature = "proposed")] -impl Notification for SemanticHighlighting { - type Params = SemanticHighlightingParams; - const METHOD: &'static str = "textDocument/semanticHighlighting"; -} - -#[cfg(test)] -mod test { - use super::*; - - fn fake_call() - where - N: Notification, - N::Params: serde::Serialize, - { - } - - macro_rules! check_macro { - ($name:tt) => { - // check whether the macro name matches the method - assert_eq!(::METHOD, $name); - // test whether type checking passes for each component - fake_call::(); - }; - } - - #[test] - fn check_macro_definitions() { - check_macro!("$/cancelRequest"); - check_macro!("$/progress"); - check_macro!("initialized"); - check_macro!("exit"); - check_macro!("window/showMessage"); - check_macro!("window/logMessage"); - check_macro!("window/workDoneProgress/cancel"); - check_macro!("telemetry/event"); - check_macro!("textDocument/didOpen"); - check_macro!("textDocument/didChange"); - check_macro!("textDocument/willSave"); - check_macro!("textDocument/didSave"); - check_macro!("textDocument/didClose"); - check_macro!("textDocument/publishDiagnostics"); - check_macro!("workspace/didChangeConfiguration"); - check_macro!("workspace/didChangeWatchedFiles"); - check_macro!("workspace/didChangeWorkspaceFolders"); - } - - #[test] - #[cfg(feature = "proposed")] - fn check_proposed_macro_definitions() { - check_macro!("textDocument/semanticHighlighting"); - } -} +use super::*; + +use serde::{de::DeserializeOwned, Serialize}; + +pub trait Notification { + type Params: DeserializeOwned + Serialize; + const METHOD: &'static str; +} + +#[macro_export] +macro_rules! lsp_notification { + ("$/cancelRequest") => { + $crate::notification::Cancel + }; + ("initialized") => { + $crate::notification::Initialized + }; + ("exit") => { + $crate::notification::Exit + }; + + ("window/showMessage") => { + $crate::notification::ShowMessage + }; + ("window/logMessage") => { + $crate::notification::LogMessage + }; + ("window/workDoneProgress/cancel") => { + $crate::notification::WorkDoneProgressCancel + }; + + ("telemetry/event") => { + $crate::notification::TelemetryEvent + }; + + ("textDocument/didOpen") => { + $crate::notification::DidOpenTextDocument + }; + ("textDocument/didChange") => { + $crate::notification::DidChangeTextDocument + }; + ("textDocument/willSave") => { + $crate::notification::WillSaveTextDocument + }; + ("textDocument/didSave") => { + $crate::notification::DidSaveTextDocument + }; + ("textDocument/didClose") => { + $crate::notification::DidCloseTextDocument + }; + ("textDocument/publishDiagnostics") => { + $crate::notification::PublishDiagnostics + }; + + ("workspace/didChangeConfiguration") => { + $crate::notification::DidChangeConfiguration + }; + ("workspace/didChangeWatchedFiles") => { + $crate::notification::DidChangeWatchedFiles + }; + ("workspace/didChangeWorkspaceFolders") => { + $crate::notification::DidChangeWorkspaceFolders + }; + ("$/progress") => { + $crate::notification::Progress + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/semanticHighlighting") => { + $crate::notification::SemanticHighlighting + }; +} + +/// The base protocol now offers support for request cancellation. To cancel a request, +/// a notification message with the following properties is sent: +/// +/// A request that got canceled still needs to return from the server and send a response back. +/// It can not be left open / hanging. This is in line with the JSON RPC protocol that requires +/// that every request sends a response back. In addition it allows for returning partial results on cancel. +#[derive(Debug)] +pub enum Cancel {} + +impl Notification for Cancel { + type Params = CancelParams; + const METHOD: &'static str = "$/cancelRequest"; +} + +/// The initialized notification is sent from the client to the server after the client received +/// the result of the initialize request but before the client is sending any other request or +/// notification to the server. The server can use the initialized notification for example to +/// dynamically register capabilities. +#[derive(Debug)] +pub enum Initialized {} + +impl Notification for Initialized { + type Params = InitializedParams; + const METHOD: &'static str = "initialized"; +} + +/// A notification to ask the server to exit its process. +/// The server should exit with success code 0 if the shutdown request has been received before; +/// otherwise with error code 1. +#[derive(Debug)] +pub enum Exit {} + +impl Notification for Exit { + type Params = (); + const METHOD: &'static str = "exit"; +} + +/// The show message notification is sent from a server to a client to ask the client to display a particular message +/// in the user interface. +#[derive(Debug)] +pub enum ShowMessage {} + +impl Notification for ShowMessage { + type Params = ShowMessageParams; + const METHOD: &'static str = "window/showMessage"; +} + +/// The log message notification is sent from the server to the client to ask the client to log a particular message. +#[derive(Debug)] +pub enum LogMessage {} + +impl Notification for LogMessage { + type Params = LogMessageParams; + const METHOD: &'static str = "window/logMessage"; +} + +/// The telemetry notification is sent from the server to the client to ask the client to log a telemetry event. +#[derive(Debug)] +pub enum TelemetryEvent {} + +impl Notification for TelemetryEvent { + type Params = serde_json::Value; + const METHOD: &'static str = "telemetry/event"; +} + +/// A notification sent from the client to the server to signal the change of configuration settings. +#[derive(Debug)] +pub enum DidChangeConfiguration {} + +impl Notification for DidChangeConfiguration { + type Params = DidChangeConfigurationParams; + const METHOD: &'static str = "workspace/didChangeConfiguration"; +} + +/// The document open notification is sent from the client to the server to signal newly opened text documents. +/// The document's truth is now managed by the client and the server must not try to read the document's truth +/// using the document's uri. +#[derive(Debug)] +pub enum DidOpenTextDocument {} + +impl Notification for DidOpenTextDocument { + type Params = DidOpenTextDocumentParams; + const METHOD: &'static str = "textDocument/didOpen"; +} + +/// The document change notification is sent from the client to the server to signal changes to a text document. +/// In 2.0 the shape of the params has changed to include proper version numbers and language ids. +#[derive(Debug)] +pub enum DidChangeTextDocument {} + +impl Notification for DidChangeTextDocument { + type Params = DidChangeTextDocumentParams; + const METHOD: &'static str = "textDocument/didChange"; +} + +/// The document will save notification is sent from the client to the server before the document +/// is actually saved. +#[derive(Debug)] +pub enum WillSaveTextDocument {} + +impl Notification for WillSaveTextDocument { + type Params = WillSaveTextDocumentParams; + const METHOD: &'static str = "textDocument/willSave"; +} + +/// The document close notification is sent from the client to the server when the document got closed in the client. +/// The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri +/// the truth now exists on disk). +#[derive(Debug)] +pub enum DidCloseTextDocument {} + +impl Notification for DidCloseTextDocument { + type Params = DidCloseTextDocumentParams; + const METHOD: &'static str = "textDocument/didClose"; +} + +/// The document save notification is sent from the client to the server when the document was saved in the client. +#[derive(Debug)] +pub enum DidSaveTextDocument {} + +impl Notification for DidSaveTextDocument { + type Params = DidSaveTextDocumentParams; + const METHOD: &'static str = "textDocument/didSave"; +} + +/// The watched files notification is sent from the client to the server when the client detects changes to files +/// watched by the language client. +#[derive(Debug)] +pub enum DidChangeWatchedFiles {} + +impl Notification for DidChangeWatchedFiles { + type Params = DidChangeWatchedFilesParams; + const METHOD: &'static str = "workspace/didChangeWatchedFiles"; +} + +/// The workspace/didChangeWorkspaceFolders notification is sent from the client to the server to inform the server +/// about workspace folder configuration changes +#[derive(Debug)] +pub enum DidChangeWorkspaceFolders {} + +impl Notification for DidChangeWorkspaceFolders { + type Params = DidChangeWorkspaceFoldersParams; + const METHOD: &'static str = "workspace/didChangeWorkspaceFolders"; +} + +/// Diagnostics notification are sent from the server to the client to signal results of validation runs. +#[derive(Debug)] +pub enum PublishDiagnostics {} + +impl Notification for PublishDiagnostics { + type Params = PublishDiagnosticsParams; + const METHOD: &'static str = "textDocument/publishDiagnostics"; +} + +/// The progress notification is sent from the server to the client to ask +/// the client to indicate progress. +#[derive(Debug)] +pub enum Progress {} + +impl Notification for Progress { + type Params = ProgressParams; + const METHOD: &'static str = "$/progress"; +} + +/// The `window/workDoneProgress/cancel` notification is sent from the client +/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. +#[derive(Debug)] +pub enum WorkDoneProgressCancel {} + +impl Notification for WorkDoneProgressCancel { + type Params = WorkDoneProgressCancelParams; + const METHOD: &'static str = "window/workDoneProgress/cancel"; +} + +#[cfg(feature = "proposed")] +/// Diagnostics notification are sent from the server to the client to signal results of validation runs. +#[derive(Debug)] +pub enum SemanticHighlighting {} + +#[cfg(feature = "proposed")] +impl Notification for SemanticHighlighting { + type Params = SemanticHighlightingParams; + const METHOD: &'static str = "textDocument/semanticHighlighting"; +} + +#[cfg(test)] +mod test { + use super::*; + + fn fake_call() + where + N: Notification, + N::Params: serde::Serialize, + { + } + + macro_rules! check_macro { + ($name:tt) => { + // check whether the macro name matches the method + assert_eq!(::METHOD, $name); + // test whether type checking passes for each component + fake_call::(); + }; + } + + #[test] + fn check_macro_definitions() { + check_macro!("$/cancelRequest"); + check_macro!("$/progress"); + check_macro!("initialized"); + check_macro!("exit"); + check_macro!("window/showMessage"); + check_macro!("window/logMessage"); + check_macro!("window/workDoneProgress/cancel"); + check_macro!("telemetry/event"); + check_macro!("textDocument/didOpen"); + check_macro!("textDocument/didChange"); + check_macro!("textDocument/willSave"); + check_macro!("textDocument/didSave"); + check_macro!("textDocument/didClose"); + check_macro!("textDocument/publishDiagnostics"); + check_macro!("workspace/didChangeConfiguration"); + check_macro!("workspace/didChangeWatchedFiles"); + check_macro!("workspace/didChangeWorkspaceFolders"); + } + + #[test] + #[cfg(feature = "proposed")] + fn check_proposed_macro_definitions() { + check_macro!("textDocument/semanticHighlighting"); + } +} diff --git a/vendor/lsp-types/src/request.rs b/vendor/lsp-types/src/request.rs index 53073a96e4..3238697776 100644 --- a/vendor/lsp-types/src/request.rs +++ b/vendor/lsp-types/src/request.rs @@ -1,739 +1,739 @@ -use super::*; - -use serde::{de::DeserializeOwned, Serialize}; - -pub trait Request { - type Params: DeserializeOwned + Serialize; - type Result: DeserializeOwned + Serialize; - const METHOD: &'static str; -} - -#[macro_export] -macro_rules! lsp_request { - ("initialize") => { - $crate::request::Initialize - }; - ("shutdown") => { - $crate::request::Shutdown - }; - - ("window/showMessageRequest") => { - $crate::request::ShowMessageRequest - }; - - ("client/registerCapability") => { - $crate::request::RegisterCapability - }; - ("client/unregisterCapability") => { - $crate::request::UnregisterCapability - }; - - ("workspace/symbol") => { - $crate::request::WorkspaceSymbol - }; - ("workspace/executeCommand") => { - $crate::request::ExecuteCommand - }; - - ("textDocument/willSaveWaitUntil") => { - $crate::request::WillSaveWaitUntil - }; - - ("textDocument/completion") => { - $crate::request::Completion - }; - ("completionItem/resolve") => { - $crate::request::ResolveCompletionItem - }; - ("textDocument/hover") => { - $crate::request::HoverRequest - }; - ("textDocument/signatureHelp") => { - $crate::request::SignatureHelpRequest - }; - ("textDocument/declaration") => { - $crate::request::GotoDeclaration - }; - ("textDocument/definition") => { - $crate::request::GotoDefinition - }; - ("textDocument/references") => { - $crate::request::References - }; - ("textDocument/documentHighlight") => { - $crate::request::DocumentHighlightRequest - }; - ("textDocument/documentSymbol") => { - $crate::request::DocumentSymbolRequest - }; - ("textDocument/codeAction") => { - $crate::request::CodeActionRequest - }; - ("textDocument/codeLens") => { - $crate::request::CodeLensRequest - }; - ("codeLens/resolve") => { - $crate::request::CodeLensResolve - }; - ("textDocument/documentLink") => { - $crate::request::DocumentLinkRequest - }; - ("documentLink/resolve") => { - $crate::request::DocumentLinkResolve - }; - ("workspace/applyEdit") => { - $crate::request::ApplyWorkspaceEdit - }; - ("textDocument/rangeFormatting") => { - $crate::request::RangeFormatting - }; - ("textDocument/onTypeFormatting") => { - $crate::request::OnTypeFormatting - }; - ("textDocument/formatting") => { - $crate::request::Formatting - }; - ("textDocument/rename") => { - $crate::request::Rename - }; - ("textDocument/documentColor") => { - $crate::request::DocumentColor - }; - ("textDocument/colorPresentation") => { - $crate::request::ColorPresentationRequest - }; - ("textDocument/foldingRange") => { - $crate::request::FoldingRangeRequest - }; - ("textDocument/prepareRename") => { - $crate::request::PrepareRenameRequest - }; - ("textDocument/implementation") => { - $crate::request::GotoImplementation - }; - ("textDocument/typeDefinition") => { - $crate::request::GotoTypeDefinition - }; - ("textDocument/selectionRange") => { - $crate::request::SelectionRangeRequest - }; - ("workspace/workspaceFolders") => { - $crate::request::WorkspaceFoldersRequest - }; - ("workspace/configuration") => { - $crate::request::WorkspaceConfiguration - }; - ("window/workDoneProgress/create") => { - $crate::request::WorkDoneProgressCreate - }; - // Requires #[cfg(feature = "proposed")] - ("callHierarchy/incomingCalls") => { - $crate::request::CallHierarchyIncomingCalls - }; - // Requires #[cfg(feature = "proposed")] - ("callHierarchy/outgoingCalls") => { - $crate::request::CallHierarchyOutgoingCalls - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/prepareCallHierarchy") => { - $crate::request::CallHierarchyPrepare - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/semanticTokens") => { - $crate::request::SemanticTokensRequest - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/semanticTokens/edits") => { - $crate::request::SemanticTokensEditsRequest - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/semanticTokens/range") => { - $crate::request::SemanticTokensRangeRequest - }; -} - -/// The initialize request is sent as the first request from the client to the server. -/// If the server receives request or notification before the `initialize` request it should act as follows: -/// -/// * for a request the respond should be errored with `code: -32001`. The message can be picked by the server. -/// * notifications should be dropped. -#[derive(Debug)] -pub enum Initialize {} - -impl Request for Initialize { - type Params = InitializeParams; - type Result = InitializeResult; - const METHOD: &'static str = "initialize"; -} - -/// The shutdown request is sent from the client to the server. It asks the server to shut down, -/// but to not exit (otherwise the response might not be delivered correctly to the client). -/// There is a separate exit notification that asks the server to exit. -#[derive(Debug)] -pub enum Shutdown {} - -impl Request for Shutdown { - type Params = (); - type Result = (); - const METHOD: &'static str = "shutdown"; -} - -/// The show message request is sent from a server to a client to ask the client to display a particular message -/// in the user interface. In addition to the show message notification the request allows to pass actions and to -/// wait for an answer from the client. -#[derive(Debug)] -pub enum ShowMessageRequest {} - -impl Request for ShowMessageRequest { - type Params = ShowMessageRequestParams; - type Result = Option; - const METHOD: &'static str = "window/showMessageRequest"; -} - -/// The client/registerCapability request is sent from the server to the client to register for a new capability -/// on the client side. Not all clients need to support dynamic capability registration. A client opts in via the -/// ClientCapabilities.GenericCapability property. -#[derive(Debug)] -pub enum RegisterCapability {} - -impl Request for RegisterCapability { - type Params = RegistrationParams; - type Result = (); - const METHOD: &'static str = "client/registerCapability"; -} - -/// The client/unregisterCapability request is sent from the server to the client to unregister a -/// previously register capability. -#[derive(Debug)] -pub enum UnregisterCapability {} - -impl Request for UnregisterCapability { - type Params = UnregistrationParams; - type Result = (); - const METHOD: &'static str = "client/unregisterCapability"; -} - -/// The Completion request is sent from the client to the server to compute completion items at a given cursor position. -/// Completion items are presented in the IntelliSense user interface. If computing full completion items is expensive, -/// servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve'). -/// This request is sent when a completion item is selected in the user interface. A typical use case is for example: -/// the 'textDocument/completion' request doesn’t fill in the documentation property for returned completion items -/// since it is expensive to compute. When the item is selected in the user interface then a ‘completionItem/resolve’ -/// request is sent with the selected completion item as a param. The returned completion item should have the -/// documentation property filled in. The request can delay the computation of the detail and documentation properties. -/// However, properties that are needed for the initial sorting and filtering, like sortText, filterText, insertText, -/// and textEdit must be provided in the textDocument/completion request and must not be changed during resolve. -#[derive(Debug)] -pub enum Completion {} - -impl Request for Completion { - type Params = CompletionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/completion"; -} - -/// The request is sent from the client to the server to resolve additional information for a given completion item. -#[derive(Debug)] -pub enum ResolveCompletionItem {} - -impl Request for ResolveCompletionItem { - type Params = CompletionItem; - type Result = CompletionItem; - const METHOD: &'static str = "completionItem/resolve"; -} - -/// The hover request is sent from the client to the server to request hover information at a given text -/// document position. -#[derive(Debug)] -pub enum HoverRequest {} - -impl Request for HoverRequest { - type Params = HoverParams; - type Result = Option; - const METHOD: &'static str = "textDocument/hover"; -} - -/// The signature help request is sent from the client to the server to request signature information at -/// a given cursor position. -#[derive(Debug)] -pub enum SignatureHelpRequest {} - -impl Request for SignatureHelpRequest { - type Params = SignatureHelpParams; - type Result = Option; - const METHOD: &'static str = "textDocument/signatureHelp"; -} - -#[derive(Debug)] -pub enum GotoDeclaration {} -pub type GotoDeclarationParams = GotoDefinitionParams; -pub type GotoDeclarationResponse = GotoDefinitionResponse; - -/// The goto declaration request is sent from the client to the server to resolve the declaration location of -/// a symbol at a given text document position. -impl Request for GotoDeclaration { - type Params = GotoDeclarationParams; - type Result = Option; - const METHOD: &'static str = "textDocument/declaration"; -} - -/// The goto definition request is sent from the client to the server to resolve the definition location of -/// a symbol at a given text document position. -#[derive(Debug)] -pub enum GotoDefinition {} - -impl Request for GotoDefinition { - type Params = GotoDefinitionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/definition"; -} - -/// The references request is sent from the client to the server to resolve project-wide references for the -/// symbol denoted by the given text document position. -#[derive(Debug)] -pub enum References {} - -impl Request for References { - type Params = ReferenceParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/references"; -} - -/// The goto type definition request is sent from the client to the -/// server to resolve the type definition location of a symbol at a -/// given text document position. -#[derive(Debug)] -pub enum GotoTypeDefinition {} - -pub type GotoTypeDefinitionParams = GotoDefinitionParams; -pub type GotoTypeDefinitionResponse = GotoDefinitionResponse; - -impl Request for GotoTypeDefinition { - type Params = GotoTypeDefinitionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/typeDefinition"; -} - -/// The goto implementation request is sent from the client to the -/// server to resolve the implementation location of a symbol at a -/// given text document position. -#[derive(Debug)] -pub enum GotoImplementation {} - -pub type GotoImplementationParams = GotoTypeDefinitionParams; -pub type GotoImplementationResponse = GotoDefinitionResponse; - -impl Request for GotoImplementation { - type Params = GotoImplementationParams; - type Result = Option; - const METHOD: &'static str = "textDocument/implementation"; -} - -/// The document highlight request is sent from the client to the server to resolve a document highlights -/// for a given text document position. -/// For programming languages this usually highlights all references to the symbol scoped to this file. -/// However we kept 'textDocument/documentHighlight' and 'textDocument/references' separate requests since -/// the first one is allowed to be more fuzzy. -/// Symbol matches usually have a DocumentHighlightKind of Read or Write whereas fuzzy or textual matches -/// use Text as the kind. -#[derive(Debug)] -pub enum DocumentHighlightRequest {} - -impl Request for DocumentHighlightRequest { - type Params = DocumentHighlightParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/documentHighlight"; -} - -/// The document symbol request is sent from the client to the server to list all symbols found in a given -/// text document. -#[derive(Debug)] -pub enum DocumentSymbolRequest {} - -impl Request for DocumentSymbolRequest { - type Params = DocumentSymbolParams; - type Result = Option; - const METHOD: &'static str = "textDocument/documentSymbol"; -} - -/// The workspace symbol request is sent from the client to the server to list project-wide symbols -/// matching the query string. -#[derive(Debug)] -pub enum WorkspaceSymbol {} - -impl Request for WorkspaceSymbol { - type Params = WorkspaceSymbolParams; - type Result = Option>; - const METHOD: &'static str = "workspace/symbol"; -} - -/// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. -/// In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request -/// workspace/applyEdit which is sent from the server to the client. -#[derive(Debug)] -pub enum ExecuteCommand {} - -impl Request for ExecuteCommand { - type Params = ExecuteCommandParams; - type Result = Option; - const METHOD: &'static str = "workspace/executeCommand"; -} - -/// The document will save request is sent from the client to the server before the document is -/// actually saved. The request can return an array of TextEdits which will be applied to the text -/// document before it is saved. Please note that clients might drop results if computing the text -/// edits took too long or if a server constantly fails on this request. This is done to keep the -/// save fast and reliable. -#[derive(Debug)] -pub enum WillSaveWaitUntil {} - -impl Request for WillSaveWaitUntil { - type Params = WillSaveTextDocumentParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/willSaveWaitUntil"; -} - -/// The workspace/applyEdit request is sent from the server to the client to modify resource on the -/// client side. -#[derive(Debug)] -pub enum ApplyWorkspaceEdit {} - -impl Request for ApplyWorkspaceEdit { - type Params = ApplyWorkspaceEditParams; - type Result = ApplyWorkspaceEditResponse; - const METHOD: &'static str = "workspace/applyEdit"; -} - -/// The workspace/configuration request is sent from the server to the client to fetch configuration settings -/// from the client. The request can fetch several configuration settings in one roundtrip. -/// The order of the returned configuration settings correspond to the order of the passed ConfigurationItems -/// (e.g. the first item in the response is the result for the first configuration item in the params). -/// -/// A ConfigurationItem consists of the configuration section to ask for and an additional scope URI. -/// The configuration section ask for is defined by the server and doesn’t necessarily need to correspond to -/// the configuration store used be the client. So a server might ask for a configuration cpp.formatterOptions -/// but the client stores the configuration in a XML store layout differently. -/// It is up to the client to do the necessary conversion. If a scope URI is provided the client should return -/// the setting scoped to the provided resource. If the client for example uses EditorConfig to manage its -/// settings the configuration should be returned for the passed resource URI. If the client can’t provide a -/// configuration setting for a given scope then null need to be present in the returned array. -#[derive(Debug)] -pub enum WorkspaceConfiguration {} - -impl Request for WorkspaceConfiguration { - type Params = ConfigurationParams; - type Result = Vec; - const METHOD: &'static str = "workspace/configuration"; -} - -/// The code action request is sent from the client to the server to compute commands for a given text document -/// and range. The request is triggered when the user moves the cursor into a problem marker in the editor or -/// presses the lightbulb associated with a marker. -#[derive(Debug)] -pub enum CodeActionRequest {} - -impl Request for CodeActionRequest { - type Params = CodeActionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/codeAction"; -} - -/// The code lens request is sent from the client to the server to compute code lenses for a given text document. -#[derive(Debug)] -pub enum CodeLensRequest {} - -impl Request for CodeLensRequest { - type Params = CodeLensParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/codeLens"; -} - -/// The code lens resolve request is sent from the client to the server to resolve the command for a -/// given code lens item. -#[derive(Debug)] -pub enum CodeLensResolve {} - -impl Request for CodeLensResolve { - type Params = CodeLens; - type Result = CodeLens; - const METHOD: &'static str = "codeLens/resolve"; -} - -/// The document links request is sent from the client to the server to request the location of links in a document. -#[derive(Debug)] -pub enum DocumentLinkRequest {} - -impl Request for DocumentLinkRequest { - type Params = DocumentLinkParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/documentLink"; -} - -/// The document link resolve request is sent from the client to the server to resolve the target of -/// a given document link. -#[derive(Debug)] -pub enum DocumentLinkResolve {} - -impl Request for DocumentLinkResolve { - type Params = DocumentLink; - type Result = DocumentLink; - const METHOD: &'static str = "documentLink/resolve"; -} - -/// The document formatting request is sent from the server to the client to format a whole document. -#[derive(Debug)] -pub enum Formatting {} - -impl Request for Formatting { - type Params = DocumentFormattingParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/formatting"; -} - -/// The document range formatting request is sent from the client to the server to format a given range in a document. -#[derive(Debug)] -pub enum RangeFormatting {} - -impl Request for RangeFormatting { - type Params = DocumentRangeFormattingParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/rangeFormatting"; -} - -/// The document on type formatting request is sent from the client to the server to format parts of -/// the document during typing. -#[derive(Debug)] -pub enum OnTypeFormatting {} - -impl Request for OnTypeFormatting { - type Params = DocumentOnTypeFormattingParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/onTypeFormatting"; -} - -/// The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol. -#[derive(Debug)] -pub enum Rename {} - -impl Request for Rename { - type Params = RenameParams; - type Result = Option; - const METHOD: &'static str = "textDocument/rename"; -} - -/// The document color request is sent from the client to the server to list all color references found in a given text document. -/// Along with the range, a color value in RGB is returned. -#[derive(Debug)] -pub enum DocumentColor {} - -impl Request for DocumentColor { - type Params = DocumentColorParams; - type Result = Vec; - const METHOD: &'static str = "textDocument/documentColor"; -} - -/// The color presentation request is sent from the client to the server to obtain a list of presentations for a color value -/// at a given location. -#[derive(Debug)] -pub enum ColorPresentationRequest {} - -impl Request for ColorPresentationRequest { - type Params = ColorPresentationParams; - type Result = Vec; - const METHOD: &'static str = "textDocument/colorPresentation"; -} - -/// The folding range request is sent from the client to the server to return all folding ranges found in a given text document. -#[derive(Debug)] -pub enum FoldingRangeRequest {} - -impl Request for FoldingRangeRequest { - type Params = FoldingRangeParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/foldingRange"; -} - -/// The prepare rename request is sent from the client to the server to setup and test the validity of a rename operation -/// at a given location. -#[derive(Debug)] -pub enum PrepareRenameRequest {} - -impl Request for PrepareRenameRequest { - type Params = TextDocumentPositionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/prepareRename"; -} - -/// The workspace/workspaceFolders request is sent from the server to the client to fetch the current open list of -/// workspace folders. Returns null in the response if only a single file is open in the tool. -/// Returns an empty array if a workspace is open but no folders are configured. -#[derive(Debug)] -pub enum WorkspaceFoldersRequest {} - -impl Request for WorkspaceFoldersRequest { - type Params = (); - type Result = Option>; - const METHOD: &'static str = "workspace/workspaceFolders"; -} - -/// The `window/workDoneProgress/create` request is sent from the server -/// to the clientto ask the client to create a work done progress. -#[derive(Debug)] -pub enum WorkDoneProgressCreate {} - -impl Request for WorkDoneProgressCreate { - type Params = WorkDoneProgressCreateParams; - type Result = (); - const METHOD: &'static str = "window/workDoneProgress/create"; -} - -/// The selection range request is sent from the client to the server to return -/// suggested selection ranges at given positions. A selection range is a range -/// around the cursor position which the user might be interested in selecting. -/// -/// A selection range in the return array is for the position in the provided parameters at the same index. -/// Therefore positions[i] must be contained in result[i].range. -/// -/// Typically, but not necessary, selection ranges correspond to the nodes of the -/// syntax tree. -pub enum SelectionRangeRequest {} - -impl Request for SelectionRangeRequest { - type Params = SelectionRangeParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/selectionRange"; -} - -#[cfg(feature = "proposed")] -pub enum CallHierarchyPrepare {} - -#[cfg(feature = "proposed")] -impl Request for CallHierarchyPrepare { - type Params = CallHierarchyPrepareParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/prepareCallHierarchy"; -} - -#[cfg(feature = "proposed")] -pub enum CallHierarchyIncomingCalls {} - -#[cfg(feature = "proposed")] -impl Request for CallHierarchyIncomingCalls { - type Params = CallHierarchyIncomingCallsParams; - type Result = Option>; - const METHOD: &'static str = "callHierarchy/incomingCalls"; -} - -#[cfg(feature = "proposed")] -pub enum CallHierarchyOutgoingCalls {} - -#[cfg(feature = "proposed")] -impl Request for CallHierarchyOutgoingCalls { - type Params = CallHierarchyOutgoingCallsParams; - type Result = Option>; - const METHOD: &'static str = "callHierarchy/outgoingCalls"; -} - -#[cfg(feature = "proposed")] -pub enum SemanticTokensRequest {} - -#[cfg(feature = "proposed")] -impl Request for SemanticTokensRequest { - type Params = SemanticTokensParams; - type Result = Option; - const METHOD: &'static str = "textDocument/semanticTokens"; -} - -#[cfg(feature = "proposed")] -pub enum SemanticTokensEditsRequest {} - -#[cfg(feature = "proposed")] -impl Request for SemanticTokensEditsRequest { - type Params = SemanticTokensEditsParams; - type Result = Option; - const METHOD: &'static str = "textDocument/semanticTokens/edits"; -} - -#[cfg(feature = "proposed")] -pub enum SemanticTokensRangeRequest {} - -#[cfg(feature = "proposed")] -impl Request for SemanticTokensRangeRequest { - type Params = SemanticTokensRangeParams; - type Result = Option; - const METHOD: &'static str = "textDocument/semanticTokens/range"; -} - -#[cfg(test)] -mod test { - use super::*; - - fn fake_call() - where - R: Request, - R::Params: serde::Serialize, - R::Result: serde::de::DeserializeOwned, - { - } - - macro_rules! check_macro { - ($name:tt) => { - // check whethe the macro name matches the method - assert_eq!(::METHOD, $name); - // test whether type checking passes for each component - fake_call::(); - }; - } - - #[test] - fn check_macro_definitions() { - check_macro!("initialize"); - check_macro!("shutdown"); - check_macro!("window/showMessageRequest"); - check_macro!("window/workDoneProgress/create"); - check_macro!("client/registerCapability"); - check_macro!("client/unregisterCapability"); - check_macro!("workspace/symbol"); - check_macro!("workspace/executeCommand"); - check_macro!("textDocument/willSaveWaitUntil"); - check_macro!("textDocument/completion"); - check_macro!("completionItem/resolve"); - check_macro!("textDocument/hover"); - check_macro!("textDocument/signatureHelp"); - check_macro!("textDocument/declaration"); - check_macro!("textDocument/definition"); - check_macro!("textDocument/references"); - check_macro!("textDocument/documentHighlight"); - check_macro!("textDocument/documentSymbol"); - check_macro!("textDocument/codeAction"); - check_macro!("textDocument/codeLens"); - check_macro!("codeLens/resolve"); - check_macro!("textDocument/documentLink"); - check_macro!("documentLink/resolve"); - check_macro!("workspace/applyEdit"); - check_macro!("textDocument/rangeFormatting"); - check_macro!("textDocument/onTypeFormatting"); - check_macro!("textDocument/formatting"); - check_macro!("textDocument/rename"); - check_macro!("textDocument/documentColor"); - check_macro!("textDocument/colorPresentation"); - check_macro!("textDocument/foldingRange"); - check_macro!("textDocument/prepareRename"); - check_macro!("workspace/workspaceFolders"); - check_macro!("textDocument/implementation"); - check_macro!("textDocument/selectionRange"); - check_macro!("textDocument/typeDefinition"); - check_macro!("workspace/configuration"); - } - - #[test] - #[cfg(feature = "proposed")] - fn check_proposed_macro_definitions() { - check_macro!("callHierarchy/incomingCalls"); - check_macro!("callHierarchy/outgoingCalls"); - check_macro!("textDocument/prepareCallHierarchy"); - check_macro!("textDocument/semanticTokens"); - check_macro!("textDocument/semanticTokens/edits"); - check_macro!("textDocument/semanticTokens/range"); - } -} +use super::*; + +use serde::{de::DeserializeOwned, Serialize}; + +pub trait Request { + type Params: DeserializeOwned + Serialize; + type Result: DeserializeOwned + Serialize; + const METHOD: &'static str; +} + +#[macro_export] +macro_rules! lsp_request { + ("initialize") => { + $crate::request::Initialize + }; + ("shutdown") => { + $crate::request::Shutdown + }; + + ("window/showMessageRequest") => { + $crate::request::ShowMessageRequest + }; + + ("client/registerCapability") => { + $crate::request::RegisterCapability + }; + ("client/unregisterCapability") => { + $crate::request::UnregisterCapability + }; + + ("workspace/symbol") => { + $crate::request::WorkspaceSymbol + }; + ("workspace/executeCommand") => { + $crate::request::ExecuteCommand + }; + + ("textDocument/willSaveWaitUntil") => { + $crate::request::WillSaveWaitUntil + }; + + ("textDocument/completion") => { + $crate::request::Completion + }; + ("completionItem/resolve") => { + $crate::request::ResolveCompletionItem + }; + ("textDocument/hover") => { + $crate::request::HoverRequest + }; + ("textDocument/signatureHelp") => { + $crate::request::SignatureHelpRequest + }; + ("textDocument/declaration") => { + $crate::request::GotoDeclaration + }; + ("textDocument/definition") => { + $crate::request::GotoDefinition + }; + ("textDocument/references") => { + $crate::request::References + }; + ("textDocument/documentHighlight") => { + $crate::request::DocumentHighlightRequest + }; + ("textDocument/documentSymbol") => { + $crate::request::DocumentSymbolRequest + }; + ("textDocument/codeAction") => { + $crate::request::CodeActionRequest + }; + ("textDocument/codeLens") => { + $crate::request::CodeLensRequest + }; + ("codeLens/resolve") => { + $crate::request::CodeLensResolve + }; + ("textDocument/documentLink") => { + $crate::request::DocumentLinkRequest + }; + ("documentLink/resolve") => { + $crate::request::DocumentLinkResolve + }; + ("workspace/applyEdit") => { + $crate::request::ApplyWorkspaceEdit + }; + ("textDocument/rangeFormatting") => { + $crate::request::RangeFormatting + }; + ("textDocument/onTypeFormatting") => { + $crate::request::OnTypeFormatting + }; + ("textDocument/formatting") => { + $crate::request::Formatting + }; + ("textDocument/rename") => { + $crate::request::Rename + }; + ("textDocument/documentColor") => { + $crate::request::DocumentColor + }; + ("textDocument/colorPresentation") => { + $crate::request::ColorPresentationRequest + }; + ("textDocument/foldingRange") => { + $crate::request::FoldingRangeRequest + }; + ("textDocument/prepareRename") => { + $crate::request::PrepareRenameRequest + }; + ("textDocument/implementation") => { + $crate::request::GotoImplementation + }; + ("textDocument/typeDefinition") => { + $crate::request::GotoTypeDefinition + }; + ("textDocument/selectionRange") => { + $crate::request::SelectionRangeRequest + }; + ("workspace/workspaceFolders") => { + $crate::request::WorkspaceFoldersRequest + }; + ("workspace/configuration") => { + $crate::request::WorkspaceConfiguration + }; + ("window/workDoneProgress/create") => { + $crate::request::WorkDoneProgressCreate + }; + // Requires #[cfg(feature = "proposed")] + ("callHierarchy/incomingCalls") => { + $crate::request::CallHierarchyIncomingCalls + }; + // Requires #[cfg(feature = "proposed")] + ("callHierarchy/outgoingCalls") => { + $crate::request::CallHierarchyOutgoingCalls + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/prepareCallHierarchy") => { + $crate::request::CallHierarchyPrepare + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/semanticTokens/full") => { + $crate::request::SemanticTokensFullRequest + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/semanticTokens/full/delta") => { + $crate::request::SemanticTokensFullDeltaRequest + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/semanticTokens/range") => { + $crate::request::SemanticTokensRangeRequest + }; +} + +/// The initialize request is sent as the first request from the client to the server. +/// If the server receives request or notification before the `initialize` request it should act as follows: +/// +/// * for a request the respond should be errored with `code: -32001`. The message can be picked by the server. +/// * notifications should be dropped. +#[derive(Debug)] +pub enum Initialize {} + +impl Request for Initialize { + type Params = InitializeParams; + type Result = InitializeResult; + const METHOD: &'static str = "initialize"; +} + +/// The shutdown request is sent from the client to the server. It asks the server to shut down, +/// but to not exit (otherwise the response might not be delivered correctly to the client). +/// There is a separate exit notification that asks the server to exit. +#[derive(Debug)] +pub enum Shutdown {} + +impl Request for Shutdown { + type Params = (); + type Result = (); + const METHOD: &'static str = "shutdown"; +} + +/// The show message request is sent from a server to a client to ask the client to display a particular message +/// in the user interface. In addition to the show message notification the request allows to pass actions and to +/// wait for an answer from the client. +#[derive(Debug)] +pub enum ShowMessageRequest {} + +impl Request for ShowMessageRequest { + type Params = ShowMessageRequestParams; + type Result = Option; + const METHOD: &'static str = "window/showMessageRequest"; +} + +/// The client/registerCapability request is sent from the server to the client to register for a new capability +/// on the client side. Not all clients need to support dynamic capability registration. A client opts in via the +/// ClientCapabilities.GenericCapability property. +#[derive(Debug)] +pub enum RegisterCapability {} + +impl Request for RegisterCapability { + type Params = RegistrationParams; + type Result = (); + const METHOD: &'static str = "client/registerCapability"; +} + +/// The client/unregisterCapability request is sent from the server to the client to unregister a +/// previously register capability. +#[derive(Debug)] +pub enum UnregisterCapability {} + +impl Request for UnregisterCapability { + type Params = UnregistrationParams; + type Result = (); + const METHOD: &'static str = "client/unregisterCapability"; +} + +/// The Completion request is sent from the client to the server to compute completion items at a given cursor position. +/// Completion items are presented in the IntelliSense user interface. If computing full completion items is expensive, +/// servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve'). +/// This request is sent when a completion item is selected in the user interface. A typical use case is for example: +/// the 'textDocument/completion' request doesn’t fill in the documentation property for returned completion items +/// since it is expensive to compute. When the item is selected in the user interface then a ‘completionItem/resolve’ +/// request is sent with the selected completion item as a param. The returned completion item should have the +/// documentation property filled in. The request can delay the computation of the detail and documentation properties. +/// However, properties that are needed for the initial sorting and filtering, like sortText, filterText, insertText, +/// and textEdit must be provided in the textDocument/completion request and must not be changed during resolve. +#[derive(Debug)] +pub enum Completion {} + +impl Request for Completion { + type Params = CompletionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/completion"; +} + +/// The request is sent from the client to the server to resolve additional information for a given completion item. +#[derive(Debug)] +pub enum ResolveCompletionItem {} + +impl Request for ResolveCompletionItem { + type Params = CompletionItem; + type Result = CompletionItem; + const METHOD: &'static str = "completionItem/resolve"; +} + +/// The hover request is sent from the client to the server to request hover information at a given text +/// document position. +#[derive(Debug)] +pub enum HoverRequest {} + +impl Request for HoverRequest { + type Params = HoverParams; + type Result = Option; + const METHOD: &'static str = "textDocument/hover"; +} + +/// The signature help request is sent from the client to the server to request signature information at +/// a given cursor position. +#[derive(Debug)] +pub enum SignatureHelpRequest {} + +impl Request for SignatureHelpRequest { + type Params = SignatureHelpParams; + type Result = Option; + const METHOD: &'static str = "textDocument/signatureHelp"; +} + +#[derive(Debug)] +pub enum GotoDeclaration {} +pub type GotoDeclarationParams = GotoDefinitionParams; +pub type GotoDeclarationResponse = GotoDefinitionResponse; + +/// The goto declaration request is sent from the client to the server to resolve the declaration location of +/// a symbol at a given text document position. +impl Request for GotoDeclaration { + type Params = GotoDeclarationParams; + type Result = Option; + const METHOD: &'static str = "textDocument/declaration"; +} + +/// The goto definition request is sent from the client to the server to resolve the definition location of +/// a symbol at a given text document position. +#[derive(Debug)] +pub enum GotoDefinition {} + +impl Request for GotoDefinition { + type Params = GotoDefinitionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/definition"; +} + +/// The references request is sent from the client to the server to resolve project-wide references for the +/// symbol denoted by the given text document position. +#[derive(Debug)] +pub enum References {} + +impl Request for References { + type Params = ReferenceParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/references"; +} + +/// The goto type definition request is sent from the client to the +/// server to resolve the type definition location of a symbol at a +/// given text document position. +#[derive(Debug)] +pub enum GotoTypeDefinition {} + +pub type GotoTypeDefinitionParams = GotoDefinitionParams; +pub type GotoTypeDefinitionResponse = GotoDefinitionResponse; + +impl Request for GotoTypeDefinition { + type Params = GotoTypeDefinitionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/typeDefinition"; +} + +/// The goto implementation request is sent from the client to the +/// server to resolve the implementation location of a symbol at a +/// given text document position. +#[derive(Debug)] +pub enum GotoImplementation {} + +pub type GotoImplementationParams = GotoTypeDefinitionParams; +pub type GotoImplementationResponse = GotoDefinitionResponse; + +impl Request for GotoImplementation { + type Params = GotoImplementationParams; + type Result = Option; + const METHOD: &'static str = "textDocument/implementation"; +} + +/// The document highlight request is sent from the client to the server to resolve a document highlights +/// for a given text document position. +/// For programming languages this usually highlights all references to the symbol scoped to this file. +/// However we kept 'textDocument/documentHighlight' and 'textDocument/references' separate requests since +/// the first one is allowed to be more fuzzy. +/// Symbol matches usually have a DocumentHighlightKind of Read or Write whereas fuzzy or textual matches +/// use Text as the kind. +#[derive(Debug)] +pub enum DocumentHighlightRequest {} + +impl Request for DocumentHighlightRequest { + type Params = DocumentHighlightParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/documentHighlight"; +} + +/// The document symbol request is sent from the client to the server to list all symbols found in a given +/// text document. +#[derive(Debug)] +pub enum DocumentSymbolRequest {} + +impl Request for DocumentSymbolRequest { + type Params = DocumentSymbolParams; + type Result = Option; + const METHOD: &'static str = "textDocument/documentSymbol"; +} + +/// The workspace symbol request is sent from the client to the server to list project-wide symbols +/// matching the query string. +#[derive(Debug)] +pub enum WorkspaceSymbol {} + +impl Request for WorkspaceSymbol { + type Params = WorkspaceSymbolParams; + type Result = Option>; + const METHOD: &'static str = "workspace/symbol"; +} + +/// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. +/// In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request +/// workspace/applyEdit which is sent from the server to the client. +#[derive(Debug)] +pub enum ExecuteCommand {} + +impl Request for ExecuteCommand { + type Params = ExecuteCommandParams; + type Result = Option; + const METHOD: &'static str = "workspace/executeCommand"; +} + +/// The document will save request is sent from the client to the server before the document is +/// actually saved. The request can return an array of TextEdits which will be applied to the text +/// document before it is saved. Please note that clients might drop results if computing the text +/// edits took too long or if a server constantly fails on this request. This is done to keep the +/// save fast and reliable. +#[derive(Debug)] +pub enum WillSaveWaitUntil {} + +impl Request for WillSaveWaitUntil { + type Params = WillSaveTextDocumentParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/willSaveWaitUntil"; +} + +/// The workspace/applyEdit request is sent from the server to the client to modify resource on the +/// client side. +#[derive(Debug)] +pub enum ApplyWorkspaceEdit {} + +impl Request for ApplyWorkspaceEdit { + type Params = ApplyWorkspaceEditParams; + type Result = ApplyWorkspaceEditResponse; + const METHOD: &'static str = "workspace/applyEdit"; +} + +/// The workspace/configuration request is sent from the server to the client to fetch configuration settings +/// from the client. The request can fetch several configuration settings in one roundtrip. +/// The order of the returned configuration settings correspond to the order of the passed ConfigurationItems +/// (e.g. the first item in the response is the result for the first configuration item in the params). +/// +/// A ConfigurationItem consists of the configuration section to ask for and an additional scope URI. +/// The configuration section ask for is defined by the server and doesn’t necessarily need to correspond to +/// the configuration store used be the client. So a server might ask for a configuration cpp.formatterOptions +/// but the client stores the configuration in a XML store layout differently. +/// It is up to the client to do the necessary conversion. If a scope URI is provided the client should return +/// the setting scoped to the provided resource. If the client for example uses EditorConfig to manage its +/// settings the configuration should be returned for the passed resource URI. If the client can’t provide a +/// configuration setting for a given scope then null need to be present in the returned array. +#[derive(Debug)] +pub enum WorkspaceConfiguration {} + +impl Request for WorkspaceConfiguration { + type Params = ConfigurationParams; + type Result = Vec; + const METHOD: &'static str = "workspace/configuration"; +} + +/// The code action request is sent from the client to the server to compute commands for a given text document +/// and range. The request is triggered when the user moves the cursor into a problem marker in the editor or +/// presses the lightbulb associated with a marker. +#[derive(Debug)] +pub enum CodeActionRequest {} + +impl Request for CodeActionRequest { + type Params = CodeActionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/codeAction"; +} + +/// The code lens request is sent from the client to the server to compute code lenses for a given text document. +#[derive(Debug)] +pub enum CodeLensRequest {} + +impl Request for CodeLensRequest { + type Params = CodeLensParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/codeLens"; +} + +/// The code lens resolve request is sent from the client to the server to resolve the command for a +/// given code lens item. +#[derive(Debug)] +pub enum CodeLensResolve {} + +impl Request for CodeLensResolve { + type Params = CodeLens; + type Result = CodeLens; + const METHOD: &'static str = "codeLens/resolve"; +} + +/// The document links request is sent from the client to the server to request the location of links in a document. +#[derive(Debug)] +pub enum DocumentLinkRequest {} + +impl Request for DocumentLinkRequest { + type Params = DocumentLinkParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/documentLink"; +} + +/// The document link resolve request is sent from the client to the server to resolve the target of +/// a given document link. +#[derive(Debug)] +pub enum DocumentLinkResolve {} + +impl Request for DocumentLinkResolve { + type Params = DocumentLink; + type Result = DocumentLink; + const METHOD: &'static str = "documentLink/resolve"; +} + +/// The document formatting request is sent from the server to the client to format a whole document. +#[derive(Debug)] +pub enum Formatting {} + +impl Request for Formatting { + type Params = DocumentFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/formatting"; +} + +/// The document range formatting request is sent from the client to the server to format a given range in a document. +#[derive(Debug)] +pub enum RangeFormatting {} + +impl Request for RangeFormatting { + type Params = DocumentRangeFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/rangeFormatting"; +} + +/// The document on type formatting request is sent from the client to the server to format parts of +/// the document during typing. +#[derive(Debug)] +pub enum OnTypeFormatting {} + +impl Request for OnTypeFormatting { + type Params = DocumentOnTypeFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/onTypeFormatting"; +} + +/// The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol. +#[derive(Debug)] +pub enum Rename {} + +impl Request for Rename { + type Params = RenameParams; + type Result = Option; + const METHOD: &'static str = "textDocument/rename"; +} + +/// The document color request is sent from the client to the server to list all color references found in a given text document. +/// Along with the range, a color value in RGB is returned. +#[derive(Debug)] +pub enum DocumentColor {} + +impl Request for DocumentColor { + type Params = DocumentColorParams; + type Result = Vec; + const METHOD: &'static str = "textDocument/documentColor"; +} + +/// The color presentation request is sent from the client to the server to obtain a list of presentations for a color value +/// at a given location. +#[derive(Debug)] +pub enum ColorPresentationRequest {} + +impl Request for ColorPresentationRequest { + type Params = ColorPresentationParams; + type Result = Vec; + const METHOD: &'static str = "textDocument/colorPresentation"; +} + +/// The folding range request is sent from the client to the server to return all folding ranges found in a given text document. +#[derive(Debug)] +pub enum FoldingRangeRequest {} + +impl Request for FoldingRangeRequest { + type Params = FoldingRangeParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/foldingRange"; +} + +/// The prepare rename request is sent from the client to the server to setup and test the validity of a rename operation +/// at a given location. +#[derive(Debug)] +pub enum PrepareRenameRequest {} + +impl Request for PrepareRenameRequest { + type Params = TextDocumentPositionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/prepareRename"; +} + +/// The workspace/workspaceFolders request is sent from the server to the client to fetch the current open list of +/// workspace folders. Returns null in the response if only a single file is open in the tool. +/// Returns an empty array if a workspace is open but no folders are configured. +#[derive(Debug)] +pub enum WorkspaceFoldersRequest {} + +impl Request for WorkspaceFoldersRequest { + type Params = (); + type Result = Option>; + const METHOD: &'static str = "workspace/workspaceFolders"; +} + +/// The `window/workDoneProgress/create` request is sent from the server +/// to the clientto ask the client to create a work done progress. +#[derive(Debug)] +pub enum WorkDoneProgressCreate {} + +impl Request for WorkDoneProgressCreate { + type Params = WorkDoneProgressCreateParams; + type Result = (); + const METHOD: &'static str = "window/workDoneProgress/create"; +} + +/// The selection range request is sent from the client to the server to return +/// suggested selection ranges at given positions. A selection range is a range +/// around the cursor position which the user might be interested in selecting. +/// +/// A selection range in the return array is for the position in the provided parameters at the same index. +/// Therefore positions[i] must be contained in result[i].range. +/// +/// Typically, but not necessary, selection ranges correspond to the nodes of the +/// syntax tree. +pub enum SelectionRangeRequest {} + +impl Request for SelectionRangeRequest { + type Params = SelectionRangeParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/selectionRange"; +} + +#[cfg(feature = "proposed")] +pub enum CallHierarchyPrepare {} + +#[cfg(feature = "proposed")] +impl Request for CallHierarchyPrepare { + type Params = CallHierarchyPrepareParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/prepareCallHierarchy"; +} + +#[cfg(feature = "proposed")] +pub enum CallHierarchyIncomingCalls {} + +#[cfg(feature = "proposed")] +impl Request for CallHierarchyIncomingCalls { + type Params = CallHierarchyIncomingCallsParams; + type Result = Option>; + const METHOD: &'static str = "callHierarchy/incomingCalls"; +} + +#[cfg(feature = "proposed")] +pub enum CallHierarchyOutgoingCalls {} + +#[cfg(feature = "proposed")] +impl Request for CallHierarchyOutgoingCalls { + type Params = CallHierarchyOutgoingCallsParams; + type Result = Option>; + const METHOD: &'static str = "callHierarchy/outgoingCalls"; +} + +#[cfg(feature = "proposed")] +pub enum SemanticTokensFullRequest {} + +#[cfg(feature = "proposed")] +impl Request for SemanticTokensFullRequest { + type Params = SemanticTokensParams; + type Result = Option; + const METHOD: &'static str = "textDocument/semanticTokens/full"; +} + +#[cfg(feature = "proposed")] +pub enum SemanticTokensFullDeltaRequest {} + +#[cfg(feature = "proposed")] +impl Request for SemanticTokensFullDeltaRequest { + type Params = SemanticTokensDeltaParams; + type Result = Option; + const METHOD: &'static str = "textDocument/semanticTokens/full/delta"; +} + +#[cfg(feature = "proposed")] +pub enum SemanticTokensRangeRequest {} + +#[cfg(feature = "proposed")] +impl Request for SemanticTokensRangeRequest { + type Params = SemanticTokensRangeParams; + type Result = Option; + const METHOD: &'static str = "textDocument/semanticTokens/range"; +} + +#[cfg(test)] +mod test { + use super::*; + + fn fake_call() + where + R: Request, + R::Params: serde::Serialize, + R::Result: serde::de::DeserializeOwned, + { + } + + macro_rules! check_macro { + ($name:tt) => { + // check whethe the macro name matches the method + assert_eq!(::METHOD, $name); + // test whether type checking passes for each component + fake_call::(); + }; + } + + #[test] + fn check_macro_definitions() { + check_macro!("initialize"); + check_macro!("shutdown"); + check_macro!("window/showMessageRequest"); + check_macro!("window/workDoneProgress/create"); + check_macro!("client/registerCapability"); + check_macro!("client/unregisterCapability"); + check_macro!("workspace/symbol"); + check_macro!("workspace/executeCommand"); + check_macro!("textDocument/willSaveWaitUntil"); + check_macro!("textDocument/completion"); + check_macro!("completionItem/resolve"); + check_macro!("textDocument/hover"); + check_macro!("textDocument/signatureHelp"); + check_macro!("textDocument/declaration"); + check_macro!("textDocument/definition"); + check_macro!("textDocument/references"); + check_macro!("textDocument/documentHighlight"); + check_macro!("textDocument/documentSymbol"); + check_macro!("textDocument/codeAction"); + check_macro!("textDocument/codeLens"); + check_macro!("codeLens/resolve"); + check_macro!("textDocument/documentLink"); + check_macro!("documentLink/resolve"); + check_macro!("workspace/applyEdit"); + check_macro!("textDocument/rangeFormatting"); + check_macro!("textDocument/onTypeFormatting"); + check_macro!("textDocument/formatting"); + check_macro!("textDocument/rename"); + check_macro!("textDocument/documentColor"); + check_macro!("textDocument/colorPresentation"); + check_macro!("textDocument/foldingRange"); + check_macro!("textDocument/prepareRename"); + check_macro!("workspace/workspaceFolders"); + check_macro!("textDocument/implementation"); + check_macro!("textDocument/selectionRange"); + check_macro!("textDocument/typeDefinition"); + check_macro!("workspace/configuration"); + } + + #[test] + #[cfg(feature = "proposed")] + fn check_proposed_macro_definitions() { + check_macro!("callHierarchy/incomingCalls"); + check_macro!("callHierarchy/outgoingCalls"); + check_macro!("textDocument/prepareCallHierarchy"); + check_macro!("textDocument/semanticTokens/full"); + check_macro!("textDocument/semanticTokens/full/delta"); + check_macro!("textDocument/semanticTokens/range"); + } +} diff --git a/vendor/mdbook/.cargo-checksum.json b/vendor/mdbook/.cargo-checksum.json index 682cfd4add..5de6dc20d4 100644 --- a/vendor/mdbook/.cargo-checksum.json +++ b/vendor/mdbook/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"3d8761959d40685fd6fb0040e47b35ca7bb7600e4efec94ab2b98bc245811dd6","CONTRIBUTING.md":"680cef0c70325c2e45ede352422ae249ed212c65fc5f502c2267243b89187595","Cargo.lock":"ba04f16c937de54f63f3c2ecb488ab905f0a8f522ddfa3c27f23dc775ccdf996","Cargo.toml":"444b724a463929eee770417b5364975bc9ac113175c35391f9a1396811f5d15b","LICENSE":"af175b9d96ee93c21a036152e1b905b0b95304d4ae8c2c921c7609100ba8df7e","README.md":"be135630660209986615180894b8f71ce865623cb7ecfb2c487c8a12ca9b59c5","ci/install-hub.sh":"ef529e66465dd624d502f4bd4a1092a741f788b948a98625b1f01375149f4ff7","ci/install-rust.sh":"c7b63b4aff867d6da241c23b45121f3efa9cf62b43f839f0eb0d4d0f86580dd6","ci/make-release.sh":"fcf307a3d28ebd60b4b339f960bc0533dfb1bafe37f3c041fac72b49c279bb3b","examples/nop-preprocessor.rs":"db48153fed353c761ec6a64774f4340a91b4ea8c07236ef571bd7601dc5bd17b","release.toml":"25e91966f4a77515244adf5775d638590916c550f9d25bba6024d629b71840e8","src/book/book.rs":"ea53860086d73d81dcbc72d2f3acddf66786ae4486674e0550396998bb10afa9","src/book/init.rs":"fad0ae98277a8b6e9eb4f79776316f2492be4866702ba32ea9745659f6087a05","src/book/mod.rs":"dcd8afc56ea9f018358a630e6ec7e14114099bc0b4f66155d9fcec2e0f530b3f","src/book/summary.rs":"7f5f0b45a5b31dbdfc70c4fbcde60a60d1a2a771b0f2130c2d62cb06a8af0f29","src/cmd/build.rs":"7a87f609ad245a808137c9ff67a92b14238c8b01c3afc834ce166f3ff161a58f","src/cmd/clean.rs":"411579d00103568b8e904db647b6360bd8f9b11d209f595d0a6de0a6e08f8915","src/cmd/init.rs":"3161219d9c4375d296c2f39fdb9cffdad09b373b46f1af5b9543173671a58e5b","src/cmd/mod.rs":"29116e5ca90e916a5f4ce62581a29508670ef184ec3e20569e2ad90b57472abe","src/cmd/serve.rs":"a15a0d7a7cbe9e0421fb2948e6e88e7c1206602dd211d666129e67bc973ad626","src/cmd/test.rs":"405e82cc63f212ec6f41e2017d34aba369c8d581b9c1431c8696d787aa2ee1cf","src/cmd/watch.rs":"86bcf487612c03a3d30c48094aa9b23350226e3e6fbb5850799e61d6f741b81e","src/config.rs":"9cfce3fab9df3705a4a08b02f4657b9eda4e5b5bd5c1cb939e6328ab6eb36a15","src/lib.rs":"5f14dc00233be5b80d41530dd44d09f46bff30fbdf418a97e8e237f53e14ea6a","src/main.rs":"867f696a76921341ab1f0664c20f3efb90c2c5cbdf8da34d5a52205b33481c84","src/preprocess/cmd.rs":"cf5a35406e0804df391c90a004e3f8624c518517a3e0b136c5341fac067068ea","src/preprocess/index.rs":"d6d34bc61165dd5f42005e5d601d6729c40cacd656358ede17798effa309e508","src/preprocess/links.rs":"ad161e8545ec7198afc98da2cb8935ed0eb242f88f36494738932c50ba0633ab","src/preprocess/mod.rs":"b699f993473abdf6e4abbe038c8286b14312003e5d4713d946b9ae87047270e7","src/renderer/html_handlebars/hbs_renderer.rs":"5c09eba4e304b898f309b275b25b88a2733a0655dfdacb7c831d8c69c224df23","src/renderer/html_handlebars/helpers/mod.rs":"d83520feecce350b03b7ffaa9f34d6db2fe7316a46562be694b8eef537124191","src/renderer/html_handlebars/helpers/navigation.rs":"51d6fed8f4af42af10a66bf24804337c87cf93daba893f2f3664b3683a24a9e1","src/renderer/html_handlebars/helpers/theme.rs":"06713b5de794eaf68538e929cce58fe55a6e48afd5e9d3bb211ef47809d18af2","src/renderer/html_handlebars/helpers/toc.rs":"2da068b91db3490d33f8798e0b10899f0bf75a24c3af1f573a66b6d626057864","src/renderer/html_handlebars/mod.rs":"b6be4801cf49040edc9dad216ed12c26dce87e2dc4724ee24729e4a8b67734b0","src/renderer/html_handlebars/search.rs":"626e3cbec3587b90a8209a314e555533cc9b3e98f54270aafc4ab9f471847599","src/renderer/markdown_renderer.rs":"319453627fa416d44e5459a3f9f4cf07b87a4133ff97df5fc962768c9235c65f","src/renderer/mod.rs":"56c11e129556e7f22750a1ad30785719f761ff98a1ca1409b5981e95a6986429","src/theme/FontAwesome/css/font-awesome.min.css":"799aeb25cc0373fdee0e1b1db7ad6c2f6a0e058dfadaa3379689f583213190bd","src/theme/FontAwesome/fonts/FontAwesome.otf":"444dd4366615ffc4a16d012b2fa90137065d3ccb410fa6fd5e4ddd7b5e4ffcd5","src/theme/FontAwesome/fonts/fontawesome-webfont.eot":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","src/theme/FontAwesome/fonts/fontawesome-webfont.svg":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","src/theme/FontAwesome/fonts/fontawesome-webfont.ttf":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","src/theme/FontAwesome/fonts/fontawesome-webfont.woff":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","src/theme/FontAwesome/fonts/fontawesome-webfont.woff2":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","src/theme/ayu-highlight.css":"c141251b5888ccc185c31976e6cb9234f7827ae6bc4975926cafc8bca5e8f83d","src/theme/book.js":"418a647fcdc6ed5388e5c669e10cb796a8d851c2b24d97c416bcb050fdaa9008","src/theme/clipboard.min.js":"1626706afc88d95ebe1173b553ec732c6dc82a576989315fdf5e7779af738a44","src/theme/css/chrome.css":"576bd3d1e4748ab1a7e000eb110f83f1b643fa4f8339b90a9305302e5c68aaeb","src/theme/css/general.css":"4c89e3e531bc5ca322e4210c8d1868d5a97df0f2a2726a7d60c192f7d933fe19","src/theme/css/print.css":"a4278dff9af38765eb9d344aa56dcc652ac79c73afc408385b62a4b611b89c14","src/theme/css/variables.css":"ccf9aa3f3dcb79b967e13658d101b3f7b9efa914ae0c5e05ac5ed322af33c5bf","src/theme/favicon.png":"8114d1fc74f4b5621ad9afde7746ed9cf7e420be317a6e29023d2298d58aa15b","src/theme/favicon.svg":"de23e50b1c4dd6e052b3e21d444fcd4b13568b3840ac3c99d9be4e9263c0ef59","src/theme/fonts/OPEN-SANS-LICENSE.txt":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","src/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt":"d1e6d465a83ba1a3be52db6484868cf5812ae9bbf91abdad3900ba0165afcf93","src/theme/fonts/fonts.css":"70d7fd9e9965df2995206106b3409b31b1455e5a5e1ef9c2db633d8c84a27622","src/theme/fonts/mod.rs":"9b97835fbc610c46245ac52f8d40df8f28ace0c4fe7aca0847835ee83cc21a15","src/theme/fonts/open-sans-v17-all-charsets-300.woff2":"7736aa3596c468515c3209f2f9d68cfae96d94c05689bcc11a5dce426a6ee2e8","src/theme/fonts/open-sans-v17-all-charsets-300italic.woff2":"2c7b95c08df0d228caec6d4bfed06da0f7ab6b76ea5cc3f75b5c6ae416bc571b","src/theme/fonts/open-sans-v17-all-charsets-600.woff2":"486c67592731a0b36a89dba1fd0b97aeb73f236bbf60dbf28d7c6b5723c07989","src/theme/fonts/open-sans-v17-all-charsets-600italic.woff2":"1a3e865977024f444834a75a1b33b89b93134c93007ae3d6e14f24e6c88d8dfb","src/theme/fonts/open-sans-v17-all-charsets-700.woff2":"c22fe8c70c36f1d862903b772eaed864d3a8fa849473c9caff224fdb852428e4","src/theme/fonts/open-sans-v17-all-charsets-700italic.woff2":"238ae9593944112bee8dd65f8ebc5f3d3862160a8a245fbe1ee3150bc9a2fd81","src/theme/fonts/open-sans-v17-all-charsets-800.woff2":"3d2c812adf74deb36fead3ff8469800d3c0b23eb2c858ae49310291f89490146","src/theme/fonts/open-sans-v17-all-charsets-800italic.woff2":"ba1521ec219db9bc5bfec0e3e7a897369d98b30d4e853ee4aa525322784428b8","src/theme/fonts/open-sans-v17-all-charsets-italic.woff2":"6c9463f7096c0b9d610e095ed248ac1e8a8da7e92d17e9be544f3baced7b62b2","src/theme/fonts/open-sans-v17-all-charsets-regular.woff2":"2e3b1d34ac67763ab50652da19305d4b3694c6b6e6bf35f4b98411ce4af646d2","src/theme/fonts/source-code-pro-v11-all-charsets-500.woff2":"2bdd9410b0141db3cbbf4cfc3818cc6fad279e8e63940940e06cd6af76ccbfcf","src/theme/head.hbs":"56b3ab3c6eabd4723d4794ecd0a7452aa8903c55a2106d60bceacc74d76311c3","src/theme/header.hbs":"1fd27c9ccd016060dc4d6e77f12bf58b26e7c604aebe2577a67097f95a3de70a","src/theme/highlight.css":"6ebb896cc720d92a56def939b787cb25a2facfcfa9d95eeac9f979b092f15716","src/theme/highlight.js":"5a2b5dadd60831dd1f82220223e2ab18e627061912cc89b5c450ab2c8f26ff90","src/theme/index.hbs":"4698beb607dd1c5571ecc60256bf6858265b4ac546548805f2345ea679dd5976","src/theme/mod.rs":"b8224089da80257f2a6550691ef4334b5f746520dfcbf61906224e4afbcf44ba","src/theme/playground_editor/ace.js":"2a3cd908c9619862b52f621ce2a40f76b772eb51c17308b14bd26d1809af8f87","src/theme/playground_editor/editor.js":"16ca416ca77428fe23cb8e18afbd3626a6a86723d6b6e189c47da95d9e9bdc31","src/theme/playground_editor/mod.rs":"b6b0f99f00ccb83cedfe5ce892834b46936a468611d056eae0f146e59711dc5c","src/theme/playground_editor/mode-rust.js":"2c9d5c9af5ae32612aef1ca5653e3473ed40747d36ecb4a97719ff14707d8535","src/theme/playground_editor/theme-dawn.js":"4493f9c88ed7185f7bb4195be77018d21cdc439a34bd4e5da64b566eb996fbe8","src/theme/playground_editor/theme-tomorrow_night.js":"9dbe62a913ebe3fd9667f41f69c0301bacd963081c69abb0219e4acac4710f60","src/theme/redirect.hbs":"c10b6e36dda1a4f222aa61cd1c6180a2f2937397379adba2c10b9b41e446709e","src/theme/searcher/elasticlunr.min.js":"ef4e11c157b1e2e89782d30bd726f2d5ff7834ea5e26ad02474325f8b1f126c9","src/theme/searcher/mark.min.js":"09e88c2cfaf23ea8a37b5681433eafea97033af632ecc948c8c1ee9944647743","src/theme/searcher/mod.rs":"36979040719b2fa39d1b78808e41cdb6e52e0ea5137c84820b437ed015278072","src/theme/searcher/searcher.js":"5fa8ef792186dcb36dea668de68d6472b899b56ddfb1a1aa8015f4dc7e16af09","src/theme/tomorrow-night.css":"243cb61aa526cef79b3545b1c7f2b681747dd346867c8ceb36c69487acc390fb","src/utils/fs.rs":"4d00080337802a355df25c85a378eae00fb3b8016f80fe71413d6e20463eca60","src/utils/mod.rs":"e4476a3afda9964cb57e29f87ee03f4d8860cdb17a7b3fe5b56e108420adc2f6","src/utils/string.rs":"34ac2235625b52530d335b318a2bea1007c6ae56f39d2e0e5f1013a23ec1ef6f","src/utils/toml_ext.rs":"77e7cb18786cdccf19983a25a3c1b44a18166fe440c3233ccb0303003f105bee","tests/alternative_backends.rs":"1453a25311e8da9d81809381f22382a93f4f2d16bb710b8c566831cea37b15ca","tests/build_process.rs":"a958404fc41ff5c00b08b4c69d26f0862160e20c781b4bea88977d85304b6ef5","tests/custom_preprocessors.rs":"22a5da0ed34ab2fe85d87ceb70e06c2a5065d66c363a39ce7d45715ae974ad1c","tests/dummy_book/mod.rs":"9b4353da9156697787cca654092c0509fec2a8bfa292bbe5d0a5414234c6f6af","tests/dummy_book/src/README.md":"2f6e578b9f31ff5e1d18ae40865355d59e56a23e02798bd8166751245ef4eb9b","tests/dummy_book/src/SUMMARY.md":"3384fd28e2974749eedf385bd3a996b71cc248abf545a696a3fda6180d22d31a","tests/dummy_book/src/conclusion.md":"eca0543344979e938b43debf3d310290a628e8b7b45d3d9bec63c21e61284a4c","tests/dummy_book/src/example.rs":"3be109d6faa3c6104c8fb5e8ffdfe3eba73d0a5ed4f537685fe2cf2c36e657d0","tests/dummy_book/src/first/includes.md":"747f8f1eb4d394c1fdb773acddb7ffdc641e3ad71b0d15afb0f4e2de13a729ed","tests/dummy_book/src/first/index.md":"e7d1af4cb454c0be73bf1e2f01a97541fba385cd04ac5c9a7acc99809adedee8","tests/dummy_book/src/first/markdown.md":"461753f7f5105e35bc246c752065a44ea1d238f6890bd01b7c34d0a5746f7902","tests/dummy_book/src/first/nested-test-with-anchors.rs":"6fdecb4c62201f2dae36ea7e35693238edca03dcfc42d33eaf1685bc957a6d1d","tests/dummy_book/src/first/nested-test.rs":"ca4cdf552842a957be49ffc753f7585dba3c0036a076fea68174719599d426fa","tests/dummy_book/src/first/nested.md":"485d24764340c0413939e52533ab304c07bb55bd23d0ad9e31151ff889425048","tests/dummy_book/src/first/partially-included-test-with-anchors.rs":"501d96562da17cbec46444a004340e711b3fac4b3384f12d7c4844909742c8c8","tests/dummy_book/src/first/partially-included-test.rs":"1bdd1a4f8fdc41ea10868f97de0fe315b2cc592d4cf4aabd784f17dc8c0a6e90","tests/dummy_book/src/first/recursive.md":"9b574239c94c24412dbd918d7b85f557a80cec44d245663cfe1ecdd8ed16765e","tests/dummy_book/src/first/unicode.md":"04a548a642ba5cbc346670a8b38c1aeb5ad23d5a967849783171c634b682de63","tests/dummy_book/src/intro.md":"2749920beee7f563f3ace2bbef204dc66382e052c7945bf27e66912351959a90","tests/dummy_book/src/second.md":"b1344cb47f69621ed68197b81652df1f86254b71b4e3dcbdcf707a4e1fee3340","tests/dummy_book/src/second/nested.md":"b0da2ce6ce1ac5fbda92b5cf7a6a09d39abd267095a29f177e44cd4e8d333d45","tests/dummy_book/src2/README.md":"1bcffb061e737e022f132f78a2dd3193fc0951d0b104e50ddc860d9bc260f505","tests/dummy_book/src2/SUMMARY.md":"4354bec1cae7db3c48dfe869e28e8e29958daef937b33da5e729211372ccb9c9","tests/dummy_book/src2/first/README.md":"ba505ed6c1e18c85ce2ca7070021c719933ce2cf9f28de8565c188c0e4a95d87","tests/dummy_book/src2/second/README.md":"2fb4a90a1359fe3725c3d95888452afd514b0b86bdc4e2768442a71bf5b642a0","tests/dummy_book/src2/second/index.md":"5bf990bec982b9e87d8dfb230fb2dfc96318d9065f97a3d3c5cf27bd134c8bdd","tests/init.rs":"087f4e2814ddc55b4726e2491c460191c387e930d86b2b9716f28baa8fa54ff9","tests/parse_existing_summary_files.rs":"f4b019e66ffc7f59efd7ec9da73bb70180e4cc23ff27904bf4dfd26491ef64a3","tests/rendered_output.rs":"79373359eaa8fd03e8bd278b576fd076d7d30450a13fa69fa40bf0f472100bdd","tests/searchindex_fixture.json":"3bedb596b17e0b74ac4e146de884594ea2a92e45ff2fe24d423c94bead8288d5","tests/summary_md_files/example_book.md":"e1dd09043d9548612b0bb4e607a8796317272aa1fe7a2bda55db6e6f47d3fc5a","tests/summary_md_files/rust_by_example.md":"c46c8eab64780297b851be196a04d573da69553f4d9c33e24fbd5fb2867efbfd","tests/summary_md_files/rust_ffi_guide.md":"26874d9ad22cfdc2a587e7a495a4404247821d2b6e8eabe07334cacc5a4ea365","tests/summary_md_files/the_book-2nd_edition.md":"7ae64929c45aa7d67560c77e5280a540c22d1b0d2f8fd85f8392ce064c2d5f0a","tests/testing.rs":"c80d579682b969045d0c067f7ae5ab425255f83642f9dfd11a42f3de75e1b4a8"},"package":"b75e31ae4eaa0e45e17ee2b6b9e3ed969c3c6ff12bb4c2e352c42493f4ebb706"} \ No newline at end of file +{"files":{"CHANGELOG.md":"01fe77b97e8d5a11bd70a48929efabbf2d29964a7ee55126fa2bdfbada00db8b","CONTRIBUTING.md":"680cef0c70325c2e45ede352422ae249ed212c65fc5f502c2267243b89187595","Cargo.lock":"b74e22f840ba0528d5f6b3118936fb26bce080216d6f3a3e57af278c89e2e0f1","Cargo.toml":"db76847db3a06a0b46319ed5d71a83fa0fb85c1cae97030b50e21ef0eeabfe0f","LICENSE":"af175b9d96ee93c21a036152e1b905b0b95304d4ae8c2c921c7609100ba8df7e","README.md":"00d699272528d6a208e8d03f5f99911340c130504aa3e6b04a1905f189433f14","ci/install-hub.sh":"ef529e66465dd624d502f4bd4a1092a741f788b948a98625b1f01375149f4ff7","ci/install-rust.sh":"c7b63b4aff867d6da241c23b45121f3efa9cf62b43f839f0eb0d4d0f86580dd6","ci/make-release.sh":"fcf307a3d28ebd60b4b339f960bc0533dfb1bafe37f3c041fac72b49c279bb3b","examples/nop-preprocessor.rs":"db48153fed353c761ec6a64774f4340a91b4ea8c07236ef571bd7601dc5bd17b","release.toml":"25e91966f4a77515244adf5775d638590916c550f9d25bba6024d629b71840e8","src/book/book.rs":"ea53860086d73d81dcbc72d2f3acddf66786ae4486674e0550396998bb10afa9","src/book/init.rs":"fad0ae98277a8b6e9eb4f79776316f2492be4866702ba32ea9745659f6087a05","src/book/mod.rs":"9f2e291b2110dd91dac88801520772122c0d9aa346c531686e9a541e935e01b2","src/book/summary.rs":"7f5f0b45a5b31dbdfc70c4fbcde60a60d1a2a771b0f2130c2d62cb06a8af0f29","src/cmd/build.rs":"7a87f609ad245a808137c9ff67a92b14238c8b01c3afc834ce166f3ff161a58f","src/cmd/clean.rs":"411579d00103568b8e904db647b6360bd8f9b11d209f595d0a6de0a6e08f8915","src/cmd/init.rs":"3161219d9c4375d296c2f39fdb9cffdad09b373b46f1af5b9543173671a58e5b","src/cmd/mod.rs":"29116e5ca90e916a5f4ce62581a29508670ef184ec3e20569e2ad90b57472abe","src/cmd/serve.rs":"a15a0d7a7cbe9e0421fb2948e6e88e7c1206602dd211d666129e67bc973ad626","src/cmd/test.rs":"405e82cc63f212ec6f41e2017d34aba369c8d581b9c1431c8696d787aa2ee1cf","src/cmd/watch.rs":"86bcf487612c03a3d30c48094aa9b23350226e3e6fbb5850799e61d6f741b81e","src/config.rs":"d2e10952cd4da18685b600aad5696cb41aa38d1c134e1d21a240f0b402e1286f","src/lib.rs":"5f14dc00233be5b80d41530dd44d09f46bff30fbdf418a97e8e237f53e14ea6a","src/main.rs":"867f696a76921341ab1f0664c20f3efb90c2c5cbdf8da34d5a52205b33481c84","src/preprocess/cmd.rs":"cf5a35406e0804df391c90a004e3f8624c518517a3e0b136c5341fac067068ea","src/preprocess/index.rs":"d6d34bc61165dd5f42005e5d601d6729c40cacd656358ede17798effa309e508","src/preprocess/links.rs":"ad161e8545ec7198afc98da2cb8935ed0eb242f88f36494738932c50ba0633ab","src/preprocess/mod.rs":"b699f993473abdf6e4abbe038c8286b14312003e5d4713d946b9ae87047270e7","src/renderer/html_handlebars/hbs_renderer.rs":"27bb7bb89f9f2abbe234f7266e9d2840f9f4f86711da1329e0033ef50e8ca189","src/renderer/html_handlebars/helpers/mod.rs":"d83520feecce350b03b7ffaa9f34d6db2fe7316a46562be694b8eef537124191","src/renderer/html_handlebars/helpers/navigation.rs":"51d6fed8f4af42af10a66bf24804337c87cf93daba893f2f3664b3683a24a9e1","src/renderer/html_handlebars/helpers/theme.rs":"06713b5de794eaf68538e929cce58fe55a6e48afd5e9d3bb211ef47809d18af2","src/renderer/html_handlebars/helpers/toc.rs":"b3d86fa13d1508eaae9f25a685802273048a5c22b6bf094abbad0b7c19cc0afc","src/renderer/html_handlebars/mod.rs":"b6be4801cf49040edc9dad216ed12c26dce87e2dc4724ee24729e4a8b67734b0","src/renderer/html_handlebars/search.rs":"626e3cbec3587b90a8209a314e555533cc9b3e98f54270aafc4ab9f471847599","src/renderer/markdown_renderer.rs":"319453627fa416d44e5459a3f9f4cf07b87a4133ff97df5fc962768c9235c65f","src/renderer/mod.rs":"56c11e129556e7f22750a1ad30785719f761ff98a1ca1409b5981e95a6986429","src/theme/FontAwesome/css/font-awesome.min.css":"799aeb25cc0373fdee0e1b1db7ad6c2f6a0e058dfadaa3379689f583213190bd","src/theme/FontAwesome/fonts/FontAwesome.otf":"444dd4366615ffc4a16d012b2fa90137065d3ccb410fa6fd5e4ddd7b5e4ffcd5","src/theme/FontAwesome/fonts/fontawesome-webfont.eot":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","src/theme/FontAwesome/fonts/fontawesome-webfont.svg":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","src/theme/FontAwesome/fonts/fontawesome-webfont.ttf":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","src/theme/FontAwesome/fonts/fontawesome-webfont.woff":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","src/theme/FontAwesome/fonts/fontawesome-webfont.woff2":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","src/theme/ayu-highlight.css":"c141251b5888ccc185c31976e6cb9234f7827ae6bc4975926cafc8bca5e8f83d","src/theme/book.js":"418a647fcdc6ed5388e5c669e10cb796a8d851c2b24d97c416bcb050fdaa9008","src/theme/clipboard.min.js":"1626706afc88d95ebe1173b553ec732c6dc82a576989315fdf5e7779af738a44","src/theme/css/chrome.css":"576bd3d1e4748ab1a7e000eb110f83f1b643fa4f8339b90a9305302e5c68aaeb","src/theme/css/general.css":"4c89e3e531bc5ca322e4210c8d1868d5a97df0f2a2726a7d60c192f7d933fe19","src/theme/css/print.css":"a4278dff9af38765eb9d344aa56dcc652ac79c73afc408385b62a4b611b89c14","src/theme/css/variables.css":"ccf9aa3f3dcb79b967e13658d101b3f7b9efa914ae0c5e05ac5ed322af33c5bf","src/theme/favicon.png":"8114d1fc74f4b5621ad9afde7746ed9cf7e420be317a6e29023d2298d58aa15b","src/theme/favicon.svg":"de23e50b1c4dd6e052b3e21d444fcd4b13568b3840ac3c99d9be4e9263c0ef59","src/theme/fonts/OPEN-SANS-LICENSE.txt":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","src/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt":"d1e6d465a83ba1a3be52db6484868cf5812ae9bbf91abdad3900ba0165afcf93","src/theme/fonts/fonts.css":"2db113e6ebede8403c607db3dceb5acc53c247720d5955d22f7db56beb7139b6","src/theme/fonts/mod.rs":"9b97835fbc610c46245ac52f8d40df8f28ace0c4fe7aca0847835ee83cc21a15","src/theme/fonts/open-sans-v17-all-charsets-300.woff2":"7736aa3596c468515c3209f2f9d68cfae96d94c05689bcc11a5dce426a6ee2e8","src/theme/fonts/open-sans-v17-all-charsets-300italic.woff2":"2c7b95c08df0d228caec6d4bfed06da0f7ab6b76ea5cc3f75b5c6ae416bc571b","src/theme/fonts/open-sans-v17-all-charsets-600.woff2":"486c67592731a0b36a89dba1fd0b97aeb73f236bbf60dbf28d7c6b5723c07989","src/theme/fonts/open-sans-v17-all-charsets-600italic.woff2":"1a3e865977024f444834a75a1b33b89b93134c93007ae3d6e14f24e6c88d8dfb","src/theme/fonts/open-sans-v17-all-charsets-700.woff2":"c22fe8c70c36f1d862903b772eaed864d3a8fa849473c9caff224fdb852428e4","src/theme/fonts/open-sans-v17-all-charsets-700italic.woff2":"238ae9593944112bee8dd65f8ebc5f3d3862160a8a245fbe1ee3150bc9a2fd81","src/theme/fonts/open-sans-v17-all-charsets-800.woff2":"3d2c812adf74deb36fead3ff8469800d3c0b23eb2c858ae49310291f89490146","src/theme/fonts/open-sans-v17-all-charsets-800italic.woff2":"ba1521ec219db9bc5bfec0e3e7a897369d98b30d4e853ee4aa525322784428b8","src/theme/fonts/open-sans-v17-all-charsets-italic.woff2":"6c9463f7096c0b9d610e095ed248ac1e8a8da7e92d17e9be544f3baced7b62b2","src/theme/fonts/open-sans-v17-all-charsets-regular.woff2":"2e3b1d34ac67763ab50652da19305d4b3694c6b6e6bf35f4b98411ce4af646d2","src/theme/fonts/source-code-pro-v11-all-charsets-500.woff2":"2bdd9410b0141db3cbbf4cfc3818cc6fad279e8e63940940e06cd6af76ccbfcf","src/theme/head.hbs":"56b3ab3c6eabd4723d4794ecd0a7452aa8903c55a2106d60bceacc74d76311c3","src/theme/header.hbs":"1fd27c9ccd016060dc4d6e77f12bf58b26e7c604aebe2577a67097f95a3de70a","src/theme/highlight.css":"6ebb896cc720d92a56def939b787cb25a2facfcfa9d95eeac9f979b092f15716","src/theme/highlight.js":"5a2b5dadd60831dd1f82220223e2ab18e627061912cc89b5c450ab2c8f26ff90","src/theme/index.hbs":"4698beb607dd1c5571ecc60256bf6858265b4ac546548805f2345ea679dd5976","src/theme/mod.rs":"b8224089da80257f2a6550691ef4334b5f746520dfcbf61906224e4afbcf44ba","src/theme/playground_editor/ace.js":"2a3cd908c9619862b52f621ce2a40f76b772eb51c17308b14bd26d1809af8f87","src/theme/playground_editor/editor.js":"16ca416ca77428fe23cb8e18afbd3626a6a86723d6b6e189c47da95d9e9bdc31","src/theme/playground_editor/mod.rs":"b6b0f99f00ccb83cedfe5ce892834b46936a468611d056eae0f146e59711dc5c","src/theme/playground_editor/mode-rust.js":"2c9d5c9af5ae32612aef1ca5653e3473ed40747d36ecb4a97719ff14707d8535","src/theme/playground_editor/theme-dawn.js":"4493f9c88ed7185f7bb4195be77018d21cdc439a34bd4e5da64b566eb996fbe8","src/theme/playground_editor/theme-tomorrow_night.js":"9dbe62a913ebe3fd9667f41f69c0301bacd963081c69abb0219e4acac4710f60","src/theme/redirect.hbs":"c10b6e36dda1a4f222aa61cd1c6180a2f2937397379adba2c10b9b41e446709e","src/theme/searcher/elasticlunr.min.js":"ef4e11c157b1e2e89782d30bd726f2d5ff7834ea5e26ad02474325f8b1f126c9","src/theme/searcher/mark.min.js":"09e88c2cfaf23ea8a37b5681433eafea97033af632ecc948c8c1ee9944647743","src/theme/searcher/mod.rs":"36979040719b2fa39d1b78808e41cdb6e52e0ea5137c84820b437ed015278072","src/theme/searcher/searcher.js":"5fa8ef792186dcb36dea668de68d6472b899b56ddfb1a1aa8015f4dc7e16af09","src/theme/tomorrow-night.css":"243cb61aa526cef79b3545b1c7f2b681747dd346867c8ceb36c69487acc390fb","src/utils/fs.rs":"4d00080337802a355df25c85a378eae00fb3b8016f80fe71413d6e20463eca60","src/utils/mod.rs":"e4476a3afda9964cb57e29f87ee03f4d8860cdb17a7b3fe5b56e108420adc2f6","src/utils/string.rs":"34ac2235625b52530d335b318a2bea1007c6ae56f39d2e0e5f1013a23ec1ef6f","src/utils/toml_ext.rs":"77e7cb18786cdccf19983a25a3c1b44a18166fe440c3233ccb0303003f105bee","tests/alternative_backends.rs":"1453a25311e8da9d81809381f22382a93f4f2d16bb710b8c566831cea37b15ca","tests/build_process.rs":"a958404fc41ff5c00b08b4c69d26f0862160e20c781b4bea88977d85304b6ef5","tests/custom_preprocessors.rs":"22a5da0ed34ab2fe85d87ceb70e06c2a5065d66c363a39ce7d45715ae974ad1c","tests/dummy_book/mod.rs":"9b4353da9156697787cca654092c0509fec2a8bfa292bbe5d0a5414234c6f6af","tests/dummy_book/src/README.md":"2f6e578b9f31ff5e1d18ae40865355d59e56a23e02798bd8166751245ef4eb9b","tests/dummy_book/src/SUMMARY.md":"3384fd28e2974749eedf385bd3a996b71cc248abf545a696a3fda6180d22d31a","tests/dummy_book/src/conclusion.md":"eca0543344979e938b43debf3d310290a628e8b7b45d3d9bec63c21e61284a4c","tests/dummy_book/src/example.rs":"3be109d6faa3c6104c8fb5e8ffdfe3eba73d0a5ed4f537685fe2cf2c36e657d0","tests/dummy_book/src/first/includes.md":"747f8f1eb4d394c1fdb773acddb7ffdc641e3ad71b0d15afb0f4e2de13a729ed","tests/dummy_book/src/first/index.md":"e7d1af4cb454c0be73bf1e2f01a97541fba385cd04ac5c9a7acc99809adedee8","tests/dummy_book/src/first/markdown.md":"461753f7f5105e35bc246c752065a44ea1d238f6890bd01b7c34d0a5746f7902","tests/dummy_book/src/first/nested-test-with-anchors.rs":"6fdecb4c62201f2dae36ea7e35693238edca03dcfc42d33eaf1685bc957a6d1d","tests/dummy_book/src/first/nested-test.rs":"ca4cdf552842a957be49ffc753f7585dba3c0036a076fea68174719599d426fa","tests/dummy_book/src/first/nested.md":"485d24764340c0413939e52533ab304c07bb55bd23d0ad9e31151ff889425048","tests/dummy_book/src/first/partially-included-test-with-anchors.rs":"501d96562da17cbec46444a004340e711b3fac4b3384f12d7c4844909742c8c8","tests/dummy_book/src/first/partially-included-test.rs":"1bdd1a4f8fdc41ea10868f97de0fe315b2cc592d4cf4aabd784f17dc8c0a6e90","tests/dummy_book/src/first/recursive.md":"9b574239c94c24412dbd918d7b85f557a80cec44d245663cfe1ecdd8ed16765e","tests/dummy_book/src/first/unicode.md":"04a548a642ba5cbc346670a8b38c1aeb5ad23d5a967849783171c634b682de63","tests/dummy_book/src/intro.md":"2749920beee7f563f3ace2bbef204dc66382e052c7945bf27e66912351959a90","tests/dummy_book/src/second.md":"b1344cb47f69621ed68197b81652df1f86254b71b4e3dcbdcf707a4e1fee3340","tests/dummy_book/src/second/nested.md":"b0da2ce6ce1ac5fbda92b5cf7a6a09d39abd267095a29f177e44cd4e8d333d45","tests/dummy_book/src2/README.md":"1bcffb061e737e022f132f78a2dd3193fc0951d0b104e50ddc860d9bc260f505","tests/dummy_book/src2/SUMMARY.md":"4354bec1cae7db3c48dfe869e28e8e29958daef937b33da5e729211372ccb9c9","tests/dummy_book/src2/first/README.md":"ba505ed6c1e18c85ce2ca7070021c719933ce2cf9f28de8565c188c0e4a95d87","tests/dummy_book/src2/second/README.md":"2fb4a90a1359fe3725c3d95888452afd514b0b86bdc4e2768442a71bf5b642a0","tests/dummy_book/src2/second/index.md":"5bf990bec982b9e87d8dfb230fb2dfc96318d9065f97a3d3c5cf27bd134c8bdd","tests/init.rs":"087f4e2814ddc55b4726e2491c460191c387e930d86b2b9716f28baa8fa54ff9","tests/parse_existing_summary_files.rs":"f4b019e66ffc7f59efd7ec9da73bb70180e4cc23ff27904bf4dfd26491ef64a3","tests/rendered_output.rs":"79373359eaa8fd03e8bd278b576fd076d7d30450a13fa69fa40bf0f472100bdd","tests/searchindex_fixture.json":"3bedb596b17e0b74ac4e146de884594ea2a92e45ff2fe24d423c94bead8288d5","tests/summary_md_files/example_book.md":"e1dd09043d9548612b0bb4e607a8796317272aa1fe7a2bda55db6e6f47d3fc5a","tests/summary_md_files/rust_by_example.md":"c46c8eab64780297b851be196a04d573da69553f4d9c33e24fbd5fb2867efbfd","tests/summary_md_files/rust_ffi_guide.md":"26874d9ad22cfdc2a587e7a495a4404247821d2b6e8eabe07334cacc5a4ea365","tests/summary_md_files/the_book-2nd_edition.md":"7ae64929c45aa7d67560c77e5280a540c22d1b0d2f8fd85f8392ce064c2d5f0a","tests/testing.rs":"c80d579682b969045d0c067f7ae5ab425255f83642f9dfd11a42f3de75e1b4a8"},"package":"29be448fcafb00c5a8966c4020c2a5ffbbc333e5b96d0bb5ef54b5bd0524d9ff"} \ No newline at end of file diff --git a/vendor/mdbook/CHANGELOG.md b/vendor/mdbook/CHANGELOG.md index d6744dd26b..3f90557fce 100644 --- a/vendor/mdbook/CHANGELOG.md +++ b/vendor/mdbook/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## mdBook 0.4.3 +[9278b83...9278b83](https://github.com/rust-lang/mdBook/compare/9278b83...4df9ec9) + +### Added +- Added `output.html.cname` option to emit a `CNAME` file which is used by + GitHub Pages to know which domain is being used. + [#1311](https://github.com/rust-lang/mdBook/pull/1311) + +### Changed +- `mdbook test` no longer stops on the first test failure, but instead will + run all the tests. + [#1313](https://github.com/rust-lang/mdBook/pull/1313) +- Removed the `local` font source for Source Code Pro, as the locally + installed font may not render properly on FireFox on macOS. + [#1307](https://github.com/rust-lang/mdBook/pull/1307) + +### Fixed +- Added newline to end of `.nojekyll` file. + [#1310](https://github.com/rust-lang/mdBook/pull/1310) +- Fixed missing space before draft chapter titles. + [#1309](https://github.com/rust-lang/mdBook/pull/1309) + ## mdBook 0.4.2 [649f355...9278b83](https://github.com/rust-lang/mdBook/compare/649f355...9278b83) diff --git a/vendor/mdbook/Cargo.lock b/vendor/mdbook/Cargo.lock index 463a69efc9..f9619fabff 100644 --- a/vendor/mdbook/Cargo.lock +++ b/vendor/mdbook/Cargo.lock @@ -723,7 +723,7 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "mdbook" -version = "0.4.2" +version = "0.4.3" dependencies = [ "ammonia", "anyhow", diff --git a/vendor/mdbook/Cargo.toml b/vendor/mdbook/Cargo.toml index c631d5a9b3..e7215f4d0c 100644 --- a/vendor/mdbook/Cargo.toml +++ b/vendor/mdbook/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "mdbook" -version = "0.4.2" +version = "0.4.3" authors = ["Mathieu David ", "Michael-F-Bryan ", "Matt Ickstadt "] exclude = ["/book-example/*"] description = "Creates a book from markdown files" diff --git a/vendor/mdbook/README.md b/vendor/mdbook/README.md index 6f839b86a3..392180dfd5 100644 --- a/vendor/mdbook/README.md +++ b/vendor/mdbook/README.md @@ -209,7 +209,7 @@ tagged [E-Easy] and **we will gladly mentor you** so that you can successfully go through the process of fixing a bug or adding a new feature! Let us know if you need any help. -For more info about contributing, check out our [contribution guide] who helps +For more info about contributing, check out our [contribution guide] which helps you go through the build and contribution process! There is also a [rendered version][master-docs] of the latest API docs diff --git a/vendor/mdbook/src/book/mod.rs b/vendor/mdbook/src/book/mod.rs index 71f0197fe4..0723578f8b 100644 --- a/vendor/mdbook/src/book/mod.rs +++ b/vendor/mdbook/src/book/mod.rs @@ -250,6 +250,7 @@ impl MDBook { // Index Preprocessor is disabled so that chapter paths continue to point to the // actual markdown files. + let mut failed = false; for item in book.iter() { if let BookItem::Chapter(ref ch) = *item { let chapter_path = match ch.path { @@ -282,7 +283,8 @@ impl MDBook { let output = cmd.output()?; if !output.status.success() { - bail!( + failed = true; + error!( "rustdoc returned an error:\n\ \n--- stdout\n{}\n--- stderr\n{}", String::from_utf8_lossy(&output.stdout), @@ -291,6 +293,9 @@ impl MDBook { } } } + if failed { + bail!("One or more tests failed"); + } Ok(()) } diff --git a/vendor/mdbook/src/config.rs b/vendor/mdbook/src/config.rs index 1389f13921..ef6bc6876e 100644 --- a/vendor/mdbook/src/config.rs +++ b/vendor/mdbook/src/config.rs @@ -508,6 +508,13 @@ pub struct HtmlConfig { pub input_404: Option, /// Absolute url to site, used to emit correct paths for the 404 page, which might be accessed in a deeply nested directory pub site_url: Option, + /// The DNS subdomain or apex domain at which your book will be hosted. This + /// string will be written to a file named CNAME in the root of your site, + /// as required by GitHub Pages (see [*Managing a custom domain for your + /// GitHub Pages site*][custom domain]). + /// + /// [custom domain]: https://docs.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site + pub cname: Option, /// This is used as a bit of a workaround for the `mdbook serve` command. /// Basically, because you set the websocket port from the command line, the /// `mdbook serve` command needs a way to let the HTML renderer know where @@ -541,6 +548,7 @@ impl Default for HtmlConfig { git_repository_icon: None, input_404: None, site_url: None, + cname: None, livereload_url: None, redirect: HashMap::new(), } diff --git a/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs b/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs index 7880817b1e..4992730e69 100644 --- a/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs +++ b/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs @@ -184,9 +184,13 @@ impl HtmlHandlebars { write_file( destination, ".nojekyll", - b"This file makes sure that Github Pages doesn't process mdBook's output.", + b"This file makes sure that Github Pages doesn't process mdBook's output.\n", )?; + if let Some(cname) = &html_config.cname { + write_file(destination, "CNAME", format!("{}\n", cname).as_bytes())?; + } + write_file(destination, "book.js", &theme.js)?; write_file(destination, "css/general.css", &theme.general_css)?; write_file(destination, "css/chrome.css", &theme.chrome_css)?; diff --git a/vendor/mdbook/src/renderer/html_handlebars/helpers/toc.rs b/vendor/mdbook/src/renderer/html_handlebars/helpers/toc.rs index 47eda59692..7a5d8a2844 100644 --- a/vendor/mdbook/src/renderer/html_handlebars/helpers/toc.rs +++ b/vendor/mdbook/src/renderer/html_handlebars/helpers/toc.rs @@ -108,32 +108,32 @@ impl HelperDef for RenderToc { } // Link - let path_exists = if let Some(path) = item.get("path") { - if !path.is_empty() { - out.write("")?; - true - } else { - false + let path_exists = if let Some(path) = + item.get("path") + .and_then(|p| if p.is_empty() { None } else { Some(p) }) + { + out.write("")?; + true } else { + out.write("

    ")?; } // Render expand/collapse toggle diff --git a/vendor/merge/.cargo-checksum.json b/vendor/merge/.cargo-checksum.json new file mode 100644 index 0000000000..f34d2c2360 --- /dev/null +++ b/vendor/merge/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"bd0078d7348a85fc7610eb3cb7da3bc4bad24f206fdf7a8dd7f8228edc7e5db0","Cargo.lock":"ad827835f7e148d5d6aae191c95d5a4d92c9636b9eacb22337d21c8e633fae9d","Cargo.toml":"15b331689931ce323547deebcafbbc3ce7b524bdb7a8b5add640784165a3095a","LICENSES/Apache-2.0.txt":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSES/CC0-1.0.txt":"6a573fb2f9082662978cf21fb153096df0a1981deaea7dbc10a11046fe005d9f","LICENSES/MIT.txt":"7bf39b72495d83b97bd314f9a58e1153455c427e5ea07e26437ac045aafa11d0","README.md":"34c55828910f5652951db174bc7d57fac0fc0fe527bf685fe3d78c41e3df2c97","examples/args.rs":"f3379155bc7f6b54db358ca1aac3728032322dc1d4e61066640c950443328e25","examples/user.rs":"bace343d99c6649f54049c04b55205a1e723662283087edf349316542e194863","src/lib.rs":"1c949876557448e8b33bbfece0f3d988344dfb661d554e438b5d3b0aaccbfcd4","tests/compile.rs":"064ca60baa606377d96c9b49d4ccb7984b1d5882557b4a36782e789486ee3ca6","tests/compile/derive-enum.rs":"602986493d04381346777a94d0bf0059ae4e318f1581aa60693f4b6bd449bdf8","tests/compile/derive-enum.stderr":"748c10c72984908503342ea915d06ac823532749a06256c0536c1b49878a602c","tests/compile/derive-invalid-attribute.rs":"41cdb984bb1bd9022191432244e1ccb53df0d4ebb9c9d34175320568dde32948","tests/compile/derive-invalid-attribute.stderr":"09ee6f8011169fbaaab8a5216012f7e04186132f16b788df6c7029405aac960d","tests/compile/derive-invalid-skip.rs":"1e6fe0b503793f1c50a0982c8a7a4e056916bf4ae3aa47e8ecdfae548f55f40c","tests/compile/derive-invalid-skip.stderr":"ad1b3febd8ad0fd6118e4c0e0bdb0accde707460bdc2b80fae7553dd8eb2cd6a","tests/compile/derive-invalid-strategy.rs":"89c17c0ed2349af3664dc6782d004385e52eb9d1210b01991668079837896fcc","tests/compile/derive-invalid-strategy.stderr":"78f45b8d3ebe8d992f6eac6091b63aac8319f2aaa9a6513fa2b48f616f49b3a9","tests/compile/derive-missing-strategy.rs":"04b44f96d788d158ceaf399c148073c4c41a0d98793d55941c8b4e15350e9354","tests/compile/derive-missing-strategy.stderr":"40155bf928c1e1a9abeba8d5161251937ed49f833cfc4859d0ed22df57a38a86","tests/compile/derive-no-strategy.rs":"31926a1b666d72b7f6bdadde5680a676ed2d39595714ed6467be4cf4a7fa5686","tests/compile/derive-no-strategy.stderr":"2006acac73f7d93bdc1f92cbd7218e69e1c0de67f41b0804280d086a6de01ecc","tests/compile/derive-u8.rs":"335ec5984150c216a7132b208b7426d5987af090c0f650bed183f9280bd51e6c","tests/compile/derive-u8.stderr":"dff1ef27d3a1fc4556daf614307c70fbca2d400dbacdf51af9b9d3570400a962","tests/derive.rs":"f3d6a11660129bc3957487b780976aadd7b674d2a2357630c071e4984fb23c97","tests/impls.rs":"50b3ed1f8ca43b9959d40326b6e8b79a34f045f79e676700cf1d06c195dd7e12","tests/strategies.rs":"3e6ddb9bbf46188552e6c6cb9cf6c6450e4d234a897837500e914477a592d92e"},"package":"10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9"} \ No newline at end of file diff --git a/vendor/merge/CHANGELOG.md b/vendor/merge/CHANGELOG.md new file mode 100644 index 0000000000..5e52de0991 --- /dev/null +++ b/vendor/merge/CHANGELOG.md @@ -0,0 +1,9 @@ + + +# v0.1.0 (2020-09-01) + +Initial release providing the `Merge` trait and some merge strategies in the +`bool`, `num`, `ord` and `vec` modules. diff --git a/vendor/merge/Cargo.lock b/vendor/merge/Cargo.lock new file mode 100644 index 0000000000..7ffd14e126 --- /dev/null +++ b/vendor/merge/Cargo.lock @@ -0,0 +1,372 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +# SPDX-FileCopyrightText: 2020 Robin Krahl +# SPDX-License-Identifier: CC0-1.0 +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "envy" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "merge" +version = "0.1.0" +dependencies = [ + "envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "merge_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "trybuild 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "merge_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", + "syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "structopt" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "structopt-derive" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn-mid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termcolor" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "trybuild" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +"checksum envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f938a4abd5b75fe3737902dbc2e79ca142cc1526827a9e40b829a086758531a9" +"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)" = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" +"checksum merge_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" +"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +"checksum proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880" +"checksum proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50" +"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" +"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +"checksum serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum structopt 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc388d94ffabf39b5ed5fadddc40147cb21e605f53db6f8f36a625d27489ac5" +"checksum structopt-derive 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2513111825077552a6751dfad9e11ce0fba07d7276a3943a037d7e93e64c5f" +"checksum syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250" +"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +"checksum trybuild 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "bbe777c4e2060f44d83892be1189f96200be8ed3d99569d5c2d5ee26e62c0ea9" +"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" +"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/merge/Cargo.toml b/vendor/merge/Cargo.toml new file mode 100644 index 0000000000..0ced55242a --- /dev/null +++ b/vendor/merge/Cargo.toml @@ -0,0 +1,51 @@ +# 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 = "merge" +version = "0.1.0" +authors = ["Robin Krahl "] +exclude = [".builds/*"] +description = "Merge multiple values into one" +keywords = ["merge", "macros", "derive"] +categories = ["rust-patterns"] +license = "Apache-2.0 OR MIT" +repository = "https://git.sr.ht/~ireas/merge-rs" +[dependencies.merge_derive] +version = "0.1.0" +optional = true + +[dependencies.num-traits] +version = "0.2.12" +optional = true +[dev-dependencies.envy] +version = "0.4" + +[dev-dependencies.serde] +version = "1.0" +features = ["derive"] + +[dev-dependencies.structopt] +version = "0.3" + +[dev-dependencies.toml] +version = "0.5" + +[dev-dependencies.trybuild] +version = "1.0" + +[features] +default = ["derive", "num", "std"] +derive = ["merge_derive"] +num = ["num-traits"] +std = [] diff --git a/vendor/merge/LICENSES/Apache-2.0.txt b/vendor/merge/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/vendor/merge/LICENSES/Apache-2.0.txt @@ -0,0 +1,202 @@ + + 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/merge/LICENSES/CC0-1.0.txt b/vendor/merge/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000000..a343ccd433 --- /dev/null +++ b/vendor/merge/LICENSES/CC0-1.0.txt @@ -0,0 +1,119 @@ +Creative Commons Legal Code + +CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES +NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE +AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION +ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE +OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS +LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION +OR WORKS PROVIDED HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer exclusive +Copyright and Related Rights (defined below) upon the creator and subsequent +owner(s) (each and all, an "owner") of an original work of authorship and/or +a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later claims +of infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute +to the Commons to promote the ideal of a free culture and the further production +of creative, cultural and scientific works, or to gain reputation or greater +distribution for their Work in part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with +a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or +her Copyright and Related Rights in the Work and the meaning and intended +legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be protected +by copyright and related or neighboring rights ("Copyright and Related Rights"). +Copyright and Related Rights include, but are not limited to, the following: + +i. the right to reproduce, adapt, distribute, perform, display, communicate, +and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + +iii. publicity and privacy rights pertaining to a person's image or likeness +depicted in a Work; + +iv. rights protecting against unfair competition in regards to a Work, subject +to the limitations in paragraph 4(a), below; + +v. rights protecting the extraction, dissemination, use and reuse of data +in a Work; + +vi. database rights (such as those arising under Directive 96/9/EC of the +European Parliament and of the Council of 11 March 1996 on the legal protection +of databases, and under any national implementation thereof, including any +amended or successor version of such directive); and + +vii. other similar, equivalent or corresponding rights throughout the world +based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time extensions), +(iii) in any current or future medium and for any number of copies, and (iv) +for any purpose whatsoever, including without limitation commercial, advertising +or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the +benefit of each member of the public at large and to the detriment of Affirmer's +heirs and successors, fully intending that such Waiver shall not be subject +to revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account Affirmer's +express Statement of Purpose. In addition, to the extent the Waiver is so +judged Affirmer hereby grants to each affected person a royalty-free, non +transferable, non sublicensable, non exclusive, irrevocable and unconditional +license to exercise Affirmer's Copyright and Related Rights in the Work (i) +in all territories worldwide, (ii) for the maximum duration provided by applicable +law or treaty (including future time extensions), (iii) in any current or +future medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional purposes +(the "License"). The License shall be deemed effective as of the date CC0 +was applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder of +the License, and in such case Affirmer hereby affirms that he or she will +not (i) exercise any of his or her remaining Copyright and Related Rights +in the Work or (ii) assert any associated claims and causes of action with +respect to the Work, in either case contrary to Affirmer's express Statement +of Purpose. + + 4. Limitations and Disclaimers. + +a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, +licensed or otherwise affected by this document. + +b. Affirmer offers the Work as-is and makes no representations or warranties +of any kind concerning the Work, express, implied, statutory or otherwise, +including without limitation warranties of title, merchantability, fitness +for a particular purpose, non infringement, or the absence of latent or other +defects, accuracy, or the present or absence of errors, whether or not discoverable, +all to the greatest extent permissible under applicable law. + +c. Affirmer disclaims responsibility for clearing rights of other persons +that may apply to the Work or any use thereof, including without limitation +any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims +responsibility for obtaining any necessary consents, permissions or other +rights required for any use of the Work. + +d. Affirmer understands and acknowledges that Creative Commons is not a party +to this document and has no duty or obligation with respect to this CC0 or +use of the Work. diff --git a/vendor/merge/LICENSES/MIT.txt b/vendor/merge/LICENSES/MIT.txt new file mode 100644 index 0000000000..741cbc3898 --- /dev/null +++ b/vendor/merge/LICENSES/MIT.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Robin Krahl + +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/merge/README.md b/vendor/merge/README.md new file mode 100644 index 0000000000..1bdb16a242 --- /dev/null +++ b/vendor/merge/README.md @@ -0,0 +1,98 @@ + + +# merge-rs + +The `merge` crate provides the `Merge` trait that can be used to merge multiple +values into one: + +```rust +trait Merge { + fn merge(&mut self, other: Self); +} +``` + +`Merge` is implemented for `Option` and can be derived for structs: + + +```rust +use merge::Merge; + +#[derive(Merge)] +struct User { + // Fields with the skip attribute are skipped by Merge + #[merge(skip)] + pub name: &'static str, + + // The Merge implementation for Option replaces its value if it is None + pub location: Option<&'static str>, + + // The strategy attribute is used to customize the merge behavior + #[merge(strategy = merge::vec::append)] + pub groups: Vec<&'static str>, +} + +let defaults = User { + name: "", + location: Some("Internet"), + groups: vec!["rust"], +}; +let mut ferris = User { + name: "Ferris", + location: None, + groups: vec!["mascot"], +}; +ferris.merge(defaults); + +assert_eq!("Ferris", ferris.name); +assert_eq!(Some("Internet"), ferris.location); +assert_eq!(vec!["mascot", "rust"], ferris.groups); +``` + +A merge strategy is a function with the signature `fn merge(left: &mut T, +right: T)` that merges `right` into `left`. The `merge` crate provides +strategies for the most common types, but you can also define your own +strategies. + +The trait can be used to merge configuration from different sources, for +example environment variables, multiple configuration files and command-line +arguments, see the `args.rs` example. + +## Features + +This crate has the following features: + +- `derive` (default): Enables the derive macro for the `Merge` trait using the + `merge_derive` crate. +- `num` (default): Enables the merge strategies in the `num` module that + require the `num_traits` crate. +- `std` (default): Enables the merge strategies in the `vec` module that + require the standard library. If this feature is not set, `merge` is a + `no_std` library. + +## Minimum Supported Rust Version + +This crate supports Rust 1.36.0 or later. + +## Contact + +For bug reports, patches, feature requests and other messages, please send a +mail to [~ireas/public-inbox@lists.sr.ht][] using the `[merge-rs]` prefix in +the subject. + +## License + +This project is dual-licensed under the [Apache-2.0][] and [MIT][] licenses. +The documentation and configuration files contained in this repository are +licensed under the [Creative Commons Zero][CC0] license. You can find a copy +of the license texts in the `LICENSES` directory. + +`merge-rs` complies with [version 3.0 of the REUSE specification][reuse]. + +[~ireas/public-inbox@lists.sr.ht]: mailto:~ireas/public-inbox@lists.sr.ht +[Apache-2.0]: https://opensource.org/licenses/Apache-2.0 +[MIT]: https://opensource.org/licenses/MIT +[CC0]: https://creativecommons.org/publicdomain/zero/1.0/ +[reuse]: https://reuse.software/practices/3.0/ diff --git a/vendor/merge/examples/args.rs b/vendor/merge/examples/args.rs new file mode 100644 index 0000000000..616a1d47a8 --- /dev/null +++ b/vendor/merge/examples/args.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: CC0-1.0 + +use merge::Merge; +use serde::Deserialize; +use structopt::StructOpt; + +#[derive(Debug, Default, Deserialize, Merge, StructOpt)] +#[serde(default)] +struct Args { + #[structopt(short, long)] + #[merge(strategy = merge::bool::overwrite_false)] + debug: bool, + + input: Option, + + output: Option, +} + +fn get_config() -> Option { + let path: &std::path::Path = "args.toml".as_ref(); + if path.is_file() { + let s = std::fs::read_to_string(path).expect("Could not read configuration file"); + Some(toml::from_str(&s).expect("Could not parse configuration")) + } else { + None + } +} + +fn get_env() -> Args { + envy::prefixed("ARGS_") + .from_env() + .expect("Could not read environment variables") +} + +fn main() { + let mut args = Args::from_args(); + args.merge(get_env()); + if let Some(config) = get_config() { + args.merge(config); + } + println!("{:?}", args); +} diff --git a/vendor/merge/examples/user.rs b/vendor/merge/examples/user.rs new file mode 100644 index 0000000000..60161d73f3 --- /dev/null +++ b/vendor/merge/examples/user.rs @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: CC0-1.0 + +use merge::Merge; + +#[derive(Merge)] +struct User { + #[merge(skip)] + pub name: &'static str, + pub location: Option<&'static str>, + #[merge(strategy = merge::vec::append)] + pub groups: Vec<&'static str>, +} + +fn main() { + let defaults = User { + name: "", + location: Some("Internet"), + groups: vec!["rust"], + }; + let mut ferris = User { + name: "Ferris", + location: None, + groups: vec!["mascot"], + }; + ferris.merge(defaults); + + assert_eq!("Ferris", ferris.name); + assert_eq!(Some("Internet"), ferris.location); + assert_eq!(vec!["mascot", "rust"], ferris.groups); +} diff --git a/vendor/merge/src/lib.rs b/vendor/merge/src/lib.rs new file mode 100644 index 0000000000..2deebca4a3 --- /dev/null +++ b/vendor/merge/src/lib.rs @@ -0,0 +1,223 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +//! Provides [`Merge`][], a trait for objects that can be merged. +//! +//! # Usage +//! +//! ``` +//! trait Merge { +//! fn merge(&mut self, other: Self); +//! } +//! ``` +//! +//! The [`Merge`][] trait can be used to merge two objects of the same type into one. The intended +//! use case is merging configuration from different sources, for example environment variables, +//! multiple configuration files and command-line arguments, see the [`args.rs`][] example. +//! +//! `Merge` is implemented for `Option` and can be derived for structs. When deriving the `Merge` +//! trait for a struct, you can provide custom merge strategies for the fields that don’t implement +//! `Merge`. A merge strategy is a function with the signature `fn merge(left: &mut T, right: +//! T)` that merges `right` into `left`. The submodules of this crate provide strategies for the +//! most common types, but you can also define your own strategies. +//! +//! ## Features +//! +//! This crate has the following features: +//! +//! - `derive` (default): Enables the derive macro for the `Merge` trait using the `merge_derive` +//! crate. +//! - `num` (default): Enables the merge strategies in the `num` module that require the +//! `num_traits` crate. +//! - `std` (default): Enables the merge strategies in the `vec` module that require the standard +//! library. If this feature is not set, `merge` is a `no_std` library. +//! +//! # Example +//! +//! ``` +//! use merge::Merge; +//! +//! #[derive(Merge)] +//! struct User { +//! // Fields with the skip attribute are skipped by Merge +//! #[merge(skip)] +//! pub name: &'static str, +//! +//! // The Merge implementation for Option replaces its value if it is None +//! pub location: Option<&'static str>, +//! +//! // The strategy attribute is used to customize the merge behavior +//! #[merge(strategy = merge::vec::append)] +//! pub groups: Vec<&'static str>, +//! } +//! +//! let defaults = User { +//! name: "", +//! location: Some("Internet"), +//! groups: vec!["rust"], +//! }; +//! let mut ferris = User { +//! name: "Ferris", +//! location: None, +//! groups: vec!["mascot"], +//! }; +//! ferris.merge(defaults); +//! +//! assert_eq!("Ferris", ferris.name); +//! assert_eq!(Some("Internet"), ferris.location); +//! assert_eq!(vec!["mascot", "rust"], ferris.groups); +//! ``` +//! +//! [`Merge`]: trait.Merge.html +//! [`args.rs`]: https://git.sr.ht/~ireas/merge-rs/tree/master/examples/args.rs + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "derive")] +pub use merge_derive::*; + +/// A trait for objects that can be merged. +/// +/// # Deriving +/// +/// `Merge` can be derived for structs if the `derive` feature is enabled. The generated +/// implementation calls the `merge` method for all fields, or the merge strategy function if set. +/// You can use these field attributes to configure the generated implementation: +/// - `skip`: Skip this field in the `merge` method. +/// - `strategy = f`: Call `f(self.field, other.field)` instead of calling the `merge` function for +/// this field. +/// +/// # Examples +/// +/// Using the `Merge` implementation for `Option`: +/// +/// ``` +/// use merge::Merge as _; +/// +/// let mut val = None; +/// val.merge(Some(42)); +/// assert_eq!(Some(42), val); +/// ``` +/// +/// Deriving `Merge` for a struct: +/// +/// ``` +/// use merge::Merge; +/// +/// #[derive(Debug, PartialEq, Merge)] +/// struct S { +/// option: Option, +/// +/// #[merge(skip)] +/// s: String, +/// +/// #[merge(strategy = merge::bool::overwrite_false)] +/// flag: bool, +/// } +/// +/// let mut val = S { +/// option: None, +/// s: "some ignored value".to_owned(), +/// flag: false, +/// }; +/// val.merge(S { +/// option: Some(42), +/// s: "some other ignored value".to_owned(), +/// flag: true, +/// }); +/// assert_eq!(S { +/// option: Some(42), +/// s: "some ignored value".to_owned(), +/// flag: true, +/// }, val); +/// ``` +pub trait Merge { + /// Merge another object into this object. + fn merge(&mut self, other: Self); +} + +impl Merge for Option { + fn merge(&mut self, mut other: Self) { + if !self.is_some() { + *self = other.take(); + } + } +} + +/// Merge strategies for boolean types. +pub mod bool { + /// Overwrite left with right if the value of left is false. + pub fn overwrite_false(left: &mut bool, right: bool) { + if !*left { + *left = right; + } + } + + /// Overwrite left with right if the value of left is true. + pub fn overwrite_true(left: &mut bool, right: bool) { + if *left { + *left = right; + } + } +} + +/// Merge strategies for numeric types. +/// +/// These strategies are only available if the `num` feature is enabled. +#[cfg(feature = "num")] +pub mod num { + /// Set left to the saturated some of left and right. + pub fn saturating_add(left: &mut T, right: T) { + *left = left.saturating_add(&right); + } + + /// Overwrite left with right if the value of left is zero. + pub fn overwrite_zero(left: &mut T, right: T) { + if left.is_zero() { + *left = right; + } + } +} + +/// Merge strategies for types that form a total order. +pub mod ord { + use core::cmp; + + /// Set left to the maximum of left and right. + pub fn max(left: &mut T, right: T) { + if cmp::Ord::cmp(left, &right) == cmp::Ordering::Less { + *left = right; + } + } + + /// Set left to the minimum of left and right. + pub fn min(left: &mut T, right: T) { + if cmp::Ord::cmp(left, &right) == cmp::Ordering::Greater { + *left = right; + } + } +} + +/// Merge strategies for vectors. +/// +/// These strategies are only available if the `std` feature is enabled. +#[cfg(feature = "std")] +pub mod vec { + /// Overwrite left with right if left is empty. + pub fn overwrite_empty(left: &mut Vec, mut right: Vec) { + if left.is_empty() { + left.append(&mut right); + } + } + + /// Append the contents of right to left. + pub fn append(left: &mut Vec, mut right: Vec) { + left.append(&mut right); + } + + /// Prepend the contents of right to left. + pub fn prepend(left: &mut Vec, mut right: Vec) { + right.append(left); + *left = right; + } +} diff --git a/vendor/merge/tests/compile.rs b/vendor/merge/tests/compile.rs new file mode 100644 index 0000000000..aa1bda72c7 --- /dev/null +++ b/vendor/merge/tests/compile.rs @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +#[test] +#[ignore] +fn test_compile_fail() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/compile/*.rs"); +} diff --git a/vendor/merge/tests/compile/derive-enum.rs b/vendor/merge/tests/compile/derive-enum.rs new file mode 100644 index 0000000000..6c4f9b2538 --- /dev/null +++ b/vendor/merge/tests/compile/derive-enum.rs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +enum E { + V1, + V2, + V3, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-enum.stderr b/vendor/merge/tests/compile/derive-enum.stderr new file mode 100644 index 0000000000..47835492ab --- /dev/null +++ b/vendor/merge/tests/compile/derive-enum.stderr @@ -0,0 +1,7 @@ +error: merge::Merge can only be derived for structs + --> $DIR/derive-enum.rs:6:10 + | +6 | #[derive(Merge)] + | ^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/merge/tests/compile/derive-invalid-attribute.rs b/vendor/merge/tests/compile/derive-invalid-attribute.rs new file mode 100644 index 0000000000..cbc3e542c7 --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-attribute.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(ignore)] + field1: Option, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-invalid-attribute.stderr b/vendor/merge/tests/compile/derive-invalid-attribute.stderr new file mode 100644 index 0000000000..ee1b2c669e --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-attribute.stderr @@ -0,0 +1,5 @@ +error: Unexpected attribute: ignore + --> $DIR/derive-invalid-attribute.rs:8:13 + | +8 | #[merge(ignore)] + | ^^^^^^ diff --git a/vendor/merge/tests/compile/derive-invalid-skip.rs b/vendor/merge/tests/compile/derive-invalid-skip.rs new file mode 100644 index 0000000000..78ed93ca32 --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-skip.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(skip = true)] + field1: u8, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-invalid-skip.stderr b/vendor/merge/tests/compile/derive-invalid-skip.stderr new file mode 100644 index 0000000000..65679f9595 --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-skip.stderr @@ -0,0 +1,5 @@ +error: expected `,` + --> $DIR/derive-invalid-skip.rs:8:18 + | +8 | #[merge(skip = true)] + | ^ diff --git a/vendor/merge/tests/compile/derive-invalid-strategy.rs b/vendor/merge/tests/compile/derive-invalid-strategy.rs new file mode 100644 index 0000000000..46dc2594dd --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-strategy.rs @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(strategy = my_custom_merge_strategy)] + field1: u8, +} + +fn my_custom_merge_strategy(left: u8, right: u8) -> u8 { + left + right +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-invalid-strategy.stderr b/vendor/merge/tests/compile/derive-invalid-strategy.stderr new file mode 100644 index 0000000000..ecdd08504e --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-strategy.stderr @@ -0,0 +1,13 @@ +error[E0308]: mismatched types + --> $DIR/derive-invalid-strategy.rs:8:24 + | +8 | #[merge(strategy = my_custom_merge_strategy)] + | ________________________^ +9 | | field1: u8, + | |__________^ expected `u8`, found `&mut u8` + | +help: consider removing the borrow + | +8 | #[merge(strategy = my_custom_merge_strategy)] +9 | field1: u8, + | diff --git a/vendor/merge/tests/compile/derive-missing-strategy.rs b/vendor/merge/tests/compile/derive-missing-strategy.rs new file mode 100644 index 0000000000..c9c107328e --- /dev/null +++ b/vendor/merge/tests/compile/derive-missing-strategy.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(strategy = my_custom_merge_strategy)] + field1: u8, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-missing-strategy.stderr b/vendor/merge/tests/compile/derive-missing-strategy.stderr new file mode 100644 index 0000000000..9fb1a03681 --- /dev/null +++ b/vendor/merge/tests/compile/derive-missing-strategy.stderr @@ -0,0 +1,5 @@ +error[E0425]: cannot find function `my_custom_merge_strategy` in this scope + --> $DIR/derive-missing-strategy.rs:8:24 + | +8 | #[merge(strategy = my_custom_merge_strategy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope diff --git a/vendor/merge/tests/compile/derive-no-strategy.rs b/vendor/merge/tests/compile/derive-no-strategy.rs new file mode 100644 index 0000000000..10b95fa8a4 --- /dev/null +++ b/vendor/merge/tests/compile/derive-no-strategy.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(strategy)] + field1: u8, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-no-strategy.stderr b/vendor/merge/tests/compile/derive-no-strategy.stderr new file mode 100644 index 0000000000..9da8914c06 --- /dev/null +++ b/vendor/merge/tests/compile/derive-no-strategy.stderr @@ -0,0 +1,5 @@ +error: expected `=` + --> $DIR/derive-no-strategy.rs:8:12 + | +8 | #[merge(strategy)] + | ^^^^^^^^^^ diff --git a/vendor/merge/tests/compile/derive-u8.rs b/vendor/merge/tests/compile/derive-u8.rs new file mode 100644 index 0000000000..25bfd9b553 --- /dev/null +++ b/vendor/merge/tests/compile/derive-u8.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + field1: Option, + field2: u8, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-u8.stderr b/vendor/merge/tests/compile/derive-u8.stderr new file mode 100644 index 0000000000..de3b5c224e --- /dev/null +++ b/vendor/merge/tests/compile/derive-u8.stderr @@ -0,0 +1,7 @@ +error[E0277]: the trait bound `u8: merge::Merge` is not satisfied + --> $DIR/derive-u8.rs:9:5 + | +9 | field2: u8, + | ^^^^^^ the trait `merge::Merge` is not implemented for `u8` + | + = note: required by `merge::Merge::merge` diff --git a/vendor/merge/tests/derive.rs b/vendor/merge/tests/derive.rs new file mode 100644 index 0000000000..0ac41638e7 --- /dev/null +++ b/vendor/merge/tests/derive.rs @@ -0,0 +1,540 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +#![cfg(feature = "derive")] + +use merge::Merge; + +fn test(expected: T, mut left: T, right: T) { + left.merge(right); + assert_eq!(expected, left); +} + +#[test] +fn test_one_option_field() { + #[derive(Debug, Merge, PartialEq)] + struct S { + field1: Option, + } + + impl S { + pub fn new(field1: Option) -> S { + S { field1 } + } + } + + test(S::new(Some(1)), S::new(Some(1)), S::new(Some(2))); + test(S::new(Some(1)), S::new(Some(1)), S::new(None)); + test(S::new(Some(2)), S::new(None), S::new(Some(2))); + test(S::new(None), S::new(None), S::new(None)); +} + +#[test] +fn test_two_option_fields() { + #[derive(Debug, Merge, PartialEq)] + struct S { + field1: Option, + field2: Option, + } + + impl S { + pub fn new(field1: Option, field2: Option) -> S { + S { field1, field2 } + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(1), Some(2)), + S::new(Some(1), None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), None), + ); + + // left.field1 == Some(1) + // right.field1 == None + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, None), + ); + test( + S::new(Some(1), Some(2)), + S::new(Some(1), None), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, None), + ); + + // left.field1 == None + // right.field1 == Some(2) + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(2), Some(2)), + S::new(None, None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), None), + ); + + // left.field1 == None + // right.field1 == None + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, None), + ); + test( + S::new(None, Some(2)), + S::new(None, None), + S::new(None, Some(2)), + ); + test(S::new(None, None), S::new(None, None), S::new(None, None)); +} + +#[test] +fn test_skip_valid() { + #[derive(Debug, Merge, PartialEq)] + struct S { + field1: Option, + #[merge(skip)] + field2: Option, + } + + impl S { + pub fn new(field1: Option, field2: Option) -> S { + S { field1, field2 } + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), None), + ); + + // left.field1 == Some(1) + // right.field1 == None + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, None), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, None), + ); + + // left.field1 == None + // right.field1 == Some(2) + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), None), + ); + + // left.field1 == None + // right.field1 == None + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, None), + ); + test( + S::new(None, None), + S::new(None, None), + S::new(None, Some(2)), + ); + test(S::new(None, None), S::new(None, None), S::new(None, None)); +} + +#[test] +fn test_skip_invalid() { + #[derive(Debug, Merge, PartialEq)] + struct S { + field1: Option, + #[merge(skip)] + field2: usize, + } + + impl S { + pub fn new(field1: Option, field2: usize) -> S { + S { field1, field2 } + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(Some(2), 2)); + test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(Some(2), 0)); + test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(Some(2), 2)); + test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(Some(2), 0)); + + // left.field1 == Some(1) + // right.field1 == None + test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(None, 2)); + test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(None, 0)); + test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(None, 2)); + test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(None, 0)); + + // left.field1 == None + // right.field1 == Some(2) + test(S::new(Some(2), 1), S::new(None, 1), S::new(Some(2), 2)); + test(S::new(Some(2), 1), S::new(None, 1), S::new(Some(2), 0)); + test(S::new(Some(2), 0), S::new(None, 0), S::new(Some(2), 2)); + test(S::new(Some(2), 0), S::new(None, 0), S::new(Some(2), 0)); + + // left.field1 == None + // right.field1 == None + test(S::new(None, 1), S::new(None, 1), S::new(None, 2)); + test(S::new(None, 1), S::new(None, 1), S::new(None, 0)); + test(S::new(None, 0), S::new(None, 0), S::new(None, 2)); + test(S::new(None, 0), S::new(None, 0), S::new(None, 0)); +} + +#[test] +fn test_strategy_usize_add() { + #[derive(Debug, Merge, PartialEq)] + struct S { + #[merge(strategy = add)] + field1: usize, + } + + impl S { + pub fn new(field1: usize) -> S { + S { field1 } + } + } + + fn add(left: &mut usize, right: usize) { + *left = *left + right; + } + + test(S::new(0), S::new(0), S::new(0)); + test(S::new(1), S::new(1), S::new(0)); + test(S::new(1), S::new(0), S::new(1)); + test(S::new(2), S::new(1), S::new(1)); +} + +#[test] +fn test_strategy_vec_append() { + #[derive(Debug, Merge, PartialEq)] + struct S { + #[merge(strategy = append)] + field1: Vec, + } + + impl S { + pub fn new(field1: Vec) -> S { + S { field1 } + } + } + + fn append(left: &mut Vec, mut right: Vec) { + left.append(&mut right); + } + + test( + S::new(vec![0, 1, 2, 3]), + S::new(vec![0, 1]), + S::new(vec![2, 3]), + ); + test( + S::new(vec![0, 1, 2, 3]), + S::new(vec![0, 1, 2, 3]), + S::new(vec![]), + ); + test( + S::new(vec![0, 1, 2, 3]), + S::new(vec![]), + S::new(vec![0, 1, 2, 3]), + ); +} + +#[test] +fn test_unnamed_fields() { + #[derive(Debug, Merge, PartialEq)] + struct S(Option, Option); + + impl S { + pub fn new(field1: Option, field2: Option) -> S { + S(field1, field2) + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(1), Some(2)), + S::new(Some(1), None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), None), + ); + + // left.field1 == Some(1) + // right.field1 == None + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, None), + ); + test( + S::new(Some(1), Some(2)), + S::new(Some(1), None), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, None), + ); + + // left.field1 == None + // right.field1 == Some(2) + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(2), Some(2)), + S::new(None, None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), None), + ); + + // left.field1 == None + // right.field1 == None + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, None), + ); + test( + S::new(None, Some(2)), + S::new(None, None), + S::new(None, Some(2)), + ); + test(S::new(None, None), S::new(None, None), S::new(None, None)); +} + +#[test] +fn test_unnamed_fields_skip() { + #[derive(Debug, Merge, PartialEq)] + struct S(Option, #[merge(skip)] Option); + + impl S { + pub fn new(field1: Option, field2: Option) -> S { + S(field1, field2) + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), None), + ); + + // left.field1 == Some(1) + // right.field1 == None + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, None), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, None), + ); + + // left.field1 == None + // right.field1 == Some(2) + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), None), + ); + + // left.field1 == None + // right.field1 == None + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, None), + ); + test( + S::new(None, None), + S::new(None, None), + S::new(None, Some(2)), + ); + test(S::new(None, None), S::new(None, None), S::new(None, None)); +} diff --git a/vendor/merge/tests/impls.rs b/vendor/merge/tests/impls.rs new file mode 100644 index 0000000000..d8378e538f --- /dev/null +++ b/vendor/merge/tests/impls.rs @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +fn test(expected: T, mut left: T, right: T) { + left.merge(right); + assert_eq!(expected, left); +} + +#[test] +fn test_option() { + test(Some(1), Some(1), Some(2)); + test(Some(2), None, Some(2)); + test(None::, None, None); +} diff --git a/vendor/merge/tests/strategies.rs b/vendor/merge/tests/strategies.rs new file mode 100644 index 0000000000..3a35ea2a65 --- /dev/null +++ b/vendor/merge/tests/strategies.rs @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +#![cfg(feature = "derive")] + +use merge::Merge; + +fn test(expected: T, mut left: T, right: T) { + left.merge(right); + assert_eq!(expected, left); +} + +#[test] +fn test_bool_overwrite_false() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::bool::overwrite_false)] bool); + + test(S(false), S(false), S(false)); + test(S(true), S(false), S(true)); + test(S(true), S(true), S(false)); + test(S(true), S(true), S(true)); +} + +#[test] +fn test_bool_overwrite_true() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::bool::overwrite_true)] bool); + + test(S(false), S(false), S(false)); + test(S(false), S(false), S(true)); + test(S(false), S(true), S(false)); + test(S(true), S(true), S(true)); +} + +#[cfg(feature = "num")] +#[test] +fn test_num_saturating_add() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::num::saturating_add)] u8); + + test(S(0), S(0), S(0)); + test(S(1), S(0), S(1)); + test(S(255), S(255), S(10)); + test(S(40), S(30), S(10)); +} + +#[cfg(feature = "num")] +#[test] +fn test_num_overwrite_zero() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::num::overwrite_zero)] u8); + + test(S(0), S(0), S(0)); + test(S(1), S(0), S(1)); + test(S(255), S(255), S(10)); +} + +#[test] +fn test_ord_max() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::ord::max)] u8); + + test(S(2), S(1), S(2)); + test(S(2), S(2), S(1)); + test(S(2), S(2), S(2)); + test(S(2), S(2), S(0)); + test(S(2), S(0), S(2)); + test(S(33), S(33), S(11)); +} + +#[test] +fn test_ord_min() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::ord::min)] u8); + + test(S(1), S(1), S(2)); + test(S(1), S(2), S(1)); + test(S(2), S(2), S(2)); + test(S(0), S(2), S(0)); + test(S(0), S(0), S(2)); + test(S(11), S(33), S(11)); +} + +#[cfg(feature = "std")] +#[test] +fn test_vec_overwrite_empty() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::vec::overwrite_empty)] Vec); + + test(S(vec![]), S(vec![]), S(vec![])); + test(S(vec![1]), S(vec![]), S(vec![1])); + test(S(vec![0]), S(vec![0]), S(vec![1])); + test(S(vec![255]), S(vec![255]), S(vec![10])); +} + +#[cfg(feature = "std")] +#[test] +fn test_vec_append() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::vec::append)] Vec); + + test(S(vec![]), S(vec![]), S(vec![])); + test(S(vec![1]), S(vec![]), S(vec![1])); + test(S(vec![0, 1]), S(vec![0]), S(vec![1])); + test(S(vec![255, 10]), S(vec![255]), S(vec![10])); + test(S(vec![0, 1, 2, 3, 4]), S(vec![0, 1, 2]), S(vec![3, 4])); + test(S(vec![3, 4, 0, 1, 2]), S(vec![3, 4]), S(vec![0, 1, 2])); +} + +#[cfg(feature = "std")] +#[test] +fn test_vec_prepend() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::vec::prepend)] Vec); + + test(S(vec![]), S(vec![]), S(vec![])); + test(S(vec![1]), S(vec![]), S(vec![1])); + test(S(vec![1, 0]), S(vec![0]), S(vec![1])); + test(S(vec![10, 255]), S(vec![255]), S(vec![10])); + test(S(vec![3, 4, 0, 1, 2]), S(vec![0, 1, 2]), S(vec![3, 4])); + test(S(vec![0, 1, 2, 3, 4]), S(vec![3, 4]), S(vec![0, 1, 2])); +} diff --git a/vendor/merge_derive/.cargo-checksum.json b/vendor/merge_derive/.cargo-checksum.json new file mode 100644 index 0000000000..745acccf38 --- /dev/null +++ b/vendor/merge_derive/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"b02f58391ecb6521ed3f453f28ff0ed1e6c7935b51e4f1c4b346039725aeffd1","Cargo.toml":"3dec793dd43afad71233015d71f53422b106fe24969cc44c4421315693b514c3","README.md":"9e7e5b4de658b75295d7e0179a4828d3699d995fa766626c253c7df09f8bff5b","src/lib.rs":"22bd90be174c7228dab8d47809f7bc9a7fb28ba2091f78959c240f0a558cc3d6"},"package":"209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07"} \ No newline at end of file diff --git a/vendor/merge_derive/CHANGELOG.md b/vendor/merge_derive/CHANGELOG.md new file mode 100644 index 0000000000..954a87357a --- /dev/null +++ b/vendor/merge_derive/CHANGELOG.md @@ -0,0 +1,8 @@ + + +# v0.1.0 (2020-09-01) + +Initial release providing a derive macro for the `Merge` trait. diff --git a/vendor/merge_derive/Cargo.toml b/vendor/merge_derive/Cargo.toml new file mode 100644 index 0000000000..2e338716ca --- /dev/null +++ b/vendor/merge_derive/Cargo.toml @@ -0,0 +1,37 @@ +# 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 = "merge_derive" +version = "0.1.0" +authors = ["Robin Krahl "] +description = "Derive macro for the merge::Merge trait" +readme = "README.md" +keywords = ["merge", "macros", "derive"] +categories = ["rust-patterns"] +license = "Apache-2.0 OR MIT" +repository = "https://git.sr.ht/~ireas/merge-rs/tree/master/merge_derive" + +[lib] +proc-macro = true +[dependencies.proc-macro-error] +version = "1.0" + +[dependencies.proc-macro2] +version = "1.0" + +[dependencies.quote] +version = "1.0" + +[dependencies.syn] +version = "1.0" diff --git a/vendor/merge_derive/README.md b/vendor/merge_derive/README.md new file mode 100644 index 0000000000..7913ba4e06 --- /dev/null +++ b/vendor/merge_derive/README.md @@ -0,0 +1,11 @@ + + +# merge-derive-rs + +This crate provides a derive macro for the `merge::Merge` crate. See the +[`merge`][] crate for more information. + +[`merge`]: https://lib.rs/crates/merge diff --git a/vendor/merge_derive/src/lib.rs b/vendor/merge_derive/src/lib.rs new file mode 100644 index 0000000000..75732f9b6f --- /dev/null +++ b/vendor/merge_derive/src/lib.rs @@ -0,0 +1,150 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +//! A derive macro for the [`merge::Merge`][] trait. +//! +//! See the documentation for the [`merge`][] crate for more information. +//! +//! [`merge`]: https://lib.rs/crates/merge +//! [`merge::Merge`]: https://docs.rs/merge/latest/merge/trait.Merge.html + +extern crate proc_macro; + +use proc_macro2::TokenStream; +use proc_macro_error::{abort, abort_call_site, dummy::set_dummy, proc_macro_error, ResultExt}; +use quote::{quote, quote_spanned}; +use syn::Token; + +struct Field { + name: syn::Member, + span: proc_macro2::Span, + attrs: FieldAttrs, +} + +#[derive(Default)] +struct FieldAttrs { + skip: bool, + strategy: Option, +} + +enum FieldAttr { + Skip, + Strategy(syn::Path), +} + +#[proc_macro_derive(Merge, attributes(merge))] +#[proc_macro_error] +pub fn merge_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse(input).unwrap(); + impl_merge(&ast).into() +} + +fn impl_merge(ast: &syn::DeriveInput) -> TokenStream { + let name = &ast.ident; + + set_dummy(quote! { + impl ::merge::Merge for #name { + fn merge(&mut self, other: Self) { + unimplemented!() + } + } + }); + + if let syn::Data::Struct(syn::DataStruct { ref fields, .. }) = ast.data { + impl_merge_for_struct(name, fields) + } else { + abort_call_site!("merge::Merge can only be derived for structs") + } +} + +fn impl_merge_for_struct(name: &syn::Ident, fields: &syn::Fields) -> TokenStream { + let assignments = gen_assignments(fields); + + quote! { + impl ::merge::Merge for #name { + fn merge(&mut self, other: Self) { + #assignments + } + } + } +} + +fn gen_assignments(fields: &syn::Fields) -> TokenStream { + let fields = fields.iter().enumerate().map(Field::from); + let assignments = fields.filter(|f| !f.attrs.skip).map(|f| gen_assignment(&f)); + quote! { + #( #assignments )* + } +} + +fn gen_assignment(field: &Field) -> TokenStream { + use syn::spanned::Spanned; + + let name = &field.name; + if let Some(strategy) = &field.attrs.strategy { + quote_spanned!(strategy.span()=> #strategy(&mut self.#name, other.#name);) + } else { + quote_spanned!(field.span=> ::merge::Merge::merge(&mut self.#name, other.#name);) + } +} + +impl From<(usize, &syn::Field)> for Field { + fn from(data: (usize, &syn::Field)) -> Self { + use syn::spanned::Spanned; + + let (index, field) = data; + Field { + name: if let Some(ident) = &field.ident { + syn::Member::Named(ident.clone()) + } else { + syn::Member::Unnamed(index.into()) + }, + span: field.span(), + attrs: field.attrs.iter().into(), + } + } +} + +impl FieldAttrs { + fn apply(&mut self, attr: FieldAttr) { + match attr { + FieldAttr::Skip => self.skip = true, + FieldAttr::Strategy(path) => self.strategy = Some(path), + } + } +} + +impl<'a, I: Iterator> From for FieldAttrs { + fn from(iter: I) -> Self { + let mut field_attrs = Self::default(); + + for attr in iter { + if !attr.path.is_ident("merge") { + continue; + } + + let parser = syn::punctuated::Punctuated::::parse_terminated; + for attr in attr.parse_args_with(parser).unwrap_or_abort() { + field_attrs.apply(attr); + } + } + + field_attrs + } +} + +impl syn::parse::Parse for FieldAttr { + fn parse(input: syn::parse::ParseStream) -> syn::parse::Result { + let name: syn::Ident = input.parse()?; + if name == "skip" { + // TODO check remaining stream + Ok(FieldAttr::Skip) + } else if name == "strategy" { + let _: Token![=] = input.parse()?; + let path: syn::Path = input.parse()?; + Ok(FieldAttr::Strategy(path)) + } else { + abort!(name, "Unexpected attribute: {}", name) + } + } +} diff --git a/vendor/miniz_oxide/.cargo-checksum.json b/vendor/miniz_oxide/.cargo-checksum.json index aeba06ecfb..fde8420c94 100644 --- a/vendor/miniz_oxide/.cargo-checksum.json +++ b/vendor/miniz_oxide/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"d302f27e8737cdcfe95db7dceb5672aa8380ed36459979c950b4735d284f667c","LICENSE":"e190940e8ad3cdd4fca962a6508ed6865d589d314b1cb055f86000e124b88d8d","Readme.md":"fca5f9500a8caf5a334dc53925fa3dda063a8a4de88fe107251998300b432c0d","src/deflate/buffer.rs":"2953214307677f33f901f8e52256b6e7a296f4234238179613168ddad106645c","src/deflate/core.rs":"db40c9a95f5a9ad72c17eef934e163d90768b2a0f8fa53cf37d71e550cdf84f9","src/deflate/mod.rs":"e6b6b114329c555bd8fc769d4e955b3a34663206b283092f13d0bc85424b56d4","src/deflate/stream.rs":"49120444fb12b58191c2bb0dda598cd3614cbc329eb3720a50ce8f5017c04838","src/inflate/core.rs":"a4d8c3cf20ec3b89b12f7ac1df37b521d29e910f854cb1ccb2b8c7bb23244b25","src/inflate/mod.rs":"c63e855ba72c44aa5df6ab199360d5cce20ec01caf5539d38c76295e076f39be","src/inflate/output_buffer.rs":"3948c26897a8d30a356fc8e9ce1df7513c21d186838220ad63a69b6b1d985eab","src/inflate/stream.rs":"b3108fb0c6ae935a27c56ac258abf6a2e47c69c6ba0d205afaa742f3b5010572","src/lib.rs":"9322a5e0d5af90c017d9ae44a502045fecfdc134bcbe946e72609835644e9b7d","src/shared.rs":"889b9d9d3b4bc0693f94c850806e9cf68ed9079e0ada2b2f51bfffe388e02c6a"},"package":"be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"} \ No newline at end of file +{"files":{"Cargo.toml":"3b97eb92a60ed95a9db4a12ddc97093efc60666077c729363c902f7d37a9c2bd","LICENSE":"e190940e8ad3cdd4fca962a6508ed6865d589d314b1cb055f86000e124b88d8d","Readme.md":"fca5f9500a8caf5a334dc53925fa3dda063a8a4de88fe107251998300b432c0d","src/deflate/buffer.rs":"2953214307677f33f901f8e52256b6e7a296f4234238179613168ddad106645c","src/deflate/core.rs":"db40c9a95f5a9ad72c17eef934e163d90768b2a0f8fa53cf37d71e550cdf84f9","src/deflate/mod.rs":"d17cd7a576be570cf948d2fbf0ce535be35cc4ef94cbfbfaefc17c6641bd412a","src/deflate/stream.rs":"49120444fb12b58191c2bb0dda598cd3614cbc329eb3720a50ce8f5017c04838","src/inflate/core.rs":"a4d8c3cf20ec3b89b12f7ac1df37b521d29e910f854cb1ccb2b8c7bb23244b25","src/inflate/mod.rs":"f9c4626e2223b12352135c4359a9f4522fce625a45adff12991bd465509f4f46","src/inflate/output_buffer.rs":"3948c26897a8d30a356fc8e9ce1df7513c21d186838220ad63a69b6b1d985eab","src/inflate/stream.rs":"799424e68bbb11e99038c4f70f67d6298b738b443652be474018844bcd4e6996","src/lib.rs":"39feb2ac3d9d8000c387865fd8de60bdd6c91d7ad8ec040b35507d917bec9b94","src/shared.rs":"889b9d9d3b4bc0693f94c850806e9cf68ed9079e0ada2b2f51bfffe388e02c6a"},"package":"4d7559a8a40d0f97e1edea3220f698f78b1c5ab67532e49f68fde3910323b722"} \ No newline at end of file diff --git a/vendor/miniz_oxide/Cargo.toml b/vendor/miniz_oxide/Cargo.toml index 477df48342..712f7bc822 100644 --- a/vendor/miniz_oxide/Cargo.toml +++ b/vendor/miniz_oxide/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "miniz_oxide" -version = "0.4.0" +version = "0.4.1" authors = ["Frommi ", "oyvindln "] exclude = ["benches/*", "tests/*"] description = "DEFLATE compression and decompression library rewritten in Rust based on miniz" @@ -46,4 +46,5 @@ optional = true package = "rustc-std-workspace-core" [features] +no_extern_crate_alloc = [] rustc-dep-of-std = ["core", "alloc", "compiler_builtins", "adler/rustc-dep-of-std"] diff --git a/vendor/miniz_oxide/src/deflate/mod.rs b/vendor/miniz_oxide/src/deflate/mod.rs index ac8b5e5677..cc90ca6749 100644 --- a/vendor/miniz_oxide/src/deflate/mod.rs +++ b/vendor/miniz_oxide/src/deflate/mod.rs @@ -1,7 +1,7 @@ //! This module contains functionality for compression. -use alloc::vec; -use alloc::vec::Vec; +use crate::alloc::vec; +use crate::alloc::vec::Vec; mod buffer; pub mod core; diff --git a/vendor/miniz_oxide/src/inflate/mod.rs b/vendor/miniz_oxide/src/inflate/mod.rs index 5757016699..8edcbbe370 100644 --- a/vendor/miniz_oxide/src/inflate/mod.rs +++ b/vendor/miniz_oxide/src/inflate/mod.rs @@ -1,9 +1,10 @@ //! This module contains functionality for decompression. +use ::core::cmp::min; use ::core::usize; -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; +use crate::alloc::boxed::Box; +use crate::alloc::vec; +use crate::alloc::vec::Vec; pub mod core; mod output_buffer; @@ -61,7 +62,7 @@ impl TINFLStatus { /// Returns a status and an integer representing where the decompressor failed on failure. #[inline] pub fn decompress_to_vec(input: &[u8]) -> Result, TINFLStatus> { - decompress_to_vec_inner(input, 0) + decompress_to_vec_inner(input, 0, usize::max_value()) } /// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector. @@ -69,12 +70,43 @@ pub fn decompress_to_vec(input: &[u8]) -> Result, TINFLStatus> { /// Returns a status and an integer representing where the decompressor failed on failure. #[inline] pub fn decompress_to_vec_zlib(input: &[u8]) -> Result, TINFLStatus> { - decompress_to_vec_inner(input, inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER) + decompress_to_vec_inner( + input, + inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER, + usize::max_value(), + ) } -fn decompress_to_vec_inner(input: &[u8], flags: u32) -> Result, TINFLStatus> { +/// Decompress the deflate-encoded data in `input` to a vector. +/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size, +/// `TINFLStatus::HasMoreOutput` error is returned. +/// +/// Returns a status and an integer representing where the decompressor failed on failure. +#[inline] +pub fn decompress_to_vec_with_limit(input: &[u8], max_size: usize) -> Result, TINFLStatus> { + decompress_to_vec_inner(input, 0, max_size) +} + +/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector. +/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size, +/// `TINFLStatus::HasMoreOutput` error is returned. +/// +/// Returns a status and an integer representing where the decompressor failed on failure. +#[inline] +pub fn decompress_to_vec_zlib_with_limit( + input: &[u8], + max_size: usize, +) -> Result, TINFLStatus> { + decompress_to_vec_inner(input, inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER, max_size) +} + +fn decompress_to_vec_inner( + input: &[u8], + flags: u32, + max_output_size: usize, +) -> Result, TINFLStatus> { let flags = flags | inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - let mut ret: Vec = vec![0; input.len() * 2]; + let mut ret: Vec = vec![0; min(input.len().saturating_mul(2), max_output_size)]; let mut decomp = Box::::default(); @@ -95,8 +127,15 @@ fn decompress_to_vec_inner(input: &[u8], flags: u32) -> Result, TINFLSta } TINFLStatus::HasMoreOutput => { - // We need more space so resize the buffer. - ret.resize(ret.len() + out_pos, 0); + // We need more space, so check if we can resize the buffer and do it. + let new_len = ret + .len() + .checked_add(out_pos) + .ok_or(TINFLStatus::HasMoreOutput)?; + if new_len > max_output_size { + return Err(TINFLStatus::HasMoreOutput); + }; + ret.resize(new_len, 0); } _ => return Err(status), @@ -106,14 +145,30 @@ fn decompress_to_vec_inner(input: &[u8], flags: u32) -> Result, TINFLSta #[cfg(test)] mod test { - use super::decompress_to_vec_zlib; + use super::TINFLStatus; + use super::{decompress_to_vec_zlib, decompress_to_vec_zlib_with_limit}; + const encoded: [u8; 20] = [ + 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19, + ]; #[test] fn decompress_vec() { - let encoded = [ - 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19, - ]; let res = decompress_to_vec_zlib(&encoded[..]).unwrap(); assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]); } + + #[test] + fn decompress_vec_with_high_limit() { + let res = decompress_to_vec_zlib_with_limit(&encoded[..], 100_000).unwrap(); + assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]); + } + + #[test] + fn fail_to_decompress_with_limit() { + let res = decompress_to_vec_zlib_with_limit(&encoded[..], 8); + match res { + Err(TINFLStatus::HasMoreOutput) => (), // expected result + _ => panic!("Decompression output size limit was not enforced"), + } + } } diff --git a/vendor/miniz_oxide/src/inflate/stream.rs b/vendor/miniz_oxide/src/inflate/stream.rs index 39c602f331..8823218387 100644 --- a/vendor/miniz_oxide/src/inflate/stream.rs +++ b/vendor/miniz_oxide/src/inflate/stream.rs @@ -1,13 +1,59 @@ //! Extra streaming decompression functionality. //! //! As of now this is mainly inteded for use to build a higher-level wrapper. -use alloc::boxed::Box; +use crate::alloc::boxed::Box; use core::{cmp, mem}; use crate::inflate::core::{decompress, inflate_flags, DecompressorOxide, TINFL_LZ_DICT_SIZE}; use crate::inflate::TINFLStatus; use crate::{DataFormat, MZError, MZFlush, MZResult, MZStatus, StreamResult}; +/// Tag that determines reset policy of [InflateState](struct.InflateState.html) +pub trait ResetPolicy { + /// Performs reset + fn reset(&self, state: &mut InflateState); +} + +/// Resets state, without performing expensive ops (e.g. zeroing buffer) +/// +/// Note that not zeroing buffer can lead to security issues when dealing with untrusted input. +pub struct MinReset; + +impl ResetPolicy for MinReset { + fn reset(&self, state: &mut InflateState) { + state.decompressor().init(); + state.dict_ofs = 0; + state.dict_avail = 0; + state.first_call = true; + state.has_flushed = false; + state.last_status = TINFLStatus::NeedsMoreInput; + } +} + +/// Resets state and zero memory, continuing to use the same data format. +pub struct ZeroReset; + +impl ResetPolicy for ZeroReset { + #[inline] + fn reset(&self, state: &mut InflateState) { + MinReset.reset(state); + state.dict = [0; TINFL_LZ_DICT_SIZE]; + } +} + +/// Full reset of the state, including zeroing memory. +/// +/// Requires to provide new data format. +pub struct FullReset(DataFormat); + +impl ResetPolicy for FullReset { + #[inline] + fn reset(&self, state: &mut InflateState) { + ZeroReset.reset(state); + state.data_format = self.0; + } +} + /// A struct that compbines a decompressor with extra data for streaming decompression. /// pub struct InflateState { @@ -95,17 +141,17 @@ impl InflateState { b } + #[inline] /// Reset the decompressor without re-allocating memory, using the given /// data format. pub fn reset(&mut self, data_format: DataFormat) { - self.decompressor().init(); - self.dict = [0; TINFL_LZ_DICT_SIZE]; - self.dict_ofs = 0; - self.dict_avail = 0; - self.first_call = true; - self.has_flushed = false; - self.data_format = data_format; - self.last_status = TINFLStatus::NeedsMoreInput; + self.reset_as(FullReset(data_format)); + } + + #[inline] + /// Resets the state according to specified policy. + pub fn reset_as(&mut self, policy: T) { + policy.reset(self) } } @@ -314,7 +360,17 @@ mod test { assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); assert_eq!(res.bytes_consumed, encoded.len()); - state.reset(DataFormat::Zlib); + state.reset_as(super::ZeroReset); + out.iter_mut().map(|x| *x = 0).count(); + let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish); + let status = res.status.expect("Failed to decompress!"); + assert_eq!(status, MZStatus::StreamEnd); + assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); + assert_eq!(res.bytes_consumed, encoded.len()); + + state.reset_as(super::MinReset); + out.iter_mut().map(|x| *x = 0).count(); + let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish); let status = res.status.expect("Failed to decompress!"); assert_eq!(status, MZStatus::StreamEnd); assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); diff --git a/vendor/miniz_oxide/src/lib.rs b/vendor/miniz_oxide/src/lib.rs index 4ae3d76c72..0b4c60787d 100644 --- a/vendor/miniz_oxide/src/lib.rs +++ b/vendor/miniz_oxide/src/lib.rs @@ -23,9 +23,12 @@ #![allow(warnings)] #![forbid(unsafe_code)] -#![no_std] +#![cfg_attr(not(feature = "no_extern_crate_alloc"), no_std)] +#[cfg(not(feature = "no_extern_crate_alloc"))] extern crate alloc; +#[cfg(feature = "no_extern_crate_alloc")] +use std as alloc; #[cfg(test)] extern crate std; diff --git a/vendor/net2/.cargo-checksum.json b/vendor/net2/.cargo-checksum.json new file mode 100644 index 0000000000..47e9b93c1d --- /dev/null +++ b/vendor/net2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"6b8d2fe4e5dd3065446c4df3d226b6582ec8c9d6349d1c07a0446638c11f1d3b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"a99cb0401bd49e68c945f6a249175dd5c4a5117b2c8cc5d5fb7dea369002574e","src/ext.rs":"fd072307ebbaa01cfe1fd7553d7f42d27093b2bd32dd81d419d2e1c9423495a0","src/lib.rs":"a5e429c904fa13291dee5ed5df6c20adcebbaa56fc0312d475fd2056e9974153","src/socket.rs":"fda3d134345dd9b6178399c9173f42775b7620b9eaa802bf2d56dd9b798c5ca8","src/sys/redox/impls.rs":"90059116f0514bd44dbf282a3e8d7b192c99e1a78a34ebacb00f2d325ca0f8b0","src/sys/redox/mod.rs":"137013d409fd174fed0ceb3eceb2c17d15f34a3af70c7d237c06dd3a144affc1","src/sys/unix/impls.rs":"05f123226e8fe7559317d50864021650b2455d25d01a9aff1c65c01ae26cf4ef","src/sys/unix/mod.rs":"e06b26bad48c815b9a2af4509d1873333e2aad0031980f6d2625f72542698d56","src/sys/wasi/impls.rs":"da4e95a27a765b64fbbebce55b860020ac891456085ed706d5f8f391e0d1cddf","src/sys/wasi/mod.rs":"e88b02f4d5e0ae558f093d49cc0bb1b3cdf86ede625d00ed9231f0ab414e483f","src/sys/windows/impls.rs":"bee70b7cd45055c4eaa1967f7aad7ec46639de458c71ed6f3e97a2f7b2c49281","src/sys/windows/mod.rs":"0706f1587af0f693f75e8597e4196075a3f673c89727dd865447da306974bf35","src/tcp.rs":"0bebf5cca75714151de30c8f2d7697ca519c57da065e93ba81796bce04673f8d","src/udp.rs":"8af5a55a4ae5e4120ffe18dcc4dc24072e18da34bf3591a02b18653e5d3e8ac8","src/unix.rs":"1156707694cb1f002a2eb2144bf205a73412e1661fd196a8a2a7bc8ea5aaad2d","src/utils.rs":"d31de5333a6fa2f5c99b64cc937be596888d9863264632e6bc6b36b30197fa5b"},"package":"3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853"} \ No newline at end of file diff --git a/vendor/net2/Cargo.toml b/vendor/net2/Cargo.toml new file mode 100644 index 0000000000..3ccf701bd2 --- /dev/null +++ b/vendor/net2/Cargo.toml @@ -0,0 +1,35 @@ +# 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 = "net2" +version = "0.2.35" +authors = ["Alex Crichton "] +include = ["Cargo.toml", "LICENSE-APACHE", "LICENSE-MIT", "README.md", "src/**/*.rs"] +description = "Extensions to the standard library's networking types as proposed in RFC 1158.\n" +homepage = "https://github.com/deprecrated/net2-rs" +documentation = "https://docs.rs/net2/~0.2" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/deprecrated/net2-rs" +[dependencies.cfg-if] +version = "0.1" + +[features] +default = ["duration"] +duration = [] +nightly = [] +[target."cfg(any(target_os=\"redox\", unix, target_os=\"wasi\"))".dependencies.libc] +version = "0.2.54" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["handleapi", "winsock2", "ws2def", "ws2ipdef", "ws2tcpip"] diff --git a/vendor/parking_lot-0.10.2/LICENSE-APACHE b/vendor/net2/LICENSE-APACHE similarity index 100% rename from vendor/parking_lot-0.10.2/LICENSE-APACHE rename to vendor/net2/LICENSE-APACHE diff --git a/vendor/net2/LICENSE-MIT b/vendor/net2/LICENSE-MIT new file mode 100644 index 0000000000..39d4bdb5ac --- /dev/null +++ b/vendor/net2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust 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/net2/README.md b/vendor/net2/README.md new file mode 100644 index 0000000000..9818422220 --- /dev/null +++ b/vendor/net2/README.md @@ -0,0 +1,31 @@ +# net2 + +Extensions to the standard library's networking types, proposed in [RFC 1158][rfc]. + +[rfc]: https://github.com/alexcrichton/rfcs/blob/net2.1/text/0000-io-net-2.1.md + +[![Build Status](https://github.com/deprecrated/net2-rs/workflows/CI/badge.svg)](https://github.com/deprecrated/net2-rs/actions?query=workflow%3ACI+branch%3Amaster) +[![Documentation](https://docs.rs/net2/badge.svg?version=0.2)](https://docs.rs/net2/~0.2) + +# net2 is Deprecated + +Prospective and existing consumers are encouraged to consider +[socket2](https://crates.io/crates/socket2) instead. + + +# License + +This project is 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 Serde 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/net2/src/ext.rs b/vendor/net2/src/ext.rs new file mode 100644 index 0000000000..ca64bef3bb --- /dev/null +++ b/vendor/net2/src/ext.rs @@ -0,0 +1,1561 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style, dead_code)] + +use std::io; +use std::mem; +use std::net::{TcpStream, TcpListener, UdpSocket, Ipv4Addr, Ipv6Addr}; +use std::net::ToSocketAddrs; + +use {TcpBuilder, UdpBuilder, FromInner}; +use sys; +use sys::c; +use socket; + +cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "illumos", + target_env = "uclibc"))] { + use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; + use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; + } else { + // ... + } +} + +use std::time::Duration; + +#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] use libc::*; +#[cfg(any(unix, target_os = "redox"))] use std::os::unix::prelude::*; +#[cfg(target_os = "wasi")] use std::os::wasi::prelude::*; +#[cfg(target_os = "redox")] pub type Socket = usize; +#[cfg(unix)] pub type Socket = c_int; +#[cfg(target_os = "wasi")] pub type Socket = std::os::wasi::io::RawFd; +#[cfg(windows)] pub type Socket = SOCKET; +#[cfg(windows)] use std::os::windows::prelude::*; +#[cfg(any(windows, target_os = "wasi"))] use sys::c::*; + +#[cfg(windows)] const SIO_KEEPALIVE_VALS: DWORD = 0x98000004; +#[cfg(windows)] +#[repr(C)] +struct tcp_keepalive { + onoff: c_ulong, + keepalivetime: c_ulong, + keepaliveinterval: c_ulong, +} + +#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] fn v(opt: c_int) -> c_int { opt } +#[cfg(windows)] fn v(opt: IPPROTO) -> c_int { opt as c_int } + +#[cfg(target_os = "wasi")] +pub fn set_opt(_sock: Socket, _opt: c_int, _val: c_int, + _payload: T) -> io::Result<()> { + Ok(()) +} + +#[cfg(not(target_os = "wasi"))] +pub fn set_opt(sock: Socket, opt: c_int, val: c_int, + payload: T) -> io::Result<()> { + unsafe { + let payload = &payload as *const T as *const c_void; + #[cfg(target_os = "redox")] + let sock = sock as c_int; + try!(::cvt(setsockopt(sock, opt, val, payload as *const _, + mem::size_of::() as socklen_t))); + } + Ok(()) +} + +#[cfg(target_os = "wasi")] +pub fn get_opt(_sock: Socket, _opt: c_int, _val: c_int) -> io::Result { + unimplemented!() +} +#[cfg(not(target_os = "wasi"))] +pub fn get_opt(sock: Socket, opt: c_int, val: c_int) -> io::Result { + unsafe { + let mut slot: T = mem::zeroed(); + let mut len = mem::size_of::() as socklen_t; + #[cfg(target_os = "redox")] + let sock = sock as c_int; + try!(::cvt(getsockopt(sock, opt, val, + &mut slot as *mut _ as *mut _, + &mut len))); + assert_eq!(len as usize, mem::size_of::()); + Ok(slot) + } +} + +/// Extension methods for the standard [`TcpStream` type][link] in `std::net`. +/// +/// [link]: https://doc.rust-lang.org/std/net/struct.TcpStream.html +pub trait TcpStreamExt { + /// Sets the value of the `TCP_NODELAY` option on this socket. + /// + /// If set, this option disables the Nagle algorithm. This means that + /// segments are always sent as soon as possible, even if there is only a + /// small amount of data. When not set, data is buffered until there is a + /// sufficient amount to send out, thereby avoiding the frequent sending of + /// small packets. + fn set_nodelay(&self, nodelay: bool) -> io::Result<()>; + + /// Gets the value of the `TCP_NODELAY` option on this socket. + /// + /// For more information about this option, see [`set_nodelay`][link]. + /// + /// [link]: #tymethod.set_nodelay + fn nodelay(&self) -> io::Result; + + /// Sets the value of the `SO_RCVBUF` option on this socket. + /// + /// Changes the size of the operating system's receive buffer associated with the socket. + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_RCVBUF` option on this socket. + /// + /// For more information about this option, see [`set_recv_buffer_size`][link]. + /// + /// [link]: #tymethod.set_recv_buffer_size + fn recv_buffer_size(&self) -> io::Result; + + /// Sets the value of the `SO_SNDBUF` option on this socket. + /// + /// Changes the size of the operating system's send buffer associated with the socket. + fn set_send_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_SNDBUF` option on this socket. + /// + /// For more information about this option, see [`set_send_buffer`][link]. + /// + /// [link]: #tymethod.set_send_buffer + fn send_buffer_size(&self) -> io::Result; + + /// Sets whether keepalive messages are enabled to be sent on this socket. + /// + /// On Unix, this option will set the `SO_KEEPALIVE` as well as the + /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform). + /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option. + /// + /// If `None` is specified then keepalive messages are disabled, otherwise + /// the number of milliseconds specified will be the time to remain idle + /// before sending a TCP keepalive probe. + /// + /// Some platforms specify this value in seconds, so sub-second millisecond + /// specifications may be omitted. + fn set_keepalive_ms(&self, keepalive: Option) -> io::Result<()>; + + /// Returns whether keepalive messages are enabled on this socket, and if so + /// the amount of milliseconds between them. + /// + /// For more information about this option, see [`set_keepalive_ms`][link]. + /// + /// [link]: #tymethod.set_keepalive_ms + fn keepalive_ms(&self) -> io::Result>; + + /// Sets whether keepalive messages are enabled to be sent on this socket. + /// + /// On Unix, this option will set the `SO_KEEPALIVE` as well as the + /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform). + /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option. + /// + /// If `None` is specified then keepalive messages are disabled, otherwise + /// the duration specified will be the time to remain idle before sending a + /// TCP keepalive probe. + /// + /// Some platforms specify this value in seconds, so sub-second + /// specifications may be omitted. + fn set_keepalive(&self, keepalive: Option) -> io::Result<()>; + + /// Returns whether keepalive messages are enabled on this socket, and if so + /// the duration of time between them. + /// + /// For more information about this option, see [`set_keepalive`][link]. + /// + /// [link]: #tymethod.set_keepalive + fn keepalive(&self) -> io::Result>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `read` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_read_timeout_ms(&self, val: Option) -> io::Result<()>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `read` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the number of duration of the timeout. + fn set_read_timeout(&self, val: Option) -> io::Result<()>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_read_timeout_ms + fn read_timeout_ms(&self) -> io::Result>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout`][link]. + /// + /// [link]: #tymethod.set_read_timeout + fn read_timeout(&self) -> io::Result>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `write` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_write_timeout_ms(&self, val: Option) -> io::Result<()>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `write` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the duration of the timeout. + fn set_write_timeout(&self, val: Option) -> io::Result<()>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_write_timeout_ms + fn write_timeout_ms(&self) -> io::Result>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout`][link]. + /// + /// [link]: #tymethod.set_write_timeout + fn write_timeout(&self) -> io::Result>; + + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This value sets the time-to-live field that is used in every packet sent + /// from this socket. + fn set_ttl(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see [`set_ttl`][link]. + /// + /// [link]: #tymethod.set_ttl + fn ttl(&self) -> io::Result; + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// If this is set to `true` then the socket is restricted to sending and + /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications + /// can bind the same port at the same time. + /// + /// If this is set to `false` then the socket can be used to send and + /// receive packets from an IPv4-mapped IPv6 address. + fn set_only_v6(&self, only_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see [`set_only_v6`][link]. + /// + /// [link]: #tymethod.set_only_v6 + fn only_v6(&self) -> io::Result; + + /// Executes a `connect` operation on this socket, establishing a connection + /// to the host specified by `addr`. + /// + /// Note that this normally does not need to be called on a `TcpStream`, + /// it's typically automatically done as part of a normal + /// `TcpStream::connect` function call or `TcpBuilder::connect` method call. + /// + /// This should only be necessary if an unconnected socket was extracted + /// from a `TcpBuilder` and then needs to be connected. + fn connect(&self, addr: T) -> io::Result<()>; + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + fn take_error(&self) -> io::Result>; + + /// Moves this TCP stream into or out of nonblocking mode. + /// + /// On Unix this corresponds to calling fcntl, and on Windows this + /// corresponds to calling ioctlsocket. + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>; + + /// Sets the linger duration of this socket by setting the SO_LINGER option + fn set_linger(&self, dur: Option) -> io::Result<()>; + + /// reads the linger duration for this socket by getting the SO_LINGER option + fn linger(&self) -> io::Result>; +} + +/// Extension methods for the standard [`TcpListener` type][link] in `std::net`. +/// +/// [link]: https://doc.rust-lang.org/std/net/struct.TcpListener.html +pub trait TcpListenerExt { + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + fn set_ttl(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_ttl`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_ttl + fn ttl(&self) -> io::Result; + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn set_only_v6(&self, only_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn only_v6(&self) -> io::Result; + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + fn take_error(&self) -> io::Result>; + + /// Moves this TCP listener into or out of nonblocking mode. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_nonblocking`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_nonblocking + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>; + + /// Sets the linger duration of this socket by setting the SO_LINGER option + fn set_linger(&self, dur: Option) -> io::Result<()>; + + /// reads the linger duration for this socket by getting the SO_LINGER option + fn linger(&self) -> io::Result>; +} + +/// Extension methods for the standard [`UdpSocket` type][link] in `std::net`. +/// +/// [link]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html +pub trait UdpSocketExt { + /// Sets the value of the `SO_RCVBUF` option on this socket. + /// + /// Changes the size of the operating system's receive buffer associated with the socket. + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_RCVBUF` option on this socket. + /// + /// For more information about this option, see [`set_recv_buffer_size`][link]. + /// + /// [link]: #tymethod.set_recv_buffer_size + fn recv_buffer_size(&self) -> io::Result; + + /// Sets the value of the `SO_SNDBUF` option on this socket. + /// + /// Changes the size of the operating system's send buffer associated with the socket. + fn set_send_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_SNDBUF` option on this socket. + /// + /// For more information about this option, see [`set_send_buffer`][link]. + /// + /// [link]: #tymethod.set_send_buffer + fn send_buffer_size(&self) -> io::Result; + + /// Sets the value of the `SO_BROADCAST` option for this socket. + /// + /// When enabled, this socket is allowed to send packets to a broadcast + /// address. + fn set_broadcast(&self, broadcast: bool) -> io::Result<()>; + + /// Gets the value of the `SO_BROADCAST` option for this socket. + /// + /// For more information about this option, see + /// [`set_broadcast`][link]. + /// + /// [link]: #tymethod.set_broadcast + fn broadcast(&self) -> io::Result; + + /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. + /// + /// If enabled, multicast packets will be looped back to the local socket. + /// Note that this may not have any affect on IPv6 sockets. + fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()>; + + /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_loop_v4`][link]. + /// + /// [link]: #tymethod.set_multicast_loop_v4 + fn multicast_loop_v4(&self) -> io::Result; + + /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. + /// + /// Indicates the time-to-live value of outgoing multicast packets for + /// this socket. The default value is 1 which means that multicast packets + /// don't leave the local network unless explicitly requested. + /// + /// Note that this may not have any affect on IPv6 sockets. + fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()>; + + /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_ttl_v4`][link]. + /// + /// [link]: #tymethod.set_multicast_ttl_v4 + fn multicast_ttl_v4(&self) -> io::Result; + + /// Sets the value of the `IPV6_MULTICAST_HOPS` option for this socket + fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()>; + + /// Gets the value of the `IPV6_MULTICAST_HOPS` option for this socket + fn multicast_hops_v6(&self) -> io::Result; + + /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. + /// + /// Controls whether this socket sees the multicast packets it sends itself. + /// Note that this may not have any affect on IPv4 sockets. + fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_loop_v6`][link]. + /// + /// [link]: #tymethod.set_multicast_loop_v6 + fn multicast_loop_v6(&self) -> io::Result; + + /// Sets the value of the `IP_MULTICAST_IF` option for this socket. + /// + /// Specifies the interface to use for routing multicast packets. + fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()>; + + /// Gets the value of the `IP_MULTICAST_IF` option for this socket. + /// + /// Returns the interface to use for routing multicast packets. + fn multicast_if_v4(&self) -> io::Result; + + + /// Sets the value of the `IPV6_MULTICAST_IF` option for this socket. + /// + /// Specifies the interface to use for routing multicast packets. + fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()>; + + /// Gets the value of the `IPV6_MULTICAST_IF` option for this socket. + /// + /// Returns the interface to use for routing multicast packets. + fn multicast_if_v6(&self) -> io::Result; + + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + fn set_ttl(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_ttl`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_ttl + fn ttl(&self) -> io::Result; + + /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// Specifies the hop limit for ipv6 unicast packets + fn set_unicast_hops_v6(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket. + /// + /// Specifies the hop limit for ipv6 unicast packets + fn unicast_hops_v6(&self) -> io::Result; + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn set_only_v6(&self, only_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn only_v6(&self) -> io::Result; + + /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. + /// + /// This function specifies a new multicast group for this socket to join. + /// The address must be a valid multicast address, and `interface` is the + /// address of the local interface with which the system should join the + /// multicast group. If it's equal to `INADDR_ANY` then an appropriate + /// interface is chosen by the system. + fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()>; + + /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. + /// + /// This function specifies a new multicast group for this socket to join. + /// The address must be a valid multicast address, and `interface` is the + /// index of the interface to join/leave (or 0 to indicate any interface). + fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()>; + + /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v4`][link]. + /// + /// [link]: #tymethod.join_multicast_v4 + fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()>; + + /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v6`][link]. + /// + /// [link]: #tymethod.join_multicast_v6 + fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `read` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_read_timeout_ms(&self, val: Option) -> io::Result<()>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `read` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the number of duration of the timeout. + fn set_read_timeout(&self, val: Option) -> io::Result<()>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_read_timeout_ms + fn read_timeout_ms(&self) -> io::Result>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout`][link]. + /// + /// [link]: #tymethod.set_read_timeout + fn read_timeout(&self) -> io::Result>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `write` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_write_timeout_ms(&self, val: Option) -> io::Result<()>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `write` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the duration of the timeout. + fn set_write_timeout(&self, val: Option) -> io::Result<()>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_write_timeout_ms + fn write_timeout_ms(&self) -> io::Result>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout`][link]. + /// + /// [link]: #tymethod.set_write_timeout + fn write_timeout(&self) -> io::Result>; + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + fn take_error(&self) -> io::Result>; + + /// Connects this UDP socket to a remote address, allowing the `send` and + /// `recv` syscalls to be used to send data and also applies filters to only + /// receive data from the specified address. + fn connect(&self, addr: A) -> io::Result<()>; + + /// Sends data on the socket to the remote address to which it is connected. + /// + /// The `connect` method will connect this socket to a remote address. This + /// method will fail if the socket is not connected. + fn send(&self, buf: &[u8]) -> io::Result; + + /// Receives data on the socket from the remote address to which it is + /// connected. + /// + /// The `connect` method will connect this socket to a remote address. This + /// method will fail if the socket is not connected. + fn recv(&self, buf: &mut [u8]) -> io::Result; + + /// Moves this UDP socket into or out of nonblocking mode. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_nonblocking`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_nonblocking + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>; +} + +#[doc(hidden)] +pub trait AsSock { + fn as_sock(&self) -> Socket; +} + +#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] +impl AsSock for T { + fn as_sock(&self) -> Socket { self.as_raw_fd() } +} +#[cfg(windows)] +impl AsSock for T { + fn as_sock(&self) -> Socket { self.as_raw_socket() as Socket } +} + +cfg_if! { + if #[cfg(any(target_os = "macos", target_os = "ios"))] { + use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION; + } else if #[cfg(any(target_os = "haiku", target_os = "netbsd", target_os = "openbsd"))] { + use libc::SO_KEEPALIVE as KEEPALIVE_OPTION; + } else if #[cfg(unix)] { + use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; + } else if #[cfg(target_os = "redox")] { + use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; + } else { + // ... + } +} + +impl TcpStreamExt for TcpStream { + + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + // TODO: casting usize to a c_int should be a checked cast + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF, size as c_int) + } + + fn recv_buffer_size(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF).map(int2usize) + } + + fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF, size as c_int) + } + + fn send_buffer_size(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF).map(int2usize) + } + + fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_TCP), TCP_NODELAY, + nodelay as c_int) + } + fn nodelay(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_TCP), TCP_NODELAY) + .map(int2bool) + } + + fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { + self.set_keepalive_ms(keepalive.map(dur2ms)) + } + + fn keepalive(&self) -> io::Result> { + self.keepalive_ms().map(|o| o.map(ms2dur)) + } + + #[cfg(target_os = "redox")] + fn set_keepalive_ms(&self, keepalive: Option) -> io::Result<()> { + try!(set_opt(self.as_sock(), SOL_SOCKET, SO_KEEPALIVE, + keepalive.is_some() as c_int)); + if let Some(dur) = keepalive { + try!(set_opt(self.as_sock(), v(IPPROTO_TCP), KEEPALIVE_OPTION, + (dur / 1000) as c_int)); + } + Ok(()) + } + + #[cfg(target_os = "redox")] + fn keepalive_ms(&self) -> io::Result> { + let keepalive = try!(get_opt::(self.as_sock(), SOL_SOCKET, + SO_KEEPALIVE)); + if keepalive == 0 { + return Ok(None) + } + let secs = try!(get_opt::(self.as_sock(), v(IPPROTO_TCP), + KEEPALIVE_OPTION)); + Ok(Some((secs as u32) * 1000)) + } + + #[cfg(unix)] + fn set_keepalive_ms(&self, keepalive: Option) -> io::Result<()> { + try!(set_opt(self.as_sock(), SOL_SOCKET, SO_KEEPALIVE, + keepalive.is_some() as c_int)); + if let Some(dur) = keepalive { + try!(set_opt(self.as_sock(), v(IPPROTO_TCP), KEEPALIVE_OPTION, + (dur / 1000) as c_int)); + } + Ok(()) + } + + #[cfg(unix)] + fn keepalive_ms(&self) -> io::Result> { + let keepalive = try!(get_opt::(self.as_sock(), SOL_SOCKET, + SO_KEEPALIVE)); + if keepalive == 0 { + return Ok(None) + } + let secs = try!(get_opt::(self.as_sock(), v(IPPROTO_TCP), + KEEPALIVE_OPTION)); + Ok(Some((secs as u32) * 1000)) + } + + #[cfg(target_os = "wasi")] + fn set_keepalive_ms(&self, _keepalive: Option) -> io::Result<()> { + unimplemented!() + } + + #[cfg(target_os = "wasi")] + fn keepalive_ms(&self) -> io::Result> { + unimplemented!() + } + + #[cfg(windows)] + fn set_keepalive_ms(&self, keepalive: Option) -> io::Result<()> { + let ms = keepalive.unwrap_or(INFINITE); + let ka = tcp_keepalive { + onoff: keepalive.is_some() as c_ulong, + keepalivetime: ms as c_ulong, + keepaliveinterval: ms as c_ulong, + }; + unsafe { + ::cvt_win(WSAIoctl(self.as_sock(), + SIO_KEEPALIVE_VALS, + &ka as *const _ as *mut _, + mem::size_of_val(&ka) as DWORD, + 0 as *mut _, + 0, + 0 as *mut _, + 0 as *mut _, + None)).map(|_| ()) + } + } + + #[cfg(windows)] + fn keepalive_ms(&self) -> io::Result> { + let mut ka = tcp_keepalive { + onoff: 0, + keepalivetime: 0, + keepaliveinterval: 0, + }; + unsafe { + try!(::cvt_win(WSAIoctl(self.as_sock(), + SIO_KEEPALIVE_VALS, + 0 as *mut _, + 0, + &mut ka as *mut _ as *mut _, + mem::size_of_val(&ka) as DWORD, + 0 as *mut _, + 0 as *mut _, + None))); + } + Ok({ + if ka.onoff == 0 { + None + } else { + timeout2ms(ka.keepaliveinterval as DWORD) + } + }) + } + + fn set_read_timeout_ms(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO, + ms2timeout(dur)) + } + + fn read_timeout_ms(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO) + .map(timeout2ms) + } + + fn set_write_timeout_ms(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO, + ms2timeout(dur)) + } + + fn write_timeout_ms(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO) + .map(timeout2ms) + } + + fn set_read_timeout(&self, dur: Option) -> io::Result<()> { + self.set_read_timeout_ms(dur.map(dur2ms)) + } + + fn read_timeout(&self) -> io::Result> { + self.read_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn set_write_timeout(&self, dur: Option) -> io::Result<()> { + self.set_write_timeout_ms(dur.map(dur2ms)) + } + + fn write_timeout(&self) -> io::Result> { + self.write_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn set_ttl(&self, ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + } + + fn ttl(&self) -> io::Result { + get_opt::(self.as_sock(), IPPROTO_IP, IP_TTL) + .map(|b| b as u32) + } + + fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + } + + fn only_v6(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool) + } + + fn connect(&self, addr: T) -> io::Result<()> { + do_connect(self.as_sock(), addr) + } + + fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + set_nonblocking(self.as_sock(), nonblocking) + } + + fn set_linger(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur)) + } + + fn linger(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur) + } +} + +#[cfg(any(target_os = "redox", unix, target_os = "wasi"))] +fn ms2timeout(dur: Option) -> timeval { + // TODO: be more rigorous + match dur { + Some(d) => timeval { + tv_sec: (d / 1000) as time_t, + tv_usec: (d % 1000) as suseconds_t, + }, + None => timeval { tv_sec: 0, tv_usec: 0 }, + } +} + +#[cfg(any(target_os = "redox", unix, target_os = "wasi"))] +fn timeout2ms(dur: timeval) -> Option { + if dur.tv_sec == 0 && dur.tv_usec == 0 { + None + } else { + Some(dur.tv_sec as u32 * 1000 + dur.tv_usec as u32 / 1000) + } +} + +#[cfg(windows)] +fn ms2timeout(dur: Option) -> DWORD { + dur.unwrap_or(0) +} + +#[cfg(windows)] +fn timeout2ms(dur: DWORD) -> Option { + if dur == 0 { + None + } else { + Some(dur) + } +} + +fn linger2dur(linger_opt: linger) -> Option { + if linger_opt.l_onoff == 0 { + None + } + else { + Some(Duration::from_secs(linger_opt.l_linger as u64)) + } +} + +#[cfg(windows)] +fn dur2linger(dur: Option) -> linger { + match dur { + Some(d) => { + linger { + l_onoff: 1, + l_linger: d.as_secs() as u16, + } + }, + None => linger { l_onoff: 0, l_linger: 0 }, + } +} + +#[cfg(any(target_os = "redox", unix, target_os = "wasi"))] +fn dur2linger(dur: Option) -> linger { + match dur { + Some(d) => { + linger { + l_onoff: 1, + l_linger: d.as_secs() as c_int, + } + }, + None => linger { l_onoff: 0, l_linger: 0 }, + } +} + +fn ms2dur(ms: u32) -> Duration { + Duration::new((ms as u64) / 1000, (ms as u32) % 1000 * 1_000_000) +} + +fn dur2ms(dur: Duration) -> u32 { + (dur.as_secs() as u32 * 1000) + (dur.subsec_nanos() / 1_000_000) +} + +pub fn int2bool(n: c_int) -> bool { + if n == 0 {false} else {true} +} + +pub fn int2usize(n: c_int) -> usize { + // TODO: casting c_int to a usize should be a checked cast + n as usize +} + +pub fn int2err(n: c_int) -> Option { + if n == 0 { + None + } else { + Some(io::Error::from_raw_os_error(n as i32)) + } +} + +impl UdpSocketExt for UdpSocket { + + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF, size as c_int) + } + + fn recv_buffer_size(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF).map(int2usize) + } + + fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF, size as c_int) + } + + fn send_buffer_size(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF).map(int2usize) + } + + fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_BROADCAST, + broadcast as c_int) + } + fn broadcast(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_BROADCAST) + .map(int2bool) + } + fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_LOOP, + multicast_loop_v4 as c_int) + } + fn multicast_loop_v4(&self) -> io::Result { + get_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_LOOP) + .map(int2bool) + } + + fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_TTL, + multicast_ttl_v4 as c_int) + } + + fn multicast_ttl_v4(&self) -> io::Result { + get_opt::(self.as_sock(), IPPROTO_IP, IP_MULTICAST_TTL) + .map(|b| b as u32) + } + + fn set_multicast_hops_v6(&self, _hops: u32) -> io::Result<()> { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_HOPS, + _hops as c_int) + } + + fn multicast_hops_v6(&self) -> io::Result { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + get_opt::(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_HOPS) + .map(|b| b as u32) + } + + fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_LOOP, + multicast_loop_v6 as c_int) + } + fn multicast_loop_v6(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_LOOP) + .map(int2bool) + } + + fn set_multicast_if_v4(&self, _interface: &Ipv4Addr) -> io::Result<()> { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_IF, ip2in_addr(_interface)) + } + + fn multicast_if_v4(&self) -> io::Result { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + get_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_IF).map(in_addr2ip) + } + + fn set_multicast_if_v6(&self, _interface: u32) -> io::Result<()> { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_IF, to_ipv6mr_interface(_interface)) + } + + fn multicast_if_v6(&self) -> io::Result { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + get_opt::(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_IF).map(|b| b as u32) + } + + fn set_ttl(&self, ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + } + + fn ttl(&self) -> io::Result { + get_opt::(self.as_sock(), IPPROTO_IP, IP_TTL) + .map(|b| b as u32) + } + + fn set_unicast_hops_v6(&self, _ttl: u32) -> io::Result<()> { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_UNICAST_HOPS, _ttl as c_int) + } + + fn unicast_hops_v6(&self) -> io::Result { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + get_opt::(self.as_sock(), IPPROTO_IP, IPV6_UNICAST_HOPS) + .map(|b| b as u32) + } + + fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + } + + fn only_v6(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool) + } + + fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()> { + let mreq = ip_mreq { + imr_multiaddr: ip2in_addr(multiaddr), + imr_interface: ip2in_addr(interface), + }; + set_opt(self.as_sock(), IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq) + } + + fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()> { + let mreq = ipv6_mreq { + ipv6mr_multiaddr: ip2in6_addr(multiaddr), + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_ADD_MEMBERSHIP, + mreq) + } + + fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()> { + let mreq = ip_mreq { + imr_multiaddr: ip2in_addr(multiaddr), + imr_interface: ip2in_addr(interface), + }; + set_opt(self.as_sock(), IPPROTO_IP, IP_DROP_MEMBERSHIP, mreq) + } + + fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()> { + let mreq = ipv6_mreq { + ipv6mr_multiaddr: ip2in6_addr(multiaddr), + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_DROP_MEMBERSHIP, + mreq) + } + + fn set_read_timeout_ms(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO, + ms2timeout(dur)) + } + + fn read_timeout_ms(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO) + .map(timeout2ms) + } + + fn set_write_timeout_ms(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO, + ms2timeout(dur)) + } + + fn write_timeout_ms(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO) + .map(timeout2ms) + } + + fn set_read_timeout(&self, dur: Option) -> io::Result<()> { + self.set_read_timeout_ms(dur.map(dur2ms)) + } + + fn read_timeout(&self) -> io::Result> { + self.read_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn set_write_timeout(&self, dur: Option) -> io::Result<()> { + self.set_write_timeout_ms(dur.map(dur2ms)) + } + + fn write_timeout(&self) -> io::Result> { + self.write_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + fn connect(&self, addr: A) -> io::Result<()> { + do_connect(self.as_sock(), addr) + } + + #[cfg(target_os = "redox")] + fn send(&self, buf: &[u8]) -> io::Result { + unsafe { + ::cvt(write(self.as_sock() as c_int, buf.as_ptr() as *const _, buf.len())).map(|n| n as usize) + } + } + + #[cfg(unix)] + fn send(&self, buf: &[u8]) -> io::Result { + unsafe { + ::cvt(send(self.as_sock() as c_int, buf.as_ptr() as *const _, buf.len(), 0)).map(|n| n as usize) + } + } + + #[cfg(target_os = "wasi")] + fn send(&self, buf: &[u8]) -> io::Result { + let _so_datalen: *mut sys::c::size_t = &mut 0; + unsafe { + let _errno = libc::__wasi_sock_send( + self.as_sock() as libc::__wasi_fd_t, + buf.as_ptr() as *const _, + buf.len(), + 0, + _so_datalen, + ); + // TODO: handle errno + Ok((*_so_datalen) as usize) + } + } + + #[cfg(windows)] + fn send(&self, buf: &[u8]) -> io::Result { + let len = ::std::cmp::min(buf.len(), c_int::max_value() as usize); + let buf = &buf[..len]; + unsafe { + ::cvt(send(self.as_sock(), buf.as_ptr() as *const _, len as c_int, 0)) + .map(|n| n as usize) + } + } + + #[cfg(target_os = "redox")] + fn recv(&self, buf: &mut [u8]) -> io::Result { + unsafe { + ::cvt(read(self.as_sock() as c_int, buf.as_mut_ptr() as *mut _, buf.len())) + .map(|n| n as usize) + } + } + + #[cfg(unix)] + fn recv(&self, buf: &mut [u8]) -> io::Result { + unsafe { + ::cvt(recv(self.as_sock(), buf.as_mut_ptr() as *mut _, buf.len(), 0)) + .map(|n| n as usize) + } + } + + #[cfg(target_os = "wasi")] + fn recv(&self, buf: &mut [u8]) -> io::Result { + let _ro_datalen: *mut sys::c::size_t = &mut 0; + let _ro_flags: *mut sys::c::__wasi_roflags_t = &mut 0; + unsafe { + let _errno = __wasi_sock_recv( + self.as_sock(), + buf.as_mut_ptr() as *mut _, + buf.len(), + 0, + _ro_datalen, + _ro_flags, + ); + // TODO: handle errno + Ok((*_ro_datalen) as usize) + } + } + + #[cfg(windows)] + fn recv(&self, buf: &mut [u8]) -> io::Result { + let len = ::std::cmp::min(buf.len(), c_int::max_value() as usize); + let buf = &mut buf[..len]; + unsafe { + ::cvt(recv(self.as_sock(), buf.as_mut_ptr() as *mut _, buf.len() as c_int, 0)) + .map(|n| n as usize) + } + } + + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + set_nonblocking(self.as_sock(), nonblocking) + } +} + +fn do_connect(sock: Socket, addr: A) -> io::Result<()> { + let err = io::Error::new(io::ErrorKind::Other, + "no socket addresses resolved"); + let addrs = try!(addr.to_socket_addrs()); + let sys = sys::Socket::from_inner(sock); + let sock = socket::Socket::from_inner(sys); + let ret = addrs.fold(Err(err), |prev, addr| { + prev.or_else(|_| sock.connect(&addr)) + }); + mem::forget(sock); + return ret +} + +#[cfg(target_os = "redox")] +fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> { + let mut flags = ::cvt(unsafe { + fcntl(sock as c_int, F_GETFL) + })?; + if nonblocking { + flags |= O_NONBLOCK; + } else { + flags &= !O_NONBLOCK; + } + ::cvt(unsafe { + fcntl(sock as c_int, F_SETFL, flags) + }).and(Ok(())) +} + +#[cfg(unix)] +fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_ulong; + ::cvt(unsafe { + ioctl(sock, FIONBIO, &mut nonblocking) + }).map(|_| ()) +} + +#[cfg(target_os = "wasi")] +fn set_nonblocking(_sock: Socket, _nonblocking: bool) -> io::Result<()> { + Ok(()) +} + +#[cfg(windows)] +fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_ulong; + ::cvt(unsafe { + ioctlsocket(sock, FIONBIO as c_int, &mut nonblocking) + }).map(|_| ()) +} + +#[cfg(target_os = "redox")] +fn ip2in_addr(ip: &Ipv4Addr) -> in_addr { + let oct = ip.octets(); + in_addr { + s_addr: ::hton(((oct[0] as u32) << 24) | + ((oct[1] as u32) << 16) | + ((oct[2] as u32) << 8) | + ((oct[3] as u32) << 0)), + } +} + +#[cfg(any(unix, target_os = "wasi"))] +fn ip2in_addr(ip: &Ipv4Addr) -> in_addr { + let oct = ip.octets(); + in_addr { + s_addr: ::hton(((oct[0] as u32) << 24) | + ((oct[1] as u32) << 16) | + ((oct[2] as u32) << 8) | + ((oct[3] as u32) << 0)), + } +} + +#[cfg(windows)] +fn ip2in_addr(ip: &Ipv4Addr) -> in_addr { + let oct = ip.octets(); + unsafe { + let mut S_un: in_addr_S_un = mem::zeroed(); + *S_un.S_addr_mut() = ::hton(((oct[0] as u32) << 24) | + ((oct[1] as u32) << 16) | + ((oct[2] as u32) << 8) | + ((oct[3] as u32) << 0)); + in_addr { + S_un: S_un, + } + } +} + +fn in_addr2ip(ip: &in_addr) -> Ipv4Addr { + let h_addr = c::in_addr_to_u32(ip); + + let a: u8 = (h_addr >> 24) as u8; + let b: u8 = (h_addr >> 16) as u8; + let c: u8 = (h_addr >> 8) as u8; + let d: u8 = (h_addr >> 0) as u8; + + Ipv4Addr::new(a,b,c,d) +} + +#[cfg(target_os = "android")] +fn to_ipv6mr_interface(value: u32) -> c_int { + value as c_int +} + +#[cfg(not(target_os = "android"))] +fn to_ipv6mr_interface(value: u32) -> c_uint { + value as c_uint +} + +fn ip2in6_addr(ip: &Ipv6Addr) -> in6_addr { + let mut ret: in6_addr = unsafe { mem::zeroed() }; + let seg = ip.segments(); + let bytes = [ + (seg[0] >> 8) as u8, + (seg[0] >> 0) as u8, + (seg[1] >> 8) as u8, + (seg[1] >> 0) as u8, + (seg[2] >> 8) as u8, + (seg[2] >> 0) as u8, + (seg[3] >> 8) as u8, + (seg[3] >> 0) as u8, + (seg[4] >> 8) as u8, + (seg[4] >> 0) as u8, + (seg[5] >> 8) as u8, + (seg[5] >> 0) as u8, + (seg[6] >> 8) as u8, + (seg[6] >> 0) as u8, + (seg[7] >> 8) as u8, + (seg[7] >> 0) as u8, + ]; + #[cfg(windows)] unsafe { *ret.u.Byte_mut() = bytes; } + #[cfg(not(windows))] { ret.s6_addr = bytes; } + + return ret +} + +impl TcpListenerExt for TcpListener { + fn set_ttl(&self, ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + } + + fn ttl(&self) -> io::Result { + get_opt::(self.as_sock(), IPPROTO_IP, IP_TTL) + .map(|b| b as u32) + } + + fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + } + + fn only_v6(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool) + } + + fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + set_nonblocking(self.as_sock(), nonblocking) + } + + fn set_linger(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur)) + } + + fn linger(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur) + } +} + +impl TcpBuilder { + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + pub fn ttl(&self, ttl: u32) -> io::Result<&Self> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + .map(|()| self) + } + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_only_v6`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_only_v6 + pub fn only_v6(&self, only_v6: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + .map(|()| self) + } + + /// Set value for the `SO_REUSEADDR` option on this socket. + /// + /// This indicates that further calls to `bind` may allow reuse of local + /// addresses. For IPv4 sockets this means that a socket may bind even when + /// there's a socket already listening on this port. + pub fn reuse_address(&self, reuse: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR, + reuse as c_int).map(|()| self) + } + + /// Check the `SO_REUSEADDR` option on this socket. + pub fn get_reuse_address(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR).map(int2bool) + } + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + pub fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + /// Sets the linger option for this socket + fn set_linger(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur)) + } + + /// Gets the linger option for this socket + fn linger(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur) + } +} + +impl UdpBuilder { + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + pub fn ttl(&self, ttl: u32) -> io::Result<&Self> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + .map(|()| self) + } + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// This is the same as [`TcpStream::only_v6`][other]. + /// + /// [other]: struct.TcpBuilder.html#method.only_v6 + pub fn only_v6(&self, only_v6: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + .map(|()| self) + } + + /// Set value for the `SO_REUSEADDR` option on this socket. + /// + /// This is the same as [`TcpBuilder::reuse_address`][other]. + /// + /// [other]: struct.TcpBuilder.html#method.reuse_address + pub fn reuse_address(&self, reuse: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR, + reuse as c_int).map(|()| self) + } + + /// Check the `SO_REUSEADDR` option on this socket. + pub fn get_reuse_address(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR).map(int2bool) + } + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + pub fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } +} diff --git a/vendor/net2/src/lib.rs b/vendor/net2/src/lib.rs new file mode 100644 index 0000000000..fcbb7b454c --- /dev/null +++ b/vendor/net2/src/lib.rs @@ -0,0 +1,127 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Extensions to `std::net` networking types. +//! +//! This crate implements a number of extensions to the standard `std::net` +//! networking types, hopefully being slated for inclusion into the standard +//! library in the future. The goal of this crate is to expose all sorts of +//! cross-platform and platform-specific configuration options of UDP/TCP +//! sockets. System APIs are wrapped with as thin a layer as possible instead of +//! bundling multiple actions into one API call. +//! +//! More information about the design of this crate can be found in the +//! [associated rfc][rfc] +//! +//! [rfc]: https://github.com/rust-lang/rfcs/pull/1158 +//! +//! # Examples +//! +//! ```no_run +//! use net2::TcpBuilder; +//! +//! let tcp = TcpBuilder::new_v4().unwrap(); +//! tcp.reuse_address(true).unwrap() +//! .only_v6(false).unwrap(); +//! +//! let mut stream = tcp.connect("127.0.0.1:80").unwrap(); +//! +//! // use `stream` as a TcpStream +//! ``` + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/net2-rs")] +#![deny(missing_docs, warnings)] + +// Silence warnings about deprecated try!() usage +#![allow(deprecated)] + +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] + +#[cfg(any(target_os = "redox", target_os = "wasi", unix))] extern crate libc; + +#[cfg(windows)] extern crate winapi; + +#[macro_use] extern crate cfg_if; + +use std::io; +use std::ops::Neg; +use std::net::{ToSocketAddrs, SocketAddr}; + +use utils::{One, NetInt}; + +mod tcp; +mod udp; +mod socket; +mod ext; +mod utils; + +#[cfg(target_os="redox")] #[path = "sys/redox/mod.rs"] mod sys; +#[cfg(unix)] #[path = "sys/unix/mod.rs"] mod sys; +#[cfg(windows)] #[path = "sys/windows/mod.rs"] mod sys; +#[cfg(target_os = "wasi")] #[path = "sys/wasi/mod.rs"] mod sys; +#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))] pub mod unix; + +pub use tcp::TcpBuilder; +pub use udp::UdpBuilder; +pub use ext::{TcpStreamExt, TcpListenerExt, UdpSocketExt}; + +fn one_addr(tsa: T) -> io::Result { + let mut addrs = try!(tsa.to_socket_addrs()); + let addr = match addrs.next() { + Some(addr) => addr, + None => return Err(io::Error::new(io::ErrorKind::Other, + "no socket addresses could be resolved")) + }; + if addrs.next().is_none() { + Ok(addr) + } else { + Err(io::Error::new(io::ErrorKind::Other, + "more than one address resolved")) + } +} + +fn cvt>(t: T) -> io::Result { + let one: T = T::one(); + if t == -one { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +#[cfg(windows)] +fn cvt_win(t: T) -> io::Result { + if t == T::zero() { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +fn hton(i: I) -> I { i.to_be() } + +fn ntoh(i: I) -> I { I::from_be(i) } + +trait AsInner { + type Inner; + fn as_inner(&self) -> &Self::Inner; +} + +trait FromInner { + type Inner; + fn from_inner(inner: Self::Inner) -> Self; +} + +trait IntoInner { + type Inner; + fn into_inner(self) -> Self::Inner; +} diff --git a/vendor/net2/src/socket.rs b/vendor/net2/src/socket.rs new file mode 100644 index 0000000000..2b4a48ce38 --- /dev/null +++ b/vendor/net2/src/socket.rs @@ -0,0 +1,142 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use std::io; +use std::mem; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] +use libc::c_int; +#[cfg(windows)] +use winapi::ctypes::c_int; + +use sys; +use sys::c; + +pub struct Socket { + inner: sys::Socket, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int) -> io::Result { + Ok(Socket { inner: try!(sys::Socket::new(family, ty)) }) + } + + pub fn bind(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr2raw(addr); + unsafe { + ::cvt(c::bind(self.inner.raw(), addr, len as c::socklen_t)).map(|_| ()) + } + } + + pub fn listen(&self, backlog: i32) -> io::Result<()> { + unsafe { + ::cvt(c::listen(self.inner.raw(), backlog)).map(|_| ()) + } + } + + pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr2raw(addr); + unsafe { + ::cvt(c::connect(self.inner.raw(), addr, len)).map(|_| ()) + } + } + + pub fn getsockname(&self) -> io::Result { + unsafe { + let mut storage: c::sockaddr_storage = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as c::socklen_t; + try!(::cvt(c::getsockname(self.inner.raw(), + &mut storage as *mut _ as *mut _, + &mut len))); + raw2addr(&storage, len) + } + } +} + +impl fmt::Debug for Socket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.raw().fmt(f) + } +} + +impl ::AsInner for Socket { + type Inner = sys::Socket; + fn as_inner(&self) -> &sys::Socket { &self.inner } +} + +impl ::FromInner for Socket { + type Inner = sys::Socket; + fn from_inner(sock: sys::Socket) -> Socket { + Socket { inner: sock } + } +} + +impl ::IntoInner for Socket { + type Inner = sys::Socket; + fn into_inner(self) -> sys::Socket { self.inner } +} + +fn addr2raw(addr: &SocketAddr) -> (*const c::sockaddr, c::socklen_t) { + match *addr { + SocketAddr::V4(ref a) => { + (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t) + } + SocketAddr::V6(ref a) => { + (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t) + } + } +} + +fn raw2addr(storage: &c::sockaddr_storage, len: c::socklen_t) -> io::Result { + match storage.ss_family as c_int { + c::AF_INET => { + unsafe { + assert!(len as usize >= mem::size_of::()); + let sa = storage as *const _ as *const c::sockaddr_in; + let bits = c::sockaddr_in_u32(&(*sa)); + let ip = Ipv4Addr::new((bits >> 24) as u8, + (bits >> 16) as u8, + (bits >> 8) as u8, + bits as u8); + Ok(SocketAddr::V4(SocketAddrV4::new(ip, ::ntoh((*sa).sin_port)))) + } + } + c::AF_INET6 => { + unsafe { + assert!(len as usize >= mem::size_of::()); + + let sa = storage as *const _ as *const c::sockaddr_in6; + #[cfg(windows)] let arr = (*sa).sin6_addr.u.Byte(); + #[cfg(not(windows))] let arr = (*sa).sin6_addr.s6_addr; + + let ip = Ipv6Addr::new( + (arr[0] as u16) << 8 | (arr[1] as u16), + (arr[2] as u16) << 8 | (arr[3] as u16), + (arr[4] as u16) << 8 | (arr[5] as u16), + (arr[6] as u16) << 8 | (arr[7] as u16), + (arr[8] as u16) << 8 | (arr[9] as u16), + (arr[10] as u16) << 8 | (arr[11] as u16), + (arr[12] as u16) << 8 | (arr[13] as u16), + (arr[14] as u16) << 8 | (arr[15] as u16), + ); + + #[cfg(windows)] let sin6_scope_id = *(*sa).u.sin6_scope_id(); + #[cfg(not(windows))] let sin6_scope_id = (*sa).sin6_scope_id; + + Ok(SocketAddr::V6(SocketAddrV6::new(ip, + ::ntoh((*sa).sin6_port), + (*sa).sin6_flowinfo, + sin6_scope_id))) + } + } + _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid argument")), + } +} diff --git a/vendor/net2/src/sys/redox/impls.rs b/vendor/net2/src/sys/redox/impls.rs new file mode 100644 index 0000000000..388ec69241 --- /dev/null +++ b/vendor/net2/src/sys/redox/impls.rs @@ -0,0 +1,43 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::unix::io::{FromRawFd, AsRawFd}; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys; + +impl FromRawFd for TcpBuilder { + unsafe fn from_raw_fd(fd: usize) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for TcpBuilder { + fn as_raw_fd(&self) -> usize { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as usize + } +} + +impl FromRawFd for UdpBuilder { + unsafe fn from_raw_fd(fd: usize) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for UdpBuilder { + fn as_raw_fd(&self) -> usize { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as usize + } +} diff --git a/vendor/net2/src/sys/redox/mod.rs b/vendor/net2/src/sys/redox/mod.rs new file mode 100644 index 0000000000..9fd9b1f20e --- /dev/null +++ b/vendor/net2/src/sys/redox/mod.rs @@ -0,0 +1,81 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::unix::io::FromRawFd; +use libc::{self, c_int}; + +mod impls; + +pub mod c { + pub use libc::*; + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh((*sa).sin_addr.s_addr) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(addr.s_addr) + } +} + +pub struct Socket { + fd: c_int, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int) -> io::Result { + unsafe { + let fd = ::cvt(libc::socket(family, ty, 0))?; + let mut flags = ::cvt(libc::fcntl(fd, libc::F_GETFD))?; + flags |= libc::O_CLOEXEC; + ::cvt(libc::fcntl(fd, libc::F_SETFD, flags))?; + Ok(Socket { fd: fd }) + } + } + + pub fn raw(&self) -> c_int { self.fd } + + fn into_fd(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_fd(self.into_fd() as usize) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_fd(self.into_fd() as usize) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_fd(self.into_fd() as usize) } + } +} + +impl ::FromInner for Socket { + type Inner = usize; + fn from_inner(fd: usize) -> Socket { + Socket { fd: fd as c_int } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = libc::close(self.fd); + } + } +} diff --git a/vendor/net2/src/sys/unix/impls.rs b/vendor/net2/src/sys/unix/impls.rs new file mode 100644 index 0000000000..95c2fb8081 --- /dev/null +++ b/vendor/net2/src/sys/unix/impls.rs @@ -0,0 +1,44 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::unix::io::{FromRawFd, AsRawFd}; +use libc::c_int; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys; + +impl FromRawFd for TcpBuilder { + unsafe fn from_raw_fd(fd: c_int) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for TcpBuilder { + fn as_raw_fd(&self) -> c_int { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() + } +} + +impl FromRawFd for UdpBuilder { + unsafe fn from_raw_fd(fd: c_int) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for UdpBuilder { + fn as_raw_fd(&self) -> c_int { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() + } +} diff --git a/vendor/net2/src/sys/unix/mod.rs b/vendor/net2/src/sys/unix/mod.rs new file mode 100644 index 0000000000..cc8a60d01e --- /dev/null +++ b/vendor/net2/src/sys/unix/mod.rs @@ -0,0 +1,104 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::unix::io::FromRawFd; +use libc::{self, c_int}; +#[cfg(not(any(target_os = "emscripten", target_os = "haiku", target_os = "illumos", target_os = "solaris")))] +use libc::{ioctl, FIOCLEX}; + +mod impls; + +pub mod c { + pub use libc::*; + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh((*sa).sin_addr.s_addr) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(addr.s_addr) + } +} + +pub struct Socket { + fd: c_int, +} + +impl Socket { + #[cfg(not(any(target_os = "emscripten", target_os = "haiku", target_os = "illumos", target_os = "solaris")))] + pub fn new(family: c_int, ty: c_int) -> io::Result { + unsafe { + // Linux >2.6.26 overloads the type argument to accept SOCK_CLOEXEC, + // avoiding a race with another thread running fork/exec between + // socket() and ioctl() + #[cfg(any(target_os = "linux", target_os = "android"))] + match ::cvt(libc::socket(family, ty | libc::SOCK_CLOEXEC, 0)) { + Ok(fd) => return Ok(Socket { fd: fd }), + // Older versions of Linux return EINVAL; fall back to ioctl + Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} + Err(e) => return Err(e), + } + + let fd = try!(::cvt(libc::socket(family, ty, 0))); + ioctl(fd, FIOCLEX); + Ok(Socket { fd: fd }) + } + } + + // ioctl(FIOCLEX) is not supported by Solaris/illumos or emscripten, + // use fcntl(FD_CLOEXEC) instead + #[cfg(any(target_os = "emscripten", target_os = "haiku", target_os = "illumos", target_os = "solaris"))] + pub fn new(family: c_int, ty: c_int) -> io::Result { + unsafe { + let fd = try!(::cvt(libc::socket(family, ty, 0))); + libc::fcntl(fd, libc::FD_CLOEXEC); + Ok(Socket { fd: fd }) + } + } + + pub fn raw(&self) -> c_int { self.fd } + + fn into_fd(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_fd(self.into_fd()) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_fd(self.into_fd()) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_fd(self.into_fd()) } + } +} + +impl ::FromInner for Socket { + type Inner = c_int; + fn from_inner(fd: c_int) -> Socket { + Socket { fd: fd } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = libc::close(self.fd); + } + } +} diff --git a/vendor/net2/src/sys/wasi/impls.rs b/vendor/net2/src/sys/wasi/impls.rs new file mode 100644 index 0000000000..eef8094b60 --- /dev/null +++ b/vendor/net2/src/sys/wasi/impls.rs @@ -0,0 +1,33 @@ +use std::os::wasi::io::{FromRawFd, AsRawFd}; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys::{self, c::__wasi_fd_t}; + +impl FromRawFd for TcpBuilder { + unsafe fn from_raw_fd(fd: __wasi_fd_t) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for TcpBuilder { + fn as_raw_fd(&self) -> __wasi_fd_t { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as __wasi_fd_t + } +} + +impl FromRawFd for UdpBuilder { + unsafe fn from_raw_fd(fd: __wasi_fd_t) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for UdpBuilder { + fn as_raw_fd(&self) -> __wasi_fd_t { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as __wasi_fd_t + } +} diff --git a/vendor/net2/src/sys/wasi/mod.rs b/vendor/net2/src/sys/wasi/mod.rs new file mode 100644 index 0000000000..bbc507ed68 --- /dev/null +++ b/vendor/net2/src/sys/wasi/mod.rs @@ -0,0 +1,185 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] +use libc::{self, c_int, __wasi_fd_t}; +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::wasi::io::FromRawFd; + +mod impls; + +pub mod c { + pub use libc::*; + + pub type sa_family_t = u16; + pub type socklen_t = u32; + pub type in_port_t = u16; + + pub const SOCK_DGRAM: c_int = 0x00; + pub const SOL_SOCKET: c_int = 0x00; + pub const SO_RCVBUF: c_int = 0x00; + pub const SO_SNDBUF: c_int = 0x00; + pub const TCP_NODELAY: c_int = 0x00; + pub const IPPROTO_TCP: c_int = 0x00; + pub const SO_RCVTIMEO: c_int = 0x00; + pub const SO_SNDTIMEO: c_int = 0x00; + pub const IPPROTO_IP: c_int = 0x00; + pub const IP_TTL: c_int = 0x00; + pub const IPPROTO_IPV6: c_int = 0x00; + pub const IPV6_V6ONLY: c_int = 0x00; + pub const SO_ERROR: c_int = 0x00; + pub const SO_LINGER: c_int = 0x00; + pub const SO_BROADCAST: c_int = 0x00; + pub const IP_MULTICAST_LOOP: c_int = 0x00; + pub const IP_MULTICAST_TTL: c_int = 0x00; + pub const IPV6_MULTICAST_HOPS: c_int = 0x00; + pub const IPV6_MULTICAST_LOOP: c_int = 0x00; + pub const IP_MULTICAST_IF: c_int = 0x00; + pub const IPV6_MULTICAST_IF: c_int = 0x00; + pub const IPV6_UNICAST_HOPS: c_int = 0x00; + pub const IP_ADD_MEMBERSHIP: c_int = 0x00; + pub const IPV6_ADD_MEMBERSHIP: c_int = 0x00; + pub const IP_DROP_MEMBERSHIP: c_int = 0x00; + pub const IPV6_DROP_MEMBERSHIP: c_int = 0x00; + pub const SO_REUSEADDR: c_int = 0x00; + pub const SOCK_STREAM: c_int = 0x00; + pub const AF_INET: c_int = 0x00; + pub const AF_INET6: c_int = 0x01; + + #[repr(C)] + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + } + #[repr(C)] + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + #[repr(C)] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: in6_addr, + pub sin6_scope_id: u32, + } + + #[repr(C)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [u8; 8], + } + + #[repr(align(4))] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, + } + + pub type in_addr_t = u32; + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: in_addr_t, + } + + #[derive(Copy, Clone)] + pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, + } + + #[derive(Copy, Clone)] + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub unsafe fn getsockname(_socket: __wasi_fd_t, _address: *mut sockaddr, + _address_len: *mut socklen_t) -> c_int { + unimplemented!() + } + pub unsafe fn connect(_socket: __wasi_fd_t, _address: *const sockaddr, + _len: socklen_t) -> c_int { + unimplemented!() + } + pub unsafe fn listen(_socket: __wasi_fd_t, _backlog: c_int) -> c_int { + unimplemented!() + } + pub unsafe fn bind(_socket: __wasi_fd_t, _address: *const sockaddr, + _address_len: socklen_t) -> c_int { + unimplemented!() + } + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh((*sa).sin_addr.s_addr) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(addr.s_addr) + } +} + +pub struct Socket { + fd: __wasi_fd_t, +} + +impl Socket { + pub fn new(_family: c_int, _ty: c_int) -> io::Result { + unimplemented!() + } + + pub fn raw(&self) -> libc::__wasi_fd_t { + self.fd + } + + fn into_fd(self) -> libc::__wasi_fd_t { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_fd(self.into_fd()) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_fd(self.into_fd()) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_fd(self.into_fd()) } + } +} + +impl ::FromInner for Socket { + type Inner = libc::__wasi_fd_t; + fn from_inner(fd: libc::__wasi_fd_t) -> Socket { + Socket { fd: fd } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + // unsafe { + // let _ = libc::close(self.fd); + // } + } +} \ No newline at end of file diff --git a/vendor/net2/src/sys/windows/impls.rs b/vendor/net2/src/sys/windows/impls.rs new file mode 100644 index 0000000000..48e787ca20 --- /dev/null +++ b/vendor/net2/src/sys/windows/impls.rs @@ -0,0 +1,44 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::windows::io::{FromRawSocket, RawSocket, AsRawSocket}; +use winapi::um::winsock2::SOCKET; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys; + +impl FromRawSocket for TcpBuilder { + unsafe fn from_raw_socket(fd: RawSocket) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd as SOCKET); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawSocket for TcpBuilder { + fn as_raw_socket(&self) -> RawSocket { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as RawSocket + } +} + +impl FromRawSocket for UdpBuilder { + unsafe fn from_raw_socket(fd: RawSocket) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd as SOCKET); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawSocket for UdpBuilder { + fn as_raw_socket(&self) -> RawSocket { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as RawSocket + } +} diff --git a/vendor/net2/src/sys/windows/mod.rs b/vendor/net2/src/sys/windows/mod.rs new file mode 100644 index 0000000000..b2da96d2f9 --- /dev/null +++ b/vendor/net2/src/sys/windows/mod.rs @@ -0,0 +1,124 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::windows::io::{RawSocket, FromRawSocket}; +use std::sync::{Once, ONCE_INIT}; + +const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; + +pub mod c { + pub use winapi::ctypes::*; + pub use winapi::um::handleapi::*; + pub use winapi::um::winbase::*; + pub use winapi::um::winsock2::*; + pub use winapi::um::ws2tcpip::*; + + pub use winapi::shared::inaddr::*; + pub use winapi::shared::in6addr::*; + pub use winapi::shared::minwindef::*; + pub use winapi::shared::ntdef::*; + pub use winapi::shared::ws2def::*; + pub use winapi::shared::ws2def::{SOCK_STREAM, SOCK_DGRAM}; + pub use winapi::shared::ws2def::SOCKADDR as sockaddr; + pub use winapi::shared::ws2def::SOCKADDR_STORAGE as sockaddr_storage; + pub use winapi::shared::ws2def::SOCKADDR_IN as sockaddr_in; + pub use winapi::shared::ws2ipdef::*; + pub use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; + pub use winapi::shared::ws2ipdef::IP_MREQ as ip_mreq; + pub use winapi::shared::ws2ipdef::IPV6_MREQ as ipv6_mreq; + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh(unsafe { *sa.sin_addr.S_un.S_addr() }) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(unsafe { *addr.S_un.S_addr() }) + } +} + +use self::c::*; + +mod impls; + +fn init() { + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + // Initialize winsock through the standard library by just creating a + // dummy socket. Whether this is successful or not we drop the result as + // libstd will be sure to have initialized winsock. + let _ = UdpSocket::bind("127.0.0.1:34254"); + }); +} + +pub struct Socket { + socket: SOCKET, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int) -> io::Result { + init(); + let socket = try!(unsafe { + match WSASocketW(family, ty, 0, 0 as *mut _, 0, + WSA_FLAG_OVERLAPPED) { + INVALID_SOCKET => Err(io::Error::last_os_error()), + n => Ok(Socket { socket: n }), + } + }); + try!(socket.set_no_inherit()); + Ok(socket) + } + + pub fn raw(&self) -> SOCKET { self.socket } + + fn into_socket(self) -> SOCKET { + let socket = self.socket; + mem::forget(self); + socket + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_socket(self.into_socket() as RawSocket) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_socket(self.into_socket() as RawSocket) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_socket(self.into_socket() as RawSocket) } + } + + fn set_no_inherit(&self) -> io::Result<()> { + ::cvt_win(unsafe { + SetHandleInformation(self.socket as HANDLE, HANDLE_FLAG_INHERIT, 0) + }).map(|_| ()) + } +} + +impl ::FromInner for Socket { + type Inner = SOCKET; + fn from_inner(socket: SOCKET) -> Socket { + Socket { socket: socket } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = closesocket(self.socket); + } + } +} diff --git a/vendor/net2/src/tcp.rs b/vendor/net2/src/tcp.rs new file mode 100644 index 0000000000..5a535dbb5c --- /dev/null +++ b/vendor/net2/src/tcp.rs @@ -0,0 +1,161 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::RefCell; +use std::io; +use std::net::{SocketAddr, ToSocketAddrs, TcpListener, TcpStream}; +use std::fmt; + +use IntoInner; +use socket::Socket; +use sys::c; + +/// An "in progress" TCP socket which has not yet been connected or listened. +/// +/// Allows configuration of a socket before one of these operations is executed. +pub struct TcpBuilder { + socket: RefCell>, +} + +impl TcpBuilder { + /// Constructs a new TcpBuilder with the `AF_INET` domain, the `SOCK_STREAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v4() -> io::Result { + Socket::new(c::AF_INET, c::SOCK_STREAM).map(::FromInner::from_inner) + } + + /// Constructs a new TcpBuilder with the `AF_INET6` domain, the `SOCK_STREAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v6() -> io::Result { + Socket::new(c::AF_INET6, c::SOCK_STREAM).map(::FromInner::from_inner) + } + + /// Binds this socket to the specified address. + /// + /// This function directly corresponds to the bind(2) function on Windows + /// and Unix. + pub fn bind(&self, addr: T) -> io::Result<&TcpBuilder> + where T: ToSocketAddrs + { + self.with_socket(|sock| { + let addr = try!(::one_addr(addr)); + sock.bind(&addr) + }).map(|()| self) + } + + /// Mark a socket as ready to accept incoming connection requests using + /// accept() + /// + /// This function directly corresponds to the listen(2) function on Windows + /// and Unix. + /// + /// An error will be returned if `listen` or `connect` has already been + /// called on this builder. + pub fn listen(&self, backlog: i32) -> io::Result { + self.with_socket(|sock| { + sock.listen(backlog) + }).and_then(|()| { + self.to_tcp_listener() + }) + } + + /// Initiate a connection on this socket to the specified address. + /// + /// This function directly corresponds to the connect(2) function on Windows + /// and Unix. + /// + /// An error will be returned if `listen` or `connect` has already been + /// called on this builder. + pub fn connect(&self, addr: T) -> io::Result + where T: ToSocketAddrs + { + self.with_socket(|sock| { + let err = io::Error::new(io::ErrorKind::Other, + "no socket addresses resolved"); + try!(addr.to_socket_addrs()).fold(Err(err), |prev, addr| { + prev.or_else(|_| sock.connect(&addr)) + }) + }).and_then(|()| { + self.to_tcp_stream() + }) + } + + /// Converts this builder into a `TcpStream` + /// + /// This function will consume the internal socket and return it re-wrapped + /// as a `TcpStream`. An error will be returned if the internal socket has + /// already been consumed from a successful call to `connect`, `listen`, + /// etc. + pub fn to_tcp_stream(&self) -> io::Result { + self.socket.borrow_mut().take().map(|s| s.into_inner().into_tcp_stream()) + .ok_or(io::Error::new(io::ErrorKind::Other, + "socket has already been consumed")) + } + + /// Converts this builder into a `TcpListener` + /// + /// This function will consume the internal socket and return it re-wrapped + /// as a `TcpListener`. An error will be returned if the internal socket has + /// already been consumed from a successful call to `connect`, `listen`, + /// etc. + pub fn to_tcp_listener(&self) -> io::Result { + self.socket.borrow_mut().take() + .map(|s| s.into_inner().into_tcp_listener()) + .ok_or(io::Error::new(io::ErrorKind::Other, + "socket has already been consumed")) + } + + /// Returns the address of the local half of this TCP socket. + /// + /// An error will be returned if `listen` or `connect` has already been + /// called on this builder. + pub fn local_addr(&self) -> io::Result { + match *self.socket.borrow() { + Some(ref s) => s.getsockname(), + None => Err(io::Error::new(io::ErrorKind::Other, + "builder has already finished its socket")), + } + } + + fn with_socket(&self, f: F) -> io::Result<()> + where F: FnOnce(&Socket) -> io::Result<()> + { + match *self.socket.borrow() { + Some(ref s) => f(s), + None => Err(io::Error::new(io::ErrorKind::Other, + "builder has already finished its socket")), + } + } +} + +impl fmt::Debug for TcpBuilder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TcpBuilder {{ socket: {:?} }}", + self.socket.borrow().as_ref().unwrap()) + } +} + +impl ::AsInner for TcpBuilder { + type Inner = RefCell>; + fn as_inner(&self) -> &RefCell> { &self.socket } +} + +impl ::FromInner for TcpBuilder { + type Inner = Socket; + fn from_inner(sock: Socket) -> TcpBuilder { + TcpBuilder { socket: RefCell::new(Some(sock)) } + } +} diff --git a/vendor/net2/src/udp.rs b/vendor/net2/src/udp.rs new file mode 100644 index 0000000000..d061ab5c6f --- /dev/null +++ b/vendor/net2/src/udp.rs @@ -0,0 +1,89 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::RefCell; +use std::fmt; +use std::io; +use std::net::{ToSocketAddrs, UdpSocket}; + +use IntoInner; +use socket::Socket; +use sys::c; + +/// An "in progress" UDP socket which has not yet been connected. +/// +/// Allows configuration of a socket before the socket is connected. +pub struct UdpBuilder { + socket: RefCell>, +} + +impl UdpBuilder { + /// Constructs a new UdpBuilder with the `AF_INET` domain, the `SOCK_DGRAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v4() -> io::Result { + Socket::new(c::AF_INET, c::SOCK_DGRAM).map(::FromInner::from_inner) + } + + /// Constructs a new UdpBuilder with the `AF_INET6` domain, the `SOCK_DGRAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v6() -> io::Result { + Socket::new(c::AF_INET6, c::SOCK_DGRAM).map(::FromInner::from_inner) + } + + /// Binds this socket to the specified address. + /// + /// This function directly corresponds to the bind(2) function on Windows + /// and Unix. + pub fn bind(&self, addr: T) -> io::Result + where T: ToSocketAddrs + { + try!(self.with_socket(|sock| { + let addr = try!(::one_addr(addr)); + sock.bind(&addr) + })); + Ok(self.socket.borrow_mut().take().unwrap().into_inner().into_udp_socket()) + } + + fn with_socket(&self, f: F) -> io::Result<()> + where F: FnOnce(&Socket) -> io::Result<()> + { + match *self.socket.borrow() { + Some(ref s) => f(s), + None => Err(io::Error::new(io::ErrorKind::Other, + "builder has already finished its socket")), + } + } +} + +impl fmt::Debug for UdpBuilder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "UdpBuilder {{ socket: {:?} }}", + self.socket.borrow().as_ref().unwrap()) + } +} + +impl ::AsInner for UdpBuilder { + type Inner = RefCell>; + fn as_inner(&self) -> &RefCell> { &self.socket } +} + +impl ::FromInner for UdpBuilder { + type Inner = Socket; + fn from_inner(sock: Socket) -> UdpBuilder { + UdpBuilder { socket: RefCell::new(Some(sock)) } + } +} + diff --git a/vendor/net2/src/unix.rs b/vendor/net2/src/unix.rs new file mode 100644 index 0000000000..a1e1c6f5e9 --- /dev/null +++ b/vendor/net2/src/unix.rs @@ -0,0 +1,57 @@ +//! Unix-specific extensions to the `std::net` types. + +use std::io; +use sys::c::{self, c_int}; + +use {TcpBuilder, UdpBuilder}; +use ext::{self, AsSock}; + +/// Unix-specific extensions for the `TcpBuilder` type in this library. +pub trait UnixTcpBuilderExt { + /// Set value for the `SO_REUSEPORT` option on this socket. + /// + /// This indicates that further calls to `bind` may allow reuse of local + /// addresses. For IPv4 sockets this means that a socket may bind even when + /// there's a socket already listening on this port. + fn reuse_port(&self, reuse: bool) -> io::Result<&Self>; + + /// Check the value of the `SO_REUSEPORT` option on this socket. + fn get_reuse_port(&self) -> io::Result; +} + +impl UnixTcpBuilderExt for TcpBuilder { + fn reuse_port(&self, reuse: bool) -> io::Result<&Self> { + ext::set_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT, + reuse as c_int).map(|()| self) + } + + fn get_reuse_port(&self) -> io::Result { + ext::get_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT) + .map(ext::int2bool) + } +} + +/// Unix-specific extensions for the `UdpBuilder` type in this library. +pub trait UnixUdpBuilderExt { + /// Set value for the `SO_REUSEPORT` option on this socket. + /// + /// This indicates that further calls to `bind` may allow reuse of local + /// addresses. For IPv4 sockets this means that a socket may bind even when + /// there's a socket already listening on this port. + fn reuse_port(&self, reuse: bool) -> io::Result<&Self>; + + /// Check the value of the `SO_REUSEPORT` option on this socket. + fn get_reuse_port(&self) -> io::Result; +} + +impl UnixUdpBuilderExt for UdpBuilder { + fn reuse_port(&self, reuse: bool) -> io::Result<&Self> { + ext::set_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT, + reuse as c_int).map(|()| self) + } + + fn get_reuse_port(&self) -> io::Result { + ext::get_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT) + .map(ext::int2bool) + } +} diff --git a/vendor/net2/src/utils.rs b/vendor/net2/src/utils.rs new file mode 100644 index 0000000000..21fe9d61fc --- /dev/null +++ b/vendor/net2/src/utils.rs @@ -0,0 +1,51 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +#[doc(hidden)] +pub trait NetInt { + fn from_be(i: Self) -> Self; + fn to_be(&self) -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl NetInt for $t { + fn from_be(i: Self) -> Self { <$t>::from_be(i) } + fn to_be(&self) -> Self { <$t>::to_be(*self) } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + +#[doc(hidden)] +pub trait One { + fn one() -> Self; +} + +macro_rules! one { + ($($t:ident)*) => ($( + impl One for $t { fn one() -> $t { 1 } } + )*) +} + +one! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + + +#[doc(hidden)] +pub trait Zero { + fn zero() -> Self; +} + +macro_rules! zero { + ($($t:ident)*) => ($( + impl Zero for $t { fn zero() -> $t { 0 } } + )*) +} + +zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + diff --git a/vendor/opaque-debug-0.2.3/.cargo-checksum.json b/vendor/opaque-debug-0.2.3/.cargo-checksum.json new file mode 100644 index 0000000000..e431ffb85c --- /dev/null +++ b/vendor/opaque-debug-0.2.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"316df812f280ae0c584b6132630119bea8de32864c29772100f9bb8352196381","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"2d7d563f4a4df4b0583d6370046642103e4909f0ec2002768308f951f2d7e05c"},"package":"2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"} \ No newline at end of file diff --git a/vendor/opaque-debug-0.2.3/Cargo.toml b/vendor/opaque-debug-0.2.3/Cargo.toml new file mode 100644 index 0000000000..a2f9f1736d --- /dev/null +++ b/vendor/opaque-debug-0.2.3/Cargo.toml @@ -0,0 +1,22 @@ +# 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 = "opaque-debug" +version = "0.2.3" +authors = ["RustCrypto Developers"] +description = "Macro for opaque Debug trait implementation" +documentation = "https://docs.rs/opaque-debug" +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/utils" + +[dependencies] diff --git a/vendor/opaque-debug-0.2.3/LICENSE-APACHE b/vendor/opaque-debug-0.2.3/LICENSE-APACHE new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/opaque-debug-0.2.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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/opaque-debug-0.2.3/LICENSE-MIT b/vendor/opaque-debug-0.2.3/LICENSE-MIT new file mode 100644 index 0000000000..502cee6e85 --- /dev/null +++ b/vendor/opaque-debug-0.2.3/LICENSE-MIT @@ -0,0 +1,25 @@ +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/opaque-debug-0.2.3/src/lib.rs b/vendor/opaque-debug-0.2.3/src/lib.rs new file mode 100644 index 0000000000..618626ead7 --- /dev/null +++ b/vendor/opaque-debug-0.2.3/src/lib.rs @@ -0,0 +1,24 @@ +//! Macro for opaque `Debug` trait implementation. +#![no_std] + +#[doc(hidden)] +pub extern crate core as __core; + +/// Macro for defining opaque `Debug` implementation. +/// +/// It will use the following format: "StructName { ... }". While it's +/// convinient to have it (e.g. for including into other structs), it could be +/// undesirable to leak internall state, which can happen for example through +/// uncareful logging. +#[macro_export] +macro_rules! impl_opaque_debug { + ($struct:ty) => { + impl $crate::__core::fmt::Debug for $struct { + fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) + -> Result<(), $crate::__core::fmt::Error> + { + write!(f, concat!(stringify!($struct), " {{ ... }}")) + } + } + } +} diff --git a/vendor/opaque-debug/.cargo-checksum.json b/vendor/opaque-debug/.cargo-checksum.json index e431ffb85c..737800c677 100644 --- a/vendor/opaque-debug/.cargo-checksum.json +++ b/vendor/opaque-debug/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"316df812f280ae0c584b6132630119bea8de32864c29772100f9bb8352196381","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"2d7d563f4a4df4b0583d6370046642103e4909f0ec2002768308f951f2d7e05c"},"package":"2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"} \ No newline at end of file +{"files":{"Cargo.toml":"6eed73941bd5295d09d546b5690ef723a88c022947461f68e246299466bf779d","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"b7f7f6a9dd862dd8d132ae35cc3fd131938f64c9a8e0e5fab42bb5a1ed0f459b","tests/mod.rs":"8db1fbb5043e175e9f780e78a34a3e6d22f2010cfd2a8b26fcfdec1b71c0a75d"},"package":"624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"} \ No newline at end of file diff --git a/vendor/opaque-debug/Cargo.toml b/vendor/opaque-debug/Cargo.toml index a2f9f1736d..9650c91794 100644 --- a/vendor/opaque-debug/Cargo.toml +++ b/vendor/opaque-debug/Cargo.toml @@ -11,12 +11,11 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "opaque-debug" -version = "0.2.3" +version = "0.3.0" authors = ["RustCrypto Developers"] description = "Macro for opaque Debug trait implementation" documentation = "https://docs.rs/opaque-debug" license = "MIT OR Apache-2.0" repository = "https://github.com/RustCrypto/utils" - -[dependencies] diff --git a/vendor/opaque-debug/src/lib.rs b/vendor/opaque-debug/src/lib.rs index 618626ead7..6d564a3bf4 100644 --- a/vendor/opaque-debug/src/lib.rs +++ b/vendor/opaque-debug/src/lib.rs @@ -8,10 +8,10 @@ pub extern crate core as __core; /// /// It will use the following format: "StructName { ... }". While it's /// convinient to have it (e.g. for including into other structs), it could be -/// undesirable to leak internall state, which can happen for example through +/// undesirable to leak internal state, which can happen for example through /// uncareful logging. #[macro_export] -macro_rules! impl_opaque_debug { +macro_rules! implement { ($struct:ty) => { impl $crate::__core::fmt::Debug for $struct { fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) diff --git a/vendor/opaque-debug/tests/mod.rs b/vendor/opaque-debug/tests/mod.rs new file mode 100644 index 0000000000..bcd575767a --- /dev/null +++ b/vendor/opaque-debug/tests/mod.rs @@ -0,0 +1,13 @@ +#![allow(dead_code)] + +struct Foo { + secret: u64, +} + +opaque_debug::implement!(Foo); + +#[test] +fn debug_formatting() { + let s = format!("{:?}", Foo { secret: 42 }); + assert_eq!(s, "Foo { ... }"); +} diff --git a/vendor/parking_lot-0.10.2/.cargo-checksum.json b/vendor/parking_lot-0.10.2/.cargo-checksum.json deleted file mode 100644 index 784094cd6f..0000000000 --- a/vendor/parking_lot-0.10.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"18a3b6c2a59fb59450362712afae444070b23c2697cf20aa9ee3911dd9f6d981","Cargo.toml":"c0d17dd8decba5afb1495577e0ded39c0228eeb2eb14be4f4d4d5d9c96ebc0c3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"0f1b45638eb0d2b3f142baec830319a5790f3f2004eac5bc5f3e95bc632bdaed","appveyor.yml":"e2416e65e27442dd8e17c773deee1e45ee96157221bc81b03d9a6d25bfa570e2","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","src/condvar.rs":"510f96e94b56f0cb0d200a8e94b0487d0799e13b9e126b9b416f22d8dc11b643","src/deadlock.rs":"7d3ebb5b4f63658435df277bb983e352e4bc651a92c4fd48ae68bf103e452d0d","src/elision.rs":"9aceb0b27fd3cdaf4ef76bda63435a96ec2fdef24be098b9e4edbc39db000765","src/fair_mutex.rs":"d0a032e8207919da04b85f1422dfb14aa2af7aad78843c708d2fe3e0478e401a","src/lib.rs":"3d89619878f3c8b6190261321a4e430e0514c97b65e8c911c0764ea57c0605f2","src/mutex.rs":"afc25db5c45da63c743029ee3cb22e262ea7a32b533245b441c0a5835f9f525f","src/once.rs":"a1c38a5d87077e3d112d57e065ee126a24ab19f04fba9cb1f2cb43bc82caf33c","src/raw_fair_mutex.rs":"a7415aa6cbc040a2f886d06dd6c0c0b3be9963936a31f60f1494e718c9d18acb","src/raw_mutex.rs":"f3507478c34b49bd725dfaed6bf4847fc3aec28700960a7823af9e15b06b5e24","src/raw_rwlock.rs":"f8ce7c4f92299cf64cb6e7b69cd46d9ddefd1211535729b6455e82f7c4eb3eae","src/remutex.rs":"7a0de55161cd57497bb52d3aecca69a89eff2e71cdb2d762df53579e0607b489","src/rwlock.rs":"1a782ab4fafc0c542d1c42151b98475829c96da168d2d0e8947181b7f2d7cb07","src/util.rs":"37a2c8b5c9254df83e8f3a5cd831558c1045061a76c2571bdc4d78eb86e467f2","tests/issue_203.rs":"5fbdf6ec63f391d86457df949678c203a1e81e8aa32d4e10037fa76e768702c0"},"package":"d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"} \ No newline at end of file diff --git a/vendor/parking_lot-0.10.2/CHANGELOG.md b/vendor/parking_lot-0.10.2/CHANGELOG.md deleted file mode 100644 index c187e4d157..0000000000 --- a/vendor/parking_lot-0.10.2/CHANGELOG.md +++ /dev/null @@ -1,120 +0,0 @@ -## parking_lot 0.10.2 (2020-04-10) - -- Update minimum version of `lock_api`. - -## parking_lot 0.10.1, parking_lot_core 0.7.1, lock_api 0.3.4 (2020-04-10) - -- Add methods to construct `Mutex`, `RwLock`, etc in a `const` context. (#217) -- Add `FairMutex` which always uses fair unlocking. (#204) -- Fixed panic with deadlock detection on macOS. (#203) -- Fixed incorrect synchronization in `create_hashtable`. (#210) -- Use `llvm_asm!` instead of the deprecated `asm!`. (#223) - -## lock_api 0.3.3 (2020-01-04) - -- Deprecate unsound `MappedRwLockWriteGuard::downgrade` (#198) - -## parking_lot 0.10.0, parking_lot_core 0.7.0, lock_api 0.3.2 (2019-11-25) - -- Upgrade smallvec dependency to 1.0 in parking_lot_core. -- Replace all usage of `mem::uninitialized` with `mem::MaybeUninit`. -- The minimum required Rust version is bumped to 1.36. Because of the above two changes. -- Make methods on `WaitTimeoutResult` and `OnceState` take `self` by value instead of reference. - -## parking_lot_core 0.6.2 (2019-07-22) - -- Fixed compile error on Windows with old cfg_if version. (#164) - -## parking_lot_core 0.6.1 (2019-07-17) - -- Fixed Android build. (#163) - -## parking_lot 0.9.0, parking_lot_core 0.6.0, lock_api 0.3.1 (2019-07-14) - -- Re-export lock_api (0.3.1) from parking_lot (#150) -- Removed (non-dev) dependency on rand crate for fairness mechanism, by - including a simple xorshift PRNG in core (#144) -- Android now uses the futex-based ThreadParker. (#140) -- Fixed CloudABI ThreadParker. (#140) -- Fix race condition in lock_api::ReentrantMutex (da16c2c7) - -## lock_api 0.3.0 (2019-07-03, _yanked_) - -- Use NonZeroUsize in GetThreadId::nonzero_thread_id (#148) -- Debug assert lock_count in ReentrantMutex (#148) -- Tag as `unsafe` and document some internal methods (#148) -- This release was _yanked_ due to a regression in ReentrantMutex (da16c2c7) - -## parking_lot 0.8.1 (2019-07-03, _yanked_) - -- Re-export lock_api (0.3.0) from parking_lot (#150) -- This release was _yanked_ from crates.io due to unexpected breakage (#156) - -## parking_lot 0.8.0, parking_lot_core 0.5.0, lock_api 0.2.0 (2019-05-04) - -- Fix race conditions in deadlock detection. -- Support for more platforms by adding ThreadParker implementations for - Wasm, Redox, SGX and CloudABI. -- Drop support for older Rust. parking_lot now requires 1.31 and is a - Rust 2018 edition crate (#122). -- Disable the owning_ref feature by default. -- Fix was_last_thread value in the timeout callback of park() (#129). -- Support single byte Mutex/Once on stable Rust when compiler is at least - version 1.34. -- Make Condvar::new and Once::new const fns on stable Rust and remove - ONCE_INIT (#134). -- Add optional Serde support (#135). - -## parking_lot 0.7.1 (2019-01-01) - -- Fixed potential deadlock when upgrading a RwLock. -- Fixed overflow panic on very long timeouts (#111). - -## parking_lot 0.7.0, parking_lot_core 0.4.0 (2018-11-26) - -- Return if or how many threads were notified from `Condvar::notify_*` - -## parking_lot 0.6.3 (2018-07-18) - -- Export `RawMutex`, `RawRwLock` and `RawThreadId`. - -## parking_lot 0.6.2 (2018-06-18) - -- Enable `lock_api/nightly` feature from `parking_lot/nightly` (#79) - -## parking_lot 0.6.1 (2018-06-08) - -Added missing typedefs for mapped lock guards: - -- `MappedMutexGuard` -- `MappedReentrantMutexGuard` -- `MappedRwLockReadGuard` -- `MappedRwLockWriteGuard` - -## parking_lot 0.6.0 (2018-06-08) - -This release moves most of the code for type-safe `Mutex` and `RwLock` types -into a separate crate called `lock_api`. This new crate is compatible with -`no_std` and provides `Mutex` and `RwLock` type-safe wrapper types from a raw -mutex type which implements the `RawMutex` or `RawRwLock` trait. The API -provided by the wrapper types can be extended by implementing more traits on -the raw mutex type which provide more functionality (e.g. `RawMutexTimed`). See -the crate documentation for more details. - -There are also several major changes: - -- The minimum required Rust version is bumped to 1.26. -- All methods on `MutexGuard` (and other guard types) are no longer inherent - methods and must be called as `MutexGuard::method(self)`. This avoids - conflicts with methods from the inner type. -- `MutexGuard` (and other guard types) add the `unlocked` method which - temporarily unlocks a mutex, runs the given closure, and then re-locks the - mutex. -- `MutexGuard` (and other guard types) add the `bump` method which gives a - chance for other threads to acquire the mutex by temporarily unlocking it and - re-locking it. However this is optimized for the common case where there are - no threads waiting on the lock, in which case no unlocking is performed. -- `MutexGuard` (and other guard types) add the `map` method which returns a - `MappedMutexGuard` which holds only a subset of the original locked type. The - `MappedMutexGuard` type is identical to `MutexGuard` except that it does not - support the `unlocked` and `bump` methods, and can't be used with `CondVar`. diff --git a/vendor/parking_lot-0.10.2/Cargo.toml b/vendor/parking_lot-0.10.2/Cargo.toml deleted file mode 100644 index 57940fff19..0000000000 --- a/vendor/parking_lot-0.10.2/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] -edition = "2018" -name = "parking_lot" -version = "0.10.2" -authors = ["Amanieu d'Antras "] -description = "More compact and efficient implementations of the standard synchronization primitives." -readme = "README.md" -keywords = ["mutex", "condvar", "rwlock", "once", "thread"] -categories = ["concurrency"] -license = "Apache-2.0/MIT" -repository = "https://github.com/Amanieu/parking_lot" -[dependencies.lock_api] -version = "0.3.4" - -[dependencies.parking_lot_core] -version = "0.7.1" -[dev-dependencies.bincode] -version = "1.1.3" - -[dev-dependencies.rand] -version = "0.7" - -[features] -deadlock_detection = ["parking_lot_core/deadlock_detection"] -default = [] -nightly = ["parking_lot_core/nightly", "lock_api/nightly"] -owning_ref = ["lock_api/owning_ref"] -serde = ["lock_api/serde"] diff --git a/vendor/parking_lot-0.10.2/README.md b/vendor/parking_lot-0.10.2/README.md deleted file mode 100644 index 3ec4cb0418..0000000000 --- a/vendor/parking_lot-0.10.2/README.md +++ /dev/null @@ -1,140 +0,0 @@ -parking_lot -============ - -[![Build Status](https://travis-ci.org/Amanieu/parking_lot.svg?branch=master)](https://travis-ci.org/Amanieu/parking_lot) [![Build status](https://ci.appveyor.com/api/projects/status/wppcc32ttpud0a30/branch/master?svg=true)](https://ci.appveyor.com/project/Amanieu/parking-lot/branch/master) [![Crates.io](https://img.shields.io/crates/v/parking_lot.svg)](https://crates.io/crates/parking_lot) - -[Documentation (synchronization primitives)](https://docs.rs/parking_lot/) - -[Documentation (core parking lot API)](https://docs.rs/parking_lot_core/) - -[Documentation (type-safe lock API)](https://docs.rs/lock_api/) - -This library provides implementations of `Mutex`, `RwLock`, `Condvar` and -`Once` that are smaller, faster and more flexible than those in the Rust -standard library, as well as a `ReentrantMutex` type which supports recursive -locking. It also exposes a low-level API for creating your own efficient -synchronization primitives. - -When tested on x86_64 Linux, `parking_lot::Mutex` was found to be 1.5x -faster than `std::sync::Mutex` when uncontended, and up to 5x faster when -contended from multiple threads. The numbers for `RwLock` vary depending on -the number of reader and writer threads, but are almost always faster than -the standard library `RwLock`, and even up to 50x faster in some cases. - -## Features - -The primitives provided by this library have several advantages over those -in the Rust standard library: - -1. `Mutex` and `Once` only require 1 byte of storage space, while `Condvar` - and `RwLock` only require 1 word of storage space. On the other hand the - standard library primitives require a dynamically allocated `Box` to hold - OS-specific synchronization primitives. The small size of `Mutex` in - particular encourages the use of fine-grained locks to increase - parallelism. -2. Since they consist of just a single atomic variable, have constant - initializers and don't need destructors, these primitives can be used as - `static` global variables. The standard library primitives require - dynamic initialization and thus need to be lazily initialized with - `lazy_static!`. -3. Uncontended lock acquisition and release is done through fast inline - paths which only require a single atomic operation. -4. Microcontention (a contended lock with a short critical section) is - efficiently handled by spinning a few times while trying to acquire a - lock. -5. The locks are adaptive and will suspend a thread after a few failed spin - attempts. This makes the locks suitable for both long and short critical - sections. -6. `Condvar`, `RwLock` and `Once` work on Windows XP, unlike the standard - library versions of those types. -7. `RwLock` takes advantage of hardware lock elision on processors that - support it, which can lead to huge performance wins with many readers. -8. `RwLock` uses a task-fair locking policy, which avoids reader and writer - starvation, whereas the standard library version makes no guarantees. -9. `Condvar` is guaranteed not to produce spurious wakeups. A thread will - only be woken up if it timed out or it was woken up by a notification. -10. `Condvar::notify_all` will only wake up a single thread and requeue the - rest to wait on the associated `Mutex`. This avoids a thundering herd - problem where all threads try to acquire the lock at the same time. -11. `RwLock` supports atomically downgrading a write lock into a read lock. -12. `Mutex` and `RwLock` allow raw unlocking without a RAII guard object. -13. `Mutex<()>` and `RwLock<()>` allow raw locking without a RAII guard - object. -14. `Mutex` and `RwLock` support [eventual fairness](https://trac.webkit.org/changeset/203350) - which allows them to be fair on average without sacrificing performance. -15. A `ReentrantMutex` type which supports recursive locking. -16. An *experimental* deadlock detector that works for `Mutex`, - `RwLock` and `ReentrantMutex`. This feature is disabled by default and - can be enabled via the `deadlock_detection` feature. -17. `RwLock` supports atomically upgrading an "upgradable" read lock into a - write lock. -18. Optional support for [serde](https://docs.serde.rs/serde/). Enable via the - feature `serde`. **NOTE!** this support is for `Mutex`, `ReentrantMutex`, - and `RwLock` only; `Condvar` and `Once` are not currently supported. - -## The parking lot - -To keep these primitives small, all thread queuing and suspending -functionality is offloaded to the *parking lot*. The idea behind this is -based on the Webkit [`WTF::ParkingLot`](https://webkit.org/blog/6161/locking-in-webkit/) -class, which essentially consists of a hash table mapping of lock addresses -to queues of parked (sleeping) threads. The Webkit parking lot was itself -inspired by Linux [futexes](http://man7.org/linux/man-pages/man2/futex.2.html), -but it is more powerful since it allows invoking callbacks while holding a queue -lock. - -## Nightly vs stable - -There are a few restrictions when using this library on stable Rust: - -- You will have to use the `const_*` functions (e.g. `const_mutex(val)`) to - statically initialize the locking primitives. Using e.g. `Mutex::new(val)` - does not work on stable Rust yet. -- `RwLock` will not be able to take advantage of hardware lock elision for - readers, which improves performance when there are multiple readers. - -To enable nightly-only functionality, you need to enable the `nightly` feature -in Cargo (see below). - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -parking_lot = "0.10" -``` - -To enable nightly-only features, add this to your `Cargo.toml` instead: - -```toml -[dependencies] -parking_lot = { version = "0.10", features = ["nightly"] } -``` - -The experimental deadlock detector can be enabled with the -`deadlock_detection` Cargo feature. - -The core parking lot API is provided by the `parking_lot_core` crate. It is -separate from the synchronization primitives in the `parking_lot` crate so that -changes to the core API do not cause breaking changes for users of `parking_lot`. - -## Minimum Rust version - -The current minimum required Rust version is 1.36. Any change to this is -considered a breaking change and will require a major version bump. - -## 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/parking_lot-0.10.2/appveyor.yml b/vendor/parking_lot-0.10.2/appveyor.yml deleted file mode 100644 index a7eb5cfc98..0000000000 --- a/vendor/parking_lot-0.10.2/appveyor.yml +++ /dev/null @@ -1,59 +0,0 @@ -environment: - TRAVIS_CARGO_NIGHTLY_FEATURE: nightly - RUST_TEST_THREADS: 1 - matrix: - - TARGET: x86_64-pc-windows-msvc - MSYSTEM: MINGW64 - CPU: x86_64 - TOOLCHAIN: nightly - FEATURES: nightly - - TARGET: i686-pc-windows-msvc - MSYSTEM: MINGW32 - CPU: i686 - TOOLCHAIN: nightly - FEATURES: nightly - - TARGET: x86_64-pc-windows-gnu - MSYSTEM: MINGW64 - CPU: x86_64 - TOOLCHAIN: nightly - FEATURES: nightly - - TARGET: i686-pc-windows-gnu - MSYSTEM: MINGW32 - CPU: i686 - TOOLCHAIN: nightly - FEATURES: nightly - - TARGET: x86_64-pc-windows-msvc - MSYSTEM: MINGW64 - CPU: x86_64 - TOOLCHAIN: 1.36.0 - - TARGET: i686-pc-windows-msvc - MSYSTEM: MINGW32 - CPU: i686 - TOOLCHAIN: 1.36.0 - - TARGET: x86_64-pc-windows-gnu - MSYSTEM: MINGW64 - CPU: x86_64 - TOOLCHAIN: 1.36.0 - - TARGET: i686-pc-windows-gnu - MSYSTEM: MINGW32 - CPU: i686 - TOOLCHAIN: 1.36.0 - -install: - - set PATH=C:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% - - pacman --noconfirm -Syu mingw-w64-%CPU%-make - - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init.exe -y --default-host %TARGET% --default-toolchain %TOOLCHAIN% - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - rustc -vV - - cargo -vV - -build_script: - - cargo build --features "%FEATURES%" - -test_script: - - cargo test --all --features "%FEATURES%" - - cargo doc --all - - cd benchmark - - cargo run --release --bin mutex -- 2 1 0 1 2 - - cargo run --release --bin rwlock -- 1 1 1 0 1 2 diff --git a/vendor/parking_lot-0.10.2/bors.toml b/vendor/parking_lot-0.10.2/bors.toml deleted file mode 100644 index ca08e818bf..0000000000 --- a/vendor/parking_lot-0.10.2/bors.toml +++ /dev/null @@ -1,3 +0,0 @@ -status = [ - "continuous-integration/travis-ci/push", -] diff --git a/vendor/parking_lot-0.10.2/src/condvar.rs b/vendor/parking_lot-0.10.2/src/condvar.rs deleted file mode 100644 index 0afda3a5b1..0000000000 --- a/vendor/parking_lot-0.10.2/src/condvar.rs +++ /dev/null @@ -1,1052 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::mutex::MutexGuard; -use crate::raw_mutex::{RawMutex, TOKEN_HANDOFF, TOKEN_NORMAL}; -use crate::{deadlock, util}; -use core::{ - fmt, ptr, - sync::atomic::{AtomicPtr, Ordering}, -}; -use lock_api::RawMutex as RawMutex_; -use parking_lot_core::{self, ParkResult, RequeueOp, UnparkResult, DEFAULT_PARK_TOKEN}; -use std::time::{Duration, Instant}; - -/// A type indicating whether a timed wait on a condition variable returned -/// due to a time out or not. -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub struct WaitTimeoutResult(bool); - -impl WaitTimeoutResult { - /// Returns whether the wait was known to have timed out. - #[inline] - pub fn timed_out(self) -> bool { - self.0 - } -} - -/// A Condition Variable -/// -/// Condition variables represent the ability to block a thread such that it -/// consumes no CPU time while waiting for an event to occur. Condition -/// variables are typically associated with a boolean predicate (a condition) -/// and a mutex. The predicate is always verified inside of the mutex before -/// determining that thread must block. -/// -/// Note that this module places one additional restriction over the system -/// condition variables: each condvar can be used with only one mutex at a -/// time. Any attempt to use multiple mutexes on the same condition variable -/// simultaneously will result in a runtime panic. However it is possible to -/// switch to a different mutex if there are no threads currently waiting on -/// the condition variable. -/// -/// # Differences from the standard library `Condvar` -/// -/// - No spurious wakeups: A wait will only return a non-timeout result if it -/// was woken up by `notify_one` or `notify_all`. -/// - `Condvar::notify_all` will only wake up a single thread, the rest are -/// requeued to wait for the `Mutex` to be unlocked by the thread that was -/// woken up. -/// - Only requires 1 word of space, whereas the standard library boxes the -/// `Condvar` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). -/// - Does not require any drop glue when dropped. -/// - Inline fast path for the uncontended case. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::{Mutex, Condvar}; -/// use std::sync::Arc; -/// use std::thread; -/// -/// let pair = Arc::new((Mutex::new(false), Condvar::new())); -/// let pair2 = pair.clone(); -/// -/// // Inside of our lock, spawn a new thread, and then wait for it to start -/// thread::spawn(move|| { -/// let &(ref lock, ref cvar) = &*pair2; -/// let mut started = lock.lock(); -/// *started = true; -/// cvar.notify_one(); -/// }); -/// -/// // wait for the thread to start up -/// let &(ref lock, ref cvar) = &*pair; -/// let mut started = lock.lock(); -/// if !*started { -/// cvar.wait(&mut started); -/// } -/// // Note that we used an if instead of a while loop above. This is only -/// // possible because parking_lot's Condvar will never spuriously wake up. -/// // This means that wait() will only return after notify_one or notify_all is -/// // called. -/// ``` -pub struct Condvar { - state: AtomicPtr, -} - -impl Condvar { - /// Creates a new condition variable which is ready to be waited on and - /// notified. - #[inline] - pub const fn new() -> Condvar { - Condvar { - state: AtomicPtr::new(ptr::null_mut()), - } - } - - /// Wakes up one blocked thread on this condvar. - /// - /// Returns whether a thread was woken up. - /// - /// If there is a blocked thread on this condition variable, then it will - /// be woken up from its call to `wait` or `wait_timeout`. Calls to - /// `notify_one` are not buffered in any way. - /// - /// To wake up all threads, see `notify_all()`. - /// - /// # Examples - /// - /// ``` - /// use parking_lot::Condvar; - /// - /// let condvar = Condvar::new(); - /// - /// // do something with condvar, share it with other threads - /// - /// if !condvar.notify_one() { - /// println!("Nobody was listening for this."); - /// } - /// ``` - #[inline] - pub fn notify_one(&self) -> bool { - // Nothing to do if there are no waiting threads - let state = self.state.load(Ordering::Relaxed); - if state.is_null() { - return false; - } - - self.notify_one_slow(state) - } - - #[cold] - fn notify_one_slow(&self, mutex: *mut RawMutex) -> bool { - unsafe { - // Unpark one thread and requeue the rest onto the mutex - let from = self as *const _ as usize; - let to = mutex as usize; - let validate = || { - // Make sure that our atomic state still points to the same - // mutex. If not then it means that all threads on the current - // mutex were woken up and a new waiting thread switched to a - // different mutex. In that case we can get away with doing - // nothing. - if self.state.load(Ordering::Relaxed) != mutex { - return RequeueOp::Abort; - } - - // Unpark one thread if the mutex is unlocked, otherwise just - // requeue everything to the mutex. This is safe to do here - // since unlocking the mutex when the parked bit is set requires - // locking the queue. There is the possibility of a race if the - // mutex gets locked after we check, but that doesn't matter in - // this case. - if (*mutex).mark_parked_if_locked() { - RequeueOp::RequeueOne - } else { - RequeueOp::UnparkOne - } - }; - let callback = |_op, result: UnparkResult| { - // Clear our state if there are no more waiting threads - if !result.have_more_threads { - self.state.store(ptr::null_mut(), Ordering::Relaxed); - } - TOKEN_NORMAL - }; - let res = parking_lot_core::unpark_requeue(from, to, validate, callback); - - res.unparked_threads + res.requeued_threads != 0 - } - } - - /// Wakes up all blocked threads on this condvar. - /// - /// Returns the number of threads woken up. - /// - /// This method will ensure that any current waiters on the condition - /// variable are awoken. Calls to `notify_all()` are not buffered in any - /// way. - /// - /// To wake up only one thread, see `notify_one()`. - #[inline] - pub fn notify_all(&self) -> usize { - // Nothing to do if there are no waiting threads - let state = self.state.load(Ordering::Relaxed); - if state.is_null() { - return 0; - } - - self.notify_all_slow(state) - } - - #[cold] - fn notify_all_slow(&self, mutex: *mut RawMutex) -> usize { - unsafe { - // Unpark one thread and requeue the rest onto the mutex - let from = self as *const _ as usize; - let to = mutex as usize; - let validate = || { - // Make sure that our atomic state still points to the same - // mutex. If not then it means that all threads on the current - // mutex were woken up and a new waiting thread switched to a - // different mutex. In that case we can get away with doing - // nothing. - if self.state.load(Ordering::Relaxed) != mutex { - return RequeueOp::Abort; - } - - // Clear our state since we are going to unpark or requeue all - // threads. - self.state.store(ptr::null_mut(), Ordering::Relaxed); - - // Unpark one thread if the mutex is unlocked, otherwise just - // requeue everything to the mutex. This is safe to do here - // since unlocking the mutex when the parked bit is set requires - // locking the queue. There is the possibility of a race if the - // mutex gets locked after we check, but that doesn't matter in - // this case. - if (*mutex).mark_parked_if_locked() { - RequeueOp::RequeueAll - } else { - RequeueOp::UnparkOneRequeueRest - } - }; - let callback = |op, result: UnparkResult| { - // If we requeued threads to the mutex, mark it as having - // parked threads. The RequeueAll case is already handled above. - if op == RequeueOp::UnparkOneRequeueRest && result.requeued_threads != 0 { - (*mutex).mark_parked(); - } - TOKEN_NORMAL - }; - let res = parking_lot_core::unpark_requeue(from, to, validate, callback); - - res.unparked_threads + res.requeued_threads - } - } - - /// Blocks the current thread until this condition variable receives a - /// notification. - /// - /// This function will atomically unlock the mutex specified (represented by - /// `mutex_guard`) and block the current thread. This means that any calls - /// to `notify_*()` which happen logically after the mutex is unlocked are - /// candidates to wake this thread up. When this function call returns, the - /// lock specified will have been re-acquired. - /// - /// # Panics - /// - /// This function will panic if another thread is waiting on the `Condvar` - /// with a different `Mutex` object. - #[inline] - pub fn wait(&self, mutex_guard: &mut MutexGuard<'_, T>) { - self.wait_until_internal(unsafe { MutexGuard::mutex(mutex_guard).raw() }, None); - } - - /// Waits on this condition variable for a notification, timing out after - /// the specified time instant. - /// - /// The semantics of this function are equivalent to `wait()` except that - /// the thread will be blocked roughly until `timeout` is reached. This - /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum - /// amount of time waited to be precisely `timeout`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. - /// - /// The returned `WaitTimeoutResult` value indicates if the timeout is - /// known to have elapsed. - /// - /// Like `wait`, the lock specified will be re-acquired when this function - /// returns, regardless of whether the timeout elapsed or not. - /// - /// # Panics - /// - /// This function will panic if another thread is waiting on the `Condvar` - /// with a different `Mutex` object. - #[inline] - pub fn wait_until( - &self, - mutex_guard: &mut MutexGuard<'_, T>, - timeout: Instant, - ) -> WaitTimeoutResult { - self.wait_until_internal( - unsafe { MutexGuard::mutex(mutex_guard).raw() }, - Some(timeout), - ) - } - - // This is a non-generic function to reduce the monomorphization cost of - // using `wait_until`. - fn wait_until_internal(&self, mutex: &RawMutex, timeout: Option) -> WaitTimeoutResult { - unsafe { - let result; - let mut bad_mutex = false; - let mut requeued = false; - { - let addr = self as *const _ as usize; - let lock_addr = mutex as *const _ as *mut _; - let validate = || { - // Ensure we don't use two different mutexes with the same - // Condvar at the same time. This is done while locked to - // avoid races with notify_one - let state = self.state.load(Ordering::Relaxed); - if state.is_null() { - self.state.store(lock_addr, Ordering::Relaxed); - } else if state != lock_addr { - bad_mutex = true; - return false; - } - true - }; - let before_sleep = || { - // Unlock the mutex before sleeping... - mutex.unlock(); - }; - let timed_out = |k, was_last_thread| { - // If we were requeued to a mutex, then we did not time out. - // We'll just park ourselves on the mutex again when we try - // to lock it later. - requeued = k != addr; - - // If we were the last thread on the queue then we need to - // clear our state. This is normally done by the - // notify_{one,all} functions when not timing out. - if !requeued && was_last_thread { - self.state.store(ptr::null_mut(), Ordering::Relaxed); - } - }; - result = parking_lot_core::park( - addr, - validate, - before_sleep, - timed_out, - DEFAULT_PARK_TOKEN, - timeout, - ); - } - - // Panic if we tried to use multiple mutexes with a Condvar. Note - // that at this point the MutexGuard is still locked. It will be - // unlocked by the unwinding logic. - if bad_mutex { - panic!("attempted to use a condition variable with more than one mutex"); - } - - // ... and re-lock it once we are done sleeping - if result == ParkResult::Unparked(TOKEN_HANDOFF) { - deadlock::acquire_resource(mutex as *const _ as usize); - } else { - mutex.lock(); - } - - WaitTimeoutResult(!(result.is_unparked() || requeued)) - } - } - - /// Waits on this condition variable for a notification, timing out after a - /// specified duration. - /// - /// The semantics of this function are equivalent to `wait()` except that - /// the thread will be blocked for roughly no longer than `timeout`. This - /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum - /// amount of time waited to be precisely `timeout`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. - /// - /// The returned `WaitTimeoutResult` value indicates if the timeout is - /// known to have elapsed. - /// - /// Like `wait`, the lock specified will be re-acquired when this function - /// returns, regardless of whether the timeout elapsed or not. - /// - /// # Panics - /// - /// Panics if the given `timeout` is so large that it can't be added to the current time. - /// This panic is not possible if the crate is built with the `nightly` feature, then a too - /// large `timeout` becomes equivalent to just calling `wait`. - #[inline] - pub fn wait_for( - &self, - mutex_guard: &mut MutexGuard<'_, T>, - timeout: Duration, - ) -> WaitTimeoutResult { - let deadline = util::to_deadline(timeout); - self.wait_until_internal(unsafe { MutexGuard::mutex(mutex_guard).raw() }, deadline) - } -} - -impl Default for Condvar { - #[inline] - fn default() -> Condvar { - Condvar::new() - } -} - -impl fmt::Debug for Condvar { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Condvar { .. }") - } -} - -#[cfg(test)] -mod tests { - use crate::{Condvar, Mutex, MutexGuard}; - use std::sync::mpsc::channel; - use std::sync::Arc; - use std::thread; - use std::time::{Duration, Instant}; - - #[test] - fn smoke() { - let c = Condvar::new(); - c.notify_one(); - c.notify_all(); - } - - #[test] - fn notify_one() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let _t = thread::spawn(move || { - let _g = m2.lock(); - c2.notify_one(); - }); - c.wait(&mut g); - } - - #[test] - fn notify_all() { - const N: usize = 10; - - let data = Arc::new((Mutex::new(0), Condvar::new())); - let (tx, rx) = channel(); - for _ in 0..N { - let data = data.clone(); - let tx = tx.clone(); - thread::spawn(move || { - let &(ref lock, ref cond) = &*data; - let mut cnt = lock.lock(); - *cnt += 1; - if *cnt == N { - tx.send(()).unwrap(); - } - while *cnt != 0 { - cond.wait(&mut cnt); - } - tx.send(()).unwrap(); - }); - } - drop(tx); - - let &(ref lock, ref cond) = &*data; - rx.recv().unwrap(); - let mut cnt = lock.lock(); - *cnt = 0; - cond.notify_all(); - drop(cnt); - - for _ in 0..N { - rx.recv().unwrap(); - } - } - - #[test] - fn notify_one_return_true() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let _t = thread::spawn(move || { - let _g = m2.lock(); - assert!(c2.notify_one()); - }); - c.wait(&mut g); - } - - #[test] - fn notify_one_return_false() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - let _t = thread::spawn(move || { - let _g = m.lock(); - assert!(!c.notify_one()); - }); - } - - #[test] - fn notify_all_return() { - const N: usize = 10; - - let data = Arc::new((Mutex::new(0), Condvar::new())); - let (tx, rx) = channel(); - for _ in 0..N { - let data = data.clone(); - let tx = tx.clone(); - thread::spawn(move || { - let &(ref lock, ref cond) = &*data; - let mut cnt = lock.lock(); - *cnt += 1; - if *cnt == N { - tx.send(()).unwrap(); - } - while *cnt != 0 { - cond.wait(&mut cnt); - } - tx.send(()).unwrap(); - }); - } - drop(tx); - - let &(ref lock, ref cond) = &*data; - rx.recv().unwrap(); - let mut cnt = lock.lock(); - *cnt = 0; - assert_eq!(cond.notify_all(), N); - drop(cnt); - - for _ in 0..N { - rx.recv().unwrap(); - } - - assert_eq!(cond.notify_all(), 0); - } - - #[test] - fn wait_for() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let no_timeout = c.wait_for(&mut g, Duration::from_millis(1)); - assert!(no_timeout.timed_out()); - - let _t = thread::spawn(move || { - let _g = m2.lock(); - c2.notify_one(); - }); - // Non-nightly panics on too large timeouts. Nightly treats it as indefinite wait. - let very_long_timeout = if cfg!(feature = "nightly") { - Duration::from_secs(u64::max_value()) - } else { - Duration::from_millis(u32::max_value() as u64) - }; - - let timeout_res = c.wait_for(&mut g, very_long_timeout); - assert!(!timeout_res.timed_out()); - - drop(g); - } - - #[test] - fn wait_until() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let no_timeout = c.wait_until(&mut g, Instant::now() + Duration::from_millis(1)); - assert!(no_timeout.timed_out()); - let _t = thread::spawn(move || { - let _g = m2.lock(); - c2.notify_one(); - }); - let timeout_res = c.wait_until( - &mut g, - Instant::now() + Duration::from_millis(u32::max_value() as u64), - ); - assert!(!timeout_res.timed_out()); - drop(g); - } - - #[test] - #[should_panic] - fn two_mutexes() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let m3 = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - // Make sure we don't leave the child thread dangling - struct PanicGuard<'a>(&'a Condvar); - impl<'a> Drop for PanicGuard<'a> { - fn drop(&mut self) { - self.0.notify_one(); - } - } - - let (tx, rx) = channel(); - let g = m.lock(); - let _t = thread::spawn(move || { - let mut g = m2.lock(); - tx.send(()).unwrap(); - c2.wait(&mut g); - }); - drop(g); - rx.recv().unwrap(); - let _g = m.lock(); - let _guard = PanicGuard(&*c); - c.wait(&mut m3.lock()); - } - - #[test] - fn two_mutexes_disjoint() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let m3 = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let _t = thread::spawn(move || { - let _g = m2.lock(); - c2.notify_one(); - }); - c.wait(&mut g); - drop(g); - - let _ = c.wait_for(&mut m3.lock(), Duration::from_millis(1)); - } - - #[test] - fn test_debug_condvar() { - let c = Condvar::new(); - assert_eq!(format!("{:?}", c), "Condvar { .. }"); - } - - #[test] - fn test_condvar_requeue() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - let t = thread::spawn(move || { - let mut g = m2.lock(); - c2.wait(&mut g); - }); - - let mut g = m.lock(); - while !c.notify_one() { - // Wait for the thread to get into wait() - MutexGuard::bump(&mut g); - } - // The thread should have been requeued to the mutex, which we wake up now. - drop(g); - t.join().unwrap(); - } - - #[test] - fn test_issue_129() { - let locks = Arc::new((Mutex::new(()), Condvar::new())); - - let (tx, rx) = channel(); - for _ in 0..4 { - let locks = locks.clone(); - let tx = tx.clone(); - thread::spawn(move || { - let mut guard = locks.0.lock(); - locks.1.wait(&mut guard); - locks.1.wait_for(&mut guard, Duration::from_millis(1)); - locks.1.notify_one(); - tx.send(()).unwrap(); - }); - } - - thread::sleep(Duration::from_millis(100)); - locks.1.notify_one(); - - for _ in 0..4 { - assert_eq!(rx.recv_timeout(Duration::from_millis(500)), Ok(())); - } - } -} - -/// This module contains an integration test that is heavily inspired from WebKit's own integration -/// tests for it's own Condvar. -#[cfg(test)] -mod webkit_queue_test { - use crate::{Condvar, Mutex, MutexGuard}; - use std::{collections::VecDeque, sync::Arc, thread, time::Duration}; - - #[derive(Clone, Copy)] - enum Timeout { - Bounded(Duration), - Forever, - } - - #[derive(Clone, Copy)] - enum NotifyStyle { - One, - All, - } - - struct Queue { - items: VecDeque, - should_continue: bool, - } - - impl Queue { - fn new() -> Self { - Self { - items: VecDeque::new(), - should_continue: true, - } - } - } - - fn wait( - condition: &Condvar, - lock: &mut MutexGuard<'_, T>, - predicate: impl Fn(&mut MutexGuard<'_, T>) -> bool, - timeout: &Timeout, - ) { - while !predicate(lock) { - match timeout { - Timeout::Forever => condition.wait(lock), - Timeout::Bounded(bound) => { - condition.wait_for(lock, *bound); - } - } - } - } - - fn notify(style: NotifyStyle, condition: &Condvar, should_notify: bool) { - match style { - NotifyStyle::One => { - condition.notify_one(); - } - NotifyStyle::All => { - if should_notify { - condition.notify_all(); - } - } - } - } - - fn run_queue_test( - num_producers: usize, - num_consumers: usize, - max_queue_size: usize, - messages_per_producer: usize, - notify_style: NotifyStyle, - timeout: Timeout, - delay: Duration, - ) { - let input_queue = Arc::new(Mutex::new(Queue::new())); - let empty_condition = Arc::new(Condvar::new()); - let full_condition = Arc::new(Condvar::new()); - - let output_vec = Arc::new(Mutex::new(vec![])); - - let consumers = (0..num_consumers) - .map(|_| { - consumer_thread( - input_queue.clone(), - empty_condition.clone(), - full_condition.clone(), - timeout, - notify_style, - output_vec.clone(), - max_queue_size, - ) - }) - .collect::>(); - let producers = (0..num_producers) - .map(|_| { - producer_thread( - messages_per_producer, - input_queue.clone(), - empty_condition.clone(), - full_condition.clone(), - timeout, - notify_style, - max_queue_size, - ) - }) - .collect::>(); - - thread::sleep(delay); - - for producer in producers.into_iter() { - producer.join().expect("Producer thread panicked"); - } - - { - let mut input_queue = input_queue.lock(); - input_queue.should_continue = false; - } - empty_condition.notify_all(); - - for consumer in consumers.into_iter() { - consumer.join().expect("Consumer thread panicked"); - } - - let mut output_vec = output_vec.lock(); - assert_eq!(output_vec.len(), num_producers * messages_per_producer); - output_vec.sort(); - for msg_idx in 0..messages_per_producer { - for producer_idx in 0..num_producers { - assert_eq!(msg_idx, output_vec[msg_idx * num_producers + producer_idx]); - } - } - } - - fn consumer_thread( - input_queue: Arc>, - empty_condition: Arc, - full_condition: Arc, - timeout: Timeout, - notify_style: NotifyStyle, - output_queue: Arc>>, - max_queue_size: usize, - ) -> thread::JoinHandle<()> { - thread::spawn(move || loop { - let (should_notify, result) = { - let mut queue = input_queue.lock(); - wait( - &*empty_condition, - &mut queue, - |state| -> bool { !state.items.is_empty() || !state.should_continue }, - &timeout, - ); - if queue.items.is_empty() && !queue.should_continue { - return; - } - let should_notify = queue.items.len() == max_queue_size; - let result = queue.items.pop_front(); - std::mem::drop(queue); - (should_notify, result) - }; - notify(notify_style, &*full_condition, should_notify); - - if let Some(result) = result { - output_queue.lock().push(result); - } - }) - } - - fn producer_thread( - num_messages: usize, - queue: Arc>, - empty_condition: Arc, - full_condition: Arc, - timeout: Timeout, - notify_style: NotifyStyle, - max_queue_size: usize, - ) -> thread::JoinHandle<()> { - thread::spawn(move || { - for message in 0..num_messages { - let should_notify = { - let mut queue = queue.lock(); - wait( - &*full_condition, - &mut queue, - |state| state.items.len() < max_queue_size, - &timeout, - ); - let should_notify = queue.items.is_empty(); - queue.items.push_back(message); - std::mem::drop(queue); - should_notify - }; - notify(notify_style, &*empty_condition, should_notify); - } - }) - } - - macro_rules! run_queue_tests { - ( $( $name:ident( - num_producers: $num_producers:expr, - num_consumers: $num_consumers:expr, - max_queue_size: $max_queue_size:expr, - messages_per_producer: $messages_per_producer:expr, - notification_style: $notification_style:expr, - timeout: $timeout:expr, - delay_seconds: $delay_seconds:expr); - )* ) => { - $(#[test] - fn $name() { - let delay = Duration::from_secs($delay_seconds); - run_queue_test( - $num_producers, - $num_consumers, - $max_queue_size, - $messages_per_producer, - $notification_style, - $timeout, - delay, - ); - })* - }; - } - - run_queue_tests! { - sanity_check_queue( - num_producers: 1, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Bounded(Duration::from_secs(1)), - delay_seconds: 0 - ); - sanity_check_queue_timeout( - num_producers: 1, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - new_test_without_timeout_5( - num_producers: 1, - num_consumers: 5, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_one_consumer_one_slot( - num_producers: 1, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_one_consumer_one_slot_timeout( - num_producers: 1, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 1 - ); - one_producer_one_consumer_hundred_slots( - num_producers: 1, - num_consumers: 1, - max_queue_size: 100, - messages_per_producer: 1_000_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_one_consumer_one_slot( - num_producers: 10, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 10000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_one_consumer_hundred_slots_notify_all( - num_producers: 10, - num_consumers: 1, - max_queue_size: 100, - messages_per_producer: 10000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_one_consumer_hundred_slots_notify_one( - num_producers: 10, - num_consumers: 1, - max_queue_size: 100, - messages_per_producer: 10000, - notification_style: NotifyStyle::One, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_ten_consumers_one_slot( - num_producers: 1, - num_consumers: 10, - max_queue_size: 1, - messages_per_producer: 10000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_ten_consumers_hundred_slots_notify_all( - num_producers: 1, - num_consumers: 10, - max_queue_size: 100, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_ten_consumers_hundred_slots_notify_one( - num_producers: 1, - num_consumers: 10, - max_queue_size: 100, - messages_per_producer: 100_000, - notification_style: NotifyStyle::One, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_ten_consumers_one_slot( - num_producers: 10, - num_consumers: 10, - max_queue_size: 1, - messages_per_producer: 50000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_ten_consumers_hundred_slots_notify_all( - num_producers: 10, - num_consumers: 10, - max_queue_size: 100, - messages_per_producer: 50000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_ten_consumers_hundred_slots_notify_one( - num_producers: 10, - num_consumers: 10, - max_queue_size: 100, - messages_per_producer: 50000, - notification_style: NotifyStyle::One, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - } -} diff --git a/vendor/parking_lot-0.10.2/src/deadlock.rs b/vendor/parking_lot-0.10.2/src/deadlock.rs deleted file mode 100644 index 0fab7228c9..0000000000 --- a/vendor/parking_lot-0.10.2/src/deadlock.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! \[Experimental\] Deadlock detection -//! -//! This feature is optional and can be enabled via the `deadlock_detection` feature flag. -//! -//! # Example -//! -//! ``` -//! #[cfg(feature = "deadlock_detection")] -//! { // only for #[cfg] -//! use std::thread; -//! use std::time::Duration; -//! use parking_lot::deadlock; -//! -//! // Create a background thread which checks for deadlocks every 10s -//! thread::spawn(move || { -//! loop { -//! thread::sleep(Duration::from_secs(10)); -//! let deadlocks = deadlock::check_deadlock(); -//! if deadlocks.is_empty() { -//! continue; -//! } -//! -//! println!("{} deadlocks detected", deadlocks.len()); -//! for (i, threads) in deadlocks.iter().enumerate() { -//! println!("Deadlock #{}", i); -//! for t in threads { -//! println!("Thread Id {:#?}", t.thread_id()); -//! println!("{:#?}", t.backtrace()); -//! } -//! } -//! } -//! }); -//! } // only for #[cfg] -//! ``` - -#[cfg(feature = "deadlock_detection")] -pub use parking_lot_core::deadlock::check_deadlock; -pub(crate) use parking_lot_core::deadlock::{acquire_resource, release_resource}; - -#[cfg(test)] -#[cfg(feature = "deadlock_detection")] -mod tests { - use crate::{Mutex, ReentrantMutex, RwLock}; - use std::sync::{Arc, Barrier}; - use std::thread::{self, sleep}; - use std::time::Duration; - - // We need to serialize these tests since deadlock detection uses global state - static DEADLOCK_DETECTION_LOCK: Mutex<()> = crate::const_mutex(()); - - fn check_deadlock() -> bool { - use parking_lot_core::deadlock::check_deadlock; - !check_deadlock().is_empty() - } - - #[test] - fn test_mutex_deadlock() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - let m2: Arc> = Default::default(); - let m3: Arc> = Default::default(); - let b = Arc::new(Barrier::new(4)); - - let m1_ = m1.clone(); - let m2_ = m2.clone(); - let m3_ = m3.clone(); - let b1 = b.clone(); - let b2 = b.clone(); - let b3 = b.clone(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.lock(); - b1.wait(); - let _ = m2_.lock(); - }); - - let _t2 = thread::spawn(move || { - let _g = m2.lock(); - b2.wait(); - let _ = m3_.lock(); - }); - - let _t3 = thread::spawn(move || { - let _g = m3.lock(); - b3.wait(); - let _ = m1_.lock(); - }); - - assert!(!check_deadlock()); - - b.wait(); - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } - - #[test] - fn test_mutex_deadlock_reentrant() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.lock(); - let _ = m1.lock(); - }); - - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } - - #[test] - fn test_remutex_deadlock() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - let m2: Arc> = Default::default(); - let m3: Arc> = Default::default(); - let b = Arc::new(Barrier::new(4)); - - let m1_ = m1.clone(); - let m2_ = m2.clone(); - let m3_ = m3.clone(); - let b1 = b.clone(); - let b2 = b.clone(); - let b3 = b.clone(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.lock(); - let _g = m1.lock(); - b1.wait(); - let _ = m2_.lock(); - }); - - let _t2 = thread::spawn(move || { - let _g = m2.lock(); - let _g = m2.lock(); - b2.wait(); - let _ = m3_.lock(); - }); - - let _t3 = thread::spawn(move || { - let _g = m3.lock(); - let _g = m3.lock(); - b3.wait(); - let _ = m1_.lock(); - }); - - assert!(!check_deadlock()); - - b.wait(); - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } - - #[test] - fn test_rwlock_deadlock() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - let m2: Arc> = Default::default(); - let m3: Arc> = Default::default(); - let b = Arc::new(Barrier::new(4)); - - let m1_ = m1.clone(); - let m2_ = m2.clone(); - let m3_ = m3.clone(); - let b1 = b.clone(); - let b2 = b.clone(); - let b3 = b.clone(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.read(); - b1.wait(); - let _g = m2_.write(); - }); - - let _t2 = thread::spawn(move || { - let _g = m2.read(); - b2.wait(); - let _g = m3_.write(); - }); - - let _t3 = thread::spawn(move || { - let _g = m3.read(); - b3.wait(); - let _ = m1_.write(); - }); - - assert!(!check_deadlock()); - - b.wait(); - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } - - #[cfg(rwlock_deadlock_detection_not_supported)] - #[test] - fn test_rwlock_deadlock_reentrant() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.read(); - let _ = m1.write(); - }); - - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } -} diff --git a/vendor/parking_lot-0.10.2/src/elision.rs b/vendor/parking_lot-0.10.2/src/elision.rs deleted file mode 100644 index 68cfa63c3e..0000000000 --- a/vendor/parking_lot-0.10.2/src/elision.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use std::sync::atomic::AtomicUsize; - -// Extension trait to add lock elision primitives to atomic types -pub trait AtomicElisionExt { - type IntType; - - // Perform a compare_exchange and start a transaction - fn elision_compare_exchange_acquire( - &self, - current: Self::IntType, - new: Self::IntType, - ) -> Result; - - // Perform a fetch_sub and end a transaction - fn elision_fetch_sub_release(&self, val: Self::IntType) -> Self::IntType; -} - -// Indicates whether the target architecture supports lock elision -#[inline] -pub fn have_elision() -> bool { - cfg!(all( - feature = "nightly", - any(target_arch = "x86", target_arch = "x86_64"), - )) -} - -// This implementation is never actually called because it is guarded by -// have_elision(). -#[cfg(not(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64"))))] -impl AtomicElisionExt for AtomicUsize { - type IntType = usize; - - #[inline] - fn elision_compare_exchange_acquire(&self, _: usize, _: usize) -> Result { - unreachable!(); - } - - #[inline] - fn elision_fetch_sub_release(&self, _: usize) -> usize { - unreachable!(); - } -} - -#[cfg(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64")))] -impl AtomicElisionExt for AtomicUsize { - type IntType = usize; - - #[cfg(target_pointer_width = "32")] - #[inline] - fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result { - unsafe { - let prev: usize; - llvm_asm!("xacquire; lock; cmpxchgl $2, $1" - : "={eax}" (prev), "+*m" (self) - : "r" (new), "{eax}" (current) - : "memory" - : "volatile"); - if prev == current { - Ok(prev) - } else { - Err(prev) - } - } - } - #[cfg(target_pointer_width = "64")] - #[inline] - fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result { - unsafe { - let prev: usize; - llvm_asm!("xacquire; lock; cmpxchgq $2, $1" - : "={rax}" (prev), "+*m" (self) - : "r" (new), "{rax}" (current) - : "memory" - : "volatile"); - if prev == current { - Ok(prev) - } else { - Err(prev) - } - } - } - - #[cfg(target_pointer_width = "32")] - #[inline] - fn elision_fetch_sub_release(&self, val: usize) -> usize { - unsafe { - let prev: usize; - llvm_asm!("xrelease; lock; xaddl $2, $1" - : "=r" (prev), "+*m" (self) - : "0" (val.wrapping_neg()) - : "memory" - : "volatile"); - prev - } - } - #[cfg(target_pointer_width = "64")] - #[inline] - fn elision_fetch_sub_release(&self, val: usize) -> usize { - unsafe { - let prev: usize; - llvm_asm!("xrelease; lock; xaddq $2, $1" - : "=r" (prev), "+*m" (self) - : "0" (val.wrapping_neg()) - : "memory" - : "volatile"); - prev - } - } -} diff --git a/vendor/parking_lot-0.10.2/src/fair_mutex.rs b/vendor/parking_lot-0.10.2/src/fair_mutex.rs deleted file mode 100644 index 449c53b051..0000000000 --- a/vendor/parking_lot-0.10.2/src/fair_mutex.rs +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::raw_fair_mutex::RawFairMutex; -use lock_api; - -/// A mutual exclusive primitive that is always fair, useful for protecting shared data -/// -/// This mutex will block threads waiting for the lock to become available. The -/// mutex can also be statically initialized or created via a `new` -/// constructor. Each mutex has a type parameter which represents the data that -/// it is protecting. The data can only be accessed through the RAII guards -/// returned from `lock` and `try_lock`, which guarantees that the data is only -/// ever accessed when the mutex is locked. -/// -/// The regular mutex provided by `parking_lot` uses eventual locking fairness -/// (after some time it will default to the fair algorithm), but eventual -/// fairness does not provide the same garantees a always fair method would. -/// Fair mutexes are generally slower, but sometimes needed. This wrapper was -/// created to avoid using a unfair protocol when it's forbidden by mistake. -/// -/// In a fair mutex the lock is provided to whichever thread asked first, -/// they form a queue and always follow the first-in first-out order. This -/// means some thread in the queue won't be able to steal the lock and use it fast -/// to increase throughput, at the cost of latency. Since the response time will grow -/// for some threads that are waiting for the lock and losing to faster but later ones, -/// but it may make sending more responses possible. -/// -/// A fair mutex may not be interesting if threads have different priorities (this is known as -/// priority inversion). -/// -/// # Differences from the standard library `Mutex` -/// -/// - No poisoning, the lock is released normally on panic. -/// - Only requires 1 byte of space, whereas the standard library boxes the -/// `FairMutex` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). -/// - Does not require any drop glue when dropped. -/// - Inline fast path for the uncontended case. -/// - Efficient handling of micro-contention using adaptive spinning. -/// - Allows raw locking & unlocking without a guard. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::FairMutex; -/// use std::sync::{Arc, mpsc::channel}; -/// use std::thread; -/// -/// const N: usize = 10; -/// -/// // Spawn a few threads to increment a shared variable (non-atomically), and -/// // let the main thread know once all increments are done. -/// // -/// // Here we're using an Arc to share memory among threads, and the data inside -/// // the Arc is protected with a mutex. -/// let data = Arc::new(FairMutex::new(0)); -/// -/// let (tx, rx) = channel(); -/// for _ in 0..10 { -/// let (data, tx) = (Arc::clone(&data), tx.clone()); -/// thread::spawn(move || { -/// // The shared state can only be accessed once the lock is held. -/// // Our non-atomic increment is safe because we're the only thread -/// // which can access the shared state when the lock is held. -/// let mut data = data.lock(); -/// *data += 1; -/// if *data == N { -/// tx.send(()).unwrap(); -/// } -/// // the lock is unlocked here when `data` goes out of scope. -/// }); -/// } -/// -/// rx.recv().unwrap(); -/// ``` -pub type FairMutex = lock_api::Mutex; - -/// Creates a new fair mutex in an unlocked state ready for use. -/// -/// This allows creating a fair mutex in a constant context on stable Rust. -pub const fn const_fair_mutex(val: T) -> FairMutex { - FairMutex::const_new(::INIT, val) -} - -/// An RAII implementation of a "scoped lock" of a mutex. When this structure is -/// dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// `Deref` and `DerefMut` implementations. -pub type FairMutexGuard<'a, T> = lock_api::MutexGuard<'a, RawFairMutex, T>; - -/// An RAII mutex guard returned by `FairMutexGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedFairMutexGuard` and `FairMutexGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedFairMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawFairMutex, T>; - -#[cfg(test)] -mod tests { - use crate::FairMutex; - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::sync::mpsc::channel; - use std::sync::Arc; - use std::thread; - - #[cfg(feature = "serde")] - use bincode::{deserialize, serialize}; - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let m = FairMutex::new(()); - drop(m.lock()); - drop(m.lock()); - } - - #[test] - fn lots_and_lots() { - const J: u32 = 1000; - const K: u32 = 3; - - let m = Arc::new(FairMutex::new(0)); - - fn inc(m: &FairMutex) { - for _ in 0..J { - *m.lock() += 1; - } - } - - let (tx, rx) = channel(); - for _ in 0..K { - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - } - - drop(tx); - for _ in 0..2 * K { - rx.recv().unwrap(); - } - assert_eq!(*m.lock(), J * K * 2); - } - - #[test] - fn try_lock() { - let m = FairMutex::new(()); - *m.try_lock().unwrap() = (); - } - - #[test] - fn test_into_inner() { - let m = FairMutex::new(NonCopy(10)); - assert_eq!(m.into_inner(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = FairMutex::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_get_mut() { - let mut m = FairMutex::new(NonCopy(10)); - *m.get_mut() = NonCopy(20); - assert_eq!(m.into_inner(), NonCopy(20)); - } - - #[test] - fn test_mutex_arc_nested() { - // Tests nested mutexes and access - // to underlying data. - let arc = Arc::new(FairMutex::new(1)); - let arc2 = Arc::new(FairMutex::new(arc)); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let lock = arc2.lock(); - let lock2 = lock.lock(); - assert_eq!(*lock2, 1); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_mutex_arc_access_in_unwind() { - let arc = Arc::new(FairMutex::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - *self.i.lock() += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.lock(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_mutex_unsized() { - let mutex: &FairMutex<[i32]> = &FairMutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock(), comp); - } - - #[test] - fn test_mutexguard_sync() { - fn sync(_: T) {} - - let mutex = FairMutex::new(()); - sync(mutex.lock()); - } - - #[test] - fn test_mutex_debug() { - let mutex = FairMutex::new(vec![0u8, 10]); - - assert_eq!(format!("{:?}", mutex), "Mutex { data: [0, 10] }"); - let _lock = mutex.lock(); - assert_eq!(format!("{:?}", mutex), "Mutex { data: }"); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serde() { - let contents: Vec = vec![0, 1, 2]; - let mutex = FairMutex::new(contents.clone()); - - let serialized = serialize(&mutex).unwrap(); - let deserialized: FairMutex> = deserialize(&serialized).unwrap(); - - assert_eq!(*(mutex.lock()), *(deserialized.lock())); - assert_eq!(contents, *(deserialized.lock())); - } -} diff --git a/vendor/parking_lot-0.10.2/src/lib.rs b/vendor/parking_lot-0.10.2/src/lib.rs deleted file mode 100644 index 73246c2e76..0000000000 --- a/vendor/parking_lot-0.10.2/src/lib.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -//! This library provides implementations of `Mutex`, `RwLock`, `Condvar` and -//! `Once` that are smaller, faster and more flexible than those in the Rust -//! standard library. It also provides a `ReentrantMutex` type. - -#![warn(missing_docs)] -#![warn(rust_2018_idioms)] -#![cfg_attr(feature = "nightly", feature(llvm_asm))] - -mod condvar; -mod elision; -mod fair_mutex; -mod mutex; -mod once; -mod raw_fair_mutex; -mod raw_mutex; -mod raw_rwlock; -mod remutex; -mod rwlock; -mod util; - -#[cfg(feature = "deadlock_detection")] -pub mod deadlock; -#[cfg(not(feature = "deadlock_detection"))] -mod deadlock; - -pub use self::condvar::{Condvar, WaitTimeoutResult}; -pub use self::fair_mutex::{const_fair_mutex, FairMutex, FairMutexGuard, MappedFairMutexGuard}; -pub use self::mutex::{const_mutex, MappedMutexGuard, Mutex, MutexGuard}; -pub use self::once::{Once, OnceState}; -pub use self::raw_fair_mutex::RawFairMutex; -pub use self::raw_mutex::RawMutex; -pub use self::raw_rwlock::RawRwLock; -pub use self::remutex::{ - const_reentrant_mutex, MappedReentrantMutexGuard, RawThreadId, ReentrantMutex, - ReentrantMutexGuard, -}; -pub use self::rwlock::{ - const_rwlock, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, - RwLockUpgradableReadGuard, RwLockWriteGuard, -}; -pub use ::lock_api; diff --git a/vendor/parking_lot-0.10.2/src/mutex.rs b/vendor/parking_lot-0.10.2/src/mutex.rs deleted file mode 100644 index 36e5ea7ec5..0000000000 --- a/vendor/parking_lot-0.10.2/src/mutex.rs +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::raw_mutex::RawMutex; -use lock_api; - -/// A mutual exclusion primitive useful for protecting shared data -/// -/// This mutex will block threads waiting for the lock to become available. The -/// mutex can also be statically initialized or created via a `new` -/// constructor. Each mutex has a type parameter which represents the data that -/// it is protecting. The data can only be accessed through the RAII guards -/// returned from `lock` and `try_lock`, which guarantees that the data is only -/// ever accessed when the mutex is locked. -/// -/// # Fairness -/// -/// A typical unfair lock can often end up in a situation where a single thread -/// quickly acquires and releases the same mutex in succession, which can starve -/// other threads waiting to acquire the mutex. While this improves performance -/// because it doesn't force a context switch when a thread tries to re-acquire -/// a mutex it has just released, this can starve other threads. -/// -/// This mutex uses [eventual fairness](https://trac.webkit.org/changeset/203350) -/// to ensure that the lock will be fair on average without sacrificing -/// performance. This is done by forcing a fair unlock on average every 0.5ms, -/// which will force the lock to go to the next thread waiting for the mutex. -/// -/// Additionally, any critical section longer than 1ms will always use a fair -/// unlock, which has a negligible performance impact compared to the length of -/// the critical section. -/// -/// You can also force a fair unlock by calling `MutexGuard::unlock_fair` when -/// unlocking a mutex instead of simply dropping the `MutexGuard`. -/// -/// # Differences from the standard library `Mutex` -/// -/// - No poisoning, the lock is released normally on panic. -/// - Only requires 1 byte of space, whereas the standard library boxes the -/// `Mutex` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). -/// - Does not require any drop glue when dropped. -/// - Inline fast path for the uncontended case. -/// - Efficient handling of micro-contention using adaptive spinning. -/// - Allows raw locking & unlocking without a guard. -/// - Supports eventual fairness so that the mutex is fair on average. -/// - Optionally allows making the mutex fair by calling `MutexGuard::unlock_fair`. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::Mutex; -/// use std::sync::{Arc, mpsc::channel}; -/// use std::thread; -/// -/// const N: usize = 10; -/// -/// // Spawn a few threads to increment a shared variable (non-atomically), and -/// // let the main thread know once all increments are done. -/// // -/// // Here we're using an Arc to share memory among threads, and the data inside -/// // the Arc is protected with a mutex. -/// let data = Arc::new(Mutex::new(0)); -/// -/// let (tx, rx) = channel(); -/// for _ in 0..10 { -/// let (data, tx) = (Arc::clone(&data), tx.clone()); -/// thread::spawn(move || { -/// // The shared state can only be accessed once the lock is held. -/// // Our non-atomic increment is safe because we're the only thread -/// // which can access the shared state when the lock is held. -/// let mut data = data.lock(); -/// *data += 1; -/// if *data == N { -/// tx.send(()).unwrap(); -/// } -/// // the lock is unlocked here when `data` goes out of scope. -/// }); -/// } -/// -/// rx.recv().unwrap(); -/// ``` -pub type Mutex = lock_api::Mutex; - -/// Creates a new mutex in an unlocked state ready for use. -/// -/// This allows creating a mutex in a constant context on stable Rust. -pub const fn const_mutex(val: T) -> Mutex { - Mutex::const_new(::INIT, val) -} - -/// An RAII implementation of a "scoped lock" of a mutex. When this structure is -/// dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// `Deref` and `DerefMut` implementations. -pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>; - -/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedMutexGuard` and `MutexGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawMutex, T>; - -#[cfg(test)] -mod tests { - use crate::{Condvar, Mutex}; - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::sync::mpsc::channel; - use std::sync::Arc; - use std::thread; - - #[cfg(feature = "serde")] - use bincode::{deserialize, serialize}; - - struct Packet(Arc<(Mutex, Condvar)>); - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - unsafe impl Send for Packet {} - unsafe impl Sync for Packet {} - - #[test] - fn smoke() { - let m = Mutex::new(()); - drop(m.lock()); - drop(m.lock()); - } - - #[test] - fn lots_and_lots() { - const J: u32 = 1000; - const K: u32 = 3; - - let m = Arc::new(Mutex::new(0)); - - fn inc(m: &Mutex) { - for _ in 0..J { - *m.lock() += 1; - } - } - - let (tx, rx) = channel(); - for _ in 0..K { - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - } - - drop(tx); - for _ in 0..2 * K { - rx.recv().unwrap(); - } - assert_eq!(*m.lock(), J * K * 2); - } - - #[test] - fn try_lock() { - let m = Mutex::new(()); - *m.try_lock().unwrap() = (); - } - - #[test] - fn test_into_inner() { - let m = Mutex::new(NonCopy(10)); - assert_eq!(m.into_inner(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = Mutex::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_get_mut() { - let mut m = Mutex::new(NonCopy(10)); - *m.get_mut() = NonCopy(20); - assert_eq!(m.into_inner(), NonCopy(20)); - } - - #[test] - fn test_mutex_arc_condvar() { - let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - // wait until parent gets in - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let mut lock = lock.lock(); - *lock = true; - cvar.notify_one(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock(); - tx.send(()).unwrap(); - assert!(!*lock); - while !*lock { - cvar.wait(&mut lock); - } - } - - #[test] - fn test_mutex_arc_nested() { - // Tests nested mutexes and access - // to underlying data. - let arc = Arc::new(Mutex::new(1)); - let arc2 = Arc::new(Mutex::new(arc)); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let lock = arc2.lock(); - let lock2 = lock.lock(); - assert_eq!(*lock2, 1); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_mutex_arc_access_in_unwind() { - let arc = Arc::new(Mutex::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - *self.i.lock() += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.lock(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_mutex_unsized() { - let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock(), comp); - } - - #[test] - fn test_mutexguard_sync() { - fn sync(_: T) {} - - let mutex = Mutex::new(()); - sync(mutex.lock()); - } - - #[test] - fn test_mutex_debug() { - let mutex = Mutex::new(vec![0u8, 10]); - - assert_eq!(format!("{:?}", mutex), "Mutex { data: [0, 10] }"); - let _lock = mutex.lock(); - assert_eq!(format!("{:?}", mutex), "Mutex { data: }"); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serde() { - let contents: Vec = vec![0, 1, 2]; - let mutex = Mutex::new(contents.clone()); - - let serialized = serialize(&mutex).unwrap(); - let deserialized: Mutex> = deserialize(&serialized).unwrap(); - - assert_eq!(*(mutex.lock()), *(deserialized.lock())); - assert_eq!(contents, *(deserialized.lock())); - } -} diff --git a/vendor/parking_lot-0.10.2/src/once.rs b/vendor/parking_lot-0.10.2/src/once.rs deleted file mode 100644 index f458c9c04b..0000000000 --- a/vendor/parking_lot-0.10.2/src/once.rs +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::util::UncheckedOptionExt; -use core::{ - fmt, mem, - sync::atomic::{fence, AtomicU8, Ordering}, -}; -use parking_lot_core::{self, SpinWait, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN}; - -const DONE_BIT: u8 = 1; -const POISON_BIT: u8 = 2; -const LOCKED_BIT: u8 = 4; -const PARKED_BIT: u8 = 8; - -/// Current state of a `Once`. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum OnceState { - /// A closure has not been executed yet - New, - - /// A closure was executed but panicked. - Poisoned, - - /// A thread is currently executing a closure. - InProgress, - - /// A closure has completed successfully. - Done, -} - -impl OnceState { - /// Returns whether the associated `Once` has been poisoned. - /// - /// Once an initialization routine for a `Once` has panicked it will forever - /// indicate to future forced initialization routines that it is poisoned. - #[inline] - pub fn poisoned(self) -> bool { - match self { - OnceState::Poisoned => true, - _ => false, - } - } - - /// Returns whether the associated `Once` has successfully executed a - /// closure. - #[inline] - pub fn done(self) -> bool { - match self { - OnceState::Done => true, - _ => false, - } - } -} - -/// A synchronization primitive which can be used to run a one-time -/// initialization. Useful for one-time initialization for globals, FFI or -/// related functionality. -/// -/// # Differences from the standard library `Once` -/// -/// - Only requires 1 byte of space, instead of 1 word. -/// - Not required to be `'static`. -/// - Relaxed memory barriers in the fast path, which can significantly improve -/// performance on some architectures. -/// - Efficient handling of micro-contention using adaptive spinning. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::Once; -/// -/// static START: Once = Once::new(); -/// -/// START.call_once(|| { -/// // run initialization here -/// }); -/// ``` -pub struct Once(AtomicU8); - -impl Once { - /// Creates a new `Once` value. - #[inline] - pub const fn new() -> Once { - Once(AtomicU8::new(0)) - } - - /// Returns the current state of this `Once`. - #[inline] - pub fn state(&self) -> OnceState { - let state = self.0.load(Ordering::Acquire); - if state & DONE_BIT != 0 { - OnceState::Done - } else if state & LOCKED_BIT != 0 { - OnceState::InProgress - } else if state & POISON_BIT != 0 { - OnceState::Poisoned - } else { - OnceState::New - } - } - - /// Performs an initialization routine once and only once. The given closure - /// will be executed if this is the first time `call_once` has been called, - /// and otherwise the routine will *not* be invoked. - /// - /// This method will block the calling thread if another initialization - /// routine is currently running. - /// - /// When this function returns, it is guaranteed that some initialization - /// has run and completed (it may not be the closure specified). It is also - /// guaranteed that any memory writes performed by the executed closure can - /// be reliably observed by other threads at this point (there is a - /// happens-before relation between the closure and code executing after the - /// return). - /// - /// # Examples - /// - /// ``` - /// use parking_lot::Once; - /// - /// static mut VAL: usize = 0; - /// static INIT: Once = Once::new(); - /// - /// // Accessing a `static mut` is unsafe much of the time, but if we do so - /// // in a synchronized fashion (e.g. write once or read all) then we're - /// // good to go! - /// // - /// // This function will only call `expensive_computation` once, and will - /// // otherwise always return the value returned from the first invocation. - /// fn get_cached_val() -> usize { - /// unsafe { - /// INIT.call_once(|| { - /// VAL = expensive_computation(); - /// }); - /// VAL - /// } - /// } - /// - /// fn expensive_computation() -> usize { - /// // ... - /// # 2 - /// } - /// ``` - /// - /// # Panics - /// - /// The closure `f` will only be executed once if this is called - /// concurrently amongst many threads. If that closure panics, however, then - /// it will *poison* this `Once` instance, causing all future invocations of - /// `call_once` to also panic. - #[inline] - pub fn call_once(&self, f: F) - where - F: FnOnce(), - { - if self.0.load(Ordering::Acquire) == DONE_BIT { - return; - } - - let mut f = Some(f); - self.call_once_slow(false, &mut |_| unsafe { f.take().unchecked_unwrap()() }); - } - - /// Performs the same function as `call_once` except ignores poisoning. - /// - /// If this `Once` has been poisoned (some initialization panicked) then - /// this function will continue to attempt to call initialization functions - /// until one of them doesn't panic. - /// - /// The closure `f` is yielded a structure which can be used to query the - /// state of this `Once` (whether initialization has previously panicked or - /// not). - #[inline] - pub fn call_once_force(&self, f: F) - where - F: FnOnce(OnceState), - { - if self.0.load(Ordering::Acquire) == DONE_BIT { - return; - } - - let mut f = Some(f); - self.call_once_slow(true, &mut |state| unsafe { - f.take().unchecked_unwrap()(state) - }); - } - - // This is a non-generic function to reduce the monomorphization cost of - // using `call_once` (this isn't exactly a trivial or small implementation). - // - // Additionally, this is tagged with `#[cold]` as it should indeed be cold - // and it helps let LLVM know that calls to this function should be off the - // fast path. Essentially, this should help generate more straight line code - // in LLVM. - // - // Finally, this takes an `FnMut` instead of a `FnOnce` because there's - // currently no way to take an `FnOnce` and call it via virtual dispatch - // without some allocation overhead. - #[cold] - fn call_once_slow(&self, ignore_poison: bool, f: &mut dyn FnMut(OnceState)) { - let mut spinwait = SpinWait::new(); - let mut state = self.0.load(Ordering::Relaxed); - loop { - // If another thread called the closure, we're done - if state & DONE_BIT != 0 { - // An acquire fence is needed here since we didn't load the - // state with Ordering::Acquire. - fence(Ordering::Acquire); - return; - } - - // If the state has been poisoned and we aren't forcing, then panic - if state & POISON_BIT != 0 && !ignore_poison { - // Need the fence here as well for the same reason - fence(Ordering::Acquire); - panic!("Once instance has previously been poisoned"); - } - - // Grab the lock if it isn't locked, even if there is a queue on it. - // We also clear the poison bit since we are going to try running - // the closure again. - if state & LOCKED_BIT == 0 { - match self.0.compare_exchange_weak( - state, - (state | LOCKED_BIT) & !POISON_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => break, - Err(x) => state = x, - } - continue; - } - - // If there is no queue, try spinning a few times - if state & PARKED_BIT == 0 && spinwait.spin() { - state = self.0.load(Ordering::Relaxed); - continue; - } - - // Set the parked bit - if state & PARKED_BIT == 0 { - if let Err(x) = self.0.compare_exchange_weak( - state, - state | PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - state = x; - continue; - } - } - - // Park our thread until we are woken up by the thread that owns the - // lock. - unsafe { - let addr = self as *const _ as usize; - let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT; - let before_sleep = || {}; - let timed_out = |_, _| unreachable!(); - parking_lot_core::park( - addr, - validate, - before_sleep, - timed_out, - DEFAULT_PARK_TOKEN, - None, - ); - } - - // Loop back and check if the done bit was set - spinwait.reset(); - state = self.0.load(Ordering::Relaxed); - } - - struct PanicGuard<'a>(&'a Once); - impl<'a> Drop for PanicGuard<'a> { - fn drop(&mut self) { - // Mark the state as poisoned, unlock it and unpark all threads. - let once = self.0; - let state = once.0.swap(POISON_BIT, Ordering::Release); - if state & PARKED_BIT != 0 { - unsafe { - let addr = once as *const _ as usize; - parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN); - } - } - } - } - - // At this point we have the lock, so run the closure. Make sure we - // properly clean up if the closure panicks. - let guard = PanicGuard(self); - let once_state = if state & POISON_BIT != 0 { - OnceState::Poisoned - } else { - OnceState::New - }; - f(once_state); - mem::forget(guard); - - // Now unlock the state, set the done bit and unpark all threads - let state = self.0.swap(DONE_BIT, Ordering::Release); - if state & PARKED_BIT != 0 { - unsafe { - let addr = self as *const _ as usize; - parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN); - } - } - } -} - -impl Default for Once { - #[inline] - fn default() -> Once { - Once::new() - } -} - -impl fmt::Debug for Once { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Once") - .field("state", &self.state()) - .finish() - } -} - -#[cfg(test)] -mod tests { - use crate::Once; - use std::panic; - use std::sync::mpsc::channel; - use std::thread; - - #[test] - fn smoke_once() { - static O: Once = Once::new(); - let mut a = 0; - O.call_once(|| a += 1); - assert_eq!(a, 1); - O.call_once(|| a += 1); - assert_eq!(a, 1); - } - - #[test] - fn stampede_once() { - static O: Once = Once::new(); - static mut RUN: bool = false; - - let (tx, rx) = channel(); - for _ in 0..10 { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..4 { - thread::yield_now() - } - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - tx.send(()).unwrap(); - }); - } - - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - - for _ in 0..10 { - rx.recv().unwrap(); - } - } - - #[test] - fn poison_bad() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // poisoning propagates - let t = panic::catch_unwind(|| { - O.call_once(|| {}); - }); - assert!(t.is_err()); - - // we can subvert poisoning, however - let mut called = false; - O.call_once_force(|p| { - called = true; - assert!(p.poisoned()) - }); - assert!(called); - - // once any success happens, we stop propagating the poison - O.call_once(|| {}); - } - - #[test] - fn wait_for_force_to_finish() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // make sure someone's waiting inside the once via a force - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let t1 = thread::spawn(move || { - O.call_once_force(|p| { - assert!(p.poisoned()); - tx1.send(()).unwrap(); - rx2.recv().unwrap(); - }); - }); - - rx1.recv().unwrap(); - - // put another waiter on the once - let t2 = thread::spawn(|| { - let mut called = false; - O.call_once(|| { - called = true; - }); - assert!(!called); - }); - - tx2.send(()).unwrap(); - - assert!(t1.join().is_ok()); - assert!(t2.join().is_ok()); - } - - #[test] - fn test_once_debug() { - static O: Once = Once::new(); - - assert_eq!(format!("{:?}", O), "Once { state: New }"); - } -} diff --git a/vendor/parking_lot-0.10.2/src/raw_fair_mutex.rs b/vendor/parking_lot-0.10.2/src/raw_fair_mutex.rs deleted file mode 100644 index 3eb7ddb779..0000000000 --- a/vendor/parking_lot-0.10.2/src/raw_fair_mutex.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::raw_mutex::RawMutex; -use lock_api::RawMutexFair; - -/// Raw fair mutex type backed by the parking lot. -pub struct RawFairMutex(RawMutex); - -unsafe impl lock_api::RawMutex for RawFairMutex { - const INIT: Self = RawFairMutex(::INIT); - - type GuardMarker = ::GuardMarker; - - #[inline] - fn lock(&self) { - self.0.lock() - } - - #[inline] - fn try_lock(&self) -> bool { - self.0.try_lock() - } - - #[inline] - fn unlock(&self) { - self.unlock_fair() - } -} - -unsafe impl lock_api::RawMutexFair for RawFairMutex { - #[inline] - fn unlock_fair(&self) { - self.0.unlock_fair() - } - - #[inline] - fn bump(&self) { - self.0.bump() - } -} - -unsafe impl lock_api::RawMutexTimed for RawFairMutex { - type Duration = ::Duration; - type Instant = ::Instant; - - #[inline] - fn try_lock_until(&self, timeout: Self::Instant) -> bool { - self.0.try_lock_until(timeout) - } - - #[inline] - fn try_lock_for(&self, timeout: Self::Duration) -> bool { - self.0.try_lock_for(timeout) - } -} diff --git a/vendor/parking_lot-0.10.2/src/raw_mutex.rs b/vendor/parking_lot-0.10.2/src/raw_mutex.rs deleted file mode 100644 index ee39c3bd96..0000000000 --- a/vendor/parking_lot-0.10.2/src/raw_mutex.rs +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::{deadlock, util}; -use core::{ - sync::atomic::{AtomicU8, Ordering}, - time::Duration, -}; -use lock_api::{GuardNoSend, RawMutex as RawMutex_}; -use parking_lot_core::{self, ParkResult, SpinWait, UnparkResult, UnparkToken, DEFAULT_PARK_TOKEN}; -use std::time::Instant; - -// UnparkToken used to indicate that that the target thread should attempt to -// lock the mutex again as soon as it is unparked. -pub(crate) const TOKEN_NORMAL: UnparkToken = UnparkToken(0); - -// UnparkToken used to indicate that the mutex is being handed off to the target -// thread directly without unlocking it. -pub(crate) const TOKEN_HANDOFF: UnparkToken = UnparkToken(1); - -/// This bit is set in the `state` of a `RawMutex` when that mutex is locked by some thread. -const LOCKED_BIT: u8 = 0b01; -/// This bit is set in the `state` of a `RawMutex` just before parking a thread. A thread is being -/// parked if it wants to lock the mutex, but it is currently being held by some other thread. -const PARKED_BIT: u8 = 0b10; - -/// Raw mutex type backed by the parking lot. -pub struct RawMutex { - /// This atomic integer holds the current state of the mutex instance. Only the two lowest bits - /// are used. See `LOCKED_BIT` and `PARKED_BIT` for the bitmask for these bits. - /// - /// # State table: - /// - /// PARKED_BIT | LOCKED_BIT | Description - /// 0 | 0 | The mutex is not locked, nor is anyone waiting for it. - /// -----------+------------+------------------------------------------------------------------ - /// 0 | 1 | The mutex is locked by exactly one thread. No other thread is - /// | | waiting for it. - /// -----------+------------+------------------------------------------------------------------ - /// 1 | 0 | The mutex is not locked. One or more thread is parked or about to - /// | | park. At least one of the parked threads are just about to be - /// | | unparked, or a thread heading for parking might abort the park. - /// -----------+------------+------------------------------------------------------------------ - /// 1 | 1 | The mutex is locked by exactly one thread. One or more thread is - /// | | parked or about to park, waiting for the lock to become available. - /// | | In this state, PARKED_BIT is only ever cleared when a bucket lock - /// | | is held (i.e. in a parking_lot_core callback). This ensures that - /// | | we never end up in a situation where there are parked threads but - /// | | PARKED_BIT is not set (which would result in those threads - /// | | potentially never getting woken up). - state: AtomicU8, -} - -unsafe impl lock_api::RawMutex for RawMutex { - const INIT: RawMutex = RawMutex { - state: AtomicU8::new(0), - }; - - type GuardMarker = GuardNoSend; - - #[inline] - fn lock(&self) { - if self - .state - .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_err() - { - self.lock_slow(None); - } - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - } - - #[inline] - fn try_lock(&self) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - if state & LOCKED_BIT != 0 { - return false; - } - match self.state.compare_exchange_weak( - state, - state | LOCKED_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => { - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - return true; - } - Err(x) => state = x, - } - } - } - - #[inline] - fn unlock(&self) { - unsafe { deadlock::release_resource(self as *const _ as usize) }; - if self - .state - .compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - return; - } - self.unlock_slow(false); - } -} - -unsafe impl lock_api::RawMutexFair for RawMutex { - #[inline] - fn unlock_fair(&self) { - unsafe { deadlock::release_resource(self as *const _ as usize) }; - if self - .state - .compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - return; - } - self.unlock_slow(true); - } - - #[inline] - fn bump(&self) { - if self.state.load(Ordering::Relaxed) & PARKED_BIT != 0 { - self.bump_slow(); - } - } -} - -unsafe impl lock_api::RawMutexTimed for RawMutex { - type Duration = Duration; - type Instant = Instant; - - #[inline] - fn try_lock_until(&self, timeout: Instant) -> bool { - let result = if self - .state - .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - true - } else { - self.lock_slow(Some(timeout)) - }; - if result { - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - } - result - } - - #[inline] - fn try_lock_for(&self, timeout: Duration) -> bool { - let result = if self - .state - .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - true - } else { - self.lock_slow(util::to_deadline(timeout)) - }; - if result { - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - } - result - } -} - -impl RawMutex { - // Used by Condvar when requeuing threads to us, must be called while - // holding the queue lock. - #[inline] - pub(crate) fn mark_parked_if_locked(&self) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - if state & LOCKED_BIT == 0 { - return false; - } - match self.state.compare_exchange_weak( - state, - state | PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - } - } - - // Used by Condvar when requeuing threads to us, must be called while - // holding the queue lock. - #[inline] - pub(crate) fn mark_parked(&self) { - self.state.fetch_or(PARKED_BIT, Ordering::Relaxed); - } - - #[cold] - fn lock_slow(&self, timeout: Option) -> bool { - let mut spinwait = SpinWait::new(); - let mut state = self.state.load(Ordering::Relaxed); - loop { - // Grab the lock if it isn't locked, even if there is a queue on it - if state & LOCKED_BIT == 0 { - match self.state.compare_exchange_weak( - state, - state | LOCKED_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - continue; - } - - // If there is no queue, try spinning a few times - if state & PARKED_BIT == 0 && spinwait.spin() { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Set the parked bit - if state & PARKED_BIT == 0 { - if let Err(x) = self.state.compare_exchange_weak( - state, - state | PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - state = x; - continue; - } - } - - // Park our thread until we are woken up by an unlock - let addr = self as *const _ as usize; - let validate = || self.state.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT; - let before_sleep = || {}; - let timed_out = |_, was_last_thread| { - // Clear the parked bit if we were the last parked thread - if was_last_thread { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - }; - // SAFETY: - // * `addr` is an address we control. - // * `validate`/`timed_out` does not panic or call into any function of `parking_lot`. - // * `before_sleep` does not call `park`, nor does it panic. - match unsafe { - parking_lot_core::park( - addr, - validate, - before_sleep, - timed_out, - DEFAULT_PARK_TOKEN, - timeout, - ) - } { - // The thread that unparked us passed the lock on to us - // directly without unlocking it. - ParkResult::Unparked(TOKEN_HANDOFF) => return true, - - // We were unparked normally, try acquiring the lock again - ParkResult::Unparked(_) => (), - - // The validation function failed, try locking again - ParkResult::Invalid => (), - - // Timeout expired - ParkResult::TimedOut => return false, - } - - // Loop back and try locking again - spinwait.reset(); - state = self.state.load(Ordering::Relaxed); - } - } - - #[cold] - fn unlock_slow(&self, force_fair: bool) { - // Unpark one thread and leave the parked bit set if there might - // still be parked threads on this address. - let addr = self as *const _ as usize; - let callback = |result: UnparkResult| { - // If we are using a fair unlock then we should keep the - // mutex locked and hand it off to the unparked thread. - if result.unparked_threads != 0 && (force_fair || result.be_fair) { - // Clear the parked bit if there are no more parked - // threads. - if !result.have_more_threads { - self.state.store(LOCKED_BIT, Ordering::Relaxed); - } - return TOKEN_HANDOFF; - } - - // Clear the locked bit, and the parked bit as well if there - // are no more parked threads. - if result.have_more_threads { - self.state.store(PARKED_BIT, Ordering::Release); - } else { - self.state.store(0, Ordering::Release); - } - TOKEN_NORMAL - }; - // SAFETY: - // * `addr` is an address we control. - // * `callback` does not panic or call into any function of `parking_lot`. - unsafe { - parking_lot_core::unpark_one(addr, callback); - } - } - - #[cold] - fn bump_slow(&self) { - unsafe { deadlock::release_resource(self as *const _ as usize) }; - self.unlock_slow(true); - self.lock(); - } -} diff --git a/vendor/parking_lot-0.10.2/src/raw_rwlock.rs b/vendor/parking_lot-0.10.2/src/raw_rwlock.rs deleted file mode 100644 index 8c1ad11256..0000000000 --- a/vendor/parking_lot-0.10.2/src/raw_rwlock.rs +++ /dev/null @@ -1,1137 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::elision::{have_elision, AtomicElisionExt}; -use crate::raw_mutex::{TOKEN_HANDOFF, TOKEN_NORMAL}; -use crate::util; -use core::{ - cell::Cell, - sync::atomic::{AtomicUsize, Ordering}, -}; -use lock_api::{GuardNoSend, RawRwLock as RawRwLock_, RawRwLockUpgrade}; -use parking_lot_core::{ - self, deadlock, FilterOp, ParkResult, ParkToken, SpinWait, UnparkResult, UnparkToken, -}; -use std::time::{Duration, Instant}; - -// This reader-writer lock implementation is based on Boost's upgrade_mutex: -// https://github.com/boostorg/thread/blob/fc08c1fe2840baeeee143440fba31ef9e9a813c8/include/boost/thread/v2/shared_mutex.hpp#L432 -// -// This implementation uses 2 wait queues, one at key [addr] and one at key -// [addr + 1]. The primary queue is used for all new waiting threads, and the -// secondary queue is used by the thread which has acquired WRITER_BIT but is -// waiting for the remaining readers to exit the lock. -// -// This implementation is fair between readers and writers since it uses the -// order in which threads first started queuing to alternate between read phases -// and write phases. In particular is it not vulnerable to write starvation -// since readers will block if there is a pending writer. - -// There is at least one thread in the main queue. -const PARKED_BIT: usize = 0b0001; -// There is a parked thread holding WRITER_BIT. WRITER_BIT must be set. -const WRITER_PARKED_BIT: usize = 0b0010; -// A reader is holding an upgradable lock. The reader count must be non-zero and -// WRITER_BIT must not be set. -const UPGRADABLE_BIT: usize = 0b0100; -// If the reader count is zero: a writer is currently holding an exclusive lock. -// Otherwise: a writer is waiting for the remaining readers to exit the lock. -const WRITER_BIT: usize = 0b1000; -// Mask of bits used to count readers. -const READERS_MASK: usize = !0b1111; -// Base unit for counting readers. -const ONE_READER: usize = 0b10000; - -// Token indicating what type of lock a queued thread is trying to acquire -const TOKEN_SHARED: ParkToken = ParkToken(ONE_READER); -const TOKEN_EXCLUSIVE: ParkToken = ParkToken(WRITER_BIT); -const TOKEN_UPGRADABLE: ParkToken = ParkToken(ONE_READER | UPGRADABLE_BIT); - -/// Raw reader-writer lock type backed by the parking lot. -pub struct RawRwLock { - state: AtomicUsize, -} - -unsafe impl lock_api::RawRwLock for RawRwLock { - const INIT: RawRwLock = RawRwLock { - state: AtomicUsize::new(0), - }; - - type GuardMarker = GuardNoSend; - - #[inline] - fn lock_exclusive(&self) { - if self - .state - .compare_exchange_weak(0, WRITER_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_err() - { - let result = self.lock_exclusive_slow(None); - debug_assert!(result); - } - self.deadlock_acquire(); - } - - #[inline] - fn try_lock_exclusive(&self) -> bool { - if self - .state - .compare_exchange(0, WRITER_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - self.deadlock_acquire(); - true - } else { - false - } - } - - #[inline] - fn unlock_exclusive(&self) { - self.deadlock_release(); - if self - .state - .compare_exchange(WRITER_BIT, 0, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - return; - } - self.unlock_exclusive_slow(false); - } - - #[inline] - fn lock_shared(&self) { - if !self.try_lock_shared_fast(false) { - let result = self.lock_shared_slow(false, None); - debug_assert!(result); - } - self.deadlock_acquire(); - } - - #[inline] - fn try_lock_shared(&self) -> bool { - let result = if self.try_lock_shared_fast(false) { - true - } else { - self.try_lock_shared_slow(false) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn unlock_shared(&self) { - self.deadlock_release(); - let state = if have_elision() { - self.state.elision_fetch_sub_release(ONE_READER) - } else { - self.state.fetch_sub(ONE_READER, Ordering::Release) - }; - if state & (READERS_MASK | WRITER_PARKED_BIT) == (ONE_READER | WRITER_PARKED_BIT) { - self.unlock_shared_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockFair for RawRwLock { - #[inline] - fn unlock_shared_fair(&self) { - // Shared unlocking is always fair in this implementation. - self.unlock_shared(); - } - - #[inline] - fn unlock_exclusive_fair(&self) { - self.deadlock_release(); - if self - .state - .compare_exchange(WRITER_BIT, 0, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - return; - } - self.unlock_exclusive_slow(true); - } - - #[inline] - fn bump_shared(&self) { - if self.state.load(Ordering::Relaxed) & (READERS_MASK | WRITER_BIT) - == ONE_READER | WRITER_BIT - { - self.bump_shared_slow(); - } - } - - #[inline] - fn bump_exclusive(&self) { - if self.state.load(Ordering::Relaxed) & PARKED_BIT != 0 { - self.bump_exclusive_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockDowngrade for RawRwLock { - #[inline] - fn downgrade(&self) { - let state = self - .state - .fetch_add(ONE_READER - WRITER_BIT, Ordering::Release); - - // Wake up parked shared and upgradable threads if there are any - if state & PARKED_BIT != 0 { - self.downgrade_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockTimed for RawRwLock { - type Duration = Duration; - type Instant = Instant; - - #[inline] - fn try_lock_shared_for(&self, timeout: Self::Duration) -> bool { - let result = if self.try_lock_shared_fast(false) { - true - } else { - self.lock_shared_slow(false, util::to_deadline(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_shared_until(&self, timeout: Self::Instant) -> bool { - let result = if self.try_lock_shared_fast(false) { - true - } else { - self.lock_shared_slow(false, Some(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_exclusive_for(&self, timeout: Duration) -> bool { - let result = if self - .state - .compare_exchange_weak(0, WRITER_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - true - } else { - self.lock_exclusive_slow(util::to_deadline(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_exclusive_until(&self, timeout: Instant) -> bool { - let result = if self - .state - .compare_exchange_weak(0, WRITER_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - true - } else { - self.lock_exclusive_slow(Some(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } -} - -unsafe impl lock_api::RawRwLockRecursive for RawRwLock { - #[inline] - fn lock_shared_recursive(&self) { - if !self.try_lock_shared_fast(true) { - let result = self.lock_shared_slow(true, None); - debug_assert!(result); - } - self.deadlock_acquire(); - } - - #[inline] - fn try_lock_shared_recursive(&self) -> bool { - let result = if self.try_lock_shared_fast(true) { - true - } else { - self.try_lock_shared_slow(true) - }; - if result { - self.deadlock_acquire(); - } - result - } -} - -unsafe impl lock_api::RawRwLockRecursiveTimed for RawRwLock { - #[inline] - fn try_lock_shared_recursive_for(&self, timeout: Self::Duration) -> bool { - let result = if self.try_lock_shared_fast(true) { - true - } else { - self.lock_shared_slow(true, util::to_deadline(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_shared_recursive_until(&self, timeout: Self::Instant) -> bool { - let result = if self.try_lock_shared_fast(true) { - true - } else { - self.lock_shared_slow(true, Some(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } -} - -unsafe impl lock_api::RawRwLockUpgrade for RawRwLock { - #[inline] - fn lock_upgradable(&self) { - if !self.try_lock_upgradable_fast() { - let result = self.lock_upgradable_slow(None); - debug_assert!(result); - } - self.deadlock_acquire(); - } - - #[inline] - fn try_lock_upgradable(&self) -> bool { - let result = if self.try_lock_upgradable_fast() { - true - } else { - self.try_lock_upgradable_slow() - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn unlock_upgradable(&self) { - self.deadlock_release(); - let state = self.state.load(Ordering::Relaxed); - if state & PARKED_BIT == 0 { - if self - .state - .compare_exchange_weak( - state, - state - (ONE_READER | UPGRADABLE_BIT), - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - return; - } - } - self.unlock_upgradable_slow(false); - } - - #[inline] - fn upgrade(&self) { - let state = self.state.fetch_sub( - (ONE_READER | UPGRADABLE_BIT) - WRITER_BIT, - Ordering::Relaxed, - ); - if state & READERS_MASK != ONE_READER { - let result = self.upgrade_slow(None); - debug_assert!(result); - } - } - - #[inline] - fn try_upgrade(&self) -> bool { - if self - .state - .compare_exchange_weak( - ONE_READER | UPGRADABLE_BIT, - WRITER_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) - .is_ok() - { - true - } else { - self.try_upgrade_slow() - } - } -} - -unsafe impl lock_api::RawRwLockUpgradeFair for RawRwLock { - #[inline] - fn unlock_upgradable_fair(&self) { - self.deadlock_release(); - let state = self.state.load(Ordering::Relaxed); - if state & PARKED_BIT == 0 { - if self - .state - .compare_exchange_weak( - state, - state - (ONE_READER | UPGRADABLE_BIT), - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - return; - } - } - self.unlock_upgradable_slow(false); - } - - #[inline] - fn bump_upgradable(&self) { - if self.state.load(Ordering::Relaxed) == ONE_READER | UPGRADABLE_BIT | PARKED_BIT { - self.bump_upgradable_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockUpgradeDowngrade for RawRwLock { - #[inline] - fn downgrade_upgradable(&self) { - let state = self.state.fetch_sub(UPGRADABLE_BIT, Ordering::Relaxed); - - // Wake up parked upgradable threads if there are any - if state & PARKED_BIT != 0 { - self.downgrade_slow(); - } - } - - #[inline] - fn downgrade_to_upgradable(&self) { - let state = self.state.fetch_add( - (ONE_READER | UPGRADABLE_BIT) - WRITER_BIT, - Ordering::Release, - ); - - // Wake up parked shared threads if there are any - if state & PARKED_BIT != 0 { - self.downgrade_to_upgradable_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockUpgradeTimed for RawRwLock { - #[inline] - fn try_lock_upgradable_until(&self, timeout: Instant) -> bool { - let result = if self.try_lock_upgradable_fast() { - true - } else { - self.lock_upgradable_slow(Some(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_upgradable_for(&self, timeout: Duration) -> bool { - let result = if self.try_lock_upgradable_fast() { - true - } else { - self.lock_upgradable_slow(util::to_deadline(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_upgrade_until(&self, timeout: Instant) -> bool { - let state = self.state.fetch_sub( - (ONE_READER | UPGRADABLE_BIT) - WRITER_BIT, - Ordering::Relaxed, - ); - if state & READERS_MASK == ONE_READER { - true - } else { - self.upgrade_slow(Some(timeout)) - } - } - - #[inline] - fn try_upgrade_for(&self, timeout: Duration) -> bool { - let state = self.state.fetch_sub( - (ONE_READER | UPGRADABLE_BIT) - WRITER_BIT, - Ordering::Relaxed, - ); - if state & READERS_MASK == ONE_READER { - true - } else { - self.upgrade_slow(util::to_deadline(timeout)) - } - } -} - -impl RawRwLock { - #[inline(always)] - fn try_lock_shared_fast(&self, recursive: bool) -> bool { - let state = self.state.load(Ordering::Relaxed); - - // We can't allow grabbing a shared lock if there is a writer, even if - // the writer is still waiting for the remaining readers to exit. - if state & WRITER_BIT != 0 { - // To allow recursive locks, we make an exception and allow readers - // to skip ahead of a pending writer to avoid deadlocking, at the - // cost of breaking the fairness guarantees. - if !recursive || state & READERS_MASK == 0 { - return false; - } - } - - // Use hardware lock elision to avoid cache conflicts when multiple - // readers try to acquire the lock. We only do this if the lock is - // completely empty since elision handles conflicts poorly. - if have_elision() && state == 0 { - self.state - .elision_compare_exchange_acquire(0, ONE_READER) - .is_ok() - } else if let Some(new_state) = state.checked_add(ONE_READER) { - self.state - .compare_exchange_weak(state, new_state, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - } else { - false - } - } - - #[cold] - fn try_lock_shared_slow(&self, recursive: bool) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - // This mirrors the condition in try_lock_shared_fast - if state & WRITER_BIT != 0 { - if !recursive || state & READERS_MASK == 0 { - return false; - } - } - if have_elision() && state == 0 { - match self.state.elision_compare_exchange_acquire(0, ONE_READER) { - Ok(_) => return true, - Err(x) => state = x, - } - } else { - match self.state.compare_exchange_weak( - state, - state - .checked_add(ONE_READER) - .expect("RwLock reader count overflow"), - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - } - } - } - - #[inline(always)] - fn try_lock_upgradable_fast(&self) -> bool { - let state = self.state.load(Ordering::Relaxed); - - // We can't grab an upgradable lock if there is already a writer or - // upgradable reader. - if state & (WRITER_BIT | UPGRADABLE_BIT) != 0 { - return false; - } - - if let Some(new_state) = state.checked_add(ONE_READER | UPGRADABLE_BIT) { - self.state - .compare_exchange_weak(state, new_state, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - } else { - false - } - } - - #[cold] - fn try_lock_upgradable_slow(&self) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - // This mirrors the condition in try_lock_upgradable_fast - if state & (WRITER_BIT | UPGRADABLE_BIT) != 0 { - return false; - } - - match self.state.compare_exchange_weak( - state, - state - .checked_add(ONE_READER | UPGRADABLE_BIT) - .expect("RwLock reader count overflow"), - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - } - } - - #[cold] - fn lock_exclusive_slow(&self, timeout: Option) -> bool { - let try_lock = |state: &mut usize| { - loop { - if *state & (WRITER_BIT | UPGRADABLE_BIT) != 0 { - return false; - } - - // Grab WRITER_BIT if it isn't set, even if there are parked threads. - match self.state.compare_exchange_weak( - *state, - *state | WRITER_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => *state = x, - } - } - }; - - // Step 1: grab exclusive ownership of WRITER_BIT - let timed_out = !self.lock_common( - timeout, - TOKEN_EXCLUSIVE, - try_lock, - WRITER_BIT | UPGRADABLE_BIT, - ); - if timed_out { - return false; - } - - // Step 2: wait for all remaining readers to exit the lock. - self.wait_for_readers(timeout, 0) - } - - #[cold] - fn unlock_exclusive_slow(&self, force_fair: bool) { - // There are threads to unpark. Try to unpark as many as we can. - let callback = |mut new_state, result: UnparkResult| { - // If we are using a fair unlock then we should keep the - // rwlock locked and hand it off to the unparked threads. - if result.unparked_threads != 0 && (force_fair || result.be_fair) { - if result.have_more_threads { - new_state |= PARKED_BIT; - } - self.state.store(new_state, Ordering::Release); - TOKEN_HANDOFF - } else { - // Clear the parked bit if there are no more parked threads. - if result.have_more_threads { - self.state.store(PARKED_BIT, Ordering::Release); - } else { - self.state.store(0, Ordering::Release); - } - TOKEN_NORMAL - } - }; - // SAFETY: `callback` does not panic or call into any function of `parking_lot`. - unsafe { - self.wake_parked_threads(0, callback); - } - } - - #[cold] - fn lock_shared_slow(&self, recursive: bool, timeout: Option) -> bool { - let try_lock = |state: &mut usize| { - let mut spinwait_shared = SpinWait::new(); - loop { - // Use hardware lock elision to avoid cache conflicts when multiple - // readers try to acquire the lock. We only do this if the lock is - // completely empty since elision handles conflicts poorly. - if have_elision() && *state == 0 { - match self.state.elision_compare_exchange_acquire(0, ONE_READER) { - Ok(_) => return true, - Err(x) => *state = x, - } - } - - // This is the same condition as try_lock_shared_fast - if *state & WRITER_BIT != 0 { - if !recursive || *state & READERS_MASK == 0 { - return false; - } - } - - if self - .state - .compare_exchange_weak( - *state, - state - .checked_add(ONE_READER) - .expect("RwLock reader count overflow"), - Ordering::Acquire, - Ordering::Relaxed, - ) - .is_ok() - { - return true; - } - - // If there is high contention on the reader count then we want - // to leave some time between attempts to acquire the lock to - // let other threads make progress. - spinwait_shared.spin_no_yield(); - *state = self.state.load(Ordering::Relaxed); - } - }; - self.lock_common(timeout, TOKEN_SHARED, try_lock, WRITER_BIT) - } - - #[cold] - fn unlock_shared_slow(&self) { - // At this point WRITER_PARKED_BIT is set and READER_MASK is empty. We - // just need to wake up a potentially sleeping pending writer. - // Using the 2nd key at addr + 1 - let addr = self as *const _ as usize + 1; - let callback = |_result: UnparkResult| { - // Clear the WRITER_PARKED_BIT here since there can only be one - // parked writer thread. - self.state.fetch_and(!WRITER_PARKED_BIT, Ordering::Relaxed); - TOKEN_NORMAL - }; - // SAFETY: - // * `addr` is an address we control. - // * `callback` does not panic or call into any function of `parking_lot`. - unsafe { - parking_lot_core::unpark_one(addr, callback); - } - } - - #[cold] - fn lock_upgradable_slow(&self, timeout: Option) -> bool { - let try_lock = |state: &mut usize| { - let mut spinwait_shared = SpinWait::new(); - loop { - if *state & (WRITER_BIT | UPGRADABLE_BIT) != 0 { - return false; - } - - if self - .state - .compare_exchange_weak( - *state, - state - .checked_add(ONE_READER | UPGRADABLE_BIT) - .expect("RwLock reader count overflow"), - Ordering::Acquire, - Ordering::Relaxed, - ) - .is_ok() - { - return true; - } - - // If there is high contention on the reader count then we want - // to leave some time between attempts to acquire the lock to - // let other threads make progress. - spinwait_shared.spin_no_yield(); - *state = self.state.load(Ordering::Relaxed); - } - }; - self.lock_common( - timeout, - TOKEN_UPGRADABLE, - try_lock, - WRITER_BIT | UPGRADABLE_BIT, - ) - } - - #[cold] - fn unlock_upgradable_slow(&self, force_fair: bool) { - // Just release the lock if there are no parked threads. - let mut state = self.state.load(Ordering::Relaxed); - while state & PARKED_BIT == 0 { - match self.state.compare_exchange_weak( - state, - state - (ONE_READER | UPGRADABLE_BIT), - Ordering::Release, - Ordering::Relaxed, - ) { - Ok(_) => return, - Err(x) => state = x, - } - } - - // There are threads to unpark. Try to unpark as many as we can. - let callback = |new_state, result: UnparkResult| { - // If we are using a fair unlock then we should keep the - // rwlock locked and hand it off to the unparked threads. - let mut state = self.state.load(Ordering::Relaxed); - if force_fair || result.be_fair { - // Fall back to normal unpark on overflow. Panicking is - // not allowed in parking_lot callbacks. - while let Some(mut new_state) = - (state - (ONE_READER | UPGRADABLE_BIT)).checked_add(new_state) - { - if result.have_more_threads { - new_state |= PARKED_BIT; - } else { - new_state &= !PARKED_BIT; - } - match self.state.compare_exchange_weak( - state, - new_state, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_) => return TOKEN_HANDOFF, - Err(x) => state = x, - } - } - } - - // Otherwise just release the upgradable lock and update PARKED_BIT. - loop { - let mut new_state = state - (ONE_READER | UPGRADABLE_BIT); - if result.have_more_threads { - new_state |= PARKED_BIT; - } else { - new_state &= !PARKED_BIT; - } - match self.state.compare_exchange_weak( - state, - new_state, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_) => return TOKEN_NORMAL, - Err(x) => state = x, - } - } - }; - // SAFETY: `callback` does not panic or call into any function of `parking_lot`. - unsafe { - self.wake_parked_threads(0, callback); - } - } - - #[cold] - fn try_upgrade_slow(&self) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - if state & READERS_MASK != ONE_READER { - return false; - } - match self.state.compare_exchange_weak( - state, - state - (ONE_READER | UPGRADABLE_BIT) + WRITER_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - } - } - - #[cold] - fn upgrade_slow(&self, timeout: Option) -> bool { - self.wait_for_readers(timeout, ONE_READER | UPGRADABLE_BIT) - } - - #[cold] - fn downgrade_slow(&self) { - // We only reach this point if PARKED_BIT is set. - let callback = |_, result: UnparkResult| { - // Clear the parked bit if there no more parked threads - if !result.have_more_threads { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - TOKEN_NORMAL - }; - // SAFETY: `callback` does not panic or call into any function of `parking_lot`. - unsafe { - self.wake_parked_threads(ONE_READER, callback); - } - } - - #[cold] - fn downgrade_to_upgradable_slow(&self) { - // We only reach this point if PARKED_BIT is set. - let callback = |_, result: UnparkResult| { - // Clear the parked bit if there no more parked threads - if !result.have_more_threads { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - TOKEN_NORMAL - }; - // SAFETY: `callback` does not panic or call into any function of `parking_lot`. - unsafe { - self.wake_parked_threads(ONE_READER | UPGRADABLE_BIT, callback); - } - } - - #[cold] - fn bump_shared_slow(&self) { - self.unlock_shared(); - self.lock_shared(); - } - - #[cold] - fn bump_exclusive_slow(&self) { - self.deadlock_release(); - self.unlock_exclusive_slow(true); - self.lock_exclusive(); - } - - #[cold] - fn bump_upgradable_slow(&self) { - self.deadlock_release(); - self.unlock_upgradable_slow(true); - self.lock_upgradable(); - } - - /// Common code for waking up parked threads after releasing WRITER_BIT or - /// UPGRADABLE_BIT. - /// - /// # Safety - /// - /// `callback` must uphold the requirements of the `callback` parameter to - /// `parking_lot_core::unpark_filter`. Meaning no panics or calls into any function in - /// `parking_lot`. - #[inline] - unsafe fn wake_parked_threads( - &self, - new_state: usize, - callback: impl FnOnce(usize, UnparkResult) -> UnparkToken, - ) { - // We must wake up at least one upgrader or writer if there is one, - // otherwise they may end up parked indefinitely since unlock_shared - // does not call wake_parked_threads. - let new_state = Cell::new(new_state); - let addr = self as *const _ as usize; - let filter = |ParkToken(token)| { - let s = new_state.get(); - - // If we are waking up a writer, don't wake anything else. - if s & WRITER_BIT != 0 { - return FilterOp::Stop; - } - - // Otherwise wake *all* readers and one upgrader/writer. - if token & (UPGRADABLE_BIT | WRITER_BIT) != 0 && s & UPGRADABLE_BIT != 0 { - // Skip writers and upgradable readers if we already have - // a writer/upgradable reader. - FilterOp::Skip - } else { - new_state.set(s + token); - FilterOp::Unpark - } - }; - let callback = |result| callback(new_state.get(), result); - // SAFETY: - // * `addr` is an address we control. - // * `filter` does not panic or call into any function of `parking_lot`. - // * `callback` safety responsibility is on caller - parking_lot_core::unpark_filter(addr, filter, callback); - } - - // Common code for waiting for readers to exit the lock after acquiring - // WRITER_BIT. - #[inline] - fn wait_for_readers(&self, timeout: Option, prev_value: usize) -> bool { - // At this point WRITER_BIT is already set, we just need to wait for the - // remaining readers to exit the lock. - let mut spinwait = SpinWait::new(); - let mut state = self.state.load(Ordering::Relaxed); - while state & READERS_MASK != 0 { - // Spin a few times to wait for readers to exit - if spinwait.spin() { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Set the parked bit - if state & WRITER_PARKED_BIT == 0 { - if let Err(x) = self.state.compare_exchange_weak( - state, - state | WRITER_PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - state = x; - continue; - } - } - - // Park our thread until we are woken up by an unlock - // Using the 2nd key at addr + 1 - let addr = self as *const _ as usize + 1; - let validate = || { - let state = self.state.load(Ordering::Relaxed); - state & READERS_MASK != 0 && state & WRITER_PARKED_BIT != 0 - }; - let before_sleep = || {}; - let timed_out = |_, _| {}; - // SAFETY: - // * `addr` is an address we control. - // * `validate`/`timed_out` does not panic or call into any function of `parking_lot`. - // * `before_sleep` does not call `park`, nor does it panic. - let park_result = unsafe { - parking_lot_core::park( - addr, - validate, - before_sleep, - timed_out, - TOKEN_EXCLUSIVE, - timeout, - ) - }; - match park_result { - // We still need to re-check the state if we are unparked - // since a previous writer timing-out could have allowed - // another reader to sneak in before we parked. - ParkResult::Unparked(_) | ParkResult::Invalid => { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Timeout expired - ParkResult::TimedOut => { - // We need to release WRITER_BIT and revert back to - // our previous value. We also wake up any threads that - // might be waiting on WRITER_BIT. - let state = self.state.fetch_add( - prev_value.wrapping_sub(WRITER_BIT | WRITER_PARKED_BIT), - Ordering::Relaxed, - ); - if state & PARKED_BIT != 0 { - let callback = |_, result: UnparkResult| { - // Clear the parked bit if there no more parked threads - if !result.have_more_threads { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - TOKEN_NORMAL - }; - // SAFETY: `callback` does not panic or call any function of `parking_lot`. - unsafe { - self.wake_parked_threads(ONE_READER | UPGRADABLE_BIT, callback); - } - } - return false; - } - } - } - true - } - - /// Common code for acquiring a lock - #[inline] - fn lock_common( - &self, - timeout: Option, - token: ParkToken, - mut try_lock: impl FnMut(&mut usize) -> bool, - validate_flags: usize, - ) -> bool { - let mut spinwait = SpinWait::new(); - let mut state = self.state.load(Ordering::Relaxed); - loop { - // Attempt to grab the lock - if try_lock(&mut state) { - return true; - } - - // If there are no parked threads, try spinning a few times. - if state & (PARKED_BIT | WRITER_PARKED_BIT) == 0 && spinwait.spin() { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Set the parked bit - if state & PARKED_BIT == 0 { - if let Err(x) = self.state.compare_exchange_weak( - state, - state | PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - state = x; - continue; - } - } - - // Park our thread until we are woken up by an unlock - let addr = self as *const _ as usize; - let validate = || { - let state = self.state.load(Ordering::Relaxed); - state & PARKED_BIT != 0 && (state & validate_flags != 0) - }; - let before_sleep = || {}; - let timed_out = |_, was_last_thread| { - // Clear the parked bit if we were the last parked thread - if was_last_thread { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - }; - - // SAFETY: - // * `addr` is an address we control. - // * `validate`/`timed_out` does not panic or call into any function of `parking_lot`. - // * `before_sleep` does not call `park`, nor does it panic. - let park_result = unsafe { - parking_lot_core::park(addr, validate, before_sleep, timed_out, token, timeout) - }; - match park_result { - // The thread that unparked us passed the lock on to us - // directly without unlocking it. - ParkResult::Unparked(TOKEN_HANDOFF) => return true, - - // We were unparked normally, try acquiring the lock again - ParkResult::Unparked(_) => (), - - // The validation function failed, try locking again - ParkResult::Invalid => (), - - // Timeout expired - ParkResult::TimedOut => return false, - } - - // Loop back and try locking again - spinwait.reset(); - state = self.state.load(Ordering::Relaxed); - } - } - - #[inline] - fn deadlock_acquire(&self) { - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - unsafe { deadlock::acquire_resource(self as *const _ as usize + 1) }; - } - - #[inline] - fn deadlock_release(&self) { - unsafe { deadlock::release_resource(self as *const _ as usize) }; - unsafe { deadlock::release_resource(self as *const _ as usize + 1) }; - } -} diff --git a/vendor/parking_lot-0.10.2/src/remutex.rs b/vendor/parking_lot-0.10.2/src/remutex.rs deleted file mode 100644 index 1037923018..0000000000 --- a/vendor/parking_lot-0.10.2/src/remutex.rs +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::raw_mutex::RawMutex; -use core::num::NonZeroUsize; -use lock_api::{self, GetThreadId}; - -/// Implementation of the `GetThreadId` trait for `lock_api::ReentrantMutex`. -pub struct RawThreadId; - -unsafe impl GetThreadId for RawThreadId { - const INIT: RawThreadId = RawThreadId; - - fn nonzero_thread_id(&self) -> NonZeroUsize { - // The address of a thread-local variable is guaranteed to be unique to the - // current thread, and is also guaranteed to be non-zero. The variable has to have a - // non-zero size to guarantee it has a unique address for each thread. - thread_local!(static KEY: u8 = 0); - KEY.with(|x| { - NonZeroUsize::new(x as *const _ as usize) - .expect("thread-local variable address is null") - }) - } -} - -/// A mutex which can be recursively locked by a single thread. -/// -/// This type is identical to `Mutex` except for the following points: -/// -/// - Locking multiple times from the same thread will work correctly instead of -/// deadlocking. -/// - `ReentrantMutexGuard` does not give mutable references to the locked data. -/// Use a `RefCell` if you need this. -/// -/// See [`Mutex`](type.Mutex.html) for more details about the underlying mutex -/// primitive. -pub type ReentrantMutex = lock_api::ReentrantMutex; - -/// Creates a new reentrant mutex in an unlocked state ready for use. -/// -/// This allows creating a reentrant mutex in a constant context on stable Rust. -pub const fn const_reentrant_mutex(val: T) -> ReentrantMutex { - ReentrantMutex::const_new( - ::INIT, - ::INIT, - val, - ) -} - -/// An RAII implementation of a "scoped lock" of a reentrant mutex. When this structure -/// is dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// `Deref` implementation. -pub type ReentrantMutexGuard<'a, T> = lock_api::ReentrantMutexGuard<'a, RawMutex, RawThreadId, T>; - -/// An RAII mutex guard returned by `ReentrantMutexGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedReentrantMutexGuard` and `ReentrantMutexGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedReentrantMutexGuard<'a, T> = - lock_api::MappedReentrantMutexGuard<'a, RawMutex, RawThreadId, T>; - -#[cfg(test)] -mod tests { - use crate::ReentrantMutex; - use std::cell::RefCell; - use std::sync::Arc; - use std::thread; - - #[cfg(feature = "serde")] - use bincode::{deserialize, serialize}; - - #[test] - fn smoke() { - let m = ReentrantMutex::new(2); - { - let a = m.lock(); - { - let b = m.lock(); - { - let c = m.lock(); - assert_eq!(*c, 2); - } - assert_eq!(*b, 2); - } - assert_eq!(*a, 2); - } - } - - #[test] - fn is_mutex() { - let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - let m2 = m.clone(); - let lock = m.lock(); - let child = thread::spawn(move || { - let lock = m2.lock(); - assert_eq!(*lock.borrow(), 4950); - }); - for i in 0..100 { - let lock = m.lock(); - *lock.borrow_mut() += i; - } - drop(lock); - child.join().unwrap(); - } - - #[test] - fn trylock_works() { - let m = Arc::new(ReentrantMutex::new(())); - let m2 = m.clone(); - let _lock = m.try_lock(); - let _lock2 = m.try_lock(); - thread::spawn(move || { - let lock = m2.try_lock(); - assert!(lock.is_none()); - }) - .join() - .unwrap(); - let _lock3 = m.try_lock(); - } - - #[test] - fn test_reentrant_mutex_debug() { - let mutex = ReentrantMutex::new(vec![0u8, 10]); - - assert_eq!(format!("{:?}", mutex), "ReentrantMutex { data: [0, 10] }"); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serde() { - let contents: Vec = vec![0, 1, 2]; - let mutex = ReentrantMutex::new(contents.clone()); - - let serialized = serialize(&mutex).unwrap(); - let deserialized: ReentrantMutex> = deserialize(&serialized).unwrap(); - - assert_eq!(*(mutex.lock()), *(deserialized.lock())); - assert_eq!(contents, *(deserialized.lock())); - } -} diff --git a/vendor/parking_lot-0.10.2/src/rwlock.rs b/vendor/parking_lot-0.10.2/src/rwlock.rs deleted file mode 100644 index 0381316eaa..0000000000 --- a/vendor/parking_lot-0.10.2/src/rwlock.rs +++ /dev/null @@ -1,613 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::raw_rwlock::RawRwLock; -use lock_api; - -/// A reader-writer lock -/// -/// This type of lock allows a number of readers or at most one writer at any -/// point in time. The write portion of this lock typically allows modification -/// of the underlying data (exclusive access) and the read portion of this lock -/// typically allows for read-only access (shared access). -/// -/// This lock uses a task-fair locking policy which avoids both reader and -/// writer starvation. This means that readers trying to acquire the lock will -/// block even if the lock is unlocked when there are writers waiting to acquire -/// the lock. Because of this, attempts to recursively acquire a read lock -/// within a single thread may result in a deadlock. -/// -/// The type parameter `T` represents the data that this lock protects. It is -/// required that `T` satisfies `Send` to be shared across threads and `Sync` to -/// allow concurrent access through readers. The RAII guards returned from the -/// locking methods implement `Deref` (and `DerefMut` for the `write` methods) -/// to allow access to the contained of the lock. -/// -/// # Fairness -/// -/// A typical unfair lock can often end up in a situation where a single thread -/// quickly acquires and releases the same lock in succession, which can starve -/// other threads waiting to acquire the rwlock. While this improves performance -/// because it doesn't force a context switch when a thread tries to re-acquire -/// a rwlock it has just released, this can starve other threads. -/// -/// This rwlock uses [eventual fairness](https://trac.webkit.org/changeset/203350) -/// to ensure that the lock will be fair on average without sacrificing -/// performance. This is done by forcing a fair unlock on average every 0.5ms, -/// which will force the lock to go to the next thread waiting for the rwlock. -/// -/// Additionally, any critical section longer than 1ms will always use a fair -/// unlock, which has a negligible performance impact compared to the length of -/// the critical section. -/// -/// You can also force a fair unlock by calling `RwLockReadGuard::unlock_fair` -/// or `RwLockWriteGuard::unlock_fair` when unlocking a mutex instead of simply -/// dropping the guard. -/// -/// # Differences from the standard library `RwLock` -/// -/// - Supports atomically downgrading a write lock into a read lock. -/// - Task-fair locking policy instead of an unspecified platform default. -/// - No poisoning, the lock is released normally on panic. -/// - Only requires 1 word of space, whereas the standard library boxes the -/// `RwLock` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). -/// - Does not require any drop glue when dropped. -/// - Inline fast path for the uncontended case. -/// - Efficient handling of micro-contention using adaptive spinning. -/// - Allows raw locking & unlocking without a guard. -/// - Supports eventual fairness so that the rwlock is fair on average. -/// - Optionally allows making the rwlock fair by calling -/// `RwLockReadGuard::unlock_fair` and `RwLockWriteGuard::unlock_fair`. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::RwLock; -/// -/// let lock = RwLock::new(5); -/// -/// // many reader locks can be held at once -/// { -/// let r1 = lock.read(); -/// let r2 = lock.read(); -/// assert_eq!(*r1, 5); -/// assert_eq!(*r2, 5); -/// } // read locks are dropped at this point -/// -/// // only one write lock may be held, however -/// { -/// let mut w = lock.write(); -/// *w += 1; -/// assert_eq!(*w, 6); -/// } // write lock is dropped here -/// ``` -pub type RwLock = lock_api::RwLock; - -/// Creates a new instance of an `RwLock` which is unlocked. -/// -/// This allows creating a `RwLock` in a constant context on stable Rust. -pub const fn const_rwlock(val: T) -> RwLock { - RwLock::const_new(::INIT, val) -} - -/// RAII structure used to release the shared read access of a lock when -/// dropped. -pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>; - -/// RAII structure used to release the exclusive write access of a lock when -/// dropped. -pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>; - -/// An RAII read lock guard returned by `RwLockReadGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedRwLockReadGuard` and `RwLockReadGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedRwLockReadGuard<'a, T> = lock_api::MappedRwLockReadGuard<'a, RawRwLock, T>; - -/// An RAII write lock guard returned by `RwLockWriteGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedRwLockWriteGuard` and `RwLockWriteGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedRwLockWriteGuard<'a, T> = lock_api::MappedRwLockWriteGuard<'a, RawRwLock, T>; - -/// RAII structure used to release the upgradable read access of a lock when -/// dropped. -pub type RwLockUpgradableReadGuard<'a, T> = lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>; - -#[cfg(test)] -mod tests { - use crate::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard}; - use rand::Rng; - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::sync::mpsc::channel; - use std::sync::Arc; - use std::thread; - use std::time::Duration; - - #[cfg(feature = "serde")] - use bincode::{deserialize, serialize}; - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let l = RwLock::new(()); - drop(l.read()); - drop(l.write()); - drop(l.upgradable_read()); - drop((l.read(), l.read())); - drop((l.read(), l.upgradable_read())); - drop(l.write()); - } - - #[test] - fn frob() { - const N: u32 = 10; - const M: u32 = 1000; - - let r = Arc::new(RwLock::new(())); - - let (tx, rx) = channel::<()>(); - for _ in 0..N { - let tx = tx.clone(); - let r = r.clone(); - thread::spawn(move || { - let mut rng = rand::thread_rng(); - for _ in 0..M { - if rng.gen_bool(1.0 / N as f64) { - drop(r.write()); - } else { - drop(r.read()); - } - } - drop(tx); - }); - } - drop(tx); - let _ = rx.recv(); - } - - #[test] - fn test_rw_arc_no_poison_wr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write(); - panic!(); - }) - .join(); - let lock = arc.read(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc_no_poison_ww() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write(); - panic!(); - }) - .join(); - let lock = arc.write(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc_no_poison_rr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read(); - panic!(); - }) - .join(); - let lock = arc.read(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc_no_poison_rw() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read(); - panic!() - }) - .join(); - let lock = arc.write(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_ruw_arc() { - let arc = Arc::new(RwLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - thread::spawn(move || { - for _ in 0..10 { - let mut lock = arc2.write(); - let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - } - tx.send(()).unwrap(); - }); - - let mut children = Vec::new(); - - // Upgradable readers try to catch the writer in the act and also - // try to touch the value - for _ in 0..5 { - let arc3 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc3.upgradable_read(); - let tmp = *lock; - assert!(tmp >= 0); - thread::yield_now(); - let mut lock = RwLockUpgradableReadGuard::upgrade(lock); - assert_eq!(tmp, *lock); - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - })); - } - - // Readers try to catch the writers in the act - for _ in 0..5 { - let arc4 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc4.read(); - assert!(*lock >= 0); - })); - } - - // Wait for children to pass their asserts - for r in children { - assert!(r.join().is_ok()); - } - - // Wait for writer to finish - rx.recv().unwrap(); - let lock = arc.read(); - assert_eq!(*lock, 15); - } - - #[test] - fn test_rw_arc() { - let arc = Arc::new(RwLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - thread::spawn(move || { - let mut lock = arc2.write(); - for _ in 0..10 { - let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - } - tx.send(()).unwrap(); - }); - - // Readers try to catch the writer in the act - let mut children = Vec::new(); - for _ in 0..5 { - let arc3 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc3.read(); - assert!(*lock >= 0); - })); - } - - // Wait for children to pass their asserts - for r in children { - assert!(r.join().is_ok()); - } - - // Wait for writer to finish - rx.recv().unwrap(); - let lock = arc.read(); - assert_eq!(*lock, 10); - } - - #[test] - fn test_rw_arc_access_in_unwind() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - let mut lock = self.i.write(); - *lock += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.read(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_rwlock_unsized() { - let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); - { - let b = &mut *rw.write(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*rw.read(), comp); - } - - #[test] - fn test_rwlock_try_read() { - let lock = RwLock::new(0isize); - { - let read_guard = lock.read(); - - let read_result = lock.try_read(); - assert!( - read_result.is_some(), - "try_read should succeed while read_guard is in scope" - ); - - drop(read_guard); - } - { - let upgrade_guard = lock.upgradable_read(); - - let read_result = lock.try_read(); - assert!( - read_result.is_some(), - "try_read should succeed while upgrade_guard is in scope" - ); - - drop(upgrade_guard); - } - { - let write_guard = lock.write(); - - let read_result = lock.try_read(); - assert!( - read_result.is_none(), - "try_read should fail while write_guard is in scope" - ); - - drop(write_guard); - } - } - - #[test] - fn test_rwlock_try_write() { - let lock = RwLock::new(0isize); - { - let read_guard = lock.read(); - - let write_result = lock.try_write(); - assert!( - write_result.is_none(), - "try_write should fail while read_guard is in scope" - ); - - drop(read_guard); - } - { - let upgrade_guard = lock.upgradable_read(); - - let write_result = lock.try_write(); - assert!( - write_result.is_none(), - "try_write should fail while upgrade_guard is in scope" - ); - - drop(upgrade_guard); - } - { - let write_guard = lock.write(); - - let write_result = lock.try_write(); - assert!( - write_result.is_none(), - "try_write should fail while write_guard is in scope" - ); - - drop(write_guard); - } - } - - #[test] - fn test_rwlock_try_upgrade() { - let lock = RwLock::new(0isize); - { - let read_guard = lock.read(); - - let upgrade_result = lock.try_upgradable_read(); - assert!( - upgrade_result.is_some(), - "try_upgradable_read should succeed while read_guard is in scope" - ); - - drop(read_guard); - } - { - let upgrade_guard = lock.upgradable_read(); - - let upgrade_result = lock.try_upgradable_read(); - assert!( - upgrade_result.is_none(), - "try_upgradable_read should fail while upgrade_guard is in scope" - ); - - drop(upgrade_guard); - } - { - let write_guard = lock.write(); - - let upgrade_result = lock.try_upgradable_read(); - assert!( - upgrade_result.is_none(), - "try_upgradable should fail while write_guard is in scope" - ); - - drop(write_guard); - } - } - - #[test] - fn test_into_inner() { - let m = RwLock::new(NonCopy(10)); - assert_eq!(m.into_inner(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = RwLock::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_get_mut() { - let mut m = RwLock::new(NonCopy(10)); - *m.get_mut() = NonCopy(20); - assert_eq!(m.into_inner(), NonCopy(20)); - } - - #[test] - fn test_rwlockguard_sync() { - fn sync(_: T) {} - - let rwlock = RwLock::new(()); - sync(rwlock.read()); - sync(rwlock.write()); - } - - #[test] - fn test_rwlock_downgrade() { - let x = Arc::new(RwLock::new(0)); - let mut handles = Vec::new(); - for _ in 0..8 { - let x = x.clone(); - handles.push(thread::spawn(move || { - for _ in 0..100 { - let mut writer = x.write(); - *writer += 1; - let cur_val = *writer; - let reader = RwLockWriteGuard::downgrade(writer); - assert_eq!(cur_val, *reader); - } - })); - } - for handle in handles { - handle.join().unwrap() - } - assert_eq!(*x.read(), 800); - } - - #[test] - fn test_rwlock_recursive() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _lock1 = arc.read(); - thread::spawn(move || { - let _lock = arc2.write(); - }); - - if cfg!(not(all(target_env = "sgx", target_vendor = "fortanix"))) { - thread::sleep(Duration::from_millis(100)); - } else { - // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - for _ in 0..100 { - thread::yield_now(); - } - } - - // A normal read would block here since there is a pending writer - let _lock2 = arc.read_recursive(); - } - - #[test] - fn test_rwlock_debug() { - let x = RwLock::new(vec![0u8, 10]); - - assert_eq!(format!("{:?}", x), "RwLock { data: [0, 10] }"); - let _lock = x.write(); - assert_eq!(format!("{:?}", x), "RwLock { data: }"); - } - - #[test] - fn test_clone() { - let rwlock = RwLock::new(Arc::new(1)); - let a = rwlock.read_recursive(); - let b = a.clone(); - assert_eq!(Arc::strong_count(&b), 2); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serde() { - let contents: Vec = vec![0, 1, 2]; - let mutex = RwLock::new(contents.clone()); - - let serialized = serialize(&mutex).unwrap(); - let deserialized: RwLock> = deserialize(&serialized).unwrap(); - - assert_eq!(*(mutex.read()), *(deserialized.read())); - assert_eq!(contents, *(deserialized.read())); - } - - #[test] - fn test_issue_203() { - struct Bar(RwLock<()>); - - impl Drop for Bar { - fn drop(&mut self) { - let _n = self.0.write(); - } - } - - thread_local! { - static B: Bar = Bar(RwLock::new(())); - } - - thread::spawn(|| { - B.with(|_| ()); - - let a = RwLock::new(()); - let _a = a.read(); - }) - .join() - .unwrap(); - } -} diff --git a/vendor/parking_lot-0.10.2/src/util.rs b/vendor/parking_lot-0.10.2/src/util.rs deleted file mode 100644 index c5496fc00b..0000000000 --- a/vendor/parking_lot-0.10.2/src/util.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use std::time::{Duration, Instant}; - -// Option::unchecked_unwrap -pub trait UncheckedOptionExt { - unsafe fn unchecked_unwrap(self) -> T; -} - -impl UncheckedOptionExt for Option { - #[inline] - unsafe fn unchecked_unwrap(self) -> T { - match self { - Some(x) => x, - None => unreachable(), - } - } -} - -// hint::unreachable_unchecked() in release mode -#[inline] -unsafe fn unreachable() -> ! { - if cfg!(debug_assertions) { - unreachable!(); - } else { - core::hint::unreachable_unchecked() - } -} - -#[inline] -pub fn to_deadline(timeout: Duration) -> Option { - Instant::now().checked_add(timeout) -} diff --git a/vendor/parking_lot-0.10.2/tests/issue_203.rs b/vendor/parking_lot-0.10.2/tests/issue_203.rs deleted file mode 100644 index a77a95f8ae..0000000000 --- a/vendor/parking_lot-0.10.2/tests/issue_203.rs +++ /dev/null @@ -1,26 +0,0 @@ -use parking_lot::RwLock; -use std::thread; - -struct Bar(RwLock<()>); - -impl Drop for Bar { - fn drop(&mut self) { - let _n = self.0.write(); - } -} - -thread_local! { - static B: Bar = Bar(RwLock::new(())); -} - -#[test] -fn main() { - thread::spawn(|| { - B.with(|_| ()); - - let a = RwLock::new(()); - let _a = a.read(); - }) - .join() - .unwrap(); -} diff --git a/vendor/parking_lot_core-0.7.2/.cargo-checksum.json b/vendor/parking_lot_core-0.7.2/.cargo-checksum.json deleted file mode 100644 index 2b1d6d8132..0000000000 --- a/vendor/parking_lot_core-0.7.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"8230dddab7c73aa75c9fcb9647c57af37c015e57223ac1706cf7e73e810559dc","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","src/lib.rs":"058dddad16d91c8d0160fa2a78bb5f7c2f801f2fd9770fc387c5843395bf0379","src/parking_lot.rs":"15c2c91f05ca117bb47fbaeb65e19cb039aab0064301c5113c2a48c86b76f5da","src/spinwait.rs":"d568d8a81f9144ec4c4a139dc934d7d04ee1656a4a221eb548742fe7aba09ab1","src/thread_parker/cloudabi.rs":"0668b50898c20e7267ac6cc977e7ad376a18958e2d07faeca8199794d873d2eb","src/thread_parker/generic.rs":"2f501c6e46fcff434ba9e13ae8859e66de3327f601ed92989b310124e4129ff4","src/thread_parker/linux.rs":"853fd22f51215d1f553ad6461ad3c92c4ec9c294e607e69ed5f53b2e8c7a11d7","src/thread_parker/mod.rs":"5bc2100d2f575608b5b76e626ca92ce3ba4830176ecc773c5594cda6ca0905e9","src/thread_parker/redox.rs":"081c76af1e24be12da45d8093e261c48d558342ac2ac64dc3f7dd95eaaa1bf11","src/thread_parker/sgx.rs":"3fd71a7066db58189f302d2344e4e425320f82c298ca482ca4318bae44ae37fd","src/thread_parker/unix.rs":"77e1f049207b7e89b22ef05e5134c7538b31fff99aa9660784136f96fec1845a","src/thread_parker/wasm.rs":"b4c9f9e9c1fd636b235a0e8e0227c954b1e7432d8394b58af77b348cdfa2141e","src/thread_parker/wasm_atomic.rs":"a1ab05981a833e72d8d353350ab2b95e6f833cd7224591e595ccdb3692968c23","src/thread_parker/windows/keyed_event.rs":"34fc4693e7afd69a5c426ae7face83b8363f114a44dece44197cd03861cfdded","src/thread_parker/windows/mod.rs":"7702ff9b72ac647ec998a9b205ace961a28839fcd94631fb750ca459e4804260","src/thread_parker/windows/waitaddress.rs":"06d994633006e237dc940f377432ea00cf1609e56096d69d46f7bb3b80eeb857","src/util.rs":"285e6133150645525f2ca1ece41f6d35bad4e7c5e08b42b20c99d2a97e04a974","src/word_lock.rs":"2c030aedb340ae8ca564365206452c298fe29986d005d6a40e808c9760f91c95"},"package":"d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"} \ No newline at end of file diff --git a/vendor/parking_lot_core-0.7.2/Cargo.toml b/vendor/parking_lot_core-0.7.2/Cargo.toml deleted file mode 100644 index d24a5cacb7..0000000000 --- a/vendor/parking_lot_core-0.7.2/Cargo.toml +++ /dev/null @@ -1,52 +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 = "parking_lot_core" -version = "0.7.2" -authors = ["Amanieu d'Antras "] -description = "An advanced API for creating custom synchronization primitives." -keywords = ["mutex", "condvar", "rwlock", "once", "thread"] -categories = ["concurrency"] -license = "Apache-2.0/MIT" -repository = "https://github.com/Amanieu/parking_lot" -[dependencies.backtrace] -version = "0.3.2" -optional = true - -[dependencies.cfg-if] -version = "0.1.5" - -[dependencies.petgraph] -version = "0.5" -optional = true - -[dependencies.smallvec] -version = "1.0" - -[dependencies.thread-id] -version = "3.2.0" -optional = true - -[features] -deadlock_detection = ["petgraph", "thread-id", "backtrace"] -nightly = [] -[target."cfg(target_os = \"cloudabi\")".dependencies.cloudabi] -version = "0.0.3" -[target."cfg(target_os = \"redox\")".dependencies.redox_syscall] -version = "0.1" -[target."cfg(unix)".dependencies.libc] -version = "0.2.55" -[target."cfg(windows)".dependencies.winapi] -version = "0.3" -features = ["winnt", "ntstatus", "minwindef", "winerror", "winbase", "errhandlingapi", "handleapi"] diff --git a/vendor/parking_lot_core-0.7.2/src/lib.rs b/vendor/parking_lot_core-0.7.2/src/lib.rs deleted file mode 100644 index ba4cb1e8c9..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/lib.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -//! This library exposes a low-level API for creating your own efficient -//! synchronization primitives. -//! -//! # The parking lot -//! -//! To keep synchronization primitives small, all thread queuing and suspending -//! functionality is offloaded to the *parking lot*. The idea behind this is based -//! on the Webkit [`WTF::ParkingLot`](https://webkit.org/blog/6161/locking-in-webkit/) -//! class, which essentially consists of a hash table mapping of lock addresses -//! to queues of parked (sleeping) threads. The Webkit parking lot was itself -//! inspired by Linux [futexes](http://man7.org/linux/man-pages/man2/futex.2.html), -//! but it is more powerful since it allows invoking callbacks while holding a -//! queue lock. -//! -//! There are two main operations that can be performed on the parking lot: -//! -//! - *Parking* refers to suspending the thread while simultaneously enqueuing it -//! on a queue keyed by some address. -//! - *Unparking* refers to dequeuing a thread from a queue keyed by some address -//! and resuming it. -//! -//! See the documentation of the individual functions for more details. -//! -//! # Building custom synchronization primitives -//! -//! Building custom synchronization primitives is very simple since the parking -//! lot takes care of all the hard parts for you. A simple example for a -//! custom primitive would be to integrate a `Mutex` inside another data type. -//! Since a mutex only requires 2 bits, it can share space with other data. -//! For example, one could create an `ArcMutex` type that combines the atomic -//! reference count and the two mutex bits in the same atomic word. - -#![warn(missing_docs)] -#![warn(rust_2018_idioms)] -#![cfg_attr( - all(target_env = "sgx", target_vendor = "fortanix"), - feature(sgx_platform) -)] -#![cfg_attr( - all( - feature = "nightly", - target_arch = "wasm32", - target_feature = "atomics" - ), - feature(stdsimd) -)] -#![cfg_attr( - all(feature = "nightly", target_os = "cloudabi",), - feature(thread_local) -)] - -mod parking_lot; -mod spinwait; -mod thread_parker; -mod util; -mod word_lock; - -pub use self::parking_lot::deadlock; -pub use self::parking_lot::{park, unpark_all, unpark_filter, unpark_one, unpark_requeue}; -pub use self::parking_lot::{ - FilterOp, ParkResult, ParkToken, RequeueOp, UnparkResult, UnparkToken, -}; -pub use self::parking_lot::{DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN}; -pub use self::spinwait::SpinWait; diff --git a/vendor/parking_lot_core-0.7.2/src/parking_lot.rs b/vendor/parking_lot_core-0.7.2/src/parking_lot.rs deleted file mode 100644 index 440b7c7063..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/parking_lot.rs +++ /dev/null @@ -1,1708 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. -use cfg_if::cfg_if; -use crate::thread_parker::{ThreadParker, ThreadParkerT, UnparkHandleT}; -use crate::util::UncheckedOptionExt; -use crate::word_lock::WordLock; -use core::{ - cell::{Cell, UnsafeCell}, - ptr, - sync::atomic::{AtomicPtr, AtomicUsize, Ordering}, -}; -use smallvec::SmallVec; -use std::time::{Duration, Instant}; - -cfg_if! { - if #[cfg(all( - target_arch = "wasm32", - target_os = "unknown", - target_vendor = "unknown" - ))] { - use core::ops::Add; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] - struct DummyInstant(Duration); - - impl DummyInstant { - pub fn now() -> DummyInstant { - DummyInstant::zero() - } - - const fn zero() -> DummyInstant { - DummyInstant(Duration::from_secs(0)) - } - } - - impl Add for DummyInstant { - type Output = DummyInstant; - - fn add(self, _rhs: Duration) -> DummyInstant { - DummyInstant::zero() - } - } - - // Use dummy implementation for `Instant` on `wasm32`. The reason for this is - // that `Instant::now()` will always panic because time is currently not implemented - // on wasm32-unknown-unknown. - // See https://github.com/rust-lang/rust/blob/master/src/libstd/sys/wasm/time.rs - type InstantType = DummyInstant; - } else { - // Otherwise use `std::time::Instant` - type InstantType = Instant; - } -} - -static NUM_THREADS: AtomicUsize = AtomicUsize::new(0); - -/// Holds the pointer to the currently active `HashTable`. -/// -/// # Safety -/// -/// Except for the initial value of null, it must always point to a valid `HashTable` instance. -/// Any `HashTable` this global static has ever pointed to must never be freed. -static HASHTABLE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - -// Even with 3x more buckets than threads, the memory overhead per thread is -// still only a few hundred bytes per thread. -const LOAD_FACTOR: usize = 3; - -struct HashTable { - // Hash buckets for the table - entries: Box<[Bucket]>, - - // Number of bits used for the hash function - hash_bits: u32, - - // Previous table. This is only kept to keep leak detectors happy. - _prev: *const HashTable, -} - -impl HashTable { - #[inline] - fn new(num_threads: usize, prev: *const HashTable) -> Box { - let new_size = (num_threads * LOAD_FACTOR).next_power_of_two(); - let hash_bits = 0usize.leading_zeros() - new_size.leading_zeros() - 1; - - let now = InstantType::now(); - let mut entries = Vec::with_capacity(new_size); - for i in 0..new_size { - // We must ensure the seed is not zero - entries.push(Bucket::new(now, i as u32 + 1)); - } - - Box::new(HashTable { - entries: entries.into_boxed_slice(), - hash_bits, - _prev: prev, - }) - } -} - -#[repr(align(64))] -struct Bucket { - // Lock protecting the queue - mutex: WordLock, - - // Linked list of threads waiting on this bucket - queue_head: Cell<*const ThreadData>, - queue_tail: Cell<*const ThreadData>, - - // Next time at which point be_fair should be set - fair_timeout: UnsafeCell, -} - -impl Bucket { - #[inline] - pub fn new(timeout: InstantType, seed: u32) -> Self { - Self { - mutex: WordLock::new(), - queue_head: Cell::new(ptr::null()), - queue_tail: Cell::new(ptr::null()), - fair_timeout: UnsafeCell::new(FairTimeout::new(timeout, seed)), - } - } -} - -struct FairTimeout { - // Next time at which point be_fair should be set - timeout: InstantType, - - // the PRNG state for calculating the next timeout - seed: u32, -} - -impl FairTimeout { - #[inline] - fn new(timeout: InstantType, seed: u32) -> FairTimeout { - FairTimeout { timeout, seed } - } - - // Determine whether we should force a fair unlock, and update the timeout - #[inline] - fn should_timeout(&mut self) -> bool { - let now = InstantType::now(); - if now > self.timeout { - // Time between 0 and 1ms. - let nanos = self.gen_u32() % 1_000_000; - self.timeout = now + Duration::new(0, nanos); - true - } else { - false - } - } - - // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia. - fn gen_u32(&mut self) -> u32 { - self.seed ^= self.seed << 13; - self.seed ^= self.seed >> 17; - self.seed ^= self.seed << 5; - self.seed - } -} - -struct ThreadData { - parker: ThreadParker, - - // Key that this thread is sleeping on. This may change if the thread is - // requeued to a different key. - key: AtomicUsize, - - // Linked list of parked threads in a bucket - next_in_queue: Cell<*const ThreadData>, - - // UnparkToken passed to this thread when it is unparked - unpark_token: Cell, - - // ParkToken value set by the thread when it was parked - park_token: Cell, - - // Is the thread parked with a timeout? - parked_with_timeout: Cell, - - // Extra data for deadlock detection - #[cfg(feature = "deadlock_detection")] - deadlock_data: deadlock::DeadlockData, -} - -impl ThreadData { - fn new() -> ThreadData { - // Keep track of the total number of live ThreadData objects and resize - // the hash table accordingly. - let num_threads = NUM_THREADS.fetch_add(1, Ordering::Relaxed) + 1; - grow_hashtable(num_threads); - - ThreadData { - parker: ThreadParker::new(), - key: AtomicUsize::new(0), - next_in_queue: Cell::new(ptr::null()), - unpark_token: Cell::new(DEFAULT_UNPARK_TOKEN), - park_token: Cell::new(DEFAULT_PARK_TOKEN), - parked_with_timeout: Cell::new(false), - #[cfg(feature = "deadlock_detection")] - deadlock_data: deadlock::DeadlockData::new(), - } - } -} - -// Invokes the given closure with a reference to the current thread `ThreadData`. -#[inline(always)] -fn with_thread_data(f: impl FnOnce(&ThreadData) -> T) -> T { - // Unlike word_lock::ThreadData, parking_lot::ThreadData is always expensive - // to construct. Try to use a thread-local version if possible. Otherwise just - // create a ThreadData on the stack - let mut thread_data_storage = None; - thread_local!(static THREAD_DATA: ThreadData = ThreadData::new()); - let thread_data_ptr = THREAD_DATA - .try_with(|x| x as *const ThreadData) - .unwrap_or_else(|_| thread_data_storage.get_or_insert_with(ThreadData::new)); - - f(unsafe { &*thread_data_ptr }) -} - -impl Drop for ThreadData { - fn drop(&mut self) { - NUM_THREADS.fetch_sub(1, Ordering::Relaxed); - } -} - -/// Returns a reference to the latest hash table, creating one if it doesn't exist yet. -/// The reference is valid forever. However, the `HashTable` it references might become stale -/// at any point. Meaning it still exists, but it is not the instance in active use. -#[inline] -fn get_hashtable() -> &'static HashTable { - let table = HASHTABLE.load(Ordering::Acquire); - - // If there is no table, create one - if table.is_null() { - create_hashtable() - } else { - // SAFETY: when not null, `HASHTABLE` always points to a `HashTable` that is never freed. - unsafe { &*table } - } -} - -/// Returns a reference to the latest hash table, creating one if it doesn't exist yet. -/// The reference is valid forever. However, the `HashTable` it references might become stale -/// at any point. Meaning it still exists, but it is not the instance in active use. -#[cold] -fn create_hashtable() -> &'static HashTable { - let new_table = Box::into_raw(HashTable::new(LOAD_FACTOR, ptr::null())); - - // If this fails then it means some other thread created the hash table first. - let table = match HASHTABLE.compare_exchange( - ptr::null_mut(), - new_table, - Ordering::AcqRel, - Ordering::Acquire, - ) { - Ok(_) => new_table, - Err(old_table) => { - // Free the table we created - // SAFETY: `new_table` is created from `Box::into_raw` above and only freed here. - unsafe { - Box::from_raw(new_table); - } - old_table - } - }; - // SAFETY: The `HashTable` behind `table` is never freed. It is either the table pointer we - // created here, or it is one loaded from `HASHTABLE`. - unsafe { &*table } -} - -// Grow the hash table so that it is big enough for the given number of threads. -// This isn't performance-critical since it is only done when a ThreadData is -// created, which only happens once per thread. -fn grow_hashtable(num_threads: usize) { - // Lock all buckets in the existing table and get a reference to it - let old_table = loop { - let table = get_hashtable(); - - // Check if we need to resize the existing table - if table.entries.len() >= LOAD_FACTOR * num_threads { - return; - } - - // Lock all buckets in the old table - for bucket in &table.entries[..] { - bucket.mutex.lock(); - } - - // Now check if our table is still the latest one. Another thread could - // have grown the hash table between us reading HASHTABLE and locking - // the buckets. - if HASHTABLE.load(Ordering::Relaxed) == table as *const _ as *mut _ { - break table; - } - - // Unlock buckets and try again - for bucket in &table.entries[..] { - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } - }; - - // Create the new table - let mut new_table = HashTable::new(num_threads, old_table); - - // Move the entries from the old table to the new one - for bucket in &old_table.entries[..] { - // SAFETY: The park, unpark* and check_wait_graph_fast functions create only correct linked - // lists. All `ThreadData` instances in these lists will remain valid as long as they are - // present in the lists, meaning as long as their threads are parked. - unsafe { rehash_bucket_into(bucket, &mut new_table) }; - } - - // Publish the new table. No races are possible at this point because - // any other thread trying to grow the hash table is blocked on the bucket - // locks in the old table. - HASHTABLE.store(Box::into_raw(new_table), Ordering::Release); - - // Unlock all buckets in the old table - for bucket in &old_table.entries[..] { - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } -} - -/// Iterate through all `ThreadData` objects in the bucket and insert them into the given table -/// in the bucket their key correspond to for this table. -/// -/// # Safety -/// -/// The given `bucket` must have a correctly constructed linked list under `queue_head`, containing -/// `ThreadData` instances that must stay valid at least as long as the given `table` is in use. -/// -/// The given `table` must only contain buckets with correctly constructed linked lists. -unsafe fn rehash_bucket_into(bucket: &'static Bucket, table: &mut HashTable) { - let mut current: *const ThreadData = bucket.queue_head.get(); - while !current.is_null() { - let next = (*current).next_in_queue.get(); - let hash = hash((*current).key.load(Ordering::Relaxed), table.hash_bits); - if table.entries[hash].queue_tail.get().is_null() { - table.entries[hash].queue_head.set(current); - } else { - (*table.entries[hash].queue_tail.get()) - .next_in_queue - .set(current); - } - table.entries[hash].queue_tail.set(current); - (*current).next_in_queue.set(ptr::null()); - current = next; - } -} - -// Hash function for addresses -#[cfg(target_pointer_width = "32")] -#[inline] -fn hash(key: usize, bits: u32) -> usize { - key.wrapping_mul(0x9E3779B9) >> (32 - bits) -} -#[cfg(target_pointer_width = "64")] -#[inline] -fn hash(key: usize, bits: u32) -> usize { - key.wrapping_mul(0x9E3779B97F4A7C15) >> (64 - bits) -} - -/// Locks the bucket for the given key and returns a reference to it. -/// The returned bucket must be unlocked again in order to not cause deadlocks. -#[inline] -fn lock_bucket(key: usize) -> &'static Bucket { - loop { - let hashtable = get_hashtable(); - - let hash = hash(key, hashtable.hash_bits); - let bucket = &hashtable.entries[hash]; - - // Lock the bucket - bucket.mutex.lock(); - - // If no other thread has rehashed the table before we grabbed the lock - // then we are good to go! The lock we grabbed prevents any rehashes. - if HASHTABLE.load(Ordering::Relaxed) == hashtable as *const _ as *mut _ { - return bucket; - } - - // Unlock the bucket and try again - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } -} - -/// Locks the bucket for the given key and returns a reference to it. But checks that the key -/// hasn't been changed in the meantime due to a requeue. -/// The returned bucket must be unlocked again in order to not cause deadlocks. -#[inline] -fn lock_bucket_checked(key: &AtomicUsize) -> (usize, &'static Bucket) { - loop { - let hashtable = get_hashtable(); - let current_key = key.load(Ordering::Relaxed); - - let hash = hash(current_key, hashtable.hash_bits); - let bucket = &hashtable.entries[hash]; - - // Lock the bucket - bucket.mutex.lock(); - - // Check that both the hash table and key are correct while the bucket - // is locked. Note that the key can't change once we locked the proper - // bucket for it, so we just keep trying until we have the correct key. - if HASHTABLE.load(Ordering::Relaxed) == hashtable as *const _ as *mut _ - && key.load(Ordering::Relaxed) == current_key - { - return (current_key, bucket); - } - - // Unlock the bucket and try again - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } -} - -/// Locks the two buckets for the given pair of keys and returns references to them. -/// The returned buckets must be unlocked again in order to not cause deadlocks. -/// -/// If both keys hash to the same value, both returned references will be to the same bucket. Be -/// careful to only unlock it once in this case, always use `unlock_bucket_pair`. -#[inline] -fn lock_bucket_pair(key1: usize, key2: usize) -> (&'static Bucket, &'static Bucket) { - loop { - let hashtable = get_hashtable(); - - let hash1 = hash(key1, hashtable.hash_bits); - let hash2 = hash(key2, hashtable.hash_bits); - - // Get the bucket at the lowest hash/index first - let bucket1 = if hash1 <= hash2 { - &hashtable.entries[hash1] - } else { - &hashtable.entries[hash2] - }; - - // Lock the first bucket - bucket1.mutex.lock(); - - // If no other thread has rehashed the table before we grabbed the lock - // then we are good to go! The lock we grabbed prevents any rehashes. - if HASHTABLE.load(Ordering::Relaxed) == hashtable as *const _ as *mut _ { - // Now lock the second bucket and return the two buckets - if hash1 == hash2 { - return (bucket1, bucket1); - } else if hash1 < hash2 { - let bucket2 = &hashtable.entries[hash2]; - bucket2.mutex.lock(); - return (bucket1, bucket2); - } else { - let bucket2 = &hashtable.entries[hash1]; - bucket2.mutex.lock(); - return (bucket2, bucket1); - } - } - - // Unlock the bucket and try again - // SAFETY: We hold the lock here, as required - unsafe { bucket1.mutex.unlock() }; - } -} - -/// Unlock a pair of buckets -/// -/// # Safety -/// -/// Both buckets must be locked -#[inline] -unsafe fn unlock_bucket_pair(bucket1: &Bucket, bucket2: &Bucket) { - bucket1.mutex.unlock(); - if !ptr::eq(bucket1, bucket2) { - bucket2.mutex.unlock(); - } -} - -/// Result of a park operation. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum ParkResult { - /// We were unparked by another thread with the given token. - Unparked(UnparkToken), - - /// The validation callback returned false. - Invalid, - - /// The timeout expired. - TimedOut, -} - -impl ParkResult { - /// Returns true if we were unparked by another thread. - #[inline] - pub fn is_unparked(self) -> bool { - if let ParkResult::Unparked(_) = self { - true - } else { - false - } - } -} - -/// Result of an unpark operation. -#[derive(Copy, Clone, Default, Eq, PartialEq, Debug)] -pub struct UnparkResult { - /// The number of threads that were unparked. - pub unparked_threads: usize, - - /// The number of threads that were requeued. - pub requeued_threads: usize, - - /// Whether there are any threads remaining in the queue. This only returns - /// true if a thread was unparked. - pub have_more_threads: bool, - - /// This is set to true on average once every 0.5ms for any given key. It - /// should be used to switch to a fair unlocking mechanism for a particular - /// unlock. - pub be_fair: bool, - - /// Private field so new fields can be added without breakage. - _sealed: (), -} - -/// Operation that `unpark_requeue` should perform. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum RequeueOp { - /// Abort the operation without doing anything. - Abort, - - /// Unpark one thread and requeue the rest onto the target queue. - UnparkOneRequeueRest, - - /// Requeue all threads onto the target queue. - RequeueAll, - - /// Unpark one thread and leave the rest parked. No requeuing is done. - UnparkOne, - - /// Requeue one thread and leave the rest parked on the original queue. - RequeueOne, -} - -/// Operation that `unpark_filter` should perform for each thread. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum FilterOp { - /// Unpark the thread and continue scanning the list of parked threads. - Unpark, - - /// Don't unpark the thread and continue scanning the list of parked threads. - Skip, - - /// Don't unpark the thread and stop scanning the list of parked threads. - Stop, -} - -/// A value which is passed from an unparker to a parked thread. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct UnparkToken(pub usize); - -/// A value associated with a parked thread which can be used by `unpark_filter`. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct ParkToken(pub usize); - -/// A default unpark token to use. -pub const DEFAULT_UNPARK_TOKEN: UnparkToken = UnparkToken(0); - -/// A default park token to use. -pub const DEFAULT_PARK_TOKEN: ParkToken = ParkToken(0); - -/// Parks the current thread in the queue associated with the given key. -/// -/// The `validate` function is called while the queue is locked and can abort -/// the operation by returning false. If `validate` returns true then the -/// current thread is appended to the queue and the queue is unlocked. -/// -/// The `before_sleep` function is called after the queue is unlocked but before -/// the thread is put to sleep. The thread will then sleep until it is unparked -/// or the given timeout is reached. -/// -/// The `timed_out` function is also called while the queue is locked, but only -/// if the timeout was reached. It is passed the key of the queue it was in when -/// it timed out, which may be different from the original key if -/// `unpark_requeue` was called. It is also passed a bool which indicates -/// whether it was the last thread in the queue. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -/// -/// The `validate` and `timed_out` functions are called while the queue is -/// locked and must not panic or call into any function in `parking_lot`. -/// -/// The `before_sleep` function is called outside the queue lock and is allowed -/// to call `unpark_one`, `unpark_all`, `unpark_requeue` or `unpark_filter`, but -/// it is not allowed to call `park` or panic. -#[inline] -pub unsafe fn park( - key: usize, - validate: impl FnOnce() -> bool, - before_sleep: impl FnOnce(), - timed_out: impl FnOnce(usize, bool), - park_token: ParkToken, - timeout: Option, -) -> ParkResult { - // Grab our thread data, this also ensures that the hash table exists - with_thread_data(|thread_data| { - // Lock the bucket for the given key - let bucket = lock_bucket(key); - - // If the validation function fails, just return - if !validate() { - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - return ParkResult::Invalid; - } - - // Append our thread data to the queue and unlock the bucket - thread_data.parked_with_timeout.set(timeout.is_some()); - thread_data.next_in_queue.set(ptr::null()); - thread_data.key.store(key, Ordering::Relaxed); - thread_data.park_token.set(park_token); - thread_data.parker.prepare_park(); - if !bucket.queue_head.get().is_null() { - (*bucket.queue_tail.get()).next_in_queue.set(thread_data); - } else { - bucket.queue_head.set(thread_data); - } - bucket.queue_tail.set(thread_data); - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - - // Invoke the pre-sleep callback - before_sleep(); - - // Park our thread and determine whether we were woken up by an unpark - // or by our timeout. Note that this isn't precise: we can still be - // unparked since we are still in the queue. - let unparked = match timeout { - Some(timeout) => thread_data.parker.park_until(timeout), - None => { - thread_data.parker.park(); - // call deadlock detection on_unpark hook - deadlock::on_unpark(thread_data); - true - } - }; - - // If we were unparked, return now - if unparked { - return ParkResult::Unparked(thread_data.unpark_token.get()); - } - - // Lock our bucket again. Note that the hashtable may have been rehashed in - // the meantime. Our key may also have changed if we were requeued. - let (key, bucket) = lock_bucket_checked(&thread_data.key); - - // Now we need to check again if we were unparked or timed out. Unlike the - // last check this is precise because we hold the bucket lock. - if !thread_data.parker.timed_out() { - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - return ParkResult::Unparked(thread_data.unpark_token.get()); - } - - // We timed out, so we now need to remove our thread from the queue - let mut link = &bucket.queue_head; - let mut current = bucket.queue_head.get(); - let mut previous = ptr::null(); - let mut was_last_thread = true; - while !current.is_null() { - if current == thread_data { - let next = (*current).next_in_queue.get(); - link.set(next); - if bucket.queue_tail.get() == current { - bucket.queue_tail.set(previous); - } else { - // Scan the rest of the queue to see if there are any other - // entries with the given key. - let mut scan = next; - while !scan.is_null() { - if (*scan).key.load(Ordering::Relaxed) == key { - was_last_thread = false; - break; - } - scan = (*scan).next_in_queue.get(); - } - } - - // Callback to indicate that we timed out, and whether we were the - // last thread on the queue. - timed_out(key, was_last_thread); - break; - } else { - if (*current).key.load(Ordering::Relaxed) == key { - was_last_thread = false; - } - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // There should be no way for our thread to have been removed from the queue - // if we timed out. - debug_assert!(!current.is_null()); - - // Unlock the bucket, we are done - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - ParkResult::TimedOut - }) -} - -/// Unparks one thread from the queue associated with the given key. -/// -/// The `callback` function is called while the queue is locked and before the -/// target thread is woken up. The `UnparkResult` argument to the function -/// indicates whether a thread was found in the queue and whether this was the -/// last thread in the queue. This value is also returned by `unpark_one`. -/// -/// The `callback` function should return an `UnparkToken` value which will be -/// passed to the thread that is unparked. If no thread is unparked then the -/// returned value is ignored. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -/// -/// The `callback` function is called while the queue is locked and must not -/// panic or call into any function in `parking_lot`. -#[inline] -pub unsafe fn unpark_one( - key: usize, - callback: impl FnOnce(UnparkResult) -> UnparkToken, -) -> UnparkResult { - // Lock the bucket for the given key - let bucket = lock_bucket(key); - - // Find a thread with a matching key and remove it from the queue - let mut link = &bucket.queue_head; - let mut current = bucket.queue_head.get(); - let mut previous = ptr::null(); - let mut result = UnparkResult::default(); - while !current.is_null() { - if (*current).key.load(Ordering::Relaxed) == key { - // Remove the thread from the queue - let next = (*current).next_in_queue.get(); - link.set(next); - if bucket.queue_tail.get() == current { - bucket.queue_tail.set(previous); - } else { - // Scan the rest of the queue to see if there are any other - // entries with the given key. - let mut scan = next; - while !scan.is_null() { - if (*scan).key.load(Ordering::Relaxed) == key { - result.have_more_threads = true; - break; - } - scan = (*scan).next_in_queue.get(); - } - } - - // Invoke the callback before waking up the thread - result.unparked_threads = 1; - result.be_fair = (*bucket.fair_timeout.get()).should_timeout(); - let token = callback(result); - - // Set the token for the target thread - (*current).unpark_token.set(token); - - // This is a bit tricky: we first lock the ThreadParker to prevent - // the thread from exiting and freeing its ThreadData if its wait - // times out. Then we unlock the queue since we don't want to keep - // the queue locked while we perform a system call. Finally we wake - // up the parked thread. - let handle = (*current).parker.unpark_lock(); - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - handle.unpark(); - - return result; - } else { - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // No threads with a matching key were found in the bucket - callback(result); - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - result -} - -/// Unparks all threads in the queue associated with the given key. -/// -/// The given `UnparkToken` is passed to all unparked threads. -/// -/// This function returns the number of threads that were unparked. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -#[inline] -pub unsafe fn unpark_all(key: usize, unpark_token: UnparkToken) -> usize { - // Lock the bucket for the given key - let bucket = lock_bucket(key); - - // Remove all threads with the given key in the bucket - let mut link = &bucket.queue_head; - let mut current = bucket.queue_head.get(); - let mut previous = ptr::null(); - let mut threads = SmallVec::<[_; 8]>::new(); - while !current.is_null() { - if (*current).key.load(Ordering::Relaxed) == key { - // Remove the thread from the queue - let next = (*current).next_in_queue.get(); - link.set(next); - if bucket.queue_tail.get() == current { - bucket.queue_tail.set(previous); - } - - // Set the token for the target thread - (*current).unpark_token.set(unpark_token); - - // Don't wake up threads while holding the queue lock. See comment - // in unpark_one. For now just record which threads we need to wake - // up. - threads.push((*current).parker.unpark_lock()); - current = next; - } else { - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // Unlock the bucket - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - - // Now that we are outside the lock, wake up all the threads that we removed - // from the queue. - let num_threads = threads.len(); - for handle in threads.into_iter() { - handle.unpark(); - } - - num_threads -} - -/// Removes all threads from the queue associated with `key_from`, optionally -/// unparks the first one and requeues the rest onto the queue associated with -/// `key_to`. -/// -/// The `validate` function is called while both queues are locked. Its return -/// value will determine which operation is performed, or whether the operation -/// should be aborted. See `RequeueOp` for details about the different possible -/// return values. -/// -/// The `callback` function is also called while both queues are locked. It is -/// passed the `RequeueOp` returned by `validate` and an `UnparkResult` -/// indicating whether a thread was unparked and whether there are threads still -/// parked in the new queue. This `UnparkResult` value is also returned by -/// `unpark_requeue`. -/// -/// The `callback` function should return an `UnparkToken` value which will be -/// passed to the thread that is unparked. If no thread is unparked then the -/// returned value is ignored. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -/// -/// The `validate` and `callback` functions are called while the queue is locked -/// and must not panic or call into any function in `parking_lot`. -#[inline] -pub unsafe fn unpark_requeue( - key_from: usize, - key_to: usize, - validate: impl FnOnce() -> RequeueOp, - callback: impl FnOnce(RequeueOp, UnparkResult) -> UnparkToken, -) -> UnparkResult { - // Lock the two buckets for the given key - let (bucket_from, bucket_to) = lock_bucket_pair(key_from, key_to); - - // If the validation function fails, just return - let mut result = UnparkResult::default(); - let op = validate(); - if op == RequeueOp::Abort { - // SAFETY: Both buckets are locked, as required. - unlock_bucket_pair(bucket_from, bucket_to); - return result; - } - - // Remove all threads with the given key in the source bucket - let mut link = &bucket_from.queue_head; - let mut current = bucket_from.queue_head.get(); - let mut previous = ptr::null(); - let mut requeue_threads: *const ThreadData = ptr::null(); - let mut requeue_threads_tail: *const ThreadData = ptr::null(); - let mut wakeup_thread = None; - while !current.is_null() { - if (*current).key.load(Ordering::Relaxed) == key_from { - // Remove the thread from the queue - let next = (*current).next_in_queue.get(); - link.set(next); - if bucket_from.queue_tail.get() == current { - bucket_from.queue_tail.set(previous); - } - - // Prepare the first thread for wakeup and requeue the rest. - if (op == RequeueOp::UnparkOneRequeueRest || op == RequeueOp::UnparkOne) - && wakeup_thread.is_none() - { - wakeup_thread = Some(current); - result.unparked_threads = 1; - } else { - if !requeue_threads.is_null() { - (*requeue_threads_tail).next_in_queue.set(current); - } else { - requeue_threads = current; - } - requeue_threads_tail = current; - (*current).key.store(key_to, Ordering::Relaxed); - result.requeued_threads += 1; - } - if op == RequeueOp::UnparkOne || op == RequeueOp::RequeueOne { - // Scan the rest of the queue to see if there are any other - // entries with the given key. - let mut scan = next; - while !scan.is_null() { - if (*scan).key.load(Ordering::Relaxed) == key_from { - result.have_more_threads = true; - break; - } - scan = (*scan).next_in_queue.get(); - } - break; - } - current = next; - } else { - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // Add the requeued threads to the destination bucket - if !requeue_threads.is_null() { - (*requeue_threads_tail).next_in_queue.set(ptr::null()); - if !bucket_to.queue_head.get().is_null() { - (*bucket_to.queue_tail.get()) - .next_in_queue - .set(requeue_threads); - } else { - bucket_to.queue_head.set(requeue_threads); - } - bucket_to.queue_tail.set(requeue_threads_tail); - } - - // Invoke the callback before waking up the thread - if result.unparked_threads != 0 { - result.be_fair = (*bucket_from.fair_timeout.get()).should_timeout(); - } - let token = callback(op, result); - - // See comment in unpark_one for why we mess with the locking - if let Some(wakeup_thread) = wakeup_thread { - (*wakeup_thread).unpark_token.set(token); - let handle = (*wakeup_thread).parker.unpark_lock(); - // SAFETY: Both buckets are locked, as required. - unlock_bucket_pair(bucket_from, bucket_to); - handle.unpark(); - } else { - // SAFETY: Both buckets are locked, as required. - unlock_bucket_pair(bucket_from, bucket_to); - } - - result -} - -/// Unparks a number of threads from the front of the queue associated with -/// `key` depending on the results of a filter function which inspects the -/// `ParkToken` associated with each thread. -/// -/// The `filter` function is called for each thread in the queue or until -/// `FilterOp::Stop` is returned. This function is passed the `ParkToken` -/// associated with a particular thread, which is unparked if `FilterOp::Unpark` -/// is returned. -/// -/// The `callback` function is also called while both queues are locked. It is -/// passed an `UnparkResult` indicating the number of threads that were unparked -/// and whether there are still parked threads in the queue. This `UnparkResult` -/// value is also returned by `unpark_filter`. -/// -/// The `callback` function should return an `UnparkToken` value which will be -/// passed to all threads that are unparked. If no thread is unparked then the -/// returned value is ignored. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -/// -/// The `filter` and `callback` functions are called while the queue is locked -/// and must not panic or call into any function in `parking_lot`. -#[inline] -pub unsafe fn unpark_filter( - key: usize, - mut filter: impl FnMut(ParkToken) -> FilterOp, - callback: impl FnOnce(UnparkResult) -> UnparkToken, -) -> UnparkResult { - // Lock the bucket for the given key - let bucket = lock_bucket(key); - - // Go through the queue looking for threads with a matching key - let mut link = &bucket.queue_head; - let mut current = bucket.queue_head.get(); - let mut previous = ptr::null(); - let mut threads = SmallVec::<[_; 8]>::new(); - let mut result = UnparkResult::default(); - while !current.is_null() { - if (*current).key.load(Ordering::Relaxed) == key { - // Call the filter function with the thread's ParkToken - let next = (*current).next_in_queue.get(); - match filter((*current).park_token.get()) { - FilterOp::Unpark => { - // Remove the thread from the queue - link.set(next); - if bucket.queue_tail.get() == current { - bucket.queue_tail.set(previous); - } - - // Add the thread to our list of threads to unpark - threads.push((current, None)); - - current = next; - } - FilterOp::Skip => { - result.have_more_threads = true; - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - FilterOp::Stop => { - result.have_more_threads = true; - break; - } - } - } else { - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // Invoke the callback before waking up the threads - result.unparked_threads = threads.len(); - if result.unparked_threads != 0 { - result.be_fair = (*bucket.fair_timeout.get()).should_timeout(); - } - let token = callback(result); - - // Pass the token to all threads that are going to be unparked and prepare - // them for unparking. - for t in threads.iter_mut() { - (*t.0).unpark_token.set(token); - t.1 = Some((*t.0).parker.unpark_lock()); - } - - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - - // Now that we are outside the lock, wake up all the threads that we removed - // from the queue. - for (_, handle) in threads.into_iter() { - handle.unchecked_unwrap().unpark(); - } - - result -} - -/// \[Experimental\] Deadlock detection -/// -/// Enabled via the `deadlock_detection` feature flag. -pub mod deadlock { - #[cfg(feature = "deadlock_detection")] - use super::deadlock_impl; - - #[cfg(feature = "deadlock_detection")] - pub(super) use super::deadlock_impl::DeadlockData; - - /// Acquire a resource identified by key in the deadlock detector - /// Noop if deadlock_detection feature isn't enabled. - /// - /// # Safety - /// - /// Call after the resource is acquired - #[inline] - pub unsafe fn acquire_resource(_key: usize) { - #[cfg(feature = "deadlock_detection")] - deadlock_impl::acquire_resource(_key); - } - - /// Release a resource identified by key in the deadlock detector. - /// Noop if deadlock_detection feature isn't enabled. - /// - /// # Panics - /// - /// Panics if the resource was already released or wasn't acquired in this thread. - /// - /// # Safety - /// - /// Call before the resource is released - #[inline] - pub unsafe fn release_resource(_key: usize) { - #[cfg(feature = "deadlock_detection")] - deadlock_impl::release_resource(_key); - } - - /// Returns all deadlocks detected *since* the last call. - /// Each cycle consist of a vector of `DeadlockedThread`. - #[cfg(feature = "deadlock_detection")] - #[inline] - pub fn check_deadlock() -> Vec> { - deadlock_impl::check_deadlock() - } - - #[inline] - pub(super) unsafe fn on_unpark(_td: &super::ThreadData) { - #[cfg(feature = "deadlock_detection")] - deadlock_impl::on_unpark(_td); - } -} - -#[cfg(feature = "deadlock_detection")] -mod deadlock_impl { - use super::{get_hashtable, lock_bucket, with_thread_data, ThreadData, NUM_THREADS}; - use crate::thread_parker::{ThreadParkerT, UnparkHandleT}; - use crate::word_lock::WordLock; - use backtrace::Backtrace; - use petgraph; - use petgraph::graphmap::DiGraphMap; - use std::cell::{Cell, UnsafeCell}; - use std::collections::HashSet; - use std::sync::atomic::Ordering; - use std::sync::mpsc; - use thread_id; - - /// Representation of a deadlocked thread - pub struct DeadlockedThread { - thread_id: usize, - backtrace: Backtrace, - } - - impl DeadlockedThread { - /// The system thread id - pub fn thread_id(&self) -> usize { - self.thread_id - } - - /// The thread backtrace - pub fn backtrace(&self) -> &Backtrace { - &self.backtrace - } - } - - pub struct DeadlockData { - // Currently owned resources (keys) - resources: UnsafeCell>, - - // Set when there's a pending callstack request - deadlocked: Cell, - - // Sender used to report the backtrace - backtrace_sender: UnsafeCell>>, - - // System thread id - thread_id: usize, - } - - impl DeadlockData { - pub fn new() -> Self { - DeadlockData { - resources: UnsafeCell::new(Vec::new()), - deadlocked: Cell::new(false), - backtrace_sender: UnsafeCell::new(None), - thread_id: thread_id::get(), - } - } - } - - pub(super) unsafe fn on_unpark(td: &ThreadData) { - if td.deadlock_data.deadlocked.get() { - let sender = (*td.deadlock_data.backtrace_sender.get()).take().unwrap(); - sender - .send(DeadlockedThread { - thread_id: td.deadlock_data.thread_id, - backtrace: Backtrace::new(), - }) - .unwrap(); - // make sure to close this sender - drop(sender); - - // park until the end of the time - td.parker.prepare_park(); - td.parker.park(); - unreachable!("unparked deadlocked thread!"); - } - } - - pub unsafe fn acquire_resource(key: usize) { - with_thread_data(|thread_data| { - (*thread_data.deadlock_data.resources.get()).push(key); - }); - } - - pub unsafe fn release_resource(key: usize) { - with_thread_data(|thread_data| { - let resources = &mut (*thread_data.deadlock_data.resources.get()); - - // There is only one situation where we can fail to find the - // resource: we are currently running TLS destructors and our - // ThreadData has already been freed. There isn't much we can do - // about it at this point, so just ignore it. - if let Some(p) = resources.iter().rposition(|x| *x == key) { - resources.swap_remove(p); - } - }); - } - - pub fn check_deadlock() -> Vec> { - unsafe { - // fast pass - if check_wait_graph_fast() { - // double check - check_wait_graph_slow() - } else { - Vec::new() - } - } - } - - // Simple algorithm that builds a wait graph f the threads and the resources, - // then checks for the presence of cycles (deadlocks). - // This variant isn't precise as it doesn't lock the entire table before checking - unsafe fn check_wait_graph_fast() -> bool { - let table = get_hashtable(); - let thread_count = NUM_THREADS.load(Ordering::Relaxed); - let mut graph = DiGraphMap::::with_capacity(thread_count * 2, thread_count * 2); - - for b in &(*table).entries[..] { - b.mutex.lock(); - let mut current = b.queue_head.get(); - while !current.is_null() { - if !(*current).parked_with_timeout.get() - && !(*current).deadlock_data.deadlocked.get() - { - // .resources are waiting for their owner - for &resource in &(*(*current).deadlock_data.resources.get()) { - graph.add_edge(resource, current as usize, ()); - } - // owner waits for resource .key - graph.add_edge(current as usize, (*current).key.load(Ordering::Relaxed), ()); - } - current = (*current).next_in_queue.get(); - } - // SAFETY: We hold the lock here, as required - b.mutex.unlock(); - } - - petgraph::algo::is_cyclic_directed(&graph) - } - - #[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] - enum WaitGraphNode { - Thread(*const ThreadData), - Resource(usize), - } - - use self::WaitGraphNode::*; - - // Contrary to the _fast variant this locks the entries table before looking for cycles. - // Returns all detected thread wait cycles. - // Note that once a cycle is reported it's never reported again. - unsafe fn check_wait_graph_slow() -> Vec> { - static DEADLOCK_DETECTION_LOCK: WordLock = WordLock::new(); - DEADLOCK_DETECTION_LOCK.lock(); - - let mut table = get_hashtable(); - loop { - // Lock all buckets in the old table - for b in &table.entries[..] { - b.mutex.lock(); - } - - // Now check if our table is still the latest one. Another thread could - // have grown the hash table between us getting and locking the hash table. - let new_table = get_hashtable(); - if new_table as *const _ == table as *const _ { - break; - } - - // Unlock buckets and try again - for b in &table.entries[..] { - // SAFETY: We hold the lock here, as required - b.mutex.unlock(); - } - - table = new_table; - } - - let thread_count = NUM_THREADS.load(Ordering::Relaxed); - let mut graph = - DiGraphMap::::with_capacity(thread_count * 2, thread_count * 2); - - for b in &table.entries[..] { - let mut current = b.queue_head.get(); - while !current.is_null() { - if !(*current).parked_with_timeout.get() - && !(*current).deadlock_data.deadlocked.get() - { - // .resources are waiting for their owner - for &resource in &(*(*current).deadlock_data.resources.get()) { - graph.add_edge(Resource(resource), Thread(current), ()); - } - // owner waits for resource .key - graph.add_edge( - Thread(current), - Resource((*current).key.load(Ordering::Relaxed)), - (), - ); - } - current = (*current).next_in_queue.get(); - } - } - - for b in &table.entries[..] { - // SAFETY: We hold the lock here, as required - b.mutex.unlock(); - } - - // find cycles - let cycles = graph_cycles(&graph); - - let mut results = Vec::with_capacity(cycles.len()); - - for cycle in cycles { - let (sender, receiver) = mpsc::channel(); - for td in cycle { - let bucket = lock_bucket((*td).key.load(Ordering::Relaxed)); - (*td).deadlock_data.deadlocked.set(true); - *(*td).deadlock_data.backtrace_sender.get() = Some(sender.clone()); - let handle = (*td).parker.unpark_lock(); - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - // unpark the deadlocked thread! - // on unpark it'll notice the deadlocked flag and report back - handle.unpark(); - } - // make sure to drop our sender before collecting results - drop(sender); - results.push(receiver.iter().collect()); - } - - DEADLOCK_DETECTION_LOCK.unlock(); - - results - } - - // normalize a cycle to start with the "smallest" node - fn normalize_cycle(input: &[T]) -> Vec { - let min_pos = input - .iter() - .enumerate() - .min_by_key(|&(_, &t)| t) - .map(|(p, _)| p) - .unwrap_or(0); - input - .iter() - .cycle() - .skip(min_pos) - .take(input.len()) - .cloned() - .collect() - } - - // returns all thread cycles in the wait graph - fn graph_cycles(g: &DiGraphMap) -> Vec> { - use petgraph::visit::depth_first_search; - use petgraph::visit::DfsEvent; - use petgraph::visit::NodeIndexable; - - let mut cycles = HashSet::new(); - let mut path = Vec::with_capacity(g.node_bound()); - // start from threads to get the correct threads cycle - let threads = g - .nodes() - .filter(|n| if let &Thread(_) = n { true } else { false }); - - depth_first_search(g, threads, |e| match e { - DfsEvent::Discover(Thread(n), _) => path.push(n), - DfsEvent::Finish(Thread(_), _) => { - path.pop(); - } - DfsEvent::BackEdge(_, Thread(n)) => { - let from = path.iter().rposition(|&i| i == n).unwrap(); - cycles.insert(normalize_cycle(&path[from..])); - } - _ => (), - }); - - cycles.iter().cloned().collect() - } -} - -#[cfg(test)] -mod tests { - use super::{ThreadData, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN}; - use std::{ - ptr, - sync::{ - atomic::{AtomicIsize, AtomicPtr, AtomicUsize, Ordering}, - Arc, - }, - thread, - time::Duration, - }; - - /// Calls a closure for every `ThreadData` currently parked on a given key - fn for_each(key: usize, mut f: impl FnMut(&ThreadData)) { - let bucket = super::lock_bucket(key); - - let mut current: *const ThreadData = bucket.queue_head.get(); - while !current.is_null() { - let current_ref = unsafe { &*current }; - if current_ref.key.load(Ordering::Relaxed) == key { - f(current_ref); - } - current = current_ref.next_in_queue.get(); - } - - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } - - macro_rules! test { - ( $( $name:ident( - repeats: $repeats:expr, - latches: $latches:expr, - delay: $delay:expr, - threads: $threads:expr, - single_unparks: $single_unparks:expr); - )* ) => { - $(#[test] - fn $name() { - let delay = Duration::from_micros($delay); - for _ in 0..$repeats { - run_parking_test($latches, delay, $threads, $single_unparks); - } - })* - }; - } - - test! { - unpark_all_one_fast( - repeats: 10000, latches: 1, delay: 0, threads: 1, single_unparks: 0 - ); - unpark_all_hundred_fast( - repeats: 100, latches: 1, delay: 0, threads: 100, single_unparks: 0 - ); - unpark_one_one_fast( - repeats: 1000, latches: 1, delay: 0, threads: 1, single_unparks: 1 - ); - unpark_one_hundred_fast( - repeats: 20, latches: 1, delay: 0, threads: 100, single_unparks: 100 - ); - unpark_one_fifty_then_fifty_all_fast( - repeats: 50, latches: 1, delay: 0, threads: 100, single_unparks: 50 - ); - unpark_all_one( - repeats: 100, latches: 1, delay: 10000, threads: 1, single_unparks: 0 - ); - unpark_all_hundred( - repeats: 100, latches: 1, delay: 10000, threads: 100, single_unparks: 0 - ); - unpark_one_one( - repeats: 10, latches: 1, delay: 10000, threads: 1, single_unparks: 1 - ); - unpark_one_fifty( - repeats: 1, latches: 1, delay: 10000, threads: 50, single_unparks: 50 - ); - unpark_one_fifty_then_fifty_all( - repeats: 2, latches: 1, delay: 10000, threads: 100, single_unparks: 50 - ); - hundred_unpark_all_one_fast( - repeats: 100, latches: 100, delay: 0, threads: 1, single_unparks: 0 - ); - hundred_unpark_all_one( - repeats: 1, latches: 100, delay: 10000, threads: 1, single_unparks: 0 - ); - } - - fn run_parking_test( - num_latches: usize, - delay: Duration, - num_threads: usize, - num_single_unparks: usize, - ) { - let mut tests = Vec::with_capacity(num_latches); - - for _ in 0..num_latches { - let test = Arc::new(SingleLatchTest::new(num_threads)); - let mut threads = Vec::with_capacity(num_threads); - for _ in 0..num_threads { - let test = test.clone(); - threads.push(thread::spawn(move || test.run())); - } - tests.push((test, threads)); - } - - for unpark_index in 0..num_single_unparks { - thread::sleep(delay); - for (test, _) in &tests { - test.unpark_one(unpark_index); - } - } - - for (test, threads) in tests { - test.finish(num_single_unparks); - for thread in threads { - thread.join().expect("Test thread panic"); - } - } - } - - struct SingleLatchTest { - semaphore: AtomicIsize, - num_awake: AtomicUsize, - /// Holds the pointer to the last *unprocessed* woken up thread. - last_awoken: AtomicPtr, - /// Total number of threads participating in this test. - num_threads: usize, - } - - impl SingleLatchTest { - pub fn new(num_threads: usize) -> Self { - Self { - // This implements a fair (FIFO) semaphore, and it starts out unavailable. - semaphore: AtomicIsize::new(0), - num_awake: AtomicUsize::new(0), - last_awoken: AtomicPtr::new(ptr::null_mut()), - num_threads, - } - } - - pub fn run(&self) { - // Get one slot from the semaphore - self.down(); - - // Report back to the test verification code that this thread woke up - let this_thread_ptr = super::with_thread_data(|t| t as *const _ as *mut _); - self.last_awoken.store(this_thread_ptr, Ordering::SeqCst); - self.num_awake.fetch_add(1, Ordering::SeqCst); - } - - pub fn unpark_one(&self, single_unpark_index: usize) { - // last_awoken should be null at all times except between self.up() and at the bottom - // of this method where it's reset to null again - assert!(self.last_awoken.load(Ordering::SeqCst).is_null()); - - let mut queue: Vec<*mut ThreadData> = Vec::with_capacity(self.num_threads); - for_each(self.semaphore_addr(), |thread_data| { - queue.push(thread_data as *const _ as *mut _); - }); - assert!(queue.len() <= self.num_threads - single_unpark_index); - - let num_awake_before_up = self.num_awake.load(Ordering::SeqCst); - - self.up(); - - // Wait for a parked thread to wake up and update num_awake + last_awoken. - while self.num_awake.load(Ordering::SeqCst) != num_awake_before_up + 1 { - thread::yield_now(); - } - - // At this point the other thread should have set last_awoken inside the run() method - let last_awoken = self.last_awoken.load(Ordering::SeqCst); - assert!(!last_awoken.is_null()); - if !queue.is_empty() && queue[0] != last_awoken { - panic!( - "Woke up wrong thread:\n\tqueue: {:?}\n\tlast awoken: {:?}", - queue, last_awoken - ); - } - self.last_awoken.store(ptr::null_mut(), Ordering::SeqCst); - } - - pub fn finish(&self, num_single_unparks: usize) { - // The amount of threads not unparked via unpark_one - let mut num_threads_left = self.num_threads.checked_sub(num_single_unparks).unwrap(); - - // Wake remaining threads up with unpark_all. Has to be in a loop, because there might - // still be threads that has not yet parked. - while num_threads_left > 0 { - let mut num_waiting_on_address = 0; - for_each(self.semaphore_addr(), |_thread_data| { - num_waiting_on_address += 1; - }); - assert!(num_waiting_on_address <= num_threads_left); - - let num_awake_before_unpark = self.num_awake.load(Ordering::SeqCst); - - let num_unparked = - unsafe { super::unpark_all(self.semaphore_addr(), DEFAULT_UNPARK_TOKEN) }; - assert!(num_unparked >= num_waiting_on_address); - assert!(num_unparked <= num_threads_left); - - // Wait for all unparked threads to wake up and update num_awake + last_awoken. - while self.num_awake.load(Ordering::SeqCst) - != num_awake_before_unpark + num_unparked - { - thread::yield_now() - } - - num_threads_left = num_threads_left.checked_sub(num_unparked).unwrap(); - } - // By now, all threads should have been woken up - assert_eq!(self.num_awake.load(Ordering::SeqCst), self.num_threads); - - // Make sure no thread is parked on our semaphore address - let mut num_waiting_on_address = 0; - for_each(self.semaphore_addr(), |_thread_data| { - num_waiting_on_address += 1; - }); - assert_eq!(num_waiting_on_address, 0); - } - - pub fn down(&self) { - let old_semaphore_value = self.semaphore.fetch_sub(1, Ordering::SeqCst); - - if old_semaphore_value > 0 { - // We acquired the semaphore. Done. - return; - } - - // We need to wait. - let validate = || true; - let before_sleep = || {}; - let timed_out = |_, _| {}; - unsafe { - super::park( - self.semaphore_addr(), - validate, - before_sleep, - timed_out, - DEFAULT_PARK_TOKEN, - None, - ); - } - } - - pub fn up(&self) { - let old_semaphore_value = self.semaphore.fetch_add(1, Ordering::SeqCst); - - // Check if anyone was waiting on the semaphore. If they were, then pass ownership to them. - if old_semaphore_value < 0 { - // We need to continue until we have actually unparked someone. It might be that - // the thread we want to pass ownership to has decremented the semaphore counter, - // but not yet parked. - loop { - match unsafe { - super::unpark_one(self.semaphore_addr(), |_| DEFAULT_UNPARK_TOKEN) - .unparked_threads - } { - 1 => break, - 0 => (), - i => panic!("Should not wake up {} threads", i), - } - } - } - } - - fn semaphore_addr(&self) -> usize { - &self.semaphore as *const _ as usize - } - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/spinwait.rs b/vendor/parking_lot_core-0.7.2/src/spinwait.rs deleted file mode 100644 index ad0327a3ae..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/spinwait.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::thread_parker; -use std::sync::atomic::spin_loop_hint; - -// Wastes some CPU time for the given number of iterations, -// using a hint to indicate to the CPU that we are spinning. -#[inline] -fn cpu_relax(iterations: u32) { - for _ in 0..iterations { - spin_loop_hint() - } -} - -/// A counter used to perform exponential backoff in spin loops. -#[derive(Default)] -pub struct SpinWait { - counter: u32, -} - -impl SpinWait { - /// Creates a new `SpinWait`. - #[inline] - pub fn new() -> Self { - Self::default() - } - - /// Resets a `SpinWait` to its initial state. - #[inline] - pub fn reset(&mut self) { - self.counter = 0; - } - - /// Spins until the sleep threshold has been reached. - /// - /// This function returns whether the sleep threshold has been reached, at - /// which point further spinning has diminishing returns and the thread - /// should be parked instead. - /// - /// The spin strategy will initially use a CPU-bound loop but will fall back - /// to yielding the CPU to the OS after a few iterations. - #[inline] - pub fn spin(&mut self) -> bool { - if self.counter >= 10 { - return false; - } - self.counter += 1; - if self.counter <= 3 { - cpu_relax(1 << self.counter); - } else { - thread_parker::thread_yield(); - } - true - } - - /// Spins without yielding the thread to the OS. - /// - /// Instead, the backoff is simply capped at a maximum value. This can be - /// used to improve throughput in `compare_exchange` loops that have high - /// contention. - #[inline] - pub fn spin_no_yield(&mut self) { - self.counter += 1; - if self.counter > 10 { - self.counter = 10; - } - cpu_relax(1 << self.counter); - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/cloudabi.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/cloudabi.rs deleted file mode 100644 index 520cc72990..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/cloudabi.rs +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use cloudabi as abi; -use core::{ - cell::Cell, - mem::{self, MaybeUninit}, - sync::atomic::{AtomicU32, Ordering}, -}; -use std::{convert::TryFrom, thread, time::Instant}; - -extern "C" { - #[thread_local] - static __pthread_thread_id: abi::tid; -} - -struct Lock { - lock: AtomicU32, -} - -impl Lock { - pub fn new() -> Self { - Lock { - lock: AtomicU32::new(abi::LOCK_UNLOCKED.0), - } - } - - /// # Safety - /// - /// See `Lock::lock`. - unsafe fn try_lock(&self) -> Option { - // Attempt to acquire the lock. - if let Err(old) = self.lock.compare_exchange( - abi::LOCK_UNLOCKED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - Ordering::Acquire, - Ordering::Relaxed, - ) { - // Failure. Crash upon recursive acquisition. - debug_assert_ne!( - old & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "Attempted to recursive write-lock a lock", - ); - None - } else { - Some(LockGuard { lock: &self.lock }) - } - } - - /// # Safety - /// - /// This method is unsafe because the `LockGuard` has a raw pointer into this `Lock` - /// that it will access on drop to unlock the lock. So make sure the `LockGuard` goes - /// out of scope before the `Lock` it came from moves or goes out of scope. - pub unsafe fn lock(&self) -> LockGuard { - self.try_lock().unwrap_or_else(|| { - // Call into the kernel to acquire a write lock. - let subscription = abi::subscription { - type_: abi::eventtype::LOCK_WRLOCK, - union: abi::subscription_union { - lock: abi::subscription_lock { - lock: self.ptr(), - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event = MaybeUninit::::uninit(); - let mut nevents: usize = 0; - let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, &mut nevents); - debug_assert_eq!(ret, abi::errno::SUCCESS); - debug_assert_eq!(event.assume_init().error, abi::errno::SUCCESS); - - LockGuard { lock: &self.lock } - }) - } - - fn ptr(&self) -> *mut abi::lock { - &self.lock as *const AtomicU32 as *mut abi::lock - } -} - -struct LockGuard { - lock: *const AtomicU32, -} - -impl LockGuard { - fn ptr(&self) -> *mut abi::lock { - self.lock as *mut abi::lock - } -} - -impl Drop for LockGuard { - fn drop(&mut self) { - let lock = unsafe { &*self.lock }; - debug_assert_eq!( - lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - unsafe { __pthread_thread_id.0 } | abi::LOCK_WRLOCKED.0, - "This lock is not write-locked by this thread" - ); - - if !lock - .compare_exchange( - unsafe { __pthread_thread_id.0 } | abi::LOCK_WRLOCKED.0, - abi::LOCK_UNLOCKED.0, - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - // Lock is managed by kernelspace. Call into the kernel - // to unblock waiting threads. - let ret = unsafe { abi::lock_unlock(self.lock as *mut abi::lock, abi::scope::PRIVATE) }; - debug_assert_eq!(ret, abi::errno::SUCCESS); - } - } -} - -struct Condvar { - condvar: AtomicU32, -} - -impl Condvar { - pub fn new() -> Self { - Condvar { - condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0), - } - } - - pub fn wait(&self, lock: &LockGuard) { - unsafe { - let subscription = abi::subscription { - type_: abi::eventtype::CONDVAR, - union: abi::subscription_union { - condvar: abi::subscription_condvar { - condvar: self.ptr(), - condvar_scope: abi::scope::PRIVATE, - lock: lock.ptr(), - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event = MaybeUninit::::uninit(); - let mut nevents: usize = 0; - - let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, &mut nevents); - debug_assert_eq!(ret, abi::errno::SUCCESS); - debug_assert_eq!(event.assume_init().error, abi::errno::SUCCESS); - } - } - - /// Waits for a signal on the condvar. - /// Returns false if it times out before anyone notified us. - pub fn wait_timeout(&self, lock: &LockGuard, timeout: abi::timestamp) -> bool { - unsafe { - let subscriptions = [ - abi::subscription { - type_: abi::eventtype::CONDVAR, - union: abi::subscription_union { - condvar: abi::subscription_condvar { - condvar: self.ptr(), - condvar_scope: abi::scope::PRIVATE, - lock: lock.ptr(), - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }, - abi::subscription { - type_: abi::eventtype::CLOCK, - union: abi::subscription_union { - clock: abi::subscription_clock { - clock_id: abi::clockid::MONOTONIC, - timeout, - ..mem::zeroed() - }, - }, - ..mem::zeroed() - }, - ]; - let mut events = MaybeUninit::<[abi::event; 2]>::uninit(); - let mut nevents: usize = 0; - - let ret = abi::poll( - subscriptions.as_ptr(), - events.as_mut_ptr() as *mut _, - 2, - &mut nevents, - ); - debug_assert_eq!(ret, abi::errno::SUCCESS); - let events = events.assume_init(); - for i in 0..nevents { - debug_assert_eq!(events[i].error, abi::errno::SUCCESS); - if events[i].type_ == abi::eventtype::CONDVAR { - return true; - } - } - } - false - } - - pub fn notify(&self) { - let ret = unsafe { abi::condvar_signal(self.ptr(), abi::scope::PRIVATE, 1) }; - debug_assert_eq!(ret, abi::errno::SUCCESS); - } - - fn ptr(&self) -> *mut abi::condvar { - &self.condvar as *const AtomicU32 as *mut abi::condvar - } -} - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - should_park: Cell, - lock: Lock, - condvar: Condvar, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - fn new() -> ThreadParker { - ThreadParker { - should_park: Cell::new(false), - lock: Lock::new(), - condvar: Condvar::new(), - } - } - - unsafe fn prepare_park(&self) { - self.should_park.set(true); - } - - unsafe fn timed_out(&self) -> bool { - // We need to grab the lock here because another thread may be - // concurrently executing UnparkHandle::unpark, which is done without - // holding the queue lock. - let _guard = self.lock.lock(); - self.should_park.get() - } - - unsafe fn park(&self) { - let guard = self.lock.lock(); - while self.should_park.get() { - self.condvar.wait(&guard); - } - } - - unsafe fn park_until(&self, timeout: Instant) -> bool { - let guard = self.lock.lock(); - while self.should_park.get() { - if let Some(duration_left) = timeout.checked_duration_since(Instant::now()) { - if let Ok(nanos_left) = abi::timestamp::try_from(duration_left.as_nanos()) { - self.condvar.wait_timeout(&guard, nanos_left); - } else { - // remaining timeout overflows an abi::timestamp. Sleep indefinitely - self.condvar.wait(&guard); - } - } else { - // We timed out - return false; - } - } - true - } - - unsafe fn unpark_lock(&self) -> UnparkHandle { - let _lock_guard = self.lock.lock(); - - UnparkHandle { - thread_parker: self, - _lock_guard, - } - } -} - -pub struct UnparkHandle { - thread_parker: *const ThreadParker, - _lock_guard: LockGuard, -} - -impl super::UnparkHandleT for UnparkHandle { - unsafe fn unpark(self) { - (*self.thread_parker).should_park.set(false); - - // We notify while holding the lock here to avoid races with the target - // thread. In particular, the thread could exit after we unlock the - // mutex, which would make the condvar access invalid memory. - (*self.thread_parker).condvar.notify(); - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/generic.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/generic.rs deleted file mode 100644 index 3ee837ac6f..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/generic.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -//! A simple spin lock based thread parker. Used on platforms without better -//! parking facilities available. - -use core::sync::atomic::{spin_loop_hint, AtomicBool, Ordering}; -use std::{thread, time::Instant}; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - parked: AtomicBool, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - parked: AtomicBool::new(false), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.parked.store(true, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.parked.load(Ordering::Relaxed) != false - } - - #[inline] - unsafe fn park(&self) { - while self.parked.load(Ordering::Acquire) != false { - spin_loop_hint(); - } - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - while self.parked.load(Ordering::Acquire) != false { - if Instant::now() >= timeout { - return false; - } - spin_loop_hint(); - } - true - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.parked.store(false, Ordering::Release); - UnparkHandle(()) - } -} - -pub struct UnparkHandle(()); - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) {} -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/linux.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/linux.rs deleted file mode 100644 index 04f66a737f..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/linux.rs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use core::{ - ptr, - sync::atomic::{AtomicI32, Ordering}, -}; -use libc; -use std::{thread, time::Instant}; - -// x32 Linux uses a non-standard type for tv_nsec in timespec. -// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 -#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -#[allow(non_camel_case_types)] -type tv_nsec_t = i64; -#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -#[allow(non_camel_case_types)] -type tv_nsec_t = libc::c_long; - -fn errno() -> libc::c_int { - #[cfg(target_os = "linux")] - unsafe { - *libc::__errno_location() - } - #[cfg(target_os = "android")] - unsafe { - *libc::__errno() - } -} - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - futex: AtomicI32, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - futex: AtomicI32::new(0), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.futex.store(1, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.futex.load(Ordering::Relaxed) != 0 - } - - #[inline] - unsafe fn park(&self) { - while self.futex.load(Ordering::Acquire) != 0 { - self.futex_wait(None); - } - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - while self.futex.load(Ordering::Acquire) != 0 { - let now = Instant::now(); - if timeout <= now { - return false; - } - let diff = timeout - now; - if diff.as_secs() as libc::time_t as u64 != diff.as_secs() { - // Timeout overflowed, just sleep indefinitely - self.park(); - return true; - } - let ts = libc::timespec { - tv_sec: diff.as_secs() as libc::time_t, - tv_nsec: diff.subsec_nanos() as tv_nsec_t, - }; - self.futex_wait(Some(ts)); - } - true - } - - // Locks the parker to prevent the target thread from exiting. This is - // necessary to ensure that thread-local ThreadData objects remain valid. - // This should be called while holding the queue lock. - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.futex.store(0, Ordering::Release); - - UnparkHandle { futex: &self.futex } - } -} - -impl ThreadParker { - #[inline] - fn futex_wait(&self, ts: Option) { - let ts_ptr = ts - .as_ref() - .map(|ts_ref| ts_ref as *const _) - .unwrap_or(ptr::null()); - let r = unsafe { - libc::syscall( - libc::SYS_futex, - &self.futex, - libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG, - 1, - ts_ptr, - ) - }; - debug_assert!(r == 0 || r == -1); - if r == -1 { - debug_assert!( - errno() == libc::EINTR - || errno() == libc::EAGAIN - || (ts.is_some() && errno() == libc::ETIMEDOUT) - ); - } - } -} - -pub struct UnparkHandle { - futex: *const AtomicI32, -} - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - // The thread data may have been freed at this point, but it doesn't - // matter since the syscall will just return EFAULT in that case. - let r = libc::syscall( - libc::SYS_futex, - self.futex, - libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG, - 1, - ); - debug_assert!(r == 0 || r == 1 || r == -1); - if r == -1 { - debug_assert_eq!(errno(), libc::EFAULT); - } - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/mod.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/mod.rs deleted file mode 100644 index 4c721c3da9..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/mod.rs +++ /dev/null @@ -1,88 +0,0 @@ -use cfg_if::cfg_if; -use std::time::Instant; - -/// Trait for the platform thread parker implementation. -/// -/// All unsafe methods are unsafe because the Unix thread parker is based on -/// pthread mutexes and condvars. Those primitives must not be moved and used -/// from any other memory address than the one they were located at when they -/// were initialized. As such, it's UB to call any unsafe method on -/// `ThreadParkerT` if the implementing instance has moved since the last -/// call to any of the unsafe methods. -pub trait ThreadParkerT { - type UnparkHandle: UnparkHandleT; - - const IS_CHEAP_TO_CONSTRUCT: bool; - - fn new() -> Self; - - /// Prepares the parker. This should be called before adding it to the queue. - unsafe fn prepare_park(&self); - - /// Checks if the park timed out. This should be called while holding the - /// queue lock after park_until has returned false. - unsafe fn timed_out(&self) -> bool; - - /// Parks the thread until it is unparked. This should be called after it has - /// been added to the queue, after unlocking the queue. - unsafe fn park(&self); - - /// Parks the thread until it is unparked or the timeout is reached. This - /// should be called after it has been added to the queue, after unlocking - /// the queue. Returns true if we were unparked and false if we timed out. - unsafe fn park_until(&self, timeout: Instant) -> bool; - - /// Locks the parker to prevent the target thread from exiting. This is - /// necessary to ensure that thread-local ThreadData objects remain valid. - /// This should be called while holding the queue lock. - unsafe fn unpark_lock(&self) -> Self::UnparkHandle; -} - -/// Handle for a thread that is about to be unparked. We need to mark the thread -/// as unparked while holding the queue lock, but we delay the actual unparking -/// until after the queue lock is released. -pub trait UnparkHandleT { - /// Wakes up the parked thread. This should be called after the queue lock is - /// released to avoid blocking the queue for too long. - /// - /// This method is unsafe for the same reason as the unsafe methods in - /// `ThreadParkerT`. - unsafe fn unpark(self); -} - -cfg_if! { - if #[cfg(any(target_os = "linux", target_os = "android"))] { - #[path = "linux.rs"] - mod imp; - } else if #[cfg(unix)] { - #[path = "unix.rs"] - mod imp; - } else if #[cfg(windows)] { - #[path = "windows/mod.rs"] - mod imp; - } else if #[cfg(target_os = "redox")] { - #[path = "redox.rs"] - mod imp; - } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] { - #[path = "sgx.rs"] - mod imp; - } else if #[cfg(all( - feature = "nightly", - target_arch = "wasm32", - target_feature = "atomics" - ))] { - #[path = "wasm_atomic.rs"] - mod imp; - } else if #[cfg(target_arch = "wasm32")] { - #[path = "wasm.rs"] - mod imp; - } else if #[cfg(all(feature = "nightly", target_os = "cloudabi"))] { - #[path = "cloudabi.rs"] - mod imp; - } else { - #[path = "generic.rs"] - mod imp; - } -} - -pub use self::imp::{thread_yield, ThreadParker, UnparkHandle}; diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/redox.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/redox.rs deleted file mode 100644 index 97ffc8adc0..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/redox.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use core::{ - ptr, - sync::atomic::{AtomicI32, Ordering}, -}; -use std::{thread, time::Instant}; -use syscall::{ - call::futex, - data::TimeSpec, - error::{Error, EAGAIN, EFAULT, EINTR, ETIMEDOUT}, - flag::{FUTEX_WAIT, FUTEX_WAKE}, -}; - -const UNPARKED: i32 = 0; -const PARKED: i32 = 1; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - futex: AtomicI32, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - futex: AtomicI32::new(UNPARKED), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.futex.store(PARKED, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.futex.load(Ordering::Relaxed) != UNPARKED - } - - #[inline] - unsafe fn park(&self) { - while self.futex.load(Ordering::Acquire) != UNPARKED { - self.futex_wait(None); - } - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - while self.futex.load(Ordering::Acquire) != UNPARKED { - let now = Instant::now(); - if timeout <= now { - return false; - } - let diff = timeout - now; - if diff.as_secs() > i64::max_value() as u64 { - // Timeout overflowed, just sleep indefinitely - self.park(); - return true; - } - let ts = TimeSpec { - tv_sec: diff.as_secs() as i64, - tv_nsec: diff.subsec_nanos() as i32, - }; - self.futex_wait(Some(ts)); - } - true - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.futex.store(UNPARKED, Ordering::Release); - - UnparkHandle { futex: self.ptr() } - } -} - -impl ThreadParker { - #[inline] - fn futex_wait(&self, ts: Option) { - let ts_ptr = ts - .as_ref() - .map(|ts_ref| ts_ref as *const _) - .unwrap_or(ptr::null()); - let r = unsafe { - futex( - self.ptr(), - FUTEX_WAIT, - PARKED, - ts_ptr as usize, - ptr::null_mut(), - ) - }; - match r { - Ok(r) => debug_assert_eq!(r, 0), - Err(Error { errno }) => { - debug_assert!(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT); - } - } - } - - #[inline] - fn ptr(&self) -> *mut i32 { - &self.futex as *const AtomicI32 as *mut i32 - } -} - -pub struct UnparkHandle { - futex: *mut i32, -} - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - // The thread data may have been freed at this point, but it doesn't - // matter since the syscall will just return EFAULT in that case. - let r = futex(self.futex, FUTEX_WAKE, PARKED, 0, ptr::null_mut()); - match r { - Ok(num_woken) => debug_assert!(num_woken == 0 || num_woken == 1), - Err(Error { errno }) => debug_assert_eq!(errno, EFAULT), - } - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/sgx.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/sgx.rs deleted file mode 100644 index 56fc65a208..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/sgx.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use core::sync::atomic::{AtomicBool, Ordering}; -use std::{ - io, - os::fortanix_sgx::{ - thread::current as current_tcs, - usercalls::{ - self, - raw::{Tcs, EV_UNPARK, WAIT_INDEFINITE}, - }, - }, - thread, - time::Instant, -}; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - parked: AtomicBool, - tcs: Tcs, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - parked: AtomicBool::new(false), - tcs: current_tcs(), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.parked.store(true, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.parked.load(Ordering::Relaxed) - } - - #[inline] - unsafe fn park(&self) { - while self.parked.load(Ordering::Acquire) { - let result = usercalls::wait(EV_UNPARK, WAIT_INDEFINITE); - debug_assert_eq!(result.expect("wait returned error") & EV_UNPARK, EV_UNPARK); - } - } - - #[inline] - unsafe fn park_until(&self, _timeout: Instant) -> bool { - // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - panic!("timeout not supported in SGX"); - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.parked.store(false, Ordering::Release); - UnparkHandle(self.tcs) - } -} - -pub struct UnparkHandle(Tcs); - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - let result = usercalls::send(EV_UNPARK, Some(self.0)); - if cfg!(debug_assertions) { - if let Err(error) = result { - // `InvalidInput` may be returned if the thread we send to has - // already been unparked and exited. - if error.kind() != io::ErrorKind::InvalidInput { - panic!("send returned an unexpected error: {:?}", error); - } - } - } - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/unix.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/unix.rs deleted file mode 100644 index e61ab623ef..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/unix.rs +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -#[cfg(any(target_os = "macos", target_os = "ios"))] -use core::ptr; -use core::{ - cell::{Cell, UnsafeCell}, - mem::MaybeUninit, -}; -use libc; -use std::{ - thread, - time::{Duration, Instant}, -}; - -// x32 Linux uses a non-standard type for tv_nsec in timespec. -// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 -#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -#[allow(non_camel_case_types)] -type tv_nsec_t = i64; -#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -#[allow(non_camel_case_types)] -type tv_nsec_t = libc::c_long; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - should_park: Cell, - mutex: UnsafeCell, - condvar: UnsafeCell, - initialized: Cell, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = false; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - should_park: Cell::new(false), - mutex: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER), - condvar: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER), - initialized: Cell::new(false), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.should_park.set(true); - if !self.initialized.get() { - self.init(); - self.initialized.set(true); - } - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - // We need to grab the mutex here because another thread may be - // concurrently executing UnparkHandle::unpark, which is done without - // holding the queue lock. - let r = libc::pthread_mutex_lock(self.mutex.get()); - debug_assert_eq!(r, 0); - let should_park = self.should_park.get(); - let r = libc::pthread_mutex_unlock(self.mutex.get()); - debug_assert_eq!(r, 0); - should_park - } - - #[inline] - unsafe fn park(&self) { - let r = libc::pthread_mutex_lock(self.mutex.get()); - debug_assert_eq!(r, 0); - while self.should_park.get() { - let r = libc::pthread_cond_wait(self.condvar.get(), self.mutex.get()); - debug_assert_eq!(r, 0); - } - let r = libc::pthread_mutex_unlock(self.mutex.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - let r = libc::pthread_mutex_lock(self.mutex.get()); - debug_assert_eq!(r, 0); - while self.should_park.get() { - let now = Instant::now(); - if timeout <= now { - let r = libc::pthread_mutex_unlock(self.mutex.get()); - debug_assert_eq!(r, 0); - return false; - } - - if let Some(ts) = timeout_to_timespec(timeout - now) { - let r = libc::pthread_cond_timedwait(self.condvar.get(), self.mutex.get(), &ts); - if ts.tv_sec < 0 { - // On some systems, negative timeouts will return EINVAL. In - // that case we won't sleep and will just busy loop instead, - // which is the best we can do. - debug_assert!(r == 0 || r == libc::ETIMEDOUT || r == libc::EINVAL); - } else { - debug_assert!(r == 0 || r == libc::ETIMEDOUT); - } - } else { - // Timeout calculation overflowed, just sleep indefinitely - let r = libc::pthread_cond_wait(self.condvar.get(), self.mutex.get()); - debug_assert_eq!(r, 0); - } - } - let r = libc::pthread_mutex_unlock(self.mutex.get()); - debug_assert_eq!(r, 0); - true - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - let r = libc::pthread_mutex_lock(self.mutex.get()); - debug_assert_eq!(r, 0); - - UnparkHandle { - thread_parker: self, - } - } -} - -impl ThreadParker { - /// Initializes the condvar to use CLOCK_MONOTONIC instead of CLOCK_REALTIME. - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))] - #[inline] - unsafe fn init(&self) {} - - /// Initializes the condvar to use CLOCK_MONOTONIC instead of CLOCK_REALTIME. - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] - #[inline] - unsafe fn init(&self) { - let mut attr = MaybeUninit::::uninit(); - let r = libc::pthread_condattr_init(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); - debug_assert_eq!(r, 0); - let r = libc::pthread_cond_init(self.condvar.get(), attr.as_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - } -} - -impl Drop for ThreadParker { - #[inline] - fn drop(&mut self) { - // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a - // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. - // Once it is used (locked/unlocked) or pthread_mutex_init() is called, - // this behaviour no longer occurs. The same applies to condvars. - unsafe { - let r = libc::pthread_mutex_destroy(self.mutex.get()); - if cfg!(target_os = "dragonfly") { - debug_assert!(r == 0 || r == libc::EINVAL); - } else { - debug_assert_eq!(r, 0); - } - let r = libc::pthread_cond_destroy(self.condvar.get()); - if cfg!(target_os = "dragonfly") { - debug_assert!(r == 0 || r == libc::EINVAL); - } else { - debug_assert_eq!(r, 0); - } - } - } -} - -pub struct UnparkHandle { - thread_parker: *const ThreadParker, -} - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - (*self.thread_parker).should_park.set(false); - - // We notify while holding the lock here to avoid races with the target - // thread. In particular, the thread could exit after we unlock the - // mutex, which would make the condvar access invalid memory. - let r = libc::pthread_cond_signal((*self.thread_parker).condvar.get()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutex_unlock((*self.thread_parker).mutex.get()); - debug_assert_eq!(r, 0); - } -} - -// Returns the current time on the clock used by pthread_cond_t as a timespec. -#[cfg(any(target_os = "macos", target_os = "ios"))] -#[inline] -fn timespec_now() -> libc::timespec { - let mut now = MaybeUninit::::uninit(); - let r = unsafe { libc::gettimeofday(now.as_mut_ptr(), ptr::null_mut()) }; - debug_assert_eq!(r, 0); - // SAFETY: We know `libc::gettimeofday` has initialized the value. - let now = unsafe { now.assume_init() }; - libc::timespec { - tv_sec: now.tv_sec, - tv_nsec: now.tv_usec as tv_nsec_t * 1000, - } -} -#[cfg(not(any(target_os = "macos", target_os = "ios")))] -#[inline] -fn timespec_now() -> libc::timespec { - let mut now = MaybeUninit::::uninit(); - let clock = if cfg!(target_os = "android") { - // Android doesn't support pthread_condattr_setclock, so we need to - // specify the timeout in CLOCK_REALTIME. - libc::CLOCK_REALTIME - } else { - libc::CLOCK_MONOTONIC - }; - let r = unsafe { libc::clock_gettime(clock, now.as_mut_ptr()) }; - debug_assert_eq!(r, 0); - // SAFETY: We know `libc::clock_gettime` has initialized the value. - unsafe { now.assume_init() } -} - -// Converts a relative timeout into an absolute timeout in the clock used by -// pthread_cond_t. -#[inline] -fn timeout_to_timespec(timeout: Duration) -> Option { - // Handle overflows early on - if timeout.as_secs() > libc::time_t::max_value() as u64 { - return None; - } - - let now = timespec_now(); - let mut nsec = now.tv_nsec + timeout.subsec_nanos() as tv_nsec_t; - let mut sec = now.tv_sec.checked_add(timeout.as_secs() as libc::time_t); - if nsec >= 1_000_000_000 { - nsec -= 1_000_000_000; - sec = sec.and_then(|sec| sec.checked_add(1)); - } - - sec.map(|sec| libc::timespec { - tv_nsec: nsec, - tv_sec: sec, - }) -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm.rs deleted file mode 100644 index f91a218cfe..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -//! The wasm platform can't park when atomic support is not available. -//! So this ThreadParker just panics on any attempt to park. - -use std::{thread, time::Instant}; - -pub struct ThreadParker(()); - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - fn new() -> ThreadParker { - ThreadParker(()) - } - - unsafe fn prepare_park(&self) { - panic!("Parking not supported on this platform"); - } - - unsafe fn timed_out(&self) -> bool { - panic!("Parking not supported on this platform"); - } - - unsafe fn park(&self) { - panic!("Parking not supported on this platform"); - } - - unsafe fn park_until(&self, _timeout: Instant) -> bool { - panic!("Parking not supported on this platform"); - } - - unsafe fn unpark_lock(&self) -> UnparkHandle { - panic!("Parking not supported on this platform"); - } -} - -pub struct UnparkHandle(()); - -impl super::UnparkHandleT for UnparkHandle { - unsafe fn unpark(self) {} -} - -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm_atomic.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm_atomic.rs deleted file mode 100644 index 37f302708f..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm_atomic.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use core::{ - arch::wasm32, - sync::atomic::{AtomicI32, Ordering}, -}; -use std::{convert::TryFrom, thread, time::Instant}; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - parked: AtomicI32, -} - -const UNPARKED: i32 = 0; -const PARKED: i32 = 1; - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - parked: AtomicI32::new(UNPARKED), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.parked.store(PARKED, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.parked.load(Ordering::Relaxed) == PARKED - } - - #[inline] - unsafe fn park(&self) { - while self.parked.load(Ordering::Acquire) == PARKED { - let r = unsafe { wasm32::i32_atomic_wait(self.ptr(), PARKED, -1) }; - // we should have either woken up (0) or got a not-equal due to a - // race (1). We should never time out (2) - debug_assert!(r == 0 || r == 1); - } - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - while self.parked.load(Ordering::Acquire) == PARKED { - if let Some(left) = timeout.checked_duration_since(Instant::now()) { - let nanos_left = i64::try_from(left.as_nanos()).unwrap_or(i64::max_value()); - let r = unsafe { wasm32::i32_atomic_wait(self.ptr(), PARKED, nanos_left) }; - debug_assert!(r == 0 || r == 1 || r == 2); - } else { - return false; - } - } - true - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.parked.store(UNPARKED, Ordering::Release); - UnparkHandle(self.ptr()) - } -} - -impl ThreadParker { - #[inline] - fn ptr(&self) -> *mut i32 { - &self.parked as *const AtomicI32 as *mut i32 - } -} - -pub struct UnparkHandle(*mut i32); - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - let num_notified = unsafe { wasm32::atomic_notify(self.0 as *mut i32, 1) }; - debug_assert!(num_notified == 0 || num_notified == 1); - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/keyed_event.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/keyed_event.rs deleted file mode 100644 index 7b516fe196..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/keyed_event.rs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use core::{ - mem::{self, MaybeUninit}, - ptr, -}; -use std::{ - sync::atomic::{AtomicUsize, Ordering}, - time::Instant, -}; -use winapi::{ - shared::{ - minwindef::{TRUE, ULONG}, - ntdef::NTSTATUS, - ntstatus::{STATUS_SUCCESS, STATUS_TIMEOUT}, - }, - um::{ - handleapi::CloseHandle, - libloaderapi::{GetModuleHandleA, GetProcAddress}, - winnt::{ - ACCESS_MASK, BOOLEAN, GENERIC_READ, GENERIC_WRITE, HANDLE, LARGE_INTEGER, LPCSTR, - PHANDLE, PLARGE_INTEGER, PVOID, - }, - }, -}; - -const STATE_UNPARKED: usize = 0; -const STATE_PARKED: usize = 1; -const STATE_TIMED_OUT: usize = 2; - -#[allow(non_snake_case)] -pub struct KeyedEvent { - handle: HANDLE, - NtReleaseKeyedEvent: extern "system" fn( - EventHandle: HANDLE, - Key: PVOID, - Alertable: BOOLEAN, - Timeout: PLARGE_INTEGER, - ) -> NTSTATUS, - NtWaitForKeyedEvent: extern "system" fn( - EventHandle: HANDLE, - Key: PVOID, - Alertable: BOOLEAN, - Timeout: PLARGE_INTEGER, - ) -> NTSTATUS, -} - -impl KeyedEvent { - #[inline] - unsafe fn wait_for(&self, key: PVOID, timeout: PLARGE_INTEGER) -> NTSTATUS { - (self.NtWaitForKeyedEvent)(self.handle, key, 0, timeout) - } - - #[inline] - unsafe fn release(&self, key: PVOID) -> NTSTATUS { - (self.NtReleaseKeyedEvent)(self.handle, key, 0, ptr::null_mut()) - } - - #[allow(non_snake_case)] - pub fn create() -> Option { - unsafe { - let ntdll = GetModuleHandleA(b"ntdll.dll\0".as_ptr() as LPCSTR); - if ntdll.is_null() { - return None; - } - - let NtCreateKeyedEvent = - GetProcAddress(ntdll, b"NtCreateKeyedEvent\0".as_ptr() as LPCSTR); - if NtCreateKeyedEvent.is_null() { - return None; - } - let NtReleaseKeyedEvent = - GetProcAddress(ntdll, b"NtReleaseKeyedEvent\0".as_ptr() as LPCSTR); - if NtReleaseKeyedEvent.is_null() { - return None; - } - let NtWaitForKeyedEvent = - GetProcAddress(ntdll, b"NtWaitForKeyedEvent\0".as_ptr() as LPCSTR); - if NtWaitForKeyedEvent.is_null() { - return None; - } - - let NtCreateKeyedEvent: extern "system" fn( - KeyedEventHandle: PHANDLE, - DesiredAccess: ACCESS_MASK, - ObjectAttributes: PVOID, - Flags: ULONG, - ) -> NTSTATUS = mem::transmute(NtCreateKeyedEvent); - let mut handle = MaybeUninit::uninit(); - let status = NtCreateKeyedEvent( - handle.as_mut_ptr(), - GENERIC_READ | GENERIC_WRITE, - ptr::null_mut(), - 0, - ); - if status != STATUS_SUCCESS { - return None; - } - - Some(KeyedEvent { - handle: handle.assume_init(), - NtReleaseKeyedEvent: mem::transmute(NtReleaseKeyedEvent), - NtWaitForKeyedEvent: mem::transmute(NtWaitForKeyedEvent), - }) - } - } - - #[inline] - pub fn prepare_park(&'static self, key: &AtomicUsize) { - key.store(STATE_PARKED, Ordering::Relaxed); - } - - #[inline] - pub fn timed_out(&'static self, key: &AtomicUsize) -> bool { - key.load(Ordering::Relaxed) == STATE_TIMED_OUT - } - - #[inline] - pub unsafe fn park(&'static self, key: &AtomicUsize) { - let status = self.wait_for(key as *const _ as PVOID, ptr::null_mut()); - debug_assert_eq!(status, STATUS_SUCCESS); - } - - #[inline] - pub unsafe fn park_until(&'static self, key: &AtomicUsize, timeout: Instant) -> bool { - let now = Instant::now(); - if timeout <= now { - // If another thread unparked us, we need to call - // NtWaitForKeyedEvent otherwise that thread will stay stuck at - // NtReleaseKeyedEvent. - if key.swap(STATE_TIMED_OUT, Ordering::Relaxed) == STATE_UNPARKED { - self.park(key); - return true; - } - return false; - } - - // NT uses a timeout in units of 100ns. We use a negative value to - // indicate a relative timeout based on a monotonic clock. - let mut nt_timeout: LARGE_INTEGER = mem::zeroed(); - let diff = timeout - now; - let value = (diff.as_secs() as i64) - .checked_mul(-10000000) - .and_then(|x| x.checked_sub((diff.subsec_nanos() as i64 + 99) / 100)); - - match value { - Some(x) => *nt_timeout.QuadPart_mut() = x, - None => { - // Timeout overflowed, just sleep indefinitely - self.park(key); - return true; - } - }; - - let status = self.wait_for(key as *const _ as PVOID, &mut nt_timeout); - if status == STATUS_SUCCESS { - return true; - } - debug_assert_eq!(status, STATUS_TIMEOUT); - - // If another thread unparked us, we need to call NtWaitForKeyedEvent - // otherwise that thread will stay stuck at NtReleaseKeyedEvent. - if key.swap(STATE_TIMED_OUT, Ordering::Relaxed) == STATE_UNPARKED { - self.park(key); - return true; - } - false - } - - #[inline] - pub unsafe fn unpark_lock(&'static self, key: &AtomicUsize) -> UnparkHandle { - // If the state was STATE_PARKED then we need to wake up the thread - if key.swap(STATE_UNPARKED, Ordering::Relaxed) == STATE_PARKED { - UnparkHandle { - key: key, - keyed_event: self, - } - } else { - UnparkHandle { - key: ptr::null(), - keyed_event: self, - } - } - } -} - -impl Drop for KeyedEvent { - #[inline] - fn drop(&mut self) { - unsafe { - let ok = CloseHandle(self.handle); - debug_assert_eq!(ok, TRUE); - } - } -} - -// Handle for a thread that is about to be unparked. We need to mark the thread -// as unparked while holding the queue lock, but we delay the actual unparking -// until after the queue lock is released. -pub struct UnparkHandle { - key: *const AtomicUsize, - keyed_event: &'static KeyedEvent, -} - -impl UnparkHandle { - // Wakes up the parked thread. This should be called after the queue lock is - // released to avoid blocking the queue for too long. - #[inline] - pub unsafe fn unpark(self) { - if !self.key.is_null() { - let status = self.keyed_event.release(self.key as PVOID); - debug_assert_eq!(status, STATUS_SUCCESS); - } - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/mod.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/mod.rs deleted file mode 100644 index 9db1652445..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/mod.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use core::{ - ptr, - sync::atomic::{AtomicPtr, AtomicUsize, Ordering}, -}; -use std::time::Instant; - -mod keyed_event; -mod waitaddress; - -enum Backend { - KeyedEvent(keyed_event::KeyedEvent), - WaitAddress(waitaddress::WaitAddress), -} - -static BACKEND: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - -impl Backend { - #[inline] - fn get() -> &'static Backend { - // Fast path: use the existing object - let backend_ptr = BACKEND.load(Ordering::Acquire); - if !backend_ptr.is_null() { - return unsafe { &*backend_ptr }; - }; - - Backend::create() - } - - #[cold] - fn create() -> &'static Backend { - // Try to create a new Backend - let backend; - if let Some(waitaddress) = waitaddress::WaitAddress::create() { - backend = Backend::WaitAddress(waitaddress); - } else if let Some(keyed_event) = keyed_event::KeyedEvent::create() { - backend = Backend::KeyedEvent(keyed_event); - } else { - panic!( - "parking_lot requires either NT Keyed Events (WinXP+) or \ - WaitOnAddress/WakeByAddress (Win8+)" - ); - } - - // Try to set our new Backend as the global one - let backend_ptr = Box::into_raw(Box::new(backend)); - match BACKEND.compare_exchange( - ptr::null_mut(), - backend_ptr, - Ordering::Release, - Ordering::Relaxed, - ) { - Ok(_) => unsafe { &*backend_ptr }, - Err(global_backend_ptr) => { - unsafe { - // We lost the race, free our object and return the global one - Box::from_raw(backend_ptr); - &*global_backend_ptr - } - } - } - } -} - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - key: AtomicUsize, - backend: &'static Backend, -} - -impl ThreadParker { - pub const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - pub fn new() -> ThreadParker { - // Initialize the backend here to ensure we don't get any panics - // later on, which could leave synchronization primitives in a broken - // state. - ThreadParker { - key: AtomicUsize::new(0), - backend: Backend::get(), - } - } - - // Prepares the parker. This should be called before adding it to the queue. - #[inline] - pub fn prepare_park(&self) { - match *self.backend { - Backend::KeyedEvent(ref x) => x.prepare_park(&self.key), - Backend::WaitAddress(ref x) => x.prepare_park(&self.key), - } - } - - // Checks if the park timed out. This should be called while holding the - // queue lock after park_until has returned false. - #[inline] - pub fn timed_out(&self) -> bool { - match *self.backend { - Backend::KeyedEvent(ref x) => x.timed_out(&self.key), - Backend::WaitAddress(ref x) => x.timed_out(&self.key), - } - } - - // Parks the thread until it is unparked. This should be called after it has - // been added to the queue, after unlocking the queue. - #[inline] - pub unsafe fn park(&self) { - match *self.backend { - Backend::KeyedEvent(ref x) => x.park(&self.key), - Backend::WaitAddress(ref x) => x.park(&self.key), - } - } - - // Parks the thread until it is unparked or the timeout is reached. This - // should be called after it has been added to the queue, after unlocking - // the queue. Returns true if we were unparked and false if we timed out. - #[inline] - pub unsafe fn park_until(&self, timeout: Instant) -> bool { - match *self.backend { - Backend::KeyedEvent(ref x) => x.park_until(&self.key, timeout), - Backend::WaitAddress(ref x) => x.park_until(&self.key, timeout), - } - } - - // Locks the parker to prevent the target thread from exiting. This is - // necessary to ensure that thread-local ThreadData objects remain valid. - // This should be called while holding the queue lock. - #[inline] - pub unsafe fn unpark_lock(&self) -> UnparkHandle { - match *self.backend { - Backend::KeyedEvent(ref x) => UnparkHandle::KeyedEvent(x.unpark_lock(&self.key)), - Backend::WaitAddress(ref x) => UnparkHandle::WaitAddress(x.unpark_lock(&self.key)), - } - } -} - -// Handle for a thread that is about to be unparked. We need to mark the thread -// as unparked while holding the queue lock, but we delay the actual unparking -// until after the queue lock is released. -pub enum UnparkHandle { - KeyedEvent(keyed_event::UnparkHandle), - WaitAddress(waitaddress::UnparkHandle), -} - -impl UnparkHandle { - // Wakes up the parked thread. This should be called after the queue lock is - // released to avoid blocking the queue for too long. - #[inline] - pub unsafe fn unpark(self) { - match self { - UnparkHandle::KeyedEvent(x) => x.unpark(), - UnparkHandle::WaitAddress(x) => x.unpark(), - } - } -} - -// Yields the rest of the current timeslice to the OS -#[inline] -pub fn thread_yield() { - // Note that this is manually defined here rather than using the definition - // through `winapi`. The `winapi` definition comes from the `synchapi` - // header which enables the "synchronization.lib" library. It turns out, - // however that `Sleep` comes from `kernel32.dll` so this activation isn't - // necessary. - // - // This was originally identified in rust-lang/rust where on MinGW the - // libsynchronization.a library pulls in a dependency on a newer DLL not - // present in older versions of Windows. (see rust-lang/rust#49438) - // - // This is a bit of a hack for now and ideally we'd fix MinGW's own import - // libraries, but that'll probably take a lot longer than patching this here - // and avoiding the `synchapi` feature entirely. - extern "system" { - fn Sleep(a: winapi::shared::minwindef::DWORD); - } - unsafe { - // We don't use SwitchToThread here because it doesn't consider all - // threads in the system and the thread we are waiting for may not get - // selected. - Sleep(0); - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/waitaddress.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/waitaddress.rs deleted file mode 100644 index 0ec780404d..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/waitaddress.rs +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use core::{ - mem, - sync::atomic::{AtomicUsize, Ordering}, -}; -use std::time::Instant; -use winapi::{ - shared::{ - basetsd::SIZE_T, - minwindef::{BOOL, DWORD, FALSE, TRUE}, - winerror::ERROR_TIMEOUT, - }, - um::{ - errhandlingapi::GetLastError, - libloaderapi::{GetModuleHandleA, GetProcAddress}, - winbase::INFINITE, - winnt::{LPCSTR, PVOID}, - }, -}; - -#[allow(non_snake_case)] -pub struct WaitAddress { - WaitOnAddress: extern "system" fn( - Address: PVOID, - CompareAddress: PVOID, - AddressSize: SIZE_T, - dwMilliseconds: DWORD, - ) -> BOOL, - WakeByAddressSingle: extern "system" fn(Address: PVOID), -} - -impl WaitAddress { - #[allow(non_snake_case)] - pub fn create() -> Option { - unsafe { - // MSDN claims that that WaitOnAddress and WakeByAddressSingle are - // located in kernel32.dll, but they are lying... - let synch_dll = - GetModuleHandleA(b"api-ms-win-core-synch-l1-2-0.dll\0".as_ptr() as LPCSTR); - if synch_dll.is_null() { - return None; - } - - let WaitOnAddress = GetProcAddress(synch_dll, b"WaitOnAddress\0".as_ptr() as LPCSTR); - if WaitOnAddress.is_null() { - return None; - } - let WakeByAddressSingle = - GetProcAddress(synch_dll, b"WakeByAddressSingle\0".as_ptr() as LPCSTR); - if WakeByAddressSingle.is_null() { - return None; - } - Some(WaitAddress { - WaitOnAddress: mem::transmute(WaitOnAddress), - WakeByAddressSingle: mem::transmute(WakeByAddressSingle), - }) - } - } - - #[inline] - pub fn prepare_park(&'static self, key: &AtomicUsize) { - key.store(1, Ordering::Relaxed); - } - - #[inline] - pub fn timed_out(&'static self, key: &AtomicUsize) -> bool { - key.load(Ordering::Relaxed) != 0 - } - - #[inline] - pub fn park(&'static self, key: &AtomicUsize) { - while key.load(Ordering::Acquire) != 0 { - let r = self.wait_on_address(key, INFINITE); - debug_assert!(r == TRUE); - } - } - - #[inline] - pub fn park_until(&'static self, key: &AtomicUsize, timeout: Instant) -> bool { - while key.load(Ordering::Acquire) != 0 { - let now = Instant::now(); - if timeout <= now { - return false; - } - let diff = timeout - now; - let timeout = diff - .as_secs() - .checked_mul(1000) - .and_then(|x| x.checked_add((diff.subsec_nanos() as u64 + 999999) / 1000000)) - .map(|ms| { - if ms > ::max_value() as u64 { - INFINITE - } else { - ms as DWORD - } - }) - .unwrap_or(INFINITE); - if self.wait_on_address(key, timeout) == FALSE { - debug_assert_eq!(unsafe { GetLastError() }, ERROR_TIMEOUT); - } - } - true - } - - #[inline] - pub fn unpark_lock(&'static self, key: &AtomicUsize) -> UnparkHandle { - // We don't need to lock anything, just clear the state - key.store(0, Ordering::Release); - - UnparkHandle { - key: key, - waitaddress: self, - } - } - - #[inline] - fn wait_on_address(&'static self, key: &AtomicUsize, timeout: DWORD) -> BOOL { - let cmp = 1usize; - (self.WaitOnAddress)( - key as *const _ as PVOID, - &cmp as *const _ as PVOID, - mem::size_of::() as SIZE_T, - timeout, - ) - } -} - -// Handle for a thread that is about to be unparked. We need to mark the thread -// as unparked while holding the queue lock, but we delay the actual unparking -// until after the queue lock is released. -pub struct UnparkHandle { - key: *const AtomicUsize, - waitaddress: &'static WaitAddress, -} - -impl UnparkHandle { - // Wakes up the parked thread. This should be called after the queue lock is - // released to avoid blocking the queue for too long. - #[inline] - pub fn unpark(self) { - (self.waitaddress.WakeByAddressSingle)(self.key as PVOID); - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/util.rs b/vendor/parking_lot_core-0.7.2/src/util.rs deleted file mode 100644 index d7aaa87155..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/util.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -// Option::unchecked_unwrap -pub trait UncheckedOptionExt { - unsafe fn unchecked_unwrap(self) -> T; -} - -impl UncheckedOptionExt for Option { - #[inline] - unsafe fn unchecked_unwrap(self) -> T { - match self { - Some(x) => x, - None => unreachable(), - } - } -} - -// hint::unreachable_unchecked() in release mode -#[inline] -unsafe fn unreachable() -> ! { - if cfg!(debug_assertions) { - unreachable!(); - } else { - core::hint::unreachable_unchecked() - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/word_lock.rs b/vendor/parking_lot_core-0.7.2/src/word_lock.rs deleted file mode 100644 index 450e98556c..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/word_lock.rs +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use crate::spinwait::SpinWait; -use crate::thread_parker::{ThreadParker, ThreadParkerT, UnparkHandleT}; -use core::{ - cell::Cell, - mem, ptr, - sync::atomic::{fence, AtomicUsize, Ordering}, -}; - -struct ThreadData { - parker: ThreadParker, - - // Linked list of threads in the queue. The queue is split into two parts: - // the processed part and the unprocessed part. When new nodes are added to - // the list, they only have the next pointer set, and queue_tail is null. - // - // Nodes are processed with the queue lock held, which consists of setting - // the prev pointer for each node and setting the queue_tail pointer on the - // first processed node of the list. - // - // This setup allows nodes to be added to the queue without a lock, while - // still allowing O(1) removal of nodes from the processed part of the list. - // The only cost is the O(n) processing, but this only needs to be done - // once for each node, and therefore isn't too expensive. - queue_tail: Cell<*const ThreadData>, - prev: Cell<*const ThreadData>, - next: Cell<*const ThreadData>, -} - -impl ThreadData { - #[inline] - fn new() -> ThreadData { - assert!(mem::align_of::() > !QUEUE_MASK); - ThreadData { - parker: ThreadParker::new(), - queue_tail: Cell::new(ptr::null()), - prev: Cell::new(ptr::null()), - next: Cell::new(ptr::null()), - } - } -} - -// Invokes the given closure with a reference to the current thread `ThreadData`. -#[inline] -fn with_thread_data(f: impl FnOnce(&ThreadData) -> T) -> T { - let mut thread_data_ptr = ptr::null(); - // If ThreadData is expensive to construct, then we want to use a cached - // version in thread-local storage if possible. - if !ThreadParker::IS_CHEAP_TO_CONSTRUCT { - thread_local!(static THREAD_DATA: ThreadData = ThreadData::new()); - if let Ok(tls_thread_data) = THREAD_DATA.try_with(|x| x as *const ThreadData) { - thread_data_ptr = tls_thread_data; - } - } - // Otherwise just create a ThreadData on the stack - let mut thread_data_storage = None; - if thread_data_ptr.is_null() { - thread_data_ptr = thread_data_storage.get_or_insert_with(ThreadData::new); - } - - f(unsafe { &*thread_data_ptr }) -} - -const LOCKED_BIT: usize = 1; -const QUEUE_LOCKED_BIT: usize = 2; -const QUEUE_MASK: usize = !3; - -// Word-sized lock that is used to implement the parking_lot API. Since this -// can't use parking_lot, it instead manages its own queue of waiting threads. -pub struct WordLock { - state: AtomicUsize, -} - -impl WordLock { - /// Returns a new, unlocked, WordLock. - pub const fn new() -> Self { - WordLock { - state: AtomicUsize::new(0), - } - } - - #[inline] - pub fn lock(&self) { - if self - .state - .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - return; - } - self.lock_slow(); - } - - /// Must not be called on an already unlocked `WordLock`! - #[inline] - pub unsafe fn unlock(&self) { - let state = self.state.fetch_sub(LOCKED_BIT, Ordering::Release); - if state.is_queue_locked() || state.queue_head().is_null() { - return; - } - self.unlock_slow(); - } - - #[cold] - fn lock_slow(&self) { - let mut spinwait = SpinWait::new(); - let mut state = self.state.load(Ordering::Relaxed); - loop { - // Grab the lock if it isn't locked, even if there is a queue on it - if !state.is_locked() { - match self.state.compare_exchange_weak( - state, - state | LOCKED_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return, - Err(x) => state = x, - } - continue; - } - - // If there is no queue, try spinning a few times - if state.queue_head().is_null() && spinwait.spin() { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Get our thread data and prepare it for parking - state = with_thread_data(|thread_data| { - // The pthread implementation is still unsafe, so we need to surround `prepare_park` - // with `unsafe {}`. - #[allow(unused_unsafe)] - unsafe { - thread_data.parker.prepare_park(); - } - - // Add our thread to the front of the queue - let queue_head = state.queue_head(); - if queue_head.is_null() { - thread_data.queue_tail.set(thread_data); - thread_data.prev.set(ptr::null()); - } else { - thread_data.queue_tail.set(ptr::null()); - thread_data.prev.set(ptr::null()); - thread_data.next.set(queue_head); - } - if let Err(x) = self.state.compare_exchange_weak( - state, - state.with_queue_head(thread_data), - Ordering::Release, - Ordering::Relaxed, - ) { - return x; - } - - // Sleep until we are woken up by an unlock - // Ignoring unused unsafe, since it's only a few platforms where this is unsafe. - #[allow(unused_unsafe)] - unsafe { - thread_data.parker.park(); - } - - // Loop back and try locking again - spinwait.reset(); - self.state.load(Ordering::Relaxed) - }); - } - } - - #[cold] - fn unlock_slow(&self) { - let mut state = self.state.load(Ordering::Relaxed); - loop { - // We just unlocked the WordLock. Just check if there is a thread - // to wake up. If the queue is locked then another thread is already - // taking care of waking up a thread. - if state.is_queue_locked() || state.queue_head().is_null() { - return; - } - - // Try to grab the queue lock - match self.state.compare_exchange_weak( - state, - state | QUEUE_LOCKED_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => break, - Err(x) => state = x, - } - } - - // Now we have the queue lock and the queue is non-empty - 'outer: loop { - // First, we need to fill in the prev pointers for any newly added - // threads. We do this until we reach a node that we previously - // processed, which has a non-null queue_tail pointer. - let queue_head = state.queue_head(); - let mut queue_tail; - let mut current = queue_head; - loop { - queue_tail = unsafe { (*current).queue_tail.get() }; - if !queue_tail.is_null() { - break; - } - unsafe { - let next = (*current).next.get(); - (*next).prev.set(current); - current = next; - } - } - - // Set queue_tail on the queue head to indicate that the whole list - // has prev pointers set correctly. - unsafe { - (*queue_head).queue_tail.set(queue_tail); - } - - // If the WordLock is locked, then there is no point waking up a - // thread now. Instead we let the next unlocker take care of waking - // up a thread. - if state.is_locked() { - match self.state.compare_exchange_weak( - state, - state & !QUEUE_LOCKED_BIT, - Ordering::Release, - Ordering::Relaxed, - ) { - Ok(_) => return, - Err(x) => state = x, - } - - // Need an acquire fence before reading the new queue - fence(Ordering::Acquire); - continue; - } - - // Remove the last thread from the queue and unlock the queue - let new_tail = unsafe { (*queue_tail).prev.get() }; - if new_tail.is_null() { - loop { - match self.state.compare_exchange_weak( - state, - state & LOCKED_BIT, - Ordering::Release, - Ordering::Relaxed, - ) { - Ok(_) => break, - Err(x) => state = x, - } - - // If the compare_exchange failed because a new thread was - // added to the queue then we need to re-scan the queue to - // find the previous element. - if state.queue_head().is_null() { - continue; - } else { - // Need an acquire fence before reading the new queue - fence(Ordering::Acquire); - continue 'outer; - } - } - } else { - unsafe { - (*queue_head).queue_tail.set(new_tail); - } - self.state.fetch_and(!QUEUE_LOCKED_BIT, Ordering::Release); - } - - // Finally, wake up the thread we removed from the queue. Note that - // we don't need to worry about any races here since the thread is - // guaranteed to be sleeping right now and we are the only one who - // can wake it up. - unsafe { - (*queue_tail).parker.unpark_lock().unpark(); - } - break; - } - } -} - -trait LockState { - fn is_locked(self) -> bool; - fn is_queue_locked(self) -> bool; - fn queue_head(self) -> *const ThreadData; - fn with_queue_head(self, thread_data: *const ThreadData) -> Self; -} - -impl LockState for usize { - #[inline] - fn is_locked(self) -> bool { - self & LOCKED_BIT != 0 - } - - #[inline] - fn is_queue_locked(self) -> bool { - self & QUEUE_LOCKED_BIT != 0 - } - - #[inline] - fn queue_head(self) -> *const ThreadData { - (self & QUEUE_MASK) as *const ThreadData - } - - #[inline] - fn with_queue_head(self, thread_data: *const ThreadData) -> Self { - (self & !QUEUE_MASK) | thread_data as *const _ as usize - } -} diff --git a/vendor/perf-event-open-sys/.cargo-checksum.json b/vendor/perf-event-open-sys/.cargo-checksum.json index 119b79c89e..94c12b528d 100644 --- a/vendor/perf-event-open-sys/.cargo-checksum.json +++ b/vendor/perf-event-open-sys/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"14708662285df53727379173710830d7cb206c1c2fe500cf58708cd0a5f90be2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"383389744bfd0cd720224f8a01fb6dd28be093ba4965363dcd0d6ae8da3d087b","regenerate.sh":"75c81d43681cd44c961da0399605a8cfe1b05b6d3a8659e11e9984f9f7c88618","src/bindings.rs":"ee0d5d224dfeae4feefbbfbf2ce46b7617ba109fa1b7f88ab886a99131d41bab","src/lib.rs":"3e95e8889d74376321caa6ff2d8ff634e08bb34d70a3ba63a6b1737de01c3e24","wrapper.h":"22abab03fcdb32f39c72756da8c45dd4d4b6cbf3de24d8922dbc3a460bccf27a"},"package":"66f37842e29d92d05872a3c0271ba6717842695ecb896cb2e147a825c804b207"} \ No newline at end of file +{"files":{"Cargo.toml":"43d4960bd26abbc5e6682924a3a35cd5b96ddde703f8578e1b304dcbfcc77a7a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"383389744bfd0cd720224f8a01fb6dd28be093ba4965363dcd0d6ae8da3d087b","regenerate.sh":"75c81d43681cd44c961da0399605a8cfe1b05b6d3a8659e11e9984f9f7c88618","src/bindings.rs":"ee0d5d224dfeae4feefbbfbf2ce46b7617ba109fa1b7f88ab886a99131d41bab","src/lib.rs":"42c2107446f81663e4c59a11148ebc8df5241b62a58f0712133382667bc35176","wrapper.h":"22abab03fcdb32f39c72756da8c45dd4d4b6cbf3de24d8922dbc3a460bccf27a"},"package":"ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a"} \ No newline at end of file diff --git a/vendor/perf-event-open-sys/Cargo.toml b/vendor/perf-event-open-sys/Cargo.toml index 650f36bb27..1fd0b9dd4c 100644 --- a/vendor/perf-event-open-sys/Cargo.toml +++ b/vendor/perf-event-open-sys/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "perf-event-open-sys" -version = "1.0.0" +version = "1.0.1" authors = ["Jim Blandy "] description = "Unsafe, direct bindings for Linux's perf_event_open system call, with associated\ntypes and constants.\n" readme = "README.md" diff --git a/vendor/perf-event-open-sys/src/lib.rs b/vendor/perf-event-open-sys/src/lib.rs index 468c3727df..3144280457 100644 --- a/vendor/perf-event-open-sys/src/lib.rs +++ b/vendor/perf-event-open-sys/src/lib.rs @@ -16,6 +16,9 @@ //! There are several ioctls for use with `perf_event_open` file descriptors; //! see the [`ioctls`] module for those. //! +//! For a safe and convenient interface to this functionality, see the +//! [`perf_event`] crate. +//! //! ## Using the raw API //! //! As the kernel interface evolves, the struct and union types from the @@ -52,55 +55,19 @@ //! ``` //! //! It is not necessary to adjust `size` to what the running kernel expects: -//! older kernels can accept newer `perf_event_attr` structs, and vice versa. -//! The kernel simply checks that any fields it doesn't know about are zero, and -//! pads smaller-than-expected structs with zeros. -//! -//! If the `size` field was properly initialized, an error result of `E2BIG` -//! indicates that the `attrs` structure has requested behavior the kernel is -//! too old to support. When this error code is returned, the kernel writes the -//! size it expected back to the `size` field of the `attrs` struct. -//! -//! This approach works nicely with Linux system call conventions. As a general -//! principle, old fields are never removed from a struct, for backwards -//! compatibility. New fields are always added to the end, and are defined to -//! have no effect when their value is zero. Each system call indicates, through -//! one means or another, the size of the struct being passed (in the case of -//! `perf_event_attr`, the `size` field does this), and this size is used to -//! indicate which version of the API userspace thinks it's using. There are -//! three cases: -//! -//! - The kernel's own definition of the struct has the same size as the -//! struct passed from userspace. This means that userspace is using the -//! same version of the header files as the kernel, so all is well. -//! -//! - The kernel's struct is larger than the one passed from userspace. This -//! means the kernel is newer than the userspace program. The kernel copies -//! the userspace data into the initial bytes of its own struct, and zeros -//! the remaining bytes. Since zeroed fields have no effect, the resulting -//! struct properly reflects the user's intent. -//! -//! - The kernel's struct is smaller than the one passed from userspace. This -//! means that an executable built on a newer kernel is running on an older -//! kernel. The kernel checks that the excess bytes in the userspace struct -//! are all zero; if they are not, the system call returns `E2BIG`, -//! indicating that userspace has requested a feature the kernel doesn't -//! support. If they are all zero, then the kernel initializes its own -//! struct with the bytes from the start of the userspace struct, and drops -//! the rest. Since the dropped bytes were all zero, they did not affect the -//! requested behavior, and the resulting struct reflects the user's intent. -//! -//! This approach is explained by the kernel comments for -//! `copy_struct_from_user` in `include/linux/uaccess.h`. The upshot is that -//! older code can run against newer kernels and vice versa, and errors are only -//! returned when the call actually requests functionality that the kernel -//! doesn't support. +//! older kernels can accept newer `perf_event_attr` structs, and vice versa. As +//! long as the `size` field was properly initialized, an error result of +//! `E2BIG` indicates that the `attrs` structure has requested behavior the +//! kernel is too old to support. //! -//! You can find one example of using `perf_event_open` in the [`perf_event`] -//! crate, which provides a safe interface to a subset of `perf_event_open`'s -//! functionality. +//! When `E2BIG` is returned, the kernel writes the size it expected back to the +//! `size` field of the `attrs` struct. Again, if you want to retry the call, it +//! is not necessary to adjust the size you pass to match what the kernel passed +//! back. The size from the kernel just indicates which version of the API the +//! kernel supports; see the documentation for the `PERF_EVENT_ATTR_SIZE_VER...` +//! constants for details. //! -//! ### Kernel versions +//! ## Kernel versions //! //! The bindings in this crate are generated from the Linux kernel headers //! packaged by Fedora as `kernel-headers-5.6.11-100.fc30.x86_64`, which @@ -119,6 +86,84 @@ //! If you need features that are available only in a more recent version of the //! types than this crate provides, please file an issue. //! +//! ## Linux API Backward/Forward Compatibility Strategy +//! +//! (This is more detail than necessary if you just want to use the crate. I +//! want to write this down somewhere so that I have something to refer to when +//! I forget the details.) +//! +//! It is an important principle of Linux kernel development that new versions +//! of the kernel should not break userspace. If upgrading your kernel breaks a +//! user program, then that's a bug in the kernel. (This refers to the run-time +//! interface. I don't know what the stability rules are for the kernel headers: +//! can new headers cause old code to fail to compile? Anyway, run time is our +//! concern here.) +//! +//! But when you have an open-ended, complex system call like `perf_event_open`, +//! it's really important for the interface to be able to evolve. Certainly, old +//! programs must run properly on new kernels, but ideally, it should work the +//! other way, too: a program built against a newer version of the kernel +//! headers should run on an older kernel, as long as it only requests features +//! the old kernel actually supports. That is, simply compiling against newer +//! headers should not be disqualifying - only using those new headers to +//! request features the running kernel can't provide should cause an error. +//! +//! Consider the specific case of passing a struct like `perf_event_attr` to a +//! system call like `perf_event_open`. In general, there are two versions of +//! the struct in play: the version the user program was compiled against, and +//! the version the running kernel was compiled against. How can we let old +//! programs call `perf_event_open` on new kernels, and vice versa? +//! +//! Linux has a neat strategy for making this work. There are four rules: +//! +//! - Every system call that passes a struct to the kernel includes some +//! indication of how large userspace thinks that struct is. For +//! `perf_event_open`, it's the `size` field of the `perf_event_attr` +//! struct. For `ioctl`s that pass a struct, it's a bitfield of the +//! `request` value. +//! +//! - Fields are never deleted from structs. At most, newer kernel headers may +//! rename them to '__reserved_foo' or something like that, but once a field +//! has been placed, its layout in the struct never changes. +//! +//! - New fields are added to the end of structs. +//! +//! - New fields' semantics are chosen such that filling them with zeros +//! preserves the old behavior. That is, turning an old struct into a new +//! struct by extending it with zero bytes should always give you a new +//! struct with the same meaning the old struct had. +//! +//! Then, the kernel's strategy for receiving structs from userspace (explained +//! by the kernel comments for `copy_struct_from_user` in +//! `include/linux/uaccess.h`) is as follows: +//! +//! - If the kernel's struct is larger than the one passed from userspace, +//! then that means the kernel is newer than the userspace program. The +//! kernel copies the userspace data into the initial bytes of its own +//! struct, and zeros the remaining bytes. Since zeroed fields have no +//! effect, the resulting struct properly reflects the user's intent. +//! +//! - If the kernel's struct is smaller than the one passed from userspace, +//! then that means that a userspace program compiled against newer kernel +//! headers is running on an older kernel. The kernel checks that the excess +//! bytes in the userspace struct are all zero; if they are not, the system +//! call returns `E2BIG`, indicating that userspace has requested a feature +//! the kernel doesn't support. If they are all zero, then the kernel +//! initializes its own struct with the bytes from the start of the +//! userspace struct, and drops the rest. Since the dropped bytes were all +//! zero, they did not affect the requested behavior, and the resulting +//! struct reflects the user's intent. +//! +//! - In either case, the kernel verifies that any `__reserved_foo` fields in +//! its own version of the struct are zero. +//! +//! This covers both the old-on-new and new-on-old cases, and returns an error +//! only when the call requests functionality the kernel doesn't support. +//! +//! You can find one example of using `perf_event_open` in the [`perf_event`] +//! crate, which provides a safe interface to a subset of `perf_event_open`'s +//! functionality. +//! //! [`bindings`]: bindings/index.html //! [`ioctls`]: ioctls/index.html //! [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html diff --git a/vendor/proc-macro-error-attr/.cargo-checksum.json b/vendor/proc-macro-error-attr/.cargo-checksum.json new file mode 100644 index 0000000000..c30b5418a8 --- /dev/null +++ b/vendor/proc-macro-error-attr/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"fbd3ce928441a0b43859bbbe36549f05e7a1ebfee62e5982710671a8f41de527","LICENSE-APACHE":"6fd0f3522047150ca7c1939f02bc4a15662a4741a89bc03ae784eefa18caa299","LICENSE-MIT":"544b3aed1fd723d0cadea567affdcfe0431e43e18d997a718f9d67256b814fde","build.rs":"37b0aca3c4a14dfc050c2df38ae633311d7a1532cdbb8eb57182802c4a1983eb","src/lib.rs":"9e3d13c266376b688642572bb4091e094ff5277fce4bee72bcc3c5f982dd831c","src/parse.rs":"2d8f220f91235be8ed0ddcab55ec3699b9d3b28d538ed24197797cc20194c473","src/settings.rs":"be9382479d7a857b55e5a0b1014f72150c9ee7f2bbb5a5bdeabc0f8de2d95c26"},"package":"a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"} \ No newline at end of file diff --git a/vendor/proc-macro-error-attr/Cargo.toml b/vendor/proc-macro-error-attr/Cargo.toml new file mode 100644 index 0000000000..a2c766de9b --- /dev/null +++ b/vendor/proc-macro-error-attr/Cargo.toml @@ -0,0 +1,33 @@ +# 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 = "proc-macro-error-attr" +version = "1.0.4" +authors = ["CreepySkeleton "] +build = "build.rs" +description = "Attribute macro for proc-macro-error crate" +license = "MIT OR Apache-2.0" +repository = "https://gitlab.com/CreepySkeleton/proc-macro-error" +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lib] +proc-macro = true +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" +[build-dependencies.version_check] +version = "0.9" diff --git a/vendor/proc-macro-error-attr/LICENSE-APACHE b/vendor/proc-macro-error-attr/LICENSE-APACHE new file mode 100644 index 0000000000..658240a840 --- /dev/null +++ b/vendor/proc-macro-error-attr/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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-2020 CreepySkeleton + +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/proc-macro-error-attr/LICENSE-MIT b/vendor/proc-macro-error-attr/LICENSE-MIT new file mode 100644 index 0000000000..fc73e591d7 --- /dev/null +++ b/vendor/proc-macro-error-attr/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2020 CreepySkeleton + +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/proc-macro-error-attr/build.rs b/vendor/proc-macro-error-attr/build.rs new file mode 100644 index 0000000000..f2ac6a70ee --- /dev/null +++ b/vendor/proc-macro-error-attr/build.rs @@ -0,0 +1,5 @@ +fn main() { + if version_check::is_max_version("1.36.0").unwrap_or(false) { + println!("cargo:rustc-cfg=always_assert_unwind"); + } +} diff --git a/vendor/proc-macro-error-attr/src/lib.rs b/vendor/proc-macro-error-attr/src/lib.rs new file mode 100644 index 0000000000..ac0ac21a26 --- /dev/null +++ b/vendor/proc-macro-error-attr/src/lib.rs @@ -0,0 +1,121 @@ +//! This is `#[proc_macro_error]` attribute to be used with +//! [`proc-macro-error`](https://docs.rs/proc-macro-error/). There you go. + +extern crate proc_macro; + +use crate::parse::parse_input; +use crate::parse::Attribute; +use proc_macro::TokenStream; +use proc_macro2::{Literal, Span, TokenStream as TokenStream2, TokenTree}; +use quote::{quote, quote_spanned}; + +use crate::settings::{Setting::*, *}; + +mod parse; +mod settings; + +type Result = std::result::Result; + +struct Error { + span: Span, + message: String, +} + +impl Error { + fn new(span: Span, message: String) -> Self { + Error { span, message } + } + + fn into_compile_error(self) -> TokenStream2 { + let mut message = Literal::string(&self.message); + message.set_span(self.span); + quote_spanned!(self.span=> compile_error!{#message}) + } +} + +#[proc_macro_attribute] +pub fn proc_macro_error(attr: TokenStream, input: TokenStream) -> TokenStream { + match impl_proc_macro_error(attr.into(), input.clone().into()) { + Ok(ts) => ts, + Err(e) => { + let error = e.into_compile_error(); + let input = TokenStream2::from(input); + + quote!(#input #error).into() + } + } +} + +fn impl_proc_macro_error(attr: TokenStream2, input: TokenStream2) -> Result { + let (attrs, signature, body) = parse_input(input)?; + let mut settings = parse_settings(attr)?; + + let is_proc_macro = is_proc_macro(&attrs); + if is_proc_macro { + settings.set(AssertUnwindSafe); + } + + if detect_proc_macro_hack(&attrs) { + settings.set(ProcMacroHack); + } + + if settings.is_set(ProcMacroHack) { + settings.set(AllowNotMacro); + } + + if !(settings.is_set(AllowNotMacro) || is_proc_macro) { + return Err(Error::new( + Span::call_site(), + "#[proc_macro_error] attribute can be used only with procedural macros\n\n \ + = hint: if you are really sure that #[proc_macro_error] should be applied \ + to this exact function, use #[proc_macro_error(allow_not_macro)]\n" + .into(), + )); + } + + let body = gen_body(body, settings); + + let res = quote! { + #(#attrs)* + #(#signature)* + { #body } + }; + Ok(res.into()) +} + +#[cfg(not(always_assert_unwind))] +fn gen_body(block: TokenTree, settings: Settings) -> proc_macro2::TokenStream { + let is_proc_macro_hack = settings.is_set(ProcMacroHack); + let closure = if settings.is_set(AssertUnwindSafe) { + quote!(::std::panic::AssertUnwindSafe(|| #block )) + } else { + quote!(|| #block) + }; + + quote!( ::proc_macro_error::entry_point(#closure, #is_proc_macro_hack) ) +} + +// FIXME: +// proc_macro::TokenStream does not implement UnwindSafe until 1.37.0. +// Considering this is the closure's return type the unwind safety check would fail +// for virtually every closure possible, the check is meaningless. +#[cfg(always_assert_unwind)] +fn gen_body(block: TokenTree, settings: Settings) -> proc_macro2::TokenStream { + let is_proc_macro_hack = settings.is_set(ProcMacroHack); + let closure = quote!(::std::panic::AssertUnwindSafe(|| #block )); + quote!( ::proc_macro_error::entry_point(#closure, #is_proc_macro_hack) ) +} + +fn detect_proc_macro_hack(attrs: &[Attribute]) -> bool { + attrs + .iter() + .any(|attr| attr.path_is_ident("proc_macro_hack")) +} + +fn is_proc_macro(attrs: &[Attribute]) -> bool { + attrs.iter().any(|attr| { + attr.path_is_ident("proc_macro") + || attr.path_is_ident("proc_macro_derive") + || attr.path_is_ident("proc_macro_attribute") + }) +} diff --git a/vendor/proc-macro-error-attr/src/parse.rs b/vendor/proc-macro-error-attr/src/parse.rs new file mode 100644 index 0000000000..6f4663f80e --- /dev/null +++ b/vendor/proc-macro-error-attr/src/parse.rs @@ -0,0 +1,89 @@ +use crate::{Error, Result}; +use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree}; +use quote::ToTokens; +use std::iter::Peekable; + +pub(crate) fn parse_input( + input: TokenStream, +) -> Result<(Vec, Vec, TokenTree)> { + let mut input = input.into_iter().peekable(); + let mut attrs = Vec::new(); + + while let Some(attr) = parse_next_attr(&mut input)? { + attrs.push(attr); + } + + let sig = parse_signature(&mut input); + let body = input.next().ok_or_else(|| { + Error::new( + Span::call_site(), + "`#[proc_macro_error]` can be applied only to functions".to_string(), + ) + })?; + + Ok((attrs, sig, body)) +} + +fn parse_next_attr( + input: &mut Peekable>, +) -> Result> { + let shebang = match input.peek() { + Some(TokenTree::Punct(ref punct)) if punct.as_char() == '#' => input.next().unwrap(), + _ => return Ok(None), + }; + + let group = match input.peek() { + Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Bracket => { + let res = group.clone(); + input.next(); + res + } + other => { + let span = other.map_or(Span::call_site(), |tt| tt.span()); + return Err(Error::new(span, "expected `[`".to_string())); + } + }; + + let path = match group.stream().into_iter().next() { + Some(TokenTree::Ident(ident)) => Some(ident), + _ => None, + }; + + Ok(Some(Attribute { + shebang, + group: TokenTree::Group(group), + path, + })) +} + +fn parse_signature(input: &mut Peekable>) -> Vec { + let mut sig = Vec::new(); + loop { + match input.peek() { + Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Brace => { + return sig; + } + None => return sig, + _ => sig.push(input.next().unwrap()), + } + } +} + +pub(crate) struct Attribute { + pub(crate) shebang: TokenTree, + pub(crate) group: TokenTree, + pub(crate) path: Option, +} + +impl Attribute { + pub(crate) fn path_is_ident(&self, ident: &str) -> bool { + self.path.as_ref().map_or(false, |p| *p == ident) + } +} + +impl ToTokens for Attribute { + fn to_tokens(&self, ts: &mut TokenStream) { + self.shebang.to_tokens(ts); + self.group.to_tokens(ts); + } +} diff --git a/vendor/proc-macro-error-attr/src/settings.rs b/vendor/proc-macro-error-attr/src/settings.rs new file mode 100644 index 0000000000..0b7ec766f6 --- /dev/null +++ b/vendor/proc-macro-error-attr/src/settings.rs @@ -0,0 +1,72 @@ +use crate::{Error, Result}; +use proc_macro2::{Ident, Span, TokenStream, TokenTree}; + +macro_rules! decl_settings { + ($($val:expr => $variant:ident),+ $(,)*) => { + #[derive(PartialEq)] + pub(crate) enum Setting { + $($variant),* + } + + fn ident_to_setting(ident: Ident) -> Result { + match &*ident.to_string() { + $($val => Ok(Setting::$variant),)* + _ => { + let possible_vals = [$($val),*] + .iter() + .map(|v| format!("`{}`", v)) + .collect::>() + .join(", "); + + Err(Error::new( + ident.span(), + format!("unknown setting `{}`, expected one of {}", ident, possible_vals))) + } + } + } + }; +} + +decl_settings! { + "assert_unwind_safe" => AssertUnwindSafe, + "allow_not_macro" => AllowNotMacro, + "proc_macro_hack" => ProcMacroHack, +} + +pub(crate) fn parse_settings(input: TokenStream) -> Result { + let mut input = input.into_iter(); + let mut res = Settings(Vec::new()); + loop { + match input.next() { + Some(TokenTree::Ident(ident)) => { + res.0.push(ident_to_setting(ident)?); + } + None => return Ok(res), + other => { + let span = other.map_or(Span::call_site(), |tt| tt.span()); + return Err(Error::new(span, "expected identifier".to_string())); + } + } + + match input.next() { + Some(TokenTree::Punct(ref punct)) if punct.as_char() == ',' => {} + None => return Ok(res), + other => { + let span = other.map_or(Span::call_site(), |tt| tt.span()); + return Err(Error::new(span, "expected `,`".to_string())); + } + } + } +} + +pub(crate) struct Settings(Vec); + +impl Settings { + pub(crate) fn is_set(&self, setting: Setting) -> bool { + self.0.iter().any(|s| *s == setting) + } + + pub(crate) fn set(&mut self, setting: Setting) { + self.0.push(setting) + } +} diff --git a/vendor/proc-macro-error/.cargo-checksum.json b/vendor/proc-macro-error/.cargo-checksum.json new file mode 100644 index 0000000000..79bcfa696f --- /dev/null +++ b/vendor/proc-macro-error/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"b84c4baa5fb093c6aaca44b98f9f28ef54d399ef6dd43c91f1dca618ab366b45","Cargo.toml":"50db093e1a4617606939dfb1f098cb59babbea0d7b390e973a3ed6bb1406170d","LICENSE-APACHE":"4665f973ccb9393807a7fb1264add6b3513d19abc6b357e4cb52c6fe59cc6a3b","LICENSE-MIT":"544b3aed1fd723d0cadea567affdcfe0431e43e18d997a718f9d67256b814fde","README.md":"72d59787d0a1f7bf161e292d0bc1bc25fdfb08cd6ad379a34cc3ed1b388d11fa","build.rs":"6238a0ad4f1146fbf55112419609e6449986154cf7ded1b5fdc978b06f4413b3","src/diagnostic.rs":"cb8724bb0bf9d2eee2f7119d0960fd5349edaa80e147abdef060ebf4572eca01","src/dummy.rs":"b44728091ddcdf9786523c01178efcedd83462bfe8bac6b97b1c2ffb19c96d09","src/imp/delegate.rs":"81da3a602a883240161dd98deb52b3b4ae29e626bfd2e1e07ef5e38d1be00679","src/imp/fallback.rs":"c3d333aba1122ac7e26f038f69750aa02e6a1222433a7cffd1c2f961befedd93","src/lib.rs":"e563d5dceaeb81551a5cb2610c1a3ad1a46200a6cbf8c3c3b394d8ac307b8cfa","src/macros.rs":"3be6feccd343cd9dc4bf03780f3107909bf70e02c6c7c72912e4b160dc6a68fc","src/sealed.rs":"dcf569c4c7ce1d372ff51b0fa73fa67f995bdca8e520cb225cde789c71276439","tests/macro-errors.rs":"7f793921dfbec692bfb2bbb067faf0480c0e7eeec83982b5e9fcddd817817616","tests/ok.rs":"a8c1925ac8647d185c7490ed1e33e3ce3203f5945bd3db4dcaf50ea55078df29","tests/runtime-errors.rs":"e53aa7d8e6c0e5128a90e856105eb05e4e7e72ea6db1bd580f3fe439bff62f24","tests/ui/abort.rs":"e209c8dd9dde6bde7440f8795624ad84b0f8486f563c8fe838238818f459bb67","tests/ui/abort.stderr":"dd0605e79be0309f92b251d055f087b0375c48ec60da978df354b48e8563fa10","tests/ui/append_dummy.rs":"ecaf939c8aabd94eef2dd1c10e9515489ba78e4db5b25195e19833b020d2483c","tests/ui/append_dummy.stderr":"ef03b01fc823aba8cfb9eb6d116640ca953fec569e61ed6ed6b7b7fa3bbad686","tests/ui/children_messages.rs":"32299679804133cb5295ed7a9341bf1ab86a4f1277679ee9738a83115c6b1d2b","tests/ui/children_messages.stderr":"dadeb86e1c7094d5fb38664b1766212b3d083fbe04962c137f8281fb3f5d162e","tests/ui/dummy.rs":"ba51c9158cef88ff2ddf0185be26fcd35a641d73c7124fab9ace0bbd546de847","tests/ui/dummy.stderr":"0635fd563d26691d07a2a875111f0b5e155caa45c37ad9cbaefe5fe617eac703","tests/ui/emit.rs":"82aaf06bcee56b7e139bbcba3a92c29448af14974d6806a28c9961aa764026e5","tests/ui/emit.stderr":"d3daa6d304453d436317495b7fc1d9d36bbebb7705bef75a5260d6d8fcfad5b1","tests/ui/explicit_span_range.rs":"3c37d5fc75b2bd460a091acd97a19acc80a40ba8d1d4ac7f36cd2f0e171bf5e7","tests/ui/explicit_span_range.stderr":"d7562847c326badbce2df8546e6f625eef0725b1dd2c786a037cc46357e4d2e8","tests/ui/misuse.rs":"0d66c61ab5c9723cf2f85cd12216751ab09722e9386cc27928034ee17f1c34e3","tests/ui/misuse.stderr":"52568a2208423e8e4050774559f269e79181a350f0805a34880bfa208e08c6bb","tests/ui/multiple_tokens.rs":"74997da1fdd3bce88a04ab42866c651723861fba4f59e826ee602d905398dcca","tests/ui/multiple_tokens.stderr":"e347ef1c18949711ce41957848e255095132f855c94db1e7e28d32e7d2c79a74","tests/ui/not_proc_macro.rs":"ca448d832ccf0cfdcda6f04281d8134a76c61b3ad96437e972b2cb5c6e0844c4","tests/ui/not_proc_macro.stderr":"a22c53a7dd5a03ddfaee5a7fb7fe5d61cb588b2d81a30c1e935b789baf0d2676","tests/ui/option_ext.rs":"1db81c17172f155c0ca8bcf92d55b5852b92107a3ba1d4b2ae6d14020df67f96","tests/ui/option_ext.stderr":"3b363759db60ee4f249dfde4d4571963032d5f0043249de40bd3b38eecc65404","tests/ui/proc_macro_hack.rs":"1d08c3e2c4c331e230c7cdaa2635ca1e43077252f90d3a430dcd091c646a842c","tests/ui/proc_macro_hack.stderr":"65e887dc208b92bfcd44405e76d5d05e315c3c5c5f637070954b7d593c723731","tests/ui/result_ext.rs":"ef398e76aab82a574ca5a988a91353e1a87fcfcb459d30314eceed3cbcf6fcd8","tests/ui/result_ext.stderr":"9e1e387b1378d9ec40ccb29be9f8cdaa5b42060c3f4f9b3c09fb307d5dcf7d85","tests/ui/to_tokens_span.rs":"d017a3c4cd583defe9806cdc51220bde89ced871ddd4d65b7cd089882feb1f61","tests/ui/to_tokens_span.stderr":"0b88e659ab214d6c7dfcd99274d327fe72da4b9bd009477e0e65165ddde65e02","tests/ui/unknown_setting.rs":"16fe9631b51023909497e857a6c674cd216ba9802fbdba360bb8273d6e00fa31","tests/ui/unknown_setting.stderr":"d605f151ce8eba5b2f867667394bd2d2adf0a233145516a9d6b801817521e587","tests/ui/unrelated_panic.rs":"438db25f8f14f1263152545a1c5135e20b3f5063dc4ab223fd8145b891039b24","tests/ui/unrelated_panic.stderr":"04cd814f2bd57d5271f93f90f0dd078b09ee3fd73137245a914d698e4a33ed57"},"package":"da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"} \ No newline at end of file diff --git a/vendor/proc-macro-error/CHANGELOG.md b/vendor/proc-macro-error/CHANGELOG.md new file mode 100644 index 0000000000..3c422f1c45 --- /dev/null +++ b/vendor/proc-macro-error/CHANGELOG.md @@ -0,0 +1,162 @@ +# v1.0.4 (2020-7-31) + +* `SpanRange` facility is now public. +* Docs have been improved. +* Introduced the `syn-error` feature so you can opt-out from the `syn` dependency. + +# v1.0.3 (2020-6-26) + +* Corrected a few typos. +* Fixed the `emit_call_site_warning` macro. + +# v1.0.2 (2020-4-9) + +* An obsolete note was removed from documentation. + +# v1.0.1 (2020-4-9) + +* `proc-macro-hack` is now well tested and supported. Not sure about `proc-macro-nested`, + please fill a request if you need it. +* Fixed `emit_call_site_error`. +* Documentation improvements. + +# v1.0.0 (2020-3-25) + +I believe the API can be considered stable because it's been a few months without +breaking changes, and I also don't think this crate will receive much further evolution. +It's perfect, admit it. + +Hence, meet the new, stable release! + +### Improvements + +* Supported nested `#[proc_macro_error]` attributes. Well, you aren't supposed to do that, + but I caught myself doing it by accident on one occasion and the behavior was... surprising. + Better to handle this smooth. + +# v0.4.12 (2020-3-23) + +* Error message on macros' misuse is now a bit more understandable. + +# v0.4.11 (2020-3-02) + +* `build.rs` no longer fails when `rustc` date could not be determined, + (thanks to [`Fabian Möller`](https://gitlab.com/CreepySkeleton/proc-macro-error/issues/8) + for noticing and to [`Igor Gnatenko`](https://gitlab.com/CreepySkeleton/proc-macro-error/-/merge_requests/25) + for fixing). + +# v0.4.10 (2020-2-29) + +* `proc-macro-error` doesn't depend on syn\[full\] anymore, the compilation + is \~30secs faster. + +# v0.4.9 (2020-2-13) + +* New function: `append_dummy`. + +# v0.4.8 (2020-2-01) + +* Support for children messages + +# v0.4.7 (2020-1-31) + +* Now any type that implements `quote::ToTokens` can be used instead of spans. + This allows for high quality error messages. + +# v0.4.6 (2020-1-31) + +* `From` implementation doesn't lose span info anymore, see + [#6](https://gitlab.com/CreepySkeleton/proc-macro-error/issues/6). + +# v0.4.5 (2020-1-20) +Just a small intermediate release. + +* Fix some bugs. +* Populate license files into subfolders. + +# v0.4.4 (2019-11-13) +* Fix `abort_if_dirty` + warnings bug +* Allow trailing commas in macros + +# v0.4.2 (2019-11-7) +* FINALLY fixed `__pme__suggestions not found` bug + +# v0.4.1 (2019-11-7) YANKED +* Fixed `__pme__suggestions not found` bug +* Documentation improvements, links checked + +# v0.4.0 (2019-11-6) YANKED + +## New features +* "help" messages that can have their own span on nightly, they + inherit parent span on stable. + ```rust + let cond_help = if condition { Some("some help message") else { None } }; + abort!( + span, // parent span + "something's wrong, {} wrongs in total", 10; // main message + help = "here's a help for you, {}", "take it"; // unconditional help message + help =? cond_help; // conditional help message, must be Option + note = note_span => "don't forget the note, {}", "would you?" // notes can have their own span but it's effective only on nightly + ) + ``` +* Warnings via `emit_warning` and `emit_warning_call_site`. Nightly only, they're ignored on stable. +* Now `proc-macro-error` delegates to `proc_macro::Diagnostic` on nightly. + +## Breaking changes +* `MacroError` is now replaced by `Diagnostic`. Its API resembles `proc_macro::Diagnostic`. +* `Diagnostic` does not implement `From<&str/String>` so `Result::abort_or_exit()` + won't work anymore (nobody used it anyway). +* `macro_error!` macro is replaced with `diagnostic!`. + +## Improvements +* Now `proc-macro-error` renders notes exactly just like rustc does. +* We don't parse a body of a function annotated with `#[proc_macro_error]` anymore, + only looking at the signature. This should somewhat decrease expansion time for large functions. + +# v0.3.3 (2019-10-16) +* Now you can use any word instead of "help", undocumented. + +# v0.3.2 (2019-10-16) +* Introduced support for "help" messages, undocumented. + +# v0.3.0 (2019-10-8) + +## The crate has been completely rewritten from scratch! + +## Changes (most are breaking): +* Renamed macros: + * `span_error` => `abort` + * `call_site_error` => `abort_call_site` +* `filter_macro_errors` was replaced by `#[proc_macro_error]` attribute. +* `set_dummy` now takes `TokenStream` instead of `Option` +* Support for multiple errors via `emit_error` and `emit_call_site_error` +* New `macro_error` macro for building errors in format=like style. +* `MacroError` API had been reconsidered. It also now implements `quote::ToTokens`. + +# v0.2.6 (2019-09-02) +* Introduce support for dummy implementations via `dummy::set_dummy` +* `multi::*` is now deprecated, will be completely rewritten in v0.3 + +# v0.2.0 (2019-08-15) + +## Breaking changes +* `trigger_error` replaced with `MacroError::trigger` and `filter_macro_error_panics` + is hidden from docs. + This is not quite a breaking change since users weren't supposed to use these functions directly anyway. +* All dependencies are updated to `v1.*`. + +## New features +* Ability to stack multiple errors via `multi::MultiMacroErrors` and emit them at once. + +## Improvements +* Now `MacroError` implements `std::fmt::Display` instead of `std::string::ToString`. +* `MacroError::span` inherent method. +* `From for proc_macro/proc_macro2::TokenStream` implementations. +* `AsRef/AsMut for MacroError` implementations. + +# v0.1.x (2019-07-XX) + +## New features +* An easy way to report errors inside within a proc-macro via `span_error`, + `call_site_error` and `filter_macro_errors`. diff --git a/vendor/proc-macro-error/Cargo.toml b/vendor/proc-macro-error/Cargo.toml new file mode 100644 index 0000000000..869585ffc2 --- /dev/null +++ b/vendor/proc-macro-error/Cargo.toml @@ -0,0 +1,56 @@ +# 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 = "proc-macro-error" +version = "1.0.4" +authors = ["CreepySkeleton "] +build = "build.rs" +description = "Almost drop-in replacement to panics in proc-macros" +readme = "README.md" +keywords = ["proc-macro", "error", "errors"] +categories = ["development-tools::procedural-macro-helpers"] +license = "MIT OR Apache-2.0" +repository = "https://gitlab.com/CreepySkeleton/proc-macro-error" +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +[dependencies.proc-macro-error-attr] +version = "=1.0.4" + +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" + +[dependencies.syn] +version = "1" +optional = true +default-features = false +[dev-dependencies.serde_derive] +version = "=1.0.107" + +[dev-dependencies.toml] +version = "=0.5.2" + +[dev-dependencies.trybuild] +version = "1.0.19" +features = ["diff"] +[build-dependencies.version_check] +version = "0.9" + +[features] +default = ["syn-error"] +syn-error = ["syn"] +[badges.maintenance] +status = "passively-maintained" diff --git a/vendor/proc-macro-error/LICENSE-APACHE b/vendor/proc-macro-error/LICENSE-APACHE new file mode 100644 index 0000000000..cc17374b25 --- /dev/null +++ b/vendor/proc-macro-error/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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-2020 CreepySkeleton + +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/proc-macro-error/LICENSE-MIT b/vendor/proc-macro-error/LICENSE-MIT new file mode 100644 index 0000000000..fc73e591d7 --- /dev/null +++ b/vendor/proc-macro-error/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2020 CreepySkeleton + +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/proc-macro-error/README.md b/vendor/proc-macro-error/README.md new file mode 100644 index 0000000000..7fbe07c53a --- /dev/null +++ b/vendor/proc-macro-error/README.md @@ -0,0 +1,258 @@ +# Makes error reporting in procedural macros nice and easy + +[![travis ci](https://travis-ci.org/CreepySkeleton/proc-macro-error.svg?branch=master)](https://travis-ci.org/CreepySkeleton/proc-macro-error) +[![docs.rs](https://docs.rs/proc-macro-error/badge.svg)](https://docs.rs/proc-macro-error) +[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/) + +This crate aims to make error reporting in proc-macros simple and easy to use. +Migrate from `panic!`-based errors for as little effort as possible! + +Also, you can explicitly [append a dummy token stream][crate::dummy] to your errors. + +To achieve his, this crate serves as a tiny shim around `proc_macro::Diagnostic` and +`compile_error!`. It detects the most preferable way to emit errors based on compiler's version. +When the underlying diagnostic type is finally stabilized, this crate will be simply +delegating to it, requiring no changes in your code! + +So you can just use this crate and have *both* some of `proc_macro::Diagnostic` functionality +available on stable ahead of time and your error-reporting code future-proof. + +```toml +[dependencies] +proc-macro-error = "1.0" +``` + +*Supports rustc 1.31 and up* + +[Documentation and guide][guide] + +## Quick example + +Code: + +```rust +#[proc_macro] +#[proc_macro_error] +pub fn make_fn(input: TokenStream) -> TokenStream { + let mut input = TokenStream2::from(input).into_iter(); + let name = input.next().unwrap(); + if let Some(second) = input.next() { + abort! { second, + "I don't like this part!"; + note = "I see what you did there..."; + help = "I need only one part, you know?"; + } + } + + quote!( fn #name() {} ).into() +} +``` + +This is how the error is rendered in a terminal: + +

    + +

    + +And this is what your users will see in their IDE: + +

    + +

    + +## Examples + +### Panic-like usage + +```rust +use proc_macro_error::{ + proc_macro_error, + abort, + abort_call_site, + ResultExt, + OptionExt, +}; +use proc_macro::TokenStream; +use syn::{DeriveInput, parse_macro_input}; +use quote::quote; + +// This is your main entry point +#[proc_macro] +// This attribute *MUST* be placed on top of the #[proc_macro] function +#[proc_macro_error] +pub fn make_answer(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + if let Err(err) = some_logic(&input) { + // we've got a span to blame, let's use it + // This immediately aborts the proc-macro and shows the error + // + // You can use `proc_macro::Span`, `proc_macro2::Span`, and + // anything that implements `quote::ToTokens` (almost every type from + // `syn` and `proc_macro2`) + abort!(err, "You made an error, go fix it: {}", err.msg); + } + + // `Result` has some handy shortcuts if your error type implements + // `Into`. `Option` has one unconditionally. + more_logic(&input).expect_or_abort("What a careless user, behave!"); + + if !more_logic_for_logic_god(&input) { + // We don't have an exact location this time, + // so just highlight the proc-macro invocation itself + abort_call_site!( + "Bad, bad user! Now go stand in the corner and think about what you did!"); + } + + // Now all the processing is done, return `proc_macro::TokenStream` + quote!(/* stuff */).into() +} +``` + +### `proc_macro::Diagnostic`-like usage + +```rust +use proc_macro_error::*; +use proc_macro::TokenStream; +use syn::{spanned::Spanned, DeriveInput, ItemStruct, Fields, Attribute , parse_macro_input}; +use quote::quote; + +fn process_attrs(attrs: &[Attribute]) -> Vec { + attrs + .iter() + .filter_map(|attr| match process_attr(attr) { + Ok(res) => Some(res), + Err(msg) => { + emit_error!(attr, "Invalid attribute: {}", msg); + None + } + }) + .collect() +} + +fn process_fields(_attrs: &Fields) -> Vec { + // processing fields in pretty much the same way as attributes + unimplemented!() +} + +#[proc_macro] +#[proc_macro_error] +pub fn make_answer(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as ItemStruct); + let attrs = process_attrs(&input.attrs); + + // abort right now if some errors were encountered + // at the attributes processing stage + abort_if_dirty(); + + let fields = process_fields(&input.fields); + + // no need to think about emitted errors + // #[proc_macro_error] will handle them for you + // + // just return a TokenStream as you normally would + quote!(/* stuff */).into() +} +``` + +## Real world examples + +* [`structopt-derive`](https://github.com/TeXitoi/structopt/tree/master/structopt-derive) + (abort-like usage) +* [`auto-impl`](https://github.com/auto-impl-rs/auto_impl/) (emit-like usage) + +## Limitations + +- Warnings are emitted only on nightly, they are ignored on stable. +- "help" suggestions can't have their own span info on stable, + (essentially inheriting the parent span). +- If your macro happens to trigger a panic, no errors will be displayed. This is not a + technical limitation but rather intentional design. `panic` is not for error reporting. + +## MSRV policy + +`proc_macro_error` will always be compatible with proc-macro Holy Trinity: +`proc_macro2`, `syn`, `quote` crates. In other words, if the Trinity is available +to you - `proc_macro_error` is available too. + +> **Important!** +> +> If you want to use `#[proc_macro_error]` with `synstructure`, you're going +> to have to put the attribute inside the `decl_derive!` invocation. Unfortunately, +> due to some bug in pre-1.34 rustc, putting proc-macro attributes inside macro +> invocations doesn't work, so your MSRV is effectively 1.34. + +## Motivation + +Error handling in proc-macros sucks. There's not much of a choice today: +you either "bubble up" the error up to the top-level of the macro and convert it to +a [`compile_error!`][compl_err] invocation or just use a good old panic. Both these ways suck: + +- Former sucks because it's quite redundant to unroll a proper error handling + just for critical errors that will crash the macro anyway; so people mostly + choose not to bother with it at all and use panic. Simple `.expect` is too tempting. + + Also, if you do decide to implement this `Result`-based architecture in your macro + you're going to have to rewrite it entirely once [`proc_macro::Diagnostic`][] is finally + stable. Not cool. + +- Later sucks because there's no way to carry out the span info via `panic!`. + `rustc` will highlight the invocation itself but not some specific token inside it. + + Furthermore, panics aren't for error-reporting at all; panics are for bug-detecting + (like unwrapping on `None` or out-of-range indexing) or for early development stages + when you need a prototype ASAP so error handling can wait. Mixing these usages only + messes things up. + +- There is [`proc_macro::Diagnostic`][] which is awesome but it has been experimental + for more than a year and is unlikely to be stabilized any time soon. + + This crate's API is intentionally designed to be compatible with `proc_macro::Diagnostic` + and delegates to it whenever possible. Once `Diagnostics` is stable this crate + will **always** delegate to it, no code changes will be required on user side. + +That said, we need a solution, but this solution must meet these conditions: + +- It must be better than `panic!`. The main point: it must offer a way to carry the span information + over to user. +- It must take as little effort as possible to migrate from `panic!`. Ideally, a new + macro with similar semantics plus ability to carry out span info. +- It must maintain compatibility with [`proc_macro::Diagnostic`][] . +- **It must be usable on stable**. + +This crate aims to provide such a mechanism. All you have to do is annotate your top-level +`#[proc_macro]` function with `#[proc_macro_error]` attribute and change panics to +[`abort!`]/[`abort_call_site!`] where appropriate, see [the Guide][guide]. + +## Disclaimer +Please note that **this crate is not intended to be used in any way other +than error reporting in procedural macros**, use `Result` and `?` (possibly along with one of the +many helpers out there) for anything else. + +
    + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
    + + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + + +[compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html +[`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html + +[crate::dummy]: https://docs.rs/proc-macro-error/1/proc_macro_error/dummy/index.html +[crate::multi]: https://docs.rs/proc-macro-error/1/proc_macro_error/multi/index.html + +[`abort_call_site!`]: https://docs.rs/proc-macro-error/1/proc_macro_error/macro.abort_call_site.html +[`abort!`]: https://docs.rs/proc-macro-error/1/proc_macro_error/macro.abort.html +[guide]: https://docs.rs/proc-macro-error diff --git a/vendor/proc-macro-error/build.rs b/vendor/proc-macro-error/build.rs new file mode 100644 index 0000000000..3c1196f269 --- /dev/null +++ b/vendor/proc-macro-error/build.rs @@ -0,0 +1,11 @@ +fn main() { + if !version_check::is_feature_flaggable().unwrap_or(false) { + println!("cargo:rustc-cfg=use_fallback"); + } + + if version_check::is_max_version("1.38.0").unwrap_or(false) + || !version_check::Channel::read().unwrap().is_stable() + { + println!("cargo:rustc-cfg=skip_ui_tests"); + } +} diff --git a/vendor/proc-macro-error/src/diagnostic.rs b/vendor/proc-macro-error/src/diagnostic.rs new file mode 100644 index 0000000000..983e6174fe --- /dev/null +++ b/vendor/proc-macro-error/src/diagnostic.rs @@ -0,0 +1,349 @@ +use crate::{abort_now, check_correctness, sealed::Sealed, SpanRange}; +use proc_macro2::Span; +use proc_macro2::TokenStream; + +use quote::{quote_spanned, ToTokens}; + +/// Represents a diagnostic level +/// +/// # Warnings +/// +/// Warnings are ignored on stable/beta +#[derive(Debug, PartialEq)] +pub enum Level { + Error, + Warning, + #[doc(hidden)] + NonExhaustive, +} + +/// Represents a single diagnostic message +#[derive(Debug)] +pub struct Diagnostic { + pub(crate) level: Level, + pub(crate) span_range: SpanRange, + pub(crate) msg: String, + pub(crate) suggestions: Vec<(SuggestionKind, String, Option)>, + pub(crate) children: Vec<(SpanRange, String)>, +} + +/// A collection of methods that do not exist in `proc_macro::Diagnostic` +/// but still useful to have around. +/// +/// This trait is sealed and cannot be implemented outside of `proc_macro_error`. +pub trait DiagnosticExt: Sealed { + /// Create a new diagnostic message that points to the `span_range`. + /// + /// This function is the same as `Diagnostic::spanned` but produces considerably + /// better error messages for multi-token spans on stable. + fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self; + + /// Add another error message to self such that it will be emitted right after + /// the main message. + /// + /// This function is the same as `Diagnostic::span_error` but produces considerably + /// better error messages for multi-token spans on stable. + fn span_range_error(self, span_range: SpanRange, msg: String) -> Self; + + /// Attach a "help" note to your main message, the note will have it's own span on nightly. + /// + /// This function is the same as `Diagnostic::span_help` but produces considerably + /// better error messages for multi-token spans on stable. + /// + /// # Span + /// + /// The span is ignored on stable, the note effectively inherits its parent's (main message) span + fn span_range_help(self, span_range: SpanRange, msg: String) -> Self; + + /// Attach a note to your main message, the note will have it's own span on nightly. + /// + /// This function is the same as `Diagnostic::span_note` but produces considerably + /// better error messages for multi-token spans on stable. + /// + /// # Span + /// + /// The span is ignored on stable, the note effectively inherits its parent's (main message) span + fn span_range_note(self, span_range: SpanRange, msg: String) -> Self; +} + +impl DiagnosticExt for Diagnostic { + fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self { + Diagnostic { + level, + span_range, + msg: message, + suggestions: vec![], + children: vec![], + } + } + + fn span_range_error(mut self, span_range: SpanRange, msg: String) -> Self { + self.children.push((span_range, msg)); + self + } + + fn span_range_help(mut self, span_range: SpanRange, msg: String) -> Self { + self.suggestions + .push((SuggestionKind::Help, msg, Some(span_range))); + self + } + + fn span_range_note(mut self, span_range: SpanRange, msg: String) -> Self { + self.suggestions + .push((SuggestionKind::Note, msg, Some(span_range))); + self + } +} + +impl Diagnostic { + /// Create a new diagnostic message that points to `Span::call_site()` + pub fn new(level: Level, message: String) -> Self { + Diagnostic::spanned(Span::call_site(), level, message) + } + + /// Create a new diagnostic message that points to the `span` + pub fn spanned(span: Span, level: Level, message: String) -> Self { + Diagnostic::spanned_range( + SpanRange { + first: span, + last: span, + }, + level, + message, + ) + } + + /// Add another error message to self such that it will be emitted right after + /// the main message. + pub fn span_error(self, span: Span, msg: String) -> Self { + self.span_range_error( + SpanRange { + first: span, + last: span, + }, + msg, + ) + } + + /// Attach a "help" note to your main message, the note will have it's own span on nightly. + /// + /// # Span + /// + /// The span is ignored on stable, the note effectively inherits its parent's (main message) span + pub fn span_help(self, span: Span, msg: String) -> Self { + self.span_range_help( + SpanRange { + first: span, + last: span, + }, + msg, + ) + } + + /// Attach a "help" note to your main message. + pub fn help(mut self, msg: String) -> Self { + self.suggestions.push((SuggestionKind::Help, msg, None)); + self + } + + /// Attach a note to your main message, the note will have it's own span on nightly. + /// + /// # Span + /// + /// The span is ignored on stable, the note effectively inherits its parent's (main message) span + pub fn span_note(self, span: Span, msg: String) -> Self { + self.span_range_note( + SpanRange { + first: span, + last: span, + }, + msg, + ) + } + + /// Attach a note to your main message + pub fn note(mut self, msg: String) -> Self { + self.suggestions.push((SuggestionKind::Note, msg, None)); + self + } + + /// The message of main warning/error (no notes attached) + pub fn message(&self) -> &str { + &self.msg + } + + /// Abort the proc-macro's execution and display the diagnostic. + /// + /// # Warnings + /// + /// Warnings are not emitted on stable and beta, but this function will abort anyway. + pub fn abort(self) -> ! { + self.emit(); + abort_now() + } + + /// Display the diagnostic while not aborting macro execution. + /// + /// # Warnings + /// + /// Warnings are ignored on stable/beta + pub fn emit(self) { + check_correctness(); + crate::imp::emit_diagnostic(self); + } +} + +/// **NOT PUBLIC API! NOTHING TO SEE HERE!!!** +#[doc(hidden)] +impl Diagnostic { + pub fn span_suggestion(self, span: Span, suggestion: &str, msg: String) -> Self { + match suggestion { + "help" | "hint" => self.span_help(span, msg), + _ => self.span_note(span, msg), + } + } + + pub fn suggestion(self, suggestion: &str, msg: String) -> Self { + match suggestion { + "help" | "hint" => self.help(msg), + _ => self.note(msg), + } + } +} + +impl ToTokens for Diagnostic { + fn to_tokens(&self, ts: &mut TokenStream) { + use std::borrow::Cow; + + fn ensure_lf(buf: &mut String, s: &str) { + if s.ends_with('\n') { + buf.push_str(s); + } else { + buf.push_str(s); + buf.push('\n'); + } + } + + fn diag_to_tokens( + span_range: SpanRange, + level: &Level, + msg: &str, + suggestions: &[(SuggestionKind, String, Option)], + ) -> TokenStream { + if *level == Level::Warning { + return TokenStream::new(); + } + + let message = if suggestions.is_empty() { + Cow::Borrowed(msg) + } else { + let mut message = String::new(); + ensure_lf(&mut message, msg); + message.push('\n'); + + for (kind, note, _span) in suggestions { + message.push_str(" = "); + message.push_str(kind.name()); + message.push_str(": "); + ensure_lf(&mut message, note); + } + message.push('\n'); + + Cow::Owned(message) + }; + + let mut msg = proc_macro2::Literal::string(&message); + msg.set_span(span_range.last); + let group = quote_spanned!(span_range.last=> { #msg } ); + quote_spanned!(span_range.first=> compile_error!#group) + } + + ts.extend(diag_to_tokens( + self.span_range, + &self.level, + &self.msg, + &self.suggestions, + )); + ts.extend( + self.children + .iter() + .map(|(span_range, msg)| diag_to_tokens(*span_range, &Level::Error, &msg, &[])), + ); + } +} + +#[derive(Debug)] +pub(crate) enum SuggestionKind { + Help, + Note, +} + +impl SuggestionKind { + fn name(&self) -> &'static str { + match self { + SuggestionKind::Note => "note", + SuggestionKind::Help => "help", + } + } +} + +#[cfg(feature = "syn-error")] +impl From for Diagnostic { + fn from(err: syn::Error) -> Self { + use proc_macro2::{Delimiter, TokenTree}; + + fn gut_error(ts: &mut impl Iterator) -> Option<(SpanRange, String)> { + let first = match ts.next() { + // compile_error + None => return None, + Some(tt) => tt.span(), + }; + ts.next().unwrap(); // ! + + let lit = match ts.next().unwrap() { + TokenTree::Group(group) => { + // Currently `syn` builds `compile_error!` invocations + // exclusively in `ident{"..."}` (braced) form which is not + // followed by `;` (semicolon). + // + // But if it changes to `ident("...");` (parenthesized) + // or `ident["..."];` (bracketed) form, + // we will need to skip the `;` as well. + // Highly unlikely, but better safe than sorry. + + if group.delimiter() == Delimiter::Parenthesis + || group.delimiter() == Delimiter::Bracket + { + ts.next().unwrap(); // ; + } + + match group.stream().into_iter().next().unwrap() { + TokenTree::Literal(lit) => lit, + _ => unreachable!(), + } + } + _ => unreachable!(), + }; + + let last = lit.span(); + let mut msg = lit.to_string(); + + // "abc" => abc + msg.pop(); + msg.remove(0); + + Some((SpanRange { first, last }, msg)) + } + + let mut ts = err.to_compile_error().into_iter(); + + let (span_range, msg) = gut_error(&mut ts).unwrap(); + let mut res = Diagnostic::spanned_range(span_range, Level::Error, msg); + + while let Some((span_range, msg)) = gut_error(&mut ts) { + res = res.span_range_error(span_range, msg); + } + + res + } +} diff --git a/vendor/proc-macro-error/src/dummy.rs b/vendor/proc-macro-error/src/dummy.rs new file mode 100644 index 0000000000..571a595aa9 --- /dev/null +++ b/vendor/proc-macro-error/src/dummy.rs @@ -0,0 +1,150 @@ +//! Facility to emit dummy implementations (or whatever) in case +//! an error happen. +//! +//! `compile_error!` does not abort a compilation right away. This means +//! `rustc` doesn't just show you the error and abort, it carries on the +//! compilation process looking for other errors to report. +//! +//! Let's consider an example: +//! +//! ```rust,ignore +//! use proc_macro::TokenStream; +//! use proc_macro_error::*; +//! +//! trait MyTrait { +//! fn do_thing(); +//! } +//! +//! // this proc macro is supposed to generate MyTrait impl +//! #[proc_macro_derive(MyTrait)] +//! #[proc_macro_error] +//! fn example(input: TokenStream) -> TokenStream { +//! // somewhere deep inside +//! abort!(span, "something's wrong"); +//! +//! // this implementation will be generated if no error happened +//! quote! { +//! impl MyTrait for #name { +//! fn do_thing() {/* whatever */} +//! } +//! } +//! } +//! +//! // ================ +//! // in main.rs +//! +//! // this derive triggers an error +//! #[derive(MyTrait)] // first BOOM! +//! struct Foo; +//! +//! fn main() { +//! Foo::do_thing(); // second BOOM! +//! } +//! ``` +//! +//! The problem is: the generated token stream contains only `compile_error!` +//! invocation, the impl was not generated. That means user will see two compilation +//! errors: +//! +//! ```text +//! error: something's wrong +//! --> $DIR/probe.rs:9:10 +//! | +//! 9 |#[proc_macro_derive(MyTrait)] +//! | ^^^^^^^ +//! +//! error[E0599]: no function or associated item named `do_thing` found for type `Foo` in the current scope +//! --> src\main.rs:3:10 +//! | +//! 1 | struct Foo; +//! | ----------- function or associated item `do_thing` not found for this +//! 2 | fn main() { +//! 3 | Foo::do_thing(); // second BOOM! +//! | ^^^^^^^^ function or associated item not found in `Foo` +//! ``` +//! +//! But the second error is meaningless! We definitely need to fix this. +//! +//! Most used approach in cases like this is "dummy implementation" - +//! omit `impl MyTrait for #name` and fill functions bodies with `unimplemented!()`. +//! +//! This is how you do it: +//! +//! ```rust,ignore +//! use proc_macro::TokenStream; +//! use proc_macro_error::*; +//! +//! trait MyTrait { +//! fn do_thing(); +//! } +//! +//! // this proc macro is supposed to generate MyTrait impl +//! #[proc_macro_derive(MyTrait)] +//! #[proc_macro_error] +//! fn example(input: TokenStream) -> TokenStream { +//! // first of all - we set a dummy impl which will be appended to +//! // `compile_error!` invocations in case a trigger does happen +//! set_dummy(quote! { +//! impl MyTrait for #name { +//! fn do_thing() { unimplemented!() } +//! } +//! }); +//! +//! // somewhere deep inside +//! abort!(span, "something's wrong"); +//! +//! // this implementation will be generated if no error happened +//! quote! { +//! impl MyTrait for #name { +//! fn do_thing() {/* whatever */} +//! } +//! } +//! } +//! +//! // ================ +//! // in main.rs +//! +//! // this derive triggers an error +//! #[derive(MyTrait)] // first BOOM! +//! struct Foo; +//! +//! fn main() { +//! Foo::do_thing(); // no more errors! +//! } +//! ``` + +use proc_macro2::TokenStream; +use std::cell::RefCell; + +use crate::check_correctness; + +thread_local! { + static DUMMY_IMPL: RefCell> = RefCell::new(None); +} + +/// Sets dummy token stream which will be appended to `compile_error!(msg);...` +/// invocations in case you'll emit any errors. +/// +/// See [guide](../index.html#guide). +pub fn set_dummy(dummy: TokenStream) -> Option { + check_correctness(); + DUMMY_IMPL.with(|old_dummy| old_dummy.replace(Some(dummy))) +} + +/// Same as [`set_dummy`] but, instead of resetting, appends tokens to the +/// existing dummy (if any). Behaves as `set_dummy` if no dummy is present. +pub fn append_dummy(dummy: TokenStream) { + check_correctness(); + DUMMY_IMPL.with(|old_dummy| { + let mut cell = old_dummy.borrow_mut(); + if let Some(ts) = cell.as_mut() { + ts.extend(dummy); + } else { + *cell = Some(dummy); + } + }); +} + +pub(crate) fn cleanup() -> Option { + DUMMY_IMPL.with(|old_dummy| old_dummy.replace(None)) +} diff --git a/vendor/proc-macro-error/src/imp/delegate.rs b/vendor/proc-macro-error/src/imp/delegate.rs new file mode 100644 index 0000000000..07def2b98e --- /dev/null +++ b/vendor/proc-macro-error/src/imp/delegate.rs @@ -0,0 +1,69 @@ +//! This implementation uses [`proc_macro::Diagnostic`], nightly only. + +use std::cell::Cell; + +use proc_macro::{Diagnostic as PDiag, Level as PLevel}; + +use crate::{ + abort_now, check_correctness, + diagnostic::{Diagnostic, Level, SuggestionKind}, +}; + +pub fn abort_if_dirty() { + check_correctness(); + if IS_DIRTY.with(|c| c.get()) { + abort_now() + } +} + +pub(crate) fn cleanup() -> Vec { + IS_DIRTY.with(|c| c.set(false)); + vec![] +} + +pub(crate) fn emit_diagnostic(diag: Diagnostic) { + let Diagnostic { + level, + span_range, + msg, + suggestions, + children, + } = diag; + + let span = span_range.collapse().unwrap(); + + let level = match level { + Level::Warning => PLevel::Warning, + Level::Error => { + IS_DIRTY.with(|c| c.set(true)); + PLevel::Error + } + _ => unreachable!(), + }; + + let mut res = PDiag::spanned(span, level, msg); + + for (kind, msg, span) in suggestions { + res = match (kind, span) { + (SuggestionKind::Note, Some(span_range)) => { + res.span_note(span_range.collapse().unwrap(), msg) + } + (SuggestionKind::Help, Some(span_range)) => { + res.span_help(span_range.collapse().unwrap(), msg) + } + (SuggestionKind::Note, None) => res.note(msg), + (SuggestionKind::Help, None) => res.help(msg), + } + } + + for (span_range, msg) in children { + let span = span_range.collapse().unwrap(); + res = res.span_error(span, msg); + } + + res.emit() +} + +thread_local! { + static IS_DIRTY: Cell = Cell::new(false); +} diff --git a/vendor/proc-macro-error/src/imp/fallback.rs b/vendor/proc-macro-error/src/imp/fallback.rs new file mode 100644 index 0000000000..ad1f730bfc --- /dev/null +++ b/vendor/proc-macro-error/src/imp/fallback.rs @@ -0,0 +1,30 @@ +//! This implementation uses self-written stable facilities. + +use crate::{ + abort_now, check_correctness, + diagnostic::{Diagnostic, Level}, +}; +use std::cell::RefCell; + +pub fn abort_if_dirty() { + check_correctness(); + ERR_STORAGE.with(|storage| { + if !storage.borrow().is_empty() { + abort_now() + } + }); +} + +pub(crate) fn cleanup() -> Vec { + ERR_STORAGE.with(|storage| storage.replace(Vec::new())) +} + +pub(crate) fn emit_diagnostic(diag: Diagnostic) { + if diag.level == Level::Error { + ERR_STORAGE.with(|storage| storage.borrow_mut().push(diag)); + } +} + +thread_local! { + static ERR_STORAGE: RefCell> = RefCell::new(Vec::new()); +} diff --git a/vendor/proc-macro-error/src/lib.rs b/vendor/proc-macro-error/src/lib.rs new file mode 100644 index 0000000000..fb867fdc03 --- /dev/null +++ b/vendor/proc-macro-error/src/lib.rs @@ -0,0 +1,560 @@ +//! # proc-macro-error +//! +//! This crate aims to make error reporting in proc-macros simple and easy to use. +//! Migrate from `panic!`-based errors for as little effort as possible! +//! +//! (Also, you can explicitly [append a dummy token stream](dummy/index.html) to your errors). +//! +//! To achieve his, this crate serves as a tiny shim around `proc_macro::Diagnostic` and +//! `compile_error!`. It detects the best way of emitting available based on compiler's version. +//! When the underlying diagnostic type is finally stabilized, this crate will simply be +//! delegating to it requiring no changes in your code! +//! +//! So you can just use this crate and have *both* some of `proc_macro::Diagnostic` functionality +//! available on stable ahead of time *and* your error-reporting code future-proof. +//! +//! ## Cargo features +//! +//! This crate provides *enabled by default* `syn-error` feature that gates +//! `impl From for Diagnostic` conversion. If you don't use `syn` and want +//! to cut off some of compilation time, you can disable it via +//! +//! ```toml +//! [dependencies] +//! proc-macro-error = { version = "1", default-features = false } +//! ``` +//! +//! ***Please note that disabling this feature makes sense only if you don't depend on `syn` +//! directly or indirectly, and you very likely do.** +//! +//! ## Real world examples +//! +//! * [`structopt-derive`](https://github.com/TeXitoi/structopt/tree/master/structopt-derive) +//! (abort-like usage) +//! * [`auto-impl`](https://github.com/auto-impl-rs/auto_impl/) (emit-like usage) +//! +//! ## Limitations +//! +//! - Warnings are emitted only on nightly, they are ignored on stable. +//! - "help" suggestions can't have their own span info on stable, +//! (essentially inheriting the parent span). +//! - If a panic occurs somewhere in your macro no errors will be displayed. This is not a +//! technical limitation but rather intentional design. `panic` is not for error reporting. +//! +//! ### `#[proc_macro_error]` attribute +//! +//! **This attribute MUST be present on the top level of your macro** (the function +//! annotated with any of `#[proc_macro]`, `#[proc_macro_derive]`, `#[proc_macro_attribute]`). +//! +//! This attribute performs the setup and cleanup necessary to make things work. +//! +//! In most cases you'll need the simple `#[proc_macro_error]` form without any +//! additional settings. Feel free to [skip the "Syntax" section](#macros). +//! +//! #### Syntax +//! +//! `#[proc_macro_error]` or `#[proc_macro_error(settings...)]`, where `settings...` +//! is a comma-separated list of: +//! +//! - `proc_macro_hack`: +//! +//! In order to correctly cooperate with `#[proc_macro_hack]`, `#[proc_macro_error]` +//! attribute must be placed *before* (above) it, like this: +//! +//! ```no_run +//! # use proc_macro2::TokenStream; +//! # const IGNORE: &str = " +//! #[proc_macro_error] +//! #[proc_macro_hack] +//! #[proc_macro] +//! # "; +//! fn my_macro(input: TokenStream) -> TokenStream { +//! unimplemented!() +//! } +//! ``` +//! +//! If, for some reason, you can't place it like that you can use +//! `#[proc_macro_error(proc_macro_hack)]` instead. +//! +//! # Note +//! +//! If `proc-macro-hack` was detected (by any means) `allow_not_macro` +//! and `assert_unwind_safe` will be applied automatically. +//! +//! - `allow_not_macro`: +//! +//! By default, the attribute checks that it's applied to a proc-macro. +//! If none of `#[proc_macro]`, `#[proc_macro_derive]` nor `#[proc_macro_attribute]` are +//! present it will panic. It's the intention - this crate is supposed to be used only with +//! proc-macros. +//! +//! This setting is made to bypass the check, useful in certain circumstances. +//! +//! Pay attention: the function this attribute is applied to must return +//! `proc_macro::TokenStream`. +//! +//! This setting is implied if `proc-macro-hack` was detected. +//! +//! - `assert_unwind_safe`: +//! +//! By default, your code must be [unwind safe]. If your code is not unwind safe, +//! but you believe it's correct, you can use this setting to bypass the check. +//! You would need this for code that uses `lazy_static` or `thread_local` with +//! `Cell/RefCell` inside (and the like). +//! +//! This setting is implied if `#[proc_macro_error]` is applied to a function +//! marked as `#[proc_macro]`, `#[proc_macro_derive]` or `#[proc_macro_attribute]`. +//! +//! This setting is also implied if `proc-macro-hack` was detected. +//! +//! ## Macros +//! +//! Most of the time you want to use the macros. Syntax is described in the next section below. +//! +//! You'll need to decide how you want to emit errors: +//! +//! * Emit the error and abort. Very much panic-like usage. Served by [`abort!`] and +//! [`abort_call_site!`]. +//! * Emit the error but do not abort right away, looking for other errors to report. +//! Served by [`emit_error!`] and [`emit_call_site_error!`]. +//! +//! You **can** mix these usages. +//! +//! `abort` and `emit_error` take a "source span" as the first argument. This source +//! will be used to highlight the place the error originates from. It must be one of: +//! +//! * *Something* that implements [`ToTokens`] (most types in `syn` and `proc-macro2` do). +//! This source is the preferable one since it doesn't lose span information on multi-token +//! spans, see [this issue](https://gitlab.com/CreepySkeleton/proc-macro-error/-/issues/6) +//! for details. +//! * [`proc_macro::Span`] +//! * [`proc-macro2::Span`] +//! +//! The rest is your message in format-like style. +//! +//! See [the next section](#syntax-1) for detailed syntax. +//! +//! - [`abort!`]: +//! +//! Very much panic-like usage - abort right away and show the error. +//! Expands to [`!`] (never type). +//! +//! - [`abort_call_site!`]: +//! +//! Shortcut for `abort!(Span::call_site(), ...)`. Expands to [`!`] (never type). +//! +//! - [`emit_error!`]: +//! +//! [`proc_macro::Diagnostic`]-like usage - emit the error but keep going, +//! looking for other errors to report. +//! The compilation will fail nonetheless. Expands to [`()`] (unit type). +//! +//! - [`emit_call_site_error!`]: +//! +//! Shortcut for `emit_error!(Span::call_site(), ...)`. Expands to [`()`] (unit type). +//! +//! - [`emit_warning!`]: +//! +//! Like `emit_error!` but emit a warning instead of error. The compilation won't fail +//! because of warnings. +//! Expands to [`()`] (unit type). +//! +//! **Beware**: warnings are nightly only, they are completely ignored on stable. +//! +//! - [`emit_call_site_warning!`]: +//! +//! Shortcut for `emit_warning!(Span::call_site(), ...)`. Expands to [`()`] (unit type). +//! +//! - [`diagnostic`]: +//! +//! Build an instance of `Diagnostic` in format-like style. +//! +//! #### Syntax +//! +//! All the macros have pretty much the same syntax: +//! +//! 1. ```ignore +//! abort!(single_expr) +//! ``` +//! Shortcut for `Diagnostic::from(expr).abort()`. +//! +//! 2. ```ignore +//! abort!(span, message) +//! ``` +//! The first argument is an expression the span info should be taken from. +//! +//! The second argument is the error message, it must implement [`ToString`]. +//! +//! 3. ```ignore +//! abort!(span, format_literal, format_args...) +//! ``` +//! +//! This form is pretty much the same as 2, except `format!(format_literal, format_args...)` +//! will be used to for the message instead of [`ToString`]. +//! +//! That's it. `abort!`, `emit_warning`, `emit_error` share this exact syntax. +//! +//! `abort_call_site!`, `emit_call_site_warning`, `emit_call_site_error` lack 1 form +//! and do not take span in 2'th and 3'th forms. Those are essentially shortcuts for +//! `macro!(Span::call_site(), args...)`. +//! +//! `diagnostic!` requires a [`Level`] instance between `span` and second argument +//! (1'th form is the same). +//! +//! > **Important!** +//! > +//! > If you have some type from `proc_macro` or `syn` to point to, do not call `.span()` +//! > on it but rather use it directly: +//! > ```no_run +//! > # use proc_macro_error::abort; +//! > # let input = proc_macro2::TokenStream::new(); +//! > let ty: syn::Type = syn::parse2(input).unwrap(); +//! > abort!(ty, "BOOM"); +//! > // ^^ <-- avoid .span() +//! > ``` +//! > +//! > `.span()` calls work too, but you may experience regressions in message quality. +//! +//! #### Note attachments +//! +//! 3. Every macro can have "note" attachments (only 2 and 3 form). +//! ```ignore +//! let opt_help = if have_some_info { Some("did you mean `this`?") } else { None }; +//! +//! abort!( +//! span, message; // <--- attachments start with `;` (semicolon) +//! +//! help = "format {} {}", "arg1", "arg2"; // <--- every attachment ends with `;`, +//! // maybe except the last one +//! +//! note = "to_string"; // <--- one arg uses `.to_string()` instead of `format!()` +//! +//! yay = "I see what {} did here", "you"; // <--- "help =" and "hint =" are mapped +//! // to Diagnostic::help, +//! // anything else is Diagnostic::note +//! +//! wow = note_span => "custom span"; // <--- attachments can have their own span +//! // it takes effect only on nightly though +//! +//! hint =? opt_help; // <-- "optional" attachment, get displayed only if `Some` +//! // must be single `Option` expression +//! +//! note =? note_span => opt_help // <-- optional attachments can have custom spans too +//! ); +//! ``` +//! + +//! ### Diagnostic type +//! +//! [`Diagnostic`] type is intentionally designed to be API compatible with [`proc_macro::Diagnostic`]. +//! Not all API is implemented, only the part that can be reasonably implemented on stable. +//! +//! +//! [`abort!`]: macro.abort.html +//! [`abort_call_site!`]: macro.abort_call_site.html +//! [`emit_warning!`]: macro.emit_warning.html +//! [`emit_error!`]: macro.emit_error.html +//! [`emit_call_site_warning!`]: macro.emit_call_site_error.html +//! [`emit_call_site_error!`]: macro.emit_call_site_warning.html +//! [`diagnostic!`]: macro.diagnostic.html +//! [`Diagnostic`]: struct.Diagnostic.html +//! +//! [`proc_macro::Span`]: https://doc.rust-lang.org/proc_macro/struct.Span.html +//! [`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html +//! +//! [unwind safe]: https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html#what-is-unwind-safety +//! [`!`]: https://doc.rust-lang.org/std/primitive.never.html +//! [`()`]: https://doc.rust-lang.org/std/primitive.unit.html +//! [`ToString`]: https://doc.rust-lang.org/std/string/trait.ToString.html +//! +//! [`proc-macro2::Span`]: https://docs.rs/proc-macro2/1.0.10/proc_macro2/struct.Span.html +//! [`ToTokens`]: https://docs.rs/quote/1.0.3/quote/trait.ToTokens.html +//! + +#![cfg_attr(not(use_fallback), feature(proc_macro_diagnostic))] +#![forbid(unsafe_code)] +#![allow(clippy::needless_doctest_main)] + +extern crate proc_macro; + +pub use crate::{ + diagnostic::{Diagnostic, DiagnosticExt, Level}, + dummy::{append_dummy, set_dummy}, +}; +pub use proc_macro_error_attr::proc_macro_error; + +use proc_macro2::Span; +use quote::{quote, ToTokens}; + +use std::cell::Cell; +use std::panic::{catch_unwind, resume_unwind, UnwindSafe}; + +pub mod dummy; + +mod diagnostic; +mod macros; +mod sealed; + +#[cfg(use_fallback)] +#[path = "imp/fallback.rs"] +mod imp; + +#[cfg(not(use_fallback))] +#[path = "imp/delegate.rs"] +mod imp; + +#[derive(Debug, Clone, Copy)] +pub struct SpanRange { + pub first: Span, + pub last: Span, +} + +impl SpanRange { + /// Create a range with the `first` and `last` spans being the same. + pub fn single_span(span: Span) -> Self { + SpanRange { + first: span, + last: span, + } + } + + /// Create a `SpanRange` resolving at call site. + pub fn call_site() -> Self { + SpanRange::single_span(Span::call_site()) + } + + /// Construct span range from a `TokenStream`. This method always preserves all the + /// range. + /// + /// ### Note + /// + /// If the stream is empty, the result is `SpanRange::call_site()`. If the stream + /// consists of only one `TokenTree`, the result is `SpanRange::single_span(tt.span())` + /// that doesn't lose anything. + pub fn from_tokens(ts: &dyn ToTokens) -> Self { + let mut spans = ts.to_token_stream().into_iter().map(|tt| tt.span()); + let first = spans.next().unwrap_or_else(|| Span::call_site()); + let last = spans.last().unwrap_or(first); + + SpanRange { first, last } + } + + /// Join two span ranges. The resulting range will start at `self.first` and end at + /// `other.last`. + pub fn join_range(self, other: SpanRange) -> Self { + SpanRange { + first: self.first, + last: other.last, + } + } + + /// Collapse the range into single span, preserving as much information as possible. + pub fn collapse(self) -> Span { + self.first.join(self.last).unwrap_or(self.first) + } +} + +/// This traits expands `Result>` with some handy shortcuts. +pub trait ResultExt { + type Ok; + + /// Behaves like `Result::unwrap`: if self is `Ok` yield the contained value, + /// otherwise abort macro execution via `abort!`. + fn unwrap_or_abort(self) -> Self::Ok; + + /// Behaves like `Result::expect`: if self is `Ok` yield the contained value, + /// otherwise abort macro execution via `abort!`. + /// If it aborts then resulting error message will be preceded with `message`. + fn expect_or_abort(self, msg: &str) -> Self::Ok; +} + +/// This traits expands `Option` with some handy shortcuts. +pub trait OptionExt { + type Some; + + /// Behaves like `Option::expect`: if self is `Some` yield the contained value, + /// otherwise abort macro execution via `abort_call_site!`. + /// If it aborts the `message` will be used for [`compile_error!`][compl_err] invocation. + /// + /// [compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html + fn expect_or_abort(self, msg: &str) -> Self::Some; +} + +/// Abort macro execution and display all the emitted errors, if any. +/// +/// Does nothing if no errors were emitted (warnings do not count). +pub fn abort_if_dirty() { + imp::abort_if_dirty(); +} + +impl> ResultExt for Result { + type Ok = T; + + fn unwrap_or_abort(self) -> T { + match self { + Ok(res) => res, + Err(e) => e.into().abort(), + } + } + + fn expect_or_abort(self, message: &str) -> T { + match self { + Ok(res) => res, + Err(e) => { + let mut e = e.into(); + e.msg = format!("{}: {}", message, e.msg); + e.abort() + } + } + } +} + +impl OptionExt for Option { + type Some = T; + + fn expect_or_abort(self, message: &str) -> T { + match self { + Some(res) => res, + None => abort_call_site!(message), + } + } +} + +/// This is the entry point for a proc-macro. +/// +/// **NOT PUBLIC API, SUBJECT TO CHANGE WITHOUT ANY NOTICE** +#[doc(hidden)] +pub fn entry_point(f: F, proc_macro_hack: bool) -> proc_macro::TokenStream +where + F: FnOnce() -> proc_macro::TokenStream + UnwindSafe, +{ + ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() + 1)); + let caught = catch_unwind(f); + let dummy = dummy::cleanup(); + let err_storage = imp::cleanup(); + ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() - 1)); + + let gen_error = || { + if proc_macro_hack { + quote! {{ + macro_rules! proc_macro_call { + () => ( unimplemented!() ) + } + + #(#err_storage)* + #dummy + + unimplemented!() + }} + } else { + quote!( #(#err_storage)* #dummy ) + } + }; + + match caught { + Ok(ts) => { + if err_storage.is_empty() { + ts + } else { + gen_error().into() + } + } + + Err(boxed) => match boxed.downcast::() { + Ok(_) => gen_error().into(), + Err(boxed) => resume_unwind(boxed), + }, + } +} + +fn abort_now() -> ! { + check_correctness(); + panic!(AbortNow) +} + +thread_local! { + static ENTERED_ENTRY_POINT: Cell = Cell::new(0); +} + +struct AbortNow; + +fn check_correctness() { + if ENTERED_ENTRY_POINT.with(|flag| flag.get()) == 0 { + panic!( + "proc-macro-error API cannot be used outside of `entry_point` invocation, \ + perhaps you forgot to annotate your #[proc_macro] function with `#[proc_macro_error]" + ); + } +} + +/// **ALL THE STUFF INSIDE IS NOT PUBLIC API!!!** +#[doc(hidden)] +pub mod __export { + // reexports for use in macros + pub extern crate proc_macro; + pub extern crate proc_macro2; + + use proc_macro2::Span; + use quote::ToTokens; + + use crate::SpanRange; + + // inspired by + // https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md#simple-application + + pub trait SpanAsSpanRange { + #[allow(non_snake_case)] + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; + } + + pub trait Span2AsSpanRange { + #[allow(non_snake_case)] + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; + } + + pub trait ToTokensAsSpanRange { + #[allow(non_snake_case)] + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; + } + + pub trait SpanRangeAsSpanRange { + #[allow(non_snake_case)] + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; + } + + impl ToTokensAsSpanRange for &T { + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { + let mut ts = self.to_token_stream().into_iter(); + let first = ts + .next() + .map(|tt| tt.span()) + .unwrap_or_else(Span::call_site); + let last = ts.last().map(|tt| tt.span()).unwrap_or(first); + SpanRange { first, last } + } + } + + impl Span2AsSpanRange for Span { + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { + SpanRange { + first: *self, + last: *self, + } + } + } + + impl SpanAsSpanRange for proc_macro::Span { + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { + SpanRange { + first: self.clone().into(), + last: self.clone().into(), + } + } + } + + impl SpanRangeAsSpanRange for SpanRange { + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { + *self + } + } +} diff --git a/vendor/proc-macro-error/src/macros.rs b/vendor/proc-macro-error/src/macros.rs new file mode 100644 index 0000000000..747b684d56 --- /dev/null +++ b/vendor/proc-macro-error/src/macros.rs @@ -0,0 +1,288 @@ +// FIXME: this can be greatly simplified via $()? +// as soon as MRSV hits 1.32 + +/// Build [`Diagnostic`](struct.Diagnostic.html) instance from provided arguments. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! diagnostic { + // from alias + ($err:expr) => { $crate::Diagnostic::from($err) }; + + // span, message, help + ($span:expr, $level:expr, $fmt:expr, $($args:expr),+ ; $($rest:tt)+) => {{ + #[allow(unused_imports)] + use $crate::__export::{ + ToTokensAsSpanRange, + Span2AsSpanRange, + SpanAsSpanRange, + SpanRangeAsSpanRange + }; + use $crate::DiagnosticExt; + let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(); + + let diag = $crate::Diagnostic::spanned_range( + span_range, + $level, + format!($fmt, $($args),*) + ); + $crate::__pme__suggestions!(diag $($rest)*); + diag + }}; + + ($span:expr, $level:expr, $msg:expr ; $($rest:tt)+) => {{ + #[allow(unused_imports)] + use $crate::__export::{ + ToTokensAsSpanRange, + Span2AsSpanRange, + SpanAsSpanRange, + SpanRangeAsSpanRange + }; + use $crate::DiagnosticExt; + let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(); + + let diag = $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string()); + $crate::__pme__suggestions!(diag $($rest)*); + diag + }}; + + // span, message, no help + ($span:expr, $level:expr, $fmt:expr, $($args:expr),+) => {{ + #[allow(unused_imports)] + use $crate::__export::{ + ToTokensAsSpanRange, + Span2AsSpanRange, + SpanAsSpanRange, + SpanRangeAsSpanRange + }; + use $crate::DiagnosticExt; + let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(); + + $crate::Diagnostic::spanned_range( + span_range, + $level, + format!($fmt, $($args),*) + ) + }}; + + ($span:expr, $level:expr, $msg:expr) => {{ + #[allow(unused_imports)] + use $crate::__export::{ + ToTokensAsSpanRange, + Span2AsSpanRange, + SpanAsSpanRange, + SpanRangeAsSpanRange + }; + use $crate::DiagnosticExt; + let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(); + + $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string()) + }}; + + + // trailing commas + + ($span:expr, $level:expr, $fmt:expr, $($args:expr),+, ; $($rest:tt)+) => { + $crate::diagnostic!($span, $level, $fmt, $($args),* ; $($rest)*) + }; + ($span:expr, $level:expr, $msg:expr, ; $($rest:tt)+) => { + $crate::diagnostic!($span, $level, $msg ; $($rest)*) + }; + ($span:expr, $level:expr, $fmt:expr, $($args:expr),+,) => { + $crate::diagnostic!($span, $level, $fmt, $($args),*) + }; + ($span:expr, $level:expr, $msg:expr,) => { + $crate::diagnostic!($span, $level, $msg) + }; + // ($err:expr,) => { $crate::diagnostic!($err) }; +} + +/// Abort proc-macro execution right now and display the error. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +#[macro_export] +macro_rules! abort { + ($err:expr) => { + $crate::diagnostic!($err).abort() + }; + + ($span:expr, $($tts:tt)*) => { + $crate::diagnostic!($span, $crate::Level::Error, $($tts)*).abort() + }; +} + +/// Shortcut for `abort!(Span::call_site(), msg...)`. This macro +/// is still preferable over plain panic, panics are not for error reporting. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! abort_call_site { + ($($tts:tt)*) => { + $crate::abort!($crate::__export::proc_macro2::Span::call_site(), $($tts)*) + }; +} + +/// Emit an error while not aborting the proc-macro right away. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! emit_error { + ($err:expr) => { + $crate::diagnostic!($err).emit() + }; + + ($span:expr, $($tts:tt)*) => {{ + let level = $crate::Level::Error; + $crate::diagnostic!($span, level, $($tts)*).emit() + }}; +} + +/// Shortcut for `emit_error!(Span::call_site(), ...)`. This macro +/// is still preferable over plain panic, panics are not for error reporting.. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! emit_call_site_error { + ($($tts:tt)*) => { + $crate::emit_error!($crate::__export::proc_macro2::Span::call_site(), $($tts)*) + }; +} + +/// Emit a warning. Warnings are not errors and compilation won't fail because of them. +/// +/// **Does nothing on stable** +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! emit_warning { + ($span:expr, $($tts:tt)*) => { + $crate::diagnostic!($span, $crate::Level::Warning, $($tts)*).emit() + }; +} + +/// Shortcut for `emit_warning!(Span::call_site(), ...)`. +/// +/// **Does nothing on stable** +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! emit_call_site_warning { + ($($tts:tt)*) => {{ + $crate::emit_warning!($crate::__export::proc_macro2::Span::call_site(), $($tts)*) + }}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __pme__suggestions { + ($var:ident) => (); + + ($var:ident $help:ident =? $msg:expr) => { + let $var = if let Some(msg) = $msg { + $var.suggestion(stringify!($help), msg.to_string()) + } else { + $var + }; + }; + ($var:ident $help:ident =? $span:expr => $msg:expr) => { + let $var = if let Some(msg) = $msg { + $var.span_suggestion($span.into(), stringify!($help), msg.to_string()) + } else { + $var + }; + }; + + ($var:ident $help:ident =? $msg:expr ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help =? $msg); + $crate::__pme__suggestions!($var $($rest)*); + }; + ($var:ident $help:ident =? $span:expr => $msg:expr ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help =? $span => $msg); + $crate::__pme__suggestions!($var $($rest)*); + }; + + + ($var:ident $help:ident = $msg:expr) => { + let $var = $var.suggestion(stringify!($help), $msg.to_string()); + }; + ($var:ident $help:ident = $fmt:expr, $($args:expr),+) => { + let $var = $var.suggestion( + stringify!($help), + format!($fmt, $($args),*) + ); + }; + ($var:ident $help:ident = $span:expr => $msg:expr) => { + let $var = $var.span_suggestion($span.into(), stringify!($help), $msg.to_string()); + }; + ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+) => { + let $var = $var.span_suggestion( + $span.into(), + stringify!($help), + format!($fmt, $($args),*) + ); + }; + + ($var:ident $help:ident = $msg:expr ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $msg); + $crate::__pme__suggestions!($var $($rest)*); + }; + ($var:ident $help:ident = $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $fmt, $($args),*); + $crate::__pme__suggestions!($var $($rest)*); + }; + ($var:ident $help:ident = $span:expr => $msg:expr ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $span => $msg); + $crate::__pme__suggestions!($var $($rest)*); + }; + ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*); + $crate::__pme__suggestions!($var $($rest)*); + }; + + // trailing commas + + ($var:ident $help:ident = $msg:expr,) => { + $crate::__pme__suggestions!($var $help = $msg) + }; + ($var:ident $help:ident = $fmt:expr, $($args:expr),+,) => { + $crate::__pme__suggestions!($var $help = $fmt, $($args)*) + }; + ($var:ident $help:ident = $span:expr => $msg:expr,) => { + $crate::__pme__suggestions!($var $help = $span => $msg) + }; + ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),*,) => { + $crate::__pme__suggestions!($var $help = $span => $fmt, $($args)*) + }; + ($var:ident $help:ident = $msg:expr, ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $msg; $($rest)*) + }; + ($var:ident $help:ident = $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $fmt, $($args),*; $($rest)*) + }; + ($var:ident $help:ident = $span:expr => $msg:expr, ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $span => $msg; $($rest)*) + }; + ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*; $($rest)*) + }; +} diff --git a/vendor/proc-macro-error/src/sealed.rs b/vendor/proc-macro-error/src/sealed.rs new file mode 100644 index 0000000000..a2d5081e55 --- /dev/null +++ b/vendor/proc-macro-error/src/sealed.rs @@ -0,0 +1,3 @@ +pub trait Sealed {} + +impl Sealed for crate::Diagnostic {} diff --git a/vendor/proc-macro-error/tests/macro-errors.rs b/vendor/proc-macro-error/tests/macro-errors.rs new file mode 100644 index 0000000000..dd60f88a80 --- /dev/null +++ b/vendor/proc-macro-error/tests/macro-errors.rs @@ -0,0 +1,8 @@ +extern crate trybuild; + +#[cfg_attr(skip_ui_tests, ignore)] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/vendor/proc-macro-error/tests/ok.rs b/vendor/proc-macro-error/tests/ok.rs new file mode 100644 index 0000000000..cf64c027f8 --- /dev/null +++ b/vendor/proc-macro-error/tests/ok.rs @@ -0,0 +1,10 @@ +extern crate test_crate; + +use test_crate::*; + +ok!(it_works); + +#[test] +fn check_it_works() { + it_works(); +} diff --git a/vendor/proc-macro-error/tests/runtime-errors.rs b/vendor/proc-macro-error/tests/runtime-errors.rs new file mode 100644 index 0000000000..13108a2d91 --- /dev/null +++ b/vendor/proc-macro-error/tests/runtime-errors.rs @@ -0,0 +1,13 @@ +use proc_macro_error::*; + +#[test] +#[should_panic = "proc-macro-error API cannot be used outside of"] +fn missing_attr_emit() { + emit_call_site_error!("You won't see me"); +} + +#[test] +#[should_panic = "proc-macro-error API cannot be used outside of"] +fn missing_attr_abort() { + abort_call_site!("You won't see me"); +} diff --git a/vendor/proc-macro-error/tests/ui/abort.rs b/vendor/proc-macro-error/tests/ui/abort.rs new file mode 100644 index 0000000000..f63118251e --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/abort.rs @@ -0,0 +1,11 @@ +extern crate test_crate; +use test_crate::*; + +abort_from!(one, two); +abort_to_string!(one, two); +abort_format!(one, two); +direct_abort!(one, two); +abort_notes!(one, two); +abort_call_site_test!(one, two); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/abort.stderr b/vendor/proc-macro-error/tests/ui/abort.stderr new file mode 100644 index 0000000000..c5399d9d91 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/abort.stderr @@ -0,0 +1,48 @@ +error: abort!(span, from) test + --> $DIR/abort.rs:4:13 + | +4 | abort_from!(one, two); + | ^^^ + +error: abort!(span, single_expr) test + --> $DIR/abort.rs:5:18 + | +5 | abort_to_string!(one, two); + | ^^^ + +error: abort!(span, expr1, expr2) test + --> $DIR/abort.rs:6:15 + | +6 | abort_format!(one, two); + | ^^^ + +error: Diagnostic::abort() test + --> $DIR/abort.rs:7:15 + | +7 | direct_abort!(one, two); + | ^^^ + +error: This is an error + + = note: simple note + = help: simple help + = help: simple hint + = note: simple yay + = note: format note + = note: Some note + = note: spanned simple note + = note: spanned format note + = note: Some note + + --> $DIR/abort.rs:8:14 + | +8 | abort_notes!(one, two); + | ^^^ + +error: abort_call_site! test + --> $DIR/abort.rs:9:1 + | +9 | abort_call_site_test!(one, two); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/append_dummy.rs b/vendor/proc-macro-error/tests/ui/append_dummy.rs new file mode 100644 index 0000000000..53d6feacc1 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/append_dummy.rs @@ -0,0 +1,13 @@ +extern crate test_crate; +use test_crate::*; + +enum NeedDefault { + A, + B +} + +append_dummy!(need_default); + +fn main() { + let _ = NeedDefault::default(); +} diff --git a/vendor/proc-macro-error/tests/ui/append_dummy.stderr b/vendor/proc-macro-error/tests/ui/append_dummy.stderr new file mode 100644 index 0000000000..8a47ddaac4 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/append_dummy.stderr @@ -0,0 +1,5 @@ +error: append_dummy test + --> $DIR/append_dummy.rs:9:15 + | +9 | append_dummy!(need_default); + | ^^^^^^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/children_messages.rs b/vendor/proc-macro-error/tests/ui/children_messages.rs new file mode 100644 index 0000000000..fb9e6dc697 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/children_messages.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +children_messages!(one, two, three, four); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/children_messages.stderr b/vendor/proc-macro-error/tests/ui/children_messages.stderr new file mode 100644 index 0000000000..3b49d83165 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/children_messages.stderr @@ -0,0 +1,23 @@ +error: main macro message + --> $DIR/children_messages.rs:4:20 + | +4 | children_messages!(one, two, three, four); + | ^^^ + +error: child message + --> $DIR/children_messages.rs:4:25 + | +4 | children_messages!(one, two, three, four); + | ^^^ + +error: main syn::Error + --> $DIR/children_messages.rs:4:30 + | +4 | children_messages!(one, two, three, four); + | ^^^^^ + +error: child syn::Error + --> $DIR/children_messages.rs:4:37 + | +4 | children_messages!(one, two, three, four); + | ^^^^ diff --git a/vendor/proc-macro-error/tests/ui/dummy.rs b/vendor/proc-macro-error/tests/ui/dummy.rs new file mode 100644 index 0000000000..caa4827886 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/dummy.rs @@ -0,0 +1,13 @@ +extern crate test_crate; +use test_crate::*; + +enum NeedDefault { + A, + B +} + +dummy!(need_default); + +fn main() { + let _ = NeedDefault::default(); +} diff --git a/vendor/proc-macro-error/tests/ui/dummy.stderr b/vendor/proc-macro-error/tests/ui/dummy.stderr new file mode 100644 index 0000000000..bae078afa8 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/dummy.stderr @@ -0,0 +1,5 @@ +error: set_dummy test + --> $DIR/dummy.rs:9:8 + | +9 | dummy!(need_default); + | ^^^^^^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/emit.rs b/vendor/proc-macro-error/tests/ui/emit.rs new file mode 100644 index 0000000000..c5c7db095f --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/emit.rs @@ -0,0 +1,7 @@ +extern crate test_crate; +use test_crate::*; + +emit!(one, two, three, four, five); +emit_notes!(one, two); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/emit.stderr b/vendor/proc-macro-error/tests/ui/emit.stderr new file mode 100644 index 0000000000..9484bd628b --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/emit.stderr @@ -0,0 +1,48 @@ +error: emit!(span, from) test + --> $DIR/emit.rs:4:7 + | +4 | emit!(one, two, three, four, five); + | ^^^ + +error: emit!(span, expr1, expr2) test + --> $DIR/emit.rs:4:12 + | +4 | emit!(one, two, three, four, five); + | ^^^ + +error: emit!(span, single_expr) test + --> $DIR/emit.rs:4:17 + | +4 | emit!(one, two, three, four, five); + | ^^^^^ + +error: Diagnostic::emit() test + --> $DIR/emit.rs:4:24 + | +4 | emit!(one, two, three, four, five); + | ^^^^ + +error: emit_call_site_error!(expr) test + --> $DIR/emit.rs:4:1 + | +4 | emit!(one, two, three, four, five); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: This is an error + + = note: simple note + = help: simple help + = help: simple hint + = note: simple yay + = note: format note + = note: Some note + = note: spanned simple note + = note: spanned format note + = note: Some note + + --> $DIR/emit.rs:5:13 + | +5 | emit_notes!(one, two); + | ^^^ diff --git a/vendor/proc-macro-error/tests/ui/explicit_span_range.rs b/vendor/proc-macro-error/tests/ui/explicit_span_range.rs new file mode 100644 index 0000000000..82bbebcc55 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/explicit_span_range.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +explicit_span_range!(one, two, three, four); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/explicit_span_range.stderr b/vendor/proc-macro-error/tests/ui/explicit_span_range.stderr new file mode 100644 index 0000000000..781a71e76a --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/explicit_span_range.stderr @@ -0,0 +1,5 @@ +error: explicit SpanRange + --> $DIR/explicit_span_range.rs:4:22 + | +4 | explicit_span_range!(one, two, three, four); + | ^^^^^^^^^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/misuse.rs b/vendor/proc-macro-error/tests/ui/misuse.rs new file mode 100644 index 0000000000..e6d2d24971 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/misuse.rs @@ -0,0 +1,11 @@ +extern crate proc_macro_error; +use proc_macro_error::abort; + +struct Foo; + +#[allow(unused)] +fn foo() { + abort!(Foo, "BOOM"); +} + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/misuse.stderr b/vendor/proc-macro-error/tests/ui/misuse.stderr new file mode 100644 index 0000000000..8eaf6456fd --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/misuse.stderr @@ -0,0 +1,13 @@ +error[E0599]: no method named `FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange` found for reference `&Foo` in the current scope + --> $DIR/misuse.rs:8:5 + | +4 | struct Foo; + | ----------- doesn't satisfy `Foo: quote::to_tokens::ToTokens` +... +8 | abort!(Foo, "BOOM"); + | ^^^^^^^^^^^^^^^^^^^^ method not found in `&Foo` + | + = note: the method `FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange` exists but the following trait bounds were not satisfied: + `Foo: quote::to_tokens::ToTokens` + which is required by `&Foo: proc_macro_error::__export::ToTokensAsSpanRange` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/multiple_tokens.rs b/vendor/proc-macro-error/tests/ui/multiple_tokens.rs new file mode 100644 index 0000000000..215928f6f4 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/multiple_tokens.rs @@ -0,0 +1,6 @@ +extern crate test_crate; + +#[test_crate::multiple_tokens] +type T = (); + +fn main() {} \ No newline at end of file diff --git a/vendor/proc-macro-error/tests/ui/multiple_tokens.stderr b/vendor/proc-macro-error/tests/ui/multiple_tokens.stderr new file mode 100644 index 0000000000..c6172c6cc6 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/multiple_tokens.stderr @@ -0,0 +1,5 @@ +error: ... + --> $DIR/multiple_tokens.rs:4:1 + | +4 | type T = (); + | ^^^^^^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/not_proc_macro.rs b/vendor/proc-macro-error/tests/ui/not_proc_macro.rs new file mode 100644 index 0000000000..e241c5cd28 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/not_proc_macro.rs @@ -0,0 +1,4 @@ +use proc_macro_error::proc_macro_error; + +#[proc_macro_error] +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/not_proc_macro.stderr b/vendor/proc-macro-error/tests/ui/not_proc_macro.stderr new file mode 100644 index 0000000000..f19f01bd8e --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/not_proc_macro.stderr @@ -0,0 +1,10 @@ +error: #[proc_macro_error] attribute can be used only with procedural macros + + = hint: if you are really sure that #[proc_macro_error] should be applied to this exact function, use #[proc_macro_error(allow_not_macro)] + + --> $DIR/not_proc_macro.rs:3:1 + | +3 | #[proc_macro_error] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/option_ext.rs b/vendor/proc-macro-error/tests/ui/option_ext.rs new file mode 100644 index 0000000000..dfbfc03835 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/option_ext.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +option_ext!(one, two); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/option_ext.stderr b/vendor/proc-macro-error/tests/ui/option_ext.stderr new file mode 100644 index 0000000000..91b151ec2f --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/option_ext.stderr @@ -0,0 +1,7 @@ +error: Option::expect_or_abort() test + --> $DIR/option_ext.rs:4:1 + | +4 | option_ext!(one, two); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/proc_macro_hack.rs b/vendor/proc-macro-error/tests/ui/proc_macro_hack.rs new file mode 100644 index 0000000000..2504bdd401 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/proc_macro_hack.rs @@ -0,0 +1,10 @@ +// Adapted from https://github.com/dtolnay/proc-macro-hack/blob/master/example/src/main.rs +// Licensed under either of Apache License, Version 2.0 or MIT license at your option. + +use proc_macro_hack_test::add_one; + +fn main() { + let two = 2; + let nine = add_one!(two) + add_one!(2 + 3); + println!("nine = {}", nine); +} diff --git a/vendor/proc-macro-error/tests/ui/proc_macro_hack.stderr b/vendor/proc-macro-error/tests/ui/proc_macro_hack.stderr new file mode 100644 index 0000000000..0e984f918d --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/proc_macro_hack.stderr @@ -0,0 +1,26 @@ +error: BOOM + --> $DIR/proc_macro_hack.rs:8:25 + | +8 | let nine = add_one!(two) + add_one!(2 + 3); + | ^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: BOOM + --> $DIR/proc_macro_hack.rs:8:41 + | +8 | let nine = add_one!(two) + add_one!(2 + 3); + | ^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: unreachable expression + --> $DIR/proc_macro_hack.rs:8:32 + | +8 | let nine = add_one!(two) + add_one!(2 + 3); + | ------------- ^^^^^^^^^^^^^^^ unreachable expression + | | + | any code following this expression is unreachable + | + = note: `#[warn(unreachable_code)]` on by default + = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/result_ext.rs b/vendor/proc-macro-error/tests/ui/result_ext.rs new file mode 100644 index 0000000000..bdd560dba9 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/result_ext.rs @@ -0,0 +1,7 @@ +extern crate test_crate; +use test_crate::*; + +result_unwrap_or_abort!(one, two); +result_expect_or_abort!(one, two); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/result_ext.stderr b/vendor/proc-macro-error/tests/ui/result_ext.stderr new file mode 100644 index 0000000000..f2dc0e4235 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/result_ext.stderr @@ -0,0 +1,11 @@ +error: Result::unwrap_or_abort() test + --> $DIR/result_ext.rs:4:25 + | +4 | result_unwrap_or_abort!(one, two); + | ^^^ + +error: BOOM: Result::expect_or_abort() test + --> $DIR/result_ext.rs:5:25 + | +5 | result_expect_or_abort!(one, two); + | ^^^ diff --git a/vendor/proc-macro-error/tests/ui/to_tokens_span.rs b/vendor/proc-macro-error/tests/ui/to_tokens_span.rs new file mode 100644 index 0000000000..a7c3fc976c --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/to_tokens_span.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +to_tokens_span!(std::option::Option); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/to_tokens_span.stderr b/vendor/proc-macro-error/tests/ui/to_tokens_span.stderr new file mode 100644 index 0000000000..b8c4968263 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/to_tokens_span.stderr @@ -0,0 +1,11 @@ +error: whole type + --> $DIR/to_tokens_span.rs:4:17 + | +4 | to_tokens_span!(std::option::Option); + | ^^^^^^^^^^^^^^^^^^^ + +error: explicit .span() + --> $DIR/to_tokens_span.rs:4:17 + | +4 | to_tokens_span!(std::option::Option); + | ^^^ diff --git a/vendor/proc-macro-error/tests/ui/unknown_setting.rs b/vendor/proc-macro-error/tests/ui/unknown_setting.rs new file mode 100644 index 0000000000..d8e58eaf87 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/unknown_setting.rs @@ -0,0 +1,4 @@ +use proc_macro_error::proc_macro_error; + +#[proc_macro_error(allow_not_macro, assert_unwind_safe, trololo)] +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/unknown_setting.stderr b/vendor/proc-macro-error/tests/ui/unknown_setting.stderr new file mode 100644 index 0000000000..a55de0b31b --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/unknown_setting.stderr @@ -0,0 +1,5 @@ +error: unknown setting `trololo`, expected one of `assert_unwind_safe`, `allow_not_macro`, `proc_macro_hack` + --> $DIR/unknown_setting.rs:3:57 + | +3 | #[proc_macro_error(allow_not_macro, assert_unwind_safe, trololo)] + | ^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/unrelated_panic.rs b/vendor/proc-macro-error/tests/ui/unrelated_panic.rs new file mode 100644 index 0000000000..c74e3e0623 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/unrelated_panic.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +unrelated_panic!(); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/unrelated_panic.stderr b/vendor/proc-macro-error/tests/ui/unrelated_panic.stderr new file mode 100644 index 0000000000..d46d689f2f --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/unrelated_panic.stderr @@ -0,0 +1,7 @@ +error: proc macro panicked + --> $DIR/unrelated_panic.rs:4:1 + | +4 | unrelated_panic!(); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: message: unrelated panic test diff --git a/vendor/proc-macro2/.cargo-checksum.json b/vendor/proc-macro2/.cargo-checksum.json index f0198b7ab4..b4cb5b04a5 100644 --- a/vendor/proc-macro2/.cargo-checksum.json +++ b/vendor/proc-macro2/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"3f9b01260486dd920150d3052c5db2cb068ef8dba56e506f9d97881911b24c72","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"e1f9d4fc22cff2c049f166a403b41458632a94357890d31cf0e3ad83807fb430","build.rs":"332185d7ad4c859210f5edd7a76bc95146c8277726a2f81417f34927c4424d68","src/detection.rs":"9d25d896889e65330858f2d6f6223c1b98cd1dad189813ad4161ff189fbda2b8","src/fallback.rs":"ddb8137cb6e8b95e99ed179a17a5cae47b29bda5aa24ab48673a2ab18a629020","src/lib.rs":"cd064d760cd68f0b52ea275677daf192dffbf99be2e0b31ca0fbe0e8f59f1630","src/parse.rs":"500edee9773132e27e44d0fdaa042b1cb9451e29e65124493986f51710c0664c","src/strnom.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/wrapper.rs":"d36c0dced7ec0e7585c1f935cda836080bcae6de1de3d7851d962e9e11a3ac48","tests/comments.rs":"ea6cbe6f4c8852e6a0612893c7d4f2c144a2e6a134a6c3db641a320cbfc3c800","tests/features.rs":"a86deb8644992a4eb64d9fd493eff16f9cf9c5cb6ade3a634ce0c990cf87d559","tests/marker.rs":"c2652e3ae1dfcb94d2e6313b29712c5dcbd0fe62026913e67bb7cebd7560aade","tests/test.rs":"310c856e27ff61c9ec7f0a5cd96031aac02971557b1621f5e17b089d58e79bcd"},"package":"04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"} \ No newline at end of file +{"files":{"Cargo.toml":"f0e7f7d56e81b261ade37919ec982db131758e2c5f3b59f293e5c8071400e467","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"e1f9d4fc22cff2c049f166a403b41458632a94357890d31cf0e3ad83807fb430","build.rs":"4ebf65b1e910e05f1b570e62b012384ef3752c052ef4df65aa70f37cc6635015","src/detection.rs":"9d25d896889e65330858f2d6f6223c1b98cd1dad189813ad4161ff189fbda2b8","src/fallback.rs":"239f9a25c0f2ab57592288d944c7f1a0f887536b6d4dc2428a17640af8d10a41","src/lib.rs":"690f1afba55506e0c9cdbd17a9601ff79cbe88ac3253afaf2f10f725b8926a7c","src/marker.rs":"87fce2d0357f5b7998b6d9dfb064f4a0cbc9dabb19e33d4b514a446243ebe2e8","src/parse.rs":"500edee9773132e27e44d0fdaa042b1cb9451e29e65124493986f51710c0664c","src/wrapper.rs":"d36c0dced7ec0e7585c1f935cda836080bcae6de1de3d7851d962e9e11a3ac48","tests/comments.rs":"ea6cbe6f4c8852e6a0612893c7d4f2c144a2e6a134a6c3db641a320cbfc3c800","tests/features.rs":"a86deb8644992a4eb64d9fd493eff16f9cf9c5cb6ade3a634ce0c990cf87d559","tests/marker.rs":"652db9f25c69ffc65baa60cdca8f195aa2e254d4de0a9ddc85de4dc2470544b6","tests/test.rs":"310c856e27ff61c9ec7f0a5cd96031aac02971557b1621f5e17b089d58e79bcd","tests/test_fmt.rs":"745dfdc41d09c5308c221395eb43f2041f0a1413d2927a813bc2ad4554438fe2"},"package":"36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"} \ No newline at end of file diff --git a/vendor/proc-macro2/Cargo.toml b/vendor/proc-macro2/Cargo.toml index 4e258b1011..2583e71547 100644 --- a/vendor/proc-macro2/Cargo.toml +++ b/vendor/proc-macro2/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "proc-macro2" -version = "1.0.19" +version = "1.0.21" authors = ["Alex Crichton ", "David Tolnay "] description = "A substitute implementation of the compiler's `proc_macro` API to decouple\ntoken-based libraries from the procedural macro use case.\n" documentation = "https://docs.rs/proc-macro2" diff --git a/vendor/proc-macro2/build.rs b/vendor/proc-macro2/build.rs index 153e13f509..edc0db7a54 100644 --- a/vendor/proc-macro2/build.rs +++ b/vendor/proc-macro2/build.rs @@ -61,6 +61,10 @@ fn main() { println!("cargo:rustc-cfg=span_locations"); } + if version.minor < 32 { + println!("cargo:rustc-cfg=no_libprocmacro_unwind_safe"); + } + if version.minor < 39 { println!("cargo:rustc-cfg=no_bind_by_move_pattern_guard"); } diff --git a/vendor/proc-macro2/src/fallback.rs b/vendor/proc-macro2/src/fallback.rs index 23250c972c..949b9a5ff1 100644 --- a/vendor/proc-macro2/src/fallback.rs +++ b/vendor/proc-macro2/src/fallback.rs @@ -157,29 +157,14 @@ impl Display for TokenStream { } joint = false; match tt { - TokenTree::Group(tt) => { - let (start, end) = match tt.delimiter() { - Delimiter::Parenthesis => ("(", ")"), - Delimiter::Brace => ("{", "}"), - Delimiter::Bracket => ("[", "]"), - Delimiter::None => ("", ""), - }; - if tt.stream().into_iter().next().is_none() { - write!(f, "{} {}", start, end)? - } else { - write!(f, "{} {} {}", start, tt.stream(), end)? - } - } - TokenTree::Ident(tt) => write!(f, "{}", tt)?, + TokenTree::Group(tt) => Display::fmt(tt, f), + TokenTree::Ident(tt) => Display::fmt(tt, f), TokenTree::Punct(tt) => { - write!(f, "{}", tt.as_char())?; - match tt.spacing() { - Spacing::Alone => {} - Spacing::Joint => joint = true, - } + joint = tt.spacing() == Spacing::Joint; + Display::fmt(tt, f) } - TokenTree::Literal(tt) => write!(f, "{}", tt)?, - } + TokenTree::Literal(tt) => Display::fmt(tt, f), + }? } Ok(()) @@ -588,17 +573,27 @@ impl Group { } impl Display for Group { + // We attempt to match libproc_macro's formatting. + // Empty parens: () + // Nonempty parens: (...) + // Empty brackets: [] + // Nonempty brackets: [...] + // Empty braces: { } + // Nonempty braces: { ... } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (left, right) = match self.delimiter { + let (open, close) = match self.delimiter { Delimiter::Parenthesis => ("(", ")"), - Delimiter::Brace => ("{", "}"), + Delimiter::Brace => ("{ ", "}"), Delimiter::Bracket => ("[", "]"), Delimiter::None => ("", ""), }; - f.write_str(left)?; + f.write_str(open)?; Display::fmt(&self.stream, f)?; - f.write_str(right)?; + if self.delimiter == Delimiter::Brace && !self.stream.inner.is_empty() { + f.write_str(" ")?; + } + f.write_str(close)?; Ok(()) } diff --git a/vendor/proc-macro2/src/lib.rs b/vendor/proc-macro2/src/lib.rs index e23fc6a84a..891d7d7984 100644 --- a/vendor/proc-macro2/src/lib.rs +++ b/vendor/proc-macro2/src/lib.rs @@ -78,7 +78,7 @@ //! a different thread. // Proc-macro2 types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/proc-macro2/1.0.19")] +#![doc(html_root_url = "https://docs.rs/proc-macro2/1.0.21")] #![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span))] #![cfg_attr(super_unstable, feature(proc_macro_raw_ident, proc_macro_def_site))] #![allow(clippy::needless_doctest_main)] @@ -86,17 +86,7 @@ #[cfg(use_proc_macro)] extern crate proc_macro; -use std::cmp::Ordering; -use std::fmt::{self, Debug, Display}; -use std::hash::{Hash, Hasher}; -use std::iter::FromIterator; -use std::marker; -use std::ops::RangeBounds; -#[cfg(procmacro2_semver_exempt)] -use std::path::PathBuf; -use std::rc::Rc; -use std::str::FromStr; - +mod marker; mod parse; #[cfg(wrap_proc_macro)] @@ -113,6 +103,16 @@ use crate::fallback as imp; #[cfg(wrap_proc_macro)] mod imp; +use crate::marker::Marker; +use std::cmp::Ordering; +use std::fmt::{self, Debug, Display}; +use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; +use std::ops::RangeBounds; +#[cfg(procmacro2_semver_exempt)] +use std::path::PathBuf; +use std::str::FromStr; + /// An abstract stream of tokens, or more concretely a sequence of token trees. /// /// This type provides interfaces for iterating over token trees and for @@ -123,27 +123,27 @@ mod imp; #[derive(Clone)] pub struct TokenStream { inner: imp::TokenStream, - _marker: marker::PhantomData>, + _marker: Marker, } /// Error returned from `TokenStream::from_str`. pub struct LexError { inner: imp::LexError, - _marker: marker::PhantomData>, + _marker: Marker, } impl TokenStream { fn _new(inner: imp::TokenStream) -> TokenStream { TokenStream { inner, - _marker: marker::PhantomData, + _marker: Marker, } } fn _new_stable(inner: fallback::TokenStream) -> TokenStream { TokenStream { inner: inner.into(), - _marker: marker::PhantomData, + _marker: Marker, } } @@ -180,7 +180,7 @@ impl FromStr for TokenStream { fn from_str(src: &str) -> Result { let e = src.parse().map_err(|e| LexError { inner: e, - _marker: marker::PhantomData, + _marker: Marker, })?; Ok(TokenStream::_new(e)) } @@ -261,7 +261,7 @@ impl Debug for LexError { #[derive(Clone, PartialEq, Eq)] pub struct SourceFile { inner: imp::SourceFile, - _marker: marker::PhantomData>, + _marker: Marker, } #[cfg(procmacro2_semver_exempt)] @@ -269,7 +269,7 @@ impl SourceFile { fn _new(inner: imp::SourceFile) -> Self { SourceFile { inner, - _marker: marker::PhantomData, + _marker: Marker, } } @@ -338,21 +338,21 @@ impl PartialOrd for LineColumn { #[derive(Copy, Clone)] pub struct Span { inner: imp::Span, - _marker: marker::PhantomData>, + _marker: Marker, } impl Span { fn _new(inner: imp::Span) -> Span { Span { inner, - _marker: marker::PhantomData, + _marker: Marker, } } fn _new_stable(inner: fallback::Span) -> Span { Span { inner: inner.into(), - _marker: marker::PhantomData, + _marker: Marker, } } @@ -840,14 +840,14 @@ impl Debug for Punct { #[derive(Clone)] pub struct Ident { inner: imp::Ident, - _marker: marker::PhantomData>, + _marker: Marker, } impl Ident { fn _new(inner: imp::Ident) -> Ident { Ident { inner, - _marker: marker::PhantomData, + _marker: Marker, } } @@ -968,7 +968,7 @@ impl Debug for Ident { #[derive(Clone)] pub struct Literal { inner: imp::Literal, - _marker: marker::PhantomData>, + _marker: Marker, } macro_rules! suffixed_int_literals { @@ -1015,14 +1015,14 @@ impl Literal { fn _new(inner: imp::Literal) -> Literal { Literal { inner, - _marker: marker::PhantomData, + _marker: Marker, } } fn _new_stable(inner: fallback::Literal) -> Literal { Literal { inner: inner.into(), - _marker: marker::PhantomData, + _marker: Marker, } } @@ -1181,10 +1181,9 @@ impl Display for Literal { /// Public implementation details for the `TokenStream` type, such as iterators. pub mod token_stream { + use crate::marker::Marker; use crate::{imp, TokenTree}; use std::fmt::{self, Debug}; - use std::marker; - use std::rc::Rc; pub use crate::TokenStream; @@ -1195,7 +1194,7 @@ pub mod token_stream { #[derive(Clone)] pub struct IntoIter { inner: imp::TokenTreeIter, - _marker: marker::PhantomData>, + _marker: Marker, } impl Iterator for IntoIter { @@ -1219,7 +1218,7 @@ pub mod token_stream { fn into_iter(self) -> IntoIter { IntoIter { inner: self.inner.into_iter(), - _marker: marker::PhantomData, + _marker: Marker, } } } diff --git a/vendor/proc-macro2/src/marker.rs b/vendor/proc-macro2/src/marker.rs new file mode 100644 index 0000000000..58729baf4a --- /dev/null +++ b/vendor/proc-macro2/src/marker.rs @@ -0,0 +1,18 @@ +use std::marker::PhantomData; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::rc::Rc; + +// Zero sized marker with the correct set of autotrait impls we want all proc +// macro types to have. +pub(crate) type Marker = PhantomData; + +pub(crate) use self::value::*; + +mod value { + pub(crate) use std::marker::PhantomData as Marker; +} + +pub(crate) struct ProcMacroAutoTraits(Rc<()>); + +impl UnwindSafe for ProcMacroAutoTraits {} +impl RefUnwindSafe for ProcMacroAutoTraits {} diff --git a/vendor/proc-macro2/src/strnom.rs b/vendor/proc-macro2/src/strnom.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/vendor/proc-macro2/tests/marker.rs b/vendor/proc-macro2/tests/marker.rs index 7af2539c1a..70e57677cd 100644 --- a/vendor/proc-macro2/tests/marker.rs +++ b/vendor/proc-macro2/tests/marker.rs @@ -57,3 +57,36 @@ mod semver_exempt { assert_impl!(SourceFile is not Send or Sync); } + +#[cfg(not(no_libprocmacro_unwind_safe))] +mod unwind_safe { + use super::*; + use std::panic::{RefUnwindSafe, UnwindSafe}; + + macro_rules! assert_unwind_safe { + ($($types:ident)*) => { + $( + assert_impl!($types is UnwindSafe and RefUnwindSafe); + )* + }; + } + + assert_unwind_safe! { + Delimiter + Group + Ident + LexError + Literal + Punct + Spacing + Span + TokenStream + TokenTree + } + + #[cfg(procmacro2_semver_exempt)] + assert_unwind_safe! { + LineColumn + SourceFile + } +} diff --git a/vendor/proc-macro2/tests/test_fmt.rs b/vendor/proc-macro2/tests/test_fmt.rs new file mode 100644 index 0000000000..99a0aee5c8 --- /dev/null +++ b/vendor/proc-macro2/tests/test_fmt.rs @@ -0,0 +1,26 @@ +use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; +use std::iter::{self, FromIterator}; + +#[test] +fn test_fmt_group() { + let ident = Ident::new("x", Span::call_site()); + let inner = TokenStream::from_iter(iter::once(TokenTree::Ident(ident))); + let parens_empty = Group::new(Delimiter::Parenthesis, TokenStream::new()); + let parens_nonempty = Group::new(Delimiter::Parenthesis, inner.clone()); + let brackets_empty = Group::new(Delimiter::Bracket, TokenStream::new()); + let brackets_nonempty = Group::new(Delimiter::Bracket, inner.clone()); + let braces_empty = Group::new(Delimiter::Brace, TokenStream::new()); + let braces_nonempty = Group::new(Delimiter::Brace, inner.clone()); + let none_empty = Group::new(Delimiter::None, TokenStream::new()); + let none_nonempty = Group::new(Delimiter::None, inner.clone()); + + // Matches libproc_macro. + assert_eq!("()", parens_empty.to_string()); + assert_eq!("(x)", parens_nonempty.to_string()); + assert_eq!("[]", brackets_empty.to_string()); + assert_eq!("[x]", brackets_nonempty.to_string()); + assert_eq!("{ }", braces_empty.to_string()); + assert_eq!("{ x }", braces_nonempty.to_string()); + assert_eq!("", none_empty.to_string()); + assert_eq!("x", none_nonempty.to_string()); +} diff --git a/vendor/pulldown-cmark-0.7.2/.cargo-checksum.json b/vendor/pulldown-cmark-0.7.2/.cargo-checksum.json new file mode 100644 index 0000000000..956e4ad354 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CONTRIBUTING.md":"ad9613136aef42ccaca15f131ecb7bb697adbd05cb2d38062e40581d570e5005","Cargo.lock":"0cce438e59390e1c92b9cf168212d1c4a7390e5de715e432e4204118fb10113c","Cargo.toml":"4a791d5e9478bf3fdfb1e85d14aebcafc85d6ed07f73dcf4e742a47981d596d6","LICENSE":"2afc41ab83a8e715bf57b2b0d9d3ca3da1a0afc4cdadefd72f3a1ba537c5213f","README.md":"2a6061d89f6232ed5e444878668bcd819508519a90966945b1f774a14fd247a1","benches/html_rendering.rs":"9dd749395295e3c27e2dbdd784e34e0d797f150665b3e0af7803217e44902a80","benches/lib.rs":"8d66217a7712baae45d1101042284ddbe99508cc240b461781b0d25da185c108","build.rs":"ea58b69966ea4d7849d1053555b9c8631aefcc977cebdc5e412541527eb6baff","examples/event-filter.rs":"625cb8218e46b97f2553c3dd85a75b3b09bdcc8055c2ef670fa3930f924f5d75","examples/string-to-string.rs":"94cf4c6e1027186b73042fb9971e1469652682398c53e2dffe60d3dc30e72629","src/entities.rs":"08f6499fd2ed5ed5be89506f04e785b33eecb3b304418f812267dd8f01bbc6b6","src/escape.rs":"b5b073435e507e3d2897ea89f6143b5cf47d6cb140948450a255cc13fc2a3c5e","src/html.rs":"25ca58d7397209a9c4048efa647940e2ead21350de567c1c1013d3540438f678","src/lib.rs":"0e9ae448b1a5ff10add1aa6d9db3339e12f7da2bac438b39fb90f98880337c4e","src/linklabel.rs":"f174a9020c23770fe14eb377e85da8280e1ecc9ec4175108ebe38f507270bfeb","src/main.rs":"a009df64cf1f559ebc7b1768bd5842b42df01a7865ef75b8f92ee476360b3db7","src/parse.rs":"05d1023a36893f72b3d9208cfc5f3c42c4af58a3c9f88c7755efdc0a39a86a1b","src/puncttable.rs":"ff83b70b65d1666712cbba1c9949f65ea69d72b25a2aa960a7c8c8d1b5fbed08","src/scanners.rs":"7bebfde06556b74391dba5e9f9e2a12995a6e62816b414d4a8d6b610e6bf307c","src/simd.rs":"6b386b1bd224d10cd8203e7162dd9ed242970de2ce5c1583635285337f4a266f","src/strings.rs":"f19ebad46ab498eef93091d4c90ba9e673c85e848ddde82bf2aa5e1dc5fdc3ea","src/tree.rs":"7c3402a077ff8dd321967e9ac685ecf2038c51601afa38fe75f329ff9564a7f0","tests/errors.rs":"59199be255a0edd7cb9a8fd988738603ec82de3b6d3ec6d331d1c43e2957f5fc","tests/html.rs":"d305de4e8b209af0db749be4bf1137d446a6b3953c01af31ef7c0a807701d022","tests/lib.rs":"02bd5825bfc3d1ec24415049914774e84169bd2f7173475b050157f5539be781","tests/suite/footnotes.rs":"aa1471b4bbaf52efdd870ab078907c95c961bbfe9e2beddbe4dddb3f0bba1c7f","tests/suite/gfm_strikethrough.rs":"a43f9578651faf6f7a4488d4e6a31f371dea8fefa4892a1de63f6dad6ad7827a","tests/suite/gfm_table.rs":"de092e0542b418fb358116aa57810805a84cefe0710e9cf0df9018f37beedc30","tests/suite/gfm_tasklist.rs":"30f9c584eaaeae31cae5a915bc84da91202de2bfceec19faa46778bb87f88cab","tests/suite/mod.rs":"7bf32170c9662f76870139b47596643a60d105427b6a6f85dd15044caf82c6c8","tests/suite/regression.rs":"c3b3975e82167a6301adb9f4ac337f1fb7cf864bf49f7adde8bd80aeadb7d226","tests/suite/spec.rs":"de043bdf7cc81120ca779bf0c38e802c865ec632870f4efa0a30bfd47590426a","tests/suite/table.rs":"f65dd8530e39b846ca6a0eb40dadf850ab266e9925dd331531f404c1cc9d422e"},"package":"ca36dea94d187597e104a5c8e4b07576a8a45aa5db48a65e12940d3eb7461f55"} \ No newline at end of file diff --git a/vendor/pulldown-cmark-0.7.2/CONTRIBUTING.md b/vendor/pulldown-cmark-0.7.2/CONTRIBUTING.md new file mode 100644 index 0000000000..8572568675 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/CONTRIBUTING.md @@ -0,0 +1,21 @@ +Want to contribute? Great! First, read this page. + +### Before you contribute + +Before you start working on a larger contribution, you should get in touch with +us first through the issue tracker with your idea so that we can help out and +possibly guide you. Coordinating up front makes it much easier to avoid +frustration later on. + +### Getting familiar with the project + +**The architecture** is somewhat unique, it was originally inspired by [XML pull parsers](http://www.xmlpull.org), but ended up going in somewhat its own direction. to get familiar with it, +- start my reading the [README](README.md) page, which gives some details on the design of the parser (pull-based events) and some rationalization for it ; +- read the [blog post](https://fullyfaithful.eu/pulldown-cmark) about the release of Pulldown-cmark 0.3 by Marcus Klaas de Vries. + +**The source code** can be approached by skimming the [API documentation](https://docs.rs/pulldown-cmark/latest/pulldown_cmark) first, then explore the code for the main struct, [`Parser`](https://docs.rs/pulldown-cmark/latest/pulldown_cmark/struct.Parser.html) + +### Code reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. diff --git a/vendor/pulldown-cmark-0.7.2/Cargo.lock b/vendor/pulldown-cmark-0.7.2/Cargo.lock new file mode 100644 index 0000000000..2c8e742e09 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/Cargo.lock @@ -0,0 +1,918 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bstr" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bumpalo" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cast" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "oorandom 11.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "plotters 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion-plot" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "half" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hermit-abi" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "html5ever" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "js-sys" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "markup5ever" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_codegen 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "markup5ever_rcdom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "xml5ever 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memoffset" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-traits" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "oorandom" +version = "11.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "siphasher 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "plotters" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pulldown-cmark" +version = "0.7.2" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever_rcdom 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-automata" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_cbor" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "siphasher" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "string_cache" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tendril" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tinytemplate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "utf-8" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasm-bindgen" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "web-sys" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "xml5ever" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" +"checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +"checksum criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "70daa7ceec6cf143990669a04c7df13391d55fb27bd4079d252fca774ba244d8" +"checksum criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" +"checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +"checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +"checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +"checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" +"checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" +"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +"checksum half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" +"checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +"checksum html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b" +"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +"checksum js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b9172132a62451e56142bff9afc91c8e4a4500aa5b847da36815b63bfda916" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +"checksum markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aae38d669396ca9b707bfc3db254bc382ddb94f57cc5c235f34623a669a01dab" +"checksum markup5ever_rcdom 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f015da43bcd8d4f144559a3423f4591d69b8ce0652c905374da7205df336ae2b" +"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +"checksum memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" +"checksum new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +"checksum oorandom 11.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c" +"checksum phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +"checksum phf_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +"checksum phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +"checksum phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +"checksum plotters 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d1685fbe7beba33de0330629da9d955ac75bd54f33d7b79f9a895590124f6bb" +"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +"checksum rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080" +"checksum rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280" +"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" +"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +"checksum serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +"checksum serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" +"checksum siphasher 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" +"checksum string_cache 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a" +"checksum string_cache_codegen 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" +"checksum syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" +"checksum tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +"checksum tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f" +"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +"checksum utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" +"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +"checksum wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "6a634620115e4a229108b71bde263bb4220c483b3f07f5ba514ee8d15064c4c2" +"checksum wasm-bindgen-backend 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df" +"checksum wasm-bindgen-macro 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "3fcfd5ef6eec85623b4c6e844293d4516470d8f19cd72d0d12246017eb9060b8" +"checksum wasm-bindgen-macro-support 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "9adff9ee0e94b926ca81b57f57f86d5545cdcb1d259e21ec9bdd95b901754c75" +"checksum wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7b90ea6c632dd06fd765d44542e234d5e63d9bb917ecd64d79778a13bd79ae" +"checksum web-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "863539788676619aac1a23e2df3655e96b32b0e05eb72ca34ba045ad573c625d" +"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum xml5ever 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b1b52e6e8614d4a58b8e70cf51ec0cc21b256ad8206708bcff8139b5bbd6a59" diff --git a/vendor/pulldown-cmark-0.7.2/Cargo.toml b/vendor/pulldown-cmark-0.7.2/Cargo.toml new file mode 100644 index 0000000000..c85952d7fa --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/Cargo.toml @@ -0,0 +1,68 @@ +# 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 = "pulldown-cmark" +version = "0.7.2" +authors = ["Raph Levien ", "Marcus Klaas de Vries "] +build = "build.rs" +exclude = ["/third_party/**/*", "/tools/**/*", "/specs/**/*", "/fuzzer/**/*", "/azure-pipelines.yml"] +description = "A pull parser for CommonMark" +readme = "README.md" +keywords = ["markdown", "commonmark"] +categories = ["text-processing"] +license = "MIT" +repository = "https://github.com/raphlinus/pulldown-cmark" + +[[bin]] +name = "pulldown-cmark" +doc = false +required-features = ["getopts"] + +[[bench]] +name = "html_rendering" +harness = false +[dependencies.bitflags] +version = "1.2" + +[dependencies.getopts] +version = "0.2" +optional = true + +[dependencies.memchr] +version = "2.3" + +[dependencies.unicase] +version = "2.6" +[dev-dependencies.criterion] +version = "0.3" + +[dev-dependencies.html5ever] +version = "0.25" + +[dev-dependencies.lazy_static] +version = "1.4" + +[dev-dependencies.markup5ever_rcdom] +version = "0.1" + +[dev-dependencies.regex] +version = "1.3" + +[dev-dependencies.tendril] +version = "0.4" + +[features] +default = ["getopts"] +gen-tests = [] +simd = [] diff --git a/vendor/pulldown-cmark-0.7.2/LICENSE b/vendor/pulldown-cmark-0.7.2/LICENSE new file mode 100644 index 0000000000..c10685cc3d --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright 2015 Google Inc. All rights reserved. + +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/pulldown-cmark-0.7.2/README.md b/vendor/pulldown-cmark-0.7.2/README.md new file mode 100644 index 0000000000..96e3437902 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/README.md @@ -0,0 +1,152 @@ +# pulldown-cmark + +[![Build Status](https://dev.azure.com/raphlinus/pulldown-cmark/_apis/build/status/pulldown-cmark-CI?branchName=master)](https://dev.azure.com/raphlinus/pulldown-cmark/_build/latest?definitionId=2&branchName=master) +[![Docs](https://docs.rs/pulldown-cmark/badge.svg)](https://docs.rs/pulldown-cmark) +[![Crates.io](https://img.shields.io/crates/v/pulldown-cmark.svg?maxAge=2592000)](https://crates.io/crates/pulldown-cmark) + +[Documentation](https://docs.rs/pulldown-cmark/) + +This library is a pull parser for [CommonMark](http://commonmark.org/), written +in [Rust](http://www.rust-lang.org/). It comes with a simple command-line tool, +useful for rendering to HTML, and is also designed to be easy to use from as +a library. + +It is designed to be: + +* Fast; a bare minimum of allocation and copying +* Safe; written in pure Rust with no unsafe blocks +* Versatile; in particular source-maps are supported +* Correct; the goal is 100% compliance with the [CommonMark spec](http://spec.commonmark.org/) + +Further, it optionally supports parsing footnotes, +[Github flavored tables](https://github.github.com/gfm/#tables-extension-), +[Github flavored task lists](https://github.github.com/gfm/#task-list-items-extension-) and +[strikethrough](https://github.github.com/gfm/#strikethrough-extension-). + +Rustc 1.34 or newer is required to build the crate. + +## Why a pull parser? + +There are many parsers for Markdown and its variants, but to my knowledge none +use pull parsing. Pull parsing has become popular for XML, especially for +memory-conscious applications, because it uses dramatically less memory than +constructing a document tree, but is much easier to use than push parsers. Push +parsers are notoriously difficult to use, and also often error-prone because of +the need for user to delicately juggle state in a series of callbacks. + +In a clean design, the parsing and rendering stages are neatly separated, but +this is often sacrificed in the name of performance and expedience. Many Markdown +implementations mix parsing and rendering together, and even designs that try +to separate them (such as the popular [hoedown](https://github.com/hoedown/hoedown)), +make the assumption that the rendering process can be fully represented as a +serialized string. + +Pull parsing is in some sense the most versatile architecture. It's possible to +drive a push interface, also with minimal memory, and quite straightforward to +construct an AST. Another advantage is that source-map information (the mapping +between parsed blocks and offsets within the source text) is readily available; +you can call `into_offset_iter()` to create an iterator that yields `(Event, Range)` +pairs, where the second element is the event's corresponding range in the source +document. + +While manipulating ASTs is the most flexible way to transform documents, +operating on iterators is surprisingly easy, and quite efficient. Here, for +example, is the code to transform soft line breaks into hard breaks: + +```rust +let parser = parser.map(|event| match event { + Event::SoftBreak => Event::HardBreak, + _ => event +}); +``` + +Or expanding an abbreviation in text: + +```rust +let parser = parser.map(|event| match event { + Event::Text(text) => Event::Text(text.replace("abbr", "abbreviation").into()), + _ => event +}); +``` + +Another simple example is code to determine the max nesting level: + +```rust +let mut max_nesting = 0; +let mut level = 0; +for event in parser { + match event { + Event::Start(_) => { + level += 1; + max_nesting = std::cmp::max(max_nesting, level); + } + Event::End(_) => level -= 1, + _ => () + } +} +``` + +There are some basic but fully functional examples of the usage of the crate in the +`examples` directory of this repository. + +## Using Rust idiomatically + +A lot of the internal scanning code is written at a pretty low level (it +pretty much scans byte patterns for the bits of syntax), but the external +interface is designed to be idiomatic Rust. + +Pull parsers are at heart an iterator of events (start and end tags, text, +and other bits and pieces). The parser data structure implements the +Rust Iterator trait directly, and Event is an enum. Thus, you can use the +full power and expressivity of Rust's iterator infrastructure, including +for loops and `map` (as in the examples above), collecting the events into +a vector (for recording, playback, and manipulation), and more. + +Further, the `Text` event (representing text) is a small copy-on-write string. +The vast majority of text fragments are just +slices of the source document. For these, copy-on-write gives a convenient +representation that requires no allocation or copying, but allocated +strings are available when they're needed. Thus, when rendering text to +HTML, most text is copied just once, from the source document to the +HTML buffer. + +When using the pulldown-cmark's own HTML renderer, make sure to write to a buffered +target like a `Vec` or `String`. Since it performs many (very) small writes, writing +directly to stdout, files, or sockets is detrimental to performance. Such writers can +be wrapped in a [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html). + +## Build options + +By default, the binary is built as well. If you don't want/need it, then build like this: + +```bash +> cargo build --no-default-features +``` + +Or put in your `Cargo.toml` file: + +```toml +pulldown-cmark = { version = "0.7", default-features = false } +``` + +SIMD accelerated scanners are available for the x64 platform from version 0.5 onwards. To +enable them, build with simd feature: + +```bash +> cargo build --release --features simd +``` + +Or add the feature to your project's `Cargo.toml`: + +```toml +pulldown-cmark = { version = "0.7", default-features = false, features = ["simd"] } +``` + +## Authors + +The main author is Raph Levien. The implementation of the new design (v0.3+) was completed by Marcus Klaas de Vries. + +## Contributions + +We gladly accept contributions via GitHub pull requests. Please see +[CONTRIBUTING.md](CONTRIBUTING.md) for more details. diff --git a/vendor/pulldown-cmark-0.7.2/benches/html_rendering.rs b/vendor/pulldown-cmark-0.7.2/benches/html_rendering.rs new file mode 100644 index 0000000000..4a2202843d --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/benches/html_rendering.rs @@ -0,0 +1,77 @@ +#[macro_use] +extern crate criterion; +extern crate pulldown_cmark; + +use criterion::Criterion; +use pulldown_cmark::{html, Options, Parser}; +use std::str::from_utf8; + +static CRDT_BYTES: &[u8] = include_bytes!("../third_party/xi-editor/crdt.md"); + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("crdt_total", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + let mut buf = String::with_capacity(input.len() * 3 / 2); + + b.iter(|| { + buf.clear(); + html::push_html(&mut buf, Parser::new_ext(input, Options::empty())); + }) + }); + + c.bench_function("crdt_html", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + let events: Vec<_> = Parser::new_ext(input, Options::empty()).collect(); + let mut buf = String::with_capacity(input.len() * 3 / 2); + + b.iter(|| { + buf.clear(); + html::push_html(&mut buf, events.clone().into_iter()); + }) + }); + + c.bench_function("crdt_parse", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + + b.iter(|| Parser::new_ext(input, Options::empty()).count()) + }); + + c.bench_function("links_n_emphasis", |b| { + let input = r#"""This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** +"""#; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("unescapes", |b| { + let input = "This is by far my favourite unicode code point: પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ"; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("autolinks_n_html", |b| { + let input = "Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! "; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/vendor/pulldown-cmark-0.7.2/benches/lib.rs b/vendor/pulldown-cmark-0.7.2/benches/lib.rs new file mode 100644 index 0000000000..392aa4e12f --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/benches/lib.rs @@ -0,0 +1,49 @@ +#![feature(test)] + +extern crate pulldown_cmark; +extern crate test; + +mod to_html { + use pulldown_cmark::{html, Options, Parser}; + + fn render_html(text: &str, opts: Options) -> String { + let mut s = String::with_capacity(text.len() * 3 / 2); + let p = Parser::new_ext(text, opts); + html::push_html(&mut s, p); + s + } + + #[bench] + fn pathological_codeblocks1(b: &mut test::Bencher) { + // Note that `buf` grows quadratically with number of + // iterations. The point here is that the render time shouldn't + // grow faster than that. + let mut buf = String::new(); + for i in 1..1000 { + for _ in 0..i { + buf.push('`'); + } + buf.push(' '); + } + + b.iter(|| render_html(&buf, Options::empty())); + } + + #[bench] + fn advanced_pathological_codeblocks(b: &mut test::Bencher) { + let mut buf = String::new(); + let mut i = 1; + while buf.len() < 1250 { + for _ in 0..i { + buf.push('`'); + } + buf.push(' '); + i += 1; + } + for _ in 0..buf.len() { + buf.push_str("*a* "); + } + + b.iter(|| render_html(&buf, Options::empty())); + } +} diff --git a/vendor/pulldown-cmark-0.7.2/build.rs b/vendor/pulldown-cmark-0.7.2/build.rs new file mode 100644 index 0000000000..68f5689976 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/build.rs @@ -0,0 +1,187 @@ +fn main() { + generate_tests_from_spec() +} + +// If the "gen-tests" feature is absent, +// this function will be compiled down to nothing +#[cfg(not(feature = "gen-tests"))] +fn generate_tests_from_spec() {} + +// If the feature is present, generate tests +// from any .txt file present in the specs/ directory +// +// Test cases are present in the files in the +// following format: +// +// ```````````````````````````````` example +// markdown +// . +// expected html output +// ```````````````````````````````` +#[cfg(feature = "gen-tests")] +fn generate_tests_from_spec() { + use std::fs::{self, File}; + use std::io::{Read, Write}; + use std::path::PathBuf; + + // This is a hardcoded path to the CommonMark spec because it is not situated in + // the specs/ directory. It's in an array to easily chain it to the other iterator + // and make it easy to eventually add other hardcoded paths in the future if needed + let hardcoded = [ + "./third_party/CommonMark/spec.txt", + "./third_party/GitHub/gfm_table.txt", + "./third_party/GitHub/gfm_strikethrough.txt", + "./third_party/GitHub/gfm_tasklist.txt", + ]; + let hardcoded_iter = hardcoded.into_iter().map(PathBuf::from); + + // Create an iterator over the files in the specs/ directory that have a .txt extension + let spec_files = fs::read_dir("./specs") + .expect("Could not find the 'specs' directory") + .filter_map(Result::ok) + .map(|d| d.path()) + .filter(|p| p.extension().map(|e| e.to_owned()).is_some()) + .chain(hardcoded_iter) + .collect::>(); + + for file_path in &spec_files { + let mut raw_spec = String::new(); + + File::open(&file_path) + .and_then(|mut f| f.read_to_string(&mut raw_spec)) + .expect("Could not read the spec file"); + + let rs_test_file = PathBuf::from("./tests/suite/") + .join(file_path.file_name().expect("Invalid filename")) + .with_extension("rs"); + + let mut spec_rs = + File::create(&rs_test_file).expect(&format!("Could not create {:?}", rs_test_file)); + + let spec_name = file_path.file_stem().unwrap().to_str().unwrap(); + + let spec = Spec::new(&raw_spec); + let mut n_tests = 0; + + spec_rs + .write(b"// This file is auto-generated by the build script\n") + .unwrap(); + spec_rs + .write(b"// Please, do not modify it manually\n") + .unwrap(); + spec_rs + .write(b"\nuse super::test_markdown_html;\n") + .unwrap(); + + for (i, testcase) in spec.enumerate() { + spec_rs + .write_fmt(format_args!( + r###" +#[test] +fn {}_test_{i}() {{ + let original = r##"{original}"##; + let expected = r##"{expected}"##; + + test_markdown_html(original, expected); +}} +"###, + spec_name, + i = i + 1, + original = testcase.original, + expected = testcase.expected + )) + .unwrap(); + + n_tests += 1; + } + + println!( + "cargo:warning=Generated {} tests in {:?}", + n_tests, rs_test_file + ); + } + + // write mods to suite/mod.rs + let suite_mod_file = PathBuf::from("./tests/suite/mod").with_extension("rs"); + + let mut mod_rs = + File::create(&suite_mod_file).expect(&format!("Could not create {:?}", &suite_mod_file)); + + mod_rs + .write(b"// This file is auto-generated by the build script\n") + .unwrap(); + mod_rs + .write(b"// Please, do not modify it manually\n") + .unwrap(); + mod_rs + .write(b"\npub use super::test_markdown_html;\n\n") + .unwrap(); + + for file_path in &spec_files { + let mod_name = file_path.file_stem().unwrap().to_str().unwrap(); + mod_rs.write(b"mod ").unwrap(); + mod_rs.write(mod_name.as_bytes()).unwrap(); + mod_rs.write(b";\n").unwrap(); + } +} + +#[cfg(feature = "gen-tests")] +pub struct Spec<'a> { + spec: &'a str, +} + +#[cfg(feature = "gen-tests")] +impl<'a> Spec<'a> { + pub fn new(spec: &'a str) -> Self { + Spec { spec: spec } + } +} + +#[cfg(feature = "gen-tests")] +pub struct TestCase { + pub original: String, + pub expected: String, +} + +#[cfg(feature = "gen-tests")] +impl<'a> Iterator for Spec<'a> { + type Item = TestCase; + + fn next(&mut self) -> Option { + let spec = self.spec; + + let i_start = match self + .spec + .find("```````````````````````````````` example\n") + .map(|pos| pos + 41) + { + Some(pos) => pos, + None => return None, + }; + + let i_end = match self.spec[i_start..] + .find("\n.\n") + .map(|pos| (pos + 1) + i_start) + { + Some(pos) => pos, + None => return None, + }; + + let e_end = match self.spec[i_end + 2..] + .find("````````````````````````````````\n") + .map(|pos| pos + i_end + 2) + { + Some(pos) => pos, + None => return None, + }; + + self.spec = &self.spec[e_end + 33..]; + + let test_case = TestCase { + original: spec[i_start..i_end].to_string().replace("→", "\t"), + expected: spec[i_end + 2..e_end].to_string().replace("→", "\t"), + }; + + Some(test_case) + } +} diff --git a/vendor/pulldown-cmark-0.7.2/examples/event-filter.rs b/vendor/pulldown-cmark-0.7.2/examples/event-filter.rs new file mode 100644 index 0000000000..86af851f9e --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/examples/event-filter.rs @@ -0,0 +1,29 @@ +extern crate pulldown_cmark; + +use std::io::Write as _; + +use pulldown_cmark::{html, Event, Options, Parser, Tag}; + +fn main() { + let markdown_input: &str = "This is Peter on ![holiday in Greece](pearl_beach.jpg)."; + println!("Parsing the following markdown string:\n{}", markdown_input); + + // Set up parser. We can treat is as any other iterator. We replace Peter by John + // and image by its alt text. + let parser = Parser::new_ext(markdown_input, Options::empty()) + .map(|event| match event { + Event::Text(text) => Event::Text(text.replace("Peter", "John").into()), + _ => event, + }) + .filter(|event| match event { + Event::Start(Tag::Image(..)) | Event::End(Tag::Image(..)) => false, + _ => true, + }); + + // Write to anything implementing the `Write` trait. This could also be a file + // or network socket. + let stdout = std::io::stdout(); + let mut handle = stdout.lock(); + handle.write_all(b"\nHTML output:\n").unwrap(); + html::write_html(&mut handle, parser).unwrap(); +} diff --git a/vendor/pulldown-cmark-0.7.2/examples/string-to-string.rs b/vendor/pulldown-cmark-0.7.2/examples/string-to-string.rs new file mode 100644 index 0000000000..ac08823334 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/examples/string-to-string.rs @@ -0,0 +1,26 @@ +extern crate pulldown_cmark; + +use pulldown_cmark::{html, Options, Parser}; + +fn main() { + let markdown_input: &str = "Hello world, this is a ~~complicated~~ *very simple* example."; + println!("Parsing the following markdown string:\n{}", markdown_input); + + // Set up options and parser. Strikethroughs are not part of the CommonMark standard + // and we therefore must enable it explicitly. + let mut options = Options::empty(); + options.insert(Options::ENABLE_STRIKETHROUGH); + let parser = Parser::new_ext(markdown_input, options); + + // Write to String buffer. + let mut html_output: String = String::with_capacity(markdown_input.len() * 3 / 2); + html::push_html(&mut html_output, parser); + + // Check that the output is what we expected. + let expected_html: &str = + "

    Hello world, this is a complicated very simple example.

    \n"; + assert_eq!(expected_html, &html_output); + + // Write result to stdout. + println!("\nHTML output:\n{}", &html_output); +} diff --git a/vendor/pulldown-cmark-0.7.2/src/entities.rs b/vendor/pulldown-cmark-0.7.2/src/entities.rs new file mode 100644 index 0000000000..152342957f --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/entities.rs @@ -0,0 +1,2158 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Expansions of HTML5 entities + +// Autogenerated by mk_entities.py + +const ENTITIES: [(&[u8], &str); 2125] = [ + (b"AElig", "\u{00C6}"), + (b"AMP", "\u{0026}"), + (b"Aacute", "\u{00C1}"), + (b"Abreve", "\u{0102}"), + (b"Acirc", "\u{00C2}"), + (b"Acy", "\u{0410}"), + (b"Afr", "\u{1D504}"), + (b"Agrave", "\u{00C0}"), + (b"Alpha", "\u{0391}"), + (b"Amacr", "\u{0100}"), + (b"And", "\u{2A53}"), + (b"Aogon", "\u{0104}"), + (b"Aopf", "\u{1D538}"), + (b"ApplyFunction", "\u{2061}"), + (b"Aring", "\u{00C5}"), + (b"Ascr", "\u{1D49C}"), + (b"Assign", "\u{2254}"), + (b"Atilde", "\u{00C3}"), + (b"Auml", "\u{00C4}"), + (b"Backslash", "\u{2216}"), + (b"Barv", "\u{2AE7}"), + (b"Barwed", "\u{2306}"), + (b"Bcy", "\u{0411}"), + (b"Because", "\u{2235}"), + (b"Bernoullis", "\u{212C}"), + (b"Beta", "\u{0392}"), + (b"Bfr", "\u{1D505}"), + (b"Bopf", "\u{1D539}"), + (b"Breve", "\u{02D8}"), + (b"Bscr", "\u{212C}"), + (b"Bumpeq", "\u{224E}"), + (b"CHcy", "\u{0427}"), + (b"COPY", "\u{00A9}"), + (b"Cacute", "\u{0106}"), + (b"Cap", "\u{22D2}"), + (b"CapitalDifferentialD", "\u{2145}"), + (b"Cayleys", "\u{212D}"), + (b"Ccaron", "\u{010C}"), + (b"Ccedil", "\u{00C7}"), + (b"Ccirc", "\u{0108}"), + (b"Cconint", "\u{2230}"), + (b"Cdot", "\u{010A}"), + (b"Cedilla", "\u{00B8}"), + (b"CenterDot", "\u{00B7}"), + (b"Cfr", "\u{212D}"), + (b"Chi", "\u{03A7}"), + (b"CircleDot", "\u{2299}"), + (b"CircleMinus", "\u{2296}"), + (b"CirclePlus", "\u{2295}"), + (b"CircleTimes", "\u{2297}"), + (b"ClockwiseContourIntegral", "\u{2232}"), + (b"CloseCurlyDoubleQuote", "\u{201D}"), + (b"CloseCurlyQuote", "\u{2019}"), + (b"Colon", "\u{2237}"), + (b"Colone", "\u{2A74}"), + (b"Congruent", "\u{2261}"), + (b"Conint", "\u{222F}"), + (b"ContourIntegral", "\u{222E}"), + (b"Copf", "\u{2102}"), + (b"Coproduct", "\u{2210}"), + (b"CounterClockwiseContourIntegral", "\u{2233}"), + (b"Cross", "\u{2A2F}"), + (b"Cscr", "\u{1D49E}"), + (b"Cup", "\u{22D3}"), + (b"CupCap", "\u{224D}"), + (b"DD", "\u{2145}"), + (b"DDotrahd", "\u{2911}"), + (b"DJcy", "\u{0402}"), + (b"DScy", "\u{0405}"), + (b"DZcy", "\u{040F}"), + (b"Dagger", "\u{2021}"), + (b"Darr", "\u{21A1}"), + (b"Dashv", "\u{2AE4}"), + (b"Dcaron", "\u{010E}"), + (b"Dcy", "\u{0414}"), + (b"Del", "\u{2207}"), + (b"Delta", "\u{0394}"), + (b"Dfr", "\u{1D507}"), + (b"DiacriticalAcute", "\u{00B4}"), + (b"DiacriticalDot", "\u{02D9}"), + (b"DiacriticalDoubleAcute", "\u{02DD}"), + (b"DiacriticalGrave", "\u{0060}"), + (b"DiacriticalTilde", "\u{02DC}"), + (b"Diamond", "\u{22C4}"), + (b"DifferentialD", "\u{2146}"), + (b"Dopf", "\u{1D53B}"), + (b"Dot", "\u{00A8}"), + (b"DotDot", "\u{20DC}"), + (b"DotEqual", "\u{2250}"), + (b"DoubleContourIntegral", "\u{222F}"), + (b"DoubleDot", "\u{00A8}"), + (b"DoubleDownArrow", "\u{21D3}"), + (b"DoubleLeftArrow", "\u{21D0}"), + (b"DoubleLeftRightArrow", "\u{21D4}"), + (b"DoubleLeftTee", "\u{2AE4}"), + (b"DoubleLongLeftArrow", "\u{27F8}"), + (b"DoubleLongLeftRightArrow", "\u{27FA}"), + (b"DoubleLongRightArrow", "\u{27F9}"), + (b"DoubleRightArrow", "\u{21D2}"), + (b"DoubleRightTee", "\u{22A8}"), + (b"DoubleUpArrow", "\u{21D1}"), + (b"DoubleUpDownArrow", "\u{21D5}"), + (b"DoubleVerticalBar", "\u{2225}"), + (b"DownArrow", "\u{2193}"), + (b"DownArrowBar", "\u{2913}"), + (b"DownArrowUpArrow", "\u{21F5}"), + (b"DownBreve", "\u{0311}"), + (b"DownLeftRightVector", "\u{2950}"), + (b"DownLeftTeeVector", "\u{295E}"), + (b"DownLeftVector", "\u{21BD}"), + (b"DownLeftVectorBar", "\u{2956}"), + (b"DownRightTeeVector", "\u{295F}"), + (b"DownRightVector", "\u{21C1}"), + (b"DownRightVectorBar", "\u{2957}"), + (b"DownTee", "\u{22A4}"), + (b"DownTeeArrow", "\u{21A7}"), + (b"Downarrow", "\u{21D3}"), + (b"Dscr", "\u{1D49F}"), + (b"Dstrok", "\u{0110}"), + (b"ENG", "\u{014A}"), + (b"ETH", "\u{00D0}"), + (b"Eacute", "\u{00C9}"), + (b"Ecaron", "\u{011A}"), + (b"Ecirc", "\u{00CA}"), + (b"Ecy", "\u{042D}"), + (b"Edot", "\u{0116}"), + (b"Efr", "\u{1D508}"), + (b"Egrave", "\u{00C8}"), + (b"Element", "\u{2208}"), + (b"Emacr", "\u{0112}"), + (b"EmptySmallSquare", "\u{25FB}"), + (b"EmptyVerySmallSquare", "\u{25AB}"), + (b"Eogon", "\u{0118}"), + (b"Eopf", "\u{1D53C}"), + (b"Epsilon", "\u{0395}"), + (b"Equal", "\u{2A75}"), + (b"EqualTilde", "\u{2242}"), + (b"Equilibrium", "\u{21CC}"), + (b"Escr", "\u{2130}"), + (b"Esim", "\u{2A73}"), + (b"Eta", "\u{0397}"), + (b"Euml", "\u{00CB}"), + (b"Exists", "\u{2203}"), + (b"ExponentialE", "\u{2147}"), + (b"Fcy", "\u{0424}"), + (b"Ffr", "\u{1D509}"), + (b"FilledSmallSquare", "\u{25FC}"), + (b"FilledVerySmallSquare", "\u{25AA}"), + (b"Fopf", "\u{1D53D}"), + (b"ForAll", "\u{2200}"), + (b"Fouriertrf", "\u{2131}"), + (b"Fscr", "\u{2131}"), + (b"GJcy", "\u{0403}"), + (b"GT", "\u{003E}"), + (b"Gamma", "\u{0393}"), + (b"Gammad", "\u{03DC}"), + (b"Gbreve", "\u{011E}"), + (b"Gcedil", "\u{0122}"), + (b"Gcirc", "\u{011C}"), + (b"Gcy", "\u{0413}"), + (b"Gdot", "\u{0120}"), + (b"Gfr", "\u{1D50A}"), + (b"Gg", "\u{22D9}"), + (b"Gopf", "\u{1D53E}"), + (b"GreaterEqual", "\u{2265}"), + (b"GreaterEqualLess", "\u{22DB}"), + (b"GreaterFullEqual", "\u{2267}"), + (b"GreaterGreater", "\u{2AA2}"), + (b"GreaterLess", "\u{2277}"), + (b"GreaterSlantEqual", "\u{2A7E}"), + (b"GreaterTilde", "\u{2273}"), + (b"Gscr", "\u{1D4A2}"), + (b"Gt", "\u{226B}"), + (b"HARDcy", "\u{042A}"), + (b"Hacek", "\u{02C7}"), + (b"Hat", "\u{005E}"), + (b"Hcirc", "\u{0124}"), + (b"Hfr", "\u{210C}"), + (b"HilbertSpace", "\u{210B}"), + (b"Hopf", "\u{210D}"), + (b"HorizontalLine", "\u{2500}"), + (b"Hscr", "\u{210B}"), + (b"Hstrok", "\u{0126}"), + (b"HumpDownHump", "\u{224E}"), + (b"HumpEqual", "\u{224F}"), + (b"IEcy", "\u{0415}"), + (b"IJlig", "\u{0132}"), + (b"IOcy", "\u{0401}"), + (b"Iacute", "\u{00CD}"), + (b"Icirc", "\u{00CE}"), + (b"Icy", "\u{0418}"), + (b"Idot", "\u{0130}"), + (b"Ifr", "\u{2111}"), + (b"Igrave", "\u{00CC}"), + (b"Im", "\u{2111}"), + (b"Imacr", "\u{012A}"), + (b"ImaginaryI", "\u{2148}"), + (b"Implies", "\u{21D2}"), + (b"Int", "\u{222C}"), + (b"Integral", "\u{222B}"), + (b"Intersection", "\u{22C2}"), + (b"InvisibleComma", "\u{2063}"), + (b"InvisibleTimes", "\u{2062}"), + (b"Iogon", "\u{012E}"), + (b"Iopf", "\u{1D540}"), + (b"Iota", "\u{0399}"), + (b"Iscr", "\u{2110}"), + (b"Itilde", "\u{0128}"), + (b"Iukcy", "\u{0406}"), + (b"Iuml", "\u{00CF}"), + (b"Jcirc", "\u{0134}"), + (b"Jcy", "\u{0419}"), + (b"Jfr", "\u{1D50D}"), + (b"Jopf", "\u{1D541}"), + (b"Jscr", "\u{1D4A5}"), + (b"Jsercy", "\u{0408}"), + (b"Jukcy", "\u{0404}"), + (b"KHcy", "\u{0425}"), + (b"KJcy", "\u{040C}"), + (b"Kappa", "\u{039A}"), + (b"Kcedil", "\u{0136}"), + (b"Kcy", "\u{041A}"), + (b"Kfr", "\u{1D50E}"), + (b"Kopf", "\u{1D542}"), + (b"Kscr", "\u{1D4A6}"), + (b"LJcy", "\u{0409}"), + (b"LT", "\u{003C}"), + (b"Lacute", "\u{0139}"), + (b"Lambda", "\u{039B}"), + (b"Lang", "\u{27EA}"), + (b"Laplacetrf", "\u{2112}"), + (b"Larr", "\u{219E}"), + (b"Lcaron", "\u{013D}"), + (b"Lcedil", "\u{013B}"), + (b"Lcy", "\u{041B}"), + (b"LeftAngleBracket", "\u{27E8}"), + (b"LeftArrow", "\u{2190}"), + (b"LeftArrowBar", "\u{21E4}"), + (b"LeftArrowRightArrow", "\u{21C6}"), + (b"LeftCeiling", "\u{2308}"), + (b"LeftDoubleBracket", "\u{27E6}"), + (b"LeftDownTeeVector", "\u{2961}"), + (b"LeftDownVector", "\u{21C3}"), + (b"LeftDownVectorBar", "\u{2959}"), + (b"LeftFloor", "\u{230A}"), + (b"LeftRightArrow", "\u{2194}"), + (b"LeftRightVector", "\u{294E}"), + (b"LeftTee", "\u{22A3}"), + (b"LeftTeeArrow", "\u{21A4}"), + (b"LeftTeeVector", "\u{295A}"), + (b"LeftTriangle", "\u{22B2}"), + (b"LeftTriangleBar", "\u{29CF}"), + (b"LeftTriangleEqual", "\u{22B4}"), + (b"LeftUpDownVector", "\u{2951}"), + (b"LeftUpTeeVector", "\u{2960}"), + (b"LeftUpVector", "\u{21BF}"), + (b"LeftUpVectorBar", "\u{2958}"), + (b"LeftVector", "\u{21BC}"), + (b"LeftVectorBar", "\u{2952}"), + (b"Leftarrow", "\u{21D0}"), + (b"Leftrightarrow", "\u{21D4}"), + (b"LessEqualGreater", "\u{22DA}"), + (b"LessFullEqual", "\u{2266}"), + (b"LessGreater", "\u{2276}"), + (b"LessLess", "\u{2AA1}"), + (b"LessSlantEqual", "\u{2A7D}"), + (b"LessTilde", "\u{2272}"), + (b"Lfr", "\u{1D50F}"), + (b"Ll", "\u{22D8}"), + (b"Lleftarrow", "\u{21DA}"), + (b"Lmidot", "\u{013F}"), + (b"LongLeftArrow", "\u{27F5}"), + (b"LongLeftRightArrow", "\u{27F7}"), + (b"LongRightArrow", "\u{27F6}"), + (b"Longleftarrow", "\u{27F8}"), + (b"Longleftrightarrow", "\u{27FA}"), + (b"Longrightarrow", "\u{27F9}"), + (b"Lopf", "\u{1D543}"), + (b"LowerLeftArrow", "\u{2199}"), + (b"LowerRightArrow", "\u{2198}"), + (b"Lscr", "\u{2112}"), + (b"Lsh", "\u{21B0}"), + (b"Lstrok", "\u{0141}"), + (b"Lt", "\u{226A}"), + (b"Map", "\u{2905}"), + (b"Mcy", "\u{041C}"), + (b"MediumSpace", "\u{205F}"), + (b"Mellintrf", "\u{2133}"), + (b"Mfr", "\u{1D510}"), + (b"MinusPlus", "\u{2213}"), + (b"Mopf", "\u{1D544}"), + (b"Mscr", "\u{2133}"), + (b"Mu", "\u{039C}"), + (b"NJcy", "\u{040A}"), + (b"Nacute", "\u{0143}"), + (b"Ncaron", "\u{0147}"), + (b"Ncedil", "\u{0145}"), + (b"Ncy", "\u{041D}"), + (b"NegativeMediumSpace", "\u{200B}"), + (b"NegativeThickSpace", "\u{200B}"), + (b"NegativeThinSpace", "\u{200B}"), + (b"NegativeVeryThinSpace", "\u{200B}"), + (b"NestedGreaterGreater", "\u{226B}"), + (b"NestedLessLess", "\u{226A}"), + (b"NewLine", "\u{000A}"), + (b"Nfr", "\u{1D511}"), + (b"NoBreak", "\u{2060}"), + (b"NonBreakingSpace", "\u{00A0}"), + (b"Nopf", "\u{2115}"), + (b"Not", "\u{2AEC}"), + (b"NotCongruent", "\u{2262}"), + (b"NotCupCap", "\u{226D}"), + (b"NotDoubleVerticalBar", "\u{2226}"), + (b"NotElement", "\u{2209}"), + (b"NotEqual", "\u{2260}"), + (b"NotEqualTilde", "\u{2242}\u{0338}"), + (b"NotExists", "\u{2204}"), + (b"NotGreater", "\u{226F}"), + (b"NotGreaterEqual", "\u{2271}"), + (b"NotGreaterFullEqual", "\u{2267}\u{0338}"), + (b"NotGreaterGreater", "\u{226B}\u{0338}"), + (b"NotGreaterLess", "\u{2279}"), + (b"NotGreaterSlantEqual", "\u{2A7E}\u{0338}"), + (b"NotGreaterTilde", "\u{2275}"), + (b"NotHumpDownHump", "\u{224E}\u{0338}"), + (b"NotHumpEqual", "\u{224F}\u{0338}"), + (b"NotLeftTriangle", "\u{22EA}"), + (b"NotLeftTriangleBar", "\u{29CF}\u{0338}"), + (b"NotLeftTriangleEqual", "\u{22EC}"), + (b"NotLess", "\u{226E}"), + (b"NotLessEqual", "\u{2270}"), + (b"NotLessGreater", "\u{2278}"), + (b"NotLessLess", "\u{226A}\u{0338}"), + (b"NotLessSlantEqual", "\u{2A7D}\u{0338}"), + (b"NotLessTilde", "\u{2274}"), + (b"NotNestedGreaterGreater", "\u{2AA2}\u{0338}"), + (b"NotNestedLessLess", "\u{2AA1}\u{0338}"), + (b"NotPrecedes", "\u{2280}"), + (b"NotPrecedesEqual", "\u{2AAF}\u{0338}"), + (b"NotPrecedesSlantEqual", "\u{22E0}"), + (b"NotReverseElement", "\u{220C}"), + (b"NotRightTriangle", "\u{22EB}"), + (b"NotRightTriangleBar", "\u{29D0}\u{0338}"), + (b"NotRightTriangleEqual", "\u{22ED}"), + (b"NotSquareSubset", "\u{228F}\u{0338}"), + (b"NotSquareSubsetEqual", "\u{22E2}"), + (b"NotSquareSuperset", "\u{2290}\u{0338}"), + (b"NotSquareSupersetEqual", "\u{22E3}"), + (b"NotSubset", "\u{2282}\u{20D2}"), + (b"NotSubsetEqual", "\u{2288}"), + (b"NotSucceeds", "\u{2281}"), + (b"NotSucceedsEqual", "\u{2AB0}\u{0338}"), + (b"NotSucceedsSlantEqual", "\u{22E1}"), + (b"NotSucceedsTilde", "\u{227F}\u{0338}"), + (b"NotSuperset", "\u{2283}\u{20D2}"), + (b"NotSupersetEqual", "\u{2289}"), + (b"NotTilde", "\u{2241}"), + (b"NotTildeEqual", "\u{2244}"), + (b"NotTildeFullEqual", "\u{2247}"), + (b"NotTildeTilde", "\u{2249}"), + (b"NotVerticalBar", "\u{2224}"), + (b"Nscr", "\u{1D4A9}"), + (b"Ntilde", "\u{00D1}"), + (b"Nu", "\u{039D}"), + (b"OElig", "\u{0152}"), + (b"Oacute", "\u{00D3}"), + (b"Ocirc", "\u{00D4}"), + (b"Ocy", "\u{041E}"), + (b"Odblac", "\u{0150}"), + (b"Ofr", "\u{1D512}"), + (b"Ograve", "\u{00D2}"), + (b"Omacr", "\u{014C}"), + (b"Omega", "\u{03A9}"), + (b"Omicron", "\u{039F}"), + (b"Oopf", "\u{1D546}"), + (b"OpenCurlyDoubleQuote", "\u{201C}"), + (b"OpenCurlyQuote", "\u{2018}"), + (b"Or", "\u{2A54}"), + (b"Oscr", "\u{1D4AA}"), + (b"Oslash", "\u{00D8}"), + (b"Otilde", "\u{00D5}"), + (b"Otimes", "\u{2A37}"), + (b"Ouml", "\u{00D6}"), + (b"OverBar", "\u{203E}"), + (b"OverBrace", "\u{23DE}"), + (b"OverBracket", "\u{23B4}"), + (b"OverParenthesis", "\u{23DC}"), + (b"PartialD", "\u{2202}"), + (b"Pcy", "\u{041F}"), + (b"Pfr", "\u{1D513}"), + (b"Phi", "\u{03A6}"), + (b"Pi", "\u{03A0}"), + (b"PlusMinus", "\u{00B1}"), + (b"Poincareplane", "\u{210C}"), + (b"Popf", "\u{2119}"), + (b"Pr", "\u{2ABB}"), + (b"Precedes", "\u{227A}"), + (b"PrecedesEqual", "\u{2AAF}"), + (b"PrecedesSlantEqual", "\u{227C}"), + (b"PrecedesTilde", "\u{227E}"), + (b"Prime", "\u{2033}"), + (b"Product", "\u{220F}"), + (b"Proportion", "\u{2237}"), + (b"Proportional", "\u{221D}"), + (b"Pscr", "\u{1D4AB}"), + (b"Psi", "\u{03A8}"), + (b"QUOT", "\u{0022}"), + (b"Qfr", "\u{1D514}"), + (b"Qopf", "\u{211A}"), + (b"Qscr", "\u{1D4AC}"), + (b"RBarr", "\u{2910}"), + (b"REG", "\u{00AE}"), + (b"Racute", "\u{0154}"), + (b"Rang", "\u{27EB}"), + (b"Rarr", "\u{21A0}"), + (b"Rarrtl", "\u{2916}"), + (b"Rcaron", "\u{0158}"), + (b"Rcedil", "\u{0156}"), + (b"Rcy", "\u{0420}"), + (b"Re", "\u{211C}"), + (b"ReverseElement", "\u{220B}"), + (b"ReverseEquilibrium", "\u{21CB}"), + (b"ReverseUpEquilibrium", "\u{296F}"), + (b"Rfr", "\u{211C}"), + (b"Rho", "\u{03A1}"), + (b"RightAngleBracket", "\u{27E9}"), + (b"RightArrow", "\u{2192}"), + (b"RightArrowBar", "\u{21E5}"), + (b"RightArrowLeftArrow", "\u{21C4}"), + (b"RightCeiling", "\u{2309}"), + (b"RightDoubleBracket", "\u{27E7}"), + (b"RightDownTeeVector", "\u{295D}"), + (b"RightDownVector", "\u{21C2}"), + (b"RightDownVectorBar", "\u{2955}"), + (b"RightFloor", "\u{230B}"), + (b"RightTee", "\u{22A2}"), + (b"RightTeeArrow", "\u{21A6}"), + (b"RightTeeVector", "\u{295B}"), + (b"RightTriangle", "\u{22B3}"), + (b"RightTriangleBar", "\u{29D0}"), + (b"RightTriangleEqual", "\u{22B5}"), + (b"RightUpDownVector", "\u{294F}"), + (b"RightUpTeeVector", "\u{295C}"), + (b"RightUpVector", "\u{21BE}"), + (b"RightUpVectorBar", "\u{2954}"), + (b"RightVector", "\u{21C0}"), + (b"RightVectorBar", "\u{2953}"), + (b"Rightarrow", "\u{21D2}"), + (b"Ropf", "\u{211D}"), + (b"RoundImplies", "\u{2970}"), + (b"Rrightarrow", "\u{21DB}"), + (b"Rscr", "\u{211B}"), + (b"Rsh", "\u{21B1}"), + (b"RuleDelayed", "\u{29F4}"), + (b"SHCHcy", "\u{0429}"), + (b"SHcy", "\u{0428}"), + (b"SOFTcy", "\u{042C}"), + (b"Sacute", "\u{015A}"), + (b"Sc", "\u{2ABC}"), + (b"Scaron", "\u{0160}"), + (b"Scedil", "\u{015E}"), + (b"Scirc", "\u{015C}"), + (b"Scy", "\u{0421}"), + (b"Sfr", "\u{1D516}"), + (b"ShortDownArrow", "\u{2193}"), + (b"ShortLeftArrow", "\u{2190}"), + (b"ShortRightArrow", "\u{2192}"), + (b"ShortUpArrow", "\u{2191}"), + (b"Sigma", "\u{03A3}"), + (b"SmallCircle", "\u{2218}"), + (b"Sopf", "\u{1D54A}"), + (b"Sqrt", "\u{221A}"), + (b"Square", "\u{25A1}"), + (b"SquareIntersection", "\u{2293}"), + (b"SquareSubset", "\u{228F}"), + (b"SquareSubsetEqual", "\u{2291}"), + (b"SquareSuperset", "\u{2290}"), + (b"SquareSupersetEqual", "\u{2292}"), + (b"SquareUnion", "\u{2294}"), + (b"Sscr", "\u{1D4AE}"), + (b"Star", "\u{22C6}"), + (b"Sub", "\u{22D0}"), + (b"Subset", "\u{22D0}"), + (b"SubsetEqual", "\u{2286}"), + (b"Succeeds", "\u{227B}"), + (b"SucceedsEqual", "\u{2AB0}"), + (b"SucceedsSlantEqual", "\u{227D}"), + (b"SucceedsTilde", "\u{227F}"), + (b"SuchThat", "\u{220B}"), + (b"Sum", "\u{2211}"), + (b"Sup", "\u{22D1}"), + (b"Superset", "\u{2283}"), + (b"SupersetEqual", "\u{2287}"), + (b"Supset", "\u{22D1}"), + (b"THORN", "\u{00DE}"), + (b"TRADE", "\u{2122}"), + (b"TSHcy", "\u{040B}"), + (b"TScy", "\u{0426}"), + (b"Tab", "\u{0009}"), + (b"Tau", "\u{03A4}"), + (b"Tcaron", "\u{0164}"), + (b"Tcedil", "\u{0162}"), + (b"Tcy", "\u{0422}"), + (b"Tfr", "\u{1D517}"), + (b"Therefore", "\u{2234}"), + (b"Theta", "\u{0398}"), + (b"ThickSpace", "\u{205F}\u{200A}"), + (b"ThinSpace", "\u{2009}"), + (b"Tilde", "\u{223C}"), + (b"TildeEqual", "\u{2243}"), + (b"TildeFullEqual", "\u{2245}"), + (b"TildeTilde", "\u{2248}"), + (b"Topf", "\u{1D54B}"), + (b"TripleDot", "\u{20DB}"), + (b"Tscr", "\u{1D4AF}"), + (b"Tstrok", "\u{0166}"), + (b"Uacute", "\u{00DA}"), + (b"Uarr", "\u{219F}"), + (b"Uarrocir", "\u{2949}"), + (b"Ubrcy", "\u{040E}"), + (b"Ubreve", "\u{016C}"), + (b"Ucirc", "\u{00DB}"), + (b"Ucy", "\u{0423}"), + (b"Udblac", "\u{0170}"), + (b"Ufr", "\u{1D518}"), + (b"Ugrave", "\u{00D9}"), + (b"Umacr", "\u{016A}"), + (b"UnderBar", "\u{005F}"), + (b"UnderBrace", "\u{23DF}"), + (b"UnderBracket", "\u{23B5}"), + (b"UnderParenthesis", "\u{23DD}"), + (b"Union", "\u{22C3}"), + (b"UnionPlus", "\u{228E}"), + (b"Uogon", "\u{0172}"), + (b"Uopf", "\u{1D54C}"), + (b"UpArrow", "\u{2191}"), + (b"UpArrowBar", "\u{2912}"), + (b"UpArrowDownArrow", "\u{21C5}"), + (b"UpDownArrow", "\u{2195}"), + (b"UpEquilibrium", "\u{296E}"), + (b"UpTee", "\u{22A5}"), + (b"UpTeeArrow", "\u{21A5}"), + (b"Uparrow", "\u{21D1}"), + (b"Updownarrow", "\u{21D5}"), + (b"UpperLeftArrow", "\u{2196}"), + (b"UpperRightArrow", "\u{2197}"), + (b"Upsi", "\u{03D2}"), + (b"Upsilon", "\u{03A5}"), + (b"Uring", "\u{016E}"), + (b"Uscr", "\u{1D4B0}"), + (b"Utilde", "\u{0168}"), + (b"Uuml", "\u{00DC}"), + (b"VDash", "\u{22AB}"), + (b"Vbar", "\u{2AEB}"), + (b"Vcy", "\u{0412}"), + (b"Vdash", "\u{22A9}"), + (b"Vdashl", "\u{2AE6}"), + (b"Vee", "\u{22C1}"), + (b"Verbar", "\u{2016}"), + (b"Vert", "\u{2016}"), + (b"VerticalBar", "\u{2223}"), + (b"VerticalLine", "\u{007C}"), + (b"VerticalSeparator", "\u{2758}"), + (b"VerticalTilde", "\u{2240}"), + (b"VeryThinSpace", "\u{200A}"), + (b"Vfr", "\u{1D519}"), + (b"Vopf", "\u{1D54D}"), + (b"Vscr", "\u{1D4B1}"), + (b"Vvdash", "\u{22AA}"), + (b"Wcirc", "\u{0174}"), + (b"Wedge", "\u{22C0}"), + (b"Wfr", "\u{1D51A}"), + (b"Wopf", "\u{1D54E}"), + (b"Wscr", "\u{1D4B2}"), + (b"Xfr", "\u{1D51B}"), + (b"Xi", "\u{039E}"), + (b"Xopf", "\u{1D54F}"), + (b"Xscr", "\u{1D4B3}"), + (b"YAcy", "\u{042F}"), + (b"YIcy", "\u{0407}"), + (b"YUcy", "\u{042E}"), + (b"Yacute", "\u{00DD}"), + (b"Ycirc", "\u{0176}"), + (b"Ycy", "\u{042B}"), + (b"Yfr", "\u{1D51C}"), + (b"Yopf", "\u{1D550}"), + (b"Yscr", "\u{1D4B4}"), + (b"Yuml", "\u{0178}"), + (b"ZHcy", "\u{0416}"), + (b"Zacute", "\u{0179}"), + (b"Zcaron", "\u{017D}"), + (b"Zcy", "\u{0417}"), + (b"Zdot", "\u{017B}"), + (b"ZeroWidthSpace", "\u{200B}"), + (b"Zeta", "\u{0396}"), + (b"Zfr", "\u{2128}"), + (b"Zopf", "\u{2124}"), + (b"Zscr", "\u{1D4B5}"), + (b"aacute", "\u{00E1}"), + (b"abreve", "\u{0103}"), + (b"ac", "\u{223E}"), + (b"acE", "\u{223E}\u{0333}"), + (b"acd", "\u{223F}"), + (b"acirc", "\u{00E2}"), + (b"acute", "\u{00B4}"), + (b"acy", "\u{0430}"), + (b"aelig", "\u{00E6}"), + (b"af", "\u{2061}"), + (b"afr", "\u{1D51E}"), + (b"agrave", "\u{00E0}"), + (b"alefsym", "\u{2135}"), + (b"aleph", "\u{2135}"), + (b"alpha", "\u{03B1}"), + (b"amacr", "\u{0101}"), + (b"amalg", "\u{2A3F}"), + (b"amp", "\u{0026}"), + (b"and", "\u{2227}"), + (b"andand", "\u{2A55}"), + (b"andd", "\u{2A5C}"), + (b"andslope", "\u{2A58}"), + (b"andv", "\u{2A5A}"), + (b"ang", "\u{2220}"), + (b"ange", "\u{29A4}"), + (b"angle", "\u{2220}"), + (b"angmsd", "\u{2221}"), + (b"angmsdaa", "\u{29A8}"), + (b"angmsdab", "\u{29A9}"), + (b"angmsdac", "\u{29AA}"), + (b"angmsdad", "\u{29AB}"), + (b"angmsdae", "\u{29AC}"), + (b"angmsdaf", "\u{29AD}"), + (b"angmsdag", "\u{29AE}"), + (b"angmsdah", "\u{29AF}"), + (b"angrt", "\u{221F}"), + (b"angrtvb", "\u{22BE}"), + (b"angrtvbd", "\u{299D}"), + (b"angsph", "\u{2222}"), + (b"angst", "\u{00C5}"), + (b"angzarr", "\u{237C}"), + (b"aogon", "\u{0105}"), + (b"aopf", "\u{1D552}"), + (b"ap", "\u{2248}"), + (b"apE", "\u{2A70}"), + (b"apacir", "\u{2A6F}"), + (b"ape", "\u{224A}"), + (b"apid", "\u{224B}"), + (b"apos", "\u{0027}"), + (b"approx", "\u{2248}"), + (b"approxeq", "\u{224A}"), + (b"aring", "\u{00E5}"), + (b"ascr", "\u{1D4B6}"), + (b"ast", "\u{002A}"), + (b"asymp", "\u{2248}"), + (b"asympeq", "\u{224D}"), + (b"atilde", "\u{00E3}"), + (b"auml", "\u{00E4}"), + (b"awconint", "\u{2233}"), + (b"awint", "\u{2A11}"), + (b"bNot", "\u{2AED}"), + (b"backcong", "\u{224C}"), + (b"backepsilon", "\u{03F6}"), + (b"backprime", "\u{2035}"), + (b"backsim", "\u{223D}"), + (b"backsimeq", "\u{22CD}"), + (b"barvee", "\u{22BD}"), + (b"barwed", "\u{2305}"), + (b"barwedge", "\u{2305}"), + (b"bbrk", "\u{23B5}"), + (b"bbrktbrk", "\u{23B6}"), + (b"bcong", "\u{224C}"), + (b"bcy", "\u{0431}"), + (b"bdquo", "\u{201E}"), + (b"becaus", "\u{2235}"), + (b"because", "\u{2235}"), + (b"bemptyv", "\u{29B0}"), + (b"bepsi", "\u{03F6}"), + (b"bernou", "\u{212C}"), + (b"beta", "\u{03B2}"), + (b"beth", "\u{2136}"), + (b"between", "\u{226C}"), + (b"bfr", "\u{1D51F}"), + (b"bigcap", "\u{22C2}"), + (b"bigcirc", "\u{25EF}"), + (b"bigcup", "\u{22C3}"), + (b"bigodot", "\u{2A00}"), + (b"bigoplus", "\u{2A01}"), + (b"bigotimes", "\u{2A02}"), + (b"bigsqcup", "\u{2A06}"), + (b"bigstar", "\u{2605}"), + (b"bigtriangledown", "\u{25BD}"), + (b"bigtriangleup", "\u{25B3}"), + (b"biguplus", "\u{2A04}"), + (b"bigvee", "\u{22C1}"), + (b"bigwedge", "\u{22C0}"), + (b"bkarow", "\u{290D}"), + (b"blacklozenge", "\u{29EB}"), + (b"blacksquare", "\u{25AA}"), + (b"blacktriangle", "\u{25B4}"), + (b"blacktriangledown", "\u{25BE}"), + (b"blacktriangleleft", "\u{25C2}"), + (b"blacktriangleright", "\u{25B8}"), + (b"blank", "\u{2423}"), + (b"blk12", "\u{2592}"), + (b"blk14", "\u{2591}"), + (b"blk34", "\u{2593}"), + (b"block", "\u{2588}"), + (b"bne", "\u{003D}\u{20E5}"), + (b"bnequiv", "\u{2261}\u{20E5}"), + (b"bnot", "\u{2310}"), + (b"bopf", "\u{1D553}"), + (b"bot", "\u{22A5}"), + (b"bottom", "\u{22A5}"), + (b"bowtie", "\u{22C8}"), + (b"boxDL", "\u{2557}"), + (b"boxDR", "\u{2554}"), + (b"boxDl", "\u{2556}"), + (b"boxDr", "\u{2553}"), + (b"boxH", "\u{2550}"), + (b"boxHD", "\u{2566}"), + (b"boxHU", "\u{2569}"), + (b"boxHd", "\u{2564}"), + (b"boxHu", "\u{2567}"), + (b"boxUL", "\u{255D}"), + (b"boxUR", "\u{255A}"), + (b"boxUl", "\u{255C}"), + (b"boxUr", "\u{2559}"), + (b"boxV", "\u{2551}"), + (b"boxVH", "\u{256C}"), + (b"boxVL", "\u{2563}"), + (b"boxVR", "\u{2560}"), + (b"boxVh", "\u{256B}"), + (b"boxVl", "\u{2562}"), + (b"boxVr", "\u{255F}"), + (b"boxbox", "\u{29C9}"), + (b"boxdL", "\u{2555}"), + (b"boxdR", "\u{2552}"), + (b"boxdl", "\u{2510}"), + (b"boxdr", "\u{250C}"), + (b"boxh", "\u{2500}"), + (b"boxhD", "\u{2565}"), + (b"boxhU", "\u{2568}"), + (b"boxhd", "\u{252C}"), + (b"boxhu", "\u{2534}"), + (b"boxminus", "\u{229F}"), + (b"boxplus", "\u{229E}"), + (b"boxtimes", "\u{22A0}"), + (b"boxuL", "\u{255B}"), + (b"boxuR", "\u{2558}"), + (b"boxul", "\u{2518}"), + (b"boxur", "\u{2514}"), + (b"boxv", "\u{2502}"), + (b"boxvH", "\u{256A}"), + (b"boxvL", "\u{2561}"), + (b"boxvR", "\u{255E}"), + (b"boxvh", "\u{253C}"), + (b"boxvl", "\u{2524}"), + (b"boxvr", "\u{251C}"), + (b"bprime", "\u{2035}"), + (b"breve", "\u{02D8}"), + (b"brvbar", "\u{00A6}"), + (b"bscr", "\u{1D4B7}"), + (b"bsemi", "\u{204F}"), + (b"bsim", "\u{223D}"), + (b"bsime", "\u{22CD}"), + (b"bsol", "\u{005C}"), + (b"bsolb", "\u{29C5}"), + (b"bsolhsub", "\u{27C8}"), + (b"bull", "\u{2022}"), + (b"bullet", "\u{2022}"), + (b"bump", "\u{224E}"), + (b"bumpE", "\u{2AAE}"), + (b"bumpe", "\u{224F}"), + (b"bumpeq", "\u{224F}"), + (b"cacute", "\u{0107}"), + (b"cap", "\u{2229}"), + (b"capand", "\u{2A44}"), + (b"capbrcup", "\u{2A49}"), + (b"capcap", "\u{2A4B}"), + (b"capcup", "\u{2A47}"), + (b"capdot", "\u{2A40}"), + (b"caps", "\u{2229}\u{FE00}"), + (b"caret", "\u{2041}"), + (b"caron", "\u{02C7}"), + (b"ccaps", "\u{2A4D}"), + (b"ccaron", "\u{010D}"), + (b"ccedil", "\u{00E7}"), + (b"ccirc", "\u{0109}"), + (b"ccups", "\u{2A4C}"), + (b"ccupssm", "\u{2A50}"), + (b"cdot", "\u{010B}"), + (b"cedil", "\u{00B8}"), + (b"cemptyv", "\u{29B2}"), + (b"cent", "\u{00A2}"), + (b"centerdot", "\u{00B7}"), + (b"cfr", "\u{1D520}"), + (b"chcy", "\u{0447}"), + (b"check", "\u{2713}"), + (b"checkmark", "\u{2713}"), + (b"chi", "\u{03C7}"), + (b"cir", "\u{25CB}"), + (b"cirE", "\u{29C3}"), + (b"circ", "\u{02C6}"), + (b"circeq", "\u{2257}"), + (b"circlearrowleft", "\u{21BA}"), + (b"circlearrowright", "\u{21BB}"), + (b"circledR", "\u{00AE}"), + (b"circledS", "\u{24C8}"), + (b"circledast", "\u{229B}"), + (b"circledcirc", "\u{229A}"), + (b"circleddash", "\u{229D}"), + (b"cire", "\u{2257}"), + (b"cirfnint", "\u{2A10}"), + (b"cirmid", "\u{2AEF}"), + (b"cirscir", "\u{29C2}"), + (b"clubs", "\u{2663}"), + (b"clubsuit", "\u{2663}"), + (b"colon", "\u{003A}"), + (b"colone", "\u{2254}"), + (b"coloneq", "\u{2254}"), + (b"comma", "\u{002C}"), + (b"commat", "\u{0040}"), + (b"comp", "\u{2201}"), + (b"compfn", "\u{2218}"), + (b"complement", "\u{2201}"), + (b"complexes", "\u{2102}"), + (b"cong", "\u{2245}"), + (b"congdot", "\u{2A6D}"), + (b"conint", "\u{222E}"), + (b"copf", "\u{1D554}"), + (b"coprod", "\u{2210}"), + (b"copy", "\u{00A9}"), + (b"copysr", "\u{2117}"), + (b"crarr", "\u{21B5}"), + (b"cross", "\u{2717}"), + (b"cscr", "\u{1D4B8}"), + (b"csub", "\u{2ACF}"), + (b"csube", "\u{2AD1}"), + (b"csup", "\u{2AD0}"), + (b"csupe", "\u{2AD2}"), + (b"ctdot", "\u{22EF}"), + (b"cudarrl", "\u{2938}"), + (b"cudarrr", "\u{2935}"), + (b"cuepr", "\u{22DE}"), + (b"cuesc", "\u{22DF}"), + (b"cularr", "\u{21B6}"), + (b"cularrp", "\u{293D}"), + (b"cup", "\u{222A}"), + (b"cupbrcap", "\u{2A48}"), + (b"cupcap", "\u{2A46}"), + (b"cupcup", "\u{2A4A}"), + (b"cupdot", "\u{228D}"), + (b"cupor", "\u{2A45}"), + (b"cups", "\u{222A}\u{FE00}"), + (b"curarr", "\u{21B7}"), + (b"curarrm", "\u{293C}"), + (b"curlyeqprec", "\u{22DE}"), + (b"curlyeqsucc", "\u{22DF}"), + (b"curlyvee", "\u{22CE}"), + (b"curlywedge", "\u{22CF}"), + (b"curren", "\u{00A4}"), + (b"curvearrowleft", "\u{21B6}"), + (b"curvearrowright", "\u{21B7}"), + (b"cuvee", "\u{22CE}"), + (b"cuwed", "\u{22CF}"), + (b"cwconint", "\u{2232}"), + (b"cwint", "\u{2231}"), + (b"cylcty", "\u{232D}"), + (b"dArr", "\u{21D3}"), + (b"dHar", "\u{2965}"), + (b"dagger", "\u{2020}"), + (b"daleth", "\u{2138}"), + (b"darr", "\u{2193}"), + (b"dash", "\u{2010}"), + (b"dashv", "\u{22A3}"), + (b"dbkarow", "\u{290F}"), + (b"dblac", "\u{02DD}"), + (b"dcaron", "\u{010F}"), + (b"dcy", "\u{0434}"), + (b"dd", "\u{2146}"), + (b"ddagger", "\u{2021}"), + (b"ddarr", "\u{21CA}"), + (b"ddotseq", "\u{2A77}"), + (b"deg", "\u{00B0}"), + (b"delta", "\u{03B4}"), + (b"demptyv", "\u{29B1}"), + (b"dfisht", "\u{297F}"), + (b"dfr", "\u{1D521}"), + (b"dharl", "\u{21C3}"), + (b"dharr", "\u{21C2}"), + (b"diam", "\u{22C4}"), + (b"diamond", "\u{22C4}"), + (b"diamondsuit", "\u{2666}"), + (b"diams", "\u{2666}"), + (b"die", "\u{00A8}"), + (b"digamma", "\u{03DD}"), + (b"disin", "\u{22F2}"), + (b"div", "\u{00F7}"), + (b"divide", "\u{00F7}"), + (b"divideontimes", "\u{22C7}"), + (b"divonx", "\u{22C7}"), + (b"djcy", "\u{0452}"), + (b"dlcorn", "\u{231E}"), + (b"dlcrop", "\u{230D}"), + (b"dollar", "\u{0024}"), + (b"dopf", "\u{1D555}"), + (b"dot", "\u{02D9}"), + (b"doteq", "\u{2250}"), + (b"doteqdot", "\u{2251}"), + (b"dotminus", "\u{2238}"), + (b"dotplus", "\u{2214}"), + (b"dotsquare", "\u{22A1}"), + (b"doublebarwedge", "\u{2306}"), + (b"downarrow", "\u{2193}"), + (b"downdownarrows", "\u{21CA}"), + (b"downharpoonleft", "\u{21C3}"), + (b"downharpoonright", "\u{21C2}"), + (b"drbkarow", "\u{2910}"), + (b"drcorn", "\u{231F}"), + (b"drcrop", "\u{230C}"), + (b"dscr", "\u{1D4B9}"), + (b"dscy", "\u{0455}"), + (b"dsol", "\u{29F6}"), + (b"dstrok", "\u{0111}"), + (b"dtdot", "\u{22F1}"), + (b"dtri", "\u{25BF}"), + (b"dtrif", "\u{25BE}"), + (b"duarr", "\u{21F5}"), + (b"duhar", "\u{296F}"), + (b"dwangle", "\u{29A6}"), + (b"dzcy", "\u{045F}"), + (b"dzigrarr", "\u{27FF}"), + (b"eDDot", "\u{2A77}"), + (b"eDot", "\u{2251}"), + (b"eacute", "\u{00E9}"), + (b"easter", "\u{2A6E}"), + (b"ecaron", "\u{011B}"), + (b"ecir", "\u{2256}"), + (b"ecirc", "\u{00EA}"), + (b"ecolon", "\u{2255}"), + (b"ecy", "\u{044D}"), + (b"edot", "\u{0117}"), + (b"ee", "\u{2147}"), + (b"efDot", "\u{2252}"), + (b"efr", "\u{1D522}"), + (b"eg", "\u{2A9A}"), + (b"egrave", "\u{00E8}"), + (b"egs", "\u{2A96}"), + (b"egsdot", "\u{2A98}"), + (b"el", "\u{2A99}"), + (b"elinters", "\u{23E7}"), + (b"ell", "\u{2113}"), + (b"els", "\u{2A95}"), + (b"elsdot", "\u{2A97}"), + (b"emacr", "\u{0113}"), + (b"empty", "\u{2205}"), + (b"emptyset", "\u{2205}"), + (b"emptyv", "\u{2205}"), + (b"emsp", "\u{2003}"), + (b"emsp13", "\u{2004}"), + (b"emsp14", "\u{2005}"), + (b"eng", "\u{014B}"), + (b"ensp", "\u{2002}"), + (b"eogon", "\u{0119}"), + (b"eopf", "\u{1D556}"), + (b"epar", "\u{22D5}"), + (b"eparsl", "\u{29E3}"), + (b"eplus", "\u{2A71}"), + (b"epsi", "\u{03B5}"), + (b"epsilon", "\u{03B5}"), + (b"epsiv", "\u{03F5}"), + (b"eqcirc", "\u{2256}"), + (b"eqcolon", "\u{2255}"), + (b"eqsim", "\u{2242}"), + (b"eqslantgtr", "\u{2A96}"), + (b"eqslantless", "\u{2A95}"), + (b"equals", "\u{003D}"), + (b"equest", "\u{225F}"), + (b"equiv", "\u{2261}"), + (b"equivDD", "\u{2A78}"), + (b"eqvparsl", "\u{29E5}"), + (b"erDot", "\u{2253}"), + (b"erarr", "\u{2971}"), + (b"escr", "\u{212F}"), + (b"esdot", "\u{2250}"), + (b"esim", "\u{2242}"), + (b"eta", "\u{03B7}"), + (b"eth", "\u{00F0}"), + (b"euml", "\u{00EB}"), + (b"euro", "\u{20AC}"), + (b"excl", "\u{0021}"), + (b"exist", "\u{2203}"), + (b"expectation", "\u{2130}"), + (b"exponentiale", "\u{2147}"), + (b"fallingdotseq", "\u{2252}"), + (b"fcy", "\u{0444}"), + (b"female", "\u{2640}"), + (b"ffilig", "\u{FB03}"), + (b"fflig", "\u{FB00}"), + (b"ffllig", "\u{FB04}"), + (b"ffr", "\u{1D523}"), + (b"filig", "\u{FB01}"), + (b"fjlig", "\u{0066}\u{006A}"), + (b"flat", "\u{266D}"), + (b"fllig", "\u{FB02}"), + (b"fltns", "\u{25B1}"), + (b"fnof", "\u{0192}"), + (b"fopf", "\u{1D557}"), + (b"forall", "\u{2200}"), + (b"fork", "\u{22D4}"), + (b"forkv", "\u{2AD9}"), + (b"fpartint", "\u{2A0D}"), + (b"frac12", "\u{00BD}"), + (b"frac13", "\u{2153}"), + (b"frac14", "\u{00BC}"), + (b"frac15", "\u{2155}"), + (b"frac16", "\u{2159}"), + (b"frac18", "\u{215B}"), + (b"frac23", "\u{2154}"), + (b"frac25", "\u{2156}"), + (b"frac34", "\u{00BE}"), + (b"frac35", "\u{2157}"), + (b"frac38", "\u{215C}"), + (b"frac45", "\u{2158}"), + (b"frac56", "\u{215A}"), + (b"frac58", "\u{215D}"), + (b"frac78", "\u{215E}"), + (b"frasl", "\u{2044}"), + (b"frown", "\u{2322}"), + (b"fscr", "\u{1D4BB}"), + (b"gE", "\u{2267}"), + (b"gEl", "\u{2A8C}"), + (b"gacute", "\u{01F5}"), + (b"gamma", "\u{03B3}"), + (b"gammad", "\u{03DD}"), + (b"gap", "\u{2A86}"), + (b"gbreve", "\u{011F}"), + (b"gcirc", "\u{011D}"), + (b"gcy", "\u{0433}"), + (b"gdot", "\u{0121}"), + (b"ge", "\u{2265}"), + (b"gel", "\u{22DB}"), + (b"geq", "\u{2265}"), + (b"geqq", "\u{2267}"), + (b"geqslant", "\u{2A7E}"), + (b"ges", "\u{2A7E}"), + (b"gescc", "\u{2AA9}"), + (b"gesdot", "\u{2A80}"), + (b"gesdoto", "\u{2A82}"), + (b"gesdotol", "\u{2A84}"), + (b"gesl", "\u{22DB}\u{FE00}"), + (b"gesles", "\u{2A94}"), + (b"gfr", "\u{1D524}"), + (b"gg", "\u{226B}"), + (b"ggg", "\u{22D9}"), + (b"gimel", "\u{2137}"), + (b"gjcy", "\u{0453}"), + (b"gl", "\u{2277}"), + (b"glE", "\u{2A92}"), + (b"gla", "\u{2AA5}"), + (b"glj", "\u{2AA4}"), + (b"gnE", "\u{2269}"), + (b"gnap", "\u{2A8A}"), + (b"gnapprox", "\u{2A8A}"), + (b"gne", "\u{2A88}"), + (b"gneq", "\u{2A88}"), + (b"gneqq", "\u{2269}"), + (b"gnsim", "\u{22E7}"), + (b"gopf", "\u{1D558}"), + (b"grave", "\u{0060}"), + (b"gscr", "\u{210A}"), + (b"gsim", "\u{2273}"), + (b"gsime", "\u{2A8E}"), + (b"gsiml", "\u{2A90}"), + (b"gt", "\u{003E}"), + (b"gtcc", "\u{2AA7}"), + (b"gtcir", "\u{2A7A}"), + (b"gtdot", "\u{22D7}"), + (b"gtlPar", "\u{2995}"), + (b"gtquest", "\u{2A7C}"), + (b"gtrapprox", "\u{2A86}"), + (b"gtrarr", "\u{2978}"), + (b"gtrdot", "\u{22D7}"), + (b"gtreqless", "\u{22DB}"), + (b"gtreqqless", "\u{2A8C}"), + (b"gtrless", "\u{2277}"), + (b"gtrsim", "\u{2273}"), + (b"gvertneqq", "\u{2269}\u{FE00}"), + (b"gvnE", "\u{2269}\u{FE00}"), + (b"hArr", "\u{21D4}"), + (b"hairsp", "\u{200A}"), + (b"half", "\u{00BD}"), + (b"hamilt", "\u{210B}"), + (b"hardcy", "\u{044A}"), + (b"harr", "\u{2194}"), + (b"harrcir", "\u{2948}"), + (b"harrw", "\u{21AD}"), + (b"hbar", "\u{210F}"), + (b"hcirc", "\u{0125}"), + (b"hearts", "\u{2665}"), + (b"heartsuit", "\u{2665}"), + (b"hellip", "\u{2026}"), + (b"hercon", "\u{22B9}"), + (b"hfr", "\u{1D525}"), + (b"hksearow", "\u{2925}"), + (b"hkswarow", "\u{2926}"), + (b"hoarr", "\u{21FF}"), + (b"homtht", "\u{223B}"), + (b"hookleftarrow", "\u{21A9}"), + (b"hookrightarrow", "\u{21AA}"), + (b"hopf", "\u{1D559}"), + (b"horbar", "\u{2015}"), + (b"hscr", "\u{1D4BD}"), + (b"hslash", "\u{210F}"), + (b"hstrok", "\u{0127}"), + (b"hybull", "\u{2043}"), + (b"hyphen", "\u{2010}"), + (b"iacute", "\u{00ED}"), + (b"ic", "\u{2063}"), + (b"icirc", "\u{00EE}"), + (b"icy", "\u{0438}"), + (b"iecy", "\u{0435}"), + (b"iexcl", "\u{00A1}"), + (b"iff", "\u{21D4}"), + (b"ifr", "\u{1D526}"), + (b"igrave", "\u{00EC}"), + (b"ii", "\u{2148}"), + (b"iiiint", "\u{2A0C}"), + (b"iiint", "\u{222D}"), + (b"iinfin", "\u{29DC}"), + (b"iiota", "\u{2129}"), + (b"ijlig", "\u{0133}"), + (b"imacr", "\u{012B}"), + (b"image", "\u{2111}"), + (b"imagline", "\u{2110}"), + (b"imagpart", "\u{2111}"), + (b"imath", "\u{0131}"), + (b"imof", "\u{22B7}"), + (b"imped", "\u{01B5}"), + (b"in", "\u{2208}"), + (b"incare", "\u{2105}"), + (b"infin", "\u{221E}"), + (b"infintie", "\u{29DD}"), + (b"inodot", "\u{0131}"), + (b"int", "\u{222B}"), + (b"intcal", "\u{22BA}"), + (b"integers", "\u{2124}"), + (b"intercal", "\u{22BA}"), + (b"intlarhk", "\u{2A17}"), + (b"intprod", "\u{2A3C}"), + (b"iocy", "\u{0451}"), + (b"iogon", "\u{012F}"), + (b"iopf", "\u{1D55A}"), + (b"iota", "\u{03B9}"), + (b"iprod", "\u{2A3C}"), + (b"iquest", "\u{00BF}"), + (b"iscr", "\u{1D4BE}"), + (b"isin", "\u{2208}"), + (b"isinE", "\u{22F9}"), + (b"isindot", "\u{22F5}"), + (b"isins", "\u{22F4}"), + (b"isinsv", "\u{22F3}"), + (b"isinv", "\u{2208}"), + (b"it", "\u{2062}"), + (b"itilde", "\u{0129}"), + (b"iukcy", "\u{0456}"), + (b"iuml", "\u{00EF}"), + (b"jcirc", "\u{0135}"), + (b"jcy", "\u{0439}"), + (b"jfr", "\u{1D527}"), + (b"jmath", "\u{0237}"), + (b"jopf", "\u{1D55B}"), + (b"jscr", "\u{1D4BF}"), + (b"jsercy", "\u{0458}"), + (b"jukcy", "\u{0454}"), + (b"kappa", "\u{03BA}"), + (b"kappav", "\u{03F0}"), + (b"kcedil", "\u{0137}"), + (b"kcy", "\u{043A}"), + (b"kfr", "\u{1D528}"), + (b"kgreen", "\u{0138}"), + (b"khcy", "\u{0445}"), + (b"kjcy", "\u{045C}"), + (b"kopf", "\u{1D55C}"), + (b"kscr", "\u{1D4C0}"), + (b"lAarr", "\u{21DA}"), + (b"lArr", "\u{21D0}"), + (b"lAtail", "\u{291B}"), + (b"lBarr", "\u{290E}"), + (b"lE", "\u{2266}"), + (b"lEg", "\u{2A8B}"), + (b"lHar", "\u{2962}"), + (b"lacute", "\u{013A}"), + (b"laemptyv", "\u{29B4}"), + (b"lagran", "\u{2112}"), + (b"lambda", "\u{03BB}"), + (b"lang", "\u{27E8}"), + (b"langd", "\u{2991}"), + (b"langle", "\u{27E8}"), + (b"lap", "\u{2A85}"), + (b"laquo", "\u{00AB}"), + (b"larr", "\u{2190}"), + (b"larrb", "\u{21E4}"), + (b"larrbfs", "\u{291F}"), + (b"larrfs", "\u{291D}"), + (b"larrhk", "\u{21A9}"), + (b"larrlp", "\u{21AB}"), + (b"larrpl", "\u{2939}"), + (b"larrsim", "\u{2973}"), + (b"larrtl", "\u{21A2}"), + (b"lat", "\u{2AAB}"), + (b"latail", "\u{2919}"), + (b"late", "\u{2AAD}"), + (b"lates", "\u{2AAD}\u{FE00}"), + (b"lbarr", "\u{290C}"), + (b"lbbrk", "\u{2772}"), + (b"lbrace", "\u{007B}"), + (b"lbrack", "\u{005B}"), + (b"lbrke", "\u{298B}"), + (b"lbrksld", "\u{298F}"), + (b"lbrkslu", "\u{298D}"), + (b"lcaron", "\u{013E}"), + (b"lcedil", "\u{013C}"), + (b"lceil", "\u{2308}"), + (b"lcub", "\u{007B}"), + (b"lcy", "\u{043B}"), + (b"ldca", "\u{2936}"), + (b"ldquo", "\u{201C}"), + (b"ldquor", "\u{201E}"), + (b"ldrdhar", "\u{2967}"), + (b"ldrushar", "\u{294B}"), + (b"ldsh", "\u{21B2}"), + (b"le", "\u{2264}"), + (b"leftarrow", "\u{2190}"), + (b"leftarrowtail", "\u{21A2}"), + (b"leftharpoondown", "\u{21BD}"), + (b"leftharpoonup", "\u{21BC}"), + (b"leftleftarrows", "\u{21C7}"), + (b"leftrightarrow", "\u{2194}"), + (b"leftrightarrows", "\u{21C6}"), + (b"leftrightharpoons", "\u{21CB}"), + (b"leftrightsquigarrow", "\u{21AD}"), + (b"leftthreetimes", "\u{22CB}"), + (b"leg", "\u{22DA}"), + (b"leq", "\u{2264}"), + (b"leqq", "\u{2266}"), + (b"leqslant", "\u{2A7D}"), + (b"les", "\u{2A7D}"), + (b"lescc", "\u{2AA8}"), + (b"lesdot", "\u{2A7F}"), + (b"lesdoto", "\u{2A81}"), + (b"lesdotor", "\u{2A83}"), + (b"lesg", "\u{22DA}\u{FE00}"), + (b"lesges", "\u{2A93}"), + (b"lessapprox", "\u{2A85}"), + (b"lessdot", "\u{22D6}"), + (b"lesseqgtr", "\u{22DA}"), + (b"lesseqqgtr", "\u{2A8B}"), + (b"lessgtr", "\u{2276}"), + (b"lesssim", "\u{2272}"), + (b"lfisht", "\u{297C}"), + (b"lfloor", "\u{230A}"), + (b"lfr", "\u{1D529}"), + (b"lg", "\u{2276}"), + (b"lgE", "\u{2A91}"), + (b"lhard", "\u{21BD}"), + (b"lharu", "\u{21BC}"), + (b"lharul", "\u{296A}"), + (b"lhblk", "\u{2584}"), + (b"ljcy", "\u{0459}"), + (b"ll", "\u{226A}"), + (b"llarr", "\u{21C7}"), + (b"llcorner", "\u{231E}"), + (b"llhard", "\u{296B}"), + (b"lltri", "\u{25FA}"), + (b"lmidot", "\u{0140}"), + (b"lmoust", "\u{23B0}"), + (b"lmoustache", "\u{23B0}"), + (b"lnE", "\u{2268}"), + (b"lnap", "\u{2A89}"), + (b"lnapprox", "\u{2A89}"), + (b"lne", "\u{2A87}"), + (b"lneq", "\u{2A87}"), + (b"lneqq", "\u{2268}"), + (b"lnsim", "\u{22E6}"), + (b"loang", "\u{27EC}"), + (b"loarr", "\u{21FD}"), + (b"lobrk", "\u{27E6}"), + (b"longleftarrow", "\u{27F5}"), + (b"longleftrightarrow", "\u{27F7}"), + (b"longmapsto", "\u{27FC}"), + (b"longrightarrow", "\u{27F6}"), + (b"looparrowleft", "\u{21AB}"), + (b"looparrowright", "\u{21AC}"), + (b"lopar", "\u{2985}"), + (b"lopf", "\u{1D55D}"), + (b"loplus", "\u{2A2D}"), + (b"lotimes", "\u{2A34}"), + (b"lowast", "\u{2217}"), + (b"lowbar", "\u{005F}"), + (b"loz", "\u{25CA}"), + (b"lozenge", "\u{25CA}"), + (b"lozf", "\u{29EB}"), + (b"lpar", "\u{0028}"), + (b"lparlt", "\u{2993}"), + (b"lrarr", "\u{21C6}"), + (b"lrcorner", "\u{231F}"), + (b"lrhar", "\u{21CB}"), + (b"lrhard", "\u{296D}"), + (b"lrm", "\u{200E}"), + (b"lrtri", "\u{22BF}"), + (b"lsaquo", "\u{2039}"), + (b"lscr", "\u{1D4C1}"), + (b"lsh", "\u{21B0}"), + (b"lsim", "\u{2272}"), + (b"lsime", "\u{2A8D}"), + (b"lsimg", "\u{2A8F}"), + (b"lsqb", "\u{005B}"), + (b"lsquo", "\u{2018}"), + (b"lsquor", "\u{201A}"), + (b"lstrok", "\u{0142}"), + (b"lt", "\u{003C}"), + (b"ltcc", "\u{2AA6}"), + (b"ltcir", "\u{2A79}"), + (b"ltdot", "\u{22D6}"), + (b"lthree", "\u{22CB}"), + (b"ltimes", "\u{22C9}"), + (b"ltlarr", "\u{2976}"), + (b"ltquest", "\u{2A7B}"), + (b"ltrPar", "\u{2996}"), + (b"ltri", "\u{25C3}"), + (b"ltrie", "\u{22B4}"), + (b"ltrif", "\u{25C2}"), + (b"lurdshar", "\u{294A}"), + (b"luruhar", "\u{2966}"), + (b"lvertneqq", "\u{2268}\u{FE00}"), + (b"lvnE", "\u{2268}\u{FE00}"), + (b"mDDot", "\u{223A}"), + (b"macr", "\u{00AF}"), + (b"male", "\u{2642}"), + (b"malt", "\u{2720}"), + (b"maltese", "\u{2720}"), + (b"map", "\u{21A6}"), + (b"mapsto", "\u{21A6}"), + (b"mapstodown", "\u{21A7}"), + (b"mapstoleft", "\u{21A4}"), + (b"mapstoup", "\u{21A5}"), + (b"marker", "\u{25AE}"), + (b"mcomma", "\u{2A29}"), + (b"mcy", "\u{043C}"), + (b"mdash", "\u{2014}"), + (b"measuredangle", "\u{2221}"), + (b"mfr", "\u{1D52A}"), + (b"mho", "\u{2127}"), + (b"micro", "\u{00B5}"), + (b"mid", "\u{2223}"), + (b"midast", "\u{002A}"), + (b"midcir", "\u{2AF0}"), + (b"middot", "\u{00B7}"), + (b"minus", "\u{2212}"), + (b"minusb", "\u{229F}"), + (b"minusd", "\u{2238}"), + (b"minusdu", "\u{2A2A}"), + (b"mlcp", "\u{2ADB}"), + (b"mldr", "\u{2026}"), + (b"mnplus", "\u{2213}"), + (b"models", "\u{22A7}"), + (b"mopf", "\u{1D55E}"), + (b"mp", "\u{2213}"), + (b"mscr", "\u{1D4C2}"), + (b"mstpos", "\u{223E}"), + (b"mu", "\u{03BC}"), + (b"multimap", "\u{22B8}"), + (b"mumap", "\u{22B8}"), + (b"nGg", "\u{22D9}\u{0338}"), + (b"nGt", "\u{226B}\u{20D2}"), + (b"nGtv", "\u{226B}\u{0338}"), + (b"nLeftarrow", "\u{21CD}"), + (b"nLeftrightarrow", "\u{21CE}"), + (b"nLl", "\u{22D8}\u{0338}"), + (b"nLt", "\u{226A}\u{20D2}"), + (b"nLtv", "\u{226A}\u{0338}"), + (b"nRightarrow", "\u{21CF}"), + (b"nVDash", "\u{22AF}"), + (b"nVdash", "\u{22AE}"), + (b"nabla", "\u{2207}"), + (b"nacute", "\u{0144}"), + (b"nang", "\u{2220}\u{20D2}"), + (b"nap", "\u{2249}"), + (b"napE", "\u{2A70}\u{0338}"), + (b"napid", "\u{224B}\u{0338}"), + (b"napos", "\u{0149}"), + (b"napprox", "\u{2249}"), + (b"natur", "\u{266E}"), + (b"natural", "\u{266E}"), + (b"naturals", "\u{2115}"), + (b"nbsp", "\u{00A0}"), + (b"nbump", "\u{224E}\u{0338}"), + (b"nbumpe", "\u{224F}\u{0338}"), + (b"ncap", "\u{2A43}"), + (b"ncaron", "\u{0148}"), + (b"ncedil", "\u{0146}"), + (b"ncong", "\u{2247}"), + (b"ncongdot", "\u{2A6D}\u{0338}"), + (b"ncup", "\u{2A42}"), + (b"ncy", "\u{043D}"), + (b"ndash", "\u{2013}"), + (b"ne", "\u{2260}"), + (b"neArr", "\u{21D7}"), + (b"nearhk", "\u{2924}"), + (b"nearr", "\u{2197}"), + (b"nearrow", "\u{2197}"), + (b"nedot", "\u{2250}\u{0338}"), + (b"nequiv", "\u{2262}"), + (b"nesear", "\u{2928}"), + (b"nesim", "\u{2242}\u{0338}"), + (b"nexist", "\u{2204}"), + (b"nexists", "\u{2204}"), + (b"nfr", "\u{1D52B}"), + (b"ngE", "\u{2267}\u{0338}"), + (b"nge", "\u{2271}"), + (b"ngeq", "\u{2271}"), + (b"ngeqq", "\u{2267}\u{0338}"), + (b"ngeqslant", "\u{2A7E}\u{0338}"), + (b"nges", "\u{2A7E}\u{0338}"), + (b"ngsim", "\u{2275}"), + (b"ngt", "\u{226F}"), + (b"ngtr", "\u{226F}"), + (b"nhArr", "\u{21CE}"), + (b"nharr", "\u{21AE}"), + (b"nhpar", "\u{2AF2}"), + (b"ni", "\u{220B}"), + (b"nis", "\u{22FC}"), + (b"nisd", "\u{22FA}"), + (b"niv", "\u{220B}"), + (b"njcy", "\u{045A}"), + (b"nlArr", "\u{21CD}"), + (b"nlE", "\u{2266}\u{0338}"), + (b"nlarr", "\u{219A}"), + (b"nldr", "\u{2025}"), + (b"nle", "\u{2270}"), + (b"nleftarrow", "\u{219A}"), + (b"nleftrightarrow", "\u{21AE}"), + (b"nleq", "\u{2270}"), + (b"nleqq", "\u{2266}\u{0338}"), + (b"nleqslant", "\u{2A7D}\u{0338}"), + (b"nles", "\u{2A7D}\u{0338}"), + (b"nless", "\u{226E}"), + (b"nlsim", "\u{2274}"), + (b"nlt", "\u{226E}"), + (b"nltri", "\u{22EA}"), + (b"nltrie", "\u{22EC}"), + (b"nmid", "\u{2224}"), + (b"nopf", "\u{1D55F}"), + (b"not", "\u{00AC}"), + (b"notin", "\u{2209}"), + (b"notinE", "\u{22F9}\u{0338}"), + (b"notindot", "\u{22F5}\u{0338}"), + (b"notinva", "\u{2209}"), + (b"notinvb", "\u{22F7}"), + (b"notinvc", "\u{22F6}"), + (b"notni", "\u{220C}"), + (b"notniva", "\u{220C}"), + (b"notnivb", "\u{22FE}"), + (b"notnivc", "\u{22FD}"), + (b"npar", "\u{2226}"), + (b"nparallel", "\u{2226}"), + (b"nparsl", "\u{2AFD}\u{20E5}"), + (b"npart", "\u{2202}\u{0338}"), + (b"npolint", "\u{2A14}"), + (b"npr", "\u{2280}"), + (b"nprcue", "\u{22E0}"), + (b"npre", "\u{2AAF}\u{0338}"), + (b"nprec", "\u{2280}"), + (b"npreceq", "\u{2AAF}\u{0338}"), + (b"nrArr", "\u{21CF}"), + (b"nrarr", "\u{219B}"), + (b"nrarrc", "\u{2933}\u{0338}"), + (b"nrarrw", "\u{219D}\u{0338}"), + (b"nrightarrow", "\u{219B}"), + (b"nrtri", "\u{22EB}"), + (b"nrtrie", "\u{22ED}"), + (b"nsc", "\u{2281}"), + (b"nsccue", "\u{22E1}"), + (b"nsce", "\u{2AB0}\u{0338}"), + (b"nscr", "\u{1D4C3}"), + (b"nshortmid", "\u{2224}"), + (b"nshortparallel", "\u{2226}"), + (b"nsim", "\u{2241}"), + (b"nsime", "\u{2244}"), + (b"nsimeq", "\u{2244}"), + (b"nsmid", "\u{2224}"), + (b"nspar", "\u{2226}"), + (b"nsqsube", "\u{22E2}"), + (b"nsqsupe", "\u{22E3}"), + (b"nsub", "\u{2284}"), + (b"nsubE", "\u{2AC5}\u{0338}"), + (b"nsube", "\u{2288}"), + (b"nsubset", "\u{2282}\u{20D2}"), + (b"nsubseteq", "\u{2288}"), + (b"nsubseteqq", "\u{2AC5}\u{0338}"), + (b"nsucc", "\u{2281}"), + (b"nsucceq", "\u{2AB0}\u{0338}"), + (b"nsup", "\u{2285}"), + (b"nsupE", "\u{2AC6}\u{0338}"), + (b"nsupe", "\u{2289}"), + (b"nsupset", "\u{2283}\u{20D2}"), + (b"nsupseteq", "\u{2289}"), + (b"nsupseteqq", "\u{2AC6}\u{0338}"), + (b"ntgl", "\u{2279}"), + (b"ntilde", "\u{00F1}"), + (b"ntlg", "\u{2278}"), + (b"ntriangleleft", "\u{22EA}"), + (b"ntrianglelefteq", "\u{22EC}"), + (b"ntriangleright", "\u{22EB}"), + (b"ntrianglerighteq", "\u{22ED}"), + (b"nu", "\u{03BD}"), + (b"num", "\u{0023}"), + (b"numero", "\u{2116}"), + (b"numsp", "\u{2007}"), + (b"nvDash", "\u{22AD}"), + (b"nvHarr", "\u{2904}"), + (b"nvap", "\u{224D}\u{20D2}"), + (b"nvdash", "\u{22AC}"), + (b"nvge", "\u{2265}\u{20D2}"), + (b"nvgt", "\u{003E}\u{20D2}"), + (b"nvinfin", "\u{29DE}"), + (b"nvlArr", "\u{2902}"), + (b"nvle", "\u{2264}\u{20D2}"), + (b"nvlt", "\u{003C}\u{20D2}"), + (b"nvltrie", "\u{22B4}\u{20D2}"), + (b"nvrArr", "\u{2903}"), + (b"nvrtrie", "\u{22B5}\u{20D2}"), + (b"nvsim", "\u{223C}\u{20D2}"), + (b"nwArr", "\u{21D6}"), + (b"nwarhk", "\u{2923}"), + (b"nwarr", "\u{2196}"), + (b"nwarrow", "\u{2196}"), + (b"nwnear", "\u{2927}"), + (b"oS", "\u{24C8}"), + (b"oacute", "\u{00F3}"), + (b"oast", "\u{229B}"), + (b"ocir", "\u{229A}"), + (b"ocirc", "\u{00F4}"), + (b"ocy", "\u{043E}"), + (b"odash", "\u{229D}"), + (b"odblac", "\u{0151}"), + (b"odiv", "\u{2A38}"), + (b"odot", "\u{2299}"), + (b"odsold", "\u{29BC}"), + (b"oelig", "\u{0153}"), + (b"ofcir", "\u{29BF}"), + (b"ofr", "\u{1D52C}"), + (b"ogon", "\u{02DB}"), + (b"ograve", "\u{00F2}"), + (b"ogt", "\u{29C1}"), + (b"ohbar", "\u{29B5}"), + (b"ohm", "\u{03A9}"), + (b"oint", "\u{222E}"), + (b"olarr", "\u{21BA}"), + (b"olcir", "\u{29BE}"), + (b"olcross", "\u{29BB}"), + (b"oline", "\u{203E}"), + (b"olt", "\u{29C0}"), + (b"omacr", "\u{014D}"), + (b"omega", "\u{03C9}"), + (b"omicron", "\u{03BF}"), + (b"omid", "\u{29B6}"), + (b"ominus", "\u{2296}"), + (b"oopf", "\u{1D560}"), + (b"opar", "\u{29B7}"), + (b"operp", "\u{29B9}"), + (b"oplus", "\u{2295}"), + (b"or", "\u{2228}"), + (b"orarr", "\u{21BB}"), + (b"ord", "\u{2A5D}"), + (b"order", "\u{2134}"), + (b"orderof", "\u{2134}"), + (b"ordf", "\u{00AA}"), + (b"ordm", "\u{00BA}"), + (b"origof", "\u{22B6}"), + (b"oror", "\u{2A56}"), + (b"orslope", "\u{2A57}"), + (b"orv", "\u{2A5B}"), + (b"oscr", "\u{2134}"), + (b"oslash", "\u{00F8}"), + (b"osol", "\u{2298}"), + (b"otilde", "\u{00F5}"), + (b"otimes", "\u{2297}"), + (b"otimesas", "\u{2A36}"), + (b"ouml", "\u{00F6}"), + (b"ovbar", "\u{233D}"), + (b"par", "\u{2225}"), + (b"para", "\u{00B6}"), + (b"parallel", "\u{2225}"), + (b"parsim", "\u{2AF3}"), + (b"parsl", "\u{2AFD}"), + (b"part", "\u{2202}"), + (b"pcy", "\u{043F}"), + (b"percnt", "\u{0025}"), + (b"period", "\u{002E}"), + (b"permil", "\u{2030}"), + (b"perp", "\u{22A5}"), + (b"pertenk", "\u{2031}"), + (b"pfr", "\u{1D52D}"), + (b"phi", "\u{03C6}"), + (b"phiv", "\u{03D5}"), + (b"phmmat", "\u{2133}"), + (b"phone", "\u{260E}"), + (b"pi", "\u{03C0}"), + (b"pitchfork", "\u{22D4}"), + (b"piv", "\u{03D6}"), + (b"planck", "\u{210F}"), + (b"planckh", "\u{210E}"), + (b"plankv", "\u{210F}"), + (b"plus", "\u{002B}"), + (b"plusacir", "\u{2A23}"), + (b"plusb", "\u{229E}"), + (b"pluscir", "\u{2A22}"), + (b"plusdo", "\u{2214}"), + (b"plusdu", "\u{2A25}"), + (b"pluse", "\u{2A72}"), + (b"plusmn", "\u{00B1}"), + (b"plussim", "\u{2A26}"), + (b"plustwo", "\u{2A27}"), + (b"pm", "\u{00B1}"), + (b"pointint", "\u{2A15}"), + (b"popf", "\u{1D561}"), + (b"pound", "\u{00A3}"), + (b"pr", "\u{227A}"), + (b"prE", "\u{2AB3}"), + (b"prap", "\u{2AB7}"), + (b"prcue", "\u{227C}"), + (b"pre", "\u{2AAF}"), + (b"prec", "\u{227A}"), + (b"precapprox", "\u{2AB7}"), + (b"preccurlyeq", "\u{227C}"), + (b"preceq", "\u{2AAF}"), + (b"precnapprox", "\u{2AB9}"), + (b"precneqq", "\u{2AB5}"), + (b"precnsim", "\u{22E8}"), + (b"precsim", "\u{227E}"), + (b"prime", "\u{2032}"), + (b"primes", "\u{2119}"), + (b"prnE", "\u{2AB5}"), + (b"prnap", "\u{2AB9}"), + (b"prnsim", "\u{22E8}"), + (b"prod", "\u{220F}"), + (b"profalar", "\u{232E}"), + (b"profline", "\u{2312}"), + (b"profsurf", "\u{2313}"), + (b"prop", "\u{221D}"), + (b"propto", "\u{221D}"), + (b"prsim", "\u{227E}"), + (b"prurel", "\u{22B0}"), + (b"pscr", "\u{1D4C5}"), + (b"psi", "\u{03C8}"), + (b"puncsp", "\u{2008}"), + (b"qfr", "\u{1D52E}"), + (b"qint", "\u{2A0C}"), + (b"qopf", "\u{1D562}"), + (b"qprime", "\u{2057}"), + (b"qscr", "\u{1D4C6}"), + (b"quaternions", "\u{210D}"), + (b"quatint", "\u{2A16}"), + (b"quest", "\u{003F}"), + (b"questeq", "\u{225F}"), + (b"quot", "\u{0022}"), + (b"rAarr", "\u{21DB}"), + (b"rArr", "\u{21D2}"), + (b"rAtail", "\u{291C}"), + (b"rBarr", "\u{290F}"), + (b"rHar", "\u{2964}"), + (b"race", "\u{223D}\u{0331}"), + (b"racute", "\u{0155}"), + (b"radic", "\u{221A}"), + (b"raemptyv", "\u{29B3}"), + (b"rang", "\u{27E9}"), + (b"rangd", "\u{2992}"), + (b"range", "\u{29A5}"), + (b"rangle", "\u{27E9}"), + (b"raquo", "\u{00BB}"), + (b"rarr", "\u{2192}"), + (b"rarrap", "\u{2975}"), + (b"rarrb", "\u{21E5}"), + (b"rarrbfs", "\u{2920}"), + (b"rarrc", "\u{2933}"), + (b"rarrfs", "\u{291E}"), + (b"rarrhk", "\u{21AA}"), + (b"rarrlp", "\u{21AC}"), + (b"rarrpl", "\u{2945}"), + (b"rarrsim", "\u{2974}"), + (b"rarrtl", "\u{21A3}"), + (b"rarrw", "\u{219D}"), + (b"ratail", "\u{291A}"), + (b"ratio", "\u{2236}"), + (b"rationals", "\u{211A}"), + (b"rbarr", "\u{290D}"), + (b"rbbrk", "\u{2773}"), + (b"rbrace", "\u{007D}"), + (b"rbrack", "\u{005D}"), + (b"rbrke", "\u{298C}"), + (b"rbrksld", "\u{298E}"), + (b"rbrkslu", "\u{2990}"), + (b"rcaron", "\u{0159}"), + (b"rcedil", "\u{0157}"), + (b"rceil", "\u{2309}"), + (b"rcub", "\u{007D}"), + (b"rcy", "\u{0440}"), + (b"rdca", "\u{2937}"), + (b"rdldhar", "\u{2969}"), + (b"rdquo", "\u{201D}"), + (b"rdquor", "\u{201D}"), + (b"rdsh", "\u{21B3}"), + (b"real", "\u{211C}"), + (b"realine", "\u{211B}"), + (b"realpart", "\u{211C}"), + (b"reals", "\u{211D}"), + (b"rect", "\u{25AD}"), + (b"reg", "\u{00AE}"), + (b"rfisht", "\u{297D}"), + (b"rfloor", "\u{230B}"), + (b"rfr", "\u{1D52F}"), + (b"rhard", "\u{21C1}"), + (b"rharu", "\u{21C0}"), + (b"rharul", "\u{296C}"), + (b"rho", "\u{03C1}"), + (b"rhov", "\u{03F1}"), + (b"rightarrow", "\u{2192}"), + (b"rightarrowtail", "\u{21A3}"), + (b"rightharpoondown", "\u{21C1}"), + (b"rightharpoonup", "\u{21C0}"), + (b"rightleftarrows", "\u{21C4}"), + (b"rightleftharpoons", "\u{21CC}"), + (b"rightrightarrows", "\u{21C9}"), + (b"rightsquigarrow", "\u{219D}"), + (b"rightthreetimes", "\u{22CC}"), + (b"ring", "\u{02DA}"), + (b"risingdotseq", "\u{2253}"), + (b"rlarr", "\u{21C4}"), + (b"rlhar", "\u{21CC}"), + (b"rlm", "\u{200F}"), + (b"rmoust", "\u{23B1}"), + (b"rmoustache", "\u{23B1}"), + (b"rnmid", "\u{2AEE}"), + (b"roang", "\u{27ED}"), + (b"roarr", "\u{21FE}"), + (b"robrk", "\u{27E7}"), + (b"ropar", "\u{2986}"), + (b"ropf", "\u{1D563}"), + (b"roplus", "\u{2A2E}"), + (b"rotimes", "\u{2A35}"), + (b"rpar", "\u{0029}"), + (b"rpargt", "\u{2994}"), + (b"rppolint", "\u{2A12}"), + (b"rrarr", "\u{21C9}"), + (b"rsaquo", "\u{203A}"), + (b"rscr", "\u{1D4C7}"), + (b"rsh", "\u{21B1}"), + (b"rsqb", "\u{005D}"), + (b"rsquo", "\u{2019}"), + (b"rsquor", "\u{2019}"), + (b"rthree", "\u{22CC}"), + (b"rtimes", "\u{22CA}"), + (b"rtri", "\u{25B9}"), + (b"rtrie", "\u{22B5}"), + (b"rtrif", "\u{25B8}"), + (b"rtriltri", "\u{29CE}"), + (b"ruluhar", "\u{2968}"), + (b"rx", "\u{211E}"), + (b"sacute", "\u{015B}"), + (b"sbquo", "\u{201A}"), + (b"sc", "\u{227B}"), + (b"scE", "\u{2AB4}"), + (b"scap", "\u{2AB8}"), + (b"scaron", "\u{0161}"), + (b"sccue", "\u{227D}"), + (b"sce", "\u{2AB0}"), + (b"scedil", "\u{015F}"), + (b"scirc", "\u{015D}"), + (b"scnE", "\u{2AB6}"), + (b"scnap", "\u{2ABA}"), + (b"scnsim", "\u{22E9}"), + (b"scpolint", "\u{2A13}"), + (b"scsim", "\u{227F}"), + (b"scy", "\u{0441}"), + (b"sdot", "\u{22C5}"), + (b"sdotb", "\u{22A1}"), + (b"sdote", "\u{2A66}"), + (b"seArr", "\u{21D8}"), + (b"searhk", "\u{2925}"), + (b"searr", "\u{2198}"), + (b"searrow", "\u{2198}"), + (b"sect", "\u{00A7}"), + (b"semi", "\u{003B}"), + (b"seswar", "\u{2929}"), + (b"setminus", "\u{2216}"), + (b"setmn", "\u{2216}"), + (b"sext", "\u{2736}"), + (b"sfr", "\u{1D530}"), + (b"sfrown", "\u{2322}"), + (b"sharp", "\u{266F}"), + (b"shchcy", "\u{0449}"), + (b"shcy", "\u{0448}"), + (b"shortmid", "\u{2223}"), + (b"shortparallel", "\u{2225}"), + (b"shy", "\u{00AD}"), + (b"sigma", "\u{03C3}"), + (b"sigmaf", "\u{03C2}"), + (b"sigmav", "\u{03C2}"), + (b"sim", "\u{223C}"), + (b"simdot", "\u{2A6A}"), + (b"sime", "\u{2243}"), + (b"simeq", "\u{2243}"), + (b"simg", "\u{2A9E}"), + (b"simgE", "\u{2AA0}"), + (b"siml", "\u{2A9D}"), + (b"simlE", "\u{2A9F}"), + (b"simne", "\u{2246}"), + (b"simplus", "\u{2A24}"), + (b"simrarr", "\u{2972}"), + (b"slarr", "\u{2190}"), + (b"smallsetminus", "\u{2216}"), + (b"smashp", "\u{2A33}"), + (b"smeparsl", "\u{29E4}"), + (b"smid", "\u{2223}"), + (b"smile", "\u{2323}"), + (b"smt", "\u{2AAA}"), + (b"smte", "\u{2AAC}"), + (b"smtes", "\u{2AAC}\u{FE00}"), + (b"softcy", "\u{044C}"), + (b"sol", "\u{002F}"), + (b"solb", "\u{29C4}"), + (b"solbar", "\u{233F}"), + (b"sopf", "\u{1D564}"), + (b"spades", "\u{2660}"), + (b"spadesuit", "\u{2660}"), + (b"spar", "\u{2225}"), + (b"sqcap", "\u{2293}"), + (b"sqcaps", "\u{2293}\u{FE00}"), + (b"sqcup", "\u{2294}"), + (b"sqcups", "\u{2294}\u{FE00}"), + (b"sqsub", "\u{228F}"), + (b"sqsube", "\u{2291}"), + (b"sqsubset", "\u{228F}"), + (b"sqsubseteq", "\u{2291}"), + (b"sqsup", "\u{2290}"), + (b"sqsupe", "\u{2292}"), + (b"sqsupset", "\u{2290}"), + (b"sqsupseteq", "\u{2292}"), + (b"squ", "\u{25A1}"), + (b"square", "\u{25A1}"), + (b"squarf", "\u{25AA}"), + (b"squf", "\u{25AA}"), + (b"srarr", "\u{2192}"), + (b"sscr", "\u{1D4C8}"), + (b"ssetmn", "\u{2216}"), + (b"ssmile", "\u{2323}"), + (b"sstarf", "\u{22C6}"), + (b"star", "\u{2606}"), + (b"starf", "\u{2605}"), + (b"straightepsilon", "\u{03F5}"), + (b"straightphi", "\u{03D5}"), + (b"strns", "\u{00AF}"), + (b"sub", "\u{2282}"), + (b"subE", "\u{2AC5}"), + (b"subdot", "\u{2ABD}"), + (b"sube", "\u{2286}"), + (b"subedot", "\u{2AC3}"), + (b"submult", "\u{2AC1}"), + (b"subnE", "\u{2ACB}"), + (b"subne", "\u{228A}"), + (b"subplus", "\u{2ABF}"), + (b"subrarr", "\u{2979}"), + (b"subset", "\u{2282}"), + (b"subseteq", "\u{2286}"), + (b"subseteqq", "\u{2AC5}"), + (b"subsetneq", "\u{228A}"), + (b"subsetneqq", "\u{2ACB}"), + (b"subsim", "\u{2AC7}"), + (b"subsub", "\u{2AD5}"), + (b"subsup", "\u{2AD3}"), + (b"succ", "\u{227B}"), + (b"succapprox", "\u{2AB8}"), + (b"succcurlyeq", "\u{227D}"), + (b"succeq", "\u{2AB0}"), + (b"succnapprox", "\u{2ABA}"), + (b"succneqq", "\u{2AB6}"), + (b"succnsim", "\u{22E9}"), + (b"succsim", "\u{227F}"), + (b"sum", "\u{2211}"), + (b"sung", "\u{266A}"), + (b"sup", "\u{2283}"), + (b"sup1", "\u{00B9}"), + (b"sup2", "\u{00B2}"), + (b"sup3", "\u{00B3}"), + (b"supE", "\u{2AC6}"), + (b"supdot", "\u{2ABE}"), + (b"supdsub", "\u{2AD8}"), + (b"supe", "\u{2287}"), + (b"supedot", "\u{2AC4}"), + (b"suphsol", "\u{27C9}"), + (b"suphsub", "\u{2AD7}"), + (b"suplarr", "\u{297B}"), + (b"supmult", "\u{2AC2}"), + (b"supnE", "\u{2ACC}"), + (b"supne", "\u{228B}"), + (b"supplus", "\u{2AC0}"), + (b"supset", "\u{2283}"), + (b"supseteq", "\u{2287}"), + (b"supseteqq", "\u{2AC6}"), + (b"supsetneq", "\u{228B}"), + (b"supsetneqq", "\u{2ACC}"), + (b"supsim", "\u{2AC8}"), + (b"supsub", "\u{2AD4}"), + (b"supsup", "\u{2AD6}"), + (b"swArr", "\u{21D9}"), + (b"swarhk", "\u{2926}"), + (b"swarr", "\u{2199}"), + (b"swarrow", "\u{2199}"), + (b"swnwar", "\u{292A}"), + (b"szlig", "\u{00DF}"), + (b"target", "\u{2316}"), + (b"tau", "\u{03C4}"), + (b"tbrk", "\u{23B4}"), + (b"tcaron", "\u{0165}"), + (b"tcedil", "\u{0163}"), + (b"tcy", "\u{0442}"), + (b"tdot", "\u{20DB}"), + (b"telrec", "\u{2315}"), + (b"tfr", "\u{1D531}"), + (b"there4", "\u{2234}"), + (b"therefore", "\u{2234}"), + (b"theta", "\u{03B8}"), + (b"thetasym", "\u{03D1}"), + (b"thetav", "\u{03D1}"), + (b"thickapprox", "\u{2248}"), + (b"thicksim", "\u{223C}"), + (b"thinsp", "\u{2009}"), + (b"thkap", "\u{2248}"), + (b"thksim", "\u{223C}"), + (b"thorn", "\u{00FE}"), + (b"tilde", "\u{02DC}"), + (b"times", "\u{00D7}"), + (b"timesb", "\u{22A0}"), + (b"timesbar", "\u{2A31}"), + (b"timesd", "\u{2A30}"), + (b"tint", "\u{222D}"), + (b"toea", "\u{2928}"), + (b"top", "\u{22A4}"), + (b"topbot", "\u{2336}"), + (b"topcir", "\u{2AF1}"), + (b"topf", "\u{1D565}"), + (b"topfork", "\u{2ADA}"), + (b"tosa", "\u{2929}"), + (b"tprime", "\u{2034}"), + (b"trade", "\u{2122}"), + (b"triangle", "\u{25B5}"), + (b"triangledown", "\u{25BF}"), + (b"triangleleft", "\u{25C3}"), + (b"trianglelefteq", "\u{22B4}"), + (b"triangleq", "\u{225C}"), + (b"triangleright", "\u{25B9}"), + (b"trianglerighteq", "\u{22B5}"), + (b"tridot", "\u{25EC}"), + (b"trie", "\u{225C}"), + (b"triminus", "\u{2A3A}"), + (b"triplus", "\u{2A39}"), + (b"trisb", "\u{29CD}"), + (b"tritime", "\u{2A3B}"), + (b"trpezium", "\u{23E2}"), + (b"tscr", "\u{1D4C9}"), + (b"tscy", "\u{0446}"), + (b"tshcy", "\u{045B}"), + (b"tstrok", "\u{0167}"), + (b"twixt", "\u{226C}"), + (b"twoheadleftarrow", "\u{219E}"), + (b"twoheadrightarrow", "\u{21A0}"), + (b"uArr", "\u{21D1}"), + (b"uHar", "\u{2963}"), + (b"uacute", "\u{00FA}"), + (b"uarr", "\u{2191}"), + (b"ubrcy", "\u{045E}"), + (b"ubreve", "\u{016D}"), + (b"ucirc", "\u{00FB}"), + (b"ucy", "\u{0443}"), + (b"udarr", "\u{21C5}"), + (b"udblac", "\u{0171}"), + (b"udhar", "\u{296E}"), + (b"ufisht", "\u{297E}"), + (b"ufr", "\u{1D532}"), + (b"ugrave", "\u{00F9}"), + (b"uharl", "\u{21BF}"), + (b"uharr", "\u{21BE}"), + (b"uhblk", "\u{2580}"), + (b"ulcorn", "\u{231C}"), + (b"ulcorner", "\u{231C}"), + (b"ulcrop", "\u{230F}"), + (b"ultri", "\u{25F8}"), + (b"umacr", "\u{016B}"), + (b"uml", "\u{00A8}"), + (b"uogon", "\u{0173}"), + (b"uopf", "\u{1D566}"), + (b"uparrow", "\u{2191}"), + (b"updownarrow", "\u{2195}"), + (b"upharpoonleft", "\u{21BF}"), + (b"upharpoonright", "\u{21BE}"), + (b"uplus", "\u{228E}"), + (b"upsi", "\u{03C5}"), + (b"upsih", "\u{03D2}"), + (b"upsilon", "\u{03C5}"), + (b"upuparrows", "\u{21C8}"), + (b"urcorn", "\u{231D}"), + (b"urcorner", "\u{231D}"), + (b"urcrop", "\u{230E}"), + (b"uring", "\u{016F}"), + (b"urtri", "\u{25F9}"), + (b"uscr", "\u{1D4CA}"), + (b"utdot", "\u{22F0}"), + (b"utilde", "\u{0169}"), + (b"utri", "\u{25B5}"), + (b"utrif", "\u{25B4}"), + (b"uuarr", "\u{21C8}"), + (b"uuml", "\u{00FC}"), + (b"uwangle", "\u{29A7}"), + (b"vArr", "\u{21D5}"), + (b"vBar", "\u{2AE8}"), + (b"vBarv", "\u{2AE9}"), + (b"vDash", "\u{22A8}"), + (b"vangrt", "\u{299C}"), + (b"varepsilon", "\u{03F5}"), + (b"varkappa", "\u{03F0}"), + (b"varnothing", "\u{2205}"), + (b"varphi", "\u{03D5}"), + (b"varpi", "\u{03D6}"), + (b"varpropto", "\u{221D}"), + (b"varr", "\u{2195}"), + (b"varrho", "\u{03F1}"), + (b"varsigma", "\u{03C2}"), + (b"varsubsetneq", "\u{228A}\u{FE00}"), + (b"varsubsetneqq", "\u{2ACB}\u{FE00}"), + (b"varsupsetneq", "\u{228B}\u{FE00}"), + (b"varsupsetneqq", "\u{2ACC}\u{FE00}"), + (b"vartheta", "\u{03D1}"), + (b"vartriangleleft", "\u{22B2}"), + (b"vartriangleright", "\u{22B3}"), + (b"vcy", "\u{0432}"), + (b"vdash", "\u{22A2}"), + (b"vee", "\u{2228}"), + (b"veebar", "\u{22BB}"), + (b"veeeq", "\u{225A}"), + (b"vellip", "\u{22EE}"), + (b"verbar", "\u{007C}"), + (b"vert", "\u{007C}"), + (b"vfr", "\u{1D533}"), + (b"vltri", "\u{22B2}"), + (b"vnsub", "\u{2282}\u{20D2}"), + (b"vnsup", "\u{2283}\u{20D2}"), + (b"vopf", "\u{1D567}"), + (b"vprop", "\u{221D}"), + (b"vrtri", "\u{22B3}"), + (b"vscr", "\u{1D4CB}"), + (b"vsubnE", "\u{2ACB}\u{FE00}"), + (b"vsubne", "\u{228A}\u{FE00}"), + (b"vsupnE", "\u{2ACC}\u{FE00}"), + (b"vsupne", "\u{228B}\u{FE00}"), + (b"vzigzag", "\u{299A}"), + (b"wcirc", "\u{0175}"), + (b"wedbar", "\u{2A5F}"), + (b"wedge", "\u{2227}"), + (b"wedgeq", "\u{2259}"), + (b"weierp", "\u{2118}"), + (b"wfr", "\u{1D534}"), + (b"wopf", "\u{1D568}"), + (b"wp", "\u{2118}"), + (b"wr", "\u{2240}"), + (b"wreath", "\u{2240}"), + (b"wscr", "\u{1D4CC}"), + (b"xcap", "\u{22C2}"), + (b"xcirc", "\u{25EF}"), + (b"xcup", "\u{22C3}"), + (b"xdtri", "\u{25BD}"), + (b"xfr", "\u{1D535}"), + (b"xhArr", "\u{27FA}"), + (b"xharr", "\u{27F7}"), + (b"xi", "\u{03BE}"), + (b"xlArr", "\u{27F8}"), + (b"xlarr", "\u{27F5}"), + (b"xmap", "\u{27FC}"), + (b"xnis", "\u{22FB}"), + (b"xodot", "\u{2A00}"), + (b"xopf", "\u{1D569}"), + (b"xoplus", "\u{2A01}"), + (b"xotime", "\u{2A02}"), + (b"xrArr", "\u{27F9}"), + (b"xrarr", "\u{27F6}"), + (b"xscr", "\u{1D4CD}"), + (b"xsqcup", "\u{2A06}"), + (b"xuplus", "\u{2A04}"), + (b"xutri", "\u{25B3}"), + (b"xvee", "\u{22C1}"), + (b"xwedge", "\u{22C0}"), + (b"yacute", "\u{00FD}"), + (b"yacy", "\u{044F}"), + (b"ycirc", "\u{0177}"), + (b"ycy", "\u{044B}"), + (b"yen", "\u{00A5}"), + (b"yfr", "\u{1D536}"), + (b"yicy", "\u{0457}"), + (b"yopf", "\u{1D56A}"), + (b"yscr", "\u{1D4CE}"), + (b"yucy", "\u{044E}"), + (b"yuml", "\u{00FF}"), + (b"zacute", "\u{017A}"), + (b"zcaron", "\u{017E}"), + (b"zcy", "\u{0437}"), + (b"zdot", "\u{017C}"), + (b"zeetrf", "\u{2128}"), + (b"zeta", "\u{03B6}"), + (b"zfr", "\u{1D537}"), + (b"zhcy", "\u{0436}"), + (b"zigrarr", "\u{21DD}"), + (b"zopf", "\u{1D56B}"), + (b"zscr", "\u{1D4CF}"), + (b"zwj", "\u{200D}"), + (b"zwnj", "\u{200C}"), +]; + +pub(crate) fn get_entity(bytes: &[u8]) -> Option<&'static str> { + ENTITIES + .binary_search_by_key(&bytes, |&(key, _value)| key) + .ok() + .map(|i| ENTITIES[i].1) +} diff --git a/vendor/pulldown-cmark-0.7.2/src/escape.rs b/vendor/pulldown-cmark-0.7.2/src/escape.rs new file mode 100644 index 0000000000..7b31cef614 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/escape.rs @@ -0,0 +1,297 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Utility functions for HTML escaping + +use std::io; +use std::str::from_utf8; + +use crate::html::StrWrite; + +#[rustfmt::skip] +static HREF_SAFE: [u8; 128] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, +]; + +static HEX_CHARS: &[u8] = b"0123456789ABCDEF"; +static AMP_ESCAPE: &str = "&"; +static SLASH_ESCAPE: &str = "'"; + +pub(crate) fn escape_href(mut w: W, s: &str) -> io::Result<()> +where + W: StrWrite, +{ + let bytes = s.as_bytes(); + let mut mark = 0; + for i in 0..bytes.len() { + let c = bytes[i]; + if c >= 0x80 || HREF_SAFE[c as usize] == 0 { + // character needing escape + + // write partial substring up to mark + if mark < i { + w.write_str(&s[mark..i])?; + } + match c { + b'&' => { + w.write_str(AMP_ESCAPE)?; + } + b'\'' => { + w.write_str(SLASH_ESCAPE)?; + } + _ => { + let mut buf = [0u8; 3]; + buf[0] = b'%'; + buf[1] = HEX_CHARS[((c as usize) >> 4) & 0xF]; + buf[2] = HEX_CHARS[(c as usize) & 0xF]; + let escaped = from_utf8(&buf).unwrap(); + w.write_str(escaped)?; + } + } + mark = i + 1; // all escaped characters are ASCII + } + } + w.write_str(&s[mark..]) +} + +const fn create_html_escape_table() -> [u8; 256] { + let mut table = [0; 256]; + table[b'"' as usize] = 1; + table[b'&' as usize] = 2; + table[b'<' as usize] = 3; + table[b'>' as usize] = 4; + table +} + +static HTML_ESCAPE_TABLE: [u8; 256] = create_html_escape_table(); + +static HTML_ESCAPES: [&'static str; 5] = ["", """, "&", "<", ">"]; + +/// Writes the given string to the Write sink, replacing special HTML bytes +/// (<, >, &, ") by escape sequences. +pub(crate) fn escape_html(w: W, s: &str) -> io::Result<()> { + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + simd::escape_html(w, s) + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + escape_html_scalar(w, s) + } +} + +fn escape_html_scalar(mut w: W, s: &str) -> io::Result<()> { + let bytes = s.as_bytes(); + let mut mark = 0; + let mut i = 0; + while i < s.len() { + match bytes[i..] + .iter() + .position(|&c| HTML_ESCAPE_TABLE[c as usize] != 0) + { + Some(pos) => { + i += pos; + } + None => break, + } + let c = bytes[i]; + let escape = HTML_ESCAPE_TABLE[c as usize]; + let escape_seq = HTML_ESCAPES[escape as usize]; + w.write_str(&s[mark..i])?; + w.write_str(escape_seq)?; + i += 1; + mark = i; // all escaped characters are ASCII + } + w.write_str(&s[mark..]) +} + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +mod simd { + use crate::html::StrWrite; + use std::arch::x86_64::*; + use std::io; + use std::mem::size_of; + + const VECTOR_SIZE: usize = size_of::<__m128i>(); + + pub(crate) fn escape_html(mut w: W, s: &str) -> io::Result<()> { + // The SIMD accelerated code uses the PSHUFB instruction, which is part + // of the SSSE3 instruction set. Further, we can only use this code if + // the buffer is at least one VECTOR_SIZE in length to prevent reading + // out of bounds. If either of these conditions is not met, we fall back + // to scalar code. + if is_x86_feature_detected!("ssse3") && s.len() >= VECTOR_SIZE { + let bytes = s.as_bytes(); + let mut mark = 0; + + unsafe { + foreach_special_simd(bytes, 0, |i| { + let escape_ix = *bytes.get_unchecked(i) as usize; + let replacement = + super::HTML_ESCAPES[super::HTML_ESCAPE_TABLE[escape_ix] as usize]; + w.write_str(&s.get_unchecked(mark..i))?; + mark = i + 1; // all escaped characters are ASCII + w.write_str(replacement) + })?; + w.write_str(&s.get_unchecked(mark..)) + } + } else { + super::escape_html_scalar(w, s) + } + } + + /// Creates the lookup table for use in `compute_mask`. + const fn create_lookup() -> [u8; 16] { + let mut table = [0; 16]; + table[(b'<' & 0x0f) as usize] = b'<'; + table[(b'>' & 0x0f) as usize] = b'>'; + table[(b'&' & 0x0f) as usize] = b'&'; + table[(b'"' & 0x0f) as usize] = b'"'; + table[0] = 0b0111_1111; + table + } + + #[target_feature(enable = "ssse3")] + /// Computes a byte mask at given offset in the byte buffer. Its first 16 (least significant) + /// bits correspond to whether there is an HTML special byte (&, <, ", >) at the 16 bytes + /// `bytes[offset..]`. For example, the mask `(1 << 3)` states that there is an HTML byte + /// at `offset + 3`. It is only safe to call this function when + /// `bytes.len() >= offset + VECTOR_SIZE`. + unsafe fn compute_mask(bytes: &[u8], offset: usize) -> i32 { + debug_assert!(bytes.len() >= offset + VECTOR_SIZE); + + let table = create_lookup(); + let lookup = _mm_loadu_si128(table.as_ptr() as *const __m128i); + let raw_ptr = bytes.as_ptr().offset(offset as isize) as *const __m128i; + + // Load the vector from memory. + let vector = _mm_loadu_si128(raw_ptr); + // We take the least significant 4 bits of every byte and use them as indices + // to map into the lookup vector. + // Note that shuffle maps bytes with their most significant bit set to lookup[0]. + // Bytes that share their lower nibble with an HTML special byte get mapped to that + // corresponding special byte. Note that all HTML special bytes have distinct lower + // nibbles. Other bytes either get mapped to 0 or 127. + let expected = _mm_shuffle_epi8(lookup, vector); + // We compare the original vector to the mapped output. Bytes that shared a lower + // nibble with an HTML special byte match *only* if they are that special byte. Bytes + // that have either a 0 lower nibble or their most significant bit set were mapped to + // 127 and will hence never match. All other bytes have non-zero lower nibbles but + // were mapped to 0 and will therefore also not match. + let matches = _mm_cmpeq_epi8(expected, vector); + + // Translate matches to a bitmask, where every 1 corresponds to a HTML special character + // and a 0 is a non-HTML byte. + _mm_movemask_epi8(matches) + } + + /// Calls the given function with the index of every byte in the given byteslice + /// that is either ", &, <, or > and for no other byte. + /// Make sure to only call this when `bytes.len() >= 16`, undefined behaviour may + /// occur otherwise. + #[target_feature(enable = "ssse3")] + unsafe fn foreach_special_simd( + bytes: &[u8], + mut offset: usize, + mut callback: F, + ) -> io::Result<()> + where + F: FnMut(usize) -> io::Result<()>, + { + // The strategy here is to walk the byte buffer in chunks of VECTOR_SIZE (16) + // bytes at a time starting at the given offset. For each chunk, we compute a + // a bitmask indicating whether the corresponding byte is a HTML special byte. + // We then iterate over all the 1 bits in this mask and call the callback function + // with the corresponding index in the buffer. + // When the number of HTML special bytes in the buffer is relatively low, this + // allows us to quickly go through the buffer without a lookup and for every + // single byte. + + debug_assert!(bytes.len() >= VECTOR_SIZE); + let upperbound = bytes.len() - VECTOR_SIZE; + while offset < upperbound { + let mut mask = compute_mask(bytes, offset); + while mask != 0 { + let ix = mask.trailing_zeros(); + callback(offset + ix as usize)?; + mask ^= mask & -mask; + } + offset += VECTOR_SIZE; + } + + // Final iteration. We align the read with the end of the slice and + // shift off the bytes at start we have already scanned. + let mut mask = compute_mask(bytes, upperbound); + mask >>= offset - upperbound; + while mask != 0 { + let ix = mask.trailing_zeros(); + callback(offset + ix as usize)?; + mask ^= mask & -mask; + } + Ok(()) + } + + #[cfg(test)] + mod html_scan_tests { + #[test] + fn multichunk() { + let mut vec = Vec::new(); + unsafe { + super::foreach_special_simd("&aXaaaa.a'aa9a<>aab&".as_bytes(), 0, |ix| { + Ok(vec.push(ix)) + }) + .unwrap(); + } + assert_eq!(vec, vec![0, 14, 15, 19]); + } + + // only match these bytes, and when we match them, match them VECTOR_SIZE times + #[test] + fn only_right_bytes_matched() { + for b in 0..255u8 { + let right_byte = b == b'&' || b == b'<' || b == b'>' || b == b'"'; + let vek = vec![b; super::VECTOR_SIZE]; + let mut match_count = 0; + unsafe { + super::foreach_special_simd(&vek, 0, |_| { + match_count += 1; + Ok(()) + }) + .unwrap(); + } + assert!((match_count > 0) == (match_count == super::VECTOR_SIZE)); + assert_eq!( + (match_count == super::VECTOR_SIZE), + right_byte, + "match_count: {}, byte: {:?}", + match_count, + b as char + ); + } + } + } +} diff --git a/vendor/pulldown-cmark-0.7.2/src/html.rs b/vendor/pulldown-cmark-0.7.2/src/html.rs new file mode 100644 index 0000000000..06e5dc68b6 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/html.rs @@ -0,0 +1,520 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! HTML renderer that takes an iterator of events as input. + +use std::collections::HashMap; +use std::fmt::{Arguments, Write as FmtWrite}; +use std::io::{self, ErrorKind, Write}; + +use crate::escape::{escape_href, escape_html}; +use crate::parse::Event::*; +use crate::parse::{Alignment, CodeBlockKind, Event, LinkType, Tag}; +use crate::strings::CowStr; + +enum TableState { + Head, + Body, +} + +/// This wrapper exists because we can't have both a blanket implementation +/// for all types implementing `Write` and types of the for `&mut W` where +/// `W: StrWrite`. Since we need the latter a lot, we choose to wrap +/// `Write` types. +struct WriteWrapper(W); + +/// Trait that allows writing string slices. This is basically an extension +/// of `std::io::Write` in order to include `String`. +pub(crate) trait StrWrite { + fn write_str(&mut self, s: &str) -> io::Result<()>; + + fn write_fmt(&mut self, args: Arguments) -> io::Result<()>; +} + +impl StrWrite for WriteWrapper +where + W: Write, +{ + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.0.write_all(s.as_bytes()) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + self.0.write_fmt(args) + } +} + +impl<'w> StrWrite for String { + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.push_str(s); + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + // FIXME: translate fmt error to io error? + FmtWrite::write_fmt(self, args).map_err(|_| ErrorKind::Other.into()) + } +} + +impl StrWrite for &'_ mut W +where + W: StrWrite, +{ + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + (**self).write_str(s) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + (**self).write_fmt(args) + } +} + +struct HtmlWriter<'a, I, W> { + /// Iterator supplying events. + iter: I, + + /// Writer to write to. + writer: W, + + /// Whether or not the last write wrote a newline. + end_newline: bool, + + table_state: TableState, + table_alignments: Vec, + table_cell_index: usize, + numbers: HashMap, usize>, +} + +impl<'a, I, W> HtmlWriter<'a, I, W> +where + I: Iterator>, + W: StrWrite, +{ + fn new(iter: I, writer: W) -> Self { + Self { + iter, + writer, + end_newline: true, + table_state: TableState::Head, + table_alignments: vec![], + table_cell_index: 0, + numbers: HashMap::new(), + } + } + + /// Writes a new line. + fn write_newline(&mut self) -> io::Result<()> { + self.end_newline = true; + self.writer.write_str("\n") + } + + /// Writes a buffer, and tracks whether or not a newline was written. + #[inline] + fn write(&mut self, s: &str) -> io::Result<()> { + self.writer.write_str(s)?; + + if !s.is_empty() { + self.end_newline = s.ends_with('\n'); + } + Ok(()) + } + + pub fn run(mut self) -> io::Result<()> { + while let Some(event) = self.iter.next() { + match event { + Start(tag) => { + self.start_tag(tag)?; + } + End(tag) => { + self.end_tag(tag)?; + } + Text(text) => { + escape_html(&mut self.writer, &text)?; + self.end_newline = text.ends_with('\n'); + } + Code(text) => { + self.write("")?; + escape_html(&mut self.writer, &text)?; + self.write("")?; + } + Html(html) => { + self.write(&html)?; + } + SoftBreak => { + self.write_newline()?; + } + HardBreak => { + self.write("
    \n")?; + } + Rule => { + if self.end_newline { + self.write("
    \n")?; + } else { + self.write("\n
    \n")?; + } + } + FootnoteReference(name) => { + let len = self.numbers.len() + 1; + self.write("")?; + let number = *self.numbers.entry(name).or_insert(len); + write!(&mut self.writer, "{}", number)?; + self.write("")?; + } + TaskListMarker(true) => { + self.write("\n")?; + } + TaskListMarker(false) => { + self.write("\n")?; + } + } + } + Ok(()) + } + + /// Writes the start of an HTML tag. + fn start_tag(&mut self, tag: Tag<'a>) -> io::Result<()> { + match tag { + Tag::Paragraph => { + if self.end_newline { + self.write("

    ") + } else { + self.write("\n

    ") + } + } + Tag::Heading(level) => { + if self.end_newline { + self.end_newline = false; + write!(&mut self.writer, "", level) + } else { + write!(&mut self.writer, "\n", level) + } + } + Tag::Table(alignments) => { + self.table_alignments = alignments; + self.write("") + } + Tag::TableHead => { + self.table_state = TableState::Head; + self.table_cell_index = 0; + self.write("") + } + Tag::TableRow => { + self.table_cell_index = 0; + self.write("") + } + Tag::TableCell => { + match self.table_state { + TableState::Head => { + self.write(" { + self.write(" self.write(" align=\"left\">"), + Some(&Alignment::Center) => self.write(" align=\"center\">"), + Some(&Alignment::Right) => self.write(" align=\"right\">"), + _ => self.write(">"), + } + } + Tag::BlockQuote => { + if self.end_newline { + self.write("
    \n") + } else { + self.write("\n
    \n") + } + } + Tag::CodeBlock(info) => { + if !self.end_newline { + self.write_newline()?; + } + match info { + CodeBlockKind::Fenced(info) => { + let lang = info.split(' ').next().unwrap(); + if lang.is_empty() { + self.write("
    ")
    +                        } else {
    +                            self.write("
    ")
    +                        }
    +                    }
    +                    CodeBlockKind::Indented => self.write("
    "),
    +                }
    +            }
    +            Tag::List(Some(1)) => {
    +                if self.end_newline {
    +                    self.write("
      \n") + } else { + self.write("\n
        \n") + } + } + Tag::List(Some(start)) => { + if self.end_newline { + self.write("
          \n") + } + Tag::List(None) => { + if self.end_newline { + self.write("
    \n")?; + } + Tag::TableHead => { + self.write("\n")?; + self.table_state = TableState::Body; + } + Tag::TableRow => { + self.write("\n")?; + } + Tag::TableCell => { + match self.table_state { + TableState::Head => { + self.write("")?; + } + TableState::Body => { + self.write("")?; + } + } + self.table_cell_index += 1; + } + Tag::BlockQuote => { + self.write("\n")?; + } + Tag::CodeBlock(_) => { + self.write("\n")?; + } + Tag::List(Some(_)) => { + self.write("\n")?; + } + Tag::List(None) => { + self.write("\n")?; + } + Tag::Item => { + self.write("\n")?; + } + Tag::Emphasis => { + self.write("")?; + } + Tag::Strong => { + self.write("")?; + } + Tag::Strikethrough => { + self.write("")?; + } + Tag::Link(_, _, _) => { + self.write("")?; + } + Tag::Image(_, _, _) => (), // shouldn't happen, handled in start + Tag::FootnoteDefinition(_) => { + self.write("\n")?; + } + } + Ok(()) + } + + // run raw text, consuming end tag + fn raw_text(&mut self) -> io::Result<()> { + let mut nest = 0; + while let Some(event) = self.iter.next() { + match event { + Start(_) => nest += 1, + End(_) => { + if nest == 0 { + break; + } + nest -= 1; + } + Html(text) | Code(text) | Text(text) => { + escape_html(&mut self.writer, &text)?; + self.end_newline = text.ends_with('\n'); + } + SoftBreak | HardBreak | Rule => { + self.write(" ")?; + } + FootnoteReference(name) => { + let len = self.numbers.len() + 1; + let number = *self.numbers.entry(name).or_insert(len); + write!(&mut self.writer, "[{}]", number)?; + } + TaskListMarker(true) => self.write("[x]")?, + TaskListMarker(false) => self.write("[ ]")?, + } + } + Ok(()) + } +} + +/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and +/// push it to a `String`. +/// +/// # Examples +/// +/// ``` +/// use pulldown_cmark::{html, Parser}; +/// +/// let markdown_str = r#" +/// hello +/// ===== +/// +/// * alpha +/// * beta +/// "#; +/// let parser = Parser::new(markdown_str); +/// +/// let mut html_buf = String::new(); +/// html::push_html(&mut html_buf, parser); +/// +/// assert_eq!(html_buf, r#"

    hello

    +///
      +///
    • alpha
    • +///
    • beta
    • +///
    +/// "#); +/// ``` +pub fn push_html<'a, I>(s: &mut String, iter: I) +where + I: Iterator>, +{ + HtmlWriter::new(iter, s).run().unwrap(); +} + +/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and +/// write it out to a writable stream. +/// +/// **Note**: using this function with an unbuffered writer like a file or socket +/// will result in poor performance. Wrap these in a +/// [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html) to +/// prevent unnecessary slowdowns. +/// +/// # Examples +/// +/// ``` +/// use pulldown_cmark::{html, Parser}; +/// use std::io::Cursor; +/// +/// let markdown_str = r#" +/// hello +/// ===== +/// +/// * alpha +/// * beta +/// "#; +/// let mut bytes = Vec::new(); +/// let parser = Parser::new(markdown_str); +/// +/// html::write_html(Cursor::new(&mut bytes), parser); +/// +/// assert_eq!(&String::from_utf8_lossy(&bytes)[..], r#"

    hello

    +///
      +///
    • alpha
    • +///
    • beta
    • +///
    +/// "#); +/// ``` +pub fn write_html<'a, I, W>(writer: W, iter: I) -> io::Result<()> +where + I: Iterator>, + W: Write, +{ + HtmlWriter::new(iter, WriteWrapper(writer)).run() +} diff --git a/vendor/pulldown-cmark-0.7.2/src/lib.rs b/vendor/pulldown-cmark-0.7.2/src/lib.rs new file mode 100644 index 0000000000..f3f16b3dab --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/lib.rs @@ -0,0 +1,76 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Pull parser for [CommonMark](https://commonmark.org). This crate provides a [Parser](struct.Parser.html) struct +//! which is an iterator over [Event](enum.Event.html)s. This iterator can be used +//! directly, or to output HTML using the [HTML module](html/index.html). +//! +//! By default, only CommonMark features are enabled. To use extensions like tables, +//! footnotes or task lists, enable them by setting the corresponding flags in the +//! [Options](struct.Options.html) struct. +//! +//! # Example +//! ```rust +//! use pulldown_cmark::{Parser, Options, html}; +//! +//! let markdown_input = "Hello world, this is a ~~complicated~~ *very simple* example."; +//! +//! // Set up options and parser. Strikethroughs are not part of the CommonMark standard +//! // and we therefore must enable it explicitly. +//! let mut options = Options::empty(); +//! options.insert(Options::ENABLE_STRIKETHROUGH); +//! let parser = Parser::new_ext(markdown_input, options); +//! +//! // Write to String buffer. +//! let mut html_output = String::new(); +//! html::push_html(&mut html_output, parser); +//! +//! // Check that the output is what we expected. +//! let expected_html = "

    Hello world, this is a complicated very simple example.

    \n"; +//! assert_eq!(expected_html, &html_output); +//! ``` + +// When compiled for the rustc compiler itself we want to make sure that this is +// an unstable crate. +#![cfg_attr(rustbuild, feature(staged_api, rustc_private))] +#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] + +pub mod html; + +#[macro_use] +extern crate bitflags; +extern crate unicase; + +mod entities; +mod escape; +mod linklabel; +mod parse; +mod puncttable; +mod scanners; +mod strings; +mod tree; + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +mod simd; + +pub use crate::parse::{ + Alignment, CodeBlockKind, Event, LinkType, OffsetIter, Options, Parser, Tag, +}; +pub use crate::strings::{CowStr, InlineStr}; diff --git a/vendor/pulldown-cmark-0.7.2/src/linklabel.rs b/vendor/pulldown-cmark-0.7.2/src/linklabel.rs new file mode 100644 index 0000000000..cfb9c2706b --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/linklabel.rs @@ -0,0 +1,135 @@ +// Copyright 2018 Google LLC +// +// 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. + +//! Link label parsing and matching. + +use unicase::UniCase; + +use crate::scanners::{is_ascii_whitespace, scan_eol}; +use crate::strings::CowStr; + +pub enum ReferenceLabel<'a> { + Link(CowStr<'a>), + Footnote(CowStr<'a>), +} + +pub type LinkLabel<'a> = UniCase>; + +/// Assumes the opening bracket has already been scanned. +/// The line break handler determines what happens when a linebreak +/// is found. It is passed the bytes following the line break and +/// either returns `Some(k)`, where `k` is the number of bytes to skip, +/// or `None` to abort parsing the label. +/// Returns the number of bytes read (including closing bracket) and label on success. +pub(crate) fn scan_link_label_rest<'t>( + text: &'t str, + linebreak_handler: &dyn Fn(&[u8]) -> Option, +) -> Option<(usize, CowStr<'t>)> { + let bytes = text.as_bytes(); + let mut ix = 0; + let mut only_white_space = true; + let mut codepoints = 0; + // no worries, doesnt allocate until we push things onto it + let mut label = String::new(); + let mut mark = 0; + + loop { + if codepoints >= 1000 { + return None; + } + match *bytes.get(ix)? { + b'[' => return None, + b']' => break, + b'\\' => { + ix += 2; + codepoints += 2; + only_white_space = false; + } + b if is_ascii_whitespace(b) => { + // normalize labels by collapsing whitespaces, including linebreaks + let mut whitespaces = 0; + let mut linebreaks = 0; + let whitespace_start = ix; + + while ix < bytes.len() && is_ascii_whitespace(bytes[ix]) { + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + linebreaks += 1; + if linebreaks > 1 { + return None; + } + ix += eol_bytes; + ix += linebreak_handler(&bytes[ix..])?; + whitespaces += 2; // indicate that we need to replace + } else { + whitespaces += if bytes[ix] == b' ' { 1 } else { 2 }; + ix += 1; + } + } + if whitespaces > 1 { + label.push_str(&text[mark..whitespace_start]); + label.push(' '); + mark = ix; + codepoints += ix - whitespace_start; + } else { + codepoints += 1; + } + } + b => { + only_white_space = false; + ix += 1; + if b & 0b1000_0000 != 0 { + codepoints += 1; + } + } + } + } + + if only_white_space { + None + } else { + let cow = if mark == 0 { + text[..ix].into() + } else { + label.push_str(&text[mark..ix]); + label.into() + }; + Some((ix + 1, cow)) + } +} + +#[cfg(test)] +mod test { + use super::scan_link_label_rest; + + #[test] + fn whitespace_normalization() { + let input = "«\t\tBlurry Eyes\t\t»][blurry_eyes]"; + let expected_output = "« Blurry Eyes »"; // regular spaces! + + let (_bytes, normalized_label) = scan_link_label_rest(input, &|_| None).unwrap(); + assert_eq!(expected_output, normalized_label.as_ref()); + } + + #[test] + fn return_carriage_linefeed_ok() { + let input = "hello\r\nworld\r\n]"; + assert!(scan_link_label_rest(input, &|_| Some(0)).is_some()); + } +} diff --git a/vendor/pulldown-cmark-0.7.2/src/main.rs b/vendor/pulldown-cmark-0.7.2/src/main.rs new file mode 100644 index 0000000000..d0225a4ce7 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/main.rs @@ -0,0 +1,109 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Command line tool to exercise pulldown-cmark. + +use pulldown_cmark::{html, Options, Parser}; + +use std::env; +use std::io::{self, Read}; +use std::mem; + +fn dry_run(text: &str, opts: Options) { + let p = Parser::new_ext(text, opts); + let count = p.count(); + println!("{} events", count); +} + +fn print_events(text: &str, opts: Options) { + let parser = Parser::new_ext(text, opts).into_offset_iter(); + for (event, range) in parser { + println!("{:?}: {:?}", range, event); + } + println!("EOF"); +} + +fn brief(program: &str) -> String { + format!( + "Usage: {} [options]\n\n{}", + program, "Reads markdown from standard input and emits HTML.", + ) +} + +pub fn main() -> std::io::Result<()> { + let args: Vec<_> = env::args().collect(); + let mut opts = getopts::Options::new(); + opts.optflag("h", "help", "this help message"); + opts.optflag("d", "dry-run", "dry run, produce no output"); + opts.optflag("e", "events", "print event sequence instead of rendering"); + opts.optflag("T", "enable-tables", "enable GitHub-style tables"); + opts.optflag("F", "enable-footnotes", "enable Hoedown-style footnotes"); + opts.optflag( + "S", + "enable-strikethrough", + "enable GitHub-style strikethrough", + ); + opts.optflag("L", "enable-tasklists", "enable GitHub-style task lists"); + + let matches = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(f) => { + eprintln!("{}\n{}", f, opts.usage(&brief(&args[0]))); + std::process::exit(1); + } + }; + if matches.opt_present("help") { + println!("{}", opts.usage(&brief(&args[0]))); + return Ok(()); + } + let mut opts = Options::empty(); + if matches.opt_present("enable-tables") { + opts.insert(Options::ENABLE_TABLES); + } + if matches.opt_present("enable-footnotes") { + opts.insert(Options::ENABLE_FOOTNOTES); + } + if matches.opt_present("enable-strikethrough") { + opts.insert(Options::ENABLE_STRIKETHROUGH); + } + if matches.opt_present("enable-tasklists") { + opts.insert(Options::ENABLE_TASKLISTS); + } + + let mut input = String::new(); + io::stdin().lock().read_to_string(&mut input)?; + if matches.opt_present("events") { + print_events(&input, opts); + } else if matches.opt_present("dry-run") { + dry_run(&input, opts); + } else { + let mut p = Parser::new_ext(&input, opts); + let stdio = io::stdout(); + let buffer = std::io::BufWriter::with_capacity(1024 * 1024, stdio.lock()); + html::write_html(buffer, &mut p)?; + // Since the program will now terminate and the memory will be returned + // to the operating system anyway, there is no point in tidely cleaning + // up all the datastructures we have used. We shouldn't do this if we'd + // do other things after this, because this is basically intentionally + // leaking data. Skipping cleanup lets us return a bit (~5%) faster. + mem::forget(p); + } + Ok(()) +} diff --git a/vendor/pulldown-cmark-0.7.2/src/parse.rs b/vendor/pulldown-cmark-0.7.2/src/parse.rs new file mode 100644 index 0000000000..ab50679f9e --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/parse.rs @@ -0,0 +1,3138 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// 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. + +//! Tree-based two pass parser. + +use std::cmp::{max, min}; +use std::collections::{HashMap, VecDeque}; +use std::ops::{Index, Range}; + +use unicase::UniCase; + +use crate::linklabel::{scan_link_label_rest, LinkLabel, ReferenceLabel}; +use crate::scanners::*; +use crate::strings::CowStr; +use crate::tree::{Tree, TreeIndex}; + +// Allowing arbitrary depth nested parentheses inside link destinations +// can create denial of service vulnerabilities if we're not careful. +// The simplest countermeasure is to limit their depth, which is +// explicitly allowed by the spec as long as the limit is at least 3: +// https://spec.commonmark.org/0.29/#link-destination +const LINK_MAX_NESTED_PARENS: usize = 5; + +/// Codeblock kind. +#[derive(Clone, Debug, PartialEq)] +pub enum CodeBlockKind<'a> { + Indented, + /// The value contained in the tag describes the language of the code, which may be empty. + Fenced(CowStr<'a>), +} + +impl<'a> CodeBlockKind<'a> { + pub fn is_indented(&self) -> bool { + match *self { + CodeBlockKind::Indented => true, + _ => false, + } + } + + pub fn is_fenced(&self) -> bool { + match *self { + CodeBlockKind::Fenced(_) => true, + _ => false, + } + } +} + +/// Tags for elements that can contain other elements. +#[derive(Clone, Debug, PartialEq)] +pub enum Tag<'a> { + /// A paragraph of text and other inline elements. + Paragraph, + + /// A heading. The field indicates the level of the heading. + Heading(u32), + + BlockQuote, + /// A code block. + CodeBlock(CodeBlockKind<'a>), + + /// A list. If the list is ordered the field indicates the number of the first item. + /// Contains only list items. + List(Option), // TODO: add delim and tight for ast (not needed for html) + /// A list item. + Item, + /// A footnote definition. The value contained is the footnote's label by which it can + /// be referred to. + FootnoteDefinition(CowStr<'a>), + + /// A table. Contains a vector describing the text-alignment for each of its columns. + Table(Vec), + /// A table header. Contains only `TableRow`s. Note that the table body starts immediately + /// after the closure of the `TableHead` tag. There is no `TableBody` tag. + TableHead, + /// A table row. Is used both for header rows as body rows. Contains only `TableCell`s. + TableRow, + TableCell, + + // span-level tags + Emphasis, + Strong, + Strikethrough, + + /// A link. The first field is the link type, the second the destination URL and the third is a title. + Link(LinkType, CowStr<'a>, CowStr<'a>), + + /// An image. The first field is the link type, the second the destination URL and the third is a title. + Image(LinkType, CowStr<'a>, CowStr<'a>), +} + +/// Type specifier for inline links. See [the Tag::Link](enum.Tag.html#variant.Link) for more information. +#[derive(Clone, Debug, PartialEq, Copy)] +pub enum LinkType { + /// Inline link like `[foo](bar)` + Inline, + /// Reference link like `[foo][bar]` + Reference, + /// Reference without destination in the document, but resolved by the broken_link_callback + ReferenceUnknown, + /// Collapsed link like `[foo][]` + Collapsed, + /// Collapsed link without destination in the document, but resolved by the broken_link_callback + CollapsedUnknown, + /// Shortcut link like `[foo]` + Shortcut, + /// Shortcut without destination in the document, but resolved by the broken_link_callback + ShortcutUnknown, + /// Autolink like `` + Autolink, + /// Email address in autolink like `` + Email, +} + +impl LinkType { + fn to_unknown(self) -> Self { + match self { + LinkType::Reference => LinkType::ReferenceUnknown, + LinkType::Collapsed => LinkType::CollapsedUnknown, + LinkType::Shortcut => LinkType::ShortcutUnknown, + _ => unreachable!(), + } + } +} + +/// Markdown events that are generated in a preorder traversal of the document +/// tree, with additional `End` events whenever all of an inner node's children +/// have been visited. +#[derive(Clone, Debug, PartialEq)] +pub enum Event<'a> { + /// Start of a tagged element. Events that are yielded after this event + /// and before its corresponding `End` event are inside this element. + /// Start and end events are guaranteed to be balanced. + Start(Tag<'a>), + /// End of a tagged element. + End(Tag<'a>), + /// A text node. + Text(CowStr<'a>), + /// An inline code node. + Code(CowStr<'a>), + /// An HTML node. + Html(CowStr<'a>), + /// A reference to a footnote with given label, which may or may not be defined + /// by an event with a `Tag::FootnoteDefinition` tag. Definitions and references to them may + /// occur in any order. + FootnoteReference(CowStr<'a>), + /// A soft line break. + SoftBreak, + /// A hard line break. + HardBreak, + /// A horizontal ruler. + Rule, + /// A task list marker, rendered as a checkbox in HTML. Contains a true when it is checked. + TaskListMarker(bool), +} + +/// Table column text alignment. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Alignment { + /// Default text alignment. + None, + Left, + Center, + Right, +} + +bitflags! { + /// Option struct containing flags for enabling extra features + /// that are not part of the CommonMark spec. + pub struct Options: u32 { + const ENABLE_TABLES = 1 << 1; + const ENABLE_FOOTNOTES = 1 << 2; + const ENABLE_STRIKETHROUGH = 1 << 3; + const ENABLE_TASKLISTS = 1 << 4; + } +} + +#[derive(Debug, Default, Clone, Copy)] +struct Item { + start: usize, + end: usize, + body: ItemBody, +} + +#[derive(Debug, PartialEq, Clone, Copy)] +enum ItemBody { + Paragraph, + Text, + SoftBreak, + HardBreak, + + // These are possible inline items, need to be resolved in second pass. + + // repeats, can_open, can_close + MaybeEmphasis(usize, bool, bool), + MaybeCode(usize, bool), // number of backticks, preceeded by backslash + MaybeHtml, + MaybeLinkOpen, + MaybeLinkClose, + MaybeImage, + + // These are inline items after resolution. + Emphasis, + Strong, + Strikethrough, + Code(CowIndex), + Link(LinkIndex), + Image(LinkIndex), + FootnoteReference(CowIndex), + TaskListMarker(bool), // true for checked + + Rule, + Heading(u32), // heading level + FencedCodeBlock(CowIndex), + IndentCodeBlock, + Html, + BlockQuote, + List(bool, u8, u64), // is_tight, list character, list start index + ListItem(usize), // indent level + SynthesizeText(CowIndex), + FootnoteDefinition(CowIndex), + + // Tables + Table(AlignmentIndex), + TableHead, + TableRow, + TableCell, + + // Dummy node at the top of the tree - should not be used otherwise! + Root, +} + +impl<'a> ItemBody { + fn is_inline(&self) -> bool { + match *self { + ItemBody::MaybeEmphasis(..) + | ItemBody::MaybeHtml + | ItemBody::MaybeCode(..) + | ItemBody::MaybeLinkOpen + | ItemBody::MaybeLinkClose + | ItemBody::MaybeImage => true, + _ => false, + } + } +} + +impl<'a> Default for ItemBody { + fn default() -> Self { + ItemBody::Root + } +} + +/// Scanning modes for `Parser`'s `parse_line` method. +#[derive(PartialEq, Eq, Copy, Clone)] +enum TableParseMode { + /// Inside a paragraph, scanning for table headers. + Scan, + /// Inside a table. + Active, + /// Inside a paragraph, not scanning for table headers. + Disabled, +} + +/// State for the first parsing pass. +/// +/// The first pass resolves all block structure, generating an AST. Within a block, items +/// are in a linear chain with potential inline markup identified. +struct FirstPass<'a> { + text: &'a str, + tree: Tree, + begin_list_item: bool, + last_line_blank: bool, + allocs: Allocations<'a>, + options: Options, + list_nesting: usize, +} + +impl<'a> FirstPass<'a> { + fn new(text: &'a str, options: Options) -> FirstPass { + // This is a very naive heuristic for the number of nodes + // we'll need. + let start_capacity = max(128, text.len() / 32); + let tree = Tree::with_capacity(start_capacity); + let begin_list_item = false; + let last_line_blank = false; + let allocs = Allocations::new(); + FirstPass { + text, + tree, + begin_list_item, + last_line_blank, + allocs, + options, + list_nesting: 0, + } + } + + fn run(mut self) -> (Tree, Allocations<'a>) { + let mut ix = 0; + while ix < self.text.len() { + ix = self.parse_block(ix); + } + for _ in 0..self.tree.spine_len() { + self.pop(ix); + } + (self.tree, self.allocs) + } + + /// Returns offset after block. + fn parse_block(&mut self, mut start_ix: usize) -> usize { + let bytes = self.text.as_bytes(); + let mut line_start = LineStart::new(&bytes[start_ix..]); + + let i = scan_containers(&self.tree, &mut line_start); + for _ in i..self.tree.spine_len() { + self.pop(start_ix); + } + + if self.options.contains(Options::ENABLE_FOOTNOTES) { + // finish footnote if it's still open and was preceeded by blank line + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::FootnoteDefinition(..) = self.tree[node_ix].item.body { + if self.last_line_blank { + self.pop(start_ix); + } + } + } + + // Footnote definitions of the form + // [^bar]: + // * anything really + let container_start = start_ix + line_start.bytes_scanned(); + if let Some(bytecount) = self.parse_footnote(container_start) { + start_ix = container_start + bytecount; + start_ix += scan_blank_line(&bytes[start_ix..]).unwrap_or(0); + line_start = LineStart::new(&bytes[start_ix..]); + } + } + + // Process new containers + loop { + let container_start = start_ix + line_start.bytes_scanned(); + if let Some((ch, index, indent)) = line_start.scan_list_marker() { + let after_marker_index = start_ix + line_start.bytes_scanned(); + self.continue_list(container_start, ch, index); + self.tree.append(Item { + start: container_start, + end: after_marker_index, // will get updated later if item not empty + body: ItemBody::ListItem(indent), + }); + self.tree.push(); + if let Some(n) = scan_blank_line(&bytes[after_marker_index..]) { + self.begin_list_item = true; + return after_marker_index + n; + } + if self.options.contains(Options::ENABLE_TASKLISTS) { + if let Some(is_checked) = line_start.scan_task_list_marker() { + self.tree.append(Item { + start: after_marker_index, + end: start_ix + line_start.bytes_scanned(), + body: ItemBody::TaskListMarker(is_checked), + }); + } + } + } else if line_start.scan_blockquote_marker() { + self.finish_list(start_ix); + self.tree.append(Item { + start: container_start, + end: 0, // will get set later + body: ItemBody::BlockQuote, + }); + self.tree.push(); + } else { + break; + } + } + + let ix = start_ix + line_start.bytes_scanned(); + + if let Some(n) = scan_blank_line(&bytes[ix..]) { + if let Some(node_ix) = self.tree.peek_up() { + match self.tree[node_ix].item.body { + ItemBody::BlockQuote => (), + _ => { + if self.begin_list_item { + // A list item can begin with at most one blank line. + self.pop(start_ix); + } + self.last_line_blank = true; + } + } + } + return ix + n; + } + + self.begin_list_item = false; + self.finish_list(start_ix); + + // Save `remaining_space` here to avoid needing to backtrack `line_start` for HTML blocks + let remaining_space = line_start.remaining_space(); + + let indent = line_start.scan_space_upto(4); + if indent == 4 { + let ix = start_ix + line_start.bytes_scanned(); + let remaining_space = line_start.remaining_space(); + return self.parse_indented_code_block(ix, remaining_space); + } + + let ix = start_ix + line_start.bytes_scanned(); + + // HTML Blocks + if bytes[ix] == b'<' { + // Types 1-5 are all detected by one function and all end with the same + // pattern + if let Some(html_end_tag) = get_html_end_tag(&bytes[(ix + 1)..]) { + return self.parse_html_block_type_1_to_5(ix, html_end_tag, remaining_space); + } + + // Detect type 6 + let possible_tag = scan_html_block_tag(&bytes[(ix + 1)..]).1; + if is_html_tag(possible_tag) { + return self.parse_html_block_type_6_or_7(ix, remaining_space); + } + + // Detect type 7 + if let Some(_html_bytes) = scan_html_type_7(&bytes[(ix + 1)..]) { + return self.parse_html_block_type_6_or_7(ix, remaining_space); + } + } + + if let Ok(n) = scan_hrule(&bytes[ix..]) { + return self.parse_hrule(n, ix); + } + + if let Some(atx_size) = scan_atx_heading(&bytes[ix..]) { + return self.parse_atx_heading(ix, atx_size); + } + + // parse refdef + if let Some((bytecount, label, link_def)) = self.parse_refdef_total(ix) { + self.allocs.refdefs.entry(label).or_insert(link_def); + let ix = ix + bytecount; + // try to read trailing whitespace or it will register as a completely blank line + // TODO: shouldn't we do this for all block level items? + return ix + scan_blank_line(&bytes[ix..]).unwrap_or(0); + } + + if let Some((n, fence_ch)) = scan_code_fence(&bytes[ix..]) { + return self.parse_fenced_code_block(ix, indent, fence_ch, n); + } + self.parse_paragraph(ix) + } + + /// Returns the offset of the first line after the table. + /// Assumptions: current focus is a table element and the table header + /// matches the separator line (same number of columns). + fn parse_table(&mut self, table_cols: usize, head_start: usize, body_start: usize) -> usize { + // parse header. this shouldn't fail because we made sure the table header is ok + let (_sep_start, thead_ix) = self.parse_table_row_inner(head_start, table_cols); + self.tree[thead_ix].item.body = ItemBody::TableHead; + + // parse body + let mut ix = body_start; + while let Some((next_ix, _row_ix)) = self.parse_table_row(ix, table_cols) { + ix = next_ix; + } + + self.pop(ix); + ix + } + + /// Call this when containers are taken care of. + /// Returns bytes scanned, row_ix + fn parse_table_row_inner(&mut self, mut ix: usize, row_cells: usize) -> (usize, TreeIndex) { + let bytes = self.text.as_bytes(); + let mut cells = 0; + let mut final_cell_ix = None; + + let row_ix = self.tree.append(Item { + start: ix, + end: 0, // set at end of this function + body: ItemBody::TableRow, + }); + self.tree.push(); + + loop { + ix += scan_ch(&bytes[ix..], b'|'); + ix += scan_whitespace_no_nl(&bytes[ix..]); + + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + ix += eol_bytes; + break; + } + + let cell_ix = self.tree.append(Item { + start: ix, + end: ix, + body: ItemBody::TableCell, + }); + self.tree.push(); + let (next_ix, _brk) = self.parse_line(ix, TableParseMode::Active); + let trailing_whitespace = scan_rev_while(&bytes[..next_ix], is_ascii_whitespace); + + if let Some(cur_ix) = self.tree.cur() { + self.tree[cur_ix].item.end -= trailing_whitespace; + } + + self.tree[cell_ix].item.end = next_ix - trailing_whitespace; + self.tree.pop(); + + ix = next_ix; + cells += 1; + + if cells == row_cells { + final_cell_ix = Some(cell_ix); + } + } + + // fill empty cells if needed + // note: this is where GFM and commonmark-extra diverge. we follow + // GFM here + for _ in cells..row_cells { + self.tree.append(Item { + start: ix, + end: ix, + body: ItemBody::TableCell, + }); + } + + // drop excess cells + if let Some(cell_ix) = final_cell_ix { + self.tree[cell_ix].next = None; + } + + self.pop(ix); + + (ix, row_ix) + } + + /// Returns first offset after the row and the tree index of the row. + fn parse_table_row(&mut self, mut ix: usize, row_cells: usize) -> Option<(usize, TreeIndex)> { + let bytes = self.text.as_bytes(); + let mut line_start = LineStart::new(&bytes[ix..]); + let containers = scan_containers(&self.tree, &mut line_start); + if containers != self.tree.spine_len() { + return None; + } + line_start.scan_all_space(); + ix += line_start.bytes_scanned(); + if scan_paragraph_interrupt(&bytes[ix..]) { + return None; + } + + let (ix, row_ix) = self.parse_table_row_inner(ix, row_cells); + Some((ix, row_ix)) + } + + /// Returns offset of line start after paragraph. + fn parse_paragraph(&mut self, start_ix: usize) -> usize { + let node_ix = self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::Paragraph, + }); + self.tree.push(); + let bytes = self.text.as_bytes(); + + let mut ix = start_ix; + loop { + let scan_mode = if self.options.contains(Options::ENABLE_TABLES) && ix == start_ix { + TableParseMode::Scan + } else { + TableParseMode::Disabled + }; + let (next_ix, brk) = self.parse_line(ix, scan_mode); + + // break out when we find a table + if let Some(Item { + body: ItemBody::Table(alignment_ix), + .. + }) = brk + { + let table_cols = self.allocs[alignment_ix].len(); + self.tree[node_ix].item.body = ItemBody::Table(alignment_ix); + // this clears out any stuff we may have appended - but there may + // be a cleaner way + self.tree[node_ix].child = None; + self.tree.pop(); + self.tree.push(); + return self.parse_table(table_cols, ix, next_ix); + } + + ix = next_ix; + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if !line_start.scan_space(4) { + let ix_new = ix + line_start.bytes_scanned(); + if n_containers == self.tree.spine_len() { + if let Some(ix_setext) = self.parse_setext_heading(ix_new, node_ix) { + if let Some(Item { + start, + body: ItemBody::HardBreak, + .. + }) = brk + { + if bytes[start] == b'\\' { + self.tree.append_text(start, start + 1); + } + } + ix = ix_setext; + break; + } + } + // first check for non-empty lists, then for other interrupts + let suffix = &bytes[ix_new..]; + if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { + break; + } + } + line_start.scan_all_space(); + if line_start.is_at_eol() { + break; + } + ix = next_ix + line_start.bytes_scanned(); + if let Some(item) = brk { + self.tree.append(item); + } + } + + self.pop(ix); + ix + } + + /// Returns end ix of setext_heading on success. + fn parse_setext_heading(&mut self, ix: usize, node_ix: TreeIndex) -> Option { + let bytes = self.text.as_bytes(); + let (n, level) = scan_setext_heading(&bytes[ix..])?; + self.tree[node_ix].item.body = ItemBody::Heading(level); + + // strip trailing whitespace + if let Some(cur_ix) = self.tree.cur() { + self.tree[cur_ix].item.end -= scan_rev_while( + &bytes[..self.tree[cur_ix].item.end], + is_ascii_whitespace_no_nl, + ); + } + + Some(ix + n) + } + + /// Parse a line of input, appending text and items to tree. + /// + /// Returns: index after line and an item representing the break. + fn parse_line(&mut self, start: usize, mode: TableParseMode) -> (usize, Option) { + let bytes = &self.text.as_bytes(); + let mut pipes = 0; + let mut last_pipe_ix = start; + let mut begin_text = start; + + let (final_ix, brk) = iterate_special_bytes(bytes, start, |ix, byte| { + match byte { + b'\n' | b'\r' => { + if let TableParseMode::Active = mode { + return LoopInstruction::BreakAtWith(ix, None); + } + + let mut i = ix; + let eol_bytes = scan_eol(&bytes[ix..]).unwrap(); + if mode == TableParseMode::Scan && pipes > 0 { + // check if we may be parsing a table + let next_line_ix = ix + eol_bytes; + let mut line_start = LineStart::new(&bytes[next_line_ix..]); + if scan_containers(&self.tree, &mut line_start) == self.tree.spine_len() { + let table_head_ix = next_line_ix + line_start.bytes_scanned(); + let (table_head_bytes, alignment) = + scan_table_head(&bytes[table_head_ix..]); + + if table_head_bytes > 0 { + // computing header count from number of pipes + let header_count = + count_header_cols(bytes, pipes, start, last_pipe_ix); + + // make sure they match the number of columns we find in separator line + if alignment.len() == header_count { + let alignment_ix = self.allocs.allocate_alignment(alignment); + let end_ix = table_head_ix + table_head_bytes; + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, // must update later + body: ItemBody::Table(alignment_ix), + }), + ); + } + } + } + } + + let end_ix = ix + eol_bytes; + let trailing_backslashes = scan_rev_while(&bytes[..ix], |b| b == b'\\'); + if trailing_backslashes % 2 == 1 && end_ix < self.text.len() { + i -= 1; + self.tree.append_text(begin_text, i); + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::HardBreak, + }), + ); + } + let trailing_whitespace = + scan_rev_while(&bytes[..ix], is_ascii_whitespace_no_nl); + if trailing_whitespace >= 2 { + i -= trailing_whitespace; + self.tree.append_text(begin_text, i); + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::HardBreak, + }), + ); + } + + self.tree.append_text(begin_text, ix); + LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::SoftBreak, + }), + ) + } + b'\\' => { + if ix + 1 < self.text.len() && is_ascii_punctuation(bytes[ix + 1]) { + self.tree.append_text(begin_text, ix); + if bytes[ix + 1] == b'`' { + let count = 1 + scan_ch_repeat(&bytes[(ix + 2)..], b'`'); + self.tree.append(Item { + start: ix + 1, + end: ix + count + 1, + body: ItemBody::MaybeCode(count, true), + }); + begin_text = ix + 1 + count; + LoopInstruction::ContinueAndSkip(count) + } else { + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(1) + } + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + c @ b'*' | c @ b'_' | c @ b'~' => { + let string_suffix = &self.text[ix..]; + let count = 1 + scan_ch_repeat(&string_suffix.as_bytes()[1..], c); + let can_open = delim_run_can_open(self.text, string_suffix, count, ix); + let can_close = delim_run_can_close(self.text, string_suffix, count, ix); + let is_valid_seq = c != b'~' + || count == 2 && self.options.contains(Options::ENABLE_STRIKETHROUGH); + + if (can_open || can_close) && is_valid_seq { + self.tree.append_text(begin_text, ix); + for i in 0..count { + self.tree.append(Item { + start: ix + i, + end: ix + i + 1, + body: ItemBody::MaybeEmphasis(count - i, can_open, can_close), + }); + } + begin_text = ix + count; + } + LoopInstruction::ContinueAndSkip(count - 1) + } + b'`' => { + self.tree.append_text(begin_text, ix); + let count = 1 + scan_ch_repeat(&bytes[(ix + 1)..], b'`'); + self.tree.append(Item { + start: ix, + end: ix + count, + body: ItemBody::MaybeCode(count, false), + }); + begin_text = ix + count; + LoopInstruction::ContinueAndSkip(count - 1) + } + b'<' => { + // Note: could detect some non-HTML cases and early escape here, but not + // clear that's a win. + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeHtml, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b'!' => { + if ix + 1 < self.text.len() && bytes[ix + 1] == b'[' { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 2, + body: ItemBody::MaybeImage, + }); + begin_text = ix + 2; + LoopInstruction::ContinueAndSkip(1) + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + b'[' => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeLinkOpen, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b']' => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeLinkClose, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b'&' => match scan_entity(&bytes[ix..]) { + (n, Some(value)) => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + n, + body: ItemBody::SynthesizeText(self.allocs.allocate_cow(value)), + }); + begin_text = ix + n; + LoopInstruction::ContinueAndSkip(n - 1) + } + _ => LoopInstruction::ContinueAndSkip(0), + }, + b'|' => { + if let TableParseMode::Active = mode { + LoopInstruction::BreakAtWith(ix, None) + } else { + last_pipe_ix = ix; + pipes += 1; + LoopInstruction::ContinueAndSkip(0) + } + } + _ => LoopInstruction::ContinueAndSkip(0), + } + }); + + if brk.is_none() { + // need to close text at eof + self.tree.append_text(begin_text, final_ix); + } + (final_ix, brk) + } + + /// Check whether we should allow a paragraph interrupt by lists. Only non-empty + /// lists are allowed. + fn interrupt_paragraph_by_list(&self, suffix: &[u8]) -> bool { + scan_listitem(suffix).map_or(false, |(ix, delim, index, _)| { + self.list_nesting > 0 || + // we don't allow interruption by either empty lists or + // numbered lists starting at an index other than 1 + !scan_empty_list(&suffix[ix..]) && (delim == b'*' || delim == b'-' || index == 1) + }) + } + + /// When start_ix is at the beginning of an HTML block of type 1 to 5, + /// this will find the end of the block, adding the block itself to the + /// tree and also keeping track of the lines of HTML within the block. + /// + /// The html_end_tag is the tag that must be found on a line to end the block. + fn parse_html_block_type_1_to_5( + &mut self, + start_ix: usize, + html_end_tag: &str, + mut remaining_space: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_html_line(remaining_space, line_start_ix, ix); + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() { + break; + } + + if (&self.text[line_start_ix..ix]).contains(html_end_tag) { + break; + } + + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + } + ix + } + + /// When start_ix is at the beginning of an HTML block of type 6 or 7, + /// this will consume lines until there is a blank line and keep track of + /// the HTML within the block. + fn parse_html_block_type_6_or_7( + &mut self, + start_ix: usize, + mut remaining_space: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_html_line(remaining_space, line_start_ix, ix); + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() || line_start.is_at_eol() { + break; + } + + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() || scan_blank_line(&bytes[next_line_ix..]).is_some() + { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + } + ix + } + + fn parse_indented_code_block(&mut self, start_ix: usize, mut remaining_space: usize) -> usize { + self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::IndentCodeBlock, + }); + self.tree.push(); + let bytes = self.text.as_bytes(); + let mut last_nonblank_child = None; + let mut last_nonblank_ix = 0; + let mut end_ix = 0; + let mut last_line_blank = false; + + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_code_text(remaining_space, line_start_ix, ix); + // TODO(spec clarification): should we synthesize newline at EOF? + + if !last_line_blank { + last_nonblank_child = self.tree.cur(); + last_nonblank_ix = ix; + end_ix = ix; + } + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() + || !(line_start.scan_space(4) || line_start.is_at_eol()) + { + break; + } + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + last_line_blank = scan_blank_line(&bytes[ix..]).is_some(); + } + + // Trim trailing blank lines. + if let Some(child) = last_nonblank_child { + self.tree[child].next = None; + self.tree[child].item.end = last_nonblank_ix; + } + self.pop(end_ix); + ix + } + + fn parse_fenced_code_block( + &mut self, + start_ix: usize, + indent: usize, + fence_ch: u8, + n_fence_char: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut info_start = start_ix + n_fence_char; + info_start += scan_whitespace_no_nl(&bytes[info_start..]); + // TODO: info strings are typically very short. wouldnt it be faster + // to just do a forward scan here? + let mut ix = info_start + scan_nextline(&bytes[info_start..]); + let info_end = ix - scan_rev_while(&bytes[info_start..ix], is_ascii_whitespace); + let info_string = unescape(&self.text[info_start..info_end]); + self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::FencedCodeBlock(self.allocs.allocate_cow(info_string)), + }); + self.tree.push(); + loop { + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() { + break; + } + line_start.scan_space(indent); + let mut close_line_start = line_start.clone(); + if !close_line_start.scan_space(4) { + let close_ix = ix + close_line_start.bytes_scanned(); + if let Some(n) = scan_closing_code_fence(&bytes[close_ix..], fence_ch, n_fence_char) + { + ix = close_ix + n; + break; + } + } + let remaining_space = line_start.remaining_space(); + ix += line_start.bytes_scanned(); + let next_ix = ix + scan_nextline(&bytes[ix..]); + self.append_code_text(remaining_space, ix, next_ix); + ix = next_ix; + } + + self.pop(ix); + + // try to read trailing whitespace or it will register as a completely blank line + ix + scan_blank_line(&bytes[ix..]).unwrap_or(0) + } + + fn append_code_text(&mut self, remaining_space: usize, start: usize, end: usize) { + if remaining_space > 0 { + let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); + self.tree.append(Item { + start, + end: start, + body: ItemBody::SynthesizeText(cow_ix), + }); + } + if self.text.as_bytes()[end - 2] == b'\r' { + // Normalize CRLF to LF + self.tree.append_text(start, end - 2); + self.tree.append_text(end - 1, end); + } else { + self.tree.append_text(start, end); + } + } + + /// Appends a line of HTML to the tree. + fn append_html_line(&mut self, remaining_space: usize, start: usize, end: usize) { + if remaining_space > 0 { + let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); + self.tree.append(Item { + start, + end: start, + // TODO: maybe this should synthesize to html rather than text? + body: ItemBody::SynthesizeText(cow_ix), + }); + } + if self.text.as_bytes()[end - 2] == b'\r' { + // Normalize CRLF to LF + self.tree.append(Item { + start, + end: end - 2, + body: ItemBody::Html, + }); + self.tree.append(Item { + start: end - 1, + end, + body: ItemBody::Html, + }); + } else { + self.tree.append(Item { + start, + end, + body: ItemBody::Html, + }); + } + } + + /// Pop a container, setting its end. + fn pop(&mut self, ix: usize) { + let cur_ix = self.tree.pop().unwrap(); + self.tree[cur_ix].item.end = ix; + if let ItemBody::List(true, _, _) = self.tree[cur_ix].item.body { + surgerize_tight_list(&mut self.tree, cur_ix); + } + } + + /// Close a list if it's open. Also set loose if last line was blank + fn finish_list(&mut self, ix: usize) { + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::List(_, _, _) = self.tree[node_ix].item.body { + self.pop(ix); + self.list_nesting -= 1; + } + } + if self.last_line_blank { + if let Some(node_ix) = self.tree.peek_grandparent() { + if let ItemBody::List(ref mut is_tight, _, _) = self.tree[node_ix].item.body { + *is_tight = false; + } + } + self.last_line_blank = false; + } + } + + /// Continue an existing list or start a new one if there's not an open + /// list that matches. + fn continue_list(&mut self, start: usize, ch: u8, index: u64) { + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::List(ref mut is_tight, existing_ch, _) = self.tree[node_ix].item.body { + if existing_ch == ch { + if self.last_line_blank { + *is_tight = false; + self.last_line_blank = false; + } + return; + } + } + // TODO: this is not the best choice for end; maybe get end from last list item. + self.finish_list(start); + } + self.tree.append(Item { + start, + end: 0, // will get set later + body: ItemBody::List(true, ch, index), + }); + self.list_nesting += 1; + self.tree.push(); + self.last_line_blank = false; + } + + /// Parse a thematic break. + /// + /// Returns index of start of next line. + fn parse_hrule(&mut self, hrule_size: usize, ix: usize) -> usize { + self.tree.append(Item { + start: ix, + end: ix + hrule_size, + body: ItemBody::Rule, + }); + ix + hrule_size + } + + /// Parse an ATX heading. + /// + /// Returns index of start of next line. + fn parse_atx_heading(&mut self, mut ix: usize, atx_size: usize) -> usize { + let heading_ix = self.tree.append(Item { + start: ix, + end: 0, // set later + body: ItemBody::Heading(atx_size as u32), + }); + ix += atx_size; + // next char is space or eol (guaranteed by scan_atx_heading) + let bytes = self.text.as_bytes(); + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + self.tree[heading_ix].item.end = ix + eol_bytes; + return ix + eol_bytes; + } + // skip leading spaces + let skip_spaces = scan_whitespace_no_nl(&bytes[ix..]); + ix += skip_spaces; + + // now handle the header text + let header_start = ix; + let header_node_idx = self.tree.push(); // so that we can set the endpoint later + ix = self.parse_line(ix, TableParseMode::Disabled).0; + self.tree[header_node_idx].item.end = ix; + + // remove trailing matter from header text + if let Some(cur_ix) = self.tree.cur() { + let header_text = &bytes[header_start..ix]; + let mut limit = header_text + .iter() + .rposition(|&b| !(b == b'\n' || b == b'\r' || b == b' ')) + .map_or(0, |i| i + 1); + let closer = header_text[..limit] + .iter() + .rposition(|&b| b != b'#') + .map_or(0, |i| i + 1); + if closer == 0 { + limit = closer; + } else { + let spaces = scan_rev_while(&header_text[..closer], |b| b == b' '); + if spaces > 0 { + limit = closer - spaces; + } + } + self.tree[cur_ix].item.end = limit + header_start; + } + + self.tree.pop(); + ix + } + + /// Returns the number of bytes scanned on success. + fn parse_footnote(&mut self, start: usize) -> Option { + let bytes = &self.text.as_bytes()[start..]; + if !bytes.starts_with(b"[^") { + return None; + } + let (mut i, label) = self.parse_refdef_label(start + 2)?; + i += 2; + if scan_ch(&bytes[i..], b':') == 0 { + return None; + } + i += 1; + self.finish_list(start); + self.tree.append(Item { + start, + end: 0, // will get set later + // TODO: check whether the label here is strictly necessary + body: ItemBody::FootnoteDefinition(self.allocs.allocate_cow(label)), + }); + self.tree.push(); + Some(i) + } + + /// Tries to parse a reference label, which can be interrupted by new blocks. + /// On success, returns the number of bytes of the label and the label itself. + fn parse_refdef_label(&self, start: usize) -> Option<(usize, CowStr<'a>)> { + scan_link_label_rest(&self.text[start..], &|bytes| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(&self.tree, &mut line_start); + let bytes_scanned = line_start.bytes_scanned(); + + let suffix = &bytes[bytes_scanned..]; + if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { + None + } else { + Some(bytes_scanned) + } + }) + } + + /// Returns number of bytes scanned, label and definition on success. + fn parse_refdef_total(&mut self, start: usize) -> Option<(usize, LinkLabel<'a>, LinkDef<'a>)> { + let bytes = &self.text.as_bytes()[start..]; + if scan_ch(bytes, b'[') == 0 { + return None; + } + let (mut i, label) = self.parse_refdef_label(start + 1)?; + i += 1; + if scan_ch(&bytes[i..], b':') == 0 { + return None; + } + i += 1; + let (bytecount, link_def) = self.scan_refdef(start + i)?; + Some((bytecount + i, UniCase::new(label), link_def)) + } + + /// Returns number of bytes and number of newlines + fn scan_refdef_space(&self, bytes: &[u8], mut i: usize) -> Option<(usize, usize)> { + let mut newlines = 0; + loop { + let whitespaces = scan_whitespace_no_nl(&bytes[i..]); + i += whitespaces; + if let Some(eol_bytes) = scan_eol(&bytes[i..]) { + i += eol_bytes; + newlines += 1; + if newlines > 1 { + return None; + } + } else { + break; + } + let mut line_start = LineStart::new(&bytes[i..]); + if self.tree.spine_len() != scan_containers(&self.tree, &mut line_start) { + return None; + } + i += line_start.bytes_scanned(); + } + Some((i, newlines)) + } + + /// Returns # of bytes and definition. + /// Assumes the label of the reference including colon has already been scanned. + fn scan_refdef(&self, start: usize) -> Option<(usize, LinkDef<'a>)> { + let bytes = self.text.as_bytes(); + + // whitespace between label and url (including up to one newline) + let (mut i, _newlines) = self.scan_refdef_space(bytes, start)?; + + // scan link dest + let (dest_length, dest) = scan_link_dest(self.text, i, 1)?; + if dest_length == 0 { + return None; + } + let dest = unescape(dest); + i += dest_length; + + // no title + let mut backup = (i - start, LinkDef { dest, title: None }); + + // scan whitespace between dest and label + let (mut i, newlines) = + if let Some((new_i, mut newlines)) = self.scan_refdef_space(bytes, i) { + if i == self.text.len() { + newlines += 1; + } + if new_i == i && newlines == 0 { + return None; + } + if newlines > 1 { + return Some(backup); + }; + (new_i, newlines) + } else { + return Some(backup); + }; + + // scan title + // if this fails but newline == 1, return also a refdef without title + if let Some((title_length, title)) = scan_refdef_title(&self.text[i..]) { + i += title_length; + backup.1.title = Some(unescape(title)); + } else if newlines > 0 { + return Some(backup); + } else { + return None; + }; + + // scan EOL + if let Some(bytes) = scan_blank_line(&bytes[i..]) { + backup.0 = i + bytes - start; + Some(backup) + } else if newlines > 0 { + Some(backup) + } else { + None + } + } +} + +/// Returns number of containers scanned. +fn scan_containers(tree: &Tree, line_start: &mut LineStart) -> usize { + let mut i = 0; + for &node_ix in tree.walk_spine() { + match tree[node_ix].item.body { + ItemBody::BlockQuote => { + let save = line_start.clone(); + if !line_start.scan_blockquote_marker() { + *line_start = save; + break; + } + } + ItemBody::ListItem(indent) => { + let save = line_start.clone(); + if !line_start.scan_space(indent) { + if !line_start.is_at_eol() { + *line_start = save; + break; + } + } + } + _ => (), + } + i += 1; + } + i +} + +/// Computes the number of header columns in a table line by computing the number of dividing pipes +/// that aren't followed or preceeded by whitespace. +fn count_header_cols( + bytes: &[u8], + mut pipes: usize, + mut start: usize, + last_pipe_ix: usize, +) -> usize { + // was first pipe preceeded by whitespace? if so, subtract one + start += scan_whitespace_no_nl(&bytes[start..]); + if bytes[start] == b'|' { + pipes -= 1; + } + + // was last pipe followed by whitespace? if so, sub one + if scan_blank_line(&bytes[(last_pipe_ix + 1)..]).is_some() { + pipes + } else { + pipes + 1 + } +} + +impl<'a> Tree { + fn append_text(&mut self, start: usize, end: usize) { + if end > start { + if let Some(ix) = self.cur() { + if ItemBody::Text == self[ix].item.body && self[ix].item.end == start { + self[ix].item.end = end; + return; + } + } + self.append(Item { + start, + end, + body: ItemBody::Text, + }); + } + } +} + +/// Determines whether the delimiter run starting at given index is +/// left-flanking, as defined by the commonmark spec (and isn't intraword +/// for _ delims). +/// suffix is &s[ix..], which is passed in as an optimization, since taking +/// a string subslice is O(n). +fn delim_run_can_open(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { + let next_char = if let Some(c) = suffix.chars().nth(run_len) { + c + } else { + return false; + }; + if next_char.is_whitespace() { + return false; + } + if ix == 0 { + return true; + } + let delim = suffix.chars().next().unwrap(); + if delim == '*' && !is_punctuation(next_char) { + return true; + } + + let prev_char = s[..ix].chars().last().unwrap(); + + prev_char.is_whitespace() || is_punctuation(prev_char) +} + +/// Determines whether the delimiter run starting at given index is +/// left-flanking, as defined by the commonmark spec (and isn't intraword +/// for _ delims) +fn delim_run_can_close(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { + if ix == 0 { + return false; + } + let prev_char = s[..ix].chars().last().unwrap(); + if prev_char.is_whitespace() { + return false; + } + let next_char = if let Some(c) = suffix.chars().nth(run_len) { + c + } else { + return true; + }; + let delim = suffix.chars().next().unwrap(); + if delim == '*' && !is_punctuation(prev_char) { + return true; + } + + next_char.is_whitespace() || is_punctuation(next_char) +} + +/// Checks whether we should break a paragraph on the given input. +/// Note: lists are dealt with in `interrupt_paragraph_by_list`, because determing +/// whether to break on a list requires additional context. +fn scan_paragraph_interrupt(bytes: &[u8]) -> bool { + if scan_eol(bytes).is_some() + || scan_hrule(bytes).is_ok() + || scan_atx_heading(bytes).is_some() + || scan_code_fence(bytes).is_some() + || scan_blockquote_start(bytes).is_some() + { + return true; + } + bytes.starts_with(b"<") + && (get_html_end_tag(&bytes[1..]).is_some() + || is_html_tag(scan_html_block_tag(&bytes[1..]).1)) +} + +/// Assumes `text_bytes` is preceded by `<`. +fn get_html_end_tag(text_bytes: &[u8]) -> Option<&'static str> { + static BEGIN_TAGS: &[&[u8]; 3] = &[b"pre", b"style", b"script"]; + static ST_BEGIN_TAGS: &[&[u8]; 3] = &[b"!--", b"?", b"![CDATA["]; + + for (beg_tag, end_tag) in BEGIN_TAGS + .iter() + .zip(["", "", ""].iter()) + { + let tag_len = beg_tag.len(); + + if text_bytes.len() < tag_len { + // begin tags are increasing in size + break; + } + + if !text_bytes[..tag_len].eq_ignore_ascii_case(beg_tag) { + continue; + } + + // Must either be the end of the line... + if text_bytes.len() == tag_len { + return Some(end_tag); + } + + // ...or be followed by whitespace, newline, or '>'. + let s = text_bytes[tag_len]; + if is_ascii_whitespace(s) || s == b'>' { + return Some(end_tag); + } + } + + for (beg_tag, end_tag) in ST_BEGIN_TAGS.iter().zip(["-->", "?>", "]]>"].iter()) { + if text_bytes.starts_with(beg_tag) { + return Some(end_tag); + } + } + + if text_bytes.len() > 1 + && text_bytes[0] == b'!' + && text_bytes[1] >= b'A' + && text_bytes[1] <= b'Z' + { + Some(">") + } else { + None + } +} + +#[derive(Copy, Clone, Debug)] +struct InlineEl { + start: TreeIndex, // offset of tree node + count: usize, + c: u8, // b'*' or b'_' + both: bool, // can both open and close +} + +#[derive(Debug, Clone, Default)] +struct InlineStack { + stack: Vec, + // Lower bounds for matching indices in the stack. For example + // a strikethrough delimiter will never match with any element + // in the stack with index smaller than + // `lower_bounds[InlineStack::TILDES]`. + lower_bounds: [usize; 7], +} + +impl InlineStack { + /// These are indices into the lower bounds array. + /// Not both refers to the property that the delimiter can not both + /// be opener as a closer. + const UNDERSCORE_NOT_BOTH: usize = 0; + const ASTERISK_NOT_BOTH: usize = 1; + const ASTERISK_BASE: usize = 2; + const TILDES: usize = 5; + const UNDERSCORE_BOTH: usize = 6; + + fn pop_all(&mut self, tree: &mut Tree) { + for el in self.stack.drain(..) { + for i in 0..el.count { + tree[el.start + i].item.body = ItemBody::Text; + } + } + self.lower_bounds = [0; 7]; + } + + fn get_lowerbound(&self, c: u8, count: usize, both: bool) -> usize { + if c == b'_' { + if both { + self.lower_bounds[InlineStack::UNDERSCORE_BOTH] + } else { + self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] + } + } else if c == b'*' { + let mod3_lower = self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3]; + if both { + mod3_lower + } else { + min( + mod3_lower, + self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH], + ) + } + } else { + self.lower_bounds[InlineStack::TILDES] + } + } + + fn set_lowerbound(&mut self, c: u8, count: usize, both: bool, new_bound: usize) { + if c == b'_' { + if both { + self.lower_bounds[InlineStack::UNDERSCORE_BOTH] = new_bound; + } else { + self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] = new_bound; + } + } else if c == b'*' { + self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3] = new_bound; + if !both { + self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH] = new_bound; + } + } else { + self.lower_bounds[InlineStack::TILDES] = new_bound; + } + } + + fn find_match( + &mut self, + tree: &mut Tree, + c: u8, + count: usize, + both: bool, + ) -> Option { + let lowerbound = min(self.stack.len(), self.get_lowerbound(c, count, both)); + let res = self.stack[lowerbound..] + .iter() + .cloned() + .enumerate() + .rfind(|(_, el)| { + el.c == c && (!both && !el.both || (count + el.count) % 3 != 0 || count % 3 == 0) + }); + + if let Some((matching_ix, matching_el)) = res { + let matching_ix = matching_ix + lowerbound; + for el in &self.stack[(matching_ix + 1)..] { + for i in 0..el.count { + tree[el.start + i].item.body = ItemBody::Text; + } + } + self.stack.truncate(matching_ix); + Some(matching_el) + } else { + self.set_lowerbound(c, count, both, self.stack.len()); + None + } + } + + fn push(&mut self, el: InlineEl) { + self.stack.push(el) + } +} + +#[derive(Debug, Clone)] +enum RefScan<'a> { + // label, next node index, source ix of label end + LinkLabel(CowStr<'a>, Option, usize), + // contains next node index + Collapsed(Option), + Failed, +} + +/// Skips forward within a block to a node which spans (ends inclusive) the given +/// index into the source. +fn scan_nodes_to_ix( + tree: &Tree, + mut node: Option, + ix: usize, +) -> Option { + while let Some(node_ix) = node { + if tree[node_ix].item.end <= ix { + node = tree[node_ix].next; + } else { + break; + } + } + node +} + +/// Scans an inline link label, which cannot be interrupted. +/// Returns number of bytes (including brackets) and label on success. +fn scan_link_label<'text, 'tree>( + tree: &'tree Tree, + text: &'text str, +) -> Option<(usize, ReferenceLabel<'text>)> { + let bytes = &text.as_bytes(); + if bytes.len() < 2 || bytes[0] != b'[' { + return None; + } + let linebreak_handler = |bytes: &[u8]| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(tree, &mut line_start); + Some(line_start.bytes_scanned()) + }; + let pair = if b'^' == bytes[1] { + let (byte_index, cow) = scan_link_label_rest(&text[2..], &linebreak_handler)?; + (byte_index + 2, ReferenceLabel::Footnote(cow)) + } else { + let (byte_index, cow) = scan_link_label_rest(&text[1..], &linebreak_handler)?; + (byte_index + 1, ReferenceLabel::Link(cow)) + }; + Some(pair) +} + +fn scan_reference<'a, 'b>( + tree: &'a Tree, + text: &'b str, + cur: Option, +) -> RefScan<'b> { + let cur_ix = match cur { + None => return RefScan::Failed, + Some(cur_ix) => cur_ix, + }; + let start = tree[cur_ix].item.start; + let tail = &text.as_bytes()[start..]; + + if tail.starts_with(b"[]") { + let closing_node = tree[cur_ix].next.unwrap(); + RefScan::Collapsed(tree[closing_node].next) + } else if let Some((ix, ReferenceLabel::Link(label))) = scan_link_label(tree, &text[start..]) { + let next_node = scan_nodes_to_ix(tree, cur, start + ix); + RefScan::LinkLabel(label, next_node, start + ix) + } else { + RefScan::Failed + } +} + +#[derive(Clone, Default)] +struct LinkStack { + inner: Vec, + disabled_ix: usize, +} + +impl LinkStack { + fn push(&mut self, el: LinkStackEl) { + self.inner.push(el); + } + + fn pop(&mut self) -> Option { + let el = self.inner.pop(); + self.disabled_ix = std::cmp::min(self.disabled_ix, self.inner.len()); + el + } + + fn clear(&mut self) { + self.inner.clear(); + self.disabled_ix = 0; + } + + fn disable_all_links(&mut self) { + for el in &mut self.inner[self.disabled_ix..] { + if el.ty == LinkStackTy::Link { + el.ty = LinkStackTy::Disabled; + } + } + self.disabled_ix = self.inner.len(); + } +} + +#[derive(Clone, Debug)] +struct LinkStackEl { + node: TreeIndex, + ty: LinkStackTy, +} + +#[derive(PartialEq, Clone, Debug)] +enum LinkStackTy { + Link, + Image, + Disabled, +} + +#[derive(Clone)] +struct LinkDef<'a> { + dest: CowStr<'a>, + title: Option>, +} + +/// Tracks tree indices of code span delimiters of each length. It should prevent +/// quadratic scanning behaviours by providing (amortized) constant time lookups. +struct CodeDelims { + inner: HashMap>, + seen_first: bool, +} + +impl CodeDelims { + fn new() -> Self { + Self { + inner: Default::default(), + seen_first: false, + } + } + + fn insert(&mut self, count: usize, ix: TreeIndex) { + if self.seen_first { + self.inner + .entry(count) + .or_insert_with(Default::default) + .push_back(ix); + } else { + // Skip the first insert, since that delimiter will always + // be an opener and not a closer. + self.seen_first = true; + } + } + + fn is_populated(&self) -> bool { + !self.inner.is_empty() + } + + fn find(&mut self, open_ix: TreeIndex, count: usize) -> Option { + while let Some(ix) = self.inner.get_mut(&count)?.pop_front() { + if ix > open_ix { + return Some(ix); + } + } + None + } + + fn clear(&mut self) { + self.inner.clear(); + self.seen_first = false; + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct LinkIndex(usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct CowIndex(usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct AlignmentIndex(usize); + +#[derive(Clone)] +struct Allocations<'a> { + refdefs: HashMap, LinkDef<'a>>, + links: Vec<(LinkType, CowStr<'a>, CowStr<'a>)>, + cows: Vec>, + alignments: Vec>, +} + +impl<'a> Allocations<'a> { + fn new() -> Self { + Self { + refdefs: HashMap::new(), + links: Vec::with_capacity(128), + cows: Vec::new(), + alignments: Vec::new(), + } + } + + fn allocate_cow(&mut self, cow: CowStr<'a>) -> CowIndex { + let ix = self.cows.len(); + self.cows.push(cow); + CowIndex(ix) + } + + fn allocate_link(&mut self, ty: LinkType, url: CowStr<'a>, title: CowStr<'a>) -> LinkIndex { + let ix = self.links.len(); + self.links.push((ty, url, title)); + LinkIndex(ix) + } + + fn allocate_alignment(&mut self, alignment: Vec) -> AlignmentIndex { + let ix = self.alignments.len(); + self.alignments.push(alignment); + AlignmentIndex(ix) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = CowStr<'a>; + + fn index(&self, ix: CowIndex) -> &Self::Output { + self.cows.index(ix.0) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = (LinkType, CowStr<'a>, CowStr<'a>); + + fn index(&self, ix: LinkIndex) -> &Self::Output { + self.links.index(ix.0) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = Vec; + + fn index(&self, ix: AlignmentIndex) -> &Self::Output { + self.alignments.index(ix.0) + } +} + +/// A struct containing information on the reachability of certain inline HTML +/// elements. In particular, for cdata elements (` { + text: &'a str, + tree: Tree, + allocs: Allocations<'a>, + broken_link_callback: Option<&'a dyn Fn(&str, &str) -> Option<(String, String)>>, + html_scan_guard: HtmlScanGuard, + + // used by inline passes. store them here for reuse + inline_stack: InlineStack, + link_stack: LinkStack, +} + +impl<'a> Parser<'a> { + /// Creates a new event iterator for a markdown string without any options enabled. + pub fn new(text: &'a str) -> Parser<'a> { + Parser::new_ext(text, Options::empty()) + } + + /// Creates a new event iterator for a markdown string with given options. + pub fn new_ext(text: &'a str, options: Options) -> Parser<'a> { + Parser::new_with_broken_link_callback(text, options, None) + } + + /// In case the parser encounters any potential links that have a broken + /// reference (e.g `[foo]` when there is no `[foo]: ` entry at the bottom) + /// the provided callback will be called with the reference name, + /// and the returned pair will be used as the link name and title if it is not + /// `None`. + pub fn new_with_broken_link_callback( + text: &'a str, + options: Options, + broken_link_callback: Option<&'a dyn Fn(&str, &str) -> Option<(String, String)>>, + ) -> Parser<'a> { + let first_pass = FirstPass::new(text, options); + let (mut tree, allocs) = first_pass.run(); + tree.reset(); + let inline_stack = Default::default(); + let link_stack = Default::default(); + let html_scan_guard = Default::default(); + Parser { + text, + tree, + allocs, + broken_link_callback, + inline_stack, + link_stack, + html_scan_guard, + } + } + + /// Handle inline markup. + /// + /// When the parser encounters any item indicating potential inline markup, all + /// inline markup passes are run on the remainder of the chain. + /// + /// Note: there's some potential for optimization here, but that's future work. + fn handle_inline(&mut self) { + self.handle_inline_pass1(); + self.handle_emphasis(); + } + + /// Handle inline HTML, code spans, and links. + /// + /// This function handles both inline HTML and code spans, because they have + /// the same precedence. It also handles links, even though they have lower + /// precedence, because the URL of links must not be processed. + fn handle_inline_pass1(&mut self) { + let mut code_delims = CodeDelims::new(); + let mut cur = self.tree.cur(); + let mut prev = None; + + let block_end = self.tree[self.tree.peek_up().unwrap()].item.end; + let block_text = &self.text[..block_end]; + + while let Some(mut cur_ix) = cur { + match self.tree[cur_ix].item.body { + ItemBody::MaybeHtml => { + let next = self.tree[cur_ix].next; + let autolink = if let Some(next_ix) = next { + scan_autolink(block_text, self.tree[next_ix].item.start) + } else { + None + }; + + if let Some((ix, uri, link_type)) = autolink { + let node = scan_nodes_to_ix(&self.tree, next, ix); + let text_node = self.tree.create_node(Item { + start: self.tree[cur_ix].item.start + 1, + end: ix - 1, + body: ItemBody::Text, + }); + let link_ix = self.allocs.allocate_link(link_type, uri, "".into()); + self.tree[cur_ix].item.body = ItemBody::Link(link_ix); + self.tree[cur_ix].item.end = ix; + self.tree[cur_ix].next = node; + self.tree[cur_ix].child = Some(text_node); + prev = cur; + cur = node; + if let Some(node_ix) = cur { + self.tree[node_ix].item.start = max(self.tree[node_ix].item.start, ix); + } + continue; + } else { + let inline_html = if let Some(next_ix) = next { + self.scan_inline_html( + block_text.as_bytes(), + self.tree[next_ix].item.start, + ) + } else { + None + }; + if let Some(ix) = inline_html { + let node = scan_nodes_to_ix(&self.tree, next, ix); + self.tree[cur_ix].item.body = ItemBody::Html; + self.tree[cur_ix].item.end = ix; + self.tree[cur_ix].next = node; + prev = cur; + cur = node; + if let Some(node_ix) = cur { + self.tree[node_ix].item.start = + max(self.tree[node_ix].item.start, ix); + } + continue; + } + } + self.tree[cur_ix].item.body = ItemBody::Text; + } + ItemBody::MaybeCode(mut search_count, preceded_by_backslash) => { + if preceded_by_backslash { + search_count -= 1; + if search_count == 0 { + self.tree[cur_ix].item.body = ItemBody::Text; + prev = cur; + cur = self.tree[cur_ix].next; + continue; + } + } + + if code_delims.is_populated() { + // we have previously scanned all codeblock delimiters, + // so we can reuse that work + if let Some(scan_ix) = code_delims.find(cur_ix, search_count) { + self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); + } else { + self.tree[cur_ix].item.body = ItemBody::Text; + } + } else { + // we haven't previously scanned all codeblock delimiters, + // so walk the AST + let mut scan = if search_count > 0 { + self.tree[cur_ix].next + } else { + None + }; + while let Some(scan_ix) = scan { + if let ItemBody::MaybeCode(delim_count, _) = + self.tree[scan_ix].item.body + { + if search_count == delim_count { + self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); + code_delims.clear(); + break; + } else { + code_delims.insert(delim_count, scan_ix); + } + } + scan = self.tree[scan_ix].next; + } + if scan == None { + self.tree[cur_ix].item.body = ItemBody::Text; + } + } + } + ItemBody::MaybeLinkOpen => { + self.tree[cur_ix].item.body = ItemBody::Text; + self.link_stack.push(LinkStackEl { + node: cur_ix, + ty: LinkStackTy::Link, + }); + } + ItemBody::MaybeImage => { + self.tree[cur_ix].item.body = ItemBody::Text; + self.link_stack.push(LinkStackEl { + node: cur_ix, + ty: LinkStackTy::Image, + }); + } + ItemBody::MaybeLinkClose => { + self.tree[cur_ix].item.body = ItemBody::Text; + if let Some(tos) = self.link_stack.pop() { + if tos.ty == LinkStackTy::Disabled { + continue; + } + let next = self.tree[cur_ix].next; + if let Some((next_ix, url, title)) = + self.scan_inline_link(block_text, self.tree[cur_ix].item.end, next) + { + let next_node = scan_nodes_to_ix(&self.tree, next, next_ix); + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + cur = Some(tos.node); + cur_ix = tos.node; + let link_ix = self.allocs.allocate_link(LinkType::Inline, url, title); + self.tree[cur_ix].item.body = if tos.ty == LinkStackTy::Image { + ItemBody::Image(link_ix) + } else { + ItemBody::Link(link_ix) + }; + self.tree[cur_ix].child = self.tree[cur_ix].next; + self.tree[cur_ix].next = next_node; + self.tree[cur_ix].item.end = next_ix; + if let Some(next_node_ix) = next_node { + self.tree[next_node_ix].item.start = + max(self.tree[next_node_ix].item.start, next_ix); + } + + if tos.ty == LinkStackTy::Link { + self.link_stack.disable_all_links(); + } + } else { + // ok, so its not an inline link. maybe it is a reference + // to a defined link? + let scan_result = scan_reference(&self.tree, block_text, next); + let (node_after_link, link_type) = match scan_result { + // [label][reference] + RefScan::LinkLabel(_, next_node, _) => { + (next_node, LinkType::Reference) + } + // [] + RefScan::Collapsed(next_node) => (next_node, LinkType::Collapsed), + // [shortcut] + // + // [shortcut]: /blah + RefScan::Failed => (next, LinkType::Shortcut), + }; + + // (label, source_ix end) + let label: Option<(ReferenceLabel<'a>, usize)> = match scan_result { + RefScan::LinkLabel(l, _, end_ix) => { + Some((ReferenceLabel::Link(l), end_ix)) + } + RefScan::Collapsed(..) | RefScan::Failed => { + // No label? maybe it is a shortcut reference + let label_start = self.tree[tos.node].item.end - 1; + scan_link_label( + &self.tree, + &self.text[label_start..self.tree[cur_ix].item.end], + ) + .map(|(ix, label)| (label, label_start + ix)) + } + }; + + // see if it's a footnote reference + if let Some((ReferenceLabel::Footnote(l), end)) = label { + self.tree[tos.node].next = node_after_link; + self.tree[tos.node].child = None; + self.tree[tos.node].item.body = + ItemBody::FootnoteReference(self.allocs.allocate_cow(l)); + self.tree[tos.node].item.end = end; + prev = Some(tos.node); + cur = node_after_link; + self.link_stack.clear(); + continue; + } else if let Some((ReferenceLabel::Link(link_label), end)) = label { + let type_url_title = self + .allocs + .refdefs + .get(&UniCase::new(link_label.as_ref().into())) + .map(|matching_def| { + // found a matching definition! + let title = matching_def + .title + .as_ref() + .cloned() + .unwrap_or_else(|| "".into()); + let url = matching_def.dest.clone(); + (link_type, url, title) + }) + .or_else(|| { + self.broken_link_callback + .and_then(|callback| { + // looked for matching definition, but didn't find it. try to fix + // link with callback, if it is defined + callback(link_label.as_ref(), link_label.as_ref()) + }) + .map(|(url, title)| { + (link_type.to_unknown(), url.into(), title.into()) + }) + }); + + if let Some((def_link_type, url, title)) = type_url_title { + let link_ix = + self.allocs.allocate_link(def_link_type, url, title); + self.tree[tos.node].item.body = if tos.ty == LinkStackTy::Image + { + ItemBody::Image(link_ix) + } else { + ItemBody::Link(link_ix) + }; + let label_node = self.tree[tos.node].next; + + // lets do some tree surgery to add the link to the tree + // 1st: skip the label node and close node + self.tree[tos.node].next = node_after_link; + + // then, if it exists, add the label node as a child to the link node + if label_node != cur { + self.tree[tos.node].child = label_node; + + // finally: disconnect list of children + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + } + + self.tree[tos.node].item.end = end; + + // set up cur so next node will be node_after_link + cur = Some(tos.node); + cur_ix = tos.node; + + if tos.ty == LinkStackTy::Link { + self.link_stack.disable_all_links(); + } + } + } + } + } + } + _ => (), + } + prev = cur; + cur = self.tree[cur_ix].next; + } + self.link_stack.clear(); + } + + fn handle_emphasis(&mut self) { + let mut prev = None; + let mut prev_ix: TreeIndex; + let mut cur = self.tree.cur(); + while let Some(mut cur_ix) = cur { + if let ItemBody::MaybeEmphasis(mut count, can_open, can_close) = + self.tree[cur_ix].item.body + { + let c = self.text.as_bytes()[self.tree[cur_ix].item.start]; + let both = can_open && can_close; + if can_close { + while let Some(el) = + self.inline_stack.find_match(&mut self.tree, c, count, both) + { + // have a match! + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + let match_count = min(count, el.count); + // start, end are tree node indices + let mut end = cur_ix - 1; + let mut start = el.start + el.count; + + // work from the inside out + while start > el.start + el.count - match_count { + let (inc, ty) = if c == b'~' { + (2, ItemBody::Strikethrough) + } else if start > el.start + el.count - match_count + 1 { + (2, ItemBody::Strong) + } else { + (1, ItemBody::Emphasis) + }; + + let root = start - inc; + end = end + inc; + self.tree[root].item.body = ty; + self.tree[root].item.end = self.tree[end].item.end; + self.tree[root].child = Some(start); + self.tree[root].next = None; + start = root; + } + + // set next for top most emph level + prev_ix = el.start + el.count - match_count; + prev = Some(prev_ix); + cur = self.tree[cur_ix + match_count - 1].next; + self.tree[prev_ix].next = cur; + + if el.count > match_count { + self.inline_stack.push(InlineEl { + start: el.start, + count: el.count - match_count, + c: el.c, + both, + }) + } + count -= match_count; + if count > 0 { + cur_ix = cur.unwrap(); + } else { + break; + } + } + } + if count > 0 { + if can_open { + self.inline_stack.push(InlineEl { + start: cur_ix, + count, + c, + both, + }); + } else { + for i in 0..count { + self.tree[cur_ix + i].item.body = ItemBody::Text; + } + } + prev_ix = cur_ix + count - 1; + prev = Some(prev_ix); + cur = self.tree[prev_ix].next; + } + } else { + prev = cur; + cur = self.tree[cur_ix].next; + } + } + self.inline_stack.pop_all(&mut self.tree); + } + + /// Returns next byte index, url and title. + fn scan_inline_link( + &self, + underlying: &'a str, + mut ix: usize, + node: Option, + ) -> Option<(usize, CowStr<'a>, CowStr<'a>)> { + if scan_ch(&underlying.as_bytes()[ix..], b'(') == 0 { + return None; + } + ix += 1; + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + + let (dest_length, dest) = scan_link_dest(underlying, ix, LINK_MAX_NESTED_PARENS)?; + let dest = unescape(dest); + ix += dest_length; + + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + + let title = if let Some((bytes_scanned, t)) = self.scan_link_title(underlying, ix, node) { + ix += bytes_scanned; + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + t + } else { + "".into() + }; + if scan_ch(&underlying.as_bytes()[ix..], b')') == 0 { + return None; + } + ix += 1; + + Some((ix, dest, title)) + } + + // returns (bytes scanned, title cow) + fn scan_link_title( + &self, + text: &'a str, + start_ix: usize, + node: Option, + ) -> Option<(usize, CowStr<'a>)> { + let bytes = text.as_bytes(); + let open = match bytes.get(start_ix) { + Some(b @ b'\'') | Some(b @ b'\"') | Some(b @ b'(') => *b, + _ => return None, + }; + let close = if open == b'(' { b')' } else { open }; + + let mut title = String::new(); + let mut mark = start_ix + 1; + let mut i = start_ix + 1; + + while i < bytes.len() { + let c = bytes[i]; + + if c == close { + let cow = if mark == 1 { + (i - start_ix + 1, text[mark..i].into()) + } else { + title.push_str(&text[mark..i]); + (i - start_ix + 1, title.into()) + }; + + return Some(cow); + } + if c == open { + return None; + } + + if c == b'\n' || c == b'\r' { + if let Some(node_ix) = scan_nodes_to_ix(&self.tree, node, i + 1) { + if self.tree[node_ix].item.start > i { + title.push_str(&text[mark..i]); + title.push('\n'); + i = self.tree[node_ix].item.start; + mark = i; + continue; + } + } + } + if c == b'&' { + if let (n, Some(value)) = scan_entity(&bytes[i..]) { + title.push_str(&text[mark..i]); + title.push_str(&value); + i += n; + mark = i; + continue; + } + } + if c == b'\\' && i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) { + title.push_str(&text[mark..i]); + i += 1; + mark = i; + } + + i += 1; + } + + None + } + + /// Make a code span. + /// + /// Both `open` and `close` are matching MaybeCode items. + fn make_code_span(&mut self, open: TreeIndex, close: TreeIndex, preceding_backslash: bool) { + let first_ix = open + 1; + let last_ix = close - 1; + let bytes = self.text.as_bytes(); + let mut span_start = self.tree[open].item.end; + let mut span_end = self.tree[close].item.start; + let mut buf: Option = None; + + // detect all-space sequences, since they are kept as-is as of commonmark 0.29 + if !bytes[span_start..span_end].iter().all(|&b| b == b' ') { + let opening = match bytes[span_start] { + b' ' | b'\r' | b'\n' => true, + _ => false, + }; + let closing = match bytes[span_end - 1] { + b' ' | b'\r' | b'\n' => true, + _ => false, + }; + let drop_enclosing_whitespace = opening && closing; + + if drop_enclosing_whitespace { + span_start += 1; + if span_start < span_end { + span_end -= 1; + } + } + + let mut ix = first_ix; + + while ix < close { + if let ItemBody::HardBreak | ItemBody::SoftBreak = self.tree[ix].item.body { + if drop_enclosing_whitespace { + // check whether break should be ignored + if ix == first_ix { + ix = ix + 1; + span_start = min(span_end, self.tree[ix].item.start); + continue; + } else if ix == last_ix && last_ix > first_ix { + ix = ix + 1; + continue; + } + } + + let end = bytes[self.tree[ix].item.start..] + .iter() + .position(|&b| b == b'\r' || b == b'\n') + .unwrap() + + self.tree[ix].item.start; + if let Some(ref mut buf) = buf { + buf.push_str(&self.text[self.tree[ix].item.start..end]); + buf.push(' '); + } else { + let mut new_buf = String::with_capacity(span_end - span_start); + new_buf.push_str(&self.text[span_start..end]); + new_buf.push(' '); + buf = Some(new_buf); + } + } else if let Some(ref mut buf) = buf { + let end = if ix == last_ix { + span_end + } else { + self.tree[ix].item.end + }; + buf.push_str(&self.text[self.tree[ix].item.start..end]); + } + ix = ix + 1; + } + } + + let cow = if let Some(buf) = buf { + buf.into() + } else { + self.text[span_start..span_end].into() + }; + if preceding_backslash { + self.tree[open].item.body = ItemBody::Text; + self.tree[open].item.end = self.tree[open].item.start + 1; + self.tree[open].next = Some(close); + self.tree[close].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); + self.tree[close].item.start = self.tree[open].item.start + 1; + } else { + self.tree[open].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); + self.tree[open].item.end = self.tree[close].item.end; + self.tree[open].next = self.tree[close].next; + } + } + + /// Returns the next byte offset on success. + fn scan_inline_html(&mut self, bytes: &[u8], ix: usize) -> Option { + let c = *bytes.get(ix)?; + if c == b'!' { + scan_inline_html_comment(bytes, ix + 1, &mut self.html_scan_guard) + } else if c == b'?' { + scan_inline_html_processing(bytes, ix + 1, &mut self.html_scan_guard) + } else { + let i = scan_html_block_inner( + &bytes[ix..], + Some(&|_bytes| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(&self.tree, &mut line_start); + line_start.bytes_scanned() + }), + )?; + Some(i + ix) + } + } + + /// Consumes the event iterator and produces an iterator that produces + /// `(Event, Range)` pairs, where the `Range` value maps to the corresponding + /// range in the markdown source. + pub fn into_offset_iter(self) -> OffsetIter<'a> { + OffsetIter { inner: self } + } +} + +pub(crate) enum LoopInstruction { + /// Continue looking for more special bytes, but skip next few bytes. + ContinueAndSkip(usize), + /// Break looping immediately, returning with the given index and value. + BreakAtWith(usize, T), +} + +/// This function walks the byte slices from the given index and +/// calls the callback function on all bytes (and their indices) that are in the following set: +/// `` ` ``, `\`, `&`, `*`, `_`, `~`, `!`, `<`, `[`, `]`, `|`, `\r`, `\n` +/// It is guaranteed not call the callback on other bytes. +/// Whenever `callback(ix, byte)` returns a `ContinueAndSkip(n)` value, the callback +/// will not be called with an index that is less than `ix + n + 1`. +/// When the callback returns a `BreakAtWith(end_ix, opt+val)`, no more callbacks will be +/// called and the function returns immediately with the return value `(end_ix, opt_val)`. +/// If `BreakAtWith(..)` is never returned, this function will return the first +/// index that is outside the byteslice bound and a `None` value. +fn iterate_special_bytes(bytes: &[u8], ix: usize, callback: F) -> (usize, Option) +where + F: FnMut(usize, u8) -> LoopInstruction>, +{ + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + crate::simd::iterate_special_bytes(bytes, ix, callback) + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + scalar_iterate_special_bytes(bytes, ix, callback) + } +} + +const fn special_bytes() -> [bool; 256] { + let mut bytes = [false; 256]; + bytes[b'<' as usize] = true; + bytes[b'!' as usize] = true; + bytes[b'[' as usize] = true; + bytes[b'~' as usize] = true; + bytes[b'`' as usize] = true; + bytes[b'|' as usize] = true; + bytes[b'\\' as usize] = true; + bytes[b'*' as usize] = true; + bytes[b'_' as usize] = true; + bytes[b'\r' as usize] = true; + bytes[b'\n' as usize] = true; + bytes[b']' as usize] = true; + bytes[b'&' as usize] = true; + bytes +} + +pub(crate) fn scalar_iterate_special_bytes( + bytes: &[u8], + mut ix: usize, + mut callback: F, +) -> (usize, Option) +where + F: FnMut(usize, u8) -> LoopInstruction>, +{ + let special_bytes = special_bytes(); + + while ix < bytes.len() { + let b = bytes[ix]; + if special_bytes[b as usize] { + match callback(ix, b) { + LoopInstruction::ContinueAndSkip(skip) => { + ix += skip; + } + LoopInstruction::BreakAtWith(ix, val) => { + return (ix, val); + } + } + } + ix += 1; + } + + (ix, None) +} + +/// Markdown event and source range iterator. +/// +/// Generates tuples where the first element is the markdown event and the second +/// is a the corresponding range in the source string. +/// +/// Constructed from a `Parser` using its +/// [`into_offset_iter`](struct.Parser.html#method.into_offset_iter) method. +pub struct OffsetIter<'a> { + inner: Parser<'a>, +} + +impl<'a> Iterator for OffsetIter<'a> { + type Item = (Event<'a>, Range); + + fn next(&mut self) -> Option { + match self.inner.tree.cur() { + None => { + let ix = self.inner.tree.pop()?; + let tag = item_to_tag(&self.inner.tree[ix].item, &self.inner.allocs); + self.inner.tree.next_sibling(ix); + Some(( + Event::End(tag), + self.inner.tree[ix].item.start..self.inner.tree[ix].item.end, + )) + } + Some(cur_ix) => { + if self.inner.tree[cur_ix].item.body.is_inline() { + self.inner.handle_inline(); + } + + let node = self.inner.tree[cur_ix]; + let item = node.item; + let event = item_to_event(item, self.inner.text, &self.inner.allocs); + if let Event::Start(..) = event { + self.inner.tree.push(); + } else { + self.inner.tree.next_sibling(cur_ix); + } + Some((event, item.start..item.end)) + } + } + } +} + +fn item_to_tag<'a>(item: &Item, allocs: &Allocations<'a>) -> Tag<'a> { + match item.body { + ItemBody::Paragraph => Tag::Paragraph, + ItemBody::Emphasis => Tag::Emphasis, + ItemBody::Strong => Tag::Strong, + ItemBody::Strikethrough => Tag::Strikethrough, + ItemBody::Link(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Link(*link_type, url.clone(), title.clone()) + } + ItemBody::Image(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Image(*link_type, url.clone(), title.clone()) + } + ItemBody::Heading(level) => Tag::Heading(level), + ItemBody::FencedCodeBlock(cow_ix) => { + Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) + } + ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), + ItemBody::BlockQuote => Tag::BlockQuote, + ItemBody::List(_, c, listitem_start) => { + if c == b'.' || c == b')' { + Tag::List(Some(listitem_start)) + } else { + Tag::List(None) + } + } + ItemBody::ListItem(_) => Tag::Item, + ItemBody::TableHead => Tag::TableHead, + ItemBody::TableCell => Tag::TableCell, + ItemBody::TableRow => Tag::TableRow, + ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), + ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), + _ => panic!("unexpected item body {:?}", item.body), + } +} + +fn item_to_event<'a>(item: Item, text: &'a str, allocs: &Allocations<'a>) -> Event<'a> { + let tag = match item.body { + ItemBody::Text => return Event::Text(text[item.start..item.end].into()), + ItemBody::Code(cow_ix) => return Event::Code(allocs[cow_ix].clone()), + ItemBody::SynthesizeText(cow_ix) => return Event::Text(allocs[cow_ix].clone()), + ItemBody::Html => return Event::Html(text[item.start..item.end].into()), + ItemBody::SoftBreak => return Event::SoftBreak, + ItemBody::HardBreak => return Event::HardBreak, + ItemBody::FootnoteReference(cow_ix) => { + return Event::FootnoteReference(allocs[cow_ix].clone()) + } + ItemBody::TaskListMarker(checked) => return Event::TaskListMarker(checked), + ItemBody::Rule => return Event::Rule, + + ItemBody::Paragraph => Tag::Paragraph, + ItemBody::Emphasis => Tag::Emphasis, + ItemBody::Strong => Tag::Strong, + ItemBody::Strikethrough => Tag::Strikethrough, + ItemBody::Link(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Link(*link_type, url.clone(), title.clone()) + } + ItemBody::Image(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Image(*link_type, url.clone(), title.clone()) + } + ItemBody::Heading(level) => Tag::Heading(level), + ItemBody::FencedCodeBlock(cow_ix) => { + Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) + } + ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), + ItemBody::BlockQuote => Tag::BlockQuote, + ItemBody::List(_, c, listitem_start) => { + if c == b'.' || c == b')' { + Tag::List(Some(listitem_start)) + } else { + Tag::List(None) + } + } + ItemBody::ListItem(_) => Tag::Item, + ItemBody::TableHead => Tag::TableHead, + ItemBody::TableCell => Tag::TableCell, + ItemBody::TableRow => Tag::TableRow, + ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), + ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), + _ => panic!("unexpected item body {:?}", item.body), + }; + + Event::Start(tag) +} + +// https://english.stackexchange.com/a/285573 +fn surgerize_tight_list(tree: &mut Tree, list_ix: TreeIndex) { + let mut list_item = tree[list_ix].child; + while let Some(listitem_ix) = list_item { + // first child is special, controls how we repoint list_item.child + let list_item_firstborn = tree[listitem_ix].child; + + // Check that list item has children - this is not necessarily the case! + if let Some(firstborn_ix) = list_item_firstborn { + if let ItemBody::Paragraph = tree[firstborn_ix].item.body { + tree[listitem_ix].child = tree[firstborn_ix].child; + } + + let mut list_item_child = Some(firstborn_ix); + let mut node_to_repoint = None; + while let Some(child_ix) = list_item_child { + // surgerize paragraphs + let repoint_ix = if let ItemBody::Paragraph = tree[child_ix].item.body { + if let Some(child_firstborn) = tree[child_ix].child { + if let Some(repoint_ix) = node_to_repoint { + tree[repoint_ix].next = Some(child_firstborn); + } + let mut child_lastborn = child_firstborn; + while let Some(lastborn_next_ix) = tree[child_lastborn].next { + child_lastborn = lastborn_next_ix; + } + child_lastborn + } else { + child_ix + } + } else { + child_ix + }; + + node_to_repoint = Some(repoint_ix); + tree[repoint_ix].next = tree[child_ix].next; + list_item_child = tree[child_ix].next; + } + } + + list_item = tree[listitem_ix].next; + } +} + +impl<'a> Iterator for Parser<'a> { + type Item = Event<'a>; + + fn next(&mut self) -> Option> { + match self.tree.cur() { + None => { + let ix = self.tree.pop()?; + let tag = item_to_tag(&self.tree[ix].item, &self.allocs); + self.tree.next_sibling(ix); + Some(Event::End(tag)) + } + Some(cur_ix) => { + if self.tree[cur_ix].item.body.is_inline() { + self.handle_inline(); + } + + let node = self.tree[cur_ix]; + let item = node.item; + let event = item_to_event(item, self.text, &self.allocs); + if let Event::Start(..) = event { + self.tree.push(); + } else { + self.tree.next_sibling(cur_ix); + } + Some(event) + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::tree::Node; + + // TODO: move these tests to tests/html.rs? + + fn parser_with_extensions(text: &str) -> Parser<'_> { + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + + Parser::new_ext(text, opts) + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn node_size() { + let node_size = std::mem::size_of::>(); + assert_eq!(48, node_size); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn body_size() { + let body_size = std::mem::size_of::(); + assert_eq!(16, body_size); + } + + #[test] + fn single_open_fish_bracket() { + // dont crash + assert_eq!(3, Parser::new("<").count()); + } + + #[test] + fn lone_hashtag() { + // dont crash + assert_eq!(2, Parser::new("#").count()); + } + + #[test] + fn lots_of_backslashes() { + // dont crash + Parser::new("\\\\\r\r").count(); + Parser::new("\\\r\r\\.\\\\\r\r\\.\\").count(); + } + + #[test] + fn issue_320() { + // dont crash + parser_with_extensions(":\r\t> |\r:\r\t> |\r").count(); + } + + #[test] + fn issue_319() { + // dont crash + parser_with_extensions("|\r-]([^|\r-]([^").count(); + parser_with_extensions("|\r\r=][^|\r\r=][^car").count(); + } + + #[test] + fn issue_303() { + // dont crash + parser_with_extensions("[^\r\ra]").count(); + parser_with_extensions("\r\r]Z[^\x00\r\r]Z[^\x00").count(); + } + + #[test] + fn issue_313() { + // dont crash + parser_with_extensions("*]0[^\r\r*]0[^").count(); + parser_with_extensions("[^\r> `][^\r> `][^\r> `][").count(); + } + + #[test] + fn issue_311() { + // dont crash + parser_with_extensions("\\\u{0d}-\u{09}\\\u{0d}-\u{09}").count(); + } + + #[test] + fn issue_283() { + let input = std::str::from_utf8(b"\xf0\x9b\xb2\x9f - \\\n> - ").count(); + parser_with_extensions("- \n\n").count(); + } + + #[test] + fn issue_306() { + // dont crash + parser_with_extensions("*\r_<__*\r_<__*\r_<__*\r_<__").count(); + } + + #[test] + fn issue_305() { + // dont crash + parser_with_extensions("_6**6*_*").count(); + } + + #[test] + fn another_emphasis_panic() { + parser_with_extensions("*__#_#__*").count(); + } + + #[test] + fn offset_iter() { + let event_offsets: Vec<_> = Parser::new("*hello* world") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..13), (0..7), (1..6), (0..7), (7..13), (0..13)]; + assert_eq!(expected_offsets, event_offsets); + } + + #[test] + fn reference_link_offsets() { + let range = + Parser::new("# H1\n[testing][Some reference]\n\n[Some reference]: https://github.com") + .into_offset_iter() + .filter_map(|(ev, range)| match ev { + Event::Start(Tag::Link(LinkType::Reference, ..), ..) => Some(range), + _ => None, + }) + .next() + .unwrap(); + assert_eq!(5..30, range); + } + + #[test] + fn footnote_offsets() { + let range = Parser::new("Testing this[^1] out.\n\n[^1]: Footnote.") + .into_offset_iter() + .filter_map(|(ev, range)| match ev { + Event::FootnoteReference(..) => Some(range), + _ => None, + }) + .next() + .unwrap(); + assert_eq!(12..16, range); + } + + #[test] + fn table_offset() { + let markdown = "a\n\nTesting|This|Outtt\n--|:--:|--:\nSome Data|Other data|asdf"; + let event_offset = parser_with_extensions(markdown) + .into_offset_iter() + .map(|(_ev, range)| range) + .nth(3) + .unwrap(); + let expected_offset = 3..59; + assert_eq!(expected_offset, event_offset); + } + + #[test] + fn offset_iter_issue_378() { + let event_offsets: Vec<_> = Parser::new("a [b](c) d") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..10), (0..2), (2..8), (3..4), (2..8), (8..10), (0..10)]; + assert_eq!(expected_offsets, event_offsets); + } + + #[test] + fn offset_iter_issue_404() { + let event_offsets: Vec<_> = Parser::new("###\n") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..4), (0..4)]; + assert_eq!(expected_offsets, event_offsets); + } + + // FIXME: add this one regression suite + #[test] + fn link_def_at_eof() { + let test_str = "[My site][world]\n\n[world]: https://vincentprouillet.com"; + let expected = "

    My site

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn ref_def_at_eof() { + let test_str = "[test]:\\"; + let expected = ""; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn ref_def_cr_lf() { + let test_str = "[a]: /u\r\n\n[a]"; + let expected = "

    a

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn no_dest_refdef() { + let test_str = "[a]:"; + let expected = "

    [a]:

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn simple_broken_link_callback() { + let test_str = "This is a link w/o def: [hello][world]"; + let parser = Parser::new_with_broken_link_callback( + test_str, + Options::empty(), + Some(&|norm, raw| { + assert_eq!("world", raw); + assert_eq!("world", norm); + Some(("YOLO".to_owned(), "SWAG".to_owned())) + }), + ); + let mut link_tag_count = 0; + for (typ, url, title) in parser.filter_map(|event| match event { + Event::Start(tag) | Event::End(tag) => match tag { + Tag::Link(typ, url, title) => Some((typ, url, title)), + _ => None, + }, + _ => None, + }) { + link_tag_count += 1; + assert_eq!(typ, LinkType::ReferenceUnknown); + assert_eq!(url.as_ref(), "YOLO"); + assert_eq!(title.as_ref(), "SWAG"); + } + assert!(link_tag_count > 0); + } + + #[test] + fn code_block_kind_check_fenced() { + let parser = Parser::new("hello\n```test\ntadam\n```"); + let mut found = 0; + for (ev, _range) in parser.into_offset_iter() { + match ev { + Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(syntax))) => { + assert_eq!(syntax.as_ref(), "test"); + found += 1; + } + _ => {} + } + } + assert_eq!(found, 1); + } + + #[test] + fn code_block_kind_check_indented() { + let parser = Parser::new("hello\n\n ```test\n tadam\nhello"); + let mut found = 0; + for (ev, _range) in parser.into_offset_iter() { + match ev { + Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => { + found += 1; + } + _ => {} + } + } + assert_eq!(found, 1); + } +} diff --git a/vendor/pulldown-cmark-0.7.2/src/puncttable.rs b/vendor/pulldown-cmark-0.7.2/src/puncttable.rs new file mode 100644 index 0000000000..a1b0751a54 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/puncttable.rs @@ -0,0 +1,351 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! CommonMark punctuation set based on spec and Unicode properties. + +// Autogenerated by mk_puncttable.py + +const PUNCT_MASKS_ASCII: [u16; 8] = [ + 0x0000, // U+0000...U+000F + 0x0000, // U+0010...U+001F + 0xfffe, // U+0020...U+002F + 0xfc00, // U+0030...U+003F + 0x0001, // U+0040...U+004F + 0xf800, // U+0050...U+005F + 0x0001, // U+0060...U+006F + 0x7800, // U+0070...U+007F +]; + +const PUNCT_TAB: [u16; 132] = [ + 10, // U+00A0...U+00AF + 11, // U+00B0...U+00BF + 55, // U+0370...U+037F + 56, // U+0380...U+038F + 85, // U+0550...U+055F + 88, // U+0580...U+058F + 91, // U+05B0...U+05BF + 92, // U+05C0...U+05CF + 95, // U+05F0...U+05FF + 96, // U+0600...U+060F + 97, // U+0610...U+061F + 102, // U+0660...U+066F + 109, // U+06D0...U+06DF + 112, // U+0700...U+070F + 127, // U+07F0...U+07FF + 131, // U+0830...U+083F + 133, // U+0850...U+085F + 150, // U+0960...U+096F + 151, // U+0970...U+097F + 175, // U+0AF0...U+0AFF + 223, // U+0DF0...U+0DFF + 228, // U+0E40...U+0E4F + 229, // U+0E50...U+0E5F + 240, // U+0F00...U+0F0F + 241, // U+0F10...U+0F1F + 243, // U+0F30...U+0F3F + 248, // U+0F80...U+0F8F + 253, // U+0FD0...U+0FDF + 260, // U+1040...U+104F + 271, // U+10F0...U+10FF + 310, // U+1360...U+136F + 320, // U+1400...U+140F + 358, // U+1660...U+166F + 361, // U+1690...U+169F + 366, // U+16E0...U+16EF + 371, // U+1730...U+173F + 381, // U+17D0...U+17DF + 384, // U+1800...U+180F + 404, // U+1940...U+194F + 417, // U+1A10...U+1A1F + 426, // U+1AA0...U+1AAF + 437, // U+1B50...U+1B5F + 438, // U+1B60...U+1B6F + 447, // U+1BF0...U+1BFF + 451, // U+1C30...U+1C3F + 455, // U+1C70...U+1C7F + 460, // U+1CC0...U+1CCF + 461, // U+1CD0...U+1CDF + 513, // U+2010...U+201F + 514, // U+2020...U+202F + 515, // U+2030...U+203F + 516, // U+2040...U+204F + 517, // U+2050...U+205F + 519, // U+2070...U+207F + 520, // U+2080...U+208F + 560, // U+2300...U+230F + 562, // U+2320...U+232F + 630, // U+2760...U+276F + 631, // U+2770...U+277F + 636, // U+27C0...U+27CF + 638, // U+27E0...U+27EF + 664, // U+2980...U+298F + 665, // U+2990...U+299F + 669, // U+29D0...U+29DF + 671, // U+29F0...U+29FF + 719, // U+2CF0...U+2CFF + 727, // U+2D70...U+2D7F + 736, // U+2E00...U+2E0F + 737, // U+2E10...U+2E1F + 738, // U+2E20...U+2E2F + 739, // U+2E30...U+2E3F + 740, // U+2E40...U+2E4F + 768, // U+3000...U+300F + 769, // U+3010...U+301F + 771, // U+3030...U+303F + 778, // U+30A0...U+30AF + 783, // U+30F0...U+30FF + 2639, // U+A4F0...U+A4FF + 2656, // U+A600...U+A60F + 2663, // U+A670...U+A67F + 2671, // U+A6F0...U+A6FF + 2695, // U+A870...U+A87F + 2700, // U+A8C0...U+A8CF + 2703, // U+A8F0...U+A8FF + 2706, // U+A920...U+A92F + 2709, // U+A950...U+A95F + 2716, // U+A9C0...U+A9CF + 2717, // U+A9D0...U+A9DF + 2725, // U+AA50...U+AA5F + 2733, // U+AAD0...U+AADF + 2735, // U+AAF0...U+AAFF + 2750, // U+ABE0...U+ABEF + 4051, // U+FD30...U+FD3F + 4065, // U+FE10...U+FE1F + 4067, // U+FE30...U+FE3F + 4068, // U+FE40...U+FE4F + 4069, // U+FE50...U+FE5F + 4070, // U+FE60...U+FE6F + 4080, // U+FF00...U+FF0F + 4081, // U+FF10...U+FF1F + 4082, // U+FF20...U+FF2F + 4083, // U+FF30...U+FF3F + 4085, // U+FF50...U+FF5F + 4086, // U+FF60...U+FF6F + 4112, // U+10100...U+1010F + 4153, // U+10390...U+1039F + 4157, // U+103D0...U+103DF + 4182, // U+10560...U+1056F + 4229, // U+10850...U+1085F + 4241, // U+10910...U+1091F + 4243, // U+10930...U+1093F + 4261, // U+10A50...U+10A5F + 4263, // U+10A70...U+10A7F + 4271, // U+10AF0...U+10AFF + 4275, // U+10B30...U+10B3F + 4281, // U+10B90...U+10B9F + 4356, // U+11040...U+1104F + 4363, // U+110B0...U+110BF + 4364, // U+110C0...U+110CF + 4372, // U+11140...U+1114F + 4375, // U+11170...U+1117F + 4380, // U+111C0...U+111CF + 4387, // U+11230...U+1123F + 4428, // U+114C0...U+114CF + 4444, // U+115C0...U+115CF + 4452, // U+11640...U+1164F + 4679, // U+12470...U+1247F + 5798, // U+16A60...U+16A6F + 5807, // U+16AF0...U+16AFF + 5811, // U+16B30...U+16B3F + 5812, // U+16B40...U+16B4F + 7113, // U+1BC90...U+1BC9F +]; + +const PUNCT_MASKS: [u16; 132] = [ + 0x0882, // U+00A0...U+00AF + 0x88c0, // U+00B0...U+00BF + 0x4000, // U+0370...U+037F + 0x0080, // U+0380...U+038F + 0xfc00, // U+0550...U+055F + 0x0600, // U+0580...U+058F + 0x4000, // U+05B0...U+05BF + 0x0049, // U+05C0...U+05CF + 0x0018, // U+05F0...U+05FF + 0x3600, // U+0600...U+060F + 0xc800, // U+0610...U+061F + 0x3c00, // U+0660...U+066F + 0x0010, // U+06D0...U+06DF + 0x3fff, // U+0700...U+070F + 0x0380, // U+07F0...U+07FF + 0x7fff, // U+0830...U+083F + 0x4000, // U+0850...U+085F + 0x0030, // U+0960...U+096F + 0x0001, // U+0970...U+097F + 0x0001, // U+0AF0...U+0AFF + 0x0010, // U+0DF0...U+0DFF + 0x8000, // U+0E40...U+0E4F + 0x0c00, // U+0E50...U+0E5F + 0xfff0, // U+0F00...U+0F0F + 0x0017, // U+0F10...U+0F1F + 0x3c00, // U+0F30...U+0F3F + 0x0020, // U+0F80...U+0F8F + 0x061f, // U+0FD0...U+0FDF + 0xfc00, // U+1040...U+104F + 0x0800, // U+10F0...U+10FF + 0x01ff, // U+1360...U+136F + 0x0001, // U+1400...U+140F + 0x6000, // U+1660...U+166F + 0x1800, // U+1690...U+169F + 0x3800, // U+16E0...U+16EF + 0x0060, // U+1730...U+173F + 0x0770, // U+17D0...U+17DF + 0x07ff, // U+1800...U+180F + 0x0030, // U+1940...U+194F + 0xc000, // U+1A10...U+1A1F + 0x3f7f, // U+1AA0...U+1AAF + 0xfc00, // U+1B50...U+1B5F + 0x0001, // U+1B60...U+1B6F + 0xf000, // U+1BF0...U+1BFF + 0xf800, // U+1C30...U+1C3F + 0xc000, // U+1C70...U+1C7F + 0x00ff, // U+1CC0...U+1CCF + 0x0008, // U+1CD0...U+1CDF + 0xffff, // U+2010...U+201F + 0x00ff, // U+2020...U+202F + 0xffff, // U+2030...U+203F + 0xffef, // U+2040...U+204F + 0x7ffb, // U+2050...U+205F + 0x6000, // U+2070...U+207F + 0x6000, // U+2080...U+208F + 0x0f00, // U+2300...U+230F + 0x0600, // U+2320...U+232F + 0xff00, // U+2760...U+276F + 0x003f, // U+2770...U+277F + 0x0060, // U+27C0...U+27CF + 0xffc0, // U+27E0...U+27EF + 0xfff8, // U+2980...U+298F + 0x01ff, // U+2990...U+299F + 0x0f00, // U+29D0...U+29DF + 0x3000, // U+29F0...U+29FF + 0xde00, // U+2CF0...U+2CFF + 0x0001, // U+2D70...U+2D7F + 0xffff, // U+2E00...U+2E0F + 0xffff, // U+2E10...U+2E1F + 0x7fff, // U+2E20...U+2E2F + 0xffff, // U+2E30...U+2E3F + 0x0007, // U+2E40...U+2E4F + 0xff0e, // U+3000...U+300F + 0xfff3, // U+3010...U+301F + 0x2001, // U+3030...U+303F + 0x0001, // U+30A0...U+30AF + 0x0800, // U+30F0...U+30FF + 0xc000, // U+A4F0...U+A4FF + 0xe000, // U+A600...U+A60F + 0x4008, // U+A670...U+A67F + 0x00fc, // U+A6F0...U+A6FF + 0x00f0, // U+A870...U+A87F + 0xc000, // U+A8C0...U+A8CF + 0x0700, // U+A8F0...U+A8FF + 0xc000, // U+A920...U+A92F + 0x8000, // U+A950...U+A95F + 0x3ffe, // U+A9C0...U+A9CF + 0xc000, // U+A9D0...U+A9DF + 0xf000, // U+AA50...U+AA5F + 0xc000, // U+AAD0...U+AADF + 0x0003, // U+AAF0...U+AAFF + 0x0800, // U+ABE0...U+ABEF + 0xc000, // U+FD30...U+FD3F + 0x03ff, // U+FE10...U+FE1F + 0xffff, // U+FE30...U+FE3F + 0xffff, // U+FE40...U+FE4F + 0xfff7, // U+FE50...U+FE5F + 0x0d0b, // U+FE60...U+FE6F + 0xf7ee, // U+FF00...U+FF0F + 0x8c00, // U+FF10...U+FF1F + 0x0001, // U+FF20...U+FF2F + 0xb800, // U+FF30...U+FF3F + 0xa800, // U+FF50...U+FF5F + 0x003f, // U+FF60...U+FF6F + 0x0007, // U+10100...U+1010F + 0x8000, // U+10390...U+1039F + 0x0001, // U+103D0...U+103DF + 0x8000, // U+10560...U+1056F + 0x0080, // U+10850...U+1085F + 0x8000, // U+10910...U+1091F + 0x8000, // U+10930...U+1093F + 0x01ff, // U+10A50...U+10A5F + 0x8000, // U+10A70...U+10A7F + 0x007f, // U+10AF0...U+10AFF + 0xfe00, // U+10B30...U+10B3F + 0x1e00, // U+10B90...U+10B9F + 0x3f80, // U+11040...U+1104F + 0xd800, // U+110B0...U+110BF + 0x0003, // U+110C0...U+110CF + 0x000f, // U+11140...U+1114F + 0x0030, // U+11170...U+1117F + 0x21e0, // U+111C0...U+111CF + 0x3f00, // U+11230...U+1123F + 0x0040, // U+114C0...U+114CF + 0x03fe, // U+115C0...U+115CF + 0x000e, // U+11640...U+1164F + 0x001f, // U+12470...U+1247F + 0xc000, // U+16A60...U+16A6F + 0x0020, // U+16AF0...U+16AFF + 0x0f80, // U+16B30...U+16B3F + 0x0010, // U+16B40...U+16B4F + 0x8000, // U+1BC90...U+1BC9F +]; + +pub fn is_ascii_punctuation(c: u8) -> bool { + c < 128 && (PUNCT_MASKS_ASCII[(c / 16) as usize] & (1 << (c & 15))) != 0 +} + +pub fn is_punctuation(c: char) -> bool { + let cp = c as u32; + if cp < 128 { + return is_ascii_punctuation(cp as u8); + } + if cp > 0x1BC9F { + return false; + } + let high = (cp / 16) as u16; + match PUNCT_TAB.binary_search(&high) { + Ok(index) => (PUNCT_MASKS[index] & (1 << (cp & 15))) != 0, + _ => false, + } +} + +#[cfg(test)] +mod tests { + use super::{is_ascii_punctuation, is_punctuation}; + + #[test] + fn test_ascii() { + assert!(is_ascii_punctuation(b'!')); + assert!(is_ascii_punctuation(b'@')); + assert!(is_ascii_punctuation(b'~')); + assert!(!is_ascii_punctuation(b' ')); + assert!(!is_ascii_punctuation(b'0')); + assert!(!is_ascii_punctuation(b'A')); + assert!(!is_ascii_punctuation(0xA1)); + } + + #[test] + fn test_unicode() { + assert!(is_punctuation('~')); + assert!(!is_punctuation(' ')); + + assert!(is_punctuation('\u{00A1}')); + assert!(is_punctuation('\u{060C}')); + assert!(is_punctuation('\u{FF65}')); + assert!(is_punctuation('\u{1BC9F}')); + assert!(!is_punctuation('\u{1BCA0}')); + } +} diff --git a/vendor/pulldown-cmark-0.7.2/src/scanners.rs b/vendor/pulldown-cmark-0.7.2/src/scanners.rs new file mode 100644 index 0000000000..884d4e49f2 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/scanners.rs @@ -0,0 +1,1247 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Scanners for fragments of CommonMark syntax + +use std::char; +use std::convert::TryInto; + +use crate::entities; +use crate::parse::{Alignment, HtmlScanGuard, LinkType}; +pub use crate::puncttable::{is_ascii_punctuation, is_punctuation}; +use crate::strings::CowStr; + +use memchr::memchr; + +// sorted for binary search +const HTML_TAGS: [&str; 62] = [ + "address", + "article", + "aside", + "base", + "basefont", + "blockquote", + "body", + "caption", + "center", + "col", + "colgroup", + "dd", + "details", + "dialog", + "dir", + "div", + "dl", + "dt", + "fieldset", + "figcaption", + "figure", + "footer", + "form", + "frame", + "frameset", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "hr", + "html", + "iframe", + "legend", + "li", + "link", + "main", + "menu", + "menuitem", + "nav", + "noframes", + "ol", + "optgroup", + "option", + "p", + "param", + "section", + "source", + "summary", + "table", + "tbody", + "td", + "tfoot", + "th", + "thead", + "title", + "tr", + "track", + "ul", +]; + +/// Analysis of the beginning of a line, including indentation and container +/// markers. +#[derive(Clone)] +pub struct LineStart<'a> { + bytes: &'a [u8], + tab_start: usize, + ix: usize, + spaces_remaining: usize, + // no thematic breaks can occur before this offset. + // this prevents scanning over and over up to a certain point + min_hrule_offset: usize, +} + +impl<'a> LineStart<'a> { + pub(crate) fn new(bytes: &[u8]) -> LineStart { + LineStart { + bytes, + tab_start: 0, + ix: 0, + spaces_remaining: 0, + min_hrule_offset: 0, + } + } + + /// Try to scan a number of spaces. + /// + /// Returns true if all spaces were consumed. + /// + /// Note: consumes some spaces even if not successful. + pub(crate) fn scan_space(&mut self, n_space: usize) -> bool { + self.scan_space_inner(n_space) == 0 + } + + /// Scan a number of spaces up to a maximum. + /// + /// Returns number of spaces scanned. + pub(crate) fn scan_space_upto(&mut self, n_space: usize) -> usize { + n_space - self.scan_space_inner(n_space) + } + + /// Returns unused remainder of spaces. + fn scan_space_inner(&mut self, mut n_space: usize) -> usize { + let n_from_remaining = self.spaces_remaining.min(n_space); + self.spaces_remaining -= n_from_remaining; + n_space -= n_from_remaining; + while n_space > 0 && self.ix < self.bytes.len() { + match self.bytes[self.ix] { + b' ' => { + self.ix += 1; + n_space -= 1; + } + b'\t' => { + let spaces = 4 - (self.ix - self.tab_start) % 4; + self.ix += 1; + self.tab_start = self.ix; + let n = spaces.min(n_space); + n_space -= n; + self.spaces_remaining = spaces - n; + } + _ => break, + } + } + n_space + } + + /// Scan all available ASCII whitespace (not including eol). + pub(crate) fn scan_all_space(&mut self) { + self.spaces_remaining = 0; + self.ix += self.bytes[self.ix..] + .iter() + .take_while(|&&b| b == b' ' || b == b'\t') + .count(); + } + + /// Determine whether we're at end of line (includes end of file). + pub(crate) fn is_at_eol(&self) -> bool { + self.bytes + .get(self.ix) + .map(|&c| c == b'\r' || c == b'\n') + .unwrap_or(true) + } + + fn scan_ch(&mut self, c: u8) -> bool { + if self.ix < self.bytes.len() && self.bytes[self.ix] == c { + self.ix += 1; + true + } else { + false + } + } + + pub(crate) fn scan_blockquote_marker(&mut self) -> bool { + let save = self.clone(); + let _ = self.scan_space(3); + if self.scan_ch(b'>') { + let _ = self.scan_space(1); + true + } else { + *self = save; + false + } + } + + /// Scan a list marker. + /// + /// Return value is the character, the start index, and the indent in spaces. + /// For ordered list markers, the character will be one of b'.' or b')'. For + /// bullet list markers, it will be one of b'-', b'+', or b'*'. + pub(crate) fn scan_list_marker(&mut self) -> Option<(u8, u64, usize)> { + let save = self.clone(); + let indent = self.scan_space_upto(3); + if self.ix < self.bytes.len() { + let c = self.bytes[self.ix]; + if c == b'-' || c == b'+' || c == b'*' { + if self.ix >= self.min_hrule_offset { + // there could be an hrule here + if let Err(min_offset) = scan_hrule(&self.bytes[self.ix..]) { + self.min_hrule_offset = min_offset; + } else { + *self = save; + return None; + } + } + self.ix += 1; + if self.scan_space(1) || self.is_at_eol() { + return self.finish_list_marker(c, 0, indent + 2); + } + } else if c >= b'0' && c <= b'9' { + let start_ix = self.ix; + let mut ix = self.ix + 1; + let mut val = u64::from(c - b'0'); + while ix < self.bytes.len() && ix - start_ix < 10 { + let c = self.bytes[ix]; + ix += 1; + if c >= b'0' && c <= b'9' { + val = val * 10 + u64::from(c - b'0'); + } else if c == b')' || c == b'.' { + self.ix = ix; + if self.scan_space(1) || self.is_at_eol() { + return self.finish_list_marker(c, val, indent + self.ix - start_ix); + } else { + break; + } + } else { + break; + } + } + } + } + *self = save; + None + } + + fn finish_list_marker( + &mut self, + c: u8, + start: u64, + mut indent: usize, + ) -> Option<(u8, u64, usize)> { + let save = self.clone(); + + // skip the rest of the line if it's blank + if scan_blank_line(&self.bytes[self.ix..]).is_some() { + return Some((c, start, indent)); + } + + let post_indent = self.scan_space_upto(4); + if post_indent < 4 { + indent += post_indent; + } else { + *self = save; + } + Some((c, start, indent)) + } + + /// Returns Some(is_checked) when a task list marker was found. Resets itself + /// to original state otherwise. + pub(crate) fn scan_task_list_marker(&mut self) -> Option { + let save = self.clone(); + self.scan_space_upto(3); + + if !self.scan_ch(b'[') { + *self = save; + return None; + } + let is_checked = match self.bytes.get(self.ix) { + Some(&c) if is_ascii_whitespace_no_nl(c) => { + self.ix += 1; + false + } + Some(b'x') | Some(b'X') => { + self.ix += 1; + true + } + _ => { + *self = save; + return None; + } + }; + if !self.scan_ch(b']') { + *self = save; + return None; + } + if !self + .bytes + .get(self.ix) + .map(|&b| is_ascii_whitespace_no_nl(b)) + .unwrap_or(false) + { + *self = save; + return None; + } + Some(is_checked) + } + + pub(crate) fn bytes_scanned(&self) -> usize { + self.ix + } + + pub(crate) fn remaining_space(&self) -> usize { + self.spaces_remaining + } +} + +pub(crate) fn is_ascii_whitespace(c: u8) -> bool { + (c >= 0x09 && c <= 0x0d) || c == b' ' +} + +pub(crate) fn is_ascii_whitespace_no_nl(c: u8) -> bool { + c == b'\t' || c == 0x0b || c == 0x0c || c == b' ' +} + +fn is_ascii_alpha(c: u8) -> bool { + match c { + b'a'..=b'z' | b'A'..=b'Z' => true, + _ => false, + } +} + +fn is_ascii_alphanumeric(c: u8) -> bool { + match c { + b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => true, + _ => false, + } +} + +fn is_ascii_letterdigitdash(c: u8) -> bool { + c == b'-' || is_ascii_alphanumeric(c) +} + +fn is_digit(c: u8) -> bool { + b'0' <= c && c <= b'9' +} + +fn is_valid_unquoted_attr_value_char(c: u8) -> bool { + match c { + b'\'' | b'"' | b' ' | b'=' | b'>' | b'<' | b'`' | b'\n' | b'\r' => false, + _ => true, + } +} + +// scan a single character +pub(crate) fn scan_ch(data: &[u8], c: u8) -> usize { + if !data.is_empty() && data[0] == c { + 1 + } else { + 0 + } +} + +pub(crate) fn scan_while(data: &[u8], mut f: F) -> usize +where + F: FnMut(u8) -> bool, +{ + data.iter().take_while(|&&c| f(c)).count() +} + +pub(crate) fn scan_rev_while(data: &[u8], mut f: F) -> usize +where + F: FnMut(u8) -> bool, +{ + data.iter().rev().take_while(|&&c| f(c)).count() +} + +pub(crate) fn scan_ch_repeat(data: &[u8], c: u8) -> usize { + scan_while(data, |x| x == c) +} + +// Note: this scans ASCII whitespace only, for Unicode whitespace use +// a different function. +pub(crate) fn scan_whitespace_no_nl(data: &[u8]) -> usize { + scan_while(data, is_ascii_whitespace_no_nl) +} + +fn scan_attr_value_chars(data: &[u8]) -> usize { + scan_while(data, is_valid_unquoted_attr_value_char) +} + +pub(crate) fn scan_eol(bytes: &[u8]) -> Option { + if bytes.is_empty() { + return Some(0); + } + match bytes[0] { + b'\n' => Some(1), + b'\r' => Some(if bytes.get(1) == Some(&b'\n') { 2 } else { 1 }), + _ => None, + } +} + +pub(crate) fn scan_blank_line(bytes: &[u8]) -> Option { + let i = scan_whitespace_no_nl(bytes); + scan_eol(&bytes[i..]).map(|n| i + n) +} + +pub(crate) fn scan_nextline(bytes: &[u8]) -> usize { + memchr(b'\n', bytes).map_or(bytes.len(), |x| x + 1) +} + +// return: end byte for closing code fence, or None +// if the line is not a closing code fence +pub(crate) fn scan_closing_code_fence( + bytes: &[u8], + fence_char: u8, + n_fence_char: usize, +) -> Option { + if bytes.is_empty() { + return Some(0); + } + let mut i = 0; + let num_fence_chars_found = scan_ch_repeat(&bytes[i..], fence_char); + if num_fence_chars_found < n_fence_char { + return None; + } + i += num_fence_chars_found; + let num_trailing_spaces = scan_ch_repeat(&bytes[i..], b' '); + i += num_trailing_spaces; + scan_eol(&bytes[i..]).map(|_| i) +} + +// returned pair is (number of bytes, number of spaces) +fn calc_indent(text: &[u8], max: usize) -> (usize, usize) { + let mut spaces = 0; + let mut offset = 0; + + for (i, &b) in text.iter().enumerate() { + match b { + b' ' => { + spaces += 1; + if spaces == max { + break; + } + } + b'\t' => { + let new_spaces = spaces + 4 - (spaces & 3); + if new_spaces > max { + break; + } + spaces = new_spaces; + } + _ => break, + } + offset = i; + } + + (offset, spaces) +} + +/// Scan hrule opening sequence. +/// +/// Returns Ok(x) when it finds an hrule, where x is the +/// size of line containing the hrule, including the trailing newline. +/// +/// Returns Err(x) when it does not find an hrule and x is +/// the offset in data before no hrule can appear. +pub(crate) fn scan_hrule(bytes: &[u8]) -> Result { + if bytes.len() < 3 { + return Err(0); + } + let c = bytes[0]; + if !(c == b'*' || c == b'-' || c == b'_') { + return Err(0); + } + let mut n = 0; + let mut i = 0; + + while i < bytes.len() { + match bytes[i] { + b'\n' | b'\r' => { + i += scan_eol(&bytes[i..]).unwrap_or(0); + break; + } + c2 if c2 == c => { + n += 1; + } + b' ' | b'\t' => (), + _ => return Err(i), + } + i += 1; + } + if n >= 3 { + Ok(i) + } else { + Err(i) + } +} + +/// Scan an ATX heading opening sequence. +/// +/// Returns number of bytes in prefix and level. +pub(crate) fn scan_atx_heading(data: &[u8]) -> Option { + let level = scan_ch_repeat(data, b'#'); + if level >= 1 && level <= 6 && data.get(level).cloned().map_or(true, is_ascii_whitespace) { + Some(level) + } else { + None + } +} + +/// Scan a setext heading underline. +/// +/// Returns number of bytes in line (including trailing newline) and level. +pub(crate) fn scan_setext_heading(data: &[u8]) -> Option<(usize, u32)> { + let c = *data.get(0)?; + if !(c == b'-' || c == b'=') { + return None; + } + let mut i = 1 + scan_ch_repeat(&data[1..], c); + i += scan_blank_line(&data[i..])?; + let level = if c == b'=' { 1 } else { 2 }; + Some((i, level)) +} + +// returns number of bytes in line (including trailing +// newline) and column alignments +pub(crate) fn scan_table_head(data: &[u8]) -> (usize, Vec) { + let (mut i, spaces) = calc_indent(data, 4); + if spaces > 3 || i == data.len() { + return (0, vec![]); + } + let mut cols = vec![]; + let mut active_col = Alignment::None; + let mut start_col = true; + if data[i] == b'|' { + i += 1; + } + for c in &data[i..] { + if let Some(n) = scan_eol(&data[i..]) { + i += n; + break; + } + match *c { + b' ' => (), + b':' => { + active_col = match (start_col, active_col) { + (true, Alignment::None) => Alignment::Left, + (false, Alignment::Left) => Alignment::Center, + (false, Alignment::None) => Alignment::Right, + _ => active_col, + }; + start_col = false; + } + b'-' => { + start_col = false; + } + b'|' => { + start_col = true; + cols.push(active_col); + active_col = Alignment::None; + } + _ => { + cols = vec![]; + start_col = true; + break; + } + } + i += 1; + } + + if !start_col { + cols.push(active_col); + } + + (i, cols) +} + +/// Scan code fence. +/// +/// Returns number of bytes scanned and the char that is repeated to make the code fence. +pub(crate) fn scan_code_fence(data: &[u8]) -> Option<(usize, u8)> { + let c = *data.get(0)?; + if !(c == b'`' || c == b'~') { + return None; + } + let i = 1 + scan_ch_repeat(&data[1..], c); + if i >= 3 { + if c == b'`' { + let suffix = &data[i..]; + let next_line = i + scan_nextline(suffix); + // FIXME: make sure this is correct + if suffix[..(next_line - i)].iter().any(|&b| b == b'`') { + return None; + } + } + Some((i, c)) + } else { + None + } +} + +pub(crate) fn scan_blockquote_start(data: &[u8]) -> Option { + if data.starts_with(b"> ") { + Some(2) + } else { + None + } +} + +/// This already assumes the list item has been scanned. +pub(crate) fn scan_empty_list(data: &[u8]) -> bool { + let mut ix = 0; + for _ in 0..2 { + if let Some(bytes) = scan_blank_line(&data[ix..]) { + ix += bytes; + } else { + return false; + } + } + true +} + +// return number of bytes scanned, delimiter, start index, and indent +pub(crate) fn scan_listitem(bytes: &[u8]) -> Option<(usize, u8, usize, usize)> { + let mut c = *bytes.get(0)?; + let (w, start) = match c { + b'-' | b'+' | b'*' => (1, 0), + b'0'..=b'9' => { + let (length, start) = parse_decimal(bytes); + c = *bytes.get(length)?; + if !(c == b'.' || c == b')') { + return None; + } + (length + 1, start) + } + _ => { + return None; + } + }; + // TODO: replace calc_indent with scan_leading_whitespace, for tab correctness + let (mut postn, mut postindent) = calc_indent(&bytes[w..], 5); + if postindent == 0 { + scan_eol(&bytes[w..])?; + postindent += 1; + } else if postindent > 4 { + postn = 1; + postindent = 1; + } + if scan_blank_line(&bytes[w..]).is_some() { + postn = 0; + postindent = 1; + } + Some((w + postn, c, start, w + postindent)) +} + +// returns (number of bytes, parsed decimal) +fn parse_decimal(bytes: &[u8]) -> (usize, usize) { + match bytes + .iter() + .take_while(|&&b| is_digit(b)) + .try_fold((0, 0usize), |(count, acc), c| { + let digit = usize::from(c - b'0'); + match acc + .checked_mul(10) + .and_then(|ten_acc| ten_acc.checked_add(digit)) + { + Some(number) => Ok((count + 1, number)), + // stop early on overflow + None => Err((count, acc)), + } + }) { + Ok(p) | Err(p) => p, + } +} + +// returns (number of bytes, parsed hex) +fn parse_hex(bytes: &[u8]) -> (usize, usize) { + match bytes.iter().try_fold((0, 0usize), |(count, acc), c| { + let mut c = *c; + let digit = if c >= b'0' && c <= b'9' { + usize::from(c - b'0') + } else { + // make lower case + c |= 0x20; + if c >= b'a' && c <= b'f' { + usize::from(c - b'a' + 10) + } else { + return Err((count, acc)); + } + }; + match acc + .checked_mul(16) + .and_then(|sixteen_acc| sixteen_acc.checked_add(digit)) + { + Some(number) => Ok((count + 1, number)), + // stop early on overflow + None => Err((count, acc)), + } + }) { + Ok(p) | Err(p) => p, + } +} + +fn char_from_codepoint(input: usize) -> Option { + let mut codepoint = input.try_into().ok()?; + if codepoint == 0 { + codepoint = 0xFFFD; + } + char::from_u32(codepoint) +} + +// doesn't bother to check data[0] == '&' +pub(crate) fn scan_entity(bytes: &[u8]) -> (usize, Option>) { + let mut end = 1; + if scan_ch(&bytes[end..], b'#') == 1 { + end += 1; + let (bytecount, codepoint) = if end < bytes.len() && bytes[end] | 0x20 == b'x' { + end += 1; + parse_hex(&bytes[end..]) + } else { + parse_decimal(&bytes[end..]) + }; + end += bytecount; + return if bytecount == 0 || scan_ch(&bytes[end..], b';') == 0 { + (0, None) + } else if let Some(c) = char_from_codepoint(codepoint) { + (end + 1, Some(c.into())) + } else { + (0, None) + }; + } + end += scan_while(&bytes[end..], is_ascii_alphanumeric); + if scan_ch(&bytes[end..], b';') == 1 { + if let Some(value) = entities::get_entity(&bytes[1..end]) { + return (end + 1, Some(value.into())); + } + } + (0, None) +} + +// FIXME: we can most likely re-use other scanners +// returns (bytelength, title_str) +pub(crate) fn scan_refdef_title(text: &str) -> Option<(usize, &str)> { + let mut chars = text.chars().peekable(); + let closing_delim = match chars.next()? { + '\'' => '\'', + '"' => '"', + '(' => ')', + _ => return None, + }; + let mut bytecount = 1; + + while let Some(c) = chars.next() { + match c { + '\n' => { + bytecount += 1; + let mut next = *chars.peek()?; + while is_ascii_whitespace_no_nl(next as u8) { + bytecount += chars.next()?.len_utf8(); + next = *chars.peek()?; + } + if *chars.peek()? == '\n' { + // blank line - not allowed + return None; + } + } + '\\' => { + let next_char = chars.next()?; + bytecount += 1 + next_char.len_utf8(); + } + c if c == closing_delim => { + return Some((bytecount + 1, &text[1..bytecount])); + } + c => { + bytecount += c.len_utf8(); + } + } + } + None +} + +// note: dest returned is raw, still needs to be unescaped +// TODO: check that nested parens are really not allowed for refdefs +// TODO(performance): this func should probably its own unescaping +pub(crate) fn scan_link_dest( + data: &str, + start_ix: usize, + max_next: usize, +) -> Option<(usize, &str)> { + let bytes = &data.as_bytes()[start_ix..]; + let mut i = scan_ch(bytes, b'<'); + + if i != 0 { + // pointy links + while i < bytes.len() { + match bytes[i] { + b'\n' | b'\r' | b'<' => return None, + b'>' => return Some((i + 1, &data[(start_ix + 1)..(start_ix + i)])), + b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { + i += 1; + } + _ => {} + } + i += 1; + } + None + } else { + // non-pointy links + let mut nest = 0; + while i < bytes.len() { + match bytes[i] { + 0x0..=0x20 => { + break; + } + b'(' => { + if nest > max_next { + return None; + } + nest += 1; + } + b')' => { + if nest == 0 { + break; + } + nest -= 1; + } + b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { + i += 1; + } + _ => {} + } + i += 1; + } + Some((i, &data[start_ix..(start_ix + i)])) + } +} + +/// Returns bytes scanned +fn scan_attribute_name(data: &[u8]) -> Option { + let (&c, tail) = data.split_first()?; + if is_ascii_alpha(c) || c == b'_' || c == b':' { + Some( + 1 + scan_while(tail, |c| { + is_ascii_alphanumeric(c) || c == b'_' || c == b'.' || c == b':' || c == b'-' + }), + ) + } else { + None + } +} + +/// Returns byte scanned (TODO: should it return new offset?) +// TODO: properly use the newline handler here +fn scan_attribute(data: &[u8], newline_handler: Option<&dyn Fn(&[u8]) -> usize>) -> Option { + let allow_newline = newline_handler.is_some(); + let whitespace_scanner = + |c| is_ascii_whitespace(c) && (allow_newline || c != b'\n' && c != b'\r'); + let mut ix = scan_attribute_name(data)?; + let n_whitespace = scan_while(&data[ix..], whitespace_scanner); + ix += n_whitespace; + if scan_ch(&data[ix..], b'=') == 1 { + ix += 1; + ix += scan_while(&data[ix..], whitespace_scanner); + ix += scan_attribute_value(&data[ix..], newline_handler)?; + } else if n_whitespace > 0 { + // Leave whitespace for next attribute. + ix -= 1; + } + Some(ix) +} + +fn scan_attribute_value( + data: &[u8], + newline_handler: Option<&dyn Fn(&[u8]) -> usize>, +) -> Option { + let mut i = 0; + match *data.get(0)? { + b @ b'"' | b @ b'\'' => { + i += 1; + while i < data.len() { + if data[i] == b { + return Some(i + 1); + } + if let Some(eol_bytes) = scan_eol(&data[i..]) { + let handler = newline_handler?; + i += eol_bytes; + i += handler(&data[i..]); + } else { + i += 1; + } + } + return None; + } + b' ' | b'=' | b'>' | b'<' | b'`' | b'\n' | b'\r' => { + return None; + } + _ => { + // unquoted attribute value + i += scan_attr_value_chars(&data[i..]); + } + } + Some(i) +} + +// Remove backslash escapes and resolve entities +pub(crate) fn unescape(input: &str) -> CowStr<'_> { + let mut result = String::new(); + let mut mark = 0; + let mut i = 0; + let bytes = input.as_bytes(); + while i < bytes.len() { + match bytes[i] { + b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { + result.push_str(&input[mark..i]); + mark = i + 1; + i += 2; + } + b'&' => match scan_entity(&bytes[i..]) { + (n, Some(value)) => { + result.push_str(&input[mark..i]); + result.push_str(&value); + i += n; + mark = i; + } + _ => i += 1, + }, + b'\r' => { + result.push_str(&input[mark..i]); + i += 1; + mark = i; + } + _ => i += 1, + } + } + if mark == 0 { + input.into() + } else { + result.push_str(&input[mark..]); + result.into() + } +} + +/// Assumes `data` is preceded by `<`. +pub(crate) fn scan_html_block_tag(data: &[u8]) -> (usize, &[u8]) { + let i = scan_ch(data, b'/'); + let n = scan_while(&data[i..], is_ascii_alphanumeric); + // TODO: scan attributes and > + (i + n, &data[i..i + n]) +} + +pub(crate) fn is_html_tag(tag: &[u8]) -> bool { + HTML_TAGS + .binary_search_by(|probe| { + let probe_bytes_iter = probe.as_bytes().iter(); + let tag_bytes_iter = tag.iter(); + + probe_bytes_iter + .zip(tag_bytes_iter) + .find_map(|(&a, &b)| { + // We can compare case insensitively because the probes are + // all lower case alpha strings. + match a.cmp(&(b | 0x20)) { + std::cmp::Ordering::Equal => None, + inequality => Some(inequality), + } + }) + .unwrap_or_else(|| probe.len().cmp(&tag.len())) + }) + .is_ok() +} + +/// Assumes that `data` is preceded by `<`. +pub(crate) fn scan_html_type_7(data: &[u8]) -> Option { + // Block type html does not allow for newlines, so we + // do not pass a newline handler. + let i = scan_html_block_inner(data, None)?; + scan_blank_line(&data[i..])?; + Some(i) +} + +// FIXME: instead of a newline handler, maybe this should receive +// a whitespace handler instead. +// With signature `&dyn Fn(&[u8]) -> Option`. +// We currently need to implement whitespace handling in all of +// this function's dependencies as well. +pub(crate) fn scan_html_block_inner( + data: &[u8], + newline_handler: Option<&dyn Fn(&[u8]) -> usize>, +) -> Option { + let close_tag_bytes = scan_ch(data, b'/'); + let l = scan_while(&data[close_tag_bytes..], is_ascii_alpha); + if l == 0 { + return None; + } + let mut i = close_tag_bytes + l; + i += scan_while(&data[i..], is_ascii_letterdigitdash); + + if close_tag_bytes == 0 { + loop { + let old_i = i; + loop { + i += scan_whitespace_no_nl(&data[i..]); + if let Some(eol_bytes) = scan_eol(&data[i..]) { + if eol_bytes == 0 { + return None; + } + if let Some(handler) = newline_handler { + i += eol_bytes; + i += handler(&data[i..]); + } else { + return None; + } + } else { + break; + } + } + if let Some(b'/') | Some(b'>') = data.get(i) { + break; + } + if old_i == i { + // No whitespace, which is mandatory. + return None; + } + i += scan_attribute(&data[i..], newline_handler)?; + } + } + + i += scan_whitespace_no_nl(&data[i..]); + + if close_tag_bytes == 0 { + i += scan_ch(&data[i..], b'/'); + } + + if scan_ch(&data[i..], b'>') == 0 { + None + } else { + Some(i + 1) + } +} + +/// Returns (next_byte_offset, uri, type) +pub(crate) fn scan_autolink(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>, LinkType)> { + scan_uri(text, start_ix) + .map(|(bytes, uri)| (bytes, uri, LinkType::Autolink)) + .or_else(|| scan_email(text, start_ix).map(|(bytes, uri)| (bytes, uri, LinkType::Email))) +} + +/// Returns (next_byte_offset, uri) +fn scan_uri(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>)> { + let bytes = &text.as_bytes()[start_ix..]; + + // scheme's first byte must be an ascii letter + if bytes.is_empty() || !is_ascii_alpha(bytes[0]) { + return None; + } + + let mut i = 1; + + while i < bytes.len() { + let c = bytes[i]; + i += 1; + match c { + c if is_ascii_alphanumeric(c) => (), + b'.' | b'-' | b'+' => (), + b':' => break, + _ => return None, + } + } + + // scheme length must be between 2 and 32 characters long. scheme + // must be followed by colon + if i < 3 || i > 33 { + return None; + } + + while i < bytes.len() { + match bytes[i] { + b'>' => return Some((start_ix + i + 1, text[start_ix..(start_ix + i)].into())), + b'\0'..=b' ' | b'<' => return None, + _ => (), + } + i += 1; + } + + None +} + +/// Returns (next_byte_offset, email) +fn scan_email(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>)> { + // using a regex library would be convenient, but doing it by hand is not too bad + let bytes = &text.as_bytes()[start_ix..]; + let mut i = 0; + + while i < bytes.len() { + let c = bytes[i]; + i += 1; + match c { + c if is_ascii_alphanumeric(c) => (), + b'.' | b'!' | b'#' | b'$' | b'%' | b'&' | b'\'' | b'*' | b'+' | b'/' | b'=' | b'?' + | b'^' | b'_' | b'`' | b'{' | b'|' | b'}' | b'~' | b'-' => (), + b'@' => break, + _ => return None, + } + } + + loop { + let label_start_ix = i; + let mut fresh_label = true; + + while i < bytes.len() { + match bytes[i] { + c if is_ascii_alphanumeric(c) => (), + b'-' if fresh_label => { + return None; + } + b'-' => (), + _ => break, + } + fresh_label = false; + i += 1; + } + + if i == label_start_ix || i - label_start_ix > 63 || bytes[i - 1] == b'-' { + return None; + } + + if scan_ch(&bytes[i..], b'.') == 0 { + break; + } + i += 1; + } + + if scan_ch(&bytes[i..], b'>') == 0 { + return None; + } + + Some((start_ix + i + 1, text[start_ix..(start_ix + i)].into())) +} + +/// Scan comment, declaration, or CDATA section, with initial " Option { + let c = *bytes.get(ix)?; + ix += 1; + match c { + b'-' => { + let dashes = scan_ch_repeat(&bytes[ix..], b'-'); + if dashes < 1 { + return None; + } + // Saw ""##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_5() { + let original = r##"Little header + + +

    Useless

    +]]>"##; + let expected = r##"

    Little header

    + +

    Useless

    +]]>"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_6() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_7() { + let original = r##"Little header +----------- + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_8() { + let original = "A | B\n---|---\nfoo | bar"; + let expected = r##" + +
    AB
    foobar
    +"##; + + let mut s = String::new(); + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + html::push_html(&mut s, Parser::new_ext(&original, opts)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_9() { + let original = "---"; + let expected = "
    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_10() { + let original = "* * *"; + let expected = "
    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +// TODO: add broken link callback feature +/* +#[test] +fn html_test_broken_callback() { + let original = r##"[foo], +[bar], +[baz], + + [baz]: https://example.org +"##; + + let expected = r##"

    foo, +[bar], +baz,

    +"##; + + use pulldown_cmark::{Options, Parser, html}; + + let mut s = String::new(); + + let callback = |reference: &str, _normalized: &str| -> Option<(String, String)> { + if reference == "foo" || reference == "baz" { + Some(("https://replaced.example.org".into(), "some title".into())) + } else { + None + } + }; + + let p = Parser::new_with_broken_link_callback(&original, Options::empty(), Some(&callback)); + html::push_html(&mut s, p); + + assert_eq!(expected, s); +} +*/ diff --git a/vendor/pulldown-cmark-0.7.2/tests/lib.rs b/vendor/pulldown-cmark-0.7.2/tests/lib.rs new file mode 100644 index 0000000000..11be5bcd09 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/lib.rs @@ -0,0 +1,422 @@ +#[macro_use] +extern crate html5ever; +#[macro_use] +extern crate lazy_static; + +use html5ever::serialize::{serialize, SerializeOpts}; +use html5ever::{driver as html, QualName}; +use markup5ever_rcdom::{Handle, NodeData, RcDom, SerializableHandle}; +use pulldown_cmark::{Options, Parser}; + +use regex::Regex; +use std::collections::HashSet; +use std::mem; +use std::rc::{Rc, Weak}; +use tendril::stream::TendrilSink; + +mod suite; + +#[inline(never)] +pub fn test_markdown_html(input: &str, output: &str) { + let mut s = String::new(); + + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + + let p = Parser::new_ext(input, opts); + pulldown_cmark::html::push_html(&mut s, p); + + assert_eq!(normalize_html(output), normalize_html(&s)); +} + +lazy_static! { + static ref WHITESPACE_RE: Regex = Regex::new(r"\s+").unwrap(); + static ref LEADING_WHITESPACE_RE: Regex = Regex::new(r"\A\s+").unwrap(); + static ref TRAILING_WHITESPACE_RE: Regex = Regex::new(r"\s+\z").unwrap(); + static ref BLOCK_TAGS: HashSet<&'static str> = [ + "article", + "header", + "aside", + "hgroup", + "blockquote", + "hr", + "iframe", + "body", + "li", + "map", + "button", + "object", + "canvas", + "ol", + "caption", + "output", + "col", + "p", + "colgroup", + "pre", + "dd", + "progress", + "div", + "section", + "dl", + "table", + "td", + "dt", + "tbody", + "embed", + "textarea", + "fieldset", + "tfoot", + "figcaption", + "th", + "figure", + "thead", + "footer", + "tr", + "form", + "ul", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "video", + "script", + "style" + ] + .iter() + .cloned() + .collect(); + static ref WHITESPACE_SENSITIVE_TAGS: HashSet<&'static str> = + ["pre", "code", "h1", "h2", "h3", "h4", "h5", "h6"] + .iter() + .cloned() + .collect(); + static ref TABLE_TAGS: HashSet<&'static str> = ["table", "thead", "tbody", "tr", "td"] + .iter() + .cloned() + .collect(); +} + +fn make_html_parser() -> html::Parser { + html::parse_fragment( + RcDom::default(), + html::ParseOpts::default(), + QualName::new(None, ns!(html), local_name!("div")), + vec![], + ) +} + +fn normalize_html(s: &str) -> String { + let parser = make_html_parser(); + let dom = parser.one(s); + let body: SerializableHandle = normalize_dom(&dom).into(); + let opts = SerializeOpts::default(); + let mut ret_val = Vec::new(); + serialize(&mut ret_val, &body, opts) + .expect("Writing to a string shouldn't fail (expect on OOM)"); + String::from_utf8(ret_val).expect("html5ever should always produce UTF8") +} + +fn normalize_dom(dom: &RcDom) -> Handle { + let body = { + let children = dom.document.children.borrow(); + children[0].clone() + }; + let mut current_level = Vec::new(); + let mut next_level = Vec::new(); + current_level.extend(body.children.borrow().iter().cloned().rev()); + loop { + while let Some(mut node) = current_level.pop() { + let parent = node.parent.replace(None); + node.parent.replace(parent.clone()); + let parent = parent + .expect("a node in the DOM will have a parent, except the root, which is not processed") + .upgrade().expect("a node's parent will be pointed to by its parent (or the root pointer), and will not be dropped"); + let retain = normalize_node(&parent, &mut node); + if !retain { + let mut siblings = parent.children.borrow_mut(); + siblings.retain(|s| !Rc::ptr_eq(&node, s)); + } else { + next_level.extend(node.children.borrow().iter().cloned().rev()); + } + } + if next_level.is_empty() { + break; + }; + mem::swap(&mut next_level, &mut current_level); + } + body +} + +// Returns false if node is an empty text node or an empty tbody. +// Returns true otherwise. +fn normalize_node(parent: &Handle, node: &mut Handle) -> bool { + match node.data { + NodeData::Comment { .. } + | NodeData::Doctype { .. } + | NodeData::Document + | NodeData::ProcessingInstruction { .. } => true, + NodeData::Text { ref contents, .. } => { + let mut contents = contents.borrow_mut(); + let is_pre = { + let mut parent = parent.clone(); + loop { + let is_pre = if let NodeData::Element { ref name, .. } = parent.data { + WHITESPACE_SENSITIVE_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + if is_pre { + break true; + }; + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_ + } else { + break false; + }; + } + }; + if !is_pre { + let (is_first_in_block, is_last_in_block) = { + let mut is_first_in_block = true; + let mut is_last_in_block = true; + let mut parent = parent.clone(); + let mut node = node.clone(); + loop { + let reached_block = if let NodeData::Element { ref name, .. } = parent.data + { + BLOCK_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + let (is_first, is_last) = { + let siblings = parent.children.borrow(); + let n = &node; + ( + siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false), + siblings.len() > 0 + && siblings + .get(siblings.len() - 1) + .map(|s| Rc::ptr_eq(s, n)) + .unwrap_or(false), + ) + }; + is_first_in_block = is_first_in_block && is_first; + is_last_in_block = is_last_in_block && is_last; + if (is_first_in_block || is_last_in_block) && !reached_block { + node = parent.clone(); + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_; + } else { + break (is_first_in_block, is_last_in_block); + } + } else { + break (is_first_in_block, is_last_in_block); + } + } + }; + let is_preceeded_by_ws = { + let mut parent = parent.clone(); + let mut node = node.clone(); + 'ascent: loop { + let is_first = { + let siblings = parent.children.borrow(); + let n = &node; + siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false) + }; + if is_first { + node = parent.clone(); + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_; + } else { + break 'ascent false; + } + } else { + let siblings = parent.children.borrow(); + let n = &node; + let mut pos = !0; + 'search: for (i, s) in siblings.iter().enumerate() { + if Rc::ptr_eq(s, n) { + pos = i; + break 'search; + } + } + assert!( + pos != !0, + "The list of node's parent's children shall contain node" + ); + assert!( + pos != 0, + "If node is not first, then node's position shall not be zero" + ); + let mut preceeding = siblings[pos - 1].clone(); + 'descent: loop { + if let NodeData::Text { .. } = preceeding.data { + break 'descent; + } + preceeding = { + let ch = preceeding.children.borrow(); + if ch.len() == 0 { + break 'descent; + } + if let Some(preceeding_) = ch.get(ch.len() - 1) { + preceeding_.clone() + } else { + break 'descent; + } + }; + } + if let NodeData::Text { ref contents, .. } = preceeding.data { + break 'ascent TRAILING_WHITESPACE_RE.is_match(&*contents.borrow()); + } else { + break 'ascent false; + } + } + } + }; + + let is_in_table = if let NodeData::Element { ref name, .. } = parent.data { + TABLE_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + let whitespace_replacement = if is_in_table { "" } else { " " }; + *contents = WHITESPACE_RE + .replace_all(&*contents, whitespace_replacement) + .as_ref() + .into(); + + if is_first_in_block || is_preceeded_by_ws { + *contents = LEADING_WHITESPACE_RE + .replace_all(&*contents, "") + .as_ref() + .into(); + } + if is_last_in_block { + *contents = TRAILING_WHITESPACE_RE + .replace_all(&*contents, "") + .as_ref() + .into(); + } + // TODO: collapse whitespace when adjacent to whitespace. + // For example, the whitespace in the span should be collapsed in all of these cases: + // + // " q " + // "q q" + // "q q" + // "q q" + // "q q" + } + &**contents != "" + } + NodeData::Element { + ref attrs, + ref name, + .. + } => { + let mut attrs = attrs.borrow_mut(); + for a in attrs.iter_mut() { + a.name.local = a.name.local.to_ascii_lowercase().into(); + } + attrs.sort_by(|a: &html5ever::Attribute, b: &html5ever::Attribute| { + (&*a.name.local).cmp(&*b.name.local) + }); + let ascii_name = &*name.local.to_ascii_lowercase(); + // drop empty tbody's + ascii_name != "tbody" + || node.children.borrow().len() > 1 + || node + .children + .borrow() + .iter() + .next() + .map(|only_child| match only_child.data { + NodeData::Text { ref contents, .. } => { + !contents.borrow().chars().all(|c| c.is_whitespace()) + } + _ => true, + }) + .unwrap_or(false) + } + } +} + +#[test] +fn strip_div_newline() { + assert_eq!("
    ", normalize_html("
    \n
    ")); +} + +#[test] +fn strip_end_newline() { + assert_eq!("test", normalize_html("test\n")); +} + +#[test] +fn strip_double_space() { + assert_eq!("test mess", normalize_html("test mess")); +} + +#[test] +fn strip_inline_internal_text() { + assert_eq!( + "a b c", + normalize_html(" a b c ") + ) +} + +#[test] +fn strip_inline_block_internal_text() { + assert_eq!( + "a b c", + normalize_html(" a b c ") + ) +} + +#[test] +fn leaves_necessary_whitespace_alone() { + assert_eq!("a b c", normalize_html("a b c")) +} + +#[test] +fn leaves_necessary_whitespace_alone_weird() { + assert_eq!( + "a b c", + normalize_html(" a b c") + ) +} + +#[test] +fn leaves_necessary_whitespace_all_nested() { + assert_eq!( + "", + normalize_html(" ") + ) +} + +#[test] +fn drops_empty_tbody() { + assert_eq!( + "
    hi
    ", + normalize_html("
    hi
    ") + ) +} + +#[test] +fn leaves_nonempty_tbody() { + let input = "
    hi
    "; + assert_eq!(input, normalize_html(input)) +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/footnotes.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/footnotes.rs new file mode 100644 index 0000000000..e31eff54b6 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/footnotes.rs @@ -0,0 +1,165 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn footnotes_test_1() { + let original = r##"Lorem ipsum.[^a] + +[^a]: Cool. +"##; + let expected = r##"

    Lorem ipsum.1

    +
    1 +

    Cool.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_2() { + let original = r##"> This is the song that never ends.\ +> Yes it goes on and on my friends.[^lambchops] +> +> [^lambchops]: +"##; + let expected = r##"
    +

    This is the song that never ends.
    +Yes it goes on and on my friends.1

    + +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_3() { + let original = r##"Songs that simply loop are a popular way to annoy people. [^examples] + +[^examples]: + * [The song that never ends](https://www.youtube.com/watch?v=0U2zJOryHKQ) + * [I know a song that gets on everybody's nerves](https://www.youtube.com/watch?v=TehWI09qxls) + * [Ninety-nine bottles of beer on the wall](https://www.youtube.com/watch?v=qVjCag8XoHQ) +"##; + let expected = r##"

    Songs that simply loop are a popular way to annoy people. 1

    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_4() { + let original = r##"[^lorem]: If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research. + +I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp. +"##; + let expected = r##"
    1 +

    If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research.

    +
    +

    I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_5() { + let original = r##"[^ipsum]: How much wood would a woodchuck chuck. + +If a woodchuck could chuck wood. + + +# Forms of entertainment that aren't childish +"##; + let expected = r##"
    1 +

    How much wood would a woodchuck chuck.

    +
    +

    If a woodchuck could chuck wood.

    +

    Forms of entertainment that aren't childish

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_6() { + let original = r##"> He's also really stupid. [^why] +> +> [^why]: Because your mamma! + +As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet. +"##; + let expected = r##"
    +

    He's also really stupid. 1

    +
    1 +

    Because your mamma!

    +
    +
    +

    As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_7() { + let original = r##"Nested footnotes are considered poor style. [^a] [^xkcd] + +[^a]: This does not mean that footnotes cannot reference each other. [^b] + +[^b]: This means that a footnote definition cannot be directly inside another footnote definition. +> This means that a footnote cannot be directly inside another footnote's body. [^e] +> +> [^e]: They can, however, be inside anything else. + +[^xkcd]: [The other kind of nested footnote is, however, considered poor style.](https://xkcd.com/1208/) +"##; + let expected = r##"

    Nested footnotes are considered poor style. 1 2

    +
    1 +

    This does not mean that footnotes cannot reference each other. 3

    +
    +
    3 +

    This means that a footnote definition cannot be directly inside another footnote definition.

    +
    +

    This means that a footnote cannot be directly inside another footnote's body. 4

    +
    4 +

    They can, however, be inside anything else.

    +
    +
    +
    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_8() { + let original = r##"[^Doh] Ray Me Fa So La Te Do! [^1] + +[^Doh]: I know. Wrong Doe. And it won't render right. +[^1]: Common for people practicing music. +"##; + let expected = r##"

    1 Ray Me Fa So La Te Do! 2

    +
    1 +

    I know. Wrong Doe. And it won't render right. +2: Common for people practicing music.

    +
    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_strikethrough.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_strikethrough.rs new file mode 100644 index 0000000000..b8fd293980 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_strikethrough.rs @@ -0,0 +1,27 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_strikethrough_test_1() { + let original = r##"~~Hi~~ Hello, world! +"##; + let expected = r##"

    Hi Hello, world!

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_strikethrough_test_2() { + let original = r##"This ~~has a + +new paragraph~~. +"##; + let expected = r##"

    This ~~has a

    +

    new paragraph~~.

    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_table.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_table.rs new file mode 100644 index 0000000000..0e286b6b77 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_table.rs @@ -0,0 +1,205 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_table_test_1() { + let original = r##"| foo | bar | +| --- | --- | +| baz | bim | +"##; + let expected = r##" + + + + + + + + + + + + +
    foobar
    bazbim
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_2() { + let original = r##"| abc | defghi | +:-: | -----------: +bar | baz +"##; + let expected = r##" + + + + + + + + + + + + +
    abcdefghi
    barbaz
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_3() { + let original = r##"| f\|oo | +| ------ | +| b `\|` az | +| b **\|** im | +"##; + let expected = r##" + + + + + + + + + + + + + +
    f|oo
    b \| az
    b | im
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_4() { + let original = r##"| abc | def | +| --- | --- | +| bar | baz | +> bar +"##; + let expected = r##" + + + + + + + + + + + + +
    abcdef
    barbaz
    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_5() { + let original = r##"| abc | def | +| --- | --- | +| bar | baz | +bar + +bar +"##; + let expected = r##" + + + + + + + + + + + + + + + + +
    abcdef
    barbaz
    bar
    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_6() { + let original = r##"| abc | def | +| --- | +| bar | +"##; + let expected = r##"

    | abc | def | +| --- | +| bar |

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_7() { + let original = r##"| abc | def | +| --- | --- | +| bar | +| bar | baz | boo | +"##; + let expected = r##" + + + + + + + + + + + + + + + + +
    abcdef
    bar
    barbaz
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_8() { + let original = r##"| abc | def | +| --- | --- | +"##; + let expected = r##" + + + + + + +
    abcdef
    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_tasklist.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_tasklist.rs new file mode 100644 index 0000000000..ca80369f99 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_tasklist.rs @@ -0,0 +1,39 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_tasklist_test_1() { + let original = r##"- [ ] foo +- [x] bar +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_tasklist_test_2() { + let original = r##"- [x] foo + - [ ] bar + - [x] baz +- [ ] bim +"##; + let expected = r##"
      +
    • foo +
        +
      • bar
      • +
      • baz
      • +
      +
    • +
    • bim
    • +
    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/mod.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/mod.rs new file mode 100644 index 0000000000..aa05206085 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/mod.rs @@ -0,0 +1,12 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +pub use super::test_markdown_html; + +mod footnotes; +mod regression; +mod table; +mod spec; +mod gfm_table; +mod gfm_strikethrough; +mod gfm_tasklist; diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/regression.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/regression.rs new file mode 100644 index 0000000000..5c723aacf1 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/regression.rs @@ -0,0 +1,904 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn regression_test_1() { + let original = r##"
    Testing 1..2..3.. + +This is a test of the details element. + +
    +"##; + let expected = r##"
    Testing 1..2..3.. +

    This is a test of the details element.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_2() { + let original = r##"see the [many] [articles] [on] [QuickCheck]. + +[many]: https://medium.com/@jlouis666/quickcheck-advice-c357efb4e7e6 +[articles]: http://www.quviq.com/products/erlang-quickcheck/ +[on]: https://wiki.haskell.org/Introduction_to_QuickCheck1 +[QuickCheck]: https://hackage.haskell.org/package/QuickCheck +"##; + let expected = r##"

    see the + many + articles + on + QuickCheck. +

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_3() { + let original = r##"[![debug-stub-derive on crates.io][cratesio-image]][cratesio] +[![debug-stub-derive on docs.rs][docsrs-image]][docsrs] + +[cratesio-image]: https://img.shields.io/crates/v/debug_stub_derive.svg +[cratesio]: https://crates.io/crates/debug_stub_derive +[docsrs-image]: https://docs.rs/debug_stub_derive/badge.svg?version=0.3.0 +[docsrs]: https://docs.rs/debug_stub_derive/0.3.0/ +"##; + let expected = r##"

    debug-stub-derive on crates.io +debug-stub-derive on docs.rs

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_4() { + let original = r##"| Title A | Title B | +| --------- | --------- | +| Content | Content | + +| Title A | Title B | Title C | Title D | +| --------- | --------- | --------- | ---------:| +| Content | Content | Conent | Content | +"##; + let expected = r##" + +
    Title A Title B
    Content Content
    + + +
    Title A Title B Title C Title D
    Content Content Conent Content
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_5() { + let original = r##"foo§__(bar)__ +"##; + let expected = r##"

    foo§(bar)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_6() { + let original = r##" hello +"##; + let expected = r##"

    https://example.com hello

    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_7() { + let original = r##"[foo][bar] + + +[bar]: a +"##; + let expected = r##"

    foo

    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_8() { + let original = r##" +- **foo** (u8, u8) + + make something + +- **bar** (u16, u16) + + make something +"##; + let expected = r##" +
      +
    • +

      foo (u8, u8)

      +

      make something

      +
    • +
    • +

      bar (u16, u16)

      +

      make something

      +
    • +
    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_9() { + let original = r##"[` +i8 +`]( +../../../std/primitive.i8.html +) +"##; + let expected = r##"

    i8

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_10() { + let original = r##"[a] + +[a]: /url (title\\*) +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_11() { + let original = r##"[a] + +[a]: /url (title\)) +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_12() { + let original = r##"[a] + +[a]: /url (title)) +"##; + let expected = r##"

    [a]

    +

    [a]: /url (title))

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_13() { + let original = r##"a +"##; + let expected = r##"

    a <?php this is not a valid processing tag

    +

    b

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_14() { + let original = r##"[a]: u\ +foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_15() { + let original = r##"\`foo` +"##; + let expected = r##"

    `foo`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_16() { + let original = r##"foo\\ +bar +"##; + let expected = r##"

    foo\ +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_17() { + let original = r##"1\. foo + +1\) bar +"##; + let expected = r##"

    1. foo

    +

    1) bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_18() { + let original = r##"1... + +1.2.3. + +1 2 3 . + +1.|2.-3. + +1)2)3) +"##; + let expected = r##"

    1...

    +

    1.2.3.

    +

    1 2 3 .

    +

    1.|2.-3.

    +

    1)2)3)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_19() { + let original = r##"[](<<>) +"##; + let expected = r##"

    [](<<>)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_20() { + let original = r##"\``foo``bar` +"##; + let expected = r##"

    `foo``bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_21() { + let original = r##"\\`foo` +"##; + let expected = r##"

    \foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_22() { + let original = r##"[\\]: x + +YOLO +"##; + let expected = r##"

    YOLO

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_23() { + let original = r##"lorem ipsum +A | B +---|--- +foo | bar +"##; + let expected = r##"

    lorem ipsum +A | B +---|--- +foo | bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_24() { + let original = r##"foo|bar +---|--- +foo|bar +"##; + let expected = r##" + +
    foobar
    foobar
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_25() { + let original = r##"foo|bar\\ +---|--- +foo|bar +"##; + let expected = r##" + +
    foobar\
    foobar
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_26() { + let original = r##"[](url) +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_27() { + let original = r##"[bar](url) +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_28() { + let original = r##"![](http://example.com/logo.png) +"##; + let expected = r##"

    http://example.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_29() { + let original = r##"[ ](url) +"##; + let expected = r##"

    http://one http://two

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_30() { + let original = r##"Markdown | Less | Pretty +--- | --- | --- + +some text +"##; + let expected = r##" +
    Markdown Less Pretty
    +

    some text

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_31() { + let original = r##"1. > foo +2. > +"##; + let expected = r##"
      +
    1. +
      +

      foo

      +
      +
    2. +
    3. +
      +
      +
    4. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_32() { + let original = r##"[ +x + +]: f +"##; + let expected = r##"

    [ +x

    +

    ]: f

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_33() { + let original = r##"[foo]: +"##; + let expected = r##"

    [foo]:

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_34() { + let original = r##"> foo | bar +> --- | --- +yolo | swag +"##; + let expected = r##"
    +
    foobar
    +
    +

    yolo | swag

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_35() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_36() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_37() { + let original = r##"~~*_**__ + +__a__ +"##; + let expected = r##"

    ~~*_**__

    +

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_38() { + let original = r##"> ` +> ` +"##; + let expected = r##"
    +

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_39() { + let original = r##"`\|` +"##; + let expected = r##"

    \|

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_40() { + let original = r##"Paragraph 1 + +Paragraph 2 +"##; + let expected = r##"

    Paragraph 1

    +

    Paragraph 2

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_41() { + let original = r##"\[[link text](https://www.google.com/)\] +"##; + let expected = r##"

    [link text]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_42() { + let original = r##"foo | bar +--- | --- +[a](< | url>) +"##; + let expected = r##"
    foobar
    [a](<url>)
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_43() { + let original = r##"[a](url " +- - - +") +"##; + let expected = r##"

    [a](url "

    +
    +

    ")

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_44() { + let original = r##"[a](url + +) +"##; + let expected = r##"

    [a](url

    +

    )

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_45() { + let original = r##"[a](b " + +") +"##; + let expected = r##"

    [a](b "

    +

    ")

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_46() { + let original = r##" +"##; + let expected = r##"

    <http:// >

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_47() { + let original = r##" +"##; + let expected = r##"

    <http://>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_48() { + let original = r##"foo | bar +--- | --- + + +foobar + + +<http://baz + + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_49() { + let original = r##"foo | bar +--- | --- + +"##; + let expected = r##" + + + + + + +
    foobar
    <http://>
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_50() { + let original = r##"\*hi\_ +"##; + let expected = r##"

    *hi_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_51() { + let original = r##"email: \_ +"##; + let expected = r##"

    email: john@example.com_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_52() { + let original = r##"> [link](/url 'foo +> bar') +"##; + let expected = r##"
    +

    link

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_53() { + let original = r##"> [foo +> bar]: /url +> +> [foo bar] +"##; + let expected = r##"
    +

    foo bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_54() { + let original = r##"> [foo bar]: /url +> +> [foo +> bar] +"##; + let expected = r##"
    +

    foo +bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_55() { + let original = r##"> - [a +> b c]: /foo + +[a b c] +"##; + let expected = r##"
    +
      +
    • +
    +
    +

    a b c

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_56() { + let original = r##"[a +> b]: /foo + +[a b] [a > b] +"##; + let expected = r##"

    [a

    +
    +

    b]: /foo

    +
    +

    [a b] [a > b]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_57() { + let original = r##"[`cargo +package`] + +[`cargo package`]: https://example.com +"##; + let expected = r##"

    cargo package

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_58() { + let original = r##"> [`cargo +> package`] + +[`cargo package`]: https://example.com +"##; + let expected = r##"
    +

    cargo package

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_59() { + let original = r##"> `cargo +> package` +"##; + let expected = r##"
    +

    cargo package

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_60() { + let original = r##"Lorem ipsum.[^a] + +An unordered list before the footnotes: +* Ipsum +* Lorem + +[^a]: Cool. +"##; + let expected = r##"

    Lorem ipsum.1

    +

    An unordered list before the footnotes:

    +
      +
    • Ipsum
    • +
    • Lorem
    • +
    +
    1 +

    Cool.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_61() { + let original = r##"[][a] + +[a]: b + +# assimp-rs [![][crates-badge]][crates] + +[crates]: https://crates.io/crates/assimp +[crates-badge]: http://meritbadge.herokuapp.com/assimp +"##; + let expected = r##"

    + +

    assimp-rs

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_62() { + let original = r##"* A list. + + * A sublist. + + * Another sublist. + + +* A list. + + * A sublist. + + * Another sublist. + +"##; + let expected = r##"
      +
    • +

      A list.

      +
        +
      • +

        A sublist.

        +
      • +
      • +

        Another sublist.

        +
      • +
      +
    • +
    • +

      A list.

      +
        +
      • +

        A sublist.

        +
      • +
      • +

        Another sublist.

        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_63() { + let original = r##"<foo

    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/spec.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/spec.rs new file mode 100644 index 0000000000..0215dd4b89 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/spec.rs @@ -0,0 +1,8447 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn spec_test_1() { + let original = r##" foo baz bim +"##; + let expected = r##"
    foo	baz		bim
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_2() { + let original = r##" foo baz bim +"##; + let expected = r##"
    foo	baz		bim
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_3() { + let original = r##" a a + ὐ a +"##; + let expected = r##"
    a	a
    +ὐ	a
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_4() { + let original = r##" - foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_5() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +
        bar
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_6() { + let original = r##"> foo +"##; + let expected = r##"
    +
      foo
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_7() { + let original = r##"- foo +"##; + let expected = r##"
      +
    • +
        foo
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_8() { + let original = r##" foo + bar +"##; + let expected = r##"
    foo
    +bar
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_9() { + let original = r##" - foo + - bar + - baz +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • baz
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_10() { + let original = r##"# Foo +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_11() { + let original = r##"* * * +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_12() { + let original = r##"- `one +- two` +"##; + let expected = r##"
      +
    • `one
    • +
    • two`
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_13() { + let original = r##"*** +--- +___ +"##; + let expected = r##"
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_14() { + let original = r##"+++ +"##; + let expected = r##"

    +++

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_15() { + let original = r##"=== +"##; + let expected = r##"

    ===

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_16() { + let original = r##"-- +** +__ +"##; + let expected = r##"

    -- +** +__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_17() { + let original = r##" *** + *** + *** +"##; + let expected = r##"
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_18() { + let original = r##" *** +"##; + let expected = r##"
    ***
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_19() { + let original = r##"Foo + *** +"##; + let expected = r##"

    Foo +***

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_20() { + let original = r##"_____________________________________ +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_21() { + let original = r##" - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_22() { + let original = r##" ** * ** * ** * ** +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_23() { + let original = r##"- - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_24() { + let original = r##"- - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_25() { + let original = r##"_ _ _ _ a + +a------ + +---a--- +"##; + let expected = r##"

    _ _ _ _ a

    +

    a------

    +

    ---a---

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_26() { + let original = r##" *-* +"##; + let expected = r##"

    -

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_27() { + let original = r##"- foo +*** +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_28() { + let original = r##"Foo +*** +bar +"##; + let expected = r##"

    Foo

    +
    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_29() { + let original = r##"Foo +--- +bar +"##; + let expected = r##"

    Foo

    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_30() { + let original = r##"* Foo +* * * +* Bar +"##; + let expected = r##"
      +
    • Foo
    • +
    +
    +
      +
    • Bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_31() { + let original = r##"- Foo +- * * * +"##; + let expected = r##"
      +
    • Foo
    • +
    • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_32() { + let original = r##"# foo +## foo +### foo +#### foo +##### foo +###### foo +"##; + let expected = r##"

    foo

    +

    foo

    +

    foo

    +

    foo

    +
    foo
    +
    foo
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_33() { + let original = r##"####### foo +"##; + let expected = r##"

    ####### foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_34() { + let original = r##"#5 bolt + +#hashtag +"##; + let expected = r##"

    #5 bolt

    +

    #hashtag

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_35() { + let original = r##"\## foo +"##; + let expected = r##"

    ## foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_36() { + let original = r##"# foo *bar* \*baz\* +"##; + let expected = r##"

    foo bar *baz*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_37() { + let original = r##"# foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_38() { + let original = r##" ### foo + ## foo + # foo +"##; + let expected = r##"

    foo

    +

    foo

    +

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_39() { + let original = r##" # foo +"##; + let expected = r##"
    # foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_40() { + let original = r##"foo + # bar +"##; + let expected = r##"

    foo +# bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_41() { + let original = r##"## foo ## + ### bar ### +"##; + let expected = r##"

    foo

    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_42() { + let original = r##"# foo ################################## +##### foo ## +"##; + let expected = r##"

    foo

    +
    foo
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_43() { + let original = r##"### foo ### +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_44() { + let original = r##"### foo ### b +"##; + let expected = r##"

    foo ### b

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_45() { + let original = r##"# foo# +"##; + let expected = r##"

    foo#

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_46() { + let original = r##"### foo \### +## foo #\## +# foo \# +"##; + let expected = r##"

    foo ###

    +

    foo ###

    +

    foo #

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_47() { + let original = r##"**** +## foo +**** +"##; + let expected = r##"
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_48() { + let original = r##"Foo bar +# baz +Bar foo +"##; + let expected = r##"

    Foo bar

    +

    baz

    +

    Bar foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_49() { + let original = r##"## +# +### ### +"##; + let expected = r##"

    +

    +

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_50() { + let original = r##"Foo *bar* +========= + +Foo *bar* +--------- +"##; + let expected = r##"

    Foo bar

    +

    Foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_51() { + let original = r##"Foo *bar +baz* +==== +"##; + let expected = r##"

    Foo bar +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_52() { + let original = r##" Foo *bar +baz* +==== +"##; + let expected = r##"

    Foo bar +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_53() { + let original = r##"Foo +------------------------- + +Foo += +"##; + let expected = r##"

    Foo

    +

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_54() { + let original = r##" Foo +--- + + Foo +----- + + Foo + === +"##; + let expected = r##"

    Foo

    +

    Foo

    +

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_55() { + let original = r##" Foo + --- + + Foo +--- +"##; + let expected = r##"
    Foo
    +---
    +
    +Foo
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_56() { + let original = r##"Foo + ---- +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_57() { + let original = r##"Foo + --- +"##; + let expected = r##"

    Foo +---

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_58() { + let original = r##"Foo += = + +Foo +--- - +"##; + let expected = r##"

    Foo += =

    +

    Foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_59() { + let original = r##"Foo +----- +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_60() { + let original = r##"Foo\ +---- +"##; + let expected = r##"

    Foo\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_61() { + let original = r##"`Foo +---- +` + + +"##; + let expected = r##"

    `Foo

    +

    `

    +

    <a title="a lot

    +

    of dashes"/>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_62() { + let original = r##"> Foo +--- +"##; + let expected = r##"
    +

    Foo

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_63() { + let original = r##"> foo +bar +=== +"##; + let expected = r##"
    +

    foo +bar +===

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_64() { + let original = r##"- Foo +--- +"##; + let expected = r##"
      +
    • Foo
    • +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_65() { + let original = r##"Foo +Bar +--- +"##; + let expected = r##"

    Foo +Bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_66() { + let original = r##"--- +Foo +--- +Bar +--- +Baz +"##; + let expected = r##"
    +

    Foo

    +

    Bar

    +

    Baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_67() { + let original = r##" +==== +"##; + let expected = r##"

    ====

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_68() { + let original = r##"--- +--- +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_69() { + let original = r##"- foo +----- +"##; + let expected = r##"
      +
    • foo
    • +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_70() { + let original = r##" foo +--- +"##; + let expected = r##"
    foo
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_71() { + let original = r##"> foo +----- +"##; + let expected = r##"
    +

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_72() { + let original = r##"\> foo +------ +"##; + let expected = r##"

    > foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_73() { + let original = r##"Foo + +bar +--- +baz +"##; + let expected = r##"

    Foo

    +

    bar

    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_74() { + let original = r##"Foo +bar + +--- + +baz +"##; + let expected = r##"

    Foo +bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_75() { + let original = r##"Foo +bar +* * * +baz +"##; + let expected = r##"

    Foo +bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_76() { + let original = r##"Foo +bar +\--- +baz +"##; + let expected = r##"

    Foo +bar +--- +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_77() { + let original = r##" a simple + indented code block +"##; + let expected = r##"
    a simple
    +  indented code block
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_78() { + let original = r##" - foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_79() { + let original = r##"1. foo + + - bar +"##; + let expected = r##"
      +
    1. +

      foo

      +
        +
      • bar
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_80() { + let original = r##"
    + *hi* + + - one +"##; + let expected = r##"
    <a/>
    +*hi*
    +
    +- one
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_81() { + let original = r##" chunk1 + + chunk2 + + + + chunk3 +"##; + let expected = r##"
    chunk1
    +
    +chunk2
    +
    +
    +
    +chunk3
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_82() { + let original = r##" chunk1 + + chunk2 +"##; + let expected = r##"
    chunk1
    +  
    +  chunk2
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_83() { + let original = r##"Foo + bar + +"##; + let expected = r##"

    Foo +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_84() { + let original = r##" foo +bar +"##; + let expected = r##"
    foo
    +
    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_85() { + let original = r##"# Heading + foo +Heading +------ + foo +---- +"##; + let expected = r##"

    Heading

    +
    foo
    +
    +

    Heading

    +
    foo
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_86() { + let original = r##" foo + bar +"##; + let expected = r##"
        foo
    +bar
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_87() { + let original = r##" + + foo + + +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_88() { + let original = r##" foo +"##; + let expected = r##"
    foo  
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_89() { + let original = r##"``` +< + > +``` +"##; + let expected = r##"
    <
    + >
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_90() { + let original = r##"~~~ +< + > +~~~ +"##; + let expected = r##"
    <
    + >
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_91() { + let original = r##"`` +foo +`` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_92() { + let original = r##"``` +aaa +~~~ +``` +"##; + let expected = r##"
    aaa
    +~~~
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_93() { + let original = r##"~~~ +aaa +``` +~~~ +"##; + let expected = r##"
    aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_94() { + let original = r##"```` +aaa +``` +`````` +"##; + let expected = r##"
    aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_95() { + let original = r##"~~~~ +aaa +~~~ +~~~~ +"##; + let expected = r##"
    aaa
    +~~~
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_96() { + let original = r##"``` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_97() { + let original = r##"````` + +``` +aaa +"##; + let expected = r##"
    
    +```
    +aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_98() { + let original = r##"> ``` +> aaa + +bbb +"##; + let expected = r##"
    +
    aaa
    +
    +
    +

    bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_99() { + let original = r##"``` + + +``` +"##; + let expected = r##"
    
    +  
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_100() { + let original = r##"``` +``` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_101() { + let original = r##" ``` + aaa +aaa +``` +"##; + let expected = r##"
    aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_102() { + let original = r##" ``` +aaa + aaa +aaa + ``` +"##; + let expected = r##"
    aaa
    +aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_103() { + let original = r##" ``` + aaa + aaa + aaa + ``` +"##; + let expected = r##"
    aaa
    + aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_104() { + let original = r##" ``` + aaa + ``` +"##; + let expected = r##"
    ```
    +aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_105() { + let original = r##"``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_106() { + let original = r##" ``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_107() { + let original = r##"``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +    ```
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_108() { + let original = r##"``` ``` +aaa +"##; + let expected = r##"

    +aaa

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_109() { + let original = r##"~~~~~~ +aaa +~~~ ~~ +"##; + let expected = r##"
    aaa
    +~~~ ~~
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_110() { + let original = r##"foo +``` +bar +``` +baz +"##; + let expected = r##"

    foo

    +
    bar
    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_111() { + let original = r##"foo +--- +~~~ +bar +~~~ +# baz +"##; + let expected = r##"

    foo

    +
    bar
    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_112() { + let original = r##"```ruby +def foo(x) + return 3 +end +``` +"##; + let expected = r##"
    def foo(x)
    +  return 3
    +end
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_113() { + let original = r##"~~~~ ruby startline=3 $%@#$ +def foo(x) + return 3 +end +~~~~~~~ +"##; + let expected = r##"
    def foo(x)
    +  return 3
    +end
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_114() { + let original = r##"````; +```` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_115() { + let original = r##"``` aa ``` +foo +"##; + let expected = r##"

    aa +foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_116() { + let original = r##"~~~ aa ``` ~~~ +foo +~~~ +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_117() { + let original = r##"``` +``` aaa +``` +"##; + let expected = r##"
    ``` aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_118() { + let original = r##"
    +
    +**Hello**,
    +
    +_world_.
    +
    +
    +"##; + let expected = r##"
    +
    +**Hello**,
    +

    world. +

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_119() { + let original = r##" + + + +
    + hi +
    + +okay. +"##; + let expected = r##" + + + +
    + hi +
    +

    okay.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_120() { + let original = r##"
    +*foo* +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_122() { + let original = r##"
    + +*Markdown* + +
    +"##; + let expected = r##"
    +

    Markdown

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_123() { + let original = r##"
    +
    +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_124() { + let original = r##"
    +
    +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_125() { + let original = r##"
    +*foo* + +*bar* +"##; + let expected = r##"
    +*foo* +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_126() { + let original = r##"
    +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_130() { + let original = r##"
    +foo +
    +"##; + let expected = r##"
    +foo +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_131() { + let original = r##"
    +``` c +int x = 33; +``` +"##; + let expected = r##"
    +``` c +int x = 33; +``` +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_132() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_133() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_134() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_135() { + let original = r##" +*bar* +"##; + let expected = r##" +*bar* +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_136() { + let original = r##" +*foo* + +"##; + let expected = r##" +*foo* + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_137() { + let original = r##" + +*foo* + + +"##; + let expected = r##" +

    foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_138() { + let original = r##"*foo* +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_139() { + let original = r##"
    
    +import Text.HTML.TagSoup
    +
    +main :: IO ()
    +main = print $ parseTags tags
    +
    +okay +"##; + let expected = r##"
    
    +import Text.HTML.TagSoup
    +
    +main :: IO ()
    +main = print $ parseTags tags
    +
    +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_140() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_141() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_142() { + let original = r##" +*foo* +"##; + let expected = r##" +

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_146() { + let original = r##"*bar* +*baz* +"##; + let expected = r##"*bar* +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_147() { + let original = r##"1. *bar* +"##; + let expected = r##"1. *bar* +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_148() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_149() { + let original = r##"'; + +?> +okay +"##; + let expected = r##"'; + +?> +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_150() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_151() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_152() { + let original = r##" + + +"##; + let expected = r##" +
    <!-- foo -->
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_153() { + let original = r##"
    + +
    +"##; + let expected = r##"
    +
    <div>
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_154() { + let original = r##"Foo +
    +bar +
    +"##; + let expected = r##"

    Foo

    +
    +bar +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_155() { + let original = r##"
    +bar +
    +*foo* +"##; + let expected = r##"
    +bar +
    +*foo* +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_156() { + let original = r##"Foo + +baz +"##; + let expected = r##"

    Foo + +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_157() { + let original = r##"
    + +*Emphasized* text. + +
    +"##; + let expected = r##"
    +

    Emphasized text.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_158() { + let original = r##"
    +*Emphasized* text. +
    +"##; + let expected = r##"
    +*Emphasized* text. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_159() { + let original = r##" + + + + + + + +
    +Hi +
    +"##; + let expected = r##" + + + +
    +Hi +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_160() { + let original = r##" + + + + + + + +
    + Hi +
    +"##; + let expected = r##" + +
    <td>
    +  Hi
    +</td>
    +
    + +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_161() { + let original = r##"[foo]: /url "title" + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_162() { + let original = r##" [foo]: + /url + 'the title' + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_163() { + let original = r##"[Foo*bar\]]:my_(url) 'title (with parens)' + +[Foo*bar\]] +"##; + let expected = r##"

    Foo*bar]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_164() { + let original = r##"[Foo bar]: + +'title' + +[Foo bar] +"##; + let expected = r##"

    Foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_165() { + let original = r##"[foo]: /url ' +title +line1 +line2 +' + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_166() { + let original = r##"[foo]: /url 'title + +with blank line' + +[foo] +"##; + let expected = r##"

    [foo]: /url 'title

    +

    with blank line'

    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_167() { + let original = r##"[foo]: +/url + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_168() { + let original = r##"[foo]: + +[foo] +"##; + let expected = r##"

    [foo]:

    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_169() { + let original = r##"[foo]: <> + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_170() { + let original = r##"[foo]: (baz) + +[foo] +"##; + let expected = r##"

    [foo]: (baz)

    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_171() { + let original = r##"[foo]: /url\bar\*baz "foo\"bar\baz" + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_172() { + let original = r##"[foo] + +[foo]: url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_173() { + let original = r##"[foo] + +[foo]: first +[foo]: second +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_174() { + let original = r##"[FOO]: /url + +[Foo] +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_175() { + let original = r##"[ΑΓΩ]: /φου + +[αγω] +"##; + let expected = r##"

    αγω

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_176() { + let original = r##"[foo]: /url +"##; + let expected = r##""##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_177() { + let original = r##"[ +foo +]: /url +bar +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_178() { + let original = r##"[foo]: /url "title" ok +"##; + let expected = r##"

    [foo]: /url "title" ok

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_179() { + let original = r##"[foo]: /url +"title" ok +"##; + let expected = r##"

    "title" ok

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_180() { + let original = r##" [foo]: /url "title" + +[foo] +"##; + let expected = r##"
    [foo]: /url "title"
    +
    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_181() { + let original = r##"``` +[foo]: /url +``` + +[foo] +"##; + let expected = r##"
    [foo]: /url
    +
    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_182() { + let original = r##"Foo +[bar]: /baz + +[bar] +"##; + let expected = r##"

    Foo +[bar]: /baz

    +

    [bar]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_183() { + let original = r##"# [Foo] +[foo]: /url +> bar +"##; + let expected = r##"

    Foo

    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_184() { + let original = r##"[foo]: /url +bar +=== +[foo] +"##; + let expected = r##"

    bar

    +

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_185() { + let original = r##"[foo]: /url +=== +[foo] +"##; + let expected = r##"

    === +foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_186() { + let original = r##"[foo]: /foo-url "foo" +[bar]: /bar-url + "bar" +[baz]: /baz-url + +[foo], +[bar], +[baz] +"##; + let expected = r##"

    foo, +bar, +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_187() { + let original = r##"[foo] + +> [foo]: /url +"##; + let expected = r##"

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_188() { + let original = r##"[foo]: /url +"##; + let expected = r##""##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_189() { + let original = r##"aaa + +bbb +"##; + let expected = r##"

    aaa

    +

    bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_190() { + let original = r##"aaa +bbb + +ccc +ddd +"##; + let expected = r##"

    aaa +bbb

    +

    ccc +ddd

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_191() { + let original = r##"aaa + + +bbb +"##; + let expected = r##"

    aaa

    +

    bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_192() { + let original = r##" aaa + bbb +"##; + let expected = r##"

    aaa +bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_193() { + let original = r##"aaa + bbb + ccc +"##; + let expected = r##"

    aaa +bbb +ccc

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_194() { + let original = r##" aaa +bbb +"##; + let expected = r##"

    aaa +bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_195() { + let original = r##" aaa +bbb +"##; + let expected = r##"
    aaa
    +
    +

    bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_196() { + let original = r##"aaa +bbb +"##; + let expected = r##"

    aaa
    +bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_197() { + let original = r##" + +aaa + + +# aaa + + +"##; + let expected = r##"

    aaa

    +

    aaa

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_198() { + let original = r##"> # Foo +> bar +> baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_199() { + let original = r##"># Foo +>bar +> baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_200() { + let original = r##" > # Foo + > bar + > baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_201() { + let original = r##" > # Foo + > bar + > baz +"##; + let expected = r##"
    > # Foo
    +> bar
    +> baz
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_202() { + let original = r##"> # Foo +> bar +baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_203() { + let original = r##"> bar +baz +> foo +"##; + let expected = r##"
    +

    bar +baz +foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_204() { + let original = r##"> foo +--- +"##; + let expected = r##"
    +

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_205() { + let original = r##"> - foo +- bar +"##; + let expected = r##"
    +
      +
    • foo
    • +
    +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_206() { + let original = r##"> foo + bar +"##; + let expected = r##"
    +
    foo
    +
    +
    +
    bar
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_207() { + let original = r##"> ``` +foo +``` +"##; + let expected = r##"
    +
    +
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_208() { + let original = r##"> foo + - bar +"##; + let expected = r##"
    +

    foo +- bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_209() { + let original = r##"> +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_210() { + let original = r##"> +> +> +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_211() { + let original = r##"> +> foo +> +"##; + let expected = r##"
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_212() { + let original = r##"> foo + +> bar +"##; + let expected = r##"
    +

    foo

    +
    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_213() { + let original = r##"> foo +> bar +"##; + let expected = r##"
    +

    foo +bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_214() { + let original = r##"> foo +> +> bar +"##; + let expected = r##"
    +

    foo

    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_215() { + let original = r##"foo +> bar +"##; + let expected = r##"

    foo

    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_216() { + let original = r##"> aaa +*** +> bbb +"##; + let expected = r##"
    +

    aaa

    +
    +
    +
    +

    bbb

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_217() { + let original = r##"> bar +baz +"##; + let expected = r##"
    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_218() { + let original = r##"> bar + +baz +"##; + let expected = r##"
    +

    bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_219() { + let original = r##"> bar +> +baz +"##; + let expected = r##"
    +

    bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_220() { + let original = r##"> > > foo +bar +"##; + let expected = r##"
    +
    +
    +

    foo +bar

    +
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_221() { + let original = r##">>> foo +> bar +>>baz +"##; + let expected = r##"
    +
    +
    +

    foo +bar +baz

    +
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_222() { + let original = r##"> code + +> not code +"##; + let expected = r##"
    +
    code
    +
    +
    +
    +

    not code

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_223() { + let original = r##"A paragraph +with two lines. + + indented code + +> A block quote. +"##; + let expected = r##"

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_224() { + let original = r##"1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_225() { + let original = r##"- one + + two +"##; + let expected = r##"
      +
    • one
    • +
    +

    two

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_226() { + let original = r##"- one + + two +"##; + let expected = r##"
      +
    • +

      one

      +

      two

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_227() { + let original = r##" - one + + two +"##; + let expected = r##"
      +
    • one
    • +
    +
     two
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_228() { + let original = r##" - one + + two +"##; + let expected = r##"
      +
    • +

      one

      +

      two

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_229() { + let original = r##" > > 1. one +>> +>> two +"##; + let expected = r##"
    +
    +
      +
    1. +

      one

      +

      two

      +
    2. +
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_230() { + let original = r##">>- one +>> + > > two +"##; + let expected = r##"
    +
    +
      +
    • one
    • +
    +

    two

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_231() { + let original = r##"-one + +2.two +"##; + let expected = r##"

    -one

    +

    2.two

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_232() { + let original = r##"- foo + + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_233() { + let original = r##"1. foo + + ``` + bar + ``` + + baz + + > bam +"##; + let expected = r##"
      +
    1. +

      foo

      +
      bar
      +
      +

      baz

      +
      +

      bam

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_234() { + let original = r##"- Foo + + bar + + + baz +"##; + let expected = r##"
      +
    • +

      Foo

      +
      bar
      +
      +
      +baz
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_235() { + let original = r##"123456789. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_236() { + let original = r##"1234567890. not ok +"##; + let expected = r##"

    1234567890. not ok

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_237() { + let original = r##"0. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_238() { + let original = r##"003. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_239() { + let original = r##"-1. not ok +"##; + let expected = r##"

    -1. not ok

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_240() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +
      bar
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_241() { + let original = r##" 10. foo + + bar +"##; + let expected = r##"
      +
    1. +

      foo

      +
      bar
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_242() { + let original = r##" indented code + +paragraph + + more code +"##; + let expected = r##"
    indented code
    +
    +

    paragraph

    +
    more code
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_243() { + let original = r##"1. indented code + + paragraph + + more code +"##; + let expected = r##"
      +
    1. +
      indented code
      +
      +

      paragraph

      +
      more code
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_244() { + let original = r##"1. indented code + + paragraph + + more code +"##; + let expected = r##"
      +
    1. +
       indented code
      +
      +

      paragraph

      +
      more code
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_245() { + let original = r##" foo + +bar +"##; + let expected = r##"

    foo

    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_246() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • foo
    • +
    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_247() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_248() { + let original = r##"- + foo +- + ``` + bar + ``` +- + baz +"##; + let expected = r##"
      +
    • foo
    • +
    • +
      bar
      +
      +
    • +
    • +
      baz
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_249() { + let original = r##"- + foo +"##; + let expected = r##"
      +
    • foo
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_250() { + let original = r##"- + + foo +"##; + let expected = r##"
      +
    • +
    +

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_251() { + let original = r##"- foo +- +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_252() { + let original = r##"- foo +- +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_253() { + let original = r##"1. foo +2. +3. bar +"##; + let expected = r##"
      +
    1. foo
    2. +
    3. +
    4. bar
    5. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_254() { + let original = r##"* +"##; + let expected = r##"
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_255() { + let original = r##"foo +* + +foo +1. +"##; + let expected = r##"

    foo +*

    +

    foo +1.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_256() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_257() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_258() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_259() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
    1.  A paragraph
    +    with two lines.
    +
    +        indented code
    +
    +    > A block quote.
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_260() { + let original = r##" 1. A paragraph +with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_261() { + let original = r##" 1. A paragraph + with two lines. +"##; + let expected = r##"
      +
    1. A paragraph +with two lines.
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_262() { + let original = r##"> 1. > Blockquote +continued here. +"##; + let expected = r##"
    +
      +
    1. +
      +

      Blockquote +continued here.

      +
      +
    2. +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_263() { + let original = r##"> 1. > Blockquote +> continued here. +"##; + let expected = r##"
    +
      +
    1. +
      +

      Blockquote +continued here.

      +
      +
    2. +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_264() { + let original = r##"- foo + - bar + - baz + - boo +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • baz +
            +
          • boo
          • +
          +
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_265() { + let original = r##"- foo + - bar + - baz + - boo +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    • baz
    • +
    • boo
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_266() { + let original = r##"10) foo + - bar +"##; + let expected = r##"
      +
    1. foo +
        +
      • bar
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_267() { + let original = r##"10) foo + - bar +"##; + let expected = r##"
      +
    1. foo
    2. +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_268() { + let original = r##"- - foo +"##; + let expected = r##"
      +
    • +
        +
      • foo
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_269() { + let original = r##"1. - 2. foo +"##; + let expected = r##"
      +
    1. +
        +
      • +
          +
        1. foo
        2. +
        +
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_270() { + let original = r##"- # Foo +- Bar + --- + baz +"##; + let expected = r##"
      +
    • +

      Foo

      +
    • +
    • +

      Bar

      +baz
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_271() { + let original = r##"- foo +- bar ++ baz +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    +
      +
    • baz
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_272() { + let original = r##"1. foo +2. bar +3) baz +"##; + let expected = r##"
      +
    1. foo
    2. +
    3. bar
    4. +
    +
      +
    1. baz
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_273() { + let original = r##"Foo +- bar +- baz +"##; + let expected = r##"

    Foo

    +
      +
    • bar
    • +
    • baz
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_274() { + let original = r##"The number of windows in my house is +14. The number of doors is 6. +"##; + let expected = r##"

    The number of windows in my house is +14. The number of doors is 6.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_275() { + let original = r##"The number of windows in my house is +1. The number of doors is 6. +"##; + let expected = r##"

    The number of windows in my house is

    +
      +
    1. The number of doors is 6.
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_276() { + let original = r##"- foo + +- bar + + +- baz +"##; + let expected = r##"
      +
    • +

      foo

      +
    • +
    • +

      bar

      +
    • +
    • +

      baz

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_277() { + let original = r##"- foo + - bar + - baz + + + bim +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • +

          baz

          +

          bim

          +
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_278() { + let original = r##"- foo +- bar + + + +- baz +- bim +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    + +
      +
    • baz
    • +
    • bim
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_279() { + let original = r##"- foo + + notcode + +- foo + + + + code +"##; + let expected = r##"
      +
    • +

      foo

      +

      notcode

      +
    • +
    • +

      foo

      +
    • +
    + +
    code
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_280() { + let original = r##"- a + - b + - c + - d + - e + - f +- g +"##; + let expected = r##"
      +
    • a
    • +
    • b
    • +
    • c
    • +
    • d
    • +
    • e
    • +
    • f
    • +
    • g
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_281() { + let original = r##"1. a + + 2. b + + 3. c +"##; + let expected = r##"
      +
    1. +

      a

      +
    2. +
    3. +

      b

      +
    4. +
    5. +

      c

      +
    6. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_282() { + let original = r##"- a + - b + - c + - d + - e +"##; + let expected = r##"
      +
    • a
    • +
    • b
    • +
    • c
    • +
    • d +- e
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_283() { + let original = r##"1. a + + 2. b + + 3. c +"##; + let expected = r##"
      +
    1. +

      a

      +
    2. +
    3. +

      b

      +
    4. +
    +
    3. c
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_284() { + let original = r##"- a +- b + +- c +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +
    • +
    • +

      c

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_285() { + let original = r##"* a +* + +* c +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +
    • +

      c

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_286() { + let original = r##"- a +- b + + c +- d +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +

      c

      +
    • +
    • +

      d

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_287() { + let original = r##"- a +- b + + [ref]: /url +- d +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +
    • +
    • +

      d

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_288() { + let original = r##"- a +- ``` + b + + + ``` +- c +"##; + let expected = r##"
      +
    • a
    • +
    • +
      b
      +
      +
      +
      +
    • +
    • c
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_289() { + let original = r##"- a + - b + + c +- d +"##; + let expected = r##"
      +
    • a +
        +
      • +

        b

        +

        c

        +
      • +
      +
    • +
    • d
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_290() { + let original = r##"* a + > b + > +* c +"##; + let expected = r##"
      +
    • a +
      +

      b

      +
      +
    • +
    • c
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_291() { + let original = r##"- a + > b + ``` + c + ``` +- d +"##; + let expected = r##"
      +
    • a +
      +

      b

      +
      +
      c
      +
      +
    • +
    • d
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_292() { + let original = r##"- a +"##; + let expected = r##"
      +
    • a
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_293() { + let original = r##"- a + - b +"##; + let expected = r##"
      +
    • a +
        +
      • b
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_294() { + let original = r##"1. ``` + foo + ``` + + bar +"##; + let expected = r##"
      +
    1. +
      foo
      +
      +

      bar

      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_295() { + let original = r##"* foo + * bar + + baz +"##; + let expected = r##"
      +
    • +

      foo

      +
        +
      • bar
      • +
      +

      baz

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_296() { + let original = r##"- a + - b + - c + +- d + - e + - f +"##; + let expected = r##"
      +
    • +

      a

      +
        +
      • b
      • +
      • c
      • +
      +
    • +
    • +

      d

      +
        +
      • e
      • +
      • f
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_297() { + let original = r##"`hi`lo` +"##; + let expected = r##"

    hilo`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_298() { + let original = r##"\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ +"##; + let expected = r##"

    !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_299() { + let original = r##"\ \A\a\ \3\φ\« +"##; + let expected = r##"

    \ \A\a\ \3\φ\«

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_300() { + let original = r##"\*not emphasized* +\
    not a tag +\[not a link](/foo) +\`not code` +1\. not a list +\* not a list +\# not a heading +\[foo]: /url "not a reference" +\ö not a character entity +"##; + let expected = r##"

    *not emphasized* +<br/> not a tag +[not a link](/foo) +`not code` +1. not a list +* not a list +# not a heading +[foo]: /url "not a reference" +&ouml; not a character entity

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_301() { + let original = r##"\\*emphasis* +"##; + let expected = r##"

    \emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_302() { + let original = r##"foo\ +bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_303() { + let original = r##"`` \[\` `` +"##; + let expected = r##"

    \[\`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_304() { + let original = r##" \[\] +"##; + let expected = r##"
    \[\]
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_305() { + let original = r##"~~~ +\[\] +~~~ +"##; + let expected = r##"
    \[\]
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_306() { + let original = r##" +"##; + let expected = r##"

    http://example.com?find=\*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_307() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_308() { + let original = r##"[foo](/bar\* "ti\*tle") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_309() { + let original = r##"[foo] + +[foo]: /bar\* "ti\*tle" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_310() { + let original = r##"``` foo\+bar +foo +``` +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_311() { + let original = r##"  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸ +"##; + let expected = r##"

      & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_312() { + let original = r##"# Ӓ Ϡ � +"##; + let expected = r##"

    # Ӓ Ϡ �

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_313() { + let original = r##"" ആ ಫ +"##; + let expected = r##"

    " ആ ಫ

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_314() { + let original = r##"  &x; &#; &#x; +� +&#abcdef0; +&ThisIsNotDefined; &hi?; +"##; + let expected = r##"

    &nbsp &x; &#; &#x; +&#87654321; +&#abcdef0; +&ThisIsNotDefined; &hi?;

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_315() { + let original = r##"© +"##; + let expected = r##"

    &copy

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_316() { + let original = r##"&MadeUpEntity; +"##; + let expected = r##"

    &MadeUpEntity;

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_317() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_318() { + let original = r##"[foo](/föö "föö") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_319() { + let original = r##"[foo] + +[foo]: /föö "föö" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_320() { + let original = r##"``` föö +foo +``` +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_321() { + let original = r##"`föö` +"##; + let expected = r##"

    f&ouml;&ouml;

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_322() { + let original = r##" föfö +"##; + let expected = r##"
    f&ouml;f&ouml;
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_323() { + let original = r##"*foo* +*foo* +"##; + let expected = r##"

    *foo* +foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_324() { + let original = r##"* foo + +* foo +"##; + let expected = r##"

    * foo

    +
      +
    • foo
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_325() { + let original = r##"foo bar +"##; + let expected = r##"

    foo + +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_326() { + let original = r##" foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_327() { + let original = r##"[a](url "tit") +"##; + let expected = r##"

    [a](url "tit")

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_328() { + let original = r##"`foo` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_329() { + let original = r##"`` foo ` bar `` +"##; + let expected = r##"

    foo ` bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_330() { + let original = r##"` `` ` +"##; + let expected = r##"

    ``

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_331() { + let original = r##"` `` ` +"##; + let expected = r##"

    ``

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_332() { + let original = r##"` a` +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_333() { + let original = r##"` b ` +"##; + let expected = r##"

     b 

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_334() { + let original = r##"` ` +` ` +"##; + let expected = r##"

      +

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_335() { + let original = r##"`` +foo +bar +baz +`` +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_336() { + let original = r##"`` +foo +`` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_337() { + let original = r##"`foo bar +baz` +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_338() { + let original = r##"`foo\`bar` +"##; + let expected = r##"

    foo\bar`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_339() { + let original = r##"``foo`bar`` +"##; + let expected = r##"

    foo`bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_340() { + let original = r##"` foo `` bar ` +"##; + let expected = r##"

    foo `` bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_341() { + let original = r##"*foo`*` +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_342() { + let original = r##"[not a `link](/foo`) +"##; + let expected = r##"

    [not a link](/foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_343() { + let original = r##"`` +"##; + let expected = r##"

    <a href="">`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_344() { + let original = r##"
    ` +"##; + let expected = r##"

    `

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_345() { + let original = r##"`` +"##; + let expected = r##"

    <http://foo.bar.baz>`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_346() { + let original = r##"` +"##; + let expected = r##"

    http://foo.bar.`baz`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_347() { + let original = r##"```foo`` +"##; + let expected = r##"

    ```foo``

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_348() { + let original = r##"`foo +"##; + let expected = r##"

    `foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_349() { + let original = r##"`foo``bar`` +"##; + let expected = r##"

    `foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_350() { + let original = r##"*foo bar* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_351() { + let original = r##"a * foo bar* +"##; + let expected = r##"

    a * foo bar*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_352() { + let original = r##"a*"foo"* +"##; + let expected = r##"

    a*"foo"*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_353() { + let original = r##"* a * +"##; + let expected = r##"

    * a *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_354() { + let original = r##"foo*bar* +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_355() { + let original = r##"5*6*78 +"##; + let expected = r##"

    5678

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_356() { + let original = r##"_foo bar_ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_357() { + let original = r##"_ foo bar_ +"##; + let expected = r##"

    _ foo bar_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_358() { + let original = r##"a_"foo"_ +"##; + let expected = r##"

    a_"foo"_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_359() { + let original = r##"foo_bar_ +"##; + let expected = r##"

    foo_bar_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_360() { + let original = r##"5_6_78 +"##; + let expected = r##"

    5_6_78

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_361() { + let original = r##"пристаням_стремятся_ +"##; + let expected = r##"

    пристаням_стремятся_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_362() { + let original = r##"aa_"bb"_cc +"##; + let expected = r##"

    aa_"bb"_cc

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_363() { + let original = r##"foo-_(bar)_ +"##; + let expected = r##"

    foo-(bar)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_364() { + let original = r##"_foo* +"##; + let expected = r##"

    _foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_365() { + let original = r##"*foo bar * +"##; + let expected = r##"

    *foo bar *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_366() { + let original = r##"*foo bar +* +"##; + let expected = r##"

    *foo bar +*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_367() { + let original = r##"*(*foo) +"##; + let expected = r##"

    *(*foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_368() { + let original = r##"*(*foo*)* +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_369() { + let original = r##"*foo*bar +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_370() { + let original = r##"_foo bar _ +"##; + let expected = r##"

    _foo bar _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_371() { + let original = r##"_(_foo) +"##; + let expected = r##"

    _(_foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_372() { + let original = r##"_(_foo_)_ +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_373() { + let original = r##"_foo_bar +"##; + let expected = r##"

    _foo_bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_374() { + let original = r##"_пристаням_стремятся +"##; + let expected = r##"

    _пристаням_стремятся

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_375() { + let original = r##"_foo_bar_baz_ +"##; + let expected = r##"

    foo_bar_baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_376() { + let original = r##"_(bar)_. +"##; + let expected = r##"

    (bar).

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_377() { + let original = r##"**foo bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_378() { + let original = r##"** foo bar** +"##; + let expected = r##"

    ** foo bar**

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_379() { + let original = r##"a**"foo"** +"##; + let expected = r##"

    a**"foo"**

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_380() { + let original = r##"foo**bar** +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_381() { + let original = r##"__foo bar__ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_382() { + let original = r##"__ foo bar__ +"##; + let expected = r##"

    __ foo bar__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_383() { + let original = r##"__ +foo bar__ +"##; + let expected = r##"

    __ +foo bar__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_384() { + let original = r##"a__"foo"__ +"##; + let expected = r##"

    a__"foo"__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_385() { + let original = r##"foo__bar__ +"##; + let expected = r##"

    foo__bar__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_386() { + let original = r##"5__6__78 +"##; + let expected = r##"

    5__6__78

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_387() { + let original = r##"пристаням__стремятся__ +"##; + let expected = r##"

    пристаням__стремятся__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_388() { + let original = r##"__foo, __bar__, baz__ +"##; + let expected = r##"

    foo, bar, baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_389() { + let original = r##"foo-__(bar)__ +"##; + let expected = r##"

    foo-(bar)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_390() { + let original = r##"**foo bar ** +"##; + let expected = r##"

    **foo bar **

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_391() { + let original = r##"**(**foo) +"##; + let expected = r##"

    **(**foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_392() { + let original = r##"*(**foo**)* +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_393() { + let original = r##"**Gomphocarpus (*Gomphocarpus physocarpus*, syn. +*Asclepias physocarpa*)** +"##; + let expected = r##"

    Gomphocarpus (Gomphocarpus physocarpus, syn. +Asclepias physocarpa)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_394() { + let original = r##"**foo "*bar*" foo** +"##; + let expected = r##"

    foo "bar" foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_395() { + let original = r##"**foo**bar +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_396() { + let original = r##"__foo bar __ +"##; + let expected = r##"

    __foo bar __

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_397() { + let original = r##"__(__foo) +"##; + let expected = r##"

    __(__foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_398() { + let original = r##"_(__foo__)_ +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_399() { + let original = r##"__foo__bar +"##; + let expected = r##"

    __foo__bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_400() { + let original = r##"__пристаням__стремятся +"##; + let expected = r##"

    __пристаням__стремятся

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_401() { + let original = r##"__foo__bar__baz__ +"##; + let expected = r##"

    foo__bar__baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_402() { + let original = r##"__(bar)__. +"##; + let expected = r##"

    (bar).

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_403() { + let original = r##"*foo [bar](/url)* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_404() { + let original = r##"*foo +bar* +"##; + let expected = r##"

    foo +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_405() { + let original = r##"_foo __bar__ baz_ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_406() { + let original = r##"_foo _bar_ baz_ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_407() { + let original = r##"__foo_ bar_ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_408() { + let original = r##"*foo *bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_409() { + let original = r##"*foo **bar** baz* +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_410() { + let original = r##"*foo**bar**baz* +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_411() { + let original = r##"*foo**bar* +"##; + let expected = r##"

    foo**bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_412() { + let original = r##"***foo** bar* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_413() { + let original = r##"*foo **bar*** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_414() { + let original = r##"*foo**bar*** +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_415() { + let original = r##"foo***bar***baz +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_416() { + let original = r##"foo******bar*********baz +"##; + let expected = r##"

    foobar***baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_417() { + let original = r##"*foo **bar *baz* bim** bop* +"##; + let expected = r##"

    foo bar baz bim bop

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_418() { + let original = r##"*foo [*bar*](/url)* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_419() { + let original = r##"** is not an empty emphasis +"##; + let expected = r##"

    ** is not an empty emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_420() { + let original = r##"**** is not an empty strong emphasis +"##; + let expected = r##"

    **** is not an empty strong emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_421() { + let original = r##"**foo [bar](/url)** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_422() { + let original = r##"**foo +bar** +"##; + let expected = r##"

    foo +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_423() { + let original = r##"__foo _bar_ baz__ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_424() { + let original = r##"__foo __bar__ baz__ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_425() { + let original = r##"____foo__ bar__ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_426() { + let original = r##"**foo **bar**** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_427() { + let original = r##"**foo *bar* baz** +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_428() { + let original = r##"**foo*bar*baz** +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_429() { + let original = r##"***foo* bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_430() { + let original = r##"**foo *bar*** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_431() { + let original = r##"**foo *bar **baz** +bim* bop** +"##; + let expected = r##"

    foo bar baz +bim bop

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_432() { + let original = r##"**foo [*bar*](/url)** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_433() { + let original = r##"__ is not an empty emphasis +"##; + let expected = r##"

    __ is not an empty emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_434() { + let original = r##"____ is not an empty strong emphasis +"##; + let expected = r##"

    ____ is not an empty strong emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_435() { + let original = r##"foo *** +"##; + let expected = r##"

    foo ***

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_436() { + let original = r##"foo *\** +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_437() { + let original = r##"foo *_* +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_438() { + let original = r##"foo ***** +"##; + let expected = r##"

    foo *****

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_439() { + let original = r##"foo **\*** +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_440() { + let original = r##"foo **_** +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_441() { + let original = r##"**foo* +"##; + let expected = r##"

    *foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_442() { + let original = r##"*foo** +"##; + let expected = r##"

    foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_443() { + let original = r##"***foo** +"##; + let expected = r##"

    *foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_444() { + let original = r##"****foo* +"##; + let expected = r##"

    ***foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_445() { + let original = r##"**foo*** +"##; + let expected = r##"

    foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_446() { + let original = r##"*foo**** +"##; + let expected = r##"

    foo***

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_447() { + let original = r##"foo ___ +"##; + let expected = r##"

    foo ___

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_448() { + let original = r##"foo _\__ +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_449() { + let original = r##"foo _*_ +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_450() { + let original = r##"foo _____ +"##; + let expected = r##"

    foo _____

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_451() { + let original = r##"foo __\___ +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_452() { + let original = r##"foo __*__ +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_453() { + let original = r##"__foo_ +"##; + let expected = r##"

    _foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_454() { + let original = r##"_foo__ +"##; + let expected = r##"

    foo_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_455() { + let original = r##"___foo__ +"##; + let expected = r##"

    _foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_456() { + let original = r##"____foo_ +"##; + let expected = r##"

    ___foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_457() { + let original = r##"__foo___ +"##; + let expected = r##"

    foo_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_458() { + let original = r##"_foo____ +"##; + let expected = r##"

    foo___

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_459() { + let original = r##"**foo** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_460() { + let original = r##"*_foo_* +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_461() { + let original = r##"__foo__ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_462() { + let original = r##"_*foo*_ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_463() { + let original = r##"****foo**** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_464() { + let original = r##"____foo____ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_465() { + let original = r##"******foo****** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_466() { + let original = r##"***foo*** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_467() { + let original = r##"_____foo_____ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_468() { + let original = r##"*foo _bar* baz_ +"##; + let expected = r##"

    foo _bar baz_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_469() { + let original = r##"*foo __bar *baz bim__ bam* +"##; + let expected = r##"

    foo bar *baz bim bam

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_470() { + let original = r##"**foo **bar baz** +"##; + let expected = r##"

    **foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_471() { + let original = r##"*foo *bar baz* +"##; + let expected = r##"

    *foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_472() { + let original = r##"*[bar*](/url) +"##; + let expected = r##"

    *bar*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_473() { + let original = r##"_foo [bar_](/url) +"##; + let expected = r##"

    _foo bar_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_474() { + let original = r##"* +"##; + let expected = r##"

    *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_475() { + let original = r##"** +"##; + let expected = r##"

    **

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_476() { + let original = r##"__ +"##; + let expected = r##"

    __

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_477() { + let original = r##"*a `*`* +"##; + let expected = r##"

    a *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_478() { + let original = r##"_a `_`_ +"##; + let expected = r##"

    a _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_479() { + let original = r##"**a +"##; + let expected = r##"

    **ahttp://foo.bar/?q=**

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_480() { + let original = r##"__a +"##; + let expected = r##"

    __ahttp://foo.bar/?q=__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_481() { + let original = r##"[link](/uri "title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_482() { + let original = r##"[link](/uri) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_483() { + let original = r##"[link]() +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_484() { + let original = r##"[link](<>) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_485() { + let original = r##"[link](/my uri) +"##; + let expected = r##"

    [link](/my uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_486() { + let original = r##"[link](
    ) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_487() { + let original = r##"[link](foo +bar) +"##; + let expected = r##"

    [link](foo +bar)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_488() { + let original = r##"[link]() +"##; + let expected = r##"

    [link]()

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_489() { + let original = r##"[a]() +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_490() { + let original = r##"[link]() +"##; + let expected = r##"

    [link](<foo>)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_491() { + let original = r##"[a]( +[a](c) +"##; + let expected = r##"

    [a](<b)c +[a](<b)c> +[a](c)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_492() { + let original = r##"[link](\(foo\)) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_493() { + let original = r##"[link](foo(and(bar))) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_494() { + let original = r##"[link](foo\(and\(bar\)) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_495() { + let original = r##"[link]() +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_496() { + let original = r##"[link](foo\)\:) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_497() { + let original = r##"[link](#fragment) + +[link](http://example.com#fragment) + +[link](http://example.com?foo=3#frag) +"##; + let expected = r##"

    link

    +

    link

    +

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_498() { + let original = r##"[link](foo\bar) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_499() { + let original = r##"[link](foo%20bä) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_500() { + let original = r##"[link]("title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_501() { + let original = r##"[link](/url "title") +[link](/url 'title') +[link](/url (title)) +"##; + let expected = r##"

    link +link +link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_502() { + let original = r##"[link](/url "title \""") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_503() { + let original = r##"[link](/url "title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_504() { + let original = r##"[link](/url "title "and" title") +"##; + let expected = r##"

    [link](/url "title "and" title")

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_505() { + let original = r##"[link](/url 'title "and" title') +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_506() { + let original = r##"[link]( /uri + "title" ) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_507() { + let original = r##"[link] (/uri) +"##; + let expected = r##"

    [link] (/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_508() { + let original = r##"[link [foo [bar]]](/uri) +"##; + let expected = r##"

    link [foo [bar]]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_509() { + let original = r##"[link] bar](/uri) +"##; + let expected = r##"

    [link] bar](/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_510() { + let original = r##"[link [bar](/uri) +"##; + let expected = r##"

    [link bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_511() { + let original = r##"[link \[bar](/uri) +"##; + let expected = r##"

    link [bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_512() { + let original = r##"[link *foo **bar** `#`*](/uri) +"##; + let expected = r##"

    link foo bar #

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_513() { + let original = r##"[![moon](moon.jpg)](/uri) +"##; + let expected = r##"

    moon

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_514() { + let original = r##"[foo [bar](/uri)](/uri) +"##; + let expected = r##"

    [foo bar](/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_515() { + let original = r##"[foo *[bar [baz](/uri)](/uri)*](/uri) +"##; + let expected = r##"

    [foo [bar baz](/uri)](/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_516() { + let original = r##"![[[foo](uri1)](uri2)](uri3) +"##; + let expected = r##"

    [foo](uri2)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_517() { + let original = r##"*[foo*](/uri) +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_518() { + let original = r##"[foo *bar](baz*) +"##; + let expected = r##"

    foo *bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_519() { + let original = r##"*foo [bar* baz] +"##; + let expected = r##"

    foo [bar baz]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_520() { + let original = r##"[foo +"##; + let expected = r##"

    [foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_521() { + let original = r##"[foo`](/uri)` +"##; + let expected = r##"

    [foo](/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_522() { + let original = r##"[foo +"##; + let expected = r##"

    [foohttp://example.com/?search=](uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_523() { + let original = r##"[foo][bar] + +[bar]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_524() { + let original = r##"[link [foo [bar]]][ref] + +[ref]: /uri +"##; + let expected = r##"

    link [foo [bar]]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_525() { + let original = r##"[link \[bar][ref] + +[ref]: /uri +"##; + let expected = r##"

    link [bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_526() { + let original = r##"[link *foo **bar** `#`*][ref] + +[ref]: /uri +"##; + let expected = r##"

    link foo bar #

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_527() { + let original = r##"[![moon](moon.jpg)][ref] + +[ref]: /uri +"##; + let expected = r##"

    moon

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_528() { + let original = r##"[foo [bar](/uri)][ref] + +[ref]: /uri +"##; + let expected = r##"

    [foo bar]ref

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_529() { + let original = r##"[foo *bar [baz][ref]*][ref] + +[ref]: /uri +"##; + let expected = r##"

    [foo bar baz]ref

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_530() { + let original = r##"*[foo*][ref] + +[ref]: /uri +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_531() { + let original = r##"[foo *bar][ref] + +[ref]: /uri +"##; + let expected = r##"

    foo *bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_532() { + let original = r##"[foo + +[ref]: /uri +"##; + let expected = r##"

    [foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_533() { + let original = r##"[foo`][ref]` + +[ref]: /uri +"##; + let expected = r##"

    [foo][ref]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_534() { + let original = r##"[foo + +[ref]: /uri +"##; + let expected = r##"

    [foohttp://example.com/?search=][ref]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_535() { + let original = r##"[foo][BaR] + +[bar]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_536() { + let original = r##"[Толпой][Толпой] is a Russian word. + +[ТОЛПОЙ]: /url +"##; + let expected = r##"

    Толпой is a Russian word.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_537() { + let original = r##"[Foo + bar]: /url + +[Baz][Foo bar] +"##; + let expected = r##"

    Baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_538() { + let original = r##"[foo] [bar] + +[bar]: /url "title" +"##; + let expected = r##"

    [foo] bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_539() { + let original = r##"[foo] +[bar] + +[bar]: /url "title" +"##; + let expected = r##"

    [foo] +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_540() { + let original = r##"[foo]: /url1 + +[foo]: /url2 + +[bar][foo] +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_541() { + let original = r##"[bar][foo\!] + +[foo!]: /url +"##; + let expected = r##"

    [bar][foo!]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_542() { + let original = r##"[foo][ref[] + +[ref[]: /uri +"##; + let expected = r##"

    [foo][ref[]

    +

    [ref[]: /uri

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_543() { + let original = r##"[foo][ref[bar]] + +[ref[bar]]: /uri +"##; + let expected = r##"

    [foo][ref[bar]]

    +

    [ref[bar]]: /uri

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_544() { + let original = r##"[[[foo]]] + +[[[foo]]]: /url +"##; + let expected = r##"

    [[[foo]]]

    +

    [[[foo]]]: /url

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_545() { + let original = r##"[foo][ref\[] + +[ref\[]: /uri +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_546() { + let original = r##"[bar\\]: /uri + +[bar\\] +"##; + let expected = r##"

    bar\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_547() { + let original = r##"[] + +[]: /uri +"##; + let expected = r##"

    []

    +

    []: /uri

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_548() { + let original = r##"[ + ] + +[ + ]: /uri +"##; + let expected = r##"

    [ +]

    +

    [ +]: /uri

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_549() { + let original = r##"[foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_550() { + let original = r##"[*foo* bar][] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_551() { + let original = r##"[Foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_552() { + let original = r##"[foo] +[] + +[foo]: /url "title" +"##; + let expected = r##"

    foo +[]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_553() { + let original = r##"[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_554() { + let original = r##"[*foo* bar] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_555() { + let original = r##"[[*foo* bar]] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    [foo bar]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_556() { + let original = r##"[[bar [foo] + +[foo]: /url +"##; + let expected = r##"

    [[bar foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_557() { + let original = r##"[Foo] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_558() { + let original = r##"[foo] bar + +[foo]: /url +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_559() { + let original = r##"\[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_560() { + let original = r##"[foo*]: /url + +*[foo*] +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_561() { + let original = r##"[foo][bar] + +[foo]: /url1 +[bar]: /url2 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_562() { + let original = r##"[foo][] + +[foo]: /url1 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_563() { + let original = r##"[foo]() + +[foo]: /url1 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_564() { + let original = r##"[foo](not a link) + +[foo]: /url1 +"##; + let expected = r##"

    foo(not a link)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_565() { + let original = r##"[foo][bar][baz] + +[baz]: /url +"##; + let expected = r##"

    [foo]bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_566() { + let original = r##"[foo][bar][baz] + +[baz]: /url1 +[bar]: /url2 +"##; + let expected = r##"

    foobaz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_567() { + let original = r##"[foo][bar][baz] + +[baz]: /url1 +[foo]: /url2 +"##; + let expected = r##"

    [foo]bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_568() { + let original = r##"![foo](/url "title") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_569() { + let original = r##"![foo *bar*] + +[foo *bar*]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_570() { + let original = r##"![foo ![bar](/url)](/url2) +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_571() { + let original = r##"![foo [bar](/url)](/url2) +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_572() { + let original = r##"![foo *bar*][] + +[foo *bar*]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_573() { + let original = r##"![foo *bar*][foobar] + +[FOOBAR]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_574() { + let original = r##"![foo](train.jpg) +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_575() { + let original = r##"My ![foo bar](/path/to/train.jpg "title" ) +"##; + let expected = r##"

    My foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_576() { + let original = r##"![foo]() +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_577() { + let original = r##"![](/url) +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_578() { + let original = r##"![foo][bar] + +[bar]: /url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_579() { + let original = r##"![foo][bar] + +[BAR]: /url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_580() { + let original = r##"![foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_581() { + let original = r##"![*foo* bar][] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_582() { + let original = r##"![Foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_583() { + let original = r##"![foo] +[] + +[foo]: /url "title" +"##; + let expected = r##"

    foo +[]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_584() { + let original = r##"![foo] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_585() { + let original = r##"![*foo* bar] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_586() { + let original = r##"![[foo]] + +[[foo]]: /url "title" +"##; + let expected = r##"

    ![[foo]]

    +

    [[foo]]: /url "title"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_587() { + let original = r##"![Foo] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_588() { + let original = r##"!\[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    ![foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_589() { + let original = r##"\![foo] + +[foo]: /url "title" +"##; + let expected = r##"

    !foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_590() { + let original = r##" +"##; + let expected = r##"

    http://foo.bar.baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_591() { + let original = r##" +"##; + let expected = r##"

    http://foo.bar.baz/test?q=hello&id=22&boolean

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_592() { + let original = r##" +"##; + let expected = r##"

    irc://foo.bar:2233/baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_593() { + let original = r##" +"##; + let expected = r##"

    MAILTO:FOO@BAR.BAZ

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_594() { + let original = r##" +"##; + let expected = r##"

    a+b+c:d

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_595() { + let original = r##" +"##; + let expected = r##"

    made-up-scheme://foo,bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_596() { + let original = r##" +"##; + let expected = r##"

    http://../

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_597() { + let original = r##" +"##; + let expected = r##"

    localhost:5001/foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_598() { + let original = r##" +"##; + let expected = r##"

    <http://foo.bar/baz bim>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_599() { + let original = r##" +"##; + let expected = r##"

    http://example.com/\[\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_600() { + let original = r##" +"##; + let expected = r##"

    foo@bar.example.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_601() { + let original = r##" +"##; + let expected = r##"

    foo+special@Bar.baz-bar0.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_602() { + let original = r##" +"##; + let expected = r##"

    <foo+@bar.example.com>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_603() { + let original = r##"<> +"##; + let expected = r##"

    <>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_604() { + let original = r##"< http://foo.bar > +"##; + let expected = r##"

    < http://foo.bar >

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_605() { + let original = r##" +"##; + let expected = r##"

    <m:abc>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_606() { + let original = r##" +"##; + let expected = r##"

    <foo.bar.baz>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_607() { + let original = r##"http://example.com +"##; + let expected = r##"

    http://example.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_608() { + let original = r##"foo@bar.example.com +"##; + let expected = r##"

    foo@bar.example.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_609() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_610() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_611() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_612() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_613() { + let original = r##"Foo +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_614() { + let original = r##"<33> <__> +"##; + let expected = r##"

    <33> <__>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_615() { + let original = r##"
    +"##; + let expected = r##"

    <a h*#ref="hi">

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_616() { + let original = r##"
    <a href="hi'> <a href=hi'>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_617() { + let original = r##"< a>< +foo> + +"##; + let expected = r##"

    < a>< +foo><bar/ > +<foo bar=baz +bim!bop />

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_618() { + let original = r##"
    +"##; + let expected = r##"

    <a href='bar'title=title>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_619() { + let original = r##"
    +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_620() { + let original = r##" +"##; + let expected = r##"

    </a href="foo">

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_621() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_622() { + let original = r##"foo +"##; + let expected = r##"

    foo <!-- not a comment -- two hyphens -->

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_623() { + let original = r##"foo foo --> + +foo +"##; + let expected = r##"

    foo <!--> foo -->

    +

    foo <!-- foo--->

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_624() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_625() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_626() { + let original = r##"foo &<]]> +"##; + let expected = r##"

    foo &<]]>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_627() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_628() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_629() { + let original = r##" +"##; + let expected = r##"

    <a href=""">

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_630() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_631() { + let original = r##"foo\ +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_632() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_633() { + let original = r##"foo + bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_634() { + let original = r##"foo\ + bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_635() { + let original = r##"*foo +bar* +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_636() { + let original = r##"*foo\ +bar* +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_637() { + let original = r##"`code +span` +"##; + let expected = r##"

    code span

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_638() { + let original = r##"`code\ +span` +"##; + let expected = r##"

    code\ span

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_639() { + let original = r##"
    +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_640() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_641() { + let original = r##"foo\ +"##; + let expected = r##"

    foo\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_642() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_643() { + let original = r##"### foo\ +"##; + let expected = r##"

    foo\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_644() { + let original = r##"### foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_645() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_646() { + let original = r##"foo + baz +"##; + let expected = r##"

    foo +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_647() { + let original = r##"hello $.;'there +"##; + let expected = r##"

    hello $.;'there

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_648() { + let original = r##"Foo χρῆν +"##; + let expected = r##"

    Foo χρῆν

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_649() { + let original = r##"Multiple spaces +"##; + let expected = r##"

    Multiple spaces

    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/table.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/table.rs new file mode 100644 index 0000000000..de4d2f65dc --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/table.rs @@ -0,0 +1,205 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn table_test_1() { + let original = r##"Test header +----------- +"##; + let expected = r##"

    Test header

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_2() { + let original = r##"Test|Table +----|----- +"##; + let expected = r##" +
    TestTable
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_3() { + let original = r##"> Test | Table +> ------|------ +> Row 1 | Every +> Row 2 | Day +> +> Paragraph +"##; + let expected = r##"
    + + + +
    Test Table
    Row 1 Every
    Row 2 Day
    +

    Paragraph

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_4() { + let original = r##" 1. First entry + 2. Second entry + + Col 1|Col 2 + -|- + Row 1|Part 2 + Row 2|Part 2 +"##; + let expected = r##"
      +
    1. +

      First entry

      +
    2. +
    3. +

      Second entry

      + + + +
      Col 1Col 2
      Row 1Part 2
      Row 2Part 2
      +
    4. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_5() { + let original = r##"|Col 1|Col 2| +|-----|-----| +|R1C1 |R1C2 | +|R2C1 |R2C2 | +"##; + let expected = r##" + + +
    Col 1Col 2
    R1C1 R1C2
    R2C1 R2C2
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_6() { + let original = r##"| Col 1 | Col 2 | +|-------|-------| +| | | +| | | +"##; + let expected = r##" + + +
    Col 1 Col 2
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_7() { + let original = r##"| Col 1 | Col 2 | +|-------|-------| +| x | | +| | x | +"##; + let expected = r##" + + +
    Col 1 Col 2
    x
    x
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_8() { + let original = r##"|Col 1|Col 2| +|-----|-----| +|✓ |✓ | +|✓ |✓ | +"##; + let expected = r##" + + +
    Col 1Col 2
    ✓ ✓
    ✓ ✓
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_9() { + let original = r##"| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | +| `arm-linux-androideabi` | ✓ | | | ARM Android | +| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `aarch64-unknown-linux-gnu` | ✓ | | | ARM64 Linux (2.6.18+) | +| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | +| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | +"##; + let expected = r##" + + + + + + + +
    Target std rustccargo notes
    x86_64-unknown-linux-musl ✓ 64-bit Linux with MUSL
    arm-linux-androideabi ✓ ARM Android
    arm-unknown-linux-gnueabi ✓ ✓ ARM Linux (2.6.18+)
    arm-unknown-linux-gnueabihf ✓ ✓ ARM Linux (2.6.18+)
    aarch64-unknown-linux-gnu ✓ ARM64 Linux (2.6.18+)
    mips-unknown-linux-gnu ✓ MIPS Linux (2.6.18+)
    mipsel-unknown-linux-gnu ✓ MIPS (LE) Linux (2.6.18+)
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_10() { + let original = r##"|-|-| +|ぃ|い| +"##; + let expected = r##"

    |-|-| +|ぃ|い|

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_11() { + let original = r##"|ぁ|ぃ| +|-|-| +|ぃ|ぃ| +"##; + let expected = r##" + +
    ぁぃ
    ぃぃ
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_12() { + let original = r##"|Колонка 1|Колонка 2| +|---------|---------| +|Ячейка 1 |Ячейка 2 | +"##; + let expected = r##" + +
    Колонка 1Колонка 2
    Ячейка 1 Ячейка 2
    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-to-cmark/.cargo-checksum.json b/vendor/pulldown-cmark-to-cmark/.cargo-checksum.json new file mode 100644 index 0000000000..48a835273e --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"e4a28a39450d75604a5def32aa4e2fe3eeb6774fc066735ef39f29d4dbbc844c","Cargo.toml":"86724eb5838df65639c5a6e369f226b05bace8c099f742d2c8e5181557a3292d","README.md":"cacc5c1dc25396fe63717b4acfb2dd13ac3fb4c28108647aaeb37f26f4120322","src/lib.rs":"62aafecee2c9c812144c48439c55a881443441c41f987af42a8b6ef05791a6fe"},"package":"32accf4473121d8c0b508ca5673363703762d6cc59cf25af1df48f653346f736"} \ No newline at end of file diff --git a/vendor/pulldown-cmark-to-cmark/CHANGELOG.md b/vendor/pulldown-cmark-to-cmark/CHANGELOG.md new file mode 100644 index 0000000000..1cbb432de7 --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/CHANGELOG.md @@ -0,0 +1,28 @@ +### v5.0.0 (2020-08-02) + +* Allow configuring the [amount of backticks used in code blocks](https://github.com/Byron/pulldown-cmark-to-cmark/pull/18). + May **break** code relying on the amount of fields in the configuration struct. + +### v4.0.2 (2020-04-22) + +* Fixed table header handling ([see PR for details](https://github.com/Byron/pulldown-cmark-to-cmark/pull/15)) + +### v4.0.0 (2020-04-22) + +* BREAKING: Move all types from `pulldown_cmark_to_cmark::fmt::*` into `pulldown_cmark_to_cmark::*` for simplicity. + For most common use-cases, this means that users of `pulldown_cmark_to_cmark::fmt::cmark` now use `pulldown_cmark_to_cmark::cmark` instead. + +### v3.0.1 (2020-04-22) + +* support for markdown embedded in HTML tags, like + + ```markdown +
    + + * list + * list + + **bold** + +
    + ``` diff --git a/vendor/pulldown-cmark-to-cmark/Cargo.toml b/vendor/pulldown-cmark-to-cmark/Cargo.toml new file mode 100644 index 0000000000..6fef63e0a4 --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/Cargo.toml @@ -0,0 +1,33 @@ +# 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 = "pulldown-cmark-to-cmark" +version = "5.0.0" +authors = ["Sebastian Thiel ", "Dylan Owen "] +include = ["src/lib.rs", "README.md", "CHANGELOG.md"] +description = "Convert pulldown-cmark Events back to the string they were parsed from" +homepage = "https://github.com/Byron/pulldown-cmark-to-cmark" +documentation = "https://docs.rs/crate/pulldown-cmark-to-cmark" +readme = "README.md" +keywords = ["markdown", "common-mark", "render", "converter"] +license = "Apache-2.0" +repository = "https://github.com/Byron/pulldown-cmark-to-cmark" +[dependencies.pulldown-cmark] +version = "0.7.0" +default-features = false +[dev-dependencies.indoc] +version = "0.3.4" + +[dev-dependencies.pretty_assertions] +version = "0.6.1" diff --git a/vendor/pulldown-cmark-to-cmark/README.md b/vendor/pulldown-cmark-to-cmark/README.md new file mode 100644 index 0000000000..263f5bdd26 --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/README.md @@ -0,0 +1,41 @@ +[![Crates.io](https://img.shields.io/crates/v/pulldown-cmark-to-cmark)](https://crates.io/crates/pulldown-cmark-to-cmark) +![Rust](https://github.com/Byron/pulldown-cmark-to-cmark/workflows/Rust/badge.svg) + +A utility library which translates [`Event`][pdcm-event] back to markdown. +It's the prerequisite for writing markdown filters which can work as +[mdbook-preprocessors][mdbook-prep]. + +This library takes great pride in supporting **everything that `pulldown-cmark`** supports, +including *tables* and *footnotes* and *codeblocks in codeblocks*, +while assuring *quality* with a powerful test suite. + +[pdcm-event]: https://docs.rs/pulldown-cmark/0.1.0/pulldown_cmark/enum.Event.html +[mdbook-prep]: https://rust-lang-nursery.github.io/mdBook/for_developers/preprocessors.html + +### How to use + +Please have a look at the [`stupicat`-example][sc-example] for a complete tour +of the API, or have a look at the [api-docs][api]. + +It's easiest to get this library into your `Cargo.toml` using `cargo-add`: +``` +cargo add pulldown-cmark-to-cmark +``` + +[sc-example]: https://github.com/Byron/pulldown-cmark-to-cmark/blob/76667725b61be24890fbdfed5e7ecdb4c1ad1dc8/examples/stupicat.rs#L21 +[api]: https://docs.rs/crate/pulldown-cmark-to-cmark + +### Friends of this project + + * [**termbook**](https://github.com/Byron/termbook) + * A runner for `mdbooks` to keep your documentation tested. + * [**Share Secrets Safely**](https://github.com/Byron/share-secrets-safely) + * share secrets within teams to avoid plain-text secrets from day one + +### Maintenance Guide + +#### Making a new release + + * **Assure all documentation is up-to-date and tests are green** + * update the `version` in `Cargo.toml` and `git commit` + * run `cargo release --no-dev-version` diff --git a/vendor/pulldown-cmark-to-cmark/src/lib.rs b/vendor/pulldown-cmark-to-cmark/src/lib.rs new file mode 100644 index 0000000000..058f0eb7f3 --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/src/lib.rs @@ -0,0 +1,482 @@ +use pulldown_cmark::{Alignment as TableAlignment, Event}; +use std::{borrow::Borrow, borrow::Cow, fmt}; + +pub const SPECIAL_CHARACTERS: &[u8; 9] = br#"#\_*<>`|["#; + +/// Similar to [Pulldown-Cmark-Alignment][pd-alignment], but with required +/// traits for comparison to allow testing. +/// +/// [pd-alignment]: https://docs.rs/pulldown-cmark/*/pulldown_cmark/enum.Alignment.html +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Alignment { + None, + Left, + Center, + Right, +} + +impl<'a> From<&'a TableAlignment> for Alignment { + fn from(s: &'a TableAlignment) -> Self { + match *s { + TableAlignment::None => Alignment::None, + TableAlignment::Left => Alignment::Left, + TableAlignment::Center => Alignment::Center, + TableAlignment::Right => Alignment::Right, + } + } +} + +/// The state of the `cmark` function. +/// This does not only allow introspection, but enables the user +/// to halt the serialization at any time, and resume it later. +#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct State<'a> { + /// The amount of newlines to insert after `Event::Start(...)` + pub newlines_before_start: usize, + /// The lists and their types for which we have seen a `Event::Start(List(...))` tag + pub list_stack: Vec>, + /// The computed padding and prefix to print after each newline. + /// This changes with the level of `BlockQuote` and `List` events. + pub padding: Vec>, + /// Keeps the current table alignments, if we are currently serializing a table. + pub table_alignments: Vec, + /// Keeps the current table headers, if we are currently serializing a table. + pub table_headers: Vec, + /// If set, the next 'text' will be stored for later use + pub store_next_text: bool, + /// The last seen text when serializing a header + pub text_for_header: Option, + /// Is set while we are handling text in a code block + pub is_in_code_block: bool, + /// True if the last event was html. Used to inject additional newlines to support markdown inside of HTML tags. + pub last_was_html: bool, +} + +/// Configuration for the `cmark` function. +/// The defaults should provide decent spacing and most importantly, will +/// provide a faithful rendering of your markdown document particularly when +/// rendering it to HTML. +/// +/// It's best used with its `Options::default()` implementation. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Options { + pub newlines_after_headline: usize, + pub newlines_after_paragraph: usize, + pub newlines_after_codeblock: usize, + pub newlines_after_table: usize, + pub newlines_after_rule: usize, + pub newlines_after_list: usize, + pub newlines_after_blockquote: usize, + pub newlines_after_rest: usize, + pub code_block_backticks: usize, +} + +impl Default for Options { + fn default() -> Self { + Options { + newlines_after_headline: 2, + newlines_after_paragraph: 2, + newlines_after_codeblock: 2, + newlines_after_table: 2, + newlines_after_rule: 2, + newlines_after_list: 2, + newlines_after_blockquote: 2, + newlines_after_rest: 1, + code_block_backticks: 4, + } + } +} + +/// Serialize a stream of [pulldown-cmark-Events][pd-event] into a string-backed buffer. +/// +/// 1. **events** +/// * An iterator over [`Events`][pd-event], for example as returned by the [`Parser`][pd-parser] +/// 1. **formatter** +/// * A format writer, can be a `String`. +/// 1. **state** +/// * The optional initial state of the serialization. +/// 1. **options** +/// * Customize the appearance of the serialization. All otherwise magic values are contained +/// here. +/// +/// *Returns* the `State` of the serialization on success. You can use it as initial state in the +/// next call if you are halting event serialization. +/// *Errors* are only happening if the underlying buffer fails, which is unlikely. +/// +/// [pd-event]: https://docs.rs/pulldown-cmark/*/pulldown_cmark/enum.Event.html +/// [pd-parser]: https://docs.rs/pulldown-cmark/*/pulldown_cmark/struct.Parser.html +pub fn cmark_with_options<'a, I, E, F>( + events: I, + mut formatter: F, + state: Option>, + options: Options, +) -> Result, fmt::Error> +where + I: Iterator, + E: Borrow>, + F: fmt::Write, +{ + let mut state = state.unwrap_or_default(); + fn padding<'a, F>(f: &mut F, p: &[Cow<'a, str>]) -> fmt::Result + where + F: fmt::Write, + { + for padding in p { + write!(f, "{}", padding)?; + } + Ok(()) + } + fn consume_newlines(f: &mut F, s: &mut State) -> fmt::Result + where + F: fmt::Write, + { + while s.newlines_before_start != 0 { + s.newlines_before_start -= 1; + f.write_char('\n')?; + padding(f, &s.padding)?; + } + Ok(()) + } + + fn escape_leading_special_characters(t: &str, is_in_block_quote: bool) -> Cow<'_, str> { + if is_in_block_quote || t.is_empty() { + return Cow::Borrowed(t); + } + + use std::convert::TryFrom; + let first = t.as_bytes()[0]; + if SPECIAL_CHARACTERS.contains(&first) { + let mut s = String::with_capacity(t.len() + 1); + s.push('\\'); + s.push(char::try_from(first as u32).expect("we know it's valid utf8")); + s.push_str(&t[1..]); + Cow::Owned(s) + } else { + Cow::Borrowed(t) + } + } + + fn print_text_without_trailing_newline<'a, F>( + t: &str, + f: &mut F, + p: &[Cow<'a, str>], + ) -> fmt::Result + where + F: fmt::Write, + { + if t.contains('\n') { + let line_count = t.split('\n').count(); + for (tid, token) in t.split('\n').enumerate() { + f.write_str(token).and(if tid + 1 == line_count { + Ok(()) + } else { + f.write_char('\n').and(padding(f, p)) + })?; + } + Ok(()) + } else { + f.write_str(t) + } + } + + fn padding_of(l: Option) -> Cow<'static, str> { + match l { + None => " ".into(), + Some(n) => format!("{}. ", n) + .chars() + .map(|_| ' ') + .collect::() + .into(), + } + } + + for event in events { + use pulldown_cmark::CodeBlockKind; + use pulldown_cmark::Event::*; + use pulldown_cmark::Tag::*; + + let event = event.borrow(); + + // Markdown allows for HTML elements, into which further markdown formatting is nested. + // However only if the HTML element is spaced by an additional newline. + // + // Relevant spec: https://spec.commonmark.org/0.28/#html-blocks + if state.last_was_html { + match event { + Html(_) => { /* no newlines if HTML continues */ } + Text(_) => { /* no newlines for inline HTML */ } + _ => { + // Ensure next Markdown block is rendered properly + // by adding a newline after an HTML element. + formatter.write_char('\n')?; + } + } + } + + state.last_was_html = false; + match *event { + Rule => { + consume_newlines(&mut formatter, &mut state)?; + if state.newlines_before_start < options.newlines_after_rule { + state.newlines_before_start = options.newlines_after_rule; + } + formatter.write_str("---") + } + Code(ref text) => { + if state.store_next_text { + state.store_next_text = false; + let code = format!("`{}`", text); + state.text_for_header = Some(code) + } + formatter + .write_char('`') + .and_then(|_| formatter.write_str(text)) + .and_then(|_| formatter.write_char('`')) + } + Start(ref tag) => { + match *tag { + List(ref list_type) => { + state.list_stack.push(list_type.clone()); + if state.list_stack.len() > 1 { + if state.newlines_before_start < options.newlines_after_rest { + state.newlines_before_start = options.newlines_after_rest; + } + } + } + _ => {} + } + let consumed_newlines = state.newlines_before_start != 0; + consume_newlines(&mut formatter, &mut state)?; + match tag { + Item => match state.list_stack.last() { + Some(inner) => { + state.padding.push(padding_of(*inner)); + match inner { + &Some(n) => write!(formatter, "{}. ", n), + &None => formatter.write_str("* "), + } + } + None => Ok(()), + }, + Table(ref alignments) => { + state.table_alignments = alignments.iter().map(From::from).collect(); + Ok(()) + } + TableHead => Ok(()), + TableRow => Ok(()), + TableCell => { + state.store_next_text = true; + formatter.write_char('|') + } + Link(..) => formatter.write_char('['), + Image(..) => formatter.write_str("!["), + Emphasis => formatter.write_char('*'), + Strong => formatter.write_str("**"), + FootnoteDefinition(ref name) => write!(formatter, "[^{}]: ", name), + Paragraph => Ok(()), + Heading(n) => { + for _ in 0..*n { + formatter.write_char('#')?; + } + formatter.write_char(' ') + } + BlockQuote => { + state.padding.push(" > ".into()); + state.newlines_before_start = 1; + + // if we consumed some newlines, we know that we can just write out the next + // level in our blockquote. This should work regardless if we have other + // padding or if we're in a list + if consumed_newlines { + formatter.write_str(" > ") + } else { + formatter + .write_char('\n') + .and(padding(&mut formatter, &state.padding)) + } + } + CodeBlock(CodeBlockKind::Indented) => { + state.is_in_code_block = true; + formatter + .write_str(&"`".repeat(options.code_block_backticks)) + .and(formatter.write_char('\n')) + .and(padding(&mut formatter, &state.padding)) + } + CodeBlock(CodeBlockKind::Fenced(ref info)) => { + state.is_in_code_block = true; + let s = if !consumed_newlines { + formatter + .write_char('\n') + .and_then(|_| padding(&mut formatter, &state.padding)) + } else { + Ok(()) + }; + + s.and_then(|_| formatter.write_str(&"`".repeat(options.code_block_backticks))) + .and_then(|_| formatter.write_str(info)) + .and_then(|_| formatter.write_char('\n')) + .and_then(|_| padding(&mut formatter, &state.padding)) + } + List(_) => Ok(()), + Strikethrough => formatter.write_str("~~"), + } + } + End(ref tag) => match tag { + Image(_, ref uri, ref title) | Link(_, ref uri, ref title) => { + if title.is_empty() { + write!(formatter, "]({})", uri) + } else { + write!(formatter, "]({uri} \"{title}\")", uri = uri, title = title) + } + } + Emphasis => formatter.write_char('*'), + Strong => formatter.write_str("**"), + Heading(_) => { + if state.newlines_before_start < options.newlines_after_headline { + state.newlines_before_start = options.newlines_after_headline; + } + Ok(()) + } + Paragraph => { + if state.newlines_before_start < options.newlines_after_paragraph { + state.newlines_before_start = options.newlines_after_paragraph; + } + Ok(()) + } + CodeBlock(_) => { + if state.newlines_before_start < options.newlines_after_codeblock { + state.newlines_before_start = options.newlines_after_codeblock; + } + state.is_in_code_block = false; + formatter.write_str(&"`".repeat(options.code_block_backticks)) + } + Table(_) => { + if state.newlines_before_start < options.newlines_after_table { + state.newlines_before_start = options.newlines_after_table; + } + state.table_alignments.clear(); + state.table_headers.clear(); + Ok(()) + } + TableCell => { + state + .table_headers + .push(match state.text_for_header.take() { + Some(text) => text, + None => " ".into(), + }); + Ok(()) + } + ref t @ TableRow | ref t @ TableHead => { + if state.newlines_before_start < options.newlines_after_rest { + state.newlines_before_start = options.newlines_after_rest; + } + formatter.write_char('|')?; + + if let &TableHead = t { + formatter + .write_char('\n') + .and(padding(&mut formatter, &state.padding))?; + for (alignment, name) in state + .table_alignments + .iter() + .zip(state.table_headers.iter()) + { + formatter.write_char('|')?; + // NOTE: For perfect counting, count grapheme clusters. + // The reason this is not done is to avoid the dependency. + let last_minus_one = name.chars().count().saturating_sub(1); + for c in 0..name.len() { + formatter.write_char( + if (c == 0 + && (alignment == &Alignment::Center + || alignment == &Alignment::Left)) + || (c == last_minus_one + && (alignment == &Alignment::Center + || alignment == &Alignment::Right)) + { + ':' + } else { + '-' + }, + )?; + } + } + formatter.write_char('|')?; + } + Ok(()) + } + Item => { + state.padding.pop(); + if state.newlines_before_start < options.newlines_after_rest { + state.newlines_before_start = options.newlines_after_rest; + } + Ok(()) + } + List(_) => { + state.list_stack.pop(); + if state.list_stack.len() == 0 + && state.newlines_before_start < options.newlines_after_list + { + state.newlines_before_start = options.newlines_after_list; + } + Ok(()) + } + BlockQuote => { + state.padding.pop(); + + if state.newlines_before_start < options.newlines_after_blockquote { + state.newlines_before_start = options.newlines_after_blockquote; + } + + Ok(()) + } + FootnoteDefinition(_) => Ok(()), + Strikethrough => formatter.write_str("~~"), + }, + HardBreak => formatter + .write_str(" \n") + .and(padding(&mut formatter, &state.padding)), + SoftBreak => formatter + .write_char('\n') + .and(padding(&mut formatter, &state.padding)), + Text(ref text) => { + if state.store_next_text { + state.store_next_text = false; + state.text_for_header = Some(text.to_owned().into_string()) + } + consume_newlines(&mut formatter, &mut state)?; + print_text_without_trailing_newline( + &escape_leading_special_characters(text, state.is_in_code_block), + &mut formatter, + &state.padding, + ) + } + Html(ref text) => { + state.last_was_html = true; + consume_newlines(&mut formatter, &mut state)?; + print_text_without_trailing_newline(text, &mut formatter, &state.padding) + } + FootnoteReference(ref name) => write!(formatter, "[^{}]", name), + TaskListMarker(checked) => { + let check = if checked { "x" } else { " " }; + write!(formatter, "[{}] ", check) + } + }? + } + Ok(state) +} + +/// As `cmark_with_options`, but with default `Options`. +pub fn cmark<'a, I, E, F>( + events: I, + formatter: F, + state: Option>, +) -> Result, fmt::Error> +where + I: Iterator, + E: Borrow>, + F: fmt::Write, +{ + cmark_with_options(events, formatter, state, Options::default()) +} diff --git a/vendor/pulldown-cmark/.cargo-checksum.json b/vendor/pulldown-cmark/.cargo-checksum.json index 956e4ad354..c5a3efcd17 100644 --- a/vendor/pulldown-cmark/.cargo-checksum.json +++ b/vendor/pulldown-cmark/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CONTRIBUTING.md":"ad9613136aef42ccaca15f131ecb7bb697adbd05cb2d38062e40581d570e5005","Cargo.lock":"0cce438e59390e1c92b9cf168212d1c4a7390e5de715e432e4204118fb10113c","Cargo.toml":"4a791d5e9478bf3fdfb1e85d14aebcafc85d6ed07f73dcf4e742a47981d596d6","LICENSE":"2afc41ab83a8e715bf57b2b0d9d3ca3da1a0afc4cdadefd72f3a1ba537c5213f","README.md":"2a6061d89f6232ed5e444878668bcd819508519a90966945b1f774a14fd247a1","benches/html_rendering.rs":"9dd749395295e3c27e2dbdd784e34e0d797f150665b3e0af7803217e44902a80","benches/lib.rs":"8d66217a7712baae45d1101042284ddbe99508cc240b461781b0d25da185c108","build.rs":"ea58b69966ea4d7849d1053555b9c8631aefcc977cebdc5e412541527eb6baff","examples/event-filter.rs":"625cb8218e46b97f2553c3dd85a75b3b09bdcc8055c2ef670fa3930f924f5d75","examples/string-to-string.rs":"94cf4c6e1027186b73042fb9971e1469652682398c53e2dffe60d3dc30e72629","src/entities.rs":"08f6499fd2ed5ed5be89506f04e785b33eecb3b304418f812267dd8f01bbc6b6","src/escape.rs":"b5b073435e507e3d2897ea89f6143b5cf47d6cb140948450a255cc13fc2a3c5e","src/html.rs":"25ca58d7397209a9c4048efa647940e2ead21350de567c1c1013d3540438f678","src/lib.rs":"0e9ae448b1a5ff10add1aa6d9db3339e12f7da2bac438b39fb90f98880337c4e","src/linklabel.rs":"f174a9020c23770fe14eb377e85da8280e1ecc9ec4175108ebe38f507270bfeb","src/main.rs":"a009df64cf1f559ebc7b1768bd5842b42df01a7865ef75b8f92ee476360b3db7","src/parse.rs":"05d1023a36893f72b3d9208cfc5f3c42c4af58a3c9f88c7755efdc0a39a86a1b","src/puncttable.rs":"ff83b70b65d1666712cbba1c9949f65ea69d72b25a2aa960a7c8c8d1b5fbed08","src/scanners.rs":"7bebfde06556b74391dba5e9f9e2a12995a6e62816b414d4a8d6b610e6bf307c","src/simd.rs":"6b386b1bd224d10cd8203e7162dd9ed242970de2ce5c1583635285337f4a266f","src/strings.rs":"f19ebad46ab498eef93091d4c90ba9e673c85e848ddde82bf2aa5e1dc5fdc3ea","src/tree.rs":"7c3402a077ff8dd321967e9ac685ecf2038c51601afa38fe75f329ff9564a7f0","tests/errors.rs":"59199be255a0edd7cb9a8fd988738603ec82de3b6d3ec6d331d1c43e2957f5fc","tests/html.rs":"d305de4e8b209af0db749be4bf1137d446a6b3953c01af31ef7c0a807701d022","tests/lib.rs":"02bd5825bfc3d1ec24415049914774e84169bd2f7173475b050157f5539be781","tests/suite/footnotes.rs":"aa1471b4bbaf52efdd870ab078907c95c961bbfe9e2beddbe4dddb3f0bba1c7f","tests/suite/gfm_strikethrough.rs":"a43f9578651faf6f7a4488d4e6a31f371dea8fefa4892a1de63f6dad6ad7827a","tests/suite/gfm_table.rs":"de092e0542b418fb358116aa57810805a84cefe0710e9cf0df9018f37beedc30","tests/suite/gfm_tasklist.rs":"30f9c584eaaeae31cae5a915bc84da91202de2bfceec19faa46778bb87f88cab","tests/suite/mod.rs":"7bf32170c9662f76870139b47596643a60d105427b6a6f85dd15044caf82c6c8","tests/suite/regression.rs":"c3b3975e82167a6301adb9f4ac337f1fb7cf864bf49f7adde8bd80aeadb7d226","tests/suite/spec.rs":"de043bdf7cc81120ca779bf0c38e802c865ec632870f4efa0a30bfd47590426a","tests/suite/table.rs":"f65dd8530e39b846ca6a0eb40dadf850ab266e9925dd331531f404c1cc9d422e"},"package":"ca36dea94d187597e104a5c8e4b07576a8a45aa5db48a65e12940d3eb7461f55"} \ No newline at end of file +{"files":{"CONTRIBUTING.md":"a5bbc113fdcb8101367da47daba32ab10aa2377a825040c78d847d870108d849","Cargo.lock":"93c21661f9a1ff503e962bfbd03cfa2b81593950f4fe03d27be7ec12cc0e7283","Cargo.toml":"1357ee8e0c7af73f5fc6ef3af6bf6a690d881a2ec901747716156837f4d44b8d","LICENSE":"c4f10f55904bdb9f27d3fbf94c354926d6cfe8b982276e556238c258941b243b","README.md":"80716579bccdb6698bba46478533414de7730422ed1572248ded8e8600ca16fd","benches/html_rendering.rs":"59d9ad8ec6c61c26bf98aa81f35387b923be01f54209cc11ed9b21902e57b58a","benches/lib.rs":"e7a2ac16b4fd024d4da03221083ed48e00404b6e79ef1f8b449dec9a96776304","build.rs":"67314d695536299ac029099ac6b7be226befbae1aa6b9acf84d83cac5eb6abe1","examples/broken-link-callbacks.rs":"c7c124b5a5b81ad312204b2df7b0e4bc423b7bb92e9b45dc8e92d333ee1c790d","examples/event-filter.rs":"85ba4695e8e83c9c59b7b675a2fb8eb40ed5e2b56bc05679732f6e2f9589106d","examples/string-to-string.rs":"864aed51aaa8ffd556995fa937ea99b98d78feeb7bf7ae4b2872c749fb02b386","src/entities.rs":"1602f3c4d22c0b0e3a4a08467a50bf9d0c27aadf2e5661b15a2cda20da0895a9","src/escape.rs":"995eb646795e40b18da4220d750d5367abeb16d71a75e0b5f8fdb29ec1ebd527","src/html.rs":"a6d8312d761151f6dc99c46a543e7ca2562ccc9cb03969b782bb87c878027a85","src/lib.rs":"faeb88e98e8ebaa8dd04ec0e653ff046157fee96540bc21d0db9f6770ad98264","src/linklabel.rs":"503710b7c540ea025b22ed2c9378cd0a741d56cb957fdd962515dd3c054fcd30","src/main.rs":"5603394cb0c1bfe9b9d33c8098a6f14e9df2100038dab225f008f45c66d894e5","src/parse.rs":"3f1df87e634b4cf49abb5f07cd05110f55570bc35cb7694f3729cab760d988b7","src/puncttable.rs":"ddb35138b537c00dd2003daba2d07f1bc8154059a745d4e18b74732614b20f1c","src/scanners.rs":"fbc3d07881240bc033f6434875201a295d733f6bf4398bccf1fff424030d4893","src/simd.rs":"926e978a509d9be8722dad894ce39fb82398150aaba715ff6070cdb933477fb7","src/strings.rs":"06a7ee24e93d536238602ce909a8a9d1c854446abaab44368a3630f7f5c5eb00","src/tree.rs":"baed43da5de244cce9409fb4008ea9c1e858aac97907674530497ec5af13f840","tests/errors.rs":"3677dc76c0ec85b3b65389fe39a82cd7ab9420dd5e2cc5b5b11f490fde2f5fbf","tests/html.rs":"370f6d1f3aa5c872ec3fdd5506d732e2c4b93ca613fe5d4a62f3e5343c4909c9","tests/lib.rs":"3d049d013ca32bb2d4308fd444afc328b177457a08cf83d8f012ec8c6c1b88bf","tests/suite/footnotes.rs":"ce4e79abdcb63f5b7c1b508af7b7be96f82e1c7c11e6b43bd5e4a288db7e9cfa","tests/suite/gfm_strikethrough.rs":"452b050235dc61024661a635107d7a94c0dd8490c1720424035e0d15ee1b97c8","tests/suite/gfm_table.rs":"21e8e5e21922e99ad7f0669dea06671b8cdea8fa4b7ee728d211f18addde1644","tests/suite/gfm_tasklist.rs":"ac19d6b7cae67de503d89a51a9e7c6a2027a375c1d60d18322ff58cd6bef3193","tests/suite/mod.rs":"3341b8f910bb3911b548858ac1770050c517a41d95573bfe6dbd1ba02d1396ff","tests/suite/regression.rs":"b22dd8089a1801ed252ae59ffa1fdd12d974b23759e1131e612462ec76afe391","tests/suite/smart_punct.rs":"6ef4168ed33e62b2f0fafd0ed68f47abfd908f298f3fa1b9dcec7ddcf0f70d5c","tests/suite/spec.rs":"6ccf4eebbafb55d5cc9716b4d61d6abb50fda54a11f634e742d6db2df1cf99d9","tests/suite/table.rs":"a77c626892b335932fc3960d5c59228d60407b35a686f1a19ea560b272f13f32"},"package":"ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"} \ No newline at end of file diff --git a/vendor/pulldown-cmark/CONTRIBUTING.md b/vendor/pulldown-cmark/CONTRIBUTING.md index 8572568675..5200aa4720 100644 --- a/vendor/pulldown-cmark/CONTRIBUTING.md +++ b/vendor/pulldown-cmark/CONTRIBUTING.md @@ -1,21 +1,21 @@ -Want to contribute? Great! First, read this page. - -### Before you contribute - -Before you start working on a larger contribution, you should get in touch with -us first through the issue tracker with your idea so that we can help out and -possibly guide you. Coordinating up front makes it much easier to avoid -frustration later on. - -### Getting familiar with the project - -**The architecture** is somewhat unique, it was originally inspired by [XML pull parsers](http://www.xmlpull.org), but ended up going in somewhat its own direction. to get familiar with it, -- start my reading the [README](README.md) page, which gives some details on the design of the parser (pull-based events) and some rationalization for it ; -- read the [blog post](https://fullyfaithful.eu/pulldown-cmark) about the release of Pulldown-cmark 0.3 by Marcus Klaas de Vries. - -**The source code** can be approached by skimming the [API documentation](https://docs.rs/pulldown-cmark/latest/pulldown_cmark) first, then explore the code for the main struct, [`Parser`](https://docs.rs/pulldown-cmark/latest/pulldown_cmark/struct.Parser.html) - -### Code reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. +Want to contribute? Great! First, read this page. + +### Before you contribute + +Before you start working on a larger contribution, you should get in touch with +us first through the issue tracker with your idea so that we can help out and +possibly guide you. Coordinating up front makes it much easier to avoid +frustration later on. + +### Getting familiar with the project + +**The architecture** is somewhat unique, it was originally inspired by [XML pull parsers](http://www.xmlpull.org), but ended up going in somewhat its own direction. to get familiar with it, +- start my reading the [README](README.md) page, which gives some details on the design of the parser (pull-based events) and some rationalization for it ; +- read the [blog post](https://fullyfaithful.eu/pulldown-cmark) about the release of Pulldown-cmark 0.3 by Marcus Klaas de Vries. + +**The source code** can be approached by skimming the [API documentation](https://docs.rs/pulldown-cmark/latest/pulldown_cmark) first, then explore the code for the main struct, [`Parser`](https://docs.rs/pulldown-cmark/latest/pulldown_cmark/struct.Parser.html) + +### Code reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. diff --git a/vendor/pulldown-cmark/Cargo.lock b/vendor/pulldown-cmark/Cargo.lock index 2c8e742e09..7a646e9f84 100644 --- a/vendor/pulldown-cmark/Cargo.lock +++ b/vendor/pulldown-cmark/Cargo.lock @@ -13,14 +13,14 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -36,7 +36,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -64,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clap" -version = "2.33.1" +version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -79,7 +79,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", "criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -87,12 +87,12 @@ dependencies = [ "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "oorandom 11.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "plotters 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", "serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -106,6 +106,15 @@ dependencies = [ "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-channel" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.7.3" @@ -121,7 +130,7 @@ name = "crossbeam-epoch" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -130,22 +139,12 @@ dependencies = [ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -159,7 +158,7 @@ dependencies = [ "csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -172,7 +171,7 @@ dependencies = [ [[package]] name = "either" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -198,7 +197,7 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -209,10 +208,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -220,12 +219,12 @@ name = "html5ever" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -233,7 +232,7 @@ name = "itertools" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -243,10 +242,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "js-sys" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -256,12 +255,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.71" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -277,12 +276,12 @@ name = "markup5ever" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -314,7 +313,7 @@ name = "memoffset" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -327,7 +326,7 @@ name = "num-traits" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -335,8 +334,8 @@ name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -383,15 +382,15 @@ name = "plotters" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -401,7 +400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -409,7 +408,7 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.7.2" +version = "0.8.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -428,7 +427,7 @@ name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -437,7 +436,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -449,7 +448,7 @@ name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -479,22 +478,22 @@ dependencies = [ [[package]] name = "rayon" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "crossbeam-channel 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -565,7 +564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -574,27 +573,27 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -611,7 +610,7 @@ dependencies = [ "new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -621,16 +620,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "1.0.33" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -663,10 +662,11 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -675,8 +675,8 @@ name = "tinytemplate" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -722,62 +722,67 @@ name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "wasm-bindgen" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "web-sys" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -812,44 +817,44 @@ name = "xml5ever" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" "checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" "checksum criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "70daa7ceec6cf143990669a04c7df13391d55fb27bd4079d252fca774ba244d8" "checksum criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" +"checksum crossbeam-channel 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -"checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" "checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" "checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" "checksum half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" -"checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" "checksum html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b" "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" "checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" -"checksum js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b9172132a62451e56142bff9afc91c8e4a4500aa5b847da36815b63bfda916" +"checksum js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)" = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" +"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" "checksum markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aae38d669396ca9b707bfc3db254bc382ddb94f57cc5c235f34623a669a01dab" "checksum markup5ever_rcdom 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f015da43bcd8d4f144559a3423f4591d69b8ce0652c905374da7205df336ae2b" @@ -865,17 +870,17 @@ dependencies = [ "checksum phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" "checksum phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" "checksum plotters 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d1685fbe7beba33de0330629da9d955ac75bd54f33d7b79f9a895590124f6bb" -"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +"checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -"checksum rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080" -"checksum rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280" +"checksum rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270" +"checksum rayon-core 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91739a34c4355b5434ce54c9086c5895604a9c278586d1f1aa95e04f66b525a0" "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" "checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" @@ -885,18 +890,18 @@ dependencies = [ "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +"checksum serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" "checksum serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" -"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" -"checksum serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" +"checksum serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +"checksum serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" "checksum siphasher 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" "checksum string_cache 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a" "checksum string_cache_codegen 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" -"checksum syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" +"checksum syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9" "checksum tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +"checksum time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" "checksum tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f" "checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" "checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" @@ -904,13 +909,14 @@ dependencies = [ "checksum utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" "checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" "checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +"checksum wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "6a634620115e4a229108b71bde263bb4220c483b3f07f5ba514ee8d15064c4c2" -"checksum wasm-bindgen-backend 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df" -"checksum wasm-bindgen-macro 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "3fcfd5ef6eec85623b4c6e844293d4516470d8f19cd72d0d12246017eb9060b8" -"checksum wasm-bindgen-macro-support 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "9adff9ee0e94b926ca81b57f57f86d5545cdcb1d259e21ec9bdd95b901754c75" -"checksum wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7b90ea6c632dd06fd765d44542e234d5e63d9bb917ecd64d79778a13bd79ae" -"checksum web-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "863539788676619aac1a23e2df3655e96b32b0e05eb72ca34ba045ad573c625d" +"checksum wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" +"checksum wasm-bindgen-backend 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0" +"checksum wasm-bindgen-macro 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2" +"checksum wasm-bindgen-macro-support 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" +"checksum wasm-bindgen-shared 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092" +"checksum web-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47" "checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" diff --git a/vendor/pulldown-cmark/Cargo.toml b/vendor/pulldown-cmark/Cargo.toml index c85952d7fa..973a2130db 100644 --- a/vendor/pulldown-cmark/Cargo.toml +++ b/vendor/pulldown-cmark/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "pulldown-cmark" -version = "0.7.2" +version = "0.8.0" authors = ["Raph Levien ", "Marcus Klaas de Vries "] build = "build.rs" exclude = ["/third_party/**/*", "/tools/**/*", "/specs/**/*", "/fuzzer/**/*", "/azure-pipelines.yml"] diff --git a/vendor/pulldown-cmark/LICENSE b/vendor/pulldown-cmark/LICENSE index c10685cc3d..cd8655ebdb 100644 --- a/vendor/pulldown-cmark/LICENSE +++ b/vendor/pulldown-cmark/LICENSE @@ -1,21 +1,21 @@ -The MIT License - -Copyright 2015 Google Inc. All rights reserved. - -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. +The MIT License + +Copyright 2015 Google Inc. All rights reserved. + +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/pulldown-cmark/README.md b/vendor/pulldown-cmark/README.md index 96e3437902..a84ebcc442 100644 --- a/vendor/pulldown-cmark/README.md +++ b/vendor/pulldown-cmark/README.md @@ -1,152 +1,152 @@ -# pulldown-cmark - -[![Build Status](https://dev.azure.com/raphlinus/pulldown-cmark/_apis/build/status/pulldown-cmark-CI?branchName=master)](https://dev.azure.com/raphlinus/pulldown-cmark/_build/latest?definitionId=2&branchName=master) -[![Docs](https://docs.rs/pulldown-cmark/badge.svg)](https://docs.rs/pulldown-cmark) -[![Crates.io](https://img.shields.io/crates/v/pulldown-cmark.svg?maxAge=2592000)](https://crates.io/crates/pulldown-cmark) - -[Documentation](https://docs.rs/pulldown-cmark/) - -This library is a pull parser for [CommonMark](http://commonmark.org/), written -in [Rust](http://www.rust-lang.org/). It comes with a simple command-line tool, -useful for rendering to HTML, and is also designed to be easy to use from as -a library. - -It is designed to be: - -* Fast; a bare minimum of allocation and copying -* Safe; written in pure Rust with no unsafe blocks -* Versatile; in particular source-maps are supported -* Correct; the goal is 100% compliance with the [CommonMark spec](http://spec.commonmark.org/) - -Further, it optionally supports parsing footnotes, -[Github flavored tables](https://github.github.com/gfm/#tables-extension-), -[Github flavored task lists](https://github.github.com/gfm/#task-list-items-extension-) and -[strikethrough](https://github.github.com/gfm/#strikethrough-extension-). - -Rustc 1.34 or newer is required to build the crate. - -## Why a pull parser? - -There are many parsers for Markdown and its variants, but to my knowledge none -use pull parsing. Pull parsing has become popular for XML, especially for -memory-conscious applications, because it uses dramatically less memory than -constructing a document tree, but is much easier to use than push parsers. Push -parsers are notoriously difficult to use, and also often error-prone because of -the need for user to delicately juggle state in a series of callbacks. - -In a clean design, the parsing and rendering stages are neatly separated, but -this is often sacrificed in the name of performance and expedience. Many Markdown -implementations mix parsing and rendering together, and even designs that try -to separate them (such as the popular [hoedown](https://github.com/hoedown/hoedown)), -make the assumption that the rendering process can be fully represented as a -serialized string. - -Pull parsing is in some sense the most versatile architecture. It's possible to -drive a push interface, also with minimal memory, and quite straightforward to -construct an AST. Another advantage is that source-map information (the mapping -between parsed blocks and offsets within the source text) is readily available; -you can call `into_offset_iter()` to create an iterator that yields `(Event, Range)` -pairs, where the second element is the event's corresponding range in the source -document. - -While manipulating ASTs is the most flexible way to transform documents, -operating on iterators is surprisingly easy, and quite efficient. Here, for -example, is the code to transform soft line breaks into hard breaks: - -```rust -let parser = parser.map(|event| match event { - Event::SoftBreak => Event::HardBreak, - _ => event -}); -``` - -Or expanding an abbreviation in text: - -```rust -let parser = parser.map(|event| match event { - Event::Text(text) => Event::Text(text.replace("abbr", "abbreviation").into()), - _ => event -}); -``` - -Another simple example is code to determine the max nesting level: - -```rust -let mut max_nesting = 0; -let mut level = 0; -for event in parser { - match event { - Event::Start(_) => { - level += 1; - max_nesting = std::cmp::max(max_nesting, level); - } - Event::End(_) => level -= 1, - _ => () - } -} -``` - -There are some basic but fully functional examples of the usage of the crate in the -`examples` directory of this repository. - -## Using Rust idiomatically - -A lot of the internal scanning code is written at a pretty low level (it -pretty much scans byte patterns for the bits of syntax), but the external -interface is designed to be idiomatic Rust. - -Pull parsers are at heart an iterator of events (start and end tags, text, -and other bits and pieces). The parser data structure implements the -Rust Iterator trait directly, and Event is an enum. Thus, you can use the -full power and expressivity of Rust's iterator infrastructure, including -for loops and `map` (as in the examples above), collecting the events into -a vector (for recording, playback, and manipulation), and more. - -Further, the `Text` event (representing text) is a small copy-on-write string. -The vast majority of text fragments are just -slices of the source document. For these, copy-on-write gives a convenient -representation that requires no allocation or copying, but allocated -strings are available when they're needed. Thus, when rendering text to -HTML, most text is copied just once, from the source document to the -HTML buffer. - -When using the pulldown-cmark's own HTML renderer, make sure to write to a buffered -target like a `Vec` or `String`. Since it performs many (very) small writes, writing -directly to stdout, files, or sockets is detrimental to performance. Such writers can -be wrapped in a [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html). - -## Build options - -By default, the binary is built as well. If you don't want/need it, then build like this: - -```bash -> cargo build --no-default-features -``` - -Or put in your `Cargo.toml` file: - -```toml -pulldown-cmark = { version = "0.7", default-features = false } -``` - -SIMD accelerated scanners are available for the x64 platform from version 0.5 onwards. To -enable them, build with simd feature: - -```bash -> cargo build --release --features simd -``` - -Or add the feature to your project's `Cargo.toml`: - -```toml -pulldown-cmark = { version = "0.7", default-features = false, features = ["simd"] } -``` - -## Authors - -The main author is Raph Levien. The implementation of the new design (v0.3+) was completed by Marcus Klaas de Vries. - -## Contributions - -We gladly accept contributions via GitHub pull requests. Please see -[CONTRIBUTING.md](CONTRIBUTING.md) for more details. +# pulldown-cmark + +[![Build Status](https://dev.azure.com/raphlinus/pulldown-cmark/_apis/build/status/pulldown-cmark-CI?branchName=master)](https://dev.azure.com/raphlinus/pulldown-cmark/_build/latest?definitionId=2&branchName=master) +[![Docs](https://docs.rs/pulldown-cmark/badge.svg)](https://docs.rs/pulldown-cmark) +[![Crates.io](https://img.shields.io/crates/v/pulldown-cmark.svg?maxAge=2592000)](https://crates.io/crates/pulldown-cmark) + +[Documentation](https://docs.rs/pulldown-cmark/) + +This library is a pull parser for [CommonMark](http://commonmark.org/), written +in [Rust](http://www.rust-lang.org/). It comes with a simple command-line tool, +useful for rendering to HTML, and is also designed to be easy to use from as +a library. + +It is designed to be: + +* Fast; a bare minimum of allocation and copying +* Safe; written in pure Rust with no unsafe blocks +* Versatile; in particular source-maps are supported +* Correct; the goal is 100% compliance with the [CommonMark spec](http://spec.commonmark.org/) + +Further, it optionally supports parsing footnotes, +[Github flavored tables](https://github.github.com/gfm/#tables-extension-), +[Github flavored task lists](https://github.github.com/gfm/#task-list-items-extension-) and +[strikethrough](https://github.github.com/gfm/#strikethrough-extension-). + +Rustc 1.36 or newer is required to build the crate. + +## Why a pull parser? + +There are many parsers for Markdown and its variants, but to my knowledge none +use pull parsing. Pull parsing has become popular for XML, especially for +memory-conscious applications, because it uses dramatically less memory than +constructing a document tree, but is much easier to use than push parsers. Push +parsers are notoriously difficult to use, and also often error-prone because of +the need for user to delicately juggle state in a series of callbacks. + +In a clean design, the parsing and rendering stages are neatly separated, but +this is often sacrificed in the name of performance and expedience. Many Markdown +implementations mix parsing and rendering together, and even designs that try +to separate them (such as the popular [hoedown](https://github.com/hoedown/hoedown)), +make the assumption that the rendering process can be fully represented as a +serialized string. + +Pull parsing is in some sense the most versatile architecture. It's possible to +drive a push interface, also with minimal memory, and quite straightforward to +construct an AST. Another advantage is that source-map information (the mapping +between parsed blocks and offsets within the source text) is readily available; +you can call `into_offset_iter()` to create an iterator that yields `(Event, Range)` +pairs, where the second element is the event's corresponding range in the source +document. + +While manipulating ASTs is the most flexible way to transform documents, +operating on iterators is surprisingly easy, and quite efficient. Here, for +example, is the code to transform soft line breaks into hard breaks: + +```rust +let parser = parser.map(|event| match event { + Event::SoftBreak => Event::HardBreak, + _ => event +}); +``` + +Or expanding an abbreviation in text: + +```rust +let parser = parser.map(|event| match event { + Event::Text(text) => Event::Text(text.replace("abbr", "abbreviation").into()), + _ => event +}); +``` + +Another simple example is code to determine the max nesting level: + +```rust +let mut max_nesting = 0; +let mut level = 0; +for event in parser { + match event { + Event::Start(_) => { + level += 1; + max_nesting = std::cmp::max(max_nesting, level); + } + Event::End(_) => level -= 1, + _ => () + } +} +``` + +There are some basic but fully functional examples of the usage of the crate in the +`examples` directory of this repository. + +## Using Rust idiomatically + +A lot of the internal scanning code is written at a pretty low level (it +pretty much scans byte patterns for the bits of syntax), but the external +interface is designed to be idiomatic Rust. + +Pull parsers are at heart an iterator of events (start and end tags, text, +and other bits and pieces). The parser data structure implements the +Rust Iterator trait directly, and Event is an enum. Thus, you can use the +full power and expressivity of Rust's iterator infrastructure, including +for loops and `map` (as in the examples above), collecting the events into +a vector (for recording, playback, and manipulation), and more. + +Further, the `Text` event (representing text) is a small copy-on-write string. +The vast majority of text fragments are just +slices of the source document. For these, copy-on-write gives a convenient +representation that requires no allocation or copying, but allocated +strings are available when they're needed. Thus, when rendering text to +HTML, most text is copied just once, from the source document to the +HTML buffer. + +When using the pulldown-cmark's own HTML renderer, make sure to write to a buffered +target like a `Vec` or `String`. Since it performs many (very) small writes, writing +directly to stdout, files, or sockets is detrimental to performance. Such writers can +be wrapped in a [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html). + +## Build options + +By default, the binary is built as well. If you don't want/need it, then build like this: + +```bash +> cargo build --no-default-features +``` + +Or put in your `Cargo.toml` file: + +```toml +pulldown-cmark = { version = "0.8", default-features = false } +``` + +SIMD accelerated scanners are available for the x64 platform from version 0.5 onwards. To +enable them, build with simd feature: + +```bash +> cargo build --release --features simd +``` + +Or add the feature to your project's `Cargo.toml`: + +```toml +pulldown-cmark = { version = "0.8", default-features = false, features = ["simd"] } +``` + +## Authors + +The main author is Raph Levien. The implementation of the new design (v0.3+) was completed by Marcus Klaas de Vries. + +## Contributions + +We gladly accept contributions via GitHub pull requests. Please see +[CONTRIBUTING.md](CONTRIBUTING.md) for more details. diff --git a/vendor/pulldown-cmark/benches/html_rendering.rs b/vendor/pulldown-cmark/benches/html_rendering.rs index 4a2202843d..45695ddb11 100644 --- a/vendor/pulldown-cmark/benches/html_rendering.rs +++ b/vendor/pulldown-cmark/benches/html_rendering.rs @@ -1,77 +1,101 @@ -#[macro_use] -extern crate criterion; -extern crate pulldown_cmark; - -use criterion::Criterion; -use pulldown_cmark::{html, Options, Parser}; -use std::str::from_utf8; - -static CRDT_BYTES: &[u8] = include_bytes!("../third_party/xi-editor/crdt.md"); - -fn criterion_benchmark(c: &mut Criterion) { - c.bench_function("crdt_total", |b| { - let input = from_utf8(CRDT_BYTES).unwrap(); - let mut buf = String::with_capacity(input.len() * 3 / 2); - - b.iter(|| { - buf.clear(); - html::push_html(&mut buf, Parser::new_ext(input, Options::empty())); - }) - }); - - c.bench_function("crdt_html", |b| { - let input = from_utf8(CRDT_BYTES).unwrap(); - let events: Vec<_> = Parser::new_ext(input, Options::empty()).collect(); - let mut buf = String::with_capacity(input.len() * 3 / 2); - - b.iter(|| { - buf.clear(); - html::push_html(&mut buf, events.clone().into_iter()); - }) - }); - - c.bench_function("crdt_parse", |b| { - let input = from_utf8(CRDT_BYTES).unwrap(); - - b.iter(|| Parser::new_ext(input, Options::empty()).count()) - }); - - c.bench_function("links_n_emphasis", |b| { - let input = r#"""This is a [link](example.com). **Cool!** - -This is a [link](example.com). **Cool!** - -This is a [link](example.com). **Cool!** - -This is a [link](example.com). **Cool!** -"""#; - - b.iter(|| Parser::new_ext(input, Options::empty()).count()); - }); - - c.bench_function("unescapes", |b| { - let input = "This is by far my favourite unicode code point: પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ"; - - b.iter(|| Parser::new_ext(input, Options::empty()).count()); - }); - - c.bench_function("autolinks_n_html", |b| { - let input = "Drop me a line at . Thanks! - Drop me a line at . Thanks! - Drop me a line at . Thanks! - Drop me a line at . Thanks! - Drop me a line at . Thanks! "; - - b.iter(|| Parser::new_ext(input, Options::empty()).count()); - }); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); +#[macro_use] +extern crate criterion; +extern crate pulldown_cmark; + +use criterion::Criterion; +use pulldown_cmark::{html, Options, Parser}; +use std::str::from_utf8; + +static CRDT_BYTES: &[u8] = include_bytes!("../third_party/xi-editor/crdt.md"); + +fn criterion_benchmark(c: &mut Criterion) { + let mut full_opts = Options::empty(); + full_opts.insert(Options::ENABLE_TABLES); + full_opts.insert(Options::ENABLE_FOOTNOTES); + full_opts.insert(Options::ENABLE_STRIKETHROUGH); + full_opts.insert(Options::ENABLE_TASKLISTS); + full_opts.insert(Options::ENABLE_SMART_PUNCTUATION); + + c.bench_function("crdt_total", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + let mut buf = String::with_capacity(input.len() * 3 / 2); + + b.iter(|| { + buf.clear(); + html::push_html(&mut buf, Parser::new_ext(input, Options::empty())); + }) + }); + + c.bench_function("crdt_html", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + let events: Vec<_> = Parser::new_ext(input, Options::empty()).collect(); + let mut buf = String::with_capacity(input.len() * 3 / 2); + + b.iter(|| { + buf.clear(); + html::push_html(&mut buf, events.clone().into_iter()); + }) + }); + + c.bench_function("crdt_all_options_parse", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + + b.iter(|| Parser::new_ext(input, full_opts).count()) + }); + + c.bench_function("crdt_parse", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + + b.iter(|| Parser::new_ext(input, Options::empty()).count()) + }); + + c.bench_function("smart_punctuation", |b| { + let input = r#"""'This here a real "quote"' + +And -- if you're interested -- some em-dashes. Wait --- she actually said that? + +Wow... Becky is so 'mean'! +"""#; + + b.iter(|| Parser::new_ext(input, full_opts).count()); + }); + + c.bench_function("links_n_emphasis", |b| { + let input = r#"""This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** +"""#; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("unescapes", |b| { + let input = "This is by far my favourite unicode code point: પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ"; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("autolinks_n_html", |b| { + let input = "Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! "; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/vendor/pulldown-cmark/benches/lib.rs b/vendor/pulldown-cmark/benches/lib.rs index 392aa4e12f..d0b8dfcb80 100644 --- a/vendor/pulldown-cmark/benches/lib.rs +++ b/vendor/pulldown-cmark/benches/lib.rs @@ -1,49 +1,49 @@ -#![feature(test)] - -extern crate pulldown_cmark; -extern crate test; - -mod to_html { - use pulldown_cmark::{html, Options, Parser}; - - fn render_html(text: &str, opts: Options) -> String { - let mut s = String::with_capacity(text.len() * 3 / 2); - let p = Parser::new_ext(text, opts); - html::push_html(&mut s, p); - s - } - - #[bench] - fn pathological_codeblocks1(b: &mut test::Bencher) { - // Note that `buf` grows quadratically with number of - // iterations. The point here is that the render time shouldn't - // grow faster than that. - let mut buf = String::new(); - for i in 1..1000 { - for _ in 0..i { - buf.push('`'); - } - buf.push(' '); - } - - b.iter(|| render_html(&buf, Options::empty())); - } - - #[bench] - fn advanced_pathological_codeblocks(b: &mut test::Bencher) { - let mut buf = String::new(); - let mut i = 1; - while buf.len() < 1250 { - for _ in 0..i { - buf.push('`'); - } - buf.push(' '); - i += 1; - } - for _ in 0..buf.len() { - buf.push_str("*a* "); - } - - b.iter(|| render_html(&buf, Options::empty())); - } -} +#![feature(test)] + +extern crate pulldown_cmark; +extern crate test; + +mod to_html { + use pulldown_cmark::{html, Options, Parser}; + + fn render_html(text: &str, opts: Options) -> String { + let mut s = String::with_capacity(text.len() * 3 / 2); + let p = Parser::new_ext(text, opts); + html::push_html(&mut s, p); + s + } + + #[bench] + fn pathological_codeblocks1(b: &mut test::Bencher) { + // Note that `buf` grows quadratically with number of + // iterations. The point here is that the render time shouldn't + // grow faster than that. + let mut buf = String::new(); + for i in 1..1000 { + for _ in 0..i { + buf.push('`'); + } + buf.push(' '); + } + + b.iter(|| render_html(&buf, Options::empty())); + } + + #[bench] + fn advanced_pathological_codeblocks(b: &mut test::Bencher) { + let mut buf = String::new(); + let mut i = 1; + while buf.len() < 1250 { + for _ in 0..i { + buf.push('`'); + } + buf.push(' '); + i += 1; + } + for _ in 0..buf.len() { + buf.push_str("*a* "); + } + + b.iter(|| render_html(&buf, Options::empty())); + } +} diff --git a/vendor/pulldown-cmark/build.rs b/vendor/pulldown-cmark/build.rs index 68f5689976..97ce420ddd 100644 --- a/vendor/pulldown-cmark/build.rs +++ b/vendor/pulldown-cmark/build.rs @@ -1,187 +1,186 @@ -fn main() { - generate_tests_from_spec() -} - -// If the "gen-tests" feature is absent, -// this function will be compiled down to nothing -#[cfg(not(feature = "gen-tests"))] -fn generate_tests_from_spec() {} - -// If the feature is present, generate tests -// from any .txt file present in the specs/ directory -// -// Test cases are present in the files in the -// following format: -// -// ```````````````````````````````` example -// markdown -// . -// expected html output -// ```````````````````````````````` -#[cfg(feature = "gen-tests")] -fn generate_tests_from_spec() { - use std::fs::{self, File}; - use std::io::{Read, Write}; - use std::path::PathBuf; - - // This is a hardcoded path to the CommonMark spec because it is not situated in - // the specs/ directory. It's in an array to easily chain it to the other iterator - // and make it easy to eventually add other hardcoded paths in the future if needed - let hardcoded = [ - "./third_party/CommonMark/spec.txt", - "./third_party/GitHub/gfm_table.txt", - "./third_party/GitHub/gfm_strikethrough.txt", - "./third_party/GitHub/gfm_tasklist.txt", - ]; - let hardcoded_iter = hardcoded.into_iter().map(PathBuf::from); - - // Create an iterator over the files in the specs/ directory that have a .txt extension - let spec_files = fs::read_dir("./specs") - .expect("Could not find the 'specs' directory") - .filter_map(Result::ok) - .map(|d| d.path()) - .filter(|p| p.extension().map(|e| e.to_owned()).is_some()) - .chain(hardcoded_iter) - .collect::>(); - - for file_path in &spec_files { - let mut raw_spec = String::new(); - - File::open(&file_path) - .and_then(|mut f| f.read_to_string(&mut raw_spec)) - .expect("Could not read the spec file"); - - let rs_test_file = PathBuf::from("./tests/suite/") - .join(file_path.file_name().expect("Invalid filename")) - .with_extension("rs"); - - let mut spec_rs = - File::create(&rs_test_file).expect(&format!("Could not create {:?}", rs_test_file)); - - let spec_name = file_path.file_stem().unwrap().to_str().unwrap(); - - let spec = Spec::new(&raw_spec); - let mut n_tests = 0; - - spec_rs - .write(b"// This file is auto-generated by the build script\n") - .unwrap(); - spec_rs - .write(b"// Please, do not modify it manually\n") - .unwrap(); - spec_rs - .write(b"\nuse super::test_markdown_html;\n") - .unwrap(); - - for (i, testcase) in spec.enumerate() { - spec_rs - .write_fmt(format_args!( - r###" -#[test] -fn {}_test_{i}() {{ - let original = r##"{original}"##; - let expected = r##"{expected}"##; - - test_markdown_html(original, expected); -}} -"###, - spec_name, - i = i + 1, - original = testcase.original, - expected = testcase.expected - )) - .unwrap(); - - n_tests += 1; - } - - println!( - "cargo:warning=Generated {} tests in {:?}", - n_tests, rs_test_file - ); - } - - // write mods to suite/mod.rs - let suite_mod_file = PathBuf::from("./tests/suite/mod").with_extension("rs"); - - let mut mod_rs = - File::create(&suite_mod_file).expect(&format!("Could not create {:?}", &suite_mod_file)); - - mod_rs - .write(b"// This file is auto-generated by the build script\n") - .unwrap(); - mod_rs - .write(b"// Please, do not modify it manually\n") - .unwrap(); - mod_rs - .write(b"\npub use super::test_markdown_html;\n\n") - .unwrap(); - - for file_path in &spec_files { - let mod_name = file_path.file_stem().unwrap().to_str().unwrap(); - mod_rs.write(b"mod ").unwrap(); - mod_rs.write(mod_name.as_bytes()).unwrap(); - mod_rs.write(b";\n").unwrap(); - } -} - -#[cfg(feature = "gen-tests")] -pub struct Spec<'a> { - spec: &'a str, -} - -#[cfg(feature = "gen-tests")] -impl<'a> Spec<'a> { - pub fn new(spec: &'a str) -> Self { - Spec { spec: spec } - } -} - -#[cfg(feature = "gen-tests")] -pub struct TestCase { - pub original: String, - pub expected: String, -} - -#[cfg(feature = "gen-tests")] -impl<'a> Iterator for Spec<'a> { - type Item = TestCase; - - fn next(&mut self) -> Option { - let spec = self.spec; - - let i_start = match self - .spec - .find("```````````````````````````````` example\n") - .map(|pos| pos + 41) - { - Some(pos) => pos, - None => return None, - }; - - let i_end = match self.spec[i_start..] - .find("\n.\n") - .map(|pos| (pos + 1) + i_start) - { - Some(pos) => pos, - None => return None, - }; - - let e_end = match self.spec[i_end + 2..] - .find("````````````````````````````````\n") - .map(|pos| pos + i_end + 2) - { - Some(pos) => pos, - None => return None, - }; - - self.spec = &self.spec[e_end + 33..]; - - let test_case = TestCase { - original: spec[i_start..i_end].to_string().replace("→", "\t"), - expected: spec[i_end + 2..e_end].to_string().replace("→", "\t"), - }; - - Some(test_case) - } -} +fn main() { + generate_tests_from_spec() +} + +// If the "gen-tests" feature is absent, +// this function will be compiled down to nothing +#[cfg(not(feature = "gen-tests"))] +fn generate_tests_from_spec() {} + +// If the feature is present, generate tests +// from any .txt file present in the specs/ directory +// +// Test cases are present in the files in the +// following format: +// +// ```````````````````````````````` example +// markdown +// . +// expected html output +// ```````````````````````````````` +#[cfg(feature = "gen-tests")] +fn generate_tests_from_spec() { + use std::fs::{self, File}; + use std::io::{Read, Write}; + use std::path::PathBuf; + + // This is a hardcoded path to the CommonMark spec because it is not situated in + // the specs/ directory. It's in an array to easily chain it to the other iterator + // and make it easy to eventually add other hardcoded paths in the future if needed + let hardcoded = [ + "./third_party/CommonMark/spec.txt", + "./third_party/CommonMark/smart_punct.txt", + "./third_party/GitHub/gfm_table.txt", + "./third_party/GitHub/gfm_strikethrough.txt", + "./third_party/GitHub/gfm_tasklist.txt", + ]; + let hardcoded_iter = hardcoded.iter().map(PathBuf::from); + + // Create an iterator over the files in the specs/ directory that have a .txt extension + let spec_files = fs::read_dir("./specs") + .expect("Could not find the 'specs' directory") + .filter_map(Result::ok) + .map(|d| d.path()) + .filter(|p| p.extension().map(|e| e.to_owned()).is_some()) + .chain(hardcoded_iter) + .collect::>(); + + for file_path in &spec_files { + let mut raw_spec = String::new(); + + File::open(&file_path) + .and_then(|mut f| f.read_to_string(&mut raw_spec)) + .expect("Could not read the spec file"); + + let rs_test_file = PathBuf::from("./tests/suite/") + .join(file_path.file_name().expect("Invalid filename")) + .with_extension("rs"); + + let mut spec_rs = + File::create(&rs_test_file).expect(&format!("Could not create {:?}", rs_test_file)); + + let spec_name = file_path.file_stem().unwrap().to_str().unwrap(); + + let spec = Spec::new(&raw_spec); + let mut n_tests = 0; + + spec_rs + .write(b"// This file is auto-generated by the build script\n") + .unwrap(); + spec_rs + .write(b"// Please, do not modify it manually\n") + .unwrap(); + spec_rs + .write(b"\nuse super::test_markdown_html;\n") + .unwrap(); + + for (i, testcase) in spec.enumerate() { + spec_rs + .write_fmt(format_args!( + r###" +#[test] +fn {}_test_{i}() {{ + let original = r##"{original}"##; + let expected = r##"{expected}"##; + + test_markdown_html(original, expected, {smart_punct}); +}} +"###, + spec_name, + i = i + 1, + original = testcase.original, + expected = testcase.expected, + smart_punct = testcase.smart_punct, + )) + .unwrap(); + + n_tests += 1; + } + + println!( + "cargo:warning=Generated {} tests in {:?}", + n_tests, rs_test_file + ); + } + + // write mods to suite/mod.rs + let suite_mod_file = PathBuf::from("./tests/suite/mod").with_extension("rs"); + + let mut mod_rs = + File::create(&suite_mod_file).expect(&format!("Could not create {:?}", &suite_mod_file)); + + mod_rs + .write(b"// This file is auto-generated by the build script\n") + .unwrap(); + mod_rs + .write(b"// Please, do not modify it manually\n") + .unwrap(); + mod_rs + .write(b"\npub use super::test_markdown_html;\n\n") + .unwrap(); + + for file_path in &spec_files { + let mod_name = file_path.file_stem().unwrap().to_str().unwrap(); + mod_rs.write(b"mod ").unwrap(); + mod_rs.write(mod_name.as_bytes()).unwrap(); + mod_rs.write(b";\n").unwrap(); + } +} + +#[cfg(feature = "gen-tests")] +pub struct Spec<'a> { + spec: &'a str, +} + +#[cfg(feature = "gen-tests")] +impl<'a> Spec<'a> { + pub fn new(spec: &'a str) -> Self { + Spec { spec } + } +} + +#[cfg(feature = "gen-tests")] +pub struct TestCase { + pub original: String, + pub expected: String, + pub smart_punct: bool, +} + +#[cfg(feature = "gen-tests")] +impl<'a> Iterator for Spec<'a> { + type Item = TestCase; + + fn next(&mut self) -> Option { + let spec = self.spec; + let prefix = "```````````````````````````````` example"; + + let (i_start, smart_punct) = self.spec.find(prefix).and_then(|pos| { + let suffix = "_smartpunct\n"; + if spec[(pos + prefix.len())..].starts_with(suffix) { + Some((pos + prefix.len() + suffix.len(), true)) + } else if spec[(pos + prefix.len())..].starts_with('\n') { + Some((pos + prefix.len() + 1, false)) + } else { + None + } + })?; + + let i_end = self.spec[i_start..] + .find("\n.\n") + .map(|pos| (pos + 1) + i_start)?; + + let e_end = self.spec[i_end + 2..] + .find("````````````````````````````````\n") + .map(|pos| pos + i_end + 2)?; + + self.spec = &self.spec[e_end + 33..]; + + let test_case = TestCase { + original: spec[i_start..i_end].to_string().replace("→", "\t"), + expected: spec[i_end + 2..e_end].to_string().replace("→", "\t"), + smart_punct, + }; + + Some(test_case) + } +} diff --git a/vendor/pulldown-cmark/examples/broken-link-callbacks.rs b/vendor/pulldown-cmark/examples/broken-link-callbacks.rs new file mode 100644 index 0000000000..73cdac118b --- /dev/null +++ b/vendor/pulldown-cmark/examples/broken-link-callbacks.rs @@ -0,0 +1,37 @@ +extern crate pulldown_cmark; + +use pulldown_cmark::{html, BrokenLink, Options, Parser}; + +fn main() { + let input: &str = "Hello world, check out [my website][]."; + println!("Parsing the following markdown string:\n{}", input); + + // Setup callback that sets the URL and title when it encounters + // a reference to our home page. + let callback = &mut |broken_link: BrokenLink| { + if broken_link.reference == "my website" { + println!( + "Replacing the markdown `{}` of type {:?} with a working link", + &input[broken_link.span], broken_link.link_type, + ); + Some(("http://example.com".into(), "my example website".into())) + } else { + None + } + }; + + // Create a parser with our callback function for broken links. + let parser = Parser::new_with_broken_link_callback(input, Options::empty(), Some(callback)); + + // Write to String buffer. + let mut html_output: String = String::with_capacity(input.len() * 3 / 2); + html::push_html(&mut html_output, parser); + + // Check that the output is what we expected. + let expected_html: &str = + "

    Hello world, check out my website.

    \n"; + assert_eq!(expected_html, &html_output); + + // Write result to stdout. + println!("\nHTML output:\n{}", &html_output); +} diff --git a/vendor/pulldown-cmark/examples/event-filter.rs b/vendor/pulldown-cmark/examples/event-filter.rs index 86af851f9e..7b1e9ed545 100644 --- a/vendor/pulldown-cmark/examples/event-filter.rs +++ b/vendor/pulldown-cmark/examples/event-filter.rs @@ -1,29 +1,29 @@ -extern crate pulldown_cmark; - -use std::io::Write as _; - -use pulldown_cmark::{html, Event, Options, Parser, Tag}; - -fn main() { - let markdown_input: &str = "This is Peter on ![holiday in Greece](pearl_beach.jpg)."; - println!("Parsing the following markdown string:\n{}", markdown_input); - - // Set up parser. We can treat is as any other iterator. We replace Peter by John - // and image by its alt text. - let parser = Parser::new_ext(markdown_input, Options::empty()) - .map(|event| match event { - Event::Text(text) => Event::Text(text.replace("Peter", "John").into()), - _ => event, - }) - .filter(|event| match event { - Event::Start(Tag::Image(..)) | Event::End(Tag::Image(..)) => false, - _ => true, - }); - - // Write to anything implementing the `Write` trait. This could also be a file - // or network socket. - let stdout = std::io::stdout(); - let mut handle = stdout.lock(); - handle.write_all(b"\nHTML output:\n").unwrap(); - html::write_html(&mut handle, parser).unwrap(); -} +extern crate pulldown_cmark; + +use std::io::Write as _; + +use pulldown_cmark::{html, Event, Options, Parser, Tag}; + +fn main() { + let markdown_input: &str = "This is Peter on ![holiday in Greece](pearl_beach.jpg)."; + println!("Parsing the following markdown string:\n{}", markdown_input); + + // Set up parser. We can treat is as any other iterator. We replace Peter by John + // and image by its alt text. + let parser = Parser::new_ext(markdown_input, Options::empty()) + .map(|event| match event { + Event::Text(text) => Event::Text(text.replace("Peter", "John").into()), + _ => event, + }) + .filter(|event| match event { + Event::Start(Tag::Image(..)) | Event::End(Tag::Image(..)) => false, + _ => true, + }); + + // Write to anything implementing the `Write` trait. This could also be a file + // or network socket. + let stdout = std::io::stdout(); + let mut handle = stdout.lock(); + handle.write_all(b"\nHTML output:\n").unwrap(); + html::write_html(&mut handle, parser).unwrap(); +} diff --git a/vendor/pulldown-cmark/examples/string-to-string.rs b/vendor/pulldown-cmark/examples/string-to-string.rs index ac08823334..af1664b44e 100644 --- a/vendor/pulldown-cmark/examples/string-to-string.rs +++ b/vendor/pulldown-cmark/examples/string-to-string.rs @@ -1,26 +1,26 @@ -extern crate pulldown_cmark; - -use pulldown_cmark::{html, Options, Parser}; - -fn main() { - let markdown_input: &str = "Hello world, this is a ~~complicated~~ *very simple* example."; - println!("Parsing the following markdown string:\n{}", markdown_input); - - // Set up options and parser. Strikethroughs are not part of the CommonMark standard - // and we therefore must enable it explicitly. - let mut options = Options::empty(); - options.insert(Options::ENABLE_STRIKETHROUGH); - let parser = Parser::new_ext(markdown_input, options); - - // Write to String buffer. - let mut html_output: String = String::with_capacity(markdown_input.len() * 3 / 2); - html::push_html(&mut html_output, parser); - - // Check that the output is what we expected. - let expected_html: &str = - "

    Hello world, this is a complicated very simple example.

    \n"; - assert_eq!(expected_html, &html_output); - - // Write result to stdout. - println!("\nHTML output:\n{}", &html_output); -} +extern crate pulldown_cmark; + +use pulldown_cmark::{html, Options, Parser}; + +fn main() { + let markdown_input: &str = "Hello world, this is a ~~complicated~~ *very simple* example."; + println!("Parsing the following markdown string:\n{}", markdown_input); + + // Set up options and parser. Strikethroughs are not part of the CommonMark standard + // and we therefore must enable it explicitly. + let mut options = Options::empty(); + options.insert(Options::ENABLE_STRIKETHROUGH); + let parser = Parser::new_ext(markdown_input, options); + + // Write to String buffer. + let mut html_output: String = String::with_capacity(markdown_input.len() * 3 / 2); + html::push_html(&mut html_output, parser); + + // Check that the output is what we expected. + let expected_html: &str = + "

    Hello world, this is a complicated very simple example.

    \n"; + assert_eq!(expected_html, &html_output); + + // Write result to stdout. + println!("\nHTML output:\n{}", &html_output); +} diff --git a/vendor/pulldown-cmark/src/entities.rs b/vendor/pulldown-cmark/src/entities.rs index 152342957f..042c9bccc7 100644 --- a/vendor/pulldown-cmark/src/entities.rs +++ b/vendor/pulldown-cmark/src/entities.rs @@ -1,2158 +1,2158 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Expansions of HTML5 entities - -// Autogenerated by mk_entities.py - -const ENTITIES: [(&[u8], &str); 2125] = [ - (b"AElig", "\u{00C6}"), - (b"AMP", "\u{0026}"), - (b"Aacute", "\u{00C1}"), - (b"Abreve", "\u{0102}"), - (b"Acirc", "\u{00C2}"), - (b"Acy", "\u{0410}"), - (b"Afr", "\u{1D504}"), - (b"Agrave", "\u{00C0}"), - (b"Alpha", "\u{0391}"), - (b"Amacr", "\u{0100}"), - (b"And", "\u{2A53}"), - (b"Aogon", "\u{0104}"), - (b"Aopf", "\u{1D538}"), - (b"ApplyFunction", "\u{2061}"), - (b"Aring", "\u{00C5}"), - (b"Ascr", "\u{1D49C}"), - (b"Assign", "\u{2254}"), - (b"Atilde", "\u{00C3}"), - (b"Auml", "\u{00C4}"), - (b"Backslash", "\u{2216}"), - (b"Barv", "\u{2AE7}"), - (b"Barwed", "\u{2306}"), - (b"Bcy", "\u{0411}"), - (b"Because", "\u{2235}"), - (b"Bernoullis", "\u{212C}"), - (b"Beta", "\u{0392}"), - (b"Bfr", "\u{1D505}"), - (b"Bopf", "\u{1D539}"), - (b"Breve", "\u{02D8}"), - (b"Bscr", "\u{212C}"), - (b"Bumpeq", "\u{224E}"), - (b"CHcy", "\u{0427}"), - (b"COPY", "\u{00A9}"), - (b"Cacute", "\u{0106}"), - (b"Cap", "\u{22D2}"), - (b"CapitalDifferentialD", "\u{2145}"), - (b"Cayleys", "\u{212D}"), - (b"Ccaron", "\u{010C}"), - (b"Ccedil", "\u{00C7}"), - (b"Ccirc", "\u{0108}"), - (b"Cconint", "\u{2230}"), - (b"Cdot", "\u{010A}"), - (b"Cedilla", "\u{00B8}"), - (b"CenterDot", "\u{00B7}"), - (b"Cfr", "\u{212D}"), - (b"Chi", "\u{03A7}"), - (b"CircleDot", "\u{2299}"), - (b"CircleMinus", "\u{2296}"), - (b"CirclePlus", "\u{2295}"), - (b"CircleTimes", "\u{2297}"), - (b"ClockwiseContourIntegral", "\u{2232}"), - (b"CloseCurlyDoubleQuote", "\u{201D}"), - (b"CloseCurlyQuote", "\u{2019}"), - (b"Colon", "\u{2237}"), - (b"Colone", "\u{2A74}"), - (b"Congruent", "\u{2261}"), - (b"Conint", "\u{222F}"), - (b"ContourIntegral", "\u{222E}"), - (b"Copf", "\u{2102}"), - (b"Coproduct", "\u{2210}"), - (b"CounterClockwiseContourIntegral", "\u{2233}"), - (b"Cross", "\u{2A2F}"), - (b"Cscr", "\u{1D49E}"), - (b"Cup", "\u{22D3}"), - (b"CupCap", "\u{224D}"), - (b"DD", "\u{2145}"), - (b"DDotrahd", "\u{2911}"), - (b"DJcy", "\u{0402}"), - (b"DScy", "\u{0405}"), - (b"DZcy", "\u{040F}"), - (b"Dagger", "\u{2021}"), - (b"Darr", "\u{21A1}"), - (b"Dashv", "\u{2AE4}"), - (b"Dcaron", "\u{010E}"), - (b"Dcy", "\u{0414}"), - (b"Del", "\u{2207}"), - (b"Delta", "\u{0394}"), - (b"Dfr", "\u{1D507}"), - (b"DiacriticalAcute", "\u{00B4}"), - (b"DiacriticalDot", "\u{02D9}"), - (b"DiacriticalDoubleAcute", "\u{02DD}"), - (b"DiacriticalGrave", "\u{0060}"), - (b"DiacriticalTilde", "\u{02DC}"), - (b"Diamond", "\u{22C4}"), - (b"DifferentialD", "\u{2146}"), - (b"Dopf", "\u{1D53B}"), - (b"Dot", "\u{00A8}"), - (b"DotDot", "\u{20DC}"), - (b"DotEqual", "\u{2250}"), - (b"DoubleContourIntegral", "\u{222F}"), - (b"DoubleDot", "\u{00A8}"), - (b"DoubleDownArrow", "\u{21D3}"), - (b"DoubleLeftArrow", "\u{21D0}"), - (b"DoubleLeftRightArrow", "\u{21D4}"), - (b"DoubleLeftTee", "\u{2AE4}"), - (b"DoubleLongLeftArrow", "\u{27F8}"), - (b"DoubleLongLeftRightArrow", "\u{27FA}"), - (b"DoubleLongRightArrow", "\u{27F9}"), - (b"DoubleRightArrow", "\u{21D2}"), - (b"DoubleRightTee", "\u{22A8}"), - (b"DoubleUpArrow", "\u{21D1}"), - (b"DoubleUpDownArrow", "\u{21D5}"), - (b"DoubleVerticalBar", "\u{2225}"), - (b"DownArrow", "\u{2193}"), - (b"DownArrowBar", "\u{2913}"), - (b"DownArrowUpArrow", "\u{21F5}"), - (b"DownBreve", "\u{0311}"), - (b"DownLeftRightVector", "\u{2950}"), - (b"DownLeftTeeVector", "\u{295E}"), - (b"DownLeftVector", "\u{21BD}"), - (b"DownLeftVectorBar", "\u{2956}"), - (b"DownRightTeeVector", "\u{295F}"), - (b"DownRightVector", "\u{21C1}"), - (b"DownRightVectorBar", "\u{2957}"), - (b"DownTee", "\u{22A4}"), - (b"DownTeeArrow", "\u{21A7}"), - (b"Downarrow", "\u{21D3}"), - (b"Dscr", "\u{1D49F}"), - (b"Dstrok", "\u{0110}"), - (b"ENG", "\u{014A}"), - (b"ETH", "\u{00D0}"), - (b"Eacute", "\u{00C9}"), - (b"Ecaron", "\u{011A}"), - (b"Ecirc", "\u{00CA}"), - (b"Ecy", "\u{042D}"), - (b"Edot", "\u{0116}"), - (b"Efr", "\u{1D508}"), - (b"Egrave", "\u{00C8}"), - (b"Element", "\u{2208}"), - (b"Emacr", "\u{0112}"), - (b"EmptySmallSquare", "\u{25FB}"), - (b"EmptyVerySmallSquare", "\u{25AB}"), - (b"Eogon", "\u{0118}"), - (b"Eopf", "\u{1D53C}"), - (b"Epsilon", "\u{0395}"), - (b"Equal", "\u{2A75}"), - (b"EqualTilde", "\u{2242}"), - (b"Equilibrium", "\u{21CC}"), - (b"Escr", "\u{2130}"), - (b"Esim", "\u{2A73}"), - (b"Eta", "\u{0397}"), - (b"Euml", "\u{00CB}"), - (b"Exists", "\u{2203}"), - (b"ExponentialE", "\u{2147}"), - (b"Fcy", "\u{0424}"), - (b"Ffr", "\u{1D509}"), - (b"FilledSmallSquare", "\u{25FC}"), - (b"FilledVerySmallSquare", "\u{25AA}"), - (b"Fopf", "\u{1D53D}"), - (b"ForAll", "\u{2200}"), - (b"Fouriertrf", "\u{2131}"), - (b"Fscr", "\u{2131}"), - (b"GJcy", "\u{0403}"), - (b"GT", "\u{003E}"), - (b"Gamma", "\u{0393}"), - (b"Gammad", "\u{03DC}"), - (b"Gbreve", "\u{011E}"), - (b"Gcedil", "\u{0122}"), - (b"Gcirc", "\u{011C}"), - (b"Gcy", "\u{0413}"), - (b"Gdot", "\u{0120}"), - (b"Gfr", "\u{1D50A}"), - (b"Gg", "\u{22D9}"), - (b"Gopf", "\u{1D53E}"), - (b"GreaterEqual", "\u{2265}"), - (b"GreaterEqualLess", "\u{22DB}"), - (b"GreaterFullEqual", "\u{2267}"), - (b"GreaterGreater", "\u{2AA2}"), - (b"GreaterLess", "\u{2277}"), - (b"GreaterSlantEqual", "\u{2A7E}"), - (b"GreaterTilde", "\u{2273}"), - (b"Gscr", "\u{1D4A2}"), - (b"Gt", "\u{226B}"), - (b"HARDcy", "\u{042A}"), - (b"Hacek", "\u{02C7}"), - (b"Hat", "\u{005E}"), - (b"Hcirc", "\u{0124}"), - (b"Hfr", "\u{210C}"), - (b"HilbertSpace", "\u{210B}"), - (b"Hopf", "\u{210D}"), - (b"HorizontalLine", "\u{2500}"), - (b"Hscr", "\u{210B}"), - (b"Hstrok", "\u{0126}"), - (b"HumpDownHump", "\u{224E}"), - (b"HumpEqual", "\u{224F}"), - (b"IEcy", "\u{0415}"), - (b"IJlig", "\u{0132}"), - (b"IOcy", "\u{0401}"), - (b"Iacute", "\u{00CD}"), - (b"Icirc", "\u{00CE}"), - (b"Icy", "\u{0418}"), - (b"Idot", "\u{0130}"), - (b"Ifr", "\u{2111}"), - (b"Igrave", "\u{00CC}"), - (b"Im", "\u{2111}"), - (b"Imacr", "\u{012A}"), - (b"ImaginaryI", "\u{2148}"), - (b"Implies", "\u{21D2}"), - (b"Int", "\u{222C}"), - (b"Integral", "\u{222B}"), - (b"Intersection", "\u{22C2}"), - (b"InvisibleComma", "\u{2063}"), - (b"InvisibleTimes", "\u{2062}"), - (b"Iogon", "\u{012E}"), - (b"Iopf", "\u{1D540}"), - (b"Iota", "\u{0399}"), - (b"Iscr", "\u{2110}"), - (b"Itilde", "\u{0128}"), - (b"Iukcy", "\u{0406}"), - (b"Iuml", "\u{00CF}"), - (b"Jcirc", "\u{0134}"), - (b"Jcy", "\u{0419}"), - (b"Jfr", "\u{1D50D}"), - (b"Jopf", "\u{1D541}"), - (b"Jscr", "\u{1D4A5}"), - (b"Jsercy", "\u{0408}"), - (b"Jukcy", "\u{0404}"), - (b"KHcy", "\u{0425}"), - (b"KJcy", "\u{040C}"), - (b"Kappa", "\u{039A}"), - (b"Kcedil", "\u{0136}"), - (b"Kcy", "\u{041A}"), - (b"Kfr", "\u{1D50E}"), - (b"Kopf", "\u{1D542}"), - (b"Kscr", "\u{1D4A6}"), - (b"LJcy", "\u{0409}"), - (b"LT", "\u{003C}"), - (b"Lacute", "\u{0139}"), - (b"Lambda", "\u{039B}"), - (b"Lang", "\u{27EA}"), - (b"Laplacetrf", "\u{2112}"), - (b"Larr", "\u{219E}"), - (b"Lcaron", "\u{013D}"), - (b"Lcedil", "\u{013B}"), - (b"Lcy", "\u{041B}"), - (b"LeftAngleBracket", "\u{27E8}"), - (b"LeftArrow", "\u{2190}"), - (b"LeftArrowBar", "\u{21E4}"), - (b"LeftArrowRightArrow", "\u{21C6}"), - (b"LeftCeiling", "\u{2308}"), - (b"LeftDoubleBracket", "\u{27E6}"), - (b"LeftDownTeeVector", "\u{2961}"), - (b"LeftDownVector", "\u{21C3}"), - (b"LeftDownVectorBar", "\u{2959}"), - (b"LeftFloor", "\u{230A}"), - (b"LeftRightArrow", "\u{2194}"), - (b"LeftRightVector", "\u{294E}"), - (b"LeftTee", "\u{22A3}"), - (b"LeftTeeArrow", "\u{21A4}"), - (b"LeftTeeVector", "\u{295A}"), - (b"LeftTriangle", "\u{22B2}"), - (b"LeftTriangleBar", "\u{29CF}"), - (b"LeftTriangleEqual", "\u{22B4}"), - (b"LeftUpDownVector", "\u{2951}"), - (b"LeftUpTeeVector", "\u{2960}"), - (b"LeftUpVector", "\u{21BF}"), - (b"LeftUpVectorBar", "\u{2958}"), - (b"LeftVector", "\u{21BC}"), - (b"LeftVectorBar", "\u{2952}"), - (b"Leftarrow", "\u{21D0}"), - (b"Leftrightarrow", "\u{21D4}"), - (b"LessEqualGreater", "\u{22DA}"), - (b"LessFullEqual", "\u{2266}"), - (b"LessGreater", "\u{2276}"), - (b"LessLess", "\u{2AA1}"), - (b"LessSlantEqual", "\u{2A7D}"), - (b"LessTilde", "\u{2272}"), - (b"Lfr", "\u{1D50F}"), - (b"Ll", "\u{22D8}"), - (b"Lleftarrow", "\u{21DA}"), - (b"Lmidot", "\u{013F}"), - (b"LongLeftArrow", "\u{27F5}"), - (b"LongLeftRightArrow", "\u{27F7}"), - (b"LongRightArrow", "\u{27F6}"), - (b"Longleftarrow", "\u{27F8}"), - (b"Longleftrightarrow", "\u{27FA}"), - (b"Longrightarrow", "\u{27F9}"), - (b"Lopf", "\u{1D543}"), - (b"LowerLeftArrow", "\u{2199}"), - (b"LowerRightArrow", "\u{2198}"), - (b"Lscr", "\u{2112}"), - (b"Lsh", "\u{21B0}"), - (b"Lstrok", "\u{0141}"), - (b"Lt", "\u{226A}"), - (b"Map", "\u{2905}"), - (b"Mcy", "\u{041C}"), - (b"MediumSpace", "\u{205F}"), - (b"Mellintrf", "\u{2133}"), - (b"Mfr", "\u{1D510}"), - (b"MinusPlus", "\u{2213}"), - (b"Mopf", "\u{1D544}"), - (b"Mscr", "\u{2133}"), - (b"Mu", "\u{039C}"), - (b"NJcy", "\u{040A}"), - (b"Nacute", "\u{0143}"), - (b"Ncaron", "\u{0147}"), - (b"Ncedil", "\u{0145}"), - (b"Ncy", "\u{041D}"), - (b"NegativeMediumSpace", "\u{200B}"), - (b"NegativeThickSpace", "\u{200B}"), - (b"NegativeThinSpace", "\u{200B}"), - (b"NegativeVeryThinSpace", "\u{200B}"), - (b"NestedGreaterGreater", "\u{226B}"), - (b"NestedLessLess", "\u{226A}"), - (b"NewLine", "\u{000A}"), - (b"Nfr", "\u{1D511}"), - (b"NoBreak", "\u{2060}"), - (b"NonBreakingSpace", "\u{00A0}"), - (b"Nopf", "\u{2115}"), - (b"Not", "\u{2AEC}"), - (b"NotCongruent", "\u{2262}"), - (b"NotCupCap", "\u{226D}"), - (b"NotDoubleVerticalBar", "\u{2226}"), - (b"NotElement", "\u{2209}"), - (b"NotEqual", "\u{2260}"), - (b"NotEqualTilde", "\u{2242}\u{0338}"), - (b"NotExists", "\u{2204}"), - (b"NotGreater", "\u{226F}"), - (b"NotGreaterEqual", "\u{2271}"), - (b"NotGreaterFullEqual", "\u{2267}\u{0338}"), - (b"NotGreaterGreater", "\u{226B}\u{0338}"), - (b"NotGreaterLess", "\u{2279}"), - (b"NotGreaterSlantEqual", "\u{2A7E}\u{0338}"), - (b"NotGreaterTilde", "\u{2275}"), - (b"NotHumpDownHump", "\u{224E}\u{0338}"), - (b"NotHumpEqual", "\u{224F}\u{0338}"), - (b"NotLeftTriangle", "\u{22EA}"), - (b"NotLeftTriangleBar", "\u{29CF}\u{0338}"), - (b"NotLeftTriangleEqual", "\u{22EC}"), - (b"NotLess", "\u{226E}"), - (b"NotLessEqual", "\u{2270}"), - (b"NotLessGreater", "\u{2278}"), - (b"NotLessLess", "\u{226A}\u{0338}"), - (b"NotLessSlantEqual", "\u{2A7D}\u{0338}"), - (b"NotLessTilde", "\u{2274}"), - (b"NotNestedGreaterGreater", "\u{2AA2}\u{0338}"), - (b"NotNestedLessLess", "\u{2AA1}\u{0338}"), - (b"NotPrecedes", "\u{2280}"), - (b"NotPrecedesEqual", "\u{2AAF}\u{0338}"), - (b"NotPrecedesSlantEqual", "\u{22E0}"), - (b"NotReverseElement", "\u{220C}"), - (b"NotRightTriangle", "\u{22EB}"), - (b"NotRightTriangleBar", "\u{29D0}\u{0338}"), - (b"NotRightTriangleEqual", "\u{22ED}"), - (b"NotSquareSubset", "\u{228F}\u{0338}"), - (b"NotSquareSubsetEqual", "\u{22E2}"), - (b"NotSquareSuperset", "\u{2290}\u{0338}"), - (b"NotSquareSupersetEqual", "\u{22E3}"), - (b"NotSubset", "\u{2282}\u{20D2}"), - (b"NotSubsetEqual", "\u{2288}"), - (b"NotSucceeds", "\u{2281}"), - (b"NotSucceedsEqual", "\u{2AB0}\u{0338}"), - (b"NotSucceedsSlantEqual", "\u{22E1}"), - (b"NotSucceedsTilde", "\u{227F}\u{0338}"), - (b"NotSuperset", "\u{2283}\u{20D2}"), - (b"NotSupersetEqual", "\u{2289}"), - (b"NotTilde", "\u{2241}"), - (b"NotTildeEqual", "\u{2244}"), - (b"NotTildeFullEqual", "\u{2247}"), - (b"NotTildeTilde", "\u{2249}"), - (b"NotVerticalBar", "\u{2224}"), - (b"Nscr", "\u{1D4A9}"), - (b"Ntilde", "\u{00D1}"), - (b"Nu", "\u{039D}"), - (b"OElig", "\u{0152}"), - (b"Oacute", "\u{00D3}"), - (b"Ocirc", "\u{00D4}"), - (b"Ocy", "\u{041E}"), - (b"Odblac", "\u{0150}"), - (b"Ofr", "\u{1D512}"), - (b"Ograve", "\u{00D2}"), - (b"Omacr", "\u{014C}"), - (b"Omega", "\u{03A9}"), - (b"Omicron", "\u{039F}"), - (b"Oopf", "\u{1D546}"), - (b"OpenCurlyDoubleQuote", "\u{201C}"), - (b"OpenCurlyQuote", "\u{2018}"), - (b"Or", "\u{2A54}"), - (b"Oscr", "\u{1D4AA}"), - (b"Oslash", "\u{00D8}"), - (b"Otilde", "\u{00D5}"), - (b"Otimes", "\u{2A37}"), - (b"Ouml", "\u{00D6}"), - (b"OverBar", "\u{203E}"), - (b"OverBrace", "\u{23DE}"), - (b"OverBracket", "\u{23B4}"), - (b"OverParenthesis", "\u{23DC}"), - (b"PartialD", "\u{2202}"), - (b"Pcy", "\u{041F}"), - (b"Pfr", "\u{1D513}"), - (b"Phi", "\u{03A6}"), - (b"Pi", "\u{03A0}"), - (b"PlusMinus", "\u{00B1}"), - (b"Poincareplane", "\u{210C}"), - (b"Popf", "\u{2119}"), - (b"Pr", "\u{2ABB}"), - (b"Precedes", "\u{227A}"), - (b"PrecedesEqual", "\u{2AAF}"), - (b"PrecedesSlantEqual", "\u{227C}"), - (b"PrecedesTilde", "\u{227E}"), - (b"Prime", "\u{2033}"), - (b"Product", "\u{220F}"), - (b"Proportion", "\u{2237}"), - (b"Proportional", "\u{221D}"), - (b"Pscr", "\u{1D4AB}"), - (b"Psi", "\u{03A8}"), - (b"QUOT", "\u{0022}"), - (b"Qfr", "\u{1D514}"), - (b"Qopf", "\u{211A}"), - (b"Qscr", "\u{1D4AC}"), - (b"RBarr", "\u{2910}"), - (b"REG", "\u{00AE}"), - (b"Racute", "\u{0154}"), - (b"Rang", "\u{27EB}"), - (b"Rarr", "\u{21A0}"), - (b"Rarrtl", "\u{2916}"), - (b"Rcaron", "\u{0158}"), - (b"Rcedil", "\u{0156}"), - (b"Rcy", "\u{0420}"), - (b"Re", "\u{211C}"), - (b"ReverseElement", "\u{220B}"), - (b"ReverseEquilibrium", "\u{21CB}"), - (b"ReverseUpEquilibrium", "\u{296F}"), - (b"Rfr", "\u{211C}"), - (b"Rho", "\u{03A1}"), - (b"RightAngleBracket", "\u{27E9}"), - (b"RightArrow", "\u{2192}"), - (b"RightArrowBar", "\u{21E5}"), - (b"RightArrowLeftArrow", "\u{21C4}"), - (b"RightCeiling", "\u{2309}"), - (b"RightDoubleBracket", "\u{27E7}"), - (b"RightDownTeeVector", "\u{295D}"), - (b"RightDownVector", "\u{21C2}"), - (b"RightDownVectorBar", "\u{2955}"), - (b"RightFloor", "\u{230B}"), - (b"RightTee", "\u{22A2}"), - (b"RightTeeArrow", "\u{21A6}"), - (b"RightTeeVector", "\u{295B}"), - (b"RightTriangle", "\u{22B3}"), - (b"RightTriangleBar", "\u{29D0}"), - (b"RightTriangleEqual", "\u{22B5}"), - (b"RightUpDownVector", "\u{294F}"), - (b"RightUpTeeVector", "\u{295C}"), - (b"RightUpVector", "\u{21BE}"), - (b"RightUpVectorBar", "\u{2954}"), - (b"RightVector", "\u{21C0}"), - (b"RightVectorBar", "\u{2953}"), - (b"Rightarrow", "\u{21D2}"), - (b"Ropf", "\u{211D}"), - (b"RoundImplies", "\u{2970}"), - (b"Rrightarrow", "\u{21DB}"), - (b"Rscr", "\u{211B}"), - (b"Rsh", "\u{21B1}"), - (b"RuleDelayed", "\u{29F4}"), - (b"SHCHcy", "\u{0429}"), - (b"SHcy", "\u{0428}"), - (b"SOFTcy", "\u{042C}"), - (b"Sacute", "\u{015A}"), - (b"Sc", "\u{2ABC}"), - (b"Scaron", "\u{0160}"), - (b"Scedil", "\u{015E}"), - (b"Scirc", "\u{015C}"), - (b"Scy", "\u{0421}"), - (b"Sfr", "\u{1D516}"), - (b"ShortDownArrow", "\u{2193}"), - (b"ShortLeftArrow", "\u{2190}"), - (b"ShortRightArrow", "\u{2192}"), - (b"ShortUpArrow", "\u{2191}"), - (b"Sigma", "\u{03A3}"), - (b"SmallCircle", "\u{2218}"), - (b"Sopf", "\u{1D54A}"), - (b"Sqrt", "\u{221A}"), - (b"Square", "\u{25A1}"), - (b"SquareIntersection", "\u{2293}"), - (b"SquareSubset", "\u{228F}"), - (b"SquareSubsetEqual", "\u{2291}"), - (b"SquareSuperset", "\u{2290}"), - (b"SquareSupersetEqual", "\u{2292}"), - (b"SquareUnion", "\u{2294}"), - (b"Sscr", "\u{1D4AE}"), - (b"Star", "\u{22C6}"), - (b"Sub", "\u{22D0}"), - (b"Subset", "\u{22D0}"), - (b"SubsetEqual", "\u{2286}"), - (b"Succeeds", "\u{227B}"), - (b"SucceedsEqual", "\u{2AB0}"), - (b"SucceedsSlantEqual", "\u{227D}"), - (b"SucceedsTilde", "\u{227F}"), - (b"SuchThat", "\u{220B}"), - (b"Sum", "\u{2211}"), - (b"Sup", "\u{22D1}"), - (b"Superset", "\u{2283}"), - (b"SupersetEqual", "\u{2287}"), - (b"Supset", "\u{22D1}"), - (b"THORN", "\u{00DE}"), - (b"TRADE", "\u{2122}"), - (b"TSHcy", "\u{040B}"), - (b"TScy", "\u{0426}"), - (b"Tab", "\u{0009}"), - (b"Tau", "\u{03A4}"), - (b"Tcaron", "\u{0164}"), - (b"Tcedil", "\u{0162}"), - (b"Tcy", "\u{0422}"), - (b"Tfr", "\u{1D517}"), - (b"Therefore", "\u{2234}"), - (b"Theta", "\u{0398}"), - (b"ThickSpace", "\u{205F}\u{200A}"), - (b"ThinSpace", "\u{2009}"), - (b"Tilde", "\u{223C}"), - (b"TildeEqual", "\u{2243}"), - (b"TildeFullEqual", "\u{2245}"), - (b"TildeTilde", "\u{2248}"), - (b"Topf", "\u{1D54B}"), - (b"TripleDot", "\u{20DB}"), - (b"Tscr", "\u{1D4AF}"), - (b"Tstrok", "\u{0166}"), - (b"Uacute", "\u{00DA}"), - (b"Uarr", "\u{219F}"), - (b"Uarrocir", "\u{2949}"), - (b"Ubrcy", "\u{040E}"), - (b"Ubreve", "\u{016C}"), - (b"Ucirc", "\u{00DB}"), - (b"Ucy", "\u{0423}"), - (b"Udblac", "\u{0170}"), - (b"Ufr", "\u{1D518}"), - (b"Ugrave", "\u{00D9}"), - (b"Umacr", "\u{016A}"), - (b"UnderBar", "\u{005F}"), - (b"UnderBrace", "\u{23DF}"), - (b"UnderBracket", "\u{23B5}"), - (b"UnderParenthesis", "\u{23DD}"), - (b"Union", "\u{22C3}"), - (b"UnionPlus", "\u{228E}"), - (b"Uogon", "\u{0172}"), - (b"Uopf", "\u{1D54C}"), - (b"UpArrow", "\u{2191}"), - (b"UpArrowBar", "\u{2912}"), - (b"UpArrowDownArrow", "\u{21C5}"), - (b"UpDownArrow", "\u{2195}"), - (b"UpEquilibrium", "\u{296E}"), - (b"UpTee", "\u{22A5}"), - (b"UpTeeArrow", "\u{21A5}"), - (b"Uparrow", "\u{21D1}"), - (b"Updownarrow", "\u{21D5}"), - (b"UpperLeftArrow", "\u{2196}"), - (b"UpperRightArrow", "\u{2197}"), - (b"Upsi", "\u{03D2}"), - (b"Upsilon", "\u{03A5}"), - (b"Uring", "\u{016E}"), - (b"Uscr", "\u{1D4B0}"), - (b"Utilde", "\u{0168}"), - (b"Uuml", "\u{00DC}"), - (b"VDash", "\u{22AB}"), - (b"Vbar", "\u{2AEB}"), - (b"Vcy", "\u{0412}"), - (b"Vdash", "\u{22A9}"), - (b"Vdashl", "\u{2AE6}"), - (b"Vee", "\u{22C1}"), - (b"Verbar", "\u{2016}"), - (b"Vert", "\u{2016}"), - (b"VerticalBar", "\u{2223}"), - (b"VerticalLine", "\u{007C}"), - (b"VerticalSeparator", "\u{2758}"), - (b"VerticalTilde", "\u{2240}"), - (b"VeryThinSpace", "\u{200A}"), - (b"Vfr", "\u{1D519}"), - (b"Vopf", "\u{1D54D}"), - (b"Vscr", "\u{1D4B1}"), - (b"Vvdash", "\u{22AA}"), - (b"Wcirc", "\u{0174}"), - (b"Wedge", "\u{22C0}"), - (b"Wfr", "\u{1D51A}"), - (b"Wopf", "\u{1D54E}"), - (b"Wscr", "\u{1D4B2}"), - (b"Xfr", "\u{1D51B}"), - (b"Xi", "\u{039E}"), - (b"Xopf", "\u{1D54F}"), - (b"Xscr", "\u{1D4B3}"), - (b"YAcy", "\u{042F}"), - (b"YIcy", "\u{0407}"), - (b"YUcy", "\u{042E}"), - (b"Yacute", "\u{00DD}"), - (b"Ycirc", "\u{0176}"), - (b"Ycy", "\u{042B}"), - (b"Yfr", "\u{1D51C}"), - (b"Yopf", "\u{1D550}"), - (b"Yscr", "\u{1D4B4}"), - (b"Yuml", "\u{0178}"), - (b"ZHcy", "\u{0416}"), - (b"Zacute", "\u{0179}"), - (b"Zcaron", "\u{017D}"), - (b"Zcy", "\u{0417}"), - (b"Zdot", "\u{017B}"), - (b"ZeroWidthSpace", "\u{200B}"), - (b"Zeta", "\u{0396}"), - (b"Zfr", "\u{2128}"), - (b"Zopf", "\u{2124}"), - (b"Zscr", "\u{1D4B5}"), - (b"aacute", "\u{00E1}"), - (b"abreve", "\u{0103}"), - (b"ac", "\u{223E}"), - (b"acE", "\u{223E}\u{0333}"), - (b"acd", "\u{223F}"), - (b"acirc", "\u{00E2}"), - (b"acute", "\u{00B4}"), - (b"acy", "\u{0430}"), - (b"aelig", "\u{00E6}"), - (b"af", "\u{2061}"), - (b"afr", "\u{1D51E}"), - (b"agrave", "\u{00E0}"), - (b"alefsym", "\u{2135}"), - (b"aleph", "\u{2135}"), - (b"alpha", "\u{03B1}"), - (b"amacr", "\u{0101}"), - (b"amalg", "\u{2A3F}"), - (b"amp", "\u{0026}"), - (b"and", "\u{2227}"), - (b"andand", "\u{2A55}"), - (b"andd", "\u{2A5C}"), - (b"andslope", "\u{2A58}"), - (b"andv", "\u{2A5A}"), - (b"ang", "\u{2220}"), - (b"ange", "\u{29A4}"), - (b"angle", "\u{2220}"), - (b"angmsd", "\u{2221}"), - (b"angmsdaa", "\u{29A8}"), - (b"angmsdab", "\u{29A9}"), - (b"angmsdac", "\u{29AA}"), - (b"angmsdad", "\u{29AB}"), - (b"angmsdae", "\u{29AC}"), - (b"angmsdaf", "\u{29AD}"), - (b"angmsdag", "\u{29AE}"), - (b"angmsdah", "\u{29AF}"), - (b"angrt", "\u{221F}"), - (b"angrtvb", "\u{22BE}"), - (b"angrtvbd", "\u{299D}"), - (b"angsph", "\u{2222}"), - (b"angst", "\u{00C5}"), - (b"angzarr", "\u{237C}"), - (b"aogon", "\u{0105}"), - (b"aopf", "\u{1D552}"), - (b"ap", "\u{2248}"), - (b"apE", "\u{2A70}"), - (b"apacir", "\u{2A6F}"), - (b"ape", "\u{224A}"), - (b"apid", "\u{224B}"), - (b"apos", "\u{0027}"), - (b"approx", "\u{2248}"), - (b"approxeq", "\u{224A}"), - (b"aring", "\u{00E5}"), - (b"ascr", "\u{1D4B6}"), - (b"ast", "\u{002A}"), - (b"asymp", "\u{2248}"), - (b"asympeq", "\u{224D}"), - (b"atilde", "\u{00E3}"), - (b"auml", "\u{00E4}"), - (b"awconint", "\u{2233}"), - (b"awint", "\u{2A11}"), - (b"bNot", "\u{2AED}"), - (b"backcong", "\u{224C}"), - (b"backepsilon", "\u{03F6}"), - (b"backprime", "\u{2035}"), - (b"backsim", "\u{223D}"), - (b"backsimeq", "\u{22CD}"), - (b"barvee", "\u{22BD}"), - (b"barwed", "\u{2305}"), - (b"barwedge", "\u{2305}"), - (b"bbrk", "\u{23B5}"), - (b"bbrktbrk", "\u{23B6}"), - (b"bcong", "\u{224C}"), - (b"bcy", "\u{0431}"), - (b"bdquo", "\u{201E}"), - (b"becaus", "\u{2235}"), - (b"because", "\u{2235}"), - (b"bemptyv", "\u{29B0}"), - (b"bepsi", "\u{03F6}"), - (b"bernou", "\u{212C}"), - (b"beta", "\u{03B2}"), - (b"beth", "\u{2136}"), - (b"between", "\u{226C}"), - (b"bfr", "\u{1D51F}"), - (b"bigcap", "\u{22C2}"), - (b"bigcirc", "\u{25EF}"), - (b"bigcup", "\u{22C3}"), - (b"bigodot", "\u{2A00}"), - (b"bigoplus", "\u{2A01}"), - (b"bigotimes", "\u{2A02}"), - (b"bigsqcup", "\u{2A06}"), - (b"bigstar", "\u{2605}"), - (b"bigtriangledown", "\u{25BD}"), - (b"bigtriangleup", "\u{25B3}"), - (b"biguplus", "\u{2A04}"), - (b"bigvee", "\u{22C1}"), - (b"bigwedge", "\u{22C0}"), - (b"bkarow", "\u{290D}"), - (b"blacklozenge", "\u{29EB}"), - (b"blacksquare", "\u{25AA}"), - (b"blacktriangle", "\u{25B4}"), - (b"blacktriangledown", "\u{25BE}"), - (b"blacktriangleleft", "\u{25C2}"), - (b"blacktriangleright", "\u{25B8}"), - (b"blank", "\u{2423}"), - (b"blk12", "\u{2592}"), - (b"blk14", "\u{2591}"), - (b"blk34", "\u{2593}"), - (b"block", "\u{2588}"), - (b"bne", "\u{003D}\u{20E5}"), - (b"bnequiv", "\u{2261}\u{20E5}"), - (b"bnot", "\u{2310}"), - (b"bopf", "\u{1D553}"), - (b"bot", "\u{22A5}"), - (b"bottom", "\u{22A5}"), - (b"bowtie", "\u{22C8}"), - (b"boxDL", "\u{2557}"), - (b"boxDR", "\u{2554}"), - (b"boxDl", "\u{2556}"), - (b"boxDr", "\u{2553}"), - (b"boxH", "\u{2550}"), - (b"boxHD", "\u{2566}"), - (b"boxHU", "\u{2569}"), - (b"boxHd", "\u{2564}"), - (b"boxHu", "\u{2567}"), - (b"boxUL", "\u{255D}"), - (b"boxUR", "\u{255A}"), - (b"boxUl", "\u{255C}"), - (b"boxUr", "\u{2559}"), - (b"boxV", "\u{2551}"), - (b"boxVH", "\u{256C}"), - (b"boxVL", "\u{2563}"), - (b"boxVR", "\u{2560}"), - (b"boxVh", "\u{256B}"), - (b"boxVl", "\u{2562}"), - (b"boxVr", "\u{255F}"), - (b"boxbox", "\u{29C9}"), - (b"boxdL", "\u{2555}"), - (b"boxdR", "\u{2552}"), - (b"boxdl", "\u{2510}"), - (b"boxdr", "\u{250C}"), - (b"boxh", "\u{2500}"), - (b"boxhD", "\u{2565}"), - (b"boxhU", "\u{2568}"), - (b"boxhd", "\u{252C}"), - (b"boxhu", "\u{2534}"), - (b"boxminus", "\u{229F}"), - (b"boxplus", "\u{229E}"), - (b"boxtimes", "\u{22A0}"), - (b"boxuL", "\u{255B}"), - (b"boxuR", "\u{2558}"), - (b"boxul", "\u{2518}"), - (b"boxur", "\u{2514}"), - (b"boxv", "\u{2502}"), - (b"boxvH", "\u{256A}"), - (b"boxvL", "\u{2561}"), - (b"boxvR", "\u{255E}"), - (b"boxvh", "\u{253C}"), - (b"boxvl", "\u{2524}"), - (b"boxvr", "\u{251C}"), - (b"bprime", "\u{2035}"), - (b"breve", "\u{02D8}"), - (b"brvbar", "\u{00A6}"), - (b"bscr", "\u{1D4B7}"), - (b"bsemi", "\u{204F}"), - (b"bsim", "\u{223D}"), - (b"bsime", "\u{22CD}"), - (b"bsol", "\u{005C}"), - (b"bsolb", "\u{29C5}"), - (b"bsolhsub", "\u{27C8}"), - (b"bull", "\u{2022}"), - (b"bullet", "\u{2022}"), - (b"bump", "\u{224E}"), - (b"bumpE", "\u{2AAE}"), - (b"bumpe", "\u{224F}"), - (b"bumpeq", "\u{224F}"), - (b"cacute", "\u{0107}"), - (b"cap", "\u{2229}"), - (b"capand", "\u{2A44}"), - (b"capbrcup", "\u{2A49}"), - (b"capcap", "\u{2A4B}"), - (b"capcup", "\u{2A47}"), - (b"capdot", "\u{2A40}"), - (b"caps", "\u{2229}\u{FE00}"), - (b"caret", "\u{2041}"), - (b"caron", "\u{02C7}"), - (b"ccaps", "\u{2A4D}"), - (b"ccaron", "\u{010D}"), - (b"ccedil", "\u{00E7}"), - (b"ccirc", "\u{0109}"), - (b"ccups", "\u{2A4C}"), - (b"ccupssm", "\u{2A50}"), - (b"cdot", "\u{010B}"), - (b"cedil", "\u{00B8}"), - (b"cemptyv", "\u{29B2}"), - (b"cent", "\u{00A2}"), - (b"centerdot", "\u{00B7}"), - (b"cfr", "\u{1D520}"), - (b"chcy", "\u{0447}"), - (b"check", "\u{2713}"), - (b"checkmark", "\u{2713}"), - (b"chi", "\u{03C7}"), - (b"cir", "\u{25CB}"), - (b"cirE", "\u{29C3}"), - (b"circ", "\u{02C6}"), - (b"circeq", "\u{2257}"), - (b"circlearrowleft", "\u{21BA}"), - (b"circlearrowright", "\u{21BB}"), - (b"circledR", "\u{00AE}"), - (b"circledS", "\u{24C8}"), - (b"circledast", "\u{229B}"), - (b"circledcirc", "\u{229A}"), - (b"circleddash", "\u{229D}"), - (b"cire", "\u{2257}"), - (b"cirfnint", "\u{2A10}"), - (b"cirmid", "\u{2AEF}"), - (b"cirscir", "\u{29C2}"), - (b"clubs", "\u{2663}"), - (b"clubsuit", "\u{2663}"), - (b"colon", "\u{003A}"), - (b"colone", "\u{2254}"), - (b"coloneq", "\u{2254}"), - (b"comma", "\u{002C}"), - (b"commat", "\u{0040}"), - (b"comp", "\u{2201}"), - (b"compfn", "\u{2218}"), - (b"complement", "\u{2201}"), - (b"complexes", "\u{2102}"), - (b"cong", "\u{2245}"), - (b"congdot", "\u{2A6D}"), - (b"conint", "\u{222E}"), - (b"copf", "\u{1D554}"), - (b"coprod", "\u{2210}"), - (b"copy", "\u{00A9}"), - (b"copysr", "\u{2117}"), - (b"crarr", "\u{21B5}"), - (b"cross", "\u{2717}"), - (b"cscr", "\u{1D4B8}"), - (b"csub", "\u{2ACF}"), - (b"csube", "\u{2AD1}"), - (b"csup", "\u{2AD0}"), - (b"csupe", "\u{2AD2}"), - (b"ctdot", "\u{22EF}"), - (b"cudarrl", "\u{2938}"), - (b"cudarrr", "\u{2935}"), - (b"cuepr", "\u{22DE}"), - (b"cuesc", "\u{22DF}"), - (b"cularr", "\u{21B6}"), - (b"cularrp", "\u{293D}"), - (b"cup", "\u{222A}"), - (b"cupbrcap", "\u{2A48}"), - (b"cupcap", "\u{2A46}"), - (b"cupcup", "\u{2A4A}"), - (b"cupdot", "\u{228D}"), - (b"cupor", "\u{2A45}"), - (b"cups", "\u{222A}\u{FE00}"), - (b"curarr", "\u{21B7}"), - (b"curarrm", "\u{293C}"), - (b"curlyeqprec", "\u{22DE}"), - (b"curlyeqsucc", "\u{22DF}"), - (b"curlyvee", "\u{22CE}"), - (b"curlywedge", "\u{22CF}"), - (b"curren", "\u{00A4}"), - (b"curvearrowleft", "\u{21B6}"), - (b"curvearrowright", "\u{21B7}"), - (b"cuvee", "\u{22CE}"), - (b"cuwed", "\u{22CF}"), - (b"cwconint", "\u{2232}"), - (b"cwint", "\u{2231}"), - (b"cylcty", "\u{232D}"), - (b"dArr", "\u{21D3}"), - (b"dHar", "\u{2965}"), - (b"dagger", "\u{2020}"), - (b"daleth", "\u{2138}"), - (b"darr", "\u{2193}"), - (b"dash", "\u{2010}"), - (b"dashv", "\u{22A3}"), - (b"dbkarow", "\u{290F}"), - (b"dblac", "\u{02DD}"), - (b"dcaron", "\u{010F}"), - (b"dcy", "\u{0434}"), - (b"dd", "\u{2146}"), - (b"ddagger", "\u{2021}"), - (b"ddarr", "\u{21CA}"), - (b"ddotseq", "\u{2A77}"), - (b"deg", "\u{00B0}"), - (b"delta", "\u{03B4}"), - (b"demptyv", "\u{29B1}"), - (b"dfisht", "\u{297F}"), - (b"dfr", "\u{1D521}"), - (b"dharl", "\u{21C3}"), - (b"dharr", "\u{21C2}"), - (b"diam", "\u{22C4}"), - (b"diamond", "\u{22C4}"), - (b"diamondsuit", "\u{2666}"), - (b"diams", "\u{2666}"), - (b"die", "\u{00A8}"), - (b"digamma", "\u{03DD}"), - (b"disin", "\u{22F2}"), - (b"div", "\u{00F7}"), - (b"divide", "\u{00F7}"), - (b"divideontimes", "\u{22C7}"), - (b"divonx", "\u{22C7}"), - (b"djcy", "\u{0452}"), - (b"dlcorn", "\u{231E}"), - (b"dlcrop", "\u{230D}"), - (b"dollar", "\u{0024}"), - (b"dopf", "\u{1D555}"), - (b"dot", "\u{02D9}"), - (b"doteq", "\u{2250}"), - (b"doteqdot", "\u{2251}"), - (b"dotminus", "\u{2238}"), - (b"dotplus", "\u{2214}"), - (b"dotsquare", "\u{22A1}"), - (b"doublebarwedge", "\u{2306}"), - (b"downarrow", "\u{2193}"), - (b"downdownarrows", "\u{21CA}"), - (b"downharpoonleft", "\u{21C3}"), - (b"downharpoonright", "\u{21C2}"), - (b"drbkarow", "\u{2910}"), - (b"drcorn", "\u{231F}"), - (b"drcrop", "\u{230C}"), - (b"dscr", "\u{1D4B9}"), - (b"dscy", "\u{0455}"), - (b"dsol", "\u{29F6}"), - (b"dstrok", "\u{0111}"), - (b"dtdot", "\u{22F1}"), - (b"dtri", "\u{25BF}"), - (b"dtrif", "\u{25BE}"), - (b"duarr", "\u{21F5}"), - (b"duhar", "\u{296F}"), - (b"dwangle", "\u{29A6}"), - (b"dzcy", "\u{045F}"), - (b"dzigrarr", "\u{27FF}"), - (b"eDDot", "\u{2A77}"), - (b"eDot", "\u{2251}"), - (b"eacute", "\u{00E9}"), - (b"easter", "\u{2A6E}"), - (b"ecaron", "\u{011B}"), - (b"ecir", "\u{2256}"), - (b"ecirc", "\u{00EA}"), - (b"ecolon", "\u{2255}"), - (b"ecy", "\u{044D}"), - (b"edot", "\u{0117}"), - (b"ee", "\u{2147}"), - (b"efDot", "\u{2252}"), - (b"efr", "\u{1D522}"), - (b"eg", "\u{2A9A}"), - (b"egrave", "\u{00E8}"), - (b"egs", "\u{2A96}"), - (b"egsdot", "\u{2A98}"), - (b"el", "\u{2A99}"), - (b"elinters", "\u{23E7}"), - (b"ell", "\u{2113}"), - (b"els", "\u{2A95}"), - (b"elsdot", "\u{2A97}"), - (b"emacr", "\u{0113}"), - (b"empty", "\u{2205}"), - (b"emptyset", "\u{2205}"), - (b"emptyv", "\u{2205}"), - (b"emsp", "\u{2003}"), - (b"emsp13", "\u{2004}"), - (b"emsp14", "\u{2005}"), - (b"eng", "\u{014B}"), - (b"ensp", "\u{2002}"), - (b"eogon", "\u{0119}"), - (b"eopf", "\u{1D556}"), - (b"epar", "\u{22D5}"), - (b"eparsl", "\u{29E3}"), - (b"eplus", "\u{2A71}"), - (b"epsi", "\u{03B5}"), - (b"epsilon", "\u{03B5}"), - (b"epsiv", "\u{03F5}"), - (b"eqcirc", "\u{2256}"), - (b"eqcolon", "\u{2255}"), - (b"eqsim", "\u{2242}"), - (b"eqslantgtr", "\u{2A96}"), - (b"eqslantless", "\u{2A95}"), - (b"equals", "\u{003D}"), - (b"equest", "\u{225F}"), - (b"equiv", "\u{2261}"), - (b"equivDD", "\u{2A78}"), - (b"eqvparsl", "\u{29E5}"), - (b"erDot", "\u{2253}"), - (b"erarr", "\u{2971}"), - (b"escr", "\u{212F}"), - (b"esdot", "\u{2250}"), - (b"esim", "\u{2242}"), - (b"eta", "\u{03B7}"), - (b"eth", "\u{00F0}"), - (b"euml", "\u{00EB}"), - (b"euro", "\u{20AC}"), - (b"excl", "\u{0021}"), - (b"exist", "\u{2203}"), - (b"expectation", "\u{2130}"), - (b"exponentiale", "\u{2147}"), - (b"fallingdotseq", "\u{2252}"), - (b"fcy", "\u{0444}"), - (b"female", "\u{2640}"), - (b"ffilig", "\u{FB03}"), - (b"fflig", "\u{FB00}"), - (b"ffllig", "\u{FB04}"), - (b"ffr", "\u{1D523}"), - (b"filig", "\u{FB01}"), - (b"fjlig", "\u{0066}\u{006A}"), - (b"flat", "\u{266D}"), - (b"fllig", "\u{FB02}"), - (b"fltns", "\u{25B1}"), - (b"fnof", "\u{0192}"), - (b"fopf", "\u{1D557}"), - (b"forall", "\u{2200}"), - (b"fork", "\u{22D4}"), - (b"forkv", "\u{2AD9}"), - (b"fpartint", "\u{2A0D}"), - (b"frac12", "\u{00BD}"), - (b"frac13", "\u{2153}"), - (b"frac14", "\u{00BC}"), - (b"frac15", "\u{2155}"), - (b"frac16", "\u{2159}"), - (b"frac18", "\u{215B}"), - (b"frac23", "\u{2154}"), - (b"frac25", "\u{2156}"), - (b"frac34", "\u{00BE}"), - (b"frac35", "\u{2157}"), - (b"frac38", "\u{215C}"), - (b"frac45", "\u{2158}"), - (b"frac56", "\u{215A}"), - (b"frac58", "\u{215D}"), - (b"frac78", "\u{215E}"), - (b"frasl", "\u{2044}"), - (b"frown", "\u{2322}"), - (b"fscr", "\u{1D4BB}"), - (b"gE", "\u{2267}"), - (b"gEl", "\u{2A8C}"), - (b"gacute", "\u{01F5}"), - (b"gamma", "\u{03B3}"), - (b"gammad", "\u{03DD}"), - (b"gap", "\u{2A86}"), - (b"gbreve", "\u{011F}"), - (b"gcirc", "\u{011D}"), - (b"gcy", "\u{0433}"), - (b"gdot", "\u{0121}"), - (b"ge", "\u{2265}"), - (b"gel", "\u{22DB}"), - (b"geq", "\u{2265}"), - (b"geqq", "\u{2267}"), - (b"geqslant", "\u{2A7E}"), - (b"ges", "\u{2A7E}"), - (b"gescc", "\u{2AA9}"), - (b"gesdot", "\u{2A80}"), - (b"gesdoto", "\u{2A82}"), - (b"gesdotol", "\u{2A84}"), - (b"gesl", "\u{22DB}\u{FE00}"), - (b"gesles", "\u{2A94}"), - (b"gfr", "\u{1D524}"), - (b"gg", "\u{226B}"), - (b"ggg", "\u{22D9}"), - (b"gimel", "\u{2137}"), - (b"gjcy", "\u{0453}"), - (b"gl", "\u{2277}"), - (b"glE", "\u{2A92}"), - (b"gla", "\u{2AA5}"), - (b"glj", "\u{2AA4}"), - (b"gnE", "\u{2269}"), - (b"gnap", "\u{2A8A}"), - (b"gnapprox", "\u{2A8A}"), - (b"gne", "\u{2A88}"), - (b"gneq", "\u{2A88}"), - (b"gneqq", "\u{2269}"), - (b"gnsim", "\u{22E7}"), - (b"gopf", "\u{1D558}"), - (b"grave", "\u{0060}"), - (b"gscr", "\u{210A}"), - (b"gsim", "\u{2273}"), - (b"gsime", "\u{2A8E}"), - (b"gsiml", "\u{2A90}"), - (b"gt", "\u{003E}"), - (b"gtcc", "\u{2AA7}"), - (b"gtcir", "\u{2A7A}"), - (b"gtdot", "\u{22D7}"), - (b"gtlPar", "\u{2995}"), - (b"gtquest", "\u{2A7C}"), - (b"gtrapprox", "\u{2A86}"), - (b"gtrarr", "\u{2978}"), - (b"gtrdot", "\u{22D7}"), - (b"gtreqless", "\u{22DB}"), - (b"gtreqqless", "\u{2A8C}"), - (b"gtrless", "\u{2277}"), - (b"gtrsim", "\u{2273}"), - (b"gvertneqq", "\u{2269}\u{FE00}"), - (b"gvnE", "\u{2269}\u{FE00}"), - (b"hArr", "\u{21D4}"), - (b"hairsp", "\u{200A}"), - (b"half", "\u{00BD}"), - (b"hamilt", "\u{210B}"), - (b"hardcy", "\u{044A}"), - (b"harr", "\u{2194}"), - (b"harrcir", "\u{2948}"), - (b"harrw", "\u{21AD}"), - (b"hbar", "\u{210F}"), - (b"hcirc", "\u{0125}"), - (b"hearts", "\u{2665}"), - (b"heartsuit", "\u{2665}"), - (b"hellip", "\u{2026}"), - (b"hercon", "\u{22B9}"), - (b"hfr", "\u{1D525}"), - (b"hksearow", "\u{2925}"), - (b"hkswarow", "\u{2926}"), - (b"hoarr", "\u{21FF}"), - (b"homtht", "\u{223B}"), - (b"hookleftarrow", "\u{21A9}"), - (b"hookrightarrow", "\u{21AA}"), - (b"hopf", "\u{1D559}"), - (b"horbar", "\u{2015}"), - (b"hscr", "\u{1D4BD}"), - (b"hslash", "\u{210F}"), - (b"hstrok", "\u{0127}"), - (b"hybull", "\u{2043}"), - (b"hyphen", "\u{2010}"), - (b"iacute", "\u{00ED}"), - (b"ic", "\u{2063}"), - (b"icirc", "\u{00EE}"), - (b"icy", "\u{0438}"), - (b"iecy", "\u{0435}"), - (b"iexcl", "\u{00A1}"), - (b"iff", "\u{21D4}"), - (b"ifr", "\u{1D526}"), - (b"igrave", "\u{00EC}"), - (b"ii", "\u{2148}"), - (b"iiiint", "\u{2A0C}"), - (b"iiint", "\u{222D}"), - (b"iinfin", "\u{29DC}"), - (b"iiota", "\u{2129}"), - (b"ijlig", "\u{0133}"), - (b"imacr", "\u{012B}"), - (b"image", "\u{2111}"), - (b"imagline", "\u{2110}"), - (b"imagpart", "\u{2111}"), - (b"imath", "\u{0131}"), - (b"imof", "\u{22B7}"), - (b"imped", "\u{01B5}"), - (b"in", "\u{2208}"), - (b"incare", "\u{2105}"), - (b"infin", "\u{221E}"), - (b"infintie", "\u{29DD}"), - (b"inodot", "\u{0131}"), - (b"int", "\u{222B}"), - (b"intcal", "\u{22BA}"), - (b"integers", "\u{2124}"), - (b"intercal", "\u{22BA}"), - (b"intlarhk", "\u{2A17}"), - (b"intprod", "\u{2A3C}"), - (b"iocy", "\u{0451}"), - (b"iogon", "\u{012F}"), - (b"iopf", "\u{1D55A}"), - (b"iota", "\u{03B9}"), - (b"iprod", "\u{2A3C}"), - (b"iquest", "\u{00BF}"), - (b"iscr", "\u{1D4BE}"), - (b"isin", "\u{2208}"), - (b"isinE", "\u{22F9}"), - (b"isindot", "\u{22F5}"), - (b"isins", "\u{22F4}"), - (b"isinsv", "\u{22F3}"), - (b"isinv", "\u{2208}"), - (b"it", "\u{2062}"), - (b"itilde", "\u{0129}"), - (b"iukcy", "\u{0456}"), - (b"iuml", "\u{00EF}"), - (b"jcirc", "\u{0135}"), - (b"jcy", "\u{0439}"), - (b"jfr", "\u{1D527}"), - (b"jmath", "\u{0237}"), - (b"jopf", "\u{1D55B}"), - (b"jscr", "\u{1D4BF}"), - (b"jsercy", "\u{0458}"), - (b"jukcy", "\u{0454}"), - (b"kappa", "\u{03BA}"), - (b"kappav", "\u{03F0}"), - (b"kcedil", "\u{0137}"), - (b"kcy", "\u{043A}"), - (b"kfr", "\u{1D528}"), - (b"kgreen", "\u{0138}"), - (b"khcy", "\u{0445}"), - (b"kjcy", "\u{045C}"), - (b"kopf", "\u{1D55C}"), - (b"kscr", "\u{1D4C0}"), - (b"lAarr", "\u{21DA}"), - (b"lArr", "\u{21D0}"), - (b"lAtail", "\u{291B}"), - (b"lBarr", "\u{290E}"), - (b"lE", "\u{2266}"), - (b"lEg", "\u{2A8B}"), - (b"lHar", "\u{2962}"), - (b"lacute", "\u{013A}"), - (b"laemptyv", "\u{29B4}"), - (b"lagran", "\u{2112}"), - (b"lambda", "\u{03BB}"), - (b"lang", "\u{27E8}"), - (b"langd", "\u{2991}"), - (b"langle", "\u{27E8}"), - (b"lap", "\u{2A85}"), - (b"laquo", "\u{00AB}"), - (b"larr", "\u{2190}"), - (b"larrb", "\u{21E4}"), - (b"larrbfs", "\u{291F}"), - (b"larrfs", "\u{291D}"), - (b"larrhk", "\u{21A9}"), - (b"larrlp", "\u{21AB}"), - (b"larrpl", "\u{2939}"), - (b"larrsim", "\u{2973}"), - (b"larrtl", "\u{21A2}"), - (b"lat", "\u{2AAB}"), - (b"latail", "\u{2919}"), - (b"late", "\u{2AAD}"), - (b"lates", "\u{2AAD}\u{FE00}"), - (b"lbarr", "\u{290C}"), - (b"lbbrk", "\u{2772}"), - (b"lbrace", "\u{007B}"), - (b"lbrack", "\u{005B}"), - (b"lbrke", "\u{298B}"), - (b"lbrksld", "\u{298F}"), - (b"lbrkslu", "\u{298D}"), - (b"lcaron", "\u{013E}"), - (b"lcedil", "\u{013C}"), - (b"lceil", "\u{2308}"), - (b"lcub", "\u{007B}"), - (b"lcy", "\u{043B}"), - (b"ldca", "\u{2936}"), - (b"ldquo", "\u{201C}"), - (b"ldquor", "\u{201E}"), - (b"ldrdhar", "\u{2967}"), - (b"ldrushar", "\u{294B}"), - (b"ldsh", "\u{21B2}"), - (b"le", "\u{2264}"), - (b"leftarrow", "\u{2190}"), - (b"leftarrowtail", "\u{21A2}"), - (b"leftharpoondown", "\u{21BD}"), - (b"leftharpoonup", "\u{21BC}"), - (b"leftleftarrows", "\u{21C7}"), - (b"leftrightarrow", "\u{2194}"), - (b"leftrightarrows", "\u{21C6}"), - (b"leftrightharpoons", "\u{21CB}"), - (b"leftrightsquigarrow", "\u{21AD}"), - (b"leftthreetimes", "\u{22CB}"), - (b"leg", "\u{22DA}"), - (b"leq", "\u{2264}"), - (b"leqq", "\u{2266}"), - (b"leqslant", "\u{2A7D}"), - (b"les", "\u{2A7D}"), - (b"lescc", "\u{2AA8}"), - (b"lesdot", "\u{2A7F}"), - (b"lesdoto", "\u{2A81}"), - (b"lesdotor", "\u{2A83}"), - (b"lesg", "\u{22DA}\u{FE00}"), - (b"lesges", "\u{2A93}"), - (b"lessapprox", "\u{2A85}"), - (b"lessdot", "\u{22D6}"), - (b"lesseqgtr", "\u{22DA}"), - (b"lesseqqgtr", "\u{2A8B}"), - (b"lessgtr", "\u{2276}"), - (b"lesssim", "\u{2272}"), - (b"lfisht", "\u{297C}"), - (b"lfloor", "\u{230A}"), - (b"lfr", "\u{1D529}"), - (b"lg", "\u{2276}"), - (b"lgE", "\u{2A91}"), - (b"lhard", "\u{21BD}"), - (b"lharu", "\u{21BC}"), - (b"lharul", "\u{296A}"), - (b"lhblk", "\u{2584}"), - (b"ljcy", "\u{0459}"), - (b"ll", "\u{226A}"), - (b"llarr", "\u{21C7}"), - (b"llcorner", "\u{231E}"), - (b"llhard", "\u{296B}"), - (b"lltri", "\u{25FA}"), - (b"lmidot", "\u{0140}"), - (b"lmoust", "\u{23B0}"), - (b"lmoustache", "\u{23B0}"), - (b"lnE", "\u{2268}"), - (b"lnap", "\u{2A89}"), - (b"lnapprox", "\u{2A89}"), - (b"lne", "\u{2A87}"), - (b"lneq", "\u{2A87}"), - (b"lneqq", "\u{2268}"), - (b"lnsim", "\u{22E6}"), - (b"loang", "\u{27EC}"), - (b"loarr", "\u{21FD}"), - (b"lobrk", "\u{27E6}"), - (b"longleftarrow", "\u{27F5}"), - (b"longleftrightarrow", "\u{27F7}"), - (b"longmapsto", "\u{27FC}"), - (b"longrightarrow", "\u{27F6}"), - (b"looparrowleft", "\u{21AB}"), - (b"looparrowright", "\u{21AC}"), - (b"lopar", "\u{2985}"), - (b"lopf", "\u{1D55D}"), - (b"loplus", "\u{2A2D}"), - (b"lotimes", "\u{2A34}"), - (b"lowast", "\u{2217}"), - (b"lowbar", "\u{005F}"), - (b"loz", "\u{25CA}"), - (b"lozenge", "\u{25CA}"), - (b"lozf", "\u{29EB}"), - (b"lpar", "\u{0028}"), - (b"lparlt", "\u{2993}"), - (b"lrarr", "\u{21C6}"), - (b"lrcorner", "\u{231F}"), - (b"lrhar", "\u{21CB}"), - (b"lrhard", "\u{296D}"), - (b"lrm", "\u{200E}"), - (b"lrtri", "\u{22BF}"), - (b"lsaquo", "\u{2039}"), - (b"lscr", "\u{1D4C1}"), - (b"lsh", "\u{21B0}"), - (b"lsim", "\u{2272}"), - (b"lsime", "\u{2A8D}"), - (b"lsimg", "\u{2A8F}"), - (b"lsqb", "\u{005B}"), - (b"lsquo", "\u{2018}"), - (b"lsquor", "\u{201A}"), - (b"lstrok", "\u{0142}"), - (b"lt", "\u{003C}"), - (b"ltcc", "\u{2AA6}"), - (b"ltcir", "\u{2A79}"), - (b"ltdot", "\u{22D6}"), - (b"lthree", "\u{22CB}"), - (b"ltimes", "\u{22C9}"), - (b"ltlarr", "\u{2976}"), - (b"ltquest", "\u{2A7B}"), - (b"ltrPar", "\u{2996}"), - (b"ltri", "\u{25C3}"), - (b"ltrie", "\u{22B4}"), - (b"ltrif", "\u{25C2}"), - (b"lurdshar", "\u{294A}"), - (b"luruhar", "\u{2966}"), - (b"lvertneqq", "\u{2268}\u{FE00}"), - (b"lvnE", "\u{2268}\u{FE00}"), - (b"mDDot", "\u{223A}"), - (b"macr", "\u{00AF}"), - (b"male", "\u{2642}"), - (b"malt", "\u{2720}"), - (b"maltese", "\u{2720}"), - (b"map", "\u{21A6}"), - (b"mapsto", "\u{21A6}"), - (b"mapstodown", "\u{21A7}"), - (b"mapstoleft", "\u{21A4}"), - (b"mapstoup", "\u{21A5}"), - (b"marker", "\u{25AE}"), - (b"mcomma", "\u{2A29}"), - (b"mcy", "\u{043C}"), - (b"mdash", "\u{2014}"), - (b"measuredangle", "\u{2221}"), - (b"mfr", "\u{1D52A}"), - (b"mho", "\u{2127}"), - (b"micro", "\u{00B5}"), - (b"mid", "\u{2223}"), - (b"midast", "\u{002A}"), - (b"midcir", "\u{2AF0}"), - (b"middot", "\u{00B7}"), - (b"minus", "\u{2212}"), - (b"minusb", "\u{229F}"), - (b"minusd", "\u{2238}"), - (b"minusdu", "\u{2A2A}"), - (b"mlcp", "\u{2ADB}"), - (b"mldr", "\u{2026}"), - (b"mnplus", "\u{2213}"), - (b"models", "\u{22A7}"), - (b"mopf", "\u{1D55E}"), - (b"mp", "\u{2213}"), - (b"mscr", "\u{1D4C2}"), - (b"mstpos", "\u{223E}"), - (b"mu", "\u{03BC}"), - (b"multimap", "\u{22B8}"), - (b"mumap", "\u{22B8}"), - (b"nGg", "\u{22D9}\u{0338}"), - (b"nGt", "\u{226B}\u{20D2}"), - (b"nGtv", "\u{226B}\u{0338}"), - (b"nLeftarrow", "\u{21CD}"), - (b"nLeftrightarrow", "\u{21CE}"), - (b"nLl", "\u{22D8}\u{0338}"), - (b"nLt", "\u{226A}\u{20D2}"), - (b"nLtv", "\u{226A}\u{0338}"), - (b"nRightarrow", "\u{21CF}"), - (b"nVDash", "\u{22AF}"), - (b"nVdash", "\u{22AE}"), - (b"nabla", "\u{2207}"), - (b"nacute", "\u{0144}"), - (b"nang", "\u{2220}\u{20D2}"), - (b"nap", "\u{2249}"), - (b"napE", "\u{2A70}\u{0338}"), - (b"napid", "\u{224B}\u{0338}"), - (b"napos", "\u{0149}"), - (b"napprox", "\u{2249}"), - (b"natur", "\u{266E}"), - (b"natural", "\u{266E}"), - (b"naturals", "\u{2115}"), - (b"nbsp", "\u{00A0}"), - (b"nbump", "\u{224E}\u{0338}"), - (b"nbumpe", "\u{224F}\u{0338}"), - (b"ncap", "\u{2A43}"), - (b"ncaron", "\u{0148}"), - (b"ncedil", "\u{0146}"), - (b"ncong", "\u{2247}"), - (b"ncongdot", "\u{2A6D}\u{0338}"), - (b"ncup", "\u{2A42}"), - (b"ncy", "\u{043D}"), - (b"ndash", "\u{2013}"), - (b"ne", "\u{2260}"), - (b"neArr", "\u{21D7}"), - (b"nearhk", "\u{2924}"), - (b"nearr", "\u{2197}"), - (b"nearrow", "\u{2197}"), - (b"nedot", "\u{2250}\u{0338}"), - (b"nequiv", "\u{2262}"), - (b"nesear", "\u{2928}"), - (b"nesim", "\u{2242}\u{0338}"), - (b"nexist", "\u{2204}"), - (b"nexists", "\u{2204}"), - (b"nfr", "\u{1D52B}"), - (b"ngE", "\u{2267}\u{0338}"), - (b"nge", "\u{2271}"), - (b"ngeq", "\u{2271}"), - (b"ngeqq", "\u{2267}\u{0338}"), - (b"ngeqslant", "\u{2A7E}\u{0338}"), - (b"nges", "\u{2A7E}\u{0338}"), - (b"ngsim", "\u{2275}"), - (b"ngt", "\u{226F}"), - (b"ngtr", "\u{226F}"), - (b"nhArr", "\u{21CE}"), - (b"nharr", "\u{21AE}"), - (b"nhpar", "\u{2AF2}"), - (b"ni", "\u{220B}"), - (b"nis", "\u{22FC}"), - (b"nisd", "\u{22FA}"), - (b"niv", "\u{220B}"), - (b"njcy", "\u{045A}"), - (b"nlArr", "\u{21CD}"), - (b"nlE", "\u{2266}\u{0338}"), - (b"nlarr", "\u{219A}"), - (b"nldr", "\u{2025}"), - (b"nle", "\u{2270}"), - (b"nleftarrow", "\u{219A}"), - (b"nleftrightarrow", "\u{21AE}"), - (b"nleq", "\u{2270}"), - (b"nleqq", "\u{2266}\u{0338}"), - (b"nleqslant", "\u{2A7D}\u{0338}"), - (b"nles", "\u{2A7D}\u{0338}"), - (b"nless", "\u{226E}"), - (b"nlsim", "\u{2274}"), - (b"nlt", "\u{226E}"), - (b"nltri", "\u{22EA}"), - (b"nltrie", "\u{22EC}"), - (b"nmid", "\u{2224}"), - (b"nopf", "\u{1D55F}"), - (b"not", "\u{00AC}"), - (b"notin", "\u{2209}"), - (b"notinE", "\u{22F9}\u{0338}"), - (b"notindot", "\u{22F5}\u{0338}"), - (b"notinva", "\u{2209}"), - (b"notinvb", "\u{22F7}"), - (b"notinvc", "\u{22F6}"), - (b"notni", "\u{220C}"), - (b"notniva", "\u{220C}"), - (b"notnivb", "\u{22FE}"), - (b"notnivc", "\u{22FD}"), - (b"npar", "\u{2226}"), - (b"nparallel", "\u{2226}"), - (b"nparsl", "\u{2AFD}\u{20E5}"), - (b"npart", "\u{2202}\u{0338}"), - (b"npolint", "\u{2A14}"), - (b"npr", "\u{2280}"), - (b"nprcue", "\u{22E0}"), - (b"npre", "\u{2AAF}\u{0338}"), - (b"nprec", "\u{2280}"), - (b"npreceq", "\u{2AAF}\u{0338}"), - (b"nrArr", "\u{21CF}"), - (b"nrarr", "\u{219B}"), - (b"nrarrc", "\u{2933}\u{0338}"), - (b"nrarrw", "\u{219D}\u{0338}"), - (b"nrightarrow", "\u{219B}"), - (b"nrtri", "\u{22EB}"), - (b"nrtrie", "\u{22ED}"), - (b"nsc", "\u{2281}"), - (b"nsccue", "\u{22E1}"), - (b"nsce", "\u{2AB0}\u{0338}"), - (b"nscr", "\u{1D4C3}"), - (b"nshortmid", "\u{2224}"), - (b"nshortparallel", "\u{2226}"), - (b"nsim", "\u{2241}"), - (b"nsime", "\u{2244}"), - (b"nsimeq", "\u{2244}"), - (b"nsmid", "\u{2224}"), - (b"nspar", "\u{2226}"), - (b"nsqsube", "\u{22E2}"), - (b"nsqsupe", "\u{22E3}"), - (b"nsub", "\u{2284}"), - (b"nsubE", "\u{2AC5}\u{0338}"), - (b"nsube", "\u{2288}"), - (b"nsubset", "\u{2282}\u{20D2}"), - (b"nsubseteq", "\u{2288}"), - (b"nsubseteqq", "\u{2AC5}\u{0338}"), - (b"nsucc", "\u{2281}"), - (b"nsucceq", "\u{2AB0}\u{0338}"), - (b"nsup", "\u{2285}"), - (b"nsupE", "\u{2AC6}\u{0338}"), - (b"nsupe", "\u{2289}"), - (b"nsupset", "\u{2283}\u{20D2}"), - (b"nsupseteq", "\u{2289}"), - (b"nsupseteqq", "\u{2AC6}\u{0338}"), - (b"ntgl", "\u{2279}"), - (b"ntilde", "\u{00F1}"), - (b"ntlg", "\u{2278}"), - (b"ntriangleleft", "\u{22EA}"), - (b"ntrianglelefteq", "\u{22EC}"), - (b"ntriangleright", "\u{22EB}"), - (b"ntrianglerighteq", "\u{22ED}"), - (b"nu", "\u{03BD}"), - (b"num", "\u{0023}"), - (b"numero", "\u{2116}"), - (b"numsp", "\u{2007}"), - (b"nvDash", "\u{22AD}"), - (b"nvHarr", "\u{2904}"), - (b"nvap", "\u{224D}\u{20D2}"), - (b"nvdash", "\u{22AC}"), - (b"nvge", "\u{2265}\u{20D2}"), - (b"nvgt", "\u{003E}\u{20D2}"), - (b"nvinfin", "\u{29DE}"), - (b"nvlArr", "\u{2902}"), - (b"nvle", "\u{2264}\u{20D2}"), - (b"nvlt", "\u{003C}\u{20D2}"), - (b"nvltrie", "\u{22B4}\u{20D2}"), - (b"nvrArr", "\u{2903}"), - (b"nvrtrie", "\u{22B5}\u{20D2}"), - (b"nvsim", "\u{223C}\u{20D2}"), - (b"nwArr", "\u{21D6}"), - (b"nwarhk", "\u{2923}"), - (b"nwarr", "\u{2196}"), - (b"nwarrow", "\u{2196}"), - (b"nwnear", "\u{2927}"), - (b"oS", "\u{24C8}"), - (b"oacute", "\u{00F3}"), - (b"oast", "\u{229B}"), - (b"ocir", "\u{229A}"), - (b"ocirc", "\u{00F4}"), - (b"ocy", "\u{043E}"), - (b"odash", "\u{229D}"), - (b"odblac", "\u{0151}"), - (b"odiv", "\u{2A38}"), - (b"odot", "\u{2299}"), - (b"odsold", "\u{29BC}"), - (b"oelig", "\u{0153}"), - (b"ofcir", "\u{29BF}"), - (b"ofr", "\u{1D52C}"), - (b"ogon", "\u{02DB}"), - (b"ograve", "\u{00F2}"), - (b"ogt", "\u{29C1}"), - (b"ohbar", "\u{29B5}"), - (b"ohm", "\u{03A9}"), - (b"oint", "\u{222E}"), - (b"olarr", "\u{21BA}"), - (b"olcir", "\u{29BE}"), - (b"olcross", "\u{29BB}"), - (b"oline", "\u{203E}"), - (b"olt", "\u{29C0}"), - (b"omacr", "\u{014D}"), - (b"omega", "\u{03C9}"), - (b"omicron", "\u{03BF}"), - (b"omid", "\u{29B6}"), - (b"ominus", "\u{2296}"), - (b"oopf", "\u{1D560}"), - (b"opar", "\u{29B7}"), - (b"operp", "\u{29B9}"), - (b"oplus", "\u{2295}"), - (b"or", "\u{2228}"), - (b"orarr", "\u{21BB}"), - (b"ord", "\u{2A5D}"), - (b"order", "\u{2134}"), - (b"orderof", "\u{2134}"), - (b"ordf", "\u{00AA}"), - (b"ordm", "\u{00BA}"), - (b"origof", "\u{22B6}"), - (b"oror", "\u{2A56}"), - (b"orslope", "\u{2A57}"), - (b"orv", "\u{2A5B}"), - (b"oscr", "\u{2134}"), - (b"oslash", "\u{00F8}"), - (b"osol", "\u{2298}"), - (b"otilde", "\u{00F5}"), - (b"otimes", "\u{2297}"), - (b"otimesas", "\u{2A36}"), - (b"ouml", "\u{00F6}"), - (b"ovbar", "\u{233D}"), - (b"par", "\u{2225}"), - (b"para", "\u{00B6}"), - (b"parallel", "\u{2225}"), - (b"parsim", "\u{2AF3}"), - (b"parsl", "\u{2AFD}"), - (b"part", "\u{2202}"), - (b"pcy", "\u{043F}"), - (b"percnt", "\u{0025}"), - (b"period", "\u{002E}"), - (b"permil", "\u{2030}"), - (b"perp", "\u{22A5}"), - (b"pertenk", "\u{2031}"), - (b"pfr", "\u{1D52D}"), - (b"phi", "\u{03C6}"), - (b"phiv", "\u{03D5}"), - (b"phmmat", "\u{2133}"), - (b"phone", "\u{260E}"), - (b"pi", "\u{03C0}"), - (b"pitchfork", "\u{22D4}"), - (b"piv", "\u{03D6}"), - (b"planck", "\u{210F}"), - (b"planckh", "\u{210E}"), - (b"plankv", "\u{210F}"), - (b"plus", "\u{002B}"), - (b"plusacir", "\u{2A23}"), - (b"plusb", "\u{229E}"), - (b"pluscir", "\u{2A22}"), - (b"plusdo", "\u{2214}"), - (b"plusdu", "\u{2A25}"), - (b"pluse", "\u{2A72}"), - (b"plusmn", "\u{00B1}"), - (b"plussim", "\u{2A26}"), - (b"plustwo", "\u{2A27}"), - (b"pm", "\u{00B1}"), - (b"pointint", "\u{2A15}"), - (b"popf", "\u{1D561}"), - (b"pound", "\u{00A3}"), - (b"pr", "\u{227A}"), - (b"prE", "\u{2AB3}"), - (b"prap", "\u{2AB7}"), - (b"prcue", "\u{227C}"), - (b"pre", "\u{2AAF}"), - (b"prec", "\u{227A}"), - (b"precapprox", "\u{2AB7}"), - (b"preccurlyeq", "\u{227C}"), - (b"preceq", "\u{2AAF}"), - (b"precnapprox", "\u{2AB9}"), - (b"precneqq", "\u{2AB5}"), - (b"precnsim", "\u{22E8}"), - (b"precsim", "\u{227E}"), - (b"prime", "\u{2032}"), - (b"primes", "\u{2119}"), - (b"prnE", "\u{2AB5}"), - (b"prnap", "\u{2AB9}"), - (b"prnsim", "\u{22E8}"), - (b"prod", "\u{220F}"), - (b"profalar", "\u{232E}"), - (b"profline", "\u{2312}"), - (b"profsurf", "\u{2313}"), - (b"prop", "\u{221D}"), - (b"propto", "\u{221D}"), - (b"prsim", "\u{227E}"), - (b"prurel", "\u{22B0}"), - (b"pscr", "\u{1D4C5}"), - (b"psi", "\u{03C8}"), - (b"puncsp", "\u{2008}"), - (b"qfr", "\u{1D52E}"), - (b"qint", "\u{2A0C}"), - (b"qopf", "\u{1D562}"), - (b"qprime", "\u{2057}"), - (b"qscr", "\u{1D4C6}"), - (b"quaternions", "\u{210D}"), - (b"quatint", "\u{2A16}"), - (b"quest", "\u{003F}"), - (b"questeq", "\u{225F}"), - (b"quot", "\u{0022}"), - (b"rAarr", "\u{21DB}"), - (b"rArr", "\u{21D2}"), - (b"rAtail", "\u{291C}"), - (b"rBarr", "\u{290F}"), - (b"rHar", "\u{2964}"), - (b"race", "\u{223D}\u{0331}"), - (b"racute", "\u{0155}"), - (b"radic", "\u{221A}"), - (b"raemptyv", "\u{29B3}"), - (b"rang", "\u{27E9}"), - (b"rangd", "\u{2992}"), - (b"range", "\u{29A5}"), - (b"rangle", "\u{27E9}"), - (b"raquo", "\u{00BB}"), - (b"rarr", "\u{2192}"), - (b"rarrap", "\u{2975}"), - (b"rarrb", "\u{21E5}"), - (b"rarrbfs", "\u{2920}"), - (b"rarrc", "\u{2933}"), - (b"rarrfs", "\u{291E}"), - (b"rarrhk", "\u{21AA}"), - (b"rarrlp", "\u{21AC}"), - (b"rarrpl", "\u{2945}"), - (b"rarrsim", "\u{2974}"), - (b"rarrtl", "\u{21A3}"), - (b"rarrw", "\u{219D}"), - (b"ratail", "\u{291A}"), - (b"ratio", "\u{2236}"), - (b"rationals", "\u{211A}"), - (b"rbarr", "\u{290D}"), - (b"rbbrk", "\u{2773}"), - (b"rbrace", "\u{007D}"), - (b"rbrack", "\u{005D}"), - (b"rbrke", "\u{298C}"), - (b"rbrksld", "\u{298E}"), - (b"rbrkslu", "\u{2990}"), - (b"rcaron", "\u{0159}"), - (b"rcedil", "\u{0157}"), - (b"rceil", "\u{2309}"), - (b"rcub", "\u{007D}"), - (b"rcy", "\u{0440}"), - (b"rdca", "\u{2937}"), - (b"rdldhar", "\u{2969}"), - (b"rdquo", "\u{201D}"), - (b"rdquor", "\u{201D}"), - (b"rdsh", "\u{21B3}"), - (b"real", "\u{211C}"), - (b"realine", "\u{211B}"), - (b"realpart", "\u{211C}"), - (b"reals", "\u{211D}"), - (b"rect", "\u{25AD}"), - (b"reg", "\u{00AE}"), - (b"rfisht", "\u{297D}"), - (b"rfloor", "\u{230B}"), - (b"rfr", "\u{1D52F}"), - (b"rhard", "\u{21C1}"), - (b"rharu", "\u{21C0}"), - (b"rharul", "\u{296C}"), - (b"rho", "\u{03C1}"), - (b"rhov", "\u{03F1}"), - (b"rightarrow", "\u{2192}"), - (b"rightarrowtail", "\u{21A3}"), - (b"rightharpoondown", "\u{21C1}"), - (b"rightharpoonup", "\u{21C0}"), - (b"rightleftarrows", "\u{21C4}"), - (b"rightleftharpoons", "\u{21CC}"), - (b"rightrightarrows", "\u{21C9}"), - (b"rightsquigarrow", "\u{219D}"), - (b"rightthreetimes", "\u{22CC}"), - (b"ring", "\u{02DA}"), - (b"risingdotseq", "\u{2253}"), - (b"rlarr", "\u{21C4}"), - (b"rlhar", "\u{21CC}"), - (b"rlm", "\u{200F}"), - (b"rmoust", "\u{23B1}"), - (b"rmoustache", "\u{23B1}"), - (b"rnmid", "\u{2AEE}"), - (b"roang", "\u{27ED}"), - (b"roarr", "\u{21FE}"), - (b"robrk", "\u{27E7}"), - (b"ropar", "\u{2986}"), - (b"ropf", "\u{1D563}"), - (b"roplus", "\u{2A2E}"), - (b"rotimes", "\u{2A35}"), - (b"rpar", "\u{0029}"), - (b"rpargt", "\u{2994}"), - (b"rppolint", "\u{2A12}"), - (b"rrarr", "\u{21C9}"), - (b"rsaquo", "\u{203A}"), - (b"rscr", "\u{1D4C7}"), - (b"rsh", "\u{21B1}"), - (b"rsqb", "\u{005D}"), - (b"rsquo", "\u{2019}"), - (b"rsquor", "\u{2019}"), - (b"rthree", "\u{22CC}"), - (b"rtimes", "\u{22CA}"), - (b"rtri", "\u{25B9}"), - (b"rtrie", "\u{22B5}"), - (b"rtrif", "\u{25B8}"), - (b"rtriltri", "\u{29CE}"), - (b"ruluhar", "\u{2968}"), - (b"rx", "\u{211E}"), - (b"sacute", "\u{015B}"), - (b"sbquo", "\u{201A}"), - (b"sc", "\u{227B}"), - (b"scE", "\u{2AB4}"), - (b"scap", "\u{2AB8}"), - (b"scaron", "\u{0161}"), - (b"sccue", "\u{227D}"), - (b"sce", "\u{2AB0}"), - (b"scedil", "\u{015F}"), - (b"scirc", "\u{015D}"), - (b"scnE", "\u{2AB6}"), - (b"scnap", "\u{2ABA}"), - (b"scnsim", "\u{22E9}"), - (b"scpolint", "\u{2A13}"), - (b"scsim", "\u{227F}"), - (b"scy", "\u{0441}"), - (b"sdot", "\u{22C5}"), - (b"sdotb", "\u{22A1}"), - (b"sdote", "\u{2A66}"), - (b"seArr", "\u{21D8}"), - (b"searhk", "\u{2925}"), - (b"searr", "\u{2198}"), - (b"searrow", "\u{2198}"), - (b"sect", "\u{00A7}"), - (b"semi", "\u{003B}"), - (b"seswar", "\u{2929}"), - (b"setminus", "\u{2216}"), - (b"setmn", "\u{2216}"), - (b"sext", "\u{2736}"), - (b"sfr", "\u{1D530}"), - (b"sfrown", "\u{2322}"), - (b"sharp", "\u{266F}"), - (b"shchcy", "\u{0449}"), - (b"shcy", "\u{0448}"), - (b"shortmid", "\u{2223}"), - (b"shortparallel", "\u{2225}"), - (b"shy", "\u{00AD}"), - (b"sigma", "\u{03C3}"), - (b"sigmaf", "\u{03C2}"), - (b"sigmav", "\u{03C2}"), - (b"sim", "\u{223C}"), - (b"simdot", "\u{2A6A}"), - (b"sime", "\u{2243}"), - (b"simeq", "\u{2243}"), - (b"simg", "\u{2A9E}"), - (b"simgE", "\u{2AA0}"), - (b"siml", "\u{2A9D}"), - (b"simlE", "\u{2A9F}"), - (b"simne", "\u{2246}"), - (b"simplus", "\u{2A24}"), - (b"simrarr", "\u{2972}"), - (b"slarr", "\u{2190}"), - (b"smallsetminus", "\u{2216}"), - (b"smashp", "\u{2A33}"), - (b"smeparsl", "\u{29E4}"), - (b"smid", "\u{2223}"), - (b"smile", "\u{2323}"), - (b"smt", "\u{2AAA}"), - (b"smte", "\u{2AAC}"), - (b"smtes", "\u{2AAC}\u{FE00}"), - (b"softcy", "\u{044C}"), - (b"sol", "\u{002F}"), - (b"solb", "\u{29C4}"), - (b"solbar", "\u{233F}"), - (b"sopf", "\u{1D564}"), - (b"spades", "\u{2660}"), - (b"spadesuit", "\u{2660}"), - (b"spar", "\u{2225}"), - (b"sqcap", "\u{2293}"), - (b"sqcaps", "\u{2293}\u{FE00}"), - (b"sqcup", "\u{2294}"), - (b"sqcups", "\u{2294}\u{FE00}"), - (b"sqsub", "\u{228F}"), - (b"sqsube", "\u{2291}"), - (b"sqsubset", "\u{228F}"), - (b"sqsubseteq", "\u{2291}"), - (b"sqsup", "\u{2290}"), - (b"sqsupe", "\u{2292}"), - (b"sqsupset", "\u{2290}"), - (b"sqsupseteq", "\u{2292}"), - (b"squ", "\u{25A1}"), - (b"square", "\u{25A1}"), - (b"squarf", "\u{25AA}"), - (b"squf", "\u{25AA}"), - (b"srarr", "\u{2192}"), - (b"sscr", "\u{1D4C8}"), - (b"ssetmn", "\u{2216}"), - (b"ssmile", "\u{2323}"), - (b"sstarf", "\u{22C6}"), - (b"star", "\u{2606}"), - (b"starf", "\u{2605}"), - (b"straightepsilon", "\u{03F5}"), - (b"straightphi", "\u{03D5}"), - (b"strns", "\u{00AF}"), - (b"sub", "\u{2282}"), - (b"subE", "\u{2AC5}"), - (b"subdot", "\u{2ABD}"), - (b"sube", "\u{2286}"), - (b"subedot", "\u{2AC3}"), - (b"submult", "\u{2AC1}"), - (b"subnE", "\u{2ACB}"), - (b"subne", "\u{228A}"), - (b"subplus", "\u{2ABF}"), - (b"subrarr", "\u{2979}"), - (b"subset", "\u{2282}"), - (b"subseteq", "\u{2286}"), - (b"subseteqq", "\u{2AC5}"), - (b"subsetneq", "\u{228A}"), - (b"subsetneqq", "\u{2ACB}"), - (b"subsim", "\u{2AC7}"), - (b"subsub", "\u{2AD5}"), - (b"subsup", "\u{2AD3}"), - (b"succ", "\u{227B}"), - (b"succapprox", "\u{2AB8}"), - (b"succcurlyeq", "\u{227D}"), - (b"succeq", "\u{2AB0}"), - (b"succnapprox", "\u{2ABA}"), - (b"succneqq", "\u{2AB6}"), - (b"succnsim", "\u{22E9}"), - (b"succsim", "\u{227F}"), - (b"sum", "\u{2211}"), - (b"sung", "\u{266A}"), - (b"sup", "\u{2283}"), - (b"sup1", "\u{00B9}"), - (b"sup2", "\u{00B2}"), - (b"sup3", "\u{00B3}"), - (b"supE", "\u{2AC6}"), - (b"supdot", "\u{2ABE}"), - (b"supdsub", "\u{2AD8}"), - (b"supe", "\u{2287}"), - (b"supedot", "\u{2AC4}"), - (b"suphsol", "\u{27C9}"), - (b"suphsub", "\u{2AD7}"), - (b"suplarr", "\u{297B}"), - (b"supmult", "\u{2AC2}"), - (b"supnE", "\u{2ACC}"), - (b"supne", "\u{228B}"), - (b"supplus", "\u{2AC0}"), - (b"supset", "\u{2283}"), - (b"supseteq", "\u{2287}"), - (b"supseteqq", "\u{2AC6}"), - (b"supsetneq", "\u{228B}"), - (b"supsetneqq", "\u{2ACC}"), - (b"supsim", "\u{2AC8}"), - (b"supsub", "\u{2AD4}"), - (b"supsup", "\u{2AD6}"), - (b"swArr", "\u{21D9}"), - (b"swarhk", "\u{2926}"), - (b"swarr", "\u{2199}"), - (b"swarrow", "\u{2199}"), - (b"swnwar", "\u{292A}"), - (b"szlig", "\u{00DF}"), - (b"target", "\u{2316}"), - (b"tau", "\u{03C4}"), - (b"tbrk", "\u{23B4}"), - (b"tcaron", "\u{0165}"), - (b"tcedil", "\u{0163}"), - (b"tcy", "\u{0442}"), - (b"tdot", "\u{20DB}"), - (b"telrec", "\u{2315}"), - (b"tfr", "\u{1D531}"), - (b"there4", "\u{2234}"), - (b"therefore", "\u{2234}"), - (b"theta", "\u{03B8}"), - (b"thetasym", "\u{03D1}"), - (b"thetav", "\u{03D1}"), - (b"thickapprox", "\u{2248}"), - (b"thicksim", "\u{223C}"), - (b"thinsp", "\u{2009}"), - (b"thkap", "\u{2248}"), - (b"thksim", "\u{223C}"), - (b"thorn", "\u{00FE}"), - (b"tilde", "\u{02DC}"), - (b"times", "\u{00D7}"), - (b"timesb", "\u{22A0}"), - (b"timesbar", "\u{2A31}"), - (b"timesd", "\u{2A30}"), - (b"tint", "\u{222D}"), - (b"toea", "\u{2928}"), - (b"top", "\u{22A4}"), - (b"topbot", "\u{2336}"), - (b"topcir", "\u{2AF1}"), - (b"topf", "\u{1D565}"), - (b"topfork", "\u{2ADA}"), - (b"tosa", "\u{2929}"), - (b"tprime", "\u{2034}"), - (b"trade", "\u{2122}"), - (b"triangle", "\u{25B5}"), - (b"triangledown", "\u{25BF}"), - (b"triangleleft", "\u{25C3}"), - (b"trianglelefteq", "\u{22B4}"), - (b"triangleq", "\u{225C}"), - (b"triangleright", "\u{25B9}"), - (b"trianglerighteq", "\u{22B5}"), - (b"tridot", "\u{25EC}"), - (b"trie", "\u{225C}"), - (b"triminus", "\u{2A3A}"), - (b"triplus", "\u{2A39}"), - (b"trisb", "\u{29CD}"), - (b"tritime", "\u{2A3B}"), - (b"trpezium", "\u{23E2}"), - (b"tscr", "\u{1D4C9}"), - (b"tscy", "\u{0446}"), - (b"tshcy", "\u{045B}"), - (b"tstrok", "\u{0167}"), - (b"twixt", "\u{226C}"), - (b"twoheadleftarrow", "\u{219E}"), - (b"twoheadrightarrow", "\u{21A0}"), - (b"uArr", "\u{21D1}"), - (b"uHar", "\u{2963}"), - (b"uacute", "\u{00FA}"), - (b"uarr", "\u{2191}"), - (b"ubrcy", "\u{045E}"), - (b"ubreve", "\u{016D}"), - (b"ucirc", "\u{00FB}"), - (b"ucy", "\u{0443}"), - (b"udarr", "\u{21C5}"), - (b"udblac", "\u{0171}"), - (b"udhar", "\u{296E}"), - (b"ufisht", "\u{297E}"), - (b"ufr", "\u{1D532}"), - (b"ugrave", "\u{00F9}"), - (b"uharl", "\u{21BF}"), - (b"uharr", "\u{21BE}"), - (b"uhblk", "\u{2580}"), - (b"ulcorn", "\u{231C}"), - (b"ulcorner", "\u{231C}"), - (b"ulcrop", "\u{230F}"), - (b"ultri", "\u{25F8}"), - (b"umacr", "\u{016B}"), - (b"uml", "\u{00A8}"), - (b"uogon", "\u{0173}"), - (b"uopf", "\u{1D566}"), - (b"uparrow", "\u{2191}"), - (b"updownarrow", "\u{2195}"), - (b"upharpoonleft", "\u{21BF}"), - (b"upharpoonright", "\u{21BE}"), - (b"uplus", "\u{228E}"), - (b"upsi", "\u{03C5}"), - (b"upsih", "\u{03D2}"), - (b"upsilon", "\u{03C5}"), - (b"upuparrows", "\u{21C8}"), - (b"urcorn", "\u{231D}"), - (b"urcorner", "\u{231D}"), - (b"urcrop", "\u{230E}"), - (b"uring", "\u{016F}"), - (b"urtri", "\u{25F9}"), - (b"uscr", "\u{1D4CA}"), - (b"utdot", "\u{22F0}"), - (b"utilde", "\u{0169}"), - (b"utri", "\u{25B5}"), - (b"utrif", "\u{25B4}"), - (b"uuarr", "\u{21C8}"), - (b"uuml", "\u{00FC}"), - (b"uwangle", "\u{29A7}"), - (b"vArr", "\u{21D5}"), - (b"vBar", "\u{2AE8}"), - (b"vBarv", "\u{2AE9}"), - (b"vDash", "\u{22A8}"), - (b"vangrt", "\u{299C}"), - (b"varepsilon", "\u{03F5}"), - (b"varkappa", "\u{03F0}"), - (b"varnothing", "\u{2205}"), - (b"varphi", "\u{03D5}"), - (b"varpi", "\u{03D6}"), - (b"varpropto", "\u{221D}"), - (b"varr", "\u{2195}"), - (b"varrho", "\u{03F1}"), - (b"varsigma", "\u{03C2}"), - (b"varsubsetneq", "\u{228A}\u{FE00}"), - (b"varsubsetneqq", "\u{2ACB}\u{FE00}"), - (b"varsupsetneq", "\u{228B}\u{FE00}"), - (b"varsupsetneqq", "\u{2ACC}\u{FE00}"), - (b"vartheta", "\u{03D1}"), - (b"vartriangleleft", "\u{22B2}"), - (b"vartriangleright", "\u{22B3}"), - (b"vcy", "\u{0432}"), - (b"vdash", "\u{22A2}"), - (b"vee", "\u{2228}"), - (b"veebar", "\u{22BB}"), - (b"veeeq", "\u{225A}"), - (b"vellip", "\u{22EE}"), - (b"verbar", "\u{007C}"), - (b"vert", "\u{007C}"), - (b"vfr", "\u{1D533}"), - (b"vltri", "\u{22B2}"), - (b"vnsub", "\u{2282}\u{20D2}"), - (b"vnsup", "\u{2283}\u{20D2}"), - (b"vopf", "\u{1D567}"), - (b"vprop", "\u{221D}"), - (b"vrtri", "\u{22B3}"), - (b"vscr", "\u{1D4CB}"), - (b"vsubnE", "\u{2ACB}\u{FE00}"), - (b"vsubne", "\u{228A}\u{FE00}"), - (b"vsupnE", "\u{2ACC}\u{FE00}"), - (b"vsupne", "\u{228B}\u{FE00}"), - (b"vzigzag", "\u{299A}"), - (b"wcirc", "\u{0175}"), - (b"wedbar", "\u{2A5F}"), - (b"wedge", "\u{2227}"), - (b"wedgeq", "\u{2259}"), - (b"weierp", "\u{2118}"), - (b"wfr", "\u{1D534}"), - (b"wopf", "\u{1D568}"), - (b"wp", "\u{2118}"), - (b"wr", "\u{2240}"), - (b"wreath", "\u{2240}"), - (b"wscr", "\u{1D4CC}"), - (b"xcap", "\u{22C2}"), - (b"xcirc", "\u{25EF}"), - (b"xcup", "\u{22C3}"), - (b"xdtri", "\u{25BD}"), - (b"xfr", "\u{1D535}"), - (b"xhArr", "\u{27FA}"), - (b"xharr", "\u{27F7}"), - (b"xi", "\u{03BE}"), - (b"xlArr", "\u{27F8}"), - (b"xlarr", "\u{27F5}"), - (b"xmap", "\u{27FC}"), - (b"xnis", "\u{22FB}"), - (b"xodot", "\u{2A00}"), - (b"xopf", "\u{1D569}"), - (b"xoplus", "\u{2A01}"), - (b"xotime", "\u{2A02}"), - (b"xrArr", "\u{27F9}"), - (b"xrarr", "\u{27F6}"), - (b"xscr", "\u{1D4CD}"), - (b"xsqcup", "\u{2A06}"), - (b"xuplus", "\u{2A04}"), - (b"xutri", "\u{25B3}"), - (b"xvee", "\u{22C1}"), - (b"xwedge", "\u{22C0}"), - (b"yacute", "\u{00FD}"), - (b"yacy", "\u{044F}"), - (b"ycirc", "\u{0177}"), - (b"ycy", "\u{044B}"), - (b"yen", "\u{00A5}"), - (b"yfr", "\u{1D536}"), - (b"yicy", "\u{0457}"), - (b"yopf", "\u{1D56A}"), - (b"yscr", "\u{1D4CE}"), - (b"yucy", "\u{044E}"), - (b"yuml", "\u{00FF}"), - (b"zacute", "\u{017A}"), - (b"zcaron", "\u{017E}"), - (b"zcy", "\u{0437}"), - (b"zdot", "\u{017C}"), - (b"zeetrf", "\u{2128}"), - (b"zeta", "\u{03B6}"), - (b"zfr", "\u{1D537}"), - (b"zhcy", "\u{0436}"), - (b"zigrarr", "\u{21DD}"), - (b"zopf", "\u{1D56B}"), - (b"zscr", "\u{1D4CF}"), - (b"zwj", "\u{200D}"), - (b"zwnj", "\u{200C}"), -]; - -pub(crate) fn get_entity(bytes: &[u8]) -> Option<&'static str> { - ENTITIES - .binary_search_by_key(&bytes, |&(key, _value)| key) - .ok() - .map(|i| ENTITIES[i].1) -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Expansions of HTML5 entities + +// Autogenerated by mk_entities.py + +const ENTITIES: [(&[u8], &str); 2125] = [ + (b"AElig", "\u{00C6}"), + (b"AMP", "\u{0026}"), + (b"Aacute", "\u{00C1}"), + (b"Abreve", "\u{0102}"), + (b"Acirc", "\u{00C2}"), + (b"Acy", "\u{0410}"), + (b"Afr", "\u{1D504}"), + (b"Agrave", "\u{00C0}"), + (b"Alpha", "\u{0391}"), + (b"Amacr", "\u{0100}"), + (b"And", "\u{2A53}"), + (b"Aogon", "\u{0104}"), + (b"Aopf", "\u{1D538}"), + (b"ApplyFunction", "\u{2061}"), + (b"Aring", "\u{00C5}"), + (b"Ascr", "\u{1D49C}"), + (b"Assign", "\u{2254}"), + (b"Atilde", "\u{00C3}"), + (b"Auml", "\u{00C4}"), + (b"Backslash", "\u{2216}"), + (b"Barv", "\u{2AE7}"), + (b"Barwed", "\u{2306}"), + (b"Bcy", "\u{0411}"), + (b"Because", "\u{2235}"), + (b"Bernoullis", "\u{212C}"), + (b"Beta", "\u{0392}"), + (b"Bfr", "\u{1D505}"), + (b"Bopf", "\u{1D539}"), + (b"Breve", "\u{02D8}"), + (b"Bscr", "\u{212C}"), + (b"Bumpeq", "\u{224E}"), + (b"CHcy", "\u{0427}"), + (b"COPY", "\u{00A9}"), + (b"Cacute", "\u{0106}"), + (b"Cap", "\u{22D2}"), + (b"CapitalDifferentialD", "\u{2145}"), + (b"Cayleys", "\u{212D}"), + (b"Ccaron", "\u{010C}"), + (b"Ccedil", "\u{00C7}"), + (b"Ccirc", "\u{0108}"), + (b"Cconint", "\u{2230}"), + (b"Cdot", "\u{010A}"), + (b"Cedilla", "\u{00B8}"), + (b"CenterDot", "\u{00B7}"), + (b"Cfr", "\u{212D}"), + (b"Chi", "\u{03A7}"), + (b"CircleDot", "\u{2299}"), + (b"CircleMinus", "\u{2296}"), + (b"CirclePlus", "\u{2295}"), + (b"CircleTimes", "\u{2297}"), + (b"ClockwiseContourIntegral", "\u{2232}"), + (b"CloseCurlyDoubleQuote", "\u{201D}"), + (b"CloseCurlyQuote", "\u{2019}"), + (b"Colon", "\u{2237}"), + (b"Colone", "\u{2A74}"), + (b"Congruent", "\u{2261}"), + (b"Conint", "\u{222F}"), + (b"ContourIntegral", "\u{222E}"), + (b"Copf", "\u{2102}"), + (b"Coproduct", "\u{2210}"), + (b"CounterClockwiseContourIntegral", "\u{2233}"), + (b"Cross", "\u{2A2F}"), + (b"Cscr", "\u{1D49E}"), + (b"Cup", "\u{22D3}"), + (b"CupCap", "\u{224D}"), + (b"DD", "\u{2145}"), + (b"DDotrahd", "\u{2911}"), + (b"DJcy", "\u{0402}"), + (b"DScy", "\u{0405}"), + (b"DZcy", "\u{040F}"), + (b"Dagger", "\u{2021}"), + (b"Darr", "\u{21A1}"), + (b"Dashv", "\u{2AE4}"), + (b"Dcaron", "\u{010E}"), + (b"Dcy", "\u{0414}"), + (b"Del", "\u{2207}"), + (b"Delta", "\u{0394}"), + (b"Dfr", "\u{1D507}"), + (b"DiacriticalAcute", "\u{00B4}"), + (b"DiacriticalDot", "\u{02D9}"), + (b"DiacriticalDoubleAcute", "\u{02DD}"), + (b"DiacriticalGrave", "\u{0060}"), + (b"DiacriticalTilde", "\u{02DC}"), + (b"Diamond", "\u{22C4}"), + (b"DifferentialD", "\u{2146}"), + (b"Dopf", "\u{1D53B}"), + (b"Dot", "\u{00A8}"), + (b"DotDot", "\u{20DC}"), + (b"DotEqual", "\u{2250}"), + (b"DoubleContourIntegral", "\u{222F}"), + (b"DoubleDot", "\u{00A8}"), + (b"DoubleDownArrow", "\u{21D3}"), + (b"DoubleLeftArrow", "\u{21D0}"), + (b"DoubleLeftRightArrow", "\u{21D4}"), + (b"DoubleLeftTee", "\u{2AE4}"), + (b"DoubleLongLeftArrow", "\u{27F8}"), + (b"DoubleLongLeftRightArrow", "\u{27FA}"), + (b"DoubleLongRightArrow", "\u{27F9}"), + (b"DoubleRightArrow", "\u{21D2}"), + (b"DoubleRightTee", "\u{22A8}"), + (b"DoubleUpArrow", "\u{21D1}"), + (b"DoubleUpDownArrow", "\u{21D5}"), + (b"DoubleVerticalBar", "\u{2225}"), + (b"DownArrow", "\u{2193}"), + (b"DownArrowBar", "\u{2913}"), + (b"DownArrowUpArrow", "\u{21F5}"), + (b"DownBreve", "\u{0311}"), + (b"DownLeftRightVector", "\u{2950}"), + (b"DownLeftTeeVector", "\u{295E}"), + (b"DownLeftVector", "\u{21BD}"), + (b"DownLeftVectorBar", "\u{2956}"), + (b"DownRightTeeVector", "\u{295F}"), + (b"DownRightVector", "\u{21C1}"), + (b"DownRightVectorBar", "\u{2957}"), + (b"DownTee", "\u{22A4}"), + (b"DownTeeArrow", "\u{21A7}"), + (b"Downarrow", "\u{21D3}"), + (b"Dscr", "\u{1D49F}"), + (b"Dstrok", "\u{0110}"), + (b"ENG", "\u{014A}"), + (b"ETH", "\u{00D0}"), + (b"Eacute", "\u{00C9}"), + (b"Ecaron", "\u{011A}"), + (b"Ecirc", "\u{00CA}"), + (b"Ecy", "\u{042D}"), + (b"Edot", "\u{0116}"), + (b"Efr", "\u{1D508}"), + (b"Egrave", "\u{00C8}"), + (b"Element", "\u{2208}"), + (b"Emacr", "\u{0112}"), + (b"EmptySmallSquare", "\u{25FB}"), + (b"EmptyVerySmallSquare", "\u{25AB}"), + (b"Eogon", "\u{0118}"), + (b"Eopf", "\u{1D53C}"), + (b"Epsilon", "\u{0395}"), + (b"Equal", "\u{2A75}"), + (b"EqualTilde", "\u{2242}"), + (b"Equilibrium", "\u{21CC}"), + (b"Escr", "\u{2130}"), + (b"Esim", "\u{2A73}"), + (b"Eta", "\u{0397}"), + (b"Euml", "\u{00CB}"), + (b"Exists", "\u{2203}"), + (b"ExponentialE", "\u{2147}"), + (b"Fcy", "\u{0424}"), + (b"Ffr", "\u{1D509}"), + (b"FilledSmallSquare", "\u{25FC}"), + (b"FilledVerySmallSquare", "\u{25AA}"), + (b"Fopf", "\u{1D53D}"), + (b"ForAll", "\u{2200}"), + (b"Fouriertrf", "\u{2131}"), + (b"Fscr", "\u{2131}"), + (b"GJcy", "\u{0403}"), + (b"GT", "\u{003E}"), + (b"Gamma", "\u{0393}"), + (b"Gammad", "\u{03DC}"), + (b"Gbreve", "\u{011E}"), + (b"Gcedil", "\u{0122}"), + (b"Gcirc", "\u{011C}"), + (b"Gcy", "\u{0413}"), + (b"Gdot", "\u{0120}"), + (b"Gfr", "\u{1D50A}"), + (b"Gg", "\u{22D9}"), + (b"Gopf", "\u{1D53E}"), + (b"GreaterEqual", "\u{2265}"), + (b"GreaterEqualLess", "\u{22DB}"), + (b"GreaterFullEqual", "\u{2267}"), + (b"GreaterGreater", "\u{2AA2}"), + (b"GreaterLess", "\u{2277}"), + (b"GreaterSlantEqual", "\u{2A7E}"), + (b"GreaterTilde", "\u{2273}"), + (b"Gscr", "\u{1D4A2}"), + (b"Gt", "\u{226B}"), + (b"HARDcy", "\u{042A}"), + (b"Hacek", "\u{02C7}"), + (b"Hat", "\u{005E}"), + (b"Hcirc", "\u{0124}"), + (b"Hfr", "\u{210C}"), + (b"HilbertSpace", "\u{210B}"), + (b"Hopf", "\u{210D}"), + (b"HorizontalLine", "\u{2500}"), + (b"Hscr", "\u{210B}"), + (b"Hstrok", "\u{0126}"), + (b"HumpDownHump", "\u{224E}"), + (b"HumpEqual", "\u{224F}"), + (b"IEcy", "\u{0415}"), + (b"IJlig", "\u{0132}"), + (b"IOcy", "\u{0401}"), + (b"Iacute", "\u{00CD}"), + (b"Icirc", "\u{00CE}"), + (b"Icy", "\u{0418}"), + (b"Idot", "\u{0130}"), + (b"Ifr", "\u{2111}"), + (b"Igrave", "\u{00CC}"), + (b"Im", "\u{2111}"), + (b"Imacr", "\u{012A}"), + (b"ImaginaryI", "\u{2148}"), + (b"Implies", "\u{21D2}"), + (b"Int", "\u{222C}"), + (b"Integral", "\u{222B}"), + (b"Intersection", "\u{22C2}"), + (b"InvisibleComma", "\u{2063}"), + (b"InvisibleTimes", "\u{2062}"), + (b"Iogon", "\u{012E}"), + (b"Iopf", "\u{1D540}"), + (b"Iota", "\u{0399}"), + (b"Iscr", "\u{2110}"), + (b"Itilde", "\u{0128}"), + (b"Iukcy", "\u{0406}"), + (b"Iuml", "\u{00CF}"), + (b"Jcirc", "\u{0134}"), + (b"Jcy", "\u{0419}"), + (b"Jfr", "\u{1D50D}"), + (b"Jopf", "\u{1D541}"), + (b"Jscr", "\u{1D4A5}"), + (b"Jsercy", "\u{0408}"), + (b"Jukcy", "\u{0404}"), + (b"KHcy", "\u{0425}"), + (b"KJcy", "\u{040C}"), + (b"Kappa", "\u{039A}"), + (b"Kcedil", "\u{0136}"), + (b"Kcy", "\u{041A}"), + (b"Kfr", "\u{1D50E}"), + (b"Kopf", "\u{1D542}"), + (b"Kscr", "\u{1D4A6}"), + (b"LJcy", "\u{0409}"), + (b"LT", "\u{003C}"), + (b"Lacute", "\u{0139}"), + (b"Lambda", "\u{039B}"), + (b"Lang", "\u{27EA}"), + (b"Laplacetrf", "\u{2112}"), + (b"Larr", "\u{219E}"), + (b"Lcaron", "\u{013D}"), + (b"Lcedil", "\u{013B}"), + (b"Lcy", "\u{041B}"), + (b"LeftAngleBracket", "\u{27E8}"), + (b"LeftArrow", "\u{2190}"), + (b"LeftArrowBar", "\u{21E4}"), + (b"LeftArrowRightArrow", "\u{21C6}"), + (b"LeftCeiling", "\u{2308}"), + (b"LeftDoubleBracket", "\u{27E6}"), + (b"LeftDownTeeVector", "\u{2961}"), + (b"LeftDownVector", "\u{21C3}"), + (b"LeftDownVectorBar", "\u{2959}"), + (b"LeftFloor", "\u{230A}"), + (b"LeftRightArrow", "\u{2194}"), + (b"LeftRightVector", "\u{294E}"), + (b"LeftTee", "\u{22A3}"), + (b"LeftTeeArrow", "\u{21A4}"), + (b"LeftTeeVector", "\u{295A}"), + (b"LeftTriangle", "\u{22B2}"), + (b"LeftTriangleBar", "\u{29CF}"), + (b"LeftTriangleEqual", "\u{22B4}"), + (b"LeftUpDownVector", "\u{2951}"), + (b"LeftUpTeeVector", "\u{2960}"), + (b"LeftUpVector", "\u{21BF}"), + (b"LeftUpVectorBar", "\u{2958}"), + (b"LeftVector", "\u{21BC}"), + (b"LeftVectorBar", "\u{2952}"), + (b"Leftarrow", "\u{21D0}"), + (b"Leftrightarrow", "\u{21D4}"), + (b"LessEqualGreater", "\u{22DA}"), + (b"LessFullEqual", "\u{2266}"), + (b"LessGreater", "\u{2276}"), + (b"LessLess", "\u{2AA1}"), + (b"LessSlantEqual", "\u{2A7D}"), + (b"LessTilde", "\u{2272}"), + (b"Lfr", "\u{1D50F}"), + (b"Ll", "\u{22D8}"), + (b"Lleftarrow", "\u{21DA}"), + (b"Lmidot", "\u{013F}"), + (b"LongLeftArrow", "\u{27F5}"), + (b"LongLeftRightArrow", "\u{27F7}"), + (b"LongRightArrow", "\u{27F6}"), + (b"Longleftarrow", "\u{27F8}"), + (b"Longleftrightarrow", "\u{27FA}"), + (b"Longrightarrow", "\u{27F9}"), + (b"Lopf", "\u{1D543}"), + (b"LowerLeftArrow", "\u{2199}"), + (b"LowerRightArrow", "\u{2198}"), + (b"Lscr", "\u{2112}"), + (b"Lsh", "\u{21B0}"), + (b"Lstrok", "\u{0141}"), + (b"Lt", "\u{226A}"), + (b"Map", "\u{2905}"), + (b"Mcy", "\u{041C}"), + (b"MediumSpace", "\u{205F}"), + (b"Mellintrf", "\u{2133}"), + (b"Mfr", "\u{1D510}"), + (b"MinusPlus", "\u{2213}"), + (b"Mopf", "\u{1D544}"), + (b"Mscr", "\u{2133}"), + (b"Mu", "\u{039C}"), + (b"NJcy", "\u{040A}"), + (b"Nacute", "\u{0143}"), + (b"Ncaron", "\u{0147}"), + (b"Ncedil", "\u{0145}"), + (b"Ncy", "\u{041D}"), + (b"NegativeMediumSpace", "\u{200B}"), + (b"NegativeThickSpace", "\u{200B}"), + (b"NegativeThinSpace", "\u{200B}"), + (b"NegativeVeryThinSpace", "\u{200B}"), + (b"NestedGreaterGreater", "\u{226B}"), + (b"NestedLessLess", "\u{226A}"), + (b"NewLine", "\u{000A}"), + (b"Nfr", "\u{1D511}"), + (b"NoBreak", "\u{2060}"), + (b"NonBreakingSpace", "\u{00A0}"), + (b"Nopf", "\u{2115}"), + (b"Not", "\u{2AEC}"), + (b"NotCongruent", "\u{2262}"), + (b"NotCupCap", "\u{226D}"), + (b"NotDoubleVerticalBar", "\u{2226}"), + (b"NotElement", "\u{2209}"), + (b"NotEqual", "\u{2260}"), + (b"NotEqualTilde", "\u{2242}\u{0338}"), + (b"NotExists", "\u{2204}"), + (b"NotGreater", "\u{226F}"), + (b"NotGreaterEqual", "\u{2271}"), + (b"NotGreaterFullEqual", "\u{2267}\u{0338}"), + (b"NotGreaterGreater", "\u{226B}\u{0338}"), + (b"NotGreaterLess", "\u{2279}"), + (b"NotGreaterSlantEqual", "\u{2A7E}\u{0338}"), + (b"NotGreaterTilde", "\u{2275}"), + (b"NotHumpDownHump", "\u{224E}\u{0338}"), + (b"NotHumpEqual", "\u{224F}\u{0338}"), + (b"NotLeftTriangle", "\u{22EA}"), + (b"NotLeftTriangleBar", "\u{29CF}\u{0338}"), + (b"NotLeftTriangleEqual", "\u{22EC}"), + (b"NotLess", "\u{226E}"), + (b"NotLessEqual", "\u{2270}"), + (b"NotLessGreater", "\u{2278}"), + (b"NotLessLess", "\u{226A}\u{0338}"), + (b"NotLessSlantEqual", "\u{2A7D}\u{0338}"), + (b"NotLessTilde", "\u{2274}"), + (b"NotNestedGreaterGreater", "\u{2AA2}\u{0338}"), + (b"NotNestedLessLess", "\u{2AA1}\u{0338}"), + (b"NotPrecedes", "\u{2280}"), + (b"NotPrecedesEqual", "\u{2AAF}\u{0338}"), + (b"NotPrecedesSlantEqual", "\u{22E0}"), + (b"NotReverseElement", "\u{220C}"), + (b"NotRightTriangle", "\u{22EB}"), + (b"NotRightTriangleBar", "\u{29D0}\u{0338}"), + (b"NotRightTriangleEqual", "\u{22ED}"), + (b"NotSquareSubset", "\u{228F}\u{0338}"), + (b"NotSquareSubsetEqual", "\u{22E2}"), + (b"NotSquareSuperset", "\u{2290}\u{0338}"), + (b"NotSquareSupersetEqual", "\u{22E3}"), + (b"NotSubset", "\u{2282}\u{20D2}"), + (b"NotSubsetEqual", "\u{2288}"), + (b"NotSucceeds", "\u{2281}"), + (b"NotSucceedsEqual", "\u{2AB0}\u{0338}"), + (b"NotSucceedsSlantEqual", "\u{22E1}"), + (b"NotSucceedsTilde", "\u{227F}\u{0338}"), + (b"NotSuperset", "\u{2283}\u{20D2}"), + (b"NotSupersetEqual", "\u{2289}"), + (b"NotTilde", "\u{2241}"), + (b"NotTildeEqual", "\u{2244}"), + (b"NotTildeFullEqual", "\u{2247}"), + (b"NotTildeTilde", "\u{2249}"), + (b"NotVerticalBar", "\u{2224}"), + (b"Nscr", "\u{1D4A9}"), + (b"Ntilde", "\u{00D1}"), + (b"Nu", "\u{039D}"), + (b"OElig", "\u{0152}"), + (b"Oacute", "\u{00D3}"), + (b"Ocirc", "\u{00D4}"), + (b"Ocy", "\u{041E}"), + (b"Odblac", "\u{0150}"), + (b"Ofr", "\u{1D512}"), + (b"Ograve", "\u{00D2}"), + (b"Omacr", "\u{014C}"), + (b"Omega", "\u{03A9}"), + (b"Omicron", "\u{039F}"), + (b"Oopf", "\u{1D546}"), + (b"OpenCurlyDoubleQuote", "\u{201C}"), + (b"OpenCurlyQuote", "\u{2018}"), + (b"Or", "\u{2A54}"), + (b"Oscr", "\u{1D4AA}"), + (b"Oslash", "\u{00D8}"), + (b"Otilde", "\u{00D5}"), + (b"Otimes", "\u{2A37}"), + (b"Ouml", "\u{00D6}"), + (b"OverBar", "\u{203E}"), + (b"OverBrace", "\u{23DE}"), + (b"OverBracket", "\u{23B4}"), + (b"OverParenthesis", "\u{23DC}"), + (b"PartialD", "\u{2202}"), + (b"Pcy", "\u{041F}"), + (b"Pfr", "\u{1D513}"), + (b"Phi", "\u{03A6}"), + (b"Pi", "\u{03A0}"), + (b"PlusMinus", "\u{00B1}"), + (b"Poincareplane", "\u{210C}"), + (b"Popf", "\u{2119}"), + (b"Pr", "\u{2ABB}"), + (b"Precedes", "\u{227A}"), + (b"PrecedesEqual", "\u{2AAF}"), + (b"PrecedesSlantEqual", "\u{227C}"), + (b"PrecedesTilde", "\u{227E}"), + (b"Prime", "\u{2033}"), + (b"Product", "\u{220F}"), + (b"Proportion", "\u{2237}"), + (b"Proportional", "\u{221D}"), + (b"Pscr", "\u{1D4AB}"), + (b"Psi", "\u{03A8}"), + (b"QUOT", "\u{0022}"), + (b"Qfr", "\u{1D514}"), + (b"Qopf", "\u{211A}"), + (b"Qscr", "\u{1D4AC}"), + (b"RBarr", "\u{2910}"), + (b"REG", "\u{00AE}"), + (b"Racute", "\u{0154}"), + (b"Rang", "\u{27EB}"), + (b"Rarr", "\u{21A0}"), + (b"Rarrtl", "\u{2916}"), + (b"Rcaron", "\u{0158}"), + (b"Rcedil", "\u{0156}"), + (b"Rcy", "\u{0420}"), + (b"Re", "\u{211C}"), + (b"ReverseElement", "\u{220B}"), + (b"ReverseEquilibrium", "\u{21CB}"), + (b"ReverseUpEquilibrium", "\u{296F}"), + (b"Rfr", "\u{211C}"), + (b"Rho", "\u{03A1}"), + (b"RightAngleBracket", "\u{27E9}"), + (b"RightArrow", "\u{2192}"), + (b"RightArrowBar", "\u{21E5}"), + (b"RightArrowLeftArrow", "\u{21C4}"), + (b"RightCeiling", "\u{2309}"), + (b"RightDoubleBracket", "\u{27E7}"), + (b"RightDownTeeVector", "\u{295D}"), + (b"RightDownVector", "\u{21C2}"), + (b"RightDownVectorBar", "\u{2955}"), + (b"RightFloor", "\u{230B}"), + (b"RightTee", "\u{22A2}"), + (b"RightTeeArrow", "\u{21A6}"), + (b"RightTeeVector", "\u{295B}"), + (b"RightTriangle", "\u{22B3}"), + (b"RightTriangleBar", "\u{29D0}"), + (b"RightTriangleEqual", "\u{22B5}"), + (b"RightUpDownVector", "\u{294F}"), + (b"RightUpTeeVector", "\u{295C}"), + (b"RightUpVector", "\u{21BE}"), + (b"RightUpVectorBar", "\u{2954}"), + (b"RightVector", "\u{21C0}"), + (b"RightVectorBar", "\u{2953}"), + (b"Rightarrow", "\u{21D2}"), + (b"Ropf", "\u{211D}"), + (b"RoundImplies", "\u{2970}"), + (b"Rrightarrow", "\u{21DB}"), + (b"Rscr", "\u{211B}"), + (b"Rsh", "\u{21B1}"), + (b"RuleDelayed", "\u{29F4}"), + (b"SHCHcy", "\u{0429}"), + (b"SHcy", "\u{0428}"), + (b"SOFTcy", "\u{042C}"), + (b"Sacute", "\u{015A}"), + (b"Sc", "\u{2ABC}"), + (b"Scaron", "\u{0160}"), + (b"Scedil", "\u{015E}"), + (b"Scirc", "\u{015C}"), + (b"Scy", "\u{0421}"), + (b"Sfr", "\u{1D516}"), + (b"ShortDownArrow", "\u{2193}"), + (b"ShortLeftArrow", "\u{2190}"), + (b"ShortRightArrow", "\u{2192}"), + (b"ShortUpArrow", "\u{2191}"), + (b"Sigma", "\u{03A3}"), + (b"SmallCircle", "\u{2218}"), + (b"Sopf", "\u{1D54A}"), + (b"Sqrt", "\u{221A}"), + (b"Square", "\u{25A1}"), + (b"SquareIntersection", "\u{2293}"), + (b"SquareSubset", "\u{228F}"), + (b"SquareSubsetEqual", "\u{2291}"), + (b"SquareSuperset", "\u{2290}"), + (b"SquareSupersetEqual", "\u{2292}"), + (b"SquareUnion", "\u{2294}"), + (b"Sscr", "\u{1D4AE}"), + (b"Star", "\u{22C6}"), + (b"Sub", "\u{22D0}"), + (b"Subset", "\u{22D0}"), + (b"SubsetEqual", "\u{2286}"), + (b"Succeeds", "\u{227B}"), + (b"SucceedsEqual", "\u{2AB0}"), + (b"SucceedsSlantEqual", "\u{227D}"), + (b"SucceedsTilde", "\u{227F}"), + (b"SuchThat", "\u{220B}"), + (b"Sum", "\u{2211}"), + (b"Sup", "\u{22D1}"), + (b"Superset", "\u{2283}"), + (b"SupersetEqual", "\u{2287}"), + (b"Supset", "\u{22D1}"), + (b"THORN", "\u{00DE}"), + (b"TRADE", "\u{2122}"), + (b"TSHcy", "\u{040B}"), + (b"TScy", "\u{0426}"), + (b"Tab", "\u{0009}"), + (b"Tau", "\u{03A4}"), + (b"Tcaron", "\u{0164}"), + (b"Tcedil", "\u{0162}"), + (b"Tcy", "\u{0422}"), + (b"Tfr", "\u{1D517}"), + (b"Therefore", "\u{2234}"), + (b"Theta", "\u{0398}"), + (b"ThickSpace", "\u{205F}\u{200A}"), + (b"ThinSpace", "\u{2009}"), + (b"Tilde", "\u{223C}"), + (b"TildeEqual", "\u{2243}"), + (b"TildeFullEqual", "\u{2245}"), + (b"TildeTilde", "\u{2248}"), + (b"Topf", "\u{1D54B}"), + (b"TripleDot", "\u{20DB}"), + (b"Tscr", "\u{1D4AF}"), + (b"Tstrok", "\u{0166}"), + (b"Uacute", "\u{00DA}"), + (b"Uarr", "\u{219F}"), + (b"Uarrocir", "\u{2949}"), + (b"Ubrcy", "\u{040E}"), + (b"Ubreve", "\u{016C}"), + (b"Ucirc", "\u{00DB}"), + (b"Ucy", "\u{0423}"), + (b"Udblac", "\u{0170}"), + (b"Ufr", "\u{1D518}"), + (b"Ugrave", "\u{00D9}"), + (b"Umacr", "\u{016A}"), + (b"UnderBar", "\u{005F}"), + (b"UnderBrace", "\u{23DF}"), + (b"UnderBracket", "\u{23B5}"), + (b"UnderParenthesis", "\u{23DD}"), + (b"Union", "\u{22C3}"), + (b"UnionPlus", "\u{228E}"), + (b"Uogon", "\u{0172}"), + (b"Uopf", "\u{1D54C}"), + (b"UpArrow", "\u{2191}"), + (b"UpArrowBar", "\u{2912}"), + (b"UpArrowDownArrow", "\u{21C5}"), + (b"UpDownArrow", "\u{2195}"), + (b"UpEquilibrium", "\u{296E}"), + (b"UpTee", "\u{22A5}"), + (b"UpTeeArrow", "\u{21A5}"), + (b"Uparrow", "\u{21D1}"), + (b"Updownarrow", "\u{21D5}"), + (b"UpperLeftArrow", "\u{2196}"), + (b"UpperRightArrow", "\u{2197}"), + (b"Upsi", "\u{03D2}"), + (b"Upsilon", "\u{03A5}"), + (b"Uring", "\u{016E}"), + (b"Uscr", "\u{1D4B0}"), + (b"Utilde", "\u{0168}"), + (b"Uuml", "\u{00DC}"), + (b"VDash", "\u{22AB}"), + (b"Vbar", "\u{2AEB}"), + (b"Vcy", "\u{0412}"), + (b"Vdash", "\u{22A9}"), + (b"Vdashl", "\u{2AE6}"), + (b"Vee", "\u{22C1}"), + (b"Verbar", "\u{2016}"), + (b"Vert", "\u{2016}"), + (b"VerticalBar", "\u{2223}"), + (b"VerticalLine", "\u{007C}"), + (b"VerticalSeparator", "\u{2758}"), + (b"VerticalTilde", "\u{2240}"), + (b"VeryThinSpace", "\u{200A}"), + (b"Vfr", "\u{1D519}"), + (b"Vopf", "\u{1D54D}"), + (b"Vscr", "\u{1D4B1}"), + (b"Vvdash", "\u{22AA}"), + (b"Wcirc", "\u{0174}"), + (b"Wedge", "\u{22C0}"), + (b"Wfr", "\u{1D51A}"), + (b"Wopf", "\u{1D54E}"), + (b"Wscr", "\u{1D4B2}"), + (b"Xfr", "\u{1D51B}"), + (b"Xi", "\u{039E}"), + (b"Xopf", "\u{1D54F}"), + (b"Xscr", "\u{1D4B3}"), + (b"YAcy", "\u{042F}"), + (b"YIcy", "\u{0407}"), + (b"YUcy", "\u{042E}"), + (b"Yacute", "\u{00DD}"), + (b"Ycirc", "\u{0176}"), + (b"Ycy", "\u{042B}"), + (b"Yfr", "\u{1D51C}"), + (b"Yopf", "\u{1D550}"), + (b"Yscr", "\u{1D4B4}"), + (b"Yuml", "\u{0178}"), + (b"ZHcy", "\u{0416}"), + (b"Zacute", "\u{0179}"), + (b"Zcaron", "\u{017D}"), + (b"Zcy", "\u{0417}"), + (b"Zdot", "\u{017B}"), + (b"ZeroWidthSpace", "\u{200B}"), + (b"Zeta", "\u{0396}"), + (b"Zfr", "\u{2128}"), + (b"Zopf", "\u{2124}"), + (b"Zscr", "\u{1D4B5}"), + (b"aacute", "\u{00E1}"), + (b"abreve", "\u{0103}"), + (b"ac", "\u{223E}"), + (b"acE", "\u{223E}\u{0333}"), + (b"acd", "\u{223F}"), + (b"acirc", "\u{00E2}"), + (b"acute", "\u{00B4}"), + (b"acy", "\u{0430}"), + (b"aelig", "\u{00E6}"), + (b"af", "\u{2061}"), + (b"afr", "\u{1D51E}"), + (b"agrave", "\u{00E0}"), + (b"alefsym", "\u{2135}"), + (b"aleph", "\u{2135}"), + (b"alpha", "\u{03B1}"), + (b"amacr", "\u{0101}"), + (b"amalg", "\u{2A3F}"), + (b"amp", "\u{0026}"), + (b"and", "\u{2227}"), + (b"andand", "\u{2A55}"), + (b"andd", "\u{2A5C}"), + (b"andslope", "\u{2A58}"), + (b"andv", "\u{2A5A}"), + (b"ang", "\u{2220}"), + (b"ange", "\u{29A4}"), + (b"angle", "\u{2220}"), + (b"angmsd", "\u{2221}"), + (b"angmsdaa", "\u{29A8}"), + (b"angmsdab", "\u{29A9}"), + (b"angmsdac", "\u{29AA}"), + (b"angmsdad", "\u{29AB}"), + (b"angmsdae", "\u{29AC}"), + (b"angmsdaf", "\u{29AD}"), + (b"angmsdag", "\u{29AE}"), + (b"angmsdah", "\u{29AF}"), + (b"angrt", "\u{221F}"), + (b"angrtvb", "\u{22BE}"), + (b"angrtvbd", "\u{299D}"), + (b"angsph", "\u{2222}"), + (b"angst", "\u{00C5}"), + (b"angzarr", "\u{237C}"), + (b"aogon", "\u{0105}"), + (b"aopf", "\u{1D552}"), + (b"ap", "\u{2248}"), + (b"apE", "\u{2A70}"), + (b"apacir", "\u{2A6F}"), + (b"ape", "\u{224A}"), + (b"apid", "\u{224B}"), + (b"apos", "\u{0027}"), + (b"approx", "\u{2248}"), + (b"approxeq", "\u{224A}"), + (b"aring", "\u{00E5}"), + (b"ascr", "\u{1D4B6}"), + (b"ast", "\u{002A}"), + (b"asymp", "\u{2248}"), + (b"asympeq", "\u{224D}"), + (b"atilde", "\u{00E3}"), + (b"auml", "\u{00E4}"), + (b"awconint", "\u{2233}"), + (b"awint", "\u{2A11}"), + (b"bNot", "\u{2AED}"), + (b"backcong", "\u{224C}"), + (b"backepsilon", "\u{03F6}"), + (b"backprime", "\u{2035}"), + (b"backsim", "\u{223D}"), + (b"backsimeq", "\u{22CD}"), + (b"barvee", "\u{22BD}"), + (b"barwed", "\u{2305}"), + (b"barwedge", "\u{2305}"), + (b"bbrk", "\u{23B5}"), + (b"bbrktbrk", "\u{23B6}"), + (b"bcong", "\u{224C}"), + (b"bcy", "\u{0431}"), + (b"bdquo", "\u{201E}"), + (b"becaus", "\u{2235}"), + (b"because", "\u{2235}"), + (b"bemptyv", "\u{29B0}"), + (b"bepsi", "\u{03F6}"), + (b"bernou", "\u{212C}"), + (b"beta", "\u{03B2}"), + (b"beth", "\u{2136}"), + (b"between", "\u{226C}"), + (b"bfr", "\u{1D51F}"), + (b"bigcap", "\u{22C2}"), + (b"bigcirc", "\u{25EF}"), + (b"bigcup", "\u{22C3}"), + (b"bigodot", "\u{2A00}"), + (b"bigoplus", "\u{2A01}"), + (b"bigotimes", "\u{2A02}"), + (b"bigsqcup", "\u{2A06}"), + (b"bigstar", "\u{2605}"), + (b"bigtriangledown", "\u{25BD}"), + (b"bigtriangleup", "\u{25B3}"), + (b"biguplus", "\u{2A04}"), + (b"bigvee", "\u{22C1}"), + (b"bigwedge", "\u{22C0}"), + (b"bkarow", "\u{290D}"), + (b"blacklozenge", "\u{29EB}"), + (b"blacksquare", "\u{25AA}"), + (b"blacktriangle", "\u{25B4}"), + (b"blacktriangledown", "\u{25BE}"), + (b"blacktriangleleft", "\u{25C2}"), + (b"blacktriangleright", "\u{25B8}"), + (b"blank", "\u{2423}"), + (b"blk12", "\u{2592}"), + (b"blk14", "\u{2591}"), + (b"blk34", "\u{2593}"), + (b"block", "\u{2588}"), + (b"bne", "\u{003D}\u{20E5}"), + (b"bnequiv", "\u{2261}\u{20E5}"), + (b"bnot", "\u{2310}"), + (b"bopf", "\u{1D553}"), + (b"bot", "\u{22A5}"), + (b"bottom", "\u{22A5}"), + (b"bowtie", "\u{22C8}"), + (b"boxDL", "\u{2557}"), + (b"boxDR", "\u{2554}"), + (b"boxDl", "\u{2556}"), + (b"boxDr", "\u{2553}"), + (b"boxH", "\u{2550}"), + (b"boxHD", "\u{2566}"), + (b"boxHU", "\u{2569}"), + (b"boxHd", "\u{2564}"), + (b"boxHu", "\u{2567}"), + (b"boxUL", "\u{255D}"), + (b"boxUR", "\u{255A}"), + (b"boxUl", "\u{255C}"), + (b"boxUr", "\u{2559}"), + (b"boxV", "\u{2551}"), + (b"boxVH", "\u{256C}"), + (b"boxVL", "\u{2563}"), + (b"boxVR", "\u{2560}"), + (b"boxVh", "\u{256B}"), + (b"boxVl", "\u{2562}"), + (b"boxVr", "\u{255F}"), + (b"boxbox", "\u{29C9}"), + (b"boxdL", "\u{2555}"), + (b"boxdR", "\u{2552}"), + (b"boxdl", "\u{2510}"), + (b"boxdr", "\u{250C}"), + (b"boxh", "\u{2500}"), + (b"boxhD", "\u{2565}"), + (b"boxhU", "\u{2568}"), + (b"boxhd", "\u{252C}"), + (b"boxhu", "\u{2534}"), + (b"boxminus", "\u{229F}"), + (b"boxplus", "\u{229E}"), + (b"boxtimes", "\u{22A0}"), + (b"boxuL", "\u{255B}"), + (b"boxuR", "\u{2558}"), + (b"boxul", "\u{2518}"), + (b"boxur", "\u{2514}"), + (b"boxv", "\u{2502}"), + (b"boxvH", "\u{256A}"), + (b"boxvL", "\u{2561}"), + (b"boxvR", "\u{255E}"), + (b"boxvh", "\u{253C}"), + (b"boxvl", "\u{2524}"), + (b"boxvr", "\u{251C}"), + (b"bprime", "\u{2035}"), + (b"breve", "\u{02D8}"), + (b"brvbar", "\u{00A6}"), + (b"bscr", "\u{1D4B7}"), + (b"bsemi", "\u{204F}"), + (b"bsim", "\u{223D}"), + (b"bsime", "\u{22CD}"), + (b"bsol", "\u{005C}"), + (b"bsolb", "\u{29C5}"), + (b"bsolhsub", "\u{27C8}"), + (b"bull", "\u{2022}"), + (b"bullet", "\u{2022}"), + (b"bump", "\u{224E}"), + (b"bumpE", "\u{2AAE}"), + (b"bumpe", "\u{224F}"), + (b"bumpeq", "\u{224F}"), + (b"cacute", "\u{0107}"), + (b"cap", "\u{2229}"), + (b"capand", "\u{2A44}"), + (b"capbrcup", "\u{2A49}"), + (b"capcap", "\u{2A4B}"), + (b"capcup", "\u{2A47}"), + (b"capdot", "\u{2A40}"), + (b"caps", "\u{2229}\u{FE00}"), + (b"caret", "\u{2041}"), + (b"caron", "\u{02C7}"), + (b"ccaps", "\u{2A4D}"), + (b"ccaron", "\u{010D}"), + (b"ccedil", "\u{00E7}"), + (b"ccirc", "\u{0109}"), + (b"ccups", "\u{2A4C}"), + (b"ccupssm", "\u{2A50}"), + (b"cdot", "\u{010B}"), + (b"cedil", "\u{00B8}"), + (b"cemptyv", "\u{29B2}"), + (b"cent", "\u{00A2}"), + (b"centerdot", "\u{00B7}"), + (b"cfr", "\u{1D520}"), + (b"chcy", "\u{0447}"), + (b"check", "\u{2713}"), + (b"checkmark", "\u{2713}"), + (b"chi", "\u{03C7}"), + (b"cir", "\u{25CB}"), + (b"cirE", "\u{29C3}"), + (b"circ", "\u{02C6}"), + (b"circeq", "\u{2257}"), + (b"circlearrowleft", "\u{21BA}"), + (b"circlearrowright", "\u{21BB}"), + (b"circledR", "\u{00AE}"), + (b"circledS", "\u{24C8}"), + (b"circledast", "\u{229B}"), + (b"circledcirc", "\u{229A}"), + (b"circleddash", "\u{229D}"), + (b"cire", "\u{2257}"), + (b"cirfnint", "\u{2A10}"), + (b"cirmid", "\u{2AEF}"), + (b"cirscir", "\u{29C2}"), + (b"clubs", "\u{2663}"), + (b"clubsuit", "\u{2663}"), + (b"colon", "\u{003A}"), + (b"colone", "\u{2254}"), + (b"coloneq", "\u{2254}"), + (b"comma", "\u{002C}"), + (b"commat", "\u{0040}"), + (b"comp", "\u{2201}"), + (b"compfn", "\u{2218}"), + (b"complement", "\u{2201}"), + (b"complexes", "\u{2102}"), + (b"cong", "\u{2245}"), + (b"congdot", "\u{2A6D}"), + (b"conint", "\u{222E}"), + (b"copf", "\u{1D554}"), + (b"coprod", "\u{2210}"), + (b"copy", "\u{00A9}"), + (b"copysr", "\u{2117}"), + (b"crarr", "\u{21B5}"), + (b"cross", "\u{2717}"), + (b"cscr", "\u{1D4B8}"), + (b"csub", "\u{2ACF}"), + (b"csube", "\u{2AD1}"), + (b"csup", "\u{2AD0}"), + (b"csupe", "\u{2AD2}"), + (b"ctdot", "\u{22EF}"), + (b"cudarrl", "\u{2938}"), + (b"cudarrr", "\u{2935}"), + (b"cuepr", "\u{22DE}"), + (b"cuesc", "\u{22DF}"), + (b"cularr", "\u{21B6}"), + (b"cularrp", "\u{293D}"), + (b"cup", "\u{222A}"), + (b"cupbrcap", "\u{2A48}"), + (b"cupcap", "\u{2A46}"), + (b"cupcup", "\u{2A4A}"), + (b"cupdot", "\u{228D}"), + (b"cupor", "\u{2A45}"), + (b"cups", "\u{222A}\u{FE00}"), + (b"curarr", "\u{21B7}"), + (b"curarrm", "\u{293C}"), + (b"curlyeqprec", "\u{22DE}"), + (b"curlyeqsucc", "\u{22DF}"), + (b"curlyvee", "\u{22CE}"), + (b"curlywedge", "\u{22CF}"), + (b"curren", "\u{00A4}"), + (b"curvearrowleft", "\u{21B6}"), + (b"curvearrowright", "\u{21B7}"), + (b"cuvee", "\u{22CE}"), + (b"cuwed", "\u{22CF}"), + (b"cwconint", "\u{2232}"), + (b"cwint", "\u{2231}"), + (b"cylcty", "\u{232D}"), + (b"dArr", "\u{21D3}"), + (b"dHar", "\u{2965}"), + (b"dagger", "\u{2020}"), + (b"daleth", "\u{2138}"), + (b"darr", "\u{2193}"), + (b"dash", "\u{2010}"), + (b"dashv", "\u{22A3}"), + (b"dbkarow", "\u{290F}"), + (b"dblac", "\u{02DD}"), + (b"dcaron", "\u{010F}"), + (b"dcy", "\u{0434}"), + (b"dd", "\u{2146}"), + (b"ddagger", "\u{2021}"), + (b"ddarr", "\u{21CA}"), + (b"ddotseq", "\u{2A77}"), + (b"deg", "\u{00B0}"), + (b"delta", "\u{03B4}"), + (b"demptyv", "\u{29B1}"), + (b"dfisht", "\u{297F}"), + (b"dfr", "\u{1D521}"), + (b"dharl", "\u{21C3}"), + (b"dharr", "\u{21C2}"), + (b"diam", "\u{22C4}"), + (b"diamond", "\u{22C4}"), + (b"diamondsuit", "\u{2666}"), + (b"diams", "\u{2666}"), + (b"die", "\u{00A8}"), + (b"digamma", "\u{03DD}"), + (b"disin", "\u{22F2}"), + (b"div", "\u{00F7}"), + (b"divide", "\u{00F7}"), + (b"divideontimes", "\u{22C7}"), + (b"divonx", "\u{22C7}"), + (b"djcy", "\u{0452}"), + (b"dlcorn", "\u{231E}"), + (b"dlcrop", "\u{230D}"), + (b"dollar", "\u{0024}"), + (b"dopf", "\u{1D555}"), + (b"dot", "\u{02D9}"), + (b"doteq", "\u{2250}"), + (b"doteqdot", "\u{2251}"), + (b"dotminus", "\u{2238}"), + (b"dotplus", "\u{2214}"), + (b"dotsquare", "\u{22A1}"), + (b"doublebarwedge", "\u{2306}"), + (b"downarrow", "\u{2193}"), + (b"downdownarrows", "\u{21CA}"), + (b"downharpoonleft", "\u{21C3}"), + (b"downharpoonright", "\u{21C2}"), + (b"drbkarow", "\u{2910}"), + (b"drcorn", "\u{231F}"), + (b"drcrop", "\u{230C}"), + (b"dscr", "\u{1D4B9}"), + (b"dscy", "\u{0455}"), + (b"dsol", "\u{29F6}"), + (b"dstrok", "\u{0111}"), + (b"dtdot", "\u{22F1}"), + (b"dtri", "\u{25BF}"), + (b"dtrif", "\u{25BE}"), + (b"duarr", "\u{21F5}"), + (b"duhar", "\u{296F}"), + (b"dwangle", "\u{29A6}"), + (b"dzcy", "\u{045F}"), + (b"dzigrarr", "\u{27FF}"), + (b"eDDot", "\u{2A77}"), + (b"eDot", "\u{2251}"), + (b"eacute", "\u{00E9}"), + (b"easter", "\u{2A6E}"), + (b"ecaron", "\u{011B}"), + (b"ecir", "\u{2256}"), + (b"ecirc", "\u{00EA}"), + (b"ecolon", "\u{2255}"), + (b"ecy", "\u{044D}"), + (b"edot", "\u{0117}"), + (b"ee", "\u{2147}"), + (b"efDot", "\u{2252}"), + (b"efr", "\u{1D522}"), + (b"eg", "\u{2A9A}"), + (b"egrave", "\u{00E8}"), + (b"egs", "\u{2A96}"), + (b"egsdot", "\u{2A98}"), + (b"el", "\u{2A99}"), + (b"elinters", "\u{23E7}"), + (b"ell", "\u{2113}"), + (b"els", "\u{2A95}"), + (b"elsdot", "\u{2A97}"), + (b"emacr", "\u{0113}"), + (b"empty", "\u{2205}"), + (b"emptyset", "\u{2205}"), + (b"emptyv", "\u{2205}"), + (b"emsp", "\u{2003}"), + (b"emsp13", "\u{2004}"), + (b"emsp14", "\u{2005}"), + (b"eng", "\u{014B}"), + (b"ensp", "\u{2002}"), + (b"eogon", "\u{0119}"), + (b"eopf", "\u{1D556}"), + (b"epar", "\u{22D5}"), + (b"eparsl", "\u{29E3}"), + (b"eplus", "\u{2A71}"), + (b"epsi", "\u{03B5}"), + (b"epsilon", "\u{03B5}"), + (b"epsiv", "\u{03F5}"), + (b"eqcirc", "\u{2256}"), + (b"eqcolon", "\u{2255}"), + (b"eqsim", "\u{2242}"), + (b"eqslantgtr", "\u{2A96}"), + (b"eqslantless", "\u{2A95}"), + (b"equals", "\u{003D}"), + (b"equest", "\u{225F}"), + (b"equiv", "\u{2261}"), + (b"equivDD", "\u{2A78}"), + (b"eqvparsl", "\u{29E5}"), + (b"erDot", "\u{2253}"), + (b"erarr", "\u{2971}"), + (b"escr", "\u{212F}"), + (b"esdot", "\u{2250}"), + (b"esim", "\u{2242}"), + (b"eta", "\u{03B7}"), + (b"eth", "\u{00F0}"), + (b"euml", "\u{00EB}"), + (b"euro", "\u{20AC}"), + (b"excl", "\u{0021}"), + (b"exist", "\u{2203}"), + (b"expectation", "\u{2130}"), + (b"exponentiale", "\u{2147}"), + (b"fallingdotseq", "\u{2252}"), + (b"fcy", "\u{0444}"), + (b"female", "\u{2640}"), + (b"ffilig", "\u{FB03}"), + (b"fflig", "\u{FB00}"), + (b"ffllig", "\u{FB04}"), + (b"ffr", "\u{1D523}"), + (b"filig", "\u{FB01}"), + (b"fjlig", "\u{0066}\u{006A}"), + (b"flat", "\u{266D}"), + (b"fllig", "\u{FB02}"), + (b"fltns", "\u{25B1}"), + (b"fnof", "\u{0192}"), + (b"fopf", "\u{1D557}"), + (b"forall", "\u{2200}"), + (b"fork", "\u{22D4}"), + (b"forkv", "\u{2AD9}"), + (b"fpartint", "\u{2A0D}"), + (b"frac12", "\u{00BD}"), + (b"frac13", "\u{2153}"), + (b"frac14", "\u{00BC}"), + (b"frac15", "\u{2155}"), + (b"frac16", "\u{2159}"), + (b"frac18", "\u{215B}"), + (b"frac23", "\u{2154}"), + (b"frac25", "\u{2156}"), + (b"frac34", "\u{00BE}"), + (b"frac35", "\u{2157}"), + (b"frac38", "\u{215C}"), + (b"frac45", "\u{2158}"), + (b"frac56", "\u{215A}"), + (b"frac58", "\u{215D}"), + (b"frac78", "\u{215E}"), + (b"frasl", "\u{2044}"), + (b"frown", "\u{2322}"), + (b"fscr", "\u{1D4BB}"), + (b"gE", "\u{2267}"), + (b"gEl", "\u{2A8C}"), + (b"gacute", "\u{01F5}"), + (b"gamma", "\u{03B3}"), + (b"gammad", "\u{03DD}"), + (b"gap", "\u{2A86}"), + (b"gbreve", "\u{011F}"), + (b"gcirc", "\u{011D}"), + (b"gcy", "\u{0433}"), + (b"gdot", "\u{0121}"), + (b"ge", "\u{2265}"), + (b"gel", "\u{22DB}"), + (b"geq", "\u{2265}"), + (b"geqq", "\u{2267}"), + (b"geqslant", "\u{2A7E}"), + (b"ges", "\u{2A7E}"), + (b"gescc", "\u{2AA9}"), + (b"gesdot", "\u{2A80}"), + (b"gesdoto", "\u{2A82}"), + (b"gesdotol", "\u{2A84}"), + (b"gesl", "\u{22DB}\u{FE00}"), + (b"gesles", "\u{2A94}"), + (b"gfr", "\u{1D524}"), + (b"gg", "\u{226B}"), + (b"ggg", "\u{22D9}"), + (b"gimel", "\u{2137}"), + (b"gjcy", "\u{0453}"), + (b"gl", "\u{2277}"), + (b"glE", "\u{2A92}"), + (b"gla", "\u{2AA5}"), + (b"glj", "\u{2AA4}"), + (b"gnE", "\u{2269}"), + (b"gnap", "\u{2A8A}"), + (b"gnapprox", "\u{2A8A}"), + (b"gne", "\u{2A88}"), + (b"gneq", "\u{2A88}"), + (b"gneqq", "\u{2269}"), + (b"gnsim", "\u{22E7}"), + (b"gopf", "\u{1D558}"), + (b"grave", "\u{0060}"), + (b"gscr", "\u{210A}"), + (b"gsim", "\u{2273}"), + (b"gsime", "\u{2A8E}"), + (b"gsiml", "\u{2A90}"), + (b"gt", "\u{003E}"), + (b"gtcc", "\u{2AA7}"), + (b"gtcir", "\u{2A7A}"), + (b"gtdot", "\u{22D7}"), + (b"gtlPar", "\u{2995}"), + (b"gtquest", "\u{2A7C}"), + (b"gtrapprox", "\u{2A86}"), + (b"gtrarr", "\u{2978}"), + (b"gtrdot", "\u{22D7}"), + (b"gtreqless", "\u{22DB}"), + (b"gtreqqless", "\u{2A8C}"), + (b"gtrless", "\u{2277}"), + (b"gtrsim", "\u{2273}"), + (b"gvertneqq", "\u{2269}\u{FE00}"), + (b"gvnE", "\u{2269}\u{FE00}"), + (b"hArr", "\u{21D4}"), + (b"hairsp", "\u{200A}"), + (b"half", "\u{00BD}"), + (b"hamilt", "\u{210B}"), + (b"hardcy", "\u{044A}"), + (b"harr", "\u{2194}"), + (b"harrcir", "\u{2948}"), + (b"harrw", "\u{21AD}"), + (b"hbar", "\u{210F}"), + (b"hcirc", "\u{0125}"), + (b"hearts", "\u{2665}"), + (b"heartsuit", "\u{2665}"), + (b"hellip", "\u{2026}"), + (b"hercon", "\u{22B9}"), + (b"hfr", "\u{1D525}"), + (b"hksearow", "\u{2925}"), + (b"hkswarow", "\u{2926}"), + (b"hoarr", "\u{21FF}"), + (b"homtht", "\u{223B}"), + (b"hookleftarrow", "\u{21A9}"), + (b"hookrightarrow", "\u{21AA}"), + (b"hopf", "\u{1D559}"), + (b"horbar", "\u{2015}"), + (b"hscr", "\u{1D4BD}"), + (b"hslash", "\u{210F}"), + (b"hstrok", "\u{0127}"), + (b"hybull", "\u{2043}"), + (b"hyphen", "\u{2010}"), + (b"iacute", "\u{00ED}"), + (b"ic", "\u{2063}"), + (b"icirc", "\u{00EE}"), + (b"icy", "\u{0438}"), + (b"iecy", "\u{0435}"), + (b"iexcl", "\u{00A1}"), + (b"iff", "\u{21D4}"), + (b"ifr", "\u{1D526}"), + (b"igrave", "\u{00EC}"), + (b"ii", "\u{2148}"), + (b"iiiint", "\u{2A0C}"), + (b"iiint", "\u{222D}"), + (b"iinfin", "\u{29DC}"), + (b"iiota", "\u{2129}"), + (b"ijlig", "\u{0133}"), + (b"imacr", "\u{012B}"), + (b"image", "\u{2111}"), + (b"imagline", "\u{2110}"), + (b"imagpart", "\u{2111}"), + (b"imath", "\u{0131}"), + (b"imof", "\u{22B7}"), + (b"imped", "\u{01B5}"), + (b"in", "\u{2208}"), + (b"incare", "\u{2105}"), + (b"infin", "\u{221E}"), + (b"infintie", "\u{29DD}"), + (b"inodot", "\u{0131}"), + (b"int", "\u{222B}"), + (b"intcal", "\u{22BA}"), + (b"integers", "\u{2124}"), + (b"intercal", "\u{22BA}"), + (b"intlarhk", "\u{2A17}"), + (b"intprod", "\u{2A3C}"), + (b"iocy", "\u{0451}"), + (b"iogon", "\u{012F}"), + (b"iopf", "\u{1D55A}"), + (b"iota", "\u{03B9}"), + (b"iprod", "\u{2A3C}"), + (b"iquest", "\u{00BF}"), + (b"iscr", "\u{1D4BE}"), + (b"isin", "\u{2208}"), + (b"isinE", "\u{22F9}"), + (b"isindot", "\u{22F5}"), + (b"isins", "\u{22F4}"), + (b"isinsv", "\u{22F3}"), + (b"isinv", "\u{2208}"), + (b"it", "\u{2062}"), + (b"itilde", "\u{0129}"), + (b"iukcy", "\u{0456}"), + (b"iuml", "\u{00EF}"), + (b"jcirc", "\u{0135}"), + (b"jcy", "\u{0439}"), + (b"jfr", "\u{1D527}"), + (b"jmath", "\u{0237}"), + (b"jopf", "\u{1D55B}"), + (b"jscr", "\u{1D4BF}"), + (b"jsercy", "\u{0458}"), + (b"jukcy", "\u{0454}"), + (b"kappa", "\u{03BA}"), + (b"kappav", "\u{03F0}"), + (b"kcedil", "\u{0137}"), + (b"kcy", "\u{043A}"), + (b"kfr", "\u{1D528}"), + (b"kgreen", "\u{0138}"), + (b"khcy", "\u{0445}"), + (b"kjcy", "\u{045C}"), + (b"kopf", "\u{1D55C}"), + (b"kscr", "\u{1D4C0}"), + (b"lAarr", "\u{21DA}"), + (b"lArr", "\u{21D0}"), + (b"lAtail", "\u{291B}"), + (b"lBarr", "\u{290E}"), + (b"lE", "\u{2266}"), + (b"lEg", "\u{2A8B}"), + (b"lHar", "\u{2962}"), + (b"lacute", "\u{013A}"), + (b"laemptyv", "\u{29B4}"), + (b"lagran", "\u{2112}"), + (b"lambda", "\u{03BB}"), + (b"lang", "\u{27E8}"), + (b"langd", "\u{2991}"), + (b"langle", "\u{27E8}"), + (b"lap", "\u{2A85}"), + (b"laquo", "\u{00AB}"), + (b"larr", "\u{2190}"), + (b"larrb", "\u{21E4}"), + (b"larrbfs", "\u{291F}"), + (b"larrfs", "\u{291D}"), + (b"larrhk", "\u{21A9}"), + (b"larrlp", "\u{21AB}"), + (b"larrpl", "\u{2939}"), + (b"larrsim", "\u{2973}"), + (b"larrtl", "\u{21A2}"), + (b"lat", "\u{2AAB}"), + (b"latail", "\u{2919}"), + (b"late", "\u{2AAD}"), + (b"lates", "\u{2AAD}\u{FE00}"), + (b"lbarr", "\u{290C}"), + (b"lbbrk", "\u{2772}"), + (b"lbrace", "\u{007B}"), + (b"lbrack", "\u{005B}"), + (b"lbrke", "\u{298B}"), + (b"lbrksld", "\u{298F}"), + (b"lbrkslu", "\u{298D}"), + (b"lcaron", "\u{013E}"), + (b"lcedil", "\u{013C}"), + (b"lceil", "\u{2308}"), + (b"lcub", "\u{007B}"), + (b"lcy", "\u{043B}"), + (b"ldca", "\u{2936}"), + (b"ldquo", "\u{201C}"), + (b"ldquor", "\u{201E}"), + (b"ldrdhar", "\u{2967}"), + (b"ldrushar", "\u{294B}"), + (b"ldsh", "\u{21B2}"), + (b"le", "\u{2264}"), + (b"leftarrow", "\u{2190}"), + (b"leftarrowtail", "\u{21A2}"), + (b"leftharpoondown", "\u{21BD}"), + (b"leftharpoonup", "\u{21BC}"), + (b"leftleftarrows", "\u{21C7}"), + (b"leftrightarrow", "\u{2194}"), + (b"leftrightarrows", "\u{21C6}"), + (b"leftrightharpoons", "\u{21CB}"), + (b"leftrightsquigarrow", "\u{21AD}"), + (b"leftthreetimes", "\u{22CB}"), + (b"leg", "\u{22DA}"), + (b"leq", "\u{2264}"), + (b"leqq", "\u{2266}"), + (b"leqslant", "\u{2A7D}"), + (b"les", "\u{2A7D}"), + (b"lescc", "\u{2AA8}"), + (b"lesdot", "\u{2A7F}"), + (b"lesdoto", "\u{2A81}"), + (b"lesdotor", "\u{2A83}"), + (b"lesg", "\u{22DA}\u{FE00}"), + (b"lesges", "\u{2A93}"), + (b"lessapprox", "\u{2A85}"), + (b"lessdot", "\u{22D6}"), + (b"lesseqgtr", "\u{22DA}"), + (b"lesseqqgtr", "\u{2A8B}"), + (b"lessgtr", "\u{2276}"), + (b"lesssim", "\u{2272}"), + (b"lfisht", "\u{297C}"), + (b"lfloor", "\u{230A}"), + (b"lfr", "\u{1D529}"), + (b"lg", "\u{2276}"), + (b"lgE", "\u{2A91}"), + (b"lhard", "\u{21BD}"), + (b"lharu", "\u{21BC}"), + (b"lharul", "\u{296A}"), + (b"lhblk", "\u{2584}"), + (b"ljcy", "\u{0459}"), + (b"ll", "\u{226A}"), + (b"llarr", "\u{21C7}"), + (b"llcorner", "\u{231E}"), + (b"llhard", "\u{296B}"), + (b"lltri", "\u{25FA}"), + (b"lmidot", "\u{0140}"), + (b"lmoust", "\u{23B0}"), + (b"lmoustache", "\u{23B0}"), + (b"lnE", "\u{2268}"), + (b"lnap", "\u{2A89}"), + (b"lnapprox", "\u{2A89}"), + (b"lne", "\u{2A87}"), + (b"lneq", "\u{2A87}"), + (b"lneqq", "\u{2268}"), + (b"lnsim", "\u{22E6}"), + (b"loang", "\u{27EC}"), + (b"loarr", "\u{21FD}"), + (b"lobrk", "\u{27E6}"), + (b"longleftarrow", "\u{27F5}"), + (b"longleftrightarrow", "\u{27F7}"), + (b"longmapsto", "\u{27FC}"), + (b"longrightarrow", "\u{27F6}"), + (b"looparrowleft", "\u{21AB}"), + (b"looparrowright", "\u{21AC}"), + (b"lopar", "\u{2985}"), + (b"lopf", "\u{1D55D}"), + (b"loplus", "\u{2A2D}"), + (b"lotimes", "\u{2A34}"), + (b"lowast", "\u{2217}"), + (b"lowbar", "\u{005F}"), + (b"loz", "\u{25CA}"), + (b"lozenge", "\u{25CA}"), + (b"lozf", "\u{29EB}"), + (b"lpar", "\u{0028}"), + (b"lparlt", "\u{2993}"), + (b"lrarr", "\u{21C6}"), + (b"lrcorner", "\u{231F}"), + (b"lrhar", "\u{21CB}"), + (b"lrhard", "\u{296D}"), + (b"lrm", "\u{200E}"), + (b"lrtri", "\u{22BF}"), + (b"lsaquo", "\u{2039}"), + (b"lscr", "\u{1D4C1}"), + (b"lsh", "\u{21B0}"), + (b"lsim", "\u{2272}"), + (b"lsime", "\u{2A8D}"), + (b"lsimg", "\u{2A8F}"), + (b"lsqb", "\u{005B}"), + (b"lsquo", "\u{2018}"), + (b"lsquor", "\u{201A}"), + (b"lstrok", "\u{0142}"), + (b"lt", "\u{003C}"), + (b"ltcc", "\u{2AA6}"), + (b"ltcir", "\u{2A79}"), + (b"ltdot", "\u{22D6}"), + (b"lthree", "\u{22CB}"), + (b"ltimes", "\u{22C9}"), + (b"ltlarr", "\u{2976}"), + (b"ltquest", "\u{2A7B}"), + (b"ltrPar", "\u{2996}"), + (b"ltri", "\u{25C3}"), + (b"ltrie", "\u{22B4}"), + (b"ltrif", "\u{25C2}"), + (b"lurdshar", "\u{294A}"), + (b"luruhar", "\u{2966}"), + (b"lvertneqq", "\u{2268}\u{FE00}"), + (b"lvnE", "\u{2268}\u{FE00}"), + (b"mDDot", "\u{223A}"), + (b"macr", "\u{00AF}"), + (b"male", "\u{2642}"), + (b"malt", "\u{2720}"), + (b"maltese", "\u{2720}"), + (b"map", "\u{21A6}"), + (b"mapsto", "\u{21A6}"), + (b"mapstodown", "\u{21A7}"), + (b"mapstoleft", "\u{21A4}"), + (b"mapstoup", "\u{21A5}"), + (b"marker", "\u{25AE}"), + (b"mcomma", "\u{2A29}"), + (b"mcy", "\u{043C}"), + (b"mdash", "\u{2014}"), + (b"measuredangle", "\u{2221}"), + (b"mfr", "\u{1D52A}"), + (b"mho", "\u{2127}"), + (b"micro", "\u{00B5}"), + (b"mid", "\u{2223}"), + (b"midast", "\u{002A}"), + (b"midcir", "\u{2AF0}"), + (b"middot", "\u{00B7}"), + (b"minus", "\u{2212}"), + (b"minusb", "\u{229F}"), + (b"minusd", "\u{2238}"), + (b"minusdu", "\u{2A2A}"), + (b"mlcp", "\u{2ADB}"), + (b"mldr", "\u{2026}"), + (b"mnplus", "\u{2213}"), + (b"models", "\u{22A7}"), + (b"mopf", "\u{1D55E}"), + (b"mp", "\u{2213}"), + (b"mscr", "\u{1D4C2}"), + (b"mstpos", "\u{223E}"), + (b"mu", "\u{03BC}"), + (b"multimap", "\u{22B8}"), + (b"mumap", "\u{22B8}"), + (b"nGg", "\u{22D9}\u{0338}"), + (b"nGt", "\u{226B}\u{20D2}"), + (b"nGtv", "\u{226B}\u{0338}"), + (b"nLeftarrow", "\u{21CD}"), + (b"nLeftrightarrow", "\u{21CE}"), + (b"nLl", "\u{22D8}\u{0338}"), + (b"nLt", "\u{226A}\u{20D2}"), + (b"nLtv", "\u{226A}\u{0338}"), + (b"nRightarrow", "\u{21CF}"), + (b"nVDash", "\u{22AF}"), + (b"nVdash", "\u{22AE}"), + (b"nabla", "\u{2207}"), + (b"nacute", "\u{0144}"), + (b"nang", "\u{2220}\u{20D2}"), + (b"nap", "\u{2249}"), + (b"napE", "\u{2A70}\u{0338}"), + (b"napid", "\u{224B}\u{0338}"), + (b"napos", "\u{0149}"), + (b"napprox", "\u{2249}"), + (b"natur", "\u{266E}"), + (b"natural", "\u{266E}"), + (b"naturals", "\u{2115}"), + (b"nbsp", "\u{00A0}"), + (b"nbump", "\u{224E}\u{0338}"), + (b"nbumpe", "\u{224F}\u{0338}"), + (b"ncap", "\u{2A43}"), + (b"ncaron", "\u{0148}"), + (b"ncedil", "\u{0146}"), + (b"ncong", "\u{2247}"), + (b"ncongdot", "\u{2A6D}\u{0338}"), + (b"ncup", "\u{2A42}"), + (b"ncy", "\u{043D}"), + (b"ndash", "\u{2013}"), + (b"ne", "\u{2260}"), + (b"neArr", "\u{21D7}"), + (b"nearhk", "\u{2924}"), + (b"nearr", "\u{2197}"), + (b"nearrow", "\u{2197}"), + (b"nedot", "\u{2250}\u{0338}"), + (b"nequiv", "\u{2262}"), + (b"nesear", "\u{2928}"), + (b"nesim", "\u{2242}\u{0338}"), + (b"nexist", "\u{2204}"), + (b"nexists", "\u{2204}"), + (b"nfr", "\u{1D52B}"), + (b"ngE", "\u{2267}\u{0338}"), + (b"nge", "\u{2271}"), + (b"ngeq", "\u{2271}"), + (b"ngeqq", "\u{2267}\u{0338}"), + (b"ngeqslant", "\u{2A7E}\u{0338}"), + (b"nges", "\u{2A7E}\u{0338}"), + (b"ngsim", "\u{2275}"), + (b"ngt", "\u{226F}"), + (b"ngtr", "\u{226F}"), + (b"nhArr", "\u{21CE}"), + (b"nharr", "\u{21AE}"), + (b"nhpar", "\u{2AF2}"), + (b"ni", "\u{220B}"), + (b"nis", "\u{22FC}"), + (b"nisd", "\u{22FA}"), + (b"niv", "\u{220B}"), + (b"njcy", "\u{045A}"), + (b"nlArr", "\u{21CD}"), + (b"nlE", "\u{2266}\u{0338}"), + (b"nlarr", "\u{219A}"), + (b"nldr", "\u{2025}"), + (b"nle", "\u{2270}"), + (b"nleftarrow", "\u{219A}"), + (b"nleftrightarrow", "\u{21AE}"), + (b"nleq", "\u{2270}"), + (b"nleqq", "\u{2266}\u{0338}"), + (b"nleqslant", "\u{2A7D}\u{0338}"), + (b"nles", "\u{2A7D}\u{0338}"), + (b"nless", "\u{226E}"), + (b"nlsim", "\u{2274}"), + (b"nlt", "\u{226E}"), + (b"nltri", "\u{22EA}"), + (b"nltrie", "\u{22EC}"), + (b"nmid", "\u{2224}"), + (b"nopf", "\u{1D55F}"), + (b"not", "\u{00AC}"), + (b"notin", "\u{2209}"), + (b"notinE", "\u{22F9}\u{0338}"), + (b"notindot", "\u{22F5}\u{0338}"), + (b"notinva", "\u{2209}"), + (b"notinvb", "\u{22F7}"), + (b"notinvc", "\u{22F6}"), + (b"notni", "\u{220C}"), + (b"notniva", "\u{220C}"), + (b"notnivb", "\u{22FE}"), + (b"notnivc", "\u{22FD}"), + (b"npar", "\u{2226}"), + (b"nparallel", "\u{2226}"), + (b"nparsl", "\u{2AFD}\u{20E5}"), + (b"npart", "\u{2202}\u{0338}"), + (b"npolint", "\u{2A14}"), + (b"npr", "\u{2280}"), + (b"nprcue", "\u{22E0}"), + (b"npre", "\u{2AAF}\u{0338}"), + (b"nprec", "\u{2280}"), + (b"npreceq", "\u{2AAF}\u{0338}"), + (b"nrArr", "\u{21CF}"), + (b"nrarr", "\u{219B}"), + (b"nrarrc", "\u{2933}\u{0338}"), + (b"nrarrw", "\u{219D}\u{0338}"), + (b"nrightarrow", "\u{219B}"), + (b"nrtri", "\u{22EB}"), + (b"nrtrie", "\u{22ED}"), + (b"nsc", "\u{2281}"), + (b"nsccue", "\u{22E1}"), + (b"nsce", "\u{2AB0}\u{0338}"), + (b"nscr", "\u{1D4C3}"), + (b"nshortmid", "\u{2224}"), + (b"nshortparallel", "\u{2226}"), + (b"nsim", "\u{2241}"), + (b"nsime", "\u{2244}"), + (b"nsimeq", "\u{2244}"), + (b"nsmid", "\u{2224}"), + (b"nspar", "\u{2226}"), + (b"nsqsube", "\u{22E2}"), + (b"nsqsupe", "\u{22E3}"), + (b"nsub", "\u{2284}"), + (b"nsubE", "\u{2AC5}\u{0338}"), + (b"nsube", "\u{2288}"), + (b"nsubset", "\u{2282}\u{20D2}"), + (b"nsubseteq", "\u{2288}"), + (b"nsubseteqq", "\u{2AC5}\u{0338}"), + (b"nsucc", "\u{2281}"), + (b"nsucceq", "\u{2AB0}\u{0338}"), + (b"nsup", "\u{2285}"), + (b"nsupE", "\u{2AC6}\u{0338}"), + (b"nsupe", "\u{2289}"), + (b"nsupset", "\u{2283}\u{20D2}"), + (b"nsupseteq", "\u{2289}"), + (b"nsupseteqq", "\u{2AC6}\u{0338}"), + (b"ntgl", "\u{2279}"), + (b"ntilde", "\u{00F1}"), + (b"ntlg", "\u{2278}"), + (b"ntriangleleft", "\u{22EA}"), + (b"ntrianglelefteq", "\u{22EC}"), + (b"ntriangleright", "\u{22EB}"), + (b"ntrianglerighteq", "\u{22ED}"), + (b"nu", "\u{03BD}"), + (b"num", "\u{0023}"), + (b"numero", "\u{2116}"), + (b"numsp", "\u{2007}"), + (b"nvDash", "\u{22AD}"), + (b"nvHarr", "\u{2904}"), + (b"nvap", "\u{224D}\u{20D2}"), + (b"nvdash", "\u{22AC}"), + (b"nvge", "\u{2265}\u{20D2}"), + (b"nvgt", "\u{003E}\u{20D2}"), + (b"nvinfin", "\u{29DE}"), + (b"nvlArr", "\u{2902}"), + (b"nvle", "\u{2264}\u{20D2}"), + (b"nvlt", "\u{003C}\u{20D2}"), + (b"nvltrie", "\u{22B4}\u{20D2}"), + (b"nvrArr", "\u{2903}"), + (b"nvrtrie", "\u{22B5}\u{20D2}"), + (b"nvsim", "\u{223C}\u{20D2}"), + (b"nwArr", "\u{21D6}"), + (b"nwarhk", "\u{2923}"), + (b"nwarr", "\u{2196}"), + (b"nwarrow", "\u{2196}"), + (b"nwnear", "\u{2927}"), + (b"oS", "\u{24C8}"), + (b"oacute", "\u{00F3}"), + (b"oast", "\u{229B}"), + (b"ocir", "\u{229A}"), + (b"ocirc", "\u{00F4}"), + (b"ocy", "\u{043E}"), + (b"odash", "\u{229D}"), + (b"odblac", "\u{0151}"), + (b"odiv", "\u{2A38}"), + (b"odot", "\u{2299}"), + (b"odsold", "\u{29BC}"), + (b"oelig", "\u{0153}"), + (b"ofcir", "\u{29BF}"), + (b"ofr", "\u{1D52C}"), + (b"ogon", "\u{02DB}"), + (b"ograve", "\u{00F2}"), + (b"ogt", "\u{29C1}"), + (b"ohbar", "\u{29B5}"), + (b"ohm", "\u{03A9}"), + (b"oint", "\u{222E}"), + (b"olarr", "\u{21BA}"), + (b"olcir", "\u{29BE}"), + (b"olcross", "\u{29BB}"), + (b"oline", "\u{203E}"), + (b"olt", "\u{29C0}"), + (b"omacr", "\u{014D}"), + (b"omega", "\u{03C9}"), + (b"omicron", "\u{03BF}"), + (b"omid", "\u{29B6}"), + (b"ominus", "\u{2296}"), + (b"oopf", "\u{1D560}"), + (b"opar", "\u{29B7}"), + (b"operp", "\u{29B9}"), + (b"oplus", "\u{2295}"), + (b"or", "\u{2228}"), + (b"orarr", "\u{21BB}"), + (b"ord", "\u{2A5D}"), + (b"order", "\u{2134}"), + (b"orderof", "\u{2134}"), + (b"ordf", "\u{00AA}"), + (b"ordm", "\u{00BA}"), + (b"origof", "\u{22B6}"), + (b"oror", "\u{2A56}"), + (b"orslope", "\u{2A57}"), + (b"orv", "\u{2A5B}"), + (b"oscr", "\u{2134}"), + (b"oslash", "\u{00F8}"), + (b"osol", "\u{2298}"), + (b"otilde", "\u{00F5}"), + (b"otimes", "\u{2297}"), + (b"otimesas", "\u{2A36}"), + (b"ouml", "\u{00F6}"), + (b"ovbar", "\u{233D}"), + (b"par", "\u{2225}"), + (b"para", "\u{00B6}"), + (b"parallel", "\u{2225}"), + (b"parsim", "\u{2AF3}"), + (b"parsl", "\u{2AFD}"), + (b"part", "\u{2202}"), + (b"pcy", "\u{043F}"), + (b"percnt", "\u{0025}"), + (b"period", "\u{002E}"), + (b"permil", "\u{2030}"), + (b"perp", "\u{22A5}"), + (b"pertenk", "\u{2031}"), + (b"pfr", "\u{1D52D}"), + (b"phi", "\u{03C6}"), + (b"phiv", "\u{03D5}"), + (b"phmmat", "\u{2133}"), + (b"phone", "\u{260E}"), + (b"pi", "\u{03C0}"), + (b"pitchfork", "\u{22D4}"), + (b"piv", "\u{03D6}"), + (b"planck", "\u{210F}"), + (b"planckh", "\u{210E}"), + (b"plankv", "\u{210F}"), + (b"plus", "\u{002B}"), + (b"plusacir", "\u{2A23}"), + (b"plusb", "\u{229E}"), + (b"pluscir", "\u{2A22}"), + (b"plusdo", "\u{2214}"), + (b"plusdu", "\u{2A25}"), + (b"pluse", "\u{2A72}"), + (b"plusmn", "\u{00B1}"), + (b"plussim", "\u{2A26}"), + (b"plustwo", "\u{2A27}"), + (b"pm", "\u{00B1}"), + (b"pointint", "\u{2A15}"), + (b"popf", "\u{1D561}"), + (b"pound", "\u{00A3}"), + (b"pr", "\u{227A}"), + (b"prE", "\u{2AB3}"), + (b"prap", "\u{2AB7}"), + (b"prcue", "\u{227C}"), + (b"pre", "\u{2AAF}"), + (b"prec", "\u{227A}"), + (b"precapprox", "\u{2AB7}"), + (b"preccurlyeq", "\u{227C}"), + (b"preceq", "\u{2AAF}"), + (b"precnapprox", "\u{2AB9}"), + (b"precneqq", "\u{2AB5}"), + (b"precnsim", "\u{22E8}"), + (b"precsim", "\u{227E}"), + (b"prime", "\u{2032}"), + (b"primes", "\u{2119}"), + (b"prnE", "\u{2AB5}"), + (b"prnap", "\u{2AB9}"), + (b"prnsim", "\u{22E8}"), + (b"prod", "\u{220F}"), + (b"profalar", "\u{232E}"), + (b"profline", "\u{2312}"), + (b"profsurf", "\u{2313}"), + (b"prop", "\u{221D}"), + (b"propto", "\u{221D}"), + (b"prsim", "\u{227E}"), + (b"prurel", "\u{22B0}"), + (b"pscr", "\u{1D4C5}"), + (b"psi", "\u{03C8}"), + (b"puncsp", "\u{2008}"), + (b"qfr", "\u{1D52E}"), + (b"qint", "\u{2A0C}"), + (b"qopf", "\u{1D562}"), + (b"qprime", "\u{2057}"), + (b"qscr", "\u{1D4C6}"), + (b"quaternions", "\u{210D}"), + (b"quatint", "\u{2A16}"), + (b"quest", "\u{003F}"), + (b"questeq", "\u{225F}"), + (b"quot", "\u{0022}"), + (b"rAarr", "\u{21DB}"), + (b"rArr", "\u{21D2}"), + (b"rAtail", "\u{291C}"), + (b"rBarr", "\u{290F}"), + (b"rHar", "\u{2964}"), + (b"race", "\u{223D}\u{0331}"), + (b"racute", "\u{0155}"), + (b"radic", "\u{221A}"), + (b"raemptyv", "\u{29B3}"), + (b"rang", "\u{27E9}"), + (b"rangd", "\u{2992}"), + (b"range", "\u{29A5}"), + (b"rangle", "\u{27E9}"), + (b"raquo", "\u{00BB}"), + (b"rarr", "\u{2192}"), + (b"rarrap", "\u{2975}"), + (b"rarrb", "\u{21E5}"), + (b"rarrbfs", "\u{2920}"), + (b"rarrc", "\u{2933}"), + (b"rarrfs", "\u{291E}"), + (b"rarrhk", "\u{21AA}"), + (b"rarrlp", "\u{21AC}"), + (b"rarrpl", "\u{2945}"), + (b"rarrsim", "\u{2974}"), + (b"rarrtl", "\u{21A3}"), + (b"rarrw", "\u{219D}"), + (b"ratail", "\u{291A}"), + (b"ratio", "\u{2236}"), + (b"rationals", "\u{211A}"), + (b"rbarr", "\u{290D}"), + (b"rbbrk", "\u{2773}"), + (b"rbrace", "\u{007D}"), + (b"rbrack", "\u{005D}"), + (b"rbrke", "\u{298C}"), + (b"rbrksld", "\u{298E}"), + (b"rbrkslu", "\u{2990}"), + (b"rcaron", "\u{0159}"), + (b"rcedil", "\u{0157}"), + (b"rceil", "\u{2309}"), + (b"rcub", "\u{007D}"), + (b"rcy", "\u{0440}"), + (b"rdca", "\u{2937}"), + (b"rdldhar", "\u{2969}"), + (b"rdquo", "\u{201D}"), + (b"rdquor", "\u{201D}"), + (b"rdsh", "\u{21B3}"), + (b"real", "\u{211C}"), + (b"realine", "\u{211B}"), + (b"realpart", "\u{211C}"), + (b"reals", "\u{211D}"), + (b"rect", "\u{25AD}"), + (b"reg", "\u{00AE}"), + (b"rfisht", "\u{297D}"), + (b"rfloor", "\u{230B}"), + (b"rfr", "\u{1D52F}"), + (b"rhard", "\u{21C1}"), + (b"rharu", "\u{21C0}"), + (b"rharul", "\u{296C}"), + (b"rho", "\u{03C1}"), + (b"rhov", "\u{03F1}"), + (b"rightarrow", "\u{2192}"), + (b"rightarrowtail", "\u{21A3}"), + (b"rightharpoondown", "\u{21C1}"), + (b"rightharpoonup", "\u{21C0}"), + (b"rightleftarrows", "\u{21C4}"), + (b"rightleftharpoons", "\u{21CC}"), + (b"rightrightarrows", "\u{21C9}"), + (b"rightsquigarrow", "\u{219D}"), + (b"rightthreetimes", "\u{22CC}"), + (b"ring", "\u{02DA}"), + (b"risingdotseq", "\u{2253}"), + (b"rlarr", "\u{21C4}"), + (b"rlhar", "\u{21CC}"), + (b"rlm", "\u{200F}"), + (b"rmoust", "\u{23B1}"), + (b"rmoustache", "\u{23B1}"), + (b"rnmid", "\u{2AEE}"), + (b"roang", "\u{27ED}"), + (b"roarr", "\u{21FE}"), + (b"robrk", "\u{27E7}"), + (b"ropar", "\u{2986}"), + (b"ropf", "\u{1D563}"), + (b"roplus", "\u{2A2E}"), + (b"rotimes", "\u{2A35}"), + (b"rpar", "\u{0029}"), + (b"rpargt", "\u{2994}"), + (b"rppolint", "\u{2A12}"), + (b"rrarr", "\u{21C9}"), + (b"rsaquo", "\u{203A}"), + (b"rscr", "\u{1D4C7}"), + (b"rsh", "\u{21B1}"), + (b"rsqb", "\u{005D}"), + (b"rsquo", "\u{2019}"), + (b"rsquor", "\u{2019}"), + (b"rthree", "\u{22CC}"), + (b"rtimes", "\u{22CA}"), + (b"rtri", "\u{25B9}"), + (b"rtrie", "\u{22B5}"), + (b"rtrif", "\u{25B8}"), + (b"rtriltri", "\u{29CE}"), + (b"ruluhar", "\u{2968}"), + (b"rx", "\u{211E}"), + (b"sacute", "\u{015B}"), + (b"sbquo", "\u{201A}"), + (b"sc", "\u{227B}"), + (b"scE", "\u{2AB4}"), + (b"scap", "\u{2AB8}"), + (b"scaron", "\u{0161}"), + (b"sccue", "\u{227D}"), + (b"sce", "\u{2AB0}"), + (b"scedil", "\u{015F}"), + (b"scirc", "\u{015D}"), + (b"scnE", "\u{2AB6}"), + (b"scnap", "\u{2ABA}"), + (b"scnsim", "\u{22E9}"), + (b"scpolint", "\u{2A13}"), + (b"scsim", "\u{227F}"), + (b"scy", "\u{0441}"), + (b"sdot", "\u{22C5}"), + (b"sdotb", "\u{22A1}"), + (b"sdote", "\u{2A66}"), + (b"seArr", "\u{21D8}"), + (b"searhk", "\u{2925}"), + (b"searr", "\u{2198}"), + (b"searrow", "\u{2198}"), + (b"sect", "\u{00A7}"), + (b"semi", "\u{003B}"), + (b"seswar", "\u{2929}"), + (b"setminus", "\u{2216}"), + (b"setmn", "\u{2216}"), + (b"sext", "\u{2736}"), + (b"sfr", "\u{1D530}"), + (b"sfrown", "\u{2322}"), + (b"sharp", "\u{266F}"), + (b"shchcy", "\u{0449}"), + (b"shcy", "\u{0448}"), + (b"shortmid", "\u{2223}"), + (b"shortparallel", "\u{2225}"), + (b"shy", "\u{00AD}"), + (b"sigma", "\u{03C3}"), + (b"sigmaf", "\u{03C2}"), + (b"sigmav", "\u{03C2}"), + (b"sim", "\u{223C}"), + (b"simdot", "\u{2A6A}"), + (b"sime", "\u{2243}"), + (b"simeq", "\u{2243}"), + (b"simg", "\u{2A9E}"), + (b"simgE", "\u{2AA0}"), + (b"siml", "\u{2A9D}"), + (b"simlE", "\u{2A9F}"), + (b"simne", "\u{2246}"), + (b"simplus", "\u{2A24}"), + (b"simrarr", "\u{2972}"), + (b"slarr", "\u{2190}"), + (b"smallsetminus", "\u{2216}"), + (b"smashp", "\u{2A33}"), + (b"smeparsl", "\u{29E4}"), + (b"smid", "\u{2223}"), + (b"smile", "\u{2323}"), + (b"smt", "\u{2AAA}"), + (b"smte", "\u{2AAC}"), + (b"smtes", "\u{2AAC}\u{FE00}"), + (b"softcy", "\u{044C}"), + (b"sol", "\u{002F}"), + (b"solb", "\u{29C4}"), + (b"solbar", "\u{233F}"), + (b"sopf", "\u{1D564}"), + (b"spades", "\u{2660}"), + (b"spadesuit", "\u{2660}"), + (b"spar", "\u{2225}"), + (b"sqcap", "\u{2293}"), + (b"sqcaps", "\u{2293}\u{FE00}"), + (b"sqcup", "\u{2294}"), + (b"sqcups", "\u{2294}\u{FE00}"), + (b"sqsub", "\u{228F}"), + (b"sqsube", "\u{2291}"), + (b"sqsubset", "\u{228F}"), + (b"sqsubseteq", "\u{2291}"), + (b"sqsup", "\u{2290}"), + (b"sqsupe", "\u{2292}"), + (b"sqsupset", "\u{2290}"), + (b"sqsupseteq", "\u{2292}"), + (b"squ", "\u{25A1}"), + (b"square", "\u{25A1}"), + (b"squarf", "\u{25AA}"), + (b"squf", "\u{25AA}"), + (b"srarr", "\u{2192}"), + (b"sscr", "\u{1D4C8}"), + (b"ssetmn", "\u{2216}"), + (b"ssmile", "\u{2323}"), + (b"sstarf", "\u{22C6}"), + (b"star", "\u{2606}"), + (b"starf", "\u{2605}"), + (b"straightepsilon", "\u{03F5}"), + (b"straightphi", "\u{03D5}"), + (b"strns", "\u{00AF}"), + (b"sub", "\u{2282}"), + (b"subE", "\u{2AC5}"), + (b"subdot", "\u{2ABD}"), + (b"sube", "\u{2286}"), + (b"subedot", "\u{2AC3}"), + (b"submult", "\u{2AC1}"), + (b"subnE", "\u{2ACB}"), + (b"subne", "\u{228A}"), + (b"subplus", "\u{2ABF}"), + (b"subrarr", "\u{2979}"), + (b"subset", "\u{2282}"), + (b"subseteq", "\u{2286}"), + (b"subseteqq", "\u{2AC5}"), + (b"subsetneq", "\u{228A}"), + (b"subsetneqq", "\u{2ACB}"), + (b"subsim", "\u{2AC7}"), + (b"subsub", "\u{2AD5}"), + (b"subsup", "\u{2AD3}"), + (b"succ", "\u{227B}"), + (b"succapprox", "\u{2AB8}"), + (b"succcurlyeq", "\u{227D}"), + (b"succeq", "\u{2AB0}"), + (b"succnapprox", "\u{2ABA}"), + (b"succneqq", "\u{2AB6}"), + (b"succnsim", "\u{22E9}"), + (b"succsim", "\u{227F}"), + (b"sum", "\u{2211}"), + (b"sung", "\u{266A}"), + (b"sup", "\u{2283}"), + (b"sup1", "\u{00B9}"), + (b"sup2", "\u{00B2}"), + (b"sup3", "\u{00B3}"), + (b"supE", "\u{2AC6}"), + (b"supdot", "\u{2ABE}"), + (b"supdsub", "\u{2AD8}"), + (b"supe", "\u{2287}"), + (b"supedot", "\u{2AC4}"), + (b"suphsol", "\u{27C9}"), + (b"suphsub", "\u{2AD7}"), + (b"suplarr", "\u{297B}"), + (b"supmult", "\u{2AC2}"), + (b"supnE", "\u{2ACC}"), + (b"supne", "\u{228B}"), + (b"supplus", "\u{2AC0}"), + (b"supset", "\u{2283}"), + (b"supseteq", "\u{2287}"), + (b"supseteqq", "\u{2AC6}"), + (b"supsetneq", "\u{228B}"), + (b"supsetneqq", "\u{2ACC}"), + (b"supsim", "\u{2AC8}"), + (b"supsub", "\u{2AD4}"), + (b"supsup", "\u{2AD6}"), + (b"swArr", "\u{21D9}"), + (b"swarhk", "\u{2926}"), + (b"swarr", "\u{2199}"), + (b"swarrow", "\u{2199}"), + (b"swnwar", "\u{292A}"), + (b"szlig", "\u{00DF}"), + (b"target", "\u{2316}"), + (b"tau", "\u{03C4}"), + (b"tbrk", "\u{23B4}"), + (b"tcaron", "\u{0165}"), + (b"tcedil", "\u{0163}"), + (b"tcy", "\u{0442}"), + (b"tdot", "\u{20DB}"), + (b"telrec", "\u{2315}"), + (b"tfr", "\u{1D531}"), + (b"there4", "\u{2234}"), + (b"therefore", "\u{2234}"), + (b"theta", "\u{03B8}"), + (b"thetasym", "\u{03D1}"), + (b"thetav", "\u{03D1}"), + (b"thickapprox", "\u{2248}"), + (b"thicksim", "\u{223C}"), + (b"thinsp", "\u{2009}"), + (b"thkap", "\u{2248}"), + (b"thksim", "\u{223C}"), + (b"thorn", "\u{00FE}"), + (b"tilde", "\u{02DC}"), + (b"times", "\u{00D7}"), + (b"timesb", "\u{22A0}"), + (b"timesbar", "\u{2A31}"), + (b"timesd", "\u{2A30}"), + (b"tint", "\u{222D}"), + (b"toea", "\u{2928}"), + (b"top", "\u{22A4}"), + (b"topbot", "\u{2336}"), + (b"topcir", "\u{2AF1}"), + (b"topf", "\u{1D565}"), + (b"topfork", "\u{2ADA}"), + (b"tosa", "\u{2929}"), + (b"tprime", "\u{2034}"), + (b"trade", "\u{2122}"), + (b"triangle", "\u{25B5}"), + (b"triangledown", "\u{25BF}"), + (b"triangleleft", "\u{25C3}"), + (b"trianglelefteq", "\u{22B4}"), + (b"triangleq", "\u{225C}"), + (b"triangleright", "\u{25B9}"), + (b"trianglerighteq", "\u{22B5}"), + (b"tridot", "\u{25EC}"), + (b"trie", "\u{225C}"), + (b"triminus", "\u{2A3A}"), + (b"triplus", "\u{2A39}"), + (b"trisb", "\u{29CD}"), + (b"tritime", "\u{2A3B}"), + (b"trpezium", "\u{23E2}"), + (b"tscr", "\u{1D4C9}"), + (b"tscy", "\u{0446}"), + (b"tshcy", "\u{045B}"), + (b"tstrok", "\u{0167}"), + (b"twixt", "\u{226C}"), + (b"twoheadleftarrow", "\u{219E}"), + (b"twoheadrightarrow", "\u{21A0}"), + (b"uArr", "\u{21D1}"), + (b"uHar", "\u{2963}"), + (b"uacute", "\u{00FA}"), + (b"uarr", "\u{2191}"), + (b"ubrcy", "\u{045E}"), + (b"ubreve", "\u{016D}"), + (b"ucirc", "\u{00FB}"), + (b"ucy", "\u{0443}"), + (b"udarr", "\u{21C5}"), + (b"udblac", "\u{0171}"), + (b"udhar", "\u{296E}"), + (b"ufisht", "\u{297E}"), + (b"ufr", "\u{1D532}"), + (b"ugrave", "\u{00F9}"), + (b"uharl", "\u{21BF}"), + (b"uharr", "\u{21BE}"), + (b"uhblk", "\u{2580}"), + (b"ulcorn", "\u{231C}"), + (b"ulcorner", "\u{231C}"), + (b"ulcrop", "\u{230F}"), + (b"ultri", "\u{25F8}"), + (b"umacr", "\u{016B}"), + (b"uml", "\u{00A8}"), + (b"uogon", "\u{0173}"), + (b"uopf", "\u{1D566}"), + (b"uparrow", "\u{2191}"), + (b"updownarrow", "\u{2195}"), + (b"upharpoonleft", "\u{21BF}"), + (b"upharpoonright", "\u{21BE}"), + (b"uplus", "\u{228E}"), + (b"upsi", "\u{03C5}"), + (b"upsih", "\u{03D2}"), + (b"upsilon", "\u{03C5}"), + (b"upuparrows", "\u{21C8}"), + (b"urcorn", "\u{231D}"), + (b"urcorner", "\u{231D}"), + (b"urcrop", "\u{230E}"), + (b"uring", "\u{016F}"), + (b"urtri", "\u{25F9}"), + (b"uscr", "\u{1D4CA}"), + (b"utdot", "\u{22F0}"), + (b"utilde", "\u{0169}"), + (b"utri", "\u{25B5}"), + (b"utrif", "\u{25B4}"), + (b"uuarr", "\u{21C8}"), + (b"uuml", "\u{00FC}"), + (b"uwangle", "\u{29A7}"), + (b"vArr", "\u{21D5}"), + (b"vBar", "\u{2AE8}"), + (b"vBarv", "\u{2AE9}"), + (b"vDash", "\u{22A8}"), + (b"vangrt", "\u{299C}"), + (b"varepsilon", "\u{03F5}"), + (b"varkappa", "\u{03F0}"), + (b"varnothing", "\u{2205}"), + (b"varphi", "\u{03D5}"), + (b"varpi", "\u{03D6}"), + (b"varpropto", "\u{221D}"), + (b"varr", "\u{2195}"), + (b"varrho", "\u{03F1}"), + (b"varsigma", "\u{03C2}"), + (b"varsubsetneq", "\u{228A}\u{FE00}"), + (b"varsubsetneqq", "\u{2ACB}\u{FE00}"), + (b"varsupsetneq", "\u{228B}\u{FE00}"), + (b"varsupsetneqq", "\u{2ACC}\u{FE00}"), + (b"vartheta", "\u{03D1}"), + (b"vartriangleleft", "\u{22B2}"), + (b"vartriangleright", "\u{22B3}"), + (b"vcy", "\u{0432}"), + (b"vdash", "\u{22A2}"), + (b"vee", "\u{2228}"), + (b"veebar", "\u{22BB}"), + (b"veeeq", "\u{225A}"), + (b"vellip", "\u{22EE}"), + (b"verbar", "\u{007C}"), + (b"vert", "\u{007C}"), + (b"vfr", "\u{1D533}"), + (b"vltri", "\u{22B2}"), + (b"vnsub", "\u{2282}\u{20D2}"), + (b"vnsup", "\u{2283}\u{20D2}"), + (b"vopf", "\u{1D567}"), + (b"vprop", "\u{221D}"), + (b"vrtri", "\u{22B3}"), + (b"vscr", "\u{1D4CB}"), + (b"vsubnE", "\u{2ACB}\u{FE00}"), + (b"vsubne", "\u{228A}\u{FE00}"), + (b"vsupnE", "\u{2ACC}\u{FE00}"), + (b"vsupne", "\u{228B}\u{FE00}"), + (b"vzigzag", "\u{299A}"), + (b"wcirc", "\u{0175}"), + (b"wedbar", "\u{2A5F}"), + (b"wedge", "\u{2227}"), + (b"wedgeq", "\u{2259}"), + (b"weierp", "\u{2118}"), + (b"wfr", "\u{1D534}"), + (b"wopf", "\u{1D568}"), + (b"wp", "\u{2118}"), + (b"wr", "\u{2240}"), + (b"wreath", "\u{2240}"), + (b"wscr", "\u{1D4CC}"), + (b"xcap", "\u{22C2}"), + (b"xcirc", "\u{25EF}"), + (b"xcup", "\u{22C3}"), + (b"xdtri", "\u{25BD}"), + (b"xfr", "\u{1D535}"), + (b"xhArr", "\u{27FA}"), + (b"xharr", "\u{27F7}"), + (b"xi", "\u{03BE}"), + (b"xlArr", "\u{27F8}"), + (b"xlarr", "\u{27F5}"), + (b"xmap", "\u{27FC}"), + (b"xnis", "\u{22FB}"), + (b"xodot", "\u{2A00}"), + (b"xopf", "\u{1D569}"), + (b"xoplus", "\u{2A01}"), + (b"xotime", "\u{2A02}"), + (b"xrArr", "\u{27F9}"), + (b"xrarr", "\u{27F6}"), + (b"xscr", "\u{1D4CD}"), + (b"xsqcup", "\u{2A06}"), + (b"xuplus", "\u{2A04}"), + (b"xutri", "\u{25B3}"), + (b"xvee", "\u{22C1}"), + (b"xwedge", "\u{22C0}"), + (b"yacute", "\u{00FD}"), + (b"yacy", "\u{044F}"), + (b"ycirc", "\u{0177}"), + (b"ycy", "\u{044B}"), + (b"yen", "\u{00A5}"), + (b"yfr", "\u{1D536}"), + (b"yicy", "\u{0457}"), + (b"yopf", "\u{1D56A}"), + (b"yscr", "\u{1D4CE}"), + (b"yucy", "\u{044E}"), + (b"yuml", "\u{00FF}"), + (b"zacute", "\u{017A}"), + (b"zcaron", "\u{017E}"), + (b"zcy", "\u{0437}"), + (b"zdot", "\u{017C}"), + (b"zeetrf", "\u{2128}"), + (b"zeta", "\u{03B6}"), + (b"zfr", "\u{1D537}"), + (b"zhcy", "\u{0436}"), + (b"zigrarr", "\u{21DD}"), + (b"zopf", "\u{1D56B}"), + (b"zscr", "\u{1D4CF}"), + (b"zwj", "\u{200D}"), + (b"zwnj", "\u{200C}"), +]; + +pub(crate) fn get_entity(bytes: &[u8]) -> Option<&'static str> { + ENTITIES + .binary_search_by_key(&bytes, |&(key, _value)| key) + .ok() + .map(|i| ENTITIES[i].1) +} diff --git a/vendor/pulldown-cmark/src/escape.rs b/vendor/pulldown-cmark/src/escape.rs index 7b31cef614..af9066dc19 100644 --- a/vendor/pulldown-cmark/src/escape.rs +++ b/vendor/pulldown-cmark/src/escape.rs @@ -1,297 +1,356 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Utility functions for HTML escaping - -use std::io; -use std::str::from_utf8; - -use crate::html::StrWrite; - -#[rustfmt::skip] -static HREF_SAFE: [u8; 128] = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, -]; - -static HEX_CHARS: &[u8] = b"0123456789ABCDEF"; -static AMP_ESCAPE: &str = "&"; -static SLASH_ESCAPE: &str = "'"; - -pub(crate) fn escape_href(mut w: W, s: &str) -> io::Result<()> -where - W: StrWrite, -{ - let bytes = s.as_bytes(); - let mut mark = 0; - for i in 0..bytes.len() { - let c = bytes[i]; - if c >= 0x80 || HREF_SAFE[c as usize] == 0 { - // character needing escape - - // write partial substring up to mark - if mark < i { - w.write_str(&s[mark..i])?; - } - match c { - b'&' => { - w.write_str(AMP_ESCAPE)?; - } - b'\'' => { - w.write_str(SLASH_ESCAPE)?; - } - _ => { - let mut buf = [0u8; 3]; - buf[0] = b'%'; - buf[1] = HEX_CHARS[((c as usize) >> 4) & 0xF]; - buf[2] = HEX_CHARS[(c as usize) & 0xF]; - let escaped = from_utf8(&buf).unwrap(); - w.write_str(escaped)?; - } - } - mark = i + 1; // all escaped characters are ASCII - } - } - w.write_str(&s[mark..]) -} - -const fn create_html_escape_table() -> [u8; 256] { - let mut table = [0; 256]; - table[b'"' as usize] = 1; - table[b'&' as usize] = 2; - table[b'<' as usize] = 3; - table[b'>' as usize] = 4; - table -} - -static HTML_ESCAPE_TABLE: [u8; 256] = create_html_escape_table(); - -static HTML_ESCAPES: [&'static str; 5] = ["", """, "&", "<", ">"]; - -/// Writes the given string to the Write sink, replacing special HTML bytes -/// (<, >, &, ") by escape sequences. -pub(crate) fn escape_html(w: W, s: &str) -> io::Result<()> { - #[cfg(all(target_arch = "x86_64", feature = "simd"))] - { - simd::escape_html(w, s) - } - #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] - { - escape_html_scalar(w, s) - } -} - -fn escape_html_scalar(mut w: W, s: &str) -> io::Result<()> { - let bytes = s.as_bytes(); - let mut mark = 0; - let mut i = 0; - while i < s.len() { - match bytes[i..] - .iter() - .position(|&c| HTML_ESCAPE_TABLE[c as usize] != 0) - { - Some(pos) => { - i += pos; - } - None => break, - } - let c = bytes[i]; - let escape = HTML_ESCAPE_TABLE[c as usize]; - let escape_seq = HTML_ESCAPES[escape as usize]; - w.write_str(&s[mark..i])?; - w.write_str(escape_seq)?; - i += 1; - mark = i; // all escaped characters are ASCII - } - w.write_str(&s[mark..]) -} - -#[cfg(all(target_arch = "x86_64", feature = "simd"))] -mod simd { - use crate::html::StrWrite; - use std::arch::x86_64::*; - use std::io; - use std::mem::size_of; - - const VECTOR_SIZE: usize = size_of::<__m128i>(); - - pub(crate) fn escape_html(mut w: W, s: &str) -> io::Result<()> { - // The SIMD accelerated code uses the PSHUFB instruction, which is part - // of the SSSE3 instruction set. Further, we can only use this code if - // the buffer is at least one VECTOR_SIZE in length to prevent reading - // out of bounds. If either of these conditions is not met, we fall back - // to scalar code. - if is_x86_feature_detected!("ssse3") && s.len() >= VECTOR_SIZE { - let bytes = s.as_bytes(); - let mut mark = 0; - - unsafe { - foreach_special_simd(bytes, 0, |i| { - let escape_ix = *bytes.get_unchecked(i) as usize; - let replacement = - super::HTML_ESCAPES[super::HTML_ESCAPE_TABLE[escape_ix] as usize]; - w.write_str(&s.get_unchecked(mark..i))?; - mark = i + 1; // all escaped characters are ASCII - w.write_str(replacement) - })?; - w.write_str(&s.get_unchecked(mark..)) - } - } else { - super::escape_html_scalar(w, s) - } - } - - /// Creates the lookup table for use in `compute_mask`. - const fn create_lookup() -> [u8; 16] { - let mut table = [0; 16]; - table[(b'<' & 0x0f) as usize] = b'<'; - table[(b'>' & 0x0f) as usize] = b'>'; - table[(b'&' & 0x0f) as usize] = b'&'; - table[(b'"' & 0x0f) as usize] = b'"'; - table[0] = 0b0111_1111; - table - } - - #[target_feature(enable = "ssse3")] - /// Computes a byte mask at given offset in the byte buffer. Its first 16 (least significant) - /// bits correspond to whether there is an HTML special byte (&, <, ", >) at the 16 bytes - /// `bytes[offset..]`. For example, the mask `(1 << 3)` states that there is an HTML byte - /// at `offset + 3`. It is only safe to call this function when - /// `bytes.len() >= offset + VECTOR_SIZE`. - unsafe fn compute_mask(bytes: &[u8], offset: usize) -> i32 { - debug_assert!(bytes.len() >= offset + VECTOR_SIZE); - - let table = create_lookup(); - let lookup = _mm_loadu_si128(table.as_ptr() as *const __m128i); - let raw_ptr = bytes.as_ptr().offset(offset as isize) as *const __m128i; - - // Load the vector from memory. - let vector = _mm_loadu_si128(raw_ptr); - // We take the least significant 4 bits of every byte and use them as indices - // to map into the lookup vector. - // Note that shuffle maps bytes with their most significant bit set to lookup[0]. - // Bytes that share their lower nibble with an HTML special byte get mapped to that - // corresponding special byte. Note that all HTML special bytes have distinct lower - // nibbles. Other bytes either get mapped to 0 or 127. - let expected = _mm_shuffle_epi8(lookup, vector); - // We compare the original vector to the mapped output. Bytes that shared a lower - // nibble with an HTML special byte match *only* if they are that special byte. Bytes - // that have either a 0 lower nibble or their most significant bit set were mapped to - // 127 and will hence never match. All other bytes have non-zero lower nibbles but - // were mapped to 0 and will therefore also not match. - let matches = _mm_cmpeq_epi8(expected, vector); - - // Translate matches to a bitmask, where every 1 corresponds to a HTML special character - // and a 0 is a non-HTML byte. - _mm_movemask_epi8(matches) - } - - /// Calls the given function with the index of every byte in the given byteslice - /// that is either ", &, <, or > and for no other byte. - /// Make sure to only call this when `bytes.len() >= 16`, undefined behaviour may - /// occur otherwise. - #[target_feature(enable = "ssse3")] - unsafe fn foreach_special_simd( - bytes: &[u8], - mut offset: usize, - mut callback: F, - ) -> io::Result<()> - where - F: FnMut(usize) -> io::Result<()>, - { - // The strategy here is to walk the byte buffer in chunks of VECTOR_SIZE (16) - // bytes at a time starting at the given offset. For each chunk, we compute a - // a bitmask indicating whether the corresponding byte is a HTML special byte. - // We then iterate over all the 1 bits in this mask and call the callback function - // with the corresponding index in the buffer. - // When the number of HTML special bytes in the buffer is relatively low, this - // allows us to quickly go through the buffer without a lookup and for every - // single byte. - - debug_assert!(bytes.len() >= VECTOR_SIZE); - let upperbound = bytes.len() - VECTOR_SIZE; - while offset < upperbound { - let mut mask = compute_mask(bytes, offset); - while mask != 0 { - let ix = mask.trailing_zeros(); - callback(offset + ix as usize)?; - mask ^= mask & -mask; - } - offset += VECTOR_SIZE; - } - - // Final iteration. We align the read with the end of the slice and - // shift off the bytes at start we have already scanned. - let mut mask = compute_mask(bytes, upperbound); - mask >>= offset - upperbound; - while mask != 0 { - let ix = mask.trailing_zeros(); - callback(offset + ix as usize)?; - mask ^= mask & -mask; - } - Ok(()) - } - - #[cfg(test)] - mod html_scan_tests { - #[test] - fn multichunk() { - let mut vec = Vec::new(); - unsafe { - super::foreach_special_simd("&aXaaaa.a'aa9a<>aab&".as_bytes(), 0, |ix| { - Ok(vec.push(ix)) - }) - .unwrap(); - } - assert_eq!(vec, vec![0, 14, 15, 19]); - } - - // only match these bytes, and when we match them, match them VECTOR_SIZE times - #[test] - fn only_right_bytes_matched() { - for b in 0..255u8 { - let right_byte = b == b'&' || b == b'<' || b == b'>' || b == b'"'; - let vek = vec![b; super::VECTOR_SIZE]; - let mut match_count = 0; - unsafe { - super::foreach_special_simd(&vek, 0, |_| { - match_count += 1; - Ok(()) - }) - .unwrap(); - } - assert!((match_count > 0) == (match_count == super::VECTOR_SIZE)); - assert_eq!( - (match_count == super::VECTOR_SIZE), - right_byte, - "match_count: {}, byte: {:?}", - match_count, - b as char - ); - } - } - } -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Utility functions for HTML escaping. Only useful when building your own +//! HTML renderer. + +use std::fmt::{Arguments, Write as FmtWrite}; +use std::io::{self, ErrorKind, Write}; +use std::str::from_utf8; + +#[rustfmt::skip] +static HREF_SAFE: [u8; 128] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, +]; + +static HEX_CHARS: &[u8] = b"0123456789ABCDEF"; +static AMP_ESCAPE: &str = "&"; +static SLASH_ESCAPE: &str = "'"; + +/// This wrapper exists because we can't have both a blanket implementation +/// for all types implementing `Write` and types of the for `&mut W` where +/// `W: StrWrite`. Since we need the latter a lot, we choose to wrap +/// `Write` types. +pub struct WriteWrapper(pub W); + +/// Trait that allows writing string slices. This is basically an extension +/// of `std::io::Write` in order to include `String`. +pub trait StrWrite { + fn write_str(&mut self, s: &str) -> io::Result<()>; + + fn write_fmt(&mut self, args: Arguments) -> io::Result<()>; +} + +impl StrWrite for WriteWrapper +where + W: Write, +{ + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.0.write_all(s.as_bytes()) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + self.0.write_fmt(args) + } +} + +impl<'w> StrWrite for String { + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.push_str(s); + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + // FIXME: translate fmt error to io error? + FmtWrite::write_fmt(self, args).map_err(|_| ErrorKind::Other.into()) + } +} + +impl StrWrite for &'_ mut W +where + W: StrWrite, +{ + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + (**self).write_str(s) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + (**self).write_fmt(args) + } +} + +/// Writes an href to the buffer, escaping href unsafe bytes. +pub fn escape_href(mut w: W, s: &str) -> io::Result<()> +where + W: StrWrite, +{ + let bytes = s.as_bytes(); + let mut mark = 0; + for i in 0..bytes.len() { + let c = bytes[i]; + if c >= 0x80 || HREF_SAFE[c as usize] == 0 { + // character needing escape + + // write partial substring up to mark + if mark < i { + w.write_str(&s[mark..i])?; + } + match c { + b'&' => { + w.write_str(AMP_ESCAPE)?; + } + b'\'' => { + w.write_str(SLASH_ESCAPE)?; + } + _ => { + let mut buf = [0u8; 3]; + buf[0] = b'%'; + buf[1] = HEX_CHARS[((c as usize) >> 4) & 0xF]; + buf[2] = HEX_CHARS[(c as usize) & 0xF]; + let escaped = from_utf8(&buf).unwrap(); + w.write_str(escaped)?; + } + } + mark = i + 1; // all escaped characters are ASCII + } + } + w.write_str(&s[mark..]) +} + +const fn create_html_escape_table() -> [u8; 256] { + let mut table = [0; 256]; + table[b'"' as usize] = 1; + table[b'&' as usize] = 2; + table[b'<' as usize] = 3; + table[b'>' as usize] = 4; + table +} + +static HTML_ESCAPE_TABLE: [u8; 256] = create_html_escape_table(); + +static HTML_ESCAPES: [&'static str; 5] = ["", """, "&", "<", ">"]; + +/// Writes the given string to the Write sink, replacing special HTML bytes +/// (<, >, &, ") by escape sequences. +pub fn escape_html(w: W, s: &str) -> io::Result<()> { + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + simd::escape_html(w, s) + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + escape_html_scalar(w, s) + } +} + +fn escape_html_scalar(mut w: W, s: &str) -> io::Result<()> { + let bytes = s.as_bytes(); + let mut mark = 0; + let mut i = 0; + while i < s.len() { + match bytes[i..] + .iter() + .position(|&c| HTML_ESCAPE_TABLE[c as usize] != 0) + { + Some(pos) => { + i += pos; + } + None => break, + } + let c = bytes[i]; + let escape = HTML_ESCAPE_TABLE[c as usize]; + let escape_seq = HTML_ESCAPES[escape as usize]; + w.write_str(&s[mark..i])?; + w.write_str(escape_seq)?; + i += 1; + mark = i; // all escaped characters are ASCII + } + w.write_str(&s[mark..]) +} + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +mod simd { + use super::StrWrite; + use std::arch::x86_64::*; + use std::io; + use std::mem::size_of; + + const VECTOR_SIZE: usize = size_of::<__m128i>(); + + pub(crate) fn escape_html(mut w: W, s: &str) -> io::Result<()> { + // The SIMD accelerated code uses the PSHUFB instruction, which is part + // of the SSSE3 instruction set. Further, we can only use this code if + // the buffer is at least one VECTOR_SIZE in length to prevent reading + // out of bounds. If either of these conditions is not met, we fall back + // to scalar code. + if is_x86_feature_detected!("ssse3") && s.len() >= VECTOR_SIZE { + let bytes = s.as_bytes(); + let mut mark = 0; + + unsafe { + foreach_special_simd(bytes, 0, |i| { + let escape_ix = *bytes.get_unchecked(i) as usize; + let replacement = + super::HTML_ESCAPES[super::HTML_ESCAPE_TABLE[escape_ix] as usize]; + w.write_str(&s.get_unchecked(mark..i))?; + mark = i + 1; // all escaped characters are ASCII + w.write_str(replacement) + })?; + w.write_str(&s.get_unchecked(mark..)) + } + } else { + super::escape_html_scalar(w, s) + } + } + + /// Creates the lookup table for use in `compute_mask`. + const fn create_lookup() -> [u8; 16] { + let mut table = [0; 16]; + table[(b'<' & 0x0f) as usize] = b'<'; + table[(b'>' & 0x0f) as usize] = b'>'; + table[(b'&' & 0x0f) as usize] = b'&'; + table[(b'"' & 0x0f) as usize] = b'"'; + table[0] = 0b0111_1111; + table + } + + #[target_feature(enable = "ssse3")] + /// Computes a byte mask at given offset in the byte buffer. Its first 16 (least significant) + /// bits correspond to whether there is an HTML special byte (&, <, ", >) at the 16 bytes + /// `bytes[offset..]`. For example, the mask `(1 << 3)` states that there is an HTML byte + /// at `offset + 3`. It is only safe to call this function when + /// `bytes.len() >= offset + VECTOR_SIZE`. + unsafe fn compute_mask(bytes: &[u8], offset: usize) -> i32 { + debug_assert!(bytes.len() >= offset + VECTOR_SIZE); + + let table = create_lookup(); + let lookup = _mm_loadu_si128(table.as_ptr() as *const __m128i); + let raw_ptr = bytes.as_ptr().offset(offset as isize) as *const __m128i; + + // Load the vector from memory. + let vector = _mm_loadu_si128(raw_ptr); + // We take the least significant 4 bits of every byte and use them as indices + // to map into the lookup vector. + // Note that shuffle maps bytes with their most significant bit set to lookup[0]. + // Bytes that share their lower nibble with an HTML special byte get mapped to that + // corresponding special byte. Note that all HTML special bytes have distinct lower + // nibbles. Other bytes either get mapped to 0 or 127. + let expected = _mm_shuffle_epi8(lookup, vector); + // We compare the original vector to the mapped output. Bytes that shared a lower + // nibble with an HTML special byte match *only* if they are that special byte. Bytes + // that have either a 0 lower nibble or their most significant bit set were mapped to + // 127 and will hence never match. All other bytes have non-zero lower nibbles but + // were mapped to 0 and will therefore also not match. + let matches = _mm_cmpeq_epi8(expected, vector); + + // Translate matches to a bitmask, where every 1 corresponds to a HTML special character + // and a 0 is a non-HTML byte. + _mm_movemask_epi8(matches) + } + + /// Calls the given function with the index of every byte in the given byteslice + /// that is either ", &, <, or > and for no other byte. + /// Make sure to only call this when `bytes.len() >= 16`, undefined behaviour may + /// occur otherwise. + #[target_feature(enable = "ssse3")] + unsafe fn foreach_special_simd( + bytes: &[u8], + mut offset: usize, + mut callback: F, + ) -> io::Result<()> + where + F: FnMut(usize) -> io::Result<()>, + { + // The strategy here is to walk the byte buffer in chunks of VECTOR_SIZE (16) + // bytes at a time starting at the given offset. For each chunk, we compute a + // a bitmask indicating whether the corresponding byte is a HTML special byte. + // We then iterate over all the 1 bits in this mask and call the callback function + // with the corresponding index in the buffer. + // When the number of HTML special bytes in the buffer is relatively low, this + // allows us to quickly go through the buffer without a lookup and for every + // single byte. + + debug_assert!(bytes.len() >= VECTOR_SIZE); + let upperbound = bytes.len() - VECTOR_SIZE; + while offset < upperbound { + let mut mask = compute_mask(bytes, offset); + while mask != 0 { + let ix = mask.trailing_zeros(); + callback(offset + ix as usize)?; + mask ^= mask & -mask; + } + offset += VECTOR_SIZE; + } + + // Final iteration. We align the read with the end of the slice and + // shift off the bytes at start we have already scanned. + let mut mask = compute_mask(bytes, upperbound); + mask >>= offset - upperbound; + while mask != 0 { + let ix = mask.trailing_zeros(); + callback(offset + ix as usize)?; + mask ^= mask & -mask; + } + Ok(()) + } + + #[cfg(test)] + mod html_scan_tests { + #[test] + fn multichunk() { + let mut vec = Vec::new(); + unsafe { + super::foreach_special_simd("&aXaaaa.a'aa9a<>aab&".as_bytes(), 0, |ix| { + Ok(vec.push(ix)) + }) + .unwrap(); + } + assert_eq!(vec, vec![0, 14, 15, 19]); + } + + // only match these bytes, and when we match them, match them VECTOR_SIZE times + #[test] + fn only_right_bytes_matched() { + for b in 0..255u8 { + let right_byte = b == b'&' || b == b'<' || b == b'>' || b == b'"'; + let vek = vec![b; super::VECTOR_SIZE]; + let mut match_count = 0; + unsafe { + super::foreach_special_simd(&vek, 0, |_| { + match_count += 1; + Ok(()) + }) + .unwrap(); + } + assert!((match_count > 0) == (match_count == super::VECTOR_SIZE)); + assert_eq!( + (match_count == super::VECTOR_SIZE), + right_byte, + "match_count: {}, byte: {:?}", + match_count, + b as char + ); + } + } + } +} diff --git a/vendor/pulldown-cmark/src/html.rs b/vendor/pulldown-cmark/src/html.rs index 06e5dc68b6..7b8b630896 100644 --- a/vendor/pulldown-cmark/src/html.rs +++ b/vendor/pulldown-cmark/src/html.rs @@ -1,520 +1,461 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! HTML renderer that takes an iterator of events as input. - -use std::collections::HashMap; -use std::fmt::{Arguments, Write as FmtWrite}; -use std::io::{self, ErrorKind, Write}; - -use crate::escape::{escape_href, escape_html}; -use crate::parse::Event::*; -use crate::parse::{Alignment, CodeBlockKind, Event, LinkType, Tag}; -use crate::strings::CowStr; - -enum TableState { - Head, - Body, -} - -/// This wrapper exists because we can't have both a blanket implementation -/// for all types implementing `Write` and types of the for `&mut W` where -/// `W: StrWrite`. Since we need the latter a lot, we choose to wrap -/// `Write` types. -struct WriteWrapper(W); - -/// Trait that allows writing string slices. This is basically an extension -/// of `std::io::Write` in order to include `String`. -pub(crate) trait StrWrite { - fn write_str(&mut self, s: &str) -> io::Result<()>; - - fn write_fmt(&mut self, args: Arguments) -> io::Result<()>; -} - -impl StrWrite for WriteWrapper -where - W: Write, -{ - #[inline] - fn write_str(&mut self, s: &str) -> io::Result<()> { - self.0.write_all(s.as_bytes()) - } - - #[inline] - fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { - self.0.write_fmt(args) - } -} - -impl<'w> StrWrite for String { - #[inline] - fn write_str(&mut self, s: &str) -> io::Result<()> { - self.push_str(s); - Ok(()) - } - - #[inline] - fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { - // FIXME: translate fmt error to io error? - FmtWrite::write_fmt(self, args).map_err(|_| ErrorKind::Other.into()) - } -} - -impl StrWrite for &'_ mut W -where - W: StrWrite, -{ - #[inline] - fn write_str(&mut self, s: &str) -> io::Result<()> { - (**self).write_str(s) - } - - #[inline] - fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { - (**self).write_fmt(args) - } -} - -struct HtmlWriter<'a, I, W> { - /// Iterator supplying events. - iter: I, - - /// Writer to write to. - writer: W, - - /// Whether or not the last write wrote a newline. - end_newline: bool, - - table_state: TableState, - table_alignments: Vec, - table_cell_index: usize, - numbers: HashMap, usize>, -} - -impl<'a, I, W> HtmlWriter<'a, I, W> -where - I: Iterator>, - W: StrWrite, -{ - fn new(iter: I, writer: W) -> Self { - Self { - iter, - writer, - end_newline: true, - table_state: TableState::Head, - table_alignments: vec![], - table_cell_index: 0, - numbers: HashMap::new(), - } - } - - /// Writes a new line. - fn write_newline(&mut self) -> io::Result<()> { - self.end_newline = true; - self.writer.write_str("\n") - } - - /// Writes a buffer, and tracks whether or not a newline was written. - #[inline] - fn write(&mut self, s: &str) -> io::Result<()> { - self.writer.write_str(s)?; - - if !s.is_empty() { - self.end_newline = s.ends_with('\n'); - } - Ok(()) - } - - pub fn run(mut self) -> io::Result<()> { - while let Some(event) = self.iter.next() { - match event { - Start(tag) => { - self.start_tag(tag)?; - } - End(tag) => { - self.end_tag(tag)?; - } - Text(text) => { - escape_html(&mut self.writer, &text)?; - self.end_newline = text.ends_with('\n'); - } - Code(text) => { - self.write("")?; - escape_html(&mut self.writer, &text)?; - self.write("")?; - } - Html(html) => { - self.write(&html)?; - } - SoftBreak => { - self.write_newline()?; - } - HardBreak => { - self.write("
    \n")?; - } - Rule => { - if self.end_newline { - self.write("
    \n")?; - } else { - self.write("\n
    \n")?; - } - } - FootnoteReference(name) => { - let len = self.numbers.len() + 1; - self.write("")?; - let number = *self.numbers.entry(name).or_insert(len); - write!(&mut self.writer, "{}", number)?; - self.write("")?; - } - TaskListMarker(true) => { - self.write("\n")?; - } - TaskListMarker(false) => { - self.write("\n")?; - } - } - } - Ok(()) - } - - /// Writes the start of an HTML tag. - fn start_tag(&mut self, tag: Tag<'a>) -> io::Result<()> { - match tag { - Tag::Paragraph => { - if self.end_newline { - self.write("

    ") - } else { - self.write("\n

    ") - } - } - Tag::Heading(level) => { - if self.end_newline { - self.end_newline = false; - write!(&mut self.writer, "", level) - } else { - write!(&mut self.writer, "\n", level) - } - } - Tag::Table(alignments) => { - self.table_alignments = alignments; - self.write("") - } - Tag::TableHead => { - self.table_state = TableState::Head; - self.table_cell_index = 0; - self.write("") - } - Tag::TableRow => { - self.table_cell_index = 0; - self.write("") - } - Tag::TableCell => { - match self.table_state { - TableState::Head => { - self.write(" { - self.write(" self.write(" align=\"left\">"), - Some(&Alignment::Center) => self.write(" align=\"center\">"), - Some(&Alignment::Right) => self.write(" align=\"right\">"), - _ => self.write(">"), - } - } - Tag::BlockQuote => { - if self.end_newline { - self.write("
    \n") - } else { - self.write("\n
    \n") - } - } - Tag::CodeBlock(info) => { - if !self.end_newline { - self.write_newline()?; - } - match info { - CodeBlockKind::Fenced(info) => { - let lang = info.split(' ').next().unwrap(); - if lang.is_empty() { - self.write("
    ")
    -                        } else {
    -                            self.write("
    ")
    -                        }
    -                    }
    -                    CodeBlockKind::Indented => self.write("
    "),
    -                }
    -            }
    -            Tag::List(Some(1)) => {
    -                if self.end_newline {
    -                    self.write("
      \n") - } else { - self.write("\n
        \n") - } - } - Tag::List(Some(start)) => { - if self.end_newline { - self.write("
          \n") - } - Tag::List(None) => { - if self.end_newline { - self.write("
    \n")?; - } - Tag::TableHead => { - self.write("\n")?; - self.table_state = TableState::Body; - } - Tag::TableRow => { - self.write("\n")?; - } - Tag::TableCell => { - match self.table_state { - TableState::Head => { - self.write("")?; - } - TableState::Body => { - self.write("")?; - } - } - self.table_cell_index += 1; - } - Tag::BlockQuote => { - self.write("

    \n")?; - } - Tag::CodeBlock(_) => { - self.write("\n")?; - } - Tag::List(Some(_)) => { - self.write("\n")?; - } - Tag::List(None) => { - self.write("\n")?; - } - Tag::Item => { - self.write("\n")?; - } - Tag::Emphasis => { - self.write("")?; - } - Tag::Strong => { - self.write("")?; - } - Tag::Strikethrough => { - self.write("")?; - } - Tag::Link(_, _, _) => { - self.write("")?; - } - Tag::Image(_, _, _) => (), // shouldn't happen, handled in start - Tag::FootnoteDefinition(_) => { - self.write("\n")?; - } - } - Ok(()) - } - - // run raw text, consuming end tag - fn raw_text(&mut self) -> io::Result<()> { - let mut nest = 0; - while let Some(event) = self.iter.next() { - match event { - Start(_) => nest += 1, - End(_) => { - if nest == 0 { - break; - } - nest -= 1; - } - Html(text) | Code(text) | Text(text) => { - escape_html(&mut self.writer, &text)?; - self.end_newline = text.ends_with('\n'); - } - SoftBreak | HardBreak | Rule => { - self.write(" ")?; - } - FootnoteReference(name) => { - let len = self.numbers.len() + 1; - let number = *self.numbers.entry(name).or_insert(len); - write!(&mut self.writer, "[{}]", number)?; - } - TaskListMarker(true) => self.write("[x]")?, - TaskListMarker(false) => self.write("[ ]")?, - } - } - Ok(()) - } -} - -/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and -/// push it to a `String`. -/// -/// # Examples -/// -/// ``` -/// use pulldown_cmark::{html, Parser}; -/// -/// let markdown_str = r#" -/// hello -/// ===== -/// -/// * alpha -/// * beta -/// "#; -/// let parser = Parser::new(markdown_str); -/// -/// let mut html_buf = String::new(); -/// html::push_html(&mut html_buf, parser); -/// -/// assert_eq!(html_buf, r#"

    hello

    -///
      -///
    • alpha
    • -///
    • beta
    • -///
    -/// "#); -/// ``` -pub fn push_html<'a, I>(s: &mut String, iter: I) -where - I: Iterator>, -{ - HtmlWriter::new(iter, s).run().unwrap(); -} - -/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and -/// write it out to a writable stream. -/// -/// **Note**: using this function with an unbuffered writer like a file or socket -/// will result in poor performance. Wrap these in a -/// [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html) to -/// prevent unnecessary slowdowns. -/// -/// # Examples -/// -/// ``` -/// use pulldown_cmark::{html, Parser}; -/// use std::io::Cursor; -/// -/// let markdown_str = r#" -/// hello -/// ===== -/// -/// * alpha -/// * beta -/// "#; -/// let mut bytes = Vec::new(); -/// let parser = Parser::new(markdown_str); -/// -/// html::write_html(Cursor::new(&mut bytes), parser); -/// -/// assert_eq!(&String::from_utf8_lossy(&bytes)[..], r#"

    hello

    -///
      -///
    • alpha
    • -///
    • beta
    • -///
    -/// "#); -/// ``` -pub fn write_html<'a, I, W>(writer: W, iter: I) -> io::Result<()> -where - I: Iterator>, - W: Write, -{ - HtmlWriter::new(iter, WriteWrapper(writer)).run() -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! HTML renderer that takes an iterator of events as input. + +use std::collections::HashMap; +use std::io::{self, Write}; + +use crate::escape::{escape_href, escape_html, StrWrite, WriteWrapper}; +use crate::parse::Event::*; +use crate::parse::{Alignment, CodeBlockKind, Event, LinkType, Tag}; +use crate::strings::CowStr; + +enum TableState { + Head, + Body, +} + +struct HtmlWriter<'a, I, W> { + /// Iterator supplying events. + iter: I, + + /// Writer to write to. + writer: W, + + /// Whether or not the last write wrote a newline. + end_newline: bool, + + table_state: TableState, + table_alignments: Vec, + table_cell_index: usize, + numbers: HashMap, usize>, +} + +impl<'a, I, W> HtmlWriter<'a, I, W> +where + I: Iterator>, + W: StrWrite, +{ + fn new(iter: I, writer: W) -> Self { + Self { + iter, + writer, + end_newline: true, + table_state: TableState::Head, + table_alignments: vec![], + table_cell_index: 0, + numbers: HashMap::new(), + } + } + + /// Writes a new line. + fn write_newline(&mut self) -> io::Result<()> { + self.end_newline = true; + self.writer.write_str("\n") + } + + /// Writes a buffer, and tracks whether or not a newline was written. + #[inline] + fn write(&mut self, s: &str) -> io::Result<()> { + self.writer.write_str(s)?; + + if !s.is_empty() { + self.end_newline = s.ends_with('\n'); + } + Ok(()) + } + + pub fn run(mut self) -> io::Result<()> { + while let Some(event) = self.iter.next() { + match event { + Start(tag) => { + self.start_tag(tag)?; + } + End(tag) => { + self.end_tag(tag)?; + } + Text(text) => { + escape_html(&mut self.writer, &text)?; + self.end_newline = text.ends_with('\n'); + } + Code(text) => { + self.write("")?; + escape_html(&mut self.writer, &text)?; + self.write("")?; + } + Html(html) => { + self.write(&html)?; + } + SoftBreak => { + self.write_newline()?; + } + HardBreak => { + self.write("
    \n")?; + } + Rule => { + if self.end_newline { + self.write("
    \n")?; + } else { + self.write("\n
    \n")?; + } + } + FootnoteReference(name) => { + let len = self.numbers.len() + 1; + self.write("")?; + let number = *self.numbers.entry(name).or_insert(len); + write!(&mut self.writer, "{}", number)?; + self.write("")?; + } + TaskListMarker(true) => { + self.write("\n")?; + } + TaskListMarker(false) => { + self.write("\n")?; + } + } + } + Ok(()) + } + + /// Writes the start of an HTML tag. + fn start_tag(&mut self, tag: Tag<'a>) -> io::Result<()> { + match tag { + Tag::Paragraph => { + if self.end_newline { + self.write("

    ") + } else { + self.write("\n

    ") + } + } + Tag::Heading(level) => { + if self.end_newline { + self.end_newline = false; + write!(&mut self.writer, "", level) + } else { + write!(&mut self.writer, "\n", level) + } + } + Tag::Table(alignments) => { + self.table_alignments = alignments; + self.write("") + } + Tag::TableHead => { + self.table_state = TableState::Head; + self.table_cell_index = 0; + self.write("") + } + Tag::TableRow => { + self.table_cell_index = 0; + self.write("") + } + Tag::TableCell => { + match self.table_state { + TableState::Head => { + self.write(" { + self.write(" self.write(" align=\"left\">"), + Some(&Alignment::Center) => self.write(" align=\"center\">"), + Some(&Alignment::Right) => self.write(" align=\"right\">"), + _ => self.write(">"), + } + } + Tag::BlockQuote => { + if self.end_newline { + self.write("
    \n") + } else { + self.write("\n
    \n") + } + } + Tag::CodeBlock(info) => { + if !self.end_newline { + self.write_newline()?; + } + match info { + CodeBlockKind::Fenced(info) => { + let lang = info.split(' ').next().unwrap(); + if lang.is_empty() { + self.write("
    ")
    +                        } else {
    +                            self.write("
    ")
    +                        }
    +                    }
    +                    CodeBlockKind::Indented => self.write("
    "),
    +                }
    +            }
    +            Tag::List(Some(1)) => {
    +                if self.end_newline {
    +                    self.write("
      \n") + } else { + self.write("\n
        \n") + } + } + Tag::List(Some(start)) => { + if self.end_newline { + self.write("
          \n") + } + Tag::List(None) => { + if self.end_newline { + self.write("
    \n")?; + } + Tag::TableHead => { + self.write("\n")?; + self.table_state = TableState::Body; + } + Tag::TableRow => { + self.write("\n")?; + } + Tag::TableCell => { + match self.table_state { + TableState::Head => { + self.write("")?; + } + TableState::Body => { + self.write("")?; + } + } + self.table_cell_index += 1; + } + Tag::BlockQuote => { + self.write("\n")?; + } + Tag::CodeBlock(_) => { + self.write("\n")?; + } + Tag::List(Some(_)) => { + self.write("\n")?; + } + Tag::List(None) => { + self.write("\n")?; + } + Tag::Item => { + self.write("\n")?; + } + Tag::Emphasis => { + self.write("")?; + } + Tag::Strong => { + self.write("")?; + } + Tag::Strikethrough => { + self.write("")?; + } + Tag::Link(_, _, _) => { + self.write("")?; + } + Tag::Image(_, _, _) => (), // shouldn't happen, handled in start + Tag::FootnoteDefinition(_) => { + self.write("\n")?; + } + } + Ok(()) + } + + // run raw text, consuming end tag + fn raw_text(&mut self) -> io::Result<()> { + let mut nest = 0; + while let Some(event) = self.iter.next() { + match event { + Start(_) => nest += 1, + End(_) => { + if nest == 0 { + break; + } + nest -= 1; + } + Html(text) | Code(text) | Text(text) => { + escape_html(&mut self.writer, &text)?; + self.end_newline = text.ends_with('\n'); + } + SoftBreak | HardBreak | Rule => { + self.write(" ")?; + } + FootnoteReference(name) => { + let len = self.numbers.len() + 1; + let number = *self.numbers.entry(name).or_insert(len); + write!(&mut self.writer, "[{}]", number)?; + } + TaskListMarker(true) => self.write("[x]")?, + TaskListMarker(false) => self.write("[ ]")?, + } + } + Ok(()) + } +} + +/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and +/// push it to a `String`. +/// +/// # Examples +/// +/// ``` +/// use pulldown_cmark::{html, Parser}; +/// +/// let markdown_str = r#" +/// hello +/// ===== +/// +/// * alpha +/// * beta +/// "#; +/// let parser = Parser::new(markdown_str); +/// +/// let mut html_buf = String::new(); +/// html::push_html(&mut html_buf, parser); +/// +/// assert_eq!(html_buf, r#"

    hello

    +///
      +///
    • alpha
    • +///
    • beta
    • +///
    +/// "#); +/// ``` +pub fn push_html<'a, I>(s: &mut String, iter: I) +where + I: Iterator>, +{ + HtmlWriter::new(iter, s).run().unwrap(); +} + +/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and +/// write it out to a writable stream. +/// +/// **Note**: using this function with an unbuffered writer like a file or socket +/// will result in poor performance. Wrap these in a +/// [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html) to +/// prevent unnecessary slowdowns. +/// +/// # Examples +/// +/// ``` +/// use pulldown_cmark::{html, Parser}; +/// use std::io::Cursor; +/// +/// let markdown_str = r#" +/// hello +/// ===== +/// +/// * alpha +/// * beta +/// "#; +/// let mut bytes = Vec::new(); +/// let parser = Parser::new(markdown_str); +/// +/// html::write_html(Cursor::new(&mut bytes), parser); +/// +/// assert_eq!(&String::from_utf8_lossy(&bytes)[..], r#"

    hello

    +///
      +///
    • alpha
    • +///
    • beta
    • +///
    +/// "#); +/// ``` +pub fn write_html<'a, I, W>(writer: W, iter: I) -> io::Result<()> +where + I: Iterator>, + W: Write, +{ + HtmlWriter::new(iter, WriteWrapper(writer)).run() +} diff --git a/vendor/pulldown-cmark/src/lib.rs b/vendor/pulldown-cmark/src/lib.rs index f3f16b3dab..e3618573a4 100644 --- a/vendor/pulldown-cmark/src/lib.rs +++ b/vendor/pulldown-cmark/src/lib.rs @@ -1,76 +1,76 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Pull parser for [CommonMark](https://commonmark.org). This crate provides a [Parser](struct.Parser.html) struct -//! which is an iterator over [Event](enum.Event.html)s. This iterator can be used -//! directly, or to output HTML using the [HTML module](html/index.html). -//! -//! By default, only CommonMark features are enabled. To use extensions like tables, -//! footnotes or task lists, enable them by setting the corresponding flags in the -//! [Options](struct.Options.html) struct. -//! -//! # Example -//! ```rust -//! use pulldown_cmark::{Parser, Options, html}; -//! -//! let markdown_input = "Hello world, this is a ~~complicated~~ *very simple* example."; -//! -//! // Set up options and parser. Strikethroughs are not part of the CommonMark standard -//! // and we therefore must enable it explicitly. -//! let mut options = Options::empty(); -//! options.insert(Options::ENABLE_STRIKETHROUGH); -//! let parser = Parser::new_ext(markdown_input, options); -//! -//! // Write to String buffer. -//! let mut html_output = String::new(); -//! html::push_html(&mut html_output, parser); -//! -//! // Check that the output is what we expected. -//! let expected_html = "

    Hello world, this is a complicated very simple example.

    \n"; -//! assert_eq!(expected_html, &html_output); -//! ``` - -// When compiled for the rustc compiler itself we want to make sure that this is -// an unstable crate. -#![cfg_attr(rustbuild, feature(staged_api, rustc_private))] -#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] - -pub mod html; - -#[macro_use] -extern crate bitflags; -extern crate unicase; - -mod entities; -mod escape; -mod linklabel; -mod parse; -mod puncttable; -mod scanners; -mod strings; -mod tree; - -#[cfg(all(target_arch = "x86_64", feature = "simd"))] -mod simd; - -pub use crate::parse::{ - Alignment, CodeBlockKind, Event, LinkType, OffsetIter, Options, Parser, Tag, -}; -pub use crate::strings::{CowStr, InlineStr}; +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Pull parser for [CommonMark](https://commonmark.org). This crate provides a [Parser](struct.Parser.html) struct +//! which is an iterator over [Event](enum.Event.html)s. This iterator can be used +//! directly, or to output HTML using the [HTML module](html/index.html). +//! +//! By default, only CommonMark features are enabled. To use extensions like tables, +//! footnotes or task lists, enable them by setting the corresponding flags in the +//! [Options](struct.Options.html) struct. +//! +//! # Example +//! ```rust +//! use pulldown_cmark::{Parser, Options, html}; +//! +//! let markdown_input = "Hello world, this is a ~~complicated~~ *very simple* example."; +//! +//! // Set up options and parser. Strikethroughs are not part of the CommonMark standard +//! // and we therefore must enable it explicitly. +//! let mut options = Options::empty(); +//! options.insert(Options::ENABLE_STRIKETHROUGH); +//! let parser = Parser::new_ext(markdown_input, options); +//! +//! // Write to String buffer. +//! let mut html_output = String::new(); +//! html::push_html(&mut html_output, parser); +//! +//! // Check that the output is what we expected. +//! let expected_html = "

    Hello world, this is a complicated very simple example.

    \n"; +//! assert_eq!(expected_html, &html_output); +//! ``` + +// When compiled for the rustc compiler itself we want to make sure that this is +// an unstable crate. +#![cfg_attr(rustbuild, feature(staged_api, rustc_private))] +#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] + +pub mod html; + +#[macro_use] +extern crate bitflags; +extern crate unicase; + +mod entities; +pub mod escape; +mod linklabel; +mod parse; +mod puncttable; +mod scanners; +mod strings; +mod tree; + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +mod simd; + +pub use crate::parse::{ + Alignment, BrokenLink, CodeBlockKind, Event, LinkType, OffsetIter, Options, Parser, Tag, +}; +pub use crate::strings::{CowStr, InlineStr}; diff --git a/vendor/pulldown-cmark/src/linklabel.rs b/vendor/pulldown-cmark/src/linklabel.rs index cfb9c2706b..846210f040 100644 --- a/vendor/pulldown-cmark/src/linklabel.rs +++ b/vendor/pulldown-cmark/src/linklabel.rs @@ -1,135 +1,135 @@ -// Copyright 2018 Google LLC -// -// 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. - -//! Link label parsing and matching. - -use unicase::UniCase; - -use crate::scanners::{is_ascii_whitespace, scan_eol}; -use crate::strings::CowStr; - -pub enum ReferenceLabel<'a> { - Link(CowStr<'a>), - Footnote(CowStr<'a>), -} - -pub type LinkLabel<'a> = UniCase>; - -/// Assumes the opening bracket has already been scanned. -/// The line break handler determines what happens when a linebreak -/// is found. It is passed the bytes following the line break and -/// either returns `Some(k)`, where `k` is the number of bytes to skip, -/// or `None` to abort parsing the label. -/// Returns the number of bytes read (including closing bracket) and label on success. -pub(crate) fn scan_link_label_rest<'t>( - text: &'t str, - linebreak_handler: &dyn Fn(&[u8]) -> Option, -) -> Option<(usize, CowStr<'t>)> { - let bytes = text.as_bytes(); - let mut ix = 0; - let mut only_white_space = true; - let mut codepoints = 0; - // no worries, doesnt allocate until we push things onto it - let mut label = String::new(); - let mut mark = 0; - - loop { - if codepoints >= 1000 { - return None; - } - match *bytes.get(ix)? { - b'[' => return None, - b']' => break, - b'\\' => { - ix += 2; - codepoints += 2; - only_white_space = false; - } - b if is_ascii_whitespace(b) => { - // normalize labels by collapsing whitespaces, including linebreaks - let mut whitespaces = 0; - let mut linebreaks = 0; - let whitespace_start = ix; - - while ix < bytes.len() && is_ascii_whitespace(bytes[ix]) { - if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { - linebreaks += 1; - if linebreaks > 1 { - return None; - } - ix += eol_bytes; - ix += linebreak_handler(&bytes[ix..])?; - whitespaces += 2; // indicate that we need to replace - } else { - whitespaces += if bytes[ix] == b' ' { 1 } else { 2 }; - ix += 1; - } - } - if whitespaces > 1 { - label.push_str(&text[mark..whitespace_start]); - label.push(' '); - mark = ix; - codepoints += ix - whitespace_start; - } else { - codepoints += 1; - } - } - b => { - only_white_space = false; - ix += 1; - if b & 0b1000_0000 != 0 { - codepoints += 1; - } - } - } - } - - if only_white_space { - None - } else { - let cow = if mark == 0 { - text[..ix].into() - } else { - label.push_str(&text[mark..ix]); - label.into() - }; - Some((ix + 1, cow)) - } -} - -#[cfg(test)] -mod test { - use super::scan_link_label_rest; - - #[test] - fn whitespace_normalization() { - let input = "«\t\tBlurry Eyes\t\t»][blurry_eyes]"; - let expected_output = "« Blurry Eyes »"; // regular spaces! - - let (_bytes, normalized_label) = scan_link_label_rest(input, &|_| None).unwrap(); - assert_eq!(expected_output, normalized_label.as_ref()); - } - - #[test] - fn return_carriage_linefeed_ok() { - let input = "hello\r\nworld\r\n]"; - assert!(scan_link_label_rest(input, &|_| Some(0)).is_some()); - } -} +// Copyright 2018 Google LLC +// +// 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. + +//! Link label parsing and matching. + +use unicase::UniCase; + +use crate::scanners::{is_ascii_whitespace, scan_eol}; +use crate::strings::CowStr; + +pub enum ReferenceLabel<'a> { + Link(CowStr<'a>), + Footnote(CowStr<'a>), +} + +pub type LinkLabel<'a> = UniCase>; + +/// Assumes the opening bracket has already been scanned. +/// The line break handler determines what happens when a linebreak +/// is found. It is passed the bytes following the line break and +/// either returns `Some(k)`, where `k` is the number of bytes to skip, +/// or `None` to abort parsing the label. +/// Returns the number of bytes read (including closing bracket) and label on success. +pub(crate) fn scan_link_label_rest<'t>( + text: &'t str, + linebreak_handler: &dyn Fn(&[u8]) -> Option, +) -> Option<(usize, CowStr<'t>)> { + let bytes = text.as_bytes(); + let mut ix = 0; + let mut only_white_space = true; + let mut codepoints = 0; + // no worries, doesnt allocate until we push things onto it + let mut label = String::new(); + let mut mark = 0; + + loop { + if codepoints >= 1000 { + return None; + } + match *bytes.get(ix)? { + b'[' => return None, + b']' => break, + b'\\' => { + ix += 2; + codepoints += 2; + only_white_space = false; + } + b if is_ascii_whitespace(b) => { + // normalize labels by collapsing whitespaces, including linebreaks + let mut whitespaces = 0; + let mut linebreaks = 0; + let whitespace_start = ix; + + while ix < bytes.len() && is_ascii_whitespace(bytes[ix]) { + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + linebreaks += 1; + if linebreaks > 1 { + return None; + } + ix += eol_bytes; + ix += linebreak_handler(&bytes[ix..])?; + whitespaces += 2; // indicate that we need to replace + } else { + whitespaces += if bytes[ix] == b' ' { 1 } else { 2 }; + ix += 1; + } + } + if whitespaces > 1 { + label.push_str(&text[mark..whitespace_start]); + label.push(' '); + mark = ix; + codepoints += ix - whitespace_start; + } else { + codepoints += 1; + } + } + b => { + only_white_space = false; + ix += 1; + if b & 0b1000_0000 != 0 { + codepoints += 1; + } + } + } + } + + if only_white_space { + None + } else { + let cow = if mark == 0 { + text[..ix].into() + } else { + label.push_str(&text[mark..ix]); + label.into() + }; + Some((ix + 1, cow)) + } +} + +#[cfg(test)] +mod test { + use super::scan_link_label_rest; + + #[test] + fn whitespace_normalization() { + let input = "«\t\tBlurry Eyes\t\t»][blurry_eyes]"; + let expected_output = "« Blurry Eyes »"; // regular spaces! + + let (_bytes, normalized_label) = scan_link_label_rest(input, &|_| None).unwrap(); + assert_eq!(expected_output, normalized_label.as_ref()); + } + + #[test] + fn return_carriage_linefeed_ok() { + let input = "hello\r\nworld\r\n]"; + assert!(scan_link_label_rest(input, &|_| Some(0)).is_some()); + } +} diff --git a/vendor/pulldown-cmark/src/main.rs b/vendor/pulldown-cmark/src/main.rs index d0225a4ce7..1a7ea77bc2 100644 --- a/vendor/pulldown-cmark/src/main.rs +++ b/vendor/pulldown-cmark/src/main.rs @@ -1,109 +1,109 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Command line tool to exercise pulldown-cmark. - -use pulldown_cmark::{html, Options, Parser}; - -use std::env; -use std::io::{self, Read}; -use std::mem; - -fn dry_run(text: &str, opts: Options) { - let p = Parser::new_ext(text, opts); - let count = p.count(); - println!("{} events", count); -} - -fn print_events(text: &str, opts: Options) { - let parser = Parser::new_ext(text, opts).into_offset_iter(); - for (event, range) in parser { - println!("{:?}: {:?}", range, event); - } - println!("EOF"); -} - -fn brief(program: &str) -> String { - format!( - "Usage: {} [options]\n\n{}", - program, "Reads markdown from standard input and emits HTML.", - ) -} - -pub fn main() -> std::io::Result<()> { - let args: Vec<_> = env::args().collect(); - let mut opts = getopts::Options::new(); - opts.optflag("h", "help", "this help message"); - opts.optflag("d", "dry-run", "dry run, produce no output"); - opts.optflag("e", "events", "print event sequence instead of rendering"); - opts.optflag("T", "enable-tables", "enable GitHub-style tables"); - opts.optflag("F", "enable-footnotes", "enable Hoedown-style footnotes"); - opts.optflag( - "S", - "enable-strikethrough", - "enable GitHub-style strikethrough", - ); - opts.optflag("L", "enable-tasklists", "enable GitHub-style task lists"); - - let matches = match opts.parse(&args[1..]) { - Ok(m) => m, - Err(f) => { - eprintln!("{}\n{}", f, opts.usage(&brief(&args[0]))); - std::process::exit(1); - } - }; - if matches.opt_present("help") { - println!("{}", opts.usage(&brief(&args[0]))); - return Ok(()); - } - let mut opts = Options::empty(); - if matches.opt_present("enable-tables") { - opts.insert(Options::ENABLE_TABLES); - } - if matches.opt_present("enable-footnotes") { - opts.insert(Options::ENABLE_FOOTNOTES); - } - if matches.opt_present("enable-strikethrough") { - opts.insert(Options::ENABLE_STRIKETHROUGH); - } - if matches.opt_present("enable-tasklists") { - opts.insert(Options::ENABLE_TASKLISTS); - } - - let mut input = String::new(); - io::stdin().lock().read_to_string(&mut input)?; - if matches.opt_present("events") { - print_events(&input, opts); - } else if matches.opt_present("dry-run") { - dry_run(&input, opts); - } else { - let mut p = Parser::new_ext(&input, opts); - let stdio = io::stdout(); - let buffer = std::io::BufWriter::with_capacity(1024 * 1024, stdio.lock()); - html::write_html(buffer, &mut p)?; - // Since the program will now terminate and the memory will be returned - // to the operating system anyway, there is no point in tidely cleaning - // up all the datastructures we have used. We shouldn't do this if we'd - // do other things after this, because this is basically intentionally - // leaking data. Skipping cleanup lets us return a bit (~5%) faster. - mem::forget(p); - } - Ok(()) -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Command line tool to exercise pulldown-cmark. + +use pulldown_cmark::{html, Options, Parser}; + +use std::env; +use std::io::{self, Read}; +use std::mem; + +fn dry_run(text: &str, opts: Options) { + let p = Parser::new_ext(text, opts); + let count = p.count(); + println!("{} events", count); +} + +fn print_events(text: &str, opts: Options) { + let parser = Parser::new_ext(text, opts).into_offset_iter(); + for (event, range) in parser { + println!("{:?}: {:?}", range, event); + } + println!("EOF"); +} + +fn brief(program: &str) -> String { + format!( + "Usage: {} [options]\n\n{}", + program, "Reads markdown from standard input and emits HTML.", + ) +} + +pub fn main() -> std::io::Result<()> { + let args: Vec<_> = env::args().collect(); + let mut opts = getopts::Options::new(); + opts.optflag("h", "help", "this help message"); + opts.optflag("d", "dry-run", "dry run, produce no output"); + opts.optflag("e", "events", "print event sequence instead of rendering"); + opts.optflag("T", "enable-tables", "enable GitHub-style tables"); + opts.optflag("F", "enable-footnotes", "enable Hoedown-style footnotes"); + opts.optflag( + "S", + "enable-strikethrough", + "enable GitHub-style strikethrough", + ); + opts.optflag("L", "enable-tasklists", "enable GitHub-style task lists"); + + let matches = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(f) => { + eprintln!("{}\n{}", f, opts.usage(&brief(&args[0]))); + std::process::exit(1); + } + }; + if matches.opt_present("help") { + println!("{}", opts.usage(&brief(&args[0]))); + return Ok(()); + } + let mut opts = Options::empty(); + if matches.opt_present("enable-tables") { + opts.insert(Options::ENABLE_TABLES); + } + if matches.opt_present("enable-footnotes") { + opts.insert(Options::ENABLE_FOOTNOTES); + } + if matches.opt_present("enable-strikethrough") { + opts.insert(Options::ENABLE_STRIKETHROUGH); + } + if matches.opt_present("enable-tasklists") { + opts.insert(Options::ENABLE_TASKLISTS); + } + + let mut input = String::new(); + io::stdin().lock().read_to_string(&mut input)?; + if matches.opt_present("events") { + print_events(&input, opts); + } else if matches.opt_present("dry-run") { + dry_run(&input, opts); + } else { + let mut p = Parser::new_ext(&input, opts); + let stdio = io::stdout(); + let buffer = std::io::BufWriter::with_capacity(1024 * 1024, stdio.lock()); + html::write_html(buffer, &mut p)?; + // Since the program will now terminate and the memory will be returned + // to the operating system anyway, there is no point in tidely cleaning + // up all the datastructures we have used. We shouldn't do this if we'd + // do other things after this, because this is basically intentionally + // leaking data. Skipping cleanup lets us return a bit (~5%) faster. + mem::forget(p); + } + Ok(()) +} diff --git a/vendor/pulldown-cmark/src/parse.rs b/vendor/pulldown-cmark/src/parse.rs index ab50679f9e..eda6a1906e 100644 --- a/vendor/pulldown-cmark/src/parse.rs +++ b/vendor/pulldown-cmark/src/parse.rs @@ -1,3138 +1,3374 @@ -// Copyright 2017 Google Inc. All rights reserved. -// -// 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. - -//! Tree-based two pass parser. - -use std::cmp::{max, min}; -use std::collections::{HashMap, VecDeque}; -use std::ops::{Index, Range}; - -use unicase::UniCase; - -use crate::linklabel::{scan_link_label_rest, LinkLabel, ReferenceLabel}; -use crate::scanners::*; -use crate::strings::CowStr; -use crate::tree::{Tree, TreeIndex}; - -// Allowing arbitrary depth nested parentheses inside link destinations -// can create denial of service vulnerabilities if we're not careful. -// The simplest countermeasure is to limit their depth, which is -// explicitly allowed by the spec as long as the limit is at least 3: -// https://spec.commonmark.org/0.29/#link-destination -const LINK_MAX_NESTED_PARENS: usize = 5; - -/// Codeblock kind. -#[derive(Clone, Debug, PartialEq)] -pub enum CodeBlockKind<'a> { - Indented, - /// The value contained in the tag describes the language of the code, which may be empty. - Fenced(CowStr<'a>), -} - -impl<'a> CodeBlockKind<'a> { - pub fn is_indented(&self) -> bool { - match *self { - CodeBlockKind::Indented => true, - _ => false, - } - } - - pub fn is_fenced(&self) -> bool { - match *self { - CodeBlockKind::Fenced(_) => true, - _ => false, - } - } -} - -/// Tags for elements that can contain other elements. -#[derive(Clone, Debug, PartialEq)] -pub enum Tag<'a> { - /// A paragraph of text and other inline elements. - Paragraph, - - /// A heading. The field indicates the level of the heading. - Heading(u32), - - BlockQuote, - /// A code block. - CodeBlock(CodeBlockKind<'a>), - - /// A list. If the list is ordered the field indicates the number of the first item. - /// Contains only list items. - List(Option), // TODO: add delim and tight for ast (not needed for html) - /// A list item. - Item, - /// A footnote definition. The value contained is the footnote's label by which it can - /// be referred to. - FootnoteDefinition(CowStr<'a>), - - /// A table. Contains a vector describing the text-alignment for each of its columns. - Table(Vec), - /// A table header. Contains only `TableRow`s. Note that the table body starts immediately - /// after the closure of the `TableHead` tag. There is no `TableBody` tag. - TableHead, - /// A table row. Is used both for header rows as body rows. Contains only `TableCell`s. - TableRow, - TableCell, - - // span-level tags - Emphasis, - Strong, - Strikethrough, - - /// A link. The first field is the link type, the second the destination URL and the third is a title. - Link(LinkType, CowStr<'a>, CowStr<'a>), - - /// An image. The first field is the link type, the second the destination URL and the third is a title. - Image(LinkType, CowStr<'a>, CowStr<'a>), -} - -/// Type specifier for inline links. See [the Tag::Link](enum.Tag.html#variant.Link) for more information. -#[derive(Clone, Debug, PartialEq, Copy)] -pub enum LinkType { - /// Inline link like `[foo](bar)` - Inline, - /// Reference link like `[foo][bar]` - Reference, - /// Reference without destination in the document, but resolved by the broken_link_callback - ReferenceUnknown, - /// Collapsed link like `[foo][]` - Collapsed, - /// Collapsed link without destination in the document, but resolved by the broken_link_callback - CollapsedUnknown, - /// Shortcut link like `[foo]` - Shortcut, - /// Shortcut without destination in the document, but resolved by the broken_link_callback - ShortcutUnknown, - /// Autolink like `` - Autolink, - /// Email address in autolink like `` - Email, -} - -impl LinkType { - fn to_unknown(self) -> Self { - match self { - LinkType::Reference => LinkType::ReferenceUnknown, - LinkType::Collapsed => LinkType::CollapsedUnknown, - LinkType::Shortcut => LinkType::ShortcutUnknown, - _ => unreachable!(), - } - } -} - -/// Markdown events that are generated in a preorder traversal of the document -/// tree, with additional `End` events whenever all of an inner node's children -/// have been visited. -#[derive(Clone, Debug, PartialEq)] -pub enum Event<'a> { - /// Start of a tagged element. Events that are yielded after this event - /// and before its corresponding `End` event are inside this element. - /// Start and end events are guaranteed to be balanced. - Start(Tag<'a>), - /// End of a tagged element. - End(Tag<'a>), - /// A text node. - Text(CowStr<'a>), - /// An inline code node. - Code(CowStr<'a>), - /// An HTML node. - Html(CowStr<'a>), - /// A reference to a footnote with given label, which may or may not be defined - /// by an event with a `Tag::FootnoteDefinition` tag. Definitions and references to them may - /// occur in any order. - FootnoteReference(CowStr<'a>), - /// A soft line break. - SoftBreak, - /// A hard line break. - HardBreak, - /// A horizontal ruler. - Rule, - /// A task list marker, rendered as a checkbox in HTML. Contains a true when it is checked. - TaskListMarker(bool), -} - -/// Table column text alignment. -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum Alignment { - /// Default text alignment. - None, - Left, - Center, - Right, -} - -bitflags! { - /// Option struct containing flags for enabling extra features - /// that are not part of the CommonMark spec. - pub struct Options: u32 { - const ENABLE_TABLES = 1 << 1; - const ENABLE_FOOTNOTES = 1 << 2; - const ENABLE_STRIKETHROUGH = 1 << 3; - const ENABLE_TASKLISTS = 1 << 4; - } -} - -#[derive(Debug, Default, Clone, Copy)] -struct Item { - start: usize, - end: usize, - body: ItemBody, -} - -#[derive(Debug, PartialEq, Clone, Copy)] -enum ItemBody { - Paragraph, - Text, - SoftBreak, - HardBreak, - - // These are possible inline items, need to be resolved in second pass. - - // repeats, can_open, can_close - MaybeEmphasis(usize, bool, bool), - MaybeCode(usize, bool), // number of backticks, preceeded by backslash - MaybeHtml, - MaybeLinkOpen, - MaybeLinkClose, - MaybeImage, - - // These are inline items after resolution. - Emphasis, - Strong, - Strikethrough, - Code(CowIndex), - Link(LinkIndex), - Image(LinkIndex), - FootnoteReference(CowIndex), - TaskListMarker(bool), // true for checked - - Rule, - Heading(u32), // heading level - FencedCodeBlock(CowIndex), - IndentCodeBlock, - Html, - BlockQuote, - List(bool, u8, u64), // is_tight, list character, list start index - ListItem(usize), // indent level - SynthesizeText(CowIndex), - FootnoteDefinition(CowIndex), - - // Tables - Table(AlignmentIndex), - TableHead, - TableRow, - TableCell, - - // Dummy node at the top of the tree - should not be used otherwise! - Root, -} - -impl<'a> ItemBody { - fn is_inline(&self) -> bool { - match *self { - ItemBody::MaybeEmphasis(..) - | ItemBody::MaybeHtml - | ItemBody::MaybeCode(..) - | ItemBody::MaybeLinkOpen - | ItemBody::MaybeLinkClose - | ItemBody::MaybeImage => true, - _ => false, - } - } -} - -impl<'a> Default for ItemBody { - fn default() -> Self { - ItemBody::Root - } -} - -/// Scanning modes for `Parser`'s `parse_line` method. -#[derive(PartialEq, Eq, Copy, Clone)] -enum TableParseMode { - /// Inside a paragraph, scanning for table headers. - Scan, - /// Inside a table. - Active, - /// Inside a paragraph, not scanning for table headers. - Disabled, -} - -/// State for the first parsing pass. -/// -/// The first pass resolves all block structure, generating an AST. Within a block, items -/// are in a linear chain with potential inline markup identified. -struct FirstPass<'a> { - text: &'a str, - tree: Tree, - begin_list_item: bool, - last_line_blank: bool, - allocs: Allocations<'a>, - options: Options, - list_nesting: usize, -} - -impl<'a> FirstPass<'a> { - fn new(text: &'a str, options: Options) -> FirstPass { - // This is a very naive heuristic for the number of nodes - // we'll need. - let start_capacity = max(128, text.len() / 32); - let tree = Tree::with_capacity(start_capacity); - let begin_list_item = false; - let last_line_blank = false; - let allocs = Allocations::new(); - FirstPass { - text, - tree, - begin_list_item, - last_line_blank, - allocs, - options, - list_nesting: 0, - } - } - - fn run(mut self) -> (Tree, Allocations<'a>) { - let mut ix = 0; - while ix < self.text.len() { - ix = self.parse_block(ix); - } - for _ in 0..self.tree.spine_len() { - self.pop(ix); - } - (self.tree, self.allocs) - } - - /// Returns offset after block. - fn parse_block(&mut self, mut start_ix: usize) -> usize { - let bytes = self.text.as_bytes(); - let mut line_start = LineStart::new(&bytes[start_ix..]); - - let i = scan_containers(&self.tree, &mut line_start); - for _ in i..self.tree.spine_len() { - self.pop(start_ix); - } - - if self.options.contains(Options::ENABLE_FOOTNOTES) { - // finish footnote if it's still open and was preceeded by blank line - if let Some(node_ix) = self.tree.peek_up() { - if let ItemBody::FootnoteDefinition(..) = self.tree[node_ix].item.body { - if self.last_line_blank { - self.pop(start_ix); - } - } - } - - // Footnote definitions of the form - // [^bar]: - // * anything really - let container_start = start_ix + line_start.bytes_scanned(); - if let Some(bytecount) = self.parse_footnote(container_start) { - start_ix = container_start + bytecount; - start_ix += scan_blank_line(&bytes[start_ix..]).unwrap_or(0); - line_start = LineStart::new(&bytes[start_ix..]); - } - } - - // Process new containers - loop { - let container_start = start_ix + line_start.bytes_scanned(); - if let Some((ch, index, indent)) = line_start.scan_list_marker() { - let after_marker_index = start_ix + line_start.bytes_scanned(); - self.continue_list(container_start, ch, index); - self.tree.append(Item { - start: container_start, - end: after_marker_index, // will get updated later if item not empty - body: ItemBody::ListItem(indent), - }); - self.tree.push(); - if let Some(n) = scan_blank_line(&bytes[after_marker_index..]) { - self.begin_list_item = true; - return after_marker_index + n; - } - if self.options.contains(Options::ENABLE_TASKLISTS) { - if let Some(is_checked) = line_start.scan_task_list_marker() { - self.tree.append(Item { - start: after_marker_index, - end: start_ix + line_start.bytes_scanned(), - body: ItemBody::TaskListMarker(is_checked), - }); - } - } - } else if line_start.scan_blockquote_marker() { - self.finish_list(start_ix); - self.tree.append(Item { - start: container_start, - end: 0, // will get set later - body: ItemBody::BlockQuote, - }); - self.tree.push(); - } else { - break; - } - } - - let ix = start_ix + line_start.bytes_scanned(); - - if let Some(n) = scan_blank_line(&bytes[ix..]) { - if let Some(node_ix) = self.tree.peek_up() { - match self.tree[node_ix].item.body { - ItemBody::BlockQuote => (), - _ => { - if self.begin_list_item { - // A list item can begin with at most one blank line. - self.pop(start_ix); - } - self.last_line_blank = true; - } - } - } - return ix + n; - } - - self.begin_list_item = false; - self.finish_list(start_ix); - - // Save `remaining_space` here to avoid needing to backtrack `line_start` for HTML blocks - let remaining_space = line_start.remaining_space(); - - let indent = line_start.scan_space_upto(4); - if indent == 4 { - let ix = start_ix + line_start.bytes_scanned(); - let remaining_space = line_start.remaining_space(); - return self.parse_indented_code_block(ix, remaining_space); - } - - let ix = start_ix + line_start.bytes_scanned(); - - // HTML Blocks - if bytes[ix] == b'<' { - // Types 1-5 are all detected by one function and all end with the same - // pattern - if let Some(html_end_tag) = get_html_end_tag(&bytes[(ix + 1)..]) { - return self.parse_html_block_type_1_to_5(ix, html_end_tag, remaining_space); - } - - // Detect type 6 - let possible_tag = scan_html_block_tag(&bytes[(ix + 1)..]).1; - if is_html_tag(possible_tag) { - return self.parse_html_block_type_6_or_7(ix, remaining_space); - } - - // Detect type 7 - if let Some(_html_bytes) = scan_html_type_7(&bytes[(ix + 1)..]) { - return self.parse_html_block_type_6_or_7(ix, remaining_space); - } - } - - if let Ok(n) = scan_hrule(&bytes[ix..]) { - return self.parse_hrule(n, ix); - } - - if let Some(atx_size) = scan_atx_heading(&bytes[ix..]) { - return self.parse_atx_heading(ix, atx_size); - } - - // parse refdef - if let Some((bytecount, label, link_def)) = self.parse_refdef_total(ix) { - self.allocs.refdefs.entry(label).or_insert(link_def); - let ix = ix + bytecount; - // try to read trailing whitespace or it will register as a completely blank line - // TODO: shouldn't we do this for all block level items? - return ix + scan_blank_line(&bytes[ix..]).unwrap_or(0); - } - - if let Some((n, fence_ch)) = scan_code_fence(&bytes[ix..]) { - return self.parse_fenced_code_block(ix, indent, fence_ch, n); - } - self.parse_paragraph(ix) - } - - /// Returns the offset of the first line after the table. - /// Assumptions: current focus is a table element and the table header - /// matches the separator line (same number of columns). - fn parse_table(&mut self, table_cols: usize, head_start: usize, body_start: usize) -> usize { - // parse header. this shouldn't fail because we made sure the table header is ok - let (_sep_start, thead_ix) = self.parse_table_row_inner(head_start, table_cols); - self.tree[thead_ix].item.body = ItemBody::TableHead; - - // parse body - let mut ix = body_start; - while let Some((next_ix, _row_ix)) = self.parse_table_row(ix, table_cols) { - ix = next_ix; - } - - self.pop(ix); - ix - } - - /// Call this when containers are taken care of. - /// Returns bytes scanned, row_ix - fn parse_table_row_inner(&mut self, mut ix: usize, row_cells: usize) -> (usize, TreeIndex) { - let bytes = self.text.as_bytes(); - let mut cells = 0; - let mut final_cell_ix = None; - - let row_ix = self.tree.append(Item { - start: ix, - end: 0, // set at end of this function - body: ItemBody::TableRow, - }); - self.tree.push(); - - loop { - ix += scan_ch(&bytes[ix..], b'|'); - ix += scan_whitespace_no_nl(&bytes[ix..]); - - if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { - ix += eol_bytes; - break; - } - - let cell_ix = self.tree.append(Item { - start: ix, - end: ix, - body: ItemBody::TableCell, - }); - self.tree.push(); - let (next_ix, _brk) = self.parse_line(ix, TableParseMode::Active); - let trailing_whitespace = scan_rev_while(&bytes[..next_ix], is_ascii_whitespace); - - if let Some(cur_ix) = self.tree.cur() { - self.tree[cur_ix].item.end -= trailing_whitespace; - } - - self.tree[cell_ix].item.end = next_ix - trailing_whitespace; - self.tree.pop(); - - ix = next_ix; - cells += 1; - - if cells == row_cells { - final_cell_ix = Some(cell_ix); - } - } - - // fill empty cells if needed - // note: this is where GFM and commonmark-extra diverge. we follow - // GFM here - for _ in cells..row_cells { - self.tree.append(Item { - start: ix, - end: ix, - body: ItemBody::TableCell, - }); - } - - // drop excess cells - if let Some(cell_ix) = final_cell_ix { - self.tree[cell_ix].next = None; - } - - self.pop(ix); - - (ix, row_ix) - } - - /// Returns first offset after the row and the tree index of the row. - fn parse_table_row(&mut self, mut ix: usize, row_cells: usize) -> Option<(usize, TreeIndex)> { - let bytes = self.text.as_bytes(); - let mut line_start = LineStart::new(&bytes[ix..]); - let containers = scan_containers(&self.tree, &mut line_start); - if containers != self.tree.spine_len() { - return None; - } - line_start.scan_all_space(); - ix += line_start.bytes_scanned(); - if scan_paragraph_interrupt(&bytes[ix..]) { - return None; - } - - let (ix, row_ix) = self.parse_table_row_inner(ix, row_cells); - Some((ix, row_ix)) - } - - /// Returns offset of line start after paragraph. - fn parse_paragraph(&mut self, start_ix: usize) -> usize { - let node_ix = self.tree.append(Item { - start: start_ix, - end: 0, // will get set later - body: ItemBody::Paragraph, - }); - self.tree.push(); - let bytes = self.text.as_bytes(); - - let mut ix = start_ix; - loop { - let scan_mode = if self.options.contains(Options::ENABLE_TABLES) && ix == start_ix { - TableParseMode::Scan - } else { - TableParseMode::Disabled - }; - let (next_ix, brk) = self.parse_line(ix, scan_mode); - - // break out when we find a table - if let Some(Item { - body: ItemBody::Table(alignment_ix), - .. - }) = brk - { - let table_cols = self.allocs[alignment_ix].len(); - self.tree[node_ix].item.body = ItemBody::Table(alignment_ix); - // this clears out any stuff we may have appended - but there may - // be a cleaner way - self.tree[node_ix].child = None; - self.tree.pop(); - self.tree.push(); - return self.parse_table(table_cols, ix, next_ix); - } - - ix = next_ix; - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if !line_start.scan_space(4) { - let ix_new = ix + line_start.bytes_scanned(); - if n_containers == self.tree.spine_len() { - if let Some(ix_setext) = self.parse_setext_heading(ix_new, node_ix) { - if let Some(Item { - start, - body: ItemBody::HardBreak, - .. - }) = brk - { - if bytes[start] == b'\\' { - self.tree.append_text(start, start + 1); - } - } - ix = ix_setext; - break; - } - } - // first check for non-empty lists, then for other interrupts - let suffix = &bytes[ix_new..]; - if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { - break; - } - } - line_start.scan_all_space(); - if line_start.is_at_eol() { - break; - } - ix = next_ix + line_start.bytes_scanned(); - if let Some(item) = brk { - self.tree.append(item); - } - } - - self.pop(ix); - ix - } - - /// Returns end ix of setext_heading on success. - fn parse_setext_heading(&mut self, ix: usize, node_ix: TreeIndex) -> Option { - let bytes = self.text.as_bytes(); - let (n, level) = scan_setext_heading(&bytes[ix..])?; - self.tree[node_ix].item.body = ItemBody::Heading(level); - - // strip trailing whitespace - if let Some(cur_ix) = self.tree.cur() { - self.tree[cur_ix].item.end -= scan_rev_while( - &bytes[..self.tree[cur_ix].item.end], - is_ascii_whitespace_no_nl, - ); - } - - Some(ix + n) - } - - /// Parse a line of input, appending text and items to tree. - /// - /// Returns: index after line and an item representing the break. - fn parse_line(&mut self, start: usize, mode: TableParseMode) -> (usize, Option) { - let bytes = &self.text.as_bytes(); - let mut pipes = 0; - let mut last_pipe_ix = start; - let mut begin_text = start; - - let (final_ix, brk) = iterate_special_bytes(bytes, start, |ix, byte| { - match byte { - b'\n' | b'\r' => { - if let TableParseMode::Active = mode { - return LoopInstruction::BreakAtWith(ix, None); - } - - let mut i = ix; - let eol_bytes = scan_eol(&bytes[ix..]).unwrap(); - if mode == TableParseMode::Scan && pipes > 0 { - // check if we may be parsing a table - let next_line_ix = ix + eol_bytes; - let mut line_start = LineStart::new(&bytes[next_line_ix..]); - if scan_containers(&self.tree, &mut line_start) == self.tree.spine_len() { - let table_head_ix = next_line_ix + line_start.bytes_scanned(); - let (table_head_bytes, alignment) = - scan_table_head(&bytes[table_head_ix..]); - - if table_head_bytes > 0 { - // computing header count from number of pipes - let header_count = - count_header_cols(bytes, pipes, start, last_pipe_ix); - - // make sure they match the number of columns we find in separator line - if alignment.len() == header_count { - let alignment_ix = self.allocs.allocate_alignment(alignment); - let end_ix = table_head_ix + table_head_bytes; - return LoopInstruction::BreakAtWith( - end_ix, - Some(Item { - start: i, - end: end_ix, // must update later - body: ItemBody::Table(alignment_ix), - }), - ); - } - } - } - } - - let end_ix = ix + eol_bytes; - let trailing_backslashes = scan_rev_while(&bytes[..ix], |b| b == b'\\'); - if trailing_backslashes % 2 == 1 && end_ix < self.text.len() { - i -= 1; - self.tree.append_text(begin_text, i); - return LoopInstruction::BreakAtWith( - end_ix, - Some(Item { - start: i, - end: end_ix, - body: ItemBody::HardBreak, - }), - ); - } - let trailing_whitespace = - scan_rev_while(&bytes[..ix], is_ascii_whitespace_no_nl); - if trailing_whitespace >= 2 { - i -= trailing_whitespace; - self.tree.append_text(begin_text, i); - return LoopInstruction::BreakAtWith( - end_ix, - Some(Item { - start: i, - end: end_ix, - body: ItemBody::HardBreak, - }), - ); - } - - self.tree.append_text(begin_text, ix); - LoopInstruction::BreakAtWith( - end_ix, - Some(Item { - start: i, - end: end_ix, - body: ItemBody::SoftBreak, - }), - ) - } - b'\\' => { - if ix + 1 < self.text.len() && is_ascii_punctuation(bytes[ix + 1]) { - self.tree.append_text(begin_text, ix); - if bytes[ix + 1] == b'`' { - let count = 1 + scan_ch_repeat(&bytes[(ix + 2)..], b'`'); - self.tree.append(Item { - start: ix + 1, - end: ix + count + 1, - body: ItemBody::MaybeCode(count, true), - }); - begin_text = ix + 1 + count; - LoopInstruction::ContinueAndSkip(count) - } else { - begin_text = ix + 1; - LoopInstruction::ContinueAndSkip(1) - } - } else { - LoopInstruction::ContinueAndSkip(0) - } - } - c @ b'*' | c @ b'_' | c @ b'~' => { - let string_suffix = &self.text[ix..]; - let count = 1 + scan_ch_repeat(&string_suffix.as_bytes()[1..], c); - let can_open = delim_run_can_open(self.text, string_suffix, count, ix); - let can_close = delim_run_can_close(self.text, string_suffix, count, ix); - let is_valid_seq = c != b'~' - || count == 2 && self.options.contains(Options::ENABLE_STRIKETHROUGH); - - if (can_open || can_close) && is_valid_seq { - self.tree.append_text(begin_text, ix); - for i in 0..count { - self.tree.append(Item { - start: ix + i, - end: ix + i + 1, - body: ItemBody::MaybeEmphasis(count - i, can_open, can_close), - }); - } - begin_text = ix + count; - } - LoopInstruction::ContinueAndSkip(count - 1) - } - b'`' => { - self.tree.append_text(begin_text, ix); - let count = 1 + scan_ch_repeat(&bytes[(ix + 1)..], b'`'); - self.tree.append(Item { - start: ix, - end: ix + count, - body: ItemBody::MaybeCode(count, false), - }); - begin_text = ix + count; - LoopInstruction::ContinueAndSkip(count - 1) - } - b'<' => { - // Note: could detect some non-HTML cases and early escape here, but not - // clear that's a win. - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + 1, - body: ItemBody::MaybeHtml, - }); - begin_text = ix + 1; - LoopInstruction::ContinueAndSkip(0) - } - b'!' => { - if ix + 1 < self.text.len() && bytes[ix + 1] == b'[' { - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + 2, - body: ItemBody::MaybeImage, - }); - begin_text = ix + 2; - LoopInstruction::ContinueAndSkip(1) - } else { - LoopInstruction::ContinueAndSkip(0) - } - } - b'[' => { - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + 1, - body: ItemBody::MaybeLinkOpen, - }); - begin_text = ix + 1; - LoopInstruction::ContinueAndSkip(0) - } - b']' => { - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + 1, - body: ItemBody::MaybeLinkClose, - }); - begin_text = ix + 1; - LoopInstruction::ContinueAndSkip(0) - } - b'&' => match scan_entity(&bytes[ix..]) { - (n, Some(value)) => { - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + n, - body: ItemBody::SynthesizeText(self.allocs.allocate_cow(value)), - }); - begin_text = ix + n; - LoopInstruction::ContinueAndSkip(n - 1) - } - _ => LoopInstruction::ContinueAndSkip(0), - }, - b'|' => { - if let TableParseMode::Active = mode { - LoopInstruction::BreakAtWith(ix, None) - } else { - last_pipe_ix = ix; - pipes += 1; - LoopInstruction::ContinueAndSkip(0) - } - } - _ => LoopInstruction::ContinueAndSkip(0), - } - }); - - if brk.is_none() { - // need to close text at eof - self.tree.append_text(begin_text, final_ix); - } - (final_ix, brk) - } - - /// Check whether we should allow a paragraph interrupt by lists. Only non-empty - /// lists are allowed. - fn interrupt_paragraph_by_list(&self, suffix: &[u8]) -> bool { - scan_listitem(suffix).map_or(false, |(ix, delim, index, _)| { - self.list_nesting > 0 || - // we don't allow interruption by either empty lists or - // numbered lists starting at an index other than 1 - !scan_empty_list(&suffix[ix..]) && (delim == b'*' || delim == b'-' || index == 1) - }) - } - - /// When start_ix is at the beginning of an HTML block of type 1 to 5, - /// this will find the end of the block, adding the block itself to the - /// tree and also keeping track of the lines of HTML within the block. - /// - /// The html_end_tag is the tag that must be found on a line to end the block. - fn parse_html_block_type_1_to_5( - &mut self, - start_ix: usize, - html_end_tag: &str, - mut remaining_space: usize, - ) -> usize { - let bytes = self.text.as_bytes(); - let mut ix = start_ix; - loop { - let line_start_ix = ix; - ix += scan_nextline(&bytes[ix..]); - self.append_html_line(remaining_space, line_start_ix, ix); - - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if n_containers < self.tree.spine_len() { - break; - } - - if (&self.text[line_start_ix..ix]).contains(html_end_tag) { - break; - } - - let next_line_ix = ix + line_start.bytes_scanned(); - if next_line_ix == self.text.len() { - break; - } - ix = next_line_ix; - remaining_space = line_start.remaining_space(); - } - ix - } - - /// When start_ix is at the beginning of an HTML block of type 6 or 7, - /// this will consume lines until there is a blank line and keep track of - /// the HTML within the block. - fn parse_html_block_type_6_or_7( - &mut self, - start_ix: usize, - mut remaining_space: usize, - ) -> usize { - let bytes = self.text.as_bytes(); - let mut ix = start_ix; - loop { - let line_start_ix = ix; - ix += scan_nextline(&bytes[ix..]); - self.append_html_line(remaining_space, line_start_ix, ix); - - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if n_containers < self.tree.spine_len() || line_start.is_at_eol() { - break; - } - - let next_line_ix = ix + line_start.bytes_scanned(); - if next_line_ix == self.text.len() || scan_blank_line(&bytes[next_line_ix..]).is_some() - { - break; - } - ix = next_line_ix; - remaining_space = line_start.remaining_space(); - } - ix - } - - fn parse_indented_code_block(&mut self, start_ix: usize, mut remaining_space: usize) -> usize { - self.tree.append(Item { - start: start_ix, - end: 0, // will get set later - body: ItemBody::IndentCodeBlock, - }); - self.tree.push(); - let bytes = self.text.as_bytes(); - let mut last_nonblank_child = None; - let mut last_nonblank_ix = 0; - let mut end_ix = 0; - let mut last_line_blank = false; - - let mut ix = start_ix; - loop { - let line_start_ix = ix; - ix += scan_nextline(&bytes[ix..]); - self.append_code_text(remaining_space, line_start_ix, ix); - // TODO(spec clarification): should we synthesize newline at EOF? - - if !last_line_blank { - last_nonblank_child = self.tree.cur(); - last_nonblank_ix = ix; - end_ix = ix; - } - - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if n_containers < self.tree.spine_len() - || !(line_start.scan_space(4) || line_start.is_at_eol()) - { - break; - } - let next_line_ix = ix + line_start.bytes_scanned(); - if next_line_ix == self.text.len() { - break; - } - ix = next_line_ix; - remaining_space = line_start.remaining_space(); - last_line_blank = scan_blank_line(&bytes[ix..]).is_some(); - } - - // Trim trailing blank lines. - if let Some(child) = last_nonblank_child { - self.tree[child].next = None; - self.tree[child].item.end = last_nonblank_ix; - } - self.pop(end_ix); - ix - } - - fn parse_fenced_code_block( - &mut self, - start_ix: usize, - indent: usize, - fence_ch: u8, - n_fence_char: usize, - ) -> usize { - let bytes = self.text.as_bytes(); - let mut info_start = start_ix + n_fence_char; - info_start += scan_whitespace_no_nl(&bytes[info_start..]); - // TODO: info strings are typically very short. wouldnt it be faster - // to just do a forward scan here? - let mut ix = info_start + scan_nextline(&bytes[info_start..]); - let info_end = ix - scan_rev_while(&bytes[info_start..ix], is_ascii_whitespace); - let info_string = unescape(&self.text[info_start..info_end]); - self.tree.append(Item { - start: start_ix, - end: 0, // will get set later - body: ItemBody::FencedCodeBlock(self.allocs.allocate_cow(info_string)), - }); - self.tree.push(); - loop { - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if n_containers < self.tree.spine_len() { - break; - } - line_start.scan_space(indent); - let mut close_line_start = line_start.clone(); - if !close_line_start.scan_space(4) { - let close_ix = ix + close_line_start.bytes_scanned(); - if let Some(n) = scan_closing_code_fence(&bytes[close_ix..], fence_ch, n_fence_char) - { - ix = close_ix + n; - break; - } - } - let remaining_space = line_start.remaining_space(); - ix += line_start.bytes_scanned(); - let next_ix = ix + scan_nextline(&bytes[ix..]); - self.append_code_text(remaining_space, ix, next_ix); - ix = next_ix; - } - - self.pop(ix); - - // try to read trailing whitespace or it will register as a completely blank line - ix + scan_blank_line(&bytes[ix..]).unwrap_or(0) - } - - fn append_code_text(&mut self, remaining_space: usize, start: usize, end: usize) { - if remaining_space > 0 { - let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); - self.tree.append(Item { - start, - end: start, - body: ItemBody::SynthesizeText(cow_ix), - }); - } - if self.text.as_bytes()[end - 2] == b'\r' { - // Normalize CRLF to LF - self.tree.append_text(start, end - 2); - self.tree.append_text(end - 1, end); - } else { - self.tree.append_text(start, end); - } - } - - /// Appends a line of HTML to the tree. - fn append_html_line(&mut self, remaining_space: usize, start: usize, end: usize) { - if remaining_space > 0 { - let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); - self.tree.append(Item { - start, - end: start, - // TODO: maybe this should synthesize to html rather than text? - body: ItemBody::SynthesizeText(cow_ix), - }); - } - if self.text.as_bytes()[end - 2] == b'\r' { - // Normalize CRLF to LF - self.tree.append(Item { - start, - end: end - 2, - body: ItemBody::Html, - }); - self.tree.append(Item { - start: end - 1, - end, - body: ItemBody::Html, - }); - } else { - self.tree.append(Item { - start, - end, - body: ItemBody::Html, - }); - } - } - - /// Pop a container, setting its end. - fn pop(&mut self, ix: usize) { - let cur_ix = self.tree.pop().unwrap(); - self.tree[cur_ix].item.end = ix; - if let ItemBody::List(true, _, _) = self.tree[cur_ix].item.body { - surgerize_tight_list(&mut self.tree, cur_ix); - } - } - - /// Close a list if it's open. Also set loose if last line was blank - fn finish_list(&mut self, ix: usize) { - if let Some(node_ix) = self.tree.peek_up() { - if let ItemBody::List(_, _, _) = self.tree[node_ix].item.body { - self.pop(ix); - self.list_nesting -= 1; - } - } - if self.last_line_blank { - if let Some(node_ix) = self.tree.peek_grandparent() { - if let ItemBody::List(ref mut is_tight, _, _) = self.tree[node_ix].item.body { - *is_tight = false; - } - } - self.last_line_blank = false; - } - } - - /// Continue an existing list or start a new one if there's not an open - /// list that matches. - fn continue_list(&mut self, start: usize, ch: u8, index: u64) { - if let Some(node_ix) = self.tree.peek_up() { - if let ItemBody::List(ref mut is_tight, existing_ch, _) = self.tree[node_ix].item.body { - if existing_ch == ch { - if self.last_line_blank { - *is_tight = false; - self.last_line_blank = false; - } - return; - } - } - // TODO: this is not the best choice for end; maybe get end from last list item. - self.finish_list(start); - } - self.tree.append(Item { - start, - end: 0, // will get set later - body: ItemBody::List(true, ch, index), - }); - self.list_nesting += 1; - self.tree.push(); - self.last_line_blank = false; - } - - /// Parse a thematic break. - /// - /// Returns index of start of next line. - fn parse_hrule(&mut self, hrule_size: usize, ix: usize) -> usize { - self.tree.append(Item { - start: ix, - end: ix + hrule_size, - body: ItemBody::Rule, - }); - ix + hrule_size - } - - /// Parse an ATX heading. - /// - /// Returns index of start of next line. - fn parse_atx_heading(&mut self, mut ix: usize, atx_size: usize) -> usize { - let heading_ix = self.tree.append(Item { - start: ix, - end: 0, // set later - body: ItemBody::Heading(atx_size as u32), - }); - ix += atx_size; - // next char is space or eol (guaranteed by scan_atx_heading) - let bytes = self.text.as_bytes(); - if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { - self.tree[heading_ix].item.end = ix + eol_bytes; - return ix + eol_bytes; - } - // skip leading spaces - let skip_spaces = scan_whitespace_no_nl(&bytes[ix..]); - ix += skip_spaces; - - // now handle the header text - let header_start = ix; - let header_node_idx = self.tree.push(); // so that we can set the endpoint later - ix = self.parse_line(ix, TableParseMode::Disabled).0; - self.tree[header_node_idx].item.end = ix; - - // remove trailing matter from header text - if let Some(cur_ix) = self.tree.cur() { - let header_text = &bytes[header_start..ix]; - let mut limit = header_text - .iter() - .rposition(|&b| !(b == b'\n' || b == b'\r' || b == b' ')) - .map_or(0, |i| i + 1); - let closer = header_text[..limit] - .iter() - .rposition(|&b| b != b'#') - .map_or(0, |i| i + 1); - if closer == 0 { - limit = closer; - } else { - let spaces = scan_rev_while(&header_text[..closer], |b| b == b' '); - if spaces > 0 { - limit = closer - spaces; - } - } - self.tree[cur_ix].item.end = limit + header_start; - } - - self.tree.pop(); - ix - } - - /// Returns the number of bytes scanned on success. - fn parse_footnote(&mut self, start: usize) -> Option { - let bytes = &self.text.as_bytes()[start..]; - if !bytes.starts_with(b"[^") { - return None; - } - let (mut i, label) = self.parse_refdef_label(start + 2)?; - i += 2; - if scan_ch(&bytes[i..], b':') == 0 { - return None; - } - i += 1; - self.finish_list(start); - self.tree.append(Item { - start, - end: 0, // will get set later - // TODO: check whether the label here is strictly necessary - body: ItemBody::FootnoteDefinition(self.allocs.allocate_cow(label)), - }); - self.tree.push(); - Some(i) - } - - /// Tries to parse a reference label, which can be interrupted by new blocks. - /// On success, returns the number of bytes of the label and the label itself. - fn parse_refdef_label(&self, start: usize) -> Option<(usize, CowStr<'a>)> { - scan_link_label_rest(&self.text[start..], &|bytes| { - let mut line_start = LineStart::new(bytes); - let _ = scan_containers(&self.tree, &mut line_start); - let bytes_scanned = line_start.bytes_scanned(); - - let suffix = &bytes[bytes_scanned..]; - if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { - None - } else { - Some(bytes_scanned) - } - }) - } - - /// Returns number of bytes scanned, label and definition on success. - fn parse_refdef_total(&mut self, start: usize) -> Option<(usize, LinkLabel<'a>, LinkDef<'a>)> { - let bytes = &self.text.as_bytes()[start..]; - if scan_ch(bytes, b'[') == 0 { - return None; - } - let (mut i, label) = self.parse_refdef_label(start + 1)?; - i += 1; - if scan_ch(&bytes[i..], b':') == 0 { - return None; - } - i += 1; - let (bytecount, link_def) = self.scan_refdef(start + i)?; - Some((bytecount + i, UniCase::new(label), link_def)) - } - - /// Returns number of bytes and number of newlines - fn scan_refdef_space(&self, bytes: &[u8], mut i: usize) -> Option<(usize, usize)> { - let mut newlines = 0; - loop { - let whitespaces = scan_whitespace_no_nl(&bytes[i..]); - i += whitespaces; - if let Some(eol_bytes) = scan_eol(&bytes[i..]) { - i += eol_bytes; - newlines += 1; - if newlines > 1 { - return None; - } - } else { - break; - } - let mut line_start = LineStart::new(&bytes[i..]); - if self.tree.spine_len() != scan_containers(&self.tree, &mut line_start) { - return None; - } - i += line_start.bytes_scanned(); - } - Some((i, newlines)) - } - - /// Returns # of bytes and definition. - /// Assumes the label of the reference including colon has already been scanned. - fn scan_refdef(&self, start: usize) -> Option<(usize, LinkDef<'a>)> { - let bytes = self.text.as_bytes(); - - // whitespace between label and url (including up to one newline) - let (mut i, _newlines) = self.scan_refdef_space(bytes, start)?; - - // scan link dest - let (dest_length, dest) = scan_link_dest(self.text, i, 1)?; - if dest_length == 0 { - return None; - } - let dest = unescape(dest); - i += dest_length; - - // no title - let mut backup = (i - start, LinkDef { dest, title: None }); - - // scan whitespace between dest and label - let (mut i, newlines) = - if let Some((new_i, mut newlines)) = self.scan_refdef_space(bytes, i) { - if i == self.text.len() { - newlines += 1; - } - if new_i == i && newlines == 0 { - return None; - } - if newlines > 1 { - return Some(backup); - }; - (new_i, newlines) - } else { - return Some(backup); - }; - - // scan title - // if this fails but newline == 1, return also a refdef without title - if let Some((title_length, title)) = scan_refdef_title(&self.text[i..]) { - i += title_length; - backup.1.title = Some(unescape(title)); - } else if newlines > 0 { - return Some(backup); - } else { - return None; - }; - - // scan EOL - if let Some(bytes) = scan_blank_line(&bytes[i..]) { - backup.0 = i + bytes - start; - Some(backup) - } else if newlines > 0 { - Some(backup) - } else { - None - } - } -} - -/// Returns number of containers scanned. -fn scan_containers(tree: &Tree, line_start: &mut LineStart) -> usize { - let mut i = 0; - for &node_ix in tree.walk_spine() { - match tree[node_ix].item.body { - ItemBody::BlockQuote => { - let save = line_start.clone(); - if !line_start.scan_blockquote_marker() { - *line_start = save; - break; - } - } - ItemBody::ListItem(indent) => { - let save = line_start.clone(); - if !line_start.scan_space(indent) { - if !line_start.is_at_eol() { - *line_start = save; - break; - } - } - } - _ => (), - } - i += 1; - } - i -} - -/// Computes the number of header columns in a table line by computing the number of dividing pipes -/// that aren't followed or preceeded by whitespace. -fn count_header_cols( - bytes: &[u8], - mut pipes: usize, - mut start: usize, - last_pipe_ix: usize, -) -> usize { - // was first pipe preceeded by whitespace? if so, subtract one - start += scan_whitespace_no_nl(&bytes[start..]); - if bytes[start] == b'|' { - pipes -= 1; - } - - // was last pipe followed by whitespace? if so, sub one - if scan_blank_line(&bytes[(last_pipe_ix + 1)..]).is_some() { - pipes - } else { - pipes + 1 - } -} - -impl<'a> Tree { - fn append_text(&mut self, start: usize, end: usize) { - if end > start { - if let Some(ix) = self.cur() { - if ItemBody::Text == self[ix].item.body && self[ix].item.end == start { - self[ix].item.end = end; - return; - } - } - self.append(Item { - start, - end, - body: ItemBody::Text, - }); - } - } -} - -/// Determines whether the delimiter run starting at given index is -/// left-flanking, as defined by the commonmark spec (and isn't intraword -/// for _ delims). -/// suffix is &s[ix..], which is passed in as an optimization, since taking -/// a string subslice is O(n). -fn delim_run_can_open(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { - let next_char = if let Some(c) = suffix.chars().nth(run_len) { - c - } else { - return false; - }; - if next_char.is_whitespace() { - return false; - } - if ix == 0 { - return true; - } - let delim = suffix.chars().next().unwrap(); - if delim == '*' && !is_punctuation(next_char) { - return true; - } - - let prev_char = s[..ix].chars().last().unwrap(); - - prev_char.is_whitespace() || is_punctuation(prev_char) -} - -/// Determines whether the delimiter run starting at given index is -/// left-flanking, as defined by the commonmark spec (and isn't intraword -/// for _ delims) -fn delim_run_can_close(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { - if ix == 0 { - return false; - } - let prev_char = s[..ix].chars().last().unwrap(); - if prev_char.is_whitespace() { - return false; - } - let next_char = if let Some(c) = suffix.chars().nth(run_len) { - c - } else { - return true; - }; - let delim = suffix.chars().next().unwrap(); - if delim == '*' && !is_punctuation(prev_char) { - return true; - } - - next_char.is_whitespace() || is_punctuation(next_char) -} - -/// Checks whether we should break a paragraph on the given input. -/// Note: lists are dealt with in `interrupt_paragraph_by_list`, because determing -/// whether to break on a list requires additional context. -fn scan_paragraph_interrupt(bytes: &[u8]) -> bool { - if scan_eol(bytes).is_some() - || scan_hrule(bytes).is_ok() - || scan_atx_heading(bytes).is_some() - || scan_code_fence(bytes).is_some() - || scan_blockquote_start(bytes).is_some() - { - return true; - } - bytes.starts_with(b"<") - && (get_html_end_tag(&bytes[1..]).is_some() - || is_html_tag(scan_html_block_tag(&bytes[1..]).1)) -} - -/// Assumes `text_bytes` is preceded by `<`. -fn get_html_end_tag(text_bytes: &[u8]) -> Option<&'static str> { - static BEGIN_TAGS: &[&[u8]; 3] = &[b"pre", b"style", b"script"]; - static ST_BEGIN_TAGS: &[&[u8]; 3] = &[b"!--", b"?", b"![CDATA["]; - - for (beg_tag, end_tag) in BEGIN_TAGS - .iter() - .zip(["", "", ""].iter()) - { - let tag_len = beg_tag.len(); - - if text_bytes.len() < tag_len { - // begin tags are increasing in size - break; - } - - if !text_bytes[..tag_len].eq_ignore_ascii_case(beg_tag) { - continue; - } - - // Must either be the end of the line... - if text_bytes.len() == tag_len { - return Some(end_tag); - } - - // ...or be followed by whitespace, newline, or '>'. - let s = text_bytes[tag_len]; - if is_ascii_whitespace(s) || s == b'>' { - return Some(end_tag); - } - } - - for (beg_tag, end_tag) in ST_BEGIN_TAGS.iter().zip(["-->", "?>", "]]>"].iter()) { - if text_bytes.starts_with(beg_tag) { - return Some(end_tag); - } - } - - if text_bytes.len() > 1 - && text_bytes[0] == b'!' - && text_bytes[1] >= b'A' - && text_bytes[1] <= b'Z' - { - Some(">") - } else { - None - } -} - -#[derive(Copy, Clone, Debug)] -struct InlineEl { - start: TreeIndex, // offset of tree node - count: usize, - c: u8, // b'*' or b'_' - both: bool, // can both open and close -} - -#[derive(Debug, Clone, Default)] -struct InlineStack { - stack: Vec, - // Lower bounds for matching indices in the stack. For example - // a strikethrough delimiter will never match with any element - // in the stack with index smaller than - // `lower_bounds[InlineStack::TILDES]`. - lower_bounds: [usize; 7], -} - -impl InlineStack { - /// These are indices into the lower bounds array. - /// Not both refers to the property that the delimiter can not both - /// be opener as a closer. - const UNDERSCORE_NOT_BOTH: usize = 0; - const ASTERISK_NOT_BOTH: usize = 1; - const ASTERISK_BASE: usize = 2; - const TILDES: usize = 5; - const UNDERSCORE_BOTH: usize = 6; - - fn pop_all(&mut self, tree: &mut Tree) { - for el in self.stack.drain(..) { - for i in 0..el.count { - tree[el.start + i].item.body = ItemBody::Text; - } - } - self.lower_bounds = [0; 7]; - } - - fn get_lowerbound(&self, c: u8, count: usize, both: bool) -> usize { - if c == b'_' { - if both { - self.lower_bounds[InlineStack::UNDERSCORE_BOTH] - } else { - self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] - } - } else if c == b'*' { - let mod3_lower = self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3]; - if both { - mod3_lower - } else { - min( - mod3_lower, - self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH], - ) - } - } else { - self.lower_bounds[InlineStack::TILDES] - } - } - - fn set_lowerbound(&mut self, c: u8, count: usize, both: bool, new_bound: usize) { - if c == b'_' { - if both { - self.lower_bounds[InlineStack::UNDERSCORE_BOTH] = new_bound; - } else { - self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] = new_bound; - } - } else if c == b'*' { - self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3] = new_bound; - if !both { - self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH] = new_bound; - } - } else { - self.lower_bounds[InlineStack::TILDES] = new_bound; - } - } - - fn find_match( - &mut self, - tree: &mut Tree, - c: u8, - count: usize, - both: bool, - ) -> Option { - let lowerbound = min(self.stack.len(), self.get_lowerbound(c, count, both)); - let res = self.stack[lowerbound..] - .iter() - .cloned() - .enumerate() - .rfind(|(_, el)| { - el.c == c && (!both && !el.both || (count + el.count) % 3 != 0 || count % 3 == 0) - }); - - if let Some((matching_ix, matching_el)) = res { - let matching_ix = matching_ix + lowerbound; - for el in &self.stack[(matching_ix + 1)..] { - for i in 0..el.count { - tree[el.start + i].item.body = ItemBody::Text; - } - } - self.stack.truncate(matching_ix); - Some(matching_el) - } else { - self.set_lowerbound(c, count, both, self.stack.len()); - None - } - } - - fn push(&mut self, el: InlineEl) { - self.stack.push(el) - } -} - -#[derive(Debug, Clone)] -enum RefScan<'a> { - // label, next node index, source ix of label end - LinkLabel(CowStr<'a>, Option, usize), - // contains next node index - Collapsed(Option), - Failed, -} - -/// Skips forward within a block to a node which spans (ends inclusive) the given -/// index into the source. -fn scan_nodes_to_ix( - tree: &Tree, - mut node: Option, - ix: usize, -) -> Option { - while let Some(node_ix) = node { - if tree[node_ix].item.end <= ix { - node = tree[node_ix].next; - } else { - break; - } - } - node -} - -/// Scans an inline link label, which cannot be interrupted. -/// Returns number of bytes (including brackets) and label on success. -fn scan_link_label<'text, 'tree>( - tree: &'tree Tree, - text: &'text str, -) -> Option<(usize, ReferenceLabel<'text>)> { - let bytes = &text.as_bytes(); - if bytes.len() < 2 || bytes[0] != b'[' { - return None; - } - let linebreak_handler = |bytes: &[u8]| { - let mut line_start = LineStart::new(bytes); - let _ = scan_containers(tree, &mut line_start); - Some(line_start.bytes_scanned()) - }; - let pair = if b'^' == bytes[1] { - let (byte_index, cow) = scan_link_label_rest(&text[2..], &linebreak_handler)?; - (byte_index + 2, ReferenceLabel::Footnote(cow)) - } else { - let (byte_index, cow) = scan_link_label_rest(&text[1..], &linebreak_handler)?; - (byte_index + 1, ReferenceLabel::Link(cow)) - }; - Some(pair) -} - -fn scan_reference<'a, 'b>( - tree: &'a Tree, - text: &'b str, - cur: Option, -) -> RefScan<'b> { - let cur_ix = match cur { - None => return RefScan::Failed, - Some(cur_ix) => cur_ix, - }; - let start = tree[cur_ix].item.start; - let tail = &text.as_bytes()[start..]; - - if tail.starts_with(b"[]") { - let closing_node = tree[cur_ix].next.unwrap(); - RefScan::Collapsed(tree[closing_node].next) - } else if let Some((ix, ReferenceLabel::Link(label))) = scan_link_label(tree, &text[start..]) { - let next_node = scan_nodes_to_ix(tree, cur, start + ix); - RefScan::LinkLabel(label, next_node, start + ix) - } else { - RefScan::Failed - } -} - -#[derive(Clone, Default)] -struct LinkStack { - inner: Vec, - disabled_ix: usize, -} - -impl LinkStack { - fn push(&mut self, el: LinkStackEl) { - self.inner.push(el); - } - - fn pop(&mut self) -> Option { - let el = self.inner.pop(); - self.disabled_ix = std::cmp::min(self.disabled_ix, self.inner.len()); - el - } - - fn clear(&mut self) { - self.inner.clear(); - self.disabled_ix = 0; - } - - fn disable_all_links(&mut self) { - for el in &mut self.inner[self.disabled_ix..] { - if el.ty == LinkStackTy::Link { - el.ty = LinkStackTy::Disabled; - } - } - self.disabled_ix = self.inner.len(); - } -} - -#[derive(Clone, Debug)] -struct LinkStackEl { - node: TreeIndex, - ty: LinkStackTy, -} - -#[derive(PartialEq, Clone, Debug)] -enum LinkStackTy { - Link, - Image, - Disabled, -} - -#[derive(Clone)] -struct LinkDef<'a> { - dest: CowStr<'a>, - title: Option>, -} - -/// Tracks tree indices of code span delimiters of each length. It should prevent -/// quadratic scanning behaviours by providing (amortized) constant time lookups. -struct CodeDelims { - inner: HashMap>, - seen_first: bool, -} - -impl CodeDelims { - fn new() -> Self { - Self { - inner: Default::default(), - seen_first: false, - } - } - - fn insert(&mut self, count: usize, ix: TreeIndex) { - if self.seen_first { - self.inner - .entry(count) - .or_insert_with(Default::default) - .push_back(ix); - } else { - // Skip the first insert, since that delimiter will always - // be an opener and not a closer. - self.seen_first = true; - } - } - - fn is_populated(&self) -> bool { - !self.inner.is_empty() - } - - fn find(&mut self, open_ix: TreeIndex, count: usize) -> Option { - while let Some(ix) = self.inner.get_mut(&count)?.pop_front() { - if ix > open_ix { - return Some(ix); - } - } - None - } - - fn clear(&mut self) { - self.inner.clear(); - self.seen_first = false; - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -struct LinkIndex(usize); - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -struct CowIndex(usize); - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -struct AlignmentIndex(usize); - -#[derive(Clone)] -struct Allocations<'a> { - refdefs: HashMap, LinkDef<'a>>, - links: Vec<(LinkType, CowStr<'a>, CowStr<'a>)>, - cows: Vec>, - alignments: Vec>, -} - -impl<'a> Allocations<'a> { - fn new() -> Self { - Self { - refdefs: HashMap::new(), - links: Vec::with_capacity(128), - cows: Vec::new(), - alignments: Vec::new(), - } - } - - fn allocate_cow(&mut self, cow: CowStr<'a>) -> CowIndex { - let ix = self.cows.len(); - self.cows.push(cow); - CowIndex(ix) - } - - fn allocate_link(&mut self, ty: LinkType, url: CowStr<'a>, title: CowStr<'a>) -> LinkIndex { - let ix = self.links.len(); - self.links.push((ty, url, title)); - LinkIndex(ix) - } - - fn allocate_alignment(&mut self, alignment: Vec) -> AlignmentIndex { - let ix = self.alignments.len(); - self.alignments.push(alignment); - AlignmentIndex(ix) - } -} - -impl<'a> Index for Allocations<'a> { - type Output = CowStr<'a>; - - fn index(&self, ix: CowIndex) -> &Self::Output { - self.cows.index(ix.0) - } -} - -impl<'a> Index for Allocations<'a> { - type Output = (LinkType, CowStr<'a>, CowStr<'a>); - - fn index(&self, ix: LinkIndex) -> &Self::Output { - self.links.index(ix.0) - } -} - -impl<'a> Index for Allocations<'a> { - type Output = Vec; - - fn index(&self, ix: AlignmentIndex) -> &Self::Output { - self.alignments.index(ix.0) - } -} - -/// A struct containing information on the reachability of certain inline HTML -/// elements. In particular, for cdata elements (` { - text: &'a str, - tree: Tree, - allocs: Allocations<'a>, - broken_link_callback: Option<&'a dyn Fn(&str, &str) -> Option<(String, String)>>, - html_scan_guard: HtmlScanGuard, - - // used by inline passes. store them here for reuse - inline_stack: InlineStack, - link_stack: LinkStack, -} - -impl<'a> Parser<'a> { - /// Creates a new event iterator for a markdown string without any options enabled. - pub fn new(text: &'a str) -> Parser<'a> { - Parser::new_ext(text, Options::empty()) - } - - /// Creates a new event iterator for a markdown string with given options. - pub fn new_ext(text: &'a str, options: Options) -> Parser<'a> { - Parser::new_with_broken_link_callback(text, options, None) - } - - /// In case the parser encounters any potential links that have a broken - /// reference (e.g `[foo]` when there is no `[foo]: ` entry at the bottom) - /// the provided callback will be called with the reference name, - /// and the returned pair will be used as the link name and title if it is not - /// `None`. - pub fn new_with_broken_link_callback( - text: &'a str, - options: Options, - broken_link_callback: Option<&'a dyn Fn(&str, &str) -> Option<(String, String)>>, - ) -> Parser<'a> { - let first_pass = FirstPass::new(text, options); - let (mut tree, allocs) = first_pass.run(); - tree.reset(); - let inline_stack = Default::default(); - let link_stack = Default::default(); - let html_scan_guard = Default::default(); - Parser { - text, - tree, - allocs, - broken_link_callback, - inline_stack, - link_stack, - html_scan_guard, - } - } - - /// Handle inline markup. - /// - /// When the parser encounters any item indicating potential inline markup, all - /// inline markup passes are run on the remainder of the chain. - /// - /// Note: there's some potential for optimization here, but that's future work. - fn handle_inline(&mut self) { - self.handle_inline_pass1(); - self.handle_emphasis(); - } - - /// Handle inline HTML, code spans, and links. - /// - /// This function handles both inline HTML and code spans, because they have - /// the same precedence. It also handles links, even though they have lower - /// precedence, because the URL of links must not be processed. - fn handle_inline_pass1(&mut self) { - let mut code_delims = CodeDelims::new(); - let mut cur = self.tree.cur(); - let mut prev = None; - - let block_end = self.tree[self.tree.peek_up().unwrap()].item.end; - let block_text = &self.text[..block_end]; - - while let Some(mut cur_ix) = cur { - match self.tree[cur_ix].item.body { - ItemBody::MaybeHtml => { - let next = self.tree[cur_ix].next; - let autolink = if let Some(next_ix) = next { - scan_autolink(block_text, self.tree[next_ix].item.start) - } else { - None - }; - - if let Some((ix, uri, link_type)) = autolink { - let node = scan_nodes_to_ix(&self.tree, next, ix); - let text_node = self.tree.create_node(Item { - start: self.tree[cur_ix].item.start + 1, - end: ix - 1, - body: ItemBody::Text, - }); - let link_ix = self.allocs.allocate_link(link_type, uri, "".into()); - self.tree[cur_ix].item.body = ItemBody::Link(link_ix); - self.tree[cur_ix].item.end = ix; - self.tree[cur_ix].next = node; - self.tree[cur_ix].child = Some(text_node); - prev = cur; - cur = node; - if let Some(node_ix) = cur { - self.tree[node_ix].item.start = max(self.tree[node_ix].item.start, ix); - } - continue; - } else { - let inline_html = if let Some(next_ix) = next { - self.scan_inline_html( - block_text.as_bytes(), - self.tree[next_ix].item.start, - ) - } else { - None - }; - if let Some(ix) = inline_html { - let node = scan_nodes_to_ix(&self.tree, next, ix); - self.tree[cur_ix].item.body = ItemBody::Html; - self.tree[cur_ix].item.end = ix; - self.tree[cur_ix].next = node; - prev = cur; - cur = node; - if let Some(node_ix) = cur { - self.tree[node_ix].item.start = - max(self.tree[node_ix].item.start, ix); - } - continue; - } - } - self.tree[cur_ix].item.body = ItemBody::Text; - } - ItemBody::MaybeCode(mut search_count, preceded_by_backslash) => { - if preceded_by_backslash { - search_count -= 1; - if search_count == 0 { - self.tree[cur_ix].item.body = ItemBody::Text; - prev = cur; - cur = self.tree[cur_ix].next; - continue; - } - } - - if code_delims.is_populated() { - // we have previously scanned all codeblock delimiters, - // so we can reuse that work - if let Some(scan_ix) = code_delims.find(cur_ix, search_count) { - self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); - } else { - self.tree[cur_ix].item.body = ItemBody::Text; - } - } else { - // we haven't previously scanned all codeblock delimiters, - // so walk the AST - let mut scan = if search_count > 0 { - self.tree[cur_ix].next - } else { - None - }; - while let Some(scan_ix) = scan { - if let ItemBody::MaybeCode(delim_count, _) = - self.tree[scan_ix].item.body - { - if search_count == delim_count { - self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); - code_delims.clear(); - break; - } else { - code_delims.insert(delim_count, scan_ix); - } - } - scan = self.tree[scan_ix].next; - } - if scan == None { - self.tree[cur_ix].item.body = ItemBody::Text; - } - } - } - ItemBody::MaybeLinkOpen => { - self.tree[cur_ix].item.body = ItemBody::Text; - self.link_stack.push(LinkStackEl { - node: cur_ix, - ty: LinkStackTy::Link, - }); - } - ItemBody::MaybeImage => { - self.tree[cur_ix].item.body = ItemBody::Text; - self.link_stack.push(LinkStackEl { - node: cur_ix, - ty: LinkStackTy::Image, - }); - } - ItemBody::MaybeLinkClose => { - self.tree[cur_ix].item.body = ItemBody::Text; - if let Some(tos) = self.link_stack.pop() { - if tos.ty == LinkStackTy::Disabled { - continue; - } - let next = self.tree[cur_ix].next; - if let Some((next_ix, url, title)) = - self.scan_inline_link(block_text, self.tree[cur_ix].item.end, next) - { - let next_node = scan_nodes_to_ix(&self.tree, next, next_ix); - if let Some(prev_ix) = prev { - self.tree[prev_ix].next = None; - } - cur = Some(tos.node); - cur_ix = tos.node; - let link_ix = self.allocs.allocate_link(LinkType::Inline, url, title); - self.tree[cur_ix].item.body = if tos.ty == LinkStackTy::Image { - ItemBody::Image(link_ix) - } else { - ItemBody::Link(link_ix) - }; - self.tree[cur_ix].child = self.tree[cur_ix].next; - self.tree[cur_ix].next = next_node; - self.tree[cur_ix].item.end = next_ix; - if let Some(next_node_ix) = next_node { - self.tree[next_node_ix].item.start = - max(self.tree[next_node_ix].item.start, next_ix); - } - - if tos.ty == LinkStackTy::Link { - self.link_stack.disable_all_links(); - } - } else { - // ok, so its not an inline link. maybe it is a reference - // to a defined link? - let scan_result = scan_reference(&self.tree, block_text, next); - let (node_after_link, link_type) = match scan_result { - // [label][reference] - RefScan::LinkLabel(_, next_node, _) => { - (next_node, LinkType::Reference) - } - // [] - RefScan::Collapsed(next_node) => (next_node, LinkType::Collapsed), - // [shortcut] - // - // [shortcut]: /blah - RefScan::Failed => (next, LinkType::Shortcut), - }; - - // (label, source_ix end) - let label: Option<(ReferenceLabel<'a>, usize)> = match scan_result { - RefScan::LinkLabel(l, _, end_ix) => { - Some((ReferenceLabel::Link(l), end_ix)) - } - RefScan::Collapsed(..) | RefScan::Failed => { - // No label? maybe it is a shortcut reference - let label_start = self.tree[tos.node].item.end - 1; - scan_link_label( - &self.tree, - &self.text[label_start..self.tree[cur_ix].item.end], - ) - .map(|(ix, label)| (label, label_start + ix)) - } - }; - - // see if it's a footnote reference - if let Some((ReferenceLabel::Footnote(l), end)) = label { - self.tree[tos.node].next = node_after_link; - self.tree[tos.node].child = None; - self.tree[tos.node].item.body = - ItemBody::FootnoteReference(self.allocs.allocate_cow(l)); - self.tree[tos.node].item.end = end; - prev = Some(tos.node); - cur = node_after_link; - self.link_stack.clear(); - continue; - } else if let Some((ReferenceLabel::Link(link_label), end)) = label { - let type_url_title = self - .allocs - .refdefs - .get(&UniCase::new(link_label.as_ref().into())) - .map(|matching_def| { - // found a matching definition! - let title = matching_def - .title - .as_ref() - .cloned() - .unwrap_or_else(|| "".into()); - let url = matching_def.dest.clone(); - (link_type, url, title) - }) - .or_else(|| { - self.broken_link_callback - .and_then(|callback| { - // looked for matching definition, but didn't find it. try to fix - // link with callback, if it is defined - callback(link_label.as_ref(), link_label.as_ref()) - }) - .map(|(url, title)| { - (link_type.to_unknown(), url.into(), title.into()) - }) - }); - - if let Some((def_link_type, url, title)) = type_url_title { - let link_ix = - self.allocs.allocate_link(def_link_type, url, title); - self.tree[tos.node].item.body = if tos.ty == LinkStackTy::Image - { - ItemBody::Image(link_ix) - } else { - ItemBody::Link(link_ix) - }; - let label_node = self.tree[tos.node].next; - - // lets do some tree surgery to add the link to the tree - // 1st: skip the label node and close node - self.tree[tos.node].next = node_after_link; - - // then, if it exists, add the label node as a child to the link node - if label_node != cur { - self.tree[tos.node].child = label_node; - - // finally: disconnect list of children - if let Some(prev_ix) = prev { - self.tree[prev_ix].next = None; - } - } - - self.tree[tos.node].item.end = end; - - // set up cur so next node will be node_after_link - cur = Some(tos.node); - cur_ix = tos.node; - - if tos.ty == LinkStackTy::Link { - self.link_stack.disable_all_links(); - } - } - } - } - } - } - _ => (), - } - prev = cur; - cur = self.tree[cur_ix].next; - } - self.link_stack.clear(); - } - - fn handle_emphasis(&mut self) { - let mut prev = None; - let mut prev_ix: TreeIndex; - let mut cur = self.tree.cur(); - while let Some(mut cur_ix) = cur { - if let ItemBody::MaybeEmphasis(mut count, can_open, can_close) = - self.tree[cur_ix].item.body - { - let c = self.text.as_bytes()[self.tree[cur_ix].item.start]; - let both = can_open && can_close; - if can_close { - while let Some(el) = - self.inline_stack.find_match(&mut self.tree, c, count, both) - { - // have a match! - if let Some(prev_ix) = prev { - self.tree[prev_ix].next = None; - } - let match_count = min(count, el.count); - // start, end are tree node indices - let mut end = cur_ix - 1; - let mut start = el.start + el.count; - - // work from the inside out - while start > el.start + el.count - match_count { - let (inc, ty) = if c == b'~' { - (2, ItemBody::Strikethrough) - } else if start > el.start + el.count - match_count + 1 { - (2, ItemBody::Strong) - } else { - (1, ItemBody::Emphasis) - }; - - let root = start - inc; - end = end + inc; - self.tree[root].item.body = ty; - self.tree[root].item.end = self.tree[end].item.end; - self.tree[root].child = Some(start); - self.tree[root].next = None; - start = root; - } - - // set next for top most emph level - prev_ix = el.start + el.count - match_count; - prev = Some(prev_ix); - cur = self.tree[cur_ix + match_count - 1].next; - self.tree[prev_ix].next = cur; - - if el.count > match_count { - self.inline_stack.push(InlineEl { - start: el.start, - count: el.count - match_count, - c: el.c, - both, - }) - } - count -= match_count; - if count > 0 { - cur_ix = cur.unwrap(); - } else { - break; - } - } - } - if count > 0 { - if can_open { - self.inline_stack.push(InlineEl { - start: cur_ix, - count, - c, - both, - }); - } else { - for i in 0..count { - self.tree[cur_ix + i].item.body = ItemBody::Text; - } - } - prev_ix = cur_ix + count - 1; - prev = Some(prev_ix); - cur = self.tree[prev_ix].next; - } - } else { - prev = cur; - cur = self.tree[cur_ix].next; - } - } - self.inline_stack.pop_all(&mut self.tree); - } - - /// Returns next byte index, url and title. - fn scan_inline_link( - &self, - underlying: &'a str, - mut ix: usize, - node: Option, - ) -> Option<(usize, CowStr<'a>, CowStr<'a>)> { - if scan_ch(&underlying.as_bytes()[ix..], b'(') == 0 { - return None; - } - ix += 1; - ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); - - let (dest_length, dest) = scan_link_dest(underlying, ix, LINK_MAX_NESTED_PARENS)?; - let dest = unescape(dest); - ix += dest_length; - - ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); - - let title = if let Some((bytes_scanned, t)) = self.scan_link_title(underlying, ix, node) { - ix += bytes_scanned; - ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); - t - } else { - "".into() - }; - if scan_ch(&underlying.as_bytes()[ix..], b')') == 0 { - return None; - } - ix += 1; - - Some((ix, dest, title)) - } - - // returns (bytes scanned, title cow) - fn scan_link_title( - &self, - text: &'a str, - start_ix: usize, - node: Option, - ) -> Option<(usize, CowStr<'a>)> { - let bytes = text.as_bytes(); - let open = match bytes.get(start_ix) { - Some(b @ b'\'') | Some(b @ b'\"') | Some(b @ b'(') => *b, - _ => return None, - }; - let close = if open == b'(' { b')' } else { open }; - - let mut title = String::new(); - let mut mark = start_ix + 1; - let mut i = start_ix + 1; - - while i < bytes.len() { - let c = bytes[i]; - - if c == close { - let cow = if mark == 1 { - (i - start_ix + 1, text[mark..i].into()) - } else { - title.push_str(&text[mark..i]); - (i - start_ix + 1, title.into()) - }; - - return Some(cow); - } - if c == open { - return None; - } - - if c == b'\n' || c == b'\r' { - if let Some(node_ix) = scan_nodes_to_ix(&self.tree, node, i + 1) { - if self.tree[node_ix].item.start > i { - title.push_str(&text[mark..i]); - title.push('\n'); - i = self.tree[node_ix].item.start; - mark = i; - continue; - } - } - } - if c == b'&' { - if let (n, Some(value)) = scan_entity(&bytes[i..]) { - title.push_str(&text[mark..i]); - title.push_str(&value); - i += n; - mark = i; - continue; - } - } - if c == b'\\' && i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) { - title.push_str(&text[mark..i]); - i += 1; - mark = i; - } - - i += 1; - } - - None - } - - /// Make a code span. - /// - /// Both `open` and `close` are matching MaybeCode items. - fn make_code_span(&mut self, open: TreeIndex, close: TreeIndex, preceding_backslash: bool) { - let first_ix = open + 1; - let last_ix = close - 1; - let bytes = self.text.as_bytes(); - let mut span_start = self.tree[open].item.end; - let mut span_end = self.tree[close].item.start; - let mut buf: Option = None; - - // detect all-space sequences, since they are kept as-is as of commonmark 0.29 - if !bytes[span_start..span_end].iter().all(|&b| b == b' ') { - let opening = match bytes[span_start] { - b' ' | b'\r' | b'\n' => true, - _ => false, - }; - let closing = match bytes[span_end - 1] { - b' ' | b'\r' | b'\n' => true, - _ => false, - }; - let drop_enclosing_whitespace = opening && closing; - - if drop_enclosing_whitespace { - span_start += 1; - if span_start < span_end { - span_end -= 1; - } - } - - let mut ix = first_ix; - - while ix < close { - if let ItemBody::HardBreak | ItemBody::SoftBreak = self.tree[ix].item.body { - if drop_enclosing_whitespace { - // check whether break should be ignored - if ix == first_ix { - ix = ix + 1; - span_start = min(span_end, self.tree[ix].item.start); - continue; - } else if ix == last_ix && last_ix > first_ix { - ix = ix + 1; - continue; - } - } - - let end = bytes[self.tree[ix].item.start..] - .iter() - .position(|&b| b == b'\r' || b == b'\n') - .unwrap() - + self.tree[ix].item.start; - if let Some(ref mut buf) = buf { - buf.push_str(&self.text[self.tree[ix].item.start..end]); - buf.push(' '); - } else { - let mut new_buf = String::with_capacity(span_end - span_start); - new_buf.push_str(&self.text[span_start..end]); - new_buf.push(' '); - buf = Some(new_buf); - } - } else if let Some(ref mut buf) = buf { - let end = if ix == last_ix { - span_end - } else { - self.tree[ix].item.end - }; - buf.push_str(&self.text[self.tree[ix].item.start..end]); - } - ix = ix + 1; - } - } - - let cow = if let Some(buf) = buf { - buf.into() - } else { - self.text[span_start..span_end].into() - }; - if preceding_backslash { - self.tree[open].item.body = ItemBody::Text; - self.tree[open].item.end = self.tree[open].item.start + 1; - self.tree[open].next = Some(close); - self.tree[close].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); - self.tree[close].item.start = self.tree[open].item.start + 1; - } else { - self.tree[open].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); - self.tree[open].item.end = self.tree[close].item.end; - self.tree[open].next = self.tree[close].next; - } - } - - /// Returns the next byte offset on success. - fn scan_inline_html(&mut self, bytes: &[u8], ix: usize) -> Option { - let c = *bytes.get(ix)?; - if c == b'!' { - scan_inline_html_comment(bytes, ix + 1, &mut self.html_scan_guard) - } else if c == b'?' { - scan_inline_html_processing(bytes, ix + 1, &mut self.html_scan_guard) - } else { - let i = scan_html_block_inner( - &bytes[ix..], - Some(&|_bytes| { - let mut line_start = LineStart::new(bytes); - let _ = scan_containers(&self.tree, &mut line_start); - line_start.bytes_scanned() - }), - )?; - Some(i + ix) - } - } - - /// Consumes the event iterator and produces an iterator that produces - /// `(Event, Range)` pairs, where the `Range` value maps to the corresponding - /// range in the markdown source. - pub fn into_offset_iter(self) -> OffsetIter<'a> { - OffsetIter { inner: self } - } -} - -pub(crate) enum LoopInstruction { - /// Continue looking for more special bytes, but skip next few bytes. - ContinueAndSkip(usize), - /// Break looping immediately, returning with the given index and value. - BreakAtWith(usize, T), -} - -/// This function walks the byte slices from the given index and -/// calls the callback function on all bytes (and their indices) that are in the following set: -/// `` ` ``, `\`, `&`, `*`, `_`, `~`, `!`, `<`, `[`, `]`, `|`, `\r`, `\n` -/// It is guaranteed not call the callback on other bytes. -/// Whenever `callback(ix, byte)` returns a `ContinueAndSkip(n)` value, the callback -/// will not be called with an index that is less than `ix + n + 1`. -/// When the callback returns a `BreakAtWith(end_ix, opt+val)`, no more callbacks will be -/// called and the function returns immediately with the return value `(end_ix, opt_val)`. -/// If `BreakAtWith(..)` is never returned, this function will return the first -/// index that is outside the byteslice bound and a `None` value. -fn iterate_special_bytes(bytes: &[u8], ix: usize, callback: F) -> (usize, Option) -where - F: FnMut(usize, u8) -> LoopInstruction>, -{ - #[cfg(all(target_arch = "x86_64", feature = "simd"))] - { - crate::simd::iterate_special_bytes(bytes, ix, callback) - } - #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] - { - scalar_iterate_special_bytes(bytes, ix, callback) - } -} - -const fn special_bytes() -> [bool; 256] { - let mut bytes = [false; 256]; - bytes[b'<' as usize] = true; - bytes[b'!' as usize] = true; - bytes[b'[' as usize] = true; - bytes[b'~' as usize] = true; - bytes[b'`' as usize] = true; - bytes[b'|' as usize] = true; - bytes[b'\\' as usize] = true; - bytes[b'*' as usize] = true; - bytes[b'_' as usize] = true; - bytes[b'\r' as usize] = true; - bytes[b'\n' as usize] = true; - bytes[b']' as usize] = true; - bytes[b'&' as usize] = true; - bytes -} - -pub(crate) fn scalar_iterate_special_bytes( - bytes: &[u8], - mut ix: usize, - mut callback: F, -) -> (usize, Option) -where - F: FnMut(usize, u8) -> LoopInstruction>, -{ - let special_bytes = special_bytes(); - - while ix < bytes.len() { - let b = bytes[ix]; - if special_bytes[b as usize] { - match callback(ix, b) { - LoopInstruction::ContinueAndSkip(skip) => { - ix += skip; - } - LoopInstruction::BreakAtWith(ix, val) => { - return (ix, val); - } - } - } - ix += 1; - } - - (ix, None) -} - -/// Markdown event and source range iterator. -/// -/// Generates tuples where the first element is the markdown event and the second -/// is a the corresponding range in the source string. -/// -/// Constructed from a `Parser` using its -/// [`into_offset_iter`](struct.Parser.html#method.into_offset_iter) method. -pub struct OffsetIter<'a> { - inner: Parser<'a>, -} - -impl<'a> Iterator for OffsetIter<'a> { - type Item = (Event<'a>, Range); - - fn next(&mut self) -> Option { - match self.inner.tree.cur() { - None => { - let ix = self.inner.tree.pop()?; - let tag = item_to_tag(&self.inner.tree[ix].item, &self.inner.allocs); - self.inner.tree.next_sibling(ix); - Some(( - Event::End(tag), - self.inner.tree[ix].item.start..self.inner.tree[ix].item.end, - )) - } - Some(cur_ix) => { - if self.inner.tree[cur_ix].item.body.is_inline() { - self.inner.handle_inline(); - } - - let node = self.inner.tree[cur_ix]; - let item = node.item; - let event = item_to_event(item, self.inner.text, &self.inner.allocs); - if let Event::Start(..) = event { - self.inner.tree.push(); - } else { - self.inner.tree.next_sibling(cur_ix); - } - Some((event, item.start..item.end)) - } - } - } -} - -fn item_to_tag<'a>(item: &Item, allocs: &Allocations<'a>) -> Tag<'a> { - match item.body { - ItemBody::Paragraph => Tag::Paragraph, - ItemBody::Emphasis => Tag::Emphasis, - ItemBody::Strong => Tag::Strong, - ItemBody::Strikethrough => Tag::Strikethrough, - ItemBody::Link(link_ix) => { - let &(ref link_type, ref url, ref title) = allocs.index(link_ix); - Tag::Link(*link_type, url.clone(), title.clone()) - } - ItemBody::Image(link_ix) => { - let &(ref link_type, ref url, ref title) = allocs.index(link_ix); - Tag::Image(*link_type, url.clone(), title.clone()) - } - ItemBody::Heading(level) => Tag::Heading(level), - ItemBody::FencedCodeBlock(cow_ix) => { - Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) - } - ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), - ItemBody::BlockQuote => Tag::BlockQuote, - ItemBody::List(_, c, listitem_start) => { - if c == b'.' || c == b')' { - Tag::List(Some(listitem_start)) - } else { - Tag::List(None) - } - } - ItemBody::ListItem(_) => Tag::Item, - ItemBody::TableHead => Tag::TableHead, - ItemBody::TableCell => Tag::TableCell, - ItemBody::TableRow => Tag::TableRow, - ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), - ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), - _ => panic!("unexpected item body {:?}", item.body), - } -} - -fn item_to_event<'a>(item: Item, text: &'a str, allocs: &Allocations<'a>) -> Event<'a> { - let tag = match item.body { - ItemBody::Text => return Event::Text(text[item.start..item.end].into()), - ItemBody::Code(cow_ix) => return Event::Code(allocs[cow_ix].clone()), - ItemBody::SynthesizeText(cow_ix) => return Event::Text(allocs[cow_ix].clone()), - ItemBody::Html => return Event::Html(text[item.start..item.end].into()), - ItemBody::SoftBreak => return Event::SoftBreak, - ItemBody::HardBreak => return Event::HardBreak, - ItemBody::FootnoteReference(cow_ix) => { - return Event::FootnoteReference(allocs[cow_ix].clone()) - } - ItemBody::TaskListMarker(checked) => return Event::TaskListMarker(checked), - ItemBody::Rule => return Event::Rule, - - ItemBody::Paragraph => Tag::Paragraph, - ItemBody::Emphasis => Tag::Emphasis, - ItemBody::Strong => Tag::Strong, - ItemBody::Strikethrough => Tag::Strikethrough, - ItemBody::Link(link_ix) => { - let &(ref link_type, ref url, ref title) = allocs.index(link_ix); - Tag::Link(*link_type, url.clone(), title.clone()) - } - ItemBody::Image(link_ix) => { - let &(ref link_type, ref url, ref title) = allocs.index(link_ix); - Tag::Image(*link_type, url.clone(), title.clone()) - } - ItemBody::Heading(level) => Tag::Heading(level), - ItemBody::FencedCodeBlock(cow_ix) => { - Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) - } - ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), - ItemBody::BlockQuote => Tag::BlockQuote, - ItemBody::List(_, c, listitem_start) => { - if c == b'.' || c == b')' { - Tag::List(Some(listitem_start)) - } else { - Tag::List(None) - } - } - ItemBody::ListItem(_) => Tag::Item, - ItemBody::TableHead => Tag::TableHead, - ItemBody::TableCell => Tag::TableCell, - ItemBody::TableRow => Tag::TableRow, - ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), - ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), - _ => panic!("unexpected item body {:?}", item.body), - }; - - Event::Start(tag) -} - -// https://english.stackexchange.com/a/285573 -fn surgerize_tight_list(tree: &mut Tree, list_ix: TreeIndex) { - let mut list_item = tree[list_ix].child; - while let Some(listitem_ix) = list_item { - // first child is special, controls how we repoint list_item.child - let list_item_firstborn = tree[listitem_ix].child; - - // Check that list item has children - this is not necessarily the case! - if let Some(firstborn_ix) = list_item_firstborn { - if let ItemBody::Paragraph = tree[firstborn_ix].item.body { - tree[listitem_ix].child = tree[firstborn_ix].child; - } - - let mut list_item_child = Some(firstborn_ix); - let mut node_to_repoint = None; - while let Some(child_ix) = list_item_child { - // surgerize paragraphs - let repoint_ix = if let ItemBody::Paragraph = tree[child_ix].item.body { - if let Some(child_firstborn) = tree[child_ix].child { - if let Some(repoint_ix) = node_to_repoint { - tree[repoint_ix].next = Some(child_firstborn); - } - let mut child_lastborn = child_firstborn; - while let Some(lastborn_next_ix) = tree[child_lastborn].next { - child_lastborn = lastborn_next_ix; - } - child_lastborn - } else { - child_ix - } - } else { - child_ix - }; - - node_to_repoint = Some(repoint_ix); - tree[repoint_ix].next = tree[child_ix].next; - list_item_child = tree[child_ix].next; - } - } - - list_item = tree[listitem_ix].next; - } -} - -impl<'a> Iterator for Parser<'a> { - type Item = Event<'a>; - - fn next(&mut self) -> Option> { - match self.tree.cur() { - None => { - let ix = self.tree.pop()?; - let tag = item_to_tag(&self.tree[ix].item, &self.allocs); - self.tree.next_sibling(ix); - Some(Event::End(tag)) - } - Some(cur_ix) => { - if self.tree[cur_ix].item.body.is_inline() { - self.handle_inline(); - } - - let node = self.tree[cur_ix]; - let item = node.item; - let event = item_to_event(item, self.text, &self.allocs); - if let Event::Start(..) = event { - self.tree.push(); - } else { - self.tree.next_sibling(cur_ix); - } - Some(event) - } - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::tree::Node; - - // TODO: move these tests to tests/html.rs? - - fn parser_with_extensions(text: &str) -> Parser<'_> { - let mut opts = Options::empty(); - opts.insert(Options::ENABLE_TABLES); - opts.insert(Options::ENABLE_FOOTNOTES); - opts.insert(Options::ENABLE_STRIKETHROUGH); - opts.insert(Options::ENABLE_TASKLISTS); - - Parser::new_ext(text, opts) - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn node_size() { - let node_size = std::mem::size_of::>(); - assert_eq!(48, node_size); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn body_size() { - let body_size = std::mem::size_of::(); - assert_eq!(16, body_size); - } - - #[test] - fn single_open_fish_bracket() { - // dont crash - assert_eq!(3, Parser::new("<").count()); - } - - #[test] - fn lone_hashtag() { - // dont crash - assert_eq!(2, Parser::new("#").count()); - } - - #[test] - fn lots_of_backslashes() { - // dont crash - Parser::new("\\\\\r\r").count(); - Parser::new("\\\r\r\\.\\\\\r\r\\.\\").count(); - } - - #[test] - fn issue_320() { - // dont crash - parser_with_extensions(":\r\t> |\r:\r\t> |\r").count(); - } - - #[test] - fn issue_319() { - // dont crash - parser_with_extensions("|\r-]([^|\r-]([^").count(); - parser_with_extensions("|\r\r=][^|\r\r=][^car").count(); - } - - #[test] - fn issue_303() { - // dont crash - parser_with_extensions("[^\r\ra]").count(); - parser_with_extensions("\r\r]Z[^\x00\r\r]Z[^\x00").count(); - } - - #[test] - fn issue_313() { - // dont crash - parser_with_extensions("*]0[^\r\r*]0[^").count(); - parser_with_extensions("[^\r> `][^\r> `][^\r> `][").count(); - } - - #[test] - fn issue_311() { - // dont crash - parser_with_extensions("\\\u{0d}-\u{09}\\\u{0d}-\u{09}").count(); - } - - #[test] - fn issue_283() { - let input = std::str::from_utf8(b"\xf0\x9b\xb2\x9f - \\\n> - ").count(); - parser_with_extensions("- \n\n").count(); - } - - #[test] - fn issue_306() { - // dont crash - parser_with_extensions("*\r_<__*\r_<__*\r_<__*\r_<__").count(); - } - - #[test] - fn issue_305() { - // dont crash - parser_with_extensions("_6**6*_*").count(); - } - - #[test] - fn another_emphasis_panic() { - parser_with_extensions("*__#_#__*").count(); - } - - #[test] - fn offset_iter() { - let event_offsets: Vec<_> = Parser::new("*hello* world") - .into_offset_iter() - .map(|(_ev, range)| range) - .collect(); - let expected_offsets = vec![(0..13), (0..7), (1..6), (0..7), (7..13), (0..13)]; - assert_eq!(expected_offsets, event_offsets); - } - - #[test] - fn reference_link_offsets() { - let range = - Parser::new("# H1\n[testing][Some reference]\n\n[Some reference]: https://github.com") - .into_offset_iter() - .filter_map(|(ev, range)| match ev { - Event::Start(Tag::Link(LinkType::Reference, ..), ..) => Some(range), - _ => None, - }) - .next() - .unwrap(); - assert_eq!(5..30, range); - } - - #[test] - fn footnote_offsets() { - let range = Parser::new("Testing this[^1] out.\n\n[^1]: Footnote.") - .into_offset_iter() - .filter_map(|(ev, range)| match ev { - Event::FootnoteReference(..) => Some(range), - _ => None, - }) - .next() - .unwrap(); - assert_eq!(12..16, range); - } - - #[test] - fn table_offset() { - let markdown = "a\n\nTesting|This|Outtt\n--|:--:|--:\nSome Data|Other data|asdf"; - let event_offset = parser_with_extensions(markdown) - .into_offset_iter() - .map(|(_ev, range)| range) - .nth(3) - .unwrap(); - let expected_offset = 3..59; - assert_eq!(expected_offset, event_offset); - } - - #[test] - fn offset_iter_issue_378() { - let event_offsets: Vec<_> = Parser::new("a [b](c) d") - .into_offset_iter() - .map(|(_ev, range)| range) - .collect(); - let expected_offsets = vec![(0..10), (0..2), (2..8), (3..4), (2..8), (8..10), (0..10)]; - assert_eq!(expected_offsets, event_offsets); - } - - #[test] - fn offset_iter_issue_404() { - let event_offsets: Vec<_> = Parser::new("###\n") - .into_offset_iter() - .map(|(_ev, range)| range) - .collect(); - let expected_offsets = vec![(0..4), (0..4)]; - assert_eq!(expected_offsets, event_offsets); - } - - // FIXME: add this one regression suite - #[test] - fn link_def_at_eof() { - let test_str = "[My site][world]\n\n[world]: https://vincentprouillet.com"; - let expected = "

    My site

    \n"; - - let mut buf = String::new(); - crate::html::push_html(&mut buf, Parser::new(test_str)); - assert_eq!(expected, buf); - } - - #[test] - fn ref_def_at_eof() { - let test_str = "[test]:\\"; - let expected = ""; - - let mut buf = String::new(); - crate::html::push_html(&mut buf, Parser::new(test_str)); - assert_eq!(expected, buf); - } - - #[test] - fn ref_def_cr_lf() { - let test_str = "[a]: /u\r\n\n[a]"; - let expected = "

    a

    \n"; - - let mut buf = String::new(); - crate::html::push_html(&mut buf, Parser::new(test_str)); - assert_eq!(expected, buf); - } - - #[test] - fn no_dest_refdef() { - let test_str = "[a]:"; - let expected = "

    [a]:

    \n"; - - let mut buf = String::new(); - crate::html::push_html(&mut buf, Parser::new(test_str)); - assert_eq!(expected, buf); - } - - #[test] - fn simple_broken_link_callback() { - let test_str = "This is a link w/o def: [hello][world]"; - let parser = Parser::new_with_broken_link_callback( - test_str, - Options::empty(), - Some(&|norm, raw| { - assert_eq!("world", raw); - assert_eq!("world", norm); - Some(("YOLO".to_owned(), "SWAG".to_owned())) - }), - ); - let mut link_tag_count = 0; - for (typ, url, title) in parser.filter_map(|event| match event { - Event::Start(tag) | Event::End(tag) => match tag { - Tag::Link(typ, url, title) => Some((typ, url, title)), - _ => None, - }, - _ => None, - }) { - link_tag_count += 1; - assert_eq!(typ, LinkType::ReferenceUnknown); - assert_eq!(url.as_ref(), "YOLO"); - assert_eq!(title.as_ref(), "SWAG"); - } - assert!(link_tag_count > 0); - } - - #[test] - fn code_block_kind_check_fenced() { - let parser = Parser::new("hello\n```test\ntadam\n```"); - let mut found = 0; - for (ev, _range) in parser.into_offset_iter() { - match ev { - Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(syntax))) => { - assert_eq!(syntax.as_ref(), "test"); - found += 1; - } - _ => {} - } - } - assert_eq!(found, 1); - } - - #[test] - fn code_block_kind_check_indented() { - let parser = Parser::new("hello\n\n ```test\n tadam\nhello"); - let mut found = 0; - for (ev, _range) in parser.into_offset_iter() { - match ev { - Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => { - found += 1; - } - _ => {} - } - } - assert_eq!(found, 1); - } -} +// Copyright 2017 Google Inc. All rights reserved. +// +// 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. + +//! Tree-based two pass parser. + +use std::cmp::{max, min}; +use std::collections::{HashMap, VecDeque}; +use std::ops::{Index, Range}; + +use unicase::UniCase; + +use crate::linklabel::{scan_link_label_rest, LinkLabel, ReferenceLabel}; +use crate::scanners::*; +use crate::strings::CowStr; +use crate::tree::{Tree, TreeIndex}; + +// Allowing arbitrary depth nested parentheses inside link destinations +// can create denial of service vulnerabilities if we're not careful. +// The simplest countermeasure is to limit their depth, which is +// explicitly allowed by the spec as long as the limit is at least 3: +// https://spec.commonmark.org/0.29/#link-destination +const LINK_MAX_NESTED_PARENS: usize = 5; + +/// Codeblock kind. +#[derive(Clone, Debug, PartialEq)] +pub enum CodeBlockKind<'a> { + Indented, + /// The value contained in the tag describes the language of the code, which may be empty. + Fenced(CowStr<'a>), +} + +impl<'a> CodeBlockKind<'a> { + pub fn is_indented(&self) -> bool { + match *self { + CodeBlockKind::Indented => true, + _ => false, + } + } + + pub fn is_fenced(&self) -> bool { + match *self { + CodeBlockKind::Fenced(_) => true, + _ => false, + } + } +} + +/// Tags for elements that can contain other elements. +#[derive(Clone, Debug, PartialEq)] +pub enum Tag<'a> { + /// A paragraph of text and other inline elements. + Paragraph, + + /// A heading. The field indicates the level of the heading. + Heading(u32), + + BlockQuote, + /// A code block. + CodeBlock(CodeBlockKind<'a>), + + /// A list. If the list is ordered the field indicates the number of the first item. + /// Contains only list items. + List(Option), // TODO: add delim and tight for ast (not needed for html) + /// A list item. + Item, + /// A footnote definition. The value contained is the footnote's label by which it can + /// be referred to. + FootnoteDefinition(CowStr<'a>), + + /// A table. Contains a vector describing the text-alignment for each of its columns. + Table(Vec), + /// A table header. Contains only `TableRow`s. Note that the table body starts immediately + /// after the closure of the `TableHead` tag. There is no `TableBody` tag. + TableHead, + /// A table row. Is used both for header rows as body rows. Contains only `TableCell`s. + TableRow, + TableCell, + + // span-level tags + Emphasis, + Strong, + Strikethrough, + + /// A link. The first field is the link type, the second the destination URL and the third is a title. + Link(LinkType, CowStr<'a>, CowStr<'a>), + + /// An image. The first field is the link type, the second the destination URL and the third is a title. + Image(LinkType, CowStr<'a>, CowStr<'a>), +} + +/// Type specifier for inline links. See [the Tag::Link](enum.Tag.html#variant.Link) for more information. +#[derive(Clone, Debug, PartialEq, Copy)] +pub enum LinkType { + /// Inline link like `[foo](bar)` + Inline, + /// Reference link like `[foo][bar]` + Reference, + /// Reference without destination in the document, but resolved by the broken_link_callback + ReferenceUnknown, + /// Collapsed link like `[foo][]` + Collapsed, + /// Collapsed link without destination in the document, but resolved by the broken_link_callback + CollapsedUnknown, + /// Shortcut link like `[foo]` + Shortcut, + /// Shortcut without destination in the document, but resolved by the broken_link_callback + ShortcutUnknown, + /// Autolink like `` + Autolink, + /// Email address in autolink like `` + Email, +} + +impl LinkType { + fn to_unknown(self) -> Self { + match self { + LinkType::Reference => LinkType::ReferenceUnknown, + LinkType::Collapsed => LinkType::CollapsedUnknown, + LinkType::Shortcut => LinkType::ShortcutUnknown, + _ => unreachable!(), + } + } +} + +/// Markdown events that are generated in a preorder traversal of the document +/// tree, with additional `End` events whenever all of an inner node's children +/// have been visited. +#[derive(Clone, Debug, PartialEq)] +pub enum Event<'a> { + /// Start of a tagged element. Events that are yielded after this event + /// and before its corresponding `End` event are inside this element. + /// Start and end events are guaranteed to be balanced. + Start(Tag<'a>), + /// End of a tagged element. + End(Tag<'a>), + /// A text node. + Text(CowStr<'a>), + /// An inline code node. + Code(CowStr<'a>), + /// An HTML node. + Html(CowStr<'a>), + /// A reference to a footnote with given label, which may or may not be defined + /// by an event with a `Tag::FootnoteDefinition` tag. Definitions and references to them may + /// occur in any order. + FootnoteReference(CowStr<'a>), + /// A soft line break. + SoftBreak, + /// A hard line break. + HardBreak, + /// A horizontal ruler. + Rule, + /// A task list marker, rendered as a checkbox in HTML. Contains a true when it is checked. + TaskListMarker(bool), +} + +/// Table column text alignment. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Alignment { + /// Default text alignment. + None, + Left, + Center, + Right, +} + +bitflags! { + /// Option struct containing flags for enabling extra features + /// that are not part of the CommonMark spec. + pub struct Options: u32 { + const ENABLE_TABLES = 1 << 1; + const ENABLE_FOOTNOTES = 1 << 2; + const ENABLE_STRIKETHROUGH = 1 << 3; + const ENABLE_TASKLISTS = 1 << 4; + const ENABLE_SMART_PUNCTUATION = 1 << 5; + } +} + +#[derive(Debug, Default, Clone, Copy)] +struct Item { + start: usize, + end: usize, + body: ItemBody, +} + +#[derive(Debug, PartialEq, Clone, Copy)] +enum ItemBody { + Paragraph, + Text, + SoftBreak, + HardBreak, + + // These are possible inline items, need to be resolved in second pass. + + // repeats, can_open, can_close + MaybeEmphasis(usize, bool, bool), + // quote byte, can_open, can_close + MaybeSmartQuote(u8, bool, bool), + MaybeCode(usize, bool), // number of backticks, preceeded by backslash + MaybeHtml, + MaybeLinkOpen, + // bool indicates whether or not the preceeding section could be a reference + MaybeLinkClose(bool), + MaybeImage, + + // These are inline items after resolution. + Emphasis, + Strong, + Strikethrough, + Code(CowIndex), + Link(LinkIndex), + Image(LinkIndex), + FootnoteReference(CowIndex), + TaskListMarker(bool), // true for checked + + Rule, + Heading(u32), // heading level + FencedCodeBlock(CowIndex), + IndentCodeBlock, + Html, + OwnedHtml(CowIndex), + BlockQuote, + List(bool, u8, u64), // is_tight, list character, list start index + ListItem(usize), // indent level + SynthesizeText(CowIndex), + SynthesizeChar(char), + FootnoteDefinition(CowIndex), + + // Tables + Table(AlignmentIndex), + TableHead, + TableRow, + TableCell, + + // Dummy node at the top of the tree - should not be used otherwise! + Root, +} + +impl<'a> ItemBody { + fn is_inline(&self) -> bool { + match *self { + ItemBody::MaybeEmphasis(..) + | ItemBody::MaybeSmartQuote(..) + | ItemBody::MaybeHtml + | ItemBody::MaybeCode(..) + | ItemBody::MaybeLinkOpen + | ItemBody::MaybeLinkClose(..) + | ItemBody::MaybeImage => true, + _ => false, + } + } +} + +impl<'a> Default for ItemBody { + fn default() -> Self { + ItemBody::Root + } +} + +/// Scanning modes for `Parser`'s `parse_line` method. +#[derive(PartialEq, Eq, Copy, Clone)] +enum TableParseMode { + /// Inside a paragraph, scanning for table headers. + Scan, + /// Inside a table. + Active, + /// Inside a paragraph, not scanning for table headers. + Disabled, +} + +pub struct BrokenLink<'a> { + pub span: std::ops::Range, + pub link_type: LinkType, + pub reference: &'a str, +} + +/// State for the first parsing pass. +/// +/// The first pass resolves all block structure, generating an AST. Within a block, items +/// are in a linear chain with potential inline markup identified. +struct FirstPass<'a, 'b> { + text: &'a str, + tree: Tree, + begin_list_item: bool, + last_line_blank: bool, + allocs: Allocations<'a>, + options: Options, + list_nesting: usize, + lookup_table: &'b LookupTable, +} + +impl<'a, 'b> FirstPass<'a, 'b> { + fn new(text: &'a str, options: Options, lookup_table: &'b LookupTable) -> FirstPass<'a, 'b> { + // This is a very naive heuristic for the number of nodes + // we'll need. + let start_capacity = max(128, text.len() / 32); + let tree = Tree::with_capacity(start_capacity); + FirstPass { + text, + tree, + begin_list_item: false, + last_line_blank: false, + allocs: Allocations::new(), + options, + list_nesting: 0, + lookup_table, + } + } + + fn run(mut self) -> (Tree, Allocations<'a>) { + let mut ix = 0; + while ix < self.text.len() { + ix = self.parse_block(ix); + } + for _ in 0..self.tree.spine_len() { + self.pop(ix); + } + (self.tree, self.allocs) + } + + /// Returns offset after block. + fn parse_block(&mut self, mut start_ix: usize) -> usize { + let bytes = self.text.as_bytes(); + let mut line_start = LineStart::new(&bytes[start_ix..]); + + let i = scan_containers(&self.tree, &mut line_start); + for _ in i..self.tree.spine_len() { + self.pop(start_ix); + } + + if self.options.contains(Options::ENABLE_FOOTNOTES) { + // finish footnote if it's still open and was preceeded by blank line + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::FootnoteDefinition(..) = self.tree[node_ix].item.body { + if self.last_line_blank { + self.pop(start_ix); + } + } + } + + // Footnote definitions of the form + // [^bar]: + // * anything really + let container_start = start_ix + line_start.bytes_scanned(); + if let Some(bytecount) = self.parse_footnote(container_start) { + start_ix = container_start + bytecount; + start_ix += scan_blank_line(&bytes[start_ix..]).unwrap_or(0); + line_start = LineStart::new(&bytes[start_ix..]); + } + } + + // Process new containers + loop { + let container_start = start_ix + line_start.bytes_scanned(); + if let Some((ch, index, indent)) = line_start.scan_list_marker() { + let after_marker_index = start_ix + line_start.bytes_scanned(); + self.continue_list(container_start, ch, index); + self.tree.append(Item { + start: container_start, + end: after_marker_index, // will get updated later if item not empty + body: ItemBody::ListItem(indent), + }); + self.tree.push(); + if let Some(n) = scan_blank_line(&bytes[after_marker_index..]) { + self.begin_list_item = true; + return after_marker_index + n; + } + if self.options.contains(Options::ENABLE_TASKLISTS) { + if let Some(is_checked) = line_start.scan_task_list_marker() { + self.tree.append(Item { + start: after_marker_index, + end: start_ix + line_start.bytes_scanned(), + body: ItemBody::TaskListMarker(is_checked), + }); + } + } + } else if line_start.scan_blockquote_marker() { + self.finish_list(start_ix); + self.tree.append(Item { + start: container_start, + end: 0, // will get set later + body: ItemBody::BlockQuote, + }); + self.tree.push(); + } else { + break; + } + } + + let ix = start_ix + line_start.bytes_scanned(); + + if let Some(n) = scan_blank_line(&bytes[ix..]) { + if let Some(node_ix) = self.tree.peek_up() { + match self.tree[node_ix].item.body { + ItemBody::BlockQuote => (), + _ => { + if self.begin_list_item { + // A list item can begin with at most one blank line. + self.pop(start_ix); + } + self.last_line_blank = true; + } + } + } + return ix + n; + } + + self.begin_list_item = false; + self.finish_list(start_ix); + + // Save `remaining_space` here to avoid needing to backtrack `line_start` for HTML blocks + let remaining_space = line_start.remaining_space(); + + let indent = line_start.scan_space_upto(4); + if indent == 4 { + let ix = start_ix + line_start.bytes_scanned(); + let remaining_space = line_start.remaining_space(); + return self.parse_indented_code_block(ix, remaining_space); + } + + let ix = start_ix + line_start.bytes_scanned(); + + // HTML Blocks + if bytes[ix] == b'<' { + // Types 1-5 are all detected by one function and all end with the same + // pattern + if let Some(html_end_tag) = get_html_end_tag(&bytes[(ix + 1)..]) { + return self.parse_html_block_type_1_to_5(ix, html_end_tag, remaining_space); + } + + // Detect type 6 + let possible_tag = scan_html_block_tag(&bytes[(ix + 1)..]).1; + if is_html_tag(possible_tag) { + return self.parse_html_block_type_6_or_7(ix, remaining_space); + } + + // Detect type 7 + if let Some(_html_bytes) = scan_html_type_7(&bytes[ix..]) { + return self.parse_html_block_type_6_or_7(ix, remaining_space); + } + } + + if let Ok(n) = scan_hrule(&bytes[ix..]) { + return self.parse_hrule(n, ix); + } + + if let Some(atx_size) = scan_atx_heading(&bytes[ix..]) { + return self.parse_atx_heading(ix, atx_size); + } + + // parse refdef + if let Some((bytecount, label, link_def)) = self.parse_refdef_total(ix) { + self.allocs.refdefs.entry(label).or_insert(link_def); + let ix = ix + bytecount; + // try to read trailing whitespace or it will register as a completely blank line + // TODO: shouldn't we do this for all block level items? + return ix + scan_blank_line(&bytes[ix..]).unwrap_or(0); + } + + if let Some((n, fence_ch)) = scan_code_fence(&bytes[ix..]) { + return self.parse_fenced_code_block(ix, indent, fence_ch, n); + } + self.parse_paragraph(ix) + } + + /// Returns the offset of the first line after the table. + /// Assumptions: current focus is a table element and the table header + /// matches the separator line (same number of columns). + fn parse_table(&mut self, table_cols: usize, head_start: usize, body_start: usize) -> usize { + // parse header. this shouldn't fail because we made sure the table header is ok + let (_sep_start, thead_ix) = self.parse_table_row_inner(head_start, table_cols); + self.tree[thead_ix].item.body = ItemBody::TableHead; + + // parse body + let mut ix = body_start; + while let Some((next_ix, _row_ix)) = self.parse_table_row(ix, table_cols) { + ix = next_ix; + } + + self.pop(ix); + ix + } + + /// Call this when containers are taken care of. + /// Returns bytes scanned, row_ix + fn parse_table_row_inner(&mut self, mut ix: usize, row_cells: usize) -> (usize, TreeIndex) { + let bytes = self.text.as_bytes(); + let mut cells = 0; + let mut final_cell_ix = None; + + let row_ix = self.tree.append(Item { + start: ix, + end: 0, // set at end of this function + body: ItemBody::TableRow, + }); + self.tree.push(); + + loop { + ix += scan_ch(&bytes[ix..], b'|'); + ix += scan_whitespace_no_nl(&bytes[ix..]); + + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + ix += eol_bytes; + break; + } + + let cell_ix = self.tree.append(Item { + start: ix, + end: ix, + body: ItemBody::TableCell, + }); + self.tree.push(); + let (next_ix, _brk) = self.parse_line(ix, TableParseMode::Active); + let trailing_whitespace = scan_rev_while(&bytes[..next_ix], is_ascii_whitespace); + + if let Some(cur_ix) = self.tree.cur() { + self.tree[cur_ix].item.end -= trailing_whitespace; + } + + self.tree[cell_ix].item.end = next_ix - trailing_whitespace; + self.tree.pop(); + + ix = next_ix; + cells += 1; + + if cells == row_cells { + final_cell_ix = Some(cell_ix); + } + } + + // fill empty cells if needed + // note: this is where GFM and commonmark-extra diverge. we follow + // GFM here + for _ in cells..row_cells { + self.tree.append(Item { + start: ix, + end: ix, + body: ItemBody::TableCell, + }); + } + + // drop excess cells + if let Some(cell_ix) = final_cell_ix { + self.tree[cell_ix].next = None; + } + + self.pop(ix); + + (ix, row_ix) + } + + /// Returns first offset after the row and the tree index of the row. + fn parse_table_row(&mut self, mut ix: usize, row_cells: usize) -> Option<(usize, TreeIndex)> { + let bytes = self.text.as_bytes(); + let mut line_start = LineStart::new(&bytes[ix..]); + let containers = scan_containers(&self.tree, &mut line_start); + if containers != self.tree.spine_len() { + return None; + } + line_start.scan_all_space(); + ix += line_start.bytes_scanned(); + if scan_paragraph_interrupt(&bytes[ix..]) { + return None; + } + + let (ix, row_ix) = self.parse_table_row_inner(ix, row_cells); + Some((ix, row_ix)) + } + + /// Returns offset of line start after paragraph. + fn parse_paragraph(&mut self, start_ix: usize) -> usize { + let node_ix = self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::Paragraph, + }); + self.tree.push(); + let bytes = self.text.as_bytes(); + + let mut ix = start_ix; + loop { + let scan_mode = if self.options.contains(Options::ENABLE_TABLES) && ix == start_ix { + TableParseMode::Scan + } else { + TableParseMode::Disabled + }; + let (next_ix, brk) = self.parse_line(ix, scan_mode); + + // break out when we find a table + if let Some(Item { + body: ItemBody::Table(alignment_ix), + .. + }) = brk + { + let table_cols = self.allocs[alignment_ix].len(); + self.tree[node_ix].item.body = ItemBody::Table(alignment_ix); + // this clears out any stuff we may have appended - but there may + // be a cleaner way + self.tree[node_ix].child = None; + self.tree.pop(); + self.tree.push(); + return self.parse_table(table_cols, ix, next_ix); + } + + ix = next_ix; + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if !line_start.scan_space(4) { + let ix_new = ix + line_start.bytes_scanned(); + if n_containers == self.tree.spine_len() { + if let Some(ix_setext) = self.parse_setext_heading(ix_new, node_ix) { + if let Some(Item { + start, + body: ItemBody::HardBreak, + .. + }) = brk + { + if bytes[start] == b'\\' { + self.tree.append_text(start, start + 1); + } + } + ix = ix_setext; + break; + } + } + // first check for non-empty lists, then for other interrupts + let suffix = &bytes[ix_new..]; + if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { + break; + } + } + line_start.scan_all_space(); + if line_start.is_at_eol() { + break; + } + ix = next_ix + line_start.bytes_scanned(); + if let Some(item) = brk { + self.tree.append(item); + } + } + + self.pop(ix); + ix + } + + /// Returns end ix of setext_heading on success. + fn parse_setext_heading(&mut self, ix: usize, node_ix: TreeIndex) -> Option { + let bytes = self.text.as_bytes(); + let (n, level) = scan_setext_heading(&bytes[ix..])?; + self.tree[node_ix].item.body = ItemBody::Heading(level); + + // strip trailing whitespace + if let Some(cur_ix) = self.tree.cur() { + self.tree[cur_ix].item.end -= scan_rev_while( + &bytes[..self.tree[cur_ix].item.end], + is_ascii_whitespace_no_nl, + ); + } + + Some(ix + n) + } + + /// Parse a line of input, appending text and items to tree. + /// + /// Returns: index after line and an item representing the break. + fn parse_line(&mut self, start: usize, mode: TableParseMode) -> (usize, Option) { + let bytes = &self.text.as_bytes(); + let mut pipes = 0; + let mut last_pipe_ix = start; + let mut begin_text = start; + + let (final_ix, brk) = + iterate_special_bytes(&self.lookup_table, bytes, start, |ix, byte| { + match byte { + b'\n' | b'\r' => { + if let TableParseMode::Active = mode { + return LoopInstruction::BreakAtWith(ix, None); + } + + let mut i = ix; + let eol_bytes = scan_eol(&bytes[ix..]).unwrap(); + if mode == TableParseMode::Scan && pipes > 0 { + // check if we may be parsing a table + let next_line_ix = ix + eol_bytes; + let mut line_start = LineStart::new(&bytes[next_line_ix..]); + if scan_containers(&self.tree, &mut line_start) == self.tree.spine_len() + { + let table_head_ix = next_line_ix + line_start.bytes_scanned(); + let (table_head_bytes, alignment) = + scan_table_head(&bytes[table_head_ix..]); + + if table_head_bytes > 0 { + // computing header count from number of pipes + let header_count = + count_header_cols(bytes, pipes, start, last_pipe_ix); + + // make sure they match the number of columns we find in separator line + if alignment.len() == header_count { + let alignment_ix = + self.allocs.allocate_alignment(alignment); + let end_ix = table_head_ix + table_head_bytes; + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, // must update later + body: ItemBody::Table(alignment_ix), + }), + ); + } + } + } + } + + let end_ix = ix + eol_bytes; + let trailing_backslashes = scan_rev_while(&bytes[..ix], |b| b == b'\\'); + if trailing_backslashes % 2 == 1 && end_ix < self.text.len() { + i -= 1; + self.tree.append_text(begin_text, i); + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::HardBreak, + }), + ); + } + let trailing_whitespace = + scan_rev_while(&bytes[..ix], is_ascii_whitespace_no_nl); + if trailing_whitespace >= 2 { + i -= trailing_whitespace; + self.tree.append_text(begin_text, i); + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::HardBreak, + }), + ); + } + + self.tree.append_text(begin_text, ix); + LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::SoftBreak, + }), + ) + } + b'\\' => { + if ix + 1 < self.text.len() && is_ascii_punctuation(bytes[ix + 1]) { + self.tree.append_text(begin_text, ix); + if bytes[ix + 1] == b'`' { + let count = 1 + scan_ch_repeat(&bytes[(ix + 2)..], b'`'); + self.tree.append(Item { + start: ix + 1, + end: ix + count + 1, + body: ItemBody::MaybeCode(count, true), + }); + begin_text = ix + 1 + count; + LoopInstruction::ContinueAndSkip(count) + } else { + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(1) + } + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + c @ b'*' | c @ b'_' | c @ b'~' => { + let string_suffix = &self.text[ix..]; + let count = 1 + scan_ch_repeat(&string_suffix.as_bytes()[1..], c); + let can_open = delim_run_can_open(self.text, string_suffix, count, ix); + let can_close = delim_run_can_close(self.text, string_suffix, count, ix); + let is_valid_seq = c != b'~' || count == 2; + + if (can_open || can_close) && is_valid_seq { + self.tree.append_text(begin_text, ix); + for i in 0..count { + self.tree.append(Item { + start: ix + i, + end: ix + i + 1, + body: ItemBody::MaybeEmphasis(count - i, can_open, can_close), + }); + } + begin_text = ix + count; + } + LoopInstruction::ContinueAndSkip(count - 1) + } + b'`' => { + self.tree.append_text(begin_text, ix); + let count = 1 + scan_ch_repeat(&bytes[(ix + 1)..], b'`'); + self.tree.append(Item { + start: ix, + end: ix + count, + body: ItemBody::MaybeCode(count, false), + }); + begin_text = ix + count; + LoopInstruction::ContinueAndSkip(count - 1) + } + b'<' => { + // Note: could detect some non-HTML cases and early escape here, but not + // clear that's a win. + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeHtml, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b'!' => { + if ix + 1 < self.text.len() && bytes[ix + 1] == b'[' { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 2, + body: ItemBody::MaybeImage, + }); + begin_text = ix + 2; + LoopInstruction::ContinueAndSkip(1) + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + b'[' => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeLinkOpen, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b']' => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeLinkClose(true), + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b'&' => match scan_entity(&bytes[ix..]) { + (n, Some(value)) => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + n, + body: ItemBody::SynthesizeText(self.allocs.allocate_cow(value)), + }); + begin_text = ix + n; + LoopInstruction::ContinueAndSkip(n - 1) + } + _ => LoopInstruction::ContinueAndSkip(0), + }, + b'|' => { + if let TableParseMode::Active = mode { + LoopInstruction::BreakAtWith(ix, None) + } else { + last_pipe_ix = ix; + pipes += 1; + LoopInstruction::ContinueAndSkip(0) + } + } + b'.' => { + if ix + 2 < bytes.len() && bytes[ix + 1] == b'.' && bytes[ix + 2] == b'.' { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 3, + body: ItemBody::SynthesizeChar('…'), + }); + begin_text = ix + 3; + LoopInstruction::ContinueAndSkip(2) + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + b'-' => { + let count = 1 + scan_ch_repeat(&bytes[(ix + 1)..], b'-'); + if count == 1 { + LoopInstruction::ContinueAndSkip(0) + } else { + let itembody = if count == 2 { + ItemBody::SynthesizeChar('–') + } else if count == 3 { + ItemBody::SynthesizeChar('—') + } else { + let (ems, ens) = match count % 6 { + 0 | 3 => (count / 3, 0), + 2 | 4 => (0, count / 2), + 1 => (count / 3 - 1, 2), + _ => (count / 3, 1), + }; + // – and — are 3 bytes each in utf8 + let mut buf = String::with_capacity(3 * (ems + ens)); + for _ in 0..ems { + buf.push('—'); + } + for _ in 0..ens { + buf.push('–'); + } + ItemBody::SynthesizeText(self.allocs.allocate_cow(buf.into())) + }; + + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + count, + body: itembody, + }); + begin_text = ix + count; + LoopInstruction::ContinueAndSkip(count - 1) + } + } + c @ b'\'' | c @ b'"' => { + let string_suffix = &self.text[ix..]; + let can_open = delim_run_can_open(self.text, string_suffix, 1, ix); + let can_close = delim_run_can_close(self.text, string_suffix, 1, ix); + + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeSmartQuote(c, can_open, can_close), + }); + begin_text = ix + 1; + + LoopInstruction::ContinueAndSkip(0) + } + _ => LoopInstruction::ContinueAndSkip(0), + } + }); + + if brk.is_none() { + // need to close text at eof + self.tree.append_text(begin_text, final_ix); + } + (final_ix, brk) + } + + /// Check whether we should allow a paragraph interrupt by lists. Only non-empty + /// lists are allowed. + fn interrupt_paragraph_by_list(&self, suffix: &[u8]) -> bool { + scan_listitem(suffix).map_or(false, |(ix, delim, index, _)| { + self.list_nesting > 0 || + // we don't allow interruption by either empty lists or + // numbered lists starting at an index other than 1 + !scan_empty_list(&suffix[ix..]) && (delim == b'*' || delim == b'-' || index == 1) + }) + } + + /// When start_ix is at the beginning of an HTML block of type 1 to 5, + /// this will find the end of the block, adding the block itself to the + /// tree and also keeping track of the lines of HTML within the block. + /// + /// The html_end_tag is the tag that must be found on a line to end the block. + fn parse_html_block_type_1_to_5( + &mut self, + start_ix: usize, + html_end_tag: &str, + mut remaining_space: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_html_line(remaining_space, line_start_ix, ix); + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() { + break; + } + + if (&self.text[line_start_ix..ix]).contains(html_end_tag) { + break; + } + + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + } + ix + } + + /// When start_ix is at the beginning of an HTML block of type 6 or 7, + /// this will consume lines until there is a blank line and keep track of + /// the HTML within the block. + fn parse_html_block_type_6_or_7( + &mut self, + start_ix: usize, + mut remaining_space: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_html_line(remaining_space, line_start_ix, ix); + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() || line_start.is_at_eol() { + break; + } + + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() || scan_blank_line(&bytes[next_line_ix..]).is_some() + { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + } + ix + } + + fn parse_indented_code_block(&mut self, start_ix: usize, mut remaining_space: usize) -> usize { + self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::IndentCodeBlock, + }); + self.tree.push(); + let bytes = self.text.as_bytes(); + let mut last_nonblank_child = None; + let mut last_nonblank_ix = 0; + let mut end_ix = 0; + let mut last_line_blank = false; + + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_code_text(remaining_space, line_start_ix, ix); + // TODO(spec clarification): should we synthesize newline at EOF? + + if !last_line_blank { + last_nonblank_child = self.tree.cur(); + last_nonblank_ix = ix; + end_ix = ix; + } + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() + || !(line_start.scan_space(4) || line_start.is_at_eol()) + { + break; + } + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + last_line_blank = scan_blank_line(&bytes[ix..]).is_some(); + } + + // Trim trailing blank lines. + if let Some(child) = last_nonblank_child { + self.tree[child].next = None; + self.tree[child].item.end = last_nonblank_ix; + } + self.pop(end_ix); + ix + } + + fn parse_fenced_code_block( + &mut self, + start_ix: usize, + indent: usize, + fence_ch: u8, + n_fence_char: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut info_start = start_ix + n_fence_char; + info_start += scan_whitespace_no_nl(&bytes[info_start..]); + // TODO: info strings are typically very short. wouldnt it be faster + // to just do a forward scan here? + let mut ix = info_start + scan_nextline(&bytes[info_start..]); + let info_end = ix - scan_rev_while(&bytes[info_start..ix], is_ascii_whitespace); + let info_string = unescape(&self.text[info_start..info_end]); + self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::FencedCodeBlock(self.allocs.allocate_cow(info_string)), + }); + self.tree.push(); + loop { + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() { + break; + } + line_start.scan_space(indent); + let mut close_line_start = line_start.clone(); + if !close_line_start.scan_space(4) { + let close_ix = ix + close_line_start.bytes_scanned(); + if let Some(n) = scan_closing_code_fence(&bytes[close_ix..], fence_ch, n_fence_char) + { + ix = close_ix + n; + break; + } + } + let remaining_space = line_start.remaining_space(); + ix += line_start.bytes_scanned(); + let next_ix = ix + scan_nextline(&bytes[ix..]); + self.append_code_text(remaining_space, ix, next_ix); + ix = next_ix; + } + + self.pop(ix); + + // try to read trailing whitespace or it will register as a completely blank line + ix + scan_blank_line(&bytes[ix..]).unwrap_or(0) + } + + fn append_code_text(&mut self, remaining_space: usize, start: usize, end: usize) { + if remaining_space > 0 { + let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); + self.tree.append(Item { + start, + end: start, + body: ItemBody::SynthesizeText(cow_ix), + }); + } + if self.text.as_bytes()[end - 2] == b'\r' { + // Normalize CRLF to LF + self.tree.append_text(start, end - 2); + self.tree.append_text(end - 1, end); + } else { + self.tree.append_text(start, end); + } + } + + /// Appends a line of HTML to the tree. + fn append_html_line(&mut self, remaining_space: usize, start: usize, end: usize) { + if remaining_space > 0 { + let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); + self.tree.append(Item { + start, + end: start, + // TODO: maybe this should synthesize to html rather than text? + body: ItemBody::SynthesizeText(cow_ix), + }); + } + if self.text.as_bytes()[end - 2] == b'\r' { + // Normalize CRLF to LF + self.tree.append(Item { + start, + end: end - 2, + body: ItemBody::Html, + }); + self.tree.append(Item { + start: end - 1, + end, + body: ItemBody::Html, + }); + } else { + self.tree.append(Item { + start, + end, + body: ItemBody::Html, + }); + } + } + + /// Pop a container, setting its end. + fn pop(&mut self, ix: usize) { + let cur_ix = self.tree.pop().unwrap(); + self.tree[cur_ix].item.end = ix; + if let ItemBody::List(true, _, _) = self.tree[cur_ix].item.body { + surgerize_tight_list(&mut self.tree, cur_ix); + } + } + + /// Close a list if it's open. Also set loose if last line was blank + fn finish_list(&mut self, ix: usize) { + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::List(_, _, _) = self.tree[node_ix].item.body { + self.pop(ix); + self.list_nesting -= 1; + } + } + if self.last_line_blank { + if let Some(node_ix) = self.tree.peek_grandparent() { + if let ItemBody::List(ref mut is_tight, _, _) = self.tree[node_ix].item.body { + *is_tight = false; + } + } + self.last_line_blank = false; + } + } + + /// Continue an existing list or start a new one if there's not an open + /// list that matches. + fn continue_list(&mut self, start: usize, ch: u8, index: u64) { + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::List(ref mut is_tight, existing_ch, _) = self.tree[node_ix].item.body { + if existing_ch == ch { + if self.last_line_blank { + *is_tight = false; + self.last_line_blank = false; + } + return; + } + } + // TODO: this is not the best choice for end; maybe get end from last list item. + self.finish_list(start); + } + self.tree.append(Item { + start, + end: 0, // will get set later + body: ItemBody::List(true, ch, index), + }); + self.list_nesting += 1; + self.tree.push(); + self.last_line_blank = false; + } + + /// Parse a thematic break. + /// + /// Returns index of start of next line. + fn parse_hrule(&mut self, hrule_size: usize, ix: usize) -> usize { + self.tree.append(Item { + start: ix, + end: ix + hrule_size, + body: ItemBody::Rule, + }); + ix + hrule_size + } + + /// Parse an ATX heading. + /// + /// Returns index of start of next line. + fn parse_atx_heading(&mut self, mut ix: usize, atx_size: usize) -> usize { + let heading_ix = self.tree.append(Item { + start: ix, + end: 0, // set later + body: ItemBody::Heading(atx_size as u32), + }); + ix += atx_size; + // next char is space or eol (guaranteed by scan_atx_heading) + let bytes = self.text.as_bytes(); + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + self.tree[heading_ix].item.end = ix + eol_bytes; + return ix + eol_bytes; + } + // skip leading spaces + let skip_spaces = scan_whitespace_no_nl(&bytes[ix..]); + ix += skip_spaces; + + // now handle the header text + let header_start = ix; + let header_node_idx = self.tree.push(); // so that we can set the endpoint later + ix = self.parse_line(ix, TableParseMode::Disabled).0; + self.tree[header_node_idx].item.end = ix; + + // remove trailing matter from header text + if let Some(cur_ix) = self.tree.cur() { + let header_text = &bytes[header_start..ix]; + let mut limit = header_text + .iter() + .rposition(|&b| !(b == b'\n' || b == b'\r' || b == b' ')) + .map_or(0, |i| i + 1); + let closer = header_text[..limit] + .iter() + .rposition(|&b| b != b'#') + .map_or(0, |i| i + 1); + if closer == 0 { + limit = closer; + } else { + let spaces = scan_rev_while(&header_text[..closer], |b| b == b' '); + if spaces > 0 { + limit = closer - spaces; + } + } + self.tree[cur_ix].item.end = limit + header_start; + } + + self.tree.pop(); + ix + } + + /// Returns the number of bytes scanned on success. + fn parse_footnote(&mut self, start: usize) -> Option { + let bytes = &self.text.as_bytes()[start..]; + if !bytes.starts_with(b"[^") { + return None; + } + let (mut i, label) = self.parse_refdef_label(start + 2)?; + i += 2; + if scan_ch(&bytes[i..], b':') == 0 { + return None; + } + i += 1; + self.finish_list(start); + self.tree.append(Item { + start, + end: 0, // will get set later + // TODO: check whether the label here is strictly necessary + body: ItemBody::FootnoteDefinition(self.allocs.allocate_cow(label)), + }); + self.tree.push(); + Some(i) + } + + /// Tries to parse a reference label, which can be interrupted by new blocks. + /// On success, returns the number of bytes of the label and the label itself. + fn parse_refdef_label(&self, start: usize) -> Option<(usize, CowStr<'a>)> { + scan_link_label_rest(&self.text[start..], &|bytes| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(&self.tree, &mut line_start); + let bytes_scanned = line_start.bytes_scanned(); + + let suffix = &bytes[bytes_scanned..]; + if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { + None + } else { + Some(bytes_scanned) + } + }) + } + + /// Returns number of bytes scanned, label and definition on success. + fn parse_refdef_total(&mut self, start: usize) -> Option<(usize, LinkLabel<'a>, LinkDef<'a>)> { + let bytes = &self.text.as_bytes()[start..]; + if scan_ch(bytes, b'[') == 0 { + return None; + } + let (mut i, label) = self.parse_refdef_label(start + 1)?; + i += 1; + if scan_ch(&bytes[i..], b':') == 0 { + return None; + } + i += 1; + let (bytecount, link_def) = self.scan_refdef(start + i)?; + Some((bytecount + i, UniCase::new(label), link_def)) + } + + /// Returns number of bytes and number of newlines + fn scan_refdef_space(&self, bytes: &[u8], mut i: usize) -> Option<(usize, usize)> { + let mut newlines = 0; + loop { + let whitespaces = scan_whitespace_no_nl(&bytes[i..]); + i += whitespaces; + if let Some(eol_bytes) = scan_eol(&bytes[i..]) { + i += eol_bytes; + newlines += 1; + if newlines > 1 { + return None; + } + } else { + break; + } + let mut line_start = LineStart::new(&bytes[i..]); + if self.tree.spine_len() != scan_containers(&self.tree, &mut line_start) { + return None; + } + i += line_start.bytes_scanned(); + } + Some((i, newlines)) + } + + /// Returns # of bytes and definition. + /// Assumes the label of the reference including colon has already been scanned. + fn scan_refdef(&self, start: usize) -> Option<(usize, LinkDef<'a>)> { + let bytes = self.text.as_bytes(); + + // whitespace between label and url (including up to one newline) + let (mut i, _newlines) = self.scan_refdef_space(bytes, start)?; + + // scan link dest + let (dest_length, dest) = scan_link_dest(self.text, i, 1)?; + if dest_length == 0 { + return None; + } + let dest = unescape(dest); + i += dest_length; + + // no title + let mut backup = (i - start, LinkDef { dest, title: None }); + + // scan whitespace between dest and label + let (mut i, newlines) = + if let Some((new_i, mut newlines)) = self.scan_refdef_space(bytes, i) { + if i == self.text.len() { + newlines += 1; + } + if new_i == i && newlines == 0 { + return None; + } + if newlines > 1 { + return Some(backup); + }; + (new_i, newlines) + } else { + return Some(backup); + }; + + // scan title + // if this fails but newline == 1, return also a refdef without title + if let Some((title_length, title)) = scan_refdef_title(&self.text[i..]) { + i += title_length; + backup.1.title = Some(unescape(title)); + } else if newlines > 0 { + return Some(backup); + } else { + return None; + }; + + // scan EOL + if let Some(bytes) = scan_blank_line(&bytes[i..]) { + backup.0 = i + bytes - start; + Some(backup) + } else if newlines > 0 { + Some(backup) + } else { + None + } + } +} + +/// Returns number of containers scanned. +fn scan_containers(tree: &Tree, line_start: &mut LineStart) -> usize { + let mut i = 0; + for &node_ix in tree.walk_spine() { + match tree[node_ix].item.body { + ItemBody::BlockQuote => { + let save = line_start.clone(); + if !line_start.scan_blockquote_marker() { + *line_start = save; + break; + } + } + ItemBody::ListItem(indent) => { + let save = line_start.clone(); + if !line_start.scan_space(indent) { + if !line_start.is_at_eol() { + *line_start = save; + break; + } + } + } + _ => (), + } + i += 1; + } + i +} + +/// Computes the number of header columns in a table line by computing the number of dividing pipes +/// that aren't followed or preceeded by whitespace. +fn count_header_cols( + bytes: &[u8], + mut pipes: usize, + mut start: usize, + last_pipe_ix: usize, +) -> usize { + // was first pipe preceeded by whitespace? if so, subtract one + start += scan_whitespace_no_nl(&bytes[start..]); + if bytes[start] == b'|' { + pipes -= 1; + } + + // was last pipe followed by whitespace? if so, sub one + if scan_blank_line(&bytes[(last_pipe_ix + 1)..]).is_some() { + pipes + } else { + pipes + 1 + } +} + +impl<'a> Tree { + fn append_text(&mut self, start: usize, end: usize) { + if end > start { + if let Some(ix) = self.cur() { + if ItemBody::Text == self[ix].item.body && self[ix].item.end == start { + self[ix].item.end = end; + return; + } + } + self.append(Item { + start, + end, + body: ItemBody::Text, + }); + } + } +} + +/// Determines whether the delimiter run starting at given index is +/// left-flanking, as defined by the commonmark spec (and isn't intraword +/// for _ delims). +/// suffix is &s[ix..], which is passed in as an optimization, since taking +/// a string subslice is O(n). +fn delim_run_can_open(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { + let next_char = if let Some(c) = suffix.chars().nth(run_len) { + c + } else { + return false; + }; + if next_char.is_whitespace() { + return false; + } + if ix == 0 { + return true; + } + let delim = suffix.chars().next().unwrap(); + if delim == '*' && !is_punctuation(next_char) { + return true; + } + + let prev_char = s[..ix].chars().last().unwrap(); + + prev_char.is_whitespace() + || is_punctuation(prev_char) && (delim != '\'' || ![']', ')'].contains(&prev_char)) +} + +/// Determines whether the delimiter run starting at given index is +/// left-flanking, as defined by the commonmark spec (and isn't intraword +/// for _ delims) +fn delim_run_can_close(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { + if ix == 0 { + return false; + } + let prev_char = s[..ix].chars().last().unwrap(); + if prev_char.is_whitespace() { + return false; + } + let next_char = if let Some(c) = suffix.chars().nth(run_len) { + c + } else { + return true; + }; + let delim = suffix.chars().next().unwrap(); + if delim == '*' && !is_punctuation(prev_char) { + return true; + } + + next_char.is_whitespace() || is_punctuation(next_char) +} + +/// Checks whether we should break a paragraph on the given input. +/// Note: lists are dealt with in `interrupt_paragraph_by_list`, because determing +/// whether to break on a list requires additional context. +fn scan_paragraph_interrupt(bytes: &[u8]) -> bool { + if scan_eol(bytes).is_some() + || scan_hrule(bytes).is_ok() + || scan_atx_heading(bytes).is_some() + || scan_code_fence(bytes).is_some() + || scan_blockquote_start(bytes).is_some() + { + return true; + } + bytes.starts_with(b"<") + && (get_html_end_tag(&bytes[1..]).is_some() + || is_html_tag(scan_html_block_tag(&bytes[1..]).1)) +} + +/// Assumes `text_bytes` is preceded by `<`. +fn get_html_end_tag(text_bytes: &[u8]) -> Option<&'static str> { + static BEGIN_TAGS: &[&[u8]; 3] = &[b"pre", b"style", b"script"]; + static ST_BEGIN_TAGS: &[&[u8]; 3] = &[b"!--", b"?", b"![CDATA["]; + + for (beg_tag, end_tag) in BEGIN_TAGS + .iter() + .zip(["", "", ""].iter()) + { + let tag_len = beg_tag.len(); + + if text_bytes.len() < tag_len { + // begin tags are increasing in size + break; + } + + if !text_bytes[..tag_len].eq_ignore_ascii_case(beg_tag) { + continue; + } + + // Must either be the end of the line... + if text_bytes.len() == tag_len { + return Some(end_tag); + } + + // ...or be followed by whitespace, newline, or '>'. + let s = text_bytes[tag_len]; + if is_ascii_whitespace(s) || s == b'>' { + return Some(end_tag); + } + } + + for (beg_tag, end_tag) in ST_BEGIN_TAGS.iter().zip(["-->", "?>", "]]>"].iter()) { + if text_bytes.starts_with(beg_tag) { + return Some(end_tag); + } + } + + if text_bytes.len() > 1 + && text_bytes[0] == b'!' + && text_bytes[1] >= b'A' + && text_bytes[1] <= b'Z' + { + Some(">") + } else { + None + } +} + +#[derive(Copy, Clone, Debug)] +struct InlineEl { + start: TreeIndex, // offset of tree node + count: usize, + c: u8, // b'*' or b'_' + both: bool, // can both open and close +} + +#[derive(Debug, Clone, Default)] +struct InlineStack { + stack: Vec, + // Lower bounds for matching indices in the stack. For example + // a strikethrough delimiter will never match with any element + // in the stack with index smaller than + // `lower_bounds[InlineStack::TILDES]`. + lower_bounds: [usize; 7], +} + +impl InlineStack { + /// These are indices into the lower bounds array. + /// Not both refers to the property that the delimiter can not both + /// be opener as a closer. + const UNDERSCORE_NOT_BOTH: usize = 0; + const ASTERISK_NOT_BOTH: usize = 1; + const ASTERISK_BASE: usize = 2; + const TILDES: usize = 5; + const UNDERSCORE_BOTH: usize = 6; + + fn pop_all(&mut self, tree: &mut Tree) { + for el in self.stack.drain(..) { + for i in 0..el.count { + tree[el.start + i].item.body = ItemBody::Text; + } + } + self.lower_bounds = [0; 7]; + } + + fn get_lowerbound(&self, c: u8, count: usize, both: bool) -> usize { + if c == b'_' { + if both { + self.lower_bounds[InlineStack::UNDERSCORE_BOTH] + } else { + self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] + } + } else if c == b'*' { + let mod3_lower = self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3]; + if both { + mod3_lower + } else { + min( + mod3_lower, + self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH], + ) + } + } else { + self.lower_bounds[InlineStack::TILDES] + } + } + + fn set_lowerbound(&mut self, c: u8, count: usize, both: bool, new_bound: usize) { + if c == b'_' { + if both { + self.lower_bounds[InlineStack::UNDERSCORE_BOTH] = new_bound; + } else { + self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] = new_bound; + } + } else if c == b'*' { + self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3] = new_bound; + if !both { + self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH] = new_bound; + } + } else { + self.lower_bounds[InlineStack::TILDES] = new_bound; + } + } + + fn find_match( + &mut self, + tree: &mut Tree, + c: u8, + count: usize, + both: bool, + ) -> Option { + let lowerbound = min(self.stack.len(), self.get_lowerbound(c, count, both)); + let res = self.stack[lowerbound..] + .iter() + .cloned() + .enumerate() + .rfind(|(_, el)| { + el.c == c && (!both && !el.both || (count + el.count) % 3 != 0 || count % 3 == 0) + }); + + if let Some((matching_ix, matching_el)) = res { + let matching_ix = matching_ix + lowerbound; + for el in &self.stack[(matching_ix + 1)..] { + for i in 0..el.count { + tree[el.start + i].item.body = ItemBody::Text; + } + } + self.stack.truncate(matching_ix); + Some(matching_el) + } else { + self.set_lowerbound(c, count, both, self.stack.len()); + None + } + } + + fn push(&mut self, el: InlineEl) { + self.stack.push(el) + } +} + +#[derive(Debug, Clone)] +enum RefScan<'a> { + // label, source ix of label end + LinkLabel(CowStr<'a>, usize), + // contains next node index + Collapsed(Option), + Failed, +} + +/// Skips forward within a block to a node which spans (ends inclusive) the given +/// index into the source. +fn scan_nodes_to_ix( + tree: &Tree, + mut node: Option, + ix: usize, +) -> Option { + while let Some(node_ix) = node { + if tree[node_ix].item.end <= ix { + node = tree[node_ix].next; + } else { + break; + } + } + node +} + +/// Scans an inline link label, which cannot be interrupted. +/// Returns number of bytes (including brackets) and label on success. +fn scan_link_label<'text, 'tree>( + tree: &'tree Tree, + text: &'text str, + allow_footnote_refs: bool, +) -> Option<(usize, ReferenceLabel<'text>)> { + let bytes = &text.as_bytes(); + if bytes.len() < 2 || bytes[0] != b'[' { + return None; + } + let linebreak_handler = |bytes: &[u8]| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(tree, &mut line_start); + Some(line_start.bytes_scanned()) + }; + let pair = if allow_footnote_refs && b'^' == bytes[1] { + let (byte_index, cow) = scan_link_label_rest(&text[2..], &linebreak_handler)?; + (byte_index + 2, ReferenceLabel::Footnote(cow)) + } else { + let (byte_index, cow) = scan_link_label_rest(&text[1..], &linebreak_handler)?; + (byte_index + 1, ReferenceLabel::Link(cow)) + }; + Some(pair) +} + +fn scan_reference<'a, 'b>( + tree: &'a Tree, + text: &'b str, + cur: Option, + allow_footnote_refs: bool, +) -> RefScan<'b> { + let cur_ix = match cur { + None => return RefScan::Failed, + Some(cur_ix) => cur_ix, + }; + let start = tree[cur_ix].item.start; + let tail = &text.as_bytes()[start..]; + + if tail.starts_with(b"[]") { + let closing_node = tree[cur_ix].next.unwrap(); + RefScan::Collapsed(tree[closing_node].next) + } else if let Some((ix, ReferenceLabel::Link(label))) = + scan_link_label(tree, &text[start..], allow_footnote_refs) + { + RefScan::LinkLabel(label, start + ix) + } else { + RefScan::Failed + } +} + +#[derive(Clone, Default)] +struct LinkStack { + inner: Vec, + disabled_ix: usize, +} + +impl LinkStack { + fn push(&mut self, el: LinkStackEl) { + self.inner.push(el); + } + + fn pop(&mut self) -> Option { + let el = self.inner.pop(); + self.disabled_ix = std::cmp::min(self.disabled_ix, self.inner.len()); + el + } + + fn clear(&mut self) { + self.inner.clear(); + self.disabled_ix = 0; + } + + fn disable_all_links(&mut self) { + for el in &mut self.inner[self.disabled_ix..] { + if el.ty == LinkStackTy::Link { + el.ty = LinkStackTy::Disabled; + } + } + self.disabled_ix = self.inner.len(); + } +} + +#[derive(Clone, Debug)] +struct LinkStackEl { + node: TreeIndex, + ty: LinkStackTy, +} + +#[derive(PartialEq, Clone, Debug)] +enum LinkStackTy { + Link, + Image, + Disabled, +} + +#[derive(Clone)] +struct LinkDef<'a> { + dest: CowStr<'a>, + title: Option>, +} + +/// Tracks tree indices of code span delimiters of each length. It should prevent +/// quadratic scanning behaviours by providing (amortized) constant time lookups. +struct CodeDelims { + inner: HashMap>, + seen_first: bool, +} + +impl CodeDelims { + fn new() -> Self { + Self { + inner: Default::default(), + seen_first: false, + } + } + + fn insert(&mut self, count: usize, ix: TreeIndex) { + if self.seen_first { + self.inner + .entry(count) + .or_insert_with(Default::default) + .push_back(ix); + } else { + // Skip the first insert, since that delimiter will always + // be an opener and not a closer. + self.seen_first = true; + } + } + + fn is_populated(&self) -> bool { + !self.inner.is_empty() + } + + fn find(&mut self, open_ix: TreeIndex, count: usize) -> Option { + while let Some(ix) = self.inner.get_mut(&count)?.pop_front() { + if ix > open_ix { + return Some(ix); + } + } + None + } + + fn clear(&mut self) { + self.inner.clear(); + self.seen_first = false; + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct LinkIndex(usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct CowIndex(usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct AlignmentIndex(usize); + +#[derive(Clone)] +struct Allocations<'a> { + refdefs: HashMap, LinkDef<'a>>, + links: Vec<(LinkType, CowStr<'a>, CowStr<'a>)>, + cows: Vec>, + alignments: Vec>, +} + +impl<'a> Allocations<'a> { + fn new() -> Self { + Self { + refdefs: HashMap::new(), + links: Vec::with_capacity(128), + cows: Vec::new(), + alignments: Vec::new(), + } + } + + fn allocate_cow(&mut self, cow: CowStr<'a>) -> CowIndex { + let ix = self.cows.len(); + self.cows.push(cow); + CowIndex(ix) + } + + fn allocate_link(&mut self, ty: LinkType, url: CowStr<'a>, title: CowStr<'a>) -> LinkIndex { + let ix = self.links.len(); + self.links.push((ty, url, title)); + LinkIndex(ix) + } + + fn allocate_alignment(&mut self, alignment: Vec) -> AlignmentIndex { + let ix = self.alignments.len(); + self.alignments.push(alignment); + AlignmentIndex(ix) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = CowStr<'a>; + + fn index(&self, ix: CowIndex) -> &Self::Output { + self.cows.index(ix.0) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = (LinkType, CowStr<'a>, CowStr<'a>); + + fn index(&self, ix: LinkIndex) -> &Self::Output { + self.links.index(ix.0) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = Vec; + + fn index(&self, ix: AlignmentIndex) -> &Self::Output { + self.alignments.index(ix.0) + } +} + +/// A struct containing information on the reachability of certain inline HTML +/// elements. In particular, for cdata elements (` [bool; 256] { + let mut bytes = [false; 256]; + let standard_bytes = [ + b'\n', b'\r', b'*', b'_', b'&', b'\\', b'[', b']', b'<', b'!', b'`', + ]; + + for &byte in &standard_bytes { + bytes[byte as usize] = true; + } + if options.contains(Options::ENABLE_TABLES) { + bytes[b'|' as usize] = true; + } + if options.contains(Options::ENABLE_STRIKETHROUGH) { + bytes[b'~' as usize] = true; + } + if options.contains(Options::ENABLE_SMART_PUNCTUATION) { + for &byte in &[b'.', b'-', b'"', b'\''] { + bytes[byte as usize] = true; + } + } + + bytes +} + +pub(crate) fn create_lut(options: &Options) -> LookupTable { + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + LookupTable { + simd: crate::simd::compute_lookup(options), + scalar: special_bytes(options), + } + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + special_bytes(options) + } +} + +pub type BrokenLinkCallback<'a> = + Option<&'a mut dyn FnMut(BrokenLink) -> Option<(CowStr<'a>, CowStr<'a>)>>; + +/// Markdown event iterator. +pub struct Parser<'a> { + text: &'a str, + options: Options, + tree: Tree, + allocs: Allocations<'a>, + broken_link_callback: BrokenLinkCallback<'a>, + html_scan_guard: HtmlScanGuard, + + // used by inline passes. store them here for reuse + inline_stack: InlineStack, + link_stack: LinkStack, +} + +impl<'a> Parser<'a> { + /// Creates a new event iterator for a markdown string without any options enabled. + pub fn new(text: &'a str) -> Parser<'a> { + Parser::new_ext(text, Options::empty()) + } + + /// Creates a new event iterator for a markdown string with given options. + pub fn new_ext(text: &'a str, options: Options) -> Parser<'a> { + Parser::new_with_broken_link_callback(text, options, None) + } + + /// In case the parser encounters any potential links that have a broken + /// reference (e.g `[foo]` when there is no `[foo]: ` entry at the bottom) + /// the provided callback will be called with the reference name, + /// and the returned pair will be used as the link name and title if it is not + /// `None`. + pub fn new_with_broken_link_callback( + text: &'a str, + options: Options, + broken_link_callback: BrokenLinkCallback<'a>, + ) -> Parser<'a> { + let lut = create_lut(&options); + let first_pass = FirstPass::new(text, options, &lut); + let (mut tree, allocs) = first_pass.run(); + tree.reset(); + let inline_stack = Default::default(); + let link_stack = Default::default(); + let html_scan_guard = Default::default(); + Parser { + text, + options, + tree, + allocs, + broken_link_callback, + inline_stack, + link_stack, + html_scan_guard, + } + } + + /// Handle inline markup. + /// + /// When the parser encounters any item indicating potential inline markup, all + /// inline markup passes are run on the remainder of the chain. + /// + /// Note: there's some potential for optimization here, but that's future work. + fn handle_inline(&mut self) { + self.handle_inline_pass1(); + self.handle_emphasis(); + } + + /// Handle inline HTML, code spans, and links. + /// + /// This function handles both inline HTML and code spans, because they have + /// the same precedence. It also handles links, even though they have lower + /// precedence, because the URL of links must not be processed. + fn handle_inline_pass1(&mut self) { + let mut code_delims = CodeDelims::new(); + let mut cur = self.tree.cur(); + let mut prev = None; + + let block_end = self.tree[self.tree.peek_up().unwrap()].item.end; + let block_text = &self.text[..block_end]; + + while let Some(mut cur_ix) = cur { + match self.tree[cur_ix].item.body { + ItemBody::MaybeHtml => { + let next = self.tree[cur_ix].next; + let autolink = if let Some(next_ix) = next { + scan_autolink(block_text, self.tree[next_ix].item.start) + } else { + None + }; + + if let Some((ix, uri, link_type)) = autolink { + let node = scan_nodes_to_ix(&self.tree, next, ix); + let text_node = self.tree.create_node(Item { + start: self.tree[cur_ix].item.start + 1, + end: ix - 1, + body: ItemBody::Text, + }); + let link_ix = self.allocs.allocate_link(link_type, uri, "".into()); + self.tree[cur_ix].item.body = ItemBody::Link(link_ix); + self.tree[cur_ix].item.end = ix; + self.tree[cur_ix].next = node; + self.tree[cur_ix].child = Some(text_node); + prev = cur; + cur = node; + if let Some(node_ix) = cur { + self.tree[node_ix].item.start = max(self.tree[node_ix].item.start, ix); + } + continue; + } else { + let inline_html = next.and_then(|next_ix| { + self.scan_inline_html( + block_text.as_bytes(), + self.tree[next_ix].item.start, + ) + }); + if let Some((span, ix)) = inline_html { + let node = scan_nodes_to_ix(&self.tree, next, ix); + self.tree[cur_ix].item.body = if !span.is_empty() { + let converted_string = + String::from_utf8(span).expect("invalid utf8"); + ItemBody::OwnedHtml( + self.allocs.allocate_cow(converted_string.into()), + ) + } else { + ItemBody::Html + }; + self.tree[cur_ix].item.end = ix; + self.tree[cur_ix].next = node; + prev = cur; + cur = node; + if let Some(node_ix) = cur { + self.tree[node_ix].item.start = + max(self.tree[node_ix].item.start, ix); + } + continue; + } + } + self.tree[cur_ix].item.body = ItemBody::Text; + } + ItemBody::MaybeCode(mut search_count, preceded_by_backslash) => { + if preceded_by_backslash { + search_count -= 1; + if search_count == 0 { + self.tree[cur_ix].item.body = ItemBody::Text; + prev = cur; + cur = self.tree[cur_ix].next; + continue; + } + } + + if code_delims.is_populated() { + // we have previously scanned all codeblock delimiters, + // so we can reuse that work + if let Some(scan_ix) = code_delims.find(cur_ix, search_count) { + self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); + } else { + self.tree[cur_ix].item.body = ItemBody::Text; + } + } else { + // we haven't previously scanned all codeblock delimiters, + // so walk the AST + let mut scan = if search_count > 0 { + self.tree[cur_ix].next + } else { + None + }; + while let Some(scan_ix) = scan { + if let ItemBody::MaybeCode(delim_count, _) = + self.tree[scan_ix].item.body + { + if search_count == delim_count { + self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); + code_delims.clear(); + break; + } else { + code_delims.insert(delim_count, scan_ix); + } + } + scan = self.tree[scan_ix].next; + } + if scan == None { + self.tree[cur_ix].item.body = ItemBody::Text; + } + } + } + ItemBody::MaybeLinkOpen => { + self.tree[cur_ix].item.body = ItemBody::Text; + self.link_stack.push(LinkStackEl { + node: cur_ix, + ty: LinkStackTy::Link, + }); + } + ItemBody::MaybeImage => { + self.tree[cur_ix].item.body = ItemBody::Text; + self.link_stack.push(LinkStackEl { + node: cur_ix, + ty: LinkStackTy::Image, + }); + } + ItemBody::MaybeLinkClose(could_be_ref) => { + self.tree[cur_ix].item.body = ItemBody::Text; + if let Some(tos) = self.link_stack.pop() { + if tos.ty == LinkStackTy::Disabled { + continue; + } + let next = self.tree[cur_ix].next; + if let Some((next_ix, url, title)) = + self.scan_inline_link(block_text, self.tree[cur_ix].item.end, next) + { + let next_node = scan_nodes_to_ix(&self.tree, next, next_ix); + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + cur = Some(tos.node); + cur_ix = tos.node; + let link_ix = self.allocs.allocate_link(LinkType::Inline, url, title); + self.tree[cur_ix].item.body = if tos.ty == LinkStackTy::Image { + ItemBody::Image(link_ix) + } else { + ItemBody::Link(link_ix) + }; + self.tree[cur_ix].child = self.tree[cur_ix].next; + self.tree[cur_ix].next = next_node; + self.tree[cur_ix].item.end = next_ix; + if let Some(next_node_ix) = next_node { + self.tree[next_node_ix].item.start = + max(self.tree[next_node_ix].item.start, next_ix); + } + + if tos.ty == LinkStackTy::Link { + self.link_stack.disable_all_links(); + } + } else { + // ok, so its not an inline link. maybe it is a reference + // to a defined link? + let scan_result = scan_reference( + &self.tree, + block_text, + next, + self.options.contains(Options::ENABLE_FOOTNOTES), + ); + let (node_after_link, link_type) = match scan_result { + // [label][reference] + RefScan::LinkLabel(_, end_ix) => { + // Toggle reference viability of the last closing bracket, + // so that we can skip it on future iterations in case + // it fails in this one. In particular, we won't call + // the broken link callback twice on one reference. + let reference_close_node = + scan_nodes_to_ix(&self.tree, next, end_ix - 1).unwrap(); + self.tree[reference_close_node].item.body = + ItemBody::MaybeLinkClose(false); + let next_node = self.tree[reference_close_node].next; + + (next_node, LinkType::Reference) + } + // [reference][] + RefScan::Collapsed(next_node) => { + // This reference has already been tried, and it's not + // valid. Skip it. + if !could_be_ref { + continue; + } + (next_node, LinkType::Collapsed) + } + // [shortcut] + // + // [shortcut]: /blah + RefScan::Failed => { + if !could_be_ref { + continue; + } + (next, LinkType::Shortcut) + } + }; + + // FIXME: references and labels are mixed in the naming of variables + // below. Disambiguate! + + // (label, source_ix end) + let label: Option<(ReferenceLabel<'a>, usize)> = match scan_result { + RefScan::LinkLabel(l, end_ix) => { + Some((ReferenceLabel::Link(l), end_ix)) + } + RefScan::Collapsed(..) | RefScan::Failed => { + // No label? maybe it is a shortcut reference + let label_start = self.tree[tos.node].item.end - 1; + scan_link_label( + &self.tree, + &self.text[label_start..self.tree[cur_ix].item.end], + self.options.contains(Options::ENABLE_FOOTNOTES), + ) + .map(|(ix, label)| (label, label_start + ix)) + } + }; + + // see if it's a footnote reference + if let Some((ReferenceLabel::Footnote(l), end)) = label { + self.tree[tos.node].next = node_after_link; + self.tree[tos.node].child = None; + self.tree[tos.node].item.body = + ItemBody::FootnoteReference(self.allocs.allocate_cow(l)); + self.tree[tos.node].item.end = end; + prev = Some(tos.node); + cur = node_after_link; + self.link_stack.clear(); + continue; + } else if let Some((ReferenceLabel::Link(link_label), end)) = label { + let type_url_title = self + .allocs + .refdefs + .get(&UniCase::new(link_label.as_ref().into())) + .map(|matching_def| { + // found a matching definition! + let title = matching_def + .title + .as_ref() + .cloned() + .unwrap_or_else(|| "".into()); + let url = matching_def.dest.clone(); + (link_type, url, title) + }) + .or_else(|| { + match self.broken_link_callback.as_mut() { + Some(callback) => { + // Construct a BrokenLink struct, which will be passed to the callback + let broken_link = BrokenLink { + span: (self.tree[tos.node].item.start)..end, + link_type: link_type, + reference: link_label.as_ref(), + }; + + callback(broken_link).map(|(url, title)| { + (link_type.to_unknown(), url, title) + }) + } + None => None, + } + }); + + if let Some((def_link_type, url, title)) = type_url_title { + let link_ix = + self.allocs.allocate_link(def_link_type, url, title); + self.tree[tos.node].item.body = if tos.ty == LinkStackTy::Image + { + ItemBody::Image(link_ix) + } else { + ItemBody::Link(link_ix) + }; + let label_node = self.tree[tos.node].next; + + // lets do some tree surgery to add the link to the tree + // 1st: skip the label node and close node + self.tree[tos.node].next = node_after_link; + + // then, if it exists, add the label node as a child to the link node + if label_node != cur { + self.tree[tos.node].child = label_node; + + // finally: disconnect list of children + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + } + + self.tree[tos.node].item.end = end; + + // set up cur so next node will be node_after_link + cur = Some(tos.node); + cur_ix = tos.node; + + if tos.ty == LinkStackTy::Link { + self.link_stack.disable_all_links(); + } + } + } + } + } + } + _ => (), + } + prev = cur; + cur = self.tree[cur_ix].next; + } + self.link_stack.clear(); + } + + fn handle_emphasis(&mut self) { + let mut prev = None; + let mut prev_ix: TreeIndex; + let mut cur = self.tree.cur(); + + let mut single_quote_open: Option = None; + let mut double_quote_open: bool = false; + + while let Some(mut cur_ix) = cur { + match self.tree[cur_ix].item.body { + ItemBody::MaybeEmphasis(mut count, can_open, can_close) => { + let c = self.text.as_bytes()[self.tree[cur_ix].item.start]; + let both = can_open && can_close; + if can_close { + while let Some(el) = + self.inline_stack.find_match(&mut self.tree, c, count, both) + { + // have a match! + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + let match_count = min(count, el.count); + // start, end are tree node indices + let mut end = cur_ix - 1; + let mut start = el.start + el.count; + + // work from the inside out + while start > el.start + el.count - match_count { + let (inc, ty) = if c == b'~' { + (2, ItemBody::Strikethrough) + } else if start > el.start + el.count - match_count + 1 { + (2, ItemBody::Strong) + } else { + (1, ItemBody::Emphasis) + }; + + let root = start - inc; + end = end + inc; + self.tree[root].item.body = ty; + self.tree[root].item.end = self.tree[end].item.end; + self.tree[root].child = Some(start); + self.tree[root].next = None; + start = root; + } + + // set next for top most emph level + prev_ix = el.start + el.count - match_count; + prev = Some(prev_ix); + cur = self.tree[cur_ix + match_count - 1].next; + self.tree[prev_ix].next = cur; + + if el.count > match_count { + self.inline_stack.push(InlineEl { + start: el.start, + count: el.count - match_count, + c: el.c, + both, + }) + } + count -= match_count; + if count > 0 { + cur_ix = cur.unwrap(); + } else { + break; + } + } + } + if count > 0 { + if can_open { + self.inline_stack.push(InlineEl { + start: cur_ix, + count, + c, + both, + }); + } else { + for i in 0..count { + self.tree[cur_ix + i].item.body = ItemBody::Text; + } + } + prev_ix = cur_ix + count - 1; + prev = Some(prev_ix); + cur = self.tree[prev_ix].next; + } + } + ItemBody::MaybeSmartQuote(c, can_open, can_close) => { + self.tree[cur_ix].item.body = match c { + b'\'' => { + if let (Some(open_ix), true) = (single_quote_open, can_close) { + self.tree[open_ix].item.body = ItemBody::SynthesizeChar('‘'); + single_quote_open = None; + } else if can_open { + single_quote_open = Some(cur_ix); + } + ItemBody::SynthesizeChar('’') + } + _ /* double quote */ => { + if can_close && double_quote_open { + double_quote_open = false; + ItemBody::SynthesizeChar('”') + } else { + if can_open && !double_quote_open { + double_quote_open = true; + } + ItemBody::SynthesizeChar('“') + } + } + }; + prev = cur; + cur = self.tree[cur_ix].next; + } + _ => { + prev = cur; + cur = self.tree[cur_ix].next; + } + } + } + self.inline_stack.pop_all(&mut self.tree); + } + + /// Returns next byte index, url and title. + fn scan_inline_link( + &self, + underlying: &'a str, + mut ix: usize, + node: Option, + ) -> Option<(usize, CowStr<'a>, CowStr<'a>)> { + if scan_ch(&underlying.as_bytes()[ix..], b'(') == 0 { + return None; + } + ix += 1; + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + + let (dest_length, dest) = scan_link_dest(underlying, ix, LINK_MAX_NESTED_PARENS)?; + let dest = unescape(dest); + ix += dest_length; + + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + + let title = if let Some((bytes_scanned, t)) = self.scan_link_title(underlying, ix, node) { + ix += bytes_scanned; + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + t + } else { + "".into() + }; + if scan_ch(&underlying.as_bytes()[ix..], b')') == 0 { + return None; + } + ix += 1; + + Some((ix, dest, title)) + } + + // returns (bytes scanned, title cow) + fn scan_link_title( + &self, + text: &'a str, + start_ix: usize, + node: Option, + ) -> Option<(usize, CowStr<'a>)> { + let bytes = text.as_bytes(); + let open = match bytes.get(start_ix) { + Some(b @ b'\'') | Some(b @ b'\"') | Some(b @ b'(') => *b, + _ => return None, + }; + let close = if open == b'(' { b')' } else { open }; + + let mut title = String::new(); + let mut mark = start_ix + 1; + let mut i = start_ix + 1; + + while i < bytes.len() { + let c = bytes[i]; + + if c == close { + let cow = if mark == 1 { + (i - start_ix + 1, text[mark..i].into()) + } else { + title.push_str(&text[mark..i]); + (i - start_ix + 1, title.into()) + }; + + return Some(cow); + } + if c == open { + return None; + } + + if c == b'\n' || c == b'\r' { + if let Some(node_ix) = scan_nodes_to_ix(&self.tree, node, i + 1) { + if self.tree[node_ix].item.start > i { + title.push_str(&text[mark..i]); + title.push('\n'); + i = self.tree[node_ix].item.start; + mark = i; + continue; + } + } + } + if c == b'&' { + if let (n, Some(value)) = scan_entity(&bytes[i..]) { + title.push_str(&text[mark..i]); + title.push_str(&value); + i += n; + mark = i; + continue; + } + } + if c == b'\\' && i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) { + title.push_str(&text[mark..i]); + i += 1; + mark = i; + } + + i += 1; + } + + None + } + + /// Make a code span. + /// + /// Both `open` and `close` are matching MaybeCode items. + fn make_code_span(&mut self, open: TreeIndex, close: TreeIndex, preceding_backslash: bool) { + let first_ix = open + 1; + let last_ix = close - 1; + let bytes = self.text.as_bytes(); + let mut span_start = self.tree[open].item.end; + let mut span_end = self.tree[close].item.start; + let mut buf: Option = None; + + // detect all-space sequences, since they are kept as-is as of commonmark 0.29 + if !bytes[span_start..span_end].iter().all(|&b| b == b' ') { + let opening = match bytes[span_start] { + b' ' | b'\r' | b'\n' => true, + _ => false, + }; + let closing = match bytes[span_end - 1] { + b' ' | b'\r' | b'\n' => true, + _ => false, + }; + let drop_enclosing_whitespace = opening && closing; + + if drop_enclosing_whitespace { + span_start += 1; + if span_start < span_end { + span_end -= 1; + } + } + + let mut ix = first_ix; + + while ix < close { + if let ItemBody::HardBreak | ItemBody::SoftBreak = self.tree[ix].item.body { + if drop_enclosing_whitespace { + // check whether break should be ignored + if ix == first_ix { + ix = ix + 1; + span_start = min(span_end, self.tree[ix].item.start); + continue; + } else if ix == last_ix && last_ix > first_ix { + ix = ix + 1; + continue; + } + } + + let end = bytes[self.tree[ix].item.start..] + .iter() + .position(|&b| b == b'\r' || b == b'\n') + .unwrap() + + self.tree[ix].item.start; + if let Some(ref mut buf) = buf { + buf.push_str(&self.text[self.tree[ix].item.start..end]); + buf.push(' '); + } else { + let mut new_buf = String::with_capacity(span_end - span_start); + new_buf.push_str(&self.text[span_start..end]); + new_buf.push(' '); + buf = Some(new_buf); + } + } else if let Some(ref mut buf) = buf { + let end = if ix == last_ix { + span_end + } else { + self.tree[ix].item.end + }; + buf.push_str(&self.text[self.tree[ix].item.start..end]); + } + ix = ix + 1; + } + } + + let cow = if let Some(buf) = buf { + buf.into() + } else { + self.text[span_start..span_end].into() + }; + if preceding_backslash { + self.tree[open].item.body = ItemBody::Text; + self.tree[open].item.end = self.tree[open].item.start + 1; + self.tree[open].next = Some(close); + self.tree[close].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); + self.tree[close].item.start = self.tree[open].item.start + 1; + } else { + self.tree[open].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); + self.tree[open].item.end = self.tree[close].item.end; + self.tree[open].next = self.tree[close].next; + } + } + + /// On success, returns a buffer containing the inline html and byte offset. + /// When no bytes were skipped, the buffer will be empty and the html can be + /// represented as a subslice of the input string. + fn scan_inline_html(&mut self, bytes: &[u8], ix: usize) -> Option<(Vec, usize)> { + let c = *bytes.get(ix)?; + if c == b'!' { + Some(( + vec![], + scan_inline_html_comment(bytes, ix + 1, &mut self.html_scan_guard)?, + )) + } else if c == b'?' { + Some(( + vec![], + scan_inline_html_processing(bytes, ix + 1, &mut self.html_scan_guard)?, + )) + } else { + let (span, i) = scan_html_block_inner( + // Subtract 1 to include the < character + &bytes[(ix - 1)..], + Some(&|_bytes| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(&self.tree, &mut line_start); + line_start.bytes_scanned() + }), + )?; + Some((span, i + ix - 1)) + } + } + + /// Consumes the event iterator and produces an iterator that produces + /// `(Event, Range)` pairs, where the `Range` value maps to the corresponding + /// range in the markdown source. + pub fn into_offset_iter(self) -> OffsetIter<'a> { + OffsetIter { inner: self } + } +} + +pub(crate) enum LoopInstruction { + /// Continue looking for more special bytes, but skip next few bytes. + ContinueAndSkip(usize), + /// Break looping immediately, returning with the given index and value. + BreakAtWith(usize, T), +} + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +pub(crate) struct LookupTable { + pub simd: [u8; 16], + pub scalar: [bool; 256], +} + +#[cfg(not(all(target_arch = "x86_64", feature = "simd")))] +type LookupTable = [bool; 256]; + +/// This function walks the byte slices from the given index and +/// calls the callback function on all bytes (and their indices) that are in the following set: +/// `` ` ``, `\`, `&`, `*`, `_`, `~`, `!`, `<`, `[`, `]`, `|`, `\r`, `\n` +/// It is guaranteed not call the callback on other bytes. +/// Whenever `callback(ix, byte)` returns a `ContinueAndSkip(n)` value, the callback +/// will not be called with an index that is less than `ix + n + 1`. +/// When the callback returns a `BreakAtWith(end_ix, opt+val)`, no more callbacks will be +/// called and the function returns immediately with the return value `(end_ix, opt_val)`. +/// If `BreakAtWith(..)` is never returned, this function will return the first +/// index that is outside the byteslice bound and a `None` value. +fn iterate_special_bytes( + lut: &LookupTable, + bytes: &[u8], + ix: usize, + callback: F, +) -> (usize, Option) +where + F: FnMut(usize, u8) -> LoopInstruction>, +{ + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + crate::simd::iterate_special_bytes(lut, bytes, ix, callback) + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + scalar_iterate_special_bytes(lut, bytes, ix, callback) + } +} + +pub(crate) fn scalar_iterate_special_bytes( + lut: &[bool; 256], + bytes: &[u8], + mut ix: usize, + mut callback: F, +) -> (usize, Option) +where + F: FnMut(usize, u8) -> LoopInstruction>, +{ + while ix < bytes.len() { + let b = bytes[ix]; + if lut[b as usize] { + match callback(ix, b) { + LoopInstruction::ContinueAndSkip(skip) => { + ix += skip; + } + LoopInstruction::BreakAtWith(ix, val) => { + return (ix, val); + } + } + } + ix += 1; + } + + (ix, None) +} + +/// Markdown event and source range iterator. +/// +/// Generates tuples where the first element is the markdown event and the second +/// is a the corresponding range in the source string. +/// +/// Constructed from a `Parser` using its +/// [`into_offset_iter`](struct.Parser.html#method.into_offset_iter) method. +pub struct OffsetIter<'a> { + inner: Parser<'a>, +} + +impl<'a> Iterator for OffsetIter<'a> { + type Item = (Event<'a>, Range); + + fn next(&mut self) -> Option { + match self.inner.tree.cur() { + None => { + let ix = self.inner.tree.pop()?; + let tag = item_to_tag(&self.inner.tree[ix].item, &self.inner.allocs); + self.inner.tree.next_sibling(ix); + Some(( + Event::End(tag), + self.inner.tree[ix].item.start..self.inner.tree[ix].item.end, + )) + } + Some(cur_ix) => { + if self.inner.tree[cur_ix].item.body.is_inline() { + self.inner.handle_inline(); + } + + let node = self.inner.tree[cur_ix]; + let item = node.item; + let event = item_to_event(item, self.inner.text, &self.inner.allocs); + if let Event::Start(..) = event { + self.inner.tree.push(); + } else { + self.inner.tree.next_sibling(cur_ix); + } + Some((event, item.start..item.end)) + } + } + } +} + +fn item_to_tag<'a>(item: &Item, allocs: &Allocations<'a>) -> Tag<'a> { + match item.body { + ItemBody::Paragraph => Tag::Paragraph, + ItemBody::Emphasis => Tag::Emphasis, + ItemBody::Strong => Tag::Strong, + ItemBody::Strikethrough => Tag::Strikethrough, + ItemBody::Link(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Link(*link_type, url.clone(), title.clone()) + } + ItemBody::Image(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Image(*link_type, url.clone(), title.clone()) + } + ItemBody::Heading(level) => Tag::Heading(level), + ItemBody::FencedCodeBlock(cow_ix) => { + Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) + } + ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), + ItemBody::BlockQuote => Tag::BlockQuote, + ItemBody::List(_, c, listitem_start) => { + if c == b'.' || c == b')' { + Tag::List(Some(listitem_start)) + } else { + Tag::List(None) + } + } + ItemBody::ListItem(_) => Tag::Item, + ItemBody::TableHead => Tag::TableHead, + ItemBody::TableCell => Tag::TableCell, + ItemBody::TableRow => Tag::TableRow, + ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), + ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), + _ => panic!("unexpected item body {:?}", item.body), + } +} + +fn item_to_event<'a>(item: Item, text: &'a str, allocs: &Allocations<'a>) -> Event<'a> { + let tag = match item.body { + ItemBody::Text => return Event::Text(text[item.start..item.end].into()), + ItemBody::Code(cow_ix) => return Event::Code(allocs[cow_ix].clone()), + ItemBody::SynthesizeText(cow_ix) => return Event::Text(allocs[cow_ix].clone()), + ItemBody::SynthesizeChar(c) => return Event::Text(c.into()), + ItemBody::Html => return Event::Html(text[item.start..item.end].into()), + ItemBody::OwnedHtml(cow_ix) => return Event::Html(allocs[cow_ix].clone()), + ItemBody::SoftBreak => return Event::SoftBreak, + ItemBody::HardBreak => return Event::HardBreak, + ItemBody::FootnoteReference(cow_ix) => { + return Event::FootnoteReference(allocs[cow_ix].clone()) + } + ItemBody::TaskListMarker(checked) => return Event::TaskListMarker(checked), + ItemBody::Rule => return Event::Rule, + + ItemBody::Paragraph => Tag::Paragraph, + ItemBody::Emphasis => Tag::Emphasis, + ItemBody::Strong => Tag::Strong, + ItemBody::Strikethrough => Tag::Strikethrough, + ItemBody::Link(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Link(*link_type, url.clone(), title.clone()) + } + ItemBody::Image(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Image(*link_type, url.clone(), title.clone()) + } + ItemBody::Heading(level) => Tag::Heading(level), + ItemBody::FencedCodeBlock(cow_ix) => { + Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) + } + ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), + ItemBody::BlockQuote => Tag::BlockQuote, + ItemBody::List(_, c, listitem_start) => { + if c == b'.' || c == b')' { + Tag::List(Some(listitem_start)) + } else { + Tag::List(None) + } + } + ItemBody::ListItem(_) => Tag::Item, + ItemBody::TableHead => Tag::TableHead, + ItemBody::TableCell => Tag::TableCell, + ItemBody::TableRow => Tag::TableRow, + ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), + ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), + _ => panic!("unexpected item body {:?}", item.body), + }; + + Event::Start(tag) +} + +// https://english.stackexchange.com/a/285573 +fn surgerize_tight_list(tree: &mut Tree, list_ix: TreeIndex) { + let mut list_item = tree[list_ix].child; + while let Some(listitem_ix) = list_item { + // first child is special, controls how we repoint list_item.child + let list_item_firstborn = tree[listitem_ix].child; + + // Check that list item has children - this is not necessarily the case! + if let Some(firstborn_ix) = list_item_firstborn { + if let ItemBody::Paragraph = tree[firstborn_ix].item.body { + tree[listitem_ix].child = tree[firstborn_ix].child; + } + + let mut list_item_child = Some(firstborn_ix); + let mut node_to_repoint = None; + while let Some(child_ix) = list_item_child { + // surgerize paragraphs + let repoint_ix = if let ItemBody::Paragraph = tree[child_ix].item.body { + if let Some(child_firstborn) = tree[child_ix].child { + if let Some(repoint_ix) = node_to_repoint { + tree[repoint_ix].next = Some(child_firstborn); + } + let mut child_lastborn = child_firstborn; + while let Some(lastborn_next_ix) = tree[child_lastborn].next { + child_lastborn = lastborn_next_ix; + } + child_lastborn + } else { + child_ix + } + } else { + child_ix + }; + + node_to_repoint = Some(repoint_ix); + tree[repoint_ix].next = tree[child_ix].next; + list_item_child = tree[child_ix].next; + } + } + + list_item = tree[listitem_ix].next; + } +} + +impl<'a> Iterator for Parser<'a> { + type Item = Event<'a>; + + fn next(&mut self) -> Option> { + match self.tree.cur() { + None => { + let ix = self.tree.pop()?; + let tag = item_to_tag(&self.tree[ix].item, &self.allocs); + self.tree.next_sibling(ix); + Some(Event::End(tag)) + } + Some(cur_ix) => { + if self.tree[cur_ix].item.body.is_inline() { + self.handle_inline(); + } + + let node = self.tree[cur_ix]; + let item = node.item; + let event = item_to_event(item, self.text, &self.allocs); + if let Event::Start(..) = event { + self.tree.push(); + } else { + self.tree.next_sibling(cur_ix); + } + Some(event) + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::tree::Node; + + // TODO: move these tests to tests/html.rs? + + fn parser_with_extensions(text: &str) -> Parser<'_> { + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + + Parser::new_ext(text, opts) + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn node_size() { + let node_size = std::mem::size_of::>(); + assert_eq!(48, node_size); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn body_size() { + let body_size = std::mem::size_of::(); + assert_eq!(16, body_size); + } + + #[test] + fn single_open_fish_bracket() { + // dont crash + assert_eq!(3, Parser::new("<").count()); + } + + #[test] + fn lone_hashtag() { + // dont crash + assert_eq!(2, Parser::new("#").count()); + } + + #[test] + fn lots_of_backslashes() { + // dont crash + Parser::new("\\\\\r\r").count(); + Parser::new("\\\r\r\\.\\\\\r\r\\.\\").count(); + } + + #[test] + fn issue_320() { + // dont crash + parser_with_extensions(":\r\t> |\r:\r\t> |\r").count(); + } + + #[test] + fn issue_319() { + // dont crash + parser_with_extensions("|\r-]([^|\r-]([^").count(); + parser_with_extensions("|\r\r=][^|\r\r=][^car").count(); + } + + #[test] + fn issue_303() { + // dont crash + parser_with_extensions("[^\r\ra]").count(); + parser_with_extensions("\r\r]Z[^\x00\r\r]Z[^\x00").count(); + } + + #[test] + fn issue_313() { + // dont crash + parser_with_extensions("*]0[^\r\r*]0[^").count(); + parser_with_extensions("[^\r> `][^\r> `][^\r> `][").count(); + } + + #[test] + fn issue_311() { + // dont crash + parser_with_extensions("\\\u{0d}-\u{09}\\\u{0d}-\u{09}").count(); + } + + #[test] + fn issue_283() { + let input = std::str::from_utf8(b"\xf0\x9b\xb2\x9f - \\\n> - ").count(); + parser_with_extensions("- \n\n").count(); + } + + #[test] + fn issue_306() { + // dont crash + parser_with_extensions("*\r_<__*\r_<__*\r_<__*\r_<__").count(); + } + + #[test] + fn issue_305() { + // dont crash + parser_with_extensions("_6**6*_*").count(); + } + + #[test] + fn another_emphasis_panic() { + parser_with_extensions("*__#_#__*").count(); + } + + #[test] + fn offset_iter() { + let event_offsets: Vec<_> = Parser::new("*hello* world") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..13), (0..7), (1..6), (0..7), (7..13), (0..13)]; + assert_eq!(expected_offsets, event_offsets); + } + + #[test] + fn reference_link_offsets() { + let range = + Parser::new("# H1\n[testing][Some reference]\n\n[Some reference]: https://github.com") + .into_offset_iter() + .filter_map(|(ev, range)| match ev { + Event::Start(Tag::Link(LinkType::Reference, ..), ..) => Some(range), + _ => None, + }) + .next() + .unwrap(); + assert_eq!(5..30, range); + } + + #[test] + fn footnote_offsets() { + let range = parser_with_extensions("Testing this[^1] out.\n\n[^1]: Footnote.") + .into_offset_iter() + .filter_map(|(ev, range)| match ev { + Event::FootnoteReference(..) => Some(range), + _ => None, + }) + .next() + .unwrap(); + assert_eq!(12..16, range); + } + + #[test] + fn table_offset() { + let markdown = "a\n\nTesting|This|Outtt\n--|:--:|--:\nSome Data|Other data|asdf"; + let event_offset = parser_with_extensions(markdown) + .into_offset_iter() + .map(|(_ev, range)| range) + .nth(3) + .unwrap(); + let expected_offset = 3..59; + assert_eq!(expected_offset, event_offset); + } + + #[test] + fn offset_iter_issue_378() { + let event_offsets: Vec<_> = Parser::new("a [b](c) d") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..10), (0..2), (2..8), (3..4), (2..8), (8..10), (0..10)]; + assert_eq!(expected_offsets, event_offsets); + } + + #[test] + fn offset_iter_issue_404() { + let event_offsets: Vec<_> = Parser::new("###\n") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..4), (0..4)]; + assert_eq!(expected_offsets, event_offsets); + } + + // FIXME: add this one regression suite + #[test] + fn link_def_at_eof() { + let test_str = "[My site][world]\n\n[world]: https://vincentprouillet.com"; + let expected = "

    My site

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn no_footnote_refs_without_option() { + let test_str = "a [^a]\n\n[^a]: yolo"; + let expected = "

    a ^a

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn ref_def_at_eof() { + let test_str = "[test]:\\"; + let expected = ""; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn ref_def_cr_lf() { + let test_str = "[a]: /u\r\n\n[a]"; + let expected = "

    a

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn no_dest_refdef() { + let test_str = "[a]:"; + let expected = "

    [a]:

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn broken_links_called_only_once() { + for &(markdown, expected) in &[ + ("See also [`g()`][crate::g].", 1), + ("See also [`g()`][crate::g][].", 1), + ("[brokenlink1] some other node [brokenlink2]", 2), + ] { + let mut times_called = 0; + let callback = &mut |_broken_link: BrokenLink| { + times_called += 1; + None + }; + let parser = + Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(callback)); + for _ in parser {} + assert_eq!(times_called, expected); + } + } + + #[test] + fn simple_broken_link_callback() { + let test_str = "This is a link w/o def: [hello][world]"; + let mut callback = |broken_link: BrokenLink| { + assert_eq!("world", broken_link.reference); + assert_eq!(&test_str[broken_link.span], "[hello][world]"); + let url = "YOLO".into(); + let title = "SWAG".to_owned().into(); + Some((url, title)) + }; + let parser = + Parser::new_with_broken_link_callback(test_str, Options::empty(), Some(&mut callback)); + let mut link_tag_count = 0; + for (typ, url, title) in parser.filter_map(|event| match event { + Event::Start(tag) | Event::End(tag) => match tag { + Tag::Link(typ, url, title) => Some((typ, url, title)), + _ => None, + }, + _ => None, + }) { + link_tag_count += 1; + assert_eq!(typ, LinkType::ReferenceUnknown); + assert_eq!(url.as_ref(), "YOLO"); + assert_eq!(title.as_ref(), "SWAG"); + } + assert!(link_tag_count > 0); + } + + #[test] + fn code_block_kind_check_fenced() { + let parser = Parser::new("hello\n```test\ntadam\n```"); + let mut found = 0; + for (ev, _range) in parser.into_offset_iter() { + match ev { + Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(syntax))) => { + assert_eq!(syntax.as_ref(), "test"); + found += 1; + } + _ => {} + } + } + assert_eq!(found, 1); + } + + #[test] + fn code_block_kind_check_indented() { + let parser = Parser::new("hello\n\n ```test\n tadam\nhello"); + let mut found = 0; + for (ev, _range) in parser.into_offset_iter() { + match ev { + Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => { + found += 1; + } + _ => {} + } + } + assert_eq!(found, 1); + } +} diff --git a/vendor/pulldown-cmark/src/puncttable.rs b/vendor/pulldown-cmark/src/puncttable.rs index a1b0751a54..f46464b64f 100644 --- a/vendor/pulldown-cmark/src/puncttable.rs +++ b/vendor/pulldown-cmark/src/puncttable.rs @@ -1,351 +1,351 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! CommonMark punctuation set based on spec and Unicode properties. - -// Autogenerated by mk_puncttable.py - -const PUNCT_MASKS_ASCII: [u16; 8] = [ - 0x0000, // U+0000...U+000F - 0x0000, // U+0010...U+001F - 0xfffe, // U+0020...U+002F - 0xfc00, // U+0030...U+003F - 0x0001, // U+0040...U+004F - 0xf800, // U+0050...U+005F - 0x0001, // U+0060...U+006F - 0x7800, // U+0070...U+007F -]; - -const PUNCT_TAB: [u16; 132] = [ - 10, // U+00A0...U+00AF - 11, // U+00B0...U+00BF - 55, // U+0370...U+037F - 56, // U+0380...U+038F - 85, // U+0550...U+055F - 88, // U+0580...U+058F - 91, // U+05B0...U+05BF - 92, // U+05C0...U+05CF - 95, // U+05F0...U+05FF - 96, // U+0600...U+060F - 97, // U+0610...U+061F - 102, // U+0660...U+066F - 109, // U+06D0...U+06DF - 112, // U+0700...U+070F - 127, // U+07F0...U+07FF - 131, // U+0830...U+083F - 133, // U+0850...U+085F - 150, // U+0960...U+096F - 151, // U+0970...U+097F - 175, // U+0AF0...U+0AFF - 223, // U+0DF0...U+0DFF - 228, // U+0E40...U+0E4F - 229, // U+0E50...U+0E5F - 240, // U+0F00...U+0F0F - 241, // U+0F10...U+0F1F - 243, // U+0F30...U+0F3F - 248, // U+0F80...U+0F8F - 253, // U+0FD0...U+0FDF - 260, // U+1040...U+104F - 271, // U+10F0...U+10FF - 310, // U+1360...U+136F - 320, // U+1400...U+140F - 358, // U+1660...U+166F - 361, // U+1690...U+169F - 366, // U+16E0...U+16EF - 371, // U+1730...U+173F - 381, // U+17D0...U+17DF - 384, // U+1800...U+180F - 404, // U+1940...U+194F - 417, // U+1A10...U+1A1F - 426, // U+1AA0...U+1AAF - 437, // U+1B50...U+1B5F - 438, // U+1B60...U+1B6F - 447, // U+1BF0...U+1BFF - 451, // U+1C30...U+1C3F - 455, // U+1C70...U+1C7F - 460, // U+1CC0...U+1CCF - 461, // U+1CD0...U+1CDF - 513, // U+2010...U+201F - 514, // U+2020...U+202F - 515, // U+2030...U+203F - 516, // U+2040...U+204F - 517, // U+2050...U+205F - 519, // U+2070...U+207F - 520, // U+2080...U+208F - 560, // U+2300...U+230F - 562, // U+2320...U+232F - 630, // U+2760...U+276F - 631, // U+2770...U+277F - 636, // U+27C0...U+27CF - 638, // U+27E0...U+27EF - 664, // U+2980...U+298F - 665, // U+2990...U+299F - 669, // U+29D0...U+29DF - 671, // U+29F0...U+29FF - 719, // U+2CF0...U+2CFF - 727, // U+2D70...U+2D7F - 736, // U+2E00...U+2E0F - 737, // U+2E10...U+2E1F - 738, // U+2E20...U+2E2F - 739, // U+2E30...U+2E3F - 740, // U+2E40...U+2E4F - 768, // U+3000...U+300F - 769, // U+3010...U+301F - 771, // U+3030...U+303F - 778, // U+30A0...U+30AF - 783, // U+30F0...U+30FF - 2639, // U+A4F0...U+A4FF - 2656, // U+A600...U+A60F - 2663, // U+A670...U+A67F - 2671, // U+A6F0...U+A6FF - 2695, // U+A870...U+A87F - 2700, // U+A8C0...U+A8CF - 2703, // U+A8F0...U+A8FF - 2706, // U+A920...U+A92F - 2709, // U+A950...U+A95F - 2716, // U+A9C0...U+A9CF - 2717, // U+A9D0...U+A9DF - 2725, // U+AA50...U+AA5F - 2733, // U+AAD0...U+AADF - 2735, // U+AAF0...U+AAFF - 2750, // U+ABE0...U+ABEF - 4051, // U+FD30...U+FD3F - 4065, // U+FE10...U+FE1F - 4067, // U+FE30...U+FE3F - 4068, // U+FE40...U+FE4F - 4069, // U+FE50...U+FE5F - 4070, // U+FE60...U+FE6F - 4080, // U+FF00...U+FF0F - 4081, // U+FF10...U+FF1F - 4082, // U+FF20...U+FF2F - 4083, // U+FF30...U+FF3F - 4085, // U+FF50...U+FF5F - 4086, // U+FF60...U+FF6F - 4112, // U+10100...U+1010F - 4153, // U+10390...U+1039F - 4157, // U+103D0...U+103DF - 4182, // U+10560...U+1056F - 4229, // U+10850...U+1085F - 4241, // U+10910...U+1091F - 4243, // U+10930...U+1093F - 4261, // U+10A50...U+10A5F - 4263, // U+10A70...U+10A7F - 4271, // U+10AF0...U+10AFF - 4275, // U+10B30...U+10B3F - 4281, // U+10B90...U+10B9F - 4356, // U+11040...U+1104F - 4363, // U+110B0...U+110BF - 4364, // U+110C0...U+110CF - 4372, // U+11140...U+1114F - 4375, // U+11170...U+1117F - 4380, // U+111C0...U+111CF - 4387, // U+11230...U+1123F - 4428, // U+114C0...U+114CF - 4444, // U+115C0...U+115CF - 4452, // U+11640...U+1164F - 4679, // U+12470...U+1247F - 5798, // U+16A60...U+16A6F - 5807, // U+16AF0...U+16AFF - 5811, // U+16B30...U+16B3F - 5812, // U+16B40...U+16B4F - 7113, // U+1BC90...U+1BC9F -]; - -const PUNCT_MASKS: [u16; 132] = [ - 0x0882, // U+00A0...U+00AF - 0x88c0, // U+00B0...U+00BF - 0x4000, // U+0370...U+037F - 0x0080, // U+0380...U+038F - 0xfc00, // U+0550...U+055F - 0x0600, // U+0580...U+058F - 0x4000, // U+05B0...U+05BF - 0x0049, // U+05C0...U+05CF - 0x0018, // U+05F0...U+05FF - 0x3600, // U+0600...U+060F - 0xc800, // U+0610...U+061F - 0x3c00, // U+0660...U+066F - 0x0010, // U+06D0...U+06DF - 0x3fff, // U+0700...U+070F - 0x0380, // U+07F0...U+07FF - 0x7fff, // U+0830...U+083F - 0x4000, // U+0850...U+085F - 0x0030, // U+0960...U+096F - 0x0001, // U+0970...U+097F - 0x0001, // U+0AF0...U+0AFF - 0x0010, // U+0DF0...U+0DFF - 0x8000, // U+0E40...U+0E4F - 0x0c00, // U+0E50...U+0E5F - 0xfff0, // U+0F00...U+0F0F - 0x0017, // U+0F10...U+0F1F - 0x3c00, // U+0F30...U+0F3F - 0x0020, // U+0F80...U+0F8F - 0x061f, // U+0FD0...U+0FDF - 0xfc00, // U+1040...U+104F - 0x0800, // U+10F0...U+10FF - 0x01ff, // U+1360...U+136F - 0x0001, // U+1400...U+140F - 0x6000, // U+1660...U+166F - 0x1800, // U+1690...U+169F - 0x3800, // U+16E0...U+16EF - 0x0060, // U+1730...U+173F - 0x0770, // U+17D0...U+17DF - 0x07ff, // U+1800...U+180F - 0x0030, // U+1940...U+194F - 0xc000, // U+1A10...U+1A1F - 0x3f7f, // U+1AA0...U+1AAF - 0xfc00, // U+1B50...U+1B5F - 0x0001, // U+1B60...U+1B6F - 0xf000, // U+1BF0...U+1BFF - 0xf800, // U+1C30...U+1C3F - 0xc000, // U+1C70...U+1C7F - 0x00ff, // U+1CC0...U+1CCF - 0x0008, // U+1CD0...U+1CDF - 0xffff, // U+2010...U+201F - 0x00ff, // U+2020...U+202F - 0xffff, // U+2030...U+203F - 0xffef, // U+2040...U+204F - 0x7ffb, // U+2050...U+205F - 0x6000, // U+2070...U+207F - 0x6000, // U+2080...U+208F - 0x0f00, // U+2300...U+230F - 0x0600, // U+2320...U+232F - 0xff00, // U+2760...U+276F - 0x003f, // U+2770...U+277F - 0x0060, // U+27C0...U+27CF - 0xffc0, // U+27E0...U+27EF - 0xfff8, // U+2980...U+298F - 0x01ff, // U+2990...U+299F - 0x0f00, // U+29D0...U+29DF - 0x3000, // U+29F0...U+29FF - 0xde00, // U+2CF0...U+2CFF - 0x0001, // U+2D70...U+2D7F - 0xffff, // U+2E00...U+2E0F - 0xffff, // U+2E10...U+2E1F - 0x7fff, // U+2E20...U+2E2F - 0xffff, // U+2E30...U+2E3F - 0x0007, // U+2E40...U+2E4F - 0xff0e, // U+3000...U+300F - 0xfff3, // U+3010...U+301F - 0x2001, // U+3030...U+303F - 0x0001, // U+30A0...U+30AF - 0x0800, // U+30F0...U+30FF - 0xc000, // U+A4F0...U+A4FF - 0xe000, // U+A600...U+A60F - 0x4008, // U+A670...U+A67F - 0x00fc, // U+A6F0...U+A6FF - 0x00f0, // U+A870...U+A87F - 0xc000, // U+A8C0...U+A8CF - 0x0700, // U+A8F0...U+A8FF - 0xc000, // U+A920...U+A92F - 0x8000, // U+A950...U+A95F - 0x3ffe, // U+A9C0...U+A9CF - 0xc000, // U+A9D0...U+A9DF - 0xf000, // U+AA50...U+AA5F - 0xc000, // U+AAD0...U+AADF - 0x0003, // U+AAF0...U+AAFF - 0x0800, // U+ABE0...U+ABEF - 0xc000, // U+FD30...U+FD3F - 0x03ff, // U+FE10...U+FE1F - 0xffff, // U+FE30...U+FE3F - 0xffff, // U+FE40...U+FE4F - 0xfff7, // U+FE50...U+FE5F - 0x0d0b, // U+FE60...U+FE6F - 0xf7ee, // U+FF00...U+FF0F - 0x8c00, // U+FF10...U+FF1F - 0x0001, // U+FF20...U+FF2F - 0xb800, // U+FF30...U+FF3F - 0xa800, // U+FF50...U+FF5F - 0x003f, // U+FF60...U+FF6F - 0x0007, // U+10100...U+1010F - 0x8000, // U+10390...U+1039F - 0x0001, // U+103D0...U+103DF - 0x8000, // U+10560...U+1056F - 0x0080, // U+10850...U+1085F - 0x8000, // U+10910...U+1091F - 0x8000, // U+10930...U+1093F - 0x01ff, // U+10A50...U+10A5F - 0x8000, // U+10A70...U+10A7F - 0x007f, // U+10AF0...U+10AFF - 0xfe00, // U+10B30...U+10B3F - 0x1e00, // U+10B90...U+10B9F - 0x3f80, // U+11040...U+1104F - 0xd800, // U+110B0...U+110BF - 0x0003, // U+110C0...U+110CF - 0x000f, // U+11140...U+1114F - 0x0030, // U+11170...U+1117F - 0x21e0, // U+111C0...U+111CF - 0x3f00, // U+11230...U+1123F - 0x0040, // U+114C0...U+114CF - 0x03fe, // U+115C0...U+115CF - 0x000e, // U+11640...U+1164F - 0x001f, // U+12470...U+1247F - 0xc000, // U+16A60...U+16A6F - 0x0020, // U+16AF0...U+16AFF - 0x0f80, // U+16B30...U+16B3F - 0x0010, // U+16B40...U+16B4F - 0x8000, // U+1BC90...U+1BC9F -]; - -pub fn is_ascii_punctuation(c: u8) -> bool { - c < 128 && (PUNCT_MASKS_ASCII[(c / 16) as usize] & (1 << (c & 15))) != 0 -} - -pub fn is_punctuation(c: char) -> bool { - let cp = c as u32; - if cp < 128 { - return is_ascii_punctuation(cp as u8); - } - if cp > 0x1BC9F { - return false; - } - let high = (cp / 16) as u16; - match PUNCT_TAB.binary_search(&high) { - Ok(index) => (PUNCT_MASKS[index] & (1 << (cp & 15))) != 0, - _ => false, - } -} - -#[cfg(test)] -mod tests { - use super::{is_ascii_punctuation, is_punctuation}; - - #[test] - fn test_ascii() { - assert!(is_ascii_punctuation(b'!')); - assert!(is_ascii_punctuation(b'@')); - assert!(is_ascii_punctuation(b'~')); - assert!(!is_ascii_punctuation(b' ')); - assert!(!is_ascii_punctuation(b'0')); - assert!(!is_ascii_punctuation(b'A')); - assert!(!is_ascii_punctuation(0xA1)); - } - - #[test] - fn test_unicode() { - assert!(is_punctuation('~')); - assert!(!is_punctuation(' ')); - - assert!(is_punctuation('\u{00A1}')); - assert!(is_punctuation('\u{060C}')); - assert!(is_punctuation('\u{FF65}')); - assert!(is_punctuation('\u{1BC9F}')); - assert!(!is_punctuation('\u{1BCA0}')); - } -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! CommonMark punctuation set based on spec and Unicode properties. + +// Autogenerated by mk_puncttable.py + +const PUNCT_MASKS_ASCII: [u16; 8] = [ + 0x0000, // U+0000...U+000F + 0x0000, // U+0010...U+001F + 0xfffe, // U+0020...U+002F + 0xfc00, // U+0030...U+003F + 0x0001, // U+0040...U+004F + 0xf800, // U+0050...U+005F + 0x0001, // U+0060...U+006F + 0x7800, // U+0070...U+007F +]; + +const PUNCT_TAB: [u16; 132] = [ + 10, // U+00A0...U+00AF + 11, // U+00B0...U+00BF + 55, // U+0370...U+037F + 56, // U+0380...U+038F + 85, // U+0550...U+055F + 88, // U+0580...U+058F + 91, // U+05B0...U+05BF + 92, // U+05C0...U+05CF + 95, // U+05F0...U+05FF + 96, // U+0600...U+060F + 97, // U+0610...U+061F + 102, // U+0660...U+066F + 109, // U+06D0...U+06DF + 112, // U+0700...U+070F + 127, // U+07F0...U+07FF + 131, // U+0830...U+083F + 133, // U+0850...U+085F + 150, // U+0960...U+096F + 151, // U+0970...U+097F + 175, // U+0AF0...U+0AFF + 223, // U+0DF0...U+0DFF + 228, // U+0E40...U+0E4F + 229, // U+0E50...U+0E5F + 240, // U+0F00...U+0F0F + 241, // U+0F10...U+0F1F + 243, // U+0F30...U+0F3F + 248, // U+0F80...U+0F8F + 253, // U+0FD0...U+0FDF + 260, // U+1040...U+104F + 271, // U+10F0...U+10FF + 310, // U+1360...U+136F + 320, // U+1400...U+140F + 358, // U+1660...U+166F + 361, // U+1690...U+169F + 366, // U+16E0...U+16EF + 371, // U+1730...U+173F + 381, // U+17D0...U+17DF + 384, // U+1800...U+180F + 404, // U+1940...U+194F + 417, // U+1A10...U+1A1F + 426, // U+1AA0...U+1AAF + 437, // U+1B50...U+1B5F + 438, // U+1B60...U+1B6F + 447, // U+1BF0...U+1BFF + 451, // U+1C30...U+1C3F + 455, // U+1C70...U+1C7F + 460, // U+1CC0...U+1CCF + 461, // U+1CD0...U+1CDF + 513, // U+2010...U+201F + 514, // U+2020...U+202F + 515, // U+2030...U+203F + 516, // U+2040...U+204F + 517, // U+2050...U+205F + 519, // U+2070...U+207F + 520, // U+2080...U+208F + 560, // U+2300...U+230F + 562, // U+2320...U+232F + 630, // U+2760...U+276F + 631, // U+2770...U+277F + 636, // U+27C0...U+27CF + 638, // U+27E0...U+27EF + 664, // U+2980...U+298F + 665, // U+2990...U+299F + 669, // U+29D0...U+29DF + 671, // U+29F0...U+29FF + 719, // U+2CF0...U+2CFF + 727, // U+2D70...U+2D7F + 736, // U+2E00...U+2E0F + 737, // U+2E10...U+2E1F + 738, // U+2E20...U+2E2F + 739, // U+2E30...U+2E3F + 740, // U+2E40...U+2E4F + 768, // U+3000...U+300F + 769, // U+3010...U+301F + 771, // U+3030...U+303F + 778, // U+30A0...U+30AF + 783, // U+30F0...U+30FF + 2639, // U+A4F0...U+A4FF + 2656, // U+A600...U+A60F + 2663, // U+A670...U+A67F + 2671, // U+A6F0...U+A6FF + 2695, // U+A870...U+A87F + 2700, // U+A8C0...U+A8CF + 2703, // U+A8F0...U+A8FF + 2706, // U+A920...U+A92F + 2709, // U+A950...U+A95F + 2716, // U+A9C0...U+A9CF + 2717, // U+A9D0...U+A9DF + 2725, // U+AA50...U+AA5F + 2733, // U+AAD0...U+AADF + 2735, // U+AAF0...U+AAFF + 2750, // U+ABE0...U+ABEF + 4051, // U+FD30...U+FD3F + 4065, // U+FE10...U+FE1F + 4067, // U+FE30...U+FE3F + 4068, // U+FE40...U+FE4F + 4069, // U+FE50...U+FE5F + 4070, // U+FE60...U+FE6F + 4080, // U+FF00...U+FF0F + 4081, // U+FF10...U+FF1F + 4082, // U+FF20...U+FF2F + 4083, // U+FF30...U+FF3F + 4085, // U+FF50...U+FF5F + 4086, // U+FF60...U+FF6F + 4112, // U+10100...U+1010F + 4153, // U+10390...U+1039F + 4157, // U+103D0...U+103DF + 4182, // U+10560...U+1056F + 4229, // U+10850...U+1085F + 4241, // U+10910...U+1091F + 4243, // U+10930...U+1093F + 4261, // U+10A50...U+10A5F + 4263, // U+10A70...U+10A7F + 4271, // U+10AF0...U+10AFF + 4275, // U+10B30...U+10B3F + 4281, // U+10B90...U+10B9F + 4356, // U+11040...U+1104F + 4363, // U+110B0...U+110BF + 4364, // U+110C0...U+110CF + 4372, // U+11140...U+1114F + 4375, // U+11170...U+1117F + 4380, // U+111C0...U+111CF + 4387, // U+11230...U+1123F + 4428, // U+114C0...U+114CF + 4444, // U+115C0...U+115CF + 4452, // U+11640...U+1164F + 4679, // U+12470...U+1247F + 5798, // U+16A60...U+16A6F + 5807, // U+16AF0...U+16AFF + 5811, // U+16B30...U+16B3F + 5812, // U+16B40...U+16B4F + 7113, // U+1BC90...U+1BC9F +]; + +const PUNCT_MASKS: [u16; 132] = [ + 0x0882, // U+00A0...U+00AF + 0x88c0, // U+00B0...U+00BF + 0x4000, // U+0370...U+037F + 0x0080, // U+0380...U+038F + 0xfc00, // U+0550...U+055F + 0x0600, // U+0580...U+058F + 0x4000, // U+05B0...U+05BF + 0x0049, // U+05C0...U+05CF + 0x0018, // U+05F0...U+05FF + 0x3600, // U+0600...U+060F + 0xc800, // U+0610...U+061F + 0x3c00, // U+0660...U+066F + 0x0010, // U+06D0...U+06DF + 0x3fff, // U+0700...U+070F + 0x0380, // U+07F0...U+07FF + 0x7fff, // U+0830...U+083F + 0x4000, // U+0850...U+085F + 0x0030, // U+0960...U+096F + 0x0001, // U+0970...U+097F + 0x0001, // U+0AF0...U+0AFF + 0x0010, // U+0DF0...U+0DFF + 0x8000, // U+0E40...U+0E4F + 0x0c00, // U+0E50...U+0E5F + 0xfff0, // U+0F00...U+0F0F + 0x0017, // U+0F10...U+0F1F + 0x3c00, // U+0F30...U+0F3F + 0x0020, // U+0F80...U+0F8F + 0x061f, // U+0FD0...U+0FDF + 0xfc00, // U+1040...U+104F + 0x0800, // U+10F0...U+10FF + 0x01ff, // U+1360...U+136F + 0x0001, // U+1400...U+140F + 0x6000, // U+1660...U+166F + 0x1800, // U+1690...U+169F + 0x3800, // U+16E0...U+16EF + 0x0060, // U+1730...U+173F + 0x0770, // U+17D0...U+17DF + 0x07ff, // U+1800...U+180F + 0x0030, // U+1940...U+194F + 0xc000, // U+1A10...U+1A1F + 0x3f7f, // U+1AA0...U+1AAF + 0xfc00, // U+1B50...U+1B5F + 0x0001, // U+1B60...U+1B6F + 0xf000, // U+1BF0...U+1BFF + 0xf800, // U+1C30...U+1C3F + 0xc000, // U+1C70...U+1C7F + 0x00ff, // U+1CC0...U+1CCF + 0x0008, // U+1CD0...U+1CDF + 0xffff, // U+2010...U+201F + 0x00ff, // U+2020...U+202F + 0xffff, // U+2030...U+203F + 0xffef, // U+2040...U+204F + 0x7ffb, // U+2050...U+205F + 0x6000, // U+2070...U+207F + 0x6000, // U+2080...U+208F + 0x0f00, // U+2300...U+230F + 0x0600, // U+2320...U+232F + 0xff00, // U+2760...U+276F + 0x003f, // U+2770...U+277F + 0x0060, // U+27C0...U+27CF + 0xffc0, // U+27E0...U+27EF + 0xfff8, // U+2980...U+298F + 0x01ff, // U+2990...U+299F + 0x0f00, // U+29D0...U+29DF + 0x3000, // U+29F0...U+29FF + 0xde00, // U+2CF0...U+2CFF + 0x0001, // U+2D70...U+2D7F + 0xffff, // U+2E00...U+2E0F + 0xffff, // U+2E10...U+2E1F + 0x7fff, // U+2E20...U+2E2F + 0xffff, // U+2E30...U+2E3F + 0x0007, // U+2E40...U+2E4F + 0xff0e, // U+3000...U+300F + 0xfff3, // U+3010...U+301F + 0x2001, // U+3030...U+303F + 0x0001, // U+30A0...U+30AF + 0x0800, // U+30F0...U+30FF + 0xc000, // U+A4F0...U+A4FF + 0xe000, // U+A600...U+A60F + 0x4008, // U+A670...U+A67F + 0x00fc, // U+A6F0...U+A6FF + 0x00f0, // U+A870...U+A87F + 0xc000, // U+A8C0...U+A8CF + 0x0700, // U+A8F0...U+A8FF + 0xc000, // U+A920...U+A92F + 0x8000, // U+A950...U+A95F + 0x3ffe, // U+A9C0...U+A9CF + 0xc000, // U+A9D0...U+A9DF + 0xf000, // U+AA50...U+AA5F + 0xc000, // U+AAD0...U+AADF + 0x0003, // U+AAF0...U+AAFF + 0x0800, // U+ABE0...U+ABEF + 0xc000, // U+FD30...U+FD3F + 0x03ff, // U+FE10...U+FE1F + 0xffff, // U+FE30...U+FE3F + 0xffff, // U+FE40...U+FE4F + 0xfff7, // U+FE50...U+FE5F + 0x0d0b, // U+FE60...U+FE6F + 0xf7ee, // U+FF00...U+FF0F + 0x8c00, // U+FF10...U+FF1F + 0x0001, // U+FF20...U+FF2F + 0xb800, // U+FF30...U+FF3F + 0xa800, // U+FF50...U+FF5F + 0x003f, // U+FF60...U+FF6F + 0x0007, // U+10100...U+1010F + 0x8000, // U+10390...U+1039F + 0x0001, // U+103D0...U+103DF + 0x8000, // U+10560...U+1056F + 0x0080, // U+10850...U+1085F + 0x8000, // U+10910...U+1091F + 0x8000, // U+10930...U+1093F + 0x01ff, // U+10A50...U+10A5F + 0x8000, // U+10A70...U+10A7F + 0x007f, // U+10AF0...U+10AFF + 0xfe00, // U+10B30...U+10B3F + 0x1e00, // U+10B90...U+10B9F + 0x3f80, // U+11040...U+1104F + 0xd800, // U+110B0...U+110BF + 0x0003, // U+110C0...U+110CF + 0x000f, // U+11140...U+1114F + 0x0030, // U+11170...U+1117F + 0x21e0, // U+111C0...U+111CF + 0x3f00, // U+11230...U+1123F + 0x0040, // U+114C0...U+114CF + 0x03fe, // U+115C0...U+115CF + 0x000e, // U+11640...U+1164F + 0x001f, // U+12470...U+1247F + 0xc000, // U+16A60...U+16A6F + 0x0020, // U+16AF0...U+16AFF + 0x0f80, // U+16B30...U+16B3F + 0x0010, // U+16B40...U+16B4F + 0x8000, // U+1BC90...U+1BC9F +]; + +pub fn is_ascii_punctuation(c: u8) -> bool { + c < 128 && (PUNCT_MASKS_ASCII[(c / 16) as usize] & (1 << (c & 15))) != 0 +} + +pub fn is_punctuation(c: char) -> bool { + let cp = c as u32; + if cp < 128 { + return is_ascii_punctuation(cp as u8); + } + if cp > 0x1BC9F { + return false; + } + let high = (cp / 16) as u16; + match PUNCT_TAB.binary_search(&high) { + Ok(index) => (PUNCT_MASKS[index] & (1 << (cp & 15))) != 0, + _ => false, + } +} + +#[cfg(test)] +mod tests { + use super::{is_ascii_punctuation, is_punctuation}; + + #[test] + fn test_ascii() { + assert!(is_ascii_punctuation(b'!')); + assert!(is_ascii_punctuation(b'@')); + assert!(is_ascii_punctuation(b'~')); + assert!(!is_ascii_punctuation(b' ')); + assert!(!is_ascii_punctuation(b'0')); + assert!(!is_ascii_punctuation(b'A')); + assert!(!is_ascii_punctuation(0xA1)); + } + + #[test] + fn test_unicode() { + assert!(is_punctuation('~')); + assert!(!is_punctuation(' ')); + + assert!(is_punctuation('\u{00A1}')); + assert!(is_punctuation('\u{060C}')); + assert!(is_punctuation('\u{FF65}')); + assert!(is_punctuation('\u{1BC9F}')); + assert!(!is_punctuation('\u{1BCA0}')); + } +} diff --git a/vendor/pulldown-cmark/src/scanners.rs b/vendor/pulldown-cmark/src/scanners.rs index 884d4e49f2..21a37c8ad6 100644 --- a/vendor/pulldown-cmark/src/scanners.rs +++ b/vendor/pulldown-cmark/src/scanners.rs @@ -1,1247 +1,1308 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Scanners for fragments of CommonMark syntax - -use std::char; -use std::convert::TryInto; - -use crate::entities; -use crate::parse::{Alignment, HtmlScanGuard, LinkType}; -pub use crate::puncttable::{is_ascii_punctuation, is_punctuation}; -use crate::strings::CowStr; - -use memchr::memchr; - -// sorted for binary search -const HTML_TAGS: [&str; 62] = [ - "address", - "article", - "aside", - "base", - "basefont", - "blockquote", - "body", - "caption", - "center", - "col", - "colgroup", - "dd", - "details", - "dialog", - "dir", - "div", - "dl", - "dt", - "fieldset", - "figcaption", - "figure", - "footer", - "form", - "frame", - "frameset", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "head", - "header", - "hr", - "html", - "iframe", - "legend", - "li", - "link", - "main", - "menu", - "menuitem", - "nav", - "noframes", - "ol", - "optgroup", - "option", - "p", - "param", - "section", - "source", - "summary", - "table", - "tbody", - "td", - "tfoot", - "th", - "thead", - "title", - "tr", - "track", - "ul", -]; - -/// Analysis of the beginning of a line, including indentation and container -/// markers. -#[derive(Clone)] -pub struct LineStart<'a> { - bytes: &'a [u8], - tab_start: usize, - ix: usize, - spaces_remaining: usize, - // no thematic breaks can occur before this offset. - // this prevents scanning over and over up to a certain point - min_hrule_offset: usize, -} - -impl<'a> LineStart<'a> { - pub(crate) fn new(bytes: &[u8]) -> LineStart { - LineStart { - bytes, - tab_start: 0, - ix: 0, - spaces_remaining: 0, - min_hrule_offset: 0, - } - } - - /// Try to scan a number of spaces. - /// - /// Returns true if all spaces were consumed. - /// - /// Note: consumes some spaces even if not successful. - pub(crate) fn scan_space(&mut self, n_space: usize) -> bool { - self.scan_space_inner(n_space) == 0 - } - - /// Scan a number of spaces up to a maximum. - /// - /// Returns number of spaces scanned. - pub(crate) fn scan_space_upto(&mut self, n_space: usize) -> usize { - n_space - self.scan_space_inner(n_space) - } - - /// Returns unused remainder of spaces. - fn scan_space_inner(&mut self, mut n_space: usize) -> usize { - let n_from_remaining = self.spaces_remaining.min(n_space); - self.spaces_remaining -= n_from_remaining; - n_space -= n_from_remaining; - while n_space > 0 && self.ix < self.bytes.len() { - match self.bytes[self.ix] { - b' ' => { - self.ix += 1; - n_space -= 1; - } - b'\t' => { - let spaces = 4 - (self.ix - self.tab_start) % 4; - self.ix += 1; - self.tab_start = self.ix; - let n = spaces.min(n_space); - n_space -= n; - self.spaces_remaining = spaces - n; - } - _ => break, - } - } - n_space - } - - /// Scan all available ASCII whitespace (not including eol). - pub(crate) fn scan_all_space(&mut self) { - self.spaces_remaining = 0; - self.ix += self.bytes[self.ix..] - .iter() - .take_while(|&&b| b == b' ' || b == b'\t') - .count(); - } - - /// Determine whether we're at end of line (includes end of file). - pub(crate) fn is_at_eol(&self) -> bool { - self.bytes - .get(self.ix) - .map(|&c| c == b'\r' || c == b'\n') - .unwrap_or(true) - } - - fn scan_ch(&mut self, c: u8) -> bool { - if self.ix < self.bytes.len() && self.bytes[self.ix] == c { - self.ix += 1; - true - } else { - false - } - } - - pub(crate) fn scan_blockquote_marker(&mut self) -> bool { - let save = self.clone(); - let _ = self.scan_space(3); - if self.scan_ch(b'>') { - let _ = self.scan_space(1); - true - } else { - *self = save; - false - } - } - - /// Scan a list marker. - /// - /// Return value is the character, the start index, and the indent in spaces. - /// For ordered list markers, the character will be one of b'.' or b')'. For - /// bullet list markers, it will be one of b'-', b'+', or b'*'. - pub(crate) fn scan_list_marker(&mut self) -> Option<(u8, u64, usize)> { - let save = self.clone(); - let indent = self.scan_space_upto(3); - if self.ix < self.bytes.len() { - let c = self.bytes[self.ix]; - if c == b'-' || c == b'+' || c == b'*' { - if self.ix >= self.min_hrule_offset { - // there could be an hrule here - if let Err(min_offset) = scan_hrule(&self.bytes[self.ix..]) { - self.min_hrule_offset = min_offset; - } else { - *self = save; - return None; - } - } - self.ix += 1; - if self.scan_space(1) || self.is_at_eol() { - return self.finish_list_marker(c, 0, indent + 2); - } - } else if c >= b'0' && c <= b'9' { - let start_ix = self.ix; - let mut ix = self.ix + 1; - let mut val = u64::from(c - b'0'); - while ix < self.bytes.len() && ix - start_ix < 10 { - let c = self.bytes[ix]; - ix += 1; - if c >= b'0' && c <= b'9' { - val = val * 10 + u64::from(c - b'0'); - } else if c == b')' || c == b'.' { - self.ix = ix; - if self.scan_space(1) || self.is_at_eol() { - return self.finish_list_marker(c, val, indent + self.ix - start_ix); - } else { - break; - } - } else { - break; - } - } - } - } - *self = save; - None - } - - fn finish_list_marker( - &mut self, - c: u8, - start: u64, - mut indent: usize, - ) -> Option<(u8, u64, usize)> { - let save = self.clone(); - - // skip the rest of the line if it's blank - if scan_blank_line(&self.bytes[self.ix..]).is_some() { - return Some((c, start, indent)); - } - - let post_indent = self.scan_space_upto(4); - if post_indent < 4 { - indent += post_indent; - } else { - *self = save; - } - Some((c, start, indent)) - } - - /// Returns Some(is_checked) when a task list marker was found. Resets itself - /// to original state otherwise. - pub(crate) fn scan_task_list_marker(&mut self) -> Option { - let save = self.clone(); - self.scan_space_upto(3); - - if !self.scan_ch(b'[') { - *self = save; - return None; - } - let is_checked = match self.bytes.get(self.ix) { - Some(&c) if is_ascii_whitespace_no_nl(c) => { - self.ix += 1; - false - } - Some(b'x') | Some(b'X') => { - self.ix += 1; - true - } - _ => { - *self = save; - return None; - } - }; - if !self.scan_ch(b']') { - *self = save; - return None; - } - if !self - .bytes - .get(self.ix) - .map(|&b| is_ascii_whitespace_no_nl(b)) - .unwrap_or(false) - { - *self = save; - return None; - } - Some(is_checked) - } - - pub(crate) fn bytes_scanned(&self) -> usize { - self.ix - } - - pub(crate) fn remaining_space(&self) -> usize { - self.spaces_remaining - } -} - -pub(crate) fn is_ascii_whitespace(c: u8) -> bool { - (c >= 0x09 && c <= 0x0d) || c == b' ' -} - -pub(crate) fn is_ascii_whitespace_no_nl(c: u8) -> bool { - c == b'\t' || c == 0x0b || c == 0x0c || c == b' ' -} - -fn is_ascii_alpha(c: u8) -> bool { - match c { - b'a'..=b'z' | b'A'..=b'Z' => true, - _ => false, - } -} - -fn is_ascii_alphanumeric(c: u8) -> bool { - match c { - b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => true, - _ => false, - } -} - -fn is_ascii_letterdigitdash(c: u8) -> bool { - c == b'-' || is_ascii_alphanumeric(c) -} - -fn is_digit(c: u8) -> bool { - b'0' <= c && c <= b'9' -} - -fn is_valid_unquoted_attr_value_char(c: u8) -> bool { - match c { - b'\'' | b'"' | b' ' | b'=' | b'>' | b'<' | b'`' | b'\n' | b'\r' => false, - _ => true, - } -} - -// scan a single character -pub(crate) fn scan_ch(data: &[u8], c: u8) -> usize { - if !data.is_empty() && data[0] == c { - 1 - } else { - 0 - } -} - -pub(crate) fn scan_while(data: &[u8], mut f: F) -> usize -where - F: FnMut(u8) -> bool, -{ - data.iter().take_while(|&&c| f(c)).count() -} - -pub(crate) fn scan_rev_while(data: &[u8], mut f: F) -> usize -where - F: FnMut(u8) -> bool, -{ - data.iter().rev().take_while(|&&c| f(c)).count() -} - -pub(crate) fn scan_ch_repeat(data: &[u8], c: u8) -> usize { - scan_while(data, |x| x == c) -} - -// Note: this scans ASCII whitespace only, for Unicode whitespace use -// a different function. -pub(crate) fn scan_whitespace_no_nl(data: &[u8]) -> usize { - scan_while(data, is_ascii_whitespace_no_nl) -} - -fn scan_attr_value_chars(data: &[u8]) -> usize { - scan_while(data, is_valid_unquoted_attr_value_char) -} - -pub(crate) fn scan_eol(bytes: &[u8]) -> Option { - if bytes.is_empty() { - return Some(0); - } - match bytes[0] { - b'\n' => Some(1), - b'\r' => Some(if bytes.get(1) == Some(&b'\n') { 2 } else { 1 }), - _ => None, - } -} - -pub(crate) fn scan_blank_line(bytes: &[u8]) -> Option { - let i = scan_whitespace_no_nl(bytes); - scan_eol(&bytes[i..]).map(|n| i + n) -} - -pub(crate) fn scan_nextline(bytes: &[u8]) -> usize { - memchr(b'\n', bytes).map_or(bytes.len(), |x| x + 1) -} - -// return: end byte for closing code fence, or None -// if the line is not a closing code fence -pub(crate) fn scan_closing_code_fence( - bytes: &[u8], - fence_char: u8, - n_fence_char: usize, -) -> Option { - if bytes.is_empty() { - return Some(0); - } - let mut i = 0; - let num_fence_chars_found = scan_ch_repeat(&bytes[i..], fence_char); - if num_fence_chars_found < n_fence_char { - return None; - } - i += num_fence_chars_found; - let num_trailing_spaces = scan_ch_repeat(&bytes[i..], b' '); - i += num_trailing_spaces; - scan_eol(&bytes[i..]).map(|_| i) -} - -// returned pair is (number of bytes, number of spaces) -fn calc_indent(text: &[u8], max: usize) -> (usize, usize) { - let mut spaces = 0; - let mut offset = 0; - - for (i, &b) in text.iter().enumerate() { - match b { - b' ' => { - spaces += 1; - if spaces == max { - break; - } - } - b'\t' => { - let new_spaces = spaces + 4 - (spaces & 3); - if new_spaces > max { - break; - } - spaces = new_spaces; - } - _ => break, - } - offset = i; - } - - (offset, spaces) -} - -/// Scan hrule opening sequence. -/// -/// Returns Ok(x) when it finds an hrule, where x is the -/// size of line containing the hrule, including the trailing newline. -/// -/// Returns Err(x) when it does not find an hrule and x is -/// the offset in data before no hrule can appear. -pub(crate) fn scan_hrule(bytes: &[u8]) -> Result { - if bytes.len() < 3 { - return Err(0); - } - let c = bytes[0]; - if !(c == b'*' || c == b'-' || c == b'_') { - return Err(0); - } - let mut n = 0; - let mut i = 0; - - while i < bytes.len() { - match bytes[i] { - b'\n' | b'\r' => { - i += scan_eol(&bytes[i..]).unwrap_or(0); - break; - } - c2 if c2 == c => { - n += 1; - } - b' ' | b'\t' => (), - _ => return Err(i), - } - i += 1; - } - if n >= 3 { - Ok(i) - } else { - Err(i) - } -} - -/// Scan an ATX heading opening sequence. -/// -/// Returns number of bytes in prefix and level. -pub(crate) fn scan_atx_heading(data: &[u8]) -> Option { - let level = scan_ch_repeat(data, b'#'); - if level >= 1 && level <= 6 && data.get(level).cloned().map_or(true, is_ascii_whitespace) { - Some(level) - } else { - None - } -} - -/// Scan a setext heading underline. -/// -/// Returns number of bytes in line (including trailing newline) and level. -pub(crate) fn scan_setext_heading(data: &[u8]) -> Option<(usize, u32)> { - let c = *data.get(0)?; - if !(c == b'-' || c == b'=') { - return None; - } - let mut i = 1 + scan_ch_repeat(&data[1..], c); - i += scan_blank_line(&data[i..])?; - let level = if c == b'=' { 1 } else { 2 }; - Some((i, level)) -} - -// returns number of bytes in line (including trailing -// newline) and column alignments -pub(crate) fn scan_table_head(data: &[u8]) -> (usize, Vec) { - let (mut i, spaces) = calc_indent(data, 4); - if spaces > 3 || i == data.len() { - return (0, vec![]); - } - let mut cols = vec![]; - let mut active_col = Alignment::None; - let mut start_col = true; - if data[i] == b'|' { - i += 1; - } - for c in &data[i..] { - if let Some(n) = scan_eol(&data[i..]) { - i += n; - break; - } - match *c { - b' ' => (), - b':' => { - active_col = match (start_col, active_col) { - (true, Alignment::None) => Alignment::Left, - (false, Alignment::Left) => Alignment::Center, - (false, Alignment::None) => Alignment::Right, - _ => active_col, - }; - start_col = false; - } - b'-' => { - start_col = false; - } - b'|' => { - start_col = true; - cols.push(active_col); - active_col = Alignment::None; - } - _ => { - cols = vec![]; - start_col = true; - break; - } - } - i += 1; - } - - if !start_col { - cols.push(active_col); - } - - (i, cols) -} - -/// Scan code fence. -/// -/// Returns number of bytes scanned and the char that is repeated to make the code fence. -pub(crate) fn scan_code_fence(data: &[u8]) -> Option<(usize, u8)> { - let c = *data.get(0)?; - if !(c == b'`' || c == b'~') { - return None; - } - let i = 1 + scan_ch_repeat(&data[1..], c); - if i >= 3 { - if c == b'`' { - let suffix = &data[i..]; - let next_line = i + scan_nextline(suffix); - // FIXME: make sure this is correct - if suffix[..(next_line - i)].iter().any(|&b| b == b'`') { - return None; - } - } - Some((i, c)) - } else { - None - } -} - -pub(crate) fn scan_blockquote_start(data: &[u8]) -> Option { - if data.starts_with(b"> ") { - Some(2) - } else { - None - } -} - -/// This already assumes the list item has been scanned. -pub(crate) fn scan_empty_list(data: &[u8]) -> bool { - let mut ix = 0; - for _ in 0..2 { - if let Some(bytes) = scan_blank_line(&data[ix..]) { - ix += bytes; - } else { - return false; - } - } - true -} - -// return number of bytes scanned, delimiter, start index, and indent -pub(crate) fn scan_listitem(bytes: &[u8]) -> Option<(usize, u8, usize, usize)> { - let mut c = *bytes.get(0)?; - let (w, start) = match c { - b'-' | b'+' | b'*' => (1, 0), - b'0'..=b'9' => { - let (length, start) = parse_decimal(bytes); - c = *bytes.get(length)?; - if !(c == b'.' || c == b')') { - return None; - } - (length + 1, start) - } - _ => { - return None; - } - }; - // TODO: replace calc_indent with scan_leading_whitespace, for tab correctness - let (mut postn, mut postindent) = calc_indent(&bytes[w..], 5); - if postindent == 0 { - scan_eol(&bytes[w..])?; - postindent += 1; - } else if postindent > 4 { - postn = 1; - postindent = 1; - } - if scan_blank_line(&bytes[w..]).is_some() { - postn = 0; - postindent = 1; - } - Some((w + postn, c, start, w + postindent)) -} - -// returns (number of bytes, parsed decimal) -fn parse_decimal(bytes: &[u8]) -> (usize, usize) { - match bytes - .iter() - .take_while(|&&b| is_digit(b)) - .try_fold((0, 0usize), |(count, acc), c| { - let digit = usize::from(c - b'0'); - match acc - .checked_mul(10) - .and_then(|ten_acc| ten_acc.checked_add(digit)) - { - Some(number) => Ok((count + 1, number)), - // stop early on overflow - None => Err((count, acc)), - } - }) { - Ok(p) | Err(p) => p, - } -} - -// returns (number of bytes, parsed hex) -fn parse_hex(bytes: &[u8]) -> (usize, usize) { - match bytes.iter().try_fold((0, 0usize), |(count, acc), c| { - let mut c = *c; - let digit = if c >= b'0' && c <= b'9' { - usize::from(c - b'0') - } else { - // make lower case - c |= 0x20; - if c >= b'a' && c <= b'f' { - usize::from(c - b'a' + 10) - } else { - return Err((count, acc)); - } - }; - match acc - .checked_mul(16) - .and_then(|sixteen_acc| sixteen_acc.checked_add(digit)) - { - Some(number) => Ok((count + 1, number)), - // stop early on overflow - None => Err((count, acc)), - } - }) { - Ok(p) | Err(p) => p, - } -} - -fn char_from_codepoint(input: usize) -> Option { - let mut codepoint = input.try_into().ok()?; - if codepoint == 0 { - codepoint = 0xFFFD; - } - char::from_u32(codepoint) -} - -// doesn't bother to check data[0] == '&' -pub(crate) fn scan_entity(bytes: &[u8]) -> (usize, Option>) { - let mut end = 1; - if scan_ch(&bytes[end..], b'#') == 1 { - end += 1; - let (bytecount, codepoint) = if end < bytes.len() && bytes[end] | 0x20 == b'x' { - end += 1; - parse_hex(&bytes[end..]) - } else { - parse_decimal(&bytes[end..]) - }; - end += bytecount; - return if bytecount == 0 || scan_ch(&bytes[end..], b';') == 0 { - (0, None) - } else if let Some(c) = char_from_codepoint(codepoint) { - (end + 1, Some(c.into())) - } else { - (0, None) - }; - } - end += scan_while(&bytes[end..], is_ascii_alphanumeric); - if scan_ch(&bytes[end..], b';') == 1 { - if let Some(value) = entities::get_entity(&bytes[1..end]) { - return (end + 1, Some(value.into())); - } - } - (0, None) -} - -// FIXME: we can most likely re-use other scanners -// returns (bytelength, title_str) -pub(crate) fn scan_refdef_title(text: &str) -> Option<(usize, &str)> { - let mut chars = text.chars().peekable(); - let closing_delim = match chars.next()? { - '\'' => '\'', - '"' => '"', - '(' => ')', - _ => return None, - }; - let mut bytecount = 1; - - while let Some(c) = chars.next() { - match c { - '\n' => { - bytecount += 1; - let mut next = *chars.peek()?; - while is_ascii_whitespace_no_nl(next as u8) { - bytecount += chars.next()?.len_utf8(); - next = *chars.peek()?; - } - if *chars.peek()? == '\n' { - // blank line - not allowed - return None; - } - } - '\\' => { - let next_char = chars.next()?; - bytecount += 1 + next_char.len_utf8(); - } - c if c == closing_delim => { - return Some((bytecount + 1, &text[1..bytecount])); - } - c => { - bytecount += c.len_utf8(); - } - } - } - None -} - -// note: dest returned is raw, still needs to be unescaped -// TODO: check that nested parens are really not allowed for refdefs -// TODO(performance): this func should probably its own unescaping -pub(crate) fn scan_link_dest( - data: &str, - start_ix: usize, - max_next: usize, -) -> Option<(usize, &str)> { - let bytes = &data.as_bytes()[start_ix..]; - let mut i = scan_ch(bytes, b'<'); - - if i != 0 { - // pointy links - while i < bytes.len() { - match bytes[i] { - b'\n' | b'\r' | b'<' => return None, - b'>' => return Some((i + 1, &data[(start_ix + 1)..(start_ix + i)])), - b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { - i += 1; - } - _ => {} - } - i += 1; - } - None - } else { - // non-pointy links - let mut nest = 0; - while i < bytes.len() { - match bytes[i] { - 0x0..=0x20 => { - break; - } - b'(' => { - if nest > max_next { - return None; - } - nest += 1; - } - b')' => { - if nest == 0 { - break; - } - nest -= 1; - } - b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { - i += 1; - } - _ => {} - } - i += 1; - } - Some((i, &data[start_ix..(start_ix + i)])) - } -} - -/// Returns bytes scanned -fn scan_attribute_name(data: &[u8]) -> Option { - let (&c, tail) = data.split_first()?; - if is_ascii_alpha(c) || c == b'_' || c == b':' { - Some( - 1 + scan_while(tail, |c| { - is_ascii_alphanumeric(c) || c == b'_' || c == b'.' || c == b':' || c == b'-' - }), - ) - } else { - None - } -} - -/// Returns byte scanned (TODO: should it return new offset?) -// TODO: properly use the newline handler here -fn scan_attribute(data: &[u8], newline_handler: Option<&dyn Fn(&[u8]) -> usize>) -> Option { - let allow_newline = newline_handler.is_some(); - let whitespace_scanner = - |c| is_ascii_whitespace(c) && (allow_newline || c != b'\n' && c != b'\r'); - let mut ix = scan_attribute_name(data)?; - let n_whitespace = scan_while(&data[ix..], whitespace_scanner); - ix += n_whitespace; - if scan_ch(&data[ix..], b'=') == 1 { - ix += 1; - ix += scan_while(&data[ix..], whitespace_scanner); - ix += scan_attribute_value(&data[ix..], newline_handler)?; - } else if n_whitespace > 0 { - // Leave whitespace for next attribute. - ix -= 1; - } - Some(ix) -} - -fn scan_attribute_value( - data: &[u8], - newline_handler: Option<&dyn Fn(&[u8]) -> usize>, -) -> Option { - let mut i = 0; - match *data.get(0)? { - b @ b'"' | b @ b'\'' => { - i += 1; - while i < data.len() { - if data[i] == b { - return Some(i + 1); - } - if let Some(eol_bytes) = scan_eol(&data[i..]) { - let handler = newline_handler?; - i += eol_bytes; - i += handler(&data[i..]); - } else { - i += 1; - } - } - return None; - } - b' ' | b'=' | b'>' | b'<' | b'`' | b'\n' | b'\r' => { - return None; - } - _ => { - // unquoted attribute value - i += scan_attr_value_chars(&data[i..]); - } - } - Some(i) -} - -// Remove backslash escapes and resolve entities -pub(crate) fn unescape(input: &str) -> CowStr<'_> { - let mut result = String::new(); - let mut mark = 0; - let mut i = 0; - let bytes = input.as_bytes(); - while i < bytes.len() { - match bytes[i] { - b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { - result.push_str(&input[mark..i]); - mark = i + 1; - i += 2; - } - b'&' => match scan_entity(&bytes[i..]) { - (n, Some(value)) => { - result.push_str(&input[mark..i]); - result.push_str(&value); - i += n; - mark = i; - } - _ => i += 1, - }, - b'\r' => { - result.push_str(&input[mark..i]); - i += 1; - mark = i; - } - _ => i += 1, - } - } - if mark == 0 { - input.into() - } else { - result.push_str(&input[mark..]); - result.into() - } -} - -/// Assumes `data` is preceded by `<`. -pub(crate) fn scan_html_block_tag(data: &[u8]) -> (usize, &[u8]) { - let i = scan_ch(data, b'/'); - let n = scan_while(&data[i..], is_ascii_alphanumeric); - // TODO: scan attributes and > - (i + n, &data[i..i + n]) -} - -pub(crate) fn is_html_tag(tag: &[u8]) -> bool { - HTML_TAGS - .binary_search_by(|probe| { - let probe_bytes_iter = probe.as_bytes().iter(); - let tag_bytes_iter = tag.iter(); - - probe_bytes_iter - .zip(tag_bytes_iter) - .find_map(|(&a, &b)| { - // We can compare case insensitively because the probes are - // all lower case alpha strings. - match a.cmp(&(b | 0x20)) { - std::cmp::Ordering::Equal => None, - inequality => Some(inequality), - } - }) - .unwrap_or_else(|| probe.len().cmp(&tag.len())) - }) - .is_ok() -} - -/// Assumes that `data` is preceded by `<`. -pub(crate) fn scan_html_type_7(data: &[u8]) -> Option { - // Block type html does not allow for newlines, so we - // do not pass a newline handler. - let i = scan_html_block_inner(data, None)?; - scan_blank_line(&data[i..])?; - Some(i) -} - -// FIXME: instead of a newline handler, maybe this should receive -// a whitespace handler instead. -// With signature `&dyn Fn(&[u8]) -> Option`. -// We currently need to implement whitespace handling in all of -// this function's dependencies as well. -pub(crate) fn scan_html_block_inner( - data: &[u8], - newline_handler: Option<&dyn Fn(&[u8]) -> usize>, -) -> Option { - let close_tag_bytes = scan_ch(data, b'/'); - let l = scan_while(&data[close_tag_bytes..], is_ascii_alpha); - if l == 0 { - return None; - } - let mut i = close_tag_bytes + l; - i += scan_while(&data[i..], is_ascii_letterdigitdash); - - if close_tag_bytes == 0 { - loop { - let old_i = i; - loop { - i += scan_whitespace_no_nl(&data[i..]); - if let Some(eol_bytes) = scan_eol(&data[i..]) { - if eol_bytes == 0 { - return None; - } - if let Some(handler) = newline_handler { - i += eol_bytes; - i += handler(&data[i..]); - } else { - return None; - } - } else { - break; - } - } - if let Some(b'/') | Some(b'>') = data.get(i) { - break; - } - if old_i == i { - // No whitespace, which is mandatory. - return None; - } - i += scan_attribute(&data[i..], newline_handler)?; - } - } - - i += scan_whitespace_no_nl(&data[i..]); - - if close_tag_bytes == 0 { - i += scan_ch(&data[i..], b'/'); - } - - if scan_ch(&data[i..], b'>') == 0 { - None - } else { - Some(i + 1) - } -} - -/// Returns (next_byte_offset, uri, type) -pub(crate) fn scan_autolink(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>, LinkType)> { - scan_uri(text, start_ix) - .map(|(bytes, uri)| (bytes, uri, LinkType::Autolink)) - .or_else(|| scan_email(text, start_ix).map(|(bytes, uri)| (bytes, uri, LinkType::Email))) -} - -/// Returns (next_byte_offset, uri) -fn scan_uri(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>)> { - let bytes = &text.as_bytes()[start_ix..]; - - // scheme's first byte must be an ascii letter - if bytes.is_empty() || !is_ascii_alpha(bytes[0]) { - return None; - } - - let mut i = 1; - - while i < bytes.len() { - let c = bytes[i]; - i += 1; - match c { - c if is_ascii_alphanumeric(c) => (), - b'.' | b'-' | b'+' => (), - b':' => break, - _ => return None, - } - } - - // scheme length must be between 2 and 32 characters long. scheme - // must be followed by colon - if i < 3 || i > 33 { - return None; - } - - while i < bytes.len() { - match bytes[i] { - b'>' => return Some((start_ix + i + 1, text[start_ix..(start_ix + i)].into())), - b'\0'..=b' ' | b'<' => return None, - _ => (), - } - i += 1; - } - - None -} - -/// Returns (next_byte_offset, email) -fn scan_email(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>)> { - // using a regex library would be convenient, but doing it by hand is not too bad - let bytes = &text.as_bytes()[start_ix..]; - let mut i = 0; - - while i < bytes.len() { - let c = bytes[i]; - i += 1; - match c { - c if is_ascii_alphanumeric(c) => (), - b'.' | b'!' | b'#' | b'$' | b'%' | b'&' | b'\'' | b'*' | b'+' | b'/' | b'=' | b'?' - | b'^' | b'_' | b'`' | b'{' | b'|' | b'}' | b'~' | b'-' => (), - b'@' => break, - _ => return None, - } - } - - loop { - let label_start_ix = i; - let mut fresh_label = true; - - while i < bytes.len() { - match bytes[i] { - c if is_ascii_alphanumeric(c) => (), - b'-' if fresh_label => { - return None; - } - b'-' => (), - _ => break, - } - fresh_label = false; - i += 1; - } - - if i == label_start_ix || i - label_start_ix > 63 || bytes[i - 1] == b'-' { - return None; - } - - if scan_ch(&bytes[i..], b'.') == 0 { - break; - } - i += 1; - } - - if scan_ch(&bytes[i..], b'>') == 0 { - return None; - } - - Some((start_ix + i + 1, text[start_ix..(start_ix + i)].into())) -} - -/// Scan comment, declaration, or CDATA section, with initial " Option { - let c = *bytes.get(ix)?; - ix += 1; - match c { - b'-' => { - let dashes = scan_ch_repeat(&bytes[ix..], b'-'); - if dashes < 1 { - return None; - } - // Saw ""##; - let expected = r##"

    Little header

    -"##; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_5() { - let original = r##"Little header - - -

    Useless

    -]]>"##; - let expected = r##"

    Little header

    - -

    Useless

    -]]>"##; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_6() { - let original = r##"Little header - -"##; - let expected = r##"

    Little header

    -"##; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_7() { - let original = r##"Little header ------------ - -"##; - let expected = r##"

    Little header

    -"##; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_8() { - let original = "A | B\n---|---\nfoo | bar"; - let expected = r##" - -
    AB
    foobar
    -"##; - - let mut s = String::new(); - let mut opts = Options::empty(); - opts.insert(Options::ENABLE_TABLES); - html::push_html(&mut s, Parser::new_ext(&original, opts)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_9() { - let original = "---"; - let expected = "
    \n"; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_10() { - let original = "* * *"; - let expected = "
    \n"; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -// TODO: add broken link callback feature -/* -#[test] -fn html_test_broken_callback() { - let original = r##"[foo], -[bar], -[baz], - - [baz]: https://example.org -"##; - - let expected = r##"

    foo, -[bar], -baz,

    -"##; - - use pulldown_cmark::{Options, Parser, html}; - - let mut s = String::new(); - - let callback = |reference: &str, _normalized: &str| -> Option<(String, String)> { - if reference == "foo" || reference == "baz" { - Some(("https://replaced.example.org".into(), "some title".into())) - } else { - None - } - }; - - let p = Parser::new_with_broken_link_callback(&original, Options::empty(), Some(&callback)); - html::push_html(&mut s, p); - - assert_eq!(expected, s); -} -*/ +// Tests for HTML spec. + +extern crate pulldown_cmark; + +use pulldown_cmark::{html, BrokenLink, Options, Parser}; + +#[test] +fn html_test_1() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_2() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_3() { + let original = r##"Little header + + +

    Useless

    +?>"##; + let expected = r##"

    Little header

    + +

    Useless

    +?>"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_4() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_5() { + let original = r##"Little header + + +

    Useless

    +]]>"##; + let expected = r##"

    Little header

    + +

    Useless

    +]]>"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_6() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_7() { + let original = r##"Little header +----------- + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_8() { + let original = "A | B\n---|---\nfoo | bar"; + let expected = r##" + +
    AB
    foobar
    +"##; + + let mut s = String::new(); + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + html::push_html(&mut s, Parser::new_ext(&original, opts)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_9() { + let original = "---"; + let expected = "
    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_10() { + let original = "* * *"; + let expected = "
    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_11() { + let original = "hi ~~no~~"; + let expected = "

    hi ~~no~~

    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_broken_callback() { + let original = r##"[foo], +[bar], +[baz], + + [baz]: https://example.org +"##; + + let expected = r##"

    foo, +[bar], +baz,

    +"##; + + use pulldown_cmark::{html, Options, Parser}; + + let mut s = String::new(); + + let mut callback = |broken_link: BrokenLink| { + if broken_link.reference == "foo" || broken_link.reference == "baz" { + Some(("https://replaced.example.org".into(), "some title".into())) + } else { + None + } + }; + + let p = Parser::new_with_broken_link_callback(&original, Options::empty(), Some(&mut callback)); + html::push_html(&mut s, p); + + assert_eq!(expected, s); +} diff --git a/vendor/pulldown-cmark/tests/lib.rs b/vendor/pulldown-cmark/tests/lib.rs index 11be5bcd09..6457625d07 100644 --- a/vendor/pulldown-cmark/tests/lib.rs +++ b/vendor/pulldown-cmark/tests/lib.rs @@ -1,422 +1,425 @@ -#[macro_use] -extern crate html5ever; -#[macro_use] -extern crate lazy_static; - -use html5ever::serialize::{serialize, SerializeOpts}; -use html5ever::{driver as html, QualName}; -use markup5ever_rcdom::{Handle, NodeData, RcDom, SerializableHandle}; -use pulldown_cmark::{Options, Parser}; - -use regex::Regex; -use std::collections::HashSet; -use std::mem; -use std::rc::{Rc, Weak}; -use tendril::stream::TendrilSink; - -mod suite; - -#[inline(never)] -pub fn test_markdown_html(input: &str, output: &str) { - let mut s = String::new(); - - let mut opts = Options::empty(); - opts.insert(Options::ENABLE_TABLES); - opts.insert(Options::ENABLE_FOOTNOTES); - opts.insert(Options::ENABLE_STRIKETHROUGH); - opts.insert(Options::ENABLE_TASKLISTS); - - let p = Parser::new_ext(input, opts); - pulldown_cmark::html::push_html(&mut s, p); - - assert_eq!(normalize_html(output), normalize_html(&s)); -} - -lazy_static! { - static ref WHITESPACE_RE: Regex = Regex::new(r"\s+").unwrap(); - static ref LEADING_WHITESPACE_RE: Regex = Regex::new(r"\A\s+").unwrap(); - static ref TRAILING_WHITESPACE_RE: Regex = Regex::new(r"\s+\z").unwrap(); - static ref BLOCK_TAGS: HashSet<&'static str> = [ - "article", - "header", - "aside", - "hgroup", - "blockquote", - "hr", - "iframe", - "body", - "li", - "map", - "button", - "object", - "canvas", - "ol", - "caption", - "output", - "col", - "p", - "colgroup", - "pre", - "dd", - "progress", - "div", - "section", - "dl", - "table", - "td", - "dt", - "tbody", - "embed", - "textarea", - "fieldset", - "tfoot", - "figcaption", - "th", - "figure", - "thead", - "footer", - "tr", - "form", - "ul", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "video", - "script", - "style" - ] - .iter() - .cloned() - .collect(); - static ref WHITESPACE_SENSITIVE_TAGS: HashSet<&'static str> = - ["pre", "code", "h1", "h2", "h3", "h4", "h5", "h6"] - .iter() - .cloned() - .collect(); - static ref TABLE_TAGS: HashSet<&'static str> = ["table", "thead", "tbody", "tr", "td"] - .iter() - .cloned() - .collect(); -} - -fn make_html_parser() -> html::Parser { - html::parse_fragment( - RcDom::default(), - html::ParseOpts::default(), - QualName::new(None, ns!(html), local_name!("div")), - vec![], - ) -} - -fn normalize_html(s: &str) -> String { - let parser = make_html_parser(); - let dom = parser.one(s); - let body: SerializableHandle = normalize_dom(&dom).into(); - let opts = SerializeOpts::default(); - let mut ret_val = Vec::new(); - serialize(&mut ret_val, &body, opts) - .expect("Writing to a string shouldn't fail (expect on OOM)"); - String::from_utf8(ret_val).expect("html5ever should always produce UTF8") -} - -fn normalize_dom(dom: &RcDom) -> Handle { - let body = { - let children = dom.document.children.borrow(); - children[0].clone() - }; - let mut current_level = Vec::new(); - let mut next_level = Vec::new(); - current_level.extend(body.children.borrow().iter().cloned().rev()); - loop { - while let Some(mut node) = current_level.pop() { - let parent = node.parent.replace(None); - node.parent.replace(parent.clone()); - let parent = parent - .expect("a node in the DOM will have a parent, except the root, which is not processed") - .upgrade().expect("a node's parent will be pointed to by its parent (or the root pointer), and will not be dropped"); - let retain = normalize_node(&parent, &mut node); - if !retain { - let mut siblings = parent.children.borrow_mut(); - siblings.retain(|s| !Rc::ptr_eq(&node, s)); - } else { - next_level.extend(node.children.borrow().iter().cloned().rev()); - } - } - if next_level.is_empty() { - break; - }; - mem::swap(&mut next_level, &mut current_level); - } - body -} - -// Returns false if node is an empty text node or an empty tbody. -// Returns true otherwise. -fn normalize_node(parent: &Handle, node: &mut Handle) -> bool { - match node.data { - NodeData::Comment { .. } - | NodeData::Doctype { .. } - | NodeData::Document - | NodeData::ProcessingInstruction { .. } => true, - NodeData::Text { ref contents, .. } => { - let mut contents = contents.borrow_mut(); - let is_pre = { - let mut parent = parent.clone(); - loop { - let is_pre = if let NodeData::Element { ref name, .. } = parent.data { - WHITESPACE_SENSITIVE_TAGS.contains(&&*name.local.to_ascii_lowercase()) - } else { - false - }; - if is_pre { - break true; - }; - let parent_ = parent.parent.replace(None); - parent.parent.replace(parent_.clone()); - let parent_ = parent_.as_ref().and_then(Weak::upgrade); - if let Some(parent_) = parent_ { - parent = parent_ - } else { - break false; - }; - } - }; - if !is_pre { - let (is_first_in_block, is_last_in_block) = { - let mut is_first_in_block = true; - let mut is_last_in_block = true; - let mut parent = parent.clone(); - let mut node = node.clone(); - loop { - let reached_block = if let NodeData::Element { ref name, .. } = parent.data - { - BLOCK_TAGS.contains(&&*name.local.to_ascii_lowercase()) - } else { - false - }; - let (is_first, is_last) = { - let siblings = parent.children.borrow(); - let n = &node; - ( - siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false), - siblings.len() > 0 - && siblings - .get(siblings.len() - 1) - .map(|s| Rc::ptr_eq(s, n)) - .unwrap_or(false), - ) - }; - is_first_in_block = is_first_in_block && is_first; - is_last_in_block = is_last_in_block && is_last; - if (is_first_in_block || is_last_in_block) && !reached_block { - node = parent.clone(); - let parent_ = parent.parent.replace(None); - parent.parent.replace(parent_.clone()); - let parent_ = parent_.as_ref().and_then(Weak::upgrade); - if let Some(parent_) = parent_ { - parent = parent_; - } else { - break (is_first_in_block, is_last_in_block); - } - } else { - break (is_first_in_block, is_last_in_block); - } - } - }; - let is_preceeded_by_ws = { - let mut parent = parent.clone(); - let mut node = node.clone(); - 'ascent: loop { - let is_first = { - let siblings = parent.children.borrow(); - let n = &node; - siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false) - }; - if is_first { - node = parent.clone(); - let parent_ = parent.parent.replace(None); - parent.parent.replace(parent_.clone()); - let parent_ = parent_.as_ref().and_then(Weak::upgrade); - if let Some(parent_) = parent_ { - parent = parent_; - } else { - break 'ascent false; - } - } else { - let siblings = parent.children.borrow(); - let n = &node; - let mut pos = !0; - 'search: for (i, s) in siblings.iter().enumerate() { - if Rc::ptr_eq(s, n) { - pos = i; - break 'search; - } - } - assert!( - pos != !0, - "The list of node's parent's children shall contain node" - ); - assert!( - pos != 0, - "If node is not first, then node's position shall not be zero" - ); - let mut preceeding = siblings[pos - 1].clone(); - 'descent: loop { - if let NodeData::Text { .. } = preceeding.data { - break 'descent; - } - preceeding = { - let ch = preceeding.children.borrow(); - if ch.len() == 0 { - break 'descent; - } - if let Some(preceeding_) = ch.get(ch.len() - 1) { - preceeding_.clone() - } else { - break 'descent; - } - }; - } - if let NodeData::Text { ref contents, .. } = preceeding.data { - break 'ascent TRAILING_WHITESPACE_RE.is_match(&*contents.borrow()); - } else { - break 'ascent false; - } - } - } - }; - - let is_in_table = if let NodeData::Element { ref name, .. } = parent.data { - TABLE_TAGS.contains(&&*name.local.to_ascii_lowercase()) - } else { - false - }; - let whitespace_replacement = if is_in_table { "" } else { " " }; - *contents = WHITESPACE_RE - .replace_all(&*contents, whitespace_replacement) - .as_ref() - .into(); - - if is_first_in_block || is_preceeded_by_ws { - *contents = LEADING_WHITESPACE_RE - .replace_all(&*contents, "") - .as_ref() - .into(); - } - if is_last_in_block { - *contents = TRAILING_WHITESPACE_RE - .replace_all(&*contents, "") - .as_ref() - .into(); - } - // TODO: collapse whitespace when adjacent to whitespace. - // For example, the whitespace in the span should be collapsed in all of these cases: - // - // " q " - // "q q" - // "q q" - // "q q" - // "q q" - } - &**contents != "" - } - NodeData::Element { - ref attrs, - ref name, - .. - } => { - let mut attrs = attrs.borrow_mut(); - for a in attrs.iter_mut() { - a.name.local = a.name.local.to_ascii_lowercase().into(); - } - attrs.sort_by(|a: &html5ever::Attribute, b: &html5ever::Attribute| { - (&*a.name.local).cmp(&*b.name.local) - }); - let ascii_name = &*name.local.to_ascii_lowercase(); - // drop empty tbody's - ascii_name != "tbody" - || node.children.borrow().len() > 1 - || node - .children - .borrow() - .iter() - .next() - .map(|only_child| match only_child.data { - NodeData::Text { ref contents, .. } => { - !contents.borrow().chars().all(|c| c.is_whitespace()) - } - _ => true, - }) - .unwrap_or(false) - } - } -} - -#[test] -fn strip_div_newline() { - assert_eq!("
    ", normalize_html("
    \n
    ")); -} - -#[test] -fn strip_end_newline() { - assert_eq!("test", normalize_html("test\n")); -} - -#[test] -fn strip_double_space() { - assert_eq!("test mess", normalize_html("test mess")); -} - -#[test] -fn strip_inline_internal_text() { - assert_eq!( - "a b c", - normalize_html(" a b c ") - ) -} - -#[test] -fn strip_inline_block_internal_text() { - assert_eq!( - "a b c", - normalize_html(" a b c ") - ) -} - -#[test] -fn leaves_necessary_whitespace_alone() { - assert_eq!("a b c", normalize_html("a b c")) -} - -#[test] -fn leaves_necessary_whitespace_alone_weird() { - assert_eq!( - "a b c", - normalize_html(" a b c") - ) -} - -#[test] -fn leaves_necessary_whitespace_all_nested() { - assert_eq!( - "", - normalize_html(" ") - ) -} - -#[test] -fn drops_empty_tbody() { - assert_eq!( - "
    hi
    ", - normalize_html("
    hi
    ") - ) -} - -#[test] -fn leaves_nonempty_tbody() { - let input = "
    hi
    "; - assert_eq!(input, normalize_html(input)) -} +#[macro_use] +extern crate html5ever; +#[macro_use] +extern crate lazy_static; + +use html5ever::serialize::{serialize, SerializeOpts}; +use html5ever::{driver as html, QualName}; +use markup5ever_rcdom::{Handle, NodeData, RcDom, SerializableHandle}; +use pulldown_cmark::{Options, Parser}; + +use regex::Regex; +use std::collections::HashSet; +use std::mem; +use std::rc::{Rc, Weak}; +use tendril::stream::TendrilSink; + +mod suite; + +#[inline(never)] +pub fn test_markdown_html(input: &str, output: &str, smart_punct: bool) { + let mut s = String::new(); + + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + if smart_punct { + opts.insert(Options::ENABLE_SMART_PUNCTUATION); + } + + let p = Parser::new_ext(input, opts); + pulldown_cmark::html::push_html(&mut s, p); + + assert_eq!(normalize_html(output), normalize_html(&s)); +} + +lazy_static! { + static ref WHITESPACE_RE: Regex = Regex::new(r"\s+").unwrap(); + static ref LEADING_WHITESPACE_RE: Regex = Regex::new(r"\A\s+").unwrap(); + static ref TRAILING_WHITESPACE_RE: Regex = Regex::new(r"\s+\z").unwrap(); + static ref BLOCK_TAGS: HashSet<&'static str> = [ + "article", + "header", + "aside", + "hgroup", + "blockquote", + "hr", + "iframe", + "body", + "li", + "map", + "button", + "object", + "canvas", + "ol", + "caption", + "output", + "col", + "p", + "colgroup", + "pre", + "dd", + "progress", + "div", + "section", + "dl", + "table", + "td", + "dt", + "tbody", + "embed", + "textarea", + "fieldset", + "tfoot", + "figcaption", + "th", + "figure", + "thead", + "footer", + "tr", + "form", + "ul", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "video", + "script", + "style" + ] + .iter() + .cloned() + .collect(); + static ref WHITESPACE_SENSITIVE_TAGS: HashSet<&'static str> = + ["pre", "code", "h1", "h2", "h3", "h4", "h5", "h6"] + .iter() + .cloned() + .collect(); + static ref TABLE_TAGS: HashSet<&'static str> = ["table", "thead", "tbody", "tr", "td"] + .iter() + .cloned() + .collect(); +} + +fn make_html_parser() -> html::Parser { + html::parse_fragment( + RcDom::default(), + html::ParseOpts::default(), + QualName::new(None, ns!(html), local_name!("div")), + vec![], + ) +} + +fn normalize_html(s: &str) -> String { + let parser = make_html_parser(); + let dom = parser.one(s); + let body: SerializableHandle = normalize_dom(&dom).into(); + let opts = SerializeOpts::default(); + let mut ret_val = Vec::new(); + serialize(&mut ret_val, &body, opts) + .expect("Writing to a string shouldn't fail (expect on OOM)"); + String::from_utf8(ret_val).expect("html5ever should always produce UTF8") +} + +fn normalize_dom(dom: &RcDom) -> Handle { + let body = { + let children = dom.document.children.borrow(); + children[0].clone() + }; + let mut current_level = Vec::new(); + let mut next_level = Vec::new(); + current_level.extend(body.children.borrow().iter().cloned().rev()); + loop { + while let Some(mut node) = current_level.pop() { + let parent = node.parent.replace(None); + node.parent.replace(parent.clone()); + let parent = parent + .expect("a node in the DOM will have a parent, except the root, which is not processed") + .upgrade().expect("a node's parent will be pointed to by its parent (or the root pointer), and will not be dropped"); + let retain = normalize_node(&parent, &mut node); + if !retain { + let mut siblings = parent.children.borrow_mut(); + siblings.retain(|s| !Rc::ptr_eq(&node, s)); + } else { + next_level.extend(node.children.borrow().iter().cloned().rev()); + } + } + if next_level.is_empty() { + break; + }; + mem::swap(&mut next_level, &mut current_level); + } + body +} + +// Returns false if node is an empty text node or an empty tbody. +// Returns true otherwise. +fn normalize_node(parent: &Handle, node: &mut Handle) -> bool { + match node.data { + NodeData::Comment { .. } + | NodeData::Doctype { .. } + | NodeData::Document + | NodeData::ProcessingInstruction { .. } => true, + NodeData::Text { ref contents, .. } => { + let mut contents = contents.borrow_mut(); + let is_pre = { + let mut parent = parent.clone(); + loop { + let is_pre = if let NodeData::Element { ref name, .. } = parent.data { + WHITESPACE_SENSITIVE_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + if is_pre { + break true; + }; + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_ + } else { + break false; + }; + } + }; + if !is_pre { + let (is_first_in_block, is_last_in_block) = { + let mut is_first_in_block = true; + let mut is_last_in_block = true; + let mut parent = parent.clone(); + let mut node = node.clone(); + loop { + let reached_block = if let NodeData::Element { ref name, .. } = parent.data + { + BLOCK_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + let (is_first, is_last) = { + let siblings = parent.children.borrow(); + let n = &node; + ( + siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false), + siblings.len() > 0 + && siblings + .get(siblings.len() - 1) + .map(|s| Rc::ptr_eq(s, n)) + .unwrap_or(false), + ) + }; + is_first_in_block = is_first_in_block && is_first; + is_last_in_block = is_last_in_block && is_last; + if (is_first_in_block || is_last_in_block) && !reached_block { + node = parent.clone(); + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_; + } else { + break (is_first_in_block, is_last_in_block); + } + } else { + break (is_first_in_block, is_last_in_block); + } + } + }; + let is_preceeded_by_ws = { + let mut parent = parent.clone(); + let mut node = node.clone(); + 'ascent: loop { + let is_first = { + let siblings = parent.children.borrow(); + let n = &node; + siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false) + }; + if is_first { + node = parent.clone(); + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_; + } else { + break 'ascent false; + } + } else { + let siblings = parent.children.borrow(); + let n = &node; + let mut pos = !0; + 'search: for (i, s) in siblings.iter().enumerate() { + if Rc::ptr_eq(s, n) { + pos = i; + break 'search; + } + } + assert!( + pos != !0, + "The list of node's parent's children shall contain node" + ); + assert!( + pos != 0, + "If node is not first, then node's position shall not be zero" + ); + let mut preceeding = siblings[pos - 1].clone(); + 'descent: loop { + if let NodeData::Text { .. } = preceeding.data { + break 'descent; + } + preceeding = { + let ch = preceeding.children.borrow(); + if ch.len() == 0 { + break 'descent; + } + if let Some(preceeding_) = ch.get(ch.len() - 1) { + preceeding_.clone() + } else { + break 'descent; + } + }; + } + if let NodeData::Text { ref contents, .. } = preceeding.data { + break 'ascent TRAILING_WHITESPACE_RE.is_match(&*contents.borrow()); + } else { + break 'ascent false; + } + } + } + }; + + let is_in_table = if let NodeData::Element { ref name, .. } = parent.data { + TABLE_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + let whitespace_replacement = if is_in_table { "" } else { " " }; + *contents = WHITESPACE_RE + .replace_all(&*contents, whitespace_replacement) + .as_ref() + .into(); + + if is_first_in_block || is_preceeded_by_ws { + *contents = LEADING_WHITESPACE_RE + .replace_all(&*contents, "") + .as_ref() + .into(); + } + if is_last_in_block { + *contents = TRAILING_WHITESPACE_RE + .replace_all(&*contents, "") + .as_ref() + .into(); + } + // TODO: collapse whitespace when adjacent to whitespace. + // For example, the whitespace in the span should be collapsed in all of these cases: + // + // " q " + // "q q" + // "q q" + // "q q" + // "q q" + } + &**contents != "" + } + NodeData::Element { + ref attrs, + ref name, + .. + } => { + let mut attrs = attrs.borrow_mut(); + for a in attrs.iter_mut() { + a.name.local = a.name.local.to_ascii_lowercase().into(); + } + attrs.sort_by(|a: &html5ever::Attribute, b: &html5ever::Attribute| { + (&*a.name.local).cmp(&*b.name.local) + }); + let ascii_name = &*name.local.to_ascii_lowercase(); + // drop empty tbody's + ascii_name != "tbody" + || node.children.borrow().len() > 1 + || node + .children + .borrow() + .iter() + .next() + .map(|only_child| match only_child.data { + NodeData::Text { ref contents, .. } => { + !contents.borrow().chars().all(|c| c.is_whitespace()) + } + _ => true, + }) + .unwrap_or(false) + } + } +} + +#[test] +fn strip_div_newline() { + assert_eq!("
    ", normalize_html("
    \n
    ")); +} + +#[test] +fn strip_end_newline() { + assert_eq!("test", normalize_html("test\n")); +} + +#[test] +fn strip_double_space() { + assert_eq!("test mess", normalize_html("test mess")); +} + +#[test] +fn strip_inline_internal_text() { + assert_eq!( + "a b c", + normalize_html(" a b c ") + ) +} + +#[test] +fn strip_inline_block_internal_text() { + assert_eq!( + "a b c", + normalize_html(" a b c ") + ) +} + +#[test] +fn leaves_necessary_whitespace_alone() { + assert_eq!("a b c", normalize_html("a b c")) +} + +#[test] +fn leaves_necessary_whitespace_alone_weird() { + assert_eq!( + "a b c", + normalize_html(" a b c") + ) +} + +#[test] +fn leaves_necessary_whitespace_all_nested() { + assert_eq!( + "", + normalize_html(" ") + ) +} + +#[test] +fn drops_empty_tbody() { + assert_eq!( + "
    hi
    ", + normalize_html("
    hi
    ") + ) +} + +#[test] +fn leaves_nonempty_tbody() { + let input = "
    hi
    "; + assert_eq!(input, normalize_html(input)) +} diff --git a/vendor/pulldown-cmark/tests/suite/footnotes.rs b/vendor/pulldown-cmark/tests/suite/footnotes.rs index e31eff54b6..5e5c49bb78 100644 --- a/vendor/pulldown-cmark/tests/suite/footnotes.rs +++ b/vendor/pulldown-cmark/tests/suite/footnotes.rs @@ -1,165 +1,165 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn footnotes_test_1() { - let original = r##"Lorem ipsum.[^a] - -[^a]: Cool. -"##; - let expected = r##"

    Lorem ipsum.1

    -
    1 -

    Cool.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_2() { - let original = r##"> This is the song that never ends.\ -> Yes it goes on and on my friends.[^lambchops] -> -> [^lambchops]: -"##; - let expected = r##"
    -

    This is the song that never ends.
    -Yes it goes on and on my friends.1

    - -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_3() { - let original = r##"Songs that simply loop are a popular way to annoy people. [^examples] - -[^examples]: - * [The song that never ends](https://www.youtube.com/watch?v=0U2zJOryHKQ) - * [I know a song that gets on everybody's nerves](https://www.youtube.com/watch?v=TehWI09qxls) - * [Ninety-nine bottles of beer on the wall](https://www.youtube.com/watch?v=qVjCag8XoHQ) -"##; - let expected = r##"

    Songs that simply loop are a popular way to annoy people. 1

    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_4() { - let original = r##"[^lorem]: If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research. - -I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp. -"##; - let expected = r##"
    1 -

    If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research.

    -
    -

    I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_5() { - let original = r##"[^ipsum]: How much wood would a woodchuck chuck. - -If a woodchuck could chuck wood. - - -# Forms of entertainment that aren't childish -"##; - let expected = r##"
    1 -

    How much wood would a woodchuck chuck.

    -
    -

    If a woodchuck could chuck wood.

    -

    Forms of entertainment that aren't childish

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_6() { - let original = r##"> He's also really stupid. [^why] -> -> [^why]: Because your mamma! - -As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet. -"##; - let expected = r##"
    -

    He's also really stupid. 1

    -
    1 -

    Because your mamma!

    -
    -
    -

    As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_7() { - let original = r##"Nested footnotes are considered poor style. [^a] [^xkcd] - -[^a]: This does not mean that footnotes cannot reference each other. [^b] - -[^b]: This means that a footnote definition cannot be directly inside another footnote definition. -> This means that a footnote cannot be directly inside another footnote's body. [^e] -> -> [^e]: They can, however, be inside anything else. - -[^xkcd]: [The other kind of nested footnote is, however, considered poor style.](https://xkcd.com/1208/) -"##; - let expected = r##"

    Nested footnotes are considered poor style. 1 2

    -
    1 -

    This does not mean that footnotes cannot reference each other. 3

    -
    -
    3 -

    This means that a footnote definition cannot be directly inside another footnote definition.

    -
    -

    This means that a footnote cannot be directly inside another footnote's body. 4

    -
    4 -

    They can, however, be inside anything else.

    -
    -
    -
    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_8() { - let original = r##"[^Doh] Ray Me Fa So La Te Do! [^1] - -[^Doh]: I know. Wrong Doe. And it won't render right. -[^1]: Common for people practicing music. -"##; - let expected = r##"

    1 Ray Me Fa So La Te Do! 2

    -
    1 -

    I know. Wrong Doe. And it won't render right. -2: Common for people practicing music.

    -
    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn footnotes_test_1() { + let original = r##"Lorem ipsum.[^a] + +[^a]: Cool. +"##; + let expected = r##"

    Lorem ipsum.1

    +
    1 +

    Cool.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_2() { + let original = r##"> This is the song that never ends.\ +> Yes it goes on and on my friends.[^lambchops] +> +> [^lambchops]: +"##; + let expected = r##"
    +

    This is the song that never ends.
    +Yes it goes on and on my friends.1

    + +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_3() { + let original = r##"Songs that simply loop are a popular way to annoy people. [^examples] + +[^examples]: + * [The song that never ends](https://www.youtube.com/watch?v=0U2zJOryHKQ) + * [I know a song that gets on everybody's nerves](https://www.youtube.com/watch?v=TehWI09qxls) + * [Ninety-nine bottles of beer on the wall](https://www.youtube.com/watch?v=qVjCag8XoHQ) +"##; + let expected = r##"

    Songs that simply loop are a popular way to annoy people. 1

    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_4() { + let original = r##"[^lorem]: If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research. + +I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp. +"##; + let expected = r##"
    1 +

    If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research.

    +
    +

    I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_5() { + let original = r##"[^ipsum]: How much wood would a woodchuck chuck. + +If a woodchuck could chuck wood. + + +# Forms of entertainment that aren't childish +"##; + let expected = r##"
    1 +

    How much wood would a woodchuck chuck.

    +
    +

    If a woodchuck could chuck wood.

    +

    Forms of entertainment that aren't childish

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_6() { + let original = r##"> He's also really stupid. [^why] +> +> [^why]: Because your mamma! + +As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet. +"##; + let expected = r##"
    +

    He's also really stupid. 1

    +
    1 +

    Because your mamma!

    +
    +
    +

    As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_7() { + let original = r##"Nested footnotes are considered poor style. [^a] [^xkcd] + +[^a]: This does not mean that footnotes cannot reference each other. [^b] + +[^b]: This means that a footnote definition cannot be directly inside another footnote definition. +> This means that a footnote cannot be directly inside another footnote's body. [^e] +> +> [^e]: They can, however, be inside anything else. + +[^xkcd]: [The other kind of nested footnote is, however, considered poor style.](https://xkcd.com/1208/) +"##; + let expected = r##"

    Nested footnotes are considered poor style. 1 2

    +
    1 +

    This does not mean that footnotes cannot reference each other. 3

    +
    +
    3 +

    This means that a footnote definition cannot be directly inside another footnote definition.

    +
    +

    This means that a footnote cannot be directly inside another footnote's body. 4

    +
    4 +

    They can, however, be inside anything else.

    +
    +
    +
    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_8() { + let original = r##"[^Doh] Ray Me Fa So La Te Do! [^1] + +[^Doh]: I know. Wrong Doe. And it won't render right. +[^1]: Common for people practicing music. +"##; + let expected = r##"

    1 Ray Me Fa So La Te Do! 2

    +
    1 +

    I know. Wrong Doe. And it won't render right. +2: Common for people practicing music.

    +
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/gfm_strikethrough.rs b/vendor/pulldown-cmark/tests/suite/gfm_strikethrough.rs index b8fd293980..92413c3068 100644 --- a/vendor/pulldown-cmark/tests/suite/gfm_strikethrough.rs +++ b/vendor/pulldown-cmark/tests/suite/gfm_strikethrough.rs @@ -1,27 +1,27 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn gfm_strikethrough_test_1() { - let original = r##"~~Hi~~ Hello, world! -"##; - let expected = r##"

    Hi Hello, world!

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_strikethrough_test_2() { - let original = r##"This ~~has a - -new paragraph~~. -"##; - let expected = r##"

    This ~~has a

    -

    new paragraph~~.

    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_strikethrough_test_1() { + let original = r##"~~Hi~~ Hello, world! +"##; + let expected = r##"

    Hi Hello, world!

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_strikethrough_test_2() { + let original = r##"This ~~has a + +new paragraph~~. +"##; + let expected = r##"

    This ~~has a

    +

    new paragraph~~.

    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/gfm_table.rs b/vendor/pulldown-cmark/tests/suite/gfm_table.rs index 0e286b6b77..8ffadbd62e 100644 --- a/vendor/pulldown-cmark/tests/suite/gfm_table.rs +++ b/vendor/pulldown-cmark/tests/suite/gfm_table.rs @@ -1,205 +1,205 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn gfm_table_test_1() { - let original = r##"| foo | bar | -| --- | --- | -| baz | bim | -"##; - let expected = r##" - - - - - - - - - - - - -
    foobar
    bazbim
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_2() { - let original = r##"| abc | defghi | -:-: | -----------: -bar | baz -"##; - let expected = r##" - - - - - - - - - - - - -
    abcdefghi
    barbaz
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_3() { - let original = r##"| f\|oo | -| ------ | -| b `\|` az | -| b **\|** im | -"##; - let expected = r##" - - - - - - - - - - - - - -
    f|oo
    b \| az
    b | im
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_4() { - let original = r##"| abc | def | -| --- | --- | -| bar | baz | -> bar -"##; - let expected = r##" - - - - - - - - - - - - -
    abcdef
    barbaz
    -
    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_5() { - let original = r##"| abc | def | -| --- | --- | -| bar | baz | -bar - -bar -"##; - let expected = r##" - - - - - - - - - - - - - - - - -
    abcdef
    barbaz
    bar
    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_6() { - let original = r##"| abc | def | -| --- | -| bar | -"##; - let expected = r##"

    | abc | def | -| --- | -| bar |

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_7() { - let original = r##"| abc | def | -| --- | --- | -| bar | -| bar | baz | boo | -"##; - let expected = r##" - - - - - - - - - - - - - - - - -
    abcdef
    bar
    barbaz
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_8() { - let original = r##"| abc | def | -| --- | --- | -"##; - let expected = r##" - - - - - - -
    abcdef
    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_table_test_1() { + let original = r##"| foo | bar | +| --- | --- | +| baz | bim | +"##; + let expected = r##" + + + + + + + + + + + + +
    foobar
    bazbim
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_2() { + let original = r##"| abc | defghi | +:-: | -----------: +bar | baz +"##; + let expected = r##" + + + + + + + + + + + + +
    abcdefghi
    barbaz
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_3() { + let original = r##"| f\|oo | +| ------ | +| b `\|` az | +| b **\|** im | +"##; + let expected = r##" + + + + + + + + + + + + + +
    f|oo
    b \| az
    b | im
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_4() { + let original = r##"| abc | def | +| --- | --- | +| bar | baz | +> bar +"##; + let expected = r##" + + + + + + + + + + + + +
    abcdef
    barbaz
    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_5() { + let original = r##"| abc | def | +| --- | --- | +| bar | baz | +bar + +bar +"##; + let expected = r##" + + + + + + + + + + + + + + + + +
    abcdef
    barbaz
    bar
    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_6() { + let original = r##"| abc | def | +| --- | +| bar | +"##; + let expected = r##"

    | abc | def | +| --- | +| bar |

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_7() { + let original = r##"| abc | def | +| --- | --- | +| bar | +| bar | baz | boo | +"##; + let expected = r##" + + + + + + + + + + + + + + + + +
    abcdef
    bar
    barbaz
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_8() { + let original = r##"| abc | def | +| --- | --- | +"##; + let expected = r##" + + + + + + +
    abcdef
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/gfm_tasklist.rs b/vendor/pulldown-cmark/tests/suite/gfm_tasklist.rs index ca80369f99..2962d545b7 100644 --- a/vendor/pulldown-cmark/tests/suite/gfm_tasklist.rs +++ b/vendor/pulldown-cmark/tests/suite/gfm_tasklist.rs @@ -1,39 +1,39 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn gfm_tasklist_test_1() { - let original = r##"- [ ] foo -- [x] bar -"##; - let expected = r##"
      -
    • foo
    • -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_tasklist_test_2() { - let original = r##"- [x] foo - - [ ] bar - - [x] baz -- [ ] bim -"##; - let expected = r##"
      -
    • foo -
        -
      • bar
      • -
      • baz
      • -
      -
    • -
    • bim
    • -
    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_tasklist_test_1() { + let original = r##"- [ ] foo +- [x] bar +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_tasklist_test_2() { + let original = r##"- [x] foo + - [ ] bar + - [x] baz +- [ ] bim +"##; + let expected = r##"
      +
    • foo +
        +
      • bar
      • +
      • baz
      • +
      +
    • +
    • bim
    • +
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/mod.rs b/vendor/pulldown-cmark/tests/suite/mod.rs index aa05206085..b355328a0b 100644 --- a/vendor/pulldown-cmark/tests/suite/mod.rs +++ b/vendor/pulldown-cmark/tests/suite/mod.rs @@ -1,12 +1,13 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -pub use super::test_markdown_html; - -mod footnotes; -mod regression; -mod table; -mod spec; -mod gfm_table; -mod gfm_strikethrough; -mod gfm_tasklist; +// This file is auto-generated by the build script +// Please, do not modify it manually + +pub use super::test_markdown_html; + +mod footnotes; +mod gfm_strikethrough; +mod gfm_table; +mod gfm_tasklist; +mod regression; +mod smart_punct; +mod spec; +mod table; diff --git a/vendor/pulldown-cmark/tests/suite/regression.rs b/vendor/pulldown-cmark/tests/suite/regression.rs index 5c723aacf1..722f0555c4 100644 --- a/vendor/pulldown-cmark/tests/suite/regression.rs +++ b/vendor/pulldown-cmark/tests/suite/regression.rs @@ -1,904 +1,953 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn regression_test_1() { - let original = r##"
    Testing 1..2..3.. - -This is a test of the details element. - -
    -"##; - let expected = r##"
    Testing 1..2..3.. -

    This is a test of the details element.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_2() { - let original = r##"see the [many] [articles] [on] [QuickCheck]. - -[many]: https://medium.com/@jlouis666/quickcheck-advice-c357efb4e7e6 -[articles]: http://www.quviq.com/products/erlang-quickcheck/ -[on]: https://wiki.haskell.org/Introduction_to_QuickCheck1 -[QuickCheck]: https://hackage.haskell.org/package/QuickCheck -"##; - let expected = r##"

    see the - many - articles - on - QuickCheck. -

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_3() { - let original = r##"[![debug-stub-derive on crates.io][cratesio-image]][cratesio] -[![debug-stub-derive on docs.rs][docsrs-image]][docsrs] - -[cratesio-image]: https://img.shields.io/crates/v/debug_stub_derive.svg -[cratesio]: https://crates.io/crates/debug_stub_derive -[docsrs-image]: https://docs.rs/debug_stub_derive/badge.svg?version=0.3.0 -[docsrs]: https://docs.rs/debug_stub_derive/0.3.0/ -"##; - let expected = r##"

    debug-stub-derive on crates.io -debug-stub-derive on docs.rs

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_4() { - let original = r##"| Title A | Title B | -| --------- | --------- | -| Content | Content | - -| Title A | Title B | Title C | Title D | -| --------- | --------- | --------- | ---------:| -| Content | Content | Conent | Content | -"##; - let expected = r##" - -
    Title A Title B
    Content Content
    - - -
    Title A Title B Title C Title D
    Content Content Conent Content
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_5() { - let original = r##"foo§__(bar)__ -"##; - let expected = r##"

    foo§(bar)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_6() { - let original = r##" hello -"##; - let expected = r##"

    https://example.com hello

    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_7() { - let original = r##"[foo][bar] - - -[bar]: a -"##; - let expected = r##"

    foo

    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_8() { - let original = r##" -- **foo** (u8, u8) - - make something - -- **bar** (u16, u16) - - make something -"##; - let expected = r##" -
      -
    • -

      foo (u8, u8)

      -

      make something

      -
    • -
    • -

      bar (u16, u16)

      -

      make something

      -
    • -
    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_9() { - let original = r##"[` -i8 -`]( -../../../std/primitive.i8.html -) -"##; - let expected = r##"

    i8

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_10() { - let original = r##"[a] - -[a]: /url (title\\*) -"##; - let expected = r##"

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_11() { - let original = r##"[a] - -[a]: /url (title\)) -"##; - let expected = r##"

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_12() { - let original = r##"[a] - -[a]: /url (title)) -"##; - let expected = r##"

    [a]

    -

    [a]: /url (title))

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_13() { - let original = r##"a -"##; - let expected = r##"

    a <?php this is not a valid processing tag

    -

    b

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_14() { - let original = r##"[a]: u\ -foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_15() { - let original = r##"\`foo` -"##; - let expected = r##"

    `foo`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_16() { - let original = r##"foo\\ -bar -"##; - let expected = r##"

    foo\ -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_17() { - let original = r##"1\. foo - -1\) bar -"##; - let expected = r##"

    1. foo

    -

    1) bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_18() { - let original = r##"1... - -1.2.3. - -1 2 3 . - -1.|2.-3. - -1)2)3) -"##; - let expected = r##"

    1...

    -

    1.2.3.

    -

    1 2 3 .

    -

    1.|2.-3.

    -

    1)2)3)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_19() { - let original = r##"[](<<>) -"##; - let expected = r##"

    [](<<>)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_20() { - let original = r##"\``foo``bar` -"##; - let expected = r##"

    `foo``bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_21() { - let original = r##"\\`foo` -"##; - let expected = r##"

    \foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_22() { - let original = r##"[\\]: x - -YOLO -"##; - let expected = r##"

    YOLO

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_23() { - let original = r##"lorem ipsum -A | B ----|--- -foo | bar -"##; - let expected = r##"

    lorem ipsum -A | B ----|--- -foo | bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_24() { - let original = r##"foo|bar ----|--- -foo|bar -"##; - let expected = r##" - -
    foobar
    foobar
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_25() { - let original = r##"foo|bar\\ ----|--- -foo|bar -"##; - let expected = r##" - -
    foobar\
    foobar
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_26() { - let original = r##"[](url) -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_27() { - let original = r##"[bar](url) -"##; - let expected = r##"

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_28() { - let original = r##"![](http://example.com/logo.png) -"##; - let expected = r##"

    http://example.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_29() { - let original = r##"[ ](url) -"##; - let expected = r##"

    http://one http://two

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_30() { - let original = r##"Markdown | Less | Pretty ---- | --- | --- - -some text -"##; - let expected = r##" -
    Markdown Less Pretty
    -

    some text

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_31() { - let original = r##"1. > foo -2. > -"##; - let expected = r##"
      -
    1. -
      -

      foo

      -
      -
    2. -
    3. -
      -
      -
    4. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_32() { - let original = r##"[ -x - -]: f -"##; - let expected = r##"

    [ -x

    -

    ]: f

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_33() { - let original = r##"[foo]: -"##; - let expected = r##"

    [foo]:

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_34() { - let original = r##"> foo | bar -> --- | --- -yolo | swag -"##; - let expected = r##"
    -
    foobar
    -
    -

    yolo | swag

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_35() { - let original = r##" -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_36() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_37() { - let original = r##"~~*_**__ - -__a__ -"##; - let expected = r##"

    ~~*_**__

    -

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_38() { - let original = r##"> ` -> ` -"##; - let expected = r##"
    -

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_39() { - let original = r##"`\|` -"##; - let expected = r##"

    \|

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_40() { - let original = r##"Paragraph 1 - -Paragraph 2 -"##; - let expected = r##"

    Paragraph 1

    -

    Paragraph 2

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_41() { - let original = r##"\[[link text](https://www.google.com/)\] -"##; - let expected = r##"

    [link text]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_42() { - let original = r##"foo | bar ---- | --- -[a](< | url>) -"##; - let expected = r##"
    foobar
    [a](<url>)
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_43() { - let original = r##"[a](url " -- - - -") -"##; - let expected = r##"

    [a](url "

    -
    -

    ")

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_44() { - let original = r##"[a](url - -) -"##; - let expected = r##"

    [a](url

    -

    )

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_45() { - let original = r##"[a](b " - -") -"##; - let expected = r##"

    [a](b "

    -

    ")

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_46() { - let original = r##" -"##; - let expected = r##"

    <http:// >

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_47() { - let original = r##" -"##; - let expected = r##"

    <http://>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_48() { - let original = r##"foo | bar ---- | --- - - -foobar - - -<http://baz - - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_49() { - let original = r##"foo | bar ---- | --- - -"##; - let expected = r##" - - - - - - -
    foobar
    <http://>
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_50() { - let original = r##"\*hi\_ -"##; - let expected = r##"

    *hi_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_51() { - let original = r##"email: \_ -"##; - let expected = r##"

    email: john@example.com_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_52() { - let original = r##"> [link](/url 'foo -> bar') -"##; - let expected = r##"
    -

    link

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_53() { - let original = r##"> [foo -> bar]: /url -> -> [foo bar] -"##; - let expected = r##"
    -

    foo bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_54() { - let original = r##"> [foo bar]: /url -> -> [foo -> bar] -"##; - let expected = r##"
    -

    foo -bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_55() { - let original = r##"> - [a -> b c]: /foo - -[a b c] -"##; - let expected = r##"
    -
      -
    • -
    -
    -

    a b c

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_56() { - let original = r##"[a -> b]: /foo - -[a b] [a > b] -"##; - let expected = r##"

    [a

    -
    -

    b]: /foo

    -
    -

    [a b] [a > b]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_57() { - let original = r##"[`cargo -package`] - -[`cargo package`]: https://example.com -"##; - let expected = r##"

    cargo package

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_58() { - let original = r##"> [`cargo -> package`] - -[`cargo package`]: https://example.com -"##; - let expected = r##"
    -

    cargo package

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_59() { - let original = r##"> `cargo -> package` -"##; - let expected = r##"
    -

    cargo package

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_60() { - let original = r##"Lorem ipsum.[^a] - -An unordered list before the footnotes: -* Ipsum -* Lorem - -[^a]: Cool. -"##; - let expected = r##"

    Lorem ipsum.1

    -

    An unordered list before the footnotes:

    -
      -
    • Ipsum
    • -
    • Lorem
    • -
    -
    1 -

    Cool.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_61() { - let original = r##"[][a] - -[a]: b - -# assimp-rs [![][crates-badge]][crates] - -[crates]: https://crates.io/crates/assimp -[crates-badge]: http://meritbadge.herokuapp.com/assimp -"##; - let expected = r##"

    - -

    assimp-rs

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_62() { - let original = r##"* A list. - - * A sublist. - - * Another sublist. - - -* A list. - - * A sublist. - - * Another sublist. - -"##; - let expected = r##"
      -
    • -

      A list.

      -
        -
      • -

        A sublist.

        -
      • -
      • -

        Another sublist.

        -
      • -
      -
    • -
    • -

      A list.

      -
        -
      • -

        A sublist.

        -
      • -
      • -

        Another sublist.

        -
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_63() { - let original = r##"<foo

    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn regression_test_1() { + let original = r##"
    Testing 1..2..3.. + +This is a test of the details element. + +
    +"##; + let expected = r##"
    Testing 1..2..3.. +

    This is a test of the details element.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_2() { + let original = r##"see the [many] [articles] [on] [QuickCheck]. + +[many]: https://medium.com/@jlouis666/quickcheck-advice-c357efb4e7e6 +[articles]: http://www.quviq.com/products/erlang-quickcheck/ +[on]: https://wiki.haskell.org/Introduction_to_QuickCheck1 +[QuickCheck]: https://hackage.haskell.org/package/QuickCheck +"##; + let expected = r##"

    see the + many + articles + on + QuickCheck. +

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_3() { + let original = r##"[![debug-stub-derive on crates.io][cratesio-image]][cratesio] +[![debug-stub-derive on docs.rs][docsrs-image]][docsrs] + +[cratesio-image]: https://img.shields.io/crates/v/debug_stub_derive.svg +[cratesio]: https://crates.io/crates/debug_stub_derive +[docsrs-image]: https://docs.rs/debug_stub_derive/badge.svg?version=0.3.0 +[docsrs]: https://docs.rs/debug_stub_derive/0.3.0/ +"##; + let expected = r##"

    debug-stub-derive on crates.io +debug-stub-derive on docs.rs

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_4() { + let original = r##"| Title A | Title B | +| --------- | --------- | +| Content | Content | + +| Title A | Title B | Title C | Title D | +| --------- | --------- | --------- | ---------:| +| Content | Content | Conent | Content | +"##; + let expected = r##" + +
    Title A Title B
    Content Content
    + + +
    Title A Title B Title C Title D
    Content Content Conent Content
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_5() { + let original = r##"foo§__(bar)__ +"##; + let expected = r##"

    foo§(bar)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_6() { + let original = r##" hello +"##; + let expected = r##"

    https://example.com hello

    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_7() { + let original = r##"[foo][bar] + + +[bar]: a +"##; + let expected = r##"

    foo

    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_8() { + let original = r##" +- **foo** (u8, u8) + + make something + +- **bar** (u16, u16) + + make something +"##; + let expected = r##" +
      +
    • +

      foo (u8, u8)

      +

      make something

      +
    • +
    • +

      bar (u16, u16)

      +

      make something

      +
    • +
    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_9() { + let original = r##"[` +i8 +`]( +../../../std/primitive.i8.html +) +"##; + let expected = r##"

    i8

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_10() { + let original = r##"[a] + +[a]: /url (title\\*) +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_11() { + let original = r##"[a] + +[a]: /url (title\)) +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_12() { + let original = r##"[a] + +[a]: /url (title)) +"##; + let expected = r##"

    [a]

    +

    [a]: /url (title))

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_13() { + let original = r##"a +"##; + let expected = r##"

    a <?php this is not a valid processing tag

    +

    b

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_14() { + let original = r##"[a]: u\ +foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_15() { + let original = r##"\`foo` +"##; + let expected = r##"

    `foo`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_16() { + let original = r##"foo\\ +bar +"##; + let expected = r##"

    foo\ +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_17() { + let original = r##"1\. foo + +1\) bar +"##; + let expected = r##"

    1. foo

    +

    1) bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_18() { + let original = r##"1... + +1.2.3. + +1 2 3 . + +1.|2.-3. + +1)2)3) +"##; + let expected = r##"

    1...

    +

    1.2.3.

    +

    1 2 3 .

    +

    1.|2.-3.

    +

    1)2)3)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_19() { + let original = r##"[](<<>) +"##; + let expected = r##"

    [](<<>)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_20() { + let original = r##"\``foo``bar` +"##; + let expected = r##"

    `foo``bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_21() { + let original = r##"\\`foo` +"##; + let expected = r##"

    \foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_22() { + let original = r##"[\\]: x + +YOLO +"##; + let expected = r##"

    YOLO

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_23() { + let original = r##"lorem ipsum +A | B +---|--- +foo | bar +"##; + let expected = r##"

    lorem ipsum +A | B +---|--- +foo | bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_24() { + let original = r##"foo|bar +---|--- +foo|bar +"##; + let expected = r##" + +
    foobar
    foobar
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_25() { + let original = r##"foo|bar\\ +---|--- +foo|bar +"##; + let expected = r##" + +
    foobar\
    foobar
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_26() { + let original = r##"[](url) +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_27() { + let original = r##"[bar](url) +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_28() { + let original = r##"![](http://example.com/logo.png) +"##; + let expected = r##"

    http://example.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_29() { + let original = r##"[ ](url) +"##; + let expected = r##"

    http://one http://two

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_30() { + let original = r##"Markdown | Less | Pretty +--- | --- | --- + +some text +"##; + let expected = r##" +
    Markdown Less Pretty
    +

    some text

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_31() { + let original = r##"1. > foo +2. > +"##; + let expected = r##"
      +
    1. +
      +

      foo

      +
      +
    2. +
    3. +
      +
      +
    4. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_32() { + let original = r##"[ +x + +]: f +"##; + let expected = r##"

    [ +x

    +

    ]: f

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_33() { + let original = r##"[foo]: +"##; + let expected = r##"

    [foo]:

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_34() { + let original = r##"> [foo +> bar]: /url +> +> [foo bar] +"##; + let expected = r##"
    +

    foo bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_35() { + let original = r##"> foo | bar +> --- | --- +yolo | swag +"##; + let expected = r##"
    +
    foobar
    +
    +

    yolo | swag

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_36() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_37() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_38() { + let original = r##"~~*_**__ + +__a__ +"##; + let expected = r##"

    ~~*_**__

    +

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_39() { + let original = r##"> ` +> ` +"##; + let expected = r##"
    +

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_40() { + let original = r##"`\|` +"##; + let expected = r##"

    \|

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_41() { + let original = r##"Paragraph 1 + +Paragraph 2 +"##; + let expected = r##"

    Paragraph 1

    +

    Paragraph 2

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_42() { + let original = r##"\[[link text](https://www.google.com/)\] +"##; + let expected = r##"

    [link text]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_43() { + let original = r##"foo | bar +--- | --- +[a](< | url>) +"##; + let expected = r##"
    foobar
    [a](<url>)
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_44() { + let original = r##"[a](url " +- - - +") +"##; + let expected = r##"

    [a](url "

    +
    +

    ")

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_45() { + let original = r##"[a](url + +) +"##; + let expected = r##"

    [a](url

    +

    )

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_46() { + let original = r##"[a](b " + +") +"##; + let expected = r##"

    [a](b "

    +

    ")

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_47() { + let original = r##" +"##; + let expected = r##"

    <http:// >

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_48() { + let original = r##" +"##; + let expected = r##"

    <http://>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_49() { + let original = r##"foo | bar +--- | --- + + +foobar + + +<http://baz + + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_50() { + let original = r##"foo | bar +--- | --- + +"##; + let expected = r##" + + + + + + +
    foobar
    <http://>
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_51() { + let original = r##"\*hi\_ +"##; + let expected = r##"

    *hi_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_52() { + let original = r##"email: \_ +"##; + let expected = r##"

    email: john@example.com_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_53() { + let original = r##"> [link](/url 'foo +> bar') +"##; + let expected = r##"
    +

    link

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_54() { + let original = r##"> [foo +> bar]: /url +> +> [foo bar] +"##; + let expected = r##"
    +

    foo bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_55() { + let original = r##"> [foo bar]: /url +> +> [foo +> bar] +"##; + let expected = r##"
    +

    foo +bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_56() { + let original = r##"> - [a +> b c]: /foo + +[a b c] +"##; + let expected = r##"
    +
      +
    • +
    +
    +

    a b c

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_57() { + let original = r##"[a +> b]: /foo + +[a b] [a > b] +"##; + let expected = r##"

    [a

    +
    +

    b]: /foo

    +
    +

    [a b] [a > b]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_58() { + let original = r##"[`cargo +package`] + +[`cargo package`]: https://example.com +"##; + let expected = r##"

    cargo package

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_59() { + let original = r##"> [`cargo +> package`] + +[`cargo package`]: https://example.com +"##; + let expected = r##"
    +

    cargo package

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_60() { + let original = r##"> `cargo +> package` +"##; + let expected = r##"
    +

    cargo package

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_61() { + let original = r##"> Note: Though you should not rely on this, all pointers to title="Dynamically Sized Types">DSTs are currently twice the size of +> the size of `usize` and have the same alignment. +"##; + let expected = r##"
    +

    Note: Though you should not rely on this, all pointers to +DSTs are currently twice the size of +the size of usize and have the same alignment.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_62() { + let original = r##"Lorem ipsum.[^a] + +An unordered list before the footnotes: +* Ipsum +* Lorem + +[^a]: Cool. +"##; + let expected = r##"

    Lorem ipsum.1

    +

    An unordered list before the footnotes:

    +
      +
    • Ipsum
    • +
    • Lorem
    • +
    +
    1 +

    Cool.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_63() { + let original = r##"[][a] + +[a]: b + +# assimp-rs [![][crates-badge]][crates] + +[crates]: https://crates.io/crates/assimp +[crates-badge]: http://meritbadge.herokuapp.com/assimp +"##; + let expected = r##"

    + +

    assimp-rs

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_64() { + let original = r##"* A list. + + * A sublist. + + * Another sublist. + + +* A list. + + * A sublist. + + * Another sublist. + +"##; + let expected = r##"
      +
    • +

      A list.

      +
        +
      • +

        A sublist.

        +
      • +
      • +

        Another sublist.

        +
      • +
      +
    • +
    • +

      A list.

      +
        +
      • +

        A sublist.

        +
      • +
      • +

        Another sublist.

        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_65() { + let original = r##"<foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_66() { + let original = r##"> > a > ="yo +> > lo"> +"##; + let expected = r##"
    +
    +

    a

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/smart_punct.rs b/vendor/pulldown-cmark/tests/suite/smart_punct.rs new file mode 100644 index 0000000000..62681b6489 --- /dev/null +++ b/vendor/pulldown-cmark/tests/suite/smart_punct.rs @@ -0,0 +1,201 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn smart_punct_test_1() { + let original = r##""Hello," said the spider. +"'Shelob' is my name." +"##; + let expected = r##"

    “Hello,” said the spider. +“‘Shelob’ is my name.”

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_2() { + let original = r##"'A', 'B', and 'C' are letters. +"##; + let expected = r##"

    ‘A’, ‘B’, and ‘C’ are letters.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_3() { + let original = r##"'Oak,' 'elm,' and 'beech' are names of trees. +So is 'pine.' +"##; + let expected = r##"

    ‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. +So is ‘pine.’

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_4() { + let original = r##"'He said, "I want to go."' +"##; + let expected = r##"

    ‘He said, “I want to go.”’

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_5() { + let original = r##"Were you alive in the 70's? +"##; + let expected = r##"

    Were you alive in the 70’s?

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_6() { + let original = r##"Here is some quoted '`code`' and a "[quoted link](url)". +"##; + let expected = r##"

    Here is some quoted ‘code’ and a “quoted link”.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_7() { + let original = r##"'tis the season to be 'jolly' +"##; + let expected = r##"

    ’tis the season to be ‘jolly’

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_8() { + let original = r##"'We'll use Jane's boat and John's truck,' Jenna said. +"##; + let expected = r##"

    ‘We’ll use Jane’s boat and John’s truck,’ Jenna said.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_9() { + let original = r##""A paragraph with no closing quote. + +"Second paragraph by same speaker, in fiction." +"##; + let expected = r##"

    “A paragraph with no closing quote.

    +

    “Second paragraph by same speaker, in fiction.”

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_10() { + let original = r##"[a]'s b' +"##; + let expected = r##"

    [a]’s b’

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_11() { + let original = r##"\"This is not smart.\" +This isn\'t either. +5\'8\" +"##; + let expected = r##"

    "This is not smart." +This isn't either. +5'8"

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_12() { + let original = r##"Some dashes: em---em +en--en +em --- em +en -- en +2--3 +"##; + let expected = r##"

    Some dashes: em—em +en–en +em — em +en – en +2–3

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_13() { + let original = r##"one- +two-- +three--- +four---- +five----- +six------ +seven------- +eight-------- +nine--------- +thirteen-------------. +"##; + let expected = r##"

    one- +two– +three— +four–– +five—– +six—— +seven—–– +eight–––– +nine——— +thirteen———––.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_14() { + let original = r##"Escaped hyphens: \-- \-\-\-. +"##; + let expected = r##"

    Escaped hyphens: -- ---.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_15() { + let original = r##"Ellipses...and...and.... +"##; + let expected = r##"

    Ellipses…and…and….

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_16() { + let original = r##"No ellipses\.\.\. +"##; + let expected = r##"

    No ellipses...

    +"##; + + test_markdown_html(original, expected, true); +} diff --git a/vendor/pulldown-cmark/tests/suite/spec.rs b/vendor/pulldown-cmark/tests/suite/spec.rs index 0215dd4b89..6a3f4d9dfc 100644 --- a/vendor/pulldown-cmark/tests/suite/spec.rs +++ b/vendor/pulldown-cmark/tests/suite/spec.rs @@ -1,8447 +1,8447 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn spec_test_1() { - let original = r##" foo baz bim -"##; - let expected = r##"
    foo	baz		bim
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_2() { - let original = r##" foo baz bim -"##; - let expected = r##"
    foo	baz		bim
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_3() { - let original = r##" a a - ὐ a -"##; - let expected = r##"
    a	a
    -ὐ	a
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_4() { - let original = r##" - foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -

      bar

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_5() { - let original = r##"- foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -
        bar
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_6() { - let original = r##"> foo -"##; - let expected = r##"
    -
      foo
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_7() { - let original = r##"- foo -"##; - let expected = r##"
      -
    • -
        foo
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_8() { - let original = r##" foo - bar -"##; - let expected = r##"
    foo
    -bar
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_9() { - let original = r##" - foo - - bar - - baz -"##; - let expected = r##"
      -
    • foo -
        -
      • bar -
          -
        • baz
        • -
        -
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_10() { - let original = r##"# Foo -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_11() { - let original = r##"* * * -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_12() { - let original = r##"- `one -- two` -"##; - let expected = r##"
      -
    • `one
    • -
    • two`
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_13() { - let original = r##"*** ---- -___ -"##; - let expected = r##"
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_14() { - let original = r##"+++ -"##; - let expected = r##"

    +++

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_15() { - let original = r##"=== -"##; - let expected = r##"

    ===

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_16() { - let original = r##"-- -** -__ -"##; - let expected = r##"

    -- -** -__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_17() { - let original = r##" *** - *** - *** -"##; - let expected = r##"
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_18() { - let original = r##" *** -"##; - let expected = r##"
    ***
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_19() { - let original = r##"Foo - *** -"##; - let expected = r##"

    Foo -***

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_20() { - let original = r##"_____________________________________ -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_21() { - let original = r##" - - - -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_22() { - let original = r##" ** * ** * ** * ** -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_23() { - let original = r##"- - - - -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_24() { - let original = r##"- - - - -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_25() { - let original = r##"_ _ _ _ a - -a------ - ----a--- -"##; - let expected = r##"

    _ _ _ _ a

    -

    a------

    -

    ---a---

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_26() { - let original = r##" *-* -"##; - let expected = r##"

    -

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_27() { - let original = r##"- foo -*** -- bar -"##; - let expected = r##"
      -
    • foo
    • -
    -
    -
      -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_28() { - let original = r##"Foo -*** -bar -"##; - let expected = r##"

    Foo

    -
    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_29() { - let original = r##"Foo ---- -bar -"##; - let expected = r##"

    Foo

    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_30() { - let original = r##"* Foo -* * * -* Bar -"##; - let expected = r##"
      -
    • Foo
    • -
    -
    -
      -
    • Bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_31() { - let original = r##"- Foo -- * * * -"##; - let expected = r##"
      -
    • Foo
    • -
    • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_32() { - let original = r##"# foo -## foo -### foo -#### foo -##### foo -###### foo -"##; - let expected = r##"

    foo

    -

    foo

    -

    foo

    -

    foo

    -
    foo
    -
    foo
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_33() { - let original = r##"####### foo -"##; - let expected = r##"

    ####### foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_34() { - let original = r##"#5 bolt - -#hashtag -"##; - let expected = r##"

    #5 bolt

    -

    #hashtag

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_35() { - let original = r##"\## foo -"##; - let expected = r##"

    ## foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_36() { - let original = r##"# foo *bar* \*baz\* -"##; - let expected = r##"

    foo bar *baz*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_37() { - let original = r##"# foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_38() { - let original = r##" ### foo - ## foo - # foo -"##; - let expected = r##"

    foo

    -

    foo

    -

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_39() { - let original = r##" # foo -"##; - let expected = r##"
    # foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_40() { - let original = r##"foo - # bar -"##; - let expected = r##"

    foo -# bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_41() { - let original = r##"## foo ## - ### bar ### -"##; - let expected = r##"

    foo

    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_42() { - let original = r##"# foo ################################## -##### foo ## -"##; - let expected = r##"

    foo

    -
    foo
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_43() { - let original = r##"### foo ### -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_44() { - let original = r##"### foo ### b -"##; - let expected = r##"

    foo ### b

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_45() { - let original = r##"# foo# -"##; - let expected = r##"

    foo#

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_46() { - let original = r##"### foo \### -## foo #\## -# foo \# -"##; - let expected = r##"

    foo ###

    -

    foo ###

    -

    foo #

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_47() { - let original = r##"**** -## foo -**** -"##; - let expected = r##"
    -

    foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_48() { - let original = r##"Foo bar -# baz -Bar foo -"##; - let expected = r##"

    Foo bar

    -

    baz

    -

    Bar foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_49() { - let original = r##"## -# -### ### -"##; - let expected = r##"

    -

    -

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_50() { - let original = r##"Foo *bar* -========= - -Foo *bar* ---------- -"##; - let expected = r##"

    Foo bar

    -

    Foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_51() { - let original = r##"Foo *bar -baz* -==== -"##; - let expected = r##"

    Foo bar -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_52() { - let original = r##" Foo *bar -baz* -==== -"##; - let expected = r##"

    Foo bar -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_53() { - let original = r##"Foo -------------------------- - -Foo -= -"##; - let expected = r##"

    Foo

    -

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_54() { - let original = r##" Foo ---- - - Foo ------ - - Foo - === -"##; - let expected = r##"

    Foo

    -

    Foo

    -

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_55() { - let original = r##" Foo - --- - - Foo ---- -"##; - let expected = r##"
    Foo
    ----
    -
    -Foo
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_56() { - let original = r##"Foo - ---- -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_57() { - let original = r##"Foo - --- -"##; - let expected = r##"

    Foo ----

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_58() { - let original = r##"Foo -= = - -Foo ---- - -"##; - let expected = r##"

    Foo -= =

    -

    Foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_59() { - let original = r##"Foo ------ -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_60() { - let original = r##"Foo\ ----- -"##; - let expected = r##"

    Foo\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_61() { - let original = r##"`Foo ----- -` - - -"##; - let expected = r##"

    `Foo

    -

    `

    -

    <a title="a lot

    -

    of dashes"/>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_62() { - let original = r##"> Foo ---- -"##; - let expected = r##"
    -

    Foo

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_63() { - let original = r##"> foo -bar -=== -"##; - let expected = r##"
    -

    foo -bar -===

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_64() { - let original = r##"- Foo ---- -"##; - let expected = r##"
      -
    • Foo
    • -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_65() { - let original = r##"Foo -Bar ---- -"##; - let expected = r##"

    Foo -Bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_66() { - let original = r##"--- -Foo ---- -Bar ---- -Baz -"##; - let expected = r##"
    -

    Foo

    -

    Bar

    -

    Baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_67() { - let original = r##" -==== -"##; - let expected = r##"

    ====

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_68() { - let original = r##"--- ---- -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_69() { - let original = r##"- foo ------ -"##; - let expected = r##"
      -
    • foo
    • -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_70() { - let original = r##" foo ---- -"##; - let expected = r##"
    foo
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_71() { - let original = r##"> foo ------ -"##; - let expected = r##"
    -

    foo

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_72() { - let original = r##"\> foo ------- -"##; - let expected = r##"

    > foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_73() { - let original = r##"Foo - -bar ---- -baz -"##; - let expected = r##"

    Foo

    -

    bar

    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_74() { - let original = r##"Foo -bar - ---- - -baz -"##; - let expected = r##"

    Foo -bar

    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_75() { - let original = r##"Foo -bar -* * * -baz -"##; - let expected = r##"

    Foo -bar

    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_76() { - let original = r##"Foo -bar -\--- -baz -"##; - let expected = r##"

    Foo -bar ---- -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_77() { - let original = r##" a simple - indented code block -"##; - let expected = r##"
    a simple
    -  indented code block
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_78() { - let original = r##" - foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -

      bar

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_79() { - let original = r##"1. foo - - - bar -"##; - let expected = r##"
      -
    1. -

      foo

      -
        -
      • bar
      • -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_80() { - let original = r##"
    - *hi* - - - one -"##; - let expected = r##"
    <a/>
    -*hi*
    -
    -- one
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_81() { - let original = r##" chunk1 - - chunk2 - - - - chunk3 -"##; - let expected = r##"
    chunk1
    -
    -chunk2
    -
    -
    -
    -chunk3
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_82() { - let original = r##" chunk1 - - chunk2 -"##; - let expected = r##"
    chunk1
    -  
    -  chunk2
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_83() { - let original = r##"Foo - bar - -"##; - let expected = r##"

    Foo -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_84() { - let original = r##" foo -bar -"##; - let expected = r##"
    foo
    -
    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_85() { - let original = r##"# Heading - foo -Heading ------- - foo ----- -"##; - let expected = r##"

    Heading

    -
    foo
    -
    -

    Heading

    -
    foo
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_86() { - let original = r##" foo - bar -"##; - let expected = r##"
        foo
    -bar
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_87() { - let original = r##" - - foo - - -"##; - let expected = r##"
    foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_88() { - let original = r##" foo -"##; - let expected = r##"
    foo  
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_89() { - let original = r##"``` -< - > -``` -"##; - let expected = r##"
    <
    - >
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_90() { - let original = r##"~~~ -< - > -~~~ -"##; - let expected = r##"
    <
    - >
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_91() { - let original = r##"`` -foo -`` -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_92() { - let original = r##"``` -aaa -~~~ -``` -"##; - let expected = r##"
    aaa
    -~~~
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_93() { - let original = r##"~~~ -aaa -``` -~~~ -"##; - let expected = r##"
    aaa
    -```
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_94() { - let original = r##"```` -aaa -``` -`````` -"##; - let expected = r##"
    aaa
    -```
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_95() { - let original = r##"~~~~ -aaa -~~~ -~~~~ -"##; - let expected = r##"
    aaa
    -~~~
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_96() { - let original = r##"``` -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_97() { - let original = r##"````` - -``` -aaa -"##; - let expected = r##"
    
    -```
    -aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_98() { - let original = r##"> ``` -> aaa - -bbb -"##; - let expected = r##"
    -
    aaa
    -
    -
    -

    bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_99() { - let original = r##"``` - - -``` -"##; - let expected = r##"
    
    -  
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_100() { - let original = r##"``` -``` -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_101() { - let original = r##" ``` - aaa -aaa -``` -"##; - let expected = r##"
    aaa
    -aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_102() { - let original = r##" ``` -aaa - aaa -aaa - ``` -"##; - let expected = r##"
    aaa
    -aaa
    -aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_103() { - let original = r##" ``` - aaa - aaa - aaa - ``` -"##; - let expected = r##"
    aaa
    - aaa
    -aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_104() { - let original = r##" ``` - aaa - ``` -"##; - let expected = r##"
    ```
    -aaa
    -```
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_105() { - let original = r##"``` -aaa - ``` -"##; - let expected = r##"
    aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_106() { - let original = r##" ``` -aaa - ``` -"##; - let expected = r##"
    aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_107() { - let original = r##"``` -aaa - ``` -"##; - let expected = r##"
    aaa
    -    ```
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_108() { - let original = r##"``` ``` -aaa -"##; - let expected = r##"

    -aaa

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_109() { - let original = r##"~~~~~~ -aaa -~~~ ~~ -"##; - let expected = r##"
    aaa
    -~~~ ~~
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_110() { - let original = r##"foo -``` -bar -``` -baz -"##; - let expected = r##"

    foo

    -
    bar
    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_111() { - let original = r##"foo ---- -~~~ -bar -~~~ -# baz -"##; - let expected = r##"

    foo

    -
    bar
    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_112() { - let original = r##"```ruby -def foo(x) - return 3 -end -``` -"##; - let expected = r##"
    def foo(x)
    -  return 3
    -end
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_113() { - let original = r##"~~~~ ruby startline=3 $%@#$ -def foo(x) - return 3 -end -~~~~~~~ -"##; - let expected = r##"
    def foo(x)
    -  return 3
    -end
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_114() { - let original = r##"````; -```` -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_115() { - let original = r##"``` aa ``` -foo -"##; - let expected = r##"

    aa -foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_116() { - let original = r##"~~~ aa ``` ~~~ -foo -~~~ -"##; - let expected = r##"
    foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_117() { - let original = r##"``` -``` aaa -``` -"##; - let expected = r##"
    ``` aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_118() { - let original = r##"
    -
    -**Hello**,
    -
    -_world_.
    -
    -
    -"##; - let expected = r##"
    -
    -**Hello**,
    -

    world. -

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_119() { - let original = r##" - - - -
    - hi -
    - -okay. -"##; - let expected = r##" - - - -
    - hi -
    -

    okay.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_120() { - let original = r##"
    -*foo* -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_122() { - let original = r##"
    - -*Markdown* - -
    -"##; - let expected = r##"
    -

    Markdown

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_123() { - let original = r##"
    -
    -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_124() { - let original = r##"
    -
    -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_125() { - let original = r##"
    -*foo* - -*bar* -"##; - let expected = r##"
    -*foo* -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_126() { - let original = r##"
    -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_130() { - let original = r##"
    -foo -
    -"##; - let expected = r##"
    -foo -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_131() { - let original = r##"
    -``` c -int x = 33; -``` -"##; - let expected = r##"
    -``` c -int x = 33; -``` -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_132() { - let original = r##" -*bar* - -"##; - let expected = r##" -*bar* - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_133() { - let original = r##" -*bar* - -"##; - let expected = r##" -*bar* - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_134() { - let original = r##" -*bar* - -"##; - let expected = r##" -*bar* - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_135() { - let original = r##" -*bar* -"##; - let expected = r##" -*bar* -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_136() { - let original = r##" -*foo* - -"##; - let expected = r##" -*foo* - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_137() { - let original = r##" - -*foo* - - -"##; - let expected = r##" -

    foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_138() { - let original = r##"*foo* -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_139() { - let original = r##"
    
    -import Text.HTML.TagSoup
    -
    -main :: IO ()
    -main = print $ parseTags tags
    -
    -okay -"##; - let expected = r##"
    
    -import Text.HTML.TagSoup
    -
    -main :: IO ()
    -main = print $ parseTags tags
    -
    -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_140() { - let original = r##" -okay -"##; - let expected = r##" -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_141() { - let original = r##" -okay -"##; - let expected = r##" -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_142() { - let original = r##" -*foo* -"##; - let expected = r##" -

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_146() { - let original = r##"*bar* -*baz* -"##; - let expected = r##"*bar* -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_147() { - let original = r##"1. *bar* -"##; - let expected = r##"1. *bar* -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_148() { - let original = r##" -okay -"##; - let expected = r##" -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_149() { - let original = r##"'; - -?> -okay -"##; - let expected = r##"'; - -?> -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_150() { - let original = r##" -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_151() { - let original = r##" -okay -"##; - let expected = r##" -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_152() { - let original = r##" - - -"##; - let expected = r##" -
    <!-- foo -->
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_153() { - let original = r##"
    - -
    -"##; - let expected = r##"
    -
    <div>
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_154() { - let original = r##"Foo -
    -bar -
    -"##; - let expected = r##"

    Foo

    -
    -bar -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_155() { - let original = r##"
    -bar -
    -*foo* -"##; - let expected = r##"
    -bar -
    -*foo* -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_156() { - let original = r##"Foo - -baz -"##; - let expected = r##"

    Foo - -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_157() { - let original = r##"
    - -*Emphasized* text. - -
    -"##; - let expected = r##"
    -

    Emphasized text.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_158() { - let original = r##"
    -*Emphasized* text. -
    -"##; - let expected = r##"
    -*Emphasized* text. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_159() { - let original = r##" - - - - - - - -
    -Hi -
    -"##; - let expected = r##" - - - -
    -Hi -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_160() { - let original = r##" - - - - - - - -
    - Hi -
    -"##; - let expected = r##" - -
    <td>
    -  Hi
    -</td>
    -
    - -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_161() { - let original = r##"[foo]: /url "title" - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_162() { - let original = r##" [foo]: - /url - 'the title' - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_163() { - let original = r##"[Foo*bar\]]:my_(url) 'title (with parens)' - -[Foo*bar\]] -"##; - let expected = r##"

    Foo*bar]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_164() { - let original = r##"[Foo bar]: - -'title' - -[Foo bar] -"##; - let expected = r##"

    Foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_165() { - let original = r##"[foo]: /url ' -title -line1 -line2 -' - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_166() { - let original = r##"[foo]: /url 'title - -with blank line' - -[foo] -"##; - let expected = r##"

    [foo]: /url 'title

    -

    with blank line'

    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_167() { - let original = r##"[foo]: -/url - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_168() { - let original = r##"[foo]: - -[foo] -"##; - let expected = r##"

    [foo]:

    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_169() { - let original = r##"[foo]: <> - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_170() { - let original = r##"[foo]: (baz) - -[foo] -"##; - let expected = r##"

    [foo]: (baz)

    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_171() { - let original = r##"[foo]: /url\bar\*baz "foo\"bar\baz" - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_172() { - let original = r##"[foo] - -[foo]: url -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_173() { - let original = r##"[foo] - -[foo]: first -[foo]: second -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_174() { - let original = r##"[FOO]: /url - -[Foo] -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_175() { - let original = r##"[ΑΓΩ]: /φου - -[αγω] -"##; - let expected = r##"

    αγω

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_176() { - let original = r##"[foo]: /url -"##; - let expected = r##""##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_177() { - let original = r##"[ -foo -]: /url -bar -"##; - let expected = r##"

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_178() { - let original = r##"[foo]: /url "title" ok -"##; - let expected = r##"

    [foo]: /url "title" ok

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_179() { - let original = r##"[foo]: /url -"title" ok -"##; - let expected = r##"

    "title" ok

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_180() { - let original = r##" [foo]: /url "title" - -[foo] -"##; - let expected = r##"
    [foo]: /url "title"
    -
    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_181() { - let original = r##"``` -[foo]: /url -``` - -[foo] -"##; - let expected = r##"
    [foo]: /url
    -
    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_182() { - let original = r##"Foo -[bar]: /baz - -[bar] -"##; - let expected = r##"

    Foo -[bar]: /baz

    -

    [bar]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_183() { - let original = r##"# [Foo] -[foo]: /url -> bar -"##; - let expected = r##"

    Foo

    -
    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_184() { - let original = r##"[foo]: /url -bar -=== -[foo] -"##; - let expected = r##"

    bar

    -

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_185() { - let original = r##"[foo]: /url -=== -[foo] -"##; - let expected = r##"

    === -foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_186() { - let original = r##"[foo]: /foo-url "foo" -[bar]: /bar-url - "bar" -[baz]: /baz-url - -[foo], -[bar], -[baz] -"##; - let expected = r##"

    foo, -bar, -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_187() { - let original = r##"[foo] - -> [foo]: /url -"##; - let expected = r##"

    foo

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_188() { - let original = r##"[foo]: /url -"##; - let expected = r##""##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_189() { - let original = r##"aaa - -bbb -"##; - let expected = r##"

    aaa

    -

    bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_190() { - let original = r##"aaa -bbb - -ccc -ddd -"##; - let expected = r##"

    aaa -bbb

    -

    ccc -ddd

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_191() { - let original = r##"aaa - - -bbb -"##; - let expected = r##"

    aaa

    -

    bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_192() { - let original = r##" aaa - bbb -"##; - let expected = r##"

    aaa -bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_193() { - let original = r##"aaa - bbb - ccc -"##; - let expected = r##"

    aaa -bbb -ccc

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_194() { - let original = r##" aaa -bbb -"##; - let expected = r##"

    aaa -bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_195() { - let original = r##" aaa -bbb -"##; - let expected = r##"
    aaa
    -
    -

    bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_196() { - let original = r##"aaa -bbb -"##; - let expected = r##"

    aaa
    -bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_197() { - let original = r##" - -aaa - - -# aaa - - -"##; - let expected = r##"

    aaa

    -

    aaa

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_198() { - let original = r##"> # Foo -> bar -> baz -"##; - let expected = r##"
    -

    Foo

    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_199() { - let original = r##"># Foo ->bar -> baz -"##; - let expected = r##"
    -

    Foo

    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_200() { - let original = r##" > # Foo - > bar - > baz -"##; - let expected = r##"
    -

    Foo

    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_201() { - let original = r##" > # Foo - > bar - > baz -"##; - let expected = r##"
    > # Foo
    -> bar
    -> baz
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_202() { - let original = r##"> # Foo -> bar -baz -"##; - let expected = r##"
    -

    Foo

    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_203() { - let original = r##"> bar -baz -> foo -"##; - let expected = r##"
    -

    bar -baz -foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_204() { - let original = r##"> foo ---- -"##; - let expected = r##"
    -

    foo

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_205() { - let original = r##"> - foo -- bar -"##; - let expected = r##"
    -
      -
    • foo
    • -
    -
    -
      -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_206() { - let original = r##"> foo - bar -"##; - let expected = r##"
    -
    foo
    -
    -
    -
    bar
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_207() { - let original = r##"> ``` -foo -``` -"##; - let expected = r##"
    -
    -
    -

    foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_208() { - let original = r##"> foo - - bar -"##; - let expected = r##"
    -

    foo -- bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_209() { - let original = r##"> -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_210() { - let original = r##"> -> -> -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_211() { - let original = r##"> -> foo -> -"##; - let expected = r##"
    -

    foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_212() { - let original = r##"> foo - -> bar -"##; - let expected = r##"
    -

    foo

    -
    -
    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_213() { - let original = r##"> foo -> bar -"##; - let expected = r##"
    -

    foo -bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_214() { - let original = r##"> foo -> -> bar -"##; - let expected = r##"
    -

    foo

    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_215() { - let original = r##"foo -> bar -"##; - let expected = r##"

    foo

    -
    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_216() { - let original = r##"> aaa -*** -> bbb -"##; - let expected = r##"
    -

    aaa

    -
    -
    -
    -

    bbb

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_217() { - let original = r##"> bar -baz -"##; - let expected = r##"
    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_218() { - let original = r##"> bar - -baz -"##; - let expected = r##"
    -

    bar

    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_219() { - let original = r##"> bar -> -baz -"##; - let expected = r##"
    -

    bar

    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_220() { - let original = r##"> > > foo -bar -"##; - let expected = r##"
    -
    -
    -

    foo -bar

    -
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_221() { - let original = r##">>> foo -> bar ->>baz -"##; - let expected = r##"
    -
    -
    -

    foo -bar -baz

    -
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_222() { - let original = r##"> code - -> not code -"##; - let expected = r##"
    -
    code
    -
    -
    -
    -

    not code

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_223() { - let original = r##"A paragraph -with two lines. - - indented code - -> A block quote. -"##; - let expected = r##"

    A paragraph -with two lines.

    -
    indented code
    -
    -
    -

    A block quote.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_224() { - let original = r##"1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_225() { - let original = r##"- one - - two -"##; - let expected = r##"
      -
    • one
    • -
    -

    two

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_226() { - let original = r##"- one - - two -"##; - let expected = r##"
      -
    • -

      one

      -

      two

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_227() { - let original = r##" - one - - two -"##; - let expected = r##"
      -
    • one
    • -
    -
     two
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_228() { - let original = r##" - one - - two -"##; - let expected = r##"
      -
    • -

      one

      -

      two

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_229() { - let original = r##" > > 1. one ->> ->> two -"##; - let expected = r##"
    -
    -
      -
    1. -

      one

      -

      two

      -
    2. -
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_230() { - let original = r##">>- one ->> - > > two -"##; - let expected = r##"
    -
    -
      -
    • one
    • -
    -

    two

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_231() { - let original = r##"-one - -2.two -"##; - let expected = r##"

    -one

    -

    2.two

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_232() { - let original = r##"- foo - - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -

      bar

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_233() { - let original = r##"1. foo - - ``` - bar - ``` - - baz - - > bam -"##; - let expected = r##"
      -
    1. -

      foo

      -
      bar
      -
      -

      baz

      -
      -

      bam

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_234() { - let original = r##"- Foo - - bar - - - baz -"##; - let expected = r##"
      -
    • -

      Foo

      -
      bar
      -
      -
      -baz
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_235() { - let original = r##"123456789. ok -"##; - let expected = r##"
      -
    1. ok
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_236() { - let original = r##"1234567890. not ok -"##; - let expected = r##"

    1234567890. not ok

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_237() { - let original = r##"0. ok -"##; - let expected = r##"
      -
    1. ok
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_238() { - let original = r##"003. ok -"##; - let expected = r##"
      -
    1. ok
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_239() { - let original = r##"-1. not ok -"##; - let expected = r##"

    -1. not ok

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_240() { - let original = r##"- foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -
      bar
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_241() { - let original = r##" 10. foo - - bar -"##; - let expected = r##"
      -
    1. -

      foo

      -
      bar
      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_242() { - let original = r##" indented code - -paragraph - - more code -"##; - let expected = r##"
    indented code
    -
    -

    paragraph

    -
    more code
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_243() { - let original = r##"1. indented code - - paragraph - - more code -"##; - let expected = r##"
      -
    1. -
      indented code
      -
      -

      paragraph

      -
      more code
      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_244() { - let original = r##"1. indented code - - paragraph - - more code -"##; - let expected = r##"
      -
    1. -
       indented code
      -
      -

      paragraph

      -
      more code
      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_245() { - let original = r##" foo - -bar -"##; - let expected = r##"

    foo

    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_246() { - let original = r##"- foo - - bar -"##; - let expected = r##"
      -
    • foo
    • -
    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_247() { - let original = r##"- foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -

      bar

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_248() { - let original = r##"- - foo -- - ``` - bar - ``` -- - baz -"##; - let expected = r##"
      -
    • foo
    • -
    • -
      bar
      -
      -
    • -
    • -
      baz
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_249() { - let original = r##"- - foo -"##; - let expected = r##"
      -
    • foo
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_250() { - let original = r##"- - - foo -"##; - let expected = r##"
      -
    • -
    -

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_251() { - let original = r##"- foo -- -- bar -"##; - let expected = r##"
      -
    • foo
    • -
    • -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_252() { - let original = r##"- foo -- -- bar -"##; - let expected = r##"
      -
    • foo
    • -
    • -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_253() { - let original = r##"1. foo -2. -3. bar -"##; - let expected = r##"
      -
    1. foo
    2. -
    3. -
    4. bar
    5. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_254() { - let original = r##"* -"##; - let expected = r##"
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_255() { - let original = r##"foo -* - -foo -1. -"##; - let expected = r##"

    foo -*

    -

    foo -1.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_256() { - let original = r##" 1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_257() { - let original = r##" 1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_258() { - let original = r##" 1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_259() { - let original = r##" 1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
    1.  A paragraph
    -    with two lines.
    -
    -        indented code
    -
    -    > A block quote.
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_260() { - let original = r##" 1. A paragraph -with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_261() { - let original = r##" 1. A paragraph - with two lines. -"##; - let expected = r##"
      -
    1. A paragraph -with two lines.
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_262() { - let original = r##"> 1. > Blockquote -continued here. -"##; - let expected = r##"
    -
      -
    1. -
      -

      Blockquote -continued here.

      -
      -
    2. -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_263() { - let original = r##"> 1. > Blockquote -> continued here. -"##; - let expected = r##"
    -
      -
    1. -
      -

      Blockquote -continued here.

      -
      -
    2. -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_264() { - let original = r##"- foo - - bar - - baz - - boo -"##; - let expected = r##"
      -
    • foo -
        -
      • bar -
          -
        • baz -
            -
          • boo
          • -
          -
        • -
        -
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_265() { - let original = r##"- foo - - bar - - baz - - boo -"##; - let expected = r##"
      -
    • foo
    • -
    • bar
    • -
    • baz
    • -
    • boo
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_266() { - let original = r##"10) foo - - bar -"##; - let expected = r##"
      -
    1. foo -
        -
      • bar
      • -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_267() { - let original = r##"10) foo - - bar -"##; - let expected = r##"
      -
    1. foo
    2. -
    -
      -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_268() { - let original = r##"- - foo -"##; - let expected = r##"
      -
    • -
        -
      • foo
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_269() { - let original = r##"1. - 2. foo -"##; - let expected = r##"
      -
    1. -
        -
      • -
          -
        1. foo
        2. -
        -
      • -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_270() { - let original = r##"- # Foo -- Bar - --- - baz -"##; - let expected = r##"
      -
    • -

      Foo

      -
    • -
    • -

      Bar

      -baz
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_271() { - let original = r##"- foo -- bar -+ baz -"##; - let expected = r##"
      -
    • foo
    • -
    • bar
    • -
    -
      -
    • baz
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_272() { - let original = r##"1. foo -2. bar -3) baz -"##; - let expected = r##"
      -
    1. foo
    2. -
    3. bar
    4. -
    -
      -
    1. baz
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_273() { - let original = r##"Foo -- bar -- baz -"##; - let expected = r##"

    Foo

    -
      -
    • bar
    • -
    • baz
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_274() { - let original = r##"The number of windows in my house is -14. The number of doors is 6. -"##; - let expected = r##"

    The number of windows in my house is -14. The number of doors is 6.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_275() { - let original = r##"The number of windows in my house is -1. The number of doors is 6. -"##; - let expected = r##"

    The number of windows in my house is

    -
      -
    1. The number of doors is 6.
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_276() { - let original = r##"- foo - -- bar - - -- baz -"##; - let expected = r##"
      -
    • -

      foo

      -
    • -
    • -

      bar

      -
    • -
    • -

      baz

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_277() { - let original = r##"- foo - - bar - - baz - - - bim -"##; - let expected = r##"
      -
    • foo -
        -
      • bar -
          -
        • -

          baz

          -

          bim

          -
        • -
        -
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_278() { - let original = r##"- foo -- bar - - - -- baz -- bim -"##; - let expected = r##"
      -
    • foo
    • -
    • bar
    • -
    - -
      -
    • baz
    • -
    • bim
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_279() { - let original = r##"- foo - - notcode - -- foo - - - - code -"##; - let expected = r##"
      -
    • -

      foo

      -

      notcode

      -
    • -
    • -

      foo

      -
    • -
    - -
    code
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_280() { - let original = r##"- a - - b - - c - - d - - e - - f -- g -"##; - let expected = r##"
      -
    • a
    • -
    • b
    • -
    • c
    • -
    • d
    • -
    • e
    • -
    • f
    • -
    • g
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_281() { - let original = r##"1. a - - 2. b - - 3. c -"##; - let expected = r##"
      -
    1. -

      a

      -
    2. -
    3. -

      b

      -
    4. -
    5. -

      c

      -
    6. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_282() { - let original = r##"- a - - b - - c - - d - - e -"##; - let expected = r##"
      -
    • a
    • -
    • b
    • -
    • c
    • -
    • d -- e
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_283() { - let original = r##"1. a - - 2. b - - 3. c -"##; - let expected = r##"
      -
    1. -

      a

      -
    2. -
    3. -

      b

      -
    4. -
    -
    3. c
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_284() { - let original = r##"- a -- b - -- c -"##; - let expected = r##"
      -
    • -

      a

      -
    • -
    • -

      b

      -
    • -
    • -

      c

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_285() { - let original = r##"* a -* - -* c -"##; - let expected = r##"
      -
    • -

      a

      -
    • -
    • -
    • -

      c

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_286() { - let original = r##"- a -- b - - c -- d -"##; - let expected = r##"
      -
    • -

      a

      -
    • -
    • -

      b

      -

      c

      -
    • -
    • -

      d

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_287() { - let original = r##"- a -- b - - [ref]: /url -- d -"##; - let expected = r##"
      -
    • -

      a

      -
    • -
    • -

      b

      -
    • -
    • -

      d

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_288() { - let original = r##"- a -- ``` - b - - - ``` -- c -"##; - let expected = r##"
      -
    • a
    • -
    • -
      b
      -
      -
      -
      -
    • -
    • c
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_289() { - let original = r##"- a - - b - - c -- d -"##; - let expected = r##"
      -
    • a -
        -
      • -

        b

        -

        c

        -
      • -
      -
    • -
    • d
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_290() { - let original = r##"* a - > b - > -* c -"##; - let expected = r##"
      -
    • a -
      -

      b

      -
      -
    • -
    • c
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_291() { - let original = r##"- a - > b - ``` - c - ``` -- d -"##; - let expected = r##"
      -
    • a -
      -

      b

      -
      -
      c
      -
      -
    • -
    • d
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_292() { - let original = r##"- a -"##; - let expected = r##"
      -
    • a
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_293() { - let original = r##"- a - - b -"##; - let expected = r##"
      -
    • a -
        -
      • b
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_294() { - let original = r##"1. ``` - foo - ``` - - bar -"##; - let expected = r##"
      -
    1. -
      foo
      -
      -

      bar

      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_295() { - let original = r##"* foo - * bar - - baz -"##; - let expected = r##"
      -
    • -

      foo

      -
        -
      • bar
      • -
      -

      baz

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_296() { - let original = r##"- a - - b - - c - -- d - - e - - f -"##; - let expected = r##"
      -
    • -

      a

      -
        -
      • b
      • -
      • c
      • -
      -
    • -
    • -

      d

      -
        -
      • e
      • -
      • f
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_297() { - let original = r##"`hi`lo` -"##; - let expected = r##"

    hilo`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_298() { - let original = r##"\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ -"##; - let expected = r##"

    !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_299() { - let original = r##"\ \A\a\ \3\φ\« -"##; - let expected = r##"

    \ \A\a\ \3\φ\«

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_300() { - let original = r##"\*not emphasized* -\
    not a tag -\[not a link](/foo) -\`not code` -1\. not a list -\* not a list -\# not a heading -\[foo]: /url "not a reference" -\ö not a character entity -"##; - let expected = r##"

    *not emphasized* -<br/> not a tag -[not a link](/foo) -`not code` -1. not a list -* not a list -# not a heading -[foo]: /url "not a reference" -&ouml; not a character entity

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_301() { - let original = r##"\\*emphasis* -"##; - let expected = r##"

    \emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_302() { - let original = r##"foo\ -bar -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_303() { - let original = r##"`` \[\` `` -"##; - let expected = r##"

    \[\`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_304() { - let original = r##" \[\] -"##; - let expected = r##"
    \[\]
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_305() { - let original = r##"~~~ -\[\] -~~~ -"##; - let expected = r##"
    \[\]
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_306() { - let original = r##" -"##; - let expected = r##"

    http://example.com?find=\*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_307() { - let original = r##" -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_308() { - let original = r##"[foo](/bar\* "ti\*tle") -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_309() { - let original = r##"[foo] - -[foo]: /bar\* "ti\*tle" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_310() { - let original = r##"``` foo\+bar -foo -``` -"##; - let expected = r##"
    foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_311() { - let original = r##"  & © Æ Ď -¾ ℋ ⅆ -∲ ≧̸ -"##; - let expected = r##"

      & © Æ Ď -¾ ℋ ⅆ -∲ ≧̸

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_312() { - let original = r##"# Ӓ Ϡ � -"##; - let expected = r##"

    # Ӓ Ϡ �

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_313() { - let original = r##"" ആ ಫ -"##; - let expected = r##"

    " ആ ಫ

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_314() { - let original = r##"  &x; &#; &#x; -� -&#abcdef0; -&ThisIsNotDefined; &hi?; -"##; - let expected = r##"

    &nbsp &x; &#; &#x; -&#87654321; -&#abcdef0; -&ThisIsNotDefined; &hi?;

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_315() { - let original = r##"© -"##; - let expected = r##"

    &copy

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_316() { - let original = r##"&MadeUpEntity; -"##; - let expected = r##"

    &MadeUpEntity;

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_317() { - let original = r##" -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_318() { - let original = r##"[foo](/föö "föö") -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_319() { - let original = r##"[foo] - -[foo]: /föö "föö" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_320() { - let original = r##"``` föö -foo -``` -"##; - let expected = r##"
    foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_321() { - let original = r##"`föö` -"##; - let expected = r##"

    f&ouml;&ouml;

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_322() { - let original = r##" föfö -"##; - let expected = r##"
    f&ouml;f&ouml;
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_323() { - let original = r##"*foo* -*foo* -"##; - let expected = r##"

    *foo* -foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_324() { - let original = r##"* foo - -* foo -"##; - let expected = r##"

    * foo

    -
      -
    • foo
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_325() { - let original = r##"foo bar -"##; - let expected = r##"

    foo - -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_326() { - let original = r##" foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_327() { - let original = r##"[a](url "tit") -"##; - let expected = r##"

    [a](url "tit")

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_328() { - let original = r##"`foo` -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_329() { - let original = r##"`` foo ` bar `` -"##; - let expected = r##"

    foo ` bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_330() { - let original = r##"` `` ` -"##; - let expected = r##"

    ``

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_331() { - let original = r##"` `` ` -"##; - let expected = r##"

    ``

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_332() { - let original = r##"` a` -"##; - let expected = r##"

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_333() { - let original = r##"` b ` -"##; - let expected = r##"

     b 

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_334() { - let original = r##"` ` -` ` -"##; - let expected = r##"

      -

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_335() { - let original = r##"`` -foo -bar -baz -`` -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_336() { - let original = r##"`` -foo -`` -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_337() { - let original = r##"`foo bar -baz` -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_338() { - let original = r##"`foo\`bar` -"##; - let expected = r##"

    foo\bar`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_339() { - let original = r##"``foo`bar`` -"##; - let expected = r##"

    foo`bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_340() { - let original = r##"` foo `` bar ` -"##; - let expected = r##"

    foo `` bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_341() { - let original = r##"*foo`*` -"##; - let expected = r##"

    *foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_342() { - let original = r##"[not a `link](/foo`) -"##; - let expected = r##"

    [not a link](/foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_343() { - let original = r##"`` -"##; - let expected = r##"

    <a href="">`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_344() { - let original = r##"
    ` -"##; - let expected = r##"

    `

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_345() { - let original = r##"`` -"##; - let expected = r##"

    <http://foo.bar.baz>`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_346() { - let original = r##"` -"##; - let expected = r##"

    http://foo.bar.`baz`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_347() { - let original = r##"```foo`` -"##; - let expected = r##"

    ```foo``

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_348() { - let original = r##"`foo -"##; - let expected = r##"

    `foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_349() { - let original = r##"`foo``bar`` -"##; - let expected = r##"

    `foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_350() { - let original = r##"*foo bar* -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_351() { - let original = r##"a * foo bar* -"##; - let expected = r##"

    a * foo bar*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_352() { - let original = r##"a*"foo"* -"##; - let expected = r##"

    a*"foo"*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_353() { - let original = r##"* a * -"##; - let expected = r##"

    * a *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_354() { - let original = r##"foo*bar* -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_355() { - let original = r##"5*6*78 -"##; - let expected = r##"

    5678

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_356() { - let original = r##"_foo bar_ -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_357() { - let original = r##"_ foo bar_ -"##; - let expected = r##"

    _ foo bar_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_358() { - let original = r##"a_"foo"_ -"##; - let expected = r##"

    a_"foo"_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_359() { - let original = r##"foo_bar_ -"##; - let expected = r##"

    foo_bar_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_360() { - let original = r##"5_6_78 -"##; - let expected = r##"

    5_6_78

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_361() { - let original = r##"пристаням_стремятся_ -"##; - let expected = r##"

    пристаням_стремятся_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_362() { - let original = r##"aa_"bb"_cc -"##; - let expected = r##"

    aa_"bb"_cc

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_363() { - let original = r##"foo-_(bar)_ -"##; - let expected = r##"

    foo-(bar)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_364() { - let original = r##"_foo* -"##; - let expected = r##"

    _foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_365() { - let original = r##"*foo bar * -"##; - let expected = r##"

    *foo bar *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_366() { - let original = r##"*foo bar -* -"##; - let expected = r##"

    *foo bar -*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_367() { - let original = r##"*(*foo) -"##; - let expected = r##"

    *(*foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_368() { - let original = r##"*(*foo*)* -"##; - let expected = r##"

    (foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_369() { - let original = r##"*foo*bar -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_370() { - let original = r##"_foo bar _ -"##; - let expected = r##"

    _foo bar _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_371() { - let original = r##"_(_foo) -"##; - let expected = r##"

    _(_foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_372() { - let original = r##"_(_foo_)_ -"##; - let expected = r##"

    (foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_373() { - let original = r##"_foo_bar -"##; - let expected = r##"

    _foo_bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_374() { - let original = r##"_пристаням_стремятся -"##; - let expected = r##"

    _пристаням_стремятся

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_375() { - let original = r##"_foo_bar_baz_ -"##; - let expected = r##"

    foo_bar_baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_376() { - let original = r##"_(bar)_. -"##; - let expected = r##"

    (bar).

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_377() { - let original = r##"**foo bar** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_378() { - let original = r##"** foo bar** -"##; - let expected = r##"

    ** foo bar**

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_379() { - let original = r##"a**"foo"** -"##; - let expected = r##"

    a**"foo"**

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_380() { - let original = r##"foo**bar** -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_381() { - let original = r##"__foo bar__ -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_382() { - let original = r##"__ foo bar__ -"##; - let expected = r##"

    __ foo bar__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_383() { - let original = r##"__ -foo bar__ -"##; - let expected = r##"

    __ -foo bar__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_384() { - let original = r##"a__"foo"__ -"##; - let expected = r##"

    a__"foo"__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_385() { - let original = r##"foo__bar__ -"##; - let expected = r##"

    foo__bar__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_386() { - let original = r##"5__6__78 -"##; - let expected = r##"

    5__6__78

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_387() { - let original = r##"пристаням__стремятся__ -"##; - let expected = r##"

    пристаням__стремятся__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_388() { - let original = r##"__foo, __bar__, baz__ -"##; - let expected = r##"

    foo, bar, baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_389() { - let original = r##"foo-__(bar)__ -"##; - let expected = r##"

    foo-(bar)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_390() { - let original = r##"**foo bar ** -"##; - let expected = r##"

    **foo bar **

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_391() { - let original = r##"**(**foo) -"##; - let expected = r##"

    **(**foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_392() { - let original = r##"*(**foo**)* -"##; - let expected = r##"

    (foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_393() { - let original = r##"**Gomphocarpus (*Gomphocarpus physocarpus*, syn. -*Asclepias physocarpa*)** -"##; - let expected = r##"

    Gomphocarpus (Gomphocarpus physocarpus, syn. -Asclepias physocarpa)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_394() { - let original = r##"**foo "*bar*" foo** -"##; - let expected = r##"

    foo "bar" foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_395() { - let original = r##"**foo**bar -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_396() { - let original = r##"__foo bar __ -"##; - let expected = r##"

    __foo bar __

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_397() { - let original = r##"__(__foo) -"##; - let expected = r##"

    __(__foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_398() { - let original = r##"_(__foo__)_ -"##; - let expected = r##"

    (foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_399() { - let original = r##"__foo__bar -"##; - let expected = r##"

    __foo__bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_400() { - let original = r##"__пристаням__стремятся -"##; - let expected = r##"

    __пристаням__стремятся

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_401() { - let original = r##"__foo__bar__baz__ -"##; - let expected = r##"

    foo__bar__baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_402() { - let original = r##"__(bar)__. -"##; - let expected = r##"

    (bar).

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_403() { - let original = r##"*foo [bar](/url)* -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_404() { - let original = r##"*foo -bar* -"##; - let expected = r##"

    foo -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_405() { - let original = r##"_foo __bar__ baz_ -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_406() { - let original = r##"_foo _bar_ baz_ -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_407() { - let original = r##"__foo_ bar_ -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_408() { - let original = r##"*foo *bar** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_409() { - let original = r##"*foo **bar** baz* -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_410() { - let original = r##"*foo**bar**baz* -"##; - let expected = r##"

    foobarbaz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_411() { - let original = r##"*foo**bar* -"##; - let expected = r##"

    foo**bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_412() { - let original = r##"***foo** bar* -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_413() { - let original = r##"*foo **bar*** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_414() { - let original = r##"*foo**bar*** -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_415() { - let original = r##"foo***bar***baz -"##; - let expected = r##"

    foobarbaz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_416() { - let original = r##"foo******bar*********baz -"##; - let expected = r##"

    foobar***baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_417() { - let original = r##"*foo **bar *baz* bim** bop* -"##; - let expected = r##"

    foo bar baz bim bop

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_418() { - let original = r##"*foo [*bar*](/url)* -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_419() { - let original = r##"** is not an empty emphasis -"##; - let expected = r##"

    ** is not an empty emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_420() { - let original = r##"**** is not an empty strong emphasis -"##; - let expected = r##"

    **** is not an empty strong emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_421() { - let original = r##"**foo [bar](/url)** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_422() { - let original = r##"**foo -bar** -"##; - let expected = r##"

    foo -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_423() { - let original = r##"__foo _bar_ baz__ -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_424() { - let original = r##"__foo __bar__ baz__ -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_425() { - let original = r##"____foo__ bar__ -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_426() { - let original = r##"**foo **bar**** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_427() { - let original = r##"**foo *bar* baz** -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_428() { - let original = r##"**foo*bar*baz** -"##; - let expected = r##"

    foobarbaz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_429() { - let original = r##"***foo* bar** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_430() { - let original = r##"**foo *bar*** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_431() { - let original = r##"**foo *bar **baz** -bim* bop** -"##; - let expected = r##"

    foo bar baz -bim bop

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_432() { - let original = r##"**foo [*bar*](/url)** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_433() { - let original = r##"__ is not an empty emphasis -"##; - let expected = r##"

    __ is not an empty emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_434() { - let original = r##"____ is not an empty strong emphasis -"##; - let expected = r##"

    ____ is not an empty strong emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_435() { - let original = r##"foo *** -"##; - let expected = r##"

    foo ***

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_436() { - let original = r##"foo *\** -"##; - let expected = r##"

    foo *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_437() { - let original = r##"foo *_* -"##; - let expected = r##"

    foo _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_438() { - let original = r##"foo ***** -"##; - let expected = r##"

    foo *****

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_439() { - let original = r##"foo **\*** -"##; - let expected = r##"

    foo *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_440() { - let original = r##"foo **_** -"##; - let expected = r##"

    foo _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_441() { - let original = r##"**foo* -"##; - let expected = r##"

    *foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_442() { - let original = r##"*foo** -"##; - let expected = r##"

    foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_443() { - let original = r##"***foo** -"##; - let expected = r##"

    *foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_444() { - let original = r##"****foo* -"##; - let expected = r##"

    ***foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_445() { - let original = r##"**foo*** -"##; - let expected = r##"

    foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_446() { - let original = r##"*foo**** -"##; - let expected = r##"

    foo***

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_447() { - let original = r##"foo ___ -"##; - let expected = r##"

    foo ___

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_448() { - let original = r##"foo _\__ -"##; - let expected = r##"

    foo _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_449() { - let original = r##"foo _*_ -"##; - let expected = r##"

    foo *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_450() { - let original = r##"foo _____ -"##; - let expected = r##"

    foo _____

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_451() { - let original = r##"foo __\___ -"##; - let expected = r##"

    foo _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_452() { - let original = r##"foo __*__ -"##; - let expected = r##"

    foo *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_453() { - let original = r##"__foo_ -"##; - let expected = r##"

    _foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_454() { - let original = r##"_foo__ -"##; - let expected = r##"

    foo_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_455() { - let original = r##"___foo__ -"##; - let expected = r##"

    _foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_456() { - let original = r##"____foo_ -"##; - let expected = r##"

    ___foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_457() { - let original = r##"__foo___ -"##; - let expected = r##"

    foo_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_458() { - let original = r##"_foo____ -"##; - let expected = r##"

    foo___

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_459() { - let original = r##"**foo** -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_460() { - let original = r##"*_foo_* -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_461() { - let original = r##"__foo__ -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_462() { - let original = r##"_*foo*_ -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_463() { - let original = r##"****foo**** -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_464() { - let original = r##"____foo____ -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_465() { - let original = r##"******foo****** -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_466() { - let original = r##"***foo*** -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_467() { - let original = r##"_____foo_____ -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_468() { - let original = r##"*foo _bar* baz_ -"##; - let expected = r##"

    foo _bar baz_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_469() { - let original = r##"*foo __bar *baz bim__ bam* -"##; - let expected = r##"

    foo bar *baz bim bam

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_470() { - let original = r##"**foo **bar baz** -"##; - let expected = r##"

    **foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_471() { - let original = r##"*foo *bar baz* -"##; - let expected = r##"

    *foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_472() { - let original = r##"*[bar*](/url) -"##; - let expected = r##"

    *bar*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_473() { - let original = r##"_foo [bar_](/url) -"##; - let expected = r##"

    _foo bar_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_474() { - let original = r##"* -"##; - let expected = r##"

    *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_475() { - let original = r##"** -"##; - let expected = r##"

    **

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_476() { - let original = r##"__ -"##; - let expected = r##"

    __

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_477() { - let original = r##"*a `*`* -"##; - let expected = r##"

    a *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_478() { - let original = r##"_a `_`_ -"##; - let expected = r##"

    a _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_479() { - let original = r##"**a -"##; - let expected = r##"

    **ahttp://foo.bar/?q=**

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_480() { - let original = r##"__a -"##; - let expected = r##"

    __ahttp://foo.bar/?q=__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_481() { - let original = r##"[link](/uri "title") -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_482() { - let original = r##"[link](/uri) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_483() { - let original = r##"[link]() -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_484() { - let original = r##"[link](<>) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_485() { - let original = r##"[link](/my uri) -"##; - let expected = r##"

    [link](/my uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_486() { - let original = r##"[link](
    ) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_487() { - let original = r##"[link](foo -bar) -"##; - let expected = r##"

    [link](foo -bar)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_488() { - let original = r##"[link]() -"##; - let expected = r##"

    [link]()

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_489() { - let original = r##"[a]() -"##; - let expected = r##"

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_490() { - let original = r##"[link]() -"##; - let expected = r##"

    [link](<foo>)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_491() { - let original = r##"[a]( -[a](c) -"##; - let expected = r##"

    [a](<b)c -[a](<b)c> -[a](c)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_492() { - let original = r##"[link](\(foo\)) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_493() { - let original = r##"[link](foo(and(bar))) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_494() { - let original = r##"[link](foo\(and\(bar\)) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_495() { - let original = r##"[link]() -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_496() { - let original = r##"[link](foo\)\:) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_497() { - let original = r##"[link](#fragment) - -[link](http://example.com#fragment) - -[link](http://example.com?foo=3#frag) -"##; - let expected = r##"

    link

    -

    link

    -

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_498() { - let original = r##"[link](foo\bar) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_499() { - let original = r##"[link](foo%20bä) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_500() { - let original = r##"[link]("title") -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_501() { - let original = r##"[link](/url "title") -[link](/url 'title') -[link](/url (title)) -"##; - let expected = r##"

    link -link -link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_502() { - let original = r##"[link](/url "title \""") -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_503() { - let original = r##"[link](/url "title") -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_504() { - let original = r##"[link](/url "title "and" title") -"##; - let expected = r##"

    [link](/url "title "and" title")

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_505() { - let original = r##"[link](/url 'title "and" title') -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_506() { - let original = r##"[link]( /uri - "title" ) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_507() { - let original = r##"[link] (/uri) -"##; - let expected = r##"

    [link] (/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_508() { - let original = r##"[link [foo [bar]]](/uri) -"##; - let expected = r##"

    link [foo [bar]]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_509() { - let original = r##"[link] bar](/uri) -"##; - let expected = r##"

    [link] bar](/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_510() { - let original = r##"[link [bar](/uri) -"##; - let expected = r##"

    [link bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_511() { - let original = r##"[link \[bar](/uri) -"##; - let expected = r##"

    link [bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_512() { - let original = r##"[link *foo **bar** `#`*](/uri) -"##; - let expected = r##"

    link foo bar #

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_513() { - let original = r##"[![moon](moon.jpg)](/uri) -"##; - let expected = r##"

    moon

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_514() { - let original = r##"[foo [bar](/uri)](/uri) -"##; - let expected = r##"

    [foo bar](/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_515() { - let original = r##"[foo *[bar [baz](/uri)](/uri)*](/uri) -"##; - let expected = r##"

    [foo [bar baz](/uri)](/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_516() { - let original = r##"![[[foo](uri1)](uri2)](uri3) -"##; - let expected = r##"

    [foo](uri2)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_517() { - let original = r##"*[foo*](/uri) -"##; - let expected = r##"

    *foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_518() { - let original = r##"[foo *bar](baz*) -"##; - let expected = r##"

    foo *bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_519() { - let original = r##"*foo [bar* baz] -"##; - let expected = r##"

    foo [bar baz]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_520() { - let original = r##"[foo -"##; - let expected = r##"

    [foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_521() { - let original = r##"[foo`](/uri)` -"##; - let expected = r##"

    [foo](/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_522() { - let original = r##"[foo -"##; - let expected = r##"

    [foohttp://example.com/?search=](uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_523() { - let original = r##"[foo][bar] - -[bar]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_524() { - let original = r##"[link [foo [bar]]][ref] - -[ref]: /uri -"##; - let expected = r##"

    link [foo [bar]]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_525() { - let original = r##"[link \[bar][ref] - -[ref]: /uri -"##; - let expected = r##"

    link [bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_526() { - let original = r##"[link *foo **bar** `#`*][ref] - -[ref]: /uri -"##; - let expected = r##"

    link foo bar #

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_527() { - let original = r##"[![moon](moon.jpg)][ref] - -[ref]: /uri -"##; - let expected = r##"

    moon

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_528() { - let original = r##"[foo [bar](/uri)][ref] - -[ref]: /uri -"##; - let expected = r##"

    [foo bar]ref

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_529() { - let original = r##"[foo *bar [baz][ref]*][ref] - -[ref]: /uri -"##; - let expected = r##"

    [foo bar baz]ref

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_530() { - let original = r##"*[foo*][ref] - -[ref]: /uri -"##; - let expected = r##"

    *foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_531() { - let original = r##"[foo *bar][ref] - -[ref]: /uri -"##; - let expected = r##"

    foo *bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_532() { - let original = r##"[foo - -[ref]: /uri -"##; - let expected = r##"

    [foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_533() { - let original = r##"[foo`][ref]` - -[ref]: /uri -"##; - let expected = r##"

    [foo][ref]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_534() { - let original = r##"[foo - -[ref]: /uri -"##; - let expected = r##"

    [foohttp://example.com/?search=][ref]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_535() { - let original = r##"[foo][BaR] - -[bar]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_536() { - let original = r##"[Толпой][Толпой] is a Russian word. - -[ТОЛПОЙ]: /url -"##; - let expected = r##"

    Толпой is a Russian word.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_537() { - let original = r##"[Foo - bar]: /url - -[Baz][Foo bar] -"##; - let expected = r##"

    Baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_538() { - let original = r##"[foo] [bar] - -[bar]: /url "title" -"##; - let expected = r##"

    [foo] bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_539() { - let original = r##"[foo] -[bar] - -[bar]: /url "title" -"##; - let expected = r##"

    [foo] -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_540() { - let original = r##"[foo]: /url1 - -[foo]: /url2 - -[bar][foo] -"##; - let expected = r##"

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_541() { - let original = r##"[bar][foo\!] - -[foo!]: /url -"##; - let expected = r##"

    [bar][foo!]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_542() { - let original = r##"[foo][ref[] - -[ref[]: /uri -"##; - let expected = r##"

    [foo][ref[]

    -

    [ref[]: /uri

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_543() { - let original = r##"[foo][ref[bar]] - -[ref[bar]]: /uri -"##; - let expected = r##"

    [foo][ref[bar]]

    -

    [ref[bar]]: /uri

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_544() { - let original = r##"[[[foo]]] - -[[[foo]]]: /url -"##; - let expected = r##"

    [[[foo]]]

    -

    [[[foo]]]: /url

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_545() { - let original = r##"[foo][ref\[] - -[ref\[]: /uri -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_546() { - let original = r##"[bar\\]: /uri - -[bar\\] -"##; - let expected = r##"

    bar\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_547() { - let original = r##"[] - -[]: /uri -"##; - let expected = r##"

    []

    -

    []: /uri

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_548() { - let original = r##"[ - ] - -[ - ]: /uri -"##; - let expected = r##"

    [ -]

    -

    [ -]: /uri

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_549() { - let original = r##"[foo][] - -[foo]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_550() { - let original = r##"[*foo* bar][] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_551() { - let original = r##"[Foo][] - -[foo]: /url "title" -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_552() { - let original = r##"[foo] -[] - -[foo]: /url "title" -"##; - let expected = r##"

    foo -[]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_553() { - let original = r##"[foo] - -[foo]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_554() { - let original = r##"[*foo* bar] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_555() { - let original = r##"[[*foo* bar]] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    [foo bar]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_556() { - let original = r##"[[bar [foo] - -[foo]: /url -"##; - let expected = r##"

    [[bar foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_557() { - let original = r##"[Foo] - -[foo]: /url "title" -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_558() { - let original = r##"[foo] bar - -[foo]: /url -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_559() { - let original = r##"\[foo] - -[foo]: /url "title" -"##; - let expected = r##"

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_560() { - let original = r##"[foo*]: /url - -*[foo*] -"##; - let expected = r##"

    *foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_561() { - let original = r##"[foo][bar] - -[foo]: /url1 -[bar]: /url2 -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_562() { - let original = r##"[foo][] - -[foo]: /url1 -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_563() { - let original = r##"[foo]() - -[foo]: /url1 -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_564() { - let original = r##"[foo](not a link) - -[foo]: /url1 -"##; - let expected = r##"

    foo(not a link)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_565() { - let original = r##"[foo][bar][baz] - -[baz]: /url -"##; - let expected = r##"

    [foo]bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_566() { - let original = r##"[foo][bar][baz] - -[baz]: /url1 -[bar]: /url2 -"##; - let expected = r##"

    foobaz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_567() { - let original = r##"[foo][bar][baz] - -[baz]: /url1 -[foo]: /url2 -"##; - let expected = r##"

    [foo]bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_568() { - let original = r##"![foo](/url "title") -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_569() { - let original = r##"![foo *bar*] - -[foo *bar*]: train.jpg "train & tracks" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_570() { - let original = r##"![foo ![bar](/url)](/url2) -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_571() { - let original = r##"![foo [bar](/url)](/url2) -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_572() { - let original = r##"![foo *bar*][] - -[foo *bar*]: train.jpg "train & tracks" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_573() { - let original = r##"![foo *bar*][foobar] - -[FOOBAR]: train.jpg "train & tracks" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_574() { - let original = r##"![foo](train.jpg) -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_575() { - let original = r##"My ![foo bar](/path/to/train.jpg "title" ) -"##; - let expected = r##"

    My foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_576() { - let original = r##"![foo]() -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_577() { - let original = r##"![](/url) -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_578() { - let original = r##"![foo][bar] - -[bar]: /url -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_579() { - let original = r##"![foo][bar] - -[BAR]: /url -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_580() { - let original = r##"![foo][] - -[foo]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_581() { - let original = r##"![*foo* bar][] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_582() { - let original = r##"![Foo][] - -[foo]: /url "title" -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_583() { - let original = r##"![foo] -[] - -[foo]: /url "title" -"##; - let expected = r##"

    foo -[]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_584() { - let original = r##"![foo] - -[foo]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_585() { - let original = r##"![*foo* bar] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_586() { - let original = r##"![[foo]] - -[[foo]]: /url "title" -"##; - let expected = r##"

    ![[foo]]

    -

    [[foo]]: /url "title"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_587() { - let original = r##"![Foo] - -[foo]: /url "title" -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_588() { - let original = r##"!\[foo] - -[foo]: /url "title" -"##; - let expected = r##"

    ![foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_589() { - let original = r##"\![foo] - -[foo]: /url "title" -"##; - let expected = r##"

    !foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_590() { - let original = r##" -"##; - let expected = r##"

    http://foo.bar.baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_591() { - let original = r##" -"##; - let expected = r##"

    http://foo.bar.baz/test?q=hello&id=22&boolean

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_592() { - let original = r##" -"##; - let expected = r##"

    irc://foo.bar:2233/baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_593() { - let original = r##" -"##; - let expected = r##"

    MAILTO:FOO@BAR.BAZ

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_594() { - let original = r##" -"##; - let expected = r##"

    a+b+c:d

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_595() { - let original = r##" -"##; - let expected = r##"

    made-up-scheme://foo,bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_596() { - let original = r##" -"##; - let expected = r##"

    http://../

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_597() { - let original = r##" -"##; - let expected = r##"

    localhost:5001/foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_598() { - let original = r##" -"##; - let expected = r##"

    <http://foo.bar/baz bim>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_599() { - let original = r##" -"##; - let expected = r##"

    http://example.com/\[\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_600() { - let original = r##" -"##; - let expected = r##"

    foo@bar.example.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_601() { - let original = r##" -"##; - let expected = r##"

    foo+special@Bar.baz-bar0.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_602() { - let original = r##" -"##; - let expected = r##"

    <foo+@bar.example.com>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_603() { - let original = r##"<> -"##; - let expected = r##"

    <>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_604() { - let original = r##"< http://foo.bar > -"##; - let expected = r##"

    < http://foo.bar >

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_605() { - let original = r##" -"##; - let expected = r##"

    <m:abc>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_606() { - let original = r##" -"##; - let expected = r##"

    <foo.bar.baz>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_607() { - let original = r##"http://example.com -"##; - let expected = r##"

    http://example.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_608() { - let original = r##"foo@bar.example.com -"##; - let expected = r##"

    foo@bar.example.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_609() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_610() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_611() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_612() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_613() { - let original = r##"Foo -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_614() { - let original = r##"<33> <__> -"##; - let expected = r##"

    <33> <__>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_615() { - let original = r##"
    -"##; - let expected = r##"

    <a h*#ref="hi">

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_616() { - let original = r##"
    <a href="hi'> <a href=hi'>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_617() { - let original = r##"< a>< -foo> - -"##; - let expected = r##"

    < a>< -foo><bar/ > -<foo bar=baz -bim!bop />

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_618() { - let original = r##"
    -"##; - let expected = r##"

    <a href='bar'title=title>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_619() { - let original = r##"
    -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_620() { - let original = r##" -"##; - let expected = r##"

    </a href="foo">

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_621() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_622() { - let original = r##"foo -"##; - let expected = r##"

    foo <!-- not a comment -- two hyphens -->

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_623() { - let original = r##"foo foo --> - -foo -"##; - let expected = r##"

    foo <!--> foo -->

    -

    foo <!-- foo--->

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_624() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_625() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_626() { - let original = r##"foo &<]]> -"##; - let expected = r##"

    foo &<]]>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_627() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_628() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_629() { - let original = r##" -"##; - let expected = r##"

    <a href=""">

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_630() { - let original = r##"foo -baz -"##; - let expected = r##"

    foo
    -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_631() { - let original = r##"foo\ -baz -"##; - let expected = r##"

    foo
    -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_632() { - let original = r##"foo -baz -"##; - let expected = r##"

    foo
    -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_633() { - let original = r##"foo - bar -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_634() { - let original = r##"foo\ - bar -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_635() { - let original = r##"*foo -bar* -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_636() { - let original = r##"*foo\ -bar* -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_637() { - let original = r##"`code -span` -"##; - let expected = r##"

    code span

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_638() { - let original = r##"`code\ -span` -"##; - let expected = r##"

    code\ span

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_639() { - let original = r##"
    -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_640() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_641() { - let original = r##"foo\ -"##; - let expected = r##"

    foo\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_642() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_643() { - let original = r##"### foo\ -"##; - let expected = r##"

    foo\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_644() { - let original = r##"### foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_645() { - let original = r##"foo -baz -"##; - let expected = r##"

    foo -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_646() { - let original = r##"foo - baz -"##; - let expected = r##"

    foo -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_647() { - let original = r##"hello $.;'there -"##; - let expected = r##"

    hello $.;'there

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_648() { - let original = r##"Foo χρῆν -"##; - let expected = r##"

    Foo χρῆν

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_649() { - let original = r##"Multiple spaces -"##; - let expected = r##"

    Multiple spaces

    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn spec_test_1() { + let original = r##" foo baz bim +"##; + let expected = r##"
    foo	baz		bim
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_2() { + let original = r##" foo baz bim +"##; + let expected = r##"
    foo	baz		bim
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_3() { + let original = r##" a a + ὐ a +"##; + let expected = r##"
    a	a
    +ὐ	a
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_4() { + let original = r##" - foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_5() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +
        bar
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_6() { + let original = r##"> foo +"##; + let expected = r##"
    +
      foo
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_7() { + let original = r##"- foo +"##; + let expected = r##"
      +
    • +
        foo
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_8() { + let original = r##" foo + bar +"##; + let expected = r##"
    foo
    +bar
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_9() { + let original = r##" - foo + - bar + - baz +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • baz
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_10() { + let original = r##"# Foo +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_11() { + let original = r##"* * * +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_12() { + let original = r##"- `one +- two` +"##; + let expected = r##"
      +
    • `one
    • +
    • two`
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_13() { + let original = r##"*** +--- +___ +"##; + let expected = r##"
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_14() { + let original = r##"+++ +"##; + let expected = r##"

    +++

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_15() { + let original = r##"=== +"##; + let expected = r##"

    ===

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_16() { + let original = r##"-- +** +__ +"##; + let expected = r##"

    -- +** +__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_17() { + let original = r##" *** + *** + *** +"##; + let expected = r##"
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_18() { + let original = r##" *** +"##; + let expected = r##"
    ***
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_19() { + let original = r##"Foo + *** +"##; + let expected = r##"

    Foo +***

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_20() { + let original = r##"_____________________________________ +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_21() { + let original = r##" - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_22() { + let original = r##" ** * ** * ** * ** +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_23() { + let original = r##"- - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_24() { + let original = r##"- - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_25() { + let original = r##"_ _ _ _ a + +a------ + +---a--- +"##; + let expected = r##"

    _ _ _ _ a

    +

    a------

    +

    ---a---

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_26() { + let original = r##" *-* +"##; + let expected = r##"

    -

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_27() { + let original = r##"- foo +*** +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_28() { + let original = r##"Foo +*** +bar +"##; + let expected = r##"

    Foo

    +
    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_29() { + let original = r##"Foo +--- +bar +"##; + let expected = r##"

    Foo

    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_30() { + let original = r##"* Foo +* * * +* Bar +"##; + let expected = r##"
      +
    • Foo
    • +
    +
    +
      +
    • Bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_31() { + let original = r##"- Foo +- * * * +"##; + let expected = r##"
      +
    • Foo
    • +
    • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_32() { + let original = r##"# foo +## foo +### foo +#### foo +##### foo +###### foo +"##; + let expected = r##"

    foo

    +

    foo

    +

    foo

    +

    foo

    +
    foo
    +
    foo
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_33() { + let original = r##"####### foo +"##; + let expected = r##"

    ####### foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_34() { + let original = r##"#5 bolt + +#hashtag +"##; + let expected = r##"

    #5 bolt

    +

    #hashtag

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_35() { + let original = r##"\## foo +"##; + let expected = r##"

    ## foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_36() { + let original = r##"# foo *bar* \*baz\* +"##; + let expected = r##"

    foo bar *baz*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_37() { + let original = r##"# foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_38() { + let original = r##" ### foo + ## foo + # foo +"##; + let expected = r##"

    foo

    +

    foo

    +

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_39() { + let original = r##" # foo +"##; + let expected = r##"
    # foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_40() { + let original = r##"foo + # bar +"##; + let expected = r##"

    foo +# bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_41() { + let original = r##"## foo ## + ### bar ### +"##; + let expected = r##"

    foo

    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_42() { + let original = r##"# foo ################################## +##### foo ## +"##; + let expected = r##"

    foo

    +
    foo
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_43() { + let original = r##"### foo ### +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_44() { + let original = r##"### foo ### b +"##; + let expected = r##"

    foo ### b

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_45() { + let original = r##"# foo# +"##; + let expected = r##"

    foo#

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_46() { + let original = r##"### foo \### +## foo #\## +# foo \# +"##; + let expected = r##"

    foo ###

    +

    foo ###

    +

    foo #

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_47() { + let original = r##"**** +## foo +**** +"##; + let expected = r##"
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_48() { + let original = r##"Foo bar +# baz +Bar foo +"##; + let expected = r##"

    Foo bar

    +

    baz

    +

    Bar foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_49() { + let original = r##"## +# +### ### +"##; + let expected = r##"

    +

    +

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_50() { + let original = r##"Foo *bar* +========= + +Foo *bar* +--------- +"##; + let expected = r##"

    Foo bar

    +

    Foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_51() { + let original = r##"Foo *bar +baz* +==== +"##; + let expected = r##"

    Foo bar +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_52() { + let original = r##" Foo *bar +baz* +==== +"##; + let expected = r##"

    Foo bar +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_53() { + let original = r##"Foo +------------------------- + +Foo += +"##; + let expected = r##"

    Foo

    +

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_54() { + let original = r##" Foo +--- + + Foo +----- + + Foo + === +"##; + let expected = r##"

    Foo

    +

    Foo

    +

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_55() { + let original = r##" Foo + --- + + Foo +--- +"##; + let expected = r##"
    Foo
    +---
    +
    +Foo
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_56() { + let original = r##"Foo + ---- +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_57() { + let original = r##"Foo + --- +"##; + let expected = r##"

    Foo +---

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_58() { + let original = r##"Foo += = + +Foo +--- - +"##; + let expected = r##"

    Foo += =

    +

    Foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_59() { + let original = r##"Foo +----- +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_60() { + let original = r##"Foo\ +---- +"##; + let expected = r##"

    Foo\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_61() { + let original = r##"`Foo +---- +` + +
    +"##; + let expected = r##"

    `Foo

    +

    `

    +

    <a title="a lot

    +

    of dashes"/>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_62() { + let original = r##"> Foo +--- +"##; + let expected = r##"
    +

    Foo

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_63() { + let original = r##"> foo +bar +=== +"##; + let expected = r##"
    +

    foo +bar +===

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_64() { + let original = r##"- Foo +--- +"##; + let expected = r##"
      +
    • Foo
    • +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_65() { + let original = r##"Foo +Bar +--- +"##; + let expected = r##"

    Foo +Bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_66() { + let original = r##"--- +Foo +--- +Bar +--- +Baz +"##; + let expected = r##"
    +

    Foo

    +

    Bar

    +

    Baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_67() { + let original = r##" +==== +"##; + let expected = r##"

    ====

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_68() { + let original = r##"--- +--- +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_69() { + let original = r##"- foo +----- +"##; + let expected = r##"
      +
    • foo
    • +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_70() { + let original = r##" foo +--- +"##; + let expected = r##"
    foo
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_71() { + let original = r##"> foo +----- +"##; + let expected = r##"
    +

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_72() { + let original = r##"\> foo +------ +"##; + let expected = r##"

    > foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_73() { + let original = r##"Foo + +bar +--- +baz +"##; + let expected = r##"

    Foo

    +

    bar

    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_74() { + let original = r##"Foo +bar + +--- + +baz +"##; + let expected = r##"

    Foo +bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_75() { + let original = r##"Foo +bar +* * * +baz +"##; + let expected = r##"

    Foo +bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_76() { + let original = r##"Foo +bar +\--- +baz +"##; + let expected = r##"

    Foo +bar +--- +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_77() { + let original = r##" a simple + indented code block +"##; + let expected = r##"
    a simple
    +  indented code block
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_78() { + let original = r##" - foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_79() { + let original = r##"1. foo + + - bar +"##; + let expected = r##"
      +
    1. +

      foo

      +
        +
      • bar
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_80() { + let original = r##"
    + *hi* + + - one +"##; + let expected = r##"
    <a/>
    +*hi*
    +
    +- one
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_81() { + let original = r##" chunk1 + + chunk2 + + + + chunk3 +"##; + let expected = r##"
    chunk1
    +
    +chunk2
    +
    +
    +
    +chunk3
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_82() { + let original = r##" chunk1 + + chunk2 +"##; + let expected = r##"
    chunk1
    +  
    +  chunk2
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_83() { + let original = r##"Foo + bar + +"##; + let expected = r##"

    Foo +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_84() { + let original = r##" foo +bar +"##; + let expected = r##"
    foo
    +
    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_85() { + let original = r##"# Heading + foo +Heading +------ + foo +---- +"##; + let expected = r##"

    Heading

    +
    foo
    +
    +

    Heading

    +
    foo
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_86() { + let original = r##" foo + bar +"##; + let expected = r##"
        foo
    +bar
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_87() { + let original = r##" + + foo + + +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_88() { + let original = r##" foo +"##; + let expected = r##"
    foo  
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_89() { + let original = r##"``` +< + > +``` +"##; + let expected = r##"
    <
    + >
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_90() { + let original = r##"~~~ +< + > +~~~ +"##; + let expected = r##"
    <
    + >
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_91() { + let original = r##"`` +foo +`` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_92() { + let original = r##"``` +aaa +~~~ +``` +"##; + let expected = r##"
    aaa
    +~~~
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_93() { + let original = r##"~~~ +aaa +``` +~~~ +"##; + let expected = r##"
    aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_94() { + let original = r##"```` +aaa +``` +`````` +"##; + let expected = r##"
    aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_95() { + let original = r##"~~~~ +aaa +~~~ +~~~~ +"##; + let expected = r##"
    aaa
    +~~~
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_96() { + let original = r##"``` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_97() { + let original = r##"````` + +``` +aaa +"##; + let expected = r##"
    
    +```
    +aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_98() { + let original = r##"> ``` +> aaa + +bbb +"##; + let expected = r##"
    +
    aaa
    +
    +
    +

    bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_99() { + let original = r##"``` + + +``` +"##; + let expected = r##"
    
    +  
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_100() { + let original = r##"``` +``` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_101() { + let original = r##" ``` + aaa +aaa +``` +"##; + let expected = r##"
    aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_102() { + let original = r##" ``` +aaa + aaa +aaa + ``` +"##; + let expected = r##"
    aaa
    +aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_103() { + let original = r##" ``` + aaa + aaa + aaa + ``` +"##; + let expected = r##"
    aaa
    + aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_104() { + let original = r##" ``` + aaa + ``` +"##; + let expected = r##"
    ```
    +aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_105() { + let original = r##"``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_106() { + let original = r##" ``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_107() { + let original = r##"``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +    ```
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_108() { + let original = r##"``` ``` +aaa +"##; + let expected = r##"

    +aaa

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_109() { + let original = r##"~~~~~~ +aaa +~~~ ~~ +"##; + let expected = r##"
    aaa
    +~~~ ~~
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_110() { + let original = r##"foo +``` +bar +``` +baz +"##; + let expected = r##"

    foo

    +
    bar
    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_111() { + let original = r##"foo +--- +~~~ +bar +~~~ +# baz +"##; + let expected = r##"

    foo

    +
    bar
    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_112() { + let original = r##"```ruby +def foo(x) + return 3 +end +``` +"##; + let expected = r##"
    def foo(x)
    +  return 3
    +end
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_113() { + let original = r##"~~~~ ruby startline=3 $%@#$ +def foo(x) + return 3 +end +~~~~~~~ +"##; + let expected = r##"
    def foo(x)
    +  return 3
    +end
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_114() { + let original = r##"````; +```` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_115() { + let original = r##"``` aa ``` +foo +"##; + let expected = r##"

    aa +foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_116() { + let original = r##"~~~ aa ``` ~~~ +foo +~~~ +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_117() { + let original = r##"``` +``` aaa +``` +"##; + let expected = r##"
    ``` aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_118() { + let original = r##"
    +
    +**Hello**,
    +
    +_world_.
    +
    +
    +"##; + let expected = r##"
    +
    +**Hello**,
    +

    world. +

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_119() { + let original = r##" + + + +
    + hi +
    + +okay. +"##; + let expected = r##" + + + +
    + hi +
    +

    okay.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_120() { + let original = r##"
    +*foo* +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_122() { + let original = r##"
    + +*Markdown* + +
    +"##; + let expected = r##"
    +

    Markdown

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_123() { + let original = r##"
    +
    +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_124() { + let original = r##"
    +
    +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_125() { + let original = r##"
    +*foo* + +*bar* +"##; + let expected = r##"
    +*foo* +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_126() { + let original = r##"
    +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_130() { + let original = r##"
    +foo +
    +"##; + let expected = r##"
    +foo +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_131() { + let original = r##"
    +``` c +int x = 33; +``` +"##; + let expected = r##"
    +``` c +int x = 33; +``` +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_132() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_133() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_134() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_135() { + let original = r##" +*bar* +"##; + let expected = r##" +*bar* +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_136() { + let original = r##" +*foo* + +"##; + let expected = r##" +*foo* + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_137() { + let original = r##" + +*foo* + + +"##; + let expected = r##" +

    foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_138() { + let original = r##"*foo* +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_139() { + let original = r##"
    
    +import Text.HTML.TagSoup
    +
    +main :: IO ()
    +main = print $ parseTags tags
    +
    +okay +"##; + let expected = r##"
    
    +import Text.HTML.TagSoup
    +
    +main :: IO ()
    +main = print $ parseTags tags
    +
    +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_140() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_141() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_142() { + let original = r##" +*foo* +"##; + let expected = r##" +

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_146() { + let original = r##"*bar* +*baz* +"##; + let expected = r##"*bar* +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_147() { + let original = r##"1. *bar* +"##; + let expected = r##"1. *bar* +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_148() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_149() { + let original = r##"'; + +?> +okay +"##; + let expected = r##"'; + +?> +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_150() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_151() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_152() { + let original = r##" + + +"##; + let expected = r##" +
    <!-- foo -->
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_153() { + let original = r##"
    + +
    +"##; + let expected = r##"
    +
    <div>
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_154() { + let original = r##"Foo +
    +bar +
    +"##; + let expected = r##"

    Foo

    +
    +bar +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_155() { + let original = r##"
    +bar +
    +*foo* +"##; + let expected = r##"
    +bar +
    +*foo* +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_156() { + let original = r##"Foo + +baz +"##; + let expected = r##"

    Foo + +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_157() { + let original = r##"
    + +*Emphasized* text. + +
    +"##; + let expected = r##"
    +

    Emphasized text.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_158() { + let original = r##"
    +*Emphasized* text. +
    +"##; + let expected = r##"
    +*Emphasized* text. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_159() { + let original = r##" + + + + + + + +
    +Hi +
    +"##; + let expected = r##" + + + +
    +Hi +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_160() { + let original = r##" + + + + + + + +
    + Hi +
    +"##; + let expected = r##" + +
    <td>
    +  Hi
    +</td>
    +
    + +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_161() { + let original = r##"[foo]: /url "title" + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_162() { + let original = r##" [foo]: + /url + 'the title' + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_163() { + let original = r##"[Foo*bar\]]:my_(url) 'title (with parens)' + +[Foo*bar\]] +"##; + let expected = r##"

    Foo*bar]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_164() { + let original = r##"[Foo bar]: + +'title' + +[Foo bar] +"##; + let expected = r##"

    Foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_165() { + let original = r##"[foo]: /url ' +title +line1 +line2 +' + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_166() { + let original = r##"[foo]: /url 'title + +with blank line' + +[foo] +"##; + let expected = r##"

    [foo]: /url 'title

    +

    with blank line'

    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_167() { + let original = r##"[foo]: +/url + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_168() { + let original = r##"[foo]: + +[foo] +"##; + let expected = r##"

    [foo]:

    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_169() { + let original = r##"[foo]: <> + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_170() { + let original = r##"[foo]: (baz) + +[foo] +"##; + let expected = r##"

    [foo]: (baz)

    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_171() { + let original = r##"[foo]: /url\bar\*baz "foo\"bar\baz" + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_172() { + let original = r##"[foo] + +[foo]: url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_173() { + let original = r##"[foo] + +[foo]: first +[foo]: second +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_174() { + let original = r##"[FOO]: /url + +[Foo] +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_175() { + let original = r##"[ΑΓΩ]: /φου + +[αγω] +"##; + let expected = r##"

    αγω

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_176() { + let original = r##"[foo]: /url +"##; + let expected = r##""##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_177() { + let original = r##"[ +foo +]: /url +bar +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_178() { + let original = r##"[foo]: /url "title" ok +"##; + let expected = r##"

    [foo]: /url "title" ok

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_179() { + let original = r##"[foo]: /url +"title" ok +"##; + let expected = r##"

    "title" ok

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_180() { + let original = r##" [foo]: /url "title" + +[foo] +"##; + let expected = r##"
    [foo]: /url "title"
    +
    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_181() { + let original = r##"``` +[foo]: /url +``` + +[foo] +"##; + let expected = r##"
    [foo]: /url
    +
    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_182() { + let original = r##"Foo +[bar]: /baz + +[bar] +"##; + let expected = r##"

    Foo +[bar]: /baz

    +

    [bar]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_183() { + let original = r##"# [Foo] +[foo]: /url +> bar +"##; + let expected = r##"

    Foo

    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_184() { + let original = r##"[foo]: /url +bar +=== +[foo] +"##; + let expected = r##"

    bar

    +

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_185() { + let original = r##"[foo]: /url +=== +[foo] +"##; + let expected = r##"

    === +foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_186() { + let original = r##"[foo]: /foo-url "foo" +[bar]: /bar-url + "bar" +[baz]: /baz-url + +[foo], +[bar], +[baz] +"##; + let expected = r##"

    foo, +bar, +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_187() { + let original = r##"[foo] + +> [foo]: /url +"##; + let expected = r##"

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_188() { + let original = r##"[foo]: /url +"##; + let expected = r##""##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_189() { + let original = r##"aaa + +bbb +"##; + let expected = r##"

    aaa

    +

    bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_190() { + let original = r##"aaa +bbb + +ccc +ddd +"##; + let expected = r##"

    aaa +bbb

    +

    ccc +ddd

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_191() { + let original = r##"aaa + + +bbb +"##; + let expected = r##"

    aaa

    +

    bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_192() { + let original = r##" aaa + bbb +"##; + let expected = r##"

    aaa +bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_193() { + let original = r##"aaa + bbb + ccc +"##; + let expected = r##"

    aaa +bbb +ccc

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_194() { + let original = r##" aaa +bbb +"##; + let expected = r##"

    aaa +bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_195() { + let original = r##" aaa +bbb +"##; + let expected = r##"
    aaa
    +
    +

    bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_196() { + let original = r##"aaa +bbb +"##; + let expected = r##"

    aaa
    +bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_197() { + let original = r##" + +aaa + + +# aaa + + +"##; + let expected = r##"

    aaa

    +

    aaa

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_198() { + let original = r##"> # Foo +> bar +> baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_199() { + let original = r##"># Foo +>bar +> baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_200() { + let original = r##" > # Foo + > bar + > baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_201() { + let original = r##" > # Foo + > bar + > baz +"##; + let expected = r##"
    > # Foo
    +> bar
    +> baz
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_202() { + let original = r##"> # Foo +> bar +baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_203() { + let original = r##"> bar +baz +> foo +"##; + let expected = r##"
    +

    bar +baz +foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_204() { + let original = r##"> foo +--- +"##; + let expected = r##"
    +

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_205() { + let original = r##"> - foo +- bar +"##; + let expected = r##"
    +
      +
    • foo
    • +
    +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_206() { + let original = r##"> foo + bar +"##; + let expected = r##"
    +
    foo
    +
    +
    +
    bar
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_207() { + let original = r##"> ``` +foo +``` +"##; + let expected = r##"
    +
    +
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_208() { + let original = r##"> foo + - bar +"##; + let expected = r##"
    +

    foo +- bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_209() { + let original = r##"> +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_210() { + let original = r##"> +> +> +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_211() { + let original = r##"> +> foo +> +"##; + let expected = r##"
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_212() { + let original = r##"> foo + +> bar +"##; + let expected = r##"
    +

    foo

    +
    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_213() { + let original = r##"> foo +> bar +"##; + let expected = r##"
    +

    foo +bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_214() { + let original = r##"> foo +> +> bar +"##; + let expected = r##"
    +

    foo

    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_215() { + let original = r##"foo +> bar +"##; + let expected = r##"

    foo

    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_216() { + let original = r##"> aaa +*** +> bbb +"##; + let expected = r##"
    +

    aaa

    +
    +
    +
    +

    bbb

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_217() { + let original = r##"> bar +baz +"##; + let expected = r##"
    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_218() { + let original = r##"> bar + +baz +"##; + let expected = r##"
    +

    bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_219() { + let original = r##"> bar +> +baz +"##; + let expected = r##"
    +

    bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_220() { + let original = r##"> > > foo +bar +"##; + let expected = r##"
    +
    +
    +

    foo +bar

    +
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_221() { + let original = r##">>> foo +> bar +>>baz +"##; + let expected = r##"
    +
    +
    +

    foo +bar +baz

    +
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_222() { + let original = r##"> code + +> not code +"##; + let expected = r##"
    +
    code
    +
    +
    +
    +

    not code

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_223() { + let original = r##"A paragraph +with two lines. + + indented code + +> A block quote. +"##; + let expected = r##"

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_224() { + let original = r##"1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_225() { + let original = r##"- one + + two +"##; + let expected = r##"
      +
    • one
    • +
    +

    two

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_226() { + let original = r##"- one + + two +"##; + let expected = r##"
      +
    • +

      one

      +

      two

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_227() { + let original = r##" - one + + two +"##; + let expected = r##"
      +
    • one
    • +
    +
     two
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_228() { + let original = r##" - one + + two +"##; + let expected = r##"
      +
    • +

      one

      +

      two

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_229() { + let original = r##" > > 1. one +>> +>> two +"##; + let expected = r##"
    +
    +
      +
    1. +

      one

      +

      two

      +
    2. +
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_230() { + let original = r##">>- one +>> + > > two +"##; + let expected = r##"
    +
    +
      +
    • one
    • +
    +

    two

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_231() { + let original = r##"-one + +2.two +"##; + let expected = r##"

    -one

    +

    2.two

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_232() { + let original = r##"- foo + + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_233() { + let original = r##"1. foo + + ``` + bar + ``` + + baz + + > bam +"##; + let expected = r##"
      +
    1. +

      foo

      +
      bar
      +
      +

      baz

      +
      +

      bam

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_234() { + let original = r##"- Foo + + bar + + + baz +"##; + let expected = r##"
      +
    • +

      Foo

      +
      bar
      +
      +
      +baz
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_235() { + let original = r##"123456789. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_236() { + let original = r##"1234567890. not ok +"##; + let expected = r##"

    1234567890. not ok

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_237() { + let original = r##"0. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_238() { + let original = r##"003. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_239() { + let original = r##"-1. not ok +"##; + let expected = r##"

    -1. not ok

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_240() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +
      bar
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_241() { + let original = r##" 10. foo + + bar +"##; + let expected = r##"
      +
    1. +

      foo

      +
      bar
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_242() { + let original = r##" indented code + +paragraph + + more code +"##; + let expected = r##"
    indented code
    +
    +

    paragraph

    +
    more code
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_243() { + let original = r##"1. indented code + + paragraph + + more code +"##; + let expected = r##"
      +
    1. +
      indented code
      +
      +

      paragraph

      +
      more code
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_244() { + let original = r##"1. indented code + + paragraph + + more code +"##; + let expected = r##"
      +
    1. +
       indented code
      +
      +

      paragraph

      +
      more code
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_245() { + let original = r##" foo + +bar +"##; + let expected = r##"

    foo

    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_246() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • foo
    • +
    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_247() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_248() { + let original = r##"- + foo +- + ``` + bar + ``` +- + baz +"##; + let expected = r##"
      +
    • foo
    • +
    • +
      bar
      +
      +
    • +
    • +
      baz
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_249() { + let original = r##"- + foo +"##; + let expected = r##"
      +
    • foo
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_250() { + let original = r##"- + + foo +"##; + let expected = r##"
      +
    • +
    +

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_251() { + let original = r##"- foo +- +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_252() { + let original = r##"- foo +- +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_253() { + let original = r##"1. foo +2. +3. bar +"##; + let expected = r##"
      +
    1. foo
    2. +
    3. +
    4. bar
    5. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_254() { + let original = r##"* +"##; + let expected = r##"
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_255() { + let original = r##"foo +* + +foo +1. +"##; + let expected = r##"

    foo +*

    +

    foo +1.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_256() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_257() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_258() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_259() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
    1.  A paragraph
    +    with two lines.
    +
    +        indented code
    +
    +    > A block quote.
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_260() { + let original = r##" 1. A paragraph +with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_261() { + let original = r##" 1. A paragraph + with two lines. +"##; + let expected = r##"
      +
    1. A paragraph +with two lines.
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_262() { + let original = r##"> 1. > Blockquote +continued here. +"##; + let expected = r##"
    +
      +
    1. +
      +

      Blockquote +continued here.

      +
      +
    2. +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_263() { + let original = r##"> 1. > Blockquote +> continued here. +"##; + let expected = r##"
    +
      +
    1. +
      +

      Blockquote +continued here.

      +
      +
    2. +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_264() { + let original = r##"- foo + - bar + - baz + - boo +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • baz +
            +
          • boo
          • +
          +
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_265() { + let original = r##"- foo + - bar + - baz + - boo +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    • baz
    • +
    • boo
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_266() { + let original = r##"10) foo + - bar +"##; + let expected = r##"
      +
    1. foo +
        +
      • bar
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_267() { + let original = r##"10) foo + - bar +"##; + let expected = r##"
      +
    1. foo
    2. +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_268() { + let original = r##"- - foo +"##; + let expected = r##"
      +
    • +
        +
      • foo
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_269() { + let original = r##"1. - 2. foo +"##; + let expected = r##"
      +
    1. +
        +
      • +
          +
        1. foo
        2. +
        +
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_270() { + let original = r##"- # Foo +- Bar + --- + baz +"##; + let expected = r##"
      +
    • +

      Foo

      +
    • +
    • +

      Bar

      +baz
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_271() { + let original = r##"- foo +- bar ++ baz +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    +
      +
    • baz
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_272() { + let original = r##"1. foo +2. bar +3) baz +"##; + let expected = r##"
      +
    1. foo
    2. +
    3. bar
    4. +
    +
      +
    1. baz
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_273() { + let original = r##"Foo +- bar +- baz +"##; + let expected = r##"

    Foo

    +
      +
    • bar
    • +
    • baz
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_274() { + let original = r##"The number of windows in my house is +14. The number of doors is 6. +"##; + let expected = r##"

    The number of windows in my house is +14. The number of doors is 6.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_275() { + let original = r##"The number of windows in my house is +1. The number of doors is 6. +"##; + let expected = r##"

    The number of windows in my house is

    +
      +
    1. The number of doors is 6.
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_276() { + let original = r##"- foo + +- bar + + +- baz +"##; + let expected = r##"
      +
    • +

      foo

      +
    • +
    • +

      bar

      +
    • +
    • +

      baz

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_277() { + let original = r##"- foo + - bar + - baz + + + bim +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • +

          baz

          +

          bim

          +
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_278() { + let original = r##"- foo +- bar + + + +- baz +- bim +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    + +
      +
    • baz
    • +
    • bim
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_279() { + let original = r##"- foo + + notcode + +- foo + + + + code +"##; + let expected = r##"
      +
    • +

      foo

      +

      notcode

      +
    • +
    • +

      foo

      +
    • +
    + +
    code
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_280() { + let original = r##"- a + - b + - c + - d + - e + - f +- g +"##; + let expected = r##"
      +
    • a
    • +
    • b
    • +
    • c
    • +
    • d
    • +
    • e
    • +
    • f
    • +
    • g
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_281() { + let original = r##"1. a + + 2. b + + 3. c +"##; + let expected = r##"
      +
    1. +

      a

      +
    2. +
    3. +

      b

      +
    4. +
    5. +

      c

      +
    6. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_282() { + let original = r##"- a + - b + - c + - d + - e +"##; + let expected = r##"
      +
    • a
    • +
    • b
    • +
    • c
    • +
    • d +- e
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_283() { + let original = r##"1. a + + 2. b + + 3. c +"##; + let expected = r##"
      +
    1. +

      a

      +
    2. +
    3. +

      b

      +
    4. +
    +
    3. c
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_284() { + let original = r##"- a +- b + +- c +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +
    • +
    • +

      c

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_285() { + let original = r##"* a +* + +* c +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +
    • +

      c

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_286() { + let original = r##"- a +- b + + c +- d +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +

      c

      +
    • +
    • +

      d

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_287() { + let original = r##"- a +- b + + [ref]: /url +- d +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +
    • +
    • +

      d

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_288() { + let original = r##"- a +- ``` + b + + + ``` +- c +"##; + let expected = r##"
      +
    • a
    • +
    • +
      b
      +
      +
      +
      +
    • +
    • c
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_289() { + let original = r##"- a + - b + + c +- d +"##; + let expected = r##"
      +
    • a +
        +
      • +

        b

        +

        c

        +
      • +
      +
    • +
    • d
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_290() { + let original = r##"* a + > b + > +* c +"##; + let expected = r##"
      +
    • a +
      +

      b

      +
      +
    • +
    • c
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_291() { + let original = r##"- a + > b + ``` + c + ``` +- d +"##; + let expected = r##"
      +
    • a +
      +

      b

      +
      +
      c
      +
      +
    • +
    • d
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_292() { + let original = r##"- a +"##; + let expected = r##"
      +
    • a
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_293() { + let original = r##"- a + - b +"##; + let expected = r##"
      +
    • a +
        +
      • b
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_294() { + let original = r##"1. ``` + foo + ``` + + bar +"##; + let expected = r##"
      +
    1. +
      foo
      +
      +

      bar

      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_295() { + let original = r##"* foo + * bar + + baz +"##; + let expected = r##"
      +
    • +

      foo

      +
        +
      • bar
      • +
      +

      baz

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_296() { + let original = r##"- a + - b + - c + +- d + - e + - f +"##; + let expected = r##"
      +
    • +

      a

      +
        +
      • b
      • +
      • c
      • +
      +
    • +
    • +

      d

      +
        +
      • e
      • +
      • f
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_297() { + let original = r##"`hi`lo` +"##; + let expected = r##"

    hilo`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_298() { + let original = r##"\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ +"##; + let expected = r##"

    !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_299() { + let original = r##"\ \A\a\ \3\φ\« +"##; + let expected = r##"

    \ \A\a\ \3\φ\«

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_300() { + let original = r##"\*not emphasized* +\
    not a tag +\[not a link](/foo) +\`not code` +1\. not a list +\* not a list +\# not a heading +\[foo]: /url "not a reference" +\ö not a character entity +"##; + let expected = r##"

    *not emphasized* +<br/> not a tag +[not a link](/foo) +`not code` +1. not a list +* not a list +# not a heading +[foo]: /url "not a reference" +&ouml; not a character entity

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_301() { + let original = r##"\\*emphasis* +"##; + let expected = r##"

    \emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_302() { + let original = r##"foo\ +bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_303() { + let original = r##"`` \[\` `` +"##; + let expected = r##"

    \[\`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_304() { + let original = r##" \[\] +"##; + let expected = r##"
    \[\]
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_305() { + let original = r##"~~~ +\[\] +~~~ +"##; + let expected = r##"
    \[\]
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_306() { + let original = r##" +"##; + let expected = r##"

    http://example.com?find=\*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_307() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_308() { + let original = r##"[foo](/bar\* "ti\*tle") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_309() { + let original = r##"[foo] + +[foo]: /bar\* "ti\*tle" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_310() { + let original = r##"``` foo\+bar +foo +``` +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_311() { + let original = r##"  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸ +"##; + let expected = r##"

      & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_312() { + let original = r##"# Ӓ Ϡ � +"##; + let expected = r##"

    # Ӓ Ϡ �

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_313() { + let original = r##"" ആ ಫ +"##; + let expected = r##"

    " ആ ಫ

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_314() { + let original = r##"  &x; &#; &#x; +� +&#abcdef0; +&ThisIsNotDefined; &hi?; +"##; + let expected = r##"

    &nbsp &x; &#; &#x; +&#87654321; +&#abcdef0; +&ThisIsNotDefined; &hi?;

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_315() { + let original = r##"© +"##; + let expected = r##"

    &copy

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_316() { + let original = r##"&MadeUpEntity; +"##; + let expected = r##"

    &MadeUpEntity;

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_317() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_318() { + let original = r##"[foo](/föö "föö") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_319() { + let original = r##"[foo] + +[foo]: /föö "föö" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_320() { + let original = r##"``` föö +foo +``` +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_321() { + let original = r##"`föö` +"##; + let expected = r##"

    f&ouml;&ouml;

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_322() { + let original = r##" föfö +"##; + let expected = r##"
    f&ouml;f&ouml;
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_323() { + let original = r##"*foo* +*foo* +"##; + let expected = r##"

    *foo* +foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_324() { + let original = r##"* foo + +* foo +"##; + let expected = r##"

    * foo

    +
      +
    • foo
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_325() { + let original = r##"foo bar +"##; + let expected = r##"

    foo + +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_326() { + let original = r##" foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_327() { + let original = r##"[a](url "tit") +"##; + let expected = r##"

    [a](url "tit")

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_328() { + let original = r##"`foo` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_329() { + let original = r##"`` foo ` bar `` +"##; + let expected = r##"

    foo ` bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_330() { + let original = r##"` `` ` +"##; + let expected = r##"

    ``

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_331() { + let original = r##"` `` ` +"##; + let expected = r##"

    ``

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_332() { + let original = r##"` a` +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_333() { + let original = r##"` b ` +"##; + let expected = r##"

     b 

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_334() { + let original = r##"` ` +` ` +"##; + let expected = r##"

      +

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_335() { + let original = r##"`` +foo +bar +baz +`` +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_336() { + let original = r##"`` +foo +`` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_337() { + let original = r##"`foo bar +baz` +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_338() { + let original = r##"`foo\`bar` +"##; + let expected = r##"

    foo\bar`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_339() { + let original = r##"``foo`bar`` +"##; + let expected = r##"

    foo`bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_340() { + let original = r##"` foo `` bar ` +"##; + let expected = r##"

    foo `` bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_341() { + let original = r##"*foo`*` +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_342() { + let original = r##"[not a `link](/foo`) +"##; + let expected = r##"

    [not a link](/foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_343() { + let original = r##"`` +"##; + let expected = r##"

    <a href="">`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_344() { + let original = r##"
    ` +"##; + let expected = r##"

    `

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_345() { + let original = r##"`` +"##; + let expected = r##"

    <http://foo.bar.baz>`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_346() { + let original = r##"` +"##; + let expected = r##"

    http://foo.bar.`baz`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_347() { + let original = r##"```foo`` +"##; + let expected = r##"

    ```foo``

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_348() { + let original = r##"`foo +"##; + let expected = r##"

    `foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_349() { + let original = r##"`foo``bar`` +"##; + let expected = r##"

    `foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_350() { + let original = r##"*foo bar* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_351() { + let original = r##"a * foo bar* +"##; + let expected = r##"

    a * foo bar*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_352() { + let original = r##"a*"foo"* +"##; + let expected = r##"

    a*"foo"*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_353() { + let original = r##"* a * +"##; + let expected = r##"

    * a *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_354() { + let original = r##"foo*bar* +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_355() { + let original = r##"5*6*78 +"##; + let expected = r##"

    5678

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_356() { + let original = r##"_foo bar_ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_357() { + let original = r##"_ foo bar_ +"##; + let expected = r##"

    _ foo bar_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_358() { + let original = r##"a_"foo"_ +"##; + let expected = r##"

    a_"foo"_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_359() { + let original = r##"foo_bar_ +"##; + let expected = r##"

    foo_bar_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_360() { + let original = r##"5_6_78 +"##; + let expected = r##"

    5_6_78

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_361() { + let original = r##"пристаням_стремятся_ +"##; + let expected = r##"

    пристаням_стремятся_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_362() { + let original = r##"aa_"bb"_cc +"##; + let expected = r##"

    aa_"bb"_cc

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_363() { + let original = r##"foo-_(bar)_ +"##; + let expected = r##"

    foo-(bar)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_364() { + let original = r##"_foo* +"##; + let expected = r##"

    _foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_365() { + let original = r##"*foo bar * +"##; + let expected = r##"

    *foo bar *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_366() { + let original = r##"*foo bar +* +"##; + let expected = r##"

    *foo bar +*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_367() { + let original = r##"*(*foo) +"##; + let expected = r##"

    *(*foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_368() { + let original = r##"*(*foo*)* +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_369() { + let original = r##"*foo*bar +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_370() { + let original = r##"_foo bar _ +"##; + let expected = r##"

    _foo bar _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_371() { + let original = r##"_(_foo) +"##; + let expected = r##"

    _(_foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_372() { + let original = r##"_(_foo_)_ +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_373() { + let original = r##"_foo_bar +"##; + let expected = r##"

    _foo_bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_374() { + let original = r##"_пристаням_стремятся +"##; + let expected = r##"

    _пристаням_стремятся

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_375() { + let original = r##"_foo_bar_baz_ +"##; + let expected = r##"

    foo_bar_baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_376() { + let original = r##"_(bar)_. +"##; + let expected = r##"

    (bar).

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_377() { + let original = r##"**foo bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_378() { + let original = r##"** foo bar** +"##; + let expected = r##"

    ** foo bar**

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_379() { + let original = r##"a**"foo"** +"##; + let expected = r##"

    a**"foo"**

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_380() { + let original = r##"foo**bar** +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_381() { + let original = r##"__foo bar__ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_382() { + let original = r##"__ foo bar__ +"##; + let expected = r##"

    __ foo bar__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_383() { + let original = r##"__ +foo bar__ +"##; + let expected = r##"

    __ +foo bar__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_384() { + let original = r##"a__"foo"__ +"##; + let expected = r##"

    a__"foo"__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_385() { + let original = r##"foo__bar__ +"##; + let expected = r##"

    foo__bar__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_386() { + let original = r##"5__6__78 +"##; + let expected = r##"

    5__6__78

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_387() { + let original = r##"пристаням__стремятся__ +"##; + let expected = r##"

    пристаням__стремятся__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_388() { + let original = r##"__foo, __bar__, baz__ +"##; + let expected = r##"

    foo, bar, baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_389() { + let original = r##"foo-__(bar)__ +"##; + let expected = r##"

    foo-(bar)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_390() { + let original = r##"**foo bar ** +"##; + let expected = r##"

    **foo bar **

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_391() { + let original = r##"**(**foo) +"##; + let expected = r##"

    **(**foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_392() { + let original = r##"*(**foo**)* +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_393() { + let original = r##"**Gomphocarpus (*Gomphocarpus physocarpus*, syn. +*Asclepias physocarpa*)** +"##; + let expected = r##"

    Gomphocarpus (Gomphocarpus physocarpus, syn. +Asclepias physocarpa)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_394() { + let original = r##"**foo "*bar*" foo** +"##; + let expected = r##"

    foo "bar" foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_395() { + let original = r##"**foo**bar +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_396() { + let original = r##"__foo bar __ +"##; + let expected = r##"

    __foo bar __

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_397() { + let original = r##"__(__foo) +"##; + let expected = r##"

    __(__foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_398() { + let original = r##"_(__foo__)_ +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_399() { + let original = r##"__foo__bar +"##; + let expected = r##"

    __foo__bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_400() { + let original = r##"__пристаням__стремятся +"##; + let expected = r##"

    __пристаням__стремятся

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_401() { + let original = r##"__foo__bar__baz__ +"##; + let expected = r##"

    foo__bar__baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_402() { + let original = r##"__(bar)__. +"##; + let expected = r##"

    (bar).

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_403() { + let original = r##"*foo [bar](/url)* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_404() { + let original = r##"*foo +bar* +"##; + let expected = r##"

    foo +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_405() { + let original = r##"_foo __bar__ baz_ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_406() { + let original = r##"_foo _bar_ baz_ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_407() { + let original = r##"__foo_ bar_ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_408() { + let original = r##"*foo *bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_409() { + let original = r##"*foo **bar** baz* +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_410() { + let original = r##"*foo**bar**baz* +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_411() { + let original = r##"*foo**bar* +"##; + let expected = r##"

    foo**bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_412() { + let original = r##"***foo** bar* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_413() { + let original = r##"*foo **bar*** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_414() { + let original = r##"*foo**bar*** +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_415() { + let original = r##"foo***bar***baz +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_416() { + let original = r##"foo******bar*********baz +"##; + let expected = r##"

    foobar***baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_417() { + let original = r##"*foo **bar *baz* bim** bop* +"##; + let expected = r##"

    foo bar baz bim bop

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_418() { + let original = r##"*foo [*bar*](/url)* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_419() { + let original = r##"** is not an empty emphasis +"##; + let expected = r##"

    ** is not an empty emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_420() { + let original = r##"**** is not an empty strong emphasis +"##; + let expected = r##"

    **** is not an empty strong emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_421() { + let original = r##"**foo [bar](/url)** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_422() { + let original = r##"**foo +bar** +"##; + let expected = r##"

    foo +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_423() { + let original = r##"__foo _bar_ baz__ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_424() { + let original = r##"__foo __bar__ baz__ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_425() { + let original = r##"____foo__ bar__ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_426() { + let original = r##"**foo **bar**** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_427() { + let original = r##"**foo *bar* baz** +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_428() { + let original = r##"**foo*bar*baz** +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_429() { + let original = r##"***foo* bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_430() { + let original = r##"**foo *bar*** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_431() { + let original = r##"**foo *bar **baz** +bim* bop** +"##; + let expected = r##"

    foo bar baz +bim bop

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_432() { + let original = r##"**foo [*bar*](/url)** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_433() { + let original = r##"__ is not an empty emphasis +"##; + let expected = r##"

    __ is not an empty emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_434() { + let original = r##"____ is not an empty strong emphasis +"##; + let expected = r##"

    ____ is not an empty strong emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_435() { + let original = r##"foo *** +"##; + let expected = r##"

    foo ***

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_436() { + let original = r##"foo *\** +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_437() { + let original = r##"foo *_* +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_438() { + let original = r##"foo ***** +"##; + let expected = r##"

    foo *****

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_439() { + let original = r##"foo **\*** +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_440() { + let original = r##"foo **_** +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_441() { + let original = r##"**foo* +"##; + let expected = r##"

    *foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_442() { + let original = r##"*foo** +"##; + let expected = r##"

    foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_443() { + let original = r##"***foo** +"##; + let expected = r##"

    *foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_444() { + let original = r##"****foo* +"##; + let expected = r##"

    ***foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_445() { + let original = r##"**foo*** +"##; + let expected = r##"

    foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_446() { + let original = r##"*foo**** +"##; + let expected = r##"

    foo***

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_447() { + let original = r##"foo ___ +"##; + let expected = r##"

    foo ___

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_448() { + let original = r##"foo _\__ +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_449() { + let original = r##"foo _*_ +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_450() { + let original = r##"foo _____ +"##; + let expected = r##"

    foo _____

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_451() { + let original = r##"foo __\___ +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_452() { + let original = r##"foo __*__ +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_453() { + let original = r##"__foo_ +"##; + let expected = r##"

    _foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_454() { + let original = r##"_foo__ +"##; + let expected = r##"

    foo_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_455() { + let original = r##"___foo__ +"##; + let expected = r##"

    _foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_456() { + let original = r##"____foo_ +"##; + let expected = r##"

    ___foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_457() { + let original = r##"__foo___ +"##; + let expected = r##"

    foo_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_458() { + let original = r##"_foo____ +"##; + let expected = r##"

    foo___

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_459() { + let original = r##"**foo** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_460() { + let original = r##"*_foo_* +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_461() { + let original = r##"__foo__ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_462() { + let original = r##"_*foo*_ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_463() { + let original = r##"****foo**** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_464() { + let original = r##"____foo____ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_465() { + let original = r##"******foo****** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_466() { + let original = r##"***foo*** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_467() { + let original = r##"_____foo_____ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_468() { + let original = r##"*foo _bar* baz_ +"##; + let expected = r##"

    foo _bar baz_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_469() { + let original = r##"*foo __bar *baz bim__ bam* +"##; + let expected = r##"

    foo bar *baz bim bam

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_470() { + let original = r##"**foo **bar baz** +"##; + let expected = r##"

    **foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_471() { + let original = r##"*foo *bar baz* +"##; + let expected = r##"

    *foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_472() { + let original = r##"*[bar*](/url) +"##; + let expected = r##"

    *bar*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_473() { + let original = r##"_foo [bar_](/url) +"##; + let expected = r##"

    _foo bar_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_474() { + let original = r##"* +"##; + let expected = r##"

    *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_475() { + let original = r##"** +"##; + let expected = r##"

    **

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_476() { + let original = r##"__ +"##; + let expected = r##"

    __

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_477() { + let original = r##"*a `*`* +"##; + let expected = r##"

    a *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_478() { + let original = r##"_a `_`_ +"##; + let expected = r##"

    a _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_479() { + let original = r##"**a +"##; + let expected = r##"

    **ahttp://foo.bar/?q=**

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_480() { + let original = r##"__a +"##; + let expected = r##"

    __ahttp://foo.bar/?q=__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_481() { + let original = r##"[link](/uri "title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_482() { + let original = r##"[link](/uri) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_483() { + let original = r##"[link]() +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_484() { + let original = r##"[link](<>) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_485() { + let original = r##"[link](/my uri) +"##; + let expected = r##"

    [link](/my uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_486() { + let original = r##"[link](
    ) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_487() { + let original = r##"[link](foo +bar) +"##; + let expected = r##"

    [link](foo +bar)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_488() { + let original = r##"[link]() +"##; + let expected = r##"

    [link]()

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_489() { + let original = r##"[a]() +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_490() { + let original = r##"[link]() +"##; + let expected = r##"

    [link](<foo>)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_491() { + let original = r##"[a]( +[a](c) +"##; + let expected = r##"

    [a](<b)c +[a](<b)c> +[a](c)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_492() { + let original = r##"[link](\(foo\)) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_493() { + let original = r##"[link](foo(and(bar))) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_494() { + let original = r##"[link](foo\(and\(bar\)) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_495() { + let original = r##"[link]() +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_496() { + let original = r##"[link](foo\)\:) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_497() { + let original = r##"[link](#fragment) + +[link](http://example.com#fragment) + +[link](http://example.com?foo=3#frag) +"##; + let expected = r##"

    link

    +

    link

    +

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_498() { + let original = r##"[link](foo\bar) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_499() { + let original = r##"[link](foo%20bä) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_500() { + let original = r##"[link]("title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_501() { + let original = r##"[link](/url "title") +[link](/url 'title') +[link](/url (title)) +"##; + let expected = r##"

    link +link +link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_502() { + let original = r##"[link](/url "title \""") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_503() { + let original = r##"[link](/url "title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_504() { + let original = r##"[link](/url "title "and" title") +"##; + let expected = r##"

    [link](/url "title "and" title")

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_505() { + let original = r##"[link](/url 'title "and" title') +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_506() { + let original = r##"[link]( /uri + "title" ) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_507() { + let original = r##"[link] (/uri) +"##; + let expected = r##"

    [link] (/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_508() { + let original = r##"[link [foo [bar]]](/uri) +"##; + let expected = r##"

    link [foo [bar]]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_509() { + let original = r##"[link] bar](/uri) +"##; + let expected = r##"

    [link] bar](/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_510() { + let original = r##"[link [bar](/uri) +"##; + let expected = r##"

    [link bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_511() { + let original = r##"[link \[bar](/uri) +"##; + let expected = r##"

    link [bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_512() { + let original = r##"[link *foo **bar** `#`*](/uri) +"##; + let expected = r##"

    link foo bar #

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_513() { + let original = r##"[![moon](moon.jpg)](/uri) +"##; + let expected = r##"

    moon

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_514() { + let original = r##"[foo [bar](/uri)](/uri) +"##; + let expected = r##"

    [foo bar](/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_515() { + let original = r##"[foo *[bar [baz](/uri)](/uri)*](/uri) +"##; + let expected = r##"

    [foo [bar baz](/uri)](/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_516() { + let original = r##"![[[foo](uri1)](uri2)](uri3) +"##; + let expected = r##"

    [foo](uri2)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_517() { + let original = r##"*[foo*](/uri) +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_518() { + let original = r##"[foo *bar](baz*) +"##; + let expected = r##"

    foo *bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_519() { + let original = r##"*foo [bar* baz] +"##; + let expected = r##"

    foo [bar baz]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_520() { + let original = r##"[foo +"##; + let expected = r##"

    [foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_521() { + let original = r##"[foo`](/uri)` +"##; + let expected = r##"

    [foo](/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_522() { + let original = r##"[foo +"##; + let expected = r##"

    [foohttp://example.com/?search=](uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_523() { + let original = r##"[foo][bar] + +[bar]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_524() { + let original = r##"[link [foo [bar]]][ref] + +[ref]: /uri +"##; + let expected = r##"

    link [foo [bar]]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_525() { + let original = r##"[link \[bar][ref] + +[ref]: /uri +"##; + let expected = r##"

    link [bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_526() { + let original = r##"[link *foo **bar** `#`*][ref] + +[ref]: /uri +"##; + let expected = r##"

    link foo bar #

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_527() { + let original = r##"[![moon](moon.jpg)][ref] + +[ref]: /uri +"##; + let expected = r##"

    moon

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_528() { + let original = r##"[foo [bar](/uri)][ref] + +[ref]: /uri +"##; + let expected = r##"

    [foo bar]ref

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_529() { + let original = r##"[foo *bar [baz][ref]*][ref] + +[ref]: /uri +"##; + let expected = r##"

    [foo bar baz]ref

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_530() { + let original = r##"*[foo*][ref] + +[ref]: /uri +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_531() { + let original = r##"[foo *bar][ref] + +[ref]: /uri +"##; + let expected = r##"

    foo *bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_532() { + let original = r##"[foo + +[ref]: /uri +"##; + let expected = r##"

    [foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_533() { + let original = r##"[foo`][ref]` + +[ref]: /uri +"##; + let expected = r##"

    [foo][ref]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_534() { + let original = r##"[foo + +[ref]: /uri +"##; + let expected = r##"

    [foohttp://example.com/?search=][ref]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_535() { + let original = r##"[foo][BaR] + +[bar]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_536() { + let original = r##"[Толпой][Толпой] is a Russian word. + +[ТОЛПОЙ]: /url +"##; + let expected = r##"

    Толпой is a Russian word.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_537() { + let original = r##"[Foo + bar]: /url + +[Baz][Foo bar] +"##; + let expected = r##"

    Baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_538() { + let original = r##"[foo] [bar] + +[bar]: /url "title" +"##; + let expected = r##"

    [foo] bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_539() { + let original = r##"[foo] +[bar] + +[bar]: /url "title" +"##; + let expected = r##"

    [foo] +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_540() { + let original = r##"[foo]: /url1 + +[foo]: /url2 + +[bar][foo] +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_541() { + let original = r##"[bar][foo\!] + +[foo!]: /url +"##; + let expected = r##"

    [bar][foo!]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_542() { + let original = r##"[foo][ref[] + +[ref[]: /uri +"##; + let expected = r##"

    [foo][ref[]

    +

    [ref[]: /uri

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_543() { + let original = r##"[foo][ref[bar]] + +[ref[bar]]: /uri +"##; + let expected = r##"

    [foo][ref[bar]]

    +

    [ref[bar]]: /uri

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_544() { + let original = r##"[[[foo]]] + +[[[foo]]]: /url +"##; + let expected = r##"

    [[[foo]]]

    +

    [[[foo]]]: /url

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_545() { + let original = r##"[foo][ref\[] + +[ref\[]: /uri +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_546() { + let original = r##"[bar\\]: /uri + +[bar\\] +"##; + let expected = r##"

    bar\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_547() { + let original = r##"[] + +[]: /uri +"##; + let expected = r##"

    []

    +

    []: /uri

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_548() { + let original = r##"[ + ] + +[ + ]: /uri +"##; + let expected = r##"

    [ +]

    +

    [ +]: /uri

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_549() { + let original = r##"[foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_550() { + let original = r##"[*foo* bar][] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_551() { + let original = r##"[Foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_552() { + let original = r##"[foo] +[] + +[foo]: /url "title" +"##; + let expected = r##"

    foo +[]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_553() { + let original = r##"[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_554() { + let original = r##"[*foo* bar] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_555() { + let original = r##"[[*foo* bar]] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    [foo bar]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_556() { + let original = r##"[[bar [foo] + +[foo]: /url +"##; + let expected = r##"

    [[bar foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_557() { + let original = r##"[Foo] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_558() { + let original = r##"[foo] bar + +[foo]: /url +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_559() { + let original = r##"\[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_560() { + let original = r##"[foo*]: /url + +*[foo*] +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_561() { + let original = r##"[foo][bar] + +[foo]: /url1 +[bar]: /url2 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_562() { + let original = r##"[foo][] + +[foo]: /url1 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_563() { + let original = r##"[foo]() + +[foo]: /url1 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_564() { + let original = r##"[foo](not a link) + +[foo]: /url1 +"##; + let expected = r##"

    foo(not a link)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_565() { + let original = r##"[foo][bar][baz] + +[baz]: /url +"##; + let expected = r##"

    [foo]bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_566() { + let original = r##"[foo][bar][baz] + +[baz]: /url1 +[bar]: /url2 +"##; + let expected = r##"

    foobaz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_567() { + let original = r##"[foo][bar][baz] + +[baz]: /url1 +[foo]: /url2 +"##; + let expected = r##"

    [foo]bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_568() { + let original = r##"![foo](/url "title") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_569() { + let original = r##"![foo *bar*] + +[foo *bar*]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_570() { + let original = r##"![foo ![bar](/url)](/url2) +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_571() { + let original = r##"![foo [bar](/url)](/url2) +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_572() { + let original = r##"![foo *bar*][] + +[foo *bar*]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_573() { + let original = r##"![foo *bar*][foobar] + +[FOOBAR]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_574() { + let original = r##"![foo](train.jpg) +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_575() { + let original = r##"My ![foo bar](/path/to/train.jpg "title" ) +"##; + let expected = r##"

    My foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_576() { + let original = r##"![foo]() +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_577() { + let original = r##"![](/url) +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_578() { + let original = r##"![foo][bar] + +[bar]: /url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_579() { + let original = r##"![foo][bar] + +[BAR]: /url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_580() { + let original = r##"![foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_581() { + let original = r##"![*foo* bar][] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_582() { + let original = r##"![Foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_583() { + let original = r##"![foo] +[] + +[foo]: /url "title" +"##; + let expected = r##"

    foo +[]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_584() { + let original = r##"![foo] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_585() { + let original = r##"![*foo* bar] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_586() { + let original = r##"![[foo]] + +[[foo]]: /url "title" +"##; + let expected = r##"

    ![[foo]]

    +

    [[foo]]: /url "title"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_587() { + let original = r##"![Foo] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_588() { + let original = r##"!\[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    ![foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_589() { + let original = r##"\![foo] + +[foo]: /url "title" +"##; + let expected = r##"

    !foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_590() { + let original = r##" +"##; + let expected = r##"

    http://foo.bar.baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_591() { + let original = r##" +"##; + let expected = r##"

    http://foo.bar.baz/test?q=hello&id=22&boolean

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_592() { + let original = r##" +"##; + let expected = r##"

    irc://foo.bar:2233/baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_593() { + let original = r##" +"##; + let expected = r##"

    MAILTO:FOO@BAR.BAZ

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_594() { + let original = r##" +"##; + let expected = r##"

    a+b+c:d

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_595() { + let original = r##" +"##; + let expected = r##"

    made-up-scheme://foo,bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_596() { + let original = r##" +"##; + let expected = r##"

    http://../

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_597() { + let original = r##" +"##; + let expected = r##"

    localhost:5001/foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_598() { + let original = r##" +"##; + let expected = r##"

    <http://foo.bar/baz bim>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_599() { + let original = r##" +"##; + let expected = r##"

    http://example.com/\[\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_600() { + let original = r##" +"##; + let expected = r##"

    foo@bar.example.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_601() { + let original = r##" +"##; + let expected = r##"

    foo+special@Bar.baz-bar0.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_602() { + let original = r##" +"##; + let expected = r##"

    <foo+@bar.example.com>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_603() { + let original = r##"<> +"##; + let expected = r##"

    <>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_604() { + let original = r##"< http://foo.bar > +"##; + let expected = r##"

    < http://foo.bar >

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_605() { + let original = r##" +"##; + let expected = r##"

    <m:abc>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_606() { + let original = r##" +"##; + let expected = r##"

    <foo.bar.baz>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_607() { + let original = r##"http://example.com +"##; + let expected = r##"

    http://example.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_608() { + let original = r##"foo@bar.example.com +"##; + let expected = r##"

    foo@bar.example.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_609() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_610() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_611() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_612() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_613() { + let original = r##"Foo +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_614() { + let original = r##"<33> <__> +"##; + let expected = r##"

    <33> <__>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_615() { + let original = r##"
    +"##; + let expected = r##"

    <a h*#ref="hi">

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_616() { + let original = r##"
    <a href="hi'> <a href=hi'>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_617() { + let original = r##"< a>< +foo> + +"##; + let expected = r##"

    < a>< +foo><bar/ > +<foo bar=baz +bim!bop />

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_618() { + let original = r##"
    +"##; + let expected = r##"

    <a href='bar'title=title>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_619() { + let original = r##"
    +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_620() { + let original = r##" +"##; + let expected = r##"

    </a href="foo">

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_621() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_622() { + let original = r##"foo +"##; + let expected = r##"

    foo <!-- not a comment -- two hyphens -->

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_623() { + let original = r##"foo foo --> + +foo +"##; + let expected = r##"

    foo <!--> foo -->

    +

    foo <!-- foo--->

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_624() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_625() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_626() { + let original = r##"foo &<]]> +"##; + let expected = r##"

    foo &<]]>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_627() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_628() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_629() { + let original = r##" +"##; + let expected = r##"

    <a href=""">

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_630() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_631() { + let original = r##"foo\ +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_632() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_633() { + let original = r##"foo + bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_634() { + let original = r##"foo\ + bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_635() { + let original = r##"*foo +bar* +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_636() { + let original = r##"*foo\ +bar* +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_637() { + let original = r##"`code +span` +"##; + let expected = r##"

    code span

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_638() { + let original = r##"`code\ +span` +"##; + let expected = r##"

    code\ span

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_639() { + let original = r##"
    +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_640() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_641() { + let original = r##"foo\ +"##; + let expected = r##"

    foo\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_642() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_643() { + let original = r##"### foo\ +"##; + let expected = r##"

    foo\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_644() { + let original = r##"### foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_645() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_646() { + let original = r##"foo + baz +"##; + let expected = r##"

    foo +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_647() { + let original = r##"hello $.;'there +"##; + let expected = r##"

    hello $.;'there

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_648() { + let original = r##"Foo χρῆν +"##; + let expected = r##"

    Foo χρῆν

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_649() { + let original = r##"Multiple spaces +"##; + let expected = r##"

    Multiple spaces

    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/table.rs b/vendor/pulldown-cmark/tests/suite/table.rs index de4d2f65dc..c034955e1d 100644 --- a/vendor/pulldown-cmark/tests/suite/table.rs +++ b/vendor/pulldown-cmark/tests/suite/table.rs @@ -1,205 +1,205 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn table_test_1() { - let original = r##"Test header ------------ -"##; - let expected = r##"

    Test header

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_2() { - let original = r##"Test|Table -----|----- -"##; - let expected = r##" -
    TestTable
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_3() { - let original = r##"> Test | Table -> ------|------ -> Row 1 | Every -> Row 2 | Day -> -> Paragraph -"##; - let expected = r##"
    - - - -
    Test Table
    Row 1 Every
    Row 2 Day
    -

    Paragraph

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_4() { - let original = r##" 1. First entry - 2. Second entry - - Col 1|Col 2 - -|- - Row 1|Part 2 - Row 2|Part 2 -"##; - let expected = r##"
      -
    1. -

      First entry

      -
    2. -
    3. -

      Second entry

      - - - -
      Col 1Col 2
      Row 1Part 2
      Row 2Part 2
      -
    4. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_5() { - let original = r##"|Col 1|Col 2| -|-----|-----| -|R1C1 |R1C2 | -|R2C1 |R2C2 | -"##; - let expected = r##" - - -
    Col 1Col 2
    R1C1 R1C2
    R2C1 R2C2
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_6() { - let original = r##"| Col 1 | Col 2 | -|-------|-------| -| | | -| | | -"##; - let expected = r##" - - -
    Col 1 Col 2
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_7() { - let original = r##"| Col 1 | Col 2 | -|-------|-------| -| x | | -| | x | -"##; - let expected = r##" - - -
    Col 1 Col 2
    x
    x
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_8() { - let original = r##"|Col 1|Col 2| -|-----|-----| -|✓ |✓ | -|✓ |✓ | -"##; - let expected = r##" - - -
    Col 1Col 2
    ✓ ✓
    ✓ ✓
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_9() { - let original = r##"| Target | std |rustc|cargo| notes | -|-------------------------------|-----|-----|-----|----------------------------| -| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | -| `arm-linux-androideabi` | ✓ | | | ARM Android | -| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) | -| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | | ARM Linux (2.6.18+) | -| `aarch64-unknown-linux-gnu` | ✓ | | | ARM64 Linux (2.6.18+) | -| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | -| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | -"##; - let expected = r##" - - - - - - - -
    Target std rustccargo notes
    x86_64-unknown-linux-musl ✓ 64-bit Linux with MUSL
    arm-linux-androideabi ✓ ARM Android
    arm-unknown-linux-gnueabi ✓ ✓ ARM Linux (2.6.18+)
    arm-unknown-linux-gnueabihf ✓ ✓ ARM Linux (2.6.18+)
    aarch64-unknown-linux-gnu ✓ ARM64 Linux (2.6.18+)
    mips-unknown-linux-gnu ✓ MIPS Linux (2.6.18+)
    mipsel-unknown-linux-gnu ✓ MIPS (LE) Linux (2.6.18+)
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_10() { - let original = r##"|-|-| -|ぃ|い| -"##; - let expected = r##"

    |-|-| -|ぃ|い|

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_11() { - let original = r##"|ぁ|ぃ| -|-|-| -|ぃ|ぃ| -"##; - let expected = r##" - -
    ぁぃ
    ぃぃ
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_12() { - let original = r##"|Колонка 1|Колонка 2| -|---------|---------| -|Ячейка 1 |Ячейка 2 | -"##; - let expected = r##" - -
    Колонка 1Колонка 2
    Ячейка 1 Ячейка 2
    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn table_test_1() { + let original = r##"Test header +----------- +"##; + let expected = r##"

    Test header

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_2() { + let original = r##"Test|Table +----|----- +"##; + let expected = r##" +
    TestTable
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_3() { + let original = r##"> Test | Table +> ------|------ +> Row 1 | Every +> Row 2 | Day +> +> Paragraph +"##; + let expected = r##"
    + + + +
    Test Table
    Row 1 Every
    Row 2 Day
    +

    Paragraph

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_4() { + let original = r##" 1. First entry + 2. Second entry + + Col 1|Col 2 + -|- + Row 1|Part 2 + Row 2|Part 2 +"##; + let expected = r##"
      +
    1. +

      First entry

      +
    2. +
    3. +

      Second entry

      + + + +
      Col 1Col 2
      Row 1Part 2
      Row 2Part 2
      +
    4. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_5() { + let original = r##"|Col 1|Col 2| +|-----|-----| +|R1C1 |R1C2 | +|R2C1 |R2C2 | +"##; + let expected = r##" + + +
    Col 1Col 2
    R1C1 R1C2
    R2C1 R2C2
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_6() { + let original = r##"| Col 1 | Col 2 | +|-------|-------| +| | | +| | | +"##; + let expected = r##" + + +
    Col 1 Col 2
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_7() { + let original = r##"| Col 1 | Col 2 | +|-------|-------| +| x | | +| | x | +"##; + let expected = r##" + + +
    Col 1 Col 2
    x
    x
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_8() { + let original = r##"|Col 1|Col 2| +|-----|-----| +|✓ |✓ | +|✓ |✓ | +"##; + let expected = r##" + + +
    Col 1Col 2
    ✓ ✓
    ✓ ✓
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_9() { + let original = r##"| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | +| `arm-linux-androideabi` | ✓ | | | ARM Android | +| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `aarch64-unknown-linux-gnu` | ✓ | | | ARM64 Linux (2.6.18+) | +| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | +| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | +"##; + let expected = r##" + + + + + + + +
    Target std rustccargo notes
    x86_64-unknown-linux-musl ✓ 64-bit Linux with MUSL
    arm-linux-androideabi ✓ ARM Android
    arm-unknown-linux-gnueabi ✓ ✓ ARM Linux (2.6.18+)
    arm-unknown-linux-gnueabihf ✓ ✓ ARM Linux (2.6.18+)
    aarch64-unknown-linux-gnu ✓ ARM64 Linux (2.6.18+)
    mips-unknown-linux-gnu ✓ MIPS Linux (2.6.18+)
    mipsel-unknown-linux-gnu ✓ MIPS (LE) Linux (2.6.18+)
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_10() { + let original = r##"|-|-| +|ぃ|い| +"##; + let expected = r##"

    |-|-| +|ぃ|い|

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_11() { + let original = r##"|ぁ|ぃ| +|-|-| +|ぃ|ぃ| +"##; + let expected = r##" + +
    ぁぃ
    ぃぃ
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_12() { + let original = r##"|Колонка 1|Колонка 2| +|---------|---------| +|Ячейка 1 |Ячейка 2 | +"##; + let expected = r##" + +
    Колонка 1Колонка 2
    Ячейка 1 Ячейка 2
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/rayon-core/.cargo-checksum.json b/vendor/rayon-core/.cargo-checksum.json index 7599f18f25..f770100278 100644 --- a/vendor/rayon-core/.cargo-checksum.json +++ b/vendor/rayon-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"a83d5bb197e911851b02a0f9335e627a445f3241e380f405e75a67f1f7682b51","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"32fe5dcb2c1d89c475ea8bf098477fef95863c3551b7633f4071eaf1bd039de4","build.rs":"fa31cb198b772600d100a7c403ddedccef637d2e6b2da431fa7f02ca41307fc6","src/compile_fail/mod.rs":"4d70256295bd64691a8c1994b323559cda1888e85f0b45ca55711541c257dcb6","src/compile_fail/quicksort_race1.rs":"35f498cda38f4eb6e00117f78ed68e0fe5a3fa61c25303d9c08a19bda345bc6c","src/compile_fail/quicksort_race2.rs":"cbb40030c7867cae34bb373b6ec5d97c2ac6de39bc917f47879b30eb423924bc","src/compile_fail/quicksort_race3.rs":"8403643e64c969306b1a9b1243378e6ccdd313b57e1878dbd31393618082fd35","src/compile_fail/rc_return.rs":"b6f1f821ef30086e2990db1ac58a92adaf31e57c23c587c7746d6303865c5c0f","src/compile_fail/rc_upvar.rs":"92a799b313fb88a0eb83fc1aaaea4b61604222b45e20f1c22ff5b092a03f8620","src/compile_fail/scope_join_bad.rs":"892959949f77cadfc07458473e7a290301182027ca64428df5a8ce887be0892b","src/job.rs":"8477aa1041881e6e0256c2d138c0731f6881a6f7dbe619db61e6f8c668a87790","src/join/mod.rs":"cde5393089286f606e45c5e0a735ca45e715a57b5ea0e50d00b784a010b01be3","src/join/test.rs":"9fbb741f97e38f7b69e63d81183e96dadb585bf5694335fed13af3090b1d3f76","src/latch.rs":"f99f146b34ab22e700abeda39d8f44d8ab8d6deefcb4ef134a1ea4155c5bc69d","src/lib.rs":"9fc60649122276044cc4f5733a253c76f03fd69ea39416bf79eb9f1fd9f3e6c8","src/log.rs":"d628635e157e36f5f6107015d660948392af30a76795674ab8a781f297c3b1c6","src/private.rs":"702ff02a2d0846d6d97b4164c7b4c2fbab2157ba5ba9c31fea5f1775ff3c9597","src/registry.rs":"51461cbc64b1e5eb9880e843a800f1b1daed7ebb8b6e6f0f8de53e3bea2298fb","src/scope/mod.rs":"00e4566dfb6e76cda555b02af18670820ee568a941946b9da9034c160653109f","src/scope/test.rs":"2980222cfabc132483333e4c8bae10ce2e8cc3770079cdc0ec79486ba05499ca","src/sleep/README.md":"34a83cd8a0f84e58472af5c40744794139fbfe22a392f0dc6eb90cfdf9389119","src/sleep/mod.rs":"de97a2f92166eec84380addddce530fc3eb8fa29f1af7824457d0823aa369a68","src/spawn/mod.rs":"60b71a325bfd90a334c7c7fa331463eab67e72375709161ef68448b9db76d296","src/spawn/test.rs":"463e39211a1b3829954ed0e486145c510d4dcf6718c2daf9a2594ae05c3eb98f","src/test.rs":"edf421670c2b3b440971fdfa20139c11e7506a4cca14c4e36ccb76d073027521","src/thread_pool/mod.rs":"252fb18f5fe9e3a7971a6bad2878168224f2d6016f5c991685e8a5c6e571da8b","src/thread_pool/test.rs":"d201a19541be093adcdcde9b8e659f3d4f018296b0d1abe7c0cbc4aa14625755","src/unwind.rs":"7baa4511467d008b14856ea8de7ced92b9251c9df4854f69c81f7efc3cf0cd6c","src/util.rs":"7b58c4aeb37b5e8a38f1028a673f06e712f6e9976a6fe938c05e06ead1c22469","tests/double_init_fail.rs":"f6f6e1b45bdba6ef8f18d1981e5356a6d5ef2f3bbecd0c8ce4341c126a3a6f1d","tests/init_zero_threads.rs":"57f66d1662f7782848d45942faa613a608188eb400943e4efa4c3ec3375e1dac","tests/scope_join.rs":"56f570c4b6a01704aacf93e7f17f89fe0f40f46ed6f9ede517abfe9adaf91f83","tests/scoped_threadpool.rs":"0f6475f440a57b6f91ecdd720228395f4feaa6165b136558f65267e185fd7127","tests/simple_panic.rs":"916d40d36c1a0fad3e1dfb31550f0672641feab4b03d480f039143dbe2f2445f","tests/stack_overflow_crash.rs":"e8865d33d51a58f5c6639f457d91f82f2a4379cf5129094eaa521e95bad72d51"},"package":"e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280"} \ No newline at end of file +{"files":{"Cargo.toml":"68535b85775c95dca419153c119059a13b3c2720ff219ca264c3928592743dde","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"32fe5dcb2c1d89c475ea8bf098477fef95863c3551b7633f4071eaf1bd039de4","build.rs":"fa31cb198b772600d100a7c403ddedccef637d2e6b2da431fa7f02ca41307fc6","src/compile_fail/mod.rs":"4d70256295bd64691a8c1994b323559cda1888e85f0b45ca55711541c257dcb6","src/compile_fail/quicksort_race1.rs":"35f498cda38f4eb6e00117f78ed68e0fe5a3fa61c25303d9c08a19bda345bc6c","src/compile_fail/quicksort_race2.rs":"cbb40030c7867cae34bb373b6ec5d97c2ac6de39bc917f47879b30eb423924bc","src/compile_fail/quicksort_race3.rs":"8403643e64c969306b1a9b1243378e6ccdd313b57e1878dbd31393618082fd35","src/compile_fail/rc_return.rs":"b6f1f821ef30086e2990db1ac58a92adaf31e57c23c587c7746d6303865c5c0f","src/compile_fail/rc_upvar.rs":"92a799b313fb88a0eb83fc1aaaea4b61604222b45e20f1c22ff5b092a03f8620","src/compile_fail/scope_join_bad.rs":"892959949f77cadfc07458473e7a290301182027ca64428df5a8ce887be0892b","src/job.rs":"f6b439551ea723f8657be9971ce5f42660e1a2bb743e226e3255887056770264","src/join/mod.rs":"91f58385a3fc5a62187df32338595a479df5aee08f8af08e5066dbc2488bacf4","src/join/test.rs":"9fbb741f97e38f7b69e63d81183e96dadb585bf5694335fed13af3090b1d3f76","src/latch.rs":"7a5fed3838d2446c7cd5608a6c3e2ff682cf5f9c8c84d0e902008f700f5ef39d","src/lib.rs":"aa8eb221c63a02b9bccb3314b1be24fe55e644e0e2e413360a5b875ecbc27442","src/log.rs":"8a25ed8661f5ae3317085a108f78bb5f5a2e40827dbde9b16d6b8a560a5f2c39","src/private.rs":"152f6d65ce4741616a1dec796b9442f78a018d38bb040f76c4cd85008333a3bb","src/registry.rs":"b4e2a2d6f577564924c3d8c56083a270f78845f344f7d287f39b4bfe232ce369","src/scope/mod.rs":"5aad3a6dcb0e4e1c19699357f0db52186b0f711d1a455e135dd0423b13315c39","src/scope/test.rs":"2fb3f2a5011a29a6d5619368bfd517c447200839296094ff4b6605950973ab3c","src/sleep/README.md":"4714cd03a8c2be7648b5f48d85b121cc3bc39af6b65c025bfa34640d85af18d6","src/sleep/counters.rs":"b7c50ac0bd035d4b0342da92b0d422bf1f69e07b7a4b025af7d01b8a9b47ce46","src/sleep/mod.rs":"091da1b21c49559f0f3af9475340249d48534310f18051ed358b27fccf52b4a3","src/spawn/mod.rs":"255ea058f7b45f8f1d488fe3d4ae6b34669f294d174e2b8b9fb7a99450896491","src/spawn/test.rs":"463e39211a1b3829954ed0e486145c510d4dcf6718c2daf9a2594ae05c3eb98f","src/test.rs":"edf421670c2b3b440971fdfa20139c11e7506a4cca14c4e36ccb76d073027521","src/thread_pool/mod.rs":"f3389baf5500896fab4c41281b9f94c298d1e2db3c1d96938e5b604614d23934","src/thread_pool/test.rs":"737d5b77c8191ba3a103a7a09d8db253ca148edac9e040e688974f2ca4a5be18","src/unwind.rs":"7baa4511467d008b14856ea8de7ced92b9251c9df4854f69c81f7efc3cf0cd6c","src/util.rs":"7b58c4aeb37b5e8a38f1028a673f06e712f6e9976a6fe938c05e06ead1c22469","tests/double_init_fail.rs":"f6f6e1b45bdba6ef8f18d1981e5356a6d5ef2f3bbecd0c8ce4341c126a3a6f1d","tests/init_zero_threads.rs":"57f66d1662f7782848d45942faa613a608188eb400943e4efa4c3ec3375e1dac","tests/scope_join.rs":"56f570c4b6a01704aacf93e7f17f89fe0f40f46ed6f9ede517abfe9adaf91f83","tests/scoped_threadpool.rs":"0f6475f440a57b6f91ecdd720228395f4feaa6165b136558f65267e185fd7127","tests/simple_panic.rs":"916d40d36c1a0fad3e1dfb31550f0672641feab4b03d480f039143dbe2f2445f","tests/stack_overflow_crash.rs":"e8865d33d51a58f5c6639f457d91f82f2a4379cf5129094eaa521e95bad72d51"},"package":"91739a34c4355b5434ce54c9086c5895604a9c278586d1f1aa95e04f66b525a0"} \ No newline at end of file diff --git a/vendor/rayon-core/Cargo.toml b/vendor/rayon-core/Cargo.toml index a04e4aeda5..4e78ab9893 100644 --- a/vendor/rayon-core/Cargo.toml +++ b/vendor/rayon-core/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "rayon-core" -version = "1.7.1" +version = "1.8.0" authors = ["Niko Matsakis ", "Josh Stone "] build = "build.rs" links = "rayon-core" @@ -49,12 +49,12 @@ path = "tests/simple_panic.rs" [[test]] name = "scoped_threadpool" path = "tests/scoped_threadpool.rs" +[dependencies.crossbeam-channel] +version = "0.4.2" + [dependencies.crossbeam-deque] version = "0.7.2" -[dependencies.crossbeam-queue] -version = "0.2" - [dependencies.crossbeam-utils] version = "0.7" diff --git a/vendor/rayon-core/src/job.rs b/vendor/rayon-core/src/job.rs index 27510cff23..a71f1b0e96 100644 --- a/vendor/rayon-core/src/job.rs +++ b/vendor/rayon-core/src/job.rs @@ -1,6 +1,6 @@ use crate::latch::Latch; use crate::unwind; -use crossbeam_queue::SegQueue; +use crossbeam_deque::{Injector, Steal}; use std::any::Any; use std::cell::UnsafeCell; use std::mem; @@ -184,13 +184,13 @@ impl JobResult { /// Indirect queue to provide FIFO job priority. pub(super) struct JobFifo { - inner: SegQueue, + inner: Injector, } impl JobFifo { pub(super) fn new() -> Self { JobFifo { - inner: SegQueue::new(), + inner: Injector::new(), } } @@ -206,6 +206,12 @@ impl JobFifo { impl Job for JobFifo { unsafe fn execute(this: *const Self) { // We "execute" a queue by executing its first job, FIFO. - (*this).inner.pop().expect("job in fifo queue").execute() + loop { + match (*this).inner.steal() { + Steal::Success(job_ref) => break job_ref.execute(), + Steal::Empty => panic!("FIFO is empty"), + Steal::Retry => {} + } + } } } diff --git a/vendor/rayon-core/src/join/mod.rs b/vendor/rayon-core/src/join/mod.rs index 295f97bc22..d72c7e61c7 100644 --- a/vendor/rayon-core/src/join/mod.rs +++ b/vendor/rayon-core/src/join/mod.rs @@ -1,6 +1,5 @@ use crate::job::StackJob; -use crate::latch::{LatchProbe, SpinLatch}; -use crate::log::Event::*; +use crate::latch::SpinLatch; use crate::registry::{self, WorkerThread}; use crate::unwind; use std::any::Any; @@ -131,14 +130,10 @@ where } registry::in_worker(|worker_thread, injected| unsafe { - log!(Join { - worker: worker_thread.index() - }); - // Create virtual wrapper for task b; this all has to be // done here so that the stack frame can keep it all live // long enough. - let job_b = StackJob::new(call_b(oper_b), SpinLatch::new()); + let job_b = StackJob::new(call_b(oper_b), SpinLatch::new(worker_thread)); let job_b_ref = job_b.as_job_ref(); worker_thread.push(job_b_ref); @@ -160,23 +155,14 @@ where // Found it! Let's run it. // // Note that this could panic, but it's ok if we unwind here. - log!(PoppedRhs { - worker: worker_thread.index() - }); let result_b = job_b.run_inline(injected); return (result_a, result_b); } else { - log!(PoppedJob { - worker: worker_thread.index() - }); worker_thread.execute(job); } } else { // Local deque is empty. Time to steal from other // threads. - log!(LostJob { - worker: worker_thread.index() - }); worker_thread.wait_until(&job_b.latch); debug_assert!(job_b.latch.probe()); break; @@ -193,7 +179,7 @@ where #[cold] // cold path unsafe fn join_recover_from_panic( worker_thread: &WorkerThread, - job_b_latch: &SpinLatch, + job_b_latch: &SpinLatch<'_>, err: Box, ) -> ! { worker_thread.wait_until(job_b_latch); diff --git a/vendor/rayon-core/src/latch.rs b/vendor/rayon-core/src/latch.rs index fb6e44b00b..0965bb95a7 100644 --- a/vendor/rayon-core/src/latch.rs +++ b/vendor/rayon-core/src/latch.rs @@ -1,7 +1,8 @@ -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Condvar, Mutex}; +use std::usize; -use crate::registry::Registry; +use crate::registry::{Registry, WorkerThread}; /// We define various kinds of latches, which are all a primitive signaling /// mechanism. A latch starts as false. Eventually someone calls `set()` and @@ -29,43 +30,189 @@ use crate::registry::Registry; /// - Once `set()` occurs, the next `probe()` *will* observe it. This /// typically requires a seq-cst ordering. See [the "tickle-then-get-sleepy" scenario in the sleep /// README](/src/sleep/README.md#tickle-then-get-sleepy) for details. -pub(super) trait Latch: LatchProbe { +pub(super) trait Latch { /// Set the latch, signalling others. + /// + /// # WARNING + /// + /// Setting a latch triggers other threads to wake up and (in some + /// cases) complete. This may, in turn, cause memory to be + /// allocated and so forth. One must be very careful about this, + /// and it's typically better to read all the fields you will need + /// to access *before* a latch is set! fn set(&self); } -pub(super) trait LatchProbe { - /// Test if the latch is set. - fn probe(&self) -> bool; +pub(super) trait AsCoreLatch { + fn as_core_latch(&self) -> &CoreLatch; } +/// Latch is not set, owning thread is awake +const UNSET: usize = 0; + +/// Latch is not set, owning thread is going to sleep on this latch +/// (but has not yet fallen asleep). +const SLEEPY: usize = 1; + +/// Latch is not set, owning thread is asleep on this latch and +/// must be awoken. +const SLEEPING: usize = 2; + +/// Latch is set. +const SET: usize = 3; + /// Spin latches are the simplest, most efficient kind, but they do /// not support a `wait()` operation. They just have a boolean flag /// that becomes true when `set()` is called. -pub(super) struct SpinLatch { - b: AtomicBool, +#[derive(Debug)] +pub(super) struct CoreLatch { + state: AtomicUsize, } -impl SpinLatch { +impl CoreLatch { + #[inline] + fn new() -> Self { + Self { + state: AtomicUsize::new(0), + } + } + + /// Returns the address of this core latch as an integer. Used + /// for logging. + #[inline] + pub(super) fn addr(&self) -> usize { + self as *const CoreLatch as usize + } + + /// Invoked by owning thread as it prepares to sleep. Returns true + /// if the owning thread may proceed to fall asleep, false if the + /// latch was set in the meantime. + #[inline] + pub(super) fn get_sleepy(&self) -> bool { + self.state + .compare_exchange(UNSET, SLEEPY, Ordering::SeqCst, Ordering::Relaxed) + .is_ok() + } + + /// Invoked by owning thread as it falls asleep sleep. Returns + /// true if the owning thread should block, or false if the latch + /// was set in the meantime. + #[inline] + pub(super) fn fall_asleep(&self) -> bool { + self.state + .compare_exchange(SLEEPY, SLEEPING, Ordering::SeqCst, Ordering::Relaxed) + .is_ok() + } + + /// Invoked by owning thread as it falls asleep sleep. Returns + /// true if the owning thread should block, or false if the latch + /// was set in the meantime. + #[inline] + pub(super) fn wake_up(&self) { + if !self.probe() { + let _ = + self.state + .compare_exchange(SLEEPING, UNSET, Ordering::SeqCst, Ordering::Relaxed); + } + } + + /// Set the latch. If this returns true, the owning thread was sleeping + /// and must be awoken. + /// + /// This is private because, typically, setting a latch involves + /// doing some wakeups; those are encapsulated in the surrounding + /// latch code. + #[inline] + fn set(&self) -> bool { + let old_state = self.state.swap(SET, Ordering::AcqRel); + old_state == SLEEPING + } + + /// Test if this latch has been set. + #[inline] + pub(super) fn probe(&self) -> bool { + self.state.load(Ordering::Acquire) == SET + } +} + +/// Spin latches are the simplest, most efficient kind, but they do +/// not support a `wait()` operation. They just have a boolean flag +/// that becomes true when `set()` is called. +pub(super) struct SpinLatch<'r> { + core_latch: CoreLatch, + registry: &'r Arc, + target_worker_index: usize, + cross: bool, +} + +impl<'r> SpinLatch<'r> { + /// Creates a new spin latch that is owned by `thread`. This means + /// that `thread` is the only thread that should be blocking on + /// this latch -- it also means that when the latch is set, we + /// will wake `thread` if it is sleeping. + #[inline] + pub(super) fn new(thread: &'r WorkerThread) -> SpinLatch<'r> { + SpinLatch { + core_latch: CoreLatch::new(), + registry: thread.registry(), + target_worker_index: thread.index(), + cross: false, + } + } + + /// Creates a new spin latch for cross-threadpool blocking. Notably, we + /// need to make sure the registry is kept alive after setting, so we can + /// safely call the notification. #[inline] - pub(super) fn new() -> SpinLatch { + pub(super) fn cross(thread: &'r WorkerThread) -> SpinLatch<'r> { SpinLatch { - b: AtomicBool::new(false), + cross: true, + ..SpinLatch::new(thread) } } + + #[inline] + pub(super) fn probe(&self) -> bool { + self.core_latch.probe() + } } -impl LatchProbe for SpinLatch { +impl<'r> AsCoreLatch for SpinLatch<'r> { #[inline] - fn probe(&self) -> bool { - self.b.load(Ordering::SeqCst) + fn as_core_latch(&self) -> &CoreLatch { + &self.core_latch } } -impl Latch for SpinLatch { +impl<'r> Latch for SpinLatch<'r> { #[inline] fn set(&self) { - self.b.store(true, Ordering::SeqCst); + let cross_registry; + + let registry = if self.cross { + // Ensure the registry stays alive while we notify it. + // Otherwise, it would be possible that we set the spin + // latch and the other thread sees it and exits, causing + // the registry to be deallocated, all before we get a + // chance to invoke `registry.notify_worker_latch_is_set`. + cross_registry = Arc::clone(self.registry); + &cross_registry + } else { + // If this is not a "cross-registry" spin-latch, then the + // thread which is performing `set` is itself ensuring + // that the registry stays alive. + self.registry + }; + let target_worker_index = self.target_worker_index; + + // NOTE: Once we `set`, the target may proceed and invalidate `&self`! + if self.core_latch.set() { + // Subtle: at this point, we can no longer read from + // `self`, because the thread owning this spin latch may + // have awoken and deallocated the latch. Therefore, we + // only use fields whose values we already read. + registry.notify_worker_latch_is_set(target_worker_index); + } } } @@ -103,15 +250,6 @@ impl LockLatch { } } -impl LatchProbe for LockLatch { - #[inline] - fn probe(&self) -> bool { - // Not particularly efficient, but we don't really use this operation - let guard = self.m.lock().unwrap(); - *guard - } -} - impl Latch for LockLatch { #[inline] fn set(&self) { @@ -126,8 +264,19 @@ impl Latch for LockLatch { /// necessarily make the latch be considered `set()`; instead, it just /// decrements the counter. The latch is only "set" (in the sense that /// `probe()` returns true) once the counter reaches zero. +/// +/// Note: like a `SpinLatch`, count laches are always associated with +/// some registry that is probing them, which must be tickled when +/// they are set. *Unlike* a `SpinLatch`, they don't themselves hold a +/// reference to that registry. This is because in some cases the +/// registry owns the count-latch, and that would create a cycle. So a +/// `CountLatch` must be given a reference to its owning registry when +/// it is set. For this reason, it does not implement the `Latch` +/// trait (but it doesn't have to, as it is not used in those generic +/// contexts). #[derive(Debug)] pub(super) struct CountLatch { + core_latch: CoreLatch, counter: AtomicUsize, } @@ -135,77 +284,47 @@ impl CountLatch { #[inline] pub(super) fn new() -> CountLatch { CountLatch { + core_latch: CoreLatch::new(), counter: AtomicUsize::new(1), } } #[inline] pub(super) fn increment(&self) { - debug_assert!(!self.probe()); + debug_assert!(!self.core_latch.probe()); self.counter.fetch_add(1, Ordering::Relaxed); } -} - -impl LatchProbe for CountLatch { - #[inline] - fn probe(&self) -> bool { - // Need to acquire any memory reads before latch was set: - self.counter.load(Ordering::SeqCst) == 0 - } -} -impl Latch for CountLatch { - /// Set the latch to true, releasing all threads who are waiting. + /// Decrements the latch counter by one. If this is the final + /// count, then the latch is **set**, and calls to `probe()` will + /// return true. Returns whether the latch was set. This is an + /// internal operation, as it does not tickle, and to fail to + /// tickle would lead to deadlock. #[inline] - fn set(&self) { - self.counter.fetch_sub(1, Ordering::SeqCst); - } -} - -/// A tickling latch wraps another latch type, and will also awaken a thread -/// pool when it is set. This is useful for jobs injected between thread pools, -/// so the source pool can continue processing its own work while waiting. -pub(super) struct TickleLatch<'a, L: Latch> { - inner: L, - registry: &'a Arc, -} - -impl<'a, L: Latch> TickleLatch<'a, L> { - #[inline] - pub(super) fn new(latch: L, registry: &'a Arc) -> Self { - registry.increment_terminate_count(); - TickleLatch { - inner: latch, - registry, + fn set(&self) -> bool { + if self.counter.fetch_sub(1, Ordering::SeqCst) == 1 { + self.core_latch.set(); + true + } else { + false } } -} -impl<'a, L: Latch> LatchProbe for TickleLatch<'a, L> { + /// Decrements the latch counter by one and possibly set it. If + /// the latch is set, then the specific worker thread is tickled, + /// which should be the one that owns this latch. #[inline] - fn probe(&self) -> bool { - self.inner.probe() + pub(super) fn set_and_tickle_one(&self, registry: &Registry, target_worker_index: usize) { + if self.set() { + registry.notify_worker_latch_is_set(target_worker_index); + } } } -impl<'a, L: Latch> Latch for TickleLatch<'a, L> { +impl AsCoreLatch for CountLatch { #[inline] - fn set(&self) { - // Ensure the registry stays alive while we tickle it. - let registry = Arc::clone(self.registry); - - // NOTE: Once we `set`, the target may proceed and invalidate `&self`! - self.inner.set(); - registry.tickle(); - } -} - -impl<'a, L> LatchProbe for &'a L -where - L: LatchProbe, -{ - fn probe(&self) -> bool { - L::probe(self) + fn as_core_latch(&self) -> &CoreLatch { + &self.core_latch } } @@ -213,6 +332,7 @@ impl<'a, L> Latch for &'a L where L: Latch, { + #[inline] fn set(&self) { L::set(self); } diff --git a/vendor/rayon-core/src/lib.rs b/vendor/rayon-core/src/lib.rs index 639386ce2e..3c8a91a7cf 100644 --- a/vendor/rayon-core/src/lib.rs +++ b/vendor/rayon-core/src/lib.rs @@ -19,10 +19,11 @@ //! conflicting requirements will need to be resolved before the build will //! succeed. -#![doc(html_root_url = "https://docs.rs/rayon-core/1.7")] +#![doc(html_root_url = "https://docs.rs/rayon-core/1.8")] #![deny(missing_debug_implementations)] #![deny(missing_docs)] #![deny(unreachable_pub)] +#![warn(rust_2018_idioms)] use std::any::Any; use std::env; diff --git a/vendor/rayon-core/src/log.rs b/vendor/rayon-core/src/log.rs index 687370d0b5..e1ff827dfd 100644 --- a/vendor/rayon-core/src/log.rs +++ b/vendor/rayon-core/src/log.rs @@ -1,116 +1,423 @@ //! Debug Logging //! -//! To use in a debug build, set the env var `RAYON_LOG=1`. In a -//! release build, logs are compiled out. You will have to change -//! `DUMP_LOGS` to be `true`. +//! To use in a debug build, set the env var `RAYON_LOG` as +//! described below. In a release build, logs are compiled out by +//! default unless Rayon is built with `--cfg rayon_rs_log` (try +//! `RUSTFLAGS="--cfg rayon_rs_log"`). //! -//! **Old environment variable:** `RAYON_LOG` is a one-to-one -//! replacement of the now deprecated `RAYON_RS_LOG` environment -//! variable, which is still supported for backwards compatibility. +//! Note that logs are an internally debugging tool and their format +//! is considered unstable, as are the details of how to enable them. +//! +//! # Valid values for RAYON_LOG +//! +//! The `RAYON_LOG` variable can take on the following values: +//! +//! * `tail:` -- dumps the last 10,000 events into the given file; +//! useful for tracking down deadlocks +//! * `profile:` -- dumps only those events needed to reconstruct how +//! many workers are active at a given time +//! * `all:` -- dumps every event to the file; useful for debugging -#[cfg(debug_assertions)] +use crossbeam_channel::{self, Receiver, Sender}; +use std::collections::VecDeque; use std::env; +use std::fs::File; +use std::io::{self, BufWriter, Write}; + +/// True if logs are compiled in. +pub(super) const LOG_ENABLED: bool = cfg!(any(rayon_rs_log, debug_assertions)); -#[cfg_attr(debug_assertions, derive(Debug))] -#[cfg_attr(not(debug_assertions), allow(dead_code))] +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] pub(super) enum Event { - Tickle { - worker: usize, - old_state: usize, - }, - GetSleepy { - worker: usize, - state: usize, - }, - GotSleepy { - worker: usize, - old_state: usize, - new_state: usize, - }, - GotAwoken { - worker: usize, - }, - FellAsleep { - worker: usize, - }, - GotInterrupted { - worker: usize, - }, - FoundWork { - worker: usize, - yields: usize, - }, - DidNotFindWork { - worker: usize, - yields: usize, - }, - StoleWork { - worker: usize, - victim: usize, - }, - UninjectedWork { - worker: usize, - }, - WaitUntil { - worker: usize, - }, - LatchSet { - worker: usize, - }, - InjectJobs { - count: usize, - }, - Join { - worker: usize, - }, - PoppedJob { - worker: usize, - }, - PoppedRhs { + /// Flushes events to disk, used to terminate benchmarking. + Flush, + + /// Indicates that a worker thread started execution. + ThreadStart { worker: usize, + terminate_addr: usize, }, - LostJob { + + /// Indicates that a worker thread started execution. + ThreadTerminate { worker: usize }, + + /// Indicates that a worker thread became idle, blocked on `latch_addr`. + ThreadIdle { worker: usize, latch_addr: usize }, + + /// Indicates that an idle worker thread found work to do, after + /// yield rounds. It should no longer be considered idle. + ThreadFoundWork { worker: usize, yields: u32 }, + + /// Indicates that a worker blocked on a latch observed that it was set. + /// + /// Internal debugging event that does not affect the state + /// machine. + ThreadSawLatchSet { worker: usize, latch_addr: usize }, + + /// Indicates that an idle worker is getting sleepy. `sleepy_counter` is the internal + /// sleep state that we saw at the time. + ThreadSleepy { worker: usize, jobs_counter: usize }, + + /// Indicates that the thread's attempt to fall asleep was + /// interrupted because the latch was set. (This is not, in and of + /// itself, a change to the thread state.) + ThreadSleepInterruptedByLatch { worker: usize, latch_addr: usize }, + + /// Indicates that the thread's attempt to fall asleep was + /// interrupted because a job was posted. (This is not, in and of + /// itself, a change to the thread state.) + ThreadSleepInterruptedByJob { worker: usize }, + + /// Indicates that an idle worker has gone to sleep. + ThreadSleeping { worker: usize, latch_addr: usize }, + + /// Indicates that a sleeping worker has awoken. + ThreadAwoken { worker: usize, latch_addr: usize }, + + /// Indicates that the given worker thread was notified it should + /// awaken. + ThreadNotify { worker: usize }, + + /// The given worker has pushed a job to its local deque. + JobPushed { worker: usize }, + + /// The given worker has popped a job from its local deque. + JobPopped { worker: usize }, + + /// The given worker has stolen a job from the deque of another. + JobStolen { worker: usize, victim: usize }, + + /// N jobs were injected into the global queue. + JobsInjected { count: usize }, + + /// A job was removed from the global queue. + JobUninjected { worker: usize }, + + /// When announcing a job, this was the value of the counters we observed. + /// + /// No effect on thread state, just a debugging event. + JobThreadCounts { worker: usize, - }, - JobCompletedOk { - owner_thread: usize, - }, - JobPanickedErrorStored { - owner_thread: usize, - }, - JobPanickedErrorNotStored { - owner_thread: usize, - }, - ScopeCompletePanicked { - owner_thread: usize, - }, - ScopeCompleteNoPanic { - owner_thread: usize, + num_idle: u16, + num_sleepers: u16, }, } -#[cfg(debug_assertions)] -lazy_static::lazy_static! { - pub(super) static ref LOG_ENV: bool = - env::var("RAYON_LOG").is_ok() || env::var("RAYON_RS_LOG").is_ok(); +/// Handle to the logging thread, if any. You can use this to deliver +/// logs. You can also clone it freely. +#[derive(Clone)] +pub(super) struct Logger { + sender: Option>, } -#[cfg(debug_assertions)] -macro_rules! log { - ($event:expr) => { - if *$crate::log::LOG_ENV { - eprintln!("{:?}", $event); +impl Logger { + pub(super) fn new(num_workers: usize) -> Logger { + if !LOG_ENABLED { + return Self::disabled(); } - }; + + // see the doc comment for the format + let env_log = match env::var("RAYON_LOG") { + Ok(s) => s, + Err(_) => return Self::disabled(), + }; + + let (sender, receiver) = crossbeam_channel::unbounded(); + + if env_log.starts_with("tail:") { + let filename = env_log["tail:".len()..].to_string(); + ::std::thread::spawn(move || { + Self::tail_logger_thread(num_workers, filename, 10_000, receiver) + }); + } else if env_log == "all" { + ::std::thread::spawn(move || Self::all_logger_thread(num_workers, receiver)); + } else if env_log.starts_with("profile:") { + let filename = env_log["profile:".len()..].to_string(); + ::std::thread::spawn(move || { + Self::profile_logger_thread(num_workers, filename, 10_000, receiver) + }); + } else { + panic!("RAYON_LOG should be 'tail:' or 'profile:'"); + } + + return Logger { + sender: Some(sender), + }; + } + + fn disabled() -> Logger { + Logger { sender: None } + } + + #[inline] + pub(super) fn log(&self, event: impl FnOnce() -> Event) { + if !LOG_ENABLED { + return; + } + + if let Some(sender) = &self.sender { + sender.send(event()).unwrap(); + } + } + + fn profile_logger_thread( + num_workers: usize, + log_filename: String, + capacity: usize, + receiver: Receiver, + ) { + let file = File::create(&log_filename) + .unwrap_or_else(|err| panic!("failed to open `{}`: {}", log_filename, err)); + + let mut writer = BufWriter::new(file); + let mut events = Vec::with_capacity(capacity); + let mut state = SimulatorState::new(num_workers); + let timeout = std::time::Duration::from_secs(30); + + loop { + loop { + match receiver.recv_timeout(timeout) { + Ok(event) => { + if let Event::Flush = event { + break; + } else { + events.push(event); + } + } + + Err(_) => break, + } + + if events.len() == capacity { + break; + } + } + + for event in events.drain(..) { + if state.simulate(&event) { + state.dump(&mut writer, &event).unwrap(); + } + } + + writer.flush().unwrap(); + } + } + + fn tail_logger_thread( + num_workers: usize, + log_filename: String, + capacity: usize, + receiver: Receiver, + ) { + let file = File::create(&log_filename) + .unwrap_or_else(|err| panic!("failed to open `{}`: {}", log_filename, err)); + + let mut writer = BufWriter::new(file); + let mut events: VecDeque = VecDeque::with_capacity(capacity); + let mut state = SimulatorState::new(num_workers); + let timeout = std::time::Duration::from_secs(30); + let mut skipped = false; + + loop { + loop { + match receiver.recv_timeout(timeout) { + Ok(event) => { + if let Event::Flush = event { + // We ignore Flush events in tail mode -- + // we're really just looking for + // deadlocks. + continue; + } else { + if events.len() == capacity { + let event = events.pop_front().unwrap(); + state.simulate(&event); + skipped = true; + } + + events.push_back(event); + } + } + + Err(_) => break, + } + } + + if skipped { + write!(writer, "...\n").unwrap(); + skipped = false; + } + + for event in events.drain(..) { + // In tail mode, we dump *all* events out, whether or + // not they were 'interesting' to the state machine. + state.simulate(&event); + state.dump(&mut writer, &event).unwrap(); + } + + writer.flush().unwrap(); + } + } + + fn all_logger_thread(num_workers: usize, receiver: Receiver) { + let stderr = std::io::stderr(); + let mut state = SimulatorState::new(num_workers); + + for event in receiver { + let mut writer = BufWriter::new(stderr.lock()); + state.simulate(&event); + state.dump(&mut writer, &event).unwrap(); + writer.flush().unwrap(); + } + } +} + +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] +enum State { + Working, + Idle, + Notified, + Sleeping, + Terminated, } -#[cfg(not(debug_assertions))] -macro_rules! log { - ($event:expr) => { - if false { - // Expand `$event` so it still appears used, but without - // any of the formatting code to be optimized away. - $event; +impl State { + fn letter(&self) -> char { + match self { + State::Working => 'W', + State::Idle => 'I', + State::Notified => 'N', + State::Sleeping => 'S', + State::Terminated => 'T', } - }; + } +} + +struct SimulatorState { + local_queue_size: Vec, + thread_states: Vec, + injector_size: usize, +} + +impl SimulatorState { + fn new(num_workers: usize) -> Self { + Self { + local_queue_size: (0..num_workers).map(|_| 0).collect(), + thread_states: (0..num_workers).map(|_| State::Working).collect(), + injector_size: 0, + } + } + + fn simulate(&mut self, event: &Event) -> bool { + match *event { + Event::ThreadIdle { worker, .. } => { + assert_eq!(self.thread_states[worker], State::Working); + self.thread_states[worker] = State::Idle; + true + } + + Event::ThreadStart { worker, .. } | Event::ThreadFoundWork { worker, .. } => { + self.thread_states[worker] = State::Working; + true + } + + Event::ThreadTerminate { worker, .. } => { + self.thread_states[worker] = State::Terminated; + true + } + + Event::ThreadSleeping { worker, .. } => { + assert_eq!(self.thread_states[worker], State::Idle); + self.thread_states[worker] = State::Sleeping; + true + } + + Event::ThreadAwoken { worker, .. } => { + assert_eq!(self.thread_states[worker], State::Notified); + self.thread_states[worker] = State::Idle; + true + } + + Event::JobPushed { worker } => { + self.local_queue_size[worker] += 1; + true + } + + Event::JobPopped { worker } => { + self.local_queue_size[worker] -= 1; + true + } + + Event::JobStolen { victim, .. } => { + self.local_queue_size[victim] -= 1; + true + } + + Event::JobsInjected { count } => { + self.injector_size += count; + true + } + + Event::JobUninjected { .. } => { + self.injector_size -= 1; + true + } + + Event::ThreadNotify { worker } => { + // Currently, this log event occurs while holding the + // thread lock, so we should *always* see it before + // the worker awakens. + assert_eq!(self.thread_states[worker], State::Sleeping); + self.thread_states[worker] = State::Notified; + true + } + + // remaining events are no-ops from pov of simulating the + // thread state + _ => false, + } + } + + fn dump(&mut self, w: &mut impl Write, event: &Event) -> io::Result<()> { + let num_idle_threads = self + .thread_states + .iter() + .filter(|s| **s == State::Idle) + .count(); + + let num_sleeping_threads = self + .thread_states + .iter() + .filter(|s| **s == State::Sleeping) + .count(); + + let num_notified_threads = self + .thread_states + .iter() + .filter(|s| **s == State::Notified) + .count(); + + let num_pending_jobs: usize = self.local_queue_size.iter().sum(); + + write!(w, "{:2},", num_idle_threads)?; + write!(w, "{:2},", num_sleeping_threads)?; + write!(w, "{:2},", num_notified_threads)?; + write!(w, "{:4},", num_pending_jobs)?; + write!(w, "{:4},", self.injector_size)?; + + let event_str = format!("{:?}", event); + write!(w, r#""{:60}","#, event_str)?; + + for ((i, state), queue_size) in (0..).zip(&self.thread_states).zip(&self.local_queue_size) { + write!(w, " T{:02},{}", i, state.letter(),)?; + + if *queue_size > 0 { + write!(w, ",{:03},", queue_size)?; + } else { + write!(w, ", ,")?; + } + } + + write!(w, "\n")?; + Ok(()) + } } diff --git a/vendor/rayon-core/src/private.rs b/vendor/rayon-core/src/private.rs index a99dd11fb2..c85e77b9cb 100644 --- a/vendor/rayon-core/src/private.rs +++ b/vendor/rayon-core/src/private.rs @@ -14,7 +14,7 @@ macro_rules! private_decl { /// impossible to implement outside the crate. #[doc(hidden)] fn __rayon_private__(&self) -> crate::private::PrivateMarker; - } + }; } macro_rules! private_impl { @@ -22,5 +22,5 @@ macro_rules! private_impl { fn __rayon_private__(&self) -> crate::private::PrivateMarker { crate::private::PrivateMarker } - } + }; } diff --git a/vendor/rayon-core/src/registry.rs b/vendor/rayon-core/src/registry.rs index 5ef77e09d8..46ae10a20f 100644 --- a/vendor/rayon-core/src/registry.rs +++ b/vendor/rayon-core/src/registry.rs @@ -1,14 +1,14 @@ use crate::job::{JobFifo, JobRef, StackJob}; -use crate::latch::{CountLatch, Latch, LatchProbe, LockLatch, SpinLatch, TickleLatch}; +use crate::latch::{AsCoreLatch, CoreLatch, CountLatch, Latch, LockLatch, SpinLatch}; use crate::log::Event::*; +use crate::log::Logger; use crate::sleep::Sleep; use crate::unwind; use crate::util::leak; use crate::{ ErrorKind, ExitHandler, PanicHandler, StartHandler, ThreadPoolBuildError, ThreadPoolBuilder, }; -use crossbeam_deque::{Steal, Stealer, Worker}; -use crossbeam_queue::SegQueue; +use crossbeam_deque::{Injector, Steal, Stealer, Worker}; use std::any::Any; use std::cell::Cell; use std::collections::hash_map::DefaultHasher; @@ -132,9 +132,10 @@ where } pub(super) struct Registry { + logger: Logger, thread_infos: Vec, sleep: Sleep, - injected_jobs: SegQueue, + injected_jobs: Injector, panic_handler: Option>, start_handler: Option>, exit_handler: Option>, @@ -152,7 +153,7 @@ pub(super) struct Registry { // - when `join()` or `scope()` is invoked, similarly, no adjustments are needed. // These are always owned by some other job (e.g., one injected by `ThreadPool::install()`) // and that job will keep the pool alive. - terminate_latch: CountLatch, + terminate_count: AtomicUsize, } /// //////////////////////////////////////////////////////////////////////// @@ -233,11 +234,13 @@ impl Registry { }) .unzip(); + let logger = Logger::new(n_threads); let registry = Arc::new(Registry { + logger: logger.clone(), thread_infos: stealers.into_iter().map(ThreadInfo::new).collect(), - sleep: Sleep::new(), - injected_jobs: SegQueue::new(), - terminate_latch: CountLatch::new(), + sleep: Sleep::new(logger, n_threads), + injected_jobs: Injector::new(), + terminate_count: AtomicUsize::new(1), panic_handler: builder.take_panic_handler(), start_handler: builder.take_start_handler(), exit_handler: builder.take_exit_handler(), @@ -311,6 +314,11 @@ impl Registry { } } + #[inline] + pub(super) fn log(&self, event: impl FnOnce() -> crate::log::Event) { + self.logger.log(event) + } + pub(super) fn num_threads(&self) -> usize { self.thread_infos.len() } @@ -374,8 +382,8 @@ impl Registry { /// whatever worker has nothing to do. Use this is you know that /// you are not on a worker of this registry. pub(super) fn inject(&self, injected_jobs: &[JobRef]) { - log!(InjectJobs { - count: injected_jobs.len() + self.log(|| JobsInjected { + count: injected_jobs.len(), }); // It should not be possible for `state.terminate` to be true @@ -383,25 +391,39 @@ impl Registry { // drops) a `ThreadPool`; and, in that case, they cannot be // calling `inject()` later, since they dropped their // `ThreadPool`. - assert!( - !self.terminate_latch.probe(), + debug_assert_ne!( + self.terminate_count.load(Ordering::Acquire), + 0, "inject() sees state.terminate as true" ); + let queue_was_empty = self.injected_jobs.is_empty(); + for &job_ref in injected_jobs { self.injected_jobs.push(job_ref); } - self.sleep.tickle(usize::MAX); + + self.sleep + .new_injected_jobs(usize::MAX, injected_jobs.len() as u32, queue_was_empty); + } + + fn has_injected_job(&self) -> bool { + !self.injected_jobs.is_empty() } fn pop_injected_job(&self, worker_index: usize) -> Option { - let job = self.injected_jobs.pop().ok(); - if job.is_some() { - log!(UninjectedWork { - worker: worker_index - }); + loop { + match self.injected_jobs.steal() { + Steal::Success(job) => { + self.log(|| JobUninjected { + worker: worker_index, + }); + return Some(job); + } + Steal::Empty => return None, + Steal::Retry => {} + } } - job } /// If already in a worker-thread of this registry, just execute `op`. @@ -450,6 +472,10 @@ impl Registry { ); self.inject(&[job.as_job_ref()]); job.latch.wait_and_reset(); // Make sure we can use the same latch again next time. + + // flush accumulated logs as we exit the thread + self.logger.log(|| Flush); + job.into_result() }) } @@ -463,7 +489,7 @@ impl Registry { // This thread is a member of a different pool, so let it process // other work while waiting for this `op` to complete. debug_assert!(current_thread.registry().id() != self.id()); - let latch = TickleLatch::new(SpinLatch::new(), current_thread.registry()); + let latch = SpinLatch::cross(current_thread); let job = StackJob::new( |injected| { let worker_thread = WorkerThread::current(); @@ -498,19 +524,28 @@ impl Registry { /// terminate count and is responsible for invoking `terminate()` /// when finished. pub(super) fn increment_terminate_count(&self) { - self.terminate_latch.increment(); + let previous = self.terminate_count.fetch_add(1, Ordering::AcqRel); + debug_assert!(previous != 0, "registry ref count incremented from zero"); + assert!( + previous != std::usize::MAX, + "overflow in registry ref count" + ); } /// Signals that the thread-pool which owns this registry has been /// dropped. The worker threads will gradually terminate, once any /// extant work is completed. pub(super) fn terminate(&self) { - self.terminate_latch.set(); - self.sleep.tickle(usize::MAX); + if self.terminate_count.fetch_sub(1, Ordering::AcqRel) == 1 { + for (i, thread_info) in self.thread_infos.iter().enumerate() { + thread_info.terminate.set_and_tickle_one(self, i); + } + } } - pub(super) fn tickle(&self) { - self.sleep.tickle(usize::MAX); + /// Notify the worker that the latch they are sleeping on has been "set". + pub(super) fn notify_worker_latch_is_set(&self, target_worker_index: usize) { + self.sleep.notify_worker_latch_is_set(target_worker_index); } } @@ -529,6 +564,15 @@ struct ThreadInfo { /// until workers have stopped; only used for tests. stopped: LockLatch, + /// The latch used to signal that terminated has been requested. + /// This latch is *set* by the `terminate` method on the + /// `Registry`, once the registry's main "terminate" counter + /// reaches zero. + /// + /// NB. We use a `CountLatch` here because it has no lifetimes and is + /// meant for async use, but the count never gets higher than one. + terminate: CountLatch, + /// the "stealer" half of the worker's deque stealer: Stealer, } @@ -538,6 +582,7 @@ impl ThreadInfo { ThreadInfo { primed: LockLatch::new(), stopped: LockLatch::new(), + terminate: CountLatch::new(), stealer, } } @@ -599,10 +644,16 @@ impl WorkerThread { } /// Returns the registry that owns this worker thread. + #[inline] pub(super) fn registry(&self) -> &Arc { &self.registry } + #[inline] + pub(super) fn log(&self, event: impl FnOnce() -> crate::log::Event) { + self.registry.logger.log(event) + } + /// Our index amongst the worker threads (ranges from `0..self.num_threads()`). #[inline] pub(super) fn index(&self) -> usize { @@ -611,8 +662,12 @@ impl WorkerThread { #[inline] pub(super) unsafe fn push(&self, job: JobRef) { + self.log(|| JobPushed { worker: self.index }); + let queue_was_empty = self.worker.is_empty(); self.worker.push(job); - self.registry.sleep.tickle(self.index); + self.registry + .sleep + .new_internal_jobs(self.index, 1, queue_was_empty); } #[inline] @@ -631,21 +686,27 @@ impl WorkerThread { /// bottom. #[inline] pub(super) unsafe fn take_local_job(&self) -> Option { - self.worker.pop() + let popped_job = self.worker.pop(); + + if popped_job.is_some() { + self.log(|| JobPopped { worker: self.index }); + } + + popped_job } /// Wait until the latch is set. Try to keep busy by popping and /// stealing tasks as necessary. #[inline] - pub(super) unsafe fn wait_until(&self, latch: &L) { - log!(WaitUntil { worker: self.index }); + pub(super) unsafe fn wait_until(&self, latch: &L) { + let latch = latch.as_core_latch(); if !latch.probe() { self.wait_until_cold(latch); } } #[cold] - unsafe fn wait_until_cold(&self, latch: &L) { + unsafe fn wait_until_cold(&self, latch: &CoreLatch) { // the code below should swallow all panics and hence never // unwind; but if something does wrong, we want to abort, // because otherwise other code in rayon may assume that the @@ -653,7 +714,7 @@ impl WorkerThread { // accesses, which would be *very bad* let abort_guard = unwind::AbortIfPanic; - let mut yields = 0; + let mut idle_state = self.registry.sleep.start_looking(self.index, latch); while !latch.probe() { // Try to find some work to do. We give preference first // to things in our local deque, then in other workers @@ -665,30 +726,31 @@ impl WorkerThread { .or_else(|| self.steal()) .or_else(|| self.registry.pop_injected_job(self.index)) { - yields = self.registry.sleep.work_found(self.index, yields); + self.registry.sleep.work_found(idle_state); self.execute(job); + idle_state = self.registry.sleep.start_looking(self.index, latch); } else { - yields = self.registry.sleep.no_work_found(self.index, yields); + self.registry + .sleep + .no_work_found(&mut idle_state, latch, || self.registry.has_injected_job()) } } // If we were sleepy, we are not anymore. We "found work" -- // whatever the surrounding thread was doing before it had to // wait. - self.registry.sleep.work_found(self.index, yields); + self.registry.sleep.work_found(idle_state); - log!(LatchSet { worker: self.index }); + self.log(|| ThreadSawLatchSet { + worker: self.index, + latch_addr: latch.addr(), + }); mem::forget(abort_guard); // successful execution, do not abort } + #[inline] pub(super) unsafe fn execute(&self, job: JobRef) { job.execute(); - - // Subtle: executing this job will have `set()` some of its - // latches. This may mean that a sleepy (or sleeping) worker - // can now make progress. So we have to tickle them to let - // them know. - self.registry.sleep.tickle(self.index); } /// Try to steal a single job and return it. @@ -700,32 +762,39 @@ impl WorkerThread { debug_assert!(self.local_deque_is_empty()); // otherwise, try to steal - let num_threads = self.registry.thread_infos.len(); + let thread_infos = &self.registry.thread_infos.as_slice(); + let num_threads = thread_infos.len(); if num_threads <= 1 { return None; } - let start = self.rng.next_usize(num_threads); - (start..num_threads) - .chain(0..start) - .filter(|&i| i != self.index) - .filter_map(|victim_index| { - let victim = &self.registry.thread_infos[victim_index]; - loop { + loop { + let mut retry = false; + let start = self.rng.next_usize(num_threads); + let job = (start..num_threads) + .chain(0..start) + .filter(move |&i| i != self.index) + .find_map(|victim_index| { + let victim = &thread_infos[victim_index]; match victim.stealer.steal() { - Steal::Empty => return None, - Steal::Success(d) => { - log!(StoleWork { + Steal::Success(job) => { + self.log(|| JobStolen { worker: self.index, - victim: victim_index + victim: victim_index, }); - return Some(d); + Some(job) + } + Steal::Empty => None, + Steal::Retry => { + retry = true; + None } - Steal::Retry => {} } - } - }) - .next() + }); + if job.is_some() || !retry { + return job; + } + } } } @@ -760,7 +829,12 @@ unsafe fn main_loop(worker: Worker, registry: Arc, index: usiz } } - worker_thread.wait_until(®istry.terminate_latch); + let my_terminate_latch = ®istry.thread_infos[index].terminate; + worker_thread.log(|| ThreadStart { + worker: index, + terminate_addr: my_terminate_latch.as_core_latch().addr(), + }); + worker_thread.wait_until(my_terminate_latch); // Should not be any work left in our queue. debug_assert!(worker_thread.take_local_job().is_none()); @@ -771,6 +845,8 @@ unsafe fn main_loop(worker: Worker, registry: Arc, index: usiz // Normal termination, do not abort. mem::forget(abort_guard); + worker_thread.log(|| ThreadTerminate { worker: index }); + // Inform a user callback that we exited a thread. if let Some(ref handler) = registry.exit_handler { let registry = registry.clone(); diff --git a/vendor/rayon-core/src/scope/mod.rs b/vendor/rayon-core/src/scope/mod.rs index 7c1333d005..a41d408e1e 100644 --- a/vendor/rayon-core/src/scope/mod.rs +++ b/vendor/rayon-core/src/scope/mod.rs @@ -5,8 +5,7 @@ //! [`join()`]: ../join/join.fn.html use crate::job::{HeapJob, JobFifo}; -use crate::latch::{CountLatch, Latch}; -use crate::log::Event::*; +use crate::latch::CountLatch; use crate::registry::{in_worker, Registry, WorkerThread}; use crate::unwind; use std::any::Any; @@ -286,7 +285,7 @@ struct ScopeBase<'scope> { /// propagated at that point. pub fn scope<'scope, OP, R>(op: OP) -> R where - OP: for<'s> FnOnce(&'s Scope<'scope>) -> R + 'scope + Send, + OP: FnOnce(&Scope<'scope>) -> R + Send, R: Send, { in_worker(|owner_thread, _| { @@ -377,7 +376,7 @@ where /// panics are propagated at that point. pub fn scope_fifo<'scope, OP, R>(op: OP) -> R where - OP: for<'s> FnOnce(&'s ScopeFifo<'scope>) -> R + 'scope + Send, + OP: FnOnce(&ScopeFifo<'scope>) -> R + Send, R: Send, { in_worker(|owner_thread, _| { @@ -580,24 +579,16 @@ impl<'scope> ScopeBase<'scope> { .compare_exchange(nil, &mut *err, Ordering::Release, Ordering::Relaxed) .is_ok() { - log!(JobPanickedErrorStored { - owner_thread: self.owner_thread_index - }); mem::forget(err); // ownership now transferred into self.panic - } else { - log!(JobPanickedErrorNotStored { - owner_thread: self.owner_thread_index - }); } - self.job_completed_latch.set(); + self.job_completed_latch + .set_and_tickle_one(&self.registry, self.owner_thread_index); } unsafe fn job_completed_ok(&self) { - log!(JobCompletedOk { - owner_thread: self.owner_thread_index - }); - self.job_completed_latch.set(); + self.job_completed_latch + .set_and_tickle_one(&self.registry, self.owner_thread_index); } unsafe fn steal_till_jobs_complete(&self, owner_thread: &WorkerThread) { @@ -609,15 +600,8 @@ impl<'scope> ScopeBase<'scope> { // ordering: let panic = self.panic.swap(ptr::null_mut(), Ordering::Relaxed); if !panic.is_null() { - log!(ScopeCompletePanicked { - owner_thread: owner_thread.index() - }); let value: Box> = mem::transmute(panic); unwind::resume_unwinding(*value); - } else { - log!(ScopeCompleteNoPanic { - owner_thread: owner_thread.index() - }); } } } diff --git a/vendor/rayon-core/src/scope/test.rs b/vendor/rayon-core/src/scope/test.rs index 3d855ecda7..8cb82b6153 100644 --- a/vendor/rayon-core/src/scope/test.rs +++ b/vendor/rayon-core/src/scope/test.rs @@ -1,6 +1,6 @@ use crate::unwind; use crate::ThreadPoolBuilder; -use crate::{scope, scope_fifo, Scope}; +use crate::{scope, scope_fifo, Scope, ScopeFifo}; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; use std::cmp; @@ -433,3 +433,83 @@ fn mixed_fifo_lifo_order() { let expected = vec![-3, 0, -2, 1, -1, 2, 3]; assert_eq!(vec, expected); } + +#[test] +fn static_scope() { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + let mut range = 0..100; + let sum = range.clone().sum(); + let iter = &mut range; + + COUNTER.store(0, Ordering::Relaxed); + scope(|s: &Scope<'static>| { + // While we're allowed the locally borrowed iterator, + // the spawns must be static. + for i in iter { + s.spawn(move |_| { + COUNTER.fetch_add(i, Ordering::Relaxed); + }); + } + }); + + assert_eq!(COUNTER.load(Ordering::Relaxed), sum); +} + +#[test] +fn static_scope_fifo() { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + let mut range = 0..100; + let sum = range.clone().sum(); + let iter = &mut range; + + COUNTER.store(0, Ordering::Relaxed); + scope_fifo(|s: &ScopeFifo<'static>| { + // While we're allowed the locally borrowed iterator, + // the spawns must be static. + for i in iter { + s.spawn_fifo(move |_| { + COUNTER.fetch_add(i, Ordering::Relaxed); + }); + } + }); + + assert_eq!(COUNTER.load(Ordering::Relaxed), sum); +} + +#[test] +fn mixed_lifetime_scope() { + fn increment<'slice, 'counter>(counters: &'slice [&'counter AtomicUsize]) { + scope(move |s: &Scope<'counter>| { + // We can borrow 'slice here, but the spawns can only borrow 'counter. + for &c in counters { + s.spawn(move |_| { + c.fetch_add(1, Ordering::Relaxed); + }); + } + }); + } + + let counter = AtomicUsize::new(0); + increment(&[&counter; 100]); + assert_eq!(counter.into_inner(), 100); +} + +#[test] +fn mixed_lifetime_scope_fifo() { + fn increment<'slice, 'counter>(counters: &'slice [&'counter AtomicUsize]) { + scope_fifo(move |s: &ScopeFifo<'counter>| { + // We can borrow 'slice here, but the spawns can only borrow 'counter. + for &c in counters { + s.spawn_fifo(move |_| { + c.fetch_add(1, Ordering::Relaxed); + }); + } + }); + } + + let counter = AtomicUsize::new(0); + increment(&[&counter; 100]); + assert_eq!(counter.into_inner(), 100); +} diff --git a/vendor/rayon-core/src/sleep/README.md b/vendor/rayon-core/src/sleep/README.md index bc2af869ff..c62c3975d9 100644 --- a/vendor/rayon-core/src/sleep/README.md +++ b/vendor/rayon-core/src/sleep/README.md @@ -1,388 +1,219 @@ # Introduction: the sleep module The code in this module governs when worker threads should go to -sleep. This is a tricky topic -- the work-stealing algorithm relies on -having active worker threads running around stealing from one -another. But, if there isn't a lot of work, this can be a bit of a -drag, because it requires high CPU usage. - -The code in this module takes a fairly simple approach to the -problem. It allows worker threads to fall asleep if they have failed -to steal work after various thresholds; however, whenever new work -appears, they will wake up briefly and try to steal again. There are some -shortcomings in this current approach: - -- it can (to some extent) scale *down* the amount of threads, but they - can never be scaled *up*. The latter might be useful in the case of - user tasks that must (perhaps very occasionally and unpredictably) - block for long periods of time. - - however, the preferred approach to this is for users to adopt futures - instead (and indeed this sleeping work is intended to enable future - integration). -- we have no way to wake up threads in a fine-grained or targeted - manner. The current system wakes up *all* sleeping threads whenever - *any* of them might be interested in an event. This means that while - we can scale CPU usage down, we do is in a fairly "bursty" manner, - where everyone comes online, then some of them go back offline. - -# The interface for workers - -Workers interact with the sleep module by invoking three methods: - -- `work_found()`: signals that the worker found some work and is about - to execute it. -- `no_work_found()`: signals that the worker searched all available sources - for work and found none. - - It is important for the coherence of the algorithm that if work - was available **before the search started**, it would have been - found. If work was made available during the search, then it's ok that - it might have been overlooked. -- `tickle()`: indicates that new work is available (e.g., a job has - been pushed to the local deque) or that some other blocking - condition has been resolved (e.g., a latch has been set). Wakes up any - sleeping workers. - -When in a loop searching for work, Workers also have to maintain an -integer `yields` that they provide to the `sleep` module (which will -return a new value for the next time). Thus the basic worker "find -work" loop looks like this (this is `wait_until()`, basically): - -```rust -let mut yields = 0; -while /* not done */ { - if let Some(job) = search_for_work() { - yields = work_found(self.index, yields); - } else { - yields = no_work_found(self.index, yields); - } -} -``` - -# Getting sleepy and falling asleep - -The basic idea here is that every worker goes through three states: - -- **Awake:** actively hunting for tasks. -- **Sleepy:** still actively hunting for tasks, but we have signaled that - we might go to sleep soon if we don't find any. -- **Asleep:** actually asleep (blocked on a condition variable). - -At any given time, only **one** worker can be in the sleepy -state. This allows us to coordinate the entire sleep protocol using a -single `AtomicUsize` and without the need of epoch counters or other -things that might rollover and so forth. - -Whenever a worker invokes `work_found()`, it transitions back to the -**awake** state. In other words, if it was sleepy, it stops being -sleepy. (`work_found()` cannot be invoked when the worker is asleep, -since then it is not doing anything.) - -On the other hand, whenever a worker invokes `no_work_found()`, it -*may* transition to a more sleepy state. To track this, we use the -counter `yields` that is maintained by the worker's steal loop. This -counter starts at 0. Whenever work is found, the counter is returned -to 0. But each time that **no** work is found, the counter is -incremented. Eventually it will reach a threshold -`ROUNDS_UNTIL_SLEEPY`. At this point, the worker will try to become -the sleepy one. It does this by executing a CAS into the global -registry state (details on this below). If that attempt is successful, -then the counter is incremented again, so that it is equal to -`ROUNDS_UNTIL_SLEEPY + 1`. Otherwise, the counter stays the same (and -hence we will keep trying to become sleepy until either work is found -or we are successful). - -Becoming sleepy does not put us to sleep immediately. Instead, we keep -iterating and looking for work for some further number of rounds. If -during this search we **do** find work, then we will return the -counter to 0 and also reset the global state to indicate we are no -longer sleepy. - -But if again no work is found, `yields` will eventually reach the -value `ROUNDS_UNTIL_ASLEEP`. At that point, we will try to transition -from **sleepy** to **asleep**. This is done by the helper fn -`sleep()`, which executes another CAS on the global state that removes -our worker as the sleepy worker and instead sets a flag to indicate -that there are sleeping workers present (the flag may already have -been set, that's ok). Assuming that CAS succeeds, we will block on a -condition variable. - -# Tickling workers - -Of course, while all the stuff in the previous section is happening, -other workers are (hopefully) producing new work. There are three kinds of -events that can allow a blocked worker to make progress: - -1. A new task is pushed onto a worker's deque. This task could be stolen. -2. A new task is injected into the thread-pool from the outside. This - task could be uninjected and executed. -3. A latch is set. One of the sleeping workers might have been waiting for - that before it could go on. - -Whenever one of these things happens, the worker (or thread, more generally) -responsible must invoke `tickle()`. Tickle will basically wake up **all** -the workers: - -- If any worker was the sleepy one, then the global state is changed - so that there is no sleepy worker. The sleepy one will notice this - when it next invokes `no_work_found()` and return to the *awake* state - (with a yield counter of zero). -- If any workers were actually **asleep**, then we invoke - `notify_all()` on the condition variable, which will cause them to - awaken and start over from the awake state (with a yield counter of - zero). - -Because `tickle()` is invoked very frequently -- and hopefully most of -the time it is not needed, because the workers are already actively -stealing -- it is important that it be very cheap. The current design -requires, in the case where nobody is even sleepy, just a load and a -compare. If there are sleepy workers, a swap is needed. If there -workers *asleep*, we must naturally acquire the lock and signal the -condition variable. - -# The global state - -We manage all of the above state transitions using a small bit of global -state (well, global to the registry). This is stored in the `Sleep` struct. -The primary thing is a single `AtomicUsize`. The value in this usize packs -in two pieces of information: - -1. **Are any workers asleep?** This is just one bit (yes or no). -2. **Which worker is the sleepy worker, if any?** This is a worker id. - -We use bit 0 to indicate whether any workers are asleep. So if `state -& 1` is zero, then no workers are sleeping. But if `state & 1` is 1, -then some workers are either sleeping or on their way to falling -asleep (i.e., they have acquired the lock). - -The remaining bits are used to store if there is a sleepy worker. We -want `0` to indicate that there is no sleepy worker. If there a sleepy -worker with index `worker_index`, we would store `(worker_index + 1) -<< 1` . The `+1` is there because worker indices are 0-based, so this -ensures that the value is non-zero, and the shift skips over the -sleepy bit. - -Some examples: - -- `0`: everyone is awake, nobody is sleepy -- `1`: some workers are asleep, no sleepy worker -- `2`: no workers are asleep, but worker 0 is sleepy (`(0 + 1) << 1 == 2`). -- `3`: some workers are asleep, and worker 0 is sleepy. - -# Correctness level 1: avoiding deadlocks etc - -In general, we do not want to miss wakeups. Two bad things could happen: - -- **Suboptimal performance**: If this is a wakeup about a new job being - pushed into a local deque, it won't deadlock, but it will cause - things to run slowly. The reason that it won't deadlock is that we - know at least one thread is active (the one doing the pushing), and - it will (sooner or later) try to pop this item from its own local - deque. -- **Deadlocks:** If this is a wakeup about an injected job or a latch that got set, however, - this can cause deadlocks. In the former case, if a job is injected but no thread ever - wakes to process it, the injector will likely block forever. In the latter case, - imagine this scenario: - - thread A calls join, forking a task T1, then executing task T2 - - thread B steals T1, forks a task T3, and executes T4. - - thread A completes task T2 and blocks on T1 - - thread A steals task T3 from thread B - - thread B finishes T4 and goes to sleep, blocking on T3 - - thread A completes task T3 and makes a wakeup, but it gets lost - At this point, thread B is still asleep and will never signal T2, so thread A will itself - go to sleep. Bad. - -It turns out that guaranteeing we don't miss a wakeup while retaining -good performance is fairly tricky. This is because of some details of -the C++11 memory model. But let's ignore those for now and generally -assume sequential consistency. In that case, our scheme should work -perfectly. - -Even if you assume seqcst, though, ensuring that you don't miss -wakeups can be fairly tricky in the absence of a central queue. For -example, consider the simplest scheme: imagine we just had a boolean -flag indicating whether anyone was asleep. Then you could imagine that -when workers find no work, they flip this flag to true. When work is -published, if the flag is true, we issue a wakeup. - -The problem here is that checking for new work is not an atomic -action. So it's possible that worker 1 could start looking for work -and (say) see that worker 0's queue is empty and then search workers -2..N. While that searching is taking place, worker 0 publishes some -new work. At the time when the new work is published, the "anyone -sleeping?" flag is still false, so nothing happens. Then worker 1, who -failed to find any work, goes to sleep --- completely missing the wakeup! - -We use the "sleepy worker" idea to sidestep this problem. Under our -scheme, instead of going right to sleep at the end, worker 1 would -become sleepy. Worker 1 would then do **at least** one additional -scan. During this scan, they should find the work published by worker -0, so they will stop being sleepy and go back to work (here of course -we are assuming that no one else has stolen the worker 0 work yet; if -someone else stole it, worker 1 may still go to sleep, but that's ok, -since there is no more work to be had). - -Now you may be wondering -- how does being sleepy help? What if, -instead of publishing its job right before worker 1 became sleepy, -worker 0 wait until right before worker 1 was going to go to sleep? In -other words, the sequence was like this: - -- worker 1 gets sleepy -- worker 1 starts its scan, scanning worker 0's deque -- worker 0 publishes its job, but nobody is sleeping yet, so no wakeups occur -- worker 1 finshes its scan, goes to sleep, missing the wakeup - -The reason that this doesn't occur is because, when worker 0 publishes -its job, it will see that there is a sleepy worker. It will clear the -global state to 0. Then, when worker 1 its scan, it will notice that -it is no longer sleepy, and hence it will not go to sleep. Instead it -will awaken and keep searching for work. - -The sleepy worker phase thus also serves as a cheap way to signal that -work is around: instead of doing the whole dance of acquiring a lock -and issuing notifications, when we publish work we can just swap a -single atomic counter and let the sleepy worker notice that on their -own. - -## Beyond seq-cst - -Unfortunately, the C++11 memory model doesn't generally guarantee -seq-cst. And, somewhat annoyingly, it's not easy for the sleep module -**in isolation** to guarantee the properties the need. The key -challenge has to do with the *synchronized-with* relation. Typically, -we try to use acquire-release reasoning, and in that case the idea is -that **if** a load observes a store, it will also observe those writes -that preceded the store. But nothing says that the load **must** -observe the store -- at least not right away. - -The place that this is most relevant is the load in the `tickle()` -routine. The routine begins by reading from the global state. If it -sees anything other than 0, it then does a swap and -- if necessary -- -acquires a lock and does a notify. This load is a seq-cst load (as are -the other accesses in tickle). This ensures that it is sensible to -talk about a tickle happening *before* a worker gets sleepy and so -forth. - -It turns out that to get things right, if we use the current tickle -routine, we have to use seq-cst operations **both in the sleep module -and when publishing work**. We'll walk through two scenarios to -show what I mean. - -### Scenario 1: get-sleepy-then-get-tickled - -This scenario shows why the operations in sleep must be seq-cst. We -want to ensure that once a worker gets sleepy, any other worker that -does a tickle will observe that. In other words, we want to ensure -that the following scenario **cannot happen**: - -1. worker 1 is blocked on latch L -2. worker 1 becomes sleepy - - becoming sleepy involves a CAS on the global state to set it to 4 ("worker 1 is sleepy") -3. worker 0 sets latch L -4. worker 0 tickles **but does not see that worker 0 is sleepy** - -Let's diagram this. The notation `read_xxx(A) = V` means that a read -of location `A` was executed with the result `V`. The `xxx` is the -ordering and the location `A` is either `L` (latch) or `S` (global -state). I will leave the ordering on the latch as `xxx` as it is not -relevant here. The numbers correspond to the steps above. - -``` - worker 0 worker 1 - | +- 2: cas_sc(S, 4) -s| 3: write_xxx(L) + -b| 4: read_sc(S) = ??? <-sc-+ - v -``` - -Clearly, this cannot happen with sc orderings, because read 4 will -always return `4` here. However, if we tried to use acquire-release -orderings on the global state, then there would be **no guarantee** -that the tickle will observe that a sleepy worker occurred. We would -be guaranteed only that worker 0 would **eventually** observe that -worker 1 had become sleepy (and, at that time, that it would see other -writes). But it could take time -- and if we indeed miss that worker 1 -is sleepy, it could lead to deadlock or loss of efficiency, as -explained earlier. - -### Scenario 2: tickle-then-get-sleepy - -
    - -This scenario shows why latch operations must *also* be seq-cst (and, -more generally, any operations that publish work before a tickle). We -wish to ensure that this ordering of events **cannot occur**: - -1. worker 1 is blocked on latch L -2. worker 1 reads latch L, sees false, starts searching for work -3. worker 0 sets latch L -4. worker 0 tickles - - the tickle reads from the global state, sees 0 -5. worker 1 finishes searching, becomes sleepy - - becoming sleepy involves a CAS on the global state to set it to 4 ("worker 1 is sleepy") -6. worker 1 reads latch L **but does not see that worker 0 set it** -7. worker 1 may then proceed to become sleepy - -In other words, we want to ensure that if worker 0 sets a latch and -does a tickle *before worker 1 gets sleepy*, then worker 1 will -observe that latch as set when it calls probe. We'll see that, with -the current scheme, this implies that the latch memory orderings must -be seq-cst as well. - -Here is the diagram: - -``` - worker 0 worker 1 - | 2: read_xxx(L) = false -s| 3: write_xxx(L, true) -b| 4: read_sc(S) = 0 -+ - | +-sc---> 5: cas_sc(S, 4) - v 6: read_xxx(L) = ??? -``` - -The diagram shows that each thread's actions are related by -*sequenced-before* (sb). Moreover the read and write of `S` are -related by `sc` (the seq-cst ordering). However, and this is crucial, -this **does not** imply that oper 4 *synchronizes-with* oper 5. This -is because a read never synchronizes-with a store, only the -reverse. Hence, if the latch were using acq-rel orderings, it would be -legal for oper 6 to return false. But if the latch were to use an -**sc** ordering itself, then we know that oper 6 must return true, -since `3 -sc-> 4 -sc-> 5 -sc-> 6`. - -**Note** that this means that, before we tickle, we must execute some -seq-cst stores to publish our work (and during the scan we must load -from those same locations) **if we wish to guarantee that the work we -published WILL be seen by the other threads** (as opposed to -*may*). This is true for setting a latch -- if a latch is set but -another thread misses it, then the system could deadlock. However, in -the case of pushing new work to a deque, we choose not to use a seqcst -ordering. This is for several reasons: - -- If we miss a wakeup, the consequences are less dire: we simply run - less efficiently (after all, the current thread will eventually - complete its current task and pop the new task off the deque). -- It is inconvenient: The deque code is beyond our control (it lies in another package). However, - we could create a dummy `AtomicBool` for each deque and do a seqcst write to it - (with whatever value) after we push to the deque, and a seqcst load whenever - we steal from the deque. -- The cost of using a dummy variable was found to be quite high for some benchmarks: - - 8-10% overhead on nbody-parreduce - - 15% overhead on increment-all - - 40% overhead on join-recursively - -### Alternative solutions - -In both cases above, our problems arose because tickle is merely -performing a seq-cst read. If we instead had tickle perform a release -*swap*, that would be a write action of the global state. No matter -the ordering mode, all writes to the same memory location have a total -ordering, and hence we would not have to worry about others storing a -value that we fail to read (as in scenario 1). Similarly, as a release -write, a swap during tickle would synchronize-with a later cas and so -scenario 2 should be averted. So you might wonder why we don't do -that. The simple reason was that it didn't perform as well! In my -measurements, many benchmarks were unaffected by using a swap, but -some of them were hit hard: - - 8-10% overhead on nbody-parreduce - - 35% overhead on increment-all - - 245% overhead on join-recursively +sleep. The system used in this code was introduced in [Rayon RFC #5]. +There is also a [video walkthrough] available. Both of those may be +valuable resources to understanding the code, though naturally they +will also grow stale over time. The comments in this file are +extracted from the RFC and meant to be kept up to date. + +[Rayon RFC #5]: https://github.com/rayon-rs/rfcs/pull/5 +[video walkthrough]: https://youtu.be/HvmQsE5M4cY + +# The `Sleep` struct + +The `Sleep` struct is embedded into each registry. It performs several functions: + +* It tracks when workers are awake or asleep. +* It decides how long a worker should look for work before it goes to sleep, + via a callback that is invoked periodically from the worker's search loop. +* It is notified when latches are set, jobs are published, or other + events occur, and it will go and wake the appropriate threads if + they are sleeping. + +# Thread states + +There are three main thread states: + +* An **active** thread is one that is actively executing a job. +* An **idle** thread is one that is searching for work to do. It will be + trying to steal work or pop work from the global injector queue. +* A **sleeping** thread is one that is blocked on a condition variable, + waiting to be awoken. + +We sometimes refer to the final two states collectively as **inactive**. +Threads begin as idle but transition to idle and finally sleeping when +they're unable to find work to do. + +## Sleepy threads + +There is one other special state worth mentioning. During the idle state, +threads can get **sleepy**. A sleepy thread is still idle, in that it is still +searching for work, but it is *about* to go to sleep after it does one more +search (or some other number, potentially). When a thread enters the sleepy +state, it signals (via the **jobs event counter**, described below) that it is +about to go to sleep. If new work is published, this will lead to the counter +being adjusted. When the thread actually goes to sleep, it will (hopefully, but +not guaranteed) see that the counter has changed and elect not to sleep, but +instead to search again. See the section on the **jobs event counter** for more +details. + +# The counters + +One of the key structs in the sleep module is `AtomicCounters`, found in +`counters.rs`. It packs three counters into one atomically managed value: + +* Two **thread counters**, which track the number of threads in a particular state. +* The **jobs event counter**, which is used to signal when new work is available. + It (sort of) tracks the number of jobs posted, but not quite, and it can rollover. + +## Thread counters + +There are two thread counters, one that tracks **inactive** threads and one that +tracks **sleeping** threads. From this, one can deduce the number of threads +that are idle by subtracting sleeping threads from inactive threads. We track +the counters in this way because it permits simpler atomic operations. One can +increment the number of sleeping threads (and thus decrease the number of idle +threads) simply by doing one atomic increment, for example. Similarly, one can +decrease the number of sleeping threads (and increase the number of idle +threads) through one atomic decrement. + +These counters are adjusted as follows: + +* When a thread enters the idle state: increment the inactive thread counter. +* When a thread enters the sleeping state: increment the sleeping thread counter. +* When a thread awakens a sleeping thread: decrement the sleeping thread counter. + * Subtle point: the thread that *awakens* the sleeping thread decrements the + counter, not the thread that is *sleeping*. This is because there is a delay + between siganling a thread to wake and the thread actually waking: + decrementing the counter when awakening the thread means that other threads + that may be posting work will see the up-to-date value that much faster. +* When a thread finds work, exiting the idle state: decrement the inactive + thread counter. + +## Jobs event counter + +The final counter is the **jobs event counter**. The role of this counter is to +help sleepy threads detect when new work is posted in a lightweight fashion. In +its simplest form, we would simply have a counter that gets incremented each +time a new job is posted. This way, when a thread gets sleepy, it could read the +counter, and then compare to see if the value has changed before it actually +goes to sleep. But this [turns out to be too expensive] in practice, so we use a +somewhat more complex scheme. + +[turns out to be too expensive]: https://github.com/rayon-rs/rayon/pull/746#issuecomment-624802747 + +The idea is that the counter toggles between two states, depending on whether +its value is even or odd (or, equivalently, on the value of its low bit): + +* Even -- If the low bit is zero, then it means that there has been no new work + since the last thread got sleepy. +* Odd -- If the low bit is one, then it means that new work was posted since + the last thread got sleepy. + +### New work is posted + +When new work is posted, we check the value of the counter: if it is even, +then we increment it by one, so that it becomes odd. + +### Worker thread gets sleepy + +When a worker thread gets sleepy, it will read the value of the counter. If the +counter is odd, it will increment the counter so that it is even. Either way, it +remembers the final value of the counter. The final value will be used later, +when the thread is going to sleep. If at that time the counter has not changed, +then we can assume no new jobs have been posted (though note the remote +possibility of rollover, discussed in detail below). + +# Protocol for a worker thread to post work + +The full protocol for a thread to post work is as follows + +* If the work is posted into the injection queue, then execute a seq-cst fence (see below). +* Load the counters, incrementing the JEC if it is even so that it is odd. +* Check if there are idle threads available to handle this new job. If not, + and there are sleeping threads, then wake one or more threads. + +# Protocol for a worker thread to fall asleep + +The full protocol for a thread to fall asleep is as follows: + +* After completing all its jobs, the worker goes idle and begins to + search for work. As it searches, it counts "rounds". In each round, + it searches all other work threads' queues, plus the 'injector queue' for + work injected from the outside. If work is found in this search, the thread + becomes active again and hence restarts this protocol from the top. +* After a certain number of rounds, the thread "gets sleepy" and executes `get_sleepy` + above, remembering the `final_value` of the JEC. It does one more search for work. +* If no work is found, the thread atomically: + * Checks the JEC to see that it has not changed from `final_value`. + * If it has, then the thread goes back to searchin for work. We reset to + just before we got sleepy, so that we will do one more search + before attending to sleep again (rather than searching for many rounds). + * Increments the number of sleeping threads by 1. +* The thread then executes a seq-cst fence operation (see below). +* The thread then does one final check for injected jobs (see below). If any + are available, it returns to the 'pre-sleepy' state as if the JEC had changed. +* The thread waits to be signaled. Once signaled, it returns to the idle state. + +# The jobs event counter and deadlock + +As described in the section on the JEC, the main concern around going to sleep +is avoiding a race condition wherein: + +* Thread A looks for work, finds none. +* Thread B posts work but sees no sleeping threads. +* Thread A goes to sleep. + +The JEC protocol largely prevents this, but due to rollover, this prevention is +not complete. It is possible -- if unlikely -- that enough activity occurs for +Thread A to observe the same JEC value that it saw when getting sleepy. If the +new work being published came from *inside* the thread-pool, then this race +condition isn't too harmful. It means that we have fewer workers processing the +work then we should, but we won't deadlock. This seems like an acceptable risk +given that this is unlikely in practice. + +However, if the work was posted as an *external* job, that is a problem. In that +case, it's possible that all of our workers could go to sleep, and the external +job would never get processed. To prevent that, the sleeping protocol includes +one final check to see if the injector queue is empty before fully falling +asleep. Note that this final check occurs **after** the number of sleeping +threads has been incremented. We are not concerned therefore with races against +injections that occur after that increment, only before. + +Unfortunately, there is one rather subtle point concerning this final check: +we wish to avoid the possibility that: + +* work is pushed into the injection queue by an outside thread X, +* the sleepy thread S sees the JEC but it has rolled over and is equal +* the sleepy thread S reads the injection queue but does not see the work posted by X. + +This is possible because the C++ memory model typically offers guarantees of the +form "if you see the access A, then you must see those other accesses" -- but it +doesn't guarantee that you will see the access A (i.e., if you think of +processors with independent caches, you may be operating on very out of date +cache state). + +## Using seq-cst fences to prevent deadlock + +To overcome this problem, we have inserted two sequentially consistent fence +operations into the protocols above: + +* One fence occurs after work is posted into the injection queue, but before the + counters are read (including the number of sleeping threads). + * Note that no fence is needed for work posted to internal queues, since it is ok + to overlook work in that case. +* One fence occurs after the number of sleeping threads is incremented, but + before the injection queue is read. + +### Proof sketch + +What follows is a "proof sketch" that the protocol is deadlock free. We model +two relevant bits of memory, the job injector queue J and the atomic counters C. + +Consider the actions of the injecting thread: + +* PushJob: Job is injected, which can be modeled as an atomic write to J with release semantics. +* PushFence: A sequentially consistent fence is executed. +* ReadSleepers: The counters C are read (they may also be incremented, but we just consider the read that comes first). + +Meanwhile, the sleepy thread does the following: + +* IncSleepers: The number of sleeping threads is incremented, which is atomic exchange to C. +* SleepFence: A sequentially consistent fence is executed. +* ReadJob: We look to see if the queue is empty, which is a read of J with acquire semantics. + +Either PushFence or SleepFence must come first: + +* If PushFence comes first, then PushJob must be visible to ReadJob. +* If SleepFence comes first, then IncSleepers is visible to ReadSleepers. \ No newline at end of file diff --git a/vendor/rayon-core/src/sleep/counters.rs b/vendor/rayon-core/src/sleep/counters.rs new file mode 100644 index 0000000000..626e24f1e2 --- /dev/null +++ b/vendor/rayon-core/src/sleep/counters.rs @@ -0,0 +1,269 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +pub(super) struct AtomicCounters { + /// Packs together a number of counters. The counters are ordered as + /// follows, from least to most significant bits (here, we assuming + /// that [`THREADS_BITS`] is equal to 10): + /// + /// * Bits 0..10: Stores the number of **sleeping threads** + /// * Bits 10..20: Stores the number of **inactive threads** + /// * Bits 20..: Stores the **job event counter** (JEC) + /// + /// This uses 10 bits ([`THREADS_BITS`]) to encode the number of threads. Note + /// that the total number of bits (and hence the number of bits used for the + /// JEC) will depend on whether we are using a 32- or 64-bit architecture. + value: AtomicUsize, +} + +#[derive(Copy, Clone)] +pub(super) struct Counters { + word: usize, +} + +/// A value read from the **Jobs Event Counter**. +/// See the [`README.md`](README.md) for more +/// coverage of how the jobs event counter works. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub(super) struct JobsEventCounter(usize); + +impl JobsEventCounter { + pub(super) const DUMMY: JobsEventCounter = JobsEventCounter(std::usize::MAX); + + #[inline] + pub(super) fn as_usize(self) -> usize { + self.0 + } + + /// The JEC "is sleepy" if the last thread to increment it was in the + /// process of becoming sleepy. This is indicated by its value being *even*. + /// When new jobs are posted, they check if the JEC is sleepy, and if so + /// they incremented it. + #[inline] + pub(super) fn is_sleepy(self) -> bool { + (self.as_usize() & 1) == 0 + } + + /// The JEC "is active" if the last thread to increment it was posting new + /// work. This is indicated by its value being *odd*. When threads get + /// sleepy, they will check if the JEC is active, and increment it. + #[inline] + pub(super) fn is_active(self) -> bool { + !self.is_sleepy() + } +} + +/// Number of bits used for the thread counters. +const THREADS_BITS: usize = 10; + +/// Bits to shift to select the sleeping threads +/// (used with `select_bits`). +const SLEEPING_SHIFT: usize = 0 * THREADS_BITS; + +/// Bits to shift to select the inactive threads +/// (used with `select_bits`). +const INACTIVE_SHIFT: usize = 1 * THREADS_BITS; + +/// Bits to shift to select the JEC +/// (use JOBS_BITS). +const JEC_SHIFT: usize = 2 * THREADS_BITS; + +/// Max value for the thread counters. +const THREADS_MAX: usize = (1 << THREADS_BITS) - 1; + +/// Constant that can be added to add one sleeping thread. +const ONE_SLEEPING: usize = 1; + +/// Constant that can be added to add one inactive thread. +/// An inactive thread is either idle, sleepy, or sleeping. +const ONE_INACTIVE: usize = 1 << INACTIVE_SHIFT; + +/// Constant that can be added to add one to the JEC. +const ONE_JEC: usize = 1 << JEC_SHIFT; + +impl AtomicCounters { + #[inline] + pub(super) fn new() -> AtomicCounters { + AtomicCounters { + value: AtomicUsize::new(0), + } + } + + /// Load and return the current value of the various counters. + /// This value can then be given to other method which will + /// attempt to update the counters via compare-and-swap. + #[inline] + pub(super) fn load(&self, ordering: Ordering) -> Counters { + Counters::new(self.value.load(ordering)) + } + + #[inline] + fn try_exchange(&self, old_value: Counters, new_value: Counters, ordering: Ordering) -> bool { + self.value + .compare_exchange(old_value.word, new_value.word, ordering, Ordering::Relaxed) + .is_ok() + } + + /// Adds an inactive thread. This cannot fail. + /// + /// This should be invoked when a thread enters its idle loop looking + /// for work. It is decremented when work is found. Note that it is + /// not decremented if the thread transitions from idle to sleepy or sleeping; + /// so the number of inactive threads is always greater-than-or-equal + /// to the number of sleeping threads. + #[inline] + pub(super) fn add_inactive_thread(&self) { + self.value.fetch_add(ONE_INACTIVE, Ordering::SeqCst); + } + + /// Increments the jobs event counter if `increment_when`, when applied to + /// the current value, is true. Used to toggle the JEC from even (sleepy) to + /// odd (active) or vice versa. Returns the final value of the counters, for + /// which `increment_when` is guaranteed to return false. + pub(super) fn increment_jobs_event_counter_if( + &self, + increment_when: impl Fn(JobsEventCounter) -> bool, + ) -> Counters { + loop { + let old_value = self.load(Ordering::SeqCst); + if increment_when(old_value.jobs_counter()) { + let new_value = old_value.plus(ONE_JEC); + if self.try_exchange(old_value, new_value, Ordering::SeqCst) { + return new_value; + } + } else { + return old_value; + } + } + } + + /// Subtracts an inactive thread. This cannot fail. It is invoked + /// when a thread finds work and hence becomes active. It returns the + /// number of sleeping threads to wake up (if any). + /// + /// See `add_inactive_thread`. + #[inline] + pub(super) fn sub_inactive_thread(&self) -> usize { + let old_value = Counters::new(self.value.fetch_sub(ONE_INACTIVE, Ordering::SeqCst)); + debug_assert!( + old_value.inactive_threads() > 0, + "sub_inactive_thread: old_value {:?} has no inactive threads", + old_value, + ); + debug_assert!( + old_value.sleeping_threads() <= old_value.inactive_threads(), + "sub_inactive_thread: old_value {:?} had {} sleeping threads and {} inactive threads", + old_value, + old_value.sleeping_threads(), + old_value.inactive_threads(), + ); + + // Current heuristic: whenever an inactive thread goes away, if + // there are any sleeping threads, wake 'em up. + let sleeping_threads = old_value.sleeping_threads(); + std::cmp::min(sleeping_threads, 2) + } + + /// Subtracts a sleeping thread. This cannot fail, but it is only + /// safe to do if you you know the number of sleeping threads is + /// non-zero (i.e., because you have just awoken a sleeping + /// thread). + #[inline] + pub(super) fn sub_sleeping_thread(&self) { + let old_value = Counters::new(self.value.fetch_sub(ONE_SLEEPING, Ordering::SeqCst)); + debug_assert!( + old_value.sleeping_threads() > 0, + "sub_sleeping_thread: old_value {:?} had no sleeping threads", + old_value, + ); + debug_assert!( + old_value.sleeping_threads() <= old_value.inactive_threads(), + "sub_sleeping_thread: old_value {:?} had {} sleeping threads and {} inactive threads", + old_value, + old_value.sleeping_threads(), + old_value.inactive_threads(), + ); + } + + #[inline] + pub(super) fn try_add_sleeping_thread(&self, old_value: Counters) -> bool { + debug_assert!( + old_value.inactive_threads() > 0, + "try_add_sleeping_thread: old_value {:?} has no inactive threads", + old_value, + ); + debug_assert!( + old_value.sleeping_threads() < THREADS_MAX, + "try_add_sleeping_thread: old_value {:?} has too many sleeping threads", + old_value, + ); + + let mut new_value = old_value; + new_value.word += ONE_SLEEPING; + + self.try_exchange(old_value, new_value, Ordering::SeqCst) + } +} + +#[inline] +fn select_thread(word: usize, shift: usize) -> usize { + ((word >> shift) as usize) & THREADS_MAX +} + +#[inline] +fn select_jec(word: usize) -> usize { + (word >> JEC_SHIFT) as usize +} + +impl Counters { + #[inline] + fn new(word: usize) -> Counters { + Counters { word } + } + + #[inline] + fn plus(self, word: usize) -> Counters { + Counters { + word: self.word + word, + } + } + + #[inline] + pub(super) fn jobs_counter(self) -> JobsEventCounter { + JobsEventCounter(select_jec(self.word)) + } + + /// The number of threads that are not actively + /// executing work. They may be idle, sleepy, or asleep. + #[inline] + pub(super) fn inactive_threads(self) -> usize { + select_thread(self.word, INACTIVE_SHIFT) + } + + #[inline] + pub(super) fn awake_but_idle_threads(self) -> usize { + debug_assert!( + self.sleeping_threads() <= self.inactive_threads(), + "sleeping threads: {} > raw idle threads {}", + self.sleeping_threads(), + self.inactive_threads() + ); + self.inactive_threads() - self.sleeping_threads() + } + + #[inline] + pub(super) fn sleeping_threads(self) -> usize { + select_thread(self.word, SLEEPING_SHIFT) + } +} + +impl std::fmt::Debug for Counters { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let word = format!("{:016x}", self.word); + fmt.debug_struct("Counters") + .field("word", &word) + .field("jobs", &self.jobs_counter().0) + .field("inactive", &self.inactive_threads()) + .field("sleeping", &self.sleeping_threads()) + .finish() + } +} diff --git a/vendor/rayon-core/src/sleep/mod.rs b/vendor/rayon-core/src/sleep/mod.rs index 5e125ed2a5..2aa262c51c 100644 --- a/vendor/rayon-core/src/sleep/mod.rs +++ b/vendor/rayon-core/src/sleep/mod.rs @@ -1,281 +1,392 @@ //! Code that decides when workers should go to sleep. See README.md //! for an overview. +use crate::latch::CoreLatch; use crate::log::Event::*; -use std::sync::atomic::{AtomicUsize, Ordering}; +use crate::log::Logger; +use crossbeam_utils::CachePadded; +use std::sync::atomic::Ordering; use std::sync::{Condvar, Mutex}; use std::thread; use std::usize; +mod counters; +use self::counters::{AtomicCounters, JobsEventCounter}; + +/// The `Sleep` struct is embedded into each registry. It governs the waking and sleeping +/// of workers. It has callbacks that are invoked periodically at significant events, +/// such as when workers are looping and looking for work, when latches are set, or when +/// jobs are published, and it either blocks threads or wakes them in response to these +/// events. See the [`README.md`] in this module for more details. +/// +/// [`README.md`] README.md pub(super) struct Sleep { - state: AtomicUsize, - data: Mutex<()>, - tickle: Condvar, + logger: Logger, + + /// One "sleep state" per worker. Used to track if a worker is sleeping and to have + /// them block. + worker_sleep_states: Vec>, + + counters: AtomicCounters, } -const AWAKE: usize = 0; -const SLEEPING: usize = 1; +/// An instance of this struct is created when a thread becomes idle. +/// It is consumed when the thread finds work, and passed by `&mut` +/// reference for operations that preserve the idle state. (In other +/// words, producing one of these structs is evidence the thread is +/// idle.) It tracks state such as how long the thread has been idle. +pub(super) struct IdleState { + /// What is worker index of the idle thread? + worker_index: usize, -const ROUNDS_UNTIL_SLEEPY: usize = 32; -const ROUNDS_UNTIL_ASLEEP: usize = 64; + /// How many rounds have we been circling without sleeping? + rounds: u32, -impl Sleep { - pub(super) fn new() -> Sleep { - Sleep { - state: AtomicUsize::new(AWAKE), - data: Mutex::new(()), - tickle: Condvar::new(), - } - } + /// Once we become sleepy, what was the sleepy counter value? + /// Set to `INVALID_SLEEPY_COUNTER` otherwise. + jobs_counter: JobsEventCounter, +} - fn anyone_sleeping(&self, state: usize) -> bool { - state & SLEEPING != 0 - } +/// The "sleep state" for an individual worker. +#[derive(Default)] +struct WorkerSleepState { + /// Set to true when the worker goes to sleep; set to false when + /// the worker is notified or when it wakes. + is_blocked: Mutex, - fn any_worker_is_sleepy(&self, state: usize) -> bool { - (state >> 1) != 0 - } + condvar: Condvar, +} - fn worker_is_sleepy(&self, state: usize, worker_index: usize) -> bool { - (state >> 1) == (worker_index + 1) - } +const ROUNDS_UNTIL_SLEEPY: u32 = 32; +const ROUNDS_UNTIL_SLEEPING: u32 = ROUNDS_UNTIL_SLEEPY + 1; - fn with_sleepy_worker(&self, state: usize, worker_index: usize) -> usize { - debug_assert!(state == AWAKE || state == SLEEPING); - ((worker_index + 1) << 1) + state +impl Sleep { + pub(super) fn new(logger: Logger, n_threads: usize) -> Sleep { + Sleep { + logger, + worker_sleep_states: (0..n_threads).map(|_| Default::default()).collect(), + counters: AtomicCounters::new(), + } } #[inline] - pub(super) fn work_found(&self, worker_index: usize, yields: usize) -> usize { - log!(FoundWork { + pub(super) fn start_looking(&self, worker_index: usize, latch: &CoreLatch) -> IdleState { + self.logger.log(|| ThreadIdle { worker: worker_index, - yields: yields, + latch_addr: latch.addr(), }); - if yields > ROUNDS_UNTIL_SLEEPY { - // FIXME tickling here is a bit extreme; mostly we want to "release the lock" - // from us being sleepy, we don't necessarily need to wake others - // who are sleeping - self.tickle(worker_index); + + self.counters.add_inactive_thread(); + + IdleState { + worker_index, + rounds: 0, + jobs_counter: JobsEventCounter::DUMMY, } - 0 } #[inline] - pub(super) fn no_work_found(&self, worker_index: usize, yields: usize) -> usize { - log!(DidNotFindWork { - worker: worker_index, - yields: yields, + pub(super) fn work_found(&self, idle_state: IdleState) { + self.logger.log(|| ThreadFoundWork { + worker: idle_state.worker_index, + yields: idle_state.rounds, }); - if yields < ROUNDS_UNTIL_SLEEPY { + + // If we were the last idle thread and other threads are still sleeping, + // then we should wake up another thread. + let threads_to_wake = self.counters.sub_inactive_thread(); + self.wake_any_threads(threads_to_wake as u32); + } + + #[inline] + pub(super) fn no_work_found( + &self, + idle_state: &mut IdleState, + latch: &CoreLatch, + has_injected_jobs: impl FnOnce() -> bool, + ) { + if idle_state.rounds < ROUNDS_UNTIL_SLEEPY { thread::yield_now(); - yields + 1 - } else if yields == ROUNDS_UNTIL_SLEEPY { + idle_state.rounds += 1; + } else if idle_state.rounds == ROUNDS_UNTIL_SLEEPY { + idle_state.jobs_counter = self.announce_sleepy(idle_state.worker_index); + idle_state.rounds += 1; thread::yield_now(); - if self.get_sleepy(worker_index) { - yields + 1 - } else { - yields - } - } else if yields < ROUNDS_UNTIL_ASLEEP { + } else if idle_state.rounds < ROUNDS_UNTIL_SLEEPING { + idle_state.rounds += 1; thread::yield_now(); - if self.still_sleepy(worker_index) { - yields + 1 - } else { - log!(GotInterrupted { - worker: worker_index - }); - 0 - } } else { - debug_assert_eq!(yields, ROUNDS_UNTIL_ASLEEP); - self.sleep(worker_index); - 0 - } - } - - pub(super) fn tickle(&self, worker_index: usize) { - // As described in README.md, this load must be SeqCst so as to ensure that: - // - if anyone is sleepy or asleep, we *definitely* see that now (and not eventually); - // - if anyone after us becomes sleepy or asleep, they see memory events that - // precede the call to `tickle()`, even though we did not do a write. - let old_state = self.state.load(Ordering::SeqCst); - if old_state != AWAKE { - self.tickle_cold(worker_index); + debug_assert_eq!(idle_state.rounds, ROUNDS_UNTIL_SLEEPING); + self.sleep(idle_state, latch, has_injected_jobs); } } #[cold] - fn tickle_cold(&self, worker_index: usize) { - // The `Release` ordering here suffices. The reasoning is that - // the atomic's own natural ordering ensure that any attempt - // to become sleepy/asleep either will come before/after this - // swap. If it comes *after*, then Release is good because we - // want it to see the action that generated this tickle. If it - // comes *before*, then we will see it here (but not other - // memory writes from that thread). If the other worker was - // becoming sleepy, the other writes don't matter. If they - // were were going to sleep, we will acquire lock and hence - // acquire their reads. - let old_state = self.state.swap(AWAKE, Ordering::Release); - log!(Tickle { + fn announce_sleepy(&self, worker_index: usize) -> JobsEventCounter { + let counters = self + .counters + .increment_jobs_event_counter_if(JobsEventCounter::is_active); + let jobs_counter = counters.jobs_counter(); + self.logger.log(|| ThreadSleepy { worker: worker_index, - old_state: old_state, + jobs_counter: jobs_counter.as_usize(), }); - if self.anyone_sleeping(old_state) { - let _data = self.data.lock().unwrap(); - self.tickle.notify_all(); - } + jobs_counter } - fn get_sleepy(&self, worker_index: usize) -> bool { - loop { - // Acquire ordering suffices here. If some other worker - // was sleepy but no longer is, we will eventually see - // that, and until then it doesn't hurt to spin. - // Otherwise, we will do a compare-exchange which will - // assert a stronger order and acquire any reads etc that - // we must see. - let state = self.state.load(Ordering::Acquire); - log!(GetSleepy { + #[cold] + fn sleep( + &self, + idle_state: &mut IdleState, + latch: &CoreLatch, + has_injected_jobs: impl FnOnce() -> bool, + ) { + let worker_index = idle_state.worker_index; + + if !latch.get_sleepy() { + self.logger.log(|| ThreadSleepInterruptedByLatch { worker: worker_index, - state: state, + latch_addr: latch.addr(), }); - if self.any_worker_is_sleepy(state) { - // somebody else is already sleepy, so we'll just wait our turn - debug_assert!( - !self.worker_is_sleepy(state, worker_index), - "worker {} called `is_sleepy()`, \ - but they are already sleepy (state={})", - worker_index, - state - ); - return false; - } else { - // make ourselves the sleepy one - let new_state = self.with_sleepy_worker(state, worker_index); - - // This must be SeqCst on success because we want to - // ensure: - // - // - That we observe any writes that preceded - // some prior tickle, and that tickle may have only - // done a SeqCst load on `self.state`. - // - That any subsequent tickle *definitely* sees this store. - // - // See the section on "Ensuring Sequentially - // Consistency" in README.md for more details. - // - // The failure ordering doesn't matter since we are - // about to spin around and do a fresh load. - if self - .state - .compare_exchange(state, new_state, Ordering::SeqCst, Ordering::Relaxed) - .is_ok() - { - log!(GotSleepy { - worker: worker_index, - old_state: state, - new_state: new_state, - }); - return true; - } + + return; + } + + let sleep_state = &self.worker_sleep_states[worker_index]; + let mut is_blocked = sleep_state.is_blocked.lock().unwrap(); + debug_assert!(!*is_blocked); + + // Our latch was signalled. We should wake back up fully as we + // wil have some stuff to do. + if !latch.fall_asleep() { + self.logger.log(|| ThreadSleepInterruptedByLatch { + worker: worker_index, + latch_addr: latch.addr(), + }); + + idle_state.wake_fully(); + return; + } + + loop { + let counters = self.counters.load(Ordering::SeqCst); + + // Check if the JEC has changed since we got sleepy. + debug_assert!(idle_state.jobs_counter.is_sleepy()); + if counters.jobs_counter() != idle_state.jobs_counter { + // JEC has changed, so a new job was posted, but for some reason + // we didn't see it. We should return to just before the SLEEPY + // state so we can do another search and (if we fail to find + // work) go back to sleep. + self.logger.log(|| ThreadSleepInterruptedByJob { + worker: worker_index, + }); + + idle_state.wake_partly(); + latch.wake_up(); + return; + } + + // Otherwise, let's move from IDLE to SLEEPING. + if self.counters.try_add_sleeping_thread(counters) { + break; } } + + // Successfully registered as asleep. + + self.logger.log(|| ThreadSleeping { + worker: worker_index, + latch_addr: latch.addr(), + }); + + // We have one last check for injected jobs to do. This protects against + // deadlock in the very unlikely event that + // + // - an external job is being injected while we are sleepy + // - that job triggers the rollover over the JEC such that we don't see it + // - we are the last active worker thread + std::sync::atomic::fence(Ordering::SeqCst); + if has_injected_jobs() { + // If we see an externally injected job, then we have to 'wake + // ourselves up'. (Ordinarily, `sub_sleeping_thread` is invoked by + // the one that wakes us.) + self.counters.sub_sleeping_thread(); + } else { + // If we don't see an injected job (the normal case), then flag + // ourselves as asleep and wait till we are notified. + // + // (Note that `is_blocked` is held under a mutex and the mutex was + // acquired *before* we incremented the "sleepy counter". This means + // that whomever is coming to wake us will have to wait until we + // release the mutex in the call to `wait`, so they will see this + // boolean as true.) + *is_blocked = true; + while *is_blocked { + is_blocked = sleep_state.condvar.wait(is_blocked).unwrap(); + } + } + + // Update other state: + idle_state.wake_fully(); + latch.wake_up(); + + self.logger.log(|| ThreadAwoken { + worker: worker_index, + latch_addr: latch.addr(), + }); } - fn still_sleepy(&self, worker_index: usize) -> bool { - let state = self.state.load(Ordering::SeqCst); - self.worker_is_sleepy(state, worker_index) + /// Notify the given thread that it should wake up (if it is + /// sleeping). When this method is invoked, we typically know the + /// thread is asleep, though in rare cases it could have been + /// awoken by (e.g.) new work having been posted. + pub(super) fn notify_worker_latch_is_set(&self, target_worker_index: usize) { + self.wake_specific_thread(target_worker_index); } - fn sleep(&self, worker_index: usize) { - loop { - // Acquire here suffices. If we observe that the current worker is still - // sleepy, then in fact we know that no writes have occurred, and anyhow - // we are going to do a CAS which will synchronize. - // - // If we observe that the state has changed, it must be - // due to a tickle, and then the Acquire means we also see - // any events that occured before that. - let state = self.state.load(Ordering::Acquire); - if self.worker_is_sleepy(state, worker_index) { - // It is important that we hold the lock when we do - // the CAS. Otherwise, if we were to CAS first, then - // the following sequence of events could occur: - // - // - Thread A (us) sets state to SLEEPING. - // - Thread B sets state to AWAKE. - // - Thread C sets state to SLEEPY(C). - // - Thread C sets state to SLEEPING. - // - Thread A reawakens, acquires lock, and goes to sleep. - // - // Now we missed the wake-up from thread B! But since - // we have the lock when we set the state to sleeping, - // that cannot happen. Note that the swap `tickle()` - // is not part of the lock, though, so let's play that - // out: - // - // # Scenario 1 - // - // - A loads state and see SLEEPY(A) - // - B swaps to AWAKE. - // - A locks, fails CAS - // - // # Scenario 2 - // - // - A loads state and see SLEEPY(A) - // - A locks, performs CAS - // - B swaps to AWAKE. - // - A waits (releasing lock) - // - B locks, notifies - // - // In general, acquiring the lock inside the loop - // seems like it could lead to bad performance, but - // actually it should be ok. This is because the only - // reason for the `compare_exchange` to fail is if an - // awaken comes, in which case the next cycle around - // the loop will just return. - let data = self.data.lock().unwrap(); - - // This must be SeqCst on success because we want to - // ensure: - // - // - That we observe any writes that preceded - // some prior tickle, and that tickle may have only - // done a SeqCst load on `self.state`. - // - That any subsequent tickle *definitely* sees this store. - // - // See the section on "Ensuring Sequentially - // Consistency" in README.md for more details. - // - // The failure ordering doesn't matter since we are - // about to spin around and do a fresh load. - if self - .state - .compare_exchange(state, SLEEPING, Ordering::SeqCst, Ordering::Relaxed) - .is_ok() - { - // Don't do this in a loop. If we do it in a loop, we need - // some way to distinguish the ABA scenario where the pool - // was awoken but before we could process it somebody went - // to sleep. Note that if we get a false wakeup it's not a - // problem for us, we'll just loop around and maybe get - // sleepy again. - log!(FellAsleep { - worker: worker_index - }); - let _ = self.tickle.wait(data).unwrap(); - log!(GotAwoken { - worker: worker_index - }); - return; + /// Signals that `num_jobs` new jobs were injected into the thread + /// pool from outside. This function will ensure that there are + /// threads available to process them, waking threads from sleep + /// if necessary. + /// + /// # Parameters + /// + /// - `source_worker_index` -- index of the thread that did the + /// push, or `usize::MAX` if this came from outside the thread + /// pool -- it is used only for logging. + /// - `num_jobs` -- lower bound on number of jobs available for stealing. + /// We'll try to get at least one thread per job. + #[inline] + pub(super) fn new_injected_jobs( + &self, + source_worker_index: usize, + num_jobs: u32, + queue_was_empty: bool, + ) { + // This fence is needed to guarantee that threads + // as they are about to fall asleep, observe any + // new jobs that may have been injected. + std::sync::atomic::fence(Ordering::SeqCst); + + self.new_jobs(source_worker_index, num_jobs, queue_was_empty) + } + + /// Signals that `num_jobs` new jobs were pushed onto a thread's + /// local deque. This function will try to ensure that there are + /// threads available to process them, waking threads from sleep + /// if necessary. However, this is not guaranteed: under certain + /// race conditions, the function may fail to wake any new + /// threads; in that case the existing thread should eventually + /// pop the job. + /// + /// # Parameters + /// + /// - `source_worker_index` -- index of the thread that did the + /// push, or `usize::MAX` if this came from outside the thread + /// pool -- it is used only for logging. + /// - `num_jobs` -- lower bound on number of jobs available for stealing. + /// We'll try to get at least one thread per job. + #[inline] + pub(super) fn new_internal_jobs( + &self, + source_worker_index: usize, + num_jobs: u32, + queue_was_empty: bool, + ) { + self.new_jobs(source_worker_index, num_jobs, queue_was_empty) + } + + /// Common helper for `new_injected_jobs` and `new_internal_jobs`. + #[inline] + fn new_jobs(&self, source_worker_index: usize, num_jobs: u32, queue_was_empty: bool) { + // Read the counters and -- if sleepy workers have announced themselves + // -- announce that there is now work available. The final value of `counters` + // with which we exit the loop thus corresponds to a state when + let counters = self + .counters + .increment_jobs_event_counter_if(JobsEventCounter::is_sleepy); + let num_awake_but_idle = counters.awake_but_idle_threads(); + let num_sleepers = counters.sleeping_threads(); + + self.logger.log(|| JobThreadCounts { + worker: source_worker_index, + num_idle: num_awake_but_idle as u16, + num_sleepers: num_sleepers as u16, + }); + + if num_sleepers == 0 { + // nobody to wake + return; + } + + // Promote from u16 to u32 so we can interoperate with + // num_jobs more easily. + let num_awake_but_idle = num_awake_but_idle as u32; + let num_sleepers = num_sleepers as u32; + + // If the queue is non-empty, then we always wake up a worker + // -- clearly the existing idle jobs aren't enough. Otherwise, + // check to see if we have enough idle workers. + if !queue_was_empty { + let num_to_wake = std::cmp::min(num_jobs, num_sleepers); + self.wake_any_threads(num_to_wake); + } else if num_awake_but_idle < num_jobs { + let num_to_wake = std::cmp::min(num_jobs - num_awake_but_idle, num_sleepers); + self.wake_any_threads(num_to_wake); + } + } + + #[cold] + fn wake_any_threads(&self, mut num_to_wake: u32) { + if num_to_wake > 0 { + for i in 0..self.worker_sleep_states.len() { + if self.wake_specific_thread(i) { + num_to_wake -= 1; + if num_to_wake == 0 { + return; + } } - } else { - log!(GotInterrupted { - worker: worker_index - }); - return; } } } + + fn wake_specific_thread(&self, index: usize) -> bool { + let sleep_state = &self.worker_sleep_states[index]; + + let mut is_blocked = sleep_state.is_blocked.lock().unwrap(); + if *is_blocked { + *is_blocked = false; + sleep_state.condvar.notify_one(); + + // When the thread went to sleep, it will have incremented + // this value. When we wake it, its our job to decrement + // it. We could have the thread do it, but that would + // introduce a delay between when the thread was + // *notified* and when this counter was decremented. That + // might mislead people with new work into thinking that + // there are sleeping threads that they should try to + // wake, when in fact there is nothing left for them to + // do. + self.counters.sub_sleeping_thread(); + + self.logger.log(|| ThreadNotify { worker: index }); + + true + } else { + false + } + } +} + +impl IdleState { + fn wake_fully(&mut self) { + self.rounds = 0; + self.jobs_counter = JobsEventCounter::DUMMY; + } + + fn wake_partly(&mut self) { + self.rounds = ROUNDS_UNTIL_SLEEPY; + self.jobs_counter = JobsEventCounter::DUMMY; + } } diff --git a/vendor/rayon-core/src/spawn/mod.rs b/vendor/rayon-core/src/spawn/mod.rs index d9eb2ed55b..00061037a6 100644 --- a/vendor/rayon-core/src/spawn/mod.rs +++ b/vendor/rayon-core/src/spawn/mod.rs @@ -21,8 +21,7 @@ use std::sync::Arc; /// /// This API assumes that the closure is executed purely for its /// side-effects (i.e., it might send messages, modify data protected -/// by a mutex, or some such thing). If you want to compute a result, -/// consider `spawn_future()`. +/// by a mutex, or some such thing). /// /// There is no guaranteed order of execution for spawns, given that /// other threads may steal tasks at any time. However, they are diff --git a/vendor/rayon-core/src/thread_pool/mod.rs b/vendor/rayon-core/src/thread_pool/mod.rs index 065d236e00..2209f63046 100644 --- a/vendor/rayon-core/src/thread_pool/mod.rs +++ b/vendor/rayon-core/src/thread_pool/mod.rs @@ -200,7 +200,7 @@ impl ThreadPool { /// [scope]: fn.scope.html pub fn scope<'scope, OP, R>(&self, op: OP) -> R where - OP: for<'s> FnOnce(&'s Scope<'scope>) -> R + 'scope + Send, + OP: FnOnce(&Scope<'scope>) -> R + Send, R: Send, { self.install(|| scope(op)) @@ -215,7 +215,7 @@ impl ThreadPool { /// [scope_fifo]: fn.scope_fifo.html pub fn scope_fifo<'scope, OP, R>(&self, op: OP) -> R where - OP: for<'s> FnOnce(&'s ScopeFifo<'scope>) -> R + 'scope + Send, + OP: FnOnce(&ScopeFifo<'scope>) -> R + Send, R: Send, { self.install(|| scope_fifo(op)) diff --git a/vendor/rayon-core/src/thread_pool/test.rs b/vendor/rayon-core/src/thread_pool/test.rs index 0d6815e129..8d1c90ca18 100644 --- a/vendor/rayon-core/src/thread_pool/test.rs +++ b/vendor/rayon-core/src/thread_pool/test.rs @@ -4,12 +4,9 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::channel; use std::sync::{Arc, Mutex}; -use crate::join; -use crate::thread_pool::ThreadPool; - #[allow(deprecated)] use crate::Configuration; -use crate::ThreadPoolBuilder; +use crate::{join, Scope, ScopeFifo, ThreadPool, ThreadPoolBuilder}; #[test] #[should_panic(expected = "Hello, world!")] @@ -267,3 +264,75 @@ fn spawn_fifo_order() { let expected: Vec = (0..10).collect(); // FIFO -> natural order assert_eq!(vec, expected); } + +#[test] +fn nested_scopes() { + // Create matching scopes for every thread pool. + fn nest<'scope, OP>(pools: &[ThreadPool], scopes: Vec<&Scope<'scope>>, op: OP) + where + OP: FnOnce(&[&Scope<'scope>]) + Send, + { + if let Some((pool, tail)) = pools.split_first() { + pool.scope(move |s| { + // This move reduces the reference lifetimes by variance to match s, + // but the actual scopes are still tied to the invariant 'scope. + let mut scopes = scopes; + scopes.push(s); + nest(tail, scopes, op) + }) + } else { + (op)(&scopes) + } + } + + let pools: Vec<_> = (0..10) + .map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()) + .collect(); + + let counter = AtomicUsize::new(0); + nest(&pools, vec![], |scopes| { + for &s in scopes { + s.spawn(|_| { + // Our 'scope lets us borrow the counter in every pool. + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }); + assert_eq!(counter.into_inner(), pools.len()); +} + +#[test] +fn nested_fifo_scopes() { + // Create matching fifo scopes for every thread pool. + fn nest<'scope, OP>(pools: &[ThreadPool], scopes: Vec<&ScopeFifo<'scope>>, op: OP) + where + OP: FnOnce(&[&ScopeFifo<'scope>]) + Send, + { + if let Some((pool, tail)) = pools.split_first() { + pool.scope_fifo(move |s| { + // This move reduces the reference lifetimes by variance to match s, + // but the actual scopes are still tied to the invariant 'scope. + let mut scopes = scopes; + scopes.push(s); + nest(tail, scopes, op) + }) + } else { + (op)(&scopes) + } + } + + let pools: Vec<_> = (0..10) + .map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()) + .collect(); + + let counter = AtomicUsize::new(0); + nest(&pools, vec![], |scopes| { + for &s in scopes { + s.spawn_fifo(|_| { + // Our 'scope lets us borrow the counter in every pool. + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }); + assert_eq!(counter.into_inner(), pools.len()); +} diff --git a/vendor/rayon/.cargo-checksum.json b/vendor/rayon/.cargo-checksum.json index 516afd63a0..37426500c5 100644 --- a/vendor/rayon/.cargo-checksum.json +++ b/vendor/rayon/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"917614b366caa797c3f6c185f2a9057339eedb21fd6e1426fdedd31be85640fe","Cargo.toml":"6ef35fc372f85b755a234e465f05c703ad1776905e634aa273f9db0b688c44c9","FAQ.md":"23e5c1ac0158e9e33dae4d3f48bb6b63037ee16e55c476da4cbeedcabe0be0fc","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"443319f333d92d6ad50ade54334c49609e5b116442639b4134b2dd95b49f8d8f","RELEASES.md":"025aec0504abf151a1353f8cf1fa2e899ef2ab66602ff2755038721ed3ae0236","build.rs":"2ec988611a2efa7aa89a1835731edcd15d019787d8184e1dac3126756121c586","examples/README.md":"537e6fe9cf696fd4ada9c08bf31055ed6e366ed65668a523e7c5fde77f97c8d3","examples/cpu_monitor.rs":"cc21a2635059ab2d86622d86508ce360c105417522b7bd1f8e0b3ac845ed484a","src/collections/binary_heap.rs":"55f2d9de4b53ce1e9e353362dc344f432e4ee0400dff6d5ea85a06a41eaa6b3e","src/collections/btree_map.rs":"d3094ed5c54620f81a86133f52e74164bae9f0137745eb66e6d31db2e942bcab","src/collections/btree_set.rs":"7de12e388d36cb2f8672bc3b68aed5b44d047c9f5fe262a7260584634299480f","src/collections/hash_map.rs":"f196ff806a334093d8f4d2d72f6e257517209996f5a6a2031b183d5130720bb4","src/collections/hash_set.rs":"2c0a8a91523a076d9153e6b7c19d2aabecc4706253b25fd6b20a0bd389253e60","src/collections/linked_list.rs":"bef7f32da49b55db76cfefa0afa4789a6979e08a69427e49bab2874967163fef","src/collections/mod.rs":"037660cbdd5907808f7df59fa69993582bf978ecaf125a83a1205452bb505a53","src/collections/vec_deque.rs":"51b3f019c05fcaff9916e258312146c540635cb38941291748f01926d4955a72","src/compile_fail/cannot_collect_filtermap_data.rs":"6a141076c14f95e31bed3433d531bc05d806eed9e0018d1b21420d7ab2fc7eb9","src/compile_fail/cannot_zip_filtered_data.rs":"a28cfb3d00b8d277bfa77a10ca132f972e8f100080ef602fdd3c6fd36ad2a156","src/compile_fail/cell_par_iter.rs":"4f076862d9c66ed42a642a5be97116ca5982608ab76816a8f8305182bf463e9e","src/compile_fail/mod.rs":"2c346e4b52941fe0ac2667eeb753c0c21a1f998a544bb9d9167f200caba0a7bb","src/compile_fail/must_use.rs":"8f26766396842fd83790f1afdc20a926bbc1ed9b5cede8d6bec172c1e7d42ed2","src/compile_fail/no_send_par_iter.rs":"e78cd466a61081a0738f63b4e74249e40c37b95240e47e3faeab6ffdb6a8f14c","src/compile_fail/rc_par_iter.rs":"0faf3d26a665c3e2acc2f2f1d66ee234e561d24442efa4980a5e946e1cb2eba3","src/delegate.rs":"897b9118443a50f1690b2506bc349cd233496eea05fa38f0bce821809a23e528","src/iter/chain.rs":"f82a25577ca36bac93b5a13e75dcd70e8cee381b9baa5993dd645f0714fb9eb6","src/iter/chunks.rs":"8ab345783cb7412438eed33264d7db79873801784af7dab25291c349c678085f","src/iter/cloned.rs":"35e1c864f99f7bc93c258c4976d15ccfc1d04df969dc878fd03d35f6799377f7","src/iter/collect/consumer.rs":"cb6f17f46fc56a782afb2a0e023338ebedefe3e7968a84fa8e513c6b89344a64","src/iter/collect/mod.rs":"cf1a50ae7bb6f13578635a61e7bfd996de3c27c184c5ff674d3f3014cc3de519","src/iter/collect/test.rs":"7fcf412afa8461312f7893a36e0a50baca0e495a1fe20885dc62b52d8f68b978","src/iter/copied.rs":"4a5de15719de5e6337925f993e0a55c87d8a62b8bbf6c0a4e2bd877136581afc","src/iter/empty.rs":"3cb2d05721aab1a4d9e9c5813473e1646116c1ea570e26d9ac81e083688a0b7d","src/iter/enumerate.rs":"3204255723a93b3275cf0f208939de8960b13a9b13b8c2ba6b664e65da21cd87","src/iter/extend.rs":"11c46e4cab6b1f3f3d82e1555f92c79b2ea9a833258b88142f14dc6d3eed4e15","src/iter/filter.rs":"c8ceea2f71afd1ffc7c713d8683e337e2c4bc3327f47d25116039ab7d950376f","src/iter/filter_map.rs":"18b2fa2d5119297ed6218e353ebb50e7cf4c853e76b9feffd2f332a885d8811d","src/iter/find.rs":"73b11b97eae7234099a05b5f59c937fe488e6a8574b9c9e4e852a7fa86341117","src/iter/find_first_last/mod.rs":"fa7d7692d81ecdbecb178606ad3b1b00c80e5e4159c57d34929b012b0bea0c82","src/iter/find_first_last/test.rs":"2052eb8b87c5a0a0d49a76c83d9d74f81be18aad52ceb1b06d7e209f4fefba94","src/iter/flat_map.rs":"073f67369d2e8b8ed217174bed5ad427e9ddc1b55e57f2c0e5e8b22a61a59b71","src/iter/flatten.rs":"a9144e37855b33d1c08f1c4179e0089ed6bc7d4b645fcf36c46a8ed687961d07","src/iter/fold.rs":"874259b408d7f8cdc376d34276d37c1837950c035ff780de8281d1edf65ded9f","src/iter/for_each.rs":"7af0e21ed8479eec65831d1409f61a88d45a31764f2385ec759eda1a46d388b2","src/iter/from_par_iter.rs":"9439b1ae01db2c7545d6416108700dfbafcff3f584e81704cf985ab1d986b660","src/iter/inspect.rs":"d4f5c031e4a79c01b8439b5e3c78b637ecb4bcf191c8d98ec9f31a0b51977abc","src/iter/interleave.rs":"dcda8d2bd46de25227ac88243ff6ca97fcf1dbb89f935b651fd04c1ecf1abe8a","src/iter/interleave_shortest.rs":"a2b1f31ea4cb29f4761d3724feddcf5a96e1f21fd623f95c85a8659294a6745a","src/iter/intersperse.rs":"6b5d3d826ed3499ba78f0ff07468d96a0e104c7ee142a2ced6be8143b43241a5","src/iter/len.rs":"427548a874aa3036adbaf12034f5065382a8e98f9131b13c6a8c92c7b97e596d","src/iter/map.rs":"66e6db399de12327fec29d069462347dd16fd96d450b121ba8227e32e51552d1","src/iter/map_with.rs":"f83950016bb02addecec049fda73663861c80232477a7b89b7e8718291a4b481","src/iter/mod.rs":"6018cee2df11c5615a028ad97539206fda3c0a92f640f4de24244b85bf63f90e","src/iter/multizip.rs":"10ec107f6673c9bc6d1d611e11b716c37e8601ab2f4257a460c4bc4962771347","src/iter/noop.rs":"5be6332ddfbb8fdbae1ffdb00983950a8b37a295bcb58e9a265b33806ee504e6","src/iter/once.rs":"fcebffc374dcdd206d13311dcc2e7d7a04da5687658b2f3ec3409f03ed12774b","src/iter/panic_fuse.rs":"2a4d43fa4e717629de7f69eb180f13db90ef95004975cfa20dcfaacc80435015","src/iter/par_bridge.rs":"26cd2dbc57e5dd2c1b99b19f8ee66900e5ad7e99a5d8b22e947426f944f72b37","src/iter/plumbing/README.md":"d9ae3d57a37af5645b1c79029dd808933279d6853b30163cd0d71ead2a9a5002","src/iter/plumbing/mod.rs":"1156c55a15b651d161f463cb86b2f602f6246a3c7f8a82fb484db12aa6a60091","src/iter/product.rs":"da69f4781c2275c4a176432994c3fd80ea1f296afe47b329de61b1d733d990df","src/iter/reduce.rs":"2f5d6e07d7c0de2360505fa5d9198c31fd43ba7e58a6ec40f79edec19319e502","src/iter/repeat.rs":"ed46b17b79d8569f9d67b50585b116ee0293e1d6c17c0dc683c66644f6a58fd5","src/iter/rev.rs":"c4c796d7cb6398e74bef043a080403acccdf70f6a4e74b242e530d1718969b8f","src/iter/skip.rs":"f1566b395a2b2e95ee14a056b28cf2532f2f9c4d2abc379a1d313ff5a837a51f","src/iter/splitter.rs":"0024db04b4430c2a1e8c921cec86af641f612f877f3675b15df0da9122de5f00","src/iter/step_by.rs":"7e02b9c18a2dc14f637959d0f90dabe877dd51d6dcd085a01c536be59c2bbcdb","src/iter/sum.rs":"cf11d996507ceba39524a102559b84289e776f8fe5772114e00ae2112b38c47c","src/iter/take.rs":"e47eeca1249553b0dfaf54cd8f99026be68db76b42f1f29e09c07a98c165c50a","src/iter/test.rs":"52ab229c2d8c4d4baf0d0cb439accbced982da088d66c3b404c97ef6bc0e136c","src/iter/try_fold.rs":"585d5a69480e1510f3d006c3bff810c98dd009ab44fa9a15a76beeea4fd8c3f2","src/iter/try_reduce.rs":"747f46db1f2d7178b40735828d877b06802296f0d69662d176062920e9a64067","src/iter/try_reduce_with.rs":"1958debdc53fab22b0d0eb603f22647fd96af44a4308549a56dd71256edd1525","src/iter/unzip.rs":"1d617107bd04cd944e64bd83482206ebfdb894a1778dcbbfc9021addf02234e6","src/iter/update.rs":"08a222cf7f8f2f82389ca48d89ecef3a88e205d21ce249f2ba15a4ff85134473","src/iter/while_some.rs":"a514891d7a07031354b48e377c239ff330d0955f184abc57a69d2a193e7fcb45","src/iter/zip.rs":"4d908f75a10b5e9b68d012bbba289f3e5e9d6a9570ce0f56fc1b4f9d96860499","src/iter/zip_eq.rs":"4c18d8f7a78e197a3268c9ef74d16690f8c960407c18bb63dc6905a2fe2bde62","src/lib.rs":"1d7a4967235467de2668c1cd94597dea339a7c20acedad6ca17f1f5126c085a0","src/math.rs":"181859dc38d787143016ce2952b6e45c5ec085d942a591bd5eaf6fe8905711a9","src/option.rs":"00979a9bb8f42629f2b956a6cfbd286fc8a41ffbbec85f1b5d0f0da5615dac9c","src/par_either.rs":"afa4b04ba6ea1d37aed2d68eca44d7ba0d1d09ea985c9091540dd8d3c51974f1","src/prelude.rs":"95b936c390cbfbbdeeca25adf81ea0db49f38ba46bbb82b9a1ebc42eed673abb","src/private.rs":"702ff02a2d0846d6d97b4164c7b4c2fbab2157ba5ba9c31fea5f1775ff3c9597","src/range.rs":"1e3ecf36f9d7c183f83952c76a9e7f9be40fe9b4a28a5b8a5083221c07f68cf3","src/range_inclusive.rs":"deccd7e2595f725ac7078a034cd774014b731653b376404b67622a7c3ad99eed","src/result.rs":"0656f0000efcea10e571df90247925dfd00a0c2194043fcbc009711fb2f7af02","src/slice/mergesort.rs":"36862f9ae70e35b905212a3c9374b5409fe32855aa067128537ad06578bb582f","src/slice/mod.rs":"c13c41176483a0251cfd1f6f92a59f6dec1ffd43f3e5d15caffb626115d6e9c7","src/slice/quicksort.rs":"874359bd23b90ebe78b2c5f9d5887c9fb063e765c905efb97c88669a6aadd88d","src/slice/test.rs":"d7aa8dbae27ef16687e673c64cde854238c37697a6ff2ce64984ec6381388006","src/split_producer.rs":"2b143e16bc6540792f861e215a86cfea7f4ee500d4faca2476d4165619eac90d","src/str.rs":"084d1e5b14f9b366519441065af7a4361ac0a96e5bfd5140c8e881c947448afc","src/vec.rs":"8f6529ec4842dec8b115f0563e5faf81f47530565685ce773416751724b86678","tests/clones.rs":"3a1a29eab0efb960fce3d0c32c8d105cc076ce6cf342d3468af2510ee941bf59","tests/collect.rs":"27173f932d5c65932ad63c215c561ecf06fcbeb7253a7bb175b819e0a40107aa","tests/cross-pool.rs":"103c121c8684eef0868e3982219e406500009c26d7602167f5a514b1dfd3b4cc","tests/debug.rs":"6672ec732f46fb9fdc62d034bda14069ac9db4bfecae7700e400fafabb584741","tests/intersperse.rs":"bda4fb2179086e32c77c8293b9bb85d55509c282441837ba1849c2d3aa3186a7","tests/issue671-unzip.rs":"d5eb38d8a6d8f66fdf1c40293abbf58f3ac42b5acfc5dca62b02c7ace5bfc1a4","tests/issue671.rs":"52914cac517074deaedcb81bd76b867f0b99cc7b65c3e01cfe12dc9fe38c0266","tests/iter_panic.rs":"376faac33739e3479b5eb744bb2c810c27f8fdda5eeb9ad96d8b93619bf11d1c","tests/named-threads.rs":"48dd0fa0de13b4554dfc1fc0adaee093e19df8b1fc601f5b9b4f15b1fc705249","tests/octillion.rs":"c136ae4612e0d964fc9cb0bcc058a04d0a59c35ba53e0304cdf1d7a0678502fc","tests/producer_split_at.rs":"a6769ac158d810cc292c23a3ee0d583f2fa77ff547f43a40f20f309764c3fb88","tests/sort-panic-safe.rs":"62391908ced36ea8f9fb69ade25bae6c07d6edc7e1cc492b0ade7b85e1b1e920","tests/str.rs":"ef7d7d4a187ab37d23f528adb3b6dcf819e82fadd8fc9ad807afb4e7771a41d9"},"package":"62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080"} \ No newline at end of file +{"files":{"Cargo.lock":"411792dbebe7caa62510806303525467bf8caf2006017b8c0e4f032d12596425","Cargo.toml":"e92f7c0946b14cdff3bbc013060b49ed335619361704287666f7884391d76d8d","FAQ.md":"23e5c1ac0158e9e33dae4d3f48bb6b63037ee16e55c476da4cbeedcabe0be0fc","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"443319f333d92d6ad50ade54334c49609e5b116442639b4134b2dd95b49f8d8f","RELEASES.md":"8aec36d41d35b65212b100bd76ef3102f2872f3cfe5fad8fac59a1c76ad1e9b9","build.rs":"2ec988611a2efa7aa89a1835731edcd15d019787d8184e1dac3126756121c586","examples/README.md":"537e6fe9cf696fd4ada9c08bf31055ed6e366ed65668a523e7c5fde77f97c8d3","examples/cpu_monitor.rs":"cc21a2635059ab2d86622d86508ce360c105417522b7bd1f8e0b3ac845ed484a","src/collections/binary_heap.rs":"55f2d9de4b53ce1e9e353362dc344f432e4ee0400dff6d5ea85a06a41eaa6b3e","src/collections/btree_map.rs":"d3094ed5c54620f81a86133f52e74164bae9f0137745eb66e6d31db2e942bcab","src/collections/btree_set.rs":"7de12e388d36cb2f8672bc3b68aed5b44d047c9f5fe262a7260584634299480f","src/collections/hash_map.rs":"f196ff806a334093d8f4d2d72f6e257517209996f5a6a2031b183d5130720bb4","src/collections/hash_set.rs":"2c0a8a91523a076d9153e6b7c19d2aabecc4706253b25fd6b20a0bd389253e60","src/collections/linked_list.rs":"bef7f32da49b55db76cfefa0afa4789a6979e08a69427e49bab2874967163fef","src/collections/mod.rs":"037660cbdd5907808f7df59fa69993582bf978ecaf125a83a1205452bb505a53","src/collections/vec_deque.rs":"51b3f019c05fcaff9916e258312146c540635cb38941291748f01926d4955a72","src/compile_fail/cannot_collect_filtermap_data.rs":"6a141076c14f95e31bed3433d531bc05d806eed9e0018d1b21420d7ab2fc7eb9","src/compile_fail/cannot_zip_filtered_data.rs":"a28cfb3d00b8d277bfa77a10ca132f972e8f100080ef602fdd3c6fd36ad2a156","src/compile_fail/cell_par_iter.rs":"4f076862d9c66ed42a642a5be97116ca5982608ab76816a8f8305182bf463e9e","src/compile_fail/mod.rs":"2c346e4b52941fe0ac2667eeb753c0c21a1f998a544bb9d9167f200caba0a7bb","src/compile_fail/must_use.rs":"8f26766396842fd83790f1afdc20a926bbc1ed9b5cede8d6bec172c1e7d42ed2","src/compile_fail/no_send_par_iter.rs":"e78cd466a61081a0738f63b4e74249e40c37b95240e47e3faeab6ffdb6a8f14c","src/compile_fail/rc_par_iter.rs":"0faf3d26a665c3e2acc2f2f1d66ee234e561d24442efa4980a5e946e1cb2eba3","src/delegate.rs":"897b9118443a50f1690b2506bc349cd233496eea05fa38f0bce821809a23e528","src/iter/chain.rs":"f82a25577ca36bac93b5a13e75dcd70e8cee381b9baa5993dd645f0714fb9eb6","src/iter/chunks.rs":"8ab345783cb7412438eed33264d7db79873801784af7dab25291c349c678085f","src/iter/cloned.rs":"35e1c864f99f7bc93c258c4976d15ccfc1d04df969dc878fd03d35f6799377f7","src/iter/collect/consumer.rs":"cb6f17f46fc56a782afb2a0e023338ebedefe3e7968a84fa8e513c6b89344a64","src/iter/collect/mod.rs":"bd2996860b205315df560e01900232e6a82940a62c4c9ad99c41f0a2423ef2a2","src/iter/collect/test.rs":"7fcf412afa8461312f7893a36e0a50baca0e495a1fe20885dc62b52d8f68b978","src/iter/copied.rs":"4a5de15719de5e6337925f993e0a55c87d8a62b8bbf6c0a4e2bd877136581afc","src/iter/empty.rs":"3cb2d05721aab1a4d9e9c5813473e1646116c1ea570e26d9ac81e083688a0b7d","src/iter/enumerate.rs":"3204255723a93b3275cf0f208939de8960b13a9b13b8c2ba6b664e65da21cd87","src/iter/extend.rs":"11c46e4cab6b1f3f3d82e1555f92c79b2ea9a833258b88142f14dc6d3eed4e15","src/iter/filter.rs":"c8ceea2f71afd1ffc7c713d8683e337e2c4bc3327f47d25116039ab7d950376f","src/iter/filter_map.rs":"18b2fa2d5119297ed6218e353ebb50e7cf4c853e76b9feffd2f332a885d8811d","src/iter/find.rs":"73b11b97eae7234099a05b5f59c937fe488e6a8574b9c9e4e852a7fa86341117","src/iter/find_first_last/mod.rs":"fa7d7692d81ecdbecb178606ad3b1b00c80e5e4159c57d34929b012b0bea0c82","src/iter/find_first_last/test.rs":"2052eb8b87c5a0a0d49a76c83d9d74f81be18aad52ceb1b06d7e209f4fefba94","src/iter/flat_map.rs":"073f67369d2e8b8ed217174bed5ad427e9ddc1b55e57f2c0e5e8b22a61a59b71","src/iter/flatten.rs":"a9144e37855b33d1c08f1c4179e0089ed6bc7d4b645fcf36c46a8ed687961d07","src/iter/fold.rs":"874259b408d7f8cdc376d34276d37c1837950c035ff780de8281d1edf65ded9f","src/iter/for_each.rs":"7af0e21ed8479eec65831d1409f61a88d45a31764f2385ec759eda1a46d388b2","src/iter/from_par_iter.rs":"9439b1ae01db2c7545d6416108700dfbafcff3f584e81704cf985ab1d986b660","src/iter/inspect.rs":"d4f5c031e4a79c01b8439b5e3c78b637ecb4bcf191c8d98ec9f31a0b51977abc","src/iter/interleave.rs":"dcda8d2bd46de25227ac88243ff6ca97fcf1dbb89f935b651fd04c1ecf1abe8a","src/iter/interleave_shortest.rs":"a2b1f31ea4cb29f4761d3724feddcf5a96e1f21fd623f95c85a8659294a6745a","src/iter/intersperse.rs":"6b5d3d826ed3499ba78f0ff07468d96a0e104c7ee142a2ced6be8143b43241a5","src/iter/len.rs":"427548a874aa3036adbaf12034f5065382a8e98f9131b13c6a8c92c7b97e596d","src/iter/map.rs":"66e6db399de12327fec29d069462347dd16fd96d450b121ba8227e32e51552d1","src/iter/map_with.rs":"f83950016bb02addecec049fda73663861c80232477a7b89b7e8718291a4b481","src/iter/mod.rs":"31a1625080d04e7447163f6e12c24e51db00526c5c598b1832ebaee7b4f9b73d","src/iter/multizip.rs":"10ec107f6673c9bc6d1d611e11b716c37e8601ab2f4257a460c4bc4962771347","src/iter/noop.rs":"5be6332ddfbb8fdbae1ffdb00983950a8b37a295bcb58e9a265b33806ee504e6","src/iter/once.rs":"fcebffc374dcdd206d13311dcc2e7d7a04da5687658b2f3ec3409f03ed12774b","src/iter/panic_fuse.rs":"2a4d43fa4e717629de7f69eb180f13db90ef95004975cfa20dcfaacc80435015","src/iter/par_bridge.rs":"26cd2dbc57e5dd2c1b99b19f8ee66900e5ad7e99a5d8b22e947426f944f72b37","src/iter/plumbing/README.md":"d9ae3d57a37af5645b1c79029dd808933279d6853b30163cd0d71ead2a9a5002","src/iter/plumbing/mod.rs":"1156c55a15b651d161f463cb86b2f602f6246a3c7f8a82fb484db12aa6a60091","src/iter/product.rs":"da69f4781c2275c4a176432994c3fd80ea1f296afe47b329de61b1d733d990df","src/iter/reduce.rs":"2f5d6e07d7c0de2360505fa5d9198c31fd43ba7e58a6ec40f79edec19319e502","src/iter/repeat.rs":"ed46b17b79d8569f9d67b50585b116ee0293e1d6c17c0dc683c66644f6a58fd5","src/iter/rev.rs":"c4c796d7cb6398e74bef043a080403acccdf70f6a4e74b242e530d1718969b8f","src/iter/skip.rs":"f1566b395a2b2e95ee14a056b28cf2532f2f9c4d2abc379a1d313ff5a837a51f","src/iter/splitter.rs":"0024db04b4430c2a1e8c921cec86af641f612f877f3675b15df0da9122de5f00","src/iter/step_by.rs":"7e02b9c18a2dc14f637959d0f90dabe877dd51d6dcd085a01c536be59c2bbcdb","src/iter/sum.rs":"cf11d996507ceba39524a102559b84289e776f8fe5772114e00ae2112b38c47c","src/iter/take.rs":"e47eeca1249553b0dfaf54cd8f99026be68db76b42f1f29e09c07a98c165c50a","src/iter/test.rs":"52ab229c2d8c4d4baf0d0cb439accbced982da088d66c3b404c97ef6bc0e136c","src/iter/try_fold.rs":"585d5a69480e1510f3d006c3bff810c98dd009ab44fa9a15a76beeea4fd8c3f2","src/iter/try_reduce.rs":"747f46db1f2d7178b40735828d877b06802296f0d69662d176062920e9a64067","src/iter/try_reduce_with.rs":"1958debdc53fab22b0d0eb603f22647fd96af44a4308549a56dd71256edd1525","src/iter/unzip.rs":"1d617107bd04cd944e64bd83482206ebfdb894a1778dcbbfc9021addf02234e6","src/iter/update.rs":"08a222cf7f8f2f82389ca48d89ecef3a88e205d21ce249f2ba15a4ff85134473","src/iter/while_some.rs":"a514891d7a07031354b48e377c239ff330d0955f184abc57a69d2a193e7fcb45","src/iter/zip.rs":"4d908f75a10b5e9b68d012bbba289f3e5e9d6a9570ce0f56fc1b4f9d96860499","src/iter/zip_eq.rs":"4c18d8f7a78e197a3268c9ef74d16690f8c960407c18bb63dc6905a2fe2bde62","src/lib.rs":"5181dcfb4ffd2149868982ed0b2c465b6199fadb61b3558e68232b9735b25435","src/math.rs":"181859dc38d787143016ce2952b6e45c5ec085d942a591bd5eaf6fe8905711a9","src/option.rs":"00979a9bb8f42629f2b956a6cfbd286fc8a41ffbbec85f1b5d0f0da5615dac9c","src/par_either.rs":"afa4b04ba6ea1d37aed2d68eca44d7ba0d1d09ea985c9091540dd8d3c51974f1","src/prelude.rs":"95b936c390cbfbbdeeca25adf81ea0db49f38ba46bbb82b9a1ebc42eed673abb","src/private.rs":"152f6d65ce4741616a1dec796b9442f78a018d38bb040f76c4cd85008333a3bb","src/range.rs":"f0174450758ecf75812e2687a59324640da19e0518bb5cdce538bd93bd5e6e03","src/range_inclusive.rs":"e20a077d6e934e37822269ff06fb16926397cb725b790d8cf0d0ef58674a9c69","src/result.rs":"0656f0000efcea10e571df90247925dfd00a0c2194043fcbc009711fb2f7af02","src/slice/mergesort.rs":"36862f9ae70e35b905212a3c9374b5409fe32855aa067128537ad06578bb582f","src/slice/mod.rs":"1b60de0ecd6e143bc729d18a2710f493ed040fcc398de992dba1836fab9ad4b3","src/slice/quicksort.rs":"874359bd23b90ebe78b2c5f9d5887c9fb063e765c905efb97c88669a6aadd88d","src/slice/test.rs":"d7aa8dbae27ef16687e673c64cde854238c37697a6ff2ce64984ec6381388006","src/split_producer.rs":"2b143e16bc6540792f861e215a86cfea7f4ee500d4faca2476d4165619eac90d","src/str.rs":"084d1e5b14f9b366519441065af7a4361ac0a96e5bfd5140c8e881c947448afc","src/vec.rs":"8f6529ec4842dec8b115f0563e5faf81f47530565685ce773416751724b86678","tests/chars.rs":"5a2bef1cd8a7d1740a4e5403830da7bbdd584e97d602a07645c4986ee34c2ad3","tests/clones.rs":"3a1a29eab0efb960fce3d0c32c8d105cc076ce6cf342d3468af2510ee941bf59","tests/collect.rs":"27173f932d5c65932ad63c215c561ecf06fcbeb7253a7bb175b819e0a40107aa","tests/cross-pool.rs":"103c121c8684eef0868e3982219e406500009c26d7602167f5a514b1dfd3b4cc","tests/debug.rs":"6672ec732f46fb9fdc62d034bda14069ac9db4bfecae7700e400fafabb584741","tests/intersperse.rs":"bda4fb2179086e32c77c8293b9bb85d55509c282441837ba1849c2d3aa3186a7","tests/issue671-unzip.rs":"d5eb38d8a6d8f66fdf1c40293abbf58f3ac42b5acfc5dca62b02c7ace5bfc1a4","tests/issue671.rs":"52914cac517074deaedcb81bd76b867f0b99cc7b65c3e01cfe12dc9fe38c0266","tests/iter_panic.rs":"376faac33739e3479b5eb744bb2c810c27f8fdda5eeb9ad96d8b93619bf11d1c","tests/named-threads.rs":"48dd0fa0de13b4554dfc1fc0adaee093e19df8b1fc601f5b9b4f15b1fc705249","tests/octillion.rs":"c136ae4612e0d964fc9cb0bcc058a04d0a59c35ba53e0304cdf1d7a0678502fc","tests/producer_split_at.rs":"a6769ac158d810cc292c23a3ee0d583f2fa77ff547f43a40f20f309764c3fb88","tests/sort-panic-safe.rs":"62391908ced36ea8f9fb69ade25bae6c07d6edc7e1cc492b0ade7b85e1b1e920","tests/str.rs":"ef7d7d4a187ab37d23f528adb3b6dcf819e82fadd8fc9ad807afb4e7771a41d9"},"package":"cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270"} \ No newline at end of file diff --git a/vendor/rayon/Cargo.lock b/vendor/rayon/Cargo.lock index 7de29b8ff1..829b7d2d0c 100644 --- a/vendor/rayon/Cargo.lock +++ b/vendor/rayon/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -10,7 +10,7 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -19,37 +19,36 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "crossbeam-deque" -version = "0.7.3" +name = "crossbeam-channel" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-epoch" -version = "0.8.2" +name = "crossbeam-deque" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-queue" -version = "0.2.3" +name = "crossbeam-epoch" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -57,7 +56,7 @@ name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -69,13 +68,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "either" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -84,16 +83,16 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -103,7 +102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.71" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -118,10 +117,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memoffset" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -129,21 +128,21 @@ name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -151,7 +150,7 @@ name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -160,7 +159,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -171,7 +170,7 @@ name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -201,26 +200,26 @@ dependencies = [ [[package]] name = "rayon" -version = "1.3.1" +version = "1.4.0" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -231,7 +230,7 @@ name = "regex" version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -249,20 +248,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.112" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.112" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -272,12 +271,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.31" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -290,7 +289,7 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -299,39 +298,39 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" +"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -"checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum docopt 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f525a586d310c87df72ebcd98009e57f1cc030c8c268305287a476beb653969" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +"checksum libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)" = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" +"checksum memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" "checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" -"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +"checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" -"checksum rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280" +"checksum rayon-core 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91739a34c4355b5434ce54c9086c5895604a9c278586d1f1aa95e04f66b525a0" "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -"checksum serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" -"checksum serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" +"checksum serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +"checksum serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" "checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" -"checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" +"checksum syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/vendor/rayon/Cargo.toml b/vendor/rayon/Cargo.toml index 4acbf210c5..14f3441a3a 100644 --- a/vendor/rayon/Cargo.toml +++ b/vendor/rayon/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "rayon" -version = "1.3.1" +version = "1.4.0" authors = ["Niko Matsakis ", "Josh Stone "] exclude = ["/ci/*", "/scripts/*", "/.github/*", "/bors.toml"] description = "Simple work-stealing parallelism for Rust" @@ -31,7 +31,7 @@ version = "1.0" default-features = false [dependencies.rayon-core] -version = "1.7.1" +version = "1.8.0" [dev-dependencies.docopt] version = "1" diff --git a/vendor/rayon/RELEASES.md b/vendor/rayon/RELEASES.md index 329c8fecc9..0d45357cc1 100644 --- a/vendor/rayon/RELEASES.md +++ b/vendor/rayon/RELEASES.md @@ -1,3 +1,25 @@ +# Release rayon 1.4.0 / rayon-core 1.8.0 (2020-08-24) + +- Implemented a new thread scheduler, [RFC 5], which uses targeted wakeups for + new work and for notifications of completed stolen work, reducing wasteful + CPU usage in idle threads. +- Implemented `IntoParallelIterator for Range` and `RangeInclusive` + with the same iteration semantics as Rust 1.45. +- Relaxed the lifetime requirements of the initial `scope` closure. + +[RFC 5]: https://github.com/rayon-rs/rfcs/pull/5 + +## Contributors + +Thanks to all of the contributors for this release! + +- @CAD97 +- @cuviper +- @kmaork +- @nikomatsakis +- @SuperFluffy + + # Release rayon 1.3.1 / rayon-core 1.7.1 (2020-06-15) - Fixed a use-after-free race in calls blocked between two rayon thread pools. diff --git a/vendor/rayon/src/iter/collect/mod.rs b/vendor/rayon/src/iter/collect/mod.rs index c6bd60f041..e18298e310 100644 --- a/vendor/rayon/src/iter/collect/mod.rs +++ b/vendor/rayon/src/iter/collect/mod.rs @@ -86,7 +86,7 @@ impl<'c, T: Send + 'c> Collect<'c, T> { /// the vector is complete with the collected result. fn with_consumer(mut self, scope_fn: F) where - F: FnOnce(CollectConsumer) -> CollectResult, + F: FnOnce(CollectConsumer<'_, T>) -> CollectResult<'_, T>, { unsafe { let slice = Self::reserve_get_tail_slice(&mut self.vec, self.len); diff --git a/vendor/rayon/src/iter/mod.rs b/vendor/rayon/src/iter/mod.rs index 3c05de957b..ff4c5dd82a 100644 --- a/vendor/rayon/src/iter/mod.rs +++ b/vendor/rayon/src/iter/mod.rs @@ -1864,10 +1864,15 @@ pub trait ParallelIterator: Sized + Send { /// Creates a fresh collection containing all the elements produced /// by this parallel iterator. /// - /// You may prefer to use `collect_into_vec()`, which allocates more - /// efficiently with precise knowledge of how many elements the - /// iterator contains, and even allows you to reuse an existing - /// vector's backing store rather than allocating a fresh vector. + /// You may prefer [`collect_into_vec()`] implemented on + /// [`IndexedParallelIterator`], if your underlying iterator also implements + /// it. [`collect_into_vec()`] allocates efficiently with precise knowledge + /// of how many elements the iterator contains, and even allows you to reuse + /// an existing vector's backing store rather than allocating a fresh vector. + /// + /// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html + /// [`collect_into_vec()`]: + /// trait.IndexedParallelIterator.html#method.collect_into_vec /// /// # Examples /// diff --git a/vendor/rayon/src/lib.rs b/vendor/rayon/src/lib.rs index 6f7b0274e4..043fa4c468 100644 --- a/vendor/rayon/src/lib.rs +++ b/vendor/rayon/src/lib.rs @@ -1,7 +1,8 @@ -#![doc(html_root_url = "https://docs.rs/rayon/1.3")] +#![doc(html_root_url = "https://docs.rs/rayon/1.4")] #![deny(missing_debug_implementations)] #![deny(missing_docs)] #![deny(unreachable_pub)] +#![warn(rust_2018_idioms)] //! Data-parallelism library that makes it easy to convert sequential //! computations into parallel diff --git a/vendor/rayon/src/private.rs b/vendor/rayon/src/private.rs index a99dd11fb2..c85e77b9cb 100644 --- a/vendor/rayon/src/private.rs +++ b/vendor/rayon/src/private.rs @@ -14,7 +14,7 @@ macro_rules! private_decl { /// impossible to implement outside the crate. #[doc(hidden)] fn __rayon_private__(&self) -> crate::private::PrivateMarker; - } + }; } macro_rules! private_impl { @@ -22,5 +22,5 @@ macro_rules! private_impl { fn __rayon_private__(&self) -> crate::private::PrivateMarker { crate::private::PrivateMarker } - } + }; } diff --git a/vendor/rayon/src/range.rs b/vendor/rayon/src/range.rs index f3b0c5181c..09ba25ec95 100644 --- a/vendor/rayon/src/range.rs +++ b/vendor/rayon/src/range.rs @@ -18,6 +18,7 @@ use crate::iter::plumbing::*; use crate::iter::*; +use std::char; use std::ops::Range; use std::usize; @@ -223,6 +224,75 @@ unindexed_range_impl! {i64, u64} unindexed_range_impl! {u128, u128} unindexed_range_impl! {i128, u128} +// char is special because of the surrogate range hole +macro_rules! convert_char { + ( $self:ident . $method:ident ( $( $arg:expr ),* ) ) => {{ + let start = $self.range.start as u32; + let end = $self.range.end as u32; + if start < 0xD800 && 0xE000 < end { + // chain the before and after surrogate range fragments + (start..0xD800) + .into_par_iter() + .chain(0xE000..end) + .map(|codepoint| unsafe { char::from_u32_unchecked(codepoint) }) + .$method($( $arg ),*) + } else { + // no surrogate range to worry about + (start..end) + .into_par_iter() + .map(|codepoint| unsafe { char::from_u32_unchecked(codepoint) }) + .$method($( $arg ),*) + } + }}; +} + +impl ParallelIterator for Iter { + type Item = char; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + convert_char!(self.drive(consumer)) + } + + fn opt_len(&self) -> Option { + Some(self.len()) + } +} + +impl IndexedParallelIterator for Iter { + // Split at the surrogate range first if we're allowed to + fn drive(self, consumer: C) -> C::Result + where + C: Consumer, + { + convert_char!(self.drive(consumer)) + } + + fn len(&self) -> usize { + // Taken from ::steps_between + let start = self.range.start as u32; + let end = self.range.end as u32; + if start < end { + let mut count = end - start; + if start < 0xD800 && 0xE000 <= end { + count -= 0x800 + } + count as usize + } else { + 0 + } + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback, + { + convert_char!(self.with_producer(callback)) + } +} + #[test] fn check_range_split_at_overflow() { // Note, this split index overflows i8! diff --git a/vendor/rayon/src/range_inclusive.rs b/vendor/rayon/src/range_inclusive.rs index c1757701a5..c802b6c61d 100644 --- a/vendor/rayon/src/range_inclusive.rs +++ b/vendor/rayon/src/range_inclusive.rs @@ -18,6 +18,7 @@ use crate::iter::plumbing::*; use crate::iter::*; +use std::char; use std::ops::RangeInclusive; /// Parallel iterator over an inclusive range, implemented for all integer types. @@ -48,7 +49,8 @@ pub struct Iter { impl Iter where - RangeInclusive: Clone + Iterator + DoubleEndedIterator, + RangeInclusive: Eq, + T: Ord + Copy, { /// Returns `Some((start, end))` for `start..=end`, or `None` if it is exhausted. /// @@ -56,7 +58,16 @@ where /// so this is a way for us to figure out what we've got. Thankfully, all of the /// integer types we care about can be trivially cloned. fn bounds(&self) -> Option<(T, T)> { - Some((self.range.clone().next()?, self.range.clone().next_back()?)) + let start = *self.range.start(); + let end = *self.range.end(); + if start <= end && self.range == (start..=end) { + // If the range is still nonempty, this is obviously true + // If the range is exhausted, either start > end or + // the range does not equal start..=end. + Some((start, end)) + } else { + None + } } } @@ -147,6 +158,80 @@ parallel_range_impl! {i64} parallel_range_impl! {u128} parallel_range_impl! {i128} +// char is special +macro_rules! convert_char { + ( $self:ident . $method:ident ( $( $arg:expr ),* ) ) => { + if let Some((start, end)) = $self.bounds() { + let start = start as u32; + let end = end as u32; + if start < 0xD800 && 0xE000 <= end { + // chain the before and after surrogate range fragments + (start..0xD800) + .into_par_iter() + .chain(0xE000..end + 1) // cannot use RangeInclusive, so add one to end + .map(|codepoint| unsafe { char::from_u32_unchecked(codepoint) }) + .$method($( $arg ),*) + } else { + // no surrogate range to worry about + (start..end + 1) // cannot use RangeInclusive, so add one to end + .into_par_iter() + .map(|codepoint| unsafe { char::from_u32_unchecked(codepoint) }) + .$method($( $arg ),*) + } + } else { + empty().into_par_iter().$method($( $arg ),*) + } + }; +} + +impl ParallelIterator for Iter { + type Item = char; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + convert_char!(self.drive(consumer)) + } + + fn opt_len(&self) -> Option { + Some(self.len()) + } +} + +// Range is broken on 16 bit platforms, may as well benefit from it +impl IndexedParallelIterator for Iter { + // Split at the surrogate range first if we're allowed to + fn drive(self, consumer: C) -> C::Result + where + C: Consumer, + { + convert_char!(self.drive(consumer)) + } + + fn len(&self) -> usize { + if let Some((start, end)) = self.bounds() { + // Taken from ::steps_between + let start = start as u32; + let end = end as u32; + let mut count = end - start; + if start < 0xD800 && 0xE000 <= end { + count -= 0x800 + } + (count + 1) as usize // add one for inclusive + } else { + 0 + } + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback, + { + convert_char!(self.with_producer(callback)) + } +} + #[test] #[cfg(target_pointer_width = "64")] fn test_u32_opt_len() { diff --git a/vendor/rayon/src/slice/mod.rs b/vendor/rayon/src/slice/mod.rs index e01fb11f5e..b80125f549 100644 --- a/vendor/rayon/src/slice/mod.rs +++ b/vendor/rayon/src/slice/mod.rs @@ -110,7 +110,7 @@ pub trait ParallelSlice { let len = slice.len() - rem; let (fst, snd) = slice.split_at(len); ChunksExact { - chunk_size: chunk_size, + chunk_size, slice: fst, rem: snd, } @@ -199,7 +199,7 @@ pub trait ParallelSliceMut { let len = slice.len() - rem; let (fst, snd) = slice.split_at_mut(len); ChunksExactMut { - chunk_size: chunk_size, + chunk_size, slice: fst, rem: snd, } diff --git a/vendor/rayon/tests/chars.rs b/vendor/rayon/tests/chars.rs new file mode 100644 index 0000000000..ac8e3f3046 --- /dev/null +++ b/vendor/rayon/tests/chars.rs @@ -0,0 +1,39 @@ +use rayon::prelude::*; +use std::char; + +#[test] +fn half_open_correctness() { + let low = char::from_u32(0xD800 - 0x7).unwrap(); + let high = char::from_u32(0xE000 + 0x7).unwrap(); + + let range = low..high; + let mut chars: Vec = range.into_par_iter().collect(); + chars.sort(); + + assert_eq!( + chars, + vec![ + '\u{D7F9}', '\u{D7FA}', '\u{D7FB}', '\u{D7FC}', '\u{D7FD}', '\u{D7FE}', '\u{D7FF}', + '\u{E000}', '\u{E001}', '\u{E002}', '\u{E003}', '\u{E004}', '\u{E005}', '\u{E006}', + ] + ); +} + +#[test] +fn closed_correctness() { + let low = char::from_u32(0xD800 - 0x7).unwrap(); + let high = char::from_u32(0xE000 + 0x7).unwrap(); + + let range = low..=high; + let mut chars: Vec = range.into_par_iter().collect(); + chars.sort(); + + assert_eq!( + chars, + vec![ + '\u{D7F9}', '\u{D7FA}', '\u{D7FB}', '\u{D7FC}', '\u{D7FD}', '\u{D7FE}', '\u{D7FF}', + '\u{E000}', '\u{E001}', '\u{E002}', '\u{E003}', '\u{E004}', '\u{E005}', '\u{E006}', + '\u{E007}', + ] + ); +} diff --git a/vendor/rustc-ap-rustc_lexer/.cargo-checksum.json b/vendor/rustc-ap-rustc_lexer-673.0.0/.cargo-checksum.json similarity index 100% rename from vendor/rustc-ap-rustc_lexer/.cargo-checksum.json rename to vendor/rustc-ap-rustc_lexer-673.0.0/.cargo-checksum.json diff --git a/vendor/rustc-ap-rustc_lexer/Cargo.toml b/vendor/rustc-ap-rustc_lexer-673.0.0/Cargo.toml similarity index 100% rename from vendor/rustc-ap-rustc_lexer/Cargo.toml rename to vendor/rustc-ap-rustc_lexer-673.0.0/Cargo.toml diff --git a/vendor/rustc-ap-rustc_lexer/src/cursor.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/cursor.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/cursor.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/cursor.rs diff --git a/vendor/rustc-ap-rustc_lexer/src/lib.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/lib.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/lib.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/lib.rs diff --git a/vendor/rustc-ap-rustc_lexer/src/tests.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/tests.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/tests.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/tests.rs diff --git a/vendor/rustc-ap-rustc_lexer/src/unescape.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/unescape.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/unescape.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/unescape.rs diff --git a/vendor/rustc-ap-rustc_lexer/src/unescape/tests.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/unescape/tests.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/unescape/tests.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/unescape/tests.rs diff --git a/vendor/serde/.cargo-checksum.json b/vendor/serde/.cargo-checksum.json index efb497c91a..ce86133bd3 100644 --- a/vendor/serde/.cargo-checksum.json +++ b/vendor/serde/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"482c1bf9407c9f37a9faf753cd6fc27227a8f8fb2c0f68d4f72391e21999087e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"d6af5a05be728765c2d98d960406ba648333745ed8644be311d2a1f52d7075f0","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/de/from_primitive.rs":"058fa17313ed3a9c29ec04c6ec67f21a756f6f28cdeb4b0dfcd7012b3e702d0b","src/de/ignored_any.rs":"6a0527edd497a56a103ae65f5e73da675b3f99094d6dcad3c335c8d932daaf40","src/de/impls.rs":"3534fafb62bfbd1f043ebbcd5abb1a1f9cf26e0f5443e7125f72928a4a7dc61e","src/de/mod.rs":"0dd0c8bdefa86f621fdeba8f7b5575463c111bf034b0297e80d3aa8fedf40955","src/de/utf8.rs":"f17524ee0af98ec3abcfd7d0b812fbd1033263bd8e2ce2f57c1e1999ce153558","src/de/value.rs":"a878f6bdd57d25b0b93bfc6288ed1e46c50870dc8703748b6fbb8c0965a6b586","src/export.rs":"2ebdf0eccaa64c5e98c6dfd13b4980474f627fc3fae90cfc2c741acf860afd5d","src/integer128.rs":"b213ec6c1ecf8c8228d9591e0b2c31b78d972cd4c6a0b231468090f15784f6f6","src/lib.rs":"40b75a05fff22e4de29a214b75f729988fa9a91c7cc2384706ec2ddfe743c235","src/macros.rs":"f18fc25c5fb857238bf119cdee5c7987a8584dea69c51f27ca718b7dfd871d0f","src/private/de.rs":"bce814fa2f2fd689c6d4a354839f38d7ea260509339181ce83d9b0fdbe0e1b3b","src/private/macros.rs":"ebb6affd4c89e3b5f9a42e03f8b7d966bc588875e9b44e962d0b7aba7f80a10f","src/private/mod.rs":"f8f2cd5edbfc26c268b34cdb89db1b34e6348f81384f03d18532e7568575006d","src/private/ser.rs":"96a1e23ad7f3c8ee51a02d799d92780e19dd3c18fa0f1ad791abef7cb346e224","src/ser/fmt.rs":"7827ed07fd8897e6324f75625ba0c926a4c4e7ec2914cd067391ce54d942ac7b","src/ser/impls.rs":"ce9996998c6485c88bbc77516611e9f5a9a92cbb12d34bb4f8ae022530be85e0","src/ser/impossible.rs":"3dd0e165b88fc67e698e675f16569b91fab9e054caa4c3e1997f929ba364fe90","src/ser/mod.rs":"d1811b0c4002bf89f0b24b6647cd5b489c27738b42acbef8207990b49dd44a74","src/std_error.rs":"3aac687856c035517fae44ed2906dd4a1e3184bae4bf613adcdeb73f74126c57"},"package":"e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"} \ No newline at end of file +{"files":{"Cargo.toml":"736542df95689176d660863d0493740313de4a030a09ffa2b5559c80223769ac","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"d6af5a05be728765c2d98d960406ba648333745ed8644be311d2a1f52d7075f0","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/de/from_primitive.rs":"058fa17313ed3a9c29ec04c6ec67f21a756f6f28cdeb4b0dfcd7012b3e702d0b","src/de/ignored_any.rs":"6a0527edd497a56a103ae65f5e73da675b3f99094d6dcad3c335c8d932daaf40","src/de/impls.rs":"077487d2bacd1fd2093e3ef2fa0d52abe7b9530a84d1ccf9eefb4ad81b6bbad1","src/de/mod.rs":"b59c365b05e4e09a7467c958f85b2c64435514c59c17275be019397ad7ccb00e","src/de/utf8.rs":"f17524ee0af98ec3abcfd7d0b812fbd1033263bd8e2ce2f57c1e1999ce153558","src/de/value.rs":"a878f6bdd57d25b0b93bfc6288ed1e46c50870dc8703748b6fbb8c0965a6b586","src/export.rs":"2ebdf0eccaa64c5e98c6dfd13b4980474f627fc3fae90cfc2c741acf860afd5d","src/integer128.rs":"b213ec6c1ecf8c8228d9591e0b2c31b78d972cd4c6a0b231468090f15784f6f6","src/lib.rs":"c8b0d22a63c9250342fbd3a3b263435e7bca98d9091a3bad5db026eac4877ef9","src/macros.rs":"f18fc25c5fb857238bf119cdee5c7987a8584dea69c51f27ca718b7dfd871d0f","src/private/de.rs":"bce814fa2f2fd689c6d4a354839f38d7ea260509339181ce83d9b0fdbe0e1b3b","src/private/macros.rs":"ebb6affd4c89e3b5f9a42e03f8b7d966bc588875e9b44e962d0b7aba7f80a10f","src/private/mod.rs":"f8f2cd5edbfc26c268b34cdb89db1b34e6348f81384f03d18532e7568575006d","src/private/ser.rs":"96a1e23ad7f3c8ee51a02d799d92780e19dd3c18fa0f1ad791abef7cb346e224","src/ser/fmt.rs":"7827ed07fd8897e6324f75625ba0c926a4c4e7ec2914cd067391ce54d942ac7b","src/ser/impls.rs":"ce9996998c6485c88bbc77516611e9f5a9a92cbb12d34bb4f8ae022530be85e0","src/ser/impossible.rs":"3dd0e165b88fc67e698e675f16569b91fab9e054caa4c3e1997f929ba364fe90","src/ser/mod.rs":"9c26100d8058a5c39aea72512fb78de959e4ed9199481eef47996f0864df0f2c","src/std_error.rs":"3aac687856c035517fae44ed2906dd4a1e3184bae4bf613adcdeb73f74126c57"},"package":"96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"} \ No newline at end of file diff --git a/vendor/serde/Cargo.toml b/vendor/serde/Cargo.toml index 437c270c99..4e6fa348f2 100644 --- a/vendor/serde/Cargo.toml +++ b/vendor/serde/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "serde" -version = "1.0.115" +version = "1.0.116" authors = ["Erick Tryzelaar ", "David Tolnay "] build = "build.rs" include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] @@ -30,7 +30,7 @@ targets = ["x86_64-unknown-linux-gnu"] [package.metadata.playground] features = ["derive", "rc"] [dependencies.serde_derive] -version = "=1.0.115" +version = "=1.0.116" optional = true [dev-dependencies.serde_derive] version = "1.0" diff --git a/vendor/serde/src/de/impls.rs b/vendor/serde/src/de/impls.rs index e460a40d6c..ae4f9dc806 100644 --- a/vendor/serde/src/de/impls.rs +++ b/vendor/serde/src/de/impls.rs @@ -1313,7 +1313,7 @@ macro_rules! variant_identifier { formatter.write_str($expecting_message) } - fn visit_u32(self, value: u32) -> Result + fn visit_u64(self, value: u64) -> Result where E: Error, { @@ -1321,7 +1321,7 @@ macro_rules! variant_identifier { $( $index => Ok($name_kind :: $variant), )* - _ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),), + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self),), } } @@ -2326,7 +2326,7 @@ where formatter.write_str("`Unbounded`, `Included` or `Excluded`") } - fn visit_u32(self, value: u32) -> Result + fn visit_u64(self, value: u64) -> Result where E: Error, { @@ -2335,7 +2335,7 @@ where 1 => Ok(Field::Included), 2 => Ok(Field::Excluded), _ => Err(Error::invalid_value( - Unexpected::Unsigned(value as u64), + Unexpected::Unsigned(value), &self, )), } @@ -2492,7 +2492,7 @@ where formatter.write_str("`Ok` or `Err`") } - fn visit_u32(self, value: u32) -> Result + fn visit_u64(self, value: u64) -> Result where E: Error, { @@ -2500,7 +2500,7 @@ where 0 => Ok(Field::Ok), 1 => Ok(Field::Err), _ => Err(Error::invalid_value( - Unexpected::Unsigned(value as u64), + Unexpected::Unsigned(value), &self, )), } diff --git a/vendor/serde/src/de/mod.rs b/vendor/serde/src/de/mod.rs index f1b8b3129a..6d39473633 100644 --- a/vendor/serde/src/de/mod.rs +++ b/vendor/serde/src/de/mod.rs @@ -104,7 +104,7 @@ //! [`Deserialize`]: ../trait.Deserialize.html //! [`Deserializer`]: ../trait.Deserializer.html //! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html -//! [`bincode`]: https://github.com/TyOverby/bincode +//! [`bincode`]: https://github.com/servo/bincode //! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map //! [`serde_derive`]: https://crates.io/crates/serde_derive //! [`serde_json`]: https://github.com/serde-rs/json diff --git a/vendor/serde/src/lib.rs b/vendor/serde/src/lib.rs index 7c4733c23f..fe40eb1ca8 100644 --- a/vendor/serde/src/lib.rs +++ b/vendor/serde/src/lib.rs @@ -48,7 +48,7 @@ //! definition. //! - [JSON5], A superset of JSON including some productions from ES5. //! - [Postcard], a no\_std and embedded-systems friendly compact binary format. -//! - [URL], the x-www-form-urlencoded format. +//! - [URL] query strings, in the x-www-form-urlencoded format. //! - [Envy], a way to deserialize environment variables into Rust structs. //! *(deserialization only)* //! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into @@ -59,7 +59,7 @@ //! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy serialization format. //! //! [JSON]: https://github.com/serde-rs/json -//! [Bincode]: https://github.com/TyOverby/bincode +//! [Bincode]: https://github.com/servo/bincode //! [CBOR]: https://github.com/pyfisch/cbor //! [YAML]: https://github.com/dtolnay/serde-yaml //! [MessagePack]: https://github.com/3Hren/msgpack-rust @@ -70,7 +70,7 @@ //! [Avro]: https://github.com/flavray/avro-rs //! [JSON5]: https://github.com/callum-oakley/json5-rs //! [Postcard]: https://github.com/jamesmunns/postcard -//! [URL]: https://github.com/nox/serde_urlencoded +//! [URL]: https://docs.rs/serde_qs //! [Envy]: https://github.com/softprops/envy //! [Envy Store]: https://github.com/softprops/envy-store //! [Cargo]: http://doc.crates.io/manifest.html @@ -82,7 +82,7 @@ //////////////////////////////////////////////////////////////////////////////// // Serde types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/serde/1.0.115")] +#![doc(html_root_url = "https://docs.rs/serde/1.0.116")] // Support using Serde without the standard library! #![cfg_attr(not(feature = "std"), no_std)] // Unstable functionality only if the user asks for it. For tracking and diff --git a/vendor/serde/src/ser/mod.rs b/vendor/serde/src/ser/mod.rs index 676b0e2f70..8a4b2e3669 100644 --- a/vendor/serde/src/ser/mod.rs +++ b/vendor/serde/src/ser/mod.rs @@ -99,7 +99,7 @@ //! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html //! [`Serialize`]: ../trait.Serialize.html //! [`Serializer`]: ../trait.Serializer.html -//! [`bincode`]: https://github.com/TyOverby/bincode +//! [`bincode`]: https://github.com/servo/bincode //! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map //! [`serde_derive`]: https://crates.io/crates/serde_derive //! [`serde_json`]: https://github.com/serde-rs/json diff --git a/vendor/serde_derive/.cargo-checksum.json b/vendor/serde_derive/.cargo-checksum.json index 88dab0b2c5..915ba422d6 100644 --- a/vendor/serde_derive/.cargo-checksum.json +++ b/vendor/serde_derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"14b95c381d691c061057f9941709d277b8f6082a2cbe86a0b967c02d965ceb8f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"17fac4a28904e90c1e46b517839bd17fd54dbc69cfbff7451f695ecf7bab34ef","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/bound.rs":"66643d6cd044a2167b2bb8a1970e5b2a07069e362ce1326a4b00fef7bcfcd5c8","src/de.rs":"8bea1aa8057c824264bb4700fa6531747bfaed88be2d1f90bb6455600aa8e222","src/dummy.rs":"7bc4267039808046fe0a7fbeb462b301ac30ea1152fcbde8a3b934dc143fe468","src/fragment.rs":"5548ba65a53d90a296f60c1328a7a7fb040db467f59c2f5210b2fb320457145d","src/internals/ast.rs":"f1a1b13cf6b68e2bf27c5cdcdbde6883f86cde1ba8c0595dffdbf2e11c4ec8b1","src/internals/attr.rs":"554bf48da8fb4e8a5ac2d16143cc9dc05e9bc493b4a4c8a196ace360bce110d5","src/internals/case.rs":"b2024f414f5d832bafa53b9ae7924b2d43a29175b19bb3da36f15c9071666558","src/internals/check.rs":"9a01a0db1fc3086891e998f544836e7498ebfc7cc5e1956199d0526e6a8d9a3c","src/internals/ctxt.rs":"6fa544ae52914498a62a395818ebdc1b36ac2fb5903c60afb741a864ad559f1c","src/internals/mod.rs":"989df41dae7a9066eec3e5afd5b262fd94a12281df30f4c03f319370811beea0","src/internals/symbol.rs":"9f2b4b9cd83dc09def75165187c97d0050bffa4218782c27b478bcf93f925a74","src/lib.rs":"5a3e1bb473b8f69a69402fec64e4c673865fa6dde2f6dfcccaa934ddad538a77","src/pretend.rs":"ffeb23da4c2abc4e501c378cffa8b776bab506735ea70d4ed10f4c0f3755321b","src/ser.rs":"4ac3d23e5a84b72137d42eaa38ef8ec1516c4d4d9ca040dc5ce2abbf33126443","src/try.rs":"b9a10c8690d442a57fc7097d42c9a4f13034c7b4a30b7eb02d538fdbf8ae0a8d"},"package":"609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"} \ No newline at end of file +{"files":{"Cargo.toml":"74677f4031ffe40137aad8407d240dfe0bd3ed5d07c518afb1983b384f4ee283","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"17fac4a28904e90c1e46b517839bd17fd54dbc69cfbff7451f695ecf7bab34ef","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/bound.rs":"66643d6cd044a2167b2bb8a1970e5b2a07069e362ce1326a4b00fef7bcfcd5c8","src/de.rs":"8bea1aa8057c824264bb4700fa6531747bfaed88be2d1f90bb6455600aa8e222","src/dummy.rs":"7bc4267039808046fe0a7fbeb462b301ac30ea1152fcbde8a3b934dc143fe468","src/fragment.rs":"5548ba65a53d90a296f60c1328a7a7fb040db467f59c2f5210b2fb320457145d","src/internals/ast.rs":"f1a1b13cf6b68e2bf27c5cdcdbde6883f86cde1ba8c0595dffdbf2e11c4ec8b1","src/internals/attr.rs":"554bf48da8fb4e8a5ac2d16143cc9dc05e9bc493b4a4c8a196ace360bce110d5","src/internals/case.rs":"b2024f414f5d832bafa53b9ae7924b2d43a29175b19bb3da36f15c9071666558","src/internals/check.rs":"9a01a0db1fc3086891e998f544836e7498ebfc7cc5e1956199d0526e6a8d9a3c","src/internals/ctxt.rs":"6fa544ae52914498a62a395818ebdc1b36ac2fb5903c60afb741a864ad559f1c","src/internals/mod.rs":"989df41dae7a9066eec3e5afd5b262fd94a12281df30f4c03f319370811beea0","src/internals/symbol.rs":"9f2b4b9cd83dc09def75165187c97d0050bffa4218782c27b478bcf93f925a74","src/lib.rs":"ae786031bb024d49a73e8c0aee126441a9e61dd2bc50ddf7aad4a586fa89081d","src/pretend.rs":"ffeb23da4c2abc4e501c378cffa8b776bab506735ea70d4ed10f4c0f3755321b","src/ser.rs":"4ac3d23e5a84b72137d42eaa38ef8ec1516c4d4d9ca040dc5ce2abbf33126443","src/try.rs":"b9a10c8690d442a57fc7097d42c9a4f13034c7b4a30b7eb02d538fdbf8ae0a8d"},"package":"f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"} \ No newline at end of file diff --git a/vendor/serde_derive/Cargo.toml b/vendor/serde_derive/Cargo.toml index 92f772de82..d06a1bb40a 100644 --- a/vendor/serde_derive/Cargo.toml +++ b/vendor/serde_derive/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "serde_derive" -version = "1.0.115" +version = "1.0.116" authors = ["Erick Tryzelaar ", "David Tolnay "] include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" diff --git a/vendor/serde_derive/src/lib.rs b/vendor/serde_derive/src/lib.rs index 650c519d3d..9307ae8147 100644 --- a/vendor/serde_derive/src/lib.rs +++ b/vendor/serde_derive/src/lib.rs @@ -13,7 +13,7 @@ //! //! [https://serde.rs/derive.html]: https://serde.rs/derive.html -#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.115")] +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.116")] #![allow(unknown_lints, bare_trait_objects)] #![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints diff --git a/vendor/sha2/.cargo-checksum.json b/vendor/sha2/.cargo-checksum.json new file mode 100644 index 0000000000..2651a75ba8 --- /dev/null +++ b/vendor/sha2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"5eac381cb8af4e38b5cffa5cac4364e59c07a6fe322e7c3a0376b6e9dce80f2a","Cargo.lock":"7fd4a53f4adea010f107fe8e6bcc0bd6b2116fb37e0bca9a53293f61a24bc4ab","Cargo.toml":"9ca349cad4ce237ef6df97dacf6cd5d9095feffa52a900efd2393266dce5de90","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1","README.md":"7f4a6be652e4fe713de1df5d3e2f7e243244ebfe6fcda5839e75e720c15f73ee","benches/sha256.rs":"b4c350e12041ba0bd9b99bac401dedb26d6429570787cc3562467e7a129e4f75","benches/sha512.rs":"7550ba0ed7915193977e19a426ba39a6825fc7337beaac6538155f0486d1d1af","examples/sha256sum.rs":"93ecb1972af2193ff88d57644d1807be9ee90f9142f1508fb3fec95a5277dbc3","examples/sha512sum.rs":"385a40d67c9637b220d90820a921c4eb57a5a4f752dcfaf2a4737a8d051c790d","src/consts.rs":"fda715379ca4b68f2deb7413328c91d018221d0af2f592d43871b4ce8a8b2b51","src/lib.rs":"9c5ac8ae7cb85c70edcb94f3af7818777324b6053e7207b05a456477a7383835","src/sha256.rs":"1b4d37bccdeb226e03bcb05621a905ea0d97295062eddc26ab6e00f90e18cd57","src/sha256/aarch64.rs":"3ce2b975a0f26a666e7449bbdd9454353f6506c4cefc1231da6f4572e2dc54c0","src/sha256/soft.rs":"b7f78d833f231996598f69086de25fcaf268faed1466e40075a6ec3d822ee8d1","src/sha256/x86.rs":"fa342ddf524eb172b0f5afd93e825c21b06c8f7b997b4711fc7ac05f73587f81","src/sha512.rs":"56d78bc095c0481027367a1036049251a81aeedf5f8cadbaf6b6f562f753fa9c","src/sha512/soft.rs":"87caece42b26b532ff7ebca8776ac34a0bc51ccd82a3416ef6e04257c510456d","tests/data/sha224.blb":"b20c77259744a50b96e73c602e8473bf811f820f072cf3313d3f254d1d532f30","tests/data/sha256.blb":"9f984fbe1f9b89115db731d9058036dcdaf450d03d732a0a8cf6fb16c7e08a92","tests/data/sha256_one_million_a.bin":"80d1189477563e1b5206b2749f1afe4807e5705e8bd77887a60187a712156688","tests/data/sha384.blb":"305f96c4237a2aeb5d9b66cf30a13d5b41b749c6c8cb079192f45bd81ad404e3","tests/data/sha512.blb":"e3c964b9a735473cf14e64953a0dfee9d98e445ba242d439ffef216e9cfe36e6","tests/data/sha512_224.blb":"8baa081f40124f5a69892d8f1e06867acba094358ad6304b60405210af27160b","tests/data/sha512_256.blb":"f1f15c1040958ed32bc1c44d2947c7827f55e53107e026535343840176cb3608","tests/data/sha512_one_million_a.bin":"a872d736156b28b7784fcc124cfb9993ed31707f1754a0a448d26bf84f5cc7f5","tests/lib.rs":"c7e5067377c91e64c76e6c7f5872f6bb491be8c1eaf2f77be4f10b38d730db24"},"package":"2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1"} \ No newline at end of file diff --git a/vendor/sha2/CHANGELOG.md b/vendor/sha2/CHANGELOG.md new file mode 100644 index 0000000000..9c6d5895e7 --- /dev/null +++ b/vendor/sha2/CHANGELOG.md @@ -0,0 +1,70 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +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). + +## 0.9.1 (2020-06-24) +### Added +- x86 hardware acceleration of SHA-256 via SHA extension instrinsics. ([#167]) + +[#167]: https://github.com/RustCrypto/hashes/pull/167 + +## 0.9.0 (2020-06-09) +### Changed +- Update to `digest` v0.9 release; MSRV 1.41+ ([#155]) +- Use new `*Dirty` traits from the `digest` crate ([#153]) +- Bump `block-buffer` to v0.8 release ([#151]) +- Rename `*result*` to `finalize` ([#148]) +- Upgrade to Rust 2018 edition ([#133]) + +[#155]: https://github.com/RustCrypto/hashes/pull/155 +[#153]: https://github.com/RustCrypto/hashes/pull/153 +[#151]: https://github.com/RustCrypto/hashes/pull/151 +[#148]: https://github.com/RustCrypto/hashes/pull/148 +[#133]: https://github.com/RustCrypto/hashes/pull/133 + +## 0.8.2 (2020-05-23) +### Added +- Expose compression function under the `compress` feature flag ([#108]) + +### Changed +- Use `libc` crate for `aarch64` consts ([#109]) +- Minor code cleanups ([#94]) + +[#109]: https://github.com/RustCrypto/hashes/pull/109 +[#108]: https://github.com/RustCrypto/hashes/pull/108 +[#94]: https://github.com/RustCrypto/hashes/pull/94 + +## 0.8.1 (2020-01-05) + +## 0.8.0 (2018-10-02) + +## 0.7.1 (2018-04-27) + +## 0.6.0 (2017-06-12) + +## 0.5.3 (2017-06-03) + +## 0.5.2 (2017-05-08) + +## 0.5.1 (2017-05-01) + +## 0.5.0 (2017-04-06) + +## 0.4.2 (2017-01-23) + +## 0.4.1 (2017-01-20) + +## 0.4.0 (2016-12-24) + +## 0.3.0 (2016-11-17) + +## 0.2.0 (2016-10-26) + +## 0.1.2 (2016-05-06) + +## 0.1.1 (2016-05-06) + +## 0.1.0 (2016-05-06) diff --git a/vendor/sha2/Cargo.lock b/vendor/sha2/Cargo.lock new file mode 100644 index 0000000000..30c940334a --- /dev/null +++ b/vendor/sha2/Cargo.lock @@ -0,0 +1,135 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "blobby" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe5f8c2940b65859ece4b3b2ba02d2b12c87cab455fd42dee2556a187bb2cf6" +dependencies = [ + "byteorder", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "cc" +version = "1.0.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cpuid-bool" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d375c433320f6c5057ae04a04376eef4d04ce2801448cf8863a78da99107be4" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "blobby", + "generic-array", +] + +[[package]] +name = "generic-array" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac746a5f3bbfdadd6106868134545e684693d54d9d44f6e9588a7d54af0bf980" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hex-literal" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" +dependencies = [ + "hex-literal-impl", + "proc-macro-hack", +] + +[[package]] +name = "hex-literal-impl" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" +dependencies = [ + "proc-macro-hack", +] + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "proc-macro-hack" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" + +[[package]] +name = "sha2" +version = "0.9.1" +dependencies = [ + "block-buffer", + "cfg-if", + "cpuid-bool", + "digest", + "hex-literal", + "libc", + "opaque-debug", + "sha2-asm", +] + +[[package]] +name = "sha2-asm" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92cfa120723b595090343400d71e4921ba4fbc7d0d48718d72c20b3348469678" +dependencies = [ + "cc", +] + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" diff --git a/vendor/sha2/Cargo.toml b/vendor/sha2/Cargo.toml new file mode 100644 index 0000000000..39fe22351b --- /dev/null +++ b/vendor/sha2/Cargo.toml @@ -0,0 +1,57 @@ +# 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 = "sha2" +version = "0.9.1" +authors = ["RustCrypto Developers"] +description = "Pure Rust implementation of the SHA-2 hash function family\nincluding SHA-224, SHA-256, SHA-384, and SHA-512.\n" +documentation = "https://docs.rs/sha2" +readme = "README.md" +keywords = ["crypto", "sha2", "hash", "digest"] +categories = ["cryptography", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/hashes" +[dependencies.block-buffer] +version = "0.9" + +[dependencies.cfg-if] +version = "0.1" + +[dependencies.digest] +version = "0.9" + +[dependencies.opaque-debug] +version = "0.3" + +[dependencies.sha2-asm] +version = "0.5" +optional = true +[dev-dependencies.digest] +version = "0.9" +features = ["dev"] + +[dev-dependencies.hex-literal] +version = "0.2" + +[features] +asm = ["sha2-asm", "libc"] +asm-aarch64 = ["asm"] +compress = [] +default = ["std"] +std = ["digest/std"] +[target."cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))".dependencies.libc] +version = "0.2.68" +optional = true +[target."cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))".dependencies.cpuid-bool] +version = "0.1" diff --git a/vendor/sha2/LICENSE-APACHE b/vendor/sha2/LICENSE-APACHE new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/sha2/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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/sha2/LICENSE-MIT b/vendor/sha2/LICENSE-MIT new file mode 100644 index 0000000000..66cf75563b --- /dev/null +++ b/vendor/sha2/LICENSE-MIT @@ -0,0 +1,27 @@ +Copyright (c) 2006-2009 Graydon Hoare +Copyright (c) 2009-2013 Mozilla Foundation +Copyright (c) 2016 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/sha2/README.md b/vendor/sha2/README.md new file mode 100644 index 0000000000..cbcde5eaab --- /dev/null +++ b/vendor/sha2/README.md @@ -0,0 +1,56 @@ +# RustCrypto: SHA-2 + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Build Status][build-image]][build-link] + +Pure Rust implementation of the [SHA-2 hash function family][1] +including SHA-224, SHA-256, SHA-384, and SHA-512. + +[Documentation][docs-link] + + + +## Minimum Supported Rust Version + +Rust **1.41** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/sha2.svg +[crate-link]: https://crates.io/crates/sha2 +[docs-image]: https://docs.rs/sha2/badge.svg +[docs-link]: https://docs.rs/sha2/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[build-image]: https://github.com/RustCrypto/hashes/workflows/sha2/badge.svg?branch=master +[build-link]: https://github.com/RustCrypto/hashes/actions?query=workflow%3Asha2 + +[//]: # (general links) + +[1]: https://en.wikipedia.org/wiki/SHA-2 diff --git a/vendor/sha2/benches/sha256.rs b/vendor/sha2/benches/sha256.rs new file mode 100644 index 0000000000..181a68c406 --- /dev/null +++ b/vendor/sha2/benches/sha256.rs @@ -0,0 +1,4 @@ +#![no_std] +#![feature(test)] + +digest::bench!(sha2::Sha256); diff --git a/vendor/sha2/benches/sha512.rs b/vendor/sha2/benches/sha512.rs new file mode 100644 index 0000000000..88708b383d --- /dev/null +++ b/vendor/sha2/benches/sha512.rs @@ -0,0 +1,4 @@ +#![no_std] +#![feature(test)] + +digest::bench!(sha2::Sha512); diff --git a/vendor/sha2/examples/sha256sum.rs b/vendor/sha2/examples/sha256sum.rs new file mode 100644 index 0000000000..31ee979290 --- /dev/null +++ b/vendor/sha2/examples/sha256sum.rs @@ -0,0 +1,47 @@ +use sha2::{Digest, Sha256}; +use std::env; +use std::fs; +use std::io::{self, Read}; + +const BUFFER_SIZE: usize = 1024; + +/// Print digest result as hex string and name pair +fn print_result(sum: &[u8], name: &str) { + for byte in sum { + print!("{:02x}", byte); + } + println!("\t{}", name); +} + +/// Compute digest value for given `Reader` and print it +/// On any error simply return without doing anything +fn process(reader: &mut R, name: &str) { + let mut sh = D::default(); + let mut buffer = [0u8; BUFFER_SIZE]; + loop { + let n = match reader.read(&mut buffer) { + Ok(n) => n, + Err(_) => return, + }; + sh.update(&buffer[..n]); + if n == 0 || n < BUFFER_SIZE { + break; + } + } + print_result(&sh.finalize(), name); +} + +fn main() { + let args = env::args(); + // Process files listed in command line arguments one by one + // If no files provided process input from stdin + if args.len() > 1 { + for path in args.skip(1) { + if let Ok(mut file) = fs::File::open(&path) { + process::(&mut file, &path); + } + } + } else { + process::(&mut io::stdin(), "-"); + } +} diff --git a/vendor/sha2/examples/sha512sum.rs b/vendor/sha2/examples/sha512sum.rs new file mode 100644 index 0000000000..9d4785acdb --- /dev/null +++ b/vendor/sha2/examples/sha512sum.rs @@ -0,0 +1,47 @@ +use sha2::{Digest, Sha512}; +use std::env; +use std::fs; +use std::io::{self, Read}; + +const BUFFER_SIZE: usize = 1024; + +/// Print digest result as hex string and name pair +fn print_result(sum: &[u8], name: &str) { + for byte in sum { + print!("{:02x}", byte); + } + println!("\t{}", name); +} + +/// Compute digest value for given `Reader` and print it +/// On any error simply return without doing anything +fn process(reader: &mut R, name: &str) { + let mut sh = D::default(); + let mut buffer = [0u8; BUFFER_SIZE]; + loop { + let n = match reader.read(&mut buffer) { + Ok(n) => n, + Err(_) => return, + }; + sh.update(&buffer[..n]); + if n == 0 || n < BUFFER_SIZE { + break; + } + } + print_result(&sh.finalize(), name); +} + +fn main() { + let args = env::args(); + // Process files listed in command line arguments one by one + // If no files provided process input from stdin + if args.len() > 1 { + for path in args.skip(1) { + if let Ok(mut file) = fs::File::open(&path) { + process::(&mut file, &path); + } + } + } else { + process::(&mut io::stdin(), "-"); + } +} diff --git a/vendor/sha2/src/consts.rs b/vendor/sha2/src/consts.rs new file mode 100644 index 0000000000..f126dc616c --- /dev/null +++ b/vendor/sha2/src/consts.rs @@ -0,0 +1,216 @@ +#![allow(dead_code, clippy::unreadable_literal)] + +pub const STATE_LEN: usize = 8; +pub const BLOCK_LEN: usize = 16; + +/// Constants necessary for SHA-256 family of digests. +pub const K32: [u32; 64] = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +]; + +/// Constants necessary for SHA-256 family of digests. +pub const K32X4: [[u32; 4]; 16] = [ + [K32[3], K32[2], K32[1], K32[0]], + [K32[7], K32[6], K32[5], K32[4]], + [K32[11], K32[10], K32[9], K32[8]], + [K32[15], K32[14], K32[13], K32[12]], + [K32[19], K32[18], K32[17], K32[16]], + [K32[23], K32[22], K32[21], K32[20]], + [K32[27], K32[26], K32[25], K32[24]], + [K32[31], K32[30], K32[29], K32[28]], + [K32[35], K32[34], K32[33], K32[32]], + [K32[39], K32[38], K32[37], K32[36]], + [K32[43], K32[42], K32[41], K32[40]], + [K32[47], K32[46], K32[45], K32[44]], + [K32[51], K32[50], K32[49], K32[48]], + [K32[55], K32[54], K32[53], K32[52]], + [K32[59], K32[58], K32[57], K32[56]], + [K32[63], K32[62], K32[61], K32[60]], +]; + +/// Constants necessary for SHA-512 family of digests. +pub const K64: [u64; 80] = [ + 0x428a2f98d728ae22, + 0x7137449123ef65cd, + 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, + 0x59f111f1b605d019, + 0x923f82a4af194f9b, + 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, + 0x12835b0145706fbe, + 0x243185be4ee4b28c, + 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, + 0x80deb1fe3b1696b1, + 0x9bdc06a725c71235, + 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, + 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, + 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, + 0x5cb0a9dcbd41fbd4, + 0x76f988da831153b5, + 0x983e5152ee66dfab, + 0xa831c66d2db43210, + 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, + 0xd5a79147930aa725, + 0x06ca6351e003826f, + 0x142929670a0e6e70, + 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, + 0x4d2c6dfc5ac42aed, + 0x53380d139d95b3df, + 0x650a73548baf63de, + 0x766a0abb3c77b2a8, + 0x81c2c92e47edaee6, + 0x92722c851482353b, + 0xa2bfe8a14cf10364, + 0xa81a664bbc423001, + 0xc24b8b70d0f89791, + 0xc76c51a30654be30, + 0xd192e819d6ef5218, + 0xd69906245565a910, + 0xf40e35855771202a, + 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, + 0x1e376c085141ab53, + 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, + 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, + 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, + 0x78a5636f43172f60, + 0x84c87814a1f0ab72, + 0x8cc702081a6439ec, + 0x90befffa23631e28, + 0xa4506cebde82bde9, + 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, + 0xca273eceea26619c, + 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, + 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, + 0x1b710b35131c471b, + 0x28db77f523047d84, + 0x32caab7b40c72493, + 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, + 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, + 0x6c44198c4a475817, +]; + +/// Constants necessary for SHA-512 family of digests. +pub const K64X2: [[u64; 2]; 40] = [ + [K64[1], K64[0]], + [K64[3], K64[2]], + [K64[5], K64[4]], + [K64[7], K64[6]], + [K64[9], K64[8]], + [K64[11], K64[10]], + [K64[13], K64[12]], + [K64[15], K64[14]], + [K64[17], K64[16]], + [K64[19], K64[18]], + [K64[21], K64[20]], + [K64[23], K64[22]], + [K64[25], K64[24]], + [K64[27], K64[26]], + [K64[29], K64[28]], + [K64[31], K64[30]], + [K64[33], K64[32]], + [K64[35], K64[34]], + [K64[37], K64[36]], + [K64[39], K64[38]], + [K64[41], K64[40]], + [K64[43], K64[42]], + [K64[45], K64[44]], + [K64[47], K64[46]], + [K64[49], K64[48]], + [K64[51], K64[50]], + [K64[53], K64[52]], + [K64[55], K64[54]], + [K64[57], K64[56]], + [K64[59], K64[58]], + [K64[61], K64[60]], + [K64[63], K64[62]], + [K64[65], K64[64]], + [K64[67], K64[66]], + [K64[69], K64[68]], + [K64[71], K64[70]], + [K64[73], K64[72]], + [K64[75], K64[74]], + [K64[77], K64[76]], + [K64[79], K64[78]], +]; + +pub static H224: [u32; STATE_LEN] = [ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4, +]; + +pub static H256: [u32; STATE_LEN] = [ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, +]; + +pub static H384: [u64; STATE_LEN] = [ + 0xcbbb9d5dc1059ed8, + 0x629a292a367cd507, + 0x9159015a3070dd17, + 0x152fecd8f70e5939, + 0x67332667ffc00b31, + 0x8eb44a8768581511, + 0xdb0c2e0d64f98fa7, + 0x47b5481dbefa4fa4, +]; + +pub static H512: [u64; STATE_LEN] = [ + 0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179, +]; + +pub static H512_TRUNC_224: [u64; STATE_LEN] = [ + 0x8c3d37c819544da2, + 0x73e1996689dcd4d6, + 0x1dfab7ae32ff9c82, + 0x679dd514582f9fcf, + 0x0f6d2b697bd44da8, + 0x77e36f7304c48942, + 0x3f9d85a86a1d36c8, + 0x1112e6ad91d692a1, +]; + +pub static H512_TRUNC_256: [u64; STATE_LEN] = [ + 0x22312194fc2bf72c, + 0x9f555fa3c84c64c2, + 0x2393b86b6f53b151, + 0x963877195940eabd, + 0x96283ee2a88effe3, + 0xbe5e1e2553863992, + 0x2b0199fc2c85b8aa, + 0x0eb72ddc81c52ca2, +]; diff --git a/vendor/sha2/src/lib.rs b/vendor/sha2/src/lib.rs new file mode 100644 index 0000000000..08829eab2a --- /dev/null +++ b/vendor/sha2/src/lib.rs @@ -0,0 +1,72 @@ +//! An implementation of the [SHA-2][1] cryptographic hash algorithms. +//! +//! There are 6 standard algorithms specified in the SHA-2 standard: +//! +//! * `Sha224`, which is the 32-bit `Sha256` algorithm with the result truncated +//! to 224 bits. +//! * `Sha256`, which is the 32-bit `Sha256` algorithm. +//! * `Sha384`, which is the 64-bit `Sha512` algorithm with the result truncated +//! to 384 bits. +//! * `Sha512`, which is the 64-bit `Sha512` algorithm. +//! * `Sha512Trunc224`, which is the 64-bit `Sha512` algorithm with the result +//! truncated to 224 bits. +//! * `Sha512Trunc256`, which is the 64-bit `Sha512` algorithm with the result +//! truncated to 256 bits. +//! +//! Algorithmically, there are only 2 core algorithms: `Sha256` and `Sha512`. +//! All other algorithms are just applications of these with different initial +//! hash values, and truncated to different digest bit lengths. +//! +//! # Usage +//! +//! ```rust +//! use hex_literal::hex; +//! use sha2::{Sha256, Sha512, Digest}; +//! +//! // create a Sha256 object +//! let mut hasher = Sha256::new(); +//! +//! // write input message +//! hasher.update(b"hello world"); +//! +//! // read hash digest and consume hasher +//! let result = hasher.finalize(); +//! +//! assert_eq!(result[..], hex!(" +//! b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 +//! ")[..]); +//! +//! // same for Sha512 +//! let mut hasher = Sha512::new(); +//! hasher.update(b"hello world"); +//! let result = hasher.finalize(); +//! +//! assert_eq!(result[..], hex!(" +//! 309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f +//! 989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f +//! ")[..]); +//! ``` +//! +//! Also see [RustCrypto/hashes][2] readme. +//! +//! [1]: https://en.wikipedia.org/wiki/SHA-2 +//! [2]: https://github.com/RustCrypto/hashes + +#![no_std] +#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] +#![warn(missing_docs, rust_2018_idioms)] + +#[cfg(feature = "std")] +extern crate std; + +mod consts; +mod sha256; +mod sha512; + +pub use digest::{self, Digest}; +#[cfg(feature = "compress")] +pub use sha256::compress256; +pub use sha256::{Sha224, Sha256}; +#[cfg(feature = "compress")] +pub use sha512::compress512; +pub use sha512::{Sha384, Sha512, Sha512Trunc224, Sha512Trunc256}; diff --git a/vendor/sha2/src/sha256.rs b/vendor/sha2/src/sha256.rs new file mode 100644 index 0000000000..8ee97beddd --- /dev/null +++ b/vendor/sha2/src/sha256.rs @@ -0,0 +1,169 @@ +//! SHA-256 +use crate::consts::{H224, H256, STATE_LEN}; +use block_buffer::BlockBuffer; +use core::slice::from_ref; +use digest::consts::{U28, U32, U64}; +use digest::generic_array::GenericArray; +use digest::{BlockInput, FixedOutputDirty, Reset, Update}; + +type BlockSize = U64; + +/// Structure that keeps state of the Sha-256 operation and +/// contains the logic necessary to perform the final calculations. +#[derive(Clone)] +struct Engine256 { + len: u64, + buffer: BlockBuffer, + state: [u32; 8], +} + +impl Engine256 { + fn new(h: &[u32; STATE_LEN]) -> Engine256 { + Engine256 { + len: 0, + buffer: Default::default(), + state: *h, + } + } + + fn update(&mut self, input: &[u8]) { + // Assumes that input.len() can be converted to u64 without overflow + self.len += (input.len() as u64) << 3; + let s = &mut self.state; + self.buffer.input_blocks(input, |b| compress256(s, b)); + } + + fn finish(&mut self) { + let s = &mut self.state; + let l = self.len; + self.buffer + .len64_padding_be(l, |b| compress256(s, from_ref(b))); + } + + fn reset(&mut self, h: &[u32; STATE_LEN]) { + self.len = 0; + self.buffer.reset(); + self.state = *h; + } +} + +/// The SHA-256 hash algorithm with the SHA-256 initial hash value. +#[derive(Clone)] +pub struct Sha256 { + engine: Engine256, +} + +impl Default for Sha256 { + fn default() -> Self { + Sha256 { + engine: Engine256::new(&H256), + } + } +} + +impl BlockInput for Sha256 { + type BlockSize = BlockSize; +} + +impl Update for Sha256 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha256 { + type OutputSize = U32; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = self.engine.state; + for (chunk, v) in out.chunks_exact_mut(4).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha256 { + fn reset(&mut self) { + self.engine.reset(&H256); + } +} + +/// The SHA-256 hash algorithm with the SHA-224 initial hash value. The result +/// is truncated to 224 bits. +#[derive(Clone)] +pub struct Sha224 { + engine: Engine256, +} + +impl Default for Sha224 { + fn default() -> Self { + Sha224 { + engine: Engine256::new(&H224), + } + } +} + +impl BlockInput for Sha224 { + type BlockSize = BlockSize; +} + +impl Update for Sha224 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha224 { + type OutputSize = U28; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = &self.engine.state[..7]; + for (chunk, v) in out.chunks_exact_mut(4).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha224 { + fn reset(&mut self) { + self.engine.reset(&H224); + } +} + +opaque_debug::implement!(Sha224); +opaque_debug::implement!(Sha256); + +digest::impl_write!(Sha224); +digest::impl_write!(Sha256); + +cfg_if::cfg_if! { + if #[cfg(all(feature = "asm", target_arch = "aarch64", target_os = "linux"))] { + mod soft; + mod aarch64; + use aarch64::compress; + } else if #[cfg(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64")))] { + // TODO: replace after sha2-asm rework + fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + for block in blocks { + sha2_asm::compress256(state, block); + } + } + } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + mod soft; + mod x86; + use x86::compress; + } else { + mod soft; + use soft::compress; + } +} + +pub fn compress256(state: &mut [u32; 8], blocks: &[GenericArray]) { + // SAFETY: GenericArray and [u8; 64] have + // exactly the same memory layout + #[allow(unsafe_code)] + let blocks: &[[u8; 64]] = unsafe { &*(blocks as *const _ as *const [[u8; 64]]) }; + compress(state, blocks) +} diff --git a/vendor/sha2/src/sha256/aarch64.rs b/vendor/sha2/src/sha256/aarch64.rs new file mode 100644 index 0000000000..a5967ca0c4 --- /dev/null +++ b/vendor/sha2/src/sha256/aarch64.rs @@ -0,0 +1,20 @@ +use libc::{getauxval, AT_HWCAP, HWCAP_SHA2}; + +#[inline(always)] +pub fn sha2_supported() -> bool { + let hwcaps: u64 = unsafe { getauxval(AT_HWCAP) }; + (hwcaps & HWCAP_SHA2) != 0 +} + +pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + // TODO: Replace with https://github.com/rust-lang/rfcs/pull/2725 + // after stabilization + if sha2_supported() { + // TODO: replace after sha2-asm rework + for block in blocks { + sha2_asm::compress256(&mut self.h, block); + } + } else { + super::soft::compress(&mut self.h, block); + } +} diff --git a/vendor/sha2/src/sha256/soft.rs b/vendor/sha2/src/sha256/soft.rs new file mode 100644 index 0000000000..d7be01dc62 --- /dev/null +++ b/vendor/sha2/src/sha256/soft.rs @@ -0,0 +1,219 @@ +#![allow(clippy::many_single_char_names)] +use crate::consts::BLOCK_LEN; +use core::convert::TryInto; + +#[inline(always)] +fn shl(v: [u32; 4], o: u32) -> [u32; 4] { + [v[0] >> o, v[1] >> o, v[2] >> o, v[3] >> o] +} + +#[inline(always)] +fn shr(v: [u32; 4], o: u32) -> [u32; 4] { + [v[0] << o, v[1] << o, v[2] << o, v[3] << o] +} + +#[inline(always)] +fn or(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { + [a[0] | b[0], a[1] | b[1], a[2] | b[2], a[3] | b[3]] +} + +#[inline(always)] +fn xor(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { + [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]] +} + +#[inline(always)] +fn add(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { + [ + a[0].wrapping_add(b[0]), + a[1].wrapping_add(b[1]), + a[2].wrapping_add(b[2]), + a[3].wrapping_add(b[3]), + ] +} + +fn sha256load(v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] { + [v3[3], v2[0], v2[1], v2[2]] +} + +fn sha256swap(v0: [u32; 4]) -> [u32; 4] { + [v0[2], v0[3], v0[0], v0[1]] +} + +fn sha256msg1(v0: [u32; 4], v1: [u32; 4]) -> [u32; 4] { + // sigma 0 on vectors + #[inline] + fn sigma0x4(x: [u32; 4]) -> [u32; 4] { + let t1 = or(shl(x, 7), shr(x, 25)); + let t2 = or(shl(x, 18), shr(x, 14)); + let t3 = shl(x, 3); + xor(xor(t1, t2), t3) + } + + add(v0, sigma0x4(sha256load(v0, v1))) +} + +fn sha256msg2(v4: [u32; 4], v3: [u32; 4]) -> [u32; 4] { + macro_rules! sigma1 { + ($a:expr) => { + $a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10) + }; + } + + let [x3, x2, x1, x0] = v4; + let [w15, w14, _, _] = v3; + + let w16 = x0.wrapping_add(sigma1!(w14)); + let w17 = x1.wrapping_add(sigma1!(w15)); + let w18 = x2.wrapping_add(sigma1!(w16)); + let w19 = x3.wrapping_add(sigma1!(w17)); + + [w19, w18, w17, w16] +} + +fn sha256_digest_round_x2(cdgh: [u32; 4], abef: [u32; 4], wk: [u32; 4]) -> [u32; 4] { + macro_rules! big_sigma0 { + ($a:expr) => { + ($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22)) + }; + } + macro_rules! big_sigma1 { + ($a:expr) => { + ($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25)) + }; + } + macro_rules! bool3ary_202 { + ($a:expr, $b:expr, $c:expr) => { + $c ^ ($a & ($b ^ $c)) + }; + } // Choose, MD5F, SHA1C + macro_rules! bool3ary_232 { + ($a:expr, $b:expr, $c:expr) => { + ($a & $b) ^ ($a & $c) ^ ($b & $c) + }; + } // Majority, SHA1M + + let [_, _, wk1, wk0] = wk; + let [a0, b0, e0, f0] = abef; + let [c0, d0, g0, h0] = cdgh; + + // a round + let x0 = big_sigma1!(e0) + .wrapping_add(bool3ary_202!(e0, f0, g0)) + .wrapping_add(wk0) + .wrapping_add(h0); + let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0)); + let (a1, b1, c1, d1, e1, f1, g1, h1) = ( + x0.wrapping_add(y0), + a0, + b0, + c0, + x0.wrapping_add(d0), + e0, + f0, + g0, + ); + + // a round + let x1 = big_sigma1!(e1) + .wrapping_add(bool3ary_202!(e1, f1, g1)) + .wrapping_add(wk1) + .wrapping_add(h1); + let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1)); + let (a2, b2, _, _, e2, f2, _, _) = ( + x1.wrapping_add(y1), + a1, + b1, + c1, + x1.wrapping_add(d1), + e1, + f1, + g1, + ); + + [a2, b2, e2, f2] +} + +fn schedule(v0: [u32; 4], v1: [u32; 4], v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] { + let t1 = sha256msg1(v0, v1); + let t2 = sha256load(v2, v3); + let t3 = add(t1, t2); + sha256msg2(t3, v3) +} + +macro_rules! rounds4 { + ($abef:ident, $cdgh:ident, $rest:expr, $i:expr) => {{ + let t1 = add($rest, crate::consts::K32X4[$i]); + $cdgh = sha256_digest_round_x2($cdgh, $abef, t1); + let t2 = sha256swap(t1); + $abef = sha256_digest_round_x2($abef, $cdgh, t2); + }}; +} + +macro_rules! schedule_rounds4 { + ( + $abef:ident, $cdgh:ident, + $w0:expr, $w1:expr, $w2:expr, $w3:expr, $w4:expr, + $i: expr + ) => {{ + $w4 = schedule($w0, $w1, $w2, $w3); + rounds4!($abef, $cdgh, $w4, $i); + }}; +} + +/// Process a block with the SHA-256 algorithm. +fn sha256_digest_block_u32(state: &mut [u32; 8], block: &[u32; 16]) { + let mut abef = [state[0], state[1], state[4], state[5]]; + let mut cdgh = [state[2], state[3], state[6], state[7]]; + + + // Rounds 0..64 + let mut w0 = [block[3], block[2], block[1], block[0]]; + let mut w1 = [block[7], block[6], block[5], block[4]]; + let mut w2 = [block[11], block[10], block[9], block[8]]; + let mut w3 = [block[15], block[14], block[13], block[12]]; + let mut w4; + + rounds4!(abef, cdgh, w0, 0); + rounds4!(abef, cdgh, w1, 1); + rounds4!(abef, cdgh, w2, 2); + rounds4!(abef, cdgh, w3, 3); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 4); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 5); + schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 6); + schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 7); + schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 8); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 9); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 10); + schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 11); + schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 12); + schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 13); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 14); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 15); + + let [a, b, e, f] = abef; + let [c, d, g, h] = cdgh; + + state[0] = state[0].wrapping_add(a); + state[1] = state[1].wrapping_add(b); + state[2] = state[2].wrapping_add(c); + state[3] = state[3].wrapping_add(d); + state[4] = state[4].wrapping_add(e); + state[5] = state[5].wrapping_add(f); + state[6] = state[6].wrapping_add(g); + state[7] = state[7].wrapping_add(h); +} + +pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + let mut block_u32 = [0u32; BLOCK_LEN]; + // since LLVM can't properly use aliasing yet it will make + // unnecessary state stores without this copy + let mut state_cpy = *state; + for block in blocks { + for (o, chunk) in block_u32.iter_mut().zip(block.chunks_exact(4)) { + *o = u32::from_be_bytes(chunk.try_into().unwrap()); + } + sha256_digest_block_u32(&mut state_cpy, &block_u32); + } + *state = state_cpy; +} diff --git a/vendor/sha2/src/sha256/x86.rs b/vendor/sha2/src/sha256/x86.rs new file mode 100644 index 0000000000..04a7d26d07 --- /dev/null +++ b/vendor/sha2/src/sha256/x86.rs @@ -0,0 +1,108 @@ +#![allow(clippy::many_single_char_names)] + +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; +#[cfg(target_arch = "x86")] +use core::arch::x86::*; + +unsafe fn schedule(v0: __m128i, v1: __m128i, v2: __m128i, v3: __m128i) -> __m128i { + let t1 = _mm_sha256msg1_epu32(v0, v1); + let t2 = _mm_alignr_epi8(v3, v2, 4); + let t3 = _mm_add_epi32(t1, t2); + _mm_sha256msg2_epu32(t3, v3) +} + +macro_rules! rounds4 { + ($abef:ident, $cdgh:ident, $rest:expr, $i:expr) => {{ + let k = crate::consts::K32X4[$i]; + let kv = _mm_set_epi32(k[0] as i32, k[1] as i32, k[2] as i32, k[3] as i32); + let t1 = _mm_add_epi32($rest, kv); + $cdgh = _mm_sha256rnds2_epu32($cdgh, $abef, t1); + let t2 = _mm_shuffle_epi32(t1, 0x0E); + $abef = _mm_sha256rnds2_epu32($abef, $cdgh, t2); + }}; +} + +macro_rules! schedule_rounds4 { + ( + $abef:ident, $cdgh:ident, + $w0:expr, $w1:expr, $w2:expr, $w3:expr, $w4:expr, + $i: expr + ) => {{ + $w4 = schedule($w0, $w1, $w2, $w3); + rounds4!($abef, $cdgh, $w4, $i); + }}; +} + +// we use unaligned loads with `__m128i` pointers +#[allow(clippy::cast_ptr_alignment)] +#[target_feature(enable = "sha,sse2,ssse3,sse4.1")] +unsafe fn digest_blocks(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + #[allow(non_snake_case)] + let MASK: __m128i = _mm_set_epi64x( + 0x0C0D_0E0F_0809_0A0Bu64 as i64, + 0x0405_0607_0001_0203u64 as i64, + ); + + let state_ptr = state.as_ptr() as *const __m128i; + let dcba = _mm_loadu_si128(state_ptr.add(0)); + let efgh = _mm_loadu_si128(state_ptr.add(1)); + + let cdab = _mm_shuffle_epi32(dcba, 0xB1); + let efgh = _mm_shuffle_epi32(efgh, 0x1B); + let mut abef = _mm_alignr_epi8(cdab, efgh, 8); + let mut cdgh = _mm_blend_epi16(efgh, cdab, 0xF0); + + for block in blocks { + let abef_save = abef; + let cdgh_save = cdgh; + + let data_ptr = block.as_ptr() as *const __m128i; + let mut w0 = _mm_shuffle_epi8(_mm_loadu_si128(data_ptr.add(0)), MASK); + let mut w1 = _mm_shuffle_epi8(_mm_loadu_si128(data_ptr.add(1)), MASK); + let mut w2 = _mm_shuffle_epi8(_mm_loadu_si128(data_ptr.add(2)), MASK); + let mut w3 = _mm_shuffle_epi8( _mm_loadu_si128(data_ptr.add(3)), MASK); + let mut w4; + + rounds4!(abef, cdgh, w0, 0); + rounds4!(abef, cdgh, w1, 1); + rounds4!(abef, cdgh, w2, 2); + rounds4!(abef, cdgh, w3, 3); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 4); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 5); + schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 6); + schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 7); + schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 8); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 9); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 10); + schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 11); + schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 12); + schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 13); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 14); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 15); + + abef = _mm_add_epi32(abef, abef_save); + cdgh = _mm_add_epi32(cdgh, cdgh_save); + } + + let feba = _mm_shuffle_epi32(abef, 0x1B); + let dchg = _mm_shuffle_epi32(cdgh, 0xB1); + let dcba = _mm_blend_epi16(feba, dchg, 0xF0); + let hgef = _mm_alignr_epi8(dchg, feba, 8); + + let state_ptr_mut = state.as_mut_ptr() as *mut __m128i; + _mm_storeu_si128(state_ptr_mut.add(0), dcba); + _mm_storeu_si128(state_ptr_mut.add(1), hgef); +} + +pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + // TODO: Replace with https://github.com/rust-lang/rfcs/pull/2725 + // after stabilization + if cpuid_bool::cpuid_bool!("sha", "sse2", "ssse3", "sse4.1") { + unsafe { + digest_blocks(state, blocks); + } + } else { + super::soft::compress(state, blocks); + } +} diff --git a/vendor/sha2/src/sha512.rs b/vendor/sha2/src/sha512.rs new file mode 100644 index 0000000000..de115d4426 --- /dev/null +++ b/vendor/sha2/src/sha512.rs @@ -0,0 +1,250 @@ +//! SHA-512 +use crate::consts::{H384, H512, H512_TRUNC_224, H512_TRUNC_256, STATE_LEN}; +use block_buffer::BlockBuffer; +use core::slice::from_ref; +use digest::consts::{U128, U28, U32, U48, U64}; +use digest::generic_array::GenericArray; +use digest::{BlockInput, FixedOutputDirty, Reset, Update}; + +type BlockSize = U128; + +/// Structure that keeps state of the Sha-512 operation and +/// contains the logic necessary to perform the final calculations. +#[derive(Clone)] +struct Engine512 { + len: u128, + buffer: BlockBuffer, + state: [u64; 8], +} + +impl Engine512 { + fn new(h: &[u64; STATE_LEN]) -> Engine512 { + Engine512 { + len: 0, + buffer: Default::default(), + state: *h, + } + } + + fn update(&mut self, input: &[u8]) { + self.len += (input.len() as u128) << 3; + let s = &mut self.state; + self.buffer.input_blocks(input, |b| compress512(s, b)); + } + + fn finish(&mut self) { + let s = &mut self.state; + self.buffer + .len128_padding_be(self.len, |d| compress512(s, from_ref(d))); + } + + fn reset(&mut self, h: &[u64; STATE_LEN]) { + self.len = 0; + self.buffer.reset(); + self.state = *h; + } +} + +/// The SHA-512 hash algorithm with the SHA-512 initial hash value. +#[derive(Clone)] +pub struct Sha512 { + engine: Engine512, +} + +impl Default for Sha512 { + fn default() -> Self { + Sha512 { + engine: Engine512::new(&H512), + } + } +} + +impl BlockInput for Sha512 { + type BlockSize = BlockSize; +} + +impl Update for Sha512 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha512 { + type OutputSize = U64; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = self.engine.state; + for (chunk, v) in out.chunks_exact_mut(8).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha512 { + fn reset(&mut self) { + self.engine.reset(&H512); + } +} + +/// The SHA-512 hash algorithm with the SHA-384 initial hash value. The result +/// is truncated to 384 bits. +#[derive(Clone)] +pub struct Sha384 { + engine: Engine512, +} + +impl Default for Sha384 { + fn default() -> Self { + Sha384 { + engine: Engine512::new(&H384), + } + } +} + +impl BlockInput for Sha384 { + type BlockSize = BlockSize; +} + +impl Update for Sha384 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha384 { + type OutputSize = U48; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = &self.engine.state[..6]; + for (chunk, v) in out.chunks_exact_mut(8).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha384 { + fn reset(&mut self) { + self.engine.reset(&H384); + } +} + +/// The SHA-512 hash algorithm with the SHA-512/256 initial hash value. The +/// result is truncated to 256 bits. +#[derive(Clone)] +pub struct Sha512Trunc256 { + engine: Engine512, +} + +impl Default for Sha512Trunc256 { + fn default() -> Self { + Sha512Trunc256 { + engine: Engine512::new(&H512_TRUNC_256), + } + } +} + +impl BlockInput for Sha512Trunc256 { + type BlockSize = BlockSize; +} + +impl Update for Sha512Trunc256 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha512Trunc256 { + type OutputSize = U32; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = &self.engine.state[..4]; + for (chunk, v) in out.chunks_exact_mut(8).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha512Trunc256 { + fn reset(&mut self) { + self.engine.reset(&H512_TRUNC_256); + } +} + +/// The SHA-512 hash algorithm with the SHA-512/224 initial hash value. +/// The result is truncated to 224 bits. +#[derive(Clone)] +pub struct Sha512Trunc224 { + engine: Engine512, +} + +impl Default for Sha512Trunc224 { + fn default() -> Self { + Sha512Trunc224 { + engine: Engine512::new(&H512_TRUNC_224), + } + } +} + +impl BlockInput for Sha512Trunc224 { + type BlockSize = BlockSize; +} + +impl Update for Sha512Trunc224 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha512Trunc224 { + type OutputSize = U28; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = &self.engine.state; + for (chunk, v) in out.chunks_exact_mut(8).zip(s[..3].iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + out[24..28].copy_from_slice(&s[3].to_be_bytes()[..4]); + } +} + +impl Reset for Sha512Trunc224 { + fn reset(&mut self) { + self.engine.reset(&H512_TRUNC_224); + } +} + +opaque_debug::implement!(Sha384); +opaque_debug::implement!(Sha512); +opaque_debug::implement!(Sha512Trunc224); +opaque_debug::implement!(Sha512Trunc256); + +digest::impl_write!(Sha384); +digest::impl_write!(Sha512); +digest::impl_write!(Sha512Trunc224); +digest::impl_write!(Sha512Trunc256); + +cfg_if::cfg_if! { + if #[cfg(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64")))] { + // TODO: replace after sha2-asm rework + fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { + for block in blocks { + sha2_asm::compress512(state, block); + } + } + } else { + mod soft; + use soft::compress; + } +} + +pub fn compress512(state: &mut [u64; 8], blocks: &[GenericArray]) { + // SAFETY: GenericArray and [u8; 128] have + // exactly the same memory layout + #[allow(unsafe_code)] + let blocks: &[[u8; 128]] = unsafe { &*(blocks as *const _ as *const [[u8; 128]]) }; + compress(state, blocks) +} diff --git a/vendor/sha2/src/sha512/soft.rs b/vendor/sha2/src/sha512/soft.rs new file mode 100644 index 0000000000..f307f0e548 --- /dev/null +++ b/vendor/sha2/src/sha512/soft.rs @@ -0,0 +1,216 @@ +#![allow(clippy::many_single_char_names)] +use crate::consts::{BLOCK_LEN, K64X2}; +use core::convert::TryInto; + +fn add(a: [u64; 2], b: [u64; 2]) -> [u64; 2] { + [a[0].wrapping_add(b[0]), a[1].wrapping_add(b[1])] +} + +/// Not an intrinsic, but works like an unaligned load. +fn sha512load(v0: [u64; 2], v1: [u64; 2]) -> [u64; 2] { + [v1[1], v0[0]] +} + +/// Performs 2 rounds of the SHA-512 message schedule update. +pub fn sha512_schedule_x2(v0: [u64; 2], v1: [u64; 2], v4to5: [u64; 2], v7: [u64; 2]) -> [u64; 2] { + // sigma 0 + fn sigma0(x: u64) -> u64 { + ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7) + } + + // sigma 1 + fn sigma1(x: u64) -> u64 { + ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6) + } + + let [w1, w0] = v0; + let [_, w2] = v1; + let [w10, w9] = v4to5; + let [w15, w14] = v7; + + let w16 = sigma1(w14) + .wrapping_add(w9) + .wrapping_add(sigma0(w1)) + .wrapping_add(w0); + let w17 = sigma1(w15) + .wrapping_add(w10) + .wrapping_add(sigma0(w2)) + .wrapping_add(w1); + + [w17, w16] +} + +/// Performs one round of the SHA-512 message block digest. +pub fn sha512_digest_round( + ae: [u64; 2], + bf: [u64; 2], + cg: [u64; 2], + dh: [u64; 2], + wk0: u64, +) -> [u64; 2] { + macro_rules! big_sigma0 { + ($a:expr) => { + ($a.rotate_right(28) ^ $a.rotate_right(34) ^ $a.rotate_right(39)) + }; + } + macro_rules! big_sigma1 { + ($a:expr) => { + ($a.rotate_right(14) ^ $a.rotate_right(18) ^ $a.rotate_right(41)) + }; + } + macro_rules! bool3ary_202 { + ($a:expr, $b:expr, $c:expr) => { + $c ^ ($a & ($b ^ $c)) + }; + } // Choose, MD5F, SHA1C + macro_rules! bool3ary_232 { + ($a:expr, $b:expr, $c:expr) => { + ($a & $b) ^ ($a & $c) ^ ($b & $c) + }; + } // Majority, SHA1M + + let [a0, e0] = ae; + let [b0, f0] = bf; + let [c0, g0] = cg; + let [d0, h0] = dh; + + // a round + let x0 = big_sigma1!(e0) + .wrapping_add(bool3ary_202!(e0, f0, g0)) + .wrapping_add(wk0) + .wrapping_add(h0); + let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0)); + let (a1, _, _, _, e1, _, _, _) = ( + x0.wrapping_add(y0), + a0, + b0, + c0, + x0.wrapping_add(d0), + e0, + f0, + g0, + ); + + [a1, e1] +} + +/// Process a block with the SHA-512 algorithm. +pub fn sha512_digest_block_u64(state: &mut [u64; 8], block: &[u64; 16]) { + let k = &K64X2; + + macro_rules! schedule { + ($v0:expr, $v1:expr, $v4:expr, $v5:expr, $v7:expr) => { + sha512_schedule_x2($v0, $v1, sha512load($v4, $v5), $v7) + }; + } + + macro_rules! rounds4 { + ($ae:ident, $bf:ident, $cg:ident, $dh:ident, $wk0:expr, $wk1:expr) => {{ + let [u, t] = $wk0; + let [w, v] = $wk1; + + $dh = sha512_digest_round($ae, $bf, $cg, $dh, t); + $cg = sha512_digest_round($dh, $ae, $bf, $cg, u); + $bf = sha512_digest_round($cg, $dh, $ae, $bf, v); + $ae = sha512_digest_round($bf, $cg, $dh, $ae, w); + }}; + } + + let mut ae = [state[0], state[4]]; + let mut bf = [state[1], state[5]]; + let mut cg = [state[2], state[6]]; + let mut dh = [state[3], state[7]]; + + // Rounds 0..20 + let (mut w1, mut w0) = ([block[3], block[2]], [block[1], block[0]]); + rounds4!(ae, bf, cg, dh, add(k[0], w0), add(k[1], w1)); + let (mut w3, mut w2) = ([block[7], block[6]], [block[5], block[4]]); + rounds4!(ae, bf, cg, dh, add(k[2], w2), add(k[3], w3)); + let (mut w5, mut w4) = ([block[11], block[10]], [block[9], block[8]]); + rounds4!(ae, bf, cg, dh, add(k[4], w4), add(k[5], w5)); + let (mut w7, mut w6) = ([block[15], block[14]], [block[13], block[12]]); + rounds4!(ae, bf, cg, dh, add(k[6], w6), add(k[7], w7)); + let mut w8 = schedule!(w0, w1, w4, w5, w7); + let mut w9 = schedule!(w1, w2, w5, w6, w8); + rounds4!(ae, bf, cg, dh, add(k[8], w8), add(k[9], w9)); + + // Rounds 20..40 + w0 = schedule!(w2, w3, w6, w7, w9); + w1 = schedule!(w3, w4, w7, w8, w0); + rounds4!(ae, bf, cg, dh, add(k[10], w0), add(k[11], w1)); + w2 = schedule!(w4, w5, w8, w9, w1); + w3 = schedule!(w5, w6, w9, w0, w2); + rounds4!(ae, bf, cg, dh, add(k[12], w2), add(k[13], w3)); + w4 = schedule!(w6, w7, w0, w1, w3); + w5 = schedule!(w7, w8, w1, w2, w4); + rounds4!(ae, bf, cg, dh, add(k[14], w4), add(k[15], w5)); + w6 = schedule!(w8, w9, w2, w3, w5); + w7 = schedule!(w9, w0, w3, w4, w6); + rounds4!(ae, bf, cg, dh, add(k[16], w6), add(k[17], w7)); + w8 = schedule!(w0, w1, w4, w5, w7); + w9 = schedule!(w1, w2, w5, w6, w8); + rounds4!(ae, bf, cg, dh, add(k[18], w8), add(k[19], w9)); + + // Rounds 40..60 + w0 = schedule!(w2, w3, w6, w7, w9); + w1 = schedule!(w3, w4, w7, w8, w0); + rounds4!(ae, bf, cg, dh, add(k[20], w0), add(k[21], w1)); + w2 = schedule!(w4, w5, w8, w9, w1); + w3 = schedule!(w5, w6, w9, w0, w2); + rounds4!(ae, bf, cg, dh, add(k[22], w2), add(k[23], w3)); + w4 = schedule!(w6, w7, w0, w1, w3); + w5 = schedule!(w7, w8, w1, w2, w4); + rounds4!(ae, bf, cg, dh, add(k[24], w4), add(k[25], w5)); + w6 = schedule!(w8, w9, w2, w3, w5); + w7 = schedule!(w9, w0, w3, w4, w6); + rounds4!(ae, bf, cg, dh, add(k[26], w6), add(k[27], w7)); + w8 = schedule!(w0, w1, w4, w5, w7); + w9 = schedule!(w1, w2, w5, w6, w8); + rounds4!(ae, bf, cg, dh, add(k[28], w8), add(k[29], w9)); + + // Rounds 60..80 + w0 = schedule!(w2, w3, w6, w7, w9); + w1 = schedule!(w3, w4, w7, w8, w0); + rounds4!(ae, bf, cg, dh, add(k[30], w0), add(k[31], w1)); + w2 = schedule!(w4, w5, w8, w9, w1); + w3 = schedule!(w5, w6, w9, w0, w2); + rounds4!(ae, bf, cg, dh, add(k[32], w2), add(k[33], w3)); + w4 = schedule!(w6, w7, w0, w1, w3); + w5 = schedule!(w7, w8, w1, w2, w4); + rounds4!(ae, bf, cg, dh, add(k[34], w4), add(k[35], w5)); + w6 = schedule!(w8, w9, w2, w3, w5); + w7 = schedule!(w9, w0, w3, w4, w6); + rounds4!(ae, bf, cg, dh, add(k[36], w6), add(k[37], w7)); + w8 = schedule!(w0, w1, w4, w5, w7); + w9 = schedule!(w1, w2, w5, w6, w8); + rounds4!(ae, bf, cg, dh, add(k[38], w8), add(k[39], w9)); + + let [a, e] = ae; + let [b, f] = bf; + let [c, g] = cg; + let [d, h] = dh; + + state[0] = state[0].wrapping_add(a); + state[1] = state[1].wrapping_add(b); + state[2] = state[2].wrapping_add(c); + state[3] = state[3].wrapping_add(d); + state[4] = state[4].wrapping_add(e); + state[5] = state[5].wrapping_add(f); + state[6] = state[6].wrapping_add(g); + state[7] = state[7].wrapping_add(h); +} + + +pub fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { + let mut block_u32 = [0u64; BLOCK_LEN]; + // since LLVM can't properly use aliasing yet it will make + // unnecessary state stores without this copy + let mut state_cpy = *state; + for block in blocks { + for (o, chunk) in block_u32.iter_mut().zip(block.chunks_exact(8)) { + *o = u64::from_be_bytes(chunk.try_into().unwrap()); + } + sha512_digest_block_u64(&mut state_cpy, &block_u32); + } + *state = state_cpy; +} diff --git a/vendor/sha2/tests/data/sha224.blb b/vendor/sha2/tests/data/sha224.blb new file mode 100644 index 0000000000000000000000000000000000000000..50759c294c8a4983e4621143d2a25009c8b0eeac GIT binary patch literal 184 zcmYew$xlkEG-Qyu=*85dWu<-6J&|d*Mw7`A(M22NoBEb%9o_syUppitRiUsnGdWu! zsVKiZPa!S8LLsX(x1d-dzbv&#p#&(MlUP-$kdmJ+Q_LqY`}&H-+A=$DE||5*C|1QF xqW1QI!`*8qimK|6V33|n;+$Q5eXLD+vwH&PaK&VN`JHOlW!tsDd((-tJ^=1mN>=~? literal 0 HcmV?d00001 diff --git a/vendor/sha2/tests/data/sha256.blb b/vendor/sha2/tests/data/sha256.blb new file mode 100644 index 0000000000000000000000000000000000000000..2096fd4ec0cd150f533d5ae8b7023c0562288981 GIT binary patch literal 196 zcmYew$xlkEG-ObCyy1w`j6X6WvwnX$F*ARsiuyXoCn>Wh`z)C{Q@SE(N2qp4Myf(# zX=ZY^LQ+wFd7eUAeuY9-X>LKWLVj6lkwOVjIw!HJQXwTjUE%tQ-<#R5H%!SqHEYiX z4n6gñ€šH¤— m9ÌÇ,Ð \ No newline at end of file diff --git a/vendor/sha2/tests/data/sha384.blb b/vendor/sha2/tests/data/sha384.blb new file mode 100644 index 0000000000000000000000000000000000000000..7e9062497c83c46aa3b13831dbca8b0baee0370a GIT binary patch literal 244 zcmYew$xlkEG-NQa*pRS1aLqIepPNQ?8#g}AQvADJP-Gvwvk%Yl{mI`R-ct9wxBq#5 z>hG&kmp*#T*cq)Il98%VSeluft&midU!JFsmS3TeRhnB+tdL)pTBJ|{l+H=4s#HkH zPd7MKTrVK9q~C`-_lnKN@(t^6J{6ms9^&KaAo$p@cK@t^IUAqek!xM)xci-Lz1HuO z8+Ax9T+iTbr%K}ub)9AR&AGp`J-NO|I^6P?V)?3PNBO3tRTTCgtE&3cIEzU}|FGZ0 Kz1vJUuLA%te{C`V literal 0 HcmV?d00001 diff --git a/vendor/sha2/tests/data/sha512.blb b/vendor/sha2/tests/data/sha512.blb new file mode 100644 index 0000000000000000000000000000000000000000..b073a77cb7fc2b17a4dcbf8b9ff23354c7407045 GIT binary patch literal 292 zcmYew$xlkEG-Pl%-~7tZH0pVN~@~{g$0}NJgqcVQFS^wn9=-etDikT7HE>R%vcQ zu|j@XYLP+-P&y~Es!|~(Kiz@-sr$`{{H)^d_PY)^$6e11RP5h=;l%Zh#hlk$owIkR z=uKV}v@+zArBFz%T$gp+wTJt!b5mgzZ6d?n=iiPvr2Eas{i z^Fuy!nBiD#DT)&D%!oy~0%r6FA@evY;19sulFOC10J literal 0 HcmV?d00001 diff --git a/vendor/sha2/tests/data/sha512_256.blb b/vendor/sha2/tests/data/sha512_256.blb new file mode 100644 index 0000000000000000000000000000000000000000..5346c9494df4f0764cb5d4cde99318b345f87595 GIT binary patch literal 196 zcmYew$xlkEG-OaXR?kftJ@DJ=>&?f&Aw}OeaFw@k{K5c$esHztx7v2BUPcW zG&4C{A*m?8JWnAlzd|9aG`FBwA-^oONTCEMos(EqsgRPNu5fp5`sTvGImYvD+`bg` zlW%&K+`GSCmv3}3#0Bdg-S@#)hXlj)6hz%hBpiM$nY1(V=8jD!-n03(N;7!xGCi(output); +} + +#[test] +fn sha512_1million_a() { + let output = include_bytes!("data/sha512_one_million_a.bin"); + one_million_a::(output); +} diff --git a/vendor/snap/.cargo-checksum.json b/vendor/snap/.cargo-checksum.json new file mode 100644 index 0000000000..ac228fc235 --- /dev/null +++ b/vendor/snap/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYING":"7ca1297d23644e30bd489193a82a33f324e5fe33f25df4195649b91b883df967","Cargo.lock":"3c9f949b07c311204734ecba573b32e03821593dac9eec193f69b2204639d10a","Cargo.toml":"1728234f0e2d3cc184e54016115612e70efa9272de59c4af0a9c4d614d69bbc7","README.md":"5be873fd869130fb1d6f55d3c66854b234b08558b3f06903482717df086bc63c","build.rs":"afae7dd3c45a9a46bcce096e9e0aa9e36ade171e8fd00309969478025b82cac1","data/COPYING":"c355b53211bfbbefc0ec641ee43a2fa1ec926966f1276698b4b9125d73c70b18","data/Mark.Twain-Tom.Sawyer.txt":"bd8df876d2a05017bb302f506883a37817d256f16f2205a932399276e08a81af","data/Mark.Twain-Tom.Sawyer.txt.rawsnappy":"7f1f5878f128aec6140fb135f7ed7e2c29575c7eb5c44431ffc65b22f7a19738","data/alice29.txt":"7467306ee0feed4971260f3c87421154a05be571d944e9cb021a5713700c38f0","data/asyoulik.txt":"eaa3526fe53859f34ecdf255712f9ecf0b2c903451d4755b2edaa2e2599cb0fc","data/baddata1.snappy":"ca84adbcd5b4b784c3405fcdd4fa88f88a6614f2d5e5d4a527838785f1806623","data/baddata2.snappy":"06f0ca34f0de885d6a849e1c8df95391d4494bf430d3784ea2167113d6ca8947","data/baddata3.snappy":"2f60f8c9b5f3b9b0e3b4ff9aef983946552cdd1fdecdfad122292882894163bd","data/fireworks.jpeg":"93b986ce7d7e361f0d3840f9d531b5f40fb6ca8c14d6d74364150e255f126512","data/geo.protodata":"7c2875cd6d06c954240ba644618d1e1f2a167e4541731f019de5b4c1f8080f24","data/html":"5912445a6d50df1079f022d7e01fa615f5d128d53bad88acbf4f49e62a7ea759","data/html_x_4":"ce3b0ceece9a0c0f66a352fd65b87a8e06357b136e99a2a85fcb3b0689ff6671","data/kppkn.gtb":"1df7e44e4ec9bad952e7716fbdba0a2208665091866ded43407d03ed9ce23c24","data/lcet10.txt":"5314ba1dbb03f471df88bec6cd120a938ef60d0fd3511c5c1dce61bf7463245f","data/paper-100k.pdf":"60f73a051b7ca35bfec44734b2eed7736cb5c0b7f728beb7b97ade6c5e44849b","data/plrabn12.txt":"07e2e0b461af78c7c647cb53dab39de560198e16f799b4516eccf0fbd69f764c","data/urls.10K":"0319ce7fe1f51b14eace3de879fe7da15418d1525d3176c2b26c5985943a3cad","examples/compress-escaped.rs":"cef1933dbc5d9b496587c4c1a596f26e326e73799ab9a0ede1c3d76b00676090","examples/compress.rs":"34bad60450e768ed4ac27edf8622abc4d918b17e57b8c286030203e2b3590c24","examples/decompress.rs":"87aa11875ec98f253c8b48ce3a202ac3412063ce2f64387074194151c11fff5e","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/bytes.rs":"2eb9783acdf949ef96a9031d2bd43ead65db50a41a60ad98dc117cd61655c7c4","src/compress.rs":"e6f3160be400c2a4869d71210a2558ba8b438b835b632a12b7ff487660db093f","src/crc32.rs":"9f3858bef802640c595705c496f462d0343c4adcff9bdf333a43306fb67db7ae","src/crc32_table.rs":"e999470ca10bb7914887747be838d05d0f5059ae99a8b8c57b0be7de3931e72a","src/decompress.rs":"05c4d0c0922b1ad084cf32f224722f2fe9d63128d6a4da0c44333742d681b80f","src/error.rs":"683e609ae19f0acacfccb5ce7bcd8bd107a0b6639cdd2308a7768a632a993f4e","src/frame.rs":"4f69a9526a5dd0367631fc7a764bea877f7f0b4c33ee30d4ece62913c42ea48d","src/lib.rs":"4534bc8b5bf0f83dc1852629362d2d392397f1b1fc4f8bdb8f638bfd3cc89b22","src/raw.rs":"a7048da3a4b76b75e4b3d071ee9959dbf12c5b3a36dabb2f7878513507c80cb9","src/read.rs":"66ceb455e451d14964eff77743e8003d58de16ec90c9ba37e03fda51da7b94c9","src/tag.rs":"9ac94977c5ab3ea687b9441ea3c615f64a23eac11a4bade19cfa3be5968cb718","src/varint.rs":"6d63fca6323c91f193628a41b6e75f5b3443777467e6a5665907bbbba549e6c7","src/write.rs":"086edd9fb1442b6bc8bf8c6a80023eccc4ca627de57ccc62279691c9ff7f0786"},"package":"da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e"} \ No newline at end of file diff --git a/vendor/snap/COPYING b/vendor/snap/COPYING new file mode 100644 index 0000000000..a42659dccd --- /dev/null +++ b/vendor/snap/COPYING @@ -0,0 +1,27 @@ +Copyright 2011, The Snappy-Rust Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/snap/Cargo.lock b/vendor/snap/Cargo.lock new file mode 100644 index 0000000000..6eb826d6e9 --- /dev/null +++ b/vendor/snap/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "doc-comment" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97" + +[[package]] +name = "snap" +version = "1.0.1" +dependencies = [ + "doc-comment", +] diff --git a/vendor/snap/Cargo.toml b/vendor/snap/Cargo.toml new file mode 100644 index 0000000000..4cdc45a344 --- /dev/null +++ b/vendor/snap/Cargo.toml @@ -0,0 +1,34 @@ +# 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 = "snap" +version = "1.0.1" +authors = ["Andrew Gallant "] +description = "A pure Rust implementation of the Snappy compression algorithm. Includes\nstreaming compression and decompression.\n" +homepage = "https://github.com/BurntSushi/rust-snappy" +documentation = "https://docs.rs/snap" +readme = "README.md" +keywords = ["snappy", "compress", "compression", "decompress", "decompression"] +license = "BSD-3-Clause" +repository = "https://github.com/BurntSushi/rust-snappy" +[profile.release] +debug = true + +[profile.test] +opt-level = 3 + +[lib] +bench = false +[dev-dependencies.doc-comment] +version = "0.3.1" diff --git a/vendor/snap/README.md b/vendor/snap/README.md new file mode 100644 index 0000000000..af06b2055b --- /dev/null +++ b/vendor/snap/README.md @@ -0,0 +1,229 @@ +snap +==== +A pure Rust implementation of the +[Snappy compression algorithm](http://google.github.io/snappy/). +Includes streaming compression and decompression using the Snappy frame format. +This implementation is ported from both the +[reference C++ implementation](https://github.com/google/snappy) +and the +[Go implementation](https://github.com/golang/snappy). + +[![Build status](https://github.com/BurntSushi/rust-snappy/workflows/ci/badge.svg)](https://github.com/BurntSushi/rust-snappy/actions) +[![](http://meritbadge.herokuapp.com/snap)](https://crates.io/crates/snap) + +Licensed under the BSD 3-Clause. + + +### Documentation + +https://docs.rs/snap + + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +snap = "1" +``` + + +### Example: compress data on `stdin` + +This program reads data from `stdin`, compresses it and emits it to `stdout`. +This example can be found in `examples/compress.rs`: + +```rust +use std::io; + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + + let mut rdr = stdin.lock(); + // Wrap the stdout writer in a Snappy writer. + let mut wtr = snap::write::FrameEncoder::new(stdout.lock()); + io::copy(&mut rdr, &mut wtr).expect("I/O operation failed"); +} +``` + + +### Example: decompress data on `stdin` + +This program reads data from `stdin`, decompresses it and emits it to `stdout`. +This example can be found in `examples/decompress.rs`: + +```rust +use std::io; + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + + // Wrap the stdin reader in a Snappy reader. + let mut rdr = snap::read::FrameDecoder::new(stdin.lock()); + let mut wtr = stdout.lock(); + io::copy(&mut rdr, &mut wtr).expect("I/O operation failed"); +} +``` + + +### Example: the szip tool + +`szip` is a tool with similar behavior as `gzip`, except it uses Snappy +compression. It can be installed with Cargo: + +``` +$ cargo install szip +``` + +To compress a file, run `szip file`. To decompress a file, run +`szip -d file.sz`. See `szip --help` for more details. + + +### Testing + +This crate is tested against the reference C++ implementation of Snappy. +Currently, compression is byte-for-byte equivalent with the C++ implementation. +This seems like a reasonable starting point, although it is not necessarily +a goal to always maintain byte-for-byte equivalence. + +Tests against the reference C++ implementation can be run with +`cargo test --features cpp`. Note that you will need to have the C++ Snappy +library in your `LD_LIBRARY_PATH` (or equivalent). + +To run tests, you'll need to explicitly run the `test` crate: + +``` +$ cargo test --manifest-path test/Cargo.toml +``` + +To test that this library matches the output of the reference C++ library, use: + +``` +$ cargo test --manifest-path test/Cargo.toml --features cpp +``` + +Tests are in a separate crate because of the dependency on the C++ reference +library. Namely, Cargo does not yet permit optional dev dependencies. + + +### Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.39.0`. + +The current policy is that the minimum Rust version required to use this crate +can be increased in minor version updates. For example, if `crate 1.0` requires +Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also require Rust +1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a newer minimum +version of Rust. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. + + +### Performance + +The performance of this implementation should roughly match the performance of +the C++ implementation on x86_64. Below are the results of the microbenchmarks +(as defined in the C++ library): + +``` +group snappy/cpp/ snappy/snap/ +----- ----------- ------------ +compress/zflat00_html 1.00 94.5±0.62µs 1033.1 MB/sec 1.02 96.1±0.74µs 1016.2 MB/sec +compress/zflat01_urls 1.00 1182.3±8.89µs 566.3 MB/sec 1.04 1235.3±11.99µs 542.0 MB/sec +compress/zflat02_jpg 1.00 7.2±0.11µs 15.9 GB/sec 1.01 7.3±0.06µs 15.8 GB/sec +compress/zflat03_jpg_200 1.10 262.4±1.84ns 727.0 MB/sec 1.00 237.5±2.95ns 803.2 MB/sec +compress/zflat04_pdf 1.02 10.3±0.18µs 9.2 GB/sec 1.00 10.1±0.16µs 9.4 GB/sec +compress/zflat05_html4 1.00 399.2±5.36µs 978.4 MB/sec 1.01 404.0±2.46µs 966.8 MB/sec +compress/zflat06_txt1 1.00 397.3±2.61µs 365.1 MB/sec 1.00 398.5±3.06µs 364.0 MB/sec +compress/zflat07_txt2 1.00 352.8±3.20µs 338.4 MB/sec 1.01 355.2±5.01µs 336.1 MB/sec +compress/zflat08_txt3 1.01 1058.8±6.85µs 384.4 MB/sec 1.00 1051.8±6.74µs 386.9 MB/sec +compress/zflat09_txt4 1.00 1444.1±8.10µs 318.2 MB/sec 1.00 1450.0±13.36µs 316.9 MB/sec +compress/zflat10_pb 1.00 85.1±0.58µs 1328.6 MB/sec 1.02 87.0±0.90µs 1300.2 MB/sec +compress/zflat11_gaviota 1.07 311.9±4.27µs 563.5 MB/sec 1.00 291.9±1.86µs 602.3 MB/sec +decompress/uflat00_html 1.03 36.9±0.28µs 2.6 GB/sec 1.00 36.0±0.25µs 2.7 GB/sec +decompress/uflat01_urls 1.04 437.4±2.89µs 1530.7 MB/sec 1.00 419.9±3.10µs 1594.6 MB/sec +decompress/uflat02_jpg 1.00 4.6±0.05µs 24.9 GB/sec 1.00 4.6±0.03µs 25.0 GB/sec +decompress/uflat03_jpg_200 1.08 122.4±1.06ns 1558.6 MB/sec 1.00 112.8±1.35ns 1690.8 MB/sec +decompress/uflat04_pdf 1.00 5.7±0.05µs 16.8 GB/sec 1.10 6.2±0.07µs 15.3 GB/sec +decompress/uflat05_html4 1.01 164.1±1.71µs 2.3 GB/sec 1.00 162.6±2.16µs 2.3 GB/sec +decompress/uflat06_txt1 1.08 146.6±1.01µs 989.5 MB/sec 1.00 135.3±1.11µs 1072.0 MB/sec +decompress/uflat07_txt2 1.09 130.2±0.93µs 916.6 MB/sec 1.00 119.2±0.96µs 1001.8 MB/sec +decompress/uflat08_txt3 1.07 387.2±2.30µs 1051.0 MB/sec 1.00 361.9±6.29µs 1124.7 MB/sec +decompress/uflat09_txt4 1.09 536.1±3.47µs 857.2 MB/sec 1.00 494.0±5.05µs 930.2 MB/sec +decompress/uflat10_pb 1.00 32.5±0.19µs 3.4 GB/sec 1.05 34.0±0.48µs 3.2 GB/sec +decompress/uflat11_gaviota 1.00 142.1±2.05µs 1236.7 MB/sec 1.00 141.5±0.92µs 1242.3 MB/sec +``` + +Notes: These benchmarks were run with Snappy/C++ 1.1.8. Both the C++ and Rust +benchmarks were run with the same benchmark harness. Benchmarks were run on an +Intel i7-6900K. + +Additionally, here are the benchmarks run on the same machine from the Go +implementation of Snappy (which has a hand rolled implementation in Assembly). +Note that these were run using Go's microbenchmark tool, so the numbers may not +be directly comparable, but they should serve as a useful signpost: + +``` +Benchmark_UFlat0 25040 45180 ns/op 2266.49 MB/s +Benchmark_UFlat1 2648 451475 ns/op 1555.10 MB/s +Benchmark_UFlat2 229965 4788 ns/op 25709.01 MB/s +Benchmark_UFlat3 11355555 101 ns/op 1973.65 MB/s +Benchmark_UFlat4 196551 6055 ns/op 16912.64 MB/s +Benchmark_UFlat5 6016 189219 ns/op 2164.68 MB/s +Benchmark_UFlat6 6914 166371 ns/op 914.16 MB/s +Benchmark_UFlat7 8173 142506 ns/op 878.41 MB/s +Benchmark_UFlat8 2744 436424 ns/op 977.84 MB/s +Benchmark_UFlat9 1999 591141 ns/op 815.14 MB/s +Benchmark_UFlat10 28885 37291 ns/op 3180.04 MB/s +Benchmark_UFlat11 7308 163366 ns/op 1128.26 MB/s +Benchmark_ZFlat0 12902 91231 ns/op 1122.43 MB/s +Benchmark_ZFlat1 997 1200579 ns/op 584.79 MB/s +Benchmark_ZFlat2 136762 7832 ns/op 15716.53 MB/s +Benchmark_ZFlat3 4896124 245 ns/op 817.27 MB/s +Benchmark_ZFlat4 117643 10129 ns/op 10109.44 MB/s +Benchmark_ZFlat5 2934 394742 ns/op 1037.64 MB/s +Benchmark_ZFlat6 3008 382877 ns/op 397.23 MB/s +Benchmark_ZFlat7 3411 344916 ns/op 362.93 MB/s +Benchmark_ZFlat8 966 1057985 ns/op 403.36 MB/s +Benchmark_ZFlat9 854 1429024 ns/op 337.20 MB/s +Benchmark_ZFlat10 13861 83040 ns/op 1428.08 MB/s +Benchmark_ZFlat11 4070 293952 ns/op 627.04 MB/s +``` + +To run benchmarks, including the reference C++ implementation, do the +following: + +``` +$ cd bench +$ cargo bench --features cpp -- --save-baseline snappy +``` + +To compare them, as shown above, install +[`critcmp`](https://github.com/BurntSushi/critcmp) +and run (assuming you saved the baseline above under the name `snappy`): + +``` +$ critcmp snappy -g '.*?/(.*$)' +``` + +Finally, the Go benchmarks were run with the following command on commit +`ff6b7dc8`: + +``` +$ go test -cpu 1 -bench Flat -download +``` + + +### Comparison with other Snappy crates + +* `snappy` - These are bindings to the C++ library. No support for the Snappy + frame format. +* `snappy_framed` - Implements the Snappy frame format on top of the `snappy` + crate. +* `rsnappy` - Written in pure Rust, but lacks documentation and the Snappy + frame format. Performance is unclear and tests appear incomplete. +* `snzip` - Was created and immediately yanked from crates.io. diff --git a/vendor/snap/build.rs b/vendor/snap/build.rs new file mode 100644 index 0000000000..283164f2e2 --- /dev/null +++ b/vendor/snap/build.rs @@ -0,0 +1,124 @@ +use std::env; +use std::fs::File; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; + +const CASTAGNOLI_POLY: u32 = 0x82f63b78; + +type Result = std::result::Result>; + +fn main() { + if let Err(err) = try_main() { + panic!("{}", err); + } +} + +fn try_main() -> Result<()> { + let out_dir = match env::var_os("OUT_DIR") { + None => { + return Err(From::from("OUT_DIR environment variable not defined")) + } + Some(out_dir) => PathBuf::from(out_dir), + }; + write_tag_lookup_table(&out_dir)?; + write_crc_tables(&out_dir)?; + Ok(()) +} + +fn write_tag_lookup_table(out_dir: &Path) -> Result<()> { + let out_path = out_dir.join("tag.rs"); + let mut out = io::BufWriter::new(File::create(out_path)?); + + writeln!(out, "pub const TAG_LOOKUP_TABLE: [u16; 256] = [")?; + for b in 0u8..=255 { + writeln!(out, " {},", tag_entry(b))?; + } + writeln!(out, "];")?; + Ok(()) +} + +fn tag_entry(b: u8) -> u16 { + let b = b as u16; + match b & 0b00000011 { + 0b00 => { + let lit_len = (b >> 2) + 1; + if lit_len <= 60 { + lit_len + } else { + assert!(lit_len <= 64); + (lit_len - 60) << 11 + } + } + 0b01 => { + let len = 4 + ((b >> 2) & 0b111); + let offset = (b >> 5) & 0b111; + (1 << 11) | (offset << 8) | len + } + 0b10 => { + let len = 1 + (b >> 2); + (2 << 11) | len + } + 0b11 => { + let len = 1 + (b >> 2); + (4 << 11) | len + } + _ => unreachable!(), + } +} + +fn write_crc_tables(out_dir: &Path) -> Result<()> { + let out_path = out_dir.join("crc32_table.rs"); + let mut out = io::BufWriter::new(File::create(out_path)?); + + let table = make_table(CASTAGNOLI_POLY); + let table16 = make_table16(CASTAGNOLI_POLY); + + writeln!(out, "pub const TABLE: [u32; 256] = [")?; + for &x in table.iter() { + writeln!(out, " {},", x)?; + } + writeln!(out, "];\n")?; + + writeln!(out, "pub const TABLE16: [[u32; 256]; 16] = [")?; + for table in table16.iter() { + writeln!(out, " [")?; + for &x in table.iter() { + writeln!(out, " {},", x)?; + } + writeln!(out, " ],")?; + } + writeln!(out, "];")?; + + out.flush()?; + + Ok(()) +} + +fn make_table16(poly: u32) -> [[u32; 256]; 16] { + let mut tab = [[0; 256]; 16]; + tab[0] = make_table(poly); + for i in 0..256 { + let mut crc = tab[0][i]; + for j in 1..16 { + crc = (crc >> 8) ^ tab[0][crc as u8 as usize]; + tab[j][i] = crc; + } + } + tab +} + +fn make_table(poly: u32) -> [u32; 256] { + let mut tab = [0; 256]; + for i in 0u32..256u32 { + let mut crc = i; + for _ in 0..8 { + if crc & 1 == 1 { + crc = (crc >> 1) ^ poly; + } else { + crc >>= 1; + } + } + tab[i as usize] = crc; + } + tab +} diff --git a/vendor/snap/data/COPYING b/vendor/snap/data/COPYING new file mode 100644 index 0000000000..ae69a7b309 --- /dev/null +++ b/vendor/snap/data/COPYING @@ -0,0 +1,23 @@ +Some of the benchmark data in in this directory is licensed thusly: + + - fireworks.jpeg is Copyright 2013 Steinar H. Gunderson, and + is licensed under the Creative Commons Attribution 3.0 license + (CC-BY-3.0). See https://creativecommons.org/licenses/by/3.0/ + for more information. + + - kppkn.gtb is taken from the Gaviota chess tablebase set, and + is licensed under the MIT License. See + https://sites.google.com/site/gaviotachessengine/Home/endgame-tablebases-1 + for more information. + + - paper-100k.pdf is an excerpt (bytes 92160 to 194560) from the paper + “Combinatorial Modeling of Chromatin Features Quantitatively Predicts DNA + Replication Timing in _Drosophila_” by Federico Comoglio and Renato Paro, + which is licensed under the CC-BY license. See + http://www.ploscompbiol.org/static/license for more ifnormation. + + - alice29.txt, asyoulik.txt, plrabn12.txt and lcet10.txt are from Project + Gutenberg. The first three have expired copyrights and are in the public + domain; the latter does not have expired copyright, but is still in the + public domain according to the license information + (http://www.gutenberg.org/ebooks/53). diff --git a/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt b/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt new file mode 100644 index 0000000000..86a18750bf --- /dev/null +++ b/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt @@ -0,0 +1,396 @@ +Produced by David Widger. The previous edition was updated by Jose +Menendez. + + + + + + THE ADVENTURES OF TOM SAWYER + BY + MARK TWAIN + (Samuel Langhorne Clemens) + + + + + P R E F A C E + +MOST of the adventures recorded in this book really occurred; one or +two were experiences of my own, the rest those of boys who were +schoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but +not from an individual--he is a combination of the characteristics of +three boys whom I knew, and therefore belongs to the composite order of +architecture. + +The odd superstitions touched upon were all prevalent among children +and slaves in the West at the period of this story--that is to say, +thirty or forty years ago. + +Although my book is intended mainly for the entertainment of boys and +girls, I hope it will not be shunned by men and women on that account, +for part of my plan has been to try to pleasantly remind adults of what +they once were themselves, and of how they felt and thought and talked, +and what queer enterprises they sometimes engaged in. + + THE AUTHOR. + +HARTFORD, 1876. + + + + T O M S A W Y E R + + + +CHAPTER I + +"TOM!" + +No answer. + +"TOM!" + +No answer. + +"What's gone with that boy, I wonder? You TOM!" + +No answer. + +The old lady pulled her spectacles down and looked over them about the +room; then she put them up and looked out under them. She seldom or +never looked THROUGH them for so small a thing as a boy; they were her +state pair, the pride of her heart, and were built for "style," not +service--she could have seen through a pair of stove-lids just as well. +She looked perplexed for a moment, and then said, not fiercely, but +still loud enough for the furniture to hear: + +"Well, I lay if I get hold of you I'll--" + +She did not finish, for by this time she was bending down and punching +under the bed with the broom, and so she needed breath to punctuate the +punches with. She resurrected nothing but the cat. + +"I never did see the beat of that boy!" + +She went to the open door and stood in it and looked out among the +tomato vines and "jimpson" weeds that constituted the garden. No Tom. +So she lifted up her voice at an angle calculated for distance and +shouted: + +"Y-o-u-u TOM!" + +There was a slight noise behind her and she turned just in time to +seize a small boy by the slack of his roundabout and arrest his flight. + +"There! I might 'a' thought of that closet. What you been doing in +there?" + +"Nothing." + +"Nothing! Look at your hands. And look at your mouth. What IS that +truck?" + +"I don't know, aunt." + +"Well, I know. It's jam--that's what it is. Forty times I've said if +you didn't let that jam alone I'd skin you. Hand me that switch." + +The switch hovered in the air--the peril was desperate-- + +"My! Look behind you, aunt!" + +The old lady whirled round, and snatched her skirts out of danger. The +lad fled on the instant, scrambled up the high board-fence, and +disappeared over it. + +His aunt Polly stood surprised a moment, and then broke into a gentle +laugh. + +"Hang the boy, can't I never learn anything? Ain't he played me tricks +enough like that for me to be looking out for him by this time? But old +fools is the biggest fools there is. Can't learn an old dog new tricks, +as the saying is. But my goodness, he never plays them alike, two days, +and how is a body to know what's coming? He 'pears to know just how +long he can torment me before I get my dander up, and he knows if he +can make out to put me off for a minute or make me laugh, it's all down +again and I can't hit him a lick. I ain't doing my duty by that boy, +and that's the Lord's truth, goodness knows. Spare the rod and spile +the child, as the Good Book says. I'm a laying up sin and suffering for +us both, I know. He's full of the Old Scratch, but laws-a-me! he's my +own dead sister's boy, poor thing, and I ain't got the heart to lash +him, somehow. Every time I let him off, my conscience does hurt me so, +and every time I hit him my old heart most breaks. Well-a-well, man +that is born of woman is of few days and full of trouble, as the +Scripture says, and I reckon it's so. He'll play hookey this evening, * +and [* Southwestern for "afternoon"] I'll just be obleeged to make him +work, to-morrow, to punish him. It's mighty hard to make him work +Saturdays, when all the boys is having holiday, but he hates work more +than he hates anything else, and I've GOT to do some of my duty by him, +or I'll be the ruination of the child." + +Tom did play hookey, and he had a very good time. He got back home +barely in season to help Jim, the small colored boy, saw next-day's +wood and split the kindlings before supper--at least he was there in +time to tell his adventures to Jim while Jim did three-fourths of the +work. Tom's younger brother (or rather half-brother) Sid was already +through with his part of the work (picking up chips), for he was a +quiet boy, and had no adventurous, troublesome ways. + +While Tom was eating his supper, and stealing sugar as opportunity +offered, Aunt Polly asked him questions that were full of guile, and +very deep--for she wanted to trap him into damaging revealments. Like +many other simple-hearted souls, it was her pet vanity to believe she +was endowed with a talent for dark and mysterious diplomacy, and she +loved to contemplate her most transparent devices as marvels of low +cunning. Said she: + +"Tom, it was middling warm in school, warn't it?" + +"Yes'm." + +"Powerful warm, warn't it?" + +"Yes'm." + +"Didn't you want to go in a-swimming, Tom?" + +A bit of a scare shot through Tom--a touch of uncomfortable suspicion. +He searched Aunt Polly's face, but it told him nothing. So he said: + +"No'm--well, not very much." + +The old lady reached out her hand and felt Tom's shirt, and said: + +"But you ain't too warm now, though." And it flattered her to reflect +that she had discovered that the shirt was dry without anybody knowing +that that was what she had in her mind. But in spite of her, Tom knew +where the wind lay, now. So he forestalled what might be the next move: + +"Some of us pumped on our heads--mine's damp yet. See?" + +Aunt Polly was vexed to think she had overlooked that bit of +circumstantial evidence, and missed a trick. Then she had a new +inspiration: + +"Tom, you didn't have to undo your shirt collar where I sewed it, to +pump on your head, did you? Unbutton your jacket!" + +The trouble vanished out of Tom's face. He opened his jacket. His +shirt collar was securely sewed. + +"Bother! Well, go 'long with you. I'd made sure you'd played hookey +and been a-swimming. But I forgive ye, Tom. I reckon you're a kind of a +singed cat, as the saying is--better'n you look. THIS time." + +She was half sorry her sagacity had miscarried, and half glad that Tom +had stumbled into obedient conduct for once. + +But Sidney said: + +"Well, now, if I didn't think you sewed his collar with white thread, +but it's black." + +"Why, I did sew it with white! Tom!" + +But Tom did not wait for the rest. As he went out at the door he said: + +"Siddy, I'll lick you for that." + +In a safe place Tom examined two large needles which were thrust into +the lapels of his jacket, and had thread bound about them--one needle +carried white thread and the other black. He said: + +"She'd never noticed if it hadn't been for Sid. Confound it! sometimes +she sews it with white, and sometimes she sews it with black. I wish to +geeminy she'd stick to one or t'other--I can't keep the run of 'em. But +I bet you I'll lam Sid for that. I'll learn him!" + +He was not the Model Boy of the village. He knew the model boy very +well though--and loathed him. + +Within two minutes, or even less, he had forgotten all his troubles. +Not because his troubles were one whit less heavy and bitter to him +than a man's are to a man, but because a new and powerful interest bore +them down and drove them out of his mind for the time--just as men's +misfortunes are forgotten in the excitement of new enterprises. This +new interest was a valued novelty in whistling, which he had just +acquired from a negro, and he was suffering to practise it undisturbed. +It consisted in a peculiar bird-like turn, a sort of liquid warble, +produced by touching the tongue to the roof of the mouth at short +intervals in the midst of the music--the reader probably remembers how +to do it, if he has ever been a boy. Diligence and attention soon gave +him the knack of it, and he strode down the street with his mouth full +of harmony and his soul full of gratitude. He felt much as an +astronomer feels who has discovered a new planet--no doubt, as far as +strong, deep, unalloyed pleasure is concerned, the advantage was with +the boy, not the astronomer. + +The summer evenings were long. It was not dark, yet. Presently Tom +checked his whistle. A stranger was before him--a boy a shade larger +than himself. A new-comer of any age or either sex was an impressive +curiosity in the poor little shabby village of St. Petersburg. This boy +was well dressed, too--well dressed on a week-day. This was simply +astounding. His cap was a dainty thing, his close-buttoned blue cloth +roundabout was new and natty, and so were his pantaloons. He had shoes +on--and it was only Friday. He even wore a necktie, a bright bit of +ribbon. He had a citified air about him that ate into Tom's vitals. The +more Tom stared at the splendid marvel, the higher he turned up his +nose at his finery and the shabbier and shabbier his own outfit seemed +to him to grow. Neither boy spoke. If one moved, the other moved--but +only sidewise, in a circle; they kept face to face and eye to eye all +the time. Finally Tom said: + +"I can lick you!" + +"I'd like to see you try it." + +"Well, I can do it." + +"No you can't, either." + +"Yes I can." + +"No you can't." + +"I can." + +"You can't." + +"Can!" + +"Can't!" + +An uncomfortable pause. Then Tom said: + +"What's your name?" + +"'Tisn't any of your business, maybe." + +"Well I 'low I'll MAKE it my business." + +"Well why don't you?" + +"If you say much, I will." + +"Much--much--MUCH. There now." + +"Oh, you think you're mighty smart, DON'T you? I could lick you with +one hand tied behind me, if I wanted to." + +"Well why don't you DO it? You SAY you can do it." + +"Well I WILL, if you fool with me." + +"Oh yes--I've seen whole families in the same fix." + +"Smarty! You think you're SOME, now, DON'T you? Oh, what a hat!" + +"You can lump that hat if you don't like it. I dare you to knock it +off--and anybody that'll take a dare will suck eggs." + +"You're a liar!" + +"You're another." + +"You're a fighting liar and dasn't take it up." + +"Aw--take a walk!" + +"Say--if you give me much more of your sass I'll take and bounce a +rock off'n your head." + +"Oh, of COURSE you will." + +"Well I WILL." + +"Well why don't you DO it then? What do you keep SAYING you will for? +Why don't you DO it? It's because you're afraid." + +"I AIN'T afraid." + +"You are." + +"I ain't." + +"You are." + +Another pause, and more eying and sidling around each other. Presently +they were shoulder to shoulder. Tom said: + +"Get away from here!" + +"Go away yourself!" + +"I won't." + +"I won't either." + +So they stood, each with a foot placed at an angle as a brace, and +both shoving with might and main, and glowering at each other with +hate. But neither could get an advantage. After struggling till both +were hot and flushed, each relaxed his strain with watchful caution, +and Tom said: + +"You're a coward and a pup. I'll tell my big brother on you, and he +can thrash you with his little finger, and I'll make him do it, too." + +"What do I care for your big brother? I've got a brother that's bigger +than he is--and what's more, he can throw him over that fence, too." +[Both brothers were imaginary.] + +"That's a lie." + +"YOUR saying so don't make it so." + +Tom drew a line in the dust with his big toe, and said: + +"I dare you to step over that, and I'll lick you till you can't stand +up. Anybody that'll take a dare will steal sheep." + +The new boy stepped over promptly, and said: + +"Now you said you'd do it, now let's see you do it." + +"Don't you crowd me now; you better look out." + +"Well, you SAID you'd do it--why don't you do it?" + +"By jingo! for two cents I WILL do it." + +The new boy took two broad coppers out of his pocket and held them out +with derision. Tom struck them to the ground. In an instant both boys +were rolling and tumbling in the dirt, gripped together like cats; and +for the space of a minute they tugged and tore at each other's hair and +clothes, punched and scratched each other's nose, and covered +themselves with dust and glory. Presently the confusion took form, and +through the fog of battle Tom appeared, seated astride the new boy, and +pounding him with his fists. "Holler 'nuff!" said he. + +The boy only struggled to free himself. He was crying--mainly from rage. + +"Holler 'nuff!"--and the pounding went on. + +At last the stranger got out a smothered "'Nuff!" and Tom let him up +and said: + +"Now that'll learn you. Better look out who you're fooling with next +time." + +The new boy went off brushing the dust from his clothes, sobbing, +snuffling, and occasionally looking back and shaking his head and +threatening what he would do to Tom the "next time he caught him out." +To which Tom responded with jeers, and started off in high feather, and +as soon as his back was turned the new boy snatched up a stone, threw +it and hit him between the shoulders and then turned tail and ran like +an antelope. Tom chased the traitor home, and thus found out where he +lived. He then held a position at the gate for some time, daring the +enemy to come outside, but the enemy only made faces at him through the +window and declined. At last the enemy's mother appeared, and called +Tom a bad, vicious, vulgar child, and ordered him away. So he went +away; but he said he "'lowed" to "lay" for that boy. + +He got home pretty late that night, and when he climbed cautiously in +at the window, he uncovered an ambuscade, in the person of his aunt; +and when she saw the state his clothes were in her resolution to turn +his Saturday holiday into captivity at hard labor became adamantine in +its firmness. diff --git a/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt.rawsnappy b/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt.rawsnappy new file mode 100644 index 0000000000000000000000000000000000000000..9c56d985888e48a9967e187523f0e3326330aeca GIT binary patch literal 9871 zcmW++d3+ni*`6u8u)A7~rM0|~WyP6QqBu?@lY=8Ar;;dGG#9aRhm?^tk~Wrh#qP>N zQ1~GlQvw7CE&Q640B$iMX|9tMwyz{)z z`#jI+Pu3f296Mjj@jT5o=rT5F=II7AU*t{??Jsd!b@-rZ*Idf;rf1p~tuvR_s(I#d zarWGEY?mu5xy7wKzoT}^s4@KYtwyn^>W(3dL`{kZP=7vyJ{wy zjghcqlQS7jS(#e zmZs@)nxac-T2WT6?(3&^fqJk`mLKGnS97>a9iFqDJZ#9c;8&(gv$j0|KV{`|gW9=V z&2e~s9<|~5wxf7;o7TC*DZjAF9g|x*cmzDO0)Jb#690QRJk^6QV6)f`XYGbd>m~Wj zDT<_YJpY-0H!a>nduzD?y4AHM2i^#*q+E4y}r zW^0~e*`7RQF@yiG@+MTj#>&ZLiQ{Ec7|q$0tZ6aN_|*UD)?A4>Ea$-*UC+#ouTk+z z4(Dw@o>`$8I$-g7f-);_bS-vx!G;}WdD*s#F7<5OhPQ;PwrhHv8gr3@d!x+BmEhZ) zu~zC)l+;Dj?0lZOHK>8>r7yyZ617|jYFMj|pSiJ2g6gGzyoQyb%9K^$xfK4toOigT z;2mMN%m$%u@x7GO4dc~fo;YM&BG`HPwbP&$u4g-qWYR0aX3z@HrY>tFVEv}!L7g31 zu(7mcktmzOUc|f?epI z^F!FaQZ${in}CXx>?)_GN9$&}OrgwB59*d`mc_X#0j%&$iPmkbNU%fkuEi{uvul=@ zP@s0S${Y`GoewXsmf>tl0QxM4e|cW=oCZE+W3|kg%PbEN+Ga;}X>V#xe|jy=C`t_a(ugU_DjSgFLL2mK z4x#7<*g=;|i|iw{ZhEEe{k?$s1cj2;ZD@375#40hhVjC+D1G9xa-No19_mypmjN#& z0JmG^IgjPau;RR3&q!0s(17qedyuEIp$cVLyOw?}q&T)+nP(Iwi@L*4$rIEHpe=q+ z@GQ0F(Hg!EPoG)op?%QYP`$ieY3>&+jyL&dg!_Bfu3mR`uh^Y_Dc}N@D(n)(n#aQc zN;oKn-x2Gmk(qxQEJkrXpei^|)7kmw0Ms& zo`^9CI-5I#W{xM5_&Mmp8f>z}2Jzjg*92&}9f*k>Z=MOD9^}cgnRn^-8v92SXn~i@ zJqjN4AED4l0Fn!NUbG|zs9op3TJTE7T$P#m1io|%EtuTN@p2EhWS)LbhRK1t>}){`}ZwY8IH<7+mLvV9nGBvc;u>S2GT(0A)oySKzL=B-0TES{&!n+}OV)XfJFT8tzeP zj(IE~WN79L{2R&TTWWiOi)}Y6RoAv+P-LEO@(}ajWUSEzsD>XfZeLbp!1-1W z1tFRB_$ZJEN@c^b;X{&J zvhlZ#4?~-hcCwbNy(;vVMt^MFGm}xbY!*u%@QCRednG8H`6_I{AqwP@hMbNLYRo!2so{4J6pevxa zjML`=1_0B*e{K&=S^4<_FLm|a;U^s~zr)8k#R+k3@!zN242`Ep@ zU9b#Kka}olc$>PNRgy>VLS3X?7MPcs5isG2%a7h}EL2@US#xq201OaR*uXf_@HVN; zJ+Xn)5)8HBJENH{7$XCwg&%_l_8Mv9GQ26|0*~ZM_{!m%Wg^hhaP9DY>GcxyB)%5$ z=6b;_$B)m?b07`}x;2@E9jADog<@HA1}vb#o4@WN`!_A>K2;1SbmO z0DzM$jL&_sNELtrt5!L~f5NW|)J)BldQDe6Akj58c}_8ZB)GNrev9&}z9~X;*aOhW zfKdkB2(tj+EWyM|U7_}ZfDv~b4G1}AT)+Et6^4bwENtgp1)DEbjJZs?IW}5(G>V~luD6joYPJOOrWTDF?bA3?D;v(A1 zX_s*q(R{LjwvWE2!c0?0$%if2GWlFaj%F#S(sZ>eea~DbR2r$XLNGYS`TZ+A3zv{P zdbN`@wFkKOVg@pkNe~@NuVMS&d zFG+ct!Mg(h=cyKwi60X597F0bK*w? z*Y5r{d0%c@FzY99H0ck?Z>5k&E4J%t2}vD*Ee`LNU}1keAnsS0E*z+@iO_? zPgckQ(98oo5|O8HknDh_1f8Bvs9UDfzR{vk=f+lK8NZlGW2^v0uxz0G^E6jBXGKB3 z+1WDZtwaUT2q7C?^*=YB~K`+zEH`ALC*9o3L8Qt?T;;Zi3%lgQokTi`w{nt5xYC8 zQeJkA`GS>y=BRY`>VAAVFmt-aXkL;@bxDft$e*KZC5mcGUTu*;93MU^*p;zqL;I7w z`&w~m_@C)g^VM|4xG{Yj%987)X(f<$N|rew1IW{o>Vl{oy*6rtI4M`@IjNr+qW-+3 z=IpXPS~={S@3J~H^@Uy%TC~em>TDl=Lv^cVGxJplC^ug=NjiYCJD;5bLLRs@nPlGZ zEy#^8CKdVaM+8fO(=fuS2U{m3f)@)<(C|~ zB?Ow+wQD3DBnyM^er>uOs)B4AWcW#(3xPc|`Jk5aBL&9-Ak6G~r{M>&=;@0!{3A8b zoPl^2h`}YtH1cIAnm4Ou5JkC)8g+p@%b-5_zrrAbJYK1iPF1{cWO~4JK*^6@9R-_~ z2kV|ABk=g2Cq=4ksXTQR0>@PEz=brY4aIZ7zWT3K0nNo zF!L*wkyYbQ#@o~s&6-+8Q9(%M#?BMm(&6heN22gMz$o>|p4Mg~50ccb0Ev1Gx*U!a zh&Tt4Lyyu+?r9-MTLqp!FEchDF><*gfp<0@1F*`z)COcla;iZ4nhOvmzxEju1FP(= zO7gh|iM6IT2$kB@VIN+sWqc|?Gl$FMWQBawM{ZE#uV@cyLch&kKrZ=9Yvm+?nIa<( z$;JfzCP@NOY77V!s_j*g<_hvEy&d+1oc1_G3e&tB_@b||# zYcRc6>a#22`C*7{sx^SdcQnDG+DHBnG^U$OlB;xRX7+?sr45oHLLb*=l6`aWGiXq& z2iXY~)a^jqOU4xPh>xwu?`H;AC^^%~)hh5Z%QIP-0%C*75Yo<-wUn%#XxXD=7|Nukhl}PQrwyLoMjrJ=hUIaM z+U1b_fw9~1ivgy%aDMA#kV5SI(J1?sw#64Rq3&RVz6mO1s&=m*me${!>C@Lr5w#V+ zHMR~Y4CYrO^@lJ-BSn@oHBXNJCy)cDV2_PNNwkC1QxUqAK`*()_a z5bCVyAzM4xMs~FZz^$ZQjY{~)P-^EkEz=smVCTy!tRRo8WPy(i`o)Lk3}RX~C}gbR zze=pY$qA?u7Y8MNA!EM>sd+0203wQ9n;jyT>jBXExzc;bBnY}lgBV-2oF9a9^|?1T z9Xh~_YsmRBESYA>J=)ZRdH}e@wu0M`l6)C+iQkug34by^zk29W+bW1VB-1mrIX*I75nN>$_=>|5$c}cf@bV7% z5b2l2sYCb9o{Id}B_I|7uMJF~6gk<{jv9D6*{G@Tf`R78_^9zX>Jpz8lF8227HNQU z{f9xpsc8%RQWu1qZb-?1|Muc{cRwPq3O*$MI`tNNK`58We}G)AvC~qgp` zE>BMnMl$P->1>&}hBS#V*hrrwWX;2XW(g0lW^ zA3jA~gsPnrWtgDXbdV2%D68lF0iN_h;4HaV}dus{Sp|S9<5{aVF|h(>uooK0AMg} z%Qa4p`BWHyp0>_E4l36p2YqBSVLKyx{rLKj!g8QM$PJSA)kOTIRCMgjlc<#GnEFD1 zyiCaR6UhyF0Ei#n{)!&0InZ%EN=BbIf!q?%u9`5PLEHmrg2@~hb6_XQ!O%-^6H!7{GO?3%NPwquNCM|hZVaP@_<0m=0boF}VrKdOlFN~Q zYLB&y-eP>OeP86sNs?Qu;GZ_5+QTi{(GKzhi7XAK-^BBX<3|a7wh~waffm>Hb&fru zLiU{_0mYb-IiW(XpEAzV{-uklh(92dOzldwd3apOl*rrC;Rlhkvnvc%1X9WZUKjun zCUfx=3?$a&*?81nfom1lg&_i3%rVK&D8C%Puie$EmQ85F zcho?MWwVW+ZN(c->jPe0!@&u;*_u-{|AueYE+!-AqdeYB9{Ha{(T}LXRp(5syGQ6A`gkVr-fRLzZj=$FSetkeuDx+nP#C+ za0s|o(asO+b0T=FVDST!RY+O9&Z7W@?t5@Asv2L0AkVejp0WDy-$00huT*U7naRlP zejZ|r<5XDgke4*E+xRzmJwT!g9BgjDGsjj-H0x+PB9S+JA;-*SZA+YqHvw%x1Dget z{K+SnPNYjBtz`655OTLhi6y0I6ewlT^jLXhkpwE6m@zU7#Db?C4o8SAf&C%LiR9l3 zxuhlYJVYf$@_>K%IaEu%O$LJ_mkYM5ebIqGlL|1D``X67VH}UYBbYq$lc@0t_Tz5$ zSqO5n0tk=KqHrycZ#v?A)TY1zVBlA+JTG-C1lr(O!T1*rze~3ID_L!VBnMH_cmOH! zRUsEL<+@2eZY9_2u2P~|O5`kA8M*JNI-at0~z1Eb-f*4>Yp+rJHc`lgEppI5)3;p`h2||L( zA8YR`XcM`r1BXS@(}l!fdk4`BEf^8Q(o$xLyR=K&u_C0bv$h7HX%1MkM#SsYg8 z460yWC|(=x0~_Tv4Dma&zk$`h)hpAH9sY^`HIgvL;3T6HQpUL{m6mH2vc?By0CGlZ zcHf|H>P){fE^HqmC{ON?@gd}COFAfA6`Gy`G0o23cU~QAdW6H|g~K1tLUH0pC^#Va z6J9K42-?(%TS!a}?lKO+n|`AqUQvQ^RA_!p{4(z0_X~NJzC|pMt7TM;x2manGAXt~ zl2(VSC2?b*kHPJm|79pI6fC`6J2gCdv36rXb(!mCo{$$KORxFKAE^YFGTJw(ROqtg z1Q`v8w$V3!8@hD$y0v|292Jj=9Scsh2hN%Ijp1&=TBN5a%J0;)zo{W8bY|7rZT+Ov zCoNJo^ejB-+>23$J=*z*uXAHSEjY}SZ&x!km0>4MY)#!QFeh^n%ILpr6>pyyMyc*A zcFxfskPjyz;@TZBIt2h=sSUBCVQ8xPp##^Wo~hrLhR=z-I)!{{pfYik;mN4Pu7qr} zX9ff+D05RAxnzQxwY?I401c*U;{2fvII8WR z*4-K?f}!Txdr>%Ux%kWtcovASJrV6Dh`Fr;e~nxjCofEqfbwIVN*LzIc%(&cmmw!E zlKm>8+N?PKE>g7r%4DH#xKg29BVw!nMKG#mMy`#ItqH-n1;U1b46#-3L~=xzK#`H_ zefqu8p6$4{A&|4dt?P+E08~h=8lf%P*X_fH1hW|XWxIY`t9&Bzac2k=G~|WG9=U;c zM&6K7fjp~4X0&TpwZz`X5wuiS{0zecfm10>ElE8Wh~q&}wf*7lE90C0@O=98;ajyRoiKC+x_gUQD0RJ&M~;D5DW=*DSbkWrPYSMK~si3DV6 zm0cI>7!115l{b!%`2?=H>SW_2a&;%-dYc^odZ>(+#S`K^Al&Nt;Tu)>{X9|AKL`P2 zU(?A{MVvXj=DiQqzEoxz?h2Mb)1I+G6!Y2^i7si-?J$~cBfXKF9t-5)2EqOCTDcpa z*Yi&VSbUx0889$yFgQ88N>(ND_lA$9-V&-d`LWJ-LwsJ=?oXl$rZ9zG0A@Ls1U92V?p;7Lcu1xJMa*DRDf576QoN+MdKZ{Xl0wQO55_b@O7-ebv<#n2c4HNt*rdMVrxA^Z57Ycxg znj5=ci@z`a$H=ccTXpShmQ-2<#Wjj}Tl`0GubP8vr!O_z&%VGHYB2-<5kfvD2JyGZ zr7~_y>Ej8i_DpQ#`0z1s{+lKCXBbHTAn~mzh9B0B_;C#7$Y5Mw8yD;v`!D2UWO`7@ zmE!Y&mfR|-_C%zFx*a~I5ZOAJOm0b?hu-`#W&p`4RGkMpjNDuTCbP zXrwz3Ikm-jXV&c4ZPUoM98(TnH9m35bGj7MaakS-vcqYIE=-E%xa!Rw$9Q&olHKSOfH?H zdhkIS4H@EOaC5J#^2OShQvlzd2G`Q$x*q+oEYw^L6sHmy4tD#r*Ceu#>N6%8pM)!* z^>Qpv9w&N98hwnood`ayL>A9L^M*oVQG2`{G5y6bNN(fl)I*iK^xtWzV*=dNP7v&} zwo1WcsX<8WW^~>k2g1KGu9vhBcn!}SB(
    +Expand for code + +This is so extensive to show how you can build up to processing totally arbitrary sequences, but for the most part these can be used on `GenericArray` instances without much added complexity. + +```rust +/// 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) +} +``` +